14#include "tknuclear_chart.h"
19enum 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};
31vector<nucleus> nucleus_list;
33map<int, map<int, pair<int, nucleus>>> nuc_chart_mapping;
37double felapsed_time=0;
42 if(tknuc_chart)
return;
43 tknuc_chart =
new tknuclear_chart(
"Decay generator",tknuclear_chart::kAll,
true);
46 for(
auto &nuc: gmanager->get_nuclei()) {
48 a_nuc.
name = nuc->get_symbol();
49 a_nuc.
z = nuc->get_z();
50 a_nuc.
n = nuc->get_n();
51 if(nuc->is_stable()) {
59 tkstring decay = nuc->get_property(
"decay_modes");
61 if(token.size() == 0) decay =
"";
62 else decay = token.front();
81 if(decay.length()) cout<<
"unknown decay: " << decay <<
" " << a_nuc.
name<<endl;
84 nucleus_list.push_back(a_nuc);
85 nuc_chart_mapping[a_nuc.
z][a_nuc.
n] = make_pair(0,a_nuc);
90void init(Int_t NEvents=1e6)
92 if(nucleus_list.empty()) make_db();
95 for(
auto &z: nuc_chart_mapping) {
96 for(
auto &n: z.second) {
100 tknuc_chart->
reset();
102 std::default_random_engine generator;
103 uniform_int_distribution<Int_t> dist(0,nucleus_list.size()-1);
105 for(Int_t inuc=0 ; inuc<NEvents ; inuc++) {
106 nucleus a_nuc = nucleus_list.at(dist(generator));
107 nuc_chart_mapping[a_nuc.
z][a_nuc.
n].first += 1;
108 tknuc_chart->
fill(a_nuc.
z,a_nuc.
n);
115 gSystem->Unlink(
"animation.gif");
116 tknuc_chart->
save_as(
"animation.gif+");
120void update_chart(
int z,
int n,
int N) {
121 if(!(nuc_chart_mapping.count(z) && nuc_chart_mapping[z].count(n)) ) {
124 nuc_chart_mapping[z][n].first += N;
125 tknuc_chart->
set_value(z,n,nuc_chart_mapping[z][n].first);
129void process_decay(
double dt,
bool save=
false) {
131 if(tknuc_chart==
nullptr) {
132 cout <<
"process first the init step to generate the T0 distribution" << endl;
137 map<int, map<int, int>> decay_to_process;
138 for(
auto &z: nuc_chart_mapping) {
139 for(
auto &n: z.second) {
140 auto &pair = n.second;
141 if(pair.first==0)
continue;
142 auto &a_nuc = pair.second;
144 double Ndecay_double = pair.first - pair.first * exp(-TMath::Log(2)*dt/a_nuc.
lifetime_in_sec);
145 int Ndecay = TMath::Nint(Ndecay_double);
147 if(Ndecay_double<1) {
148 if(gRandom->Uniform()<Ndecay_double) Ndecay=1;
150 decay_to_process[z.first][n.first] = Ndecay;
153 for(
auto &z: decay_to_process) {
154 for(
auto &n: z.second) {
155 auto &a_nuc = nuc_chart_mapping[z.first][n.first].second;
156 int Ndecay = n.second;
157 update_chart(a_nuc.
z,a_nuc.
n,-Ndecay);
159 cout<<
"oups, a stable nucleus should not pass in this loop..."<<endl;
162 update_chart(a_nuc.
z-1,a_nuc.
n,Ndecay);
165 update_chart(a_nuc.
z-2,a_nuc.
n,Ndecay);
168 update_chart(a_nuc.
z,a_nuc.
n-1,Ndecay);
171 update_chart(a_nuc.
z,a_nuc.
n-2,Ndecay);
174 update_chart(a_nuc.
z-2,a_nuc.
n-2,Ndecay);
177 update_chart(a_nuc.
z-1,a_nuc.
n+1,Ndecay);
180 update_chart(a_nuc.
z-2,a_nuc.
n+1,Ndecay);
182 else if(a_nuc.
decay_type==kdouble_beta_plus) {
183 update_chart(a_nuc.
z-1,a_nuc.
n+1,Ndecay);
186 update_chart(a_nuc.
z+1,a_nuc.
n-1,Ndecay);
188 else if(a_nuc.
decay_type==kdouble_beta_minus) {
189 update_chart(a_nuc.
z+2,a_nuc.
n-2,Ndecay);
192 update_chart(a_nuc.
z+1,a_nuc.
n-2,Ndecay);
195 update_chart(a_nuc.
z+1,a_nuc.
n-3,Ndecay);
198 update_chart(a_nuc.
z+1,a_nuc.
n-4,Ndecay);
202 for(
int i=0 ; i<Ndecay ; i++) {
204 int newz1 = TMath::Nint(gRandom->Uniform(a_nuc.
z/4,a_nuc.
z/2));
205 int newn1 = TMath::Nint(gRandom->Uniform(a_nuc.
n/4,a_nuc.
n/2));
206 int emitted_neutrons = TMath::Nint(gRandom->Uniform(2,7));
207 int newz2 = a_nuc.
z-newz1;
209 int newn2 = a_nuc.
n-newn1-emitted_neutrons;
210 if(!(nuc_chart_mapping.count(newz1) && nuc_chart_mapping[newz1].count(newn1)) || !(nuc_chart_mapping.count(newz2) && nuc_chart_mapping[newz2].count(newn2)))
continue;
211 update_chart(newz1,newn1,1);
212 update_chart(newz2,newn2,1);
220 cout<<
"unknown decay for nucleus " << a_nuc.
name <<endl;
229 if(felapsed_time<60) title += tkstring::form(
"%.1f sec",felapsed_time);
230 else if(felapsed_time<60*60) title += tkstring::form(
"%.1f min",felapsed_time/60);
231 else if(felapsed_time<60*60*24) title += tkstring::form(
"%.1f h",felapsed_time/60/60);
232 else if(felapsed_time<60*60*24*365) title += tkstring::form(
"%.1f days",felapsed_time/60/60/24);
233 else title += tkstring::form(
"%.1g years",felapsed_time/60/60/24/365);
237 tknuc_chart->
save_as(
"animation.gif+");
239 gSystem->ProcessEvents();
244void elapse_time_in_seconds(
double _time,
double dt=0.,
int nsave=5) {
246 if(tknuc_chart==
nullptr) {
247 cout <<
"process first the init step to generate the T0 distribution" << endl;
251 if(dt==0.) dt = _time/1000.;
252 int ndt=1;
int save=(_time/dt)/nsave;
253 for(
double i=dt ; i<_time ; i+=dt) {
254 if(ndt%save==0) process_decay(dt,
true);
255 else process_decay(dt);
258 process_decay(dt,
true);
261void elapse_time_in_hours(
double time,
double dt=0.) {
264 if(dt!=0.) dt = dt*3600.;
266 elapse_time_in_seconds(time,dt,nsave);
269void elapse_time_in_days(
double time,
double dt=0.) {
271 time = time*3600.*24;
272 if(dt!=0.) dt = dt*3600.*24;
274 elapse_time_in_seconds(time,dt,nsave);
277void elapse_time_in_years(
double time,
double dt=0.) {
279 time = time*3600.*24*365;
280 if(dt!=0.) dt = dt*3600.*24*365;
282 elapse_time_in_seconds(time,dt,nsave);
286void decay_generator_animation() {
288 elapse_time_in_seconds(1);
289 elapse_time_in_seconds(9);
290 elapse_time_in_seconds(20);
291 elapse_time_in_seconds(30);
292 elapse_time_in_seconds(60);
293 elapse_time_in_seconds(60*8);
294 elapse_time_in_seconds(60*20);
295 elapse_time_in_seconds(60*30);
296 elapse_time_in_hours(1);
297 elapse_time_in_hours(8);
298 elapse_time_in_hours(14);
299 elapse_time_in_days(1);
300 elapse_time_in_days(8);
301 elapse_time_in_days(40);
302 elapse_time_in_days(50);
303 elapse_time_in_days(100);
304 elapse_time_in_days(165);
305 elapse_time_in_years(1);
306 elapse_time_in_years(4);
307 elapse_time_in_years(5);
308 elapse_time_in_years(40);
309 elapse_time_in_years(50);
310 elapse_time_in_years(400);
311 elapse_time_in_years(500);
312 elapse_time_in_years(9000);
313 elapse_time_in_years(40000);
314 elapse_time_in_years(50000);
315 elapse_time_in_years(400000);
316 elapse_time_in_years(500000);
317 elapse_time_in_years(4e6);
318 elapse_time_in_years(5e6);
319 elapse_time_in_years(4e7);
320 elapse_time_in_years(5e7);
321 elapse_time_in_years(4e8);
322 elapse_time_in_years(5e8);
323 elapse_time_in_years(4e9);
324 tknuc_chart->
save_as(
"animation.gif++");
nuclear chart plot with ROOT
void set_title(TString _title)
define the nuclear chart title
void fill(int _zz, int _nn, double _val)
fill the bin for a given nucleus (increment by _val)
void draw(bool _update_only=false)
draw the tknucleus chart
void save_as(const char *file_name)
save the nuclear chart in the file file_name
void set_value(int _zz, int _nn, double _val)
set the bin value for a given nucleus
void update()
update the tknucleus chart
void reset()
reset the tknuclear chart
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)