26 #ifndef SCALE_COUPLING_H
27 #define SCALE_COUPLING_H
32 #include "../Coupling/BaseCoupling.h"
37 using namespace oomph;
39 template<
class M,
class O>
72 if (coupledElement_pt !=
nullptr) {
74 coupledElement_pt =
nullptr;
81 if (coupledElement_pt != coupledElementNew) {
82 if (coupledElement_pt !=
nullptr) {
84 logger(
VERBOSE,
"Moved particle % from element % to %", particle->
getIndex(), coupledElement_pt, coupledElementNew);
89 coupledElement_pt = coupledElementNew;
106 return coupledElements_;
111 return coupledParticles_;
120 void setCouplingWeight(
const std::function<
double(
double x,
double y,
double z)>& couplingWeight) {
121 couplingWeight_ = couplingWeight;
128 unsigned nStep = O::getOomphTimeStep()/M::getTimeStep();
131 logger(
INFO,
"Set nStep %, change mercuryTimeStep from % to %",
132 nStep, M::getTimeStep(), O::getOomphTimeStep());
134 M::setTimeStep(O::getOomphTimeStep());
136 logger(
INFO,
"Set nStep %, change oomphTimeStep from % to %",
137 nStep, O::getOomphTimeStep(), nStep * M::getTimeStep());
138 O::setOomphTimeStep(nStep * M::getTimeStep());
141 solveScaleCoupling(nStep);
150 logger.assert_always(O::getOomphTimeStep()>0,
"Oomph time step not initialised");
151 logger.assert_always(M::getTimeStep()>0,
"Mercury time step not initialised");
152 logger.assert_always(std::isfinite(penalty_),
"Penalty parameter not set");
153 logger.assert_always((
bool)couplingWeight_,
"Coupling weight is not set");
156 initialiseCoupledElements();
160 while (M::getTime() < M::getTimeMax())
162 O::actionsBeforeOomphTimeStep();
164 computeOneTimeStepScaleCoupling(nStep);
166 if (M::getParticlesWriteVTK() && M::getVtkWriter()->getFileCounter() > nDone)
169 nDone = M::getVtkWriter()->getFileCounter();
181 auto nelement = O::mesh_pt()->nelement();
182 for (
int e=0; e < nelement; ++e) {
183 bool coupledElement =
false;
184 auto* el_pt =
dynamic_cast<ELEMENT*
>(O::mesh_pt()->finite_element_pt(e));
185 auto nnode = el_pt->nnode();
186 Vector<double> nodalCouplingWeights(nnode);
187 for (
int n=0;
n < nnode; ++
n) {
188 auto* n_pt =
dynamic_cast<SolidNode*
>(el_pt->node_pt(
n));
189 nodalCouplingWeights[
n] = couplingWeight_(n_pt->xi(0), n_pt->xi(1), n_pt->xi(2));
190 if (nodalCouplingWeights[
n]>0) {
191 coupledElement =
true;
192 logger(
VERBOSE,
"Coupled element at % % %, weight %",n_pt->xi(0), n_pt->xi(1), n_pt->xi(2), nodalCouplingWeights[
n]);
195 if (coupledElement) {
196 coupledElements_.push_back({el_pt});
197 el_pt->set_coupling_weight(nodalCouplingWeights);
200 logger(
INFO,
"% of % el_pts are coupled", coupledElements_.size(), nelement);
205 updateCoupledElements();
206 computeCouplingForce();
208 this->solveMercury(nStep);
218 for (
auto& coupledElement : coupledElements_)
220 ELEMENT* el_pt = coupledElement.el_pt;
221 const unsigned nnode = el_pt->nnode();
222 const unsigned dim = el_pt->dim();
224 for (
int n=0;
n<nnode; ++
n) {
225 auto* n_pt =
dynamic_cast<SolidNode *
>(el_pt->node_pt(
n));
226 for (
int d = 0; d < dim; ++d) {
227 min[d] = std::min(min[d], n_pt->x(d));
228 max[d] = std::max(max[d], n_pt->x(d));
232 logger(
VERBOSE,
"Coupling zone: % < x < %, % < y < %, % < z < % ",min[0],max[0],min[1],max[1],min[2],max[2]);
236 coupledParticles_.resize(M::particleHandler.getSize());
238 for (
int p=0; p<coupledParticles_.size(); ++p) {
240 Vec3D pos = M::particleHandler.getObject(p)->getPosition();
242 if (pos.
X>=min[0] && pos.
X<=max[0] && pos.
Y>=min[1] && pos.
Y<=max[1] && pos.
Z>=min[2] && pos.
Z<=max[2]) {
243 logger(
VERBOSE,
"Particle % of % is in coupling zone",p, M::particleHandler.getSize());
245 Vector<double> x {pos.
X, pos.
Y, pos.
Z};
246 Vector<double>& s = coupledParticle.
s;
247 GeomObject* geom_obj_pt;
251 if (geom_obj_pt!=
nullptr) {
257 for (
auto& coupledElement : coupledElements_) {
258 coupledElement.el_pt->locate_zeta(x,geom_obj_pt,s);
259 if (geom_obj_pt!=
nullptr) {
260 logger(
VERBOSE,
"Coupled particle % to element % at % % %",p, &coupledElement, s[0], s[1], s[2]);
262 coupledParticle.
setCoupledElement(&coupledElement, M::particleHandler.getObject(p));
277 Vector<Vector<double>> projectionMatrix;
280 const unsigned nnode = coupledElement.
el_pt->nnode();
281 const unsigned dim = coupledElement.
el_pt->dim();
284 projectionMatrix.resize(nnode,Vector<double>(nParticles,0.0));
288 Vector<double> pos(dim,0.0);
292 for (
unsigned p = 0; p < nParticles; p++) {
295 coupledElement.
el_pt->shape(coupledParticles_[particle->
getIndex()].s, psi);
296 for (
unsigned n=0;
n < nnode;
n++) {
297 projectionMatrix[
n][p] = psi(
n) * particle->
getVolume();
301 for (
unsigned n=0;
n < nnode;
n++) {
303 for (
unsigned p = 0; p<nParticles; p++) {
304 sum += projectionMatrix[
n][p];
307 for (
unsigned p = 0; p < nParticles; p++) {
308 projectionMatrix[
n][p] /= sum;
312 return projectionMatrix;
319 for (
const auto& coupledElement : coupledElements_)
323 Vector<Vector<double>> projectionMatrix = computeProjectionMatrix(coupledElement);
325 ELEMENT* el_pt = coupledElement.el_pt;
326 const unsigned nParticles = coupledElement.coupledParticles.size();
328 const unsigned nnode = coupledElement.el_pt->nnode();
330 const unsigned dim = el_pt->dim();
332 computeNodalCouplingForces(coupledElement, projectionMatrix);
334 for (
unsigned p=0; p < nParticles; p++) {
335 BaseParticle* particle = coupledElement.coupledParticles[p];
337 for (
unsigned d=0; d < dim; d++) {
338 double forceComponent = 0;
339 for (
unsigned n=0;
n < nnode;
n++) {
341 forceComponent += projectionMatrix[
n][p] * el_pt->get_coupling_residual(
n, d);
358 const unsigned nnode = el_pt->nnode();
359 const unsigned dim = el_pt->dim();
363 Vector<Vector<double>> nodalVelocityDifference(nnode,Vector<double>(dim,0.0));
365 for (
unsigned n=0;
n < nnode;
n++) {
366 for (
unsigned d=0; d < dim; d++) {
367 double nodalVelocityDPM = 0;
368 for (
unsigned p=0; p < nParticles; p++) {
369 nodalVelocityDPM += projectionMatrix[
n][p] * coupledElement.
coupledParticles[p]->getVelocity().getComponent(d);
371 double nodalVelocityFEM = el_pt->dnodal_position_gen_dt(
n,0,d);
372 nodalVelocityDifference[
n][d] = nodalVelocityDPM-nodalVelocityFEM;
377 Vector<Vector<double> > nodalCouplingForces(nnode, Vector<double>(dim, 0.0));
381 DShape dpsidxi(nnode,dim);
382 const unsigned n_in = el_pt->integral_pt()->nweight();
384 for (
unsigned in=0; in<n_in; in++)
387 double w = el_pt->integral_pt()->weight(in);
389 double J = el_pt->dshape_lagrangian_at_knot(in,psi,dpsidxi);
391 for (
unsigned n=0;
n < nnode;
n++)
394 for (
unsigned nn=0; nn < nnode; nn++)
396 double volume = penalty_ * psi(nn) * psi(
n) * w * J;
398 for (
unsigned d=0; d < dim; d++)
401 double displacement = nodalVelocityDifference[
n][d] * O::time_pt()->dt(0);
402 nodalCouplingForces[
n][d] -= volume * displacement;
410 coupledElement.
el_pt->set_coupling_residual(nodalCouplingForces);
412 logger(
VERBOSE,
"VelocityDifference % % %, coupling force % % % on element %, node 0, particles %",
413 nodalVelocityDifference[0][0], nodalVelocityDifference[0][1], nodalVelocityDifference[0][2],
414 nodalCouplingForces[0][0], nodalCouplingForces[0][1], nodalCouplingForces[0][2],
const unsigned n
Definition: CG3DPackingUnitTest.cpp:32
LL< Log::VERBOSE > VERBOSE
Verbose information.
Definition: Logger.cc:57
LL< Log::INFO > INFO
Info log level.
Definition: Logger.cc:55
Logger< MERCURYDPM_LOGLEVEL > logger("MercuryKernel")
Definition of different loggers with certain modules. A user can define its own custom logger here.
Definition: BaseCoupling.h:48
const Vec3D & getPosition() const
Returns the position of this BaseInteractable.
Definition: BaseInteractable.h:218
void addForce(const Vec3D &addForce)
Adds an amount to the force on this BaseInteractable.
Definition: BaseInteractable.cc:116
unsigned int getIndex() const
Returns the index of the object in the handler.
Definition: BaseObject.h:118
Definition: BaseParticle.h:54
bool isFixed() const override
Is fixed Particle function. It returns whether a Particle is fixed or not, by checking its inverse Ma...
Definition: BaseParticle.h:93
virtual Mdouble getVolume() const
Get Particle volume function, which required a reference to the Species vector. It returns the volume...
Definition: BaseParticle.cc:143
Mdouble getMass() const
Returns the particle's mass.
Definition: BaseParticle.h:322
Definition: ScaleCoupling.h:40
void solveScaleCoupling(unsigned nStep)
Solve scale-coupled problem.
Definition: ScaleCoupling.h:147
void setCouplingWeight(const std::function< double(double x, double y, double z)> &couplingWeight)
Sets weight function (determines which nodes/el_pts are in coupling zone)
Definition: ScaleCoupling.h:120
void computeCouplingForce()
Computes coupling force for each element and particle.
Definition: ScaleCoupling.h:316
void updateCoupledElements()
Updates the coupledElements and coupledParticles vectors: finds which particles interact with which e...
Definition: ScaleCoupling.h:212
O::ELEMENT ELEMENT
type of el_pt in O (e.g. RefineableQDPVDElement<3, 2>)
Definition: ScaleCoupling.h:43
std::function< double(double x, double y, double z)> couplingWeight_
Definition: ScaleCoupling.h:48
std::vector< CoupledElement > coupledElements_
Vector of all coupled elements.
Definition: ScaleCoupling.h:59
const std::vector< CoupledParticle > & getCoupledParticles()
get coupled particle
Definition: ScaleCoupling.h:110
void computeOneTimeStepScaleCoupling(unsigned nStep)
What to do in each time step.
Definition: ScaleCoupling.h:204
const std::vector< CoupledElement > & getCoupledElements()
get coupled element
Definition: ScaleCoupling.h:105
void solveScaleCoupling()
Computes nStep, the ratio of FEM and DEM time steps, then calls solveSurfaceCoupling(nStep)
Definition: ScaleCoupling.h:125
std::vector< CoupledParticle > coupledParticles_
The i-th element of this vector describes the coupling properties of the i-th DPM particle.
Definition: ScaleCoupling.h:97
void computeExternalForces(BaseParticle *p) override
Applies coupling force to MercuryDPM in each time step.
Definition: ScaleCoupling.h:419
void computeNodalCouplingForces(const CoupledElement &coupledElement, const Vector< Vector< double >> &projectionMatrix)
Computes coupling force for each node.
Definition: ScaleCoupling.h:351
void setPenalty(double penalty)
Sets penalty parameter.
Definition: ScaleCoupling.h:115
void initialiseCoupledElements()
initialises the coupledElements vector
Definition: ScaleCoupling.h:178
Vector< Vector< double > > computeProjectionMatrix(const CoupledElement &coupledElement)
Computes projectionMatrix.
Definition: ScaleCoupling.h:275
Mdouble Y
Definition: Vector.h:66
Mdouble Z
Definition: Vector.h:66
Mdouble X
the vector components
Definition: Vector.h:66
void setComponent(int index, double val)
Sets the requested component of this Vec3D to the requested value.
Definition: Vector.cc:217
const Mdouble NaN
Definition: GeneralDefine.h:43
const Mdouble inf
Definition: GeneralDefine.h:44
Definition: AnisotropicHookean.h:31
Stores properties of a coupled element: pointer to the element and list of particles coupled to it.
Definition: ScaleCoupling.h:51
std::vector< BaseParticle * > coupledParticles
Definition: ScaleCoupling.h:55
ELEMENT * el_pt
Definition: ScaleCoupling.h:53
For all particles, stores coupling properties: coupling force, pointer to coupled element and locatio...
Definition: ScaleCoupling.h:62
CoupledElement * coupledElement_pt
Element in which this particle resides (null if particle is not coupled)
Definition: ScaleCoupling.h:66
Vec3D couplingForce
Coupling force.
Definition: ScaleCoupling.h:64
void setCoupledElement(CoupledElement *coupledElementNew, BaseParticle *particle)
Remove particle from coupledParticle.coupledElement.particles and set coupledParticle....
Definition: ScaleCoupling.h:80
void removeCoupledElement(BaseParticle *particle)
Removes particle from coupledParticle.coupledElement.particles and sets coupledParticle....
Definition: ScaleCoupling.h:71
Vector< double > s
Location of particle in coupled element, returned by locate zeta.
Definition: ScaleCoupling.h:68