musrfit 1.12.1
msr2data.cpp
Go to the documentation of this file.
1/***************************************************************************
2
3 msr2data.cpp
4
5 Author: Bastian M. Wojek / Andreas Suter
6 e-mail: andreas.suter@psi.ch
7
8***************************************************************************/
9
10/***************************************************************************
11 * Copyright (C) 2009-2026 by Bastian M. Wojek / 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// note: msr2data is on purpose implemented in a way that shows string handling can be done solely
31// using std::string, boost and related standard C++ features
32// This implies, however, occasionally strange constructs when interoperating with PMusr-classes
33// which mostly rely on ROOT's TString.
34
35#ifdef HAVE_CONFIG_H
36#include "config.h"
37#endif
38
39#ifdef HAVE_GIT_REV_H
40#include "git-revision.h"
41#endif
42
43#include "PMusr.h"
44#include "PMsr2Data.h"
45
46#include <algorithm>
47#include <sstream>
48#include <iostream>
49#include <fstream>
50#include <cstdlib>
51#include <limits>
52#include <string>
53#include <memory>
54
55#include <boost/algorithm/string.hpp>
56#include <boost/algorithm/string/case_conv.hpp> // for to_lower() in std::string
57
58#include <boost/lexical_cast.hpp> // for atoi-replacement
59
60//--------------------------------------------------------------------------
70bool isNumber(const std::string &s)
71{
72 unsigned int number(0);
73 try {
74 number = boost::lexical_cast<unsigned int>(s);
75 return true;
76 }
77 catch(boost::bad_lexical_cast &) {
78 return false;
79 }
80}
81
82//--------------------------------------------------------------------------
87{
88 std::cout << std::endl << "usage 0: msr2data [--version] | [--help]";
89 std::cout << std::endl << "usage 1: msr2data <run> <extension> options";
90 std::cout << std::endl << "usage 2: msr2data <run1> <run2> <extension> options";
91 std::cout << std::endl << "usage 3: msr2data \\[<runList>\\] <extension> options";
92 std::cout << std::endl << "usage 4: msr2data <runListFileName> <extension> options";
93 std::cout << std::endl;
94 std::cout << std::endl << " <runList> can be:";
95 std::cout << std::endl << " (i) <run0>, <run1>, <run2>, ... <runN> : run numbers, e.g. 123 124";
96 std::cout << std::endl << " (ii) <run0>-<runN> : a range, e.g. 123-125 -> 123 124 125";
97 std::cout << std::endl << " (iii) <run0>:<runN>:<step> : a sequence, e.g. 123:127:2 -> 123 125 127";
98 std::cout << std::endl << " <step> will give the step width and has to be a positive number!";
99 std::cout << std::endl << " a <runList> can also combine (i)-(iii), e.g. 123 128-130 133, etc.";
100 std::cout << std::endl << " <runListFileName> : an ASCII file containing a list of run numbers and optional";
101 std::cout << std::endl << " external parameters is passed to msr2data. For details see";
102 std::cout << std::endl << " the online documentation: http://lmu.web.psi.ch/musrfit/user/MUSR/Msr2Data.html";
103 std::cout << std::endl << " <extension> : msr-file extension, e.g. _tf_h13 for the file name 8472_tf_h13.msr";
104 std::cout << std::endl;
105 std::cout << std::endl << "options:";
106 std::cout << std::endl << " -o<outputfile> : specify the name of the DB or column-data output file; default: out.db/out.dat";
107 std::cout << std::endl << " if the option '-o none' is used, no output file will be written.";
108 std::cout << std::endl << " new : before writing a new output file, delete the contents of any existing file with the same name";
109 std::cout << std::endl << " data : instead of to a DB file the data are written to a simple column structure";
110 std::cout << std::endl << " header : force writing of the file header to the output file";
111 std::cout << std::endl << " noheader : no file header is written to the output file";
112 std::cout << std::endl << " If either none or both of the header options are given, the file header will be written";
113 std::cout << std::endl << " if a new file is created, but not if the output file exists already!";
114 std::cout << std::endl << " nosummary : no additional data from the run data file is written to the output file";
115 std::cout << std::endl << " paramList <param> : option used to select the parameters which shall be exported.";
116 std::cout << std::endl << " <param> is a list of parameter numbers to be exported. Allowed lists are:";
117 std::cout << std::endl << " 1-16 will export parameters 1 to 16. 1 3 5 will export parameters 1 3 5.";
118 std::cout << std::endl << " A combination of both is possible, e.g. 1-16 19 31 62, and so on.";
119 std::cout << std::endl << " fit : invoke musrfit to fit the specified runs";
120 std::cout << std::endl << " All msr input files are assumed to be present, none is newly generated!";
121 std::cout << std::endl << " fit-<template>! : generate msr files for the runs to be processed from the <template> run";
122 std::cout << std::endl << " and call musrfit for fitting these runs";
123 std::cout << std::endl << " fit-<template> : same as above, but the <template> run is only used for the first file creation---";
124 std::cout << std::endl << " the successive files are generated using the musrfit output from the preceding runs";
125 std::cout << std::endl << " msr-<template> : same as above without calling musrfit";
126 std::cout << std::endl << " In case any fitting option is present, this option is ignored!";
127 std::cout << std::endl << " -k, --keep-mn2-output : if fitting is used, pass the option --keep-mn2-output to musrfit";
128 std::cout << std::endl << " -t, --title-from-data-file : if fitting is used, pass the option --title-from-data-file to musrfit";
129 std::cout << std::endl << " -e, --estimateN0: estimate N0 for single histogram fits.";
130 std::cout << std::endl << " -y, --yaml: write fit results (MINUIT2.OUTPUT) into a yaml-file. Output <msr-file>.yaml";
131 std::cout << std::endl << " -p, --per-run-block-chisq: will per run block chisq to the msr-file.";
132 std::cout << std::endl << " -u, --use-no-of-threads <number>: if fitting is used, pass the option --use-no-of-threads <number> to musrfit";
133 std::cout << std::endl << " <number>: number of threads to be used (OpenMP). Needs to be <= max. number of cores.";
134 std::cout << std::endl;
135 std::cout << std::endl << " global : switch on the global-fit mode";
136 std::cout << std::endl << " Within that mode all specified runs will be united in a single msr file!";
137 std::cout << std::endl << " The fit parameters can be either run specific or common to all runs.";
138 std::cout << std::endl << " For a complete description of this feature please refer to the manual.";
139 std::cout << std::endl;
140 std::cout << std::endl << " global+[!] : operate in the global-fit mode, however, in case a global input file is created";
141 std::cout << std::endl << " all specified runs are pre-analyzed first one by one using the given template.";
142 std::cout << std::endl << " For the generation of the global input file, the run-specific parameter values are taken";
143 std::cout << std::endl << " from this pre-analysis for each run---they are not just copied from the template.";
144 std::cout << std::endl << " The specification of '!' determines which fit mode (see above) is used for this pre-analysis.";
145 std::cout << std::endl;
146 std::cout << std::endl << " Typical examples:";
147 std::cout << std::endl;
148 std::cout << std::endl << " msr2data 2047 2050 _tf_histo fit-2046";
149 std::cout << std::endl << " will use 2046_tf_histo.msr as templete, and subsequently generating 2047_tf_histo.msr until";
150 std::cout << std::endl << " 2050_tf_histo.msr and fit them.";
151 std::cout << std::endl;
152 std::cout << std::endl << " msr2data 2047 2050 _tf_histo msr-2046";
153 std::cout << std::endl << " will use 2046_tf_histo.msr as templete, and subsequently generating 2047_tf_histo.msr until";
154 std::cout << std::endl << " 2050_tf_histo.msr, but NO fitting will be done.";
155 std::cout << std::endl;
156 std::cout << std::endl << " msr2data 2046 2050 _tf_histo -o fitParam.db";
157 std::cout << std::endl << " will collect the fit parameters from runs 2046-2050 (msr-files 2046_tf_histo.msr etc.) and";
158 std::cout << std::endl << " write them to the file fitParam.db (DB-format).";
159 std::cout << std::endl;
160 std::cout << std::endl << " msr2data [2047:2053:2 2056] _tf_histo fit-2045";
161 std::cout << std::endl << " will use 2045_tf_histo.msr as templete, and subsequently generating msr-files from the run-list:";
162 std::cout << std::endl << " 2047 2049 2051 2053 2056 (2047_tf_histo.msr etc.) and fit them.";
163 std::cout << std::endl;
164 std::cout << std::endl << " msr2data 2046 2058 _tf_histo paramList 1-12 data -o fitParam.dat";
165 std::cout << std::endl << " will export the parameters number 1 trough 12 in a column like fashion of the runs 2046 to 2058,";
166 std::cout << std::endl << " collected form the msr-files 2046_tf_histo.msr and so on.";
167 std::cout << std::endl;
168 std::cout << std::endl << " For further information please refer to";
169 std::cout << std::endl << " http://lmu.web.psi.ch/musrfit/user/html/msr2data.html#msr2data";
170 std::cout << std::endl << std::endl;
171}
172
173//--------------------------------------------------------------------------
184std::string msr2data_validArguments(const std::vector<std::string> &arg)
185{
186 std::string word;
187
188 for (std::vector<std::string>::const_iterator iter(arg.begin()); iter != arg.end(); ++iter) {
189 if ( (!iter->compare("header")) || (!iter->compare("noheader")) || (!iter->compare("nosummary")) \
190 || (!iter->substr(0,3).compare("fit")) || (!iter->compare("-k")) || (!iter->compare("--keep-mn2-output")) \
191 || (!iter->compare("-t")) || (!iter->compare("--title-from-data-file")) \
192 || (!iter->compare("-e")) || (!iter->compare("--estimateN0")) \
193 || (!iter->compare("-y") || (!iter->compare("--yaml"))) \
194 || (!iter->compare("-p")) || (!iter->compare("--per-run-block-chisq")) \
195 || (!iter->compare("data")) || (!iter->substr(0,4).compare("msr-")) || (!iter->compare("global")) \
196 || (!iter->compare("global+")) || (!iter->compare("global+!")) || (!iter->compare("new")) \
197 || !iter->compare("paramList") )
198 word.clear();
199 else if (!iter->substr(0,2).compare("-o")) {
200 word.clear();
201 if (!iter->compare("-o")) {
202 // the next argument is the output file name, unless it is the -u option (which takes its own <number>)
203 std::vector<std::string>::const_iterator iterNext(iter + 1);
204 if (iterNext == arg.end())
205 break;
206 else if ((iterNext->compare("-u")) && (iterNext->compare("--use-no-of-threads")))
207 ++iter;
208 continue;
209 }
210 } else if ((!iter->compare("-u")) || (!iter->compare("--use-no-of-threads"))) {
211 word.clear();
212 if (++iter == arg.end()) // <number> is checked later in msr2data_noOfThreads
213 break;
214 else
215 continue;
216 } else {
217 word = *iter;
218 break;
219 }
220 }
221
222 return word;
223
224}
225
226//--------------------------------------------------------------------------
237std::string msr2data_outputfile(std::vector<std::string> &arg, bool db = true)
238{
239 std::string outputFile;
240 if (db)
241 outputFile = "out.db";
242 else
243 outputFile = "out.dat";
244
245 std::vector<std::string>::iterator iterNext(arg.begin());
246 for (std::vector<std::string>::iterator iter(arg.begin()); iter != arg.end(); ++iter) {
247 iterNext = iter + 1;
248 if (!iter->substr(0,2).compare("-o")) {
249 if (!iter->compare("-o")) {
250 if ((iterNext != arg.end()) && (iterNext->compare("header")) && (iterNext->compare("noheader")) && (iterNext->compare("nosummary")) \
251 && (iterNext->substr(0,3).compare("fit")) && (iterNext->compare("-k")) && (iterNext->compare("-t")) \
252 && (iterNext->compare("-e")) && (iterNext->compare("-p")) \
253 && (iterNext->compare("-u")) && (iterNext->compare("--use-no-of-threads")) \
254 && (iterNext->compare("data")) && (iterNext->substr(0,3).compare("msr")) && (iterNext->compare("global")) \
255 && (iterNext->compare("global+")) && (iterNext->compare("global+!")) && (iterNext->compare("new"))) {
256 outputFile = *iterNext;
257 arg.erase(iterNext);
258 arg.erase(iter);
259 break;
260 } else {
261 std::cout << std::endl;
262 std::cout << ">> msr2data: **WARNING** You did not specify an output file! The default one (" << outputFile << ") will be used." << std::endl;
263 arg.erase(iter);
264 break;
265 }
266 } else {
267 outputFile = iter->substr(2);
268 arg.erase(iter);
269 break;
270 }
271 }
272 }
273
274 return outputFile;
275}
276
277//--------------------------------------------------------------------------
288bool msr2data_useOption(std::vector<std::string> &arg, const std::string &s)
289{
290 bool option(true);
291
292 std::vector<std::string>::iterator iter;
293 iter = find(arg.begin(), arg.end(), s);
294
295 if (iter != arg.end()) {
296 option = false;
297 arg.erase(iter);
298 }
299 return option;
300}
301
302//--------------------------------------------------------------------------
315int msr2data_noOfThreads(std::vector<std::string> &arg)
316{
317 std::vector<std::string>::iterator iter;
318 iter = find(arg.begin(), arg.end(), "-u");
319 if (iter == arg.end())
320 iter = find(arg.begin(), arg.end(), "--use-no-of-threads");
321 if (iter == arg.end())
322 return 0;
323
324 std::vector<std::string>::iterator iterNext(iter + 1);
325 if (iterNext == arg.end()) {
326 std::cerr << std::endl << ">> msr2data: **ERROR** found option --use-no-of-threads without <number>" << std::endl;
327 return -1;
328 }
329
330 if (!isNumber(*iterNext)) {
331 std::cerr << std::endl << ">> msr2data: **ERROR** found option --use-no-of-threads where <number> is not a number: '" << *iterNext << "'" << std::endl;
332 return -1;
333 }
334
335 int noOfThreads(0);
336 try {
337 noOfThreads = boost::lexical_cast<int>(*iterNext);
338 } catch (boost::bad_lexical_cast &) {
339 noOfThreads = 0;
340 }
341 if (noOfThreads <= 0) {
342 std::cerr << std::endl << ">> msr2data: **ERROR** found option --use-no-of-threads with <number> <= 0" << std::endl;
343 return -1;
344 }
345
346 // remove the option and its <number> from the argument list
347 arg.erase(iter, iterNext + 1);
348
349 return noOfThreads;
350}
351
352//--------------------------------------------------------------------------
367int msr2data_doFitting(std::vector<std::string> &arg, bool &chainfit)
368{
369 int temp(0);
370
371 std::string s;
372 std::vector<std::string>::iterator iter(arg.begin());
373 while (iter != arg.end()) {
374 if (!iter->compare("fit")) { // fit found
375 if (temp) { // temp already found previously
376 return -2; // fatal error - another fit-<temp> option is specified
377 }
378 temp = -1; // fit only, do not prepare input files
379 chainfit = false;
380 iter = arg.erase(iter);
381 }
382 else if (!iter->substr(0,4).compare("fit-")) { // 'fit-' found
383 if (temp) {
384 return -2; // fatal error - another fit option is specified
385 }
386 s = iter->substr(4);
387 std::string::size_type loc = s.rfind('!');
388 if (loc != std::string::npos) {
389 chainfit = false;
390 s.erase(loc);
391 }
392 else
393 chainfit = true;
394 try {
395 temp = boost::lexical_cast<int>(s);
396 arg.erase(iter);
397 }
398 catch(boost::bad_lexical_cast &) {
399 return -3; // the specified template is no number
400 }
401 } else {
402 ++iter;
403 }
404 }
405
406 return temp;
407}
408
409//--------------------------------------------------------------------------
420int msr2data_doInputCreation(std::vector<std::string> &arg, bool &inputOnly)
421{
422 int temp(0);
423
424 std::string s;
425 for (std::vector<std::string>::iterator iter(arg.begin()); iter != arg.end(); ++iter) {
426 if (!iter->substr(0,4).compare("msr-")) {
427 s = iter->substr(4);
428 try {
429 temp = boost::lexical_cast<int>(s);
430 arg.erase(iter);
431 }
432 catch(boost::bad_lexical_cast &) {
433 temp = -3; // the specified template is no number
434 }
435 inputOnly = true;
436 break;
437 }
438 }
439
440 return temp;
441}
442
443//--------------------------------------------------------------------------
448int msr2data_paramList(std::vector<std::string> &arg, std::vector<unsigned int> &paramList)
449{
450 paramList.clear(); // make sure paramList is empty
451
452 unsigned int idx=0;
453 // check if paramList tag is present
454 for (unsigned int i=0; i<arg.size(); i++) {
455 if (!arg[i].compare("paramList")) {
456 idx = i+1;
457 break;
458 }
459 }
460
461 if (idx == 0) { // paramList tag NOT present
462 return 0;
463 }
464
465 // make sure there are parameter list elements to follow
466 if (idx == arg.size()) {
467 std::cerr << std::endl << "**ERROR** found paramList without any arguments!" << std::endl;
469 return -1;
470 }
471
472 // paramList tag present and further elements present: collect them
473 std::vector<std::string> str;
474 unsigned int idx_end=0;
475 size_t pos=std::string::npos;
476 for (unsigned int i=idx; i<arg.size(); i++) {
477 pos = arg[i].find("-");
478 if (pos == 0) { // likely something like -o, -k, etc.
479 idx_end = i;
480 break;
481 } else if (pos != std::string::npos) { // looks like a parameter list like n0-n1
482 boost::split(str, arg[i], boost::is_any_of("-"));
483 if (str.size() != 2) { // something is wrong, since the structure n0-n1 is expected
484 std::cerr << std::endl << "**ERROR** found token " << arg[i] << " in paramList command which cannot be handled." << std::endl;
486 return -1;
487 }
488 if (!str[0].compare("fit") || !str[0].compare("msr")) {
489 idx_end = i;
490 break;
491 }
492 if (!isNumber(str[0]) || !isNumber(str[1])) {
493 std::cerr << std::endl << "**ERROR** found token " << arg[i] << " in paramList command which cannot be handled." << std::endl;
495 return -1;
496 }
497 unsigned int start=boost::lexical_cast<unsigned int>(str[0]);
498 unsigned int end=boost::lexical_cast<unsigned int>(str[1]);
499 for (unsigned int j=start; j<=end; j++)
500 paramList.push_back(j);
501 } else if (isNumber(arg[i])) { // a single number
502 paramList.push_back(boost::lexical_cast<unsigned int>(arg[i]));
503 } else { // likely the next argument not related to paramList
504 idx_end = i;
505 break;
506 }
507 }
508 if (idx_end == 0)
509 idx_end = arg.size();
510
511 // remove all the paramList arguments for arg
512 arg.erase(arg.begin()+idx-1, arg.begin()+idx_end);
513
514 // go through the parameter list and make sure the values are unique
515 for (unsigned int i=0; i<paramList.size(); i++) {
516 for (unsigned int j=i+1; j<paramList.size(); j++) {
517 if (paramList[i] == paramList[j]) {
518 std::cerr << std::endl << "**ERROR** the parameter list numbers have to be unique. Found " << paramList[i] << " at least 2 times." << std::endl;
520 return -1;
521 }
522 }
523 }
524
525 return paramList.size();
526}
527
528//--------------------------------------------------------------------------
540int main(int argc, char *argv[])
541{
542 // check if version dump is wanted
543 if (argc == 2) {
544 if (!strcmp(argv[1], "--help")) {
546 return 0;
547 } else if (!strcmp(argv[1], "--version")) {
548#ifdef HAVE_CONFIG_H
549#ifdef HAVE_GIT_REV_H
550 std::cout << std::endl << "msr2data version: " << PACKAGE_VERSION << ", git-branch: " << GIT_BRANCH << ", git-rev: " << GIT_CURRENT_SHA1 << " (" << BUILD_TYPE << "), ROOT version: " << ROOT_VERSION_USED << std::endl << std::endl;
551#else
552 std::cout << std::endl << "msr2data version: " << PACKAGE_VERSION << " (" << BUILD_TYPE << "), ROOT version: " << ROOT_VERSION_USED << std::endl << std::endl;
553#endif
554#else
555#ifdef HAVE_GIT_REV_H
556 std::cout << std::endl << "msr2data git-branch: " << GIT_BRANCH << ", git-rev: " << GIT_CURRENT_SHA1 << std::endl << std::endl;
557#else
558 std::cout << std::endl << "msr2data version: unknown." << std::endl << std::endl;
559#endif
560#endif
561 return 0;
562 } else {
564 return 0;
565 }
566 }
567
568 // check the number of arguments
569 if (argc < 2) {
571 return 0;
572 }
573
574 // use a string-vector for the arguments to get rid of char* as far as possible...
575 std::vector<std::string> arg;
576 for (int i(1); i<argc; ++i) {
577 arg.push_back(argv[i]);
578 }
579
580 unsigned int runTAG;
581 std::vector<unsigned int> run_vec;
582 std::string run_list;
583 std::string msrExtension;
584 std::vector<unsigned int> param_vec;
585
586 try {
587 if (arg[0].at(0) == '[') { // In case a list of runs is given by [...]
588 runTAG = 1;
589
590 unsigned int firstRunNumberInArg(0), lastRunNumberInArg(0);
591 unsigned int rightbracket(std::numeric_limits<unsigned int>::max());
592
593 if (!arg[0].compare("["))
594 firstRunNumberInArg = 1;
595 else
596 arg[0]=arg[0].substr(1);
597
598 for (unsigned int i(firstRunNumberInArg); i<arg.size(); ++i) {
599 std::string::size_type loc = arg[i].rfind(']');
600 if ( loc != std::string::npos ) {
601 rightbracket = i;
602 if (!arg[i].compare("]") && i > 0)
603 lastRunNumberInArg = i-1;
604 else {
605 arg[i]=arg[i].substr(0,loc);
606 lastRunNumberInArg = i;
607 }
608 break;
609 }
610 }
611 if (rightbracket == std::numeric_limits<unsigned int>::max()) {
612 std::cerr << std::endl;
613 std::cerr << ">> msr2data: **ERROR** You used the list specification without closing bracket (])! Quitting now." << std::endl;
614 return 0;
615 }
616
617 // generate run_list string
618 for (unsigned int i(firstRunNumberInArg); i<=lastRunNumberInArg; ++i) {
619 run_list += arg[i] + " ";
620 }
621 // parse run_list string
622 std::unique_ptr<PStringNumberList> nl = std::make_unique<PStringNumberList>(run_list);
623 std::string errorMsg("");
624 if (!nl->Parse(errorMsg)) {
625 std::cerr << std::endl;
626 std::cerr << ">> msr2data: " << errorMsg << " - Quitting now." << std::endl;
627 return 0;
628 }
629 // get run list vector
630 run_vec = nl->GetList();
631
632 msrExtension = arg[rightbracket + 1];
633
634 std::vector<std::string>::iterator iter(arg.begin());
635 for (unsigned int i(0); i<rightbracket + 2; ++i) {
636 arg.erase(iter);
637 iter = arg.begin();
638 }
639
640 } else {
641 bool argOneIsNumber(isNumber(arg[0])), argTwoIsNumber(isNumber(arg[1]));
642
643 if (argOneIsNumber && argTwoIsNumber) { // the first two arguments are numbers: an interval of numbers is given
644 runTAG = 2;
645
646 if (arg.size() < 3) {
647 std::cerr << std::endl;
648 std::cerr << ">> msr2data: **ERROR** No msr-file extension specified! Quitting now..." << std::endl;
649 run_vec.clear();
650 arg.clear();
651 return 0;
652 }
653
654 run_vec.push_back(boost::lexical_cast<unsigned int>(arg[0]));
655 run_vec.push_back(boost::lexical_cast<unsigned int>(arg[1]));
656
657 msrExtension = arg[2];
658
659 std::vector<std::string>::iterator iter(arg.begin());
660 for (unsigned int i(0); i < 3; i++) {
661 arg.erase(iter);
662 iter = arg.begin();
663 }
664 } else if (argOneIsNumber && !argTwoIsNumber) { // only one run number is given
665 runTAG = 3;
666 run_vec.push_back(boost::lexical_cast<unsigned int>(arg[0]));
667 msrExtension = arg[1];
668
669 std::vector<std::string>::iterator iter(arg.begin());
670 for (unsigned int i(0); i < 2; i++) {
671 arg.erase(iter);
672 iter = arg.begin();
673 }
674 } else { // assume a runlist-file with "independent variables" is given
675 runTAG = 4;
676 run_list = arg[0];
677 msrExtension = arg[1];
678
679 std::vector<std::string>::iterator iter(arg.begin());
680 for (unsigned int i(0); i < 2; i++) {
681 arg.erase(iter);
682 iter = arg.begin();
683 }
684 }
685 }
686 }
687 catch(boost::bad_lexical_cast &) {
688 std::cerr << std::endl;
689 std::cerr << ">> msr2data: **ERROR** At least one given run number is out of range! Quitting..." << std::endl;
690 run_vec.clear();
691 arg.clear();
692 return -1;
693 }
694
695 // check if parameter list is given
696 int noParamList(msr2data_paramList(arg, param_vec));
697 if (noParamList == -1) {
698 arg.clear();
699 return -1;
700 }
701
702 // check the validity of the command line given command line arguments
703 std::string wrongArgument(msr2data_validArguments(arg));
704 if (!wrongArgument.empty()) {
705 std::cerr << std::endl;
706 std::cerr << ">> msr2data: **ERROR** Unknown argument: " << wrongArgument << ". Quitting..." << std::endl;
707 run_vec.clear();
708 arg.clear();
709 return -1;
710 }
711
712 // check if the output format is DB or data
713 bool db(msr2data_useOption(arg, "data"));
714
715 // check the arguments for the "-o" option and set the output filename
716 std::string outputFile(msr2data_outputfile(arg, db));
717
718 // introduce check, if no output should be generated - in that case we do not need msrfile and rundata handlers later
719 bool realOutput(true);
720 if (!boost::algorithm::to_lower_copy(outputFile).compare("none"))
721 realOutput = false;
722
723 // create the msr2data-object and set the run numbers according to the runTAG above
724 std::unique_ptr<PMsr2Data> msr2dataHandler = std::make_unique<PMsr2Data>(msrExtension);
725
726 int status;
727
728 switch(runTAG) {
729 case 1:
730 status = msr2dataHandler->SetRunNumbers(run_vec);
731 break;
732 case 2:
733 status = msr2dataHandler->SetRunNumbers(run_vec[0], run_vec[1]);
734 break;
735 case 3:
736 status = msr2dataHandler->SetRunNumbers(run_vec[0]);
737 break;
738 case 4:
739 status = msr2dataHandler->SetRunNumbers(run_list);
740 break;
741 default:
742 std::cerr << std::endl;
743 std::cerr << ">> msr2data: **ERROR** None of the possible run list specifications has been detected! Quitting now..." << std::endl;
744 return 0;
745 }
746
747 if (status == 1) {
748 std::cerr << std::endl;
749 std::cerr << ">> msr2data: **ERROR** The run numbers are out of range! Quitting..." << std::endl;
750 return status;
751 } else if (status == -1) {
752 return status;
753 }
754
755 run_vec.clear();
756
757 // check if fitting should be done and in case, which template run number to use
758 int temp(0);
759 bool chainfit(true), onlyInputCreation(false);
760 std::string musrfitOptions;
761
762 temp = msr2data_doFitting(arg, chainfit);
763
764 // check if the number of threads for musrfit is given (-u, --use-no-of-threads <number>)
765 int noOfThreads(msr2data_noOfThreads(arg));
766 if (noOfThreads == -1) {
768 return -1;
769 }
770
771 if (temp == -2) {
772 std::cerr << std::endl;
773 std::cerr << ">> msr2data: **ERROR** More than one fitting options are specified! Quitting..." << std::endl;
774 return temp;
775 } else if (temp == -3) {
776 std::cerr << std::endl;
777 std::cerr << ">> msr2data: **ERROR** The given template has not a valid run number! Quitting..." << std::endl;
778 return temp;
779 }
780
781
782 // check if any options should be passed to musrfit
783 if (temp) {
784 if (!msr2data_useOption(arg, "-k") || !msr2data_useOption(arg, "--keep-mn2-output"))
785 musrfitOptions.append("-k ");
786 if (!msr2data_useOption(arg, "-t") || !msr2data_useOption(arg, "--title-from-data-file"))
787 musrfitOptions.append("-t ");
788 if (!msr2data_useOption(arg, "-e") || !msr2data_useOption(arg, "--estimateN0"))
789 musrfitOptions.append("-e ");
790 if (!msr2data_useOption(arg, "-y") || !msr2data_useOption(arg, "--yaml"))
791 musrfitOptions.append("-y ");
792 if (!msr2data_useOption(arg, "-p") || !msr2data_useOption(arg, "--per-run-block-chisq"))
793 musrfitOptions.append("-p ");
794 if (noOfThreads > 0)
795 musrfitOptions.append("-u " + std::to_string(noOfThreads) + " ");
796 }
797
798 // if no fitting should be done, check if only the input files should be created
799 if (!temp) {
800 temp = msr2data_doInputCreation(arg, onlyInputCreation);
801 if (onlyInputCreation) {
802 // if only input files should be created, do not write data to an output file (no matter, what has been determined earlier)
803 realOutput = false;
804 outputFile = "none";
805 }
806 if (temp == -3) {
807 std::cerr << std::endl;
808 std::cerr << ">> msr2data: **ERROR** The given template has not a valid run number! Quitting..." << std::endl;
809 return temp;
810 }
811 }
812
813 // check if msr2data should work in the global fit regime
814 bool setNormalMode(msr2data_useOption(arg, "global"));
815 unsigned int globalMode(0);
816
817 if (!msr2data_useOption(arg, "global+!")) {
818 setNormalMode = false;
819 globalMode = 1;
820 } else if (!msr2data_useOption(arg, "global+")) {
821 setNormalMode = false;
822 globalMode = 2;
823 }
824
825 // At this point it should be clear if any template for input-file generation is given or not.
826 // Therefore, the number of digits in the run number format is determined only here.
827 if (temp > 0) {
828 status = msr2dataHandler->DetermineRunNumberDigits(temp, setNormalMode);
829 } else {
830 status = msr2dataHandler->DetermineRunNumberDigits(msr2dataHandler->GetPresentRun(), setNormalMode);
831 }
832
833 if (status) {
834 return status;
835 }
836
837 // Check if all given run numbers are covered by the formatting of the data file name
838 status = msr2dataHandler->CheckRunNumbersInRange();
839 if (status) {
840 std::cerr << std::endl;
841 std::cerr << ">> msr2data: **ERROR** At least one given run number is out of range! Quitting..." << std::endl;
842 return status;
843 }
844
845 bool writeSummary(false);
846 unsigned int writeHeader(2);
847 // writeHeader: 0 - no header
848 // 1 - write header explicitly (even if the file is present already)
849 // 2 - write header automatically if a new file is created and do not if the data is appended to an existing file
850
851 std::unique_ptr<std::fstream> fileOutput;
852 if (realOutput) {
853 // check the arguments for the "header" and "noheader" options
854 if (!msr2data_useOption(arg, "header")) {
855 if (!msr2data_useOption(arg, "noheader")) {
856 writeHeader = 2;
857 } else {
858 writeHeader = 1;
859 }
860 } else if (!msr2data_useOption(arg, "noheader")) {
861 writeHeader = 0;
862 }
863
864 // check the arguments for the "nosummary" option
865 writeSummary = msr2data_useOption(arg, "nosummary");
866
867 // delete old db/data file if the "new" option is given
868 if (!msr2data_useOption(arg, "new")) {
869 fileOutput = std::make_unique<std::fstream>();
870 fileOutput->open(outputFile.c_str(), std::ios::in);
871 if (fileOutput->is_open()) {
872 std::cout << std::endl << ">> msr2data: **INFO** Deleting output file " << outputFile << std::endl;
873 fileOutput->close();
874 fileOutput->open(outputFile.c_str(), std::ios::out | std::ios::trunc);
875 fileOutput->close();
876 } else {
877 std::cout << std::endl << ">> msr2data: **INFO** Ignoring the 'new' option since " << outputFile << " does not exist yet." << std::endl;
878 }
879 if (writeHeader == 2) {
880 writeHeader = 1;
881 }
882 }
883 }
884
885 // GLOBAL MODE
886 if (!setNormalMode) {
887 std::ostringstream strInfile;
888 strInfile << msr2dataHandler->GetPresentRun() << "+global" << msrExtension << ".msr";
889
890 // if fitting should be done, prepare a new input file
891 if (temp) {
892 if (temp > 0) { // if it is smaller no input file should be generated
893 bool success(msr2dataHandler->PrepareGlobalInputFile(temp, strInfile.str(), globalMode, musrfitOptions));
894
895 if (!success) {
896 std::cerr << std::endl << ">> msr2data: **ERROR** Input file generation has not been successful! Quitting..." << std::endl;
897 return -1;
898 }
899 }
900
901 // and do the fitting
902 if (!onlyInputCreation) {
903 // check if MUSRFITPATH is set, if not issue a warning
904 std::string path("");
905 bool pathSet(false);
906 char *pathPtr(getenv("MUSRFITPATH"));
907 if (pathPtr) {
908 path = boost::lexical_cast<std::string>(pathPtr);
909 if (!path.empty()) {
910 pathSet = true;
911 path.append("/");
912 }
913 }
914 if (!pathSet) {
915 std::cerr << std::endl << ">> msr2data: **WARNING** The MUSRFITPATH environment variable is not set!";
916 std::cerr << std::endl << ">> msr2data: **WARNING** Please set it or at least ensure that musrfit can be found on the PATH!" << std::endl;
917 }
918 std::ostringstream oss;
919 oss << path << "musrfit" << " " << strInfile.str() << " " << musrfitOptions;
920 std::cout << std::endl << ">> msr2data: **INFO** Calling " << oss.str() << std::endl;
921 if (system(oss.str().c_str()) == -1) {
922 std::cerr << "**ERROR** cmd: " << oss.str().c_str() << " failed." << std::endl;
923 }
924 }
925 }
926
927 if (realOutput) {
928 // read musrfit startup file
929 if (writeSummary) {
930 status = msr2dataHandler->ParseXmlStartupFile();
931 }
932
933 // Read msr file
934 status = msr2dataHandler->ReadMsrFile(strInfile.str());
935 if (status != PMUSR_SUCCESS) {
936 arg.clear();
937 return status;
938 }
939
940 // read data files
941 if (writeSummary)
942 status = msr2dataHandler->ReadRunDataFile();
943
944 unsigned int counter(0);
945
946 while (msr2dataHandler->GetPresentRun()) {
947 // write DB or dat file
948 status = msr2dataHandler->WriteOutput(outputFile, param_vec, db, writeHeader, !setNormalMode, counter);
949 if (status == -1) {
950 return status;
951 }
952 ++counter;
953 }
954 }
955 } else { // NORMAL MODE - one msr-file for each run
956
957 // read musrfit startup file
958 if (writeSummary) {
959 status = msr2dataHandler->ParseXmlStartupFile();
960 }
961
962 // Processing the run list, do the fitting and write the data to the DB or data output file
963 bool firstrun(true);
964 unsigned int oldtemp(0); // should be accessed only when updated before...
965 std::ostringstream strInfile;
966
967 while (msr2dataHandler->GetPresentRun()) {
968 strInfile.clear();
969 strInfile.str("");
970 strInfile << msr2dataHandler->GetPresentRun() << msrExtension << ".msr";
971
972 // if fitting should be done, prepare a new input file
973 if (temp) {
974 if (temp > 0) {
975 bool success(true);
976 if (firstrun || !chainfit)
977 success = msr2dataHandler->PrepareNewInputFile(temp, false);
978 else
979 success = msr2dataHandler->PrepareNewInputFile(oldtemp, false);
980 if (firstrun)
981 firstrun = false;
982 oldtemp = msr2dataHandler->GetPresentRun();
983
984 if (!success) {
985 std::cerr << std::endl << ">> msr2data: **ERROR** Input file generation has not been successful! Quitting..." << std::endl;
986 return -1;
987 }
988 }
989
990 // and do the fitting
991 if (!onlyInputCreation) {
992 // check if MUSRFITPATH is set, if not issue a warning
993 std::string path("");
994 bool pathSet(false);
995 char *pathPtr(getenv("MUSRFITPATH"));
996 if (pathPtr) {
997 path = boost::lexical_cast<std::string>(pathPtr);
998 if (!path.empty()) {
999 pathSet = true;
1000 path.append("/");
1001 }
1002 }
1003 if (!pathSet) {
1004 std::cerr << std::endl << ">> msr2data: **WARNING** The MUSRFITPATH environment variable is not set!";
1005 std::cerr << std::endl << ">> msr2data: **WARNING** Please set it or at least ensure that musrfit can be found on the PATH!" << std::endl;
1006 }
1007 std::ostringstream oss;
1008 oss << path << "musrfit" << " " << strInfile.str() << " " << musrfitOptions;
1009 std::string cmdStr = oss.str();
1010 cmdStr.erase(std::remove(cmdStr.begin(), cmdStr.end(), '\r'), cmdStr.end());
1011 cmdStr.erase(std::remove(cmdStr.begin(), cmdStr.end(), '\n'), cmdStr.end());
1012 std::cout << std::endl << ">> msr2data: **INFO** Calling " << cmdStr << std::endl;
1013 if (system(cmdStr.c_str()) == -1) {
1014 std::cerr << "**ERROR** cmd: " << cmdStr << " failed." << std::endl;
1015 }
1016 }
1017 }
1018
1019 // read msr-file
1020 if (realOutput) {
1021 status = msr2dataHandler->ReadMsrFile(strInfile.str());
1022 if (status != PMUSR_SUCCESS) {
1023 // if the msr-file cannot be read, write no output but proceed to the next run
1024 status = msr2dataHandler->WriteOutput("none", param_vec, db, writeHeader);
1025 if (status == -1) {
1026 return status;
1027 } else {
1028 continue;
1029 }
1030 }
1031 }
1032
1033 // read data files
1034 if (writeSummary)
1035 status = msr2dataHandler->ReadRunDataFile();
1036
1037 // write DB or dat file
1038 status = msr2dataHandler->WriteOutput(outputFile, param_vec, db, writeHeader);
1039 if (status == -1) {
1040 return status;
1041 }
1042 }
1043 }
1044
1045 // Make sure that the empty line at the end of the output file gets written
1046 // This is needed to create a "valid db-file", however, we do it for all output files
1047 // Unfortunately, this can be done in a coherent way only on that level
1048 // Unfortunately, there are also problems with boost::filesystem::exists(outputFile)
1049 // Therefore, first try to open the file for reading and if this works, write to it - not clean but it works
1050 if (realOutput) {
1051 fileOutput = std::make_unique<std::fstream>();
1052 fileOutput->open(outputFile.c_str(), std::ios::in);
1053 if (fileOutput->is_open()) {
1054 fileOutput->close();
1055 fileOutput->open(outputFile.c_str(), std::ios::out | std::ios::app);
1056 if (fileOutput->is_open()) {
1057 *fileOutput << std::endl << std::endl;
1058 fileOutput->close();
1059 } else {
1060 std::cerr << std::endl << ">> msr2data: **ERROR** The output file " << outputFile << " cannot be opened! Please check!";
1061 std::cerr << std::endl;
1062 }
1063 } else {
1064 std::cerr << std::endl << ">> msr2data: **WARNING** No output has been written to the file " << outputFile << "!";
1065 std::cerr << std::endl << ">> msr2data: **WARNING** Please check the range of runs and the specified options!" << std::endl;
1066 }
1067 }
1068
1069 if (!arg.empty()) {
1070 std::cout << std::endl << ">> msr2data: **INFO** The following command line arguments have been specified but not been used: " << std::endl;
1071 std::cout << ">> msr2data: **INFO**";
1072 for (unsigned int i(0); i<arg.size(); ++i)
1073 std::cout << " " << arg[i];
1074 std::cout << std::endl;
1075 }
1076
1077 std::cout << std::endl << ">> msr2data: done ..." << std::endl;
1078
1079 return 0;
1080}
#define PMUSR_SUCCESS
Successful operation completion.
Definition PMusr.h:58
return status
int main(int argc, char *argv[])
Definition addRun.cpp:363
int msr2data_doInputCreation(std::vector< std::string > &arg, bool &inputOnly)
Definition msr2data.cpp:420
void msr2data_syntax()
Definition msr2data.cpp:86
std::string msr2data_outputfile(std::vector< std::string > &arg, bool db=true)
Definition msr2data.cpp:237
std::string msr2data_validArguments(const std::vector< std::string > &arg)
Definition msr2data.cpp:184
int msr2data_doFitting(std::vector< std::string > &arg, bool &chainfit)
Definition msr2data.cpp:367
int msr2data_noOfThreads(std::vector< std::string > &arg)
Definition msr2data.cpp:315
bool isNumber(const std::string &s)
Definition msr2data.cpp:70
bool msr2data_useOption(std::vector< std::string > &arg, const std::string &s)
Definition msr2data.cpp:288
int msr2data_paramList(std::vector< std::string > &arg, std::vector< unsigned int > &paramList)
Definition msr2data.cpp:448