17#include <boost/optional.hpp>
30const int POINTS_PER_LINE = 4;
32double mean(
const std::vector<double> &values) {
33 return std::accumulate(values.begin(), values.end(), 0.0) /
static_cast<double>(values.size());
39double computeAverageDeltaTByT(
const HistogramData::HistogramX &tValues) {
40 std::vector<double> deltaTByT;
41 deltaTByT.reserve(tValues.size() - 1);
43 std::adjacent_difference(tValues.begin(), tValues.end(), std::back_inserter(deltaTByT),
44 [](
const double previous,
const double current) { return (previous - current) / current; });
46 deltaTByT.erase(deltaTByT.begin());
47 return mean(deltaTByT);
50std::string generateBankHeader(
int bank,
int minT,
size_t numberBins,
double deltaTByT) {
51 std::stringstream stream;
52 const auto numberLines =
static_cast<size_t>(std::ceil(
static_cast<double>(numberBins) / POINTS_PER_LINE));
54 stream << std::setprecision(2) <<
"BANK " << bank <<
" " << numberBins <<
" " << numberLines <<
" RALF " << minT
55 <<
" 96 " << minT <<
" " << deltaTByT <<
" ALT";
59boost::optional<std::vector<std::string>> getParamLinesFromGSASFile(
const std::string ¶msFilename) {
61 const static std::string paramLineDelimiter =
"ICONS";
62 std::ifstream paramsFile;
63 paramsFile.open(paramsFilename);
65 if (paramsFile.is_open()) {
66 std::vector<std::string> paramLines;
68 while (std::getline(paramsFile, line)) {
69 if (line.find(paramLineDelimiter) != std::string::npos) {
70 paramLines.emplace_back(line);
89 return "Save a group of focused banks to the MAUD three-column GDA format";
94const std::vector<std::string>
SaveGDA::seeAlso()
const {
return {
"SaveBankScatteringAngles",
"AlignDetectors"}; }
96const std::string
SaveGDA::category()
const {
return "DataHandling\\Text;Diffraction\\DataHandling"; }
108 "A GroupWorkspace where every sub-workspace is a "
109 "single-spectra focused run corresponding to a particular "
112 const static std::vector<std::string> outExts{
".gda"};
114 "The name of the file to save to");
116 const static std::vector<std::string> paramsExts{
".ipf",
".prm",
".parm",
".iprm"};
118 "GSAS calibration file containing conversion factors from D to TOF");
121 "An array of bank IDs, where the value at element i is the "
122 "ID of the bank in " +
128 std::ofstream outFile(filename.c_str());
134 outFile << std::fixed << std::setprecision(0) << std::setfill(
' ');
140 for (
int i = 0; i < inputWS->getNumberOfEntries(); ++i) {
141 const auto ws = inputWS->getItem(i);
142 const auto matrixWS = std::dynamic_pointer_cast<MatrixWorkspace>(ws);
144 auto x = matrixWS->dataX(0);
145 const size_t bankIndex(groupingScheme[i] - 1);
146 if (bankIndex >= calibParams.size()) {
149 const auto &bankCalibParams = calibParams[bankIndex];
152 const static double tofScale = 32;
153 std::vector<double> tofScaled;
154 tofScaled.reserve(
x.size());
156 std::vector<double> yunused;
161 std::transform(
x.begin(),
x.end(), std::back_inserter(tofScaled),
162 [](
const double tofVal) { return tofVal * tofScale; });
163 const auto averageDeltaTByT = computeAverageDeltaTByT(tofScaled);
165 const auto &intensity = matrixWS->y(0);
166 const auto &
error = matrixWS->e(0);
167 const auto numPoints = std::min({tofScaled.size(), intensity.size(),
error.size()});
170 generateBankHeader(i + 1,
static_cast<int>(std::round(tofScaled[0])), numPoints, averageDeltaTByT);
172 outFile << std::left << std::setw(80) << header <<
'\n' << std::right;
174 for (
size_t j = 0; j < numPoints; ++j) {
175 outFile << std::setw(8) << tofScaled[j] << std::setw(7) << intensity[j] * 1000 << std::setw(5) <<
error[j] * 1000;
177 if (j % POINTS_PER_LINE == POINTS_PER_LINE - 1) {
180 }
else if (j == numPoints - 1) {
182 outFile << std::string(80 - (i % POINTS_PER_LINE + 1) * 20,
' ') <<
'\n';
189 std::map<std::string, std::string> issues;
190 boost::optional<std::string> inputWSIssue;
193 for (
const auto &ws : *inputWS) {
194 const auto matrixWS = std::dynamic_pointer_cast<MatrixWorkspace>(ws);
196 if (matrixWS->getNumberHistograms() != 1) {
197 inputWSIssue =
"The workspace " + matrixWS->getName() +
198 " has the wrong number of histograms. It "
199 "should contain data for a single focused "
201 }
else if (matrixWS->getAxis(0)->unit()->unitID() !=
"dSpacing") {
202 inputWSIssue =
"The workspace " + matrixWS->getName() +
203 " has incorrect units. SaveGDA "
204 "expects input workspaces with "
205 "units of D-spacing";
208 inputWSIssue =
"The workspace " + ws->getName() +
" is of the wrong type. It should be a MatrixWorkspace";
216 const auto numSpectraInGroupingScheme = groupingScheme.size();
217 const auto numSpectraInWS =
static_cast<size_t>(inputWS->getNumberOfEntries());
218 if (numSpectraInGroupingScheme != numSpectraInWS) {
219 issues[
PROP_GROUPING_SCHEME] =
"The grouping scheme must contain one entry for every focused spectrum "
220 "in the input workspace. " +
230 const auto paramLines = getParamLinesFromGSASFile(paramsFilename);
235 std::vector<CalibrationParams> calibParams;
236 for (
const auto ¶mLine : *paramLines) {
237 std::vector<std::string> lineItems;
238 boost::algorithm::split(lineItems, paramLine, boost::is_any_of(
"\t "), boost::token_compress_on);
239 calibParams.emplace_back(std::stod(lineItems[3]), std::stod(lineItems[4]), std::stod(lineItems[5]));
#define DECLARE_ALGORITHM(classname)
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
@ Save
to specify a file to write to, the file may or may not exist
@ Load
allowed here which will be passed to the algorithm
A property class for workspaces.
const std::string name() const override
function to return a name of the algorithm, must be overridden in all algorithms
int version() const override
function to return a version of the algorithm, must be overridden in all algorithms
static const std::string PROP_GROUPING_SCHEME
static const std::string PROP_PARAMS_FILENAME
const std::string category() const override
function to return a category of the algorithm.
std::map< std::string, std::string > validateInputs() override
Perform validation of ALL the input properties of the algorithm.
std::vector< CalibrationParams > parseParamsFile() const
const std::string summary() const override
function returns a summary message that will be displayed in the default GUI, and in the help.
static const std::string PROP_INPUT_WS
void exec() override
Virtual method - must be overridden by concrete algorithm.
const std::vector< std::string > seeAlso() const override
Function to return all of the seeAlso (these are not validated) algorithms related to this algorithm....
static const std::string PROP_OUTPUT_FILENAME
void init() override
Virtual method - must be overridden by concrete algorithm.
Support for a property that holds an array of values.
Records the filename and the description of failure.
Exception for index errors.
void error(const std::string &msg)
Logs at error level.
void toTOF(std::vector< double > &xdata, std::vector< double > &ydata, const double &_l1, const int &_emode, std::initializer_list< std::pair< const UnitParams, double > > params)
Convert from the concrete unit to time-of-flight.
std::shared_ptr< WorkspaceGroup > WorkspaceGroup_sptr
shared pointer to Mantid::API::WorkspaceGroup
std::string to_string(const wide_integer< Bits, Signed > &n)
@ Input
An input workspace.