MUSIC unknown
Analysis for the MUSIC active-target ionization chamber
Loading...
Searching...
No Matches
main_talys_xs.cpp
Go to the documentation of this file.
1
21#include "BeamEnergies.hpp"
22#include "Constants.hpp"
23#include "InitUtils.hpp"
24#include "Paths.hpp"
25#include <TDirectory.h>
26#include <TFile.h>
27#include <TGraph.h>
28#include <TMath.h>
29#include <TNamed.h>
30#include <TString.h>
31#include <TSystem.h>
32#include <TSystemDirectory.h>
33#include <cmath>
34#include <cstdio>
35#include <cstdlib>
36#include <fstream>
37#include <iostream>
38#include <sstream>
39#include <string>
40#include <vector>
41
42#ifndef MUSIC_TALYS_BIN
43#define MUSIC_TALYS_BIN ""
44#endif
45#ifndef MUSIC_TALYS_ATOMKI_V2_DIR
46#define MUSIC_TALYS_ATOMKI_V2_DIR ""
47#endif
48
49namespace {
50
51// Grid step and the margin past the reported strips' energies. TALYS is
52// cheap at these energies, so the grid errs on the fine side.
53const Double_t kEcmStep = 0.25;
54const Double_t kEcmMargin = 1.0;
55
56// One TALYS residual-production file: E [MeV] and xs [mb] rows after the
57// YANDF header, with the lab energy converted back to centre-of-mass.
58TGraph *ReadResidual(const TString &path, Double_t cm_per_lab) {
59 std::ifstream in(path.Data());
60 if (!in)
61 return nullptr;
62 std::vector<Double_t> e, xs;
63 std::string line;
64 while (std::getline(in, line)) {
65 if (line.empty() || line[0] == '#')
66 continue;
67 std::istringstream ss(line);
68 Double_t el = 0.0, s = 0.0;
69 if (!(ss >> el >> s))
70 continue;
71 e.push_back(el * cm_per_lab);
72 xs.push_back(s);
73 }
74 if (e.empty())
75 return nullptr;
76 return new TGraph(Int_t(e.size()), &e[0], &xs[0]);
77}
78
79Bool_t WantsAtomkiV2(const TalysModel &model) {
80 for (Int_t k = 0; k < Int_t(model.keywords.size()); k++) {
81 std::istringstream ss(model.keywords[k].Data());
82 std::string key;
83 Int_t value = 0;
84 if ((ss >> key >> value) && key == "alphaomp" && value == 9)
85 return kTRUE;
86 }
87 return kFALSE;
88}
89
90void ClearWorkDir(const TString &work) {
91 TSystemDirectory sd("work", work);
92 TList *files = sd.GetListOfFiles();
93 if (!files)
94 return;
95 for (TIter it(files); TObject *o = it();) {
96 const TString name = o->GetName();
97 if (name.EndsWith(".tot") || name == "talys.out" ||
98 name == "alphaomp9real.gnu")
99 gSystem->Unlink(work + "/" + name);
100 }
101 delete files;
102}
103
104Bool_t TalysSucceeded(const TString &out_path) {
105 std::ifstream in(out_path.Data());
106 std::string line;
107 while (std::getline(in, line))
108 if (line.find("congratulates you with this successful calculation") !=
109 std::string::npos)
110 return kTRUE;
111 return kFALSE;
112}
113
114TString TalysErrorLine(const TString &out_path) {
115 std::ifstream in(out_path.Data());
116 std::string line;
117 while (std::getline(in, line))
118 if (line.find("TALYS-error") != std::string::npos)
119 return TString(line.c_str()).Strip(TString::kBoth);
120 return "no TALYS-error line found";
121}
122
123// Run one model in its own work directory and write its graphs into `dir`.
124// Returns the number of residual channels written, -1 on a TALYS failure.
125Int_t RunModel(const TalysModel &model, const TString &work,
126 const TString &talys, const TString &energies,
127 Double_t cm_per_lab, TDirectory *dir) {
128 const CrossSectionConfig &X = Constants::cfg.CROSS_SECTION_CONFIG;
129 gSystem->mkdir(work, kTRUE);
130 ClearWorkDir(work);
131 if (WantsAtomkiV2(model)) {
132 const Char_t *env = gSystem->Getenv("TALYS_ATOMKI_V2_DIR");
133 const TString pot_dir = (env && env[0] != '\0')
134 ? TString(env)
135 : TString(MUSIC_TALYS_ATOMKI_V2_DIR);
136 if (pot_dir.IsNull()) {
137 std::cerr << "talys-xs: " << model.label
138 << " needs alphaomp 9 but TALYS_ATOMKI_V2_DIR is not set"
139 << std::endl;
140 return -1;
141 }
142 const TString pot = pot_dir + Form("/z%03da%03da_talys_alphaomp9real.gnu",
143 X.BEAM_Z, X.BEAM_A);
144 if (gSystem->AccessPathName(pot, kReadPermission)) {
145 std::cerr << "talys-xs: no Atomki-V2 potential for Z=" << X.BEAM_Z
146 << " A=" << X.BEAM_A << " at " << pot << std::endl;
147 return -1;
148 }
149 if (gSystem->Symlink(pot, work + "/alphaomp9real.gnu") != 0) {
150 std::cerr << "talys-xs: cannot link " << pot << " into " << work
151 << std::endl;
152 return -1;
153 }
154 }
155 std::ostringstream input_ss;
156 input_ss << "# Written by talys-xs for " << Paths::DatasetName() << ": "
157 << model.label << std::endl;
158 input_ss << "projectile a" << std::endl;
159 input_ss << "element " << X.BEAM_ELEMENT << std::endl;
160 input_ss << Form("mass %d", X.BEAM_A) << std::endl;
161 input_ss << "energy energies" << std::endl;
162 // The shared settings first, then the model's own, which win where they
163 // repeat one (TALYS keeps the last value read).
164 if (!X.TALYS_COMMON_KEYWORDS.empty()) {
165 input_ss << "#" << std::endl;
166 input_ss << "# common settings (CROSS_SECTION_CONFIG.TALYS_COMMON_KEYWORDS)"
167 << std::endl;
168 }
169 for (Int_t k = 0; k < Int_t(X.TALYS_COMMON_KEYWORDS.size()); k++)
170 input_ss << X.TALYS_COMMON_KEYWORDS[k] << std::endl;
171 input_ss << "#" << std::endl;
172 input_ss << "# model: " << model.label << std::endl;
173 for (Int_t k = 0; k < Int_t(model.keywords.size()); k++)
174 input_ss << model.keywords[k] << std::endl;
175 const TString input = input_ss.str();
176 {
177 std::ofstream en((work + "/energies").Data());
178 en << energies;
179 std::ofstream inp((work + "/talys.inp").Data());
180 inp << input;
181 }
182 for (Int_t k = 0; k < Int_t(model.keywords.size()); k++)
183 std::cout << " " << model.keywords[k] << std::endl;
184 const TString cmd = Form("cd '%s' && '%s' < talys.inp > talys.out 2>&1",
185 work.Data(), talys.Data());
186 if (std::system(cmd.Data()) != 0 || !TalysSucceeded(work + "/talys.out")) {
187 std::cerr << "talys-xs: TALYS failed for " << model.label << ": "
188 << TalysErrorLine(work + "/talys.out") << "; see " << work
189 << "/talys.out" << std::endl;
190 return -1;
191 }
192
193 dir->cd();
194 TNamed("label", model.label.Data()).Write();
195 TNamed("input", input.Data()).Write();
196 Int_t n_graphs = 0;
197 TSystemDirectory sd("work", work);
198 TList *files = sd.GetListOfFiles();
199 for (TIter it(files); TObject *o = it();) {
200 const TString name = o->GetName();
201 Int_t z = 0, a = 0;
202 if (!name.EndsWith(".tot") || sscanf(name.Data(), "rp%3d%3d", &z, &a) != 2)
203 continue;
204 TGraph *g = ReadResidual(work + "/" + name, cm_per_lab);
205 if (!g)
206 continue;
207 g->SetName(Form("rp%03d%03d", z, a));
208 g->SetTitle(Form("Z=%d A=%d residual production;E_{c.m.} [MeV];#sigma "
209 "[mb]",
210 z, a));
211 g->Write();
212 delete g;
213 n_graphs++;
214 }
215 delete files;
216 return n_graphs;
217}
218
219} // namespace
220
221int main() {
222 InitUtils::SetROOTPreferences(PlotSaveFormat::kPNG,
223 Paths::ResultsDir() + "/plots",
224 Paths::ResultsDir() + "/root_files");
225 const CrossSectionConfig &X = Constants::cfg.CROSS_SECTION_CONFIG;
226 if (X.BEAM_A <= 0 || X.BEAM_Z <= 0 || X.BEAM_ELEMENT.IsNull() ||
227 X.BEAM_SIM_FILE.IsNull() || X.TALYS_MODELS.empty()) {
228 std::cerr << "talys-xs: this dataset's CROSS_SECTION_CONFIG needs BEAM_A, "
229 "BEAM_Z, BEAM_ELEMENT, BEAM_SIM_FILE and at least one "
230 "TALYS model"
231 << std::endl;
232 return 1;
233 }
234 const Char_t *env = gSystem->Getenv("TALYS_BIN");
235 TString talys = (env && env[0] != '\0') ? TString(env) : MUSIC_TALYS_BIN;
236 if (talys.IsNull())
237 talys = "talys";
238
239 // The grid spans the reported strips at their reported energies plus a
240 // margin and the reference table, so the curve is drawn under every point.
241 Double_t dE[18];
242 Double_t e_strip0 = 0.0;
243 if (!BeamEnergies::Profile(BeamEnergies::SimPath(), dE, e_strip0)) {
244 std::cerr << "talys-xs: cannot read the simulated beam at "
245 << BeamEnergies::SimPath() << std::endl;
246 return 1;
247 }
248 const Double_t cm_frac = BeamEnergies::CmFraction();
249 // TALYS runs the reaction the other way round, alpha on the beam nucleus,
250 // so its lab energy is E_cm * (A_b + A_t) / A_b.
251 const Double_t lab_per_cm =
252 Double_t(X.BEAM_A + TargetGasA(X.TARGET_GAS)) / Double_t(X.BEAM_A);
253 Double_t e_hi =
254 BeamEnergies::LabAtStrip(dE, e_strip0, X.XS_STRIP_MIN) * cm_frac +
255 kEcmMargin;
256 Double_t e_lo = TMath::Max(
257 kEcmStep, (BeamEnergies::LabAtStrip(dE, e_strip0, X.XS_STRIP_MAX) -
258 dE[X.XS_STRIP_MAX]) *
259 cm_frac -
260 kEcmMargin);
261 // ...widened to cover every channel's published table.
262 for (Int_t c = 0; c < Int_t(X.CHANNELS.size()); c++)
263 for (Int_t k = 0; k < Int_t(X.CHANNELS[c].reference_xs.size()); k++) {
264 e_lo = TMath::Min(e_lo, X.CHANNELS[c].reference_xs[k][0] - kEcmMargin);
265 e_hi = TMath::Max(e_hi, X.CHANNELS[c].reference_xs[k][0] + kEcmMargin);
266 }
267 const Double_t ecm_lo =
268 kEcmStep * std::floor(TMath::Max(kEcmStep, e_lo) / kEcmStep);
269 const Double_t ecm_hi = kEcmStep * std::ceil(e_hi / kEcmStep);
270 std::ostringstream energies_ss;
271 for (Double_t ecm = ecm_lo; ecm <= ecm_hi + 1.0e-9; ecm += kEcmStep)
272 energies_ss << Form("%.4f", ecm * lab_per_cm) << std::endl;
273 const TString energies = energies_ss.str();
274
275 // Everything TALYS touches lives under root_files/talys, which git
276 // ignores: one run per model under work/, the graphs beside them.
277 const TString talys_dir = Paths::ResultsDir() + "/root_files/talys";
278 const TString out_path = talys_dir + "/talys_xs.root";
279 gSystem->mkdir(talys_dir, kTRUE);
280 TFile out(out_path, "RECREATE");
281 if (out.IsZombie()) {
282 std::cerr << "talys-xs: cannot write " << out_path << std::endl;
283 return 1;
284 }
285 TNamed("talys", talys.Data()).Write();
286 std::cout << "talys-xs: alpha + " << X.BEAM_A << X.BEAM_ELEMENT << ", E_cm "
287 << ecm_lo << ".." << ecm_hi << " MeV (strips " << X.XS_STRIP_MIN
288 << ".." << X.XS_STRIP_MAX << "), " << X.TALYS_MODELS.size()
289 << " model(s), " << talys << std::endl;
290 for (Int_t m = 0; m < Int_t(X.TALYS_MODELS.size()); m++) {
291 const TalysModel &model = X.TALYS_MODELS[m];
292 std::cout << " m" << m << ": " << model.label << std::endl;
293 TDirectory *dir = out.mkdir(Form("m%d", m));
294 const Int_t n = RunModel(model, talys_dir + Form("/work/m%d", m), talys,
295 energies, 1.0 / lab_per_cm, dir);
296 if (n <= 0) {
297 if (n == 0)
298 std::cerr << "talys-xs: no residual-production files for "
299 << model.label << std::endl;
300 return 1;
301 }
302 std::cout << " " << n << " residual channels" << std::endl;
303 }
304 out.Close();
305 std::cout << "talys-xs: -> " << out_path << std::endl;
306 return 0;
307}
Dataset configuration.
Int_t TargetGasA(TargetGas gas)
Mass number of the target nucleus in a fill gas.
Definition Constants.cpp:3
static TString DatasetName()
The dataset's isotope name, e.g.
Definition Paths.cpp:22
static TString ResultsDir()
Absolute path to the directory receiving generated output.
Definition Paths.cpp:24
#define MUSIC_TALYS_ATOMKI_V2_DIR
#define MUSIC_TALYS_BIN
talys-xs: Hauser-Feshbach cross sections from TALYS for this dataset's reaction, written as ROOT grap...
int main()
Double_t LabAtStrip(const Double_t *dE, Double_t e_strip0, Int_t reac)
Lab energy entering a given strip.
Bool_t Profile(const TString &path, Double_t *dE, Double_t &e_strip0)
Read the per-strip energy loss profile from a beam simulation.
Double_t CmFraction()
Centre-of-mass energy fraction for this dataset's reaction.
TString SimPath()
Path to the dataset's beam simulation file.
const DatasetConfig & cfg
The active dataset's configuration, flat block.
Experimental details needed to properly calculate the cross section.
Int_t XS_STRIP_MIN
Reaction strips for which to calculate a cross-section.
TString BEAM_SIM_FILE
Simulated unreacted beam, read for the energy at each strip.
Int_t BEAM_A
Beam mass number, for the lab-to-centre-of-mass conversion; its Z and element symbol name it to a rea...
std::vector< TalysModel > TALYS_MODELS
Hauser-Feshbach predictions from TALYS.
std::vector< CrossSectionChannel > CHANNELS
The reaction channels measured on this dataset.
std::vector< TString > TALYS_COMMON_KEYWORDS
Input lines written into every model's TALYS input, after the projectile, target and energies and bef...
One TALYS model variant to compare against.
TString label
Legend label for this model's curve.
std::vector< TString > keywords
TALYS keywords selecting the variant.