SCoupling< M, O > Class Template Reference

#include <SCoupling.h>

+ Inheritance diagram for SCoupling< M, O >:

Classes

struct  SCoupledElement
 

Public Types

typedef O::ELEMENT ELEMENT
 

Public Member Functions

 SCoupling ()=default
 
void solveSurfaceCoupling (const unsigned max_adapt=0)
 
void solveSurfaceCoupling (unsigned nStep, const unsigned max_adapt)
 
void solveSurfaceCouplingForgiving (unsigned nStep, double timeMaxMin=-constants::inf, const unsigned max_adapt=0)
 
void solveSurfaceCouplingFixedSolid ()
 
TriangleWallcreateTriangleWall (std::array< Vec3D, 3 > vertex)
 
void updateTriangleWall (TriangleWall *&wall, std::array< Vec3D, 3 > vertex)
 
void computeOneTimeStepForSCoupling (const unsigned &nStepsMercury, const unsigned max_adapt=0)
 
void createDPMWallsFromFiniteElems ()
 
void updateDPMWallsFromFiniteElems ()
 
void updateTractionOnFiniteElems ()
 
bool computeSCouplingForcesFromTriangles (ELEMENT *const elem_pt, const unsigned &nTriangles, unsigned &wallID, Vector< Vector< double > > &nodalCouplingForces)
 
void getElementBoundingBox (ELEMENT *&elem_pt, Vec3D &min, Vec3D &max)
 
void getSCoupledElements ()
 
void coupleBoundary (unsigned b)
 
void coupleBoundaries (std::vector< unsigned > b)
 
void disableLogSurfaceCoupling ()
 
void setSolidFeelsParticles (bool val)
 
bool getSolidFeelsParticles () const
 
- Public Member Functions inherited from BaseCoupling< M, O >
 BaseCoupling ()=default
 
void setName (std::string name)
 
std::string getName () const
 
void removeOldFiles () const
 
void writeEneTimeStep (std::ostream &os) const override
 
void writeEneHeader (std::ostream &os) const override
 
void solveOomph (int max_adapt=0)
 
void checkResidual ()
 
void solveMercury (unsigned long nt)
 
void setCGWidth (const double &width)
 
double getCGWidth ()
 
bool useCGMapping ()
 
CGFunctions::LucyXYZ getCGFunction ()
 

Private Attributes

Vector< SCoupledElementsCoupledElements_
 List of surface-coupled elements. More...
 
std::vector< TriangleWall * > triangleWalls_
 List of triangle walls used for the surface coupling. More...
 
std::vector< unsignedcoupledBoundaries_
 
bool logSurfaceCoupling = true
 
bool solidFeelsParticles_ = true
 

Member Typedef Documentation

◆ ELEMENT

template<class M , class O >
typedef O::ELEMENT SCoupling< M, O >::ELEMENT

Constructor & Destructor Documentation

◆ SCoupling()

template<class M , class O >
SCoupling< M, O >::SCoupling ( )
default

Member Function Documentation

◆ computeOneTimeStepForSCoupling()

template<class M , class O >
void SCoupling< M, O >::computeOneTimeStepForSCoupling ( const unsigned nStepsMercury,
const unsigned  max_adapt = 0 
)
inline

Solve surface-coupled problem for one oomph time step (n mercury time steps)

242  {
243  auto t0 = std::chrono::system_clock::now();
245  auto t1 = std::chrono::system_clock::now();
246  BaseCoupling<M,O>::solveMercury(nStepsMercury);
247  auto t2 = std::chrono::system_clock::now();
248  if (solidFeelsParticles_) {
250  }
251  auto t3 = std::chrono::system_clock::now();
253  auto t4 = std::chrono::system_clock::now();
254  if (logSurfaceCoupling) logger(INFO, "time % Elapsed time: FEM->DEM %, DEM %, DEM->FEM %, FEM %", M::getTime(),
255  (t1-t0).count(), (t2-t1).count(), (t3-t2).count(), (t4-t3).count());
256  if(max_adapt>0)
257  {
260  }
261  }
Logger< MERCURYDPM_LOGLEVEL > logger("MercuryKernel")
Definition of different loggers with certain modules. A user can define its own custom logger here.
@ INFO
void solveOomph(int max_adapt=0)
Definition: BaseCoupling.h:120
void solveMercury(unsigned long nt)
Definition: BaseCoupling.h:149
void getSCoupledElements()
Definition: SCoupling.h:614
bool solidFeelsParticles_
Definition: SCoupling.h:732
void updateTractionOnFiniteElems()
Definition: SCoupling.h:356
void updateDPMWallsFromFiniteElems()
Definition: SCoupling.h:305
bool logSurfaceCoupling
Definition: SCoupling.h:727
void createDPMWallsFromFiniteElems()
Definition: SCoupling.h:263

References INFO, logger, BaseCoupling< M, O >::solveMercury(), and BaseCoupling< M, O >::solveOomph().

◆ computeSCouplingForcesFromTriangles()

template<class M , class O >
bool SCoupling< M, O >::computeSCouplingForcesFromTriangles ( ELEMENT *const  elem_pt,
const unsigned nTriangles,
unsigned wallID,
Vector< Vector< double > > &  nodalCouplingForces 
)
inline

Computes nodal scoupling forces from triangles.

Parameters
[in]elem_ptpointer to the element for which forces are computed
[in]nTrianglesnumber of triangles (equals number of nodes of the traction element)
[in,out]wallID
[out]nodalCouplingForces[l]= sum_i f * psi(l,cp) for each shape function l, interaction i, evaluated at contact point cp
Returns
422  {
423  // whether the element is coupled to particles
424  bool elemIsCoupled = false;
425 
426  // get number of nodes in the bulk element
427  const unsigned nnode = elem_pt->nnode();
428  // get dimension of the problem
429  const unsigned dim = elem_pt->dim();
430  // initialize the coupling force vector
431  nodalCouplingForces.resize(nnode, Vector<double>(dim, 0.0));
432 
433  // get number of TriangleWalls created from an oomph face element
434  unsigned n = 0;
435  // loop over TriangleWalls
436  while (n++ < nTriangles)
437  {
438  // get pointer to the wall
439  TriangleWall* w = triangleWalls_[wallID++];
440 
441  // skip the wall if not interactions with it
442  if (w->getInteractions().size() == 0) continue;
443 
444  // Set up memory for the shape/test functions
445  Shape psi(nnode);
446 
447  // loop over interactions with the wall
448  for (auto inter : w->getInteractions())
449  {
450  if (!inter->getForce().isZero())
451  {
452  // scale contact point and forces from DEM to FEM units
453  Vec3D xc = inter->getContactPoint();
454  Vec3D fc = inter->getForce();
455 
456  Vector<double> x(3, 0.0), f(3, 0.0);
457  x[0] = xc.getX();
458  x[1] = xc.getY();
459  x[2] = xc.getZ();
460  f[0] = fc.getX();
461  f[1] = fc.getY();
462  f[2] = fc.getZ();
463 
464  // get the local coordinate s if xc is located in the finite element
465  Vector<double> s(3, 0.0);
466  GeomObject* geom_obj_pt = 0;
467  elem_pt->locate_zeta(x, geom_obj_pt, s);
468 
469  // Get shape/test fcts
470  elem_pt->shape(s, psi);
471  // Loop over the test functions
472  for (unsigned l = 0; l < nnode; l++)
473  {
474  //Loop over the force components
475  for (unsigned i = 0; i < dim; i++)
476  {
477  // add contribution to the nodal coupling force
478  nodalCouplingForces[l][i] += f[i] * psi(l);
479  }
480  }
481  // set the flag to true
482  elemIsCoupled = true;
483  }
484  }
485  }
486  return elemIsCoupled;
487  }
int i
Definition: BiCGSTAB_step_by_step.cpp:9
const unsigned n
Definition: CG3DPackingUnitTest.cpp:11
RowVector3d w
Definition: Matrix_resize_int.cpp:3
std::vector< TriangleWall * > triangleWalls_
List of triangle walls used for the surface coupling.
Definition: SCoupling.h:719
A TriangleWall is convex polygon defined as an intersection of InfiniteWall's.
Definition: TriangleWall.h:36
Definition: Kernel/Math/Vector.h:30
Mdouble getZ() const
Definition: Kernel/Math/Vector.h:437
Mdouble getX() const
Definition: Kernel/Math/Vector.h:431
Mdouble getY() const
Definition: Kernel/Math/Vector.h:434
Definition: geom_objects.h:101
virtual void locate_zeta(const Vector< double > &zeta, GeomObject *&sub_geom_object_pt, Vector< double > &s, const bool &use_coordinate_as_initial_guess=false)
Definition: geom_objects.h:381
Definition: shape.h:76
static int f(const TensorMap< Tensor< int, 3 > > &tensor)
Definition: cxx11_tensor_map.cpp:237
RealScalar s
Definition: level1_cplx_impl.h:130
xc
Definition: MultiOpt.py:46
list x
Definition: plotDoE.py:28

References f(), Vec3D::getX(), Vec3D::getY(), Vec3D::getZ(), i, oomph::GeomObject::locate_zeta(), n, s, w, plotDoE::x, and MultiOpt::xc.

◆ coupleBoundaries()

template<class M , class O >
void SCoupling< M, O >::coupleBoundaries ( std::vector< unsigned b)
inline
697  {
698  coupledBoundaries_ = std::move(b);
699  }
Scalar * b
Definition: benchVecAdd.cpp:17
std::vector< unsigned > coupledBoundaries_
Definition: SCoupling.h:725

References b.

◆ coupleBoundary()

template<class M , class O >
void SCoupling< M, O >::coupleBoundary ( unsigned  b)
inline

◆ createDPMWallsFromFiniteElems()

template<class M , class O >
void SCoupling< M, O >::createDPMWallsFromFiniteElems ( )
inline
264  {
265  // loop over bulk elements at boundary
266  for (auto sCoupledElement : sCoupledElements_)
267  {
268  // loop over nodes in element at boundary
269  Vector<Vector<double*> > position_pt = sCoupledElement.surface_node_position_pt;
270  // reordering vertices of oomph face element (default = {0,1,3,2})
271  swap(position_pt[2], position_pt[3]);
272 
273  // get global coordinate at the center
274  Vec3D center;
275  Vector<double> x(3, 0.0);
276  sCoupledElement.bulk_elem_pt->interpolated_x(sCoupledElement.center_local, x);
277  center.setX(x[0]);
278  center.setY(x[1]);
279  center.setZ(x[2]);
280 
281  // create TriangleWalls from oomph face element
282  const unsigned nTriangles = position_pt.size();
283  unsigned n = 0;
284  while (n < nTriangles)
285  {
286  // get vertices of TriangleWall (multiply vertex position with the length scale of the O)
287  std::array<Vec3D, 3> vertex;
288  // one vertex at the center
289  vertex[0] = center;
290  // two vertices from the O<element,TIMESTEPPER>
291  vertex[1] = Vec3D(*position_pt[0][0],*position_pt[0][1],*position_pt[0][2]);
292  vertex[2] = Vec3D(*position_pt[1][0],*position_pt[1][1],*position_pt[1][2]);
293 
294  // create triangle facet
295  TriangleWall* w = createTriangleWall(vertex);
296  triangleWalls_.push_back(w);
297 
298  // rotate forward by one element
299  rotate(position_pt.begin(), position_pt.begin() + 1, position_pt.end());
300  n++;
301  }
302  }
303  }
TriangleWall * createTriangleWall(std::array< Vec3D, 3 > vertex)
Definition: SCoupling.h:196
Vector< SCoupledElement > sCoupledElements_
List of surface-coupled elements.
Definition: SCoupling.h:716
void setY(Mdouble y)
Definition: Kernel/Math/Vector.h:425
void setZ(Mdouble z)
Definition: Kernel/Math/Vector.h:428
void setX(Mdouble x)
Definition: Kernel/Math/Vector.h:422
EIGEN_BLAS_FUNC() swap(int *n, RealScalar *px, int *incx, RealScalar *py, int *incy)
Definition: level1_impl.h:117

References n, Vec3D::setX(), Vec3D::setY(), Vec3D::setZ(), swap(), w, and plotDoE::x.

◆ createTriangleWall()

template<class M , class O >
TriangleWall* SCoupling< M, O >::createTriangleWall ( std::array< Vec3D, 3 >  vertex)
inline

Create a triangle wall from a set of vertices

Parameters
vertex
Todo:
Why we need to set GroupID. I don't remember anymore.
Returns
197  {
198  TriangleWall wall;
199  auto species = M::speciesHandler.getObject(0);
200  wall.setSpecies(species);
201  wall.setGroupId(100);
202  wall.setVertices(vertex[0], vertex[1], vertex[2]);
203  auto w = M::wallHandler.copyAndAddObject(wall);
204  return w;
205  }
void setGroupId(unsigned groupId)
Definition: BaseObject.h:110
void setSpecies(const ParticleSpecies *species)
Defines the species of the current wall.
Definition: BaseWall.cc:148
void setVertices(Vec3D A, Vec3D B, Vec3D C)
Sets member variables such that the wall represents a triangle with vertices A, B,...
Definition: TriangleWall.cc:144

References BaseObject::setGroupId(), BaseWall::setSpecies(), TriangleWall::setVertices(), and w.

◆ disableLogSurfaceCoupling()

template<class M , class O >
void SCoupling< M, O >::disableLogSurfaceCoupling ( )
inline
701  {
702  logSurfaceCoupling = false;
703  }

◆ getElementBoundingBox()

template<class M , class O >
void SCoupling< M, O >::getElementBoundingBox ( ELEMENT *&  elem_pt,
Vec3D min,
Vec3D max 
)
inline

needed in computeSCouplingForcesFromCG to decide which particles affect a given element

580  {
581  // three arrays that contain the x, y and z coordinates of the bulk element
582  Vector<double> listOfCoordX;
583  Vector<double> listOfCoordY;
584  Vector<double> listOfCoordZ;
585 
586  // get the x, y and z coordinates of the bulk element
587  const unsigned nnode = elem_pt->nnode();
588  for (unsigned n = 0; n < nnode; n++)
589  {
590  listOfCoordX.push_back(elem_pt->node_pt(n)->x(0));
591  listOfCoordY.push_back(elem_pt->node_pt(n)->x(1));
592  listOfCoordZ.push_back(elem_pt->node_pt(n)->x(2));
593  }
594 
595  // get the bounding box of the bulk element
596  min.X = *min_element(listOfCoordX.begin(), listOfCoordX.end());
597  min.Y = *min_element(listOfCoordY.begin(), listOfCoordY.end());
598  min.Z = *min_element(listOfCoordZ.begin(), listOfCoordZ.end());
599  max.X = *max_element(listOfCoordX.begin(), listOfCoordX.end());
600  max.Y = *max_element(listOfCoordY.begin(), listOfCoordY.end());
601  max.Z = *max_element(listOfCoordZ.begin(), listOfCoordZ.end());
602 
603  // extend the bounding box if construct mapping with coarse graining
604  logger.assert_always(M::particleHandler.getLargestParticle(), "No particles detected");
605  //todo does it make sense with -2R here?
606  min -= Vec3D(1.0, 1.0, 1.0) * ( BaseCoupling<M,O>::getCGWidth() - 2 * M::particleHandler.getLargestParticle()->getRadius() );
607  max += Vec3D(1.0, 1.0, 1.0) * ( BaseCoupling<M,O>::getCGWidth() - 2 * M::particleHandler.getLargestParticle()->getRadius() );
608  }
double getCGWidth()
Definition: BaseCoupling.h:175
#define min(a, b)
Definition: datatypes.h:22
#define max(a, b)
Definition: datatypes.h:23

References BaseCoupling< M, O >::getCGWidth(), logger, max, min, and n.

◆ getSCoupledElements()

template<class M , class O >
void SCoupling< M, O >::getSCoupledElements ( )
inline

Get bulk elements along boundaries (SCoupling). The results are stored in sCoupledElements_.

615  {
616  // first clear bulk elements (for refineable problem)
617  sCoupledElements_.clear();
618 
619  // loop over all boundaries
620  for (unsigned b : coupledBoundaries_)
621  {
622  // number of bulk elements adjacent to boundary b
623  unsigned n_element = this->solid_mesh_pt()->nboundary_element(b);
624  // we only need to couple the elements on the upper boundary
625  logger(INFO,"Coupling boundary %. which has % elements", b, n_element);
626 
627  // loop over the bulk elements adjacent to boundary b
628  for (unsigned e = 0; e < n_element; e++)
629  {
630  // initialize the struct SCoupledElement
631  SCoupledElement sCoupledElement;
632 
633  // get pointer to the bulk element that is adjacent to boundary b
634  sCoupledElement.bulk_elem_pt = dynamic_cast<ELEMENT*>(this->solid_mesh_pt()->boundary_element_pt(b, e));
635 
636  // get the index of the face of element e along boundary b
637  sCoupledElement.face_index = this->solid_mesh_pt()->face_index_at_boundary(b, e);
638 
639  // create temporary traction element
640  SolidTractionElement<ELEMENT> trac_elem(sCoupledElement.bulk_elem_pt, sCoupledElement.face_index);
641 
642  // number of nodes on traction element
643  unsigned n_node = trac_elem.nnode();
644 
645  // allocate space to store the local coordinates of the traction element's vertices
646  sCoupledElement.surface_node_position_pt.reserve(n_node);
647 
648  // store the local coordinates of the traction element's center
649  sCoupledElement.center_local.resize(3, 0.0);
650 
651  // assign addresses of nodal coordinates to the struct SCoupledElement
652  for (unsigned n = 0; n < n_node; n++)
653  {
654  // store pointer to solid nodes
655  sCoupledElement.node_pt.push_back(dynamic_cast<CoupledSolidNode*>(trac_elem.node_pt(n)));
656 
657  Vector<double> s(2, 0.0);
658  trac_elem.local_coordinate_of_node(n, s);
659 
660  Vector<double> s_bulk(3, 0.0);
661  trac_elem.get_local_coordinate_in_bulk(s, s_bulk);
662 
663  // pass the addresses of x coordinates at boundary to x_pt
664  Vector<double*> x_pt;
665  for (unsigned i = 0; i < 3; i++)
666  {
667  x_pt.push_back(&trac_elem.node_pt(n)->x(i));
668  sCoupledElement.center_local[i] += s_bulk[i];
669  }
670  /*
671  // debug that the addresses of x coordinates are passed to surface_node_position_pt
672  cout << "Address of x(1) of node on traction element\t " << &trac_elem.node_pt(n)->x(0) << endl;
673  int nodeIDOfBulkElement = sCoupledElement.bulk_elem_pt->get_node_number(trac_elem.node_pt(n));
674  cout << "Address of x(1) of the same node in bulk element "
675  << &sCoupledElement.bulk_elem_pt->node_pt(nodeIDOfBulkElement)->x(0) << endl;
676  cout << "Address of x(1) saved in Oomph interface object\t " << x_pt[0] << endl;
677  */
678  // save the addresses of Lagrange coordinates in each element at boundary
679  sCoupledElement.surface_node_position_pt.push_back(x_pt);
680  }
681 
682  // local coordinate of the center of the face element
683  for (unsigned i = 0; i < 3; i++) sCoupledElement.center_local[i] /= n_node;
684 
685  // save bulk elements and surface nodal position pointers
686  sCoupledElements_.push_back(sCoupledElement);
687  }
688  }
689  }
Array< double, 1, 3 > e(1./3., 0.5, 2.)
O::ELEMENT ELEMENT
Definition: SCoupling.h:18
Definition: CoupledSolidNodes.h:20
Definition: SCoupledElement.h:18
Definition: solid_traction_elements.h:78

References b, SCoupling< M, O >::SCoupledElement::bulk_elem_pt, SCoupling< M, O >::SCoupledElement::center_local, e(), SCoupling< M, O >::SCoupledElement::face_index, oomph::FaceElement::get_local_coordinate_in_bulk(), i, INFO, oomph::FiniteElement::local_coordinate_of_node(), logger, n, oomph::FiniteElement::nnode(), SCoupling< M, O >::SCoupledElement::node_pt, oomph::FiniteElement::node_pt(), s, SCoupling< M, O >::SCoupledElement::surface_node_position_pt, and oomph::Node::x().

◆ getSolidFeelsParticles()

template<class M , class O >
bool SCoupling< M, O >::getSolidFeelsParticles ( ) const
inline
709  {
710  return solidFeelsParticles_;
711  }

◆ setSolidFeelsParticles()

template<class M , class O >
void SCoupling< M, O >::setSolidFeelsParticles ( bool  val)
inline
705  {
707  }
val
Definition: calibrate.py:119

References calibrate::val.

◆ solveSurfaceCoupling() [1/2]

template<class M , class O >
void SCoupling< M, O >::solveSurfaceCoupling ( const unsigned  max_adapt = 0)
inline
52  {
53  // compute nStep
54  unsigned nStep = O::getOomphTimeStep()/M::getTimeStep();
55  if (nStep==0) {
56  // if oomph has a smaller time step than Mercury
57  logger(INFO, "Set nStep %, change mercuryTimeStep from % to %",
58  nStep, M::getTimeStep(), O::getOomphTimeStep());
59  nStep = 1;
60  M::setTimeStep(O::getOomphTimeStep());
61  } else {
62  logger(INFO, "Set nStep %, change oomphTimeStep from % to %",
63  nStep, O::getOomphTimeStep(), nStep * M::getTimeStep());
64  O::setOomphTimeStep(nStep * M::getTimeStep());
65  }
66 
67  // call solve routine
68  solveSurfaceCoupling(nStep, max_adapt);
69  }
void solveSurfaceCoupling(const unsigned max_adapt=0)
Definition: SCoupling.h:51

References INFO, and logger.

Referenced by CoupledBeam::CoupledBeam(), and CoupledProblem::CoupledProblem().

◆ solveSurfaceCoupling() [2/2]

template<class M , class O >
void SCoupling< M, O >::solveSurfaceCoupling ( unsigned  nStep,
const unsigned  max_adapt 
)
inline
73  {
74  // check whether time steps are set
75  logger.assert_always(O::getOomphTimeStep()>0,"Oomph time step not initialised");
76  logger.assert_always(M::getTimeStep()>0,"Mercury time step not initialised");
77  // check whether isCoupled is set
78  logger.assert_always(!coupledBoundaries_.empty(), "isCoupled needs to be set, e.g. via setIsCoupled([](unsigned b) { return b == Boundary::Y_MIN; })");
79 
80  // first part of the Mercury solve routine, containing the actions before time-stepping
81  M::initialiseSolve();
82 
83  // read Mercury time step
84  double mercury_dt = M::getTimeStep();
85  logger(INFO, "Mercury time step: %", mercury_dt);
86 
87  // set oomph time step
88  double oomph_dt = nStep * mercury_dt;
89  logger(INFO, "Oomph time step: %", oomph_dt);
90 
91  // set oomph initial conditions
92  O::assign_initial_values_impulsive(oomph_dt);
93 
94  // read oomph-mesh
95  logger(INFO, "Set up oomph mesh: % elements (% with traction)",
96  O::solid_mesh_pt()?O::solid_mesh_pt()->nelement():0, O::traction_mesh_pt()?O::traction_mesh_pt()->nelement():0);
97 
98  // get list of bulk elements along the surface-coupled boundaries
100 
101  // create DPM triangle walls from bulk finite elements
103 
104  // this is the main loop advancing over time
105  unsigned nDone = 0; //< last written file number
106  while (M::getTime() < M::getTimeMax())
107  {
108  this->actionsBeforeOomphTimeStep();
109  // solve the coupled problem for one time step
110  computeOneTimeStepForSCoupling(nStep, max_adapt);
111  // write outputs of the oomphProb; this is slaved to the vtk output of Mercury, i.e. an oomph-lib output get written everytime a Mercury vtk file gets written
112  if (M::getParticlesWriteVTK() && M::getVtkWriter()->getFileCounter() > nDone)
113  {
114  O::writeToVTK();
115  nDone = M::getVtkWriter()->getFileCounter();
116  }
117  }
118 
119  // close output files of mercuryProb
120  M::finaliseSolve();
121  }
void computeOneTimeStepForSCoupling(const unsigned &nStepsMercury, const unsigned max_adapt=0)
Definition: SCoupling.h:241

References INFO, and logger.

◆ solveSurfaceCouplingFixedSolid()

template<class M , class O >
void SCoupling< M, O >::solveSurfaceCouplingFixedSolid ( )
inline
148  {
149  // first part of the Mercury solve routine, containing the actions before time-stepping
150  M::initialiseSolve();
151  logger.assert_always(!coupledBoundaries_.empty(), "isCoupled needs to be set, e.g. via setIsCoupled([](unsigned b) { return b == Boundary::Y_MIN; })");
152 
153  // read Mercury time step
154  double mercury_dt = M::getTimeStep();
155  logger(INFO, "Mercury time step: %", mercury_dt);
156 
157  // set oomph time step
158  logger(INFO, "Solid position fixed");
159 
160  // set oomph_dt
161  this->time_pt()->initialise_dt(0);
162  // By default do a non-impulsive start and provide initial conditions
163  this->assign_initial_values_impulsive(0);
164 
165  // read oomph-mesh
166  logger(INFO, "Set up oomph mesh: % elements (% with traction)",
167  O::solid_mesh_pt()?O::solid_mesh_pt()->nelement():0, O::traction_mesh_pt()?O::traction_mesh_pt()->nelement():0);
168 
169  // get list of bulk elements along the surface-coupled boundaries
171 
172  // create DPM triangle walls from bulk finite elements
174 
175  // this is the main loop advancing over time
176  unsigned nDone = 0; //< last written file number
177  while (M::getTime() < M::getTimeMax())
178  {
179  this->actionsBeforeOomphTimeStep();
180  M::computeOneTimeStep();
181  //if (getParticlesWriteVTK() && getVtkWriter()->getFileCounter() > nDone) {
182  // writeToVTK();
183  // nDone = getVtkWriter()->getFileCounter();
184  //}
185  }
186  // close output files of mercuryProb
187  M::finaliseSolve();
188  }

References INFO, and logger.

◆ solveSurfaceCouplingForgiving()

template<class M , class O >
void SCoupling< M, O >::solveSurfaceCouplingForgiving ( unsigned  nStep,
double  timeMaxMin = -constants::inf,
const unsigned  max_adapt = 0 
)
inline

Solves an unsteady problem, returns successful if timeMaxMin has been reached

126  {
127  // solve
128  try {
129  solveSurfaceCoupling(nStep, max_adapt);
130  } catch(OomphLibError& error) {
131  //Store output if newton solver fails
132  O::saveSolidMesh();
133  M::finaliseSolve();
134  double time = O::time_stepper_pt()->time() - nStep * M::getTimeStep();;
135  double timeMax = M::getTimeMax();;
136  if (time >= timeMaxMin) {
137  // take it as successful if a fraction of the time evolution has finished
138  logger(INFO,"Newton solver failed at t=% (tMax=%), but code will continue.", time, timeMax);
139  exit(0);
140  } else {
141  logger(ERROR,"Newton solver failed at t=% (tMax=%).", time, timeMax);
142  }
143  }
144  }
@ ERROR
Definition: oomph_definitions.h:222
int error
Definition: calibrate.py:297

References calibrate::error, ERROR, INFO, and logger.

◆ updateDPMWallsFromFiniteElems()

template<class M , class O >
void SCoupling< M, O >::updateDPMWallsFromFiniteElems ( )
inline
306  {
307  // loop over bulk elements at boundary
308  unsigned wallID = 0;
309  for (auto sCoupledElement : sCoupledElements_)
310  {
311  // get members of a SCoupledElement
312  Vector<Vector<double*> > position_pt = sCoupledElement.surface_node_position_pt;
313  Vector<CoupledSolidNode*> node_pt = sCoupledElement.node_pt;
314 
315  // reordering vertices of oomph face element (default = {0,1,3,2})
316  // \todo can we do this swap in getSCoupledElements, then we don't have to create a local copy position_pt all the time?
317  swap(position_pt[2], position_pt[3]);
318 
319  // get global coordinate at the center
320  Vector<double> x(3, 0.0);
321  sCoupledElement.bulk_elem_pt->interpolated_x(sCoupledElement.center_local, x);
322  Vec3D center {x[0], x[1], x[2]};
323 
324  // get number of TriangleWalls per oomph face element
325  const unsigned nTriangles = position_pt.size();
326  unsigned n = 0;
327  while (n < nTriangles)
328  {
329  // get vertices of TriangleWall (multiply vertex position with the length scale of the O)
330  std::array<Vec3D, 3> vertex;
331  // one vertex at the center
332  vertex[0] = center;
333  // two vertices from the O<element,TIMESTEPPER>
334  vertex[1] = Vec3D(*position_pt[0][0],
335  *position_pt[0][1],
336  *position_pt[0][2]);;
337  vertex[2] = Vec3D(*position_pt[1][0],
338  *position_pt[1][1],
339  *position_pt[1][2]);
340 
341  // update vertices of triangle facet (multiply vertex position with the length scale of the O<element,TIMESTEPPER>)
342  updateTriangleWall(triangleWalls_[wallID], vertex);
343 
344  // rotate forward by one element
345  rotate(position_pt.begin(), position_pt.begin() + 1, position_pt.end());
346  rotate(node_pt.begin(), node_pt.begin() + 1, node_pt.end());
347  n++;
348  wallID++;
349  }
350  }
351  }
void updateTriangleWall(TriangleWall *&wall, std::array< Vec3D, 3 > vertex)
Definition: SCoupling.h:212

References n, swap(), and plotDoE::x.

◆ updateTractionOnFiniteElems()

template<class M , class O >
void SCoupling< M, O >::updateTractionOnFiniteElems ( )
inline

sets nodal_coupling_residual in each scoupled element

357  {
358  // if construct mapping with FEM basis functions
360  {
361  // tracks the id of the triangle walls (get incremented in computeSCouplingForcesFromTriangles)
362  unsigned wallID = 0;
363 
364  // loop over scoupled elements
365  for (auto sCoupledElement : sCoupledElements_)
366  {
367  // set up memory for nodal coupling force
368  Vector<Vector<double> > nodalCouplingForces;
369  // returns whether the element is coupled to particles
370  bool elemIsCoupled = computeSCouplingForcesFromTriangles(sCoupledElement.bulk_elem_pt,
371  sCoupledElement.surface_node_position_pt.size(),
372  wallID,
373  nodalCouplingForces);
374 
375  // assign nodal coupling force to the element to be used by element::fill_in_contribution_to_residuals(...)
376  sCoupledElement.bulk_elem_pt->set_nodal_coupling_residual(elemIsCoupled, nodalCouplingForces);
377  }
378  logger(VERBOSE, "Update nodal_coupling_residual");
379  }
380  else
381  {
382 // // how many bulk elements in total
383 // unsigned n_element = O::solid_mesh_pt()->nelement();
384 //
385 // // loop over the bulk elements
386 // for (unsigned e = 0; e < n_element; e++)
387 // {
388 // // get pointer to the bulk element
389 // ELEMENT* elem_pt = dynamic_cast<ELEMENT*>(O::solid_mesh_pt()->element_pt(e));
390 //
391 // // set up memory for nodal coupling force
392 // Vector<Vector<double> > nodalCouplingForces;
393 // // whether the element is coupled to particles
394 // bool elemIsCoupled = computeSCouplingForcesFromCG(elem_pt, nodalCouplingForces);
395 //
396 // // assign nodal coupling force to the element to be used by element::fill_in_contribution_to_residuals(...)
397 // elem_pt->set_nodal_coupling_residual(elemIsCoupled, nodalCouplingForces);
398 // }
399 // // reset the sum of the evaluated CG values
400 // for (auto inter : M::interactionHandler)
401 // {
402 // if (inter->getI()->getName() == "TriangleWall")
403 // {
406 // inter->resetTotalCGEval();
407 // }
408 // }
409  }
410  }
@ VERBOSE
Definition: BaseCoupling.h:27
bool computeSCouplingForcesFromTriangles(ELEMENT *const elem_pt, const unsigned &nTriangles, unsigned &wallID, Vector< Vector< double > > &nodalCouplingForces)
Definition: SCoupling.h:420

References logger, and VERBOSE.

◆ updateTriangleWall()

template<class M , class O >
void SCoupling< M, O >::updateTriangleWall ( TriangleWall *&  wall,
std::array< Vec3D, 3 >  vertex 
)
inline

Update the position of a triangle wall (used in updateDPMWallsFromFiniteElems)

Todo:

why is it using setPrescribedPosition

we need to set velocity

213  {
214  double time0 = M::getTime();
215  double dTime = O::getOomphTimeStep();
216  std::array<Vec3D,3> vertex0 = wall->getVertices();
217  std::array<Vec3D,3> dVertex = {
218  vertex[0] - vertex0[0],
219  vertex[1] - vertex0[1],
220  vertex[2] - vertex0[2]};
221  wall->setPrescribedPosition( [time0, dTime, vertex0, dVertex, wall]( double time ) {
222  double f = ( time - time0 ) / dTime;
223  std::array<Vec3D, 3> vertex = {
224  vertex0[0] + dVertex[0] * f,
225  vertex0[1] + dVertex[1] * f,
226  vertex0[2] + dVertex[2] * f };
227  wall->setVertices( vertex[0], vertex[1], vertex[2] );
228  //logger(INFO,"p %",vertex[0]);
229  return wall->getPosition();
230  } );
231  Vec3D velocity = (dVertex[0]+dVertex[1]+dVertex[2])/3./dTime;
232  wall->setPrescribedVelocity([velocity] (double time) {
233  //logger(INFO,"v %",velocity);
234  return velocity;
235  });
236  }
void setPrescribedPosition(const std::function< Vec3D(double)> &prescribedPosition)
Allows the position of an infinite mass interactable to be prescribed.
Definition: BaseInteractable.cc:391
const Vec3D & getPosition() const
Returns the position of this BaseInteractable.
Definition: BaseInteractable.h:197
void setPrescribedVelocity(const std::function< Vec3D(double)> &prescribedVelocity)
Allows the velocity of an infinite mass interactable to be prescribed.
Definition: BaseInteractable.cc:422
std::array< Vec3D, 3 > getVertices() const
Definition: TriangleWall.h:84
double velocity(const double &t)
Angular velocity as function of time t.
Definition: jeffery_orbit.cc:107

References f(), BaseInteractable::getPosition(), TriangleWall::getVertices(), BaseInteractable::setPrescribedPosition(), BaseInteractable::setPrescribedVelocity(), TriangleWall::setVertices(), and Jeffery_Solution::velocity().

Member Data Documentation

◆ coupledBoundaries_

template<class M , class O >
std::vector<unsigned> SCoupling< M, O >::coupledBoundaries_
private

Function to determine whether boundary is coupled. Needs to be set before solveSurfaceCoupling is called.

◆ logSurfaceCoupling

template<class M , class O >
bool SCoupling< M, O >::logSurfaceCoupling = true
private

◆ sCoupledElements_

template<class M , class O >
Vector<SCoupledElement> SCoupling< M, O >::sCoupledElements_
private

List of surface-coupled elements.

◆ solidFeelsParticles_

template<class M , class O >
bool SCoupling< M, O >::solidFeelsParticles_ = true
private

Set false for one-way coupling (solid does not feel particles), true for two-way coupling

◆ triangleWalls_

template<class M , class O >
std::vector<TriangleWall*> SCoupling< M, O >::triangleWalls_
private

List of triangle walls used for the surface coupling.


The documentation for this class was generated from the following file: