33#include "G4SystemOfUnits.hh"
34#include "G4UnitsTable.hh"
45#include <G4NistManager.hh>
101 G4cout <<
"*******************************************" << G4endl
102 <<
"******* Parameters of the class RBE *******" << G4endl
103 <<
"*******************************************" << G4endl;
106 G4cout <<
"** RBE Dose threshold value: " <<
fDoseCut / gray <<
" gray" << G4endl;
107 G4cout <<
"** RBE Alpha X value: " <<
fAlphaX * gray <<
" 1/gray" << G4endl;
108 G4cout <<
"** RBE Beta X value: " <<
fBetaX * std::pow(gray, 2.0) <<
" 1/gray2" << G4endl;
109 G4cout <<
"*******************************************" << G4endl;
126 std::vector<G4String> result;
131 while (pos != G4String::npos) {
132 pos = line.find(delimiter, current);
133 G4String token = line.substr(current, pos - current);
138 result.push_back(token);
139 current = pos + delimiter.size();
148 std::ifstream in(path);
150 std::stringstream ss;
151 ss <<
"Cannot open LEM table input file: " << path;
152 G4Exception(
"RBE::LoadData",
"WrongTable", FatalException, ss.str().c_str());
157 if (!getline(in, line)) {
158 std::stringstream ss;
159 ss <<
"Cannot read header from the LEM table file: " << path;
160 G4Exception(
"RBE::LoadLEMTable",
"CannotReadHeader", FatalException, ss.str().c_str());
162 std::vector<G4String> header =
split(line,
",");
165 std::vector<G4String> columns = {
"alpha_x",
"beta_x",
"D_t",
"specific_energy",
166 "alpha",
"beta",
"cell",
"particle"};
167 std::map<G4String, int> columnIndices;
168 for (
auto columnName : columns) {
169 auto pos = find(header.begin(), header.end(), columnName);
170 if (pos == header.end()) {
171 std::stringstream ss;
172 ss <<
"Column " << columnName <<
" not present in the LEM table file.";
173 G4Exception(
"RBE::LoadLEMTable",
"ColumnNotPresent", FatalException, ss.str().c_str());
176 columnIndices[columnName] = distance(header.begin(), pos);
181 while (getline(in, line)) {
182 std::vector<G4String> lineParts =
split(line,
",");
183 G4String cellLine = lineParts[columnIndices[
"cell"]];
186 G4int element = man->FindOrBuildElement(lineParts[columnIndices[
"particle"]])->GetZasInt();
189 std::stod(lineParts[columnIndices[
"specific_energy"]]) * MeV);
190 fTablesAlpha[cellLine][element].push_back(stod(lineParts[columnIndices[
"alpha"]]));
194 fTablesBeta[cellLine][element].push_back(stod(lineParts[columnIndices[
"beta"]]));
196 fTablesAlphaX[cellLine] = stod(lineParts[columnIndices[
"alpha_x"]]) / gray;
197 fTablesBetaX[cellLine] = stod(lineParts[columnIndices[
"beta_x"]]) / (gray * gray);
198 fTablesDoseCut[cellLine] = stod(lineParts[columnIndices[
"D_t"]]) * gray;
204 for (
auto ePair : aPair.second) {
205 std::vector<G4double>& tableEnergy =
fTablesEnergy[aPair.first][ePair.first];
206 std::vector<G4double>& tableAlpha =
fTablesAlpha[aPair.first][ePair.first];
207 std::vector<G4double>& tableBeta =
fTablesBeta[aPair.first][ePair.first];
209 std::vector<size_t> idx(tableEnergy.size());
210 iota(idx.begin(), idx.end(), 0);
211 std::sort(idx.begin(), idx.end(),
212 [&tableEnergy](
size_t i1,
size_t i2) { return tableEnergy[i1] < tableEnergy[i2]; });
214 std::vector<std::vector<G4double>*> tables = {&tableEnergy, &tableAlpha, &tableBeta};
215 for (std::vector<G4double>* table : tables) {
216 std::vector<G4double> copy = *table;
217 for (
size_t i = 0; i < copy.size(); ++i) {
218 (*table)[i] = copy[idx[i]];
228 G4cout <<
"RBE: read LEM data for the following cell lines and elements [number of points]:"
231 G4cout <<
"- " << aPair.first <<
": ";
232 for (
auto ePair : aPair.second) {
233 G4cout << ePair.first <<
"[" << ePair.second.size() <<
"] ";
244 G4cout <<
"*************************" << G4endl <<
"*******SetCellLine*******" << G4endl
245 <<
"*************************" << G4endl;
247 G4Exception(
"RBE::SetCellLine",
"NoCellLine", FatalException,
248 "Cannot select cell line, probably LEM table not loaded yet?");
251 std::stringstream str;
252 str <<
"Cell line " << name <<
" not found in the LEM table.";
253 G4Exception(
"RBE::SetCellLine",
"", FatalException, str.str().c_str());
271 if (energyPair.first >
fMaxZ)
fMaxZ = energyPair.first;
274 fMaxEnergies[energyPair.first] = energyPair.second[energyPair.second.size() - 1];
281 G4cout <<
"RBE: cell line " << name <<
" selected." << G4endl;
290 G4Exception(
"RBE::GetHitAlphaAndBeta",
"NoCellLine", FatalException,
291 "No cell line selected. Please, do it using the /rbe/cellLine command.");
297 std::stringstream str;
298 str <<
"Alpha & beta calculation supported only for ";
299 str <<
fMinZ <<
" <= Z <= " <<
fMaxZ <<
", but " << Z <<
" requested.";
300 G4Exception(
"RBE::GetHitAlphaAndBeta",
"", JustWarning, str.str().c_str());
302 return std::make_tuple<G4double, G4double>(0.0, 0.0);
306 G4cout <<
"RBE hit: Z=" << Z <<
", E=" << E <<
" => out of LEM table";
312 return std::make_tuple<G4double, G4double>(0.0, 0.0);
315 std::vector<G4double>& vecEnergy = (*fActiveTableEnergy)[Z];
316 std::vector<G4double>& vecAlpha = (*fActiveTableAlpha)[Z];
317 std::vector<G4double>& vecBeta = (*fActiveTableBeta)[Z];
320 const auto eLarger = upper_bound(begin(vecEnergy), end(vecEnergy), E);
321 const G4int lower = distance(begin(vecEnergy), eLarger) - 1;
322 const G4int upper = lower + 1;
325 const G4double energyLower = vecEnergy[lower];
326 const G4double energyUpper = vecEnergy[upper];
327 const G4double energyFraction = (E - energyLower) / (energyUpper - energyLower);
330 const G4double alpha =
331 ((1 - energyFraction) * vecAlpha[lower] + energyFraction * vecAlpha[upper]);
332 const G4double beta = ((1 - energyFraction) * vecBeta[lower] + energyFraction * vecBeta[upper]);
334 G4cout <<
"RBE hit: Z=" << Z <<
", E=" << E <<
" => alpha=" << alpha <<
", beta=" << beta
338 return std::make_tuple(alpha, beta);
349 G4cout <<
"RBE::ComputeAlphaAndBeta() called but skipped as calculation not enabled"
356 G4cout <<
"RBE: Computing alpha and beta..." << G4endl;
383 G4cout <<
"RBE::ComputeRBE() called but skipped as calculation not enabled" << G4endl;
389 G4cout <<
"RBE: Computing survival and RBE..." << G4endl;
394 if (std::isnan(
fAlpha[i]) || std::isnan(
fBeta[i])) {
421 G4cout <<
"RBE::Compute() called but skipped as calculation not enabled" << G4endl;
444 G4Exception(
"RBE::Compute",
"RBEMissingDose", FatalException,
445 "Trying to compute RBE without knowing the dose. Please add a valid dose or "
446 "disable RBE calculation");
451 G4Exception(
"RBE::Compute",
"RBEDoseNotCalculated", JustWarning,
452 "Dose has not been calculated yet while computing RBE, that will be wrong."
453 " Please, first calculate dose");
463 G4cout <<
"RBE: Setting denominator..." << G4endl;
473 G4cout <<
"RBE: Adding denominator...";
480 G4cout <<
" (created empty array)";
492 G4cout <<
"RBE: Setting alpha numerator..." << G4endl;
502 G4cout <<
"RBE: Setting beta numerator..." << G4endl;
512 G4cout <<
"RBE: Adding alpha numerator...";
519 G4cout <<
" (created empty array)";
531 G4cout <<
"RBE: Adding beta numerator...";
538 G4cout <<
" (created empty array)";
552 G4cout <<
"RBE::StoreAlphaAndBeta() called but skipped as calculation not enabled" << G4endl;
559 G4cout <<
"RBE: Writing alpha and beta..." << G4endl;
561 std::ofstream ofs(AlphaBetaPath);
566 ofs << std::left << std::setw(
width) <<
"i" << std::setw(
width) <<
"j" << std::setw(
width)
567 <<
"k" << std::setw(
width) <<
"alpha" << std::setw(
width) <<
"beta " << G4endl;
573 for (G4int i = 0; i < voxSensDet->GetVoxelNumberAlongX(); i++)
574 for (G4int j = 0; j < voxSensDet->GetVoxelNumberAlongY(); j++)
575 for (G4int k = 0; k < voxSensDet->GetVoxelNumberAlongZ(); k++) {
576 G4int v = voxSensDet->GetThisVoxelNumber(i, j, k);
578 ofs << std::left << std::setw(
width) << i << std::setw(
width) << j << std::setw(
width)
580 << std::setw(
width) << (std::isnan(
fBeta[v]) ? 0 : (
fBeta[v] * std::pow(gray, 2.0)))
585 G4cout <<
"RBE: Alpha and beta written to " << AlphaBetaPath << G4endl;
596 G4cout <<
"RBE::StoreRBE() called but skipped as calculation not enabled" << G4endl;
603 G4Exception(
"RBE::StoreRBE",
"RBEOverwrite", JustWarning,
604 "Overwriting RBE file. For multiple runs, change filename.");
605 std::ofstream ofs(RBEPath);
610 ofs << std::left << std::setw(
width) <<
"i" << std::setw(
width) <<
"j" << std::setw(
width)
611 <<
"k" << std::setw(
width) <<
"Dose(Gy)" << std::setw(
width) <<
"ln(S) " << std::setw(
width)
612 <<
"Survival" << std::setw(
width) <<
"DoseB(Gy)" << std::setw(
width) <<
"RBE" << G4endl;
616 for (G4int i = 0; i < voxSensDet->GetVoxelNumberAlongX(); i++)
617 for (G4int j = 0; j < voxSensDet->GetVoxelNumberAlongY(); j++)
618 for (G4int k = 0; k < voxSensDet->GetVoxelNumberAlongZ(); k++) {
619 G4int v = voxSensDet->GetThisVoxelNumber(i, j, k);
621 ofs << std::left << std::setw(
width) << i << std::setw(
width) << j << std::setw(
width)
624 << std::setw(
width) << (std::isnan(
fRBE[v]) ? 0. :
fRBE[v]) << G4endl;
628 G4cout <<
"RBE: RBE written to " << RBEPath << G4endl;
639 G4cout <<
"RBE: Reset(): ";
Definition of the RadioBio::Dose class.
Definition of the RadioBio::Manager class.
Definition of the RadioBio::RBEAccumulable class.
Definition of the RadioBio::RBEMessenger class.
Definition of the RadioBio::RBE class.
Definition of the RadioBio::VoxelizedSensitiveDetector class.
array_type GetDose() const
VRadiobiologicalQuantity * GetQuantity(G4String)
static Manager * GetInstance()
Accumulable of RBE-related data (that must be thread-local).
const array_type GetDenominator() const
const array_type GetBetaNumerator() const
const array_type GetAlphaNumerator() const
vector_type * fActiveTableAlpha
vector_type * fActiveTableEnergy
void SetAlphaNumerator(const array_type alpha)
vector_type * fActiveTableBeta
array_type fBetaNumerator
std::map< G4String, vector_type > fTablesEnergy
array_type fAlphaNumerator
void AddFromAccumulable(G4VAccumulable *) override
void SetCellLine(G4String name)
void ComputeAlphaAndBeta()
std::map< G4int, G4double > fMaxEnergies
std::tuple< G4double, G4double > GetHitAlphaAndBeta(G4double E, G4int Z)
void PrintParameters() override
std::map< G4String, G4double > fTablesAlphaX
std::map< G4String, G4double > fTablesDoseCut
void AddDenominator(const array_type denom)
void SetDenominator(const array_type denom)
std::map< G4String, vector_type > fTablesAlpha
void LoadLEMTable(G4String path)
void AddAlphaNumerator(const array_type alpha)
void SetBetaNumerator(const array_type beta)
std::map< G4String, vector_type > fTablesBeta
std::map< G4String, G4double > fTablesBetaX
std::map< G4int, G4double > fMinEnergies
void AddBetaNumerator(const array_type beta)
void Initialize() override
void PrintVirtualParameters()
G4bool fCalculationEnabled
std::valarray< G4double > array_type
G4bool HasBeenCalculated() const
G4UImessenger * fMessenger
static VoxelizedSensitiveDetector * GetInstance()
Static method to retrieve a pointer to the only object existing in the simulation.
G4int GetTotalVoxelNumber() const
Method to get the total voxel number.
void strip(G4String &str, char ch=' ')
std::vector< G4String > split(const G4String &line, const G4String &delimiter)
Split string into parts using a delimiter.