OpenFPM  5.2.0
Project that contain the implementation of distributed structures
petsc_solver.hpp
1 /*
2  * petsc_solver.hpp
3  *
4  * Created on: Apr 26, 2016
5  * Author: i-bird
6  */
7 
8 #ifndef OPENFPM_NUMERICS_SRC_SOLVERS_PETSC_SOLVER_HPP_
9 #define OPENFPM_NUMERICS_SRC_SOLVERS_PETSC_SOLVER_HPP_
10 
11 #include "config.h"
12 
13 #ifdef HAVE_PETSC
14 
15 #include "Vector/Vector.hpp"
16 #include <petscksp.h>
17 #include <petsctime.h>
18 #include "Plot/GoogleChart.hpp"
19 #include "Matrix/SparseMatrix.hpp"
20 #include "Vector/Vector.hpp"
21 #include <sstream>
22 #include <iomanip>
23 
24 template <typename T>
25 std::string to_string_with_precision(const T a_value, const int n = 6)
26 {
27  std::ostringstream out;
28  out << std::setprecision(n) << a_value;
29  return out.str();
30 }
31 
32 #define UMFPACK_NONE 0
33 #define REL_DOWN 1
34 #define REL_UP 2
35 #define REL_ALL 3
36 
37 #define PCHYPRE_BOOMERAMG "petsc_boomeramg"
38 
39 enum AMG_type
40 {
41  NONE_AMG,
42  HYPRE_AMG,
43  PETSC_AMG,
44  TRILINOS_ML
45 };
46 
47 /*
54 template<typename T>
55 class petsc_solver
56 {
57 public:
58 
59  *//*
69  template<typename impl> static Vector<T> solve(const SparseMatrix<T,impl> & A, const Vector<T> & b)
70  {
71  std::cerr << "Error Petsc only suppor T precision" << "/n";
72  }
73 };*/
74 
75 #define SOLVER_NOOPTION 0
76 #define SOLVER_PRINT_RESIDUAL_NORM_INFINITY 1
77 #define SOLVER_PRINT_DETERMINANT 2
78 
80 struct solError
81 {
83  PetscReal err_inf;
84 
86  PetscReal err_norm;
87 
89  PetscInt its;
90 };
91 
92 
100 template<typename T>
102 {
104  struct itError
105  {
107  PetscInt it;
108 
110  PetscReal err_norm;
111  };
112 
118  {
120  std::string method;
121 
123  std::string smethod;
124 
126  T time;
127 
130 
133  };
134 
136  bool is_preconditioner_set = false;
137 
139  PetscInt maxits;
140 
142  KSP ksp;
143 
145  size_t tmp;
146 
149 
150 
153 
155  AMG_type atype = NONE_AMG;
156 
158  int block_sz = 0;
159 
168  static T calculate_it(T t, solv_bench_info & slv)
169  {
170  T s_int = slv.time / slv.res.size();
171 
172  // Calculate the discrete point in time
173  size_t pt = std::floor(t / s_int);
174 
175  if (pt < slv.res.size())
176  return slv.res.get(pt).err_norm;
177 
178  return slv.res.last().err_norm;
179  }
180 
186  {
187  if (create_vcluster().getProcessUnitID() != 0)
188  return;
189 
194 
195  for (size_t i = 0 ; i < bench.size() ; i++)
196  x.add(bench.get(i).smethod);
197 
198  // Each colum can have multiple data set (in this case 4 dataset)
199  // Each dataset can have a name
200  yn.add("Norm infinity");
201  yn.add("Norm average");
202  yn.add("Number of iterations");
203 
204  // Each colums can have multiple data-set
205 
206  for (size_t i = 0 ; i < bench.size() ; i++)
207  y.add({bench.get(i).err.err_inf,bench.get(i).err.err_norm,(T)bench.get(i).err.its});
208 
209  // Google charts options
210  GCoptions options;
211 
212  options.title = std::string("Residual error");
213  options.yAxis = std::string("Error");
214  options.xAxis = std::string("Method");
215  options.stype = std::string("bars");
216  options.more = std::string("vAxis: {scaleType: 'log'}");
217 
218  GoogleChart cg;
219 
220  std::stringstream ss;
221 
222  cg.addHTML("<h2>Robustness</h2>");
223  cg.AddHistGraph(x,y,yn,options);
224  cg.addHTML("<h2>Speed</h2>");
225 
226  y.clear();
227  yn.clear();
228 
229  yn.add("Time in millseconds");
230  options.title = std::string("Time");
231 
232  for (size_t i = 0 ; i < bench.size() ; i++)
233  y.add({bench.get(i).time});
234 
235  cg.AddHistGraph(x,y,yn,options);
236 
237  // Convergence in time
238 
239  x.clear();
240  y.clear();
241  yn.clear();
242  xd.clear();
243 
244  // Get the maximum in time across all the solvers
245 
246  T max_time = 0.0;
247 
248  for (size_t i = 0 ; i < bench.size() ; i++)
249  {
250  if (bench.get(i).time > max_time) {max_time = bench.get(i).time;}
251  yn.add(bench.get(i).smethod);
252  }
253 
254  size_t n_int = maxits;
255 
256  // calculate dt
257 
258  T dt = max_time / n_int;
259 
260  // Add
261 
262  // For each solver we have a convergence plot
263 
264  for (T t = dt ; t <= max_time + 0.05 * max_time ; t += dt)
265  {
266  y.add();
267  xd.add(t);
268  for (size_t j = 0 ; j < bench.size() ; j++)
269  y.last().add(calculate_it(t,bench.get(j)));
270  }
271 
272  std::stringstream ss2;
273  ss2 << "<h2>Convergence with time</h2><br>" << std::endl;
274 
275  options.title = std::string("Residual norm infinity");
276  options.yAxis = std::string("residual");
277  options.xAxis = std::string("Time in milliseconds");
278  options.lineWidth = 1.0;
279  options.more = std::string("vAxis: {scaleType: 'log'},hAxis: {scaleType: 'log'}");
280 
281  cg.addHTML(ss2.str());
282  cg.AddLinesGraph(xd,y,yn,options);
283 
284  ss << "<h2>Solvers Tested</h2><br><br>" << std::endl;
285  for (size_t i = 0 ; i < bench.size() ; i++)
286  ss << bench.get(i).smethod << " = " << bench.get(i).method << "<br>" << std::endl;
287 
288  cg.addHTML(ss.str());
289 
290  cg.write("gc_solver.html");
291  }
292 
300  void pre_solve_impl(const Mat & A_, const Vec & b_, Vec & x_)
301  {
302  PETSC_SAFE_CALL(KSPSetNormType(ksp,KSP_NORM_UNPRECONDITIONED));
303 
304  if (atype == HYPRE_AMG)
305  {
306  PC pc;
307 
308  // We set the pre-conditioner
309  PETSC_SAFE_CALL(KSPGetPC(ksp,&pc));
310 
311  PCFactorSetShiftType(pc, MAT_SHIFT_NONZERO);
312  PCFactorSetShiftAmount(pc, PETSC_DECIDE);
313  }
314  }
315 
321  {
322  auto & v_cl = create_vcluster();
323 
324  if (v_cl.getProcessUnitID() == 0)
325  std::cout << "-----------------------25-----------------------50-----------------------75----------------------100" << std::endl;
326  }
327 
328 
339  static PetscErrorCode monitor_progress_residual(KSP ksp,PetscInt it,PetscReal res,void* data)
340  {
341  petsc_solver<T> * pts = (petsc_solver *)data;
342 
343  pts->progress(it);
344 
345  itError erri;
346  erri.it = it;
347 
348  Mat A;
349  Vec Br,v,w;
350 
351  PETSC_SAFE_CALL(KSPGetOperators(ksp,&A,NULL));
352  PETSC_SAFE_CALL(MatCreateVecs(A,&w,&v));
353  PETSC_SAFE_CALL(KSPBuildResidual(ksp,v,w,&Br));
354  PETSC_SAFE_CALL(KSPBuildResidual(ksp,v,w,&Br));
355  PETSC_SAFE_CALL(VecNorm(Br,NORM_INFINITY,&erri.err_norm));
356  itError err_fill;
357 
358  size_t old_size = pts->bench.last().res.size();
359  pts->bench.last().res.resize(it+1);
360 
361  if (old_size > 0)
362  err_fill = pts->bench.last().res.get(old_size-1);
363  else
364  err_fill = erri;
365 
366  for (long int i = old_size ; i < (long int)it ; i++)
367  pts->bench.last().res.get(i) = err_fill;
368 
369  // Add the error per iteration
370  pts->bench.last().res.get(it) = erri;
371 
372  return 0;
373  }
374 
380  void progress(PetscInt it)
381  {
382  PetscInt n_max_it;
383 
384  PETSC_SAFE_CALL(KSPGetTolerances(ksp,NULL,NULL,NULL,&n_max_it));
385 
386  auto & v_cl = create_vcluster();
387 
388  if (std::floor(it * 100.0 / n_max_it) > tmp)
389  {
390  size_t diff = it * 100.0 / n_max_it - tmp;
391  tmp = it * 100.0 / n_max_it;
392  if (v_cl.getProcessUnitID() == 0)
393  {
394  for (size_t k = 0 ; k < diff ; k++) {std::cout << "*";}
395  std::cout << std::flush;
396  }
397  }
398  }
399 
405  void print_stat(solError & err)
406  {
407  auto & v_cl = create_vcluster();
408 
409  if (v_cl.getProcessUnitID() == 0)
410  {
411  KSPType typ;
412  KSPGetType(ksp,&typ);
413 
414  std::cout << "Method: " << typ << " " << " pre-conditoner: " << PCJACOBI << " iterations: " << err.its << std::endl;
415  std::cout << "Norm of error: " << err.err_norm << " Norm infinity: " << err.err_inf << std::endl;
416  }
417  }
418 
419 
427  std::string to_string_method(const std::string & solv)
428  {
429  if (solv == std::string(KSPBCGS))
430  {
431  return std::string("BiCGStab (Stabilized version of BiConjugate Gradient Squared)");
432  }
433  else if (solv == std::string(KSPIBCGS))
434  {
435  return std::string("IBiCGStab (Improved Stabilized version of BiConjugate Gradient Squared)");
436  }
437  else if (solv == std::string(KSPFBCGS))
438  {
439  return std::string("FBiCGStab (Flexible Stabilized version of BiConjugate Gradient Squared)");
440  }
441  else if (solv == std::string(KSPFBCGSR))
442  {
443  return std::string("FBiCGStab-R (Modified Flexible Stabilized version of BiConjugate Gradient Squared)");
444  }
445  else if (solv == std::string(KSPBCGSL))
446  {
447  return std::string("BiCGStab(L) (Stabilized version of BiConjugate Gradient Squared with L search directions)");
448  }
449  else if (solv == std::string(KSPGMRES))
450  {
451  return std::string("GMRES(M) (Generalized Minimal Residual method with restart)");
452  }
453  else if (solv == std::string(KSPFGMRES))
454  {
455  return std::string("FGMRES(M) (Flexible Generalized Minimal Residual with restart)");
456  }
457  else if (solv == std::string(KSPLGMRES))
458  {
459  return std::string("LGMRES(M) (Augment Generalized Minimal Residual method with restart)");
460  }
461  else if (solv == std::string(KSPPGMRES))
462  {
463  return std::string("PGMRES(M) (Pipelined Generalized Minimal Residual method)");
464  }
465  else if (solv == std::string(KSPGCR))
466  {
467  return std::string("GCR (Generalized Conjugate Residual)");
468  }
469 
470  return std::string("UNKNOWN");
471  }
472 
478  void new_bench(const std::string & str)
479  {
480  // Add a new benchmark result
481  bench.add();
482  bench.last().method = to_string_method(str);
483  bench.last().smethod = std::string(str);
484  }
485 
494  void copy_if_better(T res, Vec & sol, T & best_res, Vec & best_sol)
495  {
496  if (res < best_res)
497  {
498  VecCopy(sol,best_sol);
499  best_res = res;
500  }
501  }
502 
513  void try_solve_simple(const Mat & A_, const Vec & b_, Vec & x_)
514  {
515  Vec best_sol;
516  PETSC_SAFE_CALL(VecDuplicate(x_,&best_sol));
517 
518  // Best residual
519  T best_res = std::numeric_limits<T>::max();
520 
521  // Create a new VCluster
522  auto & v_cl = create_vcluster();
523 
524  destroyKSP();
525 
526  // for each solver
527  for (size_t i = 0 ; i < solvs.size() ; i++)
528  {
529  initKSPForTest();
530 
531  // Here we solve without preconditioner
532  PC pc;
533 
534  // We set the pre-conditioner to none
535  PETSC_SAFE_CALL(KSPGetPC(ksp,&pc));
536  PETSC_SAFE_CALL(PetscOptionsSetValue(NULL,"-pc_type",PCNONE));
537 
538  setSolver(solvs.get(i).c_str());
539 
540  // Setup for BCGSL, GMRES
541  if (solvs.get(i) == std::string(KSPBCGSL))
542  {
543  // we try from 2 to 6 as search direction
544  for (size_t j = 2 ; j < 6 ; j++)
545  {
546  new_bench(solvs.get(i));
547 
548  if (v_cl.getProcessUnitID() == 0)
549  std::cout << "L = " << j << std::endl;
550  bench.last().smethod += std::string("(") + std::to_string(j) + std::string(")");
551  searchDirections(j);
552  bench_solve_simple(A_,b_,x_,bench.last());
553 
554  copy_if_better(bench.last().err.err_inf,x_,best_res,best_sol);
555  }
556  }
557  else if (solvs.get(i) == std::string(KSPGMRES) ||
558  solvs.get(i) == std::string(std::string(KSPFGMRES)) ||
559  solvs.get(i) == std::string(std::string(KSPLGMRES)) )
560  {
561  // we try from 2 to 6 as search direction
562  for (size_t j = 50 ; j < 300 ; j += 50)
563  {
564  // Add a new benchmark result
565  new_bench(solvs.get(i));
566 
567  if (v_cl.getProcessUnitID() == 0)
568  std::cout << "Restart = " << j << std::endl;
569  bench.last().smethod += std::string("(") + std::to_string(j) + std::string(")");
570  setRestart(j);
571  bench_solve_simple(A_,b_,x_,bench.last());
572 
573  copy_if_better(bench.last().err.err_inf,x_,best_res,best_sol);
574  }
575  }
576  else
577  {
578  // Add a new benchmark result
579  new_bench(solvs.get(i));
580 
581  bench_solve_simple(A_,b_,x_,bench.last());
582 
583  copy_if_better(bench.last().err.err_inf,x_,best_res,best_sol);
584  }
585 
586  destroyKSP();
587  }
588 
590 
591  // Copy the best solution to x
592  PETSC_SAFE_CALL(VecCopy(best_sol,x_));
593  PETSC_SAFE_CALL(VecDestroy(&best_sol));
594  }
595 
596 
605  void bench_solve_simple(const Mat & A_, const Vec & b_, Vec & x_, solv_bench_info & bench)
606  {
607  // timer for benchmark
608  timer t;
609  t.start();
610  // Enable progress monitor
611  tmp = 0;
612  PETSC_SAFE_CALL(KSPMonitorCancel(ksp));
613  PETSC_SAFE_CALL(KSPMonitorSet(ksp,monitor_progress_residual,this,NULL));
615  solve_simple(A_,b_,x_);
616 
617  // New line
618  if (create_vcluster().getProcessUnitID() == 0)
619  std::cout << std::endl;
620 
621  t.stop();
622  bench.time = t.getwct() * 1000.0;
623 
624  // calculate error statistic about the solution and print
625  solError err = statSolutionError(A_,b_,x_,ksp);
626  print_stat(err);
627 
628  bench.err = err;
629 
630  // New line
631  if (create_vcluster().getProcessUnitID() == 0)
632  std::cout << std::endl;
633  }
634 
642  void solve_simple(const Mat & A_, const Vec & b_, Vec & x_)
643  {
644 // PETSC_SAFE_CALL(KSPSetType(ksp,s_type));
645 
646  // We set the size of x according to the Matrix A
647  PetscInt row;
648  PetscInt col;
649  PetscInt row_loc;
650  PetscInt col_loc;
651 
652  PETSC_SAFE_CALL(MatGetSize(A_,&row,&col));
653  PETSC_SAFE_CALL(MatGetLocalSize(A_,&row_loc,&col_loc));
654 
655  // We set the Matrix operators
656  PETSC_SAFE_CALL(KSPSetOperators(ksp,A_,A_));
657 
658  // if we are on on best solve set-up a monitor function
659 
660  PETSC_SAFE_CALL(KSPSetFromOptions(ksp));
661  //PETSC_SAFE_CALL(KSPSetUp(ksp));
662 
663  // Solve the system
664  PETSC_SAFE_CALL(KSPSolve(ksp,b_,x_));
665  }
666 
673  void solve_simple(const Vec & b_, Vec & x_)
674  {
675  // Solve the system
676  PETSC_SAFE_CALL(KSPSolve(ksp,b_,x_));
677  }
678 
689  static solError statSolutionError(const Mat & A_, const Vec & b_, Vec & x_, KSP ksp)
690  {
691  solError err;
692 
693  err = getSolNormError(A_,b_,x_);
694 
695  PetscInt its;
696  PETSC_SAFE_CALL(KSPGetIterationNumber(ksp,&its));
697  err.its = its;
698 
699  return err;
700  }
701 
702 
707  void initKSP()
708  {
709  PETSC_SAFE_CALL(KSPCreate(PETSC_COMM_WORLD,&ksp));
710  }
711 
717  {
718  PETSC_SAFE_CALL(KSPCreate(PETSC_COMM_WORLD,&ksp));
719 
721  }
722 
727  void destroyKSP()
728  {
729  KSPDestroy(&ksp);
730  }
731 
741  static solError getSolNormError(const Vec & b_, const Vec & x_,KSP ksp)
742  {
743  Mat A_;
744  Mat P_;
745  KSPGetOperators(ksp,&A_,&P_);
746 
747  return getSolNormError(A_,b_,x_);
748  }
749 
759  static solError getSolNormError(const Mat & A_, const Vec & b_, const Vec & x_)
760  {
761  PetscScalar neg_one = -1.0;
762 
763  // We set the size of x according to the Matrix A
764  PetscInt row;
765  PetscInt col;
766  PetscInt row_loc;
767  PetscInt col_loc;
768 
769  PETSC_SAFE_CALL(MatGetSize(A_,&row,&col));
770  PETSC_SAFE_CALL(MatGetLocalSize(A_,&row_loc,&col_loc));
771 
772  /*
773  Here we calculate the residual error
774  */
775  PetscReal norm;
776  PetscReal norm_inf;
777 
778  // Get a vector r for the residual
779  Vector<T,PETSC_BASE> r(row,row_loc);
780  Vec & r_ = r.getVec();
781 
782  PETSC_SAFE_CALL(MatMult(A_,x_,r_));
783  PETSC_SAFE_CALL(VecAXPY(r_,neg_one,b_));
784 
785  PETSC_SAFE_CALL(VecNorm(r_,NORM_1,&norm));
786  PETSC_SAFE_CALL(VecNorm(r_,NORM_INFINITY,&norm_inf));
787 
788  solError err;
789  err.err_norm = norm / col;
790  err.err_inf = norm_inf;
791  err.its = 0;
792 
793  return err;
794  }
795 
796 public:
797 
800 
801  ~petsc_solver()
802  {
803  PETSC_SAFE_CALL(KSPDestroy(&ksp));
804  }
805 
806  petsc_solver()
807  :maxits(300),tmp(0)
808  {
809  initKSP();
810 
811  // Add the solvers
812 
813  solvs.add(std::string(KSPBCGS));
814 // solvs.add(std::string(KSPIBCGS)); <--- Produce invalid argument
815 // solvs.add(std::string(KSPFBCGS));
816 // solvs.add(std::string(KSPFBCGSR)); <--- Nan production problems
817  solvs.add(std::string(KSPBCGSL));
818  solvs.add(std::string(KSPGMRES));
819  solvs.add(std::string(KSPFGMRES));
820  solvs.add(std::string(KSPLGMRES));
821 // solvs.add(std::string(KSPPGMRES)); <--- Take forever
822 // solvs.add(std::string(KSPGCR));
823 
824  //setSolver(KSPGMRES);
825  }
826 
832  {
833  auto & v_cl = create_vcluster();
834 
835  if (v_cl.getProcessUnitID() == 0)
836  {
837  PC pc;
838  PCType type_pc;
839 
840  // We set the pre-conditioner
841  PETSC_SAFE_CALL(KSPGetPC(ksp,&pc));
842  PETSC_SAFE_CALL(PCGetType(pc,&type_pc));
843 
844  std::cout << "The precoditioner is: " << type_pc << std::endl;
845  }
846  }
847 
853  {
854  auto & v_cl = create_vcluster();
855 
856  if (v_cl.getProcessUnitID() == 0)
857  {
858  KSPType type_ksp;
859 
860  // We get the KSP_type
861  PETSC_SAFE_CALL(KSPGetType(ksp,&type_ksp));
862 
863  std::cout << "The ksp_type is: " << type_ksp << std::endl;
864  }
865  }
866 
875  void addTestSolver(std::string & solver)
876  {
877  solvs.add(solver);
878  }
879 
888  void removeTestSolver(const std::string & solver)
889  {
890  // search for the test solver and remove it
891 
892  for (size_t i = 0 ; i < solvs.size() ; i++)
893  {
894  if (solvs.get(i) == solver)
895  return;
896  }
897  }
898 
899 
905  void log_monitor()
906  {
907  PETSC_SAFE_CALL(PetscOptionsSetValue(NULL,"-ksp_monitor",0));
908  PETSC_SAFE_CALL(PetscOptionsSetValue(NULL,"-pc_hypre_boomeramg_print_statistics","2"));
909  }
910 
918  void setSolver(KSPType type)
919  {
920  PetscOptionsSetValue(NULL,"-ksp_type",type);
921  }
922 
930  void setRelTol(PetscReal rtol_)
931  {
932  PetscReal rtol;
933  PetscReal abstol;
934  PetscReal dtol;
935  PetscInt maxits;
936 
937  PETSC_SAFE_CALL(KSPGetTolerances(ksp,&rtol,&abstol,&dtol,&maxits));
938  PETSC_SAFE_CALL(KSPSetTolerances(ksp,rtol_,abstol,dtol,maxits));
939  }
940 
948  void setAbsTol(PetscReal abstol_)
949  {
950  PetscReal rtol;
951  PetscReal abstol;
952  PetscReal dtol;
953  PetscInt maxits;
954 
955  PETSC_SAFE_CALL(KSPGetTolerances(ksp,&rtol,&abstol,&dtol,&maxits));
956  PETSC_SAFE_CALL(KSPSetTolerances(ksp,rtol,abstol_,dtol,maxits));
957  }
958 
966  void setDivTol(PetscReal dtol_)
967  {
968  PetscReal rtol;
969  PetscReal abstol;
970  PetscReal dtol;
971  PetscInt maxits;
972 
973  PETSC_SAFE_CALL(KSPGetTolerances(ksp,&rtol,&abstol,&dtol,&maxits));
974  PETSC_SAFE_CALL(KSPSetTolerances(ksp,rtol,abstol,dtol_,maxits));
975  }
976 
982  void setMaxIter(PetscInt n)
983  {
984  PetscReal rtol;
985  PetscReal abstol;
986  PetscReal dtol;
987  PetscInt maxits;
988 
989  PETSC_SAFE_CALL(KSPGetTolerances(ksp,&rtol,&abstol,&dtol,&maxits));
990  PETSC_SAFE_CALL(KSPSetTolerances(ksp,rtol,abstol,dtol,n));
991 
992  this->maxits = n;
993  }
994 
1004  void searchDirections(PetscInt l)
1005  {
1006  PetscOptionsSetValue(NULL,"-ksp_bcgsl_ell",std::to_string(l).c_str());
1007  }
1008 
1014  void setRestart(PetscInt n)
1015  {
1016  PetscOptionsSetValue(NULL,"-ksp_gmres_restart",std::to_string(n).c_str());
1017  }
1018 
1046  void setPreconditioner(PCType type)
1047  {
1048  is_preconditioner_set = true;
1049 
1050  if (std::string(type) == PCHYPRE_BOOMERAMG)
1051  {
1052  PC pc;
1053 
1054  // We set the pre-conditioner
1055  PETSC_SAFE_CALL(KSPGetPC(ksp,&pc));
1056 
1057  PETSC_SAFE_CALL(PetscOptionsSetValue(NULL,"-pc_type",PCHYPRE));
1058 
1059  PETSC_SAFE_CALL(PCFactorSetShiftType(pc, MAT_SHIFT_NONZERO));
1060  PETSC_SAFE_CALL(PCFactorSetShiftAmount(pc, PETSC_DECIDE));
1061 #ifdef PETSC_HAVE_HYPRE
1062  PETSC_SAFE_CALL(PCHYPRESetType(pc, "boomeramg"));
1063 #endif
1064  atype = HYPRE_AMG;
1065  }
1066  else
1067  {
1068  PETSC_SAFE_CALL(PetscOptionsSetValue(NULL,"-pc_type",type));
1069  }
1070  }
1071 
1081  {
1082  if (atype == HYPRE_AMG)
1083  {
1084  PETSC_SAFE_CALL(PetscOptionsSetValue(NULL,"-pc_hypre_boomeramg_max_levels",std::to_string(nl).c_str()));
1085  }
1086  else
1087  {
1088  std::cout << __FILE__ << ":" << __LINE__ << "Warning: the selected preconditioner does not support this option" << std::endl;
1089  }
1090  }
1091 
1098  {
1099  if (atype == HYPRE_AMG)
1100  {
1101  PETSC_SAFE_CALL(PetscOptionsSetValue(NULL,"-pc_hypre_boomeramg_max_iter",std::to_string(nit).c_str()));
1102  }
1103  else
1104  {
1105  std::cout << __FILE__ << ":" << __LINE__ << "Warning: the selected preconditioner does not support this option" << std::endl;
1106  }
1107  }
1108 
1109 
1129  void setPreconditionerAMG_relax(const std::string & type, int k = REL_ALL)
1130  {
1131  if (atype == HYPRE_AMG)
1132  {
1133  if (k == REL_ALL)
1134  {PETSC_SAFE_CALL(PetscOptionsSetValue(NULL,"-pc_hypre_boomeramg_relax_type_all",type.c_str()));}
1135  else if (k == REL_UP)
1136  {PETSC_SAFE_CALL(PetscOptionsSetValue(NULL,"-pc_hypre_boomeramg_relax_type_up",type.c_str()));}
1137  else if (k == REL_DOWN)
1138  {PETSC_SAFE_CALL(PetscOptionsSetValue(NULL,"-pc_hypre_boomeramg_relax_type_down",type.c_str()));}
1139  }
1140  else
1141  {
1142  std::cout << __FILE__ << ":" << __LINE__ << "Warning: the selected preconditioner does not support this option" << std::endl;
1143  }
1144  }
1145 
1162  void setPreconditionerAMG_cycleType(const std::string & cycle_type, int sweep_up = -1, int sweep_dw = -1, int sweep_crs = -1)
1163  {
1164  if (atype == HYPRE_AMG)
1165  {
1166  PETSC_SAFE_CALL(PetscOptionsSetValue(NULL,"-pc_hypre_boomeramg_cycle_type",cycle_type.c_str()));
1167 
1168  if (sweep_dw != -1)
1169  {PETSC_SAFE_CALL(PetscOptionsSetValue(NULL,"-pc_hypre_boomeramg_grid_sweeps_down",std::to_string(sweep_up).c_str()));}
1170 
1171  if (sweep_up != -1)
1172  {PETSC_SAFE_CALL(PetscOptionsSetValue(NULL,"-pc_hypre_boomeramg_grid_sweeps_up",std::to_string(sweep_dw).c_str()));}
1173 
1174  if (sweep_crs != -1)
1175  {PETSC_SAFE_CALL(PetscOptionsSetValue(NULL,"-pc_hypre_boomeramg_grid_sweeps_coarse",std::to_string(sweep_crs).c_str()));}
1176  }
1177  else
1178  {
1179  std::cout << __FILE__ << ":" << __LINE__ << "Warning: the selected preconditioner does not support this option" << std::endl;
1180  }
1181  }
1182 
1193  void setPreconditionerAMG_coarsen(const std::string & type)
1194  {
1195  if (atype == HYPRE_AMG)
1196  {
1197  PETSC_SAFE_CALL(PetscOptionsSetValue(NULL,"-pc_hypre_boomeramg_coarsen_type",type.c_str()));
1198  }
1199  else
1200  {
1201  std::cout << __FILE__ << ":" << __LINE__ << "Warning: the selected preconditioner does not support this option" << std::endl;
1202  }
1203  }
1204 
1215  void setPreconditionerAMG_interp(const std::string & type)
1216  {
1217  if (atype == HYPRE_AMG)
1218  {
1219  PETSC_SAFE_CALL(PetscOptionsSetValue(NULL,"-pc_hypre_boomeramg_interp_type",type.c_str()));
1220  }
1221  else
1222  {
1223  std::cout << __FILE__ << ":" << __LINE__ << "Warning: the selected preconditioner does not support this option" << std::endl;
1224  }
1225  }
1226 
1245  {
1246  if (atype == HYPRE_AMG)
1247  {
1248  PETSC_SAFE_CALL(PetscOptionsSetValue(NULL,"-pc_hypre_boomeramg_nodal_coarsen",std::to_string(norm).c_str()));
1249  }
1250  else
1251  {
1252  std::cout << __FILE__ << ":" << __LINE__ << "Warning: the selected preconditioner does not support this option" << std::endl;
1253  }
1254  }
1255 
1262  {
1263  if (atype == HYPRE_AMG)
1264  {
1265  PETSC_SAFE_CALL(PetscOptionsSetValue(NULL,"-pc_hypre_boomeramg_eu_level",std::to_string(k).c_str()));
1266  }
1267  else
1268  {
1269  std::cout << __FILE__ << ":" << __LINE__ << "Warning: the selected preconditioner does not support this option" << std::endl;
1270  }
1271  }
1272 
1273 
1274 
1287  {
1288  this->block_sz = block_sz;
1289  }
1290 
1307  initial_guess = false)
1308  {
1309  Mat & A_ = A.getMat();
1310  const Vec & b_ = b.getVec();
1311 
1312  // We set the size of x according to the Matrix A
1313  PetscInt row;
1314  PetscInt col;
1315  PetscInt row_loc;
1316  PetscInt col_loc;
1317 
1318  PETSC_SAFE_CALL(KSPSetInitialGuessNonzero(ksp,PETSC_FALSE));
1319  PETSC_SAFE_CALL(MatGetSize(A_,&row,&col));
1320  PETSC_SAFE_CALL(MatGetLocalSize(A_,&row_loc,&col_loc));
1321 
1322  Vector<T,PETSC_BASE> x(row,row_loc);
1323  Vec & x_ = x.getVec();
1324 
1325  pre_solve_impl(A_,b_,x_);
1326  solve_simple(A_,b_,x_);
1327 
1328  x.update();
1329 
1330  return x;
1331  }
1332 
1344  {
1345  Mat & A_ = A.getMat();
1346  const Vec & b_ = b.getVec();
1347  Vec & x_ = x.getVec();
1348 
1349  /* // We set the size of x according to the Matrix A
1350  PetscInt row;
1351  PetscInt col;
1352  PetscInt row_loc;
1353  PetscInt col_loc;*/
1354 
1355  PETSC_SAFE_CALL(KSPSetInitialGuessNonzero(ksp,PETSC_TRUE));
1356 
1357  /*PETSC_SAFE_CALL(MatGetSize(A_,&row,&col));
1358  PETSC_SAFE_CALL(MatGetLocalSize(A_,&row_loc,&col_loc));*/
1359 
1360  pre_solve_impl(A_,b_,x_);
1361  solve_simple(A_,b_,x_);
1362 
1363  x.update();
1364 
1365  return x;
1366 
1367  /*pre_solve_impl(A_,b_,x_);
1368  solve_simple(A_,b_,x_);
1369  x.update();
1370 
1371  return true;*/
1372  }
1373 
1383  Vector<T,PETSC_BASE> solve_successive(const Vector<T,PETSC_BASE> & b,bool initial_guess = false)
1384  {
1385  const Vec & b_ = b.getVec();
1386  // We set the size of x according to the Matrix A
1387  PetscInt row;
1388  PetscInt row_loc;
1389 
1390  PETSC_SAFE_CALL(KSPSetInitialGuessNonzero(ksp,PETSC_FALSE));
1391 
1392  PETSC_SAFE_CALL(VecGetSize(b_,&row));
1393  PETSC_SAFE_CALL(VecGetLocalSize(b_,&row_loc));
1394  Vector<T,PETSC_BASE> x(row,row_loc);
1395  Vec & x_ = x.getVec();
1396  PETSC_SAFE_CALL(KSPSetNormType(ksp,KSP_NORM_UNPRECONDITIONED));
1397  solve_simple(b_,x_);
1398 
1399  x.update();
1400 
1401  return x;
1402 
1403  /*pre_solve_impl(A_,b_,x_);
1404  solve_simple(A_,b_,x_);
1405  x.update();
1406 
1407  return true;*/
1408  }
1409 
1420  {
1421  const Vec & b_ = b.getVec();
1422  Vec & x_ = x.getVec();
1423 
1424  /* // We set the size of x according to the Matrix A
1425  PetscInt row;
1426  PetscInt col;
1427  PetscInt row_loc;
1428  PetscInt col_loc;*/
1429 
1430  PETSC_SAFE_CALL(KSPSetInitialGuessNonzero(ksp,PETSC_TRUE));
1431 
1432  /*PETSC_SAFE_CALL(MatGetSize(A_,&row,&col));
1433  PETSC_SAFE_CALL(MatGetLocalSize(A_,&row_loc,&col_loc));*/
1434 
1435  PETSC_SAFE_CALL(KSPSetNormType(ksp,KSP_NORM_UNPRECONDITIONED));
1436 
1437  solve_simple(b_,x_);
1438 
1439  x.update();
1440 
1441  return x;
1442 
1443  /*pre_solve_impl(A_,b_,x_);
1444  solve_simple(A_,b_,x_);
1445  x.update();
1446 
1447  return true;*/
1448  }
1449 
1466  PETSC_BASE> & b, bool initial_guess = false,bool symmetric = false)
1467  {
1468 #ifndef __arm64__
1469  Mat & A_ = A.getMat();
1470  const Vec & b_ = b.getVec();
1471 
1472  // We set the size of x according to the Matrix A
1473  PetscInt row;
1474  PetscInt col;
1475  PetscInt row_loc;
1476  PetscInt col_loc;
1477  PETSC_SAFE_CALL(KSPSetInitialGuessNonzero(ksp,PETSC_FALSE));
1478  PETSC_SAFE_CALL(MatGetSize(A_,&row,&col));
1479  PETSC_SAFE_CALL(MatGetLocalSize(A_,&row_loc,&col_loc));
1480 
1481 
1482  Vector<T,PETSC_BASE> x(row,row_loc);
1483  Vec & x_ = x.getVec();
1484 
1485  PETSC_SAFE_CALL(KSPSetFromOptions(ksp));
1486  PETSC_SAFE_CALL(KSPSetOperators(ksp,A_,A_));
1487  PETSC_SAFE_CALL(KSPSolve(ksp,b_,x_));
1488 
1489  Mat F, work, V;
1490  PetscInt N, rows;
1491 
1492  /* Determine factorability */
1493  //PETSC_SAFE_CALL(MatGetFactor(A_, MATSOLVERMUMPS, MAT_FACTOR_LU, &F));
1494  //PETSC_SAFE_CALL(MatGetLocalSize(A_, &rows, NULL));
1495 
1496  /* Set MUMPS options, see MUMPS documentation for more information */
1497  //PETSC_SAFE_CALL(MatMumpsSetIcntl(F, 24, 1));
1498  //PETSC_SAFE_CALL(MatMumpsSetIcntl(F, 25, 1));
1499 
1500  /* Perform factorization */
1501  //PETSC_SAFE_CALL(MatLUFactorSymbolic(F, A_, NULL, NULL, NULL));
1502  //PETSC_SAFE_CALL(MatLUFactorNumeric(F, A_, NULL));
1503 
1504  /* This is the dimension of the null space */
1505  //PETSC_SAFE_CALL(MatMumpsGetInfog(F, 28, &N));
1506  /* This will contain the null space in the columns */
1507  PETSC_SAFE_CALL(MatCreateDense(PETSC_COMM_WORLD, rows, N, PETSC_DETERMINE, PETSC_DETERMINE, NULL, &V));
1508  PETSC_SAFE_CALL(MatDuplicate(V, MAT_DO_NOT_COPY_VALUES, &work));
1509  PETSC_SAFE_CALL(MatMatSolve(F, work, V));
1510 
1511  std::cout<<"Dimension:" << N;
1512  Vec nvec[N];
1513  for(int i=0;i<N;i++)
1514  {
1515  PETSC_SAFE_CALL(MatGetColumnVector(V,nvec[i],i));
1516  }
1517  MatNullSpace nullspace;
1518 
1519  PETSC_SAFE_CALL(MatNullSpaceCreate(PETSC_COMM_WORLD,PETSC_TRUE,N,nvec,&nullspace));
1520  PETSC_SAFE_CALL(MatSetTransposeNullSpace(A_,nullspace));
1521  PETSC_SAFE_CALL(MatSetNullSpace(A_,nullspace));
1522  PETSC_SAFE_CALL(MatNullSpaceDestroy(&nullspace));
1523 
1524  PETSC_SAFE_CALL(KSPSetOperators(ksp,A_,A_));
1525  PETSC_SAFE_CALL(KSPSetFromOptions(ksp));
1526  PETSC_SAFE_CALL(KSPSolve(ksp,b_,x_));
1527  x.update();
1528 
1529  return x;
1530 #endif
1531  }
1532 
1542  KSP getKSP()
1543  {
1544  return ksp;
1545  }
1546 
1558  {
1559  return getSolNormError(A.getMat(),b.getVec(),x.getVec());
1560  }
1561 
1571  {
1572  return getSolNormError(b.getVec(),x.getVec(),ksp);
1573  }
1574 
1583  {
1584  const Vec & b_ = b.getVec();
1585 
1586  // We set the size of x according to the Matrix A
1587  PetscInt row;
1588  PetscInt row_loc;
1589 
1590  PETSC_SAFE_CALL(KSPSetInitialGuessNonzero(ksp,PETSC_FALSE));
1591  PETSC_SAFE_CALL(VecGetSize(b_,&row));
1592  PETSC_SAFE_CALL(VecGetLocalSize(b_,&row_loc));
1593 
1594  Vector<T,PETSC_BASE> x(row,row_loc);
1595  Vec & x_ = x.getVec();
1596 
1597  solve_simple(b_,x_);
1598  x.update();
1599 
1600  return x;
1601  }
1602 
1618  {
1619  const Vec & b_ = b.getVec();
1620  Vec & x_ = x.getVec();
1621 
1622  solve_simple(b_,x_);
1623  x.update();
1624 
1625  return true;
1626  }
1627 
1636  void setPetscOption(const char * name, const char * value)
1637  {
1638  PetscOptionsSetValue(NULL,name,value);
1639  }
1640 
1653  {
1654  Mat & A_ = A.getMat();
1655  const Vec & b_ = b.getVec();
1656 
1657  // We set the size of x according to the Matrix A
1658  PetscInt row;
1659  PetscInt col;
1660  PetscInt row_loc;
1661  PetscInt col_loc;
1662 
1663  PETSC_SAFE_CALL(KSPSetInitialGuessNonzero(ksp,PETSC_FALSE));
1664  PETSC_SAFE_CALL(MatGetSize(A_,&row,&col));
1665  PETSC_SAFE_CALL(MatGetLocalSize(A_,&row_loc,&col_loc));
1666 
1667  Vector<T,PETSC_BASE> x(row,row_loc);
1668  Vec & x_ = x.getVec();
1669 
1670  pre_solve_impl(A_,b_,x_);
1671  try_solve_simple(A_,b_,x_);
1672 
1673  x.update();
1674 
1675  return x;
1676  }
1677 };
1678 
1679 #endif
1680 
1681 #endif /* OPENFPM_NUMERICS_SRC_SOLVERS_PETSC_SOLVER_HPP_ */
std::string to_string_with_precision(const T myValue, const size_t n=6)
Converts value into string maintaining a desired precision.
Small class to produce graph with Google chart in HTML.
void write(std::string file)
It write the graphs on file in html format using Google charts.
void AddLinesGraph(openfpm::vector< X > &x, openfpm::vector< Y > &y, const GCoptions &opt)
Add a simple lines graph.
void AddHistGraph(openfpm::vector< Y > &y)
Add an histogram graph.
void addHTML(const std::string &html)
Add HTML text.
Sparse Matrix implementation.
PETSC vector for linear algebra.
Sparse Matrix implementation stub object when OpenFPM is compiled with no linear algebra support.
Definition: Vector.hpp:40
Implementation of 1-D std::vector like structure.
Definition: map_vector.hpp:204
size_t size()
Stub size.
Definition: map_vector.hpp:212
This class is able to do Matrix inversion in parallel with PETSC solvers.
Vector< T, PETSC_BASE > return_type
Type of the solution object.
size_t tmp
Temporal variable used for calculation of static members.
void setRelTol(PetscReal rtol_)
Set the relative tolerance as stop criteria.
KSP ksp
Main parallel solver.
PetscInt maxits
KSP Maximum number of iterations.
openfpm::vector< solv_bench_info > bench
It contain the solver benchmark results.
Vector< T, PETSC_BASE > solve(SparseMatrix< T, int, PETSC_BASE > &A, const Vector< T, PETSC_BASE > &b, bool initial_guess=false)
Here we invert the matrix and solve the system.
void bench_solve_simple(const Mat &A_, const Vec &b_, Vec &x_, solv_bench_info &bench)
Benchmark solve simple solving x=inv(A)*b.
void progress(PetscInt it)
This function print an "*" showing the progress of the solvers.
void print_stat(solError &err)
Print statistic about the solution error and method used.
static solError statSolutionError(const Mat &A_, const Vec &b_, Vec &x_, KSP ksp)
Calculate statistic on the error solution.
static T calculate_it(T t, solv_bench_info &slv)
Calculate the residual error at time t for one method.
void setDivTol(PetscReal dtol_)
Set the divergence tolerance.
void pre_solve_impl(const Mat &A_, const Vec &b_, Vec &x_)
It set up the solver based on the provided options.
void setPreconditionerAMG_cycleType(const std::string &cycle_type, int sweep_up=-1, int sweep_dw=-1, int sweep_crs=-1)
It set the type of cycle and optionally the number of sweep.
void try_solve_simple(const Mat &A_, const Vec &b_, Vec &x_)
Try to solve the system x=inv(A)*b using all the Krylov solvers with simple Jacobi pre-conditioner.
void write_bench_report()
Here we write the benchmark report.
void new_bench(const std::string &str)
Allocate a new benchmark slot for a method.
solError get_residual_error(SparseMatrix< T, int, PETSC_BASE > &A, const Vector< T, PETSC_BASE > &x, const Vector< T, PETSC_BASE > &b)
It return the resiual error.
void setBlockSize(int block_sz)
Set how many degree of freedom each node has.
Vector< T, PETSC_BASE > with_nullspace_solve(SparseMatrix< T, int, PETSC_BASE > &A, const Vector< T, PETSC_BASE > &b, bool initial_guess=false, bool symmetric=false)
Here we invert the matrix and solve the system using a Nullspace for Neumann BC.
solError get_residual_error(const Vector< T, PETSC_BASE > &x, const Vector< T, PETSC_BASE > &b)
It return the resiual error.
static solError getSolNormError(const Mat &A_, const Vec &b_, const Vec &x_)
Return the norm error of the solution.
void print_preconditioner()
Print the preconditioner used by the solver.
void solve_simple(const Vec &b_, Vec &x_)
solve simple use a Krylov solver + Simple selected Parallel Pre-conditioner
void removeTestSolver(const std::string &solver)
Remove a test solver.
bool is_preconditioner_set
indicate if the preconditioner is set
void copy_if_better(T res, Vec &sol, T &best_res, Vec &best_sol)
Copy the solution if better.
void initKSP()
initialize the KSP object
Vector< T, PETSC_BASE > solve_successive(Vector< T, PETSC_BASE > &x, const Vector< T, PETSC_BASE > &b)
Here we invert the matrix and solve the system with previous operator and initial guess.
void searchDirections(PetscInt l)
Vector< T, PETSC_BASE > solve_successive(const Vector< T, PETSC_BASE > &b, bool initial_guess=false)
Here we invert the matrix and solve the system with previous operator.
std::string to_string_method(const std::string &solv)
It convert the KSP type into a human read-able string.
KSP getKSP()
Return the KSP solver.
void solve_simple(const Mat &A_, const Vec &b_, Vec &x_)
solve simple use a Krylov solver + Simple selected Parallel Pre-conditioner
void setPreconditionerAMG_nl(int nl)
Set the number of levels for the algebraic-multigrid preconditioner.
Vector< T, PETSC_BASE > solve(const Vector< T, PETSC_BASE > &b)
Here we invert the matrix and solve the system.
void log_monitor()
Set the Petsc solver.
void setPreconditionerAMG_coarsenNodalType(int norm)
Set the block coarsening norm type.
void setPreconditionerAMG_interp(const std::string &type)
Set the interpolation method for the algebraic-multi-grid preconditioner.
void setPreconditioner(PCType type)
Set the preconditioner of the linear solver.
void setPreconditionerAMG_coarsen(const std::string &type)
Set the coarsening method for the algebraic-multi-grid preconditioner.
static PetscErrorCode monitor_progress_residual(KSP ksp, PetscInt it, PetscReal res, void *data)
procedure print the progress of the solver in benchmark mode
void addTestSolver(std::string &solver)
Add a test solver.
void initKSPForTest()
initialize the KSP object for solver testing
int block_sz
Block size.
void setPreconditionerAMG_interp_eu_level(int k)
Indicate the number of levels in the ILU(k) for the Euclid smoother.
void setSolver(KSPType type)
Set the Petsc solver.
void destroyKSP()
Destroy the KSP object.
AMG_type atype
Type of the algebraic multi-grid preconditioner.
openfpm::vector< std::string > solvs
The full set of solvers.
void setPreconditionerAMG_relax(const std::string &type, int k=REL_ALL)
Set the relaxation method for the algebraic-multi-grid preconditioner.
void setMaxIter(PetscInt n)
Set the maximum number of iteration for Krylov solvers.
void setAbsTol(PetscReal abstol_)
Set the absolute tolerance as stop criteria.
Vector< T, PETSC_BASE > try_solve(SparseMatrix< T, int, PETSC_BASE > &A, const Vector< T, PETSC_BASE > &b)
Try to solve the system using all the solvers and generate a report.
void print_ksptype()
Print the ksp_type used by the solver.
void setPreconditionerAMG_maxit(int nit)
Set the maximum number of V or W cycle for algebraic-multi-grid.
bool solve(Vector< T, PETSC_BASE > &x, const Vector< T, PETSC_BASE > &b)
Here we invert the matrix and solve the system.
Vector< T, PETSC_BASE > solve(SparseMatrix< T, int, PETSC_BASE > &A, Vector< T, PETSC_BASE > &x, const Vector< T, PETSC_BASE > &b)
Here we invert the matrix and solve the system.
static solError getSolNormError(const Vec &b_, const Vec &x_, KSP ksp)
Return the norm error of the solution.
void setRestart(PetscInt n)
For GMRES based method, the number of Krylov directions to orthogonalize against.
void print_progress_bar()
Print a progress bar on standard out.
void setPetscOption(const char *name, const char *value)
this function give you the possibility to set PETSC options
Class for cpu time benchmarking.
Definition: timer.hpp:28
KeyT const ValueT ValueT OffsetIteratorT OffsetIteratorT int
[in] The number of segments that comprise the sorting data
[v_transform metafunction]
Google chart options.
Definition: GoogleChart.hpp:26
std::string xAxis
X axis name.
Definition: GoogleChart.hpp:32
size_t lineWidth
Width of the line.
Definition: GoogleChart.hpp:56
std::string more
more
Definition: GoogleChart.hpp:67
std::string title
Title of the chart.
Definition: GoogleChart.hpp:28
std::string stype
Definition: GoogleChart.hpp:38
std::string yAxis
Y axis name.
Definition: GoogleChart.hpp:30
contain the infinity norm of the residual at each iteration
PetscReal err_norm
error norm at iteration it
PetscInt it
Iteration.
It contain the benchmark information for each solver.
T time
time to converge in milliseconds
std::string method
Solver Krylov name.
std::string smethod
Method name (short form)
solError err
Solution error.
openfpm::vector< itError > res
Convergence per iteration.
It contain statistic of the error of the calculated solution.
PetscReal err_inf
infinity norm of the error
PetscInt its
Number of iterations.
PetscReal err_norm
L1 norm of the error.