00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include "ct_defs.h"
00012 #include "global.h"
00013 #include "ThermoPhase.h"
00014 #include "MultiPhase.h"
00015
00016 #include <string.h>
00017
00018 using namespace Cantera;
00019 using namespace std;
00020
00021 #ifdef DEBUG_MODE
00022 namespace Cantera {
00023 int BasisOptimize_print_lvl = 0;
00024 }
00025 static void print_stringTrunc(const char *str, int space, int alignment);
00026 #endif
00027
00028 static int amax(double *x, int j, int n);
00029 static void switch_pos(vector_int &orderVector, int jr, int kspec);
00030 static int mlequ(double *c, int idem, int n, double *b, int m);
00031
00032
00033 #ifndef MIN
00034 #define MIN(x,y) (( (x) < (y) ) ? (x) : (y))
00035 #endif
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083 int Cantera::BasisOptimize(int *usedZeroedSpecies, bool doFormRxn,
00084 MultiPhase *mphase, vector_int & orderVectorSpecies,
00085 vector_int & orderVectorElements,
00086 vector_fp & formRxnMatrix) {
00087
00088 int j, jj, k=0, kk, l, i, jl, ml;
00089 bool lindep;
00090 std::string ename;
00091 std::string sname;
00092
00093
00094
00095 int ne = mphase->nElements();
00096
00097
00098
00099 int nspecies = mphase->nSpecies();
00100 doublereal tmp;
00101 doublereal const USEDBEFORE = -1;
00102
00103
00104
00105
00106 if ((int) orderVectorElements.size() < ne) {
00107 orderVectorElements.resize(ne);
00108 for (j = 0; j < ne; j++) {
00109 orderVectorElements[j] = j;
00110 }
00111 }
00112
00113
00114
00115
00116 if ((int) orderVectorSpecies.size() != nspecies) {
00117 orderVectorSpecies.resize(nspecies);
00118 for (k = 0; k < nspecies; k++) {
00119 orderVectorSpecies[k] = k;
00120 }
00121 }
00122
00123 #ifdef DEBUG_MODE
00124 double molSave = 0.0;
00125 if (BasisOptimize_print_lvl >= 1) {
00126 writelog(" "); for(i=0; i<77; i++) writelog("-"); writelog("\n");
00127 writelog(" --- Subroutine BASOPT called to ");
00128 writelog("calculate the number of components and ");
00129 writelog("evaluate the formation matrix\n");
00130 if (BasisOptimize_print_lvl > 0) {
00131 writelog(" ---\n");
00132
00133 writelog(" --- Formula Matrix used in BASOPT calculation\n");
00134 writelog(" --- Species | Order | ");
00135 for (j = 0; j < ne; j++) {
00136 jj = orderVectorElements[j];
00137 writelog(" ");
00138 ename = mphase->elementName(jj);
00139 print_stringTrunc(ename.c_str(), 4, 1);
00140 writelogf("(%1d)", j);
00141 }
00142 writelog("\n");
00143 for (k = 0; k < nspecies; k++) {
00144 kk = orderVectorSpecies[k];
00145 writelog(" --- ");
00146 sname = mphase->speciesName(kk);
00147 print_stringTrunc(sname.c_str(), 11, 1);
00148 writelogf(" | %4d |", k);
00149 for (j = 0; j < ne; j++) {
00150 jj = orderVectorElements[j];
00151 double num = mphase->nAtoms(kk,jj);
00152 writelogf("%6.1g ", num);
00153 }
00154 writelog("\n");
00155 }
00156 writelog(" --- \n");
00157 }
00158 }
00159 #endif
00160
00161
00162
00163
00164
00165
00166 int nComponents = MIN(ne, nspecies);
00167 int nNonComponents = nspecies - nComponents;
00168
00169
00170
00171 *usedZeroedSpecies = false;
00172
00173
00174
00175
00176 vector_fp molNum(nspecies,0.0);
00177 mphase->getMoles(DATA_PTR(molNum));
00178
00179
00180
00181
00182 vector_fp sm(ne*ne, 0.0);
00183 vector_fp ss(ne, 0.0);
00184 vector_fp sa(ne, 0.0);
00185 if ((int) formRxnMatrix.size() < nspecies*ne) {
00186 formRxnMatrix.resize(nspecies*ne, 0.0);
00187 }
00188
00189 #ifdef DEBUG_MODE
00190
00191
00192
00193 vector_fp molNumBase(molNum);
00194 #endif
00195
00196
00197 int jr = -1;
00198
00199
00200
00201
00202 do {
00203 ++jr;
00204
00205
00206 do {
00207
00208
00209
00210
00211
00212 kk = amax(DATA_PTR(molNum), 0, nspecies);
00213 for (j = 0; j < nspecies; j++) {
00214 if (orderVectorSpecies[j] == kk) {
00215 k = j;
00216 break;
00217 }
00218 }
00219 if (j == nspecies) {
00220 throw CanteraError("BasisOptimize", "orderVectorSpecies contains an error");
00221 }
00222
00223 if (molNum[kk] == 0.0) *usedZeroedSpecies = true;
00224
00225
00226
00227 if (molNum[kk] == USEDBEFORE) {
00228 nComponents = jr;
00229 nNonComponents = nspecies - nComponents;
00230 goto L_END_LOOP;
00231 }
00232
00233
00234
00235
00236 #ifdef DEBUG_MODE
00237 molSave = molNum[kk];
00238 #endif
00239 molNum[kk] = USEDBEFORE;
00240
00241
00242
00243
00244
00245
00246
00247
00248 jl = jr;
00249 for (j = 0; j < ne; ++j) {
00250 jj = orderVectorElements[j];
00251 sm[j + jr*ne] = mphase->nAtoms(kk,jj);
00252 }
00253 if (jl > 0) {
00254
00255
00256
00257
00258
00259
00260 for (j = 0; j < jl; ++j) {
00261 ss[j] = 0.0;
00262 for (i = 0; i < ne; ++i) {
00263 ss[j] += sm[i + jr*ne] * sm[i + j*ne];
00264 }
00265 ss[j] /= sa[j];
00266 }
00267
00268
00269
00270
00271 for (j = 0; j < jl; ++j) {
00272 for (l = 0; l < ne; ++l) {
00273 sm[l + jr*ne] -= ss[j] * sm[l + j*ne];
00274 }
00275 }
00276 }
00277
00278
00279
00280
00281 sa[jr] = 0.0;
00282 for (ml = 0; ml < ne; ++ml) {
00283 tmp = sm[ml + jr*ne];
00284 sa[jr] += tmp * tmp;
00285 }
00286
00287
00288
00289 if (sa[jr] < 1.0e-6) lindep = true;
00290 else lindep = false;
00291 } while(lindep);
00292
00293
00294
00295 if (jr != k) {
00296 #ifdef DEBUG_MODE
00297 if (BasisOptimize_print_lvl >= 1) {
00298 kk = orderVectorSpecies[k];
00299 sname = mphase->speciesName(kk);
00300 writelogf(" --- %-12.12s", sname.c_str());
00301 jj = orderVectorSpecies[jr];
00302 ename = mphase->speciesName(jj);
00303 writelogf("(%9.2g) replaces %-12.12s", molSave, ename.c_str());
00304 writelogf("(%9.2g) as component %3d\n", molNum[jj], jr);
00305 }
00306 #endif
00307 switch_pos(orderVectorSpecies, jr, k);
00308 }
00309
00310 L_END_LOOP: ;
00311
00312
00313
00314
00315
00316 } while (jr < (nComponents-1));
00317
00318
00319 if (! doFormRxn) return nComponents;
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355 for (k = 0; k < nComponents; ++k) {
00356 kk = orderVectorSpecies[k];
00357 for (j = 0; j < nComponents; ++j) {
00358 jj = orderVectorElements[j];
00359 sm[j + k*ne] = mphase->nAtoms(kk, jj);
00360 }
00361 }
00362
00363 for (i = 0; i < nNonComponents; ++i) {
00364 k = nComponents + i;
00365 kk = orderVectorSpecies[k];
00366 for (j = 0; j < nComponents; ++j) {
00367 jj = orderVectorElements[j];
00368 formRxnMatrix[j + i * ne] = mphase->nAtoms(kk, jj);
00369 }
00370 }
00371
00372
00373
00374
00375 j = mlequ(DATA_PTR(sm), ne, nComponents, DATA_PTR(formRxnMatrix), nNonComponents);
00376 if (j == 1) {
00377 writelog("ERROR: mlequ returned an error condition\n");
00378 throw CanteraError("basopt", "mlequ returned an error condition");
00379 }
00380
00381 #ifdef DEBUG_MODE
00382 if (Cantera::BasisOptimize_print_lvl >= 1) {
00383 writelog(" ---\n");
00384 writelogf(" --- Number of Components = %d\n", nComponents);
00385 writelog(" --- Formula Matrix:\n");
00386 writelog(" --- Components: ");
00387 for (k = 0; k < nComponents; k++) {
00388 kk = orderVectorSpecies[k];
00389 writelogf(" %3d (%3d) ", k, kk);
00390 }
00391 writelog("\n --- Components Moles: ");
00392 for (k = 0; k < nComponents; k++) {
00393 kk = orderVectorSpecies[k];
00394 writelogf("%-11.3g", molNumBase[kk]);
00395 }
00396 writelog("\n --- NonComponent | Moles | ");
00397 for (i = 0; i < nComponents; i++) {
00398 kk = orderVectorSpecies[i];
00399 sname = mphase->speciesName(kk);
00400 writelogf("%-11.10s", sname.c_str());
00401 }
00402 writelog("\n");
00403
00404 for (i = 0; i < nNonComponents; i++) {
00405 k = i + nComponents;
00406 kk = orderVectorSpecies[k];
00407 writelogf(" --- %3d (%3d) ", k, kk);
00408 sname = mphase->speciesName(kk);
00409 writelogf("%-10.10s", sname.c_str());
00410 writelogf("|%10.3g|", molNumBase[kk]);
00411
00412
00413
00414 for (j = 0; j < nComponents; j++) {
00415 writelogf(" %6.2f", - formRxnMatrix[j + i * ne]);
00416 }
00417 writelog("\n");
00418 }
00419 writelog(" "); for (i=0; i<77; i++) writelog("-"); writelog("\n");
00420 }
00421 #endif
00422
00423 return nComponents;
00424 }
00425
00426
00427
00428 #ifdef DEBUG_MODE
00429 static void print_stringTrunc(const char *str, int space, int alignment)
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444 {
00445 int i, ls=0, rs=0;
00446 int len = strlen(str);
00447 if ((len) >= space) {
00448 for (i = 0; i < space; i++) {
00449 writelogf("%c", str[i]);
00450 }
00451 } else {
00452 if (alignment == 1) {
00453 ls = space - len;
00454 } else if (alignment == 2) {
00455 rs = space - len;
00456 } else {
00457 ls = (space - len) / 2;
00458 rs = space - len - ls;
00459 }
00460 if (ls != 0) {
00461 for (i = 0; i < ls; i++) writelog(" ");
00462 }
00463 writelogf("%s", str);
00464 if (rs != 0) {
00465 for (i = 0; i < rs; i++) writelog(" ");
00466 }
00467 }
00468 }
00469 #endif
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480 static int amax(double *x, int j, int n) {
00481 int i;
00482 int largest = j;
00483 double big = x[j];
00484 for (i = j + 1; i < n; ++i) {
00485 if (x[i] > big) {
00486 largest = i;
00487 big = x[i];
00488 }
00489 }
00490 return largest;
00491 }
00492
00493
00494 static void switch_pos(vector_int &orderVector, int jr, int kspec) {
00495 int kcurr = orderVector[jr];
00496 orderVector[jr] = orderVector[kspec];
00497 orderVector[kspec] = kcurr;
00498 }
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528 static int mlequ(double *c, int idem, int n, double *b, int m) {
00529 int i, j, k, l;
00530 double R;
00531
00532
00533
00534
00535
00536
00537
00538 for (i = 0; i < n; ++i) {
00539 if (c[i + i * idem] == 0.0) {
00540
00541
00542
00543 for (k = i + 1; k < n; ++k) {
00544 if (c[k + i * idem] != 0.0) goto FOUND_PIVOT;
00545 }
00546 #ifdef DEBUG_MODE
00547 writelogf("vcs_mlequ ERROR: Encountered a zero column: %d\n", i);
00548 #endif
00549 return 1;
00550 FOUND_PIVOT: ;
00551 for (j = 0; j < n; ++j) c[i + j * idem] += c[k + j * idem];
00552 for (j = 0; j < m; ++j) b[i + j * idem] += b[k + j * idem];
00553 }
00554
00555 for (l = 0; l < n; ++l) {
00556 if (l != i && c[l + i * idem] != 0.0) {
00557 R = c[l + i * idem] / c[i + i * idem];
00558 c[l + i * idem] = 0.0;
00559 for (j = i+1; j < n; ++j) c[l + j * idem] -= c[i + j * idem] * R;
00560 for (j = 0; j < m; ++j) b[l + j * idem] -= b[i + j * idem] * R;
00561 }
00562 }
00563 }
00564
00565
00566
00567
00568 for (i = 0; i < n; ++i) {
00569 for (j = 0; j < m; ++j)
00570 b[i + j * idem] = -b[i + j * idem] / c[i + i*idem];
00571 }
00572 return 0;
00573 }
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611 int Cantera::ElemRearrange(int nComponents, const vector_fp & elementAbundances,
00612 MultiPhase *mphase,
00613 vector_int & orderVectorSpecies,
00614 vector_int & orderVectorElements) {
00615
00616 int j, k, l, i, jl, ml, jr, ielem, jj, kk=0;
00617
00618 bool lindep = false;
00619 int nelements = mphase->nElements();
00620 std::string ename;
00621
00622
00623
00624 int nspecies = mphase->nSpecies();
00625
00626 double test = -1.0E10;
00627 #ifdef DEBUG_MODE
00628 if (BasisOptimize_print_lvl > 0) {
00629 writelog(" "); for(i=0; i<77; i++) writelog("-"); writelog("\n");
00630 writelog(" --- Subroutine ElemRearrange() called to ");
00631 writelog("check stoich. coefficent matrix\n");
00632 writelog(" --- and to rearrange the element ordering once\n");
00633 }
00634 #endif
00635
00636
00637
00638
00639 if ((int) orderVectorElements.size() < nelements) {
00640 orderVectorElements.resize(nelements);
00641 for (j = 0; j < nelements; j++) {
00642 orderVectorElements[j] = j;
00643 }
00644 }
00645
00646
00647
00648
00649
00650
00651 if ((int) orderVectorSpecies.size() != nspecies) {
00652 orderVectorSpecies.resize(nspecies);
00653 for (k = 0; k < nspecies; k++) {
00654 orderVectorSpecies[k] = k;
00655 }
00656 }
00657
00658
00659
00660
00661
00662
00663
00664 vector_fp eAbund(nelements,0.0);
00665 if ((int) elementAbundances.size() != nelements) {
00666 for (j = 0; j < nelements; j++) {
00667 eAbund[j] = 0.0;
00668 for (k = 0; k < nspecies; k++) {
00669 eAbund[j] += fabs(mphase->nAtoms(k, j));
00670 }
00671 }
00672 } else {
00673 copy(elementAbundances.begin(), elementAbundances.end(),
00674 eAbund.begin());
00675 }
00676
00677 vector_fp sa(nelements,0.0);
00678 vector_fp ss(nelements,0.0);
00679 vector_fp sm(nelements*nelements,0.0);
00680
00681
00682
00683
00684
00685 jr = -1;
00686 do {
00687 ++jr;
00688
00689
00690
00691
00692 do {
00693
00694
00695
00696
00697
00698
00699 k = nelements;
00700 for (ielem = jr; ielem < nelements; ielem++) {
00701 kk = orderVectorElements[ielem];
00702 if (eAbund[kk] != test && eAbund[kk] > 0.0) {
00703 k = ielem;
00704 break;
00705 }
00706 }
00707 for (ielem = jr; ielem < nelements; ielem++) {
00708 kk = orderVectorElements[ielem];
00709 if (eAbund[kk] != test) {
00710 k = ielem;
00711 break;
00712 }
00713 }
00714
00715 if (k == nelements) {
00716
00717
00718
00719 #ifdef DEBUG_MODE
00720 if (BasisOptimize_print_lvl > 0) {
00721 writelogf("Error exit: returning with nComponents = %d\n", jr);
00722 }
00723 #endif
00724 return jr;
00725 }
00726
00727
00728
00729
00730
00731 eAbund[kk] = test;
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741 jl = jr;
00742
00743
00744
00745
00746
00747
00748 for (j = 0; j < nComponents; ++j) {
00749 jj = orderVectorSpecies[j];
00750 kk = orderVectorElements[k];
00751 sm[j + jr*nComponents] = mphase->nAtoms(jj,kk);
00752 }
00753 if (jl > 0) {
00754
00755
00756
00757
00758
00759
00760 for (j = 0; j < jl; ++j) {
00761 ss[j] = 0.0;
00762 for (i = 0; i < nComponents; ++i) {
00763 ss[j] += sm[i + jr*nComponents] * sm[i + j*nComponents];
00764 }
00765 ss[j] /= sa[j];
00766 }
00767
00768
00769
00770
00771 for (j = 0; j < jl; ++j) {
00772 for (l = 0; l < nComponents; ++l) {
00773 sm[l + jr*nComponents] -= ss[j] * sm[l + j*nComponents];
00774 }
00775 }
00776 }
00777
00778
00779
00780
00781
00782 sa[jr] = 0.0;
00783 for (ml = 0; ml < nComponents; ++ml) {
00784 double tmp = sm[ml + jr*nComponents];
00785 sa[jr] += tmp * tmp;
00786 }
00787
00788
00789
00790 if (sa[jr] < 1.0e-6) lindep = true;
00791 else lindep = false;
00792 } while(lindep);
00793
00794
00795
00796 if (jr != k) {
00797 #ifdef DEBUG_MODE
00798 if (BasisOptimize_print_lvl > 0) {
00799 kk = orderVectorElements[k];
00800 ename = mphase->elementName(kk);
00801 writelog(" --- ");
00802 writelogf("%-2.2s", ename.c_str());
00803 writelog("replaces ");
00804 kk = orderVectorElements[jr];
00805 ename = mphase->elementName(kk);
00806 writelogf("%-2.2s", ename.c_str());
00807 writelogf(" as element %3d\n", jr);
00808 }
00809 #endif
00810 switch_pos(orderVectorElements, jr, k);
00811 }
00812
00813
00814
00815
00816
00817
00818 } while (jr < (nComponents-1));
00819 return nComponents;
00820 }
00821