41int main(
int argc,
char** argv)
47 string outputDetector;
49 int min_working_signals;
53 JParser<> zap(
"Adjust z-positions of DOMs without acoustic data and write modified detector");
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;
63 catch (
const exception &e) {
64 FATAL(e.what() << endl);
67 if (inputDetector.empty() || outputDetector.empty() || inputFile.empty()) {
68 FATAL(
"Missing required arguments: -a <input detector> -o <output detector> -f <event files files...>" << endl);
84 for (JDetector::const_iterator m =
detector.begin(); m !=
detector.end(); ++m) {
85 acoustic_counts[m->getID()] = 0;
89 for (
const string& file_name : inputFile) {
95 if (evt->empty())
continue;
98 for (JEvent::const_iterator hit_it = evt->begin(); hit_it != evt->end(); ++hit_it) {
101 acoustic_counts[recv_id.
getID()]++;
106 catch (
const exception &e) {
107 FATAL(
"Error reading event file " << file_name <<
": " << e.what() << endl);
113 for (JDetector::const_iterator m =
detector.begin(); m !=
detector.end(); ++m) {
114 has_working[m->getID()] = (acoustic_counts[m->getID()] >= min_working_signals);
119 for (JDetector::const_iterator m =
detector.begin(); m !=
detector.end(); ++m) {
120 by_du[m->getString()].push_back(&(*m));
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;
133 cout <<
" DU " << du <<
": " << working_count <<
" working modules out of " << vec.size() << endl;
138 bool is_arca =
false;
139 bool is_orca =
false;
141 for (
const auto &entry : by_du) {
142 int du = entry.first;
143 const auto &vec = entry.second;
146 auto it = find_if(vec.begin(), vec.end(),
147 [](
const JModule* m){ return m->getFloor() == 18; });
149 if (it == vec.end()) {
150 WARNING(
"DU " << du <<
" has no floor 18 module" << endl);
154 double height = (*it)->getPosition().getZ();
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);
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;
194 for (
const auto &entry : by_du) {
195 int du = entry.first;
196 const auto &vec = entry.second;
201 if (has_working[m->getID()] && m->getFloor() > 0)
202 working_valid.push_back(m);
205 if (working_valid.size() < 2)
continue;
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;
215 double sum_x = 0.0, sum_y = 0.0;
216 for (
const JModule* m : working_valid) {
218 auto it = ideal_string.find(m->getFloor());
219 if (it != ideal_string.end()) frac = it->second;
221 sum_y += m->getPosition().getZ();
225 double mean_x = sum_x / working_valid.size();
226 double mean_y = sum_y / working_valid.size();
228 double ss_xx = 0.0, ss_xy = 0.0;
229 for (
const JModule* m : working_valid) {
231 auto it = ideal_string.find(m->getFloor());
232 if (it != ideal_string.end()) frac = it->second;
235 double diff_x = frac - mean_x;
236 ss_xx += diff_x * diff_x;
237 ss_xy += diff_x * (m->getPosition().getZ() - mean_y);
241 if (std::abs(ss_xx) < 1e-12)
continue;
243 double L = ss_xy / ss_xx;
244 double Z0 = mean_y - L * mean_x;
247 offset_fits[du] = Z0;
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;
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();
265 if (has_working[mid] || floor == 0)
continue;
267 if (length_fits.count(du) == 0 || offset_fits.count(du) == 0)
continue;
270 auto it = ideal_string.find(floor);
271 if (it != ideal_string.end()) frac = it->second;
273 double adjusted = frac * length_fits[du] + offset_fits[du];
276 double x =
module->getX();
277 double y =
module->getY();
279 module->set(JVector3D(x, y, adjusted));
283 cout <<
"Adjusted module " << mid <<
" (DU " << du <<
", floor " << floor <<
"): " << adjusted << endl;
296 cout <<
"Applied adjustments to " << changed <<
" modules and wrote " << outputDetector << endl;