def test_symplectics_against_ellipse_motion_with_numpy_PEFRL( self, monkeypatch): monkeypatch.setenv("IMPORT_TEST_NUMPY", "True", prepend=False) # After changing the import flag reload the modules. importlib.reload(elastica) importlib.reload(elastica.timestepper.symplectic_steppers) # importlib.reload(elastica.timestepper.integrate) importlib.reload(elastica.timestepper) from elastica.timestepper.symplectic_steppers import PEFRL from elastica.timestepper import integrate random_start_position = np.random.randn(3, 1) random_directors, _ = np.linalg.qr(np.random.randn(3, 3)) random_directors = random_directors.reshape(3, 3, 1) rod_like_system = make_simple_system_with_positions_directors( random_start_position, random_directors) final_time = 1.0 n_steps = 1000 stepper = PEFRL() integrate(stepper, rod_like_system, final_time=final_time, n_steps=n_steps) assert_allclose( rod_like_system.position_collection.reshape(3), rod_like_system.analytical_solution("Positions", final_time), rtol=Tolerance.rtol() * 1e1, atol=Tolerance.atol(), ) assert_allclose( rod_like_system.velocity_collection.reshape(3), rod_like_system.analytical_solution("Velocity", final_time), rtol=Tolerance.rtol() * 1e1, atol=Tolerance.atol(), ) # Reshaping done in the director collection to prevent numba from # complaining about returning multiple types assert_allclose( rod_like_system.director_collection.reshape(-1, 1), rod_like_system.analytical_solution("Directors", final_time), rtol=Tolerance.rtol() * 1e1, atol=Tolerance.atol(), ) # Remove the import flag monkeypatch.delenv("IMPORT_TEST_NUMPY") # Reload the elastica after changing flag importlib.reload(elastica) importlib.reload(elastica.timestepper.symplectic_steppers) importlib.reload(elastica.timestepper) from elastica.timestepper.symplectic_steppers import PEFRL from elastica.timestepper import integrate
def test_symplectic_against_undamped_harmonic_oscillator(self, stepper): system = SymplecticUndampedSimpleHarmonicOscillatorSystem() final_time = 4.0 * np.pi n_steps = 2000 integrate(stepper(), system, final_time=final_time, n_steps=n_steps) # Symplectic systems conserve energy to a certain extent assert_allclose( *system.compute_energy(final_time), rtol=Tolerance.rtol() * 1e1, atol=Tolerance.atol(), )
def test_against_damped_harmonic_oscillator(self, stepper): system = DampedSimpleHarmonicOscillatorSystem() final_time = 4.0 * np.pi n_steps = 2000 integrate(stepper(), system, final_time=final_time, n_steps=n_steps) assert_allclose( system.state, system.analytical_solution(final_time), rtol=Tolerance.rtol(), atol=Tolerance.atol(), )
def test_against_scalar_exponential(self, stepper): system = ScalarExponentialDecaySystem(-1, 1) final_time = 1 n_steps = 1000 integrate(stepper(), system, final_time=final_time, n_steps=n_steps) assert_allclose( system.state, system.analytical_solution(final_time), rtol=Tolerance.rtol() * 1e3, atol=Tolerance.atol(), )
def test_explicit_against_analytical_system(self, explicit_stepper): system = SecondOrderHybridSystem() final_time = 1.0 n_steps = 2000 integrate(explicit_stepper(), system, final_time=final_time, n_steps=n_steps) assert_allclose( system.final_solution(final_time), system.analytical_solution(final_time), rtol=Tolerance.rtol() * 1e2, atol=Tolerance.atol(), )
def test_hybrid_symplectic_against_analytical_system( self, symplectic_stepper): system = SecondOrderHybridSystem() final_time = 1.0 n_steps = 2000 stepper = SymplecticCosseratRodStepper( symplectic_stepper=symplectic_stepper()) integrate(stepper, system, final_time=final_time, n_steps=n_steps) assert_allclose( system.final_solution(final_time), system.analytical_solution(final_time), rtol=Tolerance.rtol() * 1e2, atol=Tolerance.atol(), )
def test_linear_exponential_integrator(self): system = MultipleFrameRotationSystem(n_frames=128) final_time = np.pi n_steps = 1000 integrate( StatefulLinearExponentialIntegrator(), system, final_time=final_time, n_steps=n_steps, ) assert_allclose( system.linearly_evolving_state, system.analytical_solution(final_time), atol=1e-4, )
def test_symplectic_steppers(self, symplectic_stepper): collective_system = SymplecticUndampedHarmonicOscillatorCollectiveSystem( ) final_time = 1.0 n_steps = 2000 stepper = symplectic_stepper() integrate(stepper, collective_system, final_time=final_time, n_steps=n_steps) for system in collective_system: assert_allclose( *system.compute_energy(final_time), rtol=Tolerance.rtol() * 1e1, atol=Tolerance.atol(), )
def test_symplectics_against_ellipse_motion(self, symplectic_stepper): from elastica.systems.analytical import ( make_simple_system_with_positions_directors, SimpleSystemWithPositionsDirectors, ) random_start_position = np.random.randn(3, 1) random_end_position = np.random.randn(3, 1) random_directors, _ = np.linalg.qr(np.random.randn(3, 3)) random_directors = random_directors.reshape(3, 3, 1) rod_like_system = make_simple_system_with_positions_directors( random_start_position, random_end_position, random_directors) final_time = 1.0 n_steps = 1000 stepper = symplectic_stepper() integrate(stepper, rod_like_system, final_time=final_time, n_steps=n_steps) assert_allclose( rod_like_system.position_collection, rod_like_system.analytical_solution("Positions", final_time), rtol=Tolerance.rtol() * 1e1, atol=Tolerance.atol(), ) assert_allclose( rod_like_system.velocity_collection, rod_like_system.analytical_solution("Velocity", final_time), rtol=Tolerance.rtol() * 1e1, atol=Tolerance.atol(), ) # Reshaping done in the director collection to prevent numba from # complaining about returning multiple types assert_allclose( rod_like_system.director_collection.reshape(-1, 1), rod_like_system.analytical_solution("Directors", final_time), rtol=Tolerance.rtol() * 1e1, atol=Tolerance.atol(), )
def test_explicit_against_ellipse_motion(self, explicit_stepper): from elastica.systems.analytical import SimpleSystemWithPositionsDirectors rod_like_system = SimpleSystemWithPositionsDirectors( np.array([0.0, 0.0, 0.0]), np.random.randn(3, 3, 1)) final_time = 1.0 n_steps = 500 stepper = explicit_stepper() integrate(stepper, rod_like_system, final_time=final_time, n_steps=n_steps) assert_allclose( rod_like_system.position_collection, rod_like_system.analytical_solution("Positions", final_time), rtol=Tolerance.rtol() * 1e1, atol=Tolerance.atol(), )
def test_symplectics_against_ellipse_motion(self, symplectic_stepper): from elastica.systems.analytical import SimpleSystemWithPositionsDirectors random_start_position = np.random.randn(3, 1) random_end_position = np.random.randn(3, 1) random_directors, _ = np.linalg.qr(np.random.randn(3, 3)) random_directors = random_directors.reshape(3, 3, 1) rod_like_system = SimpleSystemWithPositionsDirectors( random_start_position, random_end_position, random_directors) final_time = 1.0 n_steps = 1000 stepper = symplectic_stepper() integrate(stepper, rod_like_system, final_time=final_time, n_steps=n_steps) assert_allclose( rod_like_system.position_collection, rod_like_system.analytical_solution("Positions", final_time), rtol=Tolerance.rtol() * 1e1, atol=Tolerance.atol(), ) assert_allclose( rod_like_system.velocity_collection, rod_like_system.analytical_solution("Velocity", final_time), rtol=Tolerance.rtol() * 1e1, atol=Tolerance.atol(), ) assert_allclose( rod_like_system.director_collection, rod_like_system.analytical_solution("Directors", final_time), rtol=Tolerance.rtol() * 1e1, atol=Tolerance.atol(), )
def test_integrate_throws_an_assert_for_negative_total_steps(): with pytest.raises(AssertionError) as excinfo: integrate([], [], np.random.rand(1), -np.random.randint(100, 10000)) assert "steps is negative" in str(excinfo.value)
def test_integrate_throws_an_assert_for_negative_final_time(): with pytest.raises(AssertionError) as excinfo: integrate([], [], -np.random.rand(1)) assert "time is negative" in str(excinfo.value)
step_skip=1000, callback_params=pp_list_rod1) hinge_joint_sim.collect_diagnostics(rod2).using(TestJoints, step_skip=1000, callback_params=pp_list_rod2) hinge_joint_sim.finalize() timestepper = PositionVerlet() # timestepper = PEFRL() final_time = 10 dl = base_length / n_elem dt = 1e-5 total_steps = int(final_time / dt) print("Total steps", total_steps) integrate(timestepper, hinge_joint_sim, final_time, total_steps) PLOT_FIGURE = True SAVE_FIGURE = False PLOT_VIDEO = False # plotting results if PLOT_FIGURE: filename = "hinge_joint_test.png" plot_position(pp_list_rod1, pp_list_rod2, filename, SAVE_FIGURE) if PLOT_VIDEO: filename = "hinge_joint_test.mp4" plot_video(pp_list_rod1, pp_list_rod2, video_name=filename,
) fixed_joint_sim.collect_diagnostics(rod2).using( TestJoints, step_skip=1000, callback_params=pp_list_rod2 ) fixed_joint_sim.finalize() timestepper = PositionVerlet() # timestepper = PEFRL() final_time = 10 dl = base_length / n_elem dt = 1e-5 total_steps = int(final_time / dt) print("Total steps", total_steps) integrate(timestepper, fixed_joint_sim, final_time, total_steps) PLOT_FIGURE = True SAVE_FIGURE = False PLOT_VIDEO = False # plotting results if PLOT_FIGURE: filename = "fixed_joint_test.png" plot_position(pp_list_rod1, pp_list_rod2, filename, SAVE_FIGURE) if PLOT_VIDEO: filename = "fixed_joint_test.mp4" plot_video(pp_list_rod1, pp_list_rod2, video_name=filename, margin=0.2, fps=100) plot_video_xy( pp_list_rod1, pp_list_rod2, video_name=filename + "_xy.mp4", margin=0.2, fps=100
) timoshenko_sim.append(unshearable_rod) timoshenko_sim.constrain(unshearable_rod).using( OneEndFixedRod, constrained_position_idx=(0,), constrained_director_idx=(0,) ) timoshenko_sim.add_forcing_to(unshearable_rod).using( EndpointForces, 0.0 * end_force, end_force, ramp_up_time=final_time / 2.0 ) timoshenko_sim.finalize() timestepper = PositionVerlet() # timestepper = PEFRL() dl = base_length / n_elem dt = 0.01 * dl total_steps = int(final_time / dt) print("Total steps", total_steps) integrate(timestepper, timoshenko_sim, final_time, total_steps) if PLOT_FIGURE: plot_timoshenko(shearable_rod, end_force, SAVE_FIGURE, ADD_UNSHEARABLE_ROD) if SAVE_RESULTS: import pickle filename = "Timoshenko_beam_data.dat" file = open(filename, "wb") pickle.dump(shearable_rod, file) file.close()
constrained_position_idx=(0, -1), constrained_director_idx=(0, -1), twisting_time=500, slack=slack, number_of_rotations=number_of_rotations, ) helicalbuckling_sim.finalize() timestepper = PositionVerlet() shearable_rod.velocity_collection[..., int( (n_elem) / 2)] += np.array([0, 1e-6, 0.0]) # timestepper = PEFRL() final_time = 10500.0 dl = base_length / n_elem dt = 1e-3 * dl total_steps = int(final_time / dt) print("Total steps", total_steps) integrate(timestepper, helicalbuckling_sim, final_time, total_steps) if PLOT_FIGURE: plot_helicalbuckling(shearable_rod, SAVE_FIGURE) if SAVE_RESULTS: import pickle filename = "HelicalBuckling_data.dat" file = open(filename, "wb") pickle.dump(shearable_rod, file) file.close()
def simulate_rolling_friction_initial_velocity_with(IFactor=0.0): rolling_friction_initial_velocity_sim = RollingFrictionInitialVelocitySimulator( ) # setting up test params n_elem = 50 start = np.zeros((3, )) direction = np.array([0.0, 0.0, 1.0]) normal = np.array([0.0, 1.0, 0.0]) base_length = 1.0 base_radius = 0.025 base_area = np.pi * base_radius**2 mass = 1.0 density = mass / (base_length * base_area) nu = 1e-6 E = 1e9 # For shear modulus of 2E/3 poisson_ratio = 0.5 # Set shear matrix shear_matrix = np.repeat(1e4 * np.identity((3))[:, :, np.newaxis], n_elem, axis=2) shearable_rod = CosseratRod.straight_rod( n_elem, start, direction, normal, base_length, base_radius, density, nu, E, poisson_ratio, ) # TODO: CosseratRod has to be able to take shear matrix as input, we should change it as done below shearable_rod.shear_matrix = shear_matrix # change the mass moment of inertia matrix and its inverse shearable_rod.mass_second_moment_of_inertia *= IFactor shearable_rod.inv_mass_second_moment_of_inertia /= IFactor # set initial velocity of 1m/s to rod elements in the slip direction Vs = 1.0 shearable_rod.velocity_collection[0, :] += Vs rolling_friction_initial_velocity_sim.append(shearable_rod) rolling_friction_initial_velocity_sim.constrain(shearable_rod).using( FreeRod) # Add gravitational forces gravitational_acc = -9.80665 rolling_friction_initial_velocity_sim.add_forcing_to(shearable_rod).using( GravityForces, acc_gravity=np.array([0.0, gravitational_acc, 0.0])) # Add friction forces origin_plane = np.array([0.0, -base_radius, 0.0]) normal_plane = np.array([0.0, 1.0, 0.0]) slip_velocity_tol = 1e-6 static_mu_array = np.array([0.4, 0.4, 0.4]) # [forward, backward, sideways] kinetic_mu_array = np.array([0.2, 0.2, 0.2]) # [forward, backward, sideways] rolling_friction_initial_velocity_sim.add_forcing_to(shearable_rod).using( AnisotropicFrictionalPlane, k=10.0, nu=1e-4, plane_origin=origin_plane, plane_normal=normal_plane, slip_velocity_tol=slip_velocity_tol, static_mu_array=static_mu_array, kinetic_mu_array=kinetic_mu_array, ) rolling_friction_initial_velocity_sim.finalize() timestepper = PositionVerlet() final_time = 2.0 dt = 1e-6 total_steps = int(final_time / dt) print("Total steps", total_steps) integrate(timestepper, rolling_friction_initial_velocity_sim, final_time, total_steps) # compute translational and rotational energy translational_energy = shearable_rod.compute_translational_energy() rotational_energy = shearable_rod.compute_rotational_energy() # compute translational and rotational energy using analytical equations analytical_translational_energy = 0.5 * mass * Vs**2 / (1.0 + IFactor / 2)**2 analytical_rotational_energy = (0.5 * mass * Vs**2 * (IFactor / 2.0) / (1.0 + IFactor / 2)**2) return { "rod": shearable_rod, "sweep": IFactor / 2.0, "translational_energy": translational_energy, "rotational_energy": rotational_energy, "analytical_translational_energy": analytical_translational_energy, "analytical_rotational_energy": analytical_rotational_energy, }
def simulate_axial_friction_with(force=0.0): axial_friction_sim = AxialFrictionSimulator() # setting up test params n_elem = 50 start = np.zeros((3, )) direction = np.array([0.0, 0.0, 1.0]) normal = np.array([0.0, 1.0, 0.0]) base_length = 1.0 base_radius = 0.025 base_area = np.pi * base_radius**2 mass = 1.0 density = mass / (base_length * base_area) nu = 1e-6 E = 1e5 # For shear modulus of 2E/3 poisson_ratio = 0.5 # Set shear matrix shear_matrix = np.repeat(1e4 * np.identity((3))[:, :, np.newaxis], n_elem, axis=2) shearable_rod = CosseratRod.straight_rod( n_elem, start, direction, normal, base_length, base_radius, density, nu, E, poisson_ratio, ) # TODO: CosseratRod has to be able to take shear matrix as input, we should change it as done below shearable_rod.shear_matrix = shear_matrix axial_friction_sim.append(shearable_rod) axial_friction_sim.constrain(shearable_rod).using(FreeRod) # Add gravitational forces gravitational_acc = -9.80665 axial_friction_sim.add_forcing_to(shearable_rod).using( GravityForces, acc_gravity=np.array([0.0, gravitational_acc, 0.0])) # Add Uniform force on the rod axial_friction_sim.add_forcing_to(shearable_rod).using(UniformForces, force=1.0 * force, direction=direction) # Add friction forces origin_plane = np.array([0.0, -base_radius, 0.0]) normal_plane = np.array([0.0, 1.0, 0.0]) slip_velocity_tol = 1e-4 static_mu_array = np.array([0.8, 0.4, 0.4]) # [forward, backward, sideways] kinetic_mu_array = np.array([0.4, 0.2, 0.2]) # [forward, backward, sideways] axial_friction_sim.add_forcing_to(shearable_rod).using( AnisotropicFrictionalPlane, k=10.0, nu=1e-4, plane_origin=origin_plane, plane_normal=normal_plane, slip_velocity_tol=slip_velocity_tol, static_mu_array=static_mu_array, kinetic_mu_array=kinetic_mu_array, ) axial_friction_sim.finalize() timestepper = PositionVerlet() final_time = 0.25 dt = 1e-5 total_steps = int(final_time / dt) print("Total steps", total_steps) integrate(timestepper, axial_friction_sim, final_time, total_steps) # compute translational and rotational energy translational_energy = shearable_rod.compute_translational_energy() rotational_energy = shearable_rod.compute_rotational_energy() # compute translational and rotational energy using analytical equations if force >= 0.0: # forward friction force if np.abs(force) <= np.abs( static_mu_array[0] * mass * gravitational_acc): analytical_translational_energy = 0.0 else: analytical_translational_energy = ( final_time**2 / (2.0 * mass) * (np.abs(force) - kinetic_mu_array[0] * mass * np.abs(gravitational_acc))**2) else: # backward friction force if np.abs(force) <= np.abs( static_mu_array[1] * mass * gravitational_acc): analytical_translational_energy = 0.0 else: analytical_translational_energy = ( final_time**2 / (2.0 * mass) * (np.abs(force) - kinetic_mu_array[1] * mass * np.abs(gravitational_acc))**2) analytical_rotational_energy = 0.0 return { "rod": shearable_rod, "sweep": force, "translational_energy": translational_energy, "rotational_energy": rotational_energy, "analytical_translational_energy": analytical_translational_energy, "analytical_rotational_energy": analytical_rotational_energy, }
def run_snake(b_coeff, SAVE_RESULTS=False): snake_sim = SnakeSimulator() # setting up test params n_elem = 20 start = np.zeros((3, )) direction = np.array([0.0, 0.0, 1.0]) normal = np.array([0.0, 1.0, 0.0]) base_length = 1.0 base_radius = 0.025 base_area = np.pi * base_radius**2 density = 1000 nu = 5.0 E = 1e7 poisson_ratio = 0.5 shearable_rod = CosseratRod.straight_rod( n_elem, start, direction, normal, base_length, base_radius, density, nu, E, poisson_ratio, ) snake_sim.append(shearable_rod) # Add gravitational forces gravitational_acc = -9.80665 snake_sim.add_forcing_to(shearable_rod).using( GravityForces, acc_gravity=np.array([0.0, gravitational_acc, 0.0])) period = 1.0 wave_length = b_coeff[-1] snake_sim.add_forcing_to(shearable_rod).using( MuscleTorques, base_length=base_length, b_coeff=b_coeff[:-1], period=period, wave_number=2.0 * np.pi / (wave_length), phase_shift=0.0, direction=normal, rest_lengths=shearable_rod.rest_lengths, ramp_up_time=period, with_spline=True, ) # Add friction forces origin_plane = np.array([0.0, -base_radius, 0.0]) normal_plane = normal slip_velocity_tol = 1e-8 froude = 0.1 mu = base_length / (period * period * np.abs(gravitational_acc) * froude) kinetic_mu_array = np.array([mu, 1.5 * mu, 2.0 * mu]) # [forward, backward, sideways] static_mu_array = 2 * kinetic_mu_array snake_sim.add_forcing_to(shearable_rod).using( AnisotropicFrictionalPlane, k=1.0, nu=1e-6, plane_origin=origin_plane, plane_normal=normal_plane, slip_velocity_tol=slip_velocity_tol, static_mu_array=static_mu_array, kinetic_mu_array=kinetic_mu_array, ) # Add call backs class ContinuumSnakeCallBack(CallBackBaseClass): """ Call back function for continuum snake """ def __init__(self, step_skip: int, callback_params: dict): CallBackBaseClass.__init__(self) self.every = step_skip self.callback_params = callback_params def make_callback(self, system, time, current_step: int): if current_step % self.every == 0: self.callback_params["time"].append(time) self.callback_params["position"].append( system.position_collection.copy()) return pp_list = defaultdict(list) snake_sim.collect_diagnostics(shearable_rod).using(ContinuumSnakeCallBack, step_skip=200, callback_params=pp_list) snake_sim.finalize() timestepper = PositionVerlet() # timestepper = PEFRL() final_time = (11.0 + 0.01) * period dt = 5.0e-5 * period total_steps = int(final_time / dt) print("Total steps", total_steps) integrate(timestepper, snake_sim, final_time, total_steps) if SAVE_RESULTS: import pickle filename = "continuum_snake.dat" file = open(filename, "wb") pickle.dump(pp_list, file) file.close() return pp_list
def simulate_timoshenko_beam_with(elements=10, PLOT_FIGURE=False, ADD_UNSHEARABLE_ROD=False): timoshenko_sim = TimoshenkoBeamSimulator() final_time = 5000 # setting up test params n_elem = elements start = np.zeros((3, )) direction = np.array([0.0, 0.0, 1.0]) normal = np.array([0.0, 1.0, 0.0]) base_length = 3.0 base_radius = 0.25 base_area = np.pi * base_radius**2 density = 5000 nu = 0.1 E = 1e6 # For shear modulus of 1e4, nu is 99! poisson_ratio = 99 shearable_rod = CosseratRod.straight_rod( n_elem, start, direction, normal, base_length, base_radius, density, nu, E, poisson_ratio, ) timoshenko_sim.append(shearable_rod) timoshenko_sim.constrain(shearable_rod).using( OneEndFixedRod, constrained_position_idx=(0, ), constrained_director_idx=(0, )) end_force = np.array([-15.0, 0.0, 0.0]) timoshenko_sim.add_forcing_to(shearable_rod).using( EndpointForces, 0.0 * end_force, end_force, ramp_up_time=final_time / 2) if ADD_UNSHEARABLE_ROD: # Start into the plane unshearable_start = np.array([0.0, -1.0, 0.0]) unshearable_rod = CosseratRod.straight_rod( n_elem, unshearable_start, direction, normal, base_length, base_radius, density, nu, E, # Unshearable rod needs G -> inf, which is achievable with -ve poisson ratio poisson_ratio=-0.7, ) timoshenko_sim.append(unshearable_rod) timoshenko_sim.constrain(unshearable_rod).using( OneEndFixedRod, constrained_position_idx=(0, ), constrained_director_idx=(0, )) timoshenko_sim.add_forcing_to(unshearable_rod).using( EndpointForces, 0.0 * end_force, end_force, ramp_up_time=final_time / 2) timoshenko_sim.finalize() timestepper = PositionVerlet() # timestepper = PEFRL() dl = base_length / n_elem dt = 0.01 * dl total_steps = int(final_time / dt) print("Total steps", total_steps) integrate(timestepper, timoshenko_sim, final_time, total_steps) if PLOT_FIGURE: plot_timoshenko(shearable_rod, end_force, SAVE_FIGURE, ADD_UNSHEARABLE_ROD) # calculate errors and norms # Since we need to evaluate analytical solution only on nodes, n_nodes = n_elems+1 error, l1, l2, linf = calculate_error_norm( analytical_shearable(shearable_rod, end_force, n_elem + 1)[1], shearable_rod.position_collection[0, ...], n_elem, ) return { "rod": shearable_rod, "error": error, "l1": l1, "l2": l2, "linf": linf }
def simulate_rolling_friction_torque_with(C_s=0.0): rolling_friction_torque_sim = RollingFrictionTorqueSimulator() # setting up test params n_elem = 50 start = np.zeros((3, )) direction = np.array([0.0, 0.0, 1.0]) normal = np.array([0.0, 1.0, 0.0]) base_length = 1.0 base_radius = 0.025 base_area = np.pi * base_radius**2 mass = 1.0 density = mass / (base_length * base_area) nu = 1e-6 E = 1e9 # For shear modulus of 2E/3 poisson_ratio = 0.5 # Set shear matrix shear_matrix = np.repeat(1e4 * np.identity((3))[:, :, np.newaxis], n_elem, axis=2) shearable_rod = CosseratRod.straight_rod( n_elem, start, direction, normal, base_length, base_radius, density, nu, E, poisson_ratio, ) # TODO: CosseratRod has to be able to take shear matrix as input, we should change it as done below shearable_rod.shear_matrix = shear_matrix rolling_friction_torque_sim.append(shearable_rod) rolling_friction_torque_sim.constrain(shearable_rod).using(FreeRod) # Add gravitational forces gravitational_acc = -9.80665 rolling_friction_torque_sim.add_forcing_to(shearable_rod).using( GravityForces, acc_gravity=np.array([0.0, gravitational_acc, 0.0])) # Add Uniform torque on the rod rolling_friction_torque_sim.add_forcing_to(shearable_rod).using( UniformTorques, torque=1.0 * C_s, direction=direction) # Add friction forces origin_plane = np.array([0.0, -base_radius, 0.0]) normal_plane = np.array([0.0, 1.0, 0.0]) slip_velocity_tol = 1e-4 static_mu_array = np.array([0.4, 0.4, 0.4]) # [forward, backward, sideways] kinetic_mu_array = np.array([0.2, 0.2, 0.2]) # [forward, backward, sideways] rolling_friction_torque_sim.add_forcing_to(shearable_rod).using( AnisotropicFrictionalPlane, k=10.0, nu=1e-4, plane_origin=origin_plane, plane_normal=normal_plane, slip_velocity_tol=slip_velocity_tol, static_mu_array=static_mu_array, kinetic_mu_array=kinetic_mu_array, ) rolling_friction_torque_sim.finalize() timestepper = PositionVerlet() final_time = 1.0 dt = 1e-6 total_steps = int(final_time / dt) print("Total steps", total_steps) integrate(timestepper, rolling_friction_torque_sim, final_time, total_steps) # compute translational and rotational energy translational_energy = shearable_rod.compute_translational_energy() rotational_energy = shearable_rod.compute_rotational_energy() # compute translational and rotational energy using analytical equations force_slip = static_mu_array[2] * mass * gravitational_acc force_noslip = 2.0 * C_s / (3.0 * base_radius) mass_moment_of_inertia = 0.5 * mass * base_radius**2 if np.abs(force_noslip) <= np.abs(force_slip): analytical_translational_energy = (2.0 / mass * (final_time * C_s / (3.0 * base_radius))**2) analytical_rotational_energy = (2.0 * mass_moment_of_inertia * (final_time * C_s / (3.0 * base_radius**2 * mass))**2) else: analytical_translational_energy = ( mass * (kinetic_mu_array[2] * gravitational_acc * final_time)**2 / 2.0) analytical_rotational_energy = ( (C_s - kinetic_mu_array[2] * mass * np.abs(gravitational_acc) * base_radius)**2 * final_time**2 / (2.0 * mass_moment_of_inertia)) return { "rod": shearable_rod, "sweep": C_s, "translational_energy": translational_energy, "rotational_energy": rotational_energy, "analytical_translational_energy": analytical_translational_energy, "analytical_rotational_energy": analytical_rotational_energy, }
# FIXME change callback_of to collect_diagnostics spherical_joint_sim.collect_diagnostics(rod1).using( TestJoints, step_skip=1000, callback_params=pp_list_rod1) spherical_joint_sim.collect_diagnostics(rod2).using( TestJoints, step_skip=1000, callback_params=pp_list_rod2) spherical_joint_sim.finalize() timestepper = PositionVerlet() # timestepper = PEFRL() final_time = 10 dl = base_length / n_elem dt = 1e-5 total_steps = int(final_time / dt) print("Total steps", total_steps) integrate(timestepper, spherical_joint_sim, final_time, total_steps) PLOT_FIGURE = True SAVE_FIGURE = False PLOT_VIDEO = True # plotting results if PLOT_FIGURE: filename = "spherical_joint_test_last_node_pos_xy.png" plot_position(pp_list_rod1, pp_list_rod2, filename, SAVE_FIGURE) if PLOT_VIDEO: filename = "spherical_joint_test.mp4" plot_video(pp_list_rod1, pp_list_rod2, video_name=filename,