Subversion Repositories wimsdev

Rev

Rev 12963 | Rev 13325 | Go to most recent revision | 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"},
117
{110, "Uun"},
118
{111, "Uuu"},
119
{112, "Uub"},
120
{113, "Uut"},
121
{114, "Uuq"},
122
{115, "Uup"},
123
{116, "Uuh"},
124
{117, "Uus"},
125
{118, "Uuo"},
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;
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{
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 &&
185
           strcmp(al->symbole(), al->suiv->symbole()) > 1){
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
 
290
void Molec::printnorm(std::ostream & o)const{
291
  if (nb!=1) o << nb << " ";
292
  al-> printnorm(o);
293
  if (ch) {
294
    o << "^";
295
    if(fabs(1.0*ch)!=1) o << fabs(1.0*ch);
296
    if(ch>0) o << "+"; else o << "-";
297
  }
12963 georgesk 298
  // the aqueous type is the default, so: no _(aq)
299
  // to have this suffix, on must make the type to aqueous_explicit
300
  if (!iswater() && !iselectron() && t != aqueous) o << "_"  << moltypeStr[t];
10 reyssat 301
}
302
 
303
void Molec::coeff( fraction f){
304
  nb.i *= f.i;
305
  nb.d *= f.d;
306
  nb.simplifie();
307
}
308
 
104 bpr 309
bool Molec::printNernst(std::ostream & o, const char * prefix){
10 reyssat 310
  switch(t){
311
  case sol : return 0;
312
  case aqueous :
313
    if (iswater() || iselectron()) return 0;
314
    o << prefix << "[" << *al;
315
    if (ch){
316
      o << "^{";
317
      if(fabs(1.0*ch)!=1) o << fabs(1.0*ch);
318
      if(ch>0) o << "+}"; else o << "-}";
319
    }
320
    if (t != aqueous) o << "_{" << moltypeStr[t] << "}";
321
    o  <<"]";
322
    if (nb!=1) {
323
      o << "^{";
324
      printNombre(o);
325
      o << "}";
326
    }
327
    return 1;
328
  case gas :
329
    o << prefix << "P_{" << *al << "}";
330
    if (nb!=1) {
331
      o << "^{";
332
      printNombre(o);
333
      o << "}";
334
    }
335
    return 1;
336
  }
337
}
338
 
472 georgesk 339
bool Molec::printNernstWIMS(std::ostream & o, bool wantedlatex){
340
  if (iswater() || iselectron()) {
341
    return false;
342
  }
343
  switch(t){
344
  case sol : {
345
    return false;
346
  }
347
  case aqueous :
348
    if(wantedlatex){
349
      o <<  "[" << *al;
350
    }else{
351
      o << "["; al->printnorm(o);
352
    }
353
    if (ch){
354
      if(wantedlatex){
355
        o << "^{";
356
      }else{
357
        o << "^";
358
      }
359
      if(fabs(1.0*ch)!=1) o << fabs(1.0*ch);
360
      if(wantedlatex){
361
        if(ch>0) o << "+}"; else o << "-}";
362
      }else{
363
        if(ch>0) o << "+"; else o << "-";
364
      }
365
    }
366
    o  <<"]";
367
    if (nb!=1) {
368
      if(wantedlatex){
369
        o << "^{";
370
        if (nb.d==1){
371
          o << nb.i ;
372
        }
373
        else {
374
          o << "\\frac{" << nb.i << "}{" << nb.d << "}";
375
        }
376
        o << "}";
377
      }else{
378
        o << "^" << nb;
379
      }
380
    }
381
    return true;
382
  case gas :
383
    if(wantedlatex){
384
      o << "P_{" << *al << "}";
385
    }else{
386
      o << "P_"; al->printnorm(o);
387
    }
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
  }
404
  return false;
405
}
406
 
10 reyssat 407
bool Molec::iswater()const{
408
  if (t != aqueous) return 0;
7222 georgesk 409
  if (signature()==std::string("\\mathrm{H}_{2}\\mathrm{O}") ||
410
      signature()==std::string("\\mathrm{O}\\mathrm{H}_{2}")) return 1;
10 reyssat 411
  else return 0;
412
}
413
 
414
bool Molec::iselectron()const{
7222 georgesk 415
  return (signature()==std::string("\\mathrm{e}^{-}"));
10 reyssat 416
}
417
 
418
fraction Molec::nbelectron()const{
419
  if (iselectron()) return nb;
420
  else return fraction(0);
421
}
422
 
104 bpr 423
void Molec::add(fraction f){
424
  nb = nb+f;
425
}
426
 
427
void Molec::sub(fraction f){
428
  nb = nb-f;
429
}
430
 
10 reyssat 431
void Molec::printNombre(std::ostream & o)const{
432
  if (nb.d==1){
433
    o << nb.i << "\\,";
434
  }
435
  else {
436
    o << "\\frac{" << nb.i << "}{" << nb.d << "}\\,";
437
  }
438
}
439
 
440
std::ostream & operator << (std::ostream & o, const Molec & m){
441
  if (m.nombre() != 1) m.printNombre(o);
442
  o << m.liste();
443
  if (m.charge()){
444
    o << "^{";
445
    if(fabs(1.0*m.charge())!=1) o << fabs(1.0*m.charge());
446
    if(m.charge()>0) o << "+}"; else o << "-}";
447
  }
7222 georgesk 448
  if (m.typage() != aqueous && ! m.iselectron()) o << "_{" << moltypeStr[m.typage()] << "}";
10 reyssat 449
  return o;
450
}
451
 
104 bpr 452
int Membre::findMol(const Molec * m){
453
  // returns the index of a molecule with the same atomlist if any
454
  // else returns -1.
455
  int result=-1;
456
  for(int i=0; i<size(); i++){
457
    if ((*this)[i]->eqMol(m)) result=i;
458
  }
459
  return result;
460
}
461
 
462
void Membre::addMol(const Molec * m){
463
  int i = findMol(m);
464
  if (i < 0){
465
    push_back(new Molec(*m));
466
  } else {
467
    (*this)[i]->add(m->nombre());
468
  }
469
}
470
 
471
void Membre::addMembre(const Membre * m){
472
  for(int i=0; i<m->size(); i++){
473
    addMol((*m)[i]);
474
  }
475
}
476
 
477
void Membre::eraseNull(){
478
  Membre m(*this);
479
  clear();
480
  for(int i=0; i < m.size();i++){
481
    if (m[i]->nombre().i>0) push_back(m[i]);
482
  }
483
}
484
 
10 reyssat 485
void Membre::compte(Compteur & c)const{
486
  for(int i =0; i < size(); i++){
487
    operator [] (i)->compte(c);
488
  }
489
}
490
 
491
void Membre::numerote(){
492
  for (int i=0; i < size(); i++){
493
    operator [](i)->numero(i);
494
    operator [](i)->liste().numerote();
495
  }
496
}
497
 
498
void Membre::triage(){
499
  int i,j;
500
  for (i=0; i < size(); i++){
501
    operator [](i)->triage();
502
  }
503
  for (i=0; i < size(); i++){
504
    for (j=i+1; j < size(); j++){
505
      if (operator [](i)->signature() > operator [](j)->signature()){
506
        Molec * m = operator [](i);
507
        operator [](i) = operator [](j);
508
        operator [](j) = m;
509
      }
510
    }
511
  }
512
}
513
 
514
void Membre::printcount(std::ostream & o) const{
515
  bool first=true;
516
  for(int i=0; i < size(); i++){
517
    first=operator[](i)->printcount(o,first);
518
  }
519
}
520
 
521
void Membre::printelec(std::ostream & o) const{
522
  bool first=true;
523
  for(int i=0; i < size(); i++){
524
    first=operator[](i)->printelec(o,first);
525
  }
526
}
527
 
528
void Membre::printspecies(std::ostream & o) const{
529
  bool first=true;
530
  for(int i=0; i < size(); i++){
531
    first=operator[](i)->printspecies(o,first);
532
  }
533
}
534
 
535
void Membre::printnorm(std::ostream & o) const{
536
  for(int i=0; i < size(); i++){
537
    operator[](i)->printnorm(o);
538
    if (i < size()-1) o << " + ";
539
  }
540
}
541
 
542
void Membre::printweight(std::ostream & o) const{
543
  for(int i=0; i < size(); i++){
544
    o << operator[](i)->weight();
545
    if (i < size()-1) o << " ";
546
  }
547
}
548
 
549
void Membre::coeff( fraction f){
550
  for (int i=0; i<size(); i++) operator[](i)->coeff(f);
551
}
552
 
553
int Membre::printableNernst(){
554
  int result=0;
555
  for (int i=0; i<size(); i++) {
556
    if (operator[](i)->typage() != sol &&
557
        !operator[](i)->iswater() &&
558
        !operator[](i)->iselectron()) result =1;
559
  }  
560
  return result;
561
}
562
 
563
bool Membre::redox()const{
564
  for (int i=0; i<size(); i++){
104 bpr 565
    if ((*this)[i]->iselectron()) /* c'est un électron */ return 1;
10 reyssat 566
  }
567
  return 0;
568
}
569
 
570
fraction  Membre::nbelectron()const{
571
  fraction result(0);
572
 
573
  for(int i = 0; i<size(); i++) result=result+(*this)[i]->nbelectron();
574
  return result;
575
}
576
 
577
void Membre::printNernst(std::ostream & o){
578
  bool printed = 0;
104 bpr 579
  const char * prefix="";
10 reyssat 580
  for (int i=0; i<size(); i++) {
581
    if (i>0) prefix="\\,";
582
    if (operator[](i)->printNernst(o, prefix)){
583
      printed = 1;
584
    }
585
  }
586
  if (!printed) o << "1";
587
}
588
 
472 georgesk 589
void Membre::printNernstWIMS(std::ostream & o, bool wantedlatex){
590
  bool printed = false;
591
  bool addcomma = false;
592
  for (int i=0; i<size(); i++) {
593
    std::ostringstream w;
594
    if (operator[](i)->printNernstWIMS(w,wantedlatex)){
595
      if (addcomma) o << ", ";
596
      o << w.str();
597
      printed = true;
598
      addcomma = true;
599
    } else {
600
      addcomma = false;
601
    }
602
  }
603
  if (!printed) o << "1";
604
}
605
 
10 reyssat 606
std::ostream & operator << (std::ostream & o, const Membre & m){
607
  for(int i=0; i < m.size()-1; i++){
608
    o << *m[i] << "\\,+\\,";
609
  }
610
  o << *m[m.size()-1];
611
  return o;
612
}
613
 
614
Membre operator & (Membre & m1, Membre & m2){
615
  Membre result;
820 georgesk 616
  //result.printnorm(std::cout);
10 reyssat 617
  fraction min(1);
618
  for(Membre::iterator i = m1.begin(); i < m1.end(); i++){
619
    for(Membre::iterator j = m2.begin(); j < m2.end(); j++){
820 georgesk 620
      if ((*i)->eqMol(*j)){
10 reyssat 621
        Molec *m = new Molec(**i);
622
        if ((*i)->nb > (*j)->nb){
623
          min=(*j)->nb;
624
        }else{
625
          min=(*i)->nb;
626
        }
627
        m->nb=min;
628
        result.push_back(m);
629
      }
630
    }
631
  }
632
  return result;
633
}
634
 
635
Membre operator - (Membre & m1, Membre & m2){
636
  Membre result;
637
  fraction diff(1);
638
  for(Membre::iterator i = m1.begin(); i < m1.end(); i++){
639
    Molec *m = new Molec(**i);
640
    for(Membre::iterator j = m2.begin(); j < m2.end(); j++){
820 georgesk 641
      if ((*i)->eqMol(*j)){
10 reyssat 642
        diff=(*i)->nb - (*j)->nb;
643
        m->nb=diff;
644
      }
645
    }
646
    result.push_back(m);
647
  }
648
  return result;
649
}
650
 
104 bpr 651
bool Chemeq::valdefined()const{
652
  return val > MINVAL;
653
}
654
 
655
void Chemeq::addChemeq(const Chemeq * c){
656
  if (valdefined() && c->valdefined()){
657
    long double e1=enthalpy(), e2=c->enthalpy();
658
    fraction n1=nbelectron(), n2=c->nbelectron();
659
    long double e = e1+e2;
660
    fraction n=n1+n2;
472 georgesk 661
    if (n.i==0) val=exp(-e/R/T0);
104 bpr 662
    else val=-e*n.d/n.i/Faraday;
663
  } else {
664
    val=MINVAL;
665
  }
666
  gauche->addMembre(c->gauche);
667
  droit->addMembre(c->droit);
668
  simplifie(true);
669
}
670
 
671
void Chemeq::subChemeq(const Chemeq * c){
672
  if (valdefined() && c->valdefined()){
673
    long double e1=enthalpy(), e2=c->enthalpy();
674
    fraction n1=nbelectron(), n2=c->nbelectron();
675
    long double e = e1-e2;
676
    fraction n=n1-n2;
677
    if (n.i==0) {
472 georgesk 678
    val=exp(-e/R/T0);
104 bpr 679
    } else{
680
      val=-e*n.d/n.i/Faraday;
681
    }
682
  } else {
683
    val=MINVAL;
684
  }
685
  gauche->addMembre(c->droit);
686
  droit->addMembre(c->gauche);
687
  simplifie(true);
688
}
689
 
690
long double Chemeq::enthalpy() const{
691
  fraction n=nbelectron();
692
  if (redox()){
693
    return -val*n.i/n.d*Faraday;
694
  } else {
472 georgesk 695
    return -R*T0*log(val);
104 bpr 696
  }
697
}
698
 
699
void Chemeq::simplifie(bool tri=false){
700
  Membre communs(*gauche & *droit);
701
  if (communs.size()>0){
702
    Membre * g, *d;
703
    g= new Membre(*gauche - communs);
704
    d= new Membre(*droit  - communs);
705
    delete gauche;
706
    delete droit;
707
    gauche=g;
708
    droit =d;
709
  }
710
  gauche->eraseNull();
711
  droit->eraseNull();
712
  if (tri){
713
    numerote();
714
    triage();
715
  }
716
}
717
 
10 reyssat 718
void Chemeq::printnorm(std::ostream & o){
719
  gauche->printnorm(o);
720
  o << " -> ";
721
  droit->printnorm(o);
104 bpr 722
  if (val>MINVAL){
10 reyssat 723
    o << " (";
724
    if (cste!=std::string("")) o << cste << " = ";
725
    o << val;
726
    if (redox()) o << " V";
727
    o << ")";
728
  }
729
}
730
 
731
void Chemeq::printcount(std::ostream & o) const {
732
  gauche->printcount(o);
733
  o << "; ";
734
  droit->printcount(o);
735
}
736
 
737
void Chemeq::printelec(std::ostream & o) const {
738
  gauche->printelec(o);
739
  o << "; ";
740
  droit->printelec(o);
741
}
742
 
743
void Chemeq::printspecies(std::ostream & o) const {
744
  gauche->printspecies(o);
745
  o << "; ";
746
  droit->printspecies(o);
747
}
748
 
749
void Chemeq::printweight(std::ostream & o) const{
750
  gauche->printweight(o);
751
  o << " ";
752
  droit->printweight(o);
753
}
754
 
755
std::string Chemeq::equilibre(){
756
  std::ostringstream s;
757
  Compteur cpg, cpd;
758
  gauche->compte(cpg);
759
  droit->compte(cpd);
760
  if(cpg==cpd) s << "OK";
761
  else s << "ERROR " << cpg << " / " << cpd;
762
  return std::string(s.str());
763
}
764
 
765
void Chemeq::coeff1(){
766
  fraction mult = gauche->operator[](0)->nombre();
767
  mult.inverse();
768
  gauche->coeff(mult);
769
  droit->coeff(mult);
104 bpr 770
  simplifie();
110 bpr 771
  if (!redox() && valdefined()){
104 bpr 772
    val = val*mult.i/mult.d;
10 reyssat 773
  }
104 bpr 774
}
775
 
776
void Chemeq::multiply(int num, int den){
777
  fraction mult(num,den);
778
  gauche->coeff(mult);
779
  droit->coeff(mult);
780
  simplifie();
110 bpr 781
  if (!redox() && valdefined()){
10 reyssat 782
    val = val*mult.i/mult.d;
783
  }
784
}
785
 
786
bool Chemeq::redox()const{
787
  return gauche->redox() || droit->redox();
788
}
789
 
472 georgesk 790
void Chemeq::printNernst(std::ostream & o,
791
                         std::ostream & w,
792
                         bool wantedlatex){
10 reyssat 793
  Membre * ga, * dr;
794
  if (!redox()){
795
    if (gauche->printableNernst()){
796
      o << "\\frac{";
797
      droit->printNernst(o);
798
      o << "}{";
799
      gauche->printNernst(o);
800
      o << "}";
801
    }
802
    else {
803
      droit->printNernst(o);
804
    }
472 georgesk 805
    droit->printNernstWIMS(w,wantedlatex);
806
    w << "; ";
807
    gauche->printNernstWIMS(w,wantedlatex);
104 bpr 808
    if (val > MINVAL) {
10 reyssat 809
      o << "\\,=\\,";
810
      if (cste!=std::string("")) o << cste << "\\,=\\,";
104 bpr 811
      o << valeur_latex();
472 georgesk 812
      if(wantedlatex){
813
        w << "; " << valeur_latex();
814
      }else{
815
        w << "; " << val;
816
      }
10 reyssat 817
    }
818
    else{
819
      o << "\\,=\\,K";
472 georgesk 820
      w << "; K";
10 reyssat 821
    }
822
  }
472 georgesk 823
  else{ /* c'est une réaction redox  */
10 reyssat 824
    o << "E\\,=\\,";
472 georgesk 825
    if(wantedlatex){
826
      w << "E\\,=\\,";
827
    }else{
828
      w << "E=";
829
    }
104 bpr 830
    if (val > MINVAL) {
10 reyssat 831
      o << val;
472 georgesk 832
      w << val << ";";
10 reyssat 833
    }
834
    else{
835
      o << "E_{0}";
472 georgesk 836
      if(wantedlatex){
837
        w << "E_{0};";
838
      }else{
839
        w << "E0;";
840
      }
10 reyssat 841
    }
842
    o << "\\,+\\,\\frac{R\\,T}{";
843
    o << gauche->nbelectron()+droit->nbelectron() << "\\,F}";
844
    o << "\\log";
472 georgesk 845
    w << gauche->nbelectron()+droit->nbelectron() << ";";
104 bpr 846
    if (gauche->redox()){ /* c'est une réduction */
10 reyssat 847
      ga=gauche; dr=droit;
848
    }
849
    else{ /* c'est une oxydation */
850
      ga=droit; dr=gauche;
851
    }
852
    if (dr->printableNernst()){
472 georgesk 853
      o << "\\frac{";
854
      ga->printNernst(o);
855
      o << "}{";
856
      dr->printNernst(o);
857
      o << "}";
858
    }
859
    else {
860
      o << "(";
861
      ga->printNernst(o);
862
      o << ")";
863
    }
864
    // implanter la sortie pour Wims ici.
865
    dr->printNernstWIMS(w,wantedlatex);
866
    w << "; ";
867
    ga->printNernstWIMS(w,wantedlatex);
10 reyssat 868
  }
869
}
870
 
104 bpr 871
std::string Chemeq::valeur_latex()const{
872
  std::ostringstream so;
873
  so << val;
874
  std::string s(so.str());
875
  std::string::size_type epos=s.find('e',0);
876
  if (epos!=std::string::npos){
877
    s.erase(epos,1);
878
    s.insert(epos,"\\times 10^{");
879
    s=s+"}";
880
  }
881
  return (std::string) s;
882
}
883
 
10 reyssat 884
std::ostream & operator << (std::ostream & o, const Chemeq & c){
13121 georgesk 885
  if (c.is_equilibrium()){ /* equilibria must be rendered with two arrows */
886
    o << *c.membregauche() << "\\,\\leftrightharpoons\\," << *c.membredroit();
887
  } else {
888
    o << *c.membregauche() << "\\,\\longrightarrow\\," << *c.membredroit();
889
  }
104 bpr 890
  if (c.valeur() > MINVAL) {
10 reyssat 891
    o << "\\,(";
892
    if (c.constante()!=std::string("")) o << c.constante() << "\\,=\\,";
104 bpr 893
    o << c.valeur_latex();
10 reyssat 894
    if (c.redox()) o << " V";
895
    o << ")";
896
  }
897
  return o;
898
}
899
 
900
std::ostream & operator << (std::ostream & o, fraction f){
901
  o << f.i;
902
  if (f.d!=1) o << '/' << f.d;
903
  return o;
904
}
905
 
906
fraction operator * (fraction f, int m){
907
  fraction result = fraction(f.i*m, f.d);
908
  result.simplifie();
909
  return result;
910
}
911
 
912
fraction operator * (int m, fraction f){
913
  fraction result = fraction(f.i*m, f.d);
914
  result.simplifie();
915
  return result;
916
}
917
 
918
fraction operator * (fraction f, fraction m)
919
{
920
  fraction result = fraction(f.i*m.i, f.d*m.d);
921
  result.simplifie();
922
  return result;
923
}
924
 
925
fraction operator + (fraction f, fraction g){
926
  fraction result = fraction(f.i*g.d+g.i*f.d, f.d*g.d);
927
  result.simplifie();
928
  return result;
929
}
930
 
931
fraction operator - (fraction f, fraction g){
932
  fraction result = fraction(f.i*g.d-g.i*f.d, f.d*g.d);
933
  result.simplifie();
934
  return result;
935
}
936
 
104 bpr 937
const fraction & minFraction(const fraction& f1, const fraction &f2){
938
  if (f1.i*f2.d > f2.i*f1.d) return f1;
939
  else return f2;
940
}
941
 
10 reyssat 942
void fraction::simplifie(){
943
  int maxprem = 23;
944
  int premiers[]={2,3,5,7,11,13,17,19,23,29};
945
  int n;
946
 
947
  for (n=0; premiers[n]<= maxprem; n++){
948
    while (i % premiers[n] == 0 && d % premiers[n] == 0){
949
      i /= premiers[n]; d /= premiers[n];
950
    }
951
  }
952
}
953
 
954
bool operator > (fraction f, int i){
955
  return f.i > f.d*i;
956
}
957
 
958
bool operator > (fraction f1, fraction f2){
959
  return f1.i*f2.d > f1.d*f2.i;
960
}
961
 
962
bool operator != (fraction f, int i){
963
  return f.i != f.d*i;
964
}
965
 
966
double mendelweight(int i){
967
  if (i>=0) return strtod (table[i].info[WEIGHT],0); else return 0.0;
968
}
969
 
970
int findmendel(const char * symb){
971
  int i=0;
972
  while (table[i].info[0] && strcmp(table[i].info[SYMBOL], symb) != 0) i++;
973
  if (table[i].info[0]) return i; else return -1;
974
}
975
 
976
double mendelweight(const char * symb){
977
  int i;
978
  i = findmendel(symb);
979
  return mendelweight(i);
980
}