Alamo
Mechanics.H
Go to the documentation of this file.
1 //
2 // This is a general purpose integrator that focuses on solving
3 // elasticity/mechanics equations in the absence of other multiphysics
4 // simulations.
5 // It is enabled by :code:`alamo.program=mechanics` if used on its own, in
6 // which case there is no prefix.
7 // If it is being used by another integrator, see that integrator to determine
8 // the value of :code:`[prefix]` (often equal to :code:`elastic`).
9 //
10 // This integrator inherits from :ref:`Integrator::Base::Mechanics`; see
11 // documentation for that integrator for additional parameters.
12 //
13 // :bdg-primary-line:`Model setup`
14 // There are two basic tools for setting up a mechanics problem in this
15 // integrator.
16 //
17 // 1. The :code:`eta` field: this is used to mix models of different types.
18 // Use :code:`nmodels` to specify how many material models to use, and then
19 // specify each model as :code:`model1`, :code:`model2`, etc.
20 // The type of moel is specified using the :code:`alamo.program.mechanics.model`
21 // input.
22 //
23 // Once you have done this, you must determine the spatial distribution of each
24 // model. This is done by choosing an IC for the eta field with :code:`ic.type`.
25 // The :code:`IC::Expression` is the most general and recommended.
26 // The models are then mixed linearly, i.e.
27 //
28 // .. math::
29 //
30 // W_{\textrm{eff}} = \sum_{i=1}^N W_i\,\eta_i(\mathbf{x})
31 //
32 // See the :ref:`Eshelby` test for an example of model mixing.
33 //
34 // 2. The :code:`psi` field: this is used specifically for cases where a "void" region
35 // is desired. Its usage is similar to the :code:`eta` case, and is conceptually
36 // similar in that it scales the model field to near-zero in order to mimic the
37 // (lack of) mechanical behavior in an empty region.
38 // It is important to use :code:`psi` here, for reasons that are discussed in detail
39 // in
40 // `this paper <https://doi.org/10.1007/s00466-023-02325-8>`_.
41 // The initialization of :code:`psi` is similar to that for :code:`eta`.
42 //
43 // See the :ref:`PlateHole` and :ref:`RubberPlateHole` for canonical exmaples.
44 // The :ref:`Integrator::Fracture` and :ref:`Integrator::TopOp` integrators are examples
45 // of integrators that leverage the psi property.
46 //
47 // :bdg-primary-line:`Body forces`
48 // currently have limited support due to the relatively low number of
49 // times they are needed. See the :ref:`Integrator::Base::Mechanics` documentation for
50 // detail.
51 // See the :ref:`TrigTest` test for examples of current body force implementation.
52 //
53 // :bdg-primary-line:`Boundary conditions`
54 // are implemented using the :ref:`BC::Operator::Elastic` classes.
55 // See the documentation on these classes for more detail.
56 // See any of the mechanics-based tests for examples of boundary condition application.
57 //
58 
59 #ifndef INTEGRATOR_MECHANICS_H
60 #define INTEGRATOR_MECHANICS_H
61 #include <iostream>
62 #include <fstream>
63 #include <iomanip>
64 #include <numeric>
65 
66 #include "AMReX.H"
67 #include "AMReX_ParallelDescriptor.H"
68 #include "AMReX_ParmParse.H"
69 
70 #include "IO/ParmParse.H"
72 
73 
74 #include "IC/IC.H"
75 #include "BC/BC.H"
79 
80 #include "IC/Ellipse.H"
81 #include "IC/Voronoi.H"
82 #include "IC/Constant.H"
83 #include "IC/Expression.H"
84 #include "IC/BMP.H"
85 #include "IC/PNG.H"
86 #include "IC/PSRead.H"
87 #include "IC/Constant.H"
88 #include "BC/Constant.H"
89 #include "Numeric/Stencil.H"
90 
91 #include "Model/Solid/Solid.H"
92 #include "Solver/Nonlocal/Linear.H"
93 #include "Solver/Nonlocal/Newton.H"
94 
95 #include "Operator/Operator.H"
96 
97 
98 namespace Integrator
99 {
100 template<class MODEL>
101 class Mechanics : virtual public Base::Mechanics<MODEL>
102 {
103 public:
104 
105  Mechanics() : Base::Mechanics<MODEL>() { }
106  Mechanics(IO::ParmParse& pp) : Base::Mechanics<MODEL>()
107  {
108  Parse(*this, pp);
109  }
110 
111  // Mechanics inputs. See also :ref:`Integrator::Base::Mechanics`
112  static void Parse(Mechanics& value, IO::ParmParse& pp)
113  {
115  int nmodels;
116  pp_query_default("nmodels", nmodels, 1); // Number of elastic model varieties
117  for (int i = 0; i < nmodels; i++)
118  {
119  bool init = false;
120  MODEL tmp_model;
121  if (pp.contains("model"))
122  {
123  pp_queryclass("model", tmp_model);
124  init = true;
125  }
126  std::string name = "model" + std::to_string(i + 1);
127  if (pp.contains(name.c_str()))
128  {
129  pp_queryclass(std::string(name.data()), tmp_model);
130  init = true;
131  }
132 
133  if (!init) Util::Exception(INFO,"No way to initialize ",pp.full(name));
134 
135  value.models.push_back(tmp_model);
136  }
137  Util::Assert(INFO, TEST(value.models.size() > 0));
138  value.RegisterNodalFab(value.eta_mf, value.models.size(), 2, "eta", true);
139  // Refinement threshold for eta field
140  pp_query_default("eta_ref_threshold", value.m_eta_ref_threshold, 0.01);
141  // Refinement threshold for strain gradient
142  pp_query_default("ref_threshold", value.m_elastic_ref_threshold, 0.01);
143  // Explicity impose neumann condition on model at domain boundaries (2d only)
144  pp_query_default("model_neumann_boundary",value.model_neumann_boundary,false);
145 
146  // Read in IC for eta
147  if (nmodels > 1 && pp.contains("ic.type"))
148  {
149  std::string type;
150  pp_query("ic.type", type); // Read IC type for the eta field
151  if (type == "ellipse") value.ic_eta = new IC::Ellipse(value.geom, pp, "ic.ellipse");
152  else if (type == "constant") value.ic_eta = new IC::Constant(value.geom, pp, "ic.constant");
153  else if (type == "voronoi") value.ic_eta = new IC::Voronoi(value.geom, pp, "ic.voronoi");
154  else if (type == "bmp") value.ic_eta = new IC::BMP(value.geom, pp, "ic.bmp");
155  else if (type == "png") value.ic_eta = new IC::PNG(value.geom, pp, "ic.png");
156  else if (type == "expression") value.ic_eta = new IC::Expression(value.geom, pp, "ic.expression");
157  else if (type == "psread") value.ic_eta = new IC::PSRead(value.geom, pp, "ic.psread");
158  else Util::Abort(INFO, "Invalid value for ic.type: ", type);
159 
160  value.eta_reset_on_regrid = true;
161  // Whether to re-initialize eta when re-gridding occurs.
162  // Default is false unless eta ic is set, then default is.
163  // true.
164  pp_query_default("eta.reset_on_regrid", value.eta_reset_on_regrid, true);
165  }
166 
167  // Read in IC for psi
168  if (pp.contains("psi.ic.type"))
169  {
170  std::string type;
171  pp_query("psi.ic.type", type); // Read IC type for the eta field
172  if (type == "ellipse") value.ic_psi = new IC::Ellipse(value.geom, pp, "psi.ic.ellipse");
173  else if (type == "constant") value.ic_psi = new IC::Constant(value.geom, pp, "psi.ic.constant");
174  else if (type == "expression") value.ic_psi = new IC::Expression(value.geom, pp, "psi.ic.expression");
175  else if (type == "psread") value.ic_psi = new IC::PSRead(value.geom, pp, "psi.ic.psread");
176  else if (type == "png") value.ic_psi = new IC::PNG(value.geom, pp, "psi.ic.png");
177  else Util::Abort(INFO, "Invalid value for psi.ic.type: ", type);
178 
179  value.bc_psi = new BC::Nothing();
180  value.RegisterNewFab(value.psi_mf, value.bc_psi, 1, 2, "psi", value.plot_psi);
181  value.psi_on = true;
182 
183  value.psi_reset_on_regrid = true;
184  // Whether to re-initialize psi when re-gridding occurs.
185  // Default is false unless a psi ic is set, then default is
186  // true.
187  pp_query_default("psi.reset_on_regrid", value.psi_reset_on_regrid, true);
188  }
189 
190  // Read in IC for psi
191  {
192  std::string type;
193  pp_query("trac_normal.ic.type", type); // Read IC type for the eta field
194  if (type == "ellipse") value.ic_trac_normal = new IC::Ellipse(value.geom, pp, "trac_normal.ic.ellipse");
195  else if (type == "constant") value.ic_trac_normal = new IC::Constant(value.geom, pp, "trac_normal.ic.constant");
196  else if (type == "expression") value.ic_trac_normal = new IC::Expression(value.geom, pp, "trac_normal.ic.expression");
197  else if (type == "psread") value.ic_trac_normal = new IC::PSRead(value.geom, pp, "trac_normal.ic.psread");
198 
199  if (value.ic_trac_normal)
200  {
201  value.bc_trac_normal = new BC::Nothing();
202  value.RegisterNewFab(value.trac_normal_mf, value.bc_trac_normal, 1, 2, "trac_normal", true);
203  }
204  }
205 
206  }
207 
208  void Initialize(int lev) override
209  {
211  eta_mf[lev]->setVal(0.0);
212  if (models.size() > 1 && ic_eta) ic_eta->Initialize(lev, eta_mf);
213  else eta_mf[lev]->setVal(1.0);
214 
215  if (psi_on) ic_psi->Initialize(lev, psi_mf);
217  }
218 
219  virtual void UpdateModel(int a_step, Set::Scalar time) override
220  {
222 
223  if (ic_trac_normal)
224  {
225  for (int lev = 0; lev <= finest_level; ++lev)
226  {
228  psi_mf[lev]->FillBoundary();
229  amrex::Box domain = this->geom[lev].Domain();
230  domain.convert(amrex::IntVect::TheNodeVector());
231  Set::Vector DX(geom[lev].CellSize());
232 
233  for (MFIter mfi(*model_mf[lev], false); mfi.isValid(); ++mfi)
234  {
235  amrex::Box bx = mfi.grownnodaltilebox();
236  bx = bx & domain;
237 
238  amrex::Array4<Set::Vector> const& rhs = rhs_mf[lev]->array(mfi);
239  amrex::Array4<const Set::Scalar> const& psi = psi_mf[lev]->array(mfi);
240  amrex::Array4<const Set::Scalar> const& trac_normal = trac_normal_mf[lev]->array(mfi);
241 
242  amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) {
243  Set::Vector grad = Numeric::CellGradientOnNode(psi, i, j, k, 0, DX.data());
244  rhs(i,j,k) = trac_normal(i,j,k) * grad;
245  });
246  }
247  Util::RealFillBoundary(*rhs_mf[lev], geom[lev]);
248  }
249  }
250 
251  if (a_step > 0) return;
252 
253  for (int lev = 0; lev <= finest_level; ++lev)
254  {
255  eta_mf[lev]->FillBoundary();
256 
257  amrex::Box domain = this->geom[lev].Domain();
258  domain.convert(amrex::IntVect::TheNodeVector());
259 
260  Set::Vector DX(geom[lev].CellSize());
261 
262  for (MFIter mfi(*model_mf[lev], false); mfi.isValid(); ++mfi)
263  {
264  amrex::Box bx = mfi.grownnodaltilebox();
265  bx = bx & domain;
266 
267  amrex::Array4<MODEL> const& model = model_mf[lev]->array(mfi);
268  amrex::Array4<const Set::Scalar> const& eta = eta_mf[lev]->array(mfi);
269 
270  amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) {
271  model(i, j, k) = MODEL::Zero();
272  for (unsigned int n = 0; n < models.size(); n++)
273  model(i, j, k) += eta(i, j, k, n) * models[n];
274  });
275  }
276 
277 
279  {
280  Util::AssertException(INFO,TEST(AMREX_SPACEDIM==2),"neumann boundary works in 2d only");
281  for (MFIter mfi(*model_mf[lev], false); mfi.isValid(); ++mfi)
282  {
283  amrex::Box bx = mfi.grownnodaltilebox() & domain;
284  amrex::Array4<MODEL> const& model = this->model_mf[lev]->array(mfi);
285  const Dim3 lo = amrex::lbound(domain), hi = amrex::ubound(domain);
286 
287  amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k)
288  {
289  if (i==lo.x && j==lo.y)
290  model(i,j,k) = 0.5*(model(i+1,j,k)+model(i,j+1,k));
291  else if (i==lo.x && j==hi.y)
292  model(i,j,k) = 0.5*(model(i+1,j,k)+model(i,j-1,k));
293  else if (i==hi.x && j==lo.y)
294  model(i,j,k) = 0.5*(model(i-1,j,k)+model(i,j+1,k));
295  else if (i==hi.x && j==hi.y)
296  model(i,j,k) = 0.5*(model(i-1,j,k)+model(i,j-1,k));
297 
298  else if (i==lo.x)
299  model(i,j,k) = model(i+1,j,k);
300  else if (i==hi.x)
301  model(i,j,k) = model(i-1,j,k);
302  else if (j==lo.y)
303  model(i,j,k) = model(i,j+1,k);
304  else if (j==hi.y)
305  model(i,j,k) = model(i,j-1,k);
306  });
307  }
308  }
309 
310  Util::RealFillBoundary(*model_mf[lev], geom[lev]);
311  }
312  }
313 
314  void TagCellsForRefinement(int lev, amrex::TagBoxArray& a_tags, Set::Scalar a_time, int a_ngrow) override
315  {
317  Base::Mechanics<MODEL>::TagCellsForRefinement(lev, a_tags, a_time, a_ngrow);
318 
319  Set::Vector DX(geom[lev].CellSize());
320  Set::Scalar DXnorm = DX.lpNorm<2>();
321  for (amrex::MFIter mfi(*eta_mf[lev], TilingIfNotGPU()); mfi.isValid(); ++mfi)
322  {
323  amrex::Box bx = mfi.nodaltilebox();
324  amrex::Array4<char> const& tags = a_tags.array(mfi);
325  amrex::Array4<Set::Scalar> const& eta = eta_mf[lev]->array(mfi);
326  amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k)
327  {
328  auto sten = Numeric::GetStencil(i, j, k, bx);
329  for (int n = 0; n < eta_mf[lev]->nComp(); n++)
330  {
331  Set::Vector grad = Numeric::Gradient(eta, i, j, k, n, DX.data(), sten);
332  if (grad.lpNorm<2>() * DXnorm > m_eta_ref_threshold)
333  tags(i, j, k) = amrex::TagBox::SET;
334  }
335  });
336  if (psi_on)
337  {
338  amrex::Array4<Set::Scalar> const& psi = psi_mf[lev]->array(mfi);
339  amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k)
340  {
341  auto sten = Numeric::GetStencil(i, j, k, bx);
342  {
343  Set::Vector gradpsi = Numeric::Gradient(psi, i, j, k, 0, DX.data(), sten);
344  if (gradpsi.lpNorm<2>() * DXnorm > m_eta_ref_threshold)
345  tags(i, j, k) = amrex::TagBox::SET;
346  }
347  });
348  }
349  }
350  }
351 
352  void Regrid(int lev, Set::Scalar time) override
353  {
354  if (eta_reset_on_regrid && models.size() > 1 && ic_eta) ic_eta->Initialize(lev, eta_mf, time);
355  if (psi_reset_on_regrid) ic_psi->Initialize(lev, psi_mf, time);
356  }
357 
358 protected:
361  std::vector<MODEL> models;
362  IC::IC* ic_eta = nullptr;
363  IC::IC* ic_psi = nullptr;
364  IC::IC* ic_trac_normal = nullptr;
367  bool psi_reset_on_regrid = false;
368  bool eta_reset_on_regrid = false;
369 
371 
373 
381 };
382 
383 
384 
385 
386 
387 
388 
389 
390 
391 
392 } // namespace Integrator
393 #endif
Numeric::CellGradientOnNode
AMREX_FORCE_INLINE Set::Vector CellGradientOnNode(const amrex::Array4< const Set::Scalar > &f, const int &i, const int &j, const int &k, const int &m, const Set::Scalar dx[AMREX_SPACEDIM])
Definition: Stencil.H:673
IC::BMP
Definition: BMP.H:20
TensionTest.H
IC::IC::Initialize
void Initialize(const int &a_lev, Set::Field< Set::Scalar > &a_field, Set::Scalar a_time=0.0)
Definition: IC.H:26
Util::RealFillBoundary
AMREX_FORCE_INLINE void RealFillBoundary(amrex::FabArray< amrex::BaseFab< T >> &a_mf, const amrex::Geometry &)
Definition: Util.H:307
BC::BC< Set::Scalar >
IC::IC
Pure abstract IC object from which all other IC objects inherit.
Definition: IC.H:12
Integrator::Mechanics::ic_psi
IC::IC * ic_psi
Definition: Mechanics.H:363
Integrator::Mechanics::eta_reset_on_regrid
bool eta_reset_on_regrid
Definition: Mechanics.H:368
Integrator::Mechanics
Definition: Mechanics.H:101
IC::Ellipse
Definition: Ellipse.H:21
Integrator::Base::Mechanics
Definition: Mechanics.H:23
Integrator::Mechanics::psi_reset_on_regrid
bool psi_reset_on_regrid
Definition: Mechanics.H:367
TEST
#define TEST(x)
Definition: Util.H:21
Integrator::Base::Mechanics::m_elastic_ref_threshold
Set::Scalar m_elastic_ref_threshold
Definition: Mechanics.H:489
Integrator::Mechanics::eta_mf
Set::Field< Set::Scalar > eta_mf
Definition: Mechanics.H:359
IO::ParmParse::full
std::string full(std::string name)
Definition: ParmParse.H:433
Expression.H
PSRead.H
Integrator::Mechanics::Mechanics
Mechanics(IO::ParmParse &pp)
Definition: Mechanics.H:106
IC::PSRead
Definition: PSRead.H:21
Integrator::Mechanics::ic_eta
IC::IC * ic_eta
Definition: Mechanics.H:362
Integrator::Mechanics::Regrid
void Regrid(int lev, Set::Scalar time) override
Definition: Mechanics.H:352
Integrator::Base::Mechanics::psi_mf
Set::Field< Set::Scalar > psi_mf
Definition: Mechanics.H:455
Set::Field< Set::Scalar >
Definition: Set.H:236
Integrator::Mechanics::Mechanics
Mechanics()
Definition: Mechanics.H:105
Integrator::Base::Mechanics::model_mf
Set::Field< MODEL > model_mf
Definition: Mechanics.H:453
Expression.H
Integrator::Mechanics::m_eta_ref_threshold
Set::Scalar m_eta_ref_threshold
Definition: Mechanics.H:360
Util::AssertException
AMREX_FORCE_INLINE void AssertException(std::string file, std::string func, int line, std::string smt, bool pass, Args const &... args)
Definition: Util.H:221
Integrator::Base::Mechanics::m_type
Type m_type
Definition: Mechanics.H:459
Set::Vector
Eigen::Matrix< amrex::Real, AMREX_SPACEDIM, 1 > Vector
Definition: Base.H:20
Constant.H
ParmParse.H
Numeric::Gradient
AMREX_FORCE_INLINE Set::Vector Gradient(const amrex::Array4< const Set::Scalar > &f, const int &i, const int &j, const int &k, const int &m, const Set::Scalar dx[AMREX_SPACEDIM], std::array< StencilType, AMREX_SPACEDIM > stencil=DefaultType)
Definition: Stencil.H:655
Constant.H
pp_query
#define pp_query(...)
Definition: ParmParse.H:104
Integrator::Base::Mechanics::Initialize
void Initialize(int lev) override
Use the #ic object to initialize::Temp.
Definition: Mechanics.H:140
Integrator::Mechanics::model_neumann_boundary
bool model_neumann_boundary
Definition: Mechanics.H:370
Integrator::Mechanics::bc_trac_normal
BC::BC< Set::Scalar > * bc_trac_normal
Definition: Mechanics.H:366
Set::Scalar
amrex::Real Scalar
Definition: Base.H:19
Integrator::Integrator::RegisterNewFab
void RegisterNewFab(Set::Field< Set::Scalar > &new_fab, BC::BC< Set::Scalar > *new_bc, int ncomp, int nghost, std::string name, bool writeout)
Definition: Integrator.cpp:292
PNG.H
Integrator::Mechanics::bc_psi
BC::BC< Set::Scalar > * bc_psi
Definition: Mechanics.H:365
pp_queryclass
#define pp_queryclass(...)
Definition: ParmParse.H:105
Solid.H
Integrator::Mechanics::ic_trac_normal
IC::IC * ic_trac_normal
Definition: Mechanics.H:364
IC::Voronoi
Definition: Voronoi.H:10
Integrator::Mechanics::models
std::vector< MODEL > models
Definition: Mechanics.H:361
IC::PNG
Definition: PNG.H:24
Mechanics.H
Constant.H
Integrator::Mechanics::TagCellsForRefinement
void TagCellsForRefinement(int lev, amrex::TagBoxArray &a_tags, Set::Scalar a_time, int a_ngrow) override
Definition: Mechanics.H:314
BC::Nothing
Definition: Nothing.H:11
Integrator::Mechanics::trac_normal_mf
Set::Field< Set::Scalar > trac_normal_mf
Definition: Mechanics.H:372
Integrator::Base::Mechanics::Parse
static void Parse(Mechanics &value, IO::ParmParse &pp)
Definition: Mechanics.H:34
Util::Exception
void Exception(std::string file, std::string func, int line, Args const &... args)
Definition: Util.H:194
IO::ParmParse::contains
bool contains(std::string name)
Definition: ParmParse.H:151
Util::Assert
AMREX_FORCE_INLINE void Assert(std::string file, std::string func, int line, std::string smt, bool pass, Args const &... args)
Definition: Util.H:65
Integrator::Mechanics::UpdateModel
virtual void UpdateModel(int a_step, Set::Scalar time) override
Definition: Mechanics.H:219
pp_query_default
#define pp_query_default(...)
Definition: ParmParse.H:100
Util::Abort
void Abort(const char *msg)
Definition: Util.cpp:165
Integrator
Collection of numerical integrator objects.
Definition: AllenCahn.H:39
IC::Constant
Definition: Constant.H:18
Newton.H
BMP.H
IC::Expression
Definition: Expression.H:44
Integrator::Integrator::RegisterNodalFab
void RegisterNodalFab(Set::Field< Set::Scalar > &new_fab, int ncomp, int nghost, std::string name, bool writeout)
Definition: Integrator.cpp:310
Voronoi.H
Integrator::Base::Mechanics::TagCellsForRefinement
void TagCellsForRefinement(int lev, amrex::TagBoxArray &a_tags, Set::Scalar, int) override
Definition: Mechanics.H:429
BC.H
IO::ParmParse
Definition: ParmParse.H:110
Integrator::Base::Mechanics::plot_psi
bool plot_psi
Definition: Mechanics.H:500
Integrator::Mechanics::Parse
static void Parse(Mechanics &value, IO::ParmParse &pp)
Definition: Mechanics.H:112
Integrator::Mechanics::Initialize
void Initialize(int lev) override
Definition: Mechanics.H:208
INFO
#define INFO
Definition: Util.H:20
IC.H
Numeric::GetStencil
static AMREX_FORCE_INLINE std::array< StencilType, AMREX_SPACEDIM > GetStencil(const int i, const int j, const int k, const amrex::Box domain)
Definition: Stencil.H:20
Integrator::Base::Mechanics::rhs_mf
Set::Field< Set::Vector > rhs_mf
Definition: Mechanics.H:462
Integrator::Base::Mechanics::psi_on
bool psi_on
Definition: Mechanics.H:456
Linear.H
Ellipse.H