Cantera  2.2.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
vcs_solve.cpp
Go to the documentation of this file.
1 /*!
2  * @file vcs_solve.cpp Implementation file for the internal class that holds
3  * the problem.
4  */
5 /*
6  * Copyright (2005) Sandia Corporation. Under the terms of
7  * Contract DE-AC04-94AL85000 with Sandia Corporation, the
8  * U.S. Government retains certain rights in this software.
9  */
10 
14 #include "cantera/equil/vcs_prob.h"
15 
18 
19 #include "cantera/base/clockWC.h"
20 
21 using namespace std;
22 
23 namespace Cantera
24 {
25 
27 
28 VCS_SOLVE::VCS_SOLVE() :
29  NSPECIES0(0),
30  NPHASE0(0),
31  m_numSpeciesTot(0),
32  m_numElemConstraints(0),
33  m_numComponents(0),
34  m_numRxnTot(0),
35  m_numSpeciesRdc(0),
36  m_numRxnRdc(0),
37  m_numRxnMinorZeroed(0),
38  m_numPhases(0),
39  m_doEstimateEquil(0),
40  m_totalMolNum(0.0),
41  m_temperature(0.0),
42  m_pressurePA(0.0),
43  m_tolmaj(0.0),
44  m_tolmin(0.0),
45  m_tolmaj2(0.0),
46  m_tolmin2(0.0),
47  m_unitsState(VCS_DIMENSIONAL_G),
48  m_totalMoleScale(1.0),
49  m_useActCoeffJac(0),
50  m_totalVol(0.0),
51  m_Faraday_dim(ElectronCharge * Avogadro),
52  m_VCount(0),
53  m_debug_print_lvl(0),
54  m_timing_print_lvl(1),
55  m_VCS_UnitsFormat(VCS_UNITS_UNITLESS)
56 {
57 }
58 
59 void VCS_SOLVE::vcs_initSizes(const size_t nspecies0, const size_t nelements,
60  const size_t nphase0)
61 {
62  if (NSPECIES0 != 0) {
63  if ((nspecies0 != NSPECIES0) || (nelements != m_numElemConstraints) || (nphase0 != NPHASE0)) {
64  vcs_delete_memory();
65  } else {
66  return;
67  }
68  }
69 
70  NSPECIES0 = nspecies0;
71  NPHASE0 = nphase0;
72  m_numSpeciesTot = nspecies0;
73  m_numElemConstraints = nelements;
74  m_numComponents = nelements;
75 
76  string ser = "VCS_SOLVE: ERROR:\n\t";
77  if (nspecies0 <= 0) {
78  plogf("%s Number of species is nonpositive\n", ser.c_str());
79  throw CanteraError("VCS_SOLVE()", ser +
80  " Number of species is nonpositive\n");
81  }
82  if (nelements <= 0) {
83  plogf("%s Number of elements is nonpositive\n", ser.c_str());
84  throw CanteraError("VCS_SOLVE()", ser +
85  " Number of species is nonpositive\n");
86  }
87  if (nphase0 <= 0) {
88  plogf("%s Number of phases is nonpositive\n", ser.c_str());
89  throw CanteraError("VCS_SOLVE()", ser +
90  " Number of species is nonpositive\n");
91  }
92 
93  m_VCS_UnitsFormat = VCS_UNITS_UNITLESS;
94 
95  /*
96  * We will initialize sc[] to note the fact that it needs to be
97  * filled with meaningful information.
98  */
99  m_stoichCoeffRxnMatrix.resize(nelements, nspecies0, 0.0);
100 
101  m_scSize.resize(nspecies0, 0.0);
102  m_spSize.resize(nspecies0, 1.0);
103 
104  m_SSfeSpecies.resize(nspecies0, 0.0);
105  m_feSpecies_new.resize(nspecies0, 0.0);
106  m_molNumSpecies_old.resize(nspecies0, 0.0);
107 
108  m_speciesUnknownType.resize(nspecies0, VCS_SPECIES_TYPE_MOLNUM);
109 
110  m_deltaMolNumPhase.resize(nphase0, nspecies0, 0.0);
111  m_phaseParticipation.resize(nphase0, nspecies0, 0);
112  m_phasePhi.resize(nphase0, 0.0);
113 
114  m_molNumSpecies_new.resize(nspecies0, 0.0);
115 
116  m_deltaGRxn_new.resize(nspecies0, 0.0);
117  m_deltaGRxn_old.resize(nspecies0, 0.0);
118  m_deltaGRxn_Deficient.resize(nspecies0, 0.0);
119  m_deltaGRxn_tmp.resize(nspecies0, 0.0);
120  m_deltaMolNumSpecies.resize(nspecies0, 0.0);
121 
122  m_feSpecies_old.resize(nspecies0, 0.0);
123  m_elemAbundances.resize(nelements, 0.0);
124  m_elemAbundancesGoal.resize(nelements, 0.0);
125 
126  m_tPhaseMoles_old.resize(nphase0, 0.0);
127  m_tPhaseMoles_new.resize(nphase0, 0.0);
128  m_deltaPhaseMoles.resize(nphase0, 0.0);
129  m_TmpPhase.resize(nphase0, 0.0);
130  m_TmpPhase2.resize(nphase0, 0.0);
131 
132  m_formulaMatrix.resize(nspecies0, nelements);
133 
134  TPhInertMoles.resize(nphase0, 0.0);
135 
136  /*
137  * ind[] is an index variable that keep track of solution vector
138  * rotations.
139  */
140  m_speciesMapIndex.resize(nspecies0, 0);
141  m_speciesLocalPhaseIndex.resize(nspecies0, 0);
142  /*
143  * IndEl[] is an index variable that keep track of element vector
144  * rotations.
145  */
146  m_elementMapIndex.resize(nelements, 0);
147 
148  /*
149  * ir[] is an index vector that keeps track of the irxn to species
150  * mapping. We can't fill it in until we know the number of c
151  * components in the problem
152  */
153  m_indexRxnToSpecies.resize(nspecies0, 0);
154 
155  /* Initialize all species to be major species */
156  //m_rxnStatus.resize(nspecies0, 1);
157  m_speciesStatus.resize(nspecies0, 1);
158 
159  m_SSPhase.resize(2*nspecies0, 0);
160  m_phaseID.resize(nspecies0, 0);
161 
162  m_numElemConstraints = nelements;
163 
164  m_elementName.resize(nelements, std::string(""));
165  m_speciesName.resize(nspecies0, std::string(""));
166 
167  m_elType.resize(nelements, VCS_ELEM_TYPE_ABSPOS);
168 
169  m_elementActive.resize(nelements, 1);
170  /*
171  * Malloc space for activity coefficients for all species
172  * -> Set it equal to one.
173  */
174  m_actConventionSpecies.resize(nspecies0, 0);
175  m_phaseActConvention.resize(nphase0, 0);
176  m_lnMnaughtSpecies.resize(nspecies0, 0.0);
177  m_actCoeffSpecies_new.resize(nspecies0, 1.0);
178  m_actCoeffSpecies_old.resize(nspecies0, 1.0);
179  m_wtSpecies.resize(nspecies0, 0.0);
180  m_chargeSpecies.resize(nspecies0, 0.0);
181  m_speciesThermoList.resize(nspecies0, (VCS_SPECIES_THERMO*)0);
182 
183  /*
184  * Malloc Phase Info
185  */
186  m_VolPhaseList.resize(nphase0, 0);
187  for (size_t iph = 0; iph < nphase0; iph++) {
188  m_VolPhaseList[iph] = new vcs_VolPhase(this);
189  }
190 
191  /*
192  * For Future expansion
193  */
194  m_useActCoeffJac = true;
195  if (m_useActCoeffJac) {
196  m_np_dLnActCoeffdMolNum.resize(nspecies0, nspecies0, 0.0);
197  }
198 
199  m_PMVolumeSpecies.resize(nspecies0, 0.0);
200 
201  /*
202  * Malloc space for counters kept within vcs
203  *
204  */
205  m_VCount = new VCS_COUNTERS();
206  vcs_counters_init(1);
207 
208  if (vcs_timing_print_lvl == 0) {
209  m_timing_print_lvl = 0;
210  }
211 
212  return;
213 
214 }
215 
216 VCS_SOLVE::~VCS_SOLVE()
217 {
218  vcs_delete_memory();
219 }
220 
221 void VCS_SOLVE::vcs_delete_memory()
222 {
223  size_t nspecies = m_numSpeciesTot;
224 
225  for (size_t j = 0; j < m_numPhases; j++) {
226  delete m_VolPhaseList[j];
227  m_VolPhaseList[j] = 0;
228  }
229 
230  for (size_t j = 0; j < nspecies; j++) {
231  delete m_speciesThermoList[j];
232  m_speciesThermoList[j] = 0;
233  }
234 
235  delete m_VCount;
236  m_VCount = 0;
237 
238  NSPECIES0 = 0;
239  NPHASE0 = 0;
240  m_numElemConstraints = 0;
241  m_numComponents = 0;
242 }
243 
244 int VCS_SOLVE::vcs(VCS_PROB* vprob, int ifunc, int ipr, int ip1, int maxit)
245 {
246  int retn = 0, iconv = 0;
247  clockWC tickTock;
248 
249  int iprintTime = std::max(ipr, ip1);
250  iprintTime = std::min(iprintTime, m_timing_print_lvl);
251 
252  if (ifunc > 2) {
253  plogf("vcs: Unrecognized value of ifunc, %d: bailing!\n",
254  ifunc);
255  return VCS_PUB_BAD;
256  }
257 
258  if (ifunc == 0) {
259  /*
260  * This function is called to create the private data
261  * using the public data.
262  */
263  size_t nspecies0 = vprob->nspecies + 10;
264  size_t nelements0 = vprob->ne;
265  size_t nphase0 = vprob->NPhase;
266 
267  vcs_initSizes(nspecies0, nelements0, nphase0);
268 
269  if (retn != 0) {
270  plogf("vcs_priv_alloc returned a bad status, %d: bailing!\n",
271  retn);
272  return retn;
273  }
274  /*
275  * This function is called to copy the public data
276  * and the current problem specification
277  * into the current object's data structure.
278  */
279  retn = vcs_prob_specifyFully(vprob);
280  if (retn != 0) {
281  plogf("vcs_pub_to_priv returned a bad status, %d: bailing!\n",
282  retn);
283  return retn;
284  }
285  /*
286  * Prep the problem data
287  * - adjust the identity of any phases
288  * - determine the number of components in the problem
289  */
290  retn = vcs_prep_oneTime(ip1);
291  if (retn != 0) {
292  plogf("vcs_prep_oneTime returned a bad status, %d: bailing!\n",
293  retn);
294  return retn;
295  }
296  }
297  if (ifunc == 1) {
298  /*
299  * This function is called to copy the current problem
300  * into the current object's data structure.
301  */
302  retn = vcs_prob_specify(vprob);
303  if (retn != 0) {
304  plogf("vcs_prob_specify returned a bad status, %d: bailing!\n",
305  retn);
306  return retn;
307  }
308  }
309  if (ifunc != 2) {
310  /*
311  * Prep the problem data for this particular instantiation of
312  * the problem
313  */
314  retn = vcs_prep();
315  if (retn != VCS_SUCCESS) {
316  plogf("vcs_prep returned a bad status, %d: bailing!\n", retn);
317  return retn;
318  }
319 
320  /*
321  * Check to see if the current problem is well posed.
322  */
323  if (!vcs_wellPosed(vprob)) {
324  plogf("vcs has determined the problem is not well posed: Bailing\n");
325  return VCS_PUB_BAD;
326  }
327 
328  /*
329  * Once we have defined the global internal data structure defining
330  * the problem, then we go ahead and solve the problem.
331  *
332  * (right now, all we do is solve fixed T, P problems.
333  * Methods for other problem types will go in at this level.
334  * For example, solving for fixed T, V problems will involve
335  * a 2x2 Newton's method, using loops over vcs_TP() to
336  * calculate the residual and Jacobian)
337  */
338  iconv = vcs_TP(ipr, ip1, maxit, vprob->T, vprob->PresPA);
339 
340  /*
341  * If requested to print anything out, go ahead and do so;
342  */
343  if (ipr > 0) {
344  vcs_report(iconv);
345  }
346  /*
347  * Copy the results of the run back to the VCS_PROB structure,
348  * which is returned to the user.
349  */
350  vcs_prob_update(vprob);
351  }
352 
353  /*
354  * Report on the time if requested to do so
355  */
356  double te = tickTock.secondsWC();
357  m_VCount->T_Time_vcs += te;
358  if (iprintTime > 0) {
359  vcs_TCounters_report(m_timing_print_lvl);
360  }
361  /*
362  * Now, destroy the private data, if requested to do so
363  *
364  * FILL IN
365  */
366 
367  if (iconv < 0) {
368  plogf("ERROR: FAILURE its = %d!\n", m_VCount->Its);
369  } else if (iconv == 1) {
370  plogf("WARNING: RANGE SPACE ERROR encountered\n");
371  }
372  return iconv;
373 }
374 
375 int VCS_SOLVE::vcs_prob_specifyFully(const VCS_PROB* pub)
376 {
377  const char* ser =
378  "vcs_pub_to_priv ERROR :ill defined interface -> bailout:\n\t";
379 
380  /*
381  * First Check to see whether we have room for the current problem
382  * size
383  */
384  size_t nspecies = pub->nspecies;
385  if (NSPECIES0 < nspecies) {
386  plogf("%sPrivate Data is dimensioned too small\n", ser);
387  return VCS_PUB_BAD;
388  }
389  size_t nph = pub->NPhase;
390  if (NPHASE0 < nph) {
391  plogf("%sPrivate Data is dimensioned too small\n", ser);
392  return VCS_PUB_BAD;
393  }
394  size_t nelements = pub->ne;
395  if (m_numElemConstraints < nelements) {
396  plogf("%sPrivate Data is dimensioned too small\n", ser);
397  return VCS_PUB_BAD;
398  }
399 
400  /*
401  * OK, We have room. Now, transfer the integer numbers
402  */
403  m_numElemConstraints = nelements;
404  m_numSpeciesTot = nspecies;
405  m_numSpeciesRdc = m_numSpeciesTot;
406  /*
407  * nc = number of components -> will be determined later.
408  * but set it to its maximum possible value here.
409  */
410  m_numComponents = nelements;
411  /*
412  * m_numRxnTot = number of noncomponents, also equal to the
413  * number of reactions
414  * Note, it's possible that the number of elements is greater than
415  * the number of species. In that case set the number of reactions
416  * to zero.
417  */
418  if (nelements > nspecies) {
419  m_numRxnTot = 0;
420  } else {
421  m_numRxnTot = nspecies - nelements;
422  }
423  m_numRxnRdc = m_numRxnTot;
424  /*
425  * number of minor species rxn -> all species rxn are major at the start.
426  */
427  m_numRxnMinorZeroed = 0;
428  /*
429  * NPhase = number of phases
430  */
431  m_numPhases = nph;
432 
433 #ifdef DEBUG_MODE
434  m_debug_print_lvl = pub->vcs_debug_print_lvl;
435 #else
436  m_debug_print_lvl = std::min(2, pub->vcs_debug_print_lvl);
437 #endif
438 
439  /*
440  * FormulaMatrix[] -> Copy the formula matrix over
441  */
442  for (size_t i = 0; i < nspecies; i++) {
443  bool nonzero = false;
444  for (size_t j = 0; j < nelements; j++) {
445  if (pub->FormulaMatrix(i,j) != 0.0) {
446  nonzero = true;
447  }
448  m_formulaMatrix(i,j) = pub->FormulaMatrix(i,j);
449  }
450  if (!nonzero) {
451  plogf("vcs_prob_specifyFully:: species %d %s has a zero formula matrix!\n", i,
452  pub->SpName[i].c_str());
453  return VCS_PUB_BAD;
454  }
455  }
456 
457  /*
458  * Copy over the species molecular weights
459  */
460  m_wtSpecies = pub->WtSpecies;
461 
462  /*
463  * Copy over the charges
464  */
465  m_chargeSpecies = pub->Charge;
466 
467  /*
468  * Malloc and Copy the VCS_SPECIES_THERMO structures
469  *
470  */
471  for (size_t kspec = 0; kspec < nspecies; kspec++) {
472  delete m_speciesThermoList[kspec];
473  VCS_SPECIES_THERMO* spf = pub->SpeciesThermo[kspec];
474  m_speciesThermoList[kspec] = spf->duplMyselfAsVCS_SPECIES_THERMO();
475  if (m_speciesThermoList[kspec] == NULL) {
476  plogf(" duplMyselfAsVCS_SPECIES_THERMO returned an error!\n");
477  return VCS_PUB_BAD;
478  }
479  }
480 
481  /*
482  * Copy the species unknown type
483  */
484  m_speciesUnknownType = pub->SpeciesUnknownType;
485 
486  /*
487  * iest => Do we have an initial estimate of the species mole numbers ?
488  */
489  m_doEstimateEquil = pub->iest;
490 
491  /*
492  * w[] -> Copy the equilibrium mole number estimate if it exists.
493  */
494  if (pub->w.size() != 0) {
495  m_molNumSpecies_old = pub->w;
496  } else {
497  m_doEstimateEquil = -1;
498  m_molNumSpecies_old.assign(m_molNumSpecies_old.size(), 0.0);
499  }
500 
501  /*
502  * Formulate the Goal Element Abundance Vector
503  */
504  if (pub->gai.size() != 0) {
505  for (size_t i = 0; i < nelements; i++) {
506  m_elemAbundancesGoal[i] = pub->gai[i];
507  if (pub->m_elType[i] == VCS_ELEM_TYPE_LATTICERATIO) {
508  if (m_elemAbundancesGoal[i] < 1.0E-10) {
509  m_elemAbundancesGoal[i] = 0.0;
510  }
511  }
512  }
513  } else {
514  if (m_doEstimateEquil == 0) {
515  double sum = 0;
516  for (size_t j = 0; j < nelements; j++) {
517  m_elemAbundancesGoal[j] = 0.0;
518  for (size_t kspec = 0; kspec < nspecies; kspec++) {
519  if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
520  sum += m_molNumSpecies_old[kspec];
521  m_elemAbundancesGoal[j] += m_formulaMatrix(kspec,j) * m_molNumSpecies_old[kspec];
522  }
523  }
524  if (pub->m_elType[j] == VCS_ELEM_TYPE_LATTICERATIO) {
525  if (m_elemAbundancesGoal[j] < 1.0E-10 * sum) {
526  m_elemAbundancesGoal[j] = 0.0;
527  }
528  }
529  }
530  } else {
531  plogf("%sElement Abundances, m_elemAbundancesGoal[], not specified\n", ser);
532  return VCS_PUB_BAD;
533  }
534  }
535 
536  /*
537  * zero out values that will be filled in later
538  */
539  /*
540  * TPhMoles[] -> Untouched here. These will be filled in vcs_prep.c
541  * TPhMoles1[]
542  * DelTPhMoles[]
543  *
544  *
545  * T, Pres, copy over here
546  */
547  if (pub->T > 0.0) {
548  m_temperature = pub->T;
549  } else {
550  m_temperature = 293.15;
551  }
552  if (pub->PresPA > 0.0) {
553  m_pressurePA = pub->PresPA;
554  } else {
555  m_pressurePA = OneAtm;
556  }
557  /*
558  * TPhInertMoles[] -> must be copied over here
559  */
560  for (size_t iph = 0; iph < nph; iph++) {
561  vcs_VolPhase* Vphase = pub->VPhaseList[iph];
562  TPhInertMoles[iph] = Vphase->totalMolesInert();
563  }
564 
565  /*
566  * if__ : Copy over the units for the chemical potential
567  */
568  m_VCS_UnitsFormat = pub->m_VCS_UnitsFormat;
569 
570  /*
571  * tolerance requirements -> copy them over here and later
572  */
573  m_tolmaj = pub->tolmaj;
574  m_tolmin = pub->tolmin;
575  m_tolmaj2 = 0.01 * m_tolmaj;
576  m_tolmin2 = 0.01 * m_tolmin;
577 
578  /*
579  * m_speciesIndexVector[] is an index variable that keep track
580  * of solution vector rotations.
581  */
582  for (size_t i = 0; i < nspecies; i++) {
583  m_speciesMapIndex[i] = i;
584  }
585 
586  /*
587  * IndEl[] is an index variable that keep track of element vector
588  * rotations.
589  */
590  for (size_t i = 0; i < nelements; i++) {
591  m_elementMapIndex[i] = i;
592  }
593 
594  /*
595  * Define all species to be major species, initially.
596  */
597  for (size_t i = 0; i < nspecies; i++) {
598  // m_rxnStatus[i] = VCS_SPECIES_MAJOR;
599  m_speciesStatus[i] = VCS_SPECIES_MAJOR;
600  }
601  /*
602  * PhaseID: Fill in the species to phase mapping
603  * -> Check for bad values at the same time.
604  */
605  if (pub->PhaseID.size() != 0) {
606  std::vector<size_t> numPhSp(nph, 0);
607  for (size_t kspec = 0; kspec < nspecies; kspec++) {
608  size_t iph = pub->PhaseID[kspec];
609  if (iph >= nph) {
610  plogf("%sSpecies to Phase Mapping, PhaseID, has a bad value\n",
611  ser);
612  plogf("\tPhaseID[%d] = %d\n", kspec, iph);
613  plogf("\tAllowed values: 0 to %d\n", nph - 1);
614  return VCS_PUB_BAD;
615  }
616  m_phaseID[kspec] = pub->PhaseID[kspec];
617  m_speciesLocalPhaseIndex[kspec] = numPhSp[iph];
618  numPhSp[iph]++;
619  }
620  for (size_t iph = 0; iph < nph; iph++) {
621  vcs_VolPhase* Vphase = pub->VPhaseList[iph];
622  if (numPhSp[iph] != Vphase->nSpecies()) {
623  plogf("%sNumber of species in phase %d, %s, doesn't match\n",
624  ser, iph, Vphase->PhaseName.c_str());
625  return VCS_PUB_BAD;
626  }
627  }
628  } else {
629  if (m_numPhases == 1) {
630  for (size_t kspec = 0; kspec < nspecies; kspec++) {
631  m_phaseID[kspec] = 0;
632  m_speciesLocalPhaseIndex[kspec] = kspec;
633  }
634  } else {
635  plogf("%sSpecies to Phase Mapping, PhaseID, is not defined\n", ser);
636  return VCS_PUB_BAD;
637  }
638  }
639 
640  /*
641  * Copy over the element types
642  */
643  m_elType.resize(nelements, VCS_ELEM_TYPE_ABSPOS);
644  m_elementActive.resize(nelements, 1);
645 
646  /*
647  * Copy over the element names and types
648  */
649  for (size_t i = 0; i < nelements; i++) {
650  m_elementName[i] = pub->ElName[i];
651  m_elType[i] = pub->m_elType[i];
652  m_elementActive[i] = pub->ElActive[i];
653  if (!strncmp(m_elementName[i].c_str(), "cn_", 3)) {
654  m_elType[i] = VCS_ELEM_TYPE_CHARGENEUTRALITY;
655  if (pub->m_elType[i] != VCS_ELEM_TYPE_CHARGENEUTRALITY) {
656  throw CanteraError("VCS_SOLVE::vcs_prob_specifyFully",
657  "we have an inconsistency!");
658  }
659  }
660  }
661 
662  for (size_t i = 0; i < nelements; i++) {
663  if (m_elType[i] == VCS_ELEM_TYPE_CHARGENEUTRALITY) {
664  if (m_elemAbundancesGoal[i] != 0.0) {
665  if (fabs(m_elemAbundancesGoal[i]) > 1.0E-9) {
666  throw CanteraError("VCS_SOLVE::vcs_prob_specifyFully",
667  "Charge neutrality condition " + m_elementName[i] +
668  " is signicantly nonzero, " + fp2str(m_elemAbundancesGoal[i]) +
669  ". Giving up");
670  } else {
671  if (m_debug_print_lvl >= 2) {
672  plogf("Charge neutrality condition %s not zero, %g. Setting it zero\n",
673  m_elementName[i].c_str(), m_elemAbundancesGoal[i]);
674  }
675  m_elemAbundancesGoal[i] = 0.0;
676  }
677 
678  }
679  }
680  }
681 
682  /*
683  * Copy over the species names
684  */
685  for (size_t i = 0; i < nspecies; i++) {
686  m_speciesName[i] = pub->SpName[i];
687  }
688  /*
689  * Copy over all of the phase information
690  * Use the object's assignment operator
691  */
692  for (size_t iph = 0; iph < nph; iph++) {
693  *(m_VolPhaseList[iph]) = *(pub->VPhaseList[iph]);
694  /*
695  * Fix up the species thermo pointer in the vcs_SpeciesThermo object
696  * It should point to the species thermo pointer in the private
697  * data space.
698  */
699  vcs_VolPhase* Vphase = m_VolPhaseList[iph];
700  for (size_t k = 0; k < Vphase->nSpecies(); k++) {
701  vcs_SpeciesProperties* sProp = Vphase->speciesProperty(k);
702  size_t kT = Vphase->spGlobalIndexVCS(k);
703  sProp->SpeciesThermo = m_speciesThermoList[kT];
704  }
705  }
706 
707  /*
708  * Specify the Activity Convention information
709  */
710  for (size_t iph = 0; iph < nph; iph++) {
711  vcs_VolPhase* Vphase = m_VolPhaseList[iph];
712  m_phaseActConvention[iph] = Vphase->p_activityConvention;
713  if (Vphase->p_activityConvention != 0) {
714  /*
715  * We assume here that species 0 is the solvent.
716  * The solvent isn't on a unity activity basis
717  * The activity for the solvent assumes that the
718  * it goes to one as the species mole fraction goes to
719  * one; i.e., it's really on a molarity framework.
720  * So SpecLnMnaught[iSolvent] = 0.0, and the
721  * loop below starts at 1, not 0.
722  */
723  size_t iSolvent = Vphase->spGlobalIndexVCS(0);
724  double mnaught = m_wtSpecies[iSolvent] / 1000.;
725  for (size_t k = 1; k < Vphase->nSpecies(); k++) {
726  size_t kspec = Vphase->spGlobalIndexVCS(k);
727  m_actConventionSpecies[kspec] = Vphase->p_activityConvention;
728  m_lnMnaughtSpecies[kspec] = log(mnaught);
729  }
730  }
731  }
732 
733  /*
734  * Copy the title info
735  */
736  if (pub->Title.size() == 0) {
737  m_title = "Unspecified Problem Title";
738  } else {
739  m_title = pub->Title;
740  }
741 
742  /*
743  * Copy the volume info
744  */
745  m_totalVol = pub->Vol;
746  if (m_PMVolumeSpecies.size() != 0) {
747  m_PMVolumeSpecies = pub->VolPM;
748  }
749 
750  /*
751  * Return the success flag
752  */
753  return VCS_SUCCESS;
754 }
755 
756 int VCS_SOLVE::vcs_prob_specify(const VCS_PROB* pub)
757 {
758  string yo("vcs_prob_specify ERROR: ");
759  int retn = VCS_SUCCESS;
760 
761  m_temperature = pub->T;
762  m_pressurePA = pub->PresPA;
763  m_VCS_UnitsFormat = pub->m_VCS_UnitsFormat;
764  m_doEstimateEquil = pub->iest;
765 
766  m_totalVol = pub->Vol;
767 
768  m_tolmaj = pub->tolmaj;
769  m_tolmin = pub->tolmin;
770  m_tolmaj2 = 0.01 * m_tolmaj;
771  m_tolmin2 = 0.01 * m_tolmin;
772 
773  for (size_t kspec = 0; kspec < m_numSpeciesTot; ++kspec) {
774  size_t k = m_speciesMapIndex[kspec];
775  m_molNumSpecies_old[kspec] = pub->w[k];
776  m_molNumSpecies_new[kspec] = pub->mf[k];
777  m_feSpecies_old[kspec] = pub->m_gibbsSpecies[k];
778  }
779 
780  /*
781  * Transfer the element abundance goals to the solve object
782  */
783  for (size_t i = 0; i < m_numElemConstraints; i++) {
784  size_t j = m_elementMapIndex[i];
785  m_elemAbundancesGoal[i] = pub->gai[j];
786  }
787 
788  /*
789  * Try to do the best job at guessing at the title
790  */
791  if (pub->Title.size() == 0) {
792  if (m_title.size() == 0) {
793  m_title = "Unspecified Problem Title";
794  }
795  } else {
796  m_title = pub->Title;
797  }
798 
799  /*
800  * Copy over the phase information.
801  * -> For each entry in the phase structure, determine
802  * if that entry can change from its initial value
803  * Either copy over the new value or create an error
804  * condition.
805  */
806 
807  bool status_change = false;
808  for (size_t iph = 0; iph < m_numPhases; iph++) {
809  vcs_VolPhase* vPhase = m_VolPhaseList[iph];
810  vcs_VolPhase* pub_phase_ptr = pub->VPhaseList[iph];
811 
812  if (vPhase->VP_ID_ != pub_phase_ptr->VP_ID_) {
813  plogf("%sPhase numbers have changed:%d %d\n", yo.c_str(),
814  vPhase->VP_ID_, pub_phase_ptr->VP_ID_);
815  retn = VCS_PUB_BAD;
816  }
817 
818  if (vPhase->m_singleSpecies != pub_phase_ptr->m_singleSpecies) {
819  plogf("%sSingleSpecies value have changed:%d %d\n", yo.c_str(),
820  vPhase->m_singleSpecies,
821  pub_phase_ptr->m_singleSpecies);
822  retn = VCS_PUB_BAD;
823  }
824 
825  if (vPhase->m_gasPhase != pub_phase_ptr->m_gasPhase) {
826  plogf("%sGasPhase value have changed:%d %d\n", yo.c_str(),
827  vPhase->m_gasPhase,
828  pub_phase_ptr->m_gasPhase);
829  retn = VCS_PUB_BAD;
830  }
831 
832  vPhase->m_eqnState = pub_phase_ptr->m_eqnState;
833 
834  if (vPhase->nSpecies() != pub_phase_ptr->nSpecies()) {
835  plogf("%sNVolSpecies value have changed:%d %d\n", yo.c_str(),
836  vPhase->nSpecies(),
837  pub_phase_ptr->nSpecies());
838  retn = VCS_PUB_BAD;
839  }
840 
841  if (vPhase->PhaseName != pub_phase_ptr->PhaseName) {
842  plogf("%sPhaseName value have changed:%s %s\n", yo.c_str(),
843  vPhase->PhaseName.c_str(),
844  pub_phase_ptr->PhaseName.c_str());
845  retn = VCS_PUB_BAD;
846  }
847 
848  if (vPhase->totalMolesInert() != pub_phase_ptr->totalMolesInert()) {
849  status_change = true;
850  }
851  /*
852  * Copy over the number of inert moles if it has changed.
853  */
854  TPhInertMoles[iph] = pub_phase_ptr->totalMolesInert();
855  vPhase->setTotalMolesInert(pub_phase_ptr->totalMolesInert());
856  if (TPhInertMoles[iph] > 0.0) {
857  vPhase->setExistence(2);
858  vPhase->m_singleSpecies = false;
859  }
860 
861  /*
862  * Copy over the interfacial potential
863  */
864  double phi = pub_phase_ptr->electricPotential();
865  vPhase->setElectricPotential(phi);
866  }
867 
868 
869  if (status_change) {
870  vcs_SSPhase();
871  }
872  /*
873  * Calculate the total number of moles in all phases.
874  */
875  vcs_tmoles();
876 
877  return retn;
878 }
879 
880 int VCS_SOLVE::vcs_prob_update(VCS_PROB* pub)
881 {
882  size_t k1 = 0;
883 
884  vcs_tmoles();
885  m_totalVol = vcs_VolTotal(m_temperature, m_pressurePA,
886  VCS_DATA_PTR(m_molNumSpecies_old), VCS_DATA_PTR(m_PMVolumeSpecies));
887 
888  for (size_t i = 0; i < m_numSpeciesTot; ++i) {
889  /*
890  * Find the index of I in the index vector, m_speciesIndexVector[].
891  * Call it K1 and continue.
892  */
893  for (size_t j = 0; j < m_numSpeciesTot; ++j) {
894  k1 = j;
895  if (m_speciesMapIndex[j] == i) {
896  break;
897  }
898  }
899  /*
900  * - Switch the species data back from K1 into I
901  */
903  pub->w[i] = m_molNumSpecies_old[k1];
904  } else {
905  pub->w[i] = 0.0;
906  // plogf("voltage species = %g\n", m_molNumSpecies_old[k1]);
907  }
908  //pub->mf[i] = m_molNumSpecies_new[k1];
909  pub->m_gibbsSpecies[i] = m_feSpecies_old[k1];
910  pub->VolPM[i] = m_PMVolumeSpecies[k1];
911  }
912 
913  pub->T = m_temperature;
914  pub->PresPA = m_pressurePA;
915  pub->Vol = m_totalVol;
916  size_t kT = 0;
917  for (size_t iph = 0; iph < pub->NPhase; iph++) {
918  vcs_VolPhase* pubPhase = pub->VPhaseList[iph];
919  vcs_VolPhase* vPhase = m_VolPhaseList[iph];
920  pubPhase->setTotalMolesInert(vPhase->totalMolesInert());
921  pubPhase->setTotalMoles(vPhase->totalMoles());
922  pubPhase->setElectricPotential(vPhase->electricPotential());
923  double sumMoles = pubPhase->totalMolesInert();
924  pubPhase->setMoleFractionsState(vPhase->totalMoles(),
925  VCS_DATA_PTR(vPhase->moleFractions()),
927  const std::vector<double> & mfVector = pubPhase->moleFractions();
928  for (size_t k = 0; k < pubPhase->nSpecies(); k++) {
929  kT = pubPhase->spGlobalIndexVCS(k);
930  pub->mf[kT] = mfVector[k];
931  if (pubPhase->phiVarIndex() == k) {
932  k1 = vPhase->spGlobalIndexVCS(k);
933  double tmp = m_molNumSpecies_old[k1];
934  if (! vcs_doubleEqual(pubPhase->electricPotential() , tmp)) {
935  throw CanteraError("VCS_SOLVE::vcs_prob_update",
936  "We have an inconsistency in voltage, " +
937  fp2str(pubPhase->electricPotential()) + " " +
938  fp2str(tmp));
939  }
940  }
941 
942  if (! vcs_doubleEqual(pub->mf[kT], vPhase->molefraction(k))) {
943  throw CanteraError("VCS_SOLVE::vcs_prob_update",
944  "We have an inconsistency in mole fraction, " +
945  fp2str(pub->mf[kT]) + " " + fp2str(vPhase->molefraction(k)));
946  }
948  sumMoles += pub->w[kT];
949  }
950  }
951  if (! vcs_doubleEqual(sumMoles, vPhase->totalMoles())) {
952  throw CanteraError("VCS_SOLVE::vcs_prob_update",
953  "We have an inconsistency in total moles, " +
954  fp2str(sumMoles) + " " + fp2str(pubPhase->totalMoles()));
955  }
956 
957  }
958 
959  pub->m_Iterations = m_VCount->Its;
960  pub->m_NumBasisOptimizations = m_VCount->Basis_Opts;
961 
962  return VCS_SUCCESS;
963 }
964 
965 void VCS_SOLVE::vcs_counters_init(int ifunc)
966 {
967  m_VCount->Its = 0;
968  m_VCount->Basis_Opts = 0;
969  m_VCount->Time_vcs_TP = 0.0;
970  m_VCount->Time_basopt = 0.0;
971  if (ifunc) {
972  m_VCount->T_Its = 0;
973  m_VCount->T_Basis_Opts = 0;
974  m_VCount->T_Calls_Inest = 0;
975  m_VCount->T_Calls_vcs_TP = 0;
976  m_VCount->T_Time_vcs_TP = 0.0;
977  m_VCount->T_Time_basopt = 0.0;
978  m_VCount->T_Time_inest = 0.0;
979  m_VCount->T_Time_vcs = 0.0;
980  }
981 }
982 
983 double VCS_SOLVE::vcs_VolTotal(const double tkelvin, const double pres,
984  const double w[], double volPM[])
985 {
986  double VolTot = 0.0;
987  for (size_t iphase = 0; iphase < m_numPhases; iphase++) {
988  vcs_VolPhase* Vphase = m_VolPhaseList[iphase];
989  Vphase->setState_TP(tkelvin, pres);
991  double Volp = Vphase->sendToVCS_VolPM(volPM);
992  VolTot += Volp;
993  }
994  return VolTot;
995 }
996 
997 }
std::vector< int > ElActive
Specifies whether an element constraint is active.
Definition: vcs_prob.h:181
std::vector< double > WtSpecies
Molecular weight of species.
Definition: vcs_prob.h:187
bool vcs_doubleEqual(double d1, double d2)
Simple routine to check whether two doubles are equal up to roundoff error.
Definition: vcs_util.cpp:185
double sendToVCS_VolPM(double *const VolPM) const
Fill in the partial molar volume vector for VCS.
bool m_singleSpecies
If true, this phase consists of a single species.
Definition: vcs_VolPhase.h:584
void setMoleFractionsState(const double molNum, const double *const moleFracVec, const int vcsStateStatus)
Set the moles and/or mole fractions within the phase.
const doublereal OneAtm
One atmosphere [Pa].
Definition: ct_defs.h:69
double totalMolesInert() const
returns the value of the total kmol of inert in the phase
Declarations for a simple class that implements an Ansi C wall clock timer (see Cantera::clockWC).
std::vector< int > SpeciesUnknownType
Specifies the species unknown type.
Definition: vcs_prob.h:103
#define VCS_DATA_PTR(vvv)
Points to the data in a std::vector<> object.
Definition: vcs_internal.h:18
double Vol
Volume of the entire system.
Definition: vcs_prob.h:123
std::vector< std::string > ElName
vector of strings containing the element names
Definition: vcs_prob.h:171
int p_activityConvention
Convention for the activity formulation.
Definition: vcs_VolPhase.h:638
int iest
Specification of the initial estimate method.
Definition: vcs_prob.h:156
std::vector< double > w
Total number of moles of the kth species.
Definition: vcs_prob.h:70
int speciesUnknownType(const size_t k) const
Returns the type of the species unknown.
size_t nSpecies() const
Return the number of species in the phase.
int vcs_timing_print_lvl
Global hook for turning on and off time printing.
Definition: vcs_solve.cpp:26
The class provides the wall clock timer in seconds.
Definition: clockWC.h:51
std::string PhaseName
String name for the phase.
Definition: vcs_VolPhase.h:696
double totalMoles() const
Return the total moles in the phase.
std::vector< vcs_VolPhase * > VPhaseList
Array of phase structures.
Definition: vcs_prob.h:193
int m_Iterations
Number of iterations. This is an output variable.
Definition: vcs_prob.h:204
void setExistence(const int existence)
Set the existence flag in the object.
double electricPotential() const
Returns the electric field of the phase.
std::vector< size_t > PhaseID
Mapping between the species and the phases.
Definition: vcs_prob.h:165
size_t VP_ID_
Original ID of the phase in the problem.
Definition: vcs_VolPhase.h:581
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...
std::vector< double > VolPM
Partial Molar Volumes of species.
Definition: vcs_prob.h:130
Header for the object representing each phase within vcs.
#define VCS_SPECIES_TYPE_MOLNUM
Unknown refers to mole number of a single species.
Definition: vcs_defs.h:343
#define VCS_ELEM_TYPE_ABSPOS
Normal element constraint consisting of positive coefficients for the formula matrix.
Definition: vcs_defs.h:290
size_t phiVarIndex() const
Return the index of the species that represents the the voltage of the phase.
double tolmin
Tolerance requirement for minor species.
Definition: vcs_prob.h:162
Array2D FormulaMatrix
Formula Matrix for the problem.
Definition: vcs_prob.h:90
double tolmaj
Tolerance requirement for major species.
Definition: vcs_prob.h:159
int m_VCS_UnitsFormat
Units for the chemical potential data, pressure data, volume, and species amounts.
Definition: vcs_prob.h:148
#define VCS_SUCCESS
Definition: vcs_defs.h:21
double secondsWC()
Returns the wall clock time in seconds since the last reset.
Definition: clockWC.cpp:35
std::string fp2str(const double x, const std::string &fmt)
Convert a double into a c++ string.
Definition: stringUtils.cpp:28
Properties of a single species.
Header for the Interface class for the vcs thermo equilibrium solver package,.
int m_eqnState
Type of the equation of state.
Definition: vcs_VolPhase.h:597
virtual VCS_SPECIES_THERMO * duplMyselfAsVCS_SPECIES_THERMO()
Duplication function for derived classes.
const std::vector< double > & moleFractions() const
Return a const reference to the mole fractions stored in the object.
double molefraction(size_t kspec) const
Returns the mole fraction of the kspec species.
#define VCS_ELEM_TYPE_CHARGENEUTRALITY
This refers to a charge neutrality of a single phase.
Definition: vcs_defs.h:302
void setElectricPotential(const double phi)
set the electric potential of the phase
size_t nspecies
Total number of species in the problems.
Definition: vcs_prob.h:34
std::vector< double > mf
Mole fraction vector.
Definition: vcs_prob.h:77
Base class for exceptions thrown by Cantera classes.
Definition: ctexceptions.h:99
#define VCS_SPECIES_MAJOR
Species is a major species.
Definition: vcs_defs.h:128
bool m_gasPhase
If true, this phase is a gas-phase like phase.
Definition: vcs_VolPhase.h:591
std::vector< double > Charge
Charge of each species.
Definition: vcs_prob.h:190
int m_NumBasisOptimizations
Number of basis optimizations used. This is an output variable.
Definition: vcs_prob.h:207
double PresPA
Pressure.
Definition: vcs_prob.h:116
Phase information and Phase calculations for vcs.
Definition: vcs_VolPhase.h:86
#define VCS_DIMENSIONAL_G
dimensioned
Definition: vcs_defs.h:102
std::vector< int > m_elType
vector of Element types
Definition: vcs_prob.h:174
size_t ne
Number of element constraints in the equilibrium problem.
Definition: vcs_prob.h:40
const doublereal Avogadro
Avogadro's Number [number/kmol].
Definition: ct_defs.h:61
std::vector< VCS_SPECIES_THERMO * > SpeciesThermo
Vector of pointers to thermo structures which identify the model and parameters for evaluating the th...
Definition: vcs_prob.h:201
#define VCS_STATECALC_OLD
State Calculation based on the old or base mole numbers.
Definition: vcs_defs.h:365
std::vector< double > gai
Element abundances for jth element.
Definition: vcs_prob.h:84
std::vector< std::string > SpName
Vector of strings containing the species names.
Definition: vcs_prob.h:168
vcs_SpeciesProperties * speciesProperty(const size_t kindex)
Retrieve the kth Species structure for the species belonging to this phase.
std::vector< double > m_gibbsSpecies
Vector of chemical potentials of the species.
Definition: vcs_prob.h:57
Contains declarations for string manipulation functions within Cantera.
double T
Temperature (Kelvin)
Definition: vcs_prob.h:109
#define plogf
define this Cantera function to replace printf
Definition: vcs_internal.h:24
#define VCS_SPECIES_TYPE_INTERFACIALVOLTAGE
Unknown refers to the voltage level of a phase.
Definition: vcs_defs.h:352
Class to keep track of time and iterations.
Definition: vcs_internal.h:49
#define VCS_ELEM_TYPE_LATTICERATIO
Constraint associated with maintaining a fixed lattice stoichiometry in the solids.
Definition: vcs_defs.h:310
#define VCS_STATECALC_TMP
State Calculation based on a temporary set of mole numbers.
Definition: vcs_defs.h:376
size_t NPhase
Number of phases in the problem.
Definition: vcs_prob.h:47
size_t spGlobalIndexVCS(const size_t spIndex) const
Return the Global VCS index of the kth species in the phase.
Interface class for the vcs thermo equilibrium solver package, which generally describes the problem ...
Definition: vcs_prob.h:24
void setState_TP(const double temperature_Kelvin, const double pressure_PA)
Sets the temperature and pressure in this object and underlying ThermoPhase objects.
int vcs_debug_print_lvl
Debug print lvl.
Definition: vcs_prob.h:213
Definitions for the classes that are thrown when Cantera experiences an error condition (also contain...
void setTotalMolesInert(const double tMolesInert)
Sets the total moles of inert in the phase.
void setTotalMoles(const double totalMols)
Sets the total moles in the phase.