/* \brief Create the OptimizationProblem from the supplied components and
           return it */
 Teuchos::RCP<OPT> getOptimizationProblem() {
     Teuchos::RCP<V> x = getInitialGuess()->clone();
     x->set(*getInitialGuess());
     return Teuchos::rcp( new OPT ( getObjective(),
                                    x,
                                    getBoundConstraint(),
                                    getEqualityConstraint(),
                                    getEqualityMultiplier(),
                                    getInequalityConstraint(),
                                    getInequalityMultiplier() ) );
 }
示例#2
0
/* ******************************************************************************** */
int CalcConc(double *x, int **A, double *G, double *x0, int numSS, int numTotal, 
	     int MaxIters, double tol, double deltaBar, double eta, double kT, 
	     int MaxNoStep, int MaxTrial, double PerturbScale, int quiet, 
	     int WriteLogFile, char *logFile, double MolesWaterPerLiter,
	     unsigned long seed) {
  /*
    Computes the equilbrium mole fractions of species in dilute
    solution using a trust region algorithm on the dual problem.
    Discussion of the method is in Dirks, et al., Thermodynamic
    analysis of interacting nucleic acid strands, SIAM Review, (2006),
    in press.  The trust region algorithm for solving the dual problem
    is that in Nocedal and Wright, Numerical Optimization, 1999, page
    68, with the dogleg method on page 71.

    Returns 1 if converged and 0 otherwise.
  */

  int i,j; // Counters, i is over single-species and j is over all complexes
  int iters; // Number of iterations
  double *AbsTol; // The absolute tolerance on all values of gradient
  double rho; // Ratio of actual to predicted reduction in trust region method
  double delta; // Radius of trust region
  double *Grad; // The gradient of -g(lambda)
  double *lambda; // Lagrange multipliers (dual variables),x[j] = Q[j]*exp(lambda[j])
                  // for j \in \Psi^0
  double *p; // The step we take toward minimization
  double **Hes; // The Hessian
  double FreeEnergy; // The free energy of the solution
  unsigned long rand_seed = 0; // Random number seed
  int nNoStep; // Number of iterations without taking a step
  int nTrial; // Number of times we've perturbed lambda
  int **AT; // Transpose of A
  int RunStats[6]; // Statistics on results from getSearchDir (see comments below)
  FILE *fplog; // Log file

  // Initialize iters just so compiler doesn't give a warning when optimization is on
  iters = 0;

  // Allocate memory
  AT = (int **) malloc(numTotal * sizeof(int *));
  for (j = 0; j < numTotal; j++) {
    AT[j] = (int *) malloc(numSS * sizeof(int));
  }
  Hes = (double **) malloc(numSS * sizeof(double *));
  for (i = 0; i < numSS; i++) {
    Hes[i] = (double *) malloc(numSS * sizeof(double));
  }

  AbsTol = (double *) malloc(numSS * sizeof(double));
  Grad = (double *) malloc(numSS * sizeof(double));
  lambda = (double *) malloc(numSS * sizeof(double));
  p = (double *) malloc(numSS * sizeof(double));

  // The absolute tolerance is a percentage of the entries in x0
  for (i = 0; i < numSS; i++) {
    AbsTol[i] = tol * x0[i];
  }

  // Compute AT (transpose of A), useful to have around.
  IntTranspose(AT,A,numSS,numTotal);

  nTrial = 0;
  for (i = 0; i < numSS; i++) {
    Grad[i] = AbsTol[i] + 1.0; // Initialize just to get started.
  }
  while (CheckTol(Grad,AbsTol,numSS) == 0 && nTrial < MaxTrial) {

    if (nTrial == 1) {
      // Seed the random number generator if necessary
      rand_seed = GetRandSeed(seed);
      init_genrand(rand_seed);
    }

    // Set initial guess
    getInitialGuess(x0,lambda,G,AT,A,numSS,numTotal,PerturbScale,rand_seed);

    // Calculate the counts of the species based on lambda
    if (getx(x,lambda,G,AT,numSS,numTotal) == 0) { // Should be fine; checked prev.
      if (quiet == 0) {
	printf("Overflow error in calcution of mole fractions.\n\n");
	printf("Exiting....\n");
      }
      exit(ERR_OVERFLOW);
    }

    // Calculate the gradient
    getGrad(Grad,x0,x,A,numSS,numTotal);
    
    // Initialize delta to be just less than deltaBar
    delta = 0.99 * deltaBar;
    
    // Initializations
    iters = 0;
    nNoStep = 0;
    RunStats[0] = 0; // Number of pure Newton steps (didn't hit trust region boundary)
    RunStats[1] = 0; // Number of pure Cauchy steps (hit trust region boundary)
    RunStats[2] = 0; // Number of dogleg steps (part Newton and part Cauchy)
    RunStats[3] = 0; // Number of steps with Cholesky failure forcing Cauchy step
    RunStats[4] = 0; // Number of steps with irrelevant Cholesky failures
    RunStats[5] = 0; // Number of failed dogleg calculations
    
    // Run trust region with these initial conditions
    while (iters < MaxIters && CheckTol(Grad,AbsTol,numSS) == 0 
	   && nNoStep < MaxNoStep) {
      

      // Compute the Hessian (symmetric, positive, positive definite)
      getHes(Hes,x,A,numSS,numTotal);

      // Solve for the search direction
      (RunStats[getSearchDir(p,Grad,Hes,delta,numSS) - 1])++;

      // Calculate rho, ratio of actual to predicted reduction
      rho = getRho(lambda,p,Grad,x,Hes,x0,G,AT,numSS,numTotal);
      
      // Adjust delta and make step based on rho
      if (rho < 0.25) {
	delta /= 4.0;
      }
      else if (rho > 0.75 && fabs(norm(p,numSS) - delta) < NUM_PRECISION) {
	delta = min2(2.0*delta,deltaBar);
      }
      if (rho > eta) {
	for (i = 0; i < numSS; i++) {
	  lambda[i] += p[i];
	}
	nNoStep = 0;	
      }
      else {
	nNoStep++;
      }
      
      // Calculate the mole fractions of the complexes based on lambda
      if (getx(x,lambda,G,AT,numSS,numTotal) == 0) {// Should be fine;checked prev.
	if (quiet == 0) {
	  printf("Overflow error in calcution of mole fractions.\n\n");
	  printf("Exiting....\n");
	}
	exit(ERR_OVERFLOW);
      }
      
      // Calculate the gradient
      getGrad(Grad,x0,x,A,numSS,numTotal);
      
      // Advance the iterations count
      iters++;
    }

    // Advance the number of perturbations we've tried
    nTrial++;
  }

  // Compute the free energy
  FreeEnergy = 0;
  // First the reference free energy
  for (i = 0; i < numSS; i++) {
    FreeEnergy += x0[i]*(1.0 - log(x0[i]));
  }
  // Now the free energy
  for (j = 0; j < numTotal; j++) {
    if (x[j] > 0) {
      FreeEnergy += x[j]*(log(x[j]) + G[j] - 1.0);
    }
  }
  // Convert to kcal/liter of solution
  FreeEnergy *= kT*MolesWaterPerLiter;

  /* **************** WRITE OUT RESULTS ********************************* */
  if ( nTrial == MaxTrial  && quiet == 0) {
    printf("\n\n   TRUST REGION METHOD DID NOT CONVERGE DUE TO PRECISION ISSUES\n\n");
  }

  // Report errors in conservation of mass to screen
  if (quiet == 0) {
    // Print out values of the gradient, which is the error in cons. of mass
    printf("Error in conservation of mass:\n");
    for (i = 0; i < numSS; i++) {
      printf("   %8.6e Molar\n",Grad[i]*MolesWaterPerLiter);
    }
    printf("\n");

    // Print out the free energy of the solution
    printf("Free energy = %8.6e kcal/litre of solution\n",FreeEnergy);
   }

  // Write out details of calculation to outfile
  if (WriteLogFile) {
    if ((fplog = fopen(logFile,"a")) == NULL) {
      if (quiet == 0) {
	printf("Error opening %s.\n\nExiting....\n",logFile);
      }
      exit(ERR_LOG);
    }
    if (nTrial == MaxTrial) {
      fprintf(fplog,"TRUST REGION DID NOT CONVERGE DUE TO PRECISION ISSUES\n\n");
    }
    fprintf(fplog,"   --Trust region results:\n");
    fprintf(fplog,"       No. of initial conditions tried: %d\n",nTrial);
    fprintf(fplog,"       Results from succesful trial:\n");
    fprintf(fplog,"         No. of iterations: %d\n",iters);
    fprintf(fplog,"         No. of Newton steps: %d\n",RunStats[0]);
    fprintf(fplog,"         No. of Cauchy steps: %d\n",RunStats[1]);
    fprintf(fplog,"         No. of dogleg steps: %d\n",RunStats[2]);
    fprintf(fplog,"         No. of Cholesky failures resulting in Cauchy steps: %d\n"
	    ,RunStats[3]);
    fprintf(fplog,"         No. of inconsequential Cholesky failures: %d\n",
	    RunStats[4]);
    fprintf(fplog,"         No. of dogleg failures: %d\n",RunStats[5]);
    fprintf(fplog,"         Error in conservation of mass (units of molarity):\n");
    fprintf(fplog,"              Error\tTolerance\n");
    for (i = 0; i < numSS; i++) {
      fprintf(fplog, "           %.14e\t%.14e\n",Grad[i]*MolesWaterPerLiter,
	      AbsTol[i]*MolesWaterPerLiter);
    }
    fprintf(fplog,"   --Free energy of solution = %.14e kcal/litre of solution\n",
	    FreeEnergy);
    fclose(fplog);
  }
  /* **************** END OF WRITING OUT RESULTS **************************** */

   // Free memory
  for (j = 0; j < numTotal; j++) {
    free(AT[j]);
  }
  for (i = 0; i < numSS; i++) {
    free(Hes[i]);
  }
  free(AbsTol);
  free(AT);
  free(Hes);
  free(Grad);
  free(p);
  free(lambda);

  // Return convergence
  if (nTrial == MaxTrial) {
    return 0;
  }
  else {
    return 1;
  }

}
示例#3
0
/*! \fn solve non-linear systems
 *
 *  \param [in]  [data]
 *  \param [in]  [sysNumber] index of corresponding non-linear system
 *
 *  \author wbraun
 */
int solve_nonlinear_system(DATA *data, threadData_t *threadData, int sysNumber)
{
  void *dataAndThreadData[2] = {data, threadData};
  int success = 0, saveJumpState;
  NONLINEAR_SYSTEM_DATA* nonlinsys = &(data->simulationInfo->nonlinearSystemData[sysNumber]);
  struct dataNewtonAndHybrid *mixedSolverData;

  data->simulationInfo->currentNonlinearSystemIndex = sysNumber;

  /* enable to avoid division by zero */
  data->simulationInfo->noThrowDivZero = 1;
  ((DATA*)data)->simulationInfo->solveContinuous = 1;

  /* performance measurement */
  rt_ext_tp_tick(&nonlinsys->totalTimeClock);

  /* grab the initial guess */
  infoStreamPrint(LOG_NLS_EXTRAPOLATE, 1, "############ Start new iteration for system %ld at time at %g ############", nonlinsys->equationIndex, data->localData[0]->timeValue);
  /* if last solving is too long ago use just old values  */
  if (fabs(data->localData[0]->timeValue - nonlinsys->lastTimeSolved) < 5*data->simulationInfo->stepSize)
  {
    getInitialGuess(nonlinsys, data->localData[0]->timeValue);
  }
  else
  {
    nonlinsys->getIterationVars(data, nonlinsys->nlsx);
    memcpy(nonlinsys->nlsx, nonlinsys->nlsxOld, nonlinsys->size*(sizeof(double)));
  }

  /* update non continuous */
  if (data->simulationInfo->discreteCall)
  {
    updateInnerEquation(dataAndThreadData, sysNumber, 1);
  }

  /* try */
#ifndef OMC_EMCC
  MMC_TRY_INTERNAL(simulationJumpBuffer)
#endif

  /* handle asserts */
  saveJumpState = threadData->currentErrorStage;
  threadData->currentErrorStage = ERROR_NONLINEARSOLVER;

  /* use the selected solver for solving nonlinear system */
  switch(data->simulationInfo->nlsMethod)
  {
#if !defined(OMC_MINIMAL_RUNTIME)
  case NLS_HYBRID:
    success = solveHybrd(data, threadData, sysNumber);
    break;
  case NLS_KINSOL:
    success = nlsKinsolSolve(data, threadData, sysNumber);
    break;
  case NLS_NEWTON:
    success = solveNewton(data, threadData, sysNumber);
    /* check if solution process was successful, if not use alternative tearing set if available (dynamic tearing)*/
    if (!success && nonlinsys->strictTearingFunctionCall != NULL){
      debugString(LOG_DT, "Solving the casual tearing set failed! Now the strict tearing set is used.");
      success = nonlinsys->strictTearingFunctionCall(data, threadData);
      if (success) success=2;
    }
    break;
#endif
  case NLS_HOMOTOPY:
    success = solveHomotopy(data, threadData, sysNumber);
    break;
#if !defined(OMC_MINIMAL_RUNTIME)
  case NLS_MIXED:
    mixedSolverData = nonlinsys->solverData;
    nonlinsys->solverData = mixedSolverData->newtonData;

   success = solveHomotopy(data, threadData, sysNumber);

    /* check if solution process was successful, if not use alternative tearing set if available (dynamic tearing)*/
    if (!success && nonlinsys->strictTearingFunctionCall != NULL){
      debugString(LOG_DT, "Solving the casual tearing set failed! Now the strict tearing set is used.");
      success = nonlinsys->strictTearingFunctionCall(data, threadData);
      if (success){
        success=2;
        /* update iteration variables of the causal set*/
        nonlinsys->getIterationVars(data, nonlinsys->nlsx);
      }
    }

    if (!success) {
      nonlinsys->solverData = mixedSolverData->hybridData;
      success = solveHybrd(data, threadData, sysNumber);
    }
    nonlinsys->solverData = mixedSolverData;
    break;
#endif
  default:
    throwStreamPrint(threadData, "unrecognized nonlinear solver");
  }
  /* set result */
  nonlinsys->solved = success;

  /* handle asserts */
  threadData->currentErrorStage = saveJumpState;

  /*catch */
#ifndef OMC_EMCC
  MMC_CATCH_INTERNAL(simulationJumpBuffer)
#endif

  /* update value list database */
  updateInitialGuessDB(nonlinsys, data->localData[0]->timeValue, data->simulationInfo->currentContext);
  if (nonlinsys->solved == 1)
  {
    nonlinsys->lastTimeSolved = data->localData[0]->timeValue;
  }


  /* enable to avoid division by zero */
  data->simulationInfo->noThrowDivZero = 0;
  ((DATA*)data)->simulationInfo->solveContinuous = 0;

  /* performance measurement and statistics */
  nonlinsys->totalTime += rt_ext_tp_tock(&(nonlinsys->totalTimeClock));
  nonlinsys->numberOfCall++;

  /* write csv file for debugging */
#if !defined(OMC_MINIMAL_RUNTIME)
  if (data->simulationInfo->nlsCsvInfomation)
  {
    print_csvLineCallStats(((struct csvStats*) nonlinsys->csvData)->callStats,
                           nonlinsys->numberOfCall,
                           data->localData[0]->timeValue,
                           nonlinsys->numberOfIterations,
                           nonlinsys->numberOfFEval,
                           nonlinsys->totalTime,
                           nonlinsys->solved
    );
  }
#endif
  return check_nonlinear_solution(data, 1, sysNumber);
}