def _compute_internal_forces( position_collection, volume, lengths, tangents, radius, rest_lengths, rest_voronoi_lengths, dilatation, voronoi_dilatation, director_collection, sigma, rest_sigma, shear_matrix, internal_stress, velocity_collection, dissipation_constant_for_forces, damping_forces, internal_forces, ): # Compute n_l and cache it using internal_stress # Be careful about usage though _compute_internal_shear_stretch_stresses_from_model( position_collection, volume, lengths, tangents, radius, rest_lengths, rest_voronoi_lengths, dilatation, voronoi_dilatation, director_collection, sigma, rest_sigma, shear_matrix, internal_stress, ) # Signifies Q^T n_L / e # Not using batch matvec as I don't want to take directors.T here blocksize = internal_stress.shape[1] cosserat_internal_stress = np.zeros((3, blocksize)) for i in range(3): for j in range(3): for k in range(blocksize): cosserat_internal_stress[i, k] += (director_collection[j, i, k] * internal_stress[j, k]) cosserat_internal_stress /= dilatation _compute_damping_forces(damping_forces, velocity_collection, dissipation_constant_for_forces, lengths) internal_forces[:] = difference_kernel( cosserat_internal_stress) - damping_forces
def _compute_internal_torques(self): # Compute \tau_l and cache it using internal_couple # Be careful about usage though self._compute_internal_bending_twist_stresses_from_model() # Compute dilatation rate when needed, dilatation itself is done before # in internal_stresses self._compute_dilatation_rate() # FIXME: change memory overload instead for the below calls! voronoi_dilatation_inv_cube_cached = 1.0 / self.voronoi_dilatation**3 # Delta(\tau_L / \Epsilon^3) bend_twist_couple_2D = difference_kernel( self.internal_couple * voronoi_dilatation_inv_cube_cached) # \mathcal{A}[ (\kappa x \tau_L ) * \hat{D} / \Epsilon^3 ] bend_twist_couple_3D = quadrature_kernel( _batch_cross(self.kappa, self.internal_couple) * self.rest_voronoi_lengths * voronoi_dilatation_inv_cube_cached) # (Qt x n_L) * \hat{l} shear_stretch_couple = (_batch_cross( _batch_matvec(self.director_collection, self.tangents), self.internal_stress, ) * self.rest_lengths) # I apply common sub expression elimination here, as J w / e is used in both the lagrangian and dilatation # terms # TODO : the _batch_matvec kernel needs to depend on the representation of J, and should be coded as such J_omega_upon_e = (_batch_matvec(self.mass_second_moment_of_inertia, self.omega_collection) / self.dilatation) # (J \omega_L / e) x \omega_L # Warning : Do not do micro-optimization here : you can ignore dividing by dilatation as we later multiply by it # but this causes confusion and violates SRP lagrangian_transport = _batch_cross(J_omega_upon_e, self.omega_collection) # Note : in the computation of dilatation_rate, there is an optimization opportunity as dilatation rate has # a dilatation-like term in the numerator, which we cancel here # (J \omega_L / e^2) . (de/dt) unsteady_dilatation = J_omega_upon_e * self.dilatation_rate / self.dilatation # Compute damping torques self._compute_damping_torques() return (bend_twist_couple_2D + bend_twist_couple_3D + shear_stretch_couple + lagrangian_transport + unsteady_dilatation - self.damping_torques)
def _compute_internal_forces(self): # Compute n_l and cache it using internal_stress # Be careful about usage though self._compute_internal_shear_stretch_stresses_from_model() # Signifies Q^T n_L / e # Not using batch matvec as I don't want to take directors.T here # FIXME: change memory overload instead for the below calls! cosserat_internal_stress = ( np.einsum("jik, jk->ik", self.director_collection, self.internal_stress) / self. dilatation # computed in comp_dilatation <- compute_strain <- compute_stress ) # self._compute_internal_forces() self._compute_damping_forces() return difference_kernel( cosserat_internal_stress) - self.damping_forces
def _compute_internal_forces(self): """ This method computes internal forces acting on elements. Returns ------- """ # Compute n_l and cache it using internal_stress # Be careful about usage though self._compute_internal_shear_stretch_stresses_from_model() # Signifies Q^T n_L / e # Not using batch matvec as I don't want to take directors.T here cosserat_internal_stress = ( np.einsum("jik, jk->ik", self.director_collection, self.internal_stress) / self.dilatation # computed in comp_dilatation <- compute_strain <- compute_stress ) return ( difference_kernel(cosserat_internal_stress) - self._compute_damping_forces() )
def _apply_forces(amplitude, wt, tangents, external_forces): muscle_force = tangents * amplitude * np.abs(np.sin(wt)) external_forces += difference_kernel(muscle_force)
def _compute_internal_torques( position_collection, velocity_collection, tangents, lengths, rest_lengths, director_collection, rest_voronoi_lengths, bend_matrix, rest_kappa, kappa, voronoi_dilatation, mass_second_moment_of_inertia, omega_collection, internal_stress, internal_couple, dilatation, dilatation_rate, dissipation_constant_for_torques, damping_torques, internal_torques, ): # Compute \tau_l and cache it using internal_couple # Be careful about usage though _compute_internal_bending_twist_stresses_from_model( director_collection, rest_voronoi_lengths, internal_couple, bend_matrix, kappa, rest_kappa, ) # Compute dilatation rate when needed, dilatation itself is done before # in internal_stresses _compute_dilatation_rate(position_collection, velocity_collection, lengths, rest_lengths, dilatation_rate) # FIXME: change memory overload instead for the below calls! voronoi_dilatation_inv_cube_cached = 1.0 / voronoi_dilatation**3 # Delta(\tau_L / \Epsilon^3) bend_twist_couple_2D = difference_kernel( internal_couple * voronoi_dilatation_inv_cube_cached) # \mathcal{A}[ (\kappa x \tau_L ) * \hat{D} / \Epsilon^3 ] bend_twist_couple_3D = quadrature_kernel( _batch_cross(kappa, internal_couple) * rest_voronoi_lengths * voronoi_dilatation_inv_cube_cached) # (Qt x n_L) * \hat{l} shear_stretch_couple = (_batch_cross( _batch_matvec(director_collection, tangents), internal_stress) * rest_lengths) # I apply common sub expression elimination here, as J w / e is used in both the lagrangian and dilatation # terms # TODO : the _batch_matvec kernel needs to depend on the representation of J, and should be coded as such J_omega_upon_e = ( _batch_matvec(mass_second_moment_of_inertia, omega_collection) / dilatation) # (J \omega_L / e) x \omega_L # Warning : Do not do micro-optimization here : you can ignore dividing by dilatation as we later multiply by it # but this causes confusion and violates SRP lagrangian_transport = _batch_cross(J_omega_upon_e, omega_collection) # Note : in the computation of dilatation_rate, there is an optimization opportunity as dilatation rate has # a dilatation-like term in the numerator, which we cancel here # (J \omega_L / e^2) . (de/dt) unsteady_dilatation = J_omega_upon_e * dilatation_rate / dilatation _compute_damping_torques(damping_torques, omega_collection, dissipation_constant_for_torques, lengths) blocksize = internal_torques.shape[1] for i in range(3): for k in range(blocksize): internal_torques[i, k] = (bend_twist_couple_2D[i, k] + bend_twist_couple_3D[i, k] + shear_stretch_couple[i, k] + lagrangian_transport[i, k] + unsteady_dilatation[i, k] - damping_torques[i, k])