ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
JsonGeometryConverter.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file JsonGeometryConverter.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2017-2019 CERN for the benefit of the Acts project
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 
10 
11 #include <boost/algorithm/string.hpp>
12 #include <boost/algorithm/string/finder.hpp>
13 #include <boost/algorithm/string/iter_find.hpp>
14 #include <cstdio>
15 #include <fstream>
16 #include <iostream>
17 #include <map>
18 #include <sstream>
19 #include <stdexcept>
20 #include <string>
21 
41 
43 
46  : m_cfg(std::move(cfg)) {
47  // Validate the configuration
48  if (!m_cfg.logger) {
49  throw std::invalid_argument("Missing logger");
50  }
51 }
52 
53 std::pair<
54  std::map<Acts::GeometryID, std::shared_ptr<const Acts::ISurfaceMaterial>>,
55  std::map<Acts::GeometryID, std::shared_ptr<const Acts::IVolumeMaterial>>>
57  auto& j = materialmaps;
58  // The return maps
59  std::pair<SurfaceMaterialMap, VolumeMaterialMap> maps;
60  ACTS_VERBOSE("j2a: Reading material maps from json file.");
61  ACTS_VERBOSE("j2a: Found entries for " << j.count(m_cfg.volkey)
62  << " volume(s).");
63  // Structured binding
64  for (auto& [key, value] : j.items()) {
65  // Check if this the volume key
66  if (key == m_cfg.volkey) {
67  // Get the volume json
68  auto volj = value;
69  for (auto& [vkey, vvalue] : volj.items()) {
70  // Create the volume id
71  int vid = std::stoi(vkey);
72  Acts::GeometryID volumeID;
73  volumeID.setVolume(vid);
74  ACTS_VERBOSE("j2a: -> Found Volume " << vid);
75  // Loop through the information in the volume
76  for (auto& [vckey, vcvalue] : vvalue.items()) {
77  if (vckey == m_cfg.boukey and m_cfg.processBoundaries and
78  not vcvalue.empty()) {
79  ACTS_VERBOSE("j2a: --> BoundarySurface(s) to be parsed");
80  for (auto& [bkey, bvalue] : vcvalue.items()) {
81  // Create the boundary id
82  int bid = std::stoi(bkey);
83  Acts::GeometryID boundaryID(volumeID);
84  boundaryID.setBoundary(bid);
85  ACTS_VERBOSE("j2a: ---> Found boundary surface " << bid);
86  auto boumat = jsonToSurfaceMaterial(bvalue);
87  if (bvalue[m_cfg.mapkey] == true)
88  maps.first[boundaryID] =
89  std::shared_ptr<const ISurfaceMaterial>(boumat);
90  }
91  } else if (vckey == m_cfg.laykey) {
92  ACTS_VERBOSE("j2a: --> Layer(s) to be parsed");
93  // Loop over layers and repeat
94  auto layj = vcvalue;
95  for (auto& [lkey, lvalue] : layj.items()) {
96  // Create the layer id
97  int lid = std::stoi(lkey);
98  Acts::GeometryID layerID(volumeID);
99  layerID.setLayer(lid);
100  ACTS_VERBOSE("j2a: ---> Found Layer " << lid);
101  // Finally loop over layer components
102  for (auto& [lckey, lcvalue] : lvalue.items()) {
103  if (lckey == m_cfg.repkey and m_cfg.processRepresenting and
104  not lcvalue.empty()) {
105  ACTS_VERBOSE("j2a: ----> Found representing surface");
106  auto repmat = jsonToSurfaceMaterial(lcvalue);
107  if (lcvalue[m_cfg.mapkey] == true)
108  maps.first[layerID] =
109  std::shared_ptr<const Acts::ISurfaceMaterial>(repmat);
110  } else if (lckey == m_cfg.appkey and m_cfg.processApproaches and
111  not lcvalue.empty()) {
112  ACTS_VERBOSE("j2a: ----> Found approach surface(s)");
113  // Loop over approach surfaces
114  for (auto& [askey, asvalue] : lcvalue.items()) {
115  // Create the layer id, todo set to max value
116  int aid = (askey == "*") ? 0 : std::stoi(askey);
117  Acts::GeometryID approachID(layerID);
118  approachID.setApproach(aid);
119  ACTS_VERBOSE("j2a: -----> Approach surface " << askey);
120  auto appmat = jsonToSurfaceMaterial(asvalue);
121  if (asvalue[m_cfg.mapkey] == true)
122  maps.first[approachID] =
123  std::shared_ptr<const Acts::ISurfaceMaterial>(appmat);
124  }
125  } else if (lckey == m_cfg.senkey and m_cfg.processSensitives and
126  not lcvalue.empty()) {
127  ACTS_VERBOSE("j2a: ----> Found sensitive surface(s)");
128  // Loop over sensitive surfaces
129  for (auto& [sskey, ssvalue] : lcvalue.items()) {
130  // Create the layer id, todo set to max value
131  int sid = (sskey == "*") ? 0 : std::stoi(sskey);
132  Acts::GeometryID senisitiveID(layerID);
133  senisitiveID.setSensitive(sid);
134  ACTS_VERBOSE("j2a: -----> Sensitive surface " << sskey);
135  auto senmat = jsonToSurfaceMaterial(ssvalue);
136  if (ssvalue[m_cfg.mapkey] == true)
137  maps.first[senisitiveID] =
138  std::shared_ptr<const Acts::ISurfaceMaterial>(senmat);
139  }
140  }
141  }
142  }
143 
144  } else if (vckey == m_cfg.matkey and not vcvalue.empty()) {
145  ACTS_VERBOSE("--> VolumeMaterial to be parsed");
146  auto intermat = jsonToVolumeMaterial(vcvalue);
147  if (vcvalue[m_cfg.mapkey] == true) {
148  maps.second[volumeID] =
149  std::shared_ptr<const Acts::IVolumeMaterial>(intermat);
150  }
151  }
152  }
153  }
154  } else if (key == m_cfg.geoversion) {
155  ACTS_VERBOSE("Detector version: " << m_cfg.geoversion);
156  }
157  }
158 
159  // Return the filled maps
160  return maps;
161 }
162 
166  const DetectorMaterialMaps& maps) {
167  DetectorRep detRep;
168  // Collect all GeometryIDs per VolumeID for the formatted output
169  for (auto& [key, value] : maps.first) {
170  geo_id_value vid = key.volume();
171  auto volRep = detRep.volumes.find(vid);
172  if (volRep == detRep.volumes.end()) {
173  detRep.volumes.insert({vid, VolumeRep()});
174  volRep = detRep.volumes.find(vid);
175  volRep->second.volumeID = key;
176  }
177  geo_id_value lid = key.layer();
178  if (lid != 0) {
179  // we are on a layer, get the layer rep
180  auto layRep = volRep->second.layers.find(lid);
181  if (layRep == volRep->second.layers.end()) {
182  volRep->second.layers.insert({lid, LayerRep()});
183  layRep = volRep->second.layers.find(lid);
184  layRep->second.layerID = key;
185  }
186  // now insert appropriately
187  geo_id_value sid = key.sensitive();
188  geo_id_value aid = key.approach();
189  if (sid != 0) {
190  layRep->second.sensitives.insert({sid, value.get()});
191  } else if (aid != 0) {
192  layRep->second.approaches.insert({aid, value.get()});
193  } else {
194  layRep->second.representing = value.get();
195  }
196 
197  } else {
198  // not on a layer can only be a boundary surface
199  geo_id_value bid = key.boundary();
200  volRep->second.boundaries.insert({bid, value.get()});
201  }
202  }
203  for (auto& [key, value] : maps.second) {
204  // find the volume representation
205  geo_id_value vid = key.volume();
206  auto volRep = detRep.volumes.find(vid);
207  if (volRep == detRep.volumes.end()) {
208  detRep.volumes.insert({vid, VolumeRep()});
209  volRep = detRep.volumes.find(vid);
210  volRep->second.volumeID = key;
211  }
212  volRep->second.material = value.get();
213  }
214  // convert the detector representation to json format
215  return detectorRepToJson(detRep);
216 }
217 
220  json detectorj;
221  ACTS_VERBOSE("a2j: Writing json from detector representation");
222  ACTS_VERBOSE("a2j: Found entries for " << detRep.volumes.size()
223  << " volume(s).");
224 
225  json volumesj;
226  for (auto& [key, value] : detRep.volumes) {
227  json volj;
228  ACTS_VERBOSE("a2j: -> Writing Volume: " << key);
229  volj[m_cfg.namekey] = value.volumeName;
230  std::ostringstream svolumeID;
231  svolumeID << value.volumeID;
232  volj[m_cfg.geoidkey] = svolumeID.str();
233  if (value.material) {
234  volj[m_cfg.matkey] = volumeMaterialToJson(*value.material);
235  }
236  // Write the layers
237  if (not value.layers.empty()) {
238  ACTS_VERBOSE("a2j: ---> Found " << value.layers.size() << " layer(s) ");
239  json layersj;
240  for (auto& [lkey, lvalue] : value.layers) {
241  ACTS_VERBOSE("a2j: ----> Convert layer " << lkey);
242  json layj;
243  std::ostringstream slayerID;
244  slayerID << lvalue.layerID;
245  layj[m_cfg.geoidkey] = slayerID.str();
246  // First check for approaches
247  if (not lvalue.approaches.empty() and m_cfg.processApproaches) {
248  ACTS_VERBOSE("a2j: -----> Found " << lvalue.approaches.size()
249  << " approach surface(s)");
250  json approachesj;
251  for (auto& [akey, avalue] : lvalue.approaches) {
252  ACTS_VERBOSE("a2j: ------> Convert approach surface " << akey);
253  approachesj[std::to_string(akey)] = surfaceMaterialToJson(*avalue);
254  if (lvalue.approacheSurfaces.find(akey) !=
255  lvalue.approacheSurfaces.end())
256  addSurfaceToJson(approachesj[std::to_string(akey)],
257  lvalue.approacheSurfaces.at(akey));
258  }
259  // Add to the layer json
260  layj[m_cfg.appkey] = approachesj;
261  }
262  // Then check for sensitive
263  if (not lvalue.sensitives.empty() and m_cfg.processSensitives) {
264  ACTS_VERBOSE("a2j: -----> Found " << lvalue.sensitives.size()
265  << " sensitive surface(s)");
266  json sensitivesj;
267  for (auto& [skey, svalue] : lvalue.sensitives) {
268  ACTS_VERBOSE("a2j: ------> Convert sensitive surface " << skey);
269  sensitivesj[std::to_string(skey)] = surfaceMaterialToJson(*svalue);
270  if (lvalue.sensitiveSurfaces.find(skey) !=
271  lvalue.sensitiveSurfaces.end())
272  addSurfaceToJson(sensitivesj[std::to_string(skey)],
273  lvalue.sensitiveSurfaces.at(skey));
274  }
275  // Add to the layer json
276  layj[m_cfg.senkey] = sensitivesj;
277  }
278  // Finally check for representing
279  if (lvalue.representing != nullptr and m_cfg.processRepresenting) {
280  ACTS_VERBOSE("a2j: ------> Convert representing surface ");
281  layj[m_cfg.repkey] = surfaceMaterialToJson(*lvalue.representing);
282  if (lvalue.representingSurface != nullptr)
283  addSurfaceToJson(layj[m_cfg.repkey], lvalue.representingSurface);
284  }
285  layersj[std::to_string(lkey)] = layj;
286  }
287  volj[m_cfg.laykey] = layersj;
288  }
289  // Write the boundary surfaces
290  if (not value.boundaries.empty()) {
291  ACTS_VERBOSE("a2j: ---> Found " << value.boundaries.size()
292  << " boundary/ies ");
293  json boundariesj;
294  for (auto& [bkey, bvalue] : value.boundaries) {
295  ACTS_VERBOSE("a2j: ----> Convert boundary " << bkey);
296  boundariesj[std::to_string(bkey)] = surfaceMaterialToJson(*bvalue);
297  if (value.boundarySurfaces.find(bkey) != value.boundarySurfaces.end())
298  addSurfaceToJson(boundariesj[std::to_string(bkey)],
299  value.boundarySurfaces.at(bkey));
300  }
301  volj[m_cfg.boukey] = boundariesj;
302  }
303 
304  volumesj[std::to_string(key)] = volj;
305  }
306  // Assign the volume json to the detector json
307  detectorj[m_cfg.volkey] = volumesj;
308 
309  return detectorj;
310 }
311 
315  Acts::ISurfaceMaterial* sMaterial = nullptr;
316  // The bin utility for deescribing the data
317  Acts::BinUtility bUtility;
318  // Convert the material
320  // Structured binding
321  for (auto& [key, value] : material.items()) {
322  // Check json keys
323  if (key == m_cfg.bin0key and not value.empty()) {
324  bUtility += jsonToBinUtility(value);
325  } else if (key == m_cfg.bin1key and not value.empty()) {
326  bUtility += jsonToBinUtility(value);
327  }
328  if (key == m_cfg.datakey and not value.empty()) {
329  mpMatrix = jsonToMaterialMatrix(value);
330  }
331  }
332 
333  // We have protoMaterial
334  if (mpMatrix.empty()) {
335  sMaterial = new Acts::ProtoSurfaceMaterial(bUtility);
336  } else if (bUtility.bins() == 1) {
337  sMaterial = new Acts::HomogeneousSurfaceMaterial(mpMatrix[0][0]);
338  } else {
339  sMaterial = new Acts::BinnedSurfaceMaterial(bUtility, mpMatrix);
340  }
341  // return what you have
342  return sMaterial;
343 }
344 
347  const json& material) {
348  Acts::IVolumeMaterial* vMaterial = nullptr;
349  // The bin utility for deescribing the data
350  Acts::BinUtility bUtility;
351  // Convert the material
352  std::vector<std::vector<float>> mmat;
353  // Structured binding
354  for (auto& [key, value] : material.items()) {
355  // Check json keys
356  if (key == m_cfg.bin0key and not value.empty()) {
357  bUtility += jsonToBinUtility(value);
358  } else if (key == m_cfg.bin1key and not value.empty()) {
359  bUtility += jsonToBinUtility(value);
360  } else if (key == m_cfg.bin2key and not value.empty()) {
361  bUtility += jsonToBinUtility(value);
362  }
363  if (key == m_cfg.datakey and not value.empty()) {
364  for (auto& bin : value) {
365  std::vector<float> mpVector{bin[0], bin[1], bin[2], bin[3], bin[4]};
366  mmat.push_back(mpVector);
367  }
368  }
369  }
370 
371  // We have protoMaterial
372  if (mmat.empty()) {
373  vMaterial = new Acts::ProtoVolumeMaterial(bUtility);
374  } else if (mmat.size() == 1) {
376  mmat[0][0], mmat[0][1], mmat[0][2], mmat[0][3], mmat[0][4]));
377  } else {
378  if (bUtility.dimensions() == 2) {
379  std::function<Acts::Vector2D(Acts::Vector3D)> transfoGlobalToLocal;
380  Acts::Grid2D grid = createGrid2D(bUtility, transfoGlobalToLocal);
381 
384  Acts::Grid2D::index_t nBins = grid.numLocalBins();
385 
386  Acts::EAxis axis1(min[0], max[0], nBins[0]);
387  Acts::EAxis axis2(min[1], max[1], nBins[1]);
388 
389  // Build the grid and fill it with data
390  MaterialGrid2D mGrid(std::make_tuple(axis1, axis2));
391 
392  for (size_t bin = 0; bin < mmat.size(); bin++) {
393  mGrid.at(bin) = Acts::Material(mmat[bin][0], mmat[bin][1], mmat[bin][2],
394  mmat[bin][3], mmat[bin][4])
396  }
397  MaterialMapper<MaterialGrid2D> matMap(transfoGlobalToLocal, mGrid);
398  vMaterial =
400  std::move(matMap), bUtility);
401  } else if (bUtility.dimensions() == 3) {
402  std::function<Acts::Vector3D(Acts::Vector3D)> transfoGlobalToLocal;
403  Acts::Grid3D grid = createGrid3D(bUtility, transfoGlobalToLocal);
404 
407  Acts::Grid3D::index_t nBins = grid.numLocalBins();
408 
409  Acts::EAxis axis1(min[0], max[0], nBins[0]);
410  Acts::EAxis axis2(min[1], max[1], nBins[1]);
411  Acts::EAxis axis3(min[2], max[2], nBins[2]);
412 
413  // Build the grid and fill it with data
414  MaterialGrid3D mGrid(std::make_tuple(axis1, axis2, axis3));
415 
416  for (size_t bin = 0; bin < mmat.size(); bin++) {
417  mGrid.at(bin) = Acts::Material(mmat[bin][0], mmat[bin][1], mmat[bin][2],
418  mmat[bin][3], mmat[bin][4])
420  }
421  MaterialMapper<MaterialGrid3D> matMap(transfoGlobalToLocal, mGrid);
422  vMaterial =
424  std::move(matMap), bUtility);
425  }
426  }
427  // return what you have
428  return vMaterial;
429 }
430 
433  DetectorRep detRep;
434  convertToRep(detRep, *tGeometry.highestTrackingVolume());
435  return detectorRepToJson(detRep);
436 }
437 
439  DetectorRep& detRep, const Acts::TrackingVolume& tVolume) {
440  // The writer reader volume representation
441  VolumeRep volRep;
442  volRep.volumeName = tVolume.volumeName();
443  // there are confined volumes
444  if (tVolume.confinedVolumes() != nullptr) {
445  // get through the volumes
446  auto& volumes = tVolume.confinedVolumes()->arrayObjects();
447  // loop over the volumes
448  for (auto& vol : volumes) {
449  // recursive call
450  convertToRep(detRep, *vol);
451  }
452  }
453  // there are dense volumes
454  if (!tVolume.denseVolumes().empty()) {
455  // loop over the volumes
456  for (auto& vol : tVolume.denseVolumes()) {
457  // recursive call
458  convertToRep(detRep, *vol);
459  }
460  }
461  // Get the volume Id
462  Acts::GeometryID volumeID = tVolume.geoID();
463  geo_id_value vid = volumeID.volume();
464 
465  // Write the material if there's one
466  if (tVolume.volumeMaterial() != nullptr) {
467  volRep.material = tVolume.volumeMaterial();
468  } else if (m_cfg.processnonmaterial == true) {
469  Acts::BinUtility bUtility = DefaultBin(tVolume);
470  Acts::IVolumeMaterial* bMaterial = new Acts::ProtoVolumeMaterial(bUtility);
471  volRep.material = bMaterial;
472  }
473  // there are confied layers
474  if (tVolume.confinedLayers() != nullptr) {
475  // get the layers
476  auto& layers = tVolume.confinedLayers()->arrayObjects();
477  // loop of the volumes
478  for (auto& lay : layers) {
479  auto layRep = convertToRep(*lay);
480  if (layRep) {
481  // it's a valid representation so let's go with it
482  Acts::GeometryID layerID = lay->geoID();
483  geo_id_value lid = layerID.layer();
484  volRep.layers.insert({lid, std::move(layRep)});
485  }
486  }
487  }
488  // Let's finally check the boundaries
489  for (auto& bsurf : tVolume.boundarySurfaces()) {
490  // the surface representation
491  auto& bssfRep = bsurf->surfaceRepresentation();
492  if (bssfRep.surfaceMaterial() != nullptr) {
493  Acts::GeometryID boundaryID = bssfRep.geoID();
494  geo_id_value bid = boundaryID.boundary();
495  // Ignore if the volumeID is not correct (i.e. shared boundary)
496  // if (boundaryID.value(Acts::GeometryID::volume_mask) == vid){
497  volRep.boundaries[bid] = bssfRep.surfaceMaterial();
498  volRep.boundarySurfaces[bid] = &bssfRep;
499  // }
500  } else if (m_cfg.processnonmaterial == true) {
501  // if no material suface exist add a default one for the mapping
502  // configuration
503  Acts::GeometryID boundaryID = bssfRep.geoID();
504  geo_id_value bid = boundaryID.boundary();
505  Acts::BinUtility bUtility = DefaultBin(bssfRep);
506  Acts::ISurfaceMaterial* bMaterial =
507  new Acts::ProtoSurfaceMaterial(bUtility);
508  volRep.boundaries[bid] = bMaterial;
509  volRep.boundarySurfaces[bid] = &bssfRep;
510  }
511  }
512  // Write if it's good
513  if (volRep) {
514  volRep.volumeName = tVolume.volumeName();
515  volRep.volumeID = volumeID;
516  detRep.volumes.insert({vid, std::move(volRep)});
517  }
518  return;
519 }
520 
522  const Acts::Layer& tLayer) {
523  LayerRep layRep;
524  // fill layer ID information
525  layRep.layerID = tLayer.geoID();
526  if (m_cfg.processSensitives and tLayer.surfaceArray() != nullptr) {
527  for (auto& ssf : tLayer.surfaceArray()->surfaces()) {
528  if (ssf != nullptr && ssf->surfaceMaterial() != nullptr) {
529  Acts::GeometryID sensitiveID = ssf->geoID();
530  geo_id_value sid = sensitiveID.sensitive();
531  layRep.sensitives.insert({sid, ssf->surfaceMaterial()});
532  layRep.sensitiveSurfaces.insert({sid, ssf});
533  } else if (m_cfg.processnonmaterial == true) {
534  // if no material suface exist add a default one for the mapping
535  // configuration
536  Acts::GeometryID sensitiveID = ssf->geoID();
537  geo_id_value sid = sensitiveID.sensitive();
538  Acts::BinUtility sUtility = DefaultBin(*ssf);
539  Acts::ISurfaceMaterial* sMaterial =
540  new Acts::ProtoSurfaceMaterial(sUtility);
541  layRep.sensitives.insert({sid, sMaterial});
542  layRep.sensitiveSurfaces.insert({sid, ssf});
543  }
544  }
545  }
546  // the representing
547  if (!(tLayer.surfaceRepresentation().geoID() == GeometryID())) {
548  if (tLayer.surfaceRepresentation().surfaceMaterial() != nullptr) {
550  layRep.representingSurface = &tLayer.surfaceRepresentation();
551  } else if (m_cfg.processnonmaterial == true) {
552  // if no material suface exist add a default one for the mapping
553  // configuration
554  Acts::BinUtility rUtility = DefaultBin(tLayer.surfaceRepresentation());
555  Acts::ISurfaceMaterial* rMaterial =
556  new Acts::ProtoSurfaceMaterial(rUtility);
557  layRep.representing = rMaterial;
558  layRep.representingSurface = &tLayer.surfaceRepresentation();
559  }
560  }
561  // the approach
562  if (tLayer.approachDescriptor() != nullptr) {
563  for (auto& asf : tLayer.approachDescriptor()->containedSurfaces()) {
564  // get the surface and check for material
565  if (asf->surfaceMaterial() != nullptr) {
566  Acts::GeometryID approachID = asf->geoID();
567  geo_id_value aid = approachID.approach();
568  layRep.approaches.insert({aid, asf->surfaceMaterial()});
569  layRep.approacheSurfaces.insert({aid, asf});
570  } else if (m_cfg.processnonmaterial == true) {
571  // if no material suface exist add a default one for the mapping
572  // configuration
573  Acts::GeometryID approachID = asf->geoID();
574  geo_id_value aid = approachID.approach();
575  Acts::BinUtility aUtility = DefaultBin(*asf);
576  Acts::ISurfaceMaterial* aMaterial =
577  new Acts::ProtoSurfaceMaterial(aUtility);
578  layRep.approaches.insert({aid, aMaterial});
579  layRep.approacheSurfaces.insert({aid, asf});
580  }
581  }
582  }
583  // return the layer representation
584  return layRep;
585 }
586 
588  const Acts::ISurfaceMaterial& sMaterial) {
589  json smj;
590 
591  // lemma 0 : accept the surface
592  auto convertMaterialProperties =
593  [](const Acts::MaterialProperties& mp) -> std::vector<float> {
594  // convert when ready
595  if (mp) {
597  return {
598  mp.material().X0(), mp.material().L0(), mp.material().Ar(),
599  mp.material().Z(), mp.material().massDensity(), mp.thickness(),
600  };
601  }
602  return {};
603  };
604 
605  // A bin utility needs to be written
606  const Acts::BinUtility* bUtility = nullptr;
607  // Check if we have a proto material
608  auto psMaterial = dynamic_cast<const Acts::ProtoSurfaceMaterial*>(&sMaterial);
609  if (psMaterial != nullptr) {
610  // Type is proto material
611  smj[m_cfg.typekey] = "proto";
612  // by default the protoMaterial is not used for mapping
613  smj[m_cfg.mapkey] = false;
614  bUtility = &(psMaterial->binUtility());
615  } else {
616  // Now check if we have a homogeneous material
617  auto hsMaterial =
618  dynamic_cast<const Acts::HomogeneousSurfaceMaterial*>(&sMaterial);
619  if (hsMaterial != nullptr) {
620  // type is homogeneous
621  smj[m_cfg.typekey] = "homogeneous";
622  smj[m_cfg.mapkey] = true;
623  if (m_cfg.writeData) {
624  // write out the data, it's a [[[X0,L0,Z,A,rho,thickness]]]
625  auto& mp = hsMaterial->materialProperties(0, 0);
626  std::vector<std::vector<std::vector<float>>> mmat = {
627  {convertMaterialProperties(mp)}};
628  smj[m_cfg.datakey] = mmat;
629  }
630  } else {
631  // Only option remaining: BinnedSurface material
632  auto bsMaterial =
633  dynamic_cast<const Acts::BinnedSurfaceMaterial*>(&sMaterial);
634  if (bsMaterial != nullptr) {
635  // type is binned
636  smj[m_cfg.typekey] = "binned";
637  smj[m_cfg.mapkey] = true;
638  bUtility = &(bsMaterial->binUtility());
639  // convert the data
640  // get the material matrix
641  if (m_cfg.writeData) {
642  auto& mpMatrix = bsMaterial->fullMaterial();
643  std::vector<std::vector<std::vector<float>>> mmat;
644  mmat.reserve(mpMatrix.size());
645  for (auto& mpVector : mpMatrix) {
646  std::vector<std::vector<float>> mvec;
647  mvec.reserve(mpVector.size());
648  for (auto& mp : mpVector) {
649  mvec.push_back(convertMaterialProperties(mp));
650  }
651  mmat.push_back(std::move(mvec));
652  }
653  smj[m_cfg.datakey] = mmat;
654  }
655  }
656  }
657  }
658  // add the bin utility
659  if (bUtility != nullptr) {
660  std::vector<std::string> binkeys = {m_cfg.bin0key, m_cfg.bin1key};
661  // loop over dimensions and write
662  auto& binningData = bUtility->binningData();
663  // loop over the dimensions
664  for (size_t ibin = 0; ibin < binningData.size(); ++ibin) {
665  json binj;
666  auto cbData = binningData[ibin];
667  binj.push_back(Acts::binningValueNames[cbData.binvalue]);
668  if (cbData.option == Acts::closed) {
669  binj.push_back("closed");
670  } else {
671  binj.push_back("open");
672  }
673  binj.push_back(cbData.bins());
674  // If protoMaterial has a non uniform binning (non default) then it is
675  // used by default in the mapping
676  if (smj[m_cfg.typekey] == "proto" && cbData.bins() > 1)
677  smj[m_cfg.mapkey] = true;
678  // If it's not a proto map, write min / max
679  if (smj[m_cfg.typekey] != "proto") {
680  std::pair<double, double> minMax = {cbData.min, cbData.max};
681  binj.push_back(minMax);
682  }
683  smj[binkeys[ibin]] = binj;
684  }
685  }
686  return smj;
687 }
688 
690  const Acts::IVolumeMaterial& vMaterial) {
691  json smj;
692  // A bin utility needs to be written
693  const Acts::BinUtility* bUtility = nullptr;
694  // Check if we have a proto material
695  auto pvMaterial = dynamic_cast<const Acts::ProtoVolumeMaterial*>(&vMaterial);
696  if (pvMaterial != nullptr) {
697  // Type is proto material
698  smj[m_cfg.typekey] = "proto";
699  // by default the protoMaterial is not used for mapping
700  smj[m_cfg.mapkey] = false;
701  bUtility = &(pvMaterial->binUtility());
702  } else {
703  // Now check if we have a homogeneous material
704  auto hvMaterial =
705  dynamic_cast<const Acts::HomogeneousVolumeMaterial*>(&vMaterial);
706  if (hvMaterial != nullptr) {
707  // type is homogeneous
708  smj[m_cfg.typekey] = "homogeneous";
709  smj[m_cfg.mapkey] = true;
710  if (m_cfg.writeData) {
711  // write out the data, it's a [[[X0,L0,Z,A,rho,thickness]]]
712  auto mat = hvMaterial->material({0, 0, 0});
713  std::vector<std::vector<float>> mmat;
714  mmat.push_back(
715  {mat.X0(), mat.L0(), mat.Ar(), mat.Z(), mat.massDensity()});
716  smj[m_cfg.datakey] = mmat;
717  }
718  } else {
719  // Only option remaining: material map
720  auto bvMaterial2D = dynamic_cast<
722  &vMaterial);
723  // Now check if we have a 2D map
724  if (bvMaterial2D != nullptr) {
725  // type is binned
726  smj[m_cfg.typekey] = "interpolated2D";
727  smj[m_cfg.mapkey] = true;
728  bUtility = &(bvMaterial2D->binUtility());
729  // convert the data
730  if (m_cfg.writeData) {
731  std::vector<std::vector<float>> mmat;
732  MaterialGrid2D grid = bvMaterial2D->getMapper().getGrid();
733  for (size_t bin = 0; bin < grid.size(); bin++) {
734  auto mat = Material(grid.at(bin));
735  if (mat != Material()) {
736  mmat.push_back(
737  {mat.X0(), mat.L0(), mat.Ar(), mat.Z(), mat.massDensity()});
738  } else {
739  mmat.push_back({0, 0, 0, 0, 0});
740  }
741  }
742  smj[m_cfg.datakey] = mmat;
743  }
744  } else {
745  // Only option remaining: material map
746  auto bvMaterial3D = dynamic_cast<const Acts::InterpolatedMaterialMap<
747  MaterialMapper<MaterialGrid3D>>*>(&vMaterial);
748  // Now check if we have a 3D map
749  if (bvMaterial3D != nullptr) {
750  // type is binned
751  smj[m_cfg.typekey] = "interpolated3D";
752  smj[m_cfg.mapkey] = true;
753  bUtility = &(bvMaterial3D->binUtility());
754  // convert the data
755  if (m_cfg.writeData) {
756  std::vector<std::vector<float>> mmat;
757  MaterialGrid3D grid = bvMaterial3D->getMapper().getGrid();
758  for (size_t bin = 0; bin < grid.size(); bin++) {
759  auto mat = Material(grid.at(bin));
760  if (mat != Material()) {
761  mmat.push_back(
762  {mat.X0(), mat.L0(), mat.Ar(), mat.Z(), mat.massDensity()});
763  } else {
764  mmat.push_back({0, 0, 0, 0, 0});
765  }
766  }
767  smj[m_cfg.datakey] = mmat;
768  }
769  }
770  }
771  }
772  }
773  // add the bin utility
774  if (bUtility != nullptr) {
775  std::vector<std::string> binkeys = {m_cfg.bin0key, m_cfg.bin1key,
776  m_cfg.bin2key};
777  // loop over dimensions and write
778  auto& binningData = bUtility->binningData();
779  // loop over the dimensions
780  for (size_t ibin = 0; ibin < binningData.size(); ++ibin) {
781  json binj;
782  auto cbData = binningData[ibin];
783  binj.push_back(Acts::binningValueNames[cbData.binvalue]);
784  if (cbData.option == Acts::closed) {
785  binj.push_back("closed");
786  } else {
787  binj.push_back("open");
788  }
789  binj.push_back(cbData.bins());
790  // If protoMaterial has a non uniform binning (non default) then it is
791  // used by default in the mapping
792  if (smj[m_cfg.typekey] == "proto" && cbData.bins() > 1)
793  smj[m_cfg.mapkey] = true;
794  // If it's not a proto map, write min / max
795  if (smj[m_cfg.typekey] != "proto") {
796  std::pair<double, double> minMax = {cbData.min, cbData.max};
797  binj.push_back(minMax);
798  }
799  smj[binkeys[ibin]] = binj;
800  }
801  }
802  return smj;
803 }
804 
806  const Surface* surface) {
807  // Get the ID of the surface (redundant but help readability)
808  std::ostringstream SurfaceID;
809  SurfaceID << surface->geoID();
810  sjson[m_cfg.surfacegeoidkey] = SurfaceID.str();
811 
812  // Cast the surface bound to both disk and cylinder
813  const Acts::SurfaceBounds& surfaceBounds = surface->bounds();
814  auto sTransform = surface->transform(GeometryContext());
815 
816  const Acts::RadialBounds* radialBounds =
817  dynamic_cast<const Acts::RadialBounds*>(&surfaceBounds);
818  const Acts::CylinderBounds* cylinderBounds =
819  dynamic_cast<const Acts::CylinderBounds*>(&surfaceBounds);
820  const Acts::AnnulusBounds* annulusBounds =
821  dynamic_cast<const Acts::AnnulusBounds*>(&surfaceBounds);
822 
823  if (radialBounds != nullptr) {
824  sjson[m_cfg.surfacetypekey] = "Disk";
825  sjson[m_cfg.surfacepositionkey] = sTransform.translation().z();
826  sjson[m_cfg.surfacerangekey] = {radialBounds->rMin(), radialBounds->rMax()};
827  }
828  if (cylinderBounds != nullptr) {
829  sjson[m_cfg.surfacetypekey] = "Cylinder";
830  sjson[m_cfg.surfacepositionkey] = cylinderBounds->get(CylinderBounds::eR);
831  sjson[m_cfg.surfacerangekey] = {
832  -1 * cylinderBounds->get(CylinderBounds::eHalfLengthZ),
833  cylinderBounds->get(CylinderBounds::eHalfLengthZ)};
834  }
835  if (annulusBounds != nullptr) {
836  sjson[m_cfg.surfacetypekey] = "Annulus";
837  sjson[m_cfg.surfacepositionkey] = sTransform.translation().z();
838  sjson[m_cfg.surfacerangekey] = {
839  {annulusBounds->rMin(), annulusBounds->rMax()},
840  {annulusBounds->phiMin(), annulusBounds->phiMax()}};
841  }
842 }
843 
849  for (auto& outer : data) {
851  for (auto& inner : outer) {
852  if (inner.size() > 5) {
853  mpVector.push_back(Acts::MaterialProperties(
854  inner[0], inner[1], inner[2], inner[3], inner[4], inner[5]));
855  } else {
856  mpVector.push_back(Acts::MaterialProperties());
857  }
858  }
859  mpMatrix.push_back(std::move(mpVector));
860  }
861  return mpMatrix;
862 }
863 
866  const json& bin) {
867  // finding the iterator position to determine the binning value
868  auto bit = std::find(Acts::binningValueNames.begin(),
869  Acts::binningValueNames.end(), bin[0]);
870  size_t indx = std::distance(Acts::binningValueNames.begin(), bit);
872  Acts::BinningOption bopt = bin[1] == "open" ? Acts::open : Acts::closed;
873  unsigned int bins = bin[2];
874  float min = 0;
875  float max = 0;
876  if (bin[3].size() == 2) {
877  min = bin[3][0];
878  max = bin[3][1];
879  }
880  return Acts::BinUtility(bins, min, max, bopt, bval);
881 }
882 
884  const Acts::Surface& surface) {
885  Acts::BinUtility bUtility;
886 
887  const Acts::SurfaceBounds& surfaceBounds = surface.bounds();
888  const Acts::RadialBounds* radialBounds =
889  dynamic_cast<const Acts::RadialBounds*>(&surfaceBounds);
890  const Acts::CylinderBounds* cylinderBounds =
891  dynamic_cast<const Acts::CylinderBounds*>(&surfaceBounds);
892  const Acts::AnnulusBounds* annulusBounds =
893  dynamic_cast<const Acts::AnnulusBounds*>(&surfaceBounds);
894 
895  if (radialBounds != nullptr) {
896  bUtility += BinUtility(1,
897  radialBounds->get(RadialBounds::eAveragePhi) -
898  radialBounds->get(RadialBounds::eHalfPhiSector),
899  radialBounds->get(RadialBounds::eAveragePhi) +
900  radialBounds->get(RadialBounds::eHalfPhiSector),
902  bUtility += BinUtility(1, radialBounds->rMin(), radialBounds->rMax(),
904  }
905  if (cylinderBounds != nullptr) {
906  bUtility +=
907  BinUtility(1,
908  cylinderBounds->get(CylinderBounds::eAveragePhi) -
909  cylinderBounds->get(CylinderBounds::eHalfPhiSector),
910  cylinderBounds->get(CylinderBounds::eAveragePhi) +
911  cylinderBounds->get(CylinderBounds::eHalfPhiSector),
913  bUtility +=
914  BinUtility(1, -1 * cylinderBounds->get(CylinderBounds::eHalfLengthZ),
915  cylinderBounds->get(CylinderBounds::eHalfLengthZ),
917  }
918  if (annulusBounds != nullptr) {
919  bUtility += BinUtility(1, annulusBounds->get(AnnulusBounds::eMinPhiRel),
920  annulusBounds->get(AnnulusBounds::eMaxPhiRel),
922  bUtility += BinUtility(1, annulusBounds->rMin(), annulusBounds->rMax(),
924  }
925  return bUtility;
926 }
927 
929  const Acts::TrackingVolume& volume) {
930  Acts::BinUtility bUtility;
931 
932  auto cyBounds =
933  dynamic_cast<const CylinderVolumeBounds*>(&(volume.volumeBounds()));
934  auto cuBounds =
935  dynamic_cast<const CuboidVolumeBounds*>(&(volume.volumeBounds()));
936 
937  if (cyBounds != nullptr) {
938  bUtility += BinUtility(1, cyBounds->get(CylinderVolumeBounds::eMinR),
939  cyBounds->get(CylinderVolumeBounds::eMaxR),
941  bUtility +=
945  bUtility +=
947  cyBounds->get(CylinderVolumeBounds::eHalfLengthZ),
949  } else if (cuBounds != nullptr) {
950  bUtility += BinUtility(1, -cuBounds->get(CuboidVolumeBounds::eHalfLengthX),
951  cuBounds->get(CuboidVolumeBounds::eHalfLengthX),
953  bUtility += BinUtility(1, -cuBounds->get(CuboidVolumeBounds::eHalfLengthY),
954  cuBounds->get(CuboidVolumeBounds::eHalfLengthY),
956  bUtility += BinUtility(1, -cuBounds->get(CuboidVolumeBounds::eHalfLengthZ),
957  cuBounds->get(CuboidVolumeBounds::eHalfLengthZ),
959  }
960  return bUtility;
961 }