Constituents.cpp

Go to the documentation of this file.
00001 /**
00002  *  @file Constituents.cpp
00003  *  Header file  Class \link Cantera::Constituents Constitutents\endlink which 
00004  *  manages a set of elements and species (see \ref phases).
00005  */
00006 
00007 /* 
00008  *  $Date: 2009-12-09 12:29:23 -0500 (Wed, 09 Dec 2009) $
00009  *  $Revision: 306 $
00010  */
00011 
00012 //  Copyright 2001  California Institute of Technology
00013 
00014 
00015 #ifdef WIN32
00016 #pragma warning(disable:4786)
00017 #endif
00018 
00019 #include "Constituents.h"
00020 #include "Elements.h"
00021 using namespace std;
00022 
00023 namespace Cantera {
00024 
00025   /*
00026    *  Constructor sets all base variable types to zero. Also, it
00027    *  sets the pointer to the Elements object for this object to the
00028    *  default value of BaseElements. If the BaseElements Elements
00029    *  object doesn't exist, it creates it.
00030    *
00031    * Input
00032    * --------
00033    * ptr_Elements: If the Constituents object requires a different
00034    *               Elements object than the default one, input
00035    *               address here. This argument defaults to null,
00036    *               in which case the default Elements Object is
00037    *               chosen.
00038    */
00039 
00040   /*
00041    * DGG: I have reversed the role of ptr_Elements. In this version,
00042    * the default is that a new Elements object is created, so this
00043    * Constituents object is independent of any other object. But if
00044    * ptr_Elements is supplied, it will be used. This way, a class
00045    * implementing a multi-phase mixture is responsible for
00046    * maintaining the global elements list for the mixture, and no
00047    * static global element list is required.
00048    */
00049   Constituents::Constituents(Elements* ptr_Elements) :
00050     m_kk(0),
00051     m_speciesFrozen(false) ,
00052     m_Elements(ptr_Elements) 
00053   {
00054     if (!m_Elements) m_Elements = new Elements();
00055 
00056     // Register subscription to Elements object whether or not we
00057     // created it here.
00058     m_Elements->subscribe();
00059   }
00060 
00061   /**
00062    * Destructor for class Constituents.
00063    *
00064    *  Some cleanup of of the Global_Elements_List array is
00065    *  effected by unsubscribing to m_Elements.
00066    */
00067   Constituents::~Constituents()
00068   {
00069     int ileft = m_Elements->unsubscribe();
00070     /*
00071      * Here we may delete Elements Objects or not. Right now, we
00072      * will delete them. We also delete the global pointer entry
00073      * to keep everything consistent.
00074      */
00075     if (ileft <= 0) {
00076       vector<Elements *>::iterator it;
00077       for (it  = Elements::Global_Elements_List.begin();
00078            it != Elements::Global_Elements_List.end(); ++it) {
00079         if (*it == m_Elements) {
00080           Elements::Global_Elements_List.erase(it);
00081           break;
00082         }
00083       }
00084       delete m_Elements;
00085     }
00086   } 
00087 
00088   int Constituents::nElements() const { return m_Elements->nElements(); }
00089 
00090 
00091   /* 
00092    * Return the Atomic weight of element m.
00093    * units = Kg / Kmol
00094    */
00095   doublereal Constituents::atomicWeight(int m) const {
00096     return m_Elements->atomicWeight(m);
00097   }
00098 
00099 
00100   doublereal Constituents::entropyElement298(int m) const {
00101     return m_Elements->entropyElement298(m);
00102   }
00103 
00104   /*
00105    *  returns a reference to the vector of atomic weights pertinent
00106    *  to this constituents object
00107    *  units = kg / Kmol
00108    */
00109   const vector_fp& Constituents::atomicWeights() const {
00110     return m_Elements->atomicWeights();
00111   }
00112 
00113 
00114   /*
00115    * Return the atomic number of element m.
00116    */
00117   int Constituents::atomicNumber(int m) const {
00118     return m_Elements->atomicNumber(m);
00119   }
00120 
00121 
00122   /*
00123    * Add an element to the set.
00124    * @param symbol  symbol string
00125    * @param weight  atomic weight in kg/mol.
00126    *
00127    * If weight is not given, then a lookup is performed in the
00128    * element object
00129    *
00130    */
00131   void Constituents::
00132   addElement(const std::string& symbol, doublereal weight)
00133   {
00134     m_Elements->addElement(symbol, weight);
00135   }
00136 
00137   void Constituents::
00138   addElement(const XML_Node& e)
00139   {
00140     m_Elements->addElement(e);
00141   }
00142 
00143   /*
00144    * Add a unique element to the set. A check on the symbol is made
00145    * If the symbol is already an element, then a new element is
00146    * not created.
00147    *
00148    * @param symbol  symbol string
00149    * @param weight  atomic weight in kg/mol.
00150    *
00151    * If weight is not given, then a lookup is performed in the
00152    * element object
00153    *
00154    * -> Passthrough to the Element lvl.
00155    */
00156   void Constituents::
00157   addUniqueElement(const std::string& symbol, doublereal weight,
00158                    int atomicNumber, doublereal entropy298)
00159   {
00160     m_Elements->addUniqueElement(symbol, weight, atomicNumber, entropy298);
00161   }
00162 
00163   void Constituents::
00164   addUniqueElement(const XML_Node& e)
00165   {
00166     m_Elements->addUniqueElement(e);
00167   }
00168 
00169   void Constituents::addElementsFromXML(const XML_Node& phase) {
00170     m_Elements->addElementsFromXML(phase);
00171   }
00172 
00173   /*
00174    * -> Passthrough to the Element lvl.
00175    */
00176   void Constituents::freezeElements() {
00177     m_Elements->freezeElements();
00178   }
00179 
00180   /*
00181    * -> Passthrough to the Element lvl.
00182    */
00183   bool Constituents::elementsFrozen() {
00184     return m_Elements->elementsFrozen(); 
00185   }
00186 
00187   /*
00188    * Index of element named \a name. The index is an integer
00189    * assigned to each element in the order it was added,
00190    * beginning with 0 for the first element.  If \a name is not
00191    * the name of an element in the set, then the value -1 is
00192    * returned.
00193    *
00194    *
00195    * -> Passthrough to the Element class.
00196    */
00197   int Constituents::elementIndex(std::string name) const {
00198     return (m_Elements->elementIndex(name));
00199   }
00200 
00201   /*
00202    * Name of the element with index m. 
00203    *    
00204    *   This is a passthrough routine to the Element object.
00205    *   @param m  @{ Element index. @}
00206    *   \exception If m < 0 or m >= nElements(), the
00207    *              exception, ElementRangeError, is thrown.
00208    */
00209   string Constituents::elementName(int m) const {
00210     return (m_Elements->elementName(m));
00211   }
00212 
00213   /*******************************************************************
00214    *
00215    * elementNames():
00216    *
00217    * Returns a read-only reference to the vector of element names.
00218    * @code
00219    * Constituents c;
00220    * ...
00221    * const vector<string>& enames = c.elementNames();
00222    * int n = enames.size();
00223    * for (int i = 0; i < n; i++) cout << enames[i] << endl;
00224    * @endcode
00225    *
00226    *
00227    * -> Passthrough to the Element lvl.
00228    */
00229   const vector<string>& Constituents::elementNames() const {
00230     return m_Elements->elementNames();
00231   }
00232 
00233   /*
00234    * molecularWeight()
00235    *
00236    *  Returns the molecular weight of a species given the species index
00237    *
00238    *  units = kg / kmol.
00239    */
00240   doublereal Constituents::molecularWeight(int k) const {
00241     if (k < 0 || k >= nSpecies()) {
00242       throw SpeciesRangeError("Constituents::molecularWeight",
00243                               k, nSpecies());
00244     }
00245     return m_weight[k];
00246   }
00247 
00248   /*
00249    * molecularWeights()
00250    *
00251    *  Returns a const reference to the vector of molecular weights
00252    *  for all of the species defined in the object.
00253    *
00254    *  units = kg / kmol.
00255    */
00256   const array_fp& Constituents::molecularWeights() const { 
00257     return m_weight;
00258   }
00259 
00260   /*
00261    * charge():
00262    *
00263    * Electrical charge of one species k molecule, divided by
00264    * \f$ e = 1.602 \times 10^{-19}\f$ Coulombs.
00265    */ 
00266   doublereal Constituents::charge(int k) const { 
00267     return m_speciesCharge[k];
00268   }
00269 
00270   /*
00271    * addSpecies()
00272    *   
00273    *   Add a species to a Constituents object. Note, no check is made
00274    *   as to whether the species has a unique name.
00275    *
00276    *  Input
00277    *  ---------
00278    *   name = string containing the name
00279    *   comp[]
00280    *   charge = 
00281    *   weight = weight of the species. Default = 0.0.
00282    *            Note, the weight is a bit redundent and potentially
00283    *            harmful. If weight is less than or equal to zero,
00284    *            the weight is calculated from the element composition
00285    *            and it need not be supplied on the command line.
00286    */
00287   void Constituents::
00288   addSpecies(const std::string& name, const doublereal* comp,
00289              doublereal charge, doublereal size) {  
00290     m_Elements->freezeElements();
00291     m_speciesNames.push_back(name);
00292     m_speciesCharge.push_back(charge);
00293     m_speciesSize.push_back(size);
00294     int m_mm = m_Elements->nElements();
00295     // Create a changeable copy of the element composition. We now change the charge potentially
00296     vector_fp compNew(m_mm);
00297     for (int m = 0; m < m_mm; m++) {
00298       compNew[m] = comp[m];
00299     }
00300     double wt = 0.0;
00301     const vector_fp &aw = m_Elements->atomicWeights();
00302     if (charge != 0.0) {
00303       int eindex = m_Elements->elementIndex("E");
00304       if (eindex >= 0) {
00305         doublereal ecomp = compNew[eindex];
00306         if (fabs (charge + ecomp) > 0.001) {
00307           if (ecomp != 0.0) {
00308             throw CanteraError("Constituents::addSpecies",
00309                                "Input charge and element E compositions differ for species " + name);
00310           } else {
00311             // Just fix up the element E composition based on the input species charge
00312             compNew[eindex] = -charge;
00313           }
00314         }
00315       } else {
00316         m_Elements->m_elementsFrozen = false;
00317         addUniqueElement("E", 0.000545, 0, 0.0);
00318         m_Elements->m_elementsFrozen = true;
00319         m_mm = m_Elements->nElements();
00320         if (m_kk > 0) {
00321           vector_fp old(m_speciesComp);
00322           m_speciesComp.resize(m_kk*m_mm, 0.0);
00323           for (int k = 0; k < m_kk; k++) {
00324             int m_old = m_mm - 1;
00325             for (int m = 0; m < m_old; m++) {
00326               m_speciesComp[k * m_mm + m] =  old[k * (m_old) + m];
00327             }
00328             m_speciesComp[k * (m_mm) + (m_mm-1)] = 0.0; 
00329           }
00330         }
00331         eindex = m_Elements->elementIndex("E");
00332         compNew.resize(m_mm);
00333         compNew[m_mm-1] = - charge;
00334         //comp[eindex] = -charge;
00335         // throw CanteraError("Constituents::addSpecies",
00336         //                 "Element List doesn't include E, yet this species has charge:" + name);
00337       }
00338     }
00339     for (int m = 0; m < m_mm; m++) {
00340       m_speciesComp.push_back(compNew[m]);
00341       wt += compNew[m] * aw[m];
00342     }
00343     m_weight.push_back(wt);
00344     m_kk++;
00345   }
00346 
00347   /*
00348    *
00349    * addUniqueSpecies():
00350    *
00351    *   Add a species to a Constituents object. This routine will
00352    *   first check to see if the species is already part of the
00353    *   phase. It does this via a string comparison with the
00354    *   existing species in the phase.
00355    */
00356   void Constituents::
00357   addUniqueSpecies(const std::string& name, const doublereal* comp, 
00358                    doublereal charge, doublereal size) {
00359     vector<string>::const_iterator it = m_speciesNames.begin();
00360     for (int k = 0; k < m_kk; k++) {
00361       if (*it == name) {
00362         /*
00363          * We have found a match. At this point we could do some
00364          * compatibility checks. However, let's just return for the
00365          * moment without specifying any error.
00366          */
00367         int m_mm = m_Elements->nElements();
00368         for (int i = 0; i < m_mm; i++) {
00369           if (comp[i] != m_speciesComp[m_kk * m_mm + i]) {
00370             throw CanteraError("addUniqueSpecies",
00371                                "Duplicate species have different " 
00372                                "compositions: " + *it);  
00373           }
00374         }
00375         if (charge != m_speciesCharge[m_kk]) {
00376           throw CanteraError("addUniqueSpecies",
00377                              "Duplicate species have different " 
00378                              "charges: " + *it);
00379         }
00380         if (size != m_speciesSize[m_kk]) {
00381           throw CanteraError("addUniqueSpecies",
00382                              "Duplicate species have different " 
00383                              "sizes: " + *it);
00384         }
00385         return;
00386       }
00387       ++it;
00388     }
00389     addSpecies(name, comp, charge, size);
00390   }
00391 
00392   /*
00393    *
00394    * freezeSpecies()
00395    *   Set the boolean indicating that we are no longer allowing
00396    *   species to be added to the Constituents class object.
00397    */
00398   void Constituents::freezeSpecies() {
00399     m_speciesFrozen = true;
00400   }
00401 
00402   /*
00403    *
00404    * speciesIndex()
00405    *
00406    * Index of species named \c name. The first species added
00407    * will have index 0, and the last one index nSpecies() - 1.
00408    *
00409    *  Note, the [] operator shouldn't be used for map's because it
00410    *  creates new entries. Here, we use find() to look up entries.
00411    *
00412    *  If name isn't in the list, then a -1 is returned.
00413    */
00414   int Constituents::speciesIndex(std::string name) const {
00415     vector<string>::const_iterator it = m_speciesNames.begin();
00416     for (int k = 0; k < m_kk; k++) {
00417       if (*it == name) {
00418         /*
00419          * We have found a match.
00420          */
00421         return k;
00422       }
00423       ++it;
00424     }
00425     return  -1;
00426   }
00427 
00428   /*
00429    *
00430    * speciesName()
00431    *
00432    *      Name of the species with index k
00433    */
00434   string Constituents::speciesName(int k) const {
00435     if (k < 0 || k >= nSpecies()) 
00436       throw SpeciesRangeError("Constituents::speciesName",
00437                               k, nSpecies());
00438     return m_speciesNames[k];
00439   }
00440 
00441   /*
00442    *
00443    * speciesNames()
00444    *
00445    *    Return a const reference to the vector of species names
00446    */  
00447   const vector<string>& Constituents::speciesNames() const {
00448     return m_speciesNames;
00449   }
00450 
00451   /*
00452    *
00453    * ready():
00454    *   True if both elements and species have been frozen
00455    */
00456   bool Constituents::ready() const {
00457     return (m_Elements->elementsFrozen() && m_speciesFrozen);
00458   }
00459 
00460   /*
00461    * Returns the number of atoms of element \c m in species \c k.
00462    */
00463   doublereal Constituents::nAtoms(int k, int m) const
00464   {
00465     const int m_mm = m_Elements->nElements();
00466     if (m < 0 || m >=m_mm)
00467       throw ElementRangeError("Constituents::nAtoms",m,nElements());
00468     if (k < 0 || k >= nSpecies())
00469       throw SpeciesRangeError("Constituents::nAtoms",k,nSpecies());
00470     return m_speciesComp[m_mm * k + m];
00471   }
00472 
00473   /*
00474    *
00475    * getAtoms()
00476    *
00477    * Get a vector containing the atomic composition 
00478    * of species k
00479    */
00480   void Constituents::getAtoms(int k, double *atomArray) const 
00481   {
00482     const int m_mm = m_Elements->nElements();
00483     for (int m = 0; m < m_mm; m++) {
00484       atomArray[m] = (double) m_speciesComp[m_mm * k + m];
00485     }
00486   }
00487   
00488   /*
00489    * This copy constructor just calls the assignment operator
00490    * for this class.
00491    * The assignment operator does a deep copy.
00492    */
00493   Constituents::Constituents(const Constituents& right) :
00494     m_kk(0),
00495     m_speciesFrozen(false),
00496     m_Elements(0) 
00497   {
00498     *this = right;
00499   }
00500   
00501   /*
00502    *  Assignment operator for the Constituents class.
00503    *  Right now we pretty much do a straight uncomplicated
00504    *  copy of all of the protected data.
00505    */
00506   Constituents& Constituents::operator=(const Constituents& right) {
00507     /*
00508      * Check for self assignment.
00509      */
00510     if (this == &right) return *this;
00511     /*
00512      * We do a straight assignment operator on all of the
00513      * data. The vectors are copied.
00514      */
00515     m_kk             = right.m_kk;
00516     m_weight         = right.m_weight;
00517     m_speciesFrozen  = right.m_speciesFrozen;
00518     if (m_Elements) {
00519       int nleft = m_Elements->unsubscribe();
00520       if (nleft <= 0) {
00521         vector<Elements *>::iterator it;
00522         for (it  = Elements::Global_Elements_List.begin();
00523              it != Elements::Global_Elements_List.end(); ++it) {
00524           if (*it == m_Elements) {
00525             Elements::Global_Elements_List.erase(it);
00526             break;
00527           }
00528         }
00529         delete m_Elements;
00530       }
00531     }
00532     m_Elements       = right.m_Elements;
00533     if (m_Elements) {
00534       m_Elements->subscribe();
00535     }
00536     m_speciesNames   = right.m_speciesNames;
00537     m_speciesComp    = right.m_speciesComp;
00538     m_speciesCharge  = right.m_speciesCharge;
00539     m_speciesSize    = right.m_speciesSize;
00540     /*
00541      * Return the reference to the current object
00542      */
00543     return *this;
00544   }
00545   
00546 
00547 }
Generated by  doxygen 1.6.3