Serac  0.1
Serac is an implicit thermal strucural mechanics simulation code.
boundary_condition.cpp
1 // Copyright (c) 2019-2024, 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 
10 
11 namespace serac {
12 
13 BoundaryCondition::BoundaryCondition(GeneralCoefficient coef, const std::optional<int> component,
14  const mfem::ParFiniteElementSpace& space, const std::set<int>& attrs)
15  : coef_(coef), component_(component), attr_markers_(space.GetMesh()->bdr_attributes.Max()), space_(space)
16 {
17  if (get_if<std::shared_ptr<mfem::VectorCoefficient>>(&coef_)) {
18  SLIC_ERROR_ROOT_IF(component_, "A vector coefficient must be applied to all components");
19  }
20 
21  attr_markers_ = 0;
22 
23  for (const int attr : attrs) {
24  SLIC_ASSERT_MSG(attr <= attr_markers_.Size(), "Attribute specified larger than what is found in the mesh.");
25  attr_markers_[attr - 1] = 1;
26  }
27 
28  setDofListsFromAttributeMarkers();
29 }
30 
31 BoundaryCondition::BoundaryCondition(GeneralCoefficient coef, const std::optional<int> component,
32  const mfem::ParFiniteElementSpace& space, const mfem::Array<int>& true_dofs)
33  : coef_(coef), component_(component), attr_markers_(0), space_(space)
34 {
35  if (get_if<std::shared_ptr<mfem::VectorCoefficient>>(&coef_)) {
36  SLIC_ERROR_IF(component_, "A vector coefficient must be applied to all components");
37  }
38  setTrueDofList(true_dofs);
39 }
40 
41 void BoundaryCondition::setTrueDofList(const mfem::Array<int>& true_dofs)
42 {
43  true_dofs_ = true_dofs;
44 
45  // Create a marker arrays for the true and local dofs
46  mfem::Array<int> true_dof_marker(space_.GetTrueVSize());
47  mfem::Array<int> local_dof_marker(space_.GetVSize());
48 
49  mfem::FiniteElementSpace::ListToMarker(true_dofs_, space_.GetTrueVSize(), true_dof_marker);
50 
51  space_.GetRestrictionMatrix()->BooleanMultTranspose(true_dof_marker, local_dof_marker);
52 
53  mfem::FiniteElementSpace::MarkerToList(local_dof_marker, local_dofs_);
54 }
55 
56 void BoundaryCondition::setLocalDofList(const mfem::Array<int>& local_dofs)
57 {
58  local_dofs_ = local_dofs;
59 
60  // Create a marker arrays for the true and local dofs
61  mfem::Array<int> true_dof_marker(space_.GetTrueVSize());
62  mfem::Array<int> local_dof_marker(space_.GetVSize());
63 
64  mfem::FiniteElementSpace::ListToMarker(local_dofs_, space_.GetVSize(), local_dof_marker);
65 
66  space_.GetRestrictionMatrix()->BooleanMult(local_dof_marker, true_dof_marker);
67 
68  mfem::FiniteElementSpace::MarkerToList(true_dof_marker, true_dofs_);
69 }
70 
71 void BoundaryCondition::setDofListsFromAttributeMarkers()
72 {
73  auto& mutable_space = const_cast<mfem::ParFiniteElementSpace&>(space_);
74 
75  if (component_) {
76  mfem::Array<int> dof_markers;
77 
78  mutable_space.GetEssentialTrueDofs(attr_markers_, true_dofs_, *component_);
79  space_.GetEssentialVDofs(attr_markers_, dof_markers, *component_);
80 
81  // The VDof call actually returns a marker array, so we need to transform it to a list of indices
82  space_.MarkerToList(dof_markers, local_dofs_);
83 
84  } else {
85  mfem::Array<int> dof_markers;
86 
87  mutable_space.GetEssentialTrueDofs(attr_markers_, true_dofs_);
88  space_.GetEssentialVDofs(attr_markers_, dof_markers);
89 
90  // The VDof call actually returns a marker array, so we need to transform it to a list of indices
91  space_.MarkerToList(dof_markers, local_dofs_);
92  }
93 }
94 
95 void BoundaryCondition::setDofs(mfem::Vector& vector, const double time) const
96 {
97  SLIC_ERROR_IF(space_.GetTrueVSize() != vector.Size(),
98  "State to project and boundary condition space are not compatible.");
99 
100  FiniteElementState state(space_);
101 
102  // Generate the scalar dof list from the vector dof list
103  mfem::Array<int> dof_list(local_dofs_.Size());
104  std::transform(local_dofs_.begin(), local_dofs_.end(), dof_list.begin(),
105  [&space = space_](int ldof) { return space.VDofToDof(ldof); });
106 
107  // the only reason to store a VectorCoefficient is to act on all components
108  if (is_vector_valued(coef_)) {
109  auto vec_coef = get<std::shared_ptr<mfem::VectorCoefficient>>(coef_);
110  vec_coef->SetTime(time);
111  state.project(*vec_coef, dof_list);
112  } else {
113  // an mfem::Coefficient could be used to describe a scalar-valued function, or
114  // a single component of a vector-valued function
115  auto scalar_coef = get<std::shared_ptr<mfem::Coefficient>>(coef_);
116  scalar_coef->SetTime(time);
117  if (component_) {
118  state.project(*scalar_coef, dof_list, *component_);
119 
120  } else {
121  state.projectOnBoundary(*scalar_coef, attr_markers_);
122  }
123  }
124 
125  for (int i : true_dofs_) {
126  vector(i) = state(i);
127  }
128 }
129 
130 void BoundaryCondition::apply(mfem::HypreParMatrix& k_mat, mfem::Vector& rhs, mfem::Vector& state) const
131 {
132  std::unique_ptr<mfem::HypreParMatrix> eliminated_entries(k_mat.EliminateRowsCols(true_dofs_));
133  mfem::EliminateBC(k_mat, *eliminated_entries, true_dofs_, state, rhs);
134 }
135 
136 const mfem::Coefficient& BoundaryCondition::scalarCoefficient() const
137 {
138  auto scalar_coef = get_if<std::shared_ptr<mfem::Coefficient>>(&coef_);
139  if (scalar_coef) {
140  return **scalar_coef;
141  } else {
142  SLIC_ERROR_ROOT("Asking for a scalar coefficient on a BoundaryCondition that contains a vector coefficient.");
143  exit(1);
144  }
145 }
146 
148 {
149  auto scalar_coef = get_if<std::shared_ptr<mfem::Coefficient>>(&coef_);
150  if (scalar_coef) {
151  return **scalar_coef;
152  } else {
153  SLIC_ERROR_ROOT("Asking for a scalar coefficient on a BoundaryCondition that contains a vector coefficient.");
154  exit(1);
155  }
156 }
157 
158 const mfem::VectorCoefficient& BoundaryCondition::vectorCoefficient() const
159 {
160  auto vec_coef = get_if<std::shared_ptr<mfem::VectorCoefficient>>(&coef_);
161  if (vec_coef) {
162  return **vec_coef;
163  } else {
164  SLIC_ERROR_ROOT("Asking for a vector coefficient on a BoundaryCondition that contains a scalar coefficient.");
165  exit(1);
166  }
167 }
168 
169 mfem::VectorCoefficient& BoundaryCondition::vectorCoefficient()
170 {
171  auto vec_coef = get_if<std::shared_ptr<mfem::VectorCoefficient>>(&coef_);
172  if (vec_coef) {
173  return **vec_coef;
174  } else {
175  SLIC_ERROR_ROOT("Asking for a vector coefficient on a BoundaryCondition that contains a scalar coefficient.");
176  exit(1);
177  }
178 }
179 
180 } // 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...
const mfem::VectorCoefficient & vectorCoefficient() const
Accessor for the underlying vector coefficient.
const mfem::Coefficient & scalarCoefficient() const
Accessor for the underlying scalar coefficient.
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.
Accelerator functionality.
Definition: serac.cpp:38
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