GamR  0.0.0
GammaROOT
Loading...
Searching...
No Matches
CoulexCalculation.cc
Go to the documentation of this file.
1
8
9#include <iostream>
10#include <fstream>
11#include <cmath>
12#include <vector>
13#include <algorithm>
14#include <string>
15#include <complex>
16
17#include <angdist/AngDist.hh>
18#include <toolkit/Misc.hh>
19#include <utils/Utilities.hh>
20#include "Eloss.hh"
21#include "WDBSubs.hh"
22#include "Coulex.hh"
23#include "CoulexCalculation.hh"
24
25#define ANSI_COLOR_RED "\x1b[31m"
26#define ANSI_COLOR_GREEN "\x1b[32m"
27#define ANSI_COLOR_YELLOW "\x1b[33m"
28#define ANSI_COLOR_BLUE "\x1b[34m"
29#define ANSI_COLOR_MAGENTA "\x1b[35m"
30#define ANSI_COLOR_CYAN "\x1b[36m"
31#define ANSI_COLOR_RESET "\x1b[0m"
32
33namespace GamR {
34 namespace Coulex {
39 printf("Dimensions: " ANSI_COLOR_BLUE "%3.1f" ANSI_COLOR_RESET "x" ANSI_COLOR_BLUE "%3.1f " ANSI_COLOR_RESET "mm\n", fWidth, fHeight);
40 printf("Z = " ANSI_COLOR_BLUE "%5.2f" ANSI_COLOR_RESET " mm\n", fDistanceZ);
41 printf("R = " ANSI_COLOR_BLUE "%5.2f" ANSI_COLOR_RESET " mm\n", fDistanceR);
42 }
43
48 std::cout << " ________________________" << std::endl;
49 std::cout << "| Top-down view |" << std::endl;
50 std::cout << "| Euler angle a rotates |" << std::endl;
51 std::cout << "| particle detector. |" << std::endl;
52 std::cout << "| Euler angle b rotates |" << std::endl;
53 std::cout << "| gamma detector. |" << std::endl;
54 std::cout << "|________________________|" << std::endl;
55 std::cout << "| |" << std::endl;
56 std::cout << "|Beam Tgt stop|" << std::endl;
57 std::cout << "|=======|--------------[]|" << std::endl;
58 std::cout << "| < z >^ |" << std::endl;
59 std::cout << "| r |" << std::endl;
60 std::cout << "| v |" << std::endl;
61 std::cout << "| |\\y |" << std::endl;
62 std::cout << "| | \\ |" << std::endl;
63 std::cout << "| | | |" << std::endl;
64 std::cout << "| \\ |x |" << std::endl;
65 std::cout << "| \\| |" << std::endl;
66 std::cout << "|________________________|" << std::endl;
67 }
68
74 std::string Level::PrintSP() {
75 char out[10];
76 if (fParity) {
77 sprintf(out, "%5.1f+" , fSpin);
78 }
79 else {
80 sprintf(out, "%5.1f-", fSpin);
81 }
82 std::string sout(out);
83 return sout;
84 }
85
92 bool diff_parity = (fInitial->fParity == fFinal->fParity);
93 return ((pow(-1, fMult)==1)==diff_parity); //E is true, M is false
94 }
95
101 std::string Transition::Type() {
102 if (Character()) {
103 return "E"+std::to_string(fMult);
104 }
105 else {
106 return "M"+std::to_string(fMult);
107 }
108 }
109
111 for (auto &level : fLevels) {
112 if (level.second->fIndex==i) {
113 return level.second;
114 }
115 }
116 return NULL;
117 }
118
127 void LevelScheme::AddLevel(std::string name, float energy, float spin, bool parity) {
128 fLevels[name] = new Level(name, energy, spin, parity, 0);
129 fLevels[name]->fIndex = (int)fLevels.size()-1;
130 }
131
139 void LevelScheme::AddLevel(float energy, float spin, bool parity) {
140 std::string name = "l"+std::to_string((int)fLevels.size());
141 AddLevel(name, energy, spin, parity);
142 }
143
152 void LevelScheme::AddTransition(std::string initial, std::string final, float mat_el, float multipolarity) {
153 Level *init = fLevels[initial];
154 Level *fin = fLevels[final];
155 if (!init) {
156 std::cout << "Warning! Initial state does not exist!" << std::endl;
157 return;
158 }
159 if (!fin) {
160 std::cout << "Warning! Final state does not exist!" << std::endl;
161 return;
162 }
163
164 Transition* transition = new Transition(init, fin, mat_el, multipolarity);
165 fTransitions.push_back(transition);
166 }
167
172 std::vector<Level*> levels;
173 for (auto &level : fLevels) {
174 levels.push_back(level.second);
175 }
176
177 std::sort(levels.begin(), levels.end(),
178 [](const Level *a, const Level *b)
179 {
180 return *a < *b;
181 });
182
183 for (int i=0; i<(int)levels.size(); ++i) {
184 fLevels[levels[i]->fName]->fIndex = i;
185 }
186 }
187
193 void LevelScheme::PrintLevels(int loi/*=-1*/) {
194 SetIndices();
195 for (int i=0; i<(int)fLevels.size(); ++i) {
196 Level *level = GetLevelByIndex(i);
197 if (!level) { std::cout << "no level " << i << "?" << std::endl; }
198 if (level->fIndex == loi) { std::cout << ANSI_COLOR_GREEN; }
199 std::cout << level->fIndex << " " << level->PrintSP() << " " << level->fEnergy << std::endl;
200 std::cout << ANSI_COLOR_RESET ;
201 }
202 }
203
209 void LevelScheme::PrintTransitions(int toi/*=-1*/) {
210 SetIndices();
211 for (int i=0; i<(int)fTransitions.size(); ++i) {
212 Transition *transition = fTransitions[i];
213 if (i==toi) { std::cout << ANSI_COLOR_GREEN;}
214 std::cout << "Transition " << i << " from " <<
215 transition->fInitial->fIndex << " to " <<
216 transition->fFinal->fIndex << std::endl;
217 std::cout << "Energy : " << transition->Energy() << std::endl;
218 std::cout << "Type : " << transition->Type() << std::endl;
219 std::cout << "Reduced M.E. : " << transition->fMatEl << std::endl;
220 std::cout << ANSI_COLOR_RESET ;
221 }
222 }
223
230 void LevelScheme::Print(int loi/*=-1*/, int toi/*=-1*/) {
231 std::cout << "Levels: " << std::endl;
232 PrintLevels(loi);
233 std::cout << "Transitions: " << std::endl;
234 PrintTransitions(toi);
235 }
236
242 std::vector<WDB_nuclvl> LevelScheme::GetLevels() {
243 std::vector<Level*> levels;
244 for (auto &level : fLevels) {
245 levels.push_back(level.second);
246 }
247 std::sort(levels.begin(), levels.end(),
248 [](const Level *a, const Level *b)
249 {
250 return *a < *b;
251 });
252
253 std::vector<WDB_nuclvl> wdb_lvls;
254 for (int i=0; i<(int)levels.size(); ++i) {
255 WDB_nuclvl lvl;
256 lvl.spin = levels[i]->fSpin;
257 lvl.E = levels[i]->fEnergy;
258 lvl.par = levels[i]->fParity;
259 lvl.K_Band = levels[i]->fKBand;
260 wdb_lvls.push_back(lvl);
261 }
262 return wdb_lvls;
263 }
264
270 std::vector<WDB_nuctrans> LevelScheme::GetETransitions() {
271 std::vector<WDB_nuctrans> wdb_trans;
272 for (auto &transition : fTransitions) {
273 if (transition->Character()==true) {
274 WDB_nuctrans trans;
275 trans.lvl2 = transition->fInitial->fIndex+1;
276 trans.lvl1 = transition->fFinal->fIndex+1;
277 trans.B = transition->fMatEl;
278 trans.M = transition->fMult;
279 wdb_trans.push_back(trans);
280 }
281 }
282 return wdb_trans;
283 }
284
290 std::vector<WDB_nuctrans> LevelScheme::GetMTransitions() {
291 std::vector<WDB_nuctrans> wdb_trans;
292 for (auto &transition : fTransitions) {
293 if (transition->Character()==false) {
294 WDB_nuctrans trans;
295 trans.lvl2 = transition->fInitial->fIndex+1;
296 trans.lvl1 = transition->fFinal->fIndex+1;
297 trans.B = transition->fMatEl;
298 trans.M = transition->fMult;
299 wdb_trans.push_back(trans);
300 }
301 }
302 return wdb_trans;
303 }
304
309 std::cout << "Beam details: " << std::endl;
310 std::string inp;
311 int Z;
312 double A;
313 float energy = fBeamEnergy;
314 while (true) {
315 std::cout << "\tBeam nucleus [" << GamR::TK::GetElement(fBeam.Z, fBeam.A) << "]: ";
316 std::getline(std::cin,inp);
317 if (inp.empty()) { break; }
318 if(GamR::TK::GetZA(inp,Z,A)) {
319 std::cout << "\tInvalid nucleus. Ensure nucleus is in the format AEl, ElA or El-A e.g. 3He, Li5, C-13." << std::endl;
320 }
321 else {
322 fBeam.Z = Z;
323 if(A>0) fBeam.A = A;
324 else {
325 if(!SCOEFloaded) loadSCOEF();
326 if(!SCOEFloaded) fBeam.A = A;
327 else fBeam.A = Eldat[Z-1][1];
328 }
329 break;
330 }
331 }
332
333 GamR::Utils::GetInput("\tBeam energy in MeV", energy);
334 fBeamEnergy = energy;
335 }
336
341 std::cout << "Target details: " << std::endl;
342 std::string inp;
343 int Z;
344 double A;
345 while (true) {
346 std::cout << "\tTarget nucleus [" << GamR::TK::GetElement(fTarget.isotope.Z, fTarget.isotope.A) << "]: ";
347 std::getline(std::cin,inp);
348 if(inp.empty()) { break; }
349 if(GamR::TK::GetZA(inp,Z,A)) {
350 std::cout << "\tInvalid nucleus. Ensure nucleus is in the format AEl, ElA or El-A e.g. 3He, Li5, C-13." << std::endl;
351 }
352 else {
353 fTarget.isotope.Z = Z;
354 if(A>0) fTarget.isotope.A = A;
355 else {
356 if(!SCOEFloaded) loadSCOEF();
357 if(!SCOEFloaded) fTarget.isotope.A = A;
358 fTarget.isotope.A = Eldat[Z-1][2];
359 }
360 break;
361 }
362 }
363 float thickness = fTarget.thickness;
364 GamR::Utils::GetInput("\tTarget thickness in mg/cm2", thickness);
365 fTarget.thickness = thickness;
366
367 float density = fTarget.density;
368 GamR::Utils::GetInput("\tTarget density in g/cm3 (set 0 to get from SCOEF.DAT)", density, false);
369 fTarget.density = density;
370 }
371
376 std::cout << "Detection details: " << std::endl;
377 std::string inp;
378 while (true) {
379 std::cout << "\tProjectile(1) or target(2) detection [" << fDetected << "]: ";
380 std::getline(std::cin,inp);
381 if(inp.empty()) { break; }
382 switch(inp[0]) {
383 case '1':
385 break;
386 case '2':
388 break;
389 default:
390 continue;
391 }
393 }
394 }
395
400 std::cout << "Excitation details: " << std::endl;
401 std::string inp;
402 while (true) {
403 std::cout << "\tProjectile(1) or target(2) excitation [" << fExcited << "]: ";
404 std::getline(std::cin,inp);
405 if(inp.empty()) { break; }
406 switch(inp[0]) {
407 case '1':
409 break;
410 case '2':
412 break;
413 default:
414 continue;
415 }
417 }
418 }
419
424 std::cout << "Level scheme details: " << std::endl;
425 std::string inp;
426 int nstates = fLevelScheme.GetNLevels();
427 while (true) {
428 GamR::Utils::GetInput("\tTotal states including ground state", nstates);
429 if(nstates<2) {
430 std::cout << "\tInvalid entry. Must be >1." << std::endl;
431 continue;
432 }
433 break;
434 }
435
436 for(int i=0; i<nstates; i++) {
437 Level *state = fLevelScheme.GetLevelByIndex(i);
438 std::string sp;
439 float energy = 0.0;
440 bool parity = true;
441 float spin = 0.0;
442 if (state) {
443 energy = state->fEnergy;
444 parity = state->fParity;
445 spin = state->fSpin;
446 }
447
448 if (parity) { sp = std::to_string(spin) + "+"; }
449 else { sp = std::to_string(spin) + "-"; }
450
451 GamR::Utils::GetInput("\tState "+std::to_string(i)+" energy in MeV", energy);
452
453 while (true) {
454 std::cout << "\tState " << i << " spin and parity [" << sp << "]: ";
455 std::getline(std::cin,inp);
456 if(inp.empty()) { break; }
457 if(inp[inp.size()-1]=='+') parity = true;
458 else if(inp[inp.size()-1]=='-') parity = false;
459 else {
460 std::cout << "\tParity not specified. Please specify spin and parity e.g. 0.5+" << std::endl;
461 continue;
462 }
463 try { spin = std::stof(inp.substr(0,inp.size()-1)); }
464 catch(const std::invalid_argument& ia) {
465 std::cout << "\tInvalid entry. Must be numerical." << std::endl;
466 continue;
467 }
468 if(spin<0) {
469 std::cout << "\tInvalid entry. Must be >=0." << std::endl;
470 continue;
471 }
472 break;
473 }
474 if (!state) {
475 fLevelScheme.AddLevel(energy, spin, parity);
476 }
477 else {
478 state->fEnergy = energy;
479 state->fSpin = spin;
480 state->fParity = parity;
481 }
482 }
483
484 std::cout << std::endl;
485 std::cout << "Levels: " << std::endl;
486 fLevelScheme.PrintLevels();
487 std::cout << std::endl;
488
489 std::cout << "Transition details: " << std::endl;
490 int ntrans = fLevelScheme.GetNTransitions();
491
492 GamR::Utils::GetInput("\tTotal transitions between states", ntrans);
493
494 for(int i=0; i<ntrans; i++) {
495 Transition *transition = NULL;
496 int isi = 0;
497 int fsi = 0;
498 float bup = 0;
499 float mult = 0;
500 if (i < (int)fLevelScheme.fTransitions.size()) {
501 transition = fLevelScheme.fTransitions[i];
502 isi = transition->fInitial->fIndex;
503 fsi = transition->fFinal->fIndex;
504 bup = transition->GetBUp();
505 mult = transition->fMult;
506 }
507
508 GamR::Utils::GetInput("\tTransition "+std::to_string(i)+" lower state number", fsi);
509 GamR::Utils::GetInput("\tTransition "+std::to_string(i)+" upper state number", isi);
510
511 Level *initial = fLevelScheme.GetLevelByIndex(isi);
512 Level *final = fLevelScheme.GetLevelByIndex(fsi);
513
514 GamR::Utils::GetInput("\tTransition "+std::to_string(i)+" B up in eb", bup);
515 GamR::Utils::GetInput("\tTransition "+std::to_string(i)+" multipolarity", mult);
516
517 if (!transition) {
518 fLevelScheme.AddTransition(initial->fName, final->fName, 0, mult);
519 fLevelScheme.fTransitions[(int)fLevelScheme.fTransitions.size()-1]->SetBUp(bup);
520 }
521 else {
522 transition->fInitial = initial;
523 transition->fFinal = final;
524 transition->SetBUp(bup);
525 transition->fMult = mult;
526 }
527 }
528 }
529
534 std::cout << "State/transition of interest: " << std::endl;
535 std::string inp;
536 int loi = fLevelOfInterest;
537 GamR::Utils::GetInput("\tState of interest", loi);
538 fLevelOfInterest = loi;
539
540 int toi = fTransitionOfInterest;
541 GamR::Utils::GetInput("\tTransition of interest", toi);
543 }
544
546 DrawSetup();
547 std::cout << "Particle detector details:" << std::endl;
548 std::string inp;
549 float width = fParticleDetector.fWidth;
550 float height = fParticleDetector.fHeight;
551 float z = fParticleDetector.fDistanceZ;
552 float r = fParticleDetector.fDistanceR;
553
554 GamR::Utils::GetInput("\tDetector width x in mm", width);
555 fParticleDetector.fWidth = width;
556 GamR::Utils::GetInput("\tDetector height y in mm", height);
557 fParticleDetector.fHeight = height;
558 GamR::Utils::GetInput("\tHorizontal distance from target to detector z in mm", z, false);
559 fParticleDetector.fDistanceZ = z;
560 GamR::Utils::GetInput("\tRadial distance from the centre to detector edge r in mm", r, false);
561 fParticleDetector.fDistanceR = r;
562 }
563
570 int CoulexCalculation::ReadFromFile(std::string file_name /*= "Wtheta.ans"*/) {
571 std::ifstream ansfile;
572 ansfile.open(file_name.c_str());
573 if(ansfile.fail()) {
574 std::cout << "Could not open answer file " << file_name << std::endl;
575 }
576 std::string ans;
577 ans = GamR::Utils::getline(ansfile);
578
579
580 //Beam details
581
582 //isotope
583 int Z;
584 double A;
585 if(GamR::TK::GetZA(ans,Z,A)) {
586 std::cout << "\tInvalid beam nucleus. Ensure nucleus is in the format AEl, ElA or El-A e.g. 3He, Li-5." << std::endl;
587 return -1;
588 }
589 fBeam.Z = Z;
590 if(A>0) fBeam.A = A;
591 else {
592 if(!SCOEFloaded) loadSCOEF();
593 if(!SCOEFloaded) fBeam.A = A;
594 fBeam.A = Eldat[Z-1][1];
595 }
596
597 //energy
598 float energy;
599 ans = GamR::Utils::getline(ansfile);
600 if (GamR::Utils::catcherr(ans, energy)) {
601 std::cout << "\tInvalid beam energy" << std::endl;
602 return -2;
603 }
604 fBeamEnergy = energy;
605
606 //Target details
607 //isotope
608 ans = GamR::Utils::getline(ansfile);
609 if(GamR::TK::GetZA(ans,Z,A)) {
610 std::cout << "\tInvalid taget nucleus. Ensure nucleus is in the format AEl, ElA or El-A e.g. 3He, Li-5." << std::endl;
611 return -3;
612 }
613 fTarget.isotope.Z = Z;
614 if(A>0) fTarget.isotope.A = A;
615 else {
616 if(!SCOEFloaded) loadSCOEF();
617 if(!SCOEFloaded) fTarget.isotope.A = A;
618 fTarget.isotope.A = Eldat[Z-1][2];
619 }
620
621 //thickness
622 float thickness;
623 ans = GamR::Utils::getline(ansfile);
624 if(GamR::Utils::catcherr(ans, thickness)) {
625 std::cout << "\tInvalid target thickness" << std::endl;
626 return -4;
627 }
628 fTarget.thickness = thickness;
629
630 //density
631 float density;
632 ans = GamR::Utils::getline(ansfile);
633 if(GamR::Utils::catcherr(ans, density, false)) {
634 std::cout << "\tInvalid target density" << std::endl;
635 return -5;
636 }
637 fTarget.density = density;
638
639 //species
640 ans = GamR::Utils::getline(ansfile);
641 switch(ans[0]) {
642 case '1':
644 break;
645 case '2':
647 break;
648 default:
649 std::cout << "\tInvalid projectile(1) or target(2) excitation" << std::endl;
650 return -6;
651 }
652
653 ans = GamR::Utils::getline(ansfile);
654 switch(ans[0]) {
655 case '1':
657 break;
658 case '2':
660 break;
661 default:
662 std::cout << "\tInvalid projectile(1) or target(2) detection" << std::endl;
663 return -7;
664 }
665
666 ans = GamR::Utils::getline(ansfile);
667 int pread = 0;
668 if(!ans.empty()) pread = std::stoi(ans);
669
670 int nstates = 0;
671 if (GamR::Utils::catcherr(ans, nstates)) {
672 std::cout << "\nInvalid number of states" << std::endl;
673 return -8;
674 }
675
676 if (nstates < 2) {
677 std::cout << "\nInvalid number of states" << std::endl;
678 return -9;
679 }
680
681 for (int i=0; i<nstates; ++i) {
682 //energy
683 if (pread) ans = GamR::Utils::getline(ansfile);
684 float energy;
685 try { energy = stof(ans); }
686 catch(const std::invalid_argument& ia) {
687 std::cout << "Invalid state energy. Must be numerical." << std::endl;
688 return -10;
689 }
690 if(energy<0) {
691 std::cout << "Invalid state energy. Must be >=0." << std::endl;
692 return -11;
693 }
694
695 //spin and parity
696 float spin;
697 bool parity;
698 if(pread) {
699 ans = GamR::Utils::getline(ansfile);
700 pread--;
701 }
702 if(ans[ans.size()-1]=='+') parity = true;
703 else if(ans[ans.size()-1]=='-') parity = false;
704 else {
705 std::cout << "\tState parity not specified. " << std::endl;
706 return -12;
707 }
708 try { spin = std::stof(ans.substr(0,ans.size()-1)); }
709 catch(const std::invalid_argument& ia) {
710 std::cout << "\tState spin invalid. Must be numerical." << std::endl;
711 return -13;
712 }
713 if(spin<0) {
714 std::cout << "\tState spin invalid. Invalid entry. Must be >=0." << std::endl;
715 return -14;
716 }
717
718 fLevelScheme.AddLevel(energy, spin, parity);
719 }
720
721 if(pread) {
722 for(int i=0; i<pread; i++) {
723 ans = GamR::Utils::getline(ansfile);
724 ans = GamR::Utils::getline(ansfile);
725 }
726 }
727
728 //level of interest
729 ans = GamR::Utils::getline(ansfile);
730 int loi = 0;
731 if(GamR::Utils::catcherr(ans, loi)) {
732 std::cout << "\tInvalid level of interest" << std::endl;
733 return -15;
734 }
735 fLevelOfInterest = loi-1;
736
737 //transitions
738 int ntrans;
739 ans = GamR::Utils::getline(ansfile);
740 if(!ans.empty()) pread = std::stoi(ans);
741 else pread = 0;
742
743 if(GamR::Utils::catcherr(ans,ntrans)) {
744 std::cout << "\tInvalid number of transitions" << std::endl;
745 return -16;
746 }
747
748 for (int i=0; i<ntrans; ++i) {
749 int i1, i2;
750 float bup, mult;
751 if(pread) ans = GamR::Utils::getline(ansfile);
752 if(GamR::Utils::catcherr(ans, i1)) {
753 std::cout << "\tInvalid lower state index" << std::endl;
754 return -17;
755 }
756
757 if(pread) ans = GamR::Utils::getline(ansfile);
758 if(GamR::Utils::catcherr(ans, i2)) {
759 std::cout << "\tInvalid upper state index" << std::endl;
760 return -18;
761 }
762
763 if(pread) ans = GamR::Utils::getline(ansfile);
764 if(GamR::Utils::catcherr(ans, bup)) {
765 std::cout << "\tInvalid transition strength" << std::endl;
766 return -19;
767 }
768
769 if(pread) {
770 ans = GamR::Utils::getline(ansfile);
771 pread--;
772 }
773 if(GamR::Utils::catcherr(ans, mult)) {
774 std::cout << "\tInvalid transition multiplicity" << std::endl;
775 return -20;
776 }
777
778 fLevelScheme.AddTransition("l"+std::to_string(i2-1),
779 "l"+std::to_string(i1-1),
780 0,
781 mult);
782 fLevelScheme.fTransitions[(int)fLevelScheme.fTransitions.size()-1]->SetBUp(bup);
783 }
784
785 if(pread) {
786 for(int i=0; i<pread; i++) {
787 ans = GamR::Utils::getline(ansfile);
788 ans = GamR::Utils::getline(ansfile);
789 ans = GamR::Utils::getline(ansfile);
790 ans = GamR::Utils::getline(ansfile);
791 }
792 }
793
794 //transition of interest
795 int toi;
796 ans = GamR::Utils::getline(ansfile);
797 if(GamR::Utils::catcherr(ans, toi)) {
798 std::cout << "\tInvalid transition of interest" << std::endl;
799 return -21;
800 }
801 fTransitionOfInterest = toi-1;
802
803 //particle detector
804 float pdetx, pdety, pdetz, pdetr;
805 ans = GamR::Utils::getline(ansfile);
806 if(GamR::Utils::catcherr(ans, pdetx)) {
807 std::cout << "\tInvalid particle detector X" << std::endl;
808 return -22;
809 }
810
811 ans = GamR::Utils::getline(ansfile);
812 if(GamR::Utils::catcherr(ans, pdety)) {
813 std::cout << "\tInvalid particle detector Y" << std::endl;
814 return -23;
815 }
816
817 ans = GamR::Utils::getline(ansfile);
818 try { pdetz = stof(ans); }
819 catch(const std::invalid_argument& ia) {
820 std::cout << "\tInvalid particle detector Z distance. Must be numerical." << std::endl;
821 return -24;
822 }
823 if(!pdetz) {
824 std::cout << "\tInvalid particle detector Z distance. Must be non-zero." << std::endl;
825 return -25;
826 }
827
828 ans = GamR::Utils::getline(ansfile);
829 try { pdetr = stof(ans); }
830 catch(const std::invalid_argument& ia) {
831 std::cout << "\tInvalid particle detector R distance. Must be numerical." << std::endl;
832 return -26;
833 }
834 fParticleDetector.fWidth = pdetx;
835 fParticleDetector.fHeight = pdety;
836 fParticleDetector.fDistanceZ = pdetz;
837 fParticleDetector.fDistanceR = pdetr;
838
839 fLevelScheme.SetIndices();
840
841 return 0;
842 }
843
849 void CoulexCalculation::SaveToFile(std::string file_name) {
850 std::ofstream ansout;
851 ansout.open(file_name.c_str());
852 ansout << GamR::TK::GetElement(fBeam.Z, fBeam.A) << std::endl;
853 ansout << fBeamEnergy << std::endl;
854 ansout << GamR::TK::GetElement(fTarget.isotope.Z, fTarget.isotope.A) << std::endl;
855 ansout << fTarget.thickness << std::endl;
856 ansout << fTarget.density << std::endl;
857 int Ex = 1;
858 int Det = 1;
859 if (fExcited==Species::kTarget) { Ex = 2; }
860 if (fDetected==Species::kTarget) { Det = 2; }
861 ansout << Ex << std::endl;
862 ansout << Det << std::endl;
863 ansout << fLevelScheme.GetNLevels() << std::endl;
864 fLevelScheme.SetIndices();
865 for (int i=0; i<fLevelScheme.GetNLevels(); ++i) {
866 Level *level = fLevelScheme.GetLevelByIndex(i);
867 ansout << level->fEnergy << std::endl;
868 ansout << level->PrintSP() << std::endl;
869 }
870 ansout << fLevelOfInterest+1 << std::endl;
871 ansout << fLevelScheme.GetNTransitions() << std::endl;
872 for (int i=0; i<fLevelScheme.GetNTransitions(); ++i) {
873 Transition *trans = fLevelScheme.fTransitions[i];
874 ansout << trans->fFinal->fIndex+1 << std::endl;
875 ansout << trans->fInitial->fIndex+1 << std::endl;
876 ansout << trans->GetBUp() << std::endl;
877 ansout << trans->fMult << std::endl;
878 }
879 ansout << fTransitionOfInterest+1 << std::endl;
880 ansout << fParticleDetector.fWidth << std::endl;
881 ansout << fParticleDetector.fHeight << std::endl;
882 ansout << fParticleDetector.fDistanceZ << std::endl;
883 ansout << fParticleDetector.fDistanceR << std::endl;
884 ansout.close();
885 }
886
899
904 std::cout << "=====================================================" << std::endl;
905 std::cout << " COULEX CALCULATION PARAMETERS " << std::endl;
906 std::cout << "=====================================================" << std::endl;
907 printf("Beam: " ANSI_COLOR_BLUE "%s" ANSI_COLOR_RESET ", " ANSI_COLOR_BLUE "%4.1f" ANSI_COLOR_RESET " MeV\n", GamR::TK::GetElement(fBeam.Z, fBeam.A).c_str(), fBeamEnergy);
908 printf("Target: " ANSI_COLOR_BLUE "%s" ANSI_COLOR_RESET "\n", GamR::TK::GetElement(fTarget.isotope.Z, fTarget.isotope.A).c_str());
909 printf(" thickness = " ANSI_COLOR_BLUE "%5.2f" ANSI_COLOR_RESET " mg/cm^2\n", fTarget.thickness);
910 printf(" density = " ANSI_COLOR_BLUE "%5.2f" ANSI_COLOR_RESET " g/cm^3\n", fTarget.density);
912 printf( ANSI_COLOR_BLUE "Target" ANSI_COLOR_RESET " excitation, ");
913 }
914 else {
915 printf( ANSI_COLOR_BLUE "Projectile" ANSI_COLOR_RESET " excitation, ");
916 }
917
919 printf("detecting the " ANSI_COLOR_BLUE "target" ANSI_COLOR_RESET "\n");
920 }
921 else {
922 printf("detecting the " ANSI_COLOR_BLUE "projectile" ANSI_COLOR_RESET "\n");
923 }
924 std::cout << std::endl;
925 std::cout << "Level Scheme: " << std::endl;
927 std::cout << std::endl;
928 std::cout << "Particle Detector: " << std::endl;
929 fParticleDetector.Print();
930 std::cout << "=====================================================" << std::endl;
931
932 }
933
940 bool ProjDet = false;
941 bool TgtEx = false;
942 std::vector<WDB_nuclvl> levels = fLevelScheme.GetLevels();
943 std::vector<WDB_nuctrans> Etrans = fLevelScheme.GetETransitions();
944 std::vector<WDB_nuctrans> Mtrans = fLevelScheme.GetMTransitions();
945 double Q = -levels[fLevelOfInterest].E; // Used in reaction kinematics, should be equal to the negative energy of the level of interest (state populated by coulex).
946
947 if (fDetected==Species::kProjectile) { ProjDet = true; }
948 if (fExcited==Species::kTarget) { TgtEx = true; }
949
950 bool failbit = false; // Keep track of whether a component of the routine has failed and return nullptr if it has after memory cleanup
951
952 if(fBeam.A==0) {
953 if(!SCOEFloaded) loadSCOEF();
954 if(SCOEFloaded) fBeam.A = Eldat[fBeam.Z-1][1];
955 }
956 if(fTarget.isotope.A==0) {
957 if(!SCOEFloaded) loadSCOEF();
958 if(SCOEFloaded) fTarget.isotope.A = Eldat[fTarget.isotope.Z-1][2];
959 }
960 int grouptype = int(TgtEx) + 1;
961 int flag = setupcoulex(fBeam.Z, fBeam.A, fTarget.isotope.Z, fTarget.isotope.A, grouptype, levels, Etrans, Mtrans);
962 // Check the setupcoulex routine was successful and post relevant errors
963 switch(flag)
964 {
965 case 1:
966 std::cerr << "CRITICAL Could not create data file for coulex routine. Ensure you have write access to the working directory." << std::endl;
967 return nullptr;
968 case 2:
969 std::cerr << "CRITICAL There was a problem reading the coulex data file. Please check you have read access to the working directory, and your inputs for the data file." << std::endl;
970 return nullptr;
971 case 3:
972 std::cout << "NON-CRITICAL Could not remove the coulex routine data file. You may need to manually remove the file or it may already have been deleted." << std::endl;
973 }
974
975 // set stored cross sections to zero
976 for (auto &mlevel: fLevelScheme.fLevels) {
977 auto key = mlevel.first;
978 auto level = mlevel.second;
979 level->fCrossSection=0;
980 }
981 GamR::AngDist::StatTensor *retST = new GamR::AngDist::StatTensor(levels[fLevelOfInterest].spin); // The GamR library stat tensor to return
982
983 for (auto &mlevel: fLevelScheme.fLevels) {
984 auto key = mlevel.first;
985 auto level = mlevel.second;
986
987 // Setup memory for stat tensors and cross-sections from coulex routine, calculate and get values.
988 // Memory is delcared to 11 due to Simpson's rule integration requirement (n = 10 equal cuts = 11 values)
989 float xsect; // To get cross-section from coulex routine. Coulex routine uses floats and this is passed by reference.
990 double *sfctrx = new double[11]; // Scaling factor for each x piece involving the cross-section and solid angle.
991 double *sfctry = new double[11]; // Scaling factor for each y strip (x integral).
992 double *sfctrz = new double[11]; // Scaling factor for each z plane (xy integral).
993 double sfctr; // Integral scaling factor.
994 std::complex<double> ***rhox = new std::complex<double>**[11]; // Stat tensors for each x piece.
995 std::complex<double> ***rhoy = new std::complex<double>**[11]; // Stat tensors for each y strip (x integral). Remaining memory is declared later in the Simps function.
996 std::complex<double> ***rhoz = new std::complex<double>**[11]; // Stat tensors for each z plane (xy integral). Remaining memory is declared later in the Simps function.
997 std::complex<double> **rhoi; // Stat tensors for integral of x, y and z with only positive q values.
998 for(int i=0; i<=10; i++) {
999 rhox[i] = new std::complex<double>*[3];
1000 for(int k=0; k<3; k++) rhox[i][k] = new std::complex<double>[5];
1001 }
1002
1003 // Use Eloss routine to get projectile energy at 10 target depths (z).
1004 double Tout, range;
1005 float Eint[11];
1006 Eint[0] = fBeamEnergy;
1007 float Tstep = fTarget.thickness / 10.;
1008 for(int i=1;i<=10;i++) Eint[i] = ELoss(fBeamEnergy, fBeam.Z, fTarget.isotope.Z, Tstep*float(i), fBeam.A, &Tout, &range, fTarget.isotope.A, fTarget.density);
1009
1010 //std::cout << "\tCalculating tensors..." << std::endl;
1011 // Setup step segments and iterate over particle detector dimensions (x and y) and depth energies (z) to get rho values for integration
1012 double xstep = fParticleDetector.fWidth / 10.; // Divide width into 10 steps
1013 double ystep = fParticleDetector.fHeight / 10.; // Divide height into 10 steps
1014 for(int z=0; z<=10; z++) { // z step calculated with Eloss routine
1015 for(int y=0; y<=10; y++) { // y step from bottom to top (relative to 0)
1016 double ydist = (5-y) * ystep;
1017 for(int x=0; x<=10; x++) { // x step from left to right
1018 double xdist = fParticleDetector.fDistanceR + x * xstep;
1019 // Get lab scattering angle for coulex calculation and phi angle at this segment, then use Kinematics routine to determine CM angle.
1020 double angh1, angh2, anglCM1, anglCM2, anghCM1, anghCM2, angCM; // Angles
1021 double Eh1, Eh2, El1, El2; // Energies
1022 double r = std::sqrt(ydist*ydist + xdist*xdist + fParticleDetector.fDistanceZ*fParticleDetector.fDistanceZ); // Radial distance from target to segment
1023 if(r<fParticleDetector.fDistanceZ) r = fParticleDetector.fDistanceZ; // BUG FIX FOR PRECISION ERROR (when angle=0 r < Z???)
1024 double angdet = std::acos(std::fabs(fParticleDetector.fDistanceZ)/r); // Lab angle of particle detection segment
1025 double angphi = std::atan2(ydist,xdist); // Phi angle of particle detection segment
1026 if(angphi>TMath::Pi()) angphi -= 2*TMath::Pi(); // If angle is > 180 deg change to negative equivalent
1027 if(fParticleDetector.fDistanceZ<0) angdet = TMath::Pi() - angdet; // Check if particles are detected back-scattered and correct angle if so
1028 int flag;
1029 if(ProjDet && fBeam.A < fTarget.isotope.A) { // Light projectile is detected, get light CM angle for coulex.
1030 flag = Kinematics(fBeam.A,fTarget.isotope.A,fBeam.A,fTarget.isotope.A,Eint[z],Q,angdet,El1,El2,Eh1,Eh2,angh1,angh2,anglCM1,anglCM2,anghCM1,anghCM2);
1031 if(flag==-1) {
1032 std::cerr << "Impossible particle-detection geometry! Check your values and try again (ensure horizontal detector distance is negative for back-scattered detection)." << std::endl;
1033 failbit = true;
1034 goto fail;
1035 }
1036 angCM = anglCM1 * rad2deg; // The angle used for coulex calculation (projectile CM) in degrees
1037 }
1038 else if(!ProjDet && fBeam.A > fTarget.isotope.A) { // Light target is detected, get heavy CM angle for coulex and rotate the phi angle by pi (heavy mass phi = detector phi + pi).
1039 flag = Kinematics(fBeam.A,fTarget.isotope.A,fTarget.isotope.A,fBeam.A,Eint[z],Q,angdet,El1,El2,Eh1,Eh2,angh1,angh2,anglCM1,anglCM2,anghCM1,anghCM2);
1040 if(flag==-1) {
1041 std::cerr << "Impossible particle-detection geometry! Check your values and try again (ensure horizontal detector distance is negative for back-scattered detection)." << std::endl;
1042 failbit = true;
1043 goto fail;
1044 }
1045 angCM = anghCM1 * rad2deg; // The angle used for coulex calculation (projectile CM) in degrees
1046 angphi += TMath::Pi();
1047 }
1048 else {
1049 std::cerr << "Bad reaction kinematics! Lighter nucleus must be detected after scattering." << std::endl;
1050 failbit = true;
1051 goto fail;
1052 }
1053 //if (level->fIndex==fLevelOfInterest) {
1054 // Calculate stat tensors at this segment
1055 //GP_AC_Tensors(Eint[z], angCM, fLevelOfInterest, rhox[x], xsect);
1056 GP_AC_Tensors(Eint[z], angCM, level->fIndex, rhox[x], xsect);
1057 sfctrx[x] = xsect * std::fabs(fParticleDetector.fDistanceZ) / std::pow(r,3) / xcmlr(angdet,anglCM1,fBeam.A,fTarget.isotope.A,Eint[z],Q,TgtEx);
1058 //level->fCrossSection += xsect * std::fabs(fParticleDetector.fDistanceZ) / std::pow(r,3) / xcmlr(angdet,anglCM1,fBeam.A,fTarget.isotope.A,Eint[z],Q,TgtEx);
1059 for(int k=0; k<3; k++) {
1060 for(int q=0; q<=k*2; q++) {
1061 std::complex<double> expqphi = std::exp(std::complex<double>(0, double(q)*angphi));
1062 rhox[x][k][q] *= sfctrx[x] * expqphi;
1063 }
1064 }
1065 // } else {
1066 // float tempxsect;
1067 // std::complex<double> ***temprhox = new std::complex<double>**[11];
1068 // for(int i=0; i<=10; i++) {
1069 // temprhox[i] = new std::complex<double>*[3];
1070 // for(int k=0; k<3; k++) temprhox[i][k] = new std::complex<double>[5];
1071 // }
1072 // GP_AC_Tensors(Eint[z], angCM, level->fIndex, temprhox[x], tempxsect);
1073 // std::cout << key << " " << tempxsect << std::endl;
1074 // level->fCrossSection += tempxsect * std::fabs(fParticleDetector.fDistanceZ) / std::pow(r,3) / xcmlr(angdet,anglCM1,fBeam.A,fTarget.isotope.A,Eint[z],Q,TgtEx);
1075 // }
1076 }
1077 // Simpson's rule integral of x rows into y
1078 rhoy[y] = GamR::Utils::Simps(rhox, 10, xstep);
1079 sfctry[y] = GamR::Utils::Simps(sfctrx, 10, xstep);
1080 }
1081 // Simpson's rule integral of y strips into z
1082 rhoz[z] = GamR::Utils::Simps(rhoy, 10, ystep);
1083 sfctrz[z] = GamR::Utils::Simps(sfctry, 10, ystep);
1084 }
1085 // Final Simpson's rule integral of z planes then divide by integral sfctr to get average stat tensors, and assemble into GamR Stat Tensor form as return value.
1086 rhoi = GamR::Utils::Simps(rhoz, 10, Tstep);
1087 sfctr = GamR::Utils::Simps(sfctrz, 10, Tstep);
1088 level->fCrossSection = sfctr;
1089 if (level->fIndex==fLevelOfInterest) {
1090 for(int k=0; k<3; k++) {
1091 for(int q=0; q<=k*2; q++) {
1092 rhoi[k][q] /= sfctr;
1093 retST->Set(k*2,q,rhoi[k][q]);
1094 level->fStatTensor->Set(k*2,q,rhoi[k][q]);
1095 if(q) { // For each complementary negative q, correct phase factor then copy value.
1096 rhoi[k][q] *= std::pow(-1,q);
1097 retST->Set(k*2,-q,rhoi[k][q]);
1098 level->fStatTensor->Set(k*2,-q,rhoi[k][q]);
1099 }
1100 }
1101 }
1102 } else {
1103 for(int k=0; k<3; k++) {
1104 for(int q=0; q<=k*2; q++) {
1105 rhoi[k][q] /= sfctr;
1106 level->fStatTensor->Set(k*2,q,rhoi[k][q]);
1107 if(q) { // For each complementary negative q, correct phase factor then copy value.
1108 rhoi[k][q] *= std::pow(-1,q);
1109 level->fStatTensor->Set(k*2,-q,rhoi[k][q]);
1110 }
1111 }
1112 }
1113 }
1114
1115fail: // Goto point if there's an error in the routine so memory is cleared before exit
1116 // Clear heap
1117 for(int i=0; i<=10; i++) {
1118 for(int k=0; k<=2; k++) {
1119 if(i==0) delete[] rhoi[k];
1120 delete[] rhox[i][k];
1121 delete[] rhoy[i][k];
1122 delete[] rhoz[i][k];
1123 }
1124 if(i==0) delete[] rhoi;
1125 delete[] rhox[i];
1126 delete[] rhoy[i];
1127 delete[] rhoz[i];
1128 }
1129 delete[] rhox;
1130 delete[] rhoy;
1131 delete[] rhoz;
1132 delete[] sfctrx;
1133 delete[] sfctry;
1134 delete[] sfctrz;
1135
1136 if(failbit) {
1137 delete retST;
1138 return nullptr;
1139 }
1140 }
1141 return retST;
1142
1143 }
1144
1147 calc.ReadFromFile(file_name);
1148 calc.Print();
1149 calc.ExperimentalSetup();
1150 calc.SaveToFile(file_name);
1151 return calc;
1152 }
1153
1154 GamR::AngDist::StatTensor *DoCoulex(std::string file_name) {
1156 calc.ReadFromFile(file_name);
1157 calc.Print();
1158 calc.ExperimentalSetup();
1159 calc.SaveToFile(file_name);
1160 return calc.CalcTensor();
1161 }
1162 }
1163}
void sp(int i, Option_t *option)
#define ANSI_COLOR_RESET
#define ANSI_COLOR_GREEN
#define ANSI_COLOR_BLUE
void Set(std::vector< double > Pm)
Definition StatTensor.cc:45
GamR::AngDist::StatTensor * CalcTensor()
void SaveToFile(std::string file_name="Wtheta.ans")
int ReadFromFile(std::string file_name="Wtheta.ans")
std::vector< WDB_nuclvl > GetLevels()
std::vector< WDB_nuctrans > GetETransitions()
std::map< std::string, Level * > fLevels
void Print(int loi=-1, int toi=-1)
void AddLevel(std::string name, float energy, float spin, bool parity)
std::vector< WDB_nuctrans > GetMTransitions()
void AddTransition(std::string initial, std::string final, float mat_el, float multipolarity)
std::vector< Transition * > fTransitions
const double rad2deg
Definition Coulex.hh:21
GamR::Coulex::CoulexCalculation ExperimentalSetup(std::string file_name)
GamR::AngDist::StatTensor * DoCoulex(std::string file_name)
double ELoss(double E, int Zb, int Zt, double Tt, double Mb=0, double *ttime=nullptr, double *range=nullptr, double Mt=0, double denst=0, long acc=1000)
void GP_AC_Tensors(float Ebeam, float CMAng, int lvl, std::complex< double > **rho, float &xsect)
Definition Coulex.cc:317
void DrawSetup()
Definition Coulex.cc:336
int Kinematics(double A1I, double A2I, double A3I, double A4I, double E1I, double QEFFI, double PSII, double &E3I, double &E3AI, double &E4I, double &E4AI, double &ZETAI, double &ZETAAI, double &thetaI, double &thetaaI, double &PHII, double &PHIAI)
Definition Coulex.cc:50
int setupcoulex(int Zbeam, float Abeam, int Ztgt, float Atgt, int grouptype, std::vector< WDB_nuclvl > &nuclvls, std::vector< WDB_nuctrans > &nucEtrans, std::vector< WDB_nuctrans > &nucMtrans)
Definition Coulex.cc:304
double Eldat[92][5]
double xcmlr(double anglab, double angCM, double Ap, double At, double Ep, double Q, bool Tgtex)
Definition Coulex.cc:182
void loadSCOEF()
std::string GetElement(int Z, float A)
Definition Misc.cc:54
int GetZA(std::string Nuclide, int &Z, double &A)
Definition Misc.cc:9
std::string getline(std::ifstream &f)
Definition Utilities.cc:330
double Simps(double *y, int n, double dx)
Definition Utilities.cc:301
int catcherr(std::string inp, double &val, bool require_positive)
Definition Utilities.cc:340
int GetInput(std::string prompt, double &val, bool require_positive)
Definition Utilities.cc:379
Definition Gain.cc:19