Jpp 21.0.0-rc.1-88-g0130508c4
the software that should make you happy
Loading...
Searching...
No Matches
JAdjustZpos.cc
Go to the documentation of this file.
1#include <string>
2#include <iostream>
3#include <iomanip>
4#include <vector>
5#include <set>
6#include <map>
7#include <algorithm>
8#include <cmath>
9#include <sstream>
10#include <fstream>
11
12#include "TROOT.h"
13#include "TFile.h"
14
18#include "JAcoustics/JHit.hh"
21#include "JAcoustics/JEvent.hh"
22#include "JAcoustics/JEvt.hh"
26
29#include "JDetector/JModule.hh"
33#include "JSupport/JMeta.hh"
34
37
38#include "Jeep/JParser.hh"
39#include "Jeep/JMessage.hh"
40
41int main(int argc, char** argv)
42{
43 using namespace std;
44 using namespace JPP;
45
46 string inputDetector;
47 string outputDetector;
49 int min_working_signals;
50 int debug;
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;
59 zap['d'] = make_field(debug, "debug level") = 0;
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 // Load detector
73 try {
74 load(inputDetector, detector);
75 }
76 catch (const JException &e) {
77 FATAL(e);
78 }
79
80 JModuleRouter router(detector);
81
82 // Build map for acoustic counts per module
83 map<int, int> acoustic_counts; // module_id -> count
84 for (JDetector::const_iterator m = detector.begin(); m != detector.end(); ++m) {
85 acoustic_counts[m->getID()] = 0;
86 }
87
88 // Scan event files and count acoustic hits per module
89 for (const string& file_name : inputFile) {
90 try {
91 JSingleFileScanner<JEvent> in(file_name, 1); // read objects one by one
92 while (in.hasNext()) {
93 const JEvent* evt = in.next();
94
95 if (evt->empty()) continue;
96
97 // for each transmission/hit in the event, get receiver id and increment count for corresponding module
98 for (JEvent::const_iterator hit_it = evt->begin(); hit_it != evt->end(); ++hit_it) {
99 const JModuleIdentifier recv_id = hit_it->getID();
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 // Map module_id -> has_working based on acoustic counts and cutoff
112 map<int, bool> has_working;
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 // Group modules by DU
119 for (JDetector::const_iterator m = detector.begin(); m != detector.end(); ++m) {
120 by_du[m->getString()].push_back(&(*m));
121 }
122
123 // DEBUG: print number of working modules per DU
124 if (debug) {
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 // Check all DU floor 18 height and classify as ARCA or ORCA based on cutoff
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 // Find floor 18 module
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
156 if (height >= STRING_HEIGHT_CUTOFF) {
157 is_arca = true;
158 } else {
159 is_orca = true;
160 }
161 }
162
163 // All DUs must be consistent, otherwise error out
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 // Select ideal string based on ARCA/ORCA classification
171 map<int, double> ideal_string; // floor -> fractional z
172 if (is_arca) {
173 for (size_t i = 0; i < IDEAL_ARCA_STRING.size(); ++i) {
174 ideal_string[static_cast<int>(i)] = IDEAL_ARCA_STRING[i];
175 }
176 } else {
177 for (size_t i = 0; i < IDEAL_ORCA_STRING.size(); ++i) {
178 ideal_string[static_cast<int>(i)] = IDEAL_ORCA_STRING[i];
179 }
180 }
181
182 // Debug: print ARCA/ORCA classification and ideal string values
183 if (debug) {
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 // Fit per DU: linear model pos_z = frac*L + Z0 => solve normal eqns
192 map<int,double> length_fits, offset_fits;
193
194 for (const auto &entry : by_du) {
195 int du = entry.first;
196 const auto &vec = entry.second;
197
198 // Filter only working modules that are NOT floor 0
199 vector<const JModule*> working_valid;
200 for (const JModule* m : vec) {
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 // DEBUG: print all working modules for this DU with their floor and z
208 if (debug) {
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 // Calculate means (center data for numerical stability)
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 // Centering the data
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 // Slope (L) and Intercept (Z0)
241 if (std::abs(ss_xx) < 1e-12) continue; // Vertical line protection
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 // DEBUG: print fit results
251 if (debug) {
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 // Apply adjustments to detector in-memory
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; // keep original
266
267 if (length_fits.count(du) == 0 || offset_fits.count(du) == 0) continue; // no fit
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 // keep x,y as before, set new z
276 double x = module->getX();
277 double y = module->getY();
278
279 module->set(JVector3D(x, y, adjusted));
280 ++changed;
281
282 // print modified module
283 cout << "Adjusted module " << mid << " (DU " << du << ", floor " << floor << "): " << adjusted << endl;
284 }
285
286 // Write updated detector to output file
287 detector.comment.add(JMeta(argc, argv));
288
289 try {
290 store(outputDetector, detector);
291 }
292 catch (const JException &e) {
293 FATAL(e);
294 }
295
296 cout << "Applied adjustments to " << changed << " modules and wrote " << outputDetector << endl;
297
298 return 0;
299}
Acoustics toolkit.
Acoustic event.
Acoustic event fit toolkit.
Acoustic event fit.
Acoustic hit.
ROOT TTree parameter settings.
Data structure for detector geometry and calibration.
Acoustic emitter.
Acoustic fit parameters.
Fit function of acoustic model.
General purpose messaging.
#define FATAL(A)
Definition JMessage.hh:67
int debug
debug level
Definition JSirene.cc:74
#define WARNING(A)
Definition JMessage.hh:65
ROOT I/O of application specific meta data.
Direct access to module in detector data structure.
Data structure for optical module.
Scanning of objects from multiple files according a format that follows from the extension of each fi...
Utility class to parse command line options.
#define make_field(A,...)
macro to convert parameter to JParserTemplateElement object
Definition JParser.hh:2140
Scanning of objects from a single file according a format that follows from the extension of each fil...
Sound velocity.
Acoustic transmission identifier.
Detector data structure.
Definition JDetector.hh:96
Router for direct addressing of module data in detector data structure.
bool hasModule(const JModuleIdentifier &id) const
Has module.
Data structure for a composite optical module.
Definition JModule.hh:76
General exception.
Definition JException.hh:25
Auxiliary base class for object identification.
Definition JObjectID.hh:38
int getID() const
Get identifier.
Definition JObjectID.hh:63
Utility class to parse command line options.
Definition JParser.hh:1697
General purpose class for object reading from a list of file names.
Object reading from a list of files.
virtual bool hasNext() override
Check availability of next element.
virtual const pointer_type & next() override
Get next element.
int main()
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.
Definition JManip.hh:448
Detector file.
Definition JHead.hh:227
Auxiliary class for ROOT I/O of application specific meta data.
Definition JMeta.hh:72