示例#1
0
 /**
  * Return the factor by which the undamped Newton step 'step0'
  * must be multiplied in order to keep all solution components in
  * all domains between their specified lower and upper bounds.
  */
 doublereal MultiNewton::boundStep(const doublereal* x0, 
     const doublereal* step0, const OneDim& r, int loglevel) {
     doublereal fbound = 1.0;
     for (size_t i = 0; i < r.nDomains(); i++) {
         fbound = fminn(fbound, 
             bound_step(x0 + r.start(i), step0 + r.start(i),
             r.domain(i), loglevel));
     }
     return fbound;
 }
示例#2
0
 /**
  * Compute the weighted 2-norm of 'step'.
  */
 doublereal MultiNewton::norm2(const doublereal* x, 
     const doublereal* step, OneDim& r) const {
     doublereal f, sum = 0.0;//, fmx = 0.0;
     size_t nd = r.nDomains();
     for (size_t n = 0; n < nd; n++) {
         f = norm_square(x + r.start(n), step + r.start(n),
             r.domain(n));
         sum += f;
     }
     sum /= r.size();
     return sqrt(sum);
 }
示例#3
0
void MultiNewton::step(doublereal* x, doublereal* step,
                       OneDim& r, MultiJac& jac, int loglevel)
{
    size_t iok;
    size_t sz = r.size();
    r.eval(npos, x, step);
#undef DEBUG_STEP
#ifdef DEBUG_STEP
    vector_fp ssave(sz, 0.0);
    for (size_t n = 0; n < sz; n++) {
        step[n] = -step[n];
        ssave[n] = step[n];
    }
#else
    for (size_t n = 0; n < sz; n++) {
        step[n] = -step[n];
    }
#endif

    iok = jac.solve(step, step);

    // if iok is non-zero, then solve failed
    if (iok != 0) {
        iok--;
        size_t nd = r.nDomains();
        size_t n;
        for (n = nd-1; n != npos; n--)
            if (iok >= r.start(n)) {
                break;
            }
        Domain1D& dom = r.domain(n);
        size_t offset = iok - r.start(n);
        size_t pt = offset/dom.nComponents();
        size_t comp = offset - pt*dom.nComponents();
        throw CanteraError("MultiNewton::step",
                           "Jacobian is singular for domain "+
                           dom.id() + ", component "
                           +dom.componentName(comp)+" at point "
                           +int2str(pt)+"\n(Matrix row "
                           +int2str(iok)+") \nsee file bandmatrix.csv\n");
    } else if (int(iok) < 0)
        throw CanteraError("MultiNewton::step",
                           "iok = "+int2str(iok));

#ifdef DEBUG_STEP
    bool ok = false;
    Domain1D* d;
    if (!ok) {
        for (size_t n = 0; n < sz; n++) {
            d = r.pointDomain(n);
            int nvd = d->nComponents();
            int pt = (n - d->loc())/nvd;
            cout << "step: " << pt << "  " <<
                 r.pointDomain(n)->componentName(n - d->loc() - nvd*pt)
                 << "    " << x[n] << "     " << ssave[n] << "   " << step[n] << endl;
        }
    }
#endif
}
示例#4
0
MultiJac::MultiJac(OneDim& r)
    : BandMatrix(r.size(),r.bandwidth(),r.bandwidth())
{
    m_size = r.size();
    m_points = r.points();
    m_resid = &r;
    m_r1.resize(m_size);
    m_ssdiag.resize(m_size);
    m_mask.resize(m_size);
    m_elapsed = 0.0;
    m_nevals = 0;
    m_age = 100000;
    doublereal ff = 1.0;
    while (1.0 + ff != 1.0) {
        ff *= 0.5;
    }
    m_atol = sqrt(ff);
    m_rtol = 1.0e-5;
}
示例#5
0
    /**
     * Find the solution to F(X) = 0 by damped Newton iteration.  On
     * entry, x0 contains an initial estimate of the solution.  On
     * successful return, x1 contains the converged solution.
     */
    int MultiNewton::solve(doublereal* x0, doublereal* x1, 
        OneDim& r, MultiJac& jac, int loglevel) {
        clock_t t0 = clock();
        int m = 0;
        bool forceNewJac = false;
        doublereal s1=1.e30;

        doublereal* x    = getWorkArray();
        doublereal* stp  = getWorkArray();
        doublereal* stp1 = getWorkArray();

        copy(x0, x0 + m_n, x);

        bool frst = true;
        doublereal rdt = r.rdt();
        int j0 = jac.nEvals();

        while (1 > 0) {

            // Check whether the Jacobian should be re-evaluated.
            if (jac.age() > m_maxAge) {
                if (loglevel > 0) 
                    writelog("\nMaximum Jacobian age reached ("+int2str(m_maxAge)+")\n");
                forceNewJac = true;
            }

            if (forceNewJac) {
                r.eval(-1, x, stp, 0.0, 0);
                jac.eval(x, stp, 0.0);
                jac.updateTransient(rdt, DATA_PTR(r.transientMask()));
                forceNewJac = false;
            }

            // compute the undamped Newton step
            step(x, stp, r, jac, loglevel-1);

            // increment the Jacobian age
            jac.incrementAge();

            // damp the Newton step
            m = dampStep(x, stp, x1, stp1, s1, r, jac, loglevel-1, frst);
            if (loglevel == 1 && m >= 0) {
                if (frst) {
                    sprintf(m_buf,"\n\n    %10s    %10s   %5s ",
                        "log10(ss)","log10(s1)","N_jac");
                    writelog(m_buf);
                    sprintf(m_buf,"\n    ------------------------------------");
                    writelog(m_buf);
                }
                doublereal ss = r.ssnorm(x, stp);
                sprintf(m_buf,"\n    %10.4f    %10.4f       %d ",
                    log10(ss),log10(s1),jac.nEvals());
                writelog(m_buf);
            }
            frst = false;

            // Successful step, but not converged yet. Take the damped
            // step, and try again.
            if (m == 0) {
                copy(x1, x1 + m_n, x);
            }

            // convergence
            else if (m == 1) goto done;

            // If dampStep fails, first try a new Jacobian if an old
            // one was being used. If it was a new Jacobian, then
            // return -1 to signify failure.
            else if (m < 0) {
                if (jac.age() > 1) {
                    forceNewJac = true;
                    if (loglevel > 0)
                        writelog("\nRe-evaluating Jacobian, since no damping "
                            "coefficient\ncould be found with this Jacobian.\n");
                }
                else goto done;
            }
        }

 done:
        if (m < 0) {
            copy(x, x + m_n, x1);
        }
        if (m > 0 && jac.nEvals() == j0) m = 100;
        releaseWorkArray(x);
        releaseWorkArray(stp);
        releaseWorkArray(stp1);
        m_elapsed += (clock() - t0)/(1.0*CLOCKS_PER_SEC);
        return m;
    }
示例#6
0
    /**
     * On entry, step0 must contain an undamped Newton step for the
     * solution x0. This method attempts to find a damping coefficient
     * such that the next undamped step would have a norm smaller than
     * that of step0. If successful, the new solution after taking the
     * damped step is returned in x1, and the undamped step at x1 is
     * returned in step1.
     */
    int MultiNewton::dampStep(const doublereal* x0, const doublereal* step0, 
        doublereal* x1, doublereal* step1, doublereal& s1,
        OneDim& r, MultiJac& jac, int loglevel, bool writetitle) {

        // write header 
        if (loglevel > 0 && writetitle) {
            writelog("\n\nDamped Newton iteration:\n");
            writelog(dashedline);

            sprintf(m_buf,"\n%s  %9s   %9s     %9s   %9s   %9s  %5s %5s\n",
                "m","F_damp","F_bound","log10(ss)",
                "log10(s0)","log10(s1)","N_jac","Age");
            writelog(m_buf);
            writelog(dashedline+"\n");
        }

        // compute the weighted norm of the undamped step size step0
        doublereal s0 = norm2(x0, step0, r);

        // compute the multiplier to keep all components in bounds
        doublereal fbound = boundStep(x0, step0, r, loglevel-1);

        // if fbound is very small, then x0 is already close to the
        // boundary and step0 points out of the allowed domain. In
        // this case, the Newton algorithm fails, so return an error
        // condition.
        if (fbound < 1.e-10) {
            if (loglevel > 0) writelog("\nAt limits.\n");
            return -3;
        }


        //--------------------------------------------
        //           Attempt damped step
        //-------------------------------------------- 

        // damping coefficient starts at 1.0
        doublereal damp = 1.0;

        doublereal ff;

	size_t m;
        for (m = 0; m < NDAMP; m++) {

            ff = fbound*damp;

            // step the solution by the damped step size
            for (size_t j = 0; j < m_n; j++) x1[j] = ff*step0[j] + x0[j];

            // compute the next undamped step that would result if x1
            // is accepted
            step(x1, step1, r, jac, loglevel-1);

            // compute the weighted norm of step1
            s1 = norm2(x1, step1, r);

            // write log information
            if (loglevel > 0) {
                doublereal ss = r.ssnorm(x1,step1);
                sprintf(m_buf,"\n%d  %9.5f   %9.5f   %9.5f   %9.5f   %9.5f %4d  %d/%d",
                    m,damp,fbound,log10(ss+SmallNumber),
                    log10(s0+SmallNumber),
                    log10(s1+SmallNumber), 
                    jac.nEvals(), jac.age(), m_maxAge);
                writelog(m_buf);
            }

            // if the norm of s1 is less than the norm of s0, then
            // accept this damping coefficient. Also accept it if this
            // step would result in a converged solution. Otherwise,
            // decrease the damping coefficient and try again.
 
            if (s1 < 1.0 || s1 < s0) break;
            damp /= DampFactor;
        }

        // If a damping coefficient was found, return 1 if the
        // solution after stepping by the damped step would represent
        // a converged solution, and return 0 otherwise. If no damping
        // coefficient could be found, return -2.
        if (m < NDAMP) {
            if (s1 > 1.0) return 0;
            else return 1;
        }
        else {
            return -2;
        }
    }
示例#7
0
int MultiNewton::solve(doublereal* x0, doublereal* x1,
                       OneDim& r, MultiJac& jac, int loglevel)
{
    clock_t t0 = clock();
    int m = 0;
    bool forceNewJac = false;
    doublereal s1=1.e30;

    copy(x0, x0 + m_n, &m_x[0]);

    bool frst = true;
    doublereal rdt = r.rdt();
    int j0 = jac.nEvals();
    int nJacReeval = 0;

    while (1 > 0) {
        // Check whether the Jacobian should be re-evaluated.
        if (jac.age() > m_maxAge) {
            writelog("\nMaximum Jacobian age reached ("+int2str(m_maxAge)+")\n", loglevel);
            forceNewJac = true;
        }

        if (forceNewJac) {
            r.eval(npos, &m_x[0], &m_stp[0], 0.0, 0);
            jac.eval(&m_x[0], &m_stp[0], 0.0);
            jac.updateTransient(rdt, DATA_PTR(r.transientMask()));
            forceNewJac = false;
        }

        // compute the undamped Newton step
        step(&m_x[0], &m_stp[0], r, jac, loglevel-1);

        // increment the Jacobian age
        jac.incrementAge();

        // damp the Newton step
        m = dampStep(&m_x[0], &m_stp[0], x1, &m_stp1[0], s1, r, jac, loglevel-1, frst);
        if (loglevel == 1 && m >= 0) {
            if (frst) {
                sprintf(m_buf,"\n\n    %10s    %10s   %5s ",
                        "log10(ss)","log10(s1)","N_jac");
                writelog(m_buf);
                sprintf(m_buf,"\n    ------------------------------------");
                writelog(m_buf);
            }
            doublereal ss = r.ssnorm(&m_x[0], &m_stp[0]);
            sprintf(m_buf,"\n    %10.4f    %10.4f       %d ",
                    log10(ss),log10(s1),jac.nEvals());
            writelog(m_buf);
        }
        frst = false;

        // Successful step, but not converged yet. Take the damped
        // step, and try again.
        if (m == 0) {
            copy(x1, x1 + m_n, m_x.begin());
        }

        // convergence
        else if (m == 1) {
            jac.setAge(0); // for efficient sensitivity analysis
            break;
        }

        // If dampStep fails, first try a new Jacobian if an old
        // one was being used. If it was a new Jacobian, then
        // return -1 to signify failure.
        else if (m < 0) {
            if (jac.age() > 1) {
                forceNewJac = true;
                if (nJacReeval > 3) {
                    break;
                }
                nJacReeval++;
                writelog("\nRe-evaluating Jacobian, since no damping "
                         "coefficient\ncould be found with this Jacobian.\n",
                         loglevel);
            } else {
                break;
            }
        }
    }

    if (m < 0) {
        copy(m_x.begin(), m_x.end(), x1);
    }
    if (m > 0 && jac.nEvals() == j0) {
        m = 100;
    }
    m_elapsed += (clock() - t0)/(1.0*CLOCKS_PER_SEC);
    return m;
}