libMesh
Loading...
Searching...
No Matches
parallel_fe_type.h
Go to the documentation of this file.
1// The libMesh Finite Element Library.
2// Copyright (C) 2002-2026 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
37namespace 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
56template <>
57class OpFunction<libMesh::FEType>
58{
59public:
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
131template <>
132struct Attributes<libMesh::FEType>
133{
134 static const bool has_min_max = true;
135 static void set_lowest(libMesh::FEType & x) {
137 x.order = libMesh::Order(0);
138 }
143};
144
145
146// StandardType<> specializations to return a derived MPI datatype
147// to handle communication of FETypes.
148template <>
149class StandardType<libMesh::FEType> : public DataType
150{
151public:
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
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
static const bool is_fixed_type
static void fetype_max(void *intype, void *inouttype, int *len, MPI_Datatype *)
static void fetype_sum(void *, void *, int *, MPI_Datatype *)
static void fetype_min(void *intype, void *inouttype, int *len, MPI_Datatype *)
StandardType(const StandardType< libMesh::FEType > &timpi_mpi_var(t))
StandardType(const libMesh::FEType *example=nullptr)
class FEType hides (possibly multiple) FEFamily and approximation orders, thereby enabling specialize...
Definition fe_type.h:197
OrderWrapper order
The approximation order of the element (at 0 p-refinement level).
Definition fe_type.h:203
FEFamily family
The type of finite element.
Definition fe_type.h:228
TIMPI_STANDARD_TYPE(char, MPI_CHAR)
TIMPI_PARALLEL_INTEGER_OPS(char)
The libMesh namespace provides an interface to certain functionality in the library.
@ INVALID_ORDER
Definition enum_order.h:88
static void set_lowest(libMesh::FEType &x)
static void set_highest(libMesh::FEType &x)
static const bool has_min_max