SCoupling.h
Go to the documentation of this file.
1 // This file is part of the MercuryDPM project (https://www.mercurydpm.org).
2 // Copyright (c), The MercuryDPM Developers Team. All rights reserved.
3 // License: BSD 3-Clause License; see the LICENSE file in the root directory.
4 
5 #ifndef SURFACE_COUPLING_H
6 #define SURFACE_COUPLING_H
7 
9 #include "SCoupledElement.h"
10 #include "Logger.h"
11 #include "chrono"
12 using namespace oomph;
13 
14 template<class M, class O>
15 class SCoupling : public BaseCoupling<M, O>
16 {
17 public:
18  typedef typename O::ELEMENT ELEMENT;
19 
25  {
26  // pointer to the oomph bulk element
28  // index of the face on the coupled boundary
30  // local coordinates of a traction element's nodes
32  // pointer to solid nodes of the traction element
34  // local coordinates of a traction element's center
36  };
37 
38  // default constructor
39  SCoupling() = default;
40 
41 // // sets a cg width before solving a surface coupled OomphMercuryProblem
42 // void solveSurfaceCoupling(unsigned nStep, const double& width)
43 // {
44 // // set the coarse-grainning width w.r.t. length scale
45 // setCGWidth(width); // dimensional
46 // // solve surface coupled OomphMercuryProblem
47 // solveSurfaceCoupling(nStep);
48 // }
49 
50  // solve surface coupled OomphMercuryProblem
51  void solveSurfaceCoupling(const unsigned max_adapt = 0)
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  }
70 
71  // solve surface coupled OomphMercuryProblem
72  void solveSurfaceCoupling(unsigned nStep, const unsigned max_adapt)
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
99  getSCoupledElements();
100 
101  // create DPM triangle walls from bulk finite elements
102  createDPMWallsFromFiniteElems();
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  }
122 
126  void solveSurfaceCouplingForgiving(unsigned nStep, double timeMaxMin=-constants::inf, const unsigned max_adapt = 0) {
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  }
145 
146  // solve OomphMercuryProblem, but with fixed solid
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
170  getSCoupledElements();
171 
172  // create DPM triangle walls from bulk finite elements
173  createDPMWallsFromFiniteElems();
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  }
189 
196  TriangleWall* createTriangleWall(std::array<Vec3D, 3> vertex)
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  }
206 
212  void updateTriangleWall(TriangleWall*& wall, std::array<Vec3D, 3> vertex)
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  }
237 
241  void computeOneTimeStepForSCoupling(const unsigned& nStepsMercury, const unsigned max_adapt = 0)
242  {
243  auto t0 = std::chrono::system_clock::now();
244  updateDPMWallsFromFiniteElems();
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_) {
249  updateTractionOnFiniteElems();
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  {
258  getSCoupledElements();
259  createDPMWallsFromFiniteElems();
260  }
261  }
262 
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  }
304 
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  }
352 
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  }
411 
420  bool computeSCouplingForcesFromTriangles(ELEMENT* const elem_pt, const unsigned& nTriangles,
421  unsigned& wallID, Vector<Vector<double> >& nodalCouplingForces)
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  }
488 
489 // /**
490 // * Computes nodal scoupling forces from triangles using coarse graining
491 // * \param[in] elem_pt pointer to the element for which forces are computed
492 // * \param[in,out] nodalCouplingForces coupling forces at nodal positions to be added to the residual
493 // * \return
494 // */
495 // bool computeSCouplingForcesFromCG(ELEMENT*& elem_pt, Vector<Vector<double> >& nodalCouplingForces)
496 // {
497 // // whether the element is coupled to particles
498 // bool elemIsCoupled = false;
499 //
500 // // get number of nodes in the bulk element
501 // const unsigned nnode = elem_pt->nnode();
502 // // get dimension of the problem
503 // const unsigned dim = elem_pt->dim();
504 // // initialize the coupling force vector
505 // nodalCouplingForces.resize(nnode, Vector<double>(dim, 0.0));
506 //
507 // // get particles if there are in the bounding box
508 // Vec3D min, max;
509 // getElementBoundingBox(elem_pt, min, max);
510 // Vector<BaseParticle*> pList;
511 // BaseCoupling<M,O>::getParticlesInCell(min, max, pList);
512 //
513 // // loop over shape functions at the contact points
514 // for (const auto p : pList)
515 // {
516 // for (const auto inter : p->getInteractions())
517 // {
518 // if (inter->getI()->getName() == "TriangleWall")
519 // {
520 // // get the number of integration points
521 // const unsigned n_intpt = elem_pt->integral_pt()->nweight();
522 //
523 // // loop over the integration points
524 // for (unsigned ipt = 0; ipt < n_intpt; ipt++)
525 // {
526 // // set up memory for the local and global coordinates
527 // Vector<double> s(dim, 0.0), x(dim, 0.0);
528 //
529 // // get the value of the local coordinates at the integration point
530 // for (unsigned i = 0; i < dim; i++) s[i] = elem_pt->integral_pt()->knot(ipt, i);
531 //
532 // // get the value of the global coordinates at the integration point
533 // elem_pt->interpolated_x(s, x);
534 //
535 // // set CG coordinates
536 // CGCoordinates::XYZ coordinate;
537 // coordinate.setXYZ(Vec3D(x[0], x[1], x[2]));
538 // // evaluate the value of CG function around particle m at CGcoords \phi(\vec r_i-r_m)
539 // double phi = BaseCoupling<M,O>::getCGFunction().evaluateCGFunction(
540 // inter->getContactPoint(), coordinate);
541 //
542 // // add contributions to the coupling force
543 // if (!inter->getForce().isZero() && phi > 0.0)
544 // {
545 // // set the flag to true
546 // elemIsCoupled = true;
547 //
548 // // Set up memory for the shape/test functions
549 // Shape psi(nnode);
550 //
551 // // get the integral weight
552 // double w = elem_pt->integral_pt()->weight(ipt);
553 // // find the shape functions at the integration points r_i
554 // elem_pt->shape_at_knot(ipt, psi);
555 //
556 // // loop over the nodes
557 // for (unsigned l = 0; l < nnode; l++)
558 // {
559 // // CG mapping defined as \tilde{N_{l,m}}_ipt = w_ipt * \phi(\vec r_i-r_m) * N_l(r_i)
560 // double shape = w * phi * psi(l);
561 // inter->addCGEval(shape);
562 // shape /= inter->getPreviousTotalCGEval();
563 // Vec3D fc = inter->getForce() * shape;
564 // nodalCouplingForces[l][0] += fc.getX();
565 // nodalCouplingForces[l][1] += fc.getY();
566 // nodalCouplingForces[l][2] += fc.getZ();
567 // }
568 // }
569 // }
570 // }
571 // }
572 // }
573 // return elemIsCoupled;
574 // }
575 
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  }
609 
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  }
690 
691  // set is_pinned such that a certain boundary is pinned
692  void coupleBoundary(unsigned b) {
693  coupledBoundaries_ = {b};
694  }
695 
696  // set is_pinned such that a certain boundary is pinned
697  void coupleBoundaries(std::vector<unsigned> b) {
698  coupledBoundaries_ = std::move(b);
699  }
700 
702  logSurfaceCoupling = false;
703  }
704 
706  solidFeelsParticles_ = val;
707  }
708 
709  bool getSolidFeelsParticles() const {
710  return solidFeelsParticles_;
711  }
712 
713 private:
714 
717 
719  std::vector<TriangleWall*> triangleWalls_;
720 
725  std::vector<unsigned> coupledBoundaries_;
726 
727  bool logSurfaceCoupling = true;
728 
732  bool solidFeelsParticles_ = true;
733 };
734 
735 #endif //SURFACE_COUPLING_H
int i
Definition: BiCGSTAB_step_by_step.cpp:9
const unsigned n
Definition: CG3DPackingUnitTest.cpp:11
Array< double, 1, 3 > e(1./3., 0.5, 2.)
LL< Log::VERBOSE > VERBOSE
Verbose information.
Definition: Logger.cc:36
Logger< MERCURYDPM_LOGLEVEL > logger("MercuryKernel")
Definition of different loggers with certain modules. A user can define its own custom logger here.
LL< Log::ERROR > ERROR
Error log level.
Definition: Logger.cc:32
RowVector3d w
Definition: Matrix_resize_int.cpp:3
Scalar * b
Definition: benchVecAdd.cpp:17
Definition: BaseCoupling.h:27
void solveOomph(int max_adapt=0)
Definition: BaseCoupling.h:120
double getCGWidth()
Definition: BaseCoupling.h:175
void solveMercury(unsigned long nt)
Definition: BaseCoupling.h:149
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
void setGroupId(unsigned groupId)
Definition: BaseObject.h:110
void setSpecies(const ParticleSpecies *species)
Defines the species of the current wall.
Definition: BaseWall.cc:148
Definition: SCoupling.h:16
void solveSurfaceCoupling(unsigned nStep, const unsigned max_adapt)
Definition: SCoupling.h:72
void disableLogSurfaceCoupling()
Definition: SCoupling.h:701
void solveSurfaceCouplingForgiving(unsigned nStep, double timeMaxMin=-constants::inf, const unsigned max_adapt=0)
Definition: SCoupling.h:126
void getElementBoundingBox(ELEMENT *&elem_pt, Vec3D &min, Vec3D &max)
Definition: SCoupling.h:579
void coupleBoundaries(std::vector< unsigned > b)
Definition: SCoupling.h:697
void getSCoupledElements()
Definition: SCoupling.h:614
bool getSolidFeelsParticles() const
Definition: SCoupling.h:709
void computeOneTimeStepForSCoupling(const unsigned &nStepsMercury, const unsigned max_adapt=0)
Definition: SCoupling.h:241
void solveSurfaceCouplingFixedSolid()
Definition: SCoupling.h:147
O::ELEMENT ELEMENT
Definition: SCoupling.h:18
void updateTractionOnFiniteElems()
Definition: SCoupling.h:356
TriangleWall * createTriangleWall(std::array< Vec3D, 3 > vertex)
Definition: SCoupling.h:196
void updateTriangleWall(TriangleWall *&wall, std::array< Vec3D, 3 > vertex)
Definition: SCoupling.h:212
void updateDPMWallsFromFiniteElems()
Definition: SCoupling.h:305
std::vector< unsigned > coupledBoundaries_
Definition: SCoupling.h:725
void solveSurfaceCoupling(const unsigned max_adapt=0)
Definition: SCoupling.h:51
bool computeSCouplingForcesFromTriangles(ELEMENT *const elem_pt, const unsigned &nTriangles, unsigned &wallID, Vector< Vector< double > > &nodalCouplingForces)
Definition: SCoupling.h:420
std::vector< TriangleWall * > triangleWalls_
List of triangle walls used for the surface coupling.
Definition: SCoupling.h:719
Vector< SCoupledElement > sCoupledElements_
List of surface-coupled elements.
Definition: SCoupling.h:716
SCoupling()=default
void coupleBoundary(unsigned b)
Definition: SCoupling.h:692
void createDPMWallsFromFiniteElems()
Definition: SCoupling.h:263
void setSolidFeelsParticles(bool val)
Definition: SCoupling.h:705
A TriangleWall is convex polygon defined as an intersection of InfiniteWall's.
Definition: TriangleWall.h:36
std::array< Vec3D, 3 > getVertices() const
Definition: TriangleWall.h:84
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
Definition: Kernel/Math/Vector.h:30
Mdouble getZ() const
Definition: Kernel/Math/Vector.h:437
void setY(Mdouble y)
Definition: Kernel/Math/Vector.h:425
Mdouble getX() const
Definition: Kernel/Math/Vector.h:431
void setZ(Mdouble z)
Definition: Kernel/Math/Vector.h:428
void setX(Mdouble x)
Definition: Kernel/Math/Vector.h:422
Mdouble getY() const
Definition: Kernel/Math/Vector.h:434
Definition: CoupledSolidNodes.h:20
void get_local_coordinate_in_bulk(const Vector< double > &s, Vector< double > &s_bulk) const
Definition: elements.cc:6384
virtual void local_coordinate_of_node(const unsigned &j, Vector< double > &s) const
Definition: elements.h:1842
Node *& node_pt(const unsigned &n)
Return a pointer to the local node n.
Definition: elements.h:2175
unsigned nnode() const
Return the number of nodes.
Definition: elements.h:2210
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
double & x(const unsigned &i)
Return the i-th nodal coordinate.
Definition: nodes.h:1060
Definition: oomph_definitions.h:222
Definition: shape.h:76
Definition: solid_traction_elements.h:78
Definition: oomph-lib/src/generic/Vector.h:58
static int f(const TensorMap< Tensor< int, 3 > > &tensor)
Definition: cxx11_tensor_map.cpp:237
#define min(a, b)
Definition: datatypes.h:22
#define max(a, b)
Definition: datatypes.h:23
RealScalar s
Definition: level1_cplx_impl.h:130
EIGEN_BLAS_FUNC() swap(int *n, RealScalar *px, int *incx, RealScalar *py, int *incy)
Definition: level1_impl.h:117
#define INFO(i)
Definition: mumps_solver.h:54
double velocity(const double &t)
Angular velocity as function of time t.
Definition: jeffery_orbit.cc:107
xc
Definition: MultiOpt.py:46
val
Definition: calibrate.py:119
int error
Definition: calibrate.py:297
const Mdouble inf
Definition: GeneralDefine.h:23
DRAIG: Change all instances of (SPATIAL_DIM) to (DIM-1).
Definition: AnisotropicHookean.h:10
list x
Definition: plotDoE.py:28
Definition: SCoupling.h:25
Vector< Vector< double * > > surface_node_position_pt
Definition: SCoupling.h:31
Vector< double > center_local
Definition: SCoupling.h:35
int face_index
Definition: SCoupling.h:29
Vector< CoupledSolidNode * > node_pt
Definition: SCoupling.h:33
ELEMENT * bulk_elem_pt
Definition: SCoupling.h:27