42{
45
46 string inputDetector;
47 string outputDetector;
49 int min_working_signals;
51
52 try {
53 JParser<> zap(
"Adjust z-positions of DOMs without acoustic data and write modified detector");
54
55 zap[
'a'] =
make_field(inputDetector,
"input detector file (.datx)");
56 zap[
'o'] =
make_field(outputDetector,
"output detector file (.datx)");
57 zap[
'f'] =
make_field(inputFile,
"output of JAcousticEventBuilder[.sh]");
58 zap[
'm'] =
make_field(min_working_signals,
"minimum number of acoustic signals to consider a module working") = 10;
60
61 zap(argc, argv);
62 }
63 catch (const exception &e) {
64 FATAL(e.what() << endl);
65 }
66
67 if (inputDetector.empty() || outputDetector.empty() || inputFile.empty()) {
68 FATAL(
"Missing required arguments: -a <input detector> -o <output detector> -f <event files files...>" << endl);
69 }
70
71
73 try {
75 }
78 }
79
81
82
84 for (JDetector::const_iterator m =
detector.begin(); m !=
detector.end(); ++m) {
85 acoustic_counts[m->getID()] = 0;
86 }
87
88
89 for (const string& file_name : inputFile) {
90 try {
92 while (in.hasNext()) {
93 const JEvent* evt = in.next();
94
95 if (evt->empty()) continue;
96
97
98 for (JEvent::const_iterator hit_it = evt->begin(); hit_it != evt->end(); ++hit_it) {
100 if (router.hasModule(recv_id)) {
101 acoustic_counts[recv_id.getID()]++;
102 }
103 }
104 }
105 }
106 catch (const exception &e) {
107 FATAL(
"Error reading event file " << file_name <<
": " << e.what() << endl);
108 }
109 }
110
111
113 for (JDetector::const_iterator m =
detector.begin(); m !=
detector.end(); ++m) {
114 has_working[m->getID()] = (acoustic_counts[m->getID()] >= min_working_signals);
115 }
116
117
119 for (JDetector::const_iterator m =
detector.begin(); m !=
detector.end(); ++m) {
120 by_du[m->getString()].push_back(&(*m));
121 }
122
123
125 cout << "Working module counts per DU:" << endl;
126 for (const auto &entry : by_du) {
127 int du = entry.first;
128 const auto &vec = entry.second;
129 int working_count = 0;
130 for (const auto &mi : vec) {
131 if (has_working[mi->getID()]) ++working_count;
132 }
133 cout << " DU " << du << ": " << working_count << " working modules out of " << vec.size() << endl;
134 }
135 }
136
137
138 bool is_arca = false;
139 bool is_orca = false;
140
141 for (const auto &entry : by_du) {
142 int du = entry.first;
143 const auto &vec = entry.second;
144
145
146 auto it = find_if(vec.begin(), vec.end(),
147 [](
const JModule* m){ return m->getFloor() == 18; });
148
149 if (it == vec.end()) {
150 WARNING(
"DU " << du <<
" has no floor 18 module" << endl);
151 continue;
152 }
153
154 double height = (*it)->getPosition().getZ();
155
157 is_arca = true;
158 } else {
159 is_orca = true;
160 }
161 }
162
163
164 if (is_arca && is_orca) {
165 FATAL(
"Inconsistent classification: some DUs appear to be ARCA and others ORCA based on floor 18 height" << endl);
166 } else if (!is_arca && !is_orca) {
167 FATAL(
"Could not classify as ARCA or ORCA" << endl);
168 }
169
170
172 if (is_arca) {
175 }
176 } else {
179 }
180 }
181
182
184 cout << "Detector classified as " << (is_arca ? "ARCA" : "ORCA") << endl;
185 cout << "Ideal string fractional z-positions used:" << endl;
186 for (const auto &entry : ideal_string) {
187 cout << " Floor " << entry.first << ": " << entry.second << endl;
188 }
189 }
190
191
193
194 for (const auto &entry : by_du) {
195 int du = entry.first;
196 const auto &vec = entry.second;
197
198
201 if (has_working[m->getID()] && m->getFloor() > 0)
202 working_valid.push_back(m);
203 }
204
205 if (working_valid.size() < 2) continue;
206
207
209 cout << "DU " << du << ": Working modules for fit:" << endl;
210 for (const auto &mi : working_valid) {
211 cout <<
" Module ID " << mi->getID() <<
", Floor " << mi->getFloor() <<
", Z " <<
FIXED(9,4) << mi->getPosition().getZ() << endl;
212 }
213 }
214
215 double sum_x = 0.0, sum_y = 0.0;
216 for (
const JModule* m : working_valid) {
217 double frac = 0.0;
218 auto it = ideal_string.find(m->getFloor());
219 if (it != ideal_string.end()) frac = it->second;
220 sum_x += frac;
221 sum_y += m->getPosition().getZ();
222 }
223
224
225 double mean_x = sum_x / working_valid.size();
226 double mean_y = sum_y / working_valid.size();
227
228 double ss_xx = 0.0, ss_xy = 0.0;
229 for (
const JModule* m : working_valid) {
230 double frac = 0.0;
231 auto it = ideal_string.find(m->getFloor());
232 if (it != ideal_string.end()) frac = it->second;
233
234
235 double diff_x = frac - mean_x;
236 ss_xx += diff_x * diff_x;
237 ss_xy += diff_x * (m->getPosition().getZ() - mean_y);
238 }
239
240
241 if (std::abs(ss_xx) < 1e-12) continue;
242
243 double L = ss_xy / ss_xx;
244 double Z0 = mean_y - L * mean_x;
245
246 length_fits[du] = L;
247 offset_fits[du] = Z0;
248 }
249
250
252 for (const auto &entry : length_fits) {
253 int du = entry.first;
254 cout << "DU " << du << ": length fit = " << length_fits[du] << ", offset fit = " << offset_fits[du] << endl;
255 }
256 }
257
258
259 int changed = 0;
260 for (JDetector::iterator module =
detector.begin(); module !=
detector.end(); ++module) {
261 const int mid = module->getID();
262 const int floor = module->getFloor();
263 const int du = module->getString();
264
265 if (has_working[mid] || floor == 0) continue;
266
267 if (length_fits.count(du) == 0 || offset_fits.count(du) == 0) continue;
268
269 double frac = 0.0;
270 auto it = ideal_string.find(floor);
271 if (it != ideal_string.end()) frac = it->second;
272
273 double adjusted = frac * length_fits[du] + offset_fits[du];
274
275
276 double x =
module->getX();
277 double y =
module->getY();
278
279 module->set(JVector3D(x, y, adjusted));
280 ++changed;
281
282
283 cout << "Adjusted module " << mid << " (DU " << du << ", floor " << floor << "): " << adjusted << endl;
284 }
285
286
288
289 try {
291 }
294 }
295
296 cout << "Applied adjustments to " << changed << " modules and wrote " << outputDetector << endl;
297
298 return 0;
299}
#define make_field(A,...)
macro to convert parameter to JParserTemplateElement object
Router for direct addressing of module data in detector data structure.
Data structure for a composite optical module.
Auxiliary class for object identification.
Utility class to parse command line options.
General purpose class for object reading from a list of file names.
Object reading from a list of files.
static const std::vector< double > IDEAL_ORCA_STRING
void load(const std::string &file_name, JDetector &detector)
Load detector from input file.
static const std::vector< double > IDEAL_ARCA_STRING
void store(const std::string &file_name, const JDetector &detector)
Store detector to output file.
static const double STRING_HEIGHT_CUTOFF
This name space includes all other name spaces (except KM3NETDAQ, KM3NET and ANTARES).
Auxiliary data structure for floating point format specification.