Subversion Repositories wimsdev

Rev

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

Rev Author Line No. Line
104 bpr 1
// -*- coding: utf-8 -*-
10 reyssat 2
#include "chemeq.h"
472 georgesk 3
#include <cmath>
4
#include <cstdlib>
10 reyssat 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"},
17747 georgesk 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"},
10 reyssat 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{
13325 georgesk 143
  // const AtomeListe * al;
10 reyssat 144
  double w=0.0;
104 bpr 145
  if(Zed!=0 && Zed!=-1 ){ /* cas où ce n'est pas un groupe ou un électron */
10 reyssat 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{
13325 georgesk 156
  // const AtomeListe * al;
104 bpr 157
  if(Zed!=0 && Zed!=-1 ){ /* cas où ce n'est pas un groupe ou un électron */
10 reyssat 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){
104 bpr 168
  if(Zed!=0){ /* cas où ce n'est pas un groupe */
10 reyssat 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;
104 bpr 180
  if(al->Z()!=0){ /* cas où ce n'est pas un groupe */
10 reyssat 181
    if (al->suiv){
182
      al->suiv = triage(al->suiv);
183
    }
184
    while (al->suiv && al->suiv->Zed!=0 &&
17747 georgesk 185
           strcmp(al->symbole(), al->suiv->symbole()) > 0){
10 reyssat 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
 
820 georgesk 195
bool AtomeListe::isEqual(const AtomeListe & a2) const {
10 reyssat 196
  std::stringstream s1, s2;
820 georgesk 197
  printnorm(s1);
10 reyssat 198
  a2.printnorm(s2);
104 bpr 199
  return s1.str() == s2.str();
10 reyssat 200
}
201
 
202
void AtomeListe::printcount(std::ostream & o, const fraction& n, int multiple=1) const{
104 bpr 203
  if(Zed!=0){ /* cas où ce n'est pas un groupe */
10 reyssat 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 << "[";
104 bpr 215
  if(Zed!=0){ /* cas où ce n'est pas un groupe */
10 reyssat 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){
7222 georgesk 233
    o << "\\mathrm{" << l.symbole() << "}";
10 reyssat 234
  }
104 bpr 235
  else if (l.Z()==-1){ // cas de l'électron
7222 georgesk 236
    o << "\\mathrm{e}";
10 reyssat 237
  }
104 bpr 238
  else{                // cas des groupes parenthésés
10 reyssat 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
 
12963 georgesk 249
// from the header file:
250
// typedef enum { aqueous, aqueous_explicit, gas, liquid, sol } moltype;
251
const char* moltypeStr[] = { "", "(aq)", "(g)", "(l)", "(s)" };
10 reyssat 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
 
17747 georgesk 290
void Molec::delete_aq(){
291
  // retire les attributs aqueux
292
  if (t==aqueous_explicit) t=aqueous;
293
}
294
 
10 reyssat 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
  }
12963 georgesk 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];
10 reyssat 306
}
307
 
17770 georgesk 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
 
10 reyssat 317
void Molec::coeff( fraction f){
318
  nb.i *= f.i;
319
  nb.d *= f.d;
320
  nb.simplifie();
321
}
322
 
104 bpr 323
bool Molec::printNernst(std::ostream & o, const char * prefix){
10 reyssat 324
  switch(t){
13325 georgesk 325
  case sol :
326
  case liquid:
327
    return 0;
10 reyssat 328
  case aqueous :
13325 georgesk 329
  case aqueous_explicit:
10 reyssat 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
  }
13325 georgesk 354
  return 0;
10 reyssat 355
}
356
 
472 georgesk 357
bool Molec::printNernstWIMS(std::ostream & o, bool wantedlatex){
358
  if (iswater() || iselectron()) {
359
    return false;
360
  }
361
  switch(t){
13325 georgesk 362
  case sol :
363
  case liquid :
364
    {
365
      return false;
366
    }
472 georgesk 367
  case aqueous :
13325 georgesk 368
  case aqueous_explicit :
472 georgesk 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
 
10 reyssat 428
bool Molec::iswater()const{
429
  if (t != aqueous) return 0;
7222 georgesk 430
  if (signature()==std::string("\\mathrm{H}_{2}\\mathrm{O}") ||
431
      signature()==std::string("\\mathrm{O}\\mathrm{H}_{2}")) return 1;
10 reyssat 432
  else return 0;
433
}
434
 
435
bool Molec::iselectron()const{
7222 georgesk 436
  return (signature()==std::string("\\mathrm{e}^{-}"));
10 reyssat 437
}
438
 
439
fraction Molec::nbelectron()const{
440
  if (iselectron()) return nb;
441
  else return fraction(0);
442
}
443
 
104 bpr 444
void Molec::add(fraction f){
445
  nb = nb+f;
446
}
447
 
448
void Molec::sub(fraction f){
449
  nb = nb-f;
450
}
451
 
10 reyssat 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
  }
7222 georgesk 469
  if (m.typage() != aqueous && ! m.iselectron()) o << "_{" << moltypeStr[m.typage()] << "}";
10 reyssat 470
  return o;
471
}
472
 
104 bpr 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;
13325 georgesk 477
  for(unsigned int i=0; i<size(); i++){
104 bpr 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){
13325 georgesk 493
  for(unsigned int i=0; i<m->size(); i++){
104 bpr 494
    addMol((*m)[i]);
495
  }
496
}
497
 
498
void Membre::eraseNull(){
499
  Membre m(*this);
500
  clear();
13325 georgesk 501
  for(unsigned int i=0; i < m.size();i++){
104 bpr 502
    if (m[i]->nombre().i>0) push_back(m[i]);
503
  }
504
}
505
 
10 reyssat 506
void Membre::compte(Compteur & c)const{
13325 georgesk 507
  for(unsigned int i =0; i < size(); i++){
10 reyssat 508
    operator [] (i)->compte(c);
509
  }
510
}
511
 
512
void Membre::numerote(){
13325 georgesk 513
  for (unsigned int i=0; i < size(); i++){
10 reyssat 514
    operator [](i)->numero(i);
515
    operator [](i)->liste().numerote();
516
  }
517
}
518
 
17747 georgesk 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
 
10 reyssat 526
void Membre::triage(){
13325 georgesk 527
  unsigned int i,j;
10 reyssat 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;
13325 georgesk 544
  for(unsigned int i=0; i < size(); i++){
10 reyssat 545
    first=operator[](i)->printcount(o,first);
546
  }
547
}
548
 
549
void Membre::printelec(std::ostream & o) const{
550
  bool first=true;
13325 georgesk 551
  for(unsigned int i=0; i < size(); i++){
10 reyssat 552
    first=operator[](i)->printelec(o,first);
553
  }
554
}
555
 
556
void Membre::printspecies(std::ostream & o) const{
557
  bool first=true;
13325 georgesk 558
  for(unsigned int i=0; i < size(); i++){
10 reyssat 559
    first=operator[](i)->printspecies(o,first);
560
  }
561
}
562
 
563
void Membre::printnorm(std::ostream & o) const{
13325 georgesk 564
  for(unsigned int i=0; i < size(); i++){
10 reyssat 565
    operator[](i)->printnorm(o);
566
    if (i < size()-1) o << " + ";
567
  }
568
}
569
 
17770 georgesk 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
 
10 reyssat 583
void Membre::printweight(std::ostream & o) const{
13325 georgesk 584
  for(unsigned int i=0; i < size(); i++){
10 reyssat 585
    o << operator[](i)->weight();
586
    if (i < size()-1) o << " ";
587
  }
588
}
589
 
590
void Membre::coeff( fraction f){
13325 georgesk 591
  for (unsigned int i=0; i<size(); i++) operator[](i)->coeff(f);
10 reyssat 592
}
593
 
594
int Membre::printableNernst(){
595
  int result=0;
13325 georgesk 596
  for (unsigned int i=0; i<size(); i++) {
10 reyssat 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{
13325 georgesk 605
  for (unsigned int i=0; i<size(); i++){
104 bpr 606
    if ((*this)[i]->iselectron()) /* c'est un électron */ return 1;
10 reyssat 607
  }
608
  return 0;
609
}
610
 
611
fraction  Membre::nbelectron()const{
612
  fraction result(0);
613
 
13325 georgesk 614
  for(unsigned int i = 0; i<size(); i++) result=result+(*this)[i]->nbelectron();
10 reyssat 615
  return result;
616
}
617
 
618
void Membre::printNernst(std::ostream & o){
619
  bool printed = 0;
104 bpr 620
  const char * prefix="";
13325 georgesk 621
  for (unsigned int i=0; i<size(); i++) {
10 reyssat 622
    if (i>0) prefix="\\,";
623
    if (operator[](i)->printNernst(o, prefix)){
624
      printed = 1;
625
    }
626
  }
627
  if (!printed) o << "1";
628
}
629
 
472 georgesk 630
void Membre::printNernstWIMS(std::ostream & o, bool wantedlatex){
631
  bool printed = false;
632
  bool addcomma = false;
13325 georgesk 633
  for (unsigned int i=0; i<size(); i++) {
472 georgesk 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
 
10 reyssat 647
std::ostream & operator << (std::ostream & o, const Membre & m){
13325 georgesk 648
  for(unsigned int i=0; i < m.size()-1; i++){
10 reyssat 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;
820 georgesk 657
  //result.printnorm(std::cout);
10 reyssat 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++){
820 georgesk 661
      if ((*i)->eqMol(*j)){
10 reyssat 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++){
820 georgesk 682
      if ((*i)->eqMol(*j)){
10 reyssat 683
        diff=(*i)->nb - (*j)->nb;
684
        m->nb=diff;
685
      }
686
    }
687
    result.push_back(m);
688
  }
689
  return result;
690
}
691
 
104 bpr 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;
472 georgesk 702
    if (n.i==0) val=exp(-e/R/T0);
104 bpr 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) {
472 georgesk 719
    val=exp(-e/R/T0);
104 bpr 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 {
472 georgesk 736
    return -R*T0*log(val);
104 bpr 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
 
10 reyssat 759
void Chemeq::printnorm(std::ostream & o){
760
  gauche->printnorm(o);
761
  o << " -> ";
762
  droit->printnorm(o);
104 bpr 763
  if (val>MINVAL){
10 reyssat 764
    o << " (";
765
    if (cste!=std::string("")) o << cste << " = ";
766
    o << val;
767
    if (redox()) o << " V";
768
    o << ")";
769
  }
770
}
771
 
17770 georgesk 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
 
10 reyssat 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);
104 bpr 820
  simplifie();
110 bpr 821
  if (!redox() && valdefined()){
104 bpr 822
    val = val*mult.i/mult.d;
10 reyssat 823
  }
104 bpr 824
}
825
 
17747 georgesk 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
 
104 bpr 832
void Chemeq::multiply(int num, int den){
833
  fraction mult(num,den);
834
  gauche->coeff(mult);
835
  droit->coeff(mult);
836
  simplifie();
110 bpr 837
  if (!redox() && valdefined()){
10 reyssat 838
    val = val*mult.i/mult.d;
839
  }
840
}
841
 
842
bool Chemeq::redox()const{
843
  return gauche->redox() || droit->redox();
844
}
845
 
472 georgesk 846
void Chemeq::printNernst(std::ostream & o,
847
                         std::ostream & w,
848
                         bool wantedlatex){
10 reyssat 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
    }
472 georgesk 861
    droit->printNernstWIMS(w,wantedlatex);
862
    w << "; ";
863
    gauche->printNernstWIMS(w,wantedlatex);
104 bpr 864
    if (val > MINVAL) {
10 reyssat 865
      o << "\\,=\\,";
866
      if (cste!=std::string("")) o << cste << "\\,=\\,";
104 bpr 867
      o << valeur_latex();
472 georgesk 868
      if(wantedlatex){
869
        w << "; " << valeur_latex();
870
      }else{
871
        w << "; " << val;
872
      }
10 reyssat 873
    }
874
    else{
875
      o << "\\,=\\,K";
472 georgesk 876
      w << "; K";
10 reyssat 877
    }
878
  }
472 georgesk 879
  else{ /* c'est une réaction redox  */
10 reyssat 880
    o << "E\\,=\\,";
472 georgesk 881
    if(wantedlatex){
882
      w << "E\\,=\\,";
883
    }else{
884
      w << "E=";
885
    }
104 bpr 886
    if (val > MINVAL) {
10 reyssat 887
      o << val;
472 georgesk 888
      w << val << ";";
10 reyssat 889
    }
890
    else{
891
      o << "E_{0}";
472 georgesk 892
      if(wantedlatex){
893
        w << "E_{0};";
894
      }else{
895
        w << "E0;";
896
      }
10 reyssat 897
    }
898
    o << "\\,+\\,\\frac{R\\,T}{";
899
    o << gauche->nbelectron()+droit->nbelectron() << "\\,F}";
900
    o << "\\log";
472 georgesk 901
    w << gauche->nbelectron()+droit->nbelectron() << ";";
104 bpr 902
    if (gauche->redox()){ /* c'est une réduction */
10 reyssat 903
      ga=gauche; dr=droit;
904
    }
905
    else{ /* c'est une oxydation */
906
      ga=droit; dr=gauche;
907
    }
908
    if (dr->printableNernst()){
472 georgesk 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);
10 reyssat 924
  }
925
}
926
 
104 bpr 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
 
10 reyssat 940
std::ostream & operator << (std::ostream & o, const Chemeq & c){
13121 georgesk 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
  }
104 bpr 946
  if (c.valeur() > MINVAL) {
10 reyssat 947
    o << "\\,(";
948
    if (c.constante()!=std::string("")) o << c.constante() << "\\,=\\,";
104 bpr 949
    o << c.valeur_latex();
10 reyssat 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
 
104 bpr 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
 
10 reyssat 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
}