LDMX Software
SimpleTableStreamers.cxx
1#include "Conditions/SimpleTableStreamers.h"
2
3#include <iomanip>
4
5#include "DetDescr/DetectorIDInterpreter.h"
6#include "boost/format.hpp" // IWYU pragma: keep
7
8namespace conditions {
9namespace utility {
10
11static void storeIdFields(unsigned int id, std::ostream& s) {
13
14 for (auto field : did.getFieldList()) {
15 s << ",id:\"" << field->getFieldName() << '"';
16 }
17}
18
19template <class T, class V>
20void storeT(const T& t, std::ostream& s, bool expandIds) {
21 // write the header line
22 s << "\"DetID\"";
23 if (expandIds && t.getRowCount() > 0) {
24 storeIdFields(t.getRowId(0), s);
25 }
26 for (auto name : t.getColumnNames()) {
27 s << ",\"" << name << "\"";
28 }
29 s << std::endl;
30 // write the data rows
31 for (unsigned int irow = 0; irow < t.getRowCount(); irow++) {
32 std::pair<unsigned int, std::vector<V> > row = t.getRow(irow);
33 // write the id in hex
34 s << boost::format("0x%08x") % row.first;
35 if (expandIds) {
36 ldmx::DetectorIDInterpreter did(row.first);
37
38 for (int i = 0; i < did.getFieldCount(); i++)
39 s << ',' << std::setprecision(10) << did.getFieldValue(i);
40 }
41 for (auto col : row.second) s << ',' << col;
42 s << std::endl;
43 }
44}
46 std::ostream& s, bool expandIds) {
47 storeT<IntegerTableCondition, int>(t, s, expandIds);
48}
50 std::ostream& s, bool expandIds) {
51 storeT<conditions::DoubleTableCondition, double>(t, s, expandIds);
52}
53
54static int convert(const std::string& s, int dummy) {
55 return strtol(s.c_str(), 0, 0);
56}
57
58static double convert(const std::string& s, double dummy) {
59 return atof(s.c_str());
60}
61
62static std::vector<std::string> splitCSV(const std::string& s) {
63 std::vector<std::string> rv;
64 std::string field;
65 bool inquote = false;
66 for (auto chr : s) {
67 if (chr == '"') {
68 inquote = !inquote;
69 } else if ((chr == ',' || chr == '\t') && !inquote) {
70 if (!field.empty()) {
71 // std::cout << "Field: '" << field << "'\n";
72 rv.push_back(field);
73 }
74 field.clear();
75 } else if (isspace(chr) && !inquote) { // do not add spaces
76 } else if (chr == '#' && !inquote) {
77 break; // comment
78 } else {
79 field += chr;
80 }
81 }
82 if (!field.empty()) {
83 rv.push_back(field);
84 // std::cout << "Field: '" << field << "'\n";
85 }
86 return rv;
87}
88static std::vector<std::string>::const_iterator find(
89 const std::vector<std::string>& v, const std::string& a) {
90 for (auto i = v.begin(); i != v.end(); i++) {
91 if ((*i) == a) return i;
92 }
93 return v.end();
94}
95
96template <class T, class V>
97void loadT(T& table, std::istream& is) {
98 table.clear();
99 // first work with the header line
100 std::string line;
101 std::vector<std::string> split;
102 int i_det_id = -1;
103 int iline = 0;
104 size_t ncolin;
105
106 while (!is.eof()) {
107 iline++;
108 std::getline(is, line);
109 split = splitCSV(line);
110 if (split.size() < 1) {
111 split.clear();
112 continue; // need at least an id column and as many columns as requested
113 }
114 if (find(split, "DetID") == split.end() &&
115 find(split, "subdetector") == split.end()) {
116 EXCEPTION_RAISE("ConditionsException",
117 "Malformed CSV file with no DetId or subdetector column");
118 } else {
119 break;
120 }
121 }
122 if (is.eof()) {
123 EXCEPTION_RAISE("ConditionsException", "CSV file has no valid header");
124 }
125 // ok, we have a header line. Do we have a DetID column?
126 std::vector<std::string>::const_iterator id = find(split, "DetID");
127 if (id != split.end()) {
128 // good this is simpler...
129 i_det_id = int(id - split.begin());
130 } else {
131 EXCEPTION_RAISE("MissingFeatureException",
132 "Cannot actually load CSV file without valid DetID column "
133 "at this point");
134 }
135 ncolin = split.size();
136 // check for columns which match all those requested in the table
137 std::map<unsigned int, int> table_to_csv;
138 for (unsigned int ic = 0; ic != table.getColumnCount(); ic++) {
139 auto fc = find(split, table.getColumnName(ic));
140 if (fc == split.end()) {
141 EXCEPTION_RAISE(
142 "ConditionsException",
143 "Missing column '" + table.getColumnName(ic) + "' in CSV table load");
144 }
145 table_to_csv[ic] = int(fc - split.begin());
146 }
147
148 // processing additional lines
149 while (!is.eof()) {
150 iline++;
151 std::getline(is, line);
152 split = splitCSV(line);
153 if (split.size() == 0) continue; // ignore comment lines
154 if (split.size() != ncolin) {
155 EXCEPTION_RAISE("ConditionsException", "Mismatched number of columns (" +
156 std::to_string(split.size()) +
157 "!=" + std::to_string(ncolin) +
158 ") on line " +
159 std::to_string(iline));
160 }
161 unsigned int temp_id(0);
162 std::vector<V> values(table_to_csv.size(), 0);
163 if (i_det_id >= 0) temp_id = strtoul(split[i_det_id].c_str(), 0, 0);
164 V dummy(0);
165 for (auto icopy : table_to_csv) {
166 values[icopy.first] = convert(split[icopy.second], dummy);
167 }
168 if (temp_id != 0) {
169 table.add(temp_id, values);
170 }
171 }
172}
173
175 std::istream& is) {
176 loadT<IntegerTableCondition, int>(table, is);
177}
178
180 std::istream& is) {
181 loadT<conditions::DoubleTableCondition, double>(table, is);
182}
183} // namespace utility
184} // namespace conditions
static void load(IntegerTableCondition &, std::istream &)
Load the table from a stream Columns must be defined by the user.
static void store(const IntegerTableCondition &, std::ostream &, bool expandIds=true)
Convert the table into a stream.
Class provides an "introspection" capability for the 32-bit packed IDs used for uniquely identifying ...