21
21
#include "Optics/PolynomialOpticsModel.hh"
31
#include "Interface/Squeal.hh"
33
#include "Utils/Exception.hh"
32
34
#include "Maths/PolynomialMap.hh"
35
#include "src/common_cpp/DataStructure/Primary.hh"
36
#include "src/common_cpp/DataStructure/ThreeVector.hh"
37
#include "src/common_cpp/JsonCppProcessors/PrimaryProcessor.hh"
38
#include "src/common_cpp/Optics/PhaseSpaceVector.hh"
33
39
#include "src/common_cpp/Optics/PolynomialTransferMap.hh"
34
#include "Recon/Global/TrackPoint.hh"
40
#include "Recon/Global/DataStructureHelper.hh"
41
#include "Recon/Global/ParticleOpticalVector.hh"
35
42
#include "Simulation/MAUSGeant4Manager.hh"
36
43
#include "Simulation/MAUSPhysicsList.hh"
40
using recon::global::TrackPoint;
47
using MAUS::PhaseSpaceVector;
48
using recon::global::ParticleOpticalVector;
42
PolynomialOpticsModel::PolynomialOpticsModel(const Json::Value & configuration)
43
: TransferMapOpticsModel(configuration), algorithm_(kNone) {
50
PolynomialOpticsModel::PolynomialOpticsModel(
51
Json::Value const * const configuration)
52
: TransferMapOpticsModel(configuration),
44
54
// Determine which fitting algorithm to use
56
66
void PolynomialOpticsModel::Build() {
57
67
// Create some test hits at the desired First plane
58
const std::vector<TrackPoint> first_plane_hits = BuildFirstPlaneHits();
60
// Iterate through each First plane hit
68
const std::vector<PhaseSpaceVector> primary_vectors = PrimaryVectors();
69
std::cout << "DEBUG PolynomialOpticsModel::Build: "
70
<< "# primaries: " << primary_vectors.size() << std::endl;
71
Json::Value primaries_json;
72
for (std::vector<PhaseSpaceVector>::const_iterator primary_vector
73
= primary_vectors.begin();
74
primary_vector < primary_vectors.end();
76
// generate a Primary object
77
Primary primary(reference_primary_);
78
ThreeVector position(primary_vector->x(), primary_vector->y(),
79
reference_primary_.GetPosition().z());
80
ThreeVector momentum(primary_vector->Px(), primary_vector->Py(),
81
reference_primary_.GetMomentum().z());
82
primary.SetPosition(position);
83
primary.SetMomentum(momentum);
84
primary.SetTime(primary_vector->t());
85
primary.SetEnergy(primary_vector->E());
87
// serialize primary to JSON
88
PrimaryProcessor serializer;
89
Json::Value * primary_json = serializer.CppToJson(primary, "");
90
Json::Value object_value;
91
object_value["primary"] = *primary_json;
92
primaries_json.append(object_value);
61
95
MAUSGeant4Manager * simulator = MAUSGeant4Manager::GetInstance();
97
// Force setting of stochastics
62
98
simulator->GetPhysicsList()->BeginOfRunAction();
64
std::map<int, std::vector<TrackPoint> > station_hits_map;
65
std::vector<TrackPoint>::const_iterator first_plane_hit;
66
for (first_plane_hit = first_plane_hits.begin();
67
first_plane_hit < first_plane_hits.end();
69
// Simulate the current particle (First plane hit) through MICE.
70
simulator->RunParticle(
71
recon::global::PrimaryGeneratorParticle(*first_plane_hit));
73
// Identify the hits by station and add them to the mappings from stations
74
// to the hits they recorded.
75
MapStationsToHits(station_hits_map);
78
// Iterate through each station
79
std::map<int, std::vector<TrackPoint> >::iterator station_hits;
100
// Simulate on the primaries, generating virtual detector tracks for each
101
const Json::Value virtual_tracks
102
= MAUSGeant4Manager::GetInstance()->RunManyParticles(primaries_json);
103
std::cout << "DEBUG PolynomialOpticsModel::Build: "
104
<< "# virtual tracks: " << virtual_tracks.size() << std::endl;
105
if (virtual_tracks.size() == 0) {
106
throw(Exception(Exception::nonRecoverable,
107
"No events were generated during simulation.",
108
"MAUS::TransferMapOpticsModel::Build()"));
111
// Map stations to hits in each virtual track
112
std::map<int64_t, std::vector<PhaseSpaceVector> > station_hits_map;
114
for (Json::Value::const_iterator virtual_track = virtual_tracks.begin();
115
virtual_track != virtual_tracks.end();
117
MapStationsToHits(station_hits_map, *virtual_track);
120
std::cout << "DEBUG PolynomialOpticsModel::Build:" << std::endl
121
<< "\t# virtual tracks mapped: " << count << std::endl
122
<< "\t# station Zs: " << station_hits_map.size() << std::endl;
124
// Calculate transfer maps from the primary plane to each station plane
125
std::map<int64_t, std::vector<PhaseSpaceVector> >::iterator station_hits;
80
126
for (station_hits = station_hits_map.begin();
81
127
station_hits != station_hits_map.end();
83
// find the average z coordinate for the station
84
std::vector<TrackPoint>::iterator station_hit;
86
double station_plane = station_hits->second.begin()->z();
88
// Generate a transfer map between the First plane and the current station
89
// and map the station ID to the transfer map
90
transfer_maps_[station_plane]
91
= CalculateTransferMap(first_plane_hits, station_hits->second);
129
// calculate transfer map and index it by the station z-plane
130
std::cout << "DEBUG PolynomialOpticsModel::Build: "
131
<< "# virtual track hits for z = " << station_hits->first
132
<< ": " << station_hits->second.size() << std::endl;
133
transfer_maps_[station_hits->first]
134
= CalculateTransferMap(primary_vectors, station_hits->second);
140
const std::vector<int64_t> PolynomialOpticsModel::GetAvailableMapPositions()
143
throw(Exception(Exception::nonRecoverable,
144
"No transfer maps available since the optics model has not "
145
"been built yet. Call Build() first.",
146
"MAUS::PolynomialOpticsModel::GetAvailableMapPositions()"));
149
std::vector<int64_t> positions;
150
std::map<int64_t, const TransferMap *>::const_iterator maps;
151
// insertion sort the map keys (z-positions)
152
for (maps = transfer_maps_.begin(); maps != transfer_maps_.end(); ++maps) {
153
positions.push_back(maps->first);
155
std::sort(positions.begin(), positions.end()); // just in case
95
160
void PolynomialOpticsModel::SetupAlgorithm() {
134
199
* necessary in order to solve the least squares problem which involves
135
200
* the calculation of a Moore-Penrose psuedo inverse.
137
const std::vector<TrackPoint> PolynomialOpticsModel::BuildFirstPlaneHits() {
202
const std::vector<PhaseSpaceVector> PolynomialOpticsModel::PrimaryVectors() {
138
203
size_t num_poly_coefficients
139
204
= PolynomialMap::NumberOfPolynomialCoefficients(6, polynomial_order_);
141
std::vector<TrackPoint> first_plane_hits;
205
std::vector<PhaseSpaceVector> primaries;
207
// The (0,0,0,0,0,0) case produces a polynomial vector (1,0,0,...,0)
208
// primaries.push_back(reference_trajectory_);
210
std::cerr << "Primaries:" << std::endl;
142
211
for (size_t i = 0; i < 6; ++i) {
143
212
for (size_t j = i; j < 6; ++j) {
144
TrackPoint first_plane_hit;
213
PhaseSpaceVector primary;
146
215
for (size_t k = 0; k < i; ++k) {
147
first_plane_hit[k] = 1.;
216
primary[k] = deltas_[k]; // non-zero, lower triangular elements
149
double delta = deltas_[j];
150
first_plane_hit[j] = delta;
218
primary[j] = deltas_[j]; // diagonal element
152
first_plane_hits.push_back(TrackPoint(first_plane_hit + reference_particle_,
153
reference_particle_.z(),
154
reference_particle_.particle_id()));
220
// std::cerr << (primary + reference_trajectory_) << std::endl;
221
std::cerr << primary << std::endl;
222
primaries.push_back(primary + reference_trajectory_);
157
size_t base_block_length = first_plane_hits.size();
225
size_t base_block_length = primaries.size();
159
227
// adjust for the case where the base block size is greater than N(n, v)
160
228
while (base_block_length > num_poly_coefficients) {
161
first_plane_hits.pop_back();
162
base_block_length = first_plane_hits.size();
229
primaries.pop_back();
230
base_block_length = primaries.size();
166
233
for (size_t row = base_block_length; row < num_poly_coefficients; ++row) {
167
summand = row / base_block_length;
168
TrackPoint first_plane_hit
169
= TrackPoint(first_plane_hits[row % base_block_length] + summand);
234
PhaseSpaceVector deltas = deltas_ * (row / base_block_length);
235
PhaseSpaceVector primary
236
= primaries[row % base_block_length] - reference_trajectory_ + deltas;
171
first_plane_hits.push_back(TrackPoint(first_plane_hit + reference_particle_,
172
reference_particle_.z(),
173
reference_particle_.particle_id()));
238
// std::cerr << (primary + reference_trajectory_) << std::endl;
239
std::cerr << primary << std::endl;
240
primaries.push_back(primary + reference_trajectory_);
175
return first_plane_hits;
178
245
/* Calculate a transfer matrix from an equal number of inputs and output.
180
247
const TransferMap * PolynomialOpticsModel::CalculateTransferMap(
181
const std::vector<recon::global::TrackPoint> & start_plane_hits,
182
const std::vector<recon::global::TrackPoint> & station_hits)
248
const std::vector<PhaseSpaceVector> & start_plane_hits,
249
const std::vector<PhaseSpaceVector> & station_hits)
252
MAUSGeant4Manager * const simulator = MAUSGeant4Manager::GetInstance();
253
MAUSPrimaryGeneratorAction::PGParticle reference_pgparticle
254
= simulator->GetReferenceParticle();
255
const double t0 = reference_pgparticle.time;
256
const double E0 = reference_pgparticle.energy;
257
const double P0 = reference_pgparticle.pz;
185
260
if (start_plane_hits.size() != station_hits.size()) {
186
throw(Squeal(Squeal::nonRecoverable,
187
"The number of start plane hits is not the same as the number "
188
"of hits per station.",
261
std::stringstream message;
262
message << "The number of start plane hits (" << start_plane_hits.size()
263
<< ") is not the same as the number of hits per station ("
264
<< station_hits.size() << ").";
265
throw(Exception(Exception::nonRecoverable,
189
267
"PolynomialOpticsModel::CalculateTransferMap()"));
192
270
std::vector< std::vector<double> > points;
193
271
for (size_t pt_index = 0; pt_index < start_plane_hits.size(); ++pt_index) {
273
ParticleOpticalVector start_plane_point(start_plane_hits[pt_index],
276
PhaseSpaceVector start_plane_point(
277
start_plane_hits[pt_index] - reference_trajectory_);
194
279
std::vector<double> point;
195
280
for (size_t coord_index = 0; coord_index < 6; ++coord_index) {
196
point.push_back(start_plane_hits[pt_index][coord_index]);
282
point.push_back(start_plane_point[coord_index]);
284
point.push_back(start_plane_hits[pt_index][coord_index]);
198
287
points.push_back(point);
201
290
std::vector< std::vector<double> > values;
202
291
for (size_t val_index = 0; val_index < station_hits.size(); ++val_index) {
293
ParticleOpticalVector station_value(station_hits[val_index], t0, E0, P0);
295
PhaseSpaceVector station_value(
296
station_hits[val_index] - reference_trajectory_);
203
298
std::vector<double> value;
204
299
for (size_t coord_index = 0; coord_index < 6; ++coord_index) {
205
value.push_back(station_hits[val_index][coord_index]);
301
value.push_back(station_value[coord_index]);
303
value.push_back(station_hits[val_index][coord_index]);
207
306
values.push_back(value);
225
326
points, values, polynomial_order_,
226
327
linear_polynomial_map->GetCoefficientsAsVector(), weights_);
229
331
case kConstrainedLeastSquares:
230
332
// constrained least squares
231
333
// ConstrainedLeastSquaresFit(...);
232
throw(Squeal(Squeal::nonRecoverable,
334
throw(Exception(Exception::nonRecoverable,
233
335
"Constrained Polynomial fitting algorithm "
234
336
"is not yet implemented.",
235
337
"PolynomialOpticsModel::CalculateTransferMap()"));
236
338
case kConstrainedChiSquared:
237
339
// constrained chi squared least squares
238
340
// Chi2ConstrainedLeastSquaresFit(...);
239
throw(Squeal(Squeal::nonRecoverable,
341
throw(Exception(Exception::nonRecoverable,
240
342
"Constrained Chi Squared fitting algorithm "
241
343
"is not yet implemented.",
242
344
"PolynomialOpticsModel::CalculateTransferMap()"));
243
345
case kSweepingChiSquared:
244
346
// sweeping chi squared least squares
245
347
// Chi2SweepingLeastSquaresFit(...);
246
throw(Squeal(Squeal::nonRecoverable,
348
throw(Exception(Exception::nonRecoverable,
247
349
"Sweeping Chi Squared fitting algorithm "
248
350
"is not yet implemented.",
249
351
"PolynomialOpticsModel::CalculateTransferMap()"));
250
352
case kSweepingChiSquaredWithVariableWalls:
251
353
// sweeping chi squared with variable walls
252
354
// Chi2SweepingLeastSquaresFitVariableWalls(...);
253
throw(Squeal(Squeal::nonRecoverable,
355
throw(Exception(Exception::nonRecoverable,
254
356
"Sweeping Chi Squared Variable Walls fitting algorithm "
255
357
"is not yet implemented.",
256
358
"PolynomialOpticsModel::CalculateTransferMap()"));
258
throw(Squeal(Squeal::nonRecoverable,
360
throw(Exception(Exception::nonRecoverable,
259
361
"Unrecognized fitting algorithm in configuration.",
260
362
"PolynomialOpticsModel::CalculateTransferMap()"));
263
365
TransferMap * transfer_map = new PolynomialTransferMap(
264
*polynomial_map, reference_particle_);
366
*polynomial_map, reference_trajectory_);
265
367
delete polynomial_map;
267
369
return transfer_map;