Skip to content

Commit

Permalink
Merge pull request #161 from SophT-Team/160_elasticapp_interface
Browse files Browse the repository at this point in the history
160 elasticapp interface
  • Loading branch information
armantekinalp authored Sep 12, 2023
2 parents 99a094e + 9c5562b commit b483023
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 0 deletions.
1 change: 1 addition & 0 deletions sopht/simulator/immersed_body/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
from .rigid_body import *
from .cosserat_rod import *
from .flow_forces import FlowForces
from .cosserat_rod_cpp import *
4 changes: 4 additions & 0 deletions sopht/simulator/immersed_body/cosserat_rod_cpp/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from .cosserat_rod_cpp_forcing_grids import (
CosseratRodCPPElementCentricForcingGrid,
)
from .cosserat_rod_cpp_flow_interaction import CosseratRodCPPFlowInteraction
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import numpy as np
from sopht.simulator.immersed_body import (
ImmersedBodyForcingGrid,
ImmersedBodyFlowInteraction,
)
from typing import Type, Optional


class CosseratRodCPPFlowInteraction(ImmersedBodyFlowInteraction):
"""Class for Elastica++ Cosserat rod flow interaction."""

def __init__(
self,
cosserat_rod_simulator,
eul_grid_forcing_field: np.ndarray,
eul_grid_velocity_field: np.ndarray,
virtual_boundary_stiffness_coeff: float,
virtual_boundary_damping_coeff: float,
dx: float,
grid_dim: int,
forcing_grid_cls: Type[ImmersedBodyForcingGrid],
real_t: type = np.float64,
eul_grid_coord_shift: Optional[float] = None,
interp_kernel_width: Optional[float] = None,
enable_eul_grid_forcing_reset: bool = False,
num_threads: int | bool = False,
start_time: float = 0.0,
**forcing_grid_kwargs,
) -> None:
"""Class initialiser."""
rod, _ = cosserat_rod_simulator.communicate()
n_elems = int(rod.n_elems[0])
body_flow_forces = np.zeros(
(3, n_elems + 1),
)
body_flow_torques = np.zeros(
(3, n_elems),
)

forcing_grid_kwargs["cosserat_rod_simulator"] = cosserat_rod_simulator

# initialising super class
super().__init__(
eul_grid_forcing_field,
eul_grid_velocity_field,
body_flow_forces,
body_flow_torques,
forcing_grid_cls,
virtual_boundary_stiffness_coeff,
virtual_boundary_damping_coeff,
dx,
grid_dim,
real_t,
eul_grid_coord_shift,
interp_kernel_width,
enable_eul_grid_forcing_reset,
num_threads,
start_time,
**forcing_grid_kwargs,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
from elastica.interaction import node_to_element_velocity
import numpy as np
from sopht.simulator.immersed_body import ImmersedBodyForcingGrid


class CosseratRodCPPElementCentricForcingGrid(ImmersedBodyForcingGrid):
"""Class for forcing grid at Cosserat rod element centers"""

def __init__(self, grid_dim: int, cosserat_rod_simulator) -> None:
self.cs = cosserat_rod_simulator
rod, _ = self.cs.communicate()
num_lag_nodes = int(rod.n_elems[0])
super().__init__(grid_dim, num_lag_nodes)

# to ensure position/velocity are consistent during initialisation
self.compute_lag_grid_position_field()
self.compute_lag_grid_velocity_field()

def compute_lag_grid_position_field(self) -> None:
"""Computes location of forcing grid for the Cosserat rod"""
rod, _ = self.cs.communicate()
rod_position_field = np.asarray(rod.get_position())
self.position_field[...] = (
rod_position_field[: self.grid_dim, 1:]
+ rod_position_field[: self.grid_dim, :-1]
) / 2.0

def compute_lag_grid_velocity_field(self) -> None:
"""Computes velocity of forcing grid points for the Cosserat rod"""
rod, _ = self.cs.communicate()
rod_velocity_field = np.asarray(rod.get_velocity())
rod_masses = np.asarray(rod.mass)

self.velocity_field[...] = node_to_element_velocity(
rod_masses, rod_velocity_field
)[: self.grid_dim]

def transfer_forcing_from_grid_to_body(
self,
body_flow_forces: np.ndarray,
body_flow_torques: np.ndarray,
lag_grid_forcing_field: np.ndarray,
) -> None:
"""Transfer forcing from lagrangian forcing grid to the cosserat rod"""
# negative sign due to Newtons third law
_, body_forces_cpp = self.cs.communicate()
body_forces_cpp = np.asarray(body_forces_cpp)
body_flow_forces[...] = 0.0
body_flow_forces[: self.grid_dim, 1:] -= 0.5 * lag_grid_forcing_field
body_flow_forces[: self.grid_dim, :-1] -= 0.5 * lag_grid_forcing_field

body_forces_cpp *= 0.0
body_forces_cpp[: self.grid_dim, 1:] -= 0.5 * lag_grid_forcing_field
body_forces_cpp[: self.grid_dim, :-1] -= 0.5 * lag_grid_forcing_field

# torque from grid forcing (don't modify since set = 0 at initialisation)
# because no torques acting on element centers

def get_maximum_lagrangian_grid_spacing(self) -> float:
"""Get the maximum Lagrangian grid spacing"""
# estimated distance between consecutive elements
rod, _ = self.cs.communicate()
return np.amax(np.asarray(rod.lengths))

0 comments on commit b483023

Please sign in to comment.