model new
model title "Longwall Mining Simulation"
model domain extent 0 66.0 0 55.0
model config mechanical
model mechanical timestep auto
contact cmat default model linear method deformability emod 2e8 kratio 2.5 property fric 0.5 dp_nratio 0.5 dp_sratio 0.5
contact cmat apply
; ========================================
; ========================================
[bottom_coal_height = 0.0]
[top_coal_height = 15.8]
[total_coal_height = 15.8]
[gangue_layers = 0]
[gangue_thickness = 0.0]
[immediate_roof_thickness = 20.6]
[main_roof_thickness = 0.0]
[total_roof_thickness = 20.6]
[height_floor = 2.32]
[support_width = 1.5]
[support_num = 34]
[head_support_num = 6]
[total_support_num = 40]
[support_start = 3.0]
[caving_support_num = 34]
[caving_gates = 34]
[caving_rounds = 1]
[porosity = 0.105]
[gangue_threshold = 0.05]
[total_height = 36.4]
[model_width = 66.0]
[boundary_buffer = 3.0]
[effective_mining_width = 60.0] ;
[mining_start_x = 3.0]
[mining_end_x = 63.0]
[total_supports = support_num]
[gangue_extension = 10.0]
[support_top_height = 2.8]
[PI = 3.1415926535]
[y_bottom_coal_bottom = 0.0]
[y_bottom_coal_top = 0.0]
[y_top_coal_bottom = 0.0]
[y_top_coal_top = top_coal_height]
[y_immediate_roof_bottom = y_top_coal_top]
[y_immediate_roof_top = y_immediate_roof_bottom + immediate_roof_thickness]
[y_main_roof_bottom = 0.0]
[y_main_roof_top = 0.0]
[y_gangue_top = 0.0]
; ========================================
; ========================================
; ========================================
wall create vertices 0 0 0 35.0 id 100
wall create vertices 66.0 0 66.0 35.0 id 101
wall create vertices 0 0 66.0 0 id 102
wall create vertices 0 35.0 66.0 35.0 id 105
wall create vertices 3.0 0 3.0 35.0 id 103
wall create vertices 63.0 0 63.0 35.0 id 104
fish define finalize_walls
loop foreach wp wall.list
local wall_id = wall.id(wp)
command
wall attribute velocity-x 0.0 range id [wall_id]
wall attribute velocity-y 0.0 range id [wall_id]
end_command
endloop
io.out('All walls configured as rigid infinite mass surfaces.')
end
wall attribute velocity-x 0.0 range id 100
wall attribute velocity-y 0.0 range id 100
wall attribute velocity-x 0.0 range id 101
wall attribute velocity-y 0.0 range id 101
wall attribute velocity-x 0.0 range id 102
wall attribute velocity-y 0.0 range id 102
wall attribute velocity-x 0.0 range id 103
wall attribute velocity-y 0.0 range id 103
wall attribute velocity-x 0.0 range id 104
wall attribute velocity-y 0.0 range id 104
wall attribute velocity-x 0.0 range id 105
wall attribute velocity-y 0.0 range id 105
[finalize_walls]
; ========================================
; ========================================
fish define calc_ball_numbers
area_coal = model_width * total_coal_height * (1 - porosity)
area_gangue = model_width * gangue_thickness * (1 - porosity)
area_roof = model_width * total_roof_thickness * (1 - porosity)
local coal_radius_avg = (0.04 + 0.06) / 2
local gangue_radius_avg = (0.06 + 0.08) / 2
local roof_radius_avg = (0.07 + 0.09) / 2
area_ball_coal = PI * (coal_radius_avg)^2
area_ball_roof = PI * (roof_radius_avg)^2
area_ball_gangue = PI * (gangue_radius_avg)^2
num_coal = math.floor(area_coal / area_ball_coal)
num_roof = math.floor(area_roof / area_ball_roof)
num_gangue = math.floor(area_gangue / area_ball_gangue)
num_coal = math.max(50, math.min(500, num_coal))
num_gangue = math.max(25, math.min(250, num_gangue))
num_roof = math.max(30, math.min(300, num_roof))
global num_coal = num_coal
global num_gangue = num_gangue
global num_roof = num_roof
io.out('Coal balls: ' + string(num_coal))
io.out(string(num_coal))
io.out('Gangue balls: ' + string(num_gangue))
io.out('Roof balls: ' + string(num_roof))
end
fish define generate_bottom_coal
io.out('===== Bottom Coal Generation Skipped =====')
io.out('Bottom coal height is 0.0m - no bottom coal to generate')
io.out('Skipping bottom coal generation')
io.out('===============================================')
end
fish define generate_top_coal
io.out('===== Generating Top Coal (Gaussian Distribution) =====')
io.out('Top coal height: 15.8m')
io.out('Position: Y=2.8m to Y=18.6m (natural coal layer)')
io.out('X range: 3.0m to 63.0m (60m width)')
io.out('Particle radius: 0.04-0.06m (Gaussian distribution, sigma=0.5)')
local coal_y_bottom = 2.8
local coal_y_top = 18.6
local coal_thickness = coal_y_top - coal_y_bottom
local coal_x_left = 3.0
local coal_x_right = 63.0
local coal_width = coal_x_right - coal_x_left
local coal_area = coal_width * coal_thickness
local coal_volume = coal_area * 1.0
local coal_density = 1360.0
local coal_mass = coal_volume * coal_density
local radius_mean = 0.05
local radius_sigma = 0.5 ; Gaussian distribution for natural variation
local radius_min = 0.04
local radius_max = 0.06
local avg_volume = (4.0/3.0) * PI * radius_mean^3
local avg_mass = avg_volume * coal_density
local top_coal_needed = int(coal_mass / avg_mass)
; Calculate realistic number of balls based on area and radius
local ball_area = PI * radius_mean^2
local max_possible_balls = int(coal_area / (ball_area * 3.0)) ; 3.0 is packing factor for complete generation
top_coal_needed = math.min(top_coal_needed, max_possible_balls)
top_coal_needed = math.max(200, math.min(500, top_coal_needed)) ; Increased range for complete generation
io.out('Top coal balls needed: ' + string(top_coal_needed))
io.out('Max possible balls in area: ' + string(max_possible_balls))
io.out('Generating with Gaussian distribution pattern...')
command
ball generate id 1 [top_coal_needed] box [coal_x_left] [coal_x_right] [coal_y_bottom] [coal_y_top] group 'top_coal' tries 100000 radius [radius_min] [radius_max]
end_command
loop foreach bp ball.list
if ball.group(bp) == 'top_coal'
local u1 = random
local u2 = random
if u1 <= 0.0
u1 = 0.0001
endif
local z0 = math.sqrt(-2.0 * math.log(u1)) * math.cos(2.0 * PI * u2)
local radius = radius_mean + radius_sigma * z0
if radius < radius_min
radius = radius_min
endif
if radius > radius_max
radius = radius_max
endif
ball.radius(bp) = radius
endif
endloop
command
ball property density 1360 range group 'top_coal'
ball property 'young_mod' 2e8 range group 'top_coal'
ball property 'kratio' 2.5 range group 'top_coal'
ball property 'fric' 0.5 range group 'top_coal'
ball property 'dp_nratio' 0.5 range group 'top_coal'
ball property 'dp_sratio' 0.5 range group 'top_coal'
end_command
local top_coal_count = 0
loop foreach bp ball.list
if ball.group(bp) == 'top_coal'
top_coal_count = top_coal_count + 1
endif
endloop
io.out('Top coal balls generated: ' + string(top_coal_count))
io.out('*** Top coal generation completed (Y: 2.8-18.6m, Gaussian distribution) ***')
io.out('===============================================')
end
fish define generate_immediate_roof
io.out('===== Generating Immediate Roof (Gaussian Distribution) =====')
io.out('Immediate roof thickness: 15.6m')
io.out('Position: Y=18.6m to Y=34.2m (natural roof layer)')
io.out('X range: 3.0m to 63.0m (60m width)')
io.out('Particle radius: 0.07-0.09m (Gaussian distribution, sigma=0.5)')
local roof_y_bottom = 18.6
local roof_y_top = 34.2
local roof_thickness = roof_y_top - roof_y_bottom
local roof_x_left = 3.0
local roof_x_right = 63.0
local roof_width = roof_x_right - roof_x_left
local roof_area = roof_width * roof_thickness
local roof_volume = roof_area * 1.0
local roof_density = 2560.0
local roof_mass = roof_volume * roof_density
local radius_mean = 0.07
local radius_sigma = 0.6 ; Gaussian distribution for natural variation
local radius_min = 0.05
local radius_max = 0.09
local avg_volume = (4.0/3.0) * PI * radius_mean^3
local avg_mass = avg_volume * roof_density
local immediate_roof_needed = int(roof_mass / avg_mass)
; Calculate realistic number of balls based on area and radius
local ball_area = PI * radius_mean^2
local max_possible_balls = int(roof_area / (ball_area * 3.0)) ; 3.0 is packing factor for complete generation
immediate_roof_needed = math.min(immediate_roof_needed, max_possible_balls)
immediate_roof_needed = math.max(200, math.min(500, immediate_roof_needed)) ; Increased range for complete generation
io.out('Immediate roof balls needed: ' + string(immediate_roof_needed))
io.out('Max possible balls in area: ' + string(max_possible_balls))
io.out('Generating with Gaussian distribution pattern...')
; Find the next available ID
local max_id = 0
loop foreach bp ball.list
if ball.id(bp) > max_id
max_id = ball.id(bp)
endif
endloop
local start_id = max_id + 1
command
ball generate id [start_id] [start_id + immediate_roof_needed - 1] box [roof_x_left] [roof_x_right] [roof_y_bottom] [roof_y_top] group 'immediate_roof' tries 100000 radius [radius_min] [radius_max]
end_command
loop foreach bp ball.list
if ball.group(bp) == 'immediate_roof'
local u1 = random
local u2 = random
if u1 <= 0.0
u1 = 0.0001
endif
local z0 = math.sqrt(-2.0 * math.log(u1)) * math.cos(2.0 * PI * u2)
local radius = radius_mean + radius_sigma * z0
if radius < radius_min
radius = radius_min
endif
if radius > radius_max
radius = radius_max
endif
ball.radius(bp) = radius
endif
endloop
command
ball property density 2560 range group 'immediate_roof'
ball property 'young_mod' 2e8 range group 'immediate_roof'
ball property 'kratio' 2.5 range group 'immediate_roof'
ball property 'fric' 0.5 range group 'immediate_roof'
ball property 'dp_nratio' 0.5 range group 'immediate_roof'
ball property 'dp_sratio' 0.5 range group 'immediate_roof'
end_command
local immediate_roof_count = 0
loop foreach bp ball.list
if ball.group(bp) == 'immediate_roof'
immediate_roof_count = immediate_roof_count + 1
endif
endloop
io.out('Immediate roof balls generated: ' + string(immediate_roof_count))
io.out('*** Immediate roof generation completed (Y: 18.6-34.2m, Gaussian distribution) ***')
io.out('===============================================')
end
; ========================================
; ========================================
fish define create_supports
io.out('===== Creating Hydraulic Supports =====')
io.out('Support offset: +3.0m (moved right)')
io.out('Caving starts from support 6 (frame 6)')
io.out('Middle supports: ' + string(support_num) + ' frames')
io.out('Head supports: ' + string(head_support_num) + ' frames (3 at each end)')
io.out('Total supports: ' + string(total_support_num) + ' frames')
io.out('Caving supports: 34 frames (supports 6-39) with caving gates')
io.out('Caving gate design: 1.2m width, separated from support, aligned with top')
loop local i (1, 3)
local xpos_head = 3.0 + (i-1) * support_width
local wall_id_1_head = 2000 + i
local wall_id_2_head = 3000 + i
local wall_id_3_head = 4000 + i
command
wall create vertices [xpos_head] 0 [xpos_head] 2.8 id [wall_id_1_head]
wall attribute velocity-x 0.0 range id [wall_id_1_head]
wall create vertices [xpos_head+1.5] 0 [xpos_head+1.5] 2.8 id [wall_id_2_head]
wall attribute velocity-x 0.0 range id [wall_id_2_head]
wall create vertices [xpos_head] 2.8 [xpos_head+1.5] 2.8 id [wall_id_3_head]
wall attribute velocity-x 0.0 range id [wall_id_3_head]
end_command
io.out('Created head support ' + string(i) + ' at x=' + string(xpos_head) + ' (no caving gate)')
endloop
loop local j (1, support_num)
local xpos_middle = 3.0 + 3 * support_width + (j-1) * support_width
local wall_id_1_middle = 2000 + 3 + j
local wall_id_2_middle = 3000 + 3 + j
local wall_id_3_middle = 4000 + 3 + j
local wall_id_4_middle = 5000 + j
local caving_gate_id = 6000 + j
command
wall create vertices [xpos_middle] 0 [xpos_middle] 2.8 id [wall_id_1_middle]
wall attribute velocity-x 0.0 range id [wall_id_1_middle]
wall create vertices [xpos_middle+1.5] 0 [xpos_middle+1.5] 2.8 id [wall_id_2_middle]
wall attribute velocity-x 0.0 range id [wall_id_2_middle]
wall create vertices [xpos_middle] 2.8 [xpos_middle+1.5] 2.8 id [wall_id_3_middle]
wall attribute velocity-x 0.0 range id [wall_id_3_middle]
end_command
; Only support 6 (j=6) has caving gate
if j == 6
local gate_x_start = xpos_middle + 0.15
local gate_x_end = gate_x_start + 1.2
command
wall create vertices [gate_x_start] 2.8 [gate_x_end] 2.8 id [wall_id_4_middle] group 'caving_gate'
wall attribute velocity-x 0.0 range id [wall_id_4_middle]
end_command
io.out('Created middle support ' + string(j) + ' at x=' + string(xpos_middle) + ' (with 1.2m caving gate)')
else
io.out('Created middle support ' + string(j) + ' at x=' + string(xpos_middle) + ' (no caving gate)')
endif
endloop
loop local k (1, 3)
local xpos_tail = 3.0 + 3 * support_width + support_num * support_width + (k-1) * support_width
local wall_id_1_tail = 2000 + 3 + support_num + k
local wall_id_2_tail = 3000 + 3 + support_num + k
local wall_id_3_tail = 4000 + 3 + support_num + k
command
wall create vertices [xpos_tail] 0 [xpos_tail] 2.8 id [wall_id_1_tail]
wall attribute velocity-x 0.0 range id [wall_id_1_tail]
wall create vertices [xpos_tail+1.5] 0 [xpos_tail+1.5] 2.8 id [wall_id_2_tail]
wall attribute velocity-x 0.0 range id [wall_id_2_tail]
wall create vertices [xpos_tail] 2.8 [xpos_tail+1.5] 2.8 id [wall_id_3_tail]
wall attribute velocity-x 0.0 range id [wall_id_3_tail]
end_command
io.out('Created tail support ' + string(k) + ' at x=' + string(xpos_tail) + ' (no caving gate)')
endloop
io.out('All supports created successfully with 3m right offset')
io.out('Caving gates: 1.2m width, separated from supports, aligned with top')
io.out('===============================================')
end
; ========================================
; ========================================
fish define prevent_bouncing
loop foreach bp ball.list
local pos = ball.pos(bp)
local px = pos->x
local py = pos->y
if py <= support_top_height + 0.05
ball.vel.x(bp) = 0.0
ball.vel.y(bp) = 0.0
ball.spin(bp) = 0.0
endif
if px <= 3.02
ball.vel.x(bp) = 0.0
ball.vel.y(bp) = 0.0
ball.spin(bp) = 0.0
endif
if px >= 62.98
ball.vel.x(bp) = 0.0
ball.vel.y(bp) = 0.0
ball.spin(bp) = 0.0
endif
if py <= 0.02
ball.vel.x(bp) = 0.0
ball.vel.y(bp) = 0.0
ball.spin(bp) = 0.0
endif
endloop
end
fish define execute_caving
local xpos = global_xpos
local gate_width = global_gate_width
local coal_mass = 0.0
local gangue_mass = 0.0
local total_mass = 0.0
local gangue_ratio = 0.0
local stop_caving = false
local res
io.out('Executing single round caving at position: X=' + string(xpos) + ', width=' + string(gate_width))
local x1 = xpos
local x2 = xpos + gate_width
local y_min = 0.0
local y_max = support_top_height + top_coal_height + immediate_roof_thickness
io.out('Caving zone: X=' + string(x1) + '-' + string(x2) + ', Y=' + string(y_min) + '-' + string(y_max))
io.out('Caving mechanism: Particles slide down along wall surfaces')
res = 1
loop foreach bp ball.list
ball.vel.x(bp) = 0.0
ball.vel.y(bp) = 0.0
ball.spin(bp) = 0.0
endloop
prevent_bouncing()
command
model cycle 2000
model solve time 2.0
end_command
loop foreach bp ball.list
ball.vel.x(bp) = 0.0
ball.vel.y(bp) = 0.0
ball.spin(bp) = 0.0
endloop
prevent_bouncing()
prevent_bouncing()
io.out('Caving completed. All particles frozen and system stabilized.')
[return_value] = res
end
fish define sequential_caving
global total_coal_mass = 0.0
global total_gangue_mass = 0.0
global caving_area = 0.0
io.out('===== Starting Single Support Caving =====')
io.out('Only support 6 has caving gate')
io.out('Support spacing: ' + string(support_width) + 'm')
io.out('Gangue threshold: ' + string(gangue_threshold*100) + '% (5%)')
io.out('Waiting for equilibrium before opening caving gate...')
; Force equilibrium - keep running until equilibrium is reached
io.out('Checking equilibrium status...')
local current_ratio = mech_ratio
io.out('Current mechanical ratio: ' + string(current_ratio, 6))
local equilibrium_cycles = 0
local max_equilibrium_cycles = 500000
local equilibrium_threshold = 1e-3
; Keep running until equilibrium is reached
loop while current_ratio > equilibrium_threshold and equilibrium_cycles < max_equilibrium_cycles
io.out('System not in equilibrium. Mechanical ratio: ' + string(current_ratio, 6) + ' (target: ' + string(equilibrium_threshold) + ')')
io.out('Cycling until equilibrium... (cycle ' + string(equilibrium_cycles) + ')')
command
model cycle 1000
end_command
equilibrium_cycles = equilibrium_cycles + 1000
current_ratio = mech_ratio
if (equilibrium_cycles % 10000) == 0
io.out('Equilibrium check cycle ' + string(equilibrium_cycles) + ': ratio = ' + string(current_ratio, 6))
endif
endloop
if current_ratio <= equilibrium_threshold
io.out('SUCCESS: System is in equilibrium!')
io.out('Final mechanical ratio: ' + string(current_ratio, 6))
io.out('Equilibrium reached after ' + string(equilibrium_cycles) + ' cycles')
else
io.out('WARNING: Maximum equilibrium cycles reached')
io.out('Final mechanical ratio: ' + string(current_ratio, 6))
io.out('Proceeding with caving despite potential instability...')
endif
; Only proceed with caving after equilibrium is confirmed
io.out('')
io.out('===== EQUILIBRIUM REACHED - DELETING CAVING GATE HORIZONTAL LINE =====')
local support_num = 6
local gate_id = 5000 + support_num
local xpos = 3.0 + 3 * support_width + (support_num-1) * support_width
io.out('===== Processing Support ' + string(support_num) + ' (Only Support with Caving Gate) =====')
io.out('Support position: X=' + string(xpos) + 'm')
io.out('Caving gate ID: ' + string(gate_id))
io.out('Caving gate width: 1.2m horizontal line')
; List all walls before deletion
io.out('All walls before deletion:')
loop foreach wp wall.list
io.out(' Wall ID: ' + string(wall.id(wp)) + ' at ' + string(wall.pos(wp)) + ' group: ' + string(wall.group(wp)))
endloop
; Check if caving gate exists
io.out('Checking for caving gate horizontal line...')
local gate = wall.find(gate_id)
if gate == null
io.out('ERROR: Caving gate ' + string(gate_id) + ' not found!')
io.out('Trying to find caving gate by group...')
loop foreach wp wall.list
if wall.group(wp) == 'caving_gate'
io.out(' Found caving gate: ID=' + string(wall.id(wp)) + ' at ' + string(wall.pos(wp)))
gate_id = wall.id(wp)
gate = wp
endif
endloop
if gate == null
io.out('No caving gate found, cannot proceed')
return
endif
else
io.out('Caving gate horizontal line found, proceeding with deletion...')
io.out('Gate position: ' + string(wall.pos(gate)))
io.out('Gate group: ' + string(wall.group(gate)))
endif
global global_xpos = xpos
global global_gate_width = support_width
io.out('EQUILIBRIUM CONFIRMED - Deleting caving gate horizontal line for support ' + string(support_num) + '...')
io.out('Deleting 1.2m caving gate horizontal line (ID: ' + string(gate_id) + ')')
io.out('Support structure remains intact')
; Delete only the caving gate horizontal line (1.2m), not the support structure
command
wall delete range id [gate_id]
end_command
; Verify deletion
local gate_after = wall.find(gate_id)
if gate_after == null
io.out('SUCCESS: 1.2m caving gate horizontal line deleted successfully')
io.out('Support structure remains intact')
else
io.out('WARNING: Caving gate still exists after deletion attempt')
io.out('Trying alternative deletion method...')
command
wall delete range group 'caving_gate'
end_command
io.out('Alternative deletion method applied')
endif
; List all walls after deletion
io.out('All walls after deletion:')
loop foreach wp wall.list
io.out(' Wall ID: ' + string(wall.id(wp)) + ' at ' + string(wall.pos(wp)) + ' group: ' + string(wall.group(wp)))
endloop
io.out('Caving gate horizontal line deleted for support ' + string(support_num))
io.out('1.2m horizontal opening created, particles can now flow through')
; Rest of the caving process...
io.out('Waiting for particle flow and settlement...')
local settlement_cycles = 0
local max_settlement_cycles = 10000
local stable_cycles = 0
local max_stable_cycles = 5
local last_coal_mass = 0.0
local last_gangue_mass = 0.0
loop while settlement_cycles < max_settlement_cycles
command
model cycle 200
end_command
settlement_cycles = settlement_cycles + 200
if (settlement_cycles % 1000) == 0
io.out('Settlement cycle ' + string(settlement_cycles) + ' / ' + string(max_settlement_cycles))
endif
local current_coal_mass = 0.0
local current_gangue_mass = 0.0
loop foreach bp ball.list
local pos = ball.pos(bp)
local px = pos->x
local py = pos->y
if px >= (xpos - support_width/2) and px <= (xpos + support_width/2) and py <= 2.8
if ball.group(bp) == 'coal'
current_coal_mass = current_coal_mass + ball.mass(bp)
else
if ball.group(bp) == 'gangue'
current_gangue_mass = current_gangue_mass + ball.mass(bp)
endif
endif
endif
endloop
local total_mass = current_coal_mass + current_gangue_mass
local gangue_ratio = 0.0
if total_mass > 0.0
gangue_ratio = current_gangue_mass / total_mass
endif
if abs(current_coal_mass - last_coal_mass) < 0.1 and abs(current_gangue_mass - last_gangue_mass) < 0.1
stable_cycles = stable_cycles + 1
else
stable_cycles = 0
endif
last_coal_mass = current_coal_mass
last_gangue_mass = current_gangue_mass
if stable_cycles >= max_stable_cycles
io.out('Particle flow stabilized after ' + string(settlement_cycles) + ' cycles')
io.out('Final coal mass: ' + string(current_coal_mass, 2) + ' kg')
io.out('Final gangue mass: ' + string(current_gangue_mass, 2) + ' kg')
io.out('Final gangue ratio: ' + string(gangue_ratio*100, 2) + '%')
break
endif
endloop
if settlement_cycles >= max_settlement_cycles
io.out('Warning: Maximum settlement cycles reached, flow may not be fully stabilized')
endif
total_coal_mass = current_coal_mass
total_gangue_mass = current_gangue_mass
caving_area = 1.2 ; 1.2m caving gate width
io.out('')
io.out('===== Single Support Caving Completed =====')
io.out('Support ' + string(support_num) + ' caving completed:')
io.out(' Coal mined: ' + string(total_coal_mass, 2) + ' kg')
io.out(' Gangue mined: ' + string(total_gangue_mass, 2) + ' kg')
io.out(' Gangue ratio: ' + string(gangue_ratio*100, 2) + '%')
io.out(' Caving area: ' + string(caving_area, 2) + ' m2 (1.2m gate width)')
local total_mined_mass = total_coal_mass + total_gangue_mass
local overall_gangue_ratio = 0.0
if total_mined_mass > 0.0
overall_gangue_ratio = total_gangue_mass / total_mined_mass
endif
io.out('Overall gangue ratio: ' + string(overall_gangue_ratio*100, 2) + '%')
local coal_recovery_rate = 0.0
if caving_area > 0.0
coal_recovery_rate = total_coal_mass / caving_area
endif
io.out('Coal recovery rate: ' + string(coal_recovery_rate, 2) + ' kg/m2')
io.out('===============================================')
end
; ========================================
; ========================================
fish define fix_all_balls
loop foreach bp ball.list()
if ball.radius(bp) <= 0
ball.radius(bp) = 0.05
endif
if ball.density(bp) <= 0
if ball.group(bp) == "coal" or ball.group(bp) == "top_coal" or ball.group(bp) == "bottom_coal"
ball.density(bp) = 1360
else
ball.density(bp) = 2560
endif
endif
local pos = ball.pos(bp)
local py = pos->y
if py <= support_top_height + 0.1
ball.vel.y(bp) = 0.0
ball.vel.x(bp) = 0.0
ball.spin(bp) = 0.0
endif
endloop
end
fish define execute_caving_coal
local coal_mass = 0.0
loop foreach bp ball.list
if ball.group(bp) == 'caved_coal'
coal_mass = coal_mass + ball.mass(bp)
endif
endloop
[return_value] = coal_mass
end
fish define execute_caving_gangue
local gangue_mass = 0.0
loop foreach bp ball.list
if ball.group(bp) == 'caved_gangue'
gangue_mass = gangue_mass + ball.mass(bp)
endif
endloop
[return_value] = gangue_mass
end
fish define balance_model
io.out('===== Starting Model Balance =====')
io.out('Target: Maximum unbalanced force ratio < 1e-3')
io.out('Initial stress field establishment...')
command
model gravity 9.81
model cycle 10000 calm 100
end_command
local max_ratio = 1.0
local cycle_count = 0
local max_cycles = 100000
io.out('Cycling until equilibrium...')
loop while max_ratio > 1e-3 and cycle_count < max_cycles
command
model cycle 1000
end_command
max_ratio = mech_ratio
cycle_count = cycle_count + 1000
if (cycle_count % 10000) == 0
io.out('Cycle: ' + string(cycle_count) + ', Max ratio: ' + string(max_ratio, 6))
endif
endloop
command
model save 'initial_state'
end_command
io.out('===== Model Equilibrium Reached =====')
io.out('Final cycle count: ' + string(cycle_count))
io.out('Final max ratio: ' + string(max_ratio, 6))
io.out('Initial stress field established, kinetic energy 閳')
io.out('===============================================')
end
fish define set_contact_parameters
io.out('Setting contact parameters for different contact types...')
io.out('Ball-ball: emod=2e8, kratio=2.5, fric=0.5, dp_nratio=0.5, dp_sratio=0.5')
io.out('Ball-facet: emod=4e8, kratio=2.5, fric=0.5, dp_nratio=0.5, dp_sratio=0.5')
command
; Set ball-ball contact parameters (default for all contacts first)
contact cmat default model linear method deformability emod 2e8 kratio 2.5 property fric 0.5 dp_nratio 0.5 dp_sratio 0.5
contact cmat apply
; Then override ball-facet contacts with different emod
contact cmat add model linear method deformability emod 4e8 kratio 2.5 property fric 0.5 dp_nratio 0.5 dp_sratio 0.5 range contact type 'ball-facet'
contact cmat apply range contact type 'ball-facet'
end_command
io.out('Contact parameters set successfully (ball-ball: 2e8 Pa, ball-facet: 4e8 Pa).')
end
fish define reduce_damping_for_flow
io.out('===== Setting Damping for Dense Flow =====')
io.out('Setting damping to 0.15 for dense flow through 1.2m caving gates...')
command
; Set ball-ball contact parameters (default for all contacts first)
contact cmat default model linear method deformability emod 2e8 kratio 2.5 property fric 0.5 dp_nratio 0.15 dp_sratio 0.15
contact cmat apply
; Then override ball-facet contacts with different emod
contact cmat add model linear method deformability emod 4e8 kratio 2.5 property fric 0.5 dp_nratio 0.15 dp_sratio 0.15 range contact type 'ball-facet'
contact cmat apply range contact type 'ball-facet'
ball property 'dp_nratio' 0.15 'dp_sratio' 0.15
end_command
io.out('Damping set to 0.15 - dense flow mode enabled')
io.out('Particles will flow in sliding-rolling mode through 1.2m gates')
io.out('===============================================')
end
fish define visualize_layers
io.out('===== Visualization Setup =====')
io.out('Layers are ready for visualization')
io.out('Use PFC interface to set colors manually if needed')
io.out('===============================================')
end
fish define stepwise_coal_mining
io.out('===== Starting Stepwise Coal Mining =====')
io.out('*** WAITING FOR EQUILIBRIUM BEFORE STEPWISE MINING ***')
io.out('Checking equilibrium status...')
local current_ratio = mech_ratio
io.out('Current mechanical ratio: ' + string(current_ratio, 6))
if current_ratio > 1e-3
io.out('System not in equilibrium yet. Cycling until equilibrium...')
command
model cycle 5000
model solve ratio-average 1e-3
end_command
current_ratio = mech_ratio
io.out('After cycling, mechanical ratio: ' + string(current_ratio, 6))
endif
if current_ratio <= 1e-3
io.out('*** EQUILIBRIUM ACHIEVED - STARTING STEPWISE MINING ***')
local step_distance = 0.6
local total_mining_length = 10.6 ; 娣囶喗娑.6缁
local gangue_threshold = 0.05
io.out('Stepwise mining parameters:')
io.out(' Step distance: ' + string(step_distance) + 'm')
io.out(' Total mining length: ' + string(total_mining_length) + 'm')
io.out(' Total steps: ' + string(total_steps))
io.out(' Gangue threshold: ' + string(gangue_threshold*100) + '%')
global total_coal_mined = 0.0
global total_gangue_mined = 0.0
global current_step = 0
loop local step (1, total_steps)
current_step = step
local current_position = 15.0 + (step - 1) * step_distance
io.out('')
io.out('===== Mining Step ' + string(step) + ' of ' + string(total_steps) + ' =====')
io.out('Current position: ' + string(current_position, 1) + 'm')
local gate_opened = open_caving_gate(current_position)
if gate_opened
io.out('*** CAVING GATE OPENED - WAITING FOR PARTICLE SETTLEMENT ***')
local settlement_cycles = 0
local max_settlement_cycles = 30000
local stable_cycles = 0
local max_stable_cycles = 5
local last_total_discharged = 0.0
local last_mech_ratio = 1.0
loop while settlement_cycles < max_settlement_cycles
command
model cycle 1000
end_command
settlement_cycles = settlement_cycles + 1000
if (settlement_cycles % 5000) == 0
local coal_discharged = calculate_discharged_coal_mass()
local gangue_discharged = calculate_discharged_gangue_mass()
local total_discharged = coal_discharged + gangue_discharged
local gangue_ratio = 0.0
local current_mech_ratio = mech_ratio
if total_discharged > 0.0
gangue_ratio = gangue_discharged / total_discharged
endif
io.out('Settlement cycle ' + string(settlement_cycles) + ':')
io.out(' Coal discharged: ' + string(coal_discharged, 0) + ' kg')
io.out(' Gangue discharged: ' + string(gangue_discharged, 0) + ' kg')
io.out(' Gangue ratio: ' + string(gangue_ratio*100, 1) + '%')
io.out(' Mechanical ratio: ' + string(current_mech_ratio, 6))
local mass_change = math.abs(total_discharged - last_total_discharged)
local ratio_change = math.abs(current_mech_ratio - last_mech_ratio)
if mass_change < 1.0 and ratio_change < 1e-4
stable_cycles = stable_cycles + 1
io.out(' System stable for ' + string(stable_cycles) + ' cycles')
else
stable_cycles = 0
io.out(' System still flowing... (mass change: ' + string(mass_change, 1) + ' kg)')
endif
last_total_discharged = total_discharged
last_mech_ratio = current_mech_ratio
if stable_cycles >= max_stable_cycles
io.out('*** PARTICLE SETTLEMENT COMPLETED - SYSTEM STABLE ***')
break
endif
endif
endloop
local step_coal_mass = calculate_discharged_coal_mass()
local step_gangue_mass = calculate_discharged_gangue_mass()
local step_total = step_coal_mass + step_gangue_mass
gangue_ratio = 0.0
if step_total > 0.0
gangue_ratio = step_gangue_mass / step_total
endif
total_coal_mined = total_coal_mined + step_coal_mass
total_gangue_mined = total_gangue_mined + step_gangue_mass
io.out('Step ' + string(step) + ' results:')
io.out(' Coal mined: ' + string(step_coal_mass, 1) + ' kg')
io.out(' Gangue mined: ' + string(step_gangue_mass, 1) + ' kg')
io.out(' Gangue ratio: ' + string(gangue_ratio*100, 1) + '%')
io.out(' Cumulative coal: ' + string(total_coal_mined, 0) + ' kg')
io.out(' Cumulative gangue: ' + string(total_gangue_mined, 0) + ' kg')
if gangue_ratio >= gangue_threshold
io.out('Gangue ratio ' + string(gangue_ratio*100, 1) + '% >= ' + string(gangue_threshold*100) + '% - closing gate')
close_caving_gate(current_position)
else
io.out('Gangue ratio ' + string(gangue_ratio*100, 1) + '% < ' + string(gangue_threshold*100) + '% - gate remains open')
endif
else
io.out('No caving gate found at position ' + string(current_position, 1) + 'm')
endif
command
model cycle 1000
model solve ratio-average 1e-3
end_command
endloop
local total_mined = total_coal_mined + total_gangue_mined
local overall_gangue_ratio = 0.0
local coal_recovery_rate = 0.0
if total_mined > 0.0
overall_gangue_ratio = total_gangue_mined / total_mined
coal_recovery_rate = (total_coal_mined / total_mined) * 100
endif
io.out('')
io.out('===== Stepwise Mining Completed =====')
io.out('Total mining length: ' + string(total_mining_length) + 'm')
io.out('Total steps completed: ' + string(total_steps))
io.out('Total coal mined: ' + string(total_coal_mined, 0) + ' kg')
io.out('Total gangue mined: ' + string(total_gangue_mined, 0) + ' kg')
io.out('Overall gangue ratio: ' + string(overall_gangue_ratio*100, 1) + '%')
io.out('Coal recovery rate: ' + string(coal_recovery_rate, 1) + '%')
else
io.out('*** EQUILIBRIUM NOT ACHIEVED - MINING CANNOT START ***')
io.out('Current ratio: ' + string(current_ratio, 6) + ' > 1e-3')
endif
io.out('===============================================')
end
fish define debug_caving_gates
io.out('===== Debug: Caving Gates Information =====')
local gate_count = 0
loop foreach wp wall.list
if wall.group(wp) == 'caving_gate'
gate_count = gate_count + 1
local wall_pos = wall.pos(wp)
local wall_x = wall_pos->x
local wall_center_x = wall_x + 0.75
io.out('Gate ' + string(gate_count) + ': wall_x=' + string(wall_x, 1) + 'm, center=' + string(wall_center_x, 1) + 'm, ID=' + string(wall.id(wp)))
endif
endloop
io.out('Total caving gates found: ' + string(gate_count))
io.out('===============================================')
end
fish define open_caving_gate(position)
local gate_opened = false
local gate_tolerance = 1.0
io.out('Looking for caving gate near position: ' + string(position, 1) + 'm')
loop foreach wp wall.list
if wall.group(wp) == 'caving_gate'
local wall_pos = wall.pos(wp)
local wall_x = wall_pos->x
local wall_center_x = wall_x + 0.6
io.out('Found caving gate at wall_x=' + string(wall_x, 1) + 'm, center=' + string(wall_center_x, 1) + 'm')
if math.abs(wall_center_x - position) <= gate_tolerance
command
wall delete range id [wall.id(wp)]
end_command
gate_opened = true
io.out('*** CAVING GATE OPENED *** 1.2m opening created at position ' + string(position, 1) + 'm')
io.out('Wall ID ' + string(wall.id(wp)) + ' deleted - gate is now open!')
break
endif
endif
endloop
if not gate_opened
io.out('No caving gate found near position ' + string(position, 1) + 'm')
endif
[return_value] = gate_opened
end
fish define close_caving_gate(position)
local gate_closed = false
local gate_tolerance = 0.3 ; Tolerance for gate position matching
; Note: In this implementation, gates are deleted when opened
; Closing would require recreating the gate wall
; For simplicity, we just mark as closed
gate_closed = true
io.out('Closed caving gate at position ' + string(position, 1) + 'm')
[return_value] = gate_closed
end
fish define calculate_discharged_coal_mass
local discharged_mass = 0.0
loop foreach bp ball.list
local pos = ball.pos(bp)
local py = pos->y
; Check if ball is below support level (discharged)
if py < support_top_height
local ball_group = ball.group(bp)
if ball_group == 'top_coal' or ball_group == 'immediate_roof'
if ball.density(bp) <= 1400 ; Coal density threshold
local ball_mass = ball.mass(bp)
if ball_mass > 0.0
discharged_mass = discharged_mass + ball_mass
ball.group(bp) = 'discharged_coal'
endif
endif
endif
endif
endloop
[return_value] = discharged_mass
end
fish define calculate_discharged_gangue_mass
local discharged_mass = 0.0
loop foreach bp ball.list
local pos = ball.pos(bp)
local py = pos->y
; Check if ball is below support level (discharged)
if py < support_top_height
local ball_group = ball.group(bp)
if ball_group == 'top_coal' or ball_group == 'immediate_roof'
if ball.density(bp) >= 2500 ; Gangue density threshold
local ball_mass = ball.mass(bp)
if ball_mass > 0.0
discharged_mass = discharged_mass + ball_mass
ball.group(bp) = 'discharged_gangue'
endif
endif
endif
endif
endloop
[return_value] = discharged_mass
end
fish define calculate_mass_statistics
io.out('===== Mass Statistics =====')
local total_coal_mass = 0.0
local total_gangue_mass = 0.0
local caved_coal_mass = 0.0
local caved_gangue_mass = 0.0
loop foreach bp ball.list
local ball_density = ball.density(bp)
local ball_mass = ball.mass(bp)
local ball_group = ball.group(bp)
if ball_mass > 0.0
if ball_density <= 1400
total_coal_mass = total_coal_mass + ball_mass
if ball_group == 'caved_coal'
caved_coal_mass = caved_coal_mass + ball_mass
endif
else
if ball_density >= 2500
total_gangue_mass = total_gangue_mass + ball_mass
if ball_group == 'caved_gangue'
caved_gangue_mass = caved_gangue_mass + ball_mass
endif
endif
endif
endif
endloop
local caving_area = caving_gates * support_width
io.out('Original mass:')
io.out(' Total coal: ' + string(total_coal_mass, 0) + ' kg')
io.out(' Total gangue: ' + string(total_gangue_mass, 0) + ' kg')
io.out('')
io.out('Caved mass:')
io.out(' Caved coal: ' + string(caved_coal_mass, 0) + ' kg')
io.out(' Caved gangue: ' + string(caved_gangue_mass, 0) + ' kg')
io.out('')
io.out('Caving area: ' + string(caving_area, 1) + ' m2')
if total_coal_mass > 0.0
io.out('Coal recovery rate: ' + string((caved_coal_mass/total_coal_mass)*100, 1) + '%')
else
io.out('Coal recovery rate: 0% (no coal mass)')
endif
if total_gangue_mass > 0.0
io.out('Gangue recovery rate: ' + string((caved_gangue_mass/total_gangue_mass)*100, 1) + '%')
else
io.out('Gangue recovery rate: 0% (no gangue mass)')
endif
io.out('')
io.out('Mass per unit area:')
if caving_area > 0.0
io.out(' Coal: ' + string(caved_coal_mass/caving_area, 1) + ' kg/m2')
io.out(' Gangue: ' + string(caved_gangue_mass/caving_area, 1) + ' kg/m2')
io.out(' Total: ' + string((caved_coal_mass+caved_gangue_mass)/caving_area, 1) + ' kg/m2')
else
io.out(' Mass per unit area: 0 kg/m2 (no caving area)')
endif
io.out('===============================================')
end
; ========================================
; ========================================
fish define print_simulation_info
io.out('Longwall Mining Simulation Started')
io.out('Model parameters:')
io.out(' Bottom coal height: ' + string(bottom_coal_height) + 'm (Cutting)')
io.out(' Top coal height: ' + string(top_coal_height) + 'm (Caving)')
io.out(' Total coal height: ' + string(total_coal_height) + 'm')
io.out(' Gangue layers: ' + string(gangue_layers) + ' layers')
io.out(' Immediate roof: ' + string(immediate_roof_thickness) + 'm Siltstone')
io.out(' Main roof: ' + string(main_roof_thickness) + 'm Fine Sandstone')
io.out(' Support layout: ' + string(total_support_num) + ' frames total')
io.out(' Head supports: ' + string(head_support_num) + ' frames (no caving)')
io.out(' Middle supports: ' + string(support_num) + ' frames (with caving)')
io.out(' Caving gates: ' + string(caving_gates) + ' (1 per middle support)')
io.out(' Gangue threshold: ' + string(gangue_threshold*100) + ' percent')
io.out('==============================================')
local total_mined = total_coal_mass + total_gangue_mass
if total_mined > 0.0
io.out('===== Simulation Completed =====')
io.out('Final results:')
io.out(' Total coal mined: ' + string(total_coal_mass, 0) + 'kg')
io.out(' Total gangue mined: ' + string(total_gangue_mass, 0) + 'kg')
io.out(' Recovery rate: ' + string((total_coal_mass/total_mined)*100, 1) + '%')
else
io.out('===== Simulation Completed =====')
io.out('Final results:')
io.out(' Total coal mined: ' + string(total_coal_mass, 0) + 'kg')
io.out(' Total gangue mined: ' + string(total_gangue_mass, 0) + 'kg')
io.out(' Recovery rate: 0% (no material mined)')
endif
io.out('================================')
end
[print_simulation_info]
[create_supports]
[generate_bottom_coal]
[generate_top_coal]
[generate_immediate_roof]
[balance_model]
[set_contact_parameters]
[reduce_damping_for_flow]
[visualize_layers]
[debug_caving_gates]
[stepwise_coal_mining]
[calculate_mass_statistics]
fish define calculate_coal_statistics
io.out('===== Coal Mining Results =====')
local total_top_coal_mass = 0.0
local total_gangue_mass = 0.0
local discharged_coal_mass = 0.0
local discharged_gangue_mass = 0.0
loop foreach bp ball.list
local ball_density = ball.density(bp)
local ball_mass = ball.mass(bp)
local ball_group = ball.group(bp)
if ball_mass > 0.0
if ball_group == 'top_coal'
total_top_coal_mass = total_top_coal_mass + ball_mass
else
if ball_group == 'immediate_roof'
total_gangue_mass = total_gangue_mass + ball_mass
else
if ball_group == 'discharged_coal'
discharged_coal_mass = discharged_coal_mass + ball_mass
else
if ball_group == 'discharged_gangue'
discharged_gangue_mass = discharged_gangue_mass + ball_mass
endif
endif
endif
endif
endif
endloop
local total_coal_mass = total_top_coal_mass
local total_discharged_mass = discharged_coal_mass + discharged_gangue_mass
io.out('===== Original Coal Reserves =====')
io.out('Top coal mass: ' + string(total_top_coal_mass, 0) + ' kg')
io.out('Gangue mass: ' + string(total_gangue_mass, 0) + ' kg')
io.out('Total coal reserves: ' + string(total_coal_mass, 0) + ' kg')
io.out('')
io.out('===== Mining Production =====')
io.out('Coal mined: ' + string(discharged_coal_mass, 0) + ' kg')
io.out('Gangue mined: ' + string(discharged_gangue_mass, 0) + ' kg')
io.out('Total mined: ' + string(total_discharged_mass, 0) + ' kg')
io.out('')
local coal_recovery_rate = 0.0
local gangue_discharge_rate = 0.0
local gangue_ratio = 0.0
local mining_efficiency = 0.0
if total_coal_mass > 0.0
coal_recovery_rate = (discharged_coal_mass / total_coal_mass) * 100
endif
if total_gangue_mass > 0.0
gangue_discharge_rate = (discharged_gangue_mass / total_gangue_mass) * 100
endif
if total_discharged_mass > 0.0
gangue_ratio = (discharged_gangue_mass / total_discharged_mass) * 100
mining_efficiency = (discharged_coal_mass / total_discharged_mass) * 100
endif
io.out('===== Key Performance Indicators =====')
io.out('Coal recovery rate: ' + string(coal_recovery_rate, 1) + '%')
io.out('Gangue discharge rate: ' + string(gangue_discharge_rate, 1) + '%')
io.out('Gangue ratio in production: ' + string(gangue_ratio, 1) + '%')
io.out('Mining efficiency: ' + string(mining_efficiency, 1) + '%')
io.out('')
io.out('===== Economic Indicators =====')
local coal_volume = total_coal_mass / 1360.0
local mined_volume = total_discharged_mass / 1500.0
io.out('Coal volume: ' + string(coal_volume, 1) + ' m3')
io.out('Mined volume: ' + string(mined_volume, 1) + ' m3')
io.out('')
io.out('===== Summary =====')
if gangue_ratio <= 5.0
io.out('Mining successful: Gangue ratio ' + string(gangue_ratio, 1) + '% <= 5%')
else
io.out('Mining stopped: Gangue ratio ' + string(gangue_ratio, 1) + '% > 5%')
endif
if coal_recovery_rate >= 80.0
io.out('Good recovery: ' + string(coal_recovery_rate, 1) + '% >= 80%')
else
io.out('Low recovery: ' + string(coal_recovery_rate, 1) + '% < 80%')
endif
io.out('===============================================')
end
fish define control_particle_numbers
io.out('===== Particle Number Control =====')
io.out('Total particles will be limited to 2,000')
io.out('Model dimensions:')
io.out(' Total width: ' + string(model_width) + 'm')
io.out(' Effective mining width: 60.0m (X: 3-63m)')
io.out(' Boundary buffer: 6.0m (3m each side)')
io.out(' Total height: 31.4m (Y: 0-31.4m)')
io.out('Layer structure:')
io.out(' Bottom layer: Top coal (15.8m height)')
io.out(' Top layer: Immediate roof (15.6m height)')
io.out('Distribution:')
io.out(' Top coal: 1,000 particles (50%)')
io.out(' Immediate roof: 1,000 particles (50%)')
io.out(' Total: 2,000 particles')
io.out('===============================================')
end
fish define visualize_modeling_process
io.out('===== Modeling Process Visualization =====')
io.out('Step 1: Generating top coal particles...')
io.out('Step 2: Generating immediate roof particles (gangue)...')
io.out('Step 3: Model balancing...')
io.out('Step 4: Sequential caving simulation...')
io.out('Step 5: Results calculation...')
io.out('===============================================')
end
; modeling_sequence function removed - using main execution sequence instead
fish define detailed_mining_report
io.out('===== Detailed Mining Report =====')
local total_particles = 0
local top_coal_particles = 0
local gangue_particles = 0
local discharged_coal_particles = 0
local discharged_gangue_particles = 0
loop foreach bp ball.list
total_particles = total_particles + 1
local ball_group = ball.group(bp)
if ball_group == 'top_coal'
top_coal_particles = top_coal_particles + 1
else
if ball_group == 'immediate_roof'
gangue_particles = gangue_particles + 1
else
if ball_group == 'discharged_coal'
discharged_coal_particles = discharged_coal_particles + 1
else
if ball_group == 'discharged_gangue'
discharged_gangue_particles = discharged_gangue_particles + 1
endif
endif
endif
endif
endloop
io.out('Particle Statistics:')
io.out(' Total particles: ' + string(total_particles))
io.out(' Top coal particles: ' + string(top_coal_particles))
io.out(' Gangue particles: ' + string(gangue_particles))
io.out(' Discharged coal particles: ' + string(discharged_coal_particles))
io.out(' Discharged gangue particles: ' + string(discharged_gangue_particles))
io.out('')
local remaining_coal = top_coal_particles - discharged_coal_particles
local remaining_gangue = gangue_particles - discharged_gangue_particles
io.out('Remaining Particles:')
io.out(' Remaining coal: ' + string(remaining_coal))
io.out(' Remaining gangue: ' + string(remaining_gangue))
io.out(' Total remaining: ' + string(remaining_coal + remaining_gangue))
io.out('===============================================')
end
fish define calculate_mining_area_statistics
io.out('===== Mining Area Statistics =====')
io.out('Total model width: ' + string(model_width) + 'm')
io.out('Boundary buffer (each side): ' + string(boundary_buffer) + 'm')
io.out('Effective mining width: ' + string(effective_mining_width) + 'm')
io.out('Mining area: X = ' + string(mining_start_x) + ' to ' + string(mining_end_x) + 'm')
io.out('Boundary areas (not included in mining statistics):')
io.out(' Left boundary: X = 0 to ' + string(mining_start_x) + 'm')
io.out(' Right boundary: X = ' + string(mining_end_x) + ' to ' + string(model_width) + 'm')
io.out('===============================================')
end
fish define support_position_info
io.out('===== Support Position Information =====')
io.out('Support layout with 3m right offset:')
io.out('')
io.out('Head supports (3 frames):')
io.out(' Support 1: X = 3.0m to 4.5m')
io.out(' Support 2: X = 4.5m to 6.0m')
io.out(' Support 3: X = 6.0m to 7.5m')
io.out('')
io.out('Middle supports (' + string(support_num) + ' frames):')
io.out(' Start position: X = 7.5m')
io.out(' End position: X = ' + string(7.5 + support_num * support_width) + 'm')
io.out(' Spacing: ' + string(support_width) + 'm between frames')
io.out('')
io.out('Tail supports (3 frames):')
local tail_start = 7.5 + support_num * support_width
io.out(' Support 1: X = ' + string(tail_start) + 'm to ' + string(tail_start + 1.5) + 'm')
io.out(' Support 2: X = ' + string(tail_start + 1.5) + 'm to ' + string(tail_start + 3.0) + 'm')
io.out(' Support 3: X = ' + string(tail_start + 3.0) + 'm to ' + string(tail_start + 4.5) + 'm')
io.out('')
io.out('Total support coverage: X = 3.0m to ' + string(tail_start + 4.5) + 'm')
io.out('===============================================')
end
fish define verify_immediate_roof_position
io.out('===== Immediate Roof Position Verification =====')
local particles_in_x_range = 0
local particles_in_y_range = 0
local particles_in_full_range = 0
local particles_out_of_range = 0
local min_x = 1000.0
local max_x = -1000.0
local min_y = 1000.0
local max_y = -1000.0
loop foreach bp ball.list
if ball.group(bp) == 'immediate_roof'
local pos = ball.pos(bp)
local px = pos->x
local py = pos->y
if px >= 3.0 and px <= 63.0
particles_in_x_range = particles_in_x_range + 1
endif
if py >= 0.0 and py <= 31.5
particles_in_y_range = particles_in_y_range + 1
endif
if px >= 3.0 and px <= 63.0 and py >= 0.0 and py <= 31.5
particles_in_full_range = particles_in_full_range + 1
else
particles_out_of_range = particles_out_of_range + 1
endif
if px < min_x
min_x = px
endif
if px > max_x
max_x = px
endif
if py < min_y
min_y = py
endif
if py > max_y
max_y = py
endif
endif
endloop
io.out('Position verification results:')
io.out(' Particles in X range (3-63m): ' + string(particles_in_x_range))
io.out(' Particles in Y range (0-31.5m): ' + string(particles_in_y_range))
io.out(' Particles in full range: ' + string(particles_in_full_range))
io.out(' Particles out of range: ' + string(particles_out_of_range))
io.out(' Actual X range: ' + string(min_x, 2) + ' to ' + string(max_x, 2) + 'm')
io.out(' Actual Y range: ' + string(min_y, 2) + ' to ' + string(max_y, 2) + 'm')
io.out(' Expected X range: 3.0 to 63.0m')
io.out(' Expected Y range: 0.0 to 31.5m')
if particles_out_of_range == 0
io.out('Bouncing prevention activated (particles_out_of_range = 0)')
prevent_bouncing()
command
model cycle 50
model solve ratio-average 1e-3
end_command
loop foreach bp ball.list
ball.vel.x(bp) = 0.0
ball.vel.y(bp) = 0.0
ball.spin(bp) = 0.0
endloop
endif
local overall_gangue_ratio = 0.0
if (total_coal_mass + total_gangue_mass) > 0.0
overall_gangue_ratio = total_gangue_mass / (total_coal_mass + total_gangue_mass)
endif
io.out('===== Single Round Interval Caving Completed =====')
io.out('Caving area: ' + string(caving_area, 1) + ' m2 (17 odd-numbered supports)')
io.out('Total coal mined: ' + string(total_coal_mass, 0) + ' kg')
io.out('Total gangue mined: ' + string(total_gangue_mass, 0) + ' kg')
io.out('Overall gangue ratio: ' + string(overall_gangue_ratio*100, 1) + '%')
io.out('Coal recovery rate: ' + string((total_coal_mass/(total_coal_mass + total_gangue_mass))*100, 1) + '%')
io.out('Interval caving: Only odd-numbered gates (1,3,5,...,33) were processed')
io.out('Boundary areas (6m each end): Particles remain constrained')
io.out('===============================================')
end
; ========================================
; ========================================
fish define fix_boundary_walls
io.out('===== Fixing Boundary Walls =====')
command
wall delete range id 103
wall delete range id 104
end_command
command
wall create vertices 3.0 0 3.0 31.4 id 103
wall attribute velocity-x 0.0 range id 103
end_command
io.out('Left buffer wall (ID 103) created at X=3.0m')
command
wall create vertices 63.0 0 63.0 31.4 id 104
wall attribute velocity-x 0.0 range id 104
end_command
io.out('Right buffer wall (ID 104) created at X=63.0m')
io.out('Boundary walls fixed - particles should be constrained')
io.out('===============================================')
end
fish define check_particle_boundaries
io.out('===== Checking Particle Boundaries =====')
local particles_in_left_buffer = 0
local particles_in_right_buffer = 0
local particles_in_mining_area = 0
local total_particles = 0
loop foreach bp ball.list
total_particles = total_particles + 1
local pos = ball.pos(bp)
local px = pos->x
if px < 3.0
particles_in_left_buffer = particles_in_left_buffer + 1
else
if px > 63.0
particles_in_right_buffer = particles_in_right_buffer + 1
else
particles_in_mining_area = particles_in_mining_area + 1
endif
endif
endloop
io.out('Particle boundary analysis:')
io.out(' Total particles: ' + string(total_particles))
io.out(' Particles in left buffer (X<3.0m): ' + string(particles_in_left_buffer))
io.out(' Particles in mining area (3.0m to 63.0m): ' + string(particles_in_mining_area))
io.out(' Particles in right buffer (X>63.0m): ' + string(particles_in_right_buffer))
if particles_in_left_buffer > 0 or particles_in_right_buffer > 0
io.out('WARNING: Particles found in buffer zones!')
io.out('Boundary walls may not be working properly')
else
io.out('SUCCESS: All particles are in mining area')
endif
io.out('===============================================')
end
fish define enhanced_equilibrium_check
io.out('===== Enhanced Equilibrium Check =====')
local mech_ratio = mech_ratio
io.out('Mechanical ratio: ' + string(mech_ratio, 6))
local total_ke = 0.0
loop foreach bp ball.list
local vel = ball.vel(bp)
local mass = ball.mass(bp)
total_ke = total_ke + 0.5 * mass * (vel->x^2 + vel->y^2)
endloop
io.out('Total kinetic energy: ' + string(total_ke, 6))
local is_equilibrium = false
if mech_ratio <= 1e-3 and total_ke < 1e-6
is_equilibrium = true
endif
if is_equilibrium
io.out('SUCCESS: System is in equilibrium!')
else
io.out('WARNING: System not in equilibrium')
if mech_ratio > 1e-3
io.out(' - Mechanical ratio too high: ' + string(mech_ratio, 6))
endif
if total_ke > 1e-6
io.out(' - Kinetic energy too high: ' + string(total_ke, 6))
endif
endif
io.out('===============================================')
[return_value] = is_equilibrium
end对代码进行分析
最新发布