Simulating particle collision - Says something is nil when it's not

-- Define initial particle properties
local particle1 = {
	mass = 1.007276, -- in atomic mass units (amu)
	charge = 1, -- in elementary charge units (e)
	position = { x = 0, y = 0, z = 0 }, -- in meters (m)
	velocity = { x = 0, y = 0, z = 0 } -- in meters per second (m/s)
}

local particle2 = {
	mass = 0.00054858, -- in atomic mass units (amu)
	charge = -1, -- in elementary charge units (e)
	position = { x = 1, y = 0, z = 0 }, -- in meters (m)
	velocity = { x = 1000, y = 0, z = 0 } -- in meters per second (m/s)
}


-- Define simulation parameters
local time_step = 0.00001 -- in seconds (s)
local simulation_time = 0.0001 -- in seconds (s)

-- Define physical constants
local c = 299792458 -- speed of light in meters per second (m/s)
local e = 1.602176634e-19 -- elementary charge in coulombs (C)
local amu = 1.66053906660e-27 -- atomic mass unit in kilograms (kg)
local proton_mass = 1.00727647 * amu -- mass of a proton in kilograms (kg)

-- Define function to calculate Lorentz force
local function lorentz_force(particle, electric_field, magnetic_field)
	local force = { x = 0, y = 0, z = 0 }
	force.x = particle.charge * (electric_field.x + particle.velocity.y * magnetic_field.z - particle.velocity.z * magnetic_field.y)
	force.y = particle.charge * (electric_field.y + particle.velocity.z * magnetic_field.x - particle.velocity.x * magnetic_field.z)
	force.z = particle.charge * (electric_field.z + particle.velocity.x * magnetic_field.y - particle.velocity.y * magnetic_field.x)
	return force
end

-- Define function to simulate particle motion
function simulate_collision(particle1, particle2, time_step)
	local epsilon_0 = 8.854e-12
	local r = {
		x = particle2.position.x - particle1.position.x,
		y = particle2.position.y - particle1.position.y,
		z = particle2.position.z - particle1.position.z
	}
	local distance = math.sqrt(r.x^2 + r.y^2 + r.z^2)
	local force_magnitude = particle1.charge * particle2.charge / (4 * math.pi * epsilon_0 * distance^2)
	local force = {
		x = force_magnitude * r.x / distance,
		y = force_magnitude * r.y / distance,
		z = force_magnitude * r.z / distance
	}
	local acceleration1 = {
		x = force.x / particle1.mass,
		y = force.y / particle1.mass,
		z = force.z / particle1.mass
	}
	local acceleration2 = {
		x = -force.x / particle2.mass,
		y = -force.y / particle2.mass,
		z = -force.z / particle2.mass
	}
	particle1.acceleration = acceleration1
	particle2.acceleration = acceleration2

	local collision_info = {
		new_particles = nil,
		stuck = false
	}

	-- Check if particles collide
	if distance < (1.2 * (particle1.mass^(1/3) + particle2.mass^(1/3))) then
		print("Particles collided.")
		local total_mass = particle1.mass + particle2.mass
		local momentum1 = {
			x = particle1.mass * particle1.velocity.x,
			y = particle1.mass * particle1.velocity.y,
			z = particle1.mass * particle1.velocity.z
		}
		local momentum2 = {
			x = particle2.mass * particle2.velocity.x,
			y = particle2.mass * particle2.velocity.y,
			z = particle2.mass * particle2.velocity.z
		}
		local total_momentum = {
			x = momentum1.x + momentum2.x,
			y = momentum1.y + momentum2.y,
			z = momentum1.z + momentum2.z
		}
		local velocity = {
			x = total_momentum.x / total_mass,
			y = total_momentum.y / total_mass,
			z = total_momentum.z / total_mass
		}
		local new_particle = {
			mass = total_mass,
			charge = particle1.charge + particle2.charge,
			position = {
				x = particle1.position.x,
				y = particle1.position.y,
				z = particle1.position.z
			},
			velocity = velocity,
			acceleration = {
				x = 0,
				y = 0,
				z = 0
			}
		}
		print("New particle created with mass " .. new_particle.mass ..
			", charge " .. new_particle.charge ..
			", velocity (" .. new_particle.velocity.x .. ", " ..
			new_particle.velocity.y .. ", " .. new_particle.velocity.z ..
			"), and position (" .. new_particle.position.x .. ", " ..
			new_particle.position.y .. ", " .. new_particle.position.z .. ").")
		collision_info.new_particles = { new_particle }
		collision_info.stuck = true
	end

	return collision_info
end

-- Start simulation
local particles = {particle1, particle2}
for i = 1, simulation_time / time_step do
	local electric_field = {
		x = 0,
		y = 0,
		z = 0
	}
	local magnetic_field = {
		x = 0,
		y = 0,
		z = 0
	}
	-- Simulate collision between the two particles
	local particles, collision_info = simulate_collision(particles[1], particles[2], time_step)

	-- Check if the particles stuck together after the collision
	if collision_info.stuck then
		print("Particles stuck together.")
		break
	end

	-- Check if new particles were created after the collision
	if collision_info.new_particles then
		print("New particles created: " .. tostring(#collision_info.new_particles))
		for _, new_particle in ipairs(collision_info.new_particles) do
			table.insert(particles, new_particle)
		end
	end

	-- Update the velocity and position of each particle
	for _, particle in ipairs(particles) do
		particle.velocity.x = particle.velocity.x + particle.acceleration.x * time_step
		particle.velocity.y = particle.velocity.y + particle.acceleration.y * time_step
		particle.velocity.z = particle.velocity.z + particle.acceleration.z * time_step

		particle.position.x = particle.position.x + particle.velocity.x * time_step
		particle.position.y = particle.position.y + particle.velocity.y * time_step
		particle.position.z = particle.position.z + particle.velocity.z * time_step
	end

	-- Update the electric and magnetic fields
	local observation_point = {
		x = 0,
		y = 0,
		z = 0
	}
	local observation_velocity = {
		x = 0,
		y = 0,
		z = 0
	}
	for _, particle in ipairs(particles) do
		local r = {
			x = particle.position.x - observation_point.x,
			y = particle.position.y - observation_point.y,
			z = particle.position.z - observation_point.z
		}
		local distance = math.sqrt(r.x^2 + r.y^2 + r.z^2)
		local force_magnitude = particle.charge / (4 * math.pi * epsilon_0 * distance^2)
		local force = {
			x = force_magnitude * r.x / distance,
			y = force_magnitude * r.y / distance,
			z = force_magnitude * r.z / distance
		}
		local velocity = {
			x = particle.velocity.x - observation_velocity.x,
			y = particle.velocity.y - observation_velocity.y,
			z = particle.velocity.z - observation_velocity.z
		}
		local magnetic_force = {
			x = particle.charge * (velocity.y * force.z - velocity.z * force.y),
			y = particle.charge * (velocity.z * force.x - velocity.x * force.z),
			z = particle.charge * (velocity.x * force.y - velocity.y * force.x)
		}
		electric_field.x = electric_field.x + force.x
		electric_field.y = electric_field.y + force.y
		electric_field.z = electric_field.z + force.z
		magnetic_field.x = magnetic_field.x + magnetic_force.x
		magnetic_field.y = magnetic_field.y + magnetic_force.y
		magnetic_field.z = magnetic_field.z + magnetic_force.z
	end

	return electric_field, magnetic_field
end

Error:

  13:26:17.545  Stack Begin  -  Studio
  13:26:17.545  Script 'ServerScriptService.Shared.Particle Simulations', Line 138  -  Studio - Particle Simulations:138
  13:26:17.545  Stack End  -  Studio

Stuck was already defined as per line 66:

	stuck = false

and line 115:

	collision_info.stuck = true

But it still believes it’s nil on line 144:

if collision_info.stuck then
1 Like

You’re returning one type and asking for two in your variable

local particles, collision_info = simulate_collision(particles[1], particles[2], time_step)

This asks for two, and your returning one:

return collision_info

So, what is supposed to collision_info is defaulting to the variable ‘particles’ and collision_info itself is just nil since you only return one.

1 Like

Updated and FUNCTIONING script for anyone that wants to use my particle collision simulator:


-- Define initial particle properties
local particle1 = {
	mass = 1.007276, -- in atomic mass units (amu)
	charge = 1, -- in elementary charge units (e)
	position = { x = 0, y = 0, z = 0 }, -- in meters (m)
	velocity = { x = 0, y = 0, z = 0 } -- in meters per second (m/s)
}

local particle2 = {
	mass = 0.00054858, -- in atomic mass units (amu)
	charge = -1, -- in elementary charge units (e)
	position = { x = 1, y = 0, z = 0 }, -- in meters (m)
	velocity = { x = 1000, y = 0, z = 0 } -- in meters per second (m/s)
}


-- Define simulation parameters
local time_step = 0.00001 -- in seconds (s)
local simulation_time = 0.0001 -- in seconds (s)

-- Define physical constants
local c = 299792458 -- speed of light in meters per second (m/s)
local e = 1.602176634e-19 -- elementary charge in coulombs (C)
local amu = 1.66053906660e-27 -- atomic mass unit in kilograms (kg)
local proton_mass = 1.00727647 * amu -- mass of a proton in kilograms (kg)

-- Define function to calculate Lorentz force
local function lorentz_force(particle, electric_field, magnetic_field)
	local force = { x = 0, y = 0, z = 0 }
	force.x = particle.charge * (electric_field.x + particle.velocity.y * magnetic_field.z - particle.velocity.z * magnetic_field.y)
	force.y = particle.charge * (electric_field.y + particle.velocity.z * magnetic_field.x - particle.velocity.x * magnetic_field.z)
	force.z = particle.charge * (electric_field.z + particle.velocity.x * magnetic_field.y - particle.velocity.y * magnetic_field.x)
	return force
end

-- Define function to simulate particle motion
local particles = {particle1, particle2}
function simulate_collision(particle1, particle2, time_step)
	local epsilon_0 = 8.854e-12
	local r = {
		x = particle2.position.x - particle1.position.x,
		y = particle2.position.y - particle1.position.y,
		z = particle2.position.z - particle1.position.z
	}
	local distance = math.sqrt(r.x^2 + r.y^2 + r.z^2)
	local force_magnitude = particle1.charge * particle2.charge / (4 * math.pi * epsilon_0 * distance^2)
	local force = {
		x = force_magnitude * r.x / distance,
		y = force_magnitude * r.y / distance,
		z = force_magnitude * r.z / distance
	}
	local acceleration1 = {
		x = force.x / particle1.mass,
		y = force.y / particle1.mass,
		z = force.z / particle1.mass
	}
	local acceleration2 = {
		x = -force.x / particle2.mass,
		y = -force.y / particle2.mass,
		z = -force.z / particle2.mass
	}
	particle1.acceleration = acceleration1
	particle2.acceleration = acceleration2

	local collision_info = {
		new_particles = nil,
		stuck = false
	}

	-- Check if particles collide
	if distance < (1.2 * (particle1.mass^(1/3) + particle2.mass^(1/3))) then
		print("Particles collided.")
		local total_mass = particle1.mass + particle2.mass
		local momentum1 = {
			x = particle1.mass * particle1.velocity.x,
			y = particle1.mass * particle1.velocity.y,
			z = particle1.mass * particle1.velocity.z
		}
		local momentum2 = {
			x = particle2.mass * particle2.velocity.x,
			y = particle2.mass * particle2.velocity.y,
			z = particle2.mass * particle2.velocity.z
		}
		local total_momentum = {
			x = momentum1.x + momentum2.x,
			y = momentum1.y + momentum2.y,
			z = momentum1.z + momentum2.z
		}
		local velocity = {
			x = total_momentum.x / total_mass,
			y = total_momentum.y / total_mass,
			z = total_momentum.z / total_mass
		}
		local new_particle = {
			mass = total_mass,
			charge = particle1.charge + particle2.charge,
			position = {
				x = particle1.position.x,
				y = particle1.position.y,
				z = particle1.position.z
			},
			velocity = velocity,
			acceleration = {
				x = 0,
				y = 0,
				z = 0
			}
		}
		print("New particle created with mass " .. new_particle.mass ..
			", charge " .. new_particle.charge ..
			", velocity (" .. new_particle.velocity.x .. ", " ..
			new_particle.velocity.y .. ", " .. new_particle.velocity.z ..
			"), and position (" .. new_particle.position.x .. ", " ..
			new_particle.position.y .. ", " .. new_particle.position.z .. ").")
		collision_info.new_particles = { new_particle }
		collision_info.stuck = true
	end

	return particles, collision_info
end

-- Start simulation
for i = 1, simulation_time / time_step do
	local electric_field = {
		x = 0,
		y = 0,
		z = 0
	}
	local magnetic_field = {
		x = 0,
		y = 0,
		z = 0
	}
	-- Simulate collision between the two particles
	local particles, collision_info = simulate_collision(particles[1], particles[2], time_step)

	-- Check if the particles stuck together after the collision
	if collision_info.stuck then
		print("Particles stuck together.")
		break
	end

	-- Check if new particles were created after the collision
	if collision_info.new_particles then
		print("New particles created: " .. tostring(#collision_info.new_particles))
		for _, new_particle in ipairs(collision_info.new_particles) do
			table.insert(particles, new_particle)
		end
	end

	-- Update the velocity and position of each particle
	for _, particle in ipairs(particles) do
		particle.velocity.x = particle.velocity.x + particle.acceleration.x * time_step
		particle.velocity.y = particle.velocity.y + particle.acceleration.y * time_step
		particle.velocity.z = particle.velocity.z + particle.acceleration.z * time_step

		particle.position.x = particle.position.x + particle.velocity.x * time_step
		particle.position.y = particle.position.y + particle.velocity.y * time_step
		particle.position.z = particle.position.z + particle.velocity.z * time_step
	end

	-- Update the electric and magnetic fields
	local observation_point = {
		x = 0,
		y = 0,
		z = 0
	}
	local observation_velocity = {
		x = 0,
		y = 0,
		z = 0
	}
	for _, particle in ipairs(particles) do
		local r = {
			x = particle.position.x - observation_point.x,
			y = particle.position.y - observation_point.y,
			z = particle.position.z - observation_point.z
		}
		local distance = math.sqrt(r.x^2 + r.y^2 + r.z^2)
		local force_magnitude = particle.charge / (4 * math.pi * epsilon_0 * distance^2)
		local force = {
			x = force_magnitude * r.x / distance,
			y = force_magnitude * r.y / distance,
			z = force_magnitude * r.z / distance
		}
		local velocity = {
			x = particle.velocity.x - observation_velocity.x,
			y = particle.velocity.y - observation_velocity.y,
			z = particle.velocity.z - observation_velocity.z
		}
		local magnetic_force = {
			x = particle.charge * (velocity.y * force.z - velocity.z * force.y),
			y = particle.charge * (velocity.z * force.x - velocity.x * force.z),
			z = particle.charge * (velocity.x * force.y - velocity.y * force.x)
		}
		electric_field.x = electric_field.x + force.x
		electric_field.y = electric_field.y + force.y
		electric_field.z = electric_field.z + force.z
		magnetic_field.x = magnetic_field.x + magnetic_force.x
		magnetic_field.y = magnetic_field.y + magnetic_force.y
		magnetic_field.z = magnetic_field.z + magnetic_force.z
	end

	return electric_field, magnetic_field
end
1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.