Line data Source code
1 : //* This file is part of the MOOSE framework
2 : //* https://www.mooseframework.org
3 : //*
4 : //* All rights reserved, see COPYRIGHT for full restrictions
5 : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6 : //*
7 : //* Licensed under LGPL 2.1, please see LICENSE for details
8 : //* https://www.gnu.org/licenses/lgpl-2.1.html
9 :
10 : #include "KokkosLinearFVFluxKernel.h"
11 : #include "KokkosLinearFVBoundaryCondition.h"
12 : #include "LinearFVBoundaryCondition.h"
13 :
14 : #include "Attributes.h"
15 : #include "FEProblemBase.h"
16 : #include "MooseMesh.h"
17 :
18 : #include <algorithm>
19 : #include <map>
20 :
21 : namespace Moose::Kokkos
22 : {
23 :
24 : InputParameters
25 4710 : LinearFVFluxKernel::validParams()
26 : {
27 4710 : auto params = LinearFVKernel::validParams();
28 4710 : params.registerSystemAttributeName("LinearFVFluxKernel");
29 9420 : params.addPrivateParam<bool>("_kokkos_flux_kernel", true);
30 4710 : return params;
31 0 : }
32 :
33 229 : LinearFVFluxKernel::LinearFVFluxKernel(const InputParameters & parameters)
34 116 : : LinearFVKernel(parameters)
35 : {
36 229 : }
37 :
38 1689 : LinearFVFluxKernel::LinearFVFluxKernel(const LinearFVFluxKernel & object)
39 : : LinearFVKernel(object),
40 867 : _bc_data(object._bc_data),
41 867 : _bc_index(object._bc_index),
42 867 : _internal_face_ids(object._internal_face_ids),
43 1734 : _boundary_face_ids(object._boundary_face_ids)
44 : {
45 1689 : }
46 :
47 : void
48 229 : LinearFVFluxKernel::initialSetup()
49 : {
50 113 : const auto n_elems =
51 116 : libMesh::cast_int<MOOSE_KOKKOS_INDEX_TYPE>(kokkosMesh().getNumLocalElements());
52 113 : const auto max_sides =
53 116 : libMesh::cast_int<MOOSE_KOKKOS_INDEX_TYPE>(_subproblem.mesh().getMaxSidesPerElem());
54 229 : _bc_index.create(max_sides, n_elems);
55 229 : _bc_index = -1;
56 :
57 : // Build a compact list of Kokkos linear FV BC data and attach each BC worklist's packed index to
58 : // the boundary faces where this kernel's variable is active.
59 229 : const auto sys_num = _var.sys();
60 229 : const auto var_num = _var.var();
61 229 : const auto var_name = _var.mooseVar()->name();
62 :
63 229 : std::vector<LinearFVBoundaryCondition *> bcs;
64 229 : _fe_problem.theWarehouse()
65 116 : .query()
66 116 : .template condition<AttribSysNum>(sys_num)
67 116 : .template condition<AttribSystem>("LinearFVBoundaryCondition")
68 116 : .template condition<AttribKokkos>(true)
69 232 : .template condition<AttribThread>(0)
70 116 : .queryInto(bcs);
71 :
72 229 : std::vector<LinearFVBoundaryCondition::BoundaryData> bc_data;
73 : #ifdef DEBUG
74 : std::vector<LinearFVBoundaryCondition *> bc_objects;
75 : #endif
76 229 : std::map<FaceID, BoundaryFaceID> bc_faces;
77 229 : auto & mesh = _subproblem.mesh();
78 229 : const auto * const kokkos_mesh = mesh.getKokkosMesh();
79 :
80 704 : for (auto * bc : bcs)
81 : {
82 475 : const auto & variable = bc->variable();
83 :
84 475 : if (variable.var() == var_num)
85 : {
86 395 : const auto bc_index = libMesh::cast_int<int>(bc_data.size());
87 395 : bc_data.push_back(bc->boundaryData());
88 : #ifdef DEBUG
89 : bc_objects.push_back(bc);
90 : #endif
91 :
92 3419 : for (const auto bc_face_index : make_range(bc->numBoundaryFaces()))
93 : {
94 3024 : const auto [contiguous_elem, side] = bc->boundaryFaceID(bc_face_index);
95 3024 : const FaceID face{contiguous_elem, side};
96 :
97 : #ifdef DEBUG
98 : if (bc_face_index)
99 : mooseAssert(
100 : bc->boundaryFaceID(bc_face_index - 1) < face,
101 : "Kokkos linear FV boundary face worklists must be ordered by (element, side)");
102 : #endif
103 :
104 3024 : auto & existing_index = _bc_index(side, contiguous_elem);
105 :
106 : // Ambiguous boundary data would make flux kernels non-deterministic.
107 3024 : if (existing_index != -1)
108 0 : mooseError("Kokkos linear FV flux kernel '",
109 0 : name(),
110 : "' found multiple Kokkos boundary conditions for variable '",
111 : var_name,
112 : "' on contiguous element ",
113 : contiguous_elem,
114 : ", side ",
115 : side,
116 : ".");
117 :
118 3024 : existing_index = bc_index;
119 3024 : bc_faces.emplace(face, BoundaryFaceID{contiguous_elem, side, bc_index, bc_face_index});
120 : }
121 : }
122 475 : }
123 :
124 229 : std::vector<FaceID> internal_face_ids;
125 229 : std::vector<BoundaryFaceID> boundary_face_ids;
126 :
127 229 : const auto * const variable = _var.mooseVar();
128 458 : for (const auto block : blockIDs())
129 45007 : for (const auto elem : mesh.getMesh().active_local_subdomain_elements_ptr_range(block))
130 : {
131 22389 : const auto contiguous_elem = kokkos_mesh->getContiguousElementID(elem);
132 :
133 105535 : for (const auto side : make_range(elem->n_sides()))
134 : {
135 83146 : const auto * const neighbor = elem->neighbor_ptr(side);
136 :
137 : mooseAssert(!neighbor || neighbor != libMesh::remote_elem,
138 : "We should have properly ghosted side neighbors for FV");
139 83146 : if (neighbor && variable->activeOnSubdomain(neighbor->subdomain_id()))
140 79042 : internal_face_ids.push_back({contiguous_elem, side});
141 : else
142 : {
143 4104 : const auto bc_face = bc_faces.find({contiguous_elem, side});
144 :
145 4104 : if (bc_face != bc_faces.end())
146 3024 : boundary_face_ids.push_back(bc_face->second);
147 : }
148 : }
149 229 : }
150 :
151 229 : std::sort(internal_face_ids.begin(), internal_face_ids.end());
152 229 : std::sort(boundary_face_ids.begin(), boundary_face_ids.end());
153 :
154 : #ifdef DEBUG
155 : for (const auto i : index_range(boundary_face_ids))
156 : {
157 : const auto & face = boundary_face_ids[i];
158 : mooseAssert(face.bc_index >= 0 &&
159 : libMesh::cast_int<std::size_t>(face.bc_index) < bc_objects.size(),
160 : "Boundary face has an invalid compact boundary condition index");
161 : mooseAssert(_bc_index(face.side, face.elem) == face.bc_index,
162 : "Boundary face does not map to its expected compact boundary condition index");
163 :
164 : const auto * const bc = bc_objects[face.bc_index];
165 : mooseAssert(face.bc_face_index < bc->numBoundaryFaces(),
166 : "Boundary face has an invalid BC-local packed index");
167 : const auto expected_face = bc->boundaryFaceID(face.bc_face_index);
168 : mooseAssert(expected_face.first == face.elem && expected_face.second == face.side,
169 : "Boundary face does not map to its expected BC-local packed index");
170 :
171 : if (i && boundary_face_ids[i - 1].bc_index == face.bc_index)
172 : mooseAssert(boundary_face_ids[i - 1].bc_face_index < face.bc_face_index,
173 : "Boundary faces and their BC-local packed indices have inconsistent ordering");
174 : }
175 : #endif
176 :
177 229 : _internal_face_ids = internal_face_ids;
178 229 : _boundary_face_ids = boundary_face_ids;
179 :
180 : #ifndef NDEBUG
181 : _bc_index.copyToDevice();
182 : #endif
183 229 : _bc_data.create(libMesh::cast_int<MOOSE_KOKKOS_INDEX_TYPE>(bc_data.size()));
184 624 : for (const auto i : index_range(bc_data))
185 395 : _bc_data[i] = bc_data[i];
186 229 : _bc_data.copyToDevice();
187 :
188 : // Non-Kokkos BCs are never called by Kokkos flux kernels; they would be silently
189 : // ignored, producing wrong results. Reject them early for this variable.
190 229 : std::vector<::LinearFVBoundaryCondition *> non_kokkos_bcs;
191 229 : _fe_problem.theWarehouse()
192 116 : .query()
193 116 : .template condition<AttribSysNum>(sys_num)
194 116 : .template condition<AttribSystem>("LinearFVBoundaryCondition")
195 116 : .template condition<AttribKokkos>(false)
196 232 : .template condition<AttribThread>(0)
197 116 : .queryInto(non_kokkos_bcs);
198 :
199 229 : for (auto * bc : non_kokkos_bcs)
200 : {
201 0 : const auto & variable = bc->variable();
202 :
203 0 : if (variable.number() == var_num)
204 0 : mooseError("Kokkos linear FV flux kernel '",
205 0 : name(),
206 : "' found non-Kokkos boundary condition '",
207 0 : bc->name(),
208 : "' (type '",
209 0 : bc->type(),
210 : "') for variable '",
211 0 : variable.name(),
212 : "'. Non-Kokkos BCs are not called by Kokkos flux kernels and will produce "
213 : "incorrect results. Use the Kokkos equivalent, e.g. "
214 : "'KokkosLinearFVFunctorDirichletBC'.");
215 : }
216 229 : }
217 :
218 : void
219 340 : LinearFVFluxKernel::computeRightHandSide()
220 : {
221 340 : if (hasInternalRightHandSideContribution() && _internal_face_ids.size())
222 : {
223 0 : Policy policy(0, _internal_face_ids.size());
224 0 : if (!_internal_rhs_dispatcher)
225 0 : _internal_rhs_dispatcher = DispatcherRegistry::build<InternalRightHandSideLoop>(this, type());
226 0 : _internal_rhs_dispatcher->parallelFor(policy);
227 0 : }
228 :
229 340 : if (_boundary_face_ids.size())
230 : {
231 340 : Policy policy(0, _boundary_face_ids.size());
232 340 : if (!_boundary_rhs_dispatcher)
233 223 : _boundary_rhs_dispatcher = DispatcherRegistry::build<BoundaryRightHandSideLoop>(this, type());
234 340 : _boundary_rhs_dispatcher->parallelFor(policy);
235 340 : }
236 340 : }
237 :
238 : void
239 340 : LinearFVFluxKernel::computeMatrix()
240 : {
241 340 : if (DispatcherRegistry::hasUserMethod<InternalMatrixLoop>(type()) && _internal_face_ids.size())
242 : {
243 340 : Policy policy(0, _internal_face_ids.size());
244 340 : if (!_internal_matrix_dispatcher)
245 223 : _internal_matrix_dispatcher = DispatcherRegistry::build<InternalMatrixLoop>(this, type());
246 340 : _internal_matrix_dispatcher->parallelFor(policy);
247 340 : }
248 :
249 340 : if (DispatcherRegistry::hasUserMethod<BoundaryMatrixLoop>(type()) && _boundary_face_ids.size())
250 : {
251 340 : Policy policy(0, _boundary_face_ids.size());
252 340 : if (!_boundary_matrix_dispatcher)
253 223 : _boundary_matrix_dispatcher = DispatcherRegistry::build<BoundaryMatrixLoop>(this, type());
254 340 : _boundary_matrix_dispatcher->parallelFor(policy);
255 340 : }
256 340 : }
257 :
258 : } // namespace Moose::Kokkos
|