Newer
Older
#include "MantidAPI/MDGeometry.h"
#include "MantidKernel/System.h"
#include "MantidAPI/CoordTransform.h"
#include "MantidGeometry/MDGeometry/MDGeometryXMLBuilder.h"
#include "MantidGeometry/MDGeometry/IMDDimension.h"
#include "MantidGeometry/MDGeometry/MDHistoDimension.h"
using namespace Mantid::Kernel;
using namespace Mantid::API;
using namespace Mantid::Geometry;
namespace Mantid {
namespace API {
//----------------------------------------------------------------------------------------------
/** Constructor
*/
MDGeometry::MDGeometry()
: m_dimensions(), m_originalWorkspaces(), m_origin(),
m_transforms_FromOriginal(), m_transforms_ToOriginal(),
m_delete_observer(*this, &MDGeometry::deleteNotificationReceived),
m_observingDelete(false), m_Wtransf(3, 3, true), m_basisVectors() {}
//----------------------------------------------------------------------------------------------
/** Copy Constructor
*/
MDGeometry::MDGeometry(const MDGeometry &other)
: m_dimensions(), m_originalWorkspaces(), m_origin(other.m_origin),
m_transforms_FromOriginal(), m_transforms_ToOriginal(),
m_delete_observer(*this, &MDGeometry::deleteNotificationReceived),
m_observingDelete(false), m_Wtransf(other.m_Wtransf),
m_basisVectors(other.m_basisVectors) {
// Perform a deep copy of the dimensions
std::vector<Mantid::Geometry::IMDDimension_sptr> dimensions;
for (size_t d = 0; d < other.getNumDims(); d++) {
// Copy the dimension
MDHistoDimension_sptr dim(
new MDHistoDimension(other.getDimension(d).get()));
dimensions.push_back(dim);
}
this->initGeometry(dimensions);
// Perform a deep copy of the coordinate transformations
std::vector<CoordTransform_const_sptr>::const_iterator it;
for (it = other.m_transforms_FromOriginal.begin();
it != other.m_transforms_FromOriginal.end(); ++it) {
if (*it)
m_transforms_FromOriginal.push_back(
CoordTransform_const_sptr((*it)->clone()));
m_transforms_FromOriginal.push_back(CoordTransform_const_sptr());
}
for (it = other.m_transforms_ToOriginal.begin();
it != other.m_transforms_ToOriginal.end(); ++it) {
if (*it)
m_transforms_ToOriginal.push_back(
CoordTransform_const_sptr((*it)->clone()));
m_transforms_ToOriginal.push_back(CoordTransform_const_sptr());
}
// Copy the references to the original workspaces
// This will also set up the delete observer to listen to those workspaces
// being deleted.
for (size_t i = 0; i < other.m_originalWorkspaces.size(); i++)
this->setOriginalWorkspace(other.m_originalWorkspaces[i], i);
}
/**
* Clear all transforms to and from original workspaces.
*/
void MDGeometry::clearTransforms() {
m_transforms_ToOriginal.clear();
m_transforms_FromOriginal.clear();
}
/**
* Clear the original workspaces
*/
void MDGeometry::clearOriginalWorkspaces() { m_originalWorkspaces.clear(); }
//----------------------------------------------------------------------------------------------
/** Destructor
*/
MDGeometry::~MDGeometry() {
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
if (m_observingDelete) {
// Stop watching once object is deleted
API::AnalysisDataService::Instance().notificationCenter.removeObserver(
m_delete_observer);
}
m_dimensions.clear();
}
//----------------------------------------------------------------------------------------------
/** Initialize the geometry
*
* @param dimensions :: vector of IMDDimension objects, in the order of X, Y, Z,
*t, etc.
*/
void MDGeometry::initGeometry(
std::vector<Mantid::Geometry::IMDDimension_sptr> &dimensions) {
// Copy the dimensions array
m_dimensions = dimensions;
// Make sure the basis vectors are big enough
m_basisVectors.resize(m_dimensions.size(), Mantid::Kernel::VMD());
}
// --------------------------------------------------------------------------------------------
/** @return the number of dimensions in this workspace */
size_t MDGeometry::getNumDims() const { return m_dimensions.size(); }
// --------------------------------------------------------------------------------------------
/** Get a dimension
* @param index :: which dimension
* @return the dimension at that index
*/
boost::shared_ptr<const Mantid::Geometry::IMDDimension>
MDGeometry::getDimension(size_t index) const {
if (index >= m_dimensions.size())
throw std::runtime_error(
"Workspace does not have a dimension at that index.");
return m_dimensions[index];
}
// --------------------------------------------------------------------------------------------
/** Get a dimension
* @param id :: string ID of the dimension
* @return the dimension with the specified id string.
*/
boost::shared_ptr<const Mantid::Geometry::IMDDimension>
MDGeometry::getDimensionWithId(std::string id) const {
for (size_t i = 0; i < m_dimensions.size(); ++i)
if (m_dimensions[i]->getDimensionId() == id)
return m_dimensions[i];
throw std::invalid_argument("Dimension tagged " + id +
" was not found in the Workspace");
}
// --------------------------------------------------------------------------------------------
/** Get non-collapsed dimensions
@return vector of collapsed dimensions in the workspace geometry.
*/
Mantid::Geometry::VecIMDDimension_const_sptr
MDGeometry::getNonIntegratedDimensions() const {
using namespace Mantid::Geometry;
VecIMDDimension_const_sptr vecCollapsedDimensions;
std::vector<Mantid::Geometry::IMDDimension_sptr>::const_iterator it =
this->m_dimensions.begin();
for (; it != this->m_dimensions.end(); ++it) {
IMDDimension_sptr current = (*it);
if (!current->getIsIntegrated()) {
vecCollapsedDimensions.push_back(current);
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
return vecCollapsedDimensions;
}
//-----------------------------------------------------------------------------------------------
/** @return a vector with the size of the smallest bin in each dimension */
std::vector<coord_t> MDGeometry::estimateResolution() const {
std::vector<coord_t> out;
for (size_t d = 0; d < this->getNumDims(); d++)
out.push_back(this->getDimension(d)->getBinWidth());
return out;
}
//-----------------------------------------------------------------------------------------------
/** Get the index of the dimension that matches the name given
*
* @param name :: name of the m_dimensions
* @return the index (size_t)
* @throw runtime_error if it cannot be found.
*/
size_t MDGeometry::getDimensionIndexByName(const std::string &name) const {
for (size_t d = 0; d < m_dimensions.size(); d++)
if (m_dimensions[d]->getName() == name)
return d;
throw std::runtime_error("Dimension named '" + name +
"' was not found in the IMDWorkspace.");
}
//-----------------------------------------------------------------------------------------------
/** Get the index of the dimension that matches the ID given
*
* @param id :: id string of the dimension
* @return the index (size_t)
* @throw runtime_error if it cannot be found.
*/
size_t MDGeometry::getDimensionIndexById(const std::string &id) const {
for (size_t d = 0; d < m_dimensions.size(); d++)
if (m_dimensions[d]->getDimensionId() == id)
return d;
throw std::runtime_error("Dimension with id '" + id +
"' was not found in the IMDWorkspace.");
}
// --------------------------------------------------------------------------------------------
/** Add a dimension
* @param dim :: shared pointer to the dimension object */
void MDGeometry::addDimension(
boost::shared_ptr<Mantid::Geometry::IMDDimension> dim) {
m_dimensions.push_back(dim);
}
// --------------------------------------------------------------------------------------------
/** Add a dimension
* @param dim :: bare pointer to the dimension object */
void MDGeometry::addDimension(Mantid::Geometry::IMDDimension *dim) {
m_dimensions.push_back(
boost::shared_ptr<Mantid::Geometry::IMDDimension>(dim));
}
// --------------------------------------------------------------------------------------------
/// Get the x-dimension mapping.
boost::shared_ptr<const Mantid::Geometry::IMDDimension>
MDGeometry::getXDimension() const {
if (this->getNumDims() < 1)
throw std::runtime_error("Workspace does not have any dimensions!");
return this->getDimension(0);
}
/// Get the y-dimension mapping.
boost::shared_ptr<const Mantid::Geometry::IMDDimension>
MDGeometry::getYDimension() const {
if (this->getNumDims() < 2)
throw std::runtime_error("Workspace does not have a Y dimension.");
return this->getDimension(1);
}
/// Get the z-dimension mapping.
boost::shared_ptr<const Mantid::Geometry::IMDDimension>
MDGeometry::getZDimension() const {
if (this->getNumDims() < 3)
throw std::runtime_error("Workspace does not have a Z dimension.");
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
return this->getDimension(2);
}
/// Get the t-dimension mapping.
boost::shared_ptr<const Mantid::Geometry::IMDDimension>
MDGeometry::getTDimension() const {
if (this->getNumDims() < 4)
throw std::runtime_error("Workspace does not have a T dimension.");
return this->getDimension(3);
}
// --------------------------------------------------------------------------------------------
/** Get the basis vector (in the original workspace) for a dimension of this
* workspace.
* @param index :: which dimension
* @return a vector, in the dimensions of the original workspace
*/
Mantid::Kernel::VMD &MDGeometry::getBasisVector(size_t index) {
if (index >= m_basisVectors.size())
throw std::invalid_argument("getBasisVector(): invalid index");
return m_basisVectors[index];
}
/** Get the basis vector (in the original workspace) for a dimension of this
* workspace.
* @param index :: which dimension
* @return a vector, in the dimensions of the original workspace
*/
const Mantid::Kernel::VMD &MDGeometry::getBasisVector(size_t index) const {
if (index >= m_basisVectors.size())
throw std::invalid_argument("getBasisVector(): invalid index");
return m_basisVectors[index];
}
/** Set the basis vector (in the original workspace) for a dimension of this
* workspace.
* @param index :: which dimension
* @param vec :: a vector, in the dimensions of the original workspace
*/
void MDGeometry::setBasisVector(size_t index, const Mantid::Kernel::VMD &vec) {
if (index >= m_basisVectors.size())
throw std::invalid_argument("getBasisVector(): invalid index");
m_basisVectors[index] = vec;
}
/**
* @return True ONLY if ALL the basis vectors have been normalized.
*/
bool MDGeometry::allBasisNormalized() const {
bool allNormalized = true;
for (auto it = m_basisVectors.begin(); it != m_basisVectors.end(); ++it) {
if (it->length() != 1.0) {
allNormalized = false;
break;
}
}
return allNormalized;
}
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
395
396
397
398
399
400
401
402
403
404
405
406
407
408
//---------------------------------------------------------------------------------------------------
/// @return true if the geometry is defined relative to another workspace.
/// @param index :: index into the vector of original workspaces
bool MDGeometry::hasOriginalWorkspace(size_t index) const {
if (index >= m_originalWorkspaces.size())
return false;
return bool(m_originalWorkspaces[index]);
}
/// @return the number of original workspaces attached to this one
size_t MDGeometry::numOriginalWorkspaces() const {
return m_originalWorkspaces.size();
}
//---------------------------------------------------------------------------------------------------
/** Get the "original" workspace (the workspace that was the source for a binned
*MDWorkspace).
*
* In the case of a chain of workspaces: A->binned to B->binned to C:
* Index 0 = the workspace that was binned, e.g. "A"
* Index 1 = the intermediate workspace, e.g. "B"
*
* @return the original workspace to which the basis vectors relate
* @param index :: index into the vector of original workspaces.
*/
boost::shared_ptr<Workspace>
MDGeometry::getOriginalWorkspace(size_t index) const {
if (index >= m_originalWorkspaces.size())
throw std::runtime_error(
"MDGeometry::getOriginalWorkspace() invalid index.");
return m_originalWorkspaces[index];
}
//---------------------------------------------------------------------------------------------------
/** Set the "original" workspace (the workspace that was the source for a binned
*MDWorkspace).
*
* In the case of a chain of workspaces: A->binned to B->binned to C:
* Index 0 = the workspace that was binned, e.g. "A"
* Index 1 = the intermediate workspace, e.g. "B"
*
* @param ws :: original workspace shared pointer
* @param index :: index into the vector of original workspaces.
*/
void MDGeometry::setOriginalWorkspace(boost::shared_ptr<Workspace> ws,
size_t index) {
if (index >= m_originalWorkspaces.size())
m_originalWorkspaces.resize(index + 1);
m_originalWorkspaces[index] = ws;
// Watch for workspace deletions
if (!m_observingDelete) {
API::AnalysisDataService::Instance().notificationCenter.addObserver(
m_delete_observer);
m_observingDelete = true;
}
}
//---------------------------------------------------------------------------------------------------
/** Transform the dimensions contained in this geometry
* x' = x*scaling + offset
*
* This clears any original workspace or coordinate transformation
* contained.
*
* NOTE! This does not modify any other underlying data. Call the TransformMD
* algorithm to perform a full transform.
*
* @param scaling :: multiply each coordinate by this value.
* @param offset :: after multiplying, add this offset.
*/
void MDGeometry::transformDimensions(std::vector<double> &scaling,
std::vector<double> &offset) {
if (scaling.size() != m_dimensions.size())
throw std::invalid_argument("MDGeometry::transformDimensions(): "
"scaling.size() must be equal to number of "
"dimensions.");
if (offset.size() != m_dimensions.size())
throw std::invalid_argument("MDGeometry::transformDimensions(): "
"offset.size() must be equal to number of "
"dimensions.");
for (size_t d = 0; d < m_dimensions.size(); d++) {
IMDDimension_sptr dim = m_dimensions[d];
coord_t min = (dim->getMinimum() * static_cast<coord_t>(scaling[d])) +
static_cast<coord_t>(offset[d]);
coord_t max = (dim->getMaximum() * static_cast<coord_t>(scaling[d])) +
static_cast<coord_t>(offset[d]);
dim->setRange(dim->getNBins(), min, max);
}
// Clear the original workspace
setOriginalWorkspace(boost::shared_ptr<Workspace>());
setTransformFromOriginal(NULL);
setTransformToOriginal(NULL);
}
//---------------------------------------------------------------------------------------------------
/** Function called when observer objects receives a notification that
* a workspace has been deleted.
*
* This checks if the "original workspace" in this object is being deleted,
* and removes the reference to it to allow it to be destructed properly.
*
* @param notice :: notification of workspace deletion
*/
void MDGeometry::deleteNotificationReceived(
Mantid::API::WorkspacePreDeleteNotification_ptr notice) {
for (size_t i = 0; i < m_originalWorkspaces.size(); i++) {
Workspace_sptr original = m_originalWorkspaces[i];
if (original) {
// Compare the pointer being deleted to the one stored as the original.
Workspace_sptr deleted = notice->object();
if (original == deleted) {
// Clear the reference
m_originalWorkspaces[i].reset();
Janik Zikovsky
committed
}
}
}
//---------------------------------------------------------------------------------------------------
/** Get the Coordinate Transformation that goes from the original workspace
* to this workspace's coordinates.
*
* In the case of a chain of workspaces: A->binned to B->binned to C:
* Index 0 = the workspace that was binned, e.g. "A"
* Index 1 = the intermediate workspace, e.g. "B"
*
* @return CoordTransform pointer
* @param index :: index into the array of original workspaces
*/
Mantid::API::CoordTransform const *
MDGeometry::getTransformFromOriginal(size_t index) const {
if (index >= m_transforms_FromOriginal.size())
throw std::runtime_error(
"MDGeometry::getTransformFromOriginal(): invalid index.");
return m_transforms_FromOriginal[index].get();
}
//---------------------------------------------------------------------------------------------------
/** Sets the Coordinate Transformation that goes from the original workspace
* to this workspace's coordinates.
*
* In the case of a chain of workspaces: A->binned to B->binned to C:
* Index 0 = the workspace that was binned, e.g. "A"
* Index 1 = the intermediate workspace, e.g. "B"
*
* @param transform :: CoordTransform pointer (this assumes pointer ownership)
* @param index :: index into the array of original workspaces
*/
void MDGeometry::setTransformFromOriginal(
Mantid::API::CoordTransform *transform, size_t index) {
if (index >= m_transforms_FromOriginal.size()) {
m_transforms_FromOriginal.resize(index + 1);
}
m_transforms_FromOriginal[index] = CoordTransform_const_sptr(transform);
}
//---------------------------------------------------------------------------------------------------
/** Get the Coordinate Transformation that goes from THIS workspace's
*coordinates
* to the ORIGINAL workspace's coordinates
*
* In the case of a chain of workspaces: A->binned to B->binned to C:
* Index 0 = the workspace that was binned, e.g. "A"
* Index 1 = the intermediate workspace, e.g. "B"
*
* @return CoordTransform pointer
* @param index :: index into the array of original workspaces
*/
Mantid::API::CoordTransform const *
MDGeometry::getTransformToOriginal(size_t index) const {
if (index >= m_transforms_ToOriginal.size())
throw std::runtime_error(
"MDGeometry::getTransformFromOriginal(): invalid index.");
return m_transforms_ToOriginal[index].get();
}
//---------------------------------------------------------------------------------------------------
/** Sets the Coordinate Transformation that goes from THIS workspace's
*coordinates
* to the ORIGINAL workspace's coordinates
*
* In the case of a chain of workspaces: A->binned to B->binned to C:
* Index 0 = the workspace that was binned, e.g. "A"
* Index 1 = the intermediate workspace, e.g. "B"
*
* @param transform :: CoordTransform pointer (this assumes pointer ownership)
* @param index :: index into the array of original workspaces
*/
void MDGeometry::setTransformToOriginal(Mantid::API::CoordTransform *transform,
size_t index) {
if (index >= m_transforms_ToOriginal.size()) {
m_transforms_ToOriginal.resize(index + 1);
}
m_transforms_ToOriginal[index] = CoordTransform_const_sptr(transform);
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
}
//---------------------------------------------------------------------------------------------------
/** @return a XML representation of the geometry of the workspace */
std::string MDGeometry::getGeometryXML() const {
using Mantid::Geometry::MDGeometryBuilderXML;
using Mantid::Geometry::NoDimensionPolicy;
MDGeometryBuilderXML<NoDimensionPolicy> xmlBuilder;
// Add all dimensions.
const size_t nDimensions = this->getNumDims();
for (size_t i = 0; i < nDimensions; i++) {
xmlBuilder.addOrdinaryDimension(this->getDimension(i));
}
// Add mapping dimensions
if (nDimensions > 0) {
xmlBuilder.addXDimension(this->getXDimension());
}
if (nDimensions > 1) {
xmlBuilder.addYDimension(this->getYDimension());
}
if (nDimensions > 2) {
xmlBuilder.addZDimension(this->getZDimension());
}
if (nDimensions > 3) {
xmlBuilder.addTDimension(this->getTDimension());
}
// Create the xml.
return xmlBuilder.create();
}
/**
* Get the number of transforms defined to the original coordinate system.
* @return The number of transforms.
*/
size_t MDGeometry::getNumberTransformsToOriginal() const {
return m_transforms_ToOriginal.size();
}
/**
* Get the number of transforms defined from the original coordinate system.
* @return The number of transforms.
*/
size_t MDGeometry::getNumberTransformsFromOriginal() const {
return m_transforms_FromOriginal.size();
}
} // namespace Mantid
} // namespace API