1 /******************************************************************************* 2 * Copyright (c) 2018, College of William & Mary 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * * Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * * Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * * Neither the name of the College of William & Mary nor the 13 * names of its contributors may be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 * DISCLAIMED. IN NO EVENT SHALL THE COLLEGE OF WILLIAM & MARY BE LIABLE FOR ANY 20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 * 27 * PRIMME: https://github.com/primme/primme 28 * Contact: Andreas Stathopoulos, a n d r e a s _at_ c s . w m . e d u 29 ******************************************************************************* 30 * File: primme_c.c 31 * 32 * Purpose - Real, SCALAR precision front end to the multimethod eigensolver 33 * 34 * For the moment please cite the following two papers: 35 * 36 * A. Stathopoulos, Nearly optimal preconditioned methods for hermitian 37 * eigenproblems under limited memory. Part I: Seeking one eigenvalue, 38 * Tech Report: WM-CS-2005-03, July, 2005. To appear in SISC. 39 * A. Stathopoulos and J. R. McCombs, Nearly optimal preconditioned methods 40 * for hermitian eigenproblems under limited memory. Part II: Seeking many 41 * eigenvalues, Tech Report: WM-CS-2006-02, June, 2006. 42 * 43 * Additional information on the algorithms appears in: 44 * 45 * J. R. McCombs and A. Stathopoulos, Iterative Validation of Eigensolvers: 46 * A Scheme for Improving the Reliability of Hermitian Eigenvalue Solvers 47 * Tech Report: WM-CS-2005-02, July, 2005, to appear in SISC. 48 * A. Stathopoulos, Locking issues for finding a large number of eigenvectors 49 * of hermitian matrices, Tech Report: WM-CS-2005-03, July, 2005. 50 * 51 * Some papers to be listed here. For the moment contact the author: 52 * 53 * andreas@cs.wm.edu 54 * 55 ******************************************************************************/ 56 57 #ifndef THIS_FILE 58 #define THIS_FILE "../eigs/primme_c.c" 59 #endif 60 61 #include "numerical.h" 62 #include "template_normal.h" 63 #include "common_eigs.h" 64 #include "primme_interface.h" 65 /* Keep automatically generated headers under this section */ 66 #ifndef CHECK_TEMPLATE 67 #include "primme_c.h" 68 #include "main_iter.h" 69 #include "auxiliary_eigs.h" 70 #endif 71 72 /******************************************************************************* 73 * Subroutine Xprimme - This routine is a front end used to perform 74 * error checking on the input parameters, perform validation, 75 * and make the call to main_iter. 76 * 77 * INPUT/OUTPUT ARRAYS AND PARAMETERS 78 * ---------------------------------- 79 * evals Contains the converged Ritz values upon return. Should be of size 80 * primme->numEvals. 81 * 82 * evecs The local portions of the converged Ritz vectors. The dimension of 83 * the array is at least primme->nLocal*primme->numEvals 84 * 85 * resNorms The residual norms of the converged Ritz vectors. Should be of 86 * size primme->numEvals 87 * 88 * primme Structure containing various solver parameters and statistics 89 * See readme.txt for INPUT/OUTPUT variables in primme 90 * 91 * Return Value 92 * ------------ 93 * 0 - Success 94 * 1 - Reporting only memory space required 95 * -1 - Failure to allocate workspace 96 * -2 - Malloc failure in allocating a permutation integer array 97 * -3 - main_iter encountered a problem 98 * -4 ...-32 - Invalid input (parameters or primme struct) returned 99 * by check_input() 100 * 101 ******************************************************************************/ 102 103 int Xprimme(XEVAL *evals, XSCALAR *evecs, XREAL *resNorms, 104 primme_params *primme) { 105 106 return Xprimme_aux_Sprimme((void *)evals, (void *)evecs, (void *)resNorms, primme, 107 PRIMME_OP_SCALAR); 108 } 109 110 // Definition for *hsprimme, *ksprimme, and *kcprimme 111 112 #if defined(USE_HALF) || defined(USE_HALFCOMPLEX) || \ 113 defined(USE_HALF_MAGMA) || defined(USE_HALFCOMPLEX_MAGMA) 114 115 # ifdef USE_HERMITIAN 116 // Expand the terms {,magma_}{hs,ks}primme 117 # define Xsprimme CONCAT(CONCAT(STEM,USE_ARITH(hs,ks)),primme) 118 # else 119 // Expand the terms {,magma_}kcprimme_normal 120 # define Xsprimme WITH_KIND(CONCAT(CONCAT(STEM,kc),primme)) 121 # endif 122 123 int Xsprimme(KIND(float, PRIMME_COMPLEX_FLOAT) * evals, XSCALAR *evecs, 124 float *resNorms, primme_params *primme) { 125 126 return Xprimme_aux_Sprimme((void *)evals, (void *)evecs, (void *)resNorms, primme, 127 primme_op_float); 128 } 129 130 # undef Xsprimme 131 #endif inner_solve_Sprimme(int blockSize,SCALAR * x,PRIMME_INT ldx,SCALAR * Bx,PRIMME_INT ldBx,SCALAR * r,PRIMME_INT ldr,HREAL * rnorm,SCALAR * evecs,PRIMME_INT ldevecs,HSCALAR * Mfact,int * ipivot,HSCALAR * xKinvBx,SCALAR * LprojectorQ,PRIMME_INT ldLprojectorQ,SCALAR * LprojectorX,PRIMME_INT ldLprojectorX,SCALAR * LprojectorBQ,PRIMME_INT ldLprojectorBQ,SCALAR * LprojectorBX,PRIMME_INT ldLprojectorBX,SCALAR * RprojectorQ,PRIMME_INT ldRprojectorQ,SCALAR * RprojectorX,PRIMME_INT ldRprojectorX,int sizeLprojectorQ,int sizeLprojectorX,int sizeRprojectorQ,int sizeRprojectorX,SCALAR * sol,PRIMME_INT ldsol,HEVAL * eval,KIND (double,PRIMME_COMPLEX_DOUBLE)* shift,int * touch,double startTime,primme_context ctx)132 133 /******************************************************************************* 134 * Subroutine Xprimme_aux - set defaults depending on the callee's type, and 135 * call wrapper_Sprimme with type set in internalPrecision. 136 * 137 * INPUT/OUTPUT ARRAYS AND PARAMETERS 138 * ---------------------------------- 139 * evals Contains the converged Ritz values upon return. Should be of size 140 * primme->numEvals. 141 * 142 * evecs The local portions of the converged Ritz vectors. The dimension of 143 * the array is at least primme->nLocal*primme->numEvals 144 * 145 * resNorms The residual norms of the converged Ritz vectors. Should be of 146 * size primme->numEvals 147 * 148 * primme the PRIMME parameters 149 * 150 * evals_resNorms_type The type of the arrays evals and resNorsm. 151 * 152 * Return Value 153 * ------------ 154 * return error code 155 ******************************************************************************/ 156 157 TEMPLATE_PLEASE 158 int Xprimme_aux_Sprimme(void *evals, void *evecs, void *resNorms, 159 primme_params *primme, primme_op_datatype evals_resNorms_type) { 160 161 #ifdef SUPPORTED_TYPE 162 163 /* Generate context */ 164 165 primme_context ctx = primme_get_context(primme); 166 167 /* Set the current type as the default type for user's operators */ 168 169 if (primme->matrixMatvec && primme->matrixMatvec_type == primme_op_default) 170 primme->matrixMatvec_type = PRIMME_OP_SCALAR; 171 if (primme->massMatrixMatvec && primme->massMatrixMatvec_type == primme_op_default) 172 primme->massMatrixMatvec_type = PRIMME_OP_SCALAR; 173 if (primme->applyPreconditioner && primme->applyPreconditioner_type == primme_op_default) 174 primme->applyPreconditioner_type = PRIMME_OP_SCALAR; 175 if (primme->globalSumReal && primme->globalSumReal_type == primme_op_default) 176 primme->globalSumReal_type = PRIMME_OP_SCALAR; 177 if (primme->broadcastReal && primme->broadcastReal_type == primme_op_default) 178 primme->broadcastReal_type = PRIMME_OP_SCALAR; 179 if (primme->convTestFun && primme->convTestFun_type == primme_op_default) 180 primme->convTestFun_type = PRIMME_OP_SCALAR; 181 if (primme->monitorFun && primme->monitorFun_type == primme_op_default) 182 primme->monitorFun_type = PRIMME_OP_SCALAR; 183 184 /* Number of returned eigenpairs */ 185 186 int outInitSize = 0; 187 188 /* call primme for the internal working precision */ 189 190 int ret; 191 primme_op_datatype t = primme->internalPrecision; 192 if (t == primme_op_default) t = PRIMME_OP_SCALAR; 193 switch (t) { 194 # ifdef SUPPORTED_HALF_TYPE 195 case primme_op_half: 196 CHKERRVAL(wrapper_Shprimme(evals, evecs, resNorms, evals_resNorms_type, 197 PRIMME_OP_SCALAR, &outInitSize, ctx), 198 &ret); 199 break; 200 # endif 201 # ifndef PRIMME_WITHOUT_FLOAT 202 case primme_op_float: 203 CHKERRVAL(wrapper_Ssprimme(evals, evecs, resNorms, evals_resNorms_type, 204 PRIMME_OP_SCALAR, &outInitSize, ctx), 205 &ret); 206 break; 207 # endif 208 case primme_op_double: 209 CHKERRVAL(wrapper_Sdprimme(evals, evecs, resNorms, evals_resNorms_type, 210 PRIMME_OP_SCALAR, &outInitSize, ctx), 211 &ret); 212 break; 213 # ifdef PRIMME_WITH_NATIVE_QUAD 214 case primme_op_quad: 215 CHKERRVAL(wrapper_Sqprimme(evals, evecs, resNorms, evals_resNorms_type, 216 PRIMME_OP_SCALAR, &outInitSize, ctx), 217 &ret); 218 break; 219 # endif 220 default: ret = PRIMME_FUNCTION_UNAVAILABLE; 221 } 222 223 /* Free context */ 224 225 primme_free_context(ctx); 226 227 /* Set the number of returned eigenpairs */ 228 229 primme->initSize = outInitSize; 230 231 return ret; 232 #else 233 234 (void)evals; 235 (void)evecs; 236 (void)resNorms; 237 (void)evals_resNorms_type; 238 239 primme->initSize = 0; 240 return PRIMME_FUNCTION_UNAVAILABLE; 241 #endif /* SUPPORTED_TYPE */ 242 } 243 244 245 #ifdef SUPPORTED_TYPE 246 247 /******************************************************************************* 248 * Subroutine wrapper_Sprimme - Perform error checking on the input parameters, 249 * and make the call to main_iter. 250 * 251 * INPUT/OUTPUT ARRAYS AND PARAMETERS 252 * ---------------------------------- 253 * evals Contains the converged Ritz values upon return. Should be of size 254 * primme->numEvals. 255 * 256 * evecs The local portions of the converged Ritz vectors. The dimension of 257 * the array is at least primme->nLocal*primme->numEvals 258 * 259 * resNorms The residual norms of the converged Ritz vectors. Should be of 260 * size primme->numEvals 261 * 262 * evals_resNorms_type The type of the arrays evals and resNorsm. 263 * 264 * evecs_type The type of the array evecs 265 * 266 * outInitSize The number of columns returned back. 267 * 268 * ctx primme context 269 * 270 * Return Value 271 * ------------ 272 * return error code 273 ******************************************************************************/ 274 275 276 TEMPLATE_PLEASE 277 int wrapper_Sprimme(void *evals, void *evecs, void *resNorms, 278 primme_op_datatype evals_resNorms_type, primme_op_datatype evecs_type, 279 int *outInitSize, primme_context ctx) { 280 281 primme_params *primme = ctx.primme; 282 283 /* In case of error, return initSize = 0 */ 284 285 *outInitSize = 0; 286 287 /* zero out the timer */ 288 289 double t0 = primme_wTimer(); 290 291 /* Set some defaults for sequential programs */ 292 293 if (primme->numProcs <= 1 && evals != NULL && evecs != NULL && 294 resNorms != NULL) { 295 primme->nLocal = primme->n; 296 primme->procID = 0; 297 } 298 299 /* Set some defaults */ 300 301 primme_set_defaults(primme); 302 303 /* Observed orthogonality issues finding the largest/smallest values in */ 304 /* single precision. Computing V'*B*V and solving the projected problem */ 305 /* V'AVx = V'BVxl mitigates the problem. */ 306 /* Also if maxBlockSize > 1, the code uses the block orthogonalization */ 307 /* instead of Gram-Schmidt. But the current block orthogonalization does */ 308 /* not produce a machine precision orthonormal basis, and we deal with */ 309 /* this by computing V'*B*V also in this case. */ 310 311 312 if (primme->orth == primme_orth_default) { 313 if (PRIMME_OP_SCALAR <= primme_op_float || primme->maxBlockSize > 1) { 314 primme->orth = primme_orth_explicit_I; 315 } else { 316 primme->orth = primme_orth_implicit_I; 317 } 318 } 319 320 /* If we are free to choose the leading dimension of V and W, use */ 321 /* a multiple of PRIMME_BLOCK_SIZE. This may improve the performance */ 322 /* of Num_update_VWXR_Sprimme and Bortho_block_Sprimme. */ 323 324 if (primme->ldOPs == -1) { 325 if (PRIMME_BLOCK_SIZE < INT_MAX) { 326 primme->ldOPs = min(((primme->nLocal + PRIMME_BLOCK_SIZE - 1) 327 /PRIMME_BLOCK_SIZE)*PRIMME_BLOCK_SIZE, primme->nLocal); 328 } else { 329 primme->ldOPs = primme->nLocal; 330 } 331 } 332 333 /* Deprecated input: */ 334 335 if (evals == NULL && evecs == NULL && resNorms == NULL) 336 return 0; 337 338 /* Reset random number seed if inappropriate for DLARENV */ 339 /* Yields unique quadruples per proc if procID < 4096^3 */ 340 341 if (primme->iseed[0]<0 || primme->iseed[0]>4095) primme->iseed[0] = 342 primme->procID % 4096; 343 if (primme->iseed[1]<0 || primme->iseed[1]>4095) primme->iseed[1] = 344 (int)(primme->procID/4096+1) % 4096; 345 if (primme->iseed[2]<0 || primme->iseed[2]>4095) primme->iseed[2] = 346 (int)((primme->procID/4096)/4096+2) % 4096; 347 if (primme->iseed[3]<0 || primme->iseed[3]>4095) primme->iseed[3] = 348 (2*(int)(((primme->procID/4096)/4096)/4096)+1) % 4096; 349 350 /* Set default convTetFun */ 351 352 if (!primme->convTestFun) { 353 primme->convTestFun = convTestFunAbsolute; 354 primme->convTestFun_type = PRIMME_OP_SCALAR; 355 if (primme->eps == 0.0) { 356 primme->eps = MACHINE_EPSILON * 1e4; 357 /* The default value of eps is too much for half precision */ 358 if (primme->eps >= 1.0) primme->eps = 0.1; 359 } 360 } 361 362 /* Set default monitor */ 363 364 if (!primme->monitorFun) { 365 primme->monitorFun = default_monitor; 366 primme->monitorFun_type = PRIMME_OP_SCALAR; 367 } 368 369 /* Check primme input data for bounds, correct values etc. */ 370 371 CHKERR(coordinated_exit(check_params_coherence(ctx), ctx)); 372 CHKERR(check_input(evals, evecs, resNorms, primme)) 373 374 /* Cast evals, evecs and resNorms to working precision */ 375 376 HEVAL *evals0; 377 HREAL *resNorms0; 378 SCALAR *evecs0; 379 CHKERR(KIND(Num_matrix_astype_RHprimme, Num_matrix_astype_SHprimme)(evals, 1, 380 primme->numEvals, 1, evals_resNorms_type, (void **)&evals0, NULL, 381 PRIMME_OP_HREAL, 1 /* alloc */, 0 /* not copy */, ctx)); 382 PRIMME_INT ldevecs0; 383 CHKERR(Num_matrix_astype_Sprimme(evecs, primme->nLocal, 384 primme->numOrthoConst + max(primme->numEvals, primme->initSize), 385 primme->ldevecs, evecs_type, (void **)&evecs0, &ldevecs0, 386 PRIMME_OP_SCALAR, 1 /* alloc */, 387 primme->numOrthoConst + primme->initSize > 0 ? 1 : 0 /* copy? */, 388 ctx)); 389 CHKERR(Num_matrix_astype_RHprimme(resNorms, 1, primme->numEvals, 390 1, evals_resNorms_type, (void **)&resNorms0, NULL, PRIMME_OP_HREAL, 391 1 /* alloc */, 0 /* not copy */, ctx)); 392 393 /* Call the solver */ 394 395 int ret, numRet; 396 CHKERR(coordinated_exit(main_iter_Sprimme(evals0, evecs0, ldevecs0, 397 resNorms0, t0, &ret, &numRet, ctx), 398 ctx)); 399 400 /* Copy back evals, evecs and resNorms */ 401 402 CHKERR(KIND(Num_matrix_astype_RHprimme, Num_matrix_astype_SHprimme)(evals0, 403 1, numRet, 1, PRIMME_OP_HREAL, (void **)&evals, NULL, 404 evals_resNorms_type, -1 /* destroy */, 1 /* copy */, ctx)); 405 CHKERR(Num_copy_matrix_astype_Sprimme(evecs0, 0, primme->numOrthoConst, 406 primme->nLocal, numRet, ldevecs0, PRIMME_OP_SCALAR, evecs, 0, 407 primme->numOrthoConst, primme->ldevecs, evecs_type, ctx)); 408 if (evecs != evecs0) { 409 CHKERR(Num_free_Sprimme(evecs0, ctx)); 410 } 411 CHKERR(Num_matrix_astype_RHprimme(resNorms0, 1, numRet, 1, PRIMME_OP_HREAL, 412 (void **)&resNorms, NULL, evals_resNorms_type, -1 /* destroy */, 413 1 /* copy */, ctx)); 414 415 /* If no error, return initSize */ 416 417 *outInitSize = primme->initSize; 418 419 primme->stats.elapsedTime = primme_wTimer() - t0; 420 return ret; 421 } 422 423 424 /****************************************************************************** 425 * Subroutine check_input - checks the value of the input arrays, evals, 426 * evecs, and resNorms and the values of primme_params. 427 * 428 * INPUT 429 * ----- 430 * evals, evecs, resNorms Output arrays for primme 431 * primme the main structure of parameters 432 * 433 * return value - 0 If input parameters in primme are appropriate 434 * <0 Inappropriate input parameters were found 435 * 436 ******************************************************************************/ 437 STATIC int check_input( 438 void *evals, void *evecs, void *resNorms, primme_params *primme) { 439 int ret; 440 ret = 0; 441 442 if (primme == NULL) 443 ret = -4; 444 else if (primme->n < 0 || primme->nLocal < 0 || primme->nLocal > primme->n) 445 ret = -5; 446 else if (primme->numProcs < 1) 447 ret = -6; 448 else if (primme->matrixMatvec == NULL) 449 ret = -7; 450 else if (primme->applyPreconditioner == NULL && 451 primme->correctionParams.precondition > 0 ) 452 ret = -8; 453 else if (primme->numEvals > primme->n) 454 ret = -10; 455 else if (primme->numEvals < 0) 456 ret = -11; 457 else if (primme->convTestFun != NULL && fabs(primme->eps) != 0.0L && 458 primme->eps < MACHINE_EPSILON) 459 ret = -12; 460 else if ( primme->target != primme_smallest && 461 primme->target != primme_largest && 462 primme->target != primme_largest_abs && 463 primme->target != primme_closest_geq && 464 primme->target != primme_closest_leq && 465 primme->target != primme_closest_abs ) 466 ret = -13; 467 else if (primme->numOrthoConst < 0 || primme->numOrthoConst > primme->n) 468 ret = -16; 469 else if (primme->maxBasisSize < 2 && primme->n > 2) 470 ret = -17; 471 else if (primme->minRestartSize < 0 || (primme->minRestartSize == 0 472 && primme->n > 2 && primme->numEvals > 0)) 473 ret = -18; 474 else if (primme->maxBlockSize < 0 475 || (primme->maxBlockSize == 0 && primme->numEvals > 0)) 476 ret = -19; 477 else if (primme->restartingParams.maxPrevRetain < 0) 478 ret = -20; 479 else if (primme->initSize < 0) 480 ret = -22; 481 else if (primme->locking == 0 && primme->initSize > primme->maxBasisSize) 482 ret = -23; 483 else if (primme->locking > 0 && primme->initSize > primme->numEvals) 484 ret = -24; 485 else if (primme->minRestartSize + primme->restartingParams.maxPrevRetain 486 >= primme->maxBasisSize && primme->n > primme->maxBasisSize) 487 ret = -25; 488 else if (primme->minRestartSize > primme->n && primme->n > 2) 489 ret = -26; 490 else if (primme->printLevel < 0 || primme->printLevel > 5) 491 ret = -27; 492 else if (primme->correctionParams.convTest != primme_full_LTolerance && 493 primme->correctionParams.convTest != primme_decreasing_LTolerance && 494 primme->correctionParams.convTest != primme_adaptive_ETolerance && 495 primme->correctionParams.convTest != primme_adaptive ) 496 ret = -28; 497 else if (primme->correctionParams.convTest == primme_decreasing_LTolerance && 498 primme->correctionParams.relTolBase <= 1.0L ) 499 ret = -29; 500 else if (evals == NULL) 501 ret = -30; 502 else if (evecs == NULL || Num_check_pointer_Sprimme(evecs)) 503 ret = -31; 504 else if (resNorms == NULL) 505 ret = -32; 506 else if (primme->locking == 0 && primme->minRestartSize < primme->numEvals && 507 primme->n > 2) 508 ret = -33; 509 else if (primme->ldevecs < primme->nLocal) 510 ret = -34; 511 else if (primme->ldOPs != 0 && primme->ldOPs < primme->nLocal) 512 ret = -35; 513 else if (primme->locking == 0 514 && (primme->target == primme_closest_leq 515 || primme->target == primme_closest_geq)) 516 ret = -38; 517 else if (primme->massMatrixMatvec && 518 primme->projectionParams.projection != primme_proj_RR) 519 ret = -39; 520 /* Please keep this if instruction at the end */ 521 else if ( primme->target == primme_largest_abs || 522 primme->target == primme_closest_geq || 523 primme->target == primme_closest_leq || 524 primme->target == primme_closest_abs ) { 525 if (primme->numTargetShifts <= 0) { 526 ret = -14; 527 } 528 else if (primme->targetShifts == NULL ) { 529 ret = -15; 530 } 531 } 532 533 return ret; 534 } 535 536 /******************************************************************************* 537 * Subroutine convTestFunAbsolute - This routine implements primme_params. 538 * convTestFun and return an approximate eigenpair converged when 539 * resNorm < eps*|A| for standard problems, and 540 * resNorm < (|A| + max(|\lambda|)*|B|)*eps for generalized problems 541 * 542 * INPUT ARRAYS AND PARAMETERS 543 * --------------------------- 544 * evec The approximate eigenvector 545 * eval The approximate eigenvalue 546 * rNorm The norm of the residual vector 547 * primme Structure containing various solver parameters 548 * 549 * OUTPUT PARAMETERS 550 * ---------------------------------- 551 * isConv if it isn't zero the approximate pair is marked as converged 552 ******************************************************************************/ 553 554 STATIC void convTestFunAbsolute(double *eval, void *evec, double *rNorm, 555 int *isConv, primme_params *primme, int *ierr) { 556 557 (void)eval; /* unused parameter */ 558 (void)evec; /* unused parameter */ 559 560 if (primme->massMatrixMatvec == NULL) { 561 *isConv = *rNorm < max(primme->eps, MACHINE_EPSILON * 2) * 562 problemNorm_Sprimme(0, primme); 563 } 564 else { 565 *isConv = *rNorm < max(primme->eps, MACHINE_EPSILON) * 566 problemNorm_Sprimme(0, primme); 567 } 568 *ierr = 0; 569 } 570 571 /******************************************************************************* 572 * Subroutine default_monitor - report iterations, #MV, residual norm, 573 * eigenvalues, etc. at every inner/outer iteration and when some pair 574 * converges. 575 * 576 * INPUT ARRAYS AND PARAMETERS 577 * --------------------------- 578 * basisEvals The approximate eigenvalues of the basis 579 * basisSize The size of the basis 580 * basisFlags The state of every approximate pair of the basis (see conv_flags) 581 * iblock Indices of the approximate pairs in the block 582 * blockSize The size of the block 583 * basisNorms The approximate residual norms of the pairs of the basis 584 * numConverged The number of pairs converged in the basis and the locked pairs 585 * (this value isn't monotonic!) 586 * lockedEvals The locked eigenvalues 587 * numLocked The number of pairs locked 588 * lockedFlags The state of each locked eigenpair (see conv_flags) 589 * lockedNorms The residual norms of the locked pairs 590 * inner_its The number of performed QMR iterations in the current correction equation 591 * LSRes The residual norm of the linear system at the current QMR iteration 592 * event The event reported 593 * primme Structure containing various solver parameters and statistics 594 * 595 * OUTPUT 596 * ------ 597 * err Error code 598 * 599 ******************************************************************************/ 600 601 STATIC void default_monitor(void *basisEvals_, int *basisSize, int *basisFlags, 602 int *iblock, int *blockSize, void *basisNorms_, int *numConverged, 603 void *lockedEvals_, int *numLocked, int *lockedFlags, void *lockedNorms_, 604 int *inner_its, void *LSRes_, const char *msg, double *time, 605 primme_event *event, primme_params *primme, int *err) { 606 607 XEVAL *basisEvals = (XEVAL *)basisEvals_, 608 *lockedEvals = (XEVAL *)lockedEvals_; 609 XREAL *basisNorms = (XREAL *)basisNorms_, 610 *lockedNorms = (XREAL *)lockedNorms_, *LSRes = (XREAL *)LSRes_; 611 612 assert(event != NULL && primme != NULL); 613 614 /* Only print report if this is proc zero or it is profiling */ 615 if (primme->outputFile && 616 (primme->procID == 0 || *event == primme_event_profile)) { 617 switch(*event) { 618 case primme_event_outer_iteration: 619 assert(basisSize && (!*basisSize || (basisEvals && basisFlags)) && 620 blockSize && (!*blockSize || (iblock && basisNorms)) && 621 numConverged); 622 assert(!primme->locking || 623 (numLocked && (!*numLocked || (lockedEvals && lockedFlags && 624 lockedNorms)))); 625 if (primme->printLevel >= 3) { 626 int i; /* Loop variable */ 627 int found; /* Reported eigenpairs found */ 628 629 if (primme->locking) 630 found = *numLocked; 631 else 632 found = *numConverged; 633 634 for (i=0; i < *blockSize; i++) { 635 fprintf(primme->outputFile, 636 "OUT %" PRIMME_INT_P " conv %d blk %d MV %" PRIMME_INT_P 637 " Sec %E EV %13E " KIND(, "%13E i ") "|r| %.3E\n", 638 primme->stats.numOuterIterations, found, i, 639 primme->stats.numMatvecs, primme->stats.elapsedTime, 640 (double)EVAL_REAL_PART(basisEvals[iblock[i]]), 641 #ifndef USE_HERMITIAN 642 (double)EVAL_IMAGINARY_PART(basisEvals[iblock[i]]), 643 #endif 644 645 (double)basisNorms[iblock[i]]); 646 } 647 } 648 break; 649 case primme_event_inner_iteration: 650 assert(basisSize && iblock && basisNorms && inner_its && LSRes); 651 (void)inner_its; 652 if (primme->printLevel >= 4) { 653 fprintf(primme->outputFile, 654 "INN MV %" PRIMME_INT_P " Sec %e Eval %13E " KIND( 655 , "%13E i ") "Lin|r| %.3e EV|r| %.3e\n", 656 primme->stats.numMatvecs, primme->stats.elapsedTime, 657 (double)EVAL_REAL_PART(basisEvals[iblock[0]]), 658 #ifndef USE_HERMITIAN 659 (double)EVAL_IMAGINARY_PART(basisEvals[iblock[0]]), 660 #endif 661 (double)*LSRes, (double)basisNorms[iblock[0]]); 662 } 663 break; 664 case primme_event_converged: 665 assert(numConverged && iblock && basisEvals && basisNorms); 666 if ((!primme->locking && primme->printLevel >= 2) 667 || (primme->locking && primme->printLevel >= 5)) 668 fprintf(primme->outputFile, 669 "#Converged %d eval[ %d ]= %13E " KIND(, 670 "%13E i ") "norm %e Mvecs %" PRIMME_INT_P " Time %g\n", 671 *numConverged, iblock[0], 672 (double)EVAL_REAL_PART(basisEvals[iblock[0]]), 673 #ifndef USE_HERMITIAN 674 (double)EVAL_IMAGINARY_PART(basisEvals[iblock[0]]), 675 #endif 676 (double)basisNorms[iblock[0]], primme->stats.numMatvecs, 677 primme->stats.elapsedTime); 678 break; 679 case primme_event_locked: 680 assert(numLocked && lockedEvals && lockedNorms && lockedFlags); 681 if (primme->printLevel >= 2) { 682 fprintf(primme->outputFile, 683 "Lock epair[ %d ]= %13E " KIND( 684 , "%13E i ") "norm %.4e Mvecs %" PRIMME_INT_P 685 " Time %.4e Flag %d\n", 686 *numLocked - 1, 687 (double)EVAL_REAL_PART(lockedEvals[*numLocked - 1]), 688 #ifndef USE_HERMITIAN 689 (double)EVAL_IMAGINARY_PART(lockedEvals[*numLocked - 1]), 690 #endif 691 (double)lockedNorms[*numLocked - 1], primme->stats.numMatvecs, 692 primme->stats.elapsedTime, lockedFlags[*numLocked - 1]); 693 } 694 break; 695 case primme_event_message: 696 assert(msg != NULL); 697 if (primme->printLevel >= 2) { 698 fprintf(primme->outputFile, 699 "%s\n", msg); 700 } 701 break; 702 case primme_event_profile: 703 assert(msg != NULL && time != NULL); 704 if (primme->printLevel >= 3 && *time < 0.0) { 705 fprintf(primme->outputFile, "entering in %s proc %d\n", msg, primme->procID); 706 } 707 if (primme->printLevel >= 2 && *time >= 0.0) { 708 fprintf(primme->outputFile, "time %g for %s proc %d\n", *time, msg, primme->procID); 709 } 710 break; 711 default: 712 break; 713 } apply_projected_preconditioner(SCALAR * v,PRIMME_INT ldv,SCALAR * Q,PRIMME_INT ldQ,SCALAR * RprojectorQ,PRIMME_INT ldRprojectorQ,SCALAR * x,PRIMME_INT ldx,SCALAR * RprojectorX,PRIMME_INT ldRprojectorX,int sizeRprojectorQ,int sizeRprojectorX,HSCALAR * xKinvBx,HSCALAR * Mfact,int * ipivot,SCALAR * result,PRIMME_INT ldresult,int blockSize,primme_context ctx)714 fflush(primme->outputFile); 715 } 716 *err = 0; 717 } 718 719 /****************************************************************************** 720 * check_params_coherence - check that all processes has the same values in 721 * critical parameters. 722 * 723 * INPUT 724 * ----- 725 * primme the main structure of parameters 726 * 727 * RETURN: 728 * error code 729 ******************************************************************************/ 730 731 STATIC int check_params_coherence(primme_context ctx) { 732 primme_params *primme = ctx.primme; 733 734 /* Check number of procs and procs with id zero */ 735 736 HREAL aux[2] = {(HREAL)1.0, (HREAL)(ctx.procID == 0 ? 1.0 : 0.0)}; 737 CHKERR(globalSum_RHprimme(aux, 2, ctx)); 738 CHKERRM((aux[0] > 1) != (ctx.numProcs > 1), 739 -1, "numProcs does not match the actual number of processes"); 740 CHKERRM(aux[1] > 1, -1, "There is not a single process with ID zero"); 741 742 /* Check broadcast */ 743 744 HREAL val = 123, val0 = val; 745 CHKERR(broadcast_RHprimme(&val, 1, ctx)); 746 CHKERRM(fabs(val - val0) > val0 * MACHINE_EPSILON * 1.3, -1, 747 "broadcast function does not work properly"); 748 749 /* Check that all processes has the same value for the next params */ 750 751 PARALLEL_CHECK(primme->n); 752 PARALLEL_CHECK(primme->numEvals); 753 PARALLEL_CHECK(primme->target); 754 PARALLEL_CHECK(primme->numTargetShifts); 755 PARALLEL_CHECK(primme->dynamicMethodSwitch); 756 PARALLEL_CHECK(primme->locking); 757 PARALLEL_CHECK(primme->initSize); 758 PARALLEL_CHECK(primme->numOrthoConst); 759 PARALLEL_CHECK(primme->maxBasisSize); 760 PARALLEL_CHECK(primme->minRestartSize); 761 PARALLEL_CHECK(primme->maxBlockSize); 762 PARALLEL_CHECK(primme->maxMatvecs); 763 PARALLEL_CHECK(primme->maxOuterIterations); 764 PARALLEL_CHECK(primme->aNorm); 765 PARALLEL_CHECK(primme->BNorm); 766 PARALLEL_CHECK(primme->invBNorm); 767 PARALLEL_CHECK(primme->eps); 768 PARALLEL_CHECK(primme->orth); apply_skew_projector(SCALAR * Q,PRIMME_INT ldQ,SCALAR * Qhat,PRIMME_INT ldQhat,HSCALAR * Mfact,int * ipivot,int numCols,SCALAR * v,PRIMME_INT ldv,int blockSize,primme_context ctx)769 PARALLEL_CHECK(primme->initBasisMode); 770 PARALLEL_CHECK(primme->projectionParams.projection); 771 PARALLEL_CHECK(primme->restartingParams.maxPrevRetain); 772 PARALLEL_CHECK(primme->correctionParams.precondition); 773 PARALLEL_CHECK(primme->correctionParams.robustShifts); 774 PARALLEL_CHECK(primme->correctionParams.maxInnerIterations); 775 PARALLEL_CHECK(primme->correctionParams.projectors.LeftQ); 776 PARALLEL_CHECK(primme->correctionParams.projectors.LeftX); 777 PARALLEL_CHECK(primme->correctionParams.projectors.RightQ); 778 PARALLEL_CHECK(primme->correctionParams.projectors.RightX); 779 PARALLEL_CHECK(primme->correctionParams.projectors.SkewQ); 780 PARALLEL_CHECK(primme->correctionParams.projectors.SkewX); 781 PARALLEL_CHECK(primme->correctionParams.convTest); 782 PARALLEL_CHECK(primme->correctionParams.relTolBase); 783 784 return 0; 785 } 786 787 /****************************************************************************** 788 * coordinated_exit - make sure that if main_iter returns error in some process, 789 * then all processes return an error. 790 * 791 * INPUT 792 * ----- 793 * primme the main structure of parameters 794 * 795 * RETURN: 796 * error code 797 ******************************************************************************/ 798 STATIC int coordinated_exit(int ret, primme_context ctx) { 799 800 primme_params *primme = ctx.primme; 801 802 if (ret != PRIMME_PARALLEL_FAILURE && primme->globalSumReal) { 803 HREAL pret = (HREAL)(ret != 0 ? 1 : 0); 804 int count = 1, ierr = 0; 805 CHKERRM( 806 (primme->globalSumReal(&pret, &pret, &count, primme, &ierr), ierr), 807 PRIMME_USER_FAILURE, "Error returned by 'globalSumReal' %d", ierr); 808 if (pret > 0.0) return ret ? ret : PRIMME_PARALLEL_FAILURE; 809 } 810 811 return ret; 812 } 813 814 #endif /* SUPPORTED_TYPE */ 815