55#include < DD4hep/FieldTypes.h>
66#include < DD4hep/Printout.h>
77#include < XML/Utilities.h>
8+ #include < covfie/core/algebra/affine.hpp>
9+ #include < covfie/core/backend/primitive/array.hpp>
10+ #include < covfie/core/backend/transformer/affine.hpp>
11+ #include < covfie/core/backend/transformer/linear.hpp>
12+ #include < covfie/core/backend/transformer/strided.hpp>
13+ #include < covfie/core/field.hpp>
14+ #include < covfie/core/field_view.hpp>
15+ #include < covfie/core/parameter_pack.hpp>
816
917#include < cstdlib>
1018#include < filesystem>
@@ -19,6 +27,14 @@ namespace fs = std::filesystem;
1927
2028#include " FileLoaderHelper.h"
2129
30+ using fieldBrBz_t =
31+ covfie::field<covfie::backend::affine<covfie::backend::linear<covfie::backend::strided<
32+ covfie::vector::size2, covfie::backend::array<covfie::vector::float2>>>>>;
33+
34+ using fieldBxByBz_t =
35+ covfie::field<covfie::backend::affine<covfie::backend::linear<covfie::backend::strided<
36+ covfie::vector::size3, covfie::backend::array<covfie::vector::float3>>>>>;
37+
2238using namespace dd4hep ;
2339
2440// Two coordinate options:
@@ -40,11 +56,9 @@ class FieldMapB : public dd4hep::CartesianField::Object {
4056public:
4157 FieldMapB (const std::string& field_type_str = " magnetic" ,
4258 const std::string& coord_type_str = " BrBz" );
43- void Configure (std::vector< xml_comp_t > dimensions);
59+
4460 void LoadMap (const std::string& map_file, float scale);
45- bool GetIndices (float R, float Z, int * idxR, int * idxZ, float * deltaR, float * deltaZ);
46- bool GetIndices (float X, float Y, float Z, int * idxX, int * idxY, int * idxZ, float * deltaX,
47- float * deltaY, float * deltaZ);
61+
4862 void SetCoordTranslation (const Transform3D& tr) {
4963 coordTranslate = tr;
5064 coordTranslate_inv = tr.Inverse ();
@@ -62,12 +76,10 @@ class FieldMapB : public dd4hep::CartesianField::Object {
6276 std::optional<Transform3D> coordTranslate_inv{std::nullopt };
6377 std::optional<Transform3D> fieldRot{std::nullopt }; // field rotation
6478 std::optional<Transform3D> fieldRot_inv{std::nullopt };
65- std::vector<float > steps, mins, maxs; // B map cell info
66- int ir, ix, iy, iz; // lookup indices
67- float dr, dx, dy, dz; // deltas for interpolation
68- std::vector<std::vector<std::array<float , 2 >>> Bvals_RZ; // B map values: {R}, {Z}, {Br,Bz}
69- std::vector<std::vector<std::vector<std::array<float , 3 >>>>
70- Bvals_XYZ; // B map values: {X}, {Y}, {Z}, {Bx,By,Bz}
79+ std::vector<float > steps, mins, maxs; // B map cell info
80+
81+ std::shared_ptr<fieldBrBz_t> fieldBrBz;
82+ std::shared_ptr<fieldBxByBz_t> fieldBxByBz;
7183};
7284
7385// constructor
@@ -94,120 +106,21 @@ FieldMapB::FieldMapB(const std::string& field_type_str, const std::string& coord
94106 }
95107}
96108
97- // fill field vector
98- void FieldMapB::Configure (std::vector<xml_comp_t > dimensions) {
99- // Fill vectors with step size, min, max for each dimension
100- for (auto el : dimensions) {
101- steps.push_back (el.step ());
102- mins.push_back (getAttrOrDefault<float >(el, _Unicode (min), 0 ));
103- maxs.push_back (getAttrOrDefault<float >(el, _Unicode (max), 0 ));
104- }
105-
106- if (fieldCoord == FieldCoord::BrBz) {
107- // N bins increased by 1 beyond grid size to account for edge cases at upper limits
108- int nr = std::roundf ((maxs[0 ] - mins[0 ]) / steps[0 ]) + 2 ;
109- int nz = std::roundf ((maxs[1 ] - mins[1 ]) / steps[1 ]) + 2 ;
110-
111- Bvals_RZ.resize (nr);
112- for (auto & B2 : Bvals_RZ) {
113- B2.resize (nz);
114- }
115- } else {
116- // N bins increased by 1 beyond grid size to account for edge cases at upper limits
117- int nx = std::roundf ((maxs[0 ] - mins[0 ]) / steps[0 ]) + 2 ;
118- int ny = std::roundf ((maxs[1 ] - mins[1 ]) / steps[1 ]) + 2 ;
119- int nz = std::roundf ((maxs[2 ] - mins[2 ]) / steps[2 ]) + 2 ;
120-
121- Bvals_XYZ.resize (nx);
122- for (auto & B3 : Bvals_XYZ) {
123- B3.resize (ny);
124- for (auto & B2 : B3) {
125- B2.resize (nz);
126- }
127- }
128- }
129- }
130-
131- // get RZ cell indices corresponding to point of interest
132- bool FieldMapB::GetIndices (float R, float Z, int * idxR, int * idxZ, float * deltaR, float * deltaZ) {
133- // boundary check
134- if (R > maxs[0 ] || R < mins[0 ] || Z > maxs[1 ] || Z < mins[1 ]) {
135- return false ;
136- }
137-
138- // get indices
139- float idx_1_f, idx_2_f;
140- *deltaR = std::modf ((R - mins[0 ]) / steps[0 ], &idx_1_f);
141- *deltaZ = std::modf ((Z - mins[1 ]) / steps[1 ], &idx_2_f);
142- *idxR = static_cast <int >(idx_1_f);
143- *idxZ = static_cast <int >(idx_2_f);
144-
145- return true ;
146- }
147-
148- // get XYZ cell indices corresponding to point of interest
149- bool FieldMapB::GetIndices (float X, float Y, float Z, int * idxX, int * idxY, int * idxZ,
150- float * deltaX, float * deltaY, float * deltaZ) {
151- // boundary check
152- if (X > maxs[0 ] || X < mins[0 ] || Y > maxs[1 ] || Y < mins[1 ] || Z > maxs[2 ] || Z < mins[2 ]) {
153- return false ;
154- }
155-
156- // get indices
157- float idx_1_f, idx_2_f, idx_3_f;
158- *deltaX = std::modf ((X - mins[0 ]) / steps[0 ], &idx_1_f);
159- *deltaY = std::modf ((Y - mins[1 ]) / steps[1 ], &idx_2_f);
160- *deltaZ = std::modf ((Z - mins[2 ]) / steps[2 ], &idx_3_f);
161- *idxX = static_cast <int >(idx_1_f);
162- *idxY = static_cast <int >(idx_2_f);
163- *idxZ = static_cast <int >(idx_3_f);
164-
165- return true ;
166- }
167-
168109// load data
169- void FieldMapB::LoadMap (const std::string& map_file, float scale ) {
110+ void FieldMapB::LoadMap (const std::string& map_file, float ) {
170111 std::string line;
171112 std::ifstream input (map_file);
172113 if (!input) {
173114 printout (ERROR, " FieldMapB" , " FieldMapB Error: file " + map_file + " cannot be read." );
174115 }
175116
176- std::vector<float > coord = {};
177- std::vector<float > Bcomp = {};
178-
179- while (std::getline (input, line).good ()) {
180- std::istringstream iss (line);
181-
182- coord.clear ();
183- Bcomp.clear ();
184-
185- if (fieldCoord == FieldCoord::BrBz) {
186- coord.resize (2 );
187- Bcomp.resize (2 );
188- iss >> coord[0 ] >> coord[1 ] >> Bcomp[0 ] >> Bcomp[1 ];
189-
190- if (!GetIndices (coord[0 ], coord[1 ], &ir, &iz, &dr, &dz)) {
191- printout (WARNING, " FieldMapB" , " coordinates out of range, skipped it." );
192- } else { // scale field
193- Bvals_RZ[ir][iz] = {Bcomp[0 ] * scale * float (tesla), Bcomp[1 ] * scale * float (tesla)};
194- }
195- } else {
196- coord.resize (3 );
197- Bcomp.resize (3 );
198- iss >> coord[0 ] >> coord[1 ] >> coord[2 ] >> Bcomp[0 ] >> Bcomp[1 ] >> Bcomp[2 ];
199-
200- if (!GetIndices (coord[0 ], coord[1 ], coord[2 ], &ix, &iy, &iz, &dx, &dy, &dz)) {
201- printout (WARNING, " FieldMap" , " coordinates out of range, skipped it." );
202- } else { // scale and rotate B field vector
203- auto B = ROOT::Math::XYZPoint (Bcomp[0 ], Bcomp[1 ], Bcomp[2 ]);
204- B *= scale * float (tesla);
205- if (fieldRot.has_value ()) {
206- B = fieldRot.value () * B;
207- }
208- Bvals_XYZ[ix][iy][iz] = {float (B.x ()), float (B.y ()), float (B.z ())};
209- }
210- }
117+ switch (fieldCoord) {
118+ case FieldCoord::BrBz:
119+ fieldBrBz = std::make_shared<fieldBrBz_t>(input);
120+ break ;
121+ case FieldCoord::BxByBz:
122+ fieldBxByBz = std::make_shared<fieldBxByBz_t>(input);
123+ break ;
211124 }
212125}
213126
@@ -223,65 +136,31 @@ void FieldMapB::fieldComponents(const double* pos, double* field) {
223136 const float r = sqrt (p.x () * p.x () + p.y () * p.y ());
224137 const float z = p.z ();
225138
226- if (!GetIndices (r, z, &ir, &iz, &dr, &dz)) {
227- // out of range
228- return ;
229- }
230-
231- // p1 p3
232- // p
233- // p0 p2
234- auto & p0 = Bvals_RZ[ir][iz];
235- auto & p1 = Bvals_RZ[ir][iz + 1 ];
236- auto & p2 = Bvals_RZ[ir + 1 ][iz];
237- auto & p3 = Bvals_RZ[ir + 1 ][iz + 1 ];
238-
239- // Bilinear interpolation
240- float Br = p0[0 ] * (1 - dr) * (1 - dz) + p1[0 ] * (1 - dr) * dz + p2[0 ] * dr * (1 - dz) +
241- p3[0 ] * dr * dz;
242-
243- float Bz = p0[1 ] * (1 - dr) * (1 - dz) + p1[1 ] * (1 - dr) * dz + p2[1 ] * dr * (1 - dz) +
244- p3[1 ] * dr * dz;
139+ fieldBrBz_t::view_t view (*fieldBrBz);
140+ fieldBrBz_t::output_t b = view.at (r, z);
141+ float Br = b[0 ];
142+ float Bz = b[1 ];
245143
246144 // convert Br Bz to Bx By Bz and rotate field
247145 const float phi = atan2 (p.y (), p.x ());
248146 auto B = fieldRot.has_value ()
249147 ? fieldRot.value () * ROOT::Math::XYZPoint (Br * cos (phi), Br * sin (phi), Bz)
250148 : ROOT::Math::XYZPoint (Br * cos (phi), Br * sin (phi), Bz);
149+
251150 field[0 ] += B.x ();
252151 field[1 ] += B.y ();
253152 field[2 ] += B.z ();
153+
254154 } else { // BxByBz
255155
256- if (!GetIndices (p.x (), p.y (), p.z (), &ix, &iy, &iz, &dx, &dy, &dz)) {
257- return ; // out of range
258- }
259-
260- float b[3 ] = {0 };
261- for (int comp = 0 ; comp < 3 ; comp++) { // field component loop
262- // Trilinear interpolation
263- // First along X, along 4 lines
264- float b00 = Bvals_XYZ[ix][iy][iz][comp] * (1 - dx) + Bvals_XYZ[ix + 1 ][iy][iz][comp] * dx;
265- float b01 =
266- Bvals_XYZ[ix][iy][iz + 1 ][comp] * (1 - dx) + Bvals_XYZ[ix + 1 ][iy][iz + 1 ][comp] * dx;
267- float b10 =
268- Bvals_XYZ[ix][iy + 1 ][iz][comp] * (1 - dx) + Bvals_XYZ[ix + 1 ][iy + 1 ][iz][comp] * dx;
269- float b11 = Bvals_XYZ[ix][iy + 1 ][iz + 1 ][comp] * (1 - dx) +
270- Bvals_XYZ[ix + 1 ][iy + 1 ][iz + 1 ][comp] * dx;
271- // Next along Y, along 2 lines
272- float b0 = b00 * (1 - dy) + b10 * dy;
273- float b1 = b01 * (1 - dy) + b11 * dy;
274- // Finally along Z
275- b[comp] = b0 * (1 - dz) + b1 * dz;
276- }
156+ fieldBxByBz_t::view_t view (*fieldBxByBz);
157+ fieldBxByBz_t::output_t b = view.at (p.x (), p.y (), p.z ());
277158
278159 // field rotation done in LoadMap()
279160 field[0 ] += b[0 ];
280161 field[1 ] += b[1 ];
281162 field[2 ] += b[2 ];
282163 }
283-
284- return ;
285164}
286165
287166// assign the field map to CartesianField
@@ -331,7 +210,6 @@ static Ref_t create_field_map_b(Detector& /*lcdd*/, xml::Handle_t handle) {
331210 }
332211
333212 auto map = new FieldMapB (field_type, coord_type);
334- map->Configure (dimensions);
335213
336214 // translation
337215 if (x_dim.hasChild (_Unicode (rotationField))) {
0 commit comments