def test_actuator_force_can_be_used(square_lattice: Lattice): """make sure force-based protocol can be called""" actuator = Actuator(lattice=square_lattice, frozen_nodes=[2, 3], input_nodes=[0], input_vectors=np.array([[0.1, 0.2]]), output_nodes=[1], output_vectors=np.array([ [0.3, 0.4], ]), method="force") actuator.act()
def render(self, save_path="image.png"): dir_name = os.path.dirname(save_path) if not os.path.exists(dir_name): os.makedirs(dir_name) nodes_pos, edges_indices, edges_thickness, _ = self.extract_node_edge_info() lattice = EdgeInfoLattice( nodes_positions=nodes_pos, edges_indices=edges_indices, edges_thickness=edges_thickness, linear_stiffness=LINEAR_STIFFNESS, angular_stiffness=ANGULAR_STIFFNESS ) for edge in lattice._possible_edges: lattice.flip_edge(edge) actuator = Actuator( lattice=lattice, input_nodes=self.input_nodes, input_vectors=self.input_vectors, output_nodes=self.output_nodes, output_vectors=self.output_vectors, frozen_nodes=self.frozen_nodes ) show_actuator(actuator, save_path=save_path)
def _load_crane_displacement(solver_tol=1e-5) -> Actuator: input_lammps_file = Path(__file__).parent / \ "data/crane/crane_initial_config.lammps" params = read_lammps(input_lammps_file) nodes_postions = params["nodes_positions"] edges_indices = params["edges_indices"] input_nodes = params["input_nodes"] output_nodes = params["output_nodes"] frozen_nodes = params["frozen_nodes"] lattice = Lattice( nodes_positions=nodes_postions, edges_indices=edges_indices, linear_stiffness=10, angular_stiffness=0.2, ) for edge in lattice._possible_edges: lattice.flip_edge(edge) # input and output vectors input_vectors = np.array([[0, -np.sqrt(3) / 4] for _ in input_nodes]) output_vectors = np.array([[-1, 0] for _ in output_nodes]) actuator = Actuator(lattice=lattice, input_nodes=input_nodes, output_nodes=output_nodes, frozen_nodes=frozen_nodes, input_vectors=input_vectors, output_vectors=output_vectors, max_force=solver_tol, method="displacement") return actuator
def test_actuator_frozen_x_nodes(square_lattice): """make sure that we can add x-only contraints""" actuator = Actuator( lattice=square_lattice, frozen_nodes=[3], frozen_x_nodes=[2], input_nodes=[0], input_vectors=np.array([[-0.5, 0]]), output_nodes=[1], output_vectors=np.array([[-1, 0]]), ) actuator.act() # grab x and y of semifrozen nodes x_displaced = actuator._relax_params["X"][2] y_displaced = actuator._relax_params["Y"][2] assert x_displaced == -1 and y_displaced != -1
def test_actuator_rescale_efficiency_fails(square_lattice: Lattice): """make sure we can't use rescale efficiency when norms are not constant""" with pytest.raises(RuntimeError): actuator = Actuator(lattice=square_lattice, frozen_nodes=[3], input_nodes=[0, 2], input_vectors=np.array([[0.1, 0.1], [0.2, 0.2]]), output_nodes=[1], output_vectors=np.array([[0.3, 0.4]]), rescale_efficiency=True)
def test_actuator_nodes_unique(square_lattice: Lattice): """make sure we cannot pass non-unique lists of nodes""" with pytest.raises(RuntimeError): actuator = Actuator( lattice=square_lattice, frozen_nodes=[0, 1], input_nodes=[1, 2, 1], output_nodes=[2, 0], input_vectors=np.array([[1, 1]]), output_vectors=np.array([[1, 1]]), )
def test_actuator_nodes_overlap_input_output(square_lattice: Lattice): """make sure we cannot pass overlapping lists between input output""" with pytest.raises(RuntimeError): actuator = Actuator( lattice=square_lattice, frozen_nodes=[2, 3], input_nodes=[0], input_vectors=np.array([[0.1, 0.2]]), output_nodes=[0], output_vectors=np.array([[0.3, 0.4]]), )
def test_actuator_no_duplicates_in_input(square_lattice: Lattice): """make sure we cannot pass duplicated nodes to input""" with pytest.raises(RuntimeError): actuator = Actuator( lattice=square_lattice, frozen_nodes=[2, 3], input_nodes=[0, 0], input_vectors=np.array([[0.1, 0.2], [0.1, 0.2]]), output_nodes=[1], output_vectors=np.array([[0.3, 0.4]]), )
def square_actuator_force(square_lattice: Lattice): """a actuator for the simple square""" lattice = square_lattice actuator = Actuator(lattice=lattice, frozen_nodes=[2, 3], input_nodes=[0], input_vectors=np.array([[0.1, 0.2]]), output_nodes=[1], output_vectors=np.array([[0.3, 0.4]]), method="force") return actuator
def test_actuator_nodes_sizes_input(square_lattice: Lattice): """make sure we raise error when input sizes dont match""" with pytest.raises(RuntimeError): actuator = Actuator( lattice=square_lattice, frozen_nodes=[0, 1], input_nodes=[2], output_nodes=[3], input_vectors=np.array([[1, 1], [1, 1]]), output_vectors=np.array([[1, 1]]), )
def test_actuator_nodes_exist(square_lattice: Lattice): """make sure we cannot pass inexistent nodes""" with pytest.raises(RuntimeError): actuator = Actuator( lattice=square_lattice, frozen_nodes=[0, 5, 8], input_nodes=[1], output_nodes=[2, 4], input_vectors=np.array([[1, 1]]), output_vectors=np.array([[1, 1]]), )
def test_actuator_frozen_overlaps(square_lattice): """make sure that we cannot pass overlapping lists of frozen nodes""" with pytest.raises(RuntimeError): actuator = Actuator( lattice=square_lattice, frozen_nodes=[3, 2], frozen_x_nodes=[2], input_nodes=[0], input_vectors=np.array([[-0.5, 0]]), output_nodes=[1], output_vectors=np.array([[-1, 0]]), )
def test_actuator_unkown_protocols(square_lattice: Lattice): """make sure cannot use unkown protocols""" with pytest.raises(RuntimeError): actuator = Actuator(lattice=square_lattice, frozen_nodes=[2, 3], input_nodes=[0], input_vectors=np.array([[0.1, 0.2]]), output_nodes=[1], output_vectors=np.array([ [0.3, 0.4], ]), method="unknown")
def test_actuator_get_efficiency_displacement(square_lattice: Lattice): """make sure we correctly compute efficiencies for the displacement case (with just one vector) """ for _ in range(100): for rescale_efficiency in [True, False]: # set a specific displacement disp_x = np.random.uniform(-2, 2) disp_y = np.random.uniform(-2, 2) # set a specific output out_x = np.random.uniform(-2, 2) out_y = np.random.uniform(-2, 2) # set a specific input inp_x = np.random.uniform(-2, 2) inp_y = np.random.uniform(-2, 2) # setup the actuator actuator = Actuator(lattice=square_lattice, frozen_nodes=[2, 3], input_nodes=[0], input_vectors=np.array([[inp_x, inp_y]]), output_nodes=[1], output_vectors=np.array([[out_x, out_y]]), rescale_efficiency=rescale_efficiency) # move the output node by hand actuator._relax_params["X"][actuator.output_nodes] = -1 + disp_x actuator._relax_params["Y"][actuator.output_nodes] = 1 + disp_y # compute the efficiency by hand numerator = disp_x * out_x + disp_y * out_y denominator = np.sqrt(out_x**2 + out_y**2) projection_length = numerator / denominator input_length = np.sqrt(inp_x**2 + inp_y**2) if rescale_efficiency: efficiency_by_hand = projection_length / input_length else: efficiency_by_hand = projection_length # compute with the actuators method efficiency_by_code = actuator._get_efficiency() # compare assert np.isclose(efficiency_by_code, efficiency_by_hand)
def square_actuator(square_lattice): """actuator for the simple square""" lattice = square_lattice actuator = Actuator( lattice=lattice, frozen_nodes=[], input_nodes=[0], input_vectors=np.array([ [0.1, 0.2] ]), output_nodes=[1], output_vectors=np.array([ [0.3, 0.4] ]), ) return actuator
def test_metropolis_(square_lattice: Lattice): """test that metropolis raises error if no edges can be removed""" lattice = square_lattice actuator = Actuator( lattice=lattice, input_nodes=[0], output_nodes=[1], frozen_nodes=[2, 3], input_vectors=np.array([ [0.1, 0.2] ]), output_vectors=np.array([ [0.3, 0.4] ]), ) with pytest.raises(RuntimeError): metropolis = Metropolis(actuator)
def test_metropolis_max_iter_early_stop(max_iter, stop_at, square_lattice): """test that we stop at the correct value of maxiter""" lattice = square_lattice actuator = Actuator( lattice=lattice, frozen_nodes=[], input_nodes=[0], input_vectors=np.array([ [0.1, 0.2] ]), output_nodes=[1], output_vectors=np.array([ [0.3, 0.4] ]), max_iter=max_iter ) metropolis = Metropolis(actuator=actuator) metropolis.run( temperature=1, num_steps=100 ) assert metropolis.history["relax_internal_steps"][-1] == stop_at
def test_metropolis_is_valid_flag(square_lattice): """test that if max_iter is reached then is_valid is set to False""" lattice = square_lattice actuator = Actuator( lattice=lattice, frozen_nodes=[], input_nodes=[0], input_vectors=np.array([ [0.1, 0.2] ]), output_nodes=[1], output_vectors=np.array([ [0.3, 0.4] ]), max_iter=10 ) metropolis = Metropolis(actuator=actuator) metropolis.run( temperature=1, num_steps=100 ) assert not metropolis.is_valid
def calculate_simulation(self): nodes_pos, edges_indices, edges_thickness, _ = self.extract_node_edge_info() lattice = EdgeInfoLattice( nodes_positions=nodes_pos, edges_indices=edges_indices, edges_thickness=edges_thickness, linear_stiffness=LINEAR_STIFFNESS, angular_stiffness=ANGULAR_STIFFNESS ) for edge in lattice._possible_edges: lattice.flip_edge(edge) actuator = Actuator( lattice=lattice, input_nodes=self.input_nodes, input_vectors=self.input_vectors, output_nodes=self.output_nodes, output_vectors=self.output_vectors, frozen_nodes=self.frozen_nodes ) return actuator.efficiency
def _load_crane_force(solver_tol=1e-5) -> Actuator: path_to_initial_config = Path(__file__).parent / \ "data/crane/crane_initial_config.lammps" params = read_lammps(path_to_initial_config) nodes_postions = params["nodes_positions"] edges_indices = params["edges_indices"] input_nodes = params["input_nodes"] output_nodes = params["output_nodes"] frozen_nodes = params["frozen_nodes"] lattice = Lattice( nodes_positions=nodes_postions, edges_indices=edges_indices, linear_stiffness=10, angular_stiffness=0.2, ) for edge in lattice._possible_edges: lattice.flip_edge(edge) # input and output vectors input_vectors = np.array([[0, -0.0015] for _ in input_nodes]) output_vectors = np.array([[2, 0] for _ in output_nodes]) actuator = Actuator(lattice=lattice, input_nodes=input_nodes, output_nodes=output_nodes, frozen_nodes=frozen_nodes, input_vectors=input_vectors, output_vectors=output_vectors, max_force=solver_tol, method="force", output_spring_stiffness=0.001, efficiency_agg_fun=np.sum) return actuator
# measure output at top-left nodes along -x direction output_nodes = [68, 69, 70, 71] output_vectors = np.array([ [-1, 0], [-1, 0], [-1, 0], [-1, 0], ]) # freeze the bottomn layer frozen_nodes = [1, 3, 5, 7, 9, 11, 13, 15] # construct the actuator actuator = Actuator(lattice=lattice, input_nodes=input_nodes, input_vectors=input_vectors, output_nodes=output_nodes, output_vectors=output_vectors, frozen_nodes=frozen_nodes) print("initial efficiency", actuator.efficiency) metropolis = Metropolis(actuator=actuator) metropolis.run(initial_temperature=0.1, final_temperature=0, num_steps=500) print("final efficiency", actuator.efficiency) # final efficiency 2.8265941145286715 history_df = pd.DataFrame(metropolis.history) """ # 記録やOVITOを用いた可視化用 history_df.to_xlsx("/path/MC_history.xlsx")
def load_crane_scaling( size: int = 8, displacement_fraction: float = 0.01, solver_tol: float = 1e-5, ) -> Actuator: """ Load crane actuator for scaling analysis. Offers a set of initial configs on a regular lattice of increasing size and preconfigured input/output vectors, suitable for scaling analysis. Parameters ---------- size : int, optional Number of nodes of side of lattice, by default 8 solver_tol : float, optional Tolerance (max force) in FIRE algorithm, by default 1e-5 displacement_fraction : float, optional Set input displacement to a fixed fraction of the length of the lattice in the y direction, by default 0.01. Returns ------- : Actuator Preconfigured crane actuator. """ # make sure size is available if size not in AVAILABLE_CRANE_SIZES: raise RuntimeError( f"Size {size} is not available. Available sizes are", AVAILABLE_CRANE_SIZES) path_to_initial_config = Path(__file__).parent / \ f"data/crane_scaling/conf{size}.data" params = read_lammps(path_to_initial_config) nodes_postions = params["nodes_positions"] edges_indices = params["edges_indices"] # define input, output and frozen nodes xs, ys, _ = nodes_postions.T frozen_nodes = [ i for i, y in enumerate(ys) if y == min(ys) ] input_nodes = [ i for i, (x, y) in enumerate(zip(xs, ys)) if (x > min(xs) + 0.8 * (max(xs) - min(xs))) and (y > min(ys) + 0.8 * (max(ys) - min(ys))) ] output_nodes = [ i for i, (x, y) in enumerate(zip(xs, ys)) if (x < min(xs) + 0.2 * (max(xs) - min(xs))) and (y > min(ys) + 0.8 * (max(ys) - min(ys))) ] # input and output vectors # displacement is 1% of y range input_vectors = np.array([ [0, -displacement_fraction * (max(ys) - min(ys))] for _ in input_nodes ]) output_vectors = np.array([ [-1, 0] for _ in output_nodes ]) lattice = Lattice( nodes_positions=nodes_postions, edges_indices=edges_indices, linear_stiffness=10, angular_stiffness=0.2, ) for edge in lattice._possible_edges: lattice.flip_edge(edge) actuator = Actuator( lattice=lattice, input_nodes=input_nodes, output_nodes=output_nodes, frozen_nodes=frozen_nodes, input_vectors=input_vectors, output_vectors=output_vectors, max_force=solver_tol, method="displacement", ) return actuator