Cantera  2.0
vcs_VolPhase.cpp
Go to the documentation of this file.
1 /**
2  * @file vcs_VolPhase.cpp
3  */
4 /*
5  * Copyright (2005) Sandia Corporation. Under the terms of
6  * Contract DE-AC04-94AL85000 with Sandia Corporation, the
7  * U.S. Government retains certain rights in this software.
8  */
11 #include "vcs_SpeciesProperties.h"
12 #include "vcs_species_thermo.h"
14 
16 #include "cantera/thermo/mix_defs.h"
17 #include "vcs_Exception.h"
18 
19 #include <string>
20 #include <sstream>
21 #include <cstdio>
22 #include <cstdlib>
23 
24 namespace VCSnonideal
25 {
26 
27 /*
28  *
29  * vcs_VolPhase():
30  *
31  * Constructor for the VolPhase object.
32  */
33 vcs_VolPhase::vcs_VolPhase(VCS_SOLVE* owningSolverObject) :
34  m_owningSolverObject(0),
35  VP_ID_(npos),
36  Domain_ID(-1),
37  m_singleSpecies(true),
38  m_gasPhase(false),
39  m_eqnState(VCS_EOS_CONSTANT),
40  ChargeNeutralityElement(npos),
41  p_VCS_UnitsFormat(VCS_UNITS_MKS),
42  p_activityConvention(0),
43  m_numElemConstraints(0),
44  m_elemGlobalIndex(0),
45  m_numSpecies(0),
46  m_totalMolesInert(0.0),
47  m_isIdealSoln(false),
48  m_existence(VCS_PHASE_EXIST_NO),
49  m_MFStartIndex(0),
50  IndSpecies(0),
51  m_useCanteraCalls(false),
52  TP_ptr(0),
53  v_totalMoles(0.0),
54  creationMoleNumbers_(0),
55  creationGlobalRxnNumbers_(0),
56  m_phiVarIndex(npos),
57  m_totalVol(0.0),
58  m_vcsStateStatus(VCS_STATECALC_OLD),
59  m_phi(0.0),
60  m_UpToDate(false),
61  m_UpToDate_AC(false),
62  m_UpToDate_VolStar(false),
63  m_UpToDate_VolPM(false),
64  m_UpToDate_GStar(false),
65  m_UpToDate_G0(false),
66  Temp_(273.15),
67  Pres_(1.01325E5)
68 {
69  m_owningSolverObject = owningSolverObject;
70 }
71 /***************************************************************************/
72 
73 /*
74  *
75  * ~vcs_VolPhase():
76  *
77  * Destructor for the VolPhase object.
78  */
80 {
81  for (size_t k = 0; k < m_numSpecies; k++) {
82  vcs_SpeciesProperties* sp = ListSpeciesPtr[k];
83  delete sp;
84  sp = 0;
85  }
86 }
87 /************************************************************************************/
88 
89 /*
90  *
91  * Copy Constructor():
92  *
93  * Objects that are owned by this object are deep copied here, except
94  * for the ThermoPhase object.
95  * The assignment operator does most of the work.
96  */
98  m_owningSolverObject(b.m_owningSolverObject),
99  VP_ID_(b.VP_ID_),
100  Domain_ID(b.Domain_ID),
101  m_singleSpecies(b.m_singleSpecies),
102  m_gasPhase(b.m_gasPhase),
103  m_eqnState(b.m_eqnState),
104  ChargeNeutralityElement(b.ChargeNeutralityElement),
105  p_VCS_UnitsFormat(b.p_VCS_UnitsFormat),
106  p_activityConvention(b.p_activityConvention),
107  m_numElemConstraints(b.m_numElemConstraints),
108  m_numSpecies(b.m_numSpecies),
109  m_totalMolesInert(b.m_totalMolesInert),
110  m_isIdealSoln(b.m_isIdealSoln),
111  m_existence(b.m_existence),
112  m_MFStartIndex(b.m_MFStartIndex),
113  m_useCanteraCalls(b.m_useCanteraCalls),
114  TP_ptr(b.TP_ptr),
115  v_totalMoles(b.v_totalMoles),
116  creationMoleNumbers_(0),
117  creationGlobalRxnNumbers_(0),
118  m_phiVarIndex(npos),
119  m_totalVol(b.m_totalVol),
120  m_vcsStateStatus(VCS_STATECALC_OLD),
121  m_phi(b.m_phi),
122  m_UpToDate(false),
123  m_UpToDate_AC(false),
124  m_UpToDate_VolStar(false),
125  m_UpToDate_VolPM(false),
126  m_UpToDate_GStar(false),
127  m_UpToDate_G0(false),
128  Temp_(b.Temp_),
129  Pres_(b.Pres_)
130 {
131  /*
132  * Call the Assignment operator to do the heavy
133  * lifting.
134  */
135  *this = b;
136 }
137 /***************************************************************************/
138 
139 /*
140  * Assignment operator()
141  *
142  * (note, this is used, so keep it current!)
143  */
145 {
146  if (&b != this) {
147  size_t old_num = m_numSpecies;
148 
149  // Note: we comment this out for the assignment operator
150  // specifically, because it isn't true for the assignment
151  // operator but is true for a copy constructor
152  // m_owningSolverObject = b.m_owningSolverObject;
153 
154  VP_ID_ = b.VP_ID_;
155  Domain_ID = b.Domain_ID;
165  for (size_t e = 0; e < b.m_numElemConstraints; e++) {
166  m_elementNames[e] = b.m_elementNames[e];
167  }
171  for (size_t e = 0; e < m_numElemConstraints; e++) {
172  for (size_t k = 0; k < m_numSpecies; k++) {
173  m_formulaMatrix[e][k] = b.m_formulaMatrix[e][k];
174  }
175  }
178  PhaseName = b.PhaseName;
183  /*
184  * Do a shallow copy because we haven' figured this out.
185  */
187  //IndSpeciesContig = b.IndSpeciesContig;
188 
189  for (size_t k = 0; k < old_num; k++) {
190  if (ListSpeciesPtr[k]) {
191  delete ListSpeciesPtr[k];
192  ListSpeciesPtr[k] = 0;
193  }
194  }
195  ListSpeciesPtr.resize(m_numSpecies, 0);
196  for (size_t k = 0; k < m_numSpecies; k++) {
197  ListSpeciesPtr[k] =
198  new vcs_SpeciesProperties(*(b.ListSpeciesPtr[k]));
199  }
201  /*
202  * Do a shallow copy of the ThermoPhase object pointer.
203  * We don't duplicate the object.
204  * Um, there is no reason we couldn't do a
205  * duplicateMyselfAsThermoPhase() call here. This will
206  * have to be looked into.
207  */
208  TP_ptr = b.TP_ptr;
210  Xmol_ = b.Xmol_;
219  ActCoeff = b.ActCoeff;
222  m_phi = b.m_phi;
223  m_UpToDate = false;
224  m_UpToDate_AC = false;
225  m_UpToDate_VolStar = false;
226  m_UpToDate_VolPM = false;
227  m_UpToDate_GStar = false;
228  m_UpToDate_G0 = false;
229  Temp_ = b.Temp_;
230  Pres_ = b.Pres_;
231 
234  }
235  return *this;
236 }
237 /***************************************************************************/
238 
239 void vcs_VolPhase::resize(const size_t phaseNum, const size_t nspecies,
240  const size_t numElem, const char* const phaseName,
241  const double molesInert)
242 {
243 #ifdef DEBUG_MODE
244  if (nspecies <= 0) {
245  plogf("nspecies Error\n");
246  exit(EXIT_FAILURE);
247  }
248  if (phaseNum < 0) {
249  plogf("phaseNum should be greater than 0\n");
250  exit(EXIT_FAILURE);
251  }
252 #endif
253  setTotalMolesInert(molesInert);
254  m_phi = 0.0;
256 
257  if (phaseNum == VP_ID_) {
258  if (strcmp(PhaseName.c_str(), phaseName)) {
259  plogf("Strings are different: %s %s :unknown situation\n",
260  PhaseName.c_str(), phaseName);
261  exit(EXIT_FAILURE);
262  }
263  } else {
264  VP_ID_ = phaseNum;
265  if (!phaseName) {
266  std::stringstream sstmp;
267  sstmp << "Phase_" << VP_ID_;
268  PhaseName = sstmp.str();
269  } else {
270  PhaseName = phaseName;
271  }
272  }
273  if (nspecies > 1) {
274  m_singleSpecies = false;
275  } else {
276  m_singleSpecies = true;
277  }
278 
279  if (m_numSpecies == nspecies && numElem == m_numElemConstraints) {
280  return;
281  }
282 
283  m_numSpecies = nspecies;
284  if (nspecies > 1) {
285  m_singleSpecies = false;
286  }
287 
288 
289  IndSpecies.resize(nspecies, npos);
290 
291  if (ListSpeciesPtr.size() >= m_numSpecies) {
292  for (size_t i = 0; i < m_numSpecies; i++) {
293  if (ListSpeciesPtr[i]) {
294  delete ListSpeciesPtr[i];
295  ListSpeciesPtr[i] = 0;
296  }
297  }
298  }
299  ListSpeciesPtr.resize(nspecies, 0);
300  for (size_t i = 0; i < nspecies; i++) {
301  ListSpeciesPtr[i] = new vcs_SpeciesProperties(phaseNum, i, this);
302  }
303 
304  Xmol_.resize(nspecies, 0.0);
305  creationMoleNumbers_.resize(nspecies, 0.0);
306  creationGlobalRxnNumbers_.resize(nspecies, npos);
307  for (size_t i = 0; i < nspecies; i++) {
308  Xmol_[i] = 1.0/nspecies;
309  creationMoleNumbers_[i] = 1.0/nspecies;
311  }
312 
313  SS0ChemicalPotential.resize(nspecies, -1.0);
314  StarChemicalPotential.resize(nspecies, -1.0);
315  StarMolarVol.resize(nspecies, -1.0);
316  PartialMolarVol.resize(nspecies, -1.0);
317  ActCoeff.resize(nspecies, 1.0);
318  dLnActCoeffdMolNumber.resize(nspecies, nspecies, 0.0);
319 
320 
322  m_UpToDate = false;
324  m_UpToDate_AC = false;
325  m_UpToDate_VolStar = false;
326  m_UpToDate_VolPM = false;
327  m_UpToDate_GStar = false;
328  m_UpToDate_G0 = false;
329 
330 
331  elemResize(numElem);
332 
333 }
334 /***************************************************************************/
335 
336 void vcs_VolPhase::elemResize(const size_t numElemConstraints)
337 {
338 
339  m_elementNames.resize(numElemConstraints);
340 
341  m_elementActive.resize(numElemConstraints+1, 1);
342  m_elementType.resize(numElemConstraints, VCS_ELEM_TYPE_ABSPOS);
343  m_formulaMatrix.resize(numElemConstraints, m_numSpecies, 0.0);
344 
345  m_elementNames.resize(numElemConstraints, "");
346  m_elemGlobalIndex.resize(numElemConstraints, npos);
347 
348  m_numElemConstraints = numElemConstraints;
349 }
350 /***************************************************************************/
351 
352 //! Evaluate activity coefficients
353 /*!
354  * We carry out a calculation whenever UpTODate_AC is false. Specifically
355  * whenever a phase goes zero, we do not carry out calculations on it.
356  *
357  * (private)
358  */
360 {
361  if (m_isIdealSoln) {
362  m_UpToDate_AC = true;
363  return;
364  }
365  if (m_useCanteraCalls) {
367  }
368  m_UpToDate_AC = true;
369 }
370 /***************************************************************************/
371 
372 /*
373  *
374  * Evaluate one activity coefficients.
375  *
376  * return one activity coefficient. Have to recalculate them all to get
377  * one.
378  */
379 double vcs_VolPhase::AC_calc_one(size_t kspec) const
380 {
381  if (! m_UpToDate_AC) {
382  _updateActCoeff();
383  }
384  return(ActCoeff[kspec]);
385 }
386 /***************************************************************************/
387 
388 // Gibbs free energy calculation at a temperature for the reference state
389 // of each species
391 {
392  if (m_useCanteraCalls) {
394  } else {
395  double R = vcsUtil_gasConstant(p_VCS_UnitsFormat);
396  for (size_t k = 0; k < m_numSpecies; k++) {
397  size_t kglob = IndSpecies[k];
398  vcs_SpeciesProperties* sProp = ListSpeciesPtr[k];
399  VCS_SPECIES_THERMO* sTherm = sProp->SpeciesThermo;
401  R * (sTherm->G0_R_calc(kglob, Temp_));
402  }
403  }
404  m_UpToDate_G0 = true;
405 }
406 /***************************************************************************/
407 
408 double vcs_VolPhase::G0_calc_one(size_t kspec) const
409 {
410  if (!m_UpToDate_G0) {
411  _updateG0();
412  }
413  return SS0ChemicalPotential[kspec];
414 }
415 /***************************************************************************/
416 
418 {
419  if (m_useCanteraCalls) {
421  } else {
422  double R = vcsUtil_gasConstant(p_VCS_UnitsFormat);
423  for (size_t k = 0; k < m_numSpecies; k++) {
424  size_t kglob = IndSpecies[k];
425  vcs_SpeciesProperties* sProp = ListSpeciesPtr[k];
426  VCS_SPECIES_THERMO* sTherm = sProp->SpeciesThermo;
428  R * (sTherm->GStar_R_calc(kglob, Temp_, Pres_));
429  }
430  }
431  m_UpToDate_GStar = true;
432 }
433 /***************************************************************************/
434 
435 double vcs_VolPhase::GStar_calc_one(size_t kspec) const
436 {
437  if (!m_UpToDate_GStar) {
438  _updateGStar();
439  }
440  return StarChemicalPotential[kspec];
441 }
442 /***************************************************************************/
443 
444 // Set the mole fractions from a conventional mole fraction vector
445 /*
446  *
447  * @param xmol Value of the mole fractions for the species
448  * in the phase. These are contiguous.
449  */
450 void vcs_VolPhase::setMoleFractions(const double* const xmol)
451 {
452  double sum = -1.0;
453  for (size_t k = 0; k < m_numSpecies; k++) {
454  Xmol_[k] = xmol[k];
455  sum+= xmol[k];
456  }
457  if (std::fabs(sum) > 1.0E-13) {
458  for (size_t k = 0; k < m_numSpecies; k++) {
459  Xmol_[k] /= sum;
460  }
461  }
463  m_UpToDate = false;
465 }
466 /***************************************************************************/
467 
468 // Updates the mole fractions in subobjects
469 /*
470  * Whenever the mole fractions change, this routine
471  * should be called.
472  */
474 {
475  if (m_useCanteraCalls) {
476  if (TP_ptr) {
478  }
479  }
480  if (!m_isIdealSoln) {
481  m_UpToDate_AC = false;
482  m_UpToDate_VolPM = false;
483  }
484 }
485 /***************************************************************************/
486 
487 // Return a const reference to the mole fraction vector in the phase
488 const std::vector<double> & vcs_VolPhase::moleFractions() const
489 {
490  return Xmol_;
491 }
492 
493 double vcs_VolPhase::moleFraction(size_t k) const
494 {
495  return Xmol_[k];
496 }
497 /***************************************************************************/
498 
499 // Set the moles and/or mole fractions within the phase
500 void vcs_VolPhase::setMoleFractionsState(const double totalMoles,
501  const double* const moleFractions,
502  const int vcsStateStatus)
503 {
504 
505  if (totalMoles != 0.0) {
506  // There are other ways to set the mole fractions when VCS_STATECALC
507  // is set to a normal settting.
508  if (vcsStateStatus != VCS_STATECALC_TMP) {
509  printf("vcs_VolPhase::setMolesFractionsState: inappropriate usage\n");
510  exit(EXIT_FAILURE);
511  }
512  m_UpToDate = false;
515  printf("vcs_VolPhase::setMolesFractionsState: inappropriate usage\n");
516  exit(EXIT_FAILURE);
517  }
519  } else {
520  m_UpToDate = true;
521  m_vcsStateStatus = vcsStateStatus;
524  }
525  }
526  double fractotal = 1.0;
528  if (m_totalMolesInert > 0.0) {
530  printf("vcs_VolPhase::setMolesFractionsState: inerts greater than total: %g %g\n",
532  exit(EXIT_FAILURE);
533  }
534  fractotal = 1.0 - m_totalMolesInert/v_totalMoles;
535  }
536  double sum = 0.0;
537  for (size_t k = 0; k < m_numSpecies; k++) {
538  Xmol_[k] = moleFractions[k];
539  sum += moleFractions[k];
540  }
541  if (sum == 0.0) {
542  printf("vcs_VolPhase::setMolesFractionsState: inappropriate usage\n");
543  exit(EXIT_FAILURE);
544  }
545  if (sum != fractotal) {
546  for (size_t k = 0; k < m_numSpecies; k++) {
547  Xmol_[k] *= (fractotal /sum);
548  }
549  }
551 
552 }
553 /***************************************************************************/
554 
555 // Set the moles within the phase
556 /*
557  * This function takes as input the mole numbers in vcs format, and
558  * then updates this object with their values. This is essentially
559  * a gather routine.
560  *
561  *
562  * @param molesSpeciesVCS array of mole numbers. Note, the indices
563  * for species in
564  * this array may not be contiguous. IndSpecies[] is needed
565  * to gather the species into the local contiguous vector
566  * format.
567  */
568 void vcs_VolPhase::setMolesFromVCS(const int stateCalc,
569  const double* molesSpeciesVCS)
570 {
571  size_t kglob;
572  double tmp;
574 
575  if (molesSpeciesVCS == 0) {
576 #ifdef DEBUG_MODE
577  if (m_owningSolverObject == 0) {
578  printf("vcs_VolPhase::setMolesFromVCS shouldn't be here\n");
579  exit(EXIT_FAILURE);
580  }
581 #endif
582  if (stateCalc == VCS_STATECALC_OLD) {
584  } else if (stateCalc == VCS_STATECALC_NEW) {
586  }
587 #ifdef DEBUG_MODE
588  else {
589  printf("vcs_VolPhase::setMolesFromVCS shouldn't be here\n");
590  exit(EXIT_FAILURE);
591  }
592 #endif
593  }
594 #ifdef DEBUG_MODE
595  else {
596  if (m_owningSolverObject) {
597  if (stateCalc == VCS_STATECALC_OLD) {
598  if (molesSpeciesVCS != VCS_DATA_PTR(m_owningSolverObject->m_molNumSpecies_old)) {
599  printf("vcs_VolPhase::setMolesFromVCS shouldn't be here\n");
600  exit(EXIT_FAILURE);
601  }
602  } else if (stateCalc == VCS_STATECALC_NEW) {
603  if (molesSpeciesVCS != VCS_DATA_PTR(m_owningSolverObject->m_molNumSpecies_new)) {
604  printf("vcs_VolPhase::setMolesFromVCS shouldn't be here\n");
605  exit(EXIT_FAILURE);
606  }
607  }
608  }
609  }
610 #endif
611 
612  for (size_t k = 0; k < m_numSpecies; k++) {
614  kglob = IndSpecies[k];
615  v_totalMoles += std::max(0.0, molesSpeciesVCS[kglob]);
616  }
617  }
618  if (v_totalMoles > 0.0) {
619  for (size_t k = 0; k < m_numSpecies; k++) {
621  kglob = IndSpecies[k];
622  tmp = std::max(0.0, molesSpeciesVCS[kglob]);
623  Xmol_[k] = tmp / v_totalMoles;
624  }
625  }
627  } else {
628  // This is where we will start to store a better approximation
629  // for the mole fractions, when the phase doesn't exist.
630  // This is currently unimplemented.
631  //for (int k = 0; k < m_numSpecies; k++) {
632  // Xmol_[k] = 1.0 / m_numSpecies;
633  //}
635  }
636  /*
637  * Update the electric potential if it is a solution variable
638  * in the equation system
639  */
640  if (m_phiVarIndex != npos) {
641  kglob = IndSpecies[m_phiVarIndex];
642  if (m_numSpecies == 1) {
643  Xmol_[m_phiVarIndex] = 1.0;
644  } else {
645  Xmol_[m_phiVarIndex] = 0.0;
646  }
647  double phi = molesSpeciesVCS[kglob];
649  if (m_numSpecies == 1) {
651  }
652  }
654  if (m_totalMolesInert > 0.0) {
656  }
657 
658  /*
659  * If stateCalc is old and the total moles is positive,
660  * then we have a valid state. If the phase went away, it would
661  * be a valid starting point for F_k's. So, save the state.
662  */
663  if (stateCalc == VCS_STATECALC_OLD) {
664  if (v_totalMoles > 0.0) {
665  vcs_dcopy(VCS_DATA_PTR(creationMoleNumbers_), VCS_DATA_PTR(Xmol_), m_numSpecies);
666 
667  }
668  }
669 
670  /*
671  * Set flags indicating we are up to date with the VCS state vector.
672  */
673  m_UpToDate = true;
674  m_vcsStateStatus = stateCalc;
675 
676 }
677 /***************************************************************************/
678 
679 void vcs_VolPhase::setMolesFromVCSCheck(const int vcsStateStatus,
680  const double* molesSpeciesVCS,
681  const double* const TPhMoles)
682 {
683  setMolesFromVCS(vcsStateStatus, molesSpeciesVCS);
684  /*
685  * Check for consistency with TPhMoles[]
686  */
687  double Tcheck = TPhMoles[VP_ID_];
688  if (Tcheck != v_totalMoles) {
689  if (vcs_doubleEqual(Tcheck, v_totalMoles)) {
690  Tcheck = v_totalMoles;
691  } else {
692  plogf("vcs_VolPhase::setMolesFromVCSCheck: "
693  "We have a consistency problem: %21.16g %21.16g\n",
694  Tcheck, v_totalMoles);
695  exit(EXIT_FAILURE);
696  }
697  }
698 }
699 /***************************************************************************/
700 
701 // Update the moles within the phase, if necessary
702 /*
703  * This function takes as input the stateCalc value, which
704  * determines where within VCS_SOLVE to fetch the mole numbers.
705  * It then updates this object with their values. This is essentially
706  * a gather routine.
707  *
708  * @param vcsStateStatus State calc value either VCS_STATECALC_OLD
709  * or VCS_STATECALC_NEW. With any other value
710  * nothing is done.
711  *
712  */
713 void vcs_VolPhase::updateFromVCS_MoleNumbers(const int vcsStateStatus)
714 {
715  if (!m_UpToDate || (vcsStateStatus != m_vcsStateStatus)) {
716  if (vcsStateStatus == VCS_STATECALC_OLD || vcsStateStatus == VCS_STATECALC_NEW) {
717  if (m_owningSolverObject) {
718  setMolesFromVCS(vcsStateStatus);
719  }
720  }
721  }
722 }
723 /**************************************************************************/
724 
725 // Fill in an activity coefficients vector within a VCS_SOLVE object
726 /*
727  * This routine will calculate the activity coefficients for the
728  * current phase, and fill in the corresponding entries in the
729  * VCS activity coefficients vector.
730  *
731  * @param AC vector of activity coefficients for all of the species
732  * in all of the phases in a VCS problem. Only the
733  * entries for the current phase are filled in.
734  */
735 void vcs_VolPhase::sendToVCS_ActCoeff(const int vcsStateStatus,
736  double* const AC)
737 {
738  updateFromVCS_MoleNumbers(vcsStateStatus);
739  if (!m_UpToDate_AC) {
740  _updateActCoeff();
741  }
742  for (size_t k = 0; k < m_numSpecies; k++) {
743  size_t kglob = IndSpecies[k];
744  AC[kglob] = ActCoeff[k];
745  }
746 }
747 /***************************************************************************/
748 
749 // Fill in the partial molar volume vector for VCS
750 /*
751  * This routine will calculate the partial molar volumes for the
752  * current phase (if needed), and fill in the corresponding entries in the
753  * VCS partial molar volumes vector.
754  *
755  * @param VolPM vector of partial molar volumes for all of the species
756  * in all of the phases in a VCS problem. Only the
757  * entries for the current phase are filled in.
758  */
759 double vcs_VolPhase::sendToVCS_VolPM(double* const VolPM) const
760 {
761  if (!m_UpToDate_VolPM) {
762  (void) _updateVolPM();
763  }
764  for (size_t k = 0; k < m_numSpecies; k++) {
765  size_t kglob = IndSpecies[k];
766  VolPM[kglob] = PartialMolarVol[k];
767  }
768  return m_totalVol;
769 }
770 /***************************************************************************/
771 
772 void vcs_VolPhase::sendToVCS_GStar(double* const gstar) const
773 {
774  if (!m_UpToDate_GStar) {
775  _updateGStar();
776  }
777  for (size_t k = 0; k < m_numSpecies; k++) {
778  size_t kglob = IndSpecies[k];
779  gstar[kglob] = StarChemicalPotential[k];
780  }
781 }
782 /***************************************************************************/
783 
784 
786 {
787  m_phi = phi;
788  if (m_useCanteraCalls) {
790  }
791  // We have changed the state variable. Set uptodate flags to false
792  m_UpToDate_AC = false;
793  m_UpToDate_VolStar = false;
794  m_UpToDate_VolPM = false;
795  m_UpToDate_GStar = false;
796 }
797 /***************************************************************************/
798 
800 {
801  return m_phi;
802 }
803 /***************************************************************************/
804 
805 // Sets the temperature and pressure in this object and
806 // underlying objects
807 /*
808  * Sets the temperature and pressure in this object and
809  * underlying objects. The underlying objects refers to the
810  * Cantera's ThermoPhase object for this phase.
811  *
812  * @param temperature_Kelvin (Kelvin)
813  * @param pressure_PA Pressure (MKS units - Pascal)
814  */
815 void vcs_VolPhase::setState_TP(const double temp, const double pres)
816 {
817  if (Temp_ == temp) {
818  if (Pres_ == pres) {
819  return;
820  }
821  }
822  if (m_useCanteraCalls) {
824  TP_ptr->setState_TP(temp, pres);
825  }
826  Temp_ = temp;
827  Pres_ = pres;
828  m_UpToDate_AC = false;
829  m_UpToDate_VolStar = false;
830  m_UpToDate_VolPM = false;
831  m_UpToDate_GStar = false;
832  m_UpToDate_G0 = false;
833 }
834 /***************************************************************************/
835 
836 // Sets the temperature in this object and
837 // underlying objects
838 /*
839  * Sets the temperature and pressure in this object and
840  * underlying objects. The underlying objects refers to the
841  * Cantera's ThermoPhase object for this phase.
842  *
843  * @param temperature_Kelvin (Kelvin)
844  */
845 void vcs_VolPhase::setState_T(const double temp)
846 {
847  setState_TP(temp, Pres_);
848 }
849 /***************************************************************************/
850 
852 {
853  if (m_useCanteraCalls) {
855  } else {
856  for (size_t k = 0; k < m_numSpecies; k++) {
857  size_t kglob = IndSpecies[k];
858  vcs_SpeciesProperties* sProp = ListSpeciesPtr[k];
859  VCS_SPECIES_THERMO* sTherm = sProp->SpeciesThermo;
860  StarMolarVol[k] = (sTherm->VolStar_calc(kglob, Temp_, Pres_));
861  }
862  }
863  m_UpToDate_VolStar = true;
864 }
865 /***************************************************************************/
866 
867 double vcs_VolPhase::VolStar_calc_one(size_t kspec) const
868 {
869  if (!m_UpToDate_VolStar) {
870  _updateVolStar();
871  }
872  return StarMolarVol[kspec];
873 }
874 /***************************************************************************/
875 
876 // Calculate the partial molar volumes of all species and return the
877 // total volume
878 /*
879  * Calculates these quantities internally and then stores them
880  *
881  * @return total volume (m**3)
882  */
884 {
885  if (m_useCanteraCalls) {
887  } else {
888  for (size_t k = 0; k < m_numSpecies; k++) {
889  size_t kglob = IndSpecies[k];
890  vcs_SpeciesProperties* sProp = ListSpeciesPtr[k];
891  VCS_SPECIES_THERMO* sTherm = sProp->SpeciesThermo;
892  StarMolarVol[k] = (sTherm->VolStar_calc(kglob, Temp_, Pres_));
893  }
894  for (size_t k = 0; k < m_numSpecies; k++) {
896  }
897  }
898 
899  m_totalVol = 0.0;
900  for (size_t k = 0; k < m_numSpecies; k++) {
901  m_totalVol += PartialMolarVol[k] * Xmol_[k];
902  }
904 
905  if (m_totalMolesInert > 0.0) {
906  if (m_gasPhase) {
908  m_totalVol += volI;
909  } else {
910  printf("unknown situation\n");
911  exit(EXIT_FAILURE);
912  }
913  }
914  m_UpToDate_VolPM = true;
915  return m_totalVol;
916 }
917 /***************************************************************************/
918 
920 {
921  /*
922  * Evaluate the current base activity coefficients if necessary
923  */
924  if (!m_UpToDate_AC) {
925  _updateActCoeff();
926  }
927  if (!TP_ptr) {
928  return;
929  }
931  for (size_t j = 0; j < m_numSpecies; j++) {
932  double moles_j_base = v_totalMoles * Xmol_[j];
933  double* const lnActCoeffCol = dLnActCoeffdMolNumber[j];
934  if (moles_j_base < 1.0E-200) {
935  moles_j_base = 1.0E-7 * moles_j_base + 1.0E-20 * v_totalMoles + 1.0E-150;
936  }
937  for (size_t k = 0; k < m_numSpecies; k++) {
938  lnActCoeffCol[k] /= moles_j_base;
939  }
940  }
941 
942  double deltaMoles_j = 0.0;
943  // Make copies of ActCoeff and Xmol_ for use in taking differences
944  std::vector<double> ActCoeff_Base(ActCoeff);
945  std::vector<double> Xmol_Base(Xmol_);
946  double TMoles_base = v_totalMoles;
947 
948  /*
949  * Loop over the columns species to be deltad
950  */
951  for (size_t j = 0; j < m_numSpecies; j++) {
952  /*
953  * Calculate a value for the delta moles of species j
954  * -> Note Xmol_[] and Tmoles are always positive or zero
955  * quantities.
956  */
957  double moles_j_base = v_totalMoles * Xmol_Base[j];
958  deltaMoles_j = 1.0E-7 * moles_j_base + 1.0E-13 * v_totalMoles + 1.0E-150;
959  /*
960  * Now, update the total moles in the phase and all of the
961  * mole fractions based on this.
962  */
963  v_totalMoles = TMoles_base + deltaMoles_j;
964  for (size_t k = 0; k < m_numSpecies; k++) {
965  Xmol_[k] = Xmol_Base[k] * TMoles_base / v_totalMoles;
966  }
967  Xmol_[j] = (moles_j_base + deltaMoles_j) / v_totalMoles;
968 
969  /*
970  * Go get new values for the activity coefficients.
971  * -> Note this calls setState_PX();
972  */
974  _updateActCoeff();
975  /*
976  * Calculate the column of the matrix
977  */
978  double* const lnActCoeffCol = dLnActCoeffdMolNumber[j];
979  for (size_t k = 0; k < m_numSpecies; k++) {
980  double tmp;
981  tmp = (ActCoeff[k] - ActCoeff_Base[k]) /
982  ((ActCoeff[k] + ActCoeff_Base[k]) * 0.5 * deltaMoles_j);
983  if (fabs(tmp - lnActCoeffCol[k]) > 1.0E-4 * fabs(tmp) + fabs(lnActCoeffCol[k])) {
984  // printf(" we have an error\n");
985 
986  }
987  //tmp = lnActCoeffCol[k];
988 
989  }
990  /*
991  * Revert to the base case Xmol_, v_totalMoles
992  */
993  v_totalMoles = TMoles_base;
994  vcs_vdcopy(Xmol_, Xmol_Base, m_numSpecies);
995  }
996  /*
997  * Go get base values for the activity coefficients.
998  * -> Note this calls setState_TPX() again;
999  * -> Just wanted to make sure that cantera is in sync
1000  * with VolPhase after this call.
1001  */
1002  setMoleFractions(VCS_DATA_PTR(Xmol_Base));
1004  _updateActCoeff();
1005 }
1006 /***************************************************************************/
1007 
1008 // Downloads the ln ActCoeff jacobian into the VCS version of the
1009 // ln ActCoeff jacobian.
1010 /*
1011  *
1012  * This is essentially a scatter operation.
1013  *
1014  * The Jacobians are actually d( lnActCoeff) / d (MolNumber);
1015  * dLnActCoeffdMolNumber[j][k]
1016  *
1017  * j = id of the species mole number
1018  * k = id of the species activity coefficient
1019  */
1020 void
1021 vcs_VolPhase::sendToVCS_LnActCoeffJac(double* const* const LnACJac_VCS)
1022 {
1023  /*
1024  * update the Ln Act Coeff jacobian entries with respect to the
1025  * mole number of species in the phase -> we always assume that
1026  * they are out of date.
1027  */
1029 
1030  /*
1031  * Now copy over the values
1032  */
1033  for (size_t j = 0; j < m_numSpecies; j++) {
1034  size_t jglob = IndSpecies[j];
1035  double* const lnACJacVCS_col = LnACJac_VCS[jglob];
1036  const double* const lnACJac_col = dLnActCoeffdMolNumber[j];
1037  for (size_t k = 0; k < m_numSpecies; k++) {
1038  size_t kglob = IndSpecies[k];
1039  lnACJacVCS_col[kglob] = lnACJac_col[k];
1040  }
1041  }
1042 }
1043 /***************************************************************************/
1044 
1045 // Set the pointer for Cantera's ThermoPhase parameter
1046 /*
1047  * When we first initialize the ThermoPhase object, we read the
1048  * state of the ThermoPhase into vcs_VolPhase object.
1049  *
1050  * @param tp_ptr Pointer to the ThermoPhase object corresponding
1051  * to this phase.
1052  */
1054 {
1055  TP_ptr = tp_ptr;
1056  if (TP_ptr) {
1057  m_useCanteraCalls = true;
1058  Temp_ = TP_ptr->temperature();
1059  Pres_ = TP_ptr->pressure();
1061  p_VCS_UnitsFormat = VCS_UNITS_MKS;
1063  size_t nsp = TP_ptr->nSpecies();
1064  size_t nelem = TP_ptr->nElements();
1065  if (nsp != m_numSpecies) {
1066  if (m_numSpecies != 0) {
1067  plogf("Warning Nsp != NVolSpeces: %d %d \n", nsp, m_numSpecies);
1068  }
1069  resize(VP_ID_, nsp, nelem, PhaseName.c_str());
1070  }
1072  vcs_dcopy(VCS_DATA_PTR(creationMoleNumbers_), VCS_DATA_PTR(Xmol_), m_numSpecies);
1074 
1075  /*
1076  * figure out ideal solution tag
1077  */
1078  if (nsp == 1) {
1079  m_isIdealSoln = true;
1080  } else {
1081  int eos = TP_ptr->eosType();
1082  switch (eos) {
1083  case Cantera::cIdealGas:
1084  case Cantera::cIncompressible:
1085  case Cantera::cSurf:
1086  case Cantera::cMetal:
1087  case Cantera::cStoichSubstance:
1088  case Cantera::cSemiconductor:
1089  case Cantera::cLatticeSolid:
1090  case Cantera::cLattice:
1091  case Cantera::cEdge:
1093  m_isIdealSoln = true;
1094  break;
1095  default:
1096  m_isIdealSoln = false;
1097  };
1098  }
1099  } else {
1100  m_useCanteraCalls = false;
1101  }
1102 }
1103 /***************************************************************************/
1104 
1105 // Return a const ThermoPhase pointer corresponding to this phase
1106 /*
1107  * @return pointer to the ThermoPhase.
1108  */
1110 {
1111  return TP_ptr;
1112 }
1113 /***************************************************************************/
1114 
1116 {
1117  return v_totalMoles;
1118 }
1119 /***************************************************************************/
1120 
1121 double vcs_VolPhase::molefraction(size_t k) const
1122 {
1123  return Xmol_[k];
1124 }
1125 /***************************************************************************/
1126 
1127 void vcs_VolPhase::setCreationMoleNumbers(const double* const n_k,
1128  const std::vector<size_t> &creationGlobalRxnNumbers)
1129 {
1130  vcs_dcopy(VCS_DATA_PTR(creationMoleNumbers_), n_k, m_numSpecies);
1131  creationGlobalRxnNumbers_ = creationGlobalRxnNumbers;
1132 
1133 }
1134 /***************************************************************************/
1135 
1136 const std::vector<double> & vcs_VolPhase::creationMoleNumbers(std::vector<size_t> &creationGlobalRxnNumbers) const
1137 {
1138  creationGlobalRxnNumbers = creationGlobalRxnNumbers_;
1139  return creationMoleNumbers_;
1140 }
1141 /***************************************************************************/
1142 
1143 // Sets the total moles in the phase
1144 /*
1145  * We don't have to flag the internal state as changing here
1146  * because we have just changed the total moles.
1147  *
1148  * @param totalMols Total moles in the phase (kmol)
1149  */
1150 void vcs_VolPhase::setTotalMoles(const double totalMols)
1151 {
1152  v_totalMoles = totalMols;
1153  if (m_totalMolesInert > 0.0) {
1155 #ifdef DEBUG_MODE
1156  if (totalMols < m_totalMolesInert) {
1157  printf(" vcs_VolPhase::setTotalMoles:: ERROR totalMoles "
1158  "less than inert moles: %g %g\n",
1159  totalMols, m_totalMolesInert);
1160  exit(EXIT_FAILURE);
1161  }
1162 #endif
1163  } else {
1164  if (m_singleSpecies && (m_phiVarIndex == 0)) {
1166  } else {
1167  if (totalMols > 0.0) {
1169  } else {
1171  }
1172  }
1173  }
1174 }
1175 /***************************************************************************/
1176 
1177 // Sets the mole flag within the object to out of date
1178 /*
1179  * This will trigger the object to go get the current mole numbers
1180  * when it needs it.
1181  */
1183 {
1184  m_UpToDate = false;
1185  if (stateCalc != -1) {
1186  m_vcsStateStatus = stateCalc;
1187  }
1188 }
1189 /***************************************************************************/
1190 
1191 // Sets the mole flag within the object to be current
1193 {
1194  m_UpToDate = true;
1195  m_vcsStateStatus = stateCalc;
1196 }
1197 /***************************************************************************/
1198 
1199 
1200 // Return a string representing the equation of state
1201 /*
1202  * The string is no more than 16 characters.
1203  * @param EOSType : integer value of the equation of state
1204  *
1205  * @return returns a string representing the EOS
1206  */
1207 std::string string16_EOSType(int EOSType)
1208 {
1209  char st[32];
1210  st[16] = '\0';
1211  switch (EOSType) {
1212  case VCS_EOS_CONSTANT:
1213  sprintf(st,"Constant ");
1214  break;
1215  case VCS_EOS_IDEAL_GAS:
1216  sprintf(st,"Ideal Gas ");
1217  break;
1218  case VCS_EOS_STOICH_SUB:
1219  sprintf(st,"Stoich Sub ");
1220  break;
1221  case VCS_EOS_IDEAL_SOLN:
1222  sprintf(st,"Ideal Soln ");
1223  break;
1224  case VCS_EOS_DEBEYE_HUCKEL:
1225  sprintf(st,"Debeye Huckel ");
1226  break;
1227  case VCS_EOS_REDLICK_KWONG:
1228  sprintf(st,"Redlick_Kwong ");
1229  break;
1230  case VCS_EOS_REGULAR_SOLN:
1231  sprintf(st,"Regular Soln ");
1232  break;
1233  default:
1234  sprintf(st,"UnkType: %-7d", EOSType);
1235  break;
1236  }
1237  st[16] = '\0';
1238  std::string sss=st;
1239  return sss;
1240 }
1241 /***************************************************************************/
1242 
1243 // Returns whether the phase is an ideal solution phase
1245 {
1246  return m_isIdealSoln;
1247 }
1248 /***************************************************************************/
1249 
1250 // Returns whether the phase uses Cantera calls
1252 {
1253  return m_useCanteraCalls;
1254 }
1255 /***************************************************************************/
1256 
1258 {
1259  return m_phiVarIndex;
1260 }
1261 /***************************************************************************/
1262 
1263 
1264 void vcs_VolPhase::setPhiVarIndex(size_t phiVarIndex)
1265 {
1268  if (m_singleSpecies) {
1269  if (m_phiVarIndex == 0) {
1271  }
1272  }
1273 }
1274 /***************************************************************************/
1275 
1276 // Retrieve the kth Species structure for the species belonging to this phase
1277 /*
1278  * The index into this vector is the species index within the phase.
1279  *
1280  * @param kindex kth species index.
1281  */
1282 vcs_SpeciesProperties* vcs_VolPhase::speciesProperty(const size_t kindex)
1283 {
1284  return ListSpeciesPtr[kindex];
1285 }
1286 /***************************************************************************/
1287 
1288 // Boolean indicating whether the phase exists or not
1290 {
1291  return m_existence;
1292 }
1293 /**********************************************************************/
1294 
1295 // Set the existence flag in the object
1296 void vcs_VolPhase::setExistence(const int existence)
1297 {
1298  if (existence == VCS_PHASE_EXIST_NO || existence == VCS_PHASE_EXIST_ZEROEDPHASE) {
1299  if (v_totalMoles != 0.0) {
1300 #ifdef DEBUG_MODE
1301  plogf("vcs_VolPhase::setExistence setting false existence for phase with moles");
1302  plogendl();
1303  exit(EXIT_FAILURE);
1304 #else
1305  v_totalMoles = 0.0;
1306 #endif
1307  }
1308  }
1309 #ifdef DEBUG_MODE
1310  else {
1311  if (m_totalMolesInert == 0.0) {
1312  if (v_totalMoles == 0.0) {
1313  if (!m_singleSpecies || m_phiVarIndex != 0) {
1314  plogf("vcs_VolPhase::setExistence setting true existence for phase with no moles");
1315  plogendl();
1316  exit(EXIT_FAILURE);
1317  }
1318  }
1319  }
1320  }
1321 #endif
1322 #ifdef DEBUG_MODE
1323  if (m_singleSpecies) {
1324  if (m_phiVarIndex == 0) {
1325  if (existence == VCS_PHASE_EXIST_NO || existence == VCS_PHASE_EXIST_ZEROEDPHASE) {
1326  plogf("vcs_VolPhase::Trying to set existence of an electron phase to false");
1327  plogendl();
1328  exit(EXIT_FAILURE);
1329  }
1330  }
1331  }
1332 #endif
1333  m_existence = existence;
1334 }
1335 /**********************************************************************/
1336 
1337 // Return the Global VCS index of the kth species in the phase
1338 /*
1339  * @param spIndex local species index (0 to the number of species
1340  * in the phase)
1341  *
1342  * @return Returns the VCS_SOLVE species index of the that species
1343  * This changes as rearrangements are carried out.
1344  */
1345 size_t vcs_VolPhase::spGlobalIndexVCS(const size_t spIndex) const
1346 {
1347  return IndSpecies[spIndex];
1348 }
1349 /**********************************************************************/
1350 
1351 //! set the Global VCS index of the kth species in the phase
1352 /*!
1353  * @param spIndex local species index (0 to the number of species
1354  * in the phase)
1355  *
1356  * @return Returns the VCS_SOLVE species index of the that species
1357  * This changes as rearrangements are carried out.
1358  */
1359 void vcs_VolPhase::setSpGlobalIndexVCS(const size_t spIndex,
1360  const size_t spGlobalIndex)
1361 {
1362  IndSpecies[spIndex] = spGlobalIndex;
1363  if (spGlobalIndex >= m_numElemConstraints) {
1364  creationGlobalRxnNumbers_[spIndex] = spGlobalIndex - m_numElemConstraints;
1365  }
1366 }
1367 /**********************************************************************/
1368 
1369 // Sets the total moles of inert in the phase
1370 /*
1371  * @param tMolesInert Value of the total kmols of inert species in the
1372  * phase.
1373  */
1374 void vcs_VolPhase::setTotalMolesInert(const double tMolesInert)
1375 {
1376  if (m_totalMolesInert != tMolesInert) {
1377  m_UpToDate = false;
1378  m_UpToDate_AC = false;
1379  m_UpToDate_VolStar = false;
1380  m_UpToDate_VolPM = false;
1381  m_UpToDate_GStar = false;
1382  m_UpToDate_G0 = false;
1383  v_totalMoles += (tMolesInert - m_totalMolesInert);
1384  m_totalMolesInert = tMolesInert;
1385  }
1386  if (m_totalMolesInert > 0.0) {
1388  } else if (m_singleSpecies && (m_phiVarIndex == 0)) {
1390  } else {
1391  if (v_totalMoles > 0.0) {
1393  } else {
1395  }
1396  }
1397 }
1398 /**********************************************************************/
1399 
1400 // returns the value of the total kmol of inert in the phase
1402 {
1403  return m_totalMolesInert;
1404 }
1405 /**********************************************************************/
1406 
1407 // Returns the global index of the local element index for the phase
1408 size_t vcs_VolPhase::elemGlobalIndex(const size_t e) const
1409 {
1410  DebugAssertThrowVCS(e < m_numElemConstraints, " vcs_VolPhase::elemGlobalIndex") ;
1411  return m_elemGlobalIndex[e];
1412 }
1413 /**********************************************************************/
1414 
1415 // Returns the global index of the local element index for the phase
1416 void vcs_VolPhase::setElemGlobalIndex(const size_t eLocal, const size_t eGlobal)
1417 {
1418  DebugAssertThrowVCS(eLocal < m_numElemConstraints,
1419  "vcs_VolPhase::setElemGlobalIndex");
1420  m_elemGlobalIndex[eLocal] = eGlobal;
1421 }
1422 /**********************************************************************/
1423 
1425 {
1426  return m_numElemConstraints;
1427 }
1428 /**********************************************************************/
1429 
1430 std::string vcs_VolPhase::elementName(const size_t e) const
1431 {
1432  return m_elementNames[e];
1433 }
1434 /**********************************************************************/
1435 
1436 /*!
1437  * This function decides whether a phase has charged species
1438  * or not.
1439  */
1440 static bool hasChargedSpecies(const Cantera::ThermoPhase* const tPhase)
1441 {
1442  for (size_t k = 0; k < tPhase->nSpecies(); k++) {
1443  if (tPhase->charge(k) != 0.0) {
1444  return true;
1445  }
1446  }
1447  return false;
1448 }
1449 /**********************************************************************
1450  *
1451  * chargeNeutralityElement():
1452  *
1453  * This utility routine decides whether a Cantera ThermoPhase needs
1454  * a constraint equation representing the charge neutrality of the
1455  * phase. It does this by searching for charged species. If it
1456  * finds one, and if the phase needs one, then it returns true.
1457  */
1458 static bool chargeNeutralityElement(const Cantera::ThermoPhase* const tPhase)
1459 {
1460  int hasCharge = hasChargedSpecies(tPhase);
1461  if (tPhase->chargeNeutralityNecessary()) {
1462  if (hasCharge) {
1463  return true;
1464  }
1465  }
1466  return false;
1467 }
1468 
1470 {
1471  size_t e, k, eT;
1472  std::string ename;
1473  size_t eFound = npos;
1474  size_t nebase = tPhase->nElements();
1475  size_t ne = nebase;
1476  size_t ns = tPhase->nSpecies();
1477 
1478  /*
1479  * Decide whether we need an extra element constraint for charge
1480  * neutrality of the phase
1481  */
1482  bool cne = chargeNeutralityElement(tPhase);
1483  if (cne) {
1485  ne++;
1486  }
1487 
1488  /*
1489  * Assign and malloc structures
1490  */
1491  elemResize(ne);
1492 
1493 
1494  if (ChargeNeutralityElement != npos) {
1496  }
1497 
1498  if (hasChargedSpecies(tPhase)) {
1499  if (cne) {
1500  /*
1501  * We need a charge neutrality constraint.
1502  * We also have an Electron Element. These are
1503  * duplicates of each other. To avoid trouble with
1504  * possible range error conflicts, sometimes we eliminate
1505  * the Electron condition. Flag that condition for elimination
1506  * by toggling the ElActive variable. If we find we need it
1507  * later, we will retoggle ElActive to true.
1508  */
1509  for (eT = 0; eT < nebase; eT++) {
1510  ename = tPhase->elementName(eT);
1511  if (ename == "E") {
1512  eFound = eT;
1513  m_elementActive[eT] = 0;
1515  }
1516  }
1517  } else {
1518  for (eT = 0; eT < nebase; eT++) {
1519  ename = tPhase->elementName(eT);
1520  if (ename == "E") {
1521  eFound = eT;
1523  }
1524  }
1525  }
1526  if (eFound == npos) {
1527  eFound = ne;
1529  m_elementActive[ne] = 0;
1530  std::string ename = "E";
1531  m_elementNames[ne] = ename;
1532  ne++;
1533  elemResize(ne);
1534  }
1535 
1536  }
1537 
1538  m_formulaMatrix.resize(ne, ns, 0.0);
1539 
1541 
1542  elemResize(ne);
1543 
1544  e = 0;
1545  for (eT = 0; eT < nebase; eT++) {
1546  ename = tPhase->elementName(eT);
1547  m_elementNames[e] = ename;
1548  m_elementType[e] = tPhase->elementType(eT);
1549  e++;
1550  }
1551 
1552  if (cne) {
1553  std::string pname = tPhase->id();
1554  if (pname == "") {
1555  std::stringstream sss;
1556  sss << "phase" << VP_ID_;
1557  pname = sss.str();
1558  }
1559  ename = "cn_" + pname;
1561  m_elementNames[e] = ename;
1562  }
1563 
1564  double* const* const fm = m_formulaMatrix.baseDataAddr();
1565  for (k = 0; k < ns; k++) {
1566  e = 0;
1567  for (eT = 0; eT < nebase; eT++) {
1568  fm[e][k] = tPhase->nAtoms(k, eT);
1569  e++;
1570  }
1571  if (eFound != npos) {
1572  fm[eFound][k] = - tPhase->charge(k);
1573  }
1574  }
1575 
1576  if (cne) {
1577  for (k = 0; k < ns; k++) {
1578  fm[ChargeNeutralityElement][k] = tPhase->charge(k);
1579  }
1580  }
1581 
1582 
1583  /*
1584  * Here, we figure out what is the species types are
1585  * The logic isn't set in stone, and is just for a particular type
1586  * of problem that I'm solving first.
1587  */
1588  if (ns == 1) {
1589  if (tPhase->charge(0) != 0.0) {
1591  setPhiVarIndex(0);
1592  }
1593  }
1594 
1595  return ne;
1596 }
1597 /***************************************************************************/
1598 
1599 // Type of the element constraint with index \c e.
1600 /*
1601  * @param e Element index.
1602  */
1603 int vcs_VolPhase::elementType(const size_t e) const
1604 {
1605  return m_elementType[e];
1606 }
1607 /***************************************************************************/
1608 
1609 // Set the element Type of the element constraint with index \c e.
1610 /*
1611  * @param e Element index
1612  * @param eType type of the element.
1613  */
1614 void vcs_VolPhase::setElementType(const size_t e, const int eType)
1615 {
1616  m_elementType[e] = eType;
1617 }
1618 /***************************************************************************/
1619 
1620 double const* const* vcs_VolPhase::getFormulaMatrix() const
1621 {
1622  double const* const* fm = m_formulaMatrix.constBaseDataAddr();
1623  return fm;
1624 }
1625 /***************************************************************************/
1626 
1627 int vcs_VolPhase::speciesUnknownType(const size_t k) const
1628 {
1629  return m_speciesUnknownType[k];
1630 }
1631 /***************************************************************************/
1632 
1633 int vcs_VolPhase::elementActive(const size_t e) const
1634 {
1635  return m_elementActive[e];
1636 }
1637 /***************************************************************************/
1638 
1639 //! Return the number of species in the phase
1641 {
1642  return m_numSpecies;
1643 }
1644 /***************************************************************************/
1645 
1646 }
1647