17 void SpeciesNode::addPath(Path* path)
19 m_paths.push_back(path);
20 if (path->begin() ==
this) {
21 m_out += path->flow();
22 }
else if (path->end() ==
this) {
25 throw CanteraError(
"addPath",
"path added to wrong node");
29 void SpeciesNode::printPaths()
31 for (
size_t i = 0; i < m_paths.size(); i++) {
32 cout << m_paths[i]->begin()->name <<
" --> "
33 << m_paths[i]->end()->name <<
": "
34 << m_paths[i]->flow() << endl;
38 Path::Path(SpeciesNode* begin, SpeciesNode* end)
39 : m_a(begin), m_b(end), m_total(0.0)
45 void Path::addReaction(
size_t rxnNumber, doublereal value,
48 m_rxn[rxnNumber] += value;
51 m_label[label] += value;
55 void Path::writeLabel(ostream& s, doublereal threshold)
57 size_t nn = m_label.size();
62 map<string, doublereal>::const_iterator i = m_label.begin();
63 for (; i != m_label.end(); ++i) {
64 v = i->second/m_total;
66 s << i->first <<
"\\l";
67 }
else if (v > threshold) {
69 int percent = int(100*v + 0.5);
71 s <<
" (" << percent <<
"%)\\l";
79 ReactionPathDiagram::ReactionPathDiagram()
81 name =
"reaction_paths";
84 normal_color =
"steelblue";
85 dashed_color =
"gray";
86 dot_options =
"center=1;";
106 map<size_t, SpeciesNode*>::const_iterator i = m_nodes.begin();
107 for (; i != m_nodes.end(); ++i) {
112 size_t nn = nPaths();
113 for (
size_t n = 0; n < nn; n++) {
114 delete m_pathlist[n];
120 size_t i, npaths = nPaths();
121 doublereal flmax = 0.0, flxratio;
123 for (i = 0; i < npaths; i++) {
125 if (p->flow() > flmax) {
130 for (i = 0; i < npaths; i++) {
132 const Path::rxn_path_map& rxns = p->reactionMap();
133 Path::rxn_path_map::const_iterator m = rxns.begin();
134 for (; m != rxns.end(); ++m) {
135 flxratio = m->second/flmax;
136 if (flxratio > threshold) {
137 m_rxns[m->first] = 1;
142 map<size_t, int>::const_iterator begin = m_rxns.begin();
143 for (; begin != m_rxns.end(); ++begin) {
144 r.push_back(
int(begin->first));
149 void ReactionPathDiagram::add(ReactionPathDiagram& d)
157 size_t np = nPaths();
160 for (n = 0; n < np; n++) {
162 k1 = p->begin()->number;
163 k2 = p->end()->number;
164 p->setFlow(p->flow() + d.flow(k1,k2));
168 void ReactionPathDiagram::findMajorPaths(doublereal athreshold,
size_t lda,
171 size_t nn = nNodes();
173 doublereal fl, netmax = 0.0;
174 for (n = 0; n < nn; n++) {
175 for (m = n+1; m < nn; m++) {
176 k1 = m_speciesNumber[n];
177 k2 = m_speciesNumber[m];
184 for (n = 0; n < nn; n++) {
185 for (m = n+1; m < nn; m++) {
186 k1 = m_speciesNumber[n];
187 k2 = m_speciesNumber[m];
189 if (fl > athreshold*netmax) {
196 void ReactionPathDiagram::writeData(ostream& s)
199 size_t nnodes = nNodes();
200 size_t i1, i2, k1, k2;
202 for (i1 = 0; i1 < nnodes; i1++) {
203 k1 = m_speciesNumber[i1];
204 s << m_nodes[k1]->name <<
" ";
207 for (i1 = 0; i1 < nnodes; i1++) {
208 k1 = m_speciesNumber[i1];
209 for (i2 = i1+1; i2 < nnodes; i2++) {
210 k2 = m_speciesNumber[i2];
214 s << m_nodes[k1]->name <<
" " << m_nodes[k2]->name
215 <<
" " << f1 <<
" " << -f2 << endl;
223 doublereal flxratio, flmax = 0.0, lwidth;
228 s <<
"digraph " << name <<
" {" << endl;
242 if (dot_options !=
"") {
243 s << dot_options << endl;
248 size_t kbegin, kend, i1, i2, k1, k2;
252 if (flow_type == NetFlow) {
257 for (i1 = 0; i1 < nNodes(); i1++) {
258 k1 = m_speciesNumber[i1];
260 for (i2 = i1+1; i2 < nNodes(); i2++) {
261 k2 = m_speciesNumber[i2];
275 if (flmax < 1.e-10) {
281 for (i1 = 0; i1 < nNodes(); i1++) {
282 k1 = m_speciesNumber[i1];
283 for (i2 = i1+1; i2 < nNodes(); i2++) {
284 k2 = m_speciesNumber[i2];
286 if (m_local !=
npos) {
287 if (k1 != m_local && k2 != m_local) {
298 flxratio = flx/flmax;
302 flxratio = -flx/flmax;
308 if (flxratio >= threshold) {
313 s <<
"s" << kbegin <<
" -> s" << kend;
314 s <<
"[fontname=\""+m_font+
"\", style=\"setlinewidth(";
316 if (arrow_width < 0) {
318 * log10(flxratio/threshold)/log10(threshold) + 1.0;
319 s << lwidth <<
")\"";
321 << std::min(6.0, 0.5*lwidth);
323 s << arrow_width <<
")\"";
324 s <<
", arrowsize=" << flxratio + 1;
327 doublereal hue = 0.7;
328 doublereal bright = 0.9;
329 s <<
", color=" <<
"\"" << hue <<
", "
331 <<
", " << bright <<
"\"" << endl;
333 if (flxratio > label_min) {
334 s <<
", label=\" " << flxratio;
336 if (
flow(kbegin, kend) > 0.0) {
338 <<
flow(kbegin, kend)/flmax <<
"\\l";
339 path(kbegin, kend)->writeLabel(s);
341 if (
flow(kend, kbegin) > 0.0) {
343 <<
flow(kend,kbegin)/flmax <<
"\\l";
344 path(kend, kbegin)->writeLabel(s);
357 for (
size_t i = 0; i < nPaths(); i++) {
359 if (p->flow() > flmax) {
364 for (
size_t i = 0; i < nPaths(); i++) {
366 flxratio = p->flow()/flmax;
367 if (m_local !=
npos) {
368 if (p->begin()->number != m_local
369 && p->end()->number != m_local) {
373 if (flxratio > threshold) {
374 p->begin()->visible =
true;
375 p->end()->visible =
true;
376 s <<
"s" << p->begin()->number
377 <<
" -> s" << p->end()->number;
379 if (arrow_width < 0) {
380 lwidth = 1.0 - 4.0 * log10(flxratio/threshold)/log10(threshold)
382 s <<
"[fontname=\""+m_font+
"\", style=\"setlinewidth("
387 << std::min(6.0, 0.5*lwidth);
389 s <<
", style=\"setlinewidth("
390 << arrow_width <<
")\"";
391 s <<
", arrowsize=" << flxratio + 1;
393 doublereal hue = 0.7;
394 doublereal bright = 0.9;
395 s <<
", color=" <<
"\"" << hue <<
", " << flxratio + 0.5
396 <<
", " << bright <<
"\"" << endl;
398 if (flxratio > label_min) {
399 s <<
", label = \" " << flxratio;
411 map<size_t, SpeciesNode*>::const_iterator b = m_nodes.begin();
412 for (; b != m_nodes.end(); ++b) {
413 if (b->second->visible) {
414 s <<
"s" << b->first <<
" [ fontname=\""+m_font+
"\", label=\"" << b->second->name
419 s <<
" label = " <<
"\"" <<
"Scale = "
420 << flmax <<
"\\l " << title <<
"\";" << endl;
421 s <<
" fontname = \""+m_font+
"\";" << endl <<
"}" << endl;
425 void ReactionPathDiagram::addNode(
size_t k,
const string& nm, doublereal x)
429 m_nodes[k]->number = k;
430 m_nodes[k]->name = nm;
431 m_nodes[k]->value = x;
432 m_speciesNumber.push_back(k);
436 void ReactionPathDiagram::linkNodes(
size_t k1,
size_t k2,
size_t rxn,
437 doublereal value,
string legend)
439 SpeciesNode* begin = m_nodes[k1];
440 SpeciesNode* end = m_nodes[k2];
441 Path* ff = m_paths[k1][k2];
443 ff=
new Path(begin, end);
444 m_paths[k1][k2] = ff;
445 m_pathlist.push_back(ff);
447 ff->addReaction(rxn, value, legend);
449 if (ff->flow() > m_flxmax) {
450 m_flxmax = ff->flow();
454 std::vector<size_t> ReactionPathDiagram::species()
456 return m_speciesNumber;
459 int ReactionPathBuilder::findGroups(ostream& logfile, Kinetics& s)
461 m_groups.resize(m_nr);
463 for (
size_t i = 0; i < m_nr; i++) {
464 logfile << endl <<
"Reaction " << i+1 <<
": "
465 << s.reactionString(i);
467 size_t nrnet = m_reac[i].size();
468 size_t npnet = m_prod[i].size();
469 const std::vector<size_t>& r = s.reactants(i);
470 const std::vector<size_t>& p = s.products(i);
472 size_t nr = r.size();
473 size_t np = p.size();
477 vector<string>& e = m_elementSymbols;
479 const vector<grouplist_t>& rgroups = s.reactantGroups(i);
480 const vector<grouplist_t>& pgroups = s.productGroups(i);
482 if (m_determinate[i]) {
483 logfile <<
" ... OK." << endl;
486 else if (rgroups.size() > 0) {
487 logfile <<
" ... specified groups." << endl;
488 size_t nrg = rgroups.size();
489 size_t npg = pgroups.size();
490 size_t kr, kp, ngrpr, ngrpp;
493 if (nrg != nr || npg != np) {
498 for (
size_t igr = 0; igr < nrg; igr++) {
500 ngrpr = rgroups[igr].size();
503 for (
size_t igp = 0; igp < npg; igp++) {
505 ngrpp = pgroups[igp].size();
508 for (
size_t kgr = 0; kgr < ngrpr; kgr++) {
509 gr = Group(rgroups[igr][kgr]);
510 for (
size_t kgp = 0; kgp < ngrpp; kgp++) {
511 gp = Group(pgroups[igp][kgp]);
513 m_transfer[i][kr][kp] = gr;
521 else if (nrnet == 2 && npnet == 2) {
523 size_t kr0 = m_reac[i][0];
524 size_t kr1 = m_reac[i][1];
527 size_t kp0 = m_prod[i][0];
528 size_t kp1 = m_prod[i][1];
532 const Group& r0 = m_sgroup[kr0];
533 const Group& r1 = m_sgroup[kr1];
534 const Group& p0 = m_sgroup[kp0];
535 const Group& p1 = m_sgroup[kp1];
537 const Group* group_a0=0, *group_b0=0, *group_c0=0,
538 *group_a1=0, *group_b1=0, *group_c1=0;
541 if (b0.valid() && b1.valid()) {
542 logfile <<
" ... ambiguous." << endl;
543 }
else if (!b0.valid() && !b1.valid()) {
544 logfile <<
" ... cannot express as A + BC = AB + C" << endl;
554 m_transfer[i][kr0][kp0] = r0;
555 m_transfer[i][kr1][kp0] = b0;
556 m_transfer[i][kr1][kp1] = p1;
562 m_transfer[i][kr1][kp1] = r1;
563 m_transfer[i][kr0][kp1] = b0;
564 m_transfer[i][kr0][kp0] = p0;
567 group_a0->fmt(logfile,e);
569 group_b0->fmt(logfile,e);
570 group_c0->fmt(logfile,e);
572 group_a0->fmt(logfile,e);
573 group_b0->fmt(logfile,e);
575 group_c0->fmt(logfile,e);
577 logfile <<
" [<= default] " << endl;
590 m_transfer[i][kr0][kp1] = r0;
591 m_transfer[i][kr1][kp1] = b0;
592 m_transfer[i][kr1][kp0] = p0;
600 m_transfer[i][kr1][kp0] = r1;
601 m_transfer[i][kr0][kp0] = b0;
602 m_transfer[i][kr0][kp1] = p1;
606 group_a1->fmt(logfile,e);
608 group_b1->fmt(logfile,e);
609 group_c1->fmt(logfile,e);
611 group_a1->fmt(logfile,e);
612 group_b1->fmt(logfile,e);
614 group_c1->fmt(logfile,e);
618 logfile <<
"... cannot parse. [ignored]" << endl;
624 void ReactionPathBuilder::writeGroup(ostream& out,
const Group& g)
626 g.fmt(out, m_elementSymbols);
629 void ReactionPathBuilder::findElements(Kinetics& kin)
635 size_t np = kin.nPhases();
637 for (
size_t i = 0; i < np; i++) {
640 size_t nel = p->nElements();
641 for (
size_t m = 0; m < nel; m++) {
642 ename = p->elementName(m);
648 if (m_enamemap.find(ename) == m_enamemap.end()) {
649 m_enamemap[ename] = m_nel + 1;
650 m_elementSymbols.push_back(ename);
655 m_atoms.resize(kin.nTotalSpecies(), m_nel, 0.0);
658 for (
size_t m = 0; m < m_nel; m++) {
659 sym = m_elementSymbols[m];
662 for (
size_t ip = 0; ip < np; ip++) {
663 ThermoPhase* p = &kin.thermo(ip);
664 size_t nsp = p->nSpecies();
665 size_t mlocal = p->elementIndex(sym);
666 for (
size_t kp = 0; kp < nsp; kp++) {
667 if (mlocal !=
npos) {
668 m_atoms(k, m) = p->nAtoms(kp, mlocal);
676 int ReactionPathBuilder::init(ostream& logfile, Kinetics& kin)
683 m_elementSymbols.clear();
686 m_ns = kin.nTotalSpecies();
687 m_nr = kin.nReactions();
696 vector<vector<size_t> > allProducts;
697 vector<vector<size_t> > allReactants;
698 for (
size_t i = 0; i < m_nr; i++) {
699 allReactants.push_back(kin.reactants(i));
700 allProducts.push_back(kin.products(i));
711 m_determinate.resize(m_nr);
714 m_elatoms.resize(m_nel, m_nr);
718 map<size_t, int> net;
720 for (
size_t i = 0; i < m_nr; i++) {
728 nr = allReactants[i].size();
729 np = allProducts[i].size();
730 for (
size_t ir = 0; ir < nr; ir++) {
731 net[allReactants[i][ir]]--;
733 for (
size_t ip = 0; ip < np; ip++) {
734 net[allProducts[i][ip]]++;
737 for (k = 0; k < m_ns; k++) {
740 for (
size_t jr = 0; jr < nmol; jr++) {
741 m_reac[i].push_back(k);
743 }
else if (net[k] > 0) {
745 for (
size_t jp = 0; jp < nmol; jp++) {
746 m_prod[i].push_back(k);
751 size_t nrnet = m_reac[i].size();
759 for (n = 0; n < nrnet; n++) {
761 for (
size_t m = 0; m < m_nel; m++) {
762 m_elatoms(m,i) += m_atoms(k,m);
769 m_sgroup.resize(m_ns);
770 for (
size_t j = 0; j < m_ns; j++) {
771 for (
size_t m = 0; m < m_nel; m++) {
772 comp[m] = int(m_atoms(j,m));
774 m_sgroup[j] = Group(comp);
787 for (
size_t i = 0; i < m_nr; i++) {
788 nr = m_reac[i].size();
789 np = m_prod[i].size();
790 m_determinate[i] =
true;
791 for (
size_t m = 0; m < m_nel; m++) {
794 for (
size_t j = 0; j < nr; j++) {
796 if (m_atoms(m_reac[i][j],m) > 0) {
800 for (
size_t j = 0; j < np; j++) {
801 if (m_atoms(m_prod[i][j],m) > 0) {
805 if (nar > 1 && nap > 1) {
806 m_determinate[i] =
false;
812 findGroups(logfile, kin);
816 string reactionLabel(
size_t i,
size_t kr,
size_t nr,
817 const std::vector<size_t>& slist,
const Kinetics& s)
822 for (
size_t l = 0; l < nr; l++) {
824 label +=
" + "+ s.kineticsSpeciesName(slist[l]);
835 int ReactionPathBuilder::build(Kinetics& s,
const string& element,
836 ostream& output, ReactionPathDiagram& r,
bool quiet)
838 doublereal f, ropf, ropr, fwd, rev;
839 string fwdlabel, revlabel;
840 map<size_t, int> warn;
842 doublereal threshold = 0.0;
843 bool fwd_incl, rev_incl, force_incl;
846 size_t m = m_enamemap[element]-1;
853 s.getFwdRatesOfProgress(
DATA_PTR(m_ropf));
854 s.getRevRatesOfProgress(
DATA_PTR(m_ropr));
865 vector<string>& in_nodes = r.included();
866 vector<string>& out_nodes = r.excluded();
869 status.resize(s.nTotalSpecies(), 0);
870 for (
size_t ni = 0; ni < in_nodes.size(); ni++) {
871 status[s.kineticsSpeciesIndex(in_nodes[ni])] = 1;
873 for (
size_t ne = 0; ne < out_nodes.size(); ne++) {
874 status[s.kineticsSpeciesIndex(out_nodes[ne])] = -1;
877 for (
size_t i = 0; i < m_nr; i++) {
882 if (m_elatoms(m, i) > 0) {
883 size_t nr = m_reac[i].size();
884 size_t np = m_prod[i].size();
886 for (
size_t kr = 0; kr < nr; kr++) {
887 size_t kkr = m_reac[i][kr];
889 fwdlabel = reactionLabel(i, kr, nr, m_reac[i], s);
891 for (
size_t kp = 0; kp < np; kp++) {
892 size_t kkp = m_prod[i][kp];
894 for (
size_t l = 0; l < np; l++) {
896 revlabel +=
" + "+ s.kineticsSpeciesName(m_prod[i][l]);
902 revlabel +=
" (+ M)";
911 if ((kkr != kkp) && (m_atoms(kkr,m) > 0
912 && m_atoms(kkp,m) > 0)
913 && status[kkr] >= 0 && status[kkp] >= 0) {
922 if ((m_atoms(kkp,m) < m_elatoms(m, i)) &&
923 (m_atoms(kkr,m) < m_elatoms(m, i))) {
924 map<size_t, map<size_t, Group> >& g = m_transfer[i];
929 output <<
"*************** REACTION IGNORED ***************" << endl;
930 output <<
"Warning: no rule to determine partitioning of " << element
931 << endl <<
" in reaction " << s.reactionString(i) <<
"." << endl
932 <<
"*************** REACTION IGNORED **************" << endl;
942 f = g[kkr][kkp].nAtoms(m);
955 f = m_atoms(kkp,m) * m_atoms(kkr,m) / m_elatoms(m, i);
960 force_incl = ((status[kkr] == 1) || (status[kkp] == 1));
962 fwd_incl = ((fwd > threshold) ||
963 (fwd > 0.0 && force_incl));
964 rev_incl = ((rev > threshold) ||
965 (rev > 0.0 && force_incl));
966 if (fwd_incl || rev_incl) {
967 if (!r.hasNode(kkr)) {
968 r.addNode(kkr, s.kineticsSpeciesName(kkr), m_x[kkr]);
970 if (!r.hasNode(kkp)) {
971 r.addNode(kkp, s.kineticsSpeciesName(kkp), m_x[kkp]);
975 r.linkNodes(kkr, kkp,
int(i), fwd, fwdlabel);
978 r.linkNodes(kkp, kkr, -
int(i), rev, revlabel);
bool visible
Visible on graph;.
void exportToDot(std::ostream &s)
Export the reaction path diagram.
const size_t npos
index returned by functions to indicate "no position"
Nodes in reaction path graphs.
const int FALLOFF_RXN
The general form for an association or dissociation reaction, with a pressure-dependent rate...
std::vector< int > vector_int
Vector of ints.
doublereal flow(size_t k1, size_t k2)
The one-way flow from node k1 to node k2.
virtual ~ReactionPathDiagram()
Destructor.
This file defines some constants used to specify reaction types.
Base class for exceptions thrown by Cantera classes.
Base class for kinetics managers and also contains the kineticsmgr module documentation (see Kinetics...
const int THREE_BODY_RXN
A reaction that requires a third-body collision partner.
#define DATA_PTR(vec)
Creates a pointer to the start of the raw data for a vector.
Classes for reaction path analysis.
doublereal netFlow(size_t k1, size_t k2)
The net flow from node k1 to node k2.