Cantera  2.5.1
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 https://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 }
doublereal * ptrColumn(size_t j)
Return a pointer to the top of column j, columns are contiguous in memory.
Definition: Array.h:292
Base class for exceptions thrown by Cantera classes.
Definition: ctexceptions.h:61
size_t m_numPhases
Number of Phases in the problem.
Definition: vcs_solve.h:1068
double m_tolmaj2
Below this, major species aren't refined any more.
Definition: vcs_solve.h:1289
std::vector< std::string > m_speciesName
Species string name for the kth species.
Definition: vcs_solve.h:1364
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
int m_useActCoeffJac
Choice of Hessians.
Definition: vcs_solve.h:1468
vector_int m_speciesStatus
Major -Minor status vector for the species in the problem.
Definition: vcs_solve.h:1354
vector_fp m_molNumSpecies_old
Total moles of the species.
Definition: vcs_solve.h:1152
vector_int m_speciesUnknownType
Specifies the species unknown type.
Definition: vcs_solve.h:1165
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
vector_fp m_tPhaseMoles_old
Total kmols of species in each phase.
Definition: vcs_solve.h:1246
int m_debug_print_lvl
Debug printing lvl.
Definition: vcs_solve.h:1498
std::vector< size_t > m_phaseID
Mapping from the species number to the phase number.
Definition: vcs_solve.h:1357
std::vector< size_t > m_indexRxnToSpecies
Mapping between the species index for noncomponent species and the full species index.
Definition: vcs_solve.h:1346
Array2D m_stoichCoeffRxnMatrix
Stoichiometric coefficient matrix for the reaction mechanism expressed in Reduced Canonical Form.
Definition: vcs_solve.h:1095
size_t m_numRxnRdc
Current number of non-component species in the problem.
Definition: vcs_solve.h:1061
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
size_t m_numComponents
Number of components calculated for the problem.
Definition: vcs_solve.h:1050
std::vector< char > m_SSPhase
Boolean indicating whether a species belongs to a single-species phase.
Definition: vcs_solve.h:1361
size_t m_nsp
Total number of species in the problems.
Definition: vcs_solve.h:1044
std::vector< std::unique_ptr< vcs_VolPhase > > m_VolPhaseList
Array of Phase Structures. Length = number of phases.
Definition: vcs_solve.h:1394
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
size_t vcs_RxnStepSizes(int &forceComponentCalc, size_t &kSpecial)
Calculates formation reaction step sizes.
Definition: vcs_rxnadj.cpp:18
vector_fp m_deltaMolNumSpecies
Reaction Adjustments for each species during the current step.
Definition: vcs_solve.h:1213
Array2D m_deltaMolNumPhase
Change in the number of moles of phase, iphase, due to the noncomponent formation reaction,...
Definition: vcs_solve.h:1172
vector_fp m_deltaGRxn_new
Delta G(irxn) for the noncomponent species in the mechanism.
Definition: vcs_solve.h:1193
double m_totalMolNum
Total number of kmoles in all phases.
Definition: vcs_solve.h:1238
Phase information and Phase calculations for vcs.
Definition: vcs_VolPhase.h:82
bool m_singleSpecies
If true, this phase consists of a single species.
Definition: vcs_VolPhase.h:541
void setMolesFromVCS(const int stateCalc, const double *molesSpeciesVCS=0)
Set the moles within the phase.
int exists() const
int indicating whether the phase exists or not
bool isIdealSoln() const
Returns whether the phase is an ideal solution phase.
Definitions for the classes that are thrown when Cantera experiences an error condition (also contain...
void debuglog(const std::string &msg, int loglevel)
Write a message to the log only if loglevel > 0.
Definition: global.h:140
const size_t npos
index returned by functions to indicate "no position"
Definition: ct_defs.h:188
Namespace for the Cantera kernel.
Definition: AnyMap.cpp:264
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
Header for the object representing each phase within vcs.
#define VCS_SPECIES_TYPE_INTERFACIALVOLTAGE
Unknown refers to the voltage level of a phase.
Definition: vcs_defs.h:289
#define VCS_STATECALC_OLD
State Calculation based on the old or base mole numbers.
Definition: vcs_defs.h:300
#define VCS_SPECIES_MAJOR
Species is a major species.
Definition: vcs_defs.h:102
#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
#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
#define VCS_SMALL_MULTIPHASE_SPECIES
Relative value of multiphase species mole number for a multiphase species which is small.
Definition: vcs_defs.h:50
#define plogf
define this Cantera function to replace printf
Definition: vcs_internal.h:18
Header file for the internal object that holds the vcs equilibrium problem (see Class VCS_SOLVE and E...