diff --git a/Framework/Algorithms/src/GetAllEi.cpp b/Framework/Algorithms/src/GetAllEi.cpp index 60418d5071ea437e50237e3f826e2d099efadc9e..2ba9d8bff8c4935ae69d7d8aa3eb1b2b7efa5590 100644 --- a/Framework/Algorithms/src/GetAllEi.cpp +++ b/Framework/Algorithms/src/GetAllEi.cpp @@ -754,7 +754,7 @@ bool refineEGuess(const MantidVec &eBins, const MantidVec &signal, struct peakKeeper2 { double left_rng; double right_rng; - peakKeeper2(){}; + peakKeeper2() : left_rng(.0), right_rng(.0){}; peakKeeper2(double left, double right) : left_rng(left), right_rng(right) {} }; } @@ -985,6 +985,12 @@ GetAllEi::getAvrgLogValue(const API::MatrixWorkspace_sptr &inputWS, auto pTimeSeries = dynamic_cast<Kernel::TimeSeriesProperty<double> *>(pIProperty); + if (!pTimeSeries) { + throw std::runtime_error( + "Could not retrieve a time series property for the property name " + + propertyName); + } + if (splitter.size() == 0) { auto TimeStart = inputWS->run().startTime(); auto TimeEnd = inputWS->run().endTime(); diff --git a/Framework/Algorithms/src/IdentifyNoisyDetectors.cpp b/Framework/Algorithms/src/IdentifyNoisyDetectors.cpp index 8970268ec6e453b2326086689c3977de04cf60a3..754509ce3c9bb695d51fcf4ecd33c927b2509ffd 100644 --- a/Framework/Algorithms/src/IdentifyNoisyDetectors.cpp +++ b/Framework/Algorithms/src/IdentifyNoisyDetectors.cpp @@ -137,6 +137,11 @@ void IdentifyNoisyDetectors::getStdDev(MatrixWorkspace_sptr valid, } } + if (0 == count) { + // all values are zero, no need to loop + return; + } + mean = mean / count; double stddev = sqrt((mean2 / count) - std::pow(mean, 2)); diff --git a/Framework/Algorithms/src/ResizeRectangularDetector.cpp b/Framework/Algorithms/src/ResizeRectangularDetector.cpp index 564cb8d85ce64d5dbc79efe15edefc9ad619458e..9378f6e68407b8b0936036727b89c9c895ab4cb9 100644 --- a/Framework/Algorithms/src/ResizeRectangularDetector.cpp +++ b/Framework/Algorithms/src/ResizeRectangularDetector.cpp @@ -74,8 +74,21 @@ void ResizeRectangularDetector::exec() { Instrument_sptr inst; if (inputW) { inst = boost::const_pointer_cast<Instrument>(inputW->getInstrument()); + if (!inst) + throw std::runtime_error("Could not get a valid instrument from the " + "MatrixWorkspace provided as input"); + } else if (inputP) { inst = boost::const_pointer_cast<Instrument>(inputP->getInstrument()); + if (!inst) + throw std::runtime_error("Could not get a valid instrument from the " + "PeaksWorkspace provided as input"); + } else { + if (!inst) + throw std::runtime_error("Could not get a valid instrument from the " + "workspace and it does not seem to be valid as " + "input (must be either MatrixWorkspace or " + "PeaksWorkspace"); } std::string ComponentName = getPropertyValue("ComponentName"); diff --git a/Framework/Crystal/src/IntegratePeakTimeSlices.cpp b/Framework/Crystal/src/IntegratePeakTimeSlices.cpp index 9828bea2f54bfa54db588459eca4c19b2d772842..92558503c80fd9fed7c50e719f19c17ddd805321 100644 --- a/Framework/Crystal/src/IntegratePeakTimeSlices.cpp +++ b/Framework/Crystal/src/IntegratePeakTimeSlices.cpp @@ -595,7 +595,8 @@ void IntegratePeakTimeSlices::exec() { lastRow = (int)(params[i] + .5); i = find("Mcol", names); - lastCol = (int)(params[i] + .5); + if (i >= 0) + lastCol = (int)(params[i] + .5); prog.report(); } else if (dir > 0) diff --git a/Framework/CurveFitting/src/Algorithms/FitPowderDiffPeaks.cpp b/Framework/CurveFitting/src/Algorithms/FitPowderDiffPeaks.cpp index 87801460543315e7aaccd4501e43e74facf27e8f..71021ad4567b7bbed8fc34f07954ebad74a60fa3 100644 --- a/Framework/CurveFitting/src/Algorithms/FitPowderDiffPeaks.cpp +++ b/Framework/CurveFitting/src/Algorithms/FitPowderDiffPeaks.cpp @@ -2081,7 +2081,8 @@ bool FitPowderDiffPeaks::doFitMultiplePeaks( bool fitgood = doFitNPeaksSimple(dataws, wsindex, peaksfunc, peakfuncs, "Levenberg-MarquardtMD", 1000, chi2); - evergood = evergood || fitgood; + // not required. before loop starts, evergood=fitgood WITH fitgood==true + // evergood = evergood || fitgood; // c) Process the result if (!fitgood) @@ -2098,7 +2099,8 @@ bool FitPowderDiffPeaks::doFitMultiplePeaks( storeFunctionParameters(peaksfunc, peaksfuncparams); fitgood = doFitNPeaksSimple(dataws, wsindex, peaksfunc, peakfuncs, "Levenberg-MarquardtMD", 1000, chi2); - evergood = evergood || fitgood; + // not required. before, evergood=fitgood WITH fitgood==true + // evergood = evergood || fitgood; if (!fitgood) restoreFunctionParameters(peaksfunc, peaksfuncparams); diff --git a/Framework/CurveFitting/src/Algorithms/SplineBackground.cpp b/Framework/CurveFitting/src/Algorithms/SplineBackground.cpp index a19fa51061060d39206dd760f8a1d8db453d9fb0..c9ba83eb4f203689aa8651bdf57762652a205b0c 100644 --- a/Framework/CurveFitting/src/Algorithms/SplineBackground.cpp +++ b/Framework/CurveFitting/src/Algorithms/SplineBackground.cpp @@ -66,8 +66,8 @@ void SplineBackground::exec() { bool isMasked = inWS->hasMaskedBins(spec); std::vector<int> masked(Y.size()); if (isMasked) { - for (auto it = inWS->maskedBins(spec).begin(); - it != inWS->maskedBins(spec).end(); ++it) + auto maskedBins = inWS->maskedBins(spec); + for (auto it = maskedBins.begin(); it != maskedBins.end(); ++it) masked[it->first] = 1; n -= static_cast<int>(inWS->maskedBins(spec).size()); } diff --git a/Framework/DataHandling/inc/MantidDataHandling/LoadIsawDetCal.h b/Framework/DataHandling/inc/MantidDataHandling/LoadIsawDetCal.h index 7c789334c19d420896d82e3c754599dfc9ef10f7..65dce045094d0c534654bed7749e496ba0c94b40 100644 --- a/Framework/DataHandling/inc/MantidDataHandling/LoadIsawDetCal.h +++ b/Framework/DataHandling/inc/MantidDataHandling/LoadIsawDetCal.h @@ -5,6 +5,8 @@ // Includes //---------------------------------------------------------------------- #include "MantidAPI/Algorithm.h" +#include "MantidGeometry/Instrument.h" + #include <gsl/gsl_statistics.h> #include <gsl/gsl_multifit_nlin.h> #include <gsl/gsl_multimin.h> @@ -70,6 +72,8 @@ private: // Overridden Algorithm methods void init(); void exec(); + + Geometry::Instrument_sptr getCheckInst(API::Workspace_sptr ws); }; } // namespace DataHandling diff --git a/Framework/DataHandling/src/GroupDetectors2.cpp b/Framework/DataHandling/src/GroupDetectors2.cpp index 7567cc8e6da22794430ce706cb97c7f5d4c1aeca..8e9b3d0d0927e0d5a746f0cf5c994dfbc6a40d3c 100644 --- a/Framework/DataHandling/src/GroupDetectors2.cpp +++ b/Framework/DataHandling/src/GroupDetectors2.cpp @@ -353,8 +353,9 @@ void GroupDetectors2::getGroups(API::MatrixWorkspace_const_sptr workspace, } // check we don't have an index that is too high for the workspace size_t maxIn = static_cast<size_t>(workspace->getNumberHistograms() - 1); - auto it = m_GroupSpecInds[0].begin(); - for (; it != m_GroupSpecInds[0].end(); ++it) { + auto indices0 = m_GroupSpecInds[0]; + auto it = indices0.begin(); + for (; it != indices0.end(); ++it) { if (*it > maxIn) { g_log.error() << "Spectra index " << *it << " doesn't exist in the input workspace, the highest " @@ -375,8 +376,9 @@ void GroupDetectors2::getGroups(API::MatrixWorkspace_const_sptr workspace, // up date unUsedSpec, this is used to find duplicates and when the user has // set KeepUngroupedSpectra - auto index = m_GroupSpecInds[0].begin(); - for (; index != m_GroupSpecInds[0].end(); + auto indices0 = m_GroupSpecInds[0]; + auto index = indices0.begin(); + for (; index != indices0.end(); ++index) { // the vector<int> m_GroupSpecInds[0] must not index contain // numbers that don't exist in the workspaace if (unUsedSpec[*index] != USED) { diff --git a/Framework/DataHandling/src/LoadIsawDetCal.cpp b/Framework/DataHandling/src/LoadIsawDetCal.cpp index 2fc3168b716430b093a5fd2da80f0ef2f1aa17fa..02828ea742261cedb9b45d808a59049f4846d0fc 100644 --- a/Framework/DataHandling/src/LoadIsawDetCal.cpp +++ b/Framework/DataHandling/src/LoadIsawDetCal.cpp @@ -40,52 +40,6 @@ LoadIsawDetCal::LoadIsawDetCal() : API::Algorithm() {} /// Destructor LoadIsawDetCal::~LoadIsawDetCal() {} -/** - * The intensity function calculates the intensity as a function of detector - * position and angles - * @param x :: The shift along the X-axis - * @param y :: The shift along the Y-axis - * @param z :: The shift along the Z-axis - * @param detname :: The detector name - * @param ws :: The workspace - */ - -void LoadIsawDetCal::center(double x, double y, double z, std::string detname, - API::Workspace_sptr ws) { - MatrixWorkspace_sptr inputW = - boost::dynamic_pointer_cast<MatrixWorkspace>(ws); - PeaksWorkspace_sptr inputP = boost::dynamic_pointer_cast<PeaksWorkspace>(ws); - - // Get some stuff from the input workspace - Instrument_sptr inst; - if (inputW) { - inst = boost::const_pointer_cast<Instrument>(inputW->getInstrument()); - } else if (inputP) { - inst = boost::const_pointer_cast<Instrument>(inputP->getInstrument()); - } - - IComponent_const_sptr comp = inst->getComponentByName(detname); - if (comp == 0) { - std::ostringstream mess; - mess << "Component with name " << detname << " was not found."; - g_log.error(mess.str()); - throw std::runtime_error(mess.str()); - } - - // Do the move - using namespace Geometry::ComponentHelper; - TransformType positionType = Absolute; - if (inputW) { - Geometry::ParameterMap &pmap = inputW->instrumentParameters(); - Geometry::ComponentHelper::moveComponent(*comp, pmap, V3D(x, y, z), - positionType); - } else if (inputP) { - Geometry::ParameterMap &pmap = inputP->instrumentParameters(); - Geometry::ComponentHelper::moveComponent(*comp, pmap, V3D(x, y, z), - positionType); - } -} - /** Initialisation method */ void LoadIsawDetCal::init() { @@ -118,13 +72,7 @@ void LoadIsawDetCal::exec() { boost::dynamic_pointer_cast<MatrixWorkspace>(ws); PeaksWorkspace_sptr inputP = boost::dynamic_pointer_cast<PeaksWorkspace>(ws); - // Get some stuff from the input workspace - Instrument_sptr inst; - if (inputW) { - inst = boost::const_pointer_cast<Instrument>(inputW->getInstrument()); - } else if (inputP) { - inst = boost::const_pointer_cast<Instrument>(inputP->getInstrument()); - } + Instrument_sptr inst = getCheckInst(ws); std::string instname = inst->getName(); @@ -437,5 +385,82 @@ void LoadIsawDetCal::exec() { return; } +/** + * The intensity function calculates the intensity as a function of detector + * position and angles + * @param x :: The shift along the X-axis + * @param y :: The shift along the Y-axis + * @param z :: The shift along the Z-axis + * @param detname :: The detector name + * @param ws :: The workspace + */ + +void LoadIsawDetCal::center(double x, double y, double z, std::string detname, + API::Workspace_sptr ws) { + + Instrument_sptr inst = getCheckInst(ws); + + IComponent_const_sptr comp = inst->getComponentByName(detname); + if (comp == 0) { + std::ostringstream mess; + mess << "Component with name " << detname << " was not found."; + g_log.error(mess.str()); + throw std::runtime_error(mess.str()); + } + + // Do the move + using namespace Geometry::ComponentHelper; + TransformType positionType = Absolute; + MatrixWorkspace_sptr inputW = + boost::dynamic_pointer_cast<MatrixWorkspace>(ws); + PeaksWorkspace_sptr inputP = boost::dynamic_pointer_cast<PeaksWorkspace>(ws); + if (inputW) { + Geometry::ParameterMap &pmap = inputW->instrumentParameters(); + Geometry::ComponentHelper::moveComponent(*comp, pmap, V3D(x, y, z), + positionType); + } else if (inputP) { + Geometry::ParameterMap &pmap = inputP->instrumentParameters(); + Geometry::ComponentHelper::moveComponent(*comp, pmap, V3D(x, y, z), + positionType); + } +} + +/** + * Gets the instrument of the workspace, checking that the workspace + * and the instrument are as expected. + * + * @param ws workspace (expected Matrix or Peaks Workspace) + * + * @throw std::runtime_error if there's any problem with the workspace or it is + * not possible to get an instrument object from it + */ +Instrument_sptr LoadIsawDetCal::getCheckInst(API::Workspace_sptr ws) { + MatrixWorkspace_sptr inputW = + boost::dynamic_pointer_cast<MatrixWorkspace>(ws); + PeaksWorkspace_sptr inputP = boost::dynamic_pointer_cast<PeaksWorkspace>(ws); + + // Get some stuff from the input workspace + Instrument_sptr inst; + if (inputW) { + inst = boost::const_pointer_cast<Instrument>(inputW->getInstrument()); + if (!inst) + throw std::runtime_error("Could not get a valid instrument from the " + "MatrixWorkspace provided as input"); + } else if (inputP) { + inst = boost::const_pointer_cast<Instrument>(inputP->getInstrument()); + if (!inst) + throw std::runtime_error("Could not get a valid instrument from the " + "PeaksWorkspace provided as input"); + } else { + if (!inst) + throw std::runtime_error("Could not get a valid instrument from the " + "workspace which does not seem to be valid as " + "input (must be either MatrixWorkspace or " + "PeaksWorkspace"); + } + + return inst; +} + } // namespace Algorithm } // namespace Mantid diff --git a/Framework/DataHandling/src/RotateInstrumentComponent.cpp b/Framework/DataHandling/src/RotateInstrumentComponent.cpp index 8cb5b36d8803563a9ccf23cb0b265edaaca362dd..adf61ef3c061e495d3f8ea629a531897fccae69a 100644 --- a/Framework/DataHandling/src/RotateInstrumentComponent.cpp +++ b/Framework/DataHandling/src/RotateInstrumentComponent.cpp @@ -61,8 +61,20 @@ void RotateInstrumentComponent::exec() { Instrument_sptr inst; if (inputW) { inst = boost::const_pointer_cast<Instrument>(inputW->getInstrument()); + if (!inst) + throw std::runtime_error("Could not get a valid instrument from the " + "MatrixWorkspace provided as input"); } else if (inputP) { inst = boost::const_pointer_cast<Instrument>(inputP->getInstrument()); + if (!inst) + throw std::runtime_error("Could not get a valid instrument from the " + "PeaksWorkspace provided as input"); + } else { + if (!inst) + throw std::runtime_error("Could not get a valid instrument from the " + "workspace and it does not seem to be valid as " + "input (must be either MatrixWorkspace or " + "PeaksWorkspace"); } const std::string ComponentName = getProperty("ComponentName"); diff --git a/Framework/DataObjects/inc/MantidDataObjects/MDGridBox.tcc b/Framework/DataObjects/inc/MantidDataObjects/MDGridBox.tcc index 4de121711232aa6c6a24fd477c7118097ca62778..779c3a641cc521b38ff68c8af3193c88f37c4e64 100644 --- a/Framework/DataObjects/inc/MantidDataObjects/MDGridBox.tcc +++ b/Framework/DataObjects/inc/MantidDataObjects/MDGridBox.tcc @@ -1462,8 +1462,8 @@ TMDE(void MDGridBox)::integrateCylinder( // Distance from center to the peak integration center coord_t out[nd]; radiusTransform.apply(boxCenter, out); - if (out[0] < std::sqrt(diagonalSquared * 0.72 + radius * radius) && - (nd >= 1 && + if ((nd >= 1) && out[0] < std::sqrt(diagonalSquared * 0.72 + radius * radius) && + (nd >= 2 && std::fabs(out[1]) < std::sqrt(diagonalSquared * 0.72 + 0.25 * length * length))) { // If the center is closer than the size of the box, then it MIGHT be diff --git a/Framework/Geometry/src/Instrument/InstrumentDefinitionParser.cpp b/Framework/Geometry/src/Instrument/InstrumentDefinitionParser.cpp index f4c9afef815111745fea386715ae9a79b4d531ea..547f95e5a70e134f2a68d069a107be1b9c194574 100644 --- a/Framework/Geometry/src/Instrument/InstrumentDefinitionParser.cpp +++ b/Framework/Geometry/src/Instrument/InstrumentDefinitionParser.cpp @@ -1502,8 +1502,16 @@ void InstrumentDefinitionParser::populateIdList(Poco::XML::Element *pE, if (pE->hasAttribute("step")) increment = atoi((pE->getAttribute("step")).c_str()); + if (0 == increment) { + std::stringstream ss; + ss << "The step element cannot be zero, got start: " << startID + << ", end: " << endID << ", step: " << increment; + throw Kernel::Exception::InstrumentDefinitionError(ss.str(), filename); + } + // check the start end and increment values are sensible - if (((endID - startID) / increment) < 0) { + int steps = (endID - startID) / increment; + if (steps < 0) { std::stringstream ss; ss << "The start, end, and step elements do not allow a single id in the " "idlist entry - "; @@ -1513,7 +1521,7 @@ void InstrumentDefinitionParser::populateIdList(Poco::XML::Element *pE, throw Kernel::Exception::InstrumentDefinitionError(ss.str(), filename); } - idList.vec.reserve((endID - startID) / increment); + idList.vec.reserve(steps); for (int i = startID; i != endID + increment; i += increment) { idList.vec.push_back(i); } diff --git a/Framework/ICat/src/GSoap/stdsoap2.cpp b/Framework/ICat/src/GSoap/stdsoap2.cpp index 252bc7ae6514f1f8380bd35f9c89fcc5e46abd54..d351d6dcbe205759e64022794e4a7dcbbd5662d5 100644 --- a/Framework/ICat/src/GSoap/stdsoap2.cpp +++ b/Framework/ICat/src/GSoap/stdsoap2.cpp @@ -312,9 +312,21 @@ static const char *soap_strerror(struct soap *); ioctl(fd, 0 /*FIONBIO*/, &nonblocking); \ } #else -#define SOAP_SOCKBLOCK(fd) fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) & ~O_NONBLOCK); +#define SOAP_SOCKBLOCK(fd) \ + { \ + int retv = fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) & ~O_NONBLOCK); \ + if (retv < 0) { \ + DBGLOG(TEST, SOAP_MESSAGE(fdebug, "SOAP_SOCKBLOCK (fcntl) failed\n")); \ + } \ + } #define SOAP_SOCKNONBLOCK(fd) \ - fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK); + { \ + int retv = fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK); \ + if (retv < 0) { \ + DBGLOG(TEST, \ + SOAP_MESSAGE(fdebug, "SOAP_SOCNONKBLOCK (fcntl) failed\n")); \ + } \ + } #endif #endif @@ -2348,7 +2360,8 @@ int SOAP_FMAC2 soap_resolve(struct soap *soap) { } else if (*ip->id == '#') { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Missing data for id='%s'\n", ip->id)); - strncpy(soap->id, ip->id + 1, sizeof(soap->id)); + strncpy(soap->id, ip->id + 1, sizeof(soap->id) - 1); + soap->id[sizeof(soap->id) - 1] = '\0'; return soap->error = SOAP_MISSING_ID; } } @@ -3206,9 +3219,10 @@ const char *SOAP_FMAC2 soap_ssl_error(struct soap *soap, int ret) { #ifdef WITH_OPENSSL int err = SSL_get_error(soap->ssl, ret); const char *msg = soap_code_str(h_ssl_error_codes, err); - if (msg) - strncpy(soap->msgbuf, msg, sizeof(soap->msgbuf)); - else + if (msg) { + strncpy(soap->msgbuf, msg, sizeof(soap->msgbuf) - 1); + soap->msgbuf[sizeof(soap->msgbuf) - 1] = '\0'; + } else return ERR_error_string(err, soap->msgbuf); if (ERR_peek_error()) { unsigned long r; @@ -3715,10 +3729,11 @@ int SOAP_FMAC2 soap_ssl_accept(struct soap *soap) { } } #endif - if (soap->recv_timeout || soap->send_timeout) + if (soap->recv_timeout || soap->send_timeout) { SOAP_SOCKNONBLOCK(sk) - else + } else { SOAP_SOCKBLOCK(sk) + } soap->imode |= SOAP_ENC_SSL; soap->omode |= SOAP_ENC_SSL; return SOAP_OK; @@ -4615,10 +4630,11 @@ again: return SOAP_INVALID_SOCKET; #endif } - if (soap->recv_timeout || soap->send_timeout) + if (soap->recv_timeout || soap->send_timeout) { SOAP_SOCKNONBLOCK(sk) - else + } else { SOAP_SOCKBLOCK(sk) + } return sk; } #endif @@ -5169,10 +5185,11 @@ soap_accept(struct soap *soap) { } } } - if (soap->accept_timeout) + if (soap->accept_timeout) { SOAP_SOCKNONBLOCK(soap->master) - else + } else { SOAP_SOCKBLOCK(soap->master) + } soap->socket = soap->faccept(soap, soap->master, (struct sockaddr *)&soap->peer, &n); soap->peerlen = (size_t)n; @@ -5266,10 +5283,12 @@ soap_accept(struct soap *soap) { #endif soap->keep_alive = (((soap->imode | soap->omode) & SOAP_IO_KEEPALIVE) != 0); - if (soap->send_timeout || soap->recv_timeout) + + if (soap->send_timeout || soap->recv_timeout) { SOAP_SOCKNONBLOCK(soap->socket) - else + } else { SOAP_SOCKBLOCK(soap->socket) + } return soap->socket; } err = soap_socket_errno(soap->socket); @@ -6049,7 +6068,10 @@ static int http_post(struct soap *soap, const char *endpoint, const char *host, sprintf(soap->tmpbuf, "[%s]", host); /* RFC 2732 */ else #endif - strncpy(soap->tmpbuf, host, sizeof(soap->tmpbuf)); + { + strncpy(soap->tmpbuf, host, sizeof(soap->tmpbuf) - 1); + soap->tmpbuf[sizeof(soap->tmpbuf) - 1] = '\0'; + } } if ((err = soap->fposthdr(soap, "Host", soap->tmpbuf))) return err; @@ -8161,7 +8183,8 @@ void *SOAP_FMAC2 soap_id_lookup(struct soap *soap, const char *id, void **p, "Resolved href='%s' type=%d location=%p (%u bytes)\n", id, t, ip->ptr, (unsigned int)n)); if (ip->type != t) { - strncpy(soap->id, id, sizeof(soap->id)); + strncpy(soap->id, id, sizeof(soap->id) - 1); + soap->id[sizeof(soap->id) - 1] = '\0'; soap->error = SOAP_HREF; DBGLOG(TEST, SOAP_MESSAGE( @@ -8265,7 +8288,8 @@ void *SOAP_FMAC2 soap_id_forward(struct soap *soap, const char *href, void *p, "size=%lu level=%u got type=%d size=%lu\n", href, ip->type, (unsigned long)ip->size, k, st, (unsigned long)n)); - strncpy(soap->id, href, sizeof(soap->id)); + strncpy(soap->id, href, sizeof(soap->id) - 1); + soap->id[sizeof(soap->id) - 1] = '\0'; soap->error = SOAP_HREF; return NULL; } @@ -8357,12 +8381,14 @@ soap_id_enter(struct soap *soap, const char *id, void *p, int t, size_t n, "size=%lu level=%u got type=%d size=%lu\n", id, ip->type, (unsigned long)ip->size, k, t, (unsigned long)n)); - strncpy(soap->id, id, sizeof(soap->id)); + strncpy(soap->id, id, sizeof(soap->id) - 1); + soap->id[sizeof(soap->id) - 1] = '\0'; soap->error = SOAP_HREF; return NULL; } else if (ip->ptr) { DBGLOG(TEST, SOAP_MESSAGE(fdebug, "Multiply defined id='%s'\n", id)); - strncpy(soap->id, id, sizeof(soap->id)); + strncpy(soap->id, id, sizeof(soap->id) - 1); + soap->id[sizeof(soap->id) - 1] = '\0'; soap->error = SOAP_DUPLICATE_ID; return NULL; } else { @@ -16431,14 +16457,48 @@ int SOAP_FMAC2 soap_send_fault(struct soap *soap) { soap_serializefault(soap); soap_begin_count(soap); if (soap->mode & SOAP_IO_LENGTH) { - soap_envelope_begin_out(soap); - soap_putheader(soap); - soap_body_begin_out(soap); - soap_putfault(soap); - soap_body_end_out(soap); - soap_envelope_end_out(soap); + int retv = soap_envelope_begin_out(soap); + if (retv < 0) { + DBGLOG( + TEST, + SOAP_MESSAGE( + fdebug, + "soap_envelope_begin_out() failed in soap_send_fault()\n")); + } + retv = soap_putheader(soap); + if (retv < 0) { + DBGLOG(TEST, + SOAP_MESSAGE( + fdebug, "soap_putheader() failed in soap_send_fault()\n")); + } + retv = soap_body_begin_out(soap); + if (retv < 0) { + DBGLOG(TEST, + SOAP_MESSAGE( + fdebug, + "soap_body_begin_out() failed in soap_send_fault()\n")); + } + retv = soap_putfault(soap); + if (retv < 0) { + DBGLOG(TEST, + SOAP_MESSAGE(fdebug, + "soap_putfault() failed in soap_send_fault()\n")); + } + retv = soap_body_end_out(soap); + if (retv < 0) { + DBGLOG( + TEST, + SOAP_MESSAGE( + fdebug, "soap_body_end_out() failed in soap_send_fault()\n")); + } + retv = soap_envelope_end_out(soap); + } + int retv = soap_end_count(soap); + if (retv < 0) { + DBGLOG(TEST, + SOAP_MESSAGE(fdebug, + "soap_end_count() failed in soap_send_fault()\n")); } - soap_end_count(soap); if (soap_response(soap, status) || soap_envelope_begin_out(soap) || soap_putheader(soap) || soap_body_begin_out(soap) || soap_putfault(soap) || soap_body_end_out(soap) || @@ -16500,7 +16560,11 @@ int SOAP_FMAC2 soap_recv_fault(struct soap *soap, int check) { if (!soap_body_end_in(soap)) soap_envelope_end_in(soap); } - soap_end_recv(soap); + int recvsts = soap_end_recv(soap); + if (recvsts < 0) { + DBGLOG(TEST, SOAP_MESSAGE(fdebug, "soap_end_recv() failed with status %d\n", + status)); + } soap->error = status; return soap_closesock(soap); } @@ -16531,9 +16595,16 @@ int SOAP_FMAC2 soap_send_empty_response(struct soap *soap, int httpstatuscode) { SOAP_FMAC1 int SOAP_FMAC2 soap_recv_empty_response(struct soap *soap) { if (!(soap->omode & SOAP_IO_UDP)) { - if (!soap_begin_recv(soap)) + if (!soap_begin_recv(soap)) { soap_end_recv(soap); - else if (soap->error == SOAP_NO_DATA || soap->error == 202) + int recvsts = soap_end_recv(soap); + if (recvsts < 0) { + DBGLOG(TEST, + SOAP_MESSAGE( + fdebug, + "soap_end_recv() failed in soap_recv_empty_response()\n")); + } + } else if (soap->error == SOAP_NO_DATA || soap->error == 202) soap->error = SOAP_OK; } return soap_closesock(soap); diff --git a/Framework/Kernel/src/DateValidator.cpp b/Framework/Kernel/src/DateValidator.cpp index 5362fb247e217211a577736781841c1057ccacfe..4f7eee94a2965d71a42716a384035b05ade82914 100644 --- a/Framework/Kernel/src/DateValidator.cpp +++ b/Framework/Kernel/src/DateValidator.cpp @@ -30,6 +30,7 @@ struct tm getTimeValue(const std::string &sDate, std::string &error) { timeinfo.tm_isdst = -1; #ifndef _WIN32 timeinfo.tm_gmtoff = 0; + timeinfo.tm_zone = 0; #endif std::basic_string<char>::size_type index, off = 0; diff --git a/Framework/Kernel/src/VectorHelper.cpp b/Framework/Kernel/src/VectorHelper.cpp index 52144d225aa4f454563c018cefb3c214ad817445..8764accf4f6cab5eefa4949cb3e9d311c35507aa 100644 --- a/Framework/Kernel/src/VectorHelper.cpp +++ b/Framework/Kernel/src/VectorHelper.cpp @@ -533,6 +533,7 @@ void linearlyInterpolateY(const std::vector<double> &x, std::vector<double> &y, step++; } } + namespace { /** internal function converted from Lambda to identify interval around * specified point and run average around this point @@ -551,7 +552,7 @@ double runAverage(size_t index, size_t startIndex, size_t endIndex, std::vector<double> const *const binBndrs) { size_t iStart, iEnd; - double weight0(0), weight1(0), start, end; + double weight0(0), weight1(0), start(0.0), end(0.0); // if (binBndrs) { // identify initial and final bins to @@ -607,12 +608,21 @@ double runAverage(size_t index, size_t startIndex, size_t endIndex, if (iEnd != endIndex) avrg += input[iEnd] * weight1; - return avrg / (end - start); + double div = end - start; + if (.0 == div) + return 0; + else + return avrg / (end - start); } else { - return avrg / double(ic); + if (0 == ic) { + return 0; + } else { + return avrg / double(ic); + } } } } + /** Basic running average of input vector within specified range, considering * variable bin-boundaries if such boundaries are provided. * The algorithm performs trapezium integration, so some peak shift @@ -683,11 +693,11 @@ void smoothInRange(const std::vector<double> &input, output[i - startIndex] = runAverage(i, startIndex, endIndex, halfWidth, input, binBndrs) * binSize; - if (outBins) { + if (outBins && binBndrs) { outBins->operator[](i - startIndex) = binBndrs->operator[](i); } } - if (outBins) { + if (outBins && binBndrs) { outBins->operator[](endIndex - startIndex) = binBndrs->operator[](endIndex); } } diff --git a/Framework/MDAlgorithms/src/ConvertCWSDExpToMomentum.cpp b/Framework/MDAlgorithms/src/ConvertCWSDExpToMomentum.cpp index 5bb6cc662e53abe742bfb355143983a89573ce5d..22507befa430a047f4f1cb757bc943df762b53df 100644 --- a/Framework/MDAlgorithms/src/ConvertCWSDExpToMomentum.cpp +++ b/Framework/MDAlgorithms/src/ConvertCWSDExpToMomentum.cpp @@ -415,6 +415,13 @@ void ConvertCWSDExpToMomentum::convertSpiceMatrixToMomentumMDEvents( } expinfo->mutableRun().setGoniometer(dataws->run().getGoniometer(), false); expinfo->mutableRun().addProperty("run_number", runnumber); + // Add all the other propertys from original data workspace + const std::vector<Kernel::Property *> vec_property = + dataws->run().getProperties(); + for (size_t i = 0; i < vec_property.size(); ++i) { + expinfo->mutableRun().addProperty(vec_property[i]->clone()); + } + m_outputWS->addExperimentInfo(expinfo); return; diff --git a/Framework/MDAlgorithms/test/CompactMDTest.h b/Framework/MDAlgorithms/test/CompactMDTest.h index 2dc03cfe8ee693a245bdff1552c31d894a13dc68..c902a63bd606528350418ca3664b634d0314e4bd 100644 --- a/Framework/MDAlgorithms/test/CompactMDTest.h +++ b/Framework/MDAlgorithms/test/CompactMDTest.h @@ -34,9 +34,9 @@ public: * Input structure: *------------------ * ------------- - * | |///| | - * ------------- - * -3-2-1 0 1 2 3 + * | | |///| | | + * --------------------- + * -5-4-3 2-1 0 1 2 3 4 5 *--------------------------- * Expected output structure: *---------------------------- @@ -51,13 +51,13 @@ public: const size_t numDims = 1; const double signal = 0.0; const double errorSquared = 1.3; - size_t numBins[static_cast<int>(numDims)] = {3}; - Mantid::coord_t min[static_cast<int>(numDims)] = {-3}; - Mantid::coord_t max[static_cast<int>(numDims)] = {3}; + size_t numBins[static_cast<int>(numDims)] = {5}; + Mantid::coord_t min[static_cast<int>(numDims)] = {-5}; + Mantid::coord_t max[static_cast<int>(numDims)] = {5}; const std::string name("test"); auto inWS = MDEventsTestHelper::makeFakeMDHistoWorkspaceGeneral( numDims, signal, errorSquared, numBins, min, max, name); - inWS->setSignalAt(1, 1.0); // set middle bin signal to one + inWS->setSignalAt(2, 1.0); // set middle bin signal to one CompactMD alg; alg.setChild(true); alg.setRethrows(true); @@ -258,17 +258,22 @@ public: const size_t numDims = 4; const double signal = 0.0; const double errorSquared = 1.2; - size_t numBins[static_cast<int>(numDims)] = {3, 3, 3, 3}; - Mantid::coord_t min[static_cast<int>(numDims)] = {-3, -3, -3, -3}; - Mantid::coord_t max[static_cast<int>(numDims)] = {3, 3, 3, 3}; + size_t numBins[static_cast<int>(numDims)] = {10, 20, 10, 20}; + Mantid::coord_t min[static_cast<int>(numDims)] = {-5, -10, -5, -10}; + Mantid::coord_t max[static_cast<int>(numDims)] = {5, 10, 5, 10}; const std::string name("test"); m_ws = MDEventsTestHelper::makeFakeMDHistoWorkspaceGeneral( numDims, signal, errorSquared, numBins, min, max, name); + // setting signals like this for variety + auto iter = m_ws->createIterator(); + do { + auto index = iter->getLinearIndex(); + if (index % 2 == 0) { + m_ws->setSignalAt(index, 1.0); + } + } while (iter->next()); } void test_execute_4d() { - m_ws->setSignalAt(0, 1.0); - m_ws->setSignalAt(5, 1.2); - m_ws->setSignalAt(1, 2.3); CompactMD alg; alg.setChild(true); alg.setRethrows(true); diff --git a/Framework/Properties/Mantid.properties.template b/Framework/Properties/Mantid.properties.template index 27e669d1d7ff7c2297397b120797a006c97aa4b6..9b160ba84bb9860cdd4b2237dc08e7576198f65b 100644 --- a/Framework/Properties/Mantid.properties.template +++ b/Framework/Properties/Mantid.properties.template @@ -16,7 +16,7 @@ default.facility = ISIS default.instrument = # Set of PyQt interfaces to add to the Interfaces menu, separated by a space. Interfaces are seperated from their respective categories by a "/". -mantidqt.python_interfaces = Direct/DGS_Reduction.py Direct/DGSPlanner.py SANS/ORNL_SANS.py Reflectometry/REFL_Reduction.py Reflectometry/REFL_SF_Calculator.py Reflectometry/REFM_Reduction.py Utility/TofConverter.py Reflectometry/ISIS_Reflectometry.py Diffraction/Powder_Diffraction_Reduction.py Utility/FilterEvents.py Diffraction/HFIR_Powder_Diffraction_Reduction.py +mantidqt.python_interfaces = Direct/DGS_Reduction.py Direct/DGSPlanner.py SANS/ORNL_SANS.py Reflectometry/REFL_Reduction.py Reflectometry/REFL_SF_Calculator.py Reflectometry/REFM_Reduction.py Utility/TofConverter.py Reflectometry/ISIS_Reflectometry.py Diffraction/Powder_Diffraction_Reduction.py Utility/FilterEvents.py Diffraction/HFIR_Powder_Diffraction_Reduction.py Diffraction/HFIR_4Circle_Reduction.py mantidqt.python_interfaces_directory = @MANTID_ROOT@/scripts diff --git a/Framework/PythonInterface/plugins/algorithms/ComputeCalibrationCoefVan.py b/Framework/PythonInterface/plugins/algorithms/ComputeCalibrationCoefVan.py new file mode 100644 index 0000000000000000000000000000000000000000..a6964b3768e7acd5a4056f52cbfb721c8c95ef06 --- /dev/null +++ b/Framework/PythonInterface/plugins/algorithms/ComputeCalibrationCoefVan.py @@ -0,0 +1,168 @@ +from mantid.api import PythonAlgorithm, AlgorithmFactory, MatrixWorkspaceProperty, Progress, InstrumentValidator +from mantid.kernel import Direction +import numpy as np +from scipy import integrate +import scipy as sp +import mlzutils + + +class ComputeCalibrationCoefVan(PythonAlgorithm): + """ Calculate coefficients to normalize by Vanadium and correct Debye Waller factor + """ + def __init__(self): + """ + Init + """ + PythonAlgorithm.__init__(self) + self.vanaws = None + self.defaultT = 293.0 # K, default temperature if not given + self.Mvan = 50.942 # [g/mol], Vanadium molar mass + self.DebyeT = 389.0 # K, Debye temperature for Vanadium + + def category(self): + """ Return category + """ + return "PythonAlgorithms;CorrectionFunctions\\EfficiencyCorrections" + + def name(self): + """ Return summary + """ + return "ComputeCalibrationCoefVan" + + def summary(self): + return "Calculate coefficients for detector efficiency correction using the Vanadium data." + + def PyInit(self): + """ Declare properties + """ + self.declareProperty(MatrixWorkspaceProperty("VanadiumWorkspace", "", direction=Direction.Input, + validator=InstrumentValidator()), + "Input Vanadium workspace") + self.declareProperty(MatrixWorkspaceProperty("OutputWorkspace", "", direction=Direction.Output), + "Name the workspace that will contain the calibration coefficients") + return + + def validateInputs(self): + issues = dict() + inws = self.getProperty("VanadiumWorkspace").value + run = inws.getRun() + + if not run.hasProperty('wavelength'): + issues['VanadiumWorkspace'] = "Input workspace must have wavelength sample log." + else: + try: + float(run.getProperty('wavelength').value) + except ValueError: + issues['VanadiumWorkspace'] = "Invalid value for wavelength sample log. Wavelength must be a number." + + return issues + + def get_temperature(self): + """ + tries to get temperature from the sample logs + in the case of fail, default value is returned + """ + run = self.vanaws.getRun() + if not run.hasProperty('temperature'): + self.log().warning("Temperature sample log is not present in " + self.vanaws.getName() + + " T=293K is assumed for Debye-Waller factor.") + return self.defaultT + try: + temperature = float(run.getProperty('temperature').value) + except ValueError, err: + self.log().warning("Error of getting temperature: " + err + + " T=293K is assumed for Debye-Waller factor.") + return self.defaultT + + return temperature + + def PyExec(self): + """ Main execution body + """ + self.vanaws = self.getProperty("VanadiumWorkspace").value # returns workspace instance + outws_name = self.getPropertyValue("OutputWorkspace") # returns workspace name (string) + nhist = self.vanaws.getNumberHistograms() + prog_reporter = Progress(self, start=0.0, end=1.0, nreports=nhist+1) + + # calculate array of Debye-Waller factors + dwf = self.calculate_dwf() + + # for each detector: fit gaussian to get peak_centre and fwhm + # sum data in the range [peak_centre - 3*fwhm, peak_centre + 3*fwhm] + dataX = self.vanaws.readX(0) + coefY = np.zeros(nhist) + coefE = np.zeros(nhist) + instrument = self.vanaws.getInstrument() + detID_offset = self.get_detID_offset() + for idx in range(nhist): + prog_reporter.report("Setting %dth spectrum" % idx) + dataY = self.vanaws.readY(idx) + det = instrument.getDetector(idx + detID_offset) + if np.max(dataY) == 0 or det.isMasked(): + coefY[idx] = 0. + coefE[idx] = 0. + else: + dataE = self.vanaws.readE(idx) + peak_centre, sigma = mlzutils.do_fit_gaussian(self.vanaws, idx, self.log()) + fwhm = sigma*2.*np.sqrt(2.*np.log(2.)) + idxmin = (np.fabs(dataX-peak_centre+3.*fwhm)).argmin() + idxmax = (np.fabs(dataX-peak_centre-3.*fwhm)).argmin() + coefY[idx] = dwf[idx]*sum(dataY[idxmin:idxmax+1]) + coefE[idx] = dwf[idx]*sum(dataE[idxmin:idxmax+1]) + + # create X array, X data are the same for all detectors, so + coefX = np.zeros(nhist) + coefX.fill(dataX[0]) + + create = self.createChildAlgorithm("CreateWorkspace") + create.setPropertyValue('OutputWorkspace', outws_name) + create.setProperty('ParentWorkspace', self.vanaws) + create.setProperty('DataX', coefX) + create.setProperty('DataY', coefY) + create.setProperty('DataE', coefE) + create.setProperty('NSpec', nhist) + create.setProperty('UnitX', 'TOF') + create.execute() + outws = create.getProperty('OutputWorkspace').value + + self.setProperty("OutputWorkspace", outws) + + def get_detID_offset(self): + """ + returns ID of the first detector + """ + return self.vanaws.getSpectrum(0).getDetectorIDs()[0] + + def calculate_dwf(self): + """ + Calculates Debye-Waller factor according to + Sears and Shelley Acta Cryst. A 47, 441 (1991) + """ + run = self.vanaws.getRun() + nhist = self.vanaws.getNumberHistograms() + thetasort = np.zeros(nhist) # theta in radians, not 2Theta + + instrument = self.vanaws.getInstrument() + detID_offset = self.get_detID_offset() + + for i in range(nhist): + det = instrument.getDetector(i + detID_offset) + thetasort[i] = 0.5*np.sign(np.cos(det.getPhi()))*self.vanaws.detectorTwoTheta(det) + # thetasort[i] = 0.5*self.vanaws.detectorSignedTwoTheta(det) # gives opposite sign for detectors 0-24 + + temperature = self.get_temperature() # T in K + wlength = float(run.getLogData('wavelength').value) # Wavelength, Angstrom + mass_vana = 0.001*self.Mvan/sp.constants.N_A # Vanadium mass, kg + temp_ratio = temperature/self.DebyeT + + if temp_ratio < 1.e-3: + integral = 0.5 + else: + integral = integrate.quad(lambda x: x/sp.tanh(0.5*x/temp_ratio), 0, 1)[0] + + msd = 3.*sp.constants.hbar**2/(2.*mass_vana*sp.constants.k * self.DebyeT)*integral*1.e20 + return np.exp(-msd*(4.*sp.pi*sp.sin(thetasort)/wlength)**2) + + +# Register algorithm with Mantid. +AlgorithmFactory.subscribe(ComputeCalibrationCoefVan) diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/DetectorFloodWeighting.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/DetectorFloodWeighting.py index ffe6574e3e1326047cfee48cf811b073889f061c..32bb98f27c6a938069e1ccb3c01af95a91ac9472 100644 --- a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/DetectorFloodWeighting.py +++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/DetectorFloodWeighting.py @@ -86,14 +86,14 @@ class DetectorFloodWeighting(DataProcessorAlgorithm): divide.setProperty("RHSWorkspace", rhs) divide.execute() return divide.getProperty("OutputWorkspace").value - + def _add(self, lhs, rhs): divide = self.createChildAlgorithm("Plus") divide.setProperty("LHSWorkspace", lhs) divide.setProperty("RHSWorkspace", rhs) divide.execute() return divide.getProperty("OutputWorkspace").value - + def _integrate_bands(self, bands, in_ws): # Formulate bands, integrate and sum accumulated_output = None diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/EVSDiffractionReduction.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/EVSDiffractionReduction.py index 7fc7669b87706f09e5faec5f0b8e607dcb950867..69a0a5485cf1d5ce2e9d537260f2e60f09e913d5 100644 --- a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/EVSDiffractionReduction.py +++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/EVSDiffractionReduction.py @@ -1,3 +1,4 @@ +#pylint: disable=no-init from mantid.simpleapi import * from mantid.api import * from mantid.kernel import * diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ResNorm2.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ResNorm2.py index 960820fb8a070abd43f2ce9f20876c8f4d51428d..461f44dfac4040837f72c838ae4e1d8c4fd1a4a2 100644 --- a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ResNorm2.py +++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ResNorm2.py @@ -55,8 +55,8 @@ class ResNorm(PythonAlgorithm): direction=Direction.Output), doc='Fitted parameter output') - self.declareProperty(ITableWorkspaceProperty('OutputWorkspaceTable', '', - optional=PropertyMode.Optional, + self.declareProperty(ITableWorkspaceProperty('OutputWorkspaceTable', '', + optional=PropertyMode.Optional, direction=Direction.Output), doc='Table workspace of fit parameters') diff --git a/Framework/PythonInterface/plugins/algorithms/mlzutils.py b/Framework/PythonInterface/plugins/algorithms/mlzutils.py index 3b69302522b7ef2cd6d2eba41c946e3e548d5673..d0e47dbdc7891c084a714360e66ae6daf3b60f81 100644 --- a/Framework/PythonInterface/plugins/algorithms/mlzutils.py +++ b/Framework/PythonInterface/plugins/algorithms/mlzutils.py @@ -1,4 +1,6 @@ import mantid.simpleapi as api +from mantid.api import AlgorithmManager +import numpy as np def cleanup(wslist): @@ -154,3 +156,69 @@ def compare_mandatory(wslist, plist, logger, tolerance=0.01): "Workspaces: " + ", ".join(wslist) + "\n Values: " + str(properties) logger.error(message) raise RuntimeError(message) + + +def do_fit_gaussian(workspace, index, logger): + """ + Calculates guess values on peak centre, sigma and peak height. + Uses them as an input to run a fit algorithm + @ param workspace --- input workspace + @ param index --- the spectrum with which WorkspaceIndex to fit + @ returns peak_centre --- fitted peak centre + @ returns sigma --- fitted sigma + """ + nhist = workspace.getNumberHistograms() + if index > nhist: + message = "Index " + str(index) + " is out of range for the workspace " + workspace.getName() + logger.error(message) + raise RuntimeError(message) + + x_values = np.array(workspace.readX(index)) + y_values = np.array(workspace.readY(index)) + + # get peak centre position + imax = np.argmax(y_values) + height = y_values[imax] + + # check for zero or negative signal + if height <= 0: + logger.warning("Workspace %s, detector %d has maximum <= 0" % (workspace.getName(), index)) + return [0, 0] + + try_centre = x_values[imax] + + # guess sigma + indices = np.argwhere(y_values > 0.5*height) + nentries = len(indices) + if nentries < 3: + message = "Spectrum " + str(index) + " in workspace " + workspace.getName() +\ + " has too narrow peak. Cannot guess sigma. Check your data." + logger.error(message) + raise RuntimeError(message) + # fwhm = sigma * (2.*np.sqrt(2.*np.log(2.))) + fwhm = np.fabs(x_values[indices[nentries - 1, 0]] - x_values[indices[0, 0]]) + sigma = fwhm/(2.*np.sqrt(2.*np.log(2.))) + + # create and execute Fit algorithm + myfunc = 'name=Gaussian, Height='+str(height)+', PeakCentre='+str(try_centre)+', Sigma='+str(sigma) + startX = try_centre - 3.0*fwhm + endX = try_centre + 3.0*fwhm + prefix = "Fit" + workspace.getName() + str(index) + fit_alg = AlgorithmManager.createUnmanaged('Fit') + fit_alg.initialize() + fit_alg.setChild(True) + api.set_properties(fit_alg, Function=myfunc, InputWorkspace=workspace, CreateOutput=True, Output=prefix) + fit_alg.setProperty('StartX', startX) + fit_alg.setProperty('EndX', endX) + fit_alg.setProperty('WorkspaceIndex', index) + fit_successful = fit_alg.execute() + param_table = fit_alg.getProperty('OutputParameters').value + + if not fit_successful: + message = "For detector " + str(index) + " in workspace " + workspace.getName() +\ + "fit was not successful. Input guess parameters are " + str(myfunc) + logger.error(message) + raise RuntimeError(message) + + # return list: [peak_centre, sigma] + return param_table.column(1)[1:3] diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/CMakeLists.txt b/Framework/PythonInterface/test/python/plugins/algorithms/CMakeLists.txt index 06aefc104046e72c2151ed57d7933b8230e6daec..952bb617bfa603aaaedee0c7393bf6f8a7ad9af5 100644 --- a/Framework/PythonInterface/test/python/plugins/algorithms/CMakeLists.txt +++ b/Framework/PythonInterface/test/python/plugins/algorithms/CMakeLists.txt @@ -8,6 +8,7 @@ set ( TEST_PY_FILES CalculateSampleTransmissionTest.py CheckForSampleLogsTest.py ConjoinSpectraTest.py + ComputeCalibrationCoefVanTest.py CorrectLogTimesTest.py CreateLeBailFitInputTest.py CreateMDTest.py diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/ComputeCalibrationCoefVanTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/ComputeCalibrationCoefVanTest.py new file mode 100644 index 0000000000000000000000000000000000000000..aff74c2e324ac2e288cce0a16a55727b9000f691 --- /dev/null +++ b/Framework/PythonInterface/test/python/plugins/algorithms/ComputeCalibrationCoefVanTest.py @@ -0,0 +1,82 @@ +import unittest +from mantid.simpleapi import DeleteWorkspace, CreateSampleWorkspace, AddSampleLog, EditInstrumentGeometry,\ + CloneWorkspace, CheckWorkspacesMatch +from testhelpers import run_algorithm +from mantid.api import AnalysisDataService +from scipy.constants import N_A, hbar, k +import numpy as np + + +class ComputeCalibrationCoefVanTest(unittest.TestCase): + def setUp(self): + input_ws = CreateSampleWorkspace(Function="User Defined", + UserDefinedFunction="name=LinearBackground, A0=0.3;name=Gaussian, \ + PeakCentre=5, Height=10, Sigma=0.3", NumBanks=2, BankPixelWidth=1, + XMin=0, XMax=10, BinWidth=0.1, BankDistanceFromSample=4.0) + self._input_ws = input_ws + AddSampleLog(self._input_ws, LogName='wavelength', LogText='4.0', LogType='Number', LogUnit='Angstrom') + + def test_output(self): + outputWorkspaceName = "output_ws" + alg_test = run_algorithm("ComputeCalibrationCoefVan", VanadiumWorkspace=self._input_ws, + OutputWorkspace=outputWorkspaceName) + self.assertTrue(alg_test.isExecuted()) + wsoutput = AnalysisDataService.retrieve(outputWorkspaceName) + + # Output = Vanadium ws + self.assertEqual(wsoutput.getRun().getLogData('run_title').value, + self._input_ws.getRun().getLogData('run_title').value) + + # Size of output workspace + self.assertEqual(wsoutput.getNumberHistograms(), self._input_ws.getNumberHistograms()) + + DeleteWorkspace(wsoutput) + return + + def test_sum(self): + outputWorkspaceName = "output_ws" + alg_test = run_algorithm("ComputeCalibrationCoefVan", VanadiumWorkspace=self._input_ws, + OutputWorkspace=outputWorkspaceName) + self.assertTrue(alg_test.isExecuted()) + wsoutput = AnalysisDataService.retrieve(outputWorkspaceName) + + # check whether sum is calculated correctly, for theta=0, dwf=1 + y_sum = sum(self._input_ws.readY(0)[27:75]) + self.assertAlmostEqual(y_sum, wsoutput.readY(0)[0]) + + DeleteWorkspace(wsoutput) + + def test_dwf(self): + outputWorkspaceName = "output_ws" + + # change theta to make dwf != 1 + EditInstrumentGeometry(self._input_ws, L2="4,8", Polar="0,15", Azimuthal="0,0", DetectorIDs="1,2") + alg_test = run_algorithm("ComputeCalibrationCoefVan", VanadiumWorkspace=self._input_ws, + OutputWorkspace=outputWorkspaceName) + self.assertTrue(alg_test.isExecuted()) + wsoutput = AnalysisDataService.retrieve(outputWorkspaceName) + + # check dwf calculation + y_sum = sum(self._input_ws.readY(1)[27:75]) + mvan = 0.001*50.942/N_A + Bcoef = 4.736767162094296*1e+20*hbar*hbar/(2.0*mvan*k*389.0) + dwf = np.exp(-1.0*Bcoef*(4.0*np.pi*np.sin(0.5*np.radians(15.0))/4.0)**2) + self.assertAlmostEqual(y_sum*dwf, wsoutput.readY(1)[0]) + + DeleteWorkspace(wsoutput) + + def test_input_not_modified(self): + backup = CloneWorkspace(self._input_ws) + outputWorkspaceName = "output_ws" + alg_test = run_algorithm("ComputeCalibrationCoefVan", VanadiumWorkspace=self._input_ws, + OutputWorkspace=outputWorkspaceName) + self.assertTrue(alg_test.isExecuted()) + self.assertEqual("Success!", CheckWorkspacesMatch(backup, self._input_ws)) + DeleteWorkspace(backup) + + def tearDown(self): + if AnalysisDataService.doesExist(self._input_ws.getName()): + DeleteWorkspace(self._input_ws) + +if __name__ == "__main__": + unittest.main() diff --git a/Framework/WorkflowAlgorithms/inc/MantidWorkflowAlgorithms/MuonCalculateAsymmetry.h b/Framework/WorkflowAlgorithms/inc/MantidWorkflowAlgorithms/MuonCalculateAsymmetry.h index 70f448d5433155eb5d1fd7ca0cb2d466a832e7bb..0d8c35783d1c54ea3aad93fc4231da183b59000b 100644 --- a/Framework/WorkflowAlgorithms/inc/MantidWorkflowAlgorithms/MuonCalculateAsymmetry.h +++ b/Framework/WorkflowAlgorithms/inc/MantidWorkflowAlgorithms/MuonCalculateAsymmetry.h @@ -49,12 +49,22 @@ private: void init(); void exec(); - /// Converts given workspace according to the OutputType - API::MatrixWorkspace_sptr convertWorkspace(API::MatrixWorkspace_sptr ws); - - /// Merges two period workspaces according to PeriodOperation specified - API::MatrixWorkspace_sptr mergePeriods(API::MatrixWorkspace_sptr ws1, - API::MatrixWorkspace_sptr ws2); + // Calculates raw counts + API::MatrixWorkspace_sptr + calculateGroupCounts(const API::MatrixWorkspace_sptr &firstPeriodWS, + const API::MatrixWorkspace_sptr &secondPeriodWS, + int groupIndex, std::string op); + // Calculates asymmetry for specified spectrum + API::MatrixWorkspace_sptr + calculateGroupAsymmetry(const API::MatrixWorkspace_sptr &firstPeriodWS, + const API::MatrixWorkspace_sptr &secondPeriodWS, + int groupIndex, std::string op); + // Calculates asymmetry for a pair of spectra + API::MatrixWorkspace_sptr + calculatePairAsymmetry(const API::MatrixWorkspace_sptr &firstPeriodWS, + const API::MatrixWorkspace_sptr &secondPeriodWS, + int firstPairIndex, int secondPairIndex, double alpha, + std::string op); }; } // namespace WorkflowAlgorithms diff --git a/Framework/WorkflowAlgorithms/src/MuonCalculateAsymmetry.cpp b/Framework/WorkflowAlgorithms/src/MuonCalculateAsymmetry.cpp index ee9504bc04cea99fe906da51ab70484da81c0b83..0b5ee591080593aa78fc74fd76f7b8b71f7ed1d1 100644 --- a/Framework/WorkflowAlgorithms/src/MuonCalculateAsymmetry.cpp +++ b/Framework/WorkflowAlgorithms/src/MuonCalculateAsymmetry.cpp @@ -107,125 +107,286 @@ void MuonCalculateAsymmetry::exec() { MatrixWorkspace_sptr firstPeriodWS = getProperty("FirstPeriodWorkspace"); MatrixWorkspace_sptr secondPeriodWS = getProperty("SecondPeriodWorkspace"); - MatrixWorkspace_sptr convertedWS; + // The type of calculation + const std::string type = getPropertyValue("OutputType"); - if (secondPeriodWS) { - // Two periods - MatrixWorkspace_sptr mergedWS = mergePeriods(firstPeriodWS, secondPeriodWS); - convertedWS = convertWorkspace(mergedWS); + // The group index + int groupIndex = getProperty("GroupIndex"); + + // The type of period operation (+ or -) + std::string op = getProperty("PeriodOperation"); + + if (type == "GroupCounts") { + + auto outWS = + calculateGroupCounts(firstPeriodWS, secondPeriodWS, groupIndex, op); + + setProperty("OutputWorkspace", outWS); + + } else if (type == "GroupAsymmetry") { + + auto outWS = + calculateGroupAsymmetry(firstPeriodWS, secondPeriodWS, groupIndex, op); + + setProperty("OutputWorkspace", outWS); + + } else if (type == "PairAsymmetry") { + + int pairFirstIndex = getProperty("PairFirstIndex"); + int pairSecondIndex = getProperty("PairSecondIndex"); + double alpha = getProperty("Alpha"); + + auto outWS = + calculatePairAsymmetry(firstPeriodWS, secondPeriodWS, pairFirstIndex, + pairSecondIndex, alpha, op); + + setProperty("OutputWorkspace", outWS); } else { - // Single period only - convertedWS = convertWorkspace(firstPeriodWS); - } - setProperty("OutputWorkspace", convertedWS); + throw std::invalid_argument("Specified OutputType is not supported"); + } } /** - * Converts given workspace according to the OutputType. - * @param ws :: Workspace to convert - * @return Converted workspace - */ -MatrixWorkspace_sptr -MuonCalculateAsymmetry::convertWorkspace(MatrixWorkspace_sptr ws) { - const std::string type = getPropertyValue("OutputType"); +* Calculates raw counts according to period operation +* @param firstPeriodWS :: [input] First period workspace +* @param secondPeriodWS :: [input] Second period workspace +* @param groupIndex :: [input] Index of the workspace to extract counts from +* @param op :: [input] Period operation (+ or -) +*/ +MatrixWorkspace_sptr MuonCalculateAsymmetry::calculateGroupCounts( + const MatrixWorkspace_sptr &firstPeriodWS, + const MatrixWorkspace_sptr &secondPeriodWS, int groupIndex, + std::string op) { - if (type == "GroupCounts" || type == "GroupAsymmetry") { - int groupIndex = getProperty("GroupIndex"); + if (secondPeriodWS) { + // Two periods supplied - if (groupIndex == EMPTY_INT()) - throw std::runtime_error("GroupIndex is not specified"); + MatrixWorkspace_sptr tempWS; - // Yank out the counts of requested group - IAlgorithm_sptr alg = createChildAlgorithm("ExtractSingleSpectrum"); - alg->initialize(); - alg->setProperty("InputWorkspace", ws); - alg->setProperty("WorkspaceIndex", groupIndex); - alg->execute(); + if (op == "+") { - MatrixWorkspace_sptr outWS = alg->getProperty("OutputWorkspace"); + IAlgorithm_sptr alg = createChildAlgorithm("Plus"); + alg->initialize(); + alg->setProperty("LHSWorkspace", firstPeriodWS); + alg->setProperty("RHSWorkspace", secondPeriodWS); + alg->execute(); + tempWS = alg->getProperty("OutputWorkspace"); - if (type == "GroupAsymmetry") { - // GroupAsymmetry - counts with ExpDecay removed and normalized + } else if (op == "-") { - IAlgorithm_sptr alg = createChildAlgorithm("RemoveExpDecay"); + IAlgorithm_sptr alg = createChildAlgorithm("Minus"); alg->initialize(); - alg->setProperty("InputWorkspace", outWS); + alg->setProperty("LHSWorkspace", firstPeriodWS); + alg->setProperty("RHSWorkspace", secondPeriodWS); alg->execute(); - - outWS = alg->getProperty("OutputWorkspace"); + tempWS = alg->getProperty("OutputWorkspace"); } - return outWS; - } else if (type == "PairAsymmetry") { - // PairAsymmetry - result of AsymmetryCalc algorithm - - int pairFirstIndex = getProperty("PairFirstIndex"); - int pairSecondIndex = getProperty("PairSecondIndex"); - - if (pairFirstIndex == EMPTY_INT() || pairSecondIndex == EMPTY_INT()) - throw std::invalid_argument("Both pair indices should be specified"); - - double alpha = getProperty("Alpha"); + IAlgorithm_sptr alg = createChildAlgorithm("ExtractSingleSpectrum"); + alg->initialize(); + alg->setProperty("InputWorkspace", tempWS); + alg->setProperty("WorkspaceIndex", groupIndex); + alg->execute(); + MatrixWorkspace_sptr outWS = alg->getProperty("OutputWorkspace"); - // We get pair groups as their workspace indices, but AsymmetryCalc wants - // spectra numbers, - // so need to convert - specid_t spectraNo1 = ws->getSpectrum(pairFirstIndex)->getSpectrumNo(); - specid_t spectraNo2 = ws->getSpectrum(pairSecondIndex)->getSpectrumNo(); + return outWS; - if (spectraNo1 == -1 || spectraNo2 == -1 || spectraNo1 == spectraNo2) - throw std::invalid_argument( - "Spectra numbers of the input workspace are not set properly"); + } else { + // Only one period supplied - IAlgorithm_sptr alg = createChildAlgorithm("AsymmetryCalc"); - alg->setProperty("InputWorkspace", ws); - // As strings, cause otherwise would need to create arrays with single - // elements - alg->setPropertyValue("ForwardSpectra", - boost::lexical_cast<std::string>(spectraNo1)); - alg->setPropertyValue("BackwardSpectra", - boost::lexical_cast<std::string>(spectraNo2)); - alg->setProperty("Alpha", alpha); + IAlgorithm_sptr alg = createChildAlgorithm("ExtractSingleSpectrum"); + alg->initialize(); + alg->setProperty("InputWorkspace", firstPeriodWS); + alg->setProperty("WorkspaceIndex", groupIndex); alg->execute(); - MatrixWorkspace_sptr outWS = alg->getProperty("OutputWorkspace"); return outWS; } - - throw std::invalid_argument("Specified OutputType is not supported"); } /** - * Merges two period workspaces according to PeriodOperation specified. - * @param ws1 :: First period workspace - * @param ws2 :: Second period workspace - * @return Merged workspace - */ -MatrixWorkspace_sptr -MuonCalculateAsymmetry::mergePeriods(MatrixWorkspace_sptr ws1, - MatrixWorkspace_sptr ws2) { - std::string op = getProperty("PeriodOperation"); +* Calculates single-spectrum asymmetry according to period operation +* @param firstPeriodWS :: [input] First period workspace +* @param secondPeriodWS :: [input] Second period workspace +* @param groupIndex :: [input] Workspace index for which to calculate asymmetry +* @param op :: [input] Period operation (+ or -) +*/ +MatrixWorkspace_sptr MuonCalculateAsymmetry::calculateGroupAsymmetry( + const MatrixWorkspace_sptr &firstPeriodWS, + const MatrixWorkspace_sptr &secondPeriodWS, int groupIndex, + std::string op) { + + // The output workspace + MatrixWorkspace_sptr tempWS; + + if (secondPeriodWS) { + // Two period workspaces where supplied + + if (op == "+") { - std::string algorithmName; + // Sum + IAlgorithm_sptr alg = createChildAlgorithm("Plus"); + alg->initialize(); + alg->setProperty("LHSWorkspace", firstPeriodWS); + alg->setProperty("RHSWorkspace", secondPeriodWS); + alg->execute(); + MatrixWorkspace_sptr sumWS = alg->getProperty("OutputWorkspace"); + + // GroupIndex as vector + // Necessary if we want RemoveExpDecay to fit only the requested + // spectrum + std::vector<int> spec(1, groupIndex); + + // Remove decay + IAlgorithm_sptr asym = createChildAlgorithm("RemoveExpDecay"); + asym->setProperty("InputWorkspace", sumWS); + asym->setProperty("Spectra", spec); + asym->execute(); + tempWS = asym->getProperty("OutputWorkspace"); + + } else if (op == "-") { + + // GroupIndex as vector + std::vector<int> spec(1, groupIndex); + + // Remove decay (first period ws) + IAlgorithm_sptr asym = createChildAlgorithm("RemoveExpDecay"); + asym->initialize(); + asym->setProperty("InputWorkspace", firstPeriodWS); + asym->setProperty("Spectra", spec); + asym->execute(); + MatrixWorkspace_sptr asymFirstPeriod = + asym->getProperty("OutputWorkspace"); + + // Remove decay (second period ws) + asym = createChildAlgorithm("RemoveExpDecay"); + asym->initialize(); + asym->setProperty("InputWorkspace", secondPeriodWS); + asym->setProperty("Spectra", spec); + asym->execute(); + MatrixWorkspace_sptr asymSecondPeriod = + asym->getProperty("OutputWorkspace"); + + // Now subtract + IAlgorithm_sptr alg = createChildAlgorithm("Minus"); + alg->initialize(); + alg->setProperty("LHSWorkspace", asymFirstPeriod); + alg->setProperty("RHSWorkspace", asymSecondPeriod); + alg->execute(); + tempWS = alg->getProperty("OutputWorkspace"); + } + } else { + // Only one period was supplied - if (op == "+") { - algorithmName = "Plus"; - } else if (op == "-") { - algorithmName = "Minus"; + IAlgorithm_sptr alg = createChildAlgorithm("RemoveExpDecay"); + alg->initialize(); + alg->setProperty("InputWorkspace", firstPeriodWS); + alg->execute(); + tempWS = alg->getProperty("OutputWorkspace"); } - IAlgorithm_sptr alg = createChildAlgorithm(algorithmName); + // Extract the requested spectrum + IAlgorithm_sptr alg = createChildAlgorithm("ExtractSingleSpectrum"); alg->initialize(); - alg->setProperty("LHSWorkspace", ws1); - alg->setProperty("RHSWorkspace", ws2); + alg->setProperty("InputWorkspace", tempWS); + alg->setProperty("WorkspaceIndex", groupIndex); alg->execute(); - MatrixWorkspace_sptr outWS = alg->getProperty("OutputWorkspace"); - return outWS; } + +/** +* Calculates pair asymmetry according to period operation +* @param firstPeriodWS :: [input] First period workspace +* @param secondPeriodWS :: [input] Second period workspace +* @param firstPairIndex :: [input] Workspace index for the forward group +* @param secondPairIndex :: [input] Workspace index for the backward group +* @param alpha :: [input] The balance parameter +* @param op :: [input] Period operation (+ or -) +*/ +MatrixWorkspace_sptr MuonCalculateAsymmetry::calculatePairAsymmetry( + const MatrixWorkspace_sptr &firstPeriodWS, + const MatrixWorkspace_sptr &secondPeriodWS, int firstPairIndex, + int secondPairIndex, double alpha, std::string op) { + + // Pair indices as vectors + std::vector<int> fwd(1, firstPairIndex + 1); + std::vector<int> bwd(1, secondPairIndex + 1); + + if (secondPeriodWS) { + + MatrixWorkspace_sptr outWS; + + if (op == "+") { + + // Sum + IAlgorithm_sptr alg = createChildAlgorithm("Plus"); + alg->initialize(); + alg->setProperty("LHSWorkspace", firstPeriodWS); + alg->setProperty("RHSWorkspace", secondPeriodWS); + alg->execute(); + MatrixWorkspace_sptr sumWS = alg->getProperty("OutputWorkspace"); + + // Asymmetry calculation + alg = createChildAlgorithm("AsymmetryCalc"); + alg->setProperty("InputWorkspace", sumWS); + alg->setProperty("ForwardSpectra", fwd); + alg->setProperty("BackwardSpectra", bwd); + alg->setProperty("Alpha", alpha); + alg->execute(); + outWS = alg->getProperty("OutputWorkspace"); + + } else if (op == "-") { + + std::vector<int> fwd(1, firstPairIndex + 1); + std::vector<int> bwd(1, secondPairIndex + 1); + + // First period asymmetry + IAlgorithm_sptr alg = createChildAlgorithm("AsymmetryCalc"); + alg->setProperty("InputWorkspace", firstPeriodWS); + alg->setProperty("ForwardSpectra", fwd); + alg->setProperty("BackwardSpectra", bwd); + alg->setProperty("Alpha", alpha); + alg->execute(); + MatrixWorkspace_sptr asymFirstPeriod = + alg->getProperty("OutputWorkspace"); + + // Second period asymmetry + alg = createChildAlgorithm("AsymmetryCalc"); + alg->setProperty("InputWorkspace", secondPeriodWS); + alg->setProperty("ForwardSpectra", fwd); + alg->setProperty("BackwardSpectra", bwd); + alg->setProperty("Alpha", alpha); + alg->execute(); + MatrixWorkspace_sptr asymSecondPeriod = + alg->getProperty("OutputWorkspace"); + + // Now subtract + alg = createChildAlgorithm("Minus"); + alg->initialize(); + alg->setProperty("LHSWorkspace", asymFirstPeriod); + alg->setProperty("RHSWorkspace", asymSecondPeriod); + alg->execute(); + outWS = alg->getProperty("OutputWorkspace"); + } + + return outWS; + + } else { + + IAlgorithm_sptr alg = createChildAlgorithm("AsymmetryCalc"); + alg->setProperty("InputWorkspace", firstPeriodWS); + alg->setProperty("ForwardSpectra", fwd); + alg->setProperty("BackwardSpectra", bwd); + alg->setProperty("Alpha", alpha); + alg->execute(); + MatrixWorkspace_sptr outWS = alg->getProperty("OutputWorkspace"); + + return outWS; + } +} } // namespace WorkflowAlgorithms } // namespace Mantid diff --git a/Framework/WorkflowAlgorithms/src/RefReduction.cpp b/Framework/WorkflowAlgorithms/src/RefReduction.cpp index 9cc5678a2d2df87113a607c4a9ac52bc0976f26b..5a85b6b69186405fdeae7e31bee928b7e11f1dd3 100644 --- a/Framework/WorkflowAlgorithms/src/RefReduction.cpp +++ b/Framework/WorkflowAlgorithms/src/RefReduction.cpp @@ -612,16 +612,35 @@ double RefReduction::calculateAngleREFM(MatrixWorkspace_sptr workspace) { double dangle = getProperty("DetectorAngle"); if (isEmpty(dangle)) { Mantid::Kernel::Property *prop = workspace->run().getProperty("DANGLE"); + if (!prop) { + throw std::runtime_error("DetectorAngle property not given as input, and " + "could not find the log entry DANGLE either"); + } Mantid::Kernel::TimeSeriesProperty<double> *dp = dynamic_cast<Mantid::Kernel::TimeSeriesProperty<double> *>(prop); + if (!dp) { + throw std::runtime_error( + "The log entry DANGLE could not" + "be interpreted as a property of type time series of double"); + } dangle = dp->getStatistics().mean; } double dangle0 = getProperty("DetectorAngle0"); if (isEmpty(dangle0)) { Mantid::Kernel::Property *prop = workspace->run().getProperty("DANGLE0"); + if (!prop) { + throw std::runtime_error("DetectorAngle0 property not given aas input, " + "and could not find the log entry DANGLE0 " + "either"); + } Mantid::Kernel::TimeSeriesProperty<double> *dp = dynamic_cast<Mantid::Kernel::TimeSeriesProperty<double> *>(prop); + if (!dp) { + throw std::runtime_error( + "The log entry DANGLE0 could not " + "be interpreted as a property of type time series of double values"); + } dangle0 = dp->getStatistics().mean; } diff --git a/Framework/WorkflowAlgorithms/test/MuonCalculateAsymmetryTest.h b/Framework/WorkflowAlgorithms/test/MuonCalculateAsymmetryTest.h index 0d2038ad16f5aca37a804114647c0c3dfd1a2e9e..8b19f4693fb2f5ab6e98d44afdd88dafa5c84f35 100644 --- a/Framework/WorkflowAlgorithms/test/MuonCalculateAsymmetryTest.h +++ b/Framework/WorkflowAlgorithms/test/MuonCalculateAsymmetryTest.h @@ -171,7 +171,7 @@ public: AnalysisDataService::Instance().remove(outWSName); } - void test_groupAsymmetry() { + void test_groupAsymmetry_singlePeriod() { // Name of the output workspace. const std::string outWSName = outputWorkspaceName("GroupAsymmetry"); @@ -213,7 +213,96 @@ public: AnalysisDataService::Instance().remove(outWSName); } - void test_pairAsymmetry() { + void test_groupAsymmetry_twoPeriods_minus() { + // Name of the output workspace. + const std::string outWSName = outputWorkspaceName("GroupAsymmetry"); + + MatrixWorkspace_sptr inWS = createWorkspace(3); + MatrixWorkspace_sptr inWSSecond = createWorkspace(); + + MuonCalculateAsymmetry alg; + alg.initialize(); + alg.setProperty("FirstPeriodWorkspace", inWS); + alg.setProperty("SecondPeriodWorkspace", inWSSecond); + alg.setProperty("PeriodOperation", "-"); + alg.setProperty("OutputType", "GroupAsymmetry"); + alg.setProperty("GroupIndex", 2); + alg.setPropertyValue("OutputWorkspace", outWSName); + TS_ASSERT_THROWS_NOTHING(alg.execute();); + TS_ASSERT(alg.isExecuted()); + + // Retrieve the workspace from data service. + auto ws = + AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(outWSName); + TS_ASSERT(ws); + + if (ws) { + TS_ASSERT_EQUALS(ws->getNumberHistograms(), 1); + TS_ASSERT_EQUALS(ws->blocksize(), 3); + + TS_ASSERT_EQUALS(ws->readX(0)[0], 1); + TS_ASSERT_EQUALS(ws->readX(0)[1], 2); + TS_ASSERT_EQUALS(ws->readX(0)[2], 3); + + TS_ASSERT_DELTA(ws->readY(0)[0], 0.0030, 0.0001); + TS_ASSERT_DELTA(ws->readY(0)[1], -0.0455, 0.0001); + TS_ASSERT_DELTA(ws->readY(0)[2], -0.1511, 0.0001); + + TS_ASSERT_DELTA(ws->readE(0)[0], 0.1066, 0.0001); + TS_ASSERT_DELTA(ws->readE(0)[1], 0.1885, 0.0001); + TS_ASSERT_DELTA(ws->readE(0)[2], 0.3295, 0.0001); + } + + // Remove workspace from the data service. + AnalysisDataService::Instance().remove(outWSName); + } + + void test_groupAsymmetry_twoPeriods_plus() { + + // Name of the output workspace. + const std::string outWSName = outputWorkspaceName("GroupAsymmetry"); + + MatrixWorkspace_sptr inWS = createWorkspace(3); + MatrixWorkspace_sptr inWSSecond = createWorkspace(); + + MuonCalculateAsymmetry alg; + alg.initialize(); + alg.setProperty("FirstPeriodWorkspace", inWS); + alg.setProperty("SecondPeriodWorkspace", inWSSecond); + alg.setProperty("PeriodOperation", "+"); + alg.setProperty("OutputType", "GroupAsymmetry"); + alg.setProperty("GroupIndex", 1); + alg.setPropertyValue("OutputWorkspace", outWSName); + TS_ASSERT_THROWS_NOTHING(alg.execute();); + TS_ASSERT(alg.isExecuted()); + + // Retrieve the workspace from data service. + auto ws = + AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(outWSName); + TS_ASSERT(ws); + + if (ws) { + TS_ASSERT_EQUALS(ws->getNumberHistograms(), 1); + TS_ASSERT_EQUALS(ws->blocksize(), 3); + + TS_ASSERT_EQUALS(ws->readX(0)[0], 1); + TS_ASSERT_EQUALS(ws->readX(0)[1], 2); + TS_ASSERT_EQUALS(ws->readX(0)[2], 3); + + TS_ASSERT_DELTA(ws->readY(0)[0], -0.2529, 0.0001); + TS_ASSERT_DELTA(ws->readY(0)[1], 0.3918, 0.0001); + TS_ASSERT_DELTA(ws->readY(0)[2], 1.5316, 0.0001); + + TS_ASSERT_DELTA(ws->readE(0)[0], 0.0547, 0.0001); + TS_ASSERT_DELTA(ws->readE(0)[1], 0.1010, 0.0001); + TS_ASSERT_DELTA(ws->readE(0)[2], 0.1825, 0.0001); + } + + // Remove workspace from the data service. + AnalysisDataService::Instance().remove(outWSName); + } + + void test_pairAsymmetry_singlePeriod() { // Name of the output workspace. const std::string outWSName = outputWorkspaceName("GroupAsymmetry"); @@ -257,6 +346,98 @@ public: AnalysisDataService::Instance().remove(outWSName); } + void test_pairAsymmetry_twoPeriods_minus() { + // Name of the output workspace. + const std::string outWSName = outputWorkspaceName("GroupAsymmetry"); + + MatrixWorkspace_sptr inWS = createWorkspace(3); + MatrixWorkspace_sptr inWSSecond = createWorkspace(); + + MuonCalculateAsymmetry alg; + alg.initialize(); + alg.setProperty("FirstPeriodWorkspace", inWS); + alg.setProperty("SecondPeriodWorkspace", inWSSecond); + alg.setProperty("PeriodOperation", "-"); + alg.setProperty("OutputType", "PairAsymmetry"); + alg.setProperty("PeriodOperation", "-"); + alg.setProperty("PairFirstIndex", 2); + alg.setProperty("PairSecondIndex", 0); + alg.setPropertyValue("OutputWorkspace", outWSName); + TS_ASSERT_THROWS_NOTHING(alg.execute()); + TS_ASSERT(alg.isExecuted()); + + // Retrieve the workspace from data service. + auto ws = + AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(outWSName); + TS_ASSERT(ws); + + if (ws) { + TS_ASSERT_EQUALS(ws->getNumberHistograms(), 1); + TS_ASSERT_EQUALS(ws->blocksize(), 3); + + TS_ASSERT_DELTA(ws->readY(0)[0], -0.3214, 0.0001); + TS_ASSERT_DELTA(ws->readY(0)[1], -0.2250, 0.0001); + TS_ASSERT_DELTA(ws->readY(0)[2], -0.1666, 0.0001); + + TS_ASSERT_EQUALS(ws->readX(0)[0], 1.5); + TS_ASSERT_EQUALS(ws->readX(0)[1], 2.5); + TS_ASSERT_EQUALS(ws->readX(0)[2], 3); + + TS_ASSERT_DELTA(ws->readE(0)[0], 0.5290, 0.001); + TS_ASSERT_DELTA(ws->readE(0)[1], 0.4552, 0.001); + TS_ASSERT_DELTA(ws->readE(0)[2], 0.4073, 0.001); + } + + // Remove workspace from the data service. + AnalysisDataService::Instance().remove(outWSName); + } + + void test_pairAsymmetry_twoPeriods_plus() { + + // Name of the output workspace. + const std::string outWSName = outputWorkspaceName("GroupAsymmetry"); + + MatrixWorkspace_sptr inWS = createWorkspace(3); + MatrixWorkspace_sptr inWSSecond = createWorkspace(); + + MuonCalculateAsymmetry alg; + alg.initialize(); + alg.setProperty("FirstPeriodWorkspace", inWS); + alg.setProperty("SecondPeriodWorkspace", inWSSecond); + alg.setProperty("PeriodOperation", "+"); + alg.setProperty("OutputType", "PairAsymmetry"); + alg.setProperty("PairFirstIndex", 0); + alg.setProperty("PairSecondIndex", 2); + alg.setPropertyValue("OutputWorkspace", outWSName); + TS_ASSERT_THROWS_NOTHING(alg.execute();); + TS_ASSERT(alg.isExecuted()); + + // Retrieve the workspace from data service. + auto ws = + AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(outWSName); + TS_ASSERT(ws); + + if (ws) { + TS_ASSERT_EQUALS(ws->getNumberHistograms(), 1); + TS_ASSERT_EQUALS(ws->blocksize(), 3); + + TS_ASSERT_EQUALS(ws->readX(0)[0], 1.5); + TS_ASSERT_EQUALS(ws->readX(0)[1], 2.5); + TS_ASSERT_EQUALS(ws->readX(0)[2], 3); + + TS_ASSERT_DELTA(ws->readY(0)[0], -0.5454, 0.0001); + TS_ASSERT_DELTA(ws->readY(0)[1], -0.4615, 0.0001); + TS_ASSERT_DELTA(ws->readY(0)[2], -0.4000, 0.0001); + + TS_ASSERT_DELTA(ws->readE(0)[0], 0.2428, 0.0001); + TS_ASSERT_DELTA(ws->readE(0)[1], 0.2159, 0.0001); + TS_ASSERT_DELTA(ws->readE(0)[2], 0.1966, 0.0001); + } + + // Remove workspace from the data service. + AnalysisDataService::Instance().remove(outWSName); + } + private: std::string outputWorkspaceName(std::string testName) { return "MuonCalculateAsymmetryTest_" + testName + "_OutputWS"; diff --git a/MantidPlot/src/Graph.cpp b/MantidPlot/src/Graph.cpp index b90d59c0c2ba39d003eb0589957f4663b3ab805e..2fbfe1977b7b92b4614dbd36e78c743f457c99d5 100644 --- a/MantidPlot/src/Graph.cpp +++ b/MantidPlot/src/Graph.cpp @@ -1290,7 +1290,7 @@ void Graph::linColor() notifyChanges(); } -void Graph::setAxisScale(int axis, double start, double end, int type, double step, +void Graph::setAxisScale(int axis, double start, double end, int scaleType, double step, int majorTicks, int minorTicks) { ScaleEngine *sc_engine = dynamic_cast<ScaleEngine *>(d_plot->axisScaleEngine(axis)); @@ -1300,19 +1300,30 @@ void Graph::setAxisScale(int axis, double start, double end, int type, double st ScaleTransformation::Type old_type = sc_engine->type(); // If not specified, keep the same as now - if( type < 0 ) type = axisType(axis); + if( scaleType < 0 ) scaleType = axisType(axis); - if (type != old_type) + int type = ScaleTransformation::Linear; + // just to have the one-by-one ScaleType => GraphOptions; higher values of ScaleType + // will be GraphOptions::Linear + if (ScaleDraw::ScaleType::Numeric == scaleType) { + type = ScaleTransformation::Linear; + } else if (ScaleDraw::ScaleType::Text == scaleType) { + type = ScaleTransformation::Log10; + } else if (ScaleDraw::ScaleType::Day == scaleType) { + type = ScaleTransformation::Power; + } + + if (static_cast<int>(type) != static_cast<int>(old_type)) { // recalculate boundingRect of MantidCurves - emit axisScaleChanged(axis,type == ScaleTransformation::Log10); + emit axisScaleChanged(axis, type == ScaleTransformation::Log10); } - if (type == GraphOptions::Log10) + if (type == ScaleTransformation::Log10) { sc_engine->setType(ScaleTransformation::Log10); } - else if (type == GraphOptions::Power) + else if (type == ScaleTransformation::Power) { sc_engine->setType(ScaleTransformation::Power); } @@ -1321,7 +1332,7 @@ void Graph::setAxisScale(int axis, double start, double end, int type, double st sc_engine->setType(ScaleTransformation::Linear); } - if (type == GraphOptions::Log10) + if (type == ScaleTransformation::Log10) { if (start <= 0) { @@ -1368,7 +1379,7 @@ void Graph::setAxisScale(int axis, double start, double end, int type, double st // log scales can't represent zero or negative values, 1e-10 is a low number that I hope will be lower than most of the data but is still sensible for many color plots //start = start < 1e-90 ? 1e-10 : start; } - else if (type == GraphOptions::Power) + else if (type == ScaleTransformation::Power) { double const nth_power = sc_engine->nthPower(); if (start <= 0 && nth_power < 0) @@ -1440,8 +1451,7 @@ void Graph::setAxisScale(int axis, double start, double end, int type, double st QwtScaleWidget *rightAxis = d_plot->axisWidget(QwtPlot::yRight); if(rightAxis) { - //if (type == ScaleTransformation::Log10 && (start <= 0 || start == DBL_MAX)) - if (type == GraphOptions::Log10 && (start <= 0 || start == DBL_MAX)) + if (type == ScaleTransformation::Log10 && (start <= 0 || start == DBL_MAX)) { start = sp->getMinPositiveValue(); } diff --git a/MantidPlot/src/Graph.h b/MantidPlot/src/Graph.h index 34ae08f03ca7eacf89224cf0b37a0bffcc81b19d..0b3cdbecd8d2eec45c4f3cb4d9bfe6af4b2101f2 100644 --- a/MantidPlot/src/Graph.h +++ b/MantidPlot/src/Graph.h @@ -385,7 +385,7 @@ public slots: void setScale(QwtPlot::Axis axis, QString logOrLin); double axisStep(int axis){return d_user_step[axis];}; //! Set the axis scale - void setAxisScale(int axis, double start, double end, int type = -1, double step = 0.0, + void setAxisScale(int axis, double start, double end, int scaleType = -1, double step = 0.0, int majorTicks = 5, int minorTicks = 5); /// in plot windows change both axis to log-log diff --git a/MantidPlot/src/ImportASCIIDialog.cpp b/MantidPlot/src/ImportASCIIDialog.cpp index 075910ef35fb89d929af75626a20ae8a6845b781..f8b10566e93fa4cb43a9ed5ad25385d6a984380c 100644 --- a/MantidPlot/src/ImportASCIIDialog.cpp +++ b/MantidPlot/src/ImportASCIIDialog.cpp @@ -464,7 +464,7 @@ void ImportASCIIDialog::previewTable() int importMode = d_import_mode->currentIndex(); if (importMode == NewTables) { - importMode = (ImportASCIIDialog::ImportMode)Table::Overwrite; + importMode = ImportASCIIDialog::NewWorkspace; //(ImportASCIIDialog::ImportMode)Table::Overwrite; } else { importMode -= 2; } @@ -494,7 +494,7 @@ void ImportASCIIDialog::previewMatrix() { int importMode = d_import_mode->currentIndex(); if (importMode == NewMatrices) { - importMode = (ImportASCIIDialog::ImportMode)Matrix::Overwrite; + importMode = ImportASCIIDialog::NewWorkspace; //(ImportASCIIDialog::ImportMode)Matrix::Overwrite; } else { // Overwrite-2 => NewColumns (in both Matrix::importMode and // ImportASCIIDialog::importMode) diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/QtReflMainView.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/QtReflMainView.h index ab2f48dfa2db8daac520f43ab82517c3a5325e67..e57514b3b0750f06dbcc794cdfd578ea1efc4e4c 100644 --- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/QtReflMainView.h +++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/QtReflMainView.h @@ -95,6 +95,7 @@ public: virtual std::string getSearchString() const; virtual boost::shared_ptr<IReflPresenter> getPresenter() const; + private: // initialise the interface virtual void initLayout(); @@ -143,7 +144,7 @@ private slots: void showSearchContextMenu(const QPoint &pos); }; -} // namespace CustomInterfaces } // namespace Mantid +} // namespace CustomInterfaces #endif /* MANTID_CUSTOMINTERFACES_QTREFLMAINVIEW_H_ */ diff --git a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/ReflMainView.h b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/ReflMainView.h index bfcca663b78dc95a9e99974146d2ec1d066007fb..a60b2df5525e7d4ef0a35effba9220db034e6313 100644 --- a/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/ReflMainView.h +++ b/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/ReflMainView.h @@ -59,6 +59,10 @@ namespace MantidQt virtual void showAlgorithmDialog(const std::string& algorithm) = 0; virtual std::string requestNotebookPath() = 0; + //Settings + virtual void saveSettings(const std::map<std::string,QVariant>& options) = 0; + virtual void loadSettings(std::map<std::string,QVariant>& options) = 0; + //Plotting virtual void plotWorkspaces(const std::set<std::string>& workspaces) = 0; diff --git a/MantidQt/CustomInterfaces/src/Indirect/ConvFit.cpp b/MantidQt/CustomInterfaces/src/Indirect/ConvFit.cpp index 07fef6447c8a24678b514740f03f64a9664d855f..e38a224bff1f2b19cf1dbf3c3bad6b7a724deb5e 100644 --- a/MantidQt/CustomInterfaces/src/Indirect/ConvFit.cpp +++ b/MantidQt/CustomInterfaces/src/Indirect/ConvFit.cpp @@ -28,7 +28,8 @@ namespace IDA { ConvFit::ConvFit(QWidget *parent) : IndirectDataAnalysisTab(parent), m_stringManager(NULL), m_cfTree(NULL), - m_fixedProps(), m_cfInputWS(), m_cfInputWSName(), m_confitResFileType() { + m_fixedProps(), m_cfInputWS(), m_cfInputWSName(), m_confitResFileType(), + m_runMin(-1), m_runMax(-1) { m_uiForm.setupUi(parent); } @@ -996,7 +997,7 @@ void ConvFit::updatePlot() { return; if ((specNo - m_runMin) >= 0) { MatrixWorkspace_sptr ws = boost::dynamic_pointer_cast<MatrixWorkspace>( - outputGroup->getItem(specNo- m_runMin)); + outputGroup->getItem(specNo - m_runMin)); if (ws) { m_uiForm.ppPlot->addSpectrum("Fit", ws, 1, Qt::red); m_uiForm.ppPlot->addSpectrum("Diff", ws, 2, Qt::blue); @@ -1102,8 +1103,7 @@ void ConvFit::singleFit() { runPythonCode( QString( "from IndirectCommon import getWSprefix\nprint getWSprefix('") + - m_cfInputWSName + QString("')\n")) - .trimmed(); + m_cfInputWSName + QString("')\n")).trimmed(); m_singleFitOutputName += QString("conv_") + fitType + bgType + m_uiForm.spPlotSpectrum->text(); int maxIterations = diff --git a/MantidQt/CustomInterfaces/src/QtReflMainView.cpp b/MantidQt/CustomInterfaces/src/QtReflMainView.cpp index f3632eaf125e82c4d98e20af56f2a998ad70bcea..2723cd05a2779d7712ba4611ec522047e81dda1a 100644 --- a/MantidQt/CustomInterfaces/src/QtReflMainView.cpp +++ b/MantidQt/CustomInterfaces/src/QtReflMainView.cpp @@ -8,6 +8,12 @@ #include <qinputdialog.h> #include <qmessagebox.h> + +namespace +{ + const QString ReflSettingsGroup = "Mantid/CustomInterfaces/ISISReflectometry"; +} + namespace MantidQt { namespace CustomInterfaces @@ -450,6 +456,33 @@ namespace MantidQt return qfilename.toStdString(); } + /** + Save settings + @param options : map of user options to save + */ + void QtReflMainView::saveSettings(const std::map<std::string,QVariant>& options) + { + QSettings settings; + settings.beginGroup(ReflSettingsGroup); + for(auto it = options.begin(); it != options.end(); ++it) + settings.setValue(QString::fromStdString(it->first), it->second); + settings.endGroup(); + } + + /** + Load settings + @param options : map of user options to load into + */ + void QtReflMainView::loadSettings(std::map<std::string,QVariant>& options) + { + QSettings settings; + settings.beginGroup(ReflSettingsGroup); + QStringList keys = settings.childKeys(); + for(auto it = keys.begin(); it != keys.end(); ++it) + options[it->toStdString()] = settings.value(*it); + settings.endGroup(); + } + /** Plot a workspace */ diff --git a/MantidQt/CustomInterfaces/src/ReflMainViewPresenter.cpp b/MantidQt/CustomInterfaces/src/ReflMainViewPresenter.cpp index 2aedd280cf80054880642b336291837ffc642aa8..9323fb9b10cc1e91839a520a0f17ac3b65a302f9 100644 --- a/MantidQt/CustomInterfaces/src/ReflMainViewPresenter.cpp +++ b/MantidQt/CustomInterfaces/src/ReflMainViewPresenter.cpp @@ -24,9 +24,6 @@ #include <fstream> #include <sstream> -#include <QSettings> -#include <QFileDialog> - using namespace Mantid::API; using namespace Mantid::Geometry; @@ -36,7 +33,6 @@ using namespace MantidQt::MantidWidgets; namespace { - const QString ReflSettingsGroup = "Mantid/CustomInterfaces/ISISReflectometry"; void validateModel(ITableWorkspace_sptr model) { @@ -1511,11 +1507,7 @@ namespace MantidQt m_options[it->first] = it->second; //Save any changes to disk - QSettings settings; - settings.beginGroup(ReflSettingsGroup); - for(auto it = m_options.begin(); it != m_options.end(); ++it) - settings.setValue(QString::fromStdString(it->first), it->second); - settings.endGroup(); + m_view->saveSettings(m_options); } /** Load options from disk if possible, or set to defaults */ @@ -1537,12 +1529,7 @@ namespace MantidQt m_options["RoundDQQPrecision"] = 3; //Load saved values from disk - QSettings settings; - settings.beginGroup(ReflSettingsGroup); - QStringList keys = settings.childKeys(); - for(auto it = keys.begin(); it != keys.end(); ++it) - m_options[it->toStdString()] = settings.value(*it); - settings.endGroup(); + m_view->loadSettings(m_options); } } } diff --git a/MantidQt/CustomInterfaces/test/ReflMainViewMockObjects.h b/MantidQt/CustomInterfaces/test/ReflMainViewMockObjects.h index 026b49d21b3e9966e32a84f26c1b3df3b72ea023..e42a5a70d0bc573e435fb47faf22d0f7b0a6a2b6 100644 --- a/MantidQt/CustomInterfaces/test/ReflMainViewMockObjects.h +++ b/MantidQt/CustomInterfaces/test/ReflMainViewMockObjects.h @@ -57,6 +57,8 @@ public: virtual void setProgress(int) {}; virtual void setTableList(const std::set<std::string>&) {}; virtual void setInstrumentList(const std::vector<std::string>&, const std::string&) {}; + virtual void saveSettings(const std::map<std::string,QVariant>&) {}; + virtual void loadSettings(std::map<std::string,QVariant>&) {}; virtual std::string getProcessInstrument() const {return "FAKE";} virtual boost::shared_ptr<IReflPresenter> getPresenter() const {return boost::shared_ptr<IReflPresenter>();} }; diff --git a/MantidQt/Python/mantidqt.sip b/MantidQt/Python/mantidqt.sip index 47824677bf3e1bcd8e3a02a951fbbfa38afd5ad5..8278d788941a600a84f1dd6cc448d1fde138bc8f 100644 --- a/MantidQt/Python/mantidqt.sip +++ b/MantidQt/Python/mantidqt.sip @@ -1171,9 +1171,9 @@ void SliceViewer::setRebinNumBins(int xBins, int yBins) %End - void setRebinMode(bool mode, bool locked) throw (std::runtime_error); + void setRebinMode(bool mode) throw (std::runtime_error); %Docstring -void SliceViewer::setRebinMode(bool mode, bool locked) +void SliceViewer::setRebinMode(bool mode) ------------------------------------------------------ Sets the SliceViewer in dynamic rebin mode. In this mode, the current view area (see setXYLimits()) is used as the @@ -1183,8 +1183,6 @@ void SliceViewer::setRebinMode(bool mode, bool locked) Args: mode :: true for rebinning mode - locked :: if true, then the rebinned area is only refreshed manually - or when changing rebinning parameters. %End diff --git a/MantidQt/SliceViewer/inc/MantidQtSliceViewer/SliceViewer.h b/MantidQt/SliceViewer/inc/MantidQtSliceViewer/SliceViewer.h index f2eded1e2fa66061992d0583adf13527708f6afc..75014b4c584c09308350b1e6a85956cc64fa9d8a 100644 --- a/MantidQt/SliceViewer/inc/MantidQtSliceViewer/SliceViewer.h +++ b/MantidQt/SliceViewer/inc/MantidQtSliceViewer/SliceViewer.h @@ -117,7 +117,7 @@ public: /// Dynamic Rebinning-related Python bindings void setRebinThickness(int dim, double thickness); void setRebinNumBins(int xBins, int yBins); - void setRebinMode(bool mode, bool locked); + void setRebinMode(bool mode); void refreshRebin(); /// Methods relating to peaks overlays. @@ -188,7 +188,6 @@ public slots: void LineMode_toggled(bool); void SnapToGrid_toggled(bool); void RebinMode_toggled(bool); - void RebinLock_toggled(bool); void autoRebin_toggled(bool); // Dynamic rebinning @@ -333,7 +332,7 @@ private: /// Synced menu/buttons MantidQt::API::SyncedCheckboxes *m_syncLineMode, *m_syncSnapToGrid, - *m_syncRebinMode, *m_syncRebinLock, *m_syncAutoRebin; + *m_syncRebinMode, *m_syncAutoRebin; /// Cached double for infinity double m_inf; diff --git a/MantidQt/SliceViewer/inc/MantidQtSliceViewer/SliceViewer.ui b/MantidQt/SliceViewer/inc/MantidQtSliceViewer/SliceViewer.ui index 9414476bc32f0f92da829ed186475e2fdcb485cb..d3b64c0df10eab853bd8fcc3abe0e5fe74e5c353 100644 --- a/MantidQt/SliceViewer/inc/MantidQtSliceViewer/SliceViewer.ui +++ b/MantidQt/SliceViewer/inc/MantidQtSliceViewer/SliceViewer.ui @@ -489,47 +489,6 @@ </property> </widget> </item> - <item> - <widget class="QToolButton" name="btnRebinLock"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="minimumSize"> - <size> - <width>45</width> - <height>45</height> - </size> - </property> - <property name="maximumSize"> - <size> - <width>45</width> - <height>45</height> - </size> - </property> - <property name="toolTip"> - <string>Lock the rebinned workspace in place (use the refresh button to refresh)</string> - </property> - <property name="text"> - <string>...</string> - </property> - <property name="icon"> - <iconset> - <normaloff>:/SliceViewer/icons/stock-lock.png</normaloff>:/SliceViewer/icons/stock-lock.png</iconset> - </property> - <property name="iconSize"> - <size> - <width>32</width> - <height>32</height> - </size> - </property> - <property name="checkable"> - <bool>true</bool> - </property> - <property name="checked"> - <bool>true</bool> - </property> - </widget> - </item> <item> <spacer name="horizontalSpacer_5"> <property name="orientation"> diff --git a/MantidQt/SliceViewer/src/SliceViewer.cpp b/MantidQt/SliceViewer/src/SliceViewer.cpp index f251baaf4445e9f32142a3d54ea3d16ef6fe62a6..34bba3a13bc370f18250ec802dc46ad8a141908e 100644 --- a/MantidQt/SliceViewer/src/SliceViewer.cpp +++ b/MantidQt/SliceViewer/src/SliceViewer.cpp @@ -122,8 +122,6 @@ SliceViewer::SliceViewer(QWidget *parent) // hide unused buttons ui.btnZoom->hide(); // hidden for a long time - ui.btnRebinLock->hide(); // now replaced by auto rebin mode - // ui.btnClearLine->hide(); // turning off line mode now removes line // ----------- Toolbar button signals ---------------- QObject::connect(ui.btnResetZoom, SIGNAL(clicked()), this, SLOT(resetZoom())); @@ -379,13 +377,6 @@ void SliceViewer::initMenus() { SLOT(RebinMode_toggled(bool))); m_menuView->addAction(action); - action = new QAction(QPixmap(), "&Lock Rebinned WS", this); - m_syncRebinLock = new SyncedCheckboxes(action, ui.btnRebinLock, true); - connect(m_syncRebinLock, SIGNAL(toggled(bool)), this, - SLOT(RebinLock_toggled(bool))); - action->setVisible(false); // hide this action - m_menuView->addAction(action); - action = new QAction(QPixmap(), "Rebin Current View", this); action->setShortcut(Qt::Key_R + Qt::ControlModifier); action->setEnabled(false); @@ -691,7 +682,6 @@ void SliceViewer::setWorkspace(Mantid::API::IMDWorkspace_sptr ws) { // Can't use dynamic rebin mode with a MatrixWorkspace m_syncRebinMode->setEnabled(!matrix); - m_syncRebinLock->setEnabled(!matrix); // Go to no normalization by default for MatrixWorkspaces if (matrix) @@ -1008,13 +998,10 @@ void SliceViewer::setRebinNumBins(int xBins, int yBins) { * See setRebinThickness() to adjust the thickness in other dimensions. * * @param mode :: true for rebinning mode - * @param locked :: if true, then the rebinned area is only refreshed manually - * or when changing rebinning parameters. */ -void SliceViewer::setRebinMode(bool mode, bool locked) { +void SliceViewer::setRebinMode(bool mode) { // The events associated with these controls will trigger a re-draw m_syncRebinMode->toggle(mode); - m_syncRebinLock->toggle(locked); } //------------------------------------------------------------------------------ @@ -1098,7 +1085,6 @@ void SliceViewer::RebinMode_toggled(bool checked) { for (size_t d = 0; d < m_dimWidgets.size(); d++) m_dimWidgets[d]->showRebinControls(checked); ui.btnRebinRefresh->setEnabled(checked); - ui.btnRebinLock->setEnabled(checked); m_syncAutoRebin->setEnabled(checked); m_actionRefreshRebin->setEnabled(checked); m_rebinMode = checked; @@ -1118,17 +1104,6 @@ void SliceViewer::RebinMode_toggled(bool checked) { } } -//------------------------------------------------------------------------------ -/** Slot called when locking/unlocking the dynamically rebinned - * overlaid workspace - * @param checked :: DO lock the workspace in place - */ -void SliceViewer::RebinLock_toggled(bool checked) { - m_rebinLocked = checked; - // Rebin immediately - if (!m_rebinLocked && m_rebinMode) - this->rebinParamsChanged(); -} //------------------------------------------------------------------------------ /// Slot for zooming into diff --git a/MantidQt/SliceViewer/test/SliceViewerPythonInterfaceTest.py b/MantidQt/SliceViewer/test/SliceViewerPythonInterfaceTest.py index f7ac61b15e55516acb33bf420257de185ef081dc..cff5c28c1d8bc20a66cc35ae89fff4f6f0cb077d 100644 --- a/MantidQt/SliceViewer/test/SliceViewerPythonInterfaceTest.py +++ b/MantidQt/SliceViewer/test/SliceViewerPythonInterfaceTest.py @@ -449,7 +449,7 @@ class SliceViewerPythonInterfaceTest(unittest.TestCase): sv.setRebinThickness(2, 1.0) sv.setRebinNumBins(50, 200) sv.refreshRebin() - sv.setRebinMode(True, True) + sv.setRebinMode(True) time.sleep(1) self.assertTrue(mtd.doesExist('uniform_rebinned'), 'Dynamically rebinned workspace was created.') ws = mtd['uniform_rebinned'] diff --git a/Testing/SystemTests/tests/analysis/ValidateInstrumentDefinitionFiles.py b/Testing/SystemTests/tests/analysis/ValidateInstrumentDefinitionFiles.py index 70f51e4427d150b0679b9fa6579287cf043b1e07..299d6d5dc17f3a001ae3e1cb7aa485ce5db73da2 100644 --- a/Testing/SystemTests/tests/analysis/ValidateInstrumentDefinitionFiles.py +++ b/Testing/SystemTests/tests/analysis/ValidateInstrumentDefinitionFiles.py @@ -1,3 +1,4 @@ +#pylint: disable=invalid-name #pylint: disable=no-init from mantid import config import os diff --git a/Testing/SystemTests/tests/analysis/reference/MuonLoad_MUSR00015192.nxs.md5 b/Testing/SystemTests/tests/analysis/reference/MuonLoad_MUSR00015192.nxs.md5 index 26060d7d5d3cf334ac8181df8c1433b7d1113530..f5e0395c9f732ac49915ea272c372dda1a7c5366 100644 --- a/Testing/SystemTests/tests/analysis/reference/MuonLoad_MUSR00015192.nxs.md5 +++ b/Testing/SystemTests/tests/analysis/reference/MuonLoad_MUSR00015192.nxs.md5 @@ -1 +1 @@ -f9f8aee9e15f495f43a9846da7adad3e +75b425bdf72f1d82bb78e0c71a7fe2ca diff --git a/docs/source/algorithms/ComputeCalibrationCoefVan-v1.rst b/docs/source/algorithms/ComputeCalibrationCoefVan-v1.rst new file mode 100644 index 0000000000000000000000000000000000000000..47661c2ffe102b08e1a498d0c60dc5ee66232113 --- /dev/null +++ b/docs/source/algorithms/ComputeCalibrationCoefVan-v1.rst @@ -0,0 +1,83 @@ +.. algorithm:: + +.. summary:: + +.. alias:: + +.. properties:: + +Description +----------- + +Algorithm creates a workspace with detector sensitivity correction coefficients using the given Vanadium workspace. The correction coefficients are calculated as follows. + +1. Calculate the Debye-Waller factor according to Sears and Shelley *Acta Cryst. A* **47**, 441 (1991): + + :math:`D_i = \exp\left(-B_i\cdot\frac{4\pi\sin\theta_i}{\lambda^2}\right)` + + :math:`B_i = \frac{3\hbar^2\cdot 10^{20}}{2m_VkT_m}\cdot J(y)` + + where :math:`J(y) = 0.5` if :math:`y < 10^{-3}`, otherwise + + :math:`J(y) = \int_0^1 x\cdot\mathrm{coth}\left(\frac{x}{2y}\right)\,\mathrm{d}x` + + where :math:`y=T/T_m` is the ratio of the temperature during the experiment :math:`T` to the Debye temperature :math:`T_m = 389K`, :math:`m_V` is the Vanadium atomic mass (in kg) and :math:`\theta_i` is the polar angle of the i-th detector. + +.. warning:: + + If sample log *temperature* is not present in the given Vanadium workspace or temperature is set to an invalid value, T=293K will be taken for the Debye-Waller factor calculation. Algorithm will produce warning in this case. + +2. Perform Gaussian fit of the data to find out the position of the peak centre and FWHM. These values are used to calculate sum :math:`S_i` as + + :math:`S_i = \sum_{x = x_C - 3\,\mathrm{fwhm}}^{x_C + 3\,\mathrm{fwhm}} Y_i(x)` + + where :math:`x_C` is the peak centre position and :math:`Y_i(x)` is the coresponding to :math:`x` :math:`Y` value for i-th detector. + +3. Finally, the correction coefficients :math:`K_i` are calculated as + + :math:`K_i = D_i\times S_i` + +Workspace containing these correction coefficients is created as an output and can be used as a RHS workspace in :ref:`algm-Divide` to apply correction to the LHS workspace. + +.. note:: + + If gaussian fit fails, algorithm terminates with an error message. The error message contains name of the workspace and detector number. + +Restrictions on the input workspace +################################### + +The valid input workspace: + +- must have an instrument set +- must have a *wavelength* sample log + + +Usage +----- + +**Example** + +.. testcode:: ExComputeCalibrationCoefVan + + # load Vanadium data + wsVana = LoadMLZ(Filename='TOFTOFTestdata.nxs') + # calculate correction coefficients + wsCoefs = ComputeCalibrationCoefVan(wsVana) + print 'Spectrum 4 of the output workspace is filled with: ', round(wsCoefs.readY(999)[0]) + + # wsCoefs can be used as rhs with Divide algorithm to apply correction to the data + wsCorr = wsVana/wsCoefs + print 'Spectrum 4 of the input workspace is filled with: ', round(wsVana.readY(999)[0], 1) + print 'Spectrum 4 of the corrected workspace is filled with: ', round(wsCorr.readY(999)[0], 5) + +Output: + +.. testoutput:: ExComputeCalibrationCoefVan + + Spectrum 4 of the output workspace is filled with: 6596.0 + Spectrum 4 of the input workspace is filled with: 1.0 + Spectrum 4 of the corrected workspace is filled with: 0.00015 + +.. categories:: + +.. sourcelink:: diff --git a/docs/source/algorithms/ConvertCWSDExpToMomentum-v1.rst b/docs/source/algorithms/ConvertCWSDExpToMomentum-v1.rst index 904b8dd2a5ccd21368da10509b6c936c4aa5fe42..1d88cdd45e69e58036d500ee26a3af2f5b079de6 100644 --- a/docs/source/algorithms/ConvertCWSDExpToMomentum-v1.rst +++ b/docs/source/algorithms/ConvertCWSDExpToMomentum-v1.rst @@ -19,18 +19,22 @@ In this algorithm's name, ConvertCWSDToMomentum, *CW* stands for constant wave This algorithm takes ??? as inputs. Futhermore, the unit of the output matrix workspace can be converted to -momentum transfer (:math:`Q`). +momentum transfer (Q). Outline of algorithm #################### -1. Create output workspace. +1. Create output workspace + * Build a virtual instrument, requiring + - position of source - position of sample - detector ID, position, detector size of pixels + 2. Read in data via table workspace + * From each row, (1) file name and (2) starting detector ID are read in. * Detector position in (virtual) instrument of MDEventWorkspace is compared with the position in MatrixWorkspace * Momentum is calcualted by goniometry values @@ -75,8 +79,6 @@ Each MDEvent in output MDEventWorkspace contain * Detector ID * Run Number - - Combine Experiment Into One MDEventWorkspace -------------------------------------------- @@ -90,7 +92,7 @@ In order to integrate them into an organized data structure, i.e., *MDEventWorks a virtual instrument is built in the algorithm. Virtual instrument -================== +################## A virtual instrument is built in the algorithm. In this virtual instrument, the number of detectors and their position are determined @@ -98,13 +100,13 @@ by the number of individual detector's positions in the *experiment*. MDEventWorkspace -================ +################ There is only one *virtual* instrument and *N* ExperimentInfo. *N* is the total number of experiment points in the *experiment*. Inconsistency between using virtual instrument and copying instrument -===================================================================== +##################################################################### It is found that the results, i.e., the peak's position in sample-momentum space, by FindPeaksMD, are different betweent the MDEventWorkspaces @@ -145,7 +147,7 @@ with 2D angular detector. Usage ----- -**Example - convert an HB3A's experiment to MDWorkspace in sample momentum workspae and creating virtual instrument.:** +**Example - convert an HB3A's experiment to MDWorkspace in sample momentum workspae and creating virtual instrument** .. testcode:: ExConvertHB3AToMDVirtualInstrument diff --git a/docs/source/algorithms/LoadEventAndCompress-v1.rst b/docs/source/algorithms/LoadEventAndCompress-v1.rst index 904f90502164953738e1a6948991f082077e233c..62a3f3d65ff40e21572ce2ba45219dfb24bfb24a 100644 --- a/docs/source/algorithms/LoadEventAndCompress-v1.rst +++ b/docs/source/algorithms/LoadEventAndCompress-v1.rst @@ -41,6 +41,44 @@ download due to their size. They can however be downloaded using these links: PG3_9830_event = LoadEventAndCompress(Filename='PG3_9830_event.nxs', MaxChunkSize=1.) +**Example - Usage with MPI** + +Create a python driver script called test_mpi.py + +.. code-block:: python + + from mantid.simpleapi import * + import mantid + if AlgorithmFactory.exists('GatherWorkspaces'): + HAVE_MPI = True + from mpi4py import MPI + mpiRank = MPI.COMM_WORLD.Get_rank() + mpiSize = MPI.COMM_WORLD.Get_size() + else: + HAVE_MPI = False + mpiRank = 0 # simplify if clauses + mpiSize = 1 # simplify if clauses + + wksp = LoadEventAndCompress(Filename="PG3_2538_event.nxs") + print "Rank = ", mpiRank, "Number of Events = ", wksp.getNumberEvents() + if mpiRank == 0: + reduce = AlignAndFocusPowder(InputWorkspace=wksp, CalFileName='PG3_calibrate_d2538_2014_05_13.cal', Params='0.5,0.01,2') + SaveNexus(reduce,Filename=str(mpiSize)+"tasks.nxs") + +And run it using the following commands + +.. code-block:: + + $ module load mpi/openmpi-x86_64 + $ export LD_PRELOAD=/usr/lib64/openmpi/lib/libmpi.so + $ mpirun -np 8 mantidpython test_mpi.py + +to run without mpi is simply + +.. code-block:: + + $ mantidpython test_mpi.py + .. categories:: .. sourcelink:: diff --git a/docs/source/algorithms/MuonCalculateAsymmetry-v1.rst b/docs/source/algorithms/MuonCalculateAsymmetry-v1.rst index 1b977a1084e9a7272aefb2610287611cb6e22440..1bbd806a20d33affe4a25d1cc4f652faa373e3d0 100644 --- a/docs/source/algorithms/MuonCalculateAsymmetry-v1.rst +++ b/docs/source/algorithms/MuonCalculateAsymmetry-v1.rst @@ -57,7 +57,7 @@ Output: .. testcode:: ExGroupAsymmetryMultiperiod y1 = [100,50,10] - y2 = [ 50,25, 5] + y2 = [150,20,1] x = [1,2,3] input1 = CreateWorkspace(x, y1) @@ -75,7 +75,7 @@ Output: .. testoutput:: ExGroupAsymmetryMultiperiod - Output: [ 0.1524242 -0.0916425 -0.71360777] + Output: [-0.28634067 0.60594273 0.26255546] .. categories:: diff --git a/docs/source/concepts/DiffractionCalibrationWorkspace.rst b/docs/source/concepts/DiffractionCalibrationWorkspace.rst index 58ee3f066f1239d1014fabe0b5b590fe423205f9..105e6e31562877adb9521585cdb43bf2205a28ff 100644 --- a/docs/source/concepts/DiffractionCalibrationWorkspace.rst +++ b/docs/source/concepts/DiffractionCalibrationWorkspace.rst @@ -57,3 +57,5 @@ various parameters on an instrument view. * ``offset`` (double array) not used. Value of the legacy calibration file. The `group` information will still be extracted into separate `GroupingWorkspace` and `MaskWorkspace`. + +.. categories:: Concepts diff --git a/docs/source/concepts/MDNorm.rst b/docs/source/concepts/MDNorm.rst index 1a1fdf7a1e8cda9fd304ef831f7c0537bcf981d6..8f2d64ba4430c6a34de7cd74f4a404caf449b819 100644 --- a/docs/source/concepts/MDNorm.rst +++ b/docs/source/concepts/MDNorm.rst @@ -158,4 +158,6 @@ Current implementation As of release 3.3, the normalization can be calculated for single crystal diffraction (:ref:`MDNormSCD <algm-MDNormSCD>`) and single crystal direct geometry inelastic scattering -(:ref:`MDNormDirectSC <algm-MDNormDirectSC>`). +(:ref:`MDNormDirectSC <algm-MDNormDirectSC>`). + +.. categories:: Concepts diff --git a/docs/source/concepts/Properties.rst b/docs/source/concepts/Properties.rst index 3ea0cb965e0ad77b4b0a782ffb444d607a7fd356..71d8ab02a89f8b938f78a4585fec228801795fec 100644 --- a/docs/source/concepts/Properties.rst +++ b/docs/source/concepts/Properties.rst @@ -176,8 +176,7 @@ In addition to the above, if used, Workspace properties also have a built in validator that requires that input workspaces exist and are of the correct type and that output workspaces have a name set. -For more details on using validators, see the -`PropertyAlgorithm <https://github.com/mantidproject/mantid/blob/master/Code/Mantid/Framework/UserAlgorithms/PropertyAlgorithm.cpp>`__ +For more details on using validators, see the :ref:`PropertyAlgorithm <algm-PropertyAlgorithm>` example or the full documentation for the individual validators (linked above). @@ -186,4 +185,4 @@ to implement the IValidator interface. -.. categories:: Concepts \ No newline at end of file +.. categories:: Concepts diff --git a/docs/source/interfaces/HFIR_4Circle_Reduction.rst b/docs/source/interfaces/HFIR_4Circle_Reduction.rst new file mode 100644 index 0000000000000000000000000000000000000000..01c42636b87472ebfb13e637f5a3ceb0597b8c99 --- /dev/null +++ b/docs/source/interfaces/HFIR_4Circle_Reduction.rst @@ -0,0 +1,116 @@ +HFIR Single Crystal Reduction Interface +======================================= + +.. contents:: Table of Contents + :local: + +Overview +-------- + +HFIR single crystalreduction interface is a GUI to download, view and reduce data from +HFIR's four-circle single crystal diffractometer in SPICE format. + + +Introduction of Tabs +-------------------- + + 1. **Setup and Data Access**: Configure the instrument name, data server URL and directories. + + - Configure the instrument name; + - Set up and test HB3A data server's URL; + - Configure the directory to save raw data; + - Configure the directory to save working result; + - Download data from server; + + 2. **View Raw Data**: View 2D image of counts on detector of one measurement. + + - Plot the counts of the 256 by 256 2D detector; + + 3. **Calculate UB**: Calculate UB matrix. + + - Find peak in one measurement; + - Option to load Miller index directly from SPICE file; + - Calculate UB matrix; + - Re-index the peaks; + + 4. **Merge Scan**: Merge all the measurements in a scan. + + - Merge all measuring points in a scan to an MDEventWorkspace in HKL-frame or Q-sample-frame; + - Allow various ways to set up UB matrix + + 5. **Refine UB**: Refine UB matrix + + - Disabled becaues it is in development still; + + 6. **Peak Integration**: Integrate peaks + + - Disabled because it is still in development. + +Use Cases +--------- + +Here are some use cases that can be used as examples. + + +Workflow to calculate UB matrix ++++++++++++++++++++++++++++++++ + +Here is a typical use case to calculate UB matrix + + 1. User specifies *Experiment* and pushes button *Set* + + 2. User enters tab *View Raw Data* + + 3. User inputs scan number and list all the measuring points + + 4. User views all the measurements + + 5. User finds out the measurement with the strongest reflection and push button use + + 6. GUI shifts to tab *Calculate UB* automatically + + 7. User pushes button *Find Peak* with checking *Load HKL from file* + + 8. GUI finds the peak center and load HKL + + 9. User pushes button *Add peak* to add the peak to table + + 10. User repeats step 2 to 9 to add other peaks + + 11. User select the peaks that are linearly independent and pushes *Calcualte UB* + + 12. GUI calculates UB matrix and show the result + + 13. User may push *Index peak* to use the calculated UB matrix to index peaks in the table to check UB matrix. + + +Workflow to merge measurements in scan +++++++++++++++++++++++++++++++++++++++ + +Here is a typical use case to merge all the measuring points (Pt.) in a scan. + + 1. User specifies *Experiment* and pushes button *Set* + + 2. User enters tab *Merge Scan* + + 3. User specifies the UB matrix either by *From tab Calculate UB* or by entering the values to text editor + + 4. User pushes button *Set*. + + 5. User specifies the frame in which the merged data will be in. If the target frame is Q-Sample-Sapce, then there is + no need to specify UB matrix; + + 6. User specifies the scan numbers and push button *Add*; + + 7. User specifies the base name for the output MDEventWorkspaces; + + 8. User pushes button *Process*; + + 9. User goes to MantidPlot to view the merged scan by SliceView or Vates. + + + +Limitation +---------- + +- HFIR single crystal reduction GUI supports for instrument HB3A only from release 3.5.0 and nightly. diff --git a/docs/sphinxext/mantiddoc/directives/algorithm.py b/docs/sphinxext/mantiddoc/directives/algorithm.py index e01645c182f245813f77a10fedcaa153b782c8d7..9333d680eea9274d2bf3de4d7f6ed1b82a5d56f6 100644 --- a/docs/sphinxext/mantiddoc/directives/algorithm.py +++ b/docs/sphinxext/mantiddoc/directives/algorithm.py @@ -202,7 +202,7 @@ class AlgorithmDirective(AlgorithmBaseDirective): #------------------------------------------------------------------------------------------------------------ -def html_collect_pages(app): +def html_collect_pages(dummy_app): """ Write out unversioned algorithm pages that redirect to the highest version of the algorithm """ diff --git a/docs/sphinxext/mantiddoc/directives/properties.py b/docs/sphinxext/mantiddoc/directives/properties.py index 0531ada285c35b0231d90c388590851163e635ad..2e14a854077bea111e82ccfd43608175a5733b77 100644 --- a/docs/sphinxext/mantiddoc/directives/properties.py +++ b/docs/sphinxext/mantiddoc/directives/properties.py @@ -1,3 +1,4 @@ +#pylint: disable=invalid-name from mantiddoc.directives.base import AlgorithmBaseDirective import string diff --git a/docs/sphinxext/mantiddoc/directives/sourcelink.py b/docs/sphinxext/mantiddoc/directives/sourcelink.py index f60bee49b5fc22ad5029399456c5cba1190f679b..1e436b1f71b441e1c1e965677e7e8391578d7249 100644 --- a/docs/sphinxext/mantiddoc/directives/sourcelink.py +++ b/docs/sphinxext/mantiddoc/directives/sourcelink.py @@ -150,7 +150,7 @@ class SourceLinkDirective(AlgorithmBaseDirective): builddir = os.path.join(builddir, "..", "..") builddir = os.path.abspath(builddir) - for dirName, subdirList, fileList in os.walk(self.source_root): + for dirName, dummy_subdirList, fileList in os.walk(self.source_root): if dirName.startswith(builddir): continue # don't check or add to the cache for fname in fileList: @@ -186,29 +186,31 @@ class SourceLinkDirective(AlgorithmBaseDirective): suggested_path = "os_agnostic_path_to_file_from_Code/Mantid" if len(valid_ext_list) == 0: raise SourceLinkError("No file possibilities for " + file_name + " have been found\n" + - "Please specify a better one using the :filename: opiton or use the " + str(self.file_types.keys()) + " options\n" + - "e.g. \n" + - ".. sourcelink:\n" + - " :" + self.file_types.keys()[0] + ": " + suggested_path + "\n "+ - "or \n" + - ".. sourcelink:\n" + - " :filename: " + file_name) + "Please specify a better one using the :filename: opiton or use the " + + str(self.file_types.keys()) + " options\n" + + "e.g. \n" + + ".. sourcelink:\n" + + " :" + self.file_types.keys()[0] + ": " + suggested_path + "\n "+ + "or \n" + + ".. sourcelink:\n" + + " :filename: " + file_name) #if the have a cpp we should also have a h if ("cpp" in valid_ext_list) or ("h" in valid_ext_list): if ("cpp" not in valid_ext_list) or ("h" not in valid_ext_list): raise SourceLinkError("Only one of .h and .cpp found for " + file_name + "\n" + - "valid files found for " + str(valid_ext_list) + "\n" + - "Please specify the missing one using an " + str(self.file_types.keys()) + " option\n" + - "e.g. \n" + - ".. sourcelink:\n" + - " :" + self.file_types.keys()[0] + ": " + suggested_path) + "valid files found for " + str(valid_ext_list) + "\n" + + "Please specify the missing one using an " + + str(self.file_types.keys()) + " option\n" + + "e.g. \n" + + ".. sourcelink:\n" + + " :" + self.file_types.keys()[0] + ": " + suggested_path) return def output_path_to_page(self, filepath, extension): """ Outputs the source link for a file to the rst page """ - dirName,fName = os.path.split(filepath) + dummy_dirName,fName = os.path.split(filepath) self.add_rst(self.file_types[extension] + ": `" + fName + " <" + self.convert_path_to_github_url(filepath) + ">`_\n\n") return diff --git a/docs/sphinxext/mantiddoc/doctest.py b/docs/sphinxext/mantiddoc/doctest.py index e4364825320559fc06647688164ba4025b609d72..d6d176e0159c852380fc41e67e5d3993c89f0b7d 100644 --- a/docs/sphinxext/mantiddoc/doctest.py +++ b/docs/sphinxext/mantiddoc/doctest.py @@ -198,7 +198,7 @@ class TestCaseReport(object): @property def passed(self): - return (self.failure_descr == "") + return self.failure_descr == "" @property def failed(self): @@ -309,7 +309,7 @@ class DocTestOutputParser(object): % text[1]) results = results[2:] # trim off top two lines of header information maintests, cleanup = self.__split_on_cleanup(results) - overall_success = not (maintests[0] == FAILURE_MARKER) + overall_success = not maintests[0] == FAILURE_MARKER if overall_success: testcases = self.__parse_success(fullname, maintests) diff --git a/scripts/CMakeLists.txt b/scripts/CMakeLists.txt index 7c00c508283118881ab92f0d7c8e6b079bc1f0f3..7cd45300f74869139a60cf613343c6613fe322d6 100644 --- a/scripts/CMakeLists.txt +++ b/scripts/CMakeLists.txt @@ -6,6 +6,7 @@ add_subdirectory(Interface/ui) add_subdirectory(lib1to2/gui) add_subdirectory(PyChop) add_subdirectory(TofConverter) +add_subdirectory(HFIR_4Circle_Reduction) # Chain all required interface custom targets into CompilePyUI add_custom_target(CompilePyUI DEPENDS @@ -15,6 +16,7 @@ add_custom_target(CompilePyUI DEPENDS CompileUITofConverter CompileUIUI CompileUILib1To2 + CompileUIHFIR_4Circle_Reduction ) set ( TEST_PY_FILES diff --git a/scripts/HFIR_4Circle_Reduction.py b/scripts/HFIR_4Circle_Reduction.py new file mode 100644 index 0000000000000000000000000000000000000000..89742c6bfa9f75bb50d994cf3148f7d9e1c84476 --- /dev/null +++ b/scripts/HFIR_4Circle_Reduction.py @@ -0,0 +1,17 @@ +#pylint: disable=invalid-name +from HFIR_4Circle_Reduction import reduce4circleGUI +from PyQt4 import QtGui +import sys + +def qapp(): + if QtGui.QApplication.instance(): + _app = QtGui.QApplication.instance() + else: + _app = QtGui.QApplication(sys.argv) + return _app + +app = qapp() + +reducer = reduce4circleGUI.MainWindow() #the main ui class in this file is called MainWindow +reducer.show() +app.exec_() diff --git a/scripts/HFIR_4Circle_Reduction/CMakeLists.txt b/scripts/HFIR_4Circle_Reduction/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..67fe46df205d951ff83380c933f71c88d5325604 --- /dev/null +++ b/scripts/HFIR_4Circle_Reduction/CMakeLists.txt @@ -0,0 +1,8 @@ +include(UiToPy) + +# List of UIs to Auto convert +set( UI_FILES + MainWindow.ui +) + +UiToPy( UI_FILES CompileUIHFIR_4Circle_Reduction) diff --git a/scripts/HFIR_4Circle_Reduction/MainWindow.ui b/scripts/HFIR_4Circle_Reduction/MainWindow.ui new file mode 100644 index 0000000000000000000000000000000000000000..4f7fa462e7008c7cf9e167e822ad5b0b47996aca --- /dev/null +++ b/scripts/HFIR_4Circle_Reduction/MainWindow.ui @@ -0,0 +1,2312 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>MainWindow</class> + <widget class="QMainWindow" name="MainWindow"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>1292</width> + <height>783</height> + </rect> + </property> + <property name="windowTitle"> + <string>4-Circle Reduction</string> + </property> + <widget class="QWidget" name="centralwidget"> + <layout class="QHBoxLayout" name="horizontalLayout_11"> + <item> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_General"> + <item> + <widget class="QLabel" name="label_exp"> + <property name="font"> + <font> + <weight>75</weight> + <bold>true</bold> + </font> + </property> + <property name="text"> + <string>Experiment</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="lineEdit_exp"> + <property name="minimumSize"> + <size> + <width>40</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>60</width> + <height>16777215</height> + </size> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="pushButton_setExp"> + <property name="text"> + <string>Set</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_11"> + <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="QLabel" name="label_15"> + <property name="font"> + <font> + <weight>75</weight> + <bold>true</bold> + </font> + </property> + <property name="text"> + <string>Unit Cell</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label_16"> + <property name="text"> + <string>a</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="lineEdit_a"> + <property name="maximumSize"> + <size> + <width>120</width> + <height>16777215</height> + </size> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label_23"> + <property name="text"> + <string>b</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="lineEdit_b"> + <property name="maximumSize"> + <size> + <width>120</width> + <height>16777215</height> + </size> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label_24"> + <property name="text"> + <string>c</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="lineEdit_c"> + <property name="maximumSize"> + <size> + <width>120</width> + <height>16777215</height> + </size> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label_25"> + <property name="text"> + <string>alpha</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="lineEdit_alpha"> + <property name="maximumSize"> + <size> + <width>120</width> + <height>16777215</height> + </size> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label_26"> + <property name="text"> + <string>beta</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="lineEdit_beta"> + <property name="maximumSize"> + <size> + <width>120</width> + <height>16777215</height> + </size> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label_27"> + <property name="text"> + <string>gamma</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="lineEdit_gamma"> + <property name="maximumSize"> + <size> + <width>120</width> + <height>16777215</height> + </size> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_Tab"> + <item> + <widget class="QTabWidget" name="tabWidget"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="currentIndex"> + <number>0</number> + </property> + <widget class="QWidget" name="tab"> + <attribute name="title"> + <string>Setup && Data Access</string> + </attribute> + <layout class="QGridLayout" name="gridLayout_5"> + <item row="1" column="0"> + <widget class="QTextEdit" name="textEdit"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + <property name="html"> + <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;">1. Configure the data reduction</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-style:italic;">(a) Do not modify ServerURL unless necessary;</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-style:italic;">(b) Click 'Apply' to check internet connection and directories;</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-style:italic;">(c) If 'Time out' is popped out, try to click 'Apply' again. Server may not be able to respond promptly.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt; font-style:italic;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;">2. Start to reduce data</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-style:italic;">(a) Set</span><span style=" font-size:10pt;"> Experiment</span></p></body></html></string> + </property> + </widget> + </item> + <item row="6" column="0"> + <spacer name="verticalSpacer_2"> + <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 row="0" column="0"> + <widget class="QGroupBox" name="groupBox"> + <property name="title"> + <string>Configuration</string> + </property> + <layout class="QGridLayout" name="gridLayout_11"> + <item row="1" column="2"> + <widget class="QPushButton" name="pushButton_testURLs"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>100</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>200</width> + <height>16777215</height> + </size> + </property> + <property name="text"> + <string>Test</string> + </property> + </widget> + </item> + <item row="2" column="2"> + <widget class="QPushButton" name="pushButton_browseLocalDataDir"> + <property name="text"> + <string>Browse</string> + </property> + </widget> + </item> + <item row="2" column="3"> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Preferred</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="2" column="1"> + <widget class="QLineEdit" name="lineEdit_localSpiceDir"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string><html><head/><body><p>Directory for local data storage</p></body></html></string> + </property> + </widget> + </item> + <item row="0" column="0"> + <widget class="QLabel" name="label_instrument"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Instrument</string> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="label_dir"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>80</width> + <height>0</height> + </size> + </property> + <property name="toolTip"> + <string><html><head/><body><p>Directory for local data storage</p></body></html></string> + </property> + <property name="text"> + <string>Data Directory</string> + </property> + <property name="alignment"> + <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QComboBox" name="comboBox_instrument"> + <item> + <property name="text"> + <string>HB3A</string> + </property> + </item> + </widget> + </item> + <item row="0" column="2"> + <widget class="QPushButton" name="pushButton_useDefaultDir"> + <property name="font"> + <font> + <pointsize>10</pointsize> + </font> + </property> + <property name="toolTip"> + <string><html><head/><body><p>Use default set up</p><p><br/></p></body></html></string> + </property> + <property name="text"> + <string>Load Default</string> + </property> + </widget> + </item> + <item row="3" column="1"> + <widget class="QLineEdit" name="lineEdit_workDir"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string><html><head/><body><p>Directory to save outcome of the data reduction</p></body></html></string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLineEdit" name="lineEdit_url"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_url"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>80</width> + <height>0</height> + </size> + </property> + <property name="toolTip"> + <string><html><head/><body><p>URL of the http server to download HB3A data</p></body></html></string> + </property> + <property name="text"> + <string>Server URL</string> + </property> + </widget> + </item> + <item row="3" column="2"> + <widget class="QPushButton" name="pushButton_browseWorkDir"> + <property name="text"> + <string>Browse</string> + </property> + </widget> + </item> + <item row="3" column="0"> + <widget class="QLabel" name="label_2"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>140</width> + <height>1</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>140</width> + <height>16777215</height> + </size> + </property> + <property name="toolTip"> + <string><html><head/><body><p>Directory to save outcome of the data reduction</p></body></html></string> + </property> + <property name="text"> + <string>Working Direcotry</string> + </property> + </widget> + </item> + <item row="4" column="2"> + <widget class="QPushButton" name="pushButton_applySetup"> + <property name="font"> + <font> + <weight>75</weight> + <bold>true</bold> + </font> + </property> + <property name="text"> + <string>Apply</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item row="4" column="0"> + <widget class="QGroupBox" name="groupBox_2"> + <property name="title"> + <string>Data Download</string> + </property> + <layout class="QGridLayout" name="gridLayout_12"> + <item row="0" column="2"> + <widget class="QPushButton" name="pushButton_browseLocalCache"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>100</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>100</width> + <height>16777215</height> + </size> + </property> + <property name="text"> + <string>Browse</string> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="label"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>80</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string>Scans List</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QComboBox" name="comboBox_mode"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string><html><head/><body><p>Mode &quot;download&quot;: download data to local disk;</p><p>Mode &quot;http server only&quot;: download data to cache, process and delete cached data upon returning</p></body></html></string> + </property> + <item> + <property name="text"> + <string>Download Complete Experiment</string> + </property> + </item> + <item> + <property name="text"> + <string>Download Selected Scans</string> + </property> + </item> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLineEdit" name="lineEdit_localSrcDir"> + <property name="toolTip"> + <string><html><head/><body><p>Cache on local disk. The dowloaded data will be saved to here. </p></body></html></string> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_datamode"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>80</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string>Download Mode</string> + </property> + </widget> + </item> + <item row="0" column="0"> + <widget class="QLabel" name="label_4"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>140</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>140</width> + <height>16777215</height> + </size> + </property> + <property name="text"> + <string>Destination</string> + </property> + </widget> + </item> + <item row="0" column="6"> + <spacer name="horizontalSpacer_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Minimum</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="1" column="2"> + <widget class="QPushButton" name="pushButton_downloadExpData"> + <property name="font"> + <font> + <weight>75</weight> + <bold>true</bold> + </font> + </property> + <property name="toolTip"> + <string><html><head/><body><p><span style=" font-weight:400;">Download scans specified by 'Scans List'; </span></p><p><span style=" font-weight:400;">If 'Scans List' is empty, then the complete experiment data will be downloaded</span></p></body></html></string> + </property> + <property name="text"> + <string>Download</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QLineEdit" name="lineEdit_downloadScans"/> + </item> + <item row="2" column="2"> + <widget class="QPushButton" name="pushButton_ListScans"> + <property name="text"> + <string>List Scans</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item row="3" column="0"> + <spacer name="verticalSpacer_4"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Preferred</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <widget class="QWidget" name="tab_4"> + <attribute name="title"> + <string>View Raw Data</string> + </attribute> + <layout class="QGridLayout" name="gridLayout_9"> + <item row="0" column="0"> + <layout class="QGridLayout" name="gridLayout_3"> + <item row="0" column="3"> + <layout class="QVBoxLayout" name="verticalLayout_5"> + <item> + <layout class="QGridLayout" name="gridLayout"/> + </item> + <item> + <widget class="QGroupBox" name="groupBox_3"> + <property name="title"> + <string>Scan</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QLineEdit" name="lineEdit_run"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>10</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>10000</width> + <height>16777215</height> + </size> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="pushButton_setScanInfo"> + <property name="text"> + <string>Set</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="pushButton_showPtList"> + <property name="text"> + <string>List Pt.</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="Line" name="line"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item> + <widget class="QGroupBox" name="groupBox_4"> + <property name="title"> + <string> Pt</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="QLineEdit" name="lineEdit_rawDataPtNo"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>60</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>1000</width> + <height>16777215</height> + </size> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="pushButton_plotRawPt"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>80</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string>Plot</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="pushButton_usePt4UB"> + <property name="toolTip"> + <string><html><head/><body><p>Use this peak to calcualate UB matrix</p></body></html></string> + </property> + <property name="text"> + <string>Use</string> + </property> + </widget> + </item> + <item> + <spacer name="verticalSpacer_5"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Minimum</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_8"> + <item> + <widget class="QPushButton" name="pushButton_prevPtNumber"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>30</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>40</width> + <height>16777215</height> + </size> + </property> + <property name="toolTip"> + <string><html><head/><body><p>Previous Pt. No</p></body></html></string> + </property> + <property name="text"> + <string><---|</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_7"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Preferred</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>5</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="pushButton_nextPtNumber"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>30</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>40</width> + <height>16777215</height> + </size> + </property> + <property name="text"> + <string>|--></string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </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> + </layout> + </item> + <item row="0" column="0"> + <widget class="MplGraphicsView" name="graphicsView"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <widget class="QWidget" name="tab_2"> + <attribute name="title"> + <string>Calculate UB</string> + </attribute> + <layout class="QGridLayout" name="gridLayout_6"> + <item row="0" column="0"> + <layout class="QVBoxLayout" name="verticalLayout_4"> + <item> + <widget class="QGroupBox" name="groupBox_7"> + <property name="title"> + <string>Add Peak</string> + </property> + <layout class="QGridLayout" name="gridLayout_2"> + <item row="0" column="0"> + <widget class="QLabel" name="label_scanNo"> + <property name="text"> + <string>Scan Number</string> + </property> + </widget> + </item> + <item row="0" column="8"> + <widget class="QLineEdit" name="lineEdit_H"> + <property name="maximumSize"> + <size> + <width>60</width> + <height>40</height> + </size> + </property> + </widget> + </item> + <item row="0" column="2"> + <widget class="QLabel" name="label_PtNo"> + <property name="text"> + <string>Pt Number</string> + </property> + </widget> + </item> + <item row="3" column="12"> + <widget class="QLineEdit" name="lineEdit_sampleQy"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="maximumSize"> + <size> + <width>120</width> + <height>16777215</height> + </size> + </property> + </widget> + </item> + <item row="0" column="11"> + <widget class="QLabel" name="label_11"> + <property name="text"> + <string>K</string> + </property> + </widget> + </item> + <item row="0" column="13"> + <widget class="QLabel" name="label_6"> + <property name="text"> + <string>L</string> + </property> + </widget> + </item> + <item row="3" column="8"> + <widget class="QLineEdit" name="lineEdit_sampleQx"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="maximumSize"> + <size> + <width>120</width> + <height>16777215</height> + </size> + </property> + </widget> + </item> + <item row="3" column="6"> + <widget class="QLabel" name="label_7"> + <property name="text"> + <string> Q-Sample </string> + </property> + <property name="alignment"> + <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item row="0" column="3"> + <widget class="QLineEdit" name="lineEdit_ptNumber"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>60</width> + <height>16777215</height> + </size> + </property> + </widget> + </item> + <item row="3" column="11"> + <widget class="QLabel" name="label_9"> + <property name="text"> + <string>Y</string> + </property> + </widget> + </item> + <item row="3" column="14"> + <widget class="QLineEdit" name="lineEdit_sampleQz"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="maximumSize"> + <size> + <width>120</width> + <height>16777215</height> + </size> + </property> + </widget> + </item> + <item row="3" column="7"> + <widget class="QLabel" name="label_8"> + <property name="text"> + <string>X</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLineEdit" name="lineEdit_scanNumber"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>60</width> + <height>16777215</height> + </size> + </property> + </widget> + </item> + <item row="0" column="12"> + <widget class="QLineEdit" name="lineEdit_K"> + <property name="maximumSize"> + <size> + <width>60</width> + <height>16777215</height> + </size> + </property> + </widget> + </item> + <item row="0" column="14"> + <widget class="QLineEdit" name="lineEdit_L"> + <property name="maximumSize"> + <size> + <width>60</width> + <height>16777215</height> + </size> + </property> + </widget> + </item> + <item row="0" column="7"> + <widget class="QLabel" name="label_12"> + <property name="text"> + <string>H</string> + </property> + </widget> + </item> + <item row="3" column="13"> + <widget class="QLabel" name="label_10"> + <property name="text"> + <string>Z</string> + </property> + </widget> + </item> + <item row="0" column="5"> + <spacer name="horizontalSpacer_4"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Preferred</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="0" column="6"> + <widget class="QLabel" name="label_31"> + <property name="text"> + <string>Miller Index</string> + </property> + </widget> + </item> + <item row="0" column="4"> + <widget class="QPushButton" name="pushButton_findPeak"> + <property name="font"> + <font> + <weight>75</weight> + <bold>true</bold> + </font> + </property> + <property name="text"> + <string>Find Peak</string> + </property> + </widget> + </item> + <item row="3" column="4"> + <widget class="QCheckBox" name="checkBox_loadHKLfromFile"> + <property name="font"> + <font> + <pointsize>9</pointsize> + </font> + </property> + <property name="text"> + <string>Load HKL from file</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_7"> + <item> + <widget class="UBMatrixPeakTable" name="tableWidget_peaksCalUB"/> + </item> + <item> + <layout class="QVBoxLayout" name="verticalLayout_8"> + <item> + <widget class="QPushButton" name="pushButton_addPeakToCalUB"> + <property name="font"> + <font> + <weight>75</weight> + <bold>true</bold> + </font> + </property> + <property name="text"> + <string>Add Peak</string> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="checkBox_roundHKLInt"> + <property name="font"> + <font> + <pointsize>9</pointsize> + </font> + </property> + <property name="text"> + <string>RoundHKL to int</string> + </property> + </widget> + </item> + <item> + <spacer name="verticalSpacer_11"> + <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> + <widget class="QPushButton" name="pushButton_deleteUBPeak"> + <property name="minimumSize"> + <size> + <width>100</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>200</width> + <height>16777215</height> + </size> + </property> + <property name="text"> + <string>Delete</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="pushButton_clearUBPeakTable"> + <property name="text"> + <string>Clear</string> + </property> + </widget> + </item> + <item> + <spacer name="verticalSpacer_7"> + <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> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_13"> + <item> + <widget class="QLabel" name="label_32"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="font"> + <font> + <pointsize>14</pointsize> + <weight>75</weight> + <bold>true</bold> + </font> + </property> + <property name="text"> + <string>UB Matrix</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_6"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Preferred</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="UBMatrixTable" name="tableWidget_ubMatrix"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>360</width> + <height>0</height> + </size> + </property> + <row> + <property name="text"> + <string/> + </property> + </row> + <row> + <property name="text"> + <string/> + </property> + </row> + <row> + <property name="text"> + <string/> + </property> + </row> + <column> + <property name="text"> + <string/> + </property> + </column> + <column> + <property name="text"> + <string/> + </property> + </column> + <column> + <property name="text"> + <string/> + </property> + </column> + </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> + <layout class="QVBoxLayout" name="verticalLayout_12"> + <item> + <widget class="QPushButton" name="pushButton_calUB"> + <property name="minimumSize"> + <size> + <width>100</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>100</width> + <height>16777215</height> + </size> + </property> + <property name="text"> + <string>Calculate UB</string> + </property> + </widget> + </item> + <item> + <spacer name="verticalSpacer_8"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Ignored</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="pushButton_acceptUB"> + <property name="minimumSize"> + <size> + <width>100</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>100</width> + <height>16777215</height> + </size> + </property> + <property name="text"> + <string>Accept</string> + </property> + </widget> + </item> + <item> + <spacer name="verticalSpacer_9"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Preferred</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item> + <spacer name="horizontalSpacer_8"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Ignored</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <layout class="QVBoxLayout" name="verticalLayout_9"> + <item> + <widget class="QPushButton" name="pushButton_indexUBPeaks"> + <property name="minimumSize"> + <size> + <width>100</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>100</width> + <height>16777215</height> + </size> + </property> + <property name="text"> + <string>Index Peak</string> + </property> + </widget> + </item> + <item> + <spacer name="verticalSpacer_12"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Ignored</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="pushButton_resetPeakHKLs"> + <property name="text"> + <string>Reset HKL</string> + </property> + </widget> + </item> + <item> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Preferred</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + </layout> + </item> + </layout> + </item> + </layout> + </widget> + <widget class="QWidget" name="tab_advsetup"> + <attribute name="title"> + <string>Merge Scan</string> + </attribute> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QGroupBox" name="groupBox_5"> + <property name="title"> + <string>UB Matrix</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_13"> + <item> + <widget class="UBMatrixTable" name="tableWidget_ubSiceView"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>16777215</width> + <height>150</height> + </size> + </property> + <row> + <property name="text"> + <string/> + </property> + </row> + <row> + <property name="text"> + <string/> + </property> + </row> + <row> + <property name="text"> + <string/> + </property> + </row> + <column> + <property name="text"> + <string/> + </property> + </column> + <column> + <property name="text"> + <string/> + </property> + </column> + <column> + <property name="text"> + <string/> + </property> + </column> + <item row="0" column="0"> + <property name="text"> + <string>1</string> + </property> + </item> + <item row="1" column="1"> + <property name="text"> + <string>1</string> + </property> + </item> + <item row="2" column="2"> + <property name="text"> + <string>1</string> + </property> + </item> + </widget> + </item> + <item> + <spacer name="verticalSpacer_13"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Ignored</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item> + <layout class="QGridLayout" name="gridLayout_4"> + <item row="0" column="2"> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>From tab 'Caclulate UB'</string> + </property> + </widget> + </item> + <item row="0" column="0"> + <widget class="QRadioButton" name="radioButton_ubFromTab1"> + <property name="text"> + <string/> + </property> + </widget> + </item> + <item row="0" column="1"> + <spacer name="horizontalSpacer_9"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Preferred</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="2" column="0"> + <widget class="QRadioButton" name="radioButton_ubFromTab3"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string/> + </property> + </widget> + </item> + <item row="2" column="2"> + <widget class="QLabel" name="label_28"> + <property name="text"> + <string>From tab 'Refine UB'</string> + </property> + </widget> + </item> + <item row="3" column="2"> + <widget class="QPlainTextEdit" name="plainTextEdit_ubInput"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </item> + <item row="3" column="0"> + <layout class="QVBoxLayout" name="verticalLayout_15"> + <item> + <widget class="QRadioButton" name="radioButton_ubFromList"> + <property name="text"> + <string/> + </property> + </widget> + </item> + <item> + <spacer name="verticalSpacer_15"> + <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> + </item> + </layout> + </item> + <item> + <spacer name="verticalSpacer_14"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Ignored</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="pushButton_setUBSliceView"> + <property name="text"> + <string>Set</string> + </property> + </widget> + </item> + <item> + <spacer name="verticalSpacer_10"> + <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> + </widget> + </item> + <item> + <widget class="QGroupBox" name="groupBox_6"> + <property name="title"> + <string>Process Data</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_14"> + <item> + <layout class="QGridLayout" name="gridLayout_10"> + <item row="1" column="0"> + <widget class="QLabel" name="label_29"> + <property name="toolTip"> + <string><html><head/><body><p>For MDEventsWorkspace with merged runs</p><p><br/></p><p>For example:</p></body></html></string> + </property> + <property name="text"> + <string>Base Workspace Name</string> + </property> + </widget> + </item> + <item row="0" column="0"> + <widget class="QLabel" name="label_30"> + <property name="text"> + <string>Scans List</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLineEdit" name="lineEdit_listScansSliceView"/> + </item> + <item row="0" column="2"> + <widget class="QPushButton" name="pushButton_addScanSliceView"> + <property name="text"> + <string>Add</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QLineEdit" name="lineEdit_baseMergeMDName"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="comboBox_mergeScanFrame"> + <property name="minimumSize"> + <size> + <width>140</width> + <height>0</height> + </size> + </property> + <property name="toolTip"> + <string><html><head/><body><p>Type of frame that the final merged scan will be in.</p></body></html></string> + </property> + <item> + <property name="text"> + <string>HKL-Space</string> + </property> + </item> + <item> + <property name="text"> + <string>Q-Sample-Space</string> + </property> + </item> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_10"> + <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> + </layout> + </item> + <item row="1" column="2"> + <widget class="QPushButton" name="pushButton_process4SliceView"> + <property name="font"> + <font> + <weight>75</weight> + <bold>true</bold> + </font> + </property> + <property name="text"> + <string>Process</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="ProcessTableWidget" name="tableWidget_sliceViewProgress"> + <property name="toolTip"> + <string><html><head/><body><p>? columns: </p><p><br/></p><p>1. Scan number</p><p>2. Number of Pts.</p><p>3. Status: </p><p>(a) done</p><p>(b) error with error message</p><p>(c) on-going</p><p>(d) empty as not yet</p></body></html></string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="tab_3"> + <attribute name="title"> + <string>Refine UB</string> + </attribute> + <layout class="QGridLayout" name="gridLayout_8"> + <item row="0" column="0"> + <layout class="QVBoxLayout" name="verticalLayout_6"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_14"> + <item> + <widget class="QLabel" name="label_14"> + <property name="text"> + <string>Scan</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="lineEdit_scanRefineUB"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label_13"> + <property name="text"> + <string>Pt.</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="lineEdit_ptRefineUB"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="pushButton_addToRefine"> + <property name="toolTip"> + <string><html><head/><body><p>Add a data point or data points (defined by scan number and pt number) to the list to refine UB matrix; </p><p><br/></p><p>Scan number can be a list of integers;</p><p><br/></p><p>Pt number can be empty such that all Pt. of that scan will be searched for peak and then used to refine UB matrix</p></body></html></string> + </property> + <property name="text"> + <string>Add</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_3"> + <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="pushButton_addAllRefineUB"> + <property name="text"> + <string>Add All</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_15"> + <item> + <widget class="UBMatrixTable" name="tableWidget_refinedUB"> + <row> + <property name="text"> + <string/> + </property> + </row> + <row> + <property name="text"> + <string/> + </property> + </row> + <row> + <property name="text"> + <string/> + </property> + </row> + <column> + <property name="text"> + <string/> + </property> + </column> + <column> + <property name="text"> + <string/> + </property> + </column> + <column> + <property name="text"> + <string/> + </property> + </column> + </widget> + </item> + <item> + <layout class="QVBoxLayout" name="verticalLayout_7"/> + </item> + <item> + <layout class="QVBoxLayout" name="verticalLayout_10"> + <item> + <widget class="QPushButton" name="pushButton_acceptRefinedUB"> + <property name="text"> + <string>Accept</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="pushButton_resetRefinedUB"> + <property name="text"> + <string>Reset</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </item> + <item> + <layout class="QGridLayout" name="gridLayout_7"> + <item row="0" column="0"> + <widget class="QLabel" name="label_17"> + <property name="text"> + <string>a</string> + </property> + </widget> + </item> + <item row="0" column="2"> + <widget class="QLabel" name="label_19"> + <property name="text"> + <string>c</string> + </property> + </widget> + </item> + <item row="0" column="4"> + <widget class="QLabel" name="label_21"> + <property name="text"> + <string>beta</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLabel" name="label_18"> + <property name="text"> + <string>b</string> + </property> + </widget> + </item> + <item row="0" column="3"> + <widget class="QLabel" name="label_20"> + <property name="text"> + <string>alpha</string> + </property> + </widget> + </item> + <item row="0" column="5"> + <widget class="QLabel" name="label_22"> + <property name="text"> + <string>gamma</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLineEdit" name="lineEdit_bUnitCell"/> + </item> + <item row="1" column="2"> + <widget class="QLineEdit" name="lineEdit_cUnitCell"/> + </item> + <item row="1" column="3"> + <widget class="QLineEdit" name="lineEdit_alphaUnitCell"/> + </item> + <item row="2" column="1"> + <widget class="QLineEdit" name="lineEdit_bError"/> + </item> + <item row="1" column="4"> + <widget class="QLineEdit" name="lineEdit_betaUnitCell"/> + </item> + <item row="1" column="0"> + <widget class="QLineEdit" name="lineEdit_aUnitCell"/> + </item> + <item row="2" column="2"> + <widget class="QLineEdit" name="lineEdit_cError"/> + </item> + <item row="2" column="0"> + <widget class="QLineEdit" name="lineEdit_aError"/> + </item> + <item row="2" column="3"> + <widget class="QLineEdit" name="lineEdit_alphaError"/> + </item> + <item row="2" column="4"> + <widget class="QLineEdit" name="lineEdit_betaError"/> + </item> + <item row="1" column="5"> + <widget class="QLineEdit" name="lineEdit_gammaUnitCell"/> + </item> + <item row="2" column="5"> + <widget class="QLineEdit" name="lineEdit_gammaError"/> + </item> + </layout> + </item> + </layout> + </item> + <item row="1" column="0"> + <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> + </layout> + </widget> + <widget class="QWidget" name="tab_indexPeak"> + <attribute name="title"> + <string>Peak Integration</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_11"> + <item> + <layout class="QGridLayout" name="gridLayout_13"> + <item row="1" column="6"> + <widget class="QCheckBox" name="checkBox_adaptQBkgd"> + <property name="text"> + <string>Adaptive Q Background</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLineEdit" name="lineEdit_scanIntegratePeak"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QCheckBox" name="checkBox_cylinder"> + <property name="text"> + <string>Cylinder</string> + </property> + </widget> + </item> + <item row="1" column="3"> + <widget class="QLineEdit" name="lineEdit_bkgdInnerR"/> + </item> + <item row="1" column="5"> + <widget class="QLineEdit" name="lineEdit_bkgdOuterR"/> + </item> + <item row="2" column="4"> + <widget class="QLabel" name="label_36"> + <property name="text"> + <string>Percent Background</string> + </property> + </widget> + </item> + <item row="1" column="7"> + <widget class="QCheckBox" name="checkBox_integrateOnEdge"> + <property name="text"> + <string>Integrate on Edge</string> + </property> + </widget> + </item> + <item row="0" column="0"> + <widget class="QLabel" name="label_5"> + <property name="text"> + <string>Scan Number</string> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_34"> + <property name="text"> + <string>Peak Radius</string> + </property> + </widget> + </item> + <item row="0" column="3"> + <widget class="QLineEdit" name="lineEdit_ptNumListIntPeak"/> + </item> + <item row="2" column="7"> + <widget class="QComboBox" name="comboBox_cylinderIntOption"/> + </item> + <item row="0" column="7"> + <widget class="QPushButton" name="pushButton_integratePeak"> + <property name="text"> + <string>Integrate Peaks</string> + </property> + </widget> + </item> + <item row="2" column="5"> + <widget class="QLineEdit" name="lineEdit_cylinderBkgdPercent"/> + </item> + <item row="1" column="4"> + <widget class="QLabel" name="label_35"> + <property name="text"> + <string>Background Outer Radius</string> + </property> + </widget> + </item> + <item row="0" column="5"> + <widget class="QComboBox" name="comboBox_3"> + <property name="toolTip"> + <string><html><head/><body><p>Choose the name of the tab, in which the UB matrix is used to convert signals to HKL frame.</p></body></html></string> + </property> + <item> + <property name="text"> + <string>Calculate UB</string> + </property> + </item> + <item> + <property name="text"> + <string>Merge Scan</string> + </property> + </item> + <item> + <property name="text"> + <string>Refine UB</string> + </property> + </item> + </widget> + </item> + <item row="2" column="6"> + <widget class="QComboBox" name="comboBox_cylinderProfile"> + <item> + <property name="text"> + <string>Gaussian</string> + </property> + </item> + </widget> + </item> + <item row="2" column="2"> + <widget class="QLabel" name="label_39"> + <property name="text"> + <string>Cylinder Length</string> + </property> + </widget> + </item> + <item row="1" column="2"> + <widget class="QLabel" name="label_37"> + <property name="text"> + <string>Background Inner Radius</string> + </property> + </widget> + </item> + <item row="2" column="3"> + <widget class="QLineEdit" name="lineEdit_cylinderLength"/> + </item> + <item row="0" column="2"> + <widget class="QLabel" name="label_33"> + <property name="text"> + <string>Pt Numbers</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLineEdit" name="lineEdit_peakRadius"/> + </item> + </layout> + </item> + <item> + <widget class="IntegratePeaksTableWidget" name="tableWidget_peakIndex"/> + </item> + </layout> + </widget> + </widget> + </item> + </layout> + </item> + </layout> + </item> + </layout> + </widget> + <widget class="QMenuBar" name="menubar"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>1292</width> + <height>25</height> + </rect> + </property> + <widget class="QMenu" name="menuFile"> + <property name="title"> + <string>File</string> + </property> + <addaction name="separator"/> + <addaction name="actionExit"/> + <addaction name="separator"/> + </widget> + <widget class="QMenu" name="menuTools"> + <property name="title"> + <string>Tools</string> + </property> + <addaction name="actionSave_Session"/> + <addaction name="actionLoad_Session"/> + <addaction name="separator"/> + </widget> + <addaction name="menuFile"/> + <addaction name="menuTools"/> + </widget> + <widget class="QStatusBar" name="statusbar"/> + <action name="actionNew"> + <property name="text"> + <string>New</string> + </property> + <property name="shortcut"> + <string>Ctrl+N</string> + </property> + </action> + <action name="actionOpen"> + <property name="text"> + <string>Open</string> + </property> + <property name="shortcut"> + <string>Ctrl+O</string> + </property> + </action> + <action name="actionSave"> + <property name="text"> + <string>Save</string> + </property> + </action> + <action name="actionLog"> + <property name="text"> + <string>Log</string> + </property> + <property name="shortcut"> + <string>Ctrl+L</string> + </property> + </action> + <action name="actionSave_Session"> + <property name="text"> + <string>Save Session</string> + </property> + <property name="shortcut"> + <string>Ctrl+Shift+S</string> + </property> + </action> + <action name="actionExit"> + <property name="text"> + <string>Exit</string> + </property> + <property name="shortcut"> + <string>Ctrl+Q</string> + </property> + </action> + <action name="actionLoad_Session"> + <property name="text"> + <string>Load Session</string> + </property> + <property name="shortcut"> + <string>Ctrl+Shift+L</string> + </property> + </action> + </widget> + <customwidgets> + <customwidget> + <class>MplGraphicsView</class> + <extends>QGraphicsView</extends> + <header>mplgraphicsview.h</header> + </customwidget> + <customwidget> + <class>UBMatrixPeakTable</class> + <extends>QTableWidget</extends> + <header>hfctables.h</header> + </customwidget> + <customwidget> + <class>UBMatrixTable</class> + <extends>QTableWidget</extends> + <header>hfctables.h</header> + </customwidget> + <customwidget> + <class>ProcessTableWidget</class> + <extends>QTableWidget</extends> + <header>hfctables.h</header> + </customwidget> + <customwidget> + <class>IntegratePeaksTableWidget</class> + <extends>QTableWidget</extends> + <header>hfctables.h</header> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui> diff --git a/scripts/HFIR_4Circle_Reduction/NTableWidget.py b/scripts/HFIR_4Circle_Reduction/NTableWidget.py new file mode 100644 index 0000000000000000000000000000000000000000..198725f41ef1492b822dfddb572ecb7c75b0a3aa --- /dev/null +++ b/scripts/HFIR_4Circle_Reduction/NTableWidget.py @@ -0,0 +1,268 @@ +#pylint: disable=C0103,R0904 +# N(DAV)TableWidget +# + +from PyQt4 import QtGui, QtCore + +try: + _fromUtf8 = QtCore.QString.fromUtf8 +except AttributeError: + _fromUtf8 = lambda s: s + + +class NTableWidget(QtGui.QTableWidget): + """ + NdavTableWidget inherits from QTableWidget by extending the features + for easy application. + """ + def __init__(self, parent): + """ + + :param parent: + :return: + """ + QtGui.QTableWidget.__init__(self, parent) + + self._myParent = parent + + self._myHeaderList = None + self._myColumnTypeList = None + + return + + def append_row(self, row_value_list, type_list=None): + """ + + :param row_value_list: + :return: + """ + # Check input + assert isinstance(row_value_list, list) + if type_list is not None: + assert isinstance(type_list, list) + assert len(row_value_list) == len(type_list) + else: + type_list = self._myColumnTypeList + if len(row_value_list) != self.columnCount(): + ret_msg = 'Input number of values (%d) is different from ' \ + 'column number (%d).' % (len(row_value_list), self.columnCount()) + return False, ret_msg + else: + ret_msg = '' + + # Insert new row + row_number = self.rowCount() + self.insertRow(row_number) + + # Set values + for i_col in xrange(min(len(row_value_list), self.columnCount())): + item = QtGui.QTableWidgetItem() + item.setText(_fromUtf8(str(row_value_list[i_col]))) + item.setFlags(item.flags() & ~QtCore.Qt.ItemIsEditable) + if type_list[i_col] == 'checkbox': + self.set_check_box(row_number, i_col, False) + else: + self.setItem(row_number, i_col, item) + # END-FOR(i_col) + + return True, ret_msg + + def delete_rows(self, row_number_list): + """ Delete rows + :param row_number_list: + :return: + """ + # Check and re-order row numbers + assert isinstance(row_number_list, list) + row_number_list.sort(reverse=True) + + for row_number in row_number_list: + self.removeRow(row_number) + + return + + def get_selected_rows(self): + """ + + :return: list of row numbers that are selected + """ + rows_list = list() + index_status = self._myColumnTypeList.index('checkbox') + for i_row in xrange(self.rowCount()): + is_checked = self.get_row_value(i_row)[index_status] + if is_checked: + rows_list.append(i_row) + + return rows_list + + def get_cell_value(self, row_index, col_index): + """ + + :param row_index: + :param col_index: + :return: + """ + c_type = self._myColumnTypeList[col_index] + + return_value = None + if c_type == 'checkbox': + # Check box + cell_i_j = self.cellWidget(row_index, col_index) + assert isinstance(cell_i_j, QtGui.QCheckBox) + return_value = cell_i_j.isChecked() + else: + # Regular cell + item_i_j = self.item(row_index, col_index) + assert isinstance(item_i_j, QtGui.QTableWidgetItem) + value = str(item_i_j.text()) + if c_type == 'int': + return_value = int(value) + elif c_type == 'float': + return_value = float(value) + + return return_value + + def get_row_value(self, row_index): + """ + :param row_index: + :return: list of objects + """ + if row_index < 0 or row_index >= self.rowCount(): + raise IndexError('Index of row (%d) is out of range.' % row_index) + + ret_list = list() + for i_col in xrange(len(self._myColumnTypeList)): + c_type = self._myColumnTypeList[i_col] + + if c_type == 'checkbox': + # Check box + cell_i_j = self.cellWidget(row_index, i_col) + assert isinstance(cell_i_j, QtGui.QCheckBox) + is_checked = cell_i_j.isChecked() + ret_list.append(is_checked) + else: + # Regular cell + item_i_j = self.item(row_index, i_col) + assert isinstance(item_i_j, QtGui.QTableWidgetItem) + value = str(item_i_j.text()).strip() + if len(value) > 0: + if c_type == 'int': + value = int(value) + elif c_type == 'float': + value = float(value) + else: + value = None + + ret_list.append(value) + # END-IF-ELSE + # END-FOR + + return ret_list + + def init_setup(self, column_tup_list): + """ Initial setup + :param column_tup_list: list of 2-tuple as string (column name) and string (data type) + :return: + """ + # Define column headings + num_cols = len(column_tup_list) + + # Class variables + self._myHeaderList = list() + self._myColumnTypeList = list() + + for c_tup in column_tup_list: + c_name = c_tup[0] + c_type = c_tup[1] + self._myHeaderList.append(c_name) + self._myColumnTypeList.append(c_type) + + self.setColumnCount(num_cols) + self.setHorizontalHeaderLabels(self._myHeaderList) + + return + + def init_size(self, num_rows, num_cols): + """ + + :return: + """ + self.setColumnCount(num_cols) + self.setRowCount(num_rows) + + return + + def set_check_box(self, row, col, state): + """ function to add a new select checkbox to a cell in a table row + won't add a new checkbox if one already exists + """ + # Check input + assert isinstance(state, bool) + + # Check if cellWidget exists + if self.cellWidget(row,col): + # existing: just set the value + self.cellWidget(row, col).setChecked(state) + else: + # case to add checkbox + checkbox = QtGui.QCheckBox() + checkbox.setText('') + checkbox.setChecked(state) + + # Adding a widget which will be inserted into the table cell + # then centering the checkbox within this widget which in turn, + # centers it within the table column :-) + self.setCellWidget(row, col, checkbox) + # END-IF-ELSE + + return + + def set_value_cell(self, row, col, value=''): + """ + Set value to a cell with integer, float or string + :param row: + :param col: + :param value: + :return: + """ + # Check + if row < 0 or row >= self.rowCount() or col < 0 or col >= self.columnCount(): + raise IndexError('Input row number or column number is out of range.') + + # Init cell + cell_item = QtGui.QTableWidgetItem() + cell_item.setText(_fromUtf8(str(value))) + cell_item.setFlags(cell_item.flags() & ~QtCore.Qt.ItemIsEditable) + + self.setItem(row, col, cell_item) + + return + + def update_cell_value(self, row, col, value): + """ + + :param row: + :param col: + :param value: + :return: + """ + cell_item = self.item(row, col) + cell_widget = self.cellWidget(row, col) + + if cell_item is not None and cell_widget is None: + # TableWidgetItem + assert isinstance(cell_item, QtGui.QTableWidgetItem) + if isinstance(value, float): + cell_item.setText(_fromUtf8('%.7f' % value)) + else: + cell_item.setText(_fromUtf8(str(value))) + elif cell_item is None and cell_widget is not None: + # TableCellWidget + if isinstance(cell_item, QtGui.QCheckBox) is True: + cell_item.setChecked(value) + else: + raise TypeError('Cell of type %s is not supported.' % str(type(cell_item))) + else: + raise TypeError('Table cell (%d, %d) is in an unsupported situation!' % (row, col)) + + return diff --git a/scripts/HFIR_4Circle_Reduction/__init__.py b/scripts/HFIR_4Circle_Reduction/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..04a95e8315757618d54dc05da33da722b0774d94 --- /dev/null +++ b/scripts/HFIR_4Circle_Reduction/__init__.py @@ -0,0 +1,2 @@ +#pylint: disable=invalid-name +#pylint: disable=invalid-name diff --git a/scripts/HFIR_4Circle_Reduction/fourcircle_utility.py b/scripts/HFIR_4Circle_Reduction/fourcircle_utility.py new file mode 100644 index 0000000000000000000000000000000000000000..35dc1fe387e6bd1597eed0a9eb6c52f8c08811f8 --- /dev/null +++ b/scripts/HFIR_4Circle_Reduction/fourcircle_utility.py @@ -0,0 +1,188 @@ +#pylint: disable=W0633,too-many-branches +__author__ = 'wzz' + +import os +import urllib2 +import socket + + +def check_url(url, read_lines=False): + """ Check whether a URL is valid + :param url: + :return: boolean, error message + """ + lines = None + try: + # Access URL + url_stream = urllib2.urlopen(url, timeout=2) + + # Read lines + if read_lines is True: + lines = url_stream.readlines() + except urllib2.URLError as url_error: + url_stream = url_error + except socket.timeout: + return False, 'Time out. Try again!' + + # Return result + if url_stream.code in (200, 401): + url_good = True + else: + url_good = False + + # Close connect + url_stream.close() + + # Return + if read_lines is True: + return url_good, lines + if url_good is False: + error_message = 'Unable to access %s. Check internet access. Code %d' % (url, url_stream.code) + else: + error_message = '' + + return url_good, error_message + + +def get_scans_list(server_url, exp_no, return_list=False): + """ Get list of scans under one experiment + :param server_url: + :param exp_no: + :return: message + """ + if server_url.endswith('/') is False: + server_url = '%s/' % server_url + data_dir_url = '%sexp%d/Datafiles' % (server_url, exp_no) + + does_exist, raw_lines = check_url(data_dir_url, read_lines=True) + if does_exist is False: + return "Experiment %d's URL %s cannot be found." % (exp_no, data_dir_url) + + # Scan through the index page + scan_list = [] + header = 'HB3A_exp%04d_scan' % exp_no + for line in raw_lines: + if line.count(header) > 0: + # try to find file HB3A_exp0123_scan6789.dat + term = line.split(header)[1].split('.dat')[0] + scan = int(term) + # check + if '%04d' % scan == term: + scan_list.append(scan) + # END_FOR + scan_list = sorted(scan_list) + if return_list is True: + return scan_list + + message = 'Experiment %d: Scan from %d to %d' % (exp_no, scan_list[0], scan_list[-1]) + + return message + + +def get_scans_list_local_disk(local_dir, exp_no): + """ Get scans from a specified directory on local disk + :param local_dir: + :param exp_no: + :return: + """ + scan_list = [] + + file_names = os.listdir(local_dir) + header = 'HB3A_exp%04d_scan' % exp_no + for name in file_names: + if name.count(header) > 0: + scan = int(name.split(header)[1].split('.dat')[0]) + scan_list.append(scan) + + scan_list = sorted(scan_list) + + if len(scan_list) == 0: + message = 'Experiment %d: No scan can be found.' % exp_no + else: + message = 'Experiment %d: Scan from %d to %d ' % (exp_no, scan_list[0], scan_list[-1]) + num_skip_scans = scan_list[-1] - scan_list[0] + 1 - len(scan_list) + if num_skip_scans > 0: + message += 'with %d ' % num_skip_scans + else: + message += 'without ' + message += 'missing scans.' + + return message + + +def parse_int_array(int_array_str): + """ Validate whether the string can be divided into integer strings. + Allowed: a, b, c-d, e, f + :param int_array_str: + :return: + """ + int_array_str = str(int_array_str) + if int_array_str == "": + return True, [] + + # Split by "," + term_level_0 = int_array_str.split(",") + integer_list = [] + + # For each term + err_msg = "" + ret_status = True + + for level0_term in term_level_0: + level0_term = level0_term.strip() + + # split upon dash - + num_dashes = level0_term.count("-") + if num_dashes == 0: + # one integer + value_str = level0_term + try: + int_value = int(value_str) + if str(int_value) != value_str: + ret_status = False + err_msg = "Contains non-integer string %s." % value_str + except ValueError: + ret_status = False + err_msg = "String %s is not an integer." % (value_str) + else: + integer_list.append(int_value) + + elif num_dashes == 1: + # Integer range + two_terms = level0_term.split("-") + temp_list = [] + for i in xrange(2): + value_str = two_terms[i] + try: + int_value = int(value_str) + if str(int_value) != value_str: + ret_status = False + err_msg = "Contains non-integer string %s." % (value_str) + except ValueError: + ret_status = False + err_msg = "String %s is not an integer." % (value_str) + else: + temp_list.append(int_value) + + # break loop + if ret_status is False: + break + # END_FOR(i) + integer_list.extend(range(temp_list[0], temp_list[1]+1)) + + else: + # Undefined situation + ret_status = False + err_msg = "Term %s contains more than 1 dash." % level0_term + # END-IF-ELSE + + # break loop if something is wrong + if ret_status is False: + break + # END-FOR(level0_term) + + # Return with false + if ret_status is False: + return False, err_msg + + return True, integer_list diff --git a/scripts/HFIR_4Circle_Reduction/guiutility.py b/scripts/HFIR_4Circle_Reduction/guiutility.py new file mode 100644 index 0000000000000000000000000000000000000000..79237a5729470b372017478b24a0564159d67fb1 --- /dev/null +++ b/scripts/HFIR_4Circle_Reduction/guiutility.py @@ -0,0 +1,164 @@ +# +# GUI Utility Methods +# +from PyQt4 import QtGui + + +def parse_float_array(array_str): + """ Parse a string to an array of float + :param array_str: + :return: boolean, list of floats/error message + """ + print array_str + assert isinstance(array_str, str) + array_str = array_str.replace(',', ' ') + array_str = array_str.replace('\n', ' ') + array_str = array_str.replace('\t ', ' ') + array_str = array_str.strip() + print '[DB] After processing: ', array_str + + float_str_list = array_str.split() + float_list = list() + for float_str in float_str_list: + try: + value = float(float_str) + except ValueError as value_error: + return False, 'Unable to parse %s due to %s.' % (float_str, str(value_error)) + else: + float_list.append(value) + # END-FOR + + return True, float_list + + +def parse_integer_list(array_str): + """ Parse a string to an array of integer separated by ',' + also, the format as 'a-b' is supported too + :param array_str: + :return: boolean, list of floats/error message + """ + assert isinstance(array_str, str) + array_str = array_str.replace(' ', '') + array_str = array_str.replace('\n', '') + array_str = array_str.replace('\t ', '') + + int_str_list = array_str.split(',') + integer_list = list() + for int_str in int_str_list: + + try: + int_value = int(int_str) + integer_list.append(int_value) + except ValueError: + num_dash = int_str.count('-') + if num_dash == 1: + terms = int_str.split('-') + try: + start_value = int(terms[0]) + end_value = int(terms[1]) + except ValueError: + raise RuntimeError('Unable to parse %s due to value error' % int_str) + elif num_dash == 2 and int_str.startswith('-'): + terms = int_str[1:].split('-') + try: + start_value = int(terms[0])*-1 + end_value = int(terms[1]) + except ValueError: + raise RuntimeError('Unable to parse %s due to value error' % int_str) + elif num_dash == 3: + terms = int_str.split('-') + try: + start_value = -1*int(terms[1]) + end_value = -1*int(terms[3]) + except ValueError: + raise RuntimeError('Unable to parse %s due to value error' % int_str) + except IndexError: + raise RuntimeError('Unable to parse %s due to value error' % int_str) + else: + raise RuntimeError('Unable to parse %s due to value error' % int_str) + + integer_list.extend(xrange(start_value, end_value+1)) + # END-FOR + + return integer_list + + +def parse_float_editors(line_edits): + """ + :param line_edits: + :return: (True, list of floats); (False, error message) + """ + # Set flag + return_single_value = False + + if isinstance(line_edits, QtGui.QLineEdit) is True: + line_edit_list = [line_edits] + return_single_value = True + elif isinstance(line_edits, list) is True: + line_edit_list = line_edits + else: + raise RuntimeError('Input is not LineEdit or list of LineEdit.') + + error_message = '' + float_list = [] + + for line_edit in line_edit_list: + assert isinstance(line_edit, QtGui.QLineEdit) + try: + str_value = str(line_edit.text()).strip() + float_value = float(str_value) + except ValueError as value_err: + error_message += 'Unable to parse to integer. %s\n' % (str(value_err)) + else: + float_list.append(float_value) + # END-TRY + # END-FOR + + if len(error_message) > 0: + return False, error_message + elif return_single_value is True: + return True, float_list[0] + + return True, float_list + + +def parse_integers_editors(line_edits): + """ + :param line_edits: + :return: (True, list of integers); (False, error message) + """ + # Set flag + return_single_value = False + + if isinstance(line_edits, QtGui.QLineEdit) is True: + line_edit_list = [line_edits] + return_single_value = True + elif isinstance(line_edits, list) is True: + line_edit_list = line_edits + else: + raise RuntimeError('Input is not LineEdit or list of LineEdit.') + + error_message = '' + integer_list = [] + + for line_edit in line_edit_list: + assert isinstance(line_edit, QtGui.QLineEdit) + try: + str_value = str(line_edit.text()).strip() + int_value = int(str_value) + except ValueError as value_err: + error_message += 'Unable to parse to integer. %s\n' % (str(value_err)) + else: + if str_value != '%d' % int_value: + error_message += 'Value %s is not a proper integer.\n' % str_value + else: + integer_list.append(int_value) + # END-TRY + # END-FOR + + if len(error_message) > 0: + return False, error_message + elif return_single_value is True: + return True, integer_list[0] + + return True, integer_list diff --git a/scripts/HFIR_4Circle_Reduction/hfctables.py b/scripts/HFIR_4Circle_Reduction/hfctables.py new file mode 100644 index 0000000000000000000000000000000000000000..dba8cb64a3aefb4adff82b540655251d9fe41311 --- /dev/null +++ b/scripts/HFIR_4Circle_Reduction/hfctables.py @@ -0,0 +1,385 @@ +#pylint: disable=W0403,C0103,R0901,R0904 +import numpy +import NTableWidget as tableBase + +# UB peak information table +Peak_Integration_Table_Setup = [('Scan', 'int'), + ('Pt', 'int'), + ('H', 'float'), + ('K', 'float'), + ('L', 'float'), + ('Q_x', 'float'), + ('Q_y', 'float'), + ('Q_z', 'float'), + ('Intensity', 'float')] + + +class IntegratePeaksTableWidget(tableBase.NTableWidget): + """ + Extended table widget for peak integration + """ + def __init__(self, parent): + """ + :param parent: + """ + tableBase.NTableWidget.__init__(self, parent) + + return + + def setup(self): + """ + Init setup + :return: + """ + self.init_setup(Peak_Integration_Table_Setup) + + return + + +class UBMatrixTable(tableBase.NTableWidget): + """ + Extended table for UB matrix + """ + def __init__(self, parent): + """ + + :param parent: + :return: + """ + tableBase.NTableWidget.__init__(self, parent) + + # Matrix + self._matrix = numpy.ndarray((3, 3), float) + for i in xrange(3): + for j in xrange(3): + self._matrix[i][j] = 0. + + return + + def _set_to_table(self): + """ + Set values in holder '_matrix' to TableWidget + :return: + """ + for i_row in xrange(3): + for j_col in xrange(3): + self.update_cell_value(i_row, j_col, self._matrix[i_row][j_col]) + + return + + def get_matrix(self): + """ + Get the copy of the matrix + :return: + """ + # print '[DB] MatrixTable: _Matrix = ', self._matrix + return self._matrix.copy() + + def set_from_list(self, element_array): + """ + Set table value including holder and QTable from a 1D numpy array + :param element_array: + :return: + """ + # Check + assert isinstance(element_array, list) + assert len(element_array) == 9 + + # Set value + i_array = 0 + for i in xrange(3): + for j in xrange(3): + self._matrix[i][j] = element_array[i_array] + i_array += 1 + + # Set to table + self._set_to_table() + + return + + def set_from_matrix(self, matrix): + """ + Set value to both holder and QTable from a numpy 3 x 3 matrix + :param matrix: + :return: + """ + # Check + assert isinstance(matrix, numpy.ndarray) + assert matrix.shape == (3, 3) + + for i in xrange(3): + for j in xrange(3): + self._matrix[i][j] = matrix[i][j] + + self._set_to_table() + + return + + def setup(self): + """ + Init setup + :return: + """ + # self.init_size(3, 3) + + for i in xrange(3): + for j in xrange(3): + self.set_value_cell(i, j) + + self._set_to_table() + + return + + +# UB peak information table +UB_Peak_Table_Setup = [('Scan', 'int'), + ('Pt', 'int'), + ('H', 'float'), + ('K', 'float'), + ('L', 'float'), + ('Q_x', 'float'), + ('Q_y', 'float'), + ('Q_z', 'float'), + ('Selected', 'checkbox'), + ('m1', 'float'), + ('Error', 'float')] + + +class UBMatrixPeakTable(tableBase.NTableWidget): + """ + Extended table for peaks used to calculate UB matrix + """ + def __init__(self, parent): + """ + + :param parent: + :return: + """ + tableBase.NTableWidget.__init__(self, parent) + + return + + def get_exp_info(self, row_index): + """ + Get experiment information from a row + :return: scan number, pt number + """ + assert isinstance(row_index, int) + + scan_number = self.get_cell_value(row_index, 0) + assert isinstance(scan_number, int) + pt_number = self.get_cell_value(row_index, 1) + assert isinstance(pt_number, int) + + return scan_number, pt_number + + def get_hkl(self, row_index): + """ + Get reflection's miller index + :param row_index: + :return: + """ + assert isinstance(row_index, int) + + m_h = self.get_cell_value(row_index, 2) + m_k = self.get_cell_value(row_index, 3) + m_l = self.get_cell_value(row_index, 4) + + assert isinstance(m_h, float) + assert isinstance(m_k, float) + assert isinstance(m_l, float) + + return m_h, m_k, m_l + + def get_scan_pt(self, row_number): + """ + Get Scan and Pt from a row + :param row_number: + :return: + """ + scan_number = self.get_cell_value(row_number, 0) + pt_number = self.get_cell_value(row_number, 1) + + return scan_number, pt_number + + def is_selected(self, row_index): + """ + + :return: + """ + if row_index < 0 or row_index >= self.rowCount(): + raise IndexError('Input row number %d is out of range [0, %d)' % (row_index, self.rowCount())) + + col_index = UB_Peak_Table_Setup.index(('Selected', 'checkbox')) + + return self.get_cell_value(row_index, col_index) + + def setup(self): + """ + Init setup + :return: + """ + self.init_setup(UB_Peak_Table_Setup) + + return + + def set_hkl(self, i_row, hkl, error=None): + """ + Set HKL to table + :param irow: + :param hkl: + """ + # Check + assert isinstance(i_row, int) + assert isinstance(hkl, list) + + i_col_h = UB_Peak_Table_Setup.index(('H', 'float')) + i_col_k = UB_Peak_Table_Setup.index(('K', 'float')) + i_col_l = UB_Peak_Table_Setup.index(('L', 'float')) + + self.update_cell_value(i_row, i_col_h, hkl[0]) + self.update_cell_value(i_row, i_col_k, hkl[1]) + self.update_cell_value(i_row, i_col_l, hkl[2]) + + if error is not None: + i_col_error = UB_Peak_Table_Setup.index(('Error', 'float')) + self.update_cell_value(i_row, i_col_error, error) + + return + + def update_hkl(self, i_row, h, k, l): + """ Update HKL value + """ + self.update_cell_value(i_row, 2, h) + self.update_cell_value(i_row, 3, k) + self.update_cell_value(i_row, 4, l) + + return + + +# Processing status table +Process_Table_Setup = [('Scan', 'int'), + ('Number Pt', 'int'), + ('Status', 'str'), + ('Merged Workspace', 'str'), + ('Group Name', 'str'), + ('Select', 'checkbox')] + + +class ProcessTableWidget(tableBase.NTableWidget): + """ + Extended table for peaks used to calculate UB matrix + """ + def __init__(self, parent): + """ + + :param parent: + :return: + """ + tableBase.NTableWidget.__init__(self, parent) + + return + + def append_scans(self, scans): + """ Append rows + :param scans: + :return: + """ + # Check + assert isinstance(scans, list) + + # Append rows + for scan in scans: + row_value_list = [scan, 0, 'In Queue', '', '', False] + status, err = self.append_row(row_value_list) + if status is False: + raise RuntimeError(err) + + return + + def setup(self): + """ + Init setup + :return: + """ + self.init_setup(Process_Table_Setup) + + return + + def set_scan_pt(self, scan_no, pt_list): + """ + :param scan_no: + :param pt_list: + :return: + """ + # Check + assert isinstance(scan_no, int) + + num_rows = self.rowCount() + set_done = False + for i_row in xrange(num_rows): + tmp_scan_no = self.get_cell_value(i_row, 0) + if scan_no == tmp_scan_no: + self.update_cell_value(i_row, 1, len(pt_list)) + set_done = True + break + # END-FOR + + if set_done is False: + return 'Unable to find scan %d in table.' % scan_no + + return '' + + def set_status(self, scan_no, status): + """ + Set the status for merging scan to QTable + :param status: + :return: + """ + # Check + assert isinstance(scan_no, int) + + num_rows = self.rowCount() + set_done = False + for i_row in xrange(num_rows): + tmp_scan_no = self.get_cell_value(i_row, 0) + if scan_no == tmp_scan_no: + self.update_cell_value(i_row, 2, status) + set_done = True + break + # END-FOR + + if set_done is False: + return 'Unable to find scan %d in table.' % scan_no + + return '' + + def set_ws_names(self, scan_num, merged_md_name, ws_group_name): + """ + Set the output workspace and workspace group's names to QTable + :param merged_md_name: + :param ws_group_name: + :return: + """ + # Check + assert isinstance(scan_num, int) + assert isinstance(merged_md_name, str) or merged_md_name is None + assert isinstance(ws_group_name, str) or ws_group_name is None + + num_rows = self.rowCount() + set_done = False + for i_row in xrange(num_rows): + tmp_scan_no = self.get_cell_value(i_row, 0) + if scan_num == tmp_scan_no: + if merged_md_name is not None: + self.update_cell_value(i_row, 3, merged_md_name) + if ws_group_name is not None: + self.update_cell_value(i_row, 4, ws_group_name) + set_done = True + break + # END-FOR + + if set_done is False: + return 'Unable to find scan %d in table.' % scan_num + + return diff --git a/scripts/HFIR_4Circle_Reduction/mplgraphicsview.py b/scripts/HFIR_4Circle_Reduction/mplgraphicsview.py new file mode 100644 index 0000000000000000000000000000000000000000..152ffc29c4775c6f98b8b67befe0554a36d66032 --- /dev/null +++ b/scripts/HFIR_4Circle_Reduction/mplgraphicsview.py @@ -0,0 +1,1255 @@ +#pylint: disable=invalid-name,too-many-public-methods,too-many-arguments,non-parent-init-called,R0902,too-many-branches,C0302 +import os +import numpy as np + +from PyQt4 import QtGui + +from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas +from matplotlib.backends.backend_qt4agg import NavigationToolbar2QTAgg as NavigationToolbar2 +from matplotlib.figure import Figure +import matplotlib.image + +MplLineStyles = ['-' , '--' , '-.' , ':' , 'None' , ' ' , ''] +MplLineMarkers = [ + ". (point )", + "* (star )", + "x (x )", + "o (circle )", + "s (square )", + "D (diamond )", + ", (pixel )", + "v (triangle_down )", + "^ (triangle_up )", + "< (triangle_left )", + "> (triangle_right)", + "1 (tri_down )", + "2 (tri_up )", + "3 (tri_left )", + "4 (tri_right )", + "8 (octagon )", + "p (pentagon )", + "h (hexagon1 )", + "H (hexagon2 )", + "+ (plus )", + "d (thin_diamond )", + "| (vline )", + "_ (hline )", + "None (nothing )"] + +# Note: in colors, "white" is removed +MplBasicColors = [ + "black", + "red", + "blue", + "green", + "cyan", + "magenta", + "yellow"] + + +class IndicatorManager(object): + """ Manager for all indicator lines + """ + def __init__(self): + """ + + :return: + """ + # Auto color index + self._colorIndex = 0 + # Auto line ID + self._autoLineID = 1 + + self._lineManager = dict() + self._canvasLineKeyDict = dict() + self._indicatorTypeDict = dict() # value: 0 (horizontal), 1 (vertical), 2 (2-way) + + return + + def add_2way_indicator(self, x, x_min, x_max, y, y_min, y_max, color): + """ + + :param x: + :param x_min: + :param x_max: + :param y: + :param y_min: + :param y_max: + :param color: + :return: + """ + # Set up indicator ID + this_id = str(self._autoLineID) + self._autoLineID += 1 + + # Set up vectors + vec_x_horizontal = np.array([x_min, x_max]) + vec_y_horizontal = np.array([y, y]) + + vec_x_vertical = np.array([x, x]) + vec_y_vertical = np.array([y_min, y_max]) + + # + self._lineManager[this_id] = [vec_x_horizontal, vec_y_horizontal, vec_x_vertical, vec_y_vertical, color] + self._indicatorTypeDict[this_id] = 2 + + return this_id + + def add_horizontal_indicator(self, y, x_min, x_max, color): + """ + Add a horizontal indicator + :param y: + :param x_min: + :param x_max: + :param color: + :return: + """ + # Get ID + this_id = str(self._autoLineID) + self._autoLineID += 1 + + # + vec_x = np.array([x_min, x_max]) + vec_y = np.array([y, y]) + + # + self._lineManager[this_id] = [vec_x, vec_y, color] + self._indicatorTypeDict[this_id] = 0 + + return this_id + + def add_vertical_indicator(self, x, y_min, y_max, color): + """ + Add a vertical indicator to data structure + :return: indicator ID + """ + # Get ID + this_id = str(self._autoLineID) + self._autoLineID += 1 + + # + vec_x = np.array([x, x]) + vec_y = np.array([y_min, y_max]) + + # + self._lineManager[this_id] = [vec_x, vec_y, color] + self._indicatorTypeDict[this_id] = 1 + + return this_id + + def get_canvas_line_index(self, my_id): + """ + + :param my_id: + :return: + """ + assert isinstance(my_id, str) + + if my_id not in self._canvasLineKeyDict: + raise RuntimeError('Indicator ID %s cannot be found. Current keys are %s.' % ( + my_id, str(sorted(self._canvasLineKeyDict.keys())) + )) + return self._canvasLineKeyDict[my_id] + + def get_line_type(self, my_id): + """ + + :param my_id: + :return: + """ + return self._indicatorTypeDict[my_id] + + def get_2way_data(self, line_id): + """ + + :param line_id: + :return: + """ + assert self._indicatorTypeDict.has_key(line_id) + assert self._indicatorTypeDict[line_id] == 2 + + vec_set = [self._lineManager[line_id][0:2], self._lineManager[line_id][2:4]] + + return vec_set + + def get_data(self, line_id): + """ + Get line's vector x and vector y + :param line_id: + :return: + """ + return self._lineManager[line_id][0], self._lineManager[line_id][1] + + def get_line_style(self, line_id=None): + """ + + :param line_id: + :return: + """ + assert isinstance(line_id, None) + return '--' + + def get_live_indicator_ids(self): + """ + + :return: + """ + return sorted(self._lineManager.keys()) + + def get_marker(self): + """ + Get the marker a line + :param line_id: + :return: + """ + return 'o' + + def get_next_color(self): + """ + Get next color by auto color index + :return: string as color + """ + next_color = MplBasicColors[self._colorIndex] + + # Advance and possibly reset color scheme + self._colorIndex += 1 + if self._colorIndex == len(MplBasicColors): + self._colorIndex = 0 + + return next_color + + def set_canvas_line_index(self, my_id, canvas_line_index): + """ + + :param my_id: + :param canvas_line_index: + :return: + """ + self._canvasLineKeyDict[my_id] = canvas_line_index + + def shift(self, my_id, dx, dy): + """ + + :param my_id: + :param dx: + :param dy: + :return: + """ + print self._lineManager[my_id][0] + + if self._indicatorTypeDict[my_id] == 0: + # horizontal + self._lineManager[my_id][1] += dy + + elif self._indicatorTypeDict[my_id] == 1: + # vertical + self._lineManager[my_id][0] += dx + + elif self._indicatorTypeDict[my_id] == 2: + # 2-way + self._lineManager[my_id][2] += dx + self._lineManager[my_id][1] += dy + + else: + raise RuntimeError('Unsupported indicator of type %d' % self._indicatorTypeDict[my_id]) + + return + + def update_indicators_range(self, x_range, y_range): + """ + Update indicator's range + :param x_range: + :param y_range: + :return: + """ + for i_id in self._lineManager.keys(): + # NEXT - Need a new flag for direction of the indicating line, vertical or horizontal + if True: + self._lineManager[i_id][1][0] = y_range[0] + self._lineManager[i_id][1][-1] = y_range[1] + else: + self._lineManager[i_id][0][0] = x_range[0] + self._lineManager[i_id][0][-1] = x_range[1] + + return + + +class MplGraphicsView(QtGui.QWidget): + """ A combined graphics view including matplotlib canvas and + a navigation tool bar + + Note: Merged with HFIR_Powder_Reduction.MplFigureCAnvas + """ + def __init__(self, parent): + """ Initialization + """ + # Initialize parent + QtGui.QWidget.__init__(self, parent) + + # set up canvas + self._myCanvas = Qt4MplCanvas(self) + self._myToolBar = MyNavigationToolbar(self, self._myCanvas) + + # set up layout + self._vBox = QtGui.QVBoxLayout(self) + self._vBox.addWidget(self._myCanvas) + self._vBox.addWidget(self._myToolBar) + + # auto line's maker+color list + self._myLineMarkerColorList = [] + self._myLineMarkerColorIndex = 0 + self.setAutoLineMarkerColorCombo() + + # Declaration of class variables + self._indicatorKey = None + + # Indicator manager + self._myIndicatorsManager = IndicatorManager() + + return + + def add_line_set(self, vec_set, color, marker, line_style, line_width): + """ Add a set of line and manage together + :param vec_set: + :param color: + :param marker: + :param line_style: + :param line_width: + :return: + """ + key_list = list() + for vec_x, vec_y in vec_set: + temp_key = self._myCanvas.add_plot_1d(vec_x, vec_y, color=color, marker=marker, + line_style=line_style, line_width=line_width) + assert isinstance(temp_key, int) + assert temp_key >= 0 + key_list.append(temp_key) + + return key_list + + def add_plot_1d(self, vec_x, vec_y, y_err=None, color=None, label="", x_label=None, y_label=None, + marker=None, line_style=None, line_width=1): + """ Add a new plot + """ + line_key = self._myCanvas.add_plot_1d(vec_x, vec_y, y_err, color, label, x_label, y_label, marker, line_style, + line_width) + + return line_key + + def add_plot_1d_right(self, vec_x, vec_y, color=None, label='', marker=None, line_style=None, line_width=1): + """ + Add 1 line (1-d plot) to right axis + :param vec_x: + :param vec_y: + :param color: + :param label: + :param marker: + :param line_style: + :param line_width: + :return: + """ + line_key = self._myCanvas.add_1d_plot_right(vec_x, vec_y, label=label, + color=color, marker=marker, + linestyle=line_style, linewidth=line_width) + + return line_key + + def add_2way_indicator(self, x=None, y=None, color=None, master_line=None): + """ Add a 2-way indicator following an existing line? + :param x: + :param y: + :param color: + :return: + """ + if master_line is not None: + raise RuntimeError('Implement how to use master_line ASAP.') + + x_min, x_max = self._myCanvas.getXLimit() + if x is None: + x = (x_min + x_max) * 0.5 + else: + assert isinstance(x, float) + + y_min, y_max = self._myCanvas.getYLimit() + if y is None: + y = (y_min + y_max) * 0.5 + else: + assert isinstance(y, float) + + if color is None: + color = self._myIndicatorsManager.get_next_color() + else: + assert isinstance(color, str) + + my_id = self._myIndicatorsManager.add_2way_indicator(x, x_min, x_max, + y, y_min, y_max, + color) + vec_set = self._myIndicatorsManager.get_2way_data(my_id) + + canvas_line_index = self.add_line_set(vec_set, color=color, + marker=self._myIndicatorsManager.get_marker(), + line_style=self._myIndicatorsManager.get_line_style(), + line_width=1) + self._myIndicatorsManager.set_canvas_line_index(my_id, canvas_line_index) + + return my_id + + def add_horizontal_indicator(self, y=None, color=None): + """ Add an indicator line + """ + # Default + if y is None: + y_min, y_max = self._myCanvas.getYLimit() + y = (y_min + y_max) * 0.5 + else: + assert isinstance(y, float) + + x_min, x_max = self._myCanvas.getXLimit() + + # For color + if color is None: + color = self._myIndicatorsManager.get_next_color() + else: + assert isinstance(color, str) + + # Form + my_id = self._myIndicatorsManager.add_horizontal_indicator(y, x_min, x_max, color) + vec_x, vec_y = self._myIndicatorsManager.get_data(my_id) + + canvas_line_index = self._myCanvas.add_plot_1d(vec_x=vec_x, vec_y=vec_y, + color=color, marker=self._myIndicatorsManager.get_marker(), + line_style=self._myIndicatorsManager.get_line_style(), + line_width=1) + + self._myIndicatorsManager.set_canvas_line_index(my_id, canvas_line_index) + + return my_id + + def add_vertical_indicator(self, x=None, color=None): + """ + Add a vertical indicator line + :param x: None as the automatic mode using default from middle of canvas + :param color: None as the automatic mode using default + :return: indicator ID + """ + # For indicator line's position + if x is None: + x_min, x_max = self._myCanvas.getXLimit() + x = (x_min + x_max) * 0.5 + else: + assert isinstance(x, float) + + y_min, y_max = self._myCanvas.getYLimit() + + # For color + if color is None: + color = self._myIndicatorsManager.get_next_color() + else: + assert isinstance(color, str) + + # Form + my_id = self._myIndicatorsManager.add_vertical_indicator(x, y_min, y_max, color) + vec_x, vec_y = self._myIndicatorsManager.get_data(my_id) + + canvas_line_index = self._myCanvas.add_plot_1d(vec_x=vec_x, vec_y=vec_y, + color=color, marker=self._myIndicatorsManager.get_marker(), + line_style=self._myIndicatorsManager.get_line_style(), + line_width=1) + + self._myIndicatorsManager.set_canvas_line_index(my_id, canvas_line_index) + + return my_id + + def add_plot_2d(self, array2d, x_min, x_max, y_min, y_max, hold_prev_image=True, y_tick_label=None): + """ + Add a 2D image to canvas + :param array2d: numpy 2D array + :param x_min: + :param x_max: + :param y_min: + :param y_max: + :param hold_prev_image: + :param y_tick_label: + :return: + """ + self._myCanvas.addPlot2D(array2d, x_min, x_max, y_min, y_max, hold_prev_image, y_tick_label) + + return + + + def addImage(self, imagefilename): + """ Add an image by file + """ + # check + if os.path.exists(imagefilename) is False: + raise NotImplementedError("Image file %s does not exist." % (imagefilename)) + + self._myCanvas.addImage(imagefilename) + + return + + def clear_all_lines(self): + """ + """ + self._myCanvas.clear_all_1d_plots() + + def clear_canvas(self): + """ Clear canvas + """ + return self._myCanvas.clear_canvas() + + def draw(self): + """ Draw to commit the change + """ + return self._myCanvas.draw() + + def evt_view_updated(self): + """ Event handling as canvas size updated + :return: + """ + # update the indicator + new_x_range = self.getXLimit() + new_y_range = self.getYLimit() + + self._myIndicatorsManager.update_indicators_range(new_x_range, new_y_range) + for indicator_key in self._myIndicatorsManager.get_live_indicator_ids(): + canvas_line_id = self._myIndicatorsManager.get_canvas_line_index(indicator_key) + data_x, data_y = self._myIndicatorsManager.get_data(indicator_key) + self.updateLine(canvas_line_id, data_x, data_y) + # END-FOR + + return + + def getPlot(self): + """ + """ + return self._myCanvas.getPlot() + + def getLastPlotIndexKey(self): + """ Get ... + """ + return self._myCanvas.getLastPlotIndexKey() + + def getXLimit(self): + """ Get limit of Y-axis + """ + return self._myCanvas.getXLimit() + + def getYLimit(self): + """ Get limit of Y-axis + """ + return self._myCanvas.getYLimit() + + def move_indicator(self, line_id, dx, dy): + """ + Move the indicator line in horizontal + :param line_id: + :param dx: + :return: + """ + # Shift value + self._myIndicatorsManager.shift(line_id, dx=dx, dy=dy) + + # apply to plot on canvas + if self._myIndicatorsManager.get_line_type(line_id) < 2: + # horizontal or vertical + canvas_line_index = self._myIndicatorsManager.get_canvas_line_index(line_id) + vec_x, vec_y = self._myIndicatorsManager.get_data(line_id) + self._myCanvas.updateLine(ikey=canvas_line_index, vecx=vec_x, vecy=vec_y) + else: + # 2-way + canvas_line_index_h, canvas_line_index_v = self._myIndicatorsManager.get_canvas_line_index(line_id) + h_vec_set, v_vec_set = self._myIndicatorsManager.get_2way_data(line_id) + + self._myCanvas.updateLine(ikey=canvas_line_index_h, vecx=h_vec_set[0], vecy=h_vec_set[1]) + self._myCanvas.updateLine(ikey=canvas_line_index_v, vecx=v_vec_set[0], vecy=v_vec_set[1]) + + return + + def remove_indicator(self, indicator_key): + """ Remove indicator line + :param indicator_key: + :return: + """ + # + plot_id = self._myIndicatorsManager.get_canvas_line_index(indicator_key) + self._myCanvas.remove_plot_1d(plot_id) + + return + + def removePlot(self, ikey): + """ + """ + return self._myCanvas.remove_plot_1d(ikey) + + def updateLine(self, ikey, vecx, vecy, linestyle=None, linecolor=None, marker=None, markercolor=None): + """ + """ + return self._myCanvas.updateLine(ikey, vecx, vecy, linestyle, linecolor, marker, markercolor) + + def update_indicator(self, i_key, color): + """ + Update indicator with new color + :param i_key: + :param vec_x: + :param vec_y: + :param color: + :return: + """ + if self._myIndicatorsManager.get_line_type(i_key) < 2: + # horizontal or vertical + canvas_line_index = self._myIndicatorsManager.get_canvas_line_index(i_key) + self._myCanvas.updateLine(ikey=canvas_line_index, vecx=None, vecy=None, linecolor=color) + else: + # 2-way + canvas_line_index_h, canvas_line_index_v = self._myIndicatorsManager.get_canvas_line_index(i_key) + # h_vec_set, v_vec_set = self._myIndicatorsManager.get_2way_data(i_key) + + self._myCanvas.updateLine(ikey=canvas_line_index_h, vecx=None, vecy=None, linecolor=color) + self._myCanvas.updateLine(ikey=canvas_line_index_v, vecx=None, vecy=None, linecolor=color) + + return + + def get_indicator_position(self, indicator_key): + """ Get position (x or y) of the indicator + :return: + """ + # NEXT - Consider a better and more consistent return + vec_x, vec_y = self._myIndicatorsManager.get_data(indicator_key) + if vec_x[0] == vec_x[1]: + return vec_x[0] + + return vec_y[0] + + def getLineStyleList(self): + """ + """ + return MplLineStyles + + def getLineMarkerList(self): + """ + """ + return MplLineMarkers + + def getLineBasicColorList(self): + """ + """ + return MplBasicColors + + def getDefaultColorMarkerComboList(self): + """ Get a list of line/marker color and marker style combination + as default to add more and more line to plot + """ + return self._myCanvas.getDefaultColorMarkerComboList() + + def getNextLineMarkerColorCombo(self): + """ As auto line's marker and color combo list is used, + get the NEXT marker/color combo + """ + # get from list + marker, color = self._myLineMarkerColorList[self._myLineMarkerColorIndex] + # process marker if it has information + if marker.count(' (') > 0: + marker = marker.split(' (')[0] + print "[DB] Print line %d: marker = %s, color = %s" % (self._myLineMarkerColorIndex, marker, color) + + # update the index + self._myLineMarkerColorIndex += 1 + if self._myLineMarkerColorIndex == len(self._myLineMarkerColorList): + self._myLineMarkerColorIndex = 0 + + return marker, color + + def resetLineColorStyle(self): + """ Reset the auto index for line's color and style + """ + self._myLineMarkerColorIndex = 0 + return + + # NEXT-Urgent! - Find out difference between setXYLimit() and setXYLimits() + def setXYLimit(self, xmin, xmax, ymin, ymax): + """ Set X-Y limit automatically + """ + self._myCanvas.axes.set_xlim([xmin, xmax]) + self._myCanvas.axes.set_ylim([ymin, ymax]) + + self._myCanvas.draw() + + return + + def setXYLimits(self, xmin=None, xmax=None, ymin=None, ymax=None): + """ + """ + return self._myCanvas.setXYLimit(xmin, xmax, ymin, ymax) + + def setAutoLineMarkerColorCombo(self): + """ + """ + self._myLineMarkerColorList = [] + for marker in MplLineMarkers: + for color in MplBasicColors: + self._myLineMarkerColorList.append( (marker, color) ) + + return + + def setLineMarkerColorIndex(self, newindex): + """ + """ + self._myLineMarkerColorIndex = newindex + + return + + +class Qt4MplCanvas(FigureCanvas): + """ A customized Qt widget for matplotlib figure. + It can be used to replace GraphicsView of QtGui + """ + def __init__(self, parent): + """ Initialization + """ + # from mpl_toolkits.axes_grid1 import host_subplot + # import mpl_toolkits.axisartist as AA + # import matplotlib.pyplot as plt + + # Instantiating matplotlib Figure + self.fig = Figure() + self.fig.patch.set_facecolor('white') + + if True: + self.axes = self.fig.add_subplot(111) # return: matplotlib.axes.AxesSubplot + self.axes2 = None + else: + self.axes = self.fig.add_host_subplot(111) + + # Initialize parent class and set parent + FigureCanvas.__init__(self, self.fig) + self.setParent(parent) + + # Set size policy to be able to expanding and resizable with frame + FigureCanvas.setSizePolicy(self, QtGui.QSizePolicy.Expanding,QtGui.QSizePolicy.Expanding) + FigureCanvas.updateGeometry(self) + + # Variables to manage all lines/subplot + self._lineDict = {} + self._lineIndex = 0 + + # legend and color bar + self._colorBar = None + + return + + def add_plot_1d(self, vec_x, vec_y, y_err=None, color=None, label="", x_label=None, y_label=None, + marker=None, line_style=None, line_width=1): + """ + + :param vec_x: numpy array X + :param vec_y: numpy array Y + :param y_err: + :param color: + :param label: + :param x_label: + :param y_label: + :param marker: + :param line_style: + :param line_width: + :return: new key + """ + # Check input + if isinstance(vec_x, np.ndarray) is False or isinstance(vec_y, np.ndarray) is False: + raise NotImplementedError('Input vec_x or vec_y for addPlot() must be numpy.array.') + plot_error = y_err is not None + if plot_error is True: + if isinstance(y_err, np.ndarray) is False: + raise NotImplementedError('Input y_err must be either None or numpy.array.') + + if len(vec_x) != len(vec_y): + raise NotImplementedError('Input vec_x and vec_y must have same size.') + if plot_error is True and len(y_err) != len(vec_x): + raise NotImplementedError('Input vec_x, vec_y and y_error must have same size.') + + # Hold previous data + self.axes.hold(True) + + # process inputs and defaults + if color is None: + color = (0,1,0,1) + if marker is None: + marker = 'o' + if line_style is None: + line_style = '-' + + # color must be RGBA (4-tuple) + if plot_error is False: + print "[DB] line_style = ", line_style, "line_width = ", line_width, "marker = ", marker, "color = ", color + r = self.axes.plot(vec_x, vec_y, color=color, marker=marker, linestyle=line_style, + label=label, linewidth=line_width) + # return: list of matplotlib.lines.Line2D object + else: + r = self.axes.errorbar(vec_x, vec_y, yerr=y_err, color=color, marker=marker, linestyle=line_style, + label=label, linewidth=line_width) + + self.axes.set_aspect('auto') + + # set x-axis and y-axis label + if x_label is not None: + self.axes.set_xlabel(x_label, fontsize=20) + if y_label is not None: + self.axes.set_ylabel(y_label, fontsize=20) + + # set/update legend + self._setupLegend() + + # Register + line_key = self._lineIndex + if len(r) == 1: + self._lineDict[line_key] = r[0] + self._lineIndex += 1 + else: + print "Impoooooooooooooooosible! Return from plot is a %d-tuple. " % (len(r)) + + # Flush/commit + self.draw() + + return line_key + + def add_1d_plot_right(self, x, y, color=None, label="", x_label=None, ylabel=None, marker=None, linestyle=None, + linewidth=1): + """ Add a line (1-d plot) at right axis + """ + if self.axes2 is None: + self.axes2 = self.axes.twinx() + # print self.par1, type(self.par1) + + # Hold previous data + self.axes2.hold(True) + + # Default + if color is None: + color = (0, 1, 0, 1) + if marker is None: + marker = 'o' + if linestyle is None: + linestyle = '-' + + # Special default + if len(label) == 0: + label = 'right' + color = 'red' + + # color must be RGBA (4-tuple) + r = self.axes2.plot(x, y, color=color, marker=marker, linestyle=linestyle, + label=label, linewidth=linewidth) + # return: list of matplotlib.lines.Line2D object + + self.axes2.set_aspect('auto') + + # set x-axis and y-axis label + if x_label is not None: + self.axes2.set_xlabel(x_label, fontsize=20) + if ylabel is not None: + self.axes2.set_ylabel(ylabel, fontsize=20) + + # set/update legend + self._setupLegend() + + # Register + line_key = -1 + if len(r) == 1: + line_key = self._lineIndex + self._lineDict[line_key] = r[0] + self._lineIndex += 1 + else: + print "Impoooooooooooooooosible!" + + # Flush/commit + self.draw() + + return line_key + + + def addPlot2D(self, array2d, xmin, xmax, ymin, ymax, holdprev, yticklabels=None): + """ Add a 2D plot + + Arguments: + - yticklabels :: list of string for y ticks + """ + # Release the current image + self.axes.hold(holdprev) + + # Do plot + # y ticks will be shown on line 1, 4, 23, 24 and 30 + # yticks = [1, 4, 23, 24, 30] + # self.axes.set_yticks(yticks) + + # show image + imgplot = self.axes.imshow(array2d, extent=[xmin,xmax,ymin,ymax], interpolation='none') + # set y ticks as an option: + if yticklabels is not None: + # it will always label the first N ticks even image is zoomed in + print "--------> [FixMe]: Set up the Y-axis ticks is erroreous" + #self.axes.set_yticklabels(yticklabels) + + # explicitly set aspect ratio of the image + self.axes.set_aspect('auto') + + # Set color bar. plt.colorbar() does not work! + if self._colorBar is None: + # set color map type + imgplot.set_cmap('spectral') + self._colorBar = self.fig.colorbar(imgplot) + else: + self._colorBar.update_bruteforce(imgplot) + + # Flush... + self._flush() + + return + + def addImage(self, imagefilename): + """ Add an image by file + """ + #import matplotlib.image as mpimg + + # set aspect to auto mode + self.axes.set_aspect('auto') + + img = matplotlib.image.imread(str(imagefilename)) + # lum_img = img[:,:,0] + # FUTURE : refactor for image size, interpolation and origin + imgplot = self.axes.imshow(img, extent=[0, 1000, 800, 0], interpolation='none', origin='lower') + + # Set color bar. plt.colorbar() does not work! + if self._colorBar is None: + # set color map type + imgplot.set_cmap('spectral') + self._colorBar = self.fig.colorbar(imgplot) + else: + self._colorBar.update_bruteforce(imgplot) + + self._flush() + + return + + def clear_all_1d_plots(self): + """ Remove all lines from the canvas + """ + for ikey in self._lineDict.keys(): + plot = self._lineDict[ikey] + if plot is None: + continue + if isinstance(plot, tuple) is False: + try: + self.axes.lines.remove(plot) + except ValueError as e: + print "[Error] Plot %s is not in axes.lines which has %d lines. Error mesage: %s" % ( + str(plot), len(self.axes.lines), str(e)) + self._lineDict[ikey] = None + else: + # error bar + plot[0].remove() + for line in plot[1]: + line.remove() + for line in plot[2]: + line.remove() + self._lineDict[ikey] = None + # ENDIF(plot) + # ENDFOR + + self._setupLegend() + + self.draw() + + return + + def clear_canvas(self): + """ Clear data including lines and image from canvas + """ + # clear the image for next operation + self.axes.hold(False) + + # Clear all lines + self.clear_all_1d_plots() + + # clear image + self.axes.cla() + # Try to clear the color bar + if len(self.fig.axes) > 1: + self.fig.delaxes(self.fig.axes[1]) + self._colorBar = None + # This clears the space claimed by color bar but destroys sub_plot too. + self.fig.clear() + # Re-create subplot + self.axes = self.fig.add_subplot(111) + + # flush/commit + self._flush() + + return + + + def getLastPlotIndexKey(self): + """ Get the index/key of the last added line + """ + return self._lineIndex-1 + + + def getPlot(self): + """ reture figure's axes to expose the matplotlib figure to PyQt client + """ + return self.axes + + def getXLimit(self): + """ Get limit of Y-axis + """ + return self.axes.get_xlim() + + def getYLimit(self): + """ Get limit of Y-axis + """ + return self.axes.get_ylim() + + def setXYLimit(self, xmin, xmax, ymin, ymax): + """ + """ + # for X + xlims = self.axes.get_xlim() + xlims = list(xlims) + if xmin is not None: + xlims[0] = xmin + if xmax is not None: + xlims[1] = xmax + self.axes.set_xlim(xlims) + + # for Y + ylims = self.axes.get_ylim() + ylims = list(ylims) + if ymin is not None: + ylims[0] = ymin + if ymax is not None: + ylims[1] = ymax + self.axes.set_ylim(ylims) + + # try draw + self.draw() + + return + + def remove_plot_1d(self, plot_key): + """ Remove the line with its index as key + :param plot_key: + :return: + """ + # self._lineDict[ikey].remove() + print 'Remove line... ', + + # Get all lines in list + lines = self.axes.lines + assert isinstance(lines, list) + + print 'Number of lines = %d, List: %s' % (len(lines), str(lines)) + print 'Line to remove: key = %s, Line Dict has key = %s' % (str(plot_key), str(self._lineDict.has_key(plot_key))) + + if plot_key in self._lineDict: + self.axes.lines.remove(self._lineDict[plot_key]) + self._lineDict[plot_key] = None + else: + raise RuntimeError('Line with ID %s is not recorded.' % plot_key) + + # Draw + self.draw() + + return + + def updateLine(self, ikey, vecx, vecy, linestyle=None, linecolor=None, marker=None, markercolor=None): + """ + """ + line = self._lineDict[ikey] + + if vecx is not None and vecy is not None: + line.set_xdata(vecx) + line.set_ydata(vecy) + + if linecolor is not None: + line.set_color(linecolor) + + if linestyle is not None: + line.set_linestyle(linestyle) + + if marker is not None: + line.set_marker(marker) + + if markercolor is not None: + line.set_markerfacecolor(markercolor) + + oldlabel = line.get_label() + line.set_label(oldlabel) + + self.axes.legend() + + # commit + self.draw() + + return + + def getLineStyleList(self): + """ + """ + return MplLineStyles + + + def getLineMarkerList(self): + """ + """ + return MplLineMarkers + + def getLineBasicColorList(self): + """ + """ + return MplBasicColors + + def getDefaultColorMarkerComboList(self): + """ Get a list of line/marker color and marker style combination + as default to add more and more line to plot + """ + combolist = [] + nummarkers = len(MplLineMarkers) + numcolors = len(MplBasicColors) + + for i in xrange(nummarkers): + marker = MplLineMarkers[i] + for j in xrange(numcolors): + color = MplBasicColors[j] + combolist.append( (marker, color) ) + # ENDFOR (j) + # ENDFOR(i) + + return combolist + + def _flush(self): + """ A dirty hack to flush the image + """ + w, h = self.get_width_height() + self.resize(w+1,h) + self.resize(w,h) + + return + + def _setupLegend(self, location='best'): + """ Set up legend + self.axes.legend() + Handler is a Line2D object. Lable maps to the line object + """ + loclist = [ + "best", + "upper right", + "upper left", + "lower left", + "lower right", + "right", + "center left", + "center right", + "lower center", + "upper center", + "center"] + + # Check legend location valid or not + if location not in loclist: + location = 'best' + + handles, labels = self.axes.get_legend_handles_labels() + self.axes.legend(handles, labels, loc=location) + # print handles + # print labels + #self.axes.legend(self._myLegendHandlers, self._myLegentLabels) + + return + +# END-OF-CLASS (MplGraphicsView) + + +class MyNavigationToolbar(NavigationToolbar2): + """ A customized navigation tool bar attached to canvas + Note: + * home, left, right: will not disable zoom/pan mode + * zoom and pan: will turn on/off both's mode + + Other methods + * drag_pan(self, event): event handling method for dragging canvas in pan-mode + """ + NAVIGATION_MODE_NONE = 0 + NAVIGATION_MODE_PAN = 1 + NAVIGATION_MODE_ZOOM = 2 + + def __init__(self, parent, canvas): + """ Initialization + """ + NavigationToolbar2.__init__(self, canvas, canvas) + + self._myParent = parent + self._navigationMode = MyNavigationToolbar.NAVIGATION_MODE_NONE + + return + + def get_mode(self): + """ + :return: integer as none/pan/zoom mode + """ + return self._navigationMode + + # Overriding base's methods + def draw(self): + """ + Canvas is drawn called by pan(), zoom() + :return: + """ + NavigationToolbar2.draw(self) + + self._myParent.evt_view_updated() + + return + + def pan(self, *args): + """ + + :param args: + :return: + """ + NavigationToolbar2.pan(self, args) + + if self._navigationMode == MyNavigationToolbar.NAVIGATION_MODE_PAN: + # out of pan mode + self._navigationMode = MyNavigationToolbar.NAVIGATION_MODE_NONE + else: + # into pan mode + self._navigationMode = MyNavigationToolbar.NAVIGATION_MODE_PAN + + return + + def zoom(self, *args): + """ + Turn on/off zoom (zoom button) + :param args: + :return: + """ + NavigationToolbar2.zoom(self, args) + + if self._navigationMode == MyNavigationToolbar.NAVIGATION_MODE_ZOOM: + # out of zoom mode + self._navigationMode = MyNavigationToolbar.NAVIGATION_MODE_NONE + else: + # into zoom mode + self._navigationMode = MyNavigationToolbar.NAVIGATION_MODE_ZOOM + + return + + def _update_view(self): + """ + view update called by home(), back() and forward() + :return: + """ + NavigationToolbar2._update_view(self) + + self._myParent.evt_view_updated() + + return + diff --git a/scripts/HFIR_4Circle_Reduction/reduce4circleControl.py b/scripts/HFIR_4Circle_Reduction/reduce4circleControl.py new file mode 100644 index 0000000000000000000000000000000000000000..bb11355d3c1b09e8e5b011cd8b698d64614939aa --- /dev/null +++ b/scripts/HFIR_4Circle_Reduction/reduce4circleControl.py @@ -0,0 +1,1263 @@ +#pylint: disable=C0302,C0103,R0902,R0904,R0913,W0212,W0621,R0912 +################################################################################ +# +# Controlling class +# +# == Data download and storage == +# - Local data storage (local-mode) +# - Download from internet to cache (download-mode) +# +################################################################################ +import os +import urllib2 + +import numpy + +import mantid +import mantid.simpleapi as api +from mantid.api import AnalysisDataService + +DebugMode = True + +DET_X_SIZE = 256 +DET_Y_SIZE = 256 + + +class PeakInfo(object): + """ Class containing a peak's information for GUI + In order to manage some operations for a peak + It does not contain peak workspace but will hold + """ + def __init__(self, parent): + """ Init + """ + assert isinstance(parent, CWSCDReductionControl) + + # Define class variable + self._myParent = parent + self._userHKL = [0, 0, 0] + + self._myExpNumber = None + self._myScanNumber = None + self._myPtNumber = None + + self._myPeakWSKey = (None, None, None) + self._myPeakIndex = None + # IPeak instance + self._myPeak = None + + self._myLastPeakUB = None + + return + + def get_peak_workspace(self): + """ + Get peak workspace related + :return: + """ + assert isinstance(self._myPeakWSKey, tuple) + exp_number, scan_number, pt_number = self._myPeakWSKey + + return self._myParent.get_ub_peak_ws(exp_number, scan_number, pt_number)[1] + + def get_peak_ws_hkl(self): + """ Get HKL from PeakWorkspace + :return: + """ + hkl = self._myPeak.getHKL() + + return hkl.getX(), hkl.getY(), hkl.getZ() + + def get_user_hkl(self): + """ + Get HKL set to this object by client + :return: 3-tuple of float as (H, K, L) + """ + hkl = self._userHKL + + return hkl[0], hkl[1], hkl[2] + + def set_from_run_info(self, exp_number, scan_number, pt_number): + """ Set from run information with parent + :param exp_number: + :param scan_number: + :param pt_number: + :return: + """ + assert isinstance(exp_number, int) + assert isinstance(scan_number, int) + assert isinstance(pt_number, int) + + status, peak_ws = self._myParent.get_ub_peak_ws(exp_number, scan_number, pt_number) + if status is True: + self._myPeakWSKey = (exp_number, scan_number, pt_number) + self._myPeakIndex = 0 + self._myPeak = peak_ws.getPeak(0) + else: + error_message = peak_ws + return False, error_message + + self._myExpNumber = exp_number + self._myScanNumber = scan_number + self._myPtNumber = pt_number + + return True, '' + + def set_from_peak_ws(self, peak_ws, peak_index): + """ + Set from peak workspace + :param peak_ws: + :return: + """ + # Check + assert isinstance(peak_ws, mantid.dataobjects.PeaksWorkspace) + + # Get peak + try: + peak = peak_ws.getPeak(peak_index) + except RuntimeError as run_err: + raise RuntimeError(run_err) + + self._myPeak = peak + + return + + def set_peak_ws_hkl_from_user(self): + """ + + :return: + """ + # Check + if isinstance(self._myPeak, mantid.api.IPeak) is False: + raise RuntimeError('self._myPeakWS should be an instance of mantid.api.IPeak. ' + 'But it is of instance of %s now.' % str(type(self._myPeak))) + + # Get hkl + h, k, l = self._userHKL + print '[DB] PeakInfo Get User HKL = (%f, %f, %f) to IPeak ' % (h, k, l) + + self._myPeak.setHKL(h, k, l) + + return + + def set_user_hkl(self, h, k, l): + """ + Set HKL to this peak Info + :return: + """ + assert isinstance(h, float) + assert isinstance(k, float) + assert isinstance(l, float) + + self._userHKL[0] = h + self._userHKL[1] = k + self._userHKL[2] = l + + print '[DB] PeakInfo Set User HKL to (%f, %f, %f) ' % (self._userHKL[0], self._userHKL[1], self._userHKL[2]) + + return + + def getExpInfo(self): + """ + + :return: 3-tuple of integer as experiment number, scan number and Pt number + """ + return self._myExpNumber, self._myScanNumber, self._myPtNumber + + def getQSample(self): + """ + + :return: 3-tuple of floats as Qx, Qy, Qz + """ + q_sample = self._myPeak.getQSampleFrame() + return q_sample.getX(), q_sample.getY(), q_sample.getZ() + + +class CWSCDReductionControl(object): + """ Controlling class for reactor-based single crystal diffraction reduction + """ + def __init__(self, instrument_name=None): + """ init + """ + if isinstance(instrument_name, str): + self._instrumentName = instrument_name + elif instrument_name is None: + self._instrumentName = '' + else: + raise RuntimeError('Instrument name %s of type %s is not allowed.' % (str(instrument_name), + str(type(instrument_name)))) + + # Experiment number, data storage + # No Use/Confusing: self._expNumber = 0 + + self._dataDir = None + self._workDir = '/tmp' + + self._myServerURL = '' + + # Some set up + self._expNumber = None + + # Container for MDEventWorkspace for each Pt. + self._myPtMDDict = dict() + # Container for loaded workspaces + self._mySpiceTableDict = {} + # Container for loaded raw pt workspace + self._myRawDataWSDict = dict() + # Container for PeakWorkspaces for calculating UB matrix + self._myUBPeakWSDict = dict() + # Container for UB matrix + self._myUBMatrixDict = dict() + + # Peak Info + self._myPeakInfoDict = dict() + # Last UB matrix calculated + self._myLastPeakUB = None + # Flag for data storage + self._cacheDataOnly = False + + # A dictionary to manage all loaded and processed MDEventWorkspaces + # self._expDataDict = {} + + return + + def add_peak_info(self, exp_number, scan_number, pt_number): + """ Add a peak info for calculating UB matrix + :param exp_number: + :param scan_number: + :param pt_number: + :return: (boolean, PeakInfo/string) + """ + has_peak_ws, peak_ws = self.get_ub_peak_ws(exp_number, scan_number, pt_number) + if has_peak_ws is False: + err_msg = 'No peak workspace found for Exp %s Scan %s Pt %s' % ( + exp_number, scan_number, pt_number) + print '\n[DB] Fail to add peak info due to %s\n' % err_msg + return False, err_msg + + if peak_ws.rowCount() > 1: + err_msg = 'There are more than 1 peak in PeaksWorkspace.' + print '\n[DB] Fail to add peak info due to %s\n' % err_msg + return False, err_msg + + peak_info = PeakInfo(self) + peak_info.set_from_run_info(exp_number, scan_number, pt_number) + + # Add to data management + self._myPeakInfoDict[(exp_number, scan_number, pt_number)] = peak_info + + return True, peak_info + + def calculate_ub_matrix(self, peak_info_list, a, b, c, alpha, beta, gamma): + """ + Calculate UB matrix + + Set Miller index from raw data in Workspace2D. + :param peakws: + :param a: + :param b: + :param c: + :param alpha: + :param beta: + :param gamma: + :return: + """ + # Check + assert isinstance(peak_info_list, list) + for peak_info in peak_info_list: + if isinstance(peak_info, PeakInfo) is False: + raise NotImplementedError('Input PeakList is of type %s.' % str(type(peak_info_list[0]))) + assert isinstance(peak_info, PeakInfo) + + if len(peak_info_list) < 2: + return False, 'Too few peaks are input to calculate UB matrix. Must be >= 2.' + + # Construct a new peak workspace by combining all single peak + ub_peak_ws_name = 'Temp_UB_Peak' + ub_peak_ws = api.CloneWorkspace(InputWorkspace=peak_info_list[0].get_peak_workspace(), + OutputWorkspace=ub_peak_ws_name) + + for i_peak_info in xrange(1, len(peak_info_list)): + # Set HKL as optional + peak_ws = peak_info_list[i_peak_info].get_peak_workspace() + + # Combine peak workspace + ub_peak_ws = api.CombinePeaksWorkspaces(LHSWorkspace=ub_peak_ws, + RHSWorkspace=peak_ws, + CombineMatchingPeaks=False, + OutputWorkspace=ub_peak_ws_name) + # END-FOR(i_peak_info) + + # Calculate UB matrix + try: + api.CalculateUMatrix(PeaksWorkspace=ub_peak_ws_name, + a=a, b=b, c=c, alpha=alpha, beta=beta, gamma=gamma) + except ValueError as val_err: + return False, str(val_err) + + ub_matrix = ub_peak_ws.sample().getOrientedLattice().getUB() + + self._myLastPeakUB = ub_peak_ws + + return True, ub_matrix + + def does_raw_loaded(self, exp_no, scan_no, pt_no): + """ + Check whether the raw Workspace2D for a Pt. exists + :param exp_no: + :param scan_no: + :param pt_no: + :return: + """ + return (exp_no, scan_no, pt_no) in self._myRawDataWSDict + + def does_spice_loaded(self, exp_no, scan_no): + """ Check whether a SPICE file has been loaded + :param exp_no: + :param scan_no: + :return: + """ + return (exp_no, scan_no) in self._mySpiceTableDict + + def download_spice_file(self, exp_number, scan_number, over_write): + """ + Download a scan/pt data from internet + :param exp_number: experiment number + :param scan_number: + :return: + """ + # Check + if exp_number is None: + exp_number = self._expNumber + assert isinstance(exp_number, int) + assert isinstance(scan_number, int) + + # Generate the URL for SPICE data file + file_url = '%sexp%d/Datafiles/HB3A_exp%04d_scan%04d.dat' % (self._myServerURL, exp_number, + exp_number, scan_number) + file_name = '%s_exp%04d_scan%04d.dat' % (self._instrumentName, exp_number, scan_number) + file_name = os.path.join(self._dataDir, file_name) + if os.path.exists(file_name) is True and over_write is False: + return True, file_name + + # Download + try: + api.DownloadFile(Address=file_url, Filename=file_name) + except RuntimeError as run_err: + return False, str(run_err) + + # Check file exist? + if os.path.exists(file_name) is False: + return False, "Unable to locate downloaded file %s." % file_name + + return True, file_name + + def download_spice_xml_file(self, scan_no, pt_no, exp_no=None, overwrite=False): + """ Download a SPICE XML file for one measurement in a scan + :param scan_no: + :param pt_no: + :param exp_no: + :param overwrite: + :return: tuple (boolean, local file name/error message) + """ + # Experiment number + if exp_no is None: + exp_no = self._expNumber + + # Form the target file name and path + xml_file_name = '%s_exp%d_scan%04d_%04d.xml' % (self._instrumentName, exp_no, scan_no, pt_no) + local_xml_file_name = os.path.join(self._dataDir, xml_file_name) + if os.path.exists(local_xml_file_name) is True and overwrite is False: + return True, local_xml_file_name + + # Generate the URL for XML file + xml_file_url = '%sexp%d/Datafiles/%s' % (self._myServerURL, exp_no, xml_file_name) + + # Download + try: + api.DownloadFile(Address=xml_file_url, + Filename=local_xml_file_name) + except RuntimeError as run_err: + return False, 'Unable to download Detector XML file %s dur to %s.' % (xml_file_name, str(run_err)) + + # Check file exist? + if os.path.exists(local_xml_file_name) is False: + return False, "Unable to locate downloaded file %s."%(local_xml_file_name) + + return True, local_xml_file_name + + def download_data_set(self, scan_list, overwrite=False): + """ + Download data set including (1) spice file for a scan and (2) XML files for measurements + :param scan_list: + :return: + """ + # Check + if self._expNumber is None: + raise RuntimeError('Experiment number is not set up for controller.') + + error_message = '' + + for scan_no in scan_list: + # Download single spice file for a run + status, ret_obj = self.download_spice_file(exp_number=self._expNumber, + scan_number=scan_no, + over_write=overwrite) + + # Reject if SPICE file cannot download + if status is False: + error_message += '%s\n' % ret_obj + continue + + # Load SPICE file to Mantid + spice_file_name = ret_obj + status, ret_obj = self.load_spice_scan_file(self._expNumber, scan_no, spice_file_name) + if status is False: + error_message = ret_obj + return False, error_message + else: + spice_table = self._mySpiceTableDict[(self._expNumber, scan_no)] + assert spice_table + pt_no_list = self._get_pt_list_from_spice_table(spice_table) + + # Download all single-measurement file + for pt_no in pt_no_list: + status, ret_obj = self.download_spice_xml_file(scan_no, pt_no, overwrite=overwrite) + if status is False: + error_message += '%s\n' % ret_obj + # END-FOR + # END-FOR (scan_no) + + return True, error_message + + def existDataFile(self, scanno, ptno): + """ + Check whether data file for a scan or pt number exists + :param scanno: + :param ptno: + :return: + """ + # Check spice file + spice_file_name = '%s_exp%04d_scan%04d.dat'%(self._instrumentName, + self._expNumber, scanno) + spice_file_name = os.path.join(self._dataDir, spice_file_name) + if os.path.exists(spice_file_name) is False: + return False, 'Spice data file %s cannot be found.'% spice_file_name + + # Check xml file + xmlfilename = '%s_exp%d_scan%04d_%04d.xml'%(self._instrumentName, self._expNumber, + scanno, ptno) + xmlfilename = os.path.join(self._dataDir, xmlfilename) + if os.path.exists(xmlfilename) is False: + return (False, "Pt. XML file %s cannot be found."%(xmlfilename)) + + return True, "" + + def find_peak(self, exp_number, scan_number, pt_number): + """ Find 1 peak in sample Q space for UB matrix + :param scan_number: + :param pt_number: + :return:tuple as (boolean, object) such as (false, error message) and (true, PeakInfo object) + + This part will be redo as 11847_Load_HB3A_Experiment + """ + # Check + assert isinstance(exp_number, int) + assert isinstance(scan_number, int) + assert isinstance(pt_number, int) + + # Download or make sure data are there + status_sp, err_msg_sp = self.download_spice_file(exp_number, scan_number, over_write=False) + status_det, err_msg_det = self.download_spice_xml_file(scan_number, pt_number, exp_number, + overwrite=False) + if status_sp is False or status_det is False: + return False, 'Unable to access data (1) %s (2) %s' % (err_msg_sp, err_msg_det) + + # Collect reduction information: example + exp_info_ws_name = get_pt_info_ws_name(exp_number, scan_number) + virtual_instrument_info_table_name = get_virtual_instrument_table_name(exp_number, scan_number, pt_number) + api.CollectHB3AExperimentInfo( + ExperimentNumber=exp_number, + GenerateVirtualInstrument=False, + ScanList=[scan_number], + PtLists=[-1, pt_number], + DataDirectory=self._dataDir, + GetFileFromServer=False, + Detector2ThetaTolerance=0.01, + OutputWorkspace=exp_info_ws_name, + DetectorTableWorkspace=virtual_instrument_info_table_name) + + # Load XML file to MD + pt_md_ws_name = get_single_pt_md_name(exp_number, scan_number, pt_number) + api.ConvertCWSDExpToMomentum(InputWorkspace=exp_info_ws_name, + CreateVirtualInstrument=False, + OutputWorkspace=pt_md_ws_name, + Directory=self._dataDir) + + # Find peak in Q-space + pt_peak_ws_name = get_single_pt_peak_ws_name(exp_number, scan_number, pt_number) + api.FindPeaksMD(InputWorkspace=pt_md_ws_name, MaxPeaks=10, + DensityThresholdFactor=0.01, OutputWorkspace=pt_peak_ws_name) + peak_ws = AnalysisDataService.retrieve(pt_peak_ws_name) + pt_md_ws = AnalysisDataService.retrieve(pt_md_ws_name) + self._myPtMDDict[(exp_number, scan_number, pt_number)] = pt_md_ws + + num_peaks = peak_ws.getNumberPeaks() + if num_peaks != 1: + err_msg = 'Find %d peak from scan %d pt %d. ' \ + 'For UB matrix calculation, 1 and only 1 peak is allowed' % (num_peaks, scan_number, pt_number) + return False, err_msg + else: + self._add_ub_peak_ws(exp_number, scan_number, pt_number, peak_ws) + status, ret_obj = self.add_peak_info(exp_number, scan_number, pt_number) + if status is True: + pass + # peak_info = ret_obj + # peak_info.set_md_ws(pt_md_ws) + else: + err_msg = ret_obj + return False, err_msg + + return True, '' + + def get_experiment(self): + """ + Get experiment number + :return: + """ + return self._expNumber + + def get_pt_numbers(self, exp_no, scan_no, load_spice_scan=False): + """ Get Pt numbers (as a list) for a scan in an experiment + :param exp_no: + :param scan_no: + :param load_spice_scan: + :return: (Boolean, Object) as (status, pt number list/error message) + """ + # Check + if exp_no is None: + exp_no = self._expNumber + assert isinstance(exp_no, int) + assert isinstance(scan_no, int) + + # Get workspace + table_ws = self._get_spice_workspace(exp_no, scan_no) + if table_ws is None: + if load_spice_scan is False: + return False, 'Spice file for Exp %d Scan %d is not loaded.' % (exp_no, scan_no) + else: + status, error_message = self.load_spice_scan_file(exp_no, scan_no) + if status is True: + table_ws = self._get_spice_workspace(exp_no, scan_no) + if table_ws is None: + raise NotImplementedError('Logic error! Cannot happen!') + else: + return False, 'Unable to load Spice file for Exp %d Scan %d due to %s.' % ( + exp_no, scan_no, error_message) + + col_name_list = table_ws.getColumnNames() + i_pt = col_name_list.index('Pt.') + if i_pt < 0 or i_pt >= len(col_name_list): + return False, 'No column with name Pt. can be found in SPICE table.' + + pt_number_list = [] + num_rows = table_ws.rowCount() + for i in xrange(num_rows): + pt_number = table_ws.cell(i, i_pt) + pt_number_list.append(pt_number) + + return True, pt_number_list + + def get_raw_detector_counts(self, exp_no, scan_no, pt_no): + """ + Get counts on raw detector + :param scan_no: + :param pt_no: + :return: boolean, 2D numpy data + """ + # Get workspace (in memory or loading) + raw_ws = self.get_raw_data_workspace(exp_no, scan_no, pt_no) + if raw_ws is None: + return False, 'Raw data for Exp %d Scan %d Pt %d is not loaded.' % (exp_no, scan_no, pt_no) + + # Convert to numpy array + array2d = numpy.ndarray(shape=(DET_X_SIZE, DET_Y_SIZE), dtype='float') + for i in xrange(DET_X_SIZE): + for j in xrange(DET_Y_SIZE): + array2d[i][j] = raw_ws.readY(i * DET_X_SIZE + j)[0] + + return array2d + + def get_sample_log_value(self, exp_number, scan_number, pt_number, log_name): + """ + Get sample log's value + :param exp_number: + :param scan_number:167 + :param pt_number: + :param log_name: + :return: float + """ + assert isinstance(exp_number, int) + assert isinstance(scan_number, int) + assert isinstance(pt_number, int) + assert isinstance(log_name, str) + try: + md_ws = self._myPtMDDict[(exp_number, scan_number, pt_number)] + except KeyError as ke: + return 'Unable to find log value %s due to %s.' % (log_name, str(ke)) + + return md_ws.getExperimentInfo(0).run().getProperty(log_name).value + + def get_peak_info(self, exp_number, scan_number, pt_number): + """ + get peak information instance + :param exp_number: experiment number. if it is None, then use the current exp number + :param scan_number: + :param pt_number: + :return: + """ + # Check for type + if exp_number is None: + exp_number = self._expNumber + + assert isinstance(exp_number, int) + assert isinstance(scan_number, int) + assert isinstance(pt_number, int) + + # Check for existence + if (exp_number, scan_number, pt_number) not in self._myUBPeakWSDict: # self._myPeakInfoDict: + err_msg = 'Unable to find PeakInfo for Exp %d Scan %d Pt %d. ' \ + 'Existing keys are %s' % (exp_number, scan_number, pt_number, + str(self._myUBPeakWSDict.keys())) + return False, err_msg + + print '[DB] PeakInfoDictionary Keys = %s' % str(self._myPeakInfoDict.keys()) + + return True, self._myPeakInfoDict[(exp_number, scan_number, pt_number)] + + def get_ub_peak_ws(self, exp_number, scan_number, pt_number): + """ + Get peak workspace for the peak picked to calculate UB matrix + :param exp_number: + :param scan_number: + :param pt_number: + :return: + """ + assert isinstance(exp_number, int) + assert isinstance(scan_number, int) + assert isinstance(pt_number, int) + + if (exp_number, scan_number, pt_number) not in self._myUBPeakWSDict: + return False, 'Exp %d Scan %d Pt %d has no peak workspace.' % (exp_number, + scan_number, + pt_number) + + return True, self._myUBPeakWSDict[(exp_number, scan_number, pt_number)] + + def index_peak(self, ub_matrix, scan_number, pt_number): + """ Index peaks in a Pt. + :param ub_matrix: numpy.ndarray (3, 3) + :param scan_number: + :param pt_number: + :return: boolean, object (list of HKL or error message) + """ + # Check + assert isinstance(ub_matrix, numpy.ndarray) + assert ub_matrix.shape == (3, 3) + assert isinstance(scan_number, int) + assert isinstance(pt_number, int) + + # Find out the peak workspace + exp_num = self._expNumber + if (exp_num, scan_number, pt_number) in self._myUBPeakWSDict is False: + err_msg = 'No PeakWorkspace is found for exp %d scan %d pt %d' % ( + exp_num, scan_number, pt_number) + return False, err_msg + + peak_ws = self._myUBPeakWSDict[(exp_num, scan_number, pt_number)] + ub_1d = ub_matrix.reshape(9,) + print '[DB] UB matrix = ', ub_1d + + # Set UB + api.SetUB(Workspace=peak_ws, UB=ub_1d) + + # Note: IndexPeaks and CalcualtePeaksHKL do the same job + # while IndexPeaks has more control on the output + num_peak_index, error = api.IndexPeaks(PeaksWorkspace=peak_ws, + Tolerance=0.4, + RoundHKLs=False) + + if num_peak_index == 0: + return False, 'No peak can be indexed.' + elif num_peak_index > 1: + raise RuntimeError('Case for PeaksWorkspace containing more than 1 peak is not ' + 'considered. Contact developer for this issue.') + else: + hkl_v3d = peak_ws.getPeak(0).getHKL() + hkl = [hkl_v3d.X(), hkl_v3d.Y(), hkl_v3d.Z()] + + return True, (hkl, error) + + def load_spice_scan_file(self, exp_no, scan_no, spice_file_name=None): + """ + Load a SPICE scan file to table workspace and run information matrix workspace. + :param scan_no: + :param spice_file_name: + :return: status (boolean), error message (string) + """ + # Default for exp_no + if exp_no is None: + exp_no = self._expNumber + + # Check whether the workspace has been loaded + assert isinstance(exp_no, int) + assert isinstance(scan_no, int) + out_ws_name = get_spice_table_name(exp_no, scan_no) + if (exp_no, scan_no) in self._mySpiceTableDict: + return True, out_ws_name + + # Form standard name for a SPICE file if name is not given + if spice_file_name is None: + spice_file_name = os.path.join(self._dataDir, get_spice_file_name(exp_no, scan_no)) + + # Download SPICE file if necessary + if os.path.exists(spice_file_name) is False: + self.download_spice_file(exp_no, scan_no, over_write=True) + + try: + spice_table_ws, info_matrix_ws = api.LoadSpiceAscii(Filename=spice_file_name, + OutputWorkspace=out_ws_name, + RunInfoWorkspace='TempInfo') + api.DeleteWorkspace(Workspace=info_matrix_ws) + except RuntimeError as run_err: + return False, 'Unable to load SPICE data %s due to %s' % (spice_file_name, str(run_err)) + + # Store + self._add_spice_workspace(exp_no, scan_no, spice_table_ws) + + return True, out_ws_name + + def load_spice_xml_file(self, exp_no, scan_no, pt_no, xml_file_name=None): + """ + Load SPICE's XML file to + :param scan_no: + :param pt_no: + :return: + """ + # Form XMIL file as ~/../HB3A_exp355_scan%04d_%04d.xml'%(scan_no, pt) + if xml_file_name is None: + xml_file_name = os.path.join(self._dataDir, + 'HB3A_exp%d_scan%04d_%04d.xml' % (exp_no, scan_no, pt_no)) + + # Get spice table + spice_table_ws = self._get_spice_workspace(exp_no, scan_no) + assert isinstance(spice_table_ws, mantid.dataobjects.TableWorkspace) + spice_table_name = spice_table_ws.name() + + # Load SPICE Pt. file + # spice_table_name = 'Table_Exp%d_Scan%04d' % (exp_no, scan_no) + pt_ws_name = get_raw_data_workspace_name(exp_no, scan_no, pt_no) + try: + ret_obj = api.LoadSpiceXML2DDet(Filename=xml_file_name, + OutputWorkspace=pt_ws_name, + DetectorGeometry='256,256', + SpiceTableWorkspace=spice_table_name, + PtNumber=pt_no) + except RuntimeError as run_err: + return False, str(run_err) + + pt_ws = ret_obj + + # Add data storage + self._add_raw_workspace(exp_no, scan_no, pt_no, pt_ws) + + return True, pt_ws_name + + def group_workspaces(self, exp_number, group_name): + """ + + :return: + """ + # Find out the input workspace name + ws_names_str = '' + for key in self._myRawDataWSDict.keys(): + if key[0] == exp_number: + ws_names_str += '%s,' % self._myRawDataWSDict[key].name() + + for key in self._mySpiceTableDict.keys(): + if key[0] == exp_number: + ws_names_str += '%s,' % self._mySpiceTableDict[key].name() + + # Check + if len(ws_names_str) == 0: + return False, 'No workspace is found for experiment %d.' % exp_number + + # Remove last ',' + ws_names_str = ws_names_str[:-1] + + # Group + api.GroupWorkspaces(InputWorkspaces=ws_names_str, + OutputWorkspace=group_name) + + return + + def merge_pts_in_scan(self, exp_no, scan_no, target_ws_name, target_frame): + """ + Merge Pts in Scan + All the workspaces generated as internal results will be grouped + :param exp_no: + :param scan_no: + :param target_ws_name: + :param target_frame: + :return: (merged workspace name, workspace group name) + """ + # Check + if exp_no is None: + exp_no = self._expNumber + assert isinstance(exp_no, int) + assert isinstance(scan_no, int) + assert isinstance(target_frame, str) + assert isinstance(target_ws_name, str) + + ub_matrix_1d = None + + # Target frame + if target_frame.lower().startswith('hkl'): + target_frame = 'hkl' + ub_matrix_1d = self._myUBMatrixDict[self._expNumber].reshape(9,) + elif target_frame.lower().startswith('q-sample'): + target_frame = 'qsample' + + else: + raise RuntimeError('Target frame %s is not supported.' % target_frame) + + # Process data and save + status, pt_num_list = self.get_pt_numbers(exp_no, scan_no, True) + if status is False: + err_msg = pt_num_list + return False, err_msg + else: + print '[DB] Number of Pts for Scan %d is %d' % (scan_no, len(pt_num_list)) + print '[DB] Data directory: %s' % self._dataDir + max_pts = 0 + ws_names_str = '' + ws_names_to_group = '' + + for pt in pt_num_list: + try: + self.download_spice_xml_file(scan_no, pt, overwrite=False) + api.CollectHB3AExperimentInfo(ExperimentNumber=exp_no, ScanList='%d' % scan_no, PtLists='-1,%d' % pt, + DataDirectory=self._dataDir, + GenerateVirtualInstrument=False, + OutputWorkspace='ScanPtInfo_Exp%d_Scan%d' % (exp_no, scan_no), + DetectorTableWorkspace='MockDetTable') + + out_q_name = 'HB3A_Exp%d_Scan%d_Pt%d_MD' % (exp_no, scan_no, pt) + api.ConvertCWSDExpToMomentum(InputWorkspace='ScanPtInfo_Exp406_Scan%d' % scan_no, + CreateVirtualInstrument=False, + OutputWorkspace=out_q_name, + Directory=self._dataDir) + + ws_names_to_group += out_q_name + ',' + if target_frame == 'hkl': + out_hkl_name = 'HKL_Scan%d_Pt%d' % (scan_no, pt) + api.ConvertCWSDMDtoHKL(InputWorkspace=out_q_name, + UBMatrix=ub_matrix_1d, + OutputWorkspace=out_hkl_name) + ws_names_str += out_hkl_name + ',' + ws_names_to_group += out_hkl_name + ',' + else: + ws_names_str += out_q_name + ',' + + except RuntimeError as e: + print '[Error] Reducing scan %d pt %d due to %s' % (scan_no, pt, str(e)) + continue + + else: + max_pts = pt + # END-FOR + + # Merge + if target_frame == 'qsample': + out_ws_name = target_ws_name + '_QSample' + elif target_frame == 'hkl': + out_ws_name = target_ws_name + '_HKL' + else: + raise RuntimeError('Impossible to have target frame %s' % target_frame) + + ws_names_str = ws_names_str[:-1] + api.MergeMD(InputWorkspaces=ws_names_str, OutputWorkspace=out_ws_name, SplitInto=max_pts) + + # Group workspaces + group_name = 'Group_Exp406_Scan%d' % scan_no + api.GroupWorkspaces(InputWorkspaces=ws_names_to_group, OutputWorkspace=group_name) + spice_table_name = get_spice_table_name(exp_no, scan_no) + api.GroupWorkspaces(InputWorkspaces='%s,%s' % (group_name, spice_table_name), OutputWorkspace=group_name) + + ret_tup = out_ws_name, group_name + + return ret_tup + + def set_server_url(self, server_url): + """ + Set URL for server to download the data + :param server_url: + :return: + """ + # Server URL must end with '/' + self._myServerURL = str(server_url) + if self._myServerURL.endswith('/') is False: + self._myServerURL += '/' + + # Test URL valid or not + is_url_good = False + error_message = None + try: + result = urllib2.urlopen(self._myServerURL) + except urllib2.HTTPError, err: + error_message = str(err.code) + except urllib2.URLError, err: + error_message = str(err.args) + else: + is_url_good = True + result.close() + + if error_message is None: + error_message = '' + else: + error_message = 'Unable to open data server URL: %s due to %s.' % (server_url, error_message) + + return is_url_good, error_message + + def setWebAccessMode(self, mode): + """ + Set data access mode form server + :param mode: + :return: + """ + if isinstance(mode, str) is False: + raise RuntimeError('Input mode is not string') + + if mode == 'cache': + self._cacheDataOnly = True + elif mode == 'download': + self._cacheDataOnly = False + + return + + def set_local_data_dir(self, local_dir): + """ + Set local data storage + :param local_dir: + :return: + """ + # Get absolute path + if os.path.isabs(local_dir) is False: + # Input is relative path to current working directory + cwd = os.getcwd() + local_dir = os.path.join(cwd, local_dir) + + # Create cache directory if necessary + if os.path.exists(local_dir) is False: + try: + os.mkdir(local_dir) + except OSError as os_err: + return False, str(os_err) + + # Check whether the target is writable + if os.access(local_dir, os.W_OK) is False: + return False, 'Specified local data directory %s is not writable.' % local_dir + + # Successful + self._dataDir = local_dir + + return True, '' + + def set_ub_matrix(self, exp_number, ub_matrix): + """ + Set up UB matrix to _UBMatrix dictionary + :param exp_number: + :param ub_matrix: + :return: + """ + # Check + if exp_number is None: + exp_number = self._expNumber + + assert isinstance(exp_number, int) + assert isinstance(ub_matrix, numpy.ndarray) + assert ub_matrix.shape == (3, 3) + + # Set up + self._myUBMatrixDict[exp_number] = ub_matrix + + def set_working_directory(self, work_dir): + """ + Set up the directory for working result + :return: (boolean, string) + """ + if os.path.exists(work_dir) is False: + try: + os.mkdir(work_dir) + except OSError as os_err: + return False, 'Unable to create working directory %s due to %s.' % (work_dir, str(os_err)) + elif os.access(work_dir, os.W_OK) is False: + return False, 'User specified working directory %s is not writable.' % work_dir + + self._workDir = work_dir + + return True, '' + + def set_instrument_name(self, instrument_name): + """ + Set instrument name + :param instrument_name: + :return: + """ + # Check + if isinstance(instrument_name, str) is False: + return False, 'Input instrument name is not a string but of type %s.' % str(type(instrument_name)) + if len(instrument_name) == 0: + return False, 'Input instrument name is an empty string.' + + self._instrumentName = instrument_name + + return True, '' + + def set_exp_number(self, exp_number): + """ Add experiment number + :param exp_number: + :return: + """ + assert isinstance(exp_number, int) + self._expNumber = exp_number + + return True + + def set_hkl_to_peak(self, exp_number, scan_number, pt_number): + """ + Get HKL as _h, _k, _l from MDEventWorkspace. It is for HB3A only + :return: + """ + status, peak_info = self.get_peak_info(exp_number, scan_number, pt_number) + if status is False: + err_msg = peak_info + return False, err_msg + + md_ws = self._myPtMDDict[(exp_number, scan_number, pt_number)] + assert md_ws.getNumExperimentInfo() == 1 + exp_info = md_ws.getExperimentInfo(0) + + try: + m_h = float(exp_info.run().getProperty('_h').value) + m_k = float(exp_info.run().getProperty('_k').value) + m_l = float(exp_info.run().getProperty('_l').value) + except RuntimeError as error: + return False, 'Unable to retrieve HKL due to %s.' % (str(error)) + + peak_ws = peak_info.get_peak_workspace() + peak = peak_ws.getPeak(0) + peak.setHKL(m_h, m_k, m_l) + + return True, (m_h, m_k, m_l) + + def _add_raw_workspace(self, exp_no, scan_no, pt_no, raw_ws): + """ Add raw Pt.'s workspace + :param exp_no: + :param scan_no: + :param pt_no: + :param raw_ws: workspace or name of the workspace + :return: None + """ + # Check + assert isinstance(exp_no, int) + assert isinstance(scan_no, int) + assert isinstance(pt_no, int) + + if isinstance(raw_ws, str): + # Given by name + matrix_ws = AnalysisDataService.retrieve(raw_ws) + else: + matrix_ws = raw_ws + assert isinstance(matrix_ws, mantid.dataobjects.Workspace2D) + + self._myRawDataWSDict[(exp_no, scan_no, pt_no)] = matrix_ws + + return + + def _add_md_workspace(self, exp_no, scan_no, pt_no, md_ws): + """ + Add MD workspace to storage + :param exp_no: + :param scan_no: + :param pt_no: + :param md_ws: + :return: + """ + # Check input + print '[DB] Type of md_ws is %s.' % str(type(md_ws)) + assert isinstance(md_ws, mantid.dataobjects.MDEventWorkspace) + + assert isinstance(exp_no, int) + assert isinstance(scan_no, int) + assert isinstance(pt_no) + + self._myPtMDDict[(exp_no, scan_no, pt_no)] = md_ws + + return + + def _add_ub_peak_ws(self, exp_number, scan_number, pt_number, peak_ws): + """ + Add peak workspace for UB matrix + :param exp_number: + :param scan_number: + :param pt_number: + :param peak_ws: + :return: + """ + # Check + assert isinstance(peak_ws, mantid.dataobjects.PeaksWorkspace) + + assert isinstance(exp_number, int) + assert isinstance(scan_number, int) + assert isinstance(pt_number, int) + + # Add + self._myUBPeakWSDict[(exp_number, scan_number, pt_number)] = peak_ws + + return + + def _add_spice_workspace(self, exp_no, scan_no, spice_table_ws): + """ + """ + assert isinstance(exp_no, int) + assert isinstance(scan_no, int) + assert isinstance(spice_table_ws, mantid.dataobjects.TableWorkspace) + self._mySpiceTableDict[(exp_no, scan_no)] = spice_table_ws + + return + + def _get_spice_workspace(self, exp_no, scan_no): + """ Get SPICE's scan table workspace + :param exp_no: + :param scan_no: + :return: Table workspace or None + """ + try: + ws = self._mySpiceTableDict[(exp_no, scan_no)] + except KeyError: + print '[DB] Keys to SPICE TABLE: %s' % str(self._mySpiceTableDict.keys()) + return None + + return ws + + def get_raw_data_workspace(self, exp_no, scan_no, pt_no): + """ Get raw workspace + """ + try: + ws = self._myRawDataWSDict[(exp_no, scan_no, pt_no)] + assert isinstance(ws, mantid.dataobjects.Workspace2D) + except KeyError: + return None + + return ws + + def _get_pt_list_from_spice_table(self, spice_table_ws): + """ + Get list of Pt. from a SPICE table workspace + :param spice_table_ws: SPICE table workspace + :return: list of Pt. + """ + numrows = spice_table_ws.rowCount() + ptlist = [] + for irow in xrange(numrows): + ptno = int(spice_table_ws.cell(irow, 0)) + ptlist.append(ptno) + + return ptlist + + +def get_spice_file_name(exp_number, scan_number): + """ + Get standard HB3A SPICE file name from experiment number and scan number + :param exp_number: + :param scan_num: + :return: + """ + file_name = 'HB3A_exp%04d_scan%04d.dat' % (exp_number, scan_number) + + return file_name + + +def get_spice_table_name(exp_number, scan_number): + """ Form the name of the table workspace for SPICE + :param exp_number: + :param scan_number: + :return: + """ + table_name = 'HB3A_%03d_%04d_SpiceTable' % (exp_number, scan_number) + + return table_name + + +def get_raw_data_workspace_name(exp_number, scan_number, pt_number): + """ Form the name of the matrix workspace to which raw pt. XML file is loaded + :param exp_number: + :param scan_number: + :param pt_number: + :return: + """ + ws_name = 'HB3A_exp%d_scan%04d_%04d' % (exp_number, scan_number, pt_number) + + return ws_name + + +def get_pt_info_ws_name(exp_number, scan_number): + """ + Information table workspace'name from CollectHB3AInfo + :param exp_number: + :param scan_number: + :param pt_number: + :return: + """ + ws_name = 'ScanPtInfo_Exp%d_Scan%d' % (exp_number, scan_number) + + return ws_name + + +def get_single_pt_peak_ws_name(exp_number, scan_number, pt_number): + """ + Form the name of the peak workspace + :param exp_number: + :param scan_number: + :param pt_number: + :return: + """ + ws_name = 'Peak_Exp%d_Scan%d_Pt%d' % (exp_number, scan_number, pt_number) + + return ws_name + + +def get_single_pt_md_name(exp_number, scan_number, pt_number): + """ Form the name of the MDEvnetWorkspace for a single Pt. measurement + :param exp_number: + :param scan_number: + :param pt_number: + :return: + """ + ws_name = 'HB3A_Exp%d_Scan%d_Pt%d_MD' % (exp_number, scan_number, pt_number) + + return ws_name + + +def get_virtual_instrument_table_name(exp_number, scan_number, pt_number): + """ + Generate the name of the table workspace containing the virtual instrument information + :param exp_number: + :param scan_number: + :param pt_number: + :return: + """ + ws_name = 'VirtualInstrument_Exp%d_Scan%d_Pt%d_Table' % (exp_number, scan_number, pt_number) + + return ws_name diff --git a/scripts/HFIR_4Circle_Reduction/reduce4circleGUI.py b/scripts/HFIR_4Circle_Reduction/reduce4circleGUI.py new file mode 100644 index 0000000000000000000000000000000000000000..7009c1e8b8ec763ec515120f212242332cf5e2b9 --- /dev/null +++ b/scripts/HFIR_4Circle_Reduction/reduce4circleGUI.py @@ -0,0 +1,1092 @@ +#pylint: disable=invalid-name,relative-import,W0611,R0921,R0902,R0904,R0921,C0302 +################################################################################ +# +# MainWindow application for reducing HFIR 4-circle +# +################################################################################ +import os +import math +import csv +import time + +from PyQt4 import QtCore, QtGui + +import reduce4circleControl as r4c +import guiutility as gutil +import fourcircle_utility as fcutil + +try: + _fromUtf8 = QtCore.QString.fromUtf8 +except AttributeError: + def _fromUtf8(s): + return s + +# import line for the UI python class +from ui_MainWindow import Ui_MainWindow + + +class MainWindow(QtGui.QMainWindow): + """ Class of Main Window (top) + """ + def __init__(self, parent=None): + """ Initialization and set up + """ + # Base class + QtGui.QMainWindow.__init__(self,parent) + + # UI Window (from Qt Designer) + self.ui = Ui_MainWindow() + self.ui.setupUi(self) + + # Mantid configuration + self._instrument = str(self.ui.comboBox_instrument.currentText()) + # config = ConfigService.Instance() + # self._instrument = config["default.instrument"] + + # Event handling definitions + # Top + self.connect(self.ui.pushButton_setExp, QtCore.SIGNAL('clicked()'), + self.do_set_experiment) + + # Tab 'Data Access' + self.connect(self.ui.pushButton_applySetup, QtCore.SIGNAL('clicked()'), + self.do_apply_setup) + self.connect(self.ui.pushButton_browseLocalDataDir, QtCore.SIGNAL('clicked()'), + self.do_browse_local_spice_data) + self.connect(self.ui.pushButton_testURLs, QtCore.SIGNAL('clicked()'), + self.do_test_url) + self.connect(self.ui.pushButton_ListScans, QtCore.SIGNAL('clicked()'), + self.do_list_scans) + self.connect(self.ui.pushButton_downloadExpData, QtCore.SIGNAL('clicked()'), + self.do_download_spice_data) + self.connect(self.ui.comboBox_mode, QtCore.SIGNAL('currentIndexChanged(int)'), + self.change_data_access_mode) + + # Tab 'View Raw Data' + self.connect(self.ui.pushButton_setScanInfo, QtCore.SIGNAL('clicked()'), + self.do_load_scan_info) + self.connect(self.ui.pushButton_plotRawPt, QtCore.SIGNAL('clicked()'), + self.do_plot_pt_raw) + self.connect(self.ui.pushButton_prevPtNumber, QtCore.SIGNAL('clicked()'), + self.do_plot_prev_pt_raw) + self.connect(self.ui.pushButton_nextPtNumber, QtCore.SIGNAL('clicked()'), + self.do_plot_next_pt_raw) + self.connect(self.ui.pushButton_showPtList, QtCore.SIGNAL('clicked()'), + self.show_scan_pt_list) + self.connect(self.ui.pushButton_usePt4UB, QtCore.SIGNAL('clicked()'), + self.do_add_peak_to_find) + + # Tab 'calculate ub matrix' + self.connect(self.ui.pushButton_findPeak, QtCore.SIGNAL('clicked()'), + self.do_find_peak) + self.connect(self.ui.pushButton_addPeakToCalUB, QtCore.SIGNAL('clicked()'), + self.do_add_ub_peak) + self.connect(self.ui.pushButton_calUB, QtCore.SIGNAL('clicked()'), + self.do_cal_ub_matrix) + self.connect(self.ui.pushButton_acceptUB, QtCore.SIGNAL('clicked()'), + self.doAcceptCalUB) + self.connect(self.ui.pushButton_indexUBPeaks, QtCore.SIGNAL('clicked()'), + self.do_index_ub_peaks) + self.connect(self.ui.pushButton_deleteUBPeak, QtCore.SIGNAL('clicked()'), + self.do_del_ub_peaks) + self.connect(self.ui.pushButton_clearUBPeakTable, QtCore.SIGNAL('clicked()'), + self.do_clear_ub_peaks) + self.connect(self.ui.pushButton_resetPeakHKLs, QtCore.SIGNAL('clicked()'), + self.do_reset_ub_peaks_hkl) + + # Tab 'Slice View' + self.connect(self.ui.pushButton_setUBSliceView, QtCore.SIGNAL('clicked()'), + self.do_set_ub_sv) + self.connect(self.ui.pushButton_process4SliceView, QtCore.SIGNAL('clicked()'), + self.do_merge_scans) + + # Tab 'Advanced' + self.connect(self.ui.pushButton_useDefaultDir, QtCore.SIGNAL('clicked()'), + self.do_setup_dir_default) + self.connect(self.ui.pushButton_browseLocalCache, QtCore.SIGNAL('clicked()'), + self.do_browse_local_cache_dir) + self.connect(self.ui.pushButton_browseWorkDir, QtCore.SIGNAL('clicked()'), + self.do_browse_working_dir) + self.connect(self.ui.comboBox_instrument, QtCore.SIGNAL('currentIndexChanged(int)'), + self.change_instrument_name) + + # Refine UB matrix + self.connect(self.ui.pushButton_addToRefine, QtCore.SIGNAL('clicked()'), + self.do_refine_ub) + self.connect(self.ui.pushButton_addAllRefineUB, QtCore.SIGNAL('clicked()'), + self.do_refine_ub) + self.connect(self.ui.pushButton_acceptRefinedUB, QtCore.SIGNAL('clicked()'), + self.do_refine_ub) + self.connect(self.ui.pushButton_resetRefinedUB, QtCore.SIGNAL('clicked()'), + self.do_refine_ub) + + # Tab 'Integrate Peaks' + self.connect(self.ui.pushButton_integratePeak, QtCore.SIGNAL('clicked()'), + self.do_integrate_peaks) + + # Menu + self.connect(self.ui.actionExit, QtCore.SIGNAL('triggered()'), + self.menu_quit) + + self.connect(self.ui.actionSave_Session, QtCore.SIGNAL('triggered()'), + self.save_current_session) + self.connect(self.ui.actionLoad_Session, QtCore.SIGNAL('triggered()'), + self.load_session) + + # Event handling for tab 'refine ub matrix' + self.connect(self.ui.pushButton_addToRefine, QtCore.SIGNAL('clicked()'), + self.doAddScanPtToRefineUB) + + # Validator ... (NEXT) + + # Declaration of class variable + # some configuration + self._homeSrcDir = os.getcwd() + self._homeDir = os.getcwd() + + # Control + self._myControl = r4c.CWSCDReductionControl(self._instrument) + self._allowDownload = True + self._dataAccessMode = 'Download' + + # Initial setup + self.ui.tabWidget.setCurrentIndex(0) + self.ui.tabWidget.setTabEnabled(4, False) + self.ui.tabWidget.setTabEnabled(5, False) + self._init_ub_table() + self.ui.radioButton_ubFromTab1.setChecked(True) + + # Tab 'Access' + self.ui.lineEdit_url.setText('http://neutron.ornl.gov/user_data/hb3a/') + self.ui.comboBox_mode.setCurrentIndex(0) + self.ui.lineEdit_localSpiceDir.setEnabled(True) + self.ui.pushButton_browseLocalDataDir.setEnabled(True) + + return + + def do_integrate_peaks(self): + """ + + :return: + """ + raise RuntimeError('ASAP') + + def do_refine_ub(self): + """ + + :return: + """ + raise RuntimeError('Next Release') + + def _init_ub_table(self): + """ DOC + :return: + """ + # UB-peak table + # NOTE: have to call this because pyqt set column and row to 0 after __init__ + # thus a 2-step initialization has to been adopted + self.ui.tableWidget_peaksCalUB.setup() + + self.ui.tableWidget_ubMatrix.setup() + self.ui.tableWidget_ubSiceView.setup() + self.ui.tableWidget_refinedUB.setup() + + self.ui.tableWidget_sliceViewProgress.setup() + + return + + def change_data_access_mode(self): + """ Change data access mode between downloading from server and local + Event handling methods + :return: + """ + new_mode = str(self.ui.comboBox_mode.currentText()) + self._dataAccessMode = new_mode + + if new_mode.startswith('Local') is True: + self.ui.lineEdit_localSpiceDir.setEnabled(True) + self.ui.pushButton_browseLocalDataDir.setEnabled(True) + self.ui.lineEdit_url.setEnabled(False) + self.ui.lineEdit_localSrcDir.setEnabled(False) + self.ui.pushButton_browseLocalCache.setEnabled(False) + self._allowDownload = False + else: + self.ui.lineEdit_localSpiceDir.setEnabled(False) + self.ui.pushButton_browseLocalDataDir.setEnabled(False) + self.ui.lineEdit_url.setEnabled(True) + self.ui.lineEdit_localSrcDir.setEnabled(True) + self.ui.pushButton_browseLocalCache.setEnabled(True) + self._allowDownload = True + + return + + def change_instrument_name(self): + """ Handing the event as the instrument name is changed + :return: + """ + new_instrument = str(self.ui.comboBox_instrument.currentText()) + self.pop_one_button_dialog('Change of instrument during data processing is dangerous.') + status, error_message = self._myControl.set_instrument_name(new_instrument) + if status is False: + self.pop_one_button_dialog(error_message) + + return + + def do_add_ub_peak(self): + """ Add current to ub peaks + :return: + """ + # Add peak + status, int_list = gutil.parse_integers_editors([self.ui.lineEdit_exp, + self.ui.lineEdit_scanNumber, + self.ui.lineEdit_ptNumber]) + if status is False: + self.pop_one_button_dialog(int_list) + exp_no, scan_no, pt_no = int_list + + # Get HKL from GUI + status, float_list = gutil.parse_float_editors([self.ui.lineEdit_H, + self.ui.lineEdit_K, + self.ui.lineEdit_L]) + if status is False: + err_msg = float_list + self.pop_one_button_dialog(err_msg) + return + h, k, l = float_list + + status, peak_info_obj = self._myControl.get_peak_info(exp_no, scan_no, pt_no) + if status is False: + error_message = peak_info_obj + self.pop_one_button_dialog(error_message) + return + assert isinstance(peak_info_obj, r4c.PeakInfo) + + if self.ui.checkBox_roundHKLInt.isChecked(): + h = math.copysign(1, h)*int(abs(h)+0.5) + k = math.copysign(1, k)*int(abs(k)+0.5) + l = math.copysign(1, l)*int(abs(l)+0.5) + peak_info_obj.set_user_hkl(h, k, l) + self.set_ub_peak_table(peak_info_obj) + + # Clear + self.ui.lineEdit_scanNumber.setText('') + self.ui.lineEdit_ptNumber.setText('') + + self.ui.lineEdit_sampleQx.setText('') + self.ui.lineEdit_sampleQy.setText('') + self.ui.lineEdit_sampleQz.setText('') + + self.ui.lineEdit_H.setText('') + self.ui.lineEdit_K.setText('') + self.ui.lineEdit_L.setText('') + + return + + def doAcceptCalUB(self): + """ Accept the calculated UB matrix + """ + raise RuntimeError('ASAP') + return + + def doAddScanPtToRefineUB(self): + """ Add scan/pt numbers to the list of data points for refining ub matrix + + And the added scan number and pt numbers will be reflected in the (left sidebar) + + """ + raise RuntimeError("ASAP") + + def do_add_peak_to_find(self): + """ + Add the scan/pt to the next + :return: + """ + scan_no = self.ui.lineEdit_run.text() + pt_no = self.ui.lineEdit_rawDataPtNo.text() + + self.ui.lineEdit_scanNumber.setText(scan_no) + self.ui.lineEdit_ptNumber.setText(pt_no) + + self.ui.tabWidget.setCurrentIndex(2) + + def do_browse_local_cache_dir(self): + """ Browse local cache directory + :return: + """ + local_cache_dir = str(QtGui.QFileDialog.getExistingDirectory(self, + 'Get Local Cache Directory', + self._homeSrcDir)) + + # Set local directory to control + status, error_message = self._myControl.set_local_data_dir(local_cache_dir) + if status is False: + self.pop_one_button_dialog(error_message) + return + + # Synchronize to local data/spice directory and local cache directory + if str(self.ui.lineEdit_localSpiceDir.text()) != '': + prev_dir = str(self.ui.lineEdit_localSrcDir.text()) + self.pop_one_button_dialog('Local data directory was set up as %s' % + prev_dir) + self.ui.lineEdit_localSrcDir.setText(local_cache_dir) + self.ui.lineEdit_localSpiceDir.setText(local_cache_dir) + + return + + def do_browse_local_spice_data(self): + """ Browse local source SPICE data directory + """ + src_spice_dir = str(QtGui.QFileDialog.getExistingDirectory(self, 'Get Directory', + self._homeSrcDir)) + # Set local data directory to controller + status, error_message = self._myControl.set_local_data_dir(src_spice_dir) + if status is False: + self.pop_one_button_dialog(error_message) + return + + self._homeSrcDir = src_spice_dir + self.ui.lineEdit_localSpiceDir.setText(src_spice_dir) + + return + + def do_browse_working_dir(self): + """ + Browse and set up working directory + :return: + """ + work_dir = str(QtGui.QFileDialog.getExistingDirectory(self, 'Get Working Directory', self._homeDir)) + status, error_message = self._myControl.set_working_directory(work_dir) + if status is False: + self.pop_one_button_dialog(error_message) + else: + self.ui.lineEdit_workDir.setText(work_dir) + + return + + def do_cal_ub_matrix(self): + """ Calculate UB matrix by 2 or 3 reflections + """ + # Get reflections + num_rows = self.ui.tableWidget_peaksCalUB.rowCount() + peak_info_list = list() + status, exp_number = gutil.parse_integers_editors(self.ui.lineEdit_exp) + for i_row in xrange(num_rows): + if self.ui.tableWidget_peaksCalUB.is_selected(i_row) is True: + scan_num, pt_num = self.ui.tableWidget_peaksCalUB.get_exp_info(i_row) + status, peak_info = self._myControl.get_peak_info(exp_number, scan_num, pt_num) + peak_info.set_peak_ws_hkl_from_user() + if status is False: + self.pop_one_button_dialog(peak_info) + return + assert isinstance(peak_info, r4c.PeakInfo) + peak_info_list.append(peak_info) + # END-FOR + + # Get lattice + status, ret_obj = self._get_lattice_parameters() + if status is True: + a, b, c, alpha, beta, gamma = ret_obj + else: + err_msg = ret_obj + self.pop_one_button_dialog(err_msg) + return + + # Calculate UB matrix + status, ub_matrix = self._myControl.calculate_ub_matrix(peak_info_list, a, b, c, + alpha, beta, gamma) + + # Deal with result + if status is True: + self._show_ub_matrix(ub_matrix) + else: + err_msg = ub_matrix + self.pop_one_button_dialog(err_msg) + + return + + def do_clear_ub_peaks(self): + """ + Clear all peaks in UB-Peak table + :return: + """ + self.ui.tableWidget_peaksCalUB.clear() + + return + + def do_del_ub_peaks(self): + """ + Delete a peak in UB-Peak table + :return: + """ + # Find out the lines to get deleted + row_num_list = self.ui.tableWidget_peaksCalUB.get_selected_rows() + print '[DB] Row %s are selected' % str(row_num_list) + + # Delete + self.ui.tableWidget_peaksCalUB.delete_rows(row_num_list) + + return + + def do_download_spice_data(self): + """ Download SPICE data + :return: + """ + # Check scans to download + scan_list_str = str(self.ui.lineEdit_downloadScans.text()) + if len(scan_list_str) > 0: + # user specifies scans to download + valid, scan_list = fcutil.parse_int_array(scan_list_str) + if valid is False: + error_message = scan_list + self.pop_one_button_dialog(error_message) + else: + # Get all scans + status, ret_obj = gutil.parse_integers_editors([self.ui.lineEdit_exp]) + if status is False: + self.pop_one_button_dialog(ret_obj) + return + exp_no = ret_obj + assert isinstance(exp_no, int) + server_url = str(self.ui.lineEdit_url.text()) + scan_list = fcutil.get_scans_list(server_url, exp_no, return_list=True) + self.pop_one_button_dialog('Going to download scans %s.' % str(scan_list)) + + # Check location + destination_dir = str(self.ui.lineEdit_localSrcDir.text()) + status, error_message = self._myControl.set_local_data_dir(destination_dir) + if status is False: + self.pop_one_button_dialog(error_message) + else: + self.pop_one_button_dialog('Spice files will be downloaded to %s.' % destination_dir) + + # Set up myControl for downloading data + exp_no = int(self.ui.lineEdit_exp.text()) + self._myControl.set_exp_number(exp_no) + + server_url = str(self.ui.lineEdit_url.text()) + status, error_message = self._myControl.set_server_url(server_url) + if status is False: + self.pop_one_button_dialog(error_message) + return + + # Download + self._myControl.download_data_set(scan_list) + + return + + def do_find_peak(self): + """ Find peak in a given scan/pt and record it + """ + # Get experiment, scan and pt + status, ret_obj = gutil.parse_integers_editors([self.ui.lineEdit_exp, + self.ui.lineEdit_scanNumber, + self.ui.lineEdit_ptNumber]) + if status is True: + exp_no, scan_no, pt_no = ret_obj + else: + self.pop_one_button_dialog(ret_obj) + return + + # Find peak + status, err_msg = self._myControl.find_peak(exp_no, scan_no, pt_no) + if status is False: + self.pop_one_button_dialog(ret_obj) + return + if self.ui.checkBox_loadHKLfromFile.isChecked() is True: + # This is the first time that in the workflow to get HKL from MD workspace + status, err_msg = self._myControl.set_hkl_to_peak(exp_no, scan_no, pt_no) + if status is False: + self.pop_one_button_dialog('Unable to locate peak info due to %s.' % err_msg) + + # Set up correct values to table tableWidget_peaksCalUB + self._myControl.add_peak_info(exp_no, scan_no, pt_no) + status, peak_info = self._myControl.get_peak_info(exp_no, scan_no, pt_no) + if status is False: + err_msg = peak_info + raise KeyError(err_msg) + assert isinstance(peak_info, r4c.PeakInfo) + + # Set the HKL value from PeakInfo directly + # BAD PROGRAMMING! THERE ARE TOO MANY WAYS TO ACCESS STORED HKL + h, k, l = peak_info.get_peak_ws_hkl() + self.ui.lineEdit_H.setText('%.2f' % h) + self.ui.lineEdit_K.setText('%.2f' % k) + self.ui.lineEdit_L.setText('%.2f' % l) + + q_sample = peak_info.getQSample() + self.ui.lineEdit_sampleQx.setText('%.5E' % q_sample[0]) + self.ui.lineEdit_sampleQy.setText('%.5E' % q_sample[1]) + self.ui.lineEdit_sampleQz.setText('%.5E' % q_sample[2]) + + # self.set_ub_peak_table(peak_info) + + return + + def do_index_ub_peaks(self): + """ Index the peaks in the UB matrix peak table + :return: + """ + # Get UB matrix + ub_matrix = self.ui.tableWidget_ubMatrix.get_matrix() + print '[DB] Get UB matrix ', ub_matrix + + # Do it for each peak + num_peaks = self.ui.tableWidget_peaksCalUB.rowCount() + err_msg = '' + for i_peak in xrange(num_peaks): + scan_no, pt_no = self.ui.tableWidget_peaksCalUB.get_exp_info(i_peak) + status, ret_obj = self._myControl.index_peak(ub_matrix, scan_number=scan_no, + pt_number=pt_no) + if status is True: + new_hkl = ret_obj[0] + error = ret_obj[1] + self.ui.tableWidget_peaksCalUB.set_hkl(i_peak, new_hkl, error) + else: + err_msg += ret_obj + '\n' + # END-FOR + + if len(err_msg) > 0: + self.pop_one_button_dialog(err_msg) + + return + + def do_list_scans(self): + """ List all scans available + :return: + """ + # Experiment number + exp_no = int(self.ui.lineEdit_exp.text()) + + access_mode = str(self.ui.comboBox_mode.currentText()) + if access_mode == 'Local': + spice_dir = str(self.ui.lineEdit_localSpiceDir.text()) + message = fcutil.get_scans_list_local_disk(spice_dir, exp_no) + else: + url = str(self.ui.lineEdit_url.text()) + message = fcutil.get_scans_list(url, exp_no) + + self.pop_one_button_dialog(message) + + return + + def do_load_scan_info(self): + """ Load SIICE's scan file + :return: + """ + # Get scan number + status, ret_obj = gutil.parse_integers_editors([self.ui.lineEdit_run]) + if status is True: + scan_no = ret_obj[0] + else: + err_msg = ret_obj + self.pop_one_button_dialog('Unable to get scan number in raw data tab due to %s.' % err_msg) + return + + status, err_msg = self._myControl.load_spice_scan_file(exp_no=None, scan_no=scan_no) + if status is False: + self.pop_one_button_dialog(err_msg) + + return + + def do_plot_pt_raw(self): + """ Plot the Pt. + """ + # Get measurement pt and the file number + status, ret_obj = gutil.parse_integers_editors([self.ui.lineEdit_exp, + self.ui.lineEdit_run, + self.ui.lineEdit_rawDataPtNo]) + if status is True: + exp_no = ret_obj[0] + scan_no = ret_obj[1] + pt_no = ret_obj[2] + else: + self.pop_one_button_dialog(ret_obj) + return + + # Call to plot 2D + self._plot_raw_xml_2d(exp_no, scan_no, pt_no) + + return + + def do_plot_prev_pt_raw(self): + """ Plot the Pt. + """ + # Get measurement pt and the file number + status, ret_obj = gutil.parse_integers_editors([self.ui.lineEdit_exp, + self.ui.lineEdit_run, + self.ui.lineEdit_rawDataPtNo]) + if status is True: + exp_no = ret_obj[0] + scan_no = ret_obj[1] + pt_no = ret_obj[2] + else: + self.pop_one_button_dialog(ret_obj) + return + + # Previous one + pt_no -= 1 + if pt_no <= 0: + self.pop_one_button_dialog('Pt. = 1 is the first one.') + return + else: + self.ui.lineEdit_rawDataPtNo.setText('%d' % pt_no) + + # Plot + self._plot_raw_xml_2d(exp_no, scan_no, pt_no) + + return + + def do_plot_next_pt_raw(self): + """ Plot the Pt. + """ + # Get measurement pt and the file number + status, ret_obj = gutil.parse_integers_editors([self.ui.lineEdit_exp, + self.ui.lineEdit_run, + self.ui.lineEdit_rawDataPtNo]) + if status is True: + exp_no = ret_obj[0] + scan_no = ret_obj[1] + pt_no = ret_obj[2] + else: + self.pop_one_button_dialog(ret_obj) + return + + # Previous one + pt_no += 1 + # get last Pt. number + status, last_pt_no = self._myControl.get_pt_numbers(exp_no, scan_no) + if status is False: + error_message = last_pt_no + self.pop_one_button_dialog('Unable to access Spice table for scan %d. Reason" %s.' % ( + scan_no, error_message)) + if pt_no > last_pt_no: + self.pop_one_button_dialog('Pt. = %d is the last one of scan %d.' % (pt_no, scan_no)) + return + else: + self.ui.lineEdit_rawDataPtNo.setText('%d' % pt_no) + + # Plot + self._plot_raw_xml_2d(exp_no, scan_no, pt_no) + + return + + def do_merge_scans(self): + """ Process data for slicing view + :return: + """ + # Get UB matrix + ub_matrix = self.ui.tableWidget_ubSiceView.get_matrix() + self._myControl.set_ub_matrix(exp_number=None, ub_matrix=ub_matrix) + + # Get list of scans + scan_list = gutil.parse_integer_list(str(self.ui.lineEdit_listScansSliceView.text())) + if len(scan_list) == 0: + self.pop_one_button_dialog('Scan list is empty.') + + # Set table + self.ui.tableWidget_sliceViewProgress.append_scans(scans=scan_list) + + # Warning + self.pop_one_button_dialog('Data processing is long. Be patient!') + + # Process + base_name = str(self.ui.lineEdit_baseMergeMDName.text()) + scan_list.sort() + frame = str(self.ui.comboBox_mergeScanFrame.currentText()) + for scan_no in scan_list: + # Download/check SPICE file + self._myControl.download_spice_file(None, scan_no, over_write=False) + + # Get some information + status, pt_list = self._myControl.get_pt_numbers(None, scan_no, load_spice_scan=True) + if status is False: + err_msg = pt_list + self.pop_one_button_dialog('Failed to get Pt. number: %s' % err_msg) + return + else: + # Set information to table + err_msg = self.ui.tableWidget_sliceViewProgress.set_scan_pt(scan_no, pt_list) + if len(err_msg) > 0: + self.pop_one_button_dialog(err_msg) + + out_ws_name = base_name + '%04d' % scan_no + self.ui.tableWidget_sliceViewProgress.set_scan_pt(scan_no, 'In Processing') + try: + ret_tup = self._myControl.merge_pts_in_scan(exp_no=None, scan_no=scan_no, + target_ws_name=out_ws_name, + target_frame=frame) + merge_status = 'Done' + merged_name = ret_tup[0] + group_name = ret_tup[1] + except RuntimeError as e: + merge_status = 'Failed. Reason: %s' % str(e) + merged_name = '' + group_name = '' + finally: + self.ui.tableWidget_sliceViewProgress.set_status(scan_no, merge_status) + self.ui.tableWidget_sliceViewProgress.set_ws_names(scan_no, merged_name, group_name) + + # Sleep for a while + time.sleep(0.1) + # END-FOR + + return + + def do_reset_ub_peaks_hkl(self): + """ + Reset user specified HKL value to peak table + :return: + """ + num_rows = self.ui.tableWidget_peaksCalUB.rowCount() + for i_row in xrange(num_rows): + print '[DB] Update row %d' % (i_row) + scan, pt = self.ui.tableWidget_peaksCalUB.get_scan_pt(i_row) + status, peak_info = self._myControl.get_peak_info(None, scan, pt) + if status is False: + error_message = peak_info + raise RuntimeError(error_message) + h, k, l = peak_info.get_user_hkl() + self.ui.tableWidget_peaksCalUB.update_hkl(i_row, h, k, l) + # END-FOR + + return + + def do_set_experiment(self): + """ Set experiment + :return: + """ + status, ret_obj = gutil.parse_integers_editors([self.ui.lineEdit_exp]) + if status is True: + exp_number = ret_obj[0] + curr_exp_number = self._myControl.get_experiment() + if curr_exp_number is not None and exp_number != curr_exp_number: + self.pop_one_button_dialog('Changing experiment to %d. Clean previous experiment %d\'s result' + ' in Mantid manually.' % (exp_number, curr_exp_number)) + self._myControl.set_exp_number(exp_number) + self.ui.lineEdit_exp.setStyleSheet('color: black') + else: + err_msg = ret_obj + self.pop_one_button_dialog('Unable to set experiment as %s' % err_msg) + self.ui.lineEdit_exp.setStyleSheet('color: red') + + self.ui.tabWidget.setCurrentIndex(0) + + return + + def do_set_ub_sv(self): + """ Set UB matrix in Slice view + :return: + """ + if self.ui.radioButton_ubFromTab1.isChecked(): + self.ui.tableWidget_ubSiceView.set_from_matrix(self.ui.tableWidget_ubMatrix.get_matrix()) + elif self.ui.radioButton_ubFromTab3.isChecked(): + self.ui.tableWidget_ubSiceView.set_from_matrix(self.ui.tableWidget_refinedUB.get_matrix()) + elif self.ui.radioButton_ubFromList.isChecked(): + status, ret_obj = gutil.parse_float_array(str(self.ui.plainTextEdit_ubInput.toPlainText())) + if status is False: + self.pop_one_button_dialog(ret_obj) + elif len(ret_obj) != 9: + self.pop_one_button_dialog('Requiring 9 floats for UB matrix. Only %d are given.' % len(ret_obj)) + else: + self.ui.tableWidget_ubSiceView.set_from_list(ret_obj) + else: + self.pop_one_button_dialog('None is selected to set UB matrix.') + + return + + def do_setup_dir_default(self): + """ + Set up default directory for storing data and working + :return: + """ + home_dir = os.path.expanduser('~') + + # Data cache directory + data_cache_dir = os.path.join(home_dir, 'Temp/HB3ATest') + self.ui.lineEdit_localSpiceDir.setText(data_cache_dir) + self.ui.lineEdit_localSrcDir.setText(data_cache_dir) + + work_dir = os.path.join(data_cache_dir, 'Workspace') + self.ui.lineEdit_workDir.setText(work_dir) + + return + + def do_apply_setup(self): + """ + Apply set up ... + :return: + """ + # Local data directory + local_data_dir = str(self.ui.lineEdit_localSpiceDir.text()) + if os.path.exists(local_data_dir) is False: + try: + os.mkdir(local_data_dir) + except OSError as os_error: + self.pop_one_button_dialog('Unable to create local data directory %s due to %s.' % ( + local_data_dir, str(os_error))) + self.ui.lineEdit_localSpiceDir.setStyleSheet("color: red;") + return + else: + self.ui.lineEdit_localSpiceDir.setStyleSheet("color: black;") + # END-IF + + # Working directory + working_dir = str(self.ui.lineEdit_workDir.text()) + if os.path.exists(working_dir) is False: + try: + os.mkdir(working_dir) + except OSError as os_error: + self.pop_one_button_dialog('Unable to create working directory %s due to %s.' % ( + working_dir, str(os_error))) + self.ui.lineEdit_workDir.setStyleSheet("color: red;") + return + else: + self.ui.lineEdit_workDir.setStyleSheet("color: black;") + # END-IF + + # Server URL + data_server = str(self.ui.lineEdit_url.text()) + url_is_good = self.do_test_url() + if url_is_good is False: + self.ui.lineEdit_url.setStyleSheet("color: red;") + return + else: + self.ui.lineEdit_url.setStyleSheet("color: black;") + + # Set to control + self._myControl.set_local_data_dir(local_data_dir) + self._myControl.set_working_directory(working_dir) + self._myControl.set_server_url(data_server) + + return + + def do_test_url(self): + """ Test whether the root URL provided specified is good + """ + url = str(self.ui.lineEdit_url.text()) + + url_is_good, err_msg = fcutil.check_url(url) + if url_is_good is True: + self.pop_one_button_dialog("URL %s is valid." % url) + else: + self.pop_one_button_dialog(err_msg) + + return url_is_good + + def pop_one_button_dialog(self, message): + """ Pop up a one-button dialog + :param message: + :return: + """ + assert isinstance(message, str) + QtGui.QMessageBox.information(self, '4-circle Data Reduction', message) + + return + + def save_current_session(self, filename=None): + """ Save current session/value setup to + :return: + """ + # Set up dictionary + save_dict = dict() + + # Setup + save_dict['lineEdit_localSpiceDir'] = str(self.ui.lineEdit_localSpiceDir.text()) + save_dict['lineEdit_url'] = str(self.ui.lineEdit_url.text()) + save_dict['lineEdit_workDir']= str(self.ui.lineEdit_workDir.text()) + + # Experiment + save_dict['lineEdit_exp'] = str(self.ui.lineEdit_exp.text()) + save_dict['lineEdit_scanNumber'] = self.ui.lineEdit_scanNumber.text() + save_dict['lineEdit_ptNumber'] = str(self.ui.lineEdit_ptNumber.text()) + + # Lattice + save_dict['lineEdit_a'] = str(self.ui.lineEdit_a.text()) + save_dict['lineEdit_b'] = str(self.ui.lineEdit_b.text()) + save_dict['lineEdit_c'] = str(self.ui.lineEdit_c.text()) + save_dict['lineEdit_alpha'] = str(self.ui.lineEdit_alpha.text()) + save_dict['lineEdit_beta'] = str(self.ui.lineEdit_beta.text()) + save_dict['lineEdit_gamma'] = str(self.ui.lineEdit_gamma.text()) + + # Merge scan + save_dict['plainTextEdit_ubInput'] = str(self.ui.plainTextEdit_ubInput.toPlainText()) + save_dict['lineEdit_listScansSliceView'] = str(self.ui.lineEdit_listScansSliceView.text()) + save_dict['lineEdit_baseMergeMDName'] = str(self.ui.lineEdit_baseMergeMDName.text()) + + # Save to csv file + if filename is None: + filename = 'session_backup.csv' + ofile = open(filename, 'w') + writer = csv.writer(ofile) + for key, value in save_dict.items(): + writer.writerow([key, value]) + ofile.close() + + return + + def load_session(self, filename=None): + """ + To load a session, i.e., read it back: + :param filename: + :return: + """ + if filename is None: + filename = 'session_backup.csv' + + in_file = open(filename, 'r') + reader = csv.reader(in_file) + my_dict = dict(x for x in reader) + + # ... + for key, value in my_dict.items(): + if key.startswith('lineEdit') is True: + self.ui.__getattribute__(key).setText(value) + elif key.startswith('plainText') is True: + self.ui.__getattribute__(key).setPlainText(value) + elif key.startswith('comboBox') is True: + self.ui.__getattribute__(key).setCurrentIndex(int(value)) + else: + self.pop_one_button_dialog('Error! Widget name %s is not supported' % key) + # END-FOR + + # ... + self._myControl.set_local_data_dir(str(self.ui.lineEdit_localSpiceDir.text())) + + return + + def menu_quit(self): + """ + + :return: + """ + self.close() + + def show_scan_pt_list(self): + """ Show the range of Pt. in a scan + :return: + """ + # Get parameters + status, inp_list = gutil.parse_integers_editors([self.ui.lineEdit_exp, self.ui.lineEdit_run]) + if status is False: + self.pop_one_button_dialog(inp_list) + return + else: + exp_no = inp_list[0] + scan_no = inp_list[1] + + status, ret_obj = self._myControl.get_pt_numbers(exp_no, scan_no) + + # Form message + if status is False: + # Failed to get Pt. list + error_message = ret_obj + self.pop_one_button_dialog(error_message) + else: + # Form message + pt_list = sorted(ret_obj) + num_pts = len(pt_list) + info = 'Exp %d Scan %d has %d Pt. ranging from %d to %d.\n' % (exp_no, scan_no, num_pts, + pt_list[0], pt_list[-1]) + num_miss_pt = pt_list[-1] - pt_list[0] + 1 - num_pts + if num_miss_pt > 0: + info += 'There are %d Pt. skipped.\n' % num_miss_pt + + self.pop_one_button_dialog(info) + + return + + def set_ub_peak_table(self, peakinfo): + """ + DOC + :param peak_info: + :return: + """ + assert isinstance(peakinfo, r4c.PeakInfo) + + # Get data + exp_number, scan_number, pt_number = peakinfo.getExpInfo() + h, k, l = peakinfo.get_user_hkl() + q_sample = peakinfo.getQSample() + m1 = self._myControl.get_sample_log_value(exp_number, scan_number, pt_number, '_m1') + + # Set to table + status, err_msg = self.ui.tableWidget_peaksCalUB.append_row( + [scan_number, pt_number, h, k, l, q_sample[0], q_sample[1], q_sample[2], False, m1, '']) + if status is False: + self.pop_one_button_dialog(err_msg) + + return + + def _get_lattice_parameters(self): + """ + Get lattice parameters from GUI + :return: (Boolean, Object). True, 6-tuple as a, b, c, alpha, beta, gamm + False: error message + """ + status, ret_list = gutil.parse_float_editors([self.ui.lineEdit_a, + self.ui.lineEdit_b, + self.ui.lineEdit_c, + self.ui.lineEdit_alpha, + self.ui.lineEdit_beta, + self.ui.lineEdit_gamma]) + if status is False: + err_msg = ret_list + err_msg = 'Unable to parse unit cell due to %s' % err_msg + return False, err_msg + + a, b, c, alpha, beta, gamma = ret_list + + return True, (a, b, c, alpha, beta, gamma) + + def _plot_raw_xml_2d(self, exp_no, scan_no, pt_no): + """ Plot raw workspace from XML file for a measurement/pt. + """ + # Check and load SPICE table file + does_exist = self._myControl.does_spice_loaded(exp_no, scan_no) + if does_exist is False: + # Download data + status, error_message = self._myControl.download_spice_file(exp_no, scan_no, over_write=False) + if status is True: + status, error_message = self._myControl.load_spice_scan_file(exp_no, scan_no) + if status is False and self._allowDownload is False: + self.pop_one_button_dialog(error_message) + return + else: + self.pop_one_button_dialog(error_message) + return + # END-IF(does_exist) + + # Load Data for Pt's xml file + does_exist = self._myControl.does_raw_loaded(exp_no, scan_no, pt_no) + + if does_exist is False: + # Check whether needs to download + status, error_message = self._myControl.download_spice_xml_file(scan_no, pt_no, exp_no=exp_no) + if status is False: + self.pop_one_button_dialog(error_message) + return + # Load SPICE xml file + status, error_message = self._myControl.load_spice_xml_file(exp_no, scan_no, pt_no) + if status is False: + self.pop_one_button_dialog(error_message) + return + + # Convert a list of vector to 2D numpy array for imshow() + # Get data and plot + raw_det_data = self._myControl.get_raw_detector_counts(exp_no, scan_no, pt_no) + self.ui.graphicsView.clear_canvas() + self.ui.graphicsView.add_plot_2d(raw_det_data, x_min=0, x_max=256, y_min=0, y_max=256, + hold_prev_image=False) + + return + + def _show_ub_matrix(self, ubmatrix): + """ Show UB matrix + :param ubmatrix: + :return: + """ + assert ubmatrix.shape == (3, 3) + + self.ui.tableWidget_ubMatrix.set_from_matrix(ubmatrix) + + return diff --git a/scripts/Inelastic/Direct/DirectEnergyConversion.py b/scripts/Inelastic/Direct/DirectEnergyConversion.py index 56043ad5aeed4096c76b402026bf270c95982230..74394d53c59d56718d782f4b99e3b56634f1a1f9 100644 --- a/scripts/Inelastic/Direct/DirectEnergyConversion.py +++ b/scripts/Inelastic/Direct/DirectEnergyConversion.py @@ -1,3 +1,4 @@ +#pylint: disable=too-many-lines #pylint: disable=invalid-name from mantid.simpleapi import * from mantid.kernel import funcreturns diff --git a/scripts/Inelastic/Direct/ISISDirecInelasticConfig.py b/scripts/Inelastic/Direct/ISISDirecInelasticConfig.py index 624f599ba04d0e2848de1d7eae90cd134bcf83b3..f3c816ecbac11ce60b67842eb3f6dfbf1c4caad9 100644 --- a/scripts/Inelastic/Direct/ISISDirecInelasticConfig.py +++ b/scripts/Inelastic/Direct/ISISDirecInelasticConfig.py @@ -484,12 +484,12 @@ class MantidConfigDirectInelastic(object): # def init_user(self,fedIDorUser,theUser=None): """Define settings, specific to a user - Supports two interfaces -- old and the new one + Supports two interfaces -- old and the new one where - OldInterface: requested two input parameters + OldInterface: requested two input parameters fedID -- users federal id theUser -- class defining all other user property - NewInterface: requested single parameter: + NewInterface: requested single parameter: theUser -- class defining all user's properties including fedID """ if not theUser: diff --git a/scripts/Inelastic/Direct/PropertiesDescriptors.py b/scripts/Inelastic/Direct/PropertiesDescriptors.py index f05779e6e22cb3be785e93284470526939658be8..aec0169cd240da45e7d63e5218902c7578eb579e 100644 --- a/scripts/Inelastic/Direct/PropertiesDescriptors.py +++ b/scripts/Inelastic/Direct/PropertiesDescriptors.py @@ -1,3 +1,4 @@ +#pylint: disable=too-many-lines #pylint: disable=invalid-name """ File contains collection of Descriptors used to define complex properties in NonIDF_Properties and PropertyManager classes diff --git a/scripts/Inelastic/Direct/RunDescriptor.py b/scripts/Inelastic/Direct/RunDescriptor.py index 9fda6508d6224a370358ac200b8968be3aeca2c5..b5e959ff885084e6a088e0647532fa21445b65ca 100644 --- a/scripts/Inelastic/Direct/RunDescriptor.py +++ b/scripts/Inelastic/Direct/RunDescriptor.py @@ -1,3 +1,4 @@ +#pylint: disable=too-many-lines #pylint: disable=invalid-name """ File contains Descriptors used describe run for direct inelastic reduction """ @@ -995,8 +996,8 @@ class RunDescriptor(PropDescriptor): Load(Filename=data_file, OutputWorkspace=ws_name,LoadMonitors = '1',MonitorsAsEvents='0') #HACK >>> , necessary until #11565 is fixed if nxs_file : - instr_name = RunDescriptor._holder.instr_name - if instr_name == 'LET' and self._run_number>14151 and self._run_number<14382: + instr_name = RunDescriptor._holder.instr_name + if instr_name == 'LET' and self._run_number>14151 and self._run_number<14382: FrameworkManager.clearInstruments() idf_file = api.ExperimentInfo.getInstrumentFilename(instr_name) idf_path,tile = os.path.split(idf_file) diff --git a/scripts/Interface/reduction_gui/reduction/diffraction/diffraction_reduction_script.py b/scripts/Interface/reduction_gui/reduction/diffraction/diffraction_reduction_script.py index 7140a4df5633e57ccaaca3b9719cc32474b3539f..abbd2f4eee91d7db012641d90db791d3ecdec1b6 100644 --- a/scripts/Interface/reduction_gui/reduction/diffraction/diffraction_reduction_script.py +++ b/scripts/Interface/reduction_gui/reduction/diffraction/diffraction_reduction_script.py @@ -84,7 +84,7 @@ class DiffractionReductionScripter(BaseReductionScripter): file_name, autosavexmlfname) wbuf += script wbuf += "\n========== End of Script ===========" - print (wbuf) + print wbuf return script diff --git a/scripts/Interface/reduction_gui/widgets/reflectometer/base_ref_reduction.py b/scripts/Interface/reduction_gui/widgets/reflectometer/base_ref_reduction.py index ea324c63828a6e03190b8b2c5fc99b90bdf2fd80..72cfb428315fa574ee295ed307c2e1e696f1eb99 100644 --- a/scripts/Interface/reduction_gui/widgets/reflectometer/base_ref_reduction.py +++ b/scripts/Interface/reduction_gui/widgets/reflectometer/base_ref_reduction.py @@ -1,3 +1,4 @@ +#pylint: disable=too-many-lines #pylint: disable=invalid-name,unused-import from PyQt4 import QtGui, QtCore import reduction_gui.widgets.util as util diff --git a/scripts/Interface/reduction_gui/widgets/reflectometer/refl_data_simple.py b/scripts/Interface/reduction_gui/widgets/reflectometer/refl_data_simple.py index bfb043368ad53ccaeb13b243a916cea1f8f5e615..8816e2f91ded5277314a7b6e267a8a72f8c424ac 100644 --- a/scripts/Interface/reduction_gui/widgets/reflectometer/refl_data_simple.py +++ b/scripts/Interface/reduction_gui/widgets/reflectometer/refl_data_simple.py @@ -1,3 +1,4 @@ +#pylint: disable=too-many-lines #pylint: disable=invalid-name from PyQt4 import QtGui, uic, QtCore import reduction_gui.widgets.util as util diff --git a/scripts/Interface/ui/reflectometer/refl_gui.py b/scripts/Interface/ui/reflectometer/refl_gui.py index 3bb3aed9b003789fd1786e1f1ecfa46f82878888..8f1a384733c2e605fd61b22f192b30ccc26b3b90 100644 --- a/scripts/Interface/ui/reflectometer/refl_gui.py +++ b/scripts/Interface/ui/reflectometer/refl_gui.py @@ -1,3 +1,4 @@ +#pylint: disable=too-many-lines #pylint: disable=invalid-name import ui_refl_window import refl_save diff --git a/scripts/Reflectometry/isis_reflectometry/procedures.py b/scripts/Reflectometry/isis_reflectometry/procedures.py index 999dd0a65df4c3c69b2b8d82f085be1fa5d886ab..11d1a52448ec5749956eca3315db82a7a2537801 100644 --- a/scripts/Reflectometry/isis_reflectometry/procedures.py +++ b/scripts/Reflectometry/isis_reflectometry/procedures.py @@ -1,3 +1,4 @@ +#pylint: disable=too-many-lines #pylint: disable=invalid-name from math import * diff --git a/scripts/SANS/ISISCommandInterface.py b/scripts/SANS/ISISCommandInterface.py index 0ed8fd805b698e6a5c35ffdf68ae9425299ed478..3f06b3229bf67e2a871806a1a62459c5db70707b 100644 --- a/scripts/SANS/ISISCommandInterface.py +++ b/scripts/SANS/ISISCommandInterface.py @@ -1,3 +1,4 @@ +#pylint: disable=too-many-lines #pylint: disable=invalid-name """ Enables the SANS commands (listed at http://www.mantidproject.org/SANS) to @@ -574,7 +575,7 @@ def _fitRescaleAndShift(rAnds, frontData, rearData): # We need to make sure at this point that the workspaces are 1D. We # don't really know how to match the workspaces for the 2D case. - if (not su.is_1D_workspace(mtd[frontData]) or not su.is_1D_workspace(mtd[rearData])): + if not su.is_1D_workspace(mtd[frontData]) or not su.is_1D_workspace(mtd[rearData]): sanslog.warning("Request to perform a fit to find the shift and scale values for" "a non-1D workspace is not possible. Default values are provided.") scale = rAnds.scale diff --git a/scripts/SANS/SANSBatchMode.py b/scripts/SANS/SANSBatchMode.py index 3419a9c6cd16d07aede08f6ca2a48e6918fb1d9b..38f01016a7b8b7744b9bdd942883cb8c133268b4 100644 --- a/scripts/SANS/SANSBatchMode.py +++ b/scripts/SANS/SANSBatchMode.py @@ -178,7 +178,8 @@ def BatchReduce(filename, format, plotresults=False, saveAlgs={'SaveRKH':'txt'}, original_settings = settings, original_prop_man_settings = prop_man_settings) except (RunTimeError, ValueError) as e: - sanslog.warning("Error in Batchmode user files: Could not reset the specified user file %s. More info: %s" %(str(run['user_file']),str(e))) + sanslog.warning("Error in Batchmode user files: Could not reset the specified user file %s. More info: %s" %( + str(run['user_file']),str(e))) local_settings = copy.deepcopy(ReductionSingleton().reference()) local_prop_man_settings = ReductionSingleton().settings.clone("TEMP_SETTINGS") diff --git a/scripts/SANS/SANSUtility.py b/scripts/SANS/SANSUtility.py index b22d9e8c19ad5d785f2d99beb9479be8769d5258..c594e7548e3d319888d9136a2b8c14c6831b8221 100644 --- a/scripts/SANS/SANSUtility.py +++ b/scripts/SANS/SANSUtility.py @@ -1,3 +1,4 @@ +#pylint: disable=too-many-lines #pylint: disable=invalid-name ######################################################### # This module contains utility functions common to the diff --git a/scripts/SANS/isis_instrument.py b/scripts/SANS/isis_instrument.py index b4c0a9a507d3bbcb0a063ac2c540d05a12eeb1ce..821b956195403a29bfb2b308d0a83d29286235c9 100644 --- a/scripts/SANS/isis_instrument.py +++ b/scripts/SANS/isis_instrument.py @@ -1,3 +1,4 @@ +#pylint: disable=too-many-lines #pylint: disable=invalid-name import math import os diff --git a/scripts/SANS/isis_reduction_steps.py b/scripts/SANS/isis_reduction_steps.py index ebb89992488267b445b04ba4d1b5f16f99c55a98..f98175cf90062335d14d3cf0894e08d7e117e840 100644 --- a/scripts/SANS/isis_reduction_steps.py +++ b/scripts/SANS/isis_reduction_steps.py @@ -1,3 +1,4 @@ +#pylint: disable=too-many-lines #pylint: disable=invalid-name """ This file defines what happens in each step in the data reduction, it's diff --git a/scripts/reduction/instruments/reflectometer/wks_utility.py b/scripts/reduction/instruments/reflectometer/wks_utility.py index b9dec721553ac63bdbeb835d613fe0b306a45bb4..7544a27a51147a23863c1579e17d2db0afac45d3 100644 --- a/scripts/reduction/instruments/reflectometer/wks_utility.py +++ b/scripts/reduction/instruments/reflectometer/wks_utility.py @@ -1,3 +1,4 @@ +#pylint: disable=too-many-lines #pylint: disable=invalid-name from numpy import zeros, arctan2, arange, shape, sqrt, fliplr, asfarray, mean, sum, NAN from mantid.simpleapi import * diff --git a/tools/DOI/authors.py b/tools/DOI/authors.py index aefa191509e7cae27eb14df35dfc91e564189b23..2d35b45b4aec8710fb2a8a7cff85ed3b137977e2 100644 --- a/tools/DOI/authors.py +++ b/tools/DOI/authors.py @@ -1,3 +1,4 @@ +#pylint: disable=invalid-name from itertools import chain, ifilterfalse import string, os, re diff --git a/tools/DOI/doi.py b/tools/DOI/doi.py index f27811292ed89caf678ee17b70bfcabae46b99a6..56c4a8782a92cef962d8e76cd0750eac47717d4d 100644 --- a/tools/DOI/doi.py +++ b/tools/DOI/doi.py @@ -1,3 +1,4 @@ +#pylint: disable=invalid-name """A script for generating DataCite DOI's for Mantid releases, to be called by a Jenkins job during the release process. When given a major, minor and patch release number along with username and password credentials, it will build a diff --git a/tools/DefaultConfigFiles/configToCpp.py b/tools/DefaultConfigFiles/configToCpp.py index 6cd03a271650bc81ed2e03fcdc93110c0f563604..bb924e92af41df65efb48cf20fa26230099a49f7 100644 --- a/tools/DefaultConfigFiles/configToCpp.py +++ b/tools/DefaultConfigFiles/configToCpp.py @@ -7,8 +7,8 @@ import sys with open(sys.argv[2]) as f: for line in f: - line = line.rstrip('\n') - if line == "": - print sys.argv[1] + " << std::endl;" - else: - print sys.argv[1] + " << \"" + line + "\" << std::endl;" + line = line.rstrip('\n') + if line == "": + print sys.argv[1] + " << std::endl;" + else: + print sys.argv[1] + " << \"" + line + "\" << std::endl;" diff --git a/tools/PeriodicTable/generate_atom_code.py b/tools/PeriodicTable/generate_atom_code.py index 6827ab0b10015a849b672f72dbc5f1b0c5c79780..3e2be400a0091c7ae44503bf0c060233302194e2 100755 --- a/tools/PeriodicTable/generate_atom_code.py +++ b/tools/PeriodicTable/generate_atom_code.py @@ -1,3 +1,4 @@ +#pylint: disable=invalid-name #!/usr/bin/env python VERSION = "1.0" diff --git a/tools/Pylint/fixPylint.py b/tools/Pylint/fixPylint.py new file mode 100644 index 0000000000000000000000000000000000000000..5f3cf1d6990bde995780868418b7132eef3e4060 --- /dev/null +++ b/tools/Pylint/fixPylint.py @@ -0,0 +1,173 @@ +#pylint: disable=invalid-name,anomalous-backslash-in-string +import os +import re +import argparse + +def fixBadIndent(toModify,indent): + err_string=indent.replace(' Bad indentation. Found ','').replace('(bad-indentation)','').split('spaces, expected') + bad=int(err_string[0]) + good=int(err_string[1]) + return toModify.replace(' '*bad,' '*good) + +def fixParens(fname,errorlist,errlines): + tofixf=open(fname,'r') + file_content=tofixf.readlines() + tofixf.close() + newcontent=file_content + for i,error in zip(errlines,errorlist): + if error.find('(superfluous-parens)')!=-1: + kwd=error.split("'")[1] + pattern=re.compile(kwd+'(?P<spaces>\ *)\((?P<file_content>.*)\)') + match=pattern.search(file_content[i]) + d=match.groupdict() + newcontent[i]=file_content[i].replace(kwd+d['spaces']+'('+d['file_content']+')',kwd+' '+d['file_content']) + tofixf=open(fname,'w') + tofixf.write(''.join(newcontent)) + tofixf.close() + +def fixSeveralErrors(fname,errorlist,errlines): + tofixf=open(fname,'r') + file_content=tofixf.readlines() + tofixf.close() + newcontent=file_content + for i,error in zip(errlines,errorlist): + if error.find('Bad indentation')!=-1: + newcontent[i]=fixBadIndent(file_content[i],error) + if error.find('missing-final-newline')!=-1: + newcontent[-1]+='\n' + if error.find('mixed-indentation')!=-1: + newcontent[i]=file_content[i].replace('\t', ' ') + if error.find('trailing-whitespace')!=-1: + newcontent[i]=file_content[i].rstrip()+'\n' + if error.find('Unnecessary semicolon')!=-1: + newcontent[i]=file_content[i].replace(';','') + tofixf=open(fname,'w') + tofixf.write(''.join(newcontent)) + tofixf.close() + +def addIgnoreStatement(fname,errorlist): + tofixf=open(fname,'r') + file_content=tofixf.readlines() + tofixf.close() + ignore=[] + for error in errorlist: + if error.find('(invalid-name)')!=-1 and 'invalid-name' not in ignore: + ignore.append('invalid-name') + if error.find('(no-init)')!=-1 and 'no-init' not in ignore: + ignore.append('no-init') + if error.find('(too-many-lines)')!=-1 and 'too-many-lines' not in ignore: + ignore.append('too-many-lines') + if len(ignore)!=0: + tofixf=open(fname,'w') + tofixf.write("#pylint: disable="+','.join(ignore)+'\n') + tofixf.write(''.join(file_content)) + tofixf.close() + +def generate_choices(): + ch=['simple','parentheses','add_ignores'] + ch_help=['simple - fixes the following warning: bad-indentation, missing-final-newline, '+\ + 'mixed_indentation, trailing-whitespace, unnecesary-semicolon', + 'parentheses - fixes superfluous-parens warning', + 'add_ignores - adds ignore statemets at the beginning of each file to ignore invalid-name, no-init, too-many-lines'] + chhelp="The possible choices supported are:\n\t"+'\n\t'.join(ch_help) + return (ch,chhelp) + +if __name__=='__main__': + choices,choices_help=generate_choices() + parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter, + epilog=choices_help, + description='Fix some pylint warnings. It is STRONGLY RECOMMENDED to '+\ + 'rerun the pylintcheck between fixes') + parser.add_argument('-fix','--fix', default='simple', + choices=choices, + help='Select things to fix (default: simple). \nSee the choices options below.') + parser.add_argument('Filename', type=file, help='The output from "make pylint"') + parser.add_argument('-v','--version', action='version', version='%(prog)s 1.0') + + #read pylint.log + args = parser.parse_args() + oneline=args.Filename.read() + args.Filename.close() + #ignore everything up to the first error + oneline=oneline[oneline.find('****'):] + content=oneline.split('\n') + + fileindex=content.index('Checks of the following modules FAILED:') + files=[f.strip() for f in content[fileindex+1:-1]] + filenumber=0 + linenumber=0 + prevFile=True + + + while linenumber<fileindex: + filename=files[filenumber] + line=content[linenumber] + #find a file + if line.find('****')==0 and line.find('PyChop')==-1: + modname=line.split('************* Module ')[1] + if prevFile: + if os.path.isfile(filename): + correct_filename=filename + filenumber+=1 + prevFile=True + else: + prevFile=False + modname=modname.replace('.','/') + firstslash=modname.find('/') + if firstslash==-1: + correct_filename=filename+'/__init__.py' + else: + correct_filename=filename+modname[firstslash:]+'.py' + else: + lastmodulename=os.path.split(filename)[1] + modbase=modname.split('.')[0] + if lastmodulename==modbase: #still in the same module + modname=modname.replace('.','/') + firstslash=modname.find('/') + if firstslash==-1: + correct_filename=filename+'/__init__.py' + else: + correct_filename=filename+modname[firstslash:]+'.py' + else: #go to the next file or module + filenumber+=1 + filename=files[filenumber] + prevFile=True + if os.path.isfile(filename): + correct_filename=filename + filenumber+=1 + prevFile=True + else: + prevFile=False + modname=modname.replace('.','/') + firstslash=modname.find('/') + if firstslash==-1: + correct_filename=filename+'/__init__.py' + else: + correct_filename=filename+modname[firstslash:]+'.py' + #process it + j=1 + errors=[] + errorlines=[] + while linenumber+j<fileindex and content[linenumber+j].find('****')==-1: + err=content[linenumber+j] + if len(err)>0 and err[0] in ['C','W','E'] and err[1]==':': + lineNumber=int(err.split(':')[1].split(',')[0])-1 + errors.append(err.split(':')[2]) + errorlines.append(lineNumber) + j+=1 + if args.fix=='simple': + fixSeveralErrors(correct_filename,errors,errorlines) + elif args.fix=='add_ignores': + addIgnoreStatement(correct_filename,errors) + elif args.fix=='parentheses': + fixParens(correct_filename,errors,errorlines) + linenumber+=j-1 + else: + linenumber+=1 + + + + + + + diff --git a/tools/Pylint/pylint.cfg b/tools/Pylint/pylint.cfg index eec53d4f7b22bdfd67bc5e8f1c30b956fa6be060..cbf3bb4a69987805eca098774a89baba10598196 100644 --- a/tools/Pylint/pylint.cfg +++ b/tools/Pylint/pylint.cfg @@ -57,7 +57,7 @@ disable=W0142,I0011,F0401,W0614,E0602,C0111,C0326,W0401,R0201,R0801 output-format=colorized # Include message's id in output -include-ids=yes +#include-ids=yes # Put messages in a separate file for each module / package specified on the # command line instead of printing them on stdout. Reports (if any) will be diff --git a/tools/Pylint/run_pylint.py b/tools/Pylint/run_pylint.py index 2b51de4194665b59e36f43166812cdb728a1b6c4..8368854c1fcafe1db6c7f464b3fe0a61a6f7922b 100644 --- a/tools/Pylint/run_pylint.py +++ b/tools/Pylint/run_pylint.py @@ -57,7 +57,7 @@ class Results(object): """ Return true if all files were clean """ - return (len(self.failures) == 0) + return len(self.failures) == 0 def add(self, modulename, status): """ @@ -172,8 +172,8 @@ def parse_arguments(argv): help="If provided, store the output in the given file.") parser.add_option("-x", "--exclude", dest="exclude", metavar="EXCLUDES", help="If provided, a space-separated list of " - "files/directories to exclude. Relative paths are " - "taken as relative to --basedir") + "files/directories to exclude. Relative paths are " + "taken as relative to --basedir") parser.set_defaults(format=DEFAULT_PYLINT_FORMAT, exe=DEFAULT_PYLINT_EXE, nofail=False, basedir=os.getcwd(), rcfile=DEFAULT_RCFILE, exclude="") @@ -242,6 +242,7 @@ def check_module_imports(): str: String indicating success/failure """ msg = "" + #pylint: disable=unused-variable try: import mantid except ImportError, exc: @@ -292,7 +293,7 @@ def run_checks(targets, serializer, options): targetpath = os.path.join(options.basedir, target) pkg_init = os.path.join(targetpath, "__init__.py") if os.path.isfile(targetpath) or os.path.isfile(pkg_init): - overall_stats.add(target, exec_pylint_on_importable(targetpath, serializer, options)) + overall_stats.add(targetpath, exec_pylint_on_importable(targetpath, serializer, options)) else: overall_stats.update(exec_pylint_on_all(targetpath, serializer, options, excludes)) ## @@ -352,7 +353,7 @@ def find_importable_targets(dirpath): pkg_init = os.path.join(abspath, "__init__.py") if (os.path.isfile(abspath) and item.endswith(".py")) or \ os.path.isfile(pkg_init): - importables.append(abspath) + importables.append(abspath) elif os.path.isdir(abspath): importables.extend(package_walk(abspath)) return importables @@ -386,7 +387,7 @@ def exec_pylint_on_importable(srcpath, serializer, options): with temp_dir_change(os.path.dirname(srcpath)): status = subp.call(cmd, stdout=serializer) - return (status == 0) + return status == 0 #------------------------------------------------------------------------------ diff --git a/tools/TestViewer/TestViewer.py b/tools/TestViewer/TestViewer.py index 428762ca8577534af6bc5449a80c9e08df2360d4..987819601d5c954e4bb51b9a0ce43707c03fdf91 100755 --- a/tools/TestViewer/TestViewer.py +++ b/tools/TestViewer/TestViewer.py @@ -4,4 +4,4 @@ """ Launch the GUI Test Viewer """ import main_window -main_window.start() \ No newline at end of file +main_window.start() diff --git a/tools/TestViewer/main_window.py b/tools/TestViewer/main_window.py index 4117295fdb6b377a07b42355098a97c15d4e2bf9..48975b55710a5871b9c86f8211cbe22a839e7ebc 100644 --- a/tools/TestViewer/main_window.py +++ b/tools/TestViewer/main_window.py @@ -1,3 +1,4 @@ +#pylint: disable=invalid-name #!/usr/bin/env python # -*- coding: utf-8 -*- diff --git a/tools/TestViewer/test_info.py b/tools/TestViewer/test_info.py index c43fb05c0cf7a6b8ba340dea515ec46d1c5643cf..e93f07021bebedf3cb17b4ab1e53fe6281c46a4f 100644 --- a/tools/TestViewer/test_info.py +++ b/tools/TestViewer/test_info.py @@ -1,3 +1,4 @@ +#pylint: disable=too-many-lines,invalid-name # -*- coding: utf-8 -*- """ Classes describing test projects, how they are run, @@ -77,7 +78,7 @@ class TestResult: def __eq__(self, other): """ Equality comparison """ if isinstance(other, TestResult): - return ((self.value == other.value) and (self.old == other.old)) + return (self.value == other.value) and (self.old == other.old) else: return self.value == other @@ -372,7 +373,7 @@ class TestSuite(object): self.contents_changed = True else: for i in xrange(len(self.tests)): - if (self.tests[i].name != other.tests[i].name): + if self.tests[i].name != other.tests[i].name: self.contents_changed = True self.tests[i].replace_contents( other.tests[i] ) # Copy local values @@ -402,7 +403,7 @@ class TestSuite(object): oldtime = self.source_file_mtime if os.path.exists(self.source_file): self.source_file_mtime = os.path.getmtime(self.source_file) - return (self.source_file_mtime != oldtime) + return self.source_file_mtime != oldtime def get_selected(self): return self.selected @@ -587,7 +588,7 @@ class TestSuite(object): return elif len(suites) > 1: for xmlSuite in suites: - if (suites[0].getAttribute("name") == self.name): + if suites[0].getAttribute("name") == self.name: break else: xmlSuite = suites[0] @@ -596,7 +597,7 @@ class TestSuite(object): xmlCases = xmlSuite.getElementsByTagName("testcase") for case in xmlCases: classname = case.getAttribute("classname") - if (classname == self.classname): + if classname == self.classname: # This is the single test name test_name = case.getAttribute("name") test = self.find_test(test_name) @@ -752,7 +753,7 @@ class TestProject(object): # This will run while calling the stdout callback. (status, output) = run_command_with_callback(full_command, callback_func) - if (status != 0): + if status != 0: msg = "-------- BUILD FAILED! ---------" if not callback_func is None: callback_func("%s" % msg) self.build_succeeded = False @@ -1055,7 +1056,7 @@ class MultipleProjects(object): word = val[1:] for pj in self.projects: for suite in pj.suites: - suite.selected = not (word in suite.name) + suite.selected = not word in suite.name if suite.selected: num += 1 else: word = val @@ -1486,14 +1487,14 @@ def test_results_compiling(): def test_age(): a = TestSingle("my_test_test", None) - assert (a.state == TestResult.NOT_RUN) + assert a.state == TestResult.NOT_RUN a.age() - assert (a.state == TestResult.NOT_RUN) - assert (a.state.old) + assert a.state == TestResult.NOT_RUN + assert a.state.old a = TestSingle("my_test_test", None) a.state = TestResult(TestResult.ALL_PASSED) a.age() - assert (a.state.old) + assert a.state.old test_results_compiling() test_age() diff --git a/tools/TestViewer/test_tree.py b/tools/TestViewer/test_tree.py index f373d29ff19abf5b7fb4b5d4189f39e3424d7fb6..9c233db03d27a2f1b4e6569cd9ba148cf84dbf37 100644 --- a/tools/TestViewer/test_tree.py +++ b/tools/TestViewer/test_tree.py @@ -1,3 +1,4 @@ +#pylint: disable=invalid-name,no-init """ An AbstractTreeItem implementation for a QTreeView that uses the results from test runners. """ @@ -295,7 +296,7 @@ class TestTreeModel(QtCore.QAbstractItemModel): # What background color? if role == Qt.BackgroundRole: - return item.background_color(); + return item.background_color() #User role is used when directly querying the contents of the item if role == Qt.UserRole: @@ -490,7 +491,7 @@ class TestTreeModel(QtCore.QAbstractItemModel): for k in xrange(num_tests): test_indx = self.index(k, 0, suite_indx) # Sets it as checked. - self.setData(test_indx, QtCore.Qt.Checked, QtCore.Qt.CheckStateRole); + self.setData(test_indx, QtCore.Qt.Checked, QtCore.Qt.CheckStateRole) def mouseDoubleClickEvent(self): print "mouseDoubleClickEvent" @@ -536,7 +537,7 @@ class TreeFilterProxyModel(QSortFilterProxyModel): return False if self.selected_only: if isinstance(item, TestProject) or isinstance(item, TestSuite) : - return (item.get_selected() > 0) + return item.get_selected() > 0 else: # Don't filter out TestSingles based on selection (since they're all selected) return True diff --git a/tools/TestViewer/ui_main_window.py b/tools/TestViewer/ui_main_window.py index 415f4cf3f0b9fc2ffc51ce79f3bb345c6d99e958..d33d69c8a7d567dd0f6e2337f7b286e84a9f8ab6 100644 --- a/tools/TestViewer/ui_main_window.py +++ b/tools/TestViewer/ui_main_window.py @@ -1,3 +1,4 @@ +#pylint: disable=invalid-name # -*- coding: utf-8 -*- # Form implementation generated from reading ui file 'main_window.ui' diff --git a/tools/VTKConverter/VTKConvert.py b/tools/VTKConverter/VTKConvert.py index 5b84926cc4900576e1ecede9e9337d983153c9a1..3048c2c46f2f3071bb0b9f104c26f61ca1d7706f 100644 --- a/tools/VTKConverter/VTKConvert.py +++ b/tools/VTKConverter/VTKConvert.py @@ -1,3 +1,4 @@ +#pylint: disable=invalid-name #! /usr/bin/python # Convert an acor file into VTK format (specifically a vtp file) from xml.dom import minidom diff --git a/tools/VTKConverter/processISISData.py b/tools/VTKConverter/processISISData.py index 7d00849ca3f3d570c99e3dc54354b7cbac107ff3..7a988d0adbbaab4180538af8c941ed45a67dca34 100644 --- a/tools/VTKConverter/processISISData.py +++ b/tools/VTKConverter/processISISData.py @@ -1,24 +1,25 @@ +#pylint: disable=invalid-name #!/usr/bin/python import os import sys import VTKConvert -if( len(sys.argv) == 1 ): +if len(sys.argv) == 1 : print "Usage: processISISData file-name1 file-name2 ...\n processISISDATA dir-name" exit(1) names=[] is_dir = os.path.isdir(sys.argv[1]) -if( is_dir ): +if is_dir : names = os.listdir(sys.argv[1]) else: for i in range(1,len(sys.argv)): names.append(sys.argv[i]) prefix="" -if( is_dir ): +if is_dir : prefix = sys.argv[1].split('/')[0] + "-VTU/" - if( os.path.isdir(prefix) ): + if os.path.isdir(prefix) : print "Directory " + prefix + " already exists, please move\n" exit(1) else: @@ -27,7 +28,7 @@ else: prefix = "./" for file in names: - if( is_dir ): + if is_dir : filename = sys.argv[1] + file VTKConvert.convertToVTU(filename, prefix) diff --git a/tools/reports/facility-code-changes.py b/tools/reports/facility-code-changes.py index 2ea10c847d974cb144283e74900c2a675eb52a84..f8f1e906cde51814c8d5fd820b323dceb9f08b5a 100644 --- a/tools/reports/facility-code-changes.py +++ b/tools/reports/facility-code-changes.py @@ -1,3 +1,4 @@ +#pylint: disable=invalid-name from __future__ import (absolute_import, division, print_function, unicode_literals) __author__ = 'Stuart Campbell' diff --git a/tools/reports/release-list.py b/tools/reports/release-list.py index f6a48764d64dbeade4b1df4a4ed9dfb7e7a93045..a74995bfa317d57197b2f7726be302e138e8ff08 100644 --- a/tools/reports/release-list.py +++ b/tools/reports/release-list.py @@ -1,3 +1,4 @@ +#pylint: disable=invalid-name from __future__ import (absolute_import, division, print_function, unicode_literals) import csv diff --git a/tools/scripts/ConvertBadAlgmLinks.py b/tools/scripts/ConvertBadAlgmLinks.py index 4d7d71e86989bbaa469f1535c5510afdd5ce52ee..6759d9d23b3b5bdf2004bd2afeb048e9b6edd5c4 100644 --- a/tools/scripts/ConvertBadAlgmLinks.py +++ b/tools/scripts/ConvertBadAlgmLinks.py @@ -1,3 +1,4 @@ +#pylint: disable=invalid-name import re, glob, os def grep(patt,lines): @@ -30,13 +31,13 @@ for filename in files: #print os.path.basename(filename)[:-4] with open(filename) as file: - lines = file.readlines() - for alg in algs: - expr = regexs[alg] - results = grep(expr, lines) - if results: - print filename - print results + lines = file.readlines() + for alg in algs: + expr = regexs[alg] + results = grep(expr, lines) + if results: + print filename + print results diff --git a/tools/scripts/CorrectConceptLinksinAlgPages.py b/tools/scripts/CorrectConceptLinksinAlgPages.py index 700472f0529451dd752ec48008bf364e34f51806..7dcd787a465a2a84151c64ec152e6b0f2ba720c7 100644 --- a/tools/scripts/CorrectConceptLinksinAlgPages.py +++ b/tools/scripts/CorrectConceptLinksinAlgPages.py @@ -1,51 +1,52 @@ +#pylint: disable=invalid-name import os, re import urllib2 concepts = ['Algorithm', -'Analysis_Data_Service', -'categories', -'Create_an_IDF', -'Data_Service', -'Dynamic_Factory', -'Error_Propagation', -'EventWorkspace', -'Facilities_File', -'FitConstraint', -'Framework_Manager', -'Geometry', -'Geometry_of_Position', -'Geometry_of_Shape', -'HowToDefineGeometricShape', -'index', -'Instrument', -'InstrumentDefinitionFile', -'InstrumentParameterFile', -'Instrument_Data_Service', -'Lattice', -'LET_Sample_IDF', -'MatrixWorkspace', -'MDHistoWorkspace', -'MDWorkspace', -'Nexus_file', -'Plugin', -'Project', -'Properties', -'Properties_File', -'RAW_File', -'Run', -'SANS2D_Sample_IDF', -'Shared_Pointer', -'Table_Workspaces', -'Unit_Factory', -'UserAlgorithms', -'Workflow_Algorithm', -'Workspace', -'Workspace2D', -'WorkspaceGroup'] + 'Analysis_Data_Service', + 'categories', + 'Create_an_IDF', + 'Data_Service', + 'Dynamic_Factory', + 'Error_Propagation', + 'EventWorkspace', + 'Facilities_File', + 'FitConstraint', + 'Framework_Manager', + 'Geometry', + 'Geometry_of_Position', + 'Geometry_of_Shape', + 'HowToDefineGeometricShape', + 'index', + 'Instrument', + 'InstrumentDefinitionFile', + 'InstrumentParameterFile', + 'Instrument_Data_Service', + 'Lattice', + 'LET_Sample_IDF', + 'MatrixWorkspace', + 'MDHistoWorkspace', + 'MDWorkspace', + 'Nexus_file', + 'Plugin', + 'Project', + 'Properties', + 'Properties_File', + 'RAW_File', + 'Run', + 'SANS2D_Sample_IDF', + 'Shared_Pointer', + 'Table_Workspaces', + 'Unit_Factory', + 'UserAlgorithms', + 'Workflow_Algorithm', + 'Workspace', + 'Workspace2D', + 'WorkspaceGroup'] def outputError(alg, algVersion, description, notes=""): - print "%s, %i, %s, %s" % (alg, algVersion, description, notes) + print "%s, %i, %s, %s" % (alg, algVersion, description, notes) rstdir = r"C:\Mantid\Code\Mantid\docs\source\algorithms" conceptsPattern = {} @@ -61,17 +62,17 @@ for alg in algs: fileFound = False filename = os.path.join(rstdir,alg + "-v" + str(algVersion) + ".rst") if os.path.exists(filename): - algText = "" - with open (filename, "r") as algRst: - fileFound = True - algText = algRst.read() - for concept in concepts: - regex = conceptsPattern[concept] - while (regex.search(algText) != None): - outputError(alg, algVersion, "found", concept) - algText = regex.sub(r":ref:`\1 <\2>`",algText) + algText = "" + with open (filename, "r") as algRst: + fileFound = True + algText = algRst.read() + for concept in concepts: + regex = conceptsPattern[concept] + while regex.search(algText) != None: + outputError(alg, algVersion, "found", concept) + algText = regex.sub(r":ref:`\1 <\2>`",algText) with open (filename, "w") as algRst: - algRst.write(algText) + algRst.write(algText) if fileFound==False: outputError(alg, algVersion, "File not found") diff --git a/tools/scripts/FindIncompleteAlgRSTPages.py b/tools/scripts/FindIncompleteAlgRSTPages.py index a7573c89ff2705bc520ead33fea9940b662a231f..f4d05d10629102eab5eb160a5ed24eb1b0ff7749 100644 --- a/tools/scripts/FindIncompleteAlgRSTPages.py +++ b/tools/scripts/FindIncompleteAlgRSTPages.py @@ -1,3 +1,4 @@ +#pylint: disable=invalid-name import os, re import urllib2 @@ -6,7 +7,7 @@ def readWebPage(url): opener = urllib2.build_opener(proxy) urllib2.install_opener(opener) aResp =urllib2.urlopen(url) - web_pg = aResp.read(); + web_pg = aResp.read() return web_pg def ticketExists(alg, ticketHash): diff --git a/tools/scripts/TestWikiPython.py b/tools/scripts/TestWikiPython.py index 09ca6e06bc757b869f1ba53f913dd6e33c0c4c7d..63d0e4b367106c17a36bebcbf2cdb8caec1f337b 100644 --- a/tools/scripts/TestWikiPython.py +++ b/tools/scripts/TestWikiPython.py @@ -1,3 +1,4 @@ +#pylint: disable=invalid-name ########################################################################################### # Extracts code blocks marked as python from mediawiki pages and checks they run # run with -h for command line arguments @@ -133,7 +134,7 @@ parser.add_argument('-o', '--o', help='Provide a path to output to an output directory') args = parser.parse_args() -urlList = []; +urlList = [] baseUrl = "http://www.mantidproject.org/" if args.s is not None: baseUrl = args.s diff --git a/tools/scripts/extractAlgorithmNames.py b/tools/scripts/extractAlgorithmNames.py index 90c7a661aed65f9d78fc2fc2878c2f21f3f2b9ea..8945b898c9e698c5c3d261c1d0ba9d35ad42635e 100644 --- a/tools/scripts/extractAlgorithmNames.py +++ b/tools/scripts/extractAlgorithmNames.py @@ -1,3 +1,4 @@ +#pylint: disable=invalid-name # simply just print out all algorithm names in a directory which can be piped # to a file diff --git a/tools/scripts/extractAuthorNamesFromGit.py b/tools/scripts/extractAuthorNamesFromGit.py index ee6bf1e2eceb5ff853dc9c5baa93a86814ee91d0..728ac36dadd8f2cc94f81df3cf512a7f4f4b93bb 100644 --- a/tools/scripts/extractAuthorNamesFromGit.py +++ b/tools/scripts/extractAuthorNamesFromGit.py @@ -1,3 +1,4 @@ +#pylint: disable=invalid-name # This python script is run after running extractAlgorithmNames.py, where # the output of that script is saved to a *.txt # @@ -18,7 +19,7 @@ allAlgs = [line.strip() for line in open(algorithmList)] os.chdir('PythonInterface/plugins/algorithms/WorkflowAlgorithms') for line in allAlgs: #print line - fullline = line + fullline = line args = [ 'git', 'log', '--pretty=short', @@ -30,11 +31,11 @@ for line in allAlgs: authors = subprocess.check_output(args).replace('"', '').split('\n') authors = set(authors) authors = authors - set(['']) - + for author in authors: #print author fullline = fullline + ", " + author - + print fullline #line = 'GroupWorkspaces.cpp' @@ -54,5 +55,5 @@ for line in allAlgs: #for author in authors: #print author # fullline = fullline + ", " + author - + #print fullline diff --git a/tools/skipped_systemtests.py b/tools/skipped_systemtests.py index c13d3e140d18102f3e4e847377f2ebcaacca1c8b..3ffdb9fb5837d1c055e93e8f019d11e31384d56e 100755 --- a/tools/skipped_systemtests.py +++ b/tools/skipped_systemtests.py @@ -1,3 +1,4 @@ +#pylint: disable=invalid-name #!/usr/bin/env python import ast @@ -33,7 +34,7 @@ def addTestResult(results, case, label): def printResultCell(mark, length): - if (mark): + if mark: left = int(length/2) right = length-left-1 print "%sx%s" % (' '*left, ' '*right),