musrfit 1.10.0
PRgeHandler.cpp
Go to the documentation of this file.
1/***************************************************************************
2
3 PRgeHandler.cpp
4
5 Author: Andreas Suter
6 e-mail: andreas.suter@psi.ch
7
8***************************************************************************/
9
10/***************************************************************************
11 * Copyright (C) 2007-2026 by Andreas Suter *
12 * andreas.suter@psi.ch *
13 * *
14 * This program is free software; you can redistribute it and/or modify *
15 * it under the terms of the GNU General Public License as published by *
16 * the Free Software Foundation; either version 2 of the License, or *
17 * (at your option) any later version. *
18 * *
19 * This program is distributed in the hope that it will be useful, *
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
22 * GNU General Public License for more details. *
23 * *
24 * You should have received a copy of the GNU General Public License *
25 * along with this program; if not, write to the *
26 * Free Software Foundation, Inc., *
27 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
28 ***************************************************************************/
29
30#include <fstream>
31#include <iostream>
32#include <vector>
33#include <string>
34#include <memory>
35#include <cmath>
36
37#include <boost/filesystem.hpp>
38#include <boost/algorithm/string.hpp>
39
40#include <TXMLAttr.h>
41#include "PRgeHandler.h"
42
44
45//--------------------------------------------------------------------------
46// OnStartDocument
47//--------------------------------------------------------------------------
55{
56 fKey = eEmpty;
57}
58
59//--------------------------------------------------------------------------
60// OnEndDocument
61//--------------------------------------------------------------------------
73{
74 if (!fIsValid)
75 return;
76
77 // check if anything was set
78 if (fTrimSpDataPath.empty()) {
79 std::string err = "<data_path> content is missing!";
80 fIsValid = false;
81 OnError(err.c_str());
82 }
83 if (fTrimSpFlnPre.empty()) {
84 std::string err = "<rge_fln_pre> content is missing!";
85 fIsValid = false;
86 OnError(err.c_str());
87 }
88 if (fTrimSpDataEnergyList.size()==0) {
89 std::string err = "no implantation energies present!";
90 fIsValid = false;
91 OnError(err.c_str());
92 }
93}
94
95//--------------------------------------------------------------------------
96// OnStartElement
97//--------------------------------------------------------------------------
113void PXmlRgeHandler::OnStartElement(const Char_t *str, const TList *attributes)
114{
115 if (!strcmp(str, "trim_sp")) {
116 isTrimSp=true;
117 } else if (!strcmp(str, "data_path") && isTrimSp) {
118 fKey = eDataPath;
119 } else if (!strcmp(str, "rge_fln_pre") && isTrimSp) {
120 fKey = eFlnPre;
121 } else if (!strcmp(str, "energy") && isTrimSp) {
122 fKey = eEnergy;
123 } else if (!strcmp(str, "energy_vect") && isTrimSp) {
124 std::string msg("");
125 if (attributes == nullptr) {
126 fIsValid = false;
127 msg = "Found energy_list without attributes";
128 OnError(msg.c_str());
129 return;
130 }
131 if (attributes->GetEntries() != 3) {
132 fIsValid = false;
133 msg = "energy_list: expect 3 attributes (start, stop, step), found " + std::to_string(attributes->GetEntries());
134 OnError(msg.c_str());
135 return;
136 }
137
138 TXMLAttr *attr;
139
140 int start=-1, stop=-1, step=-1, ival;
141 TIter next(attributes);
142 while ((attr = (TXMLAttr*) next())) {
143 char sval[256];
144 strncpy(sval, attr->GetValue(), sizeof(sval));
145 try {
146 ival = std::stoi(sval);
147 } catch(std::invalid_argument& e) {
148 fIsValid = false;
149 msg = "The found energy_list attribute '" + std::string(sval) + "' which is not a number";
150 OnError(msg.c_str());
151 return;
152 } catch(std::out_of_range& e) {
153 fIsValid = false;
154 msg = "The found energy_list attribute '" + std::string(sval) + "' which is out-of-range.";
155 OnError(msg.c_str());
156 return;
157 } catch(...) {
158 fIsValid = false;
159 msg = "The found energy_list attribute '" + std::string(sval) + "' which generates an error.";
160 OnError(msg.c_str());
161 return;
162 }
163 if (!strcmp(attr->GetName(), "start")) {
164 start = ival;
165 } else if (!strcmp(attr->GetName(), "stop")) {
166 stop = ival;
167 } else if (!strcmp(attr->GetName(), "step")) {
168 step = ival;
169 }
170 }
171 // make sure I do have start, stop, and step values set
172 if ((start == -1) || (stop == -1) || (step == -1)) {
173 fIsValid = false;
174 msg = "Found energy_list with missing attributes. Needed start, stop and step.";
175 OnError(msg.c_str());
176 return;
177 }
178 // more checks: start < stop, and step > 0.
179 if ((start > stop)) {
180 fIsValid = false;
181 msg = "Found energy_list with start > stop. Not allowed in the context.";
182 OnError(msg.c_str());
183 return;
184 }
185 if (step < 0) {
186 fIsValid = false;
187 msg = "Found energy_list with step < 0. Not allowed in the context.";
188 OnError(msg.c_str());
189 return;
190 }
191 // generate the fTrimSpDataEnergyList vector
192 ival = start;
193 do {
194 fTrimSpDataEnergyList.push_back(ival);
195 ival += step;
196 } while (ival <= stop);
197 }
198}
199
200//--------------------------------------------------------------------------
201// OnEndElement
202//--------------------------------------------------------------------------
211void PXmlRgeHandler::OnEndElement(const Char_t *str)
212{
213 if (!strcmp(str, "trim_sp")) {
214 isTrimSp=false;
215 }
216
217 fKey = eEmpty;
218}
219
220//--------------------------------------------------------------------------
221// OnCharacters
222//--------------------------------------------------------------------------
236void PXmlRgeHandler::OnCharacters(const Char_t *str)
237{
238 int ival;
239 std::string msg(""), sstr(str);
240 size_t pos;
241
242 switch(fKey) {
243 case eDataPath:
244 fTrimSpDataPath=str;
245 break;
246 case eFlnPre:
247 fTrimSpFlnPre=str;
248 break;
249 case eEnergy:
250 try {
251 ival = std::stoi(str, &pos);
252 } catch(std::invalid_argument& e) {
253 fIsValid = false;
254 msg = "The found energy '" + sstr + "' which is not a number";
255 OnError(msg.c_str());
256 } catch(std::out_of_range& e) {
257 fIsValid = false;
258 msg = "The found energy '" + sstr + "' which is out-of-range.";
259 OnError(msg.c_str());
260 } catch(...) {
261 fIsValid = false;
262 msg = "The found energy '" + sstr + "' which generates an error.";
263 OnError(msg.c_str());
264 }
265 if (pos != sstr.length()) {
266 fIsValid = false;
267 msg = "The found energy '" + sstr + "' which is not an integer";
268 OnError(msg.c_str());
269 }
270 fTrimSpDataEnergyList.push_back(ival);
271 break;
272 default:
273 break;
274 }
275}
276
277//--------------------------------------------------------------------------
278// OnComment
279//--------------------------------------------------------------------------
287void PXmlRgeHandler::OnComment(const Char_t *str)
288{
289 // nothing to be done for now
290}
291
292//--------------------------------------------------------------------------
293// OnWarning
294//--------------------------------------------------------------------------
302void PXmlRgeHandler::OnWarning(const Char_t *str)
303{
304 std::cerr << std::endl << "PXmlRgeHandler **WARNING** " << str;
305 std::cerr << std::endl;
306}
307
308//--------------------------------------------------------------------------
309// OnError
310//--------------------------------------------------------------------------
319void PXmlRgeHandler::OnError(const Char_t *str)
320{
321 std::cerr << std::endl << "PXmlRgeHandler **ERROR** " << str;
322 std::cerr << std::endl;
323}
324
325//--------------------------------------------------------------------------
326// OnFatalError
327//--------------------------------------------------------------------------
335void PXmlRgeHandler::OnFatalError(const Char_t *str)
336{
337 std::cerr << std::endl << "PXmlRgeHandler **FATAL ERROR** " << str;
338 std::cerr << std::endl;
339}
340
341//--------------------------------------------------------------------------
342// OnCdataBlock
343//--------------------------------------------------------------------------
352void PXmlRgeHandler::OnCdataBlock(const Char_t *str, Int_t len)
353{
354 // nothing to be done for now
355}
356
357//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
358
360
361//--------------------------------------------------------------------------
362// Ctor
363//--------------------------------------------------------------------------
378PRgeHandler::PRgeHandler(const std::string fln)
379{
380 // make sure there is an xml-startup file name
381 if (fln.empty()) { // fln not given
382 std::cerr << std::endl;
383 std::cerr << "**ERROR** NO xml file name provided." << std::endl;
384 std::cerr << std::endl;
385 fValid=false;
386 return;
387 }
388
389 // read the startup xml-file to extract the necessary rge infos.
390 if (!boost::filesystem::exists(fln)) {
391 std::cerr << std::endl;
392 std::cerr << "**ERROR** xml file named: " << fln << " does not exist." << std::endl;
393 std::cerr << std::endl;
394 fValid=false;
395 return;
396 }
397
398 // create the rge xml handler
399 std::unique_ptr<PXmlRgeHandler> xmlRge = std::make_unique<PXmlRgeHandler>();
400 if (xmlRge == nullptr) {
401 std::cerr << std::endl;
402 std::cerr << "**ERROR** couldn't invoke PXmlRgeHandler." << std::endl;
403 std::cerr << std::endl;
404 fValid=false;
405 return;
406 }
407
408 // create the SAX parser
409 std::unique_ptr<TSAXParser> saxParser = std::make_unique<TSAXParser>();
410 if (saxParser == nullptr) {
411 std::cerr << std::endl;
412 std::cerr << "**ERROR** couldn't invoke TSAXParser." << std::endl;
413 std::cerr << std::endl;
414 fValid=false;
415 return;
416 }
417 saxParser->SetStopOnError();
418
419 // connect SAX parser and rge handler
420 saxParser->ConnectToHandler("PXmlRgeHandler", xmlRge.get());
421 int status = saxParser->ParseFile(fln.c_str());
422 if (status != 0) {
423 std::cerr << std::endl;
424 std::cerr << "**ERROR** parsing the xml-file: " << fln << "." << std::endl;
425 std::cerr << std::endl;
426 fValid=false;
427 return;
428 }
429 if (xmlRge->IsValid())
430 fValid = true;
431 else
432 fValid = false;
433
434 // read the rge-file(s) content if everything went fine so far
435 std::string rgeFln;
436 PRgeData dataSet;
437 if (fValid) {
438 const PIntVector energy = xmlRge->GetTrimSpDataVectorList();
439 for (int i=0; i<energy.size(); i++) {
440 // construct the file name
441 rgeFln = xmlRge->GetTrimSpDataPath();
442 if (rgeFln[rgeFln.size()-1] != '/')
443 rgeFln += "/";
444 rgeFln += xmlRge->GetTrimSpFlnPre();
445 rgeFln += std::to_string(energy[i]);
446 rgeFln += ".rge";
447 if (!boost::filesystem::exists(rgeFln)) {
448 fValid = false;
449 std::cerr << std::endl;
450 std::cerr << "**ERROR** rge-file: " << rgeFln << " not found." << std::endl;
451 std::cerr << std::endl;
452 break;
453 }
454 // init data set
455 dataSet.energy = energy[i];
456 dataSet.depth.clear();
457 dataSet.amplitude.clear();
458 if (!ReadRgeFile(rgeFln, dataSet)) {
459 fValid = false;
460 std::cerr << std::endl;
461 std::cerr << "**ERROR** read error in rge-file: " << rgeFln << " not found." << std::endl;
462 std::cerr << std::endl;
463 break;
464 }
465
466 // get the total number of particles
467 double tot=0.0;
468 for (int j=0; j<dataSet.amplitude.size(); j++)
469 tot += dataSet.amplitude[j];
470 dataSet.noOfParticles = tot;
471
472 // sum_j nn dzz == 1, (dzz_j = depth[j]-depth[j-1])
473 dataSet.nn.resize(dataSet.amplitude.size());
474 tot = 0.0;
475 double zz=0.0; // "previous" zz (since depth[j]-depth[j-1] != const) it needs to be done this way.
476 for (int j=0; j<dataSet.nn.size(); j++) {
477 tot += dataSet.amplitude[j] * (dataSet.depth[j] - zz);
478 zz = dataSet.depth[j];
479 }
480 for (int j=0; j<dataSet.nn.size(); j++) {
481 dataSet.nn[j] = dataSet.amplitude[j] / tot;
482 }
483
484 fData.push_back(dataSet);
485 }
486 }
487}
488
489//--------------------------------------------------------------------------
490// ReadRgeFile
491//--------------------------------------------------------------------------
506bool PRgeHandler::ReadRgeFile(const std::string fln, PRgeData &data)
507{
508 std::ifstream fin(fln);
509 if (!fin.is_open())
510 return false;
511
512 std::string line, msg;
513 std::vector<std::string> tok;
514 Double_t zz, nn;
515 size_t pos;
516 int lineNo=0;
517
518 while (fin.good() && fValid) {
519 std::getline(fin, line);
520 lineNo++;
521 boost::algorithm::trim(line);
522 if (line.empty())
523 continue;
524 if (!std::isdigit(line[0]))
525 continue;
526 tok.clear();
527 boost::algorithm::split(tok, line, boost::algorithm::is_any_of(" \t"), boost::algorithm::token_compress_on);
528 if (tok.size() != 2) {
529 std::cerr << std::endl;
530 std::cerr << "**ERROR** in rge-file: " << fln << ", unexpected number of tokens (" << tok.size() << ")." << std::endl;
531 std::cerr << std::endl;
532 fin.close();
533 return false;
534 }
535 // check distance
536 try {
537 zz = std::stod(tok[0], &pos);
538 } catch(std::invalid_argument& e) {
539 fValid = false;
540 msg = "The found depth '" + tok[0] + "' which is not a number";
541 std::cerr << std::endl;
542 std::cerr << "**ERROR** in rge-file: " << fln << ": lineNo: " << lineNo << std::endl;
543 std::cerr << " " << msg << std::endl;
544 std::cerr << std::endl;
545 } catch(std::out_of_range& e) {
546 fValid = false;
547 msg = "The found depth '" + tok[0] + "' which is out-of-range.";
548 std::cerr << std::endl;
549 std::cerr << "**ERROR** in rge-file: " << fln << ": lineNo: " << lineNo << std::endl;
550 std::cerr << " " << msg << std::endl;
551 std::cerr << std::endl;
552 } catch(...) {
553 fValid = false;
554 msg = "The found depth '" + tok[0] + "' which generates an error.";
555 std::cerr << std::endl;
556 std::cerr << "**ERROR** in rge-file: " << fln << ": lineNo: " << lineNo << std::endl;
557 std::cerr << " " << msg << std::endl;
558 std::cerr << std::endl;
559 }
560 if (pos != tok[0].length()) {
561 fValid = false;
562 msg = "The found depth '" + tok[0] + "' which is not an number.";
563 std::cerr << std::endl;
564 std::cerr << "**ERROR** in rge-file: " << fln << ": lineNo: " << lineNo << std::endl;
565 std::cerr << " " << msg << std::endl;
566 std::cerr << std::endl;
567 }
568 // check number of implanted particles
569 try {
570 nn = std::stod(tok[1], &pos);
571 } catch(std::invalid_argument& e) {
572 fValid = false;
573 msg = "The found #particles '" + tok[1] + "' which is not a number";
574 std::cerr << std::endl;
575 std::cerr << "**ERROR** in rge-file: " << fln << ": lineNo: " << lineNo << std::endl;
576 std::cerr << " " << msg << std::endl;
577 std::cerr << std::endl;
578 } catch(std::out_of_range& e) {
579 fValid = false;
580 msg = "The found #particles '" + tok[1] + "' which is out-of-range.";
581 std::cerr << std::endl;
582 std::cerr << "**ERROR** in rge-file: " << fln << ": lineNo: " << lineNo << std::endl;
583 std::cerr << " " << msg << std::endl;
584 std::cerr << std::endl;
585 } catch(...) {
586 fValid = false;
587 msg = "The found #particles '" + tok[1] + "' which generates an error.";
588 std::cerr << std::endl;
589 std::cerr << "**ERROR** in rge-file: " << fln << ": lineNo: " << lineNo << std::endl;
590 std::cerr << " " << msg << std::endl;
591 std::cerr << std::endl;
592 }
593 if (pos != tok[1].length()) {
594 fValid = false;
595 msg = "The found #particles '" + tok[1] + "' which is not an integer.";
596 std::cerr << std::endl;
597 std::cerr << "**ERROR** in rge-file: " << fln << ": lineNo: " << lineNo << std::endl;
598 std::cerr << " " << msg << std::endl;
599 std::cerr << std::endl;
600 }
601 data.depth.push_back(zz/10.0); // distance in nm
602 data.amplitude.push_back(nn);
603 }
604
605 fin.close();
606
607 return true;
608}
609
610//--------------------------------------------------------------------------
611// GetZmax via energy
612//--------------------------------------------------------------------------
622Double_t PRgeHandler::GetZmax(const Double_t energy)
623{
624 int idx=-1;
625 for (int i=0; i<fData.size(); i++) {
626 if (fabs(fData[i].energy-energy)*0.001 < 0.9){
627 idx = i;
628 break;
629 }
630 }
631
632 if (idx != -1)
633 return GetZmax(idx);
634
635 return -1;
636}
637
638//--------------------------------------------------------------------------
639// GetZmax via index
640//--------------------------------------------------------------------------
650Double_t PRgeHandler::GetZmax(const Int_t idx)
651{
652 if ((idx < 0) || (idx >= fData.size()))
653 return -1.0;
654
655 return fData[idx].depth[fData[idx].depth.size()-1];
656}
657
658//--------------------------------------------------------------------------
659// Get_n via energy
660//--------------------------------------------------------------------------
671Double_t PRgeHandler::Get_n(const Double_t energy, const Double_t z)
672{
673 int idx=-1;
674 for (int i=0; i<fData.size(); i++) {
675 if (fabs(fData[i].energy-energy)*0.001 < 0.90) {
676 idx = i;
677 break;
678 }
679 }
680 if (idx == -1)
681 return 0.0;
682
683 return Get_n(idx, z);
684}
685
686//--------------------------------------------------------------------------
687// Get_n via index
688//--------------------------------------------------------------------------
702Double_t PRgeHandler::Get_n(const Int_t idx, const Double_t z)
703{
704 if ((idx < 0) || (idx >= fData.size()))
705 return 0.0;
706
707 if ((z < 0.0) || (z > GetZmax(idx)))
708 return 0.0;
709
710 int pos=0;
711 for (int i=0; i<fData[idx].depth.size(); i++) {
712 if (z <= fData[idx].depth[i]) {
713 pos = i-1;
714 break;
715 }
716 }
717
718 Double_t nn=0.0;
719 if (pos < 0) {
720 nn = fData[idx].nn[0] * z/(fData[idx].depth[1]-fData[idx].depth[0]);
721 } else { // linear interpolation
722 nn = fData[idx].nn[pos] +
723 (fData[idx].nn[pos+1] - fData[idx].nn[pos]) *
724 (z-fData[idx].depth[pos])/(fData[idx].depth[pos+1]-fData[idx].depth[pos]);
725 }
726
727 return nn;
728}
729
730//--------------------------------------------------------------------------
731// GetEnergyIndex
732//--------------------------------------------------------------------------
742Int_t PRgeHandler::GetEnergyIndex(const Double_t energy)
743{
744 int idx=-1;
745 for (int i=0; i<fData.size(); i++) {
746 if (fabs(fData[i].energy-energy)*0.001 < 0.90) {
747 idx = i;
748 break;
749 }
750 }
751
752 return idx;
753}
std::vector< Int_t > PIntVector
Definition PMusr.h:367
ClassImp(PRgeHandler) PRgeHandler
Constructor that loads TrimSP range distribution data.
ClassImpQ(PXmlRgeHandler) void PXmlRgeHandler
SAX callback invoked at the start of XML document parsing.
return status
Manager for TrimSP range distribution data.
virtual Double_t Get_n(const Double_t energy, const Double_t z)
Returns normalized particle distribution at given energy and depth.
PRgeHandler(std::string fln="")
Constructor that loads TrimSP data from XML configuration.
virtual bool ReadRgeFile(const std::string fln, PRgeData &data)
Reads a single RGE file and populates a PRgeData structure.
bool fValid
Validity flag (true if all RGE files loaded successfully)
virtual Double_t GetZmax(const Double_t energy)
Returns maximum penetration depth for a given energy.
virtual Int_t GetEnergyIndex(const Double_t energy)
Finds the data set index for a given energy.
PRgeDataList fData
Collection of RGE data sets (one per energy)
XML SAX parser handler for TrimSP configuration files.
Definition PRgeHandler.h:98
bool isTrimSp
True when inside <trim_sp> element.
std::string fTrimSpFlnPre
RGE filename prefix (e.g., "LCCO_E" for LCCO_E1000.rge)
virtual void OnCdataBlock(const char *str, Int_t len)
Called for CDATA blocks (SLOT)
virtual void OnEndElement(const char *str)
Called when XML end tag is encountered (SLOT)
virtual void OnComment(const char *str)
Called for XML comments (SLOT)
std::string fTrimSpDataPath
Directory path to RGE files.
virtual void OnStartElement(const char *str, const TList *attributes)
Called when XML start tag is encountered (SLOT)
virtual void OnCharacters(const char *str)
Called for element content between tags (SLOT)
virtual void OnStartDocument()
Called at start of XML document parsing (SLOT)
PIntVector fTrimSpDataEnergyList
List of implantation energies in eV.
virtual void OnFatalError(const char *str)
Called when parser encounters a fatal error (SLOT)
bool fIsValid
Validity flag (false if parsing errors occur)
virtual void OnEndDocument()
Called at end of XML document parsing, performs validation (SLOT)
virtual void OnWarning(const char *str)
Called when parser emits a warning (SLOT)
virtual void OnError(const char *str)
Called when parser encounters an error (SLOT)
EKeyWords fKey
Current parsing context/state.
Data structure for a single TrimSP range distribution at a given energy.
Definition PRgeHandler.h:54
PDoubleVector amplitude
Number of particles at each depth (raw counts from TrimSP)
Definition PRgeHandler.h:57
Double_t noOfParticles
Total number of particles (sum of amplitudes)
Definition PRgeHandler.h:59
PDoubleVector nn
Normalized particle density where ∫nn(z)dz = 1.
Definition PRgeHandler.h:58
Double_t energy
Implantation energy in eV.
Definition PRgeHandler.h:55
PDoubleVector depth
Depth values in nanometers (nm)
Definition PRgeHandler.h:56