Serac  0.1
Serac is an implicit thermal strucural mechanics simulation code.
finite_element_vector.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 
8 
9 #include <cstring>
10 #include <ostream>
11 #include <utility>
12 
13 #include "serac/serac_config.hpp"
15 
16 namespace serac {
17 
25 bool sameFiniteElementSpace(const mfem::FiniteElementSpace& left, const mfem::FiniteElementSpace& right)
26 {
27  bool sameMesh = (left.GetMesh() == right.GetMesh());
28  bool equivalentFEColl = strcmp(left.FEColl()->Name(), right.FEColl()->Name()) == 0;
29  bool sameVectorDimension = (left.GetVDim() == right.GetVDim());
30  bool sameOrdering = (left.GetOrdering() == right.GetOrdering());
31  return sameMesh && equivalentFEColl && sameVectorDimension && sameOrdering;
32 }
33 
34 FiniteElementVector::FiniteElementVector(const mfem::ParFiniteElementSpace& space, const std::string& name)
35  : mesh_(*space.GetParMesh()),
36  coll_(std::unique_ptr<mfem::FiniteElementCollection>(mfem::FiniteElementCollection::New(space.FEColl()->Name()))),
37  space_(std::make_unique<mfem::ParFiniteElementSpace>(space, &mesh_.get(), coll_.get())),
38  name_(name)
39 {
40  SLIC_ERROR_ROOT_IF(space_->GetVDim() > 1 && space_->GetOrdering() != serac::ordering,
41  "Serac only operates on finite element spaces ordered by "
42  << (serac::ordering == mfem::Ordering::byVDIM ? "VDIM" : "NODES"));
43 
44  // Construct a hypre par vector based on the new finite element space
45  HypreParVector new_vector(space_.get());
46 
47  // Move the data from this new hypre vector into this object without doubly allocating the data
48  auto* parallel_vec = new_vector.StealParVector();
49  WrapHypreParVector(parallel_vec);
50 
51  // Initialize the vector to zero
52  HypreParVector::operator=(0.0);
53 }
54 
56  : mesh_(input_vector.mesh()),
57  coll_(std::move(input_vector.coll_)),
58  space_(std::move(input_vector.space_)),
59  name_(std::move(input_vector.name_))
60 {
61  // Grab the allocated data from the input argument for the underlying Hypre vector
62  auto* parallel_vec = input_vector.StealParVector();
63  WrapHypreParVector(parallel_vec);
64 }
65 
66 FiniteElementVector& FiniteElementVector::operator=(const mfem::HypreParVector& rhs)
67 {
68  SLIC_ERROR_IF(Size() != rhs.Size(),
69  axom::fmt::format("Finite element vector of size '{}' assigned to a HypreParVector of size '{}'",
70  Size(), rhs.Size()));
71 
72  HypreParVector::operator=(rhs);
73  return *this;
74 }
75 
77 {
78  Vector::operator=(rhs);
79  return *this;
80 }
81 
83 {
84  SLIC_ERROR_IF(!sameFiniteElementSpace(*space_, *rhs.space_), "Finite element vectors have different spaces");
85 
86  SLIC_ERROR_IF(Size() != rhs.Size(),
87  axom::fmt::format("Finite element vector of size '{}' assigned to a HypreParVector of size '{}'",
88  Size(), rhs.Size()));
89 
90  HypreParVector::operator=(rhs);
91 
92  return *this;
93 }
94 
96 {
97  mesh_ = rhs.mesh_;
98  coll_ = std::move(rhs.coll_);
99  space_ = std::move(rhs.space_);
100  name_ = rhs.name_;
101 
102  auto* parallel_vec = rhs.StealParVector();
103  WrapHypreParVector(parallel_vec);
104 
105  return *this;
106 }
107 
109 {
110  HypreParVector::operator=(value);
111  return *this;
112 }
113 
114 double avg(const FiniteElementVector& fe_vector)
115 {
116  double global_sum;
117  double local_sum = fe_vector.Sum();
118  int global_size;
119  int local_size = fe_vector.Size();
120  MPI_Allreduce(&local_sum, &global_sum, 1, MPI_DOUBLE, MPI_SUM, fe_vector.comm());
121  MPI_Allreduce(&local_size, &global_size, 1, MPI_INT, MPI_SUM, fe_vector.comm());
122  return global_sum / global_size;
123 }
124 
125 double max(const FiniteElementVector& fe_vector)
126 {
127  double global_max;
128  double local_max = fe_vector.Max();
129  MPI_Allreduce(&local_max, &global_max, 1, MPI_DOUBLE, MPI_MAX, fe_vector.comm());
130  return global_max;
131 }
132 
133 double min(const FiniteElementVector& fe_vector)
134 {
135  double global_min;
136  double local_min = fe_vector.Min();
137  MPI_Allreduce(&local_min, &global_min, 1, MPI_DOUBLE, MPI_MIN, fe_vector.comm());
138  return global_min;
139 }
140 
142 {
143  SLIC_ERROR_IF(
144  v1.Size() != v2.Size(),
145  axom::fmt::format("Finite element vector of size '{}' can not inner product with another vector of size '{}'",
146  v1.Size(), v2.Size()));
147  SLIC_ERROR_IF(v1.comm() != v2.comm(),
148  "Cannot compute inner products between finite element vectors with different mpi communicators");
149  SLIC_ERROR_IF(!sameFiniteElementSpace(v1.space(), v2.space()),
150  "Currently cannot compute inner products between finite element vectors with different mfem spaces");
151 
152  double global_ip;
153  double local_ip = mfem::InnerProduct(v1, v2);
154  MPI_Allreduce(&local_ip, &global_ip, 1, MPI_DOUBLE, MPI_SUM, v1.comm());
155  return global_ip;
156 }
157 
158 } // namespace serac
Class for encapsulating the data associated with a vector derived from a MFEM finite element space....
std::string name_
The name of the finite element vector.
std::unique_ptr< mfem::FiniteElementCollection > coll_
Handle to the FiniteElementCollection, which is owned by MFEMSidreDataCollection.
MPI_Comm comm() const
Returns the MPI communicator for the state.
mfem::ParFiniteElementSpace & space()
Returns a non-owning reference to the internal FESpace.
FiniteElementVector & operator=(const FiniteElementVector &rhs)
Copy assignment.
std::reference_wrapper< mfem::ParMesh > mesh_
A reference to the mesh object on which the field is defined.
std::unique_ptr< mfem::ParFiniteElementSpace > space_
Handle to the mfem::ParFiniteElementSpace, which is owned by MFEMSidreDataCollection.
FiniteElementVector(const mfem::ParFiniteElementSpace &space, const std::string &name="")
Minimal constructor for a FiniteElementVector given a finite element space.
This file contains the declaration of structure that manages vectors derived from an MFEM finite elem...
This file contains the all the necessary functions and macros required for logging as well as a helpe...
Accelerator functionality.
Definition: serac.cpp:36
double innerProduct(const FiniteElementVector &v1, const FiniteElementVector &v2)
Find the inner prodcut between two finite element vectors across all dofs.
constexpr T & get(variant< T0, T1 > &v)
Returns the variant member of specified type.
Definition: variant.hpp:338
SERAC_HOST_DEVICE auto max(dual< gradient_type > a, double b)
Implementation of max for dual numbers.
Definition: dual.hpp:229
SERAC_HOST_DEVICE auto min(dual< gradient_type > a, double b)
Implementation of min for dual numbers.
Definition: dual.hpp:255
double avg(const FiniteElementVector &fe_vector)
Find the average value of a finite element vector across all dofs.
bool sameFiniteElementSpace(const mfem::FiniteElementSpace &left, const mfem::FiniteElementSpace &right)
Check if two finite element spaces are the same.