@@ -4,20 +4,20 @@

namespace Mantid
{
namespace MDAlgorithms
namespace MDEvents
{
/** Interface to set of sub-classes used by ConvertToMDEvents algorithm and responsible for conversion of input workspace
* data into MD events.
*
* it fills in vector of n-dimensions which contains the values
* its output is the vector of n-dimensions which contains the values of n-coorinates in n-dimensional space
*
*
* Usual transformation constis of 4 steps
* 1) Initiate the transformation itself.
* 2) set-up, calculation and copying generic multidimensional variables which are not depenent on data
* 2) set-up, calculation and copying generic multidimensional variables which are not depenent on data (logs)
* 3) set-up, calculation and copying the multidimensional variables which dependent on detectors id only
* 4) calculation of the multidimensional variables which depend on the data along x-axis of the workspace
* and possibly on detectors parameters.
* and possibly on detectors parameters (values along y-axis)
*
*
* @date 16-05-2012
@@ -42,28 +42,50 @@ namespace MDAlgorithms
File change history is stored at: <https://svn.mantidproject.org/mantid/trunk/Code/Mantid>
Code Documentation is available at: <http://doxygen.mantidproject.org>
*/
class IMDTransform
// forvard declaration for a class, which provides all necessary parameters for the workspace
class ConvToMDEventsBase;

namespace ConvertToMD
{
/* enum describes known eneergy conversion/analysis modes
* It is important to assign enums proper numbers, as direct correspondence between enums and their emodes
* used by the external units conversion algorithms within the Mantid, so the agreement should be the stame
*/
enum EModes
{
Elastic = 0, //< int emode = 0; Elastic analysis
Direct = 1, //< emode=1; Direct inelastic analysis mode
Indir = 2, //< emode=2; InDirect inelastic analysis mode
No_DE //< couples with NoNonentum analysis, means just copying existing data (may be doing units conversion)
};
}


class MDTransfInterface
{
public:

/** Method deployed out of the loop and calculates all variables needed within the loop.
* In addition it calculates the property-dependant coordinates, which do not depend on workspace
*
* @param Coord -- subalgorithm specific number of variables, calculated from properties and placed into specific place of the Coord vector;
* @param n_ws_variabes -- specific number of variables, calculated from the workspace data
* @param Coord -- vector of ND-coordinates.
* Method calculates subalgorithm specific number of variables,
* calculated from properties and placed into specific place of the Coord vector;
* @param n_ws_variabes -- specific number of additional variables, calculated from the workspace data
*
* @return true -- if all Coord are within the range requested by algorithm. false otherwise
* @return true -- if all Coord are within the range requested by the conversion algorithm. false otherwise
*/

virtual bool calcGenericVariables(std::vector<coord_t> &Coord, size_t n_ws_variabes)=0;

/** generalizes the code to calculate Y-variables within the detector's loop of processQND workspace
/** generalizes the code to calculate Y-variables within the detector's loop of the workspace
* @param Coord -- current Y coordinate, placed in the position of the Coordinate vector, specific for particular subalgorithm.
* @param i -- index of external loop, identifying current y-coordinate
*
* @return true -- if all Coord are within the range requested by algorithm. false otherwise
*
*/
bool calcYDepCoordinates(std::vector<coord_t> &Coord,size_t i)=0;
virtual bool calcYDepCoordinates(std::vector<coord_t> &Coord,size_t i)=0;
/** Calculate all remaining coordinates, defined within the inner loop
* @param X -- vector of X workspace values
* @param i -- index of external loop, identifying generic y-coordinate
@@ -72,22 +94,30 @@ class IMDTransform
* @param Coord -- subalgorithm specific number of coordinates, placed in the proper position of the Coordinate vector
* @return true -- if all Coord are within the range requested by algorithm. false otherwise
*
* in most existing algorighms X does not depend on Y coordinate, so we can place generalization here;
* It should be overridden if the dependence on Y coordinate do exist.
*/
bool calcMatrixCoord(const MantidVec& X,size_t i,size_t j,std::vector<coord_t> &Coord)const=0;
virtual bool calcMatrixCoord(const MantidVec& X,size_t i,size_t j,std::vector<coord_t> &Coord)const
{
UNUSED_ARG(i);
double X_ev =double(0.5*(X[j]+X[j+1])); // ! POSSIBLE FACTORY HERE !!! if this histohram interpolation is different
return calcMatrixCoord(X_ev,Coord);
}

/** template generalizes the code to calculate all remaining coordinates, defined within the inner loop
/** The method to calculate all remaining coordinates, defined within the inner loop
* given that the input described by sinble value only
* @param X -- X workspace value
*
* @param Coord -- subalgorithm specific number of coordinates, placed in the proper position of the Coordinate vector
* @return true -- if all Coord are within the range requested by algorithm. false otherwise
* */
bool calcMatrixCoord(const double & X,std::vector<coord_t> &Coord)const=0;
virtual bool calcMatrixCoord(const double & X,std::vector<coord_t> &Coord)const=0;

/** set up transformation and retrieve the pointer to the incorporating class, which runs the transformation and can provide
* all necessary variables necessary for the conversion */
void initialize(IConvertToMDEventsWS *)=0;
virtual void initialize(const ConvToMDEventsBase &)=0;

virtual ~MDTransfInterface(){};
};

} // End MDAlgorighms namespace
@@ -1,11 +1,12 @@
#ifndef H_CONVERT_TO_MDEVENTS_MODQ_TRANSF
#define H_CONVERT_TO_MDEVENTS_MODQ_TRANSF
//
#include "MantidMDEvents/MDTransform.h"
#include "MantidMDEvents/MDTransfInterface.h"
#include "MantidMDEvents/ConvToMDEventsBase.h"
//
namespace Mantid
{
namespace MDAlgorithms
namespace MDEvents
{


@@ -41,82 +42,48 @@ namespace MDAlgorithms



class DLLExport MDTransfModQInelastic: public IMDTransformation

// ModQ,Elastic
class DLLExport MDTransfModQElastic: public MDTransfInterface
{
public:
public:
bool calcGenericVariables(std::vector<coord_t> &Coord, size_t nd);
//
inline bool calcYDepCoordinates(std::vector<coord_t> &Coord,size_t i)
inline bool calc1MatrixCoord(const double& E_tr,std::vector<coord_t> &Coord)const
inline bool calcMatrixCoord(const MantidVec& X,size_t i,size_t j,std::vector<coord_t> &Coord)const
{
UNUSED_ARG(i);
double X_ev = CONV_UNITS_FROM.getXConverted(X,j);
return calc1MatrixCoord(X_ev,Coord);
}

inline bool convertAndCalcMatrixCoord(const double & X,std::vector<coord_t> &Coord)const
{
double X_ev = CONV_UNITS_FROM.getXConverted(X);
return calc1MatrixCoord(X_ev,Coord);
}
bool calcYDepCoordinates(std::vector<coord_t> &Coord,size_t i);
bool calcMatrixCoord(const double& k0,std::vector<coord_t> &Coord)const;
// constructor;
CoordTransformer():pDet(NULL),pHost(NULL){}
void setUpTransf(IConvertToMDEventsWS *pConv){
pHost = pConv;
}
private:
// the energy of the incident neutrons
double Ei;
// the wavevector of incident neutrons
double ki;
MDTransfModQElastic():pDet(NULL),pHost(NULL),nMatrixDim(1){}
void initialize(const ConvToMDEventsBase &Conv);

protected:
// directions to the detectors
double ex,ey,ez;
// the matrix which transforms the neutron momentums from lablratory to crystall coordinate system.
std::vector<double> rotMat;
// min-max values, some modified to work with squared values:
std::vector<double> dim_min,dim_max;
//
Kernel::V3D const *pDet;
// Calling Mantid algorithm
IConvertToMDEventsWS *pHost;
// class which would convert units
UnitsConverter<CONV,TYPE> CONV_UNITS_FROM;
Kernel::V3D const * pDet;
// The pointer to the class, which drives this conversion and provides all necessary values for variables
ConvToMDEventsBase const* pHost;
// number of dimensions, calculated from matrix workspace
int nMatrixDim;


};
// ModQ,Elastic
class DLLExport MDTransfModQElastic: public IMDTransformation
{
inline bool calcGenericVariables(std::vector<coord_t> &Coord, size_t nd);
inline bool calcYDepCoordinates(std::vector<coord_t> &Coord,size_t i)
inline bool calc1MatrixCoord(const double& k0,std::vector<coord_t> &Coord)const

inline bool calcMatrixCoord(const MantidVec& X,size_t i,size_t j,std::vector<coord_t> &Coord)const
inline bool convertAndCalcMatrixCoord(const double & X,std::vector<coord_t> &Coord)const

// constructor;
MDTransfModQElastic():pDet(NULL),pHost(NULL){}
void setUpTransf(IConvertToMDEventsWS *pConv){
pHost = pConv;
}
class DLLExport MDTransfModQInelastic: public MDTransfModQElastic
{
public:
bool calcGenericVariables(std::vector<coord_t> &Coord, size_t nd);
bool calcMatrixCoord(const double& k0,std::vector<coord_t> &Coord)const;
void initialize(const ConvToMDEventsBase &Conv);
private:
// the energy of the incident neutrons
double Ei;
// the wavevector of incident neutrons
double ki;
// directions to the detectors
double ex,ey,ez;
// the matrix which transforms the neutron momentums from lablratory to crystall coordinate system.
std::vector<double> rotMat;
// min-max values, some modified to work with squared values:
std::vector<double> dim_min,dim_max;
//
Kernel::V3D const * pDet;
// Calling Mantid algorithm
IConvertToMDEventsWS *pHost;
// class which would convert units
UnitsConverter<CONV,TYPE> CONV_UNITS_FROM;

// energy conversion mode
ConvertToMD::EModes emode;
};

} // End MDAlgorighms namespace
@@ -0,0 +1,106 @@
#include "MantidMDEvents/ConvToMDEventsBase.h"
#include "MantidAPI/ExperimentInfo.h"
namespace Mantid
{
namespace MDEvents
{

// logger for conversion
Kernel::Logger& ConvToMDEventsBase::convert_log =Kernel::Logger::get("MD-Algorithms");

/** Helper function to obtain the units set along X-axis of the input workspace.
*
*@param pHost the pointer to the algorithm to work with
*
*@returns the name(ID) of the unit, specified along X-axis of current workspace
*/
Kernel::Unit_sptr
ConvToMDEventsBase::getAxisUnits()const{
if(!this->inWS2D.get()){
convert_log.error()<<"getAxisUnits: invoked when input workspace is undefined\n";
throw(std::logic_error(" should not be able to call this function when workpsace is undefined"));
}
API::NumericAxis *pAxis = dynamic_cast<API::NumericAxis *>(this->inWS2D->getAxis(0));
if(!pAxis){
convert_log.error()<<"getAxisUnits: can not obtained when first workspace axis is undefined or not numeric\n";
throw(std::logic_error(" should not be able to call this function when X-axis is wrong"));
}
return this->inWS2D->getAxis(0)->unit();
}
/** function extracts the coordinates from additional workspace porperties and places them to proper position within the vector of MD coodinates for
the particular workspace.
@param Coord -- vector of coordinates for current multidimensional event
@param nd -- number of the event's dimensions
@param n_ws_properties -- number of dimensions, provided by the workspace itself. E.g., processed inelastic matrix
workspace with provides 4 dimensions, matrix workspace in elastic mode -- 3 dimensions, powder
-- 1 for elastic and 2 for inelastic mode. Number of these properties is determined by the deployed algorithm
The coordinates, obtained from the workspace placed first in the array of coordinates, and the coordinates,
obtained from dimensions placed after them.
*@returns -- true if all coordinates are within the range allowed for the algorithm and false otherwise
*/

bool ConvToMDEventsBase::fillAddProperties(std::vector<coord_t> &Coord,size_t nd,size_t n_ws_properties)const
{
for(size_t i=n_ws_properties;i<nd;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(TWS.dimNames[i]));
Kernel::TimeSeriesProperty<double> *run_property = dynamic_cast<Kernel::TimeSeriesProperty<double> *>(pProperty);
if(run_property){
Coord[i]=coord_t(run_property->firstValue());
}else{
// e.g Ei can be a property and dimenson
Kernel::PropertyWithValue<double> *proc_property = dynamic_cast<Kernel::PropertyWithValue<double> *>(pProperty);
if(!proc_property){
convert_log.error()<<" property: "<<this->TWS.dimNames[i]<<" is neither a time series (run) property nor a property with double value\n";
throw(std::invalid_argument(" can not interpret property, used as dimension"));
}
Coord[i] = coord_t(*(proc_property));
}
if(Coord[i]<TWS.dimMin[i] || Coord[i]>=TWS.dimMax[i])return false;
}
return true;
}

/** method which initates all main class variables
* @param pWS2D -- shared pointer to input matirx workspace to process
* @param detLoc -- class with information about datecotrs, partially transformed for convenient Q calculations
* @param WSD -- class describing the target workspace.
* the algorithm uses target workspace limints, transformation matix from source to the target workspace and the parameters, needed for
* unit conversion (if any)
* @param pWSWrapper -- shared pointer to target MD Event workspace to add converted events to.
*/
size_t ConvToMDEventsBase::initialize(Mantid::API::MatrixWorkspace_sptr pWS2D, ConvToMDPreprocDet &detLoc,const MDEvents::MDWSDescription &WSD, boost::shared_ptr<MDEvents::MDEventWSWrapper> inWSWrapper)
{
TWS = WSD;
inWS2D= pWS2D;
pWSWrapper = inWSWrapper;

// Copy ExperimentInfo (instrument, run, sample) to the output WS
API::ExperimentInfo_sptr ei(pWS2D->cloneExperimentInfo());
runIndex = pWSWrapper->pWorkspace()->addExperimentInfo(ei);

// set values may needed for unit conversion
detLoc.setEmode(WSD.emode);
detLoc.setEfix(WSD.Ei);

// remember pointer to the preprocessed detectors information
pDetLoc = &detLoc;

n_dims = this->pWSWrapper->nDimensions();

dim_min.assign(WSD.dimMin.begin(),WSD.dimMin.end());
dim_max.assign(WSD.dimMax.begin(),WSD.dimMax.end());

size_t n_spectra =inWS2D->getNumberHistograms();
return n_spectra;
};

ConvToMDEventsBase::ConvToMDEventsBase()
{}



} // endNamespace MDAlgorithms
}
@@ -0,0 +1,215 @@
#include "MantidMDEvents/ConvToMDPreprocDet.h"
#include "MantidKernel/Exception.h"

using namespace Mantid::Kernel;
using namespace Mantid::DataObjects;
using namespace Mantid::Geometry;

namespace Mantid
{
namespace MDEvents
{
/// function sets appropriate energy conversion mode to work with detectors and unit conversion
void ConvToMDPreprocDet::setEmode(int mode)
{
if(mode<-1||mode>2){
std::string Err="Energy conversion mode has to be between -1 and 2 but trying to set: "+boost::lexical_cast<std::string>(mode);
throw(std::invalid_argument(Err));
}
emode = mode;
}
/// function sets appropriate energy to work with detectors and unit conversion
void ConvToMDPreprocDet::setEfix(double Ei)
{
if(Ei<=0){
std::string Err="Input neutron's energy can not be negative but equal: "+boost::lexical_cast<std::string>(Ei);
throw(std::invalid_argument(Err));
}
efix = Ei;
}
/// function sets source-sample distance to work with detectors and unit conversion
void ConvToMDPreprocDet::setL1(double Dist)
{
if(Dist<0){
std::string Err="Source-sample distance has to be positive but equal: "+boost::lexical_cast<std::string>(Dist);
throw(std::invalid_argument(Err));
}
L1 = Dist;
}
/// function checks if preprocessed detectors are already calculated and the class is actually defined properly
bool ConvToMDPreprocDet::isDefined(const API::MatrixWorkspace_const_sptr &inputWS)const
{
if(det_dir.empty())return false;

if(pBaseInstr !=inputWS->getInstrument()->baseInstrument())return false;
return true;
}

void ConvToMDPreprocDet::allocDetMemory(size_t nHist)
{
this->det_dir.resize(nHist);
this->det_id.resize(nHist);
this->L2.resize(nHist);
this->TwoTheta.resize(nHist);
this->detIDMap.resize(nHist);
this->spec2detMap.assign(nHist,uint32_t(-1));


}

/** helper function, does preliminary calculations of the detectors positions to convert results into k-dE space ;
and places the resutls into static cash to be used in subsequent calls to this algorithm */
void ConvToMDPreprocDet::processDetectorsPositions(const API::MatrixWorkspace_sptr inputWS,Kernel::Logger& convert_log,API::Progress *pProg)
{
convert_log.information()<<" Preprocessing detectors locations in a target reciprocal space\n";
//
Instrument_const_sptr instrument = inputWS->getInstrument();
this->pBaseInstr = instrument->baseInstrument();
//
IObjComponent_const_sptr source = instrument->getSource();
IObjComponent_const_sptr sample = instrument->getSample();
if ((!source) || (!sample)) {
convert_log.error()<<" Instrument is not fully defined. Can not identify source or sample\n";
throw Exception::InstrumentDefinitionError("Instrubment not sufficiently defined: failed to get source and/or sample");
}

// L1
try{
this->L1 = source->getDistance(*sample);
convert_log.debug() << "Source-sample distance: " << L1 << std::endl;
}catch (Exception::NotFoundError &) {
convert_log.error("Unable to calculate source-sample distance");
throw Exception::InstrumentDefinitionError("Unable to calculate source-sample distance", inputWS->getTitle());
}
// efix
this->setEi(inputWS);

//
const size_t nHist = inputWS->getNumberHistograms();

this->allocDetMemory(nHist);

size_t div=100;
// Loop over the spectra
size_t ic(0);
for (size_t i = 0; i < nHist; i++){

Geometry::IDetector_const_sptr spDet;
try{
// get detector or detector group which corresponds to the spectra i
spDet= inputWS->getDetector(i);
}catch(Kernel::Exception::NotFoundError &){
continue;
}

// Check that we aren't dealing with monitor...
if (spDet->isMonitor())continue;

this->spec2detMap[i]= ic;
this->det_id[ic] = spDet->getID();
this->detIDMap[ic] = i;
this->L2[ic] = spDet->getDistance(*sample);


double polar = inputWS->detectorTwoTheta(spDet);
this->TwoTheta[ic] = polar;
double azim = spDet->getPhi();

double sPhi=sin(polar);
double ez = cos(polar);
double ex = sPhi*cos(azim);
double ey = sPhi*sin(azim);

this->det_dir[ic].setX(ex);
this->det_dir[ic].setY(ey);
this->det_dir[ic].setZ(ez);

ic++;
if(i%div==0){
pProg->report(i);
}
}
//
if(ic<nHist){
this->det_dir.resize(ic);
this->det_id.resize(ic);
this->L2.resize(ic);
this->TwoTheta.resize(ic);
this->detIDMap.resize(ic);
}
convert_log.information()<<"finished preprocessing detectors locations \n";
pProg->report();
}
/** Function sets up energy of neurtorns used by number of conversion algorithms */
void ConvToMDPreprocDet::setEi(const API::MatrixWorkspace_sptr inputWS)
{
try{
Kernel::PropertyWithValue<double> *pProp(NULL);
pProp=dynamic_cast<Kernel::PropertyWithValue<double> *>(inputWS->run().getProperty("Ei"));
efix=(*pProp);
}catch(...){
efix= std::numeric_limits<double>::quiet_NaN();
}
}

void ConvToMDPreprocDet::buildFakeDetectorsPositions(const API::MatrixWorkspace_sptr inputWS)
{

L1 = 1;
double polar(0);
emode = 0;
// efix
this->setEi(inputWS);
//
const size_t nHist = inputWS->getNumberHistograms();
this->allocDetMemory(nHist);
// Loop over the spectra
for (size_t i = 0; i < nHist; i++){


this->spec2detMap[i]= i;
this->det_id[i] = (detid_t)i;
this->detIDMap[i] = i;
this->L2[i] = 10;


this->TwoTheta[i] = polar;


double ez = 1.;
double ex = 0.;
double ey = 0.;

this->det_dir[i].setX(ex);
this->det_dir[i].setY(ey);
this->det_dir[i].setZ(ez);

}
//
}

// constructor
ConvToMDPreprocDet::ConvToMDPreprocDet():
emode(-2),
efix(std::numeric_limits<double>::quiet_NaN()),
L1(-1)
{}
// destructor
void ConvToMDPreprocDet::clearAll()
{
emode = -2,
efix = std::numeric_limits<double>::quiet_NaN();
L1 = -1;

this->det_dir.clear();
this->det_id.clear();
this->L2.clear();
this->TwoTheta.clear();
this->detIDMap.clear();
this->spec2detMap.clear();

pBaseInstr.reset();
}

} // END MDAlgorithms ns
} // end Mantid ns
@@ -1,241 +1,131 @@
#include "MDEvents/MDTransfModQ.h"
#include "MantidMDEvents/MDTransfModQ.h"

namespace Mantid
{
namespace MDAlgorithms
namespace MDEvents
{


/** Set of internal class used by ConvertToMDEvents algorithm and responsible for conversion of input workspace
* data into proper number of output dimensions for ModQ transformation
*
* Currently contains Elastic and Inelastic transformations
*
* This particular file defines specializations of generic coordinate transformation templated to the ModQ case
*
* @date 11-10-2011
Copyright &copy; 2010 ISIS Rutherford Appleton Laboratory & NScD Oak Ridge National Laboratory
This file is part of Mantid.
Mantid is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
Mantid is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
File change history is stored at: <https://svn.mantidproject.org/mantid/trunk/Code/Mantid>
Code Documentation is available at: <http://doxygen.mantidproject.org>
*/




bool MDTransfModQInelastic::calcGenericVariables(std::vector<coord_t> &Coord, size_t nd)
//**********************************************************************************************************************
//*************************************************** ELASTIC ******************************************************
//**********************************************************************************************************************
bool MDTransfModQElastic::calcGenericVariables(std::vector<coord_t> &Coord, size_t nd)
{
/// 2 coordinates (|Q|, DeltaE) came from workspace, are interconnnected all additional defined by properties,
/// here we copy these values into Coord vector
if(!pHost->fillAddProperties(Coord,nd,2))return false;

// energy
Ei = pHost->getEi();
// the wave vector of incident neutrons;
ki=sqrt(Ei/PhysicalConstants::E_mev_toNeutronWavenumberSq);
// get transformation matrix (needed for CrystalAsPoder mode)
rotMat = pHost->getTransfMatrix();
// if workspace is not in DeltaE, initiate units conversion, if not -- empty conversion should be instanciated
const Kernel::Unit_sptr pThisUnit= pHost->getAxisUnits();
// CONV_UNITS_FROM.setUpConversion(*(pHost->getDetectors()),pThisUnit->unitID(),"DeltaE");

// 1 coordinate (|Q|) came from workspace, all additional defined by properties:
if(!pHost->fillAddProperties(Coord,nd,nMatrixDim))return false;
// get transformation matrix (needed for CrystalAsPoder mode)
rotMat = pHost->getTransfMatrix();

// get pointer to the positions of the detectors
std::vector<Kernel::V3D> const & DetDir = pHost->pPrepDetectors()->getDetDir();
pDet = &DetDir[0];
pHost->getMinMax(dim_min,dim_max);

// dim_min/max here are momentums and they are verified on momentum squared base
if(dim_min[0]<0)dim_min[0]=0;
if(dim_max[0]<0)dim_max[0]=0;

dim_min[0]*=dim_min[0];
dim_max[0]*=dim_max[0];
if(std::fabs(dim_min[0]-dim_max[0])<FLT_EPSILON||dim_max[0]<dim_min[0])
{
std::string ERR = "ModQ inelastic coordinate transformation: Min Q^2 value: "+boost::lexical_cast<std::string>(dim_min[0])+
" is more or equal then Max Q^2 value: "+boost::lexical_cast<std::string>(dim_max[0]);
throw(std::invalid_argument(ERR));
}
//
return true;
std::vector<Kernel::V3D> const & DetDir = pHost->pPrepDetectors()->getDetDir();
pDet = &DetDir[0]; //
//
pHost->getMinMax(dim_min,dim_max);
// dim_min/max here are momentums and they are verified on momentum squared base
if(dim_min[0]<0)dim_min[0]=0;
if(dim_max[0]<0)dim_max[0]=0;

// dim_min here is a momentum and it is verified on momentum squared base
dim_min[0]*=dim_min[0];
dim_max[0]*=dim_max[0];
if(std::fabs(dim_min[0]-dim_max[0])<FLT_EPSILON||dim_max[0]<dim_min[0])
{
std::string ERR = "ModQ coordinate transformation: Min Q^2 value: "+boost::lexical_cast<std::string>(dim_min[0])+
" is more or equal then Max Q^2 value: "+boost::lexical_cast<std::string>(dim_max[0]);
throw(std::invalid_argument(ERR));
}

return true;
}
//
bool MDTransfModQInelastic::calcYDepCoordinates(std::vector<coord_t> &Coord,size_t i)
bool MDTransfModQElastic::calcYDepCoordinates(std::vector<coord_t> &Coord,size_t i)
{
UNUSED_ARG(Coord);
CONV_UNITS_FROM.updateConversion(i);
ex = (pDet+i)->X();
ey = (pDet+i)->Y();
ez = (pDet+i)->Z();
return true;
}

bool MDTransfModQInelastic::calc1MatrixCoord(const double& E_tr,std::vector<coord_t> &Coord)const
//
bool MDTransfModQElastic::calcMatrixCoord(const double& k0,std::vector<coord_t> &Coord)const
{
if(E_tr<dim_min[1]||E_tr>=dim_max[1])return false;
Coord[1] =(coord_t)E_tr;

// get module of the wavevector for scattered neutrons
double k_tr = k_trans<MODE>(Ei,E_tr);

double qx = -ex*k_tr;
double qy = -ey*k_tr;
double qz = ki - ez*k_tr;
// transformation matrix has to be here for "Crystal AS Powder conversion mode, further specialization possible if "powder" switch provided"
double qx = -ex*k0;
double qy = -ey*k0;
double qz = (1 - ez)*k0;
// transformation matrix has to be here for "Crystal AS Powder mode, further specialization possible if powder mode is defined "
double Qx = (rotMat[0]*qx+rotMat[1]*qy+rotMat[2]*qz);
double Qy = (rotMat[3]*qx+rotMat[4]*qy+rotMat[5]*qz);
double Qz = (rotMat[6]*qx+rotMat[7]*qy+rotMat[8]*qz);

double Qsq = Qx*Qx+Qy*Qy+Qz*Qz;
if(Qsq < dim_min[0]||Qsq>=dim_max[0])return false;
Coord[0] = (coord_t)sqrt(Qsq);

return true;

}
// should be actually on ICoordTransformer but there is problem with template-overloaded functions
bool MDTransfModQInelastic::calcMatrixCoord(const MantidVec& X,size_t i,size_t j,std::vector<coord_t> &Coord)const

void MDTransfModQElastic::initialize(const ConvToMDEventsBase &Conv)
{
UNUSED_ARG(i);
//double X_ev = CONV_UNITS_FROM.getXConverted(X,j);
//return calc1MatrixCoord(X_ev,Coord);
nMatrixDim = 1;
pHost = &Conv;
}

bool MDTransfModQInelastic::convertAndCalcMatrixCoord(const double & X,std::vector<coord_t> &Coord)const
//**********************************************************************************************************************
//*************************************************** INELASTIC *****************************************************
//**********************************************************************************************************************


bool MDTransfModQInelastic::calcGenericVariables(std::vector<coord_t> &Coord, size_t nd)
{
double X_ev = CONV_UNITS_FROM.getXConverted(X);
return calc1MatrixCoord(X_ev,Coord);
}
// constructor;
MDTransfModQInelastic::MDTransfModQInelastic():pDet(NULL),pHost(NULL){}
void MDTransfModQInelastic::setUpTransf(IConvertToMDEventsWS *pConv){
pHost = pConv;
}
private:
// the energy of the incident neutrons
double Ei;
// the wavevector of incident neutrons
double ki;
// directions to the detectors
double ex,ey,ez;
// the matrix which transforms the neutron momentums from lablratory to crystall coordinate system.
std::vector<double> rotMat;
// min-max values, some modified to work with squared values:
std::vector<double> dim_min,dim_max;
//
Kernel::V3D const *pDet;
// Calling Mantid algorithm
IConvertToMDEventsWS *pHost;
// class which would convert units
UnitsConverter<CONV,TYPE> CONV_UNITS_FROM;

};

inline bool calcGenericVariables(std::vector<coord_t> &Coord, size_t nd)
{

// 1 coordinate (|Q|) came from workspace, all additional defined by properties:
if(!pHost->fillAddProperties(Coord,nd,1))return false;
// get transformation matrix (needed for CrystalAsPoder mode)
rotMat = pHost->getTransfMatrix();

const Kernel::Unit_sptr pThisUnit= pHost->getAxisUnits();
CONV_UNITS_FROM.setUpConversion(*(pHost->getDetectors()),pThisUnit->unitID(),"Momentum");
/// 2 coordinates (|Q|, DeltaE) came from workspace, are interconnnected all additional defined by properties,
/// here we copy these values into Coord vector
if(!MDTransfModQElastic::calcGenericVariables(Coord, nd))return false;
// energy
Ei = pHost->getEi();
// the wave vector of incident neutrons;
ki=sqrt(Ei/PhysicalConstants::E_mev_toNeutronWavenumberSq);

// get pointer to the positions of the detectors
std::vector<Kernel::V3D> const & DetDir = pHost->pPrepDetectors()->getDetDir();
pDet = &DetDir[0]; //
//
pHost->getMinMax(dim_min,dim_max);
// dim_min here is a momentum and it is verified on momentum squared base
dim_min[0]*=dim_min[0];
dim_max[0]*=dim_max[0];
return true;
}
//
inline bool calcYDepCoordinates(std::vector<coord_t> &Coord,size_t i)
{
UNUSED_ARG(Coord);
CONV_UNITS_FROM.updateConversion(i);
ex = (pDet+i)->X();
ey = (pDet+i)->Y();
ez = (pDet+i)->Z();
return true;
}
//
inline bool calc1MatrixCoord(const double& k0,std::vector<coord_t> &Coord)const
{
return true;
}

bool MDTransfModQInelastic::calcMatrixCoord(const double& E_tr,std::vector<coord_t> &Coord)const
{
if(E_tr<dim_min[1]||E_tr>=dim_max[1])return false;
Coord[1] =(coord_t)E_tr;
double k_tr;
// get module of the wavevector for scattered neutrons
if(this->emode==ConvertToMD::Direct){
k_tr=sqrt((Ei-E_tr)/PhysicalConstants::E_mev_toNeutronWavenumberSq);
}else{
k_tr=sqrt((Ei+E_tr)/PhysicalConstants::E_mev_toNeutronWavenumberSq);
}

double qx = -ex*k0;
double qy = -ey*k0;
double qz = (1 - ez)*k0;
// transformation matrix has to be here for "Crystal AS Powder mode, further specialization possible if "
double qx = -ex*k_tr;
double qy = -ey*k_tr;
double qz = ki - ez*k_tr;
// transformation matrix has to be here for "Crystal AS Powder conversion mode, further specialization possible if "powder" mode defined"
double Qx = (rotMat[0]*qx+rotMat[1]*qy+rotMat[2]*qz);
double Qy = (rotMat[3]*qx+rotMat[4]*qy+rotMat[5]*qz);
double Qz = (rotMat[6]*qx+rotMat[7]*qy+rotMat[8]*qz);

double Qsq = Qx*Qx+Qy*Qy+Qz*Qz;
if(Qsq < dim_min[0]||Qsq>=dim_max[0])return false;
Coord[0] = (coord_t)sqrt(Qsq);

return true;

}

// should be actually on ICoordTransformer
inline bool calcMatrixCoord(const MantidVec& X,size_t i,size_t j,std::vector<coord_t> &Coord)const
{
UNUSED_ARG(i);
double X_ev = CONV_UNITS_FROM.getXConverted(X,j);

return calc1MatrixCoord(X_ev,Coord);
}
inline bool convertAndCalcMatrixCoord(const double & X,std::vector<coord_t> &Coord)const
{
double X_ev = CONV_UNITS_FROM.getXConverted(X);
return calc1MatrixCoord(X_ev,Coord);
}

// constructor;
CoordTransformer():pDet(NULL),pHost(NULL){}
void setUpTransf(IConvertToMDEventsWS *pConv){
pHost = pConv;
}
private:
// the energy of the incident neutrons
double Ei;
// the wavevector of incident neutrons
double ki;
// directions to the detectors
double ex,ey,ez;
// the matrix which transforms the neutron momentums from lablratory to crystall coordinate system.
std::vector<double> rotMat;
// min-max values, some modified to work with squared values:
std::vector<double> dim_min,dim_max;
//
Kernel::V3D const * pDet;
// Calling Mantid algorithm
IConvertToMDEventsWS *pHost;
// class which would convert units
UnitsConverter<CONV,TYPE> CONV_UNITS_FROM;

};
#endif
}

void MDTransfModQInelastic::initialize(const ConvToMDEventsBase &Conv)
{
// inelastic workspace provides two variables
nMatrixDim = 2;
pHost = &Conv;
emode = (ConvertToMD::EModes)pHost->getEMode();
}

} // End MDAlgorighms namespace
} // End Mantid namespace