def load_collection(self): sc = GenericSimulatorClass() from elastica.rod.cosserat_rod import CosseratRod # rod = RodBase() rod_list = [] for _ in range(5): rod = CosseratRod.straight_rod( n_elements=10, start=np.zeros((3)), direction=np.array([0, 1, 0.0]), normal=np.array([1, 0, 0.0]), base_length=1, base_radius=1, density=1, nu=1, youngs_modulus=1, ) # Bypass check, but its fine for testing sc._systems.append(rod) # Also add rods to a separate list rod_list.append(rod) return sc, rod_list
def constructor(n_elem, nu=0.0): cls = BaseClass(n_elem, nu) rod = CosseratRod.straight_rod( cls.n_elem, cls.start, cls.direction, cls.normal, cls.base_length, cls.base_radius, cls.density, cls.nu, cls.E, cls.poisson_ratio, ) return cls, rod
def constructor(n_elem, nu=0.0): cls = BaseClass(n_elem, nu) rod = CosseratRod.straight_rod( cls.n_elem, cls.start, cls.direction, cls.normal, cls.base_length, cls.base_radius, cls.density, cls.nu, cls.E, shear_modulus=cls.shear_modulus, ) # Ghost needed for Cosserat rod functions adapted for block structure. rod.ghost_elems_idx = np.empty((0), dtype=int) rod.ghost_voronoi_idx = np.empty((0), dtype=int) return cls, rod
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, }
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 test_fixedjoint(): # Define the rod for testing # Some rod properties. We need them for constructer, they are not used. normal1 = np.array([0.0, 1.0, 0.0]) direction = np.array([1.0, 0.0, 0.0]) normal2 = np.array([0.0, 0.0, 1.0]) direction2 = np.array([1.0 / np.sqrt(2), 1.0 / np.sqrt(2), 0.0]) # direction2 = np.array([0.,1.0,0.]) base_length = 1 base_radius = 0.2 density = 1 nu = 0.1 # Youngs Modulus [Pa] E = 1e6 # poisson ratio poisson_ratio = 0.5 # Origin of the rod origin1 = np.array([0.0, 0.0, 0.0]) origin2 = np.array([1.0, 0.0, 0.0]) # Number of elements n = 2 # create rod classes rod1 = CosseratRod.straight_rod( n, origin1, direction, normal1, base_length, base_radius, density, nu, E, poisson_ratio, ) rod2 = CosseratRod.straight_rod( n, origin2, direction2, normal2, base_length, base_radius, density, nu, E, poisson_ratio, ) # Rod velocity v1 = np.array([-1, 0, 0]).reshape(3, 1) v2 = v1 * -1 rod1.velocity_collection = np.tile(v1, (1, n + 1)) rod2.velocity_collection = np.tile(v2, (1, n + 1)) # Stiffness between points k = 1e8 kt = 1e6 # Damping between two points nu = 1 # Rod indexes rod1_index = -1 rod2_index = 0 # Compute the free joint forces distance = (rod2.position_collection[..., rod2_index] - rod1.position_collection[..., rod1_index]) end_distance = np.linalg.norm(distance) if end_distance == 0: end_distance = 1 elasticforce = k * distance relative_vel = (rod2.velocity_collection[..., rod2_index] - rod1.velocity_collection[..., rod1_index]) normal_relative_vel = np.dot(relative_vel, distance) / end_distance dampingforce = nu * normal_relative_vel * distance / end_distance contactforce = elasticforce - dampingforce fxjt = FixedJoint(k, nu, kt) fxjt.apply_forces(rod1, rod1_index, rod2, rod2_index) fxjt.apply_torques(rod1, rod1_index, rod2, rod2_index) assert_allclose(rod1.external_forces[..., rod1_index], contactforce, atol=Tolerance.atol()) assert_allclose(rod2.external_forces[..., rod2_index], -1 * contactforce, atol=Tolerance.atol()) linkdirection = (rod2.position_collection[..., rod2_index + 1] - rod2.position_collection[..., rod2_index]) positiondiff = (rod1.position_collection[..., rod1_index] - rod1.position_collection[..., rod1_index - 1]) tangent = positiondiff / np.sqrt(np.dot(positiondiff, positiondiff)) # rod 2 has to be alligned with rod 1 check1 = (rod1.position_collection[..., rod1_index] + rod2.rest_lengths[rod2_index] * tangent) check2 = rod2.position_collection[..., rod2_index + 1] forcedirection = -kt * (check2 - check1) torque = np.cross(linkdirection, forcedirection) torque_rod1 = -rod1.director_collection[..., rod1_index] @ torque torque_rod2 = rod2.director_collection[..., rod2_index] @ torque assert_allclose(rod1.external_torques[..., rod1_index], torque_rod1, atol=Tolerance.atol()) assert_allclose(rod2.external_torques[..., rod2_index], torque_rod2, atol=Tolerance.atol())
def test_freejoint(): # Some rod properties. We need them for constructer, they are not used. normal = np.array([0.0, 1.0, 0.0]) direction = np.array([0.0, 0.0, 1.0]) base_length = 1 base_radius = 0.2 density = 1 nu = 0.1 # Youngs Modulus [Pa] E = 1e6 # poisson ratio poisson_ratio = 0.5 # Origin of the rod origin1 = np.array([0.0, 0.0, 0.0]) origin2 = np.array([1.0, 0.0, 0.0]) # Number of elements n = 4 # create rod classes rod1 = CosseratRod.straight_rod( n, origin1, direction, normal, base_length, base_radius, density, nu, E, poisson_ratio, ) rod2 = CosseratRod.straight_rod( n, origin2, direction, normal, base_length, base_radius, density, nu, E, poisson_ratio, ) # Stiffness between points k = 1e8 # Damping between two points nu = 1 # Rod indexes rod1_index = -1 rod2_index = 0 # Rod velocity v1 = np.array([-1, 0, 0]).reshape(3, 1) v2 = v1 * -1 rod1.velocity_collection = np.tile(v1, (1, n + 1)) rod2.velocity_collection = np.tile(v2, (1, n + 1)) # Compute the free joint forces distance = (rod2.position_collection[..., rod2_index] - rod1.position_collection[..., rod1_index]) end_distance = np.linalg.norm(distance) if end_distance <= Tolerance.atol(): end_distance = 1.0 elasticforce = k * distance relative_vel = (rod2.velocity_collection[..., rod2_index] - rod1.velocity_collection[..., rod1_index]) normal_relative_vel = np.dot(relative_vel, distance) / end_distance dampingforce = nu * normal_relative_vel * distance / end_distance contactforce = elasticforce - dampingforce frjt = FreeJoint(k, nu) frjt.apply_forces(rod1, rod1_index, rod2, rod2_index) frjt.apply_torques(rod1, rod1_index, rod2, rod2_index) assert_allclose(rod1.external_forces[..., rod1_index], contactforce, atol=Tolerance.atol()) assert_allclose(rod2.external_forces[..., rod2_index], -1 * contactforce, atol=Tolerance.atol())
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
base_area = np.pi * base_radius**2 density = 1750 nu = 0.001 E = 3e7 poisson_ratio = 0.5 start_rod_1 = np.zeros((3, )) start_rod_2 = start_rod_1 + direction * base_length # Create rod 1 rod1 = CosseratRod.straight_rod( n_elem, start_rod_1, direction, normal, base_length, base_radius, density, nu, E, poisson_ratio, ) hinge_joint_sim.append(rod1) # Create rod 2 rod2 = CosseratRod.straight_rod( n_elem, start_rod_2, direction, normal, base_length, base_radius, density,
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.0 )
number_of_rotations = 27 # For shear modulus of 1e4, nu is 99! poisson_ratio = 99 shear_matrix = np.repeat(1e5 * np.identity((3))[:, :, np.newaxis], n_elem, axis=2) temp_bend_matrix = np.zeros((3, 3)) np.fill_diagonal(temp_bend_matrix, [1.345, 1.345, 0.789]) bend_matrix = np.repeat(temp_bend_matrix[:, :, np.newaxis], n_elem - 1, 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 shearable_rod.bend_matrix = bend_matrix helicalbuckling_sim.append(shearable_rod) helicalbuckling_sim.constrain(shearable_rod).using( HelicalBucklingBC, constrained_position_idx=(0, -1), constrained_director_idx=(0, -1),
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 test_straight_rod(): # setting up test params n = 30 start = np.random.rand(3) direction = 5 * np.random.rand(3) direction_norm = np.linalg.norm(direction) direction /= direction_norm normal = np.array((direction[1], -direction[0], 0)) base_length = 10 base_radius = np.random.uniform(1, 10) density = np.random.uniform(1, 10) mass = density * np.pi * base_radius**2 * base_length / n nu = 0.1 # Youngs Modulus [Pa] E = 1e6 # poisson ratio poisson_ratio = 0.5 # Shear Modulus [Pa] G = E / (1.0 + poisson_ratio) # alpha c, constant for circular cross-sections # Second moment of inertia A0 = np.pi * base_radius * base_radius I0_1 = A0 * A0 / (4.0 * np.pi) I0_2 = I0_1 I0_3 = 2.0 * I0_2 I0 = np.array([I0_1, I0_2, I0_3]) # Mass second moment of inertia for disk cross-section mass_second_moment_of_inertia = np.zeros((3, 3), np.float64) np.fill_diagonal(mass_second_moment_of_inertia, I0 * density * base_length / n) # Inverse mass second of inertia inv_mass_second_moment_of_inertia = np.linalg.inv( mass_second_moment_of_inertia) # Shear/Stretch matrix shear_matrix = np.zeros((3, 3), np.float64) np.fill_diagonal(shear_matrix, [4.0 * G * A0 / 3.0, 4.0 * G * A0 / 3.0, E * A0]) # Bend/Twist matrix bend_matrix = np.zeros((3, 3), np.float64) np.fill_diagonal(bend_matrix, [E * I0_1, E * I0_2, G * I0_3]) test_rod = CosseratRod.straight_rod( n, start, direction, normal, base_length, base_radius, density, nu, E, poisson_ratio, ) # checking origin and length of rod assert_allclose(test_rod.position_collection[..., 0], start, atol=Tolerance.atol()) rod_length = np.linalg.norm(test_rod.position_collection[..., -1] - test_rod.position_collection[..., 0]) rest_voronoi_lengths = 0.5 * (base_length / n + base_length / n ) # element lengths are equal for all rod. # checking velocities, omegas and rest strains # density and mass assert_allclose(rod_length, base_length, atol=Tolerance.atol()) assert_allclose(test_rod.velocity_collection, np.zeros((3, n + 1)), atol=Tolerance.atol()) assert_allclose(test_rod.omega_collection, np.zeros((3, n)), atol=Tolerance.atol()) assert_allclose(test_rod.rest_sigma, np.zeros((3, n)), atol=Tolerance.atol()) assert_allclose(test_rod.rest_kappa, np.zeros((3, n - 1)), atol=Tolerance.atol()) assert_allclose(test_rod.density, density, atol=Tolerance.atol()) assert_allclose(test_rod.nu, nu, atol=Tolerance.atol()) assert_allclose(rest_voronoi_lengths, test_rod.rest_voronoi_lengths, atol=Tolerance.atol()) # Check mass at each node. Note that, node masses is # half of element mass at the first and last node. for i in range(1, n): assert_allclose(test_rod.mass[i], mass, atol=Tolerance.atol()) assert_allclose(test_rod.mass[0], 0.5 * mass, atol=Tolerance.atol()) assert_allclose(test_rod.mass[-1], 0.5 * mass, atol=Tolerance.atol()) # checking directors, rest length # and shear, bend matrices and moment of inertia for i in range(n): assert_allclose(test_rod.director_collection[0, :, i], normal, atol=Tolerance.atol()) assert_allclose( test_rod.director_collection[1, :, i], np.cross(direction, normal), atol=Tolerance.atol(), ) assert_allclose(test_rod.director_collection[2, :, i], direction, atol=Tolerance.atol()) assert_allclose(test_rod.rest_lengths, base_length / n, atol=Tolerance.atol()) assert_allclose(test_rod.shear_matrix[..., i], shear_matrix, atol=Tolerance.atol()) assert_allclose( test_rod.mass_second_moment_of_inertia[..., i], mass_second_moment_of_inertia, atol=Tolerance.atol(), ) assert_allclose( test_rod.inv_mass_second_moment_of_inertia[..., i], inv_mass_second_moment_of_inertia, atol=Tolerance.atol(), ) for i in range(n - 1): assert_allclose(test_rod.bend_matrix[..., i], bend_matrix, atol=Tolerance.atol())
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, }