15 void SpeciesNode::addPath(Path* path)
17 m_paths.push_back(path);
18 if (path->begin() ==
this) {
19 m_out += path->flow();
20 }
else if (path->end() ==
this) {
23 throw CanteraError(
"addPath",
"path added to wrong node");
27 void SpeciesNode::printPaths()
29 for (
size_t i = 0; i < m_paths.size(); i++) {
30 cout << m_paths[i]->begin()->name <<
" --> "
31 << m_paths[i]->end()->name <<
": "
32 << m_paths[i]->flow() << endl;
36 Path::Path(SpeciesNode* begin, SpeciesNode* end)
37 : m_a(begin), m_b(end), m_total(0.0)
43 void Path::addReaction(
size_t rxnNumber, doublereal value,
46 m_rxn[rxnNumber] += value;
49 m_label[label] += value;
53 void Path::writeLabel(ostream& s, doublereal threshold)
55 size_t nn = m_label.size();
60 map<string, doublereal>::const_iterator i = m_label.begin();
61 for (; i != m_label.end(); ++i) {
62 v = i->second/m_total;
64 s << i->first <<
"\\l";
65 }
else if (v > threshold) {
67 int percent = int(100*v + 0.5);
69 s <<
" (" << percent <<
"%)\\l";
77 ReactionPathDiagram::ReactionPathDiagram()
79 name =
"reaction_paths";
82 normal_color =
"steelblue";
83 dashed_color =
"gray";
84 dot_options =
"center=1;";
104 map<size_t, SpeciesNode*>::const_iterator i = m_nodes.begin();
105 for (; i != m_nodes.end(); ++i) {
110 size_t nn = nPaths();
111 for (
size_t n = 0; n < nn; n++) {
112 delete m_pathlist[n];
118 size_t i, npaths = nPaths();
119 doublereal flmax = 0.0, flxratio;
121 for (i = 0; i < npaths; i++) {
123 flmax = std::max(p->flow(), flmax);
126 for (i = 0; i < npaths; i++) {
128 const Path::rxn_path_map& rxns = p->reactionMap();
129 Path::rxn_path_map::const_iterator m = rxns.begin();
130 for (; m != rxns.end(); ++m) {
131 flxratio = m->second/flmax;
132 if (flxratio > threshold) {
133 m_rxns[m->first] = 1;
138 map<size_t, int>::const_iterator begin = m_rxns.begin();
139 for (; begin != m_rxns.end(); ++begin) {
140 r.push_back(
int(begin->first));
145 void ReactionPathDiagram::add(ReactionPathDiagram& d)
147 size_t np = nPaths();
150 for (n = 0; n < np; n++) {
152 k1 = p->begin()->number;
153 k2 = p->end()->number;
154 p->setFlow(p->flow() + d.flow(k1,k2));
158 void ReactionPathDiagram::findMajorPaths(doublereal athreshold,
size_t lda,
161 size_t nn = nNodes();
163 doublereal fl, netmax = 0.0;
164 for (n = 0; n < nn; n++) {
165 for (m = n+1; m < nn; m++) {
166 k1 = m_speciesNumber[n];
167 k2 = m_speciesNumber[m];
169 netmax = std::max(fl, netmax);
172 for (n = 0; n < nn; n++) {
173 for (m = n+1; m < nn; m++) {
174 k1 = m_speciesNumber[n];
175 k2 = m_speciesNumber[m];
177 if (fl > athreshold*netmax) {
184 void ReactionPathDiagram::writeData(ostream& s)
187 size_t nnodes = nNodes();
188 size_t i1, i2, k1, k2;
190 for (i1 = 0; i1 < nnodes; i1++) {
191 k1 = m_speciesNumber[i1];
192 s << m_nodes[k1]->name <<
" ";
195 for (i1 = 0; i1 < nnodes; i1++) {
196 k1 = m_speciesNumber[i1];
197 for (i2 = i1+1; i2 < nnodes; i2++) {
198 k2 = m_speciesNumber[i2];
201 s << m_nodes[k1]->name <<
" " << m_nodes[k2]->name
202 <<
" " << f1 <<
" " << -f2 << endl;
209 doublereal flxratio, flmax = 0.0, lwidth;
213 s <<
"digraph " << name <<
" {" << endl;
226 if (dot_options !=
"") {
227 s << dot_options << endl;
232 size_t kbegin, kend, i1, i2, k1, k2;
236 if (flow_type == NetFlow) {
241 for (i1 = 0; i1 < nNodes(); i1++) {
242 k1 = m_speciesNumber[i1];
244 for (i2 = i1+1; i2 < nNodes(); i2++) {
245 k2 = m_speciesNumber[i2];
250 flmax = std::max(flx, flmax);
256 flmax = std::max(flmax, 1e-10);
260 for (i1 = 0; i1 < nNodes(); i1++) {
261 k1 = m_speciesNumber[i1];
262 for (i2 = i1+1; i2 < nNodes(); i2++) {
263 k2 = m_speciesNumber[i2];
265 if (m_local !=
npos) {
266 if (k1 != m_local && k2 != m_local) {
277 flxratio = flx/flmax;
281 flxratio = -flx/flmax;
287 if (flxratio >= threshold) {
292 s <<
"s" << kbegin <<
" -> s" << kend;
293 s <<
"[fontname=\""+m_font+
"\", style=\"setlinewidth(";
295 if (arrow_width < 0) {
297 * log10(flxratio/threshold)/log10(threshold) + 1.0;
298 s << lwidth <<
")\"";
300 << std::min(6.0, 0.5*lwidth);
302 s << arrow_width <<
")\"";
303 s <<
", arrowsize=" << flxratio + 1;
306 doublereal hue = 0.7;
307 doublereal bright = 0.9;
308 s <<
", color=" <<
"\"" << hue <<
", "
310 <<
", " << bright <<
"\"" << endl;
312 if (flxratio > label_min) {
313 s <<
", label=\" " << flxratio;
315 if (
flow(kbegin, kend) > 0.0) {
317 <<
flow(kbegin, kend)/flmax <<
"\\l";
318 path(kbegin, kend)->writeLabel(s);
320 if (
flow(kend, kbegin) > 0.0) {
322 <<
flow(kend,kbegin)/flmax <<
"\\l";
323 path(kend, kbegin)->writeLabel(s);
336 for (
size_t i = 0; i < nPaths(); i++) {
338 flmax = std::max(p->flow(), flmax);
341 for (
size_t i = 0; i < nPaths(); i++) {
343 flxratio = p->flow()/flmax;
344 if (m_local !=
npos) {
345 if (p->begin()->number != m_local
346 && p->end()->number != m_local) {
350 if (flxratio > threshold) {
351 p->begin()->visible =
true;
352 p->end()->visible =
true;
353 s <<
"s" << p->begin()->number
354 <<
" -> s" << p->end()->number;
356 if (arrow_width < 0) {
357 lwidth = 1.0 - 4.0 * log10(flxratio/threshold)/log10(threshold)
359 s <<
"[fontname=\""+m_font+
"\", style=\"setlinewidth("
363 << std::min(6.0, 0.5*lwidth);
365 s <<
", style=\"setlinewidth("
366 << arrow_width <<
")\"";
367 s <<
", arrowsize=" << flxratio + 1;
369 doublereal hue = 0.7;
370 doublereal bright = 0.9;
371 s <<
", color=" <<
"\"" << hue <<
", " << flxratio + 0.5
372 <<
", " << bright <<
"\"" << endl;
374 if (flxratio > label_min) {
375 s <<
", label = \" " << flxratio;
387 map<size_t, SpeciesNode*>::const_iterator b = m_nodes.begin();
388 for (; b != m_nodes.end(); ++b) {
389 if (b->second->visible) {
390 s <<
"s" << b->first <<
" [ fontname=\""+m_font+
"\", label=\"" << b->second->name
394 s <<
" label = " <<
"\"" <<
"Scale = "
395 << flmax <<
"\\l " << title <<
"\";" << endl;
396 s <<
" fontname = \""+m_font+
"\";" << endl <<
"}" << endl;
400 void ReactionPathDiagram::addNode(
size_t k,
const string& nm, doublereal x)
404 m_nodes[k]->number = k;
405 m_nodes[k]->name = nm;
406 m_nodes[k]->value = x;
407 m_speciesNumber.push_back(k);
411 void ReactionPathDiagram::linkNodes(
size_t k1,
size_t k2,
size_t rxn,
412 doublereal value,
string legend)
414 SpeciesNode* begin = m_nodes[k1];
415 SpeciesNode* end = m_nodes[k2];
416 Path* ff = m_paths[k1][k2];
418 ff=
new Path(begin, end);
419 m_paths[k1][k2] = ff;
420 m_pathlist.push_back(ff);
422 ff->addReaction(rxn, value, legend);
424 m_flxmax = std::max(ff->flow(), m_flxmax);
427 std::vector<size_t> ReactionPathDiagram::species()
429 return m_speciesNumber;
432 int ReactionPathBuilder::findGroups(ostream& logfile, Kinetics& s)
434 m_groups.resize(m_nr);
436 for (
size_t i = 0; i < m_nr; i++) {
437 logfile << endl <<
"Reaction " << i+1 <<
": "
438 << s.reactionString(i);
440 size_t nrnet = m_reac[i].size();
441 size_t npnet = m_prod[i].size();
442 std::vector<size_t> r, p;
443 for (
size_t k = 0; k < s.nTotalSpecies(); k++) {
444 if (s.reactantStoichCoeff(k,i)) {
447 if (s.productStoichCoeff(k,i)) {
452 size_t nr = r.size();
453 size_t np = p.size();
457 vector<string>& e = m_elementSymbols;
459 const vector<grouplist_t>& rgroups = s.reactantGroups(i);
460 const vector<grouplist_t>& pgroups = s.productGroups(i);
462 if (m_determinate[i]) {
463 logfile <<
" ... OK." << endl;
466 else if (rgroups.size() > 0) {
467 logfile <<
" ... specified groups." << endl;
468 size_t nrg = rgroups.size();
469 size_t npg = pgroups.size();
470 size_t kr, kp, ngrpr, ngrpp;
473 if (nrg != nr || npg != np) {
478 for (
size_t igr = 0; igr < nrg; igr++) {
480 ngrpr = rgroups[igr].size();
483 for (
size_t igp = 0; igp < npg; igp++) {
485 ngrpp = pgroups[igp].size();
488 for (
size_t kgr = 0; kgr < ngrpr; kgr++) {
489 gr = Group(rgroups[igr][kgr]);
490 for (
size_t kgp = 0; kgp < ngrpp; kgp++) {
491 gp = Group(pgroups[igp][kgp]);
493 m_transfer[i][kr][kp] = gr;
501 else if (nrnet == 2 && npnet == 2) {
503 size_t kr0 = m_reac[i][0];
504 size_t kr1 = m_reac[i][1];
507 size_t kp0 = m_prod[i][0];
508 size_t kp1 = m_prod[i][1];
512 const Group& r0 = m_sgroup[kr0];
513 const Group& r1 = m_sgroup[kr1];
514 const Group& p0 = m_sgroup[kp0];
515 const Group& p1 = m_sgroup[kp1];
517 const Group* group_a0=0, *group_b0=0, *group_c0=0,
518 *group_a1=0, *group_b1=0, *group_c1=0;
521 if (b0.valid() && b1.valid()) {
522 logfile <<
" ... ambiguous." << endl;
523 }
else if (!b0.valid() && !b1.valid()) {
524 logfile <<
" ... cannot express as A + BC = AB + C" << endl;
534 m_transfer[i][kr0][kp0] = r0;
535 m_transfer[i][kr1][kp0] = b0;
536 m_transfer[i][kr1][kp1] = p1;
542 m_transfer[i][kr1][kp1] = r1;
543 m_transfer[i][kr0][kp1] = b0;
544 m_transfer[i][kr0][kp0] = p0;
547 group_a0->fmt(logfile,e);
549 group_b0->fmt(logfile,e);
550 group_c0->fmt(logfile,e);
552 group_a0->fmt(logfile,e);
553 group_b0->fmt(logfile,e);
555 group_c0->fmt(logfile,e);
557 logfile <<
" [<= default] " << endl;
570 m_transfer[i][kr0][kp1] = r0;
571 m_transfer[i][kr1][kp1] = b0;
572 m_transfer[i][kr1][kp0] = p0;
580 m_transfer[i][kr1][kp0] = r1;
581 m_transfer[i][kr0][kp0] = b0;
582 m_transfer[i][kr0][kp1] = p1;
586 group_a1->fmt(logfile,e);
588 group_b1->fmt(logfile,e);
589 group_c1->fmt(logfile,e);
591 group_a1->fmt(logfile,e);
592 group_b1->fmt(logfile,e);
594 group_c1->fmt(logfile,e);
598 logfile <<
"... cannot parse. [ignored]" << endl;
604 void ReactionPathBuilder::writeGroup(ostream& out,
const Group& g)
606 g.fmt(out, m_elementSymbols);
609 void ReactionPathBuilder::findElements(Kinetics& kin)
615 size_t np = kin.nPhases();
617 for (
size_t i = 0; i < np; i++) {
620 size_t nel = p->nElements();
621 for (
size_t m = 0; m < nel; m++) {
622 ename = p->elementName(m);
628 if (m_enamemap.find(ename) == m_enamemap.end()) {
629 m_enamemap[ename] = m_nel + 1;
630 m_elementSymbols.push_back(ename);
635 m_atoms.resize(kin.nTotalSpecies(), m_nel, 0.0);
638 for (
size_t m = 0; m < m_nel; m++) {
639 sym = m_elementSymbols[m];
642 for (
size_t ip = 0; ip < np; ip++) {
643 ThermoPhase* p = &kin.thermo(ip);
644 size_t nsp = p->nSpecies();
645 size_t mlocal = p->elementIndex(sym);
646 for (
size_t kp = 0; kp < nsp; kp++) {
647 if (mlocal !=
npos) {
648 m_atoms(k, m) = p->nAtoms(kp, mlocal);
656 int ReactionPathBuilder::init(ostream& logfile, Kinetics& kin)
659 m_elementSymbols.clear();
661 m_ns = kin.nTotalSpecies();
662 m_nr = kin.nReactions();
666 vector<vector<size_t> > allProducts(m_nr);
667 vector<vector<size_t> > allReactants(m_nr);
668 for (
size_t i = 0; i < m_nr; i++) {
669 for (
size_t k = 0; k < m_ns; k++) {
670 if (kin.reactantStoichCoeff(k, i)) {
671 allReactants[i].push_back(k);
673 if (kin.productStoichCoeff(k, i)) {
674 allProducts[i].push_back(k);
687 m_determinate.resize(m_nr);
690 m_elatoms.resize(m_nel, m_nr);
694 map<size_t, int> net;
696 for (
size_t i = 0; i < m_nr; i++) {
704 nr = allReactants[i].size();
705 np = allProducts[i].size();
706 for (
size_t ir = 0; ir < nr; ir++) {
707 net[allReactants[i][ir]]--;
709 for (
size_t ip = 0; ip < np; ip++) {
710 net[allProducts[i][ip]]++;
713 for (k = 0; k < m_ns; k++) {
716 for (
size_t jr = 0; jr < nmol; jr++) {
717 m_reac[i].push_back(k);
719 }
else if (net[k] > 0) {
721 for (
size_t jp = 0; jp < nmol; jp++) {
722 m_prod[i].push_back(k);
727 size_t nrnet = m_reac[i].size();
734 for (n = 0; n < nrnet; n++) {
736 for (
size_t m = 0; m < m_nel; m++) {
737 m_elatoms(m,i) += m_atoms(k,m);
744 m_sgroup.resize(m_ns);
745 for (
size_t j = 0; j < m_ns; j++) {
746 for (
size_t m = 0; m < m_nel; m++) {
747 comp[m] = int(m_atoms(j,m));
749 m_sgroup[j] = Group(comp);
762 for (
size_t i = 0; i < m_nr; i++) {
763 nr = m_reac[i].size();
764 np = m_prod[i].size();
765 m_determinate[i] =
true;
766 for (
size_t m = 0; m < m_nel; m++) {
769 for (
size_t j = 0; j < nr; j++) {
770 if (m_atoms(m_reac[i][j],m) > 0) {
774 for (
size_t j = 0; j < np; j++) {
775 if (m_atoms(m_prod[i][j],m) > 0) {
779 if (nar > 1 && nap > 1) {
780 m_determinate[i] =
false;
786 findGroups(logfile, kin);
790 string reactionLabel(
size_t i,
size_t kr,
size_t nr,
791 const std::vector<size_t>& slist,
const Kinetics& s)
794 for (
size_t l = 0; l < nr; l++) {
796 label +=
" + "+ s.kineticsSpeciesName(slist[l]);
807 int ReactionPathBuilder::build(Kinetics& s,
const string& element,
808 ostream& output, ReactionPathDiagram& r,
bool quiet)
810 doublereal f, ropf, ropr, fwd, rev;
811 string fwdlabel, revlabel;
812 map<size_t, int> warn;
814 doublereal threshold = 0.0;
815 bool fwd_incl, rev_incl, force_incl;
817 size_t m = m_enamemap[element]-1;
824 s.getFwdRatesOfProgress(
DATA_PTR(m_ropf));
825 s.getRevRatesOfProgress(
DATA_PTR(m_ropr));
828 vector<string>& in_nodes = r.included();
829 vector<string>& out_nodes = r.excluded();
832 status.resize(s.nTotalSpecies(), 0);
833 for (
size_t ni = 0; ni < in_nodes.size(); ni++) {
834 status[s.kineticsSpeciesIndex(in_nodes[ni])] = 1;
836 for (
size_t ne = 0; ne < out_nodes.size(); ne++) {
837 status[s.kineticsSpeciesIndex(out_nodes[ne])] = -1;
840 for (
size_t i = 0; i < m_nr; i++) {
845 if (m_elatoms(m, i) > 0) {
846 size_t nr = m_reac[i].size();
847 size_t np = m_prod[i].size();
849 for (
size_t kr = 0; kr < nr; kr++) {
850 size_t kkr = m_reac[i][kr];
852 fwdlabel = reactionLabel(i, kr, nr, m_reac[i], s);
854 for (
size_t kp = 0; kp < np; kp++) {
855 size_t kkp = m_prod[i][kp];
857 for (
size_t l = 0; l < np; l++) {
859 revlabel +=
" + "+ s.kineticsSpeciesName(m_prod[i][l]);
865 revlabel +=
" (+ M)";
874 if ((kkr != kkp) && (m_atoms(kkr,m) > 0
875 && m_atoms(kkp,m) > 0)
876 && status[kkr] >= 0 && status[kkp] >= 0) {
885 if ((m_atoms(kkp,m) < m_elatoms(m, i)) &&
886 (m_atoms(kkr,m) < m_elatoms(m, i))) {
887 map<size_t, map<size_t, Group> >& g = m_transfer[i];
892 output <<
"*************** REACTION IGNORED ***************" << endl;
893 output <<
"Warning: no rule to determine partitioning of " << element
894 << endl <<
" in reaction " << s.reactionString(i) <<
"." << endl
895 <<
"*************** REACTION IGNORED **************" << endl;
905 f = g[kkr][kkp].nAtoms(m);
918 f = m_atoms(kkp,m) * m_atoms(kkr,m) / m_elatoms(m, i);
923 force_incl = ((status[kkr] == 1) || (status[kkp] == 1));
925 fwd_incl = ((fwd > threshold) ||
926 (fwd > 0.0 && force_incl));
927 rev_incl = ((rev > threshold) ||
928 (rev > 0.0 && force_incl));
929 if (fwd_incl || rev_incl) {
930 if (!r.hasNode(kkr)) {
931 r.addNode(kkr, s.kineticsSpeciesName(kkr), m_x[kkr]);
933 if (!r.hasNode(kkp)) {
934 r.addNode(kkp, s.kineticsSpeciesName(kkp), m_x[kkp]);
938 r.linkNodes(kkr, kkp,
int(i), fwd, fwdlabel);
941 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 a gas-phase 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.
const int THREE_BODY_RXN
A gas-phase 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.