REST-for-Physics  v2.3
Rare Event Searches ToolKit for Physics
Loading...
Searching...
No Matches
src/TRestDetectorGas.cxx
1/*************************************************************************
2 * This file is part of the REST software framework. *
3 * *
4 * Copyright (C) 2016 GIFNA/TREX (University of Zaragoza) *
5 * For more information see http://gifna.unizar.es/trex *
6 * *
7 * REST is free software: you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation, either version 3 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * REST is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have a copy of the GNU General Public License along with *
18 * REST in $REST_PATH/LICENSE. *
19 * If not, see http://www.gnu.org/licenses/. *
20 * For the list of contributors see $REST_PATH/CREDITS. *
21 *************************************************************************/
22
215
216#include "TRestDetectorGas.h"
217
218#include <TRestDataBase.h>
219
220#include <algorithm>
221
222using namespace std;
223
224ClassImp(TRestDetectorGas);
225
226// const char* defaultServer = "https://sultan.unizar.es/gasFiles/";
227
232 Initialize();
233
234 fGasGeneration = false;
235}
236
249TRestDetectorGas::TRestDetectorGas(const char* configFilename, string name, bool gasGeneration, bool test)
251 Initialize();
252 fGasGeneration = gasGeneration;
253
254 fTest = test;
255
256 if (strcmp(configFilename, "server") == 0) {
257 LoadConfigFromElement(StringToElement("<TRestDetectorGas name=\"" + name + "\" file=\"server\"/>"),
258 nullptr);
259 } else {
260 fConfigFileName = configFilename;
262 }
263
264 // if ( fStatus == RESTGAS_CFG_LOADED ) LoadGasFile( );
265}
266
271 RESTDebug << "Entering ... TRestDetectorGas() destructor." << RESTendl;
272
273#if defined USE_Garfield
274 delete fGasMedium;
275#endif
276}
277
283 RESTDebug << "TRestDetectorGas. Entering ... Initialize()." << RESTendl;
284
285 SetSectionName(this->ClassName());
286 SetLibraryVersion(LIBRARY_VERSION);
287
288 fPressureInAtm = 1;
289 fTemperatureInK = 300;
290
291 fNofGases = 0;
292
293 fGasComponentName.clear();
294 fGasComponentFraction.clear();
295
296 fStatus = RESTGAS_INTITIALIZED;
297
298 fGasFilename = "";
299 fGasFileContent = "";
300
301#if defined USE_Garfield
302 fGasMedium = new Garfield::MediumMagboltz();
303#else
304 fGasMedium = nullptr;
305#endif
306
308 // This must be commented. If not when we specify gasGeneration=true on the
309 // constructor, it will be overriden inside LoadConfigFromFile
310 //
311 // fGasGeneration = false;
313
314 fEmin = 10;
315 fEmax = 1000;
316 fEnodes = 20;
317}
318
328 RESTDebug << "Entering ... TRestDetectorGas::LoadGasFile()." << RESTendl;
329
330#if defined USE_Garfield
331 RESTDebug << "fGasFilename = " << fGasFilename << RESTendl;
332 if (!TRestTools::fileExists((string)(fGasFilename))) {
333 RESTError << __PRETTY_FUNCTION__ << RESTendl;
334 RESTError << "The gas file does not exist. (name:" << fGasFilename << ")" << RESTendl;
335 fStatus = RESTGAS_ERROR;
336 return;
337 }
338
339 fGasMedium->LoadGasFile((string)(fGasFilename));
340
341 fEFields.clear();
342 fBFields.clear();
343 fAngles.clear();
344 fGasMedium->GetFieldGrid(fEFields, fBFields, fAngles);
345
346 fStatus = RESTGAS_GASFILE_LOADED;
347 RESTInfo << "TRestDetectorGas. Gas file loaded!" << RESTendl;
348
349 for (unsigned int i = 0; i < fEFields.size(); i++)
350 RESTDebug << "node " << i << " Field : " << fEFields[i] << " V/cm" << RESTendl;
351
352 if (fGasMedium && fGasMedium->GetW() == 0.) {
353 fGasMedium->SetW(GetWvalue());
354 } // as it is probably not computed by Magboltz
355#else
356 cout << "This REST is not complied with garfield, it cannot load any gas file!" << endl;
357#endif
358}
359
360void TRestDetectorGas::CalcGarField(double Emin, double Emax, int n) {
361 RESTDebug << "Entering ... TRestDetectorGas::CalcGarField( Emin=" << Emin << " , Emax=" << Emax << " )"
362 << RESTendl;
363
364#if defined USE_Garfield
365 if (fEnodes <= 0) {
366 cout << "REST ERROR : The number of nodes is not a positive number!!. Gas "
367 "file generation cancelled."
368 << endl;
369 fStatus = RESTGAS_ERROR;
370 return;
371 }
372 if (fEmin >= fEmax) {
373 cout << "REST ERROR : The Electric field grid boundaries are not properly "
374 "defined."
375 << endl;
376 fStatus = RESTGAS_ERROR;
377 return;
378 }
379
380 string gasStr[3];
381 for (int i = 0; i < fNofGases; i++) {
382 gasStr[i] = (string)fGasComponentName[i];
383 if (i == 2) break;
384 }
385
386 if (fNofGases == 1) fGasMedium->SetComposition(gasStr[0], fGasComponentFraction[0] * 100.);
387
388 if (fNofGases == 2)
389 fGasMedium->SetComposition(gasStr[0], fGasComponentFraction[0] * 100., gasStr[1],
390 fGasComponentFraction[1] * 100.);
391
392 if (fNofGases == 3)
393 fGasMedium->SetComposition(gasStr[0], fGasComponentFraction[0] * 100., gasStr[1],
394 fGasComponentFraction[1] * 100., gasStr[2],
395 fGasComponentFraction[2] * 100.);
396
397 if (fNofGases > 3) {
398 cout << "REST ERROR : Number of gas components higher than 3 not allowed" << endl;
399 fStatus = RESTGAS_ERROR;
400 return;
401 }
402
403 fGasMedium->SetTemperature(fTemperatureInK);
404
405 if (fPressureInAtm != 1)
406 RESTWarning << "-- Warning : The gas will be generated for gas pressure = 1atm" << RESTendl;
407
408 fGasMedium->SetPressure(1 * REST_Units::torr);
409
410 fGasMedium->SetFieldGrid(Emin, Emax, n, n > 1);
411
412 fGasMedium->SetMaxElectronEnergy(fMaxElectronEnergy);
413
414 cout << "Garfield: calculating..." << endl;
415
416 if (fVerboseLevel >= TRestStringOutput::REST_Verbose_Level::REST_Info) fGasMedium->EnableDebugging();
417 fGasMedium->Initialise();
418 if (fVerboseLevel >= TRestStringOutput::REST_Verbose_Level::REST_Info) fGasMedium->DisableDebugging();
419
420 fGasMedium->GenerateGasTable(fNCollisions, true);
421 if (fPressureInAtm != 1) {
422 RESTWarning << "-- Warning : Restoring the gas pressure" << RESTendl;
423 fGasMedium->SetPressure(fPressureInAtm * 760.);
424 }
425#else
426 cout << "This REST is not complied with garfield, it cannot calculate "
427 "garfield!"
428 << endl;
429#endif
430}
431
441void TRestDetectorGas::AddGasComponent(string gasName, Double_t fraction) {
442 RESTDebug << "Entering ... TRestDetectorGas::AddGasComponent( gasName=" << gasName
443 << " , fraction=" << fraction << " )" << RESTendl;
444
445 fGasComponentName.push_back(gasName);
446 fGasComponentFraction.push_back(fraction);
447 fNofGases++;
448}
449
450// This was just a test to try to Get the calculated W for the gas definition.
451// However, I tested with Xe+TMA and I got an error message that TMA
452// photoncrossection database is not available
453void TRestDetectorGas::GetGasWorkFunction() {
454#if defined USE_Garfield
455 RESTEssential << __PRETTY_FUNCTION__ << RESTendl;
456 RESTEssential << "This method has never been validated to operate properly" << RESTendl;
457 RESTEssential << "If we manage to make it work we could use this method to "
458 "obtain the calculated W of the gas"
459 << RESTendl;
460
461 // Gas gap [cm].
462 const double width = 1.;
463 SolidBox* box = new SolidBox(width / 2., 0., 0., width / 2., 10., 10.);
464 GeometrySimple* geo = new GeometrySimple();
465 geo->AddSolid(box, fGasMedium);
466
467 ComponentConstant* cmp = new ComponentConstant();
468 cmp->SetGeometry(geo);
469 cmp->SetElectricField(100., 0., 0.);
470
471 Sensor* sensor = new Sensor();
472 sensor->AddComponent(cmp);
473
474 TrackHeed* heed = new TrackHeed();
475 heed->SetSensor(sensor);
476 // Set the particle type.
477 heed->SetParticle("pi");
478 // Set the particle momentum (in eV/c).
479 heed->SetMomentum(120.e9);
480
481 // Switch on debugging to print out some information (stopping power, W value,
482 // ...)
483 heed->EnableDebugging();
484 // Initial position
485 double x0 = 0., y0 = 0., z0 = 0., t0 = 0.;
486 // Direction of the track (perpendicular incidence)
487 double dx0 = 1., dy0 = 0., dz0 = 0.;
488 heed->NewTrack(x0, y0, z0, t0, dx0, dy0, dz0);
489 cout << "W : " << heed->GetW() << endl;
490#else
491 cout << "This REST is not complied with garfield, it cannot calculate "
492 "garfield!"
493 << endl;
494#endif
495}
496
506 // if (GetVerboseLevel() <= REST_Info) fVerboseLevel = REST_Info;
507
508 RESTDebug << "Entering ... TRestDetectorGas::InitFromConfigFile()" << RESTendl;
509
510 // read config parameters of base class
512 if (fW == -1) {
513 fW = 21.9;
514 cout << "Setting default W-value : " << fW << endl;
515 }
516
517 // match the database, id=0(any), type="GAS_SERVER"
518 string _gasServer = gDataBase->query_data(DBEntry(0, "GAS_SERVER")).value;
519 if (_gasServer == "") _gasServer = "none";
520 fGasServer = GetParameter("gasServer", _gasServer);
521
522 // add gas component
523 TiXmlElement* gasComponentDefinition = GetElement("gasComponent");
524 while (gasComponentDefinition != nullptr) {
525 string gasName = GetFieldValue("name", gasComponentDefinition);
526 Double_t gasFraction = StringToDouble(GetFieldValue("fraction", gasComponentDefinition));
527 AddGasComponent(gasName, gasFraction);
528 gasComponentDefinition = GetNextElement(gasComponentDefinition);
529 }
530 if (fNofGases == 0 && fMaterial != "") {
531 vector<string> componentsdef = Split(fMaterial, " ");
532 for (auto componentdef : componentsdef) {
533 vector<string> componentdefpair = Split(componentdef, ":");
534 if (componentdefpair.size() != 2) {
535 continue;
536 }
537 AddGasComponent(componentdefpair[0], StringToDouble(componentdefpair[1]));
538 }
539 }
540 if (fNofGases == 0) {
541 RESTError << "TRestDetectorGas: No gas components added!" << RESTendl;
542 }
543 double sum = 0;
544 for (int i = 0; i < fNofGases; i++) sum += GetGasComponentFraction(i);
545 if (sum - 1 < 1.e12)
546 fStatus = RESTGAS_CFG_LOADED;
547 else {
548 RESTWarning << "TRestDetectorGas : The total gas fractions is NOT 1." << RESTendl;
549 fStatus = RESTGAS_ERROR;
550 return;
551 }
552
553 // setup e-field calculation range and gas file generation parameters
554 TiXmlElement* eFieldDefinition = GetElement("eField");
555 fEmax = StringToDouble(GetFieldValue("Emax", eFieldDefinition));
556 fEmin = StringToDouble(GetFieldValue("Emin", eFieldDefinition));
557 fEnodes = StringToInteger(GetFieldValue("nodes", eFieldDefinition));
558 fNCollisions = StringToInteger(GetParameter("nCollisions"));
559 fMaxElectronEnergy = StringToDouble(GetParameter("maxElectronEnergy", "40"));
560 if (ToUpper(GetParameter("generate")) == "ON" || ToUpper(GetParameter("generate")) == "TRUE")
561 fGasGeneration = true;
562 fGasOutputPath = GetParameter("gasOutputPath", "./");
564 RESTWarning << "-- Warning : The specified gasOutputPath is not writable!" << RESTendl;
565 RESTWarning << "-- Warning : The output path will be changed to ./" << RESTendl;
566 fGasOutputPath = "./";
567 }
568 fGDMLMaterialRef = GetParameter("GDMLMaterialRef", "");
569
570 // construct the gas file name and try to find it, either locally or from gas server
571 fGasFilename = ConstructFilename();
572 RESTDebug << "TRestDetectorGas::InitFromConfigFile. ConstructFilename. fGasFilename = " << fGasFilename
573 << RESTendl;
574 fGasFilename = FindGasFile((string)fGasFilename);
575 RESTDebug << "TRestDetectorGas::InitFromConfigFile. FindGasFile. fGasFilename = " << fGasFilename
576 << RESTendl;
577
578 // If we found the gasFile then obviously we disable the gas generation
579 if (fGasGeneration && TRestTools::fileExists((string)fGasFilename)) {
580 fGasGeneration = false;
581
582 RESTWarning << "TRestDetectorGas gasFile generation is enabled, but the "
583 "gasFile already exists!!"
584 << RESTendl;
585 RESTWarning << "Filename : " << fGasFilename << RESTendl;
586 RESTWarning << "fGasGeneration should be disabled to remove this "
587 "warning."
588 << RESTendl;
589 RESTWarning << "If you really want to re-generate the gas file you "
590 "will need to disable the gasServer."
591 << RESTendl;
592 RESTWarning << "And/or remove any local copies that are found by "
593 "SearchPath."
594 << RESTendl;
595 }
596 fStatus = RESTGAS_CFG_LOADED;
597
598#if defined USE_Garfield
599 // calling garfield, either to generate gas file or load existing gas file
600 if (fGasGeneration) {
601 RESTEssential << "Starting gas generation" << RESTendl;
602
603 CalcGarField(fEmin, fEmax, fEnodes);
605 fStatus = RESTGAS_GASFILE_LOADED;
606 } else {
607 LoadGasFile();
608 fGasMedium->SetPressure(fPressureInAtm * REST_Units::torr);
609 }
610 if (fGasMedium && fGasMedium->GetW() == 0.)
611 fGasMedium->SetW(fW); // as it is probably not computed by Magboltz
612#endif
613
615}
616
618 RESTDebug << "Entering ... TRestDetectorGas::InitFromRootFile()" << RESTendl;
620 if (fGasFileContent != "") // use gas file content by default
621 {
622 fGasFilename = "/tmp/restGasFile_" + REST_USER + ".gas";
623 ofstream outf;
624 outf.open(fGasFilename, ios::ate);
625 outf << fGasFileContent << endl;
626 outf.close();
627 LoadGasFile();
628 int z = system("rm " + fGasFilename);
629 if (z != 0) RESTError << "Problem removing gas file: " << fGasFilename << RESTendl;
630 } else {
631 fGasFilename = FindGasFile((string)fGasFilename);
632 if (fGasFilename != "") {
633 LoadGasFile();
634 }
635 }
636}
637
638void TRestDetectorGas::UploadGasToServer(string absoluteGasFilename) {
639 RESTEssential << "uploading gas file and gas definition rmls" << RESTendl;
640
641 if (!fTest && (fMaxElectronEnergy < 400 || fNCollisions < 10 || fEnodes < 20)) {
642 RESTWarning << "-- Warning : The gas file does not fulfill the requirements "
643 "for being uploaded to the gasServer"
644 << RESTendl;
645 RESTWarning << "-- Warning : maxElectronEnergy >= 400. Number of collisions >= "
646 "10. Number of E nodes >= 20."
647 << RESTendl;
648 RESTWarning << "-- Warning : The generated file will NOT be uploaded to the "
649 "server but preserved locally."
650 << RESTendl;
651 return;
652 }
653
655 // We add the gas definition we used to generate the gas file and prepare it
656 // to upload/update in the gasServer
657 string cmd;
658 int a;
659 // We download (probably again) the original version
660 string url = gDataBase->query_data(DBEntry(0, "META_RML", "TRestDetectorGas")).value;
661 string fname = TRestTools::DownloadRemoteFile(url);
662
663// We remove the last line. I.e. the enclosing </gases> in the original file
664#ifdef __APPLE__
665 cmd = "sed -i '' -e '$ d' " + fname;
666#else
667 cmd = "sed -i '$ d' " + fname;
668#endif
669
670 a = system(cmd.c_str());
671
672 if (a != 0) {
673 RESTError << "-- Error : " << __PRETTY_FUNCTION__ << RESTendl;
674 RESTError << "-- Error : problem removing last line from " << fname << RESTendl;
675 return;
676 }
677
678 // We add some header before the gas definition. We might add also date an
679 // other information essential to identify the gasFile submission
680 ofstream outf;
681 outf.open(fname, ios::app);
682 outf << endl;
683 outf << "//------- User : " << REST_USER << " ---- REST version : " << REST_RELEASE
684 << " ---------------------------" << endl;
685 outf.close();
686
687 // We write the TRestDetectorGas section
688 this->WriteConfigBuffer(fname);
689
690 // We re-write the enclosing </gases> tag
691 outf.open(fname, ios::app);
692 outf << "\n" << endl;
693 outf << "</gases>" << endl;
694 outf.close();
696
697 // We transfer the new gas definitions to the gasServer
698 TRestTools::UploadToServer(fname, (string)fGasServer, "ssh://gasUser@:22");
699
700 // We transfer the gasFile to the gasServer
701 TRestTools::UploadToServer(absoluteGasFilename, (string)fGasServer, "ssh://gasUser@:22");
702
703 // We remove the local file (afterwards, the remote copy will be used)
704 // cmd = "rm " + _name;
705 // a = system(cmd.c_str());
706
707 // if (a != 0) {
708 // ferr << "-- Error : " << __PRETTY_FUNCTION__ << endl;
709 // ferr << "-- Error : problem removing the locally generated gas file" << endl;
710 // ferr << "-- Error : Please report this problem at "
711 // "http://gifna.unizar.es/rest-forum/"
712 // << endl;
713 // return;
714 //}
715
716 RESTSuccess << "-- Success : Gasfile server database was updated successfully!" << RESTendl;
717}
718
733string TRestDetectorGas::FindGasFile(string name) {
734 RESTDebug << "Entering ... TRestDetectorGas::FindGasFile( name=" << name << " )" << RESTendl;
735
736 string absoluteName = "";
737
738 if (!fGasGeneration && fGasServer != "none") {
739 absoluteName = TRestTools::DownloadRemoteFile((string)fGasServer + "/" + name);
740 }
741
742 if (absoluteName == "") {
743 RESTInfo << "Trying to find the gasFile locally" << RESTendl;
744 absoluteName = SearchFile(name);
745 if (absoluteName == "") {
746 RESTWarning << "-- Warning : No sucess finding local gas file definition." << RESTendl;
747 RESTWarning << "-- Warning : Gas file definition does not exist." << RESTendl;
748 RESTInfo << "To generate a new gasFile enable gas generation in TRestDetectorGas "
749 "constructor"
750 << RESTendl;
751 RESTInfo << "TRestDetectorGas ( \"gasDefinition.rml\", \"gas Name\", true );" << RESTendl;
752 RESTInfo << "Further details can be found at TRestDetectorGas class definition and "
753 "tutorial."
754 << RESTendl;
755
756 absoluteName = name;
757 }
758 }
759
760 return absoluteName;
761}
762
767 RESTDebug << "Entering ... TRestDetectorGas::GetGasMixture( )" << RESTendl;
768
769 TString gasMixture;
770 char tmpStr[64];
771 for (int n = 0; n < fNofGases; n++) {
772 if (n > 0) gasMixture += "-";
773 gasMixture += GetGasComponentName(n) + "_";
774 sprintf(tmpStr, "%03.1lf", GetGasComponentFraction(n) * 100.);
775 gasMixture += (TString)tmpStr;
776 }
777 return gasMixture;
778}
779
787 RESTDebug << "Entering ... TRestDetectorGas::ConstructFilename( )" << RESTendl;
788
789 string name = "";
790 char tmpStr[256];
791 for (int n = 0; n < fNofGases; n++) {
792 if (n > 0) name += "-";
793 name += GetGasComponentName(n) + "_";
794 if (GetGasComponentFraction(n) >= 0.001)
795 sprintf(tmpStr, "%03.1lf", GetGasComponentFraction(n) * 100.);
796 else
797 sprintf(tmpStr, "%03.1lfppm", GetGasComponentFraction(n) * 1.e6);
798
799 name += (TString)tmpStr;
800 }
801
802 // The filename is constructed always at 1 atm pressure.
803 // We keep E_vs_P to remind the field calculation range will
804 // depend on pressure.
805
806 name += "-E_vs_P_";
807 sprintf(tmpStr, "%03.1lf", fEmin);
808 name += (TString)tmpStr;
809
810 name += "_";
811 sprintf(tmpStr, "%03.1lf", fEmax);
812 name += (TString)tmpStr;
813
814 name += "_nodes_";
815 sprintf(tmpStr, "%02d", fEnodes);
816 name += (TString)tmpStr;
817
818 name += "-nCol_";
819 sprintf(tmpStr, "%02d", fNCollisions);
820 name += (TString)tmpStr;
821
822 name += "-maxE_";
823 sprintf(tmpStr, "%03d", (Int_t)fMaxElectronEnergy);
824 name += (TString)tmpStr;
825
826 name += ".gas";
827
828 RESTDebug << "Constructed filename : " << name << RESTendl;
829 return name;
830}
831
835 RESTDebug << "Entering ... TRestDetectorGas::GenerateGasFile( )" << RESTendl;
836
837#if defined USE_Garfield
838
839 fGasFilename = ConstructFilename();
840 RESTDebug << " TRestDetectorGas::GenerateGasFile. fGasFilename = " << fGasFilename << RESTendl;
841
843 cout << endl;
844 RESTWarning << "-- Warning: REST ERROR. TRestDetectorGas. Path is not writtable." << RESTendl;
845 RESTWarning << "-- Warning: Path : " << fGasOutputPath << RESTendl;
846 RESTWarning << "-- Warning: Make sure the final data path is writtable before "
847 "proceed to gas generation."
848 << RESTendl;
849 RESTWarning << "-- Warning: or change the gas data path ... " << RESTendl;
850 RESTWarning << RESTendl;
851 GetChar();
852 return;
853 }
854
855 cout << "Writing gas file : " << endl;
856 cout << "-----------------" << endl;
857 cout << "Path : " << fGasOutputPath << endl;
858 cout << "Filename : " << fGasFilename << endl;
859
860 fGasMedium->WriteGasFile((string)(fGasOutputPath + "/" + fGasFilename));
861
862 if (fGasServer != "none") UploadGasToServer((string)(fGasOutputPath + "/" + fGasFilename));
863
864#else
865 cout << "This REST is not complied with garfield, it cannot save any gas file!" << endl;
866#endif
867}
868
878void TRestDetectorGas::SetPressure(Double_t pressure) {
879 RESTDebug << "Entering ... TRestDetectorGas::SetPressure( pressure=" << pressure << " )" << RESTendl;
880
881 fPressureInAtm = pressure;
882#if defined USE_Garfield
883 fGasMedium->SetPressure(fPressureInAtm * REST_Units::torr);
884#endif
885}
886
889void TRestDetectorGas::SetTemperature(Double_t temperature) {
890 RESTDebug << "Entering ... TRestDetectorGas::SetPressure( temperature=" << temperature << " )"
891 << RESTendl;
892
893 fTemperatureInK = temperature;
894#if defined USE_Garfield
895 fGasMedium->SetTemperature(temperature);
896#endif
897}
898
907void TRestDetectorGas::PlotDriftVelocity(Double_t eMin, Double_t eMax, Int_t nSteps) {
908 RESTDebug << "Entering ... TRestDetectorGas::PlotDriftVelocity( eMin=" << eMin << " , eMax=" << eMax
909 << ", nSteps=" << nSteps << " )" << RESTendl;
910
911 vector<Double_t> eField(nSteps), driftVel(nSteps);
912
913 for (int i = 0; i < nSteps; i++) {
914 eField[i] = (eMin + (double)i * (eMax - eMin) / nSteps);
915
916 this->SetElectricField(eField[i] / units("V/cm"));
917 driftVel[i] = GetDriftVelocity() * units("cm/us");
918 }
919
920 TCanvas* c = new TCanvas("Drift velocity", " ");
921 TGraph* fDriftVel = new TGraph(nSteps, &eField[0], &driftVel[0]);
922 TString str;
923 str.Form("Drift Velocity for %s (Pressure: %3.1lf bar)", GetName(), this->GetPressure());
924 fDriftVel->SetTitle(str);
925 fDriftVel->GetXaxis()->SetTitle("E [V/cm]");
926 fDriftVel->GetYaxis()->SetTitle("Drift velocity [cm/#mus]");
927 fDriftVel->GetYaxis()->SetTitleOffset(2);
928 fDriftVel->Draw("");
929 c->Update();
930}
931
940void TRestDetectorGas::PlotLongitudinalDiffusion(Double_t eMin, Double_t eMax, Int_t nSteps) {
941 RESTDebug << "Entering ... TRestDetectorGas::PlotLongitudinalDiffusion( eMin=" << eMin
942 << " , eMax=" << eMax << ", nSteps=" << nSteps << " )" << RESTendl;
943
944 vector<Double_t> eField(nSteps), longDiff(nSteps);
945
946 for (int i = 0; i < nSteps; i++) {
947 eField[i] = eMin + (double)i * (eMax - eMin) / nSteps;
948
949 this->SetElectricField(eField[i] / units("V/cm"));
950 longDiff[i] = 10. * GetLongitudinalDiffusion(); // to express it in mm/sqrt(cm)
951 }
952
953 TCanvas* c = new TCanvas("Longitudinal diffusion", " ");
954 TGraph* fLongDiff = new TGraph(nSteps, &eField[0], &longDiff[0]);
955 TString str;
956 str.Form("Longitudinal diffusion for %s (Pressure: %3.1lf bar)", GetName(), this->GetPressure());
957 fLongDiff->SetTitle(str);
958 fLongDiff->GetXaxis()->SetTitle("E [V/cm]");
959 fLongDiff->GetYaxis()->SetTitle("Longitudinal diffusion [mm/#sqrt{cm}]");
960 fLongDiff->GetYaxis()->SetTitleOffset(2);
961 fLongDiff->Draw("");
962 c->Update();
963}
964
973void TRestDetectorGas::PlotTransversalDiffusion(Double_t eMin, Double_t eMax, Int_t nSteps) {
974 RESTDebug << "Entering ... TRestDetectorGas::PlotTransversalDiffusion( eMin=" << eMin
975 << " , eMax=" << eMax << ", nSteps=" << nSteps << " )" << RESTendl;
976
977 vector<Double_t> eField(nSteps), transDiff(nSteps);
978
979 for (int i = 0; i < nSteps; i++) {
980 eField[i] = eMin + (double)i * (eMax - eMin) / nSteps;
981
982 this->SetElectricField(eField[i] / units("V/cm"));
983 transDiff[i] = 10. * GetTransversalDiffusion(); // to express it in mm/sqrt(cm)
984 }
985
986 TCanvas* c = new TCanvas("Transitudinal diffusion", " ");
987 TGraph* fTransDiff = new TGraph(nSteps, &eField[0], &transDiff[0]);
988 TString str;
989 str.Form("Transversal diffusion for %s (Pressure: %3.1lf bar)", GetName(), this->GetPressure());
990 fTransDiff->SetTitle(str);
991 fTransDiff->GetXaxis()->SetTitle("E [V/cm]");
992 fTransDiff->GetYaxis()->SetTitle("Transversal diffusion [mm/#sqrt{cm}]");
993 fTransDiff->GetYaxis()->SetTitleOffset(2);
994 fTransDiff->Draw("");
995 c->Update();
996}
997
1006void TRestDetectorGas::PlotTownsendCoefficient(Double_t eMin, Double_t eMax, Int_t nSteps) {
1007 RESTDebug << "Entering ... TRestDetectorGas::PlotTownsendCoefficient( eMin=" << eMin << " , eMax=" << eMax
1008 << ", nSteps=" << nSteps << " )" << RESTendl;
1009
1010 vector<Double_t> eField(nSteps), townsendCoeff(nSteps);
1011
1012 for (int i = 0; i < nSteps; i++) {
1013 eField[i] = eMin + (double)i * (eMax - eMin) / nSteps;
1014
1015 townsendCoeff[i] = GetTownsendCoefficient(eField[i]);
1016 }
1017
1018 TCanvas* c = new TCanvas("Townsend coefficient", " ");
1019 TGraph* fTownsend = new TGraph(nSteps, &eField[0], &townsendCoeff[0]);
1020 TString str;
1021 str.Form("Townsend coefficient for %s", GetName());
1022 fTownsend->SetTitle(str);
1023 fTownsend->GetXaxis()->SetTitle("E [V/cm]");
1024 fTownsend->GetYaxis()->SetTitle("Townsend coefficient [1/cm]");
1025 fTownsend->GetYaxis()->SetTitleOffset(2);
1026 fTownsend->Draw("");
1027 c->Update();
1028}
1029
1035 RESTDebug << "Entering ... TRestDetectorGas::GetDriftVelocity( E=" << E << " )" << RESTendl;
1036
1037 SetPressure(fPressureInAtm);
1038
1039#if defined USE_Garfield
1040 if (fStatus != RESTGAS_GASFILE_LOADED) {
1041 RESTDebug << "-- Error : " << __PRETTY_FUNCTION__ << RESTendl;
1042 RESTDebug << "-- Error : Gas file was not loaded!" << RESTendl;
1043 return 0;
1044 }
1045
1046 RESTInfo << "Calling Garfield directly. Please be aware that the unit is different "
1047 << "from REST standard unit. E is V/cm. The return is cm/us" << RESTendl;
1048
1049 Double_t vx, vy, vz;
1050 fGasMedium->ElectronVelocity(0., 0, -E, 0, 0, 0, vx, vy, vz);
1051 return vz * 1000.;
1052#else
1053 std::cout << "This REST is not complied with garfield, Do not use Drift Velocity "
1054 "from TRestDetectorGas!"
1055 << std::endl;
1056 std::cout << "Please define the Drift Velocity in each process!" << std::endl;
1057 return 0.001;
1058#endif
1059}
1060
1066 RESTDebug << "Entering ... TRestDetectorGas::GetLongitudinalDiffusion( E=" << E << " )" << RESTendl;
1067
1068 SetPressure(fPressureInAtm);
1069
1070#if defined USE_Garfield
1071 if (fStatus != RESTGAS_GASFILE_LOADED) {
1072 RESTDebug << "-- Error : " << __PRETTY_FUNCTION__ << RESTendl;
1073 RESTDebug << "-- Error : Gas file was not loaded!" << RESTendl;
1074 return 0;
1075 }
1076
1077 RESTInfo << "Calling Garfield directly. Please be aware that the unit is different "
1078 << "from REST standard unit. E is V/cm. The return is cm^1/2" << RESTendl;
1079
1080 Double_t dl, dt;
1081 fGasMedium->ElectronDiffusion(0., 0, -E, 0, 0, 0, dl, dt);
1082 return dl;
1083#else
1084 std::cout << "This REST is not compiled with garfield, Do not use Longitudinal "
1085 "Diffusion from TRestDetectorGas!"
1086 << std::endl;
1087 std::cout << "Please define the Longitudinal Diffusion in each process!" << std::endl;
1088 return 0;
1089#endif
1090}
1091
1097 RESTDebug << "Entering ... TRestDetectorGas::GetTransversalDiffusion( E=" << E << " )" << RESTendl;
1098
1099 SetPressure(fPressureInAtm);
1100#if defined USE_Garfield
1101 if (fStatus != RESTGAS_GASFILE_LOADED) {
1102 RESTDebug << "-- Error : " << __PRETTY_FUNCTION__ << RESTendl;
1103 RESTDebug << "-- Error : Gas file was not loaded!" << RESTendl;
1104 return 0;
1105 }
1106
1107 RESTInfo << "Calling Garfield directly. Please be aware that the unit is different "
1108 << "from REST standard unit. E is V/cm. The return is cm^1/2" << RESTendl;
1109
1110 Double_t dl, dt;
1111 fGasMedium->ElectronDiffusion(0., 0, -E, 0, 0, 0, dl, dt);
1112 return dt;
1113#else
1114 std::cout << "This REST is not complied with garfield, Do not use Transversal "
1115 "Diffusion from TRestDetectorGas!"
1116 << std::endl;
1117 std::cout << "Please define the Transversal Diffusion in each process!" << std::endl;
1118 return 0;
1119#endif
1120}
1121
1127 RESTDebug << "Entering ... TRestDetectorGas::GetTownsendCoefficient( E=" << E << " )" << RESTendl;
1128
1129 SetPressure(fPressureInAtm);
1130#if defined USE_Garfield
1131 if (fStatus != RESTGAS_GASFILE_LOADED) {
1132 RESTDebug << "-- Error : " << __PRETTY_FUNCTION__ << RESTendl;
1133 RESTDebug << "-- Error : Gas file was not loaded!" << RESTendl;
1134 return 0;
1135 }
1136
1137 RESTInfo << "Calling Garfield directly. Please be aware that the unit is different "
1138 << "from REST standard unit. E is V/cm. The return is V/cm" << RESTendl;
1139
1140 Double_t alpha;
1141 fGasMedium->ElectronTownsend(0., 0, -E, 0, 0, 0, alpha);
1142 return alpha;
1143#else
1144 std::cout << "This REST is not complied with garfield, Do not use Townsend "
1145 "Coefficient from TRestDetectorGas!"
1146 << std::endl;
1147 std::cout << "Please define the Townsend Coefficient in each process!" << std::endl;
1148 return 0;
1149#endif
1150}
1151
1157 RESTDebug << "Entering ... TRestDetectorGas::GetAttachmentCoefficient( E=" << E << " )" << RESTendl;
1158
1159 SetPressure(fPressureInAtm);
1160#if defined USE_Garfield
1161 if (fStatus != RESTGAS_GASFILE_LOADED) {
1162 RESTDebug << "-- Error : " << __PRETTY_FUNCTION__ << RESTendl;
1163 RESTDebug << "-- Error : Gas file was not loaded!" << RESTendl;
1164 return 0;
1165 }
1166
1167 RESTInfo << "Calling Garfield directly. Please be aware that the unit is different "
1168 << "from REST standard unit. E is V/cm. The return is V/cm" << RESTendl;
1169
1170 Double_t eta;
1171 fGasMedium->ElectronAttachment(0., 0, -E, 0, 0, 0, eta);
1172 return eta;
1173#else
1174 std::cout << "This REST is not complied with garfield, Do not use Attachment "
1175 "Coefficient from TRestDetectorGas!"
1176 << std::endl;
1177 std::cout << "Please define the Attachment Coefficient in each process!" << std::endl;
1178 return 0;
1179#endif
1180}
1181
1186 RESTDebug << "Entering ... TRestDetectorGas::PrintGasInfo( )" << RESTendl;
1187
1189
1190 RESTMetadata << "Status : ";
1191 if (fStatus == RESTGAS_INTITIALIZED) RESTMetadata << "Initialized";
1192 if (fStatus == RESTGAS_CFG_LOADED) RESTMetadata << "Configuration loaded";
1193 if (fStatus == RESTGAS_GASFILE_LOADED) RESTMetadata << "Gasfile loaded";
1194 if (fStatus == RESTGAS_ERROR) RESTMetadata << "Error";
1195 RESTMetadata << RESTendl;
1196
1197 RESTMetadata << "Gas filename : " << TRestTools::GetPureFileName((string)fGasFilename) << RESTendl;
1198 RESTMetadata << "Pressure : " << fPressureInAtm << " atm" << RESTendl;
1199 RESTMetadata << "Temperature : " << fTemperatureInK << " K" << RESTendl;
1200 RESTMetadata << "Electric Field : " << fElectricField * units("V/cm") << " V/cm " << RESTendl;
1201 RESTMetadata << "W-value : " << fW << " eV" << RESTendl;
1202 RESTMetadata << "Drift velocity : " << GetDriftVelocity(fElectricField * units("V/cm")) / units("cm/us")
1203 << " mm/us " << RESTendl;
1204 RESTMetadata << "Max. Electron energy : " << fMaxElectronEnergy << " eV" << RESTendl;
1205 RESTMetadata << "Field grid nodes : " << fEnodes << RESTendl;
1206 RESTMetadata << "Efield range : ( " << fEmin << " , " << fEmax << " ) V/cm " << RESTendl;
1207 RESTMetadata << "Number of Gases : " << fNofGases << RESTendl;
1208 for (int i = 0; i < fNofGases; i++)
1209 RESTMetadata << "Gas id : " << i << ", Name : " << fGasComponentName[i]
1210 << ", Fraction : " << fGasComponentFraction[i] << RESTendl;
1211 RESTMetadata << "******************************************" << RESTendl;
1212 RESTMetadata << RESTendl;
1213 RESTMetadata << RESTendl;
1214}
1215
1216Int_t TRestDetectorGas::Write(const char* name, Int_t option, Int_t bufsize) {
1217 RESTDebug << "Entering ... TRestDetectorGas::Write( name=" << name << " option=" << option
1218 << " bufsize=" << bufsize << " )" << RESTendl;
1219
1220 if (fGasFileContent == "" && GasFileLoaded()) {
1221 ifstream infile;
1222 infile.open(fGasFilename);
1223 if (!infile) {
1224 cout << "TRestDetectorGas: error reading gas file, gas file content won't be "
1225 "saved!"
1226 << endl;
1227 } else {
1228 string str;
1229 while (getline(infile, str)) {
1230 fGasFileContent += str + "\n";
1231 }
1232 }
1233 }
1234 return TRestMetadata::Write();
1235}
virtual DBEntry query_data(DBEntry info)
void InitFromConfigFile() override
To make settings from rml file. This method must be implemented in the derived class.
virtual void SetElectricField(double value)
Sets the electric field. Must be given in V/mm.
std::string ConstructFilename()
Constructs the filename of the pre-generated gas file using the members defined in the RML file.
void InitFromConfigFile() override
Loads the gas parameters that define the gas calculation and properties.
void InitFromRootFile() override
Method called after the object is retrieved from root file.
TString GetGasComponentName(Int_t n)
Returns the gas component n.
void PrintGasInfo()
Prints the metadata information from the gas.
void PlotTransversalDiffusion(Double_t eMin, Double_t eMax, Int_t nSteps)
It creates a TCanvas where it plots the transversal diffusion as a function of the electric field.
bool GasFileLoaded() const
Returns true if the gas file has been properly loaded. False otherwise.
Double_t GetAttachmentCoefficient(Double_t E)
It returns the attachment coefficient for a given electric field in V/cm.
Double_t GetTransversalDiffusion() override
Returns the transversal diffusion in (cm)^1/2.
TString GetGasMixture()
Returns a string defining the gas components and fractions.
void SetPressure(Double_t pressure) override
Defines the pressure of the gas.
~TRestDetectorGas()
TRestDetectorGas default destructor.
void PlotTownsendCoefficient(Double_t eMin, Double_t eMax, Int_t nSteps)
It creates a TCanvas where it plots the townsend coefficient as a function of the electric field.
TRestDetectorGas()
TRestDetectorGas default constructor.
Double_t GetDriftVelocity() override
Returns the drift velocity in mm/us.
Double_t GetTownsendCoefficient(Double_t E)
It returns the townsend coefficient for a given electric field in V/cm.
void SetTemperature(Double_t temperature) override
Defines the temperature of the gas.
Int_t Write(const char *name=0, Int_t option=0, Int_t bufsize=0) override
overwriting the write() method with fStore considered
void LoadGasFile()
It loads a pre-generated gas file corresponding to the gas defined using the RML TRestDetectorGas sec...
void Initialize() override
Defines the metadata section name and initalizes the TRestDetectorGas members.
void AddGasComponent(std::string gasName, Double_t fraction)
Adds a new element/compound to the gas.
std::string FindGasFile(std::string name)
This method tries to find the gas filename given in the argument.
void PlotDriftVelocity(Double_t eMin, Double_t eMax, Int_t nSteps)
It creates a TCanvas where it plots the drift velocity as a function of the electric field.
void PlotLongitudinalDiffusion(Double_t eMin, Double_t eMax, Int_t nSteps)
It creates a TCanvas where it plots the longitudinal diffusion as a function of the electric field.
void GenerateGasFile()
Save a gas file with a structured file name.
Double_t GetGasComponentFraction(Int_t n)
Returns the gas fraction in volume for component n.
Double_t GetLongitudinalDiffusion() override
Returns the longitudinal diffusion in (cm)^1/2.
virtual void PrintMetadata()
Implemented it in the derived metadata class to print out specific metadata information.
endl_t RESTendl
Termination flag object for TRestStringOutput.
TiXmlElement * GetElement(std::string eleDeclare, TiXmlElement *e=nullptr)
Get an xml element from a given parent element, according to its declaration.
Int_t LoadConfigFromFile(const std::string &configFilename, const std::string &sectionName="")
Give the file name, find out the corresponding section. Then call the main starter.
TRestStringOutput::REST_Verbose_Level fVerboseLevel
Verbose level used to print debug info.
TiXmlElement * StringToElement(std::string definition)
Parsing a string into TiXmlElement object.
void SetLibraryVersion(TString version)
Set the library version of this metadata class.
TRestStringOutput::REST_Verbose_Level GetVerboseLevel()
returns the verboselevel in type of REST_Verbose_Level enumerator
std::string GetFieldValue(std::string parName, TiXmlElement *e)
Returns the field value of an xml element which has the specified name.
virtual void InitFromRootFile()
Method called after the object is retrieved from root file.
Int_t LoadConfigFromElement(TiXmlElement *eSectional, TiXmlElement *eGlobal, std::map< std::string, std::string > envs={})
Main starter method.
void SetSectionName(std::string sName)
set the section name, clear the section content
std::string SearchFile(std::string filename)
Search files in current directory and directories specified in "searchPath" section.
void WriteConfigBuffer(std::string fName)
Writes the config buffer to a file in append mode.
std::string fConfigFileName
Full name of the rml file.
virtual Int_t Write(const char *name=nullptr, Int_t option=0, Int_t bufsize=0)
overwriting the write() method with fStore considered
TiXmlElement * GetNextElement(TiXmlElement *e)
Get the next sibling xml element of this element, with same eleDeclare.
std::string GetParameter(std::string parName, TiXmlElement *e, TString defaultValue=PARAMETER_NOT_FOUND_STR)
Returns the value for the parameter named parName in the given section.
@ REST_Info
+show most of the information for each steps
static std::string GetPureFileName(const std::string &fullPathFileName)
Removes all directories in the full path filename description given in the argument.
static bool fileExists(const std::string &filename)
Returns true if the file (or directory) with path filename exists.
static std::string DownloadRemoteFile(const std::string &remoteFile, bool pidPrefix=false)
download the remote file automatically, returns the downloaded file name.
static bool isPathWritable(const std::string &path)
Returns true if the path given by argument is writable.
static int UploadToServer(std::string localFile, std::string remoteFile, std::string methodUrl="")
Int_t GetChar(std::string hint="Press a KEY to continue ...")
Helps to pause the program, printing a message before pausing.
std::vector< std::string > Split(std::string in, std::string separator, bool allowBlankString=false, bool removeWhiteSpaces=false, int startPos=-1)
Split the input string according to the given separator. Returning a vector of fragments.
Double_t StringToDouble(std::string in)
Gets a double from a string.
std::string ToUpper(std::string in)
Convert string to its upper case. Alternative of TString::ToUpper.
Int_t StringToInteger(std::string in)
Gets an integer from a string.