Skip to content

Commit ee545bd

Browse files
Add interface for sim parameters to JSON (#8017)
first step to give cut and process setting from the outside more structure introduce JSON parsing into MaterialManager for that matter leave the previous interface for now where cuts and processes are set from bare text files introduce configurable params MaterialManagerParam.paramFile to pass and overwrite parameters from command line MaterialManagerParam.outputFile to write parameters used in the sim to JSON for further usage and inspection introduced policy: parameters set later will overwrite previous settings usage to overwrite from cmd ``` o2-sim <args> --configKeyValues "MaterialManagerParam.inputFile=<path/to/file.json>" to write to med_params.json o2-sim <args> --configKeyValues "MaterialManagerParam.outputFile=med_params.json" Of course, both configKeyValues can be passed simultaneously. The output in med_params.json looks like { "module_1": [ { "local_id": 1, "global_id": 5, "medium_name": "med_1_1", "material_name": "mat_1_1", "cuts": { "CUTGAM": 0.1, "CUTELE": 0.1, "CUTNEU": 0.1, "CUTHAD": 0.1, "CUTMUO": 0.1, "BCUTE": 0.1, "BCUTM": 0.1, "...": 0.1}, "processes": { "PAIR": 0, "COMP": 1, "PHOT": -1, "PFIS": 1, "DRAY": 0, "ANNI": 0, "BREM": 1, "...": -1} }, { "local_id": 2, "global_id": 3, "medium_name": "med_1_2", "material_name": "mat_1_2", "cuts": {"...": "..."}, "processes": {"...": "..."} } ], "module_N": [ { "local_id": 10, "global_id": 50, "medium_name": "med_N_10", "material_name": "mat_N_10", "cuts": {"...": "..."}, "processes": {"...": "..."} }, { "local_id": 20, "global_id": 30, "medium_name": "med_N_20", "material_name": "mat_N_20", "cuts": {"...": "..."}, "processes": {"...": "..."} } ], "default": { "cuts": {"...": "..."}, "processes": {"...": "..."} } "enableSpecialCuts": true, "enableSpecialProcesses": false } ``` This can be edited/extended and used again as input as well. The global_id is the ID assigned by ROOT's TGeo and it is indeed useful to have that available when internal information of module-local medium IDs is not available. In addition, the latter is extremely useful to be used in parameter optimisation together with the MCReplay engine
1 parent 1fbf22d commit ee545bd

File tree

9 files changed

+271
-8
lines changed

9 files changed

+271
-8
lines changed

Detectors/Base/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ o2_add_library(DetectorsBase
1313
SOURCES src/Detector.cxx
1414
src/GeometryManager.cxx
1515
src/MaterialManager.cxx
16+
src/MaterialManagerParam.cxx
1617
src/Propagator.cxx
1718
src/MatLayerCyl.cxx
1819
src/MatLayerCylSet.cxx
@@ -41,6 +42,7 @@ o2_target_root_dictionary(DetectorsBase
4142
HEADERS include/DetectorsBase/Detector.h
4243
include/DetectorsBase/GeometryManager.h
4344
include/DetectorsBase/MaterialManager.h
45+
include/DetectorsBase/MaterialManagerParam.h
4446
include/DetectorsBase/Propagator.h
4547
include/DetectorsBase/Ray.h
4648
include/DetectorsBase/MatCell.h

Detectors/Base/include/DetectorsBase/MaterialManager.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,8 @@ class MaterialManager
133133

134134
/// load cuts and process flags from a data file (like AliRoot did)
135135
void loadCutsAndProcessesFromFile(const char* modname, const char* filename);
136+
void loadCutsAndProcessesFromJSON(ESpecial special = ESpecial::kFALSE, std::string const& filename = "");
137+
void writeCutsAndProcessesToJSON(std::string const& filename = "");
136138

137139
/// Set flags whether to use special cuts and process settings
138140
void enableSpecialProcesses(bool val = true) { mApplySpecialProcesses = val; }
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2+
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3+
// All rights not expressly granted are reserved.
4+
//
5+
// This software is distributed under the terms of the GNU General Public
6+
// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7+
//
8+
// In applying this license CERN does not waive the privileges and immunities
9+
// granted to it by virtue of its status as an Intergovernmental Organization
10+
// or submit itself to any jurisdiction.
11+
12+
#ifndef DETECTORS_BASE_INCLUDE_MATERIALMANAGERPARAM_H_
13+
#define DETECTORS_BASE_INCLUDE_MATERIALMANAGERPARAM_H_
14+
15+
#include "CommonUtils/ConfigurableParam.h"
16+
#include "CommonUtils/ConfigurableParamHelper.h"
17+
18+
namespace o2
19+
{
20+
21+
struct MaterialManagerParam : public o2::conf::ConfigurableParamHelper<MaterialManagerParam> {
22+
std::string inputFile = "";
23+
std::string outputFile = "";
24+
// boilerplate stuff + make principal key "MaterialManagerParam"
25+
O2ParamDef(MaterialManagerParam, "MaterialManagerParam");
26+
};
27+
28+
} // namespace o2
29+
30+
#endif /* DETECTORS_BASE_INCLUDE_MATERIALMANAGERPARAM_H_ */

Detectors/Base/src/DetectorsBaseLinkDef.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#pragma link C++ class o2::base::GeometryManager + ;
2525
#pragma link C++ class o2::base::GeometryManager::MatBudgetExt + ;
2626
#pragma link C++ class o2::base::MaterialManager + ;
27+
#pragma link C++ class o2::MaterialManagerParam + ;
2728

2829
#pragma link C++ class o2::base::Ray + ;
2930
#pragma link C++ class o2::base::MatCell + ;

Detectors/Base/src/MaterialManager.cxx

Lines changed: 213 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
/// \brief Implementation of the MaterialManager class
1414

1515
#include "DetectorsBase/MaterialManager.h"
16+
#include "DetectorsBase/MaterialManagerParam.h"
1617
#include "TVirtualMC.h"
1718
#include "TString.h" // for TString
1819
#include <TGeoMedium.h>
@@ -26,8 +27,39 @@
2627
#endif
2728
#include <cassert>
2829
#include <set>
30+
#include "rapidjson/document.h"
31+
#include "rapidjson/istreamwrapper.h"
32+
#include "rapidjson/ostreamwrapper.h"
33+
#include "rapidjson/prettywriter.h"
2934

3035
using namespace o2::base;
36+
namespace rj = rapidjson;
37+
38+
namespace
39+
{
40+
/// helper to read/write cuts and processes from/to JSON
41+
template <typename K, typename V>
42+
void writeSingleJSONParamBatch(std::unordered_map<K, const char*> const& idToName, std::map<K, V> const& valMap, V defaultValue, rapidjson::Value& parent, rapidjson::Document::AllocatorType& a)
43+
{
44+
for (auto& itName : idToName) {
45+
auto itVal = valMap.find(itName.first);
46+
if (itVal != valMap.end()) {
47+
parent.AddMember(rj::Value(itName.second, std::strlen(itName.second), a), rj::Value(itVal->second), a);
48+
continue;
49+
}
50+
parent.AddMember(rj::Value(itName.second, std::strlen(itName.second), a), rj::Value(defaultValue), a);
51+
}
52+
}
53+
54+
/// specific names of keys wo expect and write in cut and process JSON files
55+
static constexpr const char* jsonKeyID = "local_id";
56+
static constexpr const char* jsonKeyIDGlobal = "global_id";
57+
static constexpr const char* jsonKeyDefault = "default";
58+
static constexpr const char* jsonKeyCuts = "cuts";
59+
static constexpr const char* jsonKeyProcesses = "processes";
60+
static constexpr const char* jsonKeyEnableSpecialCuts = "enableSpecialCuts";
61+
static constexpr const char* jsonKeyEnableSpecialProcesses = "enableSpecialProcesses";
62+
} // namespace
3163

3264
const std::unordered_map<EProc, const char*> MaterialManager::mProcessIDToName = {
3365
{EProc::kPAIR, "PAIR"},
@@ -178,12 +210,16 @@ void MaterialManager::Cut(ESpecial special, int globalindex, ECut cut, Float_t v
178210
return;
179211
}
180212
if (special == ESpecial::kFALSE) {
181-
mDefaultCutMap[cut] = val;
213+
auto ins = mDefaultCutMap.insert({cut, val});
214+
if (ins.second) {
215+
TVirtualMC::GetMC()->SetCut(it->second, val);
216+
}
182217
/// Explicit template definition to cover this which differs from global cut setting
183-
TVirtualMC::GetMC()->SetCut(it->second, val);
184218
} else if (mApplySpecialCuts) {
185-
mMediumCutMap[globalindex][cut] = val;
186-
TVirtualMC::GetMC()->Gstpar(globalindex, it->second, val);
219+
auto ins = mMediumCutMap[globalindex].insert({cut, val});
220+
if (ins.second) {
221+
TVirtualMC::GetMC()->Gstpar(globalindex, it->second, val);
222+
}
187223
}
188224
}
189225

@@ -198,12 +234,16 @@ void MaterialManager::Process(ESpecial special, int globalindex, EProc process,
198234
return;
199235
}
200236
if (special == ESpecial::kFALSE) {
201-
mDefaultProcessMap[process] = val;
237+
auto ins = mDefaultProcessMap.insert({process, val});
238+
if (ins.second) {
239+
TVirtualMC::GetMC()->SetProcess(it->second, val);
240+
}
202241
/// Explicit template definition to cover this which differs from global process setting
203-
TVirtualMC::GetMC()->SetProcess(it->second, val);
204242
} else if (mApplySpecialProcesses) {
205-
mMediumProcessMap[globalindex][process] = val;
206-
TVirtualMC::GetMC()->Gstpar(globalindex, it->second, val);
243+
auto ins = mMediumProcessMap[globalindex].insert({process, val});
244+
if (ins.second) {
245+
TVirtualMC::GetMC()->Gstpar(globalindex, it->second, val);
246+
}
207247
}
208248
}
209249

@@ -326,6 +366,169 @@ TGeoMedium* MaterialManager::getTGeoMedium(const char* mediumname)
326366
return med;
327367
}
328368

369+
void MaterialManager::loadCutsAndProcessesFromJSON(ESpecial special, std::string const& filename)
370+
{
371+
const std::string filenameIn = filename.empty() ? o2::MaterialManagerParam::Instance().inputFile : filename;
372+
if (filenameIn.empty()) {
373+
return;
374+
}
375+
std::ifstream is(filenameIn);
376+
if (!is.is_open()) {
377+
LOG(error) << "Cannot open file " << filenameIn;
378+
return;
379+
}
380+
auto digestCutsFromJSON = [this](int globalindex, rj::Value& cuts) {
381+
auto special = globalindex < 0 ? ESpecial::kFALSE : ESpecial::kTRUE;
382+
for (auto& cut : cuts.GetObject()) {
383+
auto name = cut.name.GetString();
384+
bool found = false;
385+
for (auto& cn : mCutIDToName) {
386+
if (std::strcmp(name, cn.second) == 0) {
387+
Cut(special, globalindex, cn.first, cut.value.GetFloat());
388+
found = true;
389+
}
390+
}
391+
if (!found) {
392+
LOG(warn) << "Unknown cut parameter " << name;
393+
}
394+
}
395+
};
396+
auto digestProcessesFromJSON = [this](int globalindex, rj::Value& processes) {
397+
auto special = globalindex < 0 ? ESpecial::kFALSE : ESpecial::kTRUE;
398+
for (auto& proc : processes.GetObject()) {
399+
auto name = proc.name.GetString();
400+
for (auto& pn : mProcessIDToName) {
401+
if (std::strcmp(name, pn.second) == 0) {
402+
Process(special, globalindex, pn.first, proc.value.GetInt());
403+
}
404+
}
405+
}
406+
};
407+
408+
rj::IStreamWrapper isw(is);
409+
rj::Document d;
410+
d.ParseStream(isw);
411+
412+
if (special == ESpecial::kFALSE && d.HasMember(jsonKeyDefault)) {
413+
// defaults
414+
auto& defaultParams = d[jsonKeyDefault];
415+
if (defaultParams.HasMember(jsonKeyCuts)) {
416+
digestCutsFromJSON(-1, defaultParams[jsonKeyCuts]);
417+
}
418+
if (defaultParams.HasMember(jsonKeyProcesses)) {
419+
digestProcessesFromJSON(-1, defaultParams[jsonKeyProcesses]);
420+
}
421+
} else if (special == ESpecial::kTRUE) {
422+
// read whether to apply special cuts and processes at all
423+
if (d.HasMember(jsonKeyEnableSpecialCuts)) {
424+
enableSpecialCuts(d[jsonKeyEnableSpecialCuts].GetBool());
425+
}
426+
if (d.HasMember(jsonKeyEnableSpecialProcesses)) {
427+
enableSpecialProcesses(d[jsonKeyEnableSpecialProcesses].GetBool());
428+
}
429+
// special
430+
for (auto& m : d.GetObject()) {
431+
if (m.name.GetString()[0] == '\0' || !m.value.IsArray()) {
432+
// do not parse anything with empty key, these at the most meant to be comments
433+
continue;
434+
}
435+
for (auto& batch : m.value.GetArray()) {
436+
if (std::strcmp(m.name.GetString(), jsonKeyDefault) == 0) {
437+
// don't do defaults here
438+
continue;
439+
}
440+
// set via their global indices
441+
auto index = getMediumID(m.name.GetString(), batch[jsonKeyID].GetInt());
442+
if (index < 0) {
443+
continue;
444+
}
445+
if (batch.HasMember(jsonKeyCuts)) {
446+
digestCutsFromJSON(index, batch[jsonKeyCuts]);
447+
}
448+
if (batch.HasMember(jsonKeyProcesses)) {
449+
digestProcessesFromJSON(index, batch[jsonKeyProcesses]);
450+
}
451+
}
452+
}
453+
}
454+
}
455+
456+
void MaterialManager::writeCutsAndProcessesToJSON(std::string const& filename)
457+
{
458+
const std::string filenameOut = filename.empty() ? o2::MaterialManagerParam::Instance().outputFile : filename;
459+
if (filenameOut.empty()) {
460+
return;
461+
}
462+
463+
// write parameters as global AND module specific
464+
std::ofstream os(filenameOut);
465+
if (!os.is_open()) {
466+
LOG(error) << "Cannot create file " << filenameOut;
467+
return;
468+
}
469+
470+
rj::Document d;
471+
rj::Document::AllocatorType& a = d.GetAllocator();
472+
d.SetObject();
473+
474+
// add each local medium with params per module
475+
for (auto& itMed : mMediumMap) {
476+
// prepare array for module
477+
rj::Value toAdd(rj::kArrayType);
478+
// extract each medium's local and global index
479+
for (auto& locToGlob : itMed.second) {
480+
auto globalindex = locToGlob.second;
481+
auto itCut = mMediumCutMap.find(globalindex);
482+
auto itProc = mMediumProcessMap.find(globalindex);
483+
// prepare a batch summarising localID, globaldID, cuts and processes
484+
rj::Value oLoc(rj::kObjectType);
485+
// IDs
486+
oLoc.AddMember(rj::Value(jsonKeyID, std::strlen(jsonKeyID), a), rj::Value(locToGlob.first), a);
487+
oLoc.AddMember(rj::Value(jsonKeyIDGlobal, std::strlen(jsonKeyIDGlobal)), rj::Value(locToGlob.second), a);
488+
// add medium and material name
489+
auto mediumIt = mTGeoMediumMap.find({itMed.first, locToGlob.first});
490+
const char* medName = mediumIt->second->GetName();
491+
const char* matName = mediumIt->second->GetMaterial()->GetName();
492+
// not using variables for key names cause they are only written for info but not read
493+
oLoc.AddMember(rj::Value("medium_name", 11, a), rj::Value(medName, std::strlen(medName), a), a);
494+
oLoc.AddMember(rj::Value("material_name", 13, a), rj::Value(matName, std::strlen(matName), a), a);
495+
// prepare for cuts
496+
if (itCut != mMediumCutMap.end()) {
497+
rj::Value cutMap(rj::kObjectType);
498+
writeSingleJSONParamBatch(mCutIDToName, itCut->second, -1.f, cutMap, a);
499+
oLoc.AddMember(rj::Value(jsonKeyCuts, std::strlen(jsonKeyCuts), a), cutMap, a);
500+
}
501+
// prepare for processes
502+
if (itProc != mMediumProcessMap.end()) {
503+
rj::Value procMap(rj::kObjectType);
504+
writeSingleJSONParamBatch(mProcessIDToName, itProc->second, -1, procMap, a);
505+
oLoc.AddMember(rj::Value(jsonKeyProcesses, std::strlen(jsonKeyProcesses), a), procMap, a);
506+
}
507+
// append this medium to module array
508+
toAdd.PushBack(oLoc, a);
509+
}
510+
// append the entire module array
511+
d.AddMember(rj::Value(itMed.first.c_str(), itMed.first.size(), a), toAdd, a);
512+
}
513+
// also add default parameters
514+
rj::Value cutMapDef(rj::kObjectType);
515+
rj::Value procMapDef(rj::kObjectType);
516+
writeSingleJSONParamBatch(mCutIDToName, mDefaultCutMap, -1.f, cutMapDef, a);
517+
writeSingleJSONParamBatch(mProcessIDToName, mDefaultProcessMap, -1, procMapDef, a);
518+
rj::Value defaultParams(rj::kObjectType);
519+
defaultParams.AddMember(rj::Value(jsonKeyCuts, std::strlen(jsonKeyCuts), a), cutMapDef, a);
520+
defaultParams.AddMember(rj::Value(jsonKeyProcesses, std::strlen(jsonKeyProcesses), a), procMapDef, a);
521+
d.AddMember(rj::Value(jsonKeyDefault, std::strlen(jsonKeyDefault), a), defaultParams, a);
522+
523+
d.AddMember(rj::Value(jsonKeyEnableSpecialCuts, std::strlen(jsonKeyEnableSpecialCuts), a), rj::Value(mApplySpecialCuts), a);
524+
d.AddMember(rj::Value(jsonKeyEnableSpecialProcesses, std::strlen(jsonKeyEnableSpecialProcesses), a), rj::Value(mApplySpecialProcesses), a);
525+
// now write to file
526+
rj::OStreamWrapper osw(os);
527+
rj::PrettyWriter<rj::OStreamWrapper> writer(osw);
528+
writer.SetIndent(' ', 2);
529+
d.Accept(writer);
530+
}
531+
329532
void MaterialManager::loadCutsAndProcessesFromFile(const char* modname, const char* filename)
330533
{
331534
// Implementation of a method to set cuts and processes as done in AliRoot.
@@ -446,6 +649,8 @@ void MaterialManager::SpecialProcess(const char* modname, int localindex, EProc
446649
int globalindex = getMediumID(modname, localindex);
447650
if (globalindex != -1) {
448651
Process(ESpecial::kTRUE, globalindex, parID, val);
652+
} else {
653+
LOG(warn) << "SpecialProcess: NO GLOBALINDEX FOUND FOR " << modname << " " << localindex;
449654
}
450655
}
451656

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2+
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3+
// All rights not expressly granted are reserved.
4+
//
5+
// This software is distributed under the terms of the GNU General Public
6+
// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7+
//
8+
// In applying this license CERN does not waive the privileges and immunities
9+
// granted to it by virtue of its status as an Intergovernmental Organization
10+
// or submit itself to any jurisdiction.
11+
12+
#include "DetectorsBase/MaterialManagerParam.h"
13+
O2ParamImpl(o2::MaterialManagerParam);

Detectors/gconfig/src/SetCuts.cxx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ void SetCuts()
3737
// \note All following settings could also be set in Cave since it is always loaded.
3838
// Use MaterialManager to set processes and cuts
3939
auto& mgr = o2::base::MaterialManager::Instance();
40+
// This loads default cuts and processes if they are defined in the MaterialManagerParam.inputFile
41+
// The cuts and processes below will only be set if they were not defined in the JSON
42+
mgr.loadCutsAndProcessesFromJSON();
4043
auto& params = o2::GlobalProcessCutSimParam::Instance();
4144

4245
LOG(info) << "Set default settings for processes and cuts.";

Steer/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ o2_add_library(Steer
1414
src/HitProcessingManager.cxx src/MCKinematicsReader.cxx
1515
PUBLIC_LINK_LIBRARIES O2::CommonDataFormat
1616
O2::CommonConstants
17+
O2::DetectorsBase
1718
O2::SimulationDataFormat
1819
O2::DetectorsCommonDataFormats)
1920

Steer/src/O2MCApplication.cxx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <SimConfig/SimConfig.h>
2121
#include <DetectorsBase/Detector.h>
2222
#include "DetectorsBase/Aligner.h"
23+
#include "DetectorsBase/MaterialManager.h"
2324
#include <CommonUtils/ShmManager.h>
2425
#include <cassert>
2526
#include <SimulationDataFormat/MCEventHeader.h>
@@ -122,7 +123,12 @@ void O2MCApplicationBase::ConstructGeometry()
122123

123124
void O2MCApplicationBase::InitGeometry()
124125
{
126+
// load special cuts which might be given from the outside first.
127+
auto& matMgr = o2::base::MaterialManager::Instance();
128+
matMgr.loadCutsAndProcessesFromJSON(o2::base::MaterialManager::ESpecial::kTRUE);
129+
// During the following, FairModule::SetSpecialPhysicsCuts will be called for each module
125130
FairMCApplication::InitGeometry();
131+
matMgr.writeCutsAndProcessesToJSON();
126132
// now the sensitive volumes are set up in fVolMap and we can query them
127133
for (auto e : fVolMap) {
128134
// since fVolMap contains multiple entries (if multiple copies), this may

0 commit comments

Comments
 (0)