mumps_solver.cc
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// Interface to MUMPS solver
27
28
29#ifdef OOMPH_HAS_MPI
30#include "mpi.h"
31#endif
32
33
34#include <iostream>
35#include <vector>
36
37
38// oomph-lib headers
39#include "mumps_solver.h"
40#include "Vector.h"
41#include "oomph_utilities.h"
42#include "problem.h"
43
44
45namespace oomph
46{
47 //////////////////////////////////////////////////////////////////////////
48 //////////////////////////////////////////////////////////////////////////
49 //////////////////////////////////////////////////////////////////////////
50
51
52 //=========================================================================
53 /// Default factor for workspace -- static so it can be overwritten
54 /// globally.
55 //=========================================================================
57
58
59 //=========================================================================
60 /// Static warning to suppress warnings about incorrect distribution of
61 /// RHS vector. Default is false
62 //=========================================================================
64 false;
65
66 //=============================================================================
67 /// Constructor: Call setup
68 //=============================================================================
70 : Suppress_solve(false),
71 Doc_stats(false),
72 Suppress_warning_about_MPI_COMM_WORLD(false),
73 Suppress_mumps_info_during_solve(false),
74 Mumps_is_initialised(false),
75 Workspace_scaling_factor(Default_workspace_scaling_factor),
76 Delete_matrix_data(false),
77 Mumps_struc_pt(nullptr),
78 Jacobian_symmetry_flag(MumpsJacobianSymmetryFlags::Unsymmetric),
79 Jacobian_ordering_flag(MumpsJacobianOrderingFlags::Metis_ordering)
80 {
81 }
82
83 //=============================================================================
84 /// Initialise instance of mumps data structure
85 //=============================================================================
87 {
88 // Make new instance of Mumps data structure
90
91 // Mumps' hack to indicate that mpi_comm_world is used. Conversion of any
92 // other communicators appears to be non-portable, so we simply
93 // issue a warning if we later discover that oomph-lib's communicator
94 // is not MPI_COMM_WORLD
95 Mumps_struc_pt->comm_fortran = -987654;
96
97 // Root processor participates in solution
98 Mumps_struc_pt->par = 1;
99
100 // Set matrix symmetry properties
101 // (unsymmetric / symmetric positive definite / general symmetric)
103
104 // First call does the initialise phase
105 Mumps_struc_pt->job = -1;
106
107 // Call c interface to double precision mumps to initialise
110
111 // Output stream for global info on host. Negative value suppresses printing
112 Mumps_struc_pt->ICNTL(3) = -1;
113
114 // Only show error messages and stats
115 // (4 for full doc; creates huge amount of output)
116 Mumps_struc_pt->ICNTL(4) = 2;
117
118 // Write matrix
119 // snprintf(Mumps_struc_pt->write_problem,
120 // sizeof(Mumps_struc_pt->write_problem), "/work/e173/e173/mheil/matrix");
121
122 // Assembled matrix (rather than element-by_element)
123 Mumps_struc_pt->ICNTL(5) = 0;
124
125 // are we doing parallel ordering?
127 {
128 // set parallel computation
129 Mumps_struc_pt->ICNTL(28) = 2;
130
131 // PT-SCOTCH magic number
132 Mumps_struc_pt->ICNTL(29) = 1;
133 }
135 {
136 // set parallel computation
137 Mumps_struc_pt->ICNTL(28) = 2;
138
139 // ParMETIS magic number
140 Mumps_struc_pt->ICNTL(29) = 2;
141 }
142 else
143 {
144 // set the package to use for ordering during (sequential) analysis
146 }
147
148 // Distributed problem with user-specified distribution
149 Mumps_struc_pt->ICNTL(18) = 3;
150
151 // Dense RHS
152 Mumps_struc_pt->ICNTL(20) = 0;
153
154 // Non-distributed solution
155 Mumps_struc_pt->ICNTL(21) = 0;
156 }
157
158
159 //=============================================================================
160 /// Shutdown mumps
161 //=============================================================================
163 {
165 {
166 // Shut down flag
167 Mumps_struc_pt->job = -2;
168
169 // Call c interface to double precision mumps to shut down
171
172 // Cleanup
173 delete Mumps_struc_pt;
174 Mumps_struc_pt = 0;
175
176 Mumps_is_initialised = false;
177
178 // Cleanup storage
179 Irn_loc.clear();
180 Jcn_loc.clear();
181 A_loc.clear();
182 }
183 }
184
185
186 //=============================================================================
187 /// Destructor: Shutdown mumps
188 //=============================================================================
193
194
195 //=============================================================================
196 /// LU decompose the matrix addressed by matrix_pt using
197 /// mumps. The resulting matrix factors are stored internally.
198 /// Note: if Delete_matrix_data is true the function
199 /// matrix_pt->clean_up_memory() will be used to wipe the matrix data.
200 //=============================================================================
202 {
203 // Initialise timer
204 double t_start = TimingHelpers::timer();
205
206 // set the distribution
208 dynamic_cast<DistributableLinearAlgebraObject*>(matrix_pt);
209 if (dist_matrix_pt)
210 {
211 // the solver has the same distribution as the matrix if possible
212 this->build_distribution(dist_matrix_pt->distribution_pt());
213 }
214 else
215 {
216 throw OomphLibError("Matrix must be distributable",
219 }
220
221
222 // Check that we have a square matrix
223#ifdef PARANOID
224 int n = matrix_pt->nrow();
225 int m = matrix_pt->ncol();
226 if (n != m)
227 {
228 std::ostringstream error_message_stream;
229 error_message_stream << "Can only solve for square matrices\n"
230 << "N, M " << n << " " << m << std::endl;
231
235 }
236#ifdef OOMPH_HAS_MPI
238 {
239 if (this->distribution_pt()->communicator_pt()->mpi_comm() !=
241 {
242 std::ostringstream error_message_stream;
244 << "Warning: Mumps wrapper assumes that communicator is "
245 "MPI_COMM_WORLD\n"
246 << " which is not the case, so mumps may die...\n"
247 << " If it does initialise oomph-lib's mpi without "
248 "requesting\n"
249 << " the communicator to be a duplicate of MPI_COMM_WORLD\n"
250 << " (done via an optional boolean to "
251 "MPI_Helpers::init(...)\n\n"
252 << " (You can suppress this warning by recompiling without\n"
253 << " paranoia or calling \n\n"
254 << " "
255 "MumpsSolver::enable_suppress_warning_about_MPI_COMM_WORLD()\n\n"
256 << " \n";
258 "MumpsSolver::factorise()",
260 }
261 }
262#endif
263
264#endif
265
266 // Initialise
268 {
270 }
272
273
274 // Doc stats?
275 if (Doc_stats)
276 {
277 // Output stream for global info on host. Negative value suppresses
278 // printing
279 Mumps_struc_pt->ICNTL(3) = 6;
280 }
281
282 // number of processors
283 unsigned nproc = 1;
284 if (dist_matrix_pt != 0)
285 {
286 nproc = dist_matrix_pt->distribution_pt()->communicator_pt()->nproc();
287 }
288
289 // Is it a CRDoubleMatrix?
290 CRDoubleMatrix* cr_matrix_pt = dynamic_cast<CRDoubleMatrix*>(matrix_pt);
291 if (cr_matrix_pt != 0)
292 {
293#ifdef PARANOID
294 // paranoid check that the matrix has been set up
295 if (!cr_matrix_pt->built())
296 {
297 throw OomphLibError(
298 "To apply MumpsSolver to a CRDoubleMatrix - it must be built",
301 }
302#endif
303
304 // if the matrix is distributed then set up solver
305 if ((nproc == 1) || (cr_matrix_pt->distributed()))
306 {
308
309 // Find the number of rows and non-zero entries in the matrix
310 const int nnz_loc = int(cr_matrix_pt->nnz());
311 const int n = matrix_pt->nrow();
312
313 // Create mumps storage
314
315 // Create vector for row numbers
316 Irn_loc.resize(nnz_loc);
317
318 // Create vector for column numbers
319 Jcn_loc.resize(nnz_loc);
320
321 // Vector for entries
322 A_loc.resize(nnz_loc);
323
324 // First row held on this processor
325 int first_row = cr_matrix_pt->first_row();
326
327 // Copy into coordinate storage scheme using pointer arithmetic
328 double* matrix_value_pt = cr_matrix_pt->value();
329 int* matrix_index_pt = cr_matrix_pt->column_index();
330 int* matrix_start_pt = cr_matrix_pt->row_start();
331 int i_row = 0;
332
333 // is the matrix symmetric? If so, we must only provide
334 // MUMPS with the upper (or lower) triangular part of the Jacobian
336 {
337 oomph_info << "Assuming Jacobian matrix is symmetric "
338 << "(passing MUMPS the upper triangular part)"
339 << std::endl;
340 }
341
342 for (int count = 0; count < nnz_loc; count++)
343 {
346 if (count < matrix_start_pt[i_row + 1])
347 {
348 Irn_loc[count] = first_row + i_row + 1;
349 }
350 else
351 {
352 i_row++;
353 Irn_loc[count] = first_row + i_row + 1;
354 }
355
356 // only pass the upper triangular part (and diagonal)
357 // if we have a symmetric matrix (MUMPS sums values,
358 // so need to set the lwoer triangle to zero)
359 if ((Mumps_struc_pt->sym !=
362 {
363 A_loc[count] = 0.0;
364 }
365 }
366
367 // Now delete the matrix if we are allowed
368 if (Delete_matrix_data == true)
369 {
370 cr_matrix_pt->clear();
371 }
372
373 if ((Doc_time) &&
374 (this->distribution_pt()->communicator_pt()->my_rank() == 0))
375 {
377 oomph_info << "Time for copying matrix into MumpsSolver data "
378 "structure : "
381 << std::endl;
382 }
383
384 // Call mumps factorisation
385 //-------------------------
386
387 // Specify size of system
388 Mumps_struc_pt->n = n;
389
390 // Number of nonzeroes
391 Mumps_struc_pt->nz_loc = nnz_loc;
392
393 // The entries
394 Mumps_struc_pt->irn_loc = &Irn_loc[0];
395 Mumps_struc_pt->jcn_loc = &Jcn_loc[0];
396 Mumps_struc_pt->a_loc = &A_loc[0];
397
399
400 // Do analysis
401 Mumps_struc_pt->job = 1;
403
404
405 if ((Doc_time) &&
406 (this->distribution_pt()->communicator_pt()->my_rank() == 0))
407 {
410 << "Time for mumps analysis stage in MumpsSolver : "
413 << "\n(Ordering generated ";
414
415 // did MUMPS select parallel analysis?
416 if (Mumps_struc_pt->INFOG(32) == 2)
417 {
418 oomph_info << "in parallel using: ";
419 switch (Mumps_struc_pt->INFOG(7))
420 {
422 oomph_info << "PT-SCOTCH";
423 break;
424
426 oomph_info << "ParMETIS";
427 break;
428 }
429 }
430 else
431 {
432 oomph_info << "sequentially using: ";
433
434 // options for sequential analysis
435 switch (Mumps_struc_pt->INFOG(7))
436 {
438 oomph_info << "SCOTCH";
439 break;
440
442 oomph_info << "PORD";
443 break;
444
446 oomph_info << "METIS";
447 break;
448
449 default:
450 oomph_info << Mumps_struc_pt->INFOG(7);
451 }
452 }
453
454 oomph_info << ")" << std::endl;
455 }
456
457
458 int my_rank = this->distribution_pt()->communicator_pt()->my_rank();
459
460 // Document estimate for size of workspace
461 if (my_rank == 0)
462 {
464 {
465 oomph_info << "Estimated max. workspace in MB: "
466 << Mumps_struc_pt->INFOG(26) << std::endl;
467 }
468 }
469
471
472 // Loop until successfully factorised
473 bool factorised = false;
474 while (!factorised)
475 {
476 // Set workspace to multiple of that -- ought to be "significantly
477 // larger than infog(26)", according to the manual :(
478 Mumps_struc_pt->ICNTL(23) =
480
482 {
483 oomph_info << "Attempting factorisation with workspace estimate: "
484 << Mumps_struc_pt->ICNTL(23) << " MB\n";
485 oomph_info << "corresponding to Workspace_scaling_factor = "
486 << Workspace_scaling_factor << "\n";
487 }
488
489 // Do factorisation
490 Mumps_struc_pt->job = 2;
492
493 // Check for error
494 if (Mumps_struc_pt->INFOG(1) != 0)
495 {
497 {
498 oomph_info << "Error during mumps factorisation!\n";
499 }
500
501 std::ostringstream error_message_stream;
502
503 switch (Mumps_struc_pt->INFOG(1))
504 {
506
507 error_message_stream << "Structurally singular matrix\n";
508
512
514
515 error_message_stream << "Numerically singular matrix\n";
516
520
522
523 // Increase scaling factor for workspace and run again
525
527 {
528 oomph_info << "Increasing workspace_scaling_factor to "
529 << Workspace_scaling_factor << std::endl;
530 }
531 break;
532
533 default:
535 << "MUMPS error codes: " << Mumps_struc_pt->INFO(1) << " "
536 << Mumps_struc_pt->INFO(2) << std::endl;
537
541 }
542 }
543 else
544 {
545 factorised = true;
546 }
547 }
548
549
550 if ((Doc_time) &&
551 (this->distribution_pt()->communicator_pt()->my_rank() == 0))
552 {
554 oomph_info << "Time for actual mumps factorisation in MumpsSolver"
555 " : "
558 << std::endl;
559 }
560 }
561 // else the CRDoubleMatrix is not distributed
562 else
563 {
564 std::ostringstream error_message_stream;
565 error_message_stream << "MumpsSolver only works for a "
566 << " distributed CRDoubleMatrix\n";
570 }
571 }
572 // Otherwise throw an error
573 else
574 {
575 std::ostringstream error_message_stream;
576 error_message_stream << "MumpsSolver implemented only for "
577 << "distributed CRDoubleMatrix. \n";
581 }
582
583
584 if ((Doc_time) &&
585 (this->distribution_pt()->communicator_pt()->my_rank() == 0))
586 {
587 double t_end = TimingHelpers::timer();
588 oomph_info << "Time for MumpsSolver factorisation : "
590 t_start)
591 << std::endl;
592 }
593
594 // Switch off docing again by setting output stream for global info on
595 // to negative number
596 Mumps_struc_pt->ICNTL(3) = -1;
597 }
598
599 //=============================================================================
600 /// Do the backsubstitution for mumps solver.
601 /// This does not make any assumption about the distribution of the
602 /// vectors
603 //=============================================================================
605 {
606 double t_start = TimingHelpers::timer();
607
608#ifdef PARANOID
609#ifdef OOMPH_HAS_MPI
611 {
612 if (this->distribution_pt()->communicator_pt()->mpi_comm() !=
614 {
615 std::ostringstream error_message_stream;
617 << "Warning: Mumps wrapper assumes that communicator is "
618 "MPI_COMM_WORLD\n"
619 << " which is not the case, so mumps may die...\n"
620 << " If it does initialise oomph-lib's mpi without "
621 "requesting\n"
622 << " the communicator to be a duplicate of MPI_COMM_WORLD\n"
623 << " (done via an optional boolean to "
624 "MPI_Helpers::init(...)\n\n"
625 << " (You can suppress this warning by recompiling without\n"
626 << " paranoia or calling \n\n"
627 << " "
628 "MumpsSolver::enable_suppress_warning_about_MPI_COMM_WORLD()\n\n"
629 << " \n";
631 "MumpsSolver::backsub()",
633 }
634 }
635#endif
636
637 // Initialised?
639 {
640 std::ostringstream error_message_stream;
641 error_message_stream << "Mumps has not been initialised.";
645 }
646
647 // check that the rhs vector is setup
648 if (!rhs.distribution_pt()->built())
649 {
650 std::ostringstream error_message_stream;
651 error_message_stream << "The vectors rhs must be setup";
655 }
656
657#endif
658
659 // Check that the rhs distribution is the same as the distribution as this
660 // solver. If not redistribute and issue a warning
662 if (!(*rhs.distribution_pt() == *this->distribution_pt()))
663 {
665 {
666 std::ostringstream warning_stream;
667 warning_stream << "The distribution of rhs vector does not match that "
668 "of the solver.\n";
670 << "The rhs may have to be redistributed but we're not doing this "
671 "because\n"
672 << "I'm no longer convinced it's necessary. Keep an eye on this...\n";
674 << "To remove this warning you can either:\n"
675 << " i) Ensure that the rhs vector has the correct distribution\n"
676 << " before calling the resolve() function\n"
677 << "or ii) Set the flag \n"
678 << " MumpsSolver::Suppress_incorrect_rhs_distribution_warning_in_"
679 "resolve\n"
680 << " to be true\n\n";
681
683 "MumpsSolver::resolve()",
685 }
686
687 // //Have to cast away const-ness (which tells us that we shouldn't really
688 // //be doing this!)
689 // const_cast<DoubleVector&>(rhs).redistribute(this->distribution_pt());
690 }
691
692
693#ifdef PARANOID
694 // if the result vector is setup then check it has the same distribution
695 // as the rhs
696 if (result.distribution_built())
697 {
698 if (!(*result.distribution_pt() == *rhs.distribution_pt()))
699 {
700 std::ostringstream error_message_stream;
702 << "The result vector distribution has been setup; it must have the "
703 << "same distribution as the rhs vector.";
707 }
708 }
709#endif
710
711
712 // Doc stats?
713 if (Doc_stats)
714 {
715 // Output stream for global info on host. Negative value suppresses
716 // printing
717 Mumps_struc_pt->ICNTL(3) = 6;
718 }
719
720 // number of DOFs
721 int ndof = this->distribution_pt()->nrow();
722
723 // Make backup to avoid over-writing
725 tmp_rhs = rhs;
726
727 // Now turn this into a global (non-distributed) vector
728 // because that's what mumps needs
729
730 // Make a global distribution (i.e. one that isn't distributed)
732 this->distribution_pt()->communicator_pt(), ndof, false);
733
734 // Redistribute the tmp_rhs vector with this distribution -- it's
735 // now "global", as required for mumps
736 tmp_rhs.redistribute(&global_distribution);
737
738 // Do the backsubsitution phase -- overwrites the tmp_rhs vector with the
739 // solution
740 Mumps_struc_pt->rhs = &tmp_rhs[0];
741 Mumps_struc_pt->job = 3;
743
744 // Copy back
745 unsigned n = Mumps_struc_pt->n;
746 for (unsigned j = 0; j < n; j++)
747 {
748 tmp_rhs[j] = Mumps_struc_pt->rhs[j];
749 }
750
751#ifdef OOMPH_HAS_MPI
752 // Broadcast the result which is only held on root
753 MPI_Bcast(&tmp_rhs[0],
754 ndof,
756 0,
757 this->distribution_pt()->communicator_pt()->mpi_comm());
758#endif
759
760 // If the result vector is distributed, re-distribute the
761 // non-distributed tmp_rhs vector to match
762 if (result.built())
763 {
764 tmp_rhs.redistribute(result.distribution_pt());
765 }
766 else
767 {
768 tmp_rhs.redistribute(this->distribution_pt());
769 }
770
771 // Now copy the tmp_rhs vector into the (matching) result
772 result = tmp_rhs;
773
774 if ((Doc_time) &&
775 (this->distribution_pt()->communicator_pt()->my_rank() == 0))
776 {
777 double t_end = TimingHelpers::timer();
778 oomph_info << "Time for MumpsSolver backsub : "
780 t_start)
781 << std::endl;
782 }
783
784 // Switch off docing again by setting output stream for global info on
785 // to negative number
786 Mumps_struc_pt->ICNTL(3) = -1;
787 }
788
789 //=========================================================================
790 /// Clean up the memory allocated for the MumpsSolver solver
791 //=========================================================================
796
797
798 //=========================================================================
799 /// Linear-algebra-type solver: Takes pointer to a matrix and rhs
800 /// vector and returns the solution of the linear system. Problem pointer
801 /// defaults to NULL and can be omitted. The function returns the global
802 /// result vector. Matrix must be CRDoubleMatrix.
803 /// Note: if Delete_matrix_data is true the function
804 /// matrix_pt->clean_up_memory() will be used to wipe the matrix data.
805 //=========================================================================
806 void MumpsSolver::solve(DoubleMatrixBase* const& matrix_pt,
807 const DoubleVector& rhs,
809 {
810#ifdef PARANOID
811#ifdef OOMPH_HAS_MPI
813 {
814 if (dynamic_cast<DistributableLinearAlgebraObject*>(matrix_pt)
816 ->communicator_pt()
818 {
819 std::ostringstream error_message_stream;
821 << "Warning: Mumps wrapper assumes that communicator is "
822 "MPI_COMM_WORLD\n"
823 << " which is not the case, so mumps may die...\n"
824 << " If it does initialise oomph-lib's mpi without "
825 "requesting\n"
826 << " the communicator to be a duplicate of MPI_COMM_WORLD\n"
827 << " (done via an optional boolean to "
828 "MPI_Helpers::init(...)\n\n"
829 << " (You can suppress this warning by recompiling without\n"
830 << " paranoia or calling \n\n"
831 << " "
832 "MumpsSolver::enable_suppress_warning_about_MPI_COMM_WORLD()\n\n"
833 << " \n";
835 "MumpsSolver::solve()",
837 }
838 }
839#endif
840#endif
841
842 // Initialise timer
843 double t_start = TimingHelpers::timer();
844
845#ifdef PARANOID
846 // check that the rhs vector is setup
847 if (!rhs.distribution_pt()->built())
848 {
849 std::ostringstream error_message_stream;
850 error_message_stream << "The vectors rhs must be setup";
854 }
855
856 // check that the matrix is square
857 if (matrix_pt->nrow() != matrix_pt->ncol())
858 {
859 std::ostringstream error_message_stream;
860 error_message_stream << "The matrix at matrix_pt must be square.";
864 }
865
866 // check that the matrix and the rhs vector have the same nrow()
867 if (matrix_pt->nrow() != rhs.nrow())
868 {
869 std::ostringstream error_message_stream;
871 << "The matrix and the rhs vector must have the same number of rows.";
875 }
876
877
878 // if the matrix is distributable then should have the same distribution
879 // as the rhs vector
881 dynamic_cast<DistributableLinearAlgebraObject*>(matrix_pt);
882 if (ddist_matrix_pt != 0)
883 {
884 if (!(*ddist_matrix_pt->distribution_pt() == *rhs.distribution_pt()))
885 {
886 std::ostringstream error_message_stream;
888 << "The matrix matrix_pt must have the same distribution as the "
889 << "rhs vector.";
893 }
894 }
895 // if the matrix is not distributable then it the rhs vector should not be
896 // distributed
897 else
898 {
899 if (rhs.distribution_pt()->distributed())
900 {
901 std::ostringstream error_message_stream;
903 << "The matrix (matrix_pt) is not distributable and therefore the rhs"
904 << " vector must not be distributed";
908 }
909 }
910 // if the result vector is setup then check it has the same distribution
911 // as the rhs
912 if (result.built())
913 {
914 if (!(*result.distribution_pt() == *rhs.distribution_pt()))
915 {
916 std::ostringstream error_message_stream;
918 << "The result vector distribution has been setup; it must have the "
919 << "same distribution as the rhs vector.";
923 }
924 }
925
926#endif
927
928
929 // set the distribution
931 dynamic_cast<DistributableLinearAlgebraObject*>(matrix_pt);
932 if (dist_matrix_pt)
933 {
934 // the solver has the same distribution as the matrix if possible
935 this->build_distribution(dist_matrix_pt->distribution_pt());
936 }
937 else
938 {
939 // the solver has the same distribution as the RHS
941 }
942
943 // Factorise the matrix
944 factorise(matrix_pt);
945
946 // Now do the back solve
948
949 // Doc time for solve
950 double t_end = TimingHelpers::timer();
952
953 if ((Doc_time) &&
954 (this->distribution_pt()->communicator_pt()->my_rank() == 0))
955 {
956 oomph_info << "Time for MumpsSolver solve : "
958 t_start)
959 << std::endl;
960 }
961
962 // Switch off docing again by setting output stream for global info on
963 // to negative number
964 Mumps_struc_pt->ICNTL(3) = -1;
965
966 // If we are not storing the solver data for resolves, delete it
967 if (!Enable_resolve)
968 {
970 }
971 }
972
973 //==================================================================
974 /// Solver: Takes pointer to problem and returns the results Vector
975 /// which contains the solution of the linear system defined by
976 /// the problem's fully assembled Jacobian and residual Vector.
977 //==================================================================
979 {
980#ifdef PARANOID
981#ifdef OOMPH_HAS_MPI
983 {
984 if (problem_pt->communicator_pt()->mpi_comm() != MPI_COMM_WORLD)
985 {
986 std::ostringstream error_message_stream;
988 << "Warning: Mumps wrapper assumes that communicator is "
989 "MPI_COMM_WORLD\n"
990 << " which is not the case, so mumps may die...\n"
991 << " If it does initialise oomph-lib's mpi without "
992 "requesting\n"
993 << " the communicator to be a duplicate of MPI_COMM_WORLD\n"
994 << " (done via an optional boolean to "
995 "MPI_Helpers::init(...)\n\n"
996 << " (You can suppress this warning by recompiling without\n"
997 << " paranoia or calling \n\n"
998 << " "
999 "MumpsSolver::enable_suppress_warning_about_MPI_COMM_WORLD()\n\n"
1000 << " \n";
1002 "MumpsSolver::solve()",
1004 }
1005 }
1006#endif
1007#endif
1008
1009 // Initialise timer
1010 double t_start = TimingHelpers::timer();
1011
1012 // number of dofs
1013 unsigned n_dof = problem_pt->ndof();
1014
1015 // Set the distribution for the solver.
1016 this->distribution_pt()->build(problem_pt->communicator_pt(), n_dof);
1017
1018 // Take a copy of Delete_matrix_data
1020
1021 // Set Delete_matrix to true
1022 Delete_matrix_data = true;
1023
1024 // Initialise timer
1026
1027 // Storage for the distributed residuals vector
1029
1030 // Get the sparse jacobian and residuals of the problem
1031 CRDoubleMatrix jacobian(this->distribution_pt());
1032 problem_pt->get_jacobian(residuals, jacobian);
1033
1034 // Doc time for setup
1035 double t_end = TimingHelpers::timer();
1037 int my_rank = this->distribution_pt()->communicator_pt()->my_rank();
1038 if ((Doc_time) && (my_rank == 0))
1039 {
1040 oomph_info << "Time to set up CRDoubleMatrix Jacobian : "
1043 << std::endl;
1044 }
1045
1046
1047 // Now call the linear algebra solve, if desired
1048 if (!Suppress_solve)
1049 {
1050 // If the distribution of the result has been build and
1051 // does not match that of
1052 // the solver then redistribute before the solve and return
1053 // to the incoming distribution afterwards.
1054 if ((result.built()) &&
1055 (!(*result.distribution_pt() == *this->distribution_pt())))
1056 {
1058 result.build(this->distribution_pt(), 0.0);
1059 solve(&jacobian, residuals, result);
1060 result.redistribute(&temp_global_dist);
1061 }
1062 else
1063 {
1064 solve(&jacobian, residuals, result);
1065 }
1066 }
1067
1068 // Set Delete_matrix back to original value
1070
1071 // Finalise/doc timings
1072 if ((Doc_time) && (my_rank == 0))
1073 {
1074 double t_end = TimingHelpers::timer();
1075 oomph_info << "Total time for MumpsSolver "
1076 << "(np="
1077 << this->distribution_pt()->communicator_pt()->nproc()
1078 << ",N=" << problem_pt->ndof() << ") : "
1080 t_start)
1081 << std::endl;
1082 }
1083 }
1084
1085
1086 //===============================================================
1087 /// Resolve the system defined by the last assembled jacobian
1088 /// and the specified rhs vector if resolve has been enabled.
1089 /// Note: returns the global result Vector.
1090 //===============================================================
1092 {
1093#ifdef PARANOID
1094#ifdef OOMPH_HAS_MPI
1096 {
1097 if (this->distribution_pt()->communicator_pt()->mpi_comm() !=
1099 {
1100 std::ostringstream error_message_stream;
1102 << "Warning: Mumps wrapper assumes communicator is MPI_COMM_WORLD\n"
1103 << " which is not the case, so mumps may die...\n"
1104 << " If it does initialise oomph-lib's mpi without "
1105 "requesting\n"
1106 << " the communicator to be a duplicate of MPI_COMM_WORLD\n"
1107 << " (done via an optional boolean to "
1108 "MPI_Helpers::init(...)\n\n"
1109 << " (You can suppress this warning by recompiling without\n"
1110 << " paranoia or calling\n\n"
1111 << " "
1112 "MumpsSolver::enable_suppress_warning_about_MPI_COMM_WORLD()\n\n"
1113 << " \n";
1115 "MumpsSolver::resolve()",
1117 }
1118 }
1119#endif
1120#endif
1121
1122 // Store starting time for solve
1123 double t_start = TimingHelpers::timer();
1124
1125 // Doc stats?
1126 if (Doc_stats)
1127 {
1128 // Output stream for global info on host. Negative value suppresses
1129 // printing
1130 Mumps_struc_pt->ICNTL(3) = 6;
1131 }
1132
1133 // Now do the back substitution phase
1134 backsub(rhs, result);
1135
1136 // Doc time for solve
1137 double t_end = TimingHelpers::timer();
1139
1140 // Switch off docing again by setting output stream for global info on
1141 // to negative number
1142 Mumps_struc_pt->ICNTL(3) = -1;
1143
1144 if ((Doc_time) &&
1145 (this->distribution_pt()->communicator_pt()->my_rank() == 0))
1146 {
1147 oomph_info << "Time for MumpsSolver solve: "
1149 t_start)
1150 << std::endl;
1151 }
1152 }
1153
1154
1155} // namespace oomph
A class for compressed row matrices. This is a distributable object.
Definition matrices.h:888
Base class for any linear algebra object that is distributable. Just contains storage for the LinearA...
unsigned first_row() const
access function for the first row on this processor
LinearAlgebraDistribution * distribution_pt() const
access to the LinearAlgebraDistribution
void build_distribution(const LinearAlgebraDistribution *const dist_pt)
setup the distribution of this distributable linear algebra object
Abstract base class for matrices of doubles – adds abstract interfaces for solving,...
Definition matrices.h:261
virtual unsigned long ncol() const =0
Return the number of columns of the matrix.
virtual unsigned long nrow() const =0
Return the number of rows of the matrix.
A vector in the mathematical sense, initially developed for linear algebra type applications....
Describes the distribution of a distributable linear algebra type object. Typically this is a contain...
OomphCommunicator * communicator_pt() const
const access to the communicator pointer
void build(const OomphCommunicator *const comm_pt, const unsigned &first_row, const unsigned &nrow_local, const unsigned &nrow=0)
Sets the distribution. Takes first_row, nrow_local and nrow as arguments. If nrow is not provided or ...
unsigned nrow() const
access function to the number of global rows.
bool Doc_time
Boolean flag that indicates whether the time taken.
bool Enable_resolve
Boolean that indicates whether the matrix (or its factors, in the case of direct solver) should be st...
double Jacobian_setup_time
Jacobian setup time.
DMUMPS_STRUC_C * Mumps_struc_pt
Pointer to MUMPS struct that contains the solver data.
~MumpsSolver()
Destructor: Cleanup.
unsigned Jacobian_ordering_flag
stores an integer from the public enum which specifies which package (PORD, Metis or SCOTCH) is used ...
bool Mumps_is_initialised
Has mumps been initialised?
bool Suppress_warning_about_MPI_COMM_WORLD
Boolean to suppress warning about communicator not equal to MPI_COMM_WORLD.
Vector< int > Jcn_loc
Vector< double > A_loc
void shutdown_mumps()
Shutdown mumps.
MumpsJacobianOrderingFlags
ordering library to use for serial analysis; magic numbers as defined by MUMPS documentation
double Solution_time
Solution time.
unsigned Workspace_scaling_factor
void resolve(const DoubleVector &rhs, DoubleVector &result)
Resolve the system defined by the last assembled Jacobian and the specified rhs vector if resolve has...
bool Suppress_solve
Suppress solve?
bool Delete_matrix_data
Delete_matrix_data flag. MumpsSolver needs its own copy of the input matrix, therefore a copy must be...
bool Doc_stats
Set to true for MumpsSolver to output statistics (false by default).
void backsub(const DoubleVector &rhs, DoubleVector &result)
Do the backsubstitution for mumps solver Note: returns the global result Vector.
Vector< int > Irn_loc
Vector for row numbers.
static bool Suppress_incorrect_rhs_distribution_warning_in_resolve
Static flag that determines whether the warning about incorrect distribution of RHSs will be printed ...
unsigned Jacobian_symmetry_flag
symmetry of the Jacobian matrix we're solving; takes one of the enum values above
MumpsSolver()
Constructor: Call setup.
bool Suppress_mumps_info_during_solve
Boolean to suppress info being printed to screen during MUMPS solve.
static int Default_workspace_scaling_factor
Default factor for workspace – static so it can be overwritten globally.
void clean_up_memory()
Clean up the memory allocated by the mumps solver.
void solve(Problem *const &problem_pt, DoubleVector &result)
Solver: Takes pointer to problem and returns the results Vector which contains the solution of the li...
void initialise_mumps()
Initialise instance of mumps data structure.
void factorise(DoubleMatrixBase *const &matrix_pt)
Do the factorisation stage Note: if Delete_matrix_data is true the function matrix_pt->clean_up_memor...
MumpsJacobianSymmetryFlags
values of the SYM variable used by the MUMPS solver which dictates the symmetry properties of the Jac...
An OomphLibError object which should be thrown when an run-time error is encountered....
An OomphLibWarning object which should be created as a temporary object to issue a warning....
////////////////////////////////////////////////////////////////// //////////////////////////////////...
Definition problem.h:154
unsigned long ndof() const
Return the number of dofs.
Definition problem.h:1704
OomphCommunicator * communicator_pt()
access function to the oomph-lib communicator
Definition problem.h:1266
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
TAdvectionDiffusionReactionElement<NREAGENT,DIM,NNODE_1D> elements are isoparametric triangular DIM-d...
double timer()
returns the time in seconds after some point in past
std::string convert_secs_to_formatted_string(const double &time_in_sec)
Returns a nicely formatted string from an input time in seconds; the format depends on the size of ti...
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...