示例#1
0
/*-----------------------------------------------------------------
  cvLsSolve

  This routine interfaces between CVode and the generic
  SUNLinearSolver object LS, by setting the appropriate tolerance
  and scaling vectors, calling the solver, and accumulating
  statistics from the solve for use/reporting by CVode.
  -----------------------------------------------------------------*/
int cvLsSolve(CVodeMem cv_mem, N_Vector b, N_Vector weight,
              N_Vector ynow, N_Vector fnow)
{
  CVLsMem  cvls_mem;
  realtype bnorm, deltar, delta, w_mean;
  int      curiter, nli_inc, retval, LSType;
  /* access CVLsMem structure */
  if (cv_mem->cv_lmem==NULL) {
    cvProcessError(cv_mem, CVLS_LMEM_NULL, "CVLS",
                   "cvLsSolve", MSG_LS_LMEM_NULL);
    return(CVLS_LMEM_NULL);
  }
  cvls_mem = (CVLsMem) cv_mem->cv_lmem;

  /* Retrieve the LS type */
  LSType = SUNLinSolGetType(cvls_mem->LS);

  /* get current nonlinear solver iteration */
  retval = SUNNonlinSolGetCurIter(cv_mem->NLS, &curiter);

  /* If the linear solver is iterative:
     test norm(b), if small, return x = 0 or x = b;
     set linear solver tolerance (in left/right scaled 2-norm) */
  if ( (LSType == SUNLINEARSOLVER_ITERATIVE) ||
       (LSType == SUNLINEARSOLVER_MATRIX_ITERATIVE) ) {
    deltar = cvls_mem->eplifac * cv_mem->cv_tq[4];
    bnorm = N_VWrmsNorm(b, weight);
    if (bnorm <= deltar) {
      if (curiter > 0) N_VConst(ZERO, b);
      cvls_mem->last_flag = CVLS_SUCCESS;
      return(cvls_mem->last_flag);
    }
    delta = deltar * cvls_mem->sqrtN;
  } else {
    delta = ZERO;
  }

  /* Set vectors ycur and fcur for use by the Atimes and Psolve
     interface routines */
  cvls_mem->ycur = ynow;
  cvls_mem->fcur = fnow;

  /* Set initial guess x = 0 to LS */
  N_VConst(ZERO, cvls_mem->x);

  /* Set scaling vectors for LS to use (if applicable) */
  if (cvls_mem->LS->ops->setscalingvectors) {
    retval = SUNLinSolSetScalingVectors(cvls_mem->LS,
                                        weight,
                                        weight);
    if (retval != SUNLS_SUCCESS) {
      cvProcessError(cv_mem, CVLS_SUNLS_FAIL, "CVLS", "cvLsSolve",
                     "Error in calling SUNLinSolSetScalingVectors");
      cvls_mem->last_flag = CVLS_SUNLS_FAIL;
      return(cvls_mem->last_flag);
    }

  /* If solver is iterative and does not support scaling vectors, update the
     tolerance in an attempt to account for weight vector.  We make the
     following assumptions:
       1. w_i = w_mean, for i=0,...,n-1 (i.e. the weights are homogeneous)
       2. the linear solver uses a basic 2-norm to measure convergence
     Hence (using the notation from sunlinsol_spgmr.h, with S = diag(w)),
           || bbar - Abar xbar ||_2 < tol
       <=> || S b - S A x ||_2 < tol
       <=> || S (b - A x) ||_2 < tol
       <=> \sum_{i=0}^{n-1} (w_i (b - A x)_i)^2 < tol^2
       <=> w_mean^2 \sum_{i=0}^{n-1} (b - A x_i)^2 < tol^2
       <=> \sum_{i=0}^{n-1} (b - A x_i)^2 < tol^2 / w_mean^2
       <=> || b - A x ||_2 < tol / w_mean
     So we compute w_mean = ||w||_RMS = ||w||_2 / sqrt(n), and scale
     the desired tolerance accordingly. */
  } else if ( (LSType == SUNLINEARSOLVER_ITERATIVE) ||
              (LSType == SUNLINEARSOLVER_MATRIX_ITERATIVE) ) {

    w_mean = SUNRsqrt( N_VDotProd(weight, weight) ) / cvls_mem->sqrtN;
    delta /= w_mean;

  }

  /* If a user-provided jtsetup routine is supplied, call that here */
  if (cvls_mem->jtsetup) {
    cvls_mem->last_flag = cvls_mem->jtsetup(cv_mem->cv_tn, ynow, fnow,
                                            cvls_mem->jt_data);
    cvls_mem->njtsetup++;
    if (cvls_mem->last_flag != 0) {
      cvProcessError(cv_mem, retval, "CVLS",
                     "cvLsSolve", MSG_LS_JTSETUP_FAILED);
      return(cvls_mem->last_flag);
    }
  }

  /* Call solver, and copy x to b */
  retval = SUNLinSolSolve(cvls_mem->LS, cvls_mem->A, cvls_mem->x, b, delta);
  N_VScale(ONE, cvls_mem->x, b);

  /* If using a direct or matrix-iterative solver, BDF method, and gamma has changed,
     scale the correction to account for change in gamma */
  if ( ((LSType == SUNLINEARSOLVER_DIRECT) ||
        (LSType == SUNLINEARSOLVER_MATRIX_ITERATIVE)) &&
       (cv_mem->cv_lmm == CV_BDF) &&
       (cv_mem->cv_gamrat != ONE) )
    N_VScale(TWO/(ONE + cv_mem->cv_gamrat), b, b);

  /* Retrieve statistics from iterative linear solvers */
  nli_inc = 0;
  if ( ((LSType == SUNLINEARSOLVER_ITERATIVE) ||
        (LSType == SUNLINEARSOLVER_MATRIX_ITERATIVE)) &&
       (cvls_mem->LS->ops->numiters) )
    nli_inc = SUNLinSolNumIters(cvls_mem->LS);

  /* Increment counters nli and ncfl */
  cvls_mem->nli += nli_inc;
  if (retval != SUNLS_SUCCESS) cvls_mem->ncfl++;

  /* Interpret solver return value  */
  cvls_mem->last_flag = retval;

  switch(retval) {

  case SUNLS_SUCCESS:
    return(0);
    break;
  case SUNLS_RES_REDUCED:
    /* allow reduction but not solution on first Newton iteration,
       otherwise return with a recoverable failure */
    if (curiter == 0) return(0);
    else              return(1);
    break;
  case SUNLS_CONV_FAIL:
  case SUNLS_ATIMES_FAIL_REC:
  case SUNLS_PSOLVE_FAIL_REC:
  case SUNLS_PACKAGE_FAIL_REC:
  case SUNLS_QRFACT_FAIL:
  case SUNLS_LUFACT_FAIL:
    return(1);
    break;
  case SUNLS_MEM_NULL:
  case SUNLS_ILL_INPUT:
  case SUNLS_MEM_FAIL:
  case SUNLS_GS_FAIL:
  case SUNLS_QRSOL_FAIL:
    return(-1);
    break;
  case SUNLS_PACKAGE_FAIL_UNREC:
    cvProcessError(cv_mem, SUNLS_PACKAGE_FAIL_UNREC, "CVLS",
                   "cvLsSolve",
                    "Failure in SUNLinSol external package");
    return(-1);
    break;
  case SUNLS_ATIMES_FAIL_UNREC:
    cvProcessError(cv_mem, SUNLS_ATIMES_FAIL_UNREC, "CVLS",
                   "cvLsSolve", MSG_LS_JTIMES_FAILED);
    return(-1);
    break;
  case SUNLS_PSOLVE_FAIL_UNREC:
    cvProcessError(cv_mem, SUNLS_PSOLVE_FAIL_UNREC, "CVLS",
                   "cvLsSolve", MSG_LS_PSOLVE_FAILED);
    return(-1);
    break;
  }

  return(0);
}
示例#2
0
/*---------------------------------------------------------------
  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);
}
示例#3
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);
}