18 void SpeciesNode::addPath(Path* path)
20 m_paths.push_back(path);
21 if (path->begin() ==
this) {
22 m_out += path->flow();
23 }
else if (path->end() ==
this) {
26 throw CanteraError(
"addPath",
"path added to wrong node");
30 void SpeciesNode::printPaths()
32 for (
size_t i = 0; i < m_paths.size(); i++) {
33 cout << m_paths[i]->begin()->name <<
" --> "
34 << m_paths[i]->end()->name <<
": "
35 << m_paths[i]->flow() << endl;
43 Path::Path(SpeciesNode* begin, SpeciesNode* end)
44 : m_a(begin), m_b(end), m_total(0.0)
56 void Path::addReaction(
size_t rxnNumber, doublereal value,
59 m_rxn[rxnNumber] += value;
62 m_label[label] += value;
71 void Path::writeLabel(ostream& s, doublereal threshold)
73 size_t nn = m_label.size();
78 map<string, doublereal>::const_iterator i = m_label.begin();
79 for (; i != m_label.end(); ++i) {
80 v = i->second/m_total;
82 s << i->first <<
"\\l";
83 }
else if (v > threshold) {
85 int percent = int(100*v + 0.5);
87 s <<
" (" << percent <<
"%)\\l";
101 name =
"reaction_paths";
104 normal_color =
"steelblue";
105 dashed_color =
"gray";
106 dot_options =
"center=1;";
107 m_font =
"Helvetica";
117 show_details =
false;
130 map<size_t, SpeciesNode*>::const_iterator i = m_nodes.begin();
131 for (; i != m_nodes.end(); ++i) {
136 size_t nn = nPaths();
137 for (
size_t n = 0; n < nn; n++) {
138 delete m_pathlist[n];
145 size_t i, npaths = nPaths();
146 doublereal flmax = 0.0, flxratio;
148 for (i = 0; i < npaths; i++) {
150 if (p->flow() > flmax) {
155 for (i = 0; i < npaths; i++) {
157 const Path::rxn_path_map& rxns = p->reactionMap();
158 Path::rxn_path_map::const_iterator m = rxns.begin();
159 for (; m != rxns.end(); ++m) {
160 flxratio = m->second/flmax;
161 if (flxratio > threshold) {
162 m_rxns[m->first] = 1;
167 map<size_t, int>::const_iterator begin = m_rxns.begin();
168 for (; begin != m_rxns.end(); ++begin) {
169 r.push_back(
int(begin->first));
174 void ReactionPathDiagram::add(ReactionPathDiagram& d)
182 size_t np = nPaths();
185 for (n = 0; n < np; n++) {
187 k1 = p->begin()->number;
188 k2 = p->end()->number;
189 p->setFlow(p->flow() + d.flow(k1,k2));
193 void ReactionPathDiagram::findMajorPaths(doublereal athreshold,
size_t lda,
196 size_t nn = nNodes();
198 doublereal fl, netmax = 0.0;
199 for (n = 0; n < nn; n++) {
200 for (m = n+1; m < nn; m++) {
201 k1 = m_speciesNumber[n];
202 k2 = m_speciesNumber[m];
209 for (n = 0; n < nn; n++) {
210 for (m = n+1; m < nn; m++) {
211 k1 = m_speciesNumber[n];
212 k2 = m_speciesNumber[m];
214 if (fl > athreshold*netmax) {
221 void ReactionPathDiagram::writeData(ostream& s)
224 size_t nnodes = nNodes();
225 size_t i1, i2, k1, k2;
227 for (i1 = 0; i1 < nnodes; i1++) {
228 k1 = m_speciesNumber[i1];
229 s << m_nodes[k1]->name <<
" ";
232 for (i1 = 0; i1 < nnodes; i1++) {
233 k1 = m_speciesNumber[i1];
234 for (i2 = i1+1; i2 < nnodes; i2++) {
235 k2 = m_speciesNumber[i2];
239 s << m_nodes[k1]->name <<
" " << m_nodes[k2]->name
240 <<
" " << f1 <<
" " << -f2 << endl;
263 doublereal flxratio, flmax = 0.0, lwidth;
268 s <<
"digraph " << name <<
" {" << endl;
282 if (dot_options !=
"") {
283 s << dot_options << endl;
288 size_t kbegin, kend, i1, i2, k1, k2;
292 if (flow_type == NetFlow) {
297 for (i1 = 0; i1 < nNodes(); i1++) {
298 k1 = m_speciesNumber[i1];
300 for (i2 = i1+1; i2 < nNodes(); i2++) {
301 k2 = m_speciesNumber[i2];
315 if (flmax < 1.e-10) {
321 for (i1 = 0; i1 < nNodes(); i1++) {
322 k1 = m_speciesNumber[i1];
323 for (i2 = i1+1; i2 < nNodes(); i2++) {
324 k2 = m_speciesNumber[i2];
326 if (m_local !=
npos) {
327 if (k1 != m_local && k2 != m_local) {
338 flxratio = flx/flmax;
342 flxratio = -flx/flmax;
348 if (flxratio >= threshold) {
353 s <<
"s" << kbegin <<
" -> s" << kend;
355 if (arrow_width < 0) {
357 * log10(flxratio/threshold)/log10(threshold) + 1.0;
358 s <<
"[fontname=\""+m_font+
"\", style=\"setlinewidth("
363 s <<
", style=\"setlinewidth("
364 << arrow_width <<
")\"";
365 s <<
", arrowsize=" << flxratio + 1;
368 doublereal hue = 0.7;
369 doublereal bright = 0.9;
370 s <<
", color=" <<
"\"" << hue <<
", "
372 <<
", " << bright <<
"\"" << endl;
374 if (flxratio > label_min) {
375 s <<
", label=\" " << flxratio;
377 if (
flow(kbegin, kend) > 0.0) {
379 <<
flow(kbegin, kend)/flmax <<
"\\l";
380 path(kbegin, kend)->writeLabel(s);
382 if (
flow(kend, kbegin) > 0.0) {
384 <<
flow(kend,kbegin)/flmax <<
"\\l";
385 path(kend, kbegin)->writeLabel(s);
398 for (
size_t i = 0; i < nPaths(); i++) {
400 if (p->flow() > flmax) {
405 for (
size_t i = 0; i < nPaths(); i++) {
407 flxratio = p->flow()/flmax;
408 if (m_local !=
npos) {
409 if (p->begin()->number != m_local
410 && p->end()->number != m_local) {
414 if (flxratio > threshold) {
415 p->begin()->visible =
true;
416 p->end()->visible =
true;
417 s <<
"s" << p->begin()->number
418 <<
" -> s" << p->end()->number;
420 if (arrow_width < 0) {
421 lwidth = 1.0 - 4.0 * log10(flxratio/threshold)/log10(threshold)
423 s <<
"[fontname=\""+m_font+
"\", style=\"setlinewidth("
430 s <<
", style=\"setlinewidth("
431 << arrow_width <<
")\"";
432 s <<
", arrowsize=" << flxratio + 1;
434 doublereal hue = 0.7;
435 doublereal bright = 0.9;
436 s <<
", color=" <<
"\"" << hue <<
", " << flxratio + 0.5
437 <<
", " << bright <<
"\"" << endl;
439 if (flxratio > label_min) {
440 s <<
", label = \" " << flxratio;
452 map<size_t, SpeciesNode*>::const_iterator b = m_nodes.begin();
453 for (; b != m_nodes.end(); ++b) {
454 if (b->second->visible) {
455 s <<
"s" << b->first <<
" [ fontname=\""+m_font+
"\", label=\"" << b->second->name
460 s <<
" label = " <<
"\"" <<
"Scale = "
461 << flmax <<
"\\l " << title <<
"\";" << endl;
462 s <<
" fontname = \""+m_font+
"\";" << endl <<
"}" << endl;
466 void ReactionPathDiagram::addNode(
size_t k,
string nm, doublereal x)
470 m_nodes[k]->number = k;
471 m_nodes[k]->name = nm;
472 m_nodes[k]->value = x;
473 m_speciesNumber.push_back(k);
477 void ReactionPathDiagram::linkNodes(
size_t k1,
size_t k2,
size_t rxn,
478 doublereal value,
string legend)
480 SpeciesNode* begin = m_nodes[k1];
481 SpeciesNode* end = m_nodes[k2];
482 Path* ff = m_paths[k1][k2];
484 ff=
new Path(begin, end);
485 m_paths[k1][k2] = ff;
486 m_pathlist.push_back(ff);
488 ff->addReaction(rxn, value, legend);
490 if (ff->flow() > m_flxmax) {
491 m_flxmax = ff->flow();
495 std::vector<size_t> ReactionPathDiagram::species()
497 return m_speciesNumber;
504 int ReactionPathBuilder::findGroups(ostream& logfile, Kinetics& s)
506 m_groups.resize(m_nr);
508 for (
size_t i = 0; i < m_nr; i++) {
509 logfile << endl <<
"Reaction " << i+1 <<
": "
510 << s.reactionString(i);
512 size_t nrnet = m_reac[i].size();
513 size_t npnet = m_prod[i].size();
514 const std::vector<size_t>& r = s.reactants(i);
515 const std::vector<size_t>& p = s.products(i);
517 size_t nr = r.size();
518 size_t np = p.size();
522 vector<string>& e = m_elementSymbols;
524 const vector<grouplist_t>& rgroups = s.reactantGroups(i);
525 const vector<grouplist_t>& pgroups = s.productGroups(i);
527 if (m_determinate[i]) {
528 logfile <<
" ... OK." << endl;
531 else if (rgroups.size() > 0) {
532 logfile <<
" ... specified groups." << endl;
533 size_t nrg = rgroups.size();
534 size_t npg = pgroups.size();
535 size_t kr, kp, ngrpr, ngrpp;
538 if (nrg != nr || npg != np) {
543 for (
size_t igr = 0; igr < nrg; igr++) {
545 ngrpr = rgroups[igr].size();
548 for (
size_t igp = 0; igp < npg; igp++) {
550 ngrpp = pgroups[igp].size();
553 for (
size_t kgr = 0; kgr < ngrpr; kgr++) {
554 gr = Group(rgroups[igr][kgr]);
555 for (
size_t kgp = 0; kgp < ngrpp; kgp++) {
556 gp = Group(pgroups[igp][kgp]);
558 m_transfer[i][kr][kp] = gr;
566 else if (nrnet == 2 && npnet == 2) {
568 size_t kr0 = m_reac[i][0];
569 size_t kr1 = m_reac[i][1];
572 size_t kp0 = m_prod[i][0];
573 size_t kp1 = m_prod[i][1];
577 const Group& r0 = m_sgroup[kr0];
578 const Group& r1 = m_sgroup[kr1];
579 const Group& p0 = m_sgroup[kp0];
580 const Group& p1 = m_sgroup[kp1];
582 const Group* group_a0=0, *group_b0=0, *group_c0=0,
583 *group_a1=0, *group_b1=0, *group_c1=0;
586 if (b0.valid() && b1.valid()) {
587 logfile <<
" ... ambiguous." << endl;
588 }
else if (!b0.valid() && !b1.valid()) {
589 logfile <<
" ... cannot express as A + BC = AB + C" << endl;
599 m_transfer[i][kr0][kp0] = r0;
600 m_transfer[i][kr1][kp0] = b0;
601 m_transfer[i][kr1][kp1] = p1;
607 m_transfer[i][kr1][kp1] = r1;
608 m_transfer[i][kr0][kp1] = b0;
609 m_transfer[i][kr0][kp0] = p0;
612 group_a0->fmt(logfile,e);
614 group_b0->fmt(logfile,e);
615 group_c0->fmt(logfile,e);
617 group_a0->fmt(logfile,e);
618 group_b0->fmt(logfile,e);
620 group_c0->fmt(logfile,e);
622 logfile <<
" [<= default] " << endl;
635 m_transfer[i][kr0][kp1] = r0;
636 m_transfer[i][kr1][kp1] = b0;
637 m_transfer[i][kr1][kp0] = p0;
645 m_transfer[i][kr1][kp0] = r1;
646 m_transfer[i][kr0][kp0] = b0;
647 m_transfer[i][kr0][kp1] = p1;
651 group_a1->fmt(logfile,e);
653 group_b1->fmt(logfile,e);
654 group_c1->fmt(logfile,e);
656 group_a1->fmt(logfile,e);
657 group_b1->fmt(logfile,e);
659 group_c1->fmt(logfile,e);
663 logfile <<
"... cannot parse. [ignored]" << endl;
669 void ReactionPathBuilder::writeGroup(ostream& out,
const Group& g)
671 g.fmt(out, m_elementSymbols);
674 void ReactionPathBuilder::findElements(Kinetics& kin)
680 size_t np = kin.nPhases();
682 for (
size_t i = 0; i < np; i++) {
685 size_t nel = p->nElements();
686 for (
size_t m = 0; m < nel; m++) {
687 ename = p->elementName(m);
693 if (m_enamemap.find(ename) == m_enamemap.end()) {
694 m_enamemap[ename] = m_nel + 1;
695 m_elementSymbols.push_back(ename);
700 m_atoms.resize(kin.nTotalSpecies(), m_nel, 0.0);
703 for (
size_t m = 0; m < m_nel; m++) {
704 sym = m_elementSymbols[m];
707 for (
size_t ip = 0; ip < np; ip++) {
708 ThermoPhase* p = &kin.thermo(ip);
709 size_t nsp = p->nSpecies();
710 size_t mlocal = p->elementIndex(sym);
711 for (
size_t kp = 0; kp < nsp; kp++) {
712 if (mlocal !=
npos) {
713 m_atoms(k, m) = p->nAtoms(kp, mlocal);
723 int ReactionPathBuilder::init(ostream& logfile, Kinetics& kin)
730 m_elementSymbols.clear();
733 m_ns = kin.nTotalSpecies();
734 m_nr = kin.nReactions();
743 vector<vector<size_t> > allProducts;
744 vector<vector<size_t> > allReactants;
745 for (
size_t i = 0; i < m_nr; i++) {
746 allReactants.push_back(kin.reactants(i));
747 allProducts.push_back(kin.products(i));
758 m_determinate.resize(m_nr);
761 m_elatoms.resize(m_nel, m_nr);
765 map<size_t, int> net;
767 for (
size_t i = 0; i < m_nr; i++) {
775 nr = allReactants[i].size();
776 np = allProducts[i].size();
777 for (
size_t ir = 0; ir < nr; ir++) {
778 net[allReactants[i][ir]]--;
780 for (
size_t ip = 0; ip < np; ip++) {
781 net[allProducts[i][ip]]++;
784 for (k = 0; k < m_ns; k++) {
787 for (
size_t jr = 0; jr < nmol; jr++) {
788 m_reac[i].push_back(k);
790 }
else if (net[k] > 0) {
792 for (
size_t jp = 0; jp < nmol; jp++) {
793 m_prod[i].push_back(k);
798 size_t nrnet = m_reac[i].size();
806 for (n = 0; n < nrnet; n++) {
808 for (
size_t m = 0; m < m_nel; m++) {
809 m_elatoms(m,i) += m_atoms(k,m);
816 m_sgroup.resize(m_ns);
817 for (
size_t j = 0; j < m_ns; j++) {
818 for (
size_t m = 0; m < m_nel; m++) {
819 comp[m] = int(m_atoms(j,m));
821 m_sgroup[j] = Group(comp);
834 for (
size_t i = 0; i < m_nr; i++) {
835 nr = m_reac[i].size();
836 np = m_prod[i].size();
837 m_determinate[i] =
true;
838 for (
size_t m = 0; m < m_nel; m++) {
841 for (
size_t j = 0; j < nr; j++) {
843 if (m_atoms(m_reac[i][j],m) > 0) {
847 for (
size_t j = 0; j < np; j++) {
848 if (m_atoms(m_prod[i][j],m) > 0) {
852 if (nar > 1 && nap > 1) {
853 m_determinate[i] =
false;
859 findGroups(logfile, kin);
863 string reactionLabel(
size_t i,
size_t kr,
size_t nr,
864 const std::vector<size_t>& slist,
const Kinetics& s)
869 for (
size_t l = 0; l < nr; l++) {
871 label +=
" + "+ s.kineticsSpeciesName(slist[l]);
883 int ReactionPathBuilder::build(Kinetics& s,
884 string element, ostream& output, ReactionPathDiagram& r,
bool quiet)
886 doublereal f, ropf, ropr, fwd, rev;
887 string fwdlabel, revlabel;
888 map<size_t, int> warn;
890 doublereal threshold = 0.0;
891 bool fwd_incl, rev_incl, force_incl;
894 size_t m = m_enamemap[element]-1;
901 s.getFwdRatesOfProgress(
DATA_PTR(m_ropf));
902 s.getRevRatesOfProgress(
DATA_PTR(m_ropr));
913 vector<string>& in_nodes = r.included();
914 vector<string>& out_nodes = r.excluded();
917 status.resize(s.nTotalSpecies(), 0);
918 for (
size_t ni = 0; ni < in_nodes.size(); ni++) {
919 status[s.kineticsSpeciesIndex(in_nodes[ni])] = 1;
921 for (
size_t ne = 0; ne < out_nodes.size(); ne++) {
922 status[s.kineticsSpeciesIndex(out_nodes[ne])] = -1;
925 for (
size_t i = 0; i < m_nr; i++) {
930 if (m_elatoms(m, i) > 0) {
931 size_t nr = m_reac[i].size();
932 size_t np = m_prod[i].size();
934 for (
size_t kr = 0; kr < nr; kr++) {
935 size_t kkr = m_reac[i][kr];
937 fwdlabel = reactionLabel(i, kr, nr, m_reac[i], s);
939 for (
size_t kp = 0; kp < np; kp++) {
940 size_t kkp = m_prod[i][kp];
942 for (
size_t l = 0; l < np; l++) {
944 revlabel +=
" + "+ s.kineticsSpeciesName(m_prod[i][l]);
950 revlabel +=
" (+ M)";
959 if ((kkr != kkp) && (m_atoms(kkr,m) > 0
960 && m_atoms(kkp,m) > 0)
961 && status[kkr] >= 0 && status[kkp] >= 0) {
970 if ((m_atoms(kkp,m) < m_elatoms(m, i)) &&
971 (m_atoms(kkr,m) < m_elatoms(m, i))) {
972 map<size_t, map<size_t, Group> >& g = m_transfer[i];
977 output <<
"*************** REACTION IGNORED ***************" << endl;
978 output <<
"Warning: no rule to determine partitioning of " << element
979 << endl <<
" in reaction " << s.reactionString(i) <<
"." << endl
980 <<
"*************** REACTION IGNORED **************" << endl;
990 f = g[kkr][kkp].nAtoms(m);
1003 f = m_atoms(kkp,m) * m_atoms(kkr,m) / m_elatoms(m, i);
1008 force_incl = ((status[kkr] == 1) || (status[kkp] == 1));
1010 fwd_incl = ((fwd > threshold) ||
1011 (fwd > 0.0 && force_incl));
1012 rev_incl = ((rev > threshold) ||
1013 (rev > 0.0 && force_incl));
1014 if (fwd_incl || rev_incl) {
1015 if (!r.hasNode(kkr)) {
1016 r.addNode(kkr, s.kineticsSpeciesName(kkr), m_x[kkr]);
1018 if (!r.hasNode(kkp)) {
1019 r.addNode(kkp, s.kineticsSpeciesName(kkp), m_x[kkp]);
1023 r.linkNodes(kkr, kkp,
int(i), fwd, fwdlabel);
1026 r.linkNodes(kkp, kkr, -
int(i), rev, revlabel);