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