navier_stokes_preconditioners.h
Go to the documentation of this file.
1// LIC// ====================================================================
2// LIC// This file forms part of oomph-lib, the object-oriented,
3// LIC// multi-physics finite-element library, available
4// LIC// at http://www.oomph-lib.org.
5// LIC//
6// LIC// Copyright (C) 2006-2025 Matthias Heil and Andrew Hazel
7// LIC//
8// LIC// This library is free software; you can redistribute it and/or
9// LIC// modify it under the terms of the GNU Lesser General Public
10// LIC// License as published by the Free Software Foundation; either
11// LIC// version 2.1 of the License, or (at your option) any later version.
12// LIC//
13// LIC// This library is distributed in the hope that it will be useful,
14// LIC// but WITHOUT ANY WARRANTY; without even the implied warranty of
15// LIC// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16// LIC// Lesser General Public License for more details.
17// LIC//
18// LIC// You should have received a copy of the GNU Lesser General Public
19// LIC// License along with this library; if not, write to the Free Software
20// LIC// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21// LIC// 02110-1301 USA.
22// LIC//
23// LIC// The authors may be contacted at oomph-lib@maths.man.ac.uk.
24// LIC//
25// LIC//====================================================================
26#ifndef OOMPH_NAVIER_STOKES_PRECONDITIONERS_HEADER
27#define OOMPH_NAVIER_STOKES_PRECONDITIONERS_HEADER
28
29
30// Config header
31#ifdef HAVE_CONFIG_H
32#include <oomph-lib-config.h>
33#endif
34
35
36// oomphlib headers
37#include "generic/matrices.h"
39#include "generic/problem.h"
46
47
48namespace oomph
49{
50 ///////////////////////////////////////////////////////////////////////
51 ///////////////////////////////////////////////////////////////////////
52 ///////////////////////////////////////////////////////////////////////
53
54
55 //======start_of_namespace============================================
56 /// Namespace for exact solution for pressure advection diffusion
57 /// problem
58 //====================================================================
59 namespace PressureAdvectionDiffusionValidation
60 {
61 /// Flag for solution
62 extern unsigned Flag;
63
64 /// Peclet number -- overwrite with actual Reynolds number
65 extern double Peclet;
66
67 /// Wind
68 extern void wind_function(const Vector<double>& x, Vector<double>& wind);
69
70 /// Exact solution as a Vector
71 extern void get_exact_u(const Vector<double>& x, Vector<double>& u);
72
73 /// Exact solution as a scalar
74 extern void get_exact_u(const Vector<double>& x, double& u);
75
76 /// Source function required to make the solution above an exact solution
77 extern double source_function(const Vector<double>& x_vect);
78
79 } // namespace PressureAdvectionDiffusionValidation
80
81
82 ////////////////////////////////////////////////////////////////
83 ////////////////////////////////////////////////////////////////
84 ////////////////////////////////////////////////////////////////
85
86
87 //=============================================================
88 /// A class that is used to define the functions used to
89 /// assemble the elemental contributions to the pressure
90 /// advection diffusion problem used by the Fp preconditioner.
91 //===============================================================
93 {
94 public:
95 /// Constructor. Pass spatial dimension
96 FpPreconditionerAssemblyHandler(const unsigned& ndim) // : Ndim(ndim)
97 {
98 }
99
100 /// Empty virtual destructor
102
103 /// Return the contribution to the residuals of the element elem_pt
106 {
107 unsigned n_dof = elem_pt->ndof();
108 for (unsigned i = 0; i < n_dof; i++)
109 {
110 residuals[i] = 0.0;
111 }
112
114 ->fill_in_pressure_advection_diffusion_residuals(residuals);
115 }
116
117 /// Calculate the elemental Jacobian matrix "d equation
118 /// / d variable" for elem_pt.
121 DenseMatrix<double>& jacobian)
122 {
123 // Initialise
124 unsigned n_dof = elem_pt->ndof();
125 for (unsigned i = 0; i < n_dof; i++)
126 {
127 residuals[i] = 0.0;
128 for (unsigned j = 0; j < n_dof; j++)
129 {
130 jacobian(i, j) = 0.0;
131 }
132 }
133
135 ->fill_in_pressure_advection_diffusion_jacobian(residuals, jacobian);
136 }
137
138 private:
139 /// Spatial dimension of problem
140 // unsigned Ndim; // cgj: Ndim is never used.
141 };
142
143
144 ///////////////////////////////////////////////////////////////////
145 ///////////////////////////////////////////////////////////////////
146 ///////////////////////////////////////////////////////////////////
147
148
149 //===========================================================================
150 /// Auxiliary Problem that can be used to assemble the
151 /// pressure advection diffusion matrix needed by the FpPreconditoner
152 //===========================================================================
153 template<class ELEMENT>
155 {
156 public:
157 /// Constructor: Pass Navier-Stokes mesh and pointer to orig problem
160 {
161 // Pass across mesh -- boundary conditions have already
162 // been applied and the equations have been enumerated.
164
165 // Store pointer to orig problem so we can re-assign the
166 // orig eqn numbers when we're done
168
169 // Get the spatial dimension
171
172 // Set new assembly handler
174 }
175
176
177 /// Get the pressure advection diffusion Jacobian
179 {
180 // Pin all non-pressure dofs
182
183 // Re-assign the equation numbers for all elements in Navier-Stokes mesh
184 unsigned n_dof = assign_eqn_numbers();
185 oomph_info << "Eqn numbers after pinning veloc dofs: " << n_dof
186 << std::endl;
187
188 // Get "Jacobian" of the modified system
190 this->get_jacobian(dummy_residuals, jacobian);
191
192 // Reset pin status
194
195 // Reassign equation numbering of original problem
196 oomph_info << "Eqn numbers in orig problem after re-assignment: "
197 << Orig_problem_pt->assign_eqn_numbers() << std::endl;
198 }
199
200
201 /// Reset pin status of all values
203 {
204 // Reset pin status for nodes
205 unsigned nnod = mesh_pt()->nnode();
206 for (unsigned j = 0; j < nnod; j++)
207 {
208 Node* nod_pt = mesh_pt()->node_pt(j);
209 unsigned nval = nod_pt->nvalue();
210 for (unsigned i = 0; i < nval; i++)
211 {
213 }
214 }
215
216 // ... and internal data
217 unsigned nelem = mesh_pt()->nelement();
218 for (unsigned e = 0; e < nelem; e++)
219 {
220 // Get actual element
221 ELEMENT* el_pt =
222 dynamic_cast<ELEMENT*>(mesh_pt()->finite_element_pt(e));
223
224
225#ifdef PARANOID
226 if (el_pt == 0)
227 {
228 std::ostringstream error_message;
229 error_message << "Navier Stokes mesh must contain only Navier Stokes"
230 << "bulk elements\n";
231 throw OomphLibError(error_message.str(),
234 }
235#endif
236
237 unsigned nint = el_pt->ninternal_data();
238 for (unsigned j = 0; j < nint; j++)
239 {
241 unsigned nvalue = data_pt->nvalue();
242 for (unsigned i = 0; i < nvalue; i++)
243 {
245 }
246 }
247 }
248
249 // Free up storage
250 Eqn_number_backup.clear();
251 }
252
253
254 /// Pin all non-pressure dofs and (if boolean flag is set to true
255 /// also all pressure dofs along domain boundaries -- only used
256 /// for validation)
258 const bool& set_pressure_bc_for_validation = false)
259 {
260 // Backup pin status and then pin all non-pressure degrees of freedom
261 unsigned nelem = mesh_pt()->nelement();
262 for (unsigned e = 0; e < nelem; e++)
263 {
264 // Get actual element (needed because different elements
265 // store nodal pressure in different places)
266 ELEMENT* el_pt =
267 dynamic_cast<ELEMENT*>(mesh_pt()->finite_element_pt(e));
268
269
270#ifdef PARANOID
271 if (el_pt == 0)
272 {
273 std::ostringstream error_message;
274 error_message << "Navier Stokes mesh must contain only Navier Stokes"
275 << "bulk elements\n";
276 throw OomphLibError(error_message.str(),
279 }
280#endif
281
282 // Check if element has internal pressure representation
283 // usually discontinuous -- preconditioner doesn't work for that case!
284 if (el_pt->p_nodal_index_nst() < 0)
285 {
286 std::ostringstream error_message;
287 error_message << "Cannot use Fp preconditioner with discontinuous\n"
288 << "pressures.\n";
289 throw OomphLibError(error_message.str(),
292 }
293
294 // Loop over internal data and pin the values (having established that
295 // pressure dofs aren't amongst those)
296 unsigned nint = el_pt->ninternal_data();
297 for (unsigned j = 0; j < nint; j++)
298 {
300 if (Eqn_number_backup[data_pt].size() == 0)
301 {
302 unsigned nvalue = data_pt->nvalue();
303 Eqn_number_backup[data_pt].resize(nvalue);
304 for (unsigned i = 0; i < nvalue; i++)
305 {
306 // Backup
308
309 // Pin everything
310 data_pt->pin(i);
311 }
312 }
313 }
314
315 // Now deal with nodal values
316 unsigned nnod = el_pt->nnode();
317 for (unsigned j = 0; j < nnod; j++)
318 {
320 if (Eqn_number_backup[nod_pt].size() == 0)
321 {
322 unsigned nvalue = nod_pt->nvalue();
323 Eqn_number_backup[nod_pt].resize(nvalue);
324 for (unsigned i = 0; i < nvalue; i++)
325 {
326 // Pin everything apart from the nodal pressure
327 // value
328 if (int(i) != el_pt->p_nodal_index_nst())
329 {
330 // Backup and pin
332 nod_pt->pin(i);
333 }
334 // Else it's a pressure value
335 else
336 {
337 // Exclude non-nodal pressure based elements
338 if (el_pt->p_nodal_index_nst() >= 0)
339 {
340 // Backup
342 }
343 }
344 }
345 }
346
347 // Set wind
349 {
350 Vector<double> x(2);
351 x[0] = nod_pt->x(0);
352 x[1] = nod_pt->x(1);
353 Vector<double> u(2);
355 nod_pt->set_value(el_pt->u_index_nst(0), u[0]);
356 nod_pt->set_value(el_pt->u_index_nst(1), u[1]);
357 }
358 }
359 }
360 }
361
362
363 /// Validate pressure advection diffusion problem and doc exact
364 /// and computed solution in directory specified in DocInfo object
365 void validate(DocInfo& doc_info)
366 {
367 oomph_info << "\n\n==============================================\n\n";
368 oomph_info << "Doing validation for pressure adv diff problem\n";
369
370 // Choose exact solution
372
373 // Pin all non-pressure dofs and pressure dofs along boundaries for
374 // validation
377
378
379 // Set Peclet number
381 dynamic_cast<NavierStokesEquations<2>*>(mesh_pt()->element_pt(0))->re();
382
383 // Loop over all elements and set source function pointer
384 unsigned nel = mesh_pt()->nelement();
385 for (unsigned e = 0; e < nel; e++)
386 {
387 dynamic_cast<NavierStokesEquations<2>*>(mesh_pt()->element_pt(e))
388 ->source_fct_for_pressure_adv_diff() =
390 }
391
392 // Re-assign the equation numbers for all elements in Navier-Stokes mesh
393 oomph_info << "Eqn numbers after pinning veloc dofs: "
394 << assign_eqn_numbers() << std::endl;
395
396 // Attach Robin BC elements
397 unsigned nbound = mesh_pt()->nboundary();
399 {
400 // Loop over all boundaries of Navier Stokes mesh
401 for (unsigned b = 0; b < nbound; b++)
402 {
403 // How many bulk elements are adjacent to boundary b?
404 unsigned n_element = mesh_pt()->nboundary_element(b);
405
406 // Loop over the bulk elements adjacent to boundary b?
407 for (unsigned e = 0; e < n_element; e++)
408 {
412
413 // What is the index of the face of the bulk element e on bondary b
414 int face_index = mesh_pt()->face_index_at_boundary(b, e);
415
416 // Build face element
417 bulk_elem_pt->build_fp_press_adv_diff_robin_bc_element(face_index);
418
419 } // end of loop over bulk elements adjacent to boundary b
420 }
421 }
422
423
424 // Loop over all elements and set source function pointer
425 std::ofstream outfile;
426 outfile.open("robin_elements.dat");
427 for (unsigned e = 0; e < nel; e++)
428 {
429 dynamic_cast<NavierStokesEquations<2>*>(mesh_pt()->element_pt(e))
430 ->output_pressure_advection_diffusion_robin_elements(outfile);
431 }
432 outfile.close();
433
434 // Solve it
435 newton_solve();
436
437 // And output the solution...
438 doc_solution(doc_info);
439
440 // Kill Robin BC elements
442 {
443 // Loop over all boundaries of Navier Stokes mesh
444 for (unsigned b = 0; b < nbound; b++)
445 {
446 // How many bulk elements are adjacent to boundary b?
447 unsigned n_element = mesh_pt()->nboundary_element(b);
448
449 // Loop over the bulk elements adjacent to boundary b?
450 for (unsigned e = 0; e < n_element; e++)
451 {
455
456 // Kill associated Robin elements
457 bulk_elem_pt->delete_pressure_advection_diffusion_robin_elements();
458
459 } // end of loop over bulk elements adjacent to boundary b
460 }
461 }
462
463 // Reset pin status
465
466 // Reassign equation numbering of original problem
467 oomph_info << "Eqn numbers in orig problem after re-assignment: "
468 << Orig_problem_pt->assign_eqn_numbers() << std::endl;
469
470
471 oomph_info << "Done validation for pressure adv diff problem\n";
472 oomph_info << "\n\n==============================================\n\n";
473 }
474
475
476 /// Doc solution (only needed during development -- kept alive
477 /// in case validation is required during code maintenance)
478 void doc_solution(DocInfo& doc_info)
479 {
480 std::ofstream some_file;
481 std::ostringstream filename;
482
483 // Number of plot points
484 unsigned npts;
485 npts = 5;
486
487 // Check value of FE solution in first element
488 Vector<double> s(Ndim, 0.0);
490 double p = dynamic_cast<ELEMENT*>(mesh_pt()->finite_element_pt(0))
491 ->interpolated_p_nst(s);
492 dynamic_cast<ELEMENT*>(mesh_pt()->finite_element_pt(0))
493 ->interpolated_x(s, x);
494
495 // Get offset-free exact solution
496 double u_exact = 0;
498
499 // Adjust offset
500 unsigned nnode = mesh_pt()->nnode();
501 for (unsigned j = 0; j < nnode; j++)
502 {
503 if (mesh_pt()->node_pt(j)->nvalue() == 3)
504 {
505 *(mesh_pt()->node_pt(j)->value_pt(2)) -= p - u_exact;
506 }
507 }
508
509 // Output solution
510 filename << doc_info.directory() << "/fp_soln" << doc_info.number()
511 << ".dat";
512 some_file.open(filename.str().c_str());
513 some_file.precision(20);
515 some_file.close();
516
517 filename.str("");
518 filename << doc_info.directory() << "/fp_exact_soln" << doc_info.number()
519 << ".dat";
520 some_file.open(filename.str().c_str());
521 some_file.precision(20);
524 some_file.close();
525 }
526
527 private:
528 /// The spatial dimension
529 unsigned Ndim;
530
531 /// Pointer to orig problem (required so we can re-assign
532 /// eqn numbers)
534
535 /// Map to store original equation numbers
536 std::map<Data*, std::vector<int>> Eqn_number_backup;
537 };
538
539
540 ////////////////////////////////////////////////////////////////////////////
541 ////////////////////////////////////////////////////////////////////////////
542 ////////////////////////////////////////////////////////////////////////////
543
544
545 //===========================================================================
546 /// The least-squares commutator (LSC; formerly BFBT) Navier Stokes
547 /// preconditioner. It uses blocks corresponding to the velocity
548 /// and pressure unknowns, i.e. there are a total of 2x2 blocks,
549 /// and all velocity components are treated as a single block of unknowns.
550 ///
551 /// Here are the details: An "ideal" Navier-Stokes preconditioner
552 /// would solve the system
553 /// \f[ \left( \begin{array}{cc} {\bf F} & {\bf G} \\ {\bf D} & {\bf 0} \end{array} \right) \left( \begin{array}{c} {\bf z}_u \\ {\bf z}_p \end{array} \right) = \left( \begin{array}{c} {\bf r}_u \\ {\bf r}_p \end{array} \right) \f]
554 /// where \f$ {\bf F}\f$ is the momentum block, \f$ {\bf G} \f$ the
555 /// discrete gradient operator, and \f$ {\bf D}\f$ the discrete
556 /// divergence operator. (For unstabilised elements, we have
557 /// \f$ {\bf D} = {\bf G}^T \f$ and in much of the literature
558 /// the divergence matrix is denoted by \f$ {\bf B} \f$ .)
559 /// The use of this preconditioner would ensure the convergence
560 /// of any iterative linear solver in a single iteration but its
561 /// application is, of course, exactly as expensive as a direct solve.
562 /// The LSC/BFBT preconditioner replaces the exact Jacobian by
563 /// a block-triangular approximation
564 /// \f[ \left( \begin{array}{cc} {\bf F} & {\bf G} \\ {\bf 0} & -{\bf M}_s \end{array} \right) \left( \begin{array}{c} {\bf z}_u \\ {\bf z}_p \end{array} \right) = \left( \begin{array}{c} {\bf r}_u \\ {\bf r}_p \end{array} \right), \f]
565 /// where \f${\bf M}_s\f$ is an approximation to the pressure
566 /// Schur-complement \f$ {\bf S} = {\bf D} {\bf F}^{-1}{\bf G}. \f$
567 /// This system can be solved in two steps:
568 /// -# Solve the second row for \f$ {\bf z}_p\f$ via
569 ///
570 /// \f[ {\bf z}_p = - {\bf M}_s^{-1} {\bf r}_p \f]
571 /// -# Given \f$ {\bf z}_p \f$ , solve the first row for \f$ {\bf z}_u\f$ via
572 ///
573 /// \f[ {\bf z}_u = {\bf F}^{-1} \big( {\bf r}_u - {\bf G} {\bf z}_p \big) \f]
574 /// .
575 /// In the LSC/BFBT preconditioner, the action of the inverse pressure
576 /// Schur complement
577 /// \f[ {\bf z}_p = - {\bf M}_s^{-1} {\bf r}_p \f]
578 /// is approximated by
579 /// \f[ {\bf z}_p = - \big({\bf D} \widehat{\bf Q}^{-1}{\bf G} \big)^{-1} \big({\bf D} \widehat{\bf Q}^{-1}{\bf F} \widehat{\bf Q}^{-1}{\bf G}\big) \big({\bf D} \widehat{\bf Q}^{-1}{\bf G} \big)^{-1} {\bf r}_p, \f]
580 /// where \f$ \widehat{\bf Q} \f$ is the diagonal of the velocity
581 /// mass matrix. The evaluation of this expression involves
582 /// two linear solves involving the matrix
583 /// \f[ {\bf P} = \big({\bf D} \widehat{\bf Q}^{-1}{\bf G} \big) \f]
584 /// which has the character of a matrix arising from the discretisation
585 /// of a Poisson problem on the pressure space. We also have
586 /// to evaluate matrix-vector products with the matrix
587 /// \f[ {\bf E}={\bf D}\widehat{\bf Q}^{-1}{\bf F}\widehat{\bf Q}^{-1}{\bf G} \f]
588 /// Details of the theory can be found in "Finite Elements and
589 /// Fast Iterative Solvers with Applications in Incompressible Fluid
590 /// Dynamics" by Howard C. Elman, David J. Silvester, and Andrew J. Wathen,
591 /// published by Oxford University Press, 2006.
592 ///
593 /// In our implementation of the preconditioner, the linear systems
594 /// can either be solved "exactly", using SuperLU (in its incarnation
595 /// as an exact preconditioner; this is the default) or by any
596 /// other Preconditioner (inexact solver) specified via the access functions
597 /// \code
598 /// NavierStokesSchurComplementPreconditioner::set_f_preconditioner(...)
599 /// \endcode
600 /// or
601 /// \code
602 /// NavierStokesSchurComplementPreconditioner::set_p_preconditioner(...)
603 /// \endcode
604 //===========================================================================
606 : public BlockPreconditioner<CRDoubleMatrix>
607 {
608 public:
609 /// Constructor - sets defaults for control flags
612 {
613 // Insist that all elements are of type
614 // NavierStokesElementWithDiagonalMassMatrices and issue a warning
615 // if one is not.
617
618 // Use Robin BC elements for Fp preconditioner -- yes by default
619 Use_robin_for_fp = true;
620
621 // Flag to indicate that the preconditioner has been setup
622 // previously -- if setup() is called again, data can
623 // be wiped.
625
626 // By default we use the LSC version
627 Use_LSC = true;
628
629 // By default we use SuperLU for both p and f blocks
632
633 // Pin pressure dof in press adv diff problem for Fp precond
635
637
638 // Set default preconditioners (inexact solvers) -- they are
639 // members of this class!
642
643 // set Doc_time to false
644 Doc_time = false;
645
646 // null the off diagonal Block matrix pt
647 Bt_mat_vec_pt = 0;
648
649 // null the F matrix vector product helper
650 F_mat_vec_pt = 0;
651
652 // null the QBt matrix vector product pt
653 QBt_mat_vec_pt = 0;
654
655 // null the E matrix vector product helper in Fp
656 E_mat_vec_pt = 0;
657
658 // Initially assume that there are no multiple element types in the
659 // Navier-Stokes mesh
661 }
662
663 /// Destructor
668
669 /// Broken copy constructor
672
673 /// Broken assignment operator
674 // Commented out broken assignment operator because this can lead to a
675 // conflict warning when used in the virtual inheritence hierarchy.
676 // Essentially the compiler doesn't realise that two separate
677 // implementations of the broken function are the same and so, quite
678 // rightly, it shouts.
679 /*void operator=(const NavierStokesSchurComplementPreconditioner&) =
680 * delete;*/
681
682 /// Set the problem pointer (non-const pointer, the problem WILL be
683 /// changed) for use in get_pressure_advection_diffusion_matrix().
688
690 {
691#ifdef PARANOID
692 if (Problem_pt == 0)
693 {
694 std::ostringstream error_msg;
695 error_msg << "Problem pointer is null, did you set it yet?";
696 throw OomphLibError(
698 }
699#endif
700 return Problem_pt;
701 }
702
703 /// Accept presence of elements that are not of type
704 /// NavierStokesElementWithDiagonalMassMatrices without issuing a warning.
709
710
711 /// Do not accept presence of elements that are not of type
712 /// NavierStokesElementWithDiagonalMassMatrices without issuing a warning.
717
718
719 /// Setup the preconditioner
720 void setup();
721
722 /// for some reason we have to remind the compiler that there is a
723 /// setup() function in Preconditioner base class.
725
726 /// Apply preconditioner to Vector r
728
729 /// Specify the mesh containing the block-preconditionable Navier-Stokes
730 /// elements. The optional argument indicates if there are multiple types
731 /// of elements in the same mesh.
733 Mesh* mesh_pt,
735 {
736 // Store the mesh pointer.
738
739 // Are there multiple element types in this mesh?
742 }
743
744 /// Function to set a new pressure matrix preconditioner (inexact solver)
746 {
747 // If the default preconditioner has been used
748 // clean it up now...
750 {
751 delete P_preconditioner_pt;
752 }
755 }
756
757 /// Function to (re-)set pressure matrix preconditioner (inexact
758 /// solver) to exact preconditioner
768
769 /// Function to set a new momentum matrix preconditioner (inexact solver)
771 {
772 // If the default preconditioner has been used
773 // clean it up now...
775 {
776 delete F_preconditioner_pt;
777 }
780 }
781
782 /// Use LSC version of the preconditioner
783 void use_lsc()
784 {
785 Use_LSC = true;
786 }
787
788 /// Use Fp version of the preconditioner
789 void use_fp()
790 {
791 Use_LSC = false;
792 }
793
794 /// Function to (re-)set momentum matrix preconditioner (inexact
795 /// solver) to exact preconditioner
805
806 /// Enable documentation of time
808 {
809 Doc_time = true;
810 }
811
812 /// Disable documentation of time
814 {
815 Doc_time = false;
816 }
817
818 /// Helper function to delete preconditioner data.
819 void clean_up_memory();
820
821 /// Use Robin BC elements for the Fp preconditioner
823 {
824 Use_robin_for_fp = true;
825 }
826
827 /// Don't use Robin BC elements for the Fp preconditioenr
829 {
830 Use_robin_for_fp = false;
831 }
832
833 /// Set boolean indicating that we want to pin first pressure
834 /// dof in Navier Stokes mesh when
835 /// assembling the pressure advection diffusion system for
836 /// Fp preconditoner -- needed at zero Reynolds number
837 /// for non-enclosed flows but seems harmless in any case
842
843 /// Set boolean indicating that we do not want to pin first pressure
844 /// dof in Navier Stokes mesh when
845 /// assembling the pressure advection diffusion system for
846 /// Fp preconditoner -- needed at zero Reynolds number
847 /// for non-enclosed flows but seems harmless in any case
852
853 /// Validate auxiliary pressure advection diffusion problem
854 /// in 2D
855 template<class ELEMENT>
862
863 /// Pin all non-pressure dofs
865 {
866 // Backup pin status and then pin all non-pressure degrees of freedom
868 for (unsigned e = 0; e < nelem; e++)
869 {
870 // Get pointer to the bulk element that is adjacent to boundary b
874
875 // Pin
876 el_pt->pin_all_non_pressure_dofs(Eqn_number_backup);
877 }
878 }
879
880
881 /// Get the pressure advection diffusion matrix
883 {
884 // Pin all non-pressure dofs
886
887 // Get the spatial dimension
888 unsigned ndim = Navier_stokes_mesh_pt->finite_element_pt(0)->dim();
889
890 // Backup assembly handler and set new one
895
896 // Backup submeshes (if any)
897 unsigned n_sub_mesh = problem_pt()->nsub_mesh();
899 for (unsigned i = 0; i < n_sub_mesh; i++)
900 {
902 }
903 // Flush sub-meshes but don't call rebuild_global_mesh()
904 // so we can simply re-instate the sub-meshes below.
906
907 // Backup the problem's own mesh pointer
910
911#ifdef OOMPH_HAS_MPI
912
913 // Backup the start and end elements for the distributed
914 // assembly process
919
920 // Now re-assign
922
923#endif
924
925 // Identify pinned pressure dof
926 int pinned_pressure_eqn = -2;
928 {
929 // Loop over all Navier Stokes elements to find first non-pinned
930 // pressure dof
931 unsigned nel = Navier_stokes_mesh_pt->nelement();
932 for (unsigned e = 0; e < nel; e++)
933 {
937 int local_eqn = bulk_elem_pt->p_local_eqn(0);
938 if (local_eqn >= 0)
939 {
941 break;
942 }
943 }
944
945
946#ifdef OOMPH_HAS_MPI
947 if (problem_pt()->distributed())
948 {
953 1,
954 MPI_INT,
955 MPI_MIN,
956 this->comm_pt()->mpi_comm());
958 }
959
960#endif
961 }
962
963
964 // Loop over all Navier Stokes elements
965 unsigned nel = Navier_stokes_mesh_pt->nelement();
966 for (unsigned e = 0; e < nel; e++)
967 {
971
972 // Set pinned pressure equation
973 bulk_elem_pt->pinned_fp_pressure_eqn() = pinned_pressure_eqn;
974 }
975
976
977 // Attach Robin BC elements
980 {
981 // Loop over all boundaries of Navier Stokes mesh
982 for (unsigned b = 0; b < nbound; b++)
983 {
984 // How many bulk elements are adjacent to boundary b?
986
987 // Loop over the bulk elements adjacent to boundary b?
988 for (unsigned e = 0; e < n_element; e++)
989 {
993
994 // What is the index of the face of the bulk element e on bondary b
995 int face_index =
997
998 // Build face element
999 bulk_elem_pt->build_fp_press_adv_diff_robin_bc_element(face_index);
1000
1001 } // end of loop over bulk elements adjacent to boundary b
1002 }
1003 }
1004
1005 // Get "Jacobian" of the modified system
1008
1009 // Kill Robin BC elements
1010 if (Use_robin_for_fp)
1011 {
1012 // Loop over all boundaries of Navier Stokes mesh
1013 for (unsigned b = 0; b < nbound; b++)
1014 {
1015 // How many bulk elements are adjacent to boundary b?
1017
1018 // Loop over the bulk elements adjacent to boundary b?
1019 for (unsigned e = 0; e < n_element; e++)
1020 {
1024
1025 // Kill associated Robin elements
1026 bulk_elem_pt->delete_pressure_advection_diffusion_robin_elements();
1027
1028 } // end of loop over bulk elements adjacent to boundary b
1029 }
1030 }
1031
1032 // Reset pin status
1034
1035#ifdef OOMPH_HAS_MPI
1036
1037 // Reset start and end elements for the distributed
1038 // assembly process
1041
1042#endif
1043
1044 // Cleanup and reset assembly handler
1045 delete problem_pt()->assembly_handler_pt();
1047
1048 // Re-instate submeshes. (No need to call rebuild_global_mesh()
1049 // as it was never unbuilt).
1050 for (unsigned i = 0; i < n_sub_mesh; i++)
1051 {
1053 }
1054
1055
1056 // Reset the problem's mesh pointer
1058 }
1059
1060
1061 /// Reset pin status of all values
1063 {
1064 // Reset pin status for nodes
1065 unsigned nnod = Navier_stokes_mesh_pt->nnode();
1066 for (unsigned j = 0; j < nnod; j++)
1067 {
1069 unsigned nval = nod_pt->nvalue();
1070 for (unsigned i = 0; i < nval; i++)
1071 {
1073 }
1074
1075 // If it's a solid node deal with its positional data too
1076 SolidNode* solid_nod_pt = dynamic_cast<SolidNode*>(nod_pt);
1077 if (solid_nod_pt != 0)
1078 {
1079 Data* solid_posn_data_pt = solid_nod_pt->variable_position_pt();
1080 unsigned nval = solid_posn_data_pt->nvalue();
1081 for (unsigned i = 0; i < nval; i++)
1082 {
1085 }
1086 }
1087 }
1088
1089 // ... and internal data
1090 unsigned nelem = Navier_stokes_mesh_pt->nelement();
1091 for (unsigned e = 0; e < nelem; e++)
1092 {
1093 // Pointer to element
1095
1096 // Pin/unpin internal data
1097 unsigned nint = el_pt->ninternal_data();
1098 for (unsigned j = 0; j < nint; j++)
1099 {
1101 unsigned nvalue = data_pt->nvalue();
1102 for (unsigned i = 0; i < nvalue; i++)
1103 {
1105 }
1106 }
1107 }
1108
1109 // Free up storage
1110 Eqn_number_backup.clear();
1111 }
1112
1113 private:
1114 // oomph-lib objects
1115 // -----------------
1116
1117 // Pointers to preconditioner (=inexact solver) objects
1118 // -----------------------------------------------------
1119 /// Pointer to the 'preconditioner' for the pressure matrix
1121
1122 /// Pointer to the 'preconditioner' for the F matrix
1124
1125 /// flag indicating whether the default F preconditioner is used
1127
1128 /// flag indicating whether the default P preconditioner is used
1130
1131 /// Control flag is true if the preconditioner has been setup
1132 /// (used so we can wipe the data when the preconditioner is
1133 /// called again)
1135
1136 /// Boolean to indicate that presence of elements that are not of
1137 /// type NavierStokesElementWithDiagonalMassMatrices is acceptable
1138 /// (suppresses warning that issued otherwise).
1140
1141 /// Helper function to assemble the inverse diagonals of the pressure
1142 /// and velocity mass matrices from the elemental contributions defined in
1143 /// NavierStokesEquations<DIM>.
1144 /// If do_both=true, both are computed, otherwise only the velocity
1145 /// mass matrix (the LSC version of the preconditioner only needs
1146 /// that one)
1150 const bool& do_both);
1151
1152 /// Boolean indicating whether the momentum system preconditioner
1153 /// is a block preconditioner
1155
1156 /// Set Doc_time to true for outputting results of timings
1158
1159 /// MatrixVectorProduct operator for Qv^{-1} Bt
1161
1162 /// MatrixVectorProduct operator for Bt
1164
1165 /// MatrixVectorProduct operator for F
1167
1168 /// MatrixVectorProduct operator for E = Fp Qp^{-1} (only for Fp variant)
1170
1171 /// the pointer to the mesh of block preconditionable Navier
1172 /// Stokes elements.
1174
1175 /// Flag to indicate if there are multiple element types in the
1176 /// Navier-Stokes mesh.
1178
1179 /// Boolean to indicate use of LSC (true) or Fp (false) variant
1181
1182 /// Use Robin BC elements for Fp preconditoner?
1184
1185 /// Map to store original eqn numbers of various Data values when
1186 /// assembling pressure advection diffusion matrix
1187 std::map<Data*, std::vector<int>> Eqn_number_backup;
1188
1189 /// Boolean indicating if we want to pin first pressure
1190 /// dof in Navier Stokes mesh when
1191 /// assembling the pressure advection diffusion system for
1192 /// Fp preconditoner -- needed at zero Reynolds number
1193 /// for non-enclosed flows but seems harmless in any case
1195
1196 /// Storage for the (non-const!) problem pointer for use in
1197 /// get_pressure_advection_diffusion_matrix().
1199 };
1200
1201
1202 ///////////////////////////////////////////////////////////////////////////////
1203 ///////////////////////////////////////////////////////////////////////////////
1204 ///////////////////////////////////////////////////////////////////////////////
1205
1206
1207 //============================================================================
1208 /// The exact Navier Stokes preconditioner. This extracts 2x2 blocks
1209 /// (corresponding to the velocity and pressure unknowns) and uses these to
1210 /// build a single preconditioner matrix for testing purposes.
1211 /// Iterative solvers should converge in a single step if this is used.
1212 /// If it doesn't something is wrong in the setup of the block matrices.
1213 //=============================================================================
1214 template<typename MATRIX>
1216 {
1217 public:
1218 /// Constructor - do nothing
1220
1221
1222 /// Destructor - do nothing
1224
1225
1226 /// Broken copy constructor
1228 delete;
1229
1230 /// Broken assignment operator
1231 /*void operator=(const NavierStokesExactPreconditioner&) = delete;*/
1232
1233 /// Setup the preconditioner
1234 void setup();
1235
1236
1237 /// Apply preconditioner to r
1239
1240 protected:
1241 /// Preconditioner matrix
1243 };
1244
1245} // namespace oomph
1246#endif
e
Definition cfortran.h:571
static char t char * s
Definition cfortran.h:568
cstr elem_len * i
Definition cfortran.h:603
A class that is used to define the functions used to assemble the elemental contributions to the resi...
Block Preconditioner base class. The block structure of the overall problem is determined from the Me...
const Mesh * mesh_pt(const unsigned &i) const
Access to i-th mesh (of the various meshes that contain block preconditionable elements of the same n...
A class for compressed row matrices. This is a distributable object.
Definition matrices.h:888
A class that represents a collection of data; each Data object may contain many different individual ...
Definition nodes.h:86
double * value_pt(const unsigned &i) const
Return the pointer to the i-the stored value. Typically this is required when direct access to the st...
Definition nodes.h:324
Information for documentation of results: Directory and file number to enable output in the form RESL...
std::string directory() const
Output directory.
unsigned & number()
Number used (e.g.) for labeling output files.
A vector in the mathematical sense, initially developed for linear algebra type applications....
unsigned dim() const
Return the spatial dimension of the element, i.e. the number of local coordinates required to paramet...
Definition elements.h:2615
unsigned nnode() const
Return the number of nodes.
Definition elements.h:2214
Node *& node_pt(const unsigned &n)
Return a pointer to the local node n.
Definition elements.h:2179
A class that is used to define the functions used to assemble the elemental contributions to the pres...
virtual ~FpPreconditionerAssemblyHandler()
Empty virtual destructor.
void get_jacobian(GeneralisedElement *const &elem_pt, Vector< double > &residuals, DenseMatrix< double > &jacobian)
Calculate the elemental Jacobian matrix "d equation / d variable" for elem_pt.
FpPreconditionerAssemblyHandler(const unsigned &ndim)
Constructor. Pass spatial dimension.
void get_residuals(GeneralisedElement *const &elem_pt, Vector< double > &residuals)
Return the contribution to the residuals of the element elem_pt.
Auxiliary Problem that can be used to assemble the pressure advection diffusion matrix needed by the ...
void get_pressure_advection_diffusion_jacobian(CRDoubleMatrix &jacobian)
Get the pressure advection diffusion Jacobian.
FpPressureAdvectionDiffusionProblem(Mesh *navier_stokes_mesh_pt, Problem *orig_problem_pt)
Constructor: Pass Navier-Stokes mesh and pointer to orig problem.
void pin_all_non_pressure_dofs(const bool &set_pressure_bc_for_validation=false)
Pin all non-pressure dofs and (if boolean flag is set to true also all pressure dofs along domain bou...
Problem * Orig_problem_pt
Pointer to orig problem (required so we can re-assign eqn numbers)
void doc_solution(DocInfo &doc_info)
Doc solution (only needed during development – kept alive in case validation is required during code ...
std::map< Data *, std::vector< int > > Eqn_number_backup
Map to store original equation numbers.
void reset_pin_status()
Reset pin status of all values.
void validate(DocInfo &doc_info)
Validate pressure advection diffusion problem and doc exact and computed solution in directory specif...
A Generalised Element class.
Definition elements.h:73
unsigned ndof() const
Return the number of equations/dofs in the element.
Definition elements.h:822
unsigned long eqn_number(const unsigned &ieqn_local) const
Return the global equation number corresponding to the ieqn_local-th local equation number.
Definition elements.h:691
Data *& internal_data_pt(const unsigned &i)
Return a pointer to i-th internal data object.
Definition elements.h:605
unsigned ninternal_data() const
Return the number of internal data objects.
Definition elements.h:810
Matrix vector product helper class - primarily a wrapper to Trilinos's Epetra matrix vector product m...
A general mesh class.
Definition mesh.h:67
FiniteElement * finite_element_pt(const unsigned &e) const
Upcast (downcast?) to FiniteElement (needed to access FiniteElement member functions).
Definition mesh.h:477
int face_index_at_boundary(const unsigned &b, const unsigned &e) const
For the e-th finite element on boundary b, return int to indicate the face_index of the face adjacent...
Definition mesh.h:904
unsigned nboundary_element(const unsigned &b) const
Return number of finite elements that are adjacent to boundary b.
Definition mesh.h:886
Node *& node_pt(const unsigned long &n)
Return pointer to global node n.
Definition mesh.h:440
FiniteElement * boundary_element_pt(const unsigned &b, const unsigned &e) const
Return pointer to e-th finite element on boundary b.
Definition mesh.h:848
void output_fct(std::ostream &outfile, const unsigned &n_plot, FiniteElement::SteadyExactSolutionFctPt)
Output a given Vector function at f(n_plot) points in each element.
Definition mesh.cc:2199
unsigned nboundary() const
Return number of boundaries.
Definition mesh.h:835
unsigned long nnode() const
Return number of nodes in the mesh.
Definition mesh.h:604
GeneralisedElement *& element_pt(const unsigned long &e)
Return pointer to element e.
Definition mesh.h:452
void output(std::ostream &outfile)
Output for all elements.
Definition mesh.cc:2027
unsigned long nelement() const
Return number of elements in the mesh.
Definition mesh.h:598
The exact Navier Stokes preconditioner. This extracts 2x2 blocks (corresponding to the velocity and p...
void setup()
Broken assignment operator.
NavierStokesExactPreconditioner(const NavierStokesExactPreconditioner &)=delete
Broken copy constructor.
void preconditioner_solve(const Vector< double > &r, Vector< double > &z)
Apply preconditioner to r.
The least-squares commutator (LSC; formerly BFBT) Navier Stokes preconditioner. It uses blocks corres...
bool Doc_time
Set Doc_time to true for outputting results of timings.
Preconditioner * F_preconditioner_pt
Pointer to the 'preconditioner' for the F matrix.
void validate(DocInfo &doc_info, Problem *orig_problem_pt)
Validate auxiliary pressure advection diffusion problem in 2D.
void use_fp()
Use Fp version of the preconditioner.
bool Accept_non_NavierStokesElementWithDiagonalMassMatrices_elements
Boolean to indicate that presence of elements that are not of type NavierStokesElementWithDiagonalMas...
Problem * Problem_pt
Storage for the (non-const!) problem pointer for use in get_pressure_advection_diffusion_matrix().
bool Preconditioner_has_been_setup
Control flag is true if the preconditioner has been setup (used so we can wipe the data when the prec...
bool Use_robin_for_fp
Use Robin BC elements for Fp preconditoner?
bool Pin_first_pressure_dof_in_press_adv_diff
Boolean indicating if we want to pin first pressure dof in Navier Stokes mesh when assembling the pre...
void set_problem_pt(Problem *problem_pt)
Broken assignment operator.
void disable_accept_non_NavierStokesElementWithDiagonalMassMatrices_elements()
Do not accept presence of elements that are not of type NavierStokesElementWithDiagonalMassMatrices w...
void set_p_preconditioner(Preconditioner *new_p_preconditioner_pt)
Function to set a new pressure matrix preconditioner (inexact solver)
void unpin_first_pressure_dof_in_press_adv_diff()
Set boolean indicating that we do not want to pin first pressure dof in Navier Stokes mesh when assem...
void clean_up_memory()
Helper function to delete preconditioner data.
Mesh * Navier_stokes_mesh_pt
the pointer to the mesh of block preconditionable Navier Stokes elements.
void set_p_exact_preconditioner()
Function to (re-)set pressure matrix preconditioner (inexact solver) to exact preconditioner.
MatrixVectorProduct * F_mat_vec_pt
MatrixVectorProduct operator for F.
MatrixVectorProduct * E_mat_vec_pt
MatrixVectorProduct operator for E = Fp Qp^{-1} (only for Fp variant)
bool Use_LSC
Boolean to indicate use of LSC (true) or Fp (false) variant.
bool Using_default_p_preconditioner
flag indicating whether the default P preconditioner is used
void set_f_exact_preconditioner()
Function to (re-)set momentum matrix preconditioner (inexact solver) to exact preconditioner.
MatrixVectorProduct * QBt_mat_vec_pt
MatrixVectorProduct operator for Qv^{-1} Bt.
bool Using_default_f_preconditioner
flag indicating whether the default F preconditioner is used
bool Allow_multiple_element_type_in_navier_stokes_mesh
Flag to indicate if there are multiple element types in the Navier-Stokes mesh.
Preconditioner * P_preconditioner_pt
Pointer to the 'preconditioner' for the pressure matrix.
void set_f_preconditioner(Preconditioner *new_f_preconditioner_pt)
Function to set a new momentum matrix preconditioner (inexact solver)
void assemble_inv_press_and_veloc_mass_matrix_diagonal(CRDoubleMatrix *&inv_p_mass_pt, CRDoubleMatrix *&inv_v_mass_pt, const bool &do_both)
Helper function to assemble the inverse diagonals of the pressure and velocity mass matrices from the...
NavierStokesSchurComplementPreconditioner(const NavierStokesSchurComplementPreconditioner &)=delete
Broken copy constructor.
void set_navier_stokes_mesh(Mesh *mesh_pt, const bool &allow_multiple_element_type_in_navier_stokes_mesh=false)
Specify the mesh containing the block-preconditionable Navier-Stokes elements. The optional argument ...
void get_pressure_advection_diffusion_matrix(CRDoubleMatrix &fp_matrix)
Get the pressure advection diffusion matrix.
NavierStokesSchurComplementPreconditioner(Problem *problem_pt)
Constructor - sets defaults for control flags.
void enable_robin_for_fp()
Use Robin BC elements for the Fp preconditioner.
bool F_preconditioner_is_block_preconditioner
Boolean indicating whether the momentum system preconditioner is a block preconditioner.
MatrixVectorProduct * Bt_mat_vec_pt
MatrixVectorProduct operator for Bt.
void preconditioner_solve(const DoubleVector &r, DoubleVector &z)
Apply preconditioner to Vector r.
void disable_robin_for_fp()
Don't use Robin BC elements for the Fp preconditioenr.
void use_lsc()
Use LSC version of the preconditioner.
std::map< Data *, std::vector< int > > Eqn_number_backup
Map to store original eqn numbers of various Data values when assembling pressure advection diffusion...
void enable_accept_non_NavierStokesElementWithDiagonalMassMatrices_elements()
Accept presence of elements that are not of type NavierStokesElementWithDiagonalMassMatrices without ...
void pin_first_pressure_dof_in_press_adv_diff()
Set boolean indicating that we want to pin first pressure dof in Navier Stokes mesh when assembling t...
Nodes are derived from Data, but, in addition, have a definite (Eulerian) position in a space of a gi...
Definition nodes.h:906
An OomphLibError object which should be thrown when an run-time error is encountered....
Preconditioner base class. Gives an interface to call all other preconditioners through and stores th...
virtual const OomphCommunicator * comm_pt() const
Get function for comm pointer.
virtual void setup()=0
Setup the preconditioner. Pure virtual generic interface function.
////////////////////////////////////////////////////////////////// //////////////////////////////////...
Definition problem.h:154
unsigned add_sub_mesh(Mesh *const &mesh_pt)
Add a submesh to the problem and return its number, i, by which it can be accessed via mesh_pt(i).
Definition problem.h:1350
unsigned long assign_eqn_numbers(const bool &assign_local_eqn_numbers=true)
Assign all equation numbers for problem: Deals with global data (= data that isn't attached to any el...
Definition problem.cc:2085
void get_first_and_last_element_for_assembly(Vector< unsigned > &first_el_for_assembly, Vector< unsigned > &last_el_for_assembly) const
Get first and last elements for parallel assembly of non-distributed problem.
Definition problem.h:1024
void flush_sub_meshes()
Flush the problem's collection of sub-meshes. Must be followed by call to rebuild_global_mesh().
Definition problem.h:1359
virtual void get_jacobian(DoubleVector &residuals, DenseDoubleMatrix &jacobian)
Return the fully-assembled Jacobian and residuals for the problem Interface for the case when the Jac...
Definition problem.cc:3935
void newton_solve()
Use Newton method to solve the problem.
Definition problem.cc:8816
void set_default_first_and_last_element_for_assembly()
Set default first and last elements for parallel assembly of non-distributed problem.
Definition problem.cc:1709
void set_first_and_last_element_for_assembly(Vector< unsigned > &first_el_for_assembly, Vector< unsigned > &last_el_for_assembly)
Manually set first and last elements for parallel assembly of non-distributed problem.
Definition problem.h:1008
unsigned nsub_mesh() const
Return number of submeshes.
Definition problem.h:1343
Mesh *& mesh_pt()
Return a pointer to the global mesh.
Definition problem.h:1300
AssemblyHandler *& assembly_handler_pt()
Return a pointer to the assembly handler object.
Definition problem.h:1590
bool distributed() const
If we have MPI return the "problem has been distributed" flag, otherwise it can't be distributed so r...
Definition problem.h:828
A Class for nodes that deform elastically (i.e. position is an unknown in the problem)....
Definition nodes.h:1686
TAdvectionDiffusionReactionElement<NREAGENT,DIM,NNODE_1D> elements are isoparametric triangular DIM-d...
Template-free base class for Navier-Stokes equations to avoid casting problems.
Preconditioner * create_exact_preconditioner()
Factory function to create suitable exact preconditioner.
void get_exact_u(const Vector< double > &x, Vector< double > &u)
Exact solution as a Vector.
double source_function(const Vector< double > &x_vect)
Source function required to make the solution above an exact solution.
void wind_function(const Vector< double > &x, Vector< double > &wind)
Wind.
double Peclet
Peclet number – overwrite with actual Reynolds number.
DRAIG: Change all instances of (SPATIAL_DIM) to (DIM-1).
OomphInfo oomph_info
Single (global) instantiation of the OomphInfo object – this is used throughout the library as a "rep...