/** Method analyzes the state of UB matrix and goniometer attached to the *workspace and decides, which target * coordinate system these variables identify. *Crystal Frame decided in case if there is UB matrix is present and is not *unit matrix *Lab frame -- if goniometer is Unit and UB is unit matrix or not present *Sample frame -- otherwise */ CnvrtToMD::TargetFrame MDWSTransform::findTargetFrame(MDWSDescription &TargWSDescription) const { bool hasGoniometer = TargWSDescription.hasGoniometer(); bool hasLattice = TargWSDescription.hasLattice(); if (!hasGoniometer) { return LabFrame; } else { if (hasLattice) return HKLFrame; else return SampleFrame; } }
/** Method verifies if the information available on the source workspace is *sufficient to build appropriate frame *@param TargWSDescription -- the class which contains the information about the *target workspace *@param CoordFrameID -- the ID of the target frame requested * * method throws invalid argument if the information on the workspace is *insufficient to define the frame requested */ void MDWSTransform::checkTargetFrame( const MDWSDescription &TargWSDescription, const CnvrtToMD::TargetFrame CoordFrameID) const { switch (CoordFrameID) { case (LabFrame): // nothing needed for lab frame return; case (SampleFrame): if (!TargWSDescription.hasGoniometer()) throw std::invalid_argument( " Sample frame needs goniometer to be defined on the workspace "); return; case (HKLFrame): // ubMatrix has to be present if (!TargWSDescription.hasLattice()) throw std::invalid_argument( " HKL frame needs UB matrix defined on the workspace "); if (!TargWSDescription.hasGoniometer()) g_Log.warning() << " HKL frame does not have goniometer defined on the " "workspace. Assuming unit goniometer matrix\n"; return; default: throw std::runtime_error( " Unexpected argument in MDWSTransform::checkTargetFrame"); } }
/** Method builds transformation Q=R*U*B*W*h where W-transf is W or WB or W*Unit*Lattice_param depending on inputs */ Kernel::DblMatrix MDWSTransform::buildQTrahsf(MDWSDescription &TargWSDescription, CnvrtToMD::CoordScaling ScaleID, bool UnitUB) const { // implements strategy if (!(TargWSDescription.hasLattice() || UnitUB)) { throw(std::invalid_argument("this function should be called only on " "workspace with defined oriented lattice")); } // if u,v us default, Wmat is unit transformation Kernel::DblMatrix Wmat(3, 3, true); // derive rotation from u0,v0 u0||ki to u,v if (!m_isUVdefault) { Wmat[0][0] = m_UProj[0]; Wmat[1][0] = m_UProj[1]; Wmat[2][0] = m_UProj[2]; Wmat[0][1] = m_VProj[0]; Wmat[1][1] = m_VProj[1]; Wmat[2][1] = m_VProj[2]; Wmat[0][2] = m_WProj[0]; Wmat[1][2] = m_WProj[1]; Wmat[2][2] = m_WProj[2]; } if (ScaleID == OrthogonalHKLScale) { std::vector<Kernel::V3D> dim_directions; std::vector<Kernel::V3D> uv(2); uv[0] = m_UProj; uv[1] = m_VProj; dim_directions = Kernel::V3D::makeVectorsOrthogonal(uv); for (size_t i = 0; i < 3; ++i) for (size_t j = 0; j < 3; ++j) Wmat[i][j] = dim_directions[j][i]; } // Now define lab frame to target frame transformation Kernel::DblMatrix Scale(3, 3, true); Kernel::DblMatrix Transf(3, 3, true); boost::shared_ptr<Geometry::OrientedLattice> spLatt; if (UnitUB) spLatt = boost::shared_ptr<Geometry::OrientedLattice>( new Geometry::OrientedLattice(1, 1, 1)); else spLatt = TargWSDescription.getLattice(); switch (ScaleID) { case NoScaling: //< momentums in A^-1 { Transf = spLatt->getU(); break; } case SingleScale: //< momentums divided by 2*Pi/Lattice -- equivalent to // d-spacing in some sense { double dMax(-1.e+32); for (int i = 0; i < 3; i++) dMax = (dMax > spLatt->a(i)) ? (dMax) : (spLatt->a(i)); for (int i = 0; i < 3; i++) Scale[i][i] = (2 * M_PI) / dMax; Transf = spLatt->getU(); break; } case OrthogonalHKLScale: //< each momentum component divided by appropriate // lattice parameter; equivalent to hkl for orthogonal // axis { if (spLatt) { for (int i = 0; i < 3; i++) { Scale[i][i] = (2 * M_PI) / spLatt->a(i); } Transf = spLatt->getU(); } break; } case HKLScale: //< non-orthogonal system for non-orthogonal lattice { if (spLatt) Scale = spLatt->getUB() * (2 * M_PI); break; } default: throw(std::invalid_argument("unrecognized conversion mode")); } TargWSDescription.addProperty("W_MATRIX", Wmat.getVector(), true); return Transf * Scale * Wmat; }
/** Build meaningful dimension names for different conversion modes * @param TargWSDescription the class-container to keep the dimension names and dimension unints * @param FrameID -- the ID describing the target transformation frame (lab, sample, hkl) * @param ScaleID -- the scale ID which define how the dimensions are scaled */ void MDWSTransform::setQ3DDimensionsNames( MDWSDescription &TargWSDescription, CnvrtToMD::TargetFrame FrameID, CnvrtToMD::CoordScaling ScaleID) const { std::vector<Kernel::V3D> dimDirections; // set default dimension names: std::vector<std::string> dimNames = TargWSDescription.getDimNames(); // define B-matrix and Lattice parameters to one in case if no OrientedLattice // is there Kernel::DblMatrix Bm(3, 3, true); std::vector<double> LatPar(3, 1); if (TargWSDescription.hasLattice()) { // redefine B-matrix and Lattice // parameters from real oriented lattice // if there is one auto spLatt = TargWSDescription.getLattice(); Bm = spLatt->getB(); for (int i = 0; i < 3; i++) LatPar[i] = spLatt->a(i); } if (FrameID == CnvrtToMD::AutoSelect) FrameID = findTargetFrame(TargWSDescription); switch (FrameID) { case (CnvrtToMD::LabFrame): { dimNames[0] = "Q_lab_x"; dimNames[1] = "Q_lab_y"; dimNames[2] = "Q_lab_z"; TargWSDescription.setCoordinateSystem(Mantid::Kernel::QLab); TargWSDescription.setFrame(Geometry::QLab::QLabName); break; } case (CnvrtToMD::SampleFrame): { dimNames[0] = "Q_sample_x"; dimNames[1] = "Q_sample_y"; dimNames[2] = "Q_sample_z"; TargWSDescription.setCoordinateSystem(Mantid::Kernel::QSample); TargWSDescription.setFrame(Geometry::QSample::QSampleName); break; } case (CnvrtToMD::HKLFrame): { dimNames[0] = "H"; dimNames[1] = "K"; dimNames[2] = "L"; Kernel::MDUnit_uptr mdUnit(new Kernel::InverseAngstromsUnit); TargWSDescription.setCoordinateSystem(Mantid::Kernel::HKL); TargWSDescription.setFrame(Geometry::HKL::HKLName); break; } default: throw(std::invalid_argument(" Unknown or undefined Target Frame ID")); } dimDirections.resize(3); dimDirections[0] = m_UProj; dimDirections[1] = m_VProj; dimDirections[2] = m_WProj; if (ScaleID == OrthogonalHKLScale) { std::vector<Kernel::V3D> uv(2); uv[0] = m_UProj; uv[1] = m_VProj; dimDirections = Kernel::V3D::makeVectorsOrthogonal(uv); } // axis names: if ((FrameID == CnvrtToMD::LabFrame) || (FrameID == CnvrtToMD::SampleFrame)) for (int i = 0; i < 3; i++) TargWSDescription.setDimName(i, dimNames[i]); else for (int i = 0; i < 3; i++) TargWSDescription.setDimName( i, MDAlgorithms::makeAxisName(dimDirections[i], dimNames)); if (ScaleID == NoScaling) { for (int i = 0; i < 3; i++) TargWSDescription.setDimUnit(i, "A^-1"); } if (ScaleID == SingleScale) { double dMax(-1.e+32); for (int i = 0; i < 3; i++) dMax = (dMax > LatPar[i]) ? (dMax) : (LatPar[i]); for (int i = 0; i < 3; i++) TargWSDescription.setDimUnit( i, "in " + MDAlgorithms::sprintfd(2 * M_PI / dMax, 1.e-3) + " A^-1"); } if ((ScaleID == OrthogonalHKLScale) || (ScaleID == HKLScale)) { // get the length along each of the axes std::vector<double> len; Kernel::V3D x; x = Bm * dimDirections[0]; len.push_back(2 * M_PI * x.norm()); x = Bm * dimDirections[1]; len.push_back(2 * M_PI * x.norm()); x = Bm * dimDirections[2]; len.push_back(2 * M_PI * x.norm()); for (int i = 0; i < 3; i++) TargWSDescription.setDimUnit( i, "in " + MDAlgorithms::sprintfd(len[i], 1.e-3) + " A^-1"); } }
/** The matrix to convert neutron momentums into the target coordinate system */ std::vector<double> MDWSTransform::getTransfMatrix(MDWSDescription &TargWSDescription, CnvrtToMD::TargetFrame FrameID, CoordScaling &ScaleID) const { Kernel::Matrix<double> mat(3, 3, true); bool powderMode = TargWSDescription.isPowder(); bool has_lattice(true); if (!TargWSDescription.hasLattice()) has_lattice = false; if (!(powderMode || has_lattice)) { std::string inWsName = TargWSDescription.getWSName(); // notice about 3D case without lattice g_Log.notice() << "Can not obtain transformation matrix from the input workspace: " << inWsName << " as no oriented lattice has been defined. \n" "Will use unit transformation matrix.\n"; } // set the frame ID to the values, requested by properties CnvrtToMD::TargetFrame CoordFrameID(FrameID); if (FrameID == AutoSelect || powderMode) // if this value is auto-select, find // appropriate frame from workspace // properties CoordFrameID = findTargetFrame(TargWSDescription); else // if not, and specific target frame requested, verify if everything is // available on the workspace for this frame checkTargetFrame( TargWSDescription, CoordFrameID); // throw, if the information is not available switch (CoordFrameID) { case (CnvrtToMD::LabFrame): { ScaleID = NoScaling; TargWSDescription.m_Wtransf = buildQTrahsf(TargWSDescription, ScaleID, true); // ignore goniometer mat = TargWSDescription.m_Wtransf; break; } case (CnvrtToMD::SampleFrame): { ScaleID = NoScaling; TargWSDescription.m_Wtransf = buildQTrahsf(TargWSDescription, ScaleID, true); // Obtain the transformation matrix to Cartesian related to Crystal mat = TargWSDescription.getGoniometerMatr() * TargWSDescription.m_Wtransf; break; } case (CnvrtToMD::HKLFrame): { TargWSDescription.m_Wtransf = buildQTrahsf(TargWSDescription, ScaleID, false); // Obtain the transformation matrix to Cartesian related to Crystal if (TargWSDescription.hasGoniometer()) mat = TargWSDescription.getGoniometerMatr() * TargWSDescription.m_Wtransf; else mat = TargWSDescription.m_Wtransf; break; } default: throw(std::invalid_argument(" Unknown or undefined Target Frame ID")); } // // and this is the transformation matrix to notional mat.Invert(); std::vector<double> rotMat = mat.getVector(); g_Log.debug() << " *********** Q-transformation matrix ***********************\n"; g_Log.debug() << "*** *qx ! *qy ! *qz !\n"; g_Log.debug() << "q1= " << rotMat[0] << " ! " << rotMat[1] << " ! " << rotMat[2] << " !\n"; g_Log.debug() << "q2= " << rotMat[3] << " ! " << rotMat[4] << " ! " << rotMat[5] << " !\n"; g_Log.debug() << "q3= " << rotMat[6] << " ! " << rotMat[7] << " ! " << rotMat[8] << " !\n"; g_Log.debug() << " *********** *********************** ***********************\n"; return rotMat; }