15#include "MantidHistogramData/HistogramE.h"
16#include "MantidHistogramData/HistogramY.h"
43#if defined(__INTEL_COMPILER) || (defined(_MSC_VER) && _MSC_VER < 1800)
45#define FPRINTF_WITH_EXCEPTION(stream, format, ...) \
46 if (fprintf(stream, format, ##__VA_ARGS__) <= 0) { \
47 throw std::runtime_error("Error writing to file. Check folder permissions and disk space."); \
53template <
typename... vargs>
void FPRINTF_WITH_EXCEPTION(FILE *stream,
const char *format, vargs... args) {
54 if (fprintf(stream, format, args...) <= 0) {
55 throw std::runtime_error(
"Error writing to file. Check folder permissions and disk space.");
60void FPRINTF_WITH_EXCEPTION(FILE *stream,
const char *format) { FPRINTF_WITH_EXCEPTION(stream, format,
""); }
64using namespace Kernel;
68const char NUM_FORM[] =
"%-10.4G";
69const char NUMS_FORM[] =
"%-10.4G%-10.4G%-10.4G%-10.4G%-10.4G%-10.4G%-10.4G%-10.4G\n";
70static const char Y_HEADER[] =
"### S(Phi,w)\n";
71static const char E_HEADER[] =
"### Errors\n";
91 auto wsValidator = std::make_shared<Kernel::CompositeValidator>();
95 "The input workspace, which must be in Energy Transfer");
97 "The filename to use for the saved data");
109 const std::string filename =
getProperty(
"Filename");
111 FILE *outSPEFile = fopen(filename.c_str(),
"w");
120 }
catch (std::exception &) {
122 Poco::File(filename).remove();
134 const size_t nHist = inputWS->getNumberHistograms();
135 m_nBins = inputWS->blocksize();
137 FPRINTF_WITH_EXCEPTION(outSPEFile,
"%8u%8u\n",
static_cast<unsigned int>(nHist),
static_cast<unsigned int>(
m_nBins));
140 if (inputWS->axes() > 1 && inputWS->getAxis(1)->isNumeric()) {
141 const Axis &axis = *inputWS->getAxis(1);
142 const std::string commentLine =
"### " + axis.
unit()->caption() +
" Grid\n";
143 FPRINTF_WITH_EXCEPTION(outSPEFile,
"%s", commentLine.c_str());
144 const size_t axisLength = axis.
length();
145 phiPoints = (axisLength == nHist) ? axisLength + 1 : axisLength;
146 for (
size_t i = 0; i < phiPoints; i++) {
147 const double value = (i < axisLength) ? axis(i) : axis(axisLength - 1) + 1;
148 FPRINTF_WITH_EXCEPTION(outSPEFile, NUM_FORM,
value);
149 if ((i + 1) % 8 == 0) {
150 FPRINTF_WITH_EXCEPTION(outSPEFile,
"\n");
154 FPRINTF_WITH_EXCEPTION(outSPEFile,
"### Phi Grid\n");
155 phiPoints = nHist + 1;
156 for (
size_t i = 0; i < phiPoints; i++) {
157 const double value =
static_cast<int>(i) + 0.5;
158 FPRINTF_WITH_EXCEPTION(outSPEFile, NUM_FORM,
value);
159 if ((i + 1) % 8 == 0) {
160 FPRINTF_WITH_EXCEPTION(outSPEFile,
"\n");
167 if (phiPoints % 8 != 0) {
168 FPRINTF_WITH_EXCEPTION(outSPEFile,
"\n");
173 const auto &
X = inputWS->x(0);
175 FPRINTF_WITH_EXCEPTION(outSPEFile,
"### Energy Grid\n");
176 const size_t energyPoints =
m_nBins + 1;
179 FPRINTF_WITH_EXCEPTION(outSPEFile, NUMS_FORM,
X[i - 7],
X[i - 6],
X[i - 5],
X[i - 4],
X[i - 3],
X[i - 2],
X[i - 1],
186 for (i -= 7; i < energyPoints; ++i) {
187 FPRINTF_WITH_EXCEPTION(outSPEFile, NUM_FORM,
X[i]);
189 FPRINTF_WITH_EXCEPTION(outSPEFile,
"\n");
203 bool isNumericAxis = WS->getAxis(1)->isNumeric();
204 const size_t nHist = WS->getNumberHistograms();
207 const auto progStep =
static_cast<int>(ceil(
static_cast<int>(nHist) / 100.0));
211 std::vector<int> spuriousSpectra;
214 const auto &spectrumInfo = WS->spectrumInfo();
216 for (
int i = 0; i < static_cast<int>(nHist); i++) {
217 if (spectrumInfo.hasDetectors(i)) {
218 if (isNumericAxis || !spectrumInfo.isMasked(i)) {
229 spuriousSpectra.emplace_back(i);
233 if (i % progStep == 0) {
251 std::vector<double> &Signal, std::vector<double> &Error)
const {
252 if (Signal.size() != inSignal.size()) {
253 Signal.resize(inSignal.size());
254 Error.resize(inSignal.size());
256 for (
size_t i = 0; i < inSignal.size(); i++) {
257 if (!std::isfinite(inSignal[i])) {
261 Signal[i] = inSignal[i];
274 FPRINTF_WITH_EXCEPTION(outFile,
"%s", Y_HEADER);
277 FPRINTF_WITH_EXCEPTION(outFile,
"%s", E_HEADER);
284 FPRINTF_WITH_EXCEPTION(outFile,
"%s", Y_HEADER);
287 FPRINTF_WITH_EXCEPTION(outFile,
"%s", E_HEADER);
298 FPRINTF_WITH_EXCEPTION(outFile, NUMS_FORM, Vs[j - 7], Vs[j - 6], Vs[j - 5], Vs[j - 4], Vs[j - 3], Vs[j - 2],
303 FPRINTF_WITH_EXCEPTION(outFile, NUM_FORM, Vs[l]);
305 FPRINTF_WITH_EXCEPTION(outFile,
"\n");
318 FPRINTF_WITH_EXCEPTION(outFile, NUM_FORM,
value);
320 FPRINTF_WITH_EXCEPTION(outFile,
"\n");
331 if (inds.cbegin() != inds.cend()) {
333 <<
" spectra without associated detectors, probably "
334 "the detectors are not present in the instrument "
335 "definition, this is not unusual. The Y values for "
336 "those spectra have been set to zero.\n";
338 g_log.
debug() <<
"Wrote " << nonMasked <<
" histograms and " << masked
339 <<
" masked histograms to the output SPE file\n";
#define DECLARE_ALGORITHM(classname)
double value
The value of the point.
Base class from which all concrete algorithm classes should be derived.
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.
void progress(double p, const std::string &msg="", double estimatedTime=0.0, int progressPrecision=0)
Sends ProgressNotification.
Class to represent the axis of a workspace.
virtual std::size_t length() const =0
Get the length of the axis.
const std::shared_ptr< Kernel::Unit > & unit() const
The unit for this axis.
A validator which provides a TENTATIVE check that a workspace contains common bins in each spectrum.
@ Save
to specify a file to write to, the file may or may not exist
A validator which checks that a workspace contains histogram data (the default) or point data as requ...
Helper class for reporting progress from algorithms.
A property class for workspaces.
void writeSPEFile(FILE *outSPEFile, const API::MatrixWorkspace_const_sptr &inputWS)
Write the data to the SPE file.
void init() override
Initialization code.
std::vector< double > m_tSignal
void writeBins(const std::vector< double > &Vs, FILE *const outFile) const
Write the values in the array to the file in the correct format.
static const double MASK_ERROR
the error value (=0.0) for spectra whose detectors are all masked, from the SPE specification http://...
void writeMaskFlags(FILE *const outFile) const
Write the mask flags for in a histogram entry.
void logMissingMasked(const std::vector< int > &inds, const size_t nonMasked, const int masked) const
Write a summary information about what the algorithm had managed to save to the file.
int m_remainder
the SPE files have a constant number of numbers written on each line, but depending on the number of ...
void writeValue(const double value, FILE *const outFile) const
Write the value the file a number of times given by m_nbins.
static const double MASK_FLAG
the mask flag (=-1e30) from the SPE specification http://www.mantidproject.org/images/3/3d/Spe_file_f...
void check_and_copy_spectra(const HistogramData::HistogramY &inSignal, const HistogramData::HistogramE &inErr, std::vector< double > &Signal, std::vector< double > &Error) const
method verifies if a spectra contains any NaN or Inf values and replaces these values with SPE-specif...
void writeHist(const API::MatrixWorkspace_const_sptr &WS, FILE *const outFile, const int wsIn) const
Write the bin values and errors in a single histogram spectra to the file.
void exec() override
Execution code.
size_t m_nBins
the number of bins in each histogram, as the histogram must have common bins this shouldn't change
void writeHists(const API::MatrixWorkspace_const_sptr &WS, FILE *const outFile)
Write the bin values and errors for all histograms to the file.
std::vector< double > m_tError
Records the filename and the description of failure.
void debug(const std::string &msg)
Logs at debug level.
void information(const std::string &msg)
Logs at information level.
std::shared_ptr< const MatrixWorkspace > MatrixWorkspace_const_sptr
shared pointer to the matrix workspace base class (const version)
static const unsigned int NUM_PER_LINE
set to the number of numbers on each line (the length of lines is hard-coded in other parts of the co...
@ Input
An input workspace.