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 const &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 declareProperty(
82 "BackgroundSubtractionWorkspace", "",
83 "The name of the workspace used in the scaled background subtraction, to be included in the metadata. Optional.");
84 declareProperty(
85 "BackgroundSubtractionScaleFactor", 0.0,
86 "The scale factor used in the scaled background subtraction, to be included in the metadata. Optional.");
87}
88
91 m_workspace = getProperty("InputWorkspace");
92 m_trans_ws = getProperty("Transmission");
93 m_transcan_ws = getProperty("TransmissionCan");
94 if (!m_workspace) {
95 throw std::invalid_argument("Invalid inputworkspace ,Error in SaveCanSAS1D");
96 }
97
98 if ((m_trans_ws && m_trans_ws->getNumberHistograms() > 1) ||
99 (m_transcan_ws && m_transcan_ws->getNumberHistograms() > 1)) {
100 throw std::invalid_argument("Error in SaveCanSAS1D - more than one "
101 "histogram for the transmission workspaces");
102 }
103
104 // write xml manually as the user requires a specific format were the
105 // placement of new line characters is controled
106 // and this can't be done in using the stylesheet part in Poco or libXML
107
108 size_t i = 0;
109 while (i < m_workspace->getNumberHistograms()) {
110 std::string fileName;
111 if (getProperty("OneSpectrumPerFile")) {
112 fileName = getPropertyValue("FileName");
113 size_t extPosition = fileName.find(".xml");
114 if (extPosition == std::string::npos)
115 extPosition = fileName.size();
116 std::ostringstream ss;
117 ss << std::string(fileName, 0, extPosition) << "_" << i;
118 auto axis = m_workspace->getAxis(1);
119 if (axis->isNumeric()) {
120 auto binEdgeAxis = dynamic_cast<BinEdgeAxis *>(axis);
121 if (binEdgeAxis)
122 ss << "_" << binEdgeAxis->label(i);
123 else
124 ss << "_" << axis->getValue(i) << axis->unit()->label().ascii();
125 } else if (axis->isText())
126 ss << "_" << axis->label(i);
127 ss << std::string(fileName, extPosition);
128 fileName = ss.str();
129 } else {
130 fileName = getPropertyValue("FileName");
131 }
132
133 prepareFileToWriteEntry(fileName);
134 m_outFile << "\n\t<SASentry name=\"" << m_workspace->getName() << "\">";
135
136 std::string sasTitle;
137 createSASTitleElement(sasTitle);
138 m_outFile << sasTitle;
139
140 std::string sasRun;
141 createSASRunElement(sasRun);
142 m_outFile << sasRun;
143
144 std::string dataUnit = m_workspace->YUnitLabel();
145 // look for xml special characters and replace with entity refrence
147
148 std::string sasData;
149 if (getProperty("OneSpectrumPerFile")) {
150 createSASDataElement(sasData, i);
151 i++;
152 } else {
153 while (i < m_workspace->getNumberHistograms()) {
154 createSASDataElement(sasData, i);
155 i++;
156 }
157 }
158 m_outFile << sasData;
159
160 if (m_trans_ws) {
161 std::string transData;
162 createSASTransElement(transData, "sample");
163 m_outFile << transData;
164 }
165 if (m_transcan_ws) {
166 std::string transData;
167 createSASTransElement(transData, "can");
168 m_outFile << transData;
169 }
170
171 std::string sasSample;
172 createSASSampleElement(sasSample);
173 m_outFile << sasSample;
174
175 // Recording the SAS instrument can throw, if there
176 // are no detecors present
177 std::string sasInstrument;
178 try {
179 createSASInstrument(sasInstrument);
181 throw;
182 } catch (std::runtime_error &) {
183 throw;
184 }
185 m_outFile << sasInstrument;
186
187 std::string sasProcess;
188 createSASProcessElement(sasProcess);
189 m_outFile << sasProcess;
190
191 std::string sasNote = "\n\t\t<SASnote>";
192 sasNote += "\n\t\t</SASnote>";
193 m_outFile << sasNote;
194
195 m_outFile << "\n\t</SASentry>";
196 m_outFile << "\n</SASroot>";
197 m_outFile.close();
198 }
199}
200
204void SaveCanSAS1D2::createSASRootElement(std::string &rootElem) {
205 rootElem = "<SASroot version=\"1.1\"";
206 rootElem += "\n\t\t xmlns=\"urn:cansas1d:1.1\"";
207 rootElem += "\n\t\t xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"";
208 rootElem += "\n\t\t xsi:schemaLocation=\"urn:cansas1d:1.1 "
209 "http://www.cansas.org/formats/1.1/cansas1d.xsd\"\n\t\t>";
210}
211
215void SaveCanSAS1D2::createSASProcessElement(std::string &sasProcess) {
216 sasProcess = "\n\t\t<SASprocess>";
217 // outFile<<sasProcess;
218
219 std::string sasProcname = "\n\t\t\t<name>";
220 sasProcname += "Mantid generated CanSAS1D XML";
221 sasProcname += "</name>";
222 sasProcess += sasProcname;
223
224 time_t rawtime;
225 time(&rawtime);
226
227 char temp[25];
228 strftime(temp, 25, "%d-%b-%Y %H:%M:%S", localtime(&rawtime));
229 std::string sasDate(temp);
230
231 std::string sasProcdate = "\n\t\t\t<date>";
232 sasProcdate += sasDate;
233 sasProcdate += "</date>";
234 sasProcess += sasProcdate;
235
236 std::string sasProcsvn = "\n\t\t\t<term name=\"svn\">";
237 sasProcsvn += MantidVersion::version();
238 sasProcsvn += "</term>";
239 sasProcess += sasProcsvn;
240
241 const API::Run &run = m_workspace->run();
242 std::string user_file;
243 if (run.hasProperty("UserFile")) {
244 user_file = run.getLogData("UserFile")->value();
245 } else {
246 g_log.information("No user file was found in the input workspace.");
247 }
248
249 std::string sasProcuserfile = "\n\t\t\t<term name=\"user_file\">";
250 sasProcuserfile += user_file;
251 sasProcuserfile += "</term>";
252 // outFile<<sasProcuserfile;
253 sasProcess += sasProcuserfile;
254
255 std::string batch_file;
256 if (run.hasProperty("BatchFile")) {
257 batch_file = run.getLogData("BatchFile")->value();
258 }
259 std::string sasProcbatchfile = "\n\t\t\t<term name=\"batch_file\">";
260 sasProcbatchfile += batch_file;
261 sasProcbatchfile += "</term>";
262 sasProcess += sasProcbatchfile;
263
264 if (m_trans_ws) {
265 // Add other run numbers
266 // SampleTransmission
267 const auto sample_trans_run = getPropertyValue("SampleTransmissionRunNumber");
268 sasProcess += "\n\t\t\t<term name=\"sample_trans_run\">";
269 sasProcess += sample_trans_run + "</term>";
270
271 // SampleDirect
272 const auto sample_direct_run = getPropertyValue("SampleDirectRunNumber");
273 sasProcess += "\n\t\t\t<term name=\"sample_direct_run\">";
274 sasProcess += sample_direct_run + "</term>";
275 }
276
277 // can run number if available
278 if (m_transcan_ws) {
279 std::string can_run;
280 if (m_transcan_ws->run().hasProperty("run_number")) {
281 Kernel::Property const *const logP = m_transcan_ws->run().getLogData("run_number");
282 can_run = logP->value();
283 } else {
284 g_log.debug() << "Didn't find RunNumber log in workspace. Writing "
285 "<Run></Run> to the CANSAS file\n";
286 }
287 std::string sasProcCanRun = "\n\t\t\t<term name=\"can_trans_run\">";
288 sasProcCanRun += can_run;
289 sasProcCanRun += "</term>";
290 sasProcess += sasProcCanRun;
291
292 // CanScatter
293 const auto can_scatter_run = getPropertyValue("CanScatterRunNumber");
294 sasProcess += "\n\t\t\t<term name=\"can_scatter_run\">";
295 sasProcess += can_scatter_run + "</term>";
296
297 // CanDirect
298 const auto can_direct_run = getPropertyValue("CanDirectRunNumber");
299 sasProcess += "\n\t\t\t<term name=\"can_direct_run\">";
300 sasProcess += can_direct_run + "</term>";
301 }
302
303 // Scaled Background Subtraction information.
304 auto const &bgsubWsName = getPropertyValue("BackgroundSubtractionWorkspace");
305 auto const &bgsubScaleFactor = getPropertyValue("BackgroundSubtractionScaleFactor");
306 if (!bgsubWsName.empty()) {
307 sasProcess += "\n\t\t\t<term name=\"scaled_bgsub_workspace\">";
308 sasProcess += bgsubWsName + "</term>";
309 sasProcess += "\n\t\t\t<term name=\"scaled_bgsub_scale_factor\">";
310 sasProcess += bgsubScaleFactor + "</term>";
311 }
312
313 // Reduction process note, if available
314 std::string process_xml = getProperty("Process");
315 if (!process_xml.empty()) {
316 std::string processNote = "\n\t\t\t<SASprocessnote>";
317 encode(process_xml);
318 processNote += process_xml;
319 processNote += "</SASprocessnote>";
320 sasProcess += processNote;
321 } else {
322 sasProcess += "\n\t\t\t<SASprocessnote/>";
323 }
324
325 sasProcess += "\n\t\t</SASprocess>";
326}
327
333void SaveCanSAS1D2::createSASTransElement(std::string &sasTrans, const std::string &name) {
335 if (name == "sample") {
336 m_ws = m_trans_ws;
337 } else if (name == "can") {
338 m_ws = m_transcan_ws;
339 } else {
340 return; // does not change sasTrans... it will add nothing
341 }
342
343 if (m_ws->getNumberHistograms() != 1)
344 return; // does not change sasTrans
345
346 std::stringstream trans;
347
348 trans << "\n\t\t<SAStransmission_spectrum name=\"" << name << "\">";
349 std::string t_unit = m_ws->YUnit();
350 std::string lambda_unit = m_ws->getAxis(0)->unit()->label();
351 if (t_unit.empty())
352 t_unit = "none";
353 if (lambda_unit.empty() || lambda_unit == "Angstrom")
354 lambda_unit = "A";
355
356 // x data is the Lambda in xml. If histogramdata take the mean
357 const auto lambda = m_ws->points(0);
358 // y data is the T in xml.
359 const auto &trans_value = m_ws->y(0);
360 // e data is the Tdev in xml.
361 const auto &trans_err = m_ws->e(0);
362 for (size_t j = 0; j < trans_value.size(); ++j) {
363 trans << "\n\t\t\t<Tdata><Lambda unit=\"" << lambda_unit << "\">";
364 if (std::isnan(lambda[j]))
365 trans << "NaN";
366 else
367 trans << lambda[j];
368 trans << "</Lambda>"
369 << "<T unit=\"" << t_unit << "\">";
370 if (std::isnan(trans_value[j]))
371 trans << "NaN";
372 else
373 trans << trans_value[j];
374 trans << "</T><Tdev unit=\"none\">";
375 if (std::isnan(trans_err[j]))
376 trans << "NaN";
377 else
378 trans << trans_err[j];
379 trans << "</Tdev></Tdata>";
380 }
381 trans << "\n\t\t</SAStransmission_spectrum>";
382 sasTrans += trans.str();
383}
384
390void SaveCanSAS1D2::writeHeader(const std::string &fileName) {
391 try {
392 m_outFile.open(fileName.c_str(), std::ios::out | std::ios::trunc);
393 // write the file header
394 m_outFile << "<?xml version=\"1.0\"?>\n"
395 << "<?xml-stylesheet type=\"text/xsl\" href=\"cansas1d.xsl\" ?>\n";
396 std::string sasroot;
397 createSASRootElement(sasroot);
398 m_outFile << sasroot;
399 } catch (std::fstream::failure &) {
400 throw Exception::FileError("Error opening the output file for writing", fileName);
401 }
402}
403} // 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:141
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 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