/*----------------------------------------------------------------- cvDlsSetup ----------------------------------------------------------------- This routine determines whether to update a Jacobian matrix (or use a stored version), based on heuristics regarding previous convergence issues, the number of time steps since it was last updated, etc.; it then creates the system matrix from this, the 'gamma' factor and the identity matrix, A = I-gamma*J. This routine then calls the LS 'setup' routine with A. -----------------------------------------------------------------*/ int cvDlsSetup(CVodeMem cv_mem, int convfail, N_Vector ypred, N_Vector fpred, booleantype *jcurPtr, N_Vector vtemp1, N_Vector vtemp2, N_Vector vtemp3) { booleantype jbad, jok; realtype dgamma; CVDlsMem cvdls_mem; int retval; /* Return immediately if cv_mem or cv_mem->cv_lmem are NULL */ if (cv_mem == NULL) { cvProcessError(NULL, CVDLS_MEM_NULL, "CVDLS", "cvDlsSetup", MSGD_CVMEM_NULL); return(CVDLS_MEM_NULL); } if (cv_mem->cv_lmem == NULL) { cvProcessError(cv_mem, CVDLS_LMEM_NULL, "CVDLS", "cvDlsSetup", MSGD_LMEM_NULL); return(CVDLS_LMEM_NULL); } cvdls_mem = (CVDlsMem) cv_mem->cv_lmem; /* Use nst, gamma/gammap, and convfail to set J eval. flag jok */ dgamma = SUNRabs((cv_mem->cv_gamma/cv_mem->cv_gammap) - ONE); jbad = (cv_mem->cv_nst == 0) || (cv_mem->cv_nst > cvdls_mem->nstlj + CVD_MSBJ) || ((convfail == CV_FAIL_BAD_J) && (dgamma < CVD_DGMAX)) || (convfail == CV_FAIL_OTHER); jok = !jbad; /* If jok = SUNTRUE, use saved copy of J */ if (jok) { *jcurPtr = SUNFALSE; retval = SUNMatCopy(cvdls_mem->savedJ, cvdls_mem->A); if (retval) { cvProcessError(cv_mem, CVDLS_SUNMAT_FAIL, "CVDLS", "cvDlsSetup", MSGD_MATCOPY_FAILED); cvdls_mem->last_flag = CVDLS_SUNMAT_FAIL; return(-1); } /* If jok = SUNFALSE, call jac routine for new J value */ } else { cvdls_mem->nje++; cvdls_mem->nstlj = cv_mem->cv_nst; *jcurPtr = SUNTRUE; retval = SUNMatZero(cvdls_mem->A); if (retval) { cvProcessError(cv_mem, CVDLS_SUNMAT_FAIL, "CVDLS", "cvDlsSetup", MSGD_MATZERO_FAILED); cvdls_mem->last_flag = CVDLS_SUNMAT_FAIL; return(-1); } retval = cvdls_mem->jac(cv_mem->cv_tn, ypred, fpred, cvdls_mem->A, cvdls_mem->J_data, vtemp1, vtemp2, vtemp3); if (retval < 0) { cvProcessError(cv_mem, CVDLS_JACFUNC_UNRECVR, "CVDLS", "cvDlsSetup", MSGD_JACFUNC_FAILED); cvdls_mem->last_flag = CVDLS_JACFUNC_UNRECVR; return(-1); } if (retval > 0) { cvdls_mem->last_flag = CVDLS_JACFUNC_RECVR; return(1); } retval = SUNMatCopy(cvdls_mem->A, cvdls_mem->savedJ); if (retval) { cvProcessError(cv_mem, CVDLS_SUNMAT_FAIL, "CVDLS", "cvDlsSetup", MSGD_MATCOPY_FAILED); cvdls_mem->last_flag = CVDLS_SUNMAT_FAIL; return(-1); } } /* Scale and add I to get A = I - gamma*J */ retval = SUNMatScaleAddI(-cv_mem->cv_gamma, cvdls_mem->A); if (retval) { cvProcessError(cv_mem, CVDLS_SUNMAT_FAIL, "CVDLS", "cvDlsSetup", MSGD_MATSCALEADDI_FAILED); cvdls_mem->last_flag = CVDLS_SUNMAT_FAIL; return(-1); } /* Call generic linear solver 'setup' with this system matrix, and return success/failure flag */ cvdls_mem->last_flag = SUNLinSolSetup(cvdls_mem->LS, cvdls_mem->A); return(cvdls_mem->last_flag); }
/*----------------------------------------------------------------- cvLsSetup This conditionally calls the LS 'setup' routine. When using a SUNMatrix object, this determines whether to update a Jacobian matrix (or use a stored version), based on heuristics regarding previous convergence issues, the number of time steps since it was last updated, etc.; it then creates the system matrix from this, the 'gamma' factor and the identity matrix, A = I-gamma*J. This routine then calls the LS 'setup' routine with A. -----------------------------------------------------------------*/ int cvLsSetup(CVodeMem cv_mem, int convfail, N_Vector ypred, N_Vector fpred, booleantype *jcurPtr, N_Vector vtemp1, N_Vector vtemp2, N_Vector vtemp3) { CVLsMem cvls_mem; realtype dgamma; int retval; /* access CVLsMem structure */ if (cv_mem->cv_lmem==NULL) { cvProcessError(cv_mem, CVLS_LMEM_NULL, "CVLS", "cvLsSetup", MSG_LS_LMEM_NULL); return(CVLS_LMEM_NULL); } cvls_mem = (CVLsMem) cv_mem->cv_lmem; /* Set CVLs N_Vector pointers to current solution and rhs */ cvls_mem->ycur = ypred; cvls_mem->fcur = fpred; /* Use nst, gamma/gammap, and convfail to set J/P eval. flag jok */ dgamma = SUNRabs((cv_mem->cv_gamma/cv_mem->cv_gammap) - ONE); cvls_mem->jbad = (cv_mem->cv_nst == 0) || (cv_mem->cv_nst > cvls_mem->nstlj + cvls_mem->msbj) || ((convfail == CV_FAIL_BAD_J) && (dgamma < CVLS_DGMAX)) || (convfail == CV_FAIL_OTHER); /* If using a NULL SUNMatrix, set jcur to jbad; otherwise update J as appropriate */ if (cvls_mem->A == NULL) { *jcurPtr = cvls_mem->jbad; } else { /* If jbad = SUNFALSE, use saved copy of J */ if (!cvls_mem->jbad) { *jcurPtr = SUNFALSE; retval = SUNMatCopy(cvls_mem->savedJ, cvls_mem->A); if (retval) { cvProcessError(cv_mem, CVLS_SUNMAT_FAIL, "CVLS", "cvLsSetup", MSG_LS_SUNMAT_FAILED); cvls_mem->last_flag = CVLS_SUNMAT_FAIL; return(cvls_mem->last_flag); } /* If jbad = SUNTRUE, call jac routine for new J value */ } else { cvls_mem->nje++; cvls_mem->nstlj = cv_mem->cv_nst; *jcurPtr = SUNTRUE; retval = SUNMatZero(cvls_mem->A); if (retval) { cvProcessError(cv_mem, CVLS_SUNMAT_FAIL, "CVLS", "cvLsSetup", MSG_LS_SUNMAT_FAILED); cvls_mem->last_flag = CVLS_SUNMAT_FAIL; return(cvls_mem->last_flag); } retval = cvls_mem->jac(cv_mem->cv_tn, ypred, fpred, cvls_mem->A, cvls_mem->J_data, vtemp1, vtemp2, vtemp3); if (retval < 0) { cvProcessError(cv_mem, CVLS_JACFUNC_UNRECVR, "CVLS", "cvLsSetup", MSG_LS_JACFUNC_FAILED); cvls_mem->last_flag = CVLS_JACFUNC_UNRECVR; return(-1); } if (retval > 0) { cvls_mem->last_flag = CVLS_JACFUNC_RECVR; return(1); } retval = SUNMatCopy(cvls_mem->A, cvls_mem->savedJ); if (retval) { cvProcessError(cv_mem, CVLS_SUNMAT_FAIL, "CVLS", "cvLsSetup", MSG_LS_SUNMAT_FAILED); cvls_mem->last_flag = CVLS_SUNMAT_FAIL; return(cvls_mem->last_flag); } } /* Scale and add I to get A = I - gamma*J */ retval = SUNMatScaleAddI(-cv_mem->cv_gamma, cvls_mem->A); if (retval) { cvProcessError(cv_mem, CVLS_SUNMAT_FAIL, "CVLS", "cvLsSetup", MSG_LS_SUNMAT_FAILED); cvls_mem->last_flag = CVLS_SUNMAT_FAIL; return(cvls_mem->last_flag); } } /* Call LS setup routine -- the LS may call cvLsPSetup, who will pass the heuristic suggestions above to the user code(s) */ cvls_mem->last_flag = SUNLinSolSetup(cvls_mem->LS, cvls_mem->A); /* If the SUNMatrix was NULL, update heuristics flags */ if (cvls_mem->A == NULL) { /* If user set jcur to SUNTRUE, increment npe and save nst value */ if (*jcurPtr) { cvls_mem->npe++; cvls_mem->nstlj = cv_mem->cv_nst; } /* Update jcur flag if we suggested an update */ if (cvls_mem->jbad) *jcurPtr = SUNTRUE; } return(cvls_mem->last_flag); }
/* ---------------------------------------------------------------------- * Extra ScaleAddI tests for sparse matrices: * A should not contain values on the diagonal, nor should it contain * sufficient storage to add those in * y should already equal A*x * --------------------------------------------------------------------*/ int Test_SUNMatScaleAddI2(SUNMatrix A, N_Vector x, N_Vector y) { int failure; SUNMatrix B, C, D; N_Vector w, z; realtype tol=100*UNIT_ROUNDOFF; /* create clones for test */ B = SUNMatClone(A); z = N_VClone(x); w = N_VClone(x); /* test 1: add I to a matrix with insufficient storage */ failure = SUNMatCopy(A, B); if (failure) { printf(">>> FAILED test -- SUNMatCopy returned %d \n", failure); SUNMatDestroy(B); N_VDestroy(z); N_VDestroy(w); return(1); } failure = SUNMatScaleAddI(NEG_ONE, B); /* B = I-A */ if (failure) { printf(">>> FAILED test -- SUNMatScaleAddI returned %d \n", failure); SUNMatDestroy(B); N_VDestroy(z); N_VDestroy(w); return(1); } failure = SUNMatMatvec(B, x, z); if (failure) { printf(">>> FAILED test -- SUNMatMatvec returned %d \n", failure); SUNMatDestroy(B); N_VDestroy(z); N_VDestroy(w); return(1); } N_VLinearSum(ONE,x,NEG_ONE,y,w); failure = check_vector(z, w, tol); if (failure) { printf(">>> FAILED test -- SUNMatScaleAddI2 check 1 \n"); printf("\nA =\n"); SUNSparseMatrix_Print(A,stdout); printf("\nB =\n"); SUNSparseMatrix_Print(B,stdout); printf("\nz =\n"); N_VPrint_Serial(z); printf("\nw =\n"); N_VPrint_Serial(w); SUNMatDestroy(B); N_VDestroy(z); N_VDestroy(w); return(1); } else { printf(" PASSED test -- SUNMatScaleAddI2 check 1 \n"); } /* test 2: add I to a matrix with sufficient but misplaced storage */ C = SUNMatClone(A); failure = SUNSparseMatrix_Reallocate(C, SM_NNZ_S(A)+SM_ROWS_S(A)); failure = SUNMatCopy(A, C); if (failure) { printf(">>> FAILED test -- SUNMatCopy returned %d \n", failure); SUNMatDestroy(B); SUNMatDestroy(C); N_VDestroy(z); N_VDestroy(w); return(1); } failure = SUNMatScaleAddI(NEG_ONE, C); /* C = I-A */ if (failure) { printf(">>> FAILED test -- SUNMatScaleAddI returned %d \n", failure); SUNMatDestroy(B); SUNMatDestroy(C); N_VDestroy(z); N_VDestroy(w); return(1); } failure = SUNMatMatvec(C, x, z); if (failure) { printf(">>> FAILED test -- SUNMatMatvec returned %d \n", failure); SUNMatDestroy(B); SUNMatDestroy(C); N_VDestroy(z); N_VDestroy(w); return(1); } N_VLinearSum(ONE,x,NEG_ONE,y,w); failure = check_vector(z, w, tol); if (failure) { printf(">>> FAILED test -- SUNMatScaleAddI2 check 2 \n"); printf("\nA =\n"); SUNSparseMatrix_Print(A,stdout); printf("\nC =\n"); SUNSparseMatrix_Print(C,stdout); printf("\nz =\n"); N_VPrint_Serial(z); printf("\nw =\n"); N_VPrint_Serial(w); SUNMatDestroy(B); SUNMatDestroy(C); N_VDestroy(z); N_VDestroy(w); return(1); } else { printf(" PASSED test -- SUNMatScaleAddI2 check 2 \n"); } /* test 3: add I to a matrix with appropriate structure already in place */ D = SUNMatClone(C); failure = SUNMatCopy(C, D); if (failure) { printf(">>> FAILED test -- SUNMatCopy returned %d \n", failure); SUNMatDestroy(B); SUNMatDestroy(C); SUNMatDestroy(D); N_VDestroy(z); N_VDestroy(w); return(1); } failure = SUNMatScaleAddI(NEG_ONE, D); /* D = A */ if (failure) { printf(">>> FAILED test -- SUNMatScaleAddI returned %d \n", failure); SUNMatDestroy(B); SUNMatDestroy(C); SUNMatDestroy(D); N_VDestroy(z); N_VDestroy(w); return(1); } failure = SUNMatMatvec(D, x, z); if (failure) { printf(">>> FAILED test -- SUNMatMatvec returned %d \n", failure); SUNMatDestroy(B); SUNMatDestroy(C); SUNMatDestroy(D); N_VDestroy(z); N_VDestroy(w); return(1); } failure = check_vector(z, y, tol); if (failure) { printf(">>> FAILED test -- SUNMatScaleAddI2 check 3 \n"); printf("\nA =\n"); SUNSparseMatrix_Print(A,stdout); printf("\nD =\n"); SUNSparseMatrix_Print(D,stdout); printf("\nz =\n"); N_VPrint_Serial(z); printf("\ny =\n"); N_VPrint_Serial(y); SUNMatDestroy(B); SUNMatDestroy(C); SUNMatDestroy(D); N_VDestroy(z); N_VDestroy(w); return(1); } else { printf(" PASSED test -- SUNMatScaleAddI2 check 3 \n"); } SUNMatDestroy(B); SUNMatDestroy(C); SUNMatDestroy(D); N_VDestroy(z); N_VDestroy(w); return(0); }