/
MDWSDescription.cpp
394 lines (336 loc) · 16.1 KB
/
MDWSDescription.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
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
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
#include "MantidMDEvents/MDWSDescription.h"
#include "MantidKernel/TimeSeriesProperty.h"
#include "MantidMDEvents/MDTransfFactory.h"
#include "MantidAPI/NumericAxis.h"
#include "MantidKernel/Strings.h"
#include <boost/lexical_cast.hpp>
namespace Mantid
{
namespace MDEvents
{
/** set specific (non-default) dimension name
* @param nDim -- number of dimension;
* @param Name -- the name to assign into dimension names vector;
*/
void MDWSDescription::setDimName(unsigned int nDim,const std::string &Name)
{
if(nDim>=m_NDims)
{
std::string ERR = "setDimName::Dimension index: "+boost::lexical_cast<std::string>(nDim)+" out of total dimensions range: "+boost::lexical_cast<std::string>(m_NDims);
throw(std::invalid_argument(ERR));
}
m_DimNames[nDim] = Name;
}
/** this is rather misleading function, as MD workspace does not currently have dimension units.
*It actually sets the units for the dimension names, which will be displayed along axis and have nothing in common with units, defined by unit factory */
void MDWSDescription::setDimUnit(unsigned int nDim,const std::string &Unit)
{
if(nDim>=m_NDims)
{
std::string ERR = "setDimUnit::Dimension index: "+boost::lexical_cast<std::string>(nDim)+" out of total dimensions range: "+boost::lexical_cast<std::string>(m_NDims);
throw(std::invalid_argument(ERR));
}
m_DimUnits[nDim] = Unit;
}
/** the method builds the MD ws description from existing matrix workspace and the requested transformation parameters.
*@param pWS -- input matrix workspace to be converted into MD workspace
*@param QMode -- momentum conversion mode. Any mode supported by Q conversion factory. Class just carries up the name of Q-mode,
* to the place where factory call to the solver is made , so no code modification is needed when new modes are added
* to the factory
*@param dEMode -- energy analysis mode (string representation). Should correspond to energy analysis modes, supported by selected Q-mode
*@param dimPropertyNames -- the vector of names for additional ws properties, which will be used as dimensions.
*/
void MDWSDescription::buildFromMatrixWS(const API::MatrixWorkspace_sptr &pWS,const std::string &QMode,const std::string dEMode,
const std::vector<std::string> &dimPropertyNames)
{
m_InWS = pWS;
// fill additional dimensions values, defined by workspace properties;
this->fillAddProperties(m_InWS,dimPropertyNames,m_AddCoord);
this->AlgID = QMode;
// check and get energy conversion mode;
m_Emode = Kernel::DeltaEMode().fromString(dEMode);
// get raw pointer to Q-transformation (do not delete this pointer, its held by MDTransfFactory!)
MDTransfInterface* pQtransf = MDTransfFactory::Instance().create(QMode).get();
// get number of dimensions this Q transformation generates from the workspace.
unsigned int nMatrixDim = pQtransf->getNMatrixDimensions(m_Emode,m_InWS);
// number of MD ws dimensions is the sum of n-matrix dimensions and dimensions coming from additional coordinates
m_NDims = nMatrixDim + (unsigned int)m_AddCoord.size();
this->resizeDimDescriptions(m_NDims);
// check if all MD dimensions descriptors are set properly
if(m_NDims!=m_DimNames.size()||m_NDims!=m_DimMin.size())
{
if (m_buildingNewWorkspace)
{
throw(std::invalid_argument(" dimension limits vectors and dimension description vectors inconsistent as have different length"));
}
else
{
throw(std::invalid_argument(" dimension limits vectors and dimension description vectors inconsistent as have different length\n"
" Are you trying to add to existing workspace with convertToMD, which generates workspace with different number of dimensions?"));
}
}
//*********** fill in dimension id-s, dimension units and dimension names
// get default dim ID-s. TODO: it should be possibility to override it later;
std::vector<std::string> MatrDimID = pQtransf->getDefaultDimID(m_Emode,m_InWS);
std::vector<std::string> MatrUnitID = pQtransf->outputUnitID(m_Emode,m_InWS);
for(unsigned int i=0;i<m_NDims;i++)
{
if(i<nMatrixDim)
{
m_DimIDs[i] = MatrDimID[i];
m_DimNames[i]= MatrDimID[i];
m_DimUnits[i]= MatrUnitID[i];
}
else
{
m_DimIDs[i] = dimPropertyNames[i-nMatrixDim];
m_DimNames[i]= dimPropertyNames[i-nMatrixDim];
m_DimUnits[i]= dimPropertyNames[i-nMatrixDim];
}
}
}
void MDWSDescription::setWS(API::MatrixWorkspace_sptr otherMatrixWS)
{
m_InWS = otherMatrixWS;
}
/// Method checks if input workspace has defined goniometer
bool MDWSDescription::hasGoniometer()const
{
if(m_InWS)
return m_InWS->run().getGoniometer().isDefined();
else
return false;
}
/// method returns goniometer matrix if one is defined on the workspace or unit matrix if there are no such matrix
Kernel::Matrix<double> MDWSDescription::getGoniometerMatr()const
{
if(m_InWS)
return m_InWS->run().getGoniometer().getR();
else
return Kernel::Matrix<double>(3,3,true);
};
/** the function builds MD event WS description from existing workspace.
* Primary used to obtain existing ws parameters
*@param pWS -- shared pointer to existing MD workspace
*/
void MDWSDescription::buildFromMDWS(const API::IMDEventWorkspace_const_sptr &pWS)
{
m_NDims = (unsigned int)pWS->getNumDims();
// prepare all arrays:
m_DimNames.resize(m_NDims);
m_DimIDs.resize(m_NDims);
m_DimUnits.resize(m_NDims);
m_NBins.resize(m_NDims);
m_DimMin.resize(m_NDims);
m_DimMax.resize(m_NDims);
for(size_t i=0;i<m_NDims;i++)
{
const Geometry::IMDDimension *pDim = pWS->getDimension(i).get();
m_DimNames[i]= pDim->getName();
m_DimIDs[i] = pDim->getDimensionId();
m_DimUnits[i]= pDim->getUnits();
m_NBins[i] = pDim->getNBins();
m_DimMin[i] = pDim->getMinimum();
m_DimMax[i] = pDim->getMaximum();
}
m_Wtransf = Kernel::DblMatrix(pWS->getWTransf());
// deal with the case when source MD workspace does not have any experiment infos
if(pWS->getNumExperimentInfo()!=0)
{
this->addProperty("W_MATRIX",pWS->getExperimentInfo(0)->run().getPropertyValueAsType<std::vector<double> >("W_MATRIX"),true);
}
}
/** When the workspace has been build from existing MDWrokspace, some target workspace parameters can not be defined,
* as these parameters are defined by the algorithm and input matrix workspace.
* examples are emode or input energy, which is actually source workspace parameters, or some other parameters
* defined by the transformation algorithm
*
* This method used to define such parameters from MDWS description, build from workspace and the transformation algorithm parameters
*
*@param SourceMatrWS -- the MDWS description obtained from input matrix workspace and the algorithm parameters
*/
void MDWSDescription::setUpMissingParameters(const MDEvents::MDWSDescription &SourceMatrWS)
{
m_InWS = SourceMatrWS.m_InWS;
m_Emode = SourceMatrWS.m_Emode;
m_LorentzCorr = SourceMatrWS.m_LorentzCorr;
this->AlgID = SourceMatrWS.AlgID;
m_AddCoord.assign(SourceMatrWS.m_AddCoord.begin(),SourceMatrWS.m_AddCoord.end());
}
/**function compares old workspace description with the new workspace description, defined by the algorithm properties and
* selects/changes the properties which can be changed through input parameters given that target MD workspace exist
*
* This situation occurs if the base description has been obtained from MD workspace, and one is building a description from
* other matrix workspace to add new data to the existing workspace. The workspaces have to be comparable.
*
* @param NewMDWorkspaceD -- MD workspace description, obtained from algorithm parameters
*
* @returns NewMDWorkspaceD -- modified md workspace description, which is compatible with existing MD workspace
*
*/
void MDWSDescription::checkWSCorresponsMDWorkspace(MDEvents::MDWSDescription &NewMDWorkspaceD)
{
if(m_NDims != NewMDWorkspaceD.m_NDims)
{
std::string ERR = "Dimension numbers are inconsistent: this workspace has "+boost::lexical_cast<std::string>(m_NDims)+" dimensions and target one: "+
boost::lexical_cast<std::string>(NewMDWorkspaceD.m_NDims);
throw(std::invalid_argument(ERR));
}
if(m_Emode==Kernel::DeltaEMode::Undefined)
throw(std::invalid_argument("Workspace description has not been correctly defined, as emode has not been defined"));
//TODO: !!! Dim Unit currently have decorative name and is not used in real conversion. It is just a name. This is why this check does not work
// properly
/* for(size_t i=0;i<m_NDims;i++)
{
if(m_DimUnits[i] != NewMDWorkspaceD.m_DimUnits[i])
{
throw std::runtime_error("The target MDEventWorkspace dimension N: "+boost::lexical_cast<std::string>(i)+" has units: "+m_DimUnits[i]+
" different from the requested: "+NewMDWorkspaceD.m_DimUnits[i]+
"\n Either give a different workspace as the output, or change the OutputDimensions parameter.");
}
}*/
//TODO: More thorough checks may be necessary to prevent adding different kind of workspaces e.g 4D |Q|-dE-T-P workspace to Q3d+dE ws
}
/// empty constructor
MDWSDescription::MDWSDescription(unsigned int nDimensions):
m_Wtransf(3,3,true),
m_RotMatrix(9,0),
m_buildingNewWorkspace(true),
m_Emode(Kernel::DeltaEMode::Undefined),
m_LorentzCorr(false),
m_coordinateSystem(Mantid::API::None)
{
this->resizeDimDescriptions(nDimensions);
m_DimMin.assign(m_NDims,std::numeric_limits<double>::quiet_NaN());
m_DimMax.assign(m_NDims,std::numeric_limits<double>::quiet_NaN());
// set transformation matrix to identity - aka do nothing
m_RotMatrix[0] = 1.;
m_RotMatrix[4] = 1.;
m_RotMatrix[8] = 1.;
}
void MDWSDescription::resizeDimDescriptions(unsigned int nDimensions, size_t nBins)
{
m_NDims = nDimensions;
m_DimNames.assign(m_NDims,"mdn");
m_DimIDs.assign(m_NDims,"mdn_");
m_DimUnits.assign(m_NDims,"Momentum");
m_NBins.assign(m_NDims,nBins);
for(size_t i=0;i<m_NDims;i++)
{
m_DimIDs[i] = m_DimIDs[i]+boost::lexical_cast<std::string>(i);
m_DimNames[i]= m_DimNames[i]+boost::lexical_cast<std::string>(i);
}
}
/**function sets up min-max values to the dimensions, described by the class
*@param minVal -- vector of minimal dimension's values
*@param maxVal -- vector of maximal dimension's values
*
*/
void MDWSDescription::setMinMax(const std::vector<double> &minVal,const std::vector<double> &maxVal)
{
m_DimMin.assign(minVal.begin(),minVal.end());
m_DimMax.assign(maxVal.begin(),maxVal.end());
this->checkMinMaxNdimConsistent(m_DimMin,m_DimMax);
}
/**get vector of minimal and maximal values from the class */
void MDWSDescription::getMinMax(std::vector<double> &min,std::vector<double> &max)const
{
min.assign(m_DimMin.begin(),m_DimMin.end());
max.assign(m_DimMax.begin(),m_DimMax.end());
}
//******************************************************************************************************************************************
//************* HELPER FUNCTIONS
//******************************************************************************************************************************************
/** Method checks if the workspace is expected to be processed in powder mode */
bool MDWSDescription::isPowder()const
{
if ((this->AlgID == "|Q|") || (this->AlgID.size()==0 && !m_InWS->sample().hasOrientedLattice()))
return true;
return false;
}
/** Returns symbolic representation of current Emode */
std::string MDWSDescription::getEModeStr()const
{
return Kernel::DeltaEMode().asString(m_Emode);
}
/** function extracts the coordinates from additional workspace properties and places them to proper position within
* the vector of MD coordinates for the particular workspace.
*
* @param inWS2D -- input workspace
* @param dimPropertyNames -- names of properties which should be treated as dimensions
* @param AddCoord --
*
* @return AddCoord -- vector of additional coordinates (derived from WS properties) for current multidimensional event
*/
void MDWSDescription::fillAddProperties(Mantid::API::MatrixWorkspace_const_sptr inWS2D,const std::vector<std::string> &dimPropertyNames,std::vector<coord_t> &AddCoord)
{
size_t nDimPropNames = dimPropertyNames.size();
if(AddCoord.size()!=nDimPropNames)AddCoord.resize(nDimPropNames);
for(size_t i=0;i<nDimPropNames;i++)
{
//HACK: A METHOD, Which converts TSP into value, correspondent to time scale of matrix workspace has to be developed and deployed!
Kernel::Property *pProperty = (inWS2D->run().getProperty(dimPropertyNames[i]));
Kernel::TimeSeriesProperty<double> *run_property = dynamic_cast<Kernel::TimeSeriesProperty<double> *>(pProperty);
if(run_property)
{
AddCoord[i]=coord_t(run_property->firstValue());
}
else
{
// e.g Ei can be a property and dimension
Kernel::PropertyWithValue<double> *proc_property = dynamic_cast<Kernel::PropertyWithValue<double> *>(pProperty);
if(!proc_property)
{
std::string ERR = " Can not interpret property, used as dimension.\n Property: "+dimPropertyNames[i]+
" is neither a time series (run) property nor a property with value<double>";
throw(std::invalid_argument(ERR));
}
AddCoord[i] = coord_t(*(proc_property));
}
}
}
/** function verifies the consistency of the min and max dimensions values checking if all necessary
* values were defined and min values are smaller then max values */
void MDWSDescription::checkMinMaxNdimConsistent(const std::vector<double> &minVal,const std::vector<double> &maxVal)
{
if(minVal.size()!=maxVal.size())
{
std::string ERR = " number of specified min dimension values: "+boost::lexical_cast<std::string>(minVal.size())+
" and number of max values: "+boost::lexical_cast<std::string>(maxVal.size())+
" are not consistent\n";
throw(std::invalid_argument(ERR));
}
for(size_t i=0; i<minVal.size();i++)
{
if(maxVal[i]<=minVal[i])
{
std::string ERR = " min value "+boost::lexical_cast<std::string>(minVal[i])+
" not less then max value"+boost::lexical_cast<std::string>(maxVal[i])+" in direction: "+
boost::lexical_cast<std::string>(i)+"\n";
throw(std::invalid_argument(ERR));
}
}
}
/** function retrieves copy of the oriented lattice from the workspace */
boost::shared_ptr<Geometry::OrientedLattice> MDWSDescription::getOrientedLattice(Mantid::API::MatrixWorkspace_const_sptr inWS2D)
{
// try to get the WS oriented lattice
boost::shared_ptr<Geometry::OrientedLattice> orl;
if(inWS2D->sample().hasOrientedLattice())
orl = boost::shared_ptr<Geometry::OrientedLattice>(new Geometry::OrientedLattice(inWS2D->sample().getOrientedLattice()));
return orl;
}
/** Set the special coordinate system if any.
@param system : coordinate system.
*/
void MDWSDescription::setCoordinateSystem(const Mantid::API::SpecialCoordinateSystem system)
{
m_coordinateSystem = system;
}
/// @return the special coordinate system if any.
Mantid::API::SpecialCoordinateSystem MDWSDescription::getCoordinateSystem() const
{
return m_coordinateSystem;
}
} //end namespace MDEvents
} //end namespace Mantid