Skip to content

Commit

Permalink
Merge branch 'develop' into mish2/remove_dead_boundary_condition_code
Browse files Browse the repository at this point in the history
  • Loading branch information
white238 authored Aug 21, 2024
2 parents 0c5e758 + 3c7eaf4 commit c371e16
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 58 deletions.
8 changes: 5 additions & 3 deletions src/serac/numerics/equation_solver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -488,8 +488,8 @@ class TrustRegion : public mfem::NewtonSolver {
TrustRegionResults trResults(X.Size());
TrustRegionSettings settings;
settings.maxCgIterations = static_cast<size_t>(linear_options.max_iterations);
settings.cgTol = 0.2 * norm_goal;
double trSize = 10.0;
settings.cgTol = 0.5 * norm_goal;
double trSize = 0.1 * std::sqrt(X.Size());
size_t cumulativeCgIters = 0;

int it = 0;
Expand All @@ -499,6 +499,8 @@ class TrustRegion : public mfem::NewtonSolver {
mfem::out << "Newton iteration " << std::setw(3) << it << " : ||r|| = " << std::setw(13) << norm;
if (it > 0) {
mfem::out << ", ||r||/||r_0|| = " << std::setw(13) << (initial_norm != 0.0 ? norm / initial_norm : norm);
} else {
mfem::out << ", norm goal = " << std::setw(13) << norm_goal << "\n";
}
mfem::out << '\n';
}
Expand Down Expand Up @@ -554,7 +556,7 @@ class TrustRegion : public mfem::NewtonSolver {
trResults.cgIterationsCount = 1;
trResults.interiorStatus = TrustRegionResults::Status::OnBoundary;
} else {
settings.cgTol = std::max(0.2 * norm_goal, 1e-3 * norm);
settings.cgTol = std::max(0.5 * norm_goal, 5e-5 * norm);
solve_trust_region_minimization(r, scratch, hess_vec_func, precond_func, settings, trSize, trResults);
}
cumulativeCgIters += trResults.cgIterationsCount;
Expand Down
38 changes: 10 additions & 28 deletions src/serac/physics/solid_mechanics.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,8 @@ class SolidMechanics<order, dim, Parameters<parameter_space...>, std::integer_se
* @param parameter_names A vector of the names of the requested parameter fields
* @param cycle The simulation cycle (i.e. timestep iteration) to intialize the physics module to
* @param time The simulation time to initialize the physics module to
* @param checkpoint_to_disk A flag to save the transient states on disk instead of memory for the transient adjoint
* solves
* @param use_warm_start A flag to turn on or off the displacement warm start predictor which helps robustness for
* @param checkpoint_to_disk Flag to save the transient states on disk instead of memory for transient adjoint solver
* @param use_warm_start Flag to turn on or off the displacement warm start predictor which helps robustness for
* large deformation problems
*
* @note On parallel file systems (e.g. lustre), significant slowdowns and occasional errors were observed when
Expand Down Expand Up @@ -158,7 +157,7 @@ class SolidMechanics<order, dim, Parameters<parameter_space...>, std::integer_se
* @param parameter_names A vector of the names of the requested parameter fields
* @param cycle The simulation cycle (i.e. timestep iteration) to intialize the physics module to
* @param time The simulation time to initialize the physics module to
* @param checkpoint_to_disk A flag to save the transient states on disk instead of memory for the transient adjoint
* @param checkpoint_to_disk Flag to save the transient states on disk instead of memory for transient adjoint solves
* @param use_warm_start A flag to turn on or off the displacement warm start predictor which helps robustness for
* large deformation problems
*
Expand Down Expand Up @@ -249,13 +248,12 @@ class SolidMechanics<order, dim, Parameters<parameter_space...>, std::integer_se
if (amg_prec) {
// ZRA - Iterative refinement tends to be more expensive than it is worth
// We should add a flag allowing users to enable it
if constexpr (serac::ordering == mfem::Ordering::byVDIM) {
bool iterative_refinement = false;
amg_prec->SetElasticityOptions(&displacement_.space(), iterative_refinement);
} else {
// SetElasticityOptions only works with byVDIM ordering, instead fallback to SetSystemsOptions
amg_prec->SetSystemsOptions(displacement_.space().GetVDim(), serac::ordering == mfem::Ordering::byNODES);
}

// bool iterative_refinement = false;
// amg_prec->SetElasticityOptions(&displacement_.space(), iterative_refinement);

// SetElasticityOptions only works with byVDIM ordering, some evidence that it is not often optimal
amg_prec->SetSystemsOptions(displacement_.space().GetVDim(), serac::ordering == mfem::Ordering::byNODES);
}

int true_size = velocity_.space().TrueVSize();
Expand Down Expand Up @@ -421,23 +419,7 @@ class SolidMechanics<order, dim, Parameters<parameter_space...>, std::integer_se
template <typename T>
qdata_type<T> createQuadratureDataBuffer(T initial_state)
{
constexpr auto Q = order + 1;

std::array<uint32_t, mfem::Geometry::NUM_GEOMETRIES> elems = geometry_counts(mesh_);
std::array<uint32_t, mfem::Geometry::NUM_GEOMETRIES> qpts_per_elem{};

std::vector<mfem::Geometry::Type> geometries;
if (dim == 2) {
geometries = {mfem::Geometry::TRIANGLE, mfem::Geometry::SQUARE};
} else {
geometries = {mfem::Geometry::TETRAHEDRON, mfem::Geometry::CUBE};
}

for (auto geom : geometries) {
qpts_per_elem[size_t(geom)] = uint32_t(num_quadrature_points(geom, Q));
}

return std::make_shared<QuadratureData<T>>(elems, qpts_per_elem, initial_state);
return StateManager::newQuadratureDataBuffer(mesh_tag_, order, dim, initial_state);
}

/**
Expand Down
26 changes: 10 additions & 16 deletions src/serac/physics/state/state_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ void StateManager::storeState(FiniteElementState& state)
{
SLIC_ERROR_ROOT_IF(!ds_, "Serac's data store was not initialized - call StateManager::initialize first");
auto mesh_tag = collectionID(&state.mesh());
SLIC_ERROR_ROOT_IF(named_states_.find(state.name()) != named_states_.end(),
SLIC_ERROR_ROOT_IF(hasState(state.name()),
axom::fmt::format("StateManager already contains a state named '{}'", state.name()));
auto& datacoll = datacolls_.at(mesh_tag);
const std::string name = state.name();
Expand All @@ -163,9 +163,8 @@ FiniteElementState StateManager::newState(const mfem::ParFiniteElementSpace& spa
std::string mesh_tag = collectionID(space.GetParMesh());

SLIC_ERROR_ROOT_IF(!ds_, "Serac's data store was not initialized - call StateManager::initialize first");
SLIC_ERROR_ROOT_IF(datacolls_.find(mesh_tag) == datacolls_.end(),
axom::fmt::format("Mesh tag '{}' not found in the data store", mesh_tag));
SLIC_ERROR_ROOT_IF(named_states_.find(state_name) != named_states_.end(),
SLIC_ERROR_ROOT_IF(!hasMesh(mesh_tag), axom::fmt::format("Mesh tag '{}' not found in the data store", mesh_tag));
SLIC_ERROR_ROOT_IF(hasState(state_name),
axom::fmt::format("StateManager already contains a state named '{}'", state_name));
auto state = FiniteElementState(space, state_name);
storeState(state);
Expand All @@ -176,7 +175,7 @@ void StateManager::storeDual(FiniteElementDual& dual)
{
SLIC_ERROR_ROOT_IF(!ds_, "Serac's data store was not initialized - call StateManager::initialize first");
auto mesh_tag = collectionID(&dual.mesh());
SLIC_ERROR_ROOT_IF(named_duals_.find(dual.name()) != named_duals_.end(),
SLIC_ERROR_ROOT_IF(hasDual(dual.name()),
axom::fmt::format("StateManager already contains a state named '{}'", dual.name()));
auto& datacoll = datacolls_.at(mesh_tag);
const std::string name = dual.name();
Expand All @@ -203,9 +202,8 @@ FiniteElementDual StateManager::newDual(const mfem::ParFiniteElementSpace& space
std::string mesh_tag = collectionID(space.GetParMesh());

SLIC_ERROR_ROOT_IF(!ds_, "Serac's data store was not initialized - call StateManager::initialize first");
SLIC_ERROR_ROOT_IF(datacolls_.find(mesh_tag) == datacolls_.end(),
axom::fmt::format("Mesh tag '{}' not found in the data store", mesh_tag));
SLIC_ERROR_ROOT_IF(named_duals_.find(dual_name) != named_duals_.end(),
SLIC_ERROR_ROOT_IF(!hasMesh(mesh_tag), axom::fmt::format("Mesh tag '{}' not found in the data store", mesh_tag));
SLIC_ERROR_ROOT_IF(hasDual(dual_name),
axom::fmt::format("StateManager already contains a dual named '{}'", dual_name));
auto dual = FiniteElementDual(space, dual_name);
storeDual(dual);
Expand All @@ -215,8 +213,7 @@ FiniteElementDual StateManager::newDual(const mfem::ParFiniteElementSpace& space
void StateManager::save(const double t, const int cycle, const std::string& mesh_tag)
{
SLIC_ERROR_ROOT_IF(!ds_, "Serac's data store was not initialized - call StateManager::initialize first");
SLIC_ERROR_ROOT_IF(datacolls_.find(mesh_tag) == datacolls_.end(),
axom::fmt::format("Mesh tag '{}' not found in the data store", mesh_tag));
SLIC_ERROR_ROOT_IF(!hasMesh(mesh_tag), axom::fmt::format("Mesh tag '{}' not found in the data store", mesh_tag));
auto& datacoll = datacolls_.at(mesh_tag);
std::string file_path = axom::utilities::filesystem::joinPath(datacoll.GetPrefixPath(), datacoll.GetCollectionName());
SLIC_INFO_ROOT(
Expand Down Expand Up @@ -295,8 +292,7 @@ void StateManager::constructShapeFields(const std::string& mesh_tag)

mfem::ParMesh& StateManager::mesh(const std::string& mesh_tag)
{
SLIC_ERROR_ROOT_IF(datacolls_.find(mesh_tag) == datacolls_.end(),
axom::fmt::format("Mesh tag \"{}\" not found in the data store", mesh_tag));
SLIC_ERROR_ROOT_IF(!hasMesh(mesh_tag), axom::fmt::format("Mesh tag \"{}\" not found in the data store", mesh_tag));
auto mesh = datacolls_.at(mesh_tag).GetMesh();
SLIC_ERROR_ROOT_IF(!mesh, "The datacollection does not contain a mesh object");
return static_cast<mfem::ParMesh&>(*mesh);
Expand All @@ -315,15 +311,13 @@ std::string StateManager::collectionID(const mfem::ParMesh* pmesh)

int StateManager::cycle(std::string mesh_tag)
{
SLIC_ERROR_ROOT_IF(datacolls_.find(mesh_tag) == datacolls_.end(),
axom::fmt::format("Mesh tag \"{}\" not found in the data store", mesh_tag));
SLIC_ERROR_ROOT_IF(!hasMesh(mesh_tag), axom::fmt::format("Mesh tag \"{}\" not found in the data store", mesh_tag));
return datacolls_.at(mesh_tag).GetCycle();
}

double StateManager::time(std::string mesh_tag)
{
SLIC_ERROR_ROOT_IF(datacolls_.find(mesh_tag) == datacolls_.end(),
axom::fmt::format("Mesh tag \"{}\" not found in the data store", mesh_tag));
SLIC_ERROR_ROOT_IF(!hasMesh(mesh_tag), axom::fmt::format("Mesh tag \"{}\" not found in the data store", mesh_tag));
return datacolls_.at(mesh_tag).GetTime();
}

Expand Down
72 changes: 63 additions & 9 deletions src/serac/physics/state/state_manager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,14 @@ class StateManager {
static void initialize(axom::sidre::DataStore& ds, const std::string& output_directory);

/**
* @brief Factory method for creating a new FEState object\
* @brief Checks if StateManager has a state with the given name
* @param[in] name A string that uniquely identifies the state
* @return True if state exists with the given name
*/
static bool hasState(const std::string& name) { return named_states_.find(name) != named_states_.end(); }

/**
* @brief Factory method for creating a new FEState object
*
* @tparam FunctionSpace The function space (e.g. H1<1>) to build the finite element state on
* @param space The function space (e.g. H1<1>) to build the finite element state on
Expand All @@ -62,9 +69,8 @@ class StateManager {
static FiniteElementState newState(FunctionSpace space, const std::string& state_name, const std::string& mesh_tag)
{
SLIC_ERROR_ROOT_IF(!ds_, "Serac's data store was not initialized - call StateManager::initialize first");
SLIC_ERROR_ROOT_IF(datacolls_.find(mesh_tag) == datacolls_.end(),
axom::fmt::format("Mesh tag '{}' not found in the data store", mesh_tag));
SLIC_ERROR_ROOT_IF(named_states_.find(state_name) != named_states_.end(),
SLIC_ERROR_ROOT_IF(!hasMesh(mesh_tag), axom::fmt::format("Mesh tag '{}' not found in the data store", mesh_tag));
SLIC_ERROR_ROOT_IF(hasState(state_name),
axom::fmt::format("StateManager already contains a state named '{}'", state_name));

auto state = FiniteElementState(mesh(mesh_tag), space, state_name);
Expand All @@ -89,6 +95,48 @@ class StateManager {
*/
static void storeState(FiniteElementState& state);

/**
* @brief Create a shared ptr to a quadrature data buffer for the given material type
*
* @tparam T the type to be created at each quadrature point
* @param mesh_tag The tag for the stored mesh used to construct the finite element state
* @param order The order of the discretization of the displacement and velocity fields
* @param dim The spatial dimension of the mesh
* @param initial_state the value to be broadcast to each quadrature point
* @return shared pointer to quadrature data buffer
*/
template <typename T>
static std::shared_ptr<QuadratureData<T>> newQuadratureDataBuffer(const std::string& mesh_tag, int order, int dim,
T initial_state)
{
SLIC_ERROR_ROOT_IF(!hasMesh(mesh_tag), axom::fmt::format("Mesh tag '{}' not found in the data store", mesh_tag));

int Q = order + 1;

std::array<uint32_t, mfem::Geometry::NUM_GEOMETRIES> elems = geometry_counts(mesh(mesh_tag));
std::array<uint32_t, mfem::Geometry::NUM_GEOMETRIES> qpts_per_elem{};

std::vector<mfem::Geometry::Type> geometries;
if (dim == 2) {
geometries = {mfem::Geometry::TRIANGLE, mfem::Geometry::SQUARE};
} else {
geometries = {mfem::Geometry::TETRAHEDRON, mfem::Geometry::CUBE};
}

for (auto geom : geometries) {
qpts_per_elem[size_t(geom)] = uint32_t(num_quadrature_points(geom, Q));
}

return std::make_shared<QuadratureData<T>>(elems, qpts_per_elem, initial_state);
}

/**
* @brief Checks if StateManager has a dual with the given name
* @param name A string that uniquely identifies the name
* @return True if dual exists with the given name
*/
static bool hasDual(const std::string& name) { return named_duals_.find(name) != named_duals_.end(); }

/**
* @brief Factory method for creating a new FEDual object
*
Expand All @@ -104,9 +152,8 @@ class StateManager {
static FiniteElementDual newDual(FunctionSpace space, const std::string& dual_name, const std::string& mesh_tag)
{
SLIC_ERROR_ROOT_IF(!ds_, "Serac's data store was not initialized - call StateManager::initialize first");
SLIC_ERROR_ROOT_IF(datacolls_.find(mesh_tag) == datacolls_.end(),
axom::fmt::format("Mesh tag '{}' not found in the data store", mesh_tag));
SLIC_ERROR_ROOT_IF(named_states_.find(dual_name) != named_duals_.end(),
SLIC_ERROR_ROOT_IF(!hasMesh(mesh_tag), axom::fmt::format("Mesh tag '{}' not found in the data store", mesh_tag));
SLIC_ERROR_ROOT_IF(hasDual(dual_name),
axom::fmt::format("StateManager already contains a dual named '{}'", dual_name));

auto dual = FiniteElementDual(mesh(mesh_tag), space, dual_name);
Expand Down Expand Up @@ -140,7 +187,7 @@ class StateManager {
*/
static void updateState(const FiniteElementState& state)
{
SLIC_ERROR_ROOT_IF(named_states_.find(state.name()) == named_states_.end(),
SLIC_ERROR_ROOT_IF(!hasState(state.name()),
axom::fmt::format("State manager does not contain state named '{}'", state.name()));

state.fillGridFunction(*named_states_[state.name()]);
Expand All @@ -156,7 +203,7 @@ class StateManager {
*/
static void updateDual(const FiniteElementDual& dual)
{
SLIC_ERROR_ROOT_IF(named_duals_.find(dual.name()) == named_duals_.end(),
SLIC_ERROR_ROOT_IF(!hasDual(dual.name()),
axom::fmt::format("State manager does not contain dual named '{}'", dual.name()));

dual.space().GetRestrictionMatrix()->MultTranspose(dual, *named_duals_[dual.name()]);
Expand Down Expand Up @@ -203,6 +250,13 @@ class StateManager {
ds_ = nullptr;
};

/**
* @brief Checks if StateManager has a mesh with the given mesh_tag
* @param[in] mesh_tag A string that uniquely identifies the mesh
* @return True if mesh exists with the given mesh_tag
*/
static bool hasMesh(const std::string& mesh_tag) { return datacolls_.find(mesh_tag) != datacolls_.end(); }

/**
* @brief Gives ownership of mesh to StateManager
* @param[in] pmesh The mesh to register
Expand Down
4 changes: 2 additions & 2 deletions src/serac/physics/tests/solid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,9 @@ void functional_solid_test_static_J2()

Material::State initial_state{};

auto state = solid_solver.createQuadratureDataBuffer(initial_state);
auto qdata = solid_solver.createQuadratureDataBuffer(initial_state);

solid_solver.setMaterial(mat, state);
solid_solver.setMaterial(mat, qdata);

// prescribe zero displacement at the supported end of the beam,
std::set<int> support = {1};
Expand Down

0 comments on commit c371e16

Please sign in to comment.