45 baseSource(0), q_allowed(0), decays(0), activity(1), sCount(0) {
49 err = input->
getInput(
"charge", tmp_q);
51 if (std::find(q_allowed.begin(), q_allowed.end(), -1) != q_allowed.end()
52 && std::find(q_allowed.begin(), q_allowed.end(), 0) != q_allowed.end()
53 && std::find(q_allowed.begin(), q_allowed.end(), 1) != q_allowed.end()
54 && std::find(q_allowed.begin(), q_allowed.end(), 2) != q_allowed.end()
65 q_allowed.push_back(-1);
66 q_allowed.push_back(1);
67 q_allowed.push_back(0);
68 q_allowed.push_back(2);
76 EGS_Float spectrumWeightTotal = 0;
77 disintegrationOccurred =
true;
83 egsInformation(
"**********************************************\n");
85 decays.push_back(createSpectrum(input));
95 EGS_Float spectrumMaxE = decays[i]->maxEnergy();
96 if (spectrumMaxE > Emax) {
100 spectrumWeightTotal += decays[i]->getSpectrumWeight();
104 if (decays.size() < 1) {
105 egsFatal(
"\nEGS_RadionuclideSource: Error: No spectrum of type EGS_RadionuclideSpectrum was defined.\n");
109 for (i=0; i<decays.size(); ++i) {
110 decays[i]->setSpectrumWeight(
111 decays[i]->getSpectrumWeight() / spectrumWeightTotal);
114 decays[i]->setSpectrumWeight(
115 decays[i]->getSpectrumWeight() +
116 decays[i-1]->getSpectrumWeight());
122 err = input->
getInput(
"activity", tmp_A);
130 egsInformation(
"EGS_RadionuclideSource: Activity [disintegrations/s]: %e\n",
136 err = input->
getInput(
"experiment time", experimentTime);
141 if (experimentTime > 0.) {
142 egsInformation(
"EGS_RadionuclideSource: Experiment time [s]: %e\n",
146 egsInformation(
"EGS_RadionuclideSource: Experiment time will not limit the simulation.\n");
154 err = input->
getInput(
"source type",dummy);
155 int err2 = input->
getInput(
"geometry",dummy);
157 egsWarning(
"\nEGS_RadionuclideSource: Warning: Inputs for defining the radionuclide source as an isotropic or collimated source (e.g. 'source type') are deprecated. Please see the documentation - define the type of source separately and then refer to it using the new 'base source' input.\n");
161 err = input->
getInput(
"base source",sName);
163 egsFatal(
"\nEGS_RadionuclideSource: Error: Base source must be defined\n"
164 "using 'base source = some_name'\n");
168 egsFatal(
"\nEGS_RadionuclideSource: Error: no source named %s"
169 " is defined\n",sName.c_str());
179 static char spec_msg1[] =
"EGS_RadionuclideSource::createSpectrum:";
189 bool delete_it =
false;
190 if (!input->
isA(
"spectrum")) {
193 egsWarning(
"%s no 'spectrum' input!\n",spec_msg1);
199 egsInformation(
"EGS_RadionuclideSource::createSpectrum: Initializing radionuclide spectrum...\n");
202 int err = inp->
getInput(
"nuclide",nuclide);
204 err = inp->
getInput(
"isotope",nuclide);
206 err = inp->
getInput(
"radionuclide",nuclide);
208 egsWarning(
"%s wrong/missing 'nuclide' input\n",spec_msg1);
214 EGS_Float relativeActivity;
215 err = inp->
getInput(
"relative activity",relativeActivity);
217 relativeActivity = 1;
222 string tmp_relaxType, relaxType;
223 err = inp->
getInput(
"atomic relaxations", tmp_relaxType);
225 relaxType = tmp_relaxType;
230 if (inp->
compare(relaxType,
"ensdf")) {
232 egsInformation(
"EGS_RadionuclideSource::createSpectrum: Fluorescence and auger from the ensdf file will be used.\n");
234 else if (inp->
compare(relaxType,
"eadl")) {
236 egsInformation(
"EGS_RadionuclideSource::createSpectrum: Fluorescence and auger from the ensdf file will be ignored. EADL relaxations will be used.\n");
238 else if (inp->
compare(relaxType,
"none") || inp->
compare(relaxType,
"off") || inp->
compare(relaxType,
"no")) {
240 egsInformation(
"EGS_RadionuclideSource::createSpectrum: Fluorescence and auger from the ensdf file will be ignored. No relaxations following radionuclide disintegrations will be modelled.\n");
243 egsFatal(
"EGS_RadionuclideSource::createSpectrum: Error: Invalid selection for 'atomic relaxations'. Use 'eadl' (default), 'ensdf' or 'off'.\n");
248 string tmp_outputBetaSpectra, outputBetaSpectra;
249 err = inp->
getInput(
"output beta spectra", tmp_outputBetaSpectra);
251 outputBetaSpectra = tmp_outputBetaSpectra;
253 if (inp->
compare(outputBetaSpectra,
"yes")) {
254 egsInformation(
"EGS_RadionuclideSource::createSpectrum: Beta energy spectra will be output to files.\n");
256 else if (inp->
compare(outputBetaSpectra,
"no")) {
257 egsInformation(
"EGS_RadionuclideSource::createSpectrum: Beta energy spectra will not be output to files.\n");
260 egsFatal(
"EGS_RadionuclideSource::createSpectrum: Error: Invalid selection for 'output beta spectra'. Use 'no' (default) or 'yes'.\n");
264 outputBetaSpectra =
"no";
269 string tmp_alphaScoring;
270 bool scoreAlphasLocally =
false;
271 err = inp->
getInput(
"alpha scoring", tmp_alphaScoring);
273 if (inp->
compare(tmp_alphaScoring,
"local")) {
274 scoreAlphasLocally =
true;
275 egsInformation(
"EGS_RadionuclideSource::createSpectrum: Alpha particles will deposit energy locally, in the same region as creation.\n");
277 else if (inp->
compare(tmp_alphaScoring,
"discard")) {
278 scoreAlphasLocally =
false;
279 egsInformation(
"EGS_RadionuclideSource::createSpectrum: Alpha particles will be discarded (no transport or energy deposition).\n");
282 egsFatal(
"EGS_RadionuclideSource::createSpectrum: Error: Invalid selection for 'alpha scoring'. Use 'discard' (default) or 'local'.\n");
288 string tmp_allowMultiTransition;
289 bool allowMultiTransition =
false;
290 err = inp->
getInput(
"extra transition approximation", tmp_allowMultiTransition);
292 if (inp->
compare(tmp_allowMultiTransition,
"on")) {
293 allowMultiTransition =
true;
294 egsInformation(
"EGS_RadionuclideSource::createSpectrum: Extra transition approximation is on. If the intensity away from a level in a radionuclide daughter is larger than the intensity feeding the level (e.g. decays to that level), then additional transitions away from that level will be sampled. They will not be correlated with decays, but the spectrum will produce emission rates to match both the decay intensities and the internal transition intensities from the ensdf file.\n");
296 else if (inp->
compare(tmp_allowMultiTransition,
"off")) {
297 allowMultiTransition =
false;
298 egsInformation(
"EGS_RadionuclideSource::createSpectrum: Extra transition approximation is off.\n");
301 egsFatal(
"EGS_RadionuclideSource::createSpectrum: Error: Invalid selection for 'extra transition approximation'. Use 'off' (default) or 'on'.\n");
307 err = inp->
getInput(
"ensdf file",ensdf_file);
316 ensdf_file =
egsJoinPath(ensdf_file.c_str(),
"lnhb");
317 ensdf_file =
egsJoinPath(ensdf_file.c_str(),
"ensdf");
320 char *hen_house = getenv(
"HEN_HOUSE");
323 egsWarning(
"EGS_RadionuclideSource::createSpectrum: "
324 "No active application and HEN_HOUSE not defined.\n"
325 "Assuming local directory for spectra\n");
330 ensdf_file =
egsJoinPath(ensdf_file.c_str(),
"lnhb");
331 ensdf_file =
egsJoinPath(ensdf_file.c_str(),
"ensdf");
334 ensdf_file =
egsJoinPath(ensdf_file.c_str(),nuclide.append(
".txt"));
339 ensdf_fh.open(ensdf_file.c_str(),ios::in);
340 if (!ensdf_fh.is_open()) {
341 egsWarning(
"EGS_RadionuclideSource::createSpectrum: failed to open ensdf file %s"
342 " for reading\n",ensdf_file.c_str());
358 if (decays.size() > 1 && disintegrationOccurred) {
363 for (i=0; i<decays.size(); ++i) {
364 if (uRand < decays[i]->getSpectrumWeight()) {
371 if (experimentTime <= 0. || time < experimentTime) {
381 EGS_I64 ishowerOld = decays[i]->getShowerIndex();
383 E = decays[i]->sample(rndm);
385 EGS_I64 ishowerNew = decays[i]->getShowerIndex();
386 if (ishowerNew > ishowerOld) {
387 disintegrationOccurred =
true;
388 time = lastDisintTime + -log(1.-rndm->
getUniform()) / activity * (ishowerNew - ishowerOld);
390 lastDisintTime = time;
391 ishower += (ishowerNew - ishowerOld);
394 disintegrationOccurred =
false;
400 time += decays[i]->getTime();
403 q = decays[i]->getCharge();
404 int qTemp(q), latchTemp(latch);
410 if (disintegrationOccurred) {
411 xOfDisintegration = x;
414 x = xOfDisintegration;
420 EGS_Float edep = decays[i]->getEdep();
423 int ireg = app->isWhere(x);
428 if (q_allowAll || std::find(q_allowed.begin(), q_allowed.end(), q) != q_allowed.end()) {
446 void EGS_RadionuclideSource::setUp() {
447 otype =
"EGS_RadionuclideSource";
452 description =
"Radionuclide production in base source ";
456 if (std::find(q_allowed.begin(), q_allowed.end(), -1) !=
460 if (std::find(q_allowed.begin(), q_allowed.end(), 0) != q_allowed.end()) {
463 if (std::find(q_allowed.begin(), q_allowed.end(), 1) != q_allowed.end()) {
466 if (std::find(q_allowed.begin(), q_allowed.end(), 1) != q_allowed.end()) {
476 for (
unsigned int i=0; i<decays.size(); ++i) {
489 for (
unsigned int i=0; i<decays.size(); ++i) {
493 ishower += decays[i]->getShowerIndex();
506 for (
unsigned int i=0; i<decays.size(); ++i) {
507 decays[i]->resetCounter();
516 for (
unsigned int i=0; i<decays.size(); ++i) {
533 createSourceTemplate<EGS_RadionuclideSource>(input,f,
"radionuclide "
540 const EGS_Float relativeActivity,
const string relaxType,
const string outputBetaSpectra,
const bool scoreAlphasLocally,
const bool allowMultiTransition) {
550 decays =
new EGS_Ensdf(nuclide, ensdf_file, relaxType, allowMultiTransition, verbose);
553 decays->normalizeIntensities();
559 myBetas = decays->getBetaRecords();
560 myAlphas = decays->getAlphaRecords();
561 myGammas = decays->getGammaRecords();
562 myMetastableGammas = decays->getMetastableGammaRecords();
563 myUncorrelatedGammas = decays->getUncorrelatedGammaRecords();
564 myLevels = decays->getLevelRecords();
565 xrayIntensities = decays->getXRayIntensities();
566 xrayEnergies = decays->getXRayEnergies();
567 augerIntensities = decays->getAugerIntensities();
568 augerEnergies = decays->getAugerEnergies();
575 totalGammaEnergy = 0;
576 relaxationType = relaxType;
577 scoreAlphasLocal = scoreAlphasLocally;
580 for (vector<BetaRecordLeaf *>::iterator beta = myBetas.begin();
581 beta != myBetas.end(); beta++) {
583 double energy = (*beta)->getFinalEnergy();
588 for (vector<AlphaRecord *>::iterator alpha = myAlphas.begin();
589 alpha != myAlphas.end(); alpha++) {
591 double energy = (*alpha)->getFinalEnergy();
596 for (vector<GammaRecord *>::iterator gamma = myGammas.begin();
597 gamma != myGammas.end(); gamma++) {
599 double energy = (*gamma)->getDecayEnergy();
604 for (vector<GammaRecord *>::iterator gamma = myUncorrelatedGammas.begin();
605 gamma != myUncorrelatedGammas.end(); gamma++) {
607 double energy = (*gamma)->getDecayEnergy();
612 for (
unsigned int i=0; i < xrayEnergies.size(); ++i) {
613 numSampledXRay.push_back(0);
614 if (Emax < xrayEnergies[i]) {
615 Emax = xrayEnergies[i];
618 for (
unsigned int i=0; i < augerEnergies.size(); ++i) {
619 numSampledAuger.push_back(0);
620 if (Emax < augerEnergies[i]) {
621 Emax = augerEnergies[i];
626 spectrumWeight = relativeActivity;
630 egsInformation(
"EGS_RadionuclideSpectrum: Relative activity: %f\n",relativeActivity);
640 egsInformation(
"\nSampled %s emissions:\n", decays->radionuclide.c_str());
644 egsWarning(
"EGS_RadionuclideSpectrum::printSampledEmissions: Warning: The number of disintegrations (tracked by `ishower`) is less than 1.\n");
648 egsInformation(
"Energy | Intensity per 100 decays (adjusted by %f)\n", decays->decayDiscrepancy);
649 if (myBetas.size() > 0) {
652 for (vector<BetaRecordLeaf *>::iterator beta = myBetas.begin();
653 beta != myBetas.end(); beta++) {
656 ((EGS_Float)(*beta)->getNumSampled()/(ishower+1))*100);
658 if (myAlphas.size() > 0) {
661 for (vector<AlphaRecord *>::iterator alpha = myAlphas.begin();
662 alpha != myAlphas.end(); alpha++) {
665 ((EGS_Float)(*alpha)->getNumSampled()/(ishower+1))*100);
667 if (myGammas.size() > 0) {
670 EGS_I64 totalNumSampled = 0;
671 for (vector<GammaRecord *>::iterator gamma = myGammas.begin();
672 gamma != myGammas.end(); gamma++) {
674 totalNumSampled += (*gamma)->getGammaSampled();
676 ((EGS_Float)(*gamma)->getGammaSampled()/(ishower+1))*100,
677 ((EGS_Float)(*gamma)->getICSampled()/(ishower+1))*100,
678 ((EGS_Float)(*gamma)->getIPSampled()/(ishower+1))*100
681 if (myGammas.size() > 0) {
682 if (totalNumSampled > 0) {
684 totalGammaEnergy / totalNumSampled);
690 if (myUncorrelatedGammas.size() > 0) {
691 egsInformation(
"Uncorrelated gamma records (E,Igamma,Ice,Ipp):\n");
693 for (vector<GammaRecord *>::iterator gamma = myUncorrelatedGammas.begin();
694 gamma != myUncorrelatedGammas.end(); gamma++) {
697 ((EGS_Float)(*gamma)->getGammaSampled()/(ishower+1))*100,
698 ((EGS_Float)(*gamma)->getICSampled()/(ishower+1))*100,
699 ((EGS_Float)(*gamma)->getIPSampled()/(ishower+1))*100
702 if (xrayEnergies.size() > 0) {
705 for (
unsigned int i=0; i < xrayEnergies.size(); ++i) {
707 ((EGS_Float)numSampledXRay[i]/(ishower+1))*100);
709 if (augerEnergies.size() > 0) {
712 for (
unsigned int i=0; i < augerEnergies.size(); ++i) {
714 ((EGS_Float)numSampledAuger[i]/(ishower+1))*100);
733 if (relaxParticles.size() > 0) {
750 if (currentLevel && currentLevel->levelCanDecay() && currentLevel->getEnergy() >
epsilon) {
752 for (vector<GammaRecord *>::iterator gamma = myGammas.begin();
753 gamma != myGammas.end(); gamma++) {
755 if ((*gamma)->getLevelRecord() == currentLevel) {
757 if (u < (*gamma)->getTransitionIntensity()) {
762 if ((*gamma)->getGammaIntensity() < 1) {
769 double hl = currentLevel->getHalfLife();
771 currentTime = -hl * log(1.-rndm->
getUniform()) /
772 0.693147180559945309417232121458176568075500134360255254120680009493393;
776 if (rndm->
getUniform() < (*gamma)->getMultiTransitionProb()) {
777 multiTransitions.push_back(currentLevel);
781 currentLevel = (*gamma)->getFinalLevel();
784 if (u2 < (*gamma)->getGammaIntensity()) {
786 (*gamma)->incrGammaSampled();
788 currentQ = (*gamma)->getCharge();
790 E = (*gamma)->getDecayEnergy();
792 totalGammaEnergy += E;
799 else if (u2 < (*gamma)->getICIntensity()) {
800 (*gamma)->incrICSampled();
804 if ((*gamma)->icIntensity.size()) {
810 for (
unsigned int i=0; i<(*gamma)->icIntensity.size(); ++i) {
811 if (u3 < (*gamma)->icIntensity[i]) {
813 E = (*gamma)->getDecayEnergy() - (*gamma)->getBindingEnergy(i);
818 if (relaxationType ==
"eadl") {
822 (*gamma)->relax(i,app->getEcut()-app->getRM(),app->getPcut(),rndm,edep,relaxParticles);
833 (*gamma)->incrIPSampled();
859 if (multiTransitions.size() > 0) {
860 currentLevel = multiTransitions.back();
861 multiTransitions.pop_back();
871 for (vector<BetaRecordLeaf *>::iterator beta = myBetas.begin();
872 beta != myBetas.end(); beta++) {
873 if (u < (*beta)->getBetaIntensity()) {
879 (*beta)->incrNumSampled();
880 currentQ = (*beta)->getCharge();
883 currentLevel = (*beta)->getLevelRecord();
889 if ((*beta)->getPositronIntensity() >
epsilon && rndm->
getUniform() < (*beta)->getPositronIntensity()) {
894 if (relaxationType ==
"eadl" && (*beta)->ecShellIntensity.size()) {
899 for (
unsigned int i=0; i<(*beta)->ecShellIntensity.size(); ++i) {
900 if (u3 < (*beta)->ecShellIntensity[i]) {
904 (*beta)->relax(i,app->getEcut()-app->getRM(),app->getPcut(),rndm,edep,relaxParticles);
926 E = (*beta)->getSpectrum()->sample(rndm);
933 for (vector<AlphaRecord *>::iterator alpha = myAlphas.begin();
934 alpha != myAlphas.end(); alpha++) {
935 if (u < (*alpha)->getAlphaIntensity()) {
941 (*alpha)->incrNumSampled();
942 currentQ = (*alpha)->getCharge();
945 currentLevel = (*alpha)->getLevelRecord();
950 if (scoreAlphasLocal) {
951 edep += (*alpha)->getFinalEnergy();
963 for (vector<GammaRecord *>::iterator gamma = myMetastableGammas.begin();
964 gamma != myMetastableGammas.end(); gamma++) {
965 if (u < (*gamma)->getTransitionIntensity()) {
972 currentLevel = (*gamma)->getLevelRecord();
982 for (vector<GammaRecord *>::iterator gamma = myUncorrelatedGammas.begin();
983 gamma != myUncorrelatedGammas.end(); gamma++) {
984 if (u < (*gamma)->getTransitionIntensity()) {
989 if ((*gamma)->getGammaIntensity() < 1) {
994 if (u2 < (*gamma)->getGammaIntensity()) {
996 (*gamma)->incrGammaSampled();
998 currentQ = (*gamma)->getCharge();
1000 E = (*gamma)->getDecayEnergy();
1002 totalGammaEnergy += E;
1009 else if (u2 < (*gamma)->getICIntensity()) {
1010 (*gamma)->incrICSampled();
1014 if ((*gamma)->icIntensity.size()) {
1020 for (
unsigned int i=0; i<(*gamma)->icIntensity.size(); ++i) {
1021 if (u3 < (*gamma)->icIntensity[i]) {
1023 E = (*gamma)->getDecayEnergy() - (*gamma)->getBindingEnergy(i);
1026 if (relaxationType ==
"eadl") {
1030 (*gamma)->relax(i,app->getEcut()-app->getRM(),app->getPcut(),rndm,edep,relaxParticles);
1041 (*gamma)->incrIPSampled();
1060 for (
unsigned int i=0; i < xrayIntensities.size(); ++i) {
1061 if (u < xrayIntensities[i]) {
1063 numSampledXRay[i]++;
1066 E = xrayEnergies[i];
1075 for (
unsigned int i=0; i < augerIntensities.size(); ++i) {
1076 if (u < augerIntensities[i]) {
1078 numSampledAuger[i]++;
1081 E = augerEnergies[i];
Base class for advanced EGSnrc C++ applications.
static EGS_Application * activeApplication()
Get the active application.
int userScoring(int iarg, int ir=-1)
User scoring function for accumulation of results and VRT implementation.
const string & getHenHouse() const
Returns the HEN_HOUSE directory.
Base source class. All particle sources must be derived from this class.
virtual bool addState(istream &data_in)
Add data from the stream data_in to the source state.
const char * getSourceDescription() const
Get a short description of this source.
static EGS_BaseSource * getSource(const string &Name)
Get a pointer to the source named Name.
virtual void resetCounter()
Reset the source state.
string description
A short source description.
virtual EGS_I64 getNextParticle(EGS_RandomGenerator *rndm, int &q, int &latch, EGS_Float &E, EGS_Float &wt, EGS_Vector &x, EGS_Vector &u)=0
Sample the next source particle from the source probability distribution.
virtual bool setState(istream &data_in)
Set the source state based on data from the stream data_in.
virtual bool storeState(ostream &data_out) const
Store the source state into the stream data_out.
The ensdf class for reading ensdf format data files.
string otype
The object type.
Beta spectrum generation for EGS_RadionuclideSpectrum.
EGS_RadionuclideSource(EGS_Input *, EGS_ObjectFactory *f=0)
Constructor from input file.
bool setState(istream &data)
Set the source state according to the data in the stream data.
bool isValid() const
Checks the validity of the source.
bool storeState(ostream &data_out) const
Store the source state to the data stream data_out.
void resetCounter()
Reset the source to a state with zero sampled particles.
EGS_I64 getNextParticle(EGS_RandomGenerator *rndm, int &q, int &latch, EGS_Float &E, EGS_Float &wt, EGS_Vector &x, EGS_Vector &u)
Gets the next particle from the radionuclide spectra.
bool addState(istream &data)
Add the source state from the stream data to the current state.
EGS_I64 getShowerIndex() const
Returns the shower index of the most recent particle.
void printSampledEmissions()
Print the sampled emission intensities.
EGS_RadionuclideSpectrum(const string nuclide, const string ensdf_file, const EGS_Float relativeActivity, const string relaxType, const string outputBetaSpectra, const bool scoreAlphasLocally, const bool allowMultiTransition)
Construct a radionuclide spectrum.
EGS_Float sample(EGS_RandomGenerator *rndm)
Sample an event from the spectrum, returns the energy of the emitted particle.
Base random number generator class. All random number generators should be derived from this class.
EGS_Float getUniform()
Returns a random number uniformly distributed between zero (inclusive) and 1 (exclusive).
A class representing 3D vectors.
EGS_Application class header file.
Attempts to fix broken math header files.
bool EGS_EXPORT egsStoreI64(ostream &data, EGS_I64 n)
Writes the 64 bit integer n to the output stream data and returns true on success,...
EGS_InfoFunction EGS_EXPORT egsInformation
Always use this function for reporting the progress of a simulation and any other type of information...
EGS_InfoFunction EGS_EXPORT egsFatal
Always use this function for reporting fatal errors.
bool EGS_EXPORT egsGetI64(istream &data, EGS_I64 &n)
Reads a 64 bit integer from the stream data and assigns it to n. Returns true on success,...
const EGS_Float epsilon
The epsilon constant for floating point comparisons.
string egsJoinPath(const string &first, const string &second)
Join two path variables (or a path and a file name) using the platform specific directory separator a...
EGS_InfoFunction EGS_EXPORT egsWarning
Always use this function for reporting warnings.
int q
charge (0-photon, -1=electron)