/*--------------------------------------------------------------- CVodeSetLinearSolver specifies the linear solver ---------------------------------------------------------------*/ int CVodeSetLinearSolver(void *cvode_mem, SUNLinearSolver LS, SUNMatrix A) { CVodeMem cv_mem; CVLsMem cvls_mem; int retval, LSType; /* Return immediately if either cvode_mem or LS inputs are NULL */ if (cvode_mem == NULL) { cvProcessError(NULL, CVLS_MEM_NULL, "CVLS", "CVodeSetLinearSolver", MSG_LS_CVMEM_NULL); return(CVLS_MEM_NULL); } if (LS == NULL) { cvProcessError(NULL, CVLS_ILL_INPUT, "CVLS", "CVodeSetLinearSolver", "LS must be non-NULL"); return(CVLS_ILL_INPUT); } cv_mem = (CVodeMem) cvode_mem; /* Test if solver is compatible with LS interface */ if ( (LS->ops->gettype == NULL) || (LS->ops->initialize == NULL) || (LS->ops->setup == NULL) || (LS->ops->solve == NULL) ) { cvProcessError(cv_mem, CVLS_ILL_INPUT, "CVLS", "CVodeSetLinearSolver", "LS object is missing a required operation"); return(CVLS_ILL_INPUT); } /* Test if vector is compatible with LS interface */ if ( (cv_mem->cv_tempv->ops->nvconst == NULL) || (cv_mem->cv_tempv->ops->nvdotprod == NULL) ) { cvProcessError(cv_mem, CVLS_ILL_INPUT, "CVLS", "CVodeSetLinearSolver", MSG_LS_BAD_NVECTOR); return(CVLS_ILL_INPUT); } /* Retrieve the LS type */ LSType = SUNLinSolGetType(LS); /* Check for compatible LS type, matrix and "atimes" support */ if ((LSType == SUNLINEARSOLVER_ITERATIVE) && (LS->ops->setatimes == NULL)) { cvProcessError(cv_mem, CVLS_ILL_INPUT, "CVLS", "CVodeSetLinearSolver", "Incompatible inputs: iterative LS must support ATimes routine"); return(CVLS_ILL_INPUT); } if ((LSType == SUNLINEARSOLVER_DIRECT) && (A == NULL)) { cvProcessError(cv_mem, CVLS_ILL_INPUT, "CVLS", "CVodeSetLinearSolver", "Incompatible inputs: direct LS requires non-NULL matrix"); return(CVLS_ILL_INPUT); } if ((LSType == SUNLINEARSOLVER_MATRIX_ITERATIVE) && (A == NULL)) { cvProcessError(cv_mem, CVLS_ILL_INPUT, "CVLS", "CVodeSetLinearSolver", "Incompatible inputs: matrix-iterative LS requires non-NULL matrix"); return(CVLS_ILL_INPUT); } /* free any existing system solver attached to CVode */ if (cv_mem->cv_lfree) cv_mem->cv_lfree(cv_mem); /* Set four main system linear solver function fields in cv_mem */ cv_mem->cv_linit = cvLsInitialize; cv_mem->cv_lsetup = cvLsSetup; cv_mem->cv_lsolve = cvLsSolve; cv_mem->cv_lfree = cvLsFree; /* Allocate memory for CVLsMemRec */ cvls_mem = NULL; cvls_mem = (CVLsMem) malloc(sizeof(struct CVLsMemRec)); if (cvls_mem == NULL) { cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVLS", "CVodeSetLinearSolver", MSG_LS_MEM_FAIL); return(CVLS_MEM_FAIL); } memset(cvls_mem, 0, sizeof(struct CVLsMemRec)); /* set SUNLinearSolver pointer */ cvls_mem->LS = LS; /* Set defaults for Jacobian-related fields */ if (A != NULL) { cvls_mem->jacDQ = SUNTRUE; cvls_mem->jac = cvLsDQJac; cvls_mem->J_data = cv_mem; } else { cvls_mem->jacDQ = SUNFALSE; cvls_mem->jac = NULL; cvls_mem->J_data = NULL; } cvls_mem->jtimesDQ = SUNTRUE; cvls_mem->jtsetup = NULL; cvls_mem->jtimes = cvLsDQJtimes; cvls_mem->jt_data = cv_mem; /* Set defaults for preconditioner-related fields */ cvls_mem->pset = NULL; cvls_mem->psolve = NULL; cvls_mem->pfree = NULL; cvls_mem->P_data = cv_mem->cv_user_data; /* Initialize counters */ cvLsInitializeCounters(cvls_mem); /* Set default values for the rest of the LS parameters */ cvls_mem->msbj = CVLS_MSBJ; cvls_mem->jbad = SUNTRUE; cvls_mem->eplifac = CVLS_EPLIN; cvls_mem->last_flag = CVLS_SUCCESS; /* If LS supports ATimes, attach CVLs routine */ if (LS->ops->setatimes) { retval = SUNLinSolSetATimes(LS, cv_mem, cvLsATimes); if (retval != SUNLS_SUCCESS) { cvProcessError(cv_mem, CVLS_SUNLS_FAIL, "CVLS", "CVodeSetLinearSolver", "Error in calling SUNLinSolSetATimes"); free(cvls_mem); cvls_mem = NULL; return(CVLS_SUNLS_FAIL); } } /* If LS supports preconditioning, initialize pset/psol to NULL */ if (LS->ops->setpreconditioner) { retval = SUNLinSolSetPreconditioner(LS, cv_mem, NULL, NULL); if (retval != SUNLS_SUCCESS) { cvProcessError(cv_mem, CVLS_SUNLS_FAIL, "CVLS", "CVodeSetLinearSolver", "Error in calling SUNLinSolSetPreconditioner"); free(cvls_mem); cvls_mem = NULL; return(CVLS_SUNLS_FAIL); } } /* When using a non-NULL SUNMatrix object, store pointer to A and create saved_J */ if (A != NULL) { cvls_mem->A = A; cvls_mem->savedJ = SUNMatClone(A); if (cvls_mem->savedJ == NULL) { cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVLS", "CVodeSetLinearSolver", MSG_LS_MEM_FAIL); free(cvls_mem); cvls_mem = NULL; return(CVLS_MEM_FAIL); } } /* Allocate memory for ytemp and x */ cvls_mem->ytemp = N_VClone(cv_mem->cv_tempv); if (cvls_mem->ytemp == NULL) { cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVLS", "CVodeSetLinearSolver", MSG_LS_MEM_FAIL); SUNMatDestroy(cvls_mem->savedJ); free(cvls_mem); cvls_mem = NULL; return(CVLS_MEM_FAIL); } cvls_mem->x = N_VClone(cv_mem->cv_tempv); if (cvls_mem->x == NULL) { cvProcessError(cv_mem, CVLS_MEM_FAIL, "CVLS", "CVodeSetLinearSolver", MSG_LS_MEM_FAIL); SUNMatDestroy(cvls_mem->savedJ); N_VDestroy(cvls_mem->ytemp); free(cvls_mem); cvls_mem = NULL; return(CVLS_MEM_FAIL); } /* For iterative LS, compute sqrtN from a dot product */ if ( (LSType == SUNLINEARSOLVER_ITERATIVE) || (LSType == SUNLINEARSOLVER_MATRIX_ITERATIVE) ) { N_VConst(ONE, cvls_mem->ytemp); cvls_mem->sqrtN = SUNRsqrt( N_VDotProd(cvls_mem->ytemp, cvls_mem->ytemp) ); } /* Attach linear solver memory to integrator memory */ cv_mem->cv_lmem = cvls_mem; return(CVLS_SUCCESS); }
/* ---------------------------------------------------------------------- * 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); }
/*--------------------------------------------------------------- CVDlsSetLinearSolver specifies the direct linear solver. ---------------------------------------------------------------*/ int CVDlsSetLinearSolver(void *cvode_mem, SUNLinearSolver LS, SUNMatrix A) { CVodeMem cv_mem; CVDlsMem cvdls_mem; /* Return immediately if any input is NULL */ if (cvode_mem == NULL) { cvProcessError(NULL, CVDLS_MEM_NULL, "CVDLS", "CVDlsSetLinearSolver", MSGD_CVMEM_NULL); return(CVDLS_MEM_NULL); } if ( (LS == NULL) || (A == NULL) ) { cvProcessError(NULL, CVDLS_ILL_INPUT, "CVDLS", "CVDlsSetLinearSolver", "Both LS and A must be non-NULL"); return(CVDLS_ILL_INPUT); } cv_mem = (CVodeMem) cvode_mem; /* Test if solver and vector are compatible with DLS */ if (SUNLinSolGetType(LS) != SUNLINEARSOLVER_DIRECT) { cvProcessError(cv_mem, CVDLS_ILL_INPUT, "CVDLS", "CVDlsSetLinearSolver", "Non-direct LS supplied to CVDls interface"); return(CVDLS_ILL_INPUT); } if (cv_mem->cv_tempv->ops->nvgetarraypointer == NULL || cv_mem->cv_tempv->ops->nvsetarraypointer == NULL) { cvProcessError(cv_mem, CVDLS_ILL_INPUT, "CVDLS", "CVDlsSetLinearSolver", MSGD_BAD_NVECTOR); return(CVDLS_ILL_INPUT); } /* free any existing system solver attached to CVode */ if (cv_mem->cv_lfree) cv_mem->cv_lfree(cv_mem); /* Set four main system linear solver function fields in cv_mem */ cv_mem->cv_linit = cvDlsInitialize; cv_mem->cv_lsetup = cvDlsSetup; cv_mem->cv_lsolve = cvDlsSolve; cv_mem->cv_lfree = cvDlsFree; /* Get memory for CVDlsMemRec */ cvdls_mem = NULL; cvdls_mem = (CVDlsMem) malloc(sizeof(struct CVDlsMemRec)); if (cvdls_mem == NULL) { cvProcessError(cv_mem, CVDLS_MEM_FAIL, "CVDLS", "CVDlsSetLinearSolver", MSGD_MEM_FAIL); return(CVDLS_MEM_FAIL); } /* set SUNLinearSolver pointer */ cvdls_mem->LS = LS; /* Initialize Jacobian-related data */ cvdls_mem->jacDQ = SUNTRUE; cvdls_mem->jac = cvDlsDQJac; cvdls_mem->J_data = cv_mem; cvdls_mem->last_flag = CVDLS_SUCCESS; /* Initialize counters */ cvDlsInitializeCounters(cvdls_mem); /* Store pointer to A and create saved_J */ cvdls_mem->A = A; cvdls_mem->savedJ = SUNMatClone(A); if (cvdls_mem->savedJ == NULL) { cvProcessError(cv_mem, CVDLS_MEM_FAIL, "CVDLS", "CVDlsSetLinearSolver", MSGD_MEM_FAIL); free(cvdls_mem); cvdls_mem = NULL; return(CVDLS_MEM_FAIL); } /* Allocate memory for x */ cvdls_mem->x = N_VClone(cv_mem->cv_tempv); if (cvdls_mem->x == NULL) { cvProcessError(cv_mem, CVDLS_MEM_FAIL, "CVDLS", "CVDlsSetLinearSolver", MSGD_MEM_FAIL); SUNMatDestroy(cvdls_mem->savedJ); free(cvdls_mem); cvdls_mem = NULL; return(CVDLS_MEM_FAIL); } /* Attach linear solver memory to integrator memory */ cv_mem->cv_lmem = cvdls_mem; return(CVDLS_SUCCESS); }
/* ---------------------------------------------------------------------- * Extra ScaleAdd tests for sparse matrices: * A and B should have different sparsity patterns, and neither should * contain sufficient storage to for their sum * y should already equal A*x * z should already equal B*x * --------------------------------------------------------------------*/ int Test_SUNMatScaleAdd2(SUNMatrix A, SUNMatrix B, N_Vector x, N_Vector y, N_Vector z) { int failure; SUNMatrix C, D, E; N_Vector u, v; realtype tol=100*UNIT_ROUNDOFF; /* create clones for test */ C = SUNMatClone(A); u = N_VClone(y); v = N_VClone(y); /* test 1: add A to B (output must be enlarged) */ failure = SUNMatCopy(A, C); /* C = A */ if (failure) { printf(">>> FAILED test -- SUNMatCopy returned %d \n", failure); SUNMatDestroy(C); N_VDestroy(u); N_VDestroy(v); return(1); } failure = SUNMatScaleAdd(ONE, C, B); /* C = A+B */ if (failure) { printf(">>> FAILED test -- SUNMatScaleAdd returned %d \n", failure); SUNMatDestroy(C); N_VDestroy(u); N_VDestroy(v); return(1); } failure = SUNMatMatvec(C, x, u); /* u = Cx = Ax+Bx */ if (failure) { printf(">>> FAILED test -- SUNMatMatvec returned %d \n", failure); SUNMatDestroy(C); N_VDestroy(u); N_VDestroy(v); return(1); } N_VLinearSum(ONE,y,ONE,z,v); /* v = y+z */ failure = check_vector(u, v, tol); /* u ?= v */ if (failure) { printf(">>> FAILED test -- SUNMatScaleAdd2 check 1 \n"); printf("\nA =\n"); SUNSparseMatrix_Print(A,stdout); printf("\nB =\n"); SUNSparseMatrix_Print(B,stdout); printf("\nC =\n"); SUNSparseMatrix_Print(C,stdout); printf("\nx =\n"); N_VPrint_Serial(x); printf("\ny =\n"); N_VPrint_Serial(y); printf("\nz =\n"); N_VPrint_Serial(z); printf("\nu =\n"); N_VPrint_Serial(u); printf("\nv =\n"); N_VPrint_Serial(v); SUNMatDestroy(C); N_VDestroy(u); N_VDestroy(v); return(1); } else { printf(" PASSED test -- SUNMatScaleAdd2 check 1 \n"); } /* test 2: add A to a matrix with sufficient but misplaced storage */ D = SUNMatClone(A); failure = SUNSparseMatrix_Reallocate(D, SM_NNZ_S(A)+SM_NNZ_S(B)); failure = SUNMatCopy(A, D); /* D = A */ if (failure) { printf(">>> FAILED test -- SUNMatCopy returned %d \n", failure); SUNMatDestroy(C); SUNMatDestroy(D); N_VDestroy(u); N_VDestroy(v); return(1); } failure = SUNMatScaleAdd(ONE, D, B); /* D = A+B */ if (failure) { printf(">>> FAILED test -- SUNMatScaleAdd returned %d \n", failure); SUNMatDestroy(C); SUNMatDestroy(D); N_VDestroy(u); N_VDestroy(v); return(1); } failure = SUNMatMatvec(D, x, u); /* u = Cx = Ax+Bx */ if (failure) { printf(">>> FAILED test -- SUNMatMatvec returned %d \n", failure); SUNMatDestroy(C); SUNMatDestroy(D); N_VDestroy(u); N_VDestroy(v); return(1); } N_VLinearSum(ONE,y,ONE,z,v); /* v = y+z */ failure = check_vector(u, v, tol); /* u ?= v */ if (failure) { printf(">>> FAILED test -- SUNMatScaleAdd2 check 2 \n"); printf("\nA =\n"); SUNSparseMatrix_Print(A,stdout); printf("\nB =\n"); SUNSparseMatrix_Print(B,stdout); printf("\nD =\n"); SUNSparseMatrix_Print(D,stdout); printf("\nx =\n"); N_VPrint_Serial(x); printf("\ny =\n"); N_VPrint_Serial(y); printf("\nz =\n"); N_VPrint_Serial(z); printf("\nu =\n"); N_VPrint_Serial(u); printf("\nv =\n"); N_VPrint_Serial(v); SUNMatDestroy(C); SUNMatDestroy(D); N_VDestroy(u); N_VDestroy(v); return(1); } else { printf(" PASSED test -- SUNMatScaleAdd2 check 2 \n"); } /* test 3: add A to a matrix with the appropriate structure already in place */ E = SUNMatClone(C); failure = SUNMatCopy(C, E); /* E = A + B */ if (failure) { printf(">>> FAILED test -- SUNMatCopy returned %d \n", failure); SUNMatDestroy(C); SUNMatDestroy(D); SUNMatDestroy(E); N_VDestroy(u); N_VDestroy(v); return(1); } failure = SUNMatScaleAdd(NEG_ONE, E, B); /* E = -A */ if (failure) { printf(">>> FAILED test -- SUNMatScaleAdd returned %d \n", failure); SUNMatDestroy(C); SUNMatDestroy(D); SUNMatDestroy(E); N_VDestroy(u); N_VDestroy(v); return(1); } failure = SUNMatMatvec(E, x, u); /* u = Ex = -Ax */ if (failure) { printf(">>> FAILED test -- SUNMatMatvec returned %d \n", failure); SUNMatDestroy(C); SUNMatDestroy(D); SUNMatDestroy(E); N_VDestroy(u); N_VDestroy(v); return(1); } N_VLinearSum(NEG_ONE,y,ZERO,z,v); /* v = -y */ failure = check_vector(u, v, tol); /* v ?= u */ if (failure) { printf(">>> FAILED test -- SUNMatScaleAdd2 check 3 \n"); printf("\nA =\n"); SUNSparseMatrix_Print(A,stdout); printf("\nB =\n"); SUNSparseMatrix_Print(B,stdout); printf("\nC =\n"); SUNSparseMatrix_Print(C,stdout); printf("\nE =\n"); SUNSparseMatrix_Print(E,stdout); printf("\nx =\n"); N_VPrint_Serial(x); printf("\ny =\n"); N_VPrint_Serial(y); printf("\nu =\n"); N_VPrint_Serial(u); printf("\nv =\n"); N_VPrint_Serial(v); SUNMatDestroy(C); SUNMatDestroy(D); SUNMatDestroy(E); N_VDestroy(u); N_VDestroy(v); return(1); } else { printf(" PASSED test -- SUNMatScaleAdd2 check 3 \n"); } SUNMatDestroy(C); SUNMatDestroy(D); SUNMatDestroy(E); N_VDestroy(u); N_VDestroy(v); return(0); }