Subversion Repositories wimsdev

Rev

Rev 17747 | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. // -*- coding: utf-8 -*-
  2. #include "chemeq.h"
  3. #include <cmath>
  4. #include <cstdlib>
  5.  
  6. atome lesatomes[] ={
  7. {-1, "e"},
  8. {1, "H"},
  9. {2, "He"},
  10. {3, "Li"},
  11. {4, "Be"},
  12. {5, "B"},
  13. {6, "C"},
  14. {7, "N"},
  15. {8, "O"},
  16. {9, "F"},
  17. {10, "Ne"},
  18. {11, "Na"},
  19. {12, "Mg"},
  20. {13, "Al"},
  21. {14, "Si"},
  22. {15, "P"},
  23. {16, "S"},
  24. {17, "Cl"},
  25. {18, "Ar"},
  26. {19, "K"},
  27. {20, "Ca"},
  28. {21, "Sc"},
  29. {22, "Ti"},
  30. {23, "V"},
  31. {24, "Cr"},
  32. {25, "Mn"},
  33. {26, "Fe"},
  34. {27, "Co"},
  35. {28, "Ni"},
  36. {29, "Cu"},
  37. {30, "Zn"},
  38. {31, "Ga"},
  39. {32, "Ge"},
  40. {33, "As"},
  41. {34, "Se"},
  42. {35, "Br"},
  43. {36, "Kr"},
  44. {37, "Rb"},
  45. {38, "Sr"},
  46. {39, "Y"},
  47. {40, "Zr"},
  48. {41, "Nb"},
  49. {42, "Mo"},
  50. {43, "Tc"},
  51. {44, "Ru"},
  52. {45, "Rh"},
  53. {46, "Pd"},
  54. {47, "Ag"},
  55. {48, "Cd"},
  56. {49, "In"},
  57. {50, "Sn"},
  58. {51, "Sb"},
  59. {52, "Te"},
  60. {53, "I"},
  61. {54, "Xe"},
  62. {55, "Cs"},
  63. {56, "Ba"},
  64. {57, "La"},
  65. {58, "Ce"},
  66. {59, "Pr"},
  67. {60, "Nd"},
  68. {61, "Pm"},
  69. {62, "Sm"},
  70. {63, "Eu"},
  71. {64, "Gd"},
  72. {65, "Tb"},
  73. {66, "Dy"},
  74. {67, "Ho"},
  75. {68, "Er"},
  76. {69, "Tm"},
  77. {70, "Yb"},
  78. {71, "Lu"},
  79. {72, "Hf"},
  80. {73, "Ta"},
  81. {74, "W"},
  82. {75, "Re"},
  83. {76, "Os"},
  84. {77, "Ir"},
  85. {78, "Pt"},
  86. {79, "Au"},
  87. {80, "Hg"},
  88. {81, "Tl"},
  89. {82, "Pb"},
  90. {83, "Bi"},
  91. {84, "Po"},
  92. {85, "At"},
  93. {86, "Rn"},
  94. {87, "Fr"},
  95. {88, "Ra"},
  96. {89, "Ac"},
  97. {90, "Th"},
  98. {91, "Pa"},
  99. {92, "U"},
  100. {93, "Np"},
  101. {94, "Pu"},
  102. {95, "Am"},
  103. {96, "Cm"},
  104. {97, "Bk"},
  105. {98, "Cf"},
  106. {99, "Es"},
  107. {100, "Fm"},
  108. {101, "Md"},
  109. {102, "No"},
  110. {103, "Lr"},
  111. {104, "Rf"},
  112. {105, "Db"},
  113. {106, "Sg"},
  114. {107, "Bh"},
  115. {108, "Hs"},
  116. {109, "Mt"},
  117. {110, "Ds"},
  118. {111, "Rg"},
  119. {112, "Cn"},
  120. {113, "Nh"},
  121. {114, "Fl"},
  122. {115, "Mc"},
  123. {116, "Lv"},
  124. {117, "Ts"},
  125. {118, "Og"},
  126. {0,"fin"}
  127. };
  128.  
  129. std::ostream & Compteur::operator << (std::ostream & o)const{
  130.   const_iterator i=begin();
  131.   while (i != end()){
  132.     o << i->first << " : " << i->second;
  133.     if (++i != end()) o << " ";
  134.   }
  135.   return o;
  136. }
  137.  
  138. std::ostream & operator << (std::ostream & o, const Compteur & c){
  139.   return c.operator << (o);
  140. }
  141.  
  142. double AtomeListe::weight(fraction mult)const{
  143.   // const AtomeListe * al;
  144.   double w=0.0;
  145.   if(Zed!=0 && Zed!=-1 ){ /* cas où ce n'est pas un groupe ou un électron */
  146.     w=mendelweight(symb)*nb*mult.i/mult.d;
  147.   }
  148.   else if (Zed==0){ /* cas d'un groupe */
  149.     if (group) w+=group->weight(mult*nb);
  150.   }
  151.   if (suiv) w+=suiv->weight(mult);
  152.   return w;
  153. }
  154.  
  155. void AtomeListe::compte(Compteur &c, fraction mult)const{
  156.   // const AtomeListe * al;
  157.   if(Zed!=0 && Zed!=-1 ){ /* cas où ce n'est pas un groupe ou un électron */
  158.     std::string key(symb);
  159.     c[key] +=1.0*nb*mult.i/mult.d;
  160.   }
  161.   else if (Zed==0){ /* cas d'un groupe */
  162.     if (group) group->compte(c,mult*nb);
  163.   }
  164.   if (suiv) suiv->compte(c,mult);
  165. }
  166.  
  167. void AtomeListe::numerote(int n){
  168.   if(Zed!=0){ /* cas où ce n'est pas un groupe */
  169.     no = n;
  170.   }
  171.   else if (Zed==0){ /* cas d'un groupe */
  172.     no = n;
  173.     if (group) group->numerote();
  174.   }
  175.   if (suiv) suiv->numerote(n+1);
  176. }
  177.  
  178. AtomeListe * AtomeListe::triage(AtomeListe * al){
  179.   AtomeListe * al1;
  180.   if(al->Z()!=0){ /* cas où ce n'est pas un groupe */
  181.     if (al->suiv){
  182.       al->suiv = triage(al->suiv);
  183.     }
  184.     while (al->suiv && al->suiv->Zed!=0 &&
  185.            strcmp(al->symbole(), al->suiv->symbole()) > 0){
  186.       al1=al; al=al->suiv; al1->suiv=al->suiv; al->suiv=triage(al1);
  187.     }
  188.   }
  189.   else{ /* cas d'un groupe */
  190.      if (al->groupe()) al->groupe(triage(al->groupe()));
  191.   }
  192.   return al;
  193. }
  194.  
  195. bool AtomeListe::isEqual(const AtomeListe & a2) const {
  196.   std::stringstream s1, s2;
  197.   printnorm(s1);
  198.   a2.printnorm(s2);
  199.   return s1.str() == s2.str();
  200. }
  201.  
  202. void AtomeListe::printcount(std::ostream & o, const fraction& n, int multiple=1) const{
  203.   if(Zed!=0){ /* cas où ce n'est pas un groupe */
  204.     o << symb;
  205.     o << ':' << n << '*' << multiple*nb;
  206.   }
  207.   else{ /* cas d'un groupe */
  208.     if (group) group->printcount(o,n,nb);
  209.   }  
  210.   if (suiv) {o << ' '; suiv->printcount(o,n,multiple);}
  211. }
  212.  
  213. void AtomeListe::printnorm(std::ostream & o) const{
  214.   if (sqbr) o << "[";
  215.   if(Zed!=0){ /* cas où ce n'est pas un groupe */
  216.     o << symb;
  217.     if (nb!=1) o << nb;
  218.   }
  219.   else{ /* cas d'un groupe */
  220.     o << "(";
  221.     if (group) group->printnorm(o);
  222.     o << ")" << nb;
  223.   }  
  224.   if (suiv) suiv->printnorm(o);
  225.   if (sqbr) o << "]";
  226. }
  227.  
  228. std::ostream & operator << (std::ostream & o, const AtomeListe & l){
  229.   int n;
  230.   const AtomeListe * al;
  231.   if (l.sq()) o << "[";
  232.   if(l.Z()>0 || l.Z()<-1){
  233.     o << "\\mathrm{" << l.symbole() << "}";
  234.   }
  235.   else if (l.Z()==-1){ // cas de l'électron
  236.     o << "\\mathrm{e}";
  237.   }
  238.   else{                // cas des groupes parenthésés
  239.     o << "(";
  240.     if((al=l.groupe())) o << *al;
  241.     o << ")";
  242.   }
  243.   if((n=l.getmolecularite())>1) o << "_{" << n << "}";
  244.   if((al=l.suivant())) o << *al;
  245.   if (l.sq()) o << "]";
  246.   return o;
  247. }
  248.  
  249. // from the header file:
  250. // typedef enum { aqueous, aqueous_explicit, gas, liquid, sol } moltype;
  251. const char* moltypeStr[] = { "", "(aq)", "(g)", "(l)", "(s)" };
  252.  
  253. const std::string Molec::signature()const{
  254.   std::ostringstream o;
  255.   o << liste();
  256.   if (charge()){
  257.     o << "^{";
  258.     if(fabs(1.0*charge())!=1) o << fabs(1.0*charge());
  259.     if(charge()>0) o << "+}"; else o << "-}";
  260.   }
  261.   if (t != aqueous) o << moltypeStr[t];
  262.   return std::string (o.str());
  263. }
  264.  
  265. bool Molec::printcount(std::ostream & o, bool first) const{
  266.   if (!first) o << ", ";
  267.   first=false;
  268.   printnorm(o);
  269.   o << '|';
  270.   al-> printcount(o,nb);
  271.   return first;
  272. }
  273.  
  274. bool Molec::printelec(std::ostream & o, bool first) const{
  275.   if (!first) o << ", ";
  276.   first=false;
  277.   printnorm(o);
  278.   o << '|';
  279.   o << nb << '*' << ch;
  280.   return first;
  281. }
  282.  
  283. bool Molec::printspecies(std::ostream & o, bool first) const{
  284.   if (!first) o << ", ";
  285.   first=false;
  286.   printnorm(o);
  287.   return first;
  288. }
  289.  
  290. void Molec::delete_aq(){
  291.   // retire les attributs aqueux
  292.   if (t==aqueous_explicit) t=aqueous;
  293. }
  294.  
  295. void Molec::printnorm(std::ostream & o)const{
  296.   if (nb!=1) o << nb << " ";
  297.   al-> printnorm(o);
  298.   if (ch) {
  299.     o << "^";
  300.     if(fabs(1.0*ch)!=1) o << fabs(1.0*ch);
  301.     if(ch>0) o << "+"; else o << "-";
  302.   }
  303.   // the aqueous type is the default, so: no _(aq)
  304.   // to have this suffix, on must make the type to aqueous_explicit
  305.   if (!iswater() && !iselectron() && t != aqueous) o << "_"  << moltypeStr[t];
  306. }
  307.  
  308. /**
  309.  * Affiche le coefficient stœchimétrique
  310.  * @param o un flux de sortie
  311.  * @param sign plus ou moins un selon que c'est un produit ou un réactif.
  312.  **/
  313. void Molec::printcoeff(std::ostream & o, int sign)const{
  314.   o << nb * sign;
  315. }
  316.  
  317. void Molec::coeff( fraction f){
  318.   nb.i *= f.i;
  319.   nb.d *= f.d;
  320.   nb.simplifie();
  321. }
  322.  
  323. bool Molec::printNernst(std::ostream & o, const char * prefix){
  324.   switch(t){
  325.   case sol :
  326.   case liquid:
  327.     return 0;
  328.   case aqueous :
  329.   case aqueous_explicit:
  330.     if (iswater() || iselectron()) return 0;
  331.     o << prefix << "[" << *al;
  332.     if (ch){
  333.       o << "^{";
  334.       if(fabs(1.0*ch)!=1) o << fabs(1.0*ch);
  335.       if(ch>0) o << "+}"; else o << "-}";
  336.     }
  337.     if (t != aqueous) o << "_{" << moltypeStr[t] << "}";
  338.     o  <<"]";
  339.     if (nb!=1) {
  340.       o << "^{";
  341.       printNombre(o);
  342.       o << "}";
  343.     }
  344.     return 1;
  345.   case gas :
  346.     o << prefix << "P_{" << *al << "}";
  347.     if (nb!=1) {
  348.       o << "^{";
  349.       printNombre(o);
  350.       o << "}";
  351.     }
  352.     return 1;
  353.   }
  354.   return 0;
  355. }
  356.  
  357. bool Molec::printNernstWIMS(std::ostream & o, bool wantedlatex){
  358.   if (iswater() || iselectron()) {
  359.     return false;
  360.   }
  361.   switch(t){
  362.   case sol :
  363.   case liquid :
  364.     {
  365.       return false;
  366.     }
  367.   case aqueous :
  368.   case aqueous_explicit :
  369.     if(wantedlatex){
  370.       o <<  "[" << *al;
  371.     }else{
  372.       o << "["; al->printnorm(o);
  373.     }
  374.     if (ch){
  375.       if(wantedlatex){
  376.         o << "^{";
  377.       }else{
  378.         o << "^";
  379.       }
  380.       if(fabs(1.0*ch)!=1) o << fabs(1.0*ch);
  381.       if(wantedlatex){
  382.         if(ch>0) o << "+}"; else o << "-}";
  383.       }else{
  384.         if(ch>0) o << "+"; else o << "-";
  385.       }
  386.     }
  387.     o  <<"]";
  388.     if (nb!=1) {
  389.       if(wantedlatex){
  390.         o << "^{";
  391.         if (nb.d==1){
  392.           o << nb.i ;
  393.         }
  394.         else {
  395.           o << "\\frac{" << nb.i << "}{" << nb.d << "}";
  396.         }
  397.         o << "}";
  398.       }else{
  399.         o << "^" << nb;
  400.       }
  401.     }
  402.     return true;
  403.   case gas :
  404.     if(wantedlatex){
  405.       o << "P_{" << *al << "}";
  406.     }else{
  407.       o << "P_"; al->printnorm(o);
  408.     }
  409.     if (nb!=1) {
  410.       if(wantedlatex){
  411.         o << "^{";
  412.         if (nb.d==1){
  413.           o << nb.i ;
  414.         }
  415.         else {
  416.           o << "\\frac{" << nb.i << "}{" << nb.d << "}";
  417.         }
  418.         o << "}";
  419.       }else{
  420.         o << "^" << nb;
  421.       }
  422.     }
  423.     return true;
  424.   }
  425.   return false;
  426. }
  427.  
  428. bool Molec::iswater()const{
  429.   if (t != aqueous) return 0;
  430.   if (signature()==std::string("\\mathrm{H}_{2}\\mathrm{O}") ||
  431.       signature()==std::string("\\mathrm{O}\\mathrm{H}_{2}")) return 1;
  432.   else return 0;
  433. }
  434.  
  435. bool Molec::iselectron()const{
  436.   return (signature()==std::string("\\mathrm{e}^{-}"));
  437. }
  438.  
  439. fraction Molec::nbelectron()const{
  440.   if (iselectron()) return nb;
  441.   else return fraction(0);
  442. }
  443.  
  444. void Molec::add(fraction f){
  445.   nb = nb+f;
  446. }
  447.  
  448. void Molec::sub(fraction f){
  449.   nb = nb-f;
  450. }
  451.  
  452. void Molec::printNombre(std::ostream & o)const{
  453.   if (nb.d==1){
  454.     o << nb.i << "\\,";
  455.   }
  456.   else {
  457.     o << "\\frac{" << nb.i << "}{" << nb.d << "}\\,";
  458.   }
  459. }
  460.  
  461. std::ostream & operator << (std::ostream & o, const Molec & m){
  462.   if (m.nombre() != 1) m.printNombre(o);
  463.   o << m.liste();
  464.   if (m.charge()){
  465.     o << "^{";
  466.     if(fabs(1.0*m.charge())!=1) o << fabs(1.0*m.charge());
  467.     if(m.charge()>0) o << "+}"; else o << "-}";
  468.   }
  469.   if (m.typage() != aqueous && ! m.iselectron()) o << "_{" << moltypeStr[m.typage()] << "}";
  470.   return o;
  471. }
  472.  
  473. int Membre::findMol(const Molec * m){
  474.   // returns the index of a molecule with the same atomlist if any
  475.   // else returns -1.
  476.   int result=-1;
  477.   for(unsigned int i=0; i<size(); i++){
  478.     if ((*this)[i]->eqMol(m)) result=i;
  479.   }
  480.   return result;
  481. }
  482.  
  483. void Membre::addMol(const Molec * m){
  484.   int i = findMol(m);
  485.   if (i < 0){
  486.     push_back(new Molec(*m));
  487.   } else {
  488.     (*this)[i]->add(m->nombre());
  489.   }
  490. }
  491.  
  492. void Membre::addMembre(const Membre * m){
  493.   for(unsigned int i=0; i<m->size(); i++){
  494.     addMol((*m)[i]);
  495.   }
  496. }
  497.  
  498. void Membre::eraseNull(){
  499.   Membre m(*this);
  500.   clear();
  501.   for(unsigned int i=0; i < m.size();i++){
  502.     if (m[i]->nombre().i>0) push_back(m[i]);
  503.   }
  504. }
  505.  
  506. void Membre::compte(Compteur & c)const{
  507.   for(unsigned int i =0; i < size(); i++){
  508.     operator [] (i)->compte(c);
  509.   }
  510. }
  511.  
  512. void Membre::numerote(){
  513.   for (unsigned int i=0; i < size(); i++){
  514.     operator [](i)->numero(i);
  515.     operator [](i)->liste().numerote();
  516.   }
  517. }
  518.  
  519. void Membre::delete_aq(){
  520.   // retire les attributs aqueux
  521.   for (unsigned int i=0; i < size(); i++){
  522.     operator [](i)->delete_aq();
  523.   }  
  524. }
  525.  
  526. void Membre::triage(){
  527.   unsigned int i,j;
  528.   for (i=0; i < size(); i++){
  529.     operator [](i)->triage();
  530.   }
  531.   for (i=0; i < size(); i++){
  532.     for (j=i+1; j < size(); j++){
  533.       if (operator [](i)->signature() > operator [](j)->signature()){
  534.         Molec * m = operator [](i);
  535.         operator [](i) = operator [](j);
  536.         operator [](j) = m;
  537.       }
  538.     }
  539.   }
  540. }
  541.  
  542. void Membre::printcount(std::ostream & o) const{
  543.   bool first=true;
  544.   for(unsigned int i=0; i < size(); i++){
  545.     first=operator[](i)->printcount(o,first);
  546.   }
  547. }
  548.  
  549. void Membre::printelec(std::ostream & o) const{
  550.   bool first=true;
  551.   for(unsigned int i=0; i < size(); i++){
  552.     first=operator[](i)->printelec(o,first);
  553.   }
  554. }
  555.  
  556. void Membre::printspecies(std::ostream & o) const{
  557.   bool first=true;
  558.   for(unsigned int i=0; i < size(); i++){
  559.     first=operator[](i)->printspecies(o,first);
  560.   }
  561. }
  562.  
  563. void Membre::printnorm(std::ostream & o) const{
  564.   for(unsigned int i=0; i < size(); i++){
  565.     operator[](i)->printnorm(o);
  566.     if (i < size()-1) o << " + ";
  567.   }
  568. }
  569.  
  570. /**
  571.  * affiche les coefficients stœchiométriques d'un membre d'équation
  572.  * @param o un flux de sortie
  573.  * @param sign la valeur plus ou moins un selon que les réactifs sont produits
  574.  *             ou consommés.
  575.  **/
  576. void Membre::printcoeff(std::ostream & o, int sign) const{
  577.   for(unsigned int i=0; i < size(); i++){
  578.     operator[](i)->printcoeff(o, sign);
  579.     if (i < size()-1) o << ",";
  580.   }
  581. }
  582.  
  583. void Membre::printweight(std::ostream & o) const{
  584.   for(unsigned int i=0; i < size(); i++){
  585.     o << operator[](i)->weight();
  586.     if (i < size()-1) o << " ";
  587.   }
  588. }
  589.  
  590. void Membre::coeff( fraction f){
  591.   for (unsigned int i=0; i<size(); i++) operator[](i)->coeff(f);
  592. }
  593.  
  594. int Membre::printableNernst(){
  595.   int result=0;
  596.   for (unsigned int i=0; i<size(); i++) {
  597.     if (operator[](i)->typage() != sol &&
  598.         !operator[](i)->iswater() &&
  599.         !operator[](i)->iselectron()) result =1;
  600.   }  
  601.   return result;
  602. }
  603.  
  604. bool Membre::redox()const{
  605.   for (unsigned int i=0; i<size(); i++){
  606.     if ((*this)[i]->iselectron()) /* c'est un électron */ return 1;
  607.   }
  608.   return 0;
  609. }
  610.  
  611. fraction  Membre::nbelectron()const{
  612.   fraction result(0);
  613.  
  614.   for(unsigned int i = 0; i<size(); i++) result=result+(*this)[i]->nbelectron();
  615.   return result;
  616. }
  617.  
  618. void Membre::printNernst(std::ostream & o){
  619.   bool printed = 0;
  620.   const char * prefix="";
  621.   for (unsigned int i=0; i<size(); i++) {
  622.     if (i>0) prefix="\\,";
  623.     if (operator[](i)->printNernst(o, prefix)){
  624.       printed = 1;
  625.     }
  626.   }
  627.   if (!printed) o << "1";
  628. }
  629.  
  630. void Membre::printNernstWIMS(std::ostream & o, bool wantedlatex){
  631.   bool printed = false;
  632.   bool addcomma = false;
  633.   for (unsigned int i=0; i<size(); i++) {
  634.     std::ostringstream w;
  635.     if (operator[](i)->printNernstWIMS(w,wantedlatex)){
  636.       if (addcomma) o << ", ";
  637.       o << w.str();
  638.       printed = true;
  639.       addcomma = true;
  640.     } else {
  641.       addcomma = false;
  642.     }
  643.   }
  644.   if (!printed) o << "1";
  645. }
  646.  
  647. std::ostream & operator << (std::ostream & o, const Membre & m){
  648.   for(unsigned int i=0; i < m.size()-1; i++){
  649.     o << *m[i] << "\\,+\\,";
  650.   }
  651.   o << *m[m.size()-1];
  652.   return o;
  653. }
  654.  
  655. Membre operator & (Membre & m1, Membre & m2){
  656.   Membre result;
  657.   //result.printnorm(std::cout);
  658.   fraction min(1);
  659.   for(Membre::iterator i = m1.begin(); i < m1.end(); i++){
  660.     for(Membre::iterator j = m2.begin(); j < m2.end(); j++){
  661.       if ((*i)->eqMol(*j)){
  662.         Molec *m = new Molec(**i);
  663.         if ((*i)->nb > (*j)->nb){
  664.           min=(*j)->nb;
  665.         }else{
  666.           min=(*i)->nb;
  667.         }
  668.         m->nb=min;
  669.         result.push_back(m);
  670.       }
  671.     }
  672.   }
  673.   return result;
  674. }
  675.  
  676. Membre operator - (Membre & m1, Membre & m2){
  677.   Membre result;
  678.   fraction diff(1);
  679.   for(Membre::iterator i = m1.begin(); i < m1.end(); i++){
  680.     Molec *m = new Molec(**i);
  681.     for(Membre::iterator j = m2.begin(); j < m2.end(); j++){
  682.       if ((*i)->eqMol(*j)){
  683.         diff=(*i)->nb - (*j)->nb;
  684.         m->nb=diff;
  685.       }
  686.     }
  687.     result.push_back(m);
  688.   }
  689.   return result;
  690. }
  691.  
  692. bool Chemeq::valdefined()const{
  693.   return val > MINVAL;
  694. }
  695.  
  696. void Chemeq::addChemeq(const Chemeq * c){
  697.   if (valdefined() && c->valdefined()){
  698.     long double e1=enthalpy(), e2=c->enthalpy();
  699.     fraction n1=nbelectron(), n2=c->nbelectron();
  700.     long double e = e1+e2;
  701.     fraction n=n1+n2;
  702.     if (n.i==0) val=exp(-e/R/T0);
  703.     else val=-e*n.d/n.i/Faraday;
  704.   } else {
  705.     val=MINVAL;
  706.   }
  707.   gauche->addMembre(c->gauche);
  708.   droit->addMembre(c->droit);
  709.   simplifie(true);
  710. }
  711.  
  712. void Chemeq::subChemeq(const Chemeq * c){
  713.   if (valdefined() && c->valdefined()){
  714.     long double e1=enthalpy(), e2=c->enthalpy();
  715.     fraction n1=nbelectron(), n2=c->nbelectron();
  716.     long double e = e1-e2;
  717.     fraction n=n1-n2;
  718.     if (n.i==0) {
  719.     val=exp(-e/R/T0);
  720.     } else{
  721.       val=-e*n.d/n.i/Faraday;
  722.     }
  723.   } else {
  724.     val=MINVAL;
  725.   }
  726.   gauche->addMembre(c->droit);
  727.   droit->addMembre(c->gauche);
  728.   simplifie(true);
  729. }
  730.  
  731. long double Chemeq::enthalpy() const{
  732.   fraction n=nbelectron();
  733.   if (redox()){
  734.     return -val*n.i/n.d*Faraday;
  735.   } else {
  736.     return -R*T0*log(val);
  737.   }
  738. }
  739.  
  740. void Chemeq::simplifie(bool tri=false){
  741.   Membre communs(*gauche & *droit);
  742.   if (communs.size()>0){
  743.     Membre * g, *d;
  744.     g= new Membre(*gauche - communs);
  745.     d= new Membre(*droit  - communs);
  746.     delete gauche;
  747.     delete droit;
  748.     gauche=g;
  749.     droit =d;
  750.   }
  751.   gauche->eraseNull();
  752.   droit->eraseNull();
  753.   if (tri){
  754.     numerote();
  755.     triage();
  756.   }
  757. }
  758.  
  759. void Chemeq::printnorm(std::ostream & o){
  760.   gauche->printnorm(o);
  761.   o << " -> ";
  762.   droit->printnorm(o);
  763.   if (val>MINVAL){
  764.     o << " (";
  765.     if (cste!=std::string("")) o << cste << " = ";
  766.     o << val;
  767.     if (redox()) o << " V";
  768.     o << ")";
  769.   }
  770. }
  771.  
  772. /**
  773.  * Affiche les coefficients stœchiométriques
  774.  **/
  775. void Chemeq::printcoeff(std::ostream & o) const {
  776.   gauche->printcoeff(o, -1);
  777.   o << ";";
  778.   droit->printcoeff(o, 1);
  779. }
  780.  
  781. void Chemeq::printcount(std::ostream & o) const {
  782.   gauche->printcount(o);
  783.   o << "; ";
  784.   droit->printcount(o);
  785. }
  786.  
  787. void Chemeq::printelec(std::ostream & o) const {
  788.   gauche->printelec(o);
  789.   o << "; ";
  790.   droit->printelec(o);
  791. }
  792.  
  793. void Chemeq::printspecies(std::ostream & o) const {
  794.   gauche->printspecies(o);
  795.   o << "; ";
  796.   droit->printspecies(o);
  797. }
  798.  
  799. void Chemeq::printweight(std::ostream & o) const{
  800.   gauche->printweight(o);
  801.   o << " ";
  802.   droit->printweight(o);
  803. }
  804.  
  805. std::string Chemeq::equilibre(){
  806.   std::ostringstream s;
  807.   Compteur cpg, cpd;
  808.   gauche->compte(cpg);
  809.   droit->compte(cpd);
  810.   if(cpg==cpd) s << "OK";
  811.   else s << "ERROR " << cpg << " / " << cpd;
  812.   return std::string(s.str());
  813. }
  814.  
  815. void Chemeq::coeff1(){
  816.   fraction mult = gauche->operator[](0)->nombre();
  817.   mult.inverse();
  818.   gauche->coeff(mult);
  819.   droit->coeff(mult);
  820.   simplifie();
  821.   if (!redox() && valdefined()){
  822.     val = val*mult.i/mult.d;
  823.   }
  824. }
  825.  
  826. void Chemeq::delete_aq(){
  827.   // supprime tous les attributs "aqueux" des molécules ou ions présents
  828.   gauche->delete_aq();
  829.   droit->delete_aq();
  830. }
  831.  
  832. void Chemeq::multiply(int num, int den){
  833.   fraction mult(num,den);
  834.   gauche->coeff(mult);
  835.   droit->coeff(mult);
  836.   simplifie();
  837.   if (!redox() && valdefined()){
  838.     val = val*mult.i/mult.d;
  839.   }
  840. }
  841.  
  842. bool Chemeq::redox()const{
  843.   return gauche->redox() || droit->redox();
  844. }
  845.  
  846. void Chemeq::printNernst(std::ostream & o,
  847.                          std::ostream & w,
  848.                          bool wantedlatex){
  849.   Membre * ga, * dr;
  850.   if (!redox()){
  851.     if (gauche->printableNernst()){
  852.       o << "\\frac{";
  853.       droit->printNernst(o);
  854.       o << "}{";
  855.       gauche->printNernst(o);
  856.       o << "}";
  857.     }
  858.     else {
  859.       droit->printNernst(o);
  860.     }
  861.     droit->printNernstWIMS(w,wantedlatex);
  862.     w << "; ";
  863.     gauche->printNernstWIMS(w,wantedlatex);
  864.     if (val > MINVAL) {
  865.       o << "\\,=\\,";
  866.       if (cste!=std::string("")) o << cste << "\\,=\\,";
  867.       o << valeur_latex();
  868.       if(wantedlatex){
  869.         w << "; " << valeur_latex();
  870.       }else{
  871.         w << "; " << val;
  872.       }
  873.     }
  874.     else{
  875.       o << "\\,=\\,K";
  876.       w << "; K";
  877.     }
  878.   }
  879.   else{ /* c'est une réaction redox  */
  880.     o << "E\\,=\\,";
  881.     if(wantedlatex){
  882.       w << "E\\,=\\,";
  883.     }else{
  884.       w << "E=";
  885.     }
  886.     if (val > MINVAL) {
  887.       o << val;
  888.       w << val << ";";
  889.     }
  890.     else{
  891.       o << "E_{0}";
  892.       if(wantedlatex){
  893.         w << "E_{0};";
  894.       }else{
  895.         w << "E0;";
  896.       }
  897.     }
  898.     o << "\\,+\\,\\frac{R\\,T}{";
  899.     o << gauche->nbelectron()+droit->nbelectron() << "\\,F}";
  900.     o << "\\log";
  901.     w << gauche->nbelectron()+droit->nbelectron() << ";";
  902.     if (gauche->redox()){ /* c'est une réduction */
  903.       ga=gauche; dr=droit;
  904.     }
  905.     else{ /* c'est une oxydation */
  906.       ga=droit; dr=gauche;
  907.     }
  908.     if (dr->printableNernst()){
  909.       o << "\\frac{";
  910.       ga->printNernst(o);
  911.       o << "}{";
  912.       dr->printNernst(o);
  913.       o << "}";
  914.     }
  915.     else {
  916.       o << "(";
  917.       ga->printNernst(o);
  918.       o << ")";
  919.     }
  920.     // implanter la sortie pour Wims ici.
  921.     dr->printNernstWIMS(w,wantedlatex);
  922.     w << "; ";
  923.     ga->printNernstWIMS(w,wantedlatex);
  924.   }
  925. }
  926.  
  927. std::string Chemeq::valeur_latex()const{
  928.   std::ostringstream so;
  929.   so << val;
  930.   std::string s(so.str());
  931.   std::string::size_type epos=s.find('e',0);
  932.   if (epos!=std::string::npos){
  933.     s.erase(epos,1);
  934.     s.insert(epos,"\\times 10^{");
  935.     s=s+"}";
  936.   }
  937.   return (std::string) s;
  938. }
  939.  
  940. std::ostream & operator << (std::ostream & o, const Chemeq & c){
  941.   if (c.is_equilibrium()){ /* equilibria must be rendered with two arrows */
  942.     o << *c.membregauche() << "\\,\\leftrightharpoons\\," << *c.membredroit();
  943.   } else {
  944.     o << *c.membregauche() << "\\,\\longrightarrow\\," << *c.membredroit();
  945.   }
  946.   if (c.valeur() > MINVAL) {
  947.     o << "\\,(";
  948.     if (c.constante()!=std::string("")) o << c.constante() << "\\,=\\,";
  949.     o << c.valeur_latex();
  950.     if (c.redox()) o << " V";
  951.     o << ")";
  952.   }
  953.   return o;
  954. }
  955.  
  956. std::ostream & operator << (std::ostream & o, fraction f){
  957.   o << f.i;
  958.   if (f.d!=1) o << '/' << f.d;
  959.   return o;
  960. }
  961.  
  962. fraction operator * (fraction f, int m){
  963.   fraction result = fraction(f.i*m, f.d);
  964.   result.simplifie();
  965.   return result;
  966. }
  967.  
  968. fraction operator * (int m, fraction f){
  969.   fraction result = fraction(f.i*m, f.d);
  970.   result.simplifie();
  971.   return result;
  972. }
  973.  
  974. fraction operator * (fraction f, fraction m)
  975. {
  976.   fraction result = fraction(f.i*m.i, f.d*m.d);
  977.   result.simplifie();
  978.   return result;
  979. }
  980.  
  981. fraction operator + (fraction f, fraction g){
  982.   fraction result = fraction(f.i*g.d+g.i*f.d, f.d*g.d);
  983.   result.simplifie();
  984.   return result;
  985. }
  986.  
  987. fraction operator - (fraction f, fraction g){
  988.   fraction result = fraction(f.i*g.d-g.i*f.d, f.d*g.d);
  989.   result.simplifie();
  990.   return result;
  991. }
  992.  
  993. const fraction & minFraction(const fraction& f1, const fraction &f2){
  994.   if (f1.i*f2.d > f2.i*f1.d) return f1;
  995.   else return f2;
  996. }
  997.  
  998. void fraction::simplifie(){
  999.   int maxprem = 23;
  1000.   int premiers[]={2,3,5,7,11,13,17,19,23,29};
  1001.   int n;
  1002.  
  1003.   for (n=0; premiers[n]<= maxprem; n++){
  1004.     while (i % premiers[n] == 0 && d % premiers[n] == 0){
  1005.       i /= premiers[n]; d /= premiers[n];
  1006.     }
  1007.   }
  1008. }
  1009.  
  1010. bool operator > (fraction f, int i){
  1011.   return f.i > f.d*i;
  1012. }
  1013.  
  1014. bool operator > (fraction f1, fraction f2){
  1015.   return f1.i*f2.d > f1.d*f2.i;
  1016. }
  1017.  
  1018. bool operator != (fraction f, int i){
  1019.   return f.i != f.d*i;
  1020. }
  1021.  
  1022. double mendelweight(int i){
  1023.   if (i>=0) return strtod (table[i].info[WEIGHT],0); else return 0.0;
  1024. }
  1025.  
  1026. int findmendel(const char * symb){
  1027.   int i=0;
  1028.   while (table[i].info[0] && strcmp(table[i].info[SYMBOL], symb) != 0) i++;
  1029.   if (table[i].info[0]) return i; else return -1;
  1030. }
  1031.  
  1032. double mendelweight(const char * symb){
  1033.   int i;
  1034.   i = findmendel(symb);
  1035.   return mendelweight(i);
  1036. }
  1037.