def analytical_solution(self, type, time): if type == "Positions": analytical_solution = (np.hstack((self.init_pos, self.final_pos)) + np.sin(np.pi * time) / np.pi**2) elif type == "Velocity": analytical_solution = (0.0 * np.hstack( (self.init_pos, self.final_pos)) + np.cos(np.pi * time) / np.pi) elif type == "Directors": from elastica._rotations import _rotate final_angle = self.omega_value * time + 0.5 * 0.1 * np.pi * time**2 axis = np.array([0.0, 0.0, 1.0]).reshape(3, 1) # There is only one director analytical_solution = _rotate(self.init_dir, final_angle, axis) return analytical_solution
def rotate(matrix, scale, axis): """ This function takes single or multiple frames as matrix. Then rotates these frames around a single axis for all frames, or can rotate each frame around its own rotation axis as defined by user. Scale determines how much frames rotates around this axis. matrix: minimum shape = dim**2x1, supports shape = 3x3xn axis: minimum dim = 3x1, 1x3, supports dim = 3xn, nx3 scale: minimum float, supports 1D vectors also dim = n """ matrix = format_matrix_shape(matrix) axis = format_vector_shape(axis) return _rotate(matrix, scale, axis)
def analytical_solution(self, type, time): if type == "Positions": analytical_solution = (np.hstack( (self.init_pos)) + np.sin(np.pi * time) / np.pi**2) elif type == "Velocity": analytical_solution = (0.0 * np.hstack( (self.init_pos)) + np.cos(np.pi * time) / np.pi) elif type == "Directors": final_angle = self.omega_value * time + 0.5 * 0.1 * np.pi * time**2 axis = np.array([0.0, 0.0, 1.0]).reshape(3, 1) # There is only one director # Reshaping done to prevent numba equivalent to complain # While we can prevent it here, its' done to make the front end testing scripts "look" # nicer and cleaner analytical_solution = _rotate(self.init_dir, final_angle, axis).reshape(-1, 1) return analytical_solution
def __add__(self, scaled_derivative_state): """overloaded + operator, useful in state.k1 = state + dt * deriv_state The add for directors is customized to reflect Rodrigues' rotation formula. Parameters ---------- scaled_derivative_state : np.ndarray with dt * (v, ω, dv/dt, dω/dt) ,as returned from _DerivativeState's __mul__ method Returns ------- state : new _State object with modified data (copied) Caveats ------- Note that the argument is not a `other` _State object but is rather assumed to be a `np.ndarray` from calling _DerivativeState's __mul__ method. This reflects the most common use-case in time-steppers """ # x += v*dt position_collection = ( self.position_collection + scaled_derivative_state[..., : self.n_nodes] ) # Devs : see `_State.__iadd__` for reasons why we do matmul here director_collection = _rotate( self.director_collection, 1.0, scaled_derivative_state[..., self.n_nodes : self.n_kinematic_rates], ) # (v,ω) += (dv/dt, dω/dt)*dt kinematic_rate_collection = ( self.kinematic_rate_collection + scaled_derivative_state[..., self.n_kinematic_rates :] ) return _State( self.n_nodes - 1, position_collection, director_collection, kinematic_rate_collection, )
def test_rotate_correctness(): blocksize = 16 def get_aligned_director_collection(theta_collection): sins = np.sin(theta_collection) coss = np.cos(theta_collection) # Get basic director out, then modify it as you like dir = np.tile(np.eye(3).reshape(3, 3, 1), blocksize) dir[0, 0, ...] = coss # Flip signs on [0,1] and [1,0] to go from our row-wise # representation to the more commonly used # columnwise representation, for similar reasons metioned # before dir[0, 1, ...] = sins dir[1, 0, ...] = -sins dir[1, 1, ...] = coss return dir base_angle = np.deg2rad(np.linspace(0.0, 90.0, blocksize)) rotated_by = np.deg2rad(15.0) + 0.0 * base_angle rotated_about = np.array([0.0, 0.0, 1.0]).reshape(-1, 1) director_collection = get_aligned_director_collection(base_angle) axis_collection = np.tile(rotated_about, blocksize) axis_collection *= rotated_by dt = 1.0 test_rotated_director_collection = _rotate(director_collection, dt, axis_collection) correct_rotation = rotated_by + 1.0 * base_angle correct_rotated_director_collection = get_aligned_director_collection( correct_rotation) assert test_rotated_director_collection.shape == (3, 3, blocksize) assert_allclose( test_rotated_director_collection, correct_rotated_director_collection, atol=Tolerance.atol(), )