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 if (m_label.size() == 0) {
61 for (
const auto& label : m_label) {
62 v = label.second/m_total;
63 if (m_label.size() == 1) {
64 s << label.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 for (
const auto& node : m_nodes) {
109 size_t nn = nPaths();
110 for (
size_t n = 0; n < nn; n++) {
111 delete m_pathlist[n];
117 doublereal flmax = 0.0;
118 for (
size_t i = 0; i < nPaths(); i++) {
120 flmax = std::max(p->flow(), flmax);
123 for (
size_t i = 0; i < nPaths(); i++) {
124 for (
const auto& rxn : path(i)->reactionMap()) {
125 double flxratio = rxn.second/flmax;
126 if (flxratio > threshold) {
127 m_rxns[rxn.first] = 1;
132 for (
const auto& rxn : m_rxns) {
133 r.push_back(
int(rxn.first));
138 void ReactionPathDiagram::add(ReactionPathDiagram& d)
140 for (
size_t n = 0; n < nPaths(); n++) {
142 size_t k1 = p->begin()->number;
143 size_t k2 = p->end()->number;
144 p->setFlow(p->flow() + d.flow(k1,k2));
148 void ReactionPathDiagram::findMajorPaths(doublereal athreshold,
size_t lda,
152 for (
size_t n = 0; n < nNodes(); n++) {
153 for (
size_t m = n+1; m < nNodes(); m++) {
154 size_t k1 = m_speciesNumber[n];
155 size_t k2 = m_speciesNumber[m];
156 double fl = fabs(
netFlow(k1,k2));
157 netmax = std::max(fl, netmax);
160 for (
size_t n = 0; n < nNodes(); n++) {
161 for (
size_t m = n+1; m < nNodes(); m++) {
162 size_t k1 = m_speciesNumber[n];
163 size_t k2 = m_speciesNumber[m];
164 double fl = fabs(
netFlow(k1,k2));
165 if (fl > athreshold*netmax) {
172 void ReactionPathDiagram::writeData(ostream& s)
175 for (
size_t i1 = 0; i1 < nNodes(); i1++) {
176 size_t k1 = m_speciesNumber[i1];
177 s << m_nodes[k1]->name <<
" ";
180 for (
size_t i1 = 0; i1 < nNodes(); i1++) {
181 size_t k1 = m_speciesNumber[i1];
182 for (
size_t i2 = i1+1; i2 < nNodes(); i2++) {
183 size_t k2 = m_speciesNumber[i2];
184 double f1 =
flow(k1, k2);
185 double f2 =
flow(k2, k1);
186 s << m_nodes[k1]->name <<
" " << m_nodes[k2]->name
187 <<
" " << f1 <<
" " << -f2 << endl;
194 doublereal flmax = 0.0;
198 s <<
"digraph " << name <<
" {" << endl;
211 if (dot_options !=
"") {
212 s << dot_options << endl;
216 if (flow_type == NetFlow) {
220 for (
size_t i1 = 0; i1 < nNodes(); i1++) {
221 size_t k1 = m_speciesNumber[i1];
223 for (
size_t i2 = i1+1; i2 < nNodes(); i2++) {
224 size_t k2 = m_speciesNumber[i2];
229 flmax = std::max(flx, flmax);
235 flmax = std::max(flmax, 1e-10);
238 for (
size_t i1 = 0; i1 < nNodes(); i1++) {
239 size_t k1 = m_speciesNumber[i1];
240 for (
size_t i2 = i1+1; i2 < nNodes(); i2++) {
241 size_t k2 = m_speciesNumber[i2];
243 if (m_local !=
npos && k1 != m_local && k2 != m_local) {
254 flxratio = flx/flmax;
258 flxratio = -flx/flmax;
263 if (flxratio >= threshold) {
268 s <<
"s" << kbegin <<
" -> s" << kend;
269 s <<
"[fontname=\""+m_font+
"\", style=\"setlinewidth(";
271 if (arrow_width < 0) {
272 double lwidth = 1.0 - 4.0
273 * log10(flxratio/threshold)/log10(threshold) + 1.0;
274 s << lwidth <<
")\"";
276 << std::min(6.0, 0.5*lwidth);
278 s << arrow_width <<
")\"";
279 s <<
", arrowsize=" << flxratio + 1;
282 doublereal hue = 0.7;
283 doublereal bright = 0.9;
284 s <<
", color=" <<
"\"" << hue <<
", " 286 <<
", " << bright <<
"\"" << endl;
288 if (flxratio > label_min) {
289 s <<
", label=\" " << flxratio;
291 if (
flow(kbegin, kend) > 0.0) {
293 <<
flow(kbegin, kend)/flmax <<
"\\l";
294 path(kbegin, kend)->writeLabel(s);
296 if (
flow(kend, kbegin) > 0.0) {
298 <<
flow(kend,kbegin)/flmax <<
"\\l";
299 path(kend, kbegin)->writeLabel(s);
310 for (
size_t i = 0; i < nPaths(); i++) {
311 flmax = std::max(path(i)->
flow(), flmax);
314 for (
size_t i = 0; i < nPaths(); i++) {
316 double flxratio = p->flow()/flmax;
317 if (m_local !=
npos) {
318 if (p->begin()->number != m_local
319 && p->end()->number != m_local) {
323 if (flxratio > threshold) {
324 p->begin()->visible =
true;
325 p->end()->visible =
true;
326 s <<
"s" << p->begin()->number
327 <<
" -> s" << p->end()->number;
329 if (arrow_width < 0) {
330 double lwidth = 1.0 - 4.0 * log10(flxratio/threshold)/log10(threshold)
332 s <<
"[fontname=\""+m_font+
"\", style=\"setlinewidth(" 336 << std::min(6.0, 0.5*lwidth);
338 s <<
", style=\"setlinewidth(" 339 << arrow_width <<
")\"";
340 s <<
", arrowsize=" << flxratio + 1;
342 doublereal hue = 0.7;
343 doublereal bright = 0.9;
344 s <<
", color=" <<
"\"" << hue <<
", " << flxratio + 0.5
345 <<
", " << bright <<
"\"" << endl;
347 if (flxratio > label_min) {
348 s <<
", label = \" " << flxratio;
360 for (
const auto& node : m_nodes) {
362 s <<
"s" << node.first <<
" [ fontname=\""+m_font+
"\", label=\"" << node.second->
name 366 s <<
" label = " <<
"\"" <<
"Scale = " 367 << flmax <<
"\\l " << title <<
"\";" << endl;
368 s <<
" fontname = \""+m_font+
"\";" << endl <<
"}" << endl;
372 void ReactionPathDiagram::addNode(
size_t k,
const string& nm, doublereal x)
376 m_nodes[k]->number = k;
377 m_nodes[k]->name = nm;
378 m_nodes[k]->value = x;
379 m_speciesNumber.push_back(k);
383 void ReactionPathDiagram::linkNodes(
size_t k1,
size_t k2,
size_t rxn,
384 doublereal value,
string legend)
386 Path* ff = m_paths[k1][k2];
388 ff=
new Path(m_nodes[k1], m_nodes[k2]);
389 m_paths[k1][k2] = ff;
390 m_pathlist.push_back(ff);
392 ff->addReaction(rxn, value, legend);
394 m_flxmax = std::max(ff->flow(), m_flxmax);
397 std::vector<size_t> ReactionPathDiagram::species()
399 return m_speciesNumber;
402 int ReactionPathBuilder::findGroups(ostream& logfile, Kinetics& s)
404 m_groups.resize(m_nr);
405 for (
size_t i = 0; i < m_nr; i++) {
406 logfile << endl <<
"Reaction " << i+1 <<
": " 407 << s.reactionString(i);
409 if (m_determinate[i]) {
410 logfile <<
" ... OK." << endl;
411 }
else if (m_reac[i].size() == 2 && m_prod[i].size() == 2) {
413 size_t kr0 = m_reac[i][0];
414 size_t kr1 = m_reac[i][1];
417 size_t kp0 = m_prod[i][0];
418 size_t kp1 = m_prod[i][1];
421 const Group& r0 = m_sgroup[kr0];
422 const Group& r1 = m_sgroup[kr1];
423 const Group& p0 = m_sgroup[kp0];
424 const Group& p1 = m_sgroup[kp1];
426 const Group* group_a0=0, *group_b0=0, *group_c0=0,
427 *group_a1=0, *group_b1=0, *group_c1=0;
430 if (b0.valid() && b1.valid()) {
431 logfile <<
" ... ambiguous." << endl;
432 }
else if (!b0.valid() && !b1.valid()) {
433 logfile <<
" ... cannot express as A + BC = AB + C" << endl;
443 m_transfer[i][kr0][kp0] = r0;
444 m_transfer[i][kr1][kp0] = b0;
445 m_transfer[i][kr1][kp1] = p1;
451 m_transfer[i][kr1][kp1] = r1;
452 m_transfer[i][kr0][kp1] = b0;
453 m_transfer[i][kr0][kp0] = p0;
456 group_a0->fmt(logfile, m_elementSymbols);
458 group_b0->fmt(logfile,m_elementSymbols);
459 group_c0->fmt(logfile, m_elementSymbols);
461 group_a0->fmt(logfile, m_elementSymbols);
462 group_b0->fmt(logfile, m_elementSymbols);
464 group_c0->fmt(logfile, m_elementSymbols);
466 logfile <<
" [<= default] " << endl;
478 m_transfer[i][kr0][kp1] = r0;
479 m_transfer[i][kr1][kp1] = b0;
480 m_transfer[i][kr1][kp0] = p0;
488 m_transfer[i][kr1][kp0] = r1;
489 m_transfer[i][kr0][kp0] = b0;
490 m_transfer[i][kr0][kp1] = p1;
494 group_a1->fmt(logfile, m_elementSymbols);
496 group_b1->fmt(logfile, m_elementSymbols);
497 group_c1->fmt(logfile, m_elementSymbols);
499 group_a1->fmt(logfile, m_elementSymbols);
500 group_b1->fmt(logfile, m_elementSymbols);
502 group_c1->fmt(logfile, m_elementSymbols);
506 logfile <<
"... cannot parse. [ignored]" << endl;
512 void ReactionPathBuilder::findElements(Kinetics& kin)
516 for (
size_t i = 0; i < kin.nPhases(); i++) {
517 ThermoPhase* p = &kin.thermo(i);
519 for (
size_t m = 0; m < p->nElements(); m++) {
520 string ename = p->elementName(m);
526 if (m_enamemap.find(ename) == m_enamemap.end()) {
527 m_enamemap[ename] = m_nel + 1;
528 m_elementSymbols.push_back(ename);
533 m_atoms.resize(kin.nTotalSpecies(), m_nel, 0.0);
535 for (
size_t m = 0; m < m_nel; m++) {
538 for (
size_t ip = 0; ip < kin.nPhases(); ip++) {
539 ThermoPhase* p = &kin.thermo(ip);
540 size_t mlocal = p->elementIndex(m_elementSymbols[m]);
541 for (
size_t kp = 0; kp < p->nSpecies(); kp++) {
542 if (mlocal !=
npos) {
543 m_atoms(k, m) = p->nAtoms(kp, mlocal);
551 int ReactionPathBuilder::init(ostream& logfile, Kinetics& kin)
554 m_elementSymbols.clear();
556 m_ns = kin.nTotalSpecies();
557 m_nr = kin.nReactions();
561 vector<vector<size_t> > allProducts(m_nr);
562 vector<vector<size_t> > allReactants(m_nr);
563 for (
size_t i = 0; i < m_nr; i++) {
564 for (
size_t k = 0; k < m_ns; k++) {
565 if (kin.reactantStoichCoeff(k, i)) {
566 allReactants[i].push_back(k);
568 if (kin.productStoichCoeff(k, i)) {
569 allProducts[i].push_back(k);
580 m_determinate.resize(m_nr);
582 m_elatoms.resize(m_nel, m_nr);
584 for (
size_t i = 0; i < m_nr; i++) {
589 map<size_t, int> net;
590 size_t nr = allReactants[i].size();
591 size_t np = allProducts[i].size();
592 for (
size_t ir = 0; ir < nr; ir++) {
593 net[allReactants[i][ir]]--;
595 for (
size_t ip = 0; ip < np; ip++) {
596 net[allProducts[i][ip]]++;
599 for (
size_t k = 0; k < m_ns; k++) {
601 size_t nmol = -net[k];
602 for (
size_t jr = 0; jr < nmol; jr++) {
603 m_reac[i].push_back(k);
605 }
else if (net[k] > 0) {
606 size_t nmol = net[k];
607 for (
size_t jp = 0; jp < nmol; jp++) {
608 m_prod[i].push_back(k);
613 size_t nrnet = m_reac[i].size();
618 for (
size_t n = 0; n < nrnet; n++) {
619 size_t k = m_reac[i][n];
620 for (
size_t m = 0; m < m_nel; m++) {
621 m_elatoms(m,i) += m_atoms(k,m);
628 m_sgroup.resize(m_ns);
629 for (
size_t j = 0; j < m_ns; j++) {
630 for (
size_t m = 0; m < m_nel; m++) {
631 comp[m] = int(m_atoms(j,m));
633 m_sgroup[j] = Group(comp);
642 for (
size_t i = 0; i < m_nr; i++) {
643 size_t nr = m_reac[i].size();
644 size_t np = m_prod[i].size();
645 m_determinate[i] =
true;
646 for (
size_t m = 0; m < m_nel; m++) {
649 for (
size_t j = 0; j < nr; j++) {
650 if (m_atoms(m_reac[i][j],m) > 0) {
654 for (
size_t j = 0; j < np; j++) {
655 if (m_atoms(m_prod[i][j],m) > 0) {
659 if (nar > 1 && nap > 1) {
660 m_determinate[i] =
false;
666 findGroups(logfile, kin);
670 string reactionLabel(
size_t i,
size_t kr,
size_t nr,
671 const std::vector<size_t>& slist,
const Kinetics& s)
674 for (
size_t j = 0; j < nr; j++) {
676 label +=
" + "+ s.kineticsSpeciesName(slist[j]);
687 int ReactionPathBuilder::build(Kinetics& s,
const string& element,
688 ostream& output, ReactionPathDiagram& r,
bool quiet)
690 map<size_t, int> warn;
691 doublereal threshold = 0.0;
692 size_t m = m_enamemap[element]-1;
698 s.getFwdRatesOfProgress(m_ropf.data());
699 s.getRevRatesOfProgress(m_ropr.data());
702 vector<string>& in_nodes = r.included();
703 vector<string>& out_nodes = r.excluded();
706 for (
size_t ni = 0; ni < in_nodes.size(); ni++) {
707 status[s.kineticsSpeciesIndex(in_nodes[ni])] = 1;
709 for (
size_t ne = 0; ne < out_nodes.size(); ne++) {
710 status[s.kineticsSpeciesIndex(out_nodes[ne])] = -1;
713 for (
size_t i = 0; i < m_nr; i++) {
714 double ropf = m_ropf[i];
715 double ropr = m_ropr[i];
718 if (m_elatoms(m, i) > 0) {
719 size_t nr = m_reac[i].size();
720 size_t np = m_prod[i].size();
722 for (
size_t kr = 0; kr < nr; kr++) {
723 size_t kkr = m_reac[i][kr];
724 string fwdlabel = reactionLabel(i, kr, nr, m_reac[i], s);
726 for (
size_t kp = 0; kp < np; kp++) {
727 size_t kkp = m_prod[i][kp];
728 string revlabel =
"";
729 for (
size_t j = 0; j < np; j++) {
731 revlabel +=
" + "+ s.kineticsSpeciesName(m_prod[i][j]);
737 revlabel +=
" (+ M)";
743 if ((kkr != kkp) && (m_atoms(kkr,m) > 0
744 && m_atoms(kkp,m) > 0)
745 && status[kkr] >= 0 && status[kkp] >= 0) {
752 if ((m_atoms(kkp,m) < m_elatoms(m, i)) &&
753 (m_atoms(kkr,m) < m_elatoms(m, i))) {
754 map<size_t, map<size_t, Group> >& g = m_transfer[i];
756 if (!warn[i] && !quiet) {
758 output <<
"*************** REACTION IGNORED ***************" << endl;
759 output <<
"Warning: no rule to determine partitioning of " << element
760 << endl <<
" in reaction " << s.reactionString(i) <<
"." << endl
761 <<
"*************** REACTION IGNORED **************" << endl;
770 f = g[kkr][kkp].nAtoms(m);
779 f = m_atoms(kkp,m) * m_atoms(kkr,m) / m_elatoms(m, i);
784 bool force_incl = ((status[kkr] == 1) || (status[kkp] == 1));
786 bool fwd_incl = ((fwd > threshold) ||
787 (fwd > 0.0 && force_incl));
788 bool rev_incl = ((rev > threshold) ||
789 (rev > 0.0 && force_incl));
790 if (fwd_incl || rev_incl) {
791 if (!r.hasNode(kkr)) {
792 r.addNode(kkr, s.kineticsSpeciesName(kkr), m_x[kkr]);
794 if (!r.hasNode(kkp)) {
795 r.addNode(kkp, s.kineticsSpeciesName(kkp), m_x[kkp]);
799 r.linkNodes(kkr, kkp,
int(i), fwd, fwdlabel);
802 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.
std::string name
Label on graph.
Classes for reaction path analysis.
doublereal netFlow(size_t k1, size_t k2)
The net flow from node k1 to node k2.
Namespace for the Cantera kernel.