Jpp 20.0.0-195-g190c9e876
the software that should make you happy
Loading...
Searching...
No Matches
JAdjustZpos.cc File Reference
#include <string>
#include <iostream>
#include <iomanip>
#include <vector>
#include <set>
#include <map>
#include <algorithm>
#include <cmath>
#include <sstream>
#include <fstream>
#include "TROOT.h"
#include "TFile.h"
#include "JAcoustics/JSoundVelocity.hh"
#include "JAcoustics/JEmitter.hh"
#include "JAcoustics/JAcousticsToolkit.hh"
#include "JAcoustics/JHit.hh"
#include "JAcoustics/JFitParameters.hh"
#include "JAcoustics/JGlobalfit.hh"
#include "JAcoustics/JEvent.hh"
#include "JAcoustics/JEvt.hh"
#include "JAcoustics/JEvtToolkit.hh"
#include "JAcoustics/JSupport.hh"
#include "JAcoustics/JTransmission_t.hh"
#include "JDetector/JDetector.hh"
#include "JDetector/JDetectorToolkit.hh"
#include "JDetector/JModule.hh"
#include "JDetector/JModuleRouter.hh"
#include "JDetector/JIdealString.hh"
#include "JGeometry3D/JVector3D.hh"
#include "JSupport/JMeta.hh"
#include "JSupport/JMultipleFileScanner.hh"
#include "JSupport/JSingleFileScanner.hh"
#include "Jeep/JParser.hh"
#include "Jeep/JMessage.hh"

Go to the source code of this file.

Functions

int main (int argc, char **argv)
 

Function Documentation

◆ main()

int main ( int argc,
char ** argv )

Definition at line 41 of file JAdjustZpos.cc.

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 JObjectID 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}
#define FATAL(A)
Definition JMessage.hh:67
int debug
debug level
Definition JSirene.cc:74
#define WARNING(A)
Definition JMessage.hh:65
#define make_field(A,...)
macro to convert parameter to JParserTemplateElement object
Definition JParser.hh:2142
Detector data structure.
Definition JDetector.hh:96
Router for direct addressing of module data in detector data structure.
Data structure for a composite optical module.
Definition JModule.hh:76
General exception.
Definition JException.hh:24
Auxiliary class for object identification.
Definition JObjectID.hh:25
Utility class to parse command line options.
Definition JParser.hh:1698
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.
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