int vcs_determine_PhaseStability(MultiPhase& s, int iphase, double& funcStab, int printLvl, int loglevel) { int iStab = 0; static int counter = 0; int printLvlSub = std::max(0, printLvl-1); s.init(); try { vcs_MultiPhaseEquil* eqsolve = new vcs_MultiPhaseEquil(&s, printLvlSub); iStab = eqsolve->determine_PhaseStability(iphase, funcStab, printLvlSub, loglevel); // hard code a csv output file. if (printLvl > 0) { string reportFile = "vcs_phaseStability.csv"; if (counter > 0) { reportFile = "vcs_phaseStability_" + int2str(counter) + ".csv"; } eqsolve->reportCSV(reportFile); counter++; } delete eqsolve; } catch (CanteraError& e) { throw e; } return iStab; }
int vcs_equilibrate_1(MultiPhase& s, int ixy, int estimateEquil, int printLvl, int solver, doublereal tol, int maxsteps, int maxiter, int loglevel) { warn_deprecated("vcs_equilibrate_1", "Use MultiPhase::equilibrate instead. " "To be removed after Cantera 2.2."); static int counter = 0; int retn = 1; int printLvlSub = std::max(0, printLvl-1); s.init(); if (solver == 2) { try { vcs_MultiPhaseEquil* eqsolve = new vcs_MultiPhaseEquil(&s, printLvlSub); int err = eqsolve->equilibrate(ixy, estimateEquil, printLvlSub, tol, maxsteps, loglevel); if (err != 0) { retn = -1; } // hard code a csv output file. if (printLvl > 0) { string reportFile = "vcs_equilibrate_res.csv"; if (counter > 0) { reportFile = "vcs_equilibrate_res_" + int2str(counter) + ".csv"; } eqsolve->reportCSV(reportFile); counter++; } delete eqsolve; } catch (CanteraError& e) { e.save(); retn = -1; throw e; } } else if (solver == 1) { if (ixy == TP || ixy == HP || ixy == SP || ixy == TV) { try { s.equilibrate(ixy, tol, maxsteps, maxiter, loglevel); return 0; } catch (CanteraError& e) { e.save(); throw e; } } else { throw CanteraError("equilibrate","unsupported option"); } } else { throw CanteraError("vcs_equilibrate_1", "unknown solver"); } return retn; }
void ThermoPhase::equilibrate(const std::string& XY, const std::string& solver, double rtol, int max_steps, int max_iter, int estimate_equil, int log_level) { if (solver == "auto" || solver == "element_potential") { vector_fp initial_state; saveState(initial_state); debuglog("Trying ChemEquil solver\n", log_level); try { ChemEquil E; E.options.maxIterations = max_steps; E.options.relTolerance = rtol; bool use_element_potentials = (estimate_equil == 0); int ret = E.equilibrate(*this, XY.c_str(), use_element_potentials, log_level-1); if (ret < 0) { throw CanteraError("ThermoPhase::equilibrate", "ChemEquil solver failed. Return code: {}", ret); } setElementPotentials(E.elementPotentials()); debuglog("ChemEquil solver succeeded\n", log_level); return; } catch (std::exception& err) { debuglog("ChemEquil solver failed.\n", log_level); debuglog(err.what(), log_level); restoreState(initial_state); if (solver == "auto") { } else { throw; } } } if (solver == "auto" || solver == "vcs" || solver == "gibbs") { MultiPhase M; M.addPhase(this, 1.0); M.init(); M.equilibrate(XY, solver, rtol, max_steps, max_iter, estimate_equil, log_level); return; } if (solver != "auto") { throw CanteraError("ThermoPhase::equilibrate", "Invalid solver specified: '{}'", solver); } }
/* * Set a multiphase mixture to a state of chemical equilibrium. * This is the top-level driver for multiphase equilibrium. It * doesn't do much more than call the equilibrate method of class * MultiPhase, except that it adds some messages to the logfile, * if loglevel is set > 0. * * @ingroup equil */ doublereal equilibrate(MultiPhase& s, const char* XY, doublereal tol, int maxsteps, int maxiter, int loglevel) { if (loglevel > 0) { beginLogGroup("equilibrate",loglevel); addLogEntry("multiphase equilibrate function"); beginLogGroup("arguments"); addLogEntry("XY",XY); addLogEntry("tol",tol); addLogEntry("maxsteps",maxsteps); addLogEntry("maxiter",maxiter); addLogEntry("loglevel",loglevel); endLogGroup("arguments"); } s.init(); int ixy = _equilflag(XY); if (ixy == TP || ixy == HP || ixy == SP || ixy == TV) { try { double err = s.equilibrate(ixy, tol, maxsteps, maxiter, loglevel); if (loglevel > 0) { addLogEntry("Success. Error",err); endLogGroup("equilibrate"); } return err; } catch (CanteraError &err) { if (loglevel > 0) { addLogEntry("Failure.",lastErrorMessage()); endLogGroup("equilibrate"); } throw err; } } else { if (loglevel > 0) { addLogEntry("multiphase equilibrium can be done only for TP, HP, SP, or TV"); endLogGroup("equilibrate"); } throw CanteraError("equilibrate","unsupported option"); return -1.0; } return 0.0; }
TEST_F(OverconstrainedEquil, DISABLED_BasisOptimize2) { setup("O H C N Ar"); MultiPhase mphase; mphase.addPhase(gas.get(), 10.0); mphase.init(); int usedZeroedSpecies = 0; std::vector<size_t> orderVectorSpecies; std::vector<size_t> orderVectorElements; bool doFormMatrix = true; vector_fp formRxnMatrix; size_t nc = BasisOptimize(&usedZeroedSpecies, doFormMatrix, &mphase, orderVectorSpecies, orderVectorElements, formRxnMatrix); ASSERT_EQ(1, (int) nc); }
/* * * @param s The MultiPhase object to be set to an equilibrium state * @param iphase Phase index within the multiphase object to be * tested for stability. * @param funcStab Function value that tests equilibrium. > 0 indicates stable * < 0 indicates unstable * * @param printLvl Determines the amount of printing that * gets sent to stdout from the vcs package * (Note, you may have to compile with debug * flags to get some printing). * * @param loglevel Controls amount of diagnostic output. loglevel * = 0 suppresses diagnostics, and increasingly-verbose * messages are written as loglevel increases. The * messages are written to a file in HTML format for viewing * in a web browser. @see HTML_logs */ int vcs_determine_PhaseStability(MultiPhase& s, int iphase, double& funcStab, int printLvl, int loglevel) { int iStab = 0; static int counter = 0; beginLogGroup("PhaseStability",loglevel); addLogEntry("multiphase phase stability function"); beginLogGroup("arguments"); addLogEntry("iphase",iphase); addLogEntry("loglevel",loglevel); endLogGroup("arguments"); int printLvlSub = std::max(0, printLvl-1); s.init(); try { VCSnonideal::vcs_MultiPhaseEquil* eqsolve = new VCSnonideal::vcs_MultiPhaseEquil(&s, printLvlSub); iStab = eqsolve->determine_PhaseStability(iphase, funcStab, printLvlSub, loglevel); if (iStab != 0) { addLogEntry("Phase is stable - ", iphase); } else { addLogEntry("Phase is not stable - ", iphase); } endLogGroup("PhaseStability"); // hard code a csv output file. if (printLvl > 0) { string reportFile = "vcs_phaseStability.csv"; if (counter > 0) { reportFile = "vcs_phaseStability_" + int2str(counter) + ".csv"; } eqsolve->reportCSV(reportFile); counter++; } delete eqsolve; } catch (CanteraError& e) { addLogEntry("Failure.", lastErrorMessage()); endLogGroup("equilibrate"); throw e; } return iStab; }
/* * Set a single-phase chemical solution to chemical equilibrium. * This is a convenience function that uses one or the other of * the two chemical equilibrium solvers. * * @param s The object to set to an equilibrium state * * @param XY An integer specifying the two properties to be held * constant. * * @param estimateEquil integer indicating whether the solver * should estimate its own initial condition. * If 0, the initial mole fraction vector * in the %ThermoPhase object is used as the * initial condition. * If 1, the initial mole fraction vector * is used if the element abundances are * satisfied. * if -1, the initial mole fraction vector * is thrown out, and an estimate is * formulated. * * @param printLvl Determines the amount of printing that * gets sent to stdout from the vcs package * (Note, you may have to compile with debug * flags to get some printing). * * @param solver The equilibrium solver to use. If solver = 0, * the ChemEquil solver will be used, and if * solver = 1, the vcs_MultiPhaseEquil solver will * be used (slower than ChemEquil, * but more stable). If solver < 0 (default, then * ChemEquil will be tried first, and if it fails * vcs_MultiPhaseEquil will be tried. * * @param maxsteps The maximum number of steps to take to find * the solution. * * @param maxiter For the MultiPhaseEquil solver only, this is * the maximum number of outer temperature or * pressure iterations to take when T and/or P is * not held fixed. * * @param loglevel Controls amount of diagnostic output. loglevel * = 0 suppresses diagnostics, and increasingly-verbose * messages are written as loglevel increases. The * messages are written to a file in HTML format for viewing * in a web browser. @see HTML_logs */ int vcs_equilibrate(thermo_t& s, const char* XY, int estimateEquil, int printLvl, int solver, doublereal rtol, int maxsteps, int maxiter, int loglevel) { MultiPhase* m = 0; int retn = 1; int retnSub = 0; beginLogGroup("equilibrate", loglevel); // retry: addLogEntry("Single-phase equilibrate function"); { beginLogGroup("arguments"); addLogEntry("phase",s.id()); addLogEntry("XY",XY); addLogEntry("solver",solver); addLogEntry("rtol",rtol); addLogEntry("maxsteps",maxsteps); addLogEntry("maxiter",maxiter); addLogEntry("loglevel",loglevel); endLogGroup("arguments"); } if (solver == 2) { m = new MultiPhase; try { /* * Set the kmoles of the phase to 1.0, arbitrarily. * It actually doesn't matter. */ m->addPhase(&s, 1.0); m->init(); retn = vcs_equilibrate(*m, XY, estimateEquil, printLvl, solver, rtol, maxsteps, maxiter, loglevel); if (retn == 1) { addLogEntry("MultiPhaseEquil solver succeeded."); } else { addLogEntry("MultiPhaseEquil solver returned an error code: ", retn); } delete m; } catch (CanteraError& err) { err.save(); addLogEntry("MultiPhaseEquil solver failed."); delete m; throw err; } } else if (solver == 1) { m = new MultiPhase; try { m->addPhase(&s, 1.0); m->init(); (void) equilibrate(*m, XY, rtol, maxsteps, maxiter, loglevel-1); if (loglevel > 0) { addLogEntry("MultiPhaseEquil solver succeeded."); } delete m; retn = 1; } catch (CanteraError& err) { err.save(); if (loglevel > 0) { addLogEntry("MultiPhaseEquil solver failed."); } delete m; throw err; } } else if (solver == 0) { ChemEquil* e = new ChemEquil; try { e->options.maxIterations = maxsteps; e->options.relTolerance = rtol; bool useThermoPhaseElementPotentials = false; if (estimateEquil == 0) { useThermoPhaseElementPotentials = true; } retnSub = e->equilibrate(s, XY, useThermoPhaseElementPotentials, loglevel-1); if (retnSub < 0) { if (loglevel > 0) { addLogEntry("ChemEquil solver failed."); } delete e; throw CanteraError("equilibrate", "ChemEquil equilibrium solver failed"); } retn = 1; s.setElementPotentials(e->elementPotentials()); delete e; if (loglevel > 0) { addLogEntry("ChemEquil solver succeeded."); } } catch (CanteraError& err) { err.save(); if (loglevel > 0) { addLogEntry("ChemEquil solver failed."); } delete e; throw err; } } else { throw CanteraError("vcs_equilibrate", "unknown solver"); } /* * We are here only for a success */ endLogGroup("equilibrate"); return retn; }
/* * This function uses the vcs_MultiPhaseEquil interface to the * vcs solver. * The function uses the element abundance vector that is * currently consistent with the composition within the phases * themselves. Two other thermodynamic quantities, determined by the * XY string, are held constant during the equilibration. * * @param s The object to set to an equilibrium state * * @param XY An integer specifying the two properties to be held * constant. * * @param estimateEquil integer indicating whether the solver * should estimate its own initial condition. * If 0, the initial mole fraction vector * in the %ThermoPhase object is used as the * initial condition. * If 1, the initial mole fraction vector * is used if the element abundances are * satisfied. * if -1, the initial mole fraction vector * is thrown out, and an estimate is * formulated. * * @param printLvl Determines the amount of printing that * gets sent to stdout from the vcs package * (Note, you may have to compile with debug * flags to get some printing). * * @param maxsteps The maximum number of steps to take to find * the solution. * * @param maxiter For the MultiPhaseEquil solver only, this is * the maximum number of outer temperature or * pressure iterations to take when T and/or P is * not held fixed. * * @param loglevel Controls amount of diagnostic output. loglevel * = 0 suppresses diagnostics, and increasingly-verbose * messages are written as loglevel increases. The * messages are written to a file in HTML format for viewing * in a web browser. @see HTML_logs * * @ingroup equilfunctions */ int vcs_equilibrate_1(MultiPhase& s, int ixy, int estimateEquil, int printLvl, int solver, doublereal tol, int maxsteps, int maxiter, int loglevel) { static int counter = 0; int retn = 1; beginLogGroup("equilibrate",loglevel); addLogEntry("multiphase equilibrate function"); beginLogGroup("arguments"); addLogEntry("XY",ixy); addLogEntry("tol",tol); addLogEntry("maxsteps",maxsteps); addLogEntry("maxiter",maxiter); addLogEntry("loglevel",loglevel); endLogGroup("arguments"); int printLvlSub = std::max(0, printLvl-1); s.init(); if (solver == 2) { try { VCSnonideal::vcs_MultiPhaseEquil* eqsolve = new VCSnonideal::vcs_MultiPhaseEquil(&s, printLvlSub); int err = eqsolve->equilibrate(ixy, estimateEquil, printLvlSub, tol, maxsteps, loglevel); if (err != 0) { retn = -1; addLogEntry("vcs_equilibrate Error - ", err); } else { addLogEntry("vcs_equilibrate Success - ", err); } endLogGroup("equilibrate"); // hard code a csv output file. if (printLvl > 0) { string reportFile = "vcs_equilibrate_res.csv"; if (counter > 0) { reportFile = "vcs_equilibrate_res_" + int2str(counter) + ".csv"; } eqsolve->reportCSV(reportFile); counter++; } delete eqsolve; } catch (CanteraError& e) { e.save(); retn = -1; addLogEntry("Failure.", lastErrorMessage()); endLogGroup("equilibrate"); throw e; } } else if (solver == 1) { if (ixy == TP || ixy == HP || ixy == SP || ixy == TV) { try { double err = s.equilibrate(ixy, tol, maxsteps, maxiter, loglevel); addLogEntry("Success. Error",err); endLogGroup("equilibrate"); return 0; } catch (CanteraError& e) { e.save(); addLogEntry("Failure.",lastErrorMessage()); endLogGroup("equilibrate"); throw e; } } else { addLogEntry("multiphase equilibrium can be done only for TP, HP, SP, or TV"); endLogGroup("equilibrate"); throw CanteraError("equilibrate","unsupported option"); //return -1.0; } } else { throw CanteraError("vcs_equilibrate_1", "unknown solver"); } return retn; }
int vcs_equilibrate(thermo_t& s, const char* XY, int estimateEquil, int printLvl, int solver, doublereal rtol, int maxsteps, int maxiter, int loglevel) { warn_deprecated("vcs_equilibrate", "Use ThermoPhase::equilibrate instead. " "To be removed after Cantera 2.2."); MultiPhase* m = 0; int retn = 1; if (solver == 2) { m = new MultiPhase; try { /* * Set the kmoles of the phase to 1.0, arbitrarily. * It actually doesn't matter. */ m->addPhase(&s, 1.0); m->init(); retn = vcs_equilibrate(*m, XY, estimateEquil, printLvl, solver, rtol, maxsteps, maxiter, loglevel); delete m; } catch (CanteraError& err) { err.save(); delete m; throw err; } } else if (solver == 1) { m = new MultiPhase; try { m->addPhase(&s, 1.0); m->init(); (void) equilibrate(*m, XY, rtol, maxsteps, maxiter, loglevel-1); delete m; retn = 1; } catch (CanteraError& err) { err.save(); delete m; throw err; } } else if (solver == 0) { ChemEquil* e = new ChemEquil; try { e->options.maxIterations = maxsteps; e->options.relTolerance = rtol; bool useThermoPhaseElementPotentials = false; if (estimateEquil == 0) { useThermoPhaseElementPotentials = true; } int retnSub = e->equilibrate(s, XY, useThermoPhaseElementPotentials, loglevel-1); if (retnSub < 0) { delete e; throw CanteraError("equilibrate", "ChemEquil equilibrium solver failed"); } retn = 1; s.setElementPotentials(e->elementPotentials()); delete e; } catch (CanteraError& err) { err.save(); delete e; throw err; } } else { throw CanteraError("vcs_equilibrate", "unknown solver"); } /* * We are here only for a success */ return retn; }
/* * Set a single-phase chemical solution to chemical equilibrium. * This is a convenience function that uses one or the other of * the two chemical equilibrium solvers. * * @param s The object to set to an equilibrium state * * @param XY An integer specifying the two properties to be held * constant. * * @param solver The equilibrium solver to use. If solver = 0, * the ChemEquil solver will be used, and if solver = 1, the * MultiPhaseEquil solver will be used (slower than ChemEquil, * but more stable). If solver < 0 (default, then ChemEquil will * be tried first, and if it fails MultiPhaseEquil will be tried. * * @param maxsteps The maximum number of steps to take to find * the solution. * * @param maxiter For the MultiPhaseEquil solver only, this is * the maximum number of outer temperature or pressure iterations * to take when T and/or P is not held fixed. * * @param loglevel Controls amount of diagnostic output. loglevel * = 0 suppresses diagnostics, and increasingly-verbose messages * are written as loglevel increases. The messages are written to * a file in HTML format for viewing in a web browser. * @see HTML_logs * * @ingroup equil */ int equilibrate(thermo_t& s, const char* XY, int solver, doublereal rtol, int maxsteps, int maxiter, int loglevel) { MultiPhase* m = 0; ChemEquil* e = 0; bool redo = true; int retn = -1; int nAttempts = 0; int retnSub = 0; if (loglevel > 0) { beginLogGroup("equilibrate", loglevel); addLogEntry("Single-phase equilibrate function"); { beginLogGroup("arguments"); addLogEntry("phase",s.id()); addLogEntry("XY",XY); addLogEntry("solver",solver); addLogEntry("rtol",rtol); addLogEntry("maxsteps",maxsteps); addLogEntry("maxiter",maxiter); addLogEntry("loglevel",loglevel); endLogGroup("arguments"); } } while (redo) { if (solver >= 2) { #ifdef WITH_VCSNONIDEAL int printLvlSub = 0; int estimateEquil = 0; m = new MultiPhase; try { m->addPhase(&s, 1.0); m->init(); nAttempts++; vcs_equilibrate(*m, XY, estimateEquil, printLvlSub, solver, rtol, maxsteps, maxiter, loglevel-1); redo = false; if (loglevel > 0) addLogEntry("VCSnonideal solver succeeded."); delete m; retn = nAttempts; } catch (CanteraError &err) { if (loglevel > 0) addLogEntry("VCSnonideal solver failed."); delete m; if (nAttempts < 2) { if (loglevel > 0) addLogEntry("Trying single phase ChemEquil solver."); solver = -1; } else { if (loglevel > 0) endLogGroup("equilibrate"); throw err; } } #else throw CanteraError("equilibrate", "VCSNonIdeal solver called, but not compiled"); #endif } else if (solver == 1) { m = new MultiPhase; try { m->addPhase(&s, 1.0); m->init(); nAttempts++; (void) equilibrate(*m, XY, rtol, maxsteps, maxiter, loglevel-1); redo = false; if (loglevel > 0) addLogEntry("MultiPhaseEquil solver succeeded."); delete m; retn = nAttempts; } catch (CanteraError &err) { if (loglevel > 0) addLogEntry("MultiPhaseEquil solver failed."); delete m; if (nAttempts < 2) { if (loglevel > 0) addLogEntry("Trying single phase ChemEquil solver."); solver = -1; } else { if (loglevel > 0) endLogGroup("equilibrate"); throw err; } } } else { // solver <= 0 /* * Call the element potential solver */ e = new ChemEquil; try { e->options.maxIterations = maxsteps; e->options.relTolerance = rtol; nAttempts++; bool useThermoPhaseElementPotentials = true; retnSub = e->equilibrate(s,XY, useThermoPhaseElementPotentials, loglevel-1); if (retnSub < 0) { if (loglevel > 0) addLogEntry("ChemEquil solver failed."); if (nAttempts < 2) { if (loglevel > 0) addLogEntry("Trying MultiPhaseEquil solver."); solver = 1; } else { throw CanteraError("equilibrate", "Both equilibrium solvers failed"); } } retn = nAttempts; s.setElementPotentials(e->elementPotentials()); redo = false; delete e; if (loglevel > 0) addLogEntry("ChemEquil solver succeeded."); } catch (CanteraError &err) { delete e; if (loglevel > 0) addLogEntry("ChemEquil solver failed."); // If ChemEquil fails, try the MultiPhase solver if (solver < 0) { if (loglevel > 0) addLogEntry("Trying MultiPhaseEquil solver."); solver = 1; } else { redo = false; if (loglevel > 0) endLogGroup("equilibrate"); throw err; } } } } // while (redo) /* * We are here only for a success */ if (loglevel > 0) endLogGroup("equilibrate"); return retn; }
int equilibrate(thermo_t& s, const char* XY, int solver, doublereal rtol, int maxsteps, int maxiter, int loglevel) { bool redo = true; int retn = -1; int nAttempts = 0; int retnSub = 0; if (loglevel > 0) { beginLogGroup("equilibrate", loglevel); addLogEntry("Single-phase equilibrate function"); { beginLogGroup("arguments"); addLogEntry("phase",s.id()); addLogEntry("XY",XY); addLogEntry("solver",solver); addLogEntry("rtol",rtol); addLogEntry("maxsteps",maxsteps); addLogEntry("maxiter",maxiter); addLogEntry("loglevel",loglevel); endLogGroup("arguments"); } } while (redo) { if (solver >= 2) { int printLvlSub = 0; int estimateEquil = 0; try { MultiPhase m; m.addPhase(&s, 1.0); m.init(); nAttempts++; vcs_equilibrate(m, XY, estimateEquil, printLvlSub, solver, rtol, maxsteps, maxiter, loglevel-1); redo = false; if (loglevel > 0) { addLogEntry("VCSnonideal solver succeeded."); } retn = nAttempts; } catch (CanteraError& err) { err.save(); if (loglevel > 0) { addLogEntry("VCSnonideal solver failed."); } if (nAttempts < 2) { if (loglevel > 0) { addLogEntry("Trying single phase ChemEquil solver."); } solver = -1; } else { if (loglevel > 0) { endLogGroup("equilibrate"); } throw err; } } } else if (solver == 1) { try { MultiPhase m; m.addPhase(&s, 1.0); m.init(); nAttempts++; equilibrate(m, XY, rtol, maxsteps, maxiter, loglevel-1); redo = false; if (loglevel > 0) { addLogEntry("MultiPhaseEquil solver succeeded."); } retn = nAttempts; } catch (CanteraError& err) { err.save(); if (loglevel > 0) { addLogEntry("MultiPhaseEquil solver failed."); } if (nAttempts < 2) { if (loglevel > 0) { addLogEntry("Trying single phase ChemEquil solver."); } solver = -1; } else { if (loglevel > 0) { endLogGroup("equilibrate"); } throw err; } } } else { // solver <= 0 /* * Call the element potential solver */ try { ChemEquil e; e.options.maxIterations = maxsteps; e.options.relTolerance = rtol; nAttempts++; bool useThermoPhaseElementPotentials = true; retnSub = e.equilibrate(s, XY, useThermoPhaseElementPotentials, loglevel-1); if (retnSub < 0) { if (loglevel > 0) { addLogEntry("ChemEquil solver failed."); } if (nAttempts < 2) { if (loglevel > 0) { addLogEntry("Trying MultiPhaseEquil solver."); } solver = 1; } else { throw CanteraError("equilibrate", "Both equilibrium solvers failed"); } } retn = nAttempts; s.setElementPotentials(e.elementPotentials()); redo = false; if (loglevel > 0) { addLogEntry("ChemEquil solver succeeded."); } } catch (CanteraError& err) { err.save(); if (loglevel > 0) { addLogEntry("ChemEquil solver failed."); } // If ChemEquil fails, try the MultiPhase solver if (solver < 0) { if (loglevel > 0) { addLogEntry("Trying MultiPhaseEquil solver."); } solver = 1; } else { redo = false; if (loglevel > 0) { endLogGroup("equilibrate"); } throw err; } } } } // while (redo) /* * We are here only for a success */ if (loglevel > 0) { endLogGroup("equilibrate"); } return retn; }