Mantid
Loading...
Searching...
No Matches
SaveRKH.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
8
9#include "MantidAPI/Axis.h"
13#include "MantidKernel/Unit.h"
15
16#include <Poco/DateTimeFormatter.h>
17#include <Poco/LocalDateTime.h>
18
19namespace Mantid::DataHandling {
20
21// Register the algorithm into the AlgorithmFactory
22DECLARE_ALGORITHM(SaveRKH)
23
24using namespace API;
25
30 declareProperty(std::make_unique<API::WorkspaceProperty<>>("InputWorkspace", "", Kernel::Direction::Input),
31 "The name of the workspace to save");
32 const std::vector<std::string> fileExts{".txt", ".Q", ".dat"};
33 declareProperty(std::make_unique<API::FileProperty>("Filename", "", API::FileProperty::Save, fileExts),
34 "The name to use when saving the file");
35 declareProperty("Append", true, "If true and Filename already exists, append, else overwrite");
36}
37
42 // Retrieve the input workspace
43 m_workspace = getProperty("InputWorkspace");
44
45 m_2d = m_workspace->getNumberHistograms() > 1 && m_workspace->blocksize() > 1;
46
47 // If a 2D workspace, check that it has two numeric axes - bail out if not
48 if (m_2d && !(m_workspace->getAxis(1)->isNumeric())) {
49 g_log.error("This algorithm expects a 2d workspace to have been converted away from \
50 spectrum numbers on the vertical axis");
51 throw std::invalid_argument("Cannot write out this kind of workspace");
52 }
53
54 // Check whether to append to an already existing file or overwrite
55 using std::ios_base;
56 ios_base::openmode mode = (getProperty("Append") ? (ios_base::out | ios_base::app) : ios_base::out);
57 // Open/create the file
58 const std::string filename = getProperty("Filename");
59 m_outRKH.open(filename.c_str(), mode);
60
61 if (!m_outRKH) {
62 g_log.error() << "An error occurred while attempting to open the file " << filename << "\n";
63 throw std::runtime_error("An error occurred while trying to open the output file for writing");
64 }
65
66 // Write out the header
67 this->writeHeader();
68
69 // Now write out the data using the appropriate method
70 if (m_2d)
71 this->write2D();
72 else
73 this->write1D();
74
75 // Close the file
76 m_outRKH.close();
77}
78
81 // The instrument name
82 m_outRKH << " " << m_workspace->getInstrument()->getName() << " ";
83 Poco::LocalDateTime timestamp;
84 // The sample file has the format of the data/time as in this example Thu
85 // 28-OCT-2004 12:23
86 m_outRKH << Poco::DateTimeFormatter::format(timestamp, std::string("%w")) << " "
87 << Poco::DateTimeFormatter::format(timestamp, std::string("%d")) << "-";
88 std::string month = Poco::DateTimeFormatter::format(timestamp, std::string("%b"));
89 std::transform(month.begin(), month.end(), month.begin(), toupper);
90 m_outRKH << month << "-" << Poco::DateTimeFormatter::format(timestamp, std::string("%Y %H:%M"))
91 << " Workspace: " << getPropertyValue("InputWorkspace") << "\n";
92
93 if (m_2d) {
94 // The units that the data is in
95 const Kernel::Unit_const_sptr unit1 = m_workspace->getAxis(0)->unit();
96 const Kernel::Unit_const_sptr unit2 = m_workspace->getAxis(1)->unit();
97 const int unitCode1 = unit1->caption() == "q" ? Q_CODE : 0;
98 const int unitCode2 = unit2->caption() == "q" ? Q_CODE : 0;
99 m_outRKH << " " << unitCode1 << " " << unit1->caption() << " (" << unit1->label().ascii() << ")\n"
100 << " " << unitCode2 << " " << unit2->caption() << " (" << unit2->label().ascii() << ")\n"
101 << " 0 " << m_workspace->YUnitLabel() << "\n"
102 << " 1\n";
103 }
104 // The workspace title
105 m_outRKH << " " << m_workspace->getTitle() << "\n";
106
107 if (!m_2d) {
108 const size_t noDataPoints = m_workspace->size();
109 m_outRKH << std::setw(5) << noDataPoints << " 0 0 0 1" << std::setw(5) << noDataPoints << " 0\n"
110 << " 0 0 0 0\n"
111 << " 3 (F12.5,2E16.6)\n";
112 }
113}
114
117 const size_t noDataPoints = m_workspace->size();
118 const size_t nhist = m_workspace->getNumberHistograms();
119 const bool horizontal = nhist == 1;
120 if (horizontal) {
121 g_log.notice() << "Values in first column are the X values\n";
122 if (m_workspace->getAxis(0)->unit())
123 g_log.notice() << "in units of " << m_workspace->getAxis(0)->unit()->unitID() << "\n";
124 } else
125 g_log.notice("Values in first column are spectrum numbers");
126 const bool histogram = m_workspace->isHistogramData();
127 Progress prg(this, 0.0, 1.0, noDataPoints);
128 const size_t nbins = m_workspace->blocksize();
129
130 for (size_t i = 0; i < nhist; ++i) {
131 const auto &xdata = m_workspace->x(i);
132 const auto &ydata = m_workspace->y(i);
133 const auto &edata = m_workspace->e(i);
134
135 specnum_t specid(0);
136 try {
137 specid = m_workspace->getSpectrum(i).getSpectrumNo();
138 } catch (...) {
139 specid = static_cast<specnum_t>(i + 1);
140 }
141
142 auto hasDx = m_workspace->hasDx(i);
143 auto dXvals = m_workspace->pointStandardDeviations(i);
144
145 for (size_t j = 0; j < nbins; ++j) {
146 // Calculate/retrieve the value to go in the first column
147 double xval(0.0);
148 if (horizontal)
149 xval = histogram ? 0.5 * (xdata[j] + xdata[j + 1]) : xdata[j];
150 else {
151 xval = static_cast<double>(specid);
152 }
153
154 m_outRKH << std::fixed << std::setw(12) << std::setprecision(5) << xval << std::scientific << std::setw(16)
155 << std::setprecision(6) << ydata[j] << std::setw(16) << edata[j];
156
157 if (hasDx) {
158 m_outRKH << std::setw(16) << dXvals[j];
159 }
160
161 m_outRKH << "\n";
162
163 prg.report();
164 }
165 }
166}
169 // First the axis values
170 const Axis *const X = m_workspace->getAxis(0);
171 const size_t Xbins = X->length();
172 m_outRKH << " " << Xbins << "\n";
173 for (size_t i = 0; i < Xbins; ++i) {
174 m_outRKH << std::setw(14) << std::scientific << std::setprecision(6) << (*X)(i);
175 if ((i + 1) % LINE_LENGTH == 0)
176 m_outRKH << "\n";
177 }
178 const Axis *const Y = m_workspace->getAxis(1);
179 const size_t Ybins = Y->length();
180 m_outRKH << "\n " << Ybins << '\n';
181 for (size_t i = 0; i < Ybins; ++i) {
182 m_outRKH << std::setw(14) << std::scientific << std::setprecision(6) << (*Y)(i);
183 if ((i + 1) % LINE_LENGTH == 0)
184 m_outRKH << "\n";
185 }
186
187 // Now the data
188 const size_t num_hist = m_workspace->getNumberHistograms();
189 m_outRKH << "\n " << m_workspace->blocksize() << " " << num_hist << " " << std::scientific
190 << std::setprecision(12) << 1.0 << "\n";
191 const int iflag = 3;
192 m_outRKH << " " << iflag << "(8E12.4)\n";
193
194 bool requireNewLine = false;
195 int itemCount(0);
196 for (size_t i = 0; i < num_hist; ++i) {
197 for (const auto &yVal : m_workspace->y(i)) {
198 m_outRKH << std::setw(12) << std::scientific << std::setprecision(4) << yVal;
199 requireNewLine = true;
200 if ((itemCount + 1) % LINE_LENGTH == 0) {
201 m_outRKH << "\n";
202 requireNewLine = false;
203 }
204 ++itemCount;
205 }
206 }
207
208 // extra new line is required if number of data written out in last column is
209 // less than LINE_LENGTH
210 if (requireNewLine)
211 m_outRKH << "\n";
212
213 // Then all the error values
214 itemCount = 0;
215 for (size_t i = 0; i < num_hist; ++i) {
216 for (const auto &eVal : m_workspace->e(i)) {
217 m_outRKH << std::setw(12) << std::scientific << std::setprecision(4) << eVal;
218 if ((itemCount + 1) % LINE_LENGTH == 0)
219 m_outRKH << "\n";
220 ++itemCount;
221 }
222 }
223}
224
225} // namespace Mantid::DataHandling
#define DECLARE_ALGORITHM(classname)
Definition: Algorithm.h:576
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
Definition: Algorithm.cpp:1913
std::string getPropertyValue(const std::string &name) const override
Get the value of a property as a string.
Definition: Algorithm.cpp:2026
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
Definition: Algorithm.cpp:2076
Kernel::Logger & g_log
Definition: Algorithm.h:451
Class to represent the axis of a workspace.
Definition: Axis.h:30
@ Save
to specify a file to write to, the file may or may not exist
Definition: FileProperty.h:49
Helper class for reporting progress from algorithms.
Definition: Progress.h:25
A property class for workspaces.
@ LINE_LENGTH
with the unit Q
Definition: SaveRKH.h:48
@ Q_CODE
this is the integer code the RKH file format associates
Definition: SaveRKH.h:46
std::ofstream m_outRKH
The output filehandle.
Definition: SaveRKH.h:66
void init() override
Initialisation code.
Definition: SaveRKH.cpp:29
API::MatrixWorkspace_const_sptr m_workspace
The input workspace.
Definition: SaveRKH.h:62
void write2D()
Writes out the 2D data.
Definition: SaveRKH.cpp:168
void exec() override
Execution code.
Definition: SaveRKH.cpp:41
void write1D()
Writes out the 1D data.
Definition: SaveRKH.cpp:116
void writeHeader()
Writes out the header of the output file.
Definition: SaveRKH.cpp:80
bool m_2d
Whether this is a 2D dataset.
Definition: SaveRKH.h:64
void notice(const std::string &msg)
Logs at notice level.
Definition: Logger.cpp:95
void error(const std::string &msg)
Logs at error level.
Definition: Logger.cpp:77
void report()
Increments the loop counter by 1, then sends the progress notification on behalf of its algorithm.
Definition: ProgressBase.h:51
std::shared_ptr< const Unit > Unit_const_sptr
Shared pointer to the Unit base class (const version)
Definition: Unit.h:231
int32_t specnum_t
Typedef for a spectrum Number.
Definition: IDTypes.h:16
@ Input
An input workspace.
Definition: Property.h:53