Cantera  2.4.0
vcs_rxnadj.cpp
Go to the documentation of this file.
1 /**
2  * @file vcs_rxnadj.cpp
3  * Routines for carrying out various adjustments to the reaction steps
4  */
5 
6 // This file is part of Cantera. See License.txt in the top-level directory or
7 // at http://www.cantera.org/license.txt for license and copyright information.
8 
12 
13 #include <cstdio>
14 
15 namespace Cantera
16 {
17 
18 size_t VCS_SOLVE::vcs_RxnStepSizes(int& forceComponentCalc, size_t& kSpecial)
19 {
20  size_t iphDel = npos;
21  size_t k = 0;
22  std::string ANOTE;
23  if (m_debug_print_lvl >= 2) {
24  plogf(" ");
25  for (int j = 0; j < 82; j++) {
26  plogf("-");
27  }
28  plogf("\n");
29  plogf(" --- Subroutine vcs_RxnStepSizes called - Details:\n");
30  plogf(" ");
31  for (int j = 0; j < 82; j++) {
32  plogf("-");
33  }
34  plogf("\n");
35  plogf(" --- Species KMoles Rxn_Adjustment DeltaG"
36  " | Comment\n");
37  }
38 
39  // We update the matrix dlnActCoeffdmolNumber[][] at the top of the loop,
40  // when necessary
41  if (m_useActCoeffJac) {
43  }
44 
45  // LOOP OVER THE FORMATION REACTIONS
46  for (size_t irxn = 0; irxn < m_numRxnRdc; ++irxn) {
47  ANOTE = "Normal Calc";
48 
49  size_t kspec = m_indexRxnToSpecies[irxn];
51  m_deltaMolNumSpecies[kspec] = 0.0;
52  ANOTE = "ZeroedPhase: Phase is artificially zeroed";
54  if (m_molNumSpecies_old[kspec] == 0.0 && (!m_SSPhase[kspec])) {
55  // MULTISPECIES PHASE WITH total moles equal to zero
56  //
57  // If dg[irxn] is negative, then the multispecies phase should
58  // come alive again. Add a small positive step size to make it
59  // come alive.
60  if (m_deltaGRxn_new[irxn] < -1.0e-4) {
61  // First decide if this species is part of a multiphase that
62  // is nontrivial in size.
63  size_t iph = m_phaseID[kspec];
64  double tphmoles = m_tPhaseMoles_old[iph];
65  double trphmoles = tphmoles / m_totalMolNum;
66  vcs_VolPhase* Vphase = m_VolPhaseList[iph].get();
67  if (Vphase->exists() && (trphmoles > VCS_DELETE_PHASE_CUTOFF)) {
70  m_deltaMolNumSpecies[kspec] = 0.0;
71  ANOTE = fmt::sprintf("MultSpec (%s): Species not born due to STOICH/PHASEPOP even though DG = %11.3E",
73  } else {
75  ANOTE = fmt::sprintf("MultSpec (%s): small species born again DG = %11.3E",
77  }
78  } else {
79  ANOTE = fmt::sprintf("MultSpec (%s):still dead, no phase pop, even though DG = %11.3E",
81  m_deltaMolNumSpecies[kspec] = 0.0;
82  if (Vphase->exists() > 0 && trphmoles > 0.0) {
84  ANOTE = fmt::sprintf("MultSpec (%s): birthed species because it was zero in a small existing phase with DG = %11.3E",
86  }
87  }
88  } else {
89  ANOTE = fmt::sprintf("MultSpec (%s): still dead DG = %11.3E",
91  m_deltaMolNumSpecies[kspec] = 0.0;
92  }
93  } else {
94  // REGULAR PROCESSING
95  //
96  // First take care of cases where we want to bail out. Don't
97  // bother if superconvergence has already been achieved in this
98  // mode.
99  if (fabs(m_deltaGRxn_new[irxn]) <= m_tolmaj2) {
100  ANOTE = fmt::sprintf("Skipped: superconverged DG = %11.3E", m_deltaGRxn_new[irxn]);
101  if (m_debug_print_lvl >= 2) {
102  plogf(" --- %-12.12s", m_speciesName[kspec]);
103  plogf(" %12.4E %12.4E %12.4E | %s\n",
105  m_deltaGRxn_new[irxn], ANOTE);
106  }
107  continue;
108  }
109 
110  // Don't calculate for minor or nonexistent species if their
111  // values are to be decreasing anyway.
112  if ((m_speciesStatus[kspec] != VCS_SPECIES_MAJOR) && (m_deltaGRxn_new[irxn] >= 0.0)) {
113  ANOTE = fmt::sprintf("Skipped: IC = %3d and DG >0: %11.3E",
114  m_speciesStatus[kspec], m_deltaGRxn_new[irxn]);
115  if (m_debug_print_lvl >= 2) {
116  plogf(" --- %-12.12s", m_speciesName[kspec]);
117  plogf(" %12.4E %12.4E %12.4E | %s\n",
119  m_deltaGRxn_new[irxn], ANOTE);
120  }
121  continue;
122  }
123 
124  // Start of the regular processing
125  double s;
126  if (m_SSPhase[kspec]) {
127  s = 0.0;
128  } else {
129  s = 1.0 / m_molNumSpecies_old[kspec];
130  }
131  for (size_t j = 0; j < m_numComponents; ++j) {
132  if (!m_SSPhase[j] && m_molNumSpecies_old[j] > 0.0) {
133  s += pow(m_stoichCoeffRxnMatrix(j,irxn), 2) / m_molNumSpecies_old[j];
134  }
135  }
136  for (size_t j = 0; j < m_numPhases; j++) {
137  vcs_VolPhase* Vphase = m_VolPhaseList[j].get();
138  if (!Vphase->m_singleSpecies && m_tPhaseMoles_old[j] > 0.0) {
139  s -= pow(m_deltaMolNumPhase(j,irxn), 2) / m_tPhaseMoles_old[j];
140  }
141  }
142  if (s != 0.0) {
143  // Take into account of the derivatives of the activity
144  // coefficients with respect to the mole numbers, even in
145  // our diagonal approximation.
146  if (m_useActCoeffJac) {
147  double s_old = s;
148  s = vcs_Hessian_diag_adj(irxn, s_old);
149  ANOTE = fmt::sprintf("Normal calc: diag adjusted from %g "
150  "to %g due to act coeff", s_old, s);
151  }
152 
153  m_deltaMolNumSpecies[kspec] = -m_deltaGRxn_new[irxn] / s;
154  // New section to do damping of the m_deltaMolNumSpecies[]
155  for (size_t j = 0; j < m_numComponents; ++j) {
156  double stoicC = m_stoichCoeffRxnMatrix(j,irxn);
157  if (stoicC != 0.0) {
158  double negChangeComp = -stoicC * m_deltaMolNumSpecies[kspec];
159  if (negChangeComp > m_molNumSpecies_old[j]) {
160  if (m_molNumSpecies_old[j] > 0.0) {
161  ANOTE = fmt::sprintf("Delta damped from %g "
162  "to %g due to component %d (%10s) going neg", m_deltaMolNumSpecies[kspec],
163  -m_molNumSpecies_old[j] / stoicC, j, m_speciesName[j]);
164  m_deltaMolNumSpecies[kspec] = -m_molNumSpecies_old[j] / stoicC;
165  } else {
166  ANOTE = fmt::sprintf("Delta damped from %g "
167  "to %g due to component %d (%10s) zero", m_deltaMolNumSpecies[kspec],
168  -m_molNumSpecies_old[j] / stoicC, j, m_speciesName[j]);
169  m_deltaMolNumSpecies[kspec] = 0.0;
170  }
171  }
172  }
173  }
174  // Implement a damping term that limits m_deltaMolNumSpecies
175  // to the size of the mole number
176  if (-m_deltaMolNumSpecies[kspec] > m_molNumSpecies_old[kspec]) {
177  ANOTE = fmt::sprintf("Delta damped from %g "
178  "to %g due to %s going negative", m_deltaMolNumSpecies[kspec], -m_molNumSpecies_old[kspec],
179  m_speciesName[kspec]);
180  m_deltaMolNumSpecies[kspec] = -m_molNumSpecies_old[kspec];
181  }
182  } else {
183  // REACTION IS ENTIRELY AMONGST SINGLE SPECIES PHASES.
184  // DELETE ONE OF THE PHASES AND RECOMPUTE BASIS.
185  //
186  // Either the species L will disappear or one of the
187  // component single species phases will disappear. The sign
188  // of DG(I) will indicate which way the reaction will go.
189  // Then, we need to follow the reaction to see which species
190  // will zero out first. The species to be zeroed out will be
191  // "k".
192  double dss;
193  if (m_deltaGRxn_new[irxn] > 0.0) {
194  dss = m_molNumSpecies_old[kspec];
195  k = kspec;
196  for (size_t j = 0; j < m_numComponents; ++j) {
197  if (m_stoichCoeffRxnMatrix(j,irxn) > 0.0) {
198  double xx = m_molNumSpecies_old[j] / m_stoichCoeffRxnMatrix(j,irxn);
199  if (xx < dss) {
200  dss = xx;
201  k = j;
202  }
203  }
204  }
205  dss = -dss;
206  } else {
207  dss = 1.0e10;
208  for (size_t j = 0; j < m_numComponents; ++j) {
209  if (m_stoichCoeffRxnMatrix(j,irxn) < 0.0) {
210  double xx = -m_molNumSpecies_old[j] / m_stoichCoeffRxnMatrix(j,irxn);
211  if (xx < dss) {
212  dss = xx;
213  k = j;
214  }
215  }
216  }
217  }
218 
219  // Here we adjust the mole fractions according to DSS and
220  // the stoichiometric array to take into account that we are
221  // eliminating the kth species. DSS contains the amount of
222  // moles of the kth species that needs to be added back into
223  // the component species.
224  if (dss != 0.0) {
225  if ((k == kspec) && (m_SSPhase[kspec] != 1)) {
226  // Found out that we can be in this spot, when
227  // components of multispecies phases are zeroed,
228  // leaving noncomponent species of the same phase
229  // having all of the mole numbers of that phases. it
230  // seems that we can suggest a zero of the species
231  // and the code will recover.
232  ANOTE = fmt::sprintf("Delta damped from %g to %g due to delete %s", m_deltaMolNumSpecies[kspec],
233  -m_molNumSpecies_old[kspec], m_speciesName[kspec]);
234  m_deltaMolNumSpecies[kspec] = -m_molNumSpecies_old[kspec];
235  if (m_debug_print_lvl >= 2) {
236  plogf(" --- %-12.12s", m_speciesName[kspec]);
237  plogf(" %12.4E %12.4E %12.4E | %s\n",
239  m_deltaGRxn_new[irxn], ANOTE);
240  }
241  continue;
242  }
243 
244  // Delete the single species phase
245  for (size_t j = 0; j < m_nsp; j++) {
246  m_deltaMolNumSpecies[j] = 0.0;
247  }
248  m_deltaMolNumSpecies[kspec] = dss;
249  for (size_t j = 0; j < m_numComponents; ++j) {
250  m_deltaMolNumSpecies[j] = dss * m_stoichCoeffRxnMatrix(j,irxn);
251  }
252 
253  iphDel = m_phaseID[k];
254  kSpecial = k;
255 
256  if (k != kspec) {
257  ANOTE = fmt::sprintf("Delete component SS phase %d named %s - SS phases only",
258  iphDel, m_speciesName[k]);
259  } else {
260  ANOTE = fmt::sprintf("Delete this SS phase %d - SS components only", iphDel);
261  }
262  if (m_debug_print_lvl >= 2) {
263  plogf(" --- %-12.12s", m_speciesName[kspec]);
264  plogf(" %12.4E %12.4E %12.4E | %s\n",
266  m_deltaGRxn_new[irxn], ANOTE);
267  plogf(" --- vcs_RxnStepSizes Special section to set up to delete %s\n",
268  m_speciesName[k]);
269  }
270  if (k != kspec) {
271  forceComponentCalc = 1;
272  debuglog(" --- Force a component recalculation\n\n", m_debug_print_lvl >= 2);
273  }
274  if (m_debug_print_lvl >= 2) {
275  plogf(" ");
276  writeline('-', 82);
277  }
278  return iphDel;
279  }
280  }
281  } // End of regular processing
282  if (m_debug_print_lvl >= 2) {
283  plogf(" --- %-12.12s", m_speciesName[kspec]);
284  plogf(" %12.4E %12.4E %12.4E | %s\n",
286  m_deltaGRxn_new[irxn], ANOTE);
287  }
288  } // End of loop over m_speciesUnknownType
289  } // End of loop over non-component stoichiometric formation reactions
290  if (m_debug_print_lvl >= 2) {
291  plogf(" ");
292  writeline('-', 82);
293  }
294  return iphDel;
295 }
296 
297 double VCS_SOLVE::vcs_Hessian_diag_adj(size_t irxn, double hessianDiag_Ideal)
298 {
299  double diag = hessianDiag_Ideal;
300  double hessActCoef = vcs_Hessian_actCoeff_diag(irxn);
301  if (hessianDiag_Ideal <= 0.0) {
302  throw CanteraError("VCS_SOLVE::vcs_Hessian_diag_adj",
303  "We shouldn't be here");
304  }
305  if (hessActCoef >= 0.0) {
306  diag += hessActCoef;
307  } else if (fabs(hessActCoef) < 0.6666 * hessianDiag_Ideal) {
308  diag += hessActCoef;
309  } else {
310  diag -= 0.6666 * hessianDiag_Ideal;
311  }
312  return diag;
313 }
314 
316 {
317  size_t kspec = m_indexRxnToSpecies[irxn];
318  size_t kph = m_phaseID[kspec];
319  double np_kspec = std::max(m_tPhaseMoles_old[kph], 1e-13);
320  double* sc_irxn = m_stoichCoeffRxnMatrix.ptrColumn(irxn);
321 
322  // First the diagonal term of the Jacobian
323  double s = m_np_dLnActCoeffdMolNum(kspec,kspec) / np_kspec;
324 
325  // Next, the other terms. Note this only a loop over the components So, it's
326  // not too expensive to calculate.
327  for (size_t j = 0; j < m_numComponents; j++) {
328  if (!m_SSPhase[j]) {
329  for (size_t k = 0; k < m_numComponents; ++k) {
330  if (m_phaseID[k] == m_phaseID[j]) {
331  double np = m_tPhaseMoles_old[m_phaseID[k]];
332  if (np > 0.0) {
333  s += sc_irxn[k] * sc_irxn[j] * m_np_dLnActCoeffdMolNum(j,k) / np;
334  }
335  }
336  }
337  if (kph == m_phaseID[j]) {
338  s += sc_irxn[j] * (m_np_dLnActCoeffdMolNum(j,kspec) + m_np_dLnActCoeffdMolNum(kspec,j)) / np_kspec;
339  }
340  }
341  }
342  return s;
343 }
344 
345 void VCS_SOLVE::vcs_CalcLnActCoeffJac(const double* const moleSpeciesVCS)
346 {
347  // Loop over all of the phases in the problem
348  for (size_t iphase = 0; iphase < m_numPhases; iphase++) {
349  vcs_VolPhase* Vphase = m_VolPhaseList[iphase].get();
350 
351  // We don't need to call single species phases;
352  if (!Vphase->m_singleSpecies && !Vphase->isIdealSoln()) {
353  // update the mole numbers
354  Vphase->setMolesFromVCS(VCS_STATECALC_OLD, moleSpeciesVCS);
355 
356  // Download the resulting calculation into the full vector. This
357  // scatter calculation is carried out in the vcs_VolPhase object.
358  Vphase->sendToVCS_LnActCoeffJac(m_np_dLnActCoeffdMolNum);
359  }
360  }
361 }
362 
363 }
size_t vcs_RxnStepSizes(int &forceComponentCalc, size_t &kSpecial)
Calculates formation reaction step sizes.
Definition: vcs_rxnadj.cpp:18
bool isIdealSoln() const
Returns whether the phase is an ideal solution phase.
std::vector< size_t > m_phaseID
Mapping from the species number to the phase number.
Definition: vcs_solve.h:1357
double vcs_Hessian_actCoeff_diag(size_t irxn)
Calculates the diagonal contribution to the Hessian due to the dependence of the activity coefficient...
Definition: vcs_rxnadj.cpp:315
vector_int m_speciesUnknownType
Specifies the species unknown type.
Definition: vcs_solve.h:1165
double m_totalMolNum
Total number of kmoles in all phases.
Definition: vcs_solve.h:1238
bool m_singleSpecies
If true, this phase consists of a single species.
Definition: vcs_VolPhase.h:541
vector_fp m_molNumSpecies_old
Total moles of the species.
Definition: vcs_solve.h:1152
double vcs_Hessian_diag_adj(size_t irxn, double hessianDiag_Ideal)
Calculates the diagonal contribution to the Hessian due to the dependence of the activity coefficient...
Definition: vcs_rxnadj.cpp:297
Array2D m_stoichCoeffRxnMatrix
Stoichiometric coefficient matrix for the reaction mechanism expressed in Reduced Canonical Form...
Definition: vcs_solve.h:1095
int m_useActCoeffJac
Choice of Hessians.
Definition: vcs_solve.h:1468
const size_t npos
index returned by functions to indicate "no position"
Definition: ct_defs.h:165
vector_fp m_deltaMolNumSpecies
Reaction Adjustments for each species during the current step.
Definition: vcs_solve.h:1213
doublereal * ptrColumn(size_t j)
Return a pointer to the top of column j, columns are contiguous in memory.
Definition: Array.h:292
std::vector< std::unique_ptr< vcs_VolPhase > > m_VolPhaseList
Array of Phase Structures. Length = number of phases.
Definition: vcs_solve.h:1394
size_t m_numRxnRdc
Current number of non-component species in the problem.
Definition: vcs_solve.h:1061
#define VCS_SMALL_MULTIPHASE_SPECIES
Relative value of multiphase species mole number for a multiphase species which is small...
Definition: vcs_defs.h:50
vector_fp m_deltaGRxn_new
Delta G(irxn) for the noncomponent species in the mechanism.
Definition: vcs_solve.h:1193
void setMolesFromVCS(const int stateCalc, const double *molesSpeciesVCS=0)
Set the moles within the phase.
Header file for the internal object that holds the vcs equilibrium problem (see Class VCS_SOLVE and E...
Header for the object representing each phase within vcs.
#define VCS_SPECIES_ZEROEDPHASE
Species lies in a multicomponent phase that is zeroed atm.
Definition: vcs_defs.h:153
#define VCS_DELETE_PHASE_CUTOFF
Cutoff relative moles below which a phase is deleted from the equilibrium problem.
Definition: vcs_defs.h:56
Base class for exceptions thrown by Cantera classes.
Definition: ctexceptions.h:65
int m_debug_print_lvl
Debug printing lvl.
Definition: vcs_solve.h:1498
#define VCS_SPECIES_MAJOR
Species is a major species.
Definition: vcs_defs.h:102
size_t m_numComponents
Number of components calculated for the problem.
Definition: vcs_solve.h:1050
#define VCS_SPECIES_STOICHZERO
Species lies in a multicomponent phase that is active, but species concentration is zero due to stoic...
Definition: vcs_defs.h:175
void debuglog(const std::string &msg, int loglevel)
Write a message to the log only if loglevel > 0.
Definition: global.h:135
std::vector< char > m_SSPhase
Boolean indicating whether a species belongs to a single-species phase.
Definition: vcs_solve.h:1361
Phase information and Phase calculations for vcs.
Definition: vcs_VolPhase.h:81
vector_fp m_tPhaseMoles_old
Total kmols of species in each phase.
Definition: vcs_solve.h:1246
std::vector< std::string > m_speciesName
Species string name for the kth species.
Definition: vcs_solve.h:1364
#define VCS_STATECALC_OLD
State Calculation based on the old or base mole numbers.
Definition: vcs_defs.h:300
Array2D m_deltaMolNumPhase
Change in the number of moles of phase, iphase, due to the noncomponent formation reaction...
Definition: vcs_solve.h:1172
int exists() const
int indicating whether the phase exists or not
size_t m_nsp
Total number of species in the problems.
Definition: vcs_solve.h:1044
vector_int m_speciesStatus
Major -Minor status vector for the species in the problem.
Definition: vcs_solve.h:1354
const char * vcs_speciesType_string(int speciesStatus, int length)
Returns a const char string representing the type of the species given by the first argument...
Definition: vcs_util.cpp:33
#define plogf
define this Cantera function to replace printf
Definition: vcs_internal.h:18
#define VCS_SPECIES_TYPE_INTERFACIALVOLTAGE
Unknown refers to the voltage level of a phase.
Definition: vcs_defs.h:289
Namespace for the Cantera kernel.
Definition: AnyMap.cpp:8
std::vector< size_t > m_indexRxnToSpecies
Mapping between the species index for noncomponent species and the full species index.
Definition: vcs_solve.h:1346
size_t m_numPhases
Number of Phases in the problem.
Definition: vcs_solve.h:1068
double m_tolmaj2
Below this, major species aren&#39;t refined any more.
Definition: vcs_solve.h:1289
Array2D m_np_dLnActCoeffdMolNum
Change in the log of the activity coefficient with respect to the mole number multiplied by the phase...
Definition: vcs_solve.h:1440
Definitions for the classes that are thrown when Cantera experiences an error condition (also contain...
void vcs_CalcLnActCoeffJac(const double *const moleSpeciesVCS)
Recalculate all of the activity coefficients in all of the phases based on input mole numbers...
Definition: vcs_rxnadj.cpp:345