def test_spawn_location_1(self): """ Base case: moving Node. Also the prototype should follow the movement. This should be done automatically when calling MarbleEmitterNode.emit(). Using a MarbleEmitterVariablePosition. """ vel = torch.tensor([1.0]) radius = 10 eps = 10e-5 prototype = Marble(ZERO, ZERO, ZERO, 0, None, None, 0, 0, 0, 0) emitter = MarbleEmitterVariablePosition(prototype, 0, 10, rel_prototype_pos=torch.tensor( [radius + eps])) emitter_node = MarbleEmitterNode(ZERO, vel, ZERO, 0, None, 0, 0, 0, 0, radius=radius, emitter=emitter) emitter_node.update_movement(1) self.assertTrue(check_close(emitter_node.pos, torch.tensor([1.0]))) expected_marble_pos = torch.tensor([1.0]) + radius + eps self.assertTrue( check_close(emitter_node.emit().pos, expected_marble_pos))
def test_spawn_location_2(self): """ Base case: stationary Node. Using a normal MarbleEmitter. """ vel = torch.tensor([1.0]) radius = 10 eps = 10e-5 prototype = Marble(ZERO + radius + eps, ZERO, ZERO, 0, None, None, 0, 0, 0, 0) emitter = MarbleEmitter(prototype, 0, 10) emitter_node = MarbleEmitterNode(ZERO, vel, ZERO, 0, None, 0, 0, 0, 0, radius=radius, emitter=emitter) self.assertTrue(check_close(emitter_node.pos, ZERO)) self.assertTrue(check_close(emitter.emit().pos, ZERO + radius + eps))
def test_reset(self): # Node and Marble have some arbitrary nonzero initial motion vars. node = Node(torch.tensor([1.]), torch.tensor([2.]), torch.tensor([3.]), 4, NewtonianGravity(), 1, 1, 1, 1) marble = Marble(torch.tensor([1.1]), torch.tensor([2.2]), torch.tensor([3.3]), 4.4, NewtonianGravity(), None) model = NenwinModel([node], [marble]) model.make_timestep(10) model.make_timestep(10) model.make_timestep(10) # Verify that the motion variables have changed self.assertFalse(check_close(node.pos, node.init_pos)) self.assertFalse(check_close(marble.vel, marble.init_vel)) self.assertFalse(check_close(marble.acc, marble.init_acc)) model.reset() # Now they should be the original values again. self.assertTrue(check_close(node.pos, node.init_pos)) self.assertTrue(check_close(node.vel, node.init_vel)) self.assertTrue(check_close(node.acc, node.init_acc)) self.assertTrue(check_close(marble.pos, marble.init_pos)) self.assertTrue(check_close(marble.vel, marble.init_vel)) self.assertTrue(check_close(marble.acc, marble.init_acc))
def test_copy(self): pos = torch.tensor([-10, -100], dtype=torch.float) vel = torch.tensor([0, 0], dtype=torch.float) acc = torch.tensor([0, 0], dtype=torch.float) original = Particle(pos, vel, acc) copy = original.copy() self.assertFalse(copy is original) self.assertTrue(check_close(acc, copy.acc)) self.assertTrue(check_close(vel, copy.vel)) self.assertTrue(check_close(pos, copy.pos))
def test_movement_3(self): """ Corner case: no vel and no acc => no movement. """ pos = torch.tensor([-10, -100], dtype=torch.float) vel = torch.tensor([0, 0], dtype=torch.float) acc = torch.tensor([0, 0], dtype=torch.float) p = Particle(pos, vel, acc) for _ in range(100): p.update_movement(0.01) expected = runge_kutta_4_step(pos, vel, acc) self.assertTrue(check_close(acc, p.acc)) self.assertTrue(check_close(vel, p.vel)) self.assertTrue(check_close(pos, p.pos))
def test_movement_2(self): """ Base case: deacceleration. """ pos = torch.tensor([-10, -100], dtype=torch.float) vel = torch.tensor([100, 1000], dtype=torch.float) acc = torch.tensor([0, -91], dtype=torch.float) p = Particle(pos, vel, acc) for _ in range(100): p.update_movement(0.01) expected = runge_kutta_4_step(pos, vel, acc) self.assertTrue(check_close(expected[1], p.vel)) self.assertTrue(check_close(expected[0], p.pos)) # Should not have changed self.assertTrue(check_close(acc, p.acc))
def test_output_1(self): """ Base case: 3 Eater nodes with different eat counts. """ marbles_eaten_per_node = [10, 20, 0] model = MockModel(marbles_eaten_per_node) result = self.output_reader.read_output(model) expected = np.array(marbles_eaten_per_node) self.assertTrue(check_close(result, expected))
def test_output_2(self): """ Corner case: no eater nodes in the model present. """ marbles_eaten_per_node = [] model = MockModel(marbles_eaten_per_node) result = self.output_reader.read_output(model) expected = np.array(marbles_eaten_per_node) self.assertTrue(check_close(result, expected))
def test_copy(self): """ Copy should use the initial values for position, velocity and acceleration. """ pos = torch.tensor([-10, -100], dtype=torch.float) vel = torch.tensor([1, 10], dtype=torch.float) acc = torch.tensor([10, 1], dtype=torch.float) original = InitialValueParticle(pos, vel, acc) original.update_movement(time_passed=10) copy = original.copy() self.assertFalse(copy is original) self.assertTrue(check_close(acc, copy.acc)) self.assertTrue(check_close(vel, copy.vel)) self.assertTrue(check_close(pos, copy.pos))
def test_distance_1(self): """ Base case: 2 nodes at different positions. """ pos1 = np.array([1, 0, 0]) pos2 = np.array([2, 0, 0]) zero_vect = np.array([0, 0, 0]) p1 = Particle(pos1, zero_vect, zero_vect) p2 = Particle(pos2, zero_vect, zero_vect) expected = 1 self.assertTrue(check_close(distance(p1, p2), expected))
def test_output_4(self): """ Base case: node close but not within eater, becomes pulled in. """ zero = np.array([0]) eater = MarbleEaterNode(zero, zero, zero, 100, self.attract_funct, 1, 10) marble = Marble(np.array([11]), zero, zero, 1, self.attract_funct, None) model = NumMarblesEatenAsOutputModel([eater], 1, [marble]) model.run(1) result = model._produce_outputs() expected = np.array([0]) self.assertTrue(check_close(result, expected)) model.run(10) result = model._produce_outputs() expected = np.array([1]) self.assertTrue(check_close(result, expected))
def test_output_2(self): """ Corner case: no eaternodes, empty array as output. """ zero = np.array([0]) marble = Marble(np.array([9]), zero, zero, 1, self.attract_funct, None) model = NumMarblesEatenAsOutputModel([], 1, [marble]) model.run(1) result = model._produce_outputs() expected = np.array([]) self.assertTrue(check_close(result, expected))
def test_distance_2(self): """ Corner case: 2 nodes at same positions. """ pos1 = np.array([9, 8, 70.5]) pos2 = np.array([9, 8, 70.5]) zero_vect = np.array([0, 0, 0]) p1 = Particle(pos1, zero_vect, zero_vect) p2 = Particle(pos2, zero_vect, zero_vect) expected = 0 self.assertTrue(check_close(distance(p1, p2), expected))
def test_copy(self): """ Check if the copy has the same values as the original. Base case: original still has init values. """ (prototype, delay, stored_mass, initial_time_passed, rel_prototype_pos, emitter) = self.set_up_full_emitter() copy = emitter.copy() self.assertIsInstance(copy, MarbleEmitterVariablePosition) self.assertAlmostEqual(copy.init_stored_mass, stored_mass) self.assertAlmostEqual(copy.init_time_passed, initial_time_passed) self.assertAlmostEqual(copy.delay, delay) self.assertTrue(check_close(copy.rel_prototype_pos, rel_prototype_pos)) self.assertIs(copy.prototype.init_pos, prototype.init_pos)
def test_distance_3(self): """ Corner case: 2 nodes at different position that differ in multiple dimensions. """ pos1 = np.array([1, 1, 1]) pos2 = np.array([-1, -1, -1]) zero_vect = np.array([0, 0, 0]) p1 = Particle(pos1, zero_vect, zero_vect) p2 = Particle(pos2, zero_vect, zero_vect) expected = np.sqrt(3 * 2**2) self.assertTrue(check_close(distance(p1, p2), expected))
def test_output_1(self): """ Base case: single marble created within radius of eater node, should become output after 1 step. """ zero = np.array([0]) eater = MarbleEaterNode(zero, zero, zero, 10, self.attract_funct, 1, 10) marble = Marble(np.array([9]), zero, zero, 1, self.attract_funct, None) model = NumMarblesEatenAsOutputModel([eater], 1, [marble]) model.run(1) result = model._produce_outputs() expected = np.array([1]) self.assertTrue(check_close(result, expected))
def test_copy_acc_with_grad(self): """ Gradients of initial accelerations should be copied as well. """ some_particle = setup_simple_particle() some_tensor = torch.tensor([4.0], requires_grad=True) loss = torch.sum(some_particle.acc + some_tensor) loss.backward() self.assertIsNotNone(some_particle.init_acc.grad) self.assertIsNotNone(some_tensor.grad) another_particle = some_particle.copy() self.assertTrue( check_close(some_particle.init_acc.grad, another_particle.init_acc.grad))
def test_output_3(self): """ Base case: single marble created outside radius of eater node, and not cominig close. Output should remain 0. """ zero = np.array([0]) eater = MarbleEaterNode(zero, zero, zero, 10, self.attract_funct, 1, 10) # Moving too fast to be pulled back. marble = Marble(np.array([11]), np.array([100]), zero, 1, self.attract_funct, None) model = NumMarblesEatenAsOutputModel([eater], 1, [marble]) model.run(1) result = model._produce_outputs() expected = np.array([0]) self.assertTrue(check_close(result, expected))