MFEM v4.8.0
Finite element discretization library
Loading...
Searching...
No Matches
mortarassembler.cpp
Go to the documentation of this file.
1// Copyright (c) 2010-2025, 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
12#ifdef MFEM_USE_MOONOLITH
13
14#include "mortarassembler.hpp"
16
17#include "cut.hpp"
18#include "transferutils.hpp"
19
20#include <cassert>
21
22// Moonolith includes
23#include "moonolith_aabb.hpp"
24#include "moonolith_serial_hash_grid.hpp"
25#include "moonolith_stream_utils.hpp"
26#include "par_moonolith_config.hpp"
27
28using namespace mfem::internal;
29
30namespace mfem
31{
32
33struct MortarAssembler::Impl
34{
35public:
36 std::shared_ptr<FiniteElementSpace> source;
37 std::shared_ptr<FiniteElementSpace> destination;
38 std::vector<std::shared_ptr<MortarIntegrator>> integrators;
39 std::shared_ptr<SparseMatrix> coupling_matrix;
40 std::shared_ptr<SparseMatrix> mass_matrix;
41 bool verbose{false};
42 bool assemble_mass_and_coupling_together{true};
43 int max_solver_iterations{400};
44
45 bool is_vector_fe() const
46 {
47 bool is_vector_fe = false;
48 for (auto i_ptr : integrators)
49 {
50 if (i_ptr->is_vector_fe())
51 {
52 is_vector_fe = true;
53 break;
54 }
55 }
56
57 return is_vector_fe;
58 }
59
60 BilinearFormIntegrator * new_mass_integrator() const
61 {
62 if (is_vector_fe())
63 {
64 return new VectorFEMassIntegrator();
65 }
66 else
67 {
68 return new MassIntegrator();
69 }
70 }
71};
72
74
76{
77 impl_->assemble_mass_and_coupling_together = value;
78}
79
80void MortarAssembler::SetMaxSolverIterations(const int max_solver_iterations)
81{
82 impl_->max_solver_iterations = max_solver_iterations;
83}
84
86 const std::shared_ptr<MortarIntegrator> &integrator)
87{
88 impl_->integrators.push_back(integrator);
89}
90
91void MortarAssembler::SetVerbose(const bool verbose)
92{
93 impl_->verbose = verbose;
94}
95
96template <int Dim>
97void BuildBoxes(const Mesh &mesh,
98 std::vector<::moonolith::AABB<Dim, double>> &element_boxes)
99{
100#ifndef NDEBUG
101 const int dim = mesh.Dimension();
102 assert(dim == Dim);
103#endif
104 element_boxes.resize(mesh.GetNE());
105
107 for (int i = 0; i < mesh.GetNE(); ++i)
108 {
109 mesh.GetPointMatrix(i, pts);
110 MinCol(pts, &element_boxes[i].min_[0], false);
111 MaxCol(pts, &element_boxes[i].max_[0], false);
112 }
113}
114
115bool HashGridDetectIntersections(const Mesh &src, const Mesh &dest,
116 std::vector<moonolith::Integer> &pairs)
117{
118 const int dim = dest.Dimension();
119
120 switch (dim)
121 {
122 case 1:
123 {
124 std::vector<::moonolith::AABB<1, double>> src_boxes, dest_boxes;
125 BuildBoxes(src, src_boxes);
126 BuildBoxes(dest, dest_boxes);
127
128 ::moonolith::SerialHashGrid<1, double> grid;
129 return grid.detect(src_boxes, dest_boxes, pairs);
130 }
131 case 2:
132 {
133 std::vector<::moonolith::AABB<2, double>> src_boxes, dest_boxes;
134 BuildBoxes(src, src_boxes);
135 BuildBoxes(dest, dest_boxes);
136
137 ::moonolith::SerialHashGrid<2, double> grid;
138 return grid.detect(src_boxes, dest_boxes, pairs);
139 }
140 case 3:
141 {
142 std::vector<::moonolith::AABB<3, double>> src_boxes, dest_boxes;
143 BuildBoxes(src, src_boxes);
144 BuildBoxes(dest, dest_boxes);
145
146 ::moonolith::SerialHashGrid<3, double> grid;
147 return grid.detect(src_boxes, dest_boxes, pairs);
148 }
149 default:
150 {
151 assert(false);
152 return false;
153 }
154 }
155}
156
158 const std::shared_ptr<FiniteElementSpace> &source,
159 const std::shared_ptr<FiniteElementSpace> &destination)
160 : impl_(new Impl())
161{
162 impl_->source = source;
163 impl_->destination = destination;
164}
165
166int order_multiplier(const Geometry::Type type, const int dim)
167{
168 return
169 (type == Geometry::TRIANGLE || type == Geometry::TETRAHEDRON ||
170 type == Geometry::SEGMENT)? 1 : dim;
171}
172
173bool MortarAssembler::Assemble(std::shared_ptr<SparseMatrix> &B)
174{
175 using namespace std;
176 const bool verbose = impl_->verbose;
177
178 const auto &source_mesh = *impl_->source->GetMesh();
179 const auto &destination_mesh = *impl_->destination->GetMesh();
180
181 int dim = source_mesh.Dimension();
182
183 std::vector<::moonolith::Integer> pairs;
184 if (!HashGridDetectIntersections(source_mesh, destination_mesh, pairs))
185 {
186 return false;
187 }
188
189 std::shared_ptr<Cut> cut = NewCut(dim);
190 if (!cut)
191 {
192 assert(false && "NOT Supported!");
193 return false;
194 }
195
196
197 IntegrationRule source_ir;
198 IntegrationRule destination_ir;
199
200 int skip_zeros = 1;
201 B = make_shared<SparseMatrix>(impl_->destination->GetNDofs(),
202 impl_->source->GetNDofs());
203
204
205 std::unique_ptr<BilinearFormIntegrator> mass_integr(
206 impl_->new_mass_integrator());
207
208 if (impl_->assemble_mass_and_coupling_together)
209 {
210 impl_->mass_matrix = make_shared<SparseMatrix>(impl_->destination->GetNDofs(),
211 impl_->destination->GetNDofs());
212 }
213
214
215
216 Array<int> source_vdofs, destination_vdofs;
217 DenseMatrix elemmat;
218 DenseMatrix cumulative_elemmat;
219 double local_element_matrices_sum = 0.0;
220
221 long n_intersections = 0;
222 long n_candidates = 0;
223
224 int max_q_order = 0;
225
226 for (auto i_ptr : impl_->integrators)
227 {
228 max_q_order = std::max(i_ptr->GetQuadratureOrder(), max_q_order);
229 }
230
231 bool intersected = false;
232 for (auto it = begin(pairs); it != end(pairs); /* inside */)
233 {
234 const int source_index = *it++;
235 const int destination_index = *it++;
236
237 auto &source_fe = *impl_->source->GetFE(source_index);
238 auto &destination_fe = *impl_->destination->GetFE(destination_index);
239
240 ElementTransformation &destination_Trans =
241 *impl_->destination->GetElementTransformation(destination_index);
242
243 // Quadrature order mangling
244 int src_order_mult = order_multiplier(source_fe.GetGeomType(), dim);
245 int dest_order_mult = order_multiplier(destination_fe.GetGeomType(), dim);
246
247 const int src_order = src_order_mult * source_fe.GetOrder();
248 const int dest_order = dest_order_mult * destination_fe.GetOrder();
249
250 int contraction_order = src_order + dest_order;
251
252 if (impl_->assemble_mass_and_coupling_together)
253 {
254 contraction_order = std::max(contraction_order, 2 * dest_order);
255 }
256
257 const int order = contraction_order + dest_order_mult *
258 destination_Trans.OrderW() + max_q_order;
259
260 // Update the quadrature rule in case it changed the order
261 cut->SetIntegrationOrder(order);
262
263 n_candidates++;
264
265 if (cut->BuildQuadrature(*impl_->source, source_index, *impl_->destination,
266 destination_index, source_ir, destination_ir))
267 {
268 impl_->source->GetElementVDofs(source_index, source_vdofs);
269 impl_->destination->GetElementVDofs(destination_index, destination_vdofs);
270
271 ElementTransformation &source_Trans =
272 *impl_->source->GetElementTransformation(source_index);
273
274 bool first = true;
275 for (auto i_ptr : impl_->integrators)
276 {
277 if (first)
278 {
279 i_ptr->AssembleElementMatrix(source_fe, source_ir, source_Trans,
280 destination_fe, destination_ir,
281 destination_Trans, cumulative_elemmat);
282 first = false;
283 }
284 else
285 {
286 i_ptr->AssembleElementMatrix(source_fe, source_ir, source_Trans,
287 destination_fe, destination_ir,
288 destination_Trans, elemmat);
289 cumulative_elemmat += elemmat;
290 }
291 }
292
293 local_element_matrices_sum += Sum(cumulative_elemmat);
294
295 B->AddSubMatrix(destination_vdofs, source_vdofs, cumulative_elemmat,
296 skip_zeros);
297
298 if (impl_->assemble_mass_and_coupling_together)
299 {
300 mass_integr->SetIntRule(&destination_ir);
301 mass_integr->AssembleElementMatrix(destination_fe, destination_Trans, elemmat);
302 impl_->mass_matrix->AddSubMatrix(destination_vdofs, destination_vdofs, elemmat,
303 skip_zeros);
304 }
305
306 intersected = true;
307 ++n_intersections;
308 }
309 }
310
311 if (!intersected)
312 {
313 return false;
314 }
315
316 B->Finalize();
317
318 if (impl_->assemble_mass_and_coupling_together)
319 {
320 impl_->mass_matrix->Finalize();
321 }
322
323 if (verbose)
324 {
325 mfem::out << "local_element_matrices_sum: " << local_element_matrices_sum
326 << std::endl;
327 mfem::out << "B in R^(" << B->Height() << " x " << B->Width() << ")"
328 << std::endl;
329
330 mfem::out << "n_intersections: " << n_intersections
331 << ", n_candidates: " << n_candidates << '\n';
332
333 cut->Describe();
334 }
335
336 return true;
337}
338
340 GridFunction &dest_fun)
341{
342 return Update() && Apply(src_fun, dest_fun);
343}
344
346 GridFunction &dest_fun)
347{
348 if (!impl_->coupling_matrix)
349 {
350 if (!Update())
351 {
352 return false;
353 }
354 }
355
356 Vector temp(impl_->coupling_matrix->Height());
357 impl_->coupling_matrix->Mult(src_fun, temp);
358
359 CGSolver Dinv;
360 Dinv.SetMaxIter(impl_->max_solver_iterations);
361
362 if (impl_->verbose)
363 {
364 Dinv.SetPrintLevel(3);
365 }
366
367 Dinv.SetOperator(*impl_->mass_matrix);
368 Dinv.SetRelTol(1e-6);
369 Dinv.SetMaxIter(80);
370 Dinv.Mult(temp, dest_fun);
371 return true;
372}
373
375{
376 using namespace std;
377 const bool verbose = impl_->verbose;
378
379 StopWatch chrono;
380
381 if (verbose)
382 {
383 mfem::out << "\nAssembling coupling operator..." << endl;
384 }
385
386 chrono.Start();
387
388 if (!Assemble(impl_->coupling_matrix))
389 {
390 return false;
391 }
392
393 chrono.Stop();
394 if (verbose)
395 {
396 mfem::out << "Done. time: ";
397 mfem::out << chrono.RealTime() << " seconds" << endl;
398 }
399
400 if (!impl_->assemble_mass_and_coupling_together)
401 {
402 BilinearForm b_form(impl_->destination.get());
403
404 b_form.AddDomainIntegrator(impl_->new_mass_integrator());
405
406 b_form.Assemble();
407 b_form.Finalize();
408
409 impl_->mass_matrix = std::shared_ptr<SparseMatrix>(b_form.LoseMat());
410 }
411
412 if (verbose)
413 {
414 Vector brs(impl_->coupling_matrix->Height());
415 impl_->coupling_matrix->GetRowSums(brs);
416
417 Vector drs(impl_->mass_matrix->Height());
418 impl_->mass_matrix->GetRowSums(drs);
419
420 mfem::out << "sum(B): " << brs.Sum() << std::endl;
421 mfem::out << "sum(D): " << drs.Sum() << std::endl;
422 }
423
424 return true;
425}
426
427} // namespace mfem
428
429#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:538
void Mult(const Vector &b, Vector &x) const override
Iterative solution of the linear system using the Conjugate Gradient method.
Definition solvers.cpp:751
void SetOperator(const Operator &op) override
Set/update the solver for the given operator.
Definition solvers.hpp:551
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:31
Class for an integration rule - an Array of IntegrationPoint.
Definition intrules.hpp:100
void SetRelTol(real_t rtol)
Definition solvers.hpp:229
virtual void SetPrintLevel(int print_lvl)
Legacy method to set the level of verbosity of the solver output.
Definition solvers.cpp:72
void SetMaxIter(int max_it)
Definition solvers.hpp:231
Mesh data type.
Definition mesh.hpp:64
int GetNE() const
Returns number of elements.
Definition mesh.hpp:1282
int Dimension() const
Dimension of the reference space used within the elements.
Definition mesh.hpp:1216
void GetPointMatrix(int i, DenseMatrix &pointmat) const
Definition mesh.cpp:7645
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:1204
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:441
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)
void pts(int iphi, int t, real_t x[])