← Documentation
ADS-IDAC Engine 5.0.0
fta_parser.cpp
Go to the documentation of this file.
2
4
5#include <sstream>
6#include <string>
7
8namespace faulttree {
9
10namespace {
11
12double parseProbability(const std::string &text, const std::string &node_name) {
13 try {
14 std::size_t consumed = 0;
15 double value = std::stod(text, &consumed);
16 while (consumed < text.size() &&
17 std::isspace(static_cast<unsigned char>(text[consumed])) != 0) {
18 ++consumed;
19 }
20 if (consumed != text.size()) {
21 throw FaultTreeError("basic event '" + node_name +
22 "' has a malformed failureProbability '" + text + "'");
23 }
24 return value;
25 } catch (const std::invalid_argument &) {
26 throw FaultTreeError("basic event '" + node_name +
27 "' has a malformed failureProbability '" + text + "'");
28 } catch (const std::out_of_range &) {
29 throw FaultTreeError("basic event '" + node_name +
30 "' has an out-of-range failureProbability '" + text + "'");
31 }
32}
33
34int parseK(const std::string &text, const std::string &node_name) {
35 if (text.empty()) { return 0; }
36 try {
37 std::size_t consumed = 0;
38 int value = std::stoi(text, &consumed);
39 if (consumed != text.size()) {
40 throw FaultTreeError("K/N gate '" + node_name + "' has a malformed k '" +
41 text + "'");
42 }
43 return value;
44 } catch (const std::invalid_argument &) {
45 throw FaultTreeError("K/N gate '" + node_name + "' has a malformed k '" +
46 text + "'");
47 } catch (const std::out_of_range &) {
48 throw FaultTreeError("K/N gate '" + node_name + "' has an out-of-range k '" +
49 text + "'");
50 }
51}
52
55std::string parseNode(const xml::Element &element, FaultTree &tree) {
56 if (element.attribute("id") == nullptr) { return {}; }
57
58 const xml::Element *info = element.child("node");
59 if (info == nullptr) {
60 throw FaultTreeError("an ftaNode is missing its <node> definition");
61 }
62 const std::string *name_attr = info->attribute("name");
63 if (name_attr == nullptr || name_attr->empty()) {
64 throw FaultTreeError("an ftaNode is missing its node name");
65 }
66 const std::string name = *name_attr;
67
68 // Identity is the node name: a node that appears again anywhere in the file
69 // is the same node, which is what shares repeated (common-cause) events.
70 if (tree.hasNode(name)) { return name; }
71
72 const std::string type = element.attributeOr("type", "");
73 Node node;
74 node.name = name;
75
76 if (type == "2" || type == "3") {
77 if (element.child("linkedBBN") != nullptr) {
78 throw FaultTreeError("basic event '" + name +
79 "' is linked to a BBN variable, which this "
80 "quantifier does not support");
81 }
82 node.type = GateType::Basic;
83 node.probability =
84 parseProbability(element.attributeOr("failureProbability", "0"), name);
85 } else if (type == "4") {
86 const xml::Element *link = element.child("transferUpFTADiagram");
87 if (link == nullptr) {
88 throw FaultTreeError("transfer gate '" + name +
89 "' has no transferUpFTADiagram reference");
90 }
91 const std::string ref = link->attributeOr("ref", "");
92 if (ref.empty()) {
93 throw FaultTreeError("transfer gate '" + name + "' has an empty reference");
94 }
95 // The legacy resolver models a transfer as an AND over the referenced
96 // diagram, so a transfer contributes nothing of its own.
97 node.type = GateType::And;
98 node.children.push_back(ref);
99 } else if (type == "5") {
100 // Diagram bookkeeping, not logic: GeNIe emits a type 5 node listing the
101 // diagram's transfer-up children (<tranferUpChild ref=...>, its spelling).
102 // The legacy resolver had no branch for it and fell through to the gate
103 // case with an uninitialised gate type, so it never quantified meaningfully.
104 return {};
105 } else if (type == "0" || type == "1" || type == "6" || type == "7") {
106 if (type == "0") {
107 node.type = GateType::And;
108 } else if (type == "1") {
109 node.type = GateType::Or;
110 } else if (type == "6") {
111 node.type = GateType::KofN;
112 } else {
113 node.type = GateType::Not;
114 }
115 node.k = parseK(element.attributeOr("k", ""), name);
116
117 for (const auto &child : element.children) {
118 if (child.name != "ftaNode") { continue; }
119 std::string child_name = parseNode(child, tree);
120 if (!child_name.empty()) { node.children.push_back(child_name); }
121 }
122 } else {
123 // The legacy resolver left the gate type uninitialised here; we refuse
124 // rather than quantify something undefined.
125 throw FaultTreeError("node '" + name + "' has unsupported type '" + type + "'");
126 }
127
128 tree.addNode(std::move(node));
129 return name;
130}
131
134FaultTree buildFromRoot(const xml::Element &root, const std::string &origin) {
135 if (root.name != "ftaDiagram") {
136 throw FaultTreeError("expected a <ftaDiagram> root in " + origin +
137 ", found <" + root.name + ">");
138 }
139
140 FaultTree tree;
141 std::string top;
142 for (const auto &child : root.children) {
143 if (child.name != "ftaNode") { continue; }
144 std::string name = parseNode(child, tree);
145 // The diagram's first node is its top event; later siblings are subtrees
146 // reachable through transfer gates.
147 if (!name.empty() && top.empty()) { top = name; }
148 }
149 if (top.empty()) { throw FaultTreeError(origin + " has no top node"); }
150
151 tree.setTop(top);
152 tree.validate();
153 return tree;
154}
155
156} // namespace
157
158FaultTree parseFtaString(const std::string &text) {
159 return buildFromRoot(xml::parse(text), "the fault tree diagram");
160}
161
162FaultTree parseFtaFile(const std::string &path) {
163 return buildFromRoot(xml::parseFile(path), "'" + path + "'");
164}
165
166} // namespace faulttree
A fault tree: nodes keyed by name, plus a designated top event.
Definition: fault_tree.hpp:78
Reader that turns a GeNIe/SMILE .fta fault tree document into a validated faulttree::FaultTree.
Element parseFile(const std::string &path)
Definition: xml_lite.cpp:261
Element parse(const std::string &text)
Definition: xml_lite.cpp:259
FaultTree parseFtaFile(const std::string &path)
Parses a .fta file from disk.
Definition: fta_parser.cpp:162
FaultTree parseFtaString(const std::string &text)
Parses .fta content held in memory.
Definition: fta_parser.cpp:158
@ Or
fails when any input fails (.fta type 1)
@ KofN
fails when at least k inputs fail (.fta type 6)
@ Basic
basic event, quantified by probability
@ Not
fails when its single input does not (.fta type 7)
@ And
fails when every input fails (.fta type 0)
Minimal XML reader used by the .fta parser: the Element tree, its lookup helpers, and parse() / parse...