Amesos2 - Direct Sparse Solver Interfaces Version of the Day
Amesos2_PardisoMKL_def.hpp
Go to the documentation of this file.
1// @HEADER
2// *****************************************************************************
3// Amesos2: Templated Direct Sparse Solver Package
4//
5// Copyright 2011 NTESS and the Amesos2 contributors.
6// SPDX-License-Identifier: BSD-3-Clause
7// *****************************************************************************
8// @HEADER
9
10
19#ifndef AMESOS2_PARDISOMKL_DEF_HPP
20#define AMESOS2_PARDISOMKL_DEF_HPP
21
22#include <Teuchos_Tuple.hpp>
23#include <Teuchos_toString.hpp>
24#include <Teuchos_StandardParameterEntryValidators.hpp>
25
28
29
30namespace Amesos2 {
31
32 namespace PMKL {
33# include <mkl.h>
34# include <mkl_pardiso.h>
35 }
36
37 template <class Matrix, class Vector>
38 PardisoMKL<Matrix,Vector>::PardisoMKL(Teuchos::RCP<const Matrix> A,
39 Teuchos::RCP<Vector> X,
40 Teuchos::RCP<const Vector> B)
41 : SolverCore<Amesos2::PardisoMKL,Matrix,Vector>(A, X, B) // instantiate superclass
42 , n_(Teuchos::as<int_t>(this->globalNumRows_))
43 , perm_(this->globalNumRows_)
44 , nrhs_(0)
45 , partial_facto_ (0)
46 , schur_size_ (0)
47 , schur_out_ptr_(nullptr)
48 , pardiso_initialized_(false)
49 , only_forward_solve_(false)
50 , only_backward_solve_(false)
51 , is_contiguous_(true)
52 , msglvl_(0)
53 , debug_level_(0)
54 {
55 // set the default matrix type
57
58 PMKL::_INTEGER_t iparm_temp[64];
59 PMKL::_INTEGER_t mtype_temp = mtype_;
60 PMKL::pardisoinit(pt_, &mtype_temp, iparm_temp);
61
62 for( int i = 0; i < 64; ++i ){
63 iparm_[i] = iparm_temp[i];
64 }
65 iparm_[0] = 1; // do not use solver defaults
66
67 // set single or double precision
68 if constexpr ( std::is_same_v<solver_magnitude_type, PMKL::_REAL_t> ) {
69 iparm_[27] = 1; // single-precision
70 } else {
71 iparm_[27] = 0; // double-precision
72 }
73
74 // Reset some of the default parameters
75 iparm_[34] = 1; // Use zero-based indexing
76#ifdef HAVE_AMESOS2_DEBUG
77 iparm_[26] = 1; // turn the Pardiso matrix checker on
78#endif
79 }
80
81
82 template <class Matrix, class Vector>
84 {
85 /*
86 * Free any memory allocated by the PardisoMKL library functions
87 */
88 int_t error = 0;
89 void *bdummy, *xdummy;
90 if( this->root_ && pardiso_initialized_){
91 int_t phase = -1; // release all internal solver memory
92 function_map::pardiso( pt_, const_cast<int_t*>(&maxfct_),
93 const_cast<int_t*>(&mnum_), &mtype_, &phase, &n_,
94 nzvals_view_.data(), rowptr_view_.data(),
95 colind_view_.data(), perm_.getRawPtr(), &nrhs_, iparm_,
96 const_cast<int_t*>(&msglvl_), &bdummy, &xdummy, &error );
97 pardiso_initialized_ = false;
98 }
99
100 check_pardiso_mkl_error(Amesos2::CLEAN, error);
101 }
102
103
104 template<class Matrix, class Vector>
105 int
107 {
108 // preOrdering done in PardisoMKL during "Analysis" (aka symbolic
109 // factorization) phase
110
111 return(0);
112 }
113
114
115 template <class Matrix, class Vector>
116 int
118 {
119 using Teuchos::as;
120
121 int_t error = 0;
122 if( this->root_ ){
123#ifdef HAVE_AMESOS2_TIMERS
124 Teuchos::TimeMonitor symbFactTimer( this->timers_.symFactTime_ );
125#endif
126
127 solver_scalar_type bdummy, xdummy; // to be cased to void*
128 if( pardiso_initialized_){
129 int_t phase = -1; // release all internal solver memory
130 function_map::pardiso( pt_, const_cast<int_t*>(&maxfct_),
131 const_cast<int_t*>(&mnum_), &mtype_, &phase, &n_,
132 nzvals_view_.data(), rowptr_view_.data(),
133 colind_view_.data(), perm_.getRawPtr(), &nrhs_, iparm_,
134 const_cast<int_t*>(&msglvl_), as<void*>(&bdummy), as<void*>(&xdummy), &error );
135 if (msglvl_ > 0 && error != 0) {
136 if (error != 0) {
137 std::cout << " PardisoMKL::symbolicFactorization: clean-up failed with " << error << std::endl;
138 } else {
139 std::cout << " PardisoMKL::symbolicFactorization: cleaned-up before calling symbolic" << error;
140 }
141 }
142 pardiso_initialized_ = false;
143 }
144 int_t phase = 11;
145 function_map::pardiso( pt_, const_cast<int_t*>(&maxfct_),
146 const_cast<int_t*>(&mnum_), &mtype_, &phase, &n_,
147 nzvals_view_.data(), rowptr_view_.data(),
148 colind_view_.data(), perm_.getRawPtr(), &nrhs_, iparm_,
149 const_cast<int_t*>(&msglvl_), as<void*>(&bdummy), as<void*>(&xdummy), &error );
150 pardiso_initialized_ = true;
151 }
152 check_pardiso_mkl_error(Amesos2::SYMBFACT, error);
153
154 if (msglvl_ > 0 && this->root_) {
155 std::cout << " PardisoMKL::symbolicFactorization done:" << std::endl;
156#ifdef HAVE_AMESOS2_TIMERS
157 std::cout << " * Time : " << this->timers_.symFactTime_.totalElapsedTime() << std::endl;
158#else
159 std::cout << " * Time : not enabled" << std::endl;
160#endif
161 }
162
163 // Pardiso only lets you retrieve the total number of factor
164 // non-zeros, not for each individually. We should document how
165 // such a situation is reported.
166 this->setNnzLU(iparm_[17]);
167
168 return(0);
169 }
170
171
172 template <class Matrix, class Vector>
173 int
175 {
176 using Teuchos::as;
177
178 int_t error = 0;
179 if( this->root_ ){
180#ifdef HAVE_AMESOS2_TIMERS
181 Teuchos::TimeMonitor numFactTimer( this->timers_.numFactTime_ );
182#endif
183
184 int_t phase = 22;
185 solver_scalar_type bdummy; // to be casted to void*
186 solver_scalar_type *xdummy = schur_out_.data();
187 function_map::pardiso( pt_, const_cast<int_t*>(&maxfct_),
188 const_cast<int_t*>(&mnum_), &mtype_, &phase, &n_,
189 nzvals_view_.data(), rowptr_view_.data(),
190 colind_view_.data(), perm_.getRawPtr(), &nrhs_, iparm_,
191 const_cast<int_t*>(&msglvl_), as<void*>(&bdummy), as<void*>(xdummy), &error );
192
193 if (error == 0 && partial_facto_ != 0) {
194 if (schur_out_ptr_ != nullptr) {
195 // copy schur out if the output pointer is valid (assuming enough space has been allocated)
196 // Pardiso returns the Schur complement in row-major
197 // So, we transpose it to store in column-major
198 for (size_t i = 0; i < schur_size_; i++) {
199 for (size_t j = 0; j < schur_size_; j++) {
200 schur_out_ptr_[i+j*schur_size_] = as<scalar_type>(schur_out_[j+i*schur_size_]);
201 }
202 }
203 }
204 }
205 }
206 check_pardiso_mkl_error(Amesos2::NUMFACT, error);
207
208 if (msglvl_ > 0 && this->root_) {
209 std::cout << " PardisoMKL::numericFactorization done:" << std::endl;
210#ifdef HAVE_AMESOS2_TIMERS
211 std::cout << " * Time : " << this->timers_.numFactTime_.totalElapsedTime() << std::endl;
212#else
213 std::cout << " * Time : not enabled" << std::endl;
214#endif
215 }
216
217 return( 0 );
218 }
219
220
221 template <class Matrix, class Vector>
222 int
224 const Teuchos::Ptr<const MultiVecAdapter<Vector> > B) const
225 {
226 using Teuchos::as;
227
228 int_t error = 0;
229
230 // Get B data
231 const global_size_type ld_rhs = this->root_ ? X->getGlobalLength() : 0;
232 nrhs_ = as<int_t>(X->getGlobalNumVectors());
233 if (debug_level_ > 0) {
234 if (this->root_) std::cout << "\n == Amesos2_PardisoMKL::solve_impl ==" << std::endl;
235 if (debug_level_ == 1) {
236 B->description();
237 } else {
238 Teuchos::RCP<Teuchos::FancyOStream> fancy = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout));
239 if (!is_null(B->getMap())) B->getMap()->describe(*fancy, Teuchos::VERB_EXTREME);
240 std::cout << std::endl;
241 B->describe(*fancy, Teuchos::VERB_EXTREME);
242 }
243 }
244
245 { // Get values from RHS B
246#ifdef HAVE_AMESOS2_TIMERS
247 Teuchos::TimeMonitor mvConvTimer( this->timers_.vecConvTime_ );
248 Teuchos::TimeMonitor redistTimer( this->timers_.vecRedistTime_ );
249#endif
250
251 const bool initialize_data = true;
252 const bool do_not_initialize_data = false;
253 Util::get_1d_copy_helper_kokkos_view<MultiVecAdapter<Vector>,
254 host_solver_scalar_view>::do_get(initialize_data, B, bvals_,
255 as<size_t>(ld_rhs),
256 (is_contiguous_ == true) ? ROOTED : CONTIGUOUS_AND_ROOTED,
257 this->rowIndexBase_);
258 Util::get_1d_copy_helper_kokkos_view<MultiVecAdapter<Vector>,
259 host_solver_scalar_view>::do_get(do_not_initialize_data, X, xvals_,
260 as<size_t>(ld_rhs),
261 (is_contiguous_ == true) ? ROOTED : CONTIGUOUS_AND_ROOTED,
262 this->rowIndexBase_);
263 }
264
265 if( this->root_ ){
266#ifdef HAVE_AMESOS2_TIMERS
267 Teuchos::TimeMonitor solveTimer( this->timers_.solveTime_ );
268#endif
269
270 int_t phase = 33; // forward & backward solve
271 if (only_forward_solve_) {
272 // forward solve
273 phase = 331;
274 if (wvals_.extent(0) != n_ || wvals_.extent(1) != nrhs_) {
275 Kokkos::resize(wvals_, n_, nrhs_);
276 }
277 } else if (only_backward_solve_) {
278 // backward solve
279 phase = 333;
280 if (wvals_.extent(0) != n_ || wvals_.extent(1) != nrhs_) {
281 Kokkos::resize(wvals_, n_, nrhs_);
282 }
283 // for consistent interface with other solvers (e.g., ShyLU-Basker)
284 // scatter RHS vectors (based on schur-part)
285 // input RHS for backward-solve has interior part followed by schur complement
286 size_t n1 = 0;
287 size_t n2 = this->globalNumCols_-schur_size_;
288 for (global_size_type i=0; i<n_; i++) {
289 if (schur_part_(i) == 1) {
290 for (size_t j=0; j<nrhs_; j++) {
291 wvals_(i,j) = bvals_(n2,j);
292 }
293 n2 ++;
294 } else {
295 for (size_t j=0; j<nrhs_; j++) {
296 wvals_(i,j) = bvals_(n1,j);
297 }
298 n1 ++;
299 }
300 }
301 }
302 solver_scalar_type *b_in = (only_backward_solve_ ? wvals_.data() : bvals_.data());
303 solver_scalar_type *x_out = (only_forward_solve_ ? wvals_.data() : xvals_.data());
304 function_map::pardiso( pt_,
305 const_cast<int_t*>(&maxfct_),
306 const_cast<int_t*>(&mnum_),
307 const_cast<int_t*>(&mtype_),
308 const_cast<int_t*>(&phase),
309 const_cast<int_t*>(&n_),
310 const_cast<solver_scalar_type*>(nzvals_view_.data()),
311 const_cast<int_t*>(rowptr_view_.data()),
312 const_cast<int_t*>(colind_view_.data()),
313 const_cast<int_t*>(perm_.getRawPtr()),
314 &nrhs_,
315 const_cast<int_t*>(iparm_),
316 const_cast<int_t*>(&msglvl_),
317 as<void*>(b_in),
318 as<void*>(x_out), &error );
319 if (only_forward_solve_) {
320 // for consistent interface with other solvers (e.g., ShyLU-Basker)
321 // gather solution vectors (based on schur-part)
322 // output vector should have interior part followed by schur complement
323 size_t n1 = 0;
324 size_t n2 = this->globalNumCols_-schur_size_;
325 for (global_size_type i=0; i<n_; i++) {
326 if (schur_part_(i) == 1) {
327 for (size_t j=0; j<nrhs_; j++) {
328 xvals_(n2,j) = wvals_(i,j);
329 }
330 n2 ++;
331 } else {
332 for (size_t j=0; j<nrhs_; j++) {
333 xvals_(n1,j) = wvals_(i,j);
334 }
335 n1 ++;
336 }
337 }
338 }
339 }
340 check_pardiso_mkl_error(Amesos2::SOLVE, error);
341
342 /* Export X from root to the global space */
343 {
344#ifdef HAVE_AMESOS2_TIMERS
345 Teuchos::TimeMonitor redistTimer(this->timers_.vecRedistTime_);
346#endif
347
348 Util::put_1d_data_helper_kokkos_view<
349 MultiVecAdapter<Vector>,host_solver_scalar_view>::do_put(X, xvals_,
350 as<size_t>(ld_rhs),
351 (is_contiguous_ == true) ? ROOTED : CONTIGUOUS_AND_ROOTED,
352 this->rowIndexBase_);
353 }
354 if (debug_level_ > 0) {
355 if (debug_level_ == 1) {
356 X->description();
357 } else {
358 Teuchos::RCP<Teuchos::FancyOStream> fancy = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout));
359 if (!is_null(X->getMap())) X->getMap()->describe(*fancy, Teuchos::VERB_EXTREME);
360 std::cout << std::endl;
361 X->describe(*fancy, Teuchos::VERB_EXTREME);
362 }
363 }
364 if (msglvl_ > 0 && this->root_) {
365 std::cout << " PardisoMKL::solve done:" << std::endl;
366#ifdef HAVE_AMESOS2_TIMERS
367 std::cout << " * Time : " << this->timers_.vecRedistTime_.totalElapsedTime()
368 << " + " << this->timers_.solveTime_.totalElapsedTime() << std::endl;
369#else
370 std::cout << " * Time : not enabled" << std::endl;
371#endif
372 }
373
374 return( 0 );
375}
376
377
378 template <class Matrix, class Vector>
379 bool
381 {
382 // PardisoMKL supports square matrices
383 return( this->globalNumRows_ == this->globalNumCols_ );
384 }
385
386
387 template <class Matrix, class Vector>
388 void
389 PardisoMKL<Matrix,Vector>::setParameters_impl(const Teuchos::RCP<Teuchos::ParameterList> & parameterList )
390 {
391 using Teuchos::RCP;
392 using Teuchos::getIntegralValue;
393 using Teuchos::ParameterEntryValidator;
394
395 RCP<const Teuchos::ParameterList> valid_params = getValidParameters_impl();
396
397 // Fill-in reordering: 0 = minimum degree, 2 = METIS 4.0.1 (default), 3 = METIS 5.1, 4 = AMD,
398 if( parameterList->isParameter("IPARM(2)") )
399 {
400 RCP<const ParameterEntryValidator> fillin_validator = valid_params->getEntry("IPARM(2)").validator();
401 parameterList->getEntry("IPARM(2)").setValidator(fillin_validator);
402 iparm_[1] = getIntegralValue<int>(*parameterList, "IPARM(2)");
403 }
404
405 // Iterative-direct algorithm
406 if( parameterList->isParameter("IPARM(4)") )
407 {
408 RCP<const ParameterEntryValidator> prec_validator = valid_params->getEntry("IPARM(4)").validator();
409 parameterList->getEntry("IPARM(4)").setValidator(prec_validator);
410 iparm_[3] = getIntegralValue<int>(*parameterList, "IPARM(4)");
411 }
412
413 // Max numbers of iterative refinement steps
414 if( parameterList->isParameter("IPARM(8)") )
415 {
416 RCP<const ParameterEntryValidator> refine_validator = valid_params->getEntry("IPARM(8)").validator();
417 parameterList->getEntry("IPARM(8)").setValidator(refine_validator);
418 iparm_[7] = getIntegralValue<int>(*parameterList, "IPARM(8)");
419 }
420
421 // Perturb the pivot elements
422 if( parameterList->isParameter("IPARM(10)") )
423 {
424 RCP<const ParameterEntryValidator> pivot_perturb_validator = valid_params->getEntry("IPARM(10)").validator();
425 parameterList->getEntry("IPARM(10)").setValidator(pivot_perturb_validator);
426 iparm_[9] = getIntegralValue<int>(*parameterList, "IPARM(10)");
427 }
428
429 // Scale vector for stability
430 if( parameterList->isParameter("IPARM(11)") )
431 {
432 RCP<const ParameterEntryValidator> mwm_validator = valid_params->getEntry("IPARM(11)").validator();
433 parameterList->getEntry("IPARM(11)").setValidator(mwm_validator);
434 iparm_[10] = getIntegralValue<int>(*parameterList, "IPARM(11)");
435 }
436
437 // First check if the control object requests a transpose solve.
438 // Then solver specific options can override this.
439 iparm_[11] = this->control_.useTranspose_ ? 2 : 0;
440
441 // Normal solve (0), or a transpose solve (1)
442 if( parameterList->isParameter("IPARM(12)") )
443 {
444 RCP<const ParameterEntryValidator> trans_validator = valid_params->getEntry("IPARM(12)").validator();
445 parameterList->getEntry("IPARM(12)").setValidator(trans_validator);
446 iparm_[11] = getIntegralValue<int>(*parameterList, "IPARM(12)");
447 }
448
449 // (Non-)symmetric matchings : detault 1 for nonsymmetric and 0 for symmetric matrix (default is nonsymmetric)
450 if( parameterList->isParameter("IPARM(13)") )
451 {
452 RCP<const ParameterEntryValidator> trans_validator = valid_params->getEntry("IPARM(13)").validator();
453 parameterList->getEntry("IPARM(13)").setValidator(trans_validator);
454 iparm_[12] = getIntegralValue<int>(*parameterList, "IPARM(13)");
455 }
456
457 // Output: Number of nonzeros in the factor LU
458 if( parameterList->isParameter("IPARM(18)") )
459 {
460 RCP<const ParameterEntryValidator> report_validator = valid_params->getEntry("IPARM(18)").validator();
461 parameterList->getEntry("IPARM(18)").setValidator(report_validator);
462 iparm_[17] = getIntegralValue<int>(*parameterList, "IPARM(18)");
463 }
464
465 // Scheduling method for the parallel numerical factorization
466 if( parameterList->isParameter("IPARM(24)") )
467 {
468 RCP<const ParameterEntryValidator> par_fact_validator = valid_params->getEntry("IPARM(24)").validator();
469 parameterList->getEntry("IPARM(24)").setValidator(par_fact_validator);
470 iparm_[23] = getIntegralValue<int>(*parameterList, "IPARM(24)");
471 }
472
473 // Parallelization scheme for the forward and backward solve
474 if( parameterList->isParameter("IPARM(25)") )
475 {
476 RCP<const ParameterEntryValidator> par_fbsolve_validator = valid_params->getEntry("IPARM(25)").validator();
477 parameterList->getEntry("IPARM(25)").setValidator(par_fbsolve_validator);
478 iparm_[24] = getIntegralValue<int>(*parameterList, "IPARM(25)");
479 }
480
481 // Check matrix
482 if( parameterList->isParameter("IPARM(27)") )
483 {
484 RCP<const ParameterEntryValidator> check_validator = valid_params->getEntry("IPARM(27)").validator();
485 parameterList->getEntry("IPARM(27)").setValidator(check_validator);
486 iparm_[26] = getIntegralValue<int>(*parameterList, "IPARM(27)");
487 }
488
489 // Graph compression scheme for METIS.
490 if( parameterList->isParameter("IPARM(60)") )
491 {
492 RCP<const ParameterEntryValidator> ooc_validator = valid_params->getEntry("IPARM(60)").validator();
493 parameterList->getEntry("IPARM(60)").setValidator(ooc_validator);
494 iparm_[59] = getIntegralValue<int>(*parameterList, "IPARM(60)");
495 }
496
497 // Partial factorization
498 // Note: partial_facto_ == 1 means iparam_[35] = 2 (compute and factor Schur)
499 // while partial_facto_ == 2 means iparam_[35] = 1 (only compute Schur)
500 if(parameterList->isParameter("PartialFacto")) {
501 partial_facto_ = parameterList->get<int>("PartialFacto");
502 if (partial_facto_ == 1)
503 iparm_[35] = 2; // calculate and factor Schur complement
504 else if (partial_facto_ == 2)
505 iparm_[35] = 1; // calculate Schur complement
506 }
507 if(parameterList->isParameter("SchurPart")) {
508 // copy schur-part to the internal view (in case the user-pointer go out of scope?)
509 auto schur_part_ptr = parameterList->get<const local_ordinal_type*>("SchurPart");
510 Kokkos::resize(schur_part_, this->globalNumCols_);
511
512 schur_size_ = 0;
513 for (global_size_type i=0; i<this->globalNumCols_; i++) {
514 schur_part_(i) = schur_part_ptr[i]; // keep track or schur part
515 perm_[i] = schur_part_ptr[i]; // input for pardiso
516 if (perm_[i] == 1) schur_size_ ++;
517 }
518 // allocate internal storage to store the schur complement (user may not want it and may not provide a valid pointer?)
519 size_t schur_size_2 = schur_size_*schur_size_;
520 Kokkos::resize(schur_out_, (schur_size_2 > 0 ? schur_size_2 : 1));
521
522 }
523 if(parameterList->isParameter("SchurOut")) {
524 // store schur-part to the internal view (if user wants the output, then the pointer should stay, so no need for internal view?)
525 schur_out_ptr_ = parameterList->get<scalar_type*>("SchurOut");
526 }
527 if(parameterList->isParameter("OnlyForwardSolve")) {
528 only_forward_solve_ = parameterList->get<bool>("OnlyForwardSolve");
529 }
530 if(parameterList->isParameter("OnlyBackwardSolve")) {
531 only_backward_solve_ = parameterList->get<bool>("OnlyBackwardSolve");
532 }
533
534
535 if( parameterList->isParameter("IsContiguous") ){
536 is_contiguous_ = parameterList->get<bool>("IsContiguous");
537 }
538 if( parameterList->isParameter("MessageLevel") ){
539 msglvl_ = parameterList->get<int>("MessageLevel");
540 }
541 if(parameterList->isParameter("verbose")){
542 bool verbose = parameterList->get<bool>("verbose");
543 if (verbose) msglvl_ = 1;
544 }
545 if( parameterList->isParameter("DebugLevel") ){
546 debug_level_ = parameterList->get<int>("DebugLevel");
547 }
548 }
549
550
551/*
552 * TODO: It would be nice if the parameters could be expressed as
553 * either all string or as all integers. I see no way of doing this
554 * at present with the standard validators. However, we could create
555 * our own validators or kindly ask the Teuchos team to add some
556 * features for use.
557 *
558 * The issue is that with the current validators we cannot specify
559 * arbitrary sets of numbers that are the only allowed parameters.
560 * For example the IPARM(2) parameter can take only the values 0, 2,
561 * and 3. The EnhancedNumberValidator can take a min value, and max
562 * value, and a step size, but with those options there is no way to
563 * specify the needed set.
564 *
565 * Another missing feature is the ability to give docstrings for such
566 * numbers. For example IPARM(25) can take on the values 0 and 1.
567 * This would be easy enough to accomplish with just a number
568 * validator, but then have no way to document the effect of each
569 * value.
570 */
571template <class Matrix, class Vector>
572Teuchos::RCP<const Teuchos::ParameterList>
574{
575 using std::string;
576 using Teuchos::as;
577 using Teuchos::RCP;
578 using Teuchos::tuple;
579 using Teuchos::toString;
580 using Teuchos::EnhancedNumberValidator;
581 using Teuchos::setStringToIntegralParameter;
582 using Teuchos::anyNumberParameterEntryValidator;
583
584 static Teuchos::RCP<const Teuchos::ParameterList> valid_params;
585
586 if( is_null(valid_params) ){
587 Teuchos::RCP<Teuchos::ParameterList> pl = Teuchos::parameterList();
588
589 // Use pardisoinit to get some default values;
590 void *pt_dummy[64];
591 PMKL::_INTEGER_t mtype_temp = mtype_;
592 PMKL::_INTEGER_t iparm_temp[64];
593 PMKL::pardisoinit(pt_dummy,
594 const_cast<PMKL::_INTEGER_t*>(&mtype_temp),
595 const_cast<PMKL::_INTEGER_t*>(iparm_temp));
596
597 setStringToIntegralParameter<int>("IPARM(2)", toString(iparm_temp[1]),
598 "Fill-in reducing ordering for the input matrix",
599 tuple<string>("0", "2", "3"),
600 tuple<string>("The minimum degree algorithm",
601 "Nested dissection algorithm from METIS",
602 "OpenMP parallel nested dissection algorithm"),
603 tuple<int>(0, 2, 3),
604 pl.getRawPtr());
605
606 Teuchos::RCP<EnhancedNumberValidator<int> > iparm_4_validator
607 = Teuchos::rcp( new EnhancedNumberValidator<int>() );
608 iparm_4_validator->setMin(0);
609 pl->set("IPARM(4)" , as<int>(iparm_temp[3]) , "Preconditioned CGS/CG",
610 iparm_4_validator);
611
612 setStringToIntegralParameter<int>("IPARM(12)", toString(iparm_temp[11]),
613 "Solve with transposed or conjugate transposed matrix A",
614 tuple<string>("0", "1", "2"),
615 tuple<string>("Non-transposed",
616 "Conjugate-transposed",
617 "Transposed"),
618 tuple<int>(0, 1, 2),
619 pl.getRawPtr());
620
621 setStringToIntegralParameter<int>("IPARM(13)", toString(iparm_temp[12]),
622 "Use weighted matching",
623 tuple<string>("0", "1"),
624 tuple<string>("No matching", "Use matching"),
625 tuple<int>(0, 1),
626 pl.getRawPtr());
627
628 setStringToIntegralParameter<int>("IPARM(24)", toString(iparm_temp[23]),
629 "Parallel factorization control",
630 tuple<string>("0", "1"),
631 tuple<string>("PARDISO uses the previous algorithm for factorization",
632 "PARDISO uses the new two-level factorization algorithm"),
633 tuple<int>(0, 1),
634 pl.getRawPtr());
635
636 setStringToIntegralParameter<int>("IPARM(25)", toString(iparm_temp[24]),
637 "Parallel forward/backward solve control",
638 tuple<string>("0", "1"),
639 tuple<string>("PARDISO uses the parallel algorithm for the solve step",
640 "PARDISO uses the sequential forward and backward solve"),
641 tuple<int>(0, 1),
642 pl.getRawPtr());
643
644 setStringToIntegralParameter<int>("IPARM(60)", toString(iparm_temp[59]),
645 "PARDISO mode (OOC mode)",
646 tuple<string>("0", "2"),
647 tuple<string>("In-core PARDISO",
648 "Out-of-core PARDISO. The OOC PARDISO can solve very "
649 "large problems by holding the matrix factors in files "
650 "on the disk. Hence the amount of RAM required by OOC "
651 "PARDISO is significantly reduced."),
652 tuple<int>(0, 2),
653 pl.getRawPtr());
654
655 Teuchos::AnyNumberParameterEntryValidator::EPreferredType preferred_int =
656 Teuchos::AnyNumberParameterEntryValidator::PREFER_INT;
657
658 Teuchos::AnyNumberParameterEntryValidator::AcceptedTypes accept_int( false );
659 accept_int.allowInt( true );
660
661 pl->set("IPARM(8)" , as<int>(iparm_temp[7]) , "Iterative refinement step",
662 anyNumberParameterEntryValidator(preferred_int, accept_int));
663
664 pl->set("IPARM(10)", as<int>(iparm_temp[9]) , "Pivoting perturbation",
665 anyNumberParameterEntryValidator(preferred_int, accept_int));
666 pl->set("IPARM(11)", as<int>(iparm_temp[10]) , "Scaling vectors",
667 anyNumberParameterEntryValidator(preferred_int, accept_int));
668
669 pl->set("IPARM(18)", as<int>(iparm_temp[17]), "Report the number of non-zero elements in the factors",
670 anyNumberParameterEntryValidator(preferred_int, accept_int));
671
672 pl->set("IPARM(27)", as<int>(iparm_temp[26]) , "Check input matrix",
673 anyNumberParameterEntryValidator(preferred_int, accept_int));
674
675 scalar_type *dummy_scalar_ptr;
676 const local_ordinal_type *dummy_ordinal_ptr;
677 pl->set("PartialFacto", 0,
678 "Perform partial factorization to extract dense Schur complement (0: no, 1: form + factor Schur, 2: ony form");
679 pl->set("SchurPart", dummy_ordinal_ptr,
680 "Specify rows/columns belonging to Schur complement for partial factorization");
681 pl->set("SchurOut", dummy_scalar_ptr,
682 "Store output Schur complement from partial factorization");
683 pl->set("OnlyForwardSolve", false,
684 "Perform only the forward substitution");
685 pl->set("OnlyBackwardSolve", false,
686 "Perform only the backward substitution");
687
688 pl->set("IsContiguous", true, "Whether GIDs contiguous");
689 pl->set("MessageLevel", 0, "PardisoMKL message level (0 to turn off message, and 1 to turn on message");
690 pl->set("verbose", false, "Set PardisoMKL message level to be 1");
691 pl->set("DebugLevel", 0, "Debug message level (0 for no message, and >0 for more message");
692
693 valid_params = pl;
694 }
695
696 return valid_params;
697}
698
699
700
701template <class Matrix, class Vector>
702bool
704{
705#ifdef HAVE_AMESOS2_TIMERS
706 Teuchos::TimeMonitor convTimer(this->timers_.mtxConvTime_);
707#endif
708 if (debug_level_ > 0) {
709 if (this->root_) {
710 std::cout << "\n == Amesos2_PardisoMKL::loadA_impl";
711 if (current_phase == PREORDERING) std::cout << "(PreOrder)";
712 if (current_phase == SYMBFACT) std::cout << "(SymFact)";
713 if (current_phase == NUMFACT) std::cout << "(NumFact)";
714 std::cout << " ==" << std::endl;
715 }
716 Teuchos::RCP<Teuchos::FancyOStream> fancy = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout));
717 this->matrixA_->describe(*fancy, (debug_level_ == 1 ? Teuchos::VERB_LOW : Teuchos::VERB_EXTREME));
718 }
719
720 // PardisoMKL does not need matrix data in the pre-ordering phase
721 if( current_phase == PREORDERING ) return( false );
722
723 if( this->root_ ){
724 Kokkos::resize(nzvals_view_, this->globalNumNonZeros_);
725 Kokkos::resize(colind_view_, this->globalNumNonZeros_);
726 Kokkos::resize(rowptr_view_, this->globalNumRows_ + 1);
727 }
728 {
729#ifdef HAVE_AMESOS2_TIMERS
730 Teuchos::TimeMonitor mtxRedistTimer( this->timers_.mtxRedistTime_ );
731#endif
732
733 int_t nnz_ret = 0;
736 host_value_type_array, host_ordinal_type_array, host_size_type_array>::do_get(
737 this->matrixA_.ptr(),
738 nzvals_view_, colind_view_, rowptr_view_, nnz_ret,
739 (is_contiguous_ == true) ? ROOTED : CONTIGUOUS_AND_ROOTED,
741 this->rowIndexBase_);
742 }
743
744 return( true );
745}
746
747
748template <class Matrix, class Vector>
749void
751 const Teuchos::EVerbosityLevel verbLevel) const
752{
753 out << " PardisoMKL current parameters:" << std::endl;
754 out << " > IPARM(2) = " << iparm_[1] << std::endl;
755 out << " > IPARM(4) = " << iparm_[3] << std::endl;
756 out << " > IPARM(8) = " << iparm_[7] << std::endl;
757 out << " > IPARM(10) = " << iparm_[9] << std::endl;
758 out << " > IPARM(11) = " << iparm_[10] << std::endl;
759 out << " > IPARM(12) = " << iparm_[11] << std::endl;
760 out << " > IPARM(13) = " << iparm_[12] << std::endl;
761 out << " > IPARM(18) = " << iparm_[17] << std::endl;
762 out << " > IPARM(24) = " << iparm_[23] << std::endl;
763 out << " > IPARM(25) = " << iparm_[24] << std::endl;
764 out << " > IPARM(27) = " << iparm_[26] << std::endl;
765 out << " > IPARM(60) = " << iparm_[59] << std::endl;
766 out << " > PartialFacto = " << partial_facto_;
767 if (partial_facto_ == 0)
768 out << " (no partial factorization)" << std::endl;
769 if (partial_facto_ == 1)
770 out << " (compute and factor schur complement : iparam_[35] = 2)" << std::endl;
771 if (partial_facto_ == 2)
772 out << " (only compute schur complement : iparam_[35] = 1)" << std::endl;
773 out << " > IsContiguous = " << (is_contiguous_ ? "YES" : "NO") << std::endl;
774 out << " > MessageLevel = " << msglvl_ << std::endl;
775 out << " > DebugLevel = " << debug_level_ << std::endl;
776 out << std::endl;
777}
778
779
780template <class Matrix, class Vector>
781void
783 int_t error) const
784{
785 int error_i = error;
786 Teuchos::broadcast(*(this->getComm()), 0, &error_i); // We only care about root's value
787
788 if( error_i == 0 ) return; // No error
789
790 std::string errmsg = "Other error";
791 switch( error_i ){
792 case -1:
793 errmsg = "PardisoMKL reported error: 'Input inconsistent'";
794 break;
795 case -2:
796 errmsg = "PardisoMKL reported error: 'Not enough memory'";
797 break;
798 case -3:
799 errmsg = "PardisoMKL reported error: 'Reordering problem'";
800 break;
801 case -4:
802 errmsg =
803 "PardisoMKL reported error: 'Zero pivot, numerical "
804 "factorization or iterative refinement problem'";
805 break;
806 case -5:
807 errmsg = "PardisoMKL reported error: 'Unclassified (internal) error'";
808 break;
809 case -6:
810 errmsg = "PardisoMKL reported error: 'Reordering failed'";
811 break;
812 case -7:
813 errmsg = "PardisoMKL reported error: 'Diagonal matrix is singular'";
814 break;
815 case -8:
816 errmsg = "PardisoMKL reported error: '32-bit integer overflow problem'";
817 break;
818 case -9:
819 errmsg = "PardisoMKL reported error: 'Not enough memory for OOC'";
820 break;
821 case -10:
822 errmsg = "PardisoMKL reported error: 'Problems with opening OOC temporary files'";
823 break;
824 case -11:
825 errmsg = "PardisoMKL reported error: 'Read/write problem with OOC data file'";
826 break;
827 }
828
829 TEUCHOS_TEST_FOR_EXCEPTION( true, std::runtime_error, errmsg );
830}
831
832
833template <class Matrix, class Vector>
834void
836{
837 if( mtype == 0 ){
838 if( complex_ ){
839 mtype_ = 13; // complex, unsymmetric
840 } else {
841 mtype_ = 11; // real, unsymmetric
842 }
843 } else {
844 switch( mtype ){
845 case 11:
846 TEUCHOS_TEST_FOR_EXCEPTION( complex_,
847 std::invalid_argument,
848 "Cannot set a real Pardiso matrix type with scalar type complex" );
849 mtype_ = 11; break;
850 case 13:
851 TEUCHOS_TEST_FOR_EXCEPTION( !complex_,
852 std::invalid_argument,
853 "Cannot set a complex Pardiso matrix type with non-complex scalars" );
854 mtype_ = 13; break;
855 default:
856 TEUCHOS_TEST_FOR_EXCEPTION( true,
857 std::invalid_argument,
858 "Symmetric matrices are not yet supported by the Amesos2 interface" );
859 }
860 }
861}
862
863
864template <class Matrix, class Vector>
865const char* PardisoMKL<Matrix,Vector>::name = "PARDISOMKL";
866
867template <class Matrix, class Vector>
868const typename PardisoMKL<Matrix,Vector>::int_t
870
871template <class Matrix, class Vector>
872const typename PardisoMKL<Matrix,Vector>::int_t
874
875} // end namespace Amesos
876
877#endif // AMESOS2_PARDISOMKL_DEF_HPP
A template class that does nothing useful besides show developers what, in general,...
@ ROOTED
Definition Amesos2_TypeDecl.hpp:93
@ CONTIGUOUS_AND_ROOTED
Definition Amesos2_TypeDecl.hpp:94
@ SORTED_INDICES
Definition Amesos2_TypeDecl.hpp:108
A Matrix adapter interface for Amesos2.
Definition Amesos2_MatrixAdapter_decl.hpp:42
Amesos2 interface to the PardisoMKL package.
Definition Amesos2_PardisoMKL_decl.hpp:48
Teuchos::RCP< const Teuchos::ParameterList > getValidParameters_impl() const
Definition Amesos2_PardisoMKL_def.hpp:573
void setParameters_impl(const Teuchos::RCP< Teuchos::ParameterList > &parameterList)
Definition Amesos2_PardisoMKL_def.hpp:389
void describe_impl(Teuchos::FancyOStream &out, const Teuchos::EVerbosityLevel verbLevel) const
Prints the status information about the current solver with some level of verbosity.
Definition Amesos2_PardisoMKL_def.hpp:750
~PardisoMKL()
Destructor.
Definition Amesos2_PardisoMKL_def.hpp:83
int_t mtype_
The matrix type. We deal only with unsymmetrix matrices.
Definition Amesos2_PardisoMKL_decl.hpp:265
PardisoMKL(Teuchos::RCP< const Matrix > A, Teuchos::RCP< Vector > X, Teuchos::RCP< const Vector > B)
Initialize from Teuchos::RCP.
Definition Amesos2_PardisoMKL_def.hpp:38
int_t iparm_[64]
Definition Amesos2_PardisoMKL_decl.hpp:285
int numericFactorization_impl()
PardisoMKL specific numeric factorization.
Definition Amesos2_PardisoMKL_def.hpp:174
bool matrixShapeOK_impl() const
Determines whether the shape of the matrix is OK for this solver.
Definition Amesos2_PardisoMKL_def.hpp:380
bool loadA_impl(EPhase current_phase)
Reads matrix data into internal structures.
Definition Amesos2_PardisoMKL_def.hpp:703
void set_pardiso_mkl_matrix_type(int_t mtype=0)
Definition Amesos2_PardisoMKL_def.hpp:835
int solve_impl(const Teuchos::Ptr< MultiVecAdapter< Vector > > X, const Teuchos::Ptr< const MultiVecAdapter< Vector > > B) const
PardisoMKL specific solve.
Definition Amesos2_PardisoMKL_def.hpp:223
int preOrdering_impl()
Performs pre-ordering on the matrix to increase efficiency.
Definition Amesos2_PardisoMKL_def.hpp:106
void check_pardiso_mkl_error(EPhase phase, int_t error) const
Throws an appropriate runtime error in the event that error < 0 .
Definition Amesos2_PardisoMKL_def.hpp:782
void * pt_[64]
PardisoMKL internal data address pointer.
Definition Amesos2_PardisoMKL_decl.hpp:263
int symbolicFactorization_impl()
Perform symbolic factorization of the matrix using PardisoMKL.
Definition Amesos2_PardisoMKL_def.hpp:117
Amesos2::SolverCore: A templated interface for interaction with third-party direct sparse solvers.
Definition Amesos2_SolverCore_decl.hpp:72
EPhase
Used to indicate a phase in the direct solution.
Definition Amesos2_TypeDecl.hpp:31
A templated MultiVector class adapter for Amesos2.
Definition Amesos2_MultiVecAdapter_decl.hpp:142
Similar to get_ccs_helper , but used to get a CRS representation of the given matrix.
Definition Amesos2_Util.hpp:600