Amesos2 - Direct Sparse Solver Interfaces Version of the Day
Amesos2_ShyLUBasker_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
20#ifndef AMESOS2_SHYLUBASKER_DEF_HPP
21#define AMESOS2_SHYLUBASKER_DEF_HPP
22
23#include <Teuchos_Tuple.hpp>
24#include <Teuchos_ParameterList.hpp>
25#include <Teuchos_StandardParameterEntryValidators.hpp>
26
29
30namespace Amesos2 {
31
32
33template <class Matrix, class Vector>
34ShyLUBasker<Matrix,Vector>::ShyLUBasker(
35 Teuchos::RCP<const Matrix> A,
36 Teuchos::RCP<Vector> X,
37 Teuchos::RCP<const Vector> B )
38 : SolverCore<Amesos2::ShyLUBasker,Matrix,Vector>(A, X, B)
39 , schur_out_ptr(nullptr)
40 , is_contiguous_(true)
41 , use_gather_(true)
42{
43
44 //Nothing
45
46 // Override some default options
47 // TODO: use data_ here to init
48#if defined(HAVE_AMESOS2_KOKKOS)
49 /*
50 static_assert(std::is_same<kokkos_exe,Kokkos::OpenMP>::value,
51 "Kokkos node type not supported by experimental ShyLUBasker Amesos2");
52 */
53 ShyLUbasker = new ::BaskerNS::BaskerTrilinosInterface<local_ordinal_type, shylubasker_dtype, Exe_Space>();
54 ShyLUbasker->Options.no_pivot = BASKER_FALSE;
55 ShyLUbasker->Options.static_delayed_pivot = 0;
56 ShyLUbasker->Options.symmetric = BASKER_FALSE;
57 ShyLUbasker->Options.realloc = BASKER_TRUE;
58 ShyLUbasker->Options.verbose = BASKER_FALSE;
59 ShyLUbasker->Options.prune = BASKER_TRUE;
60 ShyLUbasker->Options.btf_matching = 2; // use cardinary matching from Trilinos, globally
61 ShyLUbasker->Options.blk_matching = 0; // NOT use max-weight matching from Basker on each diagonal block
62 ShyLUbasker->Options.matrix_scaling = 0; // use matrix scaling on a big A block
63 ShyLUbasker->Options.min_block_size = 0; // no merging small blocks
64 ShyLUbasker->Options.amd_dom = BASKER_TRUE; // use block-wise AMD
65 ShyLUbasker->Options.use_metis = BASKER_TRUE; // use scotch/metis for ND (TODO: should METIS optional?)
66 ShyLUbasker->Options.use_nodeNDP = BASKER_TRUE; // use nodeNDP to compute ND partition
67 ShyLUbasker->Options.run_nd_on_leaves = BASKER_TRUE; // run ND on the final leaf-nodes
68 ShyLUbasker->Options.run_amd_on_leaves = BASKER_FALSE; // run AMD on the final leaf-nodes
69 ShyLUbasker->Options.transpose = BASKER_FALSE;
70 ShyLUbasker->Options.threaded_solve = BASKER_FALSE;
71 ShyLUbasker->Options.replace_zero_pivot = BASKER_TRUE;
72 ShyLUbasker->Options.replace_tiny_pivot = BASKER_FALSE;
73 ShyLUbasker->Options.verbose_matrix_out = BASKER_FALSE;
74
75 ShyLUbasker->Options.user_fill = (double)BASKER_FILL_USER;
76 ShyLUbasker->Options.use_sequential_diag_facto = BASKER_FALSE;
77#ifdef KOKKOS_ENABLE_OPENMP // TODO: check for KOKKOS_ENABLE_THREADS when ready
78 num_threads = Kokkos::OpenMP::impl_max_hardware_threads();
79#else
80 num_threads = 1;
81#endif
82 ShyLUbasker->Options.worker_threads = false;
83 // partial factorization
84 ShyLUbasker->Options.partial_facto = 0;
85 ShyLUbasker->Options.only_forward_solve = false;
86 ShyLUbasker->Options.only_backward_solve = false;
87
88#else
89 TEUCHOS_TEST_FOR_EXCEPTION(1 != 0,
90 std::runtime_error,
91 "Amesos2_ShyLUBasker Exception: Do not have Kokkos enabled for ShyLUBasker");
92#endif
93}
94
95
96template <class Matrix, class Vector>
97ShyLUBasker<Matrix,Vector>::~ShyLUBasker( )
98{
99 /* ShyLUBasker will cleanup its own internal memory*/
100#if defined(HAVE_AMESOS2_KOKKOS)
101 ShyLUbasker->Finalize();
102 delete ShyLUbasker;
103#endif
104}
105
106template <class Matrix, class Vector>
107bool
109 return (this->root_ && (this->matrixA_->getComm()->getSize() == 1) && is_contiguous_);
110}
111
112template<class Matrix, class Vector>
113int
115{
116 /* TODO: Define what it means for ShyLUBasker
117 */
118#ifdef HAVE_AMESOS2_TIMERS
119 Teuchos::TimeMonitor preOrderTimer(this->timers_.preOrderTime_);
120#endif
121
122 return(0);
123}
124
125
126template <class Matrix, class Vector>
127int
129{
130
131 int info = 0;
132 if(this->root_)
133 {
134 int nthreads = num_threads;
135 if (ShyLUbasker->Options.partial_facto != 0) {
136 // User needs to provide 2x threads, to avoid dead-lock due to busy-wait
137 TEUCHOS_TEST_FOR_EXCEPTION
138 (nthreads < 2, std::runtime_error,
139 "ShyLU-Basker dense Schur option requires # of threads (2x # of leaves) to be greater than 1 (" << nthreads << ")");
140 }
141 if (ShyLUbasker->Options.worker_threads) {
142 if (nthreads > 1) {
143 // keep one worker-thread / subdomain (where originally subdomain = num_threads)
144 if (ShyLUbasker->Options.verbose && this->root_) {
145 std::cout << "Amesos2::ShyLUBasker:: reduce num threads from " << nthreads << " to " << nthreads/2
146 << " for worker threads" << std::endl;
147 }
148 nthreads /= 2;
149 } else {
150 // turn off worker threads if one thread
151 ShyLUbasker->Options.worker_threads = false;
152 }
153 }
154 ShyLUbasker->SetThreads(nthreads);
155
156
157 // NDE: Special case
158 // Rather than going through the Amesos2 machinery to convert the matrixA_ CRS pointer data to CCS and store in Teuchos::Arrays,
159 // in this special case we pass the CRS raw pointers directly to ShyLUBasker which copies+transposes+sorts the data for CCS format
160 // loadA_impl is essentially an empty function in this case, as the raw pointers are handled here and similarly in Symbolic
161
162 if ( single_proc_optimization() ) {
163
164 host_ordinal_type_array sp_rowptr;
165 host_ordinal_type_array sp_colind;
166 // this needs to be checked during loadA_impl...
167 this->matrixA_->returnRowPtr_kokkos_view(sp_rowptr);
168 TEUCHOS_TEST_FOR_EXCEPTION(sp_rowptr.data() == nullptr,
169 std::runtime_error, "Amesos2 Runtime Error: sp_rowptr returned null ");
170 this->matrixA_->returnColInd_kokkos_view(sp_colind);
171 TEUCHOS_TEST_FOR_EXCEPTION(sp_colind.data() == nullptr,
172 std::runtime_error, "Amesos2 Runtime Error: sp_colind returned null ");
173
174 host_value_type_array hsp_values;
175 this->matrixA_->returnValues_kokkos_view(hsp_values);
176 shylubasker_dtype * sp_values = function_map::convert_scalar(hsp_values.data());
177 //shylubasker_dtype * sp_values = function_map::convert_scalar(nzvals_view_.data());
178 TEUCHOS_TEST_FOR_EXCEPTION(sp_values == nullptr,
179 std::runtime_error, "Amesos2 Runtime Error: sp_values returned null ");
180
181 // In this case, colptr_, rowind_, nzvals_ are invalid
182 if (ShyLUbasker->Options.partial_facto != 0) {
183 shylubasker_dtype * sp_schur_out = function_map::convert_scalar(schur_out.data());
184 info = ShyLUbasker->Symbolic(this->globalNumRows_,
185 this->globalNumCols_,
186 this->globalNumNonZeros_,
187 sp_rowptr.data(),
188 sp_colind.data(),
189 sp_values,
190 schur_part.data(),
191 sp_schur_out,
192 true); // true = _crs_transpose_needed
193 } else {
194 info = ShyLUbasker->Symbolic(this->globalNumRows_,
195 this->globalNumCols_,
196 this->globalNumNonZeros_,
197 sp_rowptr.data(),
198 sp_colind.data(),
199 sp_values,
200 true); // true = _crs_transpose_needed
201 }
202 TEUCHOS_TEST_FOR_EXCEPTION(info != 0,
203 std::runtime_error, "Error in ShyLUBasker Symbolic");
204 }
205 else
206 { //follow original code path if conditions not met
207 // In this case, loadA_impl updates colptr_, rowind_, nzvals_
208 shylubasker_dtype * sp_values = function_map::convert_scalar(nzvals_view_.data());
209 if (ShyLUbasker->Options.partial_facto != 0) {
210 shylubasker_dtype * sp_schur_out = function_map::convert_scalar(schur_out.data());
211 info = ShyLUbasker->Symbolic(this->globalNumRows_,
212 this->globalNumCols_,
213 this->globalNumNonZeros_,
214 colptr_view_.data(),
215 rowind_view_.data(),
216 sp_values,
217 schur_part.data(),
218 sp_schur_out);
219 } else {
220 info = ShyLUbasker->Symbolic(this->globalNumRows_,
221 this->globalNumCols_,
222 this->globalNumNonZeros_,
223 colptr_view_.data(),
224 rowind_view_.data(),
225 sp_values);
226 }
227 TEUCHOS_TEST_FOR_EXCEPTION(info != 0,
228 std::runtime_error, "Error in ShyLUBasker Symbolic");
229 }
230 } // end if (this->root_)
231 /*No symbolic factoriztion*/
232
233 /* All processes should have the same error code */
234 Teuchos::broadcast(*(this->matrixA_->getComm()), 0, &info);
235 return(info);
236}
237
238
239template <class Matrix, class Vector>
240int
242{
243 using Teuchos::as;
244
245 int info = 0;
246 if ( this->root_ ){
247 { // Do factorization
248#ifdef HAVE_AMESOS2_TIMERS
249 Teuchos::TimeMonitor numFactTimer(this->timers_.numFactTime_);
250#endif
251
252 // NDE: Special case
253 // Rather than going through the Amesos2 machinery to convert the matrixA_ CRS pointer data to CCS and store in Teuchos::Arrays,
254 // in this special case we pass the CRS raw pointers directly to ShyLUBasker which copies+transposes+sorts the data for CCS format
255 // loadA_impl is essentially an empty function in this case, as the raw pointers are handled here and similarly in Symbolic
256
257 if ( single_proc_optimization() ) {
258
259 host_ordinal_type_array sp_rowptr;
260 host_ordinal_type_array sp_colind;
261 this->matrixA_->returnRowPtr_kokkos_view(sp_rowptr);
262 TEUCHOS_TEST_FOR_EXCEPTION(sp_rowptr.data() == nullptr,
263 std::runtime_error, "Amesos2 Runtime Error: sp_rowptr returned null ");
264 this->matrixA_->returnColInd_kokkos_view(sp_colind);
265 TEUCHOS_TEST_FOR_EXCEPTION(sp_colind.data() == nullptr,
266 std::runtime_error, "Amesos2 Runtime Error: sp_colind returned null ");
267
268 host_value_type_array hsp_values;
269 this->matrixA_->returnValues_kokkos_view(hsp_values);
270 shylubasker_dtype * sp_values = function_map::convert_scalar(hsp_values.data());
271 //shylubasker_dtype * sp_values = function_map::convert_scalar(nzvals_view_.data());
272
273 TEUCHOS_TEST_FOR_EXCEPTION(sp_values == nullptr,
274 std::runtime_error, "Amesos2 Runtime Error: sp_values returned null ");
275
276 // In this case, colptr_, rowind_, nzvals_ are invalid
277 info = ShyLUbasker->Factor( this->globalNumRows_,
278 this->globalNumCols_,
279 this->globalNumNonZeros_,
280 sp_rowptr.data(),
281 sp_colind.data(),
282 sp_values);
283 }
284 else
285 {
286 // In this case, loadA_impl updates colptr_, rowind_, nzvals_
287 shylubasker_dtype * sp_values = function_map::convert_scalar(nzvals_view_.data());
288 info = ShyLUbasker->Factor(this->globalNumRows_,
289 this->globalNumCols_,
290 this->globalNumNonZeros_,
291 colptr_view_.data(),
292 rowind_view_.data(),
293 sp_values);
294 }
295 if (ShyLUbasker->Options.partial_facto != 0) {
296 if (schur_out_ptr != nullptr) {
297 // copy schur out if the output pointer is valid (assuming enough space has been allocated)
298 // Schur complement is stored in column-major
299 for (size_t j = 0; j < schur_size; j++) {
300 for (size_t i = 0; i < schur_size; i++) {
301 schur_out_ptr[i+j*schur_size] = schur_out[i+j*schur_size];
302 }
303 }
304 }
305 }
306
307 //ShyLUbasker->DEBUG_PRINT();
308
309 local_ordinal_type blnnz = local_ordinal_type(0);
310 local_ordinal_type bunnz = local_ordinal_type(0);
311 ShyLUbasker->GetLnnz(blnnz); // Add exception handling?
312 ShyLUbasker->GetUnnz(bunnz);
313
314 // This is set after numeric factorization complete as pivoting can be used;
315 // In this case, a discrepancy between symbolic and numeric nnz total can occur.
316 this->setNnzLU( as<size_t>( blnnz + bunnz ) );
317
318 } // end scope for timer
319 } // end if (this->root_)
320
321 /* All processes should have the same error code */
322 Teuchos::broadcast(*(this->matrixA_->getComm()), 0, &info);
323
324 //global_size_type info_st = as<global_size_type>(info);
325 TEUCHOS_TEST_FOR_EXCEPTION(info != 0,
326 std::runtime_error, " ShyLUBasker::numericFactorization failed.");
327
328 return(info);
329}
330
331
332template <class Matrix, class Vector>
333int
335 const Teuchos::Ptr<MultiVecAdapter<Vector> > X,
336 const Teuchos::Ptr<const MultiVecAdapter<Vector> > B) const
337{
338 int ierr = 0; // returned error code
339
340 using Teuchos::as;
341
342 const global_size_type ld_rhs = this->root_ ? X->getGlobalLength() : 0;
343 const size_t nrhs = X->getGlobalNumVectors();
344
345 const bool ShyluBaskerTransposeRequest = this->control_.useTranspose_;
346 const bool initialize_data = true;
347 const bool do_not_initialize_data = false;
348 bool use_gather = use_gather_; // user param
349 use_gather = (use_gather && this->matrixA_->getComm()->getSize() > 1); // only with multiple MPIs
350 use_gather = (use_gather && (std::is_same<vector_scalar_type, float>::value ||
351 std::is_same<vector_scalar_type, double>::value)); // only for double or float vectors
352 {
353#ifdef HAVE_AMESOS2_TIMERS
354 Teuchos::TimeMonitor mvConvTimer(this->timers_.vecConvTime_);
355#endif
356 if ( single_proc_optimization() && nrhs == 1 ) {
357
358 // no msp creation
359 Util::get_1d_copy_helper_kokkos_view<MultiVecAdapter<Vector>,
360 host_solve_array_t>::do_get(initialize_data, B, bValues_, as<size_t>(ld_rhs));
361
362 Util::get_1d_copy_helper_kokkos_view<MultiVecAdapter<Vector>,
363 host_solve_array_t>::do_get(do_not_initialize_data, X, xValues_, as<size_t>(ld_rhs));
364
365 } // end if ( single_proc_optimization() && nrhs == 1 )
366 else {
367 if (use_gather) {
368 int rval = B->gather(bValues_, this->perm_g2l, this->recvCountRows, this->recvDisplRows,
369 (is_contiguous_ == true) ? ROOTED : CONTIGUOUS_AND_ROOTED);
370 if (rval == 0) {
371 X->gather(xValues_, this->perm_g2l, this->recvCountRows, this->recvDisplRows,
372 (is_contiguous_ == true) ? ROOTED : CONTIGUOUS_AND_ROOTED);
373 } else {
374 use_gather = false;
375 }
376 }
377 if (!use_gather) {
378 Util::get_1d_copy_helper_kokkos_view<MultiVecAdapter<Vector>,
379 host_solve_array_t>::do_get(initialize_data, B, bValues_,
380 as<size_t>(ld_rhs),
381 (is_contiguous_ == true) ? ROOTED : CONTIGUOUS_AND_ROOTED,
382 this->rowIndexBase_);
383
384 // See Amesos2_Tacho_def.hpp for notes on why we 'get' x here.
385 Util::get_1d_copy_helper_kokkos_view<MultiVecAdapter<Vector>,
386 host_solve_array_t>::do_get(do_not_initialize_data, X, xValues_,
387 as<size_t>(ld_rhs),
388 (is_contiguous_ == true) ? ROOTED : CONTIGUOUS_AND_ROOTED,
389 this->rowIndexBase_);
390 }
391 }
392 }
393
394 if ( this->root_ ) { // do solve
395#ifdef HAVE_AMESOS2_TIMERS
396 Teuchos::TimeMonitor solveTimer(this->timers_.solveTime_);
397#endif
398
399 shylubasker_dtype * pxValues = function_map::convert_scalar(xValues_.data());
400 shylubasker_dtype * pbValues = function_map::convert_scalar(bValues_.data());
401 if (!ShyluBaskerTransposeRequest)
402 ierr = ShyLUbasker->Solve(nrhs, pbValues, pxValues);
403 else
404 ierr = ShyLUbasker->Solve(nrhs, pbValues, pxValues, true);
405 }
406 /* All processes should have the same error code */
407 Teuchos::broadcast(*(this->getComm()), 0, &ierr);
408
409 TEUCHOS_TEST_FOR_EXCEPTION( ierr > 0,
410 std::runtime_error,
411 "Encountered zero diag element at: " << ierr);
412 TEUCHOS_TEST_FOR_EXCEPTION( ierr == -1,
413 std::runtime_error,
414 "Could not alloc needed working memory for solve" );
415 {
416#ifdef HAVE_AMESOS2_TIMERS
417 Teuchos::TimeMonitor redistTimer(this->timers_.vecRedistTime_);
418#endif
419 if (use_gather) {
420 int rval = X->scatter(xValues_, this->perm_g2l, this->recvCountRows, this->recvDisplRows,
421 (is_contiguous_ == true) ? ROOTED : CONTIGUOUS_AND_ROOTED);
422 if (rval != 0) use_gather = false;
423 }
424 if (!use_gather) {
425 Util::put_1d_data_helper_kokkos_view<
426 MultiVecAdapter<Vector>,host_solve_array_t>::do_put(X, xValues_,
427 as<size_t>(ld_rhs),
428 (is_contiguous_ == true) ? ROOTED : CONTIGUOUS_AND_ROOTED);
429 }
430 }
431 return(ierr);
432}
433
434
435template <class Matrix, class Vector>
436bool
438{
439 // The ShyLUBasker can only handle square for right now
440 return( this->globalNumRows_ == this->globalNumCols_ );
441}
442
443
444template <class Matrix, class Vector>
445void
446ShyLUBasker<Matrix,Vector>::setParameters_impl(const Teuchos::RCP<Teuchos::ParameterList> & parameterList )
447{
448 using Teuchos::RCP;
449 using Teuchos::getIntegralValue;
450 using Teuchos::ParameterEntryValidator;
451
452 RCP<const Teuchos::ParameterList> valid_params = getValidParameters_impl();
453
454 if(parameterList->isParameter("IsContiguous"))
455 {
456 is_contiguous_ = parameterList->get<bool>("IsContiguous");
457 }
458
459 if(parameterList->isParameter("UseCustomGather"))
460 {
461 use_gather_ = parameterList->get<bool>("UseCustomGather");
462 }
463
464 if(parameterList->isParameter("num_threads"))
465 {
466 num_threads = parameterList->get<int>("num_threads");
467 }
468 if(parameterList->isParameter("worker_threads"))
469 {
470 ShyLUbasker->Options.worker_threads = parameterList->get<bool>("worker_threads");
471 }
472 if(parameterList->isParameter("pivot"))
473 {
474 ShyLUbasker->Options.no_pivot = (!parameterList->get<bool>("pivot"));
475 }
476 if(parameterList->isParameter("delayed pivot"))
477 {
478 ShyLUbasker->Options.static_delayed_pivot = (parameterList->get<int>("delayed pivot"));
479 }
480 if(parameterList->isParameter("pivot_tol"))
481 {
482 ShyLUbasker->Options.pivot_tol = parameterList->get<double>("pivot_tol");
483 }
484 if(parameterList->isParameter("symmetric"))
485 {
486 ShyLUbasker->Options.symmetric = parameterList->get<bool>("symmetric");
487 }
488 if(parameterList->isParameter("realloc"))
489 {
490 ShyLUbasker->Options.realloc = parameterList->get<bool>("realloc");
491 }
492 if(parameterList->isParameter("verbose"))
493 {
494 ShyLUbasker->Options.verbose = parameterList->get<bool>("verbose");
495 }
496 if(parameterList->isParameter("verbose_matrix"))
497 {
498 ShyLUbasker->Options.verbose_matrix_out = parameterList->get<bool>("verbose_matrix");
499 }
500 if(parameterList->isParameter("btf"))
501 {
502 ShyLUbasker->Options.btf = parameterList->get<bool>("btf");
503 }
504 if(parameterList->isParameter("use_metis"))
505 {
506 ShyLUbasker->Options.use_metis = parameterList->get<bool>("use_metis");
507 }
508 if(parameterList->isParameter("use_nodeNDP"))
509 {
510 ShyLUbasker->Options.use_nodeNDP = parameterList->get<bool>("use_nodeNDP");
511 }
512 if(parameterList->isParameter("run_nd_on_leaves"))
513 {
514 ShyLUbasker->Options.run_nd_on_leaves = parameterList->get<bool>("run_nd_on_leaves");
515 }
516 if(parameterList->isParameter("run_amd_on_leaves"))
517 {
518 ShyLUbasker->Options.run_amd_on_leaves = parameterList->get<bool>("run_amd_on_leaves");
519 }
520 if(parameterList->isParameter("amd_on_blocks"))
521 {
522 ShyLUbasker->Options.amd_dom = parameterList->get<bool>("amd_on_blocks");
523 }
524 if(parameterList->isParameter("transpose"))
525 {
526 // NDE: set transpose vs non-transpose mode as bool; track separate shylubasker objects
527 const auto transpose = parameterList->get<bool>("transpose");
528 if (transpose == true)
529 this->control_.useTranspose_ = true;
530 }
531 if(parameterList->isParameter("threaded_solve"))
532 {
533 ShyLUbasker->Options.threaded_solve = parameterList->get<bool>("threaded_solve");
534 }
535 if(parameterList->isParameter("use_sequential_diag_facto"))
536 {
537 ShyLUbasker->Options.use_sequential_diag_facto = parameterList->get<bool>("use_sequential_diag_facto");
538 }
539 if(parameterList->isParameter("user_fill"))
540 {
541 ShyLUbasker->Options.user_fill = parameterList->get<double>("user_fill");
542 }
543 if(parameterList->isParameter("prune"))
544 {
545 ShyLUbasker->Options.prune = parameterList->get<bool>("prune");
546 }
547 if(parameterList->isParameter("replace_zero_pivot"))
548 {
549 ShyLUbasker->Options.replace_zero_pivot = parameterList->get<bool>("replace_zero_pivot");
550 }
551 if(parameterList->isParameter("replace_tiny_pivot"))
552 {
553 ShyLUbasker->Options.replace_tiny_pivot = parameterList->get<bool>("replace_tiny_pivot");
554 }
555 if(parameterList->isParameter("btf_matching"))
556 {
557 ShyLUbasker->Options.btf_matching = parameterList->get<int>("btf_matching");
558 if (ShyLUbasker->Options.btf_matching == 1 || ShyLUbasker->Options.btf_matching == 2) {
559 ShyLUbasker->Options.matching = true;
560 } else {
561 ShyLUbasker->Options.matching = false;
562 }
563 }
564 if(parameterList->isParameter("blk_matching"))
565 {
566 ShyLUbasker->Options.blk_matching = parameterList->get<int>("blk_matching");
567 }
568 if(parameterList->isParameter("matrix_scaling"))
569 {
570 ShyLUbasker->Options.matrix_scaling = parameterList->get<int>("matrix_scaling");
571 }
572 if(parameterList->isParameter("min_block_size"))
573 {
574 ShyLUbasker->Options.min_block_size = parameterList->get<int>("min_block_size");
575 }
576
577 if(parameterList->isParameter("PartialFacto"))
578 {
579 ShyLUbasker->Options.partial_facto = parameterList->get<int>("PartialFacto");
580 }
581 if(parameterList->isParameter("SchurPart"))
582 {
583 // copy schur-part to the internal view (in case the user-pointer go out of scope?)
584 auto schur_part_ptr = parameterList->get<const local_ordinal_type*>("SchurPart");
585 Kokkos::resize(schur_part, this->globalNumCols_);
586 schur_size = 0;
587 for (global_size_type i=0; i<this->globalNumCols_; i++) {
588 schur_part(i) = schur_part_ptr[i];
589 if (schur_part(i) == 1) schur_size ++;
590 }
591 // allocate internal storage to store the schur complement (user may not want it and may not provide a valid pointer?)
592 Kokkos::resize(schur_out, schur_size*schur_size);
593 }
594 if(parameterList->isParameter("SchurOut"))
595 {
596 // store schur-part to the internal view (if user wants the output, then the pointer should stay, so no need for internal view?)
597 schur_out_ptr = parameterList->get<scalar_type*>("SchurOut");
598 }
599 if(parameterList->isParameter("OnlyForwardSolve"))
600 {
601 ShyLUbasker->Options.only_forward_solve = parameterList->get<bool>("OnlyForwardSolve");
602 }
603 if(parameterList->isParameter("OnlyBackwardSolve"))
604 {
605 ShyLUbasker->Options.only_backward_solve = parameterList->get<bool>("OnlyBackwardSolve");
606 }
607}
608
609template <class Matrix, class Vector>
610Teuchos::RCP<const Teuchos::ParameterList>
612{
613 using Teuchos::ParameterList;
614
615 static Teuchos::RCP<const Teuchos::ParameterList> valid_params;
616
617 if( is_null(valid_params) )
618 {
619 Teuchos::RCP<Teuchos::ParameterList> pl = Teuchos::parameterList();
620 pl->set("IsContiguous", true,
621 "Are GIDs contiguous");
622 pl->set("UseCustomGather", true,
623 "Use Matrix-gather routine");
624 pl->set("num_threads", 1,
625 "Number of threads");
626 pl->set("pivot", false,
627 "Should not pivot");
628 pl->set("delayed pivot", 0,
629 "Apply static delayed pivot on a big block");
630 pl->set("pivot_tol", .0001,
631 "Tolerance before pivot, currently not used");
632 pl->set("symmetric", false,
633 "Should Symbolic assume symmetric nonzero pattern");
634 pl->set("realloc" , false,
635 "Should realloc space if not enough");
636 pl->set("verbose", false,
637 "Information about factoring");
638 pl->set("verbose_matrix", false,
639 "Give Permuted Matrices");
640 pl->set("btf", true,
641 "Use BTF ordering");
642 pl->set("prune", false,
643 "Use prune on BTF blocks (Not Supported)");
644 pl->set("btf_matching", 2,
645 "Matching option for BTF: 0 = none, 1 = Basker, 2 = Trilinos (default), (3 = MC64 if enabled)");
646 pl->set("blk_matching", 0,
647 "Matching optioon for block: 0 = none, 1 or anything else = Basker (default), (2 = MC64 if enabled)");
648 pl->set("matrix_scaling", 0,
649 "Use matrix scaling to biig A BTF block: 0 = no-scaling, 1 = symmetric diagonal scaling, 2 = row-max, and then col-max scaling");
650 pl->set("min_block_size", 0,
651 "Size of the minimum diagonal blocks");
652 pl->set("replace_zero_pivot", true,
653 "Replace zero pivots during the numerical factorization");
654 pl->set("replace_tiny_pivot", false,
655 "Replace tiny pivots during the numerical factorization");
656 pl->set("use_metis", true,
657 "Use METIS for ND");
658 pl->set("use_nodeNDP", true,
659 "Use nodeND to compute ND partition");
660 pl->set("run_nd_on_leaves", false,
661 "Run ND on the final leaf-nodes for ND factorization");
662 pl->set("run_amd_on_leaves", false,
663 "Run AMD on the final leaf-nodes for ND factorization");
664 pl->set("amd_on_blocks", true,
665 "Run AMD on each diagonal blocks");
666 pl->set("transpose", false,
667 "Solve the transpose A");
668 pl->set("threaded_solve", false,
669 "Use threads for forward/backward solves");
670 pl->set("worker_threads", false,
671 "Use worker thread for ND factorization");
672 pl->set("use_sequential_diag_facto", false,
673 "Use sequential algorithm to factor each diagonal block");
674 pl->set("user_fill", (double)BASKER_FILL_USER,
675 "User-provided padding for the fill ratio");
676
677 // TODO: should these be const or not
678 scalar_type *dummy_scalar_ptr;
679 const local_ordinal_type *dummy_ordinal_ptr;
680 pl->set("PartialFacto", 0,
681 "Perform partial factorization to extract dense Schur complement (0: no, 1: form + factor Schur, 2: ony form");
682 pl->set("SchurPart", dummy_ordinal_ptr,
683 "Specify rows/columns belonging to Schur complement for partial factorization");
684 pl->set("SchurOut", dummy_scalar_ptr,
685 "Store output Schur complement from partial factorization");
686 pl->set("OnlyForwardSolve", false,
687 "Perform only the forward substitution");
688 pl->set("OnlyBackwardSolve", false,
689 "Perform only the backward substitution");
690 valid_params = pl;
691 }
692 return valid_params;
693}
694
695
696template <class Matrix, class Vector>
697bool
699{
700 using Teuchos::as;
701 if(current_phase == SOLVE || current_phase == PREORDERING ) return( false );
702
703 #ifdef HAVE_AMESOS2_TIMERS
704 Teuchos::TimeMonitor convTimer(this->timers_.mtxConvTime_);
705 #endif
706
707
708 // NDE: Can clean up duplicated code with the #ifdef guards
709 if ( single_proc_optimization() ) {
710 // NDE: Nothing is done in this special case - CRS raw pointers are passed to SHYLUBASKER and transpose of copies handled there
711 // In this case, colptr_, rowind_, nzvals_ are invalid
712 }
713 else
714 {
715 // Only the root image needs storage allocated
716 if( this->root_ && current_phase == SYMBFACT )
717 {
718 Kokkos::resize(nzvals_view_, this->globalNumNonZeros_);
719 Kokkos::resize(rowind_view_, this->globalNumNonZeros_);
720 Kokkos::resize(colptr_view_, this->globalNumCols_ + 1); //this will be wrong for case of gapped col ids, e.g. 0,2,4,9; num_cols = 10 ([0,10)) but num GIDs = 4...
721 }
722
723 local_ordinal_type nnz_ret = -1;
724 bool use_gather = use_gather_; // user param
725 use_gather = (use_gather && this->matrixA_->getComm()->getSize() > 1); // only with multiple MPIs
726 use_gather = (use_gather && (std::is_same<scalar_type, float>::value || std::is_same<scalar_type, double>::value)); // only for double or float
727 {
728 #ifdef HAVE_AMESOS2_TIMERS
729 Teuchos::TimeMonitor mtxRedistTimer( this->timers_.mtxRedistTime_ );
730 #endif
731 if (use_gather) {
732 bool column_major = true;
733 if (!is_contiguous_) {
734 auto contig_mat = this->matrixA_->reindex(this->contig_rowmap_, this->contig_colmap_, current_phase);
735 nnz_ret = contig_mat->gather(nzvals_view_, rowind_view_, colptr_view_, this->perm_g2l, this->recvCountRows, this->recvDisplRows, this->recvCounts, this->recvDispls,
736 this->transpose_map, this->nzvals_t, column_major, current_phase);
737 } else {
738 nnz_ret = this->matrixA_->gather(nzvals_view_, rowind_view_, colptr_view_, this->perm_g2l, this->recvCountRows, this->recvDisplRows, this->recvCounts, this->recvDispls,
739 this->transpose_map, this->nzvals_t, column_major, current_phase);
740 }
741 // gather failed (e.g., not implemened for KokkosCrsMatrix)
742 // in case of the failure, it falls back to the original "do_get"
743 if (nnz_ret < 0) use_gather = false;
744 }
745 if (!use_gather) {
747 MatrixAdapter<Matrix>, host_value_type_array, host_ordinal_type_array, host_ordinal_type_array>
748 ::do_get(this->matrixA_.ptr(), nzvals_view_, rowind_view_, colptr_view_, nnz_ret,
749 (is_contiguous_ == true) ? ROOTED : CONTIGUOUS_AND_ROOTED,
750 ARBITRARY,
751 this->rowIndexBase_); // copies from matrixA_ to ShyLUBasker ConcreteSolver cp, ri, nzval members
752 }
753 }
754
755 // gather return the total nnz_ret on every MPI process
756 if (use_gather || this->root_) {
757 TEUCHOS_TEST_FOR_EXCEPTION( nnz_ret != as<local_ordinal_type>(this->globalNumNonZeros_),
758 std::runtime_error,
759 "Amesos2_ShyLUBasker loadA_impl: Did not get the expected number of non-zero vals("
760 +std::to_string(nnz_ret)+" vs "+std::to_string(this->globalNumNonZeros_)+")");
761 }
762 } //end alternative path
763 return true;
764}
765
766
767template <class Matrix, class Vector>
768void
770 const Teuchos::EVerbosityLevel verbLevel) const
771{
772 out << " ShyLUBasker current parameters:" << std::endl;
773 out << " > IsContiguous = " << (is_contiguous_ ? "YES" : "NO") << std::endl;
774 out << " > UseCustomGather = " << (use_gather_ ? "YES" : "NO") << std::endl;
775 out << " > num_threads = " << num_threads << std::endl;
776 out << " > worker_threads = " << ShyLUbasker->Options.worker_threads << std::endl;
777 out << " > pivot = " << ShyLUbasker->Options.no_pivot << std::endl;
778 out << " > pivot_tol = " << ShyLUbasker->Options.pivot_tol << std::endl;
779 out << " > realloc = " << ShyLUbasker->Options.realloc << std::endl;
780 out << " > verbose = " << (ShyLUbasker->Options.verbose ? "YES" : "NO") << std::endl;
781 out << " > btf = " << (ShyLUbasker->Options.btf ? "YES" : "NO") << std::endl;
782 out << " > use_metis = " << (ShyLUbasker->Options.use_metis ? "YES" : "NO") << std::endl;
783 out << " > use_nodeNDP = " << (ShyLUbasker->Options.use_nodeNDP ? "YES" : "NO") << std::endl;
784 out << " > run_nd_on_leaves = " << (ShyLUbasker->Options.run_nd_on_leaves ? "YES" : "NO") << std::endl;
785 out << " > run_amd_on_leaves = " << (ShyLUbasker->Options.run_amd_on_leaves ? "YES" : "NO") << std::endl;
786 out << " > amd_on_blocks = " << (ShyLUbasker->Options.amd_dom ? "YES" : "NO") << std::endl;
787 out << " > transpose = " << (this->control_.useTranspose_ ? "YES" : "NO") << std::endl;
788 out << " > threaded_solve = " << (ShyLUbasker->Options.threaded_solve ? "YES" : "NO") << std::endl;
789 out << " > user_fill = " << ShyLUbasker->Options.user_fill << std::endl;
790 out << " > prune = " << (ShyLUbasker->Options.prune ? "YES" : "NO") << std::endl;
791 out << " > replace_zero_pivot = " << (ShyLUbasker->Options.replace_zero_pivot ? "YES" : "NO") << std::endl;
792 out << " > replace_tiny_pivot = " << (ShyLUbasker->Options.replace_tiny_pivot ? "YES" : "NO") << std::endl;
793 out << " > btf_matching = " << (ShyLUbasker->Options.btf_matching ? "YES" : "NO") << std::endl;
794 out << " > blk_matching = " << (ShyLUbasker->Options.blk_matching ? "YES" : "NO") << std::endl;
795 out << " > use_sequential_diag_facto = " << (ShyLUbasker->Options.use_sequential_diag_facto ? "YES" : "NO") << std::endl;
796 out << " > partial_facto = " << ShyLUbasker->Options.partial_facto << std::endl;
797 out << std::endl;
798}
799
800
801template<class Matrix, class Vector>
802const char* ShyLUBasker<Matrix,Vector>::name = "ShyLUBasker";
803
804
805} // end namespace Amesos2
806
807#endif // AMESOS2_SHYLUBASKER_DEF_HPP
Amesos2 ShyLUBasker declarations.
@ ROOTED
Definition Amesos2_TypeDecl.hpp:93
@ CONTIGUOUS_AND_ROOTED
Definition Amesos2_TypeDecl.hpp:94
@ ARBITRARY
Definition Amesos2_TypeDecl.hpp:109
A Matrix adapter interface for Amesos2.
Definition Amesos2_MatrixAdapter_decl.hpp:42
Amesos2 interface to the Baker package.
Definition Amesos2_ShyLUBasker_decl.hpp:43
EPhase
Used to indicate a phase in the direct solution.
Definition Amesos2_TypeDecl.hpp:31
void transpose(ArrayView< Scalar > vals, ArrayView< GlobalOrdinal > indices, ArrayView< GlobalSizeT > ptr, ArrayView< Scalar > trans_vals, ArrayView< GlobalOrdinal > trans_indices, ArrayView< GlobalSizeT > trans_ptr)
A templated MultiVector class adapter for Amesos2.
Definition Amesos2_MultiVecAdapter_decl.hpp:142
A generic helper class for getting a CCS representation of a Matrix.
Definition Amesos2_Util.hpp:589