MFEM v4.10.0
Finite element discretization library
Loading...
Searching...
No Matches
mortarassembler.cpp
Go to the documentation of this file.
1// Copyright (c) 2010-2026, Lawrence Livermore National Security, LLC. Produced
2// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3// LICENSE and NOTICE for details. LLNL-CODE-806117.
4//
5// This file is part of the MFEM library. For more information and source code
6// availability visit https://mfem.org.
7//
8// MFEM is free software; you can redistribute it and/or modify it under the
9// terms of the BSD-3 license. We welcome feedback and contributions, see file
10// CONTRIBUTING.md for details.
11
13
14#ifdef MFEM_USE_MOONOLITH
15
16#include "mortarassembler.hpp"
18
19#include "cut.hpp"
20#include "transferutils.hpp"
21
22#include <cassert>
23
24// Moonolith includes
25#include "moonolith_aabb.hpp"
26#include "moonolith_serial_hash_grid.hpp"
27#include "moonolith_stream_utils.hpp"
28#include "par_moonolith_config.hpp"
29
30using namespace mfem::internal;
31
32namespace mfem
33{
34
35struct MortarAssembler::Impl
36{
37public:
38 std::shared_ptr<FiniteElementSpace> source;
39 std::shared_ptr<FiniteElementSpace> destination;
40 std::vector<std::shared_ptr<MortarIntegrator>> integrators;
41 std::shared_ptr<SparseMatrix> coupling_matrix;
42 std::shared_ptr<SparseMatrix> mass_matrix;
43 bool verbose{false};
44 bool assemble_mass_and_coupling_together{true};
45 int max_solver_iterations{400};
46
47 BilinearFormIntegrator * newBFormIntegrator() const
48 {
49 assert(!integrators.empty());
50 return integrators[0]->newBFormIntegrator();
51 }
52};
53
55
57{
58 impl_->assemble_mass_and_coupling_together = value;
59}
60
61void MortarAssembler::SetMaxSolverIterations(const int max_solver_iterations)
62{
63 impl_->max_solver_iterations = max_solver_iterations;
64}
65
67 const std::shared_ptr<MortarIntegrator> &integrator)
68{
69 impl_->integrators.push_back(integrator);
70}
71
72void MortarAssembler::SetVerbose(const bool verbose)
73{
74 impl_->verbose = verbose;
75}
76
77template <int Dim>
78void BuildBoxes(const Mesh &mesh,
79 std::vector<::moonolith::AABB<Dim, double>> &element_boxes)
80{
81 MFEM_ASSERT(mesh.Dimension() == Dim, "Mesh and box dimensions mismatched");
82 element_boxes.resize(mesh.GetNE());
83
85 for (int i = 0; i < mesh.GetNE(); ++i)
86 {
87 mesh.GetPointMatrix(i, pts);
88 MinCol(pts, &element_boxes[i].min_[0], false);
89 MaxCol(pts, &element_boxes[i].max_[0], false);
90 }
91}
92
93bool HashGridDetectIntersections(const Mesh &src, const Mesh &dest,
94 std::vector<moonolith::Integer> &pairs)
95{
96 const int dim = dest.Dimension();
97
98 switch (dim)
99 {
100 case 1:
101 {
102 std::vector<::moonolith::AABB<1, double>> src_boxes, dest_boxes;
103 BuildBoxes(src, src_boxes);
104 BuildBoxes(dest, dest_boxes);
105
106 ::moonolith::SerialHashGrid<1, double> grid;
107 return grid.detect(src_boxes, dest_boxes, pairs);
108 }
109 case 2:
110 {
111 std::vector<::moonolith::AABB<2, double>> src_boxes, dest_boxes;
112 BuildBoxes(src, src_boxes);
113 BuildBoxes(dest, dest_boxes);
114
115 ::moonolith::SerialHashGrid<2, double> grid;
116 return grid.detect(src_boxes, dest_boxes, pairs);
117 }
118 case 3:
119 {
120 std::vector<::moonolith::AABB<3, double>> src_boxes, dest_boxes;
121 BuildBoxes(src, src_boxes);
122 BuildBoxes(dest, dest_boxes);
123
124 ::moonolith::SerialHashGrid<3, double> grid;
125 return grid.detect(src_boxes, dest_boxes, pairs);
126 }
127 default:
128 {
129 assert(false);
130 return false;
131 }
132 }
133}
134
136 const std::shared_ptr<FiniteElementSpace> &source,
137 const std::shared_ptr<FiniteElementSpace> &destination)
138 : impl_(new Impl())
139{
140 impl_->source = source;
141 impl_->destination = destination;
142}
143
144int order_multiplier(const Geometry::Type type, const int dim)
145{
146 return
147 (type == Geometry::TRIANGLE || type == Geometry::TETRAHEDRON ||
148 type == Geometry::SEGMENT)? 1 : dim;
149}
150
151bool MortarAssembler::Assemble(std::shared_ptr<SparseMatrix> &B)
152{
153 using namespace std;
154 const bool verbose = impl_->verbose;
155
156 const auto &source_mesh = *impl_->source->GetMesh();
157 const auto &destination_mesh = *impl_->destination->GetMesh();
158
159 int dim = source_mesh.Dimension();
160
161 std::vector<::moonolith::Integer> pairs;
162 if (!HashGridDetectIntersections(source_mesh, destination_mesh, pairs))
163 {
164 return false;
165 }
166
167 std::shared_ptr<Cut> cut = NewCut(dim);
168 if (!cut)
169 {
170 assert(false && "NOT Supported!");
171 return false;
172 }
173
174
175 IntegrationRule source_ir;
176 IntegrationRule destination_ir;
177
178 int skip_zeros = 1;
179 B = make_shared<SparseMatrix>(impl_->destination->GetNDofs(),
180 impl_->source->GetNDofs());
181
182 std::unique_ptr<BilinearFormIntegrator> mass_integr(
183 impl_->newBFormIntegrator());
184
185 if (impl_->assemble_mass_and_coupling_together)
186 {
187 impl_->mass_matrix = make_shared<SparseMatrix>(impl_->destination->GetNDofs(),
188 impl_->destination->GetNDofs());
189 }
190
191 Array<int> source_vdofs, destination_vdofs;
192 DenseMatrix elemmat;
193 DenseMatrix cumulative_elemmat;
194 double local_element_matrices_sum = 0.0;
195
196 long n_intersections = 0;
197 long n_candidates = 0;
198
199 int max_q_order = 0;
200
201 for (auto i_ptr : impl_->integrators)
202 {
203 max_q_order = std::max(i_ptr->GetQuadratureOrder(), max_q_order);
204 }
205
206 bool intersected = false;
207 for (auto it = begin(pairs); it != end(pairs); /* inside */)
208 {
209 const int source_index = *it++;
210 const int destination_index = *it++;
211
212 auto &source_fe = *impl_->source->GetFE(source_index);
213 auto &destination_fe = *impl_->destination->GetFE(destination_index);
214
215 ElementTransformation &destination_Trans =
216 *impl_->destination->GetElementTransformation(destination_index);
217
218 // Quadrature order mangling
219 int src_order_mult = order_multiplier(source_fe.GetGeomType(), dim);
220 int dest_order_mult = order_multiplier(destination_fe.GetGeomType(), dim);
221
222 const int src_order = src_order_mult * source_fe.GetOrder();
223 const int dest_order = dest_order_mult * destination_fe.GetOrder();
224
225 int contraction_order = src_order + dest_order;
226
227 if (impl_->assemble_mass_and_coupling_together)
228 {
229 contraction_order = std::max(contraction_order, 2 * dest_order);
230 }
231
232 const int order = contraction_order + dest_order_mult *
233 destination_Trans.OrderW() + max_q_order;
234
235 // Update the quadrature rule in case it changed the order
236 cut->SetIntegrationOrder(order);
237
238 n_candidates++;
239
240 if (cut->BuildQuadrature(*impl_->source, source_index, *impl_->destination,
241 destination_index, source_ir, destination_ir))
242 {
243 impl_->source->GetElementVDofs(source_index, source_vdofs);
244 impl_->destination->GetElementVDofs(destination_index, destination_vdofs);
245
246 ElementTransformation &source_Trans =
247 *impl_->source->GetElementTransformation(source_index);
248
249 bool first = true;
250 for (auto i_ptr : impl_->integrators)
251 {
252 if (first)
253 {
254 i_ptr->AssembleElementMatrix(source_fe, source_ir, source_Trans,
255 destination_fe, destination_ir,
256 destination_Trans, cumulative_elemmat);
257 first = false;
258 }
259 else
260 {
261 i_ptr->AssembleElementMatrix(source_fe, source_ir, source_Trans,
262 destination_fe, destination_ir,
263 destination_Trans, elemmat);
264 cumulative_elemmat += elemmat;
265 }
266 }
267
268 local_element_matrices_sum += Sum(cumulative_elemmat);
269
270 B->AddSubMatrix(destination_vdofs, source_vdofs, cumulative_elemmat,
271 skip_zeros);
272
273 if (impl_->assemble_mass_and_coupling_together)
274 {
275 mass_integr->SetIntRule(&destination_ir);
276 mass_integr->AssembleElementMatrix(destination_fe, destination_Trans, elemmat);
277 impl_->mass_matrix->AddSubMatrix(destination_vdofs, destination_vdofs, elemmat,
278 skip_zeros);
279 }
280
281 intersected = true;
282 ++n_intersections;
283 }
284 }
285
286 if (!intersected)
287 {
288 return false;
289 }
290
291 B->Finalize();
292
293 if (impl_->assemble_mass_and_coupling_together)
294 {
295 impl_->mass_matrix->Finalize();
296 }
297
298 if (verbose)
299 {
300 mfem::out << "local_element_matrices_sum: " << local_element_matrices_sum
301 << std::endl;
302 mfem::out << "B in R^(" << B->Height() << " x " << B->Width() << ")"
303 << std::endl;
304
305 mfem::out << "n_intersections: " << n_intersections
306 << ", n_candidates: " << n_candidates << '\n';
307
308 cut->Describe();
309 }
310
311 return true;
312}
313
315 GridFunction &dest_fun)
316{
317 return Update() && Apply(src_fun, dest_fun);
318}
319
321 GridFunction &dest_fun)
322{
323 if (!impl_->coupling_matrix)
324 {
325 if (!Update())
326 {
327 return false;
328 }
329 }
330
331 Vector temp(impl_->coupling_matrix->Height());
332 impl_->coupling_matrix->Mult(src_fun, temp);
333
334 CGSolver Dinv;
335 Dinv.SetMaxIter(impl_->max_solver_iterations);
336
337 if (impl_->verbose)
338 {
339 Dinv.SetPrintLevel(3);
340 }
341
342 Dinv.SetOperator(*impl_->mass_matrix);
343 Dinv.SetRelTol(1e-6);
344 Dinv.SetMaxIter(80);
345 Dinv.Mult(temp, dest_fun);
346 return true;
347}
348
350{
351 using namespace std;
352 const bool verbose = impl_->verbose;
353
354 StopWatch chrono;
355
356 if (verbose)
357 {
358 mfem::out << "\nAssembling coupling operator..." << endl;
359 }
360
361 chrono.Start();
362
363 if (!Assemble(impl_->coupling_matrix))
364 {
365 return false;
366 }
367
368 chrono.Stop();
369 if (verbose)
370 {
371 mfem::out << "Done. time: ";
372 mfem::out << chrono.RealTime() << " seconds" << endl;
373 }
374
375 if (!impl_->assemble_mass_and_coupling_together)
376 {
377 BilinearForm b_form(impl_->destination.get());
378
379 b_form.AddDomainIntegrator(impl_->newBFormIntegrator());
380
381 b_form.Assemble();
382 b_form.Finalize();
383
384 impl_->mass_matrix = std::shared_ptr<SparseMatrix>(b_form.LoseMat());
385 }
386
387 if (verbose)
388 {
389 Vector brs(impl_->coupling_matrix->Height());
390 impl_->coupling_matrix->GetRowSums(brs);
391
392 Vector drs(impl_->mass_matrix->Height());
393 impl_->mass_matrix->GetRowSums(drs);
394
395 mfem::out << "sum(B): " << brs.Sum() << std::endl;
396 mfem::out << "sum(D): " << drs.Sum() << std::endl;
397 }
398
399 return true;
400}
401
402} // namespace mfem
403
404#endif // MFEM_USE_MOONOLITH
Abstract base class BilinearFormIntegrator.
A "square matrix" operator for the associated FE space and BLFIntegrators The sum of all the BLFInteg...
void AddDomainIntegrator(BilinearFormIntegrator *bfi)
Adds new Domain Integrator. Assumes ownership of bfi.
void Finalize(int skip_zeros=1) override
Finalizes the matrix initialization if the AssemblyLevel is AssemblyLevel::LEGACY....
void Assemble(int skip_zeros=1)
Assembles the form i.e. sums over all domain/bdr integrators.
SparseMatrix * LoseMat()
Nullifies the internal matrix and returns a pointer to it. Used for transferring ownership.
Conjugate gradient method.
Definition solvers.hpp:627
void Mult(const Vector &b, Vector &x) const override
Iterative solution of the linear system using the Conjugate Gradient method.
Definition solvers.cpp:869
void SetOperator(const Operator &op) override
Set/update the solver for the given operator.
Definition solvers.hpp:640
Data type dense matrix using column-major storage.
Definition densemat.hpp:24
virtual int OrderW() const =0
Return the order of the determinant of the Jacobian (weight) of the transformation.
Class for grid function - Vector with associated FE space.
Definition gridfunc.hpp:53
Class for an integration rule - an Array of IntegrationPoint.
Definition intrules.hpp:96
void SetRelTol(real_t rtol)
Definition solvers.hpp:238
virtual void SetPrintLevel(int print_lvl)
Legacy method to set the level of verbosity of the solver output.
Definition solvers.cpp:76
void SetMaxIter(int max_it)
Definition solvers.hpp:240
Mesh data type.
Definition mesh.hpp:67
int GetNE() const
Returns number of elements.
Definition mesh.hpp:1390
int Dimension() const
Dimension of the reference space used within the elements.
Definition mesh.hpp:1314
void GetPointMatrix(int i, DenseMatrix &pointmat) const
Definition mesh.cpp:8455
void SetAssembleMassAndCouplingTogether(const bool value)
Control if the Mass matrix is computed together with the coupling operator every time.
void SetMaxSolverIterations(const int max_solver_iterations)
Control the maximum numbers of conjugate gradients steps for mass matrix inversion.
void SetVerbose(const bool verbose)
Expose process details with verbose output.
void AddMortarIntegrator(const std::shared_ptr< MortarIntegrator > &integrator)
This method must be called before Assemble or Transfer. It will assemble the operator in all intersec...
MortarAssembler(const std::shared_ptr< FiniteElementSpace > &source, const std::shared_ptr< FiniteElementSpace > &destination)
constructs the object with source and destination spaces
bool Apply(const GridFunction &src_fun, GridFunction &dest_fun)
transfer a function from source to destination. It requires that the Update function is called before
bool Transfer(const GridFunction &src_fun, GridFunction &dest_fun)
transfer a function from source to destination. if the transfer is to be performed multiple times use...
bool Assemble(std::shared_ptr< SparseMatrix > &B)
assembles the coupling matrix B. B : source -> destination If u is a coefficient associated with sour...
bool Update()
assembles the various components necessary for the transfer. To be called before calling the Apply fu...
Timing object.
Definition tic_toc.hpp:36
double RealTime()
Return the number of real seconds elapsed since the stopwatch was started.
Definition tic_toc.cpp:432
void Start()
Start the stopwatch. The elapsed time is not cleared.
Definition tic_toc.cpp:411
void Stop()
Stop the stopwatch.
Definition tic_toc.cpp:422
Vector data type.
Definition vector.hpp:82
real_t Sum() const
Return the sum of the vector entries.
Definition vector.cpp:1246
int dim
Definition ex24.cpp:53
void source(const Vector &x, Vector &f)
Definition ex25.cpp:620
std::shared_ptr< Cut > NewCut(const int dim)
Definition cut.cpp:455
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
Definition globals.hpp:66
void BuildBoxes(const Mesh &mesh, std::vector<::moonolith::AABB< Dim, double > > &element_boxes)
bool HashGridDetectIntersections(const Mesh &src, const Mesh &dest, std::vector< moonolith::Integer > &pairs)
int order_multiplier(const Geometry::Type type, const int dim)
STL namespace.
void pts(int iphi, int t, real_t x[])