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"
94
95#include "Operator/Operator.H"
96#include "Base/Mechanics.H"
97
98namespace Integrator
99{
100template<class MODEL>
101class Mechanics : virtual public Base::Mechanics<MODEL>
102{
103public:
104 static constexpr const char *name = "mechanics";
105
106 Mechanics() : Base::Mechanics<MODEL>() { }
107 Mechanics(IO::ParmParse& pp) : Base::Mechanics<MODEL>()
108 {
109 Parse(*this, pp);
110 }
111
113 {
114 delete ic_eta;
115 delete ic_psi;
116 delete ic_trac_normal;
117 delete bc_psi;
118 delete bc_trac_normal;
119 }
120
121 // Mechanics inputs. See also :ref:`Integrator::Base::Mechanics`
122 static void Parse(Mechanics& value, IO::ParmParse& pp)
123 {
125
126 int nmodels;
127 pp_query_default("nmodels", nmodels, 1); // Number of elastic model varieties
128
129 pp.queryclass_enumerate<MODEL>("model",value.models,nmodels);
130
131 Util::Assert(INFO, TEST(value.models.size() > 0));
132 value.RegisterNodalFab(value.eta_mf, value.models.size(), 2, "eta", true);
133 // Refinement threshold for eta field
134 pp_query_default("eta_ref_threshold", value.m_eta_ref_threshold, 0.01);
135 // Refinement threshold for strain gradient
136 pp_query_default("ref_threshold", value.m_elastic_ref_threshold, 0.01);
137 // Explicity impose neumann condition on model at domain boundaries (2d only)
138 pp_query_default("model_neumann_boundary",value.model_neumann_boundary,false);
139
140 // Read in IC for eta
141 if (nmodels > 1 && pp.contains("ic.type"))
142 {
143 // Select the initial condition for eta
145
146 value.eta_reset_on_regrid = true;
147 // Whether to re-initialize eta when re-gridding occurs.
148 // Default is false unless eta ic is set, then default is.
149 // true.
150 pp_query_default("eta.reset_on_regrid", value.eta_reset_on_regrid, true);
151 }
152
153 // Read in IC for psi
154 if (pp.contains("psi.ic.type"))
155 {
156 // Select initial condition for psi field
158
159 value.bc_psi = new BC::Nothing();
160 value.RegisterNewFab(value.psi_mf, value.bc_psi, 1, 2, "psi", value.plot_psi);
161 value.psi_on = true;
162
163 value.psi_reset_on_regrid = true;
164 // Whether to re-initialize psi when re-gridding occurs.
165 // Default is false unless a psi ic is set, then default is
166 // true.
167 pp_query_default("psi.reset_on_regrid", value.psi_reset_on_regrid, true);
168 }
169
170 if (pp.contains("trac_normal.ic.type"))
171 {
172 // Read in IC for the "normal traction" field (applied at diffuse boundaries)
173 pp.select<IC::Ellipse,IC::Constant,IC::Expression,IC::PSRead>("trac_normal.ic",value.ic_trac_normal,value.geom);
174
175 if (value.ic_trac_normal)
176 {
177 value.bc_trac_normal = new BC::Nothing();
178 value.RegisterNewFab(value.trac_normal_mf, value.bc_trac_normal, 1, 2, "trac_normal", true);
179 }
180 }
182
183 }
184
185 void Initialize(int lev) override
186 {
188 eta_mf[lev]->setVal(0.0);
189 if (models.size() > 1 && ic_eta) ic_eta->Initialize(lev, eta_mf);
190 else eta_mf[lev]->setVal(1.0);
191
192 if (psi_on) ic_psi->Initialize(lev, psi_mf);
194 }
195
196 virtual void UpdateModel(int a_step, Set::Scalar time) override
197 {
199
200 if (ic_trac_normal)
201 {
202 for (int lev = 0; lev <= finest_level; ++lev)
203 {
205 psi_mf[lev]->FillBoundary();
206 amrex::Box domain = this->geom[lev].Domain();
207 domain.convert(amrex::IntVect::TheNodeVector());
208 Set::Vector DX(geom[lev].CellSize());
209
210 for (MFIter mfi(*model_mf[lev], false); mfi.isValid(); ++mfi)
211 {
212 amrex::Box bx = mfi.nodaltilebox();
213 bx = bx & domain;
214
215 amrex::Array4<Set::Vector> const& rhs = rhs_mf[lev]->array(mfi);
216 amrex::Array4<const Set::Scalar> const& psi = psi_mf[lev]->array(mfi);
217 amrex::Array4<const Set::Scalar> const& trac_normal = trac_normal_mf[lev]->array(mfi);
218
219 amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) {
220 Set::Vector grad = Numeric::CellGradientOnNode(psi, i, j, k, 0, DX.data());
221 rhs(i,j,k) = trac_normal(i,j,k) * grad;
222 });
223 }
224 Util::RealFillBoundary(*rhs_mf[lev], geom[lev]);
225 }
226 }
227
228 if (a_step > 0) return;
229
230 for (int lev = 0; lev <= finest_level; ++lev)
231 {
232 eta_mf[lev]->FillBoundary();
233
234 amrex::Box domain = this->geom[lev].Domain();
235 domain.convert(amrex::IntVect::TheNodeVector());
236
237 Set::Vector DX(geom[lev].CellSize());
238
239 for (MFIter mfi(*model_mf[lev], false); mfi.isValid(); ++mfi)
240 {
241 amrex::Box bx = mfi.grownnodaltilebox();
242 bx = bx & domain;
243
244 amrex::Array4<MODEL> const& model = model_mf[lev]->array(mfi);
245 amrex::Array4<const Set::Scalar> const& eta = eta_mf[lev]->array(mfi);
246
247 amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) {
248 model(i, j, k) = MODEL::Zero();
249 for (unsigned int n = 0; n < models.size(); n++)
250 model(i, j, k) += eta(i, j, k, n) * models[n];
251 });
252 }
253
254
256 {
257 Util::AssertException(INFO,TEST(AMREX_SPACEDIM==2),"neumann boundary works in 2d only");
258 for (MFIter mfi(*model_mf[lev], false); mfi.isValid(); ++mfi)
259 {
260 amrex::Box bx = mfi.grownnodaltilebox() & domain;
261 amrex::Array4<MODEL> const& model = this->model_mf[lev]->array(mfi);
262 const Dim3 lo = amrex::lbound(domain), hi = amrex::ubound(domain);
263
264 amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k)
265 {
266 if (i==lo.x && j==lo.y)
267 model(i,j,k) = 0.5*(model(i+1,j,k)+model(i,j+1,k));
268 else if (i==lo.x && j==hi.y)
269 model(i,j,k) = 0.5*(model(i+1,j,k)+model(i,j-1,k));
270 else if (i==hi.x && j==lo.y)
271 model(i,j,k) = 0.5*(model(i-1,j,k)+model(i,j+1,k));
272 else if (i==hi.x && j==hi.y)
273 model(i,j,k) = 0.5*(model(i-1,j,k)+model(i,j-1,k));
274
275 else if (i==lo.x)
276 model(i,j,k) = model(i+1,j,k);
277 else if (i==hi.x)
278 model(i,j,k) = model(i-1,j,k);
279 else if (j==lo.y)
280 model(i,j,k) = model(i,j+1,k);
281 else if (j==hi.y)
282 model(i,j,k) = model(i,j-1,k);
283 });
284 }
285 }
286
287 Util::RealFillBoundary(*model_mf[lev], geom[lev]);
288 }
289 }
290
291 void TagCellsForRefinement(int lev, amrex::TagBoxArray& a_tags, Set::Scalar a_time, int a_ngrow) override
292 {
294 Base::Mechanics<MODEL>::TagCellsForRefinement(lev, a_tags, a_time, a_ngrow);
295
296 Set::Vector DX(geom[lev].CellSize());
297 Set::Scalar DXnorm = DX.lpNorm<2>();
298 for (amrex::MFIter mfi(*eta_mf[lev], TilingIfNotGPU()); mfi.isValid(); ++mfi)
299 {
300 amrex::Box bx = mfi.nodaltilebox();
301 amrex::Array4<char> const& tags = a_tags.array(mfi);
302 amrex::Array4<Set::Scalar> const& eta = eta_mf[lev]->array(mfi);
303 amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k)
304 {
305 auto sten = Numeric::GetStencil(i, j, k, bx);
306 for (int n = 0; n < eta_mf[lev]->nComp(); n++)
307 {
308 Set::Vector grad = Numeric::Gradient(eta, i, j, k, n, DX.data(), sten);
309 if (grad.lpNorm<2>() * DXnorm > m_eta_ref_threshold)
310 tags(i, j, k) = amrex::TagBox::SET;
311 }
312 });
313 if (psi_on)
314 {
315 amrex::Array4<Set::Scalar> const& psi = psi_mf[lev]->array(mfi);
316 amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k)
317 {
318 auto sten = Numeric::GetStencil(i, j, k, bx);
319 {
320 Set::Vector gradpsi = Numeric::Gradient(psi, i, j, k, 0, DX.data(), sten);
321 if (gradpsi.lpNorm<2>() * DXnorm > m_eta_ref_threshold)
322 tags(i, j, k) = amrex::TagBox::SET;
323 }
324 });
325 }
326 }
327 }
328
329 void Regrid(int lev, Set::Scalar time) override
330 {
331 if (eta_reset_on_regrid && models.size() > 1 && ic_eta) ic_eta->Initialize(lev, eta_mf, time);
333 }
334
335protected:
338 std::vector<MODEL> models;
346
348
350
351 using Base::Mechanics<MODEL>::m_type;
352 using Base::Mechanics<MODEL>::finest_level;
353 using Base::Mechanics<MODEL>::geom;
354 using Base::Mechanics<MODEL>::model_mf;
355 using Base::Mechanics<MODEL>::psi_mf;
356 using Base::Mechanics<MODEL>::psi_on;
357 using Base::Mechanics<MODEL>::rhs_mf;
358};
359
360
361
362
363
364
365
366
367
368
369} // namespace Integrator
370#endif
#define pp_query_default(...)
Definition ParmParse.H:100
#define TEST(x)
Definition Util.H:21
#define INFO
Definition Util.H:20
Definition BC.H:42
Definition BMP.H:21
Pure abstract IC object from which all other IC objects inherit.
Definition IC.H:23
void Initialize(const int &a_lev, Set::Field< T > &a_field, Set::Scalar a_time=0.0)
Definition IC.H:39
Definition PNG.H:26
bool contains(std::string name)
Definition ParmParse.H:154
void queryclass(std::string name, T *value, std::string file="", std::string func="", int line=-1)
Definition ParmParse.H:604
void select(std::string name, PTRTYPE *&ic_eta, Args &&... args)
Definition ParmParse.H:692
int queryclass_enumerate(std::string a_name, std::vector< T > &value, int number=1, std::string file="", std::string func="", int line=__LINE__)
Definition ParmParse.H:416
Set::Scalar m_elastic_ref_threshold
Definition Mechanics.H:498
void Initialize(int lev) override
Use the #ic object to initialize::Temp.
Definition Mechanics.H:143
void TagCellsForRefinement(int lev, amrex::TagBoxArray &a_tags, Set::Scalar, int) override
Definition Mechanics.H:439
Set::Field< Set::Vector > rhs_mf
Definition Mechanics.H:472
Set::Field< Set::Scalar > psi_mf
Definition Mechanics.H:465
Set::Field< MODEL > model_mf
Definition Mechanics.H:463
void RegisterNewFab(Set::Field< Set::Scalar > &new_fab, BC::BC< Set::Scalar > *new_bc, int ncomp, int nghost, std::string name, bool writeout, std::vector< std::string > suffix={})
Add a new cell-based scalar field.
void RegisterNodalFab(Set::Field< Set::Scalar > &new_fab, int ncomp, int nghost, std::string name, bool writeout, std::vector< std::string > suffix={})
Add a new node-based scalar field.
IC::IC< Set::Scalar > * ic_trac_normal
Definition Mechanics.H:341
void TagCellsForRefinement(int lev, amrex::TagBoxArray &a_tags, Set::Scalar a_time, int a_ngrow) override
Definition Mechanics.H:291
IC::IC< Set::Scalar > * ic_eta
Definition Mechanics.H:339
Set::Field< Set::Scalar > eta_mf
Definition Mechanics.H:336
static void Parse(Mechanics &value, IO::ParmParse &pp)
Definition Mechanics.H:122
void Regrid(int lev, Set::Scalar time) override
Definition Mechanics.H:329
Mechanics(IO::ParmParse &pp)
Definition Mechanics.H:107
std::vector< MODEL > models
Definition Mechanics.H:338
BC::BC< Set::Scalar > * bc_trac_normal
Definition Mechanics.H:343
void Initialize(int lev) override
Definition Mechanics.H:185
BC::BC< Set::Scalar > * bc_psi
Definition Mechanics.H:342
Set::Scalar m_eta_ref_threshold
Definition Mechanics.H:337
static constexpr const char * name
Definition Mechanics.H:104
IC::IC< Set::Scalar > * ic_psi
Definition Mechanics.H:340
Set::Field< Set::Scalar > trac_normal_mf
Definition Mechanics.H:349
virtual void UpdateModel(int a_step, Set::Scalar time) override
Definition Mechanics.H:196
Collection of numerical integrator objects.
Definition AllenCahn.H:41
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:36
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:690
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:672
amrex::Real Scalar
Definition Base.H:19
Eigen::Matrix< amrex::Real, AMREX_SPACEDIM, 1 > Vector
Definition Base.H:20
AMREX_FORCE_INLINE void RealFillBoundary(amrex::FabArray< amrex::BaseFab< T > > &a_mf, const amrex::Geometry &)
Definition Util.H:322
AMREX_FORCE_INLINE void AssertException(std::string file, std::string func, int line, std::string smt, bool pass, Args const &... args)
Definition Util.H:233
AMREX_FORCE_INLINE void Assert(std::string file, std::string func, int line, std::string smt, bool pass, Args const &... args)
Definition Util.H:70
void Message(std::string file, std::string func, int line, Args const &... args)
Definition Util.H:141