Skip to content

Commit e0a5711

Browse files
committed
feat(config): route SEvt output directory through app config
This branch refactors output directory handling so app-level JSON config can control where event folders are written, instead of relying only on default `SEventConfig` behavior/env vars. - Centralize runtime output path control in the application config layer. - Make output location explicit and reproducible across binaries. - Reduce dependence on ad-hoc env setup in test and local runs. If `event.output_dir` is set, SEvt output folders are rooted there.
1 parent 32a20ff commit e0a5711

12 files changed

Lines changed: 118 additions & 38 deletions

config/dev.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
"event": {
2727
"mode": "DebugLite",
28-
"maxslot": 1000000
28+
"maxslot": 1000000,
29+
"output_dir": "/tmp"
2930
}
3031
}

src/GPUCerenkov.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#include "sysrap/OPTICKS_LOG.hh"
1414

15+
#include "config.h"
1516
#include "GPUCerenkov.h"
1617

1718
#include "G4RunManager.hh"
@@ -56,7 +57,7 @@ int main(int argc, char **argv)
5657

5758
argparse::ArgumentParser program("GPUCerenkov", "0.0.0");
5859

59-
string gdml_file, macro_name;
60+
string gdml_file, config_name, macro_name;
6061
bool interactive;
6162

6263
program.add_argument("-g", "--gdml")
@@ -65,6 +66,12 @@ int main(int argc, char **argv)
6566
.nargs(1)
6667
.store_into(gdml_file);
6768

69+
program.add_argument("-c", "--config")
70+
.help("the name of a config file")
71+
.default_value(string("dev"))
72+
.nargs(1)
73+
.store_into(config_name);
74+
6875
program.add_argument("-m", "--macro")
6976
.help("path to G4 macro")
7077
.default_value(string("run.mac"))
@@ -87,6 +94,8 @@ int main(int argc, char **argv)
8794
exit(EXIT_FAILURE);
8895
}
8996

97+
gphox::Config cfg(config_name);
98+
9099
// Configure Geant4
91100
// The physics list must be instantiated before other user actions
92101
G4VModularPhysicsList *physics = new FTFP_BERT;

src/GPUPhotonFileSource.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
#include "sysrap/OPTICKS_LOG.hh"
1515

16+
#include "config.h"
1617
#include "GPUPhotonFileSource.h"
1718

1819
using namespace std;
@@ -23,7 +24,7 @@ int main(int argc, char **argv)
2324

2425
argparse::ArgumentParser program("GPUPhotonFileSource", "0.0.0");
2526

26-
string gdml_file, macro_name, photon_file;
27+
string gdml_file, config_name, macro_name, photon_file;
2728
bool interactive;
2829

2930
program.add_argument("-g", "--gdml")
@@ -32,6 +33,12 @@ int main(int argc, char **argv)
3233
.nargs(1)
3334
.store_into(gdml_file);
3435

36+
program.add_argument("-c", "--config")
37+
.help("the name of a config file")
38+
.default_value(string("dev"))
39+
.nargs(1)
40+
.store_into(config_name);
41+
3542
program.add_argument("-p", "--photons")
3643
.help("path to input photon text file (one photon per line: pos_x pos_y pos_z time mom_x mom_y mom_z pol_x "
3744
"pol_y pol_z wavelength)")
@@ -75,6 +82,8 @@ int main(int argc, char **argv)
7582
CLHEP::HepRandom::setTheSeed(seed);
7683
G4cout << "Random seed set to: " << seed << G4endl;
7784

85+
gphox::Config cfg(config_name);
86+
7887
// Configure Geant4
7988
// The physics list must be instantiated before other user actions
8089
G4VModularPhysicsList *physics = new FTFP_BERT;

src/GPURaytrace.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#include "sysrap/OPTICKS_LOG.hh"
1414

15+
#include "config.h"
1516
#include "GPURaytrace.h"
1617

1718
#include "G4RunManager.hh"
@@ -53,7 +54,7 @@ int main(int argc, char **argv)
5354

5455
argparse::ArgumentParser program("GPURaytrace", "0.0.0");
5556

56-
string gdml_file, macro_name;
57+
string gdml_file, config_name, macro_name;
5758
bool interactive;
5859

5960
program.add_argument("-g", "--gdml")
@@ -62,6 +63,12 @@ int main(int argc, char **argv)
6263
.nargs(1)
6364
.store_into(gdml_file);
6465

66+
program.add_argument("-c", "--config")
67+
.help("the name of a config file")
68+
.default_value(string("dev"))
69+
.nargs(1)
70+
.store_into(config_name);
71+
6572
program.add_argument("-m", "--macro")
6673
.help("path to G4 macro")
6774
.default_value(string("run.mac"))
@@ -98,6 +105,8 @@ int main(int argc, char **argv)
98105
CLHEP::HepRandom::setTheSeed(seed);
99106
G4cout << "Random seed set to: " << seed << G4endl;
100107

108+
gphox::Config cfg(config_name);
109+
101110
// Configure Geant4
102111
// The physics list must be instantiated before other user actions
103112
G4VModularPhysicsList *physics = new FTFP_BERT;

src/config.cpp

Lines changed: 41 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include <cstdlib>
22
#include <filesystem>
3+
#include <fstream>
34
#include <iostream>
45
#include <stdexcept>
56
#include <string>
@@ -28,8 +29,22 @@ bool FileExists(const std::string &path)
2829
return std::filesystem::exists(path, ec) && !ec;
2930
}
3031

32+
std::filesystem::path DefaultOutputDir()
33+
{
34+
return std::filesystem::current_path();
35+
}
36+
37+
std::filesystem::path ReadOutputDir(const nlohmann::json& event)
38+
{
39+
if (event.contains("output_dir"))
40+
return event["output_dir"].get<std::string>();
41+
42+
return DefaultOutputDir();
43+
}
44+
3145
Config::Config(std::string config_name) :
32-
name{std::getenv("GPHOX_CONFIG") ? std::getenv("GPHOX_CONFIG") : config_name}
46+
name{config_name},
47+
output_dir{DefaultOutputDir()}
3348
{
3449
ReadConfig(Locate(name + ".json"));
3550
}
@@ -111,31 +126,36 @@ void Config::ReadConfig(std::string filepath)
111126
std::ifstream ifs(filepath);
112127
ifs >> json;
113128

114-
nlohmann::json torch_ = json["torch"];
115-
116-
torch = {
117-
.gentype = OpticksGenstep_::Type(torch_["gentype"]),
118-
.trackid = torch_["trackid"],
119-
.matline = torch_["matline"],
120-
.numphoton = torch_["numphoton"],
121-
.pos = make_float3(torch_["pos"][0], torch_["pos"][1], torch_["pos"][2]),
122-
.time = torch_["time"],
123-
.mom = normalize(make_float3(torch_["mom"][0], torch_["mom"][1], torch_["mom"][2])),
124-
.weight = torch_["weight"],
125-
.pol = make_float3(torch_["pol"][0], torch_["pol"][1], torch_["pol"][2]),
126-
.wavelength = torch_["wavelength"],
127-
.zenith = make_float2(torch_["zenith"][0], torch_["zenith"][1]),
128-
.azimuth = make_float2(torch_["azimuth"][0], torch_["azimuth"][1]),
129-
.radius = torch_["radius"],
130-
.distance = torch_["distance"],
131-
.mode = torch_["mode"],
132-
.type = storchtype::Type(torch_["type"])
133-
};
129+
if (json.contains("torch")) {
130+
nlohmann::json torch_ = json["torch"];
131+
132+
torch = {
133+
.gentype = OpticksGenstep_::Type(torch_["gentype"]),
134+
.trackid = torch_["trackid"],
135+
.matline = torch_["matline"],
136+
.numphoton = torch_["numphoton"],
137+
.pos = make_float3(torch_["pos"][0], torch_["pos"][1], torch_["pos"][2]),
138+
.time = torch_["time"],
139+
.mom = normalize(make_float3(torch_["mom"][0], torch_["mom"][1], torch_["mom"][2])),
140+
.weight = torch_["weight"],
141+
.pol = make_float3(torch_["pol"][0], torch_["pol"][1], torch_["pol"][2]),
142+
.wavelength = torch_["wavelength"],
143+
.zenith = make_float2(torch_["zenith"][0], torch_["zenith"][1]),
144+
.azimuth = make_float2(torch_["azimuth"][0], torch_["azimuth"][1]),
145+
.radius = torch_["radius"],
146+
.distance = torch_["distance"],
147+
.mode = torch_["mode"],
148+
.type = storchtype::Type(torch_["type"])
149+
};
150+
}
134151

135152
nlohmann::json event_ = json["event"];
136153

154+
output_dir = ReadOutputDir(event_);
155+
137156
SEventConfig::SetEventMode( string(event_["mode"]).c_str() );
138157
SEventConfig::SetMaxSlot( event_["maxslot"] );
158+
SEventConfig::SetOutFold(output_dir.string().c_str());
139159
}
140160
catch (nlohmann::json::exception& e) {
141161
std::string errmsg{"Failed reading config parameters from " + filepath + "\n" + e.what()};

src/config.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ class Config
2424
/// A unique name associated with this Config
2525
std::string name;
2626

27+
/// Base directory for event output folders.
28+
std::filesystem::path output_dir;
29+
2730
storch torch;
2831

2932
private:

sysrap/SEvt.cc

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4231,6 +4231,7 @@ SEvt::DefaultBase
42314231
42324232
If argument is defined it is used, otherwise::
42334233
4234+
SEventConfig::OutFold() when explicitly overridden, otherwise
42344235
$TMP/GEOM/$GEOM/$ExecutableName
42354236
42364237
Note that when Opticks is used from python the OPTICKS_SCRIPT
@@ -4242,11 +4243,26 @@ ExecutableName of "python3.11" or whatever.
42424243
const char* SEvt::DefaultBase(const char* base_) // static
42434244
{
42444245
const char* base = nullptr ;
4246+
const char* outfold = SEventConfig::OutFold();
4247+
bool use_outfold =
4248+
base_ == nullptr &&
4249+
outfold != nullptr &&
4250+
strcmp(outfold, SEventConfig::_OutFoldDefault) != 0;
4251+
42454252
int64_t mode_save = SEventConfig::ModeSave();
4246-
if( mode_save == 0 )
4253+
if (base_ != nullptr)
4254+
{
4255+
base = base_;
4256+
}
4257+
else if (use_outfold)
4258+
{
4259+
// Honor explicit OutFold overrides from config/env for SEvt event folders.
4260+
base = outfold;
4261+
}
4262+
else if (mode_save == 0)
42474263
{
42484264
// controlled dir approach : good for campaigns
4249-
base = base_ ? base_ : spath::DefaultOutputDir() ;
4265+
base = spath::DefaultOutputDir();
42504266
}
42514267
else if( mode_save == 1 )
42524268
{
@@ -4462,8 +4478,8 @@ or the directory argument provided.
44624478
44634479
The FALLBACK_DIR which is used for the SEvt::DefaultDir is obtained from SEventConfig::OutFold
44644480
which is normally "$DefaultOutputDir" $TMP/GEOM/$GEOM/ExecutableName
4465-
This can be overriden using SEventConfig::SetOutFold or by setting the
4466-
envvar OPTICKS_OUT_FOLD.
4481+
This can be overridden using SEventConfig::SetOutFold or by setting the
4482+
envvar OPTICKS_OUT_FOLD, which are now honored directly by SEvt::DefaultBase.
44674483
44684484
It is normally much easier to use the default of "$DefaultOutputDir" as this
44694485
takes care of lots of the bookkeeping automatically.

tests/compare_ab.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
import argparse
12
import numpy as np
23

4+
from pathlib import Path
35
from optiphy.geant4_version import detect_geant4_version, geant4_series
46

57

@@ -13,11 +15,20 @@ def expected_diff_for_version(version):
1315
return EXPECTED_DIFF[geant4_series(version)]
1416

1517

18+
parser = argparse.ArgumentParser()
19+
parser.add_argument(
20+
"--base",
21+
default="/tmp",
22+
help="directory containing the ALL... event folders",
23+
)
24+
args = parser.parse_args()
25+
26+
base = Path(args.base)
1627
geant4_version = detect_geant4_version()
1728
expected_diff = expected_diff_for_version(geant4_version)
1829

19-
a = np.load("/tmp/fakeuser/opticks/GEOM/fakegeom/simg4ox/ALL0_no_opticks_event_name/A000/record.npy")
20-
b = np.load("/tmp/fakeuser/opticks/GEOM/fakegeom/simg4ox/ALL0_no_opticks_event_name/B000/f000/record.npy")
30+
a = np.load(base / "ALL0_no_opticks_event_name/A000/record.npy")
31+
b = np.load(base / "ALL0_no_opticks_event_name/B000/f000/record.npy")
2132

2233
print(a.shape)
2334
print(b.shape)

tests/test_GPUPhotonFileSource.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ cat > "$PHOTON_FILE" <<'EOF'
3131
EOF
3232

3333
echo "Running GPUPhotonFileSource with seed $SEED ..."
34-
OUTPUT=$(USER=fakeuser GEOM=fakegeom GPUPhotonFileSource \
34+
OUTPUT=$(GPUPhotonFileSource \
3535
-g "$OPTICKS_HOME/tests/geom/opticks_raindrop.gdml" \
3636
-p "$PHOTON_FILE" \
3737
-m "$OPTICKS_HOME/tests/run.mac" \
@@ -99,7 +99,7 @@ cat > "$PHOTON_FILE" <<'EOF'
9999
EOF
100100

101101
echo "Running GPUPhotonFileSource ..."
102-
OUTPUT=$(USER=fakeuser GEOM=fakegeom GPUPhotonFileSource \
102+
OUTPUT=$(GPUPhotonFileSource \
103103
-g "$OPTICKS_HOME/tests/geom/opticks_raindrop.gdml" \
104104
-p "$PHOTON_FILE" \
105105
-m "$OPTICKS_HOME/tests/run.mac" \

tests/test_GPUPhotonSource_8x8SiPM.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ echo "=== Test: GPUPhotonSource with 8x8SiPM_w_CSI_optial_grease.gdml ==="
4141
echo "Config: 1000 photons inside crystal at (-8.7, -8.7, 4.0)mm, 420nm, disc r=0.5mm"
4242
echo "Running GPUPhotonSource with seed $SEED ..."
4343

44-
OUTPUT=$(USER=fakeuser GEOM=fakegeom GPUPhotonSource \
44+
OUTPUT=$(GPUPhotonSource \
4545
-g "$OPTICKS_HOME/tests/geom/8x8SiPM_w_CSI_optial_grease.gdml" \
4646
-c 8x8SiPM_crystal \
4747
-m "$OPTICKS_HOME/tests/run.mac" \

0 commit comments

Comments
 (0)