Smith  0.1
Smith is an implicit thermal structural mechanics simulation code.
input.cpp
1 // Copyright (c) Lawrence Livermore National Security, LLC and
2 // other Smith Project Developers. See the top-level LICENSE file for
3 // details.
4 //
5 // SPDX-License-Identifier: (BSD-3-Clause)
6 
8 
9 #include <cstdlib>
10 #include <climits>
11 #include <algorithm>
12 #include <cstddef>
13 #include <utility>
14 
15 #include "axom/core.hpp"
16 
19 
20 namespace smith::input {
21 
22 axom::inlet::Inlet initialize(axom::sidre::DataStore& datastore, const std::string& input_file_path,
23  const Language language, const std::string& sidre_path)
24 {
25  // Initialize Inlet
26  std::unique_ptr<axom::inlet::Reader> reader;
27  if (language == Language::Lua) {
28  reader = std::make_unique<axom::inlet::LuaReader>();
29  } else if (language == Language::JSON) {
30  reader = std::make_unique<axom::inlet::JSONReader>();
31  } else if (language == Language::YAML) {
32  reader = std::make_unique<axom::inlet::YAMLReader>();
33  }
34 
35  if (axom::utilities::filesystem::pathExists(input_file_path)) {
36  reader->parseFile(input_file_path);
37  }
38 
39  // Store inlet data under its own group
40  if (datastore.getRoot()->hasGroup(sidre_path)) {
41  // If this is a restart, wipe out the previous input file
42  datastore.getRoot()->destroyGroup(sidre_path);
43  }
44  axom::sidre::Group* inlet_root = datastore.getRoot()->createGroup(sidre_path);
45  return axom::inlet::Inlet(std::move(reader), inlet_root);
46 }
47 
48 std::string findMeshFilePath(const std::string& mesh_path, const std::string& input_file_path)
49 {
50  using namespace axom::utilities;
51 
52  // Check if given path exists
53  if (filesystem::pathExists(mesh_path)) {
54  return mesh_path;
55  }
56 
57  // Check relative to input file
58  std::string input_file_dir = fullDirectoryFromPath(input_file_path);
59  std::string possible_path = filesystem::joinPath(input_file_dir, mesh_path);
60  if (filesystem::pathExists(possible_path)) {
61  return possible_path;
62  }
63 
64  // Failed to find mesh file
65  std::string msg = axom::fmt::format("Input file: Given mesh file does not exist: '{0}'", mesh_path);
66  SLIC_ERROR_ROOT(msg);
67  return "";
68 }
69 
70 std::string fullDirectoryFromPath(const std::string& path)
71 {
72  char actualpath[PATH_MAX + 1];
73  char* ptr = realpath(path.c_str(), actualpath);
74  if (ptr == nullptr) {
75  SLIC_ERROR_ROOT("Failed to find absolute path from input file.");
76  }
77  std::string dir;
78  axom::utilities::filesystem::getDirName(dir, std::string(actualpath));
79  return dir;
80 }
81 
82 std::string getInputFileName(const std::string& file_path)
83 {
84  axom::Path path(file_path);
85  std::string basename = path.baseName();
86  std::string name;
87 
88  std::size_t index = basename.find_last_of(".");
89  if (index != std::string::npos) {
90  name = basename.substr(0, index);
91  } else {
92  name = basename;
93  }
94 
95  return name;
96 }
97 
98 void defineVectorInputFileSchema(axom::inlet::Container& container)
99 {
100  // TODO: I had to remove the required tag on x as we now have an optional vector input in the coefficients. IT would
101  // be nice to support "If this exists, this subcomponent is required."
102  container.addDouble("x", "x-component of vector");
103  container.addDouble("y", "y-component of vector");
104  container.addDouble("z", "z-component of vector");
105 }
106 
107 void BoundaryConditionInputOptions::defineInputFileSchema(axom::inlet::Container& container)
108 {
109  container.addIntArray("attrs", "Boundary attributes to which the BC should be applied");
111 }
112 
114 {
115  return vector_function || vector_constant || (!vector_pw_const.empty());
116 }
117 
118 std::unique_ptr<mfem::VectorCoefficient> CoefficientInputOptions::constructVector(const int dim) const
119 {
120  SLIC_ERROR_ROOT_IF(!isVector(), "Cannot construct a vector coefficient from scalar input");
121 
122  if (vector_function) {
123  return std::make_unique<mfem::VectorFunctionCoefficient>(dim, vector_function);
124  } else if (vector_constant) {
125  return std::make_unique<mfem::VectorConstantCoefficient>(*vector_constant);
126  } else if (!vector_pw_const.empty()) {
127  // Find the maximum mesh attribute
128  auto max_attr_elem = std::max_element(vector_pw_const.begin(), vector_pw_const.end(),
129  [](auto a, auto b) { return a.first < b.first; });
130 
131  // Create the vector array coefficient. We will use this as an array of piecewise constant scalars
132  auto vec_pw_coeff = std::make_unique<mfem::VectorArrayCoefficient>(max_attr_elem->second.Size());
133 
134  // Loop over each spatial dimension
135  for (int i = 0; i < max_attr_elem->second.Size(); ++i) {
136  // Create an mfem vector for the attributes
137  // Note that this vector expects zero indexing
138  mfem::Vector pw_constants(max_attr_elem->first);
139  pw_constants = 0.0;
140 
141  for (auto& entry : vector_pw_const) {
142  pw_constants(entry.first - 1) = entry.second[i];
143  }
144 
145  // Set the spatial dimension coefficient to a newly constructed scalar piecewise coefficient
146  vec_pw_coeff->Set(i, new mfem::PWConstCoefficient(pw_constants));
147  }
148  return vec_pw_coeff;
149 
150  } else {
151  SLIC_ERROR(
152  "Trying to build a vector coefficient without specifying a vector_function, vector_constant, or "
153  "vector_piecewise_constant.");
154  return nullptr;
155  }
156 }
157 
158 std::unique_ptr<mfem::Coefficient> CoefficientInputOptions::constructScalar() const
159 {
160  SLIC_ERROR_ROOT_IF(isVector(), "Cannot construct a scalar coefficient from vector input");
161 
162  if (scalar_function) {
163  return std::make_unique<mfem::FunctionCoefficient>(scalar_function);
164  } else if (scalar_constant) {
165  return std::make_unique<mfem::ConstantCoefficient>(*scalar_constant);
166  } else if (!scalar_pw_const.empty()) {
167  // First, find the element with the maximum attribute key
168  auto max_attr_elem = std::max_element(scalar_pw_const.begin(), scalar_pw_const.end(),
169  [](auto a, auto b) { return a.first < b.first; });
170 
171  // Check for a valid iterator to avoid compiler warnings
172  if (max_attr_elem != scalar_pw_const.end()) {
173  // Create an mfem vector for the attributes
174  // Note that this vector expects zero indexing
175  mfem::Vector pw_constants(max_attr_elem->first);
176  pw_constants = 0.0;
177 
178  for (auto& entry : scalar_pw_const) {
179  pw_constants(entry.first - 1) = entry.second;
180  }
181 
182  // Create the MFEM coefficient
183  return std::make_unique<mfem::PWConstCoefficient>(pw_constants);
184  }
185  }
186 
187  SLIC_ERROR_ROOT(
188  "Trying to build a scalar coefficient without specifying a scalar_function, constant, or piecewise_constant.");
189  return nullptr;
190 }
191 
192 void CoefficientInputOptions::defineInputFileSchema(axom::inlet::Container& container)
193 {
194  // Vectors are implemented as lua usertypes and can be converted to/from mfem::Vector
195  container.addFunction("vector_function", axom::inlet::FunctionTag::Vector,
196  {axom::inlet::FunctionTag::Vector, axom::inlet::FunctionTag::Double},
197  "The function to use for an mfem::VectorFunctionCoefficient");
198  container.addFunction("scalar_function", axom::inlet::FunctionTag::Double,
199  {axom::inlet::FunctionTag::Vector, axom::inlet::FunctionTag::Double},
200  "The function to use for an mfem::FunctionCoefficient");
201  container.addInt("component", "The vector component to which the scalar coefficient should be applied");
202 
203  container.addDouble("constant", "The constant scalar value to use as the coefficient");
204 
205  auto& vector_container = container.addStruct("vector_constant", "The constant vector to use as the coefficient");
207 
208  container.addDoubleArray("piecewise_constant",
209  "Map of mesh attributes to constant values to use as a piecewise coefficient");
210 
211  auto& pw_vector_container = container.addStructArray(
212  "vector_piecewise_constant", "Map of mesh attributes to constant vectors to use as a piecewise coefficient");
213  smith::input::defineVectorInputFileSchema(pw_vector_container);
214 }
215 
216 } // namespace smith::input
217 
218 mfem::Vector FromInlet<mfem::Vector>::operator()(const axom::inlet::Container& base)
219 {
220  mfem::Vector result(3); // Allocate up front since it's small
221  result[0] = base["x"];
222  if (base.contains("y")) {
223  result[1] = base["y"];
224  if (base.contains("z")) {
225  result[2] = base["z"];
226  } else {
227  result.SetSize(2); // Shrink to a 2D vector, leaving the data intact
228  }
229  } else {
230  result.SetSize(1); // Shrink to a 1D vector, leaving the data intact
231  }
232  return result;
233 }
234 
236  const axom::inlet::Container& base)
237 {
239  .coef_opts = base.get<smith::input::CoefficientInputOptions>()};
240  // Build a set with just the values of the map
241  auto bdr_attr_map = base["attrs"].get<std::unordered_map<int, int>>();
242  for (const auto& [_, val] : bdr_attr_map) {
243  result.attrs.insert(val);
244  }
245  return result;
246 }
247 
249  const axom::inlet::Container& base)
250 {
252 
253  // Create a counter for definition of the coefficient
254  int coefficient_definitions = 0;
255 
256  // Check if functions have been assigned and store them appropriately
257  if (base.contains("vector_function")) {
258  auto func = base["vector_function"]
259  .get<std::function<axom::inlet::FunctionType::Vector(axom::inlet::FunctionType::Vector, double)>>();
260  result.vector_function = [func(std::move(func))](const mfem::Vector& input, double t, mfem::Vector& output) {
261  auto ret = func(axom::inlet::FunctionType::Vector{input.GetData(), input.Size()}, t);
262  // Copy from the primal vector into the MFEM vector
263  std::copy(ret.vec.data(), ret.vec.data() + input.Size(), output.GetData());
264  };
265  coefficient_definitions++;
266  }
267 
268  if (base.contains("scalar_function")) {
269  auto func = base["scalar_function"].get<std::function<double(axom::inlet::FunctionType::Vector, double)>>();
270  result.scalar_function = [func(std::move(func))](const mfem::Vector& input, double t) {
271  return func(axom::inlet::FunctionType::Vector{input.GetData(), input.Size()}, t);
272  };
273  coefficient_definitions++;
274  }
275 
276  if (base.contains("constant")) {
277  result.scalar_constant = base["constant"];
278  coefficient_definitions++;
279  }
280 
281  if (base.contains("vector_constant")) {
282  result.vector_constant = base["vector_constant"].get<mfem::Vector>();
283  coefficient_definitions++;
284  }
285 
286  if (base.contains("piecewise_constant")) {
287  result.scalar_pw_const = base["piecewise_constant"].get<std::unordered_map<int, double>>();
288  coefficient_definitions++;
289  }
290 
291  if (base.contains("vector_piecewise_constant")) {
292  result.vector_pw_const = base["vector_piecewise_constant"].get<std::unordered_map<int, mfem::Vector>>();
293  coefficient_definitions++;
294  }
295 
296  // If scalar valued, check of a component
297  if (result.scalar_constant || result.scalar_function || !result.scalar_pw_const.empty()) {
298  // If component input exists, set it in the option struct
299  if (base.contains("component")) {
300  result.component = base["component"];
301  }
302  }
303 
304  SLIC_ERROR_ROOT_IF(coefficient_definitions > 1,
305  "Coefficient has multiple definitions. Please use only one of (constant, vector_constant, "
306  "piecewise_constant, vector_piecewise_constant, scalar_function, vector_function");
307  SLIC_ERROR_ROOT_IF(coefficient_definitions == 0, "Coefficient definition does not contain known type.");
308 
309  return result;
310 }
This file contains the all the necessary functions for reading input files.
This file contains the all the necessary functions and macros required for logging as well as a helpe...
The input related helper functions and objects.
Definition: input.cpp:20
Language
The input file languages supported by Inlet.
Definition: input.hpp:37
std::string fullDirectoryFromPath(const std::string &path)
Returns the absolute directory of the given file path.
Definition: input.cpp:70
axom::inlet::Inlet initialize(axom::sidre::DataStore &datastore, const std::string &input_file_path, const Language language, const std::string &sidre_path)
Initializes Inlet with the given datastore and input file.
Definition: input.cpp:22
void defineVectorInputFileSchema(axom::inlet::Container &container)
Defines the schema for a vector in R^{1,2,3} space.
Definition: input.cpp:98
std::string getInputFileName(const std::string &file_path)
Returns the name of the input file (base name with file extension removed).
Definition: input.cpp:82
std::string findMeshFilePath(const std::string &mesh_path, const std::string &input_file_path)
Returns the absolute path of the given mesh either relative to CWD or the input file.
Definition: input.cpp:48
This file contains enumerations and record types for physics solver configuration.
mfem::Vector operator()(const axom::inlet::Container &base)
Returns created object from Inlet container.
Definition: input.cpp:218
smith::input::BoundaryConditionInputOptions operator()(const axom::inlet::Container &base)
Returns created object from Inlet container.
Definition: input.cpp:235
smith::input::CoefficientInputOptions operator()(const axom::inlet::Container &base)
Returns created object from Inlet container.
Definition: input.cpp:248
The information required from the input file for a boundary condition.
Definition: input.hpp:159
static void defineInputFileSchema(axom::inlet::Container &container)
Input file parameters specific to this class.
Definition: input.cpp:107
std::set< int > attrs
The mesh attributes on which to apply the boundary condition.
Definition: input.hpp:163
The information required from the input file for an mfem::(Vector)(Function)Coefficient.
Definition: input.hpp:92
static void defineInputFileSchema(axom::inlet::Container &container)
Defines the input file schema on the provided inlet container.
Definition: input.cpp:192
std::unordered_map< int, double > scalar_pw_const
Scalar piecewise constant definition map.
Definition: input.hpp:127
VecFunc vector_function
The vector std::function corresponding to a function coefficient.
Definition: input.hpp:112
std::unordered_map< int, mfem::Vector > vector_pw_const
Vector piecewise constant definition map.
Definition: input.hpp:132
std::optional< int > component
The component to which a scalar coefficient should be applied.
Definition: input.hpp:137
std::unique_ptr< mfem::VectorCoefficient > constructVector(const int dim=3) const
Constructs a vector coefficient with the requested dimension.
Definition: input.cpp:118
ScalarFunc scalar_function
The scalar std::function corresponding to a function coefficient.
Definition: input.hpp:107
std::optional< double > scalar_constant
The scalar constant associated with the coefficient.
Definition: input.hpp:117
std::unique_ptr< mfem::Coefficient > constructScalar() const
Constructs a scalar coefficient.
Definition: input.cpp:158
bool isVector() const
Returns whether the contained function corresponds to a vector coefficient.
Definition: input.cpp:113
std::optional< mfem::Vector > vector_constant
The vector constant associated with the coefficient.
Definition: input.hpp:122