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