Smith  0.1
Smith is an implicit thermal structural mechanics simulation code.
finite_element_vector.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 <cstring>
10 #include <ostream>
11 #include <utility>
12 
13 #include "smith/smith_config.hpp"
15 
16 namespace smith {
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() != smith::ordering,
41  "Smith only operates on finite element spaces ordered by "
42  << (smith::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  // Use device (if available)
55  UseDevice(true);
56 }
57 
59  : mesh_(input_vector.mesh()),
60  coll_(std::move(input_vector.coll_)),
61  space_(std::move(input_vector.space_)),
62  name_(std::move(input_vector.name_))
63 {
64  // Grab the allocated data from the input argument for the underlying Hypre vector
65  auto* parallel_vec = input_vector.StealParVector();
66  WrapHypreParVector(parallel_vec);
67 }
68 
69 FiniteElementVector& FiniteElementVector::operator=(const mfem::HypreParVector& rhs)
70 {
71  SLIC_ERROR_IF(
72  Size() != rhs.Size(),
73  std::format("Finite element vector of size '{}' assigned to a HypreParVector of size '{}'", Size(), rhs.Size()));
74 
75  HypreParVector::operator=(rhs);
76  return *this;
77 }
78 
80 {
81  Vector::operator=(rhs);
82  return *this;
83 }
84 
86 {
87  SLIC_ERROR_IF(!sameFiniteElementSpace(*space_, *rhs.space_), "Finite element vectors have different spaces");
88 
89  SLIC_ERROR_IF(
90  Size() != rhs.Size(),
91  std::format("Finite element vector of size '{}' assigned to a HypreParVector of size '{}'", Size(), rhs.Size()));
92 
93  HypreParVector::operator=(rhs);
94 
95  return *this;
96 }
97 
99 {
100  mesh_ = rhs.mesh_;
101  coll_ = std::move(rhs.coll_);
102  space_ = std::move(rhs.space_);
103  name_ = rhs.name_;
104 
105  auto* parallel_vec = rhs.StealParVector();
106  WrapHypreParVector(parallel_vec);
107 
108  return *this;
109 }
110 
112 {
113  HypreParVector::operator=(value);
114  return *this;
115 }
116 
117 double avg(const FiniteElementVector& fe_vector)
118 {
119  double global_sum;
120  double local_sum = fe_vector.Sum();
121  int global_size;
122  int local_size = fe_vector.Size();
123  MPI_Allreduce(&local_sum, &global_sum, 1, MPI_DOUBLE, MPI_SUM, fe_vector.comm());
124  MPI_Allreduce(&local_size, &global_size, 1, MPI_INT, MPI_SUM, fe_vector.comm());
125  return global_sum / global_size;
126 }
127 
128 double max(const FiniteElementVector& fe_vector)
129 {
130  double global_max;
131  double local_max = fe_vector.Max();
132  MPI_Allreduce(&local_max, &global_max, 1, MPI_DOUBLE, MPI_MAX, fe_vector.comm());
133  return global_max;
134 }
135 
136 double min(const FiniteElementVector& fe_vector)
137 {
138  double global_min;
139  double local_min = fe_vector.Min();
140  MPI_Allreduce(&local_min, &global_min, 1, MPI_DOUBLE, MPI_MIN, fe_vector.comm());
141  return global_min;
142 }
143 
145 {
146  SLIC_ERROR_IF(v1.Size() != v2.Size(),
147  std::format("Finite element vector of size '{}' can not inner product with another vector of size '{}'",
148  v1.Size(), v2.Size()));
149  SLIC_ERROR_IF(v1.comm() != v2.comm(),
150  "Cannot compute inner products between finite element vectors with different mpi communicators");
151  SLIC_ERROR_IF(!sameFiniteElementSpace(v1.space(), v2.space()),
152  "Currently cannot compute inner products between finite element vectors with different mfem spaces");
153 
154  double global_ip;
155  double local_ip = mfem::InnerProduct(v1, v2);
156  MPI_Allreduce(&local_ip, &global_ip, 1, MPI_DOUBLE, MPI_SUM, v1.comm());
157  return global_ip;
158 }
159 
160 } // namespace smith
Class for encapsulating the data associated with a vector derived from a MFEM finite element space....
std::unique_ptr< mfem::ParFiniteElementSpace > space_
Handle to the mfem::ParFiniteElementSpace, which is owned by MFEMSidreDataCollection.
FiniteElementVector & operator=(const FiniteElementVector &rhs)
Copy assignment.
mfem::ParFiniteElementSpace & space()
Returns a non-owning reference to the internal FESpace.
std::reference_wrapper< mfem::ParMesh > mesh_
A reference to the mesh object on which the field is defined.
std::string name_
The name of the finite element vector.
MPI_Comm comm() const
Returns the MPI communicator for the state.
std::unique_ptr< mfem::FiniteElementCollection > coll_
Handle to the FiniteElementCollection, 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: smith.cpp:36
constexpr T & get(variant< T0, T1 > &v)
Returns the variant member of specified type.
Definition: variant.hpp:338
double avg(const FiniteElementVector &fe_vector)
Find the average value of a finite element vector across all dofs.
SMITH_HOST_DEVICE auto max(dual< gradient_type > a, double b)
Implementation of max for dual numbers.
Definition: dual.hpp:229
gretl::State< double > innerProduct(const FieldState &a, const FieldState &b)
gretl-function to compute the inner product (vector l2-norm) of a and b
Definition: field_state.cpp:29
mfem::ParFiniteElementSpace & space(FieldState field)
Get the space from the primal field of a field states.
SMITH_HOST_DEVICE auto min(dual< gradient_type > a, double b)
Implementation of min for dual numbers.
Definition: dual.hpp:255
bool sameFiniteElementSpace(const mfem::FiniteElementSpace &left, const mfem::FiniteElementSpace &right)
Check if two finite element spaces are the same.