Reduced Lagrange Multipliers
 
Loading...
Searching...
No Matches
reduced_poisson.cc
Go to the documentation of this file.
1// ---------------------------------------------------------------------
2//
3// Copyright (C) 2024 by Luca Heltai
4//
5// This file is part of the reduced_lagrange_multipliers application, based on
6// the deal.II library.
7//
8// The reduced_lagrange_multipliers application is free software; you can use
9// it, redistribute it, and/or modify it under the terms of the Apache-2.0
10// License WITH LLVM-exception as published by the Free Software Foundation;
11// either version 3.0 of the License, or (at your option) any later version. The
12// full text of the license can be found in the file LICENSE.md at the top level
13// of the reduced_lagrange_multipliers distribution.
14//
15// ---------------------------------------------------------------------
16
17/* ---------------------------------------------------------------------
18 *
19 * Copyright (C) 2000 - 2020 by the deal.II authors
20 *
21 * This file is part of the deal.II library.
22 *
23 * The deal.II library is free software; you can use it, redistribute
24 * it, and/or modify it under the terms of the GNU Lesser General
25 * Public License as published by the Free Software Foundation; either
26 * version 2.1 of the License, or (at your option) any later version.
27 * The full text of the license can be found in the file LICENSE.md at
28 * the top level directory of deal.II.
29 *
30 * ---------------------------------------------------------------------
31 *
32 */
33
34#include "reduced_poisson.h"
35
36#include <boost/algorithm/string.hpp>
37
38#include <type_traits>
39
41
42
43
44template <int spacedim>
46 : ParameterAcceptor("/Reduced Poisson/")
47 , rhs("/Reduced Poisson/Right hand side")
48 , bc("/Reduced Poisson/Dirichlet boundary conditions")
49 , inner_control("/Reduced Poisson/Solver/Inner control")
50 , outer_control("/Reduced Poisson/Solver/Outer control")
51{
52 add_parameter("FE degree", fe_degree, "", this->prm, Patterns::Integer(1));
53 add_parameter("Output directory", output_directory);
54 add_parameter("Output name", output_name);
55 add_parameter("Output results also before solving",
57 add_parameter("Solver type", solver_name);
58 add_parameter("Assemble full AL system", assemble_full_AL_system);
59 add_parameter("Dirichlet boundary ids", dirichlet_ids);
60 enter_subsection("Grid generation");
61 {
62 add_parameter("Grid generator", name_of_grid);
63 add_parameter("Grid generator arguments", arguments_for_grid);
64 }
66 enter_subsection("Refinement and remeshing");
67 {
68 add_parameter("Strategy",
70 "",
71 this->prm,
72 Patterns::Selection("fixed_fraction|fixed_number|global"));
73 add_parameter("Coarsening fraction", coarsening_fraction);
74 add_parameter("Refinement fraction", refinement_fraction);
75 add_parameter("Maximum number of cells", max_cells);
76 add_parameter("Number of refinement cycles", n_refinement_cycles);
77 }
79
80 this->prm.enter_subsection("Error");
81 convergence_table.add_parameters(this->prm);
82 this->prm.leave_subsection();
83}
84
85
86template <int dim, int spacedim>
89 : par(par)
90 , mpi_communicator(MPI_COMM_WORLD)
91 , pcout(std::cout, (Utilities::MPI::this_mpi_process(mpi_communicator) == 0))
93 pcout,
94 TimerOutput::summary,
95 TimerOutput::wall_times)
97 typename Triangulation<spacedim>::MeshSmoothing(
98 Triangulation<spacedim>::smoothing_on_refinement |
99 Triangulation<spacedim>::smoothing_on_coarsening),
100 parallel::distributed::Triangulation<
101 spacedim>::construct_multigrid_hierarchy)
102 , dh(tria)
103 , reduced_coupling(tria, par.reduced_coupling_parameters)
104 , mapping(1)
105{}
106
107
108template <int dim, int spacedim>
109void
110read_grid_and_cad_files(const std::string &grid_file_name,
111 const std::string &ids_and_cad_file_names,
113{
114 GridIn<dim, spacedim> grid_in;
115 grid_in.attach_triangulation(tria);
116 grid_in.read(grid_file_name);
117#ifdef DEAL_II_WITH_OPENCASCADE
118 using map_type = std::map<types::manifold_id, std::string>;
119 using Converter = Patterns::Tools::Convert<map_type>;
120 for (const auto &pair : Converter::to_value(ids_and_cad_file_names))
121 {
122 const auto &manifold_id = pair.first;
123 const auto &cad_file_name = pair.second;
124 const auto extension = boost::to_lower_copy(
125 cad_file_name.substr(cad_file_name.find_last_of('.') + 1));
126 TopoDS_Shape shape;
127 if (extension == "iges" || extension == "igs")
128 shape = OpenCASCADE::read_IGES(cad_file_name);
129 else if (extension == "step" || extension == "stp")
130 shape = OpenCASCADE::read_STEP(cad_file_name);
131 else
132 AssertThrow(false,
133 ExcNotImplemented("We found an extension that we "
134 "do not recognize as a CAD file "
135 "extension. Bailing out."));
136 const auto n_elements = OpenCASCADE::count_elements(shape);
137 if ((std::get<0>(n_elements) == 0))
138 tria.set_manifold(
139 manifold_id,
141 else if (spacedim == 3)
142 {
143 const auto t = reinterpret_cast<Triangulation<dim, 3> *>(&tria);
144 t->set_manifold(manifold_id,
146 shape));
147 }
148 else
149 tria.set_manifold(manifold_id,
151 TopoDS::Face(shape)));
152 }
153#else
154 (void)ids_and_cad_file_names;
155 AssertThrow(false, ExcNotImplemented("Generation of the grid failed."));
156#endif
157}
158
159
160
161template <int dim, int spacedim>
162void
164{
165 try
166 {
168 par.name_of_grid,
169 par.arguments_for_grid);
170 }
171 catch (...)
172 {
173 pcout << "Generating from name and argument failed." << std::endl
174 << "Trying to read from file name." << std::endl;
175 read_grid_and_cad_files(par.name_of_grid, par.arguments_for_grid, tria);
176 }
177}
178
179
180
181template <int dim, int spacedim>
182void
184{
185 TimerOutput::Scope t(computing_timer, "Initial setup");
186 fe = std::make_unique<FESystem<spacedim>>(FE_Q<spacedim>(par.fe_degree), 1);
187 quadrature = std::make_unique<QGauss<spacedim>>(par.fe_degree + 1);
188}
189
190
191template <int dim, int spacedim>
192void
194{
195 TimerOutput::Scope t(computing_timer, "Setup dofs");
196
197 reduced_coupling.initialize(mapping);
198
199 dh.distribute_dofs(*fe);
200#ifdef MATRIX_FREE_PATH
201 dh.distribute_mg_dofs();
202#endif
203
204 owned_dofs.resize(2);
205 owned_dofs[0] = dh.locally_owned_dofs();
206 relevant_dofs.resize(2);
208 {
209 constraints.reinit(owned_dofs[0], relevant_dofs[0]);
211 for (const auto id : par.dirichlet_ids)
213 constraints.close();
214 }
215 {
216#ifdef MATRIX_FREE_PATH
217 typename MatrixFree<spacedim, double>::AdditionalData additional_data;
218 additional_data.tasks_parallel_scheme =
220 additional_data.mapping_update_flags =
222 std::shared_ptr<MatrixFree<spacedim, double>> system_mf_storage(
224 system_mf_storage->reinit(
225 mapping, dh, constraints, QGauss<1>(fe->degree + 1), additional_data);
226 stiffness_matrix.initialize(system_mf_storage);
227
228 // Perform setup for matrix-free multigrid
229 {
230 const unsigned int nlevels = tria.n_global_levels();
231 mg_matrices.resize(0, nlevels - 1);
232
233 const std::set<types::boundary_id> dirichlet_boundary_ids = {0};
234 mg_constrained_dofs.initialize(dh);
235 mg_constrained_dofs.make_zero_boundary_constraints(
236 dh, dirichlet_boundary_ids);
237
238 for (unsigned int level = 0; level < nlevels; ++level)
239 {
240 AffineConstraints<double> level_constraints(
241 dh.locally_owned_mg_dofs(level),
243 for (const types::global_dof_index dof_index :
244 mg_constrained_dofs.get_boundary_indices(level))
245 level_constraints.constrain_dof_to_zero(dof_index);
246 level_constraints.close();
247
249 additional_data_level;
250 additional_data_level.tasks_parallel_scheme =
252 additional_data_level.mapping_update_flags =
254 additional_data_level.mg_level = level;
255 std::shared_ptr<MatrixFree<spacedim, float>> mg_mf_storage_level =
256 std::make_shared<MatrixFree<spacedim, float>>();
257 mg_mf_storage_level->reinit(mapping,
258 dh,
259 level_constraints,
260 QGauss<1>(fe->degree + 1),
261 additional_data_level);
262
263 mg_matrices[level].initialize(mg_mf_storage_level,
264 mg_constrained_dofs,
265 level);
266 }
267 }
268
269
270#else
271 stiffness_matrix.clear();
275 owned_dofs[0],
277 relevant_dofs[0]);
279 owned_dofs[0],
280 dsp,
282
283#endif
284 }
285 const auto &reduced_dh = reduced_coupling.get_dof_handler();
286 owned_dofs[1] = reduced_dh.locally_owned_dofs();
288
289 coupling_matrix.clear();
290
291 DynamicSparsityPattern dsp(dh.n_dofs(),
292 reduced_dh.n_dofs(),
293 relevant_dofs[0]);
294
295 reduced_coupling.assemble_coupling_sparsity(dsp, dh, constraints);
296
298
299 // DynamicSparsityPattern idsp(inclusions.n_dofs(),
300 // inclusions.n_dofs(),
301 // relevant_dofs[1]);
302 // for (const auto i : relevant_dofs[1])
303 // idsp.add(i, i);
304 // SparsityTools::distribute_sparsity_pattern(idsp,
305 // owned_dofs[1],
306 // mpi_communicator,
307 // relevant_dofs[1]);
308 // inclusion_matrix.reinit(owned_dofs[1],
309 // owned_dofs[1],
310 // idsp,
311 // mpi_communicator);
312 // }
313
314 // Commented out inclusions-dependent reinit
316
317#ifdef MATRIX_FREE_PATH
320#else
323#endif
324
325 pcout << " Number of degrees of freedom: " << owned_dofs[0].size() << " + "
326 << owned_dofs[1].size()
327 << " (locally owned: " << owned_dofs[0].n_elements() << " + "
328 << owned_dofs[1].n_elements() << ")" << std::endl;
329}
330
331
332#ifndef MATRIX_FREE_PATH
333template <int dim, int spacedim>
334void
336{
338 coupling_matrix = 0;
339 system_rhs = 0;
340 FEValues<spacedim> fe_values(*fe,
341 *quadrature,
344 const unsigned int dofs_per_cell = fe->n_dofs_per_cell();
345 const unsigned int n_q_points = quadrature->size();
346 FullMatrix<double> cell_matrix(dofs_per_cell, dofs_per_cell);
347 Vector<double> cell_rhs(dofs_per_cell);
348 std::vector<double> rhs_values(n_q_points);
349 std::vector<Tensor<1, spacedim>> grad_phi_u(dofs_per_cell);
350 std::vector<types::global_dof_index> local_dof_indices(dofs_per_cell);
351 const FEValuesExtractors::Scalar scalar(0);
352 for (const auto &cell : dh.active_cell_iterators())
353 if (cell->is_locally_owned())
354 {
355 cell_matrix = 0;
356 cell_rhs = 0;
357 fe_values.reinit(cell);
358 par.rhs.value_list(fe_values.get_quadrature_points(), rhs_values);
359 for (unsigned int q = 0; q < n_q_points; ++q)
360 {
361 for (unsigned int k = 0; k < dofs_per_cell; ++k)
362 grad_phi_u[k] = fe_values[scalar].gradient(k, q);
363 for (unsigned int i = 0; i < dofs_per_cell; ++i)
364 {
365 for (unsigned int j = 0; j < dofs_per_cell; ++j)
366 {
367 cell_matrix(i, j) +=
368 grad_phi_u[i] * grad_phi_u[j] * fe_values.JxW(q);
369 }
370 cell_rhs(i) += fe_values.shape_value(i, q) * rhs_values[q] *
371 fe_values.JxW(q);
372 }
373 }
374 cell->get_dof_indices(local_dof_indices);
375 constraints.distribute_local_to_global(cell_matrix,
376 cell_rhs,
377 local_dof_indices,
379 system_rhs.block(0));
380 }
383}
384#endif
385
386// Commented out inclusions-dependent function
387/*
388template <int dim, int spacedim>
389void
390ReducedPoisson<dim, spacedim>::assemble_coupling()
391{
392 TimerOutput::Scope t(computing_timer, "Assemble Coupling matrix");
393 pcout << "Assemble coupling matrix. " << std::endl;
394
395 std::vector<types::global_dof_index>
396fe_dof_indices(fe->n_dofs_per_cell()); std::vector<types::global_dof_index>
397inclusion_dof_indices( inclusions.get_n_coefficients());
398
399 FullMatrix<double> local_coupling_matrix(fe->n_dofs_per_cell(),
400 inclusions.get_n_coefficients());
401
402 [[maybe_unused]] FullMatrix<double>
403local_bulk_matrix(fe->n_dofs_per_cell(), fe->n_dofs_per_cell());
404
405 FullMatrix<double> local_inclusion_matrix(inclusions.get_n_coefficients(),
406 inclusions.get_n_coefficients());
407
408 Vector<double> local_rhs(inclusions.get_n_coefficients());
409
410 auto particle = inclusions.inclusions_as_particles.begin();
411 while (particle != inclusions.inclusions_as_particles.end())
412 {
413 const auto &cell = particle->get_surrounding_cell();
414 const auto dh_cell =
415 typename DoFHandler<spacedim>::cell_iterator(*cell, &dh);
416 dh_cell->get_dof_indices(fe_dof_indices);
417 const auto pic =
418 inclusions.inclusions_as_particles.particles_in_cell(cell);
419 Assert(pic.begin() == particle, ExcInternalError());
420
421 auto p = pic.begin();
422 auto next_p = pic.begin();
423 while (p != pic.end())
424 {
425 const auto inclusion_id =
426inclusions.get_inclusion_id(p->get_id()); inclusion_dof_indices =
427inclusions.get_dof_indices(p->get_id()); local_coupling_matrix = 0;
428 local_inclusion_matrix = 0;
429 local_rhs = 0;
430
431 // Extract all points that refer to the same inclusion
432 std::vector<Point<spacedim>> ref_q_points;
433 for (; next_p != pic.end() &&
434 inclusions.get_inclusion_id(next_p->get_id()) ==
435inclusion_id;
436 ++next_p)
437 ref_q_points.push_back(next_p->get_reference_location());
438 FEValues<spacedim, spacedim> fev(*fe,
439 ref_q_points,
440 update_values | update_gradients);
441 fev.reinit(dh_cell);
442 for (unsigned int q = 0; q < ref_q_points.size(); ++q)
443 {
444 const auto id = p->get_id();
445 const auto &inclusion_fe_values =
446inclusions.get_fe_values(id); const auto &real_q =
447p->get_location();
448
449 // Coupling and inclusions matrix
450 for (unsigned int j = 0; j < inclusions.get_n_coefficients();
451++j)
452 {
453 for (unsigned int i = 0; i < fe->n_dofs_per_cell(); ++i)
454 local_coupling_matrix(i, j) +=
455 (fev.shape_value(i, q)) * inclusion_fe_values[j];
456 local_rhs(j) +=
457 inclusion_fe_values[j] *
458 inclusions.get_inclusion_data(inclusion_id, id, real_q);
459
460 local_inclusion_matrix(j, j) +=
461 (inclusion_fe_values[j] * inclusion_fe_values[j] /
462 inclusion_fe_values[0]);
463 }
464 ++p;
465 }
466 // I expect p and next_p to be the same now.
467 Assert(p == next_p, ExcInternalError());
468
469 // Add local matrices to global ones
470 constraints.distribute_local_to_global(local_coupling_matrix,
471 fe_dof_indices,
472 inclusion_constraints,
473 inclusion_dof_indices,
474 coupling_matrix);
475 inclusion_constraints.distribute_local_to_global(
476 local_rhs, inclusion_dof_indices, system_rhs.block(1));
477
478 inclusion_constraints.distribute_local_to_global(
479 local_inclusion_matrix, inclusion_dof_indices,
480inclusion_matrix);
481 }
482 particle = pic.end();
483 }
484 coupling_matrix.compress(VectorOperation::add);
485#ifndef MATRIX_FREE_PATH
486 stiffness_matrix.compress(VectorOperation::add);
487#endif
488 inclusion_matrix.compress(VectorOperation::add);
489 system_rhs.compress(VectorOperation::add);
490 pcout << "System rhs: " << system_rhs.l2_norm() << std::endl;
491}
492*/
493
494#ifdef MATRIX_FREE_PATH
495template <int dim, int spacedim>
496void
498{
499 stiffness_matrix.get_matrix_free()->initialize_dof_vector(solution.block(0));
500 stiffness_matrix.get_matrix_free()->initialize_dof_vector(
501 system_rhs.block(0));
502 system_rhs = 0;
503 solution.block(0) = 0;
504 constraints.distribute(solution.block(0));
505 solution.block(0).update_ghost_values();
506
507 FEEvaluation<spacedim, -1> phi(*stiffness_matrix.get_matrix_free());
508 for (unsigned int cell = 0;
509 cell < stiffness_matrix.get_matrix_free()->n_cell_batches();
510 ++cell)
511 {
512 phi.reinit(cell);
513 phi.read_dof_values_plain(solution.block(0));
514 phi.evaluate(EvaluationFlags::gradients);
515 for (unsigned int q = 0; q < phi.n_q_points; ++q)
516 {
518 phi.quadrature_point(q);
519
520 VectorizedArray<double> f_value = 0.0;
521 for (unsigned int v = 0; v < VectorizedArray<double>::size(); ++v)
522 {
524 for (unsigned int d = 0; d < spacedim; ++d)
525 p[d] = p_vect[d][v];
526 f_value[v] = par.rhs.value(p);
527 }
528 phi.submit_gradient(-phi.get_gradient(q), q);
529 phi.submit_value(f_value, q);
530 }
532 phi.distribute_local_to_global(system_rhs.block(0));
533 }
534
535 system_rhs.compress(VectorOperation::add);
536}
537#endif
538
539
540template <int dim, int spacedim>
541void
543{
545 pcout << "Preparing solve." << std::endl;
546 SolverCG<VectorType> cg_stiffness(par.inner_control);
547#ifdef MATRIX_FREE_PATH
548
549 using Payload = dealii::internal::LinearOperatorImplementation::EmptyPayload;
552
553 MGTransferMatrixFree<spacedim, float> mg_transfer(mg_constrained_dofs);
554 mg_transfer.build(dh);
555
556 using SmootherType =
557 PreconditionChebyshev<LevelMatrixType,
559 mg::SmootherRelaxation<SmootherType,
561 mg_smoother;
563 smoother_data.resize(0, tria.n_global_levels() - 1);
564 for (unsigned int level = 0; level < tria.n_global_levels(); ++level)
565 {
566 if (level > 0)
567 {
568 smoother_data[level].smoothing_range = 15.;
569 smoother_data[level].degree = 5;
570 smoother_data[level].eig_cg_n_iterations = 10;
571 }
572 else
573 {
574 smoother_data[0].smoothing_range = 1e-3;
575 smoother_data[0].degree = numbers::invalid_unsigned_int;
576 smoother_data[0].eig_cg_n_iterations = mg_matrices[0].m();
577 }
578 mg_matrices[level].compute_diagonal();
579 smoother_data[level].preconditioner =
580 mg_matrices[level].get_matrix_diagonal_inverse();
581 }
582 mg_smoother.initialize(mg_matrices, smoother_data);
583
585 mg_coarse;
586 mg_coarse.initialize(mg_smoother);
587
589
591 mg_interface_matrices;
592 mg_interface_matrices.resize(0, tria.n_global_levels() - 1);
593 for (unsigned int level = 0; level < tria.n_global_levels(); ++level)
594 mg_interface_matrices[level].initialize(mg_matrices[level]);
596 mg_interface_matrices);
597
599 mg_matrix, mg_coarse, mg_transfer, mg_smoother, mg_smoother);
600 mg.set_edge_matrices(mg_interface, mg_interface);
601
602 PreconditionMG<spacedim,
605 preconditioner(dh, mg, mg_transfer);
606
607 auto invA = A;
608 invA = inverse_operator(A, cg_stiffness, preconditioner);
609#else
610 using Payload =
614
615 LA::MPI::PreconditionAMG prec_A;
616 {
617 LA::MPI::PreconditionAMG::AdditionalData data;
618# ifdef USE_PETSC_LA
619 data.symmetric_operator = true;
620# endif
621 pcout << "Initialize AMG...";
622 prec_A.initialize(stiffness_matrix, data);
623 pcout << "done." << std::endl;
624 }
625 const auto amgA = linear_operator<VectorType, VectorType, Payload>(A, prec_A);
626 auto invA = A;
627 invA = inverse_operator(A, cg_stiffness, amgA);
628#endif
629
630
631 // Some aliases
632 auto &u = solution.block(0);
633 auto &lambda = solution.block(1);
634
635 const auto &f = system_rhs.block(0);
636 const auto &g = system_rhs.block(1);
637
638 if (reduced_coupling.get_dof_handler().n_dofs() == 0)
639 {
640 u = invA * f;
641 }
642 else
643 {
644#ifdef MATRIX_FREE_PATH
645 auto Bt =
647 Bt.reinit_range_vector = [this](VectorType &vec, const bool) {
648 vec.reinit(owned_dofs[0], relevant_dofs[0], mpi_communicator);
649 };
650 Bt.reinit_domain_vector = [this](VectorType &vec, const bool) {
651 vec.reinit(owned_dofs[1], relevant_dofs[1], mpi_communicator);
652 };
653
655#else
656 const auto Bt =
659 // const auto B = linear_operator<VectorType, VectorType, Payload>(
660 // coupling_matrix_transpose);
661#endif
662
663 if (par.solver_name == "Schur")
664 {
665 // Schur complement
666 pcout << " Prepare schur... ";
667 const auto S = B * invA * Bt;
668 pcout << "S was built." << std::endl;
669
670 // Schur complement preconditioner
671 auto invS = S;
672 SolverFGMRES<VectorType> solver_schur(par.outer_control);
673 invS =
675 solver_schur);
676
677 pcout << " f norm: " << f.l2_norm() << ", g norm: " << g.l2_norm()
678 << std::endl;
679
680 // Compute Lambda first
681 lambda = invS * (B * invA * f - g);
682 pcout << " Solved for lambda in " << par.outer_control.last_step()
683 << " iterations." << std::endl;
684
685 // Then compute u
686 u = invA * (f - Bt * lambda);
687 pcout << " u norm: " << u.l2_norm()
688 << ", lambda norm: " << lambda.l2_norm() << std::endl;
689
690 pcout << " Solved for u in " << par.inner_control.last_step()
691 << " iterations." << std::endl;
692
693 constraints.distribute(u);
694 reduced_coupling.get_coupling_constraints().distribute(lambda);
695 // solution.update_ghost_values();
697 }
698 else if (par.solver_name == "AL")
699 {
700 pcout << "Prepare AL preconditioner... " << std::endl;
701
703 (std::is_same_v<LA::MPI::Vector, TrilinosWrappers::MPI::Vector>),
704 ExcNotImplemented());
705
706 LA::MPI::SparseMatrix reduced_mass_matrix;
707 const auto &reduced_dh = reduced_coupling.get_dof_handler();
708 DynamicSparsityPattern dsp_reduced_mass(relevant_dofs[1]);
709 DoFTools::make_sparsity_pattern(reduced_dh, dsp_reduced_mass);
711 owned_dofs[1],
713 relevant_dofs[1]);
714 reduced_mass_matrix.reinit(owned_dofs[1],
715 owned_dofs[1],
716 dsp_reduced_mass,
718
719 // Create mass matrix associated with the reduced dof handler
720 reduced_coupling.assemble_coupling_mass_matrix(reduced_mass_matrix);
721
722 pcout << "Reduced mass matrix size: " << reduced_mass_matrix.m()
723 << " x " << reduced_mass_matrix.n()
724 << ", norm: " << reduced_mass_matrix.linfty_norm() << std::endl;
725
726
727 const auto M = linear_operator<LA::MPI::Vector>(reduced_mass_matrix);
728
729 // Augmented Lagrangian solver
731 M_inv_ilu.initialize(reduced_mass_matrix);
732
733 TrilinosWrappers::MPI::Vector inverse_squares_reduced; // diag(M)^{-2}
734 inverse_squares_reduced.reinit(owned_dofs[1], mpi_communicator);
735 for (const types::global_dof_index local_idx : owned_dofs[1])
736 {
737 const double el = reduced_mass_matrix.diag_element(local_idx);
738 Assert(std::abs(el) > 1e-10,
739 ExcMessage(
740 "Diagonal element " + std::to_string(local_idx) +
741 " of reduced mass matrix (" + std::to_string(el) +
742 ") is close to zero. Cannot compute inverse square."));
743 inverse_squares_reduced(local_idx) = 1. / (el * el);
744 }
745
746 inverse_squares_reduced.compress(VectorOperation::insert);
747
748
749 SolverControl solver_control(100, 1e-15, false, false);
751 solver_control);
752 auto invM = inverse_operator(M, solver_mass_matrix, M_inv_ilu);
753 auto invW = invM * invM;
754
755 const double gamma = 10; // TODO: add to parameters file
756 auto Aug = A + gamma * Bt * invW * B;
757
758 TrilinosWrappers::SparseMatrix augmented_matrix;
759
760 TrilinosWrappers::PreconditionAMG prec_amg_augmented_block;
762
763 if (par.assemble_full_AL_system)
764 {
765 pcout << "Building augmented matrix..." << std::endl;
768 inverse_squares_reduced,
769 gamma,
770 augmented_matrix);
771 prec_amg_augmented_block.initialize(augmented_matrix, data);
772 pcout << "done." << std::endl;
774 augmented_matrix);
775 }
776 else
777 {
778 prec_amg_augmented_block.initialize(stiffness_matrix, data);
779 }
780
781
782 auto Zero = M * 0.0;
784 {{{{Aug, Bt}}, {{B, Zero}}}});
785
786 LA::MPI::BlockVector solution_block;
787 LA::MPI::BlockVector system_rhs_block;
788 AA.reinit_domain_vector(solution_block, false);
789 AA.reinit_range_vector(system_rhs_block, false);
790
791 // lagrangian term
792 LA::MPI::Vector tmp;
793 tmp.reinit(system_rhs.block(0));
794 tmp = gamma * Bt * invW * system_rhs.block(1);
795 system_rhs_block.block(0) = system_rhs.block(0);
796 system_rhs_block.block(0).add(1., tmp); // ! augmented
797 system_rhs_block.block(1) = system_rhs.block(1);
798
799 SolverCG<LA::MPI::Vector> solver_lagrangian(par.inner_control);
800
801
802 auto Aug_inv =
803 inverse_operator(Aug, solver_lagrangian, prec_amg_augmented_block);
804
805 SolverFGMRES<LA::MPI::BlockVector> solver_fgmres(par.outer_control);
807 augmented_lagrangian_preconditioner{Aug_inv, B, Bt, invW, gamma};
808
809 solver_fgmres.solve(AA,
810 solution_block,
811 system_rhs_block,
812 augmented_lagrangian_preconditioner);
813
814 pcout << " Solved with AL preconditioner in "
815 << par.outer_control.last_step() << " iterations." << std::endl;
816
817 constraints.distribute(solution_block.block(0));
818 reduced_coupling.get_coupling_constraints().distribute(
819 solution_block.block(1));
820 // solution.update_ghost_values();
821 locally_relevant_solution = solution_block;
822
823
824#ifdef DEBUG
825 // Estimate condition number of BBt using CG
826 {
827 auto output_double_number = [this](double input,
828 const std::string &text) {
830 std::cout << text << input << std::endl;
831 };
832
833 // Estimate condition number:
834 pcout << "- - - - - - - - - - - - - - - - - - - - - - - -"
835 << std::endl;
836 pcout << "Estimate condition number of BBt using CG" << std::endl;
837 SolverControl solver_control(100000, 1e-12);
838 SolverCG<TrilinosWrappers::MPI::Vector> solver_cg(solver_control);
839
841 std::bind(output_double_number,
842 std::placeholders::_1,
843 "Condition number estimate: "));
844 using PayloadType = dealii::TrilinosWrappers::internal::
845 LinearOperatorImplementation::TrilinosPayload;
846
847 auto BBt = B * Bt;
848
850 u = 0.;
852 f = 1.;
854 try
855 {
856 solver_cg.solve(BBt, u, f, prec_no);
857 }
858 catch (...)
859 {
860 pcout
861 << "***BBt solve not successfull (see condition number above)***"
862 << std::endl;
863 }
864 }
865#endif
866 }
867 else
868 {
870 }
871 }
872}
873
874
875
876template <int dim, int spacedim>
877void
879{
881 Vector<float> error_per_cell(tria.n_active_cells());
883 QGauss<spacedim - 1>(par.fe_degree +
884 1),
885 {},
887 error_per_cell);
888 if (par.refinement_strategy == "fixed_fraction")
889 {
891 tria, error_per_cell, par.refinement_fraction, par.coarsening_fraction);
892 }
893 else if (par.refinement_strategy == "fixed_number")
894 {
896 tria,
897 error_per_cell,
898 par.refinement_fraction,
899 par.coarsening_fraction,
900 par.max_cells);
901 }
902 else if (par.refinement_strategy == "global")
903 for (const auto &cell : tria.active_cell_iterators())
904 cell->set_refine_flag();
905
907 tria.prepare_coarsening_and_refinement();
908 // inclusions.inclusions_as_particles.prepare_for_coarsening_and_refinement();
911 tria.execute_coarsening_and_refinement();
912 // inclusions.inclusions_as_particles.unpack_after_coarsening_and_refinement();
913 setup_dofs();
914 transfer.interpolate(solution.block(0));
915 constraints.distribute(solution.block(0));
916 locally_relevant_solution.block(0) = solution.block(0);
917}
918
919
920
921template <int dim, int spacedim>
922std::string
924{
925 TimerOutput::Scope t(computing_timer, "Output results");
926 std::string solution_name = "solution";
927 DataOut<spacedim> data_out;
928 data_out.attach_dof_handler(dh);
929 data_out.add_data_vector(locally_relevant_solution.block(0), solution_name);
930 Vector<float> subdomain(tria.n_active_cells());
931 for (unsigned int i = 0; i < subdomain.size(); ++i)
932 subdomain(i) = tria.locally_owned_subdomain();
933 data_out.add_data_vector(subdomain, "subdomain");
934 data_out.build_patches();
935 const std::string filename =
936 par.output_name + "_" + std::to_string(cycle) + ".vtu";
937 data_out.write_vtu_in_parallel(par.output_directory + "/" + filename,
939 return filename;
940}
941
942
943template <int dim, int spacedim>
944void
946{
947 static std::vector<std::pair<double, std::string>> cycles_and_solutions;
948 static std::vector<std::pair<double, std::string>> cycles_and_particles;
949
950 if (cycles_and_solutions.size() == cycle)
951 {
952 cycles_and_solutions.push_back({(double)cycle, output_solution()});
953
954 const std::string particles_filename =
955 par.output_name + "_particles_" + std::to_string(cycle) + ".vtu";
956 reduced_coupling.output_particles(par.output_directory + "/" +
957 particles_filename);
958
959 cycles_and_particles.push_back({(double)cycle, particles_filename});
960
961 std::ofstream pvd_solutions(par.output_directory + "/" + par.output_name +
962 ".pvd");
963 std::ofstream pvd_particles(par.output_directory + "/" + par.output_name +
964 "_particles.pvd");
965 DataOutBase::write_pvd_record(pvd_solutions, cycles_and_solutions);
966 DataOutBase::write_pvd_record(pvd_particles, cycles_and_particles);
967 }
968}
969
970template <int dim, int spacedim>
971void
973{
974#ifdef USE_PETSC_LA
975 pcout << "Running ReducedPoisson<" << Utilities::dim_string(dim, spacedim)
976 << "> using PETSc." << std::endl;
977#else
978 pcout << "Running ReducedPoisson<" << Utilities::dim_string(dim, spacedim)
979 << "> using Trilinos with "
980 << Utilities::MPI::n_mpi_processes(MPI_COMM_WORLD) << " MPI ranks."
981 << std::endl;
982#endif
984 {
985 par.prm.print_parameters(par.output_directory + "/" + "used_parameters_" +
986 std::to_string(dim) +
987 std::to_string(spacedim) + ".prm",
989 }
990}
991
992template <int dim, int spacedim>
993void
995{
997 make_grid();
998 setup_fe();
999 for (cycle = 0; cycle < par.n_refinement_cycles; ++cycle)
1000 {
1001 setup_dofs();
1002 if (par.output_results_before_solving)
1004#ifdef MATRIX_FREE_PATH
1005 assemble_rhs();
1006#else
1008#endif
1009 reduced_coupling.assemble_coupling_matrix(coupling_matrix,
1010 dh,
1011 constraints);
1012 reduced_coupling.assemble_reduced_rhs(system_rhs.block(1));
1013
1014#ifdef MATRIX_FREE_PATH
1015 // MappingQ1<spacedim> mapping;
1016 // coupling_operator =
1017 // std::make_unique<CouplingOperator<spacedim,
1018 // double>>(
1019 // inclusions, dh, constraints,
1020 // mapping, *fe);
1021#endif
1022 // return;
1023 solve();
1025 par.convergence_table.error_from_exact(dh,
1027 par.bc);
1028 if (cycle != par.n_refinement_cycles - 1)
1030 if (pcout.is_active())
1031 par.convergence_table.output_table(pcout.get_stream());
1032 }
1033}
1034
1035
1036// Template instantiations
1037template class ReducedPoissonParameters<2>;
1038template class ReducedPoissonParameters<3>;
1039
1040template class ReducedPoisson<2>;
1041template class ReducedPoisson<3>;
void constrain_dof_to_zero(const size_type constrained_dof)
void write_vtu_in_parallel(const std::string &filename, const MPI_Comm comm) const
void attach_dof_handler(const DoFHandler< dim, spacedim > &)
void add_data_vector(const VectorType &data, const std::vector< std::string > &names, const DataVectorType type=type_automatic, const std::vector< DataComponentInterpretation::DataComponentInterpretation > &data_component_interpretation={})
virtual void build_patches(const unsigned int n_subdivisions=0)
const std::vector< Point< spacedim > > & get_quadrature_points() const
double JxW(const unsigned int q_point) const
const double & shape_value(const unsigned int i, const unsigned int q_point) const
void reinit(const TriaIterator< DoFCellAccessor< dim, spacedim, level_dof_access > > &cell)
void attach_triangulation(Triangulation< dim, spacedim > &tria)
void read(std::istream &in, Format format=Default)
static void estimate(const Mapping< dim, spacedim > &mapping, const DoFHandler< dim, spacedim > &dof, const Quadrature< dim - 1 > &quadrature, const std::map< types::boundary_id, const Function< spacedim, Number > * > &neumann_bc, const ReadVector< Number > &solution, Vector< float > &error, const ComponentMask &component_mask={}, const Function< spacedim > *coefficients=nullptr, const unsigned int n_threads=numbers::invalid_unsigned_int, const types::subdomain_id subdomain_id=numbers::invalid_subdomain_id, const types::material_id material_id=numbers::invalid_material_id, const Strategy strategy=cell_diameter_over_24)
void initialize(const MGSmootherBase< VectorType > &coarse_smooth)
void resize(const unsigned int new_minlevel, const unsigned int new_maxlevel, Args &&...args)
void build(const DoFHandler< dim > &dof_handler, const std::vector< std::shared_ptr< const Utilities::MPI::Partitioner > > &external_partitioners=std::vector< std::shared_ptr< const Utilities::MPI::Partitioner > >())
ParameterAcceptor(const std::string &section_name="")
static ParameterHandler prm
void enter_subsection(const std::string &subsection)
void add_parameter(const std::string &entry, ParameterType &parameter, const std::string &documentation="", ParameterHandler &prm_=prm, const Patterns::PatternBase &pattern=*Patterns::Tools::Convert< ParameterType >::to_pattern())
void prepare_for_coarsening_and_refinement(const std::vector< const VectorType * > &all_in)
void interpolate(std::vector< VectorType * > &all_out)
boost::signals2::connection connect_condition_number_slot(const std::function< void(double)> &slot, const bool every_iteration=false)
void solve(const MatrixType &A, VectorType &x, const VectorType &b, const PreconditionerType &preconditioner)
void solve(const MatrixType &A, VectorType &x, const VectorType &b, const PreconditionerTypes &...preconditioners)
void compress(VectorOperation::values operation)
void reinit(const Vector &v, const bool omit_zeroing_entries=false, const bool allow_different_maps=false)
void initialize(const SparseMatrix &matrix, const AdditionalData &additional_data=AdditionalData())
void initialize(const SparseMatrix &matrix, const AdditionalData &additional_data=AdditionalData())
virtual size_type size() const override
BlockVectorType system_rhs
std::unique_ptr< FiniteElement< spacedim > > fe
BlockVectorType locally_relevant_solution
MappingQ< spacedim > mapping
std::vector< IndexSet > relevant_dofs
std::unique_ptr< Quadrature< spacedim > > quadrature
BlockVectorType solution
const ReducedPoissonParameters< spacedim > & par
std::vector< IndexSet > owned_dofs
parallel::distributed::Triangulation< spacedim > tria
AffineConstraints< double > constraints
ConditionalOStream pcout
unsigned int cycle
DoFHandler< spacedim > dh
LA::MPI::SparseMatrix coupling_matrix
MPI_Comm mpi_communicator
ReducedPoisson(const ReducedPoissonParameters< spacedim > &par)
void print_parameters() const
LA::MPI::Vector VectorType
void output_results() const
TimerOutput computing_timer
ReducedCoupling< 1, 2, spacedim, 1 > reduced_coupling
LA::MPI::SparseMatrix stiffness_matrix
void assemble_poisson_system()
std::string output_solution() const
ParameterAcceptorProxy< Functions::ParsedFunction< spacedim > > bc
ParsedConvergenceTable convergence_table
std::list< types::boundary_id > dirichlet_ids
ParameterAcceptorProxy< ReductionControl > inner_control
ParameterAcceptorProxy< ReductionControl > outer_control
ParameterAcceptorProxy< Functions::ParsedFunction< spacedim > > rhs
#define DEAL_II_NOT_IMPLEMENTED()
unsigned int level
#define Assert(cond, exc)
#define AssertThrow(cond, exc)
LinearOperator< Range, Domain, Payload > linear_operator(const OperatorExemplar &, const Matrix &)
LinearOperator< Domain, Range, Payload > transpose_operator(const LinearOperator< Range, Domain, Payload > &op)
LinearOperator< Domain, Range, Payload > inverse_operator(const LinearOperator< Range, Domain, Payload > &op, Solver &solver, const Preconditioner &preconditioner)
BlockLinearOperator< Range, Domain, BlockPayload > block_operator(const BlockMatrixType &matrix)
void make_hanging_node_constraints(const DoFHandler< dim, spacedim > &dof_handler, AffineConstraints< number > &constraints)
void make_sparsity_pattern(const DoFHandler< dim, spacedim > &dof_handler, SparsityPatternBase &sparsity_pattern, const AffineConstraints< number > &constraints={}, const bool keep_constrained_dofs=true, const types::subdomain_id subdomain_id=numbers::invalid_subdomain_id)
update_values
update_JxW_values
update_gradients
update_quadrature_points
void set_manifold(const types::manifold_id number, const Manifold< dim, spacedim > &manifold_object)
std::vector< index_type > data
void write_pvd_record(std::ostream &out, const std::vector< std::pair< double, std::string > > &times_and_names)
IndexSet extract_locally_relevant_dofs(const DoFHandler< dim, spacedim > &dof_handler)
IndexSet extract_locally_relevant_level_dofs(const DoFHandler< dim, spacedim > &dof_handler, const unsigned int level)
void generate_from_name_and_arguments(Triangulation< dim, spacedim > &tria, const std::string &grid_generator_function_name, const std::string &grid_generator_function_arguments)
std::tuple< unsigned int, unsigned int, unsigned int > count_elements(const TopoDS_Shape &shape)
TopoDS_Shape read_STEP(const std::string &filename, const double scale_factor=1e-3)
TopoDS_Shape read_IGES(const std::string &filename, const double scale_factor=1e-3)
SymmetricTensor< 2, dim, Number > e(const Tensor< 2, dim, Number > &F)
SymmetricTensor< 2, dim, Number > d(const Tensor< 2, dim, Number > &F, const Tensor< 2, dim, Number > &dF_dt)
void distribute_sparsity_pattern(DynamicSparsityPattern &dsp, const IndexSet &locally_owned_rows, const MPI_Comm mpi_comm, const IndexSet &locally_relevant_rows)
unsigned int n_mpi_processes(const MPI_Comm mpi_communicator)
unsigned int this_mpi_process(const MPI_Comm mpi_communicator)
std::string dim_string(const int dim, const int spacedim)
void interpolate_boundary_values(const Mapping< dim, spacedim > &mapping, const DoFHandler< dim, spacedim > &dof, const std::map< types::boundary_id, const Function< spacedim, number > * > &function_map, std::map< types::global_dof_index, number > &boundary_values, const ComponentMask &component_mask={})
void create_augmented_block(const MatrixType &A, const MatrixType &Ct, const VectorType &scaling_vector, const double gamma, MatrixType &augmented_matrix)
constexpr unsigned int invalid_unsigned_int
void refine_and_coarsen_fixed_fraction(::Triangulation< dim, spacedim > &tria, const ::Vector< Number > &criteria, const double top_fraction_of_error, const double bottom_fraction_of_error, const VectorTools::NormType norm_type=VectorTools::L1_norm)
void refine_and_coarsen_fixed_number(::Triangulation< dim, spacedim > &tria, const ::Vector< Number > &criteria, const double top_fraction_of_cells, const double bottom_fraction_of_cells, const types::global_cell_index max_n_cells=std::numeric_limits< types::global_cell_index >::max())
::SolutionTransfer< dim, VectorType, spacedim > SolutionTransfer
::VectorizedArray< Number, width > abs(const ::VectorizedArray< Number, width > &)
unsigned int global_dof_index
void read_grid_and_cad_files(const std::string &grid_file_name, const std::string &ids_and_cad_file_names, Triangulation< dim, spacedim > &tria)
TasksParallelScheme tasks_parallel_scheme
UpdateFlags mapping_update_flags