HermesCommon  2.0
mumps_solver.cpp
Go to the documentation of this file.
1 // This file is part of HermesCommon
2 //
3 // Copyright (c) 2009 hp-FEM group at the University of Nevada, Reno (UNR).
4 // Email: hpfem-group@unr.edu, home page: http://hpfem.org/.
5 //
6 // Hermes2D is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published
8 // by the Free Software Foundation; either version 2 of the License,
9 // or (at your option) any later version.
10 //
11 // Hermes2D is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with Hermes2D; if not, write to the Free Software
18 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 #include "config.h"
23 #ifdef WITH_MUMPS
24 #include "mumps_solver.h"
25 #include "callstack.h"
26 
27 namespace Hermes
28 {
29  namespace Algebra
30  {
31  extern "C"
32  {
33  extern void dmumps_c(DMUMPS_STRUC_C *mumps_param_ptr);
34  extern void zmumps_c(ZMUMPS_STRUC_C *mumps_param_ptr);
35  }
36 
37 #define USE_COMM_WORLD -987654
38 
45  static int find_position(int *Ai, int Alen, int idx)
46  {
47  assert(idx >= 0);
48 
49  register int lo = 0, hi = Alen - 1, mid;
50 
51  while (1)
52  {
53  mid = (lo + hi) >> 1;
54 
55  if(idx < Ai[mid]) hi = mid - 1;
56  else if(idx > Ai[mid]) lo = mid + 1;
57  else break;
58 
59  // Sparse matrix entry not found (raise an error when trying to add
60  // value to this position, return 0 when obtaining value there).
61  if(lo > hi)
62  {
63  mid = -1;
64  break;
65  }
66  }
67  return mid;
68  }
69 
70  template<typename Scalar>
71  MumpsMatrix<Scalar>::MumpsMatrix()
72  {
73  nnz = 0;
74  this->size = 0;
75  irn = NULL;
76  jcn = NULL;
77  Ax = NULL;
78  Ap = NULL;
79  Ai = NULL;
80  }
81 
82  template<typename Scalar>
83  MumpsMatrix<Scalar>::~MumpsMatrix()
84  {
85  free();
86  }
87 
88  template<typename Scalar>
89  void MumpsMatrix<Scalar>::alloc()
90  {
91  assert(this->pages != NULL);
92 
93  // initialize the arrays Ap and Ai
94  Ap = new unsigned int[this->size + 1];
95  int aisize = this->get_num_indices();
96  Ai = new int[aisize];
97 
98  // sort the indices and remove duplicities, insert into Ai
99  unsigned int i, pos = 0;
100  for (i = 0; i < this->size; i++)
101  {
102  Ap[i] = pos;
103  pos += sort_and_store_indices(this->pages[i], Ai + pos, Ai + aisize);
104  }
105  Ap[i] = pos;
106 
107  delete [] this->pages;
108  this->pages = NULL;
109 
110  nnz = Ap[this->size];
111 
112  Ax = new typename mumps_type<Scalar>::mumps_Scalar[nnz];
113  memset(Ax, 0, sizeof(Scalar) * nnz);
114 
115  irn = new int[nnz];
116  jcn = new int[nnz];
117  for (unsigned int i = 0; i < nnz; i++)
118  {
119  irn[i] = 1;
120  jcn[i] = 1;
121  }
122  }
123 
124  template<typename Scalar>
125  void MumpsMatrix<Scalar>::free()
126  {
127  nnz = 0;
128  delete [] Ap; Ap = NULL;
129  delete [] Ai; Ai = NULL;
130  delete [] Ax; Ax = NULL;
131  delete [] irn; irn = NULL;
132  delete [] jcn; jcn = NULL;
133  }
134 
135  inline double mumps_to_Scalar(double x)
136  {
137  return x;
138  }
139 
140  inline std::complex<double> mumps_to_Scalar(ZMUMPS_COMPLEX x)
141  {
142  return std::complex<double>(x.r, x.i);
143  }
144 
145  template<typename Scalar>
146  Scalar MumpsMatrix<Scalar>::get(unsigned int m, unsigned int n)
147  {
148  // Find m-th row in the n-th column.
149  int mid = find_position(Ai + Ap[n], Ap[n + 1] - Ap[n], m);
150  // Return 0 if the entry has not been found.
151  if(mid < 0) return 0.0;
152  // Otherwise, add offset to the n-th column and return the value.
153  if(mid >= 0) mid += Ap[n];
154  return mumps_to_Scalar(Ax[mid]);
155  }
156 
157  template<typename Scalar>
158  void MumpsMatrix<Scalar>::zero()
159  {
160  memset(Ax, 0, sizeof(Scalar) * Ap[this->size]);
161  }
162 
163  inline ZMUMPS_COMPLEX& operator +=(ZMUMPS_COMPLEX &a, std::complex<double> b)
164  {
165  a.r +=b.real();
166  a.i +=b.imag();
167  return a;
168  }
169 
170  template<typename Scalar>
171  void MumpsMatrix<Scalar>::add(unsigned int m, unsigned int n, Scalar v)
172  {
173  // produced an error in neutronics-2-group-adapt (although tutorial-07
174  // ran well).
175  // Find m-th row in the n-th column.
176  int pos = find_position(Ai + Ap[n], Ap[n + 1] - Ap[n], m);
177  // Make sure we are adding to an existing non-zero entry.
178  if(pos < 0)
179  throw Hermes::Exceptions::Exception("Sparse matrix entry not found");
180  // Add offset to the n-th column.
181  pos += Ap[n];
182 #pragma omp critical (MumpsMatrix_add)
183  Ax[pos] += v;
184  irn[pos] = m + 1; // MUMPS is indexing from 1
185  jcn[pos] = n + 1;
186  }
187 
188  template<typename Scalar>
189  void MumpsMatrix<Scalar>::add(unsigned int m, unsigned int n, Scalar **mat, int *rows, int *cols)
190  {
191  for (unsigned int i = 0; i < m; i++) // rows
192  for (unsigned int j = 0; j < n; j++) // cols
193  if(rows[i] >= 0 && cols[j] >= 0) // not Dir. dofs.
194  add(rows[i], cols[j], mat[i][j]);
195  }
196 
198 
199  template<typename Scalar>
200  void MumpsMatrix<Scalar>::add_to_diagonal(Scalar v)
201  {
202  for (unsigned int i = 0; i < this->size; i++)
203  {
204  add(i, i, v);
205  }
206  };
207 
210  template<typename Scalar>
211  bool MumpsMatrix<Scalar>::dump(FILE *file, const char *var_name, EMatrixDumpFormat fmt, char* number_format)
212  {
213  // TODO
214  switch (fmt)
215  {
216  case DF_PLAIN_ASCII:
217  fprintf(file, "%d\n", this->size);
218  fprintf(file, "%d\n", nnz);
219  for (unsigned int i = 0; i < nnz; i++)
220  {
221  fprintf(file, "%d %d ", irn[i], jcn[i]);
222  Hermes::Helpers::fprint_num(file, mumps_to_Scalar(Ax[i]));
223  fprintf(file, "\n");
224  }
225  return true;
226 
227  case DF_MATLAB_SPARSE:
228  fprintf(file, "%% Size: %dx%d\n%% Nonzeros: %d\ntemp = zeros(%d, 3);\ntemp =[\n", this->size, this->size, Ap[this->size], Ap[this->size]);
229  for (unsigned int j = 0; j < this->size; j++)
230  for (unsigned int i = Ap[j]; i < Ap[j + 1]; i++)
231  {
232  fprintf(file, "%d %d ", Ai[i] + 1, j + 1);
233  Hermes::Helpers::fprint_num(file, mumps_to_Scalar(Ax[i]));
234  fprintf(file, "\n");
235  }
236  fprintf(file, "];\n%s = spconvert(temp);\n", var_name);
237 
238  return true;
239 
240  case DF_HERMES_BIN:
241  {
242  this->hermes_fwrite("HERMESX\001", 1, 8, file);
243  int ssize = sizeof(Scalar);
244  this->hermes_fwrite(&ssize, sizeof(int), 1, file);
245  this->hermes_fwrite(&this->size, sizeof(int), 1, file);
246  this->hermes_fwrite(&nnz, sizeof(int), 1, file);
247  this->hermes_fwrite(Ap, sizeof(int), this->size + 1, file);
248  this->hermes_fwrite(Ai, sizeof(int), nnz, file);
249  this->hermes_fwrite(Ax, sizeof(Scalar), nnz, file);
250  return true;
251  }
252 
253  default:
254  return false;
255  }
256  }
257 
258  template<typename Scalar>
259  unsigned int MumpsMatrix<Scalar>::get_matrix_size() const
260  {
261  return this->size;
262  }
263 
264  template<typename Scalar>
265  unsigned int MumpsMatrix<Scalar>::get_nnz() const
266  {
267  return nnz;
268  }
269 
270  template<typename Scalar>
271  double MumpsMatrix<Scalar>::get_fill_in() const
272  {
273  return Ap[this->size] / (double) (this->size * this->size);
274  }
275 
276  template<typename Scalar>
277  void MumpsMatrix<Scalar>::add_matrix(MumpsMatrix<Scalar>* mat)
278  {
279  add_as_block(0, 0, mat);
280  };
281 
282  template<typename Scalar>
283  void MumpsMatrix<Scalar>::add_to_diagonal_blocks(int num_stages, MumpsMatrix<Scalar>* mat)
284  {
285  int ndof = mat->get_size();
286  if(this->get_size() != (unsigned int) num_stages * ndof)
287  throw Hermes::Exceptions::Exception("Incompatible matrix sizes in PetscMatrix<Scalar>::add_to_diagonal_blocks()");
288 
289  for (int i = 0; i < num_stages; i++)
290  {
291  this->add_as_block(ndof*i, ndof*i, mat);
292  }
293  }
294 
295  template<typename Scalar>
296  void MumpsMatrix<Scalar>::add_sparse_to_diagonal_blocks(int num_stages, SparseMatrix<Scalar>* mat)
297  {
298  add_to_diagonal_blocks(num_stages, static_cast<MumpsMatrix*>(mat));
299  }
300 
301  inline ZMUMPS_COMPLEX& operator +=(ZMUMPS_COMPLEX &a, ZMUMPS_COMPLEX b)
302  {
303  a.r +=b.r;
304  a.i +=b.i;
305  return a;
306  }
307 
308  template<typename Scalar>
309  void MumpsMatrix<Scalar>::add_as_block(unsigned int i, unsigned int j, MumpsMatrix<Scalar>* mat)
310  {
311  int idx;
312  for (unsigned int col = 0;col<mat->get_size();col++)
313  {
314  for (unsigned int n = mat->Ap[col];n<mat->Ap[col + 1];n++)
315  {
316  idx = find_position(Ai + Ap[col + j], Ap[col + 1 + j] - Ap[col + j], mat->Ai[n] + i);
317  if(idx<0)
318  throw Hermes::Exceptions::Exception("Sparse matrix entry not found");
319  idx +=Ap[col + j];
320  Ax[idx] +=mat->Ax[n];
321  }
322  }
323  }
324 
325  // Applies the matrix to vector_in and saves result to vector_out.
326  template<typename Scalar>
327  void MumpsMatrix<Scalar>::multiply_with_vector(Scalar* vector_in, Scalar* vector_out)
328  {
329  for(unsigned int i = 0;i<this->size;i++)
330  {
331  vector_out[i] = 0;
332  }
333  Scalar a;
334  for (unsigned int i = 0;i<nnz;i++)
335  {
336  a = mumps_to_Scalar(Ax[i]);
337  vector_out[jcn[i]-1] +=vector_in[irn[i]-1]*a;
338  }
339  }
340  // Multiplies matrix with a Scalar.
341  template<>
342  void MumpsMatrix<double>::multiply_with_Scalar(double value)
343  {
344  int n = nnz;
345  for(int i = 0;i<n;i++)
346  {
347  Ax[i] = Ax[i]*value;
348  }
349  }
350 
351  template<>
352  void MumpsMatrix<std::complex<double> >::multiply_with_Scalar(std::complex<double> value)
353  {
354  int n = nnz;
355  std::complex<double> a;
356  for(int i = 0;i<n;i++)
357  {
358  a = std::complex<double>(Ax[i].r, Ax[i].i);
359  a = a*value;
360  Ax[i].r = a.real();
361  Ax[i].i = a.imag();
362  }
363  }
364 
365  inline void mumps_assign_Scalar(ZMUMPS_COMPLEX & a, std::complex<double> b)
366  {
367  a.r = b.real();
368  a.i = b.imag();
369  }
370 
371  inline void mumps_assign_Scalar(double & a, double b)
372  {
373  a = b;
374  }
375 
376  // Creates matrix using size, nnz, and the three arrays.
377  template<typename Scalar>
378  void MumpsMatrix<Scalar>::create(unsigned int size, unsigned int nnz, int* ap, int* ai, Scalar* ax)
379  {
380  this->nnz = nnz;
381  this->size = size;
382  this->Ap = new unsigned int[this->size + 1]; assert(this->Ap != NULL);
383  this->Ai = new int[nnz]; assert(this->Ai != NULL);
384  this->Ax = new typename mumps_type<Scalar>::mumps_Scalar[nnz]; assert(this->Ax != NULL);
385  irn = new int[nnz]; assert(this->irn !=NULL); // Row indices.
386  jcn = new int[nnz]; assert(this->jcn !=NULL); // Column indices.
387 
388  for (unsigned int i = 0; i < this->size; i++)
389  {
390  this->Ap[i] = ap[i];
391  for (int j = ap[i];j<ap[i + 1];j++) jcn[j] = i;
392  }
393  this->Ap[this->size] = ap[this->size];
394  for (unsigned int i = 0; i < nnz; i++)
395  {
396  mumps_assign_Scalar(this->Ax[i], ax[i]);
397  this->Ai[i] = ai[i];
398  irn[i] = ai[i];
399  }
400  }
401  // Duplicates a matrix (including allocation).
402  template<typename Scalar>
403  MumpsMatrix<Scalar>* MumpsMatrix<Scalar>::duplicate()
404  {
405  MumpsMatrix<Scalar> * nmat = new MumpsMatrix<Scalar>();
406 
407  nmat->nnz = nnz;
408  nmat->size = this->size;
409  nmat->Ap = new unsigned int[this->size + 1]; assert(nmat->Ap != NULL);
410  nmat->Ai = new int[nnz]; assert(nmat->Ai != NULL);
411  nmat->Ax = new typename mumps_type<Scalar>::mumps_Scalar[nnz]; assert(nmat->Ax != NULL);
412  nmat->irn = new int[nnz]; assert(nmat->irn !=NULL); // Row indices.
413  nmat->jcn = new int[nnz]; assert(nmat->jcn !=NULL); // Column indices.
414  for (unsigned int i = 0;i<nnz;i++)
415  {
416  nmat->Ai[i] = Ai[i];
417  nmat->Ax[i] = Ax[i];
418  nmat->irn[i] = irn[i];
419  nmat->jcn[i] = jcn[i];
420  }
421  for (unsigned int i = 0;i<this->size + 1;i++)
422  {
423  nmat->Ap[i] = Ap[i];
424  }
425  return nmat;
426  }
427 
428  // MumpsVector<Scalar> /////////////////////////////////////////////////////////////////////////////////////
429 
430  template<typename Scalar>
431  MumpsVector<Scalar>::MumpsVector()
432  {
433  v = NULL;
434  this->size = 0;
435  }
436 
437  template<typename Scalar>
438  MumpsVector<Scalar>::~MumpsVector()
439  {
440  free();
441  }
442 
443  template<typename Scalar>
444  void MumpsVector<Scalar>::alloc(unsigned int n)
445  {
446  free();
447  this->size = n;
448  v = new Scalar[n];
449  zero();
450  }
451 
452  template<typename Scalar>
453  void MumpsVector<Scalar>::change_sign()
454  {
455  for (unsigned int i = 0; i < this->size; i++) v[i] *= -1.;
456  }
457 
458  template<typename Scalar>
459  void MumpsVector<Scalar>::zero()
460  {
461  memset(v, 0, this->size * sizeof(Scalar));
462  }
463 
464  template<typename Scalar>
465  void MumpsVector<Scalar>::free()
466  {
467  delete [] v;
468  v = NULL;
469  this->size = 0;
470  }
471 
472  template<typename Scalar>
473  void MumpsVector<Scalar>::set(unsigned int idx, Scalar y)
474  {
475  v[idx] = y;
476  }
477 
478  template<typename Scalar>
479  void MumpsVector<Scalar>::add(unsigned int idx, Scalar y)
480  {
481  #pragma omp critical (MumpsVector_add)
482  v[idx] += y;
483  }
484 
485  template<typename Scalar>
486  void MumpsVector<Scalar>::add(unsigned int n, unsigned int *idx, Scalar *y)
487  {
488  for (unsigned int i = 0; i < n; i++)
489  {
490  v[idx[i]] += y[i];
491  }
492  }
493 
494  template<typename Scalar>
495  Scalar MumpsVector<Scalar>::get(unsigned int idx)
496  {
497  return v[idx];
498  }
499 
500  template<typename Scalar>
501  void MumpsVector<Scalar>::extract(Scalar *v) const
502  {
503  memcpy(v, this->v, this->size * sizeof(Scalar));
504  }
505 
506  template<typename Scalar>
507  void MumpsVector<Scalar>::add_vector(Vector<Scalar>* vec)
508  {
509  assert(this->length() == vec->length());
510  for (unsigned int i = 0; i < this->length(); i++) this->add(i, vec->get(i));
511  }
512 
513  template<typename Scalar>
514  void MumpsVector<Scalar>::add_vector(Scalar* vec)
515  {
516  for (unsigned int i = 0; i < this->length(); i++) this->add(i, vec[i]);
517  }
518 
519  template<typename Scalar>
520  bool MumpsVector<Scalar>::dump(FILE *file, const char *var_name, EMatrixDumpFormat fmt, char* number_format)
521  {
522  switch (fmt)
523  {
524  case DF_PLAIN_ASCII:
525  for (unsigned int i = 0; i < this->size; i++)
526  {
527  Hermes::Helpers::fprint_num(file, v[i], number_format);
528  fprintf(file, "\n");
529  }
530 
531  return true;
532 
533  case DF_MATLAB_SPARSE:
534  fprintf(file, "%% Size: %dx1\n%s =[\n", this->size, var_name);
535  for (unsigned int i = 0; i < this->size; i++)
536  {
537  Hermes::Helpers::fprint_num(file, v[i], number_format);
538  fprintf(file, "\n");
539  }
540  fprintf(file, " ];\n");
541  return true;
542 
543  case DF_HERMES_BIN:
544  {
545  this->hermes_fwrite("HERMESR\001", 1, 8, file);
546  int ssize = sizeof(Scalar);
547  this->hermes_fwrite(&ssize, sizeof(int), 1, file);
548  this->hermes_fwrite(&this->size, sizeof(int), 1, file);
549  this->hermes_fwrite(v, sizeof(Scalar), this->size, file);
550  return true;
551  }
552 
553  default:
554  return false;
555  }
556  }
557 
558  template class HERMES_API MumpsMatrix<double>;
559  template class HERMES_API MumpsMatrix<std::complex<double> >;
560  template class HERMES_API MumpsVector<double>;
561  template class HERMES_API MumpsVector<std::complex<double> >;
562  }
563  namespace Solvers
564  {
566 #define ICNTL(I) icntl[(I)-1]
567 #define MUMPS_INFO(param, I) (param).infog[(I)-1]
568 #define INFOG(I) infog[(I)-1]
569 
571 #define JOB_INIT -1
572 #define JOB_END -2
573 #define JOB_ANALYZE_FACTORIZE_SOLVE 6
574 #define JOB_FACTORIZE_SOLVE 5
575 #define JOB_SOLVE 3
576 
577  template<>
578  void MumpsSolver<double>::mumps_c(mumps_type<double>::mumps_struct * param)
579  {
580  dmumps_c(param);
581  }
582 
583  template<>
584  void MumpsSolver<std::complex<double> >::mumps_c(mumps_type<std::complex<double> >::mumps_struct * param)
585  {
586  zmumps_c(param);
587  }
588 
589  template<typename Scalar>
590  bool MumpsSolver<Scalar>::check_status()
591  {
592  switch (param.INFOG(1))
593  {
594  case 0: return true; // no error
595  case -1: this->warn("Error occured on processor %d", MUMPS_INFO(param, 2)); break;
597  default: this->warn("INFOG(1) = %d", param.INFOG(1)); break;
598  }
599  return false;
600  }
601 
602  template<typename Scalar>
603  bool MumpsSolver<Scalar>::reinit()
604  {
605  if(inited)
606  {
607  // If there is already an instance of MUMPS running,
608  // terminate it.
609  param.job = JOB_END;
610  mumps_c(&param);
611  }
612 
613  param.job = JOB_INIT;
614  param.par = 1; // host also performs calculations
615  param.sym = 0; // 0 = unsymmetric
616  param.comm_fortran = USE_COMM_WORLD;
617 
618  mumps_c(&param);
619  inited = check_status();
620 
621  if(inited)
622  {
623  // No printings.
624  param.ICNTL(1) = -1;
625  param.ICNTL(2) = -1;
626  param.ICNTL(3) = -1;
627  param.ICNTL(4) = 0;
628 
629  param.ICNTL(20) = 0; // centralized dense RHS
630  param.ICNTL(21) = 0; // centralized dense solution
631 
632  // Specify the matrix.
633  param.n = m->size;
634  param.nz = m->nnz;
635  param.irn = m->irn;
636  param.jcn = m->jcn;
637  param.a = m->Ax;
638  }
639 
640  return inited;
641  }
642 
643  template<typename Scalar>
644  MumpsSolver<Scalar>::MumpsSolver(MumpsMatrix<Scalar> *m, MumpsVector<Scalar> *rhs) :
645  DirectSolver<Scalar>(), m(m), rhs(rhs)
646  {
647  inited = false;
648 
649  // Initial values for some fields of the MUMPS_STRUC structure that may be accessed
650  // before MUMPS has been initialized.
651  param.rhs = NULL;
652  param.INFOG(33) = -999; // see the case HERMES_REUSE_MATRIX_REORDERING_AND_SCALING
653  // in setup_factorization()
654  }
655 
656  template<typename Scalar>
657  MumpsSolver<Scalar>::~MumpsSolver()
658  {
659  // Terminate the current instance of MUMPS.
660  if(inited)
661  {
662  param.job = JOB_END;
663  mumps_c(&param);
664  }
665 
666  if(param.rhs != NULL) delete [] param.rhs;
667  }
668 
669  template<typename Scalar>
670  int MumpsSolver<Scalar>::get_matrix_size()
671  {
672  return m->size;
673  }
674 
675  template<typename Scalar>
676  bool MumpsSolver<Scalar>::solve()
677  {
678  bool ret = false;
679  assert(m != NULL);
680  assert(rhs != NULL);
681 
682  this->tick();
683 
684  // Prepare the MUMPS data structure with input for the solver driver
685  // (according to the chosen factorization reuse strategy), as well as
686  // the system matrix.
687  if( !setup_factorization() )
688  {
689  throw Hermes::Exceptions::LinearMatrixSolverException("LU factorization could not be completed.");
690  }
691 
692  // Specify the right-hand side (will be replaced by the solution).
693  param.rhs = new typename mumps_type<Scalar>::mumps_Scalar[m->size];
694  memcpy(param.rhs, rhs->v, m->size * sizeof(Scalar));
695 
696  // Do the jobs specified in setup_factorization().
697  mumps_c(&param);
698 
699  ret = check_status();
700 
701  if(ret)
702  {
703  delete [] this->sln;
704  this->sln = new Scalar[m->size];
705  for (unsigned int i = 0; i < rhs->size; i++)
706  this->sln[i] = mumps_to_Scalar(param.rhs[i]);
707  }
708 
709  this->tick();
710  this->time = this->accumulated();
711 
712  delete [] param.rhs;
713  param.rhs = NULL;
714 
715  return ret;
716  }
717 
718  template<typename Scalar>
719  bool MumpsSolver<Scalar>::setup_factorization()
720  {
721  // When called for the first time, all three phases (analysis, factorization,
722  // solution) must be performed.
723  int eff_fact_scheme = this->factorization_scheme;
724  if(!inited)
725  if( this->factorization_scheme == HERMES_REUSE_MATRIX_REORDERING ||
726  this->factorization_scheme == HERMES_REUSE_FACTORIZATION_COMPLETELY )
727  eff_fact_scheme = HERMES_FACTORIZE_FROM_SCRATCH;
728 
729  switch (eff_fact_scheme)
730  {
732  // (Re)initialize new instance.
733  reinit();
734 
735  // Let MUMPS decide when and how to compute matrix reordering and scaling.
736  param.ICNTL(6) = 7;
737  param.ICNTL(8) = 77;
738  param.job = JOB_ANALYZE_FACTORIZE_SOLVE;
739 
740  break;
742  // Let MUMPS reuse results of the symbolic analysis and perform
743  // scaling during each factorization (values 1-8 may be set here,
744  // corresponding to different scaling algorithms during factorization;
745  // see the MUMPS documentation for details).
746  param.ICNTL(8) = 7;
747  param.job = JOB_FACTORIZE_SOLVE;
748 
749  break;
751  // Perform scaling along with reordering during the symbolic analysis phase
752  // and then reuse it during subsequent factorizations. New instance of MUMPS
753  // has to be created before the analysis phase.
754  if(param.INFOG(33) != -2)
755  {
756  reinit();
757  param.ICNTL(6) = 5;
758  param.job = JOB_ANALYZE_FACTORIZE_SOLVE;
759  // After analysis is done, INFOG(33) will be set to -2 by MUMPS.
760  }
761  else
762  {
763  param.job = JOB_FACTORIZE_SOLVE;
764  }
765  break;
767  param.job = JOB_SOLVE;
768  break;
769  }
770 
771  return true;
772  }
773 
774  template class HERMES_API MumpsSolver<double>;
775  template class HERMES_API MumpsSolver<std::complex<double> >;
776  }
777 }
778 #endif