diff --git a/Code/Mantid/Build/dev-packages/rpm/mantid-developer/mantid-developer.spec b/Code/Mantid/Build/dev-packages/rpm/mantid-developer/mantid-developer.spec index 95fc838ccd985329c9633b5e1c9fc6ed292b65a3..39a9d019dff3cb93bc6fd1aedb2a0cb8db3ecf91 100644 --- a/Code/Mantid/Build/dev-packages/rpm/mantid-developer/mantid-developer.spec +++ b/Code/Mantid/Build/dev-packages/rpm/mantid-developer/mantid-developer.spec @@ -1,5 +1,5 @@ Name: mantid-developer -Version: 1.9 +Version: 1.10 Release: 1%{?dist} Summary: Meta Package to install dependencies for Mantid Development @@ -30,7 +30,7 @@ Requires: poco-devel Requires: PyQt4-devel Requires: python-devel Requires: python-ipython >= 1.1 -Conflicts: python-ipython >= 2.0 +%{?el6:Conflicts: python-ipython >= 2.0} Requires: python-pip Requires: python-sphinx Requires: qscintilla-devel diff --git a/Code/Mantid/Framework/API/CMakeLists.txt b/Code/Mantid/Framework/API/CMakeLists.txt index 1380797cf9153864b405b01c92cef538858b4fdb..1a8ece42503b648102159f60ac84b77ebfd39880 100644 --- a/Code/Mantid/Framework/API/CMakeLists.txt +++ b/Code/Mantid/Framework/API/CMakeLists.txt @@ -106,6 +106,7 @@ set ( SRC_FILES src/PropertyManagerDataService.cpp src/PropertyNexus.cpp src/RefAxis.cpp + src/RemoteJobManagerFactory.cpp src/Run.cpp src/Sample.cpp src/SampleEnvironment.cpp @@ -271,6 +272,7 @@ set ( INC_FILES inc/MantidAPI/PropertyManagerDataService.h inc/MantidAPI/PropertyNexus.h inc/MantidAPI/RefAxis.h + inc/MantidAPI/RemoteJobManagerFactory.h inc/MantidAPI/Run.h inc/MantidAPI/Sample.h inc/MantidAPI/SampleEnvironment.h @@ -367,6 +369,7 @@ set ( TEST_FILES ProjectionTest.h PropertyManagerDataServiceTest.h PropertyNexusTest.h + RemoteJobManagerFactoryTest.h RunTest.h SampleEnvironmentTest.h SampleShapeValidatorTest.h diff --git a/Code/Mantid/Framework/API/inc/MantidAPI/IFuncMinimizer.h b/Code/Mantid/Framework/API/inc/MantidAPI/IFuncMinimizer.h index ee45efe672c45976eaa764d737f3332899dae461..e3532a0f53c2ff1e6b002c112f4326dfb03186a8 100644 --- a/Code/Mantid/Framework/API/inc/MantidAPI/IFuncMinimizer.h +++ b/Code/Mantid/Framework/API/inc/MantidAPI/IFuncMinimizer.h @@ -69,6 +69,10 @@ public: /// Get value of cost function virtual double costFunctionVal() = 0; + /// Finalize minimization, eg store additional outputs + virtual void finalize() {} + + protected: /// Error string. std::string m_errorString; diff --git a/Code/Mantid/Framework/API/inc/MantidAPI/IRemoteJobManager.h b/Code/Mantid/Framework/API/inc/MantidAPI/IRemoteJobManager.h index 2035e271f89e416a4a0d1dc6c76fc26cc7da995e..eb6d2ef97bd9dc3a643f69368c4be2be348d5757 100644 --- a/Code/Mantid/Framework/API/inc/MantidAPI/IRemoteJobManager.h +++ b/Code/Mantid/Framework/API/inc/MantidAPI/IRemoteJobManager.h @@ -137,7 +137,7 @@ public: * @param numNodes number of nodes to use (optional and dependent on * implementation and compute resource) * - * @parm coresPerNode number of cores to use in each node (optional + * @param coresPerNode number of cores to use in each node (optional * and dependent on implemenation and compute resource) * * @return jobID string for the job started (if successful). diff --git a/Code/Mantid/Framework/API/inc/MantidAPI/RemoteJobManagerFactory.h b/Code/Mantid/Framework/API/inc/MantidAPI/RemoteJobManagerFactory.h new file mode 100644 index 0000000000000000000000000000000000000000..34fa04176d18cd43e191eb4bf346bdbfdb02b66e --- /dev/null +++ b/Code/Mantid/Framework/API/inc/MantidAPI/RemoteJobManagerFactory.h @@ -0,0 +1,124 @@ +#ifndef MANTID_API_REMOTEJOBMANAGERFACTORY_H_ +#define MANTID_API_REMOTEJOBMANAGERFACTORY_H_ + +#include "MantidAPI/DllConfig.h" +#include "MantidAPI/IRemoteJobManager.h" +#include "MantidKernel/DynamicFactory.h" +#include "MantidKernel/SingletonHolder.h" + +namespace Mantid { +namespace API { +/** +The RemoteJobManagerFactory handles the creation of remote job +managers specialised for different types of compute resources (for +different underlying job schedulers, web services, front-ends, +etc.). Through the create method of this class a shared pointer to a +remote job manager object can be obtained for a particular compute +resource. + +The remote job managers built by this factory know how to start and +stop jobs, upload/download files, etc. for the compute resource +specified when creating the job manager (as long as the compute +resource is found for the current facility in the facilities +definition file). + +Remote job manager classes must be registered/subscribe using the +macro DECLARE_REMOTEJOBMANAGER (the same way you use DECLARE_ALGORITHM +for algorithms and remote algorithms). + +As the algorithm, workspace and other factories in Mantid, this +factory is implemented as a singleton class. Typical usages: + +Mantid::API::IRemoteJob|Manager_sptr jobManager = + Mantid::API::RemoteJobManagerFactory::Instance().create("Fermi"); + +Mantid::API::IRemoteJob|Manager_sptr jobManager = + Mantid::API::RemoteJobManagerFactory::Instance().create("SCARF@STFC"); + + +Copyright © 2015 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge +National Laboratory & European Spallation Source + +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://github.com/mantidproject/mantid>. +Code Documentation is available at: <http://doxygen.mantidproject.org> +*/ +class MANTID_API_DLL RemoteJobManagerFactoryImpl + : public Kernel::DynamicFactory<IRemoteJobManager> { +public: + /// Create a remote job manager that will know how to use the + /// underlying mechanism that suits the compute resource passed + IRemoteJobManager_sptr create(const std::string &computeResourceName) const; + + /// alternative (lower level) create where the specific type of + /// manager and base URL are directly given + IRemoteJobManager_sptr create(const std::string baseURL, + const std::string jobManagerType) const; + +private: + /// So that the singleton can be created (cons/destructor are private) + friend struct Mantid::Kernel::CreateUsingNew<RemoteJobManagerFactoryImpl>; + + /// Private Constructor for singleton class + RemoteJobManagerFactoryImpl(); + /// Disallow copy construction + RemoteJobManagerFactoryImpl(const RemoteJobManagerFactoryImpl &); + /// Disallow assignment + RemoteJobManagerFactoryImpl &operator=(const RemoteJobManagerFactoryImpl &); + + /// Private Destructor + virtual ~RemoteJobManagerFactoryImpl(); + + // Unhide the inherited create method but make it private + using Kernel::DynamicFactory<IRemoteJobManager>::create; +}; + +/// Forward declaration of a specialisation of SingletonHolder for +/// RemoteJobManagerFactoryImpl (needed for dllexport) and a typedef for it. +#ifdef _WIN32 +// this breaks new namespace declaraion rules; need to find a better fix +template class MANTID_API_DLL + Mantid::Kernel::SingletonHolder<RemoteJobManagerFactoryImpl>; +#endif /* _WIN32 */ + +// The factory is just a specialisation of SingletonHolder +typedef MANTID_API_DLL Mantid::Kernel::SingletonHolder< + RemoteJobManagerFactoryImpl> RemoteJobManagerFactory; + +} // namespace API +} // namespace Mantid + +/* Macro to register (remote job manager) classes into the factory. As + * with the equivalent macros of the workspace factory or the + * algorithm factory, this creates a global object in an anonymous + * namespace. The object itself does nothing, but the comma operator + * is used in the call to its constructor to effect a call to the + * factory's subscribe method. + * + * You need to use this in every remote job manager. For example: + * DECLARE_REMOTEJOBMANAGER(MantidWebServiceAPI) + * DECLARE_REMOTEJOBMANAGER(SCARFLSFJobManager) + */ +#define DECLARE_REMOTEJOBMANAGER(classname) \ + namespace { \ + Mantid::Kernel::RegistrationHelper register_ws_##classname( \ + ((Mantid::API::RemoteJobManagerFactory::Instance().subscribe<classname>( \ + #classname)), \ + 0)); \ + } + +#endif // MANTID_API_REMOTEJOBMANAGERFACTORY_H_ diff --git a/Code/Mantid/Framework/API/src/RemoteJobManagerFactory.cpp b/Code/Mantid/Framework/API/src/RemoteJobManagerFactory.cpp new file mode 100644 index 0000000000000000000000000000000000000000..744123627a144265173445af3f7b11cd96c3c40a --- /dev/null +++ b/Code/Mantid/Framework/API/src/RemoteJobManagerFactory.cpp @@ -0,0 +1,88 @@ +#include "MantidAPI/RemoteJobManagerFactory.h" +#include "MantidKernel/ConfigService.h" +#include "MantidKernel/FacilityInfo.h" +#include "MantidKernel/Logger.h" + +namespace Mantid { +namespace API { +namespace { +/// static logger object +Kernel::Logger g_log("RemoteJobManagerFactory"); +} + +/// Private constructor, singleton class +RemoteJobManagerFactoryImpl::RemoteJobManagerFactoryImpl() + : Mantid::Kernel::DynamicFactory<IRemoteJobManager>() { + g_log.debug() << "RemoteJobManager factory created." << std::endl; +} + +/** + * Private destructor, prevent client code from using this. + */ +RemoteJobManagerFactoryImpl::~RemoteJobManagerFactoryImpl() {} + +/** + * Create a remote algorithm with the underlying mechanism that suits + * the compute resource passed. + * + * @param computeResourceName Name of a (remote) compute resource + * + * @throw std::invalid_argument If no resource is found by the name + * given (compute resources are looked up in the facilities definition + * (XML) file for the current facility. + */ +IRemoteJobManager_sptr RemoteJobManagerFactoryImpl::create( + const std::string &computeResourceName) const { + IRemoteJobManager_sptr jm; + + if (computeResourceName.empty()) + return jm; + + Mantid::Kernel::ComputeResourceInfo cr = + Mantid::Kernel::ConfigService::Instance().getFacility().computeResource( + computeResourceName); + + // this is the default. It could be "MantidWebServiceAPI", "LSF", + // "SCARFLSF", "MOAB", etc. + std::string type = "MantidWebServiceAPIJobManager"; + std::string fdfType = cr.remoteJobManagerType(); + if (!fdfType.empty()) + type = fdfType; + return create(cr.baseURL(), type); +} + +/** + * Lower level create method that makes a remote algorithm given a + * base URL and the type of remote job manager. + * + * @param baseURL URL where the resource is accessible + * + * @param jobManagerType Type/class that can handle this remote + * compute resource (string names as used in the facilities definition + * file, for example: MantidWebServiceAPIJobManager). + * + * @throw std::invalid_argument If there is an issue with the URL or + * the type (for example the type is not recognized). + */ +Mantid::API::IRemoteJobManager_sptr +RemoteJobManagerFactoryImpl::create(const std::string baseURL, + const std::string jobManagerType) const { + Mantid::API::IRemoteJobManager_sptr jm; + + // use the inherited/generic create method + try { + jm = this->create(jobManagerType); + } catch (Kernel::Exception::NotFoundError &e) { + throw Kernel::Exception::NotFoundError( + "RemoteJobManagerFactory: failed to create a remote job manager of " + "type (class) '" + + jobManagerType + "' with base URL " + baseURL + + ". Error description: " + e.what(), + jobManagerType); + } + + return jm; +} + +} // namespace API +} // Namespace Mantid diff --git a/Code/Mantid/Framework/API/test/RemoteJobManagerFactoryTest.h b/Code/Mantid/Framework/API/test/RemoteJobManagerFactoryTest.h new file mode 100644 index 0000000000000000000000000000000000000000..9fa693d8893d48bac960394befb79f17d06bf71b --- /dev/null +++ b/Code/Mantid/Framework/API/test/RemoteJobManagerFactoryTest.h @@ -0,0 +1,149 @@ +#ifndef REMOTEJOBMANAGERFACTORYTEST_H_ +#define REMOTEJOBMANAGERFACTORYTEST_H_ + +#include "MantidAPI/RemoteJobManagerFactory.h" +#include "MantidKernel/ConfigService.h" +#include "MantidKernel/FacilityInfo.h" + +using namespace Mantid::API; + +// Just a minimal implementation of IRemoteJobManager, sufficient for the +// factory +class TestJM : public IRemoteJobManager { +public: + virtual void authenticate(const std::string &username, + const std::string &password) { + UNUSED_ARG(username); + UNUSED_ARG(password); + } + + virtual std::string + submitRemoteJob(const std::string &transactionID, const std::string &runnable, + const std::string ¶m, const std::string &taskName = "", + const int numNodes = 1, const int coresPerNode = 1) { + UNUSED_ARG(transactionID); + UNUSED_ARG(runnable); + UNUSED_ARG(param); + UNUSED_ARG(taskName); + UNUSED_ARG(numNodes); + UNUSED_ARG(coresPerNode); + return ""; + } + + virtual void downloadRemoteFile(const std::string &transactionID, + const std::string &remoteFileName, + const std::string &localFileName) { + UNUSED_ARG(transactionID); + UNUSED_ARG(remoteFileName); + UNUSED_ARG(localFileName); + } + + virtual std::vector<RemoteJobInfo> queryAllRemoteJobs() const { + return std::vector<RemoteJobInfo>(); + } + + virtual std::vector<std::string> + queryRemoteFile(const std::string &transactionID) const { + UNUSED_ARG(transactionID); + return std::vector<std::string>(); + } + + virtual RemoteJobInfo queryRemoteJob(const std::string &jobID) const { + UNUSED_ARG(jobID); + return RemoteJobInfo(); + } + + virtual std::string startRemoteTransaction() { return ""; } + + virtual void stopRemoteTransaction(const std::string &transactionID) { + UNUSED_ARG(transactionID); + } + + virtual void abortRemoteJob(const std::string &jobID) { UNUSED_ARG(jobID); } + + virtual void uploadRemoteFile(const std::string &transactionID, + const std::string &remoteFileName, + const std::string &localFileName) { + UNUSED_ARG(transactionID); + UNUSED_ARG(remoteFileName); + UNUSED_ARG(localFileName); + } +}; + +class RemoteJobManagerFactoryTest : public CxxTest::TestSuite { +public: + void test_unsubscribed() { + + IRemoteJobManager_sptr jobManager; + TS_ASSERT_THROWS( + jobManager = RemoteJobManagerFactory::Instance().create("Inexistent"), + std::runtime_error); + + TS_ASSERT_THROWS(jobManager = + RemoteJobManagerFactory::Instance().create("TestJM"), + std::runtime_error); + } + + // minimal positive test + void test_createTestJM() { + RemoteJobManagerFactory::Instance().subscribe<TestJM>("TestJM"); + // throws not found cause it is not in facilities.xml, but otherwise fine + TS_ASSERT_THROWS( + jm = Mantid::API::RemoteJobManagerFactory::Instance().create("TestJM"), + Mantid::Kernel::Exception::NotFoundError); + } + + // this must fail, resource not found in the current facility + void test_createAlienResource() { + // save facility, do this before any changes + const Mantid::Kernel::FacilityInfo &prevFac = + Mantid::Kernel::ConfigService::Instance().getFacility(); + + Mantid::Kernel::ConfigService::Instance().setFacility("ISIS"); + TS_ASSERT_THROWS( + jm = Mantid::API::RemoteJobManagerFactory::Instance().create("Fermi"), + Mantid::Kernel::Exception::NotFoundError); + + Mantid::Kernel::ConfigService::Instance().setFacility("SNS"); + TS_ASSERT_THROWS( + Mantid::API::IRemoteJobManager_sptr jobManager = + Mantid::API::RemoteJobManagerFactory::Instance().create( + "SCARF@STFC"), + Mantid::Kernel::Exception::NotFoundError); + + // restore facility, always do this at the end + Mantid::Kernel::ConfigService::Instance().setFacility(prevFac.name()); + } + + // a simple positive test + void test_createRemoteManagers() { + // save facility, do this before any changes + const Mantid::Kernel::FacilityInfo &prevFac = + Mantid::Kernel::ConfigService::Instance().getFacility(); + + Mantid::Kernel::ConfigService::Instance().setFacility("SNS"); + // TODO: at the moment these two create throw a NotFoundError + // because the RemoteJobManager classes are missing and have not + // done a DECLARE_REMOTEJOBMANAGER. Change this test when that is + // done (ticket #11126 etc.) + TS_ASSERT_THROWS( + Mantid::API::IRemoteJobManager_sptr jobManager = + Mantid::API::RemoteJobManagerFactory::Instance().create("Fermi"), + Mantid::Kernel::Exception::NotFoundError); + + Mantid::Kernel::ConfigService::Instance().setFacility("ISIS"); + TS_ASSERT_THROWS( + Mantid::API::IRemoteJobManager_sptr jobManager = + Mantid::API::RemoteJobManagerFactory::Instance().create( + "SCARF@STFC"), + Mantid::Kernel::Exception::NotFoundError); + + // restore facility, always do this at the end + Mantid::Kernel::ConfigService::Instance().setFacility(prevFac.name()); + } + +private: + Mantid::API::IRemoteJobManager_sptr jm; +}; + +#endif /* REMOTEJOBMANAGERFACTORYTEST_H_ */ diff --git a/Code/Mantid/Framework/Algorithms/src/Stitch1DMany.cpp b/Code/Mantid/Framework/Algorithms/src/Stitch1DMany.cpp index 6f63f26bff51d45929ce599e7a73e14ccf3349b4..8611b757ee9372acc8d756c7727534fc5312364a 100644 --- a/Code/Mantid/Framework/Algorithms/src/Stitch1DMany.cpp +++ b/Code/Mantid/Framework/Algorithms/src/Stitch1DMany.cpp @@ -207,18 +207,20 @@ void Stitch1DMany::exec() { // List of workspaces to be grouped std::vector<std::string> toGroup; + const std::string groupName = this->getProperty("OutputWorkspace"); + size_t numWSPerGroup = groupWorkspaces[0]->size(); for (size_t i = 0; i < numWSPerGroup; ++i) { // List of workspaces to stitch std::vector<std::string> toProcess; // The name of the resulting workspace - std::string outName; + std::string outName = groupName; for (size_t j = 0; j < groupWorkspaces.size(); ++j) { const std::string wsName = groupWorkspaces[j]->getItem(i)->name(); toProcess.push_back(wsName); - outName += wsName; + outName += "_" + wsName; } IAlgorithm_sptr stitchAlg = createChildAlgorithm("Stitch1DMany"); @@ -245,8 +247,6 @@ void Stitch1DMany::exec() { scaleFactors.end()); } - const std::string groupName = this->getProperty("OutputWorkspace"); - IAlgorithm_sptr groupAlg = createChildAlgorithm("GroupWorkspaces"); groupAlg->initialize(); groupAlg->setAlwaysStoreInADS(true); diff --git a/Code/Mantid/Framework/Algorithms/test/PolarizationCorrectionTest.h b/Code/Mantid/Framework/Algorithms/test/PolarizationCorrectionTest.h index ea8ebf25defd3f47972f3316b709369c6b90be9c..e1c508f642497a2edf88ad230a6d6979d26cffec 100644 --- a/Code/Mantid/Framework/Algorithms/test/PolarizationCorrectionTest.h +++ b/Code/Mantid/Framework/Algorithms/test/PolarizationCorrectionTest.h @@ -178,6 +178,7 @@ public: checkAlg->setChild(true); checkAlg->setProperty("Workspace1", groupWS->getItem(i)); checkAlg->setProperty("Workspace2", outWS->getItem(i)); + checkAlg->setProperty("Tolerance", 3e-16); checkAlg->execute(); const std::string result = checkAlg->getProperty("Result"); TS_ASSERT_EQUALS("Success!", result); diff --git a/Code/Mantid/Framework/Crystal/src/SCDCalibratePanels.cpp b/Code/Mantid/Framework/Crystal/src/SCDCalibratePanels.cpp index 79f0d3da50ea775480d39fcb55ba4ba911e09927..106ed965dab2d10f23f8e4be54ceb8bc845d3837 100644 --- a/Code/Mantid/Framework/Crystal/src/SCDCalibratePanels.cpp +++ b/Code/Mantid/Framework/Crystal/src/SCDCalibratePanels.cpp @@ -1669,7 +1669,7 @@ void SCDCalibratePanels::FixUpBankParameterMap( void writeXmlParameter(ofstream &ostream, const string &name, const double value) { ostream << " <parameter name =\"" << name << "\"><value val=\"" << value - << "\" />" << endl; + << "\" /> </parameter>" << endl; } void diff --git a/Code/Mantid/Framework/CurveFitting/inc/MantidCurveFitting/FABADAMinimizer.h b/Code/Mantid/Framework/CurveFitting/inc/MantidCurveFitting/FABADAMinimizer.h index 96c17435ca3dcc78da315df6bd3ab5dfe0435703..751e195e233676fd8a9f8be9af86c8a123189af1 100644 --- a/Code/Mantid/Framework/CurveFitting/inc/MantidCurveFitting/FABADAMinimizer.h +++ b/Code/Mantid/Framework/CurveFitting/inc/MantidCurveFitting/FABADAMinimizer.h @@ -40,8 +40,6 @@ public: /// Constructor FABADAMinimizer(); virtual ~FABADAMinimizer(); - /// Lo ha puesto Roman y no se para que!! creo que es el destructor - /// Name of the minimizer. std::string name() const { return "FABADA"; } /// Initialize minimizer, i.e. pass a function to minimize. @@ -51,6 +49,8 @@ public: virtual bool iterate(size_t iter); /// Return current value of the cost function virtual double costFunctionVal(); + /// Finalize minimization, eg store additional outputs + virtual void finalize(); private: /// Pointer to the cost function. Must be the least squares. @@ -85,8 +85,9 @@ private: std::vector<bool> m_bound; /// Convergence criteria for each parameter std::vector<double> m_criteria; + /// Maximum number of iterations + size_t m_max_iter; }; - } // namespace CurveFitting } // namespace Mantid diff --git a/Code/Mantid/Framework/CurveFitting/src/DynamicKuboToyabe.cpp b/Code/Mantid/Framework/CurveFitting/src/DynamicKuboToyabe.cpp index 4b7bae69801a1dceab858717f86c4fe29435abbd..d19e1e94fada5d6b90608c50aec635f484fcc093 100644 --- a/Code/Mantid/Framework/CurveFitting/src/DynamicKuboToyabe.cpp +++ b/Code/Mantid/Framework/CurveFitting/src/DynamicKuboToyabe.cpp @@ -24,6 +24,111 @@ void DynamicKuboToyabe::init() declareParameter("Nu", 0.0, "Hopping rate"); } + +//-------------------------------------------------------------------------------------------------------------------------------------- +// From Numerical Recipes + +// Midpoint method +double midpnt(double func(const double, const double, const double), + const double a, const double b, const int n, const double g, const double w0) { +// quote & modified from numerical recipe 2nd edtion (page147) + + static double s; + + if (n==1) { + s = (b-a)*func(0.5*(a+b),g,w0); + return (s); + } else { + double x, tnm, sum, del, ddel; + int it, j; + for (it=1,j=1;j<n-1;j++) it *= 3; + tnm = it; + del = (b-a)/(3*tnm); + ddel=del+del; + x = a+0.5*del; + sum =0.0; + for (j=1;j<=it;j++) { + sum += func(x,g,w0); + x += ddel; + sum += func(x,g,w0); + x += del; + } + s=(s+(b-a)*sum/tnm)/3.0; + return s; + } +} + +// Polynomial interpolation +void polint (double xa[], double ya[], int n, double x, double& y, double& dy) { + int i, m, ns = 1; + double dif; + + dif = fabs(x-xa[1]); + std::vector<double> c(n+1); + std::vector<double> d(n+1); + for (i=1;i<=n;i++){ + double dift; + if((dift=fabs(x-xa[i]))<dif) { + ns=i; + dif=dift; + } + c[i]=ya[i]; + d[i]=ya[i]; + } + y=ya[ns--]; + for (m=1;m<n;m++) { + for (i=1;i<=n-m;i++) { + double den, ho, hp, w; + ho=xa[i]-x; + hp=xa[i+m]-x; + w=c[i+1]-d[i]; + if((den=ho-hp)==0.0){ //error message!!! + throw std::runtime_error("Error in routin polint"); + } + den=w/den; + d[i]=hp*den; + c[i]=ho*den; + } + y += (dy=(2*(ns)<(n-m) ? c[ns+1] : d[ns--])); + + } + +} + +// Integration +double integral (double func(const double, const double, const double), + const double a, const double b, const double g, const double w0) { + + const int JMAX = 14; + const int JMAXP = JMAX + 1; + const int K = 5; + + int j; + double ss,dss; + double h[JMAXP+1], s[JMAXP]; + + h[1] = 1.0; + for (j=1; j<= JMAX; j++) { + s[j]=midpnt(func,a,b,j,g,w0); + if (j >= K) { + polint(&h[j-K],&s[j-K],K,0.0,ss,dss); + if (fabs(dss) <= fabs(ss)) return ss; + } + h[j+1]=h[j]/9.0; + } + throw std::runtime_error("Too many steps in routine integrate"); + return 0.0; +} + +// End of Numerical Recipes routines +//-------------------------------------------------------------------------------------------------------------------------------------- + + +// f1: function to integrate +double f1(const double x, const double G, const double w0) { + return( exp(-G*G*x*x/2)*sin(w0*x)); +} + // Static Zero Field Kubo Toyabe relaxation function double ZFKT (const double x, const double G){ @@ -31,33 +136,78 @@ double ZFKT (const double x, const double G){ return (0.3333333333 + 0.6666666667*exp(-0.5*q)*(1-q)); } +// Static non-zero field Kubo Toyabe relaxation function +double HKT (const double x, const double G, const double F) { + + const double q = G*G*x*x; + const double gm = 2*M_PI*0.01355342; // Muon gyromagnetic ratio * 2 * PI + + double w; + if (F>2*G) { + // Use F + w = gm * F; + } else { + // Use G + w = gm * 2 * G; + } + + const double r = G*G/w/w; + + double ig; + if ( x>0 && r>0 ) { + // Compute integral + ig = integral(f1,0.0,x,G,w); + } else { + // Integral is 0 + ig = 0; + } + + const double ktb=(1-2*r*(1-exp(-q/2)*cos(w*x))+2*r*r*w*ig); + + if ( F>2*G ) { + return ktb; + } else { + const double kz = ZFKT(x,G); + return kz+F/2/G*(ktb-kz); + } + +} + // Dynamic Kubo-Toyabe -double getDKT (double t, double G, double v){ +double getDKT (double t, double G, double F, double v){ const int tsmax = 656; // Length of the time axis, 32 us of valid data const double eps = 0.05; // Bin width for calculations - static double oldG=-1., oldV=-1.; + static double oldG=-1., oldV=-1., oldF=-1.; static std::vector<double> gStat(tsmax), gDyn(tsmax); - if ( (G != oldG) || (v != oldV) ){ + if ( (G != oldG) || (v != oldV) || (F != oldF) ){ - // If G or v have changed with respect to the + // If G or v or F have changed with respect to the // previous call, we need to re-do the computations - if ( G != oldG ){ + if ( G != oldG || (F != oldF) ){ // But we only need to - // re-compute gStat if G has changed + // re-compute gStat if G or F have changed // Generate static Kubo-Toyabe - for (int k=0; k<tsmax; k++){ - gStat[k]= ZFKT(k*eps,G); + if (F == 0) { + for (int k=0; k<tsmax; k++){ + gStat[k]= ZFKT(k*eps,G); + } + } else { + for (int k=0; k<tsmax; k++){ + gStat[k]= HKT(k*eps,G,F); + } } // Store new G value oldG =G; + // Store new F value + oldF =F; } // Store new v value @@ -105,26 +255,19 @@ void DynamicKuboToyabe::function1D(double* out, const double* xValues, const siz } // Non-zero external field else{ - throw std::runtime_error("HKT() not implemented yet"); + for (size_t i = 0; i < nData; i++) { + out[i] = A*HKT(xValues[i],G,F); + } } } // Non-zero hopping rate else { - if ( F==0.0 ) { - - for (size_t i = 0; i<nData; i++){ - out[i] = A*getDKT(xValues[i],G,v); - } - - } else { - - // Non-zero field - throw std::runtime_error("HKT() not implemented yet"); + for (size_t i = 0; i<nData; i++){ + out[i] = A*getDKT(xValues[i],G,F,v); } - - } // else hopping rate != 0 + } } diff --git a/Code/Mantid/Framework/CurveFitting/src/FABADAMinimizer.cpp b/Code/Mantid/Framework/CurveFitting/src/FABADAMinimizer.cpp index 96696fb9f968ab9b92dfeb4ce5bcc19e2f97dc4d..4fb27b06173e78b5e22ab8ee59ff7e9996818884 100644 --- a/Code/Mantid/Framework/CurveFitting/src/FABADAMinimizer.cpp +++ b/Code/Mantid/Framework/CurveFitting/src/FABADAMinimizer.cpp @@ -37,41 +37,51 @@ namespace { Kernel::Logger g_log("FABADAMinimizer"); // absolute maximum number of iterations when fit must converge const size_t convergenceMaxIterations = 50000; -// histogram length for the PDF output workspace -const size_t pdf_length = 50; // number of iterations when convergence isn't expected const size_t lowerIterationLimit = 350; +// very large number +const double largeNumber = 1e100; +// jump checking rate +const size_t jumpCheckingRate = 200; +// low jump limit +const double lowJumpLimit = 1e-25; } DECLARE_FUNCMINIMIZER(FABADAMinimizer, FABADA) //---------------------------------------------------------------------------------------------- /// Constructor -FABADAMinimizer::FABADAMinimizer() : API::IFuncMinimizer(), m_conv_point(0) { +FABADAMinimizer::FABADAMinimizer() { declareProperty("ChainLength", static_cast<size_t>(10000), "Length of the converged chain."); + declareProperty("StepsBetweenValues", static_cast<size_t>(10), + "Steps realized between keeping each result."); declareProperty( - "ConvergenceCriteria", 0.0001, - "Variance in Chi square for considering convergence reached."); - declareProperty(new API::WorkspaceProperty<>("OutputWorkspacePDF", "pdf", - Kernel::Direction::Output), - "The name to give the output workspace"); - declareProperty(new API::WorkspaceProperty<>("OutputWorkspaceChain", "chain", + "ConvergenceCriteria", 0.01, + "Variance in Cost Function for considering convergence reached."); + declareProperty("JumpAcceptanceRate", 0.6666666, + "Desired jumping acceptance rate"); + declareProperty( + new API::WorkspaceProperty<>("PDF", "PDF", Kernel::Direction::Output), + "The name to give the output workspace"); + declareProperty(new API::WorkspaceProperty<>("Chains", "Chain", Kernel::Direction::Output), "The name to give the output workspace"); - declareProperty(new API::WorkspaceProperty<>("OutputWorkspaceConverged", "", - Kernel::Direction::Output, - API::PropertyMode::Optional), - "The name to give the output workspace"); - declareProperty(new API::WorkspaceProperty<API::ITableWorkspace>( - "ChiSquareTable", "chi2", Kernel::Direction::Output), + declareProperty(new API::WorkspaceProperty<>( + "ConvergedChain", "ConvergedChain", + Kernel::Direction::Output, API::PropertyMode::Optional), "The name to give the output workspace"); + declareProperty( + new API::WorkspaceProperty<API::ITableWorkspace>( + "CostFunctionTable", "CostFunction", Kernel::Direction::Output), + "The name to give the output workspace"); declareProperty(new API::WorkspaceProperty<API::ITableWorkspace>( - "PdfError", "pdfE", Kernel::Direction::Output), + "Parameters", "Parameters", Kernel::Direction::Output), "The name to give the output workspace"); } //---------------------------------------------------------------------------------------------- + /// Destructor FABADAMinimizer::~FABADAMinimizer() {} @@ -114,12 +124,12 @@ void FABADAMinimizer::initialize(API::ICostFunction_sptr function, if (bcon->hasLower()) { m_lower.push_back(bcon->lower()); } else { - m_lower.push_back(-10e100); + m_lower.push_back(-largeNumber); } if (bcon->hasUpper()) { m_upper.push_back(bcon->upper()); } else { - m_upper.push_back(10e100); + m_upper.push_back(largeNumber); } if (p < m_lower[i]) { p = m_lower[i]; @@ -130,10 +140,14 @@ void FABADAMinimizer::initialize(API::ICostFunction_sptr function, m_parameters.set(i, p); } } + } else { + m_lower.push_back(-largeNumber); + m_upper.push_back(largeNumber); } std::vector<double> v; v.push_back(p); m_chain.push_back(v); + m_max_iter = maxIterations; m_changes.push_back(0); m_par_converged.push_back(false); m_criteria.push_back(getProperty("ConvergenceCriteria")); @@ -148,6 +162,7 @@ void FABADAMinimizer::initialize(API::ICostFunction_sptr function, v.push_back(m_chi2); m_chain.push_back(v); m_converged = false; + m_max_iter = maxIterations; } /// Do one iteration. Returns true if iterations to be continued, false if they @@ -158,14 +173,14 @@ bool FABADAMinimizer::iterate(size_t) { throw std::runtime_error("Cost function isn't set up."); } - size_t n = m_leastSquares->nParams(); - size_t m = n; + size_t nParams = m_leastSquares->nParams(); + size_t m = nParams; // Just for the last iteration. For doing exactly the indicated number of // iterations. - if (m_converged && m_counter == (m_numberIterations)) { + if (m_converged && m_counter == m_numberIterations) { size_t t = getProperty("ChainLength"); - m = t % n; + m = t % nParams; } // Do one iteration of FABADA's algorithm for each parameter. @@ -174,25 +189,17 @@ bool FABADAMinimizer::iterate(size_t) { // Calculate the step, depending on convergence reached or not double step; - if (m_converged) { + if (m_converged || m_bound[i]) { boost::mt19937 mt; - mt.seed(123 * (int(m_counter) + 45 * int(i))); - + mt.seed(123 * (int(m_counter) + + 45 * int(i))); // Numeros inventados para la seed boost::normal_distribution<double> distr(0.0, std::abs(m_jump[i])); boost::variate_generator< boost::mt19937, boost::normal_distribution<double>> gen(mt, distr); - step = gen(); - } else { step = m_jump[i]; } - // Couts just for helping when developing when coding - /// std::cout << std::endl << m_counter << "." << i << - /// std::endl<<std::endl<< m_parameters.get(i)<<std::endl; //DELETE AT THE - /// END - /// std::cout << "Real step: " << step << " Due to the m_jump: " << - /// m_jump[i] << std::endl; //DELETE AT THE END // Calculate the new value of the parameter double new_value = m_parameters.get(i) + step; @@ -200,11 +207,25 @@ bool FABADAMinimizer::iterate(size_t) { // Comproves if it is inside the boundary constrinctions. If not, changes // it. if (m_bound[i]) { - if (new_value < m_lower[i]) { - new_value = m_lower[i] + (m_lower[i] - new_value) / 2; + while (new_value < m_lower[i]) { + if (std::abs(step) > m_upper[i] - m_lower[i]) { + new_value = m_parameters.get(i) + step / 10.0; + step = step / 10; + m_jump[i] = m_jump[i] / 10; + } else { + new_value = + m_lower[i] + std::abs(step) - (m_parameters.get(i) - m_lower[i]); + } } - if (new_value > m_upper[i]) { - new_value = m_upper[i] - (new_value - m_upper[i]) / 2; + while (new_value > m_upper[i]) { + if (std::abs(step) > m_upper[i] - m_lower[i]) { + new_value = m_parameters.get(i) + step / 10.0; + step = step / 10; + m_jump[i] = m_jump[i] / 10; + } else { + new_value = + m_upper[i] - (std::abs(step) + m_parameters.get(i) - m_upper[i]); + } } } @@ -216,102 +237,79 @@ bool FABADAMinimizer::iterate(size_t) { m_leastSquares->setParameter(i, new_value); double chi2_new = m_leastSquares->val(); - /// std::cout << "OLD Chi2: " << m_chi2 << " NEW Chi2: " << chi2_new - /// << std::endl; // DELETE AT THE END - // If new Chi square value is lower, jumping directly to new parameter if (chi2_new < m_chi2) { - for (size_t j = 0; j < n; j++) { + for (size_t j = 0; j < nParams; j++) { m_chain[j].push_back(new_parameters.get(j)); } - m_chain[n].push_back(chi2_new); + m_chain[nParams].push_back(chi2_new); m_parameters = new_parameters; m_chi2 = chi2_new; m_changes[i] += 1; - /// std::cout << "Salta directamente!!" << std::endl;// DELETE AT THE END + } // If new Chi square value is higher, it depends on the probability else { // Calculate probability of change double prob = exp((m_chi2 / 2.0) - (chi2_new / 2.0)); - /// std::cout << "PROBABILIDAD cambio: " << prob << std::endl;// DELETE - /// AT THE END // Decide if changing or not boost::mt19937 mt; mt.seed(int(time_t()) + 48 * (int(m_counter) + 76 * int(i))); boost::uniform_real<> distr(0.0, 1.0); double p = distr(mt); - /// std::cout << " Random number " << p << std::endl;// DELETE AT THE END if (p <= prob) { - for (size_t j = 0; j < n; j++) { + for (size_t j = 0; j < nParams; j++) { m_chain[j].push_back(new_parameters.get(j)); } - m_chain[n].push_back(chi2_new); + m_chain[nParams].push_back(chi2_new); m_parameters = new_parameters; m_chi2 = chi2_new; m_changes[i] += 1; - /// std::cout << "SI hay cambio" << std::endl;// DELETE AT THE END } else { - for (size_t j = 0; j < n; j++) { + for (size_t j = 0; j < nParams; j++) { m_chain[j].push_back(m_parameters.get(j)); } - m_chain[n].push_back(m_chi2); + m_chain[nParams].push_back(m_chi2); m_leastSquares->setParameter(i, new_value - m_jump[i]); m_jump[i] = -m_jump[i]; - /// std::cout << "NO hay cambio" << std::endl;// DELETE AT THE END } } - /// std::cout << std::endl << std::endl << std::endl;// DELETE AT THE END - - const size_t jumpCheckingRate = 200; - const double lowJumpLimit = 1e-15; + const double jumpAR = getProperty("JumpAcceptanceRate"); // Update the jump once each jumpCheckingRate iterations - if (m_counter % jumpCheckingRate == 150) { + if (m_counter % jumpCheckingRate == 150) // JUMP CHECKING RATE IS 200, BUT + // IS NOT CHECKED AT FIRST STEP, IT + // IS AT 150 + { double jnew; - // All this is just a temporal test... - std::vector<double>::const_iterator first = m_chain[n].end() - 41; - std::vector<double>::const_iterator last = m_chain[n].end(); - std::vector<double> test(first, last); - int c = 0; - for (int j = 0; j < 39; ++j) { - if (test[j] == test[j + 1]) { - c += 1; - } + if (m_changes[i] == 0.0) { + jnew = m_jump[i] / + 10.0; // JUST FOR THE CASE THERE HAS NOT BEEN ANY CHANGE. + } else { + double f = m_changes[i] / double(m_counter); + jnew = m_jump[i] * f / jumpAR; } - if (c > 38) { - jnew = m_jump[i] / 100; - } // ...untill here. - else { - if (m_changes[i] == 0.0) { - jnew = m_jump[i] / 10.0; - } else { - double f = m_changes[i] / double(m_counter); - jnew = m_jump[i] * f / 0.6666666666; - /// std::cout << f << " m_counter "<< m_counter << " m_changes - /// " << m_changes[i] << std::endl; // DELETE AT THE END - } - } m_jump[i] = jnew; // Check if the new jump is too small. It means that it has been a wrong // convergence. if (std::abs(m_jump[i]) < lowJumpLimit) { API::IFunction_sptr fun = m_leastSquares->getFittingFunction(); - throw std::runtime_error( - "Wrong convergence for parameter " + fun->parameterName(i) + - ". Try to set a proper initial value this parameter"); + g_log.warning() + << "Wrong convergence for parameter " + fun->parameterName(i) + + ". Try to set a proper initial value for this parameter" + << std::endl; } } // Check if the Chi square value has converged for parameter i. - if (!m_par_converged[i] && - m_counter > 350) // It only check since the iteration number 350 - { + const size_t startingPoint = + 350; // The iteration since it starts to check if convergence is reached + if (!m_par_converged[i] && m_counter > startingPoint) { if (chi2_new != m_chi2) { double chi2_quotient = std::abs(chi2_new - m_chi2) / m_chi2; if (chi2_quotient < m_criteria[i]) { @@ -319,28 +317,28 @@ bool FABADAMinimizer::iterate(size_t) { } } } - } + } // for i - m_counter += - 1; // Update the counter, after finishing the iteration for each parameter + // Update the counter, after finishing the iteration for each parameter + m_counter += 1; // Check if Chi square has converged for all the parameters. if (m_counter > lowerIterationLimit && !m_converged) { size_t t = 0; - for (size_t i = 0; i < n; i++) { + for (size_t i = 0; i < nParams; i++) { if (m_par_converged[i]) { t += 1; } } // If all parameters have converged: // It set up both the counter and the changes' vector to 0, in order to - // consider only the - // data of the converged part of the chain, when updating the jump. - if (t == n) { + // consider only the data of the converged part of the chain, when updating + // the jump. + if (t == nParams) { m_converged = true; - m_conv_point = m_counter * n + 1; + m_conv_point = m_counter * nParams + 1; m_counter = 0; - for (size_t i = 0; i < n; ++i) { + for (size_t i = 0; i < nParams; ++i) { m_changes[i] = 0; } } @@ -357,7 +355,7 @@ bool FABADAMinimizer::iterate(size_t) { else { API::IFunction_sptr fun = m_leastSquares->getFittingFunction(); std::string failed = ""; - for (size_t i = 0; i < n; ++i) { + for (size_t i = 0; i < nParams; ++i) { if (!m_par_converged[i]) { failed = failed + fun->parameterName(i) + ", "; } @@ -365,7 +363,7 @@ bool FABADAMinimizer::iterate(size_t) { failed.replace(failed.end() - 2, failed.end(), "."); throw std::runtime_error( "Convegence NOT reached after " + - boost::lexical_cast<std::string>(m_counter) + + boost::lexical_cast<std::string>(m_max_iter) + " iterations.\n Try to set better initial values for parameters: " + failed); } @@ -375,176 +373,262 @@ bool FABADAMinimizer::iterate(size_t) { if (m_counter <= m_numberIterations) { return true; } - // When the all the iterations have been done, calculate and show all the - // results. - else { - // Create the workspace for the Probability Density Functions - API::MatrixWorkspace_sptr ws = API::WorkspaceFactory::Instance().create( - "Workspace2D", n, pdf_length + 1, pdf_length); - - // Create the workspace for the parameters' value and errors. - API::ITableWorkspace_sptr wsPdfE = - API::WorkspaceFactory::Instance().createTable("TableWorkspace"); - wsPdfE->addColumn("str", "Name"); - wsPdfE->addColumn("double", "Value"); - wsPdfE->addColumn("double", "Left's error"); - wsPdfE->addColumn("double", "Rigth's error"); - - std::vector<double>::iterator pos_min = std::min_element( - m_chain[n].begin() + m_conv_point, - m_chain[n] - .end()); // Calculate the position of the minimum Chi aquare value - m_chi2 = *pos_min; - // index of the minimum chi^2 - size_t minIndex = - static_cast<size_t>(std::distance(m_chain[n].begin(), pos_min)); - - std::vector<double> par_def(n); - API::IFunction_sptr fun = m_leastSquares->getFittingFunction(); + // If convergence has been reached, but the maximum of iterations have been + // reached before finishing the chain, stop and throw the error. + if (m_counter >= m_max_iter) { + throw std::length_error("Convegence reached but Max Iterations parameter " + "insufficient for creating the whole chain.\n " + "Increase Max Iterations"); + } + // nothing else to do, stop interations + return false; + } + // can we even get here? + return true; +} - // Do one iteration for each parameter. - for (size_t j = 0; j < n; ++j) { - // Calculate the parameter value and the errors - par_def[j] = m_chain[j][minIndex]; - std::vector<double>::const_iterator first = - m_chain[j].begin() + m_conv_point; - std::vector<double>::const_iterator last = m_chain[j].end(); - std::vector<double> conv_chain(first, last); - size_t conv_length = conv_chain.size(); - std::sort(conv_chain.begin(), conv_chain.end()); - std::vector<double>::const_iterator pos_par = - std::find(conv_chain.begin(), conv_chain.end(), par_def[j]); - int sigma = int(0.34 * double(conv_length)); - // make sure the iterator is valid in any case - std::vector<double>::const_iterator pos_left = conv_chain.begin(); - if (sigma < static_cast<int>(std::distance(pos_left, pos_par))) { - pos_left = pos_par - sigma; - } - // make sure the iterator is valid in any case - std::vector<double>::const_iterator pos_right = conv_chain.end() - 1; - if (sigma < static_cast<int>(std::distance(pos_par, pos_right))) { - pos_right = pos_par + sigma; - } - API::TableRow row = wsPdfE->appendRow(); - row << fun->parameterName(j) << par_def[j] << *pos_left - *pos_par - << *pos_right - *pos_par; - - // Calculate the Probability Density Function - std::vector<double> pdf_y(pdf_length, 0); - double start = conv_chain[0]; - double bin = (conv_chain[conv_length - 1] - start) / pdf_length; - size_t step = 0; - MantidVec &X = ws->dataX(j); - MantidVec &Y = ws->dataY(j); - X[0] = start; - for (size_t i = 1; i < pdf_length + 1; i++) { - double bin_end = start + static_cast<double>(i) * bin; - X[i] = bin_end; - while (step < conv_length && conv_chain[step] <= bin_end) { - pdf_y[i - 1] += 1; - ++step; - } - Y[i - 1] = pdf_y[i - 1] / (double(conv_length) * bin); - } +double FABADAMinimizer::costFunctionVal() { return m_chi2; } - // Calculate the most probable value, from the PDF. - std::vector<double>::iterator pos_MP = - std::max_element(pdf_y.begin(), pdf_y.end()); - double mostP = X[pos_MP - pdf_y.begin()] + (bin / 2.0); - m_leastSquares->setParameter(j, mostP); - } +/// When the all the iterations have been done, calculate and show all the +/// results. +void FABADAMinimizer::finalize() { + // Creating the reduced chain (considering only one each "Steps between + // values" values) + size_t cl = getProperty("ChainLength"); + size_t n_steps = getProperty("StepsBetweenValues"); + size_t conv_length = size_t(double(cl) / double(n_steps)); + std::vector<std::vector<double>> red_conv_chain; + size_t nParams = m_leastSquares->nParams(); + for (size_t e = 0; e <= nParams; ++e) { + std::vector<double> v; + v.push_back(m_chain[e][m_conv_point]); + red_conv_chain.push_back(v); + } - // Set and name the two workspaces already calculated. - setProperty("OutputWorkspacePDF", ws); - setProperty("PdfError", wsPdfE); - - // Create the workspace for the complete parameters' chain (the last - // histogram is for the Chi square). - size_t chain_length = m_chain[0].size(); - API::MatrixWorkspace_sptr wsC = API::WorkspaceFactory::Instance().create( - "Workspace2D", n + 1, chain_length, chain_length); - - // Do one iteration for each parameter plus one for Chi square. - for (size_t j = 0; j < n + 1; ++j) { - MantidVec &X = wsC->dataX(j); - MantidVec &Y = wsC->dataY(j); - for (size_t k = 0; k < chain_length; ++k) { - X[k] = double(k); - Y[k] = m_chain[j][k]; - } + // Calculate the red_conv_chain for the cost fuction. + auto first = m_chain[nParams].begin() + m_conv_point; + auto last = m_chain[nParams].end(); + std::vector<double> conv_chain(first, last); + for (size_t k = 1; k < conv_length; ++k) { + red_conv_chain[nParams].push_back(conv_chain[n_steps * k]); + } + + // Calculate the position of the minimum Chi square value + auto pos_min = std::min_element(red_conv_chain[nParams].begin(), + red_conv_chain[nParams].end()); + m_chi2 = *pos_min; + + std::vector<double> par_def(nParams); + std::vector<double> error_left(nParams); + std::vector<double> error_rigth(nParams); + API::IFunction_sptr fun = m_leastSquares->getFittingFunction(); + + // Do one iteration for each parameter. + for (size_t j = 0; j < nParams; ++j) { + // Calculate the parameter value and the errors + auto first = m_chain[j].begin() + m_conv_point; + auto last = m_chain[j].end(); + std::vector<double> conv_chain(first, last); + auto &rc_chain_j = red_conv_chain[j]; + for (size_t k = 0; k < conv_length; ++k) { + rc_chain_j.push_back(conv_chain[n_steps * k]); + } + par_def[j] = rc_chain_j[pos_min - red_conv_chain[nParams].begin()]; + std::sort(rc_chain_j.begin(), rc_chain_j.end()); + auto pos_par = std::find(rc_chain_j.begin(), rc_chain_j.end(), par_def[j]); + size_t sigma = static_cast<size_t>(0.34 * double(conv_length)); + + auto pos_left = rc_chain_j.begin(); + if (sigma < static_cast<size_t>(std::distance(pos_left, pos_par))) { + pos_left = pos_par - sigma; + } + // make sure the iterator is valid in any case + auto pos_right = rc_chain_j.end() - 1; + if (sigma < static_cast<size_t>(std::distance(pos_par, pos_right))) { + pos_right = pos_par + sigma; + } + error_left[j] = *pos_left - *pos_par; + error_rigth[j] = *pos_right - *pos_par; + } + + const bool outputParametersTable = !getPropertyValue("Parameters").empty(); + + if (outputParametersTable) { + + // Create the workspace for the parameters' value and errors. + API::ITableWorkspace_sptr wsPdfE = + API::WorkspaceFactory::Instance().createTable("TableWorkspace"); + wsPdfE->addColumn("str", "Name"); + wsPdfE->addColumn("double", "Value"); + wsPdfE->addColumn("double", "Left's error"); + wsPdfE->addColumn("double", "Rigth's error"); + + for (size_t j = 0; j < nParams; ++j) { + API::TableRow row = wsPdfE->appendRow(); + row << fun->parameterName(j) << par_def[j] << error_left[j] + << error_rigth[j]; + } + // Set and name the Parameter Errors workspace. + setProperty("Parameters", wsPdfE); + } + + // Set the best parameter values + for (size_t j = 0; j < nParams; ++j) { + m_leastSquares->setParameter(j, par_def[j]); + } + + double mostPchi2; + + // Create the workspace for the Probability Density Functions + size_t pdf_length = 20; // histogram length for the PDF output workspace + API::MatrixWorkspace_sptr ws = API::WorkspaceFactory::Instance().create( + "Workspace2D", nParams + 1, pdf_length + 1, pdf_length); + + // Calculate the cost function Probability Density Function + std::sort(red_conv_chain[nParams].begin(), red_conv_chain[nParams].end()); + std::vector<double> pdf_y(pdf_length, 0); + double start = red_conv_chain[nParams][0]; + double bin = + (red_conv_chain[nParams][conv_length - 1] - start) / double(pdf_length); + size_t step = 0; + MantidVec &X = ws->dataX(nParams); + MantidVec &Y = ws->dataY(nParams); + X[0] = start; + for (size_t i = 1; i < pdf_length + 1; i++) { + double bin_end = start + double(i) * bin; + X[i] = bin_end; + while (step < conv_length && red_conv_chain[nParams][step] <= bin_end) { + pdf_y[i - 1] += 1; + ++step; + } + Y[i - 1] = pdf_y[i - 1] / (double(conv_length) * bin); + } + + std::vector<double>::iterator pos_MPchi2 = + std::max_element(pdf_y.begin(), pdf_y.end()); + + if (pos_MPchi2 - pdf_y.begin() == 0) { + // mostPchi2 = X[pos_MPchi2-pdf_y.begin()]; + mostPchi2 = *pos_min; + } else { + mostPchi2 = X[pos_MPchi2 - pdf_y.begin()] + (bin / 2.0); + } + + // Do one iteration for each parameter. + for (size_t j = 0; j < nParams; ++j) { + // Calculate the Probability Density Function + std::vector<double> pdf_y(pdf_length, 0); + double start = red_conv_chain[j][0]; + double bin = + (red_conv_chain[j][conv_length - 1] - start) / double(pdf_length); + size_t step = 0; + MantidVec &X = ws->dataX(j); + MantidVec &Y = ws->dataY(j); + X[0] = start; + for (size_t i = 1; i < pdf_length + 1; i++) { + double bin_end = start + double(i) * bin; + X[i] = bin_end; + while (step < conv_length && red_conv_chain[j][step] <= bin_end) { + pdf_y[i - 1] += 1; + ++step; } + Y[i - 1] = pdf_y[i - 1] / (double(conv_length) * bin); + } - // Set and name the workspace for the complete chain - setProperty("OutputWorkspaceChain", wsC); - - // Read if necessary to show the workspace for the converged part of the - // chain. - const bool con = !getPropertyValue("OutputWorkspaceConverged").empty(); - - if (con) { - // Create the workspace for the converged part of the chain. - size_t conv_length = (m_counter - 1) * n + m; - API::MatrixWorkspace_sptr wsConv = - API::WorkspaceFactory::Instance().create("Workspace2D", n + 1, - conv_length, conv_length); - - // Do one iteration for each parameter plus one for Chi square. - for (size_t j = 0; j < n + 1; ++j) { - std::vector<double>::const_iterator first = - m_chain[j].begin() + m_conv_point; - std::vector<double>::const_iterator last = m_chain[j].end(); - std::vector<double> conv_chain(first, last); - MantidVec &X = wsConv->dataX(j); - MantidVec &Y = wsConv->dataY(j); - for (size_t k = 0; k < conv_length; ++k) { - X[k] = double(k); - Y[k] = conv_chain[k]; - } - } + // Calculate the most probable value, from the PDF. + std::vector<double>::iterator pos_MP = + std::max_element(pdf_y.begin(), pdf_y.end()); + double mostP = X[pos_MP - pdf_y.begin()] + (bin / 2.0); + m_leastSquares->setParameter(j, mostP); + } + + // Set and name the PDF workspace. + setProperty("PDF", ws); - // Set and name the workspace for the converged part of the chain. - setProperty("OutputWorkspaceConverged", wsConv); + const bool outputChains = !getPropertyValue("Chains").empty(); + + if (outputChains) { + + // Create the workspace for the complete parameters' chain (the last + // histogram is for the Chi square). + size_t chain_length = m_chain[0].size(); + API::MatrixWorkspace_sptr wsC = API::WorkspaceFactory::Instance().create( + "Workspace2D", nParams + 1, chain_length, chain_length); + + // Do one iteration for each parameter plus one for Chi square. + for (size_t j = 0; j < nParams + 1; ++j) { + MantidVec &X = wsC->dataX(j); + MantidVec &Y = wsC->dataY(j); + for (size_t k = 0; k < chain_length; ++k) { + X[k] = double(k); + Y[k] = m_chain[j][k]; } + } - // Create the workspace for the Chi square values. - API::ITableWorkspace_sptr wsChi2 = - API::WorkspaceFactory::Instance().createTable("TableWorkspace"); - wsChi2->addColumn("double", "Chi2min"); - wsChi2->addColumn("double", "Chi2MP"); - wsChi2->addColumn("double", "Chi2min_red"); - wsChi2->addColumn("double", "Chi2MP_red"); - - // Calculate de Chi square most probable. - double Chi2MP = m_leastSquares->val(); - - // Reset the best parameter values ---> Si al final no se muestra la tabla - // que sale por defecto, esto se podra borrar... - for (size_t j = 0; j < n; ++j) { - m_leastSquares->setParameter(j, par_def[j]); + // Set and name the workspace for the complete chain + setProperty("Chains", wsC); + } + + // Read if necessary to show the workspace for the converged part of the + // chain. + const bool outputConvergedChains = !getPropertyValue("ConvergedChain").empty(); + + if (outputConvergedChains) { + // Create the workspace for the converged part of the chain. + API::MatrixWorkspace_sptr wsConv = API::WorkspaceFactory::Instance().create( + "Workspace2D", nParams + 1, conv_length, conv_length); + + // Do one iteration for each parameter plus one for Chi square. + for (size_t j = 0; j < nParams + 1; ++j) { + std::vector<double>::const_iterator first = + m_chain[j].begin() + m_conv_point; + std::vector<double>::const_iterator last = m_chain[j].end(); + std::vector<double> conv_chain(first, last); + MantidVec &X = wsConv->dataX(j); + MantidVec &Y = wsConv->dataY(j); + for (size_t k = 0; k < conv_length; ++k) { + X[k] = double(k); + Y[k] = conv_chain[n_steps * k]; } + } - // Obtain the quantity of the initial data. - API::FunctionDomain_sptr domain = m_leastSquares->getDomain(); - size_t data_number = domain->size(); + // Set and name the workspace for the converged part of the chain. + setProperty("ConvergedChain", wsConv); + } - // Calculate the value for the reduced Chi square. - double Chi2min_red = - *pos_min / (double(data_number - n)); // For de minimum value. - double Chi2MP_red = - Chi2MP / (double(data_number - n)); // For the most probable. + // Read if necessary to show the workspace for the Chi square values. + const bool outputCostFunctionTable = !getPropertyValue("CostFunctionTable").empty(); - // Add the information to the workspace and name it. - API::TableRow row = wsChi2->appendRow(); - row << *pos_min << Chi2MP << Chi2min_red << Chi2MP_red; - setProperty("ChiSquareTable", wsChi2); + if (outputCostFunctionTable) { - return false; - } + // Create the workspace for the Chi square values. + API::ITableWorkspace_sptr wsChi2 = + API::WorkspaceFactory::Instance().createTable("TableWorkspace"); + wsChi2->addColumn("double", "Chi2min"); + wsChi2->addColumn("double", "Chi2MP"); + wsChi2->addColumn("double", "Chi2min_red"); + wsChi2->addColumn("double", "Chi2MP_red"); + + // Obtain the quantity of the initial data. + API::FunctionDomain_sptr domain = m_leastSquares->getDomain(); + size_t data_number = domain->size(); + + // Calculate the value for the reduced Chi square. + double Chi2min_red = + m_chi2 / (double(data_number - nParams)); // For de minimum value. + double mostPchi2_red = mostPchi2 / (double(data_number - nParams)); + + // Add the information to the workspace and name it. + API::TableRow row = wsChi2->appendRow(); + row << m_chi2 << mostPchi2 << Chi2min_red << mostPchi2_red; + setProperty("CostFunctionTable", wsChi2); } - return true; + // Set the best parameter values + for (size_t j = 0; j < nParams; ++j) { + m_leastSquares->setParameter(j, par_def[j]); + } } -double FABADAMinimizer::costFunctionVal() { return m_chi2; } } // namespace CurveFitting } // namespace Mantid diff --git a/Code/Mantid/Framework/CurveFitting/src/Fit.cpp b/Code/Mantid/Framework/CurveFitting/src/Fit.cpp index b0e1c9b99b332dfb5a691440a0984ed531e29c7f..691c124409b3ae99a5e9cba7499b0da0d525bcd7 100644 --- a/Code/Mantid/Framework/CurveFitting/src/Fit.cpp +++ b/Code/Mantid/Framework/CurveFitting/src/Fit.cpp @@ -445,6 +445,8 @@ void Fit::exec() { } g_log.debug() << "Number of minimizer iterations=" << iter << "\n"; + minimizer->finalize(); + if (iter >= maxIterations) { if (!errorString.empty()) { errorString += '\n'; diff --git a/Code/Mantid/Framework/CurveFitting/test/DynamicKuboToyabeTest.h b/Code/Mantid/Framework/CurveFitting/test/DynamicKuboToyabeTest.h index 74e8717d9fb958a023358c7834ef69926c86ead9..c3a78ecebf900dc31d7ac149254887cc0e358f18 100644 --- a/Code/Mantid/Framework/CurveFitting/test/DynamicKuboToyabeTest.h +++ b/Code/Mantid/Framework/CurveFitting/test/DynamicKuboToyabeTest.h @@ -79,7 +79,7 @@ public: TS_ASSERT_DELTA( y[4], 0.323394, 0.000001); } - void xtestZNDKTFunction() + void testZNDKTFunction() { // Test Dynamic Kubo Toyabe (DKT) for non-zero Field and Zero Nu (ZN) const double asym = 1.0; @@ -107,7 +107,7 @@ public: TS_ASSERT_DELTA( y[4], 0.055052, 0.000001); } - void xtestDKTFunction() + void testDKTFunction() { // Test Dynamic Kubo Toyabe (DKT) (non-zero Field, non-zero Nu) const double asym = 1.0; @@ -129,10 +129,10 @@ public: TS_ASSERT_THROWS_NOTHING(dkt.function(x,y)); TS_ASSERT_DELTA( y[0], 1.000000, 0.000001); - TS_ASSERT_DELTA( y[1], 0.822498, 0.000001); - TS_ASSERT_DELTA( y[2], 0.518536, 0.000001); - TS_ASSERT_DELTA( y[3], 0.295988, 0.000001); - TS_ASSERT_DELTA( y[4], 0.175489, 0.000001); + TS_ASSERT_DELTA( y[1], 0.821663, 0.000001); + TS_ASSERT_DELTA( y[2], 0.518974, 0.000001); + TS_ASSERT_DELTA( y[3], 0.297548, 0.000001); + TS_ASSERT_DELTA( y[4], 0.177036, 0.000001); } diff --git a/Code/Mantid/Framework/CurveFitting/test/FABADAMinimizerTest.h b/Code/Mantid/Framework/CurveFitting/test/FABADAMinimizerTest.h index a8f1857f0f065c6b8cbb6b988828c70a02a36323..54ce15e4a07bfeecd967620864af4b4f26a2c64b 100644 --- a/Code/Mantid/Framework/CurveFitting/test/FABADAMinimizerTest.h +++ b/Code/Mantid/Framework/CurveFitting/test/FABADAMinimizerTest.h @@ -13,171 +13,166 @@ #include "MantidTestHelpers/FakeObjects.h" #include "MantidKernel/Exception.h" - using Mantid::CurveFitting::FABADAMinimizer; using namespace Mantid::API; using namespace Mantid; using namespace Mantid::CurveFitting; -class FABADAMinimizerTest : public CxxTest::TestSuite -{ +class FABADAMinimizerTest : public CxxTest::TestSuite { public: // This pair of boilerplate methods prevent the suite being created statically // This means the constructor isn't called when running other tests - static FABADAMinimizerTest *createSuite() { return new FABADAMinimizerTest(); } - static void destroySuite( FABADAMinimizerTest *suite ) { delete suite; } - + static FABADAMinimizerTest *createSuite() { + return new FABADAMinimizerTest(); + } + static void destroySuite(FABADAMinimizerTest *suite) { delete suite; } - void test_expDecay() - { - const bool histogram(false); - auto ws2 = createTestWorkspace(histogram); + void test_expDecay() { + auto ws2 = createTestWorkspace(); API::IFunction_sptr fun(new ExpDecay); - fun->setParameter("Height",8.); - fun->setParameter("Lifetime",1.0); + fun->setParameter("Height", 8.); + fun->setParameter("Lifetime", 1.0); Fit fit; fit.initialize(); fit.setRethrows(true); - fit.setProperty("Function",fun); - fit.setProperty("InputWorkspace",ws2); - fit.setProperty("WorkspaceIndex",0); - fit.setProperty("CreateOutput",true); - fit.setProperty("MaxIterations",100000); - fit.setProperty("Minimizer", "FABADA,ChainLength=5000,ConvergenceCriteria = 0.1, OutputWorkspaceConverged=conv"); + fit.setProperty("Function", fun); + fit.setProperty("InputWorkspace", ws2); + fit.setProperty("WorkspaceIndex", 0); + fit.setProperty("CreateOutput", true); + fit.setProperty("MaxIterations", 100000); + fit.setProperty("Minimizer", "FABADA,ChainLength=5000,StepsBetweenValues=" + "10,ConvergenceCriteria = 0.1"); - TS_ASSERT_THROWS_NOTHING( fit.execute() ); + TS_ASSERT_THROWS_NOTHING(fit.execute()); TS_ASSERT(fit.isExecuted()); - TS_ASSERT_DELTA( fun->getParameter("Height"), 10.0, 1e-1); - TS_ASSERT_DELTA( fun->getParameter("Lifetime"), 0.5, 1e-2); + TS_ASSERT_DELTA(fun->getParameter("Height"), 10.0, 0.7); + TS_ASSERT_DELTA(fun->getParameter("Lifetime"), 0.5, 0.1); + TS_ASSERT_DELTA(fun->getError(0), 0.7, 1e-1); + TS_ASSERT_DELTA(fun->getError(1), 0.06, 1e-2); TS_ASSERT_EQUALS(fit.getPropertyValue("OutputStatus"), "success"); - size_t n = fun -> nParams(); + size_t n = fun->nParams(); - TS_ASSERT( AnalysisDataService::Instance().doesExist("pdf") ); + TS_ASSERT(AnalysisDataService::Instance().doesExist("PDF")); MatrixWorkspace_sptr wsPDF = boost::dynamic_pointer_cast<MatrixWorkspace>( - API::AnalysisDataService::Instance().retrieve("pdf")); + API::AnalysisDataService::Instance().retrieve("PDF")); TS_ASSERT(wsPDF); - TS_ASSERT_EQUALS(wsPDF->getNumberHistograms(),n); - - const Mantid::MantidVec& X = wsPDF->dataX(0); - const Mantid::MantidVec& Y = wsPDF->dataY(0); - TS_ASSERT_EQUALS(X.size(), 51); - TS_ASSERT_EQUALS(Y.size(), 50); - - TS_ASSERT( AnalysisDataService::Instance().doesExist("chi2") ); - ITableWorkspace_sptr chi2table = boost::dynamic_pointer_cast<ITableWorkspace>( - API::AnalysisDataService::Instance().retrieve("chi2")); - - TS_ASSERT(chi2table); - TS_ASSERT_EQUALS(chi2table->columnCount(), 4); - TS_ASSERT_EQUALS(chi2table->rowCount(), 1); - TS_ASSERT_EQUALS(chi2table->getColumn(0)->type(), "double"); - TS_ASSERT_EQUALS(chi2table->getColumn(0)->name(), "Chi2min"); - TS_ASSERT_EQUALS(chi2table->getColumn(1)->type(), "double"); - TS_ASSERT_EQUALS(chi2table->getColumn(1)->name(), "Chi2MP"); - TS_ASSERT_EQUALS(chi2table->getColumn(2)->type(), "double"); - TS_ASSERT_EQUALS(chi2table->getColumn(2)->name(), "Chi2min_red"); - TS_ASSERT_EQUALS(chi2table->getColumn(3)->type(), "double"); - TS_ASSERT_EQUALS(chi2table->getColumn(3)->name(), "Chi2MP_red"); - TS_ASSERT(chi2table->Double(0,0) <= chi2table->Double(0,1)); - TS_ASSERT(chi2table->Double(0,2) <= chi2table->Double(0,3)); - TS_ASSERT_DELTA(chi2table->Double(0,0), chi2table->Double(0,1), 1); - TS_ASSERT_DELTA(chi2table->Double(0,0), 0.0, 1.0); - - TS_ASSERT( AnalysisDataService::Instance().doesExist("conv") ); + TS_ASSERT_EQUALS(wsPDF->getNumberHistograms(), n + 1); + + const Mantid::MantidVec &X = wsPDF->dataX(0); + const Mantid::MantidVec &Y = wsPDF->dataY(0); + TS_ASSERT_EQUALS(X.size(), 21); + TS_ASSERT_EQUALS(Y.size(), 20); + + TS_ASSERT(AnalysisDataService::Instance().doesExist("CostFunction")); + ITableWorkspace_sptr CostFunctionTable = + boost::dynamic_pointer_cast<ITableWorkspace>( + API::AnalysisDataService::Instance().retrieve("CostFunction")); + + TS_ASSERT(CostFunctionTable); + TS_ASSERT_EQUALS(CostFunctionTable->columnCount(), 4); + TS_ASSERT_EQUALS(CostFunctionTable->rowCount(), 1); + TS_ASSERT_EQUALS(CostFunctionTable->getColumn(0)->type(), "double"); + TS_ASSERT_EQUALS(CostFunctionTable->getColumn(0)->name(), "Chi2min"); + TS_ASSERT_EQUALS(CostFunctionTable->getColumn(1)->type(), "double"); + TS_ASSERT_EQUALS(CostFunctionTable->getColumn(1)->name(), "Chi2MP"); + TS_ASSERT_EQUALS(CostFunctionTable->getColumn(2)->type(), "double"); + TS_ASSERT_EQUALS(CostFunctionTable->getColumn(2)->name(), "Chi2min_red"); + TS_ASSERT_EQUALS(CostFunctionTable->getColumn(3)->type(), "double"); + TS_ASSERT_EQUALS(CostFunctionTable->getColumn(3)->name(), "Chi2MP_red"); + TS_ASSERT(CostFunctionTable->Double(0, 0) <= + CostFunctionTable->Double(0, 1)); + TS_ASSERT(CostFunctionTable->Double(0, 2) <= + CostFunctionTable->Double(0, 3)); + //TS_ASSERT_DELTA(CostFunctionTable->Double(0, 0), + // CostFunctionTable->Double(0, 1), 1.5); + TS_ASSERT_DELTA(CostFunctionTable->Double(0, 0), 0.0, 1.0); + + TS_ASSERT(AnalysisDataService::Instance().doesExist("ConvergedChain")); MatrixWorkspace_sptr wsConv = boost::dynamic_pointer_cast<MatrixWorkspace>( - API::AnalysisDataService::Instance().retrieve("conv")); + API::AnalysisDataService::Instance().retrieve("ConvergedChain")); TS_ASSERT(wsConv); - TS_ASSERT_EQUALS(wsConv->getNumberHistograms(),n+1); + TS_ASSERT_EQUALS(wsConv->getNumberHistograms(), n + 1); - const Mantid::MantidVec& Xconv = wsConv->dataX(0); - TS_ASSERT_EQUALS(Xconv.size(), 5000); - TS_ASSERT_EQUALS(Xconv[2437], 2437); + const Mantid::MantidVec &Xconv = wsConv->dataX(0); + TS_ASSERT_EQUALS(Xconv.size(), 500); + TS_ASSERT_EQUALS(Xconv[437], 437); - TS_ASSERT( AnalysisDataService::Instance().doesExist("chain") ); + TS_ASSERT(AnalysisDataService::Instance().doesExist("chain")); MatrixWorkspace_sptr wsChain = boost::dynamic_pointer_cast<MatrixWorkspace>( - API::AnalysisDataService::Instance().retrieve("chain")); + API::AnalysisDataService::Instance().retrieve("chain")); TS_ASSERT(wsChain); - TS_ASSERT_EQUALS(wsChain->getNumberHistograms(),n+1); + TS_ASSERT_EQUALS(wsChain->getNumberHistograms(), n + 1); - const Mantid::MantidVec& Xchain = wsChain->dataX(0); - TS_ASSERT_EQUALS(Xchain.size(), 6881); + const Mantid::MantidVec &Xchain = wsChain->dataX(0); TS_ASSERT_EQUALS(Xchain[5000], 5000); TS_ASSERT(Xconv.size() < Xchain.size()); - TS_ASSERT( AnalysisDataService::Instance().doesExist("pdfE") ); - ITableWorkspace_sptr Etable = boost::dynamic_pointer_cast<ITableWorkspace>( - API::AnalysisDataService::Instance().retrieve("pdfE")); - - TS_ASSERT(Etable); - TS_ASSERT_EQUALS(Etable->columnCount(), 4); - TS_ASSERT_EQUALS(Etable->rowCount(), n); - TS_ASSERT_EQUALS(Etable->getColumn(0)->type(), "str"); - TS_ASSERT_EQUALS(Etable->getColumn(0)->name(), "Name"); - TS_ASSERT_EQUALS(Etable->getColumn(1)->type(), "double"); - TS_ASSERT_EQUALS(Etable->getColumn(1)->name(), "Value"); - TS_ASSERT_EQUALS(Etable->getColumn(2)->type(), "double"); - TS_ASSERT_EQUALS(Etable->getColumn(2)->name(), "Left's error"); - TS_ASSERT_EQUALS(Etable->getColumn(3)->type(), "double"); - TS_ASSERT_EQUALS(Etable->getColumn(3)->name(), "Rigth's error"); - TS_ASSERT(Etable->Double(0,1) == fun->getParameter("Height")); - TS_ASSERT(Etable->Double(1,1) == fun->getParameter("Lifetime")); - + TS_ASSERT(AnalysisDataService::Instance().doesExist("Parameters")); + ITableWorkspace_sptr Ptable = boost::dynamic_pointer_cast<ITableWorkspace>( + API::AnalysisDataService::Instance().retrieve("Parameters")); + + TS_ASSERT(Ptable); + TS_ASSERT_EQUALS(Ptable->columnCount(), 4); + TS_ASSERT_EQUALS(Ptable->rowCount(), n); + TS_ASSERT_EQUALS(Ptable->getColumn(0)->type(), "str"); + TS_ASSERT_EQUALS(Ptable->getColumn(0)->name(), "Name"); + TS_ASSERT_EQUALS(Ptable->getColumn(1)->type(), "double"); + TS_ASSERT_EQUALS(Ptable->getColumn(1)->name(), "Value"); + TS_ASSERT_EQUALS(Ptable->getColumn(2)->type(), "double"); + TS_ASSERT_EQUALS(Ptable->getColumn(2)->name(), "Left's error"); + TS_ASSERT_EQUALS(Ptable->getColumn(3)->type(), "double"); + TS_ASSERT_EQUALS(Ptable->getColumn(3)->name(), "Rigth's error"); + TS_ASSERT(Ptable->Double(0, 1) == fun->getParameter("Height")); + TS_ASSERT(Ptable->Double(1, 1) == fun->getParameter("Lifetime")); } - void test_low_MaxIterations() - { - const bool histogram(false); - auto ws2 = createTestWorkspace(histogram); + void test_low_MaxIterations() { + auto ws2 = createTestWorkspace(); API::IFunction_sptr fun(new ExpDecay); - fun->setParameter("Height",1.); - fun->setParameter("Lifetime",1.0); + fun->setParameter("Height", 1.); + fun->setParameter("Lifetime", 1.0); Fit fit; fit.initialize(); fit.setRethrows(true); - fit.setProperty("Function",fun); - fit.setProperty("InputWorkspace",ws2); - fit.setProperty("WorkspaceIndex",0); - fit.setProperty("CreateOutput",true); - fit.setProperty("MaxIterations",10); - fit.setProperty("Minimizer", "FABADA,ChainLength=5000,ConvergenceCriteria = 0.01, OutputWorkspaceConverged=conv"); - - TS_ASSERT_THROWS( fit.execute(), std::runtime_error ); + fit.setProperty("Function", fun); + fit.setProperty("InputWorkspace", ws2); + fit.setProperty("WorkspaceIndex", 0); + fit.setProperty("CreateOutput", true); + fit.setProperty("MaxIterations", 10); + fit.setProperty("Minimizer", "FABADA,ChainLength=5000,StepsBetweenValues=" + "10,ConvergenceCriteria = 0.01"); - TS_ASSERT( !fit.isExecuted() ); + TS_ASSERT_THROWS(fit.execute(), std::runtime_error); + TS_ASSERT(!fit.isExecuted()); } -private: - API::MatrixWorkspace_sptr createTestWorkspace(const bool histogram) - { +private: + API::MatrixWorkspace_sptr createTestWorkspace() { MatrixWorkspace_sptr ws2(new WorkspaceTester); - ws2->initialize(2,20,20); - - for(size_t is = 0; is < ws2->getNumberHistograms(); ++is) - { - Mantid::MantidVec& x = ws2->dataX(is); - Mantid::MantidVec& y = ws2->dataY(is); - for(size_t i = 0; i < ws2->blocksize(); ++i) - { + ws2->initialize(2, 20, 20); + + for (size_t is = 0; is < ws2->getNumberHistograms(); ++is) { + Mantid::MantidVec &x = ws2->dataX(is); + Mantid::MantidVec &y = ws2->dataY(is); + for (size_t i = 0; i < ws2->blocksize(); ++i) { x[i] = 0.1 * double(i); - y[i] = (10.0 + double(is)) * exp( -(x[i])/ (0.5*(1 + double(is))) ); + y[i] = (10.0 + double(is)) * exp(-(x[i]) / (0.5 * (1 + double(is)))); } - if(histogram) x.back() = x[x.size()-2] + 0.1; } return ws2; } }; - #endif /* MANTID_CURVEFITTING_FABADAMINIMIZERTEST_H_ */ diff --git a/Code/Mantid/Framework/CurveFitting/test/FunctionParameterDecoratorFitTest.h b/Code/Mantid/Framework/CurveFitting/test/FunctionParameterDecoratorFitTest.h index 592a90b7305f9750e589643424ec4c61582cdb30..c7f60ebf936da427adc02bfe5a1b4a01c6b27288 100644 --- a/Code/Mantid/Framework/CurveFitting/test/FunctionParameterDecoratorFitTest.h +++ b/Code/Mantid/Framework/CurveFitting/test/FunctionParameterDecoratorFitTest.h @@ -70,7 +70,7 @@ public: void testFit() { Workspace2D_sptr ws = - WorkspaceCreationHelper::Create1DWorkspaceConstant(20, 1.5, 1.5); + WorkspaceCreationHelper::Create1DWorkspaceConstant(20, 1.5, 0.5); FunctionParameterDecorator_sptr fn = boost::make_shared<SimpleFunctionParameterDecorator>(); diff --git a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/LoadISISNexus2.h b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/LoadISISNexus2.h index 144387c539a9e2da30873bee5def332ee4e08e96..d36c8c4739622875c8e999bdaec1fe98471089bc 100644 --- a/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/LoadISISNexus2.h +++ b/Code/Mantid/Framework/DataHandling/inc/MantidDataHandling/LoadISISNexus2.h @@ -159,7 +159,8 @@ private: Mantid::NeXus::NXEntry &entry); // Load a given period into the workspace void loadPeriodData(int64_t period, Mantid::NeXus::NXEntry &entry, - DataObjects::Workspace2D_sptr &local_workspace); + DataObjects::Workspace2D_sptr &local_workspace, + bool update_spectra2det_mapping=false); // Load a data block void loadBlock(Mantid::NeXus::NXDataSetTyped<int> &data, int64_t blocksize, int64_t period, int64_t start, int64_t &hist, diff --git a/Code/Mantid/Framework/DataHandling/src/LoadFITS.cpp b/Code/Mantid/Framework/DataHandling/src/LoadFITS.cpp index 86df82bf489cd2146239c8de976e4e2a4c9d3377..c147984dc309b96d04e74125cca22c1dd1bf87b3 100644 --- a/Code/Mantid/Framework/DataHandling/src/LoadFITS.cpp +++ b/Code/Mantid/Framework/DataHandling/src/LoadFITS.cpp @@ -88,9 +88,11 @@ void LoadFITS::init() { "OutputWorkspace", "", Kernel::Direction::Output)); declareProperty( - new PropertyWithValue<int>("ImageKey", -1, Kernel::Direction::Input), + new PropertyWithValue<int>("ImageKey", 0, Kernel::Direction::Input), "Image type to set these files as. 0=data image, 1=flat field, 2=open " - "field, -1=use the value from FITS header."); + "field, -1=use the value from FITS header. At present, if this is not " + "specified and an IMAGEKEY entry is not found in the FITS header, the " + "loader will show an error message and stop."); declareProperty(new PropertyWithValue<string>(BIT_DEPTH_NAME, "BITPIX", Kernel::Direction::Input), diff --git a/Code/Mantid/Framework/DataHandling/src/LoadISISNexus2.cpp b/Code/Mantid/Framework/DataHandling/src/LoadISISNexus2.cpp index 9df850ea098102b9a36a8677eb425a22aa40eb10..fddfef1e1385a8439e317da6dff4302b0a858ae6 100644 --- a/Code/Mantid/Framework/DataHandling/src/LoadISISNexus2.cpp +++ b/Code/Mantid/Framework/DataHandling/src/LoadISISNexus2.cpp @@ -232,8 +232,13 @@ void LoadISISNexus2::exec() { if (m_load_selected_spectra) m_spec2det_map = SpectrumDetectorMapping(spec(), udet(), udet.dim0()); else - local_workspace->updateSpectraUsing( + if (bseparateMonitors) { + m_spec2det_map = SpectrumDetectorMapping(spec(), udet(), udet.dim0()); + local_workspace->updateSpectraUsing(m_spec2det_map); + }else{ + local_workspace->updateSpectraUsing( SpectrumDetectorMapping(spec(), udet(), udet.dim0())); + } if (!foundInstrument) { runLoadInstrument(local_workspace); @@ -258,7 +263,7 @@ void LoadISISNexus2::exec() { m_tof_data.reset(new MantidVec(timeBins(), timeBins() + x_length)); } int64_t firstentry = (m_entrynumber > 0) ? m_entrynumber : 1; - loadPeriodData(firstentry, entry, local_workspace); + loadPeriodData(firstentry, entry, local_workspace,m_load_selected_spectra); // Clone the workspace at this point to provide a base object for future // workspace generation. @@ -284,7 +289,7 @@ void LoadISISNexus2::exec() { if (p > 1) { local_workspace = boost::dynamic_pointer_cast<DataObjects::Workspace2D>( WorkspaceFactory::Instance().create(period_free_workspace)); - loadPeriodData(p, entry, local_workspace); + loadPeriodData(p, entry, local_workspace,m_load_selected_spectra); createPeriodLogs(p, local_workspace); // Check consistency of logs data for multi-period workspaces and raise // warnings where necessary. @@ -345,7 +350,7 @@ void LoadISISNexus2::exec() { prepareSpectraBlocks(m_monitors, m_specInd2specNum_map, m_monBlockInfo); int64_t firstentry = (m_entrynumber > 0) ? m_entrynumber : 1; - loadPeriodData(firstentry, entry, monitor_workspace); + loadPeriodData(firstentry, entry, monitor_workspace,true); std::string monitorwsName = wsName + "_monitors"; declareProperty(new WorkspaceProperty<Workspace>( @@ -690,10 +695,13 @@ size_t LoadISISNexus2::prepareSpectraBlocks( * @param entry :: The opened root entry node for accessing the monitor and data * nodes * @param local_workspace :: The workspace to place the data in +* @param update_spectra_det_map :: reset spectra-detector map to the one +* calculated earlier. (Warning! -- this map has to be calculated correctly!) */ void LoadISISNexus2::loadPeriodData(int64_t period, NXEntry &entry, - DataObjects::Workspace2D_sptr &local_workspace) { + DataObjects::Workspace2D_sptr &local_workspace, + bool update_spectra2det_mapping) { int64_t hist_index = 0; int64_t period_index(period - 1); // int64_t first_monitor_spectrum = 0; @@ -710,7 +718,7 @@ LoadISISNexus2::loadPeriodData(int64_t period, NXEntry &entry, MantidVec &E = local_workspace->dataE(hist_index); std::transform(Y.begin(), Y.end(), E.begin(), dblSqrt); - if (m_load_selected_spectra) { + if (update_spectra2det_mapping) { // local_workspace->getAxis(1)->setValue(hist_index, // static_cast<specid_t>(it->first)); auto spec = local_workspace->getSpectrum(hist_index); diff --git a/Code/Mantid/Framework/DataHandling/test/LoadFullprofResolutionTest.h b/Code/Mantid/Framework/DataHandling/test/LoadFullprofResolutionTest.h index 878ab8807fecc309c1adb50c1062dad5cbca615e..b8d36d13bb2420598394a4f053662b4e913beeea 100644 --- a/Code/Mantid/Framework/DataHandling/test/LoadFullprofResolutionTest.h +++ b/Code/Mantid/Framework/DataHandling/test/LoadFullprofResolutionTest.h @@ -328,7 +328,7 @@ public: void test_workspace() { // Generate file - string filename("TestWorskpace.irf"); + string filename("FullprofResolutionTest_TestWorkspace.irf"); generate1BankIrfFile(filename); // Load workspace group wsName with one workspace @@ -412,7 +412,7 @@ public: } // Clean - Poco::File("TestWorskpace.irf").remove(); + Poco::File(filename).remove(); } //---------------------------------------------------------------------------------------------- diff --git a/Code/Mantid/Framework/DataHandling/test/LoadGSASInstrumentFileTest.h b/Code/Mantid/Framework/DataHandling/test/LoadGSASInstrumentFileTest.h index 0ae94946fa50e830bd34562a0b1203b50a0b03e0..65d102d5c492aaeff5f8d6524b98a18d7c23e500 100644 --- a/Code/Mantid/Framework/DataHandling/test/LoadGSASInstrumentFileTest.h +++ b/Code/Mantid/Framework/DataHandling/test/LoadGSASInstrumentFileTest.h @@ -208,7 +208,7 @@ public: void test_workspace() { // Generate file with two banks - string filename("TestWorskpace.irf"); + string filename("GSASInstrumentFileTest_TestWorkspace.irf"); generate2BankPrmFile(filename); // Create workspace group to put parameters into @@ -308,7 +308,7 @@ public: TS_ASSERT_EQUALS( fitParam.getValue( 0.0 ), 0.0); // Clean - Poco::File("TestWorskpace.irf").remove(); + Poco::File(filename).remove(); AnalysisDataService::Instance().remove("loadGSASInstrumentFileWorkspace"); } diff --git a/Code/Mantid/Framework/DataHandling/test/LoadISISNexusTest.h b/Code/Mantid/Framework/DataHandling/test/LoadISISNexusTest.h index 9335317a294e01f4ed22140c9937f645d32f9967..6c300c5785e0849c6931fff17419e315b69c4815 100644 --- a/Code/Mantid/Framework/DataHandling/test/LoadISISNexusTest.h +++ b/Code/Mantid/Framework/DataHandling/test/LoadISISNexusTest.h @@ -633,8 +633,40 @@ public: AnalysisDataService::Instance().remove("outWS"); } + void xestExecMonExcludedInTheEnd() + { + Mantid::API::FrameworkManager::Instance(); + LoadISISNexus2 ld; + ld.initialize(); + ld.setPropertyValue("Filename","MAPS00018314.nxs"); + ld.setPropertyValue("SpectrumMin","2"); + ld.setPropertyValue("SpectrumMax","10"); + ld.setPropertyValue("OutputWorkspace","outWS"); + ld.setPropertyValue("LoadMonitors","Separate"); // + TS_ASSERT_THROWS_NOTHING(ld.execute()); + TS_ASSERT(ld.isExecuted()); + + + MatrixWorkspace_sptr ws = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("outWS"); + TS_ASSERT_EQUALS(ws->blocksize(),2000); + TS_ASSERT_EQUALS(ws->getNumberHistograms(),9); + + MatrixWorkspace_sptr ws_mon = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("outWS_monitors"); + TS_ASSERT(ws_mon) + + TS_ASSERT_EQUALS(ws_mon->blocksize(),2000); + TS_ASSERT_EQUALS(ws_mon->getNumberHistograms(),4); + TS_ASSERT_DELTA(ws_mon->readX(0)[0],10,1.e-8); + + + TS_ASSERT_EQUALS(ws_mon->getSpectrum(0)->getSpectrumNo(),41473); + TS_ASSERT_EQUALS(ws_mon->getSpectrum(3)->getSpectrumNo(),41476); + AnalysisDataService::Instance().remove("outWS"); + AnalysisDataService::Instance().remove("outWS_monitors"); + } + }; //------------------------------------------------------------------------------ diff --git a/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Crystal/Group.h b/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Crystal/Group.h index 248dca7b95ddbed494484890ab1a289ec9eb3fe9..dba8a798bac88bbb80932ffb5edd1388f1e73432 100644 --- a/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Crystal/Group.h +++ b/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Crystal/Group.h @@ -109,6 +109,11 @@ namespace Geometry { */ class MANTID_GEOMETRY_DLL Group { public: + enum CoordinateSystem { + Orthogonal, + Hexagonal + }; + Group(); Group(const std::string &symmetryOperationString); Group(const std::vector<SymmetryOperation> &symmetryOperations); @@ -118,6 +123,7 @@ public: virtual ~Group() {} size_t order() const; + CoordinateSystem getCoordinateSystem() const; std::vector<SymmetryOperation> getSymmetryOperations() const; Group operator*(const Group &other) const; @@ -131,8 +137,12 @@ protected: void setSymmetryOperations( const std::vector<SymmetryOperation> &symmetryOperations); + CoordinateSystem getCoordinateSystemFromOperations( + const std::vector<SymmetryOperation> &symmetryOperations) const; + std::vector<SymmetryOperation> m_allOperations; std::set<SymmetryOperation> m_operationSet; + CoordinateSystem m_axisSystem; }; typedef boost::shared_ptr<Group> Group_sptr; diff --git a/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Crystal/PointGroupFactory.h b/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Crystal/PointGroupFactory.h index 29056aed36fa9283a4b2daac55eccc06fb35804d..238947b38c49fcb825ae0f1fed0c67fe2d6e0c8c 100644 --- a/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Crystal/PointGroupFactory.h +++ b/Code/Mantid/Framework/Geometry/inc/MantidGeometry/Crystal/PointGroupFactory.h @@ -4,6 +4,7 @@ #include "MantidGeometry/DllConfig.h" #include "MantidKernel/SingletonHolder.h" #include "MantidGeometry/Crystal/PointGroup.h" +#include "MantidGeometry/Crystal/SpaceGroup.h" #include "MantidKernel/RegistrationHelper.h" #include <boost/regex.hpp> @@ -81,7 +82,9 @@ class MANTID_GEOMETRY_DLL PointGroupFactoryImpl { public: PointGroup_sptr createPointGroup(const std::string &hmSymbol); PointGroup_sptr - createPointGroupFromSpaceGroupSymbol(const std::string &spaceGroupSymbol); + createPointGroupFromSpaceGroup(const SpaceGroup_const_sptr &spaceGroup); + PointGroup_sptr + createPointGroupFromSpaceGroup(const SpaceGroup &spaceGroup); bool isSubscribed(const std::string &hmSymbol) const; diff --git a/Code/Mantid/Framework/Geometry/src/Crystal/CrystalStructure.cpp b/Code/Mantid/Framework/Geometry/src/Crystal/CrystalStructure.cpp index 25e266f9ada45a8242a9eabef1f51182a0d25c60..22dd7a91ae6cef5f0a6224b938921f96634a3de3 100644 --- a/Code/Mantid/Framework/Geometry/src/Crystal/CrystalStructure.cpp +++ b/Code/Mantid/Framework/Geometry/src/Crystal/CrystalStructure.cpp @@ -247,9 +247,10 @@ void CrystalStructure::setPointGroupFromSpaceGroup( if (spaceGroup) { try { m_pointGroup = - PointGroupFactory::Instance().createPointGroupFromSpaceGroupSymbol( - spaceGroup->hmSymbol()); - } catch (...) { + PointGroupFactory::Instance().createPointGroupFromSpaceGroup( + spaceGroup); + } + catch (...) { // do nothing - point group will be null } } diff --git a/Code/Mantid/Framework/Geometry/src/Crystal/Group.cpp b/Code/Mantid/Framework/Geometry/src/Crystal/Group.cpp index f39708dfa465853c71176e6682ae496f1c2e25de..687ea943cbd1fe8f3dfa10072ee5b3060972b0f4 100644 --- a/Code/Mantid/Framework/Geometry/src/Crystal/Group.cpp +++ b/Code/Mantid/Framework/Geometry/src/Crystal/Group.cpp @@ -6,7 +6,7 @@ namespace Mantid { namespace Geometry { /// Default constructor. Creates a group with one symmetry operation (identity). -Group::Group() : m_allOperations(), m_operationSet() { +Group::Group() : m_allOperations(), m_operationSet(), m_axisSystem() { std::vector<SymmetryOperation> operation(1); setSymmetryOperations(operation); } @@ -14,7 +14,7 @@ Group::Group() : m_allOperations(), m_operationSet() { /// Uses SymmetryOperationFactory to create a vector of symmetry operations from /// the string. Group::Group(const std::string &symmetryOperationString) - : m_allOperations(), m_operationSet() { + : m_allOperations(), m_operationSet(), m_axisSystem() { setSymmetryOperations(SymmetryOperationFactory::Instance().createSymOps( symmetryOperationString)); } @@ -22,19 +22,20 @@ Group::Group(const std::string &symmetryOperationString) /// Constructs a group from the symmetry operations in the vector, duplicates /// are removed. Group::Group(const std::vector<SymmetryOperation> &symmetryOperations) - : m_allOperations(), m_operationSet() { + : m_allOperations(), m_operationSet(), m_axisSystem() { setSymmetryOperations(symmetryOperations); } /// Copy constructor. Group::Group(const Group &other) : m_allOperations(other.m_allOperations), - m_operationSet(other.m_operationSet) {} + m_operationSet(other.m_operationSet), m_axisSystem(other.m_axisSystem) {} /// Assignment operator. Group &Group::operator=(const Group &other) { m_allOperations = other.m_allOperations; m_operationSet = other.m_operationSet; + m_axisSystem = other.m_axisSystem; return *this; } @@ -42,6 +43,9 @@ Group &Group::operator=(const Group &other) { /// Returns the order of the group, which is the number of symmetry operations. size_t Group::order() const { return m_allOperations.size(); } +/// Returns the axis system of the group (either orthogonal or hexagonal). +Group::CoordinateSystem Group::getCoordinateSystem() const { return m_axisSystem; } + /// Returns a vector with all symmetry operations. std::vector<SymmetryOperation> Group::getSymmetryOperations() const { return m_allOperations; @@ -105,6 +109,22 @@ void Group::setSymmetryOperations( symmetryOperations.end()); m_allOperations = std::vector<SymmetryOperation>(m_operationSet.begin(), m_operationSet.end()); + m_axisSystem = getCoordinateSystemFromOperations(m_allOperations); +} + +/// Returns the axis system based on the given symmetry operations. Hexagonal +/// systems have 4 non-zero elements in the matrix, orthogonal have 6. +Group::CoordinateSystem Group::getCoordinateSystemFromOperations( + const std::vector<SymmetryOperation> &symmetryOperations) const { + for (auto op = symmetryOperations.begin(); op != symmetryOperations.end(); + ++op) { + std::vector<int> matrix = (*op).matrix(); + if (std::count(matrix.begin(), matrix.end(), 0) == 5) { + return Group::Hexagonal; + } + } + + return Group::Orthogonal; } /// Convenience operator* for directly multiplying groups using shared pointers. diff --git a/Code/Mantid/Framework/Geometry/src/Crystal/PointGroupFactory.cpp b/Code/Mantid/Framework/Geometry/src/Crystal/PointGroupFactory.cpp index 3d8289fdb508f3448b4ed9a8b60519dcd14cf4f1..928c3f214579a9019729ed7d488f551c5db0a14c 100644 --- a/Code/Mantid/Framework/Geometry/src/Crystal/PointGroupFactory.cpp +++ b/Code/Mantid/Framework/Geometry/src/Crystal/PointGroupFactory.cpp @@ -1,4 +1,5 @@ #include "MantidGeometry/Crystal/PointGroupFactory.h" +#include "MantidGeometry/Crystal/SpaceGroup.h" #include "MantidKernel/LibraryManager.h" #include <boost/algorithm/string.hpp> @@ -18,10 +19,35 @@ PointGroupFactoryImpl::createPointGroup(const std::string &hmSymbol) { return constructFromPrototype(getPrototype(hmSymbol)); } -PointGroup_sptr PointGroupFactoryImpl::createPointGroupFromSpaceGroupSymbol( - const std::string &spaceGroupSymbol) { - return createPointGroup( - pointGroupSymbolFromSpaceGroupSymbol(spaceGroupSymbol)); +PointGroup_sptr PointGroupFactoryImpl::createPointGroupFromSpaceGroup( + const SpaceGroup_const_sptr &spaceGroup) { + return createPointGroupFromSpaceGroup(*spaceGroup); +} + +PointGroup_sptr PointGroupFactoryImpl::createPointGroupFromSpaceGroup( + const SpaceGroup &spaceGroup) { + std::string pointGroupSymbol = + pointGroupSymbolFromSpaceGroupSymbol(spaceGroup.hmSymbol()); + + try { + PointGroup_sptr pointGroup = createPointGroup(pointGroupSymbol); + + // If the crystal system is trigonal, we need to do more. + if (pointGroup->crystalSystem() == PointGroup::Trigonal) { + throw std::invalid_argument( + "Trigonal space groups need to be processed differently."); + } + + return pointGroup; + } + catch (std::invalid_argument) { + if (spaceGroup.getCoordinateSystem() != + Group::CoordinateSystem::Hexagonal) { + pointGroupSymbol.append(" r"); + } + + return createPointGroup(pointGroupSymbol); + } } bool PointGroupFactoryImpl::isSubscribed(const std::string &hmSymbol) const { @@ -187,8 +213,8 @@ DECLARE_POINTGROUP("-42m", "y,-x,-z; x,-y,-z", "Tetragonal") DECLARE_POINTGROUP("-4m2", "y,-x,-z; y,x,-z", "Tetragonal") DECLARE_POINTGROUP("4/mmm", "-y,x,z; x,y,-z; x,-y,-z", "Tetragonal") -DECLARE_POINTGROUP("3 h", "-y,x-y,z", "Trigonal - Hexagonal") -DECLARE_POINTGROUP("-3 h", "y,y-x,-z", "Trigonal - Hexagonal") +DECLARE_POINTGROUP("3", "-y,x-y,z", "Trigonal - Hexagonal") +DECLARE_POINTGROUP("-3", "y,y-x,-z", "Trigonal - Hexagonal") DECLARE_POINTGROUP("321", "-y,x-y,z; x-y,-y,-z", "Trigonal - Hexagonal") DECLARE_POINTGROUP("312", "-y,x-y,z; x,x-y,-z", "Trigonal - Hexagonal") DECLARE_POINTGROUP("3m1", "-y,x-y,z; y-x,y,z", "Trigonal - Hexagonal") @@ -196,11 +222,11 @@ DECLARE_POINTGROUP("31m", "-y,x-y,z; -x,y-x,z", "Trigonal - Hexagonal") DECLARE_POINTGROUP("-3m1", "y,y-x,-z; x-y,-y,-z", "Trigonal - Hexagonal") DECLARE_POINTGROUP("-31m", "y,y-x,-z; x,x-y,-z", "Trigonal - Hexagonal") -DECLARE_POINTGROUP("3", "z,x,y", "Trigonal - Rhombohedral") -DECLARE_POINTGROUP("-3", "-z,-x,-y", "Trigonal - Rhombohedral") -DECLARE_POINTGROUP("32", "z,x,y; -y,-x,-z", "Trigonal - Rhombohedral") -DECLARE_POINTGROUP("3m", "z,x,y; y,x,z", "Trigonal - Rhombohedral") -DECLARE_POINTGROUP("-3m", "-z,-x,-y; y,x,z", "Trigonal - Rhombohedral") +DECLARE_POINTGROUP("3 r", "z,x,y", "Trigonal - Rhombohedral") +DECLARE_POINTGROUP("-3 r", "-z,-x,-y", "Trigonal - Rhombohedral") +DECLARE_POINTGROUP("32 r", "z,x,y; -y,-x,-z", "Trigonal - Rhombohedral") +DECLARE_POINTGROUP("3m r", "z,x,y; y,x,z", "Trigonal - Rhombohedral") +DECLARE_POINTGROUP("-3m r", "-z,-x,-y; y,x,z", "Trigonal - Rhombohedral") DECLARE_POINTGROUP("6", "x-y,x,z", "Hexagonal") DECLARE_POINTGROUP("-6", "y-x,-x,-z", "Hexagonal") @@ -211,7 +237,6 @@ DECLARE_POINTGROUP("-62m", "y-x,-x,-z; x-y,-y,-z", "Hexagonal") DECLARE_POINTGROUP("-6m2", "y-x,-x,-z; y-x,y,z", "Hexagonal") DECLARE_POINTGROUP("6/mmm", "x-y,x,z; x-y,-y,-z; -x,-y,-z", "Hexagonal") - DECLARE_POINTGROUP("23", "z,x,y; -x,-y,z; x,-y,-z", "Cubic") DECLARE_POINTGROUP("m-3", "-z,-x,-y; -x,-y,z; x,-y,-z", "Cubic") DECLARE_POINTGROUP("432", "z,x,y; -y,x,z; x,-y,-z", "Cubic") diff --git a/Code/Mantid/Framework/Geometry/test/GroupTest.h b/Code/Mantid/Framework/Geometry/test/GroupTest.h index 324ba41309a535ed242f0aa825931ea746dd7cb5..12566f10e5ee3e21cf9d665422001d9c1ecd38e4 100644 --- a/Code/Mantid/Framework/Geometry/test/GroupTest.h +++ b/Code/Mantid/Framework/Geometry/test/GroupTest.h @@ -9,195 +9,230 @@ using namespace Mantid::Geometry; -class GroupTest : public CxxTest::TestSuite -{ +class GroupTest : public CxxTest::TestSuite { public: - // This pair of boilerplate methods prevent the suite being created statically - // This means the constructor isn't called when running other tests - static GroupTest *createSuite() { return new GroupTest(); } - static void destroySuite( GroupTest *suite ) { delete suite; } - - void testDefaultConstructor() - { - Group group; - TS_ASSERT_EQUALS(group.order(), 1); - TS_ASSERT(group.getSymmetryOperations().front().isIdentity()); - } - - void testStringConstructor() - { - Group group("x,y,z; -x,-y,-z"); - - TS_ASSERT_EQUALS(group.order(), 2); - } - - void testConstructor() - { - std::vector<SymmetryOperation> symOps; - symOps.push_back(SymmetryOperationFactory::Instance().createSymOp("x,y,z")); - symOps.push_back(SymmetryOperationFactory::Instance().createSymOp("-x,-y,-z")); - - TS_ASSERT_THROWS_NOTHING(Group group(symOps)); - - Group group(symOps); - - std::vector<SymmetryOperation> groupOps = group.getSymmetryOperations(); - TS_ASSERT_EQUALS(groupOps.size(), 2); - - std::vector<SymmetryOperation> empty; - TS_ASSERT_THROWS(Group group(empty), std::invalid_argument); - } - - void testCopyConstructor() - { - std::vector<SymmetryOperation> symOps; - symOps.push_back(SymmetryOperationFactory::Instance().createSymOp("x,y,z")); - symOps.push_back(SymmetryOperationFactory::Instance().createSymOp("-x,-y,-z")); - - Group group(symOps); - Group otherGroup(group); - - TS_ASSERT_EQUALS(group.order(), otherGroup.order()); - TS_ASSERT_EQUALS(group.getSymmetryOperations(), otherGroup.getSymmetryOperations()); - } - - void testAssignmentOperator() - { - std::vector<SymmetryOperation> symOps; - symOps.push_back(SymmetryOperationFactory::Instance().createSymOp("x,y,z")); - symOps.push_back(SymmetryOperationFactory::Instance().createSymOp("-x,-y,-z")); - - Group otherGroup(symOps); - - Group group; - TS_ASSERT_DIFFERS(group.order(), otherGroup.order()); - TS_ASSERT_DIFFERS(group.getSymmetryOperations(), otherGroup.getSymmetryOperations()); - - group = otherGroup; - TS_ASSERT_EQUALS(group.order(), otherGroup.order()); - TS_ASSERT_EQUALS(group.getSymmetryOperations(), otherGroup.getSymmetryOperations()); - } - - void testOrder() - { - Group defaultGroup; - TS_ASSERT_EQUALS(defaultGroup.order(), 1); - - // Making a group of two operations gives order 2 - std::vector<SymmetryOperation> symOps; - symOps.push_back(SymmetryOperationFactory::Instance().createSymOp("x,y,z")); - symOps.push_back(SymmetryOperationFactory::Instance().createSymOp("-x,-y,-z")); - - Group biggerGroup(symOps); - TS_ASSERT_EQUALS(biggerGroup.order(), 2); - - // Adding another one results in 3 - symOps.push_back(SymmetryOperationFactory::Instance().createSymOp("-x,y,z")); - Group evenBiggerGroup(symOps); - TS_ASSERT_EQUALS(evenBiggerGroup.order(), 3); - - // Multiple occurences of the same operation do not count - symOps.push_back(SymmetryOperationFactory::Instance().createSymOp("-x,-y,-z")); - Group sameAsBefore(symOps); - TS_ASSERT_EQUALS(sameAsBefore.order(), 3); - } - - void testComparison() - { - std::vector<SymmetryOperation> symOps; - symOps.push_back(SymmetryOperationFactory::Instance().createSymOp("x,y,z")); - symOps.push_back(SymmetryOperationFactory::Instance().createSymOp("-x,-y,-z")); - - Group groupOne(symOps); - Group groupTwo(symOps); - - TS_ASSERT(groupOne == groupTwo); - TS_ASSERT(groupTwo == groupOne); - - Group defaultGroup; - TS_ASSERT(!(groupOne == defaultGroup)); - TS_ASSERT(!(defaultGroup == groupOne)); - TS_ASSERT(groupOne != defaultGroup); - TS_ASSERT(defaultGroup != groupOne); - } - - void testMultiplicationOperator() - { - // We take pointgroup -1 - std::vector<SymmetryOperation> inversion; - inversion.push_back(SymmetryOperationFactory::Instance().createSymOp("x,y,z")); - inversion.push_back(SymmetryOperationFactory::Instance().createSymOp("-x,-y,-z")); - - // And 2 (b-axis unique) - std::vector<SymmetryOperation> twoFoldY; - twoFoldY.push_back(SymmetryOperationFactory::Instance().createSymOp("x,y,z")); - twoFoldY.push_back(SymmetryOperationFactory::Instance().createSymOp("-x,y,-z")); - - Group one(inversion); - Group two(twoFoldY); - - // Multiplication results in 2/m - Group three = one * two; - TS_ASSERT_EQUALS(three.order(), 4); - - // The multiplication created m perpendicular to b (x,-y,-z) - SymmetryOperation mirrorY = SymmetryOperationFactory::Instance().createSymOp("x,-y,z"); - std::vector<SymmetryOperation> opsOfThree = three.getSymmetryOperations(); - - // Check that it is found in the list of symmetry operations of the new group - TS_ASSERT_DIFFERS(std::find(opsOfThree.begin(), opsOfThree.end(), mirrorY), opsOfThree.end()); - - Group four = two * one; - TS_ASSERT(three == four); - } - - void testSmartPointerOperators() - { - // We take pointgroup -1 - std::vector<SymmetryOperation> inversion; - inversion.push_back(SymmetryOperationFactory::Instance().createSymOp("x,y,z")); - inversion.push_back(SymmetryOperationFactory::Instance().createSymOp("-x,-y,-z")); - - // And 2 (b-axis unique) - std::vector<SymmetryOperation> twoFoldY; - twoFoldY.push_back(SymmetryOperationFactory::Instance().createSymOp("x,y,z")); - twoFoldY.push_back(SymmetryOperationFactory::Instance().createSymOp("-x,y,-z")); - - Group_const_sptr one = boost::make_shared<const Group>(inversion); - Group_const_sptr two = boost::make_shared<const Group>(twoFoldY); - - Group_const_sptr three = one * two; - TS_ASSERT_EQUALS(three->order(), 4); - - SymmetryOperation mirrorY = SymmetryOperationFactory::Instance().createSymOp("x,-y,z"); - std::vector<SymmetryOperation> opsOfThree = three->getSymmetryOperations(); - - // Check that it is found in the list of symmetry operations of the new group - TS_ASSERT_DIFFERS(std::find(opsOfThree.begin(), opsOfThree.end(), mirrorY), opsOfThree.end()); - - // Make sure that null-pointer do not work - Group_const_sptr null; - - TS_ASSERT_THROWS(null * null, std::invalid_argument); - //AppleClang gives a warning if we don't use the result + // This pair of boilerplate methods prevent the suite being created statically + // This means the constructor isn't called when running other tests + static GroupTest *createSuite() { return new GroupTest(); } + static void destroySuite(GroupTest *suite) { delete suite; } + + void testDefaultConstructor() { + Group group; + TS_ASSERT_EQUALS(group.order(), 1); + TS_ASSERT(group.getSymmetryOperations().front().isIdentity()); + } + + void testStringConstructor() { + Group group("x,y,z; -x,-y,-z"); + + TS_ASSERT_EQUALS(group.order(), 2); + } + + void testConstructor() { + std::vector<SymmetryOperation> symOps; + symOps.push_back(SymmetryOperationFactory::Instance().createSymOp("x,y,z")); + symOps.push_back( + SymmetryOperationFactory::Instance().createSymOp("-x,-y,-z")); + + TS_ASSERT_THROWS_NOTHING(Group group(symOps)); + + Group group(symOps); + + std::vector<SymmetryOperation> groupOps = group.getSymmetryOperations(); + TS_ASSERT_EQUALS(groupOps.size(), 2); + + std::vector<SymmetryOperation> empty; + TS_ASSERT_THROWS(Group group(empty), std::invalid_argument); + } + + void testCopyConstructor() { + std::vector<SymmetryOperation> symOps; + symOps.push_back(SymmetryOperationFactory::Instance().createSymOp("x,y,z")); + symOps.push_back( + SymmetryOperationFactory::Instance().createSymOp("-x,-y,-z")); + + Group group(symOps); + Group otherGroup(group); + + TS_ASSERT_EQUALS(group.order(), otherGroup.order()); + TS_ASSERT_EQUALS(group.getSymmetryOperations(), + otherGroup.getSymmetryOperations()); + } + + void testAssignmentOperator() { + std::vector<SymmetryOperation> symOps; + symOps.push_back(SymmetryOperationFactory::Instance().createSymOp("x,y,z")); + symOps.push_back( + SymmetryOperationFactory::Instance().createSymOp("-x,-y,-z")); + + Group otherGroup(symOps); + + Group group; + TS_ASSERT_DIFFERS(group.order(), otherGroup.order()); + TS_ASSERT_DIFFERS(group.getSymmetryOperations(), + otherGroup.getSymmetryOperations()); + + group = otherGroup; + TS_ASSERT_EQUALS(group.order(), otherGroup.order()); + TS_ASSERT_EQUALS(group.getSymmetryOperations(), + otherGroup.getSymmetryOperations()); + } + + void testOrder() { + Group defaultGroup; + TS_ASSERT_EQUALS(defaultGroup.order(), 1); + + // Making a group of two operations gives order 2 + std::vector<SymmetryOperation> symOps; + symOps.push_back(SymmetryOperationFactory::Instance().createSymOp("x,y,z")); + symOps.push_back( + SymmetryOperationFactory::Instance().createSymOp("-x,-y,-z")); + + Group biggerGroup(symOps); + TS_ASSERT_EQUALS(biggerGroup.order(), 2); + + // Adding another one results in 3 + symOps.push_back( + SymmetryOperationFactory::Instance().createSymOp("-x,y,z")); + Group evenBiggerGroup(symOps); + TS_ASSERT_EQUALS(evenBiggerGroup.order(), 3); + + // Multiple occurences of the same operation do not count + symOps.push_back( + SymmetryOperationFactory::Instance().createSymOp("-x,-y,-z")); + Group sameAsBefore(symOps); + TS_ASSERT_EQUALS(sameAsBefore.order(), 3); + } + + void testComparison() { + std::vector<SymmetryOperation> symOps; + symOps.push_back(SymmetryOperationFactory::Instance().createSymOp("x,y,z")); + symOps.push_back( + SymmetryOperationFactory::Instance().createSymOp("-x,-y,-z")); + + Group groupOne(symOps); + Group groupTwo(symOps); + + TS_ASSERT(groupOne == groupTwo); + TS_ASSERT(groupTwo == groupOne); + + Group defaultGroup; + TS_ASSERT(!(groupOne == defaultGroup)); + TS_ASSERT(!(defaultGroup == groupOne)); + TS_ASSERT(groupOne != defaultGroup); + TS_ASSERT(defaultGroup != groupOne); + } + + void testMultiplicationOperator() { + // We take pointgroup -1 + std::vector<SymmetryOperation> inversion; + inversion.push_back( + SymmetryOperationFactory::Instance().createSymOp("x,y,z")); + inversion.push_back( + SymmetryOperationFactory::Instance().createSymOp("-x,-y,-z")); + + // And 2 (b-axis unique) + std::vector<SymmetryOperation> twoFoldY; + twoFoldY.push_back( + SymmetryOperationFactory::Instance().createSymOp("x,y,z")); + twoFoldY.push_back( + SymmetryOperationFactory::Instance().createSymOp("-x,y,-z")); + + Group one(inversion); + Group two(twoFoldY); + + // Multiplication results in 2/m + Group three = one * two; + TS_ASSERT_EQUALS(three.order(), 4); + + // The multiplication created m perpendicular to b (x,-y,-z) + SymmetryOperation mirrorY = + SymmetryOperationFactory::Instance().createSymOp("x,-y,z"); + std::vector<SymmetryOperation> opsOfThree = three.getSymmetryOperations(); + + // Check that it is found in the list of symmetry operations of the new + // group + TS_ASSERT_DIFFERS(std::find(opsOfThree.begin(), opsOfThree.end(), mirrorY), + opsOfThree.end()); + + Group four = two * one; + TS_ASSERT(three == four); + } + + void testAxisSystemOrthogonal() { + std::vector<SymmetryOperation> orthogonal; + orthogonal.push_back( + SymmetryOperationFactory::Instance().createSymOp("x,y,z")); + orthogonal.push_back( + SymmetryOperationFactory::Instance().createSymOp("-x,y,-z")); + + Group two(orthogonal); + + TS_ASSERT_EQUALS(two.getCoordinateSystem(), Group::Orthogonal); + } + + void testAxisSystemHexagonal() { + std::vector<SymmetryOperation> hexagonal; + hexagonal.push_back( + SymmetryOperationFactory::Instance().createSymOp("-y,x-y,z")); + hexagonal.push_back( + SymmetryOperationFactory::Instance().createSymOp("y,x,-z+1/2")); + + Group two(hexagonal); + + TS_ASSERT_EQUALS(two.getCoordinateSystem(), Group::Hexagonal); + } + + void testSmartPointerOperators() { + // We take pointgroup -1 + std::vector<SymmetryOperation> inversion; + inversion.push_back( + SymmetryOperationFactory::Instance().createSymOp("x,y,z")); + inversion.push_back( + SymmetryOperationFactory::Instance().createSymOp("-x,-y,-z")); + + // And 2 (b-axis unique) + std::vector<SymmetryOperation> twoFoldY; + twoFoldY.push_back( + SymmetryOperationFactory::Instance().createSymOp("x,y,z")); + twoFoldY.push_back( + SymmetryOperationFactory::Instance().createSymOp("-x,y,-z")); + + Group_const_sptr one = boost::make_shared<const Group>(inversion); + Group_const_sptr two = boost::make_shared<const Group>(twoFoldY); + + Group_const_sptr three = one * two; + TS_ASSERT_EQUALS(three->order(), 4); + + SymmetryOperation mirrorY = + SymmetryOperationFactory::Instance().createSymOp("x,-y,z"); + std::vector<SymmetryOperation> opsOfThree = three->getSymmetryOperations(); + + // Check that it is found in the list of symmetry operations of the new + // group + TS_ASSERT_DIFFERS(std::find(opsOfThree.begin(), opsOfThree.end(), mirrorY), + opsOfThree.end()); + + // Make sure that null-pointer do not work + Group_const_sptr null; + + TS_ASSERT_THROWS(null * null, std::invalid_argument); +// AppleClang gives a warning if we don't use the result #if __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-comparison" #endif - TS_ASSERT_THROWS(null == null, std::invalid_argument); - TS_ASSERT_THROWS(null != null, std::invalid_argument); + TS_ASSERT_THROWS(null == null, std::invalid_argument); + TS_ASSERT_THROWS(null != null, std::invalid_argument); #if __clang__ #pragma clang diagnostic pop #endif - TS_ASSERT_THROWS(three * null, std::invalid_argument); - TS_ASSERT_THROWS(null * three, std::invalid_argument); - - Mantid::Kernel::V3D coords(0.4, 0.3, 0.1); - TS_ASSERT_THROWS(null * coords, std::invalid_argument); - } - + TS_ASSERT_THROWS(three * null, std::invalid_argument); + TS_ASSERT_THROWS(null * three, std::invalid_argument); + Mantid::Kernel::V3D coords(0.4, 0.3, 0.1); + TS_ASSERT_THROWS(null * coords, std::invalid_argument); + } }; - #endif /* MANTID_GEOMETRY_GROUPTEST_H_ */ diff --git a/Code/Mantid/Framework/Geometry/test/PointGroupFactoryTest.h b/Code/Mantid/Framework/Geometry/test/PointGroupFactoryTest.h index c525c1e9101eb058084d2c0e19fcbe3e4d87e12d..ada6ff46fbf341f3d52e96c0a7a7e2da182371d1 100644 --- a/Code/Mantid/Framework/Geometry/test/PointGroupFactoryTest.h +++ b/Code/Mantid/Framework/Geometry/test/PointGroupFactoryTest.h @@ -12,111 +12,129 @@ using Mantid::Geometry::PointGroupFactoryImpl; using namespace Mantid::Geometry; - /* For testing the factory, three fake point groups are defined * and registered in the factory (see below). * * When the test is destroyed, these are explicitly unregistered, * so they don't interfere with other tests. */ -class PointGroupFactoryTest : public CxxTest::TestSuite -{ +class PointGroupFactoryTest : public CxxTest::TestSuite { public: // This pair of boilerplate methods prevent the suite being created statically // This means the constructor isn't called when running other tests - static PointGroupFactoryTest *createSuite() { return new PointGroupFactoryTest(); } - static void destroySuite( PointGroupFactoryTest *suite ) { delete suite; } - - PointGroupFactoryTest() - { - PointGroupFactory::Instance().subscribePointGroup("monoclinicA", "x,y,-z", "test"); - PointGroupFactory::Instance().subscribePointGroup("monoclinicB", "x,-y,-z", "test"); - PointGroupFactory::Instance().subscribePointGroup("triclinic", "-x,-y,-z", "test"); + static PointGroupFactoryTest *createSuite() { + return new PointGroupFactoryTest(); + } + static void destroySuite(PointGroupFactoryTest *suite) { delete suite; } + + PointGroupFactoryTest() { + PointGroupFactory::Instance().subscribePointGroup("monoclinicA", "x,y,-z", + "test"); + PointGroupFactory::Instance().subscribePointGroup("monoclinicB", "x,-y,-z", + "test"); + PointGroupFactory::Instance().subscribePointGroup("triclinic", "-x,-y,-z", + "test"); } - ~PointGroupFactoryTest() - { - // Unsubscribing the fake point groups - PointGroupFactory::Instance().unsubscribePointGroup("monoclinicA"); - PointGroupFactory::Instance().unsubscribePointGroup("monoclinicB"); - PointGroupFactory::Instance().unsubscribePointGroup("triclinic"); + ~PointGroupFactoryTest() { + // Unsubscribing the fake point groups + PointGroupFactory::Instance().unsubscribePointGroup("monoclinicA"); + PointGroupFactory::Instance().unsubscribePointGroup("monoclinicB"); + PointGroupFactory::Instance().unsubscribePointGroup("triclinic"); } - void testCreatePointGroup() - { - TS_ASSERT_THROWS_NOTHING(PointGroupFactory::Instance().createPointGroup("monoclinicA")); - TS_ASSERT_THROWS_NOTHING(PointGroupFactory::Instance().createPointGroup("monoclinicB")); - TS_ASSERT_THROWS_NOTHING(PointGroupFactory::Instance().createPointGroup("triclinic")); + void testCreatePointGroup() { + TS_ASSERT_THROWS_NOTHING( + PointGroupFactory::Instance().createPointGroup("monoclinicA")); + TS_ASSERT_THROWS_NOTHING( + PointGroupFactory::Instance().createPointGroup("monoclinicB")); + TS_ASSERT_THROWS_NOTHING( + PointGroupFactory::Instance().createPointGroup("triclinic")); - TS_ASSERT_THROWS(PointGroupFactory::Instance().createPointGroup("cubicC"), std::invalid_argument); + TS_ASSERT_THROWS(PointGroupFactory::Instance().createPointGroup("cubicC"), + std::invalid_argument); } - void testGetAllPointGroupSymbols() - { - std::vector<std::string> symbols = PointGroupFactory::Instance().getAllPointGroupSymbols(); + void testGetAllPointGroupSymbols() { + std::vector<std::string> symbols = + PointGroupFactory::Instance().getAllPointGroupSymbols(); - TS_ASSERT_DIFFERS(findString(symbols, "monoclinicA"), symbols.end()); - TS_ASSERT_DIFFERS(findString(symbols, "monoclinicB"), symbols.end()); - TS_ASSERT_DIFFERS(findString(symbols, "triclinic"), symbols.end()); + TS_ASSERT_DIFFERS(findString(symbols, "monoclinicA"), symbols.end()); + TS_ASSERT_DIFFERS(findString(symbols, "monoclinicB"), symbols.end()); + TS_ASSERT_DIFFERS(findString(symbols, "triclinic"), symbols.end()); } - void testGetAllPointGroupSymbolsCrystalSystems() - { - std::vector<std::string> cubic = PointGroupFactory::Instance().getPointGroupSymbols(PointGroup::Monoclinic); + void testGetAllPointGroupSymbolsCrystalSystems() { + std::vector<std::string> cubic = + PointGroupFactory::Instance().getPointGroupSymbols( + PointGroup::Monoclinic); - TS_ASSERT_DIFFERS(findString(cubic, "monoclinicA"), cubic.end()); - TS_ASSERT_DIFFERS(findString(cubic, "monoclinicB"), cubic.end()); + TS_ASSERT_DIFFERS(findString(cubic, "monoclinicA"), cubic.end()); + TS_ASSERT_DIFFERS(findString(cubic, "monoclinicB"), cubic.end()); - std::vector<std::string> triclinic = PointGroupFactory::Instance().getPointGroupSymbols(PointGroup::Triclinic); - TS_ASSERT_DIFFERS(findString(triclinic, "triclinic"), triclinic.end()); + std::vector<std::string> triclinic = + PointGroupFactory::Instance().getPointGroupSymbols( + PointGroup::Triclinic); + TS_ASSERT_DIFFERS(findString(triclinic, "triclinic"), triclinic.end()); } - void testUnsubscribePointGroup() - { - TS_ASSERT_THROWS_NOTHING(PointGroupFactory::Instance().createPointGroup("monoclinicA")); + void testUnsubscribePointGroup() { + TS_ASSERT_THROWS_NOTHING( + PointGroupFactory::Instance().createPointGroup("monoclinicA")); - PointGroupFactory::Instance().unsubscribePointGroup("monoclinicA"); + PointGroupFactory::Instance().unsubscribePointGroup("monoclinicA"); - std::vector<std::string> allSymbols = PointGroupFactory::Instance().getAllPointGroupSymbols(); - TS_ASSERT_EQUALS(findString(allSymbols, "monoclinicA"), allSymbols.end()); + std::vector<std::string> allSymbols = + PointGroupFactory::Instance().getAllPointGroupSymbols(); + TS_ASSERT_EQUALS(findString(allSymbols, "monoclinicA"), allSymbols.end()); - TS_ASSERT_THROWS(PointGroupFactory::Instance().createPointGroup("monoclinicA"), std::invalid_argument); + TS_ASSERT_THROWS( + PointGroupFactory::Instance().createPointGroup("monoclinicA"), + std::invalid_argument); - PointGroupFactory::Instance().subscribePointGroup("monoclinicA", "x,y,-z", "test"); - TS_ASSERT_THROWS_NOTHING(PointGroupFactory::Instance().createPointGroup("monoclinicA")); + PointGroupFactory::Instance().subscribePointGroup("monoclinicA", "x,y,-z", + "test"); + TS_ASSERT_THROWS_NOTHING( + PointGroupFactory::Instance().createPointGroup("monoclinicA")); } - void testPointGroupSymbolCreation() - { - TS_ASSERT_THROWS_NOTHING(checkSpaceGroupSymbol("P -1")); - TS_ASSERT_THROWS_NOTHING(checkSpaceGroupSymbol("P 1 2/m 1")); - TS_ASSERT_THROWS_NOTHING(checkSpaceGroupSymbol("P 1 1 2/m")); - TS_ASSERT_THROWS_NOTHING(checkSpaceGroupSymbol("F d d d")); - TS_ASSERT_THROWS_NOTHING(checkSpaceGroupSymbol("C m c a")); - TS_ASSERT_THROWS_NOTHING(checkSpaceGroupSymbol("P 43/a m d")); - TS_ASSERT_THROWS_NOTHING(checkSpaceGroupSymbol("I 41/c c n")); - TS_ASSERT_THROWS_NOTHING(checkSpaceGroupSymbol("P 63/m m c")); - TS_ASSERT_THROWS_NOTHING(checkSpaceGroupSymbol("F d -3 m")); - TS_ASSERT_THROWS_NOTHING(checkSpaceGroupSymbol("P -3 c 1")); - TS_ASSERT_THROWS_NOTHING(checkSpaceGroupSymbol("P -3 1 d")); - TS_ASSERT_THROWS_NOTHING(checkSpaceGroupSymbol("P 4/a")); - TS_ASSERT_THROWS_NOTHING(checkSpaceGroupSymbol("P 62/d")); - TS_ASSERT_THROWS_NOTHING(checkSpaceGroupSymbol("I d -3")); - TS_ASSERT_THROWS_NOTHING(checkSpaceGroupSymbol("I 4/c")); + void testPointGroupSymbolCreation() { + TS_ASSERT_THROWS_NOTHING(checkSpaceGroupSymbol("P -1")); + TS_ASSERT_THROWS_NOTHING(checkSpaceGroupSymbol("P 1 2/m 1")); + TS_ASSERT_THROWS_NOTHING(checkSpaceGroupSymbol("F d d d")); + TS_ASSERT_THROWS_NOTHING(checkSpaceGroupSymbol("C m c e")); + TS_ASSERT_THROWS_NOTHING(checkSpaceGroupSymbol("P 42/n b c")); + TS_ASSERT_THROWS_NOTHING(checkSpaceGroupSymbol("I 41/a m d")); + TS_ASSERT_THROWS_NOTHING(checkSpaceGroupSymbol("P 63/m m c")); + TS_ASSERT_THROWS_NOTHING(checkSpaceGroupSymbol("F d -3 m")); + TS_ASSERT_THROWS_NOTHING(checkSpaceGroupSymbol("P 42/m")); + TS_ASSERT_THROWS_NOTHING(checkSpaceGroupSymbol("P 63/m")); + TS_ASSERT_THROWS_NOTHING(checkSpaceGroupSymbol("F d -3")); + TS_ASSERT_THROWS_NOTHING(checkSpaceGroupSymbol("I 4 2 2")); + + TS_ASSERT_THROWS_NOTHING(checkSpaceGroupSymbol("P -3 c 1")); + TS_ASSERT_THROWS_NOTHING(checkSpaceGroupSymbol("P -3 1 c")); + TS_ASSERT_THROWS_NOTHING(checkSpaceGroupSymbol("R 32")); + + PointGroup_sptr pointGroup = checkSpaceGroupSymbol("R 3"); + TS_ASSERT_EQUALS(pointGroup->getCoordinateSystem(), + Group::CoordinateSystem::Hexagonal); + TS_ASSERT_EQUALS(pointGroup->getSymbol(), "3"); } - private: - std::vector<std::string>::const_iterator findString(const std::vector<std::string> &vector, const std::string &searchString) - { - return std::find(vector.begin(), vector.end(), searchString); + std::vector<std::string>::const_iterator + findString(const std::vector<std::string> &vector, + const std::string &searchString) { + return std::find(vector.begin(), vector.end(), searchString); } - void checkSpaceGroupSymbol(const std::string &symbol) - { - PointGroupFactory::Instance().createPointGroupFromSpaceGroupSymbol(symbol); + PointGroup_sptr checkSpaceGroupSymbol(const std::string &symbol) { + SpaceGroup_const_sptr spaceGroup = + SpaceGroupFactory::Instance().createSpaceGroup(symbol); + return PointGroupFactory::Instance().createPointGroupFromSpaceGroup( + spaceGroup); } }; - #endif /* MANTID_GEOMETRY_POINTGROUPFACTORYTEST_H_ */ diff --git a/Code/Mantid/Framework/Geometry/test/PointGroupTest.h b/Code/Mantid/Framework/Geometry/test/PointGroupTest.h index 414802c6e8a355cdd143f970fe00c0f21744822e..ffaac8d2e1ceb61b7ff0137a5be0663749a74bd2 100644 --- a/Code/Mantid/Framework/Geometry/test/PointGroupTest.h +++ b/Code/Mantid/Framework/Geometry/test/PointGroupTest.h @@ -63,7 +63,7 @@ public: { V3D equiv[] = {V3D(1,2,3),V3D(-1,-2,3), V3D(-2,1,3), V3D(2,-1,3), V3D(-1,2,-3), V3D(1,-2,-3), V3D(2,1,-3), V3D(-2,-1,-3), V3D(-1,-2,-3), V3D(1,2,-3), V3D(2,-1,-3), V3D(-2,1,-3), V3D(1,-2,3), V3D(-1,2,3),V3D(-2,-1,3), V3D(2,1,3)}; check_point_group("4/mmm", V3D(1,2,3), 16, equiv); } { V3D equiv[] = {V3D(1,2,3),V3D(2,-3,3),V3D(-3,1,3), V3D(-1,-2,-3),V3D(-2,3,-3),V3D(3,-1,-3)}; - check_point_group("-3 h", V3D(1,2,3), 6, equiv); } + check_point_group("-3", V3D(1,2,3), 6, equiv); } { V3D equiv[] = {V3D(1,2,3),V3D(2,-3,3),V3D(-3,1,3),V3D(2,1,-3),V3D(1,-3,-3),V3D(-3,2,-3),V3D(-1,-2,-3),V3D(-2,3,-3),V3D(3,-1,-3),V3D(-2,-1,3),V3D(-1,3,3),V3D(3,-2,3)}; check_point_group("-3m1", V3D(1,2,3), 12, equiv); } { V3D equiv[] = {V3D(1,2,3),V3D(2,-3,3),V3D(-3,1,3),V3D(-2,-1,-3),V3D(-1,3,-3),V3D(3,-2,-3),V3D(-1,-2,-3),V3D(-2,3,-3),V3D(3,-1,-3),V3D(2,1,3),V3D(1,-3,3),V3D(-3,2,3),}; @@ -128,19 +128,19 @@ public: crystalSystemsMap["-4m2"] = PointGroup::Tetragonal; crystalSystemsMap["4/mmm"] = PointGroup::Tetragonal; - crystalSystemsMap["3 h"] = PointGroup::Trigonal; - crystalSystemsMap["-3 h"] = PointGroup::Trigonal; + crystalSystemsMap["3"] = PointGroup::Trigonal; + crystalSystemsMap["-3"] = PointGroup::Trigonal; crystalSystemsMap["321"] = PointGroup::Trigonal; crystalSystemsMap["312"] = PointGroup::Trigonal; crystalSystemsMap["3m1"] = PointGroup::Trigonal; crystalSystemsMap["31m"] = PointGroup::Trigonal; crystalSystemsMap["-3m1"] = PointGroup::Trigonal; crystalSystemsMap["-31m"] = PointGroup::Trigonal; - crystalSystemsMap["3"] = PointGroup::Trigonal; - crystalSystemsMap["-3"] = PointGroup::Trigonal; - crystalSystemsMap["32"] = PointGroup::Trigonal; - crystalSystemsMap["3m"] = PointGroup::Trigonal; - crystalSystemsMap["-3m"] = PointGroup::Trigonal; + crystalSystemsMap["3 r"] = PointGroup::Trigonal; + crystalSystemsMap["-3 r"] = PointGroup::Trigonal; + crystalSystemsMap["32 r"] = PointGroup::Trigonal; + crystalSystemsMap["3m r"] = PointGroup::Trigonal; + crystalSystemsMap["-3m r"] = PointGroup::Trigonal; crystalSystemsMap["6"] = PointGroup::Hexagonal; crystalSystemsMap["-6"] = PointGroup::Hexagonal; diff --git a/Code/Mantid/Framework/Kernel/CMakeLists.txt b/Code/Mantid/Framework/Kernel/CMakeLists.txt index 887bba0271579674dd2aff16e4107f268ffe51ac..07d6f10edbb7529ecaf9e15a95a7d554e653a20e 100644 --- a/Code/Mantid/Framework/Kernel/CMakeLists.txt +++ b/Code/Mantid/Framework/Kernel/CMakeLists.txt @@ -8,6 +8,7 @@ set ( SRC_FILES src/CPUTimer.cpp src/CatalogInfo.cpp src/CompositeValidator.cpp + src/ComputeResourceInfo.cpp src/ConfigService.cpp src/ChecksumHelper.cpp src/DataItem.cpp @@ -128,6 +129,7 @@ set ( INC_FILES inc/MantidKernel/Cache.h inc/MantidKernel/CatalogInfo.h inc/MantidKernel/CompositeValidator.h + inc/MantidKernel/ComputeResourceInfo.h inc/MantidKernel/ConfigService.h inc/MantidKernel/ChecksumHelper.h inc/MantidKernel/DataItem.h @@ -264,6 +266,7 @@ set ( TEST_FILES CacheTest.h CatalogInfoTest.h CompositeValidatorTest.h + ComputeResourceInfoTest.h ConfigServiceTest.h ChecksumHelperTest.h DataServiceTest.h diff --git a/Code/Mantid/Framework/Kernel/inc/MantidKernel/ComputeResourceInfo.h b/Code/Mantid/Framework/Kernel/inc/MantidKernel/ComputeResourceInfo.h new file mode 100644 index 0000000000000000000000000000000000000000..db27c93ed68e8bcaaf1e7434fc1dca88b3bd1483 --- /dev/null +++ b/Code/Mantid/Framework/Kernel/inc/MantidKernel/ComputeResourceInfo.h @@ -0,0 +1,82 @@ +#ifndef MANTID_KERNEL_COMPUTERESOURCEINFO_H_ +#define MANTID_KERNEL_COMPUTERESOURCEINFO_H_ + +#include <string> + +#include "MantidKernel/DllConfig.h" + +namespace Poco { +namespace XML { +class Element; +} +} + +namespace Mantid { +namespace Kernel { + +class FacilityInfo; + +/** +ComputeResourceInfo holds information about / represents a compute +resource present in a facility. + +At the moment (remote) compute resources are defined by their name, +the URL they can be accessed at, and the type of remote job manager +that they use/require (Mantid web service API, LSF, etc.). + +Copyright © 2015 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge +National Laboratory & European Spallation Source + +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://github.com/mantidproject/mantid>. +Code Documentation is available at: <http://doxygen.mantidproject.org> +*/ +class MANTID_KERNEL_DLL ComputeResourceInfo { +public: + /// constructor - from facility info and the element for this resource + ComputeResourceInfo(const FacilityInfo *f, const Poco::XML::Element *elem); + + /// Equality operator + bool operator==(const ComputeResourceInfo &rhs) const; + + /// Name of the compute resource + std::string name() const; + + /// Base URL the compute resource + std::string baseURL() const ; + + /// Type/class of remote job manager required to handle this resource + std::string remoteJobManagerType() const; + + /// The facility where this compute resource is avalable + const FacilityInfo &facility() const; + +private: + const FacilityInfo *m_facility; ///< Facility + std::string m_name; ///< Cluster/resource name + std::string m_baseURL; ///< access URL (first authentication, etc.) + std::string m_managerType; ///< specific remote job manager class +}; + +/// output to stream operator for compute resource info objects +MANTID_KERNEL_DLL std::ostream & +operator<<(std::ostream &buffer, const ComputeResourceInfo &cr); + +} // namespace Kernel +} // namespace Mantid + +#endif /* MANTID_KERNEL_COMPUTERESOURCEINFO_H_ */ diff --git a/Code/Mantid/Framework/Kernel/inc/MantidKernel/FacilityInfo.h b/Code/Mantid/Framework/Kernel/inc/MantidKernel/FacilityInfo.h index 2d5976003305abfd697f2a52eb653a3accad0891..20c5d7172471f2ceb0367e185e410cbadf8a26f3 100644 --- a/Code/Mantid/Framework/Kernel/inc/MantidKernel/FacilityInfo.h +++ b/Code/Mantid/Framework/Kernel/inc/MantidKernel/FacilityInfo.h @@ -6,6 +6,7 @@ //---------------------------------------------------------------------- #include "MantidKernel/DllConfig.h" #include "MantidKernel/CatalogInfo.h" +#include "MantidKernel/ComputeResourceInfo.h" #include "MantidKernel/InstrumentInfo.h" #include "MantidKernel/RemoteJobManager.h" #ifndef Q_MOC_RUN @@ -80,7 +81,13 @@ public: std::vector<InstrumentInfo> instruments(const std::string &tech) const; /// Returns instruments with given name const InstrumentInfo &instrument(std::string iName = "") const; - /// Returns a vector of the available compute resources + + /// Returns a vector of available compute resources + std::vector<ComputeResourceInfo> computeResInfos() const; + /// Returns a compute resource identified by name + const ComputeResourceInfo &computeResource(const std::string &name) const; + + /// Returns a vector of the names of the available compute resources std::vector<std::string> computeResources() const; /// Returns the RemoteJobManager for the named compute resource boost::shared_ptr<RemoteJobManager> @@ -113,12 +120,18 @@ private: std::vector<InstrumentInfo> m_instruments; ///< list of instruments of this facility std::string m_liveListener; ///< name of the default live listener + + std::vector<ComputeResourceInfo> m_computeResInfos; ///< (remote) compute + /// resources available in + /// this facility + + // TODO: remove RemoteJobManager form here (trac ticket #11373) typedef std::map<std::string, boost::shared_ptr<RemoteJobManager>> ComputeResourcesMap; ComputeResourcesMap m_computeResources; ///< list of compute resources ///(clusters, etc...) available at - /// this facility - // (Sorted by their names) + /// this facility + // (Sorted by their names) }; } // namespace Kernel diff --git a/Code/Mantid/Framework/Kernel/src/ComputeResourceInfo.cpp b/Code/Mantid/Framework/Kernel/src/ComputeResourceInfo.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6669c1f228310ec4bcba078f3f79a072f96cad77 --- /dev/null +++ b/Code/Mantid/Framework/Kernel/src/ComputeResourceInfo.cpp @@ -0,0 +1,115 @@ +#include "MantidKernel/ComputeResourceInfo.h" +#include "MantidKernel/FacilityInfo.h" +#include "MantidKernel/Logger.h" + +#include <Poco/DOM/AutoPtr.h> +#include <Poco/DOM/Element.h> +#include <Poco/DOM/NodeList.h> +#include <Poco/DOM/Text.h> + +namespace Mantid { +namespace Kernel { +namespace { +// static logger object +Logger g_log("ComputeResourceInfo"); +} + +/** + * Construct a compute resource from information found in a facilities + * definition file. + * + * @param fac Facility where this (remote) compute resource is available + * @param elem A (Poco::XML::) Element to read the data from + * + * @throw std::runtime_error if name or required attributes are not + * found + */ +ComputeResourceInfo::ComputeResourceInfo(const FacilityInfo *fac, + const Poco::XML::Element *elem) + : m_facility(fac) { + + m_name = elem->getAttribute("name"); + if (m_name.empty()) { + std::string elemStr = ""; + if (elem) + elemStr = elem->innerText(); + throw std::runtime_error( + "The compute resource name is not defined, at element: " + elemStr); + } + + // default: Mantid web service API: + // http://www.mantidproject.org/Remote_Job_Submission_API + m_managerType = "MantidWebServiceAPIJobManager"; + std::string type = elem->getAttribute("JobManagerType"); + if (!type.empty()) { + m_managerType = type; + } + + const std::string baseTag = "baseURL"; + Poco::AutoPtr<Poco::XML::NodeList> nl = elem->getElementsByTagName(baseTag); + if (!nl || nl->length() != 1 || !nl->item(0) || !nl->item(0)->childNodes()) { + g_log.error("Failed to get base URL for remote compute resource '" + + m_name + "'"); + throw std::runtime_error("Remote compute resources must have exactly one " + "baseURL tag. It was not found for the resource " + "'" + + m_name + "'"); + } else { + nl = nl->item(0)->childNodes(); + if (nl->length() > 0) { + Poco::XML::Text *txt = dynamic_cast<Poco::XML::Text *>(nl->item(0)); + if (txt) { + m_baseURL = txt->getData(); + } else { + g_log.error("Failed to get base URL for remote compute resource '" + + m_name + "'. The " + baseTag + " tag seems empty!"); + throw std::runtime_error( + "Remote compute resources must have exactly one " + "baseURL tag containing a URL string. A tag was found for the " + "resource " + "'" + + m_name + "', but it seems empty!"); + } + } + } +} + +/** +* Equality operator. Two different resources cannot have the same name +* +* @param rhs object to compare this with +* +* @return True if the objects (names) are equal +*/ +bool ComputeResourceInfo::operator==(const ComputeResourceInfo &rhs) const { + return (this->name() == rhs.name()); +} + +std::string ComputeResourceInfo::name() const { return m_name; } + +std::string ComputeResourceInfo::baseURL() const { return m_baseURL; } + +std::string ComputeResourceInfo::remoteJobManagerType() const { + return m_managerType; +} + +const FacilityInfo &ComputeResourceInfo::facility() const { + return *m_facility; +} + +/** + * Prints the instrument name into an output stream + * + * @param buffer an output stream being written to + * @param cr a ComputeResourceInfo object to print + * + * @return reference to the output stream being written to + */ +std::ostream &operator<<(std::ostream &buffer, const ComputeResourceInfo &cr) { + buffer << "'" + cr.name() + "', at '" + cr.baseURL() + "', of type '" + + cr.remoteJobManagerType() + "'"; + return buffer; +} + +} // namespace Kernel +} // namespace Mantid diff --git a/Code/Mantid/Framework/Kernel/src/FacilityInfo.cpp b/Code/Mantid/Framework/Kernel/src/FacilityInfo.cpp index 7346c52307c62fe54291b6032c56f89309ff623a..dad72eec268239254af844eda8d20fd5d268cf1c 100644 --- a/Code/Mantid/Framework/Kernel/src/FacilityInfo.cpp +++ b/Code/Mantid/Framework/Kernel/src/FacilityInfo.cpp @@ -154,10 +154,24 @@ void FacilityInfo::fillComputeResources(const Poco::XML::Element *elem) { for (unsigned long i = 0; i < n; i++) { Poco::XML::Element *elem = dynamic_cast<Poco::XML::Element *>(pNL_compute->item(i)); - std::string name = elem->getAttribute("name"); - m_computeResources.insert(std::make_pair( - name, boost::shared_ptr<RemoteJobManager>(new RemoteJobManager(elem)))); + if (elem) { + try { + ComputeResourceInfo cr(this, elem); + m_computeResInfos.push_back(cr); + + g_log.debug() << "Compute resource found: " << cr << std::endl; + } catch (...) { // next resource... + } + + std::string name = elem->getAttribute("name"); + // TODO: this is a bit of duplicate effort at the moment, until + // RemoteJobManager goes away from here (then this would be + // removed), see header for details. + m_computeResources.insert(std::make_pair( + name, + boost::shared_ptr<RemoteJobManager>(new RemoteJobManager(elem)))); + } } } @@ -202,14 +216,22 @@ const InstrumentInfo &FacilityInfo::instrument(std::string iName) const { } /** - * Returns a list of instruments of given technique - * @param tech :: Technique name - * @return a list of instrument information objects + * Get the vector of available compute resources + * @return vector of ComputeResourInfo for the current facility */ +std::vector<ComputeResourceInfo> FacilityInfo::computeResInfos() const { + return m_computeResInfos; +} + +/** +* Returns a list of instruments of given technique +* @param tech :: Technique name +* @return a list of instrument information objects +*/ std::vector<InstrumentInfo> FacilityInfo::instruments(const std::string &tech) const { std::vector<InstrumentInfo> out; - std::vector<InstrumentInfo>::const_iterator it = m_instruments.begin(); + auto it = m_instruments.begin(); for (; it != m_instruments.end(); ++it) { if (it->techniques().count(tech)) { out.push_back(*it); @@ -219,7 +241,7 @@ FacilityInfo::instruments(const std::string &tech) const { } /** - * Returns a vector of the available compute resources + * Returns a vector of the names of the available compute resources * @return vector of strings of the compute resource names */ std::vector<std::string> FacilityInfo::computeResources() const { @@ -233,6 +255,39 @@ std::vector<std::string> FacilityInfo::computeResources() const { return names; } +/** + * Get a compute resource by name + * + * @param name Name as specified in the facilities definition file + * + * @return the named compute resource + * + * @throws NotFoundError if the resource is not found/available. + */ +const ComputeResourceInfo & +FacilityInfo::computeResource(const std::string &name) const { + if (name.empty()) { + g_log.debug("Cannot find a compute resource without name " + "(empty)."); + throw Exception::NotFoundError("FacilityInfo, empty compute resource name", + name); + } + + auto it = m_computeResInfos.begin(); + for (; it != m_computeResInfos.end(); ++it) { + if (it->name() == name) { + g_log.debug() << "Compute resource '" << name << "' found at facility " + << this->name() << "." << std::endl; + return *it; + } + } + + g_log.debug() << "Could not find requested compute resource: " << name + << " in facility " << this->name() << "." << std::endl; + throw Exception::NotFoundError("FacilityInfo, missing compute resource", + name); +} + /** * Returns a reference to the requested remote job manager * @param name :: Name of the cluster we want to submit jobs to diff --git a/Code/Mantid/Framework/Kernel/src/InstrumentInfo.cpp b/Code/Mantid/Framework/Kernel/src/InstrumentInfo.cpp index 60e610a0169609d84eb875d85918293bad4963b9..9b0f8bc57aced45671c461b6f8666ddd10a9832c 100644 --- a/Code/Mantid/Framework/Kernel/src/InstrumentInfo.cpp +++ b/Code/Mantid/Framework/Kernel/src/InstrumentInfo.cpp @@ -7,10 +7,10 @@ #include "MantidKernel/Logger.h" #include "MantidKernel/Strings.h" +#include <Poco/DOM/AutoPtr.h> #include <Poco/DOM/Element.h> #include <Poco/DOM/NodeList.h> #include <Poco/DOM/Text.h> -#include <Poco/DOM/AutoPtr.h> #include <boost/lexical_cast.hpp> diff --git a/Code/Mantid/Framework/Kernel/test/ComputeResourceInfoTest.h b/Code/Mantid/Framework/Kernel/test/ComputeResourceInfoTest.h new file mode 100644 index 0000000000000000000000000000000000000000..213a98ed2098662b0748101000aaaa992a0a8cc0 --- /dev/null +++ b/Code/Mantid/Framework/Kernel/test/ComputeResourceInfoTest.h @@ -0,0 +1,269 @@ +#ifndef COMPUTERESOURCEINFOTEST_H_ +#define COMPUTERESOURCEINFOTEST_H_ + +#include "MantidKernel/Exception.h" +#include "MantidKernel/FacilityInfo.h" + +#include <Poco/DOM/AutoPtr.h> +#include <Poco/DOM/Document.h> +#include <Poco/DOM/DOMParser.h> +#include <Poco/XML/XMLException.h> + +using namespace Mantid::Kernel; + +class ComputeResourceInfoTest : public CxxTest::TestSuite { +public: + void test_allMissing() { + FacilityInfo *fac = NULL; + TS_ASSERT_THROWS_NOTHING(fac = + createCRInfoInMinimalFacility(simpleInstStr)); + TS_ASSERT(fac); + std::vector<ComputeResourceInfo> cri; + TS_ASSERT_THROWS_NOTHING(cri = fac->computeResInfos()); + TS_ASSERT_EQUALS(cri.size(), 0); + + delete fac; + fac = NULL; + TS_ASSERT_THROWS(fac = createCRInfoInMinimalFacility( + "<computeResource fooAtt=\"barVal\"/>"), + std::runtime_error); + TS_ASSERT(!fac); + delete fac; + } + + void test_noURLTag() { + const std::string crTxt = "<computeResource name=\"foo\">" + "<u>" + + fermiURL + "</u>" + "</computeResource>"; + FacilityInfo *fac = NULL; + TS_ASSERT_THROWS(fac = createCRInfoInMinimalFacility(crTxt), + std::runtime_error); + TS_ASSERT(!fac); + delete fac; + } + + void test_wrongXML() { + const std::string crTxt = "<computeResource name=\"foo\">" + "<u_foo>" + + fermiURL + "</u_bar>" + "</compResource>"; + FacilityInfo *fac = NULL; + TS_ASSERT_THROWS(fac = createCRInfoInMinimalFacility(crTxt), + Poco::XML::XMLException); + TS_ASSERT(!fac); + delete fac; + } + + void test_normalFermi() { + const std::string fermi = "<computeResource name=\"" + fermiName + + "\">" + "<baseURL>" + + fermiURL + "</baseURL>" + "</computeResource>"; + + FacilityInfo *fac = NULL; + TS_ASSERT_THROWS_NOTHING(fac = createCRInfoInMinimalFacility(fermi)); + TS_ASSERT(fac); + TS_ASSERT_EQUALS(fac->name(), this->testFacilityName); + + std::vector<ComputeResourceInfo> cri; + TS_ASSERT_THROWS_NOTHING(cri = fac->computeResInfos()); + TS_ASSERT_EQUALS(cri.size(), 1); + + ComputeResourceInfo cr = fac->computeResInfos().front(); + TS_ASSERT_THROWS(ComputeResourceInfo fail = fac->computeResource(scarfName), + Mantid::Kernel::Exception::NotFoundError); + ComputeResourceInfo cr2 = fac->computeResource(fermiName); + TS_ASSERT_EQUALS(cr, cr2); + TS_ASSERT_EQUALS(cr, cri.front()); + TS_ASSERT_EQUALS(cr2, cri.front()); + TS_ASSERT_EQUALS(cr.name(), fermiName); + TS_ASSERT_EQUALS(cr2.name(), fermiName); + TS_ASSERT_EQUALS(cr.baseURL(), fermiURL); + TS_ASSERT_EQUALS(cr2.baseURL(), fermiURL); + TS_ASSERT_EQUALS(cr.remoteJobManagerType(), defaultType); + TS_ASSERT_EQUALS(cr2.remoteJobManagerType(), defaultType); + TS_ASSERT_EQUALS(cr.facility().name(), fac->name()); + TS_ASSERT_EQUALS(cr2.facility().name(), fac->name()); + } + + void test_brokenFermi() { + // wrong 'baseURL' tag + const std::string fermi = "<computeResource name=\"" + fermiName + "\">" + "<URL>" + + fermiURL + "</URL>" + "</computeResource>"; + + FacilityInfo *fac = NULL; + TS_ASSERT_THROWS(fac = createCRInfoInMinimalFacility(fermi), + std::runtime_error); + + TS_ASSERT(!fac); + delete fac; + } + + void test_normalSCARF() { + const std::string scarf = "<computeResource name=\"" + scarfName + + "\" JobManagerType=\"" + scarfType + "\">" + "<baseURL>" + + scarfURL + "</baseURL>" + "</computeResource>"; + + FacilityInfo *fac = NULL; + TS_ASSERT_THROWS_NOTHING(fac = createCRInfoInMinimalFacility(scarf)); + TS_ASSERT(fac); + TS_ASSERT_EQUALS(fac->name(), this->testFacilityName); + std::vector<ComputeResourceInfo> cri; + TS_ASSERT_THROWS_NOTHING(cri = fac->computeResInfos()); + TS_ASSERT_EQUALS(cri.size(), 1); + + ComputeResourceInfo cr = fac->computeResInfos().front(); + TS_ASSERT_THROWS(ComputeResourceInfo fail = fac->computeResource("inexistent!"), + Mantid::Kernel::Exception::NotFoundError); + ComputeResourceInfo cr2 = fac->computeResource(scarfName); + TS_ASSERT_EQUALS(cr, cr2); + TS_ASSERT_EQUALS(cri.front(), cr); + TS_ASSERT_EQUALS(cri.front(), cr2); + TS_ASSERT_EQUALS(scarfName, cr.name()); + TS_ASSERT_EQUALS(scarfName, cr2.name()); + TS_ASSERT_EQUALS(scarfURL, cr.baseURL()); + TS_ASSERT_EQUALS(scarfURL, cr2.baseURL()); + TS_ASSERT_EQUALS(scarfType, cr.remoteJobManagerType()); + TS_ASSERT_EQUALS(scarfType, cr2.remoteJobManagerType()); + TS_ASSERT_EQUALS(fac->name(), cr.facility().name()); + TS_ASSERT_EQUALS(fac->name(), cr2.facility().name()); + delete fac; + } + + void test_brokenSCARF() { + const std::string type = "SCARFLSFJobManager"; + const std::string err = "<computeResource foo=\"" + scarfName + + "\" JobManagerType=\"" + type + "\">" + "<URL>" + + scarfURL + "</URL>" + "</computeResource>"; + FacilityInfo *fac = NULL; + TS_ASSERT_THROWS(fac = createCRInfoInMinimalFacility(err), + std::runtime_error); + TS_ASSERT(!fac); + delete fac; + } + + void test_equals() { + const std::string otherName = "other"; + const std::string otherURL = "www.example.com/foo/baz"; + const std::string thirdName = "third"; + const std::string rep = "<computeResource name=\"" + fermiName + + "\">" + "<baseURL>" + + fermiURL + "</baseURL>" + "</computeResource>" + + "<computeResource name=\"" + + otherName + "\">" + "<baseURL>" + + otherURL + "</baseURL>" + "</computeResource>" + + "<computeResource name=\"" + + thirdName + "\">" + "<baseURL>" + + fermiURL + "</baseURL>" + "</computeResource>" + + "<computeResource name=\"" + + fermiName + "\">" + "<baseURL>" + + fermiURL + "</baseURL>" + "</computeResource>"; + + FacilityInfo *fac = NULL; + TS_ASSERT_THROWS_NOTHING(fac = createCRInfoInMinimalFacility(rep)); + TS_ASSERT(fac); + TS_ASSERT_EQUALS(fac->computeResources().size(), 3); + TS_ASSERT_EQUALS(fac->computeResInfos().size(), 4); + + // compare names + TS_ASSERT(fac->computeResources()[0] == fac->computeResources()[0]); + TS_ASSERT(!(fac->computeResources()[0] == fac->computeResources()[1])); + TS_ASSERT(!(fac->computeResources()[0] == fac->computeResources()[2])); + TS_ASSERT(!(fac->computeResources()[1] == fac->computeResources()[2])); + + // compare full comp resource info + TS_ASSERT(fac->computeResInfos()[0] == fac->computeResInfos()[0]); + TS_ASSERT(!(fac->computeResInfos()[0] == fac->computeResInfos()[1])); + TS_ASSERT(!(fac->computeResInfos()[0] == fac->computeResInfos()[2])); + TS_ASSERT(!(fac->computeResInfos()[1] == fac->computeResInfos()[2])); + TS_ASSERT(!(fac->computeResInfos()[2] == fac->computeResInfos()[3])); + TS_ASSERT(fac->computeResInfos()[0] == fac->computeResInfos()[3]); + + // compare comp resource info retrieved by names + TS_ASSERT( + !(fac->computeResource(fermiName) == fac->computeResource(otherName))); + TS_ASSERT( + !(fac->computeResource(fermiName) == fac->computeResource(thirdName))); + TS_ASSERT( + !(fac->computeResource(otherName) == fac->computeResource(thirdName))); + delete fac; + } + +private: + /// make a minimal facilities file/xml string includin the compute resource + /// passed + FacilityInfo *createCRInfoInMinimalFacility(const std::string &crStr) { + const std::string xmlStr = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + "<facilities>" + " <facility name=\"" + + testFacilityName + + "\" FileExtensions=\".xyz\">" + simpleInstStr + + crStr + " </facility>" + "</facilities>"; + + return createFacility(xmlStr); + } + + FacilityInfo *createFacility(const std::string &xml) { + Poco::XML::DOMParser parser; + Poco::AutoPtr<Poco::XML::Document> pDoc = parser.parseString(xml); + Poco::XML::Element *pRootElem = pDoc->documentElement(); + Poco::XML::Element *elem = pRootElem->getChildElement("facility"); + + return new FacilityInfo(elem); + } + +private: + // a minimal instrument to create a facility info + static const std::string simpleInstStr; + + // default remote job manager type + static const std::string defaultType; + + static const std::string testFacilityName; + + static const std::string fermiName; + static const std::string fermiURL; + static const std::string scarfName; + static const std::string scarfURL; + static const std::string scarfType; +}; + +const std::string ComputeResourceInfoTest::simpleInstStr = + "<instrument name=\"AnInst\">" + " <technique>Measuring Stuff</technique>" + "</instrument>"; + +const std::string ComputeResourceInfoTest::defaultType = + "MantidWebServiceAPIJobManager"; + +const std::string ComputeResourceInfoTest::testFacilityName = "ATestFacility"; + +const std::string ComputeResourceInfoTest::fermiURL = + "https://fermi.ornl.gov/MantidRemote"; +const std::string ComputeResourceInfoTest::fermiName = "Fermi"; +const std::string ComputeResourceInfoTest::scarfURL = + "https://portal.scarf.rl.ac.uk"; +const std::string ComputeResourceInfoTest::scarfName = "SCARF@STFC"; +const std::string ComputeResourceInfoTest::scarfType = "SCARFLSFJobManager"; + +#endif // COMPUTERESOURCEINFOTEST_H_ diff --git a/Code/Mantid/Framework/Kernel/test/LogParserTest.h b/Code/Mantid/Framework/Kernel/test/LogParserTest.h index 8ae8ca0541546eacd71928a4d32878a3b9511353..5894835816cb4ff9274bc8695f25352917d005ea 100644 --- a/Code/Mantid/Framework/Kernel/test/LogParserTest.h +++ b/Code/Mantid/Framework/Kernel/test/LogParserTest.h @@ -539,6 +539,7 @@ public: TS_ASSERT_EQUALS( it->second, " Third line"); ++it; TS_ASSERT_EQUALS( it->first.toISO8601String(), "2000-09-05T12:23:33"); TS_ASSERT_EQUALS( it->second, " Fourth line"); ++it; + delete prop; } void test_num_repeat() @@ -561,6 +562,7 @@ public: TS_ASSERT_EQUALS( it->second, 5); ++it; TS_ASSERT_EQUALS( it->first.toISO8601String(), "2000-09-05T12:23:33"); TS_ASSERT_EQUALS( it->second, 6); ++it; + delete prop; } void test_str_continuation() @@ -577,6 +579,7 @@ public: TS_ASSERT_EQUALS( it->second, " First line"); ++it; TS_ASSERT_EQUALS( it->first.toISO8601String(), "2000-09-05T12:22:34"); TS_ASSERT_EQUALS( it->second, " Second line Third line"); ++it; + delete prop; } diff --git a/Code/Mantid/Framework/MDAlgorithms/CMakeLists.txt b/Code/Mantid/Framework/MDAlgorithms/CMakeLists.txt index 0149fe5d792415c7768d8ef9de8415a151bde08a..0e2f238894bde22742308c3059194480d88ffa1d 100644 --- a/Code/Mantid/Framework/MDAlgorithms/CMakeLists.txt +++ b/Code/Mantid/Framework/MDAlgorithms/CMakeLists.txt @@ -23,6 +23,7 @@ set ( SRC_FILES src/ConvertToMDParent.cpp src/CreateMDHistoWorkspace.cpp src/CreateMDWorkspace.cpp + src/CutMD.cpp src/DivideMD.cpp src/EqualToMD.cpp src/EvaluateMDFunction.cpp @@ -107,6 +108,7 @@ set ( INC_FILES inc/MantidMDAlgorithms/ConvertToMDParent.h inc/MantidMDAlgorithms/CreateMDHistoWorkspace.h inc/MantidMDAlgorithms/CreateMDWorkspace.h + inc/MantidMDAlgorithms/CutMD.h inc/MantidMDAlgorithms/DivideMD.h inc/MantidMDAlgorithms/DllConfig.h inc/MantidMDAlgorithms/EqualToMD.h @@ -195,6 +197,7 @@ set ( TEST_FILES ConvertToQ3DdETest.h CreateMDHistoWorkspaceTest.h CreateMDWorkspaceTest.h + CutMDTest.h DivideMDTest.h EqualToMDTest.h EvaluateMDFunctionTest.h diff --git a/Code/Mantid/Framework/MDAlgorithms/inc/MantidMDAlgorithms/CutMD.h b/Code/Mantid/Framework/MDAlgorithms/inc/MantidMDAlgorithms/CutMD.h new file mode 100644 index 0000000000000000000000000000000000000000..2ad56c17ac8fb378531609d91df78f79a2aaeee7 --- /dev/null +++ b/Code/Mantid/Framework/MDAlgorithms/inc/MantidMDAlgorithms/CutMD.h @@ -0,0 +1,58 @@ +#ifndef MANTID_MDALGORITHMS_CUTMD_H_ +#define MANTID_MDALGORITHMS_CUTMD_H_ + +#include "MantidKernel/System.h" +#include "MantidAPI/Algorithm.h" +#include "MantidAPI/DataProcessorAlgorithm.h" + +namespace Mantid { +namespace MDAlgorithms { + +/** CutMD : Slices multidimensional workspaces. + + @date 2015-03-20 + + Copyright © 2015 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge + National Laboratory & European Spallation Source + + 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://github.com/mantidproject/mantid> + Code Documentation is available at: <http://doxygen.mantidproject.org> +*/ +class DLLExport CutMD : public API::DataProcessorAlgorithm { +public: + CutMD(); + virtual ~CutMD(); + + virtual const std::string name() const { return "CutMD"; } + virtual int version() const { return 1; } + virtual const std::string summary() const { + return "Slices multidimensional workspaces using input projection " + "information and binning limits."; + } + virtual const std::string category() const { return "MDAlgorithms"; } + + virtual void init(); + virtual void exec(); + +private: +}; + +} // namespace MDAlgorithms +} // namespace Mantid + +#endif /* MANTID_MDALGORITHMS_CUTMD_H_ */ diff --git a/Code/Mantid/Framework/MDAlgorithms/src/CutMD.cpp b/Code/Mantid/Framework/MDAlgorithms/src/CutMD.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8954f003c7f77163ece08edc3f7e5f891e79227f --- /dev/null +++ b/Code/Mantid/Framework/MDAlgorithms/src/CutMD.cpp @@ -0,0 +1,445 @@ +#include "MantidMDAlgorithms/CutMD.h" +#include "MantidAPI/IMDEventWorkspace.h" +#include "MantidGeometry/Crystal/OrientedLattice.h" +#include "MantidKernel/ArrayProperty.h" +#include "MantidKernel/Matrix.h" +#include "MantidKernel/System.h" + +using namespace Mantid::API; +using namespace Mantid::Geometry; +using namespace Mantid::Kernel; + +namespace { + +// Typedef to simplify function signatures +typedef std::pair<double, double> MinMax; + +MinMax getDimensionExtents(IMDEventWorkspace_sptr ws, size_t index) { + if (!ws) + throw std::runtime_error( + "Invalid workspace passed to getDimensionExtents."); + auto dim = ws->getDimension(index); + return std::make_pair(dim->getMinimum(), dim->getMaximum()); +} + +DblMatrix matrixFromProjection(ITableWorkspace_sptr projection) { + if (!projection) { + return DblMatrix(3, 3, true /* makeIdentity */); + } + + const size_t numDims = projection->rowCount(); + DblMatrix ret(3, 3); + for (size_t i = 0; i < numDims; i++) { + const std::string name = + projection->getColumn("name")->cell<std::string>(i); + const std::string valueStr = + projection->getColumn("value")->cell<std::string>(i); + std::vector<std::string> valueStrVec; + boost::split(valueStrVec, valueStr, boost::is_any_of(",")); + + std::vector<double> valueDblVec; + for (auto it = valueStrVec.begin(); it != valueStrVec.end(); ++it) + valueDblVec.push_back(boost::lexical_cast<double>(*it)); + + if (name == "u") + ret.setRow(0, valueDblVec); + else if (name == "v") + ret.setRow(1, valueDblVec); + else if (name == "w") + ret.setRow(2, valueDblVec); + } + return ret; +} + +std::vector<std::string> unitsFromProjection(ITableWorkspace_sptr projection) { + std::vector<std::string> ret(3, "r"); + if (!projection) + return ret; + + const size_t numDims = projection->rowCount(); + for (size_t i = 0; i < numDims; i++) { + const std::string name = + projection->getColumn("name")->cell<std::string>(i); + const std::string unit = + projection->getColumn("type")->cell<std::string>(i); + + if (name == "u") + ret[0] = unit; + else if (name == "v") + ret[1] = unit; + else if (name == "w") + ret[2] = unit; + } + return ret; +} + +DblMatrix scaleProjection(const DblMatrix &inMatrix, + const std::vector<std::string> &inUnits, + const std::vector<std::string> &outUnits, + IMDEventWorkspace_sptr inWS) { + DblMatrix ret(inMatrix); + // Check if we actually need to do anything + if (std::equal(inUnits.begin(), inUnits.end(), outUnits.begin())) + return ret; + + if (inUnits.size() != outUnits.size()) + throw std::runtime_error( + "scaleProjection given different quantity of input and output units"); + + const OrientedLattice &orientedLattice = + inWS->getExperimentInfo(0)->sample().getOrientedLattice(); + + const size_t numDims = inUnits.size(); + for (size_t i = 0; i < numDims; ++i) { + const double dStar = + 2 * M_PI * + orientedLattice.dstar(inMatrix[i][0], inMatrix[i][1], inMatrix[i][2]); + if (inUnits[i] == outUnits[i]) + continue; + else if (inUnits[i] == "a") { + // inv angstroms to rlu + for (size_t j = 0; j < numDims; ++j) + ret[i][j] *= dStar; + } else { + // rlu to inv angstroms + for (size_t j = 0; j < numDims; ++j) + ret[i][j] /= dStar; + } + } + + return ret; +} + +std::vector<MinMax> calculateExtents(const DblMatrix &inMatrix, + const std::vector<MinMax> &limits) { + DblMatrix invMat(inMatrix); + invMat.Invert(); + + // iterate through min/max of each dimension, calculate dot(vert, inv_mat) + // and store min/max value for each dimension + std::vector<double> hRange(2), kRange(2), lRange(2); + + hRange[0] = limits[0].first; + hRange[1] = limits[0].second; + kRange[0] = limits[1].first; + kRange[1] = limits[1].second; + lRange[0] = limits[2].first; + lRange[1] = limits[2].second; + + // Calculate the minimums and maximums of transformed coordinates + // Use maxDbl as a "not-yet-set" placeholder + const double maxDbl = std::numeric_limits<double>::max(); + std::vector<MinMax> extents(3, std::make_pair(maxDbl, maxDbl)); + + for (auto hIt = hRange.begin(); hIt != hRange.end(); ++hIt) { + for (auto kIt = kRange.begin(); kIt != kRange.end(); ++kIt) { + for (auto lIt = lRange.begin(); lIt != lRange.end(); ++lIt) { + V3D origPos(*hIt, *kIt, *lIt); + for (size_t i = 0; i < 3; ++i) { + const V3D other(invMat[i][0], invMat[i][1], invMat[i][2]); + double val = origPos.scalar_prod(other); + // Check if min needs updating + if (extents[i].first == maxDbl || extents[i].first > val) + extents[i].first = val; + // Check if max needs updating + if (extents[i].second == maxDbl || extents[i].second < val) + extents[i].second = val; + } + } + } + } + + return extents; +} + +std::pair<std::vector<MinMax>, std::vector<int>> +calculateSteps(const std::vector<MinMax> &inExtents, + const std::vector<std::vector<double>> &binning) { + std::vector<MinMax> outExtents(inExtents); + std::vector<int> outBins; + + for (size_t i = 0; i < inExtents.size(); ++i) { + const size_t nArgs = binning[i].size(); + int outBin = -1; + + if (nArgs == 0) { + throw std::runtime_error("Binning parameter cannot be empty"); + + } else if (nArgs == 1) { + const double dimRange = inExtents[i].second - inExtents[i].first; + const double stepSize = + binning[i][0] < dimRange ? binning[i][0] : dimRange; + outBin = static_cast<int>(dimRange / stepSize); + outExtents[i].second = inExtents[i].first + outBin * stepSize; + + } else if (nArgs == 2) { + outExtents[i].first = binning[i][0]; + outExtents[i].second = binning[i][1]; + outBin = 1; + + } else if (nArgs == 3) { + const double dimMin = binning[i][0]; + const double dimMax = binning[i][2]; + const double dimRange = dimMax - dimMin; + const double stepSize = + binning[i][1] < dimRange ? binning[i][1] : dimRange; + outBin = static_cast<int>(dimRange / stepSize); + outExtents[i].second = dimMin + outBin * stepSize; + outExtents[i].first = dimMin; + + } else { + throw std::runtime_error("Cannot handle " + + boost::lexical_cast<std::string>(nArgs) + + " bins."); + } + if (outBin < 0) + throw std::runtime_error("output bin calculated to be less than 0"); + outBins.push_back(outBin); + } + return std::make_pair(outExtents, outBins); +} + +std::vector<std::string> labelProjection(const DblMatrix &projection) { + const std::string replacements[] = {"zeta", "eta", "xi"}; + std::vector<std::string> ret(3); + std::vector<std::string> labels(3); + + for (size_t i = 0; i < 3; ++i) { + for (size_t j = 0; j < 3; ++j) { + const double in = projection[i][j]; + if (std::abs(in) == 1) + if (in > 0) + labels[j] = "'" + replacements[i] + "'"; + else + labels[j] = "'-" + replacements[i] + "'"; + else if (in == 0) + labels[j] = "0"; + else { + // We have to be explicit about precision, so lexical cast won't work + std::stringstream s; + s.precision(2); + s.setf(std::ios::fixed, std::ios::floatfield); + s << "'" << in << replacements[i] << "'"; + labels[j] = s.str(); + } + } + ret[i] = "[" + boost::algorithm::join(labels, ", ") + "]"; + } + return ret; +} +} // anonymous namespace + +namespace Mantid { +namespace MDAlgorithms { + +// Register the algorithm into the AlgorithmFactory +DECLARE_ALGORITHM(CutMD) + +//---------------------------------------------------------------------------------------------- +/** Constructor + */ +CutMD::CutMD() {} + +//---------------------------------------------------------------------------------------------- +/** Destructor + */ +CutMD::~CutMD() {} + +//---------------------------------------------------------------------------------------------- + +void CutMD::init() { + declareProperty(new WorkspaceProperty<IMDEventWorkspace>("InputWorkspace", "", + Direction::Input), + "MDWorkspace to slice"); + + declareProperty( + new WorkspaceProperty<ITableWorkspace>("Projection", "", Direction::Input, + PropertyMode::Optional), + "Projection"); + + declareProperty(new ArrayProperty<double>("P1Bin"), "Projection 1 binning."); + declareProperty(new ArrayProperty<double>("P2Bin"), "Projection 2 binning."); + declareProperty(new ArrayProperty<double>("P3Bin"), "Projection 3 binning."); + declareProperty(new ArrayProperty<double>("P4Bin"), "Projection 4 binning."); + declareProperty(new ArrayProperty<double>("P5Bin"), "Projection 5 binning."); + + declareProperty(new WorkspaceProperty<IMDWorkspace>("OutputWorkspace", "", + Direction::Output), + "Output cut workspace"); + declareProperty("NoPix", false, "If False creates a full MDEventWorkspaces " + "as output. True to create an " + "MDHistoWorkspace as output. This is DND " + "only in Horace terminology."); + declareProperty("CheckAxes", true, + "Check that the axis look to be correct, and abort if not."); +} + +void CutMD::exec() { + g_log.warning("CutMD is in the beta stage of development. Its properties and " + "behaviour may change without warning."); + + // Collect input properties + const IMDEventWorkspace_sptr inWS = getProperty("InputWorkspace"); + const size_t numDims = inWS->getNumDims(); + const ITableWorkspace_sptr projection = getProperty("Projection"); + std::vector<std::vector<double>> pbins(5); + pbins[0] = getProperty("P1Bin"); + pbins[1] = getProperty("P2Bin"); + pbins[2] = getProperty("P3Bin"); + pbins[3] = getProperty("P4Bin"); + pbins[4] = getProperty("P5Bin"); + const bool noPix = getProperty("NoPix"); + + // Check Projection format + if (projection) { + auto colNames = projection->getColumnNames(); + if (colNames.size() != 4 || + std::find(colNames.begin(), colNames.end(), "name") == colNames.end() || + std::find(colNames.begin(), colNames.end(), "value") == + colNames.end() || + std::find(colNames.begin(), colNames.end(), "offset") == + colNames.end() || + std::find(colNames.begin(), colNames.end(), "type") == colNames.end()) + throw std::runtime_error( + "Invalid Projection supplied. Please check column names."); + if (projection->rowCount() < 3) + throw std::runtime_error( + "Insufficient rows in projection table. Must be 3 or more."); + } + // Check PBin properties + for (size_t i = 0; i < 5; ++i) { + if (i < numDims && pbins[i].empty()) + throw std::runtime_error( + "P" + boost::lexical_cast<std::string>(i + 1) + + "Bin must be set when processing a workspace with " + + boost::lexical_cast<std::string>(numDims) + " dimensions."); + if (i >= numDims && !pbins[i].empty()) + throw std::runtime_error( + "P" + boost::lexical_cast<std::string>(i + 1) + + "Bin must NOT be set when processing a workspace with " + + boost::lexical_cast<std::string>(numDims) + " dimensions."); + } + + // Get extents in projection + std::vector<MinMax> extentLimits; + extentLimits.push_back(getDimensionExtents(inWS, 0)); + extentLimits.push_back(getDimensionExtents(inWS, 1)); + extentLimits.push_back(getDimensionExtents(inWS, 2)); + + // Scale projection + DblMatrix projectionMatrix = matrixFromProjection(projection); + std::vector<std::string> targetUnits = unitsFromProjection(projection); + std::vector<std::string> originUnits(3); // TODO. This is a hack! + originUnits[0] = "r"; + originUnits[1] = "r"; + originUnits[2] = "r"; + + DblMatrix scaledProjectionMatrix = + scaleProjection(projectionMatrix, originUnits, targetUnits, inWS); + + // Calculate extents for the first 3 dimensions + std::vector<MinMax> scaledExtents = + calculateExtents(scaledProjectionMatrix, extentLimits); + auto stepPair = calculateSteps(scaledExtents, pbins); + std::vector<MinMax> steppedExtents = stepPair.first; + std::vector<int> steppedBins = stepPair.second; + + // Calculate extents for additional dimensions + for (size_t i = 3; i < numDims; ++i) { + const size_t nArgs = pbins[i].size(); + const MinMax extentLimit = getDimensionExtents(inWS, i); + const double dimRange = extentLimit.second - extentLimit.first; + + if (nArgs == 1) { + steppedExtents.push_back(extentLimit); + steppedBins.push_back(static_cast<int>(dimRange / pbins[i][0])); + } else if (nArgs == 2) { + steppedExtents.push_back(std::make_pair(pbins[i][0], pbins[i][1])); + steppedBins.push_back(1); + } else if (nArgs == 3) { + const double dimRange = pbins[i][2] - pbins[i][0]; + const double stepSize = pbins[i][1] < dimRange ? pbins[i][1] : dimRange; + steppedExtents.push_back(std::make_pair(pbins[i][0], pbins[i][2])); + steppedBins.push_back(static_cast<int>(dimRange / stepSize)); + } + + // and double targetUnits' length by appending itself to itself + size_t preSize = targetUnits.size(); + targetUnits.resize(preSize * 2); + for (size_t i = 0; i < preSize; ++i) + targetUnits[preSize + i] = targetUnits[i]; + } + + // Make labels + std::vector<std::string> labels = labelProjection(projectionMatrix); + + // Either run RebinMD or SliceMD + const std::string cutAlgName = noPix ? "BinMD" : "SliceMD"; + IAlgorithm_sptr cutAlg = createChildAlgorithm(cutAlgName, 0.0, 1.0); + cutAlg->initialize(); + cutAlg->setProperty("InputWorkspace", inWS); + cutAlg->setProperty("OutputWorkspace", "sliced"); + cutAlg->setProperty("NormalizeBasisVectors", false); + cutAlg->setProperty("AxisAligned", false); + + for (size_t i = 0; i < numDims; ++i) { + std::string label; + std::string unit; + std::string vecStr; + + if (i < 3) { + // Slicing algorithms accept name as [x, y, z] + label = labels[i]; + unit = targetUnits[i]; + + std::vector<std::string> vec(numDims, "0"); + for (size_t j = 0; j < 3; ++j) + vec[j] = boost::lexical_cast<std::string>(projectionMatrix[i][j]); + vecStr = boost::algorithm::join(vec, ", "); + } else { + // Always orthogonal + auto dim = inWS->getDimension(i); + label = dim->getName(); + unit = dim->getUnits(); + std::vector<std::string> vec(numDims, "0"); + vec[i] = "1"; + vecStr = boost::algorithm::join(vec, ", "); + } + + const std::string value = label + ", " + unit + ", " + vecStr; + cutAlg->setProperty("BasisVector" + boost::lexical_cast<std::string>(i), + value); + } + + // Translate extents into a single vector + std::vector<double> outExtents(steppedExtents.size() * 2); + for (size_t i = 0; i < steppedExtents.size(); ++i) { + outExtents[2 * i] = steppedExtents[i].first; + outExtents[2 * i + 1] = steppedExtents[i].second; + } + + cutAlg->setProperty("OutputExtents", outExtents); + cutAlg->setProperty("OutputBins", steppedBins); + + cutAlg->execute(); + Workspace_sptr sliceWS = cutAlg->getProperty("OutputWorkspace"); + MultipleExperimentInfos_sptr sliceInfo = + boost::dynamic_pointer_cast<MultipleExperimentInfos>(sliceWS); + + if (!sliceInfo) + throw std::runtime_error( + "Could not extract experiment info from child's OutputWorkspace"); + + // Attach projection matrix to output + if (sliceInfo->getNumExperimentInfo() > 0) { + ExperimentInfo_sptr info = sliceInfo->getExperimentInfo(0); + info->mutableRun().addProperty("W_MATRIX", projectionMatrix.getVector(), + true); + } + + // Done! + setProperty("OutputWorkspace", sliceWS); +} + +} // namespace Mantid +} // namespace MDAlgorithms diff --git a/Code/Mantid/Framework/MDAlgorithms/src/SliceMD.cpp b/Code/Mantid/Framework/MDAlgorithms/src/SliceMD.cpp index f59e3e3feb2b3652bee30a9a800cc786d3ce348a..3519c4677ecaa8dcb17cd28e9dd6946f8547f368 100644 --- a/Code/Mantid/Framework/MDAlgorithms/src/SliceMD.cpp +++ b/Code/Mantid/Framework/MDAlgorithms/src/SliceMD.cpp @@ -44,8 +44,8 @@ void SliceMD::init() { // Properties for specifying the slice to perform. this->initSlicingProps(); - declareProperty(new WorkspaceProperty<IMDEventWorkspace>( - "OutputWorkspace", "", Direction::Output), + declareProperty(new WorkspaceProperty<Workspace>("OutputWorkspace", "", + Direction::Output), "Name of the output MDEventWorkspace."); std::vector<std::string> exts; diff --git a/Code/Mantid/Framework/MDAlgorithms/test/CutMDTest.h b/Code/Mantid/Framework/MDAlgorithms/test/CutMDTest.h new file mode 100644 index 0000000000000000000000000000000000000000..b93b6c4d0dcfefd3662c8551d25529e689c973ff --- /dev/null +++ b/Code/Mantid/Framework/MDAlgorithms/test/CutMDTest.h @@ -0,0 +1,490 @@ +#ifndef MANTID_MDALGORITHMS_CUTMDTEST_H_ +#define MANTID_MDALGORITHMS_CUTMDTEST_H_ + +#include "MantidMDAlgorithms/CutMD.h" + +#include "MantidAPI/FrameworkManager.h" +#include "MantidAPI/IMDWorkspace.h" +#include "MantidAPI/IMDEventWorkspace.h" +#include "MantidAPI/IMDHistoWorkspace.h" +#include "MantidAPI/TableRow.h" + +#include <cxxtest/TestSuite.h> + +using namespace Mantid::MDAlgorithms; +using namespace Mantid::API; +using namespace Mantid::Kernel; + +namespace { +const std::string sharedWSName = "__CutMDTest_dataWS"; +} + +class CutMDTest : public CxxTest::TestSuite { +private: + IMDWorkspace_sptr m_inWS; + +public: + CutMDTest() { + FrameworkManager::Instance().exec("CreateMDWorkspace", 10, + "OutputWorkspace", sharedWSName.c_str(), + "Dimensions", "3", + "Extents", "-10,10,-10,10,-10,10", + "Names", "A,B,C", + "Units", "U,U,U"); + + FrameworkManager::Instance().exec("SetSpecialCoordinates", 4, + "InputWorkspace", sharedWSName.c_str(), + "SpecialCoordinates", "HKL"); + + FrameworkManager::Instance().exec("SetUB", 14, + "Workspace", sharedWSName.c_str(), + "a", "1", + "b", "1", + "c", "1", + "alpha", "90", + "beta", "90", + "gamma", "90"); + + FrameworkManager::Instance().exec("FakeMDEventData", 4, + "InputWorkspace", sharedWSName.c_str(), + "PeakParams", "10000,0,0,0,1"); + + m_inWS = + AnalysisDataService::Instance().retrieveWS<IMDWorkspace>(sharedWSName); + } + + virtual ~CutMDTest() { AnalysisDataService::Instance().remove(sharedWSName); } + + // This pair of boilerplate methods prevent the suite being created statically + // This means the constructor isn't called when running other tests + static CutMDTest *createSuite() { return new CutMDTest(); } + static void destroySuite(CutMDTest *suite) { delete suite; } + + void test_init() { + CutMD alg; + TS_ASSERT_THROWS_NOTHING(alg.initialize()) + TS_ASSERT(alg.isInitialized()) + } + + void test_exec_throws_if_giving_4th_binning_param_when_workspace_is_3d() { + const std::string wsName = "__CutMDTest_4thbinon3dthrows"; + + FrameworkManager::Instance().exec("CreateMDWorkspace", 10, + "OutputWorkspace", wsName.c_str(), + "Dimensions", "3", + "Extents", "-10,10,-10,10,-10,10", + "Names", "H,K,L", + "Units", "U,U,U"); + + FrameworkManager::Instance().exec("SetSpecialCoordinates", 4, + "InputWorkspace", wsName.c_str(), + "SpecialCoordinates", "HKL"); + + auto algCutMD = FrameworkManager::Instance().createAlgorithm("CutMD"); + algCutMD->initialize(); + algCutMD->setRethrows(true); + algCutMD->setProperty("InputWorkspace", wsName); + algCutMD->setProperty("OutputWorkspace", wsName); + algCutMD->setProperty("P1Bin", "0.1"); + algCutMD->setProperty("P2Bin", "0.1"); + algCutMD->setProperty("P3Bin", "0.1"); + algCutMD->setProperty("P4Bin", "0.1"); + TS_ASSERT_THROWS(algCutMD->execute(), std::runtime_error) + + AnalysisDataService::Instance().remove(wsName); + } + + void test_slice_to_original() { + const std::string wsName = "__CutMDTest_slice_to_original"; + + auto algCutMD = FrameworkManager::Instance().createAlgorithm("CutMD"); + algCutMD->initialize(); + algCutMD->setRethrows(true); + algCutMD->setProperty("InputWorkspace", sharedWSName); + algCutMD->setProperty("OutputWorkspace", wsName); + algCutMD->setProperty("P1Bin", "0.1"); + algCutMD->setProperty("P2Bin", "0.1"); + algCutMD->setProperty("P3Bin", "0.1"); + algCutMD->setProperty("CheckAxes", false); + algCutMD->execute(); + TS_ASSERT(algCutMD->isExecuted()); + + IMDEventWorkspace_sptr outWS = + AnalysisDataService::Instance().retrieveWS<IMDEventWorkspace>(wsName); + TS_ASSERT(outWS.get()); + + TS_ASSERT_EQUALS( + outWS->getDimension(0)->getMinimum(), + m_inWS->getDimension(0)->getMinimum()); + TS_ASSERT_EQUALS( + outWS->getDimension(0)->getMaximum(), + m_inWS->getDimension(0)->getMaximum()); + TS_ASSERT_EQUALS( + outWS->getDimension(1)->getMinimum(), + m_inWS->getDimension(1)->getMinimum()); + TS_ASSERT_EQUALS( + outWS->getDimension(1)->getMaximum(), + m_inWS->getDimension(1)->getMaximum()); + TS_ASSERT_EQUALS( + outWS->getDimension(2)->getMinimum(), + m_inWS->getDimension(2)->getMinimum()); + TS_ASSERT_EQUALS( + outWS->getDimension(2)->getMaximum(), + m_inWS->getDimension(2)->getMaximum()); + + TS_ASSERT_EQUALS("['zeta', 0, 0]", outWS->getDimension(0)->getName()); + TS_ASSERT_EQUALS("[0, 'eta', 0]", outWS->getDimension(1)->getName()); + TS_ASSERT_EQUALS("[0, 0, 'xi']", outWS->getDimension(2)->getName()); + + AnalysisDataService::Instance().remove(wsName); + } + + void test_recalculate_extents_with_3_bin_arguments() { + const std::string wsName = "__CutMDTest_recalc_extents_with_3_bin_args"; + + auto algCutMD = FrameworkManager::Instance().createAlgorithm("CutMD"); + algCutMD->initialize(); + algCutMD->setRethrows(true); + algCutMD->setProperty("InputWorkspace", sharedWSName); + algCutMD->setProperty("OutputWorkspace", wsName); + algCutMD->setProperty("P1Bin", "0,0.3,0.8"); + algCutMD->setProperty("P2Bin", "0.1"); + algCutMD->setProperty("P3Bin", "0.1"); + algCutMD->setProperty("CheckAxes", false); + algCutMD->setProperty("NoPix", true); + algCutMD->execute(); + TS_ASSERT(algCutMD->isExecuted()); + + IMDWorkspace_sptr outWS = + AnalysisDataService::Instance().retrieveWS<IMDWorkspace>(wsName); + TS_ASSERT(outWS.get()); + + TS_ASSERT_DELTA(outWS->getDimension(0)->getMinimum(), 0.0, 1E-6); + TS_ASSERT_DELTA(outWS->getDimension(0)->getMaximum(), 0.6, 1E-6); + TS_ASSERT_EQUALS(outWS->getDimension(0)->getNBins(), 2); + + AnalysisDataService::Instance().remove(wsName); + } + + void test_truncate_extents() { + const std::string wsName = "__CutMDTest_truncate_extents"; + + auto algCutMD = FrameworkManager::Instance().createAlgorithm("CutMD"); + algCutMD->initialize(); + algCutMD->setRethrows(true); + algCutMD->setProperty("InputWorkspace", sharedWSName); + algCutMD->setProperty("OutputWorkspace", wsName); + algCutMD->setProperty("P1Bin", "0,1.1,1"); + algCutMD->setProperty("P2Bin", "21"); + algCutMD->setProperty("P3Bin", "0.1"); + algCutMD->setProperty("CheckAxes", false); + algCutMD->setProperty("NoPix", true); + algCutMD->execute(); + TS_ASSERT(algCutMD->isExecuted()); + + IMDWorkspace_sptr outWS = + AnalysisDataService::Instance().retrieveWS<IMDWorkspace>(wsName); + TS_ASSERT(outWS.get()); + + TS_ASSERT_EQUALS(outWS->getDimension(0)->getNBins(), 1); + TS_ASSERT_EQUALS(outWS->getDimension(1)->getNBins(), 1); + + AnalysisDataService::Instance().remove(wsName); + } + + void test_wrong_proj_format_columns() { + const std::string wsName = "__CutMDTest_wrong_proj_columns"; + + ITableWorkspace_sptr proj = WorkspaceFactory::Instance().createTable(); + proj->addColumn("str", "name"); + + auto algCutMD = FrameworkManager::Instance().createAlgorithm("CutMD"); + algCutMD->initialize(); + algCutMD->setRethrows(true); + algCutMD->setProperty("InputWorkspace", sharedWSName); + algCutMD->setProperty("OutputWorkspace", wsName); + algCutMD->setProperty("Projection", proj); + algCutMD->setProperty("P1Bin", "0.1"); + algCutMD->setProperty("P2Bin", "0.2"); + algCutMD->setProperty("P3Bin", "0.1"); + algCutMD->setProperty("CheckAxes", false); + TS_ASSERT_THROWS(algCutMD->execute(), std::runtime_error); + } + + void test_wrong_proj_format_rows() { + const std::string wsName = "__CutMDTest_wrong_proj_rows"; + + // Correct columns + ITableWorkspace_sptr proj = WorkspaceFactory::Instance().createTable(); + proj->addColumn("str", "name"); + proj->addColumn("str", "value"); + proj->addColumn("double", "offset"); + proj->addColumn("str", "type"); + // ...but no rows + + auto algCutMD = FrameworkManager::Instance().createAlgorithm("CutMD"); + algCutMD->initialize(); + algCutMD->setRethrows(true); + algCutMD->setProperty("InputWorkspace", sharedWSName); + algCutMD->setProperty("OutputWorkspace", wsName); + algCutMD->setProperty("Projection", proj); + algCutMD->setProperty("P1Bin", "0.1"); + algCutMD->setProperty("P2Bin", "0.2"); + algCutMD->setProperty("P3Bin", "0.1"); + algCutMD->setProperty("CheckAxes", false); + TS_ASSERT_THROWS(algCutMD->execute(), std::runtime_error); + } + + void test_orthogonal_slice_with_scaling() { + const std::string wsName = "__CutMDTest_orthog_slice_with_scaling"; + + FrameworkManager::Instance().exec("CreateMDWorkspace", 10, + "OutputWorkspace", wsName.c_str(), + "Dimensions", "3", + "Extents", "-1,1,-1,1,-1,1", + "Names", "H,K,L", + "Units", "U,U,U"); + + FrameworkManager::Instance().exec("SetUB", 14, + "Workspace", wsName.c_str(), + "a", "1", "b", "1", "c", "1", + "alpha", "90", "beta", "90", "gamma", "90"); + + FrameworkManager::Instance().exec("SetSpecialCoordinates", 4, + "InputWorkspace", wsName.c_str(), + "SpecialCoordinates", "HKL"); + + ITableWorkspace_sptr proj = WorkspaceFactory::Instance().createTable(); + proj->addColumn("str", "name"); + proj->addColumn("str", "value"); + proj->addColumn("double", "offset"); + proj->addColumn("str", "type"); + + TableRow uRow = proj->appendRow(); + TableRow vRow = proj->appendRow(); + TableRow wRow = proj->appendRow(); + uRow << "u" << "1,0,0" << 0.0 << "r"; + vRow << "v" << "0,1,0" << 0.0 << "r"; + wRow << "w" << "0,0,1" << 0.0 << "r"; + + auto algCutMD = FrameworkManager::Instance().createAlgorithm("CutMD"); + algCutMD->initialize(); + algCutMD->setRethrows(true); + algCutMD->setProperty("InputWorkspace", wsName); + algCutMD->setProperty("OutputWorkspace", wsName); + algCutMD->setProperty("Projection", proj); + algCutMD->setProperty("P1Bin", "-0.5,0.5"); + algCutMD->setProperty("P2Bin", "-0.1,0.1"); + algCutMD->setProperty("P3Bin", "-0.3,0.3"); + algCutMD->setProperty("NoPix", true); + algCutMD->execute(); + TS_ASSERT(algCutMD->isExecuted()); + + IMDHistoWorkspace_sptr outWS = + AnalysisDataService::Instance().retrieveWS<IMDHistoWorkspace>(wsName); + TS_ASSERT(outWS.get()); + + TS_ASSERT_DELTA(outWS->getDimension(0)->getMinimum(), -0.5, 1E-6); + TS_ASSERT_DELTA(outWS->getDimension(0)->getMaximum(), 0.5, 1E-6); + TS_ASSERT_DELTA(outWS->getDimension(1)->getMinimum(), -0.1, 1E-6); + TS_ASSERT_DELTA(outWS->getDimension(1)->getMaximum(), 0.1, 1E-6); + TS_ASSERT_DELTA(outWS->getDimension(2)->getMinimum(), -0.3, 1E-6); + TS_ASSERT_DELTA(outWS->getDimension(2)->getMaximum(), 0.3, 1E-6); + TS_ASSERT_EQUALS("['zeta', 0, 0]", outWS->getDimension(0)->getName()); + TS_ASSERT_EQUALS("[0, 'eta', 0]", outWS->getDimension(1)->getName()); + TS_ASSERT_EQUALS("[0, 0, 'xi']", outWS->getDimension(2)->getName()); + + AnalysisDataService::Instance().remove(wsName); + } + + void test_non_orthogonal_slice() { + const std::string wsName = "__CutMDTest_non_orthog_slice"; + + FrameworkManager::Instance().exec("CreateMDWorkspace", 10, + "OutputWorkspace", wsName.c_str(), + "Dimensions", "3", + "Extents", "-1,1,-1,1,-1,1", + "Names", "H,K,L", + "Units", "U,U,U"); + + FrameworkManager::Instance().exec("SetUB", 14, + "Workspace", wsName.c_str(), + "a", "1", "b", "1", "c", "1", + "alpha", "90", "beta", "90", "gamma", "90"); + + FrameworkManager::Instance().exec("SetSpecialCoordinates", 4, + "InputWorkspace", wsName.c_str(), + "SpecialCoordinates", "HKL"); + + ITableWorkspace_sptr proj = WorkspaceFactory::Instance().createTable(); + proj->addColumn("str", "name"); + proj->addColumn("str", "value"); + proj->addColumn("double", "offset"); + proj->addColumn("str", "type"); + + TableRow uRow = proj->appendRow(); + TableRow vRow = proj->appendRow(); + TableRow wRow = proj->appendRow(); + uRow << "u" << "1,1,0" << 0.0 << "r"; + vRow << "v" << "-1,1,0" << 0.0 << "r"; + wRow << "w" << "0,0,1" << 0.0 << "r"; + + auto algCutMD = FrameworkManager::Instance().createAlgorithm("CutMD"); + algCutMD->initialize(); + algCutMD->setRethrows(true); + algCutMD->setProperty("InputWorkspace", wsName); + algCutMD->setProperty("OutputWorkspace", wsName); + algCutMD->setProperty("Projection", proj); + algCutMD->setProperty("P1Bin", "0.1"); + algCutMD->setProperty("P2Bin", "0.1"); + algCutMD->setProperty("P3Bin", "0.1"); + algCutMD->setProperty("NoPix", true); + algCutMD->execute(); + TS_ASSERT(algCutMD->isExecuted()); + + IMDHistoWorkspace_sptr outWS = + AnalysisDataService::Instance().retrieveWS<IMDHistoWorkspace>(wsName); + TS_ASSERT(outWS.get()); + + TS_ASSERT_EQUALS(outWS->getDimension(0)->getMinimum(), -1); + TS_ASSERT_EQUALS(outWS->getDimension(0)->getMaximum(), 1); + TS_ASSERT_EQUALS(outWS->getDimension(1)->getMinimum(), -1); + TS_ASSERT_EQUALS(outWS->getDimension(1)->getMaximum(), 1); + TS_ASSERT_EQUALS(outWS->getDimension(2)->getMinimum(), -1); + TS_ASSERT_EQUALS(outWS->getDimension(2)->getMaximum(), 1); + TS_ASSERT_EQUALS("['zeta', 'zeta', 0]", outWS->getDimension(0)->getName()); + TS_ASSERT_EQUALS("['-eta', 'eta', 0]", outWS->getDimension(1)->getName()); + TS_ASSERT_EQUALS("[0, 0, 'xi']", outWS->getDimension(2)->getName()); + + AnalysisDataService::Instance().remove(wsName); + } + + void test_orthogonal_slice_with_cropping() { + const std::string wsName = "__CutMDTest_orthog_slice_crop"; + + FrameworkManager::Instance().exec("CreateMDWorkspace", 10, + "OutputWorkspace", wsName.c_str(), + "Dimensions", "3", + "Extents", "-1,1,-1,1,-1,1", + "Names", "H,K,L", + "Units", "U,U,U"); + + FrameworkManager::Instance().exec("SetUB", 14, + "Workspace", wsName.c_str(), + "a", "1", "b", "1", "c", "1", + "alpha", "90", "beta", "90", "gamma", "90"); + + FrameworkManager::Instance().exec("SetSpecialCoordinates", 4, + "InputWorkspace", wsName.c_str(), + "SpecialCoordinates", "HKL"); + + ITableWorkspace_sptr proj = WorkspaceFactory::Instance().createTable(); + proj->addColumn("str", "name"); + proj->addColumn("str", "value"); + proj->addColumn("double", "offset"); + proj->addColumn("str", "type"); + + TableRow uRow = proj->appendRow(); + TableRow vRow = proj->appendRow(); + TableRow wRow = proj->appendRow(); + uRow << "u" << "1,0,0" << 0.0 << "r"; + vRow << "v" << "0,1,0" << 0.0 << "r"; + wRow << "w" << "0,0,1" << 0.0 << "r"; + + auto algCutMD = FrameworkManager::Instance().createAlgorithm("CutMD"); + algCutMD->initialize(); + algCutMD->setRethrows(true); + algCutMD->setProperty("InputWorkspace", wsName); + algCutMD->setProperty("OutputWorkspace", wsName); + algCutMD->setProperty("Projection", proj); + algCutMD->setProperty("P1Bin", "-0.5,0.5"); + algCutMD->setProperty("P2Bin", "-0.1,0.1"); + algCutMD->setProperty("P3Bin", "-0.3,0.3"); + algCutMD->setProperty("NoPix", true); + algCutMD->execute(); + TS_ASSERT(algCutMD->isExecuted()); + + IMDHistoWorkspace_sptr outWS = + AnalysisDataService::Instance().retrieveWS<IMDHistoWorkspace>(wsName); + TS_ASSERT(outWS.get()); + + TS_ASSERT_DELTA(outWS->getDimension(0)->getMinimum(), -0.5, 1E-6); + TS_ASSERT_DELTA(outWS->getDimension(0)->getMaximum(), 0.5, 1E-6); + TS_ASSERT_DELTA(outWS->getDimension(1)->getMinimum(), -0.1, 1E-6); + TS_ASSERT_DELTA(outWS->getDimension(1)->getMaximum(), 0.1, 1E-6); + TS_ASSERT_DELTA(outWS->getDimension(2)->getMinimum(), -0.3, 1E-6); + TS_ASSERT_DELTA(outWS->getDimension(2)->getMaximum(), 0.3, 1E-6); + TS_ASSERT_EQUALS("['zeta', 0, 0]", outWS->getDimension(0)->getName()); + TS_ASSERT_EQUALS("[0, 'eta', 0]", outWS->getDimension(1)->getName()); + TS_ASSERT_EQUALS("[0, 0, 'xi']", outWS->getDimension(2)->getName()); + + AnalysisDataService::Instance().remove(wsName); + } + + void test_orthogonal_slice_4d() { + const std::string wsName = "__CutMDTest_orthog_slice_4d"; + const std::string wsOutName = "__CutMDTest_orthog_slice_4d_out"; + + FrameworkManager::Instance().exec("CreateMDWorkspace", 10, + "OutputWorkspace", wsName.c_str(), + "Dimensions", "4", + "Extents", "-1,1,-1,1,-1,1,-10,10", + "Names", "H,K,L,E", + "Units", "U,U,U,V"); + + FrameworkManager::Instance().exec("SetUB", 14, + "Workspace", wsName.c_str(), + "a", "1", "b", "1", "c", "1", + "alpha", "90", "beta", "90", "gamma", "90"); + + FrameworkManager::Instance().exec("SetSpecialCoordinates", 4, + "InputWorkspace", wsName.c_str(), + "SpecialCoordinates", "HKL"); + + auto algCutMD = FrameworkManager::Instance().createAlgorithm("CutMD"); + algCutMD->initialize(); + algCutMD->setRethrows(true); + algCutMD->setProperty("InputWorkspace", wsName); + algCutMD->setProperty("OutputWorkspace", wsOutName); + algCutMD->setProperty("P1Bin", "-0.5,0.5"); + algCutMD->setProperty("P2Bin", "-0.1,0.1"); + algCutMD->setProperty("P3Bin", "-0.3,0.3"); + algCutMD->setProperty("P4Bin", "1"); + algCutMD->setProperty("NoPix", true); + algCutMD->execute(); + TS_ASSERT(algCutMD->isExecuted()); + + IMDHistoWorkspace_sptr outWS = + AnalysisDataService::Instance().retrieveWS<IMDHistoWorkspace>(wsOutName); + TS_ASSERT(outWS.get()); + + TS_ASSERT_DELTA(outWS->getDimension(0)->getMinimum(), -0.5, 1E-6); + TS_ASSERT_DELTA(outWS->getDimension(0)->getMaximum(), 0.5, 1E-6); + TS_ASSERT_DELTA(outWS->getDimension(1)->getMinimum(), -0.1, 1E-6); + TS_ASSERT_DELTA(outWS->getDimension(1)->getMaximum(), 0.1, 1E-6); + TS_ASSERT_DELTA(outWS->getDimension(2)->getMinimum(), -0.3, 1E-6); + TS_ASSERT_DELTA(outWS->getDimension(2)->getMaximum(), 0.3, 1E-6); + TS_ASSERT_DELTA(outWS->getDimension(3)->getMinimum(), -10, 1E-6); + TS_ASSERT_DELTA(outWS->getDimension(3)->getMaximum(), 10, 1E-6); + TS_ASSERT_EQUALS(20, outWS->getDimension(3)->getNBins()); + TS_ASSERT_EQUALS("['zeta', 0, 0]", outWS->getDimension(0)->getName()); + TS_ASSERT_EQUALS("[0, 'eta', 0]", outWS->getDimension(1)->getName()); + TS_ASSERT_EQUALS("[0, 0, 'xi']", outWS->getDimension(2)->getName()); + TS_ASSERT_EQUALS("E", outWS->getDimension(3)->getName()); + + // Process again with a different binning + algCutMD->setProperty("P4Bin", "-8,1,8"); + algCutMD->setProperty("InputWorkspace", wsName); + algCutMD->setProperty("OutputWorkspace", wsOutName); + algCutMD->execute(); + TS_ASSERT(algCutMD->isExecuted()); + outWS = + AnalysisDataService::Instance().retrieveWS<IMDHistoWorkspace>(wsOutName); + TS_ASSERT_EQUALS(16, outWS->getDimension(3)->getNBins()); + + AnalysisDataService::Instance().remove(wsName); + AnalysisDataService::Instance().remove(wsOutName); + } +}; + +#endif /* MANTID_MDALGORITHMS_CUTMDTEST_H_ */ diff --git a/Code/Mantid/Framework/MDAlgorithms/test/IntegratePeaksMD2Test.h b/Code/Mantid/Framework/MDAlgorithms/test/IntegratePeaksMD2Test.h index fa6a6d32befc2e784ee4d3cba77346bf73150d86..f83bbdd97a973797691f3b2780156a9f18e2b7d3 100644 --- a/Code/Mantid/Framework/MDAlgorithms/test/IntegratePeaksMD2Test.h +++ b/Code/Mantid/Framework/MDAlgorithms/test/IntegratePeaksMD2Test.h @@ -62,7 +62,7 @@ public: /** Run the IntegratePeaksMD2 with the given peak radius integration param */ static void doRun(double PeakRadius, double BackgroundRadius, std::string OutputWorkspace = "IntegratePeaksMD2Test_peaks", - double BackgroundStartRadius = 0.0, bool edge = true, bool cyl = false, std::string fnct = "NoFit") + double BackgroundStartRadius = 0.0, bool edge = true, bool cyl = false, std::string fnct = "NoFit", double adaptive = 0.0) { IntegratePeaksMD2 alg; TS_ASSERT_THROWS_NOTHING( alg.initialize() ) @@ -79,6 +79,8 @@ public: TS_ASSERT_THROWS_NOTHING( alg.setProperty("PercentBackground", 20.0 ) ); TS_ASSERT_THROWS_NOTHING( alg.setProperty("ProfileFunction", fnct ) ); TS_ASSERT_THROWS_NOTHING( alg.setProperty("IntegrationOption", "Sum" ) ); + TS_ASSERT_THROWS_NOTHING( alg.setProperty("AdaptiveQMultiplier", adaptive ) ); + if (adaptive > 0.0) TS_ASSERT_THROWS_NOTHING( alg.setProperty("AdaptiveQBackground", true ) ); TS_ASSERT_THROWS_NOTHING( alg.execute() ); TS_ASSERT( alg.isExecuted() ); } @@ -180,6 +182,15 @@ public: // Error is also calculated TS_ASSERT_DELTA( peakWS0->getPeak(0).getSigmaIntensity(), sqrt(2.0), 1e-2);*/ + + // ------------- Adaptive Integration r=MQ+b where b is PeakRadius and m is 0.01 ------------------------ + peakWS0->addPeak( Peak(inst, 15050, 1.0, V3D(2., 3., 4.) ) ); + doRun(0.1,0.0,"IntegratePeaksMD2Test_peaks",0.0,true,false,"NoFit",0.01); + TS_ASSERT_DELTA( peakWS0->getPeak(1).getIntensity(), 29.0, 1e-2); + + // Error is also calculated + TS_ASSERT_DELTA( peakWS0->getPeak(1).getSigmaIntensity(), sqrt(29.0), 1e-2); + // ------------- Integrate with 0.1 radius but IntegrateIfOnEdge false------------------------ doRun(0.1,0.0,"IntegratePeaksMD2Test_peaks",0.0,false); diff --git a/Code/Mantid/Framework/PythonInterface/mantid/geometry/CMakeLists.txt b/Code/Mantid/Framework/PythonInterface/mantid/geometry/CMakeLists.txt index 0bbe6d970e7a3ba89682aec7b667418a92fd1eef..ece3afcacc2c82c63bc6089d728cadc3fa0e1e56 100644 --- a/Code/Mantid/Framework/PythonInterface/mantid/geometry/CMakeLists.txt +++ b/Code/Mantid/Framework/PythonInterface/mantid/geometry/CMakeLists.txt @@ -25,6 +25,7 @@ set ( EXPORT_FILES src/Exports/Goniometer.cpp src/Exports/Object.cpp src/Exports/PeakShape.cpp + src/Exports/Group.cpp src/Exports/PointGroup.cpp src/Exports/PointGroupFactory.cpp src/Exports/SpaceGroup.cpp diff --git a/Code/Mantid/Framework/PythonInterface/mantid/geometry/src/Exports/Group.cpp b/Code/Mantid/Framework/PythonInterface/mantid/geometry/src/Exports/Group.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5a0cbef5c8d3b3d4e0575c92519cbc7c75358c4a --- /dev/null +++ b/Code/Mantid/Framework/PythonInterface/mantid/geometry/src/Exports/Group.cpp @@ -0,0 +1,20 @@ +#include "MantidGeometry/Crystal/Group.h" + +#include <boost/python/class.hpp> +#include <boost/python/enum.hpp> +#include <boost/python/scope.hpp> + +using Mantid::Geometry::Group; + +using namespace boost::python; + +void export_Group() +{ + enum_<Group::CoordinateSystem>("CoordinateSystem") + .value("Orthogonal", Group::Orthogonal) + .value("Hexagonal", Group::Hexagonal); + + class_<Group, boost::noncopyable>("Group", no_init) + .def("coordinateSystem", &Group::getCoordinateSystem); +} + diff --git a/Code/Mantid/Framework/PythonInterface/mantid/geometry/src/Exports/PointGroup.cpp b/Code/Mantid/Framework/PythonInterface/mantid/geometry/src/Exports/PointGroup.cpp index 545f5bbd984793b7ab20b2003e72f34d916b2e08..074c9aae7c1f8b678156c9566167a67948345bd1 100644 --- a/Code/Mantid/Framework/PythonInterface/mantid/geometry/src/Exports/PointGroup.cpp +++ b/Code/Mantid/Framework/PythonInterface/mantid/geometry/src/Exports/PointGroup.cpp @@ -1,4 +1,4 @@ - +#include "MantidGeometry/Crystal/Group.h" #include "MantidGeometry/Crystal/PointGroup.h" #include "MantidPythonInterface/kernel/Converters/PyObjectToV3D.h" @@ -8,6 +8,7 @@ #include <boost/python/list.hpp> #include <boost/python/register_ptr_to_python.hpp> +using Mantid::Geometry::Group; using Mantid::Geometry::PointGroup; using namespace boost::python; @@ -37,7 +38,6 @@ namespace //<unnamed> { return self.getReflectionFamily(Converters::PyObjectToV3D(hkl)()); } - } void export_PointGroup() @@ -55,7 +55,7 @@ void export_PointGroup() .value("Trigonal", PointGroup::Trigonal) .value("Cubic", PointGroup::Cubic); - class_<PointGroup, boost::noncopyable>("PointGroup", no_init) + class_<PointGroup, boost::noncopyable, bases<Group> >("PointGroup", no_init) .def("getName", &PointGroup::getName) .def("getSymbol", &PointGroup::getSymbol) .def("crystalSystem", &PointGroup::crystalSystem) diff --git a/Code/Mantid/Framework/PythonInterface/mantid/geometry/src/Exports/PointGroupFactory.cpp b/Code/Mantid/Framework/PythonInterface/mantid/geometry/src/Exports/PointGroupFactory.cpp index 6d36f2418c20274930b72c9914b4e4b28f1160c3..8700da8f509361a5dbe35f4554ef28d002b9b8dc 100644 --- a/Code/Mantid/Framework/PythonInterface/mantid/geometry/src/Exports/PointGroupFactory.cpp +++ b/Code/Mantid/Framework/PythonInterface/mantid/geometry/src/Exports/PointGroupFactory.cpp @@ -1,4 +1,5 @@ #include "MantidGeometry/Crystal/PointGroupFactory.h" +#include "MantidGeometry/Crystal/SpaceGroupFactory.h" #include "MantidPythonInterface/kernel/PythonObjectInstantiator.h" #include <boost/python/class.hpp> @@ -6,13 +7,26 @@ using namespace Mantid::Geometry; using namespace boost::python; +namespace { + PointGroup_sptr getPointGroupFromSpaceGroup(PointGroupFactoryImpl & self, const SpaceGroup &group) + { + return self.createPointGroupFromSpaceGroup(group); + } + + PointGroup_sptr getPointGroupFromSpaceGroupSymbol(PointGroupFactoryImpl & self, const std::string &group) + { + return self.createPointGroupFromSpaceGroup(SpaceGroupFactory::Instance().createSpaceGroup(group)); + } +} + void export_PointGroupFactory() { class_<PointGroupFactoryImpl,boost::noncopyable>("PointGroupFactoryImpl", no_init) .def("exists", &PointGroupFactoryImpl::isSubscribed) .def("createPointGroup", &PointGroupFactoryImpl::createPointGroup) - .def("createPointGroupFromSpaceGroupSymbol", &PointGroupFactoryImpl::createPointGroupFromSpaceGroupSymbol) + .def("createPointGroupFromSpaceGroup", &getPointGroupFromSpaceGroup) + .def("createPointGroupFromSpaceGroupSymbol", &getPointGroupFromSpaceGroupSymbol) .def("getAllPointGroupSymbols", &PointGroupFactoryImpl::getAllPointGroupSymbols) .def("getPointGroupSymbols", &PointGroupFactoryImpl::getPointGroupSymbols) .def("Instance", &PointGroupFactory::Instance, return_value_policy<reference_existing_object>(), diff --git a/Code/Mantid/Framework/PythonInterface/mantid/geometry/src/Exports/SpaceGroup.cpp b/Code/Mantid/Framework/PythonInterface/mantid/geometry/src/Exports/SpaceGroup.cpp index 442a4783d4e00265e31b6004a6f26c8afc48c255..2608650efae0afb655e41a3022890f6b1da3ceb5 100644 --- a/Code/Mantid/Framework/PythonInterface/mantid/geometry/src/Exports/SpaceGroup.cpp +++ b/Code/Mantid/Framework/PythonInterface/mantid/geometry/src/Exports/SpaceGroup.cpp @@ -1,4 +1,5 @@ +#include "MantidGeometry/Crystal/Group.h" #include "MantidGeometry/Crystal/SpaceGroup.h" #include "MantidPythonInterface/kernel/Converters/PyObjectToV3D.h" @@ -8,6 +9,7 @@ #include <boost/python/list.hpp> #include <boost/python/register_ptr_to_python.hpp> +using Mantid::Geometry::Group; using Mantid::Geometry::SpaceGroup; using Mantid::Geometry::SymmetryOperation; @@ -47,7 +49,7 @@ void export_SpaceGroup() { register_ptr_to_python<boost::shared_ptr<SpaceGroup> >(); - class_<SpaceGroup, boost::noncopyable>("SpaceGroup", no_init) + class_<SpaceGroup, boost::noncopyable, bases<Group> >("SpaceGroup", no_init) .def("order", &SpaceGroup::order) .def("getSymmetryOperationStrings", &getSymmetryOperationStrings) .def("number", &SpaceGroup::number) diff --git a/Code/Mantid/Framework/PythonInterface/mantid/geometry/src/Exports/SpaceGroupFactory.cpp b/Code/Mantid/Framework/PythonInterface/mantid/geometry/src/Exports/SpaceGroupFactory.cpp index de61f14cbef451f2255ea67b6051bdb5238acb17..0f906422a0f69a1d79769f36b661ce17fd57242e 100644 --- a/Code/Mantid/Framework/PythonInterface/mantid/geometry/src/Exports/SpaceGroupFactory.cpp +++ b/Code/Mantid/Framework/PythonInterface/mantid/geometry/src/Exports/SpaceGroupFactory.cpp @@ -33,7 +33,6 @@ namespace SpaceGroup_sptr createSpaceGroup(SpaceGroupFactoryImpl &self, const std::string &symbol) { SpaceGroup_const_sptr spaceGroup = self.createSpaceGroup(symbol); - return boost::const_pointer_cast<SpaceGroup>(spaceGroup); } diff --git a/Code/Mantid/Framework/PythonInterface/mantid/simpleapi.py b/Code/Mantid/Framework/PythonInterface/mantid/simpleapi.py index a8504f916262da4b9f247d1dd228e5a850b044ca..1ded6b0bf0352e05f97a0fe0054a9010ac70383b 100644 --- a/Code/Mantid/Framework/PythonInterface/mantid/simpleapi.py +++ b/Code/Mantid/Framework/PythonInterface/mantid/simpleapi.py @@ -20,6 +20,7 @@ """ from __future__ import absolute_import +import os, string import mantid.api as _api import mantid.kernel as _kernel @@ -31,7 +32,7 @@ from mantid.api._aliases import * #------------------------ Specialized function calls -------------------------- # List of specialized algorithms -__SPECIALIZED_FUNCTIONS__ = ["Load", "Fit"] +__SPECIALIZED_FUNCTIONS__ = ["Load", "Fit", "CutMD"] # List of specialized algorithms __MDCOORD_FUNCTIONS__ = ["PeakIntensityVsRadius", "CentroidPeaksMD","IntegratePeaksMD"] # The "magic" keyword to enable/disable logging @@ -257,22 +258,124 @@ def FitDialog(*args, **kwargs): #--------------------------------------------------- -------------------------- -#This dictionary maps algorithm names to functions that preprocess their inputs -#in the simpleapi. The functions take args and kwargs as regular arguments and -#modify them as required. +def CutMD(*args, **kwargs): + """ + Slices multidimensional workspaces using input projection information and binning limits. + """ + (in_wss,) = _get_mandatory_args('CutMD', ["InputWorkspace"], *args, **kwargs) + + # If the input isn't a list, wrap it in one so we can iterate easily + if isinstance(in_wss, list): + in_list = in_wss + handling_multiple_workspaces = True + else: + in_list = [in_wss] + handling_multiple_workspaces = False + + # Remove from keywords so it is not set twice + if "InputWorkspace" in kwargs: + del kwargs['InputWorkspace'] + + #Make sure we were given some output workspace names + lhs = _kernel.funcreturns.lhs_info() + if lhs[0] == 0 and 'OutputWorkspace' not in kwargs: + raise RuntimeError("Unable to set output workspace name. Please either assign the output of " + "CutMD to a variable or use the OutputWorkspace keyword.") + + #Take what we were given + if "OutputWorkspace" in kwargs: + out_names = kwargs["OutputWorkspace"] + else: + out_names = list(lhs[1]) + + #Ensure the output names we were given are valid + if handling_multiple_workspaces: + if not isinstance(out_names, list): + raise RuntimeError("Multiple OutputWorkspaces must be given as a list when processing multiple InputWorkspaces.") + else: + #We wrap in a list for our convenience. The user musn't pass us one though. + if not isinstance(out_names, list): + out_names = [out_names] + elif len(out_names) != 1: + raise RuntimeError("Only one OutputWorkspace required") + + if len(out_names) != len(in_list): + raise RuntimeError("Different number of input and output workspaces given.") + + # Split PBins up into P1Bin, P2Bin, etc. + if "PBins" in kwargs: + bins = kwargs["PBins"] + del kwargs["PBins"] + if isinstance(bins, tuple) or isinstance(bins, list): + for bin in range(len(bins)): + kwargs["P{0}Bin".format(bin+1)] = bins[bin] + + # Create and execute + algm = _create_algorithm_object('CutMD') + _set_logging_option(algm, kwargs) -_algorithm_preprocessors = dict() + # Now check that all the kwargs we've got are correct + for key in kwargs.keys(): + if key not in algm: + raise RuntimeError("Unknown property: {0}".format(key)) + + # We're now going to build to_process, which is the list of workspaces we want to process. + to_process = list() + for i in range(len(in_list)): + ws = in_list[i] + + if isinstance(ws, _api.Workspace): + #It's a workspace, do nothing to it + to_process.append(ws) + elif isinstance(ws, str): + if ws in mtd: + #It's a name of something in the ads, just take it from the ads + to_process.append(_api.AnalysisDataService[ws]) + else: + #Let's try treating it as a filename + load_alg = AlgorithmManager.create("Load") + load_alg.setLogging(True) + load_alg.setAlwaysStoreInADS(False) + load_alg.setProperty("Filename", ws) + load_alg.setProperty("OutputWorkspace", "__loaded_by_cutmd_{0}".format(i+1)) + load_alg.execute() + if not load_alg.isExecuted(): + raise TypeError("Failed to load " + ws) + wsn = load_alg.getProperty("OutputWorkspace").valueAsStr + to_process.append(_api.AnalysisDataService[wsn]) + else: + raise TypeError("Unexpected type: " + type(ws)) + + #Run the algorithm across the inputs and outputs + for i in range(len(to_process)): + _set_properties(algm, **kwargs) + algm.setProperty('InputWorkspace', to_process[i]) + algm.setProperty('OutputWorkspace', out_names[i]) + algm.execute() -def _pp_cutmd(args, kwargs): - if "PBins" in kwargs: - bins = kwargs["PBins"] - del kwargs["PBins"] - if isinstance(bins, tuple) or isinstance(bins, list): - #PBin has been provided, we need to split it out into P1Bin, P2Bin, etc. - for bin in range(len(bins)): - kwargs["P{0}Bin".format(bin+1)] = bins[bin] + #Get the workspace objects so we can return them + for i in range(len(out_names)): + out_names[i] = _api.AnalysisDataService[out_names[i]] -_algorithm_preprocessors["CutMD"] = _pp_cutmd + #We should only return a list if we're handling multiple workspaces + if handling_multiple_workspaces: + return out_names + else: + return out_names[0] + +# Have a better load signature for autocomplete +_signature = "\bInputWorkspace" +# Getting the code object for Load +_f = CutMD.func_code +# Creating a new code object nearly identical, but with the two variable names replaced +# by the property list. +_c = _f.__new__(_f.__class__, _f.co_argcount, _f.co_nlocals, _f.co_stacksize, _f.co_flags, _f.co_code, _f.co_consts, _f.co_names,\ + (_signature, "kwargs"), _f.co_filename, _f.co_name, _f.co_firstlineno, _f.co_lnotab, _f.co_freevars) + +# Replace the code object of the wrapper function +CutMD.func_code = _c + +#--------------------------------------------------- -------------------------- def _get_function_spec(func): """Get the python function signature for the given function object @@ -568,10 +671,6 @@ def _create_algorithm_function(algorithm, version, _algm_object): the proper version of the algorithm without failing. """ - # If needed, preprocess this algorithm's input - if algorithm in _algorithm_preprocessors: - _algorithm_preprocessors[algorithm](args, kwargs) - _version = version if "Version" in kwargs: _version = kwargs["Version"] diff --git a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/LoadDNSLegacy.py b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/LoadDNSLegacy.py new file mode 100644 index 0000000000000000000000000000000000000000..62b8cc71d145baab36164ae0dd180e608fa212be --- /dev/null +++ b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/LoadDNSLegacy.py @@ -0,0 +1,98 @@ +from mantid.kernel import * +from mantid.api import * +import mantid.simpleapi as api +import numpy as np + +import os, sys + +sys.path.insert(0, os.path.dirname(__file__)) +from dnsdata import DNSdata +sys.path.pop(0) + +class LoadDNSLegacy(PythonAlgorithm): + """ + Load the DNS Legacy data file to the mantid workspace + """ + def category(self): + """ + Returns categore + """ + return 'DataHandling' + + def name(self): + """ + Returns name + """ + return "LoadDNSLegacy" + + def summary(self): + return "Load the DNS Legacy data file to the mantid workspace." + + def PyInit(self): + self.declareProperty(FileProperty("Filename", "", \ + FileAction.Load, ['.d_dat']), \ + "Name of DNS experimental data file.") + self.declareProperty(WorkspaceProperty("OutputWorkspace", \ + "", direction=Direction.Output), \ + doc="Name of the workspace to store the experimental data.") + + return + + + def PyExec(self): + # Input + filename = self.getPropertyValue("Filename") + outws = self.getPropertyValue("OutputWorkspace") + + # load data array from the given file + data_array = np.loadtxt(filename) + ndet = 24 + dataX = np.zeros(ndet) + dataY = data_array[0:ndet, 1:] + dataE = np.sqrt(dataY) + # create workspace + __temporary_workspace__ = api.CreateWorkspace(DataX=dataX, \ + DataY=dataY, DataE=dataE, NSpec=ndet, UnitX="Wavelength") + api.LoadInstrument(__temporary_workspace__, InstrumentName='DNS') + + # load run information + metadata = DNSdata() + metadata.read_legacy(filename) + run = __temporary_workspace__.mutableRun() + run.setStartAndEndTime(DateAndTime(metadata.start_time), \ + DateAndTime(metadata.end_time)) + + # rotate the detector bank to the proper position + api.RotateInstrumentComponent(__temporary_workspace__, \ + "bank0", X=0, Y=1, Z=0, Angle=metadata.deterota) + # add sample log Ei + energy = get_energy(metadata.wavelength) + api.AddSampleLog(__temporary_workspace__, \ + 'Ei', LogText=str(energy), LogType='Number') + # add other sample logs + api.AddSampleLog(__temporary_workspace__, 'deterota', \ + LogText=str(metadata.deterota), LogType='Number') + api.AddSampleLog(__temporary_workspace__, 'huber', \ + LogText=str(metadata.huber), LogType='Number') + api.AddSampleLog(__temporary_workspace__, 'T1', \ + LogText=str(metadata.t1), LogType='Number') + api.AddSampleLog(__temporary_workspace__, 'T2', \ + LogText=str(metadata.t2), LogType='Number') + api.AddSampleLog(__temporary_workspace__, 'Tsp', \ + LogText=str(metadata.tsp), LogType='Number') + + self.setProperty("OutputWorkspace", __temporary_workspace__) + self.log().debug('LoadDNSLegacy: OK') + api.DeleteWorkspace(__temporary_workspace__) + + return + + +def get_energy(wavelength): + """ + Calculates neutron energy in eV from the given wavelength in Angstrom + """ + return 1e-3*81.73 / wavelength**2 + +# Register algorithm with Mantid +AlgorithmFactory.subscribe(LoadDNSLegacy) diff --git a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/PoldiCreatePeaksFromFile.py b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/PoldiCreatePeaksFromFile.py new file mode 100644 index 0000000000000000000000000000000000000000..d68a14bfb2a65c2fcfcb370d2d4a651e66c59eca --- /dev/null +++ b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/PoldiCreatePeaksFromFile.py @@ -0,0 +1,217 @@ +# pylint: disable=no-init,invalid-name,too-few-public-methods +from mantid.kernel import * +from mantid.simpleapi import * +from mantid.api import * +from mantid.geometry import * + +from pyparsing import * + +import os + + +class PoldiCompound(object): + """Small helper class to handle the results from PoldiCrystalFileParser.""" + _name = "" + _spacegroup = "" + _atomString = "" + _cellDict = "" + + def __init__(self, name, elements): + self._name = name + + self.assign(elements) + + def assign(self, elements): + for c in elements: + if c[0] == "atoms": + self._atomString = ';'.join(c[1:]) + elif c[0] == "lattice": + cellNames = ['a', 'b', 'c', 'alpha', 'beta', 'gamma'] + self._cellDict = dict(zip(cellNames, c[1:])) + elif c[0] == "spacegroup": + self._spacegroup = c[1] + + def getAtomString(self): + return self._atomString + + def getCellParameters(self): + return self._cellDict + + def getSpaceGroup(self): + return self._spacegroup + + def getName(self): + return self._name + + +def raiseParseErrorException(message): + raise ParseException(message) + + +class PoldiCrystalFileParser(object): + """Small parser for crystal structure files used at POLDI + + This class encapsulates a small parser for crystal structure files that are used at + POLDI. The files contains information about the lattice, the space group and the basis (atoms + in the asymmetric unit). + + The file format is defined as follows: + + Compound_1 { + Lattice: [1 - 6 floats] => a, b, c, alpha, beta, gamma + Spacegroup: [valid space group symbol] + Atoms; { + Element x y z [occupancy [U_eq]] + Element x y z [occupancy [U_eq]] + } + } + + Compound_2 { + ... + } + + The parser returns a list of PoldiCompound objects with the compounds that were found + in the file. These are then processed by PoldiCreatePeaksFromFile to generate arguments + for calling PoldiCreatePeaksFromCell. + """ + elementSymbol = Word(alphas, min=1, max=2).setFailAction( + lambda o, s, loc, token: raiseParseErrorException("Element symbol must be one or two characters.")) + integerNumber = Word(nums) + decimalSeparator = Literal('.') + floatNumber = Combine( + integerNumber + + Optional(decimalSeparator + Optional(integerNumber)) + ) + + whiteSpace = Suppress(White()) + + atomLine = Combine( + elementSymbol + whiteSpace + + delimitedList(floatNumber, delim=White()), + joinString=' ' + ) + + keyValueSeparator = Suppress(Literal(":")) + + groupOpener = Suppress(Literal('{')) + groupCloser = Suppress(Literal('}')) + + atomsGroup = Group(CaselessLiteral("atoms") + keyValueSeparator + + groupOpener + delimitedList(atomLine, delim=lineEnd) + groupCloser) + + unitCell = Group(CaselessLiteral("lattice") + keyValueSeparator + delimitedList( + floatNumber, delim=White())) + + spaceGroup = Group(CaselessLiteral("spacegroup") + keyValueSeparator + Word( + alphanums + "-" + ' ')) + + compoundContent = Each([atomsGroup, unitCell, spaceGroup]).setFailAction( + lambda o, s, loc, token: raiseParseErrorException( + "One of 'Lattice', 'SpaceGroup', 'Atoms' is missing or contains errors.")) + + compoundName = Word(alphanums + '_') + + compound = Group(compoundName + Optional(whiteSpace) + \ + groupOpener + compoundContent + groupCloser) + + comment = Suppress(Literal('#') + restOfLine) + + compounds = Optional(comment) + OneOrMore(compound).ignore(comment) + stringEnd + + def __call__(self, contentString): + parsedContent = None + + if os.path.isfile(contentString): + parsedContent = self._parseFile(contentString) + else: + parsedContent = self._parseString(contentString) + + return [PoldiCompound(x[0], x[1:]) for x in parsedContent] + + def _parseFile(self, filename): + return self.compounds.parseFile(filename) + + def _parseString(self, stringContent): + return self.compounds.parseString(stringContent) + + +class PoldiCreatePeaksFromFile(PythonAlgorithm): + _parser = PoldiCrystalFileParser() + + def category(self): + return "SINQ\\POLDI" + + def name(self): + return "PoldiLoadCrystalData" + + def summary(self): + return ("The algorithm reads a POLDI crystal structure file and creates a WorkspaceGroup that contains tables" + "with the expected reflections.") + + def PyInit(self): + self.declareProperty( + FileProperty(name="InputFile", + defaultValue="", + action=FileAction.Load, + extensions=["dat"]), + doc="A file with POLDI crystal data.") + + self.declareProperty("LatticeSpacingMin", 0.5, + direction=Direction.Input, + doc="Lowest allowed lattice spacing.") + + self.declareProperty("LatticeSpacingMax", 0.0, + direction=Direction.Input, + doc="Largest allowed lattice spacing.") + + self.declareProperty( + WorkspaceProperty(name="OutputWorkspace", + defaultValue="", direction=Direction.Output), + doc="WorkspaceGroup with reflection tables.") + + + def PyExec(self): + crystalFileName = self.getProperty("InputFile").value + try: + # Try parsing the supplied file using PoldiCrystalFileParser + compounds = self._parser(crystalFileName) + + dMin = self.getProperty("LatticeSpacingMin").value + dMax = self.getProperty("LatticeSpacingMax").value + + workspaces = [] + + # Go through found compounds and run "_createPeaksFromCell" for each of them + # If two compounds have the same name, a warning is written to the log. + for compound in compounds: + if compound.getName() in workspaces: + self.log().warning("A compound with the name '" + compound.getName() + \ + "' has already been created. Please check the file '" + crystalFileName + "'") + else: + workspaces.append(self._createPeaksFromCell(compound, dMin, dMax)) + + self.setProperty("OutputWorkspace", GroupWorkspaces(workspaces)) + + # All parse errors are caught here and logged as errors + except ParseException as error: + errorString = "Could not parse input file '" + crystalFileName + "'.\n" + errorString += "The parser reported the following error:\n\t" + str(error) + + self.log().error(errorString) + + + def _createPeaksFromCell(self, compound, dMin, dMax): + if not SpaceGroupFactory.isSubscribedSymbol(compound.getSpaceGroup()): + raise RuntimeError("SpaceGroup '" + compound.getSpaceGroup() + "' is not registered.") + + PoldiCreatePeaksFromCell(SpaceGroup=compound.getSpaceGroup(), + Atoms=compound.getAtomString(), + LatticeSpacingMin=dMin, + LatticeSpacingMax=dMax, + OutputWorkspace=compound.getName(), + **compound.getCellParameters()) + + return compound.getName() + + +AlgorithmFactory.subscribe(PoldiCreatePeaksFromFile) diff --git a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/Symmetrise.py b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/Symmetrise.py index 3e5ecae529fc9fee4352b5d6c2646fc931bc0f85..563c56c6ccad12148ef4a99896e8c7f7c4a6ac8d 100644 --- a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/Symmetrise.py +++ b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/Symmetrise.py @@ -57,9 +57,6 @@ class Symmetrise(PythonAlgorithm): def PyExec(self): - from IndirectCommon import StartTime, EndTime - - StartTime('Symmetrise') self._setup() temp_ws_name = '__symm_temp' @@ -173,8 +170,6 @@ class Symmetrise(PythonAlgorithm): self.setProperty('OutputWorkspace', self._output_workspace) - EndTime('Symmetrise') - def validateInputs(self): """ diff --git a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/CutMD.py b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/CutMD.py deleted file mode 100644 index 96c0f353bca67b3e42c697871d307309877fbc2c..0000000000000000000000000000000000000000 --- a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/CutMD.py +++ /dev/null @@ -1,354 +0,0 @@ -#pylint: disable=invalid-name,no-init -from mantid.kernel import * -from mantid.api import * -from mantid.simpleapi import * -import numpy as np -import __builtin__ - -class Projection(object): - u = "u" - v = "v" - w = "w" - -class ProjectionUnit(object): - r = "r" - a = "a" - - -class CutMD(DataProcessorAlgorithm): - - def category(self): - return 'MDAlgorithms' - - def summary(self): - return 'Slices multidimensional workspaces using input projection information and binning limits.' - - def PyInit(self): - self.declareProperty(IMDEventWorkspaceProperty('InputWorkspace', '', direction=Direction.Input), - doc='MDWorkspace to slice') - - self.declareProperty(ITableWorkspaceProperty('Projection', '', direction=Direction.Input, optional = PropertyMode.Optional), doc='Projection') - - self.declareProperty(FloatArrayProperty(name='P1Bin', values=[]), - doc='Projection 1 binning') - - self.declareProperty(FloatArrayProperty(name='P2Bin', values=[]), - doc='Projection 2 binning') - - self.declareProperty(FloatArrayProperty(name='P3Bin', values=[]), - doc='Projection 3 binning') - - self.declareProperty(FloatArrayProperty(name='P4Bin', values=[]), - doc='Projection 4 binning') - - self.declareProperty(FloatArrayProperty(name='P5Bin', values=[]), - doc='Projection 5 binning') - - self.declareProperty(IMDWorkspaceProperty('OutputWorkspace', '',\ - direction=Direction.Output), - doc='Output cut workspace') - - self.declareProperty(name="NoPix", defaultValue=False, doc="If False creates a full MDEventWorkspaces as output. True to create an MDHistoWorkspace as output. This is DND only in Horace terminology.") - - self.declareProperty(name="CheckAxes", defaultValue=True, doc="Check that the axis look to be correct, and abort if not.") - - - def __calculate_steps(self, extents, horace_binning ): - # Because the step calculations may involve moving the extents, we re-publish the extents. - out_extents = extents - out_n_bins = list() - for i in range(len(horace_binning)): - - n_arguments = len(horace_binning[i]) - max_extent_index = (i*2) + 1 - min_extent_index = (i*2) - dim_range = extents[ max_extent_index ] - extents[ min_extent_index ] - - if n_arguments == 0: - raise ValueError("binning parameter cannot be empty") - elif n_arguments == 1: - step_size = horace_binning[i][0] - if step_size > dim_range: - step_size = dim_range - n_bins = int( dim_range / step_size) - # Correct the max extent to fit n * step_size - out_extents[max_extent_index] = extents[min_extent_index] + ( n_bins * step_size ) - elif n_arguments == 2: - out_extents[ min_extent_index ] = horace_binning[i][0] - out_extents[ max_extent_index ] = horace_binning[i][1] - n_bins = 1 - elif n_arguments == 3: - dim_min = horace_binning[i][0] - dim_max = horace_binning[i][2] - step_size = horace_binning[i][1] - dim_range = dim_max - dim_min - if step_size > dim_range: - step_size = dim_range - n_bins = int( dim_range / step_size) - # Correct the max extent to fit n * step_size - out_extents[ max_extent_index ] = dim_min + ( n_bins * step_size ) - out_extents[ min_extent_index ] = dim_min - if n_bins < 1: - raise ValueError("Number of bins calculated to be < 1") - out_n_bins.append( n_bins ) - return out_extents, out_n_bins - - def __extents_in_current_projection(self, to_cut, dimension_index): - - dim = to_cut.getDimension(dimension_index) - dim_min = dim.getMinimum() - dim_max = dim.getMaximum() - return (dim_min, dim_max) - - def __calculate_extents(self, u, v, w, limits): - M=np.array([u,v,w]) - Minv=np.linalg.inv(M) - - # unpack limits - Hrange, Krange, Lrange = limits - - # Create a numpy 2D array. Makes finding minimums and maximums for each transformed coordinates over every corner easier. - new_coords = np.empty([8, 3]) - counter = 0 - for h in Hrange: - for k in Krange: - for l in Lrange: - original_corner=np.array([h,k,l]) - new_coords[counter]=np.dot(original_corner, Minv) - counter += 1 - - # Get the min max extents - extents = list() - for i in range(0,3): - # Vertical slice down each corner for each dimension, then determine the max, min and use as extents - extents.append(np.amin(new_coords[:,i])) - extents.append(np.amax(new_coords[:,i])) - - return extents - - def __uvw_from_projection_table(self, projection_table): - if not isinstance(projection_table, ITableWorkspace): - I = np.identity(3) - return (I[0, :], I[1, :], I[2, :]) - (u, v, w) = (None, None, None) - for i in range(projection_table.rowCount()): - name = str(projection_table.cell("name", i)) - value = str(projection_table.cell("value", i)) - if name == "u": - u = np.array(map(float,value.split(","))) - if name == "v": - v = np.array(map(float,value.split(","))) - if name == "w": - w = np.array(map(float,value.split(","))) - - if u is None or v is None or w is None: - raise ValueError("u, v, or w missing from projection table") - - return (u, v, w) - - def __units_from_projection_table(self, projection_table): - if not isinstance(projection_table, ITableWorkspace) or not "type" in projection_table.getColumnNames(): - units = (ProjectionUnit.r, ProjectionUnit.r, ProjectionUnit.r) - else: - #Extract units for each dimension - (u, v, w) = (None, None, None) - for i in range(projection_table.rowCount()): - name = str(projection_table.cell("name", i)) - unit = str(projection_table.cell("type", i)) - if name == "u": - u = unit - if name == "v": - v = unit - if name == "w": - w = unit - if u is None or v is None or w is None: - raise ValueError("u, v, or w missing from projection table") - units = (u, v, w) - return units - - - def __make_labels(self, projection): - - class Mapping: - - def __init__(self, replace): - self.__replace = replace - - def replace(self, entry): - if np.absolute(entry) == 1: - if entry > 0: - return self.__replace - else: - return "-" + self.__replace - elif entry == 0: - return 0 - else: - return "%.2f%s" % ( entry, self.__replace ) - return entry - - crystallographic_names = ['zeta', 'eta', 'xi' ] - labels = list() - for i in range(len(projection)): - cmapping = Mapping(crystallographic_names[i]) - labels.append( [cmapping.replace(x) for x in projection[i] ] ) - - return labels - - def __verify_projection_input(self, projection_table): - if isinstance(projection_table, ITableWorkspace): - column_names = set(projection_table.getColumnNames()) - if column_names != set(["name", "value", "type", "offset"]): - raise ValueError("Projection table schema is wrong! Column names received: " + str(column_names) ) - if projection_table.rowCount() < 2: - raise ValueError("Projection table expects at least 2 rows") - elif projection_table is not None: - print(help(projection_table)) - raise ValueError("Projection should be either an ITableWorkspace or None. It's a: " + str(type(projection_table))) - - def __scale_projection(self, (u, v, w), origin_units, target_units, to_cut): - - if set(origin_units) == set(target_units): - return (u,v,w) # Nothing to do. - - ol = to_cut.getExperimentInfo(0).sample().getOrientedLattice() - - projection_scaled = [u, v, w] - - to_from_pairs = zip(origin_units, target_units) - for i in range(len(to_from_pairs)) : - - proj = projection_scaled[i] - d_star = 2 * np.pi * ol.dstar( float(proj[0]), float(proj[1]), float(proj[2]) ) - - from_unit, to_unit = to_from_pairs[i] - if from_unit == to_unit: - continue - elif from_unit == ProjectionUnit.a: # From inverse Angstroms to rlu - projection_scaled[i] *= d_star - else: # From rlu to inverse Anstroms - projection_scaled[i] /= d_star - return projection_scaled - - - def PyExec(self): - - logger.warning('You are running algorithm %s that is the beta stage of development' % (self.name())) - - to_cut = self.getProperty("InputWorkspace").value - - ndims = to_cut.getNumDims() - - nopix = self.getProperty("NoPix").value - - projection_table = self.getProperty("Projection").value - self.__verify_projection_input(projection_table) - - #Fetch pbins properties - pbins = [None] * 5 #Up to 5 dimensions - for i in range(len(pbins)): - pbins[i] = self.getProperty("P{0}Bin".format(i+1)) - - #Also check the correct pbin properties are set - if pbins[i].isDefault and i < ndims: - raise ValueError("P{0}Bin dimension binning must be set on a workspace with {1} dimensions.".format(i+1, ndims)) - elif not pbins[i].isDefault and i >= ndims: - raise ValueError("Cannot set P{0}Bin dimension binning on a workspace with {1} dimensions.".format(i+1, ndims)) - - x_extents = self.__extents_in_current_projection(to_cut, 0) - y_extents = self.__extents_in_current_projection(to_cut, 1) - z_extents = self.__extents_in_current_projection(to_cut, 2) - - projection = self.__uvw_from_projection_table(projection_table) - target_units = self.__units_from_projection_table(projection_table) - origin_units = (ProjectionUnit.r, ProjectionUnit.r, ProjectionUnit.r) # TODO. This is a hack! - - u,v,w = self.__scale_projection(projection, origin_units, target_units, to_cut) - - extents = self.__calculate_extents(u, v, w, ( x_extents, y_extents, z_extents ) ) - extents, bins = self.__calculate_steps( extents, ( pbins[0].value, pbins[1].value, pbins[2].value ) ) - - for i in range(3, ndims): - pbin = pbins[i].value - n_args = len(pbin) - min, max = self.__extents_in_current_projection(to_cut, i) - d_range = max - min - if n_args == 1: - step_size = pbin[0] - nbins = d_range / step_size - elif n_args == 2: - min = pbin[0] - max = pbin[1] - nbins = 1 - elif n_args == 3: - min = pbin[0] - max = pbin[2] - step_size = pbin[1] - dim_range = max - min - if step_size > dim_range: - step_size = dim_range - nbins = int( dim_range / step_size) - - extents.append(min) - extents.append(max) - bins.append(int(nbins)) - - temp = list(target_units) - temp.append(target_units) - target_units = tuple(temp) - - projection_labels = self.__make_labels(projection) - - cut_alg_name = "BinMD" if nopix else "SliceMD" - ''' - Actually perform the binning operation - ''' - cut_alg = self.createChildAlgorithm(name=cut_alg_name, startProgress=0, endProgress=1.0) - cut_alg.initialize() - cut_alg.setProperty("InputWorkspace", to_cut) - cut_alg.setPropertyValue("OutputWorkspace", "sliced") - cut_alg.setProperty("NormalizeBasisVectors", False) - cut_alg.setProperty("AxisAligned", False) - # Now for the basis vectors. - - n_padding = __builtin__.max(0, ndims-3) - - for i in range(0, ndims): - - - if i <= 2: - - label = projection_labels[i] - unit = target_units[i] - vec = list(projection[i]) + ( [0] * n_padding ) - - # These are always orthogonal to the rest. - else: - orthogonal_dimension = to_cut.getDimension(i) - label = orthogonal_dimension.getName() - unit = orthogonal_dimension.getUnits() - vec = [0] * ndims - vec[i] = 1 - - value = "%s, %s, %s" % ( label, unit, ",".join(map(str, vec))) - cut_alg.setPropertyValue("BasisVector{0}".format(i) , value) - - - cut_alg.setProperty("OutputExtents", extents) - cut_alg.setProperty("OutputBins", bins) - - cut_alg.execute() - - slice = cut_alg.getProperty("OutputWorkspace").value - - - # Attach the w-matrix (projection matrix) - if slice.getNumExperimentInfo() > 0: - u, v, w = projection - w_matrix = np.array([u, v, w]).flatten().tolist() - info = slice.getExperimentInfo(0) - info.run().addProperty("W_MATRIX", w_matrix, True) - - self.setProperty("OutputWorkspace", slice) - - -AlgorithmFactory.subscribe(CutMD) diff --git a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/InelasticIndirectReduction.py b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/InelasticIndirectReduction.py index aee835a8773649cedb5f47404fe10da87841ed6c..39070394a695e4f5815bd9135966038d838d16d4 100644 --- a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/InelasticIndirectReduction.py +++ b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/InelasticIndirectReduction.py @@ -77,13 +77,10 @@ class InelasticIndirectReduction(DataProcessorAlgorithm): def PyExec(self): from mantid import config, logger - from IndirectCommon import StartTime, EndTime import inelastic_indirect_reducer self._setup() - StartTime('InelasticIndirectReduction') - # Setup reducer reducer = inelastic_indirect_reducer.IndirectReducer() @@ -157,8 +154,6 @@ class InelasticIndirectReduction(DataProcessorAlgorithm): if self._plot_type != 'none': self._plot() - EndTime('InelasticIndirectReduction') - def validateInputs(self): """ diff --git a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/MSGDiffractionReduction.py b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/MSGDiffractionReduction.py index 73e8140748acaa31165604c67f7784010f430bcc..ca4277dad752be530a67fd6c9b9c0b604bce23d4 100644 --- a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/MSGDiffractionReduction.py +++ b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/MSGDiffractionReduction.py @@ -77,11 +77,8 @@ class MSGDiffractionReduction(PythonAlgorithm): def PyExec(self): - from IndirectCommon import StartTime, EndTime from IndirectDiffractionReduction import MSGDiffractionReducer - StartTime('MSGDiffractionReduction') - input_files = self.getProperty('InputFiles').value sum_files = self.getProperty('SumFiles').value individual_grouping = self.getProperty('IndividualGrouping').value @@ -119,7 +116,5 @@ class MSGDiffractionReduction(PythonAlgorithm): GroupWorkspaces(InputWorkspaces=result_ws_list, OutputWorkspace=output_ws_group) self.setProperty('OutputWorkspace', output_ws_group) - EndTime('MSGDiffractionReduction') - AlgorithmFactory.subscribe(MSGDiffractionReduction) diff --git a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/Fury.py b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/TransformToIqt.py similarity index 87% rename from Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/Fury.py rename to Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/TransformToIqt.py index ab8aff547bafaa64f74b506e7e0a53a778fd6715..ab2d4a4c5129930c1eb751de12641d099251eecf 100644 --- a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/Fury.py +++ b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/TransformToIqt.py @@ -7,7 +7,7 @@ import math import os -class Fury(PythonAlgorithm): +class TransformToIqt(PythonAlgorithm): _sample = None _resolution = None @@ -21,29 +21,35 @@ class Fury(PythonAlgorithm): _save = None _dry_run = None + def category(self): - return "Workflow\\MIDAS;PythonAlgorithms" + return "Workflow\\Inelastic;PythonAlgorithms" + + + def summary(self): + return 'Transforms an inelastic reduction to I(Q, t)' + def PyInit(self): - self.declareProperty(MatrixWorkspaceProperty('Sample', '',\ + self.declareProperty(MatrixWorkspaceProperty('SampleWorkspace', '',\ optional=PropertyMode.Mandatory, direction=Direction.Input), - doc="Name for the Sample workspace.") + doc="Name for the sample workspace.") - self.declareProperty(MatrixWorkspaceProperty('Resolution', '',\ + self.declareProperty(MatrixWorkspaceProperty('ResolutionWorkspace', '',\ optional=PropertyMode.Mandatory, direction=Direction.Input), - doc="Name for the Resolution workspace.") + doc="Name for the resolution workspace.") self.declareProperty(name='EnergyMin', defaultValue=-0.5, doc='Minimum energy for fit. Default=-0.5') self.declareProperty(name='EnergyMax', defaultValue=0.5, doc='Maximum energy for fit. Default=0.5') - self.declareProperty(name='NumBins', defaultValue=1, + self.declareProperty(name='BinReductionFactor', defaultValue=10.0, doc='Decrease total number of spectrum points by this ratio through merging of ' 'intensities from neighbouring bins. Default=1') self.declareProperty(MatrixWorkspaceProperty('ParameterWorkspace', '',\ direction=Direction.Output, optional=PropertyMode.Optional), - doc='Table workspace for saving Fury properties') + doc='Table workspace for saving TransformToIqt properties') self.declareProperty(MatrixWorkspaceProperty('OutputWorkspace', '',\ direction=Direction.Output, optional=PropertyMode.Optional), @@ -76,7 +82,7 @@ class Fury(PythonAlgorithm): if self._plot: self._plot_output() else: - logger.information('Dry run, will not run Fury') + logger.information('Dry run, will not run TransformToIqt') self.setProperty('ParameterWorkspace', self._parameter_table) self.setProperty('OutputWorkspace', self._output_workspace) @@ -88,16 +94,16 @@ class Fury(PythonAlgorithm): """ from IndirectCommon import getWSprefix - self._sample = self.getPropertyValue('Sample') - self._resolution = self.getPropertyValue('Resolution') + self._sample = self.getPropertyValue('SampleWorkspace') + self._resolution = self.getPropertyValue('ResolutionWorkspace') self._e_min = self.getProperty('EnergyMin').value self._e_max = self.getProperty('EnergyMax').value - self._number_points_per_bin = self.getProperty('NumBins').value + self._number_points_per_bin = self.getProperty('BinReductionFactor').value self._parameter_table = self.getPropertyValue('ParameterWorkspace') if self._parameter_table == '': - self._parameter_table = getWSprefix(self._sample) + 'FuryParameters' + self._parameter_table = getWSprefix(self._sample) + 'TransformToIqtParameters' self._output_workspace = self.getPropertyValue('OutputWorkspace') if self._output_workspace == '': @@ -128,13 +134,13 @@ class Fury(PythonAlgorithm): def _calculate_parameters(self): """ - Calculates the Fury parameters and saves in a table workspace. + Calculates the TransformToIqt parameters and saves in a table workspace. """ - CropWorkspace(InputWorkspace=self._sample, OutputWorkspace='__Fury_sample_cropped', + CropWorkspace(InputWorkspace=self._sample, OutputWorkspace='__TransformToIqt_sample_cropped', Xmin=self._e_min, Xmax=self._e_max) - x_data = mtd['__Fury_sample_cropped'].readX(0) + x_data = mtd['__TransformToIqt_sample_cropped'].readX(0) number_input_points = len(x_data) - 1 - num_bins = number_input_points / self._number_points_per_bin + num_bins = int(number_input_points / self._number_points_per_bin) self._e_width = (abs(self._e_min) + abs(self._e_max)) / num_bins try: @@ -167,7 +173,7 @@ class Fury(PythonAlgorithm): param_table = CreateEmptyTableWorkspace(OutputWorkspace=self._parameter_table) param_table.addColumn('int', 'SampleInputBins') - param_table.addColumn('int', 'NumberBins') + param_table.addColumn('float', 'BinReductionFactor') param_table.addColumn('int', 'SampleOutputBins') param_table.addColumn('float', 'EnergyMin') param_table.addColumn('float', 'EnergyMax') @@ -179,7 +185,7 @@ class Fury(PythonAlgorithm): self._e_min, self._e_max, self._e_width, resolution, resolution_bins]) - DeleteWorkspace('__Fury_sample_cropped') + DeleteWorkspace('__TransformToIqt_sample_cropped') self.setProperty('ParameterWorkspace', param_table) @@ -212,7 +218,7 @@ class Fury(PythonAlgorithm): def _fury(self): """ - Run Fury. + Run TransformToIqt. """ from IndirectCommon import CheckHistZero, CheckHistSame, CheckAnalysers @@ -261,4 +267,4 @@ class Fury(PythonAlgorithm): # Register algorithm with Mantid -AlgorithmFactory.subscribe(Fury) +AlgorithmFactory.subscribe(TransformToIqt) diff --git a/Code/Mantid/Framework/PythonInterface/plugins/algorithms/dnsdata.py b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/dnsdata.py new file mode 100644 index 0000000000000000000000000000000000000000..97f14ac5e68d1f33ac83c597dc64808f1980f0f3 --- /dev/null +++ b/Code/Mantid/Framework/PythonInterface/plugins/algorithms/dnsdata.py @@ -0,0 +1,213 @@ +import sys, re +import datetime + +class DNSdata: + """ + class which describes the DNS data structure + will be used for data read-in and write-out routines + """ + def __init__(self): + self.title = "" + self.experiment_number = "" + self.run_number = "" + self.start_time = "" + self.end_time = "" + self.duration = None + self.deterota = 0 + self.wavelength = None # Angstrom + self.ndet = 24 + self.sample_name = "" + self.userid = "" + self.user_name = "" + self.sample_description = "" + self.coil_status = "" + self.befilter_status = "" + self.notes = "" + self.monochromator_angle = None # degree + self.monochromator_position = None + self.huber = None + self.cradle_lower = None + self.cradle_upper = None + self.slit_i_upper_blade_position = None + self.slit_i_lower_blade_position = None + self.slit_i_left_blade_position = None + self.slit_i_right_blade_position = None + self.slit_f_upper_blade_position = None + self.slit_f_lower_blade_position = None + self.detector_position_vertical = None + self.polarizer_translation = None + self.polarizer_rotation = None + self.flipper_precession_current = None + self.flipper_z_compensation_current = None + self.a_coil_current = None + self.b_coil_current = None + self.c_coil_current = None + self.z_coil_current = None + self.t1 = None # T1 + self.t2 = None # T2 + self.tsp = None # T_setpoint + self.tof_channel_number = None + self.tof_channel_width = None + self.tof_delay_time = None + self.tof_elastic_channel = None + self.chopper_rotation_speed = None + self.chopper_slits = None + self.monitor_counts = None + + + def read_legacy(self, filename): + """ + reads the DNS legacy ascii file into the DNS data object + """ + with open(filename, 'r') as fhandler: + # read file content and split it into blocks + splitsymbol = \ + '#--------------------------------------------------------------------------' + unparsed = fhandler.read() + blocks = unparsed.split(splitsymbol) + + # parse each block + # parse block 0 (header) + res = parse_header(blocks[0]) + #if not res: raise Exception "wrong file format" else + try: + self.run_number = res['file'] + self.experiment_number = res['exp'] + self.sample_name = res['sample'] + self.userid = res['userid'] + except: + raise ValueError("The file %s does not contain valid DNS data format." % filename) + # parse block 1 (general information) + b1splitted = map(str.strip, blocks[1].split('#')) + b1rest = [el for el in b1splitted] + r_user = re.compile("User:\s*(?P<name>.*?$)") + r_sample = re.compile("Sample:\s*(?P<sample>.*?$)") + r_coil = re.compile("^(?P<coil>.*?)\s*xyz-coil.*") + r_filter = re.compile("^(?P<filter>.*?)\s*Be-filter.*") + for line in b1splitted: + res = r_user.match(line) + if res: + self.user_name = res.group("name") + b1rest.remove(line) + res = r_sample.match(line) + if res: + self.sample_description = res.group("sample") + b1rest.remove(line) + res = r_coil.match(line) + if res: + self.coil_status = res.group("coil") + b1rest.remove(line) + res = r_filter.match(line) + if res: + self.befilter_status = res.group("filter") + b1rest.remove(line) + # the rest unparsed lines go to notes for the moment + # [TODO]: parse more information about the sample + self.notes = ' '.join(b1rest) + + # parse block 2 (wavelength and mochromator angle) + # for the moment, only theta and lambda are needed + b2splitted = map(str.strip, blocks[2].split('#')) + # assume that theta and lambda are always on the fixed positions + # assume theta is give in degree, lambda in nm + line = b2splitted[2].split() + self.monochromator_angle = float(line[2]) + self.wavelength = float(line[3])*10.0 + + # parse block 3 (motors position) + b3splitted = map(str.strip, blocks[3].split('#')) + self.monochromator_position = float(b3splitted[2].split()[1]) + # DeteRota, angle of rotation of detector bank + self.deterota = float(b3splitted[3].split()[1]) + # Huber default units degree + self.huber = float(b3splitted[5].split()[1]) + self.cradle_lower = float(b3splitted[6].split()[1]) + self.cradle_upper = float(b3splitted[7].split()[1]) + # Slit_i, convert mm to meter + self.slit_i_upper_blade_position = \ + 0.001*float(b3splitted[9].split()[2]) + self.slit_i_lower_blade_position = \ + 0.001*float(b3splitted[10].split()[1]) + self.slit_i_left_blade_position = \ + 0.001*float(b3splitted[11].split()[2]) + self.slit_i_right_blade_position = \ + 0.001*float(b3splitted[12].split()[1]) + # Slit_f + self.slit_f_upper_blade_position = \ + 0.001*float(b3splitted[14].split()[1]) + self.slit_f_lower_blade_position = \ + 0.001*float(b3splitted[15].split()[1]) + # Detector_position vertical + self.detector_position_vertical = \ + 0.001*float(b3splitted[16].split()[1]) + # Polarizer + self.polarizer_translation = \ + 0.001*float(b3splitted[19].split()[1]) + self.polarizer_rotation = float(b3splitted[20].split()[1]) + + # parse block 4 (B-fields), only currents in A are taken + b4splitted = map(str.strip, blocks[4].split('#')) + self.flipper_precession_current = float(b4splitted[2].split()[1]) + self.flipper_z_compensation_current = float(b4splitted[3].split()[1]) + self.a_coil_current = float(b4splitted[4].split()[1]) + self.b_coil_current = float(b4splitted[5].split()[1]) + self.c_coil_current = float(b4splitted[6].split()[1]) + self.z_coil_current = float(b4splitted[7].split()[1]) + + + # parse block 5 (Temperatures) + # assume: T1=cold_head_temperature, T2=sample_temperature + b5splitted = map(str.strip, blocks[5].split('#')) + self.t1 = float(b5splitted[2].split()[1]) + self.t2 = float(b5splitted[3].split()[1]) + self.tsp = float(b5splitted[4].split()[1]) + + # parse block 6 (TOF parameters) + b6splitted = map(str.strip, blocks[6].split('#')) + self.tof_channel_number = int(b6splitted[2].split()[2]) + self.tof_channel_width = float(b6splitted[3].split()[3]) + self.tof_delay_time = float(b6splitted[4].split()[2]) + self.tof_elastic_channel = int(b6splitted[6].split()[3]) + # chopper rotation speed + self.chopper_rotation_speed = float(b6splitted[7].split()[2]) + # chopper number of slits + self.chopper_slits = int(b6splitted[5].split()[2]) + + # parse block 7 (Time and monitor) + # assume everything to be at the fixed positions + b7splitted = map(str.strip, blocks[7].split('#')) + # duration + line = b7splitted[2].split() + self.duration = float(line[1]) # assume seconds [TODO]: check + # monitor data + line = b7splitted[3].split() + self.monitor_counts = int(line[1]) + # start_time and end_time + outfmt = "%Y-%m-%dT%H:%M:%S" + sinfmt = "start at %a %b %d %H:%M:%S %Y" + einfmt = "stopped at %a %b %d %H:%M:%S %Y" + self.start_time = datetime.datetime.strptime(b7splitted[5], sinfmt).strftime(outfmt) + self.end_time = datetime.datetime.strptime(b7splitted[6], einfmt).strftime(outfmt) + +def parse_header(h): + """ + parses the header string and returns the parsed dictionary + """ + d = {} + regexp = re.compile("(\w+)=(\w+)") + result = regexp.finditer(h) + for r in result: + d[r.groups()[0]] = r.groups()[1] + return d + + +if __name__ == '__main__': + fname = sys.argv[1] + dns_data = DNSdata() + dns_data.read_legacy(fname) + print dns_data.__dict__ + + + + + diff --git a/Code/Mantid/Framework/PythonInterface/test/python/mantid/api/CMakeLists.txt b/Code/Mantid/Framework/PythonInterface/test/python/mantid/api/CMakeLists.txt index 0c6113c925d996ce744e70a2fafbfb75f7c9abf3..57b1f1b8c6bf6608895199784738317b1bf253a6 100644 --- a/Code/Mantid/Framework/PythonInterface/test/python/mantid/api/CMakeLists.txt +++ b/Code/Mantid/Framework/PythonInterface/test/python/mantid/api/CMakeLists.txt @@ -10,7 +10,6 @@ set ( TEST_PY_FILES AnalysisDataServiceTest.py AxisTest.py CatalogManagerTest.py - CutMDTest.py DataProcessorAlgorithmTest.py DeprecatedAlgorithmCheckerTest.py ExperimentInfoTest.py diff --git a/Code/Mantid/Framework/PythonInterface/test/python/mantid/api/CutMDTest.py b/Code/Mantid/Framework/PythonInterface/test/python/mantid/api/CutMDTest.py deleted file mode 100644 index 203ed1ecb0b930ebf9cc5f7e9b5ec199fd41d1e0..0000000000000000000000000000000000000000 --- a/Code/Mantid/Framework/PythonInterface/test/python/mantid/api/CutMDTest.py +++ /dev/null @@ -1,232 +0,0 @@ -import unittest -import testhelpers -import numpy as np -from mantid.simpleapi import * -from mantid.api import IMDHistoWorkspace, IMDEventWorkspace - - -class CutMDTest(unittest.TestCase): - - - def setUp(self): - # Create a workspace - data_ws = CreateMDWorkspace(Dimensions=3, Extents=[-10,10,-10,10,-10,10], Names="A,B,C", Units="U,U,U") - # Mark the workspace as being in HKL - SetSpecialCoordinates(InputWorkspace=data_ws, SpecialCoordinates='HKL') - # Set the UB - SetUB(Workspace=data_ws, a = 1, b = 1, c = 1, alpha =90, beta=90, gamma = 90) - # Add some data to the workspace - FakeMDEventData(InputWorkspace=data_ws, PeakParams=[10000,0,0,0,1]) - self.__in_md = data_ws - - def tearDown(self): - DeleteWorkspace(self.__in_md ) - - def test_exec_throws_if_giving_4th_binning_parameter_when_workspace_is_3D(self): - test_md = CreateMDWorkspace(Dimensions=3, Extents=[-10,10,-10,10,-10,10], Names="H,K,L", Units="U,U,U") - # Explicitly set the coordinate system to lab Q. - SetSpecialCoordinates(InputWorkspace=test_md, SpecialCoordinates='HKL') - self.assertRaises(RuntimeError, CutMD, InputWorkspace=test_md, OutputWorkspace="out_ws", P1Bin=[0.1], P2Bin=[0.1], P3Bin=[0.1], P4Bin=[0.1]) - - def test_slice_to_original(self): - out_md = CutMD(self.__in_md, P1Bin=[0.1], P2Bin=[0.1], P3Bin=[0.1], CheckAxes=False) - self.assertTrue(isinstance(out_md, IMDEventWorkspace), "Should default to producing an IMDEventWorkspace.") - # No rotation. Basis vectors should have been left the same, so no extent changes. - self.assertEquals(self.__in_md.getDimension(0).getMinimum(), out_md.getDimension(0).getMinimum()) - self.assertEquals(self.__in_md.getDimension(0).getMaximum(), out_md.getDimension(0).getMaximum()) - self.assertEquals(self.__in_md.getDimension(1).getMinimum(), out_md.getDimension(1).getMinimum()) - self.assertEquals(self.__in_md.getDimension(1).getMaximum(), out_md.getDimension(1).getMaximum()) - self.assertEquals(self.__in_md.getDimension(2).getMinimum(), out_md.getDimension(2).getMinimum()) - self.assertEquals(self.__in_md.getDimension(2).getMaximum(), out_md.getDimension(2).getMaximum()) - self.assertEquals("['zeta', 0, 0]", out_md.getDimension(0).getName() ) - self.assertEquals("[0, 'eta', 0]", out_md.getDimension(1).getName() ) - self.assertEquals("[0, 0, 'xi']", out_md.getDimension(2).getName() ) - self.assertTrue(isinstance(out_md, IMDEventWorkspace), "nopix defaults to True. Should get an IMDEventWorkspace") - - def test_recalculate_extents_with_3_bin_arguments(self): - out_md = CutMD(self.__in_md, P1Bin=[0, 0.3, 0.8], P2Bin=[0.1], P3Bin=[0.1], CheckAxes=False, NoPix=True) - dim = out_md.getDimension(0) - self.assertAlmostEqual(0, dim.getMinimum(), 6, "Wrong minimum") - self.assertEqual(2, dim.getNBins(), "Wrong calculated number of bins") - self.assertAlmostEqual(0.6, dim.getMaximum(), 6, "Wrong calculated maximum") - - def test_truncate_extents(self): - out_md = CutMD(self.__in_md, P1Bin=[0, 1.1, 1], P2Bin=[21], P3Bin=[0.1], CheckAxes=False, NoPix=True) - - self.assertEqual(1, out_md.getDimension(0).getNBins(), "Step is beyond range. Should just be integrated") - self.assertEqual(1, out_md.getDimension(1).getNBins(), "Step is beyond range. Should just be integrated") - - def test_wrong_projection_workspace_format_wrong_column_numbers(self): - projection = CreateEmptyTableWorkspace() - projection.addColumn("str", "name") - # missing other columns - self.assertRaises(RuntimeError, CutMD, InputWorkspace=self.__in_md, Projection=projection, OutputWorkspace="out_ws", P1Bin=[0.1], P2Bin=[0.1], P3Bin=[0.1], CheckAxes=False) - - def test_wrong_table_workspace_format_wrong_row_numbers(self): - projection = CreateEmptyTableWorkspace() - # Correct number of columns, and names - projection.addColumn("str", "name") - projection.addColumn("str", "value") - projection.addColumn("double", "offset") - projection.addColumn("str", "type") - # Incorrect number of rows i.e. zero in this case as none added. - self.assertRaises(RuntimeError, CutMD, InputWorkspace=self.__in_md, Projection=projection, OutputWorkspace="out_ws", P1Bin=[0.1], P2Bin=[0.1], P3Bin=[0.1], CheckAxes=False) - - def test_orthogonal_slice_with_scaling(self): - # We create a fake workspace and check to see that the extents get scaled with the new coordinate system when sliced - to_cut = CreateMDWorkspace(Dimensions=3, Extents=[-1,1,-1,1,-1,1], Names='H,K,L', Units='U,U,U') - # Set the UB - SetUB(Workspace=to_cut, a = 1, b = 1, c = 1, alpha =90, beta=90, gamma = 90) - - SetSpecialCoordinates(InputWorkspace=to_cut, SpecialCoordinates='HKL') - - scale_x = 2.0 - scale_y = 2.0 - - projection = CreateEmptyTableWorkspace() - # Correct number of columns, and names - projection.addColumn("str", "name") - projection.addColumn("str", "value") - projection.addColumn("double", "offset") - projection.addColumn("str", "type") - - projection.addRow(["u", "%s,0,0" % scale_x, 0, "r"]) - projection.addRow(["v", "0,%s,0" % scale_y, 0, "r"]) - - u = map(float,projection.cell(0,1).split(",")) - v = map(float,projection.cell(1,1).split(",")) - scale_z = np.cross(v,u)[-1] - projection.addRow(["w", "0,0,%s" % scale_z, 0, "r"]) - - out_md = CutMD(to_cut, Projection=projection, P1Bin=[0.1], P2Bin=[0.1], P3Bin=[0.1]) - - ''' - Here we check that the corners in HKL end up in the expected positions when transformed into the new scaled basis - provided by the W transform (projection table) - ''' - self.assertEquals(-(1/scale_x), out_md.getDimension(0).getMinimum()) - self.assertEquals((1/scale_x), out_md.getDimension(0).getMaximum()) - self.assertEquals(-(1/scale_y), out_md.getDimension(1).getMinimum()) - self.assertEquals((1/scale_y), out_md.getDimension(1).getMaximum()) - self.assertEquals((1/scale_z), out_md.getDimension(2).getMinimum()) - self.assertEquals(-(1/scale_z), out_md.getDimension(2).getMaximum()) - self.assertEquals("['2.00zeta', 0, 0]", out_md.getDimension(0).getName() ) - self.assertEquals("[0, '2.00eta', 0]", out_md.getDimension(1).getName() ) - self.assertEquals("[0, 0, '-4.00xi']", out_md.getDimension(2).getName() ) - - - def test_non_orthogonal_slice(self): - # We create a fake workspace and check to see that the extents get transformed to the new coordinate system. - to_cut = CreateMDWorkspace(Dimensions=3, Extents=[-1,1,-1,1,-1,1], Names='H,K,L', Units='U,U,U') - # Set the UB - SetUB(Workspace=to_cut, a = 1, b = 1, c = 1, alpha =90, beta=90, gamma = 90) - SetSpecialCoordinates(InputWorkspace=to_cut, SpecialCoordinates='HKL') - - projection = CreateEmptyTableWorkspace() - # Correct number of columns, and names - projection.addColumn("str", "name") - projection.addColumn("str", "value") - projection.addColumn("double", "offset") - projection.addColumn("str", "type") - - projection.addRow(["u", "1,1,0", 0.0, "r"]) - projection.addRow(["v","-1,1,0", 0.0, "r"]) - projection.addRow(["w", "0,0,1", 0.0, "r"]) - - out_md = CutMD(to_cut, Projection=projection, P1Bin=[0.1], P2Bin=[0.1], P3Bin=[0.1], NoPix=True) - - ''' - Here we check that the corners in HKL end up in the expected positions when transformed into the new scaled basis - provided by the W transform (projection table) - ''' - self.assertEquals(-1, out_md.getDimension(0).getMinimum()) - self.assertEquals(1, out_md.getDimension(0).getMaximum()) - self.assertEquals(-1, out_md.getDimension(1).getMinimum()) - self.assertEquals(1, out_md.getDimension(1).getMaximum()) - self.assertEquals(-1, out_md.getDimension(2).getMinimum()) - self.assertEquals(1, out_md.getDimension(2).getMaximum()) - self.assertEquals("['zeta', 'zeta', 0]", out_md.getDimension(0).getName() ) - self.assertEquals("['-eta', 'eta', 0]", out_md.getDimension(1).getName() ) - self.assertEquals("[0, 0, 'xi']", out_md.getDimension(2).getName() ) - - self.assertTrue(isinstance(out_md, IMDHistoWorkspace), "Expect that the output was an IMDHistoWorkspace given the NoPix flag.") - - def test_orthogonal_slice_with_cropping(self): - # We create a fake workspace and check to see that using bin inputs for cropping works - to_cut = CreateMDWorkspace(Dimensions=3, Extents=[-1,1,-1,1,-1,1], Names='H,K,L', Units='U,U,U') - # Set the UB - SetUB(Workspace=to_cut, a = 1, b = 1, c = 1, alpha =90, beta=90, gamma = 90) - SetSpecialCoordinates(InputWorkspace=to_cut, SpecialCoordinates='HKL') - - projection = CreateEmptyTableWorkspace() - # Correct number of columns, and names - projection.addColumn("str", "name") - projection.addColumn("str", "value") - projection.addColumn("double", "offset") - projection.addColumn("str", "type") - - projection.addRow(["u", "1,0,0", 0, "r"]) - projection.addRow(["v", "0,1,0", 0, "r"]) - projection.addRow(["w", "0,0,1", 0, "r"]) - - ''' - Specify the cropping boundaries as part of the bin inputs. - ''' - out_md = CutMD(to_cut, Projection=projection, P1Bin=[-0.5,0.5], P2Bin=[-0.1,0.1], P3Bin=[-0.3,0.3], NoPix=True) - - ''' - Here we check that the corners in HKL end up in the expected positions when transformed into the new scaled basis - provided by the W transform (projection table) - ''' - self.assertAlmostEqual(-0.5, out_md.getDimension(0).getMinimum(), 6) - self.assertAlmostEqual(0.5, out_md.getDimension(0).getMaximum(), 6) - self.assertAlmostEqual(-0.1, out_md.getDimension(1).getMinimum(), 6) - self.assertAlmostEqual(0.1, out_md.getDimension(1).getMaximum(), 6) - self.assertAlmostEqual(-0.3, out_md.getDimension(2).getMinimum(), 6) - self.assertAlmostEqual(0.3, out_md.getDimension(2).getMaximum(), 6) - self.assertEquals("['zeta', 0, 0]", out_md.getDimension(0).getName() ) - self.assertEquals("[0, 'eta', 0]", out_md.getDimension(1).getName() ) - self.assertEquals("[0, 0, 'xi']", out_md.getDimension(2).getName() ) - - self.assertTrue(isinstance(out_md, IMDHistoWorkspace), "Expect that the output was an IMDHistoWorkspace given the NoPix flag.") - - def test_orthogonal_slice_4D(self): - # We create a fake 4-D workspace and check to see that using bin inputs for cropping works - to_cut = CreateMDWorkspace(Dimensions=4, Extents=[-1,1,-1,1,-1,1,-10,10], Names='H,K,L,E', Units='U,U,U,V') - # Set the UB - SetUB(Workspace=to_cut, a = 1, b = 1, c = 1, alpha =90, beta=90, gamma = 90) - SetSpecialCoordinates(InputWorkspace=to_cut, SpecialCoordinates='HKL') - - ''' - Process the 4D workspace - ''' - out_md = CutMD(to_cut, P1Bin=[-0.5,0.5], P2Bin=[-0.1,0.1], P3Bin=[-0.3,0.3], P4Bin=[1], NoPix=True) - - - self.assertAlmostEqual(-0.5, out_md.getDimension(0).getMinimum(), 6) - self.assertAlmostEqual(0.5, out_md.getDimension(0).getMaximum(), 6) - self.assertAlmostEqual(-0.1, out_md.getDimension(1).getMinimum(), 6) - self.assertAlmostEqual(0.1, out_md.getDimension(1).getMaximum(), 6) - self.assertAlmostEqual(-0.3, out_md.getDimension(2).getMinimum(), 6) - self.assertAlmostEqual(0.3, out_md.getDimension(2).getMaximum(), 6) - self.assertAlmostEqual(-10, out_md.getDimension(3).getMinimum(), 6) - self.assertAlmostEqual(10, out_md.getDimension(3).getMaximum(), 6) - self.assertEqual(20, out_md.getDimension(3).getNBins()) - - self.assertEquals("['zeta', 0, 0]", out_md.getDimension(0).getName() ) - self.assertEquals("[0, 'eta', 0]", out_md.getDimension(1).getName() ) - self.assertEquals("[0, 0, 'xi']", out_md.getDimension(2).getName() ) - self.assertEquals("E", out_md.getDimension(3).getName() ) - - self.assertTrue(isinstance(out_md, IMDHistoWorkspace), "Expect that the output was an IMDHistoWorkspace given the NoPix flag.") - - ''' - Process the 4D workspace again, this time with different binning - ''' - out_md = CutMD(to_cut, P1Bin=[-0.5,0.5], P2Bin=[-0.1,0.1], P3Bin=[-0.3,0.3], P4Bin=[-8,1,8], NoPix=True) - self.assertEqual(16, out_md.getDimension(3).getNBins()) - self.assertTrue(isinstance(out_md, IMDHistoWorkspace), "Expect that the output was an IMDHistoWorkspace given the NoPix flag.") - - -if __name__ == '__main__': - unittest.main() diff --git a/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/CMakeLists.txt b/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/CMakeLists.txt index 7efb5e765f89aa20ec81df8c7417fed350bb8061..77b67b9edc8f9142c083ae3d3004f4ffe577537f 100644 --- a/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/CMakeLists.txt +++ b/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/CMakeLists.txt @@ -27,6 +27,7 @@ set ( TEST_PY_FILES InelasticIndirectReductionTest.py IndirectTransmissionTest.py IndirectTransmissionMonitorTest.py + LoadDNSLegacyTest.py LoadFullprofFileTest.py LoadLiveDataTest.py LoadLogPropertyTableTest.py @@ -54,10 +55,12 @@ set ( TEST_PY_FILES UpdatePeakParameterTableValueTest.py SANSSubtractTest.py TimeSliceTest.py + TransformToIqtTest.py ExportSampleLogsToCSVFileTest.py ExportExperimentLogTest.py PoldiMergeTest.py VesuvioResolutionTest.py + PoldiCreatePeaksFromFileTest.py ) check_tests_valid ( ${CMAKE_CURRENT_SOURCE_DIR} ${TEST_PY_FILES} ) diff --git a/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/LoadDNSLegacyTest.py b/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/LoadDNSLegacyTest.py new file mode 100644 index 0000000000000000000000000000000000000000..bf8977363dcbcd8fb2e2e425c124506a69166619 --- /dev/null +++ b/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/LoadDNSLegacyTest.py @@ -0,0 +1,40 @@ +from mantid.kernel import * +import mantid.simpleapi as api +import unittest +from testhelpers import run_algorithm +from mantid.api import AnalysisDataService +from math import pi + + +class LoadDNSLegacyTest(unittest.TestCase): + + def test_LoadValidData(self): + outputWorkspaceName = "LoadDNSLegacyTest_Test1" + filename = "dn134011vana.d_dat" + alg_test = run_algorithm("LoadDNSLegacy", Filename = filename, \ + OutputWorkspace = outputWorkspaceName) + + self.assertTrue(alg_test.isExecuted()) + + #Verify some values + ws = AnalysisDataService.retrieve(outputWorkspaceName) + # dimensions + self.assertEqual(24, ws.getNumberHistograms()) + self.assertEqual(2, ws.getNumDims()) + # data array + self.assertEqual(31461, ws.readY(1)) + self.assertEqual(13340, ws.readY(23)) + # sample logs + logs = ws.getRun().getLogData() + self.assertEqual('deterota', logs[4].name) + self.assertEqual(-8.54, logs[4].value) + # check whether detector bank is rotated + samplePos = ws.getInstrument().getSample().getPos() + beamDirection = V3D(0,0,1) + det = ws.getDetector(1) + self.assertAlmostEqual(8.54, det.getTwoTheta(samplePos, beamDirection)*180/pi) + run_algorithm("DeleteWorkspace", Workspace = outputWorkspaceName) + return + +if __name__ == '__main__': + unittest.main() diff --git a/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/PoldiCreatePeaksFromFileTest.py b/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/PoldiCreatePeaksFromFileTest.py new file mode 100644 index 0000000000000000000000000000000000000000..0e994d3f140e0746368a030d1676474d967ff8ac --- /dev/null +++ b/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/PoldiCreatePeaksFromFileTest.py @@ -0,0 +1,173 @@ +# pylint: disable=no-init,invalid-name,too-many-public-methods +import unittest +from testhelpers import assertRaisesNothing +from testhelpers.tempfile_wrapper import TemporaryFileHelper + +from mantid.kernel import * +from mantid.api import * +from mantid.simpleapi import * + +class PoldiCreatePeaksFromFileTest(unittest.TestCase): + testname = None + + def __init__(self, *args): + unittest.TestCase.__init__(self, *args) + + def test_Init(self): + assertRaisesNothing(self, AlgorithmManager.create, ("PoldiCreatePeaksFromFile")) + + def test_FileOneCompoundOneAtom(self): + fileHelper = TemporaryFileHelper("""Silicon { + Lattice: 5.43 5.43 5.43 90.0 90.0 90.0 + Spacegroup: F d -3 m + Atoms: { + Si 0 0 0 1.0 0.05 + } + }""") + ws = PoldiCreatePeaksFromFile(fileHelper.getName(), 0.7, 10.0) + + # Check output GroupWorkspace + self.assertEquals(ws.getNumberOfEntries(), 1) + self.assertTrue(ws.contains("Silicon")) + + # Check that the ouput is identical to what's expected + ws_expected = PoldiCreatePeaksFromCell("F d -3 m", "Si 0 0 0 1.0 0.05", a=5.43, LatticeSpacingMin=0.7) + si_ws = AnalysisDataService.retrieve("Silicon") + self._tablesAreEqual(si_ws, ws_expected) + + # Clean up + self._cleanWorkspaces([ws, ws_expected]) + + def test_FileOneCompoundTwoAtoms(self): + # It's the same structure and the same reflections, just the structure factors are different + fileHelper = TemporaryFileHelper("""SiliconCarbon { + Lattice: 5.43 5.43 5.43 90.0 90.0 90.0 + Spacegroup: F d -3 m + Atoms: { + Si 0 0 0 0.9 0.05 + C 0 0 0 0.1 0.05 + } + # Comment + }""") + ws = PoldiCreatePeaksFromFile(fileHelper.getName(), 0.7, 10.0) + + self.assertEquals(ws.getNumberOfEntries(), 1) + self.assertTrue(ws.contains("SiliconCarbon")) + + ws_expected = PoldiCreatePeaksFromCell("F d -3 m", "Si 0 0 0 0.9 0.05; C 0 0 0 0.1 0.05", a=5.43, + LatticeSpacingMin=0.7) + si_ws = AnalysisDataService.retrieve("SiliconCarbon") + self._tablesAreEqual(si_ws, ws_expected) + + # Clean up + self._cleanWorkspaces([ws, ws_expected]) + + def test_FileTwoCompounds(self): + # It's the same structure and the same reflections, just the structure factors are different + fileHelper = TemporaryFileHelper("""SiliconCarbon { + Lattice: 5.43 5.43 5.43 90.0 90.0 90.0 + Spacegroup: F d -3 m + Atoms: { + Si 0 0 0 0.9 0.05 + C 0 0 0 0.1 0.05 + } + } + Silicon { + Lattice: 5.43 5.43 5.43 90.0 90.0 90.0 + Spacegroup: F d -3 m + Atoms: { + Si 0 0 0 1.0 0.05 + } + }""") + ws = PoldiCreatePeaksFromFile(fileHelper.getName(), 0.7, 10.0) + + self.assertEquals(ws.getNumberOfEntries(), 2) + self.assertTrue(ws.contains("SiliconCarbon")) + self.assertTrue(ws.contains("Silicon")) + + self._cleanWorkspaces([ws]) + + def test_FileFaultyLatticeStrings(self): + fhLatticeMissing = TemporaryFileHelper("""Silicon { + Spacegroup: F d -3 m + Atoms: { + Si 0 0 0 1.0 0.05 + } + }""") + + fhNoLattice = TemporaryFileHelper("""Silicon { + Lattice: + Spacegroup: F d -3 m + Atoms: { + Si 0 0 0 1.0 0.05 + } + }""") + + fhInvalidLattice = TemporaryFileHelper("""Silicon { + Lattice: invalid + Spacegroup: F d -3 m + Atoms: { + Si 0 0 0 1.0 0.05 + } + }""") + + self.assertRaises(RuntimeError, PoldiCreatePeaksFromFile, *(fhLatticeMissing.getName(), 0.7, 10.0, 'ws')) + self.assertRaises(RuntimeError, PoldiCreatePeaksFromFile, *(fhNoLattice.getName(), 0.7, 10.0, 'ws')) + self.assertRaises(RuntimeError, PoldiCreatePeaksFromFile, *(fhInvalidLattice.getName(), 0.7, 10.0, 'ws')) + + + def test_FileFaultySpaceGroupStrings(self): + fhSgMissing = TemporaryFileHelper("""Silicon { + Lattice: 5.43 5.43 5.43 90.0 90.0 90.0 + Atoms: { + Si 0 0 0 1.0 0.05 + } + }""") + + fhSgInvalid = TemporaryFileHelper("""Silicon { + Lattice: 5.43 5.43 5.43 90.0 90.0 90.0 + Spacegroup: invalid + Atoms: { + Si 0 0 0 1.0 0.05 + } + }""") + + self.assertRaises(RuntimeError, PoldiCreatePeaksFromFile, *(fhSgMissing.getName(), 0.7, 10.0, 'ws')) + self.assertRaises(RuntimeError, PoldiCreatePeaksFromFile, *(fhSgInvalid.getName(), 0.7, 10.0, 'ws')) + + def test_FileFaultyAtomStrings(self): + fhAtomsMissing = TemporaryFileHelper("""Silicon { + Lattice: 5.43 5.43 5.43 90.0 90.0 90.0 + Spacegroup: F d -3 m + }""") + + fhAtomsNoBraces = TemporaryFileHelper("""Silicon { + Lattice: 5.43 5.43 5.43 90.0 90.0 90.0 + Spacegroup: invalid + Atoms: + Sis 0 0 0 1.0 0.05 + }""") + fhAtomsEmpty = TemporaryFileHelper("""Silicon { + Lattice: 5.43 5.43 5.43 90.0 90.0 90.0 + Spacegroup: invalid + Atoms: { } + }""") + + self.assertRaises(RuntimeError, PoldiCreatePeaksFromFile, *(fhAtomsMissing.getName(), 0.7, 10.0, 'ws')) + self.assertRaises(RuntimeError, PoldiCreatePeaksFromFile, *(fhAtomsNoBraces.getName(), 0.7, 10.0, 'ws')) + self.assertRaises(RuntimeError, PoldiCreatePeaksFromFile, *(fhAtomsEmpty.getName(), 0.7, 10.0, 'ws')) + + + def _tablesAreEqual(self, lhs, rhs): + self.assertEquals(lhs.rowCount(), rhs.rowCount(), msg="Row count of tables is different") + + for r in range(lhs.rowCount()): + self.assertEquals(lhs.row(r), rhs.row(r), "Row " + str(r) + " of tables differ.") + + def _cleanWorkspaces(self, wsList): + for ws in wsList: + DeleteWorkspace(ws) + + +if __name__ == '__main__': + unittest.main() diff --git a/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/TransformToIqtTest.py b/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/TransformToIqtTest.py new file mode 100644 index 0000000000000000000000000000000000000000..ac64daa184372cf0ff5cdb01be99549a8036cff2 --- /dev/null +++ b/Code/Mantid/Framework/PythonInterface/test/python/plugins/algorithms/TransformToIqtTest.py @@ -0,0 +1,60 @@ +import unittest +from mantid.simpleapi import * +from mantid.api import * + + +class TransformToIqtTest(unittest.TestCase): + + + def setUp(self): + """ + Generate reference result param table. + """ + + CreateEmptyTableWorkspace(OutputWorkspace='__TransformToIqtTest_param') + self._param_table = mtd['__TransformToIqtTest_param'] + + self._param_table.addColumn('int', 'SampleInputBins') + self._param_table.addColumn('float', 'BinReductionFactor') + self._param_table.addColumn('int', 'SampleOutputBins') + self._param_table.addColumn('float', 'EnergyMin') + self._param_table.addColumn('float', 'EnergyMax') + self._param_table.addColumn('float', 'EnergyWidth') + self._param_table.addColumn('float', 'Resolution') + self._param_table.addColumn('int', 'ResolutionBins') + + self._param_table.addRow([1725, 10.0, 172, -0.5, 0.5, 0.00581395, 0.0175, 6]) + + + def test_with_can_reduction(self): + """ + Tests running using the container reduction as a resolution. + """ + + sample = Load('irs26176_graphite002_red') + can = Load('irs26173_graphite002_red') + + params, iqt = TransformToIqt(SampleWorkspace=sample, + ResolutionWorkspace=can, + BinReductionFactor=10) + + self.assertEqual(CheckWorkspacesMatch(params, self._param_table), "Success!") + + + def test_with_resolution_reduction(self): + """ + Tests running using the instrument resolution workspace. + """ + + sample = Load('irs26176_graphite002_red') + resolution = Load('irs26173_graphite002_res') + + params, iqt = TransformToIqt(SampleWorkspace=sample, + ResolutionWorkspace=resolution, + BinReductionFactor=10) + + self.assertEqual(CheckWorkspacesMatch(params, self._param_table), "Success!") + + +if __name__ == '__main__': + unittest.main() diff --git a/Code/Mantid/Framework/PythonInterface/test/testhelpers/CMakeLists.txt b/Code/Mantid/Framework/PythonInterface/test/testhelpers/CMakeLists.txt index 8c15b65d9ee05111c20374bcfb153a78f187dbdc..8db79e4b0cec9c095b59655d80d158bc0074fb36 100644 --- a/Code/Mantid/Framework/PythonInterface/test/testhelpers/CMakeLists.txt +++ b/Code/Mantid/Framework/PythonInterface/test/testhelpers/CMakeLists.txt @@ -5,6 +5,7 @@ set ( PY_FILES __init__.py algorithm_decorator.py + tempfile_wrapper.py ) # Copy python files to output directory diff --git a/Code/Mantid/Framework/PythonInterface/test/testhelpers/tempfile_wrapper.py b/Code/Mantid/Framework/PythonInterface/test/testhelpers/tempfile_wrapper.py new file mode 100644 index 0000000000000000000000000000000000000000..b28413a026e0463066b80b6e46548049205d9651 --- /dev/null +++ b/Code/Mantid/Framework/PythonInterface/test/testhelpers/tempfile_wrapper.py @@ -0,0 +1,46 @@ +from tempfile import NamedTemporaryFile +import os + + +class TemporaryFileHelper(object): + """Helper class for temporary files in unit tests + + This class is a small helper for using temporary files for unit test. On instantiation, a temporary file will be + created (using NamedTemporaryFile from the tempfile module). If the string argument to the constructor is not empty, + its content will be written to that file. The getName()-method provides the name of the temporary file, which can + for example be passed to an algorithm that expects a FileProperty. On destruction of the TemporaryFileHelper object, + the temporary file is removed automatically using os.unlink(). + + Usage: + emptyFileHelper = TemporaryFileHelper() + fh = open(emptyFileHelper.getName(), 'r+') + fh.write("Something or other\n") + fh.close() + + filledFileHelper = TemporaryFileHelper("Something or other\n") + other = open(filledFileHelper.getName(), 'r') + for line in other: + print line + other.close() + + del emptyFileHelper + del filledFileHelper + """ + tempFile = None + + def __init__(self, fileContent=""): + self.tempFile = NamedTemporaryFile('r+', delete=False) + + if fileContent: + self._setFileContent(fileContent) + + def __del__(self): + os.unlink(self.tempFile.name) + + def getName(self): + return self.tempFile.name + + def _setFileContent(self, content): + fileHandle = open(self.getName(), 'r+') + fileHandle.write(content) + fileHandle.close() diff --git a/Code/Mantid/Framework/SINQ/inc/MantidSINQ/PoldiCreatePeaksFromCell.h b/Code/Mantid/Framework/SINQ/inc/MantidSINQ/PoldiCreatePeaksFromCell.h index 69f1a90db99018ff6e65201e5d55d9a28aa041e5..b622976ee7e2e3c5f6f2c0689cfe79a0a21b7a39 100644 --- a/Code/Mantid/Framework/SINQ/inc/MantidSINQ/PoldiCreatePeaksFromCell.h +++ b/Code/Mantid/Framework/SINQ/inc/MantidSINQ/PoldiCreatePeaksFromCell.h @@ -71,7 +71,9 @@ protected: Geometry::UnitCell getUnitCellFromProperties() const; Geometry::UnitCell getConstrainedUnitCell( const Geometry::UnitCell &unitCell, - const Geometry::PointGroup::CrystalSystem &crystalSystem) const; + const Geometry::PointGroup::CrystalSystem &crystalSystem, + const Geometry::Group::CoordinateSystem &coordinateSystem = + Geometry::Group::Orthogonal) const; private: void init(); diff --git a/Code/Mantid/Framework/SINQ/inc/MantidSINQ/PoldiFitPeaks2D.h b/Code/Mantid/Framework/SINQ/inc/MantidSINQ/PoldiFitPeaks2D.h index dc2d381822e324b24fffd5f45d4f864a9865e578..165df2ca7c0bb74e5922db6f39b58832342b1ed5 100644 --- a/Code/Mantid/Framework/SINQ/inc/MantidSINQ/PoldiFitPeaks2D.h +++ b/Code/Mantid/Framework/SINQ/inc/MantidSINQ/PoldiFitPeaks2D.h @@ -5,6 +5,10 @@ #include "MantidSINQ/DllConfig.h" #include "MantidAPI/Algorithm.h" #include "MantidAPI/IFunction.h" +#include "MantidAPI/IPeakFunction.h" + +#include "MantidKernel/Matrix.h" + #include "MantidDataObjects/TableWorkspace.h" #include "MantidSINQ/PoldiUtilities/PoldiPeakCollection.h" #include "MantidSINQ/PoldiUtilities/PoldiTimeTransformer.h" @@ -58,6 +62,10 @@ public: virtual const std::string summary() const; + boost::shared_ptr<Kernel::DblMatrix> getLocalCovarianceMatrix( + const boost::shared_ptr<const Kernel::DblMatrix> &covarianceMatrix, + size_t parameterOffset, size_t nParams) const; + protected: PoldiPeakCollection_sptr getPeakCollection(const DataObjects::TableWorkspace_sptr &peakTable) const; @@ -72,7 +80,7 @@ protected: PoldiPeakCollection_sptr &to) const; PoldiPeakCollection_sptr - getPeakCollectionFromFunction(const API::IFunction_sptr &fitFunction) const; + getPeakCollectionFromFunction(const API::IFunction_sptr &fitFunction); Poldi2DFunction_sptr getFunctionFromPeakCollection( const PoldiPeakCollection_sptr &peakCollection) const; void addBackgroundTerms(Poldi2DFunction_sptr poldi2DFunction) const; diff --git a/Code/Mantid/Framework/SINQ/src/PoldiCreatePeaksFromCell.cpp b/Code/Mantid/Framework/SINQ/src/PoldiCreatePeaksFromCell.cpp index 331f92a53ea69633cbe5ed451bd1fdefeb6cc31f..487f670ac7a22e5a2f56e9631d4e66306690b888 100644 --- a/Code/Mantid/Framework/SINQ/src/PoldiCreatePeaksFromCell.cpp +++ b/Code/Mantid/Framework/SINQ/src/PoldiCreatePeaksFromCell.cpp @@ -78,8 +78,8 @@ SpaceGroup_const_sptr PoldiCreatePeaksFromCell::getSpaceGroup( CompositeBraggScatterer_sptr PoldiCreatePeaksFromCell::getScatterers( const std::string &scattererString) const { boost::char_separator<char> atomSep(";"); - boost::tokenizer<boost::char_separator<char>> tokens(scattererString, - atomSep); + boost::tokenizer<boost::char_separator<char> > tokens(scattererString, + atomSep); std::vector<BraggScatterer_sptr> scatterers; @@ -104,7 +104,7 @@ BraggScatterer_sptr PoldiCreatePeaksFromCell::getScatterer( getCleanScattererTokens(tokens); std::vector<std::string> properties = boost::assign::list_of("Element")("Position")("Occupancy")("U") - .convert_to_container<std::vector<std::string>>(); + .convert_to_container<std::vector<std::string> >(); std::string initString; for (size_t i = 0; i < cleanScattererTokens.size(); ++i) { @@ -183,12 +183,12 @@ UnitCell PoldiCreatePeaksFromCell::getUnitCellFromProperties() const { } /** Returns a new UnitCell-object with crystal system constraints taken into - *account + * account * * This method constructs a new UnitCell-object based on the values of the - *supplied cell, + * supplied cell, * but takes into account the constraints of the crystal system. For - *monoclinic, a unique b-axis is assumed. + * monoclinic, a unique b-axis is assumed. * * It's useful for "cleaning" user input. * @@ -197,8 +197,8 @@ UnitCell PoldiCreatePeaksFromCell::getUnitCellFromProperties() const { * @return UnitCell-object with applied constraints */ UnitCell PoldiCreatePeaksFromCell::getConstrainedUnitCell( - const UnitCell &unitCell, - const PointGroup::CrystalSystem &crystalSystem) const { + const UnitCell &unitCell, const PointGroup::CrystalSystem &crystalSystem, + const Group::CoordinateSystem &coordinateSystem) const { switch (crystalSystem) { case PointGroup::Cubic: return UnitCell(unitCell.a(), unitCell.a(), unitCell.a()); @@ -209,12 +209,15 @@ UnitCell PoldiCreatePeaksFromCell::getConstrainedUnitCell( case PointGroup::Monoclinic: return UnitCell(unitCell.a(), unitCell.b(), unitCell.c(), 90.0, unitCell.beta(), 90.0); + case PointGroup::Trigonal: + if (coordinateSystem == Group::Orthogonal) { + return UnitCell(unitCell.a(), unitCell.a(), unitCell.a(), + unitCell.alpha(), unitCell.alpha(), unitCell.alpha()); + } + // fall through to hexagonal. case PointGroup::Hexagonal: return UnitCell(unitCell.a(), unitCell.a(), unitCell.c(), 90.0, 90.0, 120.0); - case PointGroup::Trigonal: - return UnitCell(unitCell.a(), unitCell.a(), unitCell.a(), unitCell.alpha(), - unitCell.alpha(), unitCell.alpha()); default: return UnitCell(unitCell); } @@ -233,8 +236,8 @@ void PoldiCreatePeaksFromCell::init() { declareProperty("Atoms", "", "Atoms in the asymmetric unit. Format: \n" "Element x y z Occupancy U; ... "); - boost::shared_ptr<BoundedValidator<double>> latticeParameterEdgeValidator = - boost::make_shared<BoundedValidator<double>>(0.0, 0.0); + boost::shared_ptr<BoundedValidator<double> > latticeParameterEdgeValidator = + boost::make_shared<BoundedValidator<double> >(0.0, 0.0); latticeParameterEdgeValidator->clearUpper(); declareProperty("a", 1.0, latticeParameterEdgeValidator, "Lattice parameter a"); @@ -243,8 +246,8 @@ void PoldiCreatePeaksFromCell::init() { declareProperty("c", 1.0, latticeParameterEdgeValidator->clone(), "Lattice parameter c"); - boost::shared_ptr<BoundedValidator<double>> latticeParameterAngleValidator = - boost::make_shared<BoundedValidator<double>>(0.0, 180.0); + boost::shared_ptr<BoundedValidator<double> > latticeParameterAngleValidator = + boost::make_shared<BoundedValidator<double> >(0.0, 180.0); declareProperty("alpha", 90.0, latticeParameterAngleValidator, "Lattice parameter alpha"); declareProperty("beta", 90.0, latticeParameterAngleValidator->clone(), @@ -252,8 +255,8 @@ void PoldiCreatePeaksFromCell::init() { declareProperty("gamma", 90.0, latticeParameterAngleValidator->clone(), "Lattice parameter gamma"); - boost::shared_ptr<BoundedValidator<double>> dValidator = - boost::make_shared<BoundedValidator<double>>(0.01, 0.0); + boost::shared_ptr<BoundedValidator<double> > dValidator = + boost::make_shared<BoundedValidator<double> >(0.01, 0.0); dValidator->clearUpper(); declareProperty("LatticeSpacingMin", 0.5, dValidator, @@ -272,10 +275,14 @@ void PoldiCreatePeaksFromCell::exec() { // Get all user input regarding the unit cell SpaceGroup_const_sptr spaceGroup = getSpaceGroup(getProperty("SpaceGroup")); PointGroup_sptr pointGroup = - PointGroupFactory::Instance().createPointGroupFromSpaceGroupSymbol( - spaceGroup->hmSymbol()); + PointGroupFactory::Instance().createPointGroupFromSpaceGroup(spaceGroup); UnitCell unitCell = getConstrainedUnitCell(getUnitCellFromProperties(), - pointGroup->crystalSystem()); + pointGroup->crystalSystem(), + pointGroup->getCoordinateSystem()); + + g_log.information() << "Constrained unit cell is: " << unitCellToStr(unitCell) + << std::endl; + CompositeBraggScatterer_sptr scatterers = getScatterers(getProperty("Atoms")); // Create a CrystalStructure-object for use with PoldiPeakCollection diff --git a/Code/Mantid/Framework/SINQ/src/PoldiFitPeaks2D.cpp b/Code/Mantid/Framework/SINQ/src/PoldiFitPeaks2D.cpp index 735094834f0288d4e726c83a446d37d785719773..ce552fe18c6fa3c9f00dc5b70fd85ea99ce4f156 100644 --- a/Code/Mantid/Framework/SINQ/src/PoldiFitPeaks2D.cpp +++ b/Code/Mantid/Framework/SINQ/src/PoldiFitPeaks2D.cpp @@ -50,9 +50,7 @@ const std::string PoldiFitPeaks2D::name() const { return "PoldiFitPeaks2D"; } int PoldiFitPeaks2D::version() const { return 1; } /// Algorithm's category for identification. @see Algorithm::category -const std::string PoldiFitPeaks2D::category() const { - return "SINQ\\Poldi"; -} +const std::string PoldiFitPeaks2D::category() const { return "SINQ\\Poldi"; } /// Very short algorithm summary. @see Algorith::summary const std::string PoldiFitPeaks2D::summary() const { @@ -102,6 +100,37 @@ void PoldiFitPeaks2D::init() { "Table workspace with fitted peaks."); } +/** + * Extracts the covariance matrix for the supplied function + * + * This method extracts the covariance matrix for a sub-function from + * the global covariance matrix. If no matrix is given, a zero-matrix is + * returned. + * + * @param covarianceMatrix :: Global covariance matrix. + * @param parameterOffset :: Offset for the parameters of profileFunction. + * @param nParams :: Number of parameters of the local function. + * @return + */ +boost::shared_ptr<DblMatrix> PoldiFitPeaks2D::getLocalCovarianceMatrix( + const boost::shared_ptr<const Kernel::DblMatrix> &covarianceMatrix, + size_t parameterOffset, size_t nParams) const { + if (covarianceMatrix) { + boost::shared_ptr<Kernel::DblMatrix> localCov = + boost::make_shared<Kernel::DblMatrix>(nParams, nParams, false); + for (size_t j = 0; j < nParams; ++j) { + for (size_t k = 0; k < nParams; ++k) { + (*localCov)[j][k] = + (*covarianceMatrix)[parameterOffset + j][parameterOffset + k]; + } + } + + return localCov; + } + + return boost::make_shared<Kernel::DblMatrix>(nParams, nParams, false); +} + /** * Construct a PoldiPeakCollection from a Poldi2DFunction * @@ -114,7 +143,7 @@ void PoldiFitPeaks2D::init() { * @return PoldiPeakCollection containing peaks with normalized intensities */ PoldiPeakCollection_sptr PoldiFitPeaks2D::getPeakCollectionFromFunction( - const IFunction_sptr &fitFunction) const { + const IFunction_sptr &fitFunction) { Poldi2DFunction_sptr poldi2DFunction = boost::dynamic_pointer_cast<Poldi2DFunction>(fitFunction); @@ -126,6 +155,11 @@ PoldiPeakCollection_sptr PoldiFitPeaks2D::getPeakCollectionFromFunction( PoldiPeakCollection_sptr normalizedPeaks = boost::make_shared<PoldiPeakCollection>(PoldiPeakCollection::Integral); + boost::shared_ptr<const Kernel::DblMatrix> covarianceMatrix = + poldi2DFunction->getCovarianceMatrix(); + + size_t offset = 0; + for (size_t i = 0; i < poldi2DFunction->nFunctions(); ++i) { boost::shared_ptr<PoldiSpectrumDomainFunction> peakFunction = boost::dynamic_pointer_cast<PoldiSpectrumDomainFunction>( @@ -136,36 +170,35 @@ PoldiPeakCollection_sptr PoldiFitPeaks2D::getPeakCollectionFromFunction( boost::dynamic_pointer_cast<IPeakFunction>( peakFunction->getProfileFunction()); + // Get local covariance matrix + size_t nLocalParams = profileFunction->nParams(); + boost::shared_ptr<Kernel::DblMatrix> localCov = + getLocalCovarianceMatrix(covarianceMatrix, offset, nLocalParams); + profileFunction->setCovarianceMatrix(localCov); + + // Increment offset for next function + offset += nLocalParams; + + IAlgorithm_sptr errorAlg = createChildAlgorithm("EstimatePeakErrors"); + errorAlg->setProperty( + "Function", boost::dynamic_pointer_cast<IFunction>(profileFunction)); + errorAlg->setPropertyValue("OutputWorkspace", "Errors"); + errorAlg->execute(); + double centre = profileFunction->centre(); double height = profileFunction->height(); + double fwhmValue = profileFunction->fwhm(); - size_t dIndex = 0; - size_t iIndex = 0; - size_t fIndex = 0; - - for (size_t j = 0; j < profileFunction->nParams(); ++j) { - if (profileFunction->getParameter(j) == centre) { - dIndex = j; - } else if (profileFunction->getParameter(j) == height) { - iIndex = j; - } else { - fIndex = j; - } - } - - // size_t dIndex = peakFunction->parameterIndex("Centre"); - UncertainValue d(peakFunction->getParameter(dIndex), - peakFunction->getError(dIndex)); + ITableWorkspace_sptr errorTable = + errorAlg->getProperty("OutputWorkspace"); - // size_t iIndex = peakFunction->parameterIndex("Area"); - UncertainValue intensity(peakFunction->getParameter(iIndex), - peakFunction->getError(iIndex)); + double centreError = errorTable->cell<double>(0, 2); + double heightError = errorTable->cell<double>(1, 2); + double fwhmError = errorTable->cell<double>(2, 2); - // size_t fIndex = peakFunction->parameterIndex("Sigma"); - double fwhmValue = profileFunction->fwhm(); - UncertainValue fwhm(fwhmValue, fwhmValue / - peakFunction->getParameter(fIndex) * - peakFunction->getError(fIndex)); + UncertainValue d(centre, centreError); + UncertainValue intensity(height, heightError); + UncertainValue fwhm(fwhmValue, fwhmError); PoldiPeak_sptr peak = PoldiPeak::create(MillerIndices(), d, intensity, UncertainValue(1.0)); diff --git a/Code/Mantid/Framework/SINQ/test/PoldiCreatePeaksFromCellTest.h b/Code/Mantid/Framework/SINQ/test/PoldiCreatePeaksFromCellTest.h index 3ab73521b241cefdb2446f9dd573e72a2b1e93a7..5bb7cd606b7635195dd720862562e1243c3b5277 100644 --- a/Code/Mantid/Framework/SINQ/test/PoldiCreatePeaksFromCellTest.h +++ b/Code/Mantid/Framework/SINQ/test/PoldiCreatePeaksFromCellTest.h @@ -10,198 +10,191 @@ using Mantid::Poldi::PoldiCreatePeaksFromCell; using namespace Mantid::API; using namespace Mantid::Geometry; -class PoldiCreatePeaksFromCellTest : public CxxTest::TestSuite -{ +class PoldiCreatePeaksFromCellTest : public CxxTest::TestSuite { public: - // This pair of boilerplate methods prevent the suite being created statically - // This means the constructor isn't called when running other tests - static PoldiCreatePeaksFromCellTest *createSuite() { return new PoldiCreatePeaksFromCellTest(); } - static void destroySuite( PoldiCreatePeaksFromCellTest *suite ) { delete suite; } + // This pair of boilerplate methods prevent the suite being created statically + // This means the constructor isn't called when running other tests + static PoldiCreatePeaksFromCellTest *createSuite() { + return new PoldiCreatePeaksFromCellTest(); + } + static void destroySuite(PoldiCreatePeaksFromCellTest *suite) { + delete suite; + } + + void test_Init() { + PoldiCreatePeaksFromCell alg; + TS_ASSERT_THROWS_NOTHING(alg.initialize()) + TS_ASSERT(alg.isInitialized()) + } + + void test_exec() { + /* This test checks that the outcome of the algorithm + * is correct. + */ + std::string outWSName("PoldiCreatePeaksFromCellTest_OutputWS"); + + PoldiCreatePeaksFromCell alg; + TS_ASSERT_THROWS_NOTHING(alg.initialize()) + TS_ASSERT(alg.isInitialized()) + TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("SpaceGroup", "P m -3 m")); + TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue( + "Atoms", "Cl 0 0 0 1.0 0.005; Cs 0.5 0.5 0.5 1.0 0.005");) + TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("a", "4.126")); + TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("LatticeSpacingMin", "0.55")); + TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("LatticeSpacingMax", "4.0")); + TS_ASSERT_THROWS_NOTHING( + alg.setPropertyValue("OutputWorkspace", outWSName)); + TS_ASSERT_THROWS_NOTHING(alg.execute();); + TS_ASSERT(alg.isExecuted()); + + // Retrieve the workspace from data service. + Workspace_sptr ws; + TS_ASSERT_THROWS_NOTHING( + ws = AnalysisDataService::Instance().retrieveWS<Workspace>(outWSName)); + TS_ASSERT(ws); + + ITableWorkspace_sptr tableWs = + boost::dynamic_pointer_cast<ITableWorkspace>(ws); + + TS_ASSERT(tableWs); + // There should be 68 unique reflections for this cell and d-range. + TS_ASSERT_EQUALS(tableWs->rowCount(), 68); + + if (ws) { + AnalysisDataService::Instance().remove(outWSName); + } + } + void testValidateInput() { + PoldiCreatePeaksFromCell alg; + alg.initialize(); - void test_Init() - { - PoldiCreatePeaksFromCell alg; - TS_ASSERT_THROWS_NOTHING( alg.initialize() ) - TS_ASSERT( alg.isInitialized() ) - } + alg.setPropertyValue("LatticeSpacingMin", "1.0"); + alg.setPropertyValue("LatticeSpacingMax", "2.0"); - void test_exec() - { - /* This test checks that the outcome of the algorithm - * is correct. - */ - std::string outWSName("PoldiCreatePeaksFromCellTest_OutputWS"); - - PoldiCreatePeaksFromCell alg; - TS_ASSERT_THROWS_NOTHING( alg.initialize() ) - TS_ASSERT( alg.isInitialized() ) - TS_ASSERT_THROWS_NOTHING( alg.setPropertyValue("SpaceGroup", "P m -3 m") ); - TS_ASSERT_THROWS_NOTHING( alg.setPropertyValue("Atoms", "Cl 0 0 0 1.0 0.005; Cs 0.5 0.5 0.5 1.0 0.005");) - TS_ASSERT_THROWS_NOTHING( alg.setPropertyValue("a", "4.126")); - TS_ASSERT_THROWS_NOTHING( alg.setPropertyValue("LatticeSpacingMin", "0.55")); - TS_ASSERT_THROWS_NOTHING( alg.setPropertyValue("LatticeSpacingMax", "4.0")); - TS_ASSERT_THROWS_NOTHING( alg.setPropertyValue("OutputWorkspace", outWSName) ); - TS_ASSERT_THROWS_NOTHING( alg.execute(); ); - TS_ASSERT( alg.isExecuted() ); - - // Retrieve the workspace from data service. - Workspace_sptr ws; - TS_ASSERT_THROWS_NOTHING( ws = AnalysisDataService::Instance().retrieveWS<Workspace>(outWSName) ); - TS_ASSERT(ws); - - ITableWorkspace_sptr tableWs = boost::dynamic_pointer_cast<ITableWorkspace>(ws); - - TS_ASSERT(tableWs); - // There should be 68 unique reflections for this cell and d-range. - TS_ASSERT_EQUALS(tableWs->rowCount(), 68); - - if (ws) { - AnalysisDataService::Instance().remove(outWSName); - } - } + // dMax is larger than dMin + std::map<std::string, std::string> errorMap = alg.validateInputs(); + TS_ASSERT_EQUALS(errorMap.size(), 0); - void testValidateInput() - { - PoldiCreatePeaksFromCell alg; - alg.initialize(); + alg.setPropertyValue("LatticeSpacingMax", "0.5"); + // now it's smaller - not allowed + errorMap = alg.validateInputs(); + TS_ASSERT_EQUALS(errorMap.size(), 1); - alg.setPropertyValue("LatticeSpacingMin", "1.0"); - alg.setPropertyValue("LatticeSpacingMax", "2.0"); + errorMap.clear(); - // dMax is larger than dMin - std::map<std::string, std::string> errorMap = alg.validateInputs(); - TS_ASSERT_EQUALS(errorMap.size(), 0); + alg.setPropertyValue("LatticeSpacingMax", "-0.5"); + errorMap = alg.validateInputs(); + TS_ASSERT_EQUALS(errorMap.size(), 1) + } - alg.setPropertyValue("LatticeSpacingMax", "0.5"); - // now it's smaller - not allowed - errorMap = alg.validateInputs(); - TS_ASSERT_EQUALS(errorMap.size(), 1); + void testGetLargestDValue() { + // Maximum d-value is 30.0 + UnitCell cell(10.0, 20.0, 30.0); + TestablePoldiCreatePeaksFromCell alg; - errorMap.clear(); + TS_ASSERT_EQUALS(alg.getLargestDValue(cell), 30.0); + } - alg.setPropertyValue("LatticeSpacingMax", "-0.5"); - errorMap = alg.validateInputs(); - TS_ASSERT_EQUALS(errorMap.size(), 1) - } + void testGetDMaxValue() { + // Maximum d-value is 30.0 + UnitCell cell(10.0, 20.0, 30.0); - void testGetLargestDValue() - { - // Maximum d-value is 30.0 - UnitCell cell(10.0, 20.0, 30.0); - TestablePoldiCreatePeaksFromCell alg; + TestablePoldiCreatePeaksFromCell alg; + alg.initialize(); - TS_ASSERT_EQUALS(alg.getLargestDValue(cell), 30.0); - } + // dMax has default value - largest d-value + 1.0 is supposed to be returned + TS_ASSERT_EQUALS(alg.getDMaxValue(cell), 31.0); - void testGetDMaxValue() - { - // Maximum d-value is 30.0 - UnitCell cell(10.0, 20.0, 30.0); + // dMax has been set to a different value + alg.setPropertyValue("LatticeSpacingMax", "2.0"); + TS_ASSERT_EQUALS(alg.getDMaxValue(cell), 2.0); - TestablePoldiCreatePeaksFromCell alg; - alg.initialize(); + alg.setPropertyValue("LatticeSpacingMax", "100.0"); + TS_ASSERT_EQUALS(alg.getDMaxValue(cell), 100.0); + } - // dMax has default value - largest d-value + 1.0 is supposed to be returned - TS_ASSERT_EQUALS(alg.getDMaxValue(cell), 31.0); + void testGetUnitCellFromProperties() { + TestablePoldiCreatePeaksFromCell alg; + alg.initialize(); - // dMax has been set to a different value - alg.setPropertyValue("LatticeSpacingMax", "2.0"); - TS_ASSERT_EQUALS(alg.getDMaxValue(cell), 2.0); + alg.setPropertyValue("a", "3.0"); + alg.setPropertyValue("b", "4.0"); + alg.setPropertyValue("c", "5.0"); - alg.setPropertyValue("LatticeSpacingMax", "100.0"); - TS_ASSERT_EQUALS(alg.getDMaxValue(cell), 100.0); - } + alg.setPropertyValue("alpha", "90.0"); + alg.setPropertyValue("beta", "91.0"); + alg.setPropertyValue("gamma", "92.0"); - void testGetUnitCellFromProperties() - { - TestablePoldiCreatePeaksFromCell alg; - alg.initialize(); + UnitCell unitCell = alg.getUnitCellFromProperties(); - alg.setPropertyValue("a", "3.0"); - alg.setPropertyValue("b", "4.0"); - alg.setPropertyValue("c", "5.0"); + TS_ASSERT_EQUALS(unitCell.a(), 3.0); + TS_ASSERT_EQUALS(unitCell.b(), 4.0); + TS_ASSERT_EQUALS(unitCell.c(), 5.0); + TS_ASSERT_EQUALS(unitCell.alpha(), 90.0); + TS_ASSERT_EQUALS(unitCell.beta(), 91.0); + TS_ASSERT_EQUALS(unitCell.gamma(), 92.0); + } - alg.setPropertyValue("alpha", "90.0"); - alg.setPropertyValue("beta", "91.0"); - alg.setPropertyValue("gamma", "92.0"); + void testGetConstrainedUnitCell() { + TestablePoldiCreatePeaksFromCell alg; - UnitCell unitCell = alg.getUnitCellFromProperties(); + UnitCell rawCell(2.0, 3.0, 4.0, 91.0, 92.0, 93.0); - TS_ASSERT_EQUALS(unitCell.a(), 3.0); - TS_ASSERT_EQUALS(unitCell.b(), 4.0); - TS_ASSERT_EQUALS(unitCell.c(), 5.0); - TS_ASSERT_EQUALS(unitCell.alpha(), 90.0); - TS_ASSERT_EQUALS(unitCell.beta(), 91.0); - TS_ASSERT_EQUALS(unitCell.gamma(), 92.0); - } + checkUnitCellParameters( + alg.getConstrainedUnitCell(rawCell, PointGroup::Cubic), 2.0, 2.0, 2.0, + 90.0, 90.0, 90.0, "Cubic"); - void testGetConstrainedUnitCell() - { - TestablePoldiCreatePeaksFromCell alg; - - UnitCell rawCell(2.0, 3.0, 4.0, 91.0, 92.0, 93.0); - - checkUnitCellParameters( - alg.getConstrainedUnitCell(rawCell, PointGroup::Cubic), - 2.0, 2.0, 2.0, 90.0, 90.0, 90.0, "Cubic" - ); - - checkUnitCellParameters( - alg.getConstrainedUnitCell(rawCell, PointGroup::Tetragonal), - 2.0, 2.0, 4.0, 90.0, 90.0, 90.0, "Tetragonal" - ); - - checkUnitCellParameters( - alg.getConstrainedUnitCell(rawCell, PointGroup::Orthorhombic), - 2.0, 3.0, 4.0, 90.0, 90.0, 90.0, "Orthorhombic" - ); - - checkUnitCellParameters( - alg.getConstrainedUnitCell(rawCell, PointGroup::Monoclinic), - 2.0, 3.0, 4.0, 90.0, 92.0, 90.0, "Monoclinic" - ); - - checkUnitCellParameters( - alg.getConstrainedUnitCell(rawCell, PointGroup::Triclinic), - 2.0, 3.0, 4.0, 91.0, 92.0, 93.0, "Triclinic" - ); - - checkUnitCellParameters( - alg.getConstrainedUnitCell(rawCell, PointGroup::Hexagonal), - 2.0, 2.0, 4.0, 90.0, 90.0, 120.0, "Hexagonal" - ); - - checkUnitCellParameters( - alg.getConstrainedUnitCell(rawCell, PointGroup::Trigonal), - 2.0, 2.0, 2.0, 91.0, 91.0, 91.0, "Trigonal" - ); - } + checkUnitCellParameters( + alg.getConstrainedUnitCell(rawCell, PointGroup::Tetragonal), 2.0, 2.0, + 4.0, 90.0, 90.0, 90.0, "Tetragonal"); -private: - void checkUnitCellParameters(const UnitCell &cell, double a, double b, double c, double alpha, double beta, double gamma, const std::string &message) - { - TSM_ASSERT_DELTA(message, cell.a(), a, 1e-14); - TSM_ASSERT_DELTA(message, cell.b(), b, 1e-14); - TSM_ASSERT_DELTA(message, cell.c(), c, 1e-14); - - TSM_ASSERT_DELTA(message, cell.alpha(), alpha, 1e-14); - TSM_ASSERT_DELTA(message, cell.beta(), beta, 1e-14); - TSM_ASSERT_DELTA(message, cell.gamma(), gamma, 1e-14); - } + checkUnitCellParameters( + alg.getConstrainedUnitCell(rawCell, PointGroup::Orthorhombic), 2.0, 3.0, + 4.0, 90.0, 90.0, 90.0, "Orthorhombic"); - class TestablePoldiCreatePeaksFromCell : public PoldiCreatePeaksFromCell - { - public: - TestablePoldiCreatePeaksFromCell() : PoldiCreatePeaksFromCell() - { } - ~TestablePoldiCreatePeaksFromCell() { } + checkUnitCellParameters( + alg.getConstrainedUnitCell(rawCell, PointGroup::Monoclinic), 2.0, 3.0, + 4.0, 90.0, 92.0, 90.0, "Monoclinic"); - friend class PoldiCreatePeaksFromCellTest; - }; + checkUnitCellParameters( + alg.getConstrainedUnitCell(rawCell, PointGroup::Triclinic), 2.0, 3.0, + 4.0, 91.0, 92.0, 93.0, "Triclinic"); + checkUnitCellParameters( + alg.getConstrainedUnitCell(rawCell, PointGroup::Hexagonal), 2.0, 2.0, + 4.0, 90.0, 90.0, 120.0, "Hexagonal"); -}; + checkUnitCellParameters( + alg.getConstrainedUnitCell(rawCell, PointGroup::Trigonal), 2.0, 2.0, + 2.0, 91.0, 91.0, 91.0, "Trigonal"); + checkUnitCellParameters(alg.getConstrainedUnitCell(rawCell, + PointGroup::Trigonal, + Group::Hexagonal), + 2.0, 2.0, 4.0, 90.0, 90.0, 120.0, "Trigonal"); + } + +private: + void checkUnitCellParameters(const UnitCell &cell, double a, double b, + double c, double alpha, double beta, + double gamma, const std::string &message) { + TSM_ASSERT_DELTA(message, cell.a(), a, 1e-14); + TSM_ASSERT_DELTA(message, cell.b(), b, 1e-14); + TSM_ASSERT_DELTA(message, cell.c(), c, 1e-14); + + TSM_ASSERT_DELTA(message, cell.alpha(), alpha, 1e-14); + TSM_ASSERT_DELTA(message, cell.beta(), beta, 1e-14); + TSM_ASSERT_DELTA(message, cell.gamma(), gamma, 1e-14); + } + + class TestablePoldiCreatePeaksFromCell : public PoldiCreatePeaksFromCell { + public: + TestablePoldiCreatePeaksFromCell() : PoldiCreatePeaksFromCell() {} + ~TestablePoldiCreatePeaksFromCell() {} + + friend class PoldiCreatePeaksFromCellTest; + }; +}; #endif /* MANTID_SINQ_POLDICREATEPEAKSFROMCELLTEST_H_ */ diff --git a/Code/Mantid/Framework/SINQ/test/PoldiFitPeaks2DTest.h b/Code/Mantid/Framework/SINQ/test/PoldiFitPeaks2DTest.h index 9c18d599c85b0f0833c8ea46ca5a989824390667..1ac7a69edaaf3814ff1e7001da18d7d75adc1249 100644 --- a/Code/Mantid/Framework/SINQ/test/PoldiFitPeaks2DTest.h +++ b/Code/Mantid/Framework/SINQ/test/PoldiFitPeaks2DTest.h @@ -6,6 +6,8 @@ #include "MantidAPI/FrameworkManager.h" #include "MantidAPI/AlgorithmManager.h" +#include "MantidKernel/Matrix.h" + #include "MantidSINQ/PoldiFitPeaks2D.h" #include "MantidSINQ/PoldiUtilities/PoldiSpectrumDomainFunction.h" #include "MantidSINQ/PoldiUtilities/PoldiMockInstrumentHelpers.h" @@ -14,6 +16,7 @@ using namespace Mantid::Poldi; using namespace Mantid::API; using namespace Mantid::DataObjects; +using namespace Mantid::Kernel; class PoldiFitPeaks2DTest : public CxxTest::TestSuite { @@ -234,6 +237,18 @@ public: PoldiPeakCollection_sptr peaks = PoldiPeakCollectionHelpers::createPoldiPeakCollectionNormalized(); IFunction_sptr poldi2DFunction = spectrumCalculator.getFunctionFromPeakCollection(peaks); + size_t nParams = poldi2DFunction->nParams(); + + // Make a matrix with diagonal elements = 0.05 and set as covariance matrix + boost::shared_ptr<DblMatrix> matrix = boost::make_shared<DblMatrix>(nParams, nParams, true); + matrix->operator *=(0.05); + poldi2DFunction->setCovarianceMatrix(matrix); + + // Also set errors for old behavior + for(size_t i = 0; i < nParams; ++i) { + poldi2DFunction->setError(i, sqrt(0.05)); + } + PoldiPeakCollection_sptr peaksFromFunction = spectrumCalculator.getPeakCollectionFromFunction(poldi2DFunction); TS_ASSERT_EQUALS(peaksFromFunction->peakCount(), peaks->peakCount()); @@ -241,8 +256,11 @@ public: PoldiPeak_sptr functionPeak = peaksFromFunction->peak(i); PoldiPeak_sptr referencePeak = peaks->peak(i); - TS_ASSERT_EQUALS(functionPeak->d(), referencePeak->d()); - TS_ASSERT_EQUALS(functionPeak->fwhm(), referencePeak->fwhm()); + TS_ASSERT_EQUALS(functionPeak->d().value(), referencePeak->d().value()); + TS_ASSERT_EQUALS(functionPeak->fwhm().value(), referencePeak->fwhm().value()); + TS_ASSERT_DELTA(functionPeak->d().error(), sqrt(0.05), 1e-6); + TS_ASSERT_DELTA(functionPeak->fwhm(PoldiPeak::AbsoluteD).error(), sqrt(0.05) * (2.0 * sqrt(2.0 * log(2.0))), 1e-6); + } } diff --git a/Code/Mantid/Framework/TestHelpers/src/WorkspaceCreationHelper.cpp b/Code/Mantid/Framework/TestHelpers/src/WorkspaceCreationHelper.cpp index 11df5295a6c60220911a920e59a2c1d0d462533f..1b5c6875f770090cd9cdbea871d42df51eee2907 100644 --- a/Code/Mantid/Framework/TestHelpers/src/WorkspaceCreationHelper.cpp +++ b/Code/Mantid/Framework/TestHelpers/src/WorkspaceCreationHelper.cpp @@ -81,10 +81,8 @@ Workspace2D_sptr Create1DWorkspaceConstant(int size, double value, double error) { MantidVecPtr x1, y1, e1; x1.access().resize(size, 1); - y1.access().resize(size); - std::fill(y1.access().begin(), y1.access().end(), value); - e1.access().resize(size); - std::fill(y1.access().begin(), y1.access().end(), error); + y1.access().resize(size, value); + e1.access().resize(size, error); Workspace2D_sptr retVal(new Workspace2D); retVal->initialize(1, size, size); retVal->setX(0, x1); diff --git a/Code/Mantid/MantidPlot/src/ApplicationWindow.cpp b/Code/Mantid/MantidPlot/src/ApplicationWindow.cpp index bff1921b0d3b2081eb73aa813d5898f851058513..e022a8b33290f6d83400ab7328144fd8886ed863 100644 --- a/Code/Mantid/MantidPlot/src/ApplicationWindow.cpp +++ b/Code/Mantid/MantidPlot/src/ApplicationWindow.cpp @@ -865,7 +865,7 @@ void ApplicationWindow::initGlobalConstants() d_locale.setNumberOptions(QLocale::OmitGroupSeparator); d_decimal_digits = 13; - d_graphing_digits = 3; + d_graphing_digits = 13; d_extended_open_dialog = true; d_extended_export_dialog = true; diff --git a/Code/Mantid/MantidPlot/src/Mantid/MantidUI.cpp b/Code/Mantid/MantidPlot/src/Mantid/MantidUI.cpp index 0b91a054f5125d95e9f2413093a846de48a0a127..e3cbe352b68a1f12721380645eb4c6d909b5ec81 100644 --- a/Code/Mantid/MantidPlot/src/Mantid/MantidUI.cpp +++ b/Code/Mantid/MantidPlot/src/Mantid/MantidUI.cpp @@ -2519,8 +2519,8 @@ void MantidUI::importNumSeriesLog(const QString &wsName, const QString &logName, { //Seconds offset t->setColName(0, "Time (sec)"); - t->setColumnType(0, Table::Numeric); //six digits after 0 - t->setNumericPrecision(6); //six digits after 0 + t->setColumnType(0, Table::Numeric); + t->setNumericPrecision(16); //it's the number of all digits } //Make the column header with the units, if any diff --git a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/ApplyCorr.h b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/ApplyCorr.h index f7d9256f52b6ec503b209092ba0c9da007140816..015811dba57e556e49ac774eadc2099b465600b8 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/ApplyCorr.h +++ b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/ApplyCorr.h @@ -25,20 +25,27 @@ namespace IDA void newData(const QString &dataName); /// Updates the preview mini plot void plotPreview(int specIndex); + /// Handle algorithm completion + void algorithmComplete(bool error); private: virtual void setup(); virtual void run(); virtual bool validate(); virtual void loadSettings(const QSettings & settings); - /// ask the user if they wish to rebin the can - bool requireCanRebin(); + + void addRebinStep(QString toRebin, QString toMatch); + void addInterpolationStep(Mantid::API::MatrixWorkspace_sptr toInterpolate, std::string toMatch); Ui::ApplyCorr m_uiForm; - /// Pointer to the result workspace (for plotting) - Mantid::API::MatrixWorkspace_sptr m_outputWs; + + /// Name of sample workspace (for plotting) + std::string m_sampleWsName; + /// Name of container workspace (for plotting) + std::string m_canWsName; }; + } // namespace IDA } // namespace CustomInterfaces } // namespace MantidQt diff --git a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/CalcCorr.h b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/CalcCorr.h index bbc3c670a3db4cbfdfedaf49612940108cab0407..2ecba2fd9edd8a7037f03939ab1894ee14023f37 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/CalcCorr.h +++ b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/CalcCorr.h @@ -23,18 +23,20 @@ namespace IDA virtual bool validate(); virtual void loadSettings(const QSettings & settings); + bool doValidation(bool silent = false); + private slots: - void shape(int index); - void useCanChecked(bool checked); - void tcSync(); - void getBeamWidthFromWorkspace(const QString& wsname); + void algorithmComplete(bool error); + void getBeamWidthFromWorkspace(const QString& wsName); private: + void addShapeSpecificSampleOptions(Mantid::API::IAlgorithm_sptr alg, QString shape); + void addShapeSpecificCanOptions(Mantid::API::IAlgorithm_sptr alg, QString shape); + Ui::CalcCorr m_uiForm; - QDoubleValidator * m_dblVal; - QDoubleValidator * m_posDblVal; }; + } // namespace IDA } // namespace CustomInterfaces } // namespace MantidQt diff --git a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/CalcCorr.ui b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/CalcCorr.ui index 6ec1670e1868361294f35eff5b84a65fd214d164..5a46cbc78a9517965a05f2e60f66ecdf6fbb775a 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/CalcCorr.ui +++ b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/CalcCorr.ui @@ -7,7 +7,7 @@ <x>0</x> <y>0</y> <width>661</width> - <height>504</height> + <height>462</height> </rect> </property> <property name="windowTitle"> @@ -21,7 +21,7 @@ </property> <layout class="QGridLayout" name="gridLayout_11"> <item row="1" column="1"> - <widget class="MantidQt::MantidWidgets::DataSelector" name="dsCanInput" native="true"> + <widget class="MantidQt::MantidWidgets::DataSelector" name="dsContainer" native="true"> <property name="enabled"> <bool>false</bool> </property> @@ -59,7 +59,7 @@ </widget> </item> <item row="0" column="1"> - <widget class="MantidQt::MantidWidgets::DataSelector" name="dsSampleInput" native="true"> + <widget class="MantidQt::MantidWidgets::DataSelector" name="dsSample" native="true"> <property name="sizePolicy"> <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> <horstretch>0</horstretch> @@ -87,7 +87,7 @@ </widget> </item> <item row="0" column="0"> - <widget class="QLabel" name="label"> + <widget class="QLabel" name="lbInputType"> <property name="text"> <string>Input type:</string> </property> @@ -109,31 +109,19 @@ </property> <layout class="QVBoxLayout" name="verticalLayout_9"> <item> - <layout class="QGridLayout" name="gridLayout_2"> - <item row="0" column="0"> + <layout class="QHBoxLayout" name="loSampleShape"> + <item> <widget class="QLabel" name="lbSampleShape"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> <property name="text"> <string>Sample Shape:</string> </property> </widget> </item> - <item row="0" column="1"> - <widget class="QComboBox" name="cbShape"> - <property name="sizePolicy"> - <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> + <item> + <widget class="QComboBox" name="cbSampleShape"> <item> <property name="text"> - <string>Flat</string> + <string>Flat Plate</string> </property> </item> <item> @@ -143,336 +131,222 @@ </item> </widget> </item> - <item row="3" column="0"> - <widget class="QLabel" name="lbWidth"> - <property name="text"> - <string>Beam Width:</string> - </property> - </widget> - </item> - <item row="2" column="1"> - <widget class="QLineEdit" name="leavar"> - <property name="text"> - <string/> - </property> - </widget> - </item> - <item row="2" column="0"> - <widget class="QLabel" name="lbAvar"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>Sample Angle:</string> - </property> - </widget> - </item> - <item row="2" column="2"> - <widget class="QLabel" name="valAvar"> - <property name="styleSheet"> - <string notr="true">color: rgb(255, 0, 0);</string> - </property> - <property name="text"> - <string>*</string> - </property> - </widget> - </item> - <item row="3" column="1"> - <widget class="QLineEdit" name="lewidth"> - <property name="text"> - <string/> - </property> - </widget> - </item> - <item row="3" column="2"> - <widget class="QLabel" name="valWidth"> - <property name="styleSheet"> - <string notr="true">color: rgb(255, 0, 0);</string> - </property> - <property name="text"> - <string>*</string> - </property> - </widget> - </item> - <item row="1" column="0" colspan="3"> - <widget class="QStackedWidget" name="swShapeDetails"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="lineWidth"> - <number>1</number> + </layout> + </item> + <item> + <widget class="QStackedWidget" name="swShapeOptions"> + <property name="currentIndex"> + <number>0</number> + </property> + <widget class="QWidget" name="pgFlatPlate"> + <layout class="QGridLayout" name="gridLayout_2"> + <property name="margin"> + <number>0</number> </property> - <property name="currentIndex"> + <item row="0" column="2"> + <widget class="QLabel" name="lbFlatSampleAngle"> + <property name="text"> + <string>Sample Angle:</string> + </property> + </widget> + </item> + <item row="3" column="0"> + <widget class="QLabel" name="lbFlatCanFrontThickness"> + <property name="text"> + <string>Container Front Thickness:</string> + </property> + </widget> + </item> + <item row="3" column="2"> + <widget class="QLabel" name="lbFlatCanBackThickness"> + <property name="text"> + <string>Container Back Thickness:</string> + </property> + </widget> + </item> + <item row="3" column="3"> + <widget class="QDoubleSpinBox" name="spFlatCanBackThickness"> + <property name="suffix"> + <string> cm</string> + </property> + <property name="decimals"> + <number>3</number> + </property> + <property name="singleStep"> + <double>0.100000000000000</double> + </property> + </widget> + </item> + <item row="0" column="0"> + <widget class="QLabel" name="lbFlatSampleThickness"> + <property name="text"> + <string>Sample Thickness:</string> + </property> + </widget> + </item> + <item row="3" column="1"> + <widget class="QDoubleSpinBox" name="spFlatCanFrontThickness"> + <property name="suffix"> + <string> cm</string> + </property> + <property name="decimals"> + <number>3</number> + </property> + <property name="singleStep"> + <double>0.100000000000000</double> + </property> + </widget> + </item> + <item row="0" column="3"> + <widget class="QDoubleSpinBox" name="spFlatSampleAngle"> + <property name="decimals"> + <number>3</number> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QDoubleSpinBox" name="spFlatSampleThickness"> + <property name="suffix"> + <string> cm</string> + </property> + <property name="decimals"> + <number>3</number> + </property> + <property name="singleStep"> + <double>0.100000000000000</double> + </property> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="pgCylinder"> + <layout class="QGridLayout" name="gridLayout_4"> + <property name="margin"> <number>0</number> </property> - <widget class="QWidget" name="pageFlat"> - <layout class="QVBoxLayout" name="verticalLayout_4"> - <property name="margin"> - <number>0</number> + <item row="5" column="3"> + <widget class="QDoubleSpinBox" name="spCylBeamWidth"> + <property name="decimals"> + <number>3</number> </property> - <item> - <layout class="QGridLayout" name="gridLayout_5_thickness" columnminimumwidth="97,0,0,0,0,0,0,0,0"> - <item row="0" column="2"> - <widget class="QLabel" name="valts"> - <property name="styleSheet"> - <string notr="true">color: rgb(255, 0, 0);</string> - </property> - <property name="text"> - <string>*</string> - </property> - </widget> - </item> - <item row="0" column="5"> - <widget class="QLabel" name="valtc1"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>9</width> - <height>24</height> - </size> - </property> - <property name="styleSheet"> - <string notr="true">color: rgb(255, 0, 0);</string> - </property> - <property name="text"> - <string>*</string> - </property> - </widget> - </item> - <item row="0" column="8"> - <widget class="QLabel" name="valtc2"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>9</width> - <height>24</height> - </size> - </property> - <property name="styleSheet"> - <string notr="true">color: rgb(255, 0, 0);</string> - </property> - <property name="text"> - <string>*</string> - </property> - </widget> - </item> - <item row="0" column="7"> - <widget class="QLineEdit" name="letc2"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string/> - </property> - </widget> - </item> - <item row="0" column="6"> - <widget class="QLabel" name="lbtc2"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="text"> - <string>Can Back Thickness:</string> - </property> - </widget> - </item> - <item row="0" column="3"> - <widget class="QLabel" name="lbtc1"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="text"> - <string>Can Front Thickness:</string> - </property> - </widget> - </item> - <item row="0" column="0"> - <widget class="QLabel" name="lbts"> - <property name="text"> - <string>Thickness:</string> - </property> - </widget> - </item> - <item row="0" column="4"> - <widget class="QLineEdit" name="letc1"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string/> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="QLineEdit" name="lets"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string/> - </property> - </widget> - </item> - </layout> - </item> - </layout> - </widget> - <widget class="QWidget" name="pageCylinder"> - <layout class="QVBoxLayout" name="cylinder_layout"> - <property name="margin"> - <number>0</number> + <property name="singleStep"> + <double>0.100000000000000</double> </property> - <item> - <layout class="QGridLayout" name="gridLayout_3" columnminimumwidth="0,97,0,0,0,0,0,0,0,0"> - <item row="0" column="1"> - <widget class="QLabel" name="lbR1"> - <property name="text"> - <string>Radius 1:</string> - </property> - </widget> - </item> - <item row="0" column="4"> - <widget class="QLabel" name="lbR2"> - <property name="text"> - <string>Radius 2:</string> - </property> - </widget> - </item> - <item row="0" column="8"> - <widget class="QLineEdit" name="ler3"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="text"> - <string/> - </property> - </widget> - </item> - <item row="0" column="6"> - <widget class="QLabel" name="valR2"> - <property name="styleSheet"> - <string notr="true">color: rgb(255, 0, 0);</string> - </property> - <property name="text"> - <string>*</string> - </property> - </widget> - </item> - <item row="0" column="3"> - <widget class="QLabel" name="valR1"> - <property name="styleSheet"> - <string notr="true">color: rgb(255, 0, 0);</string> - </property> - <property name="text"> - <string>*</string> - </property> - </widget> - </item> - <item row="0" column="2"> - <widget class="QLineEdit" name="ler1"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string/> - </property> - </widget> - </item> - <item row="0" column="9"> - <widget class="QLabel" name="valR3"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>9</width> - <height>0</height> - </size> - </property> - <property name="styleSheet"> - <string notr="true">color: rgb(255, 0, 0);</string> - </property> - <property name="text"> - <string>*</string> - </property> - </widget> - </item> - <item row="0" column="7"> - <widget class="QLabel" name="lbR3"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="text"> - <string>Can Radius:</string> - </property> - </widget> - </item> - <item row="0" column="5"> - <widget class="QLineEdit" name="ler2"> - <property name="text"> - <string/> - </property> - </widget> - </item> - </layout> - </item> - </layout> - </widget> - </widget> - </item> - </layout> + </widget> + </item> + <item row="5" column="2"> + <widget class="QLabel" name="lbCylBeamWidth"> + <property name="text"> + <string>Beam Width:</string> + </property> + </widget> + </item> + <item row="5" column="0"> + <widget class="QLabel" name="lbCylBeamHeight"> + <property name="text"> + <string>Beam Height:</string> + </property> + </widget> + </item> + <item row="5" column="1"> + <widget class="QDoubleSpinBox" name="spCylBeamHeight"> + <property name="decimals"> + <number>3</number> + </property> + <property name="singleStep"> + <double>0.100000000000000</double> + </property> + </widget> + </item> + <item row="7" column="0"> + <widget class="QLabel" name="lbCylStepSize"> + <property name="text"> + <string>Step Size:</string> + </property> + </widget> + </item> + <item row="7" column="1"> + <widget class="QDoubleSpinBox" name="spCylStepSize"> + <property name="decimals"> + <number>4</number> + </property> + <property name="singleStep"> + <double>0.001000000000000</double> + </property> + <property name="value"> + <double>0.002000000000000</double> + </property> + </widget> + </item> + <item row="0" column="0"> + <widget class="QLabel" name="lbCylSampleInnerRadius"> + <property name="text"> + <string>Sample Inner Radius:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QDoubleSpinBox" name="spCylSampleInnerRadius"> + <property name="decimals"> + <number>3</number> + </property> + <property name="maximum"> + <double>9999.989999999999782</double> + </property> + <property name="singleStep"> + <double>0.100000000000000</double> + </property> + </widget> + </item> + <item row="0" column="3"> + <widget class="QDoubleSpinBox" name="spCylSampleOuterRadius"> + <property name="decimals"> + <number>3</number> + </property> + <property name="maximum"> + <double>9999.989999999999782</double> + </property> + <property name="singleStep"> + <double>0.100000000000000</double> + </property> + </widget> + </item> + <item row="0" column="2"> + <widget class="QLabel" name="lbCylSampleOuterRadius"> + <property name="text"> + <string>Sample Outer Radius:</string> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="lbCylCanOuterRadius"> + <property name="text"> + <string>Container Outer Radius:</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QDoubleSpinBox" name="spCylCanOuterRadius"> + <property name="decimals"> + <number>3</number> + </property> + <property name="maximum"> + <double>9999.989999999999782</double> + </property> + <property name="singleStep"> + <double>0.100000000000000</double> + </property> + </widget> + </item> + </layout> + </widget> + </widget> </item> </layout> </widget> </item> <item> - <widget class="QGroupBox" name="gbSample"> + <widget class="QGroupBox" name="gbSampleDetails"> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> <horstretch>0</horstretch> @@ -482,217 +356,64 @@ <property name="title"> <string>Sample Details</string> </property> - <layout class="QVBoxLayout" name="verticalLayout_13"> - <item> - <layout class="QGridLayout" name="gridLayout_9" columnminimumwidth="0,0,0,0,0,9"> - <item row="0" column="0"> - <widget class="QLabel" name="lbsamden"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>Number Density:</string> - </property> - </widget> - </item> - <item row="1" column="0"> - <widget class="QLabel" name="abs_lblSampleInputType"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>Cross Sections From:</string> - </property> - </widget> - </item> - <item row="1" column="4" colspan="2"> - <widget class="QStackedWidget" name="swSampleInputType"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="currentIndex"> - <number>0</number> - </property> - <widget class="QWidget" name="pgSampleChemicalFormula"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <layout class="QVBoxLayout" name="verticalLayout_17"> - <property name="margin"> - <number>0</number> - </property> - <item> - <layout class="QGridLayout" name="gridLayout_12" columnminimumwidth="0,9"> - <item row="0" column="0"> - <widget class="QLineEdit" name="leSampleFormula"> - <property name="text"> - <string/> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="QLabel" name="valSampleFormula"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="styleSheet"> - <string notr="true">color: rgb(255, 0, 0);</string> - </property> - <property name="text"> - <string>*</string> - </property> - </widget> - </item> - </layout> - </item> - </layout> - </widget> - <widget class="QWidget" name="pgSampleCrossSections"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <layout class="QVBoxLayout" name="verticalLayout_16"> - <property name="margin"> - <number>0</number> - </property> - <item> - <layout class="QGridLayout" name="gridLayout_8" columnminimumwidth="0,0,0,0,0,9"> - <item row="0" column="4"> - <widget class="QLineEdit" name="lesamsiga"> - <property name="text"> - <string/> - </property> - </widget> - </item> - <item row="0" column="0"> - <widget class="QLabel" name="lbsamsigs"> - <property name="text"> - <string>Scattering cross-section:</string> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="QLineEdit" name="lesamsigs"> - <property name="text"> - <string/> - </property> - </widget> - </item> - <item row="0" column="3"> - <widget class="QLabel" name="lbsamsiga"> - <property name="text"> - <string>Absorption cross-section:</string> - </property> - </widget> - </item> - <item row="0" column="2"> - <widget class="QLabel" name="valSamsigs"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="styleSheet"> - <string notr="true">color: rgb(255, 0, 0);</string> - </property> - <property name="text"> - <string>*</string> - </property> - </widget> - </item> - <item row="0" column="5"> - <widget class="QLabel" name="valSamsiga"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="styleSheet"> - <string notr="true">color: rgb(255, 0, 0);</string> - </property> - <property name="text"> - <string>*</string> - </property> - </widget> - </item> - </layout> - </item> - </layout> - </widget> - </widget> - </item> - <item row="0" column="5"> - <widget class="QLabel" name="valSamden"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="styleSheet"> - <string notr="true">color: rgb(255, 0, 0);</string> - </property> - <property name="text"> - <string>*</string> - </property> - </widget> - </item> - <item row="0" column="1" colspan="4"> - <widget class="QLineEdit" name="lesamden"> - <property name="text"> - <string/> - </property> - </widget> - </item> - <item row="1" column="1" colspan="3"> - <widget class="QComboBox" name="cbSampleInputType"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <item> - <property name="text"> - <string>Formula</string> - </property> - </item> - <item> - <property name="text"> - <string>Input</string> - </property> - </item> - </widget> - </item> - </layout> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="1"> + <widget class="QDoubleSpinBox" name="spSampleNumberDensity"> + <property name="maximum"> + <double>9999.989999999999782</double> + </property> + <property name="singleStep"> + <double>0.100000000000000</double> + </property> + </widget> + </item> + <item row="0" column="0"> + <widget class="QLabel" name="lbSampleNumberDensity"> + <property name="text"> + <string>Number Density:</string> + </property> + </widget> + </item> + <item row="0" column="2"> + <widget class="QLabel" name="lbSampleChemicalFormula"> + <property name="text"> + <string>Chemical Formula:</string> + </property> + </widget> + </item> + <item row="0" column="3"> + <widget class="QLineEdit" name="leSampleChemicalFormula"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string/> + </property> + </widget> + </item> + <item row="0" column="4"> + <widget class="QLabel" name="valSampleChemicalFormula"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string/> + </property> + </widget> </item> </layout> </widget> </item> <item> - <widget class="QGroupBox" name="gbCan"> + <widget class="QGroupBox" name="gbCanDetails"> <property name="enabled"> - <bool>true</bool> + <bool>false</bool> </property> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> @@ -703,238 +424,53 @@ <property name="title"> <string>Can Details</string> </property> - <layout class="QVBoxLayout" name="verticalLayout_12"> - <item> - <layout class="QGridLayout" name="gridLayout_6" columnminimumwidth="0,0,0,0,9"> - <item row="0" column="0"> - <widget class="QLabel" name="lbCanden"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>Number Density:</string> - </property> - </widget> - </item> - <item row="1" column="0"> - <widget class="QLabel" name="lblInputType"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>Cross Sections From:</string> - </property> - </widget> - </item> - <item row="1" column="3" colspan="2"> - <widget class="QStackedWidget" name="swCanInputType"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="currentIndex"> - <number>0</number> - </property> - <widget class="QWidget" name="pgCanChemicalFormula"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <layout class="QVBoxLayout" name="verticalLayout_15"> - <property name="margin"> - <number>0</number> - </property> - <item> - <layout class="QGridLayout" name="gridLayout_10" columnminimumwidth="0,9"> - <item row="0" column="0"> - <widget class="QLineEdit" name="leCanFormula"/> - </item> - <item row="0" column="1"> - <widget class="QLabel" name="valCanFormula"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="styleSheet"> - <string notr="true">color: rgb(255, 0, 0);</string> - </property> - <property name="text"> - <string>*</string> - </property> - </widget> - </item> - </layout> - </item> - </layout> - </widget> - <widget class="QWidget" name="pgCanCrossSections"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <layout class="QVBoxLayout" name="verticalLayout_14"> - <property name="margin"> - <number>0</number> - </property> - <item> - <layout class="QGridLayout" name="gridLayout_7" columnminimumwidth="0,0,0,0,0,0,9"> - <item row="0" column="0"> - <widget class="QLabel" name="lbCansigs"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>Scattering cross-section:</string> - </property> - </widget> - </item> - <item row="0" column="1" colspan="2"> - <widget class="QLineEdit" name="lecansigs"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="text"> - <string/> - </property> - </widget> - </item> - <item row="0" column="3"> - <widget class="QLabel" name="valCansigs"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>0</width> - <height>0</height> - </size> - </property> - <property name="styleSheet"> - <string notr="true">color: rgb(255, 0, 0);</string> - </property> - <property name="text"> - <string>*</string> - </property> - </widget> - </item> - <item row="0" column="5"> - <widget class="QLineEdit" name="lecansiga"> - <property name="text"> - <string/> - </property> - </widget> - </item> - <item row="0" column="6"> - <widget class="QLabel" name="valCansiga"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="styleSheet"> - <string notr="true">color: rgb(255, 0, 0);</string> - </property> - <property name="text"> - <string>*</string> - </property> - </widget> - </item> - <item row="0" column="4"> - <widget class="QLabel" name="lbCansiga"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>Absorption cross-section:</string> - </property> - </widget> - </item> - </layout> - </item> - </layout> - </widget> - </widget> - </item> - <item row="0" column="4"> - <widget class="QLabel" name="valCanden"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="styleSheet"> - <string notr="true">color: rgb(255, 0, 0);</string> - </property> - <property name="text"> - <string>*</string> - </property> - </widget> - </item> - <item row="0" column="1" colspan="3"> - <widget class="QLineEdit" name="lecanden"> - <property name="text"> - <string/> - </property> - </widget> - </item> - <item row="1" column="1" colspan="2"> - <widget class="QComboBox" name="cbCanInputType"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <item> - <property name="text"> - <string>Formula</string> - </property> - </item> - <item> - <property name="text"> - <string>Input</string> - </property> - </item> - </widget> - </item> - </layout> + <layout class="QGridLayout" name="gridLayout_3"> + <item row="0" column="0"> + <widget class="QLabel" name="lbCanNumberDensity"> + <property name="text"> + <string>Number Density:</string> + </property> + </widget> + </item> + <item row="0" column="3"> + <widget class="QLineEdit" name="leCanChemicalFormula"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QDoubleSpinBox" name="spCanNumberDensity"> + <property name="maximum"> + <double>9999.989999999999782</double> + </property> + <property name="singleStep"> + <double>0.100000000000000</double> + </property> + </widget> + </item> + <item row="0" column="2"> + <widget class="QLabel" name="lbCanChemicalFormula"> + <property name="text"> + <string>Chemical Formula:</string> + </property> + </widget> + </item> + <item row="0" column="4"> + <widget class="QLabel" name="valCanChemicalFormula"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string/> + </property> + </widget> </item> </layout> </widget> @@ -950,67 +486,33 @@ <property name="title"> <string>Output Options</string> </property> - <layout class="QVBoxLayout" name="verticalLayout_11"> + <layout class="QHBoxLayout" name="horizontalLayout"> <item> - <layout class="QHBoxLayout" name="horizontalLayout_6"> - <item> - <widget class="QLabel" name="lbPlotOutput"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>Plot Output</string> - </property> - </widget> - </item> - <item> - <widget class="QComboBox" name="cbPlotOutput"> - <item> - <property name="text"> - <string>None</string> - </property> - </item> - <item> - <property name="text"> - <string>Wavelength</string> - </property> - </item> - <item> - <property name="text"> - <string>Angle</string> - </property> - </item> - <item> - <property name="text"> - <string>Both</string> - </property> - </item> - </widget> - </item> - <item> - <spacer name="horizontalSpacer_12"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QCheckBox" name="ckSave"> - <property name="text"> - <string>Save Result</string> - </property> - </widget> - </item> - </layout> + <widget class="QCheckBox" name="ckPlotOutput"> + <property name="text"> + <string>Plot Output</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QCheckBox" name="ckSave"> + <property name="text"> + <string>Save Result</string> + </property> + </widget> </item> </layout> </widget> @@ -1026,59 +528,71 @@ </customwidgets> <tabstops> <tabstop>ckUseCan</tabstop> - <tabstop>cbShape</tabstop> - <tabstop>lets</tabstop> - <tabstop>letc1</tabstop> - <tabstop>letc2</tabstop> - <tabstop>ler1</tabstop> - <tabstop>ler2</tabstop> - <tabstop>ler3</tabstop> - <tabstop>leavar</tabstop> - <tabstop>lewidth</tabstop> - <tabstop>lesamden</tabstop> - <tabstop>cbSampleInputType</tabstop> - <tabstop>lesamsigs</tabstop> - <tabstop>lesamsiga</tabstop> - <tabstop>leSampleFormula</tabstop> - <tabstop>lecanden</tabstop> - <tabstop>cbCanInputType</tabstop> - <tabstop>lecansigs</tabstop> - <tabstop>lecansiga</tabstop> - <tabstop>leCanFormula</tabstop> - <tabstop>cbPlotOutput</tabstop> + <tabstop>cbSampleShape</tabstop> + <tabstop>spFlatSampleThickness</tabstop> + <tabstop>spFlatSampleAngle</tabstop> + <tabstop>spFlatCanFrontThickness</tabstop> + <tabstop>spFlatCanBackThickness</tabstop> + <tabstop>spCylSampleInnerRadius</tabstop> + <tabstop>spCylSampleOuterRadius</tabstop> + <tabstop>spCylCanOuterRadius</tabstop> + <tabstop>spCylBeamHeight</tabstop> + <tabstop>spCylBeamWidth</tabstop> + <tabstop>spCylStepSize</tabstop> + <tabstop>spSampleNumberDensity</tabstop> + <tabstop>leSampleChemicalFormula</tabstop> + <tabstop>spCanNumberDensity</tabstop> + <tabstop>leCanChemicalFormula</tabstop> + <tabstop>ckPlotOutput</tabstop> <tabstop>ckSave</tabstop> </tabstops> <resources/> <connections> <connection> - <sender>cbCanInputType</sender> + <sender>cbSampleShape</sender> <signal>currentIndexChanged(int)</signal> - <receiver>swCanInputType</receiver> + <receiver>swShapeOptions</receiver> <slot>setCurrentIndex(int)</slot> <hints> <hint type="sourcelabel"> - <x>193</x> - <y>405</y> + <x>486</x> + <y>130</y> </hint> <hint type="destinationlabel"> - <x>440</x> - <y>405</y> + <x>330</x> + <y>239</y> </hint> </hints> </connection> <connection> - <sender>cbSampleInputType</sender> - <signal>currentIndexChanged(int)</signal> - <receiver>swSampleInputType</receiver> - <slot>setCurrentIndex(int)</slot> + <sender>ckUseCan</sender> + <signal>toggled(bool)</signal> + <receiver>gbCanDetails</receiver> + <slot>setEnabled(bool)</slot> + <hints> + <hint type="sourcelabel"> + <x>173</x> + <y>65</y> + </hint> + <hint type="destinationlabel"> + <x>330</x> + <y>481</y> + </hint> + </hints> + </connection> + <connection> + <sender>ckUseCan</sender> + <signal>toggled(bool)</signal> + <receiver>dsContainer</receiver> + <slot>setEnabled(bool)</slot> <hints> <hint type="sourcelabel"> - <x>193</x> - <y>310</y> + <x>173</x> + <y>65</y> </hint> <hint type="destinationlabel"> - <x>440</x> - <y>310</y> + <x>487</x> + <y>65</y> </hint> </hints> </connection> diff --git a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/IDATab.h b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/IDATab.h index ada19ebb3932a29bb482160e46fd776f1786d4fc..c77d08e199d9d2412386fae92872bbe59e5caa18 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/IDATab.h +++ b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/IDATab.h @@ -67,6 +67,8 @@ namespace IDA /// Check the binning between two workspaces match bool checkWorkspaceBinningMatches(Mantid::API::MatrixWorkspace_const_sptr left, Mantid::API::MatrixWorkspace_const_sptr right); + /// Adds a conversion to wavelength step to the algorithm queue + std::string addConvertToWavelengthStep(Mantid::API::MatrixWorkspace_sptr ws); /// DoubleEditorFactory DoubleEditorFactory* m_dblEdFac; diff --git a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/IndirectTab.h b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/IndirectTab.h index 2664203f1fc7f8d0aa4341d4e4a5a252938ae462..802933488db6fcc51f853c00fb460f630bb6abe4 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/IndirectTab.h +++ b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/IndirectTab.h @@ -91,6 +91,16 @@ namespace CustomInterfaces /// Run the load algorithm with the given file name, output name and spectrum range bool loadFile(const QString& filename, const QString& outputName, const int specMin = -1, const int specMax = -1); + /// Add a SaveNexusProcessed step to the batch queue + void addSaveWorkspaceToQueue(const QString & wsName, const QString & filename = ""); + + /// Plot a spectrum plot given a list of workspace names + void plotSpectrum(const QStringList & workspaceNames, int specIndex = 0); + void plotSpectrum(const QString & workspaceName, int specIndex = 0); + + /// Plot a contour plot of a given workspace + void plotContour(const QString & workspaceName); + /// Function to set the range limits of the plot void setPlotPropertyRange(MantidQt::MantidWidgets::RangeSelector * rs, QtProperty* min, QtProperty* max, @@ -100,6 +110,12 @@ namespace CustomInterfaces QtProperty* lower, QtProperty* upper, const QPair<double, double> & bounds); + /// Function to get energy mode from a workspace + std::string getEMode(Mantid::API::MatrixWorkspace_sptr ws); + + /// Function to get eFixed from a workspace + double getEFixed(Mantid::API::MatrixWorkspace_sptr ws); + /// Function to run an algorithm on a seperate thread void runAlgorithm(const Mantid::API::IAlgorithm_sptr algorithm); diff --git a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/MantidEV.h b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/MantidEV.h index 2bb6f7f0130a9b2020af35f140cb87c8e0afda6b..d521c6f5df8cd3f1a374792c42cad55cefb69eef 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/MantidEV.h +++ b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/MantidEV.h @@ -310,6 +310,12 @@ private slots: /// Slot to load a peaks workspace to the current MantidEV named workspace void loadIsawPeaks_slot(); + /// Slot to save the current MantidEV peaks workspace + void saveNexusPeaks_slot(); + + /// Slot to load a peaks workspace to the current MantidEV named workspace + void loadNexusPeaks_slot(); + /// Slot to show the UB matrix void showUB_slot(); diff --git a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/MantidEV.ui b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/MantidEV.ui index bffc3627533b62b8a837bb18c45adffc169d2487..4906f166dbcb095a57fff07ca31a045459a3fce7 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/MantidEV.ui +++ b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/MantidEV.ui @@ -20,3442 +20,3435 @@ <string>SCD Event Data Reduction</string> </property> <widget class="QWidget" name="centralwidget"> - <layout class="QVBoxLayout" name="verticalLayout"> - <item> - <widget class="QMenuBar" name="menubar"> - <widget class="QMenu" name="menuFile"> - <property name="title"> - <string>File</string> - </property> - <addaction name="actionSave_Isaw_UB"/> - <addaction name="actionLoad_Isaw_UB"/> - <addaction name="actionSave_Isaw_Peaks"/> - <addaction name="actionLoad_Isaw_Peaks"/> - <addaction name="actionSave_State"/> - <addaction name="actionLoad_State"/> - <addaction name="actionReset_Default_Settings"/> - </widget> - <widget class="QMenu" name="menuView"> - <property name="title"> - <string>View</string> - </property> - <addaction name="actionShow_UB"/> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QMenuBar" name="menubar"> + <widget class="QMenu" name="menuFile"> + <property name="title"> + <string>File</string> + </property> + <addaction name="actionSave_Isaw_UB"/> + <addaction name="actionLoad_Isaw_UB"/> + <addaction name="actionSave_Isaw_Peaks"/> + <addaction name="actionLoad_Isaw_Peaks"/> + <addaction name="actionSave_Nexus_Peaks"/> + <addaction name="actionLoad_Nexus_Peaks"/> + <addaction name="actionSave_State"/> + <addaction name="actionLoad_State"/> + <addaction name="actionReset_Default_Settings"/> + </widget> + <widget class="QMenu" name="menuView"> + <property name="title"> + <string>View</string> + </property> + <addaction name="actionShow_UB"/> + </widget> + <widget class="QMenu" name="menuHelp"> + <property name="title"> + <string>Help</string> + </property> + <addaction name="actionOnline_Help_Page"/> + </widget> + <addaction name="menuFile"/> + <addaction name="menuView"/> + <addaction name="menuHelp"/> </widget> - <widget class="QMenu" name="menuHelp"> - <property name="title"> - <string>Help</string> + </item> + <item> + <widget class="QTabWidget" name="MantidEV_tabwidg"> + <property name="toolTip"> + <string/> </property> - <addaction name="actionOnline_Help_Page"/> - </widget> - <addaction name="menuFile"/> - <addaction name="menuView"/> - <addaction name="menuHelp"/> - </widget> - </item> - <item> - <widget class="QTabWidget" name="MantidEV_tabwidg"> - <property name="toolTip"> - <string/> - </property> - <property name="currentIndex"> - <number>3</number> - </property> - <widget class="QWidget" name="SelectData"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> + <property name="currentIndex"> + <number>1</number> </property> - <attribute name="title"> - <string>Select Data</string> - </attribute> - <layout class="QVBoxLayout" name="verticalLayout_3"> - <item> - <widget class="QScrollArea" name="selectDataScrollArea"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>0</width> - <height>0</height> - </size> - </property> - <property name="baseSize"> - <size> - <width>0</width> - <height>0</height> - </size> - </property> - <property name="frameShape"> - <enum>QFrame::NoFrame</enum> - </property> - <property name="frameShadow"> - <enum>QFrame::Plain</enum> - </property> - <property name="lineWidth"> - <number>0</number> - </property> - <property name="verticalScrollBarPolicy"> - <enum>Qt::ScrollBarAsNeeded</enum> - </property> - <property name="widgetResizable"> - <bool>true</bool> - </property> - <property name="alignment"> - <set>Qt::AlignCenter</set> - </property> - <widget class="QWidget" name="scrollAreaWidgetContents"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>903</width> - <height>708</height> - </rect> + <widget class="QWidget" name="SelectData"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <attribute name="title"> + <string>Select Data</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <item> + <widget class="QScrollArea" name="selectDataScrollArea"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> </property> <property name="minimumSize"> <size> - <width>500</width> - <height>500</height> + <width>0</width> + <height>0</height> + </size> + </property> + <property name="baseSize"> + <size> + <width>0</width> + <height>0</height> </size> </property> - <property name="autoFillBackground"> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Plain</enum> + </property> + <property name="lineWidth"> + <number>0</number> + </property> + <property name="verticalScrollBarPolicy"> + <enum>Qt::ScrollBarAsNeeded</enum> + </property> + <property name="widgetResizable"> <bool>true</bool> </property> - <layout class="QVBoxLayout" name="verticalLayout_7"> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_7"> - <property name="sizeConstraint"> - <enum>QLayout::SetDefaultConstraint</enum> - </property> - <item> - <widget class="QLabel" name="SelectEventWorkspace_lbl"> - <property name="text"> - <string>Event Workspace Name</string> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer_6"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLineEdit" name="SelectEventWorkspace_ledt"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>200</width> - <height>0</height> - </size> - </property> - <property name="toolTip"> - <string>Name of the event workspace to use. This name is set by default,<br> if data is loaded from an event file and mapped to an MD workspace.</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_8"> - <item> - <widget class="QLabel" name="SelectMDWorkspace_lbl"> - <property name="text"> - <string>MD Workspace Name</string> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer_7"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLineEdit" name="MDworkspace_ledt"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>200</width> - <height>0</height> - </size> - </property> - <property name="toolTip"> - <string>Name of the MD workspace to use. This name is set<br>by default, if data is loaded from an event file and mapped to an MD workspace.</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <widget class="QGroupBox" name="convertToMDGroupBox"> - <property name="minimumSize"> - <size> - <width>0</width> - <height>160</height> - </size> - </property> - <property name="toolTip"> - <string>Not doing this will use existing workspace</string> - </property> - <property name="title"> - <string>Convert to MD</string> - </property> - <property name="checkable"> - <bool>true</bool> - </property> - <layout class="QVBoxLayout" name="verticalLayout_8"> - <item> - <layout class="QVBoxLayout" name="verticalLayout_4"> - <property name="sizeConstraint"> - <enum>QLayout::SetDefaultConstraint</enum> - </property> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_3"> - <item> - <widget class="QLabel" name="MinMagQ_lbl"> - <property name="text"> - <string>Min |Q| to Map to MD</string> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer_2"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLineEdit" name="MinMagQ_ledt"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>50</width> - <height>0</height> - </size> - </property> - <property name="toolTip"> - <string>Specify value to use as bound on |Qx|, |Qy| and |Qz|</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_2"> - <item> - <widget class="QLabel" name="MaxMagQ_lbl"> - <property name="text"> - <string>Max |Q| to Map to MD</string> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLineEdit" name="MaxMagQ_ledt"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>50</width> - <height>0</height> - </size> - </property> - <property name="toolTip"> - <string>Specify value to use as bound on |Qx|, |Qy| and |Qz|</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <widget class="QCheckBox" name="LorentzCorrection_ckbx"> - <property name="toolTip"> - <string>Apply the Lorentz Correction as<br> data is mapped to reciprocal space and stored in the MD workspace. This helps with finding peaks with larger |Q|.</string> - </property> - <property name="text"> - <string>Apply Lorentz Correction</string> - </property> - </widget> - </item> - </layout> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + <widget class="QWidget" name="scrollAreaWidgetContents"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>903</width> + <height>696</height> + </rect> + </property> + <property name="minimumSize"> + <size> + <width>500</width> + <height>500</height> + </size> + </property> + <property name="autoFillBackground"> + <bool>true</bool> + </property> + <layout class="QVBoxLayout" name="verticalLayout_7"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_7"> + <property name="sizeConstraint"> + <enum>QLayout::SetDefaultConstraint</enum> + </property> + <item> + <widget class="QLabel" name="SelectEventWorkspace_lbl"> + <property name="text"> + <string>Event Workspace Name</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_6"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLineEdit" name="SelectEventWorkspace_ledt"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>200</width> + <height>0</height> + </size> + </property> + <property name="toolTip"> + <string>Name of the event workspace to use. This name is set by default,<br> if data is loaded from an event file and mapped to an MD workspace.</string> + </property> + </widget> </item> </layout> - </widget> - </item> - <item> - <widget class="QGroupBox" name="loadDataGroupBox"> - <property name="minimumSize"> - <size> - <width>0</width> - <height>200</height> - </size> - </property> - <property name="toolTip"> - <string>If disabled then use existing workspaces</string> - </property> - <property name="title"> - <string>Load Event Data</string> - </property> - <property name="checkable"> - <bool>true</bool> - </property> - <layout class="QVBoxLayout" name="verticalLayout_5"> - <item> - <layout class="QVBoxLayout" name="verticalLayout_6"> - <property name="sizeConstraint"> - <enum>QLayout::SetDefaultConstraint</enum> - </property> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_6"> - <item> - <widget class="QLabel" name="EventFileName_lbl"> - <property name="text"> - <string>Filename</string> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer_5"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLineEdit" name="EventFileName_ledt"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>400</width> - <height>0</height> - </size> - </property> - <property name="toolTip"> - <string>Specify the name of the data file to load. Press<br> return to set default names for Event, MD and Peaks workspaces.</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="SelectEventFile_btn"> - <property name="toolTip"> - <string>Browse for the event file to be loaded.</string> - </property> - <property name="text"> - <string>Browse</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <widget class="QCheckBox" name="LoadDetCal_ckbx"> - <property name="toolTip"> - <string>Optionally, apply<br> calibration information from the specified .DetCal file(s).</string> - </property> - <property name="text"> - <string> Load ISAW Detector Calibration</string> - </property> - </widget> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_5"> - <item> - <widget class="QLabel" name="CalFileName_lbl"> - <property name="text"> - <string>Filename</string> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer_4"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Expanding</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLineEdit" name="CalFileName_ledt"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>400</width> - <height>0</height> - </size> - </property> - <property name="toolTip"> - <string>Select the .DetCal file to apply.</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="SelectCalFile_btn"> - <property name="toolTip"> - <string>Browse for the first .DetCal file to be used.</string> - </property> - <property name="text"> - <string>Browse</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_4"> - <item> - <widget class="QLabel" name="CalFileName2_lbl"> - <property name="text"> - <string>Filename2</string> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer_3"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Expanding</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLineEdit" name="CalFileName2_ledt"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>400</width> - <height>0</height> - </size> - </property> - <property name="toolTip"> - <string>Select the second .DetCal file for the second detector<br> panel on the SNAP instrument at the SNS.</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="SelectCalFile2_btn"> - <property name="toolTip"> - <string>Browse for the second .DetCal file to be used<br> for the second panel on SNAP.</string> - </property> - <property name="text"> - <string>Browse</string> - </property> - </widget> - </item> - </layout> - </item> - </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_8"> + <item> + <widget class="QLabel" name="SelectMDWorkspace_lbl"> + <property name="text"> + <string>MD Workspace Name</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_7"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLineEdit" name="MDworkspace_ledt"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>200</width> + <height>0</height> + </size> + </property> + <property name="toolTip"> + <string>Name of the MD workspace to use. This name is set<br>by default, if data is loaded from an event file and mapped to an MD workspace.</string> + </property> + </widget> </item> </layout> - </widget> - </item> - <item> - <spacer name="verticalSpacer"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_9"> - <property name="sizeConstraint"> - <enum>QLayout::SetDefaultConstraint</enum> - </property> - <item> - <spacer name="horizontalSpacer_10"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QPushButton" name="ApplySelectData_btn"> - <property name="toolTip"> - <string>Actually load the data and convert to MD, or just<br> proceed to the next tab using previously loaded data.</string> - </property> - <property name="text"> - <string>Apply</string> - </property> - </widget> - </item> - </layout> - </item> - </layout> + </item> + <item> + <widget class="QGroupBox" name="convertToMDGroupBox"> + <property name="minimumSize"> + <size> + <width>0</width> + <height>160</height> + </size> + </property> + <property name="toolTip"> + <string>Not doing this will use existing workspace</string> + </property> + <property name="title"> + <string>Convert to MD</string> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + <layout class="QVBoxLayout" name="verticalLayout_8"> + <item> + <layout class="QVBoxLayout" name="verticalLayout_4"> + <property name="sizeConstraint"> + <enum>QLayout::SetDefaultConstraint</enum> + </property> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_3"> + <item> + <widget class="QLabel" name="MinMagQ_lbl"> + <property name="text"> + <string>Min |Q| to Map to MD</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLineEdit" name="MinMagQ_ledt"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>50</width> + <height>0</height> + </size> + </property> + <property name="toolTip"> + <string>Specify value to use as bound on |Qx|, |Qy| and |Qz|</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QLabel" name="MaxMagQ_lbl"> + <property name="text"> + <string>Max |Q| to Map to MD</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLineEdit" name="MaxMagQ_ledt"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>50</width> + <height>0</height> + </size> + </property> + <property name="toolTip"> + <string>Specify value to use as bound on |Qx|, |Qy| and |Qz|</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QCheckBox" name="LorentzCorrection_ckbx"> + <property name="toolTip"> + <string>Apply the Lorentz Correction as<br> data is mapped to reciprocal space and stored in the MD workspace. This helps with finding peaks with larger |Q|.</string> + </property> + <property name="text"> + <string>Apply Lorentz Correction</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="loadDataGroupBox"> + <property name="minimumSize"> + <size> + <width>0</width> + <height>200</height> + </size> + </property> + <property name="toolTip"> + <string>If disabled then use existing workspaces</string> + </property> + <property name="title"> + <string>Load Event Data</string> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + <layout class="QVBoxLayout" name="verticalLayout_5"> + <item> + <layout class="QVBoxLayout" name="verticalLayout_6"> + <property name="sizeConstraint"> + <enum>QLayout::SetDefaultConstraint</enum> + </property> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_6"> + <item> + <widget class="QLabel" name="EventFileName_lbl"> + <property name="text"> + <string>Filename</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_5"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLineEdit" name="EventFileName_ledt"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>400</width> + <height>0</height> + </size> + </property> + <property name="toolTip"> + <string>Specify the name of the data file to load. Press<br> return to set default names for Event, MD and Peaks workspaces.</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="SelectEventFile_btn"> + <property name="toolTip"> + <string>Browse for the event file to be loaded.</string> + </property> + <property name="text"> + <string>Browse</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QCheckBox" name="LoadDetCal_ckbx"> + <property name="toolTip"> + <string>Optionally, apply<br> calibration information from the specified .DetCal file(s).</string> + </property> + <property name="text"> + <string> Load ISAW Detector Calibration</string> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_5"> + <item> + <widget class="QLabel" name="CalFileName_lbl"> + <property name="text"> + <string>Filename</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_4"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Expanding</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLineEdit" name="CalFileName_ledt"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>400</width> + <height>0</height> + </size> + </property> + <property name="toolTip"> + <string>Select the .DetCal file to apply.</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="SelectCalFile_btn"> + <property name="toolTip"> + <string>Browse for the first .DetCal file to be used.</string> + </property> + <property name="text"> + <string>Browse</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_4"> + <item> + <widget class="QLabel" name="CalFileName2_lbl"> + <property name="text"> + <string>Filename2</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_3"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Expanding</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLineEdit" name="CalFileName2_ledt"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>400</width> + <height>0</height> + </size> + </property> + <property name="toolTip"> + <string>Select the second .DetCal file for the second detector<br> panel on the SNAP instrument at the SNS.</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="SelectCalFile2_btn"> + <property name="toolTip"> + <string>Browse for the second .DetCal file to be used<br> for the second panel on SNAP.</string> + </property> + <property name="text"> + <string>Browse</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </item> + </layout> + </widget> + </item> + <item> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_9"> + <property name="sizeConstraint"> + <enum>QLayout::SetDefaultConstraint</enum> + </property> + <item> + <spacer name="horizontalSpacer_10"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="ApplySelectData_btn"> + <property name="toolTip"> + <string>Actually load the data and convert to MD, or just<br> proceed to the next tab using previously loaded data.</string> + </property> + <property name="text"> + <string>Apply</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> </widget> - </widget> - </item> - </layout> - </widget> - <widget class="QWidget" name="FindPeaks"> - <attribute name="title"> - <string>Find Peaks</string> - </attribute> - <layout class="QVBoxLayout" name="verticalLayout_9"> - <item> - <widget class="QScrollArea" name="scrollArea"> - <property name="frameShape"> - <enum>QFrame::NoFrame</enum> - </property> - <property name="frameShadow"> - <enum>QFrame::Plain</enum> - </property> - <property name="widgetResizable"> - <bool>true</bool> - </property> - <widget class="QWidget" name="scrollAreaWidgetContents_2"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>903</width> - <height>708</height> - </rect> + </item> + </layout> + </widget> + <widget class="QWidget" name="FindPeaks"> + <attribute name="title"> + <string>Find Peaks</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_9"> + <item> + <widget class="QScrollArea" name="scrollArea"> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> </property> - <layout class="QVBoxLayout" name="verticalLayout_10"> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_10"> - <item> - <widget class="QLabel" name="PeaksWorkspace_lbl"> - <property name="text"> - <string>Peaks Workspace Name</string> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer_18"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLineEdit" name="PeaksWorkspace_ledt"> - <property name="toolTip"> - <string>Name of the peaks workspace to use. This name is set by default,<br> if data is loaded from an event file and mapped to an MD workspace on the Select Data tab.</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <widget class="Line" name="line_2"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - </widget> - </item> - <item> - <widget class="QRadioButton" name="FindPeaks_rbtn"> - <property name="toolTip"> - <string>Search through the MD workspace to find Bragg peaks.</string> - </property> - <property name="text"> - <string>Find Peaks</string> - </property> - </widget> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_11"> - <item> - <spacer name="horizontalSpacer_9"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Fixed</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>15</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLabel" name="MaxABC_lbl"> - <property name="text"> - <string>Estimated Max of a,b,c</string> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer_14"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLineEdit" name="MaxABC_ledt"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="toolTip"> - <string>Estimated maximum for real<br> space cell edge length in Angstroms. This is used to get an approximate lower bound on the possible distances between peaks.</string> - </property> - <property name="text"> - <string>15</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_12"> - <item> - <spacer name="horizontalSpacer_11"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Fixed</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>15</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLabel" name="NumToFind_lbl"> - <property name="text"> - <string>Number of Peaks to Find</string> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer_15"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLineEdit" name="NumToFind_ledt"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="toolTip"> - <string>Maximum number of peaks to find. Boxes with progressively<br> lower local intensity will be tried, until the specified number of peaks is found, or until the intensity falls below the specified Min Intensity.</string> - </property> - <property name="text"> - <string>50</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_13"> - <item> - <spacer name="horizontalSpacer_12"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Fixed</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>15</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLabel" name="MinIntensity_lbl"> - <property name="text"> - <string>Min Intensity(above ave)</string> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer_16"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLineEdit" name="MinIntensity_ledt"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="toolTip"> - <string>Lower bound on the local intensity of MD boxes to consider as possible peaks, expressed as a multiple of the overall average intensity of the entire MD workspace region. Boxes with progressively<br> lower local intensity will be tried, until the specified number of peaks is found, or until the intensity falls below the specified Min Intensity.</string> - </property> - <property name="text"> - <string>10000</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <widget class="QRadioButton" name="UseExistingPeaksWorkspace_rbtn"> - <property name="toolTip"> - <string>Use a peaks workspace with peaks that have been<br> been previously found, predicted, or loaded. </string> - </property> - <property name="text"> - <string>Use Existing Peaks Workspace</string> - </property> - </widget> - </item> - <item> - <widget class="QRadioButton" name="LoadIsawPeaks_rbtn"> - <property name="toolTip"> - <string>Load the peaks workspace from a file of peaks<br> that have been previously found or predicted.</string> - </property> - <property name="text"> - <string>Load ISAW Peaks (or Integrate) File</string> - </property> - </widget> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_14"> - <item> - <spacer name="horizontalSpacer_13"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Fixed</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>15</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLabel" name="SelectPeaksFile_lbl"> - <property name="text"> - <string>Filename</string> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer_17"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLineEdit" name="SelectPeaksFile_ledt"> - <property name="toolTip"> - <string>Name of the peaks file that should be loaded.</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="SelectPeaksFile_btn"> - <property name="toolTip"> - <string>Browse for the file of peaks to load.</string> - </property> - <property name="text"> - <string>Browse</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <spacer name="verticalSpacer_2"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_15"> - <item> - <spacer name="horizontalSpacer_8"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QPushButton" name="ApplyFindPeaks_btn"> - <property name="toolTip"> - <string>Proceed to actually get the<br> peaks or use the existing peaks, as specified..</string> - </property> - <property name="text"> - <string>Apply</string> - </property> - </widget> - </item> - </layout> - </item> - </layout> - </widget> - </widget> - </item> - </layout> - </widget> - <widget class="QWidget" name="FindUB"> - <attribute name="title"> - <string>Find UB</string> - </attribute> - <layout class="QVBoxLayout" name="verticalLayout_11"> - <item> - <widget class="QScrollArea" name="scrollArea_2"> - <property name="frameShape"> - <enum>QFrame::NoFrame</enum> - </property> - <property name="frameShadow"> - <enum>QFrame::Plain</enum> - </property> - <property name="widgetResizable"> - <bool>true</bool> - </property> - <widget class="QWidget" name="scrollAreaWidgetContents_4"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>903</width> - <height>708</height> - </rect> + <property name="frameShadow"> + <enum>QFrame::Plain</enum> </property> - <layout class="QVBoxLayout" name="verticalLayout_12"> - <item> - <widget class="QRadioButton" name="FindUBUsingFFT_rbtn"> - <property name="toolTip"> - <string>Find a UB matrix using the<br> FindUBUsingFFT algorithm. This will produce a UB matrix corresponding to the Niggli reduced cell for the lattice.</string> - </property> - <property name="text"> - <string>Find UB Using FFT</string> - </property> - </widget> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_20"> - <item> - <spacer name="horizontalSpacer_28"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Fixed</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>15</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLabel" name="MinD_lbl"> - <property name="text"> - <string>Estimated Lower Bound for a,b,c</string> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer_29"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLineEdit" name="MinD_ledt"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="toolTip"> - <string>Set this to a value that is<br> about 50%-90% of the shortest real space edge length, in Angstroms.</string> - </property> - <property name="text"> - <string>3</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_21"> - <item> - <spacer name="horizontalSpacer_27"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Fixed</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>15</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLabel" name="MaxD_lbl"> - <property name="text"> - <string>Estimated Upper Bound for a,b,c</string> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer_30"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLineEdit" name="MaxD_ledt"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="toolTip"> - <string>Set this to a value that is<br> about 110%-150% of the longest real space edge length, in Angstroms.</string> - </property> - <property name="text"> - <string>15</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_22"> - <item> - <spacer name="horizontalSpacer_26"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Fixed</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>15</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLabel" name="FFTTolerance_lbl"> - <property name="text"> - <string>Tolerance</string> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer_31"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLineEdit" name="FFTTolerance_ledt"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="toolTip"> - <string>Maximum distance of h,k or l from integer values to<br> consider a peak to be indexed.</string> - </property> - <property name="text"> - <string>0.12</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <widget class="QRadioButton" name="FindUBUsingIndexedPeaks_rbtn"> - <property name="toolTip"> - <string>Find the UB matrix using the FindUBUsingIndexedPeaks algorithm. Specifically, if the<br> peaks in the peaks workspace have already been indexed, find the UB matrix that corresponds to that indexing.</string> - </property> - <property name="text"> - <string>Find UB Using Indexed Peaks</string> - </property> - </widget> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_23"> - <item> - <spacer name="horizontalSpacer_25"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Fixed</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>15</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLabel" name="IndexedPeaksTolerance_lbl"> - <property name="text"> - <string>Tolerance</string> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer_32"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLineEdit" name="IndexedPeaksTolerance_ledt"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="toolTip"> - <string>Maximum distance of h,k or l from integer values to<br> consider a peak to be indexed.</string> - </property> - <property name="text"> - <string>0.1</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <widget class="QRadioButton" name="LoadISAWUB_rbtn"> - <property name="toolTip"> - <string>Load the UB matrix from a file.</string> - </property> - <property name="text"> - <string>Load Isaw UB</string> - </property> - </widget> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_24"> - <item> - <spacer name="horizontalSpacer_24"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Fixed</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>15</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLabel" name="SelectUBFile_lbl"> - <property name="text"> - <string>Filename</string> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer_33"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::MinimumExpanding</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLineEdit" name="SelectUBFile_ledt"> - <property name="toolTip"> - <string>Name of the file with the UB matrix.</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="SelectUBFile_btn"> - <property name="toolTip"> - <string>Browse for the file with the UB matrix.</string> - </property> - <property name="text"> - <string>Browse</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_31"> - <item> - <spacer name="horizontalSpacer_23"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Fixed</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>15</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QCheckBox" name="OptimizeGoniometerAngles_ckbx"> - <property name="toolTip"> - <string>Optimize the goniometer<br> angles, to index the peaks as accurately as possible using the UB matrix that was loaded.</string> - </property> - <property name="text"> - <string>Optimize Phi, Chi and Omega</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_25"> - <item> - <spacer name="horizontalSpacer_22"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Fixed</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>15</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLabel" name="MaxGoniometerChange_lbl"> - <property name="text"> - <string>Maximum Change (degrees)</string> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer_34"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLineEdit" name="MaxGoniometerChange_ledt"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="toolTip"> - <string>Maximum number of degrees that CHI, PHI<br> or OMEGA can be changed.</string> - </property> - <property name="text"> - <string>5</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_30"> - <item> - <widget class="QRadioButton" name="UseCurrentUB_rbtn"> - <property name="toolTip"> - <string>If the peaks workspace<br> already has a UB matrix, just use that UB.</string> - </property> - <property name="text"> - <string>Use Current UB (if already found or loaded)</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <widget class="Line" name="line"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - </widget> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_29"> - <item> - <widget class="QCheckBox" name="IndexPeaks_ckbx"> - <property name="toolTip"> - <string>After obtaining the UB<br> matrix, index the peaks using that UB.</string> - </property> - <property name="text"> - <string>Index Peaks Using UB</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_26"> - <item> - <spacer name="horizontalSpacer_20"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Fixed</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>15</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLabel" name="IndexingTolerance_lbl"> - <property name="text"> - <string>Indexing Tolerance</string> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer_35"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLineEdit" name="IndexingTolerance_ledt"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="toolTip"> - <string>Only set the h,k,l values on peaks for which the maximum distance of h,k or l from integer values<br> is less than this tolerance.</string> - </property> - <property name="text"> - <string>0.12</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_28"> - <item> - <spacer name="horizontalSpacer_21"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Fixed</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>15</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QCheckBox" name="RoundHKLs_ckbx"> - <property name="toolTip"> - <string>Round the h,k,l values to the nearest integer.</string> - </property> - <property name="text"> - <string>Round HKLs</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <widget class="QCheckBox" name="PredictPeaks_ckbx"> - <property name="text"> - <string>Predict Peaks</string> - </property> - </widget> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_16"> - <item> - <spacer name="horizontalSpacer_91"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Fixed</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>15</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLabel" name="min_pred_wl_lbl"> - <property name="maximumSize"> - <size> - <width>160</width> - <height>16777215</height> - </size> - </property> - <property name="text"> - <string>Minimum wavelength</string> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer_64"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLineEdit" name="min_pred_wl_ledt"> - <property name="minimumSize"> - <size> - <width>146</width> - <height>0</height> - </size> - </property> - <property name="maximumSize"> - <size> - <width>146</width> - <height>16777215</height> - </size> - </property> - <property name="text"> - <string>0.4</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_17"> - <item> - <spacer name="horizontalSpacer_92"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Fixed</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>15</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLabel" name="max_pred_wl_lbl"> - <property name="maximumSize"> - <size> - <width>160</width> - <height>16777215</height> - </size> - </property> - <property name="text"> - <string>Maximum wavelength</string> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer_65"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLineEdit" name="max_pred_wl_ledt"> - <property name="maximumSize"> - <size> - <width>146</width> - <height>16777215</height> - </size> - </property> - <property name="text"> - <string>3.5</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_18"> - <item> - <spacer name="horizontalSpacer_93"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Fixed</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>15</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLabel" name="min_pred_dspacing_lbl"> - <property name="maximumSize"> - <size> - <width>160</width> - <height>16777215</height> - </size> - </property> - <property name="text"> - <string>Minimum d-spacing</string> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer_66"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLineEdit" name="min_pred_dspacing_ledt"> - <property name="maximumSize"> - <size> - <width>146</width> - <height>16777215</height> - </size> - </property> - <property name="text"> - <string>0.4</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_19"> - <item> - <spacer name="horizontalSpacer_94"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Fixed</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>15</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLabel" name="max_pred_dspacing_lbl"> - <property name="maximumSize"> - <size> - <width>160</width> - <height>16777215</height> - </size> - </property> - <property name="text"> - <string>Maximum d-spacing</string> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer_67"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLineEdit" name="max_pred_dspacing_ledt"> - <property name="maximumSize"> - <size> - <width>146</width> - <height>16777215</height> - </size> - </property> - <property name="text"> - <string>8.5</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <spacer name="verticalSpacer_3"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_27"> - <item> - <spacer name="horizontalSpacer_19"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QPushButton" name="ApplyFindUB_btn"> - <property name="toolTip"> - <string>Proceed to actually get the<br> UB matrix and (optionally) index the peaks.</string> - </property> - <property name="text"> - <string>Apply</string> - </property> - </widget> - </item> - </layout> - </item> - </layout> - </widget> - </widget> - </item> - </layout> - </widget> - <widget class="QWidget" name="ChooseCell"> - <attribute name="title"> - <string>Choose Cell</string> - </attribute> - <layout class="QVBoxLayout" name="verticalLayout_13"> - <item> - <widget class="QScrollArea" name="scrollArea_3"> - <property name="frameShape"> - <enum>QFrame::NoFrame</enum> - </property> - <property name="frameShadow"> - <enum>QFrame::Plain</enum> - </property> - <property name="widgetResizable"> - <bool>true</bool> - </property> - <widget class="QWidget" name="scrollAreaWidgetContents_5"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>903</width> - <height>708</height> - </rect> + <property name="widgetResizable"> + <bool>true</bool> </property> - <layout class="QVBoxLayout" name="verticalLayout_14"> - <item> - <widget class="QRadioButton" name="ShowPossibleCells_rbtn"> - <property name="toolTip"> - <string>Show a list of the possible<br> conventional cells in the MantidPlot Results Log window. NOTE: The current UB must correspond to a Niggli reduced cell for these to be valid.</string> - </property> - <property name="text"> - <string>Show Possible Cells</string> - </property> - </widget> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_36"> - <item> - <spacer name="horizontalSpacer_38"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Fixed</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>15</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLabel" name="MaxScalarError_lbl"> - <property name="text"> - <string>Max Scalar Error </string> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer_41"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLineEdit" name="MaxScalarError_ledt"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="toolTip"> - <string>Maximum error allowed in the cell<br> scalars. If this is set very large, all possible conventional cells will be shown, including those that don't really match the current cell. If this is set too small, the desired correct cell may be missing from the list due to experimental error. The default value of 0.2 should usually work.</string> - </property> - <property name="text"> - <string>0.2</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_35"> - <item> - <spacer name="horizontalSpacer_37"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Fixed</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>15</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QCheckBox" name="BestCellOnly_ckbx"> - <property name="toolTip"> - <string>Only show the best fitting<br> cell for each cell type and centering that is in the list of possible cells.</string> - </property> - <property name="text"> - <string>Best Only</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_351"> - <item> - <spacer name="horizontalSpacer_371"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Fixed</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>15</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QCheckBox" name="AllowPermutations_ckbx"> - <property name="toolTip"> - <string>Allow permutations of conventional cells.</string> - </property> - <property name="text"> - <string>Allow Permutations</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <widget class="QRadioButton" name="SelectCellOfType_rbtn"> - <property name="toolTip"> - <string>Transform the current UB<br> matrix and indexing to correspond to the best fitting cell with the specified cell-type and centering.</string> - </property> - <property name="text"> - <string>Select Cell of Type</string> - </property> - </widget> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_33"> - <item> - <spacer name="horizontalSpacer_39"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Fixed</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>15</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QComboBox" name="CellType_cmbx"> - <property name="toolTip"> - <string>The cell-type to be used.</string> - </property> - <item> + <widget class="QWidget" name="scrollAreaWidgetContents_2"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>903</width> + <height>696</height> + </rect> + </property> + <layout class="QVBoxLayout" name="verticalLayout_10"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_10"> + <item> + <widget class="QLabel" name="PeaksWorkspace_lbl"> + <property name="text"> + <string>Peaks Workspace Name</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_18"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLineEdit" name="PeaksWorkspace_ledt"> + <property name="toolTip"> + <string>Name of the peaks workspace to use. This name is set by default,<br> if data is loaded from an event file and mapped to an MD workspace on the Select Data tab.</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="Line" name="line_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="FindPeaks_rbtn"> + <property name="toolTip"> + <string>Search through the MD workspace to find Bragg peaks.</string> + </property> + <property name="text"> + <string>Find Peaks</string> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_11"> + <item> + <spacer name="horizontalSpacer_9"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>15</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="MaxABC_lbl"> + <property name="text"> + <string>Estimated Max of a,b,c</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_14"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLineEdit" name="MaxABC_ledt"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Estimated maximum for real<br> space cell edge length in Angstroms. This is used to get an approximate lower bound on the possible distances between peaks.</string> + </property> + <property name="text"> + <string>15</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_12"> + <item> + <spacer name="horizontalSpacer_11"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>15</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="NumToFind_lbl"> + <property name="text"> + <string>Number of Peaks to Find</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_15"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLineEdit" name="NumToFind_ledt"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Maximum number of peaks to find. Boxes with progressively<br> lower local intensity will be tried, until the specified number of peaks is found, or until the intensity falls below the specified Min Intensity.</string> + </property> + <property name="text"> + <string>50</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_13"> + <item> + <spacer name="horizontalSpacer_12"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>15</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="MinIntensity_lbl"> + <property name="text"> + <string>Min Intensity(above ave)</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_16"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLineEdit" name="MinIntensity_ledt"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Lower bound on the local intensity of MD boxes to consider as possible peaks, expressed as a multiple of the overall average intensity of the entire MD workspace region. Boxes with progressively<br> lower local intensity will be tried, until the specified number of peaks is found, or until the intensity falls below the specified Min Intensity.</string> + </property> + <property name="text"> + <string>10000</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QRadioButton" name="UseExistingPeaksWorkspace_rbtn"> + <property name="toolTip"> + <string>Use a peaks workspace with peaks that have been<br> been previously found, predicted, or loaded. </string> + </property> + <property name="text"> + <string>Use Existing Peaks Workspace</string> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="LoadIsawPeaks_rbtn"> + <property name="toolTip"> + <string>Load the peaks workspace from a file of peaks<br> that have been previously found or predicted.</string> + </property> + <property name="text"> + <string>Load ISAW Peaks (or Integrate or Nexus) File</string> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_14"> + <item> + <spacer name="horizontalSpacer_13"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>15</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="SelectPeaksFile_lbl"> + <property name="text"> + <string>Filename</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_17"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLineEdit" name="SelectPeaksFile_ledt"> + <property name="toolTip"> + <string>Name of the peaks file that should be loaded.</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="SelectPeaksFile_btn"> + <property name="toolTip"> + <string>Browse for the file of peaks to load.</string> + </property> + <property name="text"> + <string>Browse</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <spacer name="verticalSpacer_2"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_15"> + <item> + <spacer name="horizontalSpacer_8"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="ApplyFindPeaks_btn"> + <property name="toolTip"> + <string>Proceed to actually get the<br> peaks or use the existing peaks, as specified..</string> + </property> + <property name="text"> + <string>Apply</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="FindUB"> + <attribute name="title"> + <string>Find UB</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_11"> + <item> + <widget class="QScrollArea" name="scrollArea_2"> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Plain</enum> + </property> + <property name="widgetResizable"> + <bool>true</bool> + </property> + <widget class="QWidget" name="scrollAreaWidgetContents_4"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>903</width> + <height>696</height> + </rect> + </property> + <layout class="QVBoxLayout" name="verticalLayout_12"> + <item> + <widget class="QRadioButton" name="FindUBUsingFFT_rbtn"> + <property name="toolTip"> + <string>Find a UB matrix using the<br> FindUBUsingFFT algorithm. This will produce a UB matrix corresponding to the Niggli reduced cell for the lattice.</string> + </property> + <property name="text"> + <string>Find UB Using FFT</string> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_20"> + <item> + <spacer name="horizontalSpacer_28"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>15</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="MinD_lbl"> + <property name="text"> + <string>Estimated Lower Bound for a,b,c</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_29"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLineEdit" name="MinD_ledt"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Set this to a value that is<br> about 50%-90% of the shortest real space edge length, in Angstroms.</string> + </property> + <property name="text"> + <string>3</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_21"> + <item> + <spacer name="horizontalSpacer_27"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>15</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="MaxD_lbl"> + <property name="text"> + <string>Estimated Upper Bound for a,b,c</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_30"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLineEdit" name="MaxD_ledt"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Set this to a value that is<br> about 110%-150% of the longest real space edge length, in Angstroms.</string> + </property> + <property name="text"> + <string>15</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_22"> + <item> + <spacer name="horizontalSpacer_26"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>15</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="FFTTolerance_lbl"> + <property name="text"> + <string>Tolerance</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_31"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLineEdit" name="FFTTolerance_ledt"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Maximum distance of h,k or l from integer values to<br> consider a peak to be indexed.</string> + </property> + <property name="text"> + <string>0.12</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QRadioButton" name="FindUBUsingIndexedPeaks_rbtn"> + <property name="toolTip"> + <string>Find the UB matrix using the FindUBUsingIndexedPeaks algorithm. Specifically, if the<br> peaks in the peaks workspace have already been indexed, find the UB matrix that corresponds to that indexing.</string> + </property> + <property name="text"> + <string>Find UB Using Indexed Peaks</string> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_23"> + <item> + <spacer name="horizontalSpacer_25"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>15</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="IndexedPeaksTolerance_lbl"> + <property name="text"> + <string>Tolerance</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_32"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLineEdit" name="IndexedPeaksTolerance_ledt"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Maximum distance of h,k or l from integer values to<br> consider a peak to be indexed.</string> + </property> + <property name="text"> + <string>0.1</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QRadioButton" name="LoadISAWUB_rbtn"> + <property name="toolTip"> + <string>Load the UB matrix from a file.</string> + </property> + <property name="text"> + <string>Load Isaw UB</string> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_24"> + <item> + <spacer name="horizontalSpacer_24"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>15</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="SelectUBFile_lbl"> + <property name="text"> + <string>Filename</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_33"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::MinimumExpanding</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLineEdit" name="SelectUBFile_ledt"> + <property name="toolTip"> + <string>Name of the file with the UB matrix.</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="SelectUBFile_btn"> + <property name="toolTip"> + <string>Browse for the file with the UB matrix.</string> + </property> + <property name="text"> + <string>Browse</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_31"> + <item> + <spacer name="horizontalSpacer_23"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>15</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QCheckBox" name="OptimizeGoniometerAngles_ckbx"> + <property name="toolTip"> + <string>Optimize the goniometer<br> angles, to index the peaks as accurately as possible using the UB matrix that was loaded.</string> + </property> + <property name="text"> + <string>Optimize Phi, Chi and Omega</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_25"> + <item> + <spacer name="horizontalSpacer_22"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>15</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="MaxGoniometerChange_lbl"> + <property name="text"> + <string>Maximum Change (degrees)</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_34"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLineEdit" name="MaxGoniometerChange_ledt"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Maximum number of degrees that CHI, PHI<br> or OMEGA can be changed.</string> + </property> + <property name="text"> + <string>5</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_30"> + <item> + <widget class="QRadioButton" name="UseCurrentUB_rbtn"> + <property name="toolTip"> + <string>If the peaks workspace<br> already has a UB matrix, just use that UB.</string> + </property> + <property name="text"> + <string>Use Current UB (if already found or loaded)</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="Line" name="line"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_29"> + <item> + <widget class="QCheckBox" name="IndexPeaks_ckbx"> + <property name="toolTip"> + <string>After obtaining the UB<br> matrix, index the peaks using that UB.</string> + </property> + <property name="text"> + <string>Index Peaks Using UB</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_26"> + <item> + <spacer name="horizontalSpacer_20"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>15</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="IndexingTolerance_lbl"> + <property name="text"> + <string>Indexing Tolerance</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_35"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLineEdit" name="IndexingTolerance_ledt"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Only set the h,k,l values on peaks for which the maximum distance of h,k or l from integer values<br> is less than this tolerance.</string> + </property> + <property name="text"> + <string>0.12</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_28"> + <item> + <spacer name="horizontalSpacer_21"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>15</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QCheckBox" name="RoundHKLs_ckbx"> + <property name="toolTip"> + <string>Round the h,k,l values to the nearest integer.</string> + </property> + <property name="text"> + <string>Round HKLs</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QCheckBox" name="PredictPeaks_ckbx"> + <property name="text"> + <string>Predict Peaks</string> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_16"> + <item> + <spacer name="horizontalSpacer_91"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>15</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="min_pred_wl_lbl"> + <property name="maximumSize"> + <size> + <width>160</width> + <height>16777215</height> + </size> + </property> + <property name="text"> + <string>Minimum wavelength</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_64"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLineEdit" name="min_pred_wl_ledt"> + <property name="minimumSize"> + <size> + <width>146</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>146</width> + <height>16777215</height> + </size> + </property> + <property name="text"> + <string>0.4</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_17"> + <item> + <spacer name="horizontalSpacer_92"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>15</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="max_pred_wl_lbl"> + <property name="maximumSize"> + <size> + <width>160</width> + <height>16777215</height> + </size> + </property> + <property name="text"> + <string>Maximum wavelength</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_65"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLineEdit" name="max_pred_wl_ledt"> + <property name="maximumSize"> + <size> + <width>146</width> + <height>16777215</height> + </size> + </property> + <property name="text"> + <string>3.5</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_18"> + <item> + <spacer name="horizontalSpacer_93"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>15</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="min_pred_dspacing_lbl"> + <property name="maximumSize"> + <size> + <width>160</width> + <height>16777215</height> + </size> + </property> + <property name="text"> + <string>Minimum d-spacing</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_66"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLineEdit" name="min_pred_dspacing_ledt"> + <property name="maximumSize"> + <size> + <width>146</width> + <height>16777215</height> + </size> + </property> + <property name="text"> + <string>0.4</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_19"> + <item> + <spacer name="horizontalSpacer_94"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>15</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="max_pred_dspacing_lbl"> + <property name="maximumSize"> + <size> + <width>160</width> + <height>16777215</height> + </size> + </property> + <property name="text"> + <string>Maximum d-spacing</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_67"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLineEdit" name="max_pred_dspacing_ledt"> + <property name="maximumSize"> + <size> + <width>146</width> + <height>16777215</height> + </size> + </property> + <property name="text"> + <string>8.5</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <spacer name="verticalSpacer_3"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_27"> + <item> + <spacer name="horizontalSpacer_19"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="ApplyFindUB_btn"> + <property name="toolTip"> + <string>Proceed to actually get the<br> UB matrix and (optionally) index the peaks.</string> + </property> + <property name="text"> + <string>Apply</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="ChooseCell"> + <attribute name="title"> + <string>Choose Cell</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_13"> + <item> + <widget class="QScrollArea" name="scrollArea_3"> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Plain</enum> + </property> + <property name="widgetResizable"> + <bool>true</bool> + </property> + <widget class="QWidget" name="scrollAreaWidgetContents_5"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>903</width> + <height>696</height> + </rect> + </property> + <layout class="QVBoxLayout" name="verticalLayout_14"> + <item> + <widget class="QRadioButton" name="ShowPossibleCells_rbtn"> + <property name="toolTip"> + <string>Show a list of the possible<br> conventional cells in the MantidPlot Results Log window. NOTE: The current UB must correspond to a Niggli reduced cell for these to be valid.</string> + </property> + <property name="text"> + <string>Show Possible Cells</string> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_36"> + <item> + <spacer name="horizontalSpacer_38"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>15</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="MaxScalarError_lbl"> + <property name="text"> + <string>Max Scalar Error </string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_41"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLineEdit" name="MaxScalarError_ledt"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Maximum error allowed in the cell<br> scalars. If this is set very large, all possible conventional cells will be shown, including those that don't really match the current cell. If this is set too small, the desired correct cell may be missing from the list due to experimental error. The default value of 0.2 should usually work.</string> + </property> + <property name="text"> + <string>0.2</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_35"> + <item> + <spacer name="horizontalSpacer_37"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>15</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QCheckBox" name="BestCellOnly_ckbx"> + <property name="toolTip"> + <string>Only show the best fitting<br> cell for each cell type and centering that is in the list of possible cells.</string> + </property> + <property name="text"> + <string>Best Only</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_351"> + <item> + <spacer name="horizontalSpacer_371"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>15</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QCheckBox" name="AllowPermutations_ckbx"> + <property name="toolTip"> + <string>Allow permutations of conventional cells.</string> + </property> + <property name="text"> + <string>Allow Permutations</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QRadioButton" name="SelectCellOfType_rbtn"> + <property name="toolTip"> + <string>Transform the current UB<br> matrix and indexing to correspond to the best fitting cell with the specified cell-type and centering.</string> + </property> + <property name="text"> + <string>Select Cell of Type</string> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_33"> + <item> + <spacer name="horizontalSpacer_39"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>15</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QComboBox" name="CellType_cmbx"> + <property name="toolTip"> + <string>The cell-type to be used.</string> + </property> + <item> + <property name="text"> + <string>Cubic</string> + </property> + </item> + <item> + <property name="text"> + <string>Hexagonal</string> + </property> + </item> + <item> + <property name="text"> + <string>Monoclinic</string> + </property> + </item> + <item> + <property name="text"> + <string>Orthorhombic</string> + </property> + </item> + <item> + <property name="text"> + <string>Rhombohedral</string> + </property> + </item> + <item> + <property name="text"> + <string>Tetragonal</string> + </property> + </item> + <item> + <property name="text"> + <string>Triclinic</string> + </property> + </item> + </widget> + </item> + <item> + <widget class="QComboBox" name="CellCentering_cmbx"> + <property name="toolTip"> + <string>The centering to be used.</string> + </property> + <item> + <property name="text"> + <string>C</string> + </property> + </item> + <item> + <property name="text"> + <string>F</string> + </property> + </item> + <item> + <property name="text"> + <string>I</string> + </property> + </item> + <item> + <property name="text"> + <string>P</string> + </property> + </item> + <item> + <property name="text"> + <string>R</string> + </property> + </item> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_42"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item> + <widget class="QRadioButton" name="SelectCellWithForm_rbtn"> + <property name="toolTip"> + <string>Transform the current UB<br> matrix and indexing to correspond to the cell with the specified Form number, as shown in the list of possible cells.</string> + </property> + <property name="text"> + <string>Select Cell With Form</string> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_34"> + <item> + <spacer name="horizontalSpacer_40"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>15</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QComboBox" name="CellFormNumber_cmbx"> + <property name="toolTip"> + <string>The Form number of the<br> desired conventional cell.</string> + </property> + <item> + <property name="text"> + <string>1</string> + </property> + </item> + <item> + <property name="text"> + <string>2</string> + </property> + </item> + <item> + <property name="text"> + <string>3</string> + </property> + </item> + <item> + <property name="text"> + <string>4</string> + </property> + </item> + <item> + <property name="text"> + <string>5</string> + </property> + </item> + <item> + <property name="text"> + <string>6</string> + </property> + </item> + <item> + <property name="text"> + <string>7</string> + </property> + </item> + <item> + <property name="text"> + <string>8</string> + </property> + </item> + <item> + <property name="text"> + <string>9</string> + </property> + </item> + <item> + <property name="text"> + <string>10</string> + </property> + </item> + <item> + <property name="text"> + <string>11</string> + </property> + </item> + <item> + <property name="text"> + <string>12</string> + </property> + </item> + <item> + <property name="text"> + <string>13</string> + </property> + </item> + <item> + <property name="text"> + <string>14</string> + </property> + </item> + <item> + <property name="text"> + <string>15</string> + </property> + </item> + <item> + <property name="text"> + <string>16</string> + </property> + </item> + <item> + <property name="text"> + <string>17</string> + </property> + </item> + <item> + <property name="text"> + <string>18</string> + </property> + </item> + <item> + <property name="text"> + <string>19</string> + </property> + </item> + <item> + <property name="text"> + <string>20</string> + </property> + </item> + <item> + <property name="text"> + <string>21</string> + </property> + </item> + <item> + <property name="text"> + <string>22</string> + </property> + </item> + <item> + <property name="text"> + <string>23</string> + </property> + </item> + <item> + <property name="text"> + <string>24</string> + </property> + </item> + <item> + <property name="text"> + <string>25</string> + </property> + </item> + <item> + <property name="text"> + <string>26</string> + </property> + </item> + <item> + <property name="text"> + <string>27</string> + </property> + </item> + <item> + <property name="text"> + <string>28</string> + </property> + </item> + <item> + <property name="text"> + <string>29</string> + </property> + </item> + <item> + <property name="text"> + <string>30</string> + </property> + </item> + <item> + <property name="text"> + <string>31</string> + </property> + </item> + <item> + <property name="text"> + <string>32</string> + </property> + </item> + <item> + <property name="text"> + <string>33</string> + </property> + </item> + <item> + <property name="text"> + <string>34</string> + </property> + </item> + <item> + <property name="text"> + <string>35</string> + </property> + </item> + <item> + <property name="text"> + <string>36</string> + </property> + </item> + <item> + <property name="text"> + <string>37</string> + </property> + </item> + <item> + <property name="text"> + <string>38</string> + </property> + </item> + <item> + <property name="text"> + <string>39</string> + </property> + </item> + <item> + <property name="text"> + <string>40</string> + </property> + </item> + <item> + <property name="text"> + <string>41</string> + </property> + </item> + <item> + <property name="text"> + <string>42</string> + </property> + </item> + <item> + <property name="text"> + <string>43</string> + </property> + </item> + <item> + <property name="text"> + <string>44</string> + </property> + </item> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_43"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item> + <spacer name="verticalSpacer_4"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_32"> + <item> + <spacer name="horizontalSpacer_36"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="ApplyChooseCell_btn"> + <property name="toolTip"> + <string>Proceed to show the<br> possible cells, or change the UB matrix and indexing, according to the options selected.</string> + </property> <property name="text"> - <string>Cubic</string> + <string>Apply</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="ChangeHKL"> + <attribute name="title"> + <string>Change HKL</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_15"> + <item> + <widget class="QScrollArea" name="scrollArea_4"> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Plain</enum> + </property> + <property name="widgetResizable"> + <bool>true</bool> + </property> + <widget class="QWidget" name="scrollAreaWidgetContents_6"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>903</width> + <height>696</height> + </rect> + </property> + <layout class="QVBoxLayout" name="verticalLayout_16"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_37"> + <item> + <widget class="QLabel" name="HKL_Transfrom_lbl"> + <property name="toolTip"> + <string>Transform the UB matrix<br> and peak indexes using the specified 3X3 matrix.</string> </property> - </item> - <item> <property name="text"> - <string>Hexagonal</string> + <string>Specify 3x3 Matrix to Apply to HKL</string> </property> - </item> - <item> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_38"> + <item> + <spacer name="horizontalSpacer_48"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>15</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="HKL_Tran_Row_1_lbl"> <property name="text"> - <string>Monoclinic</string> + <string>HKL Transformation, Row 1</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_45"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLineEdit" name="HKL_tran_row_1_ledt"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>First row of the<br> transformation matrix to apply the HKL indexes.</string> </property> - </item> - <item> <property name="text"> - <string>Orthorhombic</string> + <string>1, 0, 0</string> </property> - </item> - <item> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_39"> + <item> + <spacer name="horizontalSpacer_49"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>15</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="HKL_Tran_Row_2_lbl"> <property name="text"> - <string>Rhombohedral</string> + <string>HKL Transformation, Row 2</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_46"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLineEdit" name="HKL_tran_row_2_ledt"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Second row of the<br> transformation matrix to apply the HKL indexes.</string> </property> - </item> - <item> <property name="text"> - <string>Tetragonal</string> + <string>0, 1, 0</string> </property> - </item> - <item> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_40"> + <item> + <spacer name="horizontalSpacer_50"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>15</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="HKL_Tran_Row_3_lbl"> <property name="text"> - <string>Triclinic</string> + <string>HKL Transformation, Row 3</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_47"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLineEdit" name="HKL_tran_row_3_ledt"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Third row of the<br> transformation matrix to apply the HKL indexes.</string> </property> - </item> - </widget> - </item> - <item> - <widget class="QComboBox" name="CellCentering_cmbx"> - <property name="toolTip"> - <string>The centering to be used.</string> - </property> - <item> <property name="text"> - <string>C</string> + <string>0, 0, 1</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <spacer name="verticalSpacer_5"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_42"> + <item> + <spacer name="horizontalSpacer_44"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="ApplyChangeHKL_btn"> + <property name="toolTip"> + <string>Use the specified matrix<br> to update the peak indexes and UB matrix.</string> </property> - </item> - <item> <property name="text"> - <string>F</string> + <string>Apply</string> </property> - </item> - <item> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="Integrate"> + <attribute name="title"> + <string>Integrate</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_18"> + <item> + <widget class="QScrollArea" name="scrollArea_5"> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Plain</enum> + </property> + <property name="widgetResizable"> + <bool>true</bool> + </property> + <widget class="QWidget" name="scrollAreaWidgetContents_7"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>903</width> + <height>696</height> + </rect> + </property> + <layout class="QVBoxLayout" name="verticalLayout_17"> + <item> + <widget class="QRadioButton" name="SphereIntegration_rbtn"> + <property name="toolTip"> + <string>Apply the IntegratePeaksMD<br> algorithm to integrate the current list of peaks, using spherical regions around the peaks in reciprocal space. This is the fastest of the integration methods. See the algorithm documentation for more details.</string> + </property> + <property name="text"> + <string>Spherical or Cylindrical Integration</string> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_55"> + <item> + <spacer name="horizontalSpacer_63"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>15</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="PeakRadius_lbl"> <property name="text"> - <string>I</string> + <string>Peak Radius (A^-1)</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="PeakRadius_ledt"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Radius of the spherical<br> region that will be considered the body of the peak.</string> </property> - </item> - <item> <property name="text"> - <string>P</string> + <string>0.20</string> </property> - </item> - <item> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_54"> + <item> + <spacer name="horizontalSpacer_62"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>15</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="BackgroundInnerRadius_lbl"> <property name="text"> - <string>R</string> + <string>Background Inner Radius (A^-1)</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="BackgroundInnerRadius_ledt"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Radius of the inner surface<br> of the spherical shell that will be used for the background estimate.</string> </property> - </item> - </widget> - </item> - <item> - <spacer name="horizontalSpacer_42"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - </layout> - </item> - <item> - <widget class="QRadioButton" name="SelectCellWithForm_rbtn"> - <property name="toolTip"> - <string>Transform the current UB<br> matrix and indexing to correspond to the cell with the specified Form number, as shown in the list of possible cells.</string> - </property> - <property name="text"> - <string>Select Cell With Form</string> - </property> - </widget> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_34"> - <item> - <spacer name="horizontalSpacer_40"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Fixed</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>15</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QComboBox" name="CellFormNumber_cmbx"> - <property name="toolTip"> - <string>The Form number of the<br> desired conventional cell.</string> - </property> - <item> <property name="text"> - <string>1</string> + <string>0.20</string> </property> - </item> - <item> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_53"> + <item> + <spacer name="horizontalSpacer_61"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>15</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="BackgroundOuterRadius_lbl"> <property name="text"> - <string>2</string> + <string>Background Outer Radius (A^-1)</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="BackgroundOuterRadius_ledt"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Radius of the outer surface<br> of the spherical shell that will be used for the background estimate.</string> </property> - </item> - <item> <property name="text"> - <string>3</string> + <string>0.25</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_52"> + <item> + <spacer name="horizontalSpacer_55"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>15</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QCheckBox" name="IntegrateEdge_ckbx"> + <property name="toolTip"> + <string>If true, all peaks will be<br> integrated. If false, any peak for which the background shell goes off the edge of the detector will not be integrated.</string> </property> - </item> - <item> <property name="text"> - <string>4</string> + <string>Integrate if on Edge</string> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="Cylinder_ckbx"> + <property name="toolTip"> + <string>If true, cylinder instead of sphere..</string> </property> - </item> - <item> <property name="text"> - <string>5</string> + <string>Integrate with cylinder</string> </property> - </item> - <item> + </widget> + </item> + <item> + <widget class="QComboBox" name="CylinderProfileFit_cmbx"> + <property name="toolTip"> + <string>Fit cylinder profile with function</string> + </property> + <item> + <property name="text"> + <string>BackToBackExponential</string> + </property> + </item> + <item> + <property name="text"> + <string>Bk2BKExpConvPV</string> + </property> + </item> + <item> + <property name="text"> + <string>DeltaFunction</string> + </property> + </item> + <item> + <property name="text"> + <string>ElasticDiffSphere</string> + </property> + </item> + <item> + <property name="text"> + <string>ExamplePeakFunction</string> + </property> + </item> + <item> + <property name="text"> + <string>Gaussian</string> + </property> + </item> + <item> + <property name="text"> + <string>IkedaCarpenterPV</string> + </property> + </item> + <item> + <property name="text"> + <string>Lorentzian</string> + </property> + </item> + <item> + <property name="text"> + <string>NoFit</string> + </property> + </item> + <item> + <property name="text"> + <string>Voigt</string> + </property> + </item> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_53a"> + <item> + <spacer name="horizontalSpacer_61a"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>15</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="CylinderLength_lbl"> <property name="text"> - <string>6</string> + <string>Cylinder Length (A^-1)</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="CylinderLength_ledt"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Length of the cylinder used for integration.</string> </property> - </item> - <item> <property name="text"> - <string>7</string> + <string>0.4</string> </property> - </item> - <item> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_53b"> + <item> + <spacer name="horizontalSpacer_61b"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>15</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="CylinderPercentBkg_lbl"> <property name="text"> - <string>8</string> + <string>Percent of cylinder length that is background.</string> </property> - </item> - <item> + </widget> + </item> + <item> + <widget class="QLineEdit" name="CylinderPercentBkg_ledt"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Radius of the outer surface<br> of the spherical shell that will be used for the background estimate.</string> + </property> + <property name="text"> + <string>0.25</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QRadioButton" name="TwoDFitIntegration_rbtn"> + <property name="toolTip"> + <string>Apply the PeakIntegration<br> algorithm to integrate the current list of peaks, by combining the integrated intensities on multiple time-of-flight slices. This method is much slower than the Spherical Integration method, so please allow time for the calculation to complete. See the algorithm documentation for more details.</string> + </property> + <property name="text"> + <string>2-D Fitting Integration</string> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_51"> + <item> + <spacer name="horizontalSpacer_60"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>15</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="FitRebinParams_lbl"> <property name="text"> - <string>9</string> + <string>Rebin Parameters</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="FitRebinParams_ledt"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Parameters used to form<br> histograms from the event data. The first and last values are the start and end times-of-flight. The middle value is the step size. If the step size is negative it represents the decimal fraction increase in the bin boundary at each step, instead of the actual bin size.</string> + </property> + <property name="text"> + <string>1000,-0.004,16000</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_50"> + <item> + <spacer name="horizontalSpacer_59"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>15</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="NBadEdgePixels_lbl"> + <property name="text"> + <string>Number of Bad Edge Pixels</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="NBadEdgePixels_ledt"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>The width of the border of<br> bad pixels around the edge of each detector that should be omitted.</string> + </property> + <property name="text"> + <string>5</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_49"> + <item> + <spacer name="horizontalSpacer_54"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>15</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QCheckBox" name="IkedaCarpenter_ckbx"> + <property name="toolTip"> + <string>If true, the Ikeda-Carpenter<br> function will be used to fit the results of integrating the various time-of-flight slices, to obtain the final integrated result.</string> </property> - </item> - <item> <property name="text"> - <string>10</string> + <string>Ikeda-Carpenter TOF</string> </property> - </item> - <item> - <property name="text"> - <string>11</string> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QRadioButton" name="EllipsoidIntegration_rbtn"> + <property name="toolTip"> + <string>Apply the IntegrateEllipsoids<br> algorithm to integrate the current list of peaks, by finding the principal axes of the 3D events in regions around each peak. This method is a little slower than the Spherical Integration method. See the algorithm documentation for more details.</string> + </property> + <property name="text"> + <string>Ellipsoidal Integration (Integer HKL only)</string> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_48"> + <item> + <spacer name="horizontalSpacer_58"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> </property> - </item> - <item> - <property name="text"> - <string>12</string> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> </property> - </item> - <item> - <property name="text"> - <string>13</string> + <property name="sizeHint" stdset="0"> + <size> + <width>15</width> + <height>0</height> + </size> </property> - </item> - <item> + </spacer> + </item> + <item> + <widget class="QLabel" name="RegionRadius_lbl"> <property name="text"> - <string>14</string> + <string>Region Radius (A^-1)</string> </property> - </item> - <item> - <property name="text"> - <string>15</string> + </widget> + </item> + <item> + <widget class="QLineEdit" name="RegionRadius_ledt"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> </property> - </item> - <item> - <property name="text"> - <string>16</string> + <property name="toolTip"> + <string>Radius of a spherical region<br> around each peak that will be used when finding the principal axes. This should be large enough to include the entire peak and nearby background region, but not much larger.</string> </property> - </item> - <item> <property name="text"> - <string>17</string> + <string>0.25</string> </property> - </item> - <item> - <property name="text"> - <string>18</string> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_47"> + <item> + <spacer name="horizontalSpacer_52"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> </property> - </item> - <item> - <property name="text"> - <string>19</string> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> </property> - </item> - <item> - <property name="text"> - <string>20</string> + <property name="sizeHint" stdset="0"> + <size> + <width>15</width> + <height>0</height> + </size> </property> - </item> - <item> - <property name="text"> - <string>21</string> + </spacer> + </item> + <item> + <widget class="QCheckBox" name="SpecifySize_ckbx"> + <property name="toolTip"> + <string>If this is set true, the major axis<br> size of each ellipsoidal region will be constant for all peaks, and will be set by the following three parameters. If this is set false, the major axis sizes will be calculated based on the standard deviation in the direction of the major axis.</string> </property> - </item> - <item> <property name="text"> - <string>22</string> + <string>Specify Size</string> </property> - </item> - <item> - <property name="text"> - <string>23</string> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_46"> + <item> + <spacer name="horizontalSpacer_57"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> </property> - </item> - <item> - <property name="text"> - <string>24</string> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> </property> - </item> - <item> - <property name="text"> - <string>25</string> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>0</height> + </size> </property> - </item> - <item> + </spacer> + </item> + <item> + <widget class="QLabel" name="PeakSize_lbl"> <property name="text"> - <string>26</string> + <string>Peak Size (A^-1)</string> </property> - </item> - <item> - <property name="text"> - <string>27</string> + </widget> + </item> + <item> + <widget class="QLineEdit" name="PeakSize_ledt"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> </property> - </item> - <item> - <property name="text"> - <string>28</string> + <property name="toolTip"> + <string>Length of the major axis<br> to use for the ellipsoidal peak region.</string> </property> - </item> - <item> <property name="text"> - <string>29</string> + <string>0.20</string> </property> - </item> - <item> - <property name="text"> - <string>30</string> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_45"> + <item> + <spacer name="horizontalSpacer_56"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> </property> - </item> - <item> - <property name="text"> - <string>31</string> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> </property> - </item> - <item> - <property name="text"> - <string>32</string> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>0</height> + </size> </property> - </item> - <item> + </spacer> + </item> + <item> + <widget class="QLabel" name="BackgroundInnerSize_lbl"> <property name="text"> - <string>33</string> + <string>Background Inner Size (A^-1)</string> </property> - </item> - <item> - <property name="text"> - <string>34</string> + </widget> + </item> + <item> + <widget class="QLineEdit" name="BackgroundInnerSize_ledt"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> </property> - </item> - <item> - <property name="text"> - <string>35</string> + <property name="toolTip"> + <string>Length of the major axis<br> of the inner surface of the ellipsoidal shell used for the background region.</string> </property> - </item> - <item> <property name="text"> - <string>36</string> + <string>0.20</string> </property> - </item> - <item> - <property name="text"> - <string>37</string> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_44"> + <item> + <spacer name="horizontalSpacer_53"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> </property> - </item> - <item> - <property name="text"> - <string>38</string> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> </property> - </item> - <item> - <property name="text"> - <string>39</string> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>0</height> + </size> </property> - </item> - <item> + </spacer> + </item> + <item> + <widget class="QLabel" name="BackgroundOuterSize_lbl"> <property name="text"> - <string>40</string> + <string>Background Outer Size (A^-1) </string> </property> - </item> - <item> - <property name="text"> - <string>41</string> + </widget> + </item> + <item> + <widget class="QLineEdit" name="BackgroundOuterSize_ledt"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> </property> - </item> - <item> - <property name="text"> - <string>42</string> + <property name="toolTip"> + <string>Length of the major axis<br> of the outer surface of the ellipsoidal shell used for the background region.</string> </property> - </item> - <item> <property name="text"> - <string>43</string> + <string>0.25</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <spacer name="verticalSpacer_6"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_43"> + <item> + <spacer name="horizontalSpacer_51"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="ApplyIntegrate_btn"> + <property name="toolTip"> + <string>Proceed to actually do the peak integration as specified.</string> </property> - </item> - <item> <property name="text"> - <string>44</string> + <string>Apply</string> </property> - </item> - </widget> - </item> - <item> - <spacer name="horizontalSpacer_43"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - </layout> - </item> - <item> - <spacer name="verticalSpacer_4"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_32"> - <item> - <spacer name="horizontalSpacer_36"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QPushButton" name="ApplyChooseCell_btn"> - <property name="toolTip"> - <string>Proceed to show the<br> possible cells, or change the UB matrix and indexing, according to the options selected.</string> - </property> - <property name="text"> - <string>Apply</string> - </property> - </widget> - </item> - </layout> - </item> - </layout> + </widget> + </item> + </layout> + </item> + </layout> + </widget> </widget> - </widget> - </item> - </layout> - </widget> - <widget class="QWidget" name="ChangeHKL"> - <attribute name="title"> - <string>Change HKL</string> - </attribute> - <layout class="QVBoxLayout" name="verticalLayout_15"> - <item> - <widget class="QScrollArea" name="scrollArea_4"> - <property name="frameShape"> - <enum>QFrame::NoFrame</enum> - </property> - <property name="frameShadow"> - <enum>QFrame::Plain</enum> - </property> - <property name="widgetResizable"> - <bool>true</bool> - </property> - <widget class="QWidget" name="scrollAreaWidgetContents_6"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>903</width> - <height>708</height> - </rect> + </item> + </layout> + </widget> + <widget class="QWidget" name="PointInfo_tab"> + <attribute name="title"> + <string>Point Info</string> + </attribute> + <layout class="QGridLayout" name="gridLayout_3"> + <item row="0" column="0"> + <widget class="QGroupBox" name="SelectedPoint_grpbx"> + <property name="title"> + <string>Selected Point Info</string> </property> - <layout class="QVBoxLayout" name="verticalLayout_16"> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_37"> - <item> - <widget class="QLabel" name="HKL_Transfrom_lbl"> - <property name="toolTip"> - <string>Transform the UB matrix<br> and peak indexes using the specified 3X3 matrix.</string> - </property> - <property name="text"> - <string>Specify 3x3 Matrix to Apply to HKL</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_38"> - <item> - <spacer name="horizontalSpacer_48"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Fixed</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>15</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLabel" name="HKL_Tran_Row_1_lbl"> - <property name="text"> - <string>HKL Transformation, Row 1</string> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer_45"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLineEdit" name="HKL_tran_row_1_ledt"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="toolTip"> - <string>First row of the<br> transformation matrix to apply the HKL indexes.</string> - </property> - <property name="text"> - <string>1, 0, 0</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_39"> - <item> - <spacer name="horizontalSpacer_49"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Fixed</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>15</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLabel" name="HKL_Tran_Row_2_lbl"> - <property name="text"> - <string>HKL Transformation, Row 2</string> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer_46"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLineEdit" name="HKL_tran_row_2_ledt"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="toolTip"> - <string>Second row of the<br> transformation matrix to apply the HKL indexes.</string> - </property> - <property name="text"> - <string>0, 1, 0</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_40"> - <item> - <spacer name="horizontalSpacer_50"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Fixed</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>15</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLabel" name="HKL_Tran_Row_3_lbl"> - <property name="text"> - <string>HKL Transformation, Row 3</string> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer_47"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLineEdit" name="HKL_tran_row_3_ledt"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="toolTip"> - <string>Third row of the<br> transformation matrix to apply the HKL indexes.</string> - </property> - <property name="text"> - <string>0, 0, 1</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <spacer name="verticalSpacer_5"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> + <layout class="QVBoxLayout" name="verticalLayout_2"> <item> - <layout class="QHBoxLayout" name="horizontalLayout_42"> - <item> - <spacer name="horizontalSpacer_44"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QPushButton" name="ApplyChangeHKL_btn"> - <property name="toolTip"> - <string>Use the specified matrix<br> to update the peak indexes and UB matrix.</string> - </property> - <property name="text"> - <string>Apply</string> - </property> - </widget> - </item> - </layout> + <widget class="QTableWidget" name="SelectedPoint_tbl"/> </item> - </layout> - </widget> - </widget> - </item> - </layout> - </widget> - <widget class="QWidget" name="Integrate"> - <attribute name="title"> - <string>Integrate</string> - </attribute> - <layout class="QVBoxLayout" name="verticalLayout_18"> - <item> - <widget class="QScrollArea" name="scrollArea_5"> - <property name="frameShape"> - <enum>QFrame::NoFrame</enum> - </property> - <property name="frameShadow"> - <enum>QFrame::Plain</enum> - </property> - <property name="widgetResizable"> - <bool>true</bool> - </property> - <widget class="QWidget" name="scrollAreaWidgetContents_7"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>903</width> - <height>708</height> - </rect> - </property> - <layout class="QVBoxLayout" name="verticalLayout_17"> <item> - <widget class="QRadioButton" name="SphereIntegration_rbtn"> - <property name="toolTip"> - <string>Apply the IntegratePeaksMD<br> algorithm to integrate the current list of peaks, using spherical regions around the peaks in reciprocal space. This is the fastest of the integration methods. See the algorithm documentation for more details.</string> - </property> - <property name="text"> - <string>Spherical or Cylindrical Integration</string> + <widget class="QGroupBox" name="groupBox"> + <property name="title"> + <string>Specify Qx Qy Qz</string> </property> - </widget> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_55"> - <item> - <spacer name="horizontalSpacer_63"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Fixed</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>15</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLabel" name="PeakRadius_lbl"> - <property name="text"> - <string>Peak Radius (A^-1)</string> - </property> - </widget> - </item> - <item> - <widget class="QLineEdit" name="PeakRadius_ledt"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="toolTip"> - <string>Radius of the spherical<br> region that will be considered the body of the peak.</string> - </property> - <property name="text"> - <string>0.20</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_54"> - <item> - <spacer name="horizontalSpacer_62"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Fixed</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>15</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLabel" name="BackgroundInnerRadius_lbl"> - <property name="text"> - <string>Background Inner Radius (A^-1)</string> - </property> - </widget> - </item> - <item> - <widget class="QLineEdit" name="BackgroundInnerRadius_ledt"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="toolTip"> - <string>Radius of the inner surface<br> of the spherical shell that will be used for the background estimate.</string> - </property> - <property name="text"> - <string>0.20</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_53"> - <item> - <spacer name="horizontalSpacer_61"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Fixed</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>15</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLabel" name="BackgroundOuterRadius_lbl"> - <property name="text"> - <string>Background Outer Radius (A^-1)</string> - </property> - </widget> - </item> - <item> - <widget class="QLineEdit" name="BackgroundOuterRadius_ledt"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="toolTip"> - <string>Radius of the outer surface<br> of the spherical shell that will be used for the background estimate.</string> - </property> - <property name="text"> - <string>0.25</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_52"> - <item> - <spacer name="horizontalSpacer_55"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Fixed</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>15</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QCheckBox" name="IntegrateEdge_ckbx"> - <property name="toolTip"> - <string>If true, all peaks will be<br> integrated. If false, any peak for which the background shell goes off the edge of the detector will not be integrated.</string> - </property> - <property name="text"> - <string>Integrate if on Edge</string> - </property> - </widget> - </item> - <item> - <widget class="QCheckBox" name="Cylinder_ckbx"> - <property name="toolTip"> - <string>If true, cylinder instead of sphere..</string> - </property> - <property name="text"> - <string>Integrate with cylinder</string> - </property> - </widget> - </item> - <item> - <widget class="QComboBox" name="CylinderProfileFit_cmbx"> - <property name="toolTip"> - <string>Fit cylinder profile with function</string> - </property> - <item> - <property name="text"> - <string>BackToBackExponential</string> - </property> - </item> - <item> - <property name="text"> - <string>Bk2BKExpConvPV</string> - </property> - </item> - <item> - <property name="text"> - <string>DeltaFunction</string> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QLineEdit" name="Qx_ledt"> + <property name="toolTip"> + <string>The X-coordinate of a point<br> of interest in reciprocal space specified in lab coordinates.</string> </property> - </item> - <item> <property name="text"> - <string>ElasticDiffSphere</string> + <string>0.0</string> </property> - </item> - <item> - <property name="text"> - <string>ExamplePeakFunction</string> + </widget> + </item> + <item> + <widget class="QLineEdit" name="Qy_ledt"> + <property name="toolTip"> + <string>The Y-coordinate of a point<br> of interest in reciprocal space specified in lab coordinates.</string> </property> - </item> - <item> <property name="text"> - <string>Gaussian</string> + <string>0.0</string> </property> - </item> - <item> - <property name="text"> - <string>IkedaCarpenterPV</string> + </widget> + </item> + <item> + <widget class="QLineEdit" name="Qz_ledt"> + <property name="toolTip"> + <string>The Z-coordinate of a point<br> of interest in reciprocal space specified in lab coordinates.</string> </property> - </item> - <item> <property name="text"> - <string>Lorentzian</string> + <string>0.0</string> </property> - </item> - <item> - <property name="text"> - <string>NoFit</string> + </widget> + </item> + <item> + <widget class="QPushButton" name="ShowInfo_btn"> + <property name="toolTip"> + <string>Press this after entering<br> Qx,Qy,Qz in lab coordinates to display information about that point in the Selected Point Info table.</string> </property> - </item> - <item> <property name="text"> - <string>Voigt</string> + <string>Show Info</string> </property> - </item> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_53a"> - <item> - <spacer name="horizontalSpacer_61a"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Fixed</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>15</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLabel" name="CylinderLength_lbl"> - <property name="text"> - <string>Cylinder Length (A^-1)</string> - </property> - </widget> - </item> - <item> - <widget class="QLineEdit" name="CylinderLength_ledt"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="toolTip"> - <string>Length of the cylinder used for integration.</string> - </property> - <property name="text"> - <string>0.4</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_53b"> - <item> - <spacer name="horizontalSpacer_61b"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Fixed</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>15</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLabel" name="CylinderPercentBkg_lbl"> - <property name="text"> - <string>Percent of cylinder length that is background.</string> - </property> - </widget> - </item> - <item> - <widget class="QLineEdit" name="CylinderPercentBkg_ledt"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="toolTip"> - <string>Radius of the outer surface<br> of the spherical shell that will be used for the background estimate.</string> - </property> - <property name="text"> - <string>0.25</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <widget class="QRadioButton" name="TwoDFitIntegration_rbtn"> - <property name="toolTip"> - <string>Apply the PeakIntegration<br> algorithm to integrate the current list of peaks, by combining the integrated intensities on multiple time-of-flight slices. This method is much slower than the Spherical Integration method, so please allow time for the calculation to complete. See the algorithm documentation for more details.</string> - </property> - <property name="text"> - <string>2-D Fitting Integration</string> - </property> - </widget> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_51"> - <item> - <spacer name="horizontalSpacer_60"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Fixed</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>15</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLabel" name="FitRebinParams_lbl"> - <property name="text"> - <string>Rebin Parameters</string> - </property> - </widget> - </item> - <item> - <widget class="QLineEdit" name="FitRebinParams_ledt"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="toolTip"> - <string>Parameters used to form<br> histograms from the event data. The first and last values are the start and end times-of-flight. The middle value is the step size. If the step size is negative it represents the decimal fraction increase in the bin boundary at each step, instead of the actual bin size.</string> - </property> - <property name="text"> - <string>1000,-0.004,16000</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_50"> - <item> - <spacer name="horizontalSpacer_59"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Fixed</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>15</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLabel" name="NBadEdgePixels_lbl"> - <property name="text"> - <string>Number of Bad Edge Pixels</string> - </property> - </widget> - </item> - <item> - <widget class="QLineEdit" name="NBadEdgePixels_ledt"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="toolTip"> - <string>The width of the border of<br> bad pixels around the edge of each detector that should be omitted.</string> - </property> - <property name="text"> - <string>5</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_49"> - <item> - <spacer name="horizontalSpacer_54"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Fixed</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>15</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QCheckBox" name="IkedaCarpenter_ckbx"> - <property name="toolTip"> - <string>If true, the Ikeda-Carpenter<br> function will be used to fit the results of integrating the various time-of-flight slices, to obtain the final integrated result.</string> - </property> - <property name="text"> - <string>Ikeda-Carpenter TOF</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <widget class="QRadioButton" name="EllipsoidIntegration_rbtn"> - <property name="toolTip"> - <string>Apply the IntegrateEllipsoids<br> algorithm to integrate the current list of peaks, by finding the principal axes of the 3D events in regions around each peak. This method is a little slower than the Spherical Integration method. See the algorithm documentation for more details.</string> - </property> - <property name="text"> - <string>Ellipsoidal Integration (Integer HKL only)</string> - </property> + </widget> + </item> + </layout> </widget> </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_48"> - <item> - <spacer name="horizontalSpacer_58"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Fixed</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>15</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLabel" name="RegionRadius_lbl"> - <property name="text"> - <string>Region Radius (A^-1)</string> - </property> - </widget> - </item> - <item> - <widget class="QLineEdit" name="RegionRadius_ledt"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="toolTip"> - <string>Radius of a spherical region<br> around each peak that will be used when finding the principal axes. This should be large enough to include the entire peak and nearby background region, but not much larger.</string> - </property> - <property name="text"> - <string>0.25</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_47"> - <item> - <spacer name="horizontalSpacer_52"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Fixed</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>15</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QCheckBox" name="SpecifySize_ckbx"> - <property name="toolTip"> - <string>If this is set true, the major axis<br> size of each ellipsoidal region will be constant for all peaks, and will be set by the following three parameters. If this is set false, the major axis sizes will be calculated based on the standard deviation in the direction of the major axis.</string> - </property> - <property name="text"> - <string>Specify Size</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_46"> - <item> - <spacer name="horizontalSpacer_57"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Fixed</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLabel" name="PeakSize_lbl"> - <property name="text"> - <string>Peak Size (A^-1)</string> - </property> - </widget> - </item> - <item> - <widget class="QLineEdit" name="PeakSize_ledt"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="toolTip"> - <string>Length of the major axis<br> to use for the ellipsoidal peak region.</string> - </property> - <property name="text"> - <string>0.20</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_45"> - <item> - <spacer name="horizontalSpacer_56"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Fixed</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLabel" name="BackgroundInnerSize_lbl"> - <property name="text"> - <string>Background Inner Size (A^-1)</string> - </property> - </widget> - </item> - <item> - <widget class="QLineEdit" name="BackgroundInnerSize_ledt"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="toolTip"> - <string>Length of the major axis<br> of the inner surface of the ellipsoidal shell used for the background region.</string> - </property> - <property name="text"> - <string>0.20</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_44"> - <item> - <spacer name="horizontalSpacer_53"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Fixed</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLabel" name="BackgroundOuterSize_lbl"> - <property name="text"> - <string>Background Outer Size (A^-1) </string> - </property> - </widget> - </item> - <item> - <widget class="QLineEdit" name="BackgroundOuterSize_ledt"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="toolTip"> - <string>Length of the major axis<br> of the outer surface of the ellipsoidal shell used for the background region.</string> - </property> - <property name="text"> - <string>0.25</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <spacer name="verticalSpacer_6"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_43"> - <item> - <spacer name="horizontalSpacer_51"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QPushButton" name="ApplyIntegrate_btn"> - <property name="toolTip"> - <string>Proceed to actually do the peak integration as specified.</string> - </property> - <property name="text"> - <string>Apply</string> - </property> - </widget> - </item> - </layout> - </item> </layout> </widget> - </widget> - </item> - </layout> - </widget> - <widget class="QWidget" name="PointInfo_tab"> - <attribute name="title"> - <string>Point Info</string> - </attribute> - <layout class="QGridLayout" name="gridLayout_3"> - <item row="0" column="0"> - <widget class="QGroupBox" name="SelectedPoint_grpbx"> - <property name="title"> - <string>Selected Point Info</string> - </property> - <layout class="QVBoxLayout" name="verticalLayout_2"> - <item> - <widget class="QTableWidget" name="SelectedPoint_tbl"/> - </item> - <item> - <widget class="QGroupBox" name="groupBox"> - <property name="title"> - <string>Specify Qx Qy Qz</string> - </property> - <layout class="QHBoxLayout" name="horizontalLayout"> - <item> - <widget class="QLineEdit" name="Qx_ledt"> - <property name="toolTip"> - <string>The X-coordinate of a point<br> of interest in reciprocal space specified in lab coordinates.</string> - </property> - <property name="text"> - <string>0.0</string> - </property> - </widget> - </item> - <item> - <widget class="QLineEdit" name="Qy_ledt"> - <property name="toolTip"> - <string>The Y-coordinate of a point<br> of interest in reciprocal space specified in lab coordinates.</string> - </property> - <property name="text"> - <string>0.0</string> - </property> - </widget> - </item> - <item> - <widget class="QLineEdit" name="Qz_ledt"> - <property name="toolTip"> - <string>The Z-coordinate of a point<br> of interest in reciprocal space specified in lab coordinates.</string> - </property> - <property name="text"> - <string>0.0</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="ShowInfo_btn"> - <property name="toolTip"> - <string>Press this after entering<br> Qx,Qy,Qz in lab coordinates to display information about that point in the Selected Point Info table.</string> - </property> - <property name="text"> - <string>Show Info</string> - </property> - </widget> - </item> - </layout> - </widget> - </item> - </layout> - </widget> - </item> - </layout> + </item> + </layout> + </widget> </widget> - </widget> - </item> - </layout> - </widget> - <widget class="QStatusBar" name="statusbar"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>3</width> - <height>27</height> - </rect> - </property> + </item> + </layout> </widget> + <widget class="QStatusBar" name="statusbar"/> <action name="actionSave_State"> <property name="text"> <string>Save Settings</string> @@ -3529,6 +3522,16 @@ <string>Online Help Page</string> </property> </action> + <action name="actionSave_Nexus_Peaks"> + <property name="text"> + <string>Save Nexus Peaks</string> + </property> + </action> + <action name="actionLoad_Nexus_Peaks"> + <property name="text"> + <string>Load Nexus Peaks</string> + </property> + </action> </widget> <resources/> <connections/> diff --git a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/MantidEVWorker.h b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/MantidEVWorker.h index af3a2a596b9f7a586c39a05f0975e6e6e2f02ab6..5f92a905fa2eb2ad2d050a7bdb9ae23c4fc470f6 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/MantidEVWorker.h +++ b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/MantidEVWorker.h @@ -95,11 +95,19 @@ public: bool loadIsawPeaks( const std::string & peaks_ws_name, const std::string & file_name ); + bool loadNexusPeaks( const std::string & peaks_ws_name, + const std::string & file_name ); + /// Save the peaks workspace to a .peaks or .integrate file bool saveIsawPeaks( const std::string & peaks_ws_name, const std::string & file_name, bool append ); + /// Save the peaks workspace to a .nxs file + bool saveNexusPeaks( const std::string & peaks_ws_name, + const std::string & file_name, + bool append ); + /// Index the peaks using the FFT method bool findUBUsingFFT( const std::string & peaks_ws_name, double min_abc, diff --git a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/ALCDataLoadingView.h b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/ALCDataLoadingView.h index e7ae3ae6b3c7514ad4f4b94446e4888f2a5c23d7..119a4b206db4cbd5f13e90c4cfb44a8f39d1b84e 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/ALCDataLoadingView.h +++ b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/ALCDataLoadingView.h @@ -68,6 +68,8 @@ namespace CustomInterfaces void displayError(const std::string &error); void setAvailableLogs(const std::vector<std::string> &logs); void setAvailablePeriods(const std::vector<std::string> &periods); + void setTimeLimits(double tMin, double tMax); + void setTimeRange (double tMin, double tMax); void setWaitingCursor(); void restoreCursor(); void help(); diff --git a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/ALCDataLoadingView.ui b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/ALCDataLoadingView.ui index 41440428b1cbb8f4c0992fee55681f94a34a0848..ebd0214679a8790968ec3c8b6f175f30520d54a4 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/ALCDataLoadingView.ui +++ b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/ALCDataLoadingView.ui @@ -387,7 +387,17 @@ </widget> </item> <item> - <widget class="QDoubleSpinBox" name="minTime"/> + <widget class="QDoubleSpinBox" name="minTime"> + <property name="minimum"> + <double>-6</double> + </property> + <property name="maximum"> + <double>33</double> + </property> + <property name="decimals"> + <number>3</number> + </property> + </widget> </item> <item> <widget class="QLabel" name="label_5"> @@ -397,7 +407,17 @@ </widget> </item> <item> - <widget class="QDoubleSpinBox" name="maxTime"/> + <widget class="QDoubleSpinBox" name="maxTime"> + <property name="minimum"> + <double>-6</double> + </property> + <property name="maximum"> + <double>33</double> + </property> + <property name="decimals"> + <number>3</number> + </property> + </widget> </item> </layout> </widget> diff --git a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/IALCDataLoadingView.h b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/IALCDataLoadingView.h index 56a61e0bbc2377bfbee68ea22c9cdcbc37720127..54ec12db0a804fe6e9a5667054c5f37bdf52116f 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/IALCDataLoadingView.h +++ b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/IALCDataLoadingView.h @@ -103,6 +103,16 @@ namespace CustomInterfaces /// @param periods :: New list of periods virtual void setAvailablePeriods(const std::vector<std::string>& periods) = 0; + /// Update the time limits + /// @param tMin :: Minimum X value available + /// @param tMax :: Maximum X value available + virtual void setTimeLimits(double tMin, double tMax) = 0; + + /// Update the time limits + /// @param tMin :: Minimum X value available + /// @param tMax :: Maximum X value available + virtual void setTimeRange(double tMin, double tMax) = 0; + /// Set waiting cursor for long operation virtual void setWaitingCursor() = 0; diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/Indirect/ApplyCorr.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/Indirect/ApplyCorr.cpp index 7ca36c482874d676f761e9e0ecc0eb0b3fd60361..1e3827e19558474516d9681fce45fb28f2c72278 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/src/Indirect/ApplyCorr.cpp +++ b/Code/Mantid/MantidQt/CustomInterfaces/src/Indirect/ApplyCorr.cpp @@ -1,9 +1,11 @@ #include "MantidQtCustomInterfaces/Indirect/ApplyCorr.h" +#include "MantidQtCustomInterfaces/UserInputValidator.h" #include "MantidAPI/AnalysisDataService.h" #include "MantidAPI/TextAxis.h" #include <QStringList> + using namespace Mantid::API; namespace @@ -21,10 +23,8 @@ namespace IDA IDATab(parent) { m_uiForm.setupUi(parent); - } - void ApplyCorr::setup() - { + connect(m_batchAlgoRunner, SIGNAL(batchComplete(bool)), this, SLOT(algorithmComplete(bool))); connect(m_uiForm.cbGeometry, SIGNAL(currentIndexChanged(int)), this, SLOT(handleGeometryChange(int))); connect(m_uiForm.dsSample, SIGNAL(dataReady(const QString&)), this, SLOT(newData(const QString&))); connect(m_uiForm.spPreviewSpec, SIGNAL(valueChanged(int)), this, SLOT(plotPreview(int))); @@ -33,6 +33,12 @@ namespace IDA m_uiForm.spPreviewSpec->setMaximum(0); } + + void ApplyCorr::setup() + { + } + + /** * Disables corrections when using S(Q, w) as input data. * @@ -48,155 +54,301 @@ namespace IDA m_uiForm.ppPreview->addSpectrum("Sample", sampleWs, 0, Qt::black); } + void ApplyCorr::run() { - QString geom = m_uiForm.cbGeometry->currentText(); - if ( geom == "Flat" ) + API::BatchAlgorithmRunner::AlgorithmRuntimeProps absCorProps; + IAlgorithm_sptr applyCorrAlg = AlgorithmManager::Instance().create("ApplyPaalmanPingsCorrection"); + applyCorrAlg->initialize(); + + QString sampleWsName = m_uiForm.dsSample->getCurrentDataName(); + MatrixWorkspace_sptr sampleWs = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(sampleWsName.toStdString()); + Mantid::Kernel::Unit_sptr sampleXUnit = sampleWs->getAxis(0)->unit(); + + // If not in wavelength then do conversion + if(sampleXUnit->caption() != "Wavelength") { - geom = "flt"; + g_log.information("Sample workspace not in wavelength, need to convert to continue."); + absCorProps["SampleWorkspace"] = addConvertToWavelengthStep(sampleWs); } - else if ( geom == "Cylinder" ) + else { - geom = "cyl"; + absCorProps["SampleWorkspace"] = sampleWsName.toStdString(); } - QString pyInput = "from IndirectDataAnalysis import abscorFeeder\n"; - - QString sample = m_uiForm.dsSample->getCurrentDataName(); - MatrixWorkspace_const_sptr sampleWs = AnalysisDataService::Instance().retrieveWS<const MatrixWorkspace>(sample.toStdString()); - - pyInput += "sample = '"+sample+"'\n"; - pyInput += "rebin_can = False\n"; - bool noContainer = false; - bool useCan = m_uiForm.ckUseCan->isChecked(); if(useCan) { - QString container = m_uiForm.dsContainer->getCurrentDataName(); - MatrixWorkspace_const_sptr canWs = AnalysisDataService::Instance().retrieveWS<const MatrixWorkspace>(container.toStdString()); + QString canWsName = m_uiForm.dsContainer->getCurrentDataName(); + MatrixWorkspace_sptr canWs = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(canWsName.toStdString()); - if (!checkWorkspaceBinningMatches(sampleWs, canWs)) + // If not in wavelength then do conversion + Mantid::Kernel::Unit_sptr canXUnit = canWs->getAxis(0)->unit(); + if(canXUnit->caption() != "Wavelength") { - if (requireCanRebin()) + g_log.information("Container workspace not in wavelength, need to convert to continue."); + absCorProps["CanWorkspace"] = addConvertToWavelengthStep(canWs); + } + else + { + absCorProps["CanWorkspace"] = canWsName.toStdString(); + } + + bool useCanScale = m_uiForm.ckScaleCan->isChecked(); + if(useCanScale) + { + double canScaleFactor = m_uiForm.spCanScale->value(); + applyCorrAlg->setProperty("CanScaleFactor", canScaleFactor); + } + + // Check for same binning across sample and container + if(!checkWorkspaceBinningMatches(sampleWs, canWs)) + { + QString text = "Binning on sample and container does not match." + "Would you like to rebin the sample to match the container?"; + + int result = QMessageBox::question(NULL, tr("Rebin sample?"), tr(text), + QMessageBox::Yes, QMessageBox::No, QMessageBox::NoButton); + + if(result == QMessageBox::Yes) { - pyInput += "rebin_can = True\n"; + addRebinStep(sampleWsName, canWsName); } else { - //user clicked cancel and didn't want to rebin, so just do nothing. + m_batchAlgoRunner->clearQueue(); + g_log.error("Cannot apply absorption corrections using a sample and container with different binning."); return; } } - - pyInput += "container = '" + container + "'\n"; } - else - { - pyInput += "container = ''\n"; - noContainer = true; - } - - pyInput += "geom = '" + geom + "'\n"; - if( m_uiForm.ckUseCorrections->isChecked() ) - { - pyInput += "useCor = True\n"; - QString corrections = m_uiForm.dsCorrections->getCurrentDataName(); - pyInput += "corrections = '" + corrections + "'\n"; - } - else + bool useCorrections = m_uiForm.ckUseCorrections->isChecked(); + if(useCorrections) { - pyInput += "useCor = False\n"; - pyInput += "corrections = ''\n"; + QString correctionsWsName = m_uiForm.dsCorrections->getCurrentDataName(); - // if we have no container and no corrections then abort - if(noContainer) + WorkspaceGroup_sptr corrections = AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>(correctionsWsName.toStdString()); + bool interpolateAll = false; + for(size_t i = 0; i < corrections->size(); i++) { - showMessageBox("Apply Corrections requires either a can file or a corrections file."); - return; + MatrixWorkspace_sptr factorWs = boost::dynamic_pointer_cast<MatrixWorkspace>(corrections->getItem(i)); + + // Check for matching binning + if(sampleWs && (sampleWs->blocksize() != factorWs->blocksize())) + { + int result; + if(interpolateAll) + { + result = QMessageBox::Yes; + } + else + { + QString text = "Number of bins on sample and " + + QString::fromStdString(factorWs->name()) + + " workspace does not match.\n" + + "Would you like to interpolate this workspace to match the sample?"; + + result = QMessageBox::question(NULL, tr("Interpolate corrections?"), tr(text), + QMessageBox::YesToAll, QMessageBox::Yes, QMessageBox::No); + } + + switch(result) + { + case QMessageBox::YesToAll: + interpolateAll = true; + case QMessageBox::Yes: + addInterpolationStep(factorWs, absCorProps["SampleWorkspace"]); + break; + default: + m_batchAlgoRunner->clearQueue(); + g_log.error("ApplyCorr cannot run with corrections that do not match sample binning."); + return; + } + } } - } - QString ScalingFactor = "1.0\n"; - QString ScaleOrNot = "False\n"; + applyCorrAlg->setProperty("CorrectionsWorkspace", correctionsWsName.toStdString()); + } - pyInput += m_uiForm.ckScaleCan->isChecked() ? "True\n" : "False\n"; + // Generate output workspace name + int nameCutIndex = sampleWsName.lastIndexOf("_"); + if(nameCutIndex == -1) + nameCutIndex = sampleWsName.length(); - if ( m_uiForm.ckScaleCan->isChecked() ) + QString correctionType; + switch(m_uiForm.cbGeometry->currentIndex()) { - ScalingFactor = m_uiForm.spCanScale->text(); - ScaleOrNot = "True\n"; + case 0: + correctionType = "flt"; + break; + case 1: + correctionType = "cyl"; + break; } + const QString outputWsName = sampleWsName.left(nameCutIndex) + + "_" + correctionType + "_Corrected"; - pyInput += "scale = " + ScaleOrNot + "\n"; - pyInput += "scaleFactor = " + ScalingFactor + "\n"; + applyCorrAlg->setProperty("OutputWorkspace", outputWsName.toStdString()); - if ( m_uiForm.ckSave->isChecked() ) pyInput += "save = True\n"; - else pyInput += "save = False\n"; + // Add corrections algorithm to queue + m_sampleWsName = absCorProps["SampleWorkspace"]; + m_canWsName = absCorProps["CanWorkspace"]; + m_batchAlgoRunner->addAlgorithm(applyCorrAlg, absCorProps); - QString plotResult = m_uiForm.cbPlotOutput->currentText(); - if ( plotResult == "Contour" ) - { - plotResult = "Contour"; - } - else if ( plotResult == "Spectra" ) - { - plotResult = "Spectrum"; - } - else if ( plotResult == "Both" ) - { - plotResult = "Both"; - } + // Add save algorithms if required + bool save = m_uiForm.ckSave->isChecked(); + if(save) + addSaveWorkspaceToQueue(outputWsName); - pyInput += "plotResult = '" + plotResult + "'\n"; - pyInput += "print abscorFeeder(sample, container, geom, useCor, corrections, RebinCan=rebin_can, ScaleOrNotToScale=scale, factor=scaleFactor, Save=save, PlotResult=plotResult)\n"; + // Run algorithm queue + m_batchAlgoRunner->executeBatchAsync(); - QString pyOutput = runPythonCode(pyInput).trimmed(); + // Set the result workspace for Python script export + m_pythonExportWsName = outputWsName.toStdString(); + } - m_outputWs = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(pyOutput.toStdString()); - plotPreview(m_uiForm.spPreviewSpec->value()); - // Set the result workspace for Python script export - m_pythonExportWsName = pyOutput.toStdString(); + /** + * Adds a rebin to workspace step to the calculation for when using a sample and container that + * have different binning. + * + * @param toRebin + * @param toMatch + */ + void ApplyCorr::addRebinStep(QString toRebin, QString toMatch) + { + API::BatchAlgorithmRunner::AlgorithmRuntimeProps rebinProps; + rebinProps["WorkspaceToMatch"] = toMatch.toStdString(); + + IAlgorithm_sptr rebinAlg = AlgorithmManager::Instance().create("RebinToWorkspace"); + rebinAlg->initialize(); + + rebinAlg->setProperty("WorkspaceToRebin", toRebin.toStdString()); + rebinAlg->setProperty("OutputWorkspace", toRebin.toStdString()); + + m_batchAlgoRunner->addAlgorithm(rebinAlg, rebinProps); } + /** - * Ask the user is they wish to rebin the can to the sample. - * @return whether a rebin of the can workspace is required. + * Adds a spline interpolation as a step in the calculation for using legacy correction factor + * workspaces. + * + * @param toInterpolate Pointer to the workspace to interpolate + * @param toMatch Name of the workspace to match */ - bool ApplyCorr::requireCanRebin() + void ApplyCorr::addInterpolationStep(MatrixWorkspace_sptr toInterpolate, std::string toMatch) { - QString message = "The sample and can energy ranges do not match, this is not recommended." - "\n\n Click OK to rebin the can to match the sample and continue or Cancel to abort applying corrections."; - QMessageBox::StandardButton reply = QMessageBox::warning(m_parentWidget, "Energy Ranges Do Not Match", - message, QMessageBox::Ok|QMessageBox::Cancel); - return (reply == QMessageBox::Ok); + API::BatchAlgorithmRunner::AlgorithmRuntimeProps interpolationProps; + interpolationProps["WorkspaceToMatch"] = toMatch; + + IAlgorithm_sptr interpolationAlg = AlgorithmManager::Instance().create("SplineInterpolation"); + interpolationAlg->initialize(); + + interpolationAlg->setProperty("WorkspaceToInterpolate", toInterpolate->name()); + interpolationAlg->setProperty("OutputWorkspace", toInterpolate->name()); + + m_batchAlgoRunner->addAlgorithm(interpolationAlg, interpolationProps); + } + + + /** + * Handles completion of the algorithm. + * + * @param error True if algorithm failed. + */ + void ApplyCorr::algorithmComplete(bool error) + { + if(error) + { + emit showMessageBox("Unable to apply corrections.\nSee Results Log for more details."); + return; + } + + // Handle preview plot + plotPreview(m_uiForm.spPreviewSpec->value()); + + // Handle Mantid plotting + QString plotType = m_uiForm.cbPlotOutput->currentText(); + + if(plotType == "Spectra" || plotType == "Both") + plotSpectrum(QString::fromStdString(m_pythonExportWsName)); + + if(plotType == "Contour" || plotType == "Both") + plotContour(QString::fromStdString(m_pythonExportWsName)); } + bool ApplyCorr::validate() { + UserInputValidator uiv; + + uiv.checkDataSelectorIsValid("Sample", m_uiForm.dsSample); + + MatrixWorkspace_sptr sampleWs; + bool useCan = m_uiForm.ckUseCan->isChecked(); + bool useCorrections = m_uiForm.ckUseCorrections->isChecked(); + + if(!(useCan || useCorrections)) + uiv.addErrorMessage("Must use either container subtraction or corrections"); if(useCan) { + uiv.checkDataSelectorIsValid("Container", m_uiForm.dsContainer); + + // Check can and sample workspaces are the same "type" (reduced or S(Q, w)) QString sample = m_uiForm.dsSample->getCurrentDataName(); QString sampleType = sample.right(sample.length() - sample.lastIndexOf("_")); QString container = m_uiForm.dsContainer->getCurrentDataName(); QString containerType = container.right(container.length() - container.lastIndexOf("_")); g_log.debug() << "Sample type is: " << sampleType.toStdString() << std::endl; - g_log.debug() << "Container type is: " << containerType.toStdString() << std::endl; + g_log.debug() << "Can type is: " << containerType.toStdString() << std::endl; if(containerType != sampleType) + uiv.addErrorMessage("Sample and can workspaces must contain the same type of data."); + } + + if(useCorrections) + { + uiv.checkDataSelectorIsValid("Corrections", m_uiForm.dsCorrections); + + QString correctionsWsName = m_uiForm.dsCorrections->getCurrentDataName(); + WorkspaceGroup_sptr corrections = AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>(correctionsWsName.toStdString()); + for(size_t i = 0; i < corrections->size(); i++) { - g_log.error("Must use the same type of files for sample and container inputs."); - return false; + // Check it is a MatrixWorkspace + MatrixWorkspace_sptr factorWs = boost::dynamic_pointer_cast<MatrixWorkspace>(corrections->getItem(i)); + if(!factorWs) + { + QString msg = "Correction factor workspace " + + QString::number(i) + + " is not a MatrixWorkspace"; + uiv.addErrorMessage(msg); + continue; + } + + // Check X unit is wavelength + Mantid::Kernel::Unit_sptr xUnit = factorWs->getAxis(0)->unit(); + if(xUnit->caption() != "Wavelength") + { + QString msg = "Correction factor workspace " + + QString::fromStdString(factorWs->name()) + + " is not in wavelength"; + uiv.addErrorMessage(msg); + } } } - return true; + // Show errors if there are any + if(!uiv.isAllInputValid()) + emit showMessageBox(uiv.generateErrorMessage()); + + return uiv.isAllInputValid(); } + void ApplyCorr::loadSettings(const QSettings & settings) { m_uiForm.dsCorrections->readSettings(settings.group()); @@ -204,6 +356,7 @@ namespace IDA m_uiForm.dsSample->readSettings(settings.group()); } + /** * Handles when the type of geometry changes * @@ -229,6 +382,7 @@ namespace IDA } } + /** * Replots the preview plot. * @@ -241,25 +395,19 @@ namespace IDA m_uiForm.ppPreview->clear(); // Plot sample - const QString sample = m_uiForm.dsSample->getCurrentDataName(); - if(AnalysisDataService::Instance().doesExist(sample.toStdString())) - { - m_uiForm.ppPreview->addSpectrum("Sample", sample, specIndex, Qt::black); - } + if(AnalysisDataService::Instance().doesExist(m_sampleWsName)) + m_uiForm.ppPreview->addSpectrum("Sample", QString::fromStdString(m_sampleWsName), + specIndex, Qt::black); // Plot result - if(m_outputWs) - { - m_uiForm.ppPreview->addSpectrum("Corrected", m_outputWs, specIndex, Qt::green); - } + if(!m_pythonExportWsName.empty()) + m_uiForm.ppPreview->addSpectrum("Corrected", QString::fromStdString(m_pythonExportWsName), + specIndex, Qt::green); // Plot can - if(useCan) - { - QString container = m_uiForm.dsContainer->getCurrentDataName(); - const MatrixWorkspace_sptr canWs = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(container.toStdString()); - m_uiForm.ppPreview->addSpectrum("Can", canWs, specIndex, Qt::red); - } + if(useCan && AnalysisDataService::Instance().doesExist(m_canWsName)) + m_uiForm.ppPreview->addSpectrum("Can", QString::fromStdString(m_canWsName), + specIndex, Qt::red); } } // namespace IDA diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/Indirect/CalcCorr.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/Indirect/CalcCorr.cpp index 2f19360e2dff1c784596a81c776ef7d29e670985..8e42432f024c3da5660c3cfe8b55d071367764f0 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/src/Indirect/CalcCorr.cpp +++ b/Code/Mantid/MantidQt/CustomInterfaces/src/Indirect/CalcCorr.cpp @@ -3,86 +3,13 @@ #include "MantidQtCustomInterfaces/UserInputValidator.h" #include "MantidQtMantidWidgets/WorkspaceSelector.h" - #include <QLineEdit> #include <QList> #include <QValidator> #include <QDoubleValidator> #include <QRegExpValidator> -class QDoubleMultiRangeValidator : public QValidator -{ -public: - /** - * Constructor. - * - * @param ranges :: a set of pairs of doubles representing the valid ranges of the input - * @param parent :: the parent QObject of this QObject. - */ - QDoubleMultiRangeValidator(std::set<std::pair<double, double>> ranges, QObject * parent) : - QValidator(parent), m_ranges(ranges), m_slaveVal(NULL) - { - m_slaveVal = new QDoubleValidator(this); - } - - ~QDoubleMultiRangeValidator() {} - - /** - * Reimplemented from QValidator::validate(). - * - * Returns Acceptable if the string input contains a double that is within at least one - * of the ranges and is in the correct format. - * - * Else returns Intermediate if input contains a double that is outside the ranges or is in - * the wrong format; e.g. with too many digits after the decimal point or is empty. - * - * Else returns Invalid - i.e. the input is not a double. - * - * @param input :: the input string to validate - * @param pos :: not used. - */ - virtual QValidator::State validate( QString & input, int & pos ) const - { - UNUSED_ARG(pos); - - if( m_ranges.empty() ) - return Intermediate; - - bool acceptable = false; - bool intermediate = false; - - // For each range in the list, use the slave QDoubleValidator to find out the state. - for( auto range = m_ranges.begin(); range != m_ranges.end(); ++ range ) - { - if(range->first >= range->second) - throw std::runtime_error("Invalid range"); - - m_slaveVal->setBottom(range->first); - m_slaveVal->setTop(range->second); - - QValidator::State rangeState = m_slaveVal->validate(input, pos); - - if( rangeState == Acceptable ) - acceptable = true; - else if( rangeState == Intermediate ) - intermediate = true; - } - - if( acceptable ) - return Acceptable; - if( intermediate ) - return Intermediate; - - return Invalid; - } - -private: - /// Disallow default constructor. - QDoubleMultiRangeValidator(); - - std::set<std::pair<double, double>> m_ranges; - QDoubleValidator * m_slaveVal; -}; +using namespace Mantid::API; namespace { @@ -96,419 +23,296 @@ namespace CustomInterfaces namespace IDA { CalcCorr::CalcCorr(QWidget * parent) : - IDATab(parent), m_dblVal(NULL), m_posDblVal(NULL) + IDATab(parent) { m_uiForm.setupUi(parent); - m_dblVal = new QDoubleValidator(this); - m_posDblVal = new QDoubleValidator(this); - m_posDblVal->setBottom(0.0); + connect(m_uiForm.dsSample, SIGNAL(dataReady(const QString&)), this, SLOT(getBeamWidthFromWorkspace(const QString&))); + connect(m_batchAlgoRunner, SIGNAL(batchComplete(bool)), this, SLOT(algorithmComplete(bool))); + + QRegExp regex("[A-Za-z0-9\\-\\(\\)]*"); + QValidator *formulaValidator = new QRegExpValidator(regex, this); + m_uiForm.leSampleChemicalFormula->setValidator(formulaValidator); + m_uiForm.leCanChemicalFormula->setValidator(formulaValidator); } + void CalcCorr::setup() { - // set signals and slot connections for F2Py Absorption routine - connect(m_uiForm.cbShape, SIGNAL(currentIndexChanged(int)), this, SLOT(shape(int))); - connect(m_uiForm.ckUseCan, SIGNAL(toggled(bool)), this, SLOT(useCanChecked(bool))); - connect(m_uiForm.letc1, SIGNAL(editingFinished()), this, SLOT(tcSync())); - connect(m_uiForm.dsSampleInput, SIGNAL(dataReady(const QString&)), this, SLOT(getBeamWidthFromWorkspace(const QString&))); - - // Sort the fields into various lists. - - QList<QLineEdit*> allFields; - QList<QLineEdit*> doubleFields; - QList<QLineEdit*> positiveDoubleFields; - - positiveDoubleFields += m_uiForm.lets; // Thickness - positiveDoubleFields += m_uiForm.letc1; // Front Thickness - positiveDoubleFields += m_uiForm.letc2; // Back Thickness + doValidation(true); + } - positiveDoubleFields += m_uiForm.ler1; // Radius 1 - positiveDoubleFields += m_uiForm.ler2; // Radius 2 - positiveDoubleFields += m_uiForm.ler3; // Radius 3 - positiveDoubleFields += m_uiForm.lewidth; // Beam Width + void CalcCorr::run() + { + // Get correct corrections algorithm + QString sampleShape = m_uiForm.cbSampleShape->currentText(); + QString algorithmName = sampleShape.replace(" ", "") + "PaalmanPingsCorrection"; - positiveDoubleFields += m_uiForm.lesamden; // Sample Number Density - positiveDoubleFields += m_uiForm.lesamsigs; // Sample Scattering Cross-Section - positiveDoubleFields += m_uiForm.lesamsiga; // Sample Absorption Cross-Section + API::BatchAlgorithmRunner::AlgorithmRuntimeProps absCorProps; + IAlgorithm_sptr absCorAlgo = AlgorithmManager::Instance().create(algorithmName.toStdString()); + absCorAlgo->initialize(); - positiveDoubleFields += m_uiForm.lecanden; // Can Number Density - positiveDoubleFields += m_uiForm.lecansigs; // Can Scattering Cross-Section - positiveDoubleFields += m_uiForm.lecansiga; // Can Absorption Cross-Section + // Sample details + QString sampleWsName = m_uiForm.dsSample->getCurrentDataName(); + MatrixWorkspace_sptr sampleWs = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(sampleWsName.toStdString()); - // Set appropriate validators. - foreach(QLineEdit * positiveDoubleField, positiveDoubleFields) + // If not in wavelength then do conversion + Mantid::Kernel::Unit_sptr sampleXUnit = sampleWs->getAxis(0)->unit(); + if(sampleXUnit->caption() != "Wavelength") { - positiveDoubleField->setValidator(m_posDblVal); + g_log.information("Sample workspace not in wavelength, need to convert to continue."); + absCorProps["SampleWorkspace"] = addConvertToWavelengthStep(sampleWs); + } + else + { + absCorProps["SampleWorkspace"] = sampleWsName.toStdString(); } - // Deal with the slightly more complex multi-range "Can Angle to Beam" field. - std::set<std::pair<double, double>> angleRanges; - angleRanges.insert(std::make_pair(-180, -100)); - angleRanges.insert(std::make_pair(-80, 80)); - angleRanges.insert(std::make_pair(100, 180)); - QDoubleMultiRangeValidator * angleValidator = new QDoubleMultiRangeValidator(angleRanges, this); - m_uiForm.leavar->setValidator(angleValidator); // Can Angle to Beam - - allFields = positiveDoubleFields; - allFields += m_uiForm.leavar; - - QRegExp regex("[A-Za-z0-9\\-\\(\\)]*"); - QValidator *formulaValidator = new QRegExpValidator(regex, this); - m_uiForm.leSampleFormula->setValidator(formulaValidator); - m_uiForm.leCanFormula->setValidator(formulaValidator); - - // "Nudge" color of title of QGroupBox to change. - useCanChecked(m_uiForm.ckUseCan->isChecked()); - } + double sampleNumberDensity = m_uiForm.spSampleNumberDensity->value(); + absCorAlgo->setProperty("SampleNumberDensity", sampleNumberDensity); - void CalcCorr::run() - { - QString pyInput = "import IndirectAbsCor\n"; + QString sampleChemicalFormula = m_uiForm.leSampleChemicalFormula->text(); + absCorAlgo->setProperty("SampleChemicalFormula", sampleChemicalFormula.toStdString()); - QString geom; - QString size; + addShapeSpecificSampleOptions(absCorAlgo, sampleShape); - if ( m_uiForm.cbShape->currentText() == "Flat" ) - { - geom = "flt"; - if ( m_uiForm.ckUseCan->isChecked() ) - { - size = "[" + m_uiForm.lets->text() + ", " + - m_uiForm.letc1->text() + ", " + - m_uiForm.letc2->text() + "]"; - } - else - { - size = "[" + m_uiForm.lets->text() + ", 0.0, 0.0]"; - } - } - else if ( m_uiForm.cbShape->currentText() == "Cylinder" ) + // Can details + bool useCan = m_uiForm.ckUseCan->isChecked(); + if(useCan) { - geom = "cyl"; + QString canWsName = m_uiForm.dsContainer->getCurrentDataName(); + MatrixWorkspace_sptr canWs = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(canWsName.toStdString()); - // R3 only populated when using can. R4 is fixed to 0.0 - if ( m_uiForm.ckUseCan->isChecked() ) + // If not in wavelength then do conversion + Mantid::Kernel::Unit_sptr canXUnit = canWs->getAxis(0)->unit(); + if(canXUnit->caption() != "Wavelength") { - size = "[" + m_uiForm.ler1->text() + ", " + - m_uiForm.ler2->text() + ", " + - m_uiForm.ler3->text() + ", 0.0 ]"; + g_log.information("Container workspace not in wavelength, need to convert to continue."); + absCorProps["CanWorkspace"] = addConvertToWavelengthStep(canWs); } else { - size = "[" + m_uiForm.ler1->text() + ", " + - m_uiForm.ler2->text() + ", 0.0, 0.0 ]"; + absCorProps["CanWorkspace"] = canWsName.toStdString(); } - } - - //get beam width - QString width = m_uiForm.lewidth->text(); - if (width.isEmpty()) { width = "None"; } - //get sample workspace. Load from if needed. - QString sampleWs = m_uiForm.dsSampleInput->getCurrentDataName(); - pyInput += "inputws = '" + sampleWs + "'\n"; + double canNumberDensity = m_uiForm.spCanNumberDensity->value(); + absCorAlgo->setProperty("CanNumberDensity", canNumberDensity); - //sample absorption and scattering x sections. - QString sampleScatteringXSec = m_uiForm.lesamsigs->text(); - QString sampleAbsorptionXSec = m_uiForm.lesamsiga->text(); + QString canChemicalFormula = m_uiForm.leCanChemicalFormula->text(); + absCorAlgo->setProperty("CanChemicalFormula", canChemicalFormula.toStdString()); - if ( sampleScatteringXSec.isEmpty() ) { sampleScatteringXSec = "0.0"; } - if ( sampleAbsorptionXSec.isEmpty() ) { sampleAbsorptionXSec = "0.0"; } + addShapeSpecificCanOptions(absCorAlgo, sampleShape); + } - //can and sample formulas - QString sampleFormula = m_uiForm.leSampleFormula->text(); - QString canFormula = m_uiForm.leCanFormula->text(); + std::string eMode = getEMode(sampleWs); + absCorAlgo->setProperty("EMode", eMode); + if(eMode == "Indirect") + absCorAlgo->setProperty("EFixed", getEFixed(sampleWs)); - if ( sampleFormula.isEmpty() ) - { - sampleFormula = "None"; - } - else - { - sampleFormula = "'" + sampleFormula + "'"; - } + // Generate workspace names + int nameCutIndex = sampleWsName.lastIndexOf("_"); + if(nameCutIndex == -1) + nameCutIndex = sampleWsName.length(); - if ( canFormula.isEmpty() ) - { - canFormula = "None"; - } - else + QString correctionType; + switch(m_uiForm.cbSampleShape->currentIndex()) { - canFormula = "'" + canFormula + "'"; + case 0: + correctionType = "flt"; + break; + case 1: + correctionType = "cyl"; + break; } - //create python string to execute - if ( m_uiForm.ckUseCan->isChecked() ) - { - //get sample workspace. Load from if needed. - QString canWs = m_uiForm.dsCanInput->getCurrentDataName(); - pyInput += "canws = '" + canWs + "'\n"; - - //can absoprtion and scattering x section. - QString canScatteringXSec = m_uiForm.lecansigs->text(); - QString canAbsorptionXSec = m_uiForm.lecansiga->text(); - - if ( canScatteringXSec.isEmpty() ) { canScatteringXSec = "0.0"; } - if ( canAbsorptionXSec.isEmpty() ) { canAbsorptionXSec = "0.0"; } - - pyInput += - "ncan = 2\n" - "density = [" + m_uiForm.lesamden->text() + ", " + m_uiForm.lecanden->text() + ", " + m_uiForm.lecanden->text() + "]\n" - "sigs = [" + sampleScatteringXSec + "," + canScatteringXSec + "," + canScatteringXSec + "]\n" - "siga = [" + sampleAbsorptionXSec + "," + canAbsorptionXSec + "," + canAbsorptionXSec + "]\n"; - } - else - { - pyInput += - "ncan = 1\n" - "density = [" + m_uiForm.lesamden->text() + ", 0.0, 0.0 ]\n" - "sigs = [" + sampleScatteringXSec + ", 0.0, 0.0]\n" - "siga = [" + sampleAbsorptionXSec + ", 0.0, 0.0]\n" - "canws = None\n"; - } + const QString outputWsName = sampleWsName.left(nameCutIndex) + "_" + correctionType + "_abs"; + absCorAlgo->setProperty("OutputWorkspace", outputWsName.toStdString()); - //Output options - if ( m_uiForm.ckSave->isChecked() ) pyInput += "save = True\n"; - else pyInput += "save = False\n"; + // Add corrections algorithm to queue + m_batchAlgoRunner->addAlgorithm(absCorAlgo, absCorProps); - pyInput += - "geom = '" + geom + "'\n" - "beam = " + width + "\n" - "size = " + size + "\n" - "avar = " + m_uiForm.leavar->text() + "\n" - "plotOpt = '" + m_uiForm.cbPlotOutput->currentText() + "'\n" - "sampleFormula = " + sampleFormula + "\n" - "canFormula = " + canFormula + "\n" - "print IndirectAbsCor.AbsRunFeeder(inputws, canws, geom, ncan, size, avar, density, beam, sampleFormula, canFormula, sigs, siga, plot_opt=plotOpt, save=save)\n"; + // Add save algorithms if required + bool save = m_uiForm.ckSave->isChecked(); + if(save) + addSaveWorkspaceToQueue(outputWsName); - QString pyOutput = runPythonCode(pyInput); + // Run algorithm queue + m_batchAlgoRunner->executeBatchAsync(); // Set the result workspace for Python script export - m_pythonExportWsName = pyOutput.trimmed().toStdString(); + m_pythonExportWsName = outputWsName.toStdString(); } + bool CalcCorr::validate() + { + return doValidation(); + } + + + /** + * Does validation on the user input. + * + * @param silent Set to true to avoid creating an error message + * @return True if all user input is valid + */ + bool CalcCorr::doValidation(bool silent) { UserInputValidator uiv; - bool useCan = m_uiForm.ckUseCan->isChecked(); - // Input files/workspaces - uiv.checkDataSelectorIsValid("Sample", m_uiForm.dsSampleInput); - if (useCan) + uiv.checkDataSelectorIsValid("Sample", m_uiForm.dsSample); + + // Validate chemical formula + if(uiv.checkFieldIsNotEmpty("Sample Chemical Formula", m_uiForm.leSampleChemicalFormula, m_uiForm.valSampleChemicalFormula)) + uiv.checkFieldIsValid("Sample Chemical Formula", m_uiForm.leSampleChemicalFormula, m_uiForm.valSampleChemicalFormula); + + bool useCan = m_uiForm.ckUseCan->isChecked(); + if(useCan) { - uiv.checkDataSelectorIsValid("Can", m_uiForm.dsCanInput); + uiv.checkDataSelectorIsValid("Can", m_uiForm.dsContainer); - QString sample = m_uiForm.dsSampleInput->getCurrentDataName(); - QString sampleType = sample.right(sample.length() - sample.lastIndexOf("_")); - QString container = m_uiForm.dsCanInput->getCurrentDataName(); - QString containerType = container.right(container.length() - container.lastIndexOf("_")); + // Validate chemical formula + if(uiv.checkFieldIsNotEmpty("Can Chemical Formula", m_uiForm.leCanChemicalFormula, m_uiForm.valCanChemicalFormula)) + uiv.checkFieldIsValid("Can Chemical Formula", m_uiForm.leCanChemicalFormula, m_uiForm.valCanChemicalFormula); + + // Ensure sample and container are the same kind of data + QString sampleWsName = m_uiForm.dsSample->getCurrentDataName(); + QString sampleType = sampleWsName.right(sampleWsName.length() - sampleWsName.lastIndexOf("_")); + QString containerWsName = m_uiForm.dsContainer->getCurrentDataName(); + QString containerType = containerWsName.right(containerWsName.length() - containerWsName.lastIndexOf("_")); g_log.debug() << "Sample type is: " << sampleType.toStdString() << std::endl; g_log.debug() << "Can type is: " << containerType.toStdString() << std::endl; if(containerType != sampleType) - { uiv.addErrorMessage("Sample and can workspaces must contain the same type of data."); - } } - uiv.checkFieldIsValid("Beam Width", m_uiForm.lewidth, m_uiForm.valWidth); - - if ( m_uiForm.cbShape->currentText() == "Flat" ) - { - // Flat Geometry - uiv.checkFieldIsValid("Thickness", m_uiForm.lets, m_uiForm.valts); + // Show error mssage if needed + if(!uiv.isAllInputValid() && !silent) + emit showMessageBox(uiv.generateErrorMessage()); - if ( useCan ) - { - uiv.checkFieldIsValid("Front Thickness", m_uiForm.letc1, m_uiForm.valtc1); - uiv.checkFieldIsValid("Back Thickness", m_uiForm.letc2, m_uiForm.valtc2); - } + return uiv.isAllInputValid(); + } - uiv.checkFieldIsValid("Can Angle to Beam must be in the range [-180 to -100], [-80 to 80] or [100 to 180].", m_uiForm.leavar, m_uiForm.valAvar); - } - if ( m_uiForm.cbShape->currentText() == "Cylinder" ) + /** + * Handles completion of the correction algorithm. + * + * @param error True of the algorithm failed + */ + void CalcCorr::algorithmComplete(bool error) + { + if(error) { - // Cylinder geometry - uiv.checkFieldIsValid("Radius 1", m_uiForm.ler1, m_uiForm.valR1); - uiv.checkFieldIsValid("Radius 2", m_uiForm.ler2, m_uiForm.valR2); - - double radius1 = m_uiForm.ler1->text().toDouble(); - double radius2 = m_uiForm.ler2->text().toDouble(); - if( radius1 >= radius2 ) - uiv.addErrorMessage("Radius 1 should be less than Radius 2."); - - // R3 only relevant when using can - if ( useCan ) - { - uiv.checkFieldIsValid("Radius 3", m_uiForm.ler3, m_uiForm.valR3); + emit showMessageBox("Absorption correction calculation failed.\nSee Results Log for more details."); + return; + } - double radius3 = m_uiForm.ler3->text().toDouble(); - if( radius2 >= radius3 ) - uiv.addErrorMessage("Radius 2 should be less than Radius 3."); + // Handle Mantid plotting + bool plot = m_uiForm.ckPlotOutput->isChecked(); + if(plot) + plotSpectrum(QString::fromStdString(m_pythonExportWsName)); + } - } - uiv.checkFieldIsValid("Step Size", m_uiForm.leavar, m_uiForm.valAvar); + void CalcCorr::loadSettings(const QSettings & settings) + { + m_uiForm.dsSample->readSettings(settings.group()); + m_uiForm.dsContainer->readSettings(settings.group()); + } - double stepSize = m_uiForm.leavar->text().toDouble(); - if( stepSize >= (radius2 - radius1) ) - uiv.addErrorMessage("Step size should be less than (Radius 2 - Radius 1)."); - } - // Sample details - uiv.checkFieldIsValid("Sample Number Density", m_uiForm.lesamden, m_uiForm.valSamden); + /** + * Gets the beam width from the instrument parameters on a given workspace + * and update the relevant options on the UI. + * + * @param wsName Name of the workspace + */ + void CalcCorr::getBeamWidthFromWorkspace(const QString& wsName) + { + auto ws = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(wsName.toStdString()); - switch(m_uiForm.cbSampleInputType->currentIndex()) + if(!ws) { - case 0: - //input using formula - uiv.checkFieldIsValid("Sample Formula", m_uiForm.leSampleFormula, m_uiForm.valSampleFormula); - break; - case 1: - //using direct input - uiv.checkFieldIsValid("Sample Scattering Cross-Section", m_uiForm.lesamsigs, m_uiForm.valSamsigs); - uiv.checkFieldIsValid("Sample Absorption Cross-Section", m_uiForm.lesamsiga, m_uiForm.valSamsiga); - break; + g_log.warning() << "Failed to find workspace " << wsName.toStdString() << std::endl; + return; } + std::string paramName = "Workflow.beam-width"; + auto instrument = ws->getInstrument(); - // Can details (only test if "Use Can" is checked) - if ( m_uiForm.ckUseCan->isChecked() ) + if(instrument->hasParameter(paramName)) { - QString canFile = m_uiForm.dsCanInput->getCurrentDataName(); - if(canFile.isEmpty()) - { - uiv.addErrorMessage("You must select a Sample file or workspace."); - } - - uiv.checkFieldIsValid("Can Number Density",m_uiForm.lecanden,m_uiForm.valCanden); - - switch(m_uiForm.cbCanInputType->currentIndex()) - { - case 0: - //input using formula - uiv.checkFieldIsValid("Can Formula", m_uiForm.leCanFormula, m_uiForm.valCanFormula); - break; - case 1: - // using direct input - uiv.checkFieldIsValid("Can Scattering Cross-Section", m_uiForm.lecansigs, m_uiForm.valCansigs); - uiv.checkFieldIsValid("Can Absorption Cross-Section", m_uiForm.lecansiga, m_uiForm.valCansiga); - break; - } + QString beamWidth = QString::fromStdString(instrument->getStringParameter(paramName)[0]); + double beamWidthValue = beamWidth.toDouble(); + m_uiForm.spCylBeamWidth->setValue(beamWidthValue); + m_uiForm.spCylBeamHeight->setValue(beamWidthValue); } - - QString error = uiv.generateErrorMessage(); - showMessageBox(error); - - return error.isEmpty(); } - void CalcCorr::loadSettings(const QSettings & settings) - { - m_uiForm.dsSampleInput->readSettings(settings.group()); - m_uiForm.dsCanInput->readSettings(settings.group()); - } - void CalcCorr::shape(int index) - { - m_uiForm.swShapeDetails->setCurrentIndex(index); - // Meaning of the "avar" variable changes depending on shape selection - if ( index == 0 ) { m_uiForm.lbAvar->setText("Sample Angle:"); } - else if ( index == 1 ) { m_uiForm.lbAvar->setText("Step Size:"); } - } - - void CalcCorr::useCanChecked(bool checked) + /** + * Sets algorithm properties specific to the sample for a given shape. + * + * @param alg Algorithm to set properties of + * @param shape Sample shape + */ + void CalcCorr::addShapeSpecificSampleOptions(IAlgorithm_sptr alg, QString shape) { - - // Disable "Can Details" group and asterisks. - m_uiForm.gbCan->setEnabled(checked); - m_uiForm.valCanden->setVisible(checked); - m_uiForm.lbtc1->setEnabled(checked); - m_uiForm.lbtc2->setEnabled(checked); - m_uiForm.letc1->setEnabled(checked); - m_uiForm.letc2->setEnabled(checked); - m_uiForm.lbR3->setEnabled(checked); - m_uiForm.ler3->setEnabled(checked); - - QString value; - (checked ? value = "*" : value = " "); - - m_uiForm.valCansigs->setText(value); - m_uiForm.valCansiga->setText(value); - m_uiForm.valCanFormula->setText(value); - - // Disable thickness fields/labels/asterisks. - m_uiForm.valtc1->setText(value); - m_uiForm.valtc2->setText(value); - - // // Disable R3 field/label/asterisk. - m_uiForm.valR3->setText(value); - - if (checked) + if(shape == "FlatPlate") { - UserInputValidator uiv; - uiv.checkFieldIsValid("",m_uiForm.lecansigs, m_uiForm.valCansigs); - uiv.checkFieldIsValid("",m_uiForm.lecansiga, m_uiForm.valCansiga); - uiv.checkFieldIsValid("",m_uiForm.letc1, m_uiForm.valtc1); - uiv.checkFieldIsValid("",m_uiForm.letc2, m_uiForm.valtc2); - uiv.checkFieldIsValid("",m_uiForm.ler3, m_uiForm.valR3); + double sampleThickness = m_uiForm.spFlatSampleThickness->value(); + alg->setProperty("SampleThickness", sampleThickness); + + double sampleAngle = m_uiForm.spFlatSampleAngle->value(); + alg->setProperty("SampleAngle", sampleAngle); } + else if(shape == "Cylinder") + { + double sampleInnerRadius = m_uiForm.spCylSampleInnerRadius->value(); + alg->setProperty("SampleInnerRadius", sampleInnerRadius); - m_uiForm.dsCanInput->setEnabled(checked); + double sampleOuterRadius = m_uiForm.spCylSampleOuterRadius->value(); + alg->setProperty("SampleOuterRadius", sampleOuterRadius); - // Workaround for "disabling" title of the QGroupBox. - QPalette palette; - if(checked) - palette.setColor( - QPalette::Disabled, - QPalette::WindowText, - QApplication::palette().color(QPalette::Disabled, QPalette::WindowText)); - else - palette.setColor( - QPalette::Active, - QPalette::WindowText, - QApplication::palette().color(QPalette::Active, QPalette::WindowText)); + double beamWidth = m_uiForm.spCylBeamWidth->value(); + alg->setProperty("BeamWidth", beamWidth); - m_uiForm.gbCan->setPalette(palette); - } + double beamHeight = m_uiForm.spCylBeamHeight->value(); + alg->setProperty("BeamHeight", beamHeight); - void CalcCorr::tcSync() - { - if ( m_uiForm.letc2->text() == "" ) - { - QString val = m_uiForm.letc1->text(); - m_uiForm.letc2->setText(val); + double stepSize = m_uiForm.spCylStepSize->value(); + alg->setProperty("StepSize", stepSize); } } - void CalcCorr::getBeamWidthFromWorkspace(const QString& wsname) - { - using namespace Mantid::API; - auto ws = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(wsname.toStdString()); - if (!ws) + /** + * Sets algorithm properties specific to the container for a given shape. + * + * @param alg Algorithm to set properties of + * @param shape Sample shape + */ + void CalcCorr::addShapeSpecificCanOptions(IAlgorithm_sptr alg, QString shape) + { + if(shape == "FlatPlate") { - showMessageBox("Failed to find workspace " + wsname); - return; - } + double canFrontThickness = m_uiForm.spFlatCanFrontThickness->value(); + alg->setProperty("CanFrontThickness", canFrontThickness); - std::string paramName = "Workflow.beam-width"; - auto instrument = ws->getInstrument(); - if (instrument->hasParameter(paramName)) - { - std::string beamWidth = instrument->getStringParameter(paramName)[0]; - m_uiForm.lewidth->setText(QString::fromUtf8(beamWidth.c_str())); + double canBackThickness = m_uiForm.spFlatCanBackThickness->value(); + alg->setProperty("SampleThickness", canBackThickness); } - else + else if(shape == "Cylinder") { - m_uiForm.lewidth->setText(""); + double canOuterRadius = m_uiForm.spCylCanOuterRadius->value(); + alg->setProperty("CanOuterRadius", canOuterRadius); } - } + + } // namespace IDA } // namespace CustomInterfaces } // namespace MantidQt diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/Indirect/Fury.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/Indirect/Fury.cpp index 87c3b3416da06f74275c0db18fc57d6105fd32eb..d1f64dc1bcc2e7b197c66ee3d8896b230585af8f 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/src/Indirect/Fury.cpp +++ b/Code/Mantid/MantidQt/CustomInterfaces/src/Indirect/Fury.cpp @@ -89,20 +89,20 @@ namespace IDA double energyMin = m_dblManager->value(m_properties["ELow"]); double energyMax = m_dblManager->value(m_properties["EHigh"]); - long numBins = static_cast<long>(m_dblManager->value(m_properties["SampleBinning"])); + double numBins = m_dblManager->value(m_properties["SampleBinning"]); bool plot = m_uiForm.ckPlot->isChecked(); bool save = m_uiForm.ckSave->isChecked(); - IAlgorithm_sptr furyAlg = AlgorithmManager::Instance().create("Fury", -1); + IAlgorithm_sptr furyAlg = AlgorithmManager::Instance().create("TransformToIqt", -1); furyAlg->initialize(); - furyAlg->setProperty("Sample", wsName.toStdString()); - furyAlg->setProperty("Resolution", resName.toStdString()); + furyAlg->setProperty("SampleWorkspace", wsName.toStdString()); + furyAlg->setProperty("ResolutionWorkspace", resName.toStdString()); furyAlg->setProperty("EnergyMin", energyMin); furyAlg->setProperty("EnergyMax", energyMax); - furyAlg->setProperty("NumBins", numBins); + furyAlg->setProperty("BinReductionFactor", numBins); furyAlg->setProperty("Plot", plot); furyAlg->setProperty("Save", save); @@ -188,20 +188,20 @@ namespace IDA double energyMin = m_dblManager->value(m_properties["ELow"]); double energyMax = m_dblManager->value(m_properties["EHigh"]); - long numBins = static_cast<long>(m_dblManager->value(m_properties["SampleBinning"])); // Default value + double numBins = m_dblManager->value(m_properties["SampleBinning"]); if(numBins == 0) return; - IAlgorithm_sptr furyAlg = AlgorithmManager::Instance().create("Fury"); + IAlgorithm_sptr furyAlg = AlgorithmManager::Instance().create("TransformToIqt"); furyAlg->initialize(); - furyAlg->setProperty("Sample", wsName.toStdString()); - furyAlg->setProperty("Resolution", resName.toStdString()); + furyAlg->setProperty("SampleWorkspace", wsName.toStdString()); + furyAlg->setProperty("ResolutionWorkspace", resName.toStdString()); furyAlg->setProperty("ParameterWorkspace", "__FuryProperties_temp"); furyAlg->setProperty("EnergyMin", energyMin); furyAlg->setProperty("EnergyMax", energyMax); - furyAlg->setProperty("NumBins", numBins); + furyAlg->setProperty("BinReductionFactor", numBins); furyAlg->setProperty("Plot", false); furyAlg->setProperty("Save", false); diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/Indirect/IDATab.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/Indirect/IDATab.cpp index 0cabe7f5e333cc35de84aec9fd83e2a75b5615f8..4b394e01c0370771d4e95e458b66e96062477afa 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/src/Indirect/IDATab.cpp +++ b/Code/Mantid/MantidQt/CustomInterfaces/src/Indirect/IDATab.cpp @@ -32,6 +32,7 @@ namespace IDA m_blnEdFac = new QtCheckBoxFactory(this); } + /** * Loads the tab's settings. * @@ -44,6 +45,7 @@ namespace IDA loadSettings(settings); } + /** * Slot that can be called when a user edits an input. */ @@ -52,6 +54,7 @@ namespace IDA validate(); } + /** * Check that the binning between two workspaces matches. * @@ -74,6 +77,35 @@ namespace IDA } } + + /** + * Adds a unit converstion into wavelength step to the batch algorithm queue. + * + * @param ws Pointer to the workspace to convert + * @return Name of output workspace + */ + std::string IDATab::addConvertToWavelengthStep(MatrixWorkspace_sptr ws) + { + std::string outputName = ws->name() + "_inWavelength"; + + IAlgorithm_sptr convertAlg = AlgorithmManager::Instance().create("ConvertUnits"); + convertAlg->initialize(); + + convertAlg->setProperty("InputWorkspace", ws->name()); + convertAlg->setProperty("OutputWorkspace", outputName); + convertAlg->setProperty("Target", "Wavelength"); + + std::string eMode = getEMode(ws); + convertAlg->setProperty("EMode", eMode); + + if(eMode == "Indirect") + convertAlg->setProperty("EFixed", getEFixed(ws)); + + m_batchAlgoRunner->addAlgorithm(convertAlg); + + return outputName; + } + } // namespace IDA } // namespace CustomInterfaces } // namespace MantidQt diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/Indirect/IndirectDataReductionTab.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/Indirect/IndirectDataReductionTab.cpp index 87c0f817542f3db909188d93a28661f049851618..423cd02cae0214aa3325bfb9fcb5bb9de12a19f2 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/src/Indirect/IndirectDataReductionTab.cpp +++ b/Code/Mantid/MantidQt/CustomInterfaces/src/Indirect/IndirectDataReductionTab.cpp @@ -188,7 +188,7 @@ namespace CustomInterfaces loadParamAlg->execute(); energyWs = loadParamAlg->getProperty("Workspace"); - double efixed = energyWs->getInstrument()->getNumberParameter("efixed-val")[0]; + double efixed = getEFixed(energyWs); auto spectrum = energyWs->getSpectrum(0); spectrum->setSpectrumNo(3); diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/Indirect/IndirectTab.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/Indirect/IndirectTab.cpp index 2e35ed5775cab275e89d46d050334fe3a8412936..856a69723d9939f2eafcbf0c09d1b1f52cd89981 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/src/Indirect/IndirectTab.cpp +++ b/Code/Mantid/MantidQt/CustomInterfaces/src/Indirect/IndirectTab.cpp @@ -6,6 +6,8 @@ #include "MantidQtAPI/InterfaceManager.h" #include "MantidQtMantidWidgets/RangeSelector.h" +#include <boost/algorithm/string/find.hpp> + using namespace Mantid::API; using namespace Mantid::Geometry; using namespace Mantid::Kernel; @@ -44,6 +46,7 @@ namespace CustomInterfaces connect(&m_pythonRunner, SIGNAL(runAsPythonScript(const QString&, bool)), this, SIGNAL(runAsPythonScript(const QString&, bool))); } + //---------------------------------------------------------------------------------------------- /** Destructor */ @@ -51,6 +54,7 @@ namespace CustomInterfaces { } + void IndirectTab::runTab() { if(validate()) @@ -64,16 +68,19 @@ namespace CustomInterfaces } } + void IndirectTab::setupTab() { setup(); } + bool IndirectTab::validateTab() { return validate(); } + /** * Handles generating a Python script for the algorithms run on the current tab. */ @@ -114,6 +121,7 @@ namespace CustomInterfaces dlg->activateWindow(); } + /** * Run the load algorithm with the supplied filename and spectrum range * @@ -140,10 +148,97 @@ namespace CustomInterfaces load->execute(); - //If reloading fails we're out of options + // If reloading fails we're out of options return load->isExecuted(); } + + /** + * Configures the SaveNexusProcessed algorithm to save a workspace in the default + * save directory and adds the algorithm to the batch queue. + * + * This uses the plotSpectrum function from the Python API. + * + * @param wsName Name of workspace to save + * @param filename Name of file to save as (including extension) + */ + void IndirectTab::addSaveWorkspaceToQueue(const QString & wsName, const QString & filename) + { + // Setup the input workspace property + API::BatchAlgorithmRunner::AlgorithmRuntimeProps saveProps; + saveProps["InputWorkspace"] = wsName.toStdString(); + + // Setup the algorithm + IAlgorithm_sptr saveAlgo = AlgorithmManager::Instance().create("SaveNexusProcessed"); + saveAlgo->initialize(); + + if(filename.isEmpty()) + saveAlgo->setProperty("Filename", wsName.toStdString() + ".nxs"); + else + saveAlgo->setProperty("Filename", filename.toStdString()); + + // Add the save algorithm to the batch + m_batchAlgoRunner->addAlgorithm(saveAlgo, saveProps); + } + + + /** + * Creates a spectrum plot of one or more workspaces at a given spectrum + * index. + * + * This uses the plotSpectrum function from the Python API. + * + * @param workspaceNames List of names of workspaces to plot + * @param specIndex Index of spectrum from each workspace to plot + */ + void IndirectTab::plotSpectrum(const QStringList & workspaceNames, int specIndex) + { + QString pyInput = "from mantidplot import plotSpectrum\n"; + + pyInput += "plotSpectrum('"; + pyInput += workspaceNames.join("','"); + pyInput += "', "; + pyInput += QString::number(specIndex); + pyInput += ")\n"; + + m_pythonRunner.runPythonCode(pyInput); + } + + + /** + * Creates a spectrum plot of a single workspace at a given spectrum + * index. + * + * @param workspaceName Names of workspace to plot + * @param specIndex Index of spectrum to plot + */ + void IndirectTab::plotSpectrum(const QString & workspaceName, int specIndex) + { + QStringList workspaceNames; + workspaceNames << workspaceName; + plotSpectrum(workspaceNames, specIndex); + } + + + /** + * Plots a contour (2D) plot of a given workspace. + * + * This uses the plot2D function from the Python API. + * + * @param workspaceName Name of workspace to plot + */ + void IndirectTab::plotContour(const QString & workspaceName) + { + QString pyInput = "from mantidplot import plot2D\n"; + + pyInput += "plot2D('"; + pyInput += workspaceName; + pyInput += "')\n"; + + m_pythonRunner.runPythonCode(pyInput); + } + + /** * Sets the edge bounds of plot to prevent the user inputting invalid values * Also sets limits for range selector movement @@ -163,6 +258,7 @@ namespace CustomInterfaces rs->setRange(bounds.first, bounds.second); } + /** * Set the position of the range selectors on the mini plot * @@ -180,6 +276,49 @@ namespace CustomInterfaces rs->setMaximum(bounds.second); } + + /** + * Gets the energy mode from a workspace based on the X unit. + * + * Units of dSpacing typically denote diffraction, hence Elastic. + * All other units default to spectroscopy, therefore Indirect. + * + * @param ws Pointer to the workspace + * @return Energy mode + */ + std::string IndirectTab::getEMode(Mantid::API::MatrixWorkspace_sptr ws) + { + Mantid::Kernel::Unit_sptr xUnit = ws->getAxis(0)->unit(); + std::string xUnitName = xUnit->caption(); + + g_log.debug() << "X unit name is: " << xUnitName << std::endl; + + if(boost::algorithm::find_first(xUnitName, "d-Spacing")) + return "Elastic"; + + return "Indirect"; + } + + + /** + * Gets the eFixed value from the workspace using the instrument parameters. + * + * @param ws Pointer to the workspace + * @return eFixed value + */ + double IndirectTab::getEFixed(Mantid::API::MatrixWorkspace_sptr ws) + { + Mantid::Geometry::Instrument_const_sptr inst = ws->getInstrument(); + if(!inst) + throw std::runtime_error("No instrument on workspace"); + + if(!inst->hasParameter("efixed-val")) + throw std::runtime_error("Instrument has no efixed parameter"); + + return inst->getNumberParameter("efixed-val")[0]; + } + + /** * Runs an algorithm async * @@ -198,6 +337,7 @@ namespace CustomInterfaces m_batchAlgoRunner->executeBatchAsync(); } + /** * Handles getting the results of an algorithm running async * @@ -213,6 +353,7 @@ namespace CustomInterfaces } } + /** * Run Python code and return anything printed to stdout. * diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/MantidEV.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/MantidEV.cpp index 39964eda49a65ef0b605494dd47e165886e1ce11..5ac92097495116849472d24de678d91822f465b9 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/src/MantidEV.cpp +++ b/Code/Mantid/MantidQt/CustomInterfaces/src/MantidEV.cpp @@ -4,6 +4,7 @@ #include <QSettings> #include <QDesktopServices> #include <QDesktopWidget> +#include <Poco/Path.h> #include "MantidQtCustomInterfaces/MantidEV.h" #include "MantidAPI/AlgorithmManager.h" @@ -319,6 +320,12 @@ void MantidEV::initLayout() QObject::connect( m_uiForm.actionLoad_Isaw_Peaks, SIGNAL(triggered()), this, SLOT(loadIsawPeaks_slot()) ); + QObject::connect( m_uiForm.actionSave_Nexus_Peaks, SIGNAL(triggered()), + this, SLOT(saveNexusPeaks_slot()) ); + + QObject::connect( m_uiForm.actionLoad_Nexus_Peaks, SIGNAL(triggered()), + this, SLOT(loadNexusPeaks_slot()) ); + QObject::connect( m_uiForm.actionShow_UB, SIGNAL(triggered()), this, SLOT(showUB_slot()) ); @@ -765,15 +772,22 @@ void MantidEV::findPeaks_slot() else if ( load_peaks ) { std::string file_name = m_uiForm.SelectPeaksFile_ledt->text().trimmed().toStdString(); + std::string extension = Poco::Path(file_name).getExtension(); if ( file_name.length() == 0 ) { errorMessage("Specify a peaks file with the peaks to be loaded."); return; } - - if ( !worker->loadIsawPeaks( peaks_ws_name, file_name ) ) - { - errorMessage("Could not load requested peaks file"); + if (extension.compare("nxs") == 0 || extension.compare("h5") == 0){ + if ( !worker->loadNexusPeaks( peaks_ws_name, file_name ) ){ + errorMessage("Could not load requested peaks file"); + } + } + else { + if ( !worker->loadIsawPeaks( peaks_ws_name, file_name ) ) + { + errorMessage("Could not load requested NeXus file"); + } } } } @@ -788,7 +802,7 @@ void MantidEV::getLoadPeaksFileName_slot() QString Qfile_name = QFileDialog::getOpenFileName( this, tr("Load peaks file"), file_path, - tr("Peaks Files (*.peaks *.integrate);; All files(*.*)")); + tr("Peaks Files (*.peaks *.integrate *.nxs *.h5);; All files(*.*)")); if ( Qfile_name.length()> 0 ) { @@ -808,7 +822,7 @@ void MantidEV::getSavePeaksFileName() QString Qfile_name = QFileDialog::getSaveFileName( this, tr("Save peaks file"), file_path, - tr("Peaks Files (*.peaks *.integrate);; All files(*.*) "), + tr("Peaks Files (*.peaks *.integrate *.nxs *.h5);; All files(*.*)"), 0, QFileDialog::DontConfirmOverwrite ); if ( Qfile_name.length() > 0 ) @@ -1495,6 +1509,67 @@ void MantidEV::saveIsawPeaks_slot() } } +/** + * Slot called when the Save Nexus Peaks action is selected from the File menu. + */ +void MantidEV::saveNexusPeaks_slot() +{ + std::string peaks_ws_name = m_uiForm.PeaksWorkspace_ledt->text().trimmed().toStdString(); + if ( peaks_ws_name.length() == 0 ) + { + errorMessage("Specify a peaks workspace name on the Find Peaks tab."); + return; + } + + getSavePeaksFileName(); + + std::string file_name = m_uiForm.SelectPeaksFile_ledt->text().trimmed().toStdString(); + if ( file_name.length() == 0 ) + { + errorMessage("Specify a peaks file name for saving the peaks workspace."); + return; + } + else + { + // if the file exists, check for overwrite or append + bool append = false; + QFile peaks_file( QString::fromStdString( file_name ) ); + if ( peaks_file.exists() ) + { + QMessageBox message_box( this->window() ); + message_box.setText( tr("File Exists") ); + message_box.setInformativeText("Replace file, or append peaks to file?"); + QAbstractButton *replace_btn = message_box.addButton( tr("Replace"), QMessageBox::NoRole ); + QAbstractButton *append_btn = message_box.addButton( tr("Append"), QMessageBox::YesRole ); + message_box.setIcon( QMessageBox::Question ); + // it should not be necessary to do the next + // four lines, but without them the message box + // appears at random locations on RHEL 6 + message_box.show(); + QSize box_size = message_box.sizeHint(); + QRect screen_rect = QDesktopWidget().screen()->rect(); + message_box.move( QPoint( screen_rect.width()/2 - box_size.width()/2, + screen_rect.height()/2 - box_size.height()/2 ) ); + message_box.exec(); + + if ( message_box.clickedButton() == append_btn ) + { + append = true; + } + else if ( message_box.clickedButton() == replace_btn ) // no strictly needed, but clearer + { + append = false; + } + } + + if ( !worker->saveNexusPeaks( peaks_ws_name, file_name, append ) ) + { + errorMessage( "Failed to save peaks to file" ); + return; + } + } +} + /** * Slot called when the Load Isaw Peaks action is selected from the File menu. @@ -1526,6 +1601,36 @@ void MantidEV::loadIsawPeaks_slot() } } +/** + * Slot called when the Load Nexus Peaks action is selected from the File menu. + */ +void MantidEV::loadNexusPeaks_slot() +{ + std::string peaks_ws_name = m_uiForm.PeaksWorkspace_ledt->text().trimmed().toStdString(); + if ( peaks_ws_name.length() == 0 ) + { + errorMessage("Specify a peaks workspace name on the Find Peaks tab."); + return; + } + + getLoadPeaksFileName_slot(); + + std::string file_name = m_uiForm.SelectPeaksFile_ledt->text().trimmed().toStdString(); + if ( file_name.length() == 0 ) + { + errorMessage("Select a peaks file to be loaded."); + return; + } + else + { + if ( !worker->loadNexusPeaks( peaks_ws_name, file_name ) ) + { + errorMessage( "Failed to Load Peaks File" ); + return; + } + } +} + /** * Slot called when the Show UB action is selected from the View menu. diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/MantidEVWorker.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/MantidEVWorker.cpp index 0cba832b97f19448f1f25cf4cb021a12722ce7c8..6200f7641430ba30e3eef5835c6b14bfe9f1e36e 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/src/MantidEVWorker.cpp +++ b/Code/Mantid/MantidQt/CustomInterfaces/src/MantidEVWorker.cpp @@ -397,9 +397,31 @@ bool MantidEVWorker::loadIsawPeaks( const std::string & peaks_ws_name, return false; } +/** + * Load the specified peaks workspace from the specified NeXus file. + * + * @param peaks_ws_name The name of the peaks workspace to load/create. + * @param file_name The name of the NeXus file to load. + * + * @return true if LoadNexusPeaks completed successfully. + */ +bool MantidEVWorker::loadNexusPeaks( const std::string & peaks_ws_name, + const std::string & file_name ) +{ + + IAlgorithm_sptr alg = AlgorithmManager::Instance().create("Load"); + alg->setProperty("Filename",file_name ); + + alg->setProperty("OutputWorkspace", peaks_ws_name ); + + if ( alg->execute() ) + return true; + + return false; +} /** - * Load the specified peaks workspace to the specified peaks file. + * Save the specified peaks workspace to the specified peaks file. * * @param peaks_ws_name The name of the peaks workspace to save. * @param file_name The name of the peaks file to write to. @@ -425,6 +447,43 @@ bool MantidEVWorker::saveIsawPeaks( const std::string & peaks_ws_name, return false; } +/** + * Save the specified peaks workspace to the specified peaks file. + * + * @param peaks_ws_name The name of the peaks workspace to save. + * @param file_name The name of the NeXus file to write to. + * + * @return true if SaveNexusPeaks completed successfully. + */ +bool MantidEVWorker::saveNexusPeaks( const std::string & peaks_ws_name, + const std::string & file_name, + bool append ) +{ + if (append){ + std::string temp_peaks_ws_name = "__MantidEVWorker_peaks_ws"; + IAlgorithm_sptr load = AlgorithmManager::Instance().create("Load"); + load->setProperty("OutputWorkspace", temp_peaks_ws_name ); + load->setProperty("Filename",file_name ); + + load->execute(); + + IAlgorithm_sptr combine = AlgorithmManager::Instance().create("CombinePeaksWorkspaces"); + combine->setProperty("LHSWorkspace", temp_peaks_ws_name ); + combine->setProperty("RHSWorkspace", peaks_ws_name ); + combine->setProperty("OutputWorkspace", peaks_ws_name ); + + combine->execute(); + } + IAlgorithm_sptr alg = AlgorithmManager::Instance().create("SaveNexus"); + alg->setProperty("InputWorkspace", peaks_ws_name ); + alg->setProperty("Filename",file_name ); + + if ( alg->execute() ) + return true; + + return false; +} + /** * Find an optimized UB matrix that indexes the peaks in the specified diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/Muon/ALCDataLoadingPresenter.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/Muon/ALCDataLoadingPresenter.cpp index c92356a85561c25da2d4c5ff05080aa93feb9499..1e42a20b0d5a59e29a08c47d4a832bb993333f5f 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/src/Muon/ALCDataLoadingPresenter.cpp +++ b/Code/Mantid/MantidQt/CustomInterfaces/src/Muon/ALCDataLoadingPresenter.cpp @@ -137,6 +137,7 @@ namespace CustomInterfaces { m_view->setAvailableLogs(std::vector<std::string>()); // Empty logs list m_view->setAvailablePeriods(std::vector<std::string>()); // Empty period list + m_view->setTimeLimits(0,0); // "Empty" time limits return; } @@ -161,6 +162,11 @@ namespace CustomInterfaces periods.push_back(buffer.str()); } m_view->setAvailablePeriods(periods); + + // Set time limits + m_view->setTimeLimits(ws->readX(0).front(),ws->readX(0).back()); + // Set allowed time range + m_view->setTimeRange (ws->readX(0).front(),ws->readX(0).back()); } } // namespace CustomInterfaces diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/Muon/ALCDataLoadingView.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/Muon/ALCDataLoadingView.cpp index 1c10a0abf0a1548174d232962fa3657ca1e17339..6cea3759e0f926c01a1289b7d673dd3100963327 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/src/Muon/ALCDataLoadingView.cpp +++ b/Code/Mantid/MantidQt/CustomInterfaces/src/Muon/ALCDataLoadingView.cpp @@ -163,6 +163,23 @@ namespace CustomInterfaces } } + void ALCDataLoadingView::setTimeLimits(double tMin, double tMax) + { + // Set initial values + m_ui.minTime->setValue(tMin); + m_ui.maxTime->setValue(tMax); + } + + void ALCDataLoadingView::setTimeRange(double tMin, double tMax) + { + // Set range for minTime + m_ui.minTime->setMinimum(tMin); + m_ui.minTime->setMaximum(tMax); + // Set range for maxTime + m_ui.maxTime->setMinimum(tMin); + m_ui.maxTime->setMaximum(tMax); + } + void ALCDataLoadingView::help() { MantidQt::API::HelpWindow::showCustomInterface(NULL, QString("Muon_ALC")); diff --git a/Code/Mantid/MantidQt/CustomInterfaces/test/ALCDataLoadingPresenterTest.h b/Code/Mantid/MantidQt/CustomInterfaces/test/ALCDataLoadingPresenterTest.h index 850d5812542ee6b72f317f6c7674313399262a35..e61879312c74af0428c2825ca5acd6ba8308326c 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/test/ALCDataLoadingPresenterTest.h +++ b/Code/Mantid/MantidQt/CustomInterfaces/test/ALCDataLoadingPresenterTest.h @@ -48,6 +48,8 @@ public: MOCK_METHOD1(displayError, void(const std::string&)); MOCK_METHOD1(setAvailableLogs, void(const std::vector<std::string>&)); MOCK_METHOD1(setAvailablePeriods, void(const std::vector<std::string>&)); + MOCK_METHOD2(setTimeLimits, void(double,double)); + MOCK_METHOD2(setTimeRange, void(double,double)); MOCK_METHOD0(setWaitingCursor, void()); MOCK_METHOD0(restoreCursor, void()); MOCK_METHOD0(help, void()); diff --git a/Code/Mantid/Testing/Data/DocTest/PoldiCrystalFileExample.dat.md5 b/Code/Mantid/Testing/Data/DocTest/PoldiCrystalFileExample.dat.md5 new file mode 100644 index 0000000000000000000000000000000000000000..fb77808522c795bde838bad1aba33b5ddb7f8afb --- /dev/null +++ b/Code/Mantid/Testing/Data/DocTest/PoldiCrystalFileExample.dat.md5 @@ -0,0 +1 @@ +0a93f7213e39cf02f7cb7ddb27f4d6f9 diff --git a/Code/Mantid/Testing/Data/UnitTest/dn134011vana.d_dat.md5 b/Code/Mantid/Testing/Data/UnitTest/dn134011vana.d_dat.md5 new file mode 100644 index 0000000000000000000000000000000000000000..e99469630d6e0dcdb7a224f83817cb20eb2d2a24 --- /dev/null +++ b/Code/Mantid/Testing/Data/UnitTest/dn134011vana.d_dat.md5 @@ -0,0 +1 @@ +28151e3198f9f57b18b97d87627eadf6 diff --git a/Code/Mantid/Testing/Data/UnitTest/irs26173_graphite002_res.nxs.md5 b/Code/Mantid/Testing/Data/UnitTest/irs26173_graphite002_res.nxs.md5 new file mode 100644 index 0000000000000000000000000000000000000000..f8094ffb61e4994fb5350f25c238d1d2730c85b6 --- /dev/null +++ b/Code/Mantid/Testing/Data/UnitTest/irs26173_graphite002_res.nxs.md5 @@ -0,0 +1 @@ +4a322a634e527c87fbef27f1cc9559d2 \ No newline at end of file diff --git a/Code/Mantid/Testing/SystemTests/tests/analysis/ISISDirectReductionComponents.py b/Code/Mantid/Testing/SystemTests/tests/analysis/ISISDirectReductionComponents.py index a7677cb70662eaf5ea25d44a2ce71d15b1064a23..1e556601d2e32ba363d7564ffeecaf87e2a3c8a8 100644 --- a/Code/Mantid/Testing/SystemTests/tests/analysis/ISISDirectReductionComponents.py +++ b/Code/Mantid/Testing/SystemTests/tests/analysis/ISISDirectReductionComponents.py @@ -136,6 +136,8 @@ class ISISLoadFilesRAW(stresstesting.MantidStressTest): self.assertTrue(isinstance(ws,Workspace)) self.assertEqual(ws.getNumberHistograms(),41472) self.assertEqual(mon_ws.getNumberHistograms(),4) + + # self.valid = True @@ -180,26 +182,36 @@ class ISISLoadFilesMER(stresstesting.MantidStressTest): propman.sample_run = 18492 # (histogram nxs file ) propman.det_cal_file = None mon_ws = PropertyManager.sample_run.get_monitors_ws() + self.assertTrue('SR_MER018492' in mtd) self.assertTrue(not mon_ws is None) ws = PropertyManager.sample_run.get_workspace() self.assertTrue(isinstance(ws,Workspace)) self.assertEqual(ws.getNumberHistograms(),69641) self.assertEqual(mon_ws.getNumberHistograms(),69641) + self.assertEqual(mon_ws.getIndexFromSpectrumNumber(69638),69637) + det = mon_ws.getDetector(69632) + self.assertTrue(det.isMonitor()) + det = mon_ws.getDetector(69631) + self.assertFalse(det.isMonitor()) - self.valid = True - return # enable when bug #10980 is fixed + propman.sample_run = None # delete all + self.assertFalse('SR_MER018492' in mtd) propman.sample_run = 18492 # (histogram nxs file ) + propman.load_monitors_with_workspace = False propman.det_cal_file = None mon_ws = PropertyManager.sample_run.get_monitors_ws() self.assertTrue(not mon_ws is None) + self.assertTrue('SR_MER018492_monitors' in mtd) ws = PropertyManager.sample_run.get_workspace() self.assertTrue(isinstance(ws,Workspace)) self.assertEqual(ws.getNumberHistograms(),69632) self.assertEqual(mon_ws.getNumberHistograms(),9) - + self.assertEqual(mon_ws.getIndexFromSpectrumNumber(69633),0) + det = mon_ws.getDetector(0) + self.assertTrue(det.isMonitor()) self.valid = True diff --git a/Code/Mantid/Testing/SystemTests/tests/analysis/ISISIndirectInelastic.py b/Code/Mantid/Testing/SystemTests/tests/analysis/ISISIndirectInelastic.py index 573b3654654da2b0eec2c3a4d0506ada2e03acb9..60c6e04a961de78ed7c22d955ade098454380b06 100644 --- a/Code/Mantid/Testing/SystemTests/tests/analysis/ISISIndirectInelastic.py +++ b/Code/Mantid/Testing/SystemTests/tests/analysis/ISISIndirectInelastic.py @@ -682,7 +682,7 @@ class OSIRISDiagnostics(ISISIndirectInelasticDiagnostics): #============================================================================== class ISISIndirectInelasticMoments(ISISIndirectInelasticBase): - '''A base class for the ISIS indirect inelastic Fury/FuryFit tests + '''A base class for the ISIS indirect inelastic TransformToIqt/TransformToIqtFit tests The output of Elwin is usually used with MSDFit and so we plug one into the other in this test. @@ -849,7 +849,7 @@ class ISISIndirectInelasticFuryAndFuryFit(ISISIndirectInelasticBase): ''' A base class for the ISIS indirect inelastic Fury/FuryFit tests - The output of Fury is usually used with FuryFit and so we plug one into + The output of TransformToIqt is usually used with FuryFit and so we plug one into the other in this test. ''' @@ -865,14 +865,14 @@ class ISISIndirectInelasticFuryAndFuryFit(ISISIndirectInelasticBase): LoadNexus(sample, OutputWorkspace=sample) LoadNexus(self.resolution, OutputWorkspace=self.resolution) - fury_props, fury_ws = Fury(Sample=self.samples[0], - Resolution=self.resolution, - EnergyMin=self.e_min, - EnergyMax=self.e_max, - NumBins=self.num_bins, - DryRun=False, - Save=False, - Plot=False) + fury_props, fury_ws = TransformToIqt(SampleWorkspace=self.samples[0], + ResolutionWorkspace=self.resolution, + EnergyMin=self.e_min, + EnergyMax=self.e_max, + BinReductionFactor=self.num_bins, + DryRun=False, + Save=False, + Plot=False) # Test FuryFit Sequential furyfitSeq_ws = furyfitSeq(fury_ws.getName(), @@ -922,7 +922,7 @@ class OSIRISFuryAndFuryFit(ISISIndirectInelasticFuryAndFuryFit): def __init__(self): ISISIndirectInelasticFuryAndFuryFit.__init__(self) - # Fury + # TransformToIqt self.samples = ['osi97935_graphite002_red.nxs'] self.resolution = 'osi97935_graphite002_res.nxs' self.e_min = -0.4 @@ -947,7 +947,7 @@ class IRISFuryAndFuryFit(ISISIndirectInelasticFuryAndFuryFit): def __init__(self): ISISIndirectInelasticFuryAndFuryFit.__init__(self) - # Fury + # TransformToIqt self.samples = ['irs53664_graphite002_red.nxs'] self.resolution = 'irs53664_graphite002_res.nxs' self.e_min = -0.4 @@ -986,14 +986,14 @@ class ISISIndirectInelasticFuryAndFuryFitMulti(ISISIndirectInelasticBase): LoadNexus(sample, OutputWorkspace=sample) LoadNexus(self.resolution, OutputWorkspace=self.resolution) - fury_props, fury_ws = Fury(Sample=self.samples[0], - Resolution=self.resolution, - EnergyMin=self.e_min, - EnergyMax=self.e_max, - NumBins=self.num_bins, - DryRun=False, - Save=False, - Plot=False) + fury_props, fury_ws = TransformToIqt(SampleWorkspace=self.samples[0], + ResolutionWorkspace=self.resolution, + EnergyMin=self.e_min, + EnergyMax=self.e_max, + BinReductionFactor=self.num_bins, + DryRun=False, + Save=False, + Plot=False) # Test FuryFit Sequential furyfitSeq_ws = furyfitMult(fury_ws.getName(), @@ -1045,7 +1045,7 @@ class OSIRISFuryAndFuryFitMulti(ISISIndirectInelasticFuryAndFuryFitMulti): def __init__(self): ISISIndirectInelasticFuryAndFuryFitMulti.__init__(self) - # Fury + # TransformToIqt self.samples = ['osi97935_graphite002_red.nxs'] self.resolution = 'osi97935_graphite002_res.nxs' self.e_min = -0.4 @@ -1070,7 +1070,7 @@ class IRISFuryAndFuryFitMulti(ISISIndirectInelasticFuryAndFuryFitMulti): def __init__(self): ISISIndirectInelasticFuryAndFuryFitMulti.__init__(self) - # Fury + # TransformToIqt self.samples = ['irs53664_graphite002_red.nxs'] self.resolution = 'irs53664_graphite002_res.nxs' self.e_min = -0.4 diff --git a/Code/Mantid/Testing/SystemTests/tests/analysis/reference/LET14305_3_4meV2015.nxs.md5 b/Code/Mantid/Testing/SystemTests/tests/analysis/reference/LET14305_3_4meV2015.nxs.md5 index 6ed489c5d183269d37b381740d357b69880be926..db2816f3213cd365f848967e5fee8545639fb54b 100644 --- a/Code/Mantid/Testing/SystemTests/tests/analysis/reference/LET14305_3_4meV2015.nxs.md5 +++ b/Code/Mantid/Testing/SystemTests/tests/analysis/reference/LET14305_3_4meV2015.nxs.md5 @@ -1 +1 @@ -df968e07d52c10b9c3ecf4b2c5db596a \ No newline at end of file +6441be305fa8c6d32fe322786bafa26a diff --git a/Code/Mantid/docs/source/algorithms/CutMD-v1.rst b/Code/Mantid/docs/source/algorithms/CutMD-v1.rst index 98b00565f70354061e153679fb13593d870b82d5..da2f0f251e15456314cd10bdb50cc2a8e139241e 100644 --- a/Code/Mantid/docs/source/algorithms/CutMD-v1.rst +++ b/Code/Mantid/docs/source/algorithms/CutMD-v1.rst @@ -9,11 +9,20 @@ Description ----------- -This algorithm performs slicing of multiDimensional data according to a chosen projection, and binning choice. The algorithm uses :ref:`algm-BinMD` or -:ref:`algm-SliceMD` to achieve the binning of the data. The choice of child algorithm used for the slicing is controlled by the NoPix option. +This algorithm performs slicing of multiDimensional data according to a chosen +projection, and binning choice. The algorithm uses :ref:`algm-BinMD` or +:ref:`algm-SliceMD` to achieve the binning of the data. The choice of child +algorithm used for the slicing is controlled by the NoPix option. The synax is similar to that used by `Horace <http://horace.isis.rl.ac.uk/Manipulating_and_extracting_data_from_SQW_files_and_objects#cut_sqw>`__. +Unlike most Mantid algorithms, CutMD can accept a list of workspaces as the +input workspace, given as the name of a workspace in the analysis data service +or the path to a workspace, or simply a workspace object in python. These will +all then be processed sequentially with the same options. The only requirement +is that the same number of output workspaces are also given so that CutMD knows +what to call each output workspace created. + Usage ----- @@ -39,6 +48,10 @@ Usage # Apply the cut (PBins property sets the P1Bin, P2Bin, etc. properties for you) out_md = CutMD(to_cut, Projection=proj_ws, PBins=([0.1], [0.1], [0.1], [-5,5]), NoPix=True) + + #Another way we can call CutMD: + #[out1, out2, out3] = CutMD([to_cut, "some_other_file.nxs", "some_workspace_name"], ...) + print 'number of dimensions', out_md.getNumDims() print 'number of dimensions not integrated', len(out_md.getNonIntegratedDimensions()) dim_dE = out_md.getDimension(3) diff --git a/Code/Mantid/docs/source/algorithms/Fury-v1.rst b/Code/Mantid/docs/source/algorithms/Fury-v1.rst deleted file mode 100644 index a82a566e5ec784ab5326137903881925e7dee98c..0000000000000000000000000000000000000000 --- a/Code/Mantid/docs/source/algorithms/Fury-v1.rst +++ /dev/null @@ -1,24 +0,0 @@ -.. algorithm:: - -.. summary:: - -.. alias:: - -.. properties:: - -Description ------------ - -The model that is being fitted is that of a delta-function (elastic component) of amplitude :math:`A(0)` and Lorentzians of amplitude :math:`A(j)` and HWHM :math:`W(j)` where :math:`j=1,2,3`. The whole function is then convolved with the resolution function. The -function and Lorentzians are intrinsically -normalised to unity so that the amplitudes represent their integrated areas. - -For a Lorentzian, the Fourier transform does the conversion: :math:`1/(x^{2}+\delta^{2}) \Leftrightarrow exp[-2\pi(\delta k)]`. -If :math:`x` is identified with energy :math:`E` and :math:`2\pi k` with :math:`t/\hbar` where t is time then: :math:`1/[E^{2}+(\hbar / \tau )^{2}] \Leftrightarrow exp[-t /\tau]` and :math:`\sigma` is identified with :math:`\hbar / \tau`. -The program estimates the quasielastic components of each of the groups of spectra and requires the resolution file and optionally the normalisation file created by ResNorm. - -For a Stretched Exponential, the choice of several Lorentzians is replaced with a single function with the shape : :math:`\psi\beta(x) \Leftrightarrow exp[-2\pi(\sigma k)\beta]`. This, in the energy to time FT transformation, is :math:`\psi\beta(E) \Leftrightarrow exp[-(t/\tau)\beta]`. So \sigma is identified with :math:`(2\pi)\beta\hbar/\tau`. -The model that is fitted is that of an elastic component and the stretched exponential and the program gives the best estimate for the :math:`\beta` parameter and the width for each group of spectra. - -This routine was originally part of the MODES package. - -.. categories:: diff --git a/Code/Mantid/docs/source/algorithms/IntegrateEllipsoids-v1.rst b/Code/Mantid/docs/source/algorithms/IntegrateEllipsoids-v1.rst index c64b003e766818d4182edddb6a8e23a1cf076013..831d0c6d5d858af5fb5ce90a6b224ede544d19e6 100644 --- a/Code/Mantid/docs/source/algorithms/IntegrateEllipsoids-v1.rst +++ b/Code/Mantid/docs/source/algorithms/IntegrateEllipsoids-v1.rst @@ -162,7 +162,7 @@ Usage **Example - IntegrateEllipsoids:** -The code iteslef works but disabled from doc tests as takes too long to complete. User should provide its own +The code itself works but disabled from doc tests as takes too long to complete. User should provide its own event nexus file instead of **TOPAZ_3132_event.nxs** used within this example. The original **TOPAZ_3132_event.nxs** file is availible in `Mantid system tests repository <https://github.com/mantidproject/systemtests/tree/master/Data/TOPAZ_3132_event.nxs>`_. diff --git a/Code/Mantid/docs/source/algorithms/IntegratePeaksMD-v2.rst b/Code/Mantid/docs/source/algorithms/IntegratePeaksMD-v2.rst index 704b3cf2ce53deaaf40819d51773d39376e16bb4..20ec4aae8a90ee567c814fd446119c9c6716dd14 100644 --- a/Code/Mantid/docs/source/algorithms/IntegratePeaksMD-v2.rst +++ b/Code/Mantid/docs/source/algorithms/IntegratePeaksMD-v2.rst @@ -129,7 +129,7 @@ Usage **Example - IntegratePeaks:** -The code iteslef works but disabled from doc tests as takes too long to complete. User should provide its own +The code itself works but disabled from doc tests as takes too long to complete. User should provide its own event nexus file instead of **TOPAZ_3132_event.nxs** used within this example. The original **TOPAZ_3132_event.nxs** file is availible in `Mantid system tests repository <https://github.com/mantidproject/systemtests/tree/master/Data/TOPAZ_3132_event.nxs>`_. diff --git a/Code/Mantid/docs/source/algorithms/LoadDNSLegacy-v1.rst b/Code/Mantid/docs/source/algorithms/LoadDNSLegacy-v1.rst new file mode 100644 index 0000000000000000000000000000000000000000..369b381acf627d81d508958d0cf9efaeec993993 --- /dev/null +++ b/Code/Mantid/docs/source/algorithms/LoadDNSLegacy-v1.rst @@ -0,0 +1,39 @@ +.. algorithm:: + +.. summary:: + +.. alias:: + +.. properties:: + +Description +----------- + +Loads a DNS legacy .d_dat data file into a :ref:`Workspace2D <Workspace2D>` with +the given name. + +The loader rotates the detector bank in the position given in the data file. + +This algorithm only supports DNS instrument in its configuration before major upgrade. + +Usage +----- + +**Example - Load a DNS legacy .d_dat file:** + +.. code-block:: python + + # data file. + datafile = 'dn134011vana.d_dat' + + # Load dataset + ws = LoadDNSLegacy(datafile) + + print "This workspace has", ws.getNumDims(), "dimensions and has", \ + ws.getNumberHistograms(), "histograms." + +Output: + + This workspace has 2 dimensions and has 24 histograms. + +.. categories:: diff --git a/Code/Mantid/docs/source/algorithms/LoadFITS-v1.rst b/Code/Mantid/docs/source/algorithms/LoadFITS-v1.rst index 557447bc10fd2b485125fe0b816072e009c36e29..1184957082ea3bb9cc5fcd8427abafca0877988f 100644 --- a/Code/Mantid/docs/source/algorithms/LoadFITS-v1.rst +++ b/Code/Mantid/docs/source/algorithms/LoadFITS-v1.rst @@ -9,6 +9,86 @@ Description ----------- -Load data from FITS files +Load FITS files, which typically contain images, into a +:ref:`WorkspaceGroup <WorkspaceGroup>`. FITS stands for Flexible Image +Transport System, see http://en.wikipedia.org/wiki/FITS. A new +workspace (of type :ref:`Workspace2D <Workspace2D>`) is created for +every FITS file loaded with this algorithm, and these workspaces are +added into a :ref:`WorkspaceGroup <WorkspaceGroup>`. The group +workspace is named as indicated in the OutputWorkspace input +property. The workspaces included in the group are named with the same +name and an appendix _1, _2, etc., incremented sequentially as new +files are loaded with the same OutputWorkspace property. + +The current implementation of this algorithm only supports 2D files +(FITS images with two axes), and it should in principle be able to +load FITS files from different sources. + +The workspaces created by this algorithm contain one spectrum per +pixel. The first spectrum correspond to the top-left corner and the +last spectrum to the bottom-right corner. + +FITS header entries +################### + +At a very minimum, the standard header entries SIMPLE, BITPIX, NAXIS, +NAXIS1, and NAXIS2 must be present in the file. + +This algorithm interprets extension headers defined for the IMAT +instrument (ISIS facility). The set of extension headers for the IMAT +instrument is being defined as of this writing and specific support +and/or functionality related to additional headers might be added in +this algorithm. + +Child algorithms used +##################### + +This algorithm uses one child algorithm: + +- :ref:`algm-LoadInstrument`, which looks for a description of the + instrument in the facilities definition file and if found reads it. + This algorithm is used only once when loading a set of FITS file + corresponding to the same instrument. + +Usage +----- + +**Example** + +.. testcode:: LoadFITS + + ws_name = 'FITSws' + wsg = LoadFITS(Filename='FITS_small_01.fits', OutputWorkspace=ws_name) + ws = wsg.getItem(0) + + # A couple of standard FITS header entries + bpp_log = '_BITPIX' + try: + log = ws.getRun().getLogData(bpp_log).value + print "Bits per pixel: %s" % int(log) + except RuntimeError: + print "Could not find the keyword '%s' in this FITS file" % bpp_log + + axis1_log = '_NAXIS1' + axis2_log = '_NAXIS2' + try: + log1 = ws.getRun().getLogData(axis1_log).value + log2 = ws.getRun().getLogData(axis2_log).value + print "FITS image size: %s x %s pixels" % (int(log1), int(log2)) + print "Number of spectra in the output workspace: %d" % ws.getNumberHistograms() + except RuntimeError: + print "Could not find the keywords '%s' and '%s' in this FITS file" % (axis1_log, axis2_log) + +.. testcleanup:: LoadFITS + + DeleteWorkspace(ws_name) + +Output: + +.. testoutput:: LoadFITS + + Bits per pixel: 16 + FITS image size: 512 x 512 pixels + Number of spectra in the output workspace: 262144 .. categories:: diff --git a/Code/Mantid/docs/source/algorithms/PoldiCreatePeaksFromFile-v1.rst b/Code/Mantid/docs/source/algorithms/PoldiCreatePeaksFromFile-v1.rst new file mode 100644 index 0000000000000000000000000000000000000000..a25b5e8d3f8b3607adb6f579a7aab1a8662d6fa6 --- /dev/null +++ b/Code/Mantid/docs/source/algorithms/PoldiCreatePeaksFromFile-v1.rst @@ -0,0 +1,87 @@ + +.. algorithm:: + +.. summary:: + +.. alias:: + +.. properties:: + +Description +----------- + +Some steps in the analysis of POLDI data require that detected peaks are indexed. This can be done by using +:ref:`algm-PoldiIndexKnownCompounds`, which accepts a table with unindexed peaks and one or more workspaces with +calculated peaks corresponding to the crystal structures that are expected in the sample. These can be calculated +using the algorithm :ref:`algm-PoldiCreatePeaksFromCell`. Calling this algorithm over and over with the same +parameters is not practical, but storing the tables is not practical either, since lattice parameters may change +slightly from sample to sample. + +PoldiCreatePeaksFromFile reads a text file which contains one or more crystal structure definitions. Since the +analysis requires information mainly about the lattice and the symmetry, the format is very simple. The following +block shows how such a file would look when there are two compounds: + +.. code-block:: none + + # The name may contain letters, numbers and _ + Iron_FCC { + # Up to 6 values in the order a, b, c, alpha, beta, gamma. + # Lattice parameters are given in Angstrom. + Lattice: 3.65 + Spacegroup: F m -3 m + Atoms: { + # Element x y z are mandatory. Optional occupancy and isotropic ADP (in Angstrom^2) + Fe 0.0 0.0 0.0 + } + } + + Iron_BCC { + Lattice: 2.88 + Spacegroup: F m -3 m + Atoms: { + Fe 0.0 0.0 0.0 + } + } + +Note that only the atoms in the asymmetric unit need to be specified, the space group is used to generate all +equivalent atoms. This information is used to determine systematic absences, while the space group is also used by +some POLDI algorithms to obtain the point group to get reflection multiplicities and more. Anything that follows the +`#`-character is considered a comment and is ignored by the parser to allow documentation of the crystal structures +if necessary. + +The algorithm will always produce a WorkspaceGroup which contains as many peak tables as compounds specified in the +file. + +Usage +----- + +.. include:: ../usagedata-note.txt + +The following usage example takes up the file showed above and passes it to the algorithm. + +.. testcode:: + + # Create two tables with expected peaks directly from a file + compounds = PoldiCreatePeaksFromFile('PoldiCrystalFileExample.dat', LatticeSpacingMin=0.7) + + compound_count = compounds.getNumberOfEntries() + print 'Number of loaded compounds:', compound_count + + for i in range(compound_count): + ws = compounds.getItem(i) + print 'Compound ' + str(i + 1) +':', ws.getName(), 'has', ws.rowCount(), 'reflections in the resolution range.' + + +The script produces a WorkspaceGroup which contains a table with reflections for each compound in the file: + +.. testoutput:: + + Number of loaded compounds: 2 + Compound 1: Iron_FCC has 11 reflections in the resolution range. + Compound 2: Iron_BCC has 8 reflections in the resolution range. + +.. testcleanup:: + + DeleteWorkspace('compounds') + +.. categories:: diff --git a/Code/Mantid/docs/source/algorithms/SCDCalibratePanels-v1.rst b/Code/Mantid/docs/source/algorithms/SCDCalibratePanels-v1.rst index 0ddba6913fe7ea9f4d9a99d6b3b81326d8d5b01c..1f98aa15a476e3838012d2570b2cee52b2ba01b5 100644 --- a/Code/Mantid/docs/source/algorithms/SCDCalibratePanels-v1.rst +++ b/Code/Mantid/docs/source/algorithms/SCDCalibratePanels-v1.rst @@ -95,4 +95,17 @@ algorithm. To do so select the workspace, which you have calibrated as the InputWorkspace and the workspace you want to copy the calibration to, the OutputWorkspace. +Usage +------ + +**Example - SCDCalibratePanels:** + + LoadIsawPeaks(Filename='MANDI_801.peaks', OutputWorkspace='peaks') + SCDCalibratePanels(PeakWorkspace='peaks',DetCalFilename='mandi_801.DetCal',XmlFilename='mandi_801.xml',a=74,b=74.5,c=99.9,alpha=90,beta=90,gamma=60) + Load(Filename='MANDI_801_event.nxs', OutputWorkspace='MANDI_801_event') + CloneWorkspace(InputWorkspace='MANDI_801_event', OutputWorkspace='MANDI_801_event_xml') + LoadParameterFile(Workspace='MANDI_801_event_xml', Filename='mandi_801.xml') + RenameWorkspace(InputWorkspace='MANDI_801_event_xml', OutputWorkspace='MANDI_801_event_DetCal') + LoadIsawDetCal(InputWorkspace='MANDI_801_event_DetCal', Filename='mandi_801.DetCal') + .. categories:: diff --git a/Code/Mantid/docs/source/algorithms/TransformToIqt-v1.rst b/Code/Mantid/docs/source/algorithms/TransformToIqt-v1.rst new file mode 100644 index 0000000000000000000000000000000000000000..83480d11785c64b0edfd40982bb5bcdf0ad8006d --- /dev/null +++ b/Code/Mantid/docs/source/algorithms/TransformToIqt-v1.rst @@ -0,0 +1,112 @@ +.. algorithm:: + +.. summary:: + +.. alias:: + +.. properties:: + +Description +----------- + +This algorithm transforms either a reduced (*_red*) or S(Q, w) (*_sqw*) +workspace to a I(Q, t) workspace. + +Theory +------ + +The measured spectrum :math:`I(Q, \omega)` is proportional to the four +dimensional convolution of the scattering law :math:`S(Q, \omega)` with the +resolution function :math:`R(Q, \omega)` of the spectrometer via :math:`I(Q, +\omega) = S(Q, \omega) ⊗ R(Q, \omega)`, so :math:`S(Q, \omega)` can be obtained, +in principle, by a deconvolution in :math:`Q` and :math:`\omega`. The method +employed here is based on the Fourier Transform (FT) technique [6,7]. On Fourier +transforming the equation becomes :math:`I(Q, t) = S(Q, t) x R(Q, t)` where the +convolution in :math:`\omega`-space is replaced by a simple multiplication in +:math:`t`-space. The intermediate scattering law :math:`I(Q, t)` is then +obtained by simple division and the scattering law :math:`S(Q, \omega)` itself +can be obtained by back transformation. The latter however is full of pitfalls +for the unwary. The advantage of this technique over that of a fitting procedure +such as SWIFT is that a functional form for :math:`I(Q, t)` does not have to be +assumed. On IRIS the resolution function is close to a Lorentzian and the +scattering law is often in the form of one or more Lorentzians. The FT of a +Lorentzian is a decaying exponential, :math:`exp(-\alpha t)` , so that plots of +:math:`ln(I(Q, t))` against t would be straight lines thus making interpretation +easier. + +In general, the origin in energy for the sample run and the resolution run need +not necessarily be the same or indeed be exactly zero in the conversion of the +RAW data from time-of-flight to energy transfer. This will depend, for example, +on the sample and vanadium shapes and positions and whether the analyser +temperature has changed between the runs. The procedure takes this into account +automatically, without using an arbitrary fitting procedure, in the following +way. From the general properties of the FT, the transform of an offset +Lorentzian has the form :math:`(cos(\omega_{0}t) + isin(\omega_{0}t))exp(-\Gamma +t)` , thus taking the modulus produces the exponential :math:`exp(-\Gamma t)` +which is the required function. If this is carried out for both sample and +resolution, the difference in the energy origin is automatically removed. The +results of this procedure should however be treated with some caution when +applied to more complicated spectra in which it is possible for :math:`I(Q, t)` +to become negative, for example, when inelastic side peaks are comparable in +height to the elastic peak. + +The interpretation of the data must also take into account the propagation of +statistical errors (counting statistics) in the measured data as discussed by +Wild et al [1]. If the count in channel :math:`k` is :math:`X_{k}` , then +:math:`X_{k}=<X_{k}>+\Delta X_{k}` where :math:`<X_{k}>` is the mean value and +:math:`\Delta X_{k}` the error. The standard deviation for channel :math:`k` is +:math:`\sigma k` :math:`2=<\Delta X_{k}>2` which is assumed to be given by +:math:`\sigma k=<X_{k}>`. The FT of :math:`X_{k}` is defined by +:math:`X_{j}=<X_{j}>+\Delta X_{j}` and the real and imaginary parts denoted by +:math:`X_{j} I` and :math:`X_{j} I` respectively. The standard deviations on +:math:`X_{j}` are then given by :math:`\sigma 2(X_{j} R)=1/2 X0 R + 1/2 X2j R` +and :math:`\sigma 2(X_{j} I)=1/2 X0 I - 1/2 X2j I`. + +Note that :math:`\sigma 2(X_{0} R) = X_{0} R` and from the properties of FT +:math:`X_{0} R = X_{k}`. Thus the standard deviation of the first coefficient +of the FT is the square root of the integrated intensity of the spectrum. In +practice, apart from the first few coefficients, the error is nearly constant +and close to :math:`X_{0} R`. A further point to note is that the errors make +the imaginary part of :math:`I(Q, t)` non-zero and that, although these will be +distributed about zero, on taking the modulus of :math:`I(Q, t)`, they become +positive at all times and are distributed about a non-zero positive value. When +:math:`I(Q, t)` is plotted on a log-scale the size of the error bars increases +with time (coefficient) and for the resolution will reach a point where the +error on a coefficient is comparable to its value. This region must therefore be +treated with caution. For a true deconvolution by back transforming, the data +would be truncated to remove this poor region before back transforming. If the +truncation is severe the back transform may contain added ripples, so an +automatic back transform is not provided. + +References +---------- + +1. U P Wild, R Holzwarth & H P Good, Rev Sci Instr 48 1621 (1977) + +Usage +----- + +**Example - TransformToIqt with IRIS data.** + +.. testcode:: exTransformToIqtIRIS + + sample = Load('irs26176_graphite002_red.nxs') + can = Load('irs26173_graphite002_red.nxs') + + params, iqt = TransformToIqt(SampleWorkspace=sample, + ResolutionWorkspace=can, + EnergyMin=-0.5, + EnergyMax=0.5, + BinReductionFactor=10) + + print 'Number of output bins: %d' % (params.cell('SampleOutputBins', 0)) + print 'Resolution bins: %d' % (params.cell('ResolutionBins', 0)) + +Output: + +.. testoutput:: exTransformToIqtIRIS + + Number of output bins: 172 + Resolution bins: 6 + +.. categories:: diff --git a/Code/Mantid/docs/source/concepts/HowToDefineGeometricShape.rst b/Code/Mantid/docs/source/concepts/HowToDefineGeometricShape.rst index b85cee29f6c3209c50a4065efb8aa3024b770c91..b70b96b0003b1a3befe406dc494d2af58658b3ca 100644 --- a/Code/Mantid/docs/source/concepts/HowToDefineGeometricShape.rst +++ b/Code/Mantid/docs/source/concepts/HowToDefineGeometricShape.rst @@ -31,11 +31,11 @@ algebra that follows the following notation: +------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------+ | Operator | Description | Example | +============+================================================================================================================================================================+======================================================================================================+ -| | Union (i.e two or more things making up one shape). See e.g. also `1 <http://en.wikipedia.org/wiki/Union_(set_theory)>`__ | a body = legs : torso : arms : head | +| : | Union (i.e two or more things making up one shape). See e.g. also `1 <http://en.wikipedia.org/wiki/Union_(set_theory)>`__ | a body = legs : torso : arms : head | +------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------+ | " " | "space" shared between shapes, i,e. intersection (the common region of shapes). See e.g. also `2 <http://en.wikipedia.org/wiki/Intersection_(set_theory)>`__ | "small-circle = big-circle small-circle" (where the small circle placed within the big-circle) | +------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------+ -| #. | Complement | #. sphere = shape defined by all points outside sphere | +| \# | Complement | \# sphere = shape defined by all points outside sphere | +------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------+ | ( ) | Brackets are used to emphasise which shapes an operation should be applied to. | box1 (# box2) is the intersection between box1 and the shape defined by all points not inside box2 | +------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------+ diff --git a/Code/Mantid/docs/source/concepts/PointGroups.rst b/Code/Mantid/docs/source/concepts/PointGroups.rst index 4974ba3e280b785ff2c04a0e97d149a185beedf8..65a6c9540f93e3ae3b9d7921620a24832d972c1d 100644 --- a/Code/Mantid/docs/source/concepts/PointGroups.rst +++ b/Code/Mantid/docs/source/concepts/PointGroups.rst @@ -42,7 +42,7 @@ As mentioned before, point groups can describe the symmetry of a lattice, includ To describe the rotational and translational components of the symmetry operation, a matrix :math:`\mathbf{W}_i` and a vector :math:`\mathbf{w}_i` are used. In three dimensions :math:`\mathbf{h}` has three elements, so :math:`\mathbf{W}_i` is a :math:`3\times3`-matrix and the symmetry operation is applied like this: .. math:: - \mathbf{h}' = \mathbf{W}_i^{-1T} \cdot \mathbf{h} + \mathbf{h}' = {\mathbf{W}_i^{-1}}^T \cdot \mathbf{h} Note that the translational component is not used for transforming HKLs and :math:`\mathbf{W}_i` is inverted and transposed. Coordinates :math:`\mathbf{x}` are transformed differently, they are affected by the translational component: @@ -170,10 +170,12 @@ Which results in the following output: .. testoutput :: ExQueryPointGroups - All point groups: ['-1','-3','-3 h','-31m','-3m','-3m1','-4','-42m','-43m','-4m2','-6','-62m','-6m2','1','112/m','2','2/m','222','23','3','3 h','312','31m','32','321','3m','3m1','4','4/m','4/mmm','422','432','4mm','6','6/m','6/mmm','622','6mm','m','m-3','m-3m','mm2','mmm'] + All point groups: ['-1','-3','-3 r','-31m','-3m r','-3m1','-4','-42m','-43m','-4m2','-6','-62m','-6m2','1','112/m','2','2/m','222','23','3','3 r','312','31m','32 r','321','3m r','3m1','4','4/m','4/mmm','422','432','4mm','6','6/m','6/mmm','622','6mm','m','m-3','m-3m','mm2','mmm'] Cubic point groups: ['-43m','23','432','m-3','m-3m'] Tetragonal point groups: ['-4','-42m','-4m2','4','4/m','4/mmm','422','4mm'] +The point groups with an extra ``r`` at the end are trigonal point groups with rhombohedral axes. Trigonal point groups without that additional letter use the hexagonal coordinate system. + After having obtained a ``PointGroup``-object, it can be used for working with reflection data, more specifically :math:`hkl`-indices. It's possible to check whether two reflections are equivalent in a certain point group: .. testcode :: ExIsEquivalent diff --git a/Code/Mantid/docs/source/interfaces/Indirect_DataAnalysis.rst b/Code/Mantid/docs/source/interfaces/Indirect_DataAnalysis.rst index 49b5128e1904e6d819e389aa28e8865ca8965a38..1eb4013e2b83808aab28349430f1fa3a2368cc3d 100644 --- a/Code/Mantid/docs/source/interfaces/Indirect_DataAnalysis.rst +++ b/Code/Mantid/docs/source/interfaces/Indirect_DataAnalysis.rst @@ -127,9 +127,6 @@ Plot Spectrum Spectra Range The spectra range over which to perform sequential fitting. -Verbose - Enables outputting additional information to the Results Log. - Plot Result If enabled will plot the result as a spectra plot. @@ -144,7 +141,7 @@ Fury :widget: tabFury Given sample and resolution inputs, carries out a fit as per the theory detailed -below. +in the :ref:`TransformToIqt <algm-TransformToIqt>` algorithm. Options ~~~~~~~ @@ -164,9 +161,6 @@ SampleBinning The ratio at which to decrease the number of bins by through merging of intensities from neighbouring bins. -Verbose - Enables outputting additional information to the Results Log. - Plot Result If enabled will plot the result as a spectra plot. @@ -194,76 +188,6 @@ ResolutionBins Number of bins in the resolution after rebinning, typically this should be at least 5 and a warning will be shown if it is less. -Theory -~~~~~~ - -The measured spectrum :math:`I(Q, \omega)` is proportional to the four -dimensional convolution of the scattering law :math:`S(Q, \omega)` with the -resolution function :math:`R(Q, \omega)` of the spectrometer via :math:`I(Q, -\omega) = S(Q, \omega) ⊗ R(Q, \omega)`, so :math:`S(Q, \omega)` can be obtained, -in principle, by a deconvolution in :math:`Q` and :math:`\omega`. The method -employed here is based on the Fourier Transform (FT) technique [6,7]. On Fourier -transforming the equation becomes :math:`I(Q, t) = S(Q, t) x R(Q, t)` where the -convolution in :math:`\omega`-space is replaced by a simple multiplication in -:math:`t`-space. The intermediate scattering law :math:`I(Q, t)` is then -obtained by simple division and the scattering law :math:`S(Q, \omega)` itself -can be obtained by back transformation. The latter however is full of pitfalls -for the unwary. The advantage of this technique over that of a fitting procedure -such as SWIFT is that a functional form for :math:`I(Q, t)` does not have to be -assumed. On IRIS the resolution function is close to a Lorentzian and the -scattering law is often in the form of one or more Lorentzians. The FT of a -Lorentzian is a decaying exponential, :math:`exp(-\alpha t)` , so that plots of -:math:`ln(I(Q, t))` against t would be straight lines thus making interpretation -easier. - -In general, the origin in energy for the sample run and the resolution run need -not necessarily be the same or indeed be exactly zero in the conversion of the -RAW data from time-of-flight to energy transfer. This will depend, for example, -on the sample and vanadium shapes and positions and whether the analyser -temperature has changed between the runs. The procedure takes this into account -automatically, without using an arbitrary fitting procedure, in the following -way. From the general properties of the FT, the transform of an offset -Lorentzian has the form :math:`(cos(\omega_{0}t) + isin(\omega_{0}t))exp(-\Gamma -t)` , thus taking the modulus produces the exponential :math:`exp(-\Gamma t)` -which is the required function. If this is carried out for both sample and -resolution, the difference in the energy origin is automatically removed. The -results of this procedure should however be treated with some caution when -applied to more complicated spectra in which it is possible for :math:`I(Q, t)` -to become negative, for example, when inelastic side peaks are comparable in -height to the elastic peak. - -The interpretation of the data must also take into account the propagation of -statistical errors (counting statistics) in the measured data as discussed by -Wild et al [1]. If the count in channel :math:`k` is :math:`X_{k}` , then -:math:`X_{k}=<X_{k}>+\Delta X_{k}` where :math:`<X_{k}>` is the mean value and -:math:`\Delta X_{k}` the error. The standard deviation for channel :math:`k` is -:math:`\sigma k` :math:`2=<\Delta X_{k}>2` which is assumed to be given by -:math:`\sigma k=<X_{k}>`. The FT of :math:`X_{k}` is defined by -:math:`X_{j}=<X_{j}>+\Delta X_{j}` and the real and imaginary parts denoted by -:math:`X_{j} I` and :math:`X_{j} I` respectively. The standard deviations on -:math:`X_{j}` are then given by :math:`\sigma 2(X_{j} R)=1/2 X0 R + 1/2 X2j R` -and :math:`\sigma 2(X_{j} I)=1/2 X0 I - 1/2 X2j I`. - -Note that :math:`\sigma 2(X_{0} R) = X_{0} R` and from the properties of FT -:math:`X_{0} R = X_{k}`. Thus the standard deviation of the first coefficient -of the FT is the square root of the integrated intensity of the spectrum. In -practice, apart from the first few coefficients, the error is nearly constant -and close to :math:`X_{0} R`. A further point to note is that the errors make -the imaginary part of :math:`I(Q, t)` non-zero and that, although these will be -distributed about zero, on taking the modulus of :math:`I(Q, t)`, they become -positive at all times and are distributed about a non-zero positive value. When -:math:`I(Q, t)` is plotted on a log-scale the size of the error bars increases -with time (coefficient) and for the resolution will reach a point where the -error on a coefficient is comparable to its value. This region must therefore be -treated with caution. For a true deconvolution by back transforming, the data -would be truncated to remove this poor region before back transforming. If the -truncation is severe the back transform may contain added ripples, so an -automatic back transform is not provided. - -References: - -1. U P Wild, R Holzwarth & H P Good, Rev Sci Instr 48 1621 (1977) - Fury Fit -------- @@ -326,9 +250,6 @@ Plot Spectrum Spectra Range The spectra range over which to perform sequential fitting. -Verbose - Enables outputting additional information to the Results Log. - Plot Output Allows plotting spectra plots of fitting parameters, the options available will depend on the type of fit chosen. @@ -401,9 +322,6 @@ Plot Spectrum Spectra Range The spectra range over which to perform sequential fitting. -Verbose - Enables outputting additional information to the Results Log. - Plot Output Allows plotting spectra plots of fitting parameters, the options available will depend on the type of fit chosen. @@ -506,13 +424,12 @@ References: Calculate Corrections --------------------- -.. warning:: This interface is only available on Windows - .. interface:: Data Analysis :widget: tabCalcCorr -Calculates absorption corrections that could be applied to the data when given -information about the sample (and optionally can) geometry. +Calculates absorption corrections in the Paalman & Pings absorption factors that +could be applied to the data when given information about the sample (and +optionally can) geometry. Options ~~~~~~~ @@ -527,16 +444,18 @@ Use Can \omega)` file (*_sqw.nxs*) or workspace (*_sqw*). Sample Shape - Sets the shape of the sample, this affects the options for the sample details, - see below. + Sets the shape of the sample, this affects the options for the shape details + (see below). -Beam Width - Width of the incident beam. +Sample/Can Number Density + Density of the sample or container. -Verbose - Enables outputting additional information to the Results Log. +Sample/Can Chemical Formula + Chemical formula of the sample or can material. This must be provided in the + format expected by the :ref:`SetSampleMaterial <algm-SetSampleMaterial>` + algorithm. -Plot Result +Plot Output Plots the :math:`A_{s,s}`, :math:`A_{s,sc}`, :math:`A_{c,sc}` and :math:`A_{c,c}` workspaces as spectra plots. @@ -544,60 +463,74 @@ Save Result If enabled the result will be saved as a NeXus file in the default save directory. -Sample Details -~~~~~~~~~~~~~~ +Shape Details +~~~~~~~~~~~~~ Depending on the shape of the sample different parameters for the sample dimension are required and are detailed below. -Flat -#### +Flat Plate +########## .. interface:: Data Analysis - :widget: pageFlat + :widget: pgFlatPlate -Thickness +The calculation for a flat plate geometry is performed by the +:ref:`FlatPlatePaalmanPingsCorrection <algm-FlatPlatePaalmanPingsCorrection>` +algorithm. + +Sample Thickness Thickness of sample (cm). +Sample Angle + Sample angle (degrees). + Can Front Thickness Thickness of front container (cm). Can Back Thickness Thickness of back container (cm). -Sample Angle - Sample angle (degrees). - Cylinder ######## +.. warning:: This mode is only available on Windows + .. interface:: Data Analysis - :widget: pageCylinder + :widget: pgCylinder + +The calculation for a cylindrical geometry is performed by the +:ref:`CylinderPaalmanPingsCorrection <algm-CylinderPaalmanPingsCorrection>` +algorithm, this algorithm is currently only available on Windows as it uses +FORTRAN code dependant of F2Py. + +Sample Inner Radius + Radius of the inner wall of the sample (cm). -Radius 1 - Sample radius 1 (cm). +Sample Outer Radius + Radius of the outer wall of the sample (cm). -Radius 2 - Sample radius 2 (cm). +Container Outer Radius + Radius of outer wall of the container (cm). -Can Radius - Radius of inside of the container (cm). +Beam Height + Height of incident beam (cm). + +Beam Width + Width of incident beam (cm). Step Size Step size used in calculation. -Theory -~~~~~~ +Background +~~~~~~~~~~ The main correction to be applied to neutron scattering data is that for absorption both in the sample and its container, when present. For flat plate geometry, the corrections can be analytical and have been discussed for example by Carlile [1]. The situation for cylindrical geometry is more complex and requires numerical integration. These techniques are well known and used in -liquid and amorphous diffraction, and are described in the ATLAS manual [2]. The -routines used here have been developed from the corrections programs in the -ATLAS suite and take into account the wavelength variation of both the -absorption and the scattering cross-sections for the inelastic flight paths. +liquid and amorphous diffraction, and are described in the ATLAS manual [2]. The absorption corrections use the formulism of Paalman and Pings [3] and involve the attenuation factors :math:`A_{i,j}` where :math:`i` refers to @@ -608,9 +541,7 @@ plus container. If the scattering cross sections for sample and container are scattering from the empty container is :math:`I_{c} = \Sigma_{c}A_{c,c}` and that from the sample plus container is :math:`I_{sc} = \Sigma_{s}A_{s,sc} + \Sigma_{c}A_{c,sc}`, thus :math:`\Sigma_{s} = (I_{sc} - I_{c}A_{c,sc}/A_{c,c}) / -A_{s,sc}`. In the package, the program Acorn calculates the attenuation -coefficients :math:`A_{i,j}` and the routine Analyse uses them to calculate Σs -which we identify with :math:`S(Q, \omega)`. +A_{s,sc}`. References: @@ -627,12 +558,29 @@ Apply Corrections The Apply Corrections tab applies the corrections calculated in the Calculate Corrections tab of the Indirect Data Analysis interface. -This tab will expect to find the ass file generated in the previous tab. If Use -Can is selected, it will also expect the assc, acsc and acc files. It will take -the run number from the sample file, and geometry from the option you select. +This uses the :ref:`ApplyPaalmanPingsCorrection +<algm-ApplyPaalmanPingsCorrection>` algorithm to apply absorption corrections in +the form of the Paalman & Pings correction factors. When *Use Can* is disabled +only the :math:`A_{s,s}` factor must be provided, when using a container the +additional factors must be provided: :math:`A_{c,sc}`, :math:`A_{s,sc}` and +:math:`A_{c,c}`. Once run the corrected output and can correction is shown in the preview plot, -the Spectrum spin box can be used to scroll through each spectrum. +the Spectrum spin box can be used to scroll through each spectrum. Note that +when this plot shows the result of a calculation the X axis is always in +wavelength, however when data is initially selected the X axis unit matches that +of the sample workspace. + +The input and container workspaces will be converted to wavelength (using +:ref:`ConvertUnits <algm-ConvertUnits>`) if they do not already have wavelength +as their X unit. + +The binning of the sample, container and corrections factor workspace must all +match, if the sample and container do not match you will be given the option to +rebin (using :ref:`RebinToWorkspace <algm-RebinToWorkspace>`) the sample to +match the container, if the correction factors do not match you will be given +the option to interpolate (:ref:`SplineInterpolation +<algm-SplineInterpolation>`) the correction factor to match the sample. Options ~~~~~~~ @@ -650,12 +598,14 @@ Use Can either a reduced file (*_red.nxs*) or workspace (*_red*) or an :math:`S(Q, \omega)` file (*_sqw.nxs*) or workspace (*_sqw*). -Corrections File - The output file (_Abs.nxs) or workspace group (_Abs) generated by Calculate - Corrections. +Scale Can by factor + Allows the container intensity to be scaled by a given scale factor before + being used in the corrections calculation. -Verbose - Enables outputting additional information to the Results Log. +Use Corrections + The Paalman & Pings correction factors to use in the calculation, note that + the file or workspace name must end in either *_flt_abs* or *_cyl_abs* for the + flat plate and cylinder geometries respectively. Plot Output Gives the option to create either a spectra or contour plot (or both) of the diff --git a/Code/Mantid/instrument/ALF_Definition.xml b/Code/Mantid/instrument/ALF_Definition.xml index 331f26d6a83d6e62b358c57cec515bdab2477f10..f9c2c35766952edb35428d9613ad15e9dacdead0 100644 --- a/Code/Mantid/instrument/ALF_Definition.xml +++ b/Code/Mantid/instrument/ALF_Definition.xml @@ -5,8 +5,8 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.mantidproject.org/IDF/1.0 http://schema.mantidproject.org/IDF/1.0/IDFSchema.xsd" name="ALF" valid-from ="1900-01-31 23:59:59" - valid-to ="2100-01-31 23:59:59" - last-modified="2009-01-15 00:00:00"> + valid-to ="2015-03-16 23:59:59" + last-modified="2015-03-27 00:00:00"> <defaults> <length unit="meter"/> diff --git a/Code/Mantid/instrument/ALF_Definition_20130317-.xml b/Code/Mantid/instrument/ALF_Definition_20130317-.xml new file mode 100644 index 0000000000000000000000000000000000000000..034b567050c4302a4700d12d652fe2e0b40d5820 --- /dev/null +++ b/Code/Mantid/instrument/ALF_Definition_20130317-.xml @@ -0,0 +1,789 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- For help on the notation used to specify an Instrument Definition File + see http://www.mantidproject.org/IDF --> +<instrument xmlns="http://www.mantidproject.org/IDF/1.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.mantidproject.org/IDF/1.0 http://schema.mantidproject.org/IDF/1.0/IDFSchema.xsd" + name="ALF" valid-from ="2015-03-17 00:00:00" + valid-to ="2100-01-31 23:59:59" + last-modified="2015-03-27 00:00:00"> + + <defaults> + <length unit="meter"/> + <angle unit="degree"/> + <location r="0.0" t="0.0" p="0.0" ang="0.0" axis-x="0.0" axis-y="0.0" axis-z="1.0"/> + <reference-frame> + <!-- The z-axis is set parallel to and in the direction of the beam. the + y-axis points up and the coordinate system is right handed. --> + <along-beam axis="z"/> + <pointing-up axis="y"/> + <handedness val="right"/> + <origin val="beam" /> + </reference-frame> + <!-- Comment "components-are-facing" out if you dont want the + components defined in this file to face a position by default --> + <components-are-facing x="0.0" y="0.0" z="0.0" /> + <default-view view="cylindrical_y"/> + </defaults> + <!-- LIST OF PHYSICAL COMPONENTS (which the instrument consists of) --> + <!-- detector components --> + <properties> + </properties> + + <component type="monitors" idlist="monitors"> + <location/> + </component> +<!-- +<component type="ALFpack1" idlist="ALFpack1"> +<location /> +</component> +<component type="ALFpack2" idlist="ALFpack2"> +<location /> +</component> +<component type="ALFpack3" idlist="ALFpack3"> +<location /> +</component> --> +<component type="ALFdetectors" idlist="ALFdetectors"> +<location /> +</component> + +<!-- +<component type="ALFextratube1" idlist="ALFextratube1"> +<location /> +</component> +<component type="ALFextratube2" idlist="ALFextratube2"> +<location /> +</component> +--> +<!-- source and sample-position components --> + <component type="undulator"> + <location z="-14.9165"> <facing val="none"/> </location> + </component> + + <component type="nickel-holder"> + <location> <facing val="none"/> </location> + </component> + + <!-- DEFINITION OF TYPES --> + <!-- Source types --> + <type name="undulator" is="Source"> + <properties /> + <cylinder id="some-shape"> + <centre-of-bottom-base r="0.0" t="0.0" p="0.0" /> + <axis x="0.0" y="0.0" z="1.0" /> + <radius val="0.01" /> + <height val="0.03" /> + </cylinder> + <algebra val="some-shape" /> + </type> + + <!-- Sample-position types --> + <type name="nickel-holder" is="SamplePos"> + <properties /> + <sphere id="some-shape"> + <centre x="0.0" y="0.0" z="0.0" /> + <radius val="0.03" /> + </sphere> + <algebra val="some-shape" /> + </type> + + <!-- Detectors types --> + <type name="monitors"> + <component type="monitor"> + <location r="2.03" t="180.0" p="0.0" name="monitor1" /> + <location r="1.54" t="0.0" p="0.0" name="monitor2" /> + <location r="4.0" t="0.0" p="0.0" name="monitor3" /> + </component> + </type> + +<type name="ALFdetectors"> + <component type="ALF24tubes"> +<location x="0.7309 " z=" 1.3328 "> <facing x="0" y="0" z="0"/> </location> + </component> + </type> + +<!-- <type name="ALFpack1"> + <component type="ALFpack"> +<location x="0.52833 " z=" 1.4252 "> <facing x="0" y="0" z="0"/> </location> + </component> + </type> +<type name="ALFpack2"> + <component type="ALFpack"> +<location x="0.7309 " z=" 1.3328 "> <facing x="0" y="0" z="0"/> </location> + </component> + </type> +<type name="ALFpack3"> + <component type="ALFpack"> +<location x="0.91857 " z=" 1.21105 "> <facing x="0" y="0" z="0"/> </location> + </component> + </type> --> +<!-- +<type name="ALFextratube1"> + <component type="ALFtube"> +<location x="1.52 " z=" -0.0200 "> <facing x="0" y="0" z="0"/> </location> + </component> + </type> +<type name="ALFextratube2"> + <component type="ALFtube"> +<location x="1.52 " z=" 0.0200 "> <facing x="0" y="0" z="0"/> </location> + </component> + </type> +--> + + <type name="ALF24tubes"> + <properties /> + <component type="ALFtube" > +<location x=" -0.3220 " z=" 0.00000" name="tube1" /> +<location x=" -0.2940 " z=" 0.00000" name="tube2" /> +<location x=" -0.2660 " z=" 0.00000" name="tube3" /> +<location x=" -0.2380 " z=" 0.00000" name="tube4" /> +<location x=" -0.2100 " z=" 0.00000" name="tube5" /> +<location x=" -0.1820 " z=" 0.00000" name="tube6" /> +<location x=" -0.1540 " z=" 0.00000" name="tube7" /> +<location x=" -0.1260 " z=" 0.00000" name="tube8" /> +<location x=" -0.0980 " z=" 0.00000" name="tube9" /> +<location x=" -0.0700 " z=" 0.00000" name="tube10" /> +<location x=" -0.0420 " z=" 0.00000" name="tube11" /> +<location x=" -0.0140 " z=" 0.00000" name="tube12" /> +<location x=" 0.01400 " z=" 0.00000" name="tube13" /> +<location x=" 0.04200 " z=" 0.00000" name="tube14" /> +<location x=" 0.07000 " z=" 0.00000" name="tube15" /> +<location x=" 0.09800 " z=" 0.00000" name="tube16" /> +<location x=" 0.12600 " z=" 0.00000" name="tube17" /> +<location x=" 0.15400 " z=" 0.00000" name="tube18" /> +<location x=" 0.18200 " z=" 0.00000" name="tube19" /> +<location x=" 0.21000 " z=" 0.00000" name="tube20" /> +<location x=" 0.23800 " z=" 0.00000" name="tube21" /> +<location x=" 0.26600 " z=" 0.00000" name="tube22" /> +<location x=" 0.29400 " z=" 0.00000" name="tube23" /> +<location x=" 0.32200 " z=" 0.00000" name="tube24" /> + + </component> + </type> + +<!-- + <type name="ALFpack"> + <properties /> + <component type="ALFtube" > +<location x=" -0.0980 " z=" 0.00000" name="tube1" /> +<location x=" -0.0700 " z=" 0.00000" name="tube2" /> +<location x=" -0.0420 " z=" 0.00000" name="tube3" /> +<location x=" -0.0140 " z=" 0.00000" name="tube4" /> +<location x=" 0.01400 " z=" 0.00000" name="tube5" /> +<location x=" 0.04200 " z=" 0.00000" name="tube6" /> +<location x=" 0.07000 " z=" 0.00000" name="tube7" /> +<location x=" 0.09800 " z=" 0.00000" name="tube8" /> + </component> + </type> --> + +<type name="ALFtube" outline="yes"> + <component type="pixel"> +<location y=" -0.498047" /> +<location y=" -0.496094" /> +<location y=" -0.494141" /> +<location y=" -0.492188" /> +<location y=" -0.490234" /> +<location y=" -0.488281" /> +<location y=" -0.486328" /> +<location y=" -0.484375" /> +<location y=" -0.482422" /> +<location y=" -0.480469" /> +<location y=" -0.478516" /> +<location y=" -0.476563" /> +<location y=" -0.474609" /> +<location y=" -0.472656" /> +<location y=" -0.470703" /> +<location y=" -0.468750" /> +<location y=" -0.466797" /> +<location y=" -0.464844" /> +<location y=" -0.462891" /> +<location y=" -0.460938" /> +<location y=" -0.458984" /> +<location y=" -0.457031" /> +<location y=" -0.455078" /> +<location y=" -0.453125" /> +<location y=" -0.451172" /> +<location y=" -0.449219" /> +<location y=" -0.447266" /> +<location y=" -0.445313" /> +<location y=" -0.443359" /> +<location y=" -0.441406" /> +<location y=" -0.439453" /> +<location y=" -0.437500" /> +<location y=" -0.435547" /> +<location y=" -0.433594" /> +<location y=" -0.431641" /> +<location y=" -0.429688" /> +<location y=" -0.427734" /> +<location y=" -0.425781" /> +<location y=" -0.423828" /> +<location y=" -0.421875" /> +<location y=" -0.419922" /> +<location y=" -0.417969" /> +<location y=" -0.416016" /> +<location y=" -0.414063" /> +<location y=" -0.412109" /> +<location y=" -0.410156" /> +<location y=" -0.408203" /> +<location y=" -0.406250" /> +<location y=" -0.404297" /> +<location y=" -0.402344" /> +<location y=" -0.400391" /> +<location y=" -0.398438" /> +<location y=" -0.396484" /> +<location y=" -0.394531" /> +<location y=" -0.392578" /> +<location y=" -0.390625" /> +<location y=" -0.388672" /> +<location y=" -0.386719" /> +<location y=" -0.384766" /> +<location y=" -0.382813" /> +<location y=" -0.380859" /> +<location y=" -0.378906" /> +<location y=" -0.376953" /> +<location y=" -0.375000" /> +<location y=" -0.373047" /> +<location y=" -0.371094" /> +<location y=" -0.369141" /> +<location y=" -0.367188" /> +<location y=" -0.365234" /> +<location y=" -0.363281" /> +<location y=" -0.361328" /> +<location y=" -0.359375" /> +<location y=" -0.357422" /> +<location y=" -0.355469" /> +<location y=" -0.353516" /> +<location y=" -0.351563" /> +<location y=" -0.349609" /> +<location y=" -0.347656" /> +<location y=" -0.345703" /> +<location y=" -0.343750" /> +<location y=" -0.341797" /> +<location y=" -0.339844" /> +<location y=" -0.337891" /> +<location y=" -0.335938" /> +<location y=" -0.333984" /> +<location y=" -0.332031" /> +<location y=" -0.330078" /> +<location y=" -0.328125" /> +<location y=" -0.326172" /> +<location y=" -0.324219" /> +<location y=" -0.322266" /> +<location y=" -0.320313" /> +<location y=" -0.318359" /> +<location y=" -0.316406" /> +<location y=" -0.314453" /> +<location y=" -0.312500" /> +<location y=" -0.310547" /> +<location y=" -0.308594" /> +<location y=" -0.306641" /> +<location y=" -0.304688" /> +<location y=" -0.302734" /> +<location y=" -0.300781" /> +<location y=" -0.298828" /> +<location y=" -0.296875" /> +<location y=" -0.294922" /> +<location y=" -0.292969" /> +<location y=" -0.291016" /> +<location y=" -0.289063" /> +<location y=" -0.287109" /> +<location y=" -0.285156" /> +<location y=" -0.283203" /> +<location y=" -0.281250" /> +<location y=" -0.279297" /> +<location y=" -0.277344" /> +<location y=" -0.275391" /> +<location y=" -0.273438" /> +<location y=" -0.271484" /> +<location y=" -0.269531" /> +<location y=" -0.267578" /> +<location y=" -0.265625" /> +<location y=" -0.263672" /> +<location y=" -0.261719" /> +<location y=" -0.259766" /> +<location y=" -0.257813" /> +<location y=" -0.255859" /> +<location y=" -0.253906" /> +<location y=" -0.251953" /> +<location y=" -0.250000" /> +<location y=" -0.248047" /> +<location y=" -0.246094" /> +<location y=" -0.244141" /> +<location y=" -0.242188" /> +<location y=" -0.240234" /> +<location y=" -0.238281" /> +<location y=" -0.236328" /> +<location y=" -0.234375" /> +<location y=" -0.232422" /> +<location y=" -0.230469" /> +<location y=" -0.228516" /> +<location y=" -0.226563" /> +<location y=" -0.224609" /> +<location y=" -0.222656" /> +<location y=" -0.220703" /> +<location y=" -0.218750" /> +<location y=" -0.216797" /> +<location y=" -0.214844" /> +<location y=" -0.212891" /> +<location y=" -0.210938" /> +<location y=" -0.208984" /> +<location y=" -0.207031" /> +<location y=" -0.205078" /> +<location y=" -0.203125" /> +<location y=" -0.201172" /> +<location y=" -0.199219" /> +<location y=" -0.197266" /> +<location y=" -0.195313" /> +<location y=" -0.193359" /> +<location y=" -0.191406" /> +<location y=" -0.189453" /> +<location y=" -0.187500" /> +<location y=" -0.185547" /> +<location y=" -0.183594" /> +<location y=" -0.181641" /> +<location y=" -0.179688" /> +<location y=" -0.177734" /> +<location y=" -0.175781" /> +<location y=" -0.173828" /> +<location y=" -0.171875" /> +<location y=" -0.169922" /> +<location y=" -0.167969" /> +<location y=" -0.166016" /> +<location y=" -0.164063" /> +<location y=" -0.162109" /> +<location y=" -0.160156" /> +<location y=" -0.158203" /> +<location y=" -0.156250" /> +<location y=" -0.154297" /> +<location y=" -0.152344" /> +<location y=" -0.150391" /> +<location y=" -0.148438" /> +<location y=" -0.146484" /> +<location y=" -0.144531" /> +<location y=" -0.142578" /> +<location y=" -0.140625" /> +<location y=" -0.138672" /> +<location y=" -0.136719" /> +<location y=" -0.134766" /> +<location y=" -0.132813" /> +<location y=" -0.130859" /> +<location y=" -0.128906" /> +<location y=" -0.126953" /> +<location y=" -0.125000" /> +<location y=" -0.123047" /> +<location y=" -0.121094" /> +<location y=" -0.119141" /> +<location y=" -0.117188" /> +<location y=" -0.115234" /> +<location y=" -0.113281" /> +<location y=" -0.111328" /> +<location y=" -0.109375" /> +<location y=" -0.107422" /> +<location y=" -0.105469" /> +<location y=" -0.103516" /> +<location y=" -0.101563" /> +<location y=" -0.099609" /> +<location y=" -0.097656" /> +<location y=" -0.095703" /> +<location y=" -0.093750" /> +<location y=" -0.091797" /> +<location y=" -0.089844" /> +<location y=" -0.087891" /> +<location y=" -0.085938" /> +<location y=" -0.083984" /> +<location y=" -0.082031" /> +<location y=" -0.080078" /> +<location y=" -0.078125" /> +<location y=" -0.076172" /> +<location y=" -0.074219" /> +<location y=" -0.072266" /> +<location y=" -0.070313" /> +<location y=" -0.068359" /> +<location y=" -0.066406" /> +<location y=" -0.064453" /> +<location y=" -0.062500" /> +<location y=" -0.060547" /> +<location y=" -0.058594" /> +<location y=" -0.056641" /> +<location y=" -0.054688" /> +<location y=" -0.052734" /> +<location y=" -0.050781" /> +<location y=" -0.048828" /> +<location y=" -0.046875" /> +<location y=" -0.044922" /> +<location y=" -0.042969" /> +<location y=" -0.041016" /> +<location y=" -0.039063" /> +<location y=" -0.037109" /> +<location y=" -0.035156" /> +<location y=" -0.033203" /> +<location y=" -0.031250" /> +<location y=" -0.029297" /> +<location y=" -0.027344" /> +<location y=" -0.025391" /> +<location y=" -0.023438" /> +<location y=" -0.021484" /> +<location y=" -0.019531" /> +<location y=" -0.017578" /> +<location y=" -0.015625" /> +<location y=" -0.013672" /> +<location y=" -0.011719" /> +<location y=" -0.009766" /> +<location y=" -0.007812" /> +<location y=" -0.005859" /> +<location y=" -0.003906" /> +<location y=" -0.001953" /> +<location y=" 0.000000" /> +<location y=" 0.001953" /> +<location y=" 0.003906" /> +<location y=" 0.005859" /> +<location y=" 0.007813" /> +<location y=" 0.009766" /> +<location y=" 0.011719" /> +<location y=" 0.013672" /> +<location y=" 0.015625" /> +<location y=" 0.017578" /> +<location y=" 0.019531" /> +<location y=" 0.021484" /> +<location y=" 0.023438" /> +<location y=" 0.025391" /> +<location y=" 0.027344" /> +<location y=" 0.029297" /> +<location y=" 0.031250" /> +<location y=" 0.033203" /> +<location y=" 0.035156" /> +<location y=" 0.037109" /> +<location y=" 0.039063" /> +<location y=" 0.041016" /> +<location y=" 0.042969" /> +<location y=" 0.044922" /> +<location y=" 0.046875" /> +<location y=" 0.048828" /> +<location y=" 0.050781" /> +<location y=" 0.052734" /> +<location y=" 0.054688" /> +<location y=" 0.056641" /> +<location y=" 0.058594" /> +<location y=" 0.060547" /> +<location y=" 0.062500" /> +<location y=" 0.064453" /> +<location y=" 0.066406" /> +<location y=" 0.068359" /> +<location y=" 0.070313" /> +<location y=" 0.072266" /> +<location y=" 0.074219" /> +<location y=" 0.076172" /> +<location y=" 0.078125" /> +<location y=" 0.080078" /> +<location y=" 0.082031" /> +<location y=" 0.083984" /> +<location y=" 0.085938" /> +<location y=" 0.087891" /> +<location y=" 0.089844" /> +<location y=" 0.091797" /> +<location y=" 0.093750" /> +<location y=" 0.095703" /> +<location y=" 0.097656" /> +<location y=" 0.099609" /> +<location y=" 0.101563" /> +<location y=" 0.103516" /> +<location y=" 0.105469" /> +<location y=" 0.107422" /> +<location y=" 0.109375" /> +<location y=" 0.111328" /> +<location y=" 0.113281" /> +<location y=" 0.115234" /> +<location y=" 0.117188" /> +<location y=" 0.119141" /> +<location y=" 0.121094" /> +<location y=" 0.123047" /> +<location y=" 0.125000" /> +<location y=" 0.126953" /> +<location y=" 0.128906" /> +<location y=" 0.130859" /> +<location y=" 0.132813" /> +<location y=" 0.134766" /> +<location y=" 0.136719" /> +<location y=" 0.138672" /> +<location y=" 0.140625" /> +<location y=" 0.142578" /> +<location y=" 0.144531" /> +<location y=" 0.146484" /> +<location y=" 0.148438" /> +<location y=" 0.150391" /> +<location y=" 0.152344" /> +<location y=" 0.154297" /> +<location y=" 0.156250" /> +<location y=" 0.158203" /> +<location y=" 0.160156" /> +<location y=" 0.162109" /> +<location y=" 0.164063" /> +<location y=" 0.166016" /> +<location y=" 0.167969" /> +<location y=" 0.169922" /> +<location y=" 0.171875" /> +<location y=" 0.173828" /> +<location y=" 0.175781" /> +<location y=" 0.177734" /> +<location y=" 0.179688" /> +<location y=" 0.181641" /> +<location y=" 0.183594" /> +<location y=" 0.185547" /> +<location y=" 0.187500" /> +<location y=" 0.189453" /> +<location y=" 0.191406" /> +<location y=" 0.193359" /> +<location y=" 0.195313" /> +<location y=" 0.197266" /> +<location y=" 0.199219" /> +<location y=" 0.201172" /> +<location y=" 0.203125" /> +<location y=" 0.205078" /> +<location y=" 0.207031" /> +<location y=" 0.208984" /> +<location y=" 0.210938" /> +<location y=" 0.212891" /> +<location y=" 0.214844" /> +<location y=" 0.216797" /> +<location y=" 0.218750" /> +<location y=" 0.220703" /> +<location y=" 0.222656" /> +<location y=" 0.224609" /> +<location y=" 0.226563" /> +<location y=" 0.228516" /> +<location y=" 0.230469" /> +<location y=" 0.232422" /> +<location y=" 0.234375" /> +<location y=" 0.236328" /> +<location y=" 0.238281" /> +<location y=" 0.240234" /> +<location y=" 0.242188" /> +<location y=" 0.244141" /> +<location y=" 0.246094" /> +<location y=" 0.248047" /> +<location y=" 0.250000" /> +<location y=" 0.251953" /> +<location y=" 0.253906" /> +<location y=" 0.255859" /> +<location y=" 0.257813" /> +<location y=" 0.259766" /> +<location y=" 0.261719" /> +<location y=" 0.263672" /> +<location y=" 0.265625" /> +<location y=" 0.267578" /> +<location y=" 0.269531" /> +<location y=" 0.271484" /> +<location y=" 0.273438" /> +<location y=" 0.275391" /> +<location y=" 0.277344" /> +<location y=" 0.279297" /> +<location y=" 0.281250" /> +<location y=" 0.283203" /> +<location y=" 0.285156" /> +<location y=" 0.287109" /> +<location y=" 0.289063" /> +<location y=" 0.291016" /> +<location y=" 0.292969" /> +<location y=" 0.294922" /> +<location y=" 0.296875" /> +<location y=" 0.298828" /> +<location y=" 0.300781" /> +<location y=" 0.302734" /> +<location y=" 0.304688" /> +<location y=" 0.306641" /> +<location y=" 0.308594" /> +<location y=" 0.310547" /> +<location y=" 0.312500" /> +<location y=" 0.314453" /> +<location y=" 0.316406" /> +<location y=" 0.318359" /> +<location y=" 0.320313" /> +<location y=" 0.322266" /> +<location y=" 0.324219" /> +<location y=" 0.326172" /> +<location y=" 0.328125" /> +<location y=" 0.330078" /> +<location y=" 0.332031" /> +<location y=" 0.333984" /> +<location y=" 0.335938" /> +<location y=" 0.337891" /> +<location y=" 0.339844" /> +<location y=" 0.341797" /> +<location y=" 0.343750" /> +<location y=" 0.345703" /> +<location y=" 0.347656" /> +<location y=" 0.349609" /> +<location y=" 0.351563" /> +<location y=" 0.353516" /> +<location y=" 0.355469" /> +<location y=" 0.357422" /> +<location y=" 0.359375" /> +<location y=" 0.361328" /> +<location y=" 0.363281" /> +<location y=" 0.365234" /> +<location y=" 0.367188" /> +<location y=" 0.369141" /> +<location y=" 0.371094" /> +<location y=" 0.373047" /> +<location y=" 0.375000" /> +<location y=" 0.376953" /> +<location y=" 0.378906" /> +<location y=" 0.380859" /> +<location y=" 0.382813" /> +<location y=" 0.384766" /> +<location y=" 0.386719" /> +<location y=" 0.388672" /> +<location y=" 0.390625" /> +<location y=" 0.392578" /> +<location y=" 0.394531" /> +<location y=" 0.396484" /> +<location y=" 0.398438" /> +<location y=" 0.400391" /> +<location y=" 0.402344" /> +<location y=" 0.404297" /> +<location y=" 0.406250" /> +<location y=" 0.408203" /> +<location y=" 0.410156" /> +<location y=" 0.412109" /> +<location y=" 0.414063" /> +<location y=" 0.416016" /> +<location y=" 0.417969" /> +<location y=" 0.419922" /> +<location y=" 0.421875" /> +<location y=" 0.423828" /> +<location y=" 0.425781" /> +<location y=" 0.427734" /> +<location y=" 0.429688" /> +<location y=" 0.431641" /> +<location y=" 0.433594" /> +<location y=" 0.435547" /> +<location y=" 0.437500" /> +<location y=" 0.439453" /> +<location y=" 0.441406" /> +<location y=" 0.443359" /> +<location y=" 0.445313" /> +<location y=" 0.447266" /> +<location y=" 0.449219" /> +<location y=" 0.451172" /> +<location y=" 0.453125" /> +<location y=" 0.455078" /> +<location y=" 0.457031" /> +<location y=" 0.458984" /> +<location y=" 0.460938" /> +<location y=" 0.462891" /> +<location y=" 0.464844" /> +<location y=" 0.466797" /> +<location y=" 0.468750" /> +<location y=" 0.470703" /> +<location y=" 0.472656" /> +<location y=" 0.474609" /> +<location y=" 0.476563" /> +<location y=" 0.478516" /> +<location y=" 0.480469" /> +<location y=" 0.482422" /> +<location y=" 0.484375" /> +<location y=" 0.486328" /> +<location y=" 0.488281" /> +<location y=" 0.490234" /> +<location y=" 0.492188" /> +<location y=" 0.494141" /> +<location y=" 0.496094" /> +<location y=" 0.498047" /> +<location y=" 0.500000" /> + </component> + </type> + + <type name="monitor" is="monitor"> + <properties/> + <cylinder id="some-shape"> + <centre-of-bottom-base r="0.0" t="0.0" p="0.0" /> + <axis x="0.0" y="0.0" z="1.0" /> + <radius val="0.01" /> + <height val="0.03" /> + </cylinder> + <algebra val="some-shape" /> + </type> + + <type name="pixel" is="detector"> + <cylinder id="cyl-approx"> + <centre-of-bottom-base r="0.0" t="0.0" p="0.0" /> + <axis x="0.0" y="0.2" z="0.0" /> + <radius val="0.0127" /> + <height val=" 0.002" /> + </cylinder> + <algebra val="cyl-approx" /> + </type> + + + +<!-- MONITOR ID LISTS --> + <idlist idname="monitors"> + <id start="1" end="3" /> + </idlist> + <!-- DETECTOR ID LISTS --> + <idlist idname="ALFdetectors"> + <id start="3103000" end="3103511" /> + <id start="3105000" end="3105511" /> + <id start="3109000" end="3109511" /> + <id start="3111000" end="3111511" /> + <id start="3113000" end="3113511" /> + <id start="3115000" end="3115511" /> + <id start="3119000" end="3119511" /> + <id start="3121000" end="3121511" /> + <id start="3203000" end="3203511" /> + <id start="3205000" end="3205511" /> + <id start="3209000" end="3209511" /> + <id start="3211000" end="3211511" /> + <id start="3213000" end="3213511" /> + <id start="3215000" end="3215511" /> + <id start="3219000" end="3219511" /> + <id start="3221000" end="3221511" /> + <id start="3303000" end="3303511" /> + <id start="3305000" end="3305511" /> + <id start="3309000" end="3309511" /> + <id start="3311000" end="3311511" /> + <id start="3313000" end="3313511" /> + <id start="3315000" end="3315511" /> + <id start="3319000" end="3319511" /> + <id start="3321000" end="3321511" /> + </idlist> + +<!-- <idlist idname="ALFpack1"> + <id start="1" end="256" /> + <id start="257" end="512" /> + <id start="513" end="768" /> + <id start="769" end="1024" /> + <id start="1025" end="1280" /> + <id start="1281" end="1536" /> + <id start="1537" end="1792" /> + <id start="1793" end="2048" /> + </idlist> + <idlist idname="ALFpack2"> + <id start="2049" end="2304" /> + <id start="2305" end="2560" /> + <id start="2561" end="2816" /> + <id start="2817" end="3072" /> + <id start="3073" end="3328" /> + <id start="3329" end="3584" /> + <id start="3585" end="3840" /> + <id start="3841" end="4096" /> + </idlist> + <idlist idname="ALFpack3"> + <id start="4097" end="4352" /> + <id start="4353" end="4608" /> + <id start="4609" end="4864" /> + <id start="4865" end="5120" /> + <id start="5121" end="5376" /> + <id start="5377" end="5632" /> + <id start="5633" end="5888" /> + <id start="5889" end="6144" /> + </idlist> --> +<!-- + <idlist idname="ALFextratube1"> + <id start="6145" end="6400" /> + </idlist> + <idlist idname="ALFextratube2"> + <id start="6401" end="6656" /> + </idlist> +--> +</instrument> diff --git a/Code/Mantid/instrument/DNS_Definition_PAonly.xml b/Code/Mantid/instrument/DNS_Definition_PAonly.xml new file mode 100644 index 0000000000000000000000000000000000000000..b9949f4781afadaf90bf51091f12d43616b2b0cd --- /dev/null +++ b/Code/Mantid/instrument/DNS_Definition_PAonly.xml @@ -0,0 +1,87 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- For help on the notation used to specify an Instrument Definition File see http://www.mantidproject.org/IDF --> +<instrument name="DNS" valid-from="1900-01-31 23:59:59" valid-to="2100-01-31 23:59:59" last-modified="2015-03-25 10:17:17"> + <!-- Author: m.ganeva@fz-juelich.de --> + <defaults> + <length unit="meter" /> + <angle unit="degree" /> + <reference-frame> + <!-- The z-axis is set parallel to and in the direction of the beam. the + y-axis points up and the coordinate system is right handed. --> + <along-beam axis="z" /> + <pointing-up axis="y" /> + <handedness val="right" /> + </reference-frame> + </defaults> + <!-- moderator --> + <component type="moderator"> + <location z="-2.27" /> + </component> + <type name="moderator" is="Source"></type> + <!-- monitor --> + <component type="monitor" idlist="monitor"> + <location z="-0.229" /> + </component> + <type name="monitor" is="monitor"></type> + <idlist idname="monitor"> + <id val="-1"/> + </idlist> + <!-- Sample position --> + <component type="sample-position"> + <location y="0.0" x="0.0" z="0.0" /> + </component> + <type name="sample-position" is="SamplePos" /> + <idlist idname="detectors"> + <id start="1" end="24" /> + </idlist> + <!-- Detector list def --> + <component type="detectors" idlist="detectors"> + <location /> + </component> + <!-- Detector Banks --> + <type name="detectors"> + <component type="bank0"> + <location> + <parameter name="r-position"> + <value val="0"/> + </parameter> + <parameter name="t-position"> + <logfile id="deterota" eq="0.0+value" extract-single-value-as="first_value"/> + </parameter> + <parameter name="p-position"> + <value val="0"/> + </parameter> + <parameter name="rotx"> + <value val="0"/> + </parameter> + <parameter name="roty"> + <logfile id="deterota" eq="0.0+value" extract-single-value-as="first_value"/> + </parameter> + <parameter name="rotz"> + <value val="0"/> + </parameter> + </location> + </component> + </type> + <!-- Definition of the PA detector bank (made of 24 tubes) --> + <type name="bank0"> + <component type="standard_tube"> + <locations r="0.800000" t="0.000000" t-end="-115.0" p="0.0" name="tube_" n-elements="24" /> + </component> + </type> + <!-- Definition of standard_tube --> + <type name="standard_tube"> + <component type="standard_pixel"> + <location y="0.0" /> + </component> + </type> + <type name="standard_pixel" is="detector"> + <cylinder id="shape"> + <centre-of-bottom-base x="0.0" y="-0.075" z="0.0" /> + <axis x="0.0" y="1.0" z="0.0" /> + <radius val="0.0127" /> + <height val=".15" /> + </cylinder> + <algebra val="shape" /> + </type> +</instrument> diff --git a/Code/Mantid/instrument/Facilities.xml b/Code/Mantid/instrument/Facilities.xml index 5b7c6c8b41a29ad5343a1cd3314291b9d4703f2c..1213adaf37862f103db1ccae6db21105283eec1a 100644 --- a/Code/Mantid/instrument/Facilities.xml +++ b/Code/Mantid/instrument/Facilities.xml @@ -6,7 +6,7 @@ <archiveSearch plugin="ISISDataSearch" /> </archive> - <computeResource name="SCARF@STFC"> + <computeResource name="SCARF@STFC" JobManagerType="SCARFLSFJobManager"> <baseURL>https://portal.scarf.rl.ac.uk</baseURL> </computeResource> diff --git a/Code/Mantid/instrument/MAPS_Definition.xml b/Code/Mantid/instrument/MAPS_Definition.xml index 5bef2b032e4eb8cd001902eace891e0d78747a31..5945f1ff1bdb314b8188dd48326e052f114087e9 100644 --- a/Code/Mantid/instrument/MAPS_Definition.xml +++ b/Code/Mantid/instrument/MAPS_Definition.xml @@ -6,7 +6,7 @@ xsi:schemaLocation="http://www.mantidproject.org/IDF/1.0 http://schema.mantidproject.org/IDF/1.0/IDFSchema.xsd" name="MAPS" valid-from ="1900-01-31 23:59:59" valid-to ="2100-01-31 23:59:59" - last-modified="2011-09-30 13:30:00"> + last-modified="2015-03-01 13:30:00"> <defaults> <length unit="meter"/> diff --git a/Code/Mantid/instrument/MAPS_Parameters.xml b/Code/Mantid/instrument/MAPS_Parameters.xml index 0e961f2d2e597dab1ada0b56388b229a47b48e5b..eabd02d8f5eae12c97d3e45520699193ed0e5637 100644 --- a/Code/Mantid/instrument/MAPS_Parameters.xml +++ b/Code/Mantid/instrument/MAPS_Parameters.xml @@ -391,7 +391,7 @@ </parameter> <!-- The semicolon separated list of possible log names, containing information on crystl rotation. - First found log will be used togethere with motor_offset to identify crystal rotation + First found log will be used togethere with motor_offset to identify crystal rotation (psi in Horace) --> <parameter name="motor_log_names" type="string"> <value val="wccr;Rot"/> diff --git a/Code/Mantid/instrument/MARI_Definition.xml b/Code/Mantid/instrument/MARI_Definition.xml index ad7332298c5643d768cad43305e34e5e19d997f5..b4e2f79bd9885fc25b5748eda3987589331b13b5 100644 --- a/Code/Mantid/instrument/MARI_Definition.xml +++ b/Code/Mantid/instrument/MARI_Definition.xml @@ -6,7 +6,7 @@ xsi:schemaLocation="http://www.mantidproject.org/IDF/1.0 http://schema.mantidproject.org/IDF/1.0/IDFSchema.xsd" name="MARI" valid-from ="1900-01-31 23:59:59" valid-to ="2100-01-31 23:59:59" - last-modified="2009-09-15 00:00:00"> + last-modified="2015-03-01 00:00:00"> <defaults> <length unit="meter"/> diff --git a/Code/Mantid/instrument/MERLIN_Definition_after2013_4.xml b/Code/Mantid/instrument/MERLIN_Definition_after2013_4.xml index c87581b895a84e9531eb4ab767201b35af1b6856..fd69107e5c7fdd2600996cd426f5dfb5fb84af57 100644 --- a/Code/Mantid/instrument/MERLIN_Definition_after2013_4.xml +++ b/Code/Mantid/instrument/MERLIN_Definition_after2013_4.xml @@ -6,7 +6,7 @@ xsi:schemaLocation="http://www.mantidproject.org/IDF/1.0 http://schema.mantidproject.org/IDF/1.0/IDFSchema.xsd" name="MERLIN" valid-from ="2014-02-10 00:00:01" valid-to ="2100-01-31 23:59:59" - last-modified="2012-03-19 12:00:05"> + last-modified="2015-03-01 12:00:05"> <defaults> <length unit="meter"/> @@ -27,7 +27,7 @@ The data for Merlin was obtained from Robert Bewley. 2012-05-17 - added names to tubes - 2013-11-14 - use locations tag in tube definitions + 2013-11-14 - use locations tag in tube definitions --> diff --git a/Code/Mantid/scripts/Inelastic/Direct/DirectEnergyConversion.py b/Code/Mantid/scripts/Inelastic/Direct/DirectEnergyConversion.py index 6ef761fff5569b7884017216b263f2bce72b93f5..d6e3f5352f0fc883cd33a91e0640b55fa8a3bcc8 100644 --- a/Code/Mantid/scripts/Inelastic/Direct/DirectEnergyConversion.py +++ b/Code/Mantid/scripts/Inelastic/Direct/DirectEnergyConversion.py @@ -342,7 +342,9 @@ class DirectEnergyConversion(object): # inform user on what parameters have changed from script or gui # if monovan present, check if abs_norm_ parameters are set self.prop_man.log_changed_values('notice') - + # before trying to process new results, let's remove from memory old results + # if any present and they are not needed any more (user have not renamed them) + self._clear_old_results() start_time = time.time() @@ -420,7 +422,9 @@ class DirectEnergyConversion(object): num_ei_cuts = len(self.incident_energy) if self.check_background: # find the count rate seen in the regions of the histograms defined - # as the background regions, if the user defined such region + # as the background regions, if the user defined such region. + # In multirep mode this has to be done here, as workspace + # will be cut in chunks and bg regions -- removed ws_base = PropertyManager.sample_run.get_workspace() bkgd_range = self.bkgd_range bkgr_ws = self._find_or_build_bkgr_ws(ws_base,bkgd_range[0],bkgd_range[1]) @@ -430,7 +434,9 @@ class DirectEnergyConversion(object): else: self._multirep_mode = False num_ei_cuts = 0 - +#------------------------------------------------------------------------------------------ +# Main loop over incident energies +#------------------------------------------------------------------------------------------ cut_ind = 0 # do not do enumerate if it generates all sequence at once # -- code below uses current energy state from PropertyManager.incident_energy for ei_guess in PropertyManager.incident_energy: @@ -475,6 +481,7 @@ class DirectEnergyConversion(object): if out_ws_name: if self._multirep_mode: result.append(deltaE_ws_sample) + self._old_runs_list.append(deltaE_ws_sample.name()) else: results_name = deltaE_ws_sample.name() if results_name != out_ws_name: @@ -483,6 +490,9 @@ class DirectEnergyConversion(object): else: # delete workspace if no output is requested self.sample_run = None #end_for +#------------------------------------------------------------------------------------------ +# END Main loop over incident energies +#------------------------------------------------------------------------------------------ end_time = time.time() prop_man.log("*** Elapsed time = {0} sec".format(end_time - start_time),'notice') @@ -838,13 +848,16 @@ class DirectEnergyConversion(object): workspace = PropertyManager.sample_run.get_workspace() spectra_id = self.prop_man.multirep_tof_specta_list - if not spectra_id: + if not spectra_id or len(spectra_id) == 0: + self.prop_man.log("*** WARNING! no multirep spectra found in IDF! using first existing spectra number\n"\ + " This is wrong unless sample-detector distances of the instrument are all equal.",\ + 'warning') spectra_id = [1] eMin,dE,eMax = PropertyManager.energy_bins.get_abs_range(self.prop_man) ei = PropertyManager.incident_energy.get_current() en_list = [eMin,eMin + dE,eMax - dE,eMax] - TOF_range = DirectEnergyConversion.get_TOF_for_energies(workspace,en_list,spectra_id,ei) + TOF_range = self.get_TOF_for_energies(workspace,en_list,spectra_id,ei) def process_block(tof_range): @@ -867,15 +880,16 @@ class DirectEnergyConversion(object): else: tof_min,t_step,tof_max = process_block(TOF_range) #end - return (tof_min,t_step,tof_max) + # add 5% for detectors specified in Par file are shifted a bit and not min-max det any more + return (0.95*tof_min,t_step,1.05*tof_max) + #return (tof_min,t_step,tof_max) # - @staticmethod - def get_TOF_for_energies(workspace,energy_list,specID_list,ei=None,debug_mode=False): + def get_TOF_for_energies(self,workspace,energy_list,specID_list,ei=None,debug_mode=False): """ Method to find what TOF range corresponds to given energy range for given workspace and detectors. Input: - workspace pointer to workspace with instrument attached. + workspace handler for the workspace with instrument attached. energy_list the list of input energies to process detID_list list of detectors to find ei incident energy. If present, TOF range is calculated in direct mode, @@ -884,6 +898,37 @@ class DirectEnergyConversion(object): Returns: list of TOF corresponding to input energies list. """ + if ei: + ei_guess = PropertyManager.incident_energy.get_current() + fix_ei = self.fix_ei + ei_mon_spectra = self.ei_mon_spectra + monitor_ws = PropertyManager.sample_run.get_monitors_ws(ei_mon_spectra,workspace) + if monitor_ws is None: # no shifting to monitor position + src_name = None + mon1_peak = 0 + else: + mon_2_spec_ID = int(ei_mon_spectra[0]) + # Calculate the incident energy and TOF when the particles access Monitor1 + try: + ei,mon1_peak,mon1_index,tzero = \ + GetEi(InputWorkspace=monitor_ws, Monitor1Spec=mon_2_spec_ID, + Monitor2Spec=int(ei_mon_spectra[1]), + EnergyEstimate=ei_guess,FixEi=fix_ei) + mon1_det = monitor_ws.getDetector(mon1_index) + mon1_pos = mon1_det.getPos() + src_name = monitor_ws.getInstrument().getSource().getName() + except : + src_name = None + mon1_peak = 0 + en_bin = [energy_list[0],energy_list[1]-energy_list[0],energy_list[3]] + self.prop_man.log("*** WARNING: message from multirep chunking procedure: get_TOF_for_energies:\n"\ + " not able to identify energy peak looking for TOF range for incident energy: {0}meV, binning: {1}\n"\ + " Continuing under assumption that incident neutrons arrive at source at time=0".\ + format(ei_guess,en_bin),'warning') + else: + mon1_peak = 0 + #end if + template_ws_name = '_energy_range_ws' range_ws_name = '_TOF_range_ws' y = [1] * (len(energy_list) - 1) @@ -893,11 +938,14 @@ class DirectEnergyConversion(object): ExtractSingleSpectrum(InputWorkspace=workspace, OutputWorkspace=template_ws_name, WorkspaceIndex=ind) if ei: CreateWorkspace(OutputWorkspace=range_ws_name,NSpec = 1,DataX=energy_list,DataY=y,UnitX='DeltaE',ParentWorkspace=template_ws_name) + if src_name: + MoveInstrumentComponent(Workspace=range_ws_name,ComponentName= src_name, X=mon1_pos.getX(), + Y=mon1_pos.getY(), Z=mon1_pos.getZ(), RelativePosition=False) range_ws = ConvertUnits(InputWorkspace=range_ws_name,OutputWorkspace=range_ws_name,Target='TOF',EMode='Direct',EFixed=ei) else: CreateWorkspace(OutputWorkspace=range_ws_name,NSpec = 1,DataX=energy_list,DataY=y,UnitX='Energy',ParentWorkspace=template_ws_name) range_ws = ConvertUnits(InputWorkspace=range_ws_name,OutputWorkspace=range_ws_name,Target='TOF',EMode='Elastic') - x = range_ws.dataX(0) + x = range_ws.dataX(0)+mon1_peak TOF_range.append(x.tolist()) if not debug_mode: @@ -1224,11 +1272,15 @@ class DirectEnergyConversion(object): # workspace # processed object.__setattr__(self,'_multirep_mode',False) + # list of workspace names, processed earlier + object.__setattr__(self,'_old_runs_list',[]) + all_methods = dir(self) # define list of all existing properties, which have descriptors object.__setattr__(self,'_descriptors',extract_non_system_names(all_methods)) + if instr_name: self.initialise(instr_name,reload_instrument) #end @@ -1468,7 +1520,7 @@ class DirectEnergyConversion(object): #------------------------------------------------------------------------------- def _get_wb_inegrals(self,run): """Obtain white bean vanadium integrals either by integrating - workspace in question or cashed value + workspace in question or using cashed value """ run = self.get_run_descriptor(run) white_ws = run.get_workspace() @@ -1531,7 +1583,15 @@ class DirectEnergyConversion(object): low,upp = self.wb_integr_range white_tag = 'NormBy:{0}_IntergatedIn:{1:0>10.2f}:{2:0>10.2f}'.format(self.normalise_method,low,upp) return white_tag - + # + def _clear_old_results(self): + """Remove workspaces, processed earlier and not used any more""" + ws_list = self._old_runs_list + for ws_name in ws_list: + if ws_name in mtd: + DeleteWorkspace(ws_name) + object.__setattr__(self,'_old_runs_list',[]) + # def get_failed_spectra_list_from_masks(masked_wksp,prop_man): """Compile a list of spectra numbers that are marked as masked in the masking workspace diff --git a/Code/Mantid/scripts/Inelastic/Direct/PropertyManager.py b/Code/Mantid/scripts/Inelastic/Direct/PropertyManager.py index 5b72a5818980f75fe98d670543dba492716166fc..435d98eb403f96512989dba358aaa5e79a823756 100644 --- a/Code/Mantid/scripts/Inelastic/Direct/PropertyManager.py +++ b/Code/Mantid/scripts/Inelastic/Direct/PropertyManager.py @@ -584,7 +584,7 @@ class PropertyManager(NonIDF_Properties): ok,mess= self._check_ouptut_dir() if not ok: - mess = '*** WARNING: saving results: --> {1}'.format(mess) + mess = '*** WARNING: saving results: --> {0}'.format(mess) if fail_on_errors: self.log(mess,'warning') diff --git a/Code/Mantid/scripts/Inelastic/Direct/ReductionWrapper.py b/Code/Mantid/scripts/Inelastic/Direct/ReductionWrapper.py index d3c7ff4af87cffceee1b2c09d1c0600a96edd8b2..35a7e72238653e60840eb37a4c6e756924cbcfcf 100644 --- a/Code/Mantid/scripts/Inelastic/Direct/ReductionWrapper.py +++ b/Code/Mantid/scripts/Inelastic/Direct/ReductionWrapper.py @@ -338,11 +338,17 @@ class ReductionWrapper(object): nruns = len(runfiles) for num,file in enumerate(runfiles): red_ws = self.reduce(file) - if nruns > 1: - out_name = out_ws_name + '#{0}of{1}'.format(num + 1,nruns) - RenameWorkspace(InputWorkspace=red_ws,OutputWorkspace=out_name) - red_ws = mtd[out_name] - results.append(red_ws) + if isinstance(red_ws,list): + for ws in red_ws: + results.append(ws) + else: + if nruns == 1: + RenameWorkspace(InputWorkspace=red_ws,OutputWorkspace=out_ws_name) + results.append(mtd[out_ws_name]) + else: + OutWSName = '{0}#{1}of{2}'.format(out_ws_name,num+1,nruns) + RenameWorkspace(InputWorkspace=red_ws,OutputWorkspace=OutWSName) + results.append(mtd[OutWSName]) #end if len(results) == 1: return results[0] diff --git a/Code/Mantid/scripts/Inelastic/Direct/RunDescriptor.py b/Code/Mantid/scripts/Inelastic/Direct/RunDescriptor.py index 7e567c8e95e7b97629e0b522c665e0859b3906c5..a146d0a0c99de03dd1258a4409e8cb2b2c158b70 100644 --- a/Code/Mantid/scripts/Inelastic/Direct/RunDescriptor.py +++ b/Code/Mantid/scripts/Inelastic/Direct/RunDescriptor.py @@ -455,7 +455,10 @@ class RunDescriptor(PropDescriptor): self._run_list.set_last_ind2sum(ind) self._run_number = run_num self._run_file_path = file_path - self._fext = main_fext + if fext is None: + self._fext = None + else: + self._fext = main_fext self._ws_name = self._build_ws_name() def run_number(self): @@ -775,13 +778,16 @@ class RunDescriptor(PropDescriptor): return origin #-------------------------------------------------------------------------------------------------------------------- - def get_monitors_ws(self,monitor_ID=None): + def get_monitors_ws(self,monitors_ID=None,otherWS=None): """Get pointer to a workspace containing monitors. Explores different ways of finding monitor workspace in Mantid and returns the python pointer to the workspace which contains monitors. """ - data_ws = self.get_workspace() + if otherWS: + data_ws = otherWS + else: + data_ws = self.get_workspace() if not data_ws: return None @@ -798,25 +804,26 @@ class RunDescriptor(PropDescriptor): for specID in spec_to_mon: mon_ws = self.copy_spectrum2monitors(data_ws,mon_ws,specID) - if monitor_ID: - try: - ws_index = mon_ws.getIndexFromSpectrumNumber(monitor_ID) - except: # - mon_ws = None + if monitors_ID: + if isinstance(monitors_ID,list): + mon_list = monitors_ID + else: + mon_list = [monitors_ID] else: mon_list = self._holder.get_used_monitors_list() - for monID in mon_list: + # + for monID in mon_list: + try: + ws_ind = mon_ws.getIndexFromSpectrumNumber(int(monID)) + except: try: - ws_ind = mon_ws.getIndexFromSpectrumNumber(int(monID)) - except: - try: - monws_name = mon_ws.name() - except: - monws_name = 'None' - RunDescriptor._logger('*** Monitor workspace {0} does not have monitor with ID {1}. Monitor workspace set to None'.\ + monws_name = mon_ws.name() + except: + monws_name = 'None' + RunDescriptor._logger('*** Monitor workspace {0} does not have monitor with ID {1}. Monitor workspace set to None'.\ format(monws_name,monID),'warning') - mon_ws = None - break + mon_ws = None + break return mon_ws #-------------------------------------------------------------------------------------------------------------------- def is_existing_ws(self): diff --git a/Code/Mantid/scripts/Inelastic/IndirectAbsCor.py b/Code/Mantid/scripts/Inelastic/IndirectAbsCor.py index bd2855548e4a6196cb2d27547ab29e7d28284c34..3f7b40f777eb10a18243316b4de8b0d6d37bb77c 100644 --- a/Code/Mantid/scripts/Inelastic/IndirectAbsCor.py +++ b/Code/Mantid/scripts/Inelastic/IndirectAbsCor.py @@ -193,25 +193,28 @@ def AbsRun(inputWS, geom, beam, ncan, size, density, sigs, siga, avar, Save): accWS = name + '_acc' fname = name + '_abs' + log_names = [item[0] for item in sample_logs] + log_values = [item[1] for item in sample_logs] + CreateWorkspace(OutputWorkspace=assWS, DataX=dataX, DataY=dataA1, NSpec=ndet, UnitX='Wavelength', VerticalAxisUnit=v_axis_unit, VerticalAxisValues=v_axis_values) - addSampleLogs(assWS, sample_logs) + AddSampleLogMultiple(Workspace=assWS, LogNames=log_names, LogValues=log_values) CreateWorkspace(OutputWorkspace=asscWS, DataX=dataX, DataY=dataA2, NSpec=ndet, UnitX='Wavelength', VerticalAxisUnit=v_axis_unit, VerticalAxisValues=v_axis_values) - addSampleLogs(asscWS, sample_logs) + AddSampleLogMultiple(Workspace=asscWS, LogNames=log_names, LogValues=log_values) CreateWorkspace(OutputWorkspace=acscWS, DataX=dataX, DataY=dataA3, NSpec=ndet, UnitX='Wavelength', VerticalAxisUnit=v_axis_unit, VerticalAxisValues=v_axis_values) - addSampleLogs(acscWS, sample_logs) + AddSampleLogMultiple(Workspace=acscWS, LogNames=log_names, LogValues=log_values) CreateWorkspace(OutputWorkspace=accWS, DataX=dataX, DataY=dataA4, NSpec=ndet, UnitX='Wavelength', VerticalAxisUnit=v_axis_unit, VerticalAxisValues=v_axis_values) - addSampleLogs(accWS, sample_logs) + AddSampleLogMultiple(Workspace=accWS, LogNames=log_names, LogValues=log_values) group = assWS + ',' + asscWS + ',' + acscWS + ',' + accWS GroupWorkspaces(InputWorkspaces=group, OutputWorkspace=fname) diff --git a/Code/Mantid/scripts/Inelastic/IndirectCommon.py b/Code/Mantid/scripts/Inelastic/IndirectCommon.py index 7804beeac9c0d789bfdf57db35304691f364d11c..b96219f3b30d0ad6eb8f76acbf3fcef637b0db26 100644 --- a/Code/Mantid/scripts/Inelastic/IndirectCommon.py +++ b/Code/Mantid/scripts/Inelastic/IndirectCommon.py @@ -545,23 +545,3 @@ def convertParametersToWorkspace(params_table, x_column, param_names, output_nam axis.setLabel(i, name) mtd[output_name].replaceAxis(1, axis) - -def addSampleLogs(ws, sample_logs): - """ - Add a dictionary of logs to a workspace. - - The type of the log is inferred by the type of the value passed to the log. - - @param ws - workspace to add logs too. - @param sample_logs - dictionary of logs to append to the workspace. - """ - - for key, value in sample_logs.iteritems(): - if isinstance(value, bool): - log_type = 'String' - elif isinstance(value, (int, long, float)): - log_type = 'Number' - else: - log_type = 'String' - - AddSampleLog(Workspace=ws, LogName=key, LogType=log_type, LogText=str(value)) diff --git a/Code/Mantid/scripts/Inelastic/IndirectDataAnalysis.py b/Code/Mantid/scripts/Inelastic/IndirectDataAnalysis.py index 54e34ca44457893d7b7090a436bc0127c658a5c8..a1d11b69033a13cadda975757e3775e6e857fbc1 100644 --- a/Code/Mantid/scripts/Inelastic/IndirectDataAnalysis.py +++ b/Code/Mantid/scripts/Inelastic/IndirectDataAnalysis.py @@ -98,26 +98,28 @@ def confitSeq(inputWS, func, startX, endX, ftype, bgd, temperature=None, specMin axis = mtd[wsname].getAxis(0) axis.setUnit("MomentumTransfer") + # Handle sample logs + temp_correction = temperature is not None + CopyLogs(InputWorkspace=inputWS, OutputWorkspace=wsname) - AddSampleLog(Workspace=wsname, LogName='convolve_members', - LogType='String', LogText=str(convolve)) - AddSampleLog(Workspace=wsname, LogName="fit_program", - LogType="String", LogText='ConvFit') - AddSampleLog(Workspace=wsname, LogName='background', - LogType='String', LogText=str(bgd)) - AddSampleLog(Workspace=wsname, LogName='delta_function', - LogType='String', LogText=str(using_delta_func)) - AddSampleLog(Workspace=wsname, LogName='lorentzians', - LogType='String', LogText=str(lorentzians)) - CopyLogs(InputWorkspace=wsname, OutputWorkspace=output_workspace + "_Workspaces") + sample_logs = [('convolve_members', convolve), + ('fit_program', 'ConvFit'), + ('background', bgd), + ('delta_function', using_delta_func), + ('lorentzians', lorentzians), + ('temperature_correction', temp_correction)] - temp_correction = temperature is not None - AddSampleLog(Workspace=wsname, LogName='temperature_correction', - LogType='String', LogText=str(temp_correction)) if temp_correction: - AddSampleLog(Workspace=wsname, LogName='temperature_value', - LogType='String', LogText=str(temperature)) + sample_logs.append(('temperature_value', temperature)) + + log_names = [log[0] for log in sample_logs] + log_values = [log[1] for log in sample_logs] + AddSampleLogMultiple(Workspace=wsname, + LogNames=log_names, + LogValues=log_values) + + CopyLogs(InputWorkspace=wsname, OutputWorkspace=output_workspace + "_Workspaces") RenameWorkspace(InputWorkspace=output_workspace, OutputWorkspace=output_workspace + "_Parameters") @@ -200,8 +202,10 @@ def furyfitSeq(inputWS, func, ftype, startx, endx, spec_min=0, spec_max=None, in CopyLogs(InputWorkspace=inputWS, OutputWorkspace=fit_group) CopyLogs(InputWorkspace=inputWS, OutputWorkspace=result_workspace) - addSampleLogs(fit_group, sample_logs) - addSampleLogs(result_workspace, sample_logs) + log_names = [item[0] for item in sample_logs] + log_values = [item[1] for item in sample_logs] + AddSampleLogMultiple(Workspace=result_workspace, LogNames=log_names, LogValues=log_values) + AddSampleLogMultiple(Workspace=fit_group, LogNames=log_names, LogValues=log_values) if Save: save_workspaces = [result_workspace, fit_group] @@ -270,8 +274,10 @@ def furyfitMult(inputWS, function, ftype, startx, endx, spec_min=0, spec_max=Non CopyLogs(InputWorkspace=inputWS, OutputWorkspace=result_workspace) CopyLogs(InputWorkspace=inputWS, OutputWorkspace=fit_group) - addSampleLogs(result_workspace, sample_logs) - addSampleLogs(fit_group, sample_logs) + log_names = [item[0] for item in sample_logs] + log_values = [item[1] for item in sample_logs] + AddSampleLogMultiple(Workspace=result_workspace, LogNames=log_names, LogValues=log_values) + AddSampleLogMultiple(Workspace=fit_group, LogNames=log_names, LogValues=log_values) DeleteWorkspace(tmp_fit_workspace) @@ -282,7 +288,7 @@ def furyfitMult(inputWS, function, ftype, startx, endx, spec_min=0, spec_max=Non if Plot != 'None': furyfitPlotSeq(result_workspace, Plot) - EndTime('FuryFit Multi') + EndTime('TransformToIqtFit Multi') return result_workspace diff --git a/Code/Mantid/scripts/SCD_Reduction/ReduceSCD.config b/Code/Mantid/scripts/SCD_Reduction/ReduceSCD.config index 67b5014828afe4eb8502b3a4816760b39390420c..324b3883589caf24d49f3ea2b12b0f784a38cdd6 100644 --- a/Code/Mantid/scripts/SCD_Reduction/ReduceSCD.config +++ b/Code/Mantid/scripts/SCD_Reduction/ReduceSCD.config @@ -43,6 +43,8 @@ calibration_file_2 None # data_directory None output_directory /SNS/TOPAZ/IPTS-9890/shared/SPAnH +# Change to true for data with lots of peaks. Use False for ISAW ASCII output +output_nexus False # # If use_monitor_counts is True, then the integrated beam monitor diff --git a/Code/Mantid/scripts/SCD_Reduction/ReduceSCD_OneRun.py b/Code/Mantid/scripts/SCD_Reduction/ReduceSCD_OneRun.py index da992481ba3ac2c36cd0634d9073a5a3f2989c71..8ae81127207be15b6d7bff3d4f079f5d9f55bd07 100644 --- a/Code/Mantid/scripts/SCD_Reduction/ReduceSCD_OneRun.py +++ b/Code/Mantid/scripts/SCD_Reduction/ReduceSCD_OneRun.py @@ -72,6 +72,7 @@ calibration_file_1 = params_dictionary.get('calibration_file_1', None) calibration_file_2 = params_dictionary.get('calibration_file_2', None) data_directory = params_dictionary[ "data_directory" ] output_directory = params_dictionary[ "output_directory" ] +output_nexus = params_dictionary.get( "output_nexus", False) min_tof = params_dictionary[ "min_tof" ] max_tof = params_dictionary[ "max_tof" ] use_monitor_counts = params_dictionary[ "use_monitor_counts" ] @@ -145,7 +146,10 @@ print "\nProcessing File: " + full_name + " ......\n" # Name the files to write for this run # run_niggli_matrix_file = output_directory + "/" + run + "_Niggli.mat" -run_niggli_integrate_file = output_directory + "/" + run + "_Niggli.integrate" +if output_nexus: + run_niggli_integrate_file = output_directory + "/" + run + "_Niggli.nxs" +else: + run_niggli_integrate_file = output_directory + "/" + run + "_Niggli.integrate" # # Load the run data and find the total monitor counts @@ -219,7 +223,10 @@ IndexPeaks( PeaksWorkspace=peaks_ws, Tolerance=tolerance) # see these partial results # SaveIsawUB( InputWorkspace=peaks_ws,Filename=run_niggli_matrix_file ) -SaveIsawPeaks( InputWorkspace=peaks_ws, AppendFile=False, +if output_nexus: + SaveNexus( InputWorkspace=peaks_ws, Filename=run_niggli_integrate_file ) +else: + SaveIsawPeaks( InputWorkspace=peaks_ws, AppendFile=False, Filename=run_niggli_integrate_file ) # @@ -327,7 +334,10 @@ elif use_cylindrical_integration: # This is the only file needed, for the driving script to get a combined # result. # -SaveIsawPeaks( InputWorkspace=peaks_ws, AppendFile=False, +if output_nexus: + SaveNexus( InputWorkspace=peaks_ws, Filename=run_niggli_integrate_file ) +else: + SaveIsawPeaks( InputWorkspace=peaks_ws, AppendFile=False, Filename=run_niggli_integrate_file ) # Print warning if user is trying to integrate using the cylindrical method and transorm the cell @@ -342,13 +352,20 @@ else: if (not cell_type is None) and (not centering is None) : run_conventional_matrix_file = output_directory + "/" + run + "_" + \ cell_type + "_" + centering + ".mat" - run_conventional_integrate_file = output_directory + "/" + run + "_" + \ + if output_nexus: + run_conventional_integrate_file = output_directory + "/" + run + "_" + \ + cell_type + "_" + centering + ".nxs" + else: + run_conventional_integrate_file = output_directory + "/" + run + "_" + \ cell_type + "_" + centering + ".integrate" SelectCellOfType( PeaksWorkspace=peaks_ws,\ CellType=cell_type, Centering=centering,\ AllowPermutations=allow_perm,\ Apply=True, Tolerance=tolerance ) - SaveIsawPeaks( InputWorkspace=peaks_ws, AppendFile=False,\ + if output_nexus: + SaveNexus( InputWorkspace=peaks_ws, Filename=run_conventional_integrate_file ) + else: + SaveIsawPeaks( InputWorkspace=peaks_ws, AppendFile=False,\ Filename=run_conventional_integrate_file ) SaveIsawUB( InputWorkspace=peaks_ws, Filename=run_conventional_matrix_file ) diff --git a/Code/Mantid/scripts/SCD_Reduction/ReduceSCD_Parallel.py b/Code/Mantid/scripts/SCD_Reduction/ReduceSCD_Parallel.py index 16a978089c34d4a2f4c1ad37234f8ce01d269a62..804358531b1d668af187c5aedeea8ff4958e5339 100644 --- a/Code/Mantid/scripts/SCD_Reduction/ReduceSCD_Parallel.py +++ b/Code/Mantid/scripts/SCD_Reduction/ReduceSCD_Parallel.py @@ -84,6 +84,7 @@ params_dictionary = ReduceDictionary.LoadDictionary( *config_files ) exp_name = params_dictionary[ "exp_name" ] output_directory = params_dictionary[ "output_directory" ] +output_nexus = params_dictionary.get( "output_nexus", False) reduce_one_run_script = params_dictionary[ "reduce_one_run_script" ] slurm_queue_name = params_dictionary[ "slurm_queue_name" ] max_processes = int(params_dictionary[ "max_processes" ]) @@ -94,6 +95,7 @@ cell_type = params_dictionary[ "cell_type" ] centering = params_dictionary[ "centering" ] allow_perm = params_dictionary[ "allow_perm" ] run_nums = params_dictionary[ "run_nums" ] +data_directory = params_dictionary[ "data_directory" ] use_cylindrical_integration = params_dictionary[ "use_cylindrical_integration" ] instrument_name = params_dictionary[ "instrument_name" ] @@ -153,14 +155,44 @@ print "*********************************************************************** # appending them to a combined output file. # niggli_name = output_directory + "/" + exp_name + "_Niggli" -niggli_integrate_file = niggli_name + ".integrate" +if output_nexus: + niggli_integrate_file = niggli_name + ".nxs" +else: + niggli_integrate_file = niggli_name + ".integrate" niggli_matrix_file = niggli_name + ".mat" first_time = True + +if output_nexus: + #Only need this for instrument for peaks_total + short_filename = "%s_%s_event.nxs" % (instrument_name, str(run_nums[0])) + if data_directory is not None: + full_name = data_directory + "/" + short_filename + else: + candidates = FileFinder.findRuns(short_filename) + full_name = "" + for item in candidates: + if os.path.exists(item): + full_name = str(item) + + if not full_name.endswith('nxs'): + print "Exiting since the data_directory was not specified and" + print "findnexus failed for event NeXus file: " + instrument_name + " " + str(run) + exit(0) + # + # Load the first data file to find instrument + # + wksp = LoadEventNexus( Filename=full_name, FilterByTofMin=0, FilterByTofMax=0 ) + peaks_total = CreatePeaksWorkspace(NumberOfPeaks=0, InstrumentWorkspace=wksp) + if not use_cylindrical_integration: for r_num in run_nums: - one_run_file = output_directory + '/' + str(r_num) + '_Niggli.integrate' - peaks_ws = LoadIsawPeaks( Filename=one_run_file ) + if output_nexus: + one_run_file = output_directory + '/' + str(r_num) + '_Niggli.nxs' + peaks_ws = Load( Filename=one_run_file ) + else: + one_run_file = output_directory + '/' + str(r_num) + '_Niggli.integrate' + peaks_ws = LoadIsawPeaks( Filename=one_run_file ) if first_time: if UseFirstLattice and not read_UB: # Find a UB (using FFT) for the first run to use in the FindUBUsingLatticeParameters @@ -171,17 +203,27 @@ if not use_cylindrical_integration: uc_alpha = peaks_ws.sample().getOrientedLattice().alpha() uc_beta = peaks_ws.sample().getOrientedLattice().beta() uc_gamma = peaks_ws.sample().getOrientedLattice().gamma() - SaveIsawPeaks( InputWorkspace=peaks_ws, AppendFile=False, Filename=niggli_integrate_file ) - + if output_nexus: + peaks_total = CombinePeaksWorkspaces(LHSWorkspace=peaks_total, RHSWorkspace=peaks_ws) + SaveNexus( InputWorkspace=peaks_ws, Filename=niggli_integrate_file ) + else: + SaveIsawPeaks( InputWorkspace=peaks_ws, AppendFile=False, Filename=niggli_integrate_file ) first_time = False else: - SaveIsawPeaks( InputWorkspace=peaks_ws, AppendFile=True, Filename=niggli_integrate_file ) + if output_nexus: + peaks_total = CombinePeaksWorkspaces(LHSWorkspace=peaks_total, RHSWorkspace=peaks_ws) + SaveNexus( InputWorkspace=peaks_total, Filename=niggli_integrate_file ) + else: + SaveIsawPeaks( InputWorkspace=peaks_ws, AppendFile=True, Filename=niggli_integrate_file ) # # Load the combined file and re-index all of the peaks together. # Save them back to the combined Niggli file (Or selcted UB file if in use...) # - peaks_ws = LoadIsawPeaks( Filename=niggli_integrate_file ) + if output_nexus: + peaks_ws = Load( Filename=niggli_integrate_file ) + else: + peaks_ws = LoadIsawPeaks( Filename=niggli_integrate_file ) # # Find a Niggli UB matrix that indexes the peaks in this run @@ -206,7 +248,10 @@ if not use_cylindrical_integration: FindUBUsingFFT( PeaksWorkspace=peaks_ws, MinD=min_d, MaxD=max_d, Tolerance=tolerance ) IndexPeaks( PeaksWorkspace=peaks_ws, Tolerance=tolerance ) - SaveIsawPeaks( InputWorkspace=peaks_ws, AppendFile=False, Filename=niggli_integrate_file ) + if output_nexus: + SaveNexus( InputWorkspace=peaks_ws, Filename=niggli_integrate_file ) + else: + SaveIsawPeaks( InputWorkspace=peaks_ws, AppendFile=False, Filename=niggli_integrate_file ) SaveIsawUB( InputWorkspace=peaks_ws, Filename=niggli_matrix_file ) # @@ -216,12 +261,18 @@ if not use_cylindrical_integration: if not use_cylindrical_integration: if (not cell_type is None) and (not centering is None) : conv_name = output_directory + "/" + exp_name + "_" + cell_type + "_" + centering - conventional_integrate_file = conv_name + ".integrate" + if output_nexus: + conventional_integrate_file = conv_name + ".nxs" + else: + conventional_integrate_file = conv_name + ".integrate" conventional_matrix_file = conv_name + ".mat" SelectCellOfType( PeaksWorkspace=peaks_ws, CellType=cell_type, Centering=centering,\ AllowPermutations=allow_perm, Apply=True, Tolerance=tolerance ) - SaveIsawPeaks( InputWorkspace=peaks_ws, AppendFile=False, Filename=conventional_integrate_file ) + if output_nexus: + SaveNexus( InputWorkspace=peaks_ws, Filename=conventional_integrate_file ) + else: + SaveIsawPeaks( InputWorkspace=peaks_ws, AppendFile=False, Filename=conventional_integrate_file ) SaveIsawUB( InputWorkspace=peaks_ws, Filename=conventional_matrix_file ) if use_cylindrical_integration: diff --git a/Code/Mantid/scripts/test/DirectEnergyConversionTest.py b/Code/Mantid/scripts/test/DirectEnergyConversionTest.py index e5f988c366f5baf2fd3945c8ebc5022c3b33ae69..c8f735d78d24c63759e8d676865d68bf5dc98691 100644 --- a/Code/Mantid/scripts/test/DirectEnergyConversionTest.py +++ b/Code/Mantid/scripts/test/DirectEnergyConversionTest.py @@ -307,23 +307,23 @@ class DirectEnergyConversionTest(unittest.TestCase): def test_tof_range(self): run=CreateSampleWorkspace(Function='Multiple Peaks', NumBanks=6, BankPixelWidth=1, NumEvents=10,\ - XUnit='DeltaE', XMin=-20, XMax=65, BinWidth=0.2) + XUnit='Energy', XMin=5, XMax=75, BinWidth=0.2) LoadInstrument(run,InstrumentName='MARI') red = DirectEnergyConversion(run.getInstrument()) - red.prop_man.incident_energy = 67 - red.prop_man.energy_bins = [-20,0.2,65] + red.prop_man.incident_energy = 26.2 + red.prop_man.energy_bins = [-20,0.1,20] red.prop_man.multirep_tof_specta_list = [4,5,6] MoveInstrumentComponent(Workspace='run', ComponentName='Detector', DetectorID=1102, Z=3) MoveInstrumentComponent(Workspace='run', ComponentName='Detector', DetectorID=1103,Z=6) + run_tof = ConvertUnits(run,Target='TOF',EMode='Elastic') - tof_range = red.find_tof_range_for_multirep(run) + tof_range = red.find_tof_range_for_multirep(run_tof) self.assertEqual(len(tof_range),3) - run_tof = ConvertUnits(run,Target='TOF',EMode='Direct',EFixed=67.) x = run_tof.readX(3) dx=abs(x[1:]-x[:-1]) xMin = min(x) @@ -332,17 +332,23 @@ class DirectEnergyConversionTest(unittest.TestCase): xMax = max(x) - self.assertAlmostEqual(tof_range[0],xMin) - self.assertAlmostEqual(tof_range[1],dt) - self.assertAlmostEqual(tof_range[2],xMax) + self.assertTrue(tof_range[0]>xMin) + #self.assertAlmostEqual(tof_range[1],dt) + self.assertTrue(tof_range[2]<xMax) # check another working mode red.prop_man.multirep_tof_specta_list = 4 - tof_range1 = red.find_tof_range_for_multirep(run) + red.prop_man.incident_energy = 47.505 + red.prop_man.energy_bins = [-20,0.1,45] + + tof_range1 = red.find_tof_range_for_multirep(run_tof) - self.assertAlmostEqual(tof_range[0],tof_range1[0]) - self.assertAlmostEqual(tof_range[1],tof_range1[1]) - #self.assertAlmostEqual(tof_range[2],tof_range1[2]) + self.assertTrue(tof_range1[0]>xMin) + self.assertTrue(tof_range1[2]<xMax) + + self.assertTrue(tof_range1[2]<tof_range[2]) + self.assertTrue(tof_range1[0]<tof_range[0]) + self.assertTrue(tof_range1[1]<tof_range[1]) def test_multirep_mode(self): # create test workspace diff --git a/Code/Mantid/scripts/test/IndirectCommonTests.py b/Code/Mantid/scripts/test/IndirectCommonTests.py index 48b88d94cdbcfd17c9ca79127b289d06d92d8704..a0bbe462f14254221715448ab0b8b70d7269affa 100644 --- a/Code/Mantid/scripts/test/IndirectCommonTests.py +++ b/Code/Mantid/scripts/test/IndirectCommonTests.py @@ -285,23 +285,6 @@ class IndirectCommonTests(unittest.TestCase): self.assert_matrix_workspace_dimensions(params_workspace.name(), expected_num_histograms=3, expected_blocksize=5) - def test_addSampleLogs(self): - ws = CreateSampleWorkspace() - logs = {} - logs['FloatLog'] = 3.149 - logs['IntLog'] = 42 - logs['StringLog'] = "A String Log" - logs['BooleanLog'] = True - - indirect_common.addSampleLogs(ws, logs) - - self.assert_logs_match_expected(ws.name(), logs) - - def test_addSampleLogs_empty_dict(self): - ws = CreateSampleWorkspace() - logs = {} - self.assert_does_not_raise(Exception, indirect_common.addSampleLogs, ws, logs) - #----------------------------------------------------------- # Custom assertion functions #----------------------------------------------------------- diff --git a/Code/Mantid/scripts/test/ReductionWrapperTest.py b/Code/Mantid/scripts/test/ReductionWrapperTest.py index f037da458dd5e8dd5c435dddec07099d8715c3e1..d9ba91438a67778aac58c91a50f32d65456c9a77 100644 --- a/Code/Mantid/scripts/test/ReductionWrapperTest.py +++ b/Code/Mantid/scripts/test/ReductionWrapperTest.py @@ -44,7 +44,32 @@ class test_helper(ReductionWrapper): #return None @iliad def reduce(self, input_file = None, output_directory = None): - return '' + + self.reducer._clear_old_results() + if input_file: + self.reducer.prop_man.sample_run = input_file + run = self.reducer.prop_man.sample_run + + result = [] + if PropertyManager.incident_energy.multirep_mode(): + en_range = self.reducer.prop_man.incident_energy + for ind,en in enumerate(en_range): + ws=CreateSampleWorkspace() + AddSampleLog(ws,LogName = 'run_number',LogText=str(run)) + PropertyManager.sample_run.set_action_suffix('#{0}_reduced'.format(ind+1)) + PropertyManager.sample_run.synchronize_ws(ws) + result.append(ws) + self.reducer._old_runs_list.append(ws.name()) + else: + ws=CreateSampleWorkspace() + AddSampleLog(ws,LogName = 'run_number',LogText=str(run)) + PropertyManager.sample_run.set_action_suffix('_reduced') + PropertyManager.sample_run.synchronize_ws(ws) + result.append(ws) + + if len(result) == 1: + result = result[0] + return result #----------------------------------------------------------------------------------------------------------------------------------------- #----------------------------------------------------------------------------------------------------------------------------------------- #----------------------------------------------------------------------------------------------------------------------------------------- @@ -82,6 +107,14 @@ class ReductionWrapperTest(unittest.TestCase): test_dir = config['defaultsave.directory'] file = os.path.join(test_dir,'reduce_vars.py') + #clear up previous rubbish may be present from other runs + if os.path.isfile(file): + os.remove(file) + fbase,fext = os.path.splitext(file) + fcomp = fbase+'.pyc' + if os.path.isfile(fcomp): + os.remove(fcomp) + # save wen variables red.save_web_variables(file) self.assertTrue(os.path.isfile(file)) @@ -166,12 +199,64 @@ class ReductionWrapperTest(unittest.TestCase): th.reduce() save_file = th.reducer.prop_man.save_file_name - self.assertEqual(save_file,'SOMETHING100_10.01meV_rings') + # such strange name because custom print function above access workspace, + # generated by reduction + self.assertEqual(save_file,'SOMETHINGSR_MAR000100#2_reduced_10.01meV_rings') - th.reducer.prop_man.sample_run = 200 PropertyManager.incident_energy.next() save_file = th.reducer.prop_man.save_file_name - self.assertEqual(save_file,'SOMETHING200_20.00meV_rings') + # now reduction have not been run, and the name is generated from run number + self.assertEqual(save_file,'SOMETHINGSR_MAR000100#2_reduced_20.00meV_rings') + + def test_return_run_list(self): + th=test_helper() + + th.reducer.prop_man.sample_run=200 + th.run_reduction() + # standard reduction would save and delete workspace but our simplified one + # will just keep it + name = 'SR_MAR000200_reduced' + self.assertTrue(name in mtd) + + th.reducer.prop_man.sample_run=300 + # new run deletes the old one + self.assertFalse(name in mtd) + + rez = th.run_reduction() + self.assertTrue(isinstance(rez,api.Workspace)) + self.assertTrue('rez' in mtd) + self.assertEqual(rez.name(),'rez') + + th.reducer.prop_man.sample_run=[300,400] + th.run_reduction() + self.assertFalse('SR_MAR000300_reduced' in mtd) + self.assertTrue('SR_MAR000400_reduced' in mtd) + + th.reducer.prop_man.sample_run=[500,600] + self.assertFalse('SR_MAR000400_reduced' in mtd) + th.run_reduction() + self.assertFalse('SR_MAR000500_reduced' in mtd) + self.assertTrue('SR_MAR000600_reduced' in mtd) + + th.reducer.prop_man.sample_run=[300,400] + runs = th.run_reduction() + self.assertTrue('runs#1of2' in mtd) + self.assertTrue('runs#2of2' in mtd) + self.assertEqual(runs[0].name(),'runs#1of2') + self.assertEqual(runs[1].name(),'runs#2of2') + + th.reducer.prop_man.incident_energy=[10,20] + th.reducer.prop_man.sample_run=300 + th.run_reduction() + self.assertTrue('SR_MAR000300#1_reduced' in mtd) + self.assertTrue('SR_MAR000300#2_reduced' in mtd) + th.reducer.prop_man.sample_run=400 + th.run_reduction() + self.assertFalse('SR_MAR000300#1_reduced' in mtd) + self.assertFalse('SR_MAR000300#2_reduced' in mtd) + self.assertTrue('SR_MAR000400#1_reduced' in mtd) + self.assertTrue('SR_MAR000400#2_reduced' in mtd) +