Mantid
Loading...
Searching...
No Matches
SaveAscii.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 +
7//----------------------------------------------------------------------
8// Includes
9//----------------------------------------------------------------------
18
19#include <boost/tokenizer.hpp>
20#include <fstream>
21#include <set>
22
23namespace Mantid::DataHandling {
24// Register the algorithm into the algorithm factory
25DECLARE_ALGORITHM(SaveAscii)
26
27using namespace Kernel;
28using namespace API;
29
31SaveAscii::SaveAscii() : m_separatorIndex() {}
32
35 declareProperty(std::make_unique<WorkspaceProperty<MatrixWorkspace>>("InputWorkspace", "", Direction::Input),
36 "The name of the workspace containing the data you want to save to a "
37 "Ascii file.");
38 const std::vector<std::string> asciiExts{".dat", ".txt", ".csv"};
39 declareProperty(std::make_unique<FileProperty>("Filename", "", FileProperty::Save, asciiExts),
40 "The filename of the output Ascii file.");
41
42 auto mustBeNonNegative = std::make_shared<BoundedValidator<int>>();
43 mustBeNonNegative->setLower(0);
44 declareProperty("WorkspaceIndexMin", 0, mustBeNonNegative, "The starting workspace index.");
45 declareProperty("WorkspaceIndexMax", EMPTY_INT(), mustBeNonNegative, "The ending workspace index.");
46 declareProperty(std::make_unique<ArrayProperty<int>>("SpectrumList"), "List of workspace indices to save.");
47 declareProperty("Precision", EMPTY_INT(), mustBeNonNegative, "Precision of output double values.");
48 declareProperty("WriteXError", false, "If true, the error on X will be written as the fourth column.");
49
50 declareProperty("CommentIndicator", "", "Character(s) to put in front of comment lines.");
51
52 // For the ListValidator
53 std::string spacers[6][2] = {{"CSV", ","}, {"Tab", "\t"}, {"Space", " "},
54 {"Colon", ":"}, {"SemiColon", ";"}, {"UserDefined", "UserDefined"}};
55 std::vector<std::string> sepOptions;
56 for (auto &spacer : spacers) {
57 std::string option = spacer[0];
58 m_separatorIndex.insert(std::pair<std::string, std::string>(option, spacer[1]));
59 sepOptions.emplace_back(option);
60 }
61
62 declareProperty("Separator", "CSV", std::make_shared<StringListValidator>(sepOptions),
63 "Character(s) to put as separator between X, Y, E values.");
64
65 declareProperty(std::make_unique<PropertyWithValue<std::string>>("CustomSeparator", "", Direction::Input),
66 "If present, will override any specified choice given to Separator.");
67 getPointerToProperty("CustomSeparator")->setAutoTrim(false);
68
69 setPropertySettings("CustomSeparator",
70 std::make_unique<VisibleWhenProperty>("Separator", IS_EQUAL_TO, "UserDefined"));
71
72 declareProperty("ColumnHeader", true, "If true, put column headers into file. ");
73
74 declareProperty("ICEFormat", false, "If true, special column headers for ICE in file. ");
75}
76
81 // Get the workspace
82 MatrixWorkspace_const_sptr ws = getProperty("InputWorkspace");
83 auto nSpectra = static_cast<int>(ws->getNumberHistograms());
84 auto nBins = static_cast<int>(ws->blocksize());
85
86 // Get the properties
87 std::vector<int> spec_list = getProperty("SpectrumList");
88 int spec_min = getProperty("WorkspaceIndexMin");
89 int spec_max = getProperty("WorkspaceIndexMax");
90 bool writeHeader = getProperty("ColumnHeader");
91
92 // Check whether we need to write the fourth column
93 bool write_dx = getProperty("WriteXError");
94 std::string choice = getPropertyValue("Separator");
95 std::string custom = getPropertyValue("CustomSeparator");
96 std::string sep;
97 // If the custom separator property is not empty, then we use that under any
98 // circumstance.
99 if (!custom.empty()) {
100 sep = custom;
101 }
102 // Else if the separator drop down choice is not UserDefined then we use that.
103 else if (choice != "UserDefined") {
104 auto it = m_separatorIndex.find(choice);
105 sep = it->second;
106 }
107 // If we still have nothing, then we are forced to use a default.
108 if (sep.empty()) {
109 g_log.notice() << "\"UserDefined\" has been selected, but no custom "
110 "separator has been entered. Using default instead.";
111 sep = " , ";
112 }
113 std::string comment = getPropertyValue("CommentIndicator");
114 std::string errstr = "E";
115 std::string errstr2;
116 std::string comstr = " , ";
117 bool ice = getProperty("ICEFormat");
118 if (ice) {
119 // overwrite properties so file can be read by ICE
120 errstr = "Y";
121 errstr2 = "_error";
122 comstr = ", ";
123 writeHeader = true;
124 write_dx = false;
125 comment = "#features:";
126 }
127
128 // Create an spectra index list for output
129 std::set<int> idx;
130
131 // Add spectra interval into the index list
132 if (spec_max != EMPTY_INT() && spec_min != EMPTY_INT()) {
133 if (spec_min >= nSpectra || spec_max >= nSpectra || spec_min > spec_max)
134 throw std::invalid_argument("Inconsistent spectra interval");
135 for (int spec = spec_min; spec <= spec_max; spec++)
136 idx.insert(spec);
137 }
138
139 // Add spectra list into the index list
140 if (!spec_list.empty()) {
141 for (auto &spec : spec_list) {
142 if (spec >= nSpectra)
143 throw std::invalid_argument("Inconsistent spectra list");
144 else
145 idx.insert(spec);
146 }
147 }
148 if (!idx.empty())
149 nSpectra = static_cast<int>(idx.size());
150
151 if (nBins == 0 || nSpectra == 0)
152 throw std::runtime_error("Trying to save an empty workspace");
153
154 std::string filename = getProperty("Filename");
155 std::ofstream file(filename.c_str());
156
157 if (!file) {
158 g_log.error("Unable to create file: " + filename);
159 throw Exception::FileError("Unable to create file: ", filename);
160 }
161
162 // Write the column captions
163 if (writeHeader) {
164 file << comment << "X";
165 if (idx.empty())
166 for (int spec = 0; spec < nSpectra; spec++) {
167 file << comstr << "Y" << spec << comstr << errstr << spec << errstr2;
168 if (write_dx)
169 file << " , DX" << spec;
170 }
171 else
172 for (auto spec : idx) {
173 file << comstr << "Y" << spec << comstr << errstr << spec << errstr2;
174 if (write_dx)
175 file << " , DX" << spec;
176 }
177 file << '\n';
178 }
179
180 // Set the number precision
181 int prec = getProperty("Precision");
182 if (prec != EMPTY_INT())
183 file.precision(prec);
184
185 Progress progress(this, 0.0, 1.0, nBins);
186 auto pointDeltas = ws->pointStandardDeviations(0);
187 auto points = ws->points(0);
188 for (int bin = 0; bin < nBins; bin++) {
189 file << points[bin];
190
191 if (idx.empty())
192 for (int spec = 0; spec < nSpectra; spec++) {
193 file << sep;
194 file << ws->y(spec)[bin];
195 file << sep;
196 file << ws->e(spec)[bin];
197 }
198 else
199 for (auto spec : idx) {
200 file << sep;
201 file << ws->y(spec)[bin];
202 file << sep;
203 file << ws->e(spec)[bin];
204 }
205
206 if (write_dx) {
207 file << sep;
208 file << pointDeltas[bin];
209 }
210 file << '\n';
211 progress.report();
212 }
213}
214
215} // namespace Mantid::DataHandling
#define DECLARE_ALGORITHM(classname)
Definition: Algorithm.h:576
int nSpectra
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
Kernel::Property * getPointerToProperty(const std::string &name) const override
Get a property by name.
Definition: Algorithm.cpp:2033
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
void progress(double p, const std::string &msg="", double estimatedTime=0.0, int progressPrecision=0)
Sends ProgressNotification.
Definition: Algorithm.cpp:231
@ 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.
void init() override
Overwrites Algorithm method.
Definition: SaveAscii.cpp:34
std::map< std::string, std::string > m_separatorIndex
Map the separator options to their string equivalents.
Definition: SaveAscii.h:46
SaveAscii()
Default constructor.
Definition: SaveAscii.cpp:31
void exec() override
Overwrites Algorithm method.
Definition: SaveAscii.cpp:80
Support for a property that holds an array of values.
Definition: ArrayProperty.h:28
Records the filename and the description of failure.
Definition: Exception.h:98
void setPropertySettings(const std::string &name, std::unique_ptr< IPropertySettings > settings)
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
The concrete, templated class for properties.
void setAutoTrim(const bool &setting)
Sets if the property is set to automatically trim string unput values of whitespace.
Definition: Property.cpp:371
std::shared_ptr< const MatrixWorkspace > MatrixWorkspace_const_sptr
shared pointer to the matrix workspace base class (const version)
constexpr int EMPTY_INT() noexcept
Returns what we consider an "empty" integer within a property.
Definition: EmptyValues.h:25
@ Input
An input workspace.
Definition: Property.h:53