This example macro takes all the known nuclei from the nuclear chart, and generates randomly a initial distribution of nuclei that are represented on a tkn::tknuclear_chart. The user can then simulate a time evolution that will make the nuclei decay corresponding to their main decay mode and lifetime.
This is not a perfect representation of the decay process, but just a simple view. For example, for a time evolution of 1 second, the program actually process 1000 successive decays of 1ms.
a fonction is already prepared to simulate the earth age time evolution using adapted time scales to have a global overview of the different decay steps.
#include "Riostream.h"
#include "TH2F.h"
#include "TROOT.h"
#include "TMath.h"
#include "TRandom3.h"
#include "TCanvas.h"
#include "TSystem.h"
#include "TLatex.h"
#include "TStyle.h"
#include <random>
#include "tkmanager.h"
#include "tknuclear_chart.h"
enum decay_types{kEF,kEP,kBN,kB2N,kB3N,kstable,kproton, kdiproton, kneutron, kdineutron, kalpha, kbeta_plus, kdouble_beta_plus, kdouble_beta_minus ,kbeta_minus, kfission, kunknown};
};
vector<nucleus> nucleus_list;
map<int, map<int, pair<int, nucleus>>> nuc_chart_mapping;
double felapsed_time=0;
void make_db()
{
if(tknuc_chart) return;
tknuc_chart =
new tknuclear_chart(
"Decay generator",tknuclear_chart::kAll,
true);
for(auto &nuc: gmanager->get_nuclei()) {
a_nuc.
name = nuc->get_symbol();
if(nuc->is_stable()) {
}
else {
tkstring decay = nuc->get_property(
"decay_modes");
if(token.size() == 0) decay = "";
else decay = token.front();
else {
if(decay.length()) cout<<
"unknown decay: " << decay <<
" " << a_nuc.
name<<endl;
}
}
nucleus_list.push_back(a_nuc);
nuc_chart_mapping[a_nuc.
z][a_nuc.
n] = make_pair(0,a_nuc);
}
}
void init(Int_t NEvents=1e6)
{
if(nucleus_list.empty()) make_db();
for(auto &z: nuc_chart_mapping) {
for(auto &n: z.second) {
n.second.first=0;
}
}
tknuc_chart->reset();
std::default_random_engine generator;
uniform_int_distribution<Int_t> dist(0,nucleus_list.size()-1);
for(Int_t inuc=0 ; inuc<NEvents ; inuc++) {
nucleus a_nuc = nucleus_list.at(dist(generator));
nuc_chart_mapping[a_nuc.
z][a_nuc.
n].first += 1;
tknuc_chart->fill(a_nuc.
z,a_nuc.
n);
}
tknuc_chart->set_title("T = 0");
tknuc_chart->draw();
felapsed_time=0.;
gSystem->Unlink("animation.gif");
tknuc_chart->save_as("animation.gif+");
}
void update_chart(int z, int n, int N) {
if(!(nuc_chart_mapping.count(z) && nuc_chart_mapping[z].count(n)) ) {
return;
}
nuc_chart_mapping[z][n].first += N;
tknuc_chart->set_value(z,n,nuc_chart_mapping[z][n].first);
}
void process_decay(double dt, bool save=false) {
if(tknuc_chart==nullptr) {
cout << "process first the init step to generate the T0 distribution" << endl;
return;
}
map<int, map<int, int>> decay_to_process;
for(auto &z: nuc_chart_mapping) {
for(auto &n: z.second) {
auto &pair = n.second;
if(pair.first==0) continue;
auto &a_nuc = pair.second;
double Ndecay_double = pair.first - pair.first * exp(-TMath::Log(2)*dt/a_nuc.
lifetime_in_sec);
int Ndecay = TMath::Nint(Ndecay_double);
if(Ndecay_double<1) {
if(gRandom->Uniform()<Ndecay_double) Ndecay=1;
}
decay_to_process[z.first][n.first] = Ndecay;
}
}
for(auto &z: decay_to_process) {
for(auto &n: z.second) {
auto &a_nuc = nuc_chart_mapping[z.first][n.first].second;
int Ndecay = n.second;
update_chart(a_nuc.
z,a_nuc.
n,-Ndecay);
cout<<"oups, a stable nucleus should not pass in this loop..."<<endl;
}
update_chart(a_nuc.
z-1,a_nuc.
n,Ndecay);
}
update_chart(a_nuc.
z-2,a_nuc.
n,Ndecay);
}
update_chart(a_nuc.
z,a_nuc.
n-1,Ndecay);
}
update_chart(a_nuc.
z,a_nuc.
n-2,Ndecay);
}
update_chart(a_nuc.
z-2,a_nuc.
n-2,Ndecay);
}
update_chart(a_nuc.
z-1,a_nuc.
n+1,Ndecay);
}
update_chart(a_nuc.
z-2,a_nuc.
n+1,Ndecay);
}
update_chart(a_nuc.
z-1,a_nuc.
n+1,Ndecay);
}
update_chart(a_nuc.
z+1,a_nuc.
n-1,Ndecay);
}
update_chart(a_nuc.
z+2,a_nuc.
n-2,Ndecay);
}
update_chart(a_nuc.
z+1,a_nuc.
n-2,Ndecay);
}
update_chart(a_nuc.
z+1,a_nuc.
n-3,Ndecay);
}
update_chart(a_nuc.
z+1,a_nuc.
n-4,Ndecay);
}
for(int i=0 ; i<Ndecay ; i++) {
while(true) {
int newz1 = TMath::Nint(gRandom->Uniform(a_nuc.
z/4,a_nuc.
z/2));
int newn1 = TMath::Nint(gRandom->Uniform(a_nuc.
n/4,a_nuc.
n/2));
int emitted_neutrons = TMath::Nint(gRandom->Uniform(2,7));
int newz2 = a_nuc.
z-newz1;
int newn2 = a_nuc.
n-newn1-emitted_neutrons;
if(!(nuc_chart_mapping.count(newz1) && nuc_chart_mapping[newz1].count(newn1)) || !(nuc_chart_mapping.count(newz2) && nuc_chart_mapping[newz2].count(newn2))) continue;
update_chart(newz1,newn1,1);
update_chart(newz2,newn2,1);
break;
}
}
}
}
else {
cout<<
"unknown decay for nucleus " << a_nuc.
name <<endl;
}
}
}
felapsed_time += dt;
if(save) {
if(felapsed_time<60) title += tkstring::form("%.1f sec",felapsed_time);
else if(felapsed_time<60*60) title += tkstring::form("%.1f min",felapsed_time/60);
else if(felapsed_time<60*60*24) title += tkstring::form("%.1f h",felapsed_time/60/60);
else if(felapsed_time<60*60*24*365) title += tkstring::form("%.1f days",felapsed_time/60/60/24);
else title += tkstring::form("%.1g years",felapsed_time/60/60/24/365);
tknuc_chart->set_title(title);
tknuc_chart->update();
tknuc_chart->save_as("animation.gif+");
gSystem->ProcessEvents();
}
}
void elapse_time_in_seconds(double _time, double dt=0., int nsave=5) {
if(tknuc_chart==nullptr) {
cout << "process first the init step to generate the T0 distribution" << endl;
return;
}
if(dt==0.) dt = _time/1000.;
int ndt=1;int save=(_time/dt)/nsave;
for(double i=dt ; i<_time ; i+=dt) {
if(ndt%save==0) process_decay(dt,true);
else process_decay(dt);
ndt++;
}
process_decay(dt,true);
}
void elapse_time_in_hours(double time, double dt=0.) {
time = time*3600.;
if(dt!=0.) dt = dt*3600.;
int nsave=4;
elapse_time_in_seconds(time,dt,nsave);
}
void elapse_time_in_days(double time, double dt=0.) {
time = time*3600.*24;
if(dt!=0.) dt = dt*3600.*24;
int nsave=2;
elapse_time_in_seconds(time,dt,nsave);
}
void elapse_time_in_years(double time, double dt=0.) {
time = time*3600.*24*365;
if(dt!=0.) dt = dt*3600.*24*365;
int nsave=1;
elapse_time_in_seconds(time,dt,nsave);
}
void decay_generator_animation() {
init(1e9);
elapse_time_in_seconds(1);
elapse_time_in_seconds(9);
elapse_time_in_seconds(20);
elapse_time_in_seconds(30);
elapse_time_in_seconds(60);
elapse_time_in_seconds(60*8);
elapse_time_in_seconds(60*20);
elapse_time_in_seconds(60*30);
elapse_time_in_hours(1);
elapse_time_in_hours(8);
elapse_time_in_hours(14);
elapse_time_in_days(1);
elapse_time_in_days(8);
elapse_time_in_days(40);
elapse_time_in_days(50);
elapse_time_in_days(100);
elapse_time_in_days(165);
elapse_time_in_years(1);
elapse_time_in_years(4);
elapse_time_in_years(5);
elapse_time_in_years(40);
elapse_time_in_years(50);
elapse_time_in_years(400);
elapse_time_in_years(500);
elapse_time_in_years(9000);
elapse_time_in_years(40000);
elapse_time_in_years(50000);
elapse_time_in_years(400000);
elapse_time_in_years(500000);
elapse_time_in_years(4e6);
elapse_time_in_years(5e6);
elapse_time_in_years(4e7);
elapse_time_in_years(5e7);
elapse_time_in_years(4e8);
elapse_time_in_years(5e8);
elapse_time_in_years(4e9);
tknuc_chart->save_as("animation.gif++");
}
nuclear chart plot with ROOT
std::string with usefull tricks from TString (ROOT) and KVString (KaliVeda) and more....
std::vector< tkstring > tokenize(const tkstring &_delim=" ") const
Create a vector of string separated by at least one delimiter.
bool begins_with(const char *_s, ECaseCompare _cmp=kExact) const
tkstring & replace_all(const tkstring &_s1, const tkstring &_s2)