SaveDiffFittingAscii.cpp 9.3 KB
Newer Older
1
2
3
#include "MantidDataHandling/SaveDiffFittingAscii.h"

#include "MantidAPI/FileProperty.h"
4
#include "MantidAPI/TableRow.h"
5
#include "MantidAPI/WorkspaceGroup.h"
6
#include "MantidDataObjects/TableWorkspace.h"
7
#include "MantidKernel/ListValidator.h"
8
9
10
11
#include "MantidKernel/MandatoryValidator.h"
#include "Poco/File.h"
#include <boost/tokenizer.hpp>
#include <fstream>
12
13
14
15
16
17
18
19
20
21
22

namespace Mantid {
namespace DataHandling {

using namespace Kernel;
using namespace Mantid::API;

// Register the algorithm into the algorithm factory
DECLARE_ALGORITHM(SaveDiffFittingAscii)

/// Empty constructor
23
SaveDiffFittingAscii::SaveDiffFittingAscii()
Shahroz Ahmed's avatar
Shahroz Ahmed committed
24
    : Mantid::API::Algorithm(), m_sep(','), m_counter(0) {}
25
26
27
28

/// Initialisation method.
void SaveDiffFittingAscii::init() {

29
30
31
  declareProperty(make_unique<WorkspaceProperty<ITableWorkspace>>(
                      "InputWorkspace", "", Direction::Input),
                  "The name of the workspace containing the data you want to "
32
                  "save to a TBL file");
33
34
35
36
37
38
39
40

  // Declare required parameters, filename with ext {.his} and input
  // workspace
  const std::vector<std::string> exts{".txt", ".csv", ""};
  declareProperty(Kernel::make_unique<API::FileProperty>(
                      "Filename", "", API::FileProperty::Save, exts),
                  "The filename to use for the saved data");

41
42
43
44
  declareProperty(
      "RunNumber", "", boost::make_shared<MandatoryValidator<std::string>>(),
      "Run number list of the focused files, which is used to generate the "
      "parameters table workspace");
45

46
47
48
49
  declareProperty(
      "Bank", "", boost::make_shared<MandatoryValidator<std::string>>(),
      "Bank number list of the focused files, which is used to generate "
      "the parameters table workspace");
50

51
52
53
  std::vector<std::string> formats;

  formats.push_back("AppendToExistingFile");
54
  formats.push_back("OverwriteFile");
55
56
57
  declareProperty("OutMode", "AppendToExistingFile",
                  boost::make_shared<Kernel::StringListValidator>(formats),
                  "Over write the file or append data to existing file");
58
59
60
}

/**
61
62
 *   Executes the algorithm.
 */
63
void SaveDiffFittingAscii::exec() {
64
65
66

  // Retrieve the input workspace
  /// Workspace
67
  const ITableWorkspace_sptr tbl_ws = getProperty("InputWorkspace");
68
  if (!tbl_ws)
69
70
    throw std::runtime_error(
        "Please provide an input table workspace to be saved.");
71

Shahroz Ahmed's avatar
Shahroz Ahmed committed
72
73
  std::vector<API::ITableWorkspace_sptr> input_ws;
  input_ws.push_back(
74
75
      boost::dynamic_pointer_cast<DataObjects::TableWorkspace>(tbl_ws));

Shahroz Ahmed's avatar
Shahroz Ahmed committed
76
  processAll(input_ws);
77
}
78
79

bool SaveDiffFittingAscii::processGroups() {
80

81
82
83
84
85
86
87
  try {

    std::string name = getPropertyValue("InputWorkspace");

    WorkspaceGroup_sptr inputGroup =
        AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>(name);

Shahroz Ahmed's avatar
Shahroz Ahmed committed
88
    std::vector<API::ITableWorkspace_sptr> input_ws;
89
    input_ws.reserve(inputGroup->getNumberOfEntries());
90
    for (int i = 0; i < inputGroup->getNumberOfEntries(); ++i) {
Shahroz Ahmed's avatar
Shahroz Ahmed committed
91
      input_ws.push_back(
92
93
94
          boost::dynamic_pointer_cast<ITableWorkspace>(inputGroup->getItem(i)));
    }

95
    processAll(input_ws);
96
97
98
99
  } catch (std::runtime_error &rexc) {
    g_log.error(
        std::string("Error while processing a group of workspaces. Details: ") +
        rexc.what() + '\n');
100
101
102
103
  }

  return true;
}
104

Shahroz Ahmed's avatar
Shahroz Ahmed committed
105
void SaveDiffFittingAscii::processAll(
106
    const std::vector<API::ITableWorkspace_sptr> input_ws) {
107

108
  const std::string filename = getProperty("Filename");
109
  const std::string outMode = getProperty("OutMode");
110
111
  std::string runNumList = getProperty("RunNumber");
  std::string bankList = getProperty("Bank");
112
113
114
115
116

  Poco::File pFile = (filename);
  bool exist = pFile.exists();

  bool appendToFile = false;
117
  if (outMode == "AppendToExistingFile")
118
    appendToFile = true;
119

120
  // Initialize the file stream
121
122
  std::ofstream file(filename.c_str(),
                     (appendToFile ? std::ios::app : std::ios::out));
123
124
125
126
127

  if (!file) {
    throw Exception::FileError("Unable to create file: ", filename);
  }

128
129
130
131
132
  if (exist && !appendToFile) {
    g_log.warning() << "File " << filename << " exists and will be overwritten."
                    << "\n";
  }

133
134
135
  if (exist && appendToFile) {
    file << "\n";
  }
136

137
138
  // reset counter
  m_counter = 0;
139

140
141
  std::vector<std::string> splitRunNum = splitList(runNumList);
  std::vector<std::string> splitBank = splitList(bankList);
142

143
  // Create a progress reporting object
144
  Progress progress(this, 0.0, 1.0, input_ws.size());
145

Shahroz Ahmed's avatar
Shahroz Ahmed committed
146
  size_t breaker = input_ws.size();
147
  if (outMode == "AppendToExistingFile" && input_ws.size() == 1)
148
149
150
151
152
153
154
155
156
    breaker = 1;

  for (size_t i = 0; i < breaker; ++i) {

    std::string runNum = splitRunNum[m_counter];
    std::string bank = splitBank[m_counter];
    writeInfo(runNum, bank, file);

    // write header
Shahroz Ahmed's avatar
Shahroz Ahmed committed
157
    std::vector<std::string> columnHeadings = input_ws[i]->getColumnNames();
158
159
160
161
    writeHeader(columnHeadings, file);

    // write out the data form the table workspace
    size_t columnSize = columnHeadings.size();
Shahroz Ahmed's avatar
Shahroz Ahmed committed
162
    writeData(input_ws[i], file, columnSize);
163

164
    if (input_ws.size() > 1 && (i + 1) != input_ws.size()) {
Shahroz Ahmed's avatar
Shahroz Ahmed committed
165
      file << '\n';
166
167
    }
  }
168
  progress.report();
169
170
}

171
172
173
174
175
176
177
178
179
std::vector<std::string> SaveDiffFittingAscii::splitList(std::string strList) {
  std::vector<std::string> splitList;
  strList.erase(std::remove(strList.begin(), strList.end(), ' '),
                strList.end());
  boost::split(splitList, strList, boost::is_any_of(","));

  return splitList;
}

180
181
182
183
void SaveDiffFittingAscii::writeInfo(const std::string &runNumber,
                                     const std::string &bank,
                                     std::ofstream &file) {

Shahroz Ahmed's avatar
Shahroz Ahmed committed
184
185
  file << "run number: " << runNumber << '\n';
  file << "bank: " << bank << '\n';
186
  m_counter++;
187
188
}

189
190
void SaveDiffFittingAscii::writeHeader(
    const std::vector<std::string> &columnHeadings, std::ofstream &file) {
Shahroz Ahmed's avatar
Shahroz Ahmed committed
191
192
  for (const auto &heading : columnHeadings) {
    // Chi being the last header in the table workspace
193
194
195
196
197
198
199
200
    if (heading == "Chi") {
      writeVal(heading, file, true);
    } else {
      writeVal(heading, file, false);
    }
  }
}

201
202
203
void SaveDiffFittingAscii::writeData(const API::ITableWorkspace_sptr workspace,
                                     std::ofstream &file,
                                     const size_t columnSize) {
204
205
206
207
208

  for (size_t rowIndex = 0; rowIndex < workspace->rowCount(); ++rowIndex) {
    TableRow row = workspace->getRow(rowIndex);
    for (size_t columnIndex = 0; columnIndex < columnSize; columnIndex++) {

Shahroz Ahmed's avatar
Shahroz Ahmed committed
209
210
      const auto row_str =
          boost::lexical_cast<std::string>(row.Double(columnIndex));
211
212
213
214
215
216
217
218
219
220
      g_log.debug() << row_str << std::endl;

      if (columnIndex == columnSize - 1)
        writeVal(row_str, file, true);
      else
        writeVal(row_str, file, false);
    }
  }
}

221
void SaveDiffFittingAscii::writeVal(const std::string &val, std::ofstream &file,
222
                                    const bool endline) {
223
224
225
226
227
228
229
230
  std::string valStr = boost::lexical_cast<std::string>(val);

  // checking if it needs to be surrounded in
  // quotes due to a comma being included
  size_t comPos = valStr.find(',');
  if (comPos != std::string::npos) {
    file << '"' << val << '"';
  } else {
Shahroz Ahmed's avatar
Shahroz Ahmed committed
231
    file << boost::lexical_cast<std::string>(val);
232
233
234
  }

  if (endline) {
Shahroz Ahmed's avatar
Shahroz Ahmed committed
235
    file << '\n';
236
237
238
  } else {
    file << m_sep;
  }
239
240
}

241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
std::map<std::string, std::string> SaveDiffFittingAscii::validateInputs() {
  std::map<std::string, std::string> errors;

  bool is_grp = true;

  // check for null pointers - this is to protect against workspace groups
  const std::string inputWS = getProperty("InputWorkspace");

  WorkspaceGroup_sptr inWks =
      AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>(inputWS);
  API::WorkspaceGroup_const_sptr inGrp =
      boost::dynamic_pointer_cast<const API::WorkspaceGroup>(inWks);

  const ITableWorkspace_sptr tbl_ws = getProperty("InputWorkspace");
  if (tbl_ws) {
    is_grp = false;
  }

  if (!inGrp && !tbl_ws) {
    std::string message =
        "The current version of this algorithm only "
        "supports input workspaces of type TableWorkspace and WorkspaceGroup";
    errors["InputWorkspace"] = message;
  }

  const std::string file = getProperty("Filename");
  if (file.empty()) {
    errors["Filename"] = "File name directory cannot be empty";
  }

  std::string runNumber = getPropertyValue("RunNumber");
  std::vector<std::string> splitRunNum = splitList(runNumber);

  std::string bankNumber = getPropertyValue("Bank");
  std::vector<std::string> splitBank = splitList(bankNumber);

  if (runNumber.empty()) {
    errors["Bank"] = "Please provide a valid bank list";
  }
  if (splitBank.empty()) {
    errors["Bank"] = "Please provide a valid bank list";
  } else if (!is_grp) {
    if (splitRunNum.size() > 1) {
      errors["RunNumber"] = "One run number should be provided when a Table"
                            "workspace is selected";
    }
    if (splitBank.size() > 1) {
      errors["Bank"] = "One bank should be provided when a Table"
                       "Workspace is selected";
    }
  } else {
    if (splitRunNum.size() != inGrp->size()) {
      errors["RunNumber"] = "Run number list size should match the number of "
                            "TableWorkspaces in the GroupWorkspace selected";
    }
    if (splitBank.size() != inGrp->size()) {
      errors["Bank"] = "Bank list size should match the number of "
                       "TableWorkspaces in the GroupWorkspace selected";
    }
  }

  return errors;
}

305
306
} // namespace DataHandling
} // namespace Mantid