diff --git a/include/cantera/base/ct_defs.h b/include/cantera/base/ct_defs.h index b2c10ea98..7b80e3c25 100644 --- a/include/cantera/base/ct_defs.h +++ b/include/cantera/base/ct_defs.h @@ -80,6 +80,7 @@ const doublereal logGasConstant = std::log(GasConstant); //! One atmosphere [Pa] const doublereal OneAtm = 1.01325e5; +const doublereal OneBar = 1.0E5; //! Universal gas constant in cal/mol/K const doublereal GasConst_cal_mol_K = GasConstant / 4184.0; diff --git a/include/cantera/equil/vcs_SpeciesProperties.h b/include/cantera/equil/vcs_SpeciesProperties.h new file mode 100644 index 000000000..07fdc5d23 --- /dev/null +++ b/include/cantera/equil/vcs_SpeciesProperties.h @@ -0,0 +1,65 @@ + +#ifndef VCS_SPECIES_PROPERTIES_H +#define VCS_SPECIES_PROPERTIES_H + +#include +#include + +namespace VCSnonideal +{ + +class VCS_SPECIES_THERMO; +class vcs_VolPhase; + +class vcs_SpeciesProperties +{ + +public: + size_t IndexPhase; + size_t IndexSpeciesPhase; + vcs_VolPhase* OwningPhase; + size_t NumElements; + + //! Name of the species + std::string SpName; + + VCS_SPECIES_THERMO* SpeciesThermo; /* Pointer to the thermo + structure for this species */ + double WtSpecies; /* Molecular Weight of the species (gm/mol) */ + + //! Column of the formula matrix, comprising the + //! element composition of the species */ + std::vector FormulaMatrixCol; + + double Charge; /* Charge state of the species -> This may + be duplication of what's in the + FormulaMatrixCol entries. However, it's prudent + to separate it out. */ + int SurfaceSpecies; /* True if this species belongs to a surface phase */ + /* + * Various Calculated Quantities that are appropriate to + * keep copies of at this level. + */ + double VolPM; /* Partial molar volume of the species */ + double ReferenceMoleFraction; /* Representative value of the mole + fraction of this species in a phase. + This value is used for convergence issues + and for calculation of numerical derivs */ + + /* + * constructor and destructor + */ + vcs_SpeciesProperties(size_t indexPhase, size_t indexSpeciesPhase, + vcs_VolPhase* owning); + virtual ~vcs_SpeciesProperties(); + + /* + * Copy constructor and assignment operator + */ + vcs_SpeciesProperties(const vcs_SpeciesProperties& b); + vcs_SpeciesProperties& operator=(const vcs_SpeciesProperties& b); +}; + +} + +#endif diff --git a/include/cantera/equil/vcs_VolPhase.h b/include/cantera/equil/vcs_VolPhase.h index 9b75e4e87..1da3837a7 100644 --- a/include/cantera/equil/vcs_VolPhase.h +++ b/include/cantera/equil/vcs_VolPhase.h @@ -12,6 +12,7 @@ #define VCS_VOLPHASE_H #include "cantera/equil/vcs_DoubleStarStar.h" +#include "cantera/equil/vcs_SpeciesProperties.h" #include #include diff --git a/include/cantera/equil/vcs_solve.h b/include/cantera/equil/vcs_solve.h index cfd931b1c..3988cbe19 100644 --- a/include/cantera/equil/vcs_solve.h +++ b/include/cantera/equil/vcs_solve.h @@ -1445,6 +1445,48 @@ private: */ void vcs_updateMolNumVolPhases(const int stateCalc); +public: + //! Calculate the rank of a matrix and return the rows and columns that will generate an independent basis + //! for that rank + /* + * Choose the optimum component species basis for the calculations, finding the rank and + * set of linearly independent rows for that calculation. + * Then find the set of linearly indepedent element columns that can support that rank. + * This is done by taking the transpose of the matrix and redoing the same calculation. + * (there may be a better way to do this. I don't know.) + * + * + * Input + * --------- + * + * @param awtmp Vector of mole numbers which will be used to construct a + * ranking for how to pick the basis species. This is largely ignored + * here. + * + * @param numSpecies Number of species. This is the number of rows in the matrix. + * + * @param matrix Matrix. This is the formula matrix. Nominally, the rows are species, while + * the columns are element compositions. However, this routine + * is totally general, so that the rows and columns can be anything. + * + * @param numElemConstraints Number of element constraints + * + * Output + * --------- + * @param usedZeroedSpecies = If true, then a species with a zero concentration + * was used as a component. + * + * + * @param compRes Vector of rows which are linearly independent. (these are the components) + * + * @param elemComp Vector of columns which are linearly independent (These are the actionable element + * constraints). + * + * @return Returns number of components. This is the rank of the matrix + */ + int vcs_rank(const double * awtmp, size_t numSpecies, const double * matrix, size_t numElemConstraints, + std::vector &compRes, std::vector &elemComp, int * const usedZeroedSpecies) const; + public: //! value of the number of species used to malloc data structures diff --git a/include/cantera/equil/vcs_species_thermo.h b/include/cantera/equil/vcs_species_thermo.h new file mode 100644 index 000000000..f0b7cb3ef --- /dev/null +++ b/include/cantera/equil/vcs_species_thermo.h @@ -0,0 +1,264 @@ + +/* + * Copyright (2005) Sandia Corporation. Under the terms of + * Contract DE-AC04-94AL85000 with Sandia Corporation, the + * U.S. Government retains certain rights in this software. + */ + +#ifndef VCS_SPECIES_THERMO_H +#define VCS_SPECIES_THERMO_H + +#include + +namespace VCSnonideal +{ + +class vcs_VolPhase; + +/*****************************************************************************/ +/*****************************************************************************/ +/*****************************************************************************/ +/* + * Models for the species standard state Naught temperature + * dependence + */ +#define VCS_SS0_NOTHANDLED -1 +#define VCS_SS0_CONSTANT 0 +//#define VCS_SS0_NASA_POLY 1 +#define VCS_SS0_CONSTANT_CP 2 + + +/* + * Models for the species standard state extra pressure dependence + * + */ +#define VCS_SSSTAR_NOTHANDLED -1 +#define VCS_SSSTAR_CONSTANT 0 +#define VCS_SSSTAR_IDEAL_GAS 1 + +/* + * Identifies the thermo model for the species + * This structure is shared by volumetric and surface species. However, + * each will have its own types of thermodynamic models. These + * quantities all have appropriate units. The units are specified by + * VCS_UnitsFormat. + */ +class VCS_SPECIES_THERMO +{ + /* + * All objects are public for ease of development + */ +public: + /** + * Index of the phase that this species belongs to. + */ + size_t IndexPhase; + + /** + * Index of this species in the current phase. + */ + size_t IndexSpeciesPhase; + + /** + * Pointer to the owning phase object. + */ + vcs_VolPhase* OwningPhase; + + /** + * Integer representing the models for the species standard state + * Naught temperature dependence. They are listed above and start + * with VCS_SS0_... + */ + int SS0_Model; + + /** + * Internal storage of the last calculation of the reference + * naught Gibbs free energy at SS0_TSave. + * (always in units of Kelvin) + */ + double SS0_feSave; + + /** + * Internal storage of the last temperature used in the + * calculation of the reference naught Gibbs free energy. + * units = kelvin + */ + double SS0_TSave; + + /** + * Base temperature used in the VCS_SS0_CONSTANT_CP + * model + */ + double SS0_T0; + + /** + * Base enthalpy used in the VCS_SS0_CONSTANT_CP + * model + */ + double SS0_H0; + + /** + * Base entropy used in the VCS_SS0_CONSTANT_CP + * model + */ + double SS0_S0; + + /** + * Base heat capacity used in the VCS_SS0_CONSTANT_CP + * model + */ + double SS0_Cp0; + + /** + * Value of the pressure for the reference state. + * defaults to 1.01325E5 = 1 atm + */ + double SS0_Pref; + /** + * Pointer to a list of parameters that is malloced for + * complicated reference state calculation. + */ + void* SS0_Params; + /** + * Integer value representing the star state model. + */ + int SSStar_Model; + + /** + * Pointer to a list of parameters that is malloced for + * complicated reference star state calculation. + */ + void* SSStar_Params; + + /** + * Integer value representing the activity coefficient model + * These are defined in vcs_VolPhase.h and start with + * VCS_AC_... + */ + int Activity_Coeff_Model; + + /** + * Pointer to a list of parameters that is malloced for + * activity coefficient models. + */ + void* Activity_Coeff_Params; + + /** + * Models for the standard state volume of each species + */ + int SSStar_Vol_Model; + + /** + * Pointer to a list of parameters that is malloced for + * volume models + */ + void* SSStar_Vol_Params; + + /** + * parameter that is used int eh VCS_SSVOL_CONSTANT model. + */ + double SSStar_Vol0; + + /** + * If true, this object will call Cantera to do its member + * calculations. + */ + bool UseCanteraCalls; + + int m_VCS_UnitsFormat; + /* + * constructor and destructor + */ + VCS_SPECIES_THERMO(size_t indexPhase, size_t indexSpeciesPhase); + virtual ~VCS_SPECIES_THERMO(); + + /* + * Copy constructor and assignment operator + */ + VCS_SPECIES_THERMO(const VCS_SPECIES_THERMO& b); + VCS_SPECIES_THERMO& operator=(const VCS_SPECIES_THERMO& b); + + /* + * Duplication function for inherited classes. + */ + virtual VCS_SPECIES_THERMO* duplMyselfAsVCS_SPECIES_THERMO(); + + /** + * This function calculates the standard state Gibbs free energy + * for species, kspec, at the temperature TKelvin and pressure, Pres. + * + * + * Input + * TKelvin = Temperature in Kelvin + * pres = pressure is given in units specified by if__ variable. + * + * + * Output + * return value = standard state free energy in units of Kelvin. + */ + virtual double GStar_R_calc(size_t kspec, double TKelvin, double pres); + + /** + * + * G0_calc: + * + * This function calculates the standard state Gibbs free energy + * for species, kspec, at the temperature TKelvin + * + * Input + * + * + * Output + * return value = standard state free energy in Kelvin. + */ + virtual double G0_R_calc(size_t kspec, double TKelvin); + + /** + * cpc_ts_VStar_calc: + * + * This function calculates the standard state molar volume + * for species, kspec, at the temperature TKelvin and pressure, Pres, + * + * + * Input + * + * + * Output + * return value = standard state volume in cm**3 per mol. + * (if__=3) m**3 / kmol + */ + virtual double VolStar_calc(size_t kglob, double TKelvin, double Pres); + + /** + * This function evaluates the activity coefficient + * for species, kspec + * + * Input + * kspec -> integer value of the species in the global + * species list within VCS_SOLVE. Phase and local species id + * can be looked up within object. + * + * Note, T, P and mole fractions are obtained from the + * single private instance of VCS_SOLVE + * + * + * + * Output + * return value = activity coefficient for species kspec + */ + virtual double eval_ac(size_t kspec); + + /** + * Get the pointer to the vcs_VolPhase object for this species. + */ + +}; + +/* Externals for vcs_species_thermo.c */ + +//extern double vcs_Gxs_phase_calc(vcs_VolPhase *, double *); +//extern double vcs_Gxs_calc(int iphase); + +} + +#endif diff --git a/src/kinetics/ImplicitSurfChem.h b/include/cantera/kinetics/ImplicitSurfChem.h similarity index 100% rename from src/kinetics/ImplicitSurfChem.h rename to include/cantera/kinetics/ImplicitSurfChem.h diff --git a/src/kinetics/solveSP.h b/include/cantera/kinetics/solveSP.h similarity index 100% rename from src/kinetics/solveSP.h rename to include/cantera/kinetics/solveSP.h diff --git a/src/numerics/CVodesIntegrator.h b/include/cantera/numerics/CVodesIntegrator.h similarity index 100% rename from src/numerics/CVodesIntegrator.h rename to include/cantera/numerics/CVodesIntegrator.h diff --git a/include/cantera/numerics/NonlinearSolver.h b/include/cantera/numerics/NonlinearSolver.h index fc3234905..d1a7898f1 100644 --- a/include/cantera/numerics/NonlinearSolver.h +++ b/include/cantera/numerics/NonlinearSolver.h @@ -6,7 +6,11 @@ */ /* - * Copyright 2004 Sandia Corporation. Under the terms of Contract + * $Date$ + * $Revision$ + */ +/* + * Copywrite 2004 Sandia Corporation. Under the terms of Contract * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government * retains certain rights in this software. * See file License.txt for licensing information. @@ -15,136 +19,134 @@ #ifndef CT_NONLINEARSOLVER_H #define CT_NONLINEARSOLVER_H -#include "ResidJacEval.h" -#include "SquareMatrix.h" +#include "cantera/numerics/ResidJacEval.h" +#include "cantera/numerics/SquareMatrix.h" -namespace Cantera -{ - -//@{ -/// @name Constant which determines the type of the nonlinear solve -/*! - * I think steady state is the only option I'm gunning for - */ -//! The nonlinear problem is part of a pseudo time dependent calculation (NOT TESTED) +namespace Cantera { + + //@{ + /// @name Constant which determines the type of the nonlinear solve + /*! + * I think steady state is the only option I'm gunning for + */ + //! The nonlinear problem is part of a pseudo time dependent calculation (NOT TESTED) #define NSOLN_TYPE_PSEUDO_TIME_DEPENDENT 2 -//! The nonlinear problem is part of a time dependent calculation + //! The nonlinear problem is part of a time dependent calculation #define NSOLN_TYPE_TIME_DEPENDENT 1 -//! The nonlinear problem is part of a steady state calculation + //! The nonlinear problem is part of a steady state calculation #define NSOLN_TYPE_STEADY_STATE 0 -//@} + //@} - -//@{ -/// @name Constant which determines the Return int from the nonlinear solver -/*! - * This int is returned from the nonlinear solver - */ -//! The nonlinear solve is successful. + + //@{ + /// @name Constant which determines the Return int from the nonlinear solver + /*! + * This int is returned from the nonlinear solver + */ + //! The nonlinear solve is successful. #define NSOLN_RETN_SUCCESS 1 -//! Problem isn't solved yet -#define NSOLN_RETN_CONTINUE 0 -//! The nonlinear problem started to take too small an update step. This indicates that either the -//! Jacobian is bad, or a constraint is being bumped up against. + //! Problem isn't solved yet +#define NSOLN_RETN_CONTINUE 0 + //! The nonlinear problem started to take too small an update step. This indicates that either the + //! Jacobian is bad, or a constraint is being bumped up against. #define NSOLN_RETN_FAIL_STEPTOOSMALL -1 -//! The nonlinear problem didn't solve the problem + //! The nonlinear problem didn't solve the problem #define NSOLN_RETN_FAIL_DAMPSTEP -2 -//! The nonlinear problem's jacobian is singular + //! The nonlinear problem's jacobian is singular #define NSOLN_RETN_MATRIXINVERSIONERROR -3 -//! The nonlinear problem's jacobian formation produced an error + //! The nonlinear problem's jacobian formation produced an error #define NSOLN_RETN_JACOBIANFORMATIONERROR -4 -//! The nonlinear problem's base residual produced an error + //! The nonlinear problem's base residual produced an error #define NSOLN_RETN_RESIDUALFORMATIONERROR -5 -//! The nonlinear problem's max number of iterations has been exceeded + //! The nonlinear problem's max number of iterations has been exceeded #define NSOLN_RETN_MAXIMUMITERATIONSEXCEEDED -7 -//@} -//@} + //@} + //@} -//@{ -/// @name Constant which determines the type of the Jacobian -//! The jacobian will be calculated from a numerical method + //@{ + /// @name Constant which determines the type of the Jacobian + //! The jacobian will be calculated from a numerical method #define NSOLN_JAC_NUM 1 -//! The jacobian is calculated from an analytical function + //! The jacobian is calculated from an analytical function #define NSOLN_JAC_ANAL 2 -//@} + //@} -//! Class that calculates the solution to a nonlinear system -/*! - * This is a small nonlinear solver that can solve highly nonlinear problems that - * must use a dense matrix to relax the system. - * - * Newton's method is used. - * - * Damping is used extensively when relaxing the system. - * - * - * The basic idea is that we predict a direction that is parameterized by an overall coordinate - * value, beta, from zero to one, This may or may not be the same as the value, damp, - * depending upon whether the direction is straight. - * - * - * TIME STEP TYPE - * - * The code solves a nonlinear problem. Frequently the nonlinear problem is created from time-dependent - * residual. Whenever you change the solution vector, you are also changing the derivative of the - * solution vector. Therefore, the code has the option of altering ydot, a vector of time derivatives - * of the solution in tandem with the solution vector and then feeding a residual and Jacobian routine - * with the time derivatives as well as the solution. The code has support for a backwards euler method - * and a second order Adams-Bashforth or Trapezoidal Rule. - * - * In order to use these methods, the solver must be initialized with delta_t and m_y_nm1[i] to specify - * the conditions at the previous time step. For second order methods, the time derivative at t_nm1 must - * also be supplied, m_ydot_nm1[i]. Then the solution type NSOLN_TYPE_TIME_DEPENDENT may be used to - * solve the problem. - * - * For steady state problem whose residual doesn't have a solution time derivative in it, you should - * use the NSOLN_TYPE_STEADY_STATE problem type. - * - * We have a NSOLN_TYPE_PSEUDO_TIME_DEPENDENT defined. However, this is not implemented yet. This would - * be a pseudo time dependent calculation, where an optional time derivative could be added in order to - * help equilibrate a nonlinear steady state system. The time transient is not important in and of - * itself. Many physical systems have a time dependence to them that provides a natural way to relax - * the nonlinear system. - * - * MATRIX SCALING - * - * - * - * - * @code - * - * - * NonlinearSolver *nls = new NonlinearSolver(&r1); - * - * int solnType = NSOLN_TYPE_STEADY_STATE ; - * - * nls->setDeltaBoundsMagnitudes(deltaBounds); - * - * nls->solve_nonlinear_problem(solnType, y_comm, ydot_comm, CJ, time_curr, jac, - * num_newt_its, num_linear_solves, numBacktracks, - * loglevelInput); - * - * @endcode - * - * - * @ingroup numerics - */ -class NonlinearSolver -{ + //! Class that calculates the solution to a nonlinear system + /*! + * This is a small nonlinear solver that can solve highly nonlinear problems that + * must use a dense matrix to relax the system. + * + * Newton's method is used. + * + * Damping is used extensively when relaxing the system. + * + * + * The basic idea is that we predict a direction that is parameterized by an overall coordinate + * value, beta, from zero to one, This may or may not be the same as the value, damp, + * depending upon whether the direction is straight. + * + * + * TIME STEP TYPE + * + * The code solves a nonlinear problem. Frequently the nonlinear problem is created from time-dependent + * residual. Whenever you change the solution vector, you are also changing the derivative of the + * solution vector. Therefore, the code has the option of altering ydot, a vector of time derivatives + * of the solution in tandem with the solution vector and then feeding a residual and Jacobian routine + * with the time derivatives as well as the solution. The code has support for a backwards euler method + * and a second order Adams-Bashforth or Trapezoidal Rule. + * + * In order to use these methods, the solver must be initialized with delta_t and m_y_nm1[i] to specify + * the conditions at the previous time step. For second order methods, the time derivative at t_nm1 must + * also be supplied, m_ydot_nm1[i]. Then the solution type NSOLN_TYPE_TIME_DEPENDENT may be used to + * solve the problem. + * + * For steady state problem whose residual doesn't have a solution time derivative in it, you should + * use the NSOLN_TYPE_STEADY_STATE problem type. + * + * We have a NSOLN_TYPE_PSEUDO_TIME_DEPENDENT defined. However, this is not implemented yet. This would + * be a pseudo time dependent calculation, where an optional time derivative could be added in order to + * help equilibrate a nonlinear steady state system. The time transient is not important in and of + * itself. Many physical systems have a time dependence to them that provides a natural way to relax + * the nonlinear system. + * + * MATRIX SCALING + * + * + * + * + * @code + * + * + * NonlinearSolver *nls = new NonlinearSolver(&r1); + * + * int solnType = NSOLN_TYPE_STEADY_STATE ; + * + * nls->setDeltaBoundsMagnitudes(deltaBounds); + * + * nls->solve_nonlinear_problem(solnType, y_comm, ydot_comm, CJ, time_curr, jac, + * num_newt_its, num_linear_solves, numBacktracks, + * loglevelInput); + * + * @endcode + * + * + * @ingroup numerics + */ + class NonlinearSolver { -public: + public: //! Default constructor /*! * @param func Residual and jacobian evaluator function object */ - NonlinearSolver(ResidJacEval* func); + NonlinearSolver(ResidJacEval *func); //!Copy Constructor for the %ThermoPhase object. /*! * @param right Item to be copied */ - NonlinearSolver(const NonlinearSolver& right); + NonlinearSolver(const NonlinearSolver &right); //! Destructor ~NonlinearSolver(); @@ -157,7 +159,7 @@ public: * copied into the * current one. */ - NonlinearSolver& operator=(const NonlinearSolver& right); + NonlinearSolver& operator=(const NonlinearSolver &right); //! Create solution weights for convergence criteria /*! @@ -170,7 +172,7 @@ public: * * @param y vector of the current solution values */ - void createSolnWeights(const doublereal* const y); + void createSolnWeights(const doublereal * const y); //! L2 norm of the delta of the solution vector /*! @@ -189,13 +191,13 @@ public: * * @return Returns the L2 norm of the delta */ - doublereal solnErrorNorm(const doublereal* const delta_y, const char* title = 0, int printLargest = 0, - const doublereal dampFactor = 1.0) const; + doublereal solnErrorNorm(const doublereal * const delta_y, const char * title = 0, int printLargest = 0, + const doublereal dampFactor = 1.0) const; //! L2 norm of the residual of the equation system /*! * Calculate the norm of the residual vector. This may - * involve using the row sum scaling from the matrix problem. + * involve using the row sum scaling from the matrix problem. * * The second argument has a default of false. However, * if true, then a table of the largest values is printed @@ -209,40 +211,40 @@ public: * * @return Returns the L2 norm of the delta */ - doublereal residErrorNorm(const doublereal* const resid, const char* title = 0, const int printLargest = 0, - const doublereal* const y = 0) const; + doublereal residErrorNorm(const doublereal * const resid, const char * title = 0, const int printLargest = 0, + const doublereal * const y = 0) const; //! Compute the current residual /*! - * The current value of the residual is stored in the internal work array m_resid, which is defined + * The current value of the residual is storred in the internal work array m_resid, which is defined * as mutable * - * @param time_curr Value of the time + * @param time_curr Value of the time * @param typeCalc Type of the calculation * @param y_curr Current value of the solution vector * @param ydot_curr Current value of the time derivative of the solution vector - * @param evalType Base evaluation type + * @param evalType Base evalulation type * Defaults to Base_ResidEval * * @return Returns a flag to indicate that operation is successful. * 1 Means a successful operation * -0 or neg value Means an unsuccessful operation */ - int doResidualCalc(const doublereal time_curr, const int typeCalc, const doublereal* const y_curr, - const doublereal* const ydot_curr, - const ResidEval_Type_Enum evalType = Base_ResidEval) const; + int doResidualCalc(const doublereal time_curr, const int typeCalc, const doublereal * const y_curr, + const doublereal * const ydot_curr, + const ResidEval_Type_Enum evalType = Base_ResidEval) const; //! Compute the undamped Newton step /*! * * Compute the undamped Newton step. The residual function is * evaluated at the current time, t_n, at the current values of the - * solution vector, m_y_n, and the solution time derivative, m_ydot_n. + * solution vector, m_y_n, and the solution time derivative, m_ydot_n. * The Jacobian is not recomputed. * * A factored jacobian is reused, if available. If a factored jacobian * is not available, then the jacobian is factored. Before factoring, - * the jacobian is row and column-scaled. Column scaling is not + * the jacobian is row and column-scaled. Column scaling is not * recomputed. The row scales are recomputed here, after column * scaling has been implemented. * @@ -254,10 +256,10 @@ public: * * @return Returns the result code from lapack. A zero means success. Anything * else indicates a failure. - */ - int doNewtonSolve(const doublereal time_curr, const doublereal* const y_curr, - const doublereal* const ydot_curr, doublereal* const delta_y, - GeneralMatrix& jac); + */ + int doNewtonSolve(const doublereal time_curr, const doublereal * const y_curr, + const doublereal * const ydot_curr, doublereal * const delta_y, + GeneralMatrix& jac); //! Compute the newton step, either by direct newton's or by solving a close problem that is represented //! by a Hessian ( @@ -265,15 +267,15 @@ public: * This is algorith A.6.5.1 in Dennis / Schnabel * * Compute the QR decomposition - * + * * Compute the undamped Newton step. The residual function is * evaluated at the current time, t_n, at the current values of the - * solution vector, m_y_n, and the solution time derivative, m_ydot_n. + * solution vector, m_y_n, and the solution time derivative, m_ydot_n. * The Jacobian is not recomputed. * * A factored jacobian is reused, if available. If a factored jacobian * is not available, then the jacobian is factored. Before factoring, - * the jacobian is row and column-scaled. Column scaling is not + * the jacobian is row and column-scaled. Column scaling is not * recomputed. The row scales are recomputed here, after column * scaling has been implemented. * @@ -284,14 +286,14 @@ public: * * Internal input * --------------- - * internal m_resid Stored residual is used as input + * internal m_resid Storred residual is used as input * * * @return Returns the result code from lapack. A zero means success. Anything * else indicates a failure. */ - int doAffineNewtonSolve(const doublereal* const y_curr, const doublereal* const ydot_curr, - doublereal* const delta_y, GeneralMatrix& jac); + int doAffineNewtonSolve(const doublereal * const y_curr, const doublereal * const ydot_curr, + doublereal * const delta_y, GeneralMatrix& jac); //! Calculate the length of the current trust region in terms of the solution error norm /*! @@ -314,11 +316,11 @@ public: //! Set the delta Bounds magnitudes by hand /*! - * @param deltaBoundsMagnitudes set the deltaBoundsMagnitude vector + * @param deltaBoundsMagnitudes set the deltaBoundsMagnitude vector */ - void setDeltaBoundsMagnitudes(const doublereal* const deltaBoundsMagnitudes); - -protected: + void setDeltaBoundsMagnitudes(const doublereal * const deltaBoundsMagnitudes); + + protected: //! Readjust the trust region vectors /*! @@ -326,7 +328,7 @@ protected: * We periodically recalculate the trustVector_ values so that they renormalize to the * correct length. We change the trustDelta_ values regularly * - * The trust region calculate is based on + * The trust region calculate is based on * * || delta_x dot 1/trustDeltaX_ || <= trustDelta_ * @@ -348,16 +350,16 @@ protected: /*! * 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_ || * * @param deltaX Current value of deltaX */ - doublereal calcTrustDistance(std::vector const& deltaX) const; + doublereal calcTrustDistance(std::vector const & deltaX) const; -public: + public: //! Bound the step /*! * @@ -378,8 +380,8 @@ public: * Delta bounds: The idea behind these is that the Jacobian * couldn't possibly be representative if the * variable is changed by a lot. (true for - * nonlinear systems, false for linear systems) - * Maximum increase in variable in any one newton iteration: + * nonlinear systems, false for linear systems) + * Maximum increase in variable in any one newton iteration: * factor of 2 * Maximum decrease in variable in any one newton iteration: * factor of 5 @@ -389,23 +391,23 @@ public: * * @return Returns the damping factor determined by the bounds calculation */ - doublereal boundStep(const doublereal* const y, const doublereal* const step0); + doublereal boundStep(const doublereal * const y, const doublereal * const step0); //! Set bounds constraints for all variables in the problem /*! - * + * * @param y_low_bounds Vector of lower bounds * @param y_high_bounds Vector of high bounds */ - void setBoundsConstraints(const doublereal* const y_low_bounds, - const doublereal* const y_high_bounds); + void setBoundsConstraints(const doublereal * const y_low_bounds, + const doublereal * const y_high_bounds); //! Return an editable vector of the low bounds constraints std::vector & lowBoundsConstraintVector(); //! Return an editable vector of the high bounds constraints std::vector & highBoundsConstraintVector(); - + //! Internal function to calculate the time derivative of the solution at the new step /*! * Previously, the user must have supplied information about the previous time step for this routine to @@ -414,13 +416,13 @@ public: * @param order of the BDF method * @param y_curr current value of the solution * @param ydot_curr Calculated value of the solution derivative that is consistent with y_curr - */ - void calc_ydot(const int order, const doublereal* const y_curr, doublereal* const ydot_curr) const; + */ + void calc_ydot(const int order, const doublereal * const y_curr, doublereal * const ydot_curr) const; //! Function called to evaluate the jacobian matrix and the current //! residual vector at the current time step /*! - * + * * * @param J Jacobian matrix to be filled in * @param f Right hand side. This routine returns the current @@ -431,14 +433,14 @@ public: * @param y value of the solution vector * @param ydot value of the time derivative of the solution vector * @param num_newt_its Number of newton iterations - * + * * @return Returns a flag to indicate that operation is successful. * 1 Means a successful operation * 0 Means an unsuccessful operation */ - int beuler_jac(GeneralMatrix& J, doublereal* const f, - doublereal time_curr, doublereal CJ, doublereal* const y, - doublereal* const ydot, int num_newt_its); + int beuler_jac(GeneralMatrix &J, doublereal * const f, + doublereal time_curr, doublereal CJ, doublereal * const y, + doublereal * const ydot, int num_newt_its); //! Apply a filtering process to the step /*! @@ -448,7 +450,7 @@ public: * * @return Returns the norm of the value of the amount filtered */ - doublereal filterNewStep(const doublereal timeCurrent, const doublereal* const ybase, doublereal* const step0); + doublereal filterNewStep(const doublereal timeCurrent, const doublereal * const ybase, doublereal * const step0); //! Apply a filter to the solution /*! @@ -458,8 +460,8 @@ public: * * @return Returns the norm of the value of the amount filtered */ - doublereal filterNewSolution(const doublereal timeCurrent, doublereal* const y_current, - doublereal* const ydot_current); + doublereal filterNewSolution(const doublereal timeCurrent, doublereal * const y_current, + doublereal * const ydot_current); //! Return the factor by which the undamped Newton step 'step0' //! must be multiplied in order to keep the update within the bounds of an accurate jacobian. @@ -477,8 +479,8 @@ public: * * @return returns the damping factor */ - doublereal deltaBoundStep(const doublereal* const y, const doublereal* const step0); - + doublereal deltaBoundStep(const doublereal * const y, const doublereal * const step0); + //! Find a damping coefficient through a look-ahead mechanism /*! * On entry, step_1 must contain an undamped Newton step for the @@ -490,9 +492,9 @@ public: * returned in step_2. * * @param time_curr Current physical time - * @param y_n_curr Base value of the solution before any steps + * @param y_n_curr Base value of the solution before any steps * are taken - * @param ydot_n_curr Base value of the time derivative of the + * @param ydot_n_curr Base value of the time derivative of teh * solution * @param step_1 Initial step suggested. * @param y_n_1 Value of y1, the suggested solution after damping @@ -505,13 +507,13 @@ public: * * @return returns an integer indicating what happened. */ - int dampStep(const doublereal time_curr, const doublereal* const y_n_curr, - const doublereal* const ydot_n_curr, doublereal* const step_1, - doublereal* const y_n_1, doublereal* const ydot_n_1, doublereal* step_2, - doublereal& stepNorm_2, GeneralMatrix& jac, bool writetitle, - int& num_backtracks); + int dampStep(const doublereal time_curr, const doublereal * const y_n_curr, + const doublereal * const ydot_n_curr, doublereal * const step_1, + doublereal * const y_n_1, doublereal * const ydot_n_1, doublereal * step_2, + doublereal & stepNorm_2, GeneralMatrix& jac, bool writetitle, + int& num_backtracks); - //! Find the solution to F(X) = 0 by damped Newton iteration. + //! Find the solution to F(X) = 0 by damped Newton iteration. /*! * On * entry, x0 contains an initial estimate of the solution. On @@ -529,7 +531,7 @@ public: * @param CJ Inverse of the value of deltaT * @param time_curr Current value of the time * @param jac Matrix that will be used to store the jacobian - * @param num_newt_its Number of newton iterations taken + * @param num_newt_its Number of newton iterations taken * @param num_linear_solves Number of linear solves taken * @param num_backtracks Number of backtracking steps taken * @param loglevelInput Input log level determines the amount of printing. @@ -538,15 +540,15 @@ public: * @return A positive value indicates a successful convergence * -1 Failed convergence */ - int solve_nonlinear_problem(int SolnType, doublereal* const y_comm, doublereal* const ydot_comm, doublereal CJ, - doublereal time_curr, GeneralMatrix& jac, int& num_newt_its, - int& num_linear_solves, int& num_backtracks, int loglevelInput); + int solve_nonlinear_problem(int SolnType, doublereal * const y_comm, doublereal * const ydot_comm, doublereal CJ, + doublereal time_curr, GeneralMatrix & jac, int &num_newt_its, + int &num_linear_solves, int &num_backtracks, int loglevelInput); -private: + private: //! Set the column scales void calcColumnScales(); -public: + public: //! Set the column scaling that are used for the inversion of the matrix /*! @@ -556,19 +558,19 @@ public: * Then, the column scales will be set to the solution error weighting factors. This has the * effect of ensuring that all delta variables will have the same order of magnitude at convergence * end. - * - * The second way is the explicitly set the column factors in the second argument of this function call. + * + * The second way is the explicity set the column factors in the second argument of this function call. * * The final way to input the scales is to override the ResidJacEval member function call, * * calcSolnScales(double time_n, const double *m_y_n_curr, const double *m_y_nm1, double *m_colScales) * * Overriding this function call will trump all other ways to specify the column scaling factors. - * + * * @param useColScaling Turn this on if you want to use column scaling in the calculations * @param scaleFactors A vector of doubles that specifies the column factors. */ - void setColumnScaling(bool useColScaling, const double* const scaleFactors = 0); + void setColumnScaling(bool useColScaling, const double * const scaleFactors = 0); //! Set the rowscaling that are used for the inversion of the matrix @@ -587,8 +589,8 @@ public: * @param time_curr current value of the time * @param num_newt_its Current value of the number of newt its */ - void scaleMatrix(GeneralMatrix& jac, doublereal* const y_comm, doublereal* const ydot_comm, - doublereal time_curr, int num_newt_its); + void scaleMatrix(GeneralMatrix& jac, doublereal * const y_comm, doublereal * const ydot_comm, + doublereal time_curr, int num_newt_its); //! Print solution norm contribution /*! @@ -605,10 +607,10 @@ public: * @param num_entries Number of entries to print out */ void - print_solnDelta_norm_contrib(const doublereal* const step_1, const char* const stepNorm_1, - const doublereal* const step_2, const char* const stepNorm_2, - const char* const title, const doublereal* const y_n_curr, - const doublereal* const y_n_1, doublereal damp, size_t num_entries); + print_solnDelta_norm_contrib(const doublereal * const step_1, const char * const stepNorm_1, + const doublereal * const step_2, const char * const stepNorm_2, + const char * const title, const doublereal * const y_n_curr, + const doublereal * const y_n_1, doublereal damp, int num_entries); //! Compute the Residual Weights /*! @@ -627,9 +629,9 @@ public: /*! * @param residWts Vector of length neq_ */ - void getResidWts(doublereal* const residWts) const; - + void getResidWts(doublereal * const residWts) const; + //! Check to see if the nonlinear problem has converged /*! @@ -655,7 +657,7 @@ public: * * @param atol Vector of length neq_ that contains the tolerances to be used for the solution variables */ - void setAtol(const doublereal* const atol); + void setAtol(const doublereal * const atol); //! Set the relative tolerances for the solution variables /*! @@ -680,9 +682,12 @@ public: * and the residual norms are converging at the same time and thus accounts for some-illconditioning issues * but not all. * + * With this routine the user can override or add to the residual weighting norm evaluation by specifying + * their own vector of residual absolute and relative tolerances. + * * The user specified tolerance for the residual is given by the following quantity * - * residWeightNorm[i] = residAtol[i] + residRtol * m_rowWtScales[i] / neq + * residWeightNorm[i] = residAtol[i] + residRtol * m_rowWtScales[i] / neq * * @param residNormHandling Parameter that sets the default handling of the residual norms * 0 The residual weighting vector is calculated to make sure that the solution @@ -692,7 +697,7 @@ public: * 2 Use the minimum value of the residual weights calculcated by method 1 and 2. * This is the default if this routine is called and this parameter isn't specified. */ - void setResidualTols(double residRtol, double* residATol, int residNormHandling = 2); + void setResidualTols(double residRtol, double * residATol, int residNormHandling = 2); //! Set the value of the maximum # of newton iterations /*! @@ -709,7 +714,7 @@ public: */ void calcSolnToResNormVector(); - //! Calculate the steepest descent direction and the Cauchy Point where the quadratic formulation + //! Calculate the steepest descent direction and the Cauchy Point where the quadratic formulation //! of the nonlinear problem expects a minimum along the descent direction. /*! * @param jac Jacobian matrix: must be unfactored. @@ -737,12 +742,12 @@ public: * * @param time_curr Current time * @param ydot0 INPUT Current value of the derivative of the solution vector - * @param ydot1 INPUT Time derivatives of solution at the conditions which are evaluated for success + * @param ydot1 INPUT Time derivates of solution at the conditions which are evalulated for success * @param numTrials OUTPUT Counter for the number of residual evaluations */ - void descentComparison(doublereal time_curr ,doublereal* ydot0, doublereal* ydot1, int& numTrials); - + void descentComparison(doublereal time_curr ,doublereal * ydot0, doublereal * ydot1, int &numTrials); + //! Setup the parameters for the double dog leg /*! * The calls to the doCauchySolve() and doNewtonSolve() routines are done at the main level. This routine comes @@ -758,7 +763,7 @@ public: * * @return Returns the leg number ( 0, 1, or 2). */ - int lambdaToLeg(const doublereal lambda, doublereal& alpha) const; + int lambdaToLeg(const doublereal lambda, doublereal &alpha) const; //! Given a trust distance, this routine calculates the intersection of the this distance with the //! double dogleg curve @@ -768,7 +773,7 @@ public: * @param alpha (OUTPUT) Returns the relative distance along the appropriate leg * @return leg (OUTPUT) Returns the leg ID (0, 1, or 2) */ - int calcTrustIntersection(doublereal trustVal, doublereal& lambda, doublereal& alpha) const; + int calcTrustIntersection(doublereal trustVal, doublereal &lambda, doublereal &alpha) const; //! Initialize the size of the trust vector. /*! @@ -787,7 +792,7 @@ public: * 2 Factor of the first Cauchy Point distance * 3 Factor of the first Newton step distance * - * @param factor Factor to use in combination with the method + * @param factor Factor to use in combination with the method * */ void setTrustRegionInitializationMethod(int method, doublereal factor); @@ -795,7 +800,7 @@ public: //! Damp using the dog leg approach /*! - * + * * @param time_curr INPUT Current value of the time * @param y_n_curr INPUT Current value of the solution vector * @param ydot_n_curr INPUT Current value of the derivative of the solution vector @@ -817,10 +822,10 @@ public: * 0 Uncertain Success: s1 is about the same as s0 * -2 Unsuccessful step. */ - int dampDogLeg(const doublereal time_curr, const doublereal* y_n_curr, - const doublereal* ydot_n_curr, std::vector & step_1, - doublereal* const y_n_1, doublereal* const ydot_n_1, - doublereal& stepNorm_1, doublereal& stepNorm_2, GeneralMatrix& jac, int& num_backtracks); + int dampDogLeg(const doublereal time_curr, const doublereal* y_n_curr, + const doublereal *ydot_n_curr, std::vector & step_1, + doublereal* const y_n_1, doublereal* const ydot_n_1, + doublereal& stepNorm_1, doublereal& stepNorm_2, GeneralMatrix& jac, int& num_backtracks); //! Decide whether the current step is acceptable and adjust the trust region size /*! @@ -835,8 +840,8 @@ public: * @param y_n_curr INPUT Current value of the solution vector * @param ydot_n_curr INPUT Current value of the derivative of the solution vector * @param step_1 INPUT Trial step - * @param y_n_1 OUTPUT Solution values at the conditions which are evaluated for success - * @param ydot_n_1 OUTPUT Time derivatives of solution at the conditions which are evaluated for success + * @param y_n_1 OUTPUT Solution values at the conditions which are evalulated for success + * @param ydot_n_1 OUTPUT Time derivates of solution at the conditions which are evalulated for success * @param trustDeltaOld INPUT Value of the trust length at the old conditions * * @@ -846,15 +851,15 @@ public: * 0 The step passed. * -1 The step size is now too small (||d || < 0.1). A really small step isn't decreasing the function. * This is an error condition. - * -2 Current value of the solution vector caused a residual error in its evaluation. + * -2 Current value of the solution vector caused a residual error in its evaluation. * Step is a failure, and the step size must be reduced in order to proceed further. */ - int decideStep(const doublereal time_curr, int leg, doublereal alpha, const doublereal* const y_n_curr, - const doublereal* const ydot_n_curr, - const std::vector & step_1, - const doublereal* const y_n_1, const doublereal* const ydot_n_1, doublereal trustDeltaOld); + int decideStep(const doublereal time_curr, int leg, doublereal alpha, const doublereal * const y_n_curr, + const doublereal * const ydot_n_curr, + const std::vector & step_1, + const doublereal * const y_n_1, const doublereal * const ydot_n_1, doublereal trustDeltaOld); - //! Calculated the expected residual along the double dogleg curve. + //! Calculated the expected residual along the double dogleg curve. /*! * @param leg 0, 1, or 2 representing the curves of the dogleg * @param alpha Relative distance along the particular curve. @@ -873,12 +878,12 @@ public: * @param legBest OUTPUT leg of the dogleg that gives the lowest residual * @param alphaBest OUTPUT distance along dogleg for best result. */ - void residualComparisonLeg(const doublereal time_curr, const doublereal* const ydot0, int& legBest, - doublereal& alphaBest) const; + void residualComparisonLeg(const doublereal time_curr, const doublereal * const ydot0, int & legBest, + doublereal & alphaBest) const; //! Set the print level from the nonlinear solver /*! - * + * * 0 -> absolutely nothing is printed for a single time step. * 1 -> One line summary per solve_nonlinear call * 2 -> short description, points of interest: Table of nonlinear solve - one line per iteration @@ -912,21 +917,21 @@ public: * MEMBER DATA * ------------------------------------------------------------------------------------------------ */ -private: + private: - //! Pointer to the residual and jacobian evaluator for the + //! Pointer to the residual and jacobian evaluator for the //! function /*! * See ResidJacEval.h for an evaluator. */ - ResidJacEval* m_func; + ResidJacEval *m_func; //! Solution type int solnType_; //! Local copy of the number of equations - size_t neq_; - + int neq_; + //! Soln error weights std::vector m_ewt; @@ -970,7 +975,7 @@ private: //! Weights for normalizing the values of the residuals /*! - * They are calculated as the sum of the absolute values of the jacobian + * They are calculated as the sum of the absolute values of the jacobian * multiplied by the solution weight function. * This is carried out in scaleMatrix(). */ @@ -997,7 +1002,7 @@ private: //! Norm of the residual at the start of each nonlinear iteration doublereal m_normResid_0; - //! Norm of the residual after it has been bounded + //! Norm of the residual after it has been bounded doublereal m_normResid_Bound; //! Norm of the residual at the end of the first leg of the current iteration @@ -1067,8 +1072,10 @@ private: //! Total number of newton iterations int m_numTotalNewtIts; + public: //! Minimum number of newton iterations to use int m_min_newt_its; + private: //! Maximum number of newton iterations int maxNewtIts_; @@ -1086,14 +1093,14 @@ private: //! Current system time /*! * Note, we assume even for steady state problems that the residual - * is a function of a system time. + * is a function of a system time. */ doublereal time_n; //! Boolean indicating matrix conditioning int m_matrixConditioning; - //! Order of the time step method = 1 + //! Order of the time step method = 1 int m_order; //! value of the relative tolerance to use in solving the equation set @@ -1103,7 +1110,7 @@ private: doublereal atolBase_; //! Pointer containing the solution derivative at the previous time step - doublereal* m_ydot_nm1; + doublereal *m_ydot_nm1; //! absolute tolerance in the solution unknown /*! @@ -1132,8 +1139,10 @@ private: * 2 -> short description, points of interest: Table of nonlinear solve - one line per iteration * 3 -> Table is included -> More printing per nonlinear iteration (default) that occurs during the table * 4 -> Summaries of the nonlinear solve iteration as they are occurring -> table no longer printed + * Base_ShowSolution Residual called for residual printing at the end of convergence. * 5 -> Algorithm information on the nonlinear iterates are printed out * 6 -> Additional info on the nonlinear iterates are printed out + * Base_ShowSolution Residual called for residual printing at the end of each step. * 7 -> Additional info on the linear solve is printed out. * 8 -> Info on a per iterate of the linear solve is printed out. */ @@ -1144,12 +1153,12 @@ private: //! Copy of the jacobian that doesn't get overwritten when the inverse is determined /*! - * The jacobian stored here is the raw matrix, before any row or column scaling is carried out + * The jacobian storred here is the raw matrix, before any row or column scaling is carried out */ - Cantera::GeneralMatrix* jacCopyPtr_; + Cantera::GeneralMatrix * jacCopyPtr_; //! Hessian - Cantera::GeneralMatrix* HessianPtr_; + Cantera::GeneralMatrix * HessianPtr_; /********************************************************************************************* * VARIABLES ASSOCIATED WITH STEPS AND ASSOCIATED DOUBLE DOGLEG PARAMETERS @@ -1176,16 +1185,16 @@ private: //! Residual dot Jd norm /*! - * This is equal to R_hat dot J_hat d_y_descent + * This is equal to R_hat dot J_hat d_y_descent */ doublereal RJd_norm_; //! Value of lambdaStar_ which is used to calculate the Cauchy point doublereal lambdaStar_; - //! Jacobian times the steepest descent direction in the normalized coordinates. + //! Jacobian times the steepest descent direction in the normalized coordinates. /*! - * This is equal to [ Jhat d^y_{descent} ] in the notes, Eqn. 18. + * This is equal to [ Jhat d^y_{descent} ] in the notes, Eqn. 18. */ std::vector Jd_; @@ -1195,7 +1204,7 @@ private: //! Current norm of the vector deltaX_trust_ in terms of the solution norm mutable doublereal norm_deltaX_trust_; - //! Current value of trust radius. This is used with deltaX_trust_ to + //! Current value of trust radius. This is used with deltaX_trust_ to //! calculate the max step size. doublereal trustDelta_; @@ -1253,7 +1262,7 @@ private: //! Factor indicating how much trust region has been changed next iteration - output variable doublereal NextTrustFactor_; - //! Boolean indicating that the residual weights have been reevaluated this iteration - output variable + //! Boolean indicating that the residual weights have been reevalulated this iteration - output variable bool ResidWtsReevaluated_; //! Expected DResid_dS for the steepest descent path - output variable @@ -1272,7 +1281,7 @@ private: * STATIC VARIABLES *****************************************************************************************/ -public: + public: //! Turn off printing of time /*! * Necessary to do for test suites @@ -1297,7 +1306,7 @@ public: */ static bool s_alwaysAssumeNewtonGood; -}; + }; } diff --git a/include/cantera/transport/DustyGasTransport.h b/include/cantera/transport/DustyGasTransport.h index 40c828bad..331723192 100644 --- a/include/cantera/transport/DustyGasTransport.h +++ b/include/cantera/transport/DustyGasTransport.h @@ -100,7 +100,23 @@ public: * These routines are basically wrappers around the derived copy * constructor. */ - virtual Transport* duplMyselfAsTransport() const; + virtual Transport *duplMyselfAsTransport() const; + + //! Specifies the %ThermPhase object. + /*! + * We have relaxed this operation so that it will succeed when + * the underlying old and new ThermoPhase objects have the same + * number of species and the same names of the species in the + * same order. The idea here is to allow copy constructors and duplicators + * to work. In order for them to work, we need a method to switch the + * internal pointer within the Transport object after the duplication + * takes place. Also, different thermodynamic instanteations of the same + * species should also work. + * + * @param thermo Reference to the ThermoPhase object that + * the transport object will use + */ + virtual void setThermo(thermo_t& thermo); //--------------------------------------------------------- // overloaded base class methods diff --git a/include/cantera/transport/LTPspecies.h b/include/cantera/transport/LTPspecies.h index b78f7dc31..bfff44e48 100644 --- a/include/cantera/transport/LTPspecies.h +++ b/include/cantera/transport/LTPspecies.h @@ -45,7 +45,9 @@ enum TransportPropertyType { TP_THERMALCOND, TP_DIFFUSIVITY, TP_HYDRORADIUS, - TP_ELECTCOND + TP_ELECTCOND, + TP_DEFECTCONC, + TP_DEFECTDIFF }; //==================================================================================================================== @@ -96,10 +98,10 @@ public: * @param tp_ind enum TransportPropertyType containing the property id that this object * is creating a parameterization for (e.g., viscosity) * @param thermo const pointer to the ThermoPhase object, which is used to find the temperature. - */ - LTPspecies(const XML_Node* const propNode = 0, const std::string& name = "-", - TransportPropertyType tp_ind = TP_UNKNOWN, const thermo_t* thermo = 0); - + */ + LTPspecies(const XML_Node * const propNode = 0, const std::string name = "-", + TransportPropertyType tp_ind = TP_UNKNOWN, const thermo_t* thermo = 0); + //! Copy constructor /*! * @param right Object to be copied @@ -224,10 +226,10 @@ public: * @param tp_ind enum TransportPropertyType containing the property id that this object * is creating a parameterization for (e.g., viscosity) * @param thermo const pointer to the ThermoPhase object, which is used to find the temperature. - */ - LTPspecies_Const(const XML_Node& propNode, const std::string& name, - TransportPropertyType tp_ind, const thermo_t* const thermo); - + */ + LTPspecies_Const(const XML_Node &propNode, const std::string name, + TransportPropertyType tp_ind, const thermo_t * const thermo); + //! Copy constructor /*! * @param right Object to be copied @@ -308,10 +310,11 @@ public: * is creating a parameterization for (e.g., viscosity) * @param thermo const pointer to the ThermoPhase object, which is used to find the temperature. * - */ - LTPspecies_Arrhenius(const XML_Node& propNode, const std::string& name, - TransportPropertyType tp_ind, const thermo_t* thermo); + */ + LTPspecies_Arrhenius(const XML_Node &propNode, const std::string name, + TransportPropertyType tp_ind, const thermo_t * thermo); + //! Copy constructor /*! * @param right Object to be copied @@ -415,9 +418,10 @@ public: * is creating a parameterization for (e.g., viscosity) * @param thermo const pointer to the ThermoPhase object, which is used to find the temperature. * - */ - LTPspecies_Poly(const XML_Node& propNode, const std::string& name, TransportPropertyType tp_ind, const thermo_t* thermo); + */ + LTPspecies_Poly(const XML_Node &propNode, const std::string name, TransportPropertyType tp_ind, const thermo_t * thermo); + //! Copy constructor /*! * @param right Object to be copied @@ -503,9 +507,10 @@ public: * is creating a parameterization for (e.g., viscosity) * @param thermo const pointer to the ThermoPhase object, which is used to find the temperature. * - */ - LTPspecies_ExpT(const XML_Node& propNode, const std::string& name, - TransportPropertyType tp_ind, const thermo_t* thermo); + */ + LTPspecies_ExpT(const XML_Node &propNode, const std::string name, + TransportPropertyType tp_ind, const thermo_t* thermo); + //! Copy constructor /*! diff --git a/include/cantera/transport/SolidTransport.h b/include/cantera/transport/SolidTransport.h index 0627f294b..6e0c09246 100644 --- a/include/cantera/transport/SolidTransport.h +++ b/include/cantera/transport/SolidTransport.h @@ -18,6 +18,7 @@ #include // Cantera includes +#include "LTPspecies.h" #include "TransportBase.h" #include "cantera/numerics/DenseMatrix.h" @@ -62,14 +63,47 @@ public: */ virtual Transport* duplMyselfAsTransport() const; - virtual int model() const { return cSolidTransport; } + /** + * The ionic conducitivity in 1/ohm/m. + */ + virtual doublereal ionConductivity() ; + + + //! Returns the mixture thermal conductivity in W/m/K. + /*! + * Units are in W / m K or equivalently kg m / s3 K + * + * @return returns thermal conductivity in W/m/K. + */ virtual doublereal thermalConductivity(); + + /** + * The electrical conductivity (Siemens/m). + */ + virtual doublereal electricalConductivity(); + + /** + * The diffusivity of defects in the solid (m^2/s). + */ + virtual doublereal defectDiffusivity(); + + /** + * The activity of defects in the solid. + * At some point this should be variable and the diffusion coefficient should depend on it... + */ + virtual doublereal defectActivity(); + + + + + ///////////HEWSON WONDERS IF THE FOLLOWING ARE RELEVANT?? virtual void getMixDiffCoeffs(doublereal* const d); + //! Compute the electrical mobilities of the species from the diffusion coefficients, //! using the Einstein relation. /*! @@ -87,17 +121,72 @@ public: */ virtual void getMobilities(doublereal* const mobil); + //! Set model parameters for derived classes + /*! + * This method may be derived in subclasses to set model-specific parameters. + * The primary use of this class is to set parameters while in the middle of a calculation + * without actually having to dynamically cast the base Transport pointer. + * + * @param type Specifies the type of parameters to set + * 0 : Diffusion coefficient + * 1 : Thermal Conductivity + * The rest are currently unused. + * @param k Species index to set the parameters on + * @param p Vector of parameters. The length of the vector + * varies with the parameterization + */ virtual void setParameters(const int n, const int k, const doublereal* const p); friend class TransportFactory; - /** - * The electrical conductivity (Siemens/m). + protected: + + //! Initialize the transport object + /*! + * Here we change all of the internal dimensions to be sufficient. + * We get the object ready to do property evaluations. + * A lot of the input required to do property evaluations is + * contained in the SolidTransportParams class that is + * filled in TransportFactory. + * + * @param tr Transport parameters for all of the species + * in the phase. */ - virtual doublereal electricalConductivity(); + virtual bool initSolid(SolidTransportData& tr); -private: + private: + + + //! Model type for the ionic conductivity + /*! + * shallow pointer that should be zero during destructor + */ + LTPspecies* m_ionConductivity; + + //! Model type for the thermal conductivity + /*! + * shallow pointer that should be zero during destructor + */ + LTPspecies* m_thermalConductivity; + + //! Model type for the electrical conductivity + /*! + * shallow pointer that should be zero during destructor + */ + LTPspecies* m_electConductivity; + + //! Model type for the defectDiffusivity -- or more like a defect diffusivity in the context of the solid phase. + /*! + * shallow pointer that should be zero during destructor + */ + LTPspecies* m_defectDiffusivity; + + //! Model type for the defectActivity + /*! + * shallow pointer that should be zero during destructor + */ + LTPspecies* m_defectActivity; //! number of mobile species /*! diff --git a/include/cantera/transport/SolidTransportData.h b/include/cantera/transport/SolidTransportData.h new file mode 100644 index 000000000..67495cfdb --- /dev/null +++ b/include/cantera/transport/SolidTransportData.h @@ -0,0 +1,130 @@ +/** + * @file SolidTransportData.h + * Header file defining class SolidTransportData + */ +/* + * $Author: hkmoffa $ + * $Date: 2010-07-13 13:22:30 -0600 (Tue, 13 Jul 2010) $ + * $Revision: 507 $ + */ + +#ifndef CT_SOLIDTRANSPORTDATA_H +#define CT_SOLIDTRANSPORTDATA_H + + +// STL includes +#include +#include + +// Cantera includes +#include "cantera/base/ct_defs.h" +#include "cantera/transport/TransportBase.h" +#include "cantera/transport/TransportParams.h" +#include "cantera/base/FactoryBase.h" +#include "cantera/transport/LTPspecies.h" + +namespace Cantera { + + //! Class SolidTransportData holds transport parameters for a + //! specific solid-phase species. + /*! + * A SolidTransportData object is created for a solid phase + * (not for each species as happens for the analogous LiquidTransportData). + * + * This class is mainly used to collect transport properties + * from the parse phase in the TranportFactory and transfer + * them to the Transport class. Transport properties are + * expressed by subclasses of LTPspecies. + * Note that we use the liquid phase species model for the solid phases. + * That is, for the time being at least, we ignore mixing models for + * solid phases and just specify a transport property at the level + * that we specify the transport property for a species in the liquid phase. + * One may need to be careful about deleting pointers to LTPspecies + * objects created in the TransportFactory. + * + * All of the pointers in this class are shallow pointers. Therefore, this + * is a passthrough class, which keeps track of pointer ownership by zeroing + * pointers as we go. Yes, Yes, yes, this is not good. + */ + class SolidTransportData : public TransportParams { + + public: + + //! Default constructor + SolidTransportData(); + + //! Copy constructor + SolidTransportData(const SolidTransportData &right); + + //! Assignment operator + SolidTransportData& operator=(const SolidTransportData& right ); + + //! Destructor + ~SolidTransportData(); + + //! A SolidTransportData object is instantiated for each species. + //! This is the species name for which this object is instantiated. + std::string speciesName; + + //! Model type for the ionic conductivity + /*! + * shallow pointer that should be zero during destructor + */ + LTPspecies* ionConductivity; + + //! Model type for the thermal conductivity + /*! + * shallow pointer that should be zero during destructor + */ + LTPspecies* thermalConductivity; + + //! Model type for the electrical conductivity + /*! + * shallow pointer that should be zero during destructor + */ + LTPspecies* electConductivity; + + //! Model type for the defectDiffusivity -- or more like a defect diffusivity in the context of the solid phase. + /*! + * shallow pointer that should be zero during destructor + */ + LTPspecies* defectDiffusivity; + + //! Model type for the defectActivity + /*! + * shallow pointer that should be zero during destructor + */ + LTPspecies* defectActivity; + + protected: + //protected members of SolidTransportData are analogous to those found in TransportParams + + //! Local storage of the number of species + // int nsp_; + + //! Pointer to the ThermoPhase object + // thermo_t* thermo; + + //! Local storage of the molecular weights of the species + /*! + * Length is nsp_ and units are kg kmol-1. + */ + // vector_fp mw; + + //! Maximum temperatures for parameter fits + // doublereal tmax; + + //! Minimum temperatures for parameter fits + // doublereal tmin; + + //! Pointer to the xml tree describing the implementation of transport for this object + // XML_Writer* xml; + + //! Log level + // int log_level; + + }; + +} +#endif + diff --git a/include/cantera/transport/TransportBase.h b/include/cantera/transport/TransportBase.h index 5e424441d..bbf4a23e0 100644 --- a/include/cantera/transport/TransportBase.h +++ b/include/cantera/transport/TransportBase.h @@ -30,6 +30,7 @@ namespace Cantera class TransportParams; class GasTransportParams; class LiquidTransportParams; + class SolidTransportData; /*! * \addtogroup tranprops @@ -833,14 +834,40 @@ protected: return false; } - //! Specifies the %ThermPhase object. +public: + //! Called by TransportFactory to set parameters. /*! + * This is called by classes that use the solid phase parameter + * list to initialize themselves. + * + * @param tr Reference to the parameter list that will be used + * to initialize the class + */ + virtual bool initSolid(SolidTransportData& tr) + { + err("initSolid"); + return false; + } + + public: + //! Specifies the %ThermPhase object. + /*! + * We have relaxed this operation so that it will succeed when + * the underlying old and new ThermoPhase objects have the same + * number of species and the same names of the species in the + * same order. The idea here is to allow copy constructors and duplicators + * to work. In order for them to work, we need a method to switch the + * internal pointer within the Transport object after the duplication + * takes place. Also, different thermodynamic instanteations of the same + * species should also work. + * * @param thermo Reference to the ThermoPhase object that * the transport object will use - */ - void setThermo(thermo_t& thermo); + */ + virtual void setThermo(thermo_t& thermo); +protected: //! Enable the transport object for use. /*! * Once finalize() has been called, the diff --git a/include/cantera/transport/TransportFactory.h b/include/cantera/transport/TransportFactory.h index dd99b6b4e..b85a8bdba 100644 --- a/include/cantera/transport/TransportFactory.h +++ b/include/cantera/transport/TransportFactory.h @@ -18,6 +18,7 @@ #include "TransportBase.h" #include "cantera/base/FactoryBase.h" #include "LiquidTransportParams.h" +#include "SolidTransportData.h" //====================================================================================================================== namespace Cantera @@ -78,6 +79,9 @@ public: virtual ~TransportFactory() {} //! Get the name of the transport model corresponding to the specified constant. + /*! + * @param model Integer representing the model name + */ static std::string modelName(int model); //! Make one of several transport models, and return a base class pointer to it. @@ -90,8 +94,9 @@ public: * @param tp_ind TransportPropertyType class * @param thermo Pointer to the %ThermoPhase class */ - virtual LTPspecies* newLTP(const XML_Node& trNode, std::string& name, - TransportPropertyType tp_ind, thermo_t* thermo); + + virtual LTPspecies* newLTP(const XML_Node &trNode, const std::string &name, + TransportPropertyType tp_ind, thermo_t* thermo); //! Factory function for the construction of new LiquidTranInteraction @@ -164,6 +169,26 @@ public: private: + + //! Initialize an existing transport manager for solid phase + /*! + * This routine sets up an existing solid-phase transport manager. + * It is similar to initTransport except that it uses the SolidTransportData + * class and calls setupSolidTransport(). + * + * @param tr Pointer to the Transport manager + * @param thermo Pointer to the ThermoPhase object + * @param log_level Defaults to zero, no logging + * + * In DEBUG_MODE, this routine will create the file transport_log.xml + * and write informative information to it. + */ + virtual void initSolidTransport(Transport* tr, thermo_t* thermo, int log_level=0); + + + private: + + //! Static instance of the factor -> This is the only instance of this //! object allowed static TransportFactory* s_factory; @@ -239,6 +264,22 @@ private: void getLiquidInteractionsTransportData(const XML_Node& phaseTran_db, XML_Node& log, const std::vector& names, LiquidTransportParams& tr); + + //! Read transport property data from a file for a solid phase + /*! + * Given a phase XML data base, this method constructs the + * SolidTransportData object containing the transport data for the phase. + * + * @param db Reference to XML_Node containing the phase. + * @param log Reference to an XML log file. (currently unused) + * @param tr Reference to the SolidTransportData object that will contain the results. + */ + void getSolidTransportData(const XML_Node &transportNode, + XML_Node& log, + const std::string phaseName, + SolidTransportData& tr); + + //! Generate polynomial fits to the viscosity, conductivity, and //! the binary diffusion coefficients /*! @@ -307,6 +348,15 @@ private: */ void setupLiquidTransport(std::ostream& flog, thermo_t* thermo, int log_level, LiquidTransportParams& trParam); + //! Prepare to build a new transport manager for solids + /*! + * @param flog Reference to the ostream for writing log info + * @param thermo Pointer to the %ThermoPhase object + * @param log_level log level + * @param trParam SolidTransportData structure to be filled up with information + */ + void setupSolidTransport(std::ostream &flog, thermo_t* thermo, int log_level, SolidTransportData& trParam); + //! Second-order correction to the binary diffusion coefficients /*! diff --git a/src/clib/ctsurf.cpp b/src/clib/ctsurf.cpp index ec511b3c4..274fb9545 100644 --- a/src/clib/ctsurf.cpp +++ b/src/clib/ctsurf.cpp @@ -8,7 +8,7 @@ // Cantera includes #include "cantera/thermo/SurfPhase.h" #include "cantera/kinetics/InterfaceKinetics.h" -#include "kinetics/ImplicitSurfChem.h" +#include "cantera/kinetics/ImplicitSurfChem.h" #include "Cabinet.h" using namespace std; diff --git a/src/equil/MultiPhase.cpp b/src/equil/MultiPhase.cpp index 75e7c62d0..c092667f7 100644 --- a/src/equil/MultiPhase.cpp +++ b/src/equil/MultiPhase.cpp @@ -20,8 +20,8 @@ namespace Cantera // Constructor. MultiPhase::MultiPhase() : m_np(0), - m_temp(0.0), - m_press(0.0), + m_temp(298.15), + m_press(OneBar), m_nel(0), m_nsp(0), m_init(false), @@ -37,8 +37,8 @@ MultiPhase::MultiPhase() : */ MultiPhase::MultiPhase(const MultiPhase& right) : m_np(0), - m_temp(0.0), - m_press(0.0), + m_temp(298.15), + m_press(OneBar), m_nel(0), m_nsp(0), m_init(false), @@ -160,8 +160,8 @@ addPhase(ThermoPhase* p, doublereal moles) // If the mixture temperature hasn't been set, then set the // temperature and pressure to the values for the phase being - // added. - if (m_temp == 0.0 && p->temperature() > 0.0) { + // added. There is no good way to do this. However, this will be overridden later. + if (m_temp == 298.15 && p->temperature() > 2.0E-3) { m_temp = p->temperature(); m_press = p->pressure(); } diff --git a/src/equil/vcs_MultiPhaseEquil.cpp b/src/equil/vcs_MultiPhaseEquil.cpp index 3b26d03a2..47a1d482b 100644 --- a/src/equil/vcs_MultiPhaseEquil.cpp +++ b/src/equil/vcs_MultiPhaseEquil.cpp @@ -12,8 +12,7 @@ #include "cantera/equil/vcs_prob.h" #include "cantera/equil/vcs_internal.h" #include "cantera/equil/vcs_VolPhase.h" -#include "vcs_species_thermo.h" -#include "vcs_SpeciesProperties.h" +#include "cantera/equil/vcs_species_thermo.h" #include "cantera/equil/vcs_solve.h" @@ -26,6 +25,7 @@ #include "cantera/thermo/IdealSolidSolnPhase.h" #include "cantera/thermo/IdealMolalSoln.h" #include "cantera/equil/ChemEquil.h" +#include "cantera/equil/vcs_SpeciesProperties.h" #include #include diff --git a/src/equil/vcs_SpeciesProperties.cpp b/src/equil/vcs_SpeciesProperties.cpp index 386d7aad7..1e279a570 100644 --- a/src/equil/vcs_SpeciesProperties.cpp +++ b/src/equil/vcs_SpeciesProperties.cpp @@ -2,9 +2,9 @@ * @file vcs_SpeciesProperties.cpp */ #include "cantera/equil/vcs_defs.h" -#include "vcs_SpeciesProperties.h" +#include "cantera/equil/vcs_SpeciesProperties.h" #include "cantera/equil/vcs_VolPhase.h" -#include "vcs_species_thermo.h" +#include "cantera/equil/vcs_species_thermo.h" #include "cantera/equil/vcs_internal.h" #include diff --git a/src/equil/vcs_TP.cpp b/src/equil/vcs_TP.cpp index 77b0ab8fe..c7be748b1 100644 --- a/src/equil/vcs_TP.cpp +++ b/src/equil/vcs_TP.cpp @@ -1,6 +1,6 @@ #include "cantera/equil/vcs_solve.h" #include "cantera/equil/vcs_internal.h" -#include "vcs_species_thermo.h" +#include "cantera/equil/vcs_species_thermo.h" #include "cantera/equil/vcs_VolPhase.h" #include diff --git a/src/equil/vcs_VolPhase.cpp b/src/equil/vcs_VolPhase.cpp index ac98b79e0..bdd86bcaf 100644 --- a/src/equil/vcs_VolPhase.cpp +++ b/src/equil/vcs_VolPhase.cpp @@ -8,8 +8,8 @@ */ #include "cantera/equil/vcs_VolPhase.h" #include "cantera/equil/vcs_internal.h" -#include "vcs_SpeciesProperties.h" -#include "vcs_species_thermo.h" +#include "cantera/equil/vcs_SpeciesProperties.h" +#include "cantera/equil/vcs_species_thermo.h" #include "cantera/equil/vcs_solve.h" #include "cantera/thermo/ThermoPhase.h" diff --git a/src/equil/vcs_equilibrate.cpp b/src/equil/vcs_equilibrate.cpp index e6053a539..07e2f4368 100644 --- a/src/equil/vcs_equilibrate.cpp +++ b/src/equil/vcs_equilibrate.cpp @@ -11,8 +11,8 @@ #include "cantera/equil/vcs_prob.h" #include "cantera/equil/vcs_internal.h" #include "cantera/equil/vcs_VolPhase.h" -#include "vcs_species_thermo.h" -#include "vcs_SpeciesProperties.h" +#include "cantera/equil/vcs_species_thermo.h" +#include "cantera/equil/vcs_SpeciesProperties.h" #include "cantera/equil/vcs_VolPhase.h" #include "cantera/equil/vcs_solve.h" #include "cantera/equil/equil.h" diff --git a/src/equil/vcs_phaseStability.cpp b/src/equil/vcs_phaseStability.cpp index 3298f30ca..36e3d7530 100644 --- a/src/equil/vcs_phaseStability.cpp +++ b/src/equil/vcs_phaseStability.cpp @@ -5,7 +5,7 @@ */ #include "cantera/equil/vcs_solve.h" #include "cantera/equil/vcs_internal.h" -#include "vcs_species_thermo.h" +#include "cantera/equil/vcs_species_thermo.h" #include "cantera/equil/vcs_VolPhase.h" #include diff --git a/src/equil/vcs_prep.cpp b/src/equil/vcs_prep.cpp index c1f4f69c4..7dc3e9fc1 100644 --- a/src/equil/vcs_prep.cpp +++ b/src/equil/vcs_prep.cpp @@ -13,7 +13,7 @@ #include "cantera/equil/vcs_internal.h" #include "cantera/equil/vcs_prob.h" #include "cantera/equil/vcs_VolPhase.h" -#include "vcs_SpeciesProperties.h" +#include "cantera/equil/vcs_SpeciesProperties.h" #include #include diff --git a/src/equil/vcs_prob.cpp b/src/equil/vcs_prob.cpp index 53416749b..66a3e632e 100644 --- a/src/equil/vcs_prob.cpp +++ b/src/equil/vcs_prob.cpp @@ -11,7 +11,7 @@ #include "cantera/equil/vcs_prob.h" #include "cantera/equil/vcs_VolPhase.h" -#include "vcs_species_thermo.h" +#include "cantera/equil/vcs_species_thermo.h" #include "cantera/equil/vcs_internal.h" #include "cantera/thermo/ThermoPhase.h" diff --git a/src/equil/vcs_rank.cpp b/src/equil/vcs_rank.cpp new file mode 100644 index 000000000..8a292e9b3 --- /dev/null +++ b/src/equil/vcs_rank.cpp @@ -0,0 +1,348 @@ + +/*! + * @file vcs_rank.cpp + * Header file for the internal class that holds the problem. + */ +/* + * $Id: vcs_solve.cpp 735 2011-07-25 14:44:41Z hkmoffa $ + */ +/* + * Copywrite (2005) Sandia Corporation. Under the terms of + * Contract DE-AC04-94AL85000 with Sandia Corporation, the + * U.S. Government retains certain rights in this software. + */ + + +#include "cantera/equil/vcs_solve.h" +#include "cantera/equil/vcs_internal.h" +#include "cantera/equil/vcs_prob.h" + +#include "cantera/equil/vcs_VolPhase.h" +#include "cantera/equil/vcs_SpeciesProperties.h" +#include "cantera/equil/vcs_species_thermo.h" + +#include "cantera/base/clockWC.h" +#include "cantera/base/ctexceptions.h" + +#include +#include +#include "math.h" +using namespace std; + +namespace VCSnonideal { + //==================================================================================================================== + static int basisOptMax1(const double * const molNum, + const int n) { + // int largest = 0; + + for (int i = 0; i < n; ++i) { + + if (molNum[i] > -1.0E200 && fabs(molNum[i]) > 1.0E-13) { + return i; + } + } + for (int i = 0; i < n; ++i) { + + if (molNum[i] > -1.0E200) { + return i; + } + } + return n-1; + } + //==================================================================================================================== + // Calculate the rank of a matrix and return the rows and columns that will generate an independent basis + // for that rank + /* + * Choose the optimum component species basis for the calculations, finding the rank and + * set of linearly independent rows for that calculation. + * Then find the set of linearly indepedent element columns that can support that rank. + * This is done by taking the transpose of the matrix and redoing the same calculation. + * (there may be a better way to do this. I don't know.) + * + * + * Input + * --------- + * + * @param awtmp Vector of mole numbers which will be used to construct a + * ranking for how to pick the basis species. This is largely ignored + * here. + * + * @param numSpecies Number of species. This is the number of rows in the matrix. + * + * @param matrix Matrix. This is the formula matrix. Nominally, the rows are species, while + * the columns are element compositions. However, this routine + * is totally general, so that the rows and columns can be anything. + * + * @param numElemConstraints Number of element constraints + * + * Output + * --------- + * @param usedZeroedSpecies = If true, then a species with a zero concentration + * was used as a component. + * + * + * @param compRes Vector of rows which are linearly independent. (these are the components) + * + * @param elemComp Vector of columns which are linearly independent (These are the actionable element + * constraints). + * + * @return Returns number of components. This is the rank of the matrix + */ + int VCS_SOLVE::vcs_rank(const double * awtmp, size_t numSpecies, const double matrix[], size_t numElemConstraints, + std::vector &compRes, std::vector& elemComp, int * const usedZeroedSpecies) const + { + + int lindep; + size_t j, k, jl, i, l, ml; + int numComponents = 0; + + compRes.clear(); + elemComp.clear(); + vector sm(numElemConstraints*numSpecies); + vector sa(numSpecies); + vector ss(numSpecies); + + double test = -0.2512345E298; +#ifdef DEBUG_MODE + if (m_debug_print_lvl >= 2) { + plogf(" "); for(i=0; i<77; i++) plogf("-"); plogf("\n"); + plogf(" --- Subroutine vcs_rank called to "); + plogf("calculate the rank and independent rows /colums of the following matrix\n"); + if (m_debug_print_lvl >= 5) { + plogf(" --- Species | "); + for (j = 0; j < numElemConstraints; j++) { + plogf(" "); + plogf(" %3d ", j); + } + plogf("\n"); + plogf(" --- -----------"); + for (j = 0; j < numElemConstraints; j++) { + plogf("---------"); + } + plogf("\n"); + for (k = 0; k < numSpecies; k++) { + plogf(" --- "); + plogf(" %3d ", k); + plogf(" |"); + for (j = 0; j < numElemConstraints; j++) { + plogf(" %8.2g", matrix[j*numSpecies + k]); + } + plogf("\n"); + } + plogf(" ---"); + plogendl(); + } + } +#endif + + /* + * Calculate the maximum value of the number of components possible + * It's equal to the minimum of the number of elements and the + * number of total species. + */ + int ncTrial = std::min(numElemConstraints, numSpecies); + numComponents = ncTrial; + *usedZeroedSpecies = false; + + /* + * Use a temporary work array for the mole numbers, aw[] + */ + std::vector aw(numSpecies); + for (j = 0; j < numSpecies; j++) { + aw[j] = awtmp[j]; + } + + int jr = -1; + /* + * Top of a loop of some sort based on the index JR. JR is the + * current number of component species found. + */ + do { + ++jr; + /* - Top of another loop point based on finding a linearly */ + /* - independent species */ + do { + /* + * Search the remaining part of the mole number vector, AW, + * for the largest remaining species. Return its identity in K. + * The first search criteria is always the largest positive + * magnitude of the mole number. + */ + k = basisOptMax1(VCS_DATA_PTR(aw), numSpecies); + + if ((aw[k] != test) && fabs(aw[k]) == 0.0) { + *usedZeroedSpecies = true; + } + + + if (aw[k] == test) { + numComponents = jr; + + goto L_CLEANUP; + } + /* + * Assign a small negative number to the component that we have + * just found, in order to take it out of further consideration. + */ + aw[k] = test; + /* *********************************************************** */ + /* **** CHECK LINEAR INDEPENDENCE WITH PREVIOUS SPECIES ****** */ + /* *********************************************************** */ + /* + * Modified Gram-Schmidt Method, p. 202 Dalquist + * QR factorization of a matrix without row pivoting. + */ + jl = jr; + for (j = 0; j < numElemConstraints; ++j) { + sm[j + jr*numElemConstraints] = matrix[j*numSpecies + k]; + } + if (jl > 0) { + /* + * Compute the coefficients of JA column of the + * the upper triangular R matrix, SS(J) = R_J_JR + * (this is slightly different than Dalquist) + * R_JA_JA = 1 + */ + for (j = 0; j < jl; ++j) { + ss[j] = 0.0; + for (i = 0; i < numElemConstraints; ++i) { + ss[j] += sm[i + jr* numElemConstraints] * sm[i + j* numElemConstraints]; + } + ss[j] /= sa[j]; + } + /* + * Now make the new column, (*,JR), orthogonal to the + * previous columns + */ + for (j = 0; j < jl; ++j) { + for (l = 0; l < numElemConstraints; ++l) { + sm[l + jr*numElemConstraints] -= ss[j] * sm[l + j*numElemConstraints]; + } + } + } + /* + * Find the new length of the new column in Q. + * It will be used in the denominator in future row calcs. + */ + sa[jr] = 0.0; + for (ml = 0; ml < numElemConstraints; ++ml) { + sa[jr] += SQUARE(sm[ml + jr * numElemConstraints]); + } + /* **************************************************** */ + /* **** IF NORM OF NEW ROW .LT. 1E-3 REJECT ********** */ + /* **************************************************** */ + if (sa[jr] < 1.0e-6) lindep = true; + else lindep = false; + } while(lindep); + /* ****************************************** */ + /* **** REARRANGE THE DATA ****************** */ + /* ****************************************** */ + compRes.push_back(k); + elemComp.push_back(jr); + + } while (jr < (ncTrial-1)); + + L_CLEANUP: ; + + if (numComponents == ncTrial && numElemConstraints == numSpecies) { + return numComponents; + } + + + int numComponentsR = numComponents; + + ss.resize(numElemConstraints); + sa.resize(numElemConstraints); + + + elemComp.clear(); + + aw.resize(numElemConstraints); + for (j = 0; j < numSpecies; j++) { + aw[j] = 1.0; + } + + jr = -1; + + do { + ++jr; + + do { + + k = basisOptMax1(VCS_DATA_PTR(aw), numElemConstraints); + + if (aw[k] == test) { + numComponents = jr; + goto LE_CLEANUP; + } + aw[k] = test; + + + jl = jr; + for (j = 0; j < numSpecies; ++j) { + sm[j + jr*numSpecies] = matrix[k*numSpecies + j]; + } + if (jl > 0) { + + for (j = 0; j < jl; ++j) { + ss[j] = 0.0; + for (i = 0; i < numSpecies; ++i) { + ss[j] += sm[i + jr* numSpecies] * sm[i + j* numSpecies]; + } + ss[j] /= sa[j]; + } + + for (j = 0; j < jl; ++j) { + for (l = 0; l < numSpecies; ++l) { + sm[l + jr*numSpecies] -= ss[j] * sm[l + j*numSpecies]; + } + } + } + + sa[jr] = 0.0; + for (ml = 0; ml < numSpecies; ++ml) { + sa[jr] += SQUARE(sm[ml + jr * numSpecies]); + } + + if (sa[jr] < 1.0e-6) lindep = true; + else lindep = false; + } while(lindep); + + elemComp.push_back(k); + + } while (jr < (ncTrial-1)); + numComponents = jr; + LE_CLEANUP: ; + +#ifdef DEBUG_MODE + if (m_debug_print_lvl >= 2) { + plogf(" --- vcs_rank found rank %d\n", numComponents); + if (m_debug_print_lvl >= 5) { + if (compRes.size() == elemComp.size()) { + printf(" --- compRes elemComp\n"); + for (int i = 0; i < (int) compRes.size(); i++) { + printf(" --- %d %d \n", (int) compRes[i], (int) elemComp[i]); + } + } else { + for (int i = 0; i < (int) compRes.size(); i++) { + printf(" --- compRes[%d] = %d \n", (int) i, (int) compRes[i]); + } + for (int i = 0; i < (int) elemComp.size(); i++) { + printf(" --- elemComp[%d] = %d \n", (int) i, (int) elemComp[i]); + } + } + } + } +#endif + + if (numComponentsR != numComponents) { + printf("vcs_rank ERROR: number of components are different: %d %d\n", numComponentsR, numComponents); + throw Cantera::CanteraError("vcs_rank ERROR:", + " logical inconsistency"); + exit(-1); + } + return numComponents; + } + + +} diff --git a/src/equil/vcs_setMolesLinProg.cpp b/src/equil/vcs_setMolesLinProg.cpp index 033d74d87..193f82282 100644 --- a/src/equil/vcs_setMolesLinProg.cpp +++ b/src/equil/vcs_setMolesLinProg.cpp @@ -10,7 +10,7 @@ #include "cantera/equil/vcs_internal.h" #include "cantera/equil/vcs_VolPhase.h" -#include "vcs_species_thermo.h" +#include "cantera/equil/vcs_species_thermo.h" #include "cantera/equil/vcs_solve.h" #include diff --git a/src/equil/vcs_solve.cpp b/src/equil/vcs_solve.cpp index 3db3f2505..0df8e809d 100644 --- a/src/equil/vcs_solve.cpp +++ b/src/equil/vcs_solve.cpp @@ -15,8 +15,8 @@ #include "cantera/equil/vcs_prob.h" #include "cantera/equil/vcs_VolPhase.h" -#include "vcs_SpeciesProperties.h" -#include "vcs_species_thermo.h" +#include "cantera/equil/vcs_SpeciesProperties.h" +#include "cantera/equil/vcs_species_thermo.h" #include "cantera/base/clockWC.h" diff --git a/src/equil/vcs_solve_TP.cpp b/src/equil/vcs_solve_TP.cpp index 372399ad1..ec473cb68 100644 --- a/src/equil/vcs_solve_TP.cpp +++ b/src/equil/vcs_solve_TP.cpp @@ -16,7 +16,7 @@ #include "cantera/equil/vcs_solve.h" #include "cantera/equil/vcs_internal.h" #include "cantera/equil/vcs_VolPhase.h" -#include "vcs_species_thermo.h" +#include "cantera/equil/vcs_species_thermo.h" #include "cantera/base/ctexceptions.h" #include "cantera/base/clockWC.h" diff --git a/src/equil/vcs_solve_phaseStability.cpp b/src/equil/vcs_solve_phaseStability.cpp index 256696184..a2871e77f 100644 --- a/src/equil/vcs_solve_phaseStability.cpp +++ b/src/equil/vcs_solve_phaseStability.cpp @@ -17,7 +17,7 @@ #include "cantera/equil/vcs_solve.h" #include "cantera/equil/vcs_internal.h" #include "cantera/equil/vcs_VolPhase.h" -#include "vcs_species_thermo.h" +#include "cantera/equil/vcs_species_thermo.h" #include "cantera/equil/vcs_prob.h" #include "cantera/base/clockWC.h" diff --git a/src/equil/vcs_species_thermo.cpp b/src/equil/vcs_species_thermo.cpp index 6644c34b9..aaca0f416 100644 --- a/src/equil/vcs_species_thermo.cpp +++ b/src/equil/vcs_species_thermo.cpp @@ -11,7 +11,7 @@ #include "cantera/equil/vcs_solve.h" -#include "vcs_species_thermo.h" +#include "cantera/equil/vcs_species_thermo.h" #include "cantera/equil/vcs_defs.h" #include "cantera/equil/vcs_VolPhase.h" diff --git a/src/kinetics/ImplicitSurfChem.cpp b/src/kinetics/ImplicitSurfChem.cpp index f9146127d..a975b0cff 100644 --- a/src/kinetics/ImplicitSurfChem.cpp +++ b/src/kinetics/ImplicitSurfChem.cpp @@ -6,9 +6,9 @@ */ // Copyright 2001 California Institute of Technology -#include "ImplicitSurfChem.h" +#include "cantera/kinetics/ImplicitSurfChem.h" #include "cantera/numerics/Integrator.h" -#include "solveSP.h" +#include "cantera/kinetics/solveSP.h" using namespace std; diff --git a/src/kinetics/InterfaceKinetics.cpp b/src/kinetics/InterfaceKinetics.cpp index 77dbad560..1fdc0394f 100644 --- a/src/kinetics/InterfaceKinetics.cpp +++ b/src/kinetics/InterfaceKinetics.cpp @@ -12,7 +12,7 @@ #include "cantera/kinetics/ReactionData.h" #include "cantera/kinetics/RateCoeffMgr.h" -#include "ImplicitSurfChem.h" +#include "cantera/kinetics/ImplicitSurfChem.h" using namespace std; diff --git a/src/kinetics/Kinetics.cpp b/src/kinetics/Kinetics.cpp index 800d668a6..7e666c6ec 100644 --- a/src/kinetics/Kinetics.cpp +++ b/src/kinetics/Kinetics.cpp @@ -15,7 +15,7 @@ #include "cantera/kinetics/StoichManager.h" #include "cantera/kinetics/RateCoeffMgr.h" -#include "ImplicitSurfChem.h" +#include "cantera/kinetics/ImplicitSurfChem.h" #include using namespace std; diff --git a/src/kinetics/solveSP.cpp b/src/kinetics/solveSP.cpp index f6bcc6d2f..67db682b5 100644 --- a/src/kinetics/solveSP.cpp +++ b/src/kinetics/solveSP.cpp @@ -8,7 +8,7 @@ * See file License.txt for licensing information. */ -#include "solveSP.h" +#include "cantera/kinetics/solveSP.h" #include "cantera/base/clockWC.h" #include "cantera/numerics/ctlapack.h" diff --git a/src/numerics/CVodesIntegrator.cpp b/src/numerics/CVodesIntegrator.cpp index fdc49c892..c11fcf1f3 100644 --- a/src/numerics/CVodesIntegrator.cpp +++ b/src/numerics/CVodesIntegrator.cpp @@ -6,7 +6,7 @@ // Copyright 2001 California Institute of Technology #include "cantera/base/config.h" -#include "CVodesIntegrator.h" +#include "cantera/numerics/CVodesIntegrator.h" #include "cantera/base/stringUtils.h" #include diff --git a/src/numerics/NonlinearSolver.cpp b/src/numerics/NonlinearSolver.cpp index f3d643a5c..a20dced0c 100644 --- a/src/numerics/NonlinearSolver.cpp +++ b/src/numerics/NonlinearSolver.cpp @@ -6,7 +6,11 @@ */ /* - * Copyright 2004 Sandia Corporation. Under the terms of Contract + * $Date$ + * $Revision$ + */ +/* + * Copywrite 2004 Sandia Corporation. Under the terms of Contract * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government * retains certain rights in this software. * See file License.txt for licensing information. @@ -22,7 +26,6 @@ #include "cantera/base/clockWC.h" #include "cantera/base/vec_functions.h" #include "cantera/base/mdp_allo.h" -#include "cantera/base/stringUtils.h" #include #include @@ -31,65 +34,72 @@ #include //@{ +extern void print_line(const char *, int); + +#ifndef MAX +#define MAX(x,y) (( (x) > (y) ) ? (x) : (y)) +#define MIN(x,y) (( (x) < (y) ) ? (x) : (y)) +#endif #ifndef CONSTD_DATA_PTR #define CONSTD_DATA_PTR(x) (( const doublereal *) (&x[0])) #endif + //@} using namespace std; -namespace Cantera -{ -//==================================================================================================================== -//----------------------------------------------------------- -// Constants -//----------------------------------------------------------- -//! Dampfactor is the factor by which the damping factor is reduced by when a reduction in step length is warranted -const doublereal DampFactor = 4.0; -//! Number of damping steps that are carried out before the solution is deemed a failure -const int NDAMP = 7; -//==================================================================================================================== -//! Print a line of a single repeated character string -/*! - * @param str Character string - * @param n Iteration length - */ -static void print_line(const char* str, int n) -{ +namespace Cantera { + + + //==================================================================================================================== + //----------------------------------------------------------- + // Constants + //----------------------------------------------------------- + //! Dampfactor is the factor by which the damping factor is reduced by when a reduction in step length is warranted + const doublereal DampFactor = 4.0; + //! Number of damping steps that are carried out before the solution is deemed a failure + const int NDAMP = 7; + //==================================================================================================================== + //! Print a line of a single repeated character string + /*! + * @param str Character string + * @param n Iteration length + */ + static void print_line(const char *str, int n) { for (int i = 0; i < n; i++) { - printf("%s", str); + printf("%s", str); } printf("\n"); -} + } -bool NonlinearSolver::s_TurnOffTiming(false); + bool NonlinearSolver::s_TurnOffTiming(false); -#ifdef DEBUG_NUMJAC -bool NonlinearSolver::s_print_NumJac(true); +#ifdef DEBUG_NUMJAC + bool NonlinearSolver::s_print_NumJac(true); #else -bool NonlinearSolver::s_print_NumJac(false); + bool NonlinearSolver::s_print_NumJac(false); #endif -// Turn off printing of dogleg information -bool NonlinearSolver::s_print_DogLeg(false); + // Turn off printing of dogleg information + bool NonlinearSolver::s_print_DogLeg(false); -// Turn off solving the system twice and comparing the answer. -/* - * Turn this on if you want to compare the Hessian and Newton solve results. - */ -bool NonlinearSolver::s_doBothSolvesAndCompare(false); + // Turn off solving the system twice and comparing the answer. + /* + * Turn this on if you want to compare the Hessian and Newton solve results. + */ + bool NonlinearSolver::s_doBothSolvesAndCompare(false); -// This toggle turns off the use of the Hessian when it is warranted by the condition number. -/* - * This is a debugging option. - */ -bool NonlinearSolver::s_alwaysAssumeNewtonGood(false); + // This toggle turns off the use of the Hessian when it is warranted by the condition number. + /* + * This is a debugging option. + */ + bool NonlinearSolver::s_alwaysAssumeNewtonGood(false); -//==================================================================================================================== -// Default constructor -/* - * @param func Residual and jacobian evaluator function object - */ -NonlinearSolver::NonlinearSolver(ResidJacEval* func) : + //==================================================================================================================== + // Default constructor + /* + * @param func Residual and jacobian evaluator function object + */ + NonlinearSolver::NonlinearSolver(ResidJacEval *func) : m_func(func), solnType_(NSOLN_TYPE_STEADY_STATE), neq_(0), @@ -167,13 +177,13 @@ NonlinearSolver::NonlinearSolver(ResidJacEval* func) : doDogLeg_(0), doAffineSolve_(0) , CurrentTrustFactor_(1.0), - NextTrustFactor_(1.0), + NextTrustFactor_ (1.0), ResidWtsReevaluated_(false), ResidDecreaseSDExp_(0.0), ResidDecreaseSD_(0.0), ResidDecreaseNewtExp_(0.0), ResidDecreaseNewt_(0.0) -{ + { neq_ = m_func->nEquations(); m_ewt.resize(neq_, rtol_); @@ -197,11 +207,11 @@ NonlinearSolver::NonlinearSolver(ResidJacEval* func) : m_y_n_1.resize(neq_, 0.0); doublereal hb = std::numeric_limits::max(); m_y_high_bounds.resize(neq_, hb); - m_y_low_bounds.resize(neq_, -hb); + m_y_low_bounds.resize(neq_, -hb); - for (size_t i = 0; i < neq_; i++) { - atolk_[i] = atolBase_; - m_ewt[i] = atolk_[i]; + for (int i = 0; i < neq_; i++) { + atolk_[i] = atolBase_; + m_ewt[i] = atolk_[i]; } @@ -210,10 +220,10 @@ NonlinearSolver::NonlinearSolver(ResidJacEval* func) : Jd_.resize(neq_, 0.0); deltaX_trust_.resize(neq_, 1.0); -} -//==================================================================================================================== -NonlinearSolver::NonlinearSolver(const NonlinearSolver& right) : - m_func(right.m_func), + } + //==================================================================================================================== + NonlinearSolver::NonlinearSolver(const NonlinearSolver &right) : + m_func(right.m_func), solnType_(NSOLN_TYPE_STEADY_STATE), neq_(0), m_ewt(0), @@ -235,7 +245,7 @@ NonlinearSolver::NonlinearSolver(const NonlinearSolver& right) : m_normResid_0(0.0), m_normResid_Bound(0.0), m_normResid_1(0.0), - m_normDeltaSoln_Newton(0.0), + m_normDeltaSoln_Newton(0.0), m_normDeltaSoln_CP(0.0), m_normResidTrial(0.0), m_resid_scaled(false), @@ -291,31 +301,29 @@ NonlinearSolver::NonlinearSolver(const NonlinearSolver& right) : doDogLeg_(0), doAffineSolve_(0), CurrentTrustFactor_(1.0), - NextTrustFactor_(1.0), + NextTrustFactor_ (1.0), ResidWtsReevaluated_(false), ResidDecreaseSDExp_(0.0), ResidDecreaseSD_(0.0), ResidDecreaseNewtExp_(0.0), ResidDecreaseNewt_(0.0) -{ + { *this =operator=(right); -} + } -//==================================================================================================================== -NonlinearSolver::~NonlinearSolver() -{ + //==================================================================================================================== + NonlinearSolver::~NonlinearSolver() { if (jacCopyPtr_) { - delete jacCopyPtr_; + delete jacCopyPtr_; } if (HessianPtr_) { - delete HessianPtr_; + delete HessianPtr_; } -} -//==================================================================================================================== -NonlinearSolver& NonlinearSolver::operator=(const NonlinearSolver& right) -{ + } + //==================================================================================================================== + NonlinearSolver& NonlinearSolver::operator=(const NonlinearSolver &right) { if (this == &right) { - return *this; + return *this; } // rely on the ResidJacEval duplMyselfAsresidJacEval() function to // create a deep copy @@ -373,11 +381,11 @@ NonlinearSolver& NonlinearSolver::operator=(const NonlinearSolver& right) m_ScaleSolnNormToResNorm = right.m_ScaleSolnNormToResNorm; if (jacCopyPtr_) { - delete(jacCopyPtr_); + delete (jacCopyPtr_); } jacCopyPtr_ = (right.jacCopyPtr_)->duplMyselfAsGeneralMatrix(); if (HessianPtr_) { - delete(HessianPtr_); + delete (HessianPtr_); } HessianPtr_ = (right.HessianPtr_)->duplMyselfAsGeneralMatrix(); @@ -389,7 +397,7 @@ NonlinearSolver& NonlinearSolver::operator=(const NonlinearSolver& right) RJd_norm_ = right.RJd_norm_; lambdaStar_ = right.lambdaStar_; Jd_ = right.Jd_; - deltaX_trust_ = right.deltaX_trust_; + deltaX_trust_ = right.deltaX_trust_; norm_deltaX_trust_ = right.norm_deltaX_trust_; trustDelta_ = right.trustDelta_; trustRegionInitializationMethod_ = right.trustRegionInitializationMethod_; @@ -414,1041 +422,1048 @@ NonlinearSolver& NonlinearSolver::operator=(const NonlinearSolver& right) ResidDecreaseNewt_ = right.ResidDecreaseNewt_; return *this; -} -//==================================================================================================================== -// Create solution weights for convergence criteria -/* - * We create soln weights from the following formula - * - * wt[i] = rtol * abs(y[i]) + atol[i] - * - * The program always assumes that atol is specific - * to the solution component - * - * @param y vector of the current solution values - */ -void NonlinearSolver::createSolnWeights(const doublereal* const y) -{ - for (size_t i = 0; i < neq_; i++) { - m_ewt[i] = rtol_ * fabs(y[i]) + atolk_[i]; + } + //==================================================================================================================== + // Create solution weights for convergence criteria + /* + * We create soln weights from the following formula + * + * wt[i] = rtol * abs(y[i]) + atol[i] + * + * The program always assumes that atol is specific + * to the solution component + * + * @param y vector of the current solution values + */ + void NonlinearSolver::createSolnWeights(const doublereal * const y) { + for (int i = 0; i < neq_; i++) { + m_ewt[i] = rtol_ * fabs(y[i]) + atolk_[i]; +#ifdef DEBUG_MODE + if (m_ewt[i] <= 0.0) { + throw CanteraError(" NonlinearSolver::createSolnWeights()", "ewts <= 0.0"); + } +#endif } -} -//==================================================================================================================== -// set bounds constraints for all variables in the problem -/* - * - * @param y_low_bounds Vector of lower bounds - * @param y_high_bounds Vector of high bounds - */ -void NonlinearSolver::setBoundsConstraints(const doublereal* const y_low_bounds, - const doublereal* const y_high_bounds) -{ - for (size_t i = 0; i < neq_; i++) { - m_y_low_bounds[i] = y_low_bounds[i]; - m_y_high_bounds[i] = y_high_bounds[i]; + } + //==================================================================================================================== + // set bounds constraints for all variables in the problem + /* + * + * @param y_low_bounds Vector of lower bounds + * @param y_high_bounds Vector of high bounds + */ + void NonlinearSolver::setBoundsConstraints(const doublereal * const y_low_bounds, + const doublereal * const y_high_bounds) { + for (int i = 0; i < neq_; i++) { + m_y_low_bounds[i] = y_low_bounds[i]; + m_y_high_bounds[i] = y_high_bounds[i]; } -} -//==================================================================================================================== -void NonlinearSolver::setSolverScheme(int doDogLeg, int doAffineSolve) -{ + } + //==================================================================================================================== + void NonlinearSolver::setSolverScheme(int doDogLeg, int doAffineSolve) { doDogLeg_ = doDogLeg; doAffineSolve_ = doAffineSolve; -} -//==================================================================================================================== -std::vector & NonlinearSolver::lowBoundsConstraintVector() -{ + } + //==================================================================================================================== + std::vector & NonlinearSolver::lowBoundsConstraintVector() { return m_y_low_bounds; -} -//==================================================================================================================== -std::vector & NonlinearSolver::highBoundsConstraintVector() -{ + } + //==================================================================================================================== + std::vector & NonlinearSolver::highBoundsConstraintVector() { return m_y_high_bounds; -} -//==================================================================================================================== -// L2 norm of the delta of the solution vector -/* - * calculate the norm of the solution vector. This will - * involve the column scaling of the matrix - * - * The third argument has a default of false. However, - * if true, then a table of the largest values is printed - * out to standard output. - * - * @param delta_y Vector to take the norm of - * @param title Optional title to be printed out - * @param printLargest int indicating how many specific lines should be printed out - * @param dampFactor Current value of the damping factor. Defaults to 1. - * only used for printout out a table. - */ -doublereal NonlinearSolver::solnErrorNorm(const doublereal* const delta_y, const char* title, int printLargest, - const doublereal dampFactor) const -{ + } + //==================================================================================================================== + // L2 norm of the delta of the solution vector + /* + * calculate the norm of the solution vector. This will + * involve the column scaling of the matrix + * + * The third argument has a default of false. However, + * if true, then a table of the largest values is printed + * out to standard output. + * + * @param delta_y Vector to take the norm of + * @param title Optional title to be printed out + * @param printLargest int indicating how many specific lines should be printed out + * @param dampFactor Current value of the damping factor. Defaults to 1. + * only used for printout out a table. + */ + doublereal NonlinearSolver::solnErrorNorm(const doublereal * const delta_y, const char * title, int printLargest, + const doublereal dampFactor) const + { + int i; doublereal sum_norm = 0.0, error; - for (size_t i = 0; i < neq_; i++) { - error = delta_y[i] / m_ewt[i]; - sum_norm += (error * error); + for (i = 0; i < neq_; i++) { + error = delta_y[i] / m_ewt[i]; + sum_norm += (error * error); } - sum_norm = sqrt(sum_norm / neq_); - if (printLargest) { - if ((printLargest == 1) || (m_print_flag >= 4 && m_print_flag <= 5)) { + sum_norm = sqrt(sum_norm / neq_); + if (printLargest) { + if ((printLargest == 1) || (m_print_flag >= 4 && m_print_flag <= 5)) { - printf("\t\t solnErrorNorm(): "); - if (title) { - printf("%s", title); - } else { - printf(" Delta soln norm "); - } - printf(" = %-11.4E\n", sum_norm); - } else if (m_print_flag >= 6) { - const int num_entries = printLargest; - printf("\t\t "); - print_line("-", 90); - printf("\t\t solnErrorNorm(): "); - if (title) { - printf("%s", title); - } else { - printf(" Delta soln norm "); - } - printf(" = %-11.4E\n", sum_norm); + printf("\t\t solnErrorNorm(): "); + if (title) { + printf("%s", title); + } else { + printf(" Delta soln norm "); + } + printf(" = %-11.4E\n", sum_norm); + } else if (m_print_flag >= 6) { - doublereal dmax1, normContrib; - int j; - std::vector imax(num_entries, npos); - printf("\t\t Printout of Largest Contributors: (damp = %g)\n", dampFactor); - printf("\t\t I weightdeltaY/sqtN| deltaY " - "ysolnOld ysolnNew Soln_Weights\n"); - printf("\t\t "); - print_line("-", 88); - for (int jnum = 0; jnum < num_entries; jnum++) { - dmax1 = -1.0; - for (size_t i = 0; i < neq_; i++) { - bool used = false; - for (j = 0; j < jnum; j++) { - if (imax[j] == i) { - used = true; - } - } - if (!used) { - error = delta_y[i] / m_ewt[i]; - normContrib = sqrt(error * error); - if (normContrib > dmax1) { - imax[jnum] = i; - dmax1 = normContrib; - } - } - } - size_t i = imax[jnum]; - if (i != npos) { - error = delta_y[i] / m_ewt[i]; - normContrib = sqrt(error * error); - printf("\t\t %4s %12.4e | %12.4e %12.4e %12.4e %12.4e\n", - int2str(i).c_str(), normContrib/sqrt((double)neq_), delta_y[i], - m_y_n_curr[i], m_y_n_curr[i] + dampFactor * delta_y[i], m_ewt[i]); - } - } - printf("\t\t "); - print_line("-", 90); + const int num_entries = printLargest; + printf("\t\t "); print_line("-", 90); + printf("\t\t solnErrorNorm(): "); + if (title) { + printf("%s", title); + } else { + printf(" Delta soln norm "); } + printf(" = %-11.4E\n", sum_norm); + + doublereal dmax1, normContrib; + int j; + int *imax = mdp::mdp_alloc_int_1(num_entries, -1); + printf("\t\t Printout of Largest Contributors: (damp = %g)\n", dampFactor); + printf("\t\t I weightdeltaY/sqtN| deltaY " + "ysolnOld ysolnNew Soln_Weights\n"); + printf("\t\t "); print_line("-", 88); + + for (int jnum = 0; jnum < num_entries; jnum++) { + dmax1 = -1.0; + for (i = 0; i < neq_; i++) { + bool used = false; + for (j = 0; j < jnum; j++) { + if (imax[j] == i) used = true; + } + if (!used) { + error = delta_y[i] / m_ewt[i]; + normContrib = sqrt(error * error); + if (normContrib > dmax1) { + imax[jnum] = i; + dmax1 = normContrib; + } + } + } + i = imax[jnum]; + if (i >= 0) { + error = delta_y[i] / m_ewt[i]; + normContrib = sqrt(error * error); + printf("\t\t %4d %12.4e | %12.4e %12.4e %12.4e %12.4e\n", i, normContrib/sqrt((double)neq_), + delta_y[i], m_y_n_curr[i], m_y_n_curr[i] + dampFactor * delta_y[i], m_ewt[i]); + + } + } + printf("\t\t "); print_line("-", 90); + mdp::mdp_safe_free((void **) &imax); + } } return sum_norm; -} -//==================================================================================================================== -/* - * L2 Norm of the residual - * - * The second argument has a default of false. However, - * if true, then a table of the largest values is printed - * out to standard output. - */ -doublereal NonlinearSolver::residErrorNorm(const doublereal* const resid, const char* title, const int printLargest, - const doublereal* const y) const -{ + } + //==================================================================================================================== + /* + * L2 Norm of the residual + * + * The second argument has a default of false. However, + * if true, then a table of the largest values is printed + * out to standard output. + */ + doublereal NonlinearSolver::residErrorNorm(const doublereal * const resid, const char * title, const int printLargest, + const doublereal * const y) const + { + int i; doublereal sum_norm = 0.0, error; - for (size_t i = 0; i < neq_; i++) { -#ifdef DEBUG_HKM - mdp::checkFinite(resid[i]); + for (i = 0; i < neq_; i++) { +#ifdef DEBUG_MODE + mdp::checkFinite(resid[i]); #endif - error = resid[i] / m_residWts[i]; -#ifdef DEBUG_HKM - mdp::checkFinite(error); + error = resid[i] / m_residWts[i]; +#ifdef DEBUG_MODE + mdp::checkFinite(error); #endif - sum_norm += (error * error); + sum_norm += (error * error); } - sum_norm = sqrt(sum_norm / neq_); -#ifdef DEBUG_HKM + sum_norm = sqrt(sum_norm / neq_); +#ifdef DEBUG_MODE mdp::checkFinite(sum_norm); #endif if (printLargest) { - const int num_entries = printLargest; - doublereal dmax1, normContrib; - int j; - std::vector imax(num_entries, npos); + const int num_entries = printLargest; + doublereal dmax1, normContrib; + int j; + int *imax = mdp::mdp_alloc_int_1(num_entries, -1); - if (m_print_flag >= 4 && m_print_flag <= 5) { - printf("\t\t residErrorNorm():"); - if (title) { - printf(" %s ", title); - } else { - printf(" residual L2 norm "); - } - printf("= %12.4E\n", sum_norm); - } - if (m_print_flag >= 6) { - printf("\t\t "); - print_line("-", 90); - printf("\t\t residErrorNorm(): "); - if (title) { - printf(" %s ", title); - } else { - printf(" residual L2 norm "); - } - printf("= %12.4E\n", sum_norm); - printf("\t\t Printout of Largest Contributors to norm:\n"); - printf("\t\t I |Resid/ResWt| UnsclRes ResWt | y_curr\n"); - printf("\t\t "); - print_line("-", 88); - for (int jnum = 0; jnum < num_entries; jnum++) { - dmax1 = -1.0; - for (size_t i = 0; i < neq_; i++) { - bool used = false; - for (j = 0; j < jnum; j++) { - if (imax[j] == i) { - used = true; - } - } - if (!used) { - error = resid[i] / m_residWts[i]; - normContrib = sqrt(error * error); - if (normContrib > dmax1) { - imax[jnum] = i; - dmax1 = normContrib; - } - } - } - size_t i = imax[jnum]; - if (i != npos) { - error = resid[i] / m_residWts[i]; - normContrib = sqrt(error * error); - printf("\t\t %4s %12.4e %12.4e %12.4e | %12.4e\n", - int2str(i).c_str(), normContrib, resid[i], m_residWts[i], y[i]); - } - } - - printf("\t\t "); - print_line("-", 90); - } + if (m_print_flag >= 4 && m_print_flag <= 5) { + printf("\t\t residErrorNorm():"); + if (title) { + printf(" %s ", title); + } else { + printf(" residual L2 norm "); + } + printf("= %12.4E\n", sum_norm); + } + if (m_print_flag >= 6) { + printf("\t\t "); print_line("-", 90); + printf("\t\t residErrorNorm(): "); + if (title) { + printf(" %s ", title); + } else { + printf(" residual L2 norm "); + } + printf("= %12.4E\n", sum_norm); + printf("\t\t Printout of Largest Contributors to norm:\n"); + printf("\t\t I |Resid/ResWt| UnsclRes ResWt | y_curr\n"); + printf("\t\t "); + print_line("-", 88); + for (int jnum = 0; jnum < num_entries; jnum++) { + dmax1 = -1.0; + for (i = 0; i < neq_; i++) { + bool used = false; + for (j = 0; j < jnum; j++) { + if (imax[j] == i) used = true; + } + if (!used) { + error = resid[i] / m_residWts[i]; + normContrib = sqrt(error * error); + if (normContrib > dmax1) { + imax[jnum] = i; + dmax1 = normContrib; + } + } + } + i = imax[jnum]; + if (i >= 0) { + error = resid[i] / m_residWts[i]; + normContrib = sqrt(error * error); + printf("\t\t %4d %12.4e %12.4e %12.4e | %12.4e\n", i, normContrib, resid[i], m_residWts[i], y[i]); + } + } + + printf("\t\t "); + print_line("-", 90); + } + mdp::mdp_safe_free((void **) &imax); } return sum_norm; -} -//==================================================================================================================== -// Set the column scaling that are used for the inversion of the matrix -/* - * There are three ways to do this. - * - * The first method is to set the bool useColScaling to true, leaving the scaling factors unset. - * Then, the column scales will be set to the solution error weighting factors. This has the - * effect of ensuring that all delta variables will have the same order of magnitude at convergence - * end. - * - * The second way is the explicitly set the column factors in the second argument of this function call. - * - * The final way to input the scales is to override the ResidJacEval member function call, - * - * calcSolnScales(double time_n, const double *m_y_n_curr, const double *m_y_nm1, double *m_colScales) - * - * Overriding this function call will trump all other ways to specify the column scaling factors. - * - * @param useColScaling Turn this on if you want to use column scaling in the calculations - * @param scaleFactors A vector of doubles that specifies the column factors. - */ -void NonlinearSolver::setColumnScaling(bool useColScaling, const double* const scaleFactors) -{ + } + //==================================================================================================================== + // Set the column scaling that are used for the inversion of the matrix + /* + * There are three ways to do this. + * + * The first method is to set the bool useColScaling to true, leaving the scaling factors unset. + * Then, the column scales will be set to the solution error weighting factors. This has the + * effect of ensuring that all delta variables will have the same order of magnitude at convergence + * end. + * + * The second way is the explicity set the column factors in the second argument of this function call. + * + * The final way to input the scales is to override the ResidJacEval member function call, + * + * calcSolnScales(double time_n, const double *m_y_n_curr, const double *m_y_nm1, double *m_colScales) + * + * Overriding this function call will trump all other ways to specify the column scaling factors. + * + * @param useColScaling Turn this on if you want to use column scaling in the calculations + * @param scaleFactors A vector of doubles that specifies the column factors. + */ + void NonlinearSolver::setColumnScaling(bool useColScaling, const double * const scaleFactors) { if (useColScaling) { - if (scaleFactors) { - m_colScaling = 2; - for (size_t i = 0; i < neq_; i++) { - m_colScales[i] = scaleFactors[i]; - if (m_colScales[i] <= 1.0E-200) { - throw CanteraError("NonlinearSolver::setColumnScaling() ERROR", "Bad column scale factor"); - } - } - } else { - m_colScaling = 1; + if (scaleFactors) { + m_colScaling = 2; + for (int i = 0; i < neq_; i++) { + m_colScales[i] = scaleFactors[i]; + if (m_colScales[i] <= 1.0E-200) { + throw CanteraError("NonlinearSolver::setColumnScaling() ERROR", "Bad column scale factor"); + } } + } else { + m_colScaling = 1; + } } else { - m_colScaling = 0; + m_colScaling = 0; } -} -//==================================================================================================================== -// Set the rowscaling that are used for the inversion of the matrix -/* - * Row scaling is set here. Right now the row scaling is set internally in the code. - * - * @param useRowScaling Turn row scaling on or off. - */ -void NonlinearSolver::setRowScaling(bool useRowScaling) -{ - m_rowScaling = useRowScaling; -} -//==================================================================================================================== -/* - * calcColumnScales(): - * - * Set the column scaling vector at the current time - */ -void NonlinearSolver::calcColumnScales() -{ + } + //==================================================================================================================== + // Set the rowscaling that are used for the inversion of the matrix + /* + * Row scaling is set here. Right now the row scaling is set internally in the code. + * + * @param useRowScaling Turn row scaling on or off. + */ + void NonlinearSolver::setRowScaling(bool useRowScaling) { + m_rowScaling = useRowScaling; + } + //==================================================================================================================== + /* + * calcColumnScales(): + * + * Set the column scaling vector at the current time + */ + void NonlinearSolver::calcColumnScales() { if (m_colScaling == 1) { - for (size_t i = 0; i < neq_; i++) { - m_colScales[i] = m_ewt[i]; - } + for (int i = 0; i < neq_; i++) { + m_colScales[i] = m_ewt[i]; + } } else { - for (size_t i = 0; i < neq_; i++) { - m_colScales[i] = 1.0; - } + for (int i = 0; i < neq_; i++) { + m_colScales[i] = 1.0; + } } if (m_colScaling) { - m_func->calcSolnScales(time_n, DATA_PTR(m_y_n_curr), DATA_PTR(m_y_nm1), DATA_PTR(m_colScales)); + m_func->calcSolnScales(time_n, DATA_PTR(m_y_n_curr), DATA_PTR(m_y_nm1), DATA_PTR(m_colScales)); } -} -//==================================================================================================================== -// Compute the current residual -/* - * @param time_curr Value of the time - * @param typeCalc Type of the calculation - * @param y_curr Current value of the solution vector - * @param ydot_curr Current value of the time derivative of the solution vector - * - * @return Returns a flag to indicate that operation is successful. - * 1 Means a successful operation - * -0 or neg value Means an unsuccessful operation - */ -int NonlinearSolver::doResidualCalc(const doublereal time_curr, const int typeCalc, const doublereal* const y_curr, - const doublereal* const ydot_curr, const ResidEval_Type_Enum evalType) const -{ + } + //==================================================================================================================== + // Compute the current residual + /* + * @param time_curr Value of the time + * @param typeCalc Type of the calculation + * @param y_curr Current value of the solution vector + * @param ydot_curr Current value of the time derivative of the solution vector + * + * @return Returns a flag to indicate that operation is successful. + * 1 Means a successful operation + * -0 or neg value Means an unsuccessful operation + */ + int NonlinearSolver::doResidualCalc(const doublereal time_curr, const int typeCalc, const doublereal * const y_curr, + const doublereal * const ydot_curr, const ResidEval_Type_Enum evalType) const + { int retn = m_func->evalResidNJ(time_curr, delta_t_n, y_curr, ydot_curr, DATA_PTR(m_resid), evalType); m_nfe++; m_resid_scaled = false; return retn; -} -//==================================================================================================================== -// Scale the matrix -/* - * @param jac Jacobian - * @param y_comm Current value of the solution vector - * @param ydot_comm Current value of the time derivative of the solution vector - * @param time_curr current value of the time - */ -void NonlinearSolver::scaleMatrix(GeneralMatrix& jac, doublereal* const y_comm, doublereal* const ydot_comm, - doublereal time_curr, int num_newt_its) -{ - size_t irow, jcol; + } + //==================================================================================================================== + // Scale the matrix + /* + * @param jac Jacobian + * @param y_comm Current value of the solution vector + * @param ydot_comm Current value of the time derivative of the solution vector + * @param time_curr current value of the time + */ + void NonlinearSolver::scaleMatrix(GeneralMatrix& jac, doublereal * const y_comm, doublereal * const ydot_comm, + doublereal time_curr, int num_newt_its) + { + int irow, jcol; + int ku, kl; size_t ivec[2]; jac.nRowsAndStruct(ivec); - double* colP_j; + double *colP_j; /* * Column scaling -> We scale the columns of the Jacobian * by the nominal important change in the solution vector */ if (m_colScaling) { - if (!jac.factored()) { - if (jac.matrixType_ == 0) { - /* - * Go get new scales -> Took this out of this inner loop. - * Needs to be done at a larger scale. - */ - // setColumnScales(); + if (!jac.factored()) { + if (jac.matrixType_ == 0) { + /* + * Go get new scales -> Took this out of this inner loop. + * Needs to be done at a larger scale. + */ + // setColumnScales(); - /* - * Scale the new Jacobian - */ - doublereal* jptr = &(*(jac.begin())); - for (jcol = 0; jcol < neq_; jcol++) { - for (irow = 0; irow < neq_; irow++) { - *jptr *= m_colScales[jcol]; - jptr++; - } - } - } else if (jac.matrixType_ == 1) { - int kl = static_cast(ivec[0]); - int ku = static_cast(ivec[1]); - for (int jcol = 0; jcol < (int) neq_; jcol++) { - colP_j = (doublereal*) jac.ptrColumn(jcol); - for (int irow = jcol - ku; irow <= jcol + kl; irow++) { - if (irow >= 0 && irow < (int) neq_) { - colP_j[kl + ku + irow - jcol] *= m_colScales[jcol]; - } - } - } - } - } + /* + * Scale the new Jacobian + */ + doublereal *jptr = &(*(jac.begin())); + for (jcol = 0; jcol < neq_; jcol++) { + for (irow = 0; irow < neq_; irow++) { + *jptr *= m_colScales[jcol]; + jptr++; + } + } + } else if (jac.matrixType_ == 1) { + kl = ivec[0]; + ku = ivec[1]; + for (jcol = 0; jcol < neq_; jcol++) { + colP_j = (doublereal *) jac.ptrColumn(jcol); + for (irow = jcol - ku; irow <= jcol + kl; irow++) { + if (irow >= 0 && irow < neq_) { + colP_j[kl + ku + irow - jcol] *= m_colScales[jcol]; + } + } + } + } + } } /* - * row sum scaling -> Note, this is an unequivocal success + * row sum scaling -> Note, this is an unequivical success * at keeping the small numbers well balanced and nonnegative. */ if (! jac.factored()) { - /* - * Ok, this is ugly. jac.begin() returns an vector iterator - * to the first data location. - * Then &(*()) reverts it to a doublereal *. - */ - doublereal* jptr = &(*(jac.begin())); - for (irow = 0; irow < neq_; irow++) { - m_rowScales[irow] = 0.0; - m_rowWtScales[irow] = 0.0; - } - if (jac.matrixType_ == 0) { - for (jcol = 0; jcol < neq_; jcol++) { - for (irow = 0; irow < neq_; irow++) { - if (m_rowScaling) { - m_rowScales[irow] += fabs(*jptr); - } - if (m_colScaling) { - // This is needed in order to mitigate the change in J_ij carried out just above this loop. - // Alternatively, we could move this loop up to the top - m_rowWtScales[irow] += fabs(*jptr) * m_ewt[jcol] / m_colScales[jcol]; - } else { - m_rowWtScales[irow] += fabs(*jptr) * m_ewt[jcol]; - } - jptr++; - } - } - } else if (jac.matrixType_ == 1) { - int kl = static_cast(ivec[0]); - int ku = static_cast(ivec[1]); - for (int jcol = 0; jcol < (int) neq_; jcol++) { - colP_j = (doublereal*) jac.ptrColumn(jcol); - for (int irow = jcol - ku; irow <= jcol + kl; irow++) { - if (irow >= 0 && irow < (int) neq_) { - double vv = fabs(colP_j[kl + ku + irow - jcol]); - if (m_rowScaling) { - m_rowScales[irow] += vv; - } - if (m_colScaling) { - // This is needed in order to mitigate the change in J_ij carried out just above this loop. - // Alternatively, we could move this loop up to the top - m_rowWtScales[irow] += vv * m_ewt[jcol] / m_colScales[jcol]; - } else { - m_rowWtScales[irow] += vv * m_ewt[jcol]; - } - } - } - } - } - if (m_rowScaling) { - for (irow = 0; irow < neq_; irow++) { - m_rowScales[irow] = 1.0/m_rowScales[irow]; - } - } else { - for (irow = 0; irow < neq_; irow++) { - m_rowScales[irow] = 1.0; - } - } - // What we have defined is a maximum value that the residual can be and still pass. - // This isn't sufficient. - - if (m_rowScaling) { - if (jac.matrixType_ == 0) { - jptr = &(*(jac.begin())); - for (jcol = 0; jcol < neq_; jcol++) { - for (irow = 0; irow < neq_; irow++) { - *jptr *= m_rowScales[irow]; - jptr++; - } - } - } else if (jac.matrixType_ == 1) { - int kl = static_cast(ivec[0]); - int ku = static_cast(ivec[1]); - for (int jcol = 0; jcol < (int) neq_; jcol++) { - colP_j = (doublereal*) jac.ptrColumn(jcol); - for (int irow = jcol - ku; irow <= jcol + kl; irow++) { - if (irow >= 0 && irow < (int) neq_) { - colP_j[kl + ku + irow - jcol] *= m_rowScales[irow]; - } - } - } - } - } - - if (num_newt_its % 5 == 1) { - computeResidWts(); - } - + /* + * Ok, this is ugly. jac.begin() returns an vector iterator + * to the first data location. + * Then &(*()) reverts it to a doublereal *. + */ + doublereal *jptr = &(*(jac.begin())); + for (irow = 0; irow < neq_; irow++) { + m_rowScales[irow] = 0.0; + m_rowWtScales[irow] = 0.0; + } + if (jac.matrixType_ == 0) { + for (jcol = 0; jcol < neq_; jcol++) { + for (irow = 0; irow < neq_; irow++) { + if (m_rowScaling) { + m_rowScales[irow] += fabs(*jptr); + } + if (m_colScaling) { + // This is needed in order to mitgate the change in J_ij carried out just above this loop. + // Alternatively, we could move this loop up to the top + m_rowWtScales[irow] += fabs(*jptr) * m_ewt[jcol] / m_colScales[jcol]; + } else { + m_rowWtScales[irow] += fabs(*jptr) * m_ewt[jcol]; + } +#ifdef DEBUG_MODE + mdp::checkFinite(m_rowWtScales[irow]); +#endif + jptr++; + } + } + } else if (jac.matrixType_ == 1) { + kl = ivec[0]; + ku = ivec[1]; + for (jcol = 0; jcol < neq_; jcol++) { + colP_j = (doublereal *) jac.ptrColumn(jcol); + for (irow = jcol - ku; irow <= jcol + kl; irow++) { + if (irow >= 0 && irow < neq_) { + double vv = fabs(colP_j[kl + ku + irow - jcol]); + if (m_rowScaling) { + m_rowScales[irow] += vv; + } + if (m_colScaling) { + // This is needed in order to mitgate the change in J_ij carried out just above this loop. + // Alternatively, we could move this loop up to the top + m_rowWtScales[irow] += vv * m_ewt[jcol] / m_colScales[jcol]; + } else { + m_rowWtScales[irow] += vv * m_ewt[jcol]; + } +#ifdef DEBUG_MODE + mdp::checkFinite(m_rowWtScales[irow]); +#endif + } + } + } + } + if (m_rowScaling) { + for (irow = 0; irow < neq_; irow++) { + m_rowScales[irow] = 1.0/m_rowScales[irow]; + } + } else { + for (irow = 0; irow < neq_; irow++) { + m_rowScales[irow] = 1.0; + } + } + // What we have defined is a maximum value that the residual can be and still pass. + // This isn't sufficient. + + if (m_rowScaling) { + if (jac.matrixType_ == 0) { + jptr = &(*(jac.begin())); + for (jcol = 0; jcol < neq_; jcol++) { + for (irow = 0; irow < neq_; irow++) { + *jptr *= m_rowScales[irow]; + jptr++; + } + } + } else if (jac.matrixType_ == 1) { + kl = ivec[0]; + ku = ivec[1]; + for (jcol = 0; jcol < neq_; jcol++) { + colP_j = (doublereal *) jac.ptrColumn(jcol); + for (irow = jcol - ku; irow <= jcol + kl; irow++) { + if (irow >= 0 && irow < neq_) { + colP_j[kl + ku + irow - jcol] *= m_rowScales[irow]; + } + } + } + } + } + + if (num_newt_its % 5 == 1) { + computeResidWts(); + } + } -} -//==================================================================================================================== -// Calculate the scaling factor for translating residual norms into solution norms. -/* - * This routine calls computeResidWts() a couple of times in the calculation of m_ScaleSolnNormToResNorm. - * A more sophisticated routine may do more with signs to get a better value. Perhaps, a series of calculations - * with different signs attached may be in order. Then, m_ScaleSolnNormToResNorm would be calculated - * as the minimum of a series of calculations. - */ -void NonlinearSolver::calcSolnToResNormVector() -{ - if (! jacCopyPtr_->factored()) { + } + //==================================================================================================================== + // Calculate the scaling factor for translating residual norms into solution norms. + /* + * This routine calls computeResidWts() a couple of times in the calculation of m_ScaleSolnNormToResNorm. + * A more sophisticated routine may do more with signs to get a better value. Perhaps, a series of calculations + * with different signs attached may be in order. Then, m_ScaleSolnNormToResNorm would be calculated + * as the minimum of a series of calculations. + */ + void NonlinearSolver::calcSolnToResNormVector() + { + if (! jacCopyPtr_->factored()) { + + if (checkUserResidualTols_ != 1) { + doublereal sum = 0.0; + for (int irow = 0; irow < neq_; irow++) { + m_residWts[irow] = m_rowWtScales[irow] / neq_; + sum += m_residWts[irow]; + } + sum /= neq_; + for (int irow = 0; irow < neq_; irow++) { + m_residWts[irow] = (m_residWts[irow] + atolBase_ * atolBase_ * sum); + } + if (checkUserResidualTols_ == 2) { + for (int irow = 0; irow < neq_; irow++) { + m_residWts[irow] = MIN(m_residWts[irow], userResidAtol_[irow] + userResidRtol_ * m_rowWtScales[irow] / neq_); + } + } + } else { + for (int irow = 0; irow < neq_; irow++) { + m_residWts[irow] = userResidAtol_[irow] + userResidRtol_ * m_rowWtScales[irow] / neq_; + } + } + + + for (int irow = 0; irow < neq_; irow++) { + m_wksp[irow] = 0.0; + } + doublereal *jptr = &(jacCopyPtr_->operator()(0,0)); + for (int jcol = 0; jcol < neq_; jcol++) { + for (int irow = 0; irow < neq_; irow++) { + m_wksp[irow] += (*jptr) * m_ewt[jcol]; + jptr++; + } + } + doublereal resNormOld = 0.0; + doublereal error; + + for (int irow = 0; irow < neq_; irow++) { + error = m_wksp[irow] / m_residWts[irow]; + resNormOld += error * error; + } + resNormOld = sqrt(resNormOld / neq_); - if (checkUserResidualTols_ != 1) { - doublereal sum = 0.0; - for (size_t irow = 0; irow < neq_; irow++) { - m_residWts[irow] = m_rowWtScales[irow] / neq_; - sum += m_residWts[irow]; - } - sum /= neq_; - for (size_t irow = 0; irow < neq_; irow++) { - m_residWts[irow] = (m_residWts[irow] + atolBase_ * atolBase_ * sum); - } - if (checkUserResidualTols_ == 2) { - for (size_t irow = 0; irow < neq_; irow++) { - m_residWts[irow] = std::min(m_residWts[irow], userResidAtol_[irow] + userResidRtol_ * m_rowWtScales[irow] / neq_); - } - } - } else { - for (size_t irow = 0; irow < neq_; irow++) { - m_residWts[irow] = userResidAtol_[irow] + userResidRtol_ * m_rowWtScales[irow] / neq_; - } - } - - - for (size_t irow = 0; irow < neq_; irow++) { - m_wksp[irow] = 0.0; - } - doublereal* jptr = &(jacCopyPtr_->operator()(0,0)); - for (size_t jcol = 0; jcol < neq_; jcol++) { - for (size_t irow = 0; irow < neq_; irow++) { - m_wksp[irow] += (*jptr) * m_ewt[jcol]; - jptr++; - } - } - doublereal resNormOld = 0.0; - doublereal error; - - for (size_t irow = 0; irow < neq_; irow++) { - error = m_wksp[irow] / m_residWts[irow]; - resNormOld += error * error; - } - resNormOld = sqrt(resNormOld / neq_); - - if (resNormOld > 0.0) { - m_ScaleSolnNormToResNorm = resNormOld; - } - if (m_ScaleSolnNormToResNorm < 1.0E-8) { - m_ScaleSolnNormToResNorm = 1.0E-8; - } - - // Recalculate the residual weights now that we know the value of m_ScaleSolnNormToResNorm - computeResidWts(); + if (resNormOld > 0.0) { + m_ScaleSolnNormToResNorm = resNormOld; + } + if (m_ScaleSolnNormToResNorm < 1.0E-8) { + m_ScaleSolnNormToResNorm = 1.0E-8; + } + + // Recalculate the residual weights now that we know the value of m_ScaleSolnNormToResNorm + computeResidWts(); } else { - throw CanteraError("NonlinearSolver::calcSolnToResNormVector()" , "Logic error"); + throw CanteraError("NonlinearSolver::calcSolnToResNormVector()" , "Logic error"); } -} -//==================================================================================================================== -// Compute the undamped Newton step based on the current jacobian and an input rhs -/* - * Compute the undamped Newton step. The residual function is - * evaluated at the current time, t_n, at the current values of the - * solution vector, m_y_n_curr, and the solution time derivative, m_ydot_n. - * The Jacobian is not recomputed. - * - * A factored jacobian is reused, if available. If a factored jacobian - * is not available, then the jacobian is factored. Before factoring, - * the jacobian is row and column-scaled. Column scaling is not - * recomputed. The row scales are recomputed here, after column - * scaling has been implemented. - */ -int NonlinearSolver::doNewtonSolve(const doublereal time_curr, const doublereal* const y_curr, - const doublereal* const ydot_curr, doublereal* const delta_y, - GeneralMatrix& jac) -{ + } + //==================================================================================================================== + // Compute the undamped Newton step based on the current jacobian and an input rhs + /* + * Compute the undamped Newton step. The residual function is + * evaluated at the current time, t_n, at the current values of the + * solution vector, m_y_n_curr, and the solution time derivative, m_ydot_n. + * The Jacobian is not recomputed. + * + * A factored jacobian is reused, if available. If a factored jacobian + * is not available, then the jacobian is factored. Before factoring, + * the jacobian is row and column-scaled. Column scaling is not + * recomputed. The row scales are recomputed here, after column + * scaling has been implemented. + */ + int NonlinearSolver::doNewtonSolve(const doublereal time_curr, const doublereal * const y_curr, + const doublereal * const ydot_curr, doublereal * const delta_y, + GeneralMatrix& jac) + { + int irow; + + // multiply the residual by -1 if (m_rowScaling && !m_resid_scaled) { - for (size_t n = 0; n < neq_; n++) { - delta_y[n] = -m_rowScales[n] * m_resid[n]; - } - m_resid_scaled = true; + for (int n = 0; n < neq_; n++) { + delta_y[n] = -m_rowScales[n] * m_resid[n]; + } + m_resid_scaled = true; } else { - for (size_t n = 0; n < neq_; n++) { - delta_y[n] = -m_resid[n]; - } + for (int n = 0; n < neq_; n++) { + delta_y[n] = -m_resid[n]; + } } + + /* * Solve the system -> This also involves inverting the * matrix */ int info = jac.solve(DATA_PTR(delta_y)); + /* * reverse the column scaling if there was any. */ if (m_colScaling) { - for (size_t irow = 0; irow < neq_; irow++) { - delta_y[irow] = delta_y[irow] * m_colScales[irow]; - } + for (irow = 0; irow < neq_; irow++) { + delta_y[irow] = delta_y[irow] * m_colScales[irow]; + } } - + #ifdef DEBUG_JAC if (printJacContributions) { - for (size_t iNum = 0; iNum < numRows; iNum++) { - if (iNum > 0) { - focusRow++; - } - doublereal dsum = 0.0; - vector_fp& Jdata = jacBack.data(); - doublereal dRow = Jdata[neq_ * focusRow + focusRow]; - printf("\n Details on delta_Y for row %d \n", focusRow); - printf(" Value before = %15.5e, delta = %15.5e," - "value after = %15.5e\n", y_curr[focusRow], - delta_y[focusRow], y_curr[focusRow] + delta_y[focusRow]); - if (!freshJac) { - printf(" Old Jacobian\n"); - } - printf(" col delta_y aij " - "contrib \n"); - printf("--------------------------------------------------" - "---------------------------------------------\n"); - printf(" Res(%d) %15.5e %15.5e %15.5e (Res = %g)\n", - focusRow, delta_y[focusRow], - dRow, RRow[iNum] / dRow, RRow[iNum]); - dsum += RRow[iNum] / dRow; - for (size_t ii = 0; ii < neq_; ii++) { - if (ii != focusRow) { - doublereal aij = Jdata[neq_ * ii + focusRow]; - doublereal contrib = aij * delta_y[ii] * (-1.0) / dRow; - dsum += contrib; - if (fabs(contrib) > Pcutoff) { - printf("%6d %15.5e %15.5e %15.5e\n", ii, - delta_y[ii] , aij, contrib); - } - } - } - printf("--------------------------------------------------" - "---------------------------------------------\n"); - printf(" %15.5e %15.5e\n", - delta_y[focusRow], dsum); - } + for (int iNum = 0; iNum < numRows; iNum++) { + if (iNum > 0) focusRow++; + doublereal dsum = 0.0; + vector_fp& Jdata = jacBack.data(); + doublereal dRow = Jdata[neq_ * focusRow + focusRow]; + printf("\n Details on delta_Y for row %d \n", focusRow); + printf(" Value before = %15.5e, delta = %15.5e," + "value after = %15.5e\n", y_curr[focusRow], + delta_y[focusRow], y_curr[focusRow] + delta_y[focusRow]); + if (!freshJac) { + printf(" Old Jacobian\n"); + } + printf(" col delta_y aij " + "contrib \n"); + printf("--------------------------------------------------" + "---------------------------------------------\n"); + printf(" Res(%d) %15.5e %15.5e %15.5e (Res = %g)\n", + focusRow, delta_y[focusRow], + dRow, RRow[iNum] / dRow, RRow[iNum]); + dsum += RRow[iNum] / dRow; + for (int ii = 0; ii < neq_; ii++) { + if (ii != focusRow) { + doublereal aij = Jdata[neq_ * ii + focusRow]; + doublereal contrib = aij * delta_y[ii] * (-1.0) / dRow; + dsum += contrib; + if (fabs(contrib) > Pcutoff) { + printf("%6d %15.5e %15.5e %15.5e\n", ii, + delta_y[ii] , aij, contrib); + } + } + } + printf("--------------------------------------------------" + "---------------------------------------------\n"); + printf(" %15.5e %15.5e\n", + delta_y[focusRow], dsum); + } } #endif - - m_numTotalLinearSolves++; + + m_numTotalLinearSolves++; m_numLocalLinearSolves++; return info; -} -//==================================================================================================================== -// Compute the newton step, either by direct newton's or by solving a close problem that is represented -// by a Hessian ( -/* - * This is algorith A.6.5.1 in Dennis / Schnabel - * - * Compute the QR decomposition - * - * Notes on banded Hessian solve: - * The matrix for jT j has a larger band width. Both the top and bottom band widths - * are doubled, going from KU to KU+KL and KL to KU+KL in size. This is not an impossible increase in cost, but - * has to be considered. - */ -int NonlinearSolver::doAffineNewtonSolve(const doublereal* const y_curr, const doublereal* const ydot_curr, - doublereal* const delta_y, GeneralMatrix& jac) -{ + } + //==================================================================================================================== + // Compute the newton step, either by direct newton's or by solving a close problem that is represented + // by a Hessian ( + /* + * This is algorith A.6.5.1 in Dennis / Schnabel + * + * Compute the QR decomposition + * + * Notes on banded Hessian solve: + * The matrix for jT j has a larger band width. Both the top and bottom band widths + * are doubled, going from KU to KU+KL and KL to KU+KL in size. This is not an impossible increase in cost, but + * has to be considered. + */ + int NonlinearSolver::doAffineNewtonSolve(const doublereal * const y_curr, const doublereal * const ydot_curr, + doublereal * const delta_y, GeneralMatrix& jac) + { bool newtonGood = true; - doublereal* delyNewton = 0; + int irow; + doublereal *delyNewton = 0; // We can default to QR here ( or not ) jac.useFactorAlgorithm(1); int useQR = jac.factorAlgorithm(); - // multiply the residual by -1 + // multiplyl the residual by -1 // Scale the residual if there is row scaling. Note, the matrix has already been scaled if (m_rowScaling && !m_resid_scaled) { - for (size_t n = 0; n < neq_; n++) { - delta_y[n] = -m_rowScales[n] * m_resid[n]; - } - m_resid_scaled = true; + for (int n = 0; n < neq_; n++) { + delta_y[n] = -m_rowScales[n] * m_resid[n]; + } + m_resid_scaled = true; } else { - for (size_t n = 0; n < neq_; n++) { - delta_y[n] = -m_resid[n]; - } + for (int n = 0; n < neq_; n++) { + delta_y[n] = -m_resid[n]; + } } // Factor the matrix using a standard Newton solve m_conditionNumber = 1.0E300; int info = 0; - if (!jac.factored()) { - if (useQR) { - info = jac.factorQR(); - } else { - info = jac.factor(); - } + if (!jac.factored()) { + if (useQR) { + info = jac.factorQR(); + } else { + info = jac.factor(); + } } /* * Find the condition number of the matrix * If we have failed to factor, we will fall back to calculating and factoring a modified Hessian */ - if (info == 0) { - doublereal rcond = 0.0; - if (useQR) { - rcond = jac.rcondQR(); - } else { - doublereal a1norm = jac.oneNorm(); - rcond = jac.rcond(a1norm); - } - if (rcond > 0.0) { - m_conditionNumber = 1.0 / rcond; - } + if (info == 0) { + doublereal rcond = 0.0; + if (useQR) { + rcond = jac.rcondQR(); + } else { + doublereal a1norm = jac.oneNorm(); + rcond = jac.rcond(a1norm); + } + if (rcond > 0.0) { + m_conditionNumber = 1.0 / rcond; + } } else { - m_conditionNumber = 1.0E300; - newtonGood = false; - if (m_print_flag >= 1) { - printf("\t\t doAffineNewtonSolve: "); - if (useQR) { - printf("factorQR()"); - } else { - printf("factor()"); - } - printf(" returned with info = %d, indicating a zero row or column\n", info); - } + m_conditionNumber = 1.0E300; + newtonGood = false; + if (m_print_flag >= 1) { + printf("\t\t doAffineNewtonSolve: "); + if (useQR) { + printf("factorQR()"); + } else { + printf("factor()"); + } + printf(" returned with info = %d, indicating a zero row or column\n", info); + } } bool doHessian = false; if (s_doBothSolvesAndCompare) { - doHessian = true; + doHessian = true; } + bool useNewton = false; if (m_conditionNumber < 1.0E7) { - if (m_print_flag >= 4) { - printf("\t\t doAffineNewtonSolve: Condition number = %g during regular solve\n", m_conditionNumber); - } - - /* - * Solve the system -> This also involves inverting the matrix - */ - int info = jac.solve(DATA_PTR(delta_y)); - if (info) { - if (m_print_flag >= 2) { - printf("\t\t doAffineNewtonSolve() ERROR: QRSolve returned INFO = %d. Switching to Hessian solve\n", info); - } - doHessian = true; - newtonGood = false; - } - /* - * reverse the column scaling if there was any on a successful solve - */ - if (m_colScaling) { - for (size_t irow = 0; irow < neq_; irow++) { - delta_y[irow] = delta_y[irow] * m_colScales[irow]; - } - } + useNewton = true; + if (m_print_flag >= 4) { + printf("\t\t doAffineNewtonSolve: Condition number = %g during regular solve\n", m_conditionNumber); + } + /* + * Solve the system -> This also involves inverting the matrix + */ + int info = jac.solve(DATA_PTR(delta_y)); + if (info) { + if (m_print_flag >= 2) { + printf("\t\t doAffineNewtonSolve() ERROR: QRSolve returned INFO = %d. Switching to Hessian solve\n", info); + } + doHessian = true; + newtonGood = false; + } + /* + * reverse the column scaling if there was any on a successful solve + */ + if (m_colScaling) { + for (irow = 0; irow < neq_; irow++) { + delta_y[irow] = delta_y[irow] * m_colScales[irow]; + } + } + } else { - if (jac.matrixType_ == 1) { - newtonGood = true; - if (m_print_flag >= 3) { - printf("\t\t doAffineNewtonSolve() WARNING: Condition number too large, %g, But Banded Hessian solve " - "not implemented yet \n", m_conditionNumber); - } - } else { - doHessian = true; - newtonGood = false; - if (m_print_flag >= 3) { - printf("\t\t doAffineNewtonSolve() WARNING: Condition number too large, %g. Doing a Hessian solve \n", m_conditionNumber); - } - } + if (jac.matrixType_ == 1) { + useNewton = true; + newtonGood = true; + if (m_print_flag >= 3) { + printf("\t\t doAffineNewtonSolve() WARNING: Condition number too large, %g, But Banded Hessian solve " + "not implemented yet \n", m_conditionNumber); + } + } else { + doHessian = true; + newtonGood = false; + if (m_print_flag >= 3) { + printf("\t\t doAffineNewtonSolve() WARNING: Condition number too large, %g. Doing a Hessian solve \n", m_conditionNumber); + } + } } if (doHessian) { - // Store the old value for later comparison + // Store the old value for later comparison + + delyNewton = mdp::mdp_alloc_dbl_1(neq_, MDP_DBL_NOINIT); + for (irow = 0; irow < neq_; irow++) { + delyNewton[irow] = delta_y[irow]; + } + + // Get memory if not done before + if (HessianPtr_ == 0) { + HessianPtr_ = jac.duplMyselfAsGeneralMatrix(); + } - delyNewton = mdp::mdp_alloc_dbl_1((int) neq_, MDP_DBL_NOINIT); - for (size_t irow = 0; irow < neq_; irow++) { - delyNewton[irow] = delta_y[irow]; - } + /* + * Calculate the symmetric Hessian + */ + GeneralMatrix &hessian = *HessianPtr_; + GeneralMatrix &jacCopy = *jacCopyPtr_; + hessian.zero(); + if (m_rowScaling) { + for (int i = 0; i < neq_; i++) { + for (int j = i; j < neq_; j++) { + for (int k = 0; k < neq_; k++) { + hessian(i,j) += jacCopy(k,i) * jacCopy(k,j) * m_rowScales[k] * m_rowScales[k]; + } + hessian(j,i) = hessian(i,j); + } + } + } else { + for (int i = 0; i < neq_; i++) { + for (int j = i; j < neq_; j++) { + for (int k = 0; k < neq_; k++) { + hessian(i,j) += jacCopy(k,i) * jacCopy(k,j); + } + hessian(j,i) = hessian(i,j); + } + } + } - // Get memory if not done before - if (HessianPtr_ == 0) { - HessianPtr_ = jac.duplMyselfAsGeneralMatrix(); - } - - /* - * Calculate the symmetric Hessian - */ - GeneralMatrix& hessian = *HessianPtr_; - GeneralMatrix& jacCopy = *jacCopyPtr_; - hessian.zero(); - if (m_rowScaling) { - for (size_t i = 0; i < neq_; i++) { - for (size_t j = i; j < neq_; j++) { - for (size_t k = 0; k < neq_; k++) { - hessian(i,j) += jacCopy(k,i) * jacCopy(k,j) * m_rowScales[k] * m_rowScales[k]; - } - hessian(j,i) = hessian(i,j); - } - } - } else { - for (size_t i = 0; i < neq_; i++) { - for (size_t j = i; j < neq_; j++) { - for (size_t k = 0; k < neq_; k++) { - hessian(i,j) += jacCopy(k,i) * jacCopy(k,j); - } - hessian(j,i) = hessian(i,j); - } - } - } - - /* - * Calculate the matrix norm of the Hessian - */ - doublereal hnorm = 0.0; - doublereal hcol = 0.0; - if (m_colScaling) { - for (size_t i = 0; i < neq_; i++) { - for (size_t j = i; j < neq_; j++) { - hcol += fabs(hessian(j,i)) * m_colScales[j]; - } - for (size_t j = i+1; j < neq_; j++) { - hcol += fabs(hessian(i,j)) * m_colScales[j]; - } - hcol *= m_colScales[i]; - if (hcol > hnorm) { - hnorm = hcol; - } - } - } else { - for (size_t i = 0; i < neq_; i++) { - for (size_t j = i; j < neq_; j++) { - hcol += fabs(hessian(j,i)); - } - for (size_t j = i+1; j < neq_; j++) { - hcol += fabs(hessian(i,j)); - } - if (hcol > hnorm) { - hnorm = hcol; - } - } - } - /* - * Add junk to the Hessian diagonal - * -> Note, testing indicates that this will get too big for ill-conditioned systems. - */ - hcol = sqrt(1.0*neq_) * 1.0E-7 * hnorm; + /* + * Calculate the matrix norm of the Hessian + */ + doublereal hnorm = 0.0; + doublereal hcol = 0.0; + if (m_colScaling) { + for (int i = 0; i < neq_; i++) { + for (int j = i; j < neq_; j++) { + hcol += fabs(hessian(j,i)) * m_colScales[j]; + } + for (int j = i+1; j < neq_; j++) { + hcol += fabs(hessian(i,j)) * m_colScales[j]; + } + hcol *= m_colScales[i]; + if (hcol > hnorm) { + hnorm = hcol; + } + } + } else { + for (int i = 0; i < neq_; i++) { + for (int j = i; j < neq_; j++) { + hcol += fabs(hessian(j,i)); + } + for (int j = i+1; j < neq_; j++) { + hcol += fabs(hessian(i,j)); + } + if (hcol > hnorm) { + hnorm = hcol; + } + } + } + /* + * Add junk to the Hessian diagonal + * -> Note, testing indicates that this will get too big for ill-conditioned systems. + */ + hcol = sqrt(neq_) * 1.0E-7 * hnorm; #ifdef DEBUG_HKM_NOT - if (hcol > 1.0) { - hcol = 1.0E1; - } + if (hcol > 1.0) { + hcol = 1.0E1; + } #endif - if (m_colScaling) { - for (size_t i = 0; i < neq_; i++) { - hessian(i,i) += hcol / (m_colScales[i] * m_colScales[i]); - } - } else { - for (size_t i = 0; i < neq_; i++) { - hessian(i,i) += hcol; - } - } + if (m_colScaling) { + for (int i = 0; i < neq_; i++) { + hessian(i,i) += hcol / (m_colScales[i] * m_colScales[i]); + } + } else { + for (int i = 0; i < neq_; i++) { + hessian(i,i) += hcol; + } + } - /* - * Factor the Hessian - */ - int info = 0; - ct_dpotrf(ctlapack::UpperTriangular, neq_, &(*(HessianPtr_->begin())), neq_, info); - if (info) { - if (m_print_flag >= 2) { - printf("\t\t doAffineNewtonSolve() ERROR: Hessian isn't positive definate DPOTRF returned INFO = %d\n", info); - } - return info; - } + /* + * Factor the Hessian + */ + int info; + ct_dpotrf(ctlapack::UpperTriangular, neq_, &(*(HessianPtr_->begin())), neq_, info); + if (info) { + if (m_print_flag >= 2) { + printf("\t\t doAffineNewtonSolve() ERROR: Hessian isn't positive definate DPOTRF returned INFO = %d\n", info); + } + return info; + } - // doublereal *JTF = delta_y; - doublereal* delyH = mdp::mdp_alloc_dbl_1((int) neq_, MDP_DBL_NOINIT); - // First recalculate the scaled residual. It got wiped out doing the newton solve - if (m_rowScaling) { - for (size_t n = 0; n < neq_; n++) { - delyH[n] = -m_rowScales[n] * m_resid[n]; - } - } else { - for (size_t n = 0; n < neq_; n++) { - delyH[n] = -m_resid[n]; - } - } + // doublereal *JTF = delta_y; + doublereal *delyH = mdp::mdp_alloc_dbl_1(neq_, MDP_DBL_NOINIT); + // First recalculate the scaled residual. It got wiped out doing the newton solve + if (m_rowScaling) { + for (int n = 0; n < neq_; n++) { + delyH[n] = -m_rowScales[n] * m_resid[n]; + } + } else { + for (int n = 0; n < neq_; n++) { + delyH[n] = -m_resid[n]; + } + } - if (m_rowScaling) { - for (size_t j = 0; j < neq_; j++) { - delta_y[j] = 0.0; - for (size_t i = 0; i < neq_; i++) { - delta_y[j] += delyH[i] * jacCopy(i,j) * m_rowScales[i]; - } - } - } else { - for (size_t j = 0; j < neq_; j++) { - delta_y[j] = 0.0; - for (size_t i = 0; i < neq_; i++) { - delta_y[j] += delyH[i] * jacCopy(i,j); - } - } - } + if (m_rowScaling) { + for (int j = 0; j < neq_; j++) { + delta_y[j] = 0.0; + for (int i = 0; i < neq_; i++) { + delta_y[j] += delyH[i] * jacCopy(i,j) * m_rowScales[i]; + } + } + } else { + for (int j = 0; j < neq_; j++) { + delta_y[j] = 0.0; + for (int i = 0; i < neq_; i++) { + delta_y[j] += delyH[i] * jacCopy(i,j); + } + } + } - /* - * Solve the factored Hessian System - */ - ct_dpotrs(ctlapack::UpperTriangular, neq_, 1,&(*(hessian.begin())), neq_, delta_y, neq_, info); - if (info) { - if (m_print_flag >= 2) { - printf("\t\t NonlinearSolver::doAffineNewtonSolve() ERROR: DPOTRS returned INFO = %d\n", info); - } - return info; - } - /* - * reverse the column scaling if there was any. - */ - if (m_colScaling) { - for (size_t irow = 0; irow < neq_; irow++) { - delta_y[irow] = delta_y[irow] * m_colScales[irow]; - } - } + + /* + * Solve the factored Hessian System + */ + ct_dpotrs(ctlapack::UpperTriangular, neq_, 1,&(*(hessian.begin())), neq_, delta_y, neq_, info); + if (info) { + if (m_print_flag >= 2) { + printf("\t\t NonlinearSolver::doAffineNewtonSolve() ERROR: DPOTRS returned INFO = %d\n", info); + } + return info; + } + /* + * reverse the column scaling if there was any. + */ + if (m_colScaling) { + for (irow = 0; irow < neq_; irow++) { + delta_y[irow] = delta_y[irow] * m_colScales[irow]; + } + } - if (doDogLeg_ && m_print_flag > 7) { - double normNewt = solnErrorNorm(CONSTD_DATA_PTR(delyNewton)); - double normHess = solnErrorNorm(CONSTD_DATA_PTR(delta_y)); - printf("\t\t doAffineNewtonSolve(): Printout Comparison between Hessian deltaX and Newton deltaX\n"); + if (doDogLeg_ && m_print_flag > 7) { + double normNewt = solnErrorNorm(CONSTD_DATA_PTR(delyNewton)); + double normHess = solnErrorNorm(CONSTD_DATA_PTR(delta_y)); + printf("\t\t doAffineNewtonSolve(): Printout Comparison between Hessian deltaX and Newton deltaX\n"); + + printf("\t\t I Hessian+Junk Newton"); + if (newtonGood || s_alwaysAssumeNewtonGood) { + printf(" (USING NEWTON DIRECTION)\n"); + } else { + printf(" (USING HESSIAN DIRECTION)\n"); + } + printf("\t\t Norm: %12.4E %12.4E\n", normHess, normNewt); + + printf("\t\t --------------------------------------------------------\n"); + for (int i =0; i < neq_; i++) { + printf("\t\t %3d %13.5E %13.5E\n", i, delta_y[i], delyNewton[i]); + } + printf("\t\t --------------------------------------------------------\n"); + } else if (doDogLeg_ && m_print_flag >= 4) { + double normNewt = solnErrorNorm(CONSTD_DATA_PTR(delyNewton)); + double normHess = solnErrorNorm(CONSTD_DATA_PTR(delta_y)); + printf("\t\t doAffineNewtonSolve(): Hessian update norm = %12.4E \n" + "\t\t Newton update norm = %12.4E \n", normHess, normNewt); + if (newtonGood || s_alwaysAssumeNewtonGood) { + printf("\t\t (USING NEWTON DIRECTION)\n"); + } else { + printf("\t\t (USING HESSIAN DIRECTION)\n"); + } + } - printf("\t\t I Hessian+Junk Newton"); - if (newtonGood || s_alwaysAssumeNewtonGood) { - printf(" (USING NEWTON DIRECTION)\n"); - } else { - printf(" (USING HESSIAN DIRECTION)\n"); - } - printf("\t\t Norm: %12.4E %12.4E\n", normHess, normNewt); - - printf("\t\t --------------------------------------------------------\n"); - for (size_t i =0; i < neq_; i++) { - printf("\t\t %3s %13.5E %13.5E\n", - int2str(i).c_str(), delta_y[i], delyNewton[i]); - } - printf("\t\t --------------------------------------------------------\n"); - } else if (doDogLeg_ && m_print_flag >= 4) { - double normNewt = solnErrorNorm(CONSTD_DATA_PTR(delyNewton)); - double normHess = solnErrorNorm(CONSTD_DATA_PTR(delta_y)); - printf("\t\t doAffineNewtonSolve(): Hessian update norm = %12.4E \n" - "\t\t Newton update norm = %12.4E \n", normHess, normNewt); - if (newtonGood || s_alwaysAssumeNewtonGood) { - printf("\t\t (USING NEWTON DIRECTION)\n"); - } else { - printf("\t\t (USING HESSIAN DIRECTION)\n"); - } - } - - /* - * Choose the delta_y to use - */ - if (newtonGood || s_alwaysAssumeNewtonGood) { - mdp::mdp_copy_dbl_1(DATA_PTR(delta_y), CONSTD_DATA_PTR(delyNewton), (int) neq_); - } - mdp::mdp_safe_free((void**) &delyH); - mdp::mdp_safe_free((void**) &delyNewton); + /* + * Choose the delta_y to use + */ + if (newtonGood || s_alwaysAssumeNewtonGood) { + mdp::mdp_copy_dbl_1(DATA_PTR(delta_y), CONSTD_DATA_PTR(delyNewton), neq_); + } + mdp::mdp_safe_free((void **) &delyH); + mdp::mdp_safe_free((void **) &delyNewton); } - + #ifdef DEBUG_JAC if (printJacContributions) { - for (int iNum = 0; iNum < numRows; iNum++) { - if (iNum > 0) { - focusRow++; - } - doublereal dsum = 0.0; - vector_fp& Jdata = jacBack.data(); - doublereal dRow = Jdata[neq_ * focusRow + focusRow]; - printf("\n Details on delta_Y for row %d \n", focusRow); - printf(" Value before = %15.5e, delta = %15.5e," - "value after = %15.5e\n", y_curr[focusRow], - delta_y[focusRow], y_curr[focusRow] + delta_y[focusRow]); - if (!freshJac) { - printf(" Old Jacobian\n"); - } - printf(" col delta_y aij " - "contrib \n"); - printf("-----------------------------------------------------------------------------------------------\n"); - printf(" Res(%d) %15.5e %15.5e %15.5e (Res = %g)\n", - focusRow, delta_y[focusRow], - dRow, RRow[iNum] / dRow, RRow[iNum]); - dsum += RRow[iNum] / dRow; - for (int ii = 0; ii < neq_; ii++) { - if (ii != focusRow) { - doublereal aij = Jdata[neq_ * ii + focusRow]; - doublereal contrib = aij * delta_y[ii] * (-1.0) / dRow; - dsum += contrib; - if (fabs(contrib) > Pcutoff) { - printf("%6d %15.5e %15.5e %15.5e\n", ii, - delta_y[ii] , aij, contrib); - } - } - } - printf("-----------------------------------------------------------------------------------------------\n"); - printf(" %15.5e %15.5e\n", - delta_y[focusRow], dsum); - } + for (int iNum = 0; iNum < numRows; iNum++) { + if (iNum > 0) focusRow++; + doublereal dsum = 0.0; + vector_fp& Jdata = jacBack.data(); + doublereal dRow = Jdata[neq_ * focusRow + focusRow]; + printf("\n Details on delta_Y for row %d \n", focusRow); + printf(" Value before = %15.5e, delta = %15.5e," + "value after = %15.5e\n", y_curr[focusRow], + delta_y[focusRow], y_curr[focusRow] + delta_y[focusRow]); + if (!freshJac) { + printf(" Old Jacobian\n"); + } + printf(" col delta_y aij " + "contrib \n"); + printf("-----------------------------------------------------------------------------------------------\n"); + printf(" Res(%d) %15.5e %15.5e %15.5e (Res = %g)\n", + focusRow, delta_y[focusRow], + dRow, RRow[iNum] / dRow, RRow[iNum]); + dsum += RRow[iNum] / dRow; + for (int ii = 0; ii < neq_; ii++) { + if (ii != focusRow) { + doublereal aij = Jdata[neq_ * ii + focusRow]; + doublereal contrib = aij * delta_y[ii] * (-1.0) / dRow; + dsum += contrib; + if (fabs(contrib) > Pcutoff) { + printf("%6d %15.5e %15.5e %15.5e\n", ii, + delta_y[ii] , aij, contrib); + } + } + } + printf("-----------------------------------------------------------------------------------------------\n"); + printf(" %15.5e %15.5e\n", + delta_y[focusRow], dsum); + } } #endif - - m_numTotalLinearSolves++; + + m_numTotalLinearSolves++; m_numLocalLinearSolves++; return info; -} -//==================================================================================================================== -// Do a steepest descent calculation -/* - * This call must be made on the unfactored jacobian! - */ -doublereal NonlinearSolver::doCauchyPointSolve(GeneralMatrix& jac) -{ + } + //==================================================================================================================== + // Do a steepest descent calculation + /* + * This call must be made on the unfactored jacobian! + */ + doublereal NonlinearSolver::doCauchyPointSolve(GeneralMatrix& jac) + { doublereal rowFac = 1.0; doublereal colFac = 1.0; doublereal normSoln; // Calculate the descent direction /* * For confirmation of the scaling factors, see Dennis and Schnabel p, 152, p, 156 and my notes - * - * The colFac and rowFac values are used to eliminate the scaling of the matrix from the + * + * The colFac and rowFac values are used to eliminate the scaling of the matrix from the * actual equation * * Here we calculate the steepest descent direction. This is equation (11) in the notes. It is - * stored in deltaX_CP_[].The value corresponds to d_descent[]. + * storred in deltaX_CP_[].The value corresponds to d_descent[]. */ - for (size_t j = 0; j < neq_; j++) { - deltaX_CP_[j] = 0.0; - if (m_colScaling) { - colFac = 1.0 / m_colScales[j]; - } - for (size_t i = 0; i < neq_; i++) { - if (m_rowScaling) { - rowFac = 1.0 / m_rowScales[i]; - } - deltaX_CP_[j] -= m_resid[i] * jac(i,j) * colFac * rowFac * m_ewt[j] * m_ewt[j] - / (m_residWts[i] * m_residWts[i]); + for (int j = 0; j < neq_; j++) { + deltaX_CP_[j] = 0.0; + if (m_colScaling) { + colFac = 1.0 / m_colScales[j]; + } + for (int i = 0; i < neq_; i++) { + if (m_rowScaling) { + rowFac = 1.0 / m_rowScales[i]; + } + deltaX_CP_[j] -= m_resid[i] * jac(i,j) * colFac * rowFac * m_ewt[j] * m_ewt[j] + / (m_residWts[i] * m_residWts[i]); #ifdef DEBUG_MODE - mdp::checkFinite(deltaX_CP_[j]); + mdp::checkFinite(deltaX_CP_[j]); #endif - } + } } /* * Calculate J_hat d_y_descent. This is formula 18 in the notes. */ - for (size_t i = 0; i < neq_; i++) { - Jd_[i] = 0.0; - if (m_rowScaling) { - rowFac = 1.0 / m_rowScales[i]; - } else { - rowFac = 1.0; - } - for (size_t j = 0; j < neq_; j++) { - if (m_colScaling) { - colFac = 1.0 / m_colScales[j]; - } - Jd_[i] += deltaX_CP_[j] * jac(i,j) * rowFac * colFac / m_residWts[i]; + for (int i = 0; i < neq_; i++) { + Jd_[i] = 0.0; + if (m_rowScaling) { + rowFac = 1.0 / m_rowScales[i]; + } else { + rowFac = 1.0; + } + for (int j = 0; j < neq_; j++) { + if (m_colScaling) { + colFac = 1.0 / m_colScales[j]; } + Jd_[i] += deltaX_CP_[j] * jac(i,j) * rowFac * colFac / m_residWts[i]; + } } /* @@ -1457,30 +1472,30 @@ doublereal NonlinearSolver::doCauchyPointSolve(GeneralMatrix& jac) */ RJd_norm_ = 0.0; JdJd_norm_ = 0.0; - for (size_t i = 0; i < neq_; i++) { - RJd_norm_ += m_resid[i] * Jd_[i] / m_residWts[i]; - JdJd_norm_ += Jd_[i] * Jd_[i]; + for (int i = 0; i < neq_; i++) { + RJd_norm_ += m_resid[i] * Jd_[i] / m_residWts[i]; + JdJd_norm_ += Jd_[i] * Jd_[i]; } //if (RJd_norm_ > -1.0E-300) { // printf("we are here: zero residual\n"); //} if (fabs(JdJd_norm_) < 1.0E-290) { - if (fabs(RJd_norm_) < 1.0E-300) { - lambdaStar_ = 0.0; - } else { - throw CanteraError("NonlinearSolver::doCauchyPointSolve()", "Unexpected condition: norms are zero"); - } + if (fabs(RJd_norm_) < 1.0E-300) { + lambdaStar_ = 0.0; + } else { + throw CanteraError("NonlinearSolver::doCauchyPointSolve()", "Unexpected condition: norms are zero"); + } } else { - lambdaStar_ = - RJd_norm_ / (JdJd_norm_); + lambdaStar_ = - RJd_norm_ / (JdJd_norm_); } /* - * Now we modify the steepest descent vector such that its length is equal to the + * Now we modify the steepest descent vector such that its length is equal to the * Cauchy distance. From now on, if we want to recreate the descent vector, we have * to unnormalize it by dividing by lambdaStar_. */ - for (size_t i = 0; i < neq_; i++) { - deltaX_CP_[i] *= lambdaStar_; + for (int i = 0; i < neq_; i++) { + deltaX_CP_[i] *= lambdaStar_; } @@ -1490,83 +1505,84 @@ doublereal NonlinearSolver::doCauchyPointSolve(GeneralMatrix& jac) * Calculate the expected square of the risdual at the Cauchy point if the linear model is correct */ if (fabs(JdJd_norm_) < 1.0E-290) { - residNorm2Cauchy_ = normResid02; + residNorm2Cauchy_ = normResid02; } else { - residNorm2Cauchy_ = normResid02 - RJd_norm_ * RJd_norm_ / (JdJd_norm_); + residNorm2Cauchy_ = normResid02 - RJd_norm_ * RJd_norm_ / (JdJd_norm_); } // Extra printout section if (m_print_flag > 2) { - // Calculate the expected residual at the Cauchy point if the linear model is correct - doublereal residCauchy = 0.0; - if (residNorm2Cauchy_ > 0.0) { - residCauchy = sqrt(residNorm2Cauchy_ / neq_); - } else { - if (fabs(JdJd_norm_) < 1.0E-290) { - residCauchy = m_normResid_0; - } else { - residCauchy = m_normResid_0 - sqrt(RJd_norm_ * RJd_norm_ / (JdJd_norm_)); - } - } - // Compute the weighted norm of the undamped step size descentDir_[] - if ((s_print_DogLeg || doDogLeg_) && m_print_flag >= 6) { - normSoln = solnErrorNorm(DATA_PTR(deltaX_CP_), "SteepestDescentDir", 10); - } else { - normSoln = solnErrorNorm(DATA_PTR(deltaX_CP_), "SteepestDescentDir", 0); - } - if ((s_print_DogLeg || doDogLeg_) && m_print_flag >= 5) { - printf("\t\t doCauchyPointSolve: Steepest descent to Cauchy point: \n"); - printf("\t\t\t R0 = %g \n", m_normResid_0); - printf("\t\t\t Rpred = %g\n", residCauchy); - printf("\t\t\t Rjd = %g\n", RJd_norm_); - printf("\t\t\t JdJd = %g\n", JdJd_norm_); - printf("\t\t\t deltaX = %g\n", normSoln); - printf("\t\t\t lambda = %g\n", lambdaStar_); - } + // Calculate the expected residual at the Cauchy point if the linear model is correct + doublereal residCauchy = 0.0; + if (residNorm2Cauchy_ > 0.0) { + residCauchy = sqrt(residNorm2Cauchy_ / neq_); + } else { + if (fabs(JdJd_norm_) < 1.0E-290) { + residCauchy = m_normResid_0; + } else { + residCauchy = m_normResid_0 - sqrt(RJd_norm_ * RJd_norm_ / (JdJd_norm_)); + } + } + // Compute the weighted norm of the undamped step size descentDir_[] + if ((s_print_DogLeg || doDogLeg_) && m_print_flag >= 6) { + normSoln = solnErrorNorm(DATA_PTR(deltaX_CP_), "SteepestDescentDir", 10); + } else { + normSoln = solnErrorNorm(DATA_PTR(deltaX_CP_), "SteepestDescentDir", 0); + } + if ((s_print_DogLeg || doDogLeg_) && m_print_flag >= 5) { + printf("\t\t doCauchyPointSolve: Steepest descent to Cauchy point: \n"); + printf("\t\t\t R0 = %g \n", m_normResid_0); + printf("\t\t\t Rpred = %g\n", residCauchy); + printf("\t\t\t Rjd = %g\n", RJd_norm_); + printf("\t\t\t JdJd = %g\n", JdJd_norm_); + printf("\t\t\t deltaX = %g\n", normSoln); + printf("\t\t\t lambda = %g\n", lambdaStar_); + } } else { - // Calculate the norm of the Cauchy solution update in any case - normSoln = solnErrorNorm(DATA_PTR(deltaX_CP_), "SteepestDescentDir", 0); + // Calculate the norm of the Cauchy solution update in any case + normSoln = solnErrorNorm(DATA_PTR(deltaX_CP_), "SteepestDescentDir", 0); } return normSoln; -} -//=================================================================================================================== -void NonlinearSolver::descentComparison(doublereal time_curr, doublereal* ydot0, doublereal* ydot1, int& numTrials) -{ + } + //=================================================================================================================== + void NonlinearSolver::descentComparison(doublereal time_curr, doublereal *ydot0, doublereal *ydot1, int &numTrials) + { + int info; doublereal ff = 1.0E-5; doublereal ffNewt = 1.0E-5; - doublereal* y_n_1 = DATA_PTR(m_wksp); + doublereal *y_n_1 = DATA_PTR(m_wksp); doublereal cauchyDistanceNorm = solnErrorNorm(DATA_PTR(deltaX_CP_)); if (cauchyDistanceNorm < 1.0E-2) { - ff = 1.0E-9 / cauchyDistanceNorm; - if (ff > 1.0E-2) { - ff = 1.0E-2; - } + ff = 1.0E-9 / cauchyDistanceNorm; + if (ff > 1.0E-2) { + ff = 1.0E-2; + } } - for (size_t i = 0; i < neq_; i++) { - y_n_1[i] = m_y_n_curr[i] + ff * deltaX_CP_[i]; + for (int i = 0; i < neq_; i++) { + y_n_1[i] = m_y_n_curr[i] + ff * deltaX_CP_[i]; } /* * Calculate the residual that would result if y1[] were the new solution vector * -> m_resid[] contains the result of the residual calculation */ if (solnType_ != NSOLN_TYPE_STEADY_STATE) { - doResidualCalc(time_curr, solnType_, y_n_1, ydot1, Base_LaggedSolutionComponents); + info = doResidualCalc(time_curr, solnType_, y_n_1, ydot1, Base_LaggedSolutionComponents); } else { - doResidualCalc(time_curr, solnType_, y_n_1, ydot0, Base_LaggedSolutionComponents); - } + info = doResidualCalc(time_curr, solnType_, y_n_1, ydot0, Base_LaggedSolutionComponents); + } doublereal normResid02 = m_normResid_0 * m_normResid_0 * neq_; doublereal residSteep = residErrorNorm(DATA_PTR(m_resid)); doublereal residSteep2 = residSteep * residSteep * neq_; - doublereal funcDecreaseSD = 0.5 * (residSteep2 - normResid02) / (ff * cauchyDistanceNorm); + doublereal funcDecreaseSD = 0.5 * (residSteep2 - normResid02) / ( ff * cauchyDistanceNorm); doublereal sNewt = solnErrorNorm(DATA_PTR(deltaX_Newton_)); if (sNewt > 1.0) { - ffNewt = ffNewt / sNewt; + ffNewt = ffNewt / sNewt; } - for (size_t i = 0; i < neq_; i++) { - y_n_1[i] = m_y_n_curr[i] + ffNewt * deltaX_Newton_[i]; + for (int i = 0; i < neq_; i++) { + y_n_1[i] = m_y_n_curr[i] + ffNewt * deltaX_Newton_[i]; } /* * Calculate the residual that would result if y1[] were the new solution vector. @@ -1576,31 +1592,31 @@ void NonlinearSolver::descentComparison(doublereal time_curr, doublereal* ydot0 * -> m_resid[] contains the result of the residual calculation */ if (solnType_ != NSOLN_TYPE_STEADY_STATE) { - doResidualCalc(time_curr, solnType_, y_n_1, ydot1, Base_LaggedSolutionComponents); + info = doResidualCalc(time_curr, solnType_, y_n_1, ydot1, Base_LaggedSolutionComponents); } else { - doResidualCalc(time_curr, solnType_, y_n_1, ydot0, Base_LaggedSolutionComponents); - } + info = doResidualCalc(time_curr, solnType_, y_n_1, ydot0, Base_LaggedSolutionComponents); + } doublereal residNewt = residErrorNorm(DATA_PTR(m_resid)); doublereal residNewt2 = residNewt * residNewt * neq_; - doublereal funcDecreaseNewt2 = 0.5 * (residNewt2 - normResid02) / (ffNewt * sNewt); + doublereal funcDecreaseNewt2 = 0.5 * (residNewt2 - normResid02) / ( ffNewt * sNewt); - // This is the expected initial rate of decrease in the Cauchy direction. + // This is the expected inital rate of decrease in the Cauchy direction. // -> This is Eqn. 29 = Rhat dot Jhat dy / || d || doublereal funcDecreaseSDExp = RJd_norm_ / cauchyDistanceNorm * lambdaStar_; doublereal funcDecreaseNewtExp2 = - normResid02 / sNewt; - if (m_normResid_0 > 1.0E-100) { - ResidDecreaseSDExp_ = funcDecreaseSDExp / neq_ / m_normResid_0; - ResidDecreaseSD_ = funcDecreaseSD / neq_ / m_normResid_0; - ResidDecreaseNewtExp_ = funcDecreaseNewtExp2 / neq_ / m_normResid_0; - ResidDecreaseNewt_ = funcDecreaseNewt2 / neq_ / m_normResid_0; + if ( m_normResid_0 > 1.0E-100) { + ResidDecreaseSDExp_ = funcDecreaseSDExp / neq_ / m_normResid_0; + ResidDecreaseSD_ = funcDecreaseSD / neq_ / m_normResid_0; + ResidDecreaseNewtExp_ = funcDecreaseNewtExp2 / neq_ / m_normResid_0; + ResidDecreaseNewt_ = funcDecreaseNewt2 / neq_ / m_normResid_0; } else { - ResidDecreaseSDExp_ = 0.0; - ResidDecreaseSD_ = funcDecreaseSD / neq_; - ResidDecreaseNewtExp_ = 0.0; - ResidDecreaseNewt_ = funcDecreaseNewt2 / neq_; + ResidDecreaseSDExp_ = 0.0; + ResidDecreaseSD_ = funcDecreaseSD / neq_; + ResidDecreaseNewtExp_ = 0.0; + ResidDecreaseNewt_ = funcDecreaseNewt2 / neq_; } numTrials += 2; @@ -1609,64 +1625,64 @@ void NonlinearSolver::descentComparison(doublereal time_curr, doublereal* ydot0 * The steepest direction is always largest even when there are variable solution weights * * HKM When a hessian is used with junk on the diagonal, funcDecreaseNewtExp2 is no longer accurate as the - * direction gets significantly shorter with increasing condition number. This suggests an algorithm where the + * direction gets signficantly shorter with increasing condition number. This suggests an algorithm where the * newton step from the Hessian should be increased so as to match funcDecreaseNewtExp2 = funcDecreaseNewt2. * This roughly equals the ratio of the norms of the hessian and newton steps. This increased Newton step can - * then be used with the trust region double dogleg algorithm. + * then be used with the trust region double dogleg algorithm. */ if ((s_print_DogLeg && m_print_flag >= 3) || (doDogLeg_ && m_print_flag >= 5)) { - printf("\t\t descentComparison: initial rate of decrease of func in cauchy dir (expected) = %g\n", funcDecreaseSDExp); - printf("\t\t descentComparison: initial rate of decrease of func in cauchy dir = %g\n", funcDecreaseSD); - printf("\t\t descentComparison: initial rate of decrease of func in newton dir (expected) = %g\n", funcDecreaseNewtExp2); - printf("\t\t descentComparison: initial rate of decrease of func in newton dir = %g\n", funcDecreaseNewt2); + printf("\t\t descentComparison: initial rate of decrease of func in cauchy dir (expected) = %g\n", funcDecreaseSDExp); + printf("\t\t descentComparison: initial rate of decrease of func in cauchy dir = %g\n", funcDecreaseSD); + printf("\t\t descentComparison: initial rate of decrease of func in newton dir (expected) = %g\n", funcDecreaseNewtExp2); + printf("\t\t descentComparison: initial rate of decrease of func in newton dir = %g\n", funcDecreaseNewt2); } if ((s_print_DogLeg && m_print_flag >= 3) || (doDogLeg_ && m_print_flag >= 4)) { - printf("\t\t descentComparison: initial rate of decrease of Resid in cauchy dir (expected) = %g\n", ResidDecreaseSDExp_); - printf("\t\t descentComparison: initial rate of decrease of Resid in cauchy dir = %g\n", ResidDecreaseSD_); - printf("\t\t descentComparison: initial rate of decrease of Resid in newton dir (expected) = %g\n", ResidDecreaseNewtExp_); - printf("\t\t descentComparison: initial rate of decrease of Resid in newton dir = %g\n", ResidDecreaseNewt_); + printf("\t\t descentComparison: initial rate of decrease of Resid in cauchy dir (expected) = %g\n", ResidDecreaseSDExp_); + printf("\t\t descentComparison: initial rate of decrease of Resid in cauchy dir = %g\n", ResidDecreaseSD_); + printf("\t\t descentComparison: initial rate of decrease of Resid in newton dir (expected) = %g\n", ResidDecreaseNewtExp_); + printf("\t\t descentComparison: initial rate of decrease of Resid in newton dir = %g\n", ResidDecreaseNewt_); } if ((s_print_DogLeg && m_print_flag >= 5) || (doDogLeg_ && m_print_flag >= 5)) { - if (funcDecreaseNewt2 >= 0.0) { - printf("\t\t %13.5E %22.16E\n", funcDecreaseNewtExp2, m_normResid_0); - double ff = ffNewt * 1.0E-5; - for (int ii = 0; ii < 13; ii++) { - ff *= 10.; - if (ii == 12) { - ff = ffNewt; - } - for (size_t i = 0; i < neq_; i++) { - y_n_1[i] = m_y_n_curr[i] + ff * deltaX_Newton_[i]; - } - numTrials += 1; - if (solnType_ != NSOLN_TYPE_STEADY_STATE) { - doResidualCalc(time_curr, solnType_, y_n_1, ydot1, Base_LaggedSolutionComponents); - } else { - doResidualCalc(time_curr, solnType_, y_n_1, ydot0, Base_LaggedSolutionComponents); - } - residNewt = residErrorNorm(DATA_PTR(m_resid)); - residNewt2 = residNewt * residNewt * neq_; - funcDecreaseNewt2 = 0.5 * (residNewt2 - normResid02) / (ff * sNewt); - printf("\t\t %10.3E %13.5E %22.16E\n", ff, funcDecreaseNewt2, residNewt); - } + if (funcDecreaseNewt2 >= 0.0) { + printf("\t\t %13.5E %22.16E\n", funcDecreaseNewtExp2, m_normResid_0); + double ff = ffNewt * 1.0E-5; + for (int ii = 0; ii < 13; ii++) { + ff *= 10.; + if (ii == 12) { + ff = ffNewt; + } + for (int i = 0; i < neq_; i++) { + y_n_1[i] = m_y_n_curr[i] + ff * deltaX_Newton_[i]; + } + numTrials += 1; + if (solnType_ != NSOLN_TYPE_STEADY_STATE) { + info = doResidualCalc(time_curr, solnType_, y_n_1, ydot1, Base_LaggedSolutionComponents); + } else { + info = doResidualCalc(time_curr, solnType_, y_n_1, ydot0, Base_LaggedSolutionComponents); + } + residNewt = residErrorNorm(DATA_PTR(m_resid)); + residNewt2 = residNewt * residNewt * neq_; + funcDecreaseNewt2 = 0.5 * (residNewt2 - normResid02) / ( ff * sNewt); + printf("\t\t %10.3E %13.5E %22.16E\n", ff, funcDecreaseNewt2, residNewt ); + } - } + } - } + } -} + } -//==================================================================================================================== -// Setup the parameters for the double dog leg -/* - * The calls to the doCauchySolve() and doNewtonSolve() routines are done at the main level. This routine comes - * after those calls. We calculate the point Nuu_ here, the distances of the dog-legs, - * and the norms of the CP and Newton points in terms of the trust vectors. - */ -void NonlinearSolver::setupDoubleDogleg() -{ + //==================================================================================================================== + // Setup the parameters for the double dog leg + /* + * The calls to the doCauchySolve() and doNewtonSolve() routines are done at the main level. This routine comes + * after those calls. We calculate the point Nuu_ here, the distances of the dog-legs, + * and the norms of the CP and Newton points in terms of the trust vectors. + */ + void NonlinearSolver::setupDoubleDogleg() + { /* * Gamma = ||grad f ||**4 * --------------------------------------------- @@ -1707,8 +1723,8 @@ void NonlinearSolver::setupDoubleDogleg() Nuu_ = beta; dist_R0_ = m_normDeltaSoln_CP; - for (size_t i = 0; i < neq_; i++) { - m_wksp[i] = Nuu_ * deltaX_Newton_[i] - deltaX_CP_[i]; + for (int i = 0; i < neq_; i++) { + m_wksp[i] = Nuu_ * deltaX_Newton_[i] - deltaX_CP_[i]; } dist_R1_ = solnErrorNorm(DATA_PTR(m_wksp)); dist_R2_ = (1.0 - Nuu_) * m_normDeltaSoln_Newton; @@ -1720,114 +1736,111 @@ void NonlinearSolver::setupDoubleDogleg() normTrust_Newton_ = calcTrustDistance(deltaX_Newton_); normTrust_CP_ = calcTrustDistance(deltaX_CP_); -} -//==================================================================================================================== -// Change the global lambda coordinate into the (leg,alpha) coordinate for the double dogleg -/* - * @param lambda Global value of the distance along the double dogleg - * @param alpha relative value along the particular leg - * - * @return Returns the leg number ( 0, 1, or 2). - */ -int NonlinearSolver::lambdaToLeg(const doublereal lambda, doublereal& alpha) const -{ + } + //==================================================================================================================== + // Change the global lambda coordinate into the (leg,alpha) coordinate for the double dogleg + /* + * @param lambda Global value of the distance along the double dogleg + * @param alpha relative value along the particular leg + * + * @return Returns the leg number ( 0, 1, or 2). + */ + int NonlinearSolver::lambdaToLeg(const doublereal lambda, doublereal &alpha) const { if (lambda < dist_R0_ / dist_Total_) { - alpha = lambda * dist_Total_ / dist_R0_; - return 0; + alpha = lambda * dist_Total_ / dist_R0_; + return 0; } else if (lambda < ((dist_R0_ + dist_R1_)/ dist_Total_)) { - alpha = (lambda * dist_Total_ - dist_R0_) / dist_R1_; - return 1; - } + alpha = (lambda * dist_Total_ - dist_R0_) / dist_R1_; + return 1; + } alpha = (lambda * dist_Total_ - dist_R0_ - dist_R1_) / dist_R2_; return 2; -} -//==================================================================================================================== -// Calculated the expected residual along the double dogleg curve. -/* - * @param leg 0, 1, or 2 representing the curves of the dogleg - * @param alpha Relative distance along the particular curve. - * - * @return Returns the expected value of the residual at that point according to the quadratic model. - * The residual at the newton point will always be zero. - */ -doublereal NonlinearSolver::expectedResidLeg(int leg, doublereal alpha) const -{ + } + //==================================================================================================================== + // Calculated the expected residual along the double dogleg curve. + /* + * @param leg 0, 1, or 2 representing the curves of the dogleg + * @param alpha Relative distance along the particular curve. + * + * @return Returns the expected value of the residual at that point according to the quadratic model. + * The residual at the newton point will always be zero. + */ + doublereal NonlinearSolver::expectedResidLeg(int leg, doublereal alpha) const { doublereal resD2, res2, resNorm; doublereal normResid02 = m_normResid_0 * m_normResid_0 * neq_; if (leg == 0) { - /* - * We are on the steepest descent line - * along that line - * R2 = R2 + 2 lambda R dot Jd + lambda**2 Jd dot Jd - */ + /* + * We are on the steepest descent line + * along that line + * R2 = R2 + 2 lambda R dot Jd + lambda**2 Jd dot Jd + */ - doublereal tmp = - 2.0 * alpha + alpha * alpha; - doublereal tmp2 = - RJd_norm_ * lambdaStar_; - resD2 = tmp2 * tmp; + doublereal tmp = - 2.0 * alpha + alpha * alpha; + doublereal tmp2 = - RJd_norm_ * lambdaStar_; + resD2 = tmp2 * tmp; } else if (leg == 1) { - /* - * Same formula as above for lambda=1. - */ - doublereal tmp2 = - RJd_norm_ * lambdaStar_; - doublereal RdotJS = - tmp2; - doublereal JsJs = tmp2; + /* + * Same formula as above for lambda=1. + */ + doublereal tmp2 = - RJd_norm_ * lambdaStar_; + doublereal RdotJS = - tmp2; + doublereal JsJs = tmp2; - doublereal res0_2 = m_normResid_0 * m_normResid_0 * neq_; + doublereal res0_2 = m_normResid_0 * m_normResid_0 * neq_; - res2 = res0_2 + (1.0 - alpha) * 2 * RdotJS - 2 * alpha * Nuu_ * res0_2 - + (1.0 - alpha) * (1.0 - alpha) * JsJs - + alpha * alpha * Nuu_ * Nuu_ * res0_2 - - 2 * alpha * Nuu_ * (1.0 - alpha) * RdotJS; + res2 = res0_2 + (1.0 - alpha) * 2 * RdotJS - 2 * alpha * Nuu_ * res0_2 + + (1.0 - alpha) * (1.0 - alpha) * JsJs + + alpha * alpha * Nuu_ * Nuu_ * res0_2 + - 2 * alpha * Nuu_ * (1.0 - alpha) * RdotJS; - resNorm = sqrt(res2 / neq_); - return resNorm; + resNorm = sqrt(res2 / neq_); + return resNorm; } else { - doublereal beta = Nuu_ + alpha * (1.0 - Nuu_); - doublereal tmp2 = normResid02; - doublereal tmp = 1.0 - 2.0 * beta + 1.0 * beta * beta - 1.0; - resD2 = tmp * tmp2; + doublereal beta = Nuu_ + alpha * (1.0 - Nuu_); + doublereal tmp2 = normResid02; + doublereal tmp = 1.0 - 2.0 * beta + 1.0 * beta * beta - 1.0; + resD2 = tmp * tmp2; } res2 = m_normResid_0 * m_normResid_0 * neq_ + resD2; if (res2 < 0.0) { - resNorm = m_normResid_0 - sqrt(resD2/neq_); + resNorm = m_normResid_0 - sqrt(resD2/neq_); } else { - resNorm = sqrt(res2 / neq_); + resNorm = sqrt(res2 / neq_); } - + return resNorm; -} -//==================================================================================================================== -// Here we print out the residual at various points along the double dogleg, comparing against the quadratic model -// in a table format -/* - * @param time_curr INPUT current time - * @param ydot0 INPUT Current value of the derivative of the solution vector for non-time dependent - * determinations - * @param legBest OUTPUT leg of the dogleg that gives the lowest residual - * @param alphaBest OUTPUT distance along dogleg for best result. - */ -void NonlinearSolver::residualComparisonLeg(const doublereal time_curr, const doublereal* const ydot0, int& legBest, - doublereal& alphaBest) const -{ - doublereal* y1 = DATA_PTR(m_wksp); - doublereal* ydot1 = DATA_PTR(m_wksp_2); + } + //==================================================================================================================== + // Here we print out the residual at various points along the double dogleg, comparing against the quadratic model + // in a table format + /* + * @param time_curr INPUT current time + * @param ydot0 INPUT Current value of the derivative of the solution vector for non-time dependent + * determinations + * @param legBest OUTPUT leg of the dogleg that gives the lowest residual + * @param alphaBest OUTPUT distance along dogleg for best result. + */ + void NonlinearSolver::residualComparisonLeg(const doublereal time_curr, const doublereal * const ydot0, int &legBest, + doublereal &alphaBest) const { + doublereal *y1 = DATA_PTR(m_wksp); + doublereal *ydot1 = DATA_PTR(m_wksp_2); doublereal sLen; - doublereal alpha = 0; + doublereal alpha; doublereal residSteepBest = 1.0E300; doublereal residSteepLinBest = 0.0; if (s_print_DogLeg || (doDogLeg_ && m_print_flag > 6)) { - printf("\t\t residualComparisonLeg() \n"); - printf("\t\t Point StepLen Residual_Actual Residual_Linear RelativeMatch\n"); + printf("\t\t residualComparisonLeg() \n"); + printf("\t\t Point StepLen Residual_Actual Residual_Linear RelativeMatch\n"); } // First compare at 1/4 along SD curve std::vector alphaT; @@ -1838,305 +1851,304 @@ void NonlinearSolver::residualComparisonLeg(const doublereal time_curr, const do alphaT.push_back(0.50); alphaT.push_back(0.75); alphaT.push_back(1.0); - for (size_t iteration = 0; iteration < alphaT.size(); iteration++) { - alpha = alphaT[iteration]; - for (size_t i = 0; i < neq_; i++) { - y1[i] = m_y_n_curr[i] + alpha * deltaX_CP_[i]; - } - if (solnType_ != NSOLN_TYPE_STEADY_STATE) { - calc_ydot(m_order, y1, ydot1); - } - sLen = alpha * solnErrorNorm(DATA_PTR(deltaX_CP_)); - /* - * Calculate the residual that would result if y1[] were the new solution vector - * -> m_resid[] contains the result of the residual calculation - */ - if (solnType_ != NSOLN_TYPE_STEADY_STATE) { - doResidualCalc(time_curr, solnType_, y1, ydot1, Base_LaggedSolutionComponents); - } else { - doResidualCalc(time_curr, solnType_, y1, ydot0, Base_LaggedSolutionComponents); - } + for (int iteration = 0; iteration < (int) alphaT.size(); iteration++) { + alpha = alphaT[iteration]; + for (int i = 0; i < neq_; i++) { + y1[i] = m_y_n_curr[i] + alpha * deltaX_CP_[i]; + } + if (solnType_ != NSOLN_TYPE_STEADY_STATE) { + calc_ydot(m_order, y1, ydot1); + } + sLen = alpha * solnErrorNorm(DATA_PTR(deltaX_CP_)); + /* + * Calculate the residual that would result if y1[] were the new solution vector + * -> m_resid[] contains the result of the residual calculation + */ + if (solnType_ != NSOLN_TYPE_STEADY_STATE) { + doResidualCalc(time_curr, solnType_, y1, ydot1, Base_LaggedSolutionComponents); + } else { + doResidualCalc(time_curr, solnType_, y1, ydot0, Base_LaggedSolutionComponents); + } - doublereal residSteep = residErrorNorm(DATA_PTR(m_resid)); - doublereal residSteepLin = expectedResidLeg(0, alpha); - if (residSteep < residSteepBest) { - legBest = 0; - alphaBest = alpha; - residSteepBest = residSteep; - residSteepLinBest = residSteepLin; - } + doublereal residSteep = residErrorNorm(DATA_PTR(m_resid)); + doublereal residSteepLin = expectedResidLeg(0, alpha); + if (residSteep < residSteepBest) { + legBest = 0; + alphaBest = alpha; + residSteepBest = residSteep; + residSteepLinBest = residSteepLin; + } - doublereal relFit = (residSteep - residSteepLin) / (fabs(residSteepLin) + 1.0E-10); - if (s_print_DogLeg || (doDogLeg_ && m_print_flag > 6)) { - printf("\t\t (%2d - % 10.3g) % 15.8E % 15.8E % 15.8E % 15.8E\n", 0, alpha, sLen, residSteep, residSteepLin , relFit); - } + doublereal relFit = (residSteep - residSteepLin) / (fabs(residSteepLin) + 1.0E-10); + if (s_print_DogLeg || (doDogLeg_ && m_print_flag > 6)) { + printf("\t\t (%2d - % 10.3g) % 15.8E % 15.8E % 15.8E % 15.8E\n", 0, alpha, sLen, residSteep, residSteepLin , relFit); + } } - for (size_t iteration = 0; iteration < alphaT.size(); iteration++) { - doublereal alpha = alphaT[iteration]; - for (size_t i = 0; i < neq_; i++) { - y1[i] = m_y_n_curr[i] + (1.0 - alpha) * deltaX_CP_[i]; - y1[i] += alpha * Nuu_ * deltaX_Newton_[i]; - } - if (solnType_ != NSOLN_TYPE_STEADY_STATE) { - calc_ydot(m_order, y1, ydot1); - } - /* - * Calculate the residual that would result if y1[] were the new solution vector - * -> m_resid[] contains the result of the residual calculation - */ - if (solnType_ != NSOLN_TYPE_STEADY_STATE) { - doResidualCalc(time_curr, solnType_, y1, ydot1, Base_LaggedSolutionComponents); - } else { - doResidualCalc(time_curr, solnType_, y1, ydot0, Base_LaggedSolutionComponents); - } + for (int iteration = 0; iteration < (int) alphaT.size(); iteration++) { + doublereal alpha = alphaT[iteration]; + for (int i = 0; i < neq_; i++) { + y1[i] = m_y_n_curr[i] + (1.0 - alpha) * deltaX_CP_[i]; + y1[i] += alpha * Nuu_ * deltaX_Newton_[i]; + } + if (solnType_ != NSOLN_TYPE_STEADY_STATE) { + calc_ydot(m_order, y1, ydot1); + } + /* + * Calculate the residual that would result if y1[] were the new solution vector + * -> m_resid[] contains the result of the residual calculation + */ + if (solnType_ != NSOLN_TYPE_STEADY_STATE) { + doResidualCalc(time_curr, solnType_, y1, ydot1, Base_LaggedSolutionComponents); + } else { + doResidualCalc(time_curr, solnType_, y1, ydot0, Base_LaggedSolutionComponents); + } - for (size_t i = 0; i < neq_; i++) { - y1[i] -= m_y_n_curr[i]; - } - sLen = solnErrorNorm(DATA_PTR(y1)); + for (int i = 0; i < neq_; i++) { + y1[i] -= m_y_n_curr[i]; + } + sLen = solnErrorNorm(DATA_PTR(y1)); - doublereal residSteep = residErrorNorm(DATA_PTR(m_resid)); - doublereal residSteepLin = expectedResidLeg(1, alpha); - if (residSteep < residSteepBest) { - legBest = 1; - alphaBest = alpha; - residSteepBest = residSteep; - residSteepLinBest = residSteepLin; - } + doublereal residSteep = residErrorNorm(DATA_PTR(m_resid)); + doublereal residSteepLin = expectedResidLeg(1, alpha); + if (residSteep < residSteepBest) { + legBest = 1; + alphaBest = alpha; + residSteepBest = residSteep; + residSteepLinBest = residSteepLin; + } - doublereal relFit = (residSteep - residSteepLin) / (fabs(residSteepLin) + 1.0E-10); - if (s_print_DogLeg || (doDogLeg_ && m_print_flag > 6)) { - printf("\t\t (%2d - % 10.3g) % 15.8E % 15.8E % 15.8E % 15.8E\n", 1, alpha, sLen, residSteep, residSteepLin , relFit); - } + doublereal relFit = (residSteep - residSteepLin) / (fabs(residSteepLin) + 1.0E-10); + if (s_print_DogLeg || (doDogLeg_ && m_print_flag > 6)) { + printf("\t\t (%2d - % 10.3g) % 15.8E % 15.8E % 15.8E % 15.8E\n", 1, alpha, sLen, residSteep, residSteepLin , relFit); + } } - for (size_t iteration = 0; iteration < alphaT.size(); iteration++) { - doublereal alpha = alphaT[iteration]; - for (size_t i = 0; i < neq_; i++) { - y1[i] = m_y_n_curr[i] + (Nuu_ + alpha * (1.0 - Nuu_))* deltaX_Newton_[i]; - } - if (solnType_ != NSOLN_TYPE_STEADY_STATE) { - calc_ydot(m_order, y1, ydot1); - } - sLen = (Nuu_ + alpha * (1.0 - Nuu_)) * solnErrorNorm(DATA_PTR(deltaX_Newton_)); - /* - * Calculate the residual that would result if y1[] were the new solution vector - * -> m_resid[] contains the result of the residual calculation - */ - if (solnType_ != NSOLN_TYPE_STEADY_STATE) { - doResidualCalc(time_curr, solnType_, y1, ydot1, Base_LaggedSolutionComponents); - } else { - doResidualCalc(time_curr, solnType_, y1, ydot0, Base_LaggedSolutionComponents); - } + for (int iteration = 0; iteration < (int) alphaT.size(); iteration++) { + doublereal alpha = alphaT[iteration]; + for (int i = 0; i < neq_; i++) { + y1[i] = m_y_n_curr[i] + ( Nuu_ + alpha * (1.0 - Nuu_))* deltaX_Newton_[i]; + } + if (solnType_ != NSOLN_TYPE_STEADY_STATE) { + calc_ydot(m_order, y1, ydot1); + } + sLen = ( Nuu_ + alpha * (1.0 - Nuu_)) * solnErrorNorm(DATA_PTR(deltaX_Newton_)); + /* + * Calculate the residual that would result if y1[] were the new solution vector + * -> m_resid[] contains the result of the residual calculation + */ + if (solnType_ != NSOLN_TYPE_STEADY_STATE) { + doResidualCalc(time_curr, solnType_, y1, ydot1, Base_LaggedSolutionComponents); + } else { + doResidualCalc(time_curr, solnType_, y1, ydot0, Base_LaggedSolutionComponents); + } - doublereal residSteep = residErrorNorm(DATA_PTR(m_resid)); - doublereal residSteepLin = expectedResidLeg(2, alpha); - if (residSteep < residSteepBest) { - legBest = 2; - alphaBest = alpha; - residSteepBest = residSteep; - residSteepLinBest = residSteepLin; - } - doublereal relFit = (residSteep - residSteepLin) / (fabs(residSteepLin) + 1.0E-10); - if (s_print_DogLeg || (doDogLeg_ && m_print_flag > 6)) { - printf("\t\t (%2d - % 10.3g) % 15.8E % 15.8E % 15.8E % 15.8E\n", 2, alpha, sLen, residSteep, residSteepLin , relFit); - } + doublereal residSteep = residErrorNorm(DATA_PTR(m_resid)); + doublereal residSteepLin = expectedResidLeg(2, alpha); + if (residSteep < residSteepBest) { + legBest = 2; + alphaBest = alpha; + residSteepBest = residSteep; + residSteepLinBest = residSteepLin; + } + doublereal relFit = (residSteep - residSteepLin) / (fabs(residSteepLin) + 1.0E-10); + if (s_print_DogLeg || (doDogLeg_ && m_print_flag > 6)) { + printf("\t\t (%2d - % 10.3g) % 15.8E % 15.8E % 15.8E % 15.8E\n", 2, alpha, sLen, residSteep, residSteepLin , relFit); + } } if (s_print_DogLeg || (doDogLeg_ && m_print_flag > 6)) { - printf("\t\t Best Result: \n"); - doublereal relFit = (residSteepBest - residSteepLinBest) / (fabs(residSteepLinBest) + 1.0E-10); - if (m_print_flag <= 6) { - printf("\t\t Leg %2d alpha %5g: NonlinResid = %g LinResid = %g, relfit = %g\n", - legBest, alphaBest, residSteepBest, residSteepLinBest, relFit); - } else { - if (legBest == 0) { - sLen = alpha * solnErrorNorm(DATA_PTR(deltaX_CP_)); - } else if (legBest == 1) { - for (size_t i = 0; i < neq_; i++) { - y1[i] = (1.0 - alphaBest) * deltaX_CP_[i]; - y1[i] += alphaBest * Nuu_ * deltaX_Newton_[i]; - } - sLen = solnErrorNorm(DATA_PTR(y1)); - } else { - sLen = (Nuu_ + alpha * (1.0 - Nuu_)) * solnErrorNorm(DATA_PTR(deltaX_Newton_)); - } - printf("\t\t (%2d - % 10.3g) % 15.8E % 15.8E % 15.8E % 15.8E\n", legBest, alphaBest, sLen, - residSteepBest, residSteepLinBest , relFit); - } + printf("\t\t Best Result: \n"); + doublereal relFit = (residSteepBest - residSteepLinBest) / (fabs(residSteepLinBest) + 1.0E-10); + if (m_print_flag <= 6) { + printf("\t\t Leg %2d alpha %5g: NonlinResid = %g LinResid = %g, relfit = %g\n", + legBest, alphaBest, residSteepBest, residSteepLinBest, relFit); + } else { + if (legBest == 0) { + sLen = alpha * solnErrorNorm(DATA_PTR(deltaX_CP_)); + } else if (legBest == 1) { + for (int i = 0; i < neq_; i++) { + y1[i] = (1.0 - alphaBest) * deltaX_CP_[i]; + y1[i] += alphaBest * Nuu_ * deltaX_Newton_[i]; + } + sLen = solnErrorNorm(DATA_PTR(y1)); + } else { + sLen = ( Nuu_ + alpha * (1.0 - Nuu_)) * solnErrorNorm(DATA_PTR(deltaX_Newton_)); + } + printf("\t\t (%2d - % 10.3g) % 15.8E % 15.8E % 15.8E % 15.8E\n", legBest, alphaBest, sLen, + residSteepBest, residSteepLinBest , relFit); + } } -} -//==================================================================================================================== -// Calculate the length of the current trust region in terms of the solution error norm -/* - * We carry out a norm of deltaX_trust_ first. Then, we multiply that value - * by trustDelta_ - */ -doublereal NonlinearSolver::trustRegionLength() const -{ + } + //==================================================================================================================== + // Calculate the length of the current trust region in terms of the solution error norm + /* + * We carry out a norm of deltaX_trust_ first. Then, we multiply that value + * by trustDelta_ + */ + doublereal NonlinearSolver::trustRegionLength() const + { norm_deltaX_trust_ = solnErrorNorm(DATA_PTR(deltaX_trust_)); return (trustDelta_ * norm_deltaX_trust_); -} -//==================================================================================================================== -void NonlinearSolver::setDefaultDeltaBoundsMagnitudes() -{ - for (size_t i = 0; i < neq_; i++) { - m_deltaStepMinimum[i] = 1000. * atolk_[i]; - m_deltaStepMinimum[i] = std::max(m_deltaStepMinimum[i], 0.1 * fabs(m_y_n_curr[i])); + } + //==================================================================================================================== + void NonlinearSolver::setDefaultDeltaBoundsMagnitudes() + { + for (int i = 0; i < neq_; i++) { + m_deltaStepMinimum[i] = 1000. * atolk_[i]; + m_deltaStepMinimum[i] = MAX(m_deltaStepMinimum[i], 0.1 * fabs(m_y_n_curr[i])); } -} -//==================================================================================================================== -void NonlinearSolver::adjustUpStepMinimums() -{ - for (size_t i = 0; i < neq_; i++) { - doublereal goodVal = deltaX_trust_[i] * trustDelta_; - if (deltaX_trust_[i] * trustDelta_ > m_deltaStepMinimum[i]) { - m_deltaStepMinimum[i] = 1.1 * goodVal; - } - + } + //==================================================================================================================== + void NonlinearSolver::adjustUpStepMinimums() { + for (int i = 0; i < neq_; i++) { + doublereal goodVal = deltaX_trust_[i] * trustDelta_; + if (deltaX_trust_[i] * trustDelta_ > m_deltaStepMinimum[i]) { + m_deltaStepMinimum[i] = 1.1 * goodVal; + } + } -} -//==================================================================================================================== -void NonlinearSolver::setDeltaBoundsMagnitudes(const doublereal* const deltaStepMinimum) -{ - for (size_t i = 0; i < neq_; i++) { - m_deltaStepMinimum[i] = deltaStepMinimum[i]; + } + //==================================================================================================================== + void NonlinearSolver::setDeltaBoundsMagnitudes(const doublereal * const deltaStepMinimum) + { + + for (int i = 0; i < neq_; i++) { + m_deltaStepMinimum[i] = deltaStepMinimum[i]; } m_manualDeltaStepSet = 1; -} -//==================================================================================================================== -/* - * - * Return the factor by which the undamped Newton step 'step0' - * must be multiplied in order to keep the update within the bounds of an accurate jacobian. - * - * The idea behind these is that the Jacobian couldn't possibly be representative, if the - * variable is changed by a lot. (true for nonlinear systems, false for linear systems) - * Maximum increase in variable in any one newton iteration: - * factor of 1.5 - * Maximum decrease in variable in any one newton iteration: - * factor of 2 - * - * @param y_n_curr Initial value of the solution vector - * @param step_1 initial proposed step size - * - * @return returns the damping factor - */ -double -NonlinearSolver::deltaBoundStep(const doublereal* const y_n_curr, const doublereal* const step_1) -{ - - size_t i_fbounds = 0; + } + //==================================================================================================================== + /* + * + * Return the factor by which the undamped Newton step 'step0' + * must be multiplied in order to keep the update within the bounds of an accurate jacobian. + * + * The idea behind these is that the Jacobian couldn't possibly be representative, if the + * variable is changed by a lot. (true for nonlinear systems, false for linear systems) + * Maximum increase in variable in any one newton iteration: + * factor of 1.5 + * Maximum decrease in variable in any one newton iteration: + * factor of 2 + * + * @param y_n_curr Initial value of the solution vector + * @param step_1 initial proposed step size + * + * @return returns the damping factor + */ + double + NonlinearSolver::deltaBoundStep(const doublereal * const y_n_curr, const doublereal * const step_1) { + + int i_fbounds = 0; int ifbd = 0; int i_fbd = 0; doublereal UPFAC = 2.0; - + doublereal sameSign = 0.0; doublereal ff; doublereal f_delta_bounds = 1.0; doublereal ff_alt; - for (size_t i = 0; i < neq_; i++) { - doublereal y_new = y_n_curr[i] + step_1[i]; - sameSign = y_new * y_n_curr[i]; - - /* - * Now do a delta bounds - * Increase variables by a factor of UPFAC only - * decrease variables by a factor of 2 only - */ - ff = 1.0; + for (int i = 0; i < neq_; i++) { + doublereal y_new = y_n_curr[i] + step_1[i]; + sameSign = y_new * y_n_curr[i]; + + /* + * Now do a delta bounds + * Increase variables by a factor of UPFAC only + * decrease variables by a factor of 2 only + */ + ff = 1.0; - if (sameSign >= 0.0) { - if ((fabs(y_new) > UPFAC * fabs(y_n_curr[i])) && - (fabs(y_new - y_n_curr[i]) > m_deltaStepMinimum[i])) { - ff = (UPFAC - 1.0) * fabs(y_n_curr[i]/(y_new - y_n_curr[i])); - ff_alt = fabs(m_deltaStepMinimum[i] / (y_new - y_n_curr[i])); - ff = std::max(ff, ff_alt); - ifbd = 1; - } - if ((fabs(2.0 * y_new) < fabs(y_n_curr[i])) && - (fabs(y_new - y_n_curr[i]) > m_deltaStepMinimum[i])) { - ff = y_n_curr[i]/(y_new - y_n_curr[i]) * (1.0 - 2.0)/2.0; - ff_alt = fabs(m_deltaStepMinimum[i] / (y_new - y_n_curr[i])); - ff = std::max(ff, ff_alt); - ifbd = 0; - } - } else { - /* - * This handles the case where the value crosses the origin. - * - First we don't let it cross the origin until it's shrunk to the size of m_deltaStepMinimum[i] - */ - if (fabs(y_n_curr[i]) > m_deltaStepMinimum[i]) { - ff = y_n_curr[i]/(y_new - y_n_curr[i]) * (1.0 - 2.0)/2.0; - ff_alt = fabs(m_deltaStepMinimum[i] / (y_new - y_n_curr[i])); - ff = std::max(ff, ff_alt); - if (y_n_curr[i] >= 0.0) { - ifbd = 0; - } else { - ifbd = 1; - } - } - /* - * Second when it does cross the origin, we make sure that its magnitude is only 50% of the previous value. - */ - else if (fabs(y_new) > 0.5 * fabs(y_n_curr[i])) { - ff = y_n_curr[i]/(y_new - y_n_curr[i]) * (-1.5); - ff_alt = fabs(m_deltaStepMinimum[i] / (y_new - y_n_curr[i])); - ff = std::max(ff, ff_alt); - ifbd = 0; - } - } - - if (ff < f_delta_bounds) { - f_delta_bounds = ff; - i_fbounds = i; - i_fbd = ifbd; - } - + if (sameSign >= 0.0) { + if ((fabs(y_new) > UPFAC * fabs(y_n_curr[i])) && + (fabs(y_new - y_n_curr[i]) > m_deltaStepMinimum[i])) { + ff = (UPFAC - 1.0) * fabs(y_n_curr[i]/(y_new - y_n_curr[i])); + ff_alt = fabs(m_deltaStepMinimum[i] / (y_new - y_n_curr[i])); + ff = MAX(ff, ff_alt); + ifbd = 1; + } + if ((fabs(2.0 * y_new) < fabs(y_n_curr[i])) && + (fabs(y_new - y_n_curr[i]) > m_deltaStepMinimum[i])) { + ff = y_n_curr[i]/(y_new - y_n_curr[i]) * (1.0 - 2.0)/2.0; + ff_alt = fabs(m_deltaStepMinimum[i] / (y_new - y_n_curr[i])); + ff = MAX(ff, ff_alt); + ifbd = 0; + } + } else { + /* + * This handles the case where the value crosses the origin. + * - First we don't let it cross the origin until its shrunk to the size of m_deltaStepMinimum[i] + */ + if (fabs(y_n_curr[i]) > m_deltaStepMinimum[i]) { + ff = y_n_curr[i]/(y_new - y_n_curr[i]) * (1.0 - 2.0)/2.0; + ff_alt = fabs(m_deltaStepMinimum[i] / (y_new - y_n_curr[i])); + ff = MAX(ff, ff_alt); + if (y_n_curr[i] >= 0.0) { + ifbd = 0; + } else { + ifbd = 1; + } + } + /* + * Second when it does cross the origin, we make sure that its magnitude is only 50% of the previous value. + */ + else if (fabs(y_new) > 0.5 * fabs(y_n_curr[i])) { + ff = y_n_curr[i]/(y_new - y_n_curr[i]) * (-1.5); + ff_alt = fabs(m_deltaStepMinimum[i] / (y_new - y_n_curr[i])); + ff = MAX(ff, ff_alt); + ifbd = 0; + } + } + if (ff < f_delta_bounds) { + f_delta_bounds = ff; + i_fbounds = i; + i_fbd = ifbd; + } + + } - - + + /* * Report on any corrections */ if (m_print_flag >= 3) { - if (f_delta_bounds < 1.0) { - if (i_fbd) { - printf("\t\tdeltaBoundStep: Increase of Variable %s causing " - "delta damping of %g: origVal = %10.3g, undampedNew = %10.3g, dampedNew = %10.3g\n", - int2str(i_fbounds).c_str(), f_delta_bounds, y_n_curr[i_fbounds], y_n_curr[i_fbounds] + step_1[i_fbounds], - y_n_curr[i_fbounds] + f_delta_bounds * step_1[i_fbounds]); - } else { - printf("\t\tdeltaBoundStep: Decrease of variable %s causing" - "delta damping of %g: origVal = %10.3g, undampedNew = %10.3g, dampedNew = %10.3g\n", - int2str(i_fbounds).c_str(), f_delta_bounds, y_n_curr[i_fbounds], y_n_curr[i_fbounds] + step_1[i_fbounds], - y_n_curr[i_fbounds] + f_delta_bounds * step_1[i_fbounds]); - } - } + if (f_delta_bounds < 1.0) { + if (i_fbd) { + printf("\t\tdeltaBoundStep: Increase of Variable %d causing " + "delta damping of %g: origVal = %10.3g, undampedNew = %10.3g, dampedNew = %10.3g\n", + i_fbounds, f_delta_bounds, y_n_curr[i_fbounds], y_n_curr[i_fbounds] + step_1[i_fbounds], + y_n_curr[i_fbounds] + f_delta_bounds * step_1[i_fbounds] ); + } else { + printf("\t\tdeltaBoundStep: Decrease of variable %d causing" + "delta damping of %g: origVal = %10.3g, undampedNew = %10.3g, dampedNew = %10.3g\n", + i_fbounds, f_delta_bounds, y_n_curr[i_fbounds], y_n_curr[i_fbounds] + step_1[i_fbounds], + y_n_curr[i_fbounds] + f_delta_bounds * step_1[i_fbounds]); + } + } } - - + + return f_delta_bounds; -} -//==================================================================================================================== -// Readjust the trust region vectors -/* - * The trust region is made up of the trust region vector calculation and the trustDelta_ value - * We periodically recalculate the trustVector_ values so that they renormalize to the - * correct length. - */ -void NonlinearSolver::readjustTrustVector() -{ + } + //==================================================================================================================== + // Readjust the trust region vectors + /* + * The trust region is made up of the trust region vector calculation and the trustDelta_ value + * We periodically recalculate the trustVector_ values so that they renormalize to the + * correct length. + */ + void NonlinearSolver::readjustTrustVector() + { doublereal trustDeltaOld = trustDelta_; doublereal wtSum = 0.0; - for (size_t i = 0; i < neq_; i++) { - wtSum += m_ewt[i]; + for (int i = 0; i < neq_; i++) { + wtSum += m_ewt[i]; } wtSum /= neq_; doublereal trustNorm = solnErrorNorm(DATA_PTR(deltaX_trust_)); @@ -2145,316 +2157,314 @@ void NonlinearSolver::readjustTrustVector() // This is the size of each component. // doublereal trustDeltaEach = trustDelta_ * trustNorm / neq_; - doublereal oldVal; + doublereal oldVal; doublereal fabsy; // we use the old value of the trust region as an indicator - for (size_t i = 0; i < neq_; i++) { - oldVal = deltaX_trust_[i]; - fabsy = fabs(m_y_n_curr[i]); - // First off make sure that each trust region vector is 1/2 the size of each variable or smaller - // unless overridden by the deltaStepMininum value. - // doublereal newValue = trustDeltaEach * m_ewt[i] / wtSum; - doublereal newValue = trustNormGoal * m_ewt[i]; - if (newValue > 0.5 * fabsy) { - if (fabsy * 0.5 > m_deltaStepMinimum[i]) { - deltaX_trust_[i] = 0.5 * fabsy; - } else { - deltaX_trust_[i] = m_deltaStepMinimum[i]; - } - } else { - 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] = 0.75 * m_deltaStepMaximum[i]; - } - } + for (int i = 0; i < neq_; i++) { + oldVal = deltaX_trust_[i]; + fabsy = fabs(m_y_n_curr[i]); + // First off make sure that each trust region vector is 1/2 the size of each variable or smaller + // unless overridden by the deltaStepMininum value. + // doublereal newValue = trustDeltaEach * m_ewt[i] / wtSum; + doublereal newValue = trustNormGoal * m_ewt[i]; + if (newValue > 0.5 * fabsy) { + if (fabsy * 0.5 > m_deltaStepMinimum[i]) { + deltaX_trust_[i] = 0.5 * fabsy; + } else { + deltaX_trust_[i] = m_deltaStepMinimum[i]; + } + } else { + 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] = 0.75 * m_deltaStepMaximum[i]; + } + } } - // Final renormalization. + // Final renormalization. norm_deltaX_trust_ = solnErrorNorm(DATA_PTR(deltaX_trust_)); doublereal sum = trustNormGoal / trustNorm; - for (size_t i = 0; i < neq_; i++) { - deltaX_trust_[i] = deltaX_trust_[i] * sum; - } + for (int i = 0; i < neq_; i++) { + deltaX_trust_[i] = deltaX_trust_[i] * sum; + } norm_deltaX_trust_ = solnErrorNorm(DATA_PTR(deltaX_trust_)); trustDelta_ = trustNormGoal / norm_deltaX_trust_; if (doDogLeg_ && m_print_flag >= 4) { - printf("\t\t reajustTrustVector(): Trust size = %11.3E: Old deltaX size = %11.3E trustDelta_ = %11.3E\n" - "\t\t new deltaX size = %11.3E trustdelta_ = %11.3E\n", - trustNormGoal, deltaXSizeOld, trustDeltaOld, norm_deltaX_trust_, trustDelta_); + printf("\t\t reajustTrustVector(): Trust size = %11.3E: Old deltaX size = %11.3E trustDelta_ = %11.3E\n" + "\t\t new deltaX size = %11.3E trustdelta_ = %11.3E\n", + trustNormGoal, deltaXSizeOld, trustDeltaOld, norm_deltaX_trust_, trustDelta_ ); } -} -//==================================================================================================================== -//! Initialize the size of the trust vector. -/*! - * The algorithm we use is to set it equal to the length of the Distance to the Cauchy point. - */ -void NonlinearSolver::initializeTrustRegion() -{ + } + //==================================================================================================================== + //! Initialize the size of the trust vector. + /*! + * The algorithm we use is to set it equal to the length of the Distance to the Cauchy point. + */ + void NonlinearSolver::initializeTrustRegion() + { if (trustRegionInitializationMethod_ == 0) { - return; + return; } if (trustRegionInitializationMethod_ == 1) { - for (size_t i = 0; i < neq_; i++) { - deltaX_trust_[i] = m_ewt[i] * trustRegionInitializationFactor_; - } - trustDelta_ = 1.0; + for (int i = 0; i < neq_; i++) { + deltaX_trust_[i] = m_ewt[i] * trustRegionInitializationFactor_; + } + trustDelta_ = 1.0; } if (trustRegionInitializationMethod_ == 2) { - for (size_t i = 0; i < neq_; i++) { - deltaX_trust_[i] = m_ewt[i] * m_normDeltaSoln_CP * trustRegionInitializationFactor_; - } - doublereal cpd = calcTrustDistance(deltaX_CP_); - if ((doDogLeg_ && m_print_flag >= 4)) { - printf("\t\t initializeTrustRegion(): Relative Distance of Cauchy Vector wrt Trust Vector = %g\n", cpd); - } - trustDelta_ = trustDelta_ * cpd * trustRegionInitializationFactor_; - readjustTrustVector(); - cpd = calcTrustDistance(deltaX_CP_); - if ((doDogLeg_ && m_print_flag >= 4)) { - printf("\t\t initializeTrustRegion(): Relative Distance of Cauchy Vector wrt Trust Vector = %g\n", cpd); - } + for (int i = 0; i < neq_; i++) { + deltaX_trust_[i] = m_ewt[i] * m_normDeltaSoln_CP * trustRegionInitializationFactor_; + } + doublereal cpd = calcTrustDistance(deltaX_CP_); + if ((doDogLeg_ && m_print_flag >= 4)) { + printf("\t\t initializeTrustRegion(): Relative Distance of Cauchy Vector wrt Trust Vector = %g\n", cpd); + } + trustDelta_ = trustDelta_ * cpd * trustRegionInitializationFactor_; + readjustTrustVector(); + cpd = calcTrustDistance(deltaX_CP_); + if ((doDogLeg_ && m_print_flag >= 4)) { + printf("\t\t initializeTrustRegion(): Relative Distance of Cauchy Vector wrt Trust Vector = %g\n", cpd); + } } if (trustRegionInitializationMethod_ == 3) { - for (size_t i = 0; i < neq_; i++) { - deltaX_trust_[i] = m_ewt[i] * m_normDeltaSoln_Newton * trustRegionInitializationFactor_; - } - doublereal cpd = calcTrustDistance(deltaX_Newton_); - if ((doDogLeg_ && m_print_flag >= 4)) { - printf("\t\t initializeTrustRegion(): Relative Distance of Newton Vector wrt Trust Vector = %g\n", cpd); - } - trustDelta_ = trustDelta_ * cpd; - readjustTrustVector(); - cpd = calcTrustDistance(deltaX_Newton_); - if ((doDogLeg_ && m_print_flag >= 4)) { - printf("\t\t initializeTrustRegion(): Relative Distance of Newton Vector wrt Trust Vector = %g\n", cpd); - } + for (int i = 0; i < neq_; i++) { + deltaX_trust_[i] = m_ewt[i] * m_normDeltaSoln_Newton * trustRegionInitializationFactor_; + } + doublereal cpd = calcTrustDistance(deltaX_Newton_); + if ((doDogLeg_ && m_print_flag >= 4)) { + printf("\t\t initializeTrustRegion(): Relative Distance of Newton Vector wrt Trust Vector = %g\n", cpd); + } + trustDelta_ = trustDelta_ * cpd; + readjustTrustVector(); + cpd = calcTrustDistance(deltaX_Newton_); + if ((doDogLeg_ && m_print_flag >= 4)) { + printf("\t\t initializeTrustRegion(): Relative Distance of Newton Vector wrt Trust Vector = %g\n", cpd); + } } -} + } -//==================================================================================================================== -// Fill a dogleg solution step vector -/* - * Previously, we have filled up deltaX_Newton_[], deltaX_CP_[], and Nuu_, so that - * this routine is straightforward. - * - * @param leg Leg of the dog leg you are on (0, 1, or 2) - * @param alpha Relative length along the dog length that you are on. - * @param deltaX Vector to be filled up - */ -void NonlinearSolver::fillDogLegStep(int leg, doublereal alpha, std::vector & deltaX) const -{ + //==================================================================================================================== + // Fill a dogleg solution step vector + /* + * Previously, we have filled up deltaX_Newton_[], deltaX_CP_[], and Nuu_, so that + * this routine is straightforward. + * + * @param leg Leg of the dog leg you are on (0, 1, or 2) + * @param alpha Relative length along the dog length that you are on. + * @param deltaX Vector to be filled up + */ + void NonlinearSolver::fillDogLegStep(int leg, doublereal alpha, std::vector & deltaX) const { if (leg == 0) { - for (size_t i = 0; i < neq_; i++) { - deltaX[i] = alpha * deltaX_CP_[i]; - } + for (int i = 0; i < neq_; i++) { + deltaX[i] = alpha * deltaX_CP_[i]; + } } else if (leg == 2) { - for (size_t i = 0; i < neq_; i++) { - deltaX[i] = (alpha + (1.0 - alpha) * Nuu_) * deltaX_Newton_[i]; - } + for (int i = 0; i < neq_; i++) { + deltaX[i] = (alpha + (1.0 - alpha) * Nuu_) * deltaX_Newton_[i]; + } } else { - for (size_t i = 0; i < neq_; i++) { - deltaX[i] = deltaX_CP_[i] * (1.0 - alpha) + alpha * Nuu_ * deltaX_Newton_[i]; - } + for (int i = 0; i < neq_; i++) { + deltaX[i] = deltaX_CP_[i] * (1.0 - alpha) + alpha * Nuu_ * deltaX_Newton_[i]; + } } -} -//==================================================================================================================== -// Calculate the trust distance of a step in the solution variables -/* - * 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_ || / trustDelta_ - * - * @param deltaX Current value of deltaX - */ -doublereal NonlinearSolver::calcTrustDistance(std::vector const& deltaX) const -{ + } + //==================================================================================================================== + // Calculate the trust distance of a step in the solution variables + /* + * 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_ || / trustDelta_ + * + * @param deltaX Current value of deltaX + */ + doublereal NonlinearSolver::calcTrustDistance(std::vector const & deltaX) const + { doublereal sum = 0.0; doublereal tmp = 0.0; - for (size_t i = 0; i < neq_; i++) { - tmp = deltaX[i] / deltaX_trust_[i]; - sum += tmp * tmp; + for (int i = 0; i < neq_; i++) { + tmp = deltaX[i] / deltaX_trust_[i]; + sum += tmp * tmp; } sum = sqrt(sum / neq_) / trustDelta_; return sum; -} -//==================================================================================================================== -// Given a trust distance, this routine calculates the intersection of the this distance with the -// double dogleg curve -/* - * @param trustDelta (INPUT) Value of the trust distance - * @param lambda (OUTPUT) Returns the internal coordinate of the double dogleg - * @param alpha (OUTPUT) Returns the relative distance along the appropriate leg - * @return leg (OUTPUT) Returns the leg ID (0, 1, or 2) - */ -int NonlinearSolver::calcTrustIntersection(doublereal trustDelta, doublereal& lambda, doublereal& alpha) const -{ + } + //==================================================================================================================== + // Given a trust distance, this routine calculates the intersection of the this distance with the + // double dogleg curve + /* + * @param trustDelta (INPUT) Value of the trust distance + * @param lambda (OUTPUT) Returns the internal coordinate of the double dogleg + * @param alpha (OUTPUT) Returns the relative distance along the appropriate leg + * @return leg (OUTPUT) Returns the leg ID (0, 1, or 2) + */ + int NonlinearSolver::calcTrustIntersection(doublereal trustDelta, doublereal &lambda, doublereal &alpha) const + { doublereal dist; if (normTrust_Newton_ < trustDelta) { - lambda = 1.0; - alpha = 1.0; - return 2; + lambda = 1.0; + alpha = 1.0; + return 2; } - + if (normTrust_Newton_ * Nuu_ < trustDelta) { - alpha = (trustDelta - normTrust_Newton_ * Nuu_) / (normTrust_Newton_ - normTrust_Newton_ * Nuu_); - dist = dist_R0_ + dist_R1_ + alpha * dist_R2_; - lambda = dist / dist_Total_; - return 2; + alpha = (trustDelta - normTrust_Newton_ * Nuu_) / (normTrust_Newton_ - normTrust_Newton_ * Nuu_); + dist = dist_R0_ + dist_R1_ + alpha * dist_R2_; + lambda = dist / dist_Total_; + return 2; } if (normTrust_CP_ > trustDelta) { - lambda = 1.0; - dist = dist_R0_ * trustDelta / normTrust_CP_; - lambda = dist / dist_Total_; - alpha = trustDelta / normTrust_CP_; - return 0; + lambda = 1.0; + dist = dist_R0_ * trustDelta / normTrust_CP_; + lambda = dist / dist_Total_; + alpha = trustDelta / normTrust_CP_; + return 0; } doublereal sumv = 0.0; - for (size_t i = 0; i < neq_; i++) { - sumv += (deltaX_Newton_[i] / deltaX_trust_[i]) * (deltaX_CP_[i] / deltaX_trust_[i]); + for (int i = 0; i < neq_; i++) { + sumv += (deltaX_Newton_[i] / deltaX_trust_[i]) * (deltaX_CP_[i] / deltaX_trust_[i]); } doublereal a = normTrust_Newton_ * normTrust_Newton_ * Nuu_ * Nuu_; doublereal b = 2.0 * Nuu_ * sumv; doublereal c = normTrust_CP_ * normTrust_CP_ - trustDelta * trustDelta; - alpha =(-b + sqrt(b * b - 4.0 * a * c)) / (2.0 * a); - + alpha =( -b + sqrt( b * b - 4.0 * a * c)) / (2.0 * a); + dist = dist_R0_ + alpha * dist_R1_; lambda = dist / dist_Total_; - return 1; -} -//==================================================================================================================== -/* - * - * boundStep(): - * - * 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. - * Other bounds may be applied here as well. - * - * Currently the bounds are hard coded into this routine: - * - * Minimum value for all variables: - 0.01 * m_ewt[i] - * Maximum value = none. - * - * Thus, this means that all solution components are expected - * to be numerical greater than zero in the limit of time step - * truncation errors going to zero. - * - * Delta bounds: The idea behind these is that the Jacobian - * couldn't possibly be representative if the - * variable is changed by a lot. (true for - * nonlinear systems, false for linear systems) - * Maximum increase in variable in any one newton iteration: - * factor of 2 - * Maximum decrease in variable in any one newton iteration: - * factor of 5 - */ -doublereal NonlinearSolver::boundStep(const doublereal* const y, const doublereal* const step0) -{ - size_t i_lower = npos; + return 1; + } + //==================================================================================================================== + /* + * + * boundStep(): + * + * 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. + * Other bounds may be applied here as well. + * + * Currently the bounds are hard coded into this routine: + * + * Minimum value for all variables: - 0.01 * m_ewt[i] + * Maximum value = none. + * + * Thus, this means that all solution components are expected + * to be numerical greater than zero in the limit of time step + * truncation errors going to zero. + * + * Delta bounds: The idea behind these is that the Jacobian + * couldn't possibly be representative if the + * variable is changed by a lot. (true for + * nonlinear systems, false for linear systems) + * Maximum increase in variable in any one newton iteration: + * factor of 2 + * Maximum decrease in variable in any one newton iteration: + * factor of 5 + */ + doublereal NonlinearSolver::boundStep(const doublereal * const y, const doublereal * const step0) + { + int i, i_lower = -1; doublereal fbound = 1.0, f_bounds = 1.0; doublereal ff, y_new; - - for (size_t i = 0; i < neq_; i++) { - y_new = y[i] + step0[i]; - /* - * Force the step to only take 80% a step towards the lower bounds - */ - if (step0[i] < 0.0) { - if (y_new < (y[i] + 0.8 * (m_y_low_bounds[i] - y[i]))) { - doublereal legalDelta = 0.8*(m_y_low_bounds[i] - y[i]); - ff = legalDelta / step0[i]; - if (ff < f_bounds) { - f_bounds = ff; - i_lower = i; - } - } - } - /* - * Force the step to only take 80% a step towards the high bounds - */ - if (step0[i] > 0.0) { - if (y_new > (y[i] + 0.8 * (m_y_high_bounds[i] - y[i]))) { - doublereal legalDelta = 0.8*(m_y_high_bounds[i] - y[i]); - ff = legalDelta / step0[i]; - if (ff < f_bounds) { - f_bounds = ff; - i_lower = i; - } - } - } - + + for (i = 0; i < neq_; i++) { + y_new = y[i] + step0[i]; + /* + * Force the step to only take 80% a step towards the lower bounds + */ + if (step0[i] < 0.0) { + if (y_new < (y[i] + 0.8 * (m_y_low_bounds[i] - y[i]))) { + doublereal legalDelta = 0.8*(m_y_low_bounds[i] - y[i]); + ff = legalDelta / step0[i]; + if (ff < f_bounds) { + f_bounds = ff; + i_lower = i; + } + } + } + /* + * Force the step to only take 80% a step towards the high bounds + */ + if (step0[i] > 0.0) { + if (y_new > (y[i] + 0.8 * (m_y_high_bounds[i] - y[i]))) { + doublereal legalDelta = 0.8*(m_y_high_bounds[i] - y[i]); + ff = legalDelta / step0[i]; + if (ff < f_bounds) { + f_bounds = ff; + i_lower = i; + } + } + } + } /* * Report on any corrections */ if (m_print_flag >= 3) { - if (f_bounds != 1.0) { - printf("\t\tboundStep: Variable %s causing bounds damping of %g\n", - int2str(i_lower).c_str(), f_bounds); - } + if (f_bounds != 1.0) { + printf("\t\tboundStep: Variable %d causing bounds damping of %g\n", i_lower, f_bounds); + } } doublereal f_delta_bounds = deltaBoundStep(y, step0); - fbound = std::min(f_bounds, f_delta_bounds); + fbound = MIN(f_bounds, f_delta_bounds); return fbound; -} -//=================================================================================================================== -// Find a damping coefficient through a look-ahead mechanism -/* - * - * On entry, step0 must contain an undamped Newton step to the - * current solution y0. 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 y1, and the undamped step at y1 is - * returned in step1. - * - * - * @return 1 Successful step was taken: Next step was less than previous step. - * s1 is calculated - * 2 Successful step: Next step's norm is less than 0.8 - * 3 Success: The final residual is less than 1.0 - * A predicted deltaSoln1 is not produced however. s1 is estimated. - * 4 Success: The final residual is less than the residual - * from the previous step. - * A predicted deltaSoln1 is not produced however. s1 is estimated. - * 0 Uncertain Success: s1 is about the same as s0 - * NSOLN_RETN_FAIL_DAMPSTEP - * Unsuccessful step. We can not find a damping factor that is suitable. - */ -int NonlinearSolver::dampStep(const doublereal time_curr, const doublereal* const y_n_curr, - const doublereal* const ydot_n_curr, doublereal* const step_1, - doublereal* const y_n_1, doublereal* const ydot_n_1, doublereal* const step_2, - doublereal& stepNorm_2, GeneralMatrix& jac, bool writetitle, int& num_backtracks) -{ - int m; + } + //=================================================================================================================== + // Find a damping coefficient through a look-ahead mechanism + /* + * + * On entry, step0 must contain an undamped Newton step to the + * current solution y0. 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 y1, and the undamped step at y1 is + * returned in step1. + * + * + * @return 1 Successful step was taken: Next step was less than previous step. + * s1 is calculated + * 2 Successful step: Next step's norm is less than 0.8 + * 3 Success: The final residual is less than 1.0 + * A predicted deltaSoln1 is not produced however. s1 is estimated. + * 4 Success: The final residual is less than the residual + * from the previous step. + * A predicted deltaSoln1 is not produced however. s1 is estimated. + * 0 Uncertain Success: s1 is about the same as s0 + * NSOLN_RETN_FAIL_DAMPSTEP + * Unsuccessful step. We can not find a damping factor that is suitable. + */ + int NonlinearSolver::dampStep(const doublereal time_curr, const doublereal * const y_n_curr, + const doublereal * const ydot_n_curr, doublereal * const step_1, + doublereal * const y_n_1, doublereal * const ydot_n_1, doublereal * const step_2, + doublereal & stepNorm_2, GeneralMatrix& jac, bool writetitle, int& num_backtracks) + { + int j, m; int info = 0; int retnTrial = NSOLN_RETN_FAIL_DAMPSTEP; // Compute the weighted norm of the undamped step size step_1 doublereal stepNorm_1 = solnErrorNorm(step_1); - doublereal* step_1_orig = DATA_PTR(m_wksp); - for (size_t j = 0; j < neq_; j++) { - step_1_orig[j] = step_1[j]; + doublereal * step_1_orig = DATA_PTR(m_wksp); + for (j = 0; j < neq_; j++) { + step_1_orig[j] = step_1[j]; } - + // 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 @@ -2464,156 +2474,155 @@ int NonlinearSolver::dampStep(const doublereal time_curr, const doublereal* cons // If fbound is very small, then y0 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 (m_dampBound < 1.e-30) { - if (m_print_flag > 1) { - printf("\t\t\tdampStep(): At limits.\n"); - } - return -3; + if (m_print_flag > 1) printf("\t\t\tdampStep(): At limits.\n"); + return -3; } //-------------------------------------------- // Attempt damped step - //-------------------------------------------- + //-------------------------------------------- // damping coefficient starts at 1.0 m_dampRes = 1.0; - + doublereal ff = m_dampBound; num_backtracks = 0; for (m = 0; m < NDAMP; m++) { - ff = m_dampBound * m_dampRes; + ff = m_dampBound * m_dampRes; - // step the solution by the damped step size - /* - * Whenever we update the solution, we must also always - * update the time derivative. - */ - for (size_t j = 0; j < neq_; j++) { - step_1[j] = ff * step_1_orig[j]; - y_n_1[j] = y_n_curr[j] + step_1[j]; - } + // step the solution by the damped step size + /* + * Whenever we update the solution, we must also always + * update the time derivative. + */ + for (j = 0; j < neq_; j++) { + step_1[j] = ff * step_1_orig[j]; + y_n_1[j] = y_n_curr[j] + step_1[j]; + } + + if (solnType_ != NSOLN_TYPE_STEADY_STATE) { + calc_ydot(m_order, y_n_1, ydot_n_1); + } + /* + * Calculate the residual that would result if y1[] were the new solution vector + * -> m_resid[] contains the result of the residual calculation + */ + if (solnType_ != NSOLN_TYPE_STEADY_STATE) { + info = doResidualCalc(time_curr, solnType_, y_n_1, ydot_n_1, Base_LaggedSolutionComponents); + } else { + info = doResidualCalc(time_curr, solnType_, y_n_1, ydot_n_curr, Base_LaggedSolutionComponents); + } + if (info != 1) { + if (m_print_flag > 0) { + printf("\t\t\tdampStep(): current trial step and damping led to Residual Calc ERROR %d. Bailing\n", info); + } + return -1; + } + m_normResidTrial = residErrorNorm(DATA_PTR(m_resid)); + m_normResid_1 = m_normResidTrial; + if (m == 0) { + m_normResid_Bound = m_normResidTrial; + } - if (solnType_ != NSOLN_TYPE_STEADY_STATE) { - calc_ydot(m_order, y_n_1, ydot_n_1); - } - /* - * Calculate the residual that would result if y1[] were the new solution vector - * -> m_resid[] contains the result of the residual calculation - */ - if (solnType_ != NSOLN_TYPE_STEADY_STATE) { - info = doResidualCalc(time_curr, solnType_, y_n_1, ydot_n_1, Base_LaggedSolutionComponents); - } else { - info = doResidualCalc(time_curr, solnType_, y_n_1, ydot_n_curr, Base_LaggedSolutionComponents); - } - if (info != 1) { - if (m_print_flag > 0) { - printf("\t\t\tdampStep(): current trial step and damping led to Residual Calc ERROR %d. Bailing\n", info); - } - return -1; - } - m_normResidTrial = residErrorNorm(DATA_PTR(m_resid)); - m_normResid_1 = m_normResidTrial; - if (m == 0) { - m_normResid_Bound = m_normResidTrial; - } + bool steepEnough = (m_normResidTrial < m_normResid_0 * (0.9 * (1.0 - ff) * (1.0 - ff)* (1.0 - ff) + 0.1)); - bool steepEnough = (m_normResidTrial < m_normResid_0 * (0.9 * (1.0 - ff) * (1.0 - ff)* (1.0 - ff) + 0.1)); + if (m_normResidTrial < 1.0 || steepEnough) { + if (m_print_flag >= 5) { + if (m_normResidTrial < 1.0) { + printf("\t dampStep(): Current trial step and damping" + " coefficient accepted because residTrial test step < 1:\n"); + printf("\t resid0 = %g, residTrial = %g\n", m_normResid_0, m_normResidTrial); + } else if (steepEnough) { + printf("\t dampStep(): Current trial step and damping" + " coefficient accepted because resid0 > residTrial and steep enough:\n"); + printf("\t resid0 = %g, residTrial = %g\n", m_normResid_0, m_normResidTrial); + } else { + printf("\t dampStep(): Current trial step and damping" + " coefficient accepted because residual solution damping is turned off:\n"); + printf("\t resid0 = %g, residTrial = %g\n", m_normResid_0, m_normResidTrial); + } + } + /* + * We aren't going to solve the system if we don't need to. Therefore, return an estimate + * of the next solution update based on the ratio of the residual reduction. + */ + if (m_normResid_0 > 0.0) { + stepNorm_2 = stepNorm_1 * m_normResidTrial / m_normResid_0; + } + else { + stepNorm_2 = 0; + } + if (m_normResidTrial < 1.0) { + retnTrial = 3; + } else { + retnTrial = 4; + } + break; + } + + // Compute the next undamped step, step1[], that would result if y1[] were accepted. + // We now have two steps that we have calculated step0[] and step1[] + if (solnType_ != NSOLN_TYPE_STEADY_STATE) { + info = doNewtonSolve(time_curr, y_n_1, ydot_n_1, step_2, jac); + } else { + info = doNewtonSolve(time_curr, y_n_1, ydot_n_curr, step_2, jac); + } + if (info) { + if (m_print_flag > 0) { + printf("\t\t\tdampStep: current trial step and damping led to LAPACK ERROR %d. Bailing\n", info); + } + return -1; + } - if (m_normResidTrial < 1.0 || steepEnough) { - if (m_print_flag >= 5) { - if (m_normResidTrial < 1.0) { - printf("\t dampStep(): Current trial step and damping" - " coefficient accepted because residTrial test step < 1:\n"); - printf("\t resid0 = %g, residTrial = %g\n", m_normResid_0, m_normResidTrial); - } else if (steepEnough) { - printf("\t dampStep(): Current trial step and damping" - " coefficient accepted because resid0 > residTrial and steep enough:\n"); - printf("\t resid0 = %g, residTrial = %g\n", m_normResid_0, m_normResidTrial); - } else { - printf("\t dampStep(): Current trial step and damping" - " coefficient accepted because residual solution damping is turned off:\n"); - printf("\t resid0 = %g, residTrial = %g\n", m_normResid_0, m_normResidTrial); - } - } - /* - * We aren't going to solve the system if we don't need to. Therefore, return an estimate - * of the next solution update based on the ratio of the residual reduction. - */ - if (m_normResid_0 > 0.0) { - stepNorm_2 = stepNorm_1 * m_normResidTrial / m_normResid_0; - } else { - stepNorm_2 = 0; - } - if (m_normResidTrial < 1.0) { - retnTrial = 3; - } else { - retnTrial = 4; - } - break; - } + // compute the weighted norm of step1 + stepNorm_2 = solnErrorNorm(step_2); - // Compute the next undamped step, step1[], that would result if y1[] were accepted. - // We now have two steps that we have calculated step0[] and step1[] - if (solnType_ != NSOLN_TYPE_STEADY_STATE) { - info = doNewtonSolve(time_curr, y_n_1, ydot_n_1, step_2, jac); - } else { - info = doNewtonSolve(time_curr, y_n_1, ydot_n_curr, step_2, jac); - } - if (info) { - if (m_print_flag > 0) { - printf("\t\t\tdampStep: current trial step and damping led to LAPACK ERROR %d. Bailing\n", info); - } - return -1; - } - - // compute the weighted norm of step1 - stepNorm_2 = solnErrorNorm(step_2); - - // write log information - if (m_print_flag >= 5) { - print_solnDelta_norm_contrib((const doublereal*) step_1_orig, "DeltaSoln", - (const doublereal*) step_2, "DeltaSolnTrial", - "dampNewt: Important Entries for Weighted Soln Updates:", - y_n_curr, y_n_1, ff, 5); - } - if (m_print_flag >= 4) { - printf("\t\t\tdampStep(): s1 = %g, s2 = %g, dampBound = %g," - "dampRes = %g\n", stepNorm_1, stepNorm_2, m_dampBound, m_dampRes); - } + // write log information + if (m_print_flag >= 5) { + print_solnDelta_norm_contrib((const doublereal *) step_1_orig, "DeltaSoln", + (const doublereal *) step_2, "DeltaSolnTrial", + "dampNewt: Important Entries for Weighted Soln Updates:", + y_n_curr, y_n_1, ff, 5); + } + if (m_print_flag >= 4) { + printf("\t\t\tdampStep(): s1 = %g, s2 = %g, dampBound = %g," + "dampRes = %g\n", stepNorm_1, stepNorm_2, m_dampBound, m_dampRes); + } - // 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 (stepNorm_2 < 0.8 || stepNorm_2 < stepNorm_1) { - if (stepNorm_2 < 1.0) { - if (m_print_flag >= 3) { - if (stepNorm_2 < 1.0) { - printf("\t\t\tdampStep: current trial step and damping coefficient accepted because test step < 1\n"); - printf("\t\t\t s2 = %g, s1 = %g\n", stepNorm_2, stepNorm_1); - } - } - retnTrial = 2; - } else { - retnTrial = 1; - } - break; - } else { - if (m_print_flag > 1) { - printf("\t\t\tdampStep: current step rejected: (s1 = %g > " - "s0 = %g)", stepNorm_2, stepNorm_1); - if (m < (NDAMP-1)) { - printf(" Decreasing damping factor and retrying"); - } else { - printf(" Giving up!!!"); - } - printf("\n"); - } - } - num_backtracks++; - m_dampRes /= DampFactor; + // 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 (stepNorm_2 < 0.8 || stepNorm_2 < stepNorm_1) { + if (stepNorm_2 < 1.0) { + if (m_print_flag >= 3) { + if (stepNorm_2 < 1.0) { + printf("\t\t\tdampStep: current trial step and damping coefficient accepted because test step < 1\n"); + printf("\t\t\t s2 = %g, s1 = %g\n", stepNorm_2, stepNorm_1); + } + } + retnTrial = 2; + } else { + retnTrial = 1; + } + break; + } else { + if (m_print_flag > 1) { + printf("\t\t\tdampStep: current step rejected: (s1 = %g > " + "s0 = %g)", stepNorm_2, stepNorm_1); + if (m < (NDAMP-1)) { + printf(" Decreasing damping factor and retrying"); + } else { + printf(" Giving up!!!"); + } + printf("\n"); + } + } + num_backtracks++; + m_dampRes /= DampFactor; } // If a damping coefficient was found, return 1 if the @@ -2621,178 +2630,181 @@ int NonlinearSolver::dampStep(const doublereal time_curr, const doublereal* cons // a converged solution, and return 0 otherwise. If no damping // coefficient could be found, return NSOLN_RETN_FAIL_DAMPSTEP. if (m < NDAMP) { - if (m_print_flag >= 4) { - printf("\t dampStep(): current trial step accepted retnTrial = %d, its = %d, damp = %g\n", retnTrial, m+1, ff); - } - return retnTrial; + if (m_print_flag >= 4 ) { + printf("\t dampStep(): current trial step accepted retnTrial = %d, its = %d, damp = %g\n", retnTrial, m+1, ff); + } + return retnTrial; } else { - if (stepNorm_2 < 0.5 && (stepNorm_1 < 0.5)) { - if (m_print_flag >= 4) { - printf("\t dampStep(): current trial step accepted kindof retnTrial = %d, its = %d, damp = %g\n", 2, m+1, ff); - } - return 2; - } - if (stepNorm_2 < 1.0) { - if (m_print_flag >= 4) { - printf("\t dampStep(): current trial step accepted and soln converged retnTrial =" - "%d, its = %d, damp = %g\n", 0, m+1, ff); - } - return 0; - } + if (stepNorm_2 < 0.5 && (stepNorm_1 < 0.5)) { + if (m_print_flag >= 4 ) { + printf("\t dampStep(): current trial step accepted kindof retnTrial = %d, its = %d, damp = %g\n", 2, m+1, ff); + } + return 2; + } + if (stepNorm_2 < 1.0) { + if (m_print_flag >= 4 ) { + printf("\t dampStep(): current trial step accepted and soln converged retnTrial =" + "%d, its = %d, damp = %g\n", 0, m+1, ff); + } + return 0; + } } - if (m_print_flag >= 4) { - printf("\t dampStep(): current direction is rejected! retnTrial = %d, its = %d, damp = %g\n", - NSOLN_RETN_FAIL_DAMPSTEP, m+1, ff); + if (m_print_flag >= 4 ) { + printf("\t dampStep(): current direction is rejected! retnTrial = %d, its = %d, damp = %g\n", + NSOLN_RETN_FAIL_DAMPSTEP, m+1, ff); } return NSOLN_RETN_FAIL_DAMPSTEP; -} -//==================================================================================================================== -// Damp using the dog leg approach -/* - * - * @param time_curr INPUT Current value of the time - * @param y_n_curr INPUT Current value of the solution vector - * @param ydot_n_curr INPUT Current value of the derivative of the solution vector - * @param step_1 INPUT First trial step for the first iteration - * @param y_n_1 INPUT First trial value of the solution vector - * @param ydot_n_1 INPUT First trial value of the derivative of the solution vector - * @param s1 OUTPUT Norm of the vector step_1 - * @param jac INPUT jacobian - * @param numTrials OUTPUT number of trials taken in the current damping step - * - * - * @return 1 Success: Good step was taken. The predicted residual norm is less than one - * 2 Success: Good step: Next step's norm is less than 0.8 - * 3 Success: The final residual is less than 1.0 - * A predicted deltaSoln1 is not produced however. s1 is estimated. - * 4 Success: The final residual is less than the residual from the previous step. - * A predicted deltaSoln1 is not produced however. s1 is estimated. - * 0 Unknown Uncertain Success: s1 is about the same as s0 - * NSOLN_RETN_FAIL_DAMPSTEP - * Unsuccessful step. Can not find a damping coefficient that is suitable - */ -int NonlinearSolver::dampDogLeg(const doublereal time_curr, const doublereal* y_n_curr, - const doublereal* ydot_n_curr, std::vector & step_1, - doublereal* const y_n_1, doublereal* const ydot_n_1, - doublereal& stepNorm_1, doublereal& stepNorm_2, GeneralMatrix& jac, int& numTrials) -{ + } + //==================================================================================================================== + // Damp using the dog leg approach + /* + * + * @param time_curr INPUT Current value of the time + * @param y_n_curr INPUT Current value of the solution vector + * @param ydot_n_curr INPUT Current value of the derivative of the solution vector + * @param step_1 INPUT First trial step for the first iteration + * @param y_n_1 INPUT First trial value of the solution vector + * @param ydot_n_1 INPUT First trial value of the derivative of the solution vector + * @param s1 OUTPUT Norm of the vector step_1 + * @param jac INPUT jacobian + * @param numTrials OUTPUT number of trials taken in the current damping step + * + * + * @return 1 Success: Good step was taken. The predicted residual norm is less than one + * 2 Success: Good step: Next step's norm is less than 0.8 + * 3 Success: The final residual is less than 1.0 + * A predicted deltaSoln1 is not produced however. s1 is estimated. + * 4 Success: The final residual is less than the residual from the previous step. + * A predicted deltaSoln1 is not produced however. s1 is estimated. + * 0 Unknown Uncertain Success: s1 is about the same as s0 + * NSOLN_RETN_FAIL_DAMPSTEP + * Unsuccessful step. Can not find a damping coefficient that is suitable + */ + int NonlinearSolver::dampDogLeg(const doublereal time_curr, const doublereal* y_n_curr, + const doublereal *ydot_n_curr, std::vector & step_1, + doublereal* const y_n_1, doublereal* const ydot_n_1, + doublereal& stepNorm_1, doublereal& stepNorm_2, GeneralMatrix& jac, int& numTrials) + { doublereal lambda; int info; - + bool success = false; + int retn = 0; bool haveASuccess = false; doublereal trustDeltaOld = trustDelta_; doublereal* stepLastGood = DATA_PTR(m_wksp); //-------------------------------------------- // Attempt damped step - //-------------------------------------------- + //-------------------------------------------- // damping coefficient starts at 1.0 m_dampRes = 1.0; - int m; + int j, m; doublereal tlen; - + for (m = 0; m < NDAMP; m++) { - numTrials++; - /* - * Find the initial value of lambda that satisfies the trust distance, trustDelta_ - */ - dogLegID_ = calcTrustIntersection(trustDelta_, lambda, dogLegAlpha_); - if (m_print_flag >= 4) { - tlen = trustRegionLength(); - printf("\t\t dampDogLeg: trust region with length %13.5E has intersection at leg = %d, alpha = %g, lambda = %g\n", - tlen, dogLegID_, dogLegAlpha_, lambda); - } - /* - * Figure out the new step vector, step_1, based on (leg, alpha). Here we are using the - * intersection of the trust oval with the dog-leg curve. - */ - fillDogLegStep(dogLegID_, dogLegAlpha_, step_1); + numTrials++; + /* + * Find the initial value of lambda that satisfies the trust distance, trustDelta_ + */ + dogLegID_ = calcTrustIntersection(trustDelta_, lambda, dogLegAlpha_); + if (m_print_flag >= 4) { + tlen = trustRegionLength(); + printf("\t\t dampDogLeg: trust region with length %13.5E has intersection at leg = %d, alpha = %g, lambda = %g\n", + tlen, dogLegID_, dogLegAlpha_, lambda); + } + /* + * Figure out the new step vector, step_1, based on (leg, alpha). Here we are using the + * intersection of the trust oval with the dog-leg curve. + */ + fillDogLegStep(dogLegID_, dogLegAlpha_, step_1); - /* - * OK, now that we have step0, Bound the step - */ - m_dampBound = boundStep(y_n_curr, DATA_PTR(step_1)); - /* - * Decrease the step length if we are bound - */ - if (m_dampBound < 1.0) { - for (size_t j = 0; j < neq_; j++) { - step_1[j] = step_1[j] * m_dampBound; - } - } - /* - * Calculate the new solution value y1[] given the step size - */ - for (size_t j = 0; j < neq_; j++) { - y_n_1[j] = y_n_curr[j] + step_1[j]; - } - /* - * Calculate the new solution time derivative given the step size - */ - if (solnType_ != NSOLN_TYPE_STEADY_STATE) { - calc_ydot(m_order, y_n_1, ydot_n_1); - } - /* - * OK, we have the step0. Now, ask the question whether it satisfies the acceptance criteria - * as a good step. The overall outcome is returned in the variable info. - */ - info = decideStep(time_curr, dogLegID_, dogLegAlpha_, y_n_curr, ydot_n_curr, step_1, - y_n_1, ydot_n_1, trustDeltaOld); - m_normResid_Bound = m_normResid_1; + /* + * OK, now that we have step0, Bound the step + */ + m_dampBound = boundStep(y_n_curr, DATA_PTR(step_1)); + /* + * Decrease the step length if we are bound + */ + if (m_dampBound < 1.0) { + for (j = 0; j < neq_; j++) { + step_1[j] = step_1[j] * m_dampBound; + } + } + /* + * Calculate the new solution value y1[] given the step size + */ + for (j = 0; j < neq_; j++) { + y_n_1[j] = y_n_curr[j] + step_1[j]; + } + /* + * Calculate the new solution time derivative given the step size + */ + if (solnType_ != NSOLN_TYPE_STEADY_STATE) { + calc_ydot(m_order, y_n_1, ydot_n_1); + } + /* + * OK, we have the step0. Now, ask the question whether it satisfies the acceptance criteria + * as a good step. The overall outcome is returned in the variable info. + */ + info = decideStep(time_curr, dogLegID_, dogLegAlpha_, y_n_curr, ydot_n_curr, step_1, + y_n_1, ydot_n_1, trustDeltaOld); + m_normResid_Bound = m_normResid_1; - /* - * The algorithm failed to find a solution vector sufficiently different than the current point - */ - if (info == -1) { + /* + * The algorithm failed to find a solution vector sufficiently different than the current point + */ + if (info == -1) { - if (m_print_flag >= 1) { - doublereal stepNorm = solnErrorNorm(DATA_PTR(step_1)); - printf("\t\t dampDogLeg: Current direction rejected, update became too small %g\n", stepNorm); - success = false; - break; - } - } - if (info == -2) { - if (m_print_flag >= 1) { - printf("\t\t dampDogLeg: current trial step and damping led to LAPACK ERROR %d. Bailing\n", info); - success = false; - break; - } - } - if (info == 0) { - success = true; - break; - } - if (info == 3) { + if (m_print_flag >= 1) { + doublereal stepNorm = solnErrorNorm(DATA_PTR(step_1)); + printf("\t\t dampDogLeg: Current direction rejected, update became too small %g\n", stepNorm); + success = false; + retn = NSOLN_RETN_FAIL_STEPTOOSMALL; + break; + } + } + if (info == -2) { + if (m_print_flag >= 1) { + printf("\t\t dampDogLeg: current trial step and damping led to LAPACK ERROR %d. Bailing\n", info); + success = false; + retn = NSOLN_RETN_MATRIXINVERSIONERROR; + break; + } + } + if (info == 0) { + success = true; + break; + } + if (info == 3) { - haveASuccess = true; - // Store the good results in stepLastGood - mdp::mdp_copy_dbl_1(DATA_PTR(stepLastGood), CONSTD_DATA_PTR(step_1), (int) neq_); - // Within the program decideStep(), we have already increased the value of trustDelta_. We store the - // value of step0 in step1, recalculate a larger step0 in the next fillDogLegStep(), - // and then attempt to see if the larger step works in the next iteration - } - if (info == 2) { - // Step was a failure. If we had a previous success with a smaller stepsize, haveASuccess is true - // and we execute the next block and break. If we didn't have a previous success, trustDelta_ has - // already been decreased in the decideStep() routine. We go back and try another iteration with - // a smaller trust region. - if (haveASuccess) { - mdp::mdp_copy_dbl_1(DATA_PTR(step_1), CONSTD_DATA_PTR(stepLastGood), (int) neq_); - for (size_t j = 0; j < neq_; j++) { - y_n_1[j] = y_n_curr[j] + step_1[j]; - } - if (solnType_ != NSOLN_TYPE_STEADY_STATE) { - calc_ydot(m_order, y_n_1, ydot_n_1); - } - success = true; - break; - } else { + haveASuccess = true; + // Store the good results in stepLastGood + mdp::mdp_copy_dbl_1(DATA_PTR(stepLastGood), CONSTD_DATA_PTR(step_1), neq_); + // Within the program decideStep(), we have already increased the value of trustDelta_. We store the + // value of step0 in step1, recalculate a larger step0 in the next fillDogLegStep(), + // and then attempt to see if the larger step works in the next iteration + } + if (info == 2) { + // Step was a failure. If we had a previous success with a smaller stepsize, haveASuccess is true + // and we execute the next block and break. If we didn't have a previous success, trustDelta_ has + // already been decreased in the decideStep() routine. We go back and try another iteration with + // a smaller trust region. + if (haveASuccess) { + mdp::mdp_copy_dbl_1(DATA_PTR(step_1), CONSTD_DATA_PTR(stepLastGood), neq_); + for (j = 0; j < neq_; j++) { + y_n_1[j] = y_n_curr[j] + step_1[j]; + } + if (solnType_ != NSOLN_TYPE_STEADY_STATE) { + calc_ydot(m_order, y_n_1, ydot_n_1); + } + success = true; + break; + } else { - } - } + } + } } /* @@ -2801,59 +2813,60 @@ int NonlinearSolver::dampDogLeg(const doublereal time_curr, const doublereal* y_ stepNorm_1 = solnErrorNorm(DATA_PTR(step_1)); stepNorm_2 = stepNorm_1; if (m_dampBound < 1.0) { - stepNorm_2 /= m_dampBound; + stepNorm_2 /= m_dampBound; } stepNorm_2 /= lambda; stepNorm_2 *= m_normResidTrial / m_normResid_0; - + if (success) { - if (m_normResidTrial < 1.0) { - if (normTrust_Newton_ < trustDelta_ && m_dampBound == 1.0) { - return 1; - } else { - return 0; - } - } - return 0; + if (m_normResidTrial < 1.0) { + if (normTrust_Newton_ < trustDelta_ && m_dampBound == 1.0) { + return 1; + } else { + return 0; + } + } + return 0; } return NSOLN_RETN_FAIL_DAMPSTEP; -} -//==================================================================================================================== -// Decide whether the current step is acceptable and adjust the trust region size -/* - * This is an extension of algorithm 6.4.5 of Dennis and Schnabel. - * - * Here we decide whether to accept the current step - * At the end of the calculation a new estimate of the trust region is calculated - * - * @param time_curr INPUT Current value of the time - * @param leg INPUT Leg of the dogleg that we are on - * @param alpha INPUT Distance down that leg that we are on - * @param y0 INPUT Current value of the solution vector - * @param ydot0 INPUT Current value of the derivative of the solution vector - * @param step0 INPUT Trial step - * @param y1 OUTPUT Solution values at the conditions which are evaluated for success - * @param ydot1 OUTPUT Time derivates of solution at the conditions which are evaluated for success - * @param trustDeltaOld INPUT Value of the trust length at the old conditions - * - * - * @return This function returns a code which indicates whether the step will be accepted or not. - * 3 Step passed with flying colors. Try redoing the calculation with a bigger trust region. - * 2 Step didn't pass deltaF requirement. Decrease the size of the next trust region for a retry and return - * 0 The step passed. - * -1 The step size is now too small (||d || < 0.1). A really small step isn't decreasing the function. - * This is an error condition. - * -2 Current value of the solution vector caused a residual error in its evaluation. - * Step is a failure, and the step size must be reduced in order to proceed further. - */ -int NonlinearSolver::decideStep(const doublereal time_curr, int leg, doublereal alpha, - const doublereal* const y_n_curr, - const doublereal* const ydot_n_curr, const std::vector & step_1, - const doublereal* const y_n_1, const doublereal* const ydot_n_1, - doublereal trustDeltaOld) -{ + } + //==================================================================================================================== + // Decide whether the current step is acceptable and adjust the trust region size + /* + * This is an extension of algorithm 6.4.5 of Dennis and Schnabel. + * + * Here we decide whether to accept the current step + * At the end of the calculation a new estimate of the trust region is calculated + * + * @param time_curr INPUT Current value of the time + * @param leg INPUT Leg of the dogleg that we are on + * @param alpha INPUT Distance down that leg that we are on + * @param y0 INPUT Current value of the solution vector + * @param ydot0 INPUT Current value of the derivative of the solution vector + * @param step0 INPUT Trial step + * @param y1 OUTPUT Solution values at the conditions which are evalulated for success + * @param ydot1 OUTPUT Time derivates of solution at the conditions which are evalulated for success + * @param trustDeltaOld INPUT Value of the trust length at the old conditions + * + * + * @return This function returns a code which indicates whether the step will be accepted or not. + * 3 Step passed with flying colors. Try redoing the calculation with a bigger trust region. + * 2 Step didn't pass deltaF requirement. Decrease the size of the next trust region for a retry and return + * 0 The step passed. + * -1 The step size is now too small (||d || < 0.1). A really small step isn't decreasing the function. + * This is an error condition. + * -2 Current value of the solution vector caused a residual error in its evaluation. + * Step is a failure, and the step size must be reduced in order to proceed further. + */ + int NonlinearSolver::decideStep(const doublereal time_curr, int leg, doublereal alpha, + const doublereal * const y_n_curr, + const doublereal * const ydot_n_curr, const std::vector & step_1, + const doublereal * const y_n_1, const doublereal * const ydot_n_1, + doublereal trustDeltaOld) + { int retn = 2; + bool goodStep = false; int info; doublereal ll; // Calculate the solution step length @@ -2865,36 +2878,36 @@ int NonlinearSolver::decideStep(const doublereal time_curr, int leg, doublereal // Calculate the distance to the cauchy point doublereal cauchyDistanceNorm = solnErrorNorm(DATA_PTR(deltaX_CP_)); - // This is the expected initial rate of decrease in the cauchy direction. + // This is the expected inital rate of decrease in the cauchy direction. // -> This is Eqn. 29 = Rhat dot Jhat dy / || d || doublereal funcDecreaseSDExp = RJd_norm_ / cauchyDistanceNorm * lambdaStar_; if (funcDecreaseSDExp > 0.0) { - if (m_print_flag >= 5) { - printf("\t\tdecideStep(): Unexpected condition -> cauchy slope is positive\n"); - } + if (m_print_flag >= 5) { + printf("\t\tdecideStep(): Unexpected condition -> cauchy slope is positive\n"); + } } - + /* * Calculate the residual that would result if y1[] were the new solution vector. * The Lagged solution components are kept lagged here. Unfortunately, it just doesn't work in some cases to use a * Jacobian from a lagged state and then use a residual from an unlagged condition. The linear model doesn't - * agree with the nonlinear model. + * agree with the nonlinear model. * -> m_resid[] contains the result of the residual calculation */ if (solnType_ != NSOLN_TYPE_STEADY_STATE) { - info = doResidualCalc(time_curr, solnType_, y_n_1, ydot_n_1, Base_LaggedSolutionComponents); + info = doResidualCalc(time_curr, solnType_, y_n_1, ydot_n_1, Base_LaggedSolutionComponents); } else { - info = doResidualCalc(time_curr, solnType_, y_n_1, ydot_n_curr, Base_LaggedSolutionComponents); + info = doResidualCalc(time_curr, solnType_, y_n_1, ydot_n_curr, Base_LaggedSolutionComponents); } if (info != 1) { - if (m_print_flag >= 2) { - printf("\t\tdecideStep: current trial step and damping led to Residual Calc ERROR %d. Bailing\n", info); - } - return -2; + if (m_print_flag >= 2) { + printf("\t\tdecideStep: current trial step and damping led to Residual Calc ERROR %d. Bailing\n", info); + } + return -2; } /* - * Ok we have a successful new residual. Calculate the normalized residual value and store it in + * Ok we have a successful new residual. Calculate the normalized residual value and store it in * m_normResidTrial */ m_normResidTrial = residErrorNorm(DATA_PTR(m_resid)); @@ -2907,147 +2920,152 @@ int NonlinearSolver::decideStep(const doublereal time_curr, int leg, doublereal doublereal funcDecrease = 0.5 * (normResidTrial_2 - normResid0_2); doublereal acceptableDelF = funcDecreaseSDExp * stepNorm * 1.0E-4; if (funcDecrease < acceptableDelF) { - m_normResid_1 = m_normResidTrial; - m_normResid_1 = m_normResidTrial; - retn = 0; - if (m_print_flag >= 4) { - printf("\t\t decideStep: Norm Residual(leg=%1d, alpha=%10.2E) = %11.4E passes\n", - dogLegID_, dogLegAlpha_, m_normResidTrial); - } + m_normResid_1 = m_normResidTrial; + goodStep = true; + m_normResid_1 = m_normResidTrial; + retn = 0; + if (m_print_flag >= 4) { + printf("\t\t decideStep: Norm Residual(leg=%1d, alpha=%10.2E) = %11.4E passes\n", + dogLegID_, dogLegAlpha_, m_normResidTrial); + } } else { - if (m_print_flag >= 4) { - printf("\t\t decideStep: Norm Residual(leg=%1d, alpha=%10.2E) = %11.4E failes\n", - dogLegID_, dogLegAlpha_, m_normResidTrial); - } - trustDelta_ *= 0.33; - CurrentTrustFactor_ *= 0.33; - retn = 2; - // error condition if step is getting too small - if (rtol_ * stepNorm < 1.0E-6) { - retn = -1; - } - return retn; + if (m_print_flag >= 4) { + printf("\t\t decideStep: Norm Residual(leg=%1d, alpha=%10.2E) = %11.4E failes\n", + dogLegID_, dogLegAlpha_, m_normResidTrial); + } + trustDelta_ *= 0.33; + CurrentTrustFactor_ *= 0.33; + retn = 2; + // error condition if step is getting too small + if (rtol_ * stepNorm < 1.0E-6) { + retn = -1; + } + return retn; } - /* + /* * Figure out the next trust region. We are here iff retn = 0 * * If we had to bounds delta the update, decrease the trust region */ if (m_dampBound < 1.0) { - // trustDelta_ *= 0.5; - // NextTrustFactor_ *= 0.5; - // ll = trustRegionLength(); - // if (m_print_flag >= 5) { - // printf("\t\tdecideStep(): Trust region decreased from %g to %g due to bounds constraint\n", ll*2, ll); - //} + // trustDelta_ *= 0.5; + // NextTrustFactor_ *= 0.5; + // ll = trustRegionLength(); + // if (m_print_flag >= 5) { + // printf("\t\tdecideStep(): Trust region decreased from %g to %g due to bounds constraint\n", ll*2, ll); + //} } else { - retn = 0; - /* - * Calculate the expected residual from the quadratic model - */ - doublereal expectedNormRes = expectedResidLeg(leg, alpha); - doublereal expectedFuncDecrease = 0.5 * (neq_ * expectedNormRes * expectedNormRes - normResid0_2); - if (funcDecrease > 0.1 * expectedFuncDecrease) { - if ((m_normResidTrial > 0.5 * m_normResid_0) && (m_normResidTrial > 0.1)) { - trustDelta_ *= 0.5; - NextTrustFactor_ *= 0.5; - ll = trustRegionLength(); - if (m_print_flag >= 4) { - printf("\t\t decideStep: Trust region decreased from %g to %g due to bad quad approximation\n", - ll*2, ll); - } - } - } else { - /* - * If we are doing well, consider increasing the trust region and recalculating - */ - if (funcDecrease < 0.8 * expectedFuncDecrease || (m_normResidTrial < 0.33 * m_normResid_0)) { - if (trustDelta_ <= trustDeltaOld && (leg != 2 || alpha < 0.75)) { - trustDelta_ *= 2.0; - CurrentTrustFactor_ *= 2; - adjustUpStepMinimums(); - ll = trustRegionLength(); - if (m_print_flag >= 4) { - if (m_normResidTrial < 0.33 * m_normResid_0) { - printf("\t\t decideStep: Redo line search with trust region increased from %g to %g due to good nonlinear behavior\n", - ll*0.5, ll); - } else { - printf("\t\t decideStep: Redi line search with trust region increased from %g to %g due to good linear model approximation\n", - ll*0.5, ll); - } - } - retn = 3; - } else { - /* - * Increase the size of the trust region for the next calculation - */ - if (m_normResidTrial < 0.99 * expectedNormRes || (m_normResidTrial < 0.20 * m_normResid_0) || - (funcDecrease < -1.0E-50 && (funcDecrease < 0.9 *expectedFuncDecrease))) { - if (leg == 2 && alpha == 1.0) { - ll = trustRegionLength(); - if (ll < 2.0 * m_normDeltaSoln_Newton) { - trustDelta_ *= 2.0; - NextTrustFactor_ *= 2.0; - adjustUpStepMinimums(); - ll = trustRegionLength(); - if (m_print_flag >= 4) { - printf("\t\t decideStep: Trust region further increased from %g to %g next step due to good linear model behavior\n", - ll*0.5, ll); - } - } - } else { - ll = trustRegionLength(); - trustDelta_ *= 2.0; - NextTrustFactor_ *= 2.0; - adjustUpStepMinimums(); - ll = trustRegionLength(); - if (m_print_flag >= 4) { - printf("\t\t decideStep: Trust region further increased from %g to %g next step due to good linear model behavior\n", - ll*0.5, ll); - } - } - } - } - } - } + retn = 0; + /* + * Calculate the expected residual from the quadratic model + */ + doublereal expectedNormRes = expectedResidLeg(leg, alpha); + doublereal expectedFuncDecrease = 0.5 * (neq_ * expectedNormRes * expectedNormRes - normResid0_2); + if (funcDecrease > 0.1 * expectedFuncDecrease) { + if ((m_normResidTrial > 0.5 * m_normResid_0) && (m_normResidTrial > 0.1)) { + trustDelta_ *= 0.5; + NextTrustFactor_ *= 0.5; + ll = trustRegionLength(); + if (m_print_flag >= 4) { + printf("\t\t decideStep: Trust region decreased from %g to %g due to bad quad approximation\n", + ll*2, ll); + } + } + } else { + /* + * If we are doing well, consider increasing the trust region and recalculating + */ + if (funcDecrease < 0.8 * expectedFuncDecrease || (m_normResidTrial < 0.33 * m_normResid_0)) { + if (trustDelta_ <= trustDeltaOld && (leg != 2 || alpha < 0.75) ) { + trustDelta_ *= 2.0; + CurrentTrustFactor_ *= 2; + adjustUpStepMinimums(); + ll = trustRegionLength(); + if (m_print_flag >= 4) { + if (m_normResidTrial < 0.33 * m_normResid_0) { + printf("\t\t decideStep: Redo line search with trust region increased from %g to %g due to good nonlinear behavior\n", + ll*0.5, ll); + } else { + printf("\t\t decideStep: Redi line search with trust region increased from %g to %g due to good linear model approximation\n", + ll*0.5, ll); + } + } + retn = 3; + } else { + /* + * Increase the size of the trust region for the next calculation + */ + if (m_normResidTrial < 0.99 * expectedNormRes || (m_normResidTrial < 0.20 * m_normResid_0) || + (funcDecrease < -1.0E-50 && ( funcDecrease < 0.9 *expectedFuncDecrease)) ) { + if (leg == 2 && alpha == 1.0 ) { + ll = trustRegionLength(); + if (ll < 2.0 * m_normDeltaSoln_Newton) { + trustDelta_ *= 2.0; + NextTrustFactor_ *= 2.0; + adjustUpStepMinimums(); + ll = trustRegionLength(); + if (m_print_flag >= 4) { + printf("\t\t decideStep: Trust region further increased from %g to %g next step due to good linear model behavior\n", + ll*0.5, ll); + } + } + } else { + ll = trustRegionLength(); + trustDelta_ *= 2.0; + NextTrustFactor_ *= 2.0; + adjustUpStepMinimums(); + ll = trustRegionLength(); + if (m_print_flag >= 4) { + printf("\t\t decideStep: Trust region further increased from %g to %g next step due to good linear model behavior\n", + ll*0.5, ll); + } + } + } + } + } + } } return retn; -} -//==================================================================================================================== -/* - * solve_nonlinear_problem(): - * - * 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. - * - * SolnType = TRANSIENT -> we will assume we are relaxing a transient - * equation system for now. Will make it more general later, - * if an application comes up. - * - * @return A positive value indicates a successful convergence - * -1 Failed convergence - */ -int NonlinearSolver::solve_nonlinear_problem(int SolnType, doublereal* const y_comm, doublereal* const ydot_comm, - doublereal CJ, doublereal time_curr, GeneralMatrix& jac, - int& num_newt_its, int& num_linear_solves, - int& num_backtracks, int loglevelInput) -{ + } + //==================================================================================================================== + /* + * solve_nonlinear_problem(): + * + * 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. + * + * SolnType = TRANSIENT -> we will assume we are relaxing a transient + * equation system for now. Will make it more general later, + * if an application comes up. + * + * @return A positive value indicates a successful convergence + * -1 Failed convergence + */ + int NonlinearSolver::solve_nonlinear_problem(int SolnType, doublereal * const y_comm, doublereal * const ydot_comm, + doublereal CJ, doublereal time_curr, GeneralMatrix& jac, + int &num_newt_its, int &num_linear_solves, + int &num_backtracks, int loglevelInput) + { clockWC wc; int convRes = 0; solnType_ = SolnType; int info = 0; + if (neq_ <= 0) { + return 1; + } + bool m_residCurrent = false; num_linear_solves -= m_numTotalLinearSolves; int retnDamp = 0; int retnCode = 0; bool forceNewJac = false; if (jacCopyPtr_) { - delete jacCopyPtr_; + delete jacCopyPtr_; } jacCopyPtr_ = jac.duplMyselfAsGeneralMatrix(); - + doublereal stepNorm_1; doublereal stepNorm_2; #ifdef DEBUG_MODE @@ -3056,12 +3074,12 @@ int NonlinearSolver::solve_nonlinear_problem(int SolnType, doublereal* const y_c #endif bool trInit = false; - - mdp::mdp_copy_dbl_1(DATA_PTR(m_y_n_curr), DATA_PTR(y_comm), (int) neq_); - + + mdp::mdp_copy_dbl_1(DATA_PTR(m_y_n_curr), DATA_PTR(y_comm), neq_); + if (SolnType != NSOLN_TYPE_STEADY_STATE || ydot_comm) { - mdp::mdp_copy_dbl_1(DATA_PTR(m_ydot_n_curr), ydot_comm, (int) neq_); - mdp::mdp_copy_dbl_1(DATA_PTR(m_ydot_n_1), ydot_comm, (int) neq_); + mdp::mdp_copy_dbl_1(DATA_PTR(m_ydot_n_curr), ydot_comm, neq_); + mdp::mdp_copy_dbl_1(DATA_PTR(m_ydot_n_1), ydot_comm, neq_); } // Redo the solution weights every time we enter the function createSolnWeights(DATA_PTR(m_y_n_curr)); @@ -3073,879 +3091,905 @@ int NonlinearSolver::solve_nonlinear_problem(int SolnType, doublereal* const y_c m_print_flag = loglevelInput; if (trustRegionInitializationMethod_ == 0) { - trInit = true; + trInit = true; } else if (trustRegionInitializationMethod_ == 1) { - trInit = true; - initializeTrustRegion(); + trInit = true; + initializeTrustRegion(); } else { - mdp::mdp_init_dbl_1(DATA_PTR(deltaX_trust_), 1.0, (int) neq_); - trustDelta_ = 1.0; + mdp::mdp_init_dbl_1(DATA_PTR(deltaX_trust_), 1.0, neq_); + trustDelta_ = 1.0; } if (m_print_flag == 2 || m_print_flag == 3) { - printf("\tsolve_nonlinear_problem():\n\n"); - if (doDogLeg_) { - printf("\tWt Iter Resid NewJac log(CN)| dRdS_CDexp dRdS_CD dRdS_Newtexp dRdS_Newt |" - "DS_Cauchy DS_Newton DS_Trust | legID legAlpha Fbound | CTF NTF | nTr|" - "DS_Final ResidLag ResidFull\n"); - printf("\t---------------------------------------------------------------------------------------------------" - "--------------------------------------------------------------------------------\n"); - } else { - printf("\t Wt Iter Resid NewJac | Fbound ResidBound | DampIts Fdamp DS_Step1 DS_Step2" - "ResidLag | DS_Damp DS_Newton ResidFull\n"); - printf("\t--------------------------------------------------------------------------------------------------" - "----------------------------------\n"); - } + printf("\tsolve_nonlinear_problem():\n\n"); + if (doDogLeg_) { + printf("\tWt Iter Resid NewJac log(CN)| dRdS_CDexp dRdS_CD dRdS_Newtexp dRdS_Newt |" + "DS_Cauchy DS_Newton DS_Trust | legID legAlpha Fbound | CTF NTF | nTr|" + "DS_Final ResidLag ResidFull\n"); + printf("\t---------------------------------------------------------------------------------------------------" + "--------------------------------------------------------------------------------\n"); + } else { + printf("\t Wt Iter Resid NewJac | Fbound ResidBound | DampIts Fdamp DS_Step1 DS_Step2" + "ResidLag | DS_Damp DS_Newton ResidFull\n"); + printf("\t--------------------------------------------------------------------------------------------------" + "----------------------------------\n"); + } } while (1 > 0) { - CurrentTrustFactor_ = 1.0; - NextTrustFactor_ = 1.0; - ResidWtsReevaluated_ = false; - i_numTrials = 0; - /* - * Increment Newton Solve counter - */ - m_numTotalNewtIts++; - num_newt_its++; - m_numLocalLinearSolves = 0; + CurrentTrustFactor_ = 1.0; + NextTrustFactor_ = 1.0; + ResidWtsReevaluated_ = false; + i_numTrials = 0; + /* + * Increment Newton Solve counter + */ + m_numTotalNewtIts++; + num_newt_its++; + m_numLocalLinearSolves = 0; - if (m_print_flag > 3) { - printf("\t"); - print_line("=", 119); - printf("\tsolve_nonlinear_problem(): iteration %d:\n", - num_newt_its); - } - /* - * If we are far enough away from the solution, redo the solution weights and the trust vectors. - */ - if (m_normDeltaSoln_Newton > 1.0E2) { - createSolnWeights(DATA_PTR(m_y_n_curr)); + if (m_print_flag > 3) { + printf("\t"); + print_line("=", 119); + printf("\tsolve_nonlinear_problem(): iteration %d:\n", + num_newt_its); + } + /* + * If we are far enough away from the solution, redo the solution weights and the trust vectors. + */ + if (m_normDeltaSoln_Newton > 1.0E2) { + createSolnWeights(DATA_PTR(m_y_n_curr)); #ifdef DEBUG_MODE - if (trInit) { - readjustTrustVector(); - } + if (trInit) { + readjustTrustVector(); + } #else - if (doDogLeg_ && trInit) { - readjustTrustVector(); - } + if (doDogLeg_ && trInit) { + readjustTrustVector(); + } #endif - } else { - // Do this stuff every 5 iterations - if ((num_newt_its % 5) == 1) { - createSolnWeights(DATA_PTR(m_y_n_curr)); + } else { + // Do this stuff every 5 iterations + if ((num_newt_its % 5) == 1) { + createSolnWeights(DATA_PTR(m_y_n_curr)); #ifdef DEBUG_MODE - if (trInit) { - readjustTrustVector(); - } + if (trInit) { + readjustTrustVector(); + } #else - if (doDogLeg_ && trInit) { - readjustTrustVector(); - } + if (doDogLeg_ && trInit) { + readjustTrustVector(); + } #endif - } - } + } + } + + /* + * Set default values of Delta bounds constraints + */ + if (!m_manualDeltaStepSet) { + setDefaultDeltaBoundsMagnitudes(); + } - /* - * Set default values of Delta bounds constraints - */ - if (!m_manualDeltaStepSet) { - setDefaultDeltaBoundsMagnitudes(); - } - - // Check whether the Jacobian should be re-evaluated. - - forceNewJac = true; - - if (forceNewJac) { - if (m_print_flag > 3) { - printf("\t solve_nonlinear_problem(): Getting a new Jacobian\n"); - } - info = beuler_jac(jac, DATA_PTR(m_resid), time_curr, CJ, DATA_PTR(m_y_n_curr), - DATA_PTR(m_ydot_n_curr), num_newt_its); - if (info != 1) { - if (m_print_flag > 0) { - printf("\t solve_nonlinear_problem(): Jacobian Formation Error: %d Bailing\n", info); - } - retnDamp = NSOLN_RETN_JACOBIANFORMATIONERROR ; - goto done; - } - } else { - if (m_print_flag > 1) { - printf("\t solve_nonlinear_problem(): Solving system with old jacobian\n"); - } - } - /* - * Go get new scales - */ - calcColumnScales(); + // Check whether the Jacobian should be re-evaluated. + + forceNewJac = true; + + if (forceNewJac) { + if (m_print_flag > 3) { + printf("\t solve_nonlinear_problem(): Getting a new Jacobian\n"); + } + info = beuler_jac(jac, DATA_PTR(m_resid), time_curr, CJ, DATA_PTR(m_y_n_curr), + DATA_PTR(m_ydot_n_curr), num_newt_its); + if (info != 1) { + if (m_print_flag > 0) { + printf("\t solve_nonlinear_problem(): Jacobian Formation Error: %d Bailing\n", info); + } + retnDamp = NSOLN_RETN_JACOBIANFORMATIONERROR ; + goto done; + } + m_residCurrent = true; + } else { + if (m_print_flag > 1) { + printf("\t solve_nonlinear_problem(): Solving system with old jacobian\n"); + } + m_residCurrent = false; + } + /* + * Go get new scales + */ + calcColumnScales(); - /* - * Calculate the base residual - */ - if (m_print_flag >= 6) { - printf("\t solve_nonlinear_problem(): Calculate the base residual\n"); - } - info = doResidualCalc(time_curr, NSOLN_TYPE_STEADY_STATE, DATA_PTR(m_y_n_curr), DATA_PTR(m_ydot_n_curr)); - if (info != 1) { - if (m_print_flag > 0) { - printf("\t solve_nonlinear_problem(): Residual Calc ERROR %d. Bailing\n", info); - } - retnDamp = NSOLN_RETN_RESIDUALFORMATIONERROR; - goto done; - } + /* + * Calculate the base residual + */ + if (m_print_flag >= 6) { + printf("\t solve_nonlinear_problem(): Calculate the base residual\n"); + } + info = doResidualCalc(time_curr, NSOLN_TYPE_STEADY_STATE, DATA_PTR(m_y_n_curr), DATA_PTR(m_ydot_n_curr)); + if (info != 1) { + if (m_print_flag > 0) { + printf("\t solve_nonlinear_problem(): Residual Calc ERROR %d. Bailing\n", info); + } + retnDamp = NSOLN_RETN_RESIDUALFORMATIONERROR; + goto done; + } - /* - * Scale the matrix and the rhs, if they aren't already scaled - * Figure out and store the residual scaling factors. - */ - scaleMatrix(jac, DATA_PTR(m_y_n_curr), DATA_PTR(m_ydot_n_curr), time_curr, num_newt_its); - - - /* - * Optional print out the initial residual - */ - if (m_print_flag >= 6) { - m_normResid_0 = residErrorNorm(DATA_PTR(m_resid), "Initial norm of the residual", 10, DATA_PTR(m_y_n_curr)); - } else { - m_normResid_0 = residErrorNorm(DATA_PTR(m_resid), "Initial norm of the residual", 0, DATA_PTR(m_y_n_curr)); - if (m_print_flag == 4 || m_print_flag == 5) { - printf("\t solve_nonlinear_problem(): Initial Residual Norm = %13.4E\n", m_normResid_0); - } - } + /* + * Scale the matrix and the rhs, if they aren't already scaled + * Figure out and store the residual scaling factors. + */ + scaleMatrix(jac, DATA_PTR(m_y_n_curr), DATA_PTR(m_ydot_n_curr), time_curr, num_newt_its); + /* + * Optional print out the initial residual + */ + if (m_print_flag >= 6) { + m_normResid_0 = residErrorNorm(DATA_PTR(m_resid), "Initial norm of the residual", 10, DATA_PTR(m_y_n_curr)); + } else { + m_normResid_0 = residErrorNorm(DATA_PTR(m_resid), "Initial norm of the residual", 0, DATA_PTR(m_y_n_curr)); + if (m_print_flag == 4 || m_print_flag == 5 ) { + printf("\t solve_nonlinear_problem(): Initial Residual Norm = %13.4E\n", m_normResid_0); + } + } + + #ifdef DEBUG_MODE - if (m_print_flag > 3) { - printf("\t solve_nonlinear_problem(): Calculate the steepest descent direction and Cauchy Point\n"); - } - m_normDeltaSoln_CP = doCauchyPointSolve(jac); - + if (m_print_flag > 3) { + printf("\t solve_nonlinear_problem(): Calculate the steepest descent direction and Cauchy Point\n"); + } + m_normDeltaSoln_CP = doCauchyPointSolve(jac); + #else - if (doDogLeg_) { - if (m_print_flag > 3) { - printf("\t solve_nonlinear_problem(): Calculate the steepest descent direction and Cauchy Point\n"); - } - m_normDeltaSoln_CP = doCauchyPointSolve(jac); - } + if (doDogLeg_) { + if (m_print_flag > 3) { + printf("\t solve_nonlinear_problem(): Calculate the steepest descent direction and Cauchy Point\n"); + } + m_normDeltaSoln_CP = doCauchyPointSolve(jac); + } #endif - // compute the undamped Newton step - if (doAffineSolve_) { - if (m_print_flag >= 4) { - printf("\t solve_nonlinear_problem(): Calculate the Newton direction via an Affine solve\n"); - } - info = doAffineNewtonSolve(DATA_PTR(m_y_n_curr), DATA_PTR(m_ydot_n_curr), DATA_PTR(deltaX_Newton_), jac); - } else { - if (m_print_flag >= 4) { - printf("\t solve_nonlinear_problem(): Calculate the Newton direction via a Newton solve\n"); - } - info = doNewtonSolve(time_curr, DATA_PTR(m_y_n_curr), DATA_PTR(m_ydot_n_curr), DATA_PTR(deltaX_Newton_), jac); - } + // compute the undamped Newton step + if (doAffineSolve_) { + if (m_print_flag >= 4) { + printf("\t solve_nonlinear_problem(): Calculate the Newton direction via an Affine solve\n"); + } + info = doAffineNewtonSolve(DATA_PTR(m_y_n_curr), DATA_PTR(m_ydot_n_curr), DATA_PTR(deltaX_Newton_), jac); + } else { + if (m_print_flag >= 4) { + printf("\t solve_nonlinear_problem(): Calculate the Newton direction via a Newton solve\n"); + } + info = doNewtonSolve(time_curr, DATA_PTR(m_y_n_curr), DATA_PTR(m_ydot_n_curr), DATA_PTR(deltaX_Newton_), jac); + } - if (info) { - retnDamp = NSOLN_RETN_MATRIXINVERSIONERROR; - if (m_print_flag > 0) { - printf("\t solve_nonlinear_problem(): Matrix Inversion Error: %d Bailing\n", info); - } - goto done; - } - mdp::mdp_copy_dbl_1(DATA_PTR(m_step_1), CONSTD_DATA_PTR(deltaX_Newton_), (int) neq_); + if (info) { + retnDamp = NSOLN_RETN_MATRIXINVERSIONERROR; + if (m_print_flag > 0) { + printf("\t solve_nonlinear_problem(): Matrix Inversion Error: %d Bailing\n", info); + } + goto done; + } + mdp::mdp_copy_dbl_1(DATA_PTR(m_step_1), CONSTD_DATA_PTR(deltaX_Newton_), neq_); - if (m_print_flag >= 6) { - m_normDeltaSoln_Newton = solnErrorNorm(DATA_PTR(deltaX_Newton_), "Initial Undamped Newton Step of the iteration", 10); - } else { - m_normDeltaSoln_Newton = solnErrorNorm(DATA_PTR(deltaX_Newton_), "Initial Undamped Newton Step of the iteration", 0); - } + if (m_print_flag >= 6) { + m_normDeltaSoln_Newton = solnErrorNorm(DATA_PTR(deltaX_Newton_), "Initial Undamped Newton Step of the iteration", 10); + } else { + m_normDeltaSoln_Newton = solnErrorNorm(DATA_PTR(deltaX_Newton_), "Initial Undamped Newton Step of the iteration", 0); + } - if (m_numTotalNewtIts == 1) { - if (trustRegionInitializationMethod_ == 2 || trustRegionInitializationMethod_ == 3) { - if (m_print_flag > 3) { - if (trustRegionInitializationMethod_ == 2) { - printf("\t solve_nonlinear_problem(): Initialize the trust region size as the length of the Cauchy Vector times %f\n", - trustRegionInitializationFactor_); - } else { - printf("\t solve_nonlinear_problem(): Initialize the trust region size as the length of the Newton Vector times %f\n", - trustRegionInitializationFactor_); - } - } - initializeTrustRegion(); - trInit = true; - } - } + if (m_numTotalNewtIts == 1) { + if (trustRegionInitializationMethod_ == 2 || trustRegionInitializationMethod_ == 3) { + if (m_print_flag > 3) { + if (trustRegionInitializationMethod_ == 2) { + printf("\t solve_nonlinear_problem(): Initialize the trust region size as the length of the Cauchy Vector times %f\n", + trustRegionInitializationFactor_); + } else { + printf("\t solve_nonlinear_problem(): Initialize the trust region size as the length of the Newton Vector times %f\n", + trustRegionInitializationFactor_); + } + } + initializeTrustRegion(); + trInit = true; + } + } + - - if (doDogLeg_) { + if (doDogLeg_) { #ifdef DEBUG_MODE - doublereal trustD = calcTrustDistance(m_step_1); - if (m_print_flag >= 4) { - if (trustD > trustDelta_) { - printf("\t\t Newton's method step size, %g trustVectorUnits, larger than trust region, %g trustVectorUnits\n", - trustD, trustDelta_); - printf("\t\t Newton's method step size, %g trustVectorUnits, larger than trust region, %g trustVectorUnits\n", - trustD, trustDelta_); - } else { - printf("\t\t Newton's method step size, %g trustVectorUnits, smaller than trust region, %g trustVectorUnits\n", - trustD, trustDelta_); - } - } + doublereal trustD = calcTrustDistance(m_step_1); + if (m_print_flag >= 4) { + if (trustD > trustDelta_) { + printf("\t\t Newton's method step size, %g trustVectorUnits, larger than trust region, %g trustVectorUnits\n", + trustD, trustDelta_); + printf("\t\t Newton's method step size, %g trustVectorUnits, larger than trust region, %g trustVectorUnits\n", + trustD, trustDelta_); + } else { + printf("\t\t Newton's method step size, %g trustVectorUnits, smaller than trust region, %g trustVectorUnits\n", + trustD, trustDelta_); + } + } #endif - } + } - /* - * Filter out bad directions - */ - filterNewStep(time_curr, DATA_PTR(m_y_n_curr), DATA_PTR(m_step_1)); + /* + * Filter out bad directions + */ + filterNewStep(time_curr, DATA_PTR(m_y_n_curr), DATA_PTR(m_step_1)); + + if (s_print_DogLeg && m_print_flag >= 4) { + printf("\t solve_nonlinear_problem(): Compare descent rates for Cauchy and Newton directions\n"); + descentComparison(time_curr, DATA_PTR(m_ydot_n_curr), DATA_PTR(m_ydot_n_1), i_numTrials); + } else { + if (doDogLeg_) { + descentComparison(time_curr, DATA_PTR(m_ydot_n_curr), DATA_PTR(m_ydot_n_1), i_numTrials); + } + } - if (s_print_DogLeg && m_print_flag >= 4) { - printf("\t solve_nonlinear_problem(): Compare descent rates for Cauchy and Newton directions\n"); - descentComparison(time_curr, DATA_PTR(m_ydot_n_curr), DATA_PTR(m_ydot_n_1), i_numTrials); - } else { - if (doDogLeg_) { - descentComparison(time_curr, DATA_PTR(m_ydot_n_curr), DATA_PTR(m_ydot_n_1), i_numTrials); - } - } - - - - if (doDogLeg_) { - setupDoubleDogleg(); + + + if (doDogLeg_) { + setupDoubleDogleg(); #ifdef DEBUG_MODE - if (s_print_DogLeg && m_print_flag >= 5) { - printf("\t solve_nonlinear_problem(): Compare Linear and nonlinear residuals along double dog-leg path\n"); - residualComparisonLeg(time_curr, DATA_PTR(m_ydot_n_curr), legBest, alphaBest); - } + if (s_print_DogLeg && m_print_flag >= 5) { + printf("\t solve_nonlinear_problem(): Compare Linear and nonlinear residuals along double dog-leg path\n"); + residualComparisonLeg(time_curr, DATA_PTR(m_ydot_n_curr), legBest, alphaBest); + } #endif - if (m_print_flag >= 4) { - printf("\t solve_nonlinear_problem(): Calculate damping along dog-leg path to ensure residual decrease\n"); - } - retnDamp = dampDogLeg(time_curr, DATA_PTR(m_y_n_curr), DATA_PTR(m_ydot_n_curr), - m_step_1, DATA_PTR(m_y_n_1), DATA_PTR(m_ydot_n_1), stepNorm_1, stepNorm_2, jac, i_numTrials); - } + if (m_print_flag >= 4) { + printf("\t solve_nonlinear_problem(): Calculate damping along dog-leg path to ensure residual decrease\n"); + } + retnDamp = dampDogLeg(time_curr, DATA_PTR(m_y_n_curr), DATA_PTR(m_ydot_n_curr), + m_step_1, DATA_PTR(m_y_n_1), DATA_PTR(m_ydot_n_1), stepNorm_1, stepNorm_2, jac, i_numTrials); + } #ifdef DEBUG_MODE - else { - if (s_print_DogLeg && m_print_flag >= 5) { - printf("\t solve_nonlinear_problem(): Compare Linear and nonlinear residuals along double dog-leg path\n"); - residualComparisonLeg(time_curr, DATA_PTR(m_ydot_n_curr), legBest, alphaBest); - } - } -#endif + else { + if (s_print_DogLeg && m_print_flag >= 5) { + printf("\t solve_nonlinear_problem(): Compare Linear and nonlinear residuals along double dog-leg path\n"); + residualComparisonLeg(time_curr, DATA_PTR(m_ydot_n_curr), legBest, alphaBest); + } + } +#endif - // Damp the Newton step - /* - * On return the recommended new solution and derivatisve is located in: - * y_new - * y_dot_new - * The update delta vector is located in - * stp1 - * The estimate of the solution update norm for the next step is located in - * s1 - */ - if (!doDogLeg_) { - retnDamp = dampStep(time_curr, DATA_PTR(m_y_n_curr), DATA_PTR(m_ydot_n_curr), - DATA_PTR(m_step_1), DATA_PTR(m_y_n_1), DATA_PTR(m_ydot_n_1), - DATA_PTR(m_wksp_2), stepNorm_2, jac, frst, i_numTrials); - frst = false; - num_backtracks += i_numTrials; - stepNorm_1 = solnErrorNorm(DATA_PTR(m_step_1)); - } + // Damp the Newton step + /* + * On return the recommended new solution and derivatisve is located in: + * y_new + * y_dot_new + * The update delta vector is located in + * stp1 + * The estimate of the solution update norm for the next step is located in + * s1 + */ + if (!doDogLeg_) { + retnDamp = dampStep(time_curr, DATA_PTR(m_y_n_curr), DATA_PTR(m_ydot_n_curr), + DATA_PTR(m_step_1), DATA_PTR(m_y_n_1), DATA_PTR(m_ydot_n_1), + DATA_PTR(m_wksp_2), stepNorm_2, jac, frst, i_numTrials); + frst = false; + num_backtracks += i_numTrials; + stepNorm_1 = solnErrorNorm(DATA_PTR(m_step_1)); + } - /* - * Impose the minimum number of newton iterations critera - */ - if (num_newt_its < m_min_newt_its) { - if (retnDamp > NSOLN_RETN_CONTINUE) { - if (m_print_flag > 2) { - printf("\t solve_nonlinear_problem(): Damped Newton successful (m=%d) but minimum newton" - "iterations not attained. Resolving ...\n", retnDamp); - } - retnDamp = NSOLN_RETN_CONTINUE; - } - } + /* + * Impose the minimum number of newton iterations critera + */ + if (num_newt_its < m_min_newt_its) { + if (retnDamp > NSOLN_RETN_CONTINUE) { + if (m_print_flag > 2) { + printf("\t solve_nonlinear_problem(): Damped Newton successful (m=%d) but minimum newton" + "iterations not attained. Resolving ...\n", retnDamp); + } + retnDamp = NSOLN_RETN_CONTINUE; + } + } - /* - * Impose max newton iteration - */ - if (num_newt_its > maxNewtIts_) { - retnDamp = NSOLN_RETN_MAXIMUMITERATIONSEXCEEDED; - if (m_print_flag > 1) { - printf("\t solve_nonlinear_problem(): Damped newton unsuccessful (max newts exceeded) sfinal = %g\n", - stepNorm_1); - } - } + /* + * Impose max newton iteration + */ + if (num_newt_its > maxNewtIts_) { + retnDamp = NSOLN_RETN_MAXIMUMITERATIONSEXCEEDED; + if (m_print_flag > 1) { + printf("\t solve_nonlinear_problem(): Damped newton unsuccessful (max newts exceeded) sfinal = %g\n", + stepNorm_1); + } + } - /* - * Do a full residual calculation with the unlagged solution components. - * Then get the norm of the residual - */ - info = doResidualCalc(time_curr, NSOLN_TYPE_STEADY_STATE, DATA_PTR(m_y_n_1), DATA_PTR(m_ydot_n_1)); - if (info != 1) { - if (m_print_flag > 0) { - printf("\t solve_nonlinear_problem(): current trial step and damping led to Residual Calc " - "ERROR %d. Bailing\n", info); - } - retnDamp = NSOLN_RETN_RESIDUALFORMATIONERROR; - goto done; - } - if (m_print_flag >= 4) { - m_normResid_full = residErrorNorm(DATA_PTR(m_resid), " Resulting full residual norm", 10, DATA_PTR(m_y_n_1)); - if (fabs(m_normResid_full - m_normResid_1) > 1.0E-3 * (m_normResid_1 + m_normResid_full + 1.0E-4)) { - if (m_print_flag >= 4) { - printf("\t solve_nonlinear_problem(): Full residual norm changed from %g to %g due to " - "lagging of components\n", m_normResid_1, m_normResid_full); - } - } - } else { - m_normResid_full = residErrorNorm(DATA_PTR(m_resid)); - } + /* + * Do a full residual calculation with the unlagged solution components. + * Then get the norm of the residual + */ + info = doResidualCalc(time_curr, NSOLN_TYPE_STEADY_STATE, DATA_PTR(m_y_n_1), DATA_PTR(m_ydot_n_1)); + if (info != 1) { + if (m_print_flag > 0) { + printf("\t solve_nonlinear_problem(): current trial step and damping led to Residual Calc " + "ERROR %d. Bailing\n", info); + } + retnDamp = NSOLN_RETN_RESIDUALFORMATIONERROR; + goto done; + } + if (m_print_flag >= 4) { + m_normResid_full = residErrorNorm(DATA_PTR(m_resid), " Resulting full residual norm", 10, DATA_PTR(m_y_n_1)); + if (fabs(m_normResid_full - m_normResid_1) > 1.0E-3 * ( m_normResid_1 + m_normResid_full + 1.0E-4)) { + if (m_print_flag >= 4) { + printf("\t solve_nonlinear_problem(): Full residual norm changed from %g to %g due to " + "lagging of components\n", m_normResid_1, m_normResid_full); + } + } + } else { + m_normResid_full = residErrorNorm(DATA_PTR(m_resid)); + } - /* - * Check the convergence criteria - */ - convRes = 0; - if (retnDamp > NSOLN_RETN_CONTINUE) { - convRes = convergenceCheck(retnDamp, stepNorm_1); - } + /* + * Check the convergence criteria + */ + convRes = 0; + if (retnDamp > NSOLN_RETN_CONTINUE) { + convRes = convergenceCheck(retnDamp, stepNorm_1); + } + + bool m_filterIntermediate = false; + if (m_filterIntermediate) { + if (retnDamp == NSOLN_RETN_CONTINUE) { + (void) filterNewSolution(time_n, DATA_PTR(m_y_n_1), DATA_PTR(m_ydot_n_1)); + } + } - bool m_filterIntermediate = false; - if (m_filterIntermediate) { - if (retnDamp == NSOLN_RETN_CONTINUE) { - (void) filterNewSolution(time_n, DATA_PTR(m_y_n_1), DATA_PTR(m_ydot_n_1)); - } - } + // Exchange new for curr solutions + if (retnDamp >= NSOLN_RETN_CONTINUE) { + mdp::mdp_copy_dbl_1(DATA_PTR(m_y_n_curr), CONSTD_DATA_PTR(m_y_n_1), neq_); - // Exchange new for curr solutions - if (retnDamp >= NSOLN_RETN_CONTINUE) { - mdp::mdp_copy_dbl_1(DATA_PTR(m_y_n_curr), CONSTD_DATA_PTR(m_y_n_1), (int) neq_); + if (solnType_ != NSOLN_TYPE_STEADY_STATE) { + calc_ydot(m_order, DATA_PTR(m_y_n_curr), DATA_PTR(m_ydot_n_curr)); + } + } - if (solnType_ != NSOLN_TYPE_STEADY_STATE) { - calc_ydot(m_order, DATA_PTR(m_y_n_curr), DATA_PTR(m_ydot_n_curr)); - } - } + if (m_print_flag == 2 || m_print_flag == 3) { + // printf("\t Iter Resid NewJac | Fbound | ResidBound | Fdamp DampIts | DeltaSolnNewton ResidFinal \n"); + if (ResidWtsReevaluated_) { + printf("\t*"); + } else { + printf("\t "); + } + printf(" %3d %11.3E", num_newt_its, m_normResid_0); + bool m_jacAge = false; + if (!m_jacAge) { + printf(" Y "); + } else { + printf(" N "); + } + if (doDogLeg_) { + printf("%5.1F |", log10(m_conditionNumber)); + // printf("\t Iter Resid NewJac | DS_Cauchy DS_Newton DS_Trust | legID legAlpha Fbound | | DS_F ResidFinal \n"); + printf("%10.3E %10.3E %10.3E %10.3E|", ResidDecreaseSDExp_, ResidDecreaseSD_, + ResidDecreaseNewtExp_, ResidDecreaseNewt_); + printf("%10.3E %10.3E %10.3E|", m_normDeltaSoln_CP , m_normDeltaSoln_Newton, norm_deltaX_trust_ * trustDelta_); + printf("%2d %10.2E %10.2E", dogLegID_ , dogLegAlpha_, m_dampBound); + printf("| %3.2f %3.2f |", CurrentTrustFactor_, NextTrustFactor_); + printf(" %2d ", i_numTrials); + printf("| %10.3E %10.3E %10.3E", stepNorm_1, m_normResid_1, m_normResid_full); + } else { + printf(" |"); + printf("%10.2E %10.3E |", m_dampBound, m_normResid_Bound); + printf("%2d %10.2E %10.3E %10.3E %10.3E", i_numTrials + 1, m_dampRes, + stepNorm_1 / ( m_dampRes * m_dampBound), stepNorm_2, m_normResid_1); + printf("| %10.3E %10.3E %10.3E", stepNorm_1, m_normDeltaSoln_Newton, m_normResid_full); + } + printf("\n"); + + } + if (m_print_flag >= 4) { + if (doDogLeg_) { + if (convRes > 0) { + printf("\t solve_nonlinear_problem(): Problem Converged, stepNorm = %11.3E, reduction of res from %11.3E to %11.3E\n", + stepNorm_1, m_normResid_0, m_normResid_full); + printf("\t"); + print_line("=", 119); + } else { + printf("\t solve_nonlinear_problem(): Successfull step taken with stepNorm = %11.3E, reduction of res from %11.3E to %11.3E\n", + stepNorm_1, m_normResid_0, m_normResid_full); + } + } else { + if (convRes > 0) { + printf("\t solve_nonlinear_problem(): Damped Newton iteration successful, nonlin " + "converged, final estimate of the next solution update norm = %-12.4E\n", stepNorm_2); + printf("\t"); + print_line("=", 119); + } else if (retnDamp >= NSOLN_RETN_CONTINUE) { + printf("\t solve_nonlinear_problem(): Damped Newton iteration successful, " + "estimate of the next solution update norm = %-12.4E\n", stepNorm_2); + } else { + printf("\t solve_nonlinear_problem(): Damped Newton unsuccessful, final estimate " + "of the next solution update norm = %-12.4E\n", stepNorm_2); + } + } + } - if (m_print_flag == 2 || m_print_flag == 3) { - // printf("\t Iter Resid NewJac | Fbound | ResidBound | Fdamp DampIts | DeltaSolnNewton ResidFinal \n"); - if (ResidWtsReevaluated_) { - printf("\t*"); - } else { - printf("\t "); - } - printf(" %3d %11.3E", num_newt_its, m_normResid_0); - bool m_jacAge = false; - if (!m_jacAge) { - printf(" Y "); - } else { - printf(" N "); - } - if (doDogLeg_) { - printf("%5.1f |", log10(m_conditionNumber)); - // printf("\t Iter Resid NewJac | DS_Cauchy DS_Newton DS_Trust | legID legAlpha Fbound | | DS_F ResidFinal \n"); - printf("%10.3E %10.3E %10.3E %10.3E|", ResidDecreaseSDExp_, ResidDecreaseSD_, - ResidDecreaseNewtExp_, ResidDecreaseNewt_); - printf("%10.3E %10.3E %10.3E|", m_normDeltaSoln_CP , m_normDeltaSoln_Newton, norm_deltaX_trust_ * trustDelta_); - printf("%2d %10.2E %10.2E", dogLegID_ , dogLegAlpha_, m_dampBound); - printf("| %3.2f %3.2f |", CurrentTrustFactor_, NextTrustFactor_); - printf(" %2d ", i_numTrials); - printf("| %10.3E %10.3E %10.3E", stepNorm_1, m_normResid_1, m_normResid_full); - } else { - printf(" |"); - printf("%10.2E %10.3E |", m_dampBound, m_normResid_Bound); - printf("%2d %10.2E %10.3E %10.3E %10.3E", i_numTrials + 1, m_dampRes, - stepNorm_1 / (m_dampRes * m_dampBound), stepNorm_2, m_normResid_1); - printf("| %10.3E %10.3E %10.3E", stepNorm_1, m_normDeltaSoln_Newton, m_normResid_full); - } - printf("\n"); + /* + * Do a full residual calculation with the unlagged solution components calling ShowSolution to perhaps print out the solution. + */ + if (m_print_flag >= 4) { + if (convRes > 0 || m_print_flag >= 6) { + info = doResidualCalc(time_curr, NSOLN_TYPE_STEADY_STATE, DATA_PTR(m_y_n_curr), DATA_PTR(m_ydot_n_curr), Base_ShowSolution); + if (info != 1) { + if (m_print_flag > 0) { + printf("\t solve_nonlinear_problem(): Final ShowSolution residual eval returned an error! " + "ERROR %d. Bailing\n", info); + } + retnDamp = NSOLN_RETN_RESIDUALFORMATIONERROR; + goto done; + } + } + } - } - if (m_print_flag >= 4) { - if (doDogLeg_) { - if (convRes > 0) { - printf("\t solve_nonlinear_problem(): Problem Converged, stepNorm = %11.3E, reduction of res from %11.3E to %11.3E\n", - stepNorm_1, m_normResid_0, m_normResid_full); - printf("\t"); - print_line("=", 119); - } else { - printf("\t solve_nonlinear_problem(): Successfull step taken with stepNorm = %11.3E, reduction of res from %11.3E to %11.3E\n", - stepNorm_1, m_normResid_0, m_normResid_full); - } - } else { - if (convRes > 0) { - printf("\t solve_nonlinear_problem(): Damped Newton iteration successful, nonlin " - "converged, final estimate of the next solution update norm = %-12.4E\n", stepNorm_2); - printf("\t"); - print_line("=", 119); - } else if (retnDamp >= NSOLN_RETN_CONTINUE) { - printf("\t solve_nonlinear_problem(): Damped Newton iteration successful, " - "estimate of the next solution update norm = %-12.4E\n", stepNorm_2); - } else { - printf("\t solve_nonlinear_problem(): Damped Newton unsuccessful, final estimate " - "of the next solution update norm = %-12.4E\n", stepNorm_2); - } - } - } - // convergence - if (convRes) { - goto done; - } + // convergence + if (convRes) { + 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 (retnDamp < NSOLN_RETN_CONTINUE) { - 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 (retnDamp < NSOLN_RETN_CONTINUE) { + goto done; + } } -done: + done: if (m_print_flag == 2 || m_print_flag == 3) { - if (convRes > 0) { - if (doDogLeg_) { - if (convRes == 3) { - printf("\t | | " - " | | converged = 3 |(%11.3E) \n", stepNorm_2); - } else { - printf("\t | | " - " | | converged = %1d | %10.3E %10.3E\n", convRes, - stepNorm_2, m_normResidTrial); - } - printf("\t-----------------------------------------------------------------------------------------------------" - "------------------------------------------------------------------------------\n"); - } else { - if (convRes == 3) { - printf("\t | " - " | converged = 3 | (%11.3E) \n", stepNorm_2); - } else { - printf("\t | " - " | converged = %1d | %10.3E %10.3E\n", convRes, - stepNorm_2, m_normResidTrial); - } - printf("\t------------------------------------------------------------------------------------" - "-----------------------------------------------\n"); - } - } - - - + if (convRes > 0) { + if (doDogLeg_) { + if (convRes == 3) { + printf("\t | | " + " | | converged = 3 |(%11.3E) \n", stepNorm_2); + } else { + printf("\t | | " + " | | converged = %1d | %10.3E %10.3E\n", convRes, + stepNorm_2, m_normResidTrial); + } + printf("\t-----------------------------------------------------------------------------------------------------" + "------------------------------------------------------------------------------\n"); + } else { + if (convRes == 3) { + printf("\t | " + " | converged = 3 | (%11.3E) \n", stepNorm_2); + } else { + printf("\t | " + " | converged = %1d | %10.3E %10.3E\n", convRes, + stepNorm_2, m_normResidTrial); + } + printf("\t------------------------------------------------------------------------------------" + "-----------------------------------------------\n"); + } + } + + + } - - mdp::mdp_copy_dbl_1(y_comm, CONSTD_DATA_PTR(m_y_n_curr), (int) neq_); + + mdp::mdp_copy_dbl_1(y_comm, CONSTD_DATA_PTR(m_y_n_curr), neq_); if (solnType_ != NSOLN_TYPE_STEADY_STATE) { - mdp::mdp_copy_dbl_1(ydot_comm, CONSTD_DATA_PTR(m_ydot_n_curr), (int) neq_); + mdp::mdp_copy_dbl_1(ydot_comm, CONSTD_DATA_PTR(m_ydot_n_curr), neq_); } - + num_linear_solves += m_numTotalLinearSolves; - + doublereal time_elapsed = wc.secondsWC(); - if (m_print_flag > 1) { - if (retnDamp > 0) { - if (NonlinearSolver::s_TurnOffTiming) { - printf("\tNonlinear problem solved successfully in %d its\n", - num_newt_its); - } else { - printf("\tNonlinear problem solved successfully in %d its, time elapsed = %g sec\n", - num_newt_its, time_elapsed); - } - } else { - printf("\tNonlinear problem failed to solve after %d its\n", num_newt_its); - } + if (m_print_flag > 1 ) { + if (retnDamp > 0) { + if (NonlinearSolver::s_TurnOffTiming) { + printf("\tNonlinear problem solved successfully in %d its\n", + num_newt_its); + } else { + printf("\tNonlinear problem solved successfully in %d its, time elapsed = %g sec\n", + num_newt_its, time_elapsed); + } + } else { + printf("\tNonlinear problem failed to solve after %d its\n", num_newt_its); + } } retnCode = retnDamp; if (retnDamp > 0) { - retnCode = NSOLN_RETN_SUCCESS; + retnCode = NSOLN_RETN_SUCCESS; } return retnCode; -} -//==================================================================================================================== -// Print solution norm contribution -/* - * Prints out the most important entries to the update to the solution vector for the current step - * - * @param step_1 Raw update vector for the current nonlinear step - * @param stepNorm_1 Norm of the vector step_1 - * @param step_2 Raw update vector for the next solution value based on the old matrix - * @param stepNorm_2 Norm of the vector step_2 - * @param title title of the printout - * @param y_n_curr Old value of the solution - * @param y_n_1 New value of the solution after damping corrections - * @param damp Value of the damping factor - * @param num_entries Number of entries to print out - */ -void NonlinearSolver:: -print_solnDelta_norm_contrib(const doublereal* const step_1, - const char* const stepNorm_1, - const doublereal* const step_2, - const char* const stepNorm_2, - const char* const title, - const doublereal* const y_n_curr, - const doublereal* const y_n_1, - doublereal damp, - size_t num_entries) -{ + } + //==================================================================================================================== + // Print solution norm contribution + /* + * Prints out the most important entries to the update to the solution vector for the current step + * + * @param step_1 Raw update vector for the current nonlinear step + * @param stepNorm_1 Norm of the vector step_1 + * @param step_2 Raw update vector for the next solution value based on the old matrix + * @param stepNorm_2 Norm of the vector step_2 + * @param title title of the printout + * @param y_n_curr Old value of the solution + * @param y_n_1 New value of the solution after damping corrections + * @param damp Value of the damping factor + * @param num_entries Number of entries to print out + */ + void NonlinearSolver:: + print_solnDelta_norm_contrib(const doublereal * const step_1, + const char * const stepNorm_1, + const doublereal * const step_2, + const char * const stepNorm_2, + const char * const title, + const doublereal * const y_n_curr, + const doublereal * const y_n_1, + doublereal damp, + int num_entries) { + int i, j, jnum; bool used; doublereal dmax0, dmax1, error, rel_norm; printf("\t\t%s currentDamp = %g\n", title, damp); printf("\t\t I ysolnOld %13s ysolnNewRaw | ysolnNewTrial " - "%10s ysolnNewTrialRaw | solnWeight wtDelSoln wtDelSolnTrial\n", stepNorm_1, stepNorm_2); - std::vector imax(num_entries, npos); - printf("\t\t "); - print_line("-", 125); - for (size_t jnum = 0; jnum < num_entries; jnum++) { - dmax1 = -1.0; - for (size_t i = 0; i < neq_; i++) { - used = false; - for (size_t j = 0; j < jnum; j++) { - if (imax[j] == i) { - used = true; - } - } - if (!used) { - error = step_1[i] / m_ewt[i]; - rel_norm = sqrt(error * error); - error = step_2[i] / m_ewt[i]; - rel_norm += sqrt(error * error); - if (rel_norm > dmax1) { - imax[jnum] = i; - dmax1 = rel_norm; - } - } - } - if (imax[jnum] != npos) { - size_t i = imax[jnum]; - error = step_1[i] / m_ewt[i]; - dmax0 = sqrt(error * error); - error = step_2[i] / m_ewt[i]; - dmax1 = sqrt(error * error); - printf("\t\t %4s %12.4e %12.4e %12.4e | %12.4e %12.4e %12.4e |%12.4e %12.4e %12.4e\n", - int2str(i).c_str(), y_n_curr[i], step_1[i], y_n_curr[i] + step_1[i], y_n_1[i], - step_2[i], y_n_1[i]+ step_2[i], m_ewt[i], dmax0, dmax1); - } + "%10s ysolnNewTrialRaw | solnWeight wtDelSoln wtDelSolnTrial\n", stepNorm_1, stepNorm_2); + int *imax = mdp::mdp_alloc_int_1(num_entries, -1); + printf("\t\t "); print_line("-", 125); + for (jnum = 0; jnum < num_entries; jnum++) { + dmax1 = -1.0; + for (i = 0; i < neq_; i++) { + used = false; + for (j = 0; j < jnum; j++) { + if (imax[j] == i) used = true; + } + if (!used) { + error = step_1[i] / m_ewt[i]; + rel_norm = sqrt(error * error); + error = step_2[i] / m_ewt[i]; + rel_norm += sqrt(error * error); + if (rel_norm > dmax1) { + imax[jnum] = i; + dmax1 = rel_norm; + } + } + } + if (imax[jnum] >= 0) { + i = imax[jnum]; + error = step_1[i] / m_ewt[i]; + dmax0 = sqrt(error * error); + error = step_2[i] / m_ewt[i]; + dmax1 = sqrt(error * error); + printf("\t\t %4d %12.4e %12.4e %12.4e | %12.4e %12.4e %12.4e |%12.4e %12.4e %12.4e\n", + i, y_n_curr[i], step_1[i], y_n_curr[i] + step_1[i], y_n_1[i], + step_2[i], y_n_1[i]+ step_2[i], m_ewt[i], dmax0, dmax1); + } } - printf("\t\t "); - print_line("-", 125); -} -//==================================================================================================================== -//! This routine subtracts two numbers for one another -/*! - * This routine subtracts 2 numbers. If the difference is less - * than 1.0E-14 times the magnitude of the smallest number, then diff returns an exact zero. - * It also returns an exact zero if the difference is less than - * 1.0E-300. - * - * returns: a - b - * - * This routine is used in numerical differencing schemes in order - * to avoid roundoff errors resulting in creating Jacobian terms. - * Note: This is a slow routine. However, jacobian errors may cause - * loss of convergence. Therefore, in practice this routine has proved cost-effective. - * - * @param a Value of a - * @param b value of b - * - * @return returns the difference between a and b - */ -static inline doublereal subtractRD(doublereal a, doublereal b) -{ + printf("\t\t "); print_line("-", 125); + mdp::mdp_safe_free((void **) &imax); + } + //==================================================================================================================== + //! This routine subtracts two numbers for one another + /*! + * This routine subtracts 2 numbers. If the difference is less + * than 1.0E-14 times the magnitude of the smallest number, then diff returns an exact zero. + * It also returns an exact zero if the difference is less than + * 1.0E-300. + * + * returns: a - b + * + * This routine is used in numerical differencing schemes in order + * to avoid roundoff errors resulting in creating Jacobian terms. + * Note: This is a slow routine. However, jacobian errors may cause + * loss of convergence. Therefore, in practice this routine has proved cost-effective. + * + * @param a Value of a + * @param b value of b + * + * @return returns the difference between a and b + */ + static inline doublereal subtractRD(doublereal a, doublereal b) { doublereal diff = a - b; - doublereal d = std::min(fabs(a), fabs(b)); + doublereal d = MIN(fabs(a), fabs(b)); d *= 1.0E-14; doublereal ad = fabs(diff); if (ad < 1.0E-300) { - diff = 0.0; + diff = 0.0; } if (ad < d) { - diff = 0.0; + diff = 0.0; } return diff; -} -//==================================================================================================================== -/* - * - * Function called by BEuler to evaluate the Jacobian matrix and the - * current residual at the current time step. - * @param N = The size of the equation system - * @param J = Jacobian matrix to be filled in - * @param f = Right hand side. This routine returns the current - * value of the rhs (output), so that it does - * not have to be computed again. - * - * @return Returns a flag to indicate that operation is successful. - * 1 Means a successful operation - * 0 Means an unsuccessful operation - */ -int NonlinearSolver::beuler_jac(GeneralMatrix& J, doublereal* const f, - doublereal time_curr, doublereal CJ, - doublereal* const y, doublereal* const ydot, - int num_newt_its) -{ + } + //==================================================================================================================== + /* + * + * Function called by BEuler to evaluate the Jacobian matrix and the + * current residual at the current time step. + * @param N = The size of the equation system + * @param J = Jacobian matrix to be filled in + * @param f = Right hand side. This routine returns the current + * value of the rhs (output), so that it does + * not have to be computed again. + * + * @return Returns a flag to indicate that operation is successful. + * 1 Means a successful operation + * 0 Means an unsuccessful operation + */ + int NonlinearSolver::beuler_jac(GeneralMatrix &J, doublereal * const f, + doublereal time_curr, doublereal CJ, + doublereal * const y, doublereal * const ydot, + int num_newt_its) + { + int i, j; double* col_j; int info; - doublereal ysave, ydotsave=0., dy; + doublereal ysave, ydotsave, dy; int retn = 1; - + /* * Clear the factor flag */ J.clearFactorFlag(); if (m_jacFormMethod == NSOLN_JAC_ANAL) { - /******************************************************************** - * Call the function to get a jacobian. - */ - info = m_func->evalJacobian(time_curr, delta_t_n, CJ, y, ydot, J, f); - m_nJacEval++; - m_nfe++; - if (info != 1) { - return info; - } + /******************************************************************** + * Call the function to get a jacobian. + */ + info = m_func->evalJacobian(time_curr, delta_t_n, CJ, y, ydot, J, f); + m_nJacEval++; + m_nfe++; + if (info != 1) { + return info; + } } else { - if (J.matrixType_ == 0) { - /******************************************************************* - * Generic algorithm to calculate a numerical Jacobian - */ - /* - * Calculate the current value of the rhs given the - * current conditions. - */ + if (J.matrixType_ == 0) { + /******************************************************************* + * Generic algorithm to calculate a numerical Jacobian + */ + /* + * Calculate the current value of the rhs given the + * current conditions. + */ - info = m_func->evalResidNJ(time_curr, delta_t_n, y, ydot, f, JacBase_ResidEval); - m_nfe++; - if (info != 1) { - return info; - } - m_nJacEval++; + info = m_func->evalResidNJ(time_curr, delta_t_n, y, ydot, f, JacBase_ResidEval); + m_nfe++; + if (info != 1) { + return info; + } + m_nJacEval++; +#ifdef DEBUG_MODE + for (int ii = 0; ii < neq_; ii++) { + mdp::checkFinite(f[ii]); + } +#endif - /* - * Malloc a vector and call the function object to return a set of - * deltaY's that are appropriate for calculating the numerical - * derivative. - */ - doublereal* dyVector = mdp::mdp_alloc_dbl_1((int) neq_, MDP_DBL_NOINIT); - retn = m_func->calcDeltaSolnVariables(time_curr, y, ydot, dyVector, DATA_PTR(m_ewt)); - if (s_print_NumJac) { - if (m_print_flag >= 7) { - if (retn != 1) { - printf("\t\tbeuler_jac ERROR: calcDeltaSolnVariables() returned an error condition.\n"); - printf("\t\t We will bail after calculating the Jacobian\n"); - } - if (neq_ < 20) { - printf("\t\tUnk m_ewt y dyVector ResN\n"); - for (size_t iii = 0; iii < neq_; iii++) { - printf("\t\t %4s %16.8e %16.8e %16.8e %16.8e \n", - int2str(iii).c_str(), m_ewt[iii], y[iii], dyVector[iii], f[iii]); - } - } - } - } + /* + * Malloc a vector and call the function object to return a set of + * deltaY's that are appropriate for calculating the numerical + * derivative. + */ + doublereal *dyVector = mdp::mdp_alloc_dbl_1(neq_, MDP_DBL_NOINIT); + retn = m_func->calcDeltaSolnVariables(time_curr, y, ydot, dyVector, DATA_PTR(m_ewt)); + if (s_print_NumJac) { + if (m_print_flag >= 7) { + if (retn != 1) { + printf("\t\t beuler_jac ERROR! calcDeltaSolnVariables() returned an error flag\n"); + printf("\t\t We will bail from the nonlinear solver after calculating the jacobian"); + } + if (neq_ < 20) { + printf("\t\tUnk m_ewt y dyVector ResN\n"); + for (int iii = 0; iii < neq_; iii++){ + printf("\t\t %4d %16.8e %16.8e %16.8e %16.8e \n", + iii, m_ewt[iii], y[iii], dyVector[iii], f[iii]); + } + } + } + } - /* - * Loop over the variables, formulating a numerical derivative - * of the dense matrix. - * For the delta in the variable, we will use a variety of approaches - * The original approach was to use the error tolerance amount. - * This may not be the best approach, as it could be overly large in - * some instances and overly small in others. - * We will first protect from being overly small, by using the usual - * sqrt of machine precision approach, i.e., 1.0E-7, - * to bound the lower limit of the delta. - */ - for (size_t j = 0; j < neq_; j++) { + /* + * Loop over the variables, formulating a numerical derivative + * of the dense matrix. + * For the delta in the variable, we will use a variety of approaches + * The original approach was to use the error tolerance amount. + * This may not be the best approach, as it could be overly large in + * some instances and overly small in others. + * We will first protect from being overly small, by using the usual + * sqrt of machine precision approach, i.e., 1.0E-7, + * to bound the lower limit of the delta. + */ + for (j = 0; j < neq_; j++) { - /* - * Get a pointer into the column of the matrix - */ + /* + * Get a pointer into the column of the matrix + */ - col_j = (doublereal*) J.ptrColumn(j); - ysave = y[j]; - dy = dyVector[j]; - //dy = fmaxx(1.0E-6 * m_ewt[j], fabs(ysave)*1.0E-7); + col_j = (doublereal *) J.ptrColumn(j); + ysave = y[j]; + dy = dyVector[j]; + //dy = fmaxx(1.0E-6 * m_ewt[j], fabs(ysave)*1.0E-7); - y[j] = ysave + dy; - dy = y[j] - ysave; - if (solnType_ != NSOLN_TYPE_STEADY_STATE) { - ydotsave = ydot[j]; - ydot[j] += dy * CJ; - } - /* - * Call the function - */ + y[j] = ysave + dy; + dy = y[j] - ysave; + if (solnType_ != NSOLN_TYPE_STEADY_STATE) { + ydotsave = ydot[j]; + ydot[j] += dy * CJ; + } + /* + * Call the function + */ - info = m_func->evalResidNJ(time_curr, delta_t_n, y, ydot, DATA_PTR(m_wksp), - JacDelta_ResidEval, - static_cast(j), dy); - m_nfe++; - if (info != 1) { - mdp::mdp_safe_free((void**) &dyVector); - return info; - } + info = m_func->evalResidNJ(time_curr, delta_t_n, y, ydot, DATA_PTR(m_wksp), + JacDelta_ResidEval, j, dy); + m_nfe++; + +#ifdef DEBUG_MODE + if (fabs(dy) < 1.0E-300) { + throw CanteraError("NonlinearSolver::beuler_jac", "dy is equal to zero"); + } + for (int ii = 0; ii < neq_; ii++) { + mdp::checkFinite(m_wksp[ii]); + } +#endif + + if (info != 1) { + mdp::mdp_safe_free((void **) &dyVector); + return info; + } - doublereal diff; - for (size_t i = 0; i < neq_; i++) { - diff = subtractRD(m_wksp[i], f[i]); - col_j[i] = diff / dy; - } - y[j] = ysave; - if (solnType_ != NSOLN_TYPE_STEADY_STATE) { - ydot[j] = ydotsave; - } + doublereal diff; + for (i = 0; i < neq_; i++) { + diff = subtractRD(m_wksp[i], f[i]); + col_j[i] = diff / dy; + } + y[j] = ysave; + if (solnType_ != NSOLN_TYPE_STEADY_STATE) { + ydot[j] = ydotsave; + } - } - /* - * Release memory - */ - mdp::mdp_safe_free((void**) &dyVector); - } else if (J.matrixType_ == 1) { - size_t ku, kl; - size_t ivec[2]; - size_t n = J.nRowsAndStruct(ivec); - kl = ivec[0]; - ku = ivec[1]; - if (n != neq_) { - printf("we have probs\n"); - exit(-1); - } + } + /* + * Release memory + */ + mdp::mdp_safe_free((void **) &dyVector); + } else if (J.matrixType_ == 1) { + int ku, kl; + size_t ivec[2]; + int n = J.nRowsAndStruct(ivec); + kl = ivec[0]; + ku = ivec[1]; + if (n != neq_) { + printf("we have probs\n"); exit(-1); + } - // --------------------------------- BANDED MATRIX BRAIN DEAD --------------------------------------------------- - info = m_func->evalResidNJ(time_curr, delta_t_n, y, ydot, f, JacBase_ResidEval); - m_nfe++; - if (info != 1) { - return info; - } - m_nJacEval++; + // --------------------------------- BANDED MATRIX BRAIN DEAD --------------------------------------------------- + info = m_func->evalResidNJ(time_curr, delta_t_n, y, ydot, f, JacBase_ResidEval); + m_nfe++; + if (info != 1) { + return info; + } + m_nJacEval++; - doublereal* dyVector = mdp::mdp_alloc_dbl_1((int) neq_, MDP_DBL_NOINIT); - retn = m_func->calcDeltaSolnVariables(time_curr, y, ydot, dyVector, DATA_PTR(m_ewt)); - if (s_print_NumJac) { - if (m_print_flag >= 7) { - if (retn != 1) { - printf("\t\tbeuler_jac ERROR: calcDeltaSolnVariables() returned an error condition.\n"); - printf("\t\t We will bail after calculating the Jacobian\n"); - } - if (neq_ < 20) { - printf("\t\tUnk m_ewt y dyVector ResN\n"); - for (size_t iii = 0; iii < neq_; iii++) { - printf("\t\t %4s %16.8e %16.8e %16.8e %16.8e \n", - int2str(iii).c_str(), m_ewt[iii], y[iii], dyVector[iii], f[iii]); - } - } - } - } + doublereal *dyVector = mdp::mdp_alloc_dbl_1(neq_, MDP_DBL_NOINIT); + retn = m_func->calcDeltaSolnVariables(time_curr, y, ydot, dyVector, DATA_PTR(m_ewt)); + if (s_print_NumJac) { + if (m_print_flag >= 7) { + if (retn != 1) { + printf("\t\t beuler_jac ERROR! calcDeltaSolnVariables() returned an error flag\n"); + printf("\t\t We will bail from the nonlinear solver after calculating the jacobian"); + } + if (neq_ < 20) { + printf("\t\tUnk m_ewt y dyVector ResN\n"); + for (int iii = 0; iii < neq_; iii++){ + printf("\t\t %4d %16.8e %16.8e %16.8e %16.8e \n", + iii, m_ewt[iii], y[iii], dyVector[iii], f[iii]); + } + } + } + } - for (size_t j = 0; j < neq_; j++) { + for (j = 0; j < neq_; j++) { - col_j = (doublereal*) J.ptrColumn(j); - ysave = y[j]; - dy = dyVector[j]; + col_j = (doublereal *) J.ptrColumn(j); + ysave = y[j]; + dy = dyVector[j]; + + + y[j] = ysave + dy; + dy = y[j] - ysave; + if (solnType_ != NSOLN_TYPE_STEADY_STATE) { + ydotsave = ydot[j]; + ydot[j] += dy * CJ; + } + + info = m_func->evalResidNJ(time_curr, delta_t_n, y, ydot, DATA_PTR(m_wksp), JacDelta_ResidEval, j, dy); + m_nfe++; +#ifdef DEBUG_MODE + if (fabs(dy) < 1.0E-300) { + throw CanteraError("NonlinearSolver::beuler_jac", "dy is equal to zero"); + } + for (int ii = 0; ii < neq_; ii++) { + mdp::checkFinite(m_wksp[ii]); + } +#endif + if (info != 1) { + mdp::mdp_safe_free((void **) &dyVector); + return info; + } + + doublereal diff; - y[j] = ysave + dy; - dy = y[j] - ysave; - if (solnType_ != NSOLN_TYPE_STEADY_STATE) { - ydotsave = ydot[j]; - ydot[j] += dy * CJ; - } - info = m_func->evalResidNJ(time_curr, delta_t_n, y, ydot, - DATA_PTR(m_wksp), JacDelta_ResidEval, - static_cast(j), dy); - m_nfe++; - if (info != 1) { - mdp::mdp_safe_free((void**) &dyVector); - return info; - } + for (int i = j - ku; i <= j + kl; i++) { + if (i >= 0 && i < neq_) { + diff = subtractRD(m_wksp[i], f[i]); + col_j[kl + ku + i - j] = diff / dy; + } + } + y[j] = ysave; + if (solnType_ != NSOLN_TYPE_STEADY_STATE) { + ydot[j] = ydotsave; + } - doublereal diff; + } - int ileft = (int) j - (int) ku; - int iright = static_cast(j + kl); - for (int i = ileft; i <= iright; i++) { - if (i >= 0 && i < (int) neq_) { - size_t ii = i; - size_t index = (int) kl + (int) ku + i - (int) j; - diff = subtractRD(m_wksp[ii], f[ii]); - col_j[index] = diff / dy; - } - } - /* - for (size_t i = j - ku; i <= j + kl; i++) { - if (i < neq_) { - diff = subtractRD(m_wksp[i], f[i]); - col_j[kl + ku + i - j] = diff / dy; - } - } - */ - y[j] = ysave; - if (solnType_ != NSOLN_TYPE_STEADY_STATE) { - ydot[j] = ydotsave; - } + mdp::mdp_safe_free((void **) &dyVector); + double vSmall; + int ismall = J.checkRows(vSmall); + if (vSmall < 1.0E-100) { + printf("WE have a zero row, %d\n", ismall); + exit(-1); + } + ismall = J.checkColumns(vSmall); + if (vSmall < 1.0E-100) { + printf("WE have a zero column, %d\n", ismall); + exit(-1); + } - } - - mdp::mdp_safe_free((void**) &dyVector); - double vSmall; - size_t ismall = J.checkRows(vSmall); - if (vSmall < 1.0E-100) { - printf("WE have a zero row, %s\n", int2str(ismall).c_str()); - exit(-1); - } - ismall = J.checkColumns(vSmall); - if (vSmall < 1.0E-100) { - printf("WE have a zero column, %s\n", int2str(ismall).c_str()); - exit(-1); - } - - // ---------------------BANDED MATRIX BRAIN DEAD ----------------------- - } + // ---------------------BANDED MATRIX BRAIN DEAD ----------------------- + } } if (m_print_flag >= 7 && s_print_NumJac) { - if (neq_ < 30) { - printf("\t\tCurrent Matrix and Residual:\n"); - printf("\t\t I,J | "); - for (size_t j = 0; j < neq_; j++) { - printf(" %5s ", int2str(j).c_str()); - } - printf("| Residual \n"); - printf("\t\t --"); - for (size_t j = 0; j < neq_; j++) { - printf("------------"); - } - printf("| -----------\n"); + if (neq_ < 30) { + printf("\t\tCurrent Matrix and Residual:\n"); + printf("\t\t I,J | "); + for (j = 0; j < neq_; j++) { + printf(" %5d ", j); + } + printf("| Residual \n"); + printf("\t\t --"); + for (j = 0; j < neq_; j++) { + printf("------------"); + } + printf("| -----------\n"); - for (size_t i = 0; i < neq_; i++) { - printf("\t\t %4s |", int2str(i).c_str()); - for (size_t j = 0; j < neq_; j++) { - printf(" % 11.4E", J(i,j)); - } - printf(" | % 11.4E\n", f[i]); - } + for (i = 0; i < neq_; i++) { + printf("\t\t %4d |", i); + for (j = 0; j < neq_; j++) { + printf(" % 11.4E", J(i,j) ); + } + printf(" | % 11.4E\n", f[i]); + } - printf("\t\t --"); - for (size_t j = 0; j < neq_; j++) { - printf("------------"); - } - printf("--------------\n"); - } + printf("\t\t --"); + for (j = 0; j < neq_; j++) { + printf("------------"); + } + printf("--------------\n"); + } } /* * Make a copy of the data. Note, this jacobian copy occurs before any matrix scaling operations. @@ -3954,248 +3998,265 @@ int NonlinearSolver::beuler_jac(GeneralMatrix& J, doublereal* const f, jacCopyPtr_->copyData(J); return retn; -} -//==================================================================================================================== -// Internal function to calculate the time derivative of the solution at the new step -/* - * Previously, the user must have supplied information about the previous time step for this routine to - * work as intended. - * - * @param order of the BDF method - * @param y_curr current value of the solution - * @param ydot_curr Calculated value of the solution derivative that is consistent with y_curr - */ -void NonlinearSolver:: -calc_ydot(const int order, const doublereal* const y_curr, doublereal* const ydot_curr) const -{ + } + //==================================================================================================================== + // Internal function to calculate the time derivative of the solution at the new step + /* + * Previously, the user must have supplied information about the previous time step for this routine to + * work as intended. + * + * @param order of the BDF method + * @param y_curr current value of the solution + * @param ydot_curr Calculated value of the solution derivative that is consistent with y_curr + */ + void NonlinearSolver:: + calc_ydot(const int order, const doublereal * const y_curr, doublereal * const ydot_curr) const + { if (!ydot_curr) { - return; + return; } + int i; doublereal c1; switch (order) { case 0: case 1: /* First order forward Euler/backward Euler */ - c1 = 1.0 / delta_t_n; - for (size_t i = 0; i < neq_; i++) { - ydot_curr[i] = c1 * (y_curr[i] - m_y_nm1[i]); - } - return; + c1 = 1.0 / delta_t_n; + for (i = 0; i < neq_; i++) { + ydot_curr[i] = c1 * (y_curr[i] - m_y_nm1[i]); + } + return; case 2: /* Second order Adams-Bashforth / Trapezoidal Rule */ - c1 = 2.0 / delta_t_n; - for (size_t i = 0; i < neq_; i++) { - ydot_curr[i] = c1 * (y_curr[i] - m_y_nm1[i]) - m_ydot_nm1[i]; - } - - return; + c1 = 2.0 / delta_t_n; + for (i = 0; i < neq_; i++) { + ydot_curr[i] = c1 * (y_curr[i] - m_y_nm1[i]) - m_ydot_nm1[i]; + } + + return; default: - throw CanteraError("calc_ydot()", "Case not covered"); + throw CanteraError("calc_ydot()", "Case not covered"); } -} -//==================================================================================================================== -// Apply a filtering process to the new step -/* - * @param timeCurrent Current value of the time - * @param y_current current value of the solution - * @param ydot_current Current value of the solution derivative. - * - * @return Returns the norm of the value of the amount filtered - */ -doublereal NonlinearSolver::filterNewStep(const doublereal timeCurrent, - const doublereal* const ybase, doublereal* const step0) -{ + } + //==================================================================================================================== + // Apply a filtering process to the new step + /* + * @param timeCurrent Current value of the time + * @param y_current current value of the solution + * @param ydot_current Current value of the solution derivative. + * + * @return Returns the norm of the value of the amount filtered + */ + doublereal NonlinearSolver::filterNewStep(const doublereal timeCurrent, + const doublereal * const ybase, doublereal * const step0) { doublereal tmp = m_func->filterNewStep(timeCurrent, ybase, step0); return tmp; -} -//==================================================================================================================== -// Apply a filtering process to the new solution -/* - * @param timeCurrent Current value of the time - * @param y_current current value of the solution - * @param ydot_current Current value of the solution derivative. - * - * @return Returns the norm of the value of the amount filtered - */ -doublereal NonlinearSolver::filterNewSolution(const doublereal timeCurrent, - doublereal* const y_current, doublereal* const ydot_current) -{ + } + //==================================================================================================================== + // Apply a filtering process to the new solution + /* + * @param timeCurrent Current value of the time + * @param y_current current value of the solution + * @param ydot_current Current value of the solution derivative. + * + * @return Returns the norm of the value of the amount filtered + */ + doublereal NonlinearSolver::filterNewSolution(const doublereal timeCurrent, + doublereal * const y_current, doublereal *const ydot_current) { doublereal tmp = m_func->filterSolnPrediction(timeCurrent, y_current); return tmp; -} -//==================================================================================================================== -// Compute the Residual Weights -/* - * The residual weights are defined here to be equal to the inverse of the row scaling factors used to - * row scale the matrix, after column scaling is used. They are multiplied by rtol and an atol factor - * is added as well so that if the residual is less than 1, then the calculation is deemed to be converged. - * - * The basic idea is that a change in the solution vector on the order of the convergence tolerance - * multiplied by [RJC] which is of order one after row scaling should give you the relative weight - * of the row. Values of the residual for that row can then be normalized by the value of this weight. - * When the tolerance in delta x is achieved, the tolerance in the residual should also be achieved - * and should be checked. - */ -void -NonlinearSolver::computeResidWts() -{ + } + //==================================================================================================================== + // Compute the Residual Weights + /* + * The residual weights are defined here to be equal to the inverse of the row scaling factors used to + * row scale the matrix, after column scaling is used. They are multiplied by rtol and an atol factor + * is added as well so that if the residual is less than 1, then the calculation is deemed to be converged. + * + * The basic idea is that a change in the solution vector on the order of the convergence tolerance + * multiplied by [RJC] which is of order one after row scaling should give you the relative weight + * of the row. Values of the residual for that row can then be normalized by the value of this weight. + * When the tolerance in delta x is achieved, the tolerance in the residual should also be achieved + * and should be checked. + */ + void + NonlinearSolver::computeResidWts() + { ResidWtsReevaluated_ = true; if (checkUserResidualTols_ == 1) { - for (size_t i = 0; i < neq_; i++) { - m_residWts[i] = userResidAtol_[i] + userResidRtol_ * m_rowWtScales[i] / neq_; - } + for (int i = 0; i < neq_; i++) { + m_residWts[i] = userResidAtol_[i] + userResidRtol_ * m_rowWtScales[i] / rtol_; +#ifdef DEBUG_MODE + mdp::checkFinite(m_residWts[i]); +#endif + } } else { - doublereal sum = 0.0; - for (size_t i = 0; i < neq_; i++) { - m_residWts[i] = m_rowWtScales[i] / neq_; - sum += m_residWts[i]; - } - sum /= neq_; - for (size_t i = 0; i < neq_; i++) { - m_residWts[i] = m_ScaleSolnNormToResNorm * (m_residWts[i] + atolBase_ * atolBase_ * sum); - } - if (checkUserResidualTols_ == 2) { - for (size_t i = 0; i < neq_; i++) { - double uR = userResidAtol_[i] + userResidRtol_ * m_rowWtScales[i] / neq_; - m_residWts[i] = std::min(m_residWts[i], uR); - } - } + doublereal sum = 0.0; + for (int i = 0; i < neq_; i++) { + m_residWts[i] = m_rowWtScales[i]; +#ifdef DEBUG_MODE + mdp::checkFinite(m_residWts[i]); +#endif + sum += m_residWts[i]; + } + sum /= neq_; + for (int i = 0; i < neq_; i++) { + m_residWts[i] = m_ScaleSolnNormToResNorm * (m_residWts[i] + atolBase_ * atolBase_ * sum); + } + if (checkUserResidualTols_ == 2) { + for (int i = 0; i < neq_; i++) { + double uR = userResidAtol_[i] + userResidRtol_ * m_rowWtScales[i] / rtol_; + m_residWts[i] = MIN(m_residWts[i], uR); + } + } } -} -//===================================================================================================================== -// return the residual weights -/* - * @param residWts Vector of length neq_ - */ -void -NonlinearSolver::getResidWts(doublereal* const residWts) const -{ - for (size_t i = 0; i < neq_; i++) { - residWts[i] = (m_residWts)[i]; + } + //===================================================================================================================== + // return the residual weights + /* + * @param residWts Vector of length neq_ + */ + void + NonlinearSolver::getResidWts(doublereal * const residWts) const + { + for (int i = 0; i < neq_; i++) { + residWts[i] = (m_residWts)[i]; } -} -//===================================================================================================================== -// Check to see if the nonlinear problem has converged -/* - * - * @return integer is returned. If positive, then the problem has converged - * 1 Successful step was taken: Next step's norm is less than 1.0. - * The final residual norm is less than 1.0. - * 2 Successful step: Next step's norm is less than 0.8. - * This step's norm is less than 1.0. - * The residual norm can be anything. - * 3 Success: The final residual is less than 1.0E-2 - * The predicted deltaSoln is below 1.0E-2. - * 0 Not converged yet - */ -int -NonlinearSolver::convergenceCheck(int dampCode, doublereal s1) -{ + } + //===================================================================================================================== + // Check to see if the nonlinear problem has converged + /* + * + * @return integer is returned. If positive, then the problem has converged + * 1 Successful step was taken: Next step's norm is less than 1.0. + * The final residual norm is less than 1.0. + * 2 Successful step: Next step's norm is less than 0.8. + * This step's norm is less than 1.0. + * The residual norm can be anything. + * 3 Success: The final residual is less than 1.0E-2 + * The predicted deltaSoln is below 1.0E-2. + * 0 Not converged yet + */ + int + NonlinearSolver::convergenceCheck(int dampCode, doublereal s1) + { int retn = 0; if (m_dampBound < 0.9999) { - return retn; + return retn; } if (m_dampRes < 0.9999) { - return retn; + return retn; } if (dampCode <= 0) { - return retn; + return retn; } if (dampCode == 3) { - if (s1 < 1.0E-2) { - if (m_normResidTrial < 1.0E-6) { - return 3; - } - } - if (s1 < 0.8) { - if (m_normDeltaSoln_Newton < 1.0) { - return 2; - } - } + if (s1 < 1.0E-2) { + if (m_normResid_full < 1.0E-1) { + return 3; + } + } + if (s1 < 0.8) { + if (m_normDeltaSoln_Newton < 1.0) { + if (m_normResid_full < 1.0E-1) { + return 2; + } + } + } } if (dampCode == 4) { - if (s1 < 1.0E-2) { - if (m_normResidTrial < 1.0E-6) { - return 3; - } - } + if (s1 < 1.0E-2) { + if (m_normResid_full < 1.0E-1) { + return 3; + } + } } if (s1 < 0.8) { - if (m_normDeltaSoln_Newton < 1.0) { - return 2; - } + if (m_normDeltaSoln_Newton < 1.0) { + if (m_normResid_full < 1.0E-1) { + return 2; + } + } } if (dampCode == 1 || dampCode == 2) { - if (s1 < 1.0) { - if (m_normResidTrial < 1.0) { - return 1; - } - } + if (s1 < 1.0) { + if (m_normResid_full < 1.0E-1) { + return 1; + } + } } return retn; -} -//===================================================================================================================== -// Set the absolute tolerances for the solution variables -/* - * Set the absolute tolerances used in the calculation - * - * @param atol Vector of length neq_ that contains the tolerances to be used for the solution variables - */ -void NonlinearSolver::setAtol(const doublereal* const atol) -{ - for (size_t i = 0; i < neq_; i++) { - atolk_[i]= atol[i]; + } + //===================================================================================================================== + // Set the absolute tolerances for the solution variables + /* + * Set the absolute tolerances used in the calculation + * + * @param atol Vector of length neq_ that contains the tolerances to be used for the solution variables + */ + void NonlinearSolver::setAtol(const doublereal * const atol) + { + for (int i = 0; i < neq_; i++) { + if (atol[i] <= 0.0) { + throw CanteraError("NonlinearSolver::setAtol()", + "Atol is less than or equal to zero"); + } + atolk_[i]= atol[i]; + } + } + //===================================================================================================================== + // Set the relative tolerances for the solution variables + /* + * Set the relative tolerances used in the calculation for the solution variables. + * + * @param rtol single double + */ + void NonlinearSolver::setRtol(const doublereal rtol) + { + if (rtol <= 0.0) { + throw CanteraError( "NonlinearSolver::setRtol()", + "Rtol is <= zero"); } -} -//===================================================================================================================== -// Set the relative tolerances for the solution variables -/* - * Set the relative tolerances used in the calculation for the solution variables. - * - * @param rtol single double - */ -void NonlinearSolver::setRtol(const doublereal rtol) -{ rtol_ = rtol; -} -//===================================================================================================================== -// Set the relative and absolute tolerances for the Residual norm comparisons, if used -/* - * - * residWeightNorm[i] = residAtol[i] + residRtol * m_rowWtScales[i] / neq - * - * @param residNormHandling Parameter that sets the default handling of the residual norms - * 0 The residual weighting vector is calculated to make sure that the solution - * norms are roughly 1 when the residual norm is roughly 1. - * This is the default if this routine is not called. - * 1 Use the user residual norm specified by the parameters in this routine - * 2 Use the minimum value of the residual weights calculcated by method 1 and 2. - * This is the default if this routine is called and this parameter isn't specified. - */ -void NonlinearSolver::setResidualTols(double residRtol, double* residATol, int residNormHandling) -{ + } + //===================================================================================================================== + // Set the relative and absolute tolerances for the Residual norm comparisons, if used + /* + * + * residWeightNorm[i] = residAtol[i] + residRtol * m_rowWtScales[i] / neq + * + * @param residNormHandling Parameter that sets the default handling of the residual norms + * 0 The residual weighting vector is calculated to make sure that the solution + * norms are roughly 1 when the residual norm is roughly 1. + * This is the default if this routine is not called. + * 1 Use the user residual norm specified by the parameters in this routine + * 2 Use the minimum value of the residual weights calculcated by method 0 and 1. + * This is the default if this routine is called and this parameter isn't specified. + */ + void NonlinearSolver::setResidualTols(double residRtol, double * residATol, int residNormHandling) + { if (residNormHandling < 0 || residNormHandling > 2) { - throw CanteraError("NonlinearSolver::setResidualTols()", - "Unknown int for residNormHandling"); + throw CanteraError("NonlinearSolver::setResidualTols()", + "Unknown int for residNormHandling"); } checkUserResidualTols_ = residNormHandling; userResidRtol_ = residRtol; if (residATol) { - userResidAtol_.resize(neq_); - for (size_t i = 0; i < neq_; i++) { - userResidAtol_[i] = residATol[i]; - } + userResidAtol_.resize(neq_); + for (int i = 0; i < neq_; i++) { + userResidAtol_[i] = residATol[i]; + } } else { - if (residNormHandling ==1 || residNormHandling == 2) { - throw CanteraError("NonlinearSolver::setResidualTols()", - "Must set residATol vector"); - } + if (residNormHandling ==1 || residNormHandling == 2) { + throw CanteraError("NonlinearSolver::setResidualTols()", + "Must set residATol vector"); + } } -} -//===================================================================================================================== -void NonlinearSolver::setPrintLvl(int printLvl) -{ + } + //===================================================================================================================== + void NonlinearSolver::setPrintLvl(int printLvl) + { m_print_flag = printLvl; -} -//===================================================================================================================== + } + //===================================================================================================================== } diff --git a/src/numerics/ODE_integrators.cpp b/src/numerics/ODE_integrators.cpp index 169080327..f533dba9c 100644 --- a/src/numerics/ODE_integrators.cpp +++ b/src/numerics/ODE_integrators.cpp @@ -3,7 +3,7 @@ #ifdef HAS_SUNDIALS -#include "CVodesIntegrator.h" +#include "cantera/numerics/CVodesIntegrator.h" #else #include "CVodeInt.h" #endif diff --git a/src/thermo/HMWSoln.cpp b/src/thermo/HMWSoln.cpp index 9bc4d8e31..cda293c3b 100644 --- a/src/thermo/HMWSoln.cpp +++ b/src/thermo/HMWSoln.cpp @@ -328,14 +328,28 @@ operator=(const HMWSoln& b) m_Lambda_nj_LL = b.m_Lambda_nj_LL; m_Lambda_nj_P = b.m_Lambda_nj_P; m_Lambda_nj_coeff = b.m_Lambda_nj_coeff; + + m_Mu_nnn = b.m_Mu_nnn; + m_Mu_nnn_L = b.m_Mu_nnn_L; + m_Mu_nnn_LL = b.m_Mu_nnn_LL; + m_Mu_nnn_P = b.m_Mu_nnn_P; + m_Mu_nnn_coeff = b.m_Mu_nnn_coeff; + m_lnActCoeffMolal_Scaled = b.m_lnActCoeffMolal_Scaled; m_lnActCoeffMolal_Unscaled = b.m_lnActCoeffMolal_Unscaled; + + m_dlnActCoeffMolaldT_Scaled = b.m_dlnActCoeffMolaldT_Scaled; m_dlnActCoeffMolaldT_Unscaled = b.m_dlnActCoeffMolaldT_Unscaled; + + m_d2lnActCoeffMolaldT2_Scaled = b.m_d2lnActCoeffMolaldT2_Scaled; m_d2lnActCoeffMolaldT2_Unscaled= b.m_d2lnActCoeffMolaldT2_Unscaled; + + m_dlnActCoeffMolaldP_Scaled = b.m_dlnActCoeffMolaldP_Scaled; m_dlnActCoeffMolaldP_Unscaled = b.m_dlnActCoeffMolaldP_Unscaled; - m_dlnActCoeffMolaldT_Scaled = b.m_dlnActCoeffMolaldT_Unscaled; - m_d2lnActCoeffMolaldT2_Scaled = b.m_d2lnActCoeffMolaldT2_Unscaled; - m_dlnActCoeffMolaldP_Scaled = b.m_dlnActCoeffMolaldP_Unscaled; + + m_molalitiesCropped = b.m_molalitiesCropped; + m_molalitiesAreCropped = b.m_molalitiesAreCropped; + m_CounterIJ = b.m_CounterIJ; m_gfunc_IJ = b.m_gfunc_IJ; m_g2func_IJ = b.m_g2func_IJ; @@ -397,9 +411,7 @@ operator=(const HMWSoln& b) CROP_ln_gamma_k_min = b.CROP_ln_gamma_k_min; CROP_ln_gamma_k_max = b.CROP_ln_gamma_k_max; CROP_speciesCropped_ = b.CROP_speciesCropped_; - m_CounterIJ = b.m_CounterIJ; - m_molalitiesCropped = b.m_molalitiesCropped; - m_molalitiesAreCropped= b.m_molalitiesAreCropped; + m_debugCalc = b.m_debugCalc; } return *this; @@ -2645,9 +2657,9 @@ s_updatePitzer_lnMolalityActCoeff() const if (counterIJ == 2) { printf("%s %s\n", speciesName(i).c_str(), speciesName(j).c_str()); - printf("beta0MX[%d] = %g\n", counterIJ, beta0MX[counterIJ]); - printf("beta1MX[%d] = %g\n", counterIJ, beta1MX[counterIJ]); - printf("beta2MX[%d] = %g\n", counterIJ, beta2MX[counterIJ]); + printf("beta0MX[%d] = %g\n", (int) counterIJ, beta0MX[counterIJ]); + printf("beta1MX[%d] = %g\n", (int) counterIJ, beta1MX[counterIJ]); + printf("beta2MX[%d] = %g\n", (int) counterIJ, beta2MX[counterIJ]); } } #endif @@ -2662,7 +2674,7 @@ s_updatePitzer_lnMolalityActCoeff() const #ifdef DEBUG_MODE if (m_debugCalc) { printf("%d %g: %g %g %g %g\n", - counterIJ, BMX[counterIJ], beta0MX[counterIJ], + (int) counterIJ, BMX[counterIJ], beta0MX[counterIJ], beta1MX[counterIJ], beta2MX[counterIJ], gfunc[counterIJ]); } #endif @@ -2722,7 +2734,7 @@ s_updatePitzer_lnMolalityActCoeff() const if (counterIJ == 2) { printf("%s %s\n", speciesName(i).c_str(), speciesName(j).c_str()); - printf("CphiMX[%d] = %g\n", counterIJ, CphiMX[counterIJ]); + printf("CphiMX[%d] = %g\n", (int) counterIJ, CphiMX[counterIJ]); } } #endif @@ -4597,7 +4609,7 @@ void HMWSoln::s_updatePitzer_d2lnMolalityActCoeff_dT2() const #ifdef DEBUG_MODE if (m_debugCalc) { printf("%d %g: %g %g %g %g\n", - counterIJ, BMX_LL[counterIJ], beta0MX_LL[counterIJ], + (int) counterIJ, BMX_LL[counterIJ], beta0MX_LL[counterIJ], beta1MX_LL[counterIJ], beta2MX_LL[counterIJ], gfunc[counterIJ]); } #endif @@ -5479,7 +5491,7 @@ void HMWSoln::s_updatePitzer_dlnMolalityActCoeff_dP() const #ifdef DEBUG_MODE if (m_debugCalc) { printf("%d %g: %g %g %g %g\n", - counterIJ, BMX_P[counterIJ], beta0MX_P[counterIJ], + (int) counterIJ, BMX_P[counterIJ], beta0MX_P[counterIJ], beta1MX_P[counterIJ], beta2MX_P[counterIJ], gfunc[counterIJ]); } #endif diff --git a/src/thermo/IdealSolidSolnPhase.cpp b/src/thermo/IdealSolidSolnPhase.cpp index 655434aa1..e5f95a3f8 100644 --- a/src/thermo/IdealSolidSolnPhase.cpp +++ b/src/thermo/IdealSolidSolnPhase.cpp @@ -80,8 +80,8 @@ IdealSolidSolnPhase& IdealSolidSolnPhase:: operator=(const IdealSolidSolnPhase& b) { if (this != &b) { - //ThermoPhase::operator=(b); - // m_spthermo = dupMyselfAsSpeciesThermo(b.m_spthermo); + ThermoPhase::operator=(b); + m_formGC = b.m_formGC; m_Pref = b.m_Pref; m_Pcurrent = b.m_Pcurrent; diff --git a/src/thermo/IonsFromNeutralVPSSTP.cpp b/src/thermo/IonsFromNeutralVPSSTP.cpp index d424699c3..a608f98d4 100644 --- a/src/thermo/IonsFromNeutralVPSSTP.cpp +++ b/src/thermo/IonsFromNeutralVPSSTP.cpp @@ -101,7 +101,7 @@ IonsFromNeutralVPSSTP::IonsFromNeutralVPSSTP(const std::string& inputFile, if (neutralPhase) { IOwnNThermoPhase_ = false; } - initThermoFile(inputFile, id); + constructPhaseFile(inputFile, id); geThermo = dynamic_cast(neutralMoleculePhase_); } //==================================================================================================================== @@ -125,7 +125,7 @@ IonsFromNeutralVPSSTP::IonsFromNeutralVPSSTP(XML_Node& phaseRoot, if (neutralPhase) { IOwnNThermoPhase_ = false; } - importPhase(*findXMLPhase(&phaseRoot, id), this); + constructPhaseXML(phaseRoot, id); geThermo = dynamic_cast(neutralMoleculePhase_); } @@ -846,7 +846,7 @@ void IonsFromNeutralVPSSTP::calcNeutralMoleculeMoleFractions() const } #ifdef DEBUG_MODE sum = -1.0; - for (int k = 0; k < m_kk; k++) { + for (size_t k = 0; k < m_kk; k++) { sum += moleFractions_[k]; } if (fabs(sum) > 1.0E-11) { diff --git a/src/thermo/ThermoFactory.cpp b/src/thermo/ThermoFactory.cpp index 700479b6a..c84526fd3 100644 --- a/src/thermo/ThermoFactory.cpp +++ b/src/thermo/ThermoFactory.cpp @@ -65,14 +65,14 @@ ThermoFactory* ThermoFactory::s_factory = 0; mutex_t ThermoFactory::thermo_mutex; //! Define the number of %ThermoPhase types for use in this factory routine -static int ntypes = 23; +static int ntypes = 24; //! Define the string name of the %ThermoPhase types that are handled by this factory routine static string _types[] = {"IdealGas", "Incompressible", "Surface", "Edge", "Metal", "StoichSubstance", "PureFluid", "LatticeSolid", "Lattice", "HMW", "IdealSolidSolution", "DebyeHuckel", - "IdealMolalSolution", "IdealGasVPSS", + "IdealMolalSolution", "IdealGasVPSS", "IdealSolnVPSS", "MineralEQ3", "MetalSHEelectrons", "Margules", "PhaseCombo_Interaction", "IonsFromNeutralMolecule", "FixedChemPot", "MolarityIonicVPSSTP", "MixedSolventElectrolyte", "Redlich-Kister" @@ -83,7 +83,7 @@ static int _itypes[] = {cIdealGas, cIncompressible, cSurf, cEdge, cMetal, cStoichSubstance, cPureFluid, cLatticeSolid, cLattice, cHMW, cIdealSolidSolnPhase, cDebyeHuckel, - cIdealMolalSoln, cVPSS_IdealGas, + cIdealMolalSoln, cVPSS_IdealGas, cIdealSolnGasVPSS_iscv, cMineralEQ3, cMetalSHEelectrons, cMargulesVPSSTP, cPhaseCombo_Interaction, cIonsFromNeutral, cFixedChemPot, cMolarityIonicVPSSTP, cMixedSolventElectrolyte, cRedlichKisterVPSSTP @@ -202,6 +202,10 @@ ThermoPhase* ThermoFactory::newThermoPhase(const std::string& model) th = new IdealSolnGasVPSS; break; + case cIdealSolnGasVPSS_iscv: + th = new IdealSolnGasVPSS; + break; + default: throw UnknownThermoPhaseModel("ThermoFactory::newThermoPhase", model); diff --git a/src/thermo/ThermoPhase.cpp b/src/thermo/ThermoPhase.cpp index f8302cadd..4760b2d31 100644 --- a/src/thermo/ThermoPhase.cpp +++ b/src/thermo/ThermoPhase.cpp @@ -384,6 +384,10 @@ void ThermoPhase::setState_HPorUV(doublereal Htarget, doublereal p, // spinodal value of H. for (int its = 0; its < 10; its++) { Tnew = Told + dt; + if (Tnew < Told / 3.0) { + Tnew = Told / 3.0; + dt = -2.0 * Told / 3.0; + } setState_conditional_TP(Tnew, p, !doUV); if (doUV) { Hnew = intEnergy_mass(); diff --git a/src/transport/DustyGasTransport.cpp b/src/transport/DustyGasTransport.cpp index 5e204ccf3..1262f86d7 100644 --- a/src/transport/DustyGasTransport.cpp +++ b/src/transport/DustyGasTransport.cpp @@ -112,37 +112,56 @@ DustyGasTransport& DustyGasTransport::operator=(const DustyGasTransport& right) DustyGasTransport::~DustyGasTransport() { delete m_gastran; -} -//==================================================================================================================== -// Duplication routine for objects which inherit from %Transport -/* - * This virtual routine can be used to duplicate %Transport objects - * inherited from %Transport even if the application only has - * a pointer to %Transport to work with. - * - * These routines are basically wrappers around the derived copy - * constructor. - */ -Transport* DustyGasTransport::duplMyselfAsTransport() const -{ - return new DustyGasTransport(*this); -} -//==================================================================================================================== -// Set the Parameters in the model -/* - * @param type Type of the parameter to set - * 0 - porosity - * 1 - tortuosity - * 2 - mean pore radius - * 3 - mean particle radius - * 4 - permeability - * @param k Unused int - * @param p pointer to double for the input list of parameters - * - */ -void DustyGasTransport::setParameters(const int type, const int k, const doublereal* const p) -{ - switch (type) { + } + //==================================================================================================================== + // Duplication routine for objects which inherit from %Transport + /* + * This virtual routine can be used to duplicate %Transport objects + * inherited from %Transport even if the application only has + * a pointer to %Transport to work with. + * + * These routines are basically wrappers around the derived copy + * constructor. + */ + Transport *DustyGasTransport::duplMyselfAsTransport() const { + DustyGasTransport* tr = new DustyGasTransport(*this); + return (dynamic_cast(tr)); + } + //==================================================================================================================== + // Specifies the %ThermPhase object. + /* + * We have relaxed this operation so that it will succeed when + * the underlying old and new ThermoPhase objects have the same + * number of species and the same names of the species in the + * same order. The idea here is to allow copy constructors and duplicators + * to work. In order for them to work, we need a method to switch the + * internal pointer within the Transport object after the duplication + * takes place. Also, different thermodynamic instanteations of the same + * species should also work. + * + * @param thermo Reference to the ThermoPhase object that + * the transport object will use + */ + void DustyGasTransport::setThermo(thermo_t& thermo) { + + Transport::setThermo(thermo); + m_gastran->setThermo(thermo); + } + //==================================================================================================================== + // Set the Parameters in the model + /* + * @param type Type of the parameter to set + * 0 - porosity + * 1 - tortuosity + * 2 - mean pore radius + * 3 - mean particle radius + * 4 - permeability + * @param k Unused int + * @param p pointer to double for the input list of parameters + * + */ + void DustyGasTransport::setParameters(const int type, const int k, const doublereal* const p) { + switch(type) { case 0: setPorosity(p[0]); break; diff --git a/src/transport/LTPspecies.cpp b/src/transport/LTPspecies.cpp index 788373d53..3afb72f03 100644 --- a/src/transport/LTPspecies.cpp +++ b/src/transport/LTPspecies.cpp @@ -47,39 +47,41 @@ static void getArrhenius(const XML_Node& node, b = getFloat(node, "b"); E = getFloat(node, "E", "actEnergy"); E /= GasConstant; -} -//==================================================================================================================== -// Construct an LTPspecies object for a liquid transport property. -/* - * The species transport property is constructed from the XML node, - * \verbatim , \endverbatim that is a child of the - * \verbatim \endverbatim node in the species block and specifies a type of transport - * property (like viscosity) - * - * @param propNode Pointer to the XML node that contains the property information - * @param name String containing the species name - * @param tp_ind enum TransportPropertyType containing the property id that this object - * is creating a parameterization for (e.g., viscosity) - * @param thermo const pointer to the ThermoPhase object, which is used to find the temperature. - */ -LTPspecies::LTPspecies(const XML_Node* const propNode, const std::string& name, - TransportPropertyType tp_ind, const thermo_t* thermo) : - m_speciesName(name), - m_model(LTP_TD_NOTSET), - m_property(tp_ind), - m_thermo(thermo), - m_mixWeight(1.0) -{ - if (propNode) { - if (propNode->hasChild("mixtureWeighting")) { - m_mixWeight = getFloat(*propNode, "mixtureWeighting"); - } - } -} -//==================================================================================================================== -// Copy constructor -LTPspecies::LTPspecies(const LTPspecies& right) -{ + + } + //==================================================================================================================== + // Construct an LTPspecies object for a liquid tranport property. + /* + * The species transport property is constructed from the XML node, + * \verbatim , \endverbatim that is a child of the + * \verbatim \endverbatim node in the species block and specifies a type of transport + * property (like viscosity) + * + * @param propNode Pointer to the XML node that contains the property information + * @param name String containing the species name + * @param tp_ind enum TransportPropertyType containing the property id that this object + * is creating a parameterization for (e.g., viscosity) + * @param thermo const pointer to the ThermoPhase object, which is used to find the temperature. + */ + LTPspecies::LTPspecies(const XML_Node * const propNode, const std::string name, + TransportPropertyType tp_ind, const thermo_t * thermo) : + m_speciesName(name), + m_model(LTP_TD_NOTSET), + m_property(tp_ind), + m_thermo(thermo), + m_mixWeight(1.0) + { + if (propNode) { + if (propNode->hasChild("mixtureWeighting") ) { + m_mixWeight = getFloat(*propNode, "mixtureWeighting"); + } + } + } + //==================================================================================================================== + // Copy constructor + LTPspecies::LTPspecies(const LTPspecies &right) + { + *this = right; } //==================================================================================================================== @@ -126,35 +128,36 @@ doublereal LTPspecies::getSpeciesTransProp() bool LTPspecies::checkPositive() const { return (m_coeffs[0] > 0); -} -//==================================================================================================================== -doublereal LTPspecies::getMixWeight() const -{ - return m_mixWeight; -} -//==================================================================================================================== -// Internal model to adjust species-specific properties for composition. -/* - * Currently just a place holder, but this method could take - * the composition from the thermo object and adjust coefficients - * accoding to some unspecified model. - */ -void LTPspecies::adjustCoeffsForComposition() -{ -} -//==================================================================================================================== -// Construct an LTPspecies object for a liquid transport property -// expressed as a constant value. -/* The transport property is constructed from the XML node, - * \verbatim , \endverbatim that is a child of the - * \verbatim \endverbatim node and specifies a type of - * transport property (like viscosity) - */ -LTPspecies_Const::LTPspecies_Const(const XML_Node& propNode, const std::string& name, - TransportPropertyType tp_ind, const thermo_t* const thermo) : - LTPspecies(&propNode, name, tp_ind, thermo) -{ - m_model = LTP_TD_CONSTANT; + + } + //==================================================================================================================== + doublereal LTPspecies::getMixWeight() const + { + return m_mixWeight; + } + //==================================================================================================================== + // Internal model to adjust species-specific properties for composition. + /* + * Currently just a place holder, but this method could take + * the composition from the thermo object and adjust coefficients + * accoding to some unspecified model. + */ + void LTPspecies::adjustCoeffsForComposition() + { + } + //==================================================================================================================== + // Construct an LTPspecies object for a liquid tranport property + // expressed as a constant value. + /* The transport property is constructed from the XML node, + * \verbatim , \endverbatim that is a child of the + * \verbatim \endverbatim node and specifies a type of + * transport property (like viscosity) + */ + LTPspecies_Const::LTPspecies_Const(const XML_Node &propNode, const std::string name, + TransportPropertyType tp_ind, const thermo_t * const thermo) : + LTPspecies(&propNode, name, tp_ind, thermo) + { + m_model = LTP_TD_CONSTANT; double A_k = getFloatCurrent(propNode, "toSI"); if (A_k > 0.0) { m_coeffs.push_back(A_k); @@ -196,28 +199,30 @@ LTPspecies* LTPspecies_Const::duplMyselfAsLTPspecies() const doublereal LTPspecies_Const::getSpeciesTransProp() { return m_coeffs[0]; -} -//==================================================================================================================== -// Construct an LTPspecies object for a liquid transport property -// expressed in extended Arrhenius form. -/* - * The transport property is constructed from the XML node, - * \verbatim , \endverbatim that is a child of the - * \verbatim \endverbatim node and specifies a type of transport property (like viscosity) - * - * - * @param propNode Reference to the XML node that contains the property information.This class - * is assumed to be parameterized by reading XML_Node information. - * @param name String containing the species name - * @param tp_ind enum TransportPropertyType containing the property id that this object - * is creating a parameterization for (e.g., viscosity) - * @param thermo const pointer to the ThermoPhase object, which is used to find the temperature. - * - */ -LTPspecies_Arrhenius::LTPspecies_Arrhenius(const XML_Node& propNode, const std::string& name, - TransportPropertyType tp_ind, const thermo_t* thermo) : - LTPspecies(&propNode, name, tp_ind, thermo) -{ + + } + //==================================================================================================================== + // Construct an LTPspecies object for a liquid tranport property + // expressed in extended Arrhenius form. + /* + * The transport property is constructed from the XML node, + * \verbatim , \endverbatim that is a child of the + * \verbatim \endverbatim node and specifies a type of transport property (like viscosity) + * + * + * @param propNode Referenc to the XML node that contains the property information.This class + * is assumed to be parameterized by reading XML_Node information. + * @param name String containing the species name + * @param tp_ind enum TransportPropertyType containing the property id that this object + * is creating a parameterization for (e.g., viscosity) + * @param thermo const pointer to the ThermoPhase object, which is used to find the temperature. + * + */ + LTPspecies_Arrhenius::LTPspecies_Arrhenius(const XML_Node &propNode, const std::string name, + TransportPropertyType tp_ind, const thermo_t* thermo) : + LTPspecies(&propNode, name, tp_ind, thermo) + { + m_model = LTP_TD_ARRHENIUS; m_temp = 0.0; m_prop = 0.0; @@ -310,24 +315,25 @@ doublereal LTPspecies_Arrhenius::getSpeciesTransProp() m_prop = exp(m_logProp); } return m_prop; -} -//==================================================================================================================== -// Construct an LTPspecies object for a liquid transport property expressed as a polynomial in temperature. -/* - * The transport property is constructed from the XML node, \verbatim , \endverbatim that is a child of the - * \verbatim \endverbatim node and specifies a type of transport property (like viscosity). - * - * - * @param propNode Reference to the XML node that contains the property information. This class - * must be parameterized by reading XML_Node information. - * @param name String containing the species name - * @param tp_ind enum TransportPropertyType containing the property id that this object - * is creating a parameterization for (e.g., viscosity) - * @param thermo const pointer to the ThermoPhase object, which is used to find the temperature. - * - */ -LTPspecies_Poly::LTPspecies_Poly(const XML_Node& propNode, const std::string& name, - TransportPropertyType tp_ind, const thermo_t* thermo) : + + } + //==================================================================================================================== + // Construct an LTPspecies object for a liquid tranport property expressed as a polynomial in temperature. + /* + * The transport property is constructed from the XML node, \verbatim , \endverbatim that is a child of the + * \verbatim \endverbatim node and specifies a type of transport property (like viscosity). + * + * + * @param propNode Referenc to the XML node that contains the property information. This class + * must be parameterized by reading XML_Node information. + * @param name String containing the species name + * @param tp_ind enum TransportPropertyType containing the property id that this object + * is creating a parameterization for (e.g., viscosity) + * @param thermo const pointer to the ThermoPhase object, which is used to find the temperature. + * + */ + LTPspecies_Poly::LTPspecies_Poly(const XML_Node &propNode, const std::string name, + TransportPropertyType tp_ind, const thermo_t* thermo) : LTPspecies(&propNode, name, tp_ind, thermo), m_temp(-1.0), m_prop(0.0) @@ -381,25 +387,27 @@ doublereal LTPspecies_Poly::getSpeciesTransProp() } } return m_prop; -} -//==================================================================================================================== -// Construct an LTPspecies object for a liquid transport property -// expressed as an exponential in temperature. -/* - * The transport property is constructed from the XML node, \verbatim , \endverbatim that is a child of the - * \verbatim \endverbatim node and specifies a type of transport property (like viscosity). - * - * - * @param propNode Reference to the XML node that contains the property information. This class - * must be parameterized by reading XML_Node information. - * @param name String containing the species name - * @param tp_ind enum TransportPropertyType containing the property id that this object - * is creating a parameterization for (e.g., viscosity) - * @param thermo const pointer to the ThermoPhase object, which is used to find the temperature. - * - */ -LTPspecies_ExpT::LTPspecies_ExpT(const XML_Node& propNode, const std::string& name, TransportPropertyType tp_ind, - const thermo_t* thermo) : + + } + //==================================================================================================================== + // Construct an LTPspecies object for a liquid tranport property + // expressed as an exponential in temperature. + /* + * The transport property is constructed from the XML node, \verbatim , \endverbatim that is a child of the + * \verbatim \endverbatim node and specifies a type of transport property (like viscosity). + * + * + * @param propNode Referenc to the XML node that contains the property information. This class + * must be parameterized by reading XML_Node information. + * @param name String containing the species name + * @param tp_ind enum TransportPropertyType containing the property id that this object + * is creating a parameterization for (e.g., viscosity) + * @param thermo const pointer to the ThermoPhase object, which is used to find the temperature. + * + */ + LTPspecies_ExpT::LTPspecies_ExpT(const XML_Node &propNode, const std::string name, TransportPropertyType tp_ind, + const thermo_t* thermo) : + LTPspecies(&propNode, name, tp_ind, thermo), m_temp(-1.0), m_prop(0.0) diff --git a/src/transport/SolidTransport.cpp b/src/transport/SolidTransport.cpp index d652da3e1..f6446665a 100644 --- a/src/transport/SolidTransport.cpp +++ b/src/transport/SolidTransport.cpp @@ -7,9 +7,12 @@ // copyright 2008 California Institute of Technology #include "cantera/thermo/ThermoPhase.h" +#include "cantera/transport/SolidTransportData.h" #include "cantera/transport/SolidTransport.h" + #include "cantera/base/utilities.h" + #include using namespace std; @@ -25,7 +28,7 @@ SolidTransport::SolidTransport() : m_Ndiff(0), m_Ediff(0), m_sp(0), - m_Alam(0), + m_Alam(-1.0), m_Nlam(0), m_Elam(0) { @@ -42,7 +45,7 @@ SolidTransport::SolidTransport(const SolidTransport& right) : m_Ndiff(0), m_Ediff(0), m_sp(0), - m_Alam(0), + m_Alam(-1.0), m_Nlam(0), m_Elam(0) { @@ -70,15 +73,56 @@ SolidTransport& SolidTransport::operator=(const SolidTransport& b) m_Elam = b.m_Elam; return *this; -} -//==================================================================================================================== -Transport* SolidTransport::duplMyselfAsTransport() const -{ - return new SolidTransport(*this); -} -//==================================================================================================================== -void SolidTransport::setParameters(const int n, const int k, const doublereal* const p) -{ + + } + //==================================================================================================================== + Transport *SolidTransport::duplMyselfAsTransport() const + { + SolidTransport* tr = new SolidTransport(*this); + return (dynamic_cast(tr)); + } + + //==================================================================================================================== + // Initialize the transport object + /* + * Here we change all of the internal dimensions to be sufficient. + * We get the object ready to do property evaluations. + * A lot of the input required to do property evaluations is + * contained in the SolidTransportData class that is + * filled in TransportFactory. + * + * @param tr Transport parameters for the phase + */ + bool SolidTransport::initSolid(SolidTransportData& tr) { + + m_thermo = tr.thermo; + tr.thermo = 0; + //m_nsp = m_thermo->nSpecies(); + //m_tmin = m_thermo->minTemp(); + //m_tmax = m_thermo->maxTemp(); + + // make a local copy of the molecular weights + //m_mw.resize(m_nsp, 0.0); + //copy(m_thermo->molecularWeights().begin(), + // m_thermo->molecularWeights().end(), m_mw.begin()); + + m_ionConductivity = tr.ionConductivity; + tr.ionConductivity = 0; + m_electConductivity = tr.electConductivity; + tr.electConductivity = 0; + m_thermalConductivity = tr.thermalConductivity; + tr.thermalConductivity = 0; + m_defectDiffusivity = tr.defectDiffusivity; + tr.defectDiffusivity = 0; + m_defectActivity = tr.defectActivity; + tr.defectActivity = 0; + + return true; + } + + //==================================================================================================================== + + void SolidTransport::setParameters(const int n, const int k, const doublereal * const p) { switch (n) { case 0: @@ -103,67 +147,131 @@ void SolidTransport::setParameters(const int n, const int k, const doublereal* c } m_work.resize(m_thermo->nSpecies()); -} -//==================================================================================================================== -/* - * Compute the mobilities of the species from the diffusion coefficients, - * using the Einstein relation. - */ -void SolidTransport::getMobilities(doublereal* const mobil) -{ + + } + + /****************** ionConductivity ******************************/ + + // Returns the ionic conductivity of the phase + /* + * The thermo phase needs to be updated (temperature) prior to calling this. + * The ionConductivity calculation is handled by subclasses of + * LTPspecies as specified in the input file. + * + */ + doublereal SolidTransport::ionConductivity() { + // LTPspecies method + return m_ionConductivity->getSpeciesTransProp(); + } + + /****************** electron Conductivity ******************************/ + + // Returns the electron conductivity of the phase + /* + * The thermo phase needs to be updated (temperature) prior to calling this. + * The ionConductivity calculation is handled by subclasses of + * LTPspecies as specified in the input file. + * + * There is also a legacy multicomponent diffusion approach to electrical conductivity. + * + */ + doublereal SolidTransport::electricalConductivity() { + if ( m_nmobile == 0 ) { + // LTPspecies method + return m_electConductivity->getSpeciesTransProp(); + } else { + getMobilities(&m_work[0]); + int nsp = m_thermo->nSpecies(); + doublereal sum = 0.0; + for (int k = 0; k < nsp; k++) { + sum += m_thermo->charge(k) * m_thermo->moleFraction(k) * m_work[k]; + } + return sum * m_thermo->molarDensity(); + } + } + + /****************** thermalConductivity ******************************/ + + // Returns the thermal conductivity of the phase + /* + * The thermo phase needs to be updated (temperature) prior to calling this. + * The thermalConductivity calculation is handled by subclasses of + * LTPspecies as specified in the input file. + * + * There is also a legacy method to evaluate + * \f[ + * \lambda = A T^n \exp(-E/RT) + * \f] + */ + doublereal SolidTransport::thermalConductivity() { + if ( m_Alam > 0.0 ) { + //legacy test case? + doublereal t = m_thermo->temperature(); + return m_Alam * pow(t, m_Nlam) * exp(-m_Elam/t); + } else { + // LTPspecies method + return m_thermalConductivity->getSpeciesTransProp(); + } + } + + /****************** defectDiffusivity ******************************/ + + // Returns the diffusivity of the phase + /* + * The thermo phase needs to be updated (temperature) prior to calling this. + * The defectDiffusivity calculation is handled by subclasses of + * LTPspecies as specified in the input file. + * + */ + doublereal SolidTransport::defectDiffusivity() { + // LTPspecies method + return m_defectDiffusivity->getSpeciesTransProp(); + } + + /****************** defectActivity ******************************/ + + // Returns the diffusivity of the phase + /* + * The thermo phase needs to be updated (temperature) prior to calling this. + * The defectActivity calculation is handled by subclasses of + * LTPspecies as specified in the input file. + * + */ + doublereal SolidTransport::defectActivity() { + // LTPspecies method + return m_defectActivity->getSpeciesTransProp(); + } + //==================================================================================================================== + /* + * Compute the mobilities of the species from the diffusion coefficients, + * using the Einstein relation. + */ + void SolidTransport::getMobilities(doublereal* const mobil) { getMixDiffCoeffs(mobil); doublereal t = m_thermo->temperature(); doublereal c1 = ElectronCharge / (Boltzmann * t); for (size_t k = 0; k < m_thermo->nSpecies(); k++) { mobil[k] *= c1; } -} -//==================================================================================================================== -/* - * Thermal Conductivity. - * \f[ - * \lambda = A T^n \exp(-E/RT) - * \f] - */ -doublereal SolidTransport::thermalConductivity() -{ - doublereal t = m_thermo->temperature(); - return m_Alam * pow(t, m_Nlam) * exp(-m_Elam/t); -} -//==================================================================================================================== -/* - * The diffusion coefficients are computed from - * - * \f[ - * D_k = A_k T^{n_k} \exp(-E_k/RT). - * \f] - * - * The diffusion coefficients are only non-zero for species for - * which parameters have been specified using method - * setParameters. - */ -void SolidTransport::getMixDiffCoeffs(doublereal* const d) -{ - doublereal temp = m_thermo->temperature(); + + } + //==================================================================================================================== + /* + * The diffusion coefficients are computed from + * + * \f[ + * D_k = A_k T^{n_k} \exp(-E_k/RT). + * \f] + * + * The diffusion coefficients are only non-zero for species for + * which parameters have been specified using method + * setParameters. + */ + void SolidTransport::getMixDiffCoeffs(doublereal* const d) { size_t nsp = m_thermo->nSpecies(); for (size_t k = 0; k < nsp; k++) { d[k] = 0.0; } - for (size_t k = 0; k < m_nmobile; k++) { - d[m_sp[k]] = - m_Adiff[k] * pow(temp, m_Ndiff[k]) * exp(-m_Ediff[k]/temp); - } + } } //==================================================================================================================== -doublereal SolidTransport::electricalConductivity() -{ - getMobilities(&m_work[0]); - size_t nsp = m_thermo->nSpecies(); - doublereal sum = 0.0; - for (size_t k = 0; k < nsp; k++) { - sum += m_thermo->charge(k) * m_thermo->moleFraction(k) * m_work[k]; - } - return sum * m_thermo->molarDensity(); -} -//==================================================================================================================== -} diff --git a/src/transport/SolidTransportData.cpp b/src/transport/SolidTransportData.cpp new file mode 100644 index 000000000..5ccc96e49 --- /dev/null +++ b/src/transport/SolidTransportData.cpp @@ -0,0 +1,80 @@ +/** + * @file SolidTransportData.cpp + * Source code for solid transport property evaluations. + */ +/* + * $Author: hkmoffa $ + * $Date: 2010-07-13 13:22:30 -0600 (Tue, 13 Jul 2010) $ + * $Revision: 507 $ + */ + +#include "cantera/transport/SolidTransportData.h" + +using namespace std; + +#ifndef SAFE_DELETE +#define SAFE_DELETE(x) if (x) { delete (x); x = 0; } +#endif +namespace Cantera { + + //==================================================================================================================== + SolidTransportData::SolidTransportData() : + speciesName("-"), + ionConductivity(0), + thermalConductivity(0), + electConductivity(0), + defectDiffusivity(0), + defectActivity(0) + { + + } + //==================================================================================================================== + // Copy constructor + SolidTransportData::SolidTransportData(const SolidTransportData &right) : + speciesName("-"), + ionConductivity(0), + thermalConductivity(0), + electConductivity(0), + defectDiffusivity(0), + defectActivity(0) + { + *this = right; //use assignment operator to do other work + } + //==================================================================================================================== + // Assignment operator + SolidTransportData& SolidTransportData::operator=(const SolidTransportData& right) + { + if (&right != this) { + // These are all shallow pointer copies - yes, yes, yes horrible crime. + speciesName = right.speciesName; + if (right.ionConductivity) { + ionConductivity = (right.ionConductivity)->duplMyselfAsLTPspecies(); + } + + if (right.thermalConductivity) { + thermalConductivity = (right.thermalConductivity)->duplMyselfAsLTPspecies(); + } + if (right.electConductivity) { + electConductivity = (right.electConductivity)->duplMyselfAsLTPspecies(); + } + if (right.defectDiffusivity) { + defectDiffusivity = (right.defectDiffusivity)->duplMyselfAsLTPspecies(); + } + if (right.defectActivity) { + defectActivity = (right.defectActivity)->duplMyselfAsLTPspecies(); + } + } + return *this; + } + //==================================================================================================================== + SolidTransportData::~SolidTransportData() { + + SAFE_DELETE(ionConductivity); + SAFE_DELETE(thermalConductivity); + SAFE_DELETE(electConductivity); + SAFE_DELETE(defectDiffusivity); + SAFE_DELETE(defectActivity); + + } + //==================================================================================================================== +} diff --git a/src/transport/TransportBase.cpp b/src/transport/TransportBase.cpp index 25cc4cd06..d1a1a3c93 100644 --- a/src/transport/TransportBase.cpp +++ b/src/transport/TransportBase.cpp @@ -98,6 +98,7 @@ void Transport::checkSpeciesArraySize(size_t kk) const } } + /* Set transport model parameters. This method may be * overloaded in subclasses to set model-specific parameters. */ @@ -108,16 +109,31 @@ void Transport::setParameters(const int type, const int k, } -void Transport::setThermo(thermo_t& thermo) -{ - if (!ready()) { - m_thermo = &thermo; - m_nsp = m_thermo->nSpecies(); - } else + void Transport::setThermo(thermo_t& thermo) { + if (!ready()) { + m_thermo = &thermo; + //m_nmin = m_thermo->nSpecies(); + } + else { + int newNum = thermo.nSpecies(); + int oldNum = m_thermo->nSpecies(); + if (newNum != oldNum) { throw CanteraError("Transport::setThermo", - "the phase object cannot be changed after " - "the transport manager has been constructed."); -} + "base object cannot be changed after " + "the transport manager has been constructed because num species isn't the same."); + } + for (int i = 0; i < newNum; i++) { + std::string newS0 = thermo.speciesName(i); + std::string oldS0 = m_thermo->speciesName(i); + if (newNum != oldNum) { + throw CanteraError("Transport::setThermo", + "base object cannot be changed after " + "the transport manager has been constructed because species names are not the same"); + } + } + m_thermo = &thermo; + } + } doublereal Transport::err(const std::string& msg) const diff --git a/src/transport/TransportFactory.cpp b/src/transport/TransportFactory.cpp index b385a58cc..805c77cb2 100644 --- a/src/transport/TransportFactory.cpp +++ b/src/transport/TransportFactory.cpp @@ -19,16 +19,19 @@ #include "cantera/numerics/polyfit.h" #include "MMCollisionInt.h" + #include "cantera/base/xml.h" #include "cantera/base/XML_Writer.h" #include "cantera/transport/TransportParams.h" #include "cantera/transport/LiquidTransportParams.h" #include "cantera/transport/LiquidTranInteraction.h" +#include "cantera/transport/SolidTransportData.h" #include "cantera/base/global.h" #include "cantera/thermo/IdealGasPhase.h" #include "cantera/base/ctml.h" #include "cantera/base/stringUtils.h" + #include #include #include @@ -220,6 +223,8 @@ TransportFactory::TransportFactory() : m_tranPropMap["speciesDiffusivity"] = TP_DIFFUSIVITY; m_tranPropMap["hydrodynamicRadius"] = TP_HYDRORADIUS; m_tranPropMap["electricalConductivity"] = TP_ELECTCOND; + m_tranPropMap["defectDiffusivity"] = TP_DEFECTDIFF; + m_tranPropMap["defectActivity"] = TP_DEFECTCONC; m_LTRmodelMap[""] = LTP_TD_CONSTANT; m_LTRmodelMap["constant"] = LTP_TD_CONSTANT; @@ -260,15 +265,16 @@ std::string TransportFactory::modelName(int model) } } -/* - make one of several transport models, and return a base class - pointer to it. This method operates at the level of a - single transport property as a function of temperature - and possibly composition. -*/ -LTPspecies* TransportFactory::newLTP(const XML_Node& trNode, std::string& name, - TransportPropertyType tp_ind, thermo_t* thermo) -{ + + /* + make one of several transport models, and return a base class + pointer to it. This method operates at the level of a + single transport property as a function of temperature + and possibly composition. + */ + LTPspecies* TransportFactory::newLTP(const XML_Node &trNode, const std::string &name, + TransportPropertyType tp_ind, thermo_t* thermo) + { LTPspecies* ltps = 0; std::string model = lowercase(trNode["model"]); switch (m_LTRmodelMap[model]) { @@ -395,9 +401,11 @@ Transport* TransportFactory::newTransport(const std::string& transportModel, initTransport(tr, phase, 0, log_level); break; case cSolidTransport: - tr = new SolidTransport; - tr->setThermo(*phase); - break; + + tr = new SolidTransport; + initSolidTransport(tr, phase, log_level); + tr->setThermo(*phase); + break; case cDustyGasTransport: tr = new DustyGasTransport; gastr = new MultiTransport; @@ -642,27 +650,75 @@ void TransportFactory::setupLiquidTransport(std::ostream& flog, thermo_t* thermo XML_Node& transportNode = phase_database->child("transport"); getLiquidInteractionsTransportData(transportNode, log, trParam.thermo->speciesNames(), trParam); } -} -//==================================================================================================================== -// Initialize an existing transport manager -/* - * This routine sets up an existing gas-phase transport manager. - * It calculates the collision integrals and calls the initGas() function to - * populate the species-dependent data structure. - * - * @param tr Pointer to the Transport manager - * @param thermo Pointer to the ThermoPhase object - * @param mode Chemkin compatible mode or not. This alters the specification of the - * collision integrals. defaults to no. - * @param log_level Defaults to zero, no logging - * - * In DEBUG_MODE, this routine will create the file transport_log.xml - * and write informative information to it. - */ -void TransportFactory::initTransport(Transport* tran, - thermo_t* thermo, int mode, int log_level) -{ + + } + + + //==================================================================================================================== + // Prepare to build a new transport manager for solids + /* + * @param flog Reference to the ostream for writing log info + * @param thermo Pointer to the %ThermoPhase object + * @param log_level log level + * @param trParam SolidTransportParams structure to be filled up with information + */ + void TransportFactory::setupSolidTransport(std::ostream &flog, thermo_t* thermo, int log_level, + SolidTransportData& trParam) { + + const XML_Node* phase_database = &thermo->xml(); + + // constant mixture attributes + trParam.thermo = thermo; + trParam.nsp_ = trParam.thermo->nSpecies(); + int nsp = trParam.nsp_; + + trParam.tmin = thermo->minTemp(); + trParam.tmax = thermo->maxTemp(); + trParam.log_level = log_level; + + // Get the molecular weights and load them into trParam + trParam.mw.resize(nsp); + copy(trParam.thermo->molecularWeights().begin(), + trParam.thermo->molecularWeights().end(), trParam.mw.begin()); + + // Resize all other vectors in trParam + //trParam.LTData.resize(nsp); + + XML_Node root, log; + + // Note that getSolidSpeciesTransportData just populates the pure species transport data. + // const std::vector & species_database = thermo->speciesData(); + // getSolidSpeciesTransportData(species_database, log, trParam.thermo->speciesNames(), trParam); + + // getSolidTransportData() populates the + // phase transport models like electronic conductivity + // thermal conductivity, interstitial diffusion + if (phase_database->hasChild("transport")) { + XML_Node& transportNode = phase_database->child("transport"); + getSolidTransportData(transportNode, log, thermo->name(), trParam); + } + } + //==================================================================================================================== + // Initialize an existing transport manager + /* + * This routine sets up an existing gas-phase transport manager. + * It calculates the collision integrals and calls the initGas() function to + * populate the species-dependent data structure. + * + * @param tr Pointer to the Transport manager + * @param thermo Pointer to the ThermoPhase object + * @param mode Chemkin compatible mode or not. This alters the specification of the + * collision integrals. defaults to no. + * @param log_level Defaults to zero, no logging + * + * In DEBUG_MODE, this routine will create the file transport_log.xml + * and write informative information to it. + */ + void TransportFactory::initTransport(Transport* tran, + thermo_t* thermo, int mode, int log_level) { + ScopedLock transportLock(transport_mutex); + const std::vector & transport_database = thermo->speciesData(); GasTransportParams trParam; @@ -725,7 +781,47 @@ void TransportFactory::initLiquidTransport(Transport* tran, #endif return; -} + + } + //==================================================================================================================== + + /* Similar to initTransport except uses SolidTransportParams + class and calls setupSolidTransport(). + */ + void TransportFactory::initSolidTransport(Transport* tran, + thermo_t* thermo, + int log_level) { + + SolidTransportData trParam; + + //setup output +#ifdef DEBUG_MODE + ofstream flog("transport_log.xml"); + trParam.xml = new XML_Writer(flog); + if (m_verbose) { + trParam.xml->XML_open(flog, "transport"); + } +#else + // create the object, but don't associate it with a file + std::ostream &flog(std::cout); +#endif + + //real work next two statements + setupSolidTransport(flog, thermo, log_level, trParam ); + // do model-specific initialization + tran->initSolid( trParam ); + + +#ifdef DEBUG_MODE + if (m_verbose) { + trParam.xml->XML_close(flog, "transport"); + } + // finished with log file + flog.close(); +#endif + return; + } + void TransportFactory::fitCollisionIntegrals(ostream& logfile, GasTransportParams& tr, @@ -1058,9 +1154,10 @@ void TransportFactory::getLiquidInteractionsTransportData(const XML_Node& transp XML_Node& tranTypeNode = transportNode.child(iChild); std::string nodeName = tranTypeNode.name(); - trParam.mobilityRatio.resize(nsp*nsp,0); - trParam.selfDiffusion.resize(nsp,0); - ThermoPhase* temp_thermo = trParam.thermo; + trParam.mobilityRatio.resize(nsp*nsp,0); + trParam.selfDiffusion.resize(nsp,0); + ThermoPhase *temp_thermo = trParam.thermo; + if (tranTypeNode.hasChild("compositionDependence")) { //compDepNode contains the interaction model @@ -1154,6 +1251,85 @@ void TransportFactory::getLiquidInteractionsTransportData(const XML_Node& transp return; } + + + + + /* + * Given a phase XML data base, this method constructs the + * SolidTransportData object containing the transport data for the phase. + * + * @param db Reference to a vector of XML_Node pointers containing the species XML + * nodes. + * @param log Reference to an XML log file. (currently unused) + * @param tr Reference to the SolidTransportData object that will contain the results. + * NOTE: For now we are using the LTPspecies class to describe the solid transport models. + */ + void TransportFactory::getSolidTransportData(const XML_Node &transportNode, + XML_Node& log, + const std::string phaseName, + SolidTransportData& trParam) + { + try { + + int num = transportNode.nChildren(); + for (int iChild = 0; iChild < num; iChild++) { + //tranTypeNode is a type of transport property like viscosity + XML_Node &tranTypeNode = transportNode.child(iChild); + std::string nodeName = tranTypeNode.name(); + + ThermoPhase *temp_thermo = trParam.thermo; + + //tranTypeNode contains the interaction model + // XML_Node &compDepNode = tranTypeNode.child("compositionDependence"); + switch (m_tranPropMap[nodeName]) { + case TP_IONCONDUCTIVITY: + trParam.ionConductivity = newLTP(tranTypeNode, phaseName, + m_tranPropMap[nodeName], + temp_thermo); + break; + case TP_THERMALCOND: + trParam.thermalConductivity = newLTP(tranTypeNode, phaseName, + m_tranPropMap[nodeName], + temp_thermo); + break; + case TP_DEFECTDIFF: + trParam.defectDiffusivity = newLTP(tranTypeNode, phaseName, + m_tranPropMap[nodeName], + temp_thermo); + break; + case TP_DEFECTCONC: + trParam.defectActivity = newLTP(tranTypeNode, phaseName, + m_tranPropMap[nodeName], + temp_thermo); + break; + case TP_ELECTCOND: + trParam.electConductivity = newLTP(tranTypeNode, phaseName, + m_tranPropMap[nodeName], + temp_thermo); + break; + default: + throw CanteraError("getSolidTransportData","unknown transport property: " + nodeName); + + } + } + } + catch (CanteraError) { + showErrors(std::cout); + } + //catch(CanteraError) { + // ; + //} + return; + } + + /********************************************************* + * + * Polynomial fitting + * + *********************************************************/ + + /********************************************************* * * Polynomial fitting diff --git a/test_problems/surfSolverTest/surfaceSolver.cpp b/test_problems/surfSolverTest/surfaceSolver.cpp index ef457b45e..374a92c1a 100644 --- a/test_problems/surfSolverTest/surfaceSolver.cpp +++ b/test_problems/surfSolverTest/surfaceSolver.cpp @@ -32,8 +32,8 @@ static void printUsage() #include "cantera/Interface.h" #include "cantera/kinetics.h" -#include "kinetics/ImplicitSurfChem.h" -#include "kinetics/solveSP.h" +#include "cantera/kinetics/ImplicitSurfChem.h" +#include "cantera/kinetics/solveSP.h" using namespace Cantera; diff --git a/test_problems/surfSolverTest/surfaceSolver2.cpp b/test_problems/surfSolverTest/surfaceSolver2.cpp index fea138de9..78cca65b7 100644 --- a/test_problems/surfSolverTest/surfaceSolver2.cpp +++ b/test_problems/surfSolverTest/surfaceSolver2.cpp @@ -35,8 +35,8 @@ static void printUsage() #include "cantera/Interface.h" #include "cantera/kinetics.h" -#include "kinetics/ImplicitSurfChem.h" -#include "kinetics/solveSP.h" +#include "cantera/kinetics/ImplicitSurfChem.h" +#include "cantera/kinetics/solveSP.h" using namespace Cantera;