libMesh
parallel_fe_type.h
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2025 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3 
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Lesser General Public
6 // License as published by the Free Software Foundation; either
7 // version 2.1 of the License, or (at your option) any later version.
8 
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // Lesser General Public License for more details.
13 
14 // You should have received a copy of the GNU Lesser General Public
15 // License along with this library; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 
18 
19 #ifndef LIBMESH_PARALLEL_FE_TYPE_H
20 #define LIBMESH_PARALLEL_FE_TYPE_H
21 
22 
23 // libMesh includes
24 #include "libmesh/libmesh_common.h"
25 #include "libmesh/fe_type.h"
26 
27 // TIMPI includes
28 #include "timpi/attributes.h"
29 #include "timpi/op_function.h"
30 #include "timpi/standard_type.h"
31 
32 // C++ includes
33 #include <cstddef>
34 #include <memory>
35 #include <type_traits>
36 
37 namespace TIMPI {
38 
42 
43 // OpFunction<> specializations to return an MPI_Op version of the
44 // reduction operations on FETypes
45 //
46 // We use static variables to minimize the number of MPI datatype
47 // construction calls executed over the course of the program.
48 //
49 // We use a singleton pattern because a global variable would
50 // have tried to call MPI functions before MPI got initialized.
51 //
52 // Doing this to the FEFamily part of a type doesn't make much sense,
53 // *except* that it's how we verify that a requested family matches
54 // across multiple processors.
55 
56 template <>
57 class OpFunction<libMesh::FEType>
58 {
59 public:
60 #ifdef LIBMESH_HAVE_MPI
61  static void fetype_max (void * intype, void * inouttype, int * len, MPI_Datatype *)
62  {
63  libMesh::FEType *in = static_cast<libMesh::FEType *>(intype);
64  libMesh::FEType *inout = static_cast<libMesh::FEType *>(inouttype);
65  for (int i=0; i != *len; ++i)
66  {
67  inout[i].family = std::max(in[i].family, inout[i].family);
68  inout[i].order = std::max(in[i].order, inout[i].order);
69  }
70  }
71 
72  static void fetype_min (void * intype, void * inouttype, int * len, MPI_Datatype *)
73  {
74  libMesh::FEType *in = static_cast<libMesh::FEType *>(intype);
75  libMesh::FEType *inout = static_cast<libMesh::FEType *>(inouttype);
76  for (int i=0; i != *len; ++i)
77  {
78  inout[i].family = std::min(in[i].family, inout[i].family);
79  inout[i].order = std::min(in[i].order, inout[i].order);
80  }
81  }
82 
83  static void fetype_sum (void *, void *, int *, MPI_Datatype *)
84  {
85  libmesh_not_implemented();
86  }
87 
88  static MPI_Op max()
89  {
90  // _static_op never gets freed, but it only gets committed once,
91  // so it's not a *huge* memory leak...
92  static MPI_Op _static_op;
93  static bool _is_initialized = false;
94  if (!_is_initialized)
95  {
96  timpi_call_mpi
97  (MPI_Op_create (fetype_max, /*commute=*/ true,
98  &_static_op));
99 
100  _is_initialized = true;
101  }
102 
103  return _static_op;
104  }
105  static MPI_Op min()
106  {
107  // _static_op never gets freed, but it only gets committed once,
108  // so it's not a *huge* memory leak...
109  static MPI_Op _static_op;
110  static bool _is_initialized = false;
111  if (!_is_initialized)
112  {
113  timpi_call_mpi
114  (MPI_Op_create (fetype_min, /*commute=*/ true,
115  &_static_op));
116 
117  _is_initialized = true;
118  }
119 
120  return _static_op;
121  }
122  static MPI_Op sum()
123  {
124  libmesh_not_implemented();
125  }
126 
127 #endif // LIBMESH_HAVE_MPI
128 };
129 
130 
131 template <>
132 struct Attributes<libMesh::FEType>
133 {
134  static const bool has_min_max = true;
135  static void set_lowest(libMesh::FEType & x) {
136  x.family = libMesh::FEFamily(0);
137  x.order = libMesh::Order(0);
138  }
139  static void set_highest(libMesh::FEType & x) {
142  }
143 };
144 
145 
146 // StandardType<> specializations to return a derived MPI datatype
147 // to handle communication of FETypes.
148 template <>
149 class StandardType<libMesh::FEType> : public DataType
150 {
151 public:
152  explicit
153  StandardType(const libMesh::FEType * example=nullptr)
154  {
155 #ifdef LIBMESH_HAVE_MPI
156  using libMesh::FEType;
157 
158  // We need an example for MPI_Address to use
159  FEType * ex;
160  std::unique_ptr<FEType> temp;
161  if (example)
162  ex = const_cast<FEType *>(example);
163  else
164  {
165  temp = std::make_unique<FEType>();
166  ex = temp.get();
167  }
168 
169 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
170  constexpr std::size_t structsize = 5;
171 #else
172  constexpr std::size_t structsize = 2;
173 #endif
174 
175  // Our FEType enums pack into int
176  MPI_Datatype int_types[structsize];
177 
178  // We require MPI-2 here:
179  int blocklengths[structsize];
180  MPI_Aint start, displs[structsize];
181  MPI_Datatype tmptype;
182 
183  timpi_call_mpi
184  (MPI_Get_address (ex, &start));
185 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
186  timpi_call_mpi
187  (MPI_Get_address (&(ex->order), &displs[0]));
188  timpi_call_mpi
189  (MPI_Get_address (&(ex->radial_order), &displs[1]));
190  timpi_call_mpi
191  (MPI_Get_address (&(ex->family), &displs[2]));
192  timpi_call_mpi
193  (MPI_Get_address (&(ex->radial_family), &displs[3]));
194  timpi_call_mpi
195  (MPI_Get_address (&(ex->inf_map), &displs[4]));
196 #else // ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
197  timpi_call_mpi
198  (MPI_Get_address (&(ex->order), &displs[0]));
199  timpi_call_mpi
200  (MPI_Get_address (&(ex->family), &displs[1]));
201 #endif // ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
202 
203  // subtract off beginning of the structure to get offsets. We'll
204  // be creating a struct type later to account for any weird
205  // padding issues.
206  for (std::size_t i = 0; i != structsize; ++i)
207  {
208  displs[i] -= start;
209  int_types[i] = MPI_INT;
210  blocklengths[i] = 1;
211  }
212 
213  // create a prototype structure
214  timpi_call_mpi
215  (MPI_Type_create_struct (structsize, blocklengths, displs,
216  int_types, &tmptype));
217  timpi_call_mpi
218  (MPI_Type_commit (&tmptype));
219 
220  // resize the structure type to account for padding, if any
221  timpi_call_mpi
222  (MPI_Type_create_resized (tmptype, 0, sizeof(FEType),
223  &_datatype));
224 
225  timpi_call_mpi
226  (MPI_Type_commit (&_datatype));
227 
228  timpi_call_mpi
229  (MPI_Type_free (&tmptype));
230 #else
231  libmesh_ignore(example);
232 #endif // #ifdef LIBMESH_HAVE_MPI
233  }
234 
235  StandardType(const StandardType<libMesh::FEType> & timpi_mpi_var(t))
236  : DataType()
237  {
238  timpi_call_mpi (MPI_Type_dup (t._datatype, &_datatype));
239  }
240 
241  ~StandardType() { this->free(); }
242 
243  static const bool is_fixed_type = true;
244 };
245 
246 } // namespace TIMPI
247 
248 #endif // LIBMESH_PARALLEL_FE_TYPE_H
class FEType hides (possibly multiple) FEFamily and approximation orders, thereby enabling specialize...
Definition: fe_type.h:196
static void set_lowest(libMesh::FEType &x)
FEFamily family
The type of finite element.
Definition: fe_type.h:221
Order
defines an enum for polynomial orders.
Definition: enum_order.h:40
static void set_highest(libMesh::FEType &x)
OrderWrapper order
The approximation order of the element.
Definition: fe_type.h:215
The libMesh namespace provides an interface to certain functionality in the library.
StandardType(const libMesh::FEType *example=nullptr)
void libmesh_ignore(const Args &...)
StandardType(const StandardType< libMesh::FEType > &timpi_mpi_var(t))
bool _is_initialized
Flag that tells if init() has been called.
Definition: libmesh.C:257
static const bool has_min_max
static const bool is_fixed_type
static void fetype_min(void *intype, void *inouttype, int *len, MPI_Datatype *)
TIMPI_PARALLEL_INTEGER_OPS(char)
static void fetype_max(void *intype, void *inouttype, int *len, MPI_Datatype *)
static void fetype_sum(void *, void *, int *, MPI_Datatype *)
FEFamily
defines an enum for finite element families.
TIMPI_STANDARD_TYPE(char, MPI_CHAR)