Serac  0.1
Serac is an implicit thermal strucural mechanics simulation code.
boundary_condition.cpp
1 // Copyright (c) Lawrence Livermore National Security, LLC and
2 // other Serac Project Developers. See the top-level LICENSE file for
3 // details.
4 //
5 // SPDX-License-Identifier: (BSD-3-Clause)
6 
7 #include <algorithm>
8 #include <memory>
9 
13 
14 namespace serac {
15 
16 BoundaryCondition::BoundaryCondition(GeneralCoefficient coef, const std::optional<int> component,
17  const mfem::ParFiniteElementSpace& space, const std::set<int>& attrs)
18  : coef_(coef), component_(component), attr_markers_(space.GetMesh()->bdr_attributes.Max()), space_(space)
19 {
20  if (get_if<std::shared_ptr<mfem::VectorCoefficient>>(&coef_)) {
21  SLIC_ERROR_ROOT_IF(component_, "A vector coefficient must be applied to all components");
22  }
23 
24  attr_markers_ = 0;
25 
26  for (const int attr : attrs) {
27  SLIC_ASSERT_MSG(attr <= attr_markers_.Size(), "Attribute specified larger than what is found in the mesh.");
28  attr_markers_[attr - 1] = 1;
29  }
30 
31  setDofListsFromAttributeMarkers();
32 }
33 
34 BoundaryCondition::BoundaryCondition(GeneralCoefficient coef, const std::optional<int> component,
35  const mfem::ParFiniteElementSpace& space, const mfem::Array<int>& true_dofs)
36  : coef_(coef), component_(component), attr_markers_(0), space_(space)
37 {
38  if (get_if<std::shared_ptr<mfem::VectorCoefficient>>(&coef_)) {
39  SLIC_ERROR_IF(component_, "A vector coefficient must be applied to all components");
40  }
41  setTrueDofList(true_dofs);
42 }
43 
44 void BoundaryCondition::setTrueDofList(const mfem::Array<int>& true_dofs)
45 {
46  true_dofs_ = true_dofs;
47 
48  // Create a marker arrays for the true and local dofs
49  mfem::Array<int> true_dof_marker(space_.GetTrueVSize());
50  mfem::Array<int> local_dof_marker(space_.GetVSize());
51 
52  mfem::FiniteElementSpace::ListToMarker(true_dofs_, space_.GetTrueVSize(), true_dof_marker);
53 
54  space_.GetRestrictionMatrix()->BooleanMultTranspose(true_dof_marker, local_dof_marker);
55 
56  mfem::FiniteElementSpace::MarkerToList(local_dof_marker, local_dofs_);
57 }
58 
59 void BoundaryCondition::setDofListsFromAttributeMarkers()
60 {
61  auto& mutable_space = const_cast<mfem::ParFiniteElementSpace&>(space_);
62 
63  if (component_) {
64  mfem::Array<int> dof_markers;
65 
66  mutable_space.GetEssentialTrueDofs(attr_markers_, true_dofs_, *component_);
67  space_.GetEssentialVDofs(attr_markers_, dof_markers, *component_);
68 
69  // The VDof call actually returns a marker array, so we need to transform it to a list of indices
70  space_.MarkerToList(dof_markers, local_dofs_);
71 
72  } else {
73  mfem::Array<int> dof_markers;
74 
75  mutable_space.GetEssentialTrueDofs(attr_markers_, true_dofs_);
76  space_.GetEssentialVDofs(attr_markers_, dof_markers);
77 
78  // The VDof call actually returns a marker array, so we need to transform it to a list of indices
79  space_.MarkerToList(dof_markers, local_dofs_);
80  }
81 }
82 
83 void BoundaryCondition::setDofs(mfem::Vector& vector, const double time) const
84 {
85  SLIC_ERROR_IF(space_.GetTrueVSize() != vector.Size(),
86  "State to project and boundary condition space are not compatible.");
87 
88  FiniteElementState state(space_);
89 
90  // Generate the scalar dof list from the vector dof list
91  mfem::Array<int> dof_list(local_dofs_.Size());
92  std::transform(local_dofs_.begin(), local_dofs_.end(), dof_list.begin(),
93  [&space = space_](int ldof) { return space.VDofToDof(ldof); });
94 
95  // the only reason to store a VectorCoefficient is to act on all components
96  if (is_vector_valued(coef_)) {
97  auto vec_coef = get<std::shared_ptr<mfem::VectorCoefficient>>(coef_);
98  vec_coef->SetTime(time);
99  state.project(*vec_coef, dof_list);
100  } else {
101  // an mfem::Coefficient could be used to describe a scalar-valued function, or
102  // a single component of a vector-valued function
103  auto scalar_coef = get<std::shared_ptr<mfem::Coefficient>>(coef_);
104  scalar_coef->SetTime(time);
105  if (component_) {
106  state.project(*scalar_coef, dof_list, *component_);
107 
108  } else {
109  state.projectOnBoundary(*scalar_coef, attr_markers_);
110  }
111  }
112 
113  for (int i : true_dofs_) {
114  vector(i) = state(i);
115  }
116 }
117 
118 void BoundaryCondition::apply(mfem::HypreParMatrix& k_mat, mfem::Vector& rhs, mfem::Vector& state) const
119 {
120  std::unique_ptr<mfem::HypreParMatrix> eliminated_entries(k_mat.EliminateRowsCols(true_dofs_));
121  mfem::EliminateBC(k_mat, *eliminated_entries, true_dofs_, state, rhs);
122 }
123 
124 } // namespace serac
This file contains the declaration of the boundary condition class.
void setDofs(mfem::Vector &state, const double time=0.0) const
Projects the associated coefficient over a solution vector on the DOFs constrained by the boundary co...
BoundaryCondition(GeneralCoefficient coef, const std::optional< int > component, const mfem::ParFiniteElementSpace &space, const std::set< int > &attrs)
Constructor for setting up a boundary condition using a set of attributes.
void apply(mfem::HypreParMatrix &k_mat, mfem::Vector &rhs, mfem::Vector &state) const
Modify the system of equations by replacing equations that correspond to essential boundary conditio...
Class for encapsulating the critical MFEM components of a primal finite element field.
void projectOnBoundary(mfem::Coefficient &coef, const mfem::Array< int > &markers)
Project a coefficient on a specific set of marked boundaries.
void project(mfem::VectorCoefficient &coef, mfem::Array< int > &dof_list)
Project a vector coefficient onto a set of dofs.
This file contains the declaration of structure that manages the MFEM objects that make up the state ...
Accelerator functionality.
Definition: serac.cpp:36
bool is_vector_valued(const GeneralCoefficient &coef)
convenience function for querying the type stored in a GeneralCoefficient
T * get_if(variant< T0, T1 > *v)
Returns the member of requested type if it's active, otherwise nullptr.
Definition: variant.hpp:398
This file contains the declaration of a two-element variant type.