38const std::string RALF(
"RALF");
39const std::string SLOG(
"SLOG");
40const std::string FXYE(
"FXYE");
41const std::string ALT(
"ALT");
44const double m_TOLERANCE = 1.e-10;
46void assertNumFilesAndSpectraIsValid(
size_t numOutFiles,
size_t numOutSpectra) {
49 if ((numOutFiles != 1) || (numOutSpectra != 1)) {
50 assert((numOutFiles > 1) != (numOutSpectra > 1));
54bool doesFileExist(
const std::string &filePath) {
55 auto file = Poco::File(filePath);
59double fixErrorValue(
const double value) {
69bool isEqual(
const double left,
const double right) {
75bool isConstantDelta(
const HistogramData::BinEdges &xAxis) {
76 const double deltaX = (xAxis[1] - xAxis[0]);
77 for (std::size_t i = 1; i < xAxis.size(); ++i) {
78 if (!isEqual(xAxis[i] - xAxis[i - 1], deltaX)) {
85std::unique_ptr<std::stringstream> makeStringStream() {
93 return std::make_unique<std::stringstream>();
106void writeBankHeader(std::stringstream &out,
const std::string &bintype,
const int banknum,
const size_t datasize) {
107 std::ios::fmtflags fflags(out.flags());
108 out <<
"BANK " << std::fixed << std::setprecision(0)
110 << std::fixed <<
" " << datasize << std::fixed <<
" " << datasize << std::fixed <<
" " << bintype;
118 const std::vector<std::string> exts{
".gsa",
".gss",
".gda",
".txt"};
121 "The input workspace");
124 "The filename to use for the saved data");
127 "Whether to save each spectrum into a separate file ('true') "
128 "or not ('false'). Note that this is a string, not a boolean property.");
130 declareProperty(
"Append",
true,
"If true and Filename already exists, append, else overwrite ");
133 "The bank number to include in the file header for the first spectrum, "
134 "i.e., the starting bank number. "
135 "This will increment for each spectrum or group member.");
137 const std::vector<std::string> formats{RALF, SLOG};
138 declareProperty(
"Format", RALF, std::make_shared<Kernel::StringListValidator>(formats),
"GSAS format to save as");
140 const std::vector<std::string> ralfDataFormats{FXYE, ALT};
141 declareProperty(
"DataFormat", FXYE, std::make_shared<Kernel::StringListValidator>(ralfDataFormats),
142 "Saves RALF data as either FXYE or alternative format");
146 declareProperty(
"MultiplyByBinWidth",
true,
"Multiply the intensity (Y) by the bin width; default TRUE.");
148 declareProperty(
"ExtendedHeader",
false,
"Add information to the header about iparm file and normalization");
151 "If true, then each bank's bank ID is equal to the spectrum number; "
152 "otherwise, the continuous bank IDs are applied. ");
155 "Each line will be put to the header of the output GSAS file.");
158 "If true, then the standard header will be replaced "
159 "by the user specified header. Otherwise, the user "
160 "specified header will be "
161 "inserted before the original header");
164 "Each string will be used to replaced the standard GSAS bank header."
165 "Number of strings in the give array must be same as number of banks."
166 "And the order is preserved.");
168 auto must_be_3 = std::make_shared<Kernel::ArrayLengthValidator<int>>(3);
169 auto precision_range = std::make_shared<Kernel::ArrayBoundedValidator<int>>(0, 10);
171 auto precision_validator = std::make_shared<Kernel::CompositeValidator>();
172 precision_validator->add(must_be_3);
173 precision_validator->add(precision_range);
175 std::vector<int> default_precision(3, 9);
177 std::move(precision_validator)),
178 "Enter 3 integers as the precisions of output X, Y and E for SLOG data "
180 "Default is (9, 9, 9) if it is left empty. Otherwise it is not "
188 const size_t nHist =
m_inputWS->getNumberHistograms();
196 const size_t numOfOutFiles{
split ? nHist : 1};
197 const size_t numOutSpectra{
split ? 1 : nHist};
207 m_progress = std::make_unique<Progress>(
this, 0.0, 1.0, (nHist * 2));
244 const auto &spectrumInfo =
m_inputWS->spectrumInfo();
245 const size_t numHist =
m_inputWS->getNumberHistograms();
248 g_log.
warning(
"No valid instrument found with this workspace"
249 " Treating as NO-INSTRUMENT CASE");
253 bool allValid =
true;
255 const auto numHistInt64 =
static_cast<int64_t
>(numHist);
258 for (int64_t histoIndex = 0; histoIndex < numHistInt64; histoIndex++) {
261 if (!spectrumInfo.hasDetectors(histoIndex)) {
263 g_log.
warning() <<
"There is no detector associated with spectrum " << histoIndex
264 <<
". Workspace is treated as NO-INSTRUMENT case. \n";
284 const std::vector<int> &slog_xye_precisions)
const {
286 const bool useSpecAsBank =
getProperty(
"UseSpectrumNumberAsBankID");
287 const bool multiplyByBinWidth =
getProperty(
"MultiplyByBinWidth");
288 const int userStartingBankNumber =
getProperty(
"Bank");
293 bankid =
static_cast<int>(
m_inputWS->getSpectrum(specIndex).getSpectrumNo());
295 bankid = userStartingBankNumber +
static_cast<int>(specIndex);
299 const auto &histogram =
m_inputWS->histogram(specIndex);
300 if (outputFormat == RALF) {
301 if (ralfDataFormat == FXYE) {
303 }
else if (ralfDataFormat == ALT) {
306 throw std::runtime_error(
"Unknown RALF data format" + ralfDataFormat);
308 }
else if (outputFormat == SLOG) {
309 writeSLOGdata(specIndex, bankid, multiplyByBinWidth, outBuf, histogram, slog_xye_precisions);
311 throw std::runtime_error(
"Cannot write to the unknown " + outputFormat +
"output format");
324 size_t specIndex)
const {
327 const auto l1 = spectrumInfo.
l1();
328 const auto l2 = spectrumInfo.
l2(specIndex);
331 out <<
"# Total flight path " << (l1 +
l2) <<
"m, tth " << (
twoTheta * 180. / M_PI) <<
"deg, DIFC "
334 out <<
"# Data for spectrum :" << specIndex <<
"\n";
346 const auto &spectrumInfo =
m_inputWS->spectrumInfo();
355 assertNumFilesAndSpectraIsValid(numOutFiles, numOutSpectra);
361 const auto numOutFilesInt64 =
static_cast<int64_t
>(numOutFiles);
365 std::vector<int> slog_xye_precisions =
getProperty(
"SLOGXYEPrecision");
369 for (int64_t fileIndex = 0; fileIndex < numOutFilesInt64; fileIndex++) {
376 for (
size_t specIndex = 0; specIndex < numOutSpectra; specIndex++) {
384 const int64_t
index = specIndex + fileIndex;
422 if (format == SLOG) {
423 out <<
"Sample Run: ";
425 out <<
" Vanadium Run: ";
427 out <<
" Wavelength: ";
436 if (prop !=
nullptr && (!prop->
value().empty())) {
437 out << std::setw(80) << std::left;
438 out <<
"#Instrument parameter file: " << prop->
value() <<
"\n";
452 if (format == SLOG) {
456 out <<
"# " <<
m_inputWS->getNumberHistograms() <<
" Histograms\n";
457 out <<
"# File generated by Mantid:\n";
458 out <<
"# Instrument: " <<
m_inputWS->getInstrument()->getName() <<
"\n";
459 out <<
"# From workspace named : " <<
m_inputWS->getName() <<
"\n";
461 out <<
"# with Y multiplied by the bin widths.\n";
462 out <<
"# Primary flight path " << l1 <<
"m \n";
463 if (format == SLOG) {
464 out <<
"# Sample Temperature: ";
473 bool norm_by_current =
false;
474 bool norm_by_monitor =
false;
476 for (
const auto &algo : algohist) {
477 if (algo->name() ==
"NormaliseByCurrent")
478 norm_by_current =
true;
479 if (algo->name() ==
"NormaliseToMonitor")
480 norm_by_monitor =
true;
484 out <<
" Normalised to pCharge";
486 out <<
" Normalised to monitor";
501 const std::string outputFileName =
getProperty(
"Filename");
502 assert(numberOfOutFiles > 0);
504 if (numberOfOutFiles == 1) {
513 Poco::Path path(outputFileName);
515 const std::string basename = path.getBaseName();
516 const std::string ext = path.getExtension();
520 for (
size_t i = 0; i < numberOfOutFiles; i++) {
522 std::string newFileName = basename;
526 path.append(newFileName);
527 std::string filename = path.toString();
530 if (!append && doesFileExist(filename)) {
531 g_log.
warning(
"Target GSAS file " + filename +
" exists and will be overwritten.\n");
532 }
else if (append && !doesFileExist(filename)) {
533 g_log.
warning(
"Target GSAS file " + filename +
" does not exist but algorithm was set to append.\n");
553 const std::string &failsafeValue)
const {
556 out << failsafeValue;
564 out << failsafeValue;
575 out << prop->value();
579 std::string units = prop->units();
580 if (!units.empty()) {
594 auto source = instrument->getSource();
595 auto sample = instrument->getSample();
596 if (source && sample) {
622 const ios_base::openmode mode = (append ? (ios_base::out | ios_base::app) : (ios_base::out | ios_base::trunc));
626 outStream.open(outFilePath, mode);
627 if (outStream.fail()) {
629 const std::string
error = strerror(errno);
648 if (propertyName ==
"Append") {
649 if (periodNum != 1) {
655 else if (propertyName ==
"Bank") {
656 alg->
setProperty(
"Bank", std::stoi(propertyValue) + periodNum - 1);
669 std::map<std::string, std::string> result;
673 result[
"InputWorkspace"] =
"The input workspace cannot be a GroupWorkspace.";
677 const auto nHist =
static_cast<int>(input_ws->getNumberHistograms());
679 if (nHist > 99 && !
split) {
680 std::string outError =
"Number of Spectra(" +
std::to_string(nHist) +
") cannot be larger than 99 for GSAS file";
681 result[
"InputWorkspace"] = outError;
682 result[
"SplitFiles"] = outError;
687 std::string output_file_name =
getProperty(
"Filename");
688 if (output_file_name.size() == 0) {
689 result[
"Filename"] =
"Filename cannot be left empty.";
694 std::vector<std::string> user_header_vec =
getProperty(
"UserSpecifiedBankHeader");
695 if (user_header_vec.size() > 0 && user_header_vec.size() != input_ws->getNumberHistograms()) {
696 result[
"UserSpecifiedBankHeader"] =
"If user specifies bank header, each bank must "
697 "have a unique user-specified header.";
716 assertNumFilesAndSpectraIsValid(numOutFiles, numSpectra);
718 const auto numOutFilesInt64 =
static_cast<int64_t
>(numOutFiles);
721 for (int64_t fileIndex = 0; fileIndex < numOutFilesInt64; fileIndex++) {
725 std::ofstream fileStream;
727 for (
size_t specIndex = 0; specIndex < numSpectra; specIndex++) {
729 const size_t index = specIndex + fileIndex;
735 if (fileStream.fail()) {
736 const std::string
error = strerror(errno);
738 throw std::runtime_error(
"Failed to close the file at " +
m_outFileNames[fileIndex] +
739 " - this file may be empty, corrupted or incorrect.");
747 const auto &xVals = histo.binEdges();
748 const size_t datasize = histo.y().size();
749 const double bc1 = xVals[0] * 32;
750 const double bc2 = (xVals[1] - xVals[0]) * 32;
752 double bc4 = (xVals[1] - xVals[0]) / xVals[0];
753 if (!std::isfinite(bc4))
757 writeBankHeader(out,
"RALF", bank, datasize);
759 out << std::fixed <<
" " << std::setprecision(0) << std::setw(8) << bc1 << std::fixed <<
" " << std::setprecision(0)
760 << std::setw(8) << bc2 << std::fixed <<
" " << std::setprecision(0) << std::setw(8) << bc1 << std::fixed <<
" "
761 << std::setprecision(5) << std::setw(7) << bc4 <<
" " << bankDataType <<
"\n";
765 const size_t datasize = histo.y().size();
766 const auto &xPointVals = histo.points();
767 const auto &yVals = histo.y();
768 const auto &eVals = histo.e();
772 const size_t dataEntriesPerLine = 4;
776 const int64_t numberOfOutLines = (datasize + dataEntriesPerLine - 1) / dataEntriesPerLine;
778 std::vector<std::unique_ptr<std::stringstream>> outLines;
779 outLines.resize(numberOfOutLines);
781 for (int64_t i = 0; i < numberOfOutLines; i++) {
782 outLines[i] = makeStringStream();
783 auto &outLine = *outLines[i];
785 size_t dataPosition = i * dataEntriesPerLine;
786 const size_t endPosition = dataPosition + dataEntriesPerLine;
789 for (; dataPosition < endPosition; dataPosition++) {
790 if (dataPosition < datasize) {
793 const auto epos =
static_cast<int>(fixErrorValue(eVals[dataPosition] * 1000));
795 outLine << std::fixed << std::setw(8) << static_cast<int>(xPointVals[dataPosition] * 32);
796 outLine << std::fixed << std::setw(7) << static_cast<int>(yVals[dataPosition] * 1000);
797 outLine << std::fixed << std::setw(5) << epos;
804 for (
const auto &outLine : outLines) {
806 out << outLine->rdbuf();
811 const HistogramData::Histogram &histo)
const {
812 const auto &xVals = histo.binEdges();
813 const auto &xPointVals = histo.points();
814 const auto &yVals = histo.y();
815 const auto &eVals = histo.e();
816 const size_t datasize = yVals.size();
820 std::vector<std::unique_ptr<std::stringstream>> outLines;
821 outLines.resize(datasize);
824 for (int64_t i = 0; i < static_cast<int64_t>(datasize); i++) {
825 outLines[i] = makeStringStream();
826 auto &outLine = *outLines[i];
827 const double binWidth = xVals[i + 1] - xVals[i];
828 const double outYVal{MultiplyByBinWidth ? yVals[i] * binWidth : yVals[i]};
829 const double epos = fixErrorValue(MultiplyByBinWidth ? eVals[i] * binWidth : eVals[i]);
832 outLine << std::fixed << std::setprecision(5) << std::setw(15) << xPointVals[i];
833 outLine << std::fixed << std::setprecision(8) << std::setw(18) << outYVal;
834 outLine << std::fixed << std::setprecision(8) << std::setw(18) << epos <<
"\n";
837 for (
const auto &outLine : outLines) {
839 out << outLine->rdbuf();
855 std::stringstream &out,
const HistogramData::Histogram &histo,
856 const std::vector<int> &xye_precision)
const {
858 if (xye_precision.size() != 3)
859 throw std::runtime_error(
"SLOG XYE precisions are not given in a 3-item vector.");
861 const auto &xVals = histo.binEdges();
862 const auto &xPoints = histo.points();
863 const auto &yVals = histo.y();
864 const auto &eVals = histo.e();
865 const size_t datasize = yVals.size();
867 const double bc1 = xVals.front();
868 const double bc2 = *(xPoints.end() - 1);
869 const double bc3 = (*(xVals.begin() + 1) - bc1) / bc1;
872 throw std::runtime_error(
"Cannot write out logarithmic data starting at zero or less");
874 if (isConstantDelta(xVals)) {
875 g_log.
error() <<
"Constant delta - T binning : " << xVals.front() <<
", " << *(xVals.begin() + 1) <<
", "
876 << *(xVals.begin() + 2) <<
"... " << std::endl;
877 throw std::runtime_error(
"While writing SLOG format : Found constant "
878 "delta - T binning for bank " +
882 g_log.
debug() <<
"SaveGSS(): Min TOF = " << bc1 <<
'\n';
890 writeBankHeader(out,
"SLOG", bank, datasize);
892 out << std::fixed <<
" " << std::setprecision(0) << std::setw(10) << bc1 << std::fixed <<
" "
893 << std::setprecision(0) << std::setw(10) << bc2 << std::fixed <<
" " << std::setprecision(7) << std::setw(10)
894 << bc3 << std::fixed <<
" 0 FXYE\n";
897 std::vector<std::unique_ptr<std::stringstream>> outLines;
898 outLines.resize(datasize);
901 for (int64_t i = 0; i < static_cast<int64_t>(datasize); i++) {
902 outLines[i] = makeStringStream();
903 auto &outLine = *outLines[i];
904 const double binWidth = xVals[i + 1] - xVals[i];
905 const double yValue{MultiplyByBinWidth ? yVals[i] * binWidth : yVals[i]};
906 const double eValue{fixErrorValue(MultiplyByBinWidth ? eVals[i] * binWidth : eVals[i])};
910 outLine <<
" " << std::fixed << std::setprecision(xye_precision[0]) << std::setw(20) << xPoints[i] <<
" "
911 << std::fixed << std::setprecision(xye_precision[1]) << std::setw(20) << yValue <<
" " << std::fixed
912 << std::setprecision(xye_precision[2]) << std::setw(20) << eValue << std::setw(12) <<
" "
916 for (
const auto &outLine : outLines) {
917 out << outLine->rdbuf();
#define DECLARE_ALGORITHM(classname)
double value
The value of the point.
std::map< DeltaEMode::Type, std::string > index
#define PARALLEL_START_INTERRUPT_REGION
Begins a block to skip processing is the algorithm has been interupted Note the end of the block if n...
#define PARALLEL_FOR_NO_WSP_CHECK()
#define PARALLEL_END_INTERRUPT_REGION
Ends a block to skip processing is the algorithm has been interupted Note the start of the block if n...
#define PARALLEL_CHECK_INTERRUPT_REGION
Adds a check after a Parallel region to see if it was interupted.
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
std::string getPropertyValue(const std::string &name) const override
Get the value of a property as a string.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
virtual void setOtherProperties(IAlgorithm *alg, const std::string &propertyName, const std::string &propertyValue, int periodNum)
Virtual method to set the non workspace properties for this algorithm.
@ Save
to specify a file to write to, the file may or may not exist
IAlgorithm is the interface implemented by the Algorithm base class.
bool hasProperty(const std::string &name) const
Does the property exist on the object.
Kernel::Property * getProperty(const std::string &name) const
Returns the named property as a pointer.
This class stores information regarding an experimental run as a series of log entries.
API::SpectrumInfo is an intermediate step towards a SpectrumInfo that is part of Instrument-2....
Kernel::UnitParametersMap diffractometerConstants(const size_t index, std::vector< detid_t > &uncalibratedDets) const
Calculate average diffractometer constants (DIFA, DIFC, TZERO) of detectors associated with this spec...
double twoTheta(const size_t index) const
Returns the scattering angle 2 theta in radians (angle w.r.t.
double l2(const size_t index) const
Returns L2 (distance from sample to spectrum).
double l1() const
Returns L1 (distance from source to sample).
A property class for workspaces.
Saves a focused data set into a three column GSAS format containing X_i, Y_i*step,...
bool m_overwrite_std_gsas_header
flag to overwrite standard GSAS header
void init() override
Initialisation code.
std::map< std::string, std::string > validateInputs() override
Validates the user input and warns / throws on bad conditions.
void writeSLOGdata(const size_t ws_index, const int bank, const bool MultiplyByBinWidth, std::stringstream &out, const HistogramData::Histogram &histo, const std::vector< int > &xye_precision) const
Write out the data in SLOG format.
void processUserSpecifiedHeaders()
Process input user-specified headers.
void generateOutFileNames(size_t numberOfOutFiles)
Generates the filename(s) and paths to write to and stores in member var.
void generateInstrumentHeader(std::stringstream &out, double l1) const
Generates the instrument header and returns this as a string stream.
void writeBufferToFile(size_t numOutFiles, size_t numSpectra)
Writes the current buffer to the user specified file path.
void setOtherProperties(IAlgorithm *alg, const std::string &propertyName, const std::string &propertyValue, int periodNum) override
sets non workspace properties for the algorithm
const std::string name() const override
Algorithm's name.
void generateBankData(std::stringstream &outBuf, size_t specIndex, const std::string &outputFormat, const std::vector< int > &slog_xye_precisions) const
Turns the data associated with this spectra into a string stream.
std::vector< std::string > m_user_specified_gsas_header
User specified header string.
API::MatrixWorkspace_const_sptr m_inputWS
Workspace.
void getLogValue(std::stringstream &out, const API::Run &runInfo, const std::string &name, const std::string &failsafeValue="UNKNOWN") const
Returns the log value in a GSAS format as a string stream.
void writeRALF_ALTdata(std::stringstream &out, const int bank, const HistogramData::Histogram &histo) const
Write out the data in RALF - ALT format.
void openFileStream(const std::string &outFilePath, std::ofstream &outStream)
Opens a new file stream at the path specified.
std::vector< std::unique_ptr< std::stringstream > > m_outputBuffer
The output buffer.
std::unique_ptr< API::Progress > m_progress
Holds pointer to progress bar.
void writeRALF_XYEdata(const int bank, const bool MultiplyByBinWidth, std::stringstream &out, const HistogramData::Histogram &histo) const
Write out the data in RALF - FXYE format.
std::vector< std::string > m_outFileNames
The output filename(s)
bool areAllDetectorsValid() const
Determines if all spectra have detectors.
std::vector< std::string > m_user_specified_bank_headers
User specified bank header.
void generateGSASBuffer(size_t numOutFiles, size_t numOutSpectra)
Generates the output which will be written to the GSAS file.
void generateBankHeader(std::stringstream &out, const API::SpectrumInfo &spectrumInfo, size_t specIndex) const
Generates the bank header and returns this as a string stream.
bool m_overwrite_std_bank_header
flag to overwrite standard GSAS bank header
void writeRALFHeader(std::stringstream &out, int bank, const HistogramData::Histogram &histo) const
bool isInstrumentValid() const
Returns if the input workspace instrument is valid.
bool m_allDetectorsValid
Indicates whether all spectra have valid detectors.
void exec() override
Execution code.
Support for a property that holds an array of values.
Records the filename and the description of failure.
virtual void setPropertyValue(const std::string &name, const std::string &value)=0
Sets property value from a string.
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void setPropertySettings(const std::string &name, std::unique_ptr< IPropertySettings > settings)
void debug(const std::string &msg)
Logs at debug level.
void error(const std::string &msg)
Logs at error level.
void warning(const std::string &msg)
Logs at warning level.
Base class for properties.
virtual std::string value() const =0
Returns the value of the property as a string.
A specialised Property class for holding a series of time-value pairs.
TimeSeriesPropertyStatistics getStatistics() const
Return a TimeSeriesPropertyStatistics object.
std::vector< AlgorithmHistory_sptr > AlgorithmHistories
std::shared_ptr< const MatrixWorkspace > MatrixWorkspace_const_sptr
shared pointer to the matrix workspace base class (const version)
void split(const int A, int &S, int &V)
Split a number into the sign and positive value.
std::shared_ptr< const Instrument > Instrument_const_sptr
Shared pointer to an const instrument object.
std::string to_string(const wide_integer< Bits, Signed > &n)
@ Input
An input workspace.