MFEM v4.10.0
Finite element discretization library
Loading...
Searching...
No Matches
tmop_tools.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
12#include "tmop_tools.hpp"
13#include "nonlinearform.hpp"
14#include "pnonlinearform.hpp"
16
17namespace mfem
18{
19
20using namespace mfem;
21
22void AdvectorCG::SetInitialField(const Vector &init_nodes,
23 const Vector &init_field)
24{
25 nodes0 = init_nodes;
26 field0 = init_field;
27}
28
29void AdvectorCG::ComputeAtNewPosition(const Vector &new_mesh_nodes,
30 Vector &new_field,
31 int nodes_ordering)
32{
33 MFEM_VERIFY(nodes0.Size() == new_mesh_nodes.Size(),
34 "AdvectorCG assumes fixed mesh topology!");
35
37#ifdef MFEM_USE_MPI
38 if (pfes) { space = pfes; }
39#endif
40 int fes_ordering = space->GetOrdering(),
41 ncomp = space->GetVDim();
42
43 const int dof_cnt = field0.Size() / ncomp;
44
45 new_field = field0;
46 Vector new_field_temp;
47 for (int i = 0; i < ncomp; i++)
48 {
49 if (fes_ordering == Ordering::byNODES)
50 {
51 new_field_temp.MakeRef(new_field, i*dof_cnt, dof_cnt);
52 }
53 else
54 {
55 new_field_temp.SetSize(dof_cnt);
56 for (int j = 0; j < dof_cnt; j++)
57 {
58 new_field_temp(j) = new_field(i + j*ncomp);
59 }
60 }
61 ComputeAtNewPositionScalar(new_mesh_nodes, new_field_temp);
62 if (fes_ordering == Ordering::byVDIM)
63 {
64 for (int j = 0; j < dof_cnt; j++)
65 {
66 new_field(i + j*ncomp) = new_field_temp(j);
67 }
68 }
69 }
70
71 // Without this, the next remap would start from the initial mesh, i.e.,
72 // every consecutive remap would be more expensive, as it would have to
73 // transport the solution through bigger displacements.
74 field0 = new_field;
75 nodes0 = new_mesh_nodes;
76}
77
78void AdvectorCG::ComputeAtNewPositionScalar(const Vector &new_mesh_nodes,
79 Vector &new_field)
80{
81 Mesh *m = mesh;
82#ifdef MFEM_USE_MPI
83 if (pmesh) { m = pmesh; }
84#endif
85
86 MFEM_VERIFY(m != NULL, "No mesh has been given to the AdaptivityEvaluator.");
87
88 // This will be used to move the positions.
89 GridFunction *mesh_nodes = m->GetNodes();
90 *mesh_nodes = nodes0;
91 real_t minv = new_field.Min(), maxv = new_field.Max();
92
93 // Velocity of the positions.
94 GridFunction u(mesh_nodes->FESpace());
95 subtract(new_mesh_nodes, nodes0, u);
96
97 // Define a scalar FE space for the solution, and the advection operator.
98 TimeDependentOperator *oper = NULL;
99 FiniteElementSpace *fess = NULL;
100#ifdef MFEM_USE_MPI
101 ParFiniteElementSpace *pfess = NULL;
102#endif
103 if (fes)
104 {
105 fess = new FiniteElementSpace(fes->GetMesh(), fes->FEColl(), 1);
106 oper = new SerialAdvectorCGOper(nodes0, u, *fess, al);
107 }
108#ifdef MFEM_USE_MPI
109 else if (pfes)
110 {
111 pfess = new ParFiniteElementSpace(pfes->GetParMesh(), pfes->FEColl(), 1);
112 oper = new ParAdvectorCGOper(nodes0, u, *pfess, al, opt_mt);
113 }
114#endif
115 MFEM_VERIFY(oper != NULL,
116 "No FE space has been given to the AdaptivityEvaluator.");
117 ode_solver.Init(*oper);
118
119 // Compute some time step [mesh_size / speed].
120 real_t h_min = std::numeric_limits<real_t>::infinity();
121 for (int i = 0; i < m->GetNE(); i++)
122 {
123 h_min = std::min(h_min, m->GetElementSize(i));
124 }
125 real_t v_max = 0.0;
126 const int s = u.Size()/m->Dimension();
127
128 u.HostReadWrite();
129 for (int i = 0; i < s; i++)
130 {
131 real_t vel = 0.;
132 for (int j = 0; j < m->Dimension(); j++)
133 {
134 vel += u(i+j*s)*u(i+j*s);
135 }
136 v_max = std::max(v_max, vel);
137 }
138
139#ifdef MFEM_USE_MPI
140 if (pfes)
141 {
142 real_t v_loc = v_max, h_loc = h_min;
143 MPI_Allreduce(&v_loc, &v_max, 1, MPITypeMap<real_t>::mpi_type, MPI_MAX,
144 pfes->GetComm());
145 MPI_Allreduce(&h_loc, &h_min, 1, MPITypeMap<real_t>::mpi_type, MPI_MIN,
146 pfes->GetComm());
147 }
148#endif
149
150 if (v_max == 0.0) // No need to change the field.
151 {
152 delete oper;
153 delete fess;
154#ifdef MFEM_USE_MPI
155 delete pfess;
156#endif
157 return;
158 }
159
160 v_max = std::sqrt(v_max);
161 real_t dt = dt_scale * h_min / v_max;
162
163 real_t t = 0.0;
164 bool last_step = false;
165 while (!last_step)
166 {
167 if (t + dt >= 1.0)
168 {
169 dt = 1.0 - t;
170 last_step = true;
171 }
172 ode_solver.Step(new_field, t, dt);
173 }
174
175 real_t glob_minv = minv,
176 glob_maxv = maxv;
177#ifdef MFEM_USE_MPI
178 if (pfes)
179 {
180 MPI_Allreduce(&minv, &glob_minv, 1, MPITypeMap<real_t>::mpi_type, MPI_MIN,
181 pfes->GetComm());
182 MPI_Allreduce(&maxv, &glob_maxv, 1, MPITypeMap<real_t>::mpi_type, MPI_MAX,
183 pfes->GetComm());
184 }
185#endif
186
187 // Trim the overshoots and undershoots.
188 new_field.HostReadWrite();
189 for (int i = 0; i < new_field.Size(); i++)
190 {
191 if (new_field(i) < glob_minv) { new_field(i) = glob_minv; }
192 if (new_field(i) > glob_maxv) { new_field(i) = glob_maxv; }
193 }
194
195 delete oper;
196 delete fess;
197#ifdef MFEM_USE_MPI
198 delete pfess;
199#endif
200}
201
205 AssemblyLevel al)
206 : TimeDependentOperator(fes.GetVSize()),
207 x0(x_start), x_now(*fes.GetMesh()->GetNodes()),
208 u(vel), u_coeff(&u), M(&fes), K(&fes), al(al)
209{
211 K.AddDomainIntegrator(Kinteg);
213 K.Assemble(0);
214 K.Finalize(0);
215
216 MassIntegrator *Minteg = new MassIntegrator;
217 M.AddDomainIntegrator(Minteg);
219 M.Assemble(0);
220 M.Finalize(0);
221}
222
223void SerialAdvectorCGOper::Mult(const Vector &ind, Vector &di_dt) const
224{
225 // Move the mesh.
226 const real_t t = GetTime();
227 add(x0, t, u, x_now);
229
230 // Assemble on the new mesh.
231 K.BilinearForm::operator=(0.0);
232 K.Assemble();
233 Vector rhs(K.Size());
234 K.Mult(ind, rhs);
235 M.BilinearForm::operator=(0.0);
236 M.Assemble();
237
238#ifdef MFEM_USE_SINGLE
239 const real_t rtol = 1e-4;
240#else
241 const real_t rtol = 1e-12;
242#endif
243
244 // Solve.
245 di_dt = 0.0;
247 {
248 // Solve mat-free on the tdofs as the JacobiSmoother operates on tdofs.
249 OperatorPtr A;
250 Vector B, X;
252 M.FormLinearSystem(ess_tdof_list, di_dt, rhs, A, X, B);
254 PCG(*A, S, B, X, 0, 100, rtol, 0.0);
255 M.RecoverFEMSolution(X, rhs, di_dt);
256 }
257 else
258 {
259 // Solve the SpMat directly on the ldofs.
260 DSmoother S(M.SpMat());
261 PCG(M.SpMat(), S, rhs, di_dt, 0, 100, rtol, 0.0);
262 }
263}
264
265#ifdef MFEM_USE_MPI
269 AssemblyLevel al,
270 MemoryType mt)
271 : TimeDependentOperator(pfes.GetVSize()),
272 x0(x_start), x_now(*pfes.GetMesh()->GetNodes()),
273 u(vel), u_coeff(&u), M(&pfes), K(&pfes), al(al)
274{
277 {
278 Kinteg->SetPAMemoryType(mt);
279 }
280 K.AddDomainIntegrator(Kinteg);
282 K.Assemble(0);
283 K.Finalize(0);
284
285 MassIntegrator *Minteg = new MassIntegrator;
287 {
288 Minteg->SetPAMemoryType(mt);
289 }
290 M.AddDomainIntegrator(Minteg);
292 M.Assemble(0);
293 M.Finalize(0);
294}
295
296void ParAdvectorCGOper::Mult(const Vector &ind, Vector &di_dt) const
297{
298 // Move the mesh.
299 const real_t t = GetTime();
300 add(x0, t, u, x_now);
302
303 // Assemble on the new mesh.
304 K.BilinearForm::operator=(0.0);
305 K.Assemble();
307 K.Mult(ind, rhs);
308 M.BilinearForm::operator=(0.0);
309 M.Assemble();
310
311 Vector RHS;
312 RHS.SetSize(M.ParFESpace()->GetTrueVSize(), ind);
313 RHS.UseDevice(ind.UseDevice());
314 rhs.ParallelAssemble(RHS);
315
316 Vector X;
317 X.SetSize(M.ParFESpace()->GetTrueVSize(), ind);
318 X.UseDevice(ind.UseDevice());
319 X = 0.0;
320
321 OperatorHandle Mop;
322 Solver *prec = nullptr;
325 {
328 }
329 else
330 {
331 Mop.Reset(M.ParallelAssemble());
332 prec = new HypreSmoother;
333 static_cast<HypreSmoother*>(prec)->SetType(HypreSmoother::Jacobi, 1);
334 }
335
336 CGSolver lin_solver(M.ParFESpace()->GetParMesh()->GetComm());
337 lin_solver.SetPreconditioner(*prec);
338 lin_solver.SetOperator(*Mop);
339#ifdef MFEM_USE_SINGLE
340 const real_t rtol = 1e-4;
341#else
342 const real_t rtol = 1e-8;
343#endif
344 lin_solver.SetRelTol(rtol); lin_solver.SetAbsTol(0.0);
345 lin_solver.SetMaxIter(100);
346 lin_solver.SetPrintLevel(0);
347 lin_solver.Mult(RHS, X);
348 K.ParFESpace()->GetProlongationMatrix()->Mult(X, di_dt);
349 delete prec;
350}
351#endif
352
353#ifdef MFEM_USE_GSLIB
355 const Vector &init_field)
356{
357 nodes0 = init_nodes;
358 Mesh *m = mesh;
360#ifdef MFEM_USE_MPI
361 if (pmesh) { m = pmesh; }
362 if (pfes) { f = pfes; }
363#endif
364 m->SetNodes(nodes0);
365
366 if (m->GetNodes()->FESpace()->IsDGSpace())
367 {
368 MFEM_ABORT("InterpolatorFP is not supported for periodic meshes yet.");
369 }
370
371 const real_t rel_bbox_el = 0.1;
372 const real_t newton_tol = 1.0e-12;
373 const int npts_at_once = 256;
374
375 if (finder)
376 {
377 finder->FreeData();
378 delete finder;
379 }
380
381#ifdef MFEM_USE_MPI
382 if (pfes) { finder = new FindPointsGSLIB(pfes->GetComm()); }
383 else { finder = new FindPointsGSLIB(); }
384#else
385 finder = new FindPointsGSLIB();
386#endif
387 finder->Setup(*m, rel_bbox_el, newton_tol, npts_at_once);
388
389 field0_gf.SetSpace(f);
390 field0_gf = init_field;
391}
392
394 Vector &new_field, int nodes_ordering)
395{
396 // TODO - this is here only to prevent breaking user codes. To be removed.
397 // If the meshes are different, one has to call SetNewFieldFESpace().
398 // If only some positions are interpolated, use ComputeAtGivenPositions().
399 if (fes_new_field == nullptr && new_mesh_nodes.Size() != nodes0.Size())
400 {
401 MFEM_WARNING("Deprecated -- use ComputeAtGivenPositions() instead!");
402 ComputeAtGivenPositions(new_mesh_nodes, new_field, nodes_ordering);
403 return;
404 }
405
406 const FiniteElementSpace *fes_field =
407 (fes_new_field) ? fes_new_field : field0_gf.FESpace();
408 const int dim = fes_field->GetMesh()->Dimension();
409
410 if (new_mesh_nodes.Size() / dim != fes_field->GetNDofs())
411 {
412 // The nodes of the FE space don't coincide with the mesh nodes.
413 Vector mapped_nodes;
414 fes_field->GetNodePositions(new_mesh_nodes, mapped_nodes);
415 finder->Interpolate(mapped_nodes, field0_gf, new_field);
416 }
417 else
418 {
419 finder->Interpolate(new_mesh_nodes, field0_gf, new_field, nodes_ordering);
420 }
421}
422
424 Vector &values, int p_ordering)
425{
426 finder->Interpolate(positions, field0_gf, values, p_ordering);
427}
428
429#endif
430
432 const Vector &b) const
433{
434 const FiniteElementSpace *fes = NULL;
435 real_t energy_in = 0.0;
436#ifdef MFEM_USE_MPI
437 const ParNonlinearForm *p_nlf = dynamic_cast<const ParNonlinearForm *>(oper);
438 MFEM_VERIFY(!(parallel && p_nlf == NULL), "Invalid Operator subclass.");
439 if (parallel)
440 {
441 fes = p_nlf->FESpace();
442 energy_in = p_nlf->GetEnergy(d_in);
443 }
444#endif
445 const bool serial = !parallel;
446 const NonlinearForm *nlf = dynamic_cast<const NonlinearForm *>(oper);
447 MFEM_VERIFY(!(serial && nlf == NULL), "Invalid Operator subclass.");
448 if (serial)
449 {
450 fes = nlf->FESpace();
451 energy_in = nlf->GetEnergy(d_in);
452 }
453
454 // Get the local prolongation of the solution vector.
455 Vector d_loc(fes->GetVSize(), (temp_mt == MemoryType::DEFAULT) ?
457 if (serial)
458 {
459 const SparseMatrix *cP = fes->GetConformingProlongation();
460 if (!cP) { d_loc = d_in; }
461 else { cP->Mult(d_in, d_loc); }
462 }
463#ifdef MFEM_USE_MPI
464 else
465 {
466 fes->GetProlongationMatrix()->Mult(d_in, d_loc);
467 }
468#endif
469
470 real_t scale = 1.0;
471 bool fitting = IsSurfaceFittingEnabled();
472 real_t init_fit_avg_err, init_fit_max_err = 0.0;
473 if (fitting && surf_fit_converge_error)
474 {
475 GetSurfaceFittingError(d_loc, init_fit_avg_err, init_fit_max_err);
476 // Check for convergence
477 if (init_fit_max_err < surf_fit_max_err_limit)
478 {
480 {
481 mfem::out << "TMOPNewtonSolver converged "
482 "based on the surface fitting error.\n";
483 }
484 scale = 0.0;
485 return scale;
486 }
487 }
488
490 {
492 {
493 mfem::out << "TMOPNewtonSolver terminated "
494 "based on max number of times surface fitting weight can"
495 "be increased. \n";
496 }
497 scale = 0.0;
498 return scale;
499 }
500
501 // Check if the starting mesh (given by x) is inverted. Note that x hasn't
502 // been modified by the Newton update yet.
503 const real_t min_detT_in =
505 /* */ : ComputeMinDet(d_loc, *fes);
506
507 const bool untangling = (min_detT_in <= 0.0) ? true : false;
508 const real_t untangle_factor = 1.5;
509 if (untangling)
510 {
511 // Needed for the line search below. The untangling metrics see this
512 // reference to detect deteriorations.
513 MFEM_VERIFY(min_det_ptr != NULL, " Initial mesh was valid, but"
514 " intermediate mesh is invalid. Contact TMOP Developers.");
515 MFEM_VERIFY(min_detJ_limit == 0.0,
516 "This setup is not supported. Contact TMOP Developers.");
517 *min_det_ptr = untangle_factor * min_detT_in;
518 }
519
520 const bool have_b = (b.Size() == Height());
521
522 Vector d_out(d_in.Size());
523 bool x_out_ok = false;
524 real_t energy_out = 0.0, min_detT_out;
525 const real_t norm_in = Norm(r);
526 real_t avg_fit_err, max_fit_err = 0.0;
527
528 const real_t detJ_factor = (solver_type == 1) ? 0.25 : 0.5;
530 // TODO:
531 // - Customized line search for worst-quality optimization.
532 // - What is the Newton exit criterion for worst-quality optimization?
533
534 // Perform the line search.
535 for (int i = 0; i < 12; i++)
536 {
537 avg_fit_err = 0.0;
538 max_fit_err = 0.0;
539
540 //
541 // Update the mesh and get the L-vector in x_out_loc.
542 //
543 // Form limited (line-search) displacement d_out = d_in - scale * c,
544 // and the corresponding mesh positions x_out = x_0 + d_out.
545 add(d_in, -scale, c, d_out);
546 if (serial)
547 {
548 const SparseMatrix *cP = fes->GetConformingProlongation();
549 if (!cP) { d_loc = d_out; }
550 else { cP->Mult(d_out, d_loc); }
551 }
552#ifdef MFEM_USE_MPI
553 else { fes->GetProlongationMatrix()->Mult(d_out, d_loc); }
554#endif
555
556 // Check the changes in detJ.
557 min_detT_out =
559 /* */ : ComputeMinDet(d_loc, *fes);
560
561 if (untangling == false && min_detT_out <= min_detJ_limit)
562 {
563 // No untangling, and detJ got negative (or small) -- no good.
565 {
566 mfem::out << "Scale = " << scale << " Neg det(J) found.\n";
567 }
568 scale *= detJ_factor; continue;
569 }
570 if (untangling == true && min_detT_out < *min_det_ptr)
571 {
572 // Untangling, and detJ got even more negative -- no good.
574 {
575 mfem::out << "Scale = " << scale << " Neg det(J) decreased.\n";
576 }
577 scale *= detJ_factor; continue;
578 }
579
580 // Skip the energy and residual checks when we're untangling. The
581 // untangling metrics change their denominators, which can affect the
582 // energy and residual, so their increase/decrease is not relevant.
583 if (untangling) { x_out_ok = true; break; }
584
585 // Update mesh-dependent quantities.
586 ProcessNewState(d_out);
587
588 // Ensure sufficient decrease in fitting error if we are trying to
589 // converge based on error.
590 if (fitting && surf_fit_converge_error)
591 {
592 GetSurfaceFittingError(d_loc, avg_fit_err, max_fit_err);
593 if (max_fit_err >= 1.2*init_fit_max_err)
594 {
596 {
597 mfem::out << "Scale = " << scale << " Surf fit err increased.\n";
598 }
599 scale *= 0.5; continue;
600 }
601 }
602
603 // Check the changes in total energy.
604 if (serial)
605 {
606 energy_out = nlf->GetEnergy(d_out);
607 }
608#ifdef MFEM_USE_MPI
609 else
610 {
611 energy_out = p_nlf->GetEnergy(d_out);
612 }
613#endif
614 if (energy_out > energy_in + 0.2*fabs(energy_in) ||
615 std::isnan(energy_out) != 0)
616 {
618 {
619 mfem::out << "Scale = " << scale << " Increasing energy: "
620 << energy_in << " --> " << energy_out << '\n';
621 }
622 scale *= 0.5; continue;
623 }
624
625 // Check the changes in the Newton residual.
626 oper->Mult(d_out, r);
627 if (have_b) { r -= b; }
628 real_t norm_out = Norm(r);
629
630 if (norm_out > 1.2*norm_in)
631 {
633 {
634 mfem::out << "Scale = " << scale << " Norm increased: "
635 << norm_in << " --> " << norm_out << '\n';
636 }
637 scale *= 0.5; continue;
638 }
639 else { x_out_ok = true; break; }
640 } // end line search
641
642 if (untangling)
643 {
644 // Update the global min detJ. Untangling metrics see this min_det_ptr.
645 if (min_detT_out > 0.0)
646 {
647 *min_det_ptr = 0.0;
650 { mfem::out << "The mesh has been untangled at the used points!\n"; }
651 }
652 else { *min_det_ptr = untangle_factor * min_detT_out; }
653 }
654
657 {
658 if (untangling)
659 {
660 mfem::out << "Min det(T) change: "
661 << min_detT_in << " -> " << min_detT_out
662 << " with " << scale << " scaling.\n";
663 }
664 else
665 {
666 mfem::out << "Energy decrease: "
667 << energy_in << " --> " << energy_out << " or "
668 << (energy_in - energy_out) / energy_in * 100.0
669 << "% with " << scale << " scaling.\n";
670 }
671 }
672
673 if (x_out_ok == false) { scale = 0.0; }
674
675 if (surf_fit_scale_factor > 0.0) { surf_fit_coeff_update = true; }
677
678 return scale;
679}
680
681void TMOPNewtonSolver::Mult(const Vector &b, Vector &x) const
682{
683 // Prolongate x to ldofs.
684 const NonlinearForm *nlf = dynamic_cast<const NonlinearForm *>(oper);
685 auto fes_mesh_nodes = nlf->FESpace()->GetMesh()->GetNodes()->FESpace();
686 const Operator *P = fes_mesh_nodes->GetProlongationMatrix();
687 x_0.SetSpace(fes_mesh_nodes);
688 periodic = fes_mesh_nodes->IsDGSpace();
689 if (P)
690 {
691 MFEM_VERIFY(x.Size() == P->Width(),
692 "The input's size must be the tdof size of the mesh nodes.");
693 P->Mult(x, x_0);
694 }
695 else
696 {
697 MFEM_VERIFY(x.Size() == x_0.Size(),
698 "The input's size must match the size of the mesh nodes.");
699 x_0 = x;
700 }
701
702 // Pass down the initial position to the integrators.
703 const Array<NonlinearFormIntegrator*> &integs = *nlf->GetDNFI();
704 for (int i = 0; i < integs.Size(); i++)
705 {
706 auto ti = dynamic_cast<TMOP_Integrator *>(integs[i]);
707 if (ti) { ti->SetInitialMeshPos(&x_0); }
708 auto co = dynamic_cast<TMOPComboIntegrator *>(integs[i]);
709 if (co) { co->SetInitialMeshPos(&x_0); }
710 }
711
712 // Solve for the displacement, which always starts from zero.
713 Vector dx(height); dx = 0.0;
714 if (solver_type == 0) { NewtonSolver::Mult(b, dx); }
715 else if (solver_type == 1) { LBFGSSolver::Mult(b, dx); }
716 else { MFEM_ABORT("Invalid solver_type"); }
717
718 // Form the final mesh using the computed displacement.
719 if (periodic)
720 {
721 Vector dx_loc(nlf->FESpace()->GetVSize());
722 const Operator *Pd = nlf->FESpace()->GetProlongationMatrix();
723 if (Pd) { Pd->Mult(dx, dx_loc); }
724 else { dx_loc = dx; }
725
726 GetPeriodicPositions(x_0, dx_loc, *fes_mesh_nodes, *nlf->FESpace(), x);
727 }
728 else { x += dx; }
729
730 // Make sure the pointers don't use invalid memory (x_0_loc is gone).
731 for (int i = 0; i < integs.Size(); i++)
732 {
733 auto ti = dynamic_cast<TMOP_Integrator *>(integs[i]);
734 if (ti) { ti->SetInitialMeshPos(nullptr); }
735 auto co = dynamic_cast<TMOPComboIntegrator *>(integs[i]);
736 if (co) { co->SetInitialMeshPos(nullptr); }
737 }
738}
739
741{
742 const NonlinearForm *nlf = dynamic_cast<const NonlinearForm *>(oper);
743 const Array<NonlinearFormIntegrator*> &integs = *nlf->GetDNFI();
744 TMOP_Integrator *ti = NULL;
745 TMOPComboIntegrator *co = NULL;
746 for (int i = 0; i < integs.Size(); i++)
747 {
748 ti = dynamic_cast<TMOP_Integrator *>(integs[i]);
749 if (ti)
750 {
751 ti->UpdateSurfaceFittingWeight(factor);
752 }
753 co = dynamic_cast<TMOPComboIntegrator *>(integs[i]);
754 if (co)
755 {
757 for (int j = 0; j < ati.Size(); j++)
758 {
759 ati[j]->UpdateSurfaceFittingWeight(factor);
760 }
761 }
762 }
763}
764
766{
767 const NonlinearForm *nlf = dynamic_cast<const NonlinearForm *>(oper);
768 const Array<NonlinearFormIntegrator*> &integs = *nlf->GetDNFI();
769 TMOP_Integrator *ti = NULL;
770 TMOPComboIntegrator *co = NULL;
771 weights.SetSize(0);
773
774 for (int i = 0; i < integs.Size(); i++)
775 {
776 ti = dynamic_cast<TMOP_Integrator *>(integs[i]);
777 if (ti && ti->IsSurfaceFittingEnabled())
778 {
780 weights.Append(weight);
781 }
782 co = dynamic_cast<TMOPComboIntegrator *>(integs[i]);
783 if (co)
784 {
786 for (int j = 0; j < ati.Size(); j++)
787 {
788 if (ati[j]->IsSurfaceFittingEnabled())
789 {
790 weight = ati[j]->GetSurfaceFittingWeight();
791 weights.Append(weight);
792 }
793 }
794 }
795 }
796}
797
799 real_t &err_avg,
800 real_t &err_max) const
801{
802 const NonlinearForm *nlf = dynamic_cast<const NonlinearForm *>(oper);
803 const Array<NonlinearFormIntegrator*> &integs = *nlf->GetDNFI();
804 TMOP_Integrator *ti = NULL;
805 TMOPComboIntegrator *co = NULL;
806
807 err_avg = 0.0;
808 err_max = 0.0;
809 real_t err_avg_loc, err_max_loc;
810 for (int i = 0; i < integs.Size(); i++)
811 {
812 ti = dynamic_cast<TMOP_Integrator *>(integs[i]);
813 if (ti)
814 {
815 if (ti->IsSurfaceFittingEnabled())
816 {
817 ti->GetSurfaceFittingErrors(d_loc, err_avg_loc, err_max_loc);
818 err_avg = std::max(err_avg_loc, err_avg);
819 err_max = std::max(err_max_loc, err_max);
820 }
821 }
822 co = dynamic_cast<TMOPComboIntegrator *>(integs[i]);
823 if (co)
824 {
826 for (int j = 0; j < ati.Size(); j++)
827 {
828 if (ati[j]->IsSurfaceFittingEnabled())
829 {
830 ati[j]->GetSurfaceFittingErrors(d_loc, err_avg_loc, err_max_loc);
831 err_avg = std::max(err_avg_loc, err_avg);
832 err_max = std::max(err_max_loc, err_max);
833 }
834 }
835 }
836 }
837}
838
840{
841 const NonlinearForm *nlf = dynamic_cast<const NonlinearForm *>(oper);
842 const Array<NonlinearFormIntegrator*> &integs = *nlf->GetDNFI();
843 TMOP_Integrator *ti = NULL;
844 TMOPComboIntegrator *co = NULL;
845
846 for (int i = 0; i < integs.Size(); i++)
847 {
848 ti = dynamic_cast<TMOP_Integrator *>(integs[i]);
849 if (ti)
850 {
851 if (ti->IsSurfaceFittingEnabled())
852 {
853 return true;
854 }
855 }
856 co = dynamic_cast<TMOPComboIntegrator *>(integs[i]);
857 if (co)
858 {
860 for (int j = 0; j < ati.Size(); j++)
861 {
862 if (ati[j]->IsSurfaceFittingEnabled())
863 {
864 return true;
865 }
866 }
867 }
868 }
869 return false;
870}
871
873{
874 const NonlinearForm *nlf = dynamic_cast<const NonlinearForm *>(oper);
875 const Array<NonlinearFormIntegrator*> &integs = *nlf->GetDNFI();
876
877 // Reset the update flags of all TargetConstructors. This is done to avoid
878 // repeated updates of shared TargetConstructors.
879 TMOP_Integrator *ti = NULL;
880 TMOPComboIntegrator *co = NULL;
881 DiscreteAdaptTC *dtc = NULL;
882 for (int i = 0; i < integs.Size(); i++)
883 {
884 ti = dynamic_cast<TMOP_Integrator *>(integs[i]);
885 if (ti)
886 {
887 dtc = ti->GetDiscreteAdaptTC();
888 if (dtc) { dtc->ResetUpdateFlags(); }
889 }
890 co = dynamic_cast<TMOPComboIntegrator *>(integs[i]);
891 if (co)
892 {
894 for (int j = 0; j < ati.Size(); j++)
895 {
896 dtc = ati[j]->GetDiscreteAdaptTC();
897 if (dtc) { dtc->ResetUpdateFlags(); }
898 }
899 }
900 }
901
902 Vector dx_loc;
903 const Operator *P = nlf->GetProlongation();
904 if (P)
905 {
906 dx_loc.SetSize(P->Height());
907 P->Mult(dx, dx_loc);
908 }
909 else { dx_loc = dx; }
910
911 const FiniteElementSpace *dx_fes = nlf->FESpace();
912 for (int i = 0; i < integs.Size(); i++)
913 {
914 ti = dynamic_cast<TMOP_Integrator *>(integs[i]);
915 if (ti)
916 {
917 ti->UpdateAfterMeshPositionChange(dx_loc, *dx_fes);
919 {
920 ti->ComputeUntangleMetricQuantiles(dx_loc, *dx_fes);
921 }
922 }
923 co = dynamic_cast<TMOPComboIntegrator *>(integs[i]);
924 if (co)
925 {
927 for (int j = 0; j < ati.Size(); j++)
928 {
929 ati[j]->UpdateAfterMeshPositionChange(dx_loc, *dx_fes);
931 {
932 ati[j]->ComputeUntangleMetricQuantiles(dx_loc, *dx_fes);
933 }
934 }
935 }
936 }
937
938 // Constant coefficient associated with the surface fitting terms if
939 // adaptive surface fitting is enabled. The idea is to increase the
940 // coefficient if the surface fitting error does not sufficiently
941 // decrease between subsequent TMOPNewtonSolver iterations.
943 {
944 // Get surface fitting errors.
946 // Get array with surface fitting weights.
947 Array<real_t> fitweights;
948 GetSurfaceFittingWeight(fitweights);
949
951 {
952 mfem::out << "Avg/Max surface fitting error: " <<
953 surf_fit_avg_err << " " <<
954 surf_fit_max_err << "\n";
955 mfem::out << "Min/Max surface fitting weight: " <<
956 fitweights.Min() << " " << fitweights.Max() << "\n";
957 }
958
959 real_t change_surf_fit_err = surf_fit_avg_err_prvs-surf_fit_avg_err;
960 real_t rel_change_surf_fit_err = change_surf_fit_err/surf_fit_avg_err_prvs;
961
962 // Increase the surface fitting coefficient if the surface fitting error
963 // does not decrease sufficiently. If we are converging based on residual,
964 // also make sure we have not reached the maximum fitting weight and
965 // error threshold.
966 if (rel_change_surf_fit_err < surf_fit_err_rel_change_limit &&
968 (fitweights.Max() < surf_fit_weight_limit &&
970 {
971 real_t scale_factor = std::min(surf_fit_scale_factor,
972 surf_fit_weight_limit/fitweights.Max());
973 UpdateSurfaceFittingWeight(scale_factor);
975 }
976 else
977 {
979 }
981 surf_fit_coeff_update = false;
982 }
983}
984
986 Mesh &mesh, int ref_factor, int max_recursion_depth)
987{
988#ifdef MFEM_USE_MPI
989 if (ParMesh *pmesh = dynamic_cast<ParMesh *>(&mesh))
990 {
991 det_gf = pmesh->GetJacobianDeterminantGF();
992 }
993 else
994#endif
995 {
997 }
998
999 // setup the PLBound object for estimating the minima.
1000 // note: this must be updated if the mesh is p-refined.
1001 int max_order = det_gf->FESpace()->GetMaxElementOrder();
1002 det_plb = std::make_unique<PLBound>(det_gf->FESpace(),
1003 ref_factor*(max_order+1));
1004 plb_rec_depth = max_recursion_depth;
1005 detJpr_pos_bound = true;
1006}
1007
1009{
1010 if (!det_gf) { return; }
1011
1012 det_gf->FESpace()->Update();
1013 det_gf->Update();
1014}
1015
1017 const FiniteElementSpace &fes) const
1018{
1019 real_t min_detJ = infinity();
1020 const int NE = fes.GetNE(), dim = fes.GetMesh()->Dimension();
1021 Array<int> xdofs;
1022 DenseMatrix Jpr(dim);
1023 const bool mixed_mesh = fes.GetMesh()->GetNumGeometries(dim) > 1;
1024 if (dim == 1 || mixed_mesh ||
1025 UsesTensorBasis(fes) == false || fes.IsVariableOrder())
1026 {
1027 for (int i = 0; i < NE; i++)
1028 {
1029 const int dof = fes.GetFE(i)->GetDof();
1030 DenseMatrix dshape(dof, dim), pos(dof, dim);
1031 Vector posV(pos.Data(), dof * dim);
1032
1033 x_0.GetElementDofValues(i, posV);
1034 if (periodic)
1035 {
1036 auto n_el = dynamic_cast<const NodalFiniteElement *>(fes.GetFE(i));
1037 n_el->ReorderLexToNative(dim, posV);
1038 }
1039
1040 Vector d_loc_el;
1041 fes.GetElementVDofs(i, xdofs);
1042 d_loc.GetSubVector(xdofs, d_loc_el);
1043 posV += d_loc_el;
1044
1045 const IntegrationRule &irule = GetIntegrationRule(*fes.GetFE(i));
1046 const int nsp = irule.GetNPoints();
1047 for (int j = 0; j < nsp; j++)
1048 {
1049 fes.GetFE(i)->CalcDShape(irule.IntPoint(j), dshape);
1050 MultAtB(pos, dshape, Jpr);
1051 min_detJ = std::min(min_detJ, Jpr.Det());
1052 }
1053 }
1054 }
1055 else
1056 {
1057 min_detJ = dim == 2 ? MinDetJpr_2D(&fes, d_loc) :
1058 dim == 3 ? MinDetJpr_3D(&fes, d_loc) : 0.0;
1059 }
1060#ifdef MFEM_USE_MPI
1061 if (parallel)
1062 {
1063 auto p_nlf = dynamic_cast<const ParNonlinearForm *>(oper);
1064 MPI_Allreduce(MPI_IN_PLACE, &min_detJ, 1, MPITypeMap<real_t>::mpi_type,
1065 MPI_MIN, p_nlf->ParFESpace()->GetComm());
1066 }
1067#endif
1068 const DenseMatrix &Wideal =
1070 min_detJ /= Wideal.Det();
1071
1072 return min_detJ;
1073}
1074
1076 const FiniteElementSpace &fes) const
1077{
1078 MFEM_VERIFY(det_gf != nullptr && det_plb != nullptr,
1079 "Determinant bounding has not been setup.");
1080 FiniteElementSpace *det_fes = det_gf->FESpace();
1081 MFEM_VERIFY(!det_fes->IsVariableOrder() && UsesTensorBasis(*det_fes),
1082 "Determinant lower bounds require a fixed-order tensor-product "
1083 "determinant space.");
1084 Array<int> dofs, xdofs;
1085 DenseMatrix dshape, Jpr, pos;
1086 Vector d_loc_el, detvals;
1087
1088 for (int e = 0; e < fes.GetNE(); e++)
1089 {
1090 const FiniteElement *fe = fes.GetFE(e);
1091 const int dof = fe->GetDof(), dim = fe->GetDim();
1092 dshape.SetSize(dof, dim);
1093 Jpr.SetSize(dim);
1094 pos.SetSize(dof, dim);
1095 Vector posV(pos.Data(), dof * dim);
1096
1097 x_0.GetElementDofValues(e, posV);
1098 if (periodic)
1099 {
1100 auto n_el = dynamic_cast<const NodalFiniteElement *>(fe);
1101 n_el->ReorderLexToNative(dim, posV);
1102 }
1103
1104 fes.GetElementVDofs(e, xdofs);
1105 d_loc.GetSubVector(xdofs, d_loc_el);
1106 posV += d_loc_el;
1107
1108 const IntegrationRule &irule = det_fes->GetFE(e)->GetNodes();
1109 const int nsp = irule.GetNPoints();
1110 detvals.SetSize(nsp);
1111 det_fes->GetElementDofs(e, dofs);
1112 for (int q = 0; q < nsp; q++)
1113 {
1114 fe->CalcDShape(irule.IntPoint(q), dshape);
1115 MultAtB(pos, dshape, Jpr);
1116 detvals(q) = Jpr.Det();
1117 }
1118 det_gf->SetSubVector(dofs, detvals);
1119 }
1120
1121 auto minbounds = det_gf->EstimateFunctionMinimum(0, *det_plb,
1122 plb_rec_depth, 1e-5);
1123
1124 const DenseMatrix &Wideal =
1126 return minbounds.first/Wideal.Det();
1127}
1128
1129#ifdef MFEM_USE_MPI
1130// Metric values are visualized by creating an L2 finite element functions and
1131// computing the metric values at the nodes.
1133 const TargetConstructor &tc, ParMesh &pmesh,
1134 char *title, int position)
1135{
1137 ParFiniteElementSpace fes(&pmesh, &fec, 1);
1138 ParGridFunction metric(&fes);
1139 InterpolateTMOP_QualityMetric(qm, tc, pmesh, metric);
1140 socketstream sock;
1141 if (pmesh.GetMyRank() == 0)
1142 {
1143 sock.open("localhost", 19916);
1144 sock << "solution\n";
1145 }
1146 pmesh.PrintAsOne(sock);
1147 metric.SaveAsOne(sock);
1148 if (pmesh.GetMyRank() == 0)
1149 {
1150 sock << "window_title '"<< title << "'\n"
1151 << "window_geometry "
1152 << position << " " << 0 << " " << 600 << " " << 600 << "\n"
1153 << "keys jRmclA\n";
1154 }
1155}
1156#endif
1157
1158// Metric values are visualized by creating an L2 finite element functions and
1159// computing the metric values at the nodes.
1161 const TargetConstructor &tc, Mesh &mesh,
1162 char *title, int position)
1163{
1165 FiniteElementSpace fes(&mesh, &fec, 1);
1166 GridFunction metric(&fes);
1167 InterpolateTMOP_QualityMetric(qm, tc, mesh, metric);
1168 osockstream sock(19916, "localhost");
1169 sock << "solution\n";
1170 mesh.Print(sock);
1171 metric.Save(sock);
1172 sock.send();
1173 sock << "window_title '"<< title << "'\n"
1174 << "window_geometry "
1175 << position << " " << 0 << " " << 600 << " " << 600 << "\n"
1176 << "keys jRmclA\n";
1177}
1178
1179void GetPeriodicPositions(const Vector &x_0, const Vector &dx,
1180 const FiniteElementSpace &fesL2,
1181 const FiniteElementSpace &fesH1, Vector &x)
1182{
1183 x = x_0;
1184 Vector dx_r(x.Size());
1186 auto R_H1 = fesH1.GetElementRestriction(ord);
1187 auto R_L2 = fesL2.GetElementRestriction(ord);
1188 R_H1->Mult(dx, dx_r);
1189 R_L2->AddMultTranspose(dx_r, x);
1190}
1191
1192}
FiniteElementSpace * fes
Definition tmop.hpp:1514
ParFiniteElementSpace * pfes
Definition tmop.hpp:1519
void SetInitialField(const Vector &init_nodes, const Vector &init_field) override
void ComputeAtNewPosition(const Vector &new_mesh_nodes, Vector &new_field, int nodes_ordering=Ordering::byNODES) override
T Max() const
Find the maximal element in the array, using the comparison operator < for class T.
Definition array.cpp:69
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
Definition array.hpp:869
T Min() const
Find the minimal element in the array, using the comparison operator < for class T.
Definition array.cpp:86
int Size() const
Return the logical size of the array.
Definition array.hpp:192
int Append(const T &el)
Append element 'el' to array, resize if necessary.
Definition array.hpp:941
@ GaussLobatto
Closed type.
Definition fe_base.hpp:36
void SetAssemblyLevel(AssemblyLevel assembly_level)
Set the desired assembly level.
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....
FiniteElementSpace * FESpace()
Return the FE space associated with the BilinearForm.
void Assemble(int skip_zeros=1)
Assembles the form i.e. sums over all domain/bdr integrators.
void RecoverFEMSolution(const Vector &X, const Vector &b, Vector &x) override
Recover the solution of a linear system formed with FormLinearSystem().
virtual void FormLinearSystem(const Array< int > &ess_tdof_list, Vector &x, Vector &b, OperatorHandle &A, Vector &X, Vector &B, int copy_interior=0)
Form the linear system A X = B, corresponding to this bilinear form and the linear form b(....
int Size() const
Get the size of the BilinearForm as a square matrix.
void Mult(const Vector &x, Vector &y) const override
Matrix vector multiplication: .
const SparseMatrix & SpMat() const
Returns a const reference to the sparse matrix: .
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
Jacobi-type diagonal smoother of a sparse matrix.
Data type dense matrix using column-major storage.
Definition densemat.hpp:24
real_t * Data() const
Returns the matrix data array. Warning: this method casts away constness.
Definition densemat.hpp:131
void SetSize(int s)
Change the size of the DenseMatrix to s x s.
Definition densemat.hpp:125
real_t Det() const
Definition densemat.cpp:496
static MemoryType GetDeviceMemoryType()
Get the current Device MemoryType. This is the MemoryType used by most MFEM classes when allocating m...
Definition device.hpp:298
void ResetUpdateFlags()
Used in combination with the Update methods to avoid extra computations.
Definition tmop.hpp:1871
FindPointsGSLIB can robustly evaluate a GridFunction on an arbitrary collection of points....
Definition gslib.hpp:115
void Setup(Mesh &m, const double bbox_rel_size_inc=0.1, const double newt_tol=1.0e-12, const int npt_max=256)
Preprocess the internal mesh in gslib.
Definition gslib.cpp:321
virtual void Interpolate(const GridFunction &field_in, Vector &field_out)
Interpolation of field values at prescribed reference space positions.
Definition gslib.cpp:3679
virtual void FreeData()
Cleans up memory allocated internally by gslib.
Definition gslib.cpp:2984
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
Definition fespace.hpp:210
bool IsVariableOrder() const
Returns true if the space contains elements of varying polynomial orders.
Definition fespace.hpp:673
DofTransformation * GetElementDofs(int elem, Array< int > &dofs) const
Returns indices of degrees of freedom of element 'elem'. The returned indices are offsets into an ldo...
Definition fespace.cpp:3538
int GetNDofs() const
Returns number of degrees of freedom. This is the number of Local Degrees of Freedom.
Definition fespace.hpp:821
virtual const Operator * GetProlongationMatrix() const
Definition fespace.hpp:691
void GetNodePositions(const Vector &mesh_nodes, Vector &fes_node_pos, int fes_nodes_ordering=Ordering::byNODES) const
Compute the space's node positions w.r.t. given mesh positions. The function uses FiniteElement::GetN...
Definition fespace.cpp:4368
DofTransformation * GetElementVDofs(int i, Array< int > &vdofs) const
Returns indices of degrees of freedom for the i'th element. The returned indices are offsets into an ...
Definition fespace.cpp:299
virtual const FiniteElement * GetFE(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th element in t...
Definition fespace.cpp:3860
Ordering::Type GetOrdering() const
Return the ordering method.
Definition fespace.hpp:852
int GetNE() const
Returns number of elements in the mesh.
Definition fespace.hpp:867
const ElementRestrictionOperator * GetElementRestriction(ElementDofOrdering e_ordering) const
Return an Operator that converts L-vectors to E-vectors.
Definition fespace.cpp:1476
const SparseMatrix * GetConformingProlongation() const
Definition fespace.cpp:1422
const FiniteElementCollection * FEColl() const
Definition fespace.hpp:854
Mesh * GetMesh() const
Returns the mesh.
Definition fespace.hpp:639
int GetVSize() const
Return the number of vector dofs, i.e. GetNDofs() x GetVDim().
Definition fespace.hpp:824
Abstract class for all finite elements.
Definition fe_base.hpp:294
int GetDim() const
Returns the reference space dimension for the finite element.
Definition fe_base.hpp:381
const IntegrationRule & GetNodes() const
Get a const reference to the nodes of the element.
Definition fe_base.hpp:476
virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const =0
Evaluate the gradients of all shape functions of a scalar finite element in reference space at the gi...
int GetDof() const
Returns the number of degrees of freedom in the finite element.
Definition fe_base.hpp:410
const DenseMatrix & GetGeomToPerfGeomJac(int GeomType) const
Definition geom.hpp:102
Class for grid function - Vector with associated FE space.
Definition gridfunc.hpp:53
virtual void Save(std::ostream &out) const
Save the GridFunction to an output stream.
virtual void GetElementDofValues(int el, Vector &dof_vals) const
FiniteElementSpace * FESpace()
virtual void SetSpace(FiniteElementSpace *f)
Associate a new FiniteElementSpace with the GridFunction.
Definition gridfunc.cpp:227
Parallel smoothers in hypre.
Definition hypre.hpp:1077
Class for an integration rule - an Array of IntegrationPoint.
Definition intrules.hpp:96
int GetNPoints() const
Returns the number of the points in the integration rule.
Definition intrules.hpp:255
IntegrationPoint & IntPoint(int i)
Returns a reference to the i-th integration point.
Definition intrules.hpp:258
void ComputeAtGivenPositions(const Vector &positions, Vector &values, int p_ordering=Ordering::byNODES) override
Direct interpolation of field0_gf at the given positions.
void SetInitialField(const Vector &init_nodes, const Vector &init_field) override
void ComputeAtNewPosition(const Vector &new_mesh_nodes, Vector &new_field, int nodes_ordering=Ordering::byNODES) override
PrintLevel print_options
Output behavior for the iterative solver.
Definition solvers.hpp:163
const Operator * oper
Definition solvers.hpp:145
void SetRelTol(real_t rtol)
Definition solvers.hpp:238
virtual void SetPreconditioner(Solver &pr)
This should be called before SetOperator.
Definition solvers.cpp:178
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
void SetAbsTol(real_t atol)
Definition solvers.hpp:239
real_t Norm(const Vector &x) const
Return the inner product norm of x, using the inner product defined by Dot()
Definition solvers.hpp:206
Arbitrary order "L2-conforming" discontinuous finite elements.
Definition fe_coll.hpp:369
void Mult(const Vector &b, Vector &x) const override
Solve the nonlinear system with right-hand side b.
Definition solvers.cpp:2253
Mesh data type.
Definition mesh.hpp:67
void NodesUpdated()
This function should be called after the mesh node coordinates have been updated externally,...
Definition mesh.hpp:2342
Geometry::Type GetTypicalElementGeometry() const
If the local mesh is not empty, return GetElementGeometry(0); otherwise, return a typical Geometry pr...
Definition mesh.cpp:1705
std::unique_ptr< GridFunction > GetJacobianDeterminantGF() const
Create a GridFunction representing the Jacobian determinant.
Definition mesh.cpp:7285
virtual void Print(std::ostream &os=mfem::out, const std::string &comments="") const
Print the mesh to the given stream using the default MFEM mesh format.
Definition mesh.hpp:2610
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
real_t GetElementSize(int i, int type=0)
Get the size of the i-th element relative to the perfect reference element.
Definition mesh.cpp:111
void GetNodes(Vector &node_coord) const
Definition mesh.cpp:10112
void SetNodes(const Vector &node_coord)
Updates the vertex/node locations. Invokes NodesUpdated().
Definition mesh.cpp:10124
int GetNumGeometries(int dim) const
Return the number of geometries of the given dimension present in the mesh.
Definition mesh.cpp:8014
void Mult(const Vector &b, Vector &x) const override
Solve the nonlinear system with right-hand side b.
Definition solvers.cpp:2062
Class for standard nodal finite elements.
Definition fe_base.hpp:798
void ReorderLexToNative(int ncomp, Vector &dofs) const
Definition fe_base.cpp:996
void SetPAMemoryType(MemoryType mt)
FiniteElementSpace * FESpace()
virtual real_t GetEnergy(const Vector &x) const
Compute the energy corresponding to the state x.
const Operator * GetProlongation() const override
Get the finite element space prolongation matrix.
Array< NonlinearFormIntegrator * > * GetDNFI()
Access all integrators added with AddDomainIntegrator().
Pointer to an Operator of a specified type.
Definition handle.hpp:34
void Reset(OpType *A, bool own_A=true)
Reset the OperatorHandle to the given OpType pointer, A.
Definition handle.hpp:145
Jacobi smoothing for a given bilinear form (no matrix necessary).
Definition solvers.hpp:422
Abstract operator.
Definition operator.hpp:27
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
Definition operator.hpp:68
int height
Dimension of the output / number of rows in the matrix.
Definition operator.hpp:29
virtual void Mult(const Vector &x, Vector &y) const =0
Operator application: y=A(x).
int Width() const
Get the width (size of input) of the Operator. Synonym with NumCols().
Definition operator.hpp:74
Performs a single remap advection step in parallel.
ParAdvectorCGOper(const Vector &x_start, GridFunction &vel, ParFiniteElementSpace &pfes, AssemblyLevel al=AssemblyLevel::LEGACY, MemoryType mt=MemoryType::DEFAULT)
VectorGridFunctionCoefficient u_coeff
void Mult(const Vector &ind, Vector &di_dt) const override
Operator application: y=A(x).
const AssemblyLevel al
HypreParMatrix * ParallelAssemble()
Returns the matrix assembled on the true dofs, i.e. P^t A P.
void Assemble(int skip_zeros=1)
Assemble the local matrix.
void FormSystemMatrix(const Array< int > &ess_tdof_list, OperatorHandle &A) override
Form the linear system matrix A, see FormLinearSystem() for details.
ParFiniteElementSpace * ParFESpace() const
Return the parallel FE space associated with the ParBilinearForm.
Abstract parallel finite element space.
Definition pfespace.hpp:31
MPI_Comm GetComm() const
Definition pfespace.hpp:337
int GetTrueVSize() const override
Return the number of local vector true dofs.
Definition pfespace.hpp:365
const Operator * GetProlongationMatrix() const override
ParMesh * GetParMesh() const
Definition pfespace.hpp:341
Class for parallel grid function.
Definition pgridfunc.hpp:50
void ParallelAssemble(Vector &tv) const
Returns the vector assembled on the true dofs.
void SaveAsOne(const char *fname, int precision=16) const
Class for parallel meshes.
Definition pmesh.hpp:35
MPI_Comm GetComm() const
Definition pmesh.hpp:403
int GetMyRank() const
Definition pmesh.hpp:405
void PrintAsOne(std::ostream &out=mfem::out, const std::string &comments="") const
Write the mesh to the stream 'out' on Process 0 in a form suitable for visualization.
Definition pmesh.cpp:5131
Parallel non-linear operator on the true dofs.
real_t GetEnergy(const ParGridFunction &x) const
Compute the energy of a ParGridFunction.
void Init(TimeDependentOperator &f_) override
Associate a TimeDependentOperator with the ODE solver.
Definition ode.cpp:287
void Step(Vector &x, real_t &t, real_t &dt) override
Perform a time step from time t [in] to time t [out] based on the requested step size dt [in].
Definition ode.cpp:296
Performs a single remap advection step in serial.
VectorGridFunctionCoefficient u_coeff
SerialAdvectorCGOper(const Vector &x_start, GridFunction &vel, FiniteElementSpace &fes, AssemblyLevel al=AssemblyLevel::LEGACY)
const AssemblyLevel al
void Mult(const Vector &ind, Vector &di_dt) const override
Operator application: y=A(x).
Base class for solvers.
Definition operator.hpp:855
Data type sparse matrix.
Definition sparsemat.hpp:51
void Mult(const Vector &x, Vector &y) const override
Matrix vector multiplication.
void SetInitialMeshPos(const GridFunction *x0)
Definition tmop.hpp:2617
const Array< TMOP_Integrator * > & GetTMOPIntegrators() const
Definition tmop.hpp:2634
real_t ComputeScalingFactor(const Vector &d, const Vector &b) const override
virtual void GetSurfaceFittingError(const Vector &d_loc, real_t &err_avg, real_t &err_max) const
std::unique_ptr< GridFunction > det_gf
void Mult(const Vector &b, Vector &x) const override
Optimizes the mesh positions given by x.
bool IsSurfaceFittingEnabled() const
Check if surface fitting is enabled.
void EnsurePositiveDeterminantBound(Mesh &mesh, int ref_factor, int max_recursion_depth=0)
Ensure a positive lower bound for the Jacobian determinant in tensor-product elements during line-sea...
real_t MinDetJpr_3D(const FiniteElementSpace *, const Vector &) const
std::unique_ptr< PLBound > det_plb
const IntegrationRule & GetIntegrationRule(const FiniteElement &el) const
void UpdateDeterminantBoundGridFunction()
Update internal determinant GridFunction after a mesh topology change.
void UpdateSurfaceFittingWeight(real_t factor) const
Update surface fitting weight as surf_fit_weight *= factor.
real_t MinDetJpr_2D(const FiniteElementSpace *, const Vector &) const
void ProcessNewState(const Vector &dx) const override
real_t ComputeMinDet(const Vector &d_loc, const FiniteElementSpace &fes) const
real_t ComputeDetJptLowerBound(const Vector &d_loc, const FiniteElementSpace &fes) const
void GetSurfaceFittingWeight(Array< real_t > &weights) const
Get the surface fitting weight for all the TMOP integrators.
A TMOP integrator class based on any given TMOP_QualityMetric and TargetConstructor.
Definition tmop.hpp:1995
void UpdateAfterMeshPositionChange(const Vector &d, const FiniteElementSpace &d_fes)
Definition tmop.cpp:5803
void GetSurfaceFittingErrors(const Vector &d_loc, real_t &err_avg, real_t &err_max)
Definition tmop.cpp:4168
void ComputeUntangleMetricQuantiles(const Vector &d, const FiniteElementSpace &fes)
Definition tmop.cpp:6069
real_t GetSurfaceFittingWeight()
Get the surface fitting weight.
Definition tmop.cpp:5508
void SetInitialMeshPos(const GridFunction *x0)
Definition tmop.cpp:3741
bool IsSurfaceFittingEnabled()
Definition tmop.hpp:2506
DiscreteAdaptTC * GetDiscreteAdaptTC() const
Definition tmop.hpp:2569
void UpdateSurfaceFittingWeight(real_t factor)
Update the surface fitting weight as surf_fit_coeff *= factor;.
Definition tmop.cpp:5496
Abstract class for local mesh quality metrics in the target-matrix optimization paradigm (TMOP) by P....
Definition tmop.hpp:28
Base class representing target-matrix construction algorithms for mesh optimization via the target-ma...
Definition tmop.hpp:1586
Base abstract class for first order time dependent operators.
Definition operator.hpp:367
real_t t
Current time.
Definition operator.hpp:417
virtual real_t GetTime() const
Read the currently set time.
Definition operator.hpp:439
Vector data type.
Definition vector.hpp:82
real_t Max() const
Returns the maximal element of the vector.
Definition vector.cpp:1200
int Size() const
Returns the size of the vector.
Definition vector.hpp:234
virtual void UseDevice(bool use_dev) const
Enable execution of Vector operations using the mfem::Device.
Definition vector.hpp:145
void SetSize(int s)
Resize the vector to size s.
Definition vector.hpp:633
virtual real_t * HostReadWrite()
Shortcut for mfem::ReadWrite(vec.GetMemory(), vec.Size(), false).
Definition vector.hpp:540
real_t Min() const
Returns the minimal element of the vector.
Definition vector.cpp:1154
void GetSubVector(const Array< int > &dofs, Vector &elemvect) const
Extract entries listed in dofs to the output Vector elemvect.
Definition vector.cpp:676
void MakeRef(Vector &base, int offset, int size)
Reset the Vector to be a reference to a sub-vector of base.
Definition vector.hpp:709
int open(const char hostname[], int port)
Open the socket stream on 'port' at 'hostname'.
const int * ess_tdof_list
int dim
Definition ex24.cpp:53
Mesh * GetMesh(int type)
Definition ex29.cpp:218
real_t b
Definition lissajous.cpp:42
real_t weight(const Vector &x)
string space
mfem::real_t real_t
real_t u(const Vector &xvec)
Definition lor_mms.hpp:22
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
Geometry Geometries
Definition fe.cpp:49
void add(const Vector &v1, const Vector &v2, Vector &v)
Definition vector.cpp:414
AssemblyLevel
Enumeration defining the assembly level for bilinear and nonlinear form classes derived from Operator...
void vis_tmop_metric_s(int order, TMOP_QualityMetric &qm, const TargetConstructor &tc, Mesh &mesh, char *title, int position)
void InterpolateTMOP_QualityMetric(TMOP_QualityMetric &metric, const TargetConstructor &tc, const Mesh &mesh, GridFunction &metric_gf)
Interpolates the metric's values at the nodes of metric_gf.
Definition tmop.cpp:6341
void PCG(const Operator &A, Solver &B, const Vector &b, Vector &x, int print_iter, int max_num_iter, real_t RTOLERANCE, real_t ATOLERANCE)
Preconditioned conjugate gradient method. (tolerances are squared)
Definition solvers.cpp:1067
void vis_tmop_metric_p(int order, TMOP_QualityMetric &qm, const TargetConstructor &tc, ParMesh &pmesh, char *title, int position)
void GetPeriodicPositions(const Vector &x_0, const Vector &dx, const FiniteElementSpace &fesL2, const FiniteElementSpace &fesH1, Vector &x)
bool UsesTensorBasis(const FiniteElementSpace &fes)
Return true if the mesh contains only one topology and the elements are tensor elements.
Definition fespace.hpp:1644
void subtract(const Vector &x, const Vector &y, Vector &z)
Definition vector.cpp:570
ComplexDenseMatrix * MultAtB(const ComplexDenseMatrix &A, const ComplexDenseMatrix &B)
Multiply the complex conjugate transpose of a matrix A with a matrix B. A^H*B.
float real_t
Definition config.hpp:46
MemoryType
Memory types supported by MFEM.
ElementDofOrdering
Constants describing the possible orderings of the DOFs in one element.
Definition fespace.hpp:49
std::function< real_t(const Vector &)> f(real_t mass_coeff)
Definition lor_mms.hpp:30
constexpr real_t infinity()
Define a shortcut for std::numeric_limits<double>::infinity()
Definition vector.hpp:47
void vel(const Vector &x, real_t t, Vector &u)
bool iterations
Detailed information about each iteration will be reported to mfem::out.
Definition solvers.hpp:112
bool warnings
If a non-fatal problem has been detected some context-specific information will be reported to mfem::...
Definition solvers.hpp:109
bool first_and_last
Information about the first and last iteration will be printed to mfem::out.
Definition solvers.hpp:118
bool summary
A summary of the solver process will be reported after the last iteration to mfem::out.
Definition solvers.hpp:115
Helper struct to convert a C++ type to an MPI type.