Mantid
Loading...
Searching...
No Matches
SaveCanSAS1D2.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#include "MantidAPI/Axis.h"
11#include "MantidAPI/Run.h"
17#include "MantidKernel/Unit.h"
18
19namespace {
20void encode(std::string &data) {
21 std::string buffer;
22 buffer.reserve(data.size());
23
24 for (auto &element : data) {
25 switch (element) {
26 case '&':
27 buffer.append("&");
28 break;
29 case '\"':
30 buffer.append(""");
31 break;
32 case '\'':
33 buffer.append("'");
34 break;
35 case '<':
36 buffer.append("&lt;");
37 break;
38 case '>':
39 buffer.append("&gt;");
40 break;
41 default:
42 buffer.push_back(element);
43 }
44 }
45
46 data.swap(buffer);
47}
48} // namespace
49
50using namespace Mantid::Kernel;
51using namespace Mantid::Geometry;
52using namespace Mantid::API;
53
54namespace Mantid::DataHandling {
55
56// Register the algorithm into the AlgorithmFactory
58
59
60void SaveCanSAS1D2::init() {
62
63 declareProperty(
65 std::make_shared<API::WorkspaceUnitValidator>("Wavelength")),
66 "The transmission workspace. Optional. If given, will be saved at "
67 "TransmissionSpectrum");
68
69 declareProperty(std::make_unique<API::WorkspaceProperty<>>(
71 std::make_shared<API::WorkspaceUnitValidator>("Wavelength")),
72 "The transmission workspace of the Can. Optional. If given, will be "
73 "saved at TransmissionSpectrum");
74
75 declareProperty("SampleTransmissionRunNumber", "", "The run number for the sample transmission workspace. Optional.");
76 declareProperty("SampleDirectRunNumber", "", "The run number for the sample direct workspace. Optional.");
77 declareProperty("CanScatterRunNumber", "", "The run number for the can scatter workspace. Optional.");
78 declareProperty("CanDirectRunNumber", "", "The run number for the can direct workspace. Optional.");
79 declareProperty("OneSpectrumPerFile", false, "If true, each spectrum will be saved in an invididual file");
80}
81
84 m_workspace = getProperty("InputWorkspace");
85 m_trans_ws = getProperty("Transmission");
86 m_transcan_ws = getProperty("TransmissionCan");
87 if (!m_workspace) {
88 throw std::invalid_argument("Invalid inputworkspace ,Error in SaveCanSAS1D");
89 }
90
91 if ((m_trans_ws && m_trans_ws->getNumberHistograms() > 1) ||
92 (m_transcan_ws && m_transcan_ws->getNumberHistograms() > 1)) {
93 throw std::invalid_argument("Error in SaveCanSAS1D - more than one "
94 "histogram for the transmission workspaces");
95 }
96
97 // write xml manually as the user requires a specific format were the
98 // placement of new line characters is controled
99 // and this can't be done in using the stylesheet part in Poco or libXML
100
101 size_t i = 0;
102 while (i < m_workspace->getNumberHistograms()) {
103 std::string fileName;
104 if (getProperty("OneSpectrumPerFile")) {
105 fileName = getPropertyValue("FileName");
106 size_t extPosition = fileName.find(".xml");
107 if (extPosition == std::string::npos)
108 extPosition = fileName.size();
109 std::ostringstream ss;
110 ss << std::string(fileName, 0, extPosition) << "_" << i;
111 auto axis = m_workspace->getAxis(1);
112 if (axis->isNumeric()) {
113 auto binEdgeAxis = dynamic_cast<BinEdgeAxis *>(axis);
114 if (binEdgeAxis)
115 ss << "_" << binEdgeAxis->label(i);
116 else
117 ss << "_" << axis->getValue(i) << axis->unit()->label().ascii();
118 } else if (axis->isText())
119 ss << "_" << axis->label(i);
120 ss << std::string(fileName, extPosition);
121 fileName = ss.str();
122 } else {
123 fileName = getPropertyValue("FileName");
124 }
125
126 prepareFileToWriteEntry(fileName);
127 m_outFile << "\n\t<SASentry name=\"" << m_workspace->getName() << "\">";
128
129 std::string sasTitle;
130 createSASTitleElement(sasTitle);
131 m_outFile << sasTitle;
132
133 std::string sasRun;
134 createSASRunElement(sasRun);
135 m_outFile << sasRun;
136
137 std::string dataUnit = m_workspace->YUnitLabel();
138 // look for xml special characters and replace with entity refrence
140
141 std::string sasData;
142 if (getProperty("OneSpectrumPerFile")) {
143 createSASDataElement(sasData, i);
144 i++;
145 } else {
146 while (i < m_workspace->getNumberHistograms()) {
147 createSASDataElement(sasData, i);
148 i++;
149 }
150 }
151 m_outFile << sasData;
152
153 if (m_trans_ws) {
154 std::string transData;
155 createSASTransElement(transData, "sample");
156 m_outFile << transData;
157 }
158 if (m_transcan_ws) {
159 std::string transData;
160 createSASTransElement(transData, "can");
161 m_outFile << transData;
162 }
163
164 std::string sasSample;
165 createSASSampleElement(sasSample);
166 m_outFile << sasSample;
167
168 // Recording the SAS instrument can throw, if there
169 // are no detecors present
170 std::string sasInstrument;
171 try {
172 createSASInstrument(sasInstrument);
174 throw;
175 } catch (std::runtime_error &) {
176 throw;
177 }
178 m_outFile << sasInstrument;
179
180 std::string sasProcess;
181 createSASProcessElement(sasProcess);
182 m_outFile << sasProcess;
183
184 std::string sasNote = "\n\t\t<SASnote>";
185 sasNote += "\n\t\t</SASnote>";
186 m_outFile << sasNote;
187
188 m_outFile << "\n\t</SASentry>";
189 m_outFile << "\n</SASroot>";
190 m_outFile.close();
191 }
192}
193
197void SaveCanSAS1D2::createSASRootElement(std::string &rootElem) {
198 rootElem = "<SASroot version=\"1.1\"";
199 rootElem += "\n\t\t xmlns=\"urn:cansas1d:1.1\"";
200 rootElem += "\n\t\t xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"";
201 rootElem += "\n\t\t xsi:schemaLocation=\"urn:cansas1d:1.1 "
202 "http://www.cansas.org/formats/1.1/cansas1d.xsd\"\n\t\t>";
203}
204
208void SaveCanSAS1D2::createSASProcessElement(std::string &sasProcess) {
209 sasProcess = "\n\t\t<SASprocess>";
210 // outFile<<sasProcess;
211
212 std::string sasProcname = "\n\t\t\t<name>";
213 sasProcname += "Mantid generated CanSAS1D XML";
214 sasProcname += "</name>";
215 sasProcess += sasProcname;
216
217 time_t rawtime;
218 time(&rawtime);
219
220 char temp[25];
221 strftime(temp, 25, "%d-%b-%Y %H:%M:%S", localtime(&rawtime));
222 std::string sasDate(temp);
223
224 std::string sasProcdate = "\n\t\t\t<date>";
225 sasProcdate += sasDate;
226 sasProcdate += "</date>";
227 sasProcess += sasProcdate;
228
229 std::string sasProcsvn = "\n\t\t\t<term name=\"svn\">";
230 sasProcsvn += MantidVersion::version();
231 sasProcsvn += "</term>";
232 sasProcess += sasProcsvn;
233
234 const API::Run &run = m_workspace->run();
235 std::string user_file;
236 if (run.hasProperty("UserFile")) {
237 user_file = run.getLogData("UserFile")->value();
238 } else {
239 g_log.information("No user file was found in the input workspace.");
240 }
241
242 std::string sasProcuserfile = "\n\t\t\t<term name=\"user_file\">";
243 sasProcuserfile += user_file;
244 sasProcuserfile += "</term>";
245 // outFile<<sasProcuserfile;
246 sasProcess += sasProcuserfile;
247
248 std::string batch_file;
249 if (run.hasProperty("BatchFile")) {
250 batch_file = run.getLogData("BatchFile")->value();
251 }
252 std::string sasProcbatchfile = "\n\t\t\t<term name=\"batch_file\">";
253 sasProcbatchfile += batch_file;
254 sasProcbatchfile += "</term>";
255 sasProcess += sasProcbatchfile;
256
257 if (m_trans_ws) {
258 // Add other run numbers
259 // SampleTransmission
260 const auto sample_trans_run = getPropertyValue("SampleTransmissionRunNumber");
261 sasProcess += "\n\t\t\t<term name=\"sample_trans_run\">";
262 sasProcess += sample_trans_run + "</term>";
263
264 // SampleDirect
265 const auto sample_direct_run = getPropertyValue("SampleDirectRunNumber");
266 sasProcess += "\n\t\t\t<term name=\"sample_direct_run\">";
267 sasProcess += sample_direct_run + "</term>";
268 }
269
270 // can run number if available
271 if (m_transcan_ws) {
272 std::string can_run;
273 if (m_transcan_ws->run().hasProperty("run_number")) {
274 Kernel::Property *logP = m_transcan_ws->run().getLogData("run_number");
275 can_run = logP->value();
276 } else {
277 g_log.debug() << "Didn't find RunNumber log in workspace. Writing "
278 "<Run></Run> to the CANSAS file\n";
279 }
280 std::string sasProcCanRun = "\n\t\t\t<term name=\"can_trans_run\">";
281 sasProcCanRun += can_run;
282 sasProcCanRun += "</term>";
283 sasProcess += sasProcCanRun;
284
285 // CanScatter
286 const auto can_scatter_run = getPropertyValue("CanScatterRunNumber");
287 sasProcess += "\n\t\t\t<term name=\"can_scatter_run\">";
288 sasProcess += can_scatter_run + "</term>";
289
290 // CanDirect
291 const auto can_direct_run = getPropertyValue("CanDirectRunNumber");
292 sasProcess += "\n\t\t\t<term name=\"can_direct_run\">";
293 sasProcess += can_direct_run + "</term>";
294 }
295
296 // Reduction process note, if available
297 std::string process_xml = getProperty("Process");
298 if (!process_xml.empty()) {
299 std::string processNote = "\n\t\t\t<SASprocessnote>";
300 encode(process_xml);
301 processNote += process_xml;
302 processNote += "</SASprocessnote>";
303 sasProcess += processNote;
304 } else {
305 sasProcess += "\n\t\t\t<SASprocessnote/>";
306 }
307
308 sasProcess += "\n\t\t</SASprocess>";
309}
310
316void SaveCanSAS1D2::createSASTransElement(std::string &sasTrans, const std::string &name) {
318 if (name == "sample") {
319 m_ws = m_trans_ws;
320 } else if (name == "can") {
321 m_ws = m_transcan_ws;
322 } else {
323 return; // does not change sasTrans... it will add nothing
324 }
325
326 if (m_ws->getNumberHistograms() != 1)
327 return; // does not change sasTrans
328
329 std::stringstream trans;
330
331 trans << "\n\t\t<SAStransmission_spectrum name=\"" << name << "\">";
332 std::string t_unit = m_ws->YUnit();
333 std::string lambda_unit = m_ws->getAxis(0)->unit()->label();
334 if (t_unit.empty())
335 t_unit = "none";
336 if (lambda_unit.empty() || lambda_unit == "Angstrom")
337 lambda_unit = "A";
338
339 // x data is the Lambda in xml. If histogramdata take the mean
340 const auto lambda = m_ws->points(0);
341 // y data is the T in xml.
342 const auto &trans_value = m_ws->y(0);
343 // e data is the Tdev in xml.
344 const auto &trans_err = m_ws->e(0);
345 for (size_t j = 0; j < trans_value.size(); ++j) {
346 trans << "\n\t\t\t<Tdata><Lambda unit=\"" << lambda_unit << "\">";
347 if (std::isnan(lambda[j]))
348 trans << "NaN";
349 else
350 trans << lambda[j];
351 trans << "</Lambda>"
352 << "<T unit=\"" << t_unit << "\">";
353 if (std::isnan(trans_value[j]))
354 trans << "NaN";
355 else
356 trans << trans_value[j];
357 trans << "</T><Tdev unit=\"none\">";
358 if (std::isnan(trans_err[j]))
359 trans << "NaN";
360 else
361 trans << trans_err[j];
362 trans << "</Tdev></Tdata>";
363 }
364 trans << "\n\t\t</SAStransmission_spectrum>";
365 sasTrans += trans.str();
366}
367
373void SaveCanSAS1D2::writeHeader(const std::string &fileName) {
374 try {
375 m_outFile.open(fileName.c_str(), std::ios::out | std::ios::trunc);
376 // write the file header
377 m_outFile << "<?xml version=\"1.0\"?>\n"
378 << "<?xml-stylesheet type=\"text/xsl\" href=\"cansas1d.xsl\" ?>\n";
379 std::string sasroot;
380 createSASRootElement(sasroot);
381 m_outFile << sasroot;
382 } catch (std::fstream::failure &) {
383 throw Exception::FileError("Error opening the output file for writing", fileName);
384 }
385}
386} // namespace Mantid::DataHandling
#define DECLARE_ALGORITHM(classname)
Definition: Algorithm.h:576
const std::vector< double > * lambda
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
Stores numeric values that are assumed to be bin edge values.
Definition: BinEdgeAxis.h:20
std::string label(const std::size_t &index) const override
Returns a text label which shows the value at the given bin index.
Definition: BinEdgeAxis.cpp:93
bool hasProperty(const std::string &name) const
Does the property exist on the object.
Definition: LogManager.cpp:265
Kernel::Property * getLogData(const std::string &name) const
Access a single log entry.
Definition: LogManager.h:129
This class stores information regarding an experimental run as a series of log entries.
Definition: Run.h:38
A property class for workspaces.
This algorithm saves workspace into CanSAS1d format.
Definition: SaveCanSAS1D2.h:64
API::MatrixWorkspace_const_sptr m_transcan_ws
Definition: SaveCanSAS1D2.h:88
API::MatrixWorkspace_const_sptr m_trans_ws
points to the workspace that will be written to file
Definition: SaveCanSAS1D2.h:88
void createSASRootElement(std::string &rootElem) override
Create the SASRoot element.
void createSASProcessElement(std::string &sasProcess)
this method creates SASProcess element
void createSASTransElement(std::string &sasTrans, const std::string &name)
this method creates SAStransmission_spectrum element
void exec() override
Overwrites Algorithm method.
void writeHeader(const std::string &fileName) override
Overwrites writeHeader method.
std::fstream m_outFile
an fstream object is used to write the xml manually as the user requires a specific format with new l...
Definition: SaveCanSAS1D.h:146
const std::string name() const override
function to return a name of the algorithm, must be overridden in all algorithms
Definition: SaveCanSAS1D.h:85
void createSASTitleElement(std::string &sasTitle)
this method creates a sasTitle element
void createSASInstrument(std::string &sasInstrument)
this method creates a sasInstrument element
void init() override
Overwrites Algorithm method.
void searchandreplaceSpecialChars(std::string &input)
this method searches for xml special characters and replace with entity references
void createSASDataElement(std::string &sasData, size_t workspaceIndex)
this method creates a sasData element
void createSASSampleElement(std::string &sasSample)
this method creates a sasSample element
void prepareFileToWriteEntry(const std::string &fileName)
Opens the output file and, as necessary blanks it, writes the file header and moves the file pointer.
void createSASRunElement(std::string &sasRun)
this method creates a sasRun Element
API::MatrixWorkspace_const_sptr m_workspace
points to the workspace that will be written to file
Definition: SaveCanSAS1D.h:142
Records the filename and the description of failure.
Definition: Exception.h:98
Exception for when an item is not found in a collection.
Definition: Exception.h:145
void debug(const std::string &msg)
Logs at debug level.
Definition: Logger.cpp:114
void information(const std::string &msg)
Logs at information level.
Definition: Logger.cpp:105
static const char * version()
The full version number.
Base class for properties.
Definition: Property.h:94
virtual std::string value() const =0
Returns the value of the property as a string.
std::shared_ptr< const MatrixWorkspace > MatrixWorkspace_const_sptr
shared pointer to the matrix workspace base class (const version)
@ Input
An input workspace.
Definition: Property.h:53