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