/* \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() ) ); }
/* ******************************************************************************** */ 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; } }
/*! \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); }