Got the dog leg algorithm into a working state, at least on one problem.
This commit is contained in:
parent
af4b40d9c3
commit
f1669ba3e2
2 changed files with 166 additions and 49 deletions
|
|
@ -142,7 +142,8 @@ namespace Cantera {
|
|||
dist_Total_(0.0),
|
||||
JdJd_norm_(0.0),
|
||||
normTrust_Newton_(0.0),
|
||||
normTrust_CP_(0.0)
|
||||
normTrust_CP_(0.0),
|
||||
doDogLeg_(0)
|
||||
{
|
||||
neq_ = m_func->nEquations();
|
||||
|
||||
|
|
@ -239,7 +240,8 @@ namespace Cantera {
|
|||
dist_Total_(0.0),
|
||||
JdJd_norm_(0.0),
|
||||
normTrust_Newton_(0.0),
|
||||
normTrust_CP_(0.0)
|
||||
normTrust_CP_(0.0),
|
||||
doDogLeg_(0)
|
||||
{
|
||||
*this =operator=(right);
|
||||
}
|
||||
|
|
@ -316,6 +318,7 @@ namespace Cantera {
|
|||
JdJd_norm_ = right.JdJd_norm_;
|
||||
normTrust_Newton_ = right.normTrust_Newton_;
|
||||
normTrust_CP_ = right.normTrust_CP_;
|
||||
doDogLeg_ = right.doDogLeg_;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
|
@ -356,6 +359,10 @@ namespace Cantera {
|
|||
}
|
||||
}
|
||||
//====================================================================================================================
|
||||
void NonlinearSolver::setSolverScheme(int doDogLeg) {
|
||||
doDogLeg_ = doDogLeg;
|
||||
}
|
||||
//====================================================================================================================
|
||||
std::vector<double> & NonlinearSolver::lowBoundsConstraintVector() {
|
||||
return m_y_low_bounds;
|
||||
}
|
||||
|
|
@ -1137,7 +1144,12 @@ namespace Cantera {
|
|||
|
||||
|
||||
}
|
||||
|
||||
//====================================================================================================================
|
||||
double NonlinearSolver::trustRegionLength() const
|
||||
{
|
||||
double dlen = solnErrorNorm(DATA_PTR(deltaX_trust_));
|
||||
return (trustDelta_ * dlen);
|
||||
}
|
||||
//====================================================================================================================
|
||||
void NonlinearSolver::setDefaultDeltaBoundsMagnitudes()
|
||||
{
|
||||
|
|
@ -1281,9 +1293,12 @@ namespace Cantera {
|
|||
for (int i = 0; i < neq_; i++) {
|
||||
wtSum += m_ewt[i];
|
||||
}
|
||||
wtSum /= neq_;
|
||||
double trustNorm = solnErrorNorm(DATA_PTR(deltaX_trust_));
|
||||
double trustNormGoal = trustNorm * trustDelta_;
|
||||
|
||||
// This is the size of each component.
|
||||
double trustDeltaEach = trustDelta_ / neq_;
|
||||
double trustDeltaEach = trustDelta_ * trustNorm / neq_;
|
||||
double oldVal;
|
||||
double fabsy;
|
||||
// we use the old value of the trust region as an indicator
|
||||
|
|
@ -1300,30 +1315,47 @@ namespace Cantera {
|
|||
}
|
||||
} else {
|
||||
double newValue = trustDeltaEach * m_ewt[i] / wtSum;
|
||||
if (newValue > 2.0 * oldVal) {
|
||||
newValue = 2.0 * oldVal;
|
||||
} else if (newValue < 0.5 * oldVal) {
|
||||
newValue = 0.5 * oldVal;
|
||||
if (newValue > 4.0 * oldVal) {
|
||||
newValue = 4.0 * oldVal;
|
||||
} else if (newValue < 0.25 * oldVal) {
|
||||
newValue = 0.25 * oldVal;
|
||||
if (deltaX_trust_[i] < m_deltaStepMinimum[i]) {
|
||||
newValue = m_deltaStepMinimum[i];
|
||||
}
|
||||
}
|
||||
deltaX_trust_[i] = newValue;
|
||||
if (deltaX_trust_[i] > 0.75 * m_deltaStepMaximum[i]) {
|
||||
deltaX_trust_[i] = m_deltaStepMaximum[i];
|
||||
deltaX_trust_[i] = 0.75 * m_deltaStepMaximum[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Final renormalization.
|
||||
double sum = 0.0;
|
||||
trustNorm = solnErrorNorm(DATA_PTR(deltaX_trust_));
|
||||
double sum = trustNormGoal / trustNorm;
|
||||
for (int i = 0; i < neq_; i++) {
|
||||
sum += deltaX_trust_[i];
|
||||
}
|
||||
for (int i = 0; i < neq_; i++) {
|
||||
deltaX_trust_[i] = deltaX_trust_[i] / sum;
|
||||
deltaX_trust_[i] = deltaX_trust_[i] * sum;
|
||||
}
|
||||
trustDelta_ = 1.0;
|
||||
|
||||
printf("calcTrustVector(): Trust vector size (SolnNorm Basis) changed from %g to %g \n",
|
||||
trustNorm, trustNormGoal);
|
||||
}
|
||||
//====================================================================================================================
|
||||
void NonlinearSolver::initializeTrustRegion()
|
||||
{
|
||||
double cpd = calcTrustDistance(deltaX_CP_);
|
||||
printf("Relative Distance of Cauchy Vector wrt Trust Vector = %g\n", cpd);
|
||||
trustDelta_ = trustDelta_ * cpd;
|
||||
calcTrustVector();
|
||||
cpd = calcTrustDistance(deltaX_CP_);
|
||||
printf("Relative Distance of Cauchy Vector wrt Trust Vector = %g\n", cpd);
|
||||
trustDelta_ = trustDelta_ * cpd;
|
||||
calcTrustVector();
|
||||
cpd = calcTrustDistance(deltaX_CP_);
|
||||
printf("Relative Distance of Cauchy Vector wrt Trust Vector = %g\n", cpd);
|
||||
}
|
||||
|
||||
//====================================================================================================================
|
||||
// Fill a dogleg solution step vector
|
||||
/*
|
||||
|
|
@ -1355,7 +1387,7 @@ namespace Cantera {
|
|||
* The trust distance is defined as the length of the step according to the norm wrt to the trust region.
|
||||
* We calculate the trust distance by the following method
|
||||
*
|
||||
* trustDist = || delta_x dot 1/trustDeltaX_ ||
|
||||
* trustDist = || delta_x dot 1/trustDeltaX_ || / trustDelta_
|
||||
*
|
||||
* @param deltaX Current value of deltaX
|
||||
*/
|
||||
|
|
@ -1367,7 +1399,7 @@ namespace Cantera {
|
|||
tmp = deltaX[i] / deltaX_trust_[i];
|
||||
sum += tmp * tmp;
|
||||
}
|
||||
sum = sqrt(sum / neq_);
|
||||
sum = sqrt(sum / neq_) / trustDelta_;
|
||||
return sum;
|
||||
}
|
||||
//====================================================================================================================
|
||||
|
|
@ -1744,7 +1776,7 @@ namespace Cantera {
|
|||
double deltaSolnNorm = solnErrorNorm(DATA_PTR(deltaX_CP_));
|
||||
double funcDecreaseSDExp = RJd_norm_ / deltaSolnNorm * lambda_;
|
||||
bool goodStep = false;
|
||||
|
||||
double tlen;
|
||||
|
||||
|
||||
for (m = 0; m < NDAMP; m++) {
|
||||
|
|
@ -1752,10 +1784,29 @@ namespace Cantera {
|
|||
* Find the initial value of lambda that satisfies the trust distance, trustDelta_
|
||||
*/
|
||||
leg = calcTrustIntersection(trustDelta_, lambda, alpha);
|
||||
|
||||
if (loglevel > 5) {
|
||||
tlen = trustRegionLength();
|
||||
printf("\tdampDogLeg: trust region with length %13.5E has intersection at leg = %d, alpha = %g\n",
|
||||
tlen, leg, alpha);
|
||||
}
|
||||
/*
|
||||
* Figure out the new step vector, step0, based on (leg, alpha)
|
||||
*/
|
||||
fillDogLegStep(leg, alpha, step0);
|
||||
|
||||
/*
|
||||
* Bound the step
|
||||
*/
|
||||
m_dampBound = boundStep(y0, DATA_PTR(step0), loglevel);
|
||||
/*
|
||||
* Decrease the step length if we are bound
|
||||
*/
|
||||
if (m_dampBound < 1.0) {
|
||||
for (j = 0; j < neq_; j++) {
|
||||
step0[j] = step0[j] * m_dampBound;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* OK, we have the step0. Now, ask the question whether it satisfies the acceptance criteria
|
||||
|
|
@ -1810,6 +1861,16 @@ namespace Cantera {
|
|||
|
||||
}
|
||||
|
||||
/*
|
||||
* Estimate s1, the norm after the next step
|
||||
*/
|
||||
double stepNorm = solnErrorNorm(DATA_PTR(step1));
|
||||
if ( m_dampBound < 1.0) {
|
||||
stepNorm /= m_dampBound;
|
||||
}
|
||||
stepNorm *= m_normResidTrial / m_normResid0;
|
||||
s1 = stepNorm;
|
||||
|
||||
if (success) {
|
||||
if (m_normResidTrial < 1.0) {
|
||||
return 1;
|
||||
|
|
@ -1828,21 +1889,15 @@ namespace Cantera {
|
|||
bool goodStep = false;
|
||||
int j;
|
||||
int info;
|
||||
double ll;
|
||||
double stepNorm = solnErrorNorm(DATA_PTR(step0));
|
||||
double normResid02 = m_normResid0 * m_normResid0 * neq_;
|
||||
double deltaSolnNorm = solnErrorNorm(DATA_PTR(deltaX_CP_));
|
||||
double funcDecreaseSDExp = RJd_norm_ / deltaSolnNorm * lambda_;
|
||||
// Compute the multiplier to keep all components in bounds
|
||||
// A value of one indicates that there is no limitation
|
||||
// on the current step size in the nonlinear method due to
|
||||
// bounds constraints (either negative values of delta
|
||||
// bounds constraints.
|
||||
m_dampBound = boundStep(y0, DATA_PTR(step0), loglevel);
|
||||
|
||||
double ff = m_dampBound;
|
||||
|
||||
|
||||
for (j = 0; j < neq_; j++) {
|
||||
y1[j] = y0[j] + ff * step0[j];
|
||||
y1[j] = y0[j] + step0[j];
|
||||
}
|
||||
|
||||
if (solnType_ != NSOLN_TYPE_STEADY_STATE) {
|
||||
|
|
@ -1867,7 +1922,7 @@ namespace Cantera {
|
|||
}
|
||||
m_normResidTrial = residErrorNorm(DATA_PTR(m_resid));
|
||||
|
||||
double funcDecrease = 0.5 * (m_normResidTrial - normResid02) / (ff * stepNorm);
|
||||
double funcDecrease = 0.5 * (m_normResidTrial - normResid02) / (stepNorm);
|
||||
if (funcDecrease < 1.0E-4 * funcDecreaseSDExp) {
|
||||
goodStep = true;
|
||||
retn = 0;
|
||||
|
|
@ -1887,19 +1942,33 @@ namespace Cantera {
|
|||
*/
|
||||
if (m_dampBound < 1.0) {
|
||||
trustDelta_ *= 0.5;
|
||||
ll = trustRegionLength();
|
||||
printf("decideStep(): Trust region decreased from %g to %g due to bounds constraint\n",
|
||||
ll*2, ll);
|
||||
} else {
|
||||
retn = 0;
|
||||
double expectedNormRes = expectedResidLeg(leg, alpha);
|
||||
if (m_normResidTrial > 1.1 * expectedNormRes) {
|
||||
trustDelta_ *= 0.5;
|
||||
if ((m_normResidTrial > 0.2 * m_normResid0) && (m_normResidTrial > 0.1)) {
|
||||
trustDelta_ *= 0.5;
|
||||
ll = trustRegionLength();
|
||||
printf("decideStep(): Trust region decreased from %g to %g due to bad quad approximation\n",
|
||||
ll*2, ll);
|
||||
}
|
||||
} else {
|
||||
|
||||
if (trustDelta_ <= trustDeltaOld) {
|
||||
trustDelta_ *= 2.0;
|
||||
ll = trustRegionLength();
|
||||
printf("decideStep(): Trust region increased from %g to %g due to good quad approximation\n",
|
||||
ll*0.5, ll);
|
||||
retn = 3;
|
||||
} else {
|
||||
if (m_normResidTrial < 0.75 * expectedNormRes) {
|
||||
trustDelta_ *= 2.0;
|
||||
ll = trustRegionLength();
|
||||
printf("decideStep(): Trust region further increased from %g to %g due to good nonlinear behavior\n",
|
||||
ll*0.5, ll);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1938,9 +2007,7 @@ namespace Cantera {
|
|||
int m = 0;
|
||||
bool forceNewJac = false;
|
||||
doublereal s1=1.e30;
|
||||
#ifdef DEBUG_DOGLEG
|
||||
//jacCopy_ = jac;
|
||||
#endif
|
||||
|
||||
|
||||
// std::vector<doublereal> y_curr(neq_, 0.0);
|
||||
std::vector<doublereal> ydot_curr(neq_, 0.0);
|
||||
|
|
@ -1996,6 +2063,10 @@ namespace Cantera {
|
|||
createSolnWeights(DATA_PTR(m_y_n));
|
||||
#ifdef DEBUG_DOGLEG
|
||||
calcTrustVector();
|
||||
#else
|
||||
if (doDogLeg_) {
|
||||
calcTrustVector();
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
// Do this stuff every 5 iterations
|
||||
|
|
@ -2003,6 +2074,10 @@ namespace Cantera {
|
|||
createSolnWeights(DATA_PTR(m_y_n));
|
||||
#ifdef DEBUG_DOGLEG
|
||||
calcTrustVector();
|
||||
#else
|
||||
if (doDogLeg_) {
|
||||
calcTrustVector();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
@ -2077,6 +2152,16 @@ namespace Cantera {
|
|||
|
||||
#ifdef DEBUG_DOGLEG
|
||||
m_normDeltaSoln_CP = doCauchyPointSolve(jac);
|
||||
if (m_numTotalNewtIts == 1) {
|
||||
initializeTrustRegion();
|
||||
}
|
||||
#else
|
||||
if (doDogLeg_) {
|
||||
m_normDeltaSoln_CP = doCauchyPointSolve(jac);
|
||||
if (m_numTotalNewtIts == 1) {
|
||||
initializeTrustRegion();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// compute the undamped Newton step
|
||||
|
|
@ -2094,15 +2179,17 @@ namespace Cantera {
|
|||
}
|
||||
|
||||
|
||||
#ifdef DEBUG_DOGLEG
|
||||
double trustD = calcTrustDistance(stp);
|
||||
if (trustD > trustDelta_) {
|
||||
printf("newton's method trustD, %g, larger than trust region, %g\n", trustD, trustDelta_);
|
||||
} else {
|
||||
printf("newton's method trustD, %g, smaller than trust region, %g\n", trustD, trustDelta_);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (doDogLeg_) {
|
||||
double trustD = calcTrustDistance(stp);
|
||||
#ifdef DEBUG_DOGLEG
|
||||
if (trustD > trustDelta_) {
|
||||
printf("newton's method trustD, %g, larger than trust region, %g\n", trustD, trustDelta_);
|
||||
} else {
|
||||
printf("newton's method trustD, %g, smaller than trust region, %g\n", trustD, trustDelta_);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Filter out bad directions
|
||||
|
|
@ -2111,18 +2198,27 @@ namespace Cantera {
|
|||
|
||||
|
||||
|
||||
int doDogLeg = 0;
|
||||
|
||||
#ifdef DEBUG_DOGLEG
|
||||
doDogLeg = 0;
|
||||
descentComparison(time_curr, DATA_PTR(ydot_curr), DATA_PTR(ydot_new), DATA_PTR(stp));
|
||||
setupDoubleDogleg(DATA_PTR(stp));
|
||||
residualComparisonLeg(time_curr, DATA_PTR(ydot_curr), DATA_PTR(ydot_new), DATA_PTR(stp));
|
||||
if (doDogLeg) {
|
||||
#endif
|
||||
|
||||
|
||||
if (doDogLeg_) {
|
||||
setupDoubleDogleg(DATA_PTR(stp));
|
||||
#ifdef DEBUG_DOGLEG
|
||||
residualComparisonLeg(time_curr, DATA_PTR(ydot_curr), DATA_PTR(ydot_new), DATA_PTR(stp));
|
||||
#endif
|
||||
m = dampDogLeg(time_curr, DATA_PTR(m_y_n), DATA_PTR(ydot_curr),
|
||||
stp, DATA_PTR(y_new), DATA_PTR(ydot_new),
|
||||
DATA_PTR(stp1), s1, jac, m_print_flag, frst, i_backtracks);
|
||||
}
|
||||
#endif
|
||||
#ifdef DEBUG_DOGLEG
|
||||
else {
|
||||
residualComparisonLeg(time_curr, DATA_PTR(ydot_curr), DATA_PTR(ydot_new), DATA_PTR(stp));
|
||||
}
|
||||
#endif
|
||||
|
||||
// Damp the Newton step
|
||||
/*
|
||||
* On return the recommended new solution and derivatisve is located in:
|
||||
|
|
@ -2133,7 +2229,7 @@ namespace Cantera {
|
|||
* The estimate of the solution update norm for the next step is located in
|
||||
* s1
|
||||
*/
|
||||
if (!doDogLeg) {
|
||||
if (!doDogLeg_) {
|
||||
m = dampStep(time_curr, DATA_PTR(m_y_n), DATA_PTR(ydot_curr),
|
||||
DATA_PTR(stp), DATA_PTR(y_new), DATA_PTR(ydot_new),
|
||||
DATA_PTR(stp1), s1, jac, m_print_flag, frst, i_backtracks);
|
||||
|
|
|
|||
|
|
@ -208,6 +208,13 @@ namespace Cantera {
|
|||
const doublereal * const ydot_curr, doublereal * const delta_y,
|
||||
SquareMatrix& jac, int loglevel);
|
||||
|
||||
//! Calculate the size of the current trust region
|
||||
/*!
|
||||
* We carry out a norm of deltaX_trust_ first. Then, we multiply that value
|
||||
* by trustDelta_
|
||||
*/
|
||||
double trustRegionLength() const;
|
||||
|
||||
//! Set default deulta bounds amounts
|
||||
/*!
|
||||
* Delta bounds are set to 0.01 for all unknowns arbitrarily and capriciously
|
||||
|
|
@ -262,7 +269,6 @@ namespace Cantera {
|
|||
|
||||
|
||||
|
||||
int calcTrustIntersection(double trustDelta, double &lambda, double &alpha) const;
|
||||
public:
|
||||
//! Bound the step
|
||||
/*!
|
||||
|
|
@ -582,7 +588,9 @@ namespace Cantera {
|
|||
*/
|
||||
int lambdaToLeg(const double lambda, double &alpha) const;
|
||||
|
||||
int calcTrustIntersection(double trustVal, const double &lambda, double &alpha) const;
|
||||
int calcTrustIntersection(double trustVal, double &lambda, double &alpha) const;
|
||||
|
||||
void initializeTrustRegion();
|
||||
|
||||
int dampDogLeg(const doublereal time_curr, const double* y0,
|
||||
const doublereal *ydot0, std::vector<doublereal> & step0,
|
||||
|
|
@ -623,6 +631,15 @@ namespace Cantera {
|
|||
*/
|
||||
void setPrintLvl(int printLvl);
|
||||
|
||||
//! Parameter to turn on solution solver schemes
|
||||
/*!
|
||||
* @param doDogLeg Parameter to turn on the double dog leg scheme
|
||||
* Default is to always use a damping scheme in the Newton Direction.
|
||||
* When this is nonzero, a model trust region approach is used using a double dog leg
|
||||
* with the steepest descent direction used for small step sizes.
|
||||
*/
|
||||
void setSolverScheme(int doDogLeg = 0);
|
||||
|
||||
/*
|
||||
* -----------------------------------------------------------------------------------------------------------------
|
||||
* MEMBER DATA
|
||||
|
|
@ -871,6 +888,10 @@ namespace Cantera {
|
|||
doublereal normTrust_CP_;
|
||||
|
||||
|
||||
//! General toggle for turning on dog leg damping.
|
||||
int doDogLeg_;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************************
|
||||
* OTHER COUNTERS
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue