/// Get the counting time from a workspace /// @param inputWS :: workspace to read the counting time from double HFIRDarkCurrentSubtraction::getCountingTime(MatrixWorkspace_sptr inputWS) { // First, look whether we have the information in the log if (inputWS->run().hasProperty("timer")) { return inputWS->run().getPropertyValueAsType<double>("timer"); } else { // If we don't have the information in the log, use the default timer // spectrum MantidVec &timer = inputWS->dataY(DEFAULT_TIMER_ID); return timer[0]; } }
double RefReduction::calculateAngleREFL(MatrixWorkspace_sptr workspace) { Mantid::Kernel::Property* prop = workspace->run().getProperty("ths"); Mantid::Kernel::TimeSeriesProperty<double>* dp = dynamic_cast<Mantid::Kernel::TimeSeriesProperty<double>* >(prop); const double ths = dp->getStatistics().mean; prop = workspace->run().getProperty("tthd"); dp = dynamic_cast<Mantid::Kernel::TimeSeriesProperty<double>* >(prop); const double tthd = dp->getStatistics().mean; double offset = getProperty("AngleOffset"); if (isEmpty(offset)) offset = 0.0; return tthd - ths + offset; }
/// Get the counting time from a workspace /// @param inputWS :: workspace to read the counting time from double HFIRDarkCurrentSubtraction::getCountingTime(MatrixWorkspace_sptr inputWS) { // First, look whether we have the information in the log if (inputWS->run().hasProperty("timer")) { Mantid::Kernel::Property* prop = inputWS->run().getProperty("timer"); Mantid::Kernel::PropertyWithValue<double>* dp = dynamic_cast<Mantid::Kernel::PropertyWithValue<double>* >(prop); return *dp; } else { // If we don't have the information in the log, use the default timer spectrum MantidVec& timer = inputWS->dataY(DEFAULT_TIMER_ID); return timer[0]; } }
/** Return the to-be axis of the workspace dependent on the log entry * @param ws : the input workspace * @return : the x-axis to use for the output workspace */ std::vector<double> ConjoinXRuns::getXAxis(MatrixWorkspace_sptr ws) const { std::vector<double> axis; axis.reserve(ws->blocksize()); auto &run = ws->run(); // try time series first TimeSeriesProperty<double> *timeSeriesDouble(nullptr); timeSeriesDouble = dynamic_cast<TimeSeriesProperty<double> *>(run.getLogData(m_logEntry)); if (timeSeriesDouble) { // try double series axis = timeSeriesDouble->filteredValuesAsVector(); } else { // try int series next TimeSeriesProperty<int> *timeSeriesInt(nullptr); timeSeriesInt = dynamic_cast<TimeSeriesProperty<int> *>(run.getLogData(m_logEntry)); if (timeSeriesInt) { std::vector<int> intAxis = timeSeriesInt->filteredValuesAsVector(); axis = std::vector<double>(intAxis.begin(), intAxis.end()); } else { // then scalar axis.push_back(run.getPropertyAsSingleValue(m_logEntry)); } } return axis; }
double RefReduction::calculateAngleREFM(MatrixWorkspace_sptr workspace) { double dangle = getProperty("DetectorAngle"); if (isEmpty(dangle)) { Mantid::Kernel::Property* prop = workspace->run().getProperty("DANGLE"); Mantid::Kernel::TimeSeriesProperty<double>* dp = dynamic_cast<Mantid::Kernel::TimeSeriesProperty<double>* >(prop); dangle = dp->getStatistics().mean; } double dangle0 = getProperty("DetectorAngle0"); if (isEmpty(dangle0)) { Mantid::Kernel::Property* prop = workspace->run().getProperty("DANGLE0"); Mantid::Kernel::TimeSeriesProperty<double>* dp = dynamic_cast<Mantid::Kernel::TimeSeriesProperty<double>* >(prop); dangle0 = dp->getStatistics().mean; } Mantid::Kernel::Property* prop = workspace->run().getProperty("SampleDetDis"); Mantid::Kernel::TimeSeriesProperty<double>* dp = dynamic_cast<Mantid::Kernel::TimeSeriesProperty<double>* >(prop); const double det_distance = dp->getStatistics().mean/1000.0; double direct_beam_pix = getProperty("DirectPixel"); if (isEmpty(direct_beam_pix)) { Mantid::Kernel::Property* prop = workspace->run().getProperty("DIRPIX"); Mantid::Kernel::TimeSeriesProperty<double>* dp = dynamic_cast<Mantid::Kernel::TimeSeriesProperty<double>* >(prop); direct_beam_pix = dp->getStatistics().mean; } double ref_pix = getProperty("ReflectivityPixel"); if (ref_pix==0 || isEmpty(ref_pix)) { const std::vector<int> peakRange = getProperty("SignalPeakPixelRange"); if (peakRange.size()<2) { g_log.error() << "SignalPeakPixelRange parameter should be a vector of two values" << std::endl; throw std::invalid_argument("SignalPeakPixelRange parameter should be a vector of two values"); } ref_pix = (peakRange[0] + peakRange[1])/2.0; } double theta = (dangle-dangle0)*M_PI/180.0/2.0 + ((direct_beam_pix-ref_pix)*PIXEL_SIZE)/ (2.0*det_distance); return theta*180.0/M_PI; }
/** * Check the inputs for invalid values * @returns A map with validation warnings. */ std::map<std::string, std::string> ChangeTimeZero::validateInputs() { std::map<std::string, std::string> invalidProperties; // Check the time offset for either a value or a date time double relativeTimeOffset = getProperty("RelativeTimeOffset"); std::string absoluteTimeOffset = getProperty("AbsoluteTimeOffset"); auto isRelative = isRelativeTimeShift(relativeTimeOffset); auto absoluteTimeInput = absoluteTimeOffset != m_defaultAbsoluteTimeShift; auto isAbsolute = isAbsoluteTimeShift(absoluteTimeOffset); // If both inputs are being used, then return straight away. if (isRelative && absoluteTimeInput) { invalidProperties.insert(std::make_pair( "RelativeTimeOffset", "You can either sepcify a relative time shift or " "an absolute time shift.")); invalidProperties.insert(std::make_pair( "AbsoluteTimeOffset", "You can either sepcify a relative time shift or " "an absolute time shift.")); return invalidProperties; } else if (!isRelative && !isAbsolute) { invalidProperties.insert(std::make_pair( "RelativeTimeOffset", "TimeOffset must either be a numeric " "value or a ISO8601 (YYYY-MM-DDTHH:MM::SS) date-time stamp.")); invalidProperties.insert(std::make_pair( "AbsoluteTimeOffset", "TimeOffset must either be a numeric " "value or a ISO8601 (YYYY-MM-DDTHH:MM::SS) date-time stamp.")); } // If we are dealing with an absolute time we need to ensure that the // proton_charge entry exists if (isAbsolute) { MatrixWorkspace_sptr ws = getProperty("InputWorkspace"); auto run = ws->run(); try { run.getTimeSeriesProperty<double>("proton_charge"); } catch (...) { invalidProperties.insert( std::make_pair("InputWorkspace", "A TimeOffset with an absolute time, requires the " "input workspace to have a proton_charge property in " "its log.")); } } return invalidProperties; }
/** * Execute the algorithm. */ void CreateChopperModel::exec() { const std::string modelType = getProperty("ModelType"); if (modelType != "FermiChopperModel") { throw std::invalid_argument("Invalid chopper model type."); } MatrixWorkspace_sptr workspace = getProperty("Workspace"); API::ChopperModel *chopper = new API::FermiChopperModel; chopper->setRun(workspace->run()); chopper->initialize(getProperty("Parameters")); int index = getProperty("ChopperPoint"); workspace->setChopperModel(chopper, static_cast<size_t>(index)); }
/** Export time stamps looking erroreous * @param dts :: standard delta T in second * @param ws :: shared pointer to a matrix workspace, which has the log to *study * @param abstimevec :: vector of log time * * This algorithm should be reconsidered how to work with it. */ void GetTimeSeriesLogInformation::exportErrorLog(MatrixWorkspace_sptr ws, vector<DateAndTime> abstimevec, double dts) { std::string outputdir = getProperty("OutputDirectory"); if (!outputdir.empty() && outputdir.back() != '/') outputdir += "/"; std::string ofilename = outputdir + "errordeltatime.txt"; g_log.notice() << ofilename << '\n'; std::ofstream ofs; ofs.open(ofilename.c_str(), std::ios::out); size_t numbaddt = 0; Kernel::DateAndTime t0(ws->run().getProperty("run_start")->value()); for (size_t i = 1; i < abstimevec.size(); i++) { double tempdts = static_cast<double>(abstimevec[i].totalNanoseconds() - abstimevec[i - 1].totalNanoseconds()) * 1.0E-9; double dev = (tempdts - dts) / dts; bool baddt = false; if (fabs(dev) > 0.5) baddt = true; if (baddt) { numbaddt++; double deltapulsetimeSec1 = static_cast<double>(abstimevec[i - 1].totalNanoseconds() - t0.totalNanoseconds()) * 1.0E-9; double deltapulsetimeSec2 = static_cast<double>(abstimevec[i].totalNanoseconds() - t0.totalNanoseconds()) * 1.0E-9; int index1 = static_cast<int>(deltapulsetimeSec1 * 60); int index2 = static_cast<int>(deltapulsetimeSec2 * 60); ofs << "Error d(T) = " << tempdts << " vs Correct d(T) = " << dts << '\n'; ofs << index1 << "\t\t" << abstimevec[i - 1].totalNanoseconds() << "\t\t" << index2 << "\t\t" << abstimevec[i].totalNanoseconds() << '\n'; } } ofs.close(); }
void NormaliseByCurrent::exec() { // Get the input workspace MatrixWorkspace_sptr inputWS = getProperty("InputWorkspace"); MatrixWorkspace_sptr outputWS = getProperty("OutputWorkspace"); // Get the good proton charge and check it's valid double charge(-1.0); try { charge = inputWS->run().getProtonCharge(); } catch(Exception::NotFoundError &) { g_log.error() << "The proton charge is not set for the run attached to this workspace\n"; throw; } if (charge == 0) { throw std::domain_error("The proton charge is zero"); } g_log.information() << "Normalisation current: " << charge << " uamps" << std::endl; charge=1.0/charge; // Inverse of the charge to be multiplied by // The operator overloads properly take into account of both EventWorkspaces and doing it in place or not. if (getPropertyValue("InputWorkspace") != getPropertyValue("OutputWorkspace")) { outputWS = inputWS*charge; setProperty("OutputWorkspace", outputWS); } else { inputWS *= charge; setProperty("OutputWorkspace", inputWS); } outputWS->setYUnitLabel("Counts per microAmp.hour"); }
void ApplyPaalmanPings::run() { // Create / Initialize algorithm API::BatchAlgorithmRunner::AlgorithmRuntimeProps absCorProps; IAlgorithm_sptr applyCorrAlg = AlgorithmManager::Instance().create("ApplyPaalmanPingsCorrection"); applyCorrAlg->initialize(); // get Sample Workspace MatrixWorkspace_sptr sampleWs = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>( m_sampleWorkspaceName); m_originalSampleUnits = sampleWs->getAxis(0)->unit()->unitID(); // If not in wavelength then do conversion if (m_originalSampleUnits != "Wavelength") { g_log.information( "Sample workspace not in wavelength, need to convert to continue."); absCorProps["SampleWorkspace"] = addConvertUnitsStep(sampleWs, "Wavelength"); } else { absCorProps["SampleWorkspace"] = m_sampleWorkspaceName; } const bool useCan = m_uiForm.ckUseCan->isChecked(); const bool useCorrections = m_uiForm.ckUseCorrections->isChecked(); // Get Can and Clone MatrixWorkspace_sptr canClone; if (useCan) { const auto canName = m_uiForm.dsContainer->getCurrentDataName().toStdString(); const auto cloneName = "__algorithm_can"; IAlgorithm_sptr clone = AlgorithmManager::Instance().create("CloneWorkspace"); clone->initialize(); clone->setProperty("InputWorkspace", canName); clone->setProperty("Outputworkspace", cloneName); clone->execute(); const bool useShift = m_uiForm.ckShiftCan->isChecked(); if (useShift) { IAlgorithm_sptr scaleX = AlgorithmManager::Instance().create("ScaleX"); scaleX->initialize(); scaleX->setLogging(false); scaleX->setProperty("InputWorkspace", cloneName); scaleX->setProperty("OutputWorkspace", cloneName); scaleX->setProperty("Factor", m_uiForm.spCanShift->value()); scaleX->setProperty("Operation", "Add"); scaleX->execute(); IAlgorithm_sptr rebin = AlgorithmManager::Instance().create("RebinToWorkspace"); rebin->initialize(); rebin->setLogging(false); rebin->setProperty("WorkspaceToRebin", cloneName); rebin->setProperty("WorkspaceToMatch", m_sampleWorkspaceName); rebin->setProperty("OutputWorkspace", cloneName); rebin->execute(); } canClone = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(cloneName); // Check for same binning across sample and container if (!checkWorkspaceBinningMatches(sampleWs, canClone)) { const char *text = "Binning on sample and container does not match." "Would you like to rebin the container to match the sample?"; int result = QMessageBox::question(NULL, tr("Rebin sample?"), tr(text), QMessageBox::Yes, QMessageBox::No, QMessageBox::NoButton); if (result == QMessageBox::Yes) { addRebinStep(QString::fromStdString(canName), QString::fromStdString(m_sampleWorkspaceName)); } else { m_batchAlgoRunner->clearQueue(); g_log.error("Cannot apply absorption corrections " "using a sample and " "container with different binning."); return; } } // If not in wavelength then do conversion std::string originalCanUnits = canClone->getAxis(0)->unit()->unitID(); if (originalCanUnits != "Wavelength") { g_log.information("Container workspace not in wavelength, need to " "convert to continue."); absCorProps["CanWorkspace"] = addConvertUnitsStep(canClone, "Wavelength"); } else { absCorProps["CanWorkspace"] = cloneName; } const bool useCanScale = m_uiForm.ckScaleCan->isChecked(); if (useCanScale) { const double canScaleFactor = m_uiForm.spCanScale->value(); applyCorrAlg->setProperty("CanScaleFactor", canScaleFactor); } } if (useCorrections) { QString correctionsWsName = m_uiForm.dsCorrections->getCurrentDataName(); WorkspaceGroup_sptr corrections = AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>( correctionsWsName.toStdString()); bool interpolateAll = false; for (size_t i = 0; i < corrections->size(); i++) { MatrixWorkspace_sptr factorWs = boost::dynamic_pointer_cast<MatrixWorkspace>(corrections->getItem(i)); // Check for matching binning if (sampleWs && (sampleWs->blocksize() != factorWs->blocksize())) { int result; if (interpolateAll) { result = QMessageBox::Yes; } else { std::string text = "Number of bins on sample and " + factorWs->name() + " workspace does not match.\n" + "Would you like to interpolate this workspace to " "match the sample?"; result = QMessageBox::question( NULL, tr("Interpolate corrections?"), tr(text.c_str()), QMessageBox::YesToAll, QMessageBox::Yes, QMessageBox::No); } switch (result) { case QMessageBox::YesToAll: interpolateAll = true; // fall through case QMessageBox::Yes: addInterpolationStep(factorWs, absCorProps["SampleWorkspace"]); break; default: m_batchAlgoRunner->clearQueue(); g_log.error("ApplyPaalmanPings cannot run with corrections that do " "not match sample binning."); return; } } } applyCorrAlg->setProperty("CorrectionsWorkspace", correctionsWsName.toStdString()); } // Generate output workspace name auto QStrSampleWsName = QString::fromStdString(m_sampleWorkspaceName); int nameCutIndex = QStrSampleWsName.lastIndexOf("_"); if (nameCutIndex == -1) nameCutIndex = QStrSampleWsName.length(); QString correctionType; switch (m_uiForm.cbGeometry->currentIndex()) { case 0: correctionType = "flt"; break; case 1: correctionType = "cyl"; break; case 2: correctionType = "anl"; break; } QString outputWsName = QStrSampleWsName.left(nameCutIndex); // Using corrections if (m_uiForm.ckUseCorrections->isChecked()) { outputWsName += "_" + correctionType + "_Corrected"; } else { outputWsName += "_Subtracted"; } // Using container if (m_uiForm.ckUseCan->isChecked()) { const auto canName = m_uiForm.dsContainer->getCurrentDataName().toStdString(); MatrixWorkspace_sptr containerWs = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(canName); auto run = containerWs->run(); if (run.hasProperty("run_number")) { outputWsName += "_" + QString::fromStdString(run.getProperty("run_number")->value()); } else { auto canCutIndex = QString::fromStdString(canName).indexOf("_"); outputWsName += "_" + QString::fromStdString(canName).left(canCutIndex); } } outputWsName += "_red"; applyCorrAlg->setProperty("OutputWorkspace", outputWsName.toStdString()); // Add corrections algorithm to queue m_batchAlgoRunner->addAlgorithm(applyCorrAlg, absCorProps); // Run algorithm queue connect(m_batchAlgoRunner, SIGNAL(batchComplete(bool)), this, SLOT(absCorComplete(bool))); m_batchAlgoRunner->executeBatchAsync(); // Set the result workspace for Python script export m_pythonExportWsName = outputWsName.toStdString(); // m_containerWorkspaceName = m_uiForm.dsContainer->getCurrentDataName(); // updateContainer(); }
void ImageROIViewQtWidget::showProjectionImage( const Mantid::API::WorkspaceGroup_sptr &wsg, size_t idx) { MatrixWorkspace_sptr ws; try { ws = boost::dynamic_pointer_cast<MatrixWorkspace>(wsg->getItem(idx)); if (!ws) return; } catch (std::exception &e) { QMessageBox::warning( this, "Cannot load image", "There was a problem while trying to find the image data: " + QString::fromStdString(e.what())); } const size_t MAXDIM = 2048 * 16; size_t width; try { width = boost::lexical_cast<size_t>(ws->run().getLogData("Axis1")->value()); // TODO: add a settings option for this (like max mem allocation for // images)? if (width >= MAXDIM) width = MAXDIM; } catch (std::exception &e) { QMessageBox::critical(this, "Cannot load image", "There was a problem while trying to " "find the width of the image: " + QString::fromStdString(e.what())); return; } size_t height; try { height = boost::lexical_cast<size_t>(ws->run().getLogData("Axis2")->value()); if (height >= MAXDIM) height = MAXDIM; } catch (std::exception &e) { QMessageBox::critical(this, "Cannot load image", "There was a problem while trying to " "find the height of the image: " + QString::fromStdString(e.what())); return; } // images are loaded as 1 histogram == 1 pixel (1 bin per histogram): if (height != ws->getNumberHistograms() || width != ws->blocksize()) { QMessageBox::critical( this, "Image dimensions do not match in the input image workspace", "Could not load the expected " "number of rows and columns."); return; } // find min and max to scale pixel values double min = std::numeric_limits<double>::max(), max = std::numeric_limits<double>::min(); for (size_t i = 0; i < ws->getNumberHistograms(); ++i) { for (size_t j = 0; j < ws->blocksize(); ++j) { const double &v = ws->readY(i)[j]; if (v < min) min = v; if (v > max) max = v; } } if (min >= max) { QMessageBox::warning( this, "Empty image!", "The image could be loaded but it contains " "effectively no information, all pixels have the same value."); // black picture QPixmap pix(static_cast<int>(width), static_cast<int>(height)); pix.fill(QColor(0, 0, 0)); m_ui.label_img->setPixmap(pix); m_ui.label_img->show(); m_basePixmap.reset(new QPixmap(pix)); return; } // load / transfer image into a QImage QImage rawImg(QSize(static_cast<int>(width), static_cast<int>(height)), QImage::Format_RGB32); const double max_min = max - min; const double scaleFactor = 255.0 / max_min; for (size_t yi = 0; yi < width; ++yi) { for (size_t xi = 0; xi < width; ++xi) { const double &v = ws->readY(yi)[xi]; // color the range min-max in gray scale. To apply different color // maps you'd need to use rawImg.setColorTable() or similar. const int scaled = static_cast<int>(scaleFactor * (v - min)); QRgb vRgb = qRgb(scaled, scaled, scaled); rawImg.setPixel(static_cast<int>(xi), static_cast<int>(yi), vRgb); } } // paint and show image // direct from image QPixmap pix = QPixmap::fromImage(rawImg); m_ui.label_img->setPixmap(pix); m_ui.label_img->show(); m_basePixmap.reset(new QPixmap(pix)); // Alternative, drawing with a painter: // QPixmap pix(static_cast<int>(width), static_cast<int>(height)); // QPainter painter; // painter.begin(&pix); // painter.drawImage(0, 0, rawImg); // painter.end(); // m_ui.label_img->setPixmap(pix); // m_ui.label_img->show(); // m_basePixmap.reset(new QPixmap(pix)); }
/** Convert a SPICE 2D Det MatrixWorkspace to MDEvents and append to an * MDEventWorkspace * It is optional to use a virtual instrument or copy from input data workspace * @brief ConvertCWSDExpToMomentum::convertSpiceMatrixToMomentumMDEvents * @param dataws :: data matrix workspace * @param usevirtual :: boolean flag to use virtual instrument * @param startdetid :: starting detid for detectors from this workspace mapping * to virtual instrument in MDEventWorkspace * @param runnumber :: run number for all MDEvents created from this matrix * workspace */ void ConvertCWSDExpToMomentum::convertSpiceMatrixToMomentumMDEvents( MatrixWorkspace_sptr dataws, bool usevirtual, const detid_t &startdetid, const int runnumber) { // Create transformation matrix from which the transformation is Kernel::DblMatrix rotationMatrix; setupTransferMatrix(dataws, rotationMatrix); g_log.information() << "Before insert new event, output workspace has " << m_outputWS->getNEvents() << "Events.\n"; // Creates a new instance of the MDEventInserte to output workspace MDEventWorkspace<MDEvent<3>, 3>::sptr mdws_mdevt_3 = boost::dynamic_pointer_cast<MDEventWorkspace<MDEvent<3>, 3>>(m_outputWS); MDEventInserter<MDEventWorkspace<MDEvent<3>, 3>::sptr> inserter(mdws_mdevt_3); // Calcualte k_i: it is assumed that all k_i are same for one Pt. // number, i.e., one 2D XML file Kernel::V3D sourcePos = dataws->getInstrument()->getSource()->getPos(); Kernel::V3D samplePos = dataws->getInstrument()->getSample()->getPos(); if (dataws->readX(0).size() != 2) throw std::runtime_error( "Input matrix workspace has wrong dimension in X-axis."); double momentum = 0.5 * (dataws->readX(0)[0] + dataws->readX(0)[1]); Kernel::V3D ki = (samplePos - sourcePos) * (momentum / sourcePos.norm()); g_log.debug() << "Source at " << sourcePos.toString() << ", Norm = " << sourcePos.norm() << ", momentum = " << momentum << "\n" << "k_i = " << ki.toString() << "\n"; // Go though each spectrum to conver to MDEvent size_t numspec = dataws->getNumberHistograms(); double maxsignal = 0; size_t nummdevents = 0; for (size_t iws = 0; iws < numspec; ++iws) { // Get detector positions and signal double signal = dataws->readY(iws)[0]; // Skip event with 0 signal if (signal < 0.001) continue; double error = dataws->readE(iws)[0]; Kernel::V3D detpos = dataws->getDetector(iws)->getPos(); std::vector<Mantid::coord_t> q_sample(3); // Calculate Q-sample and new detector ID in virtual instrument. Kernel::V3D qlab = convertToQSample(samplePos, ki, detpos, momentum, q_sample, rotationMatrix); detid_t native_detid = dataws->getDetector(iws)->getID(); detid_t detid = native_detid + startdetid; // Insert inserter.insertMDEvent( static_cast<float>(signal), static_cast<float>(error * error), static_cast<uint16_t>(runnumber), detid, q_sample.data()); updateQRange(q_sample); g_log.debug() << "Q-lab = " << qlab.toString() << "\n"; g_log.debug() << "Insert DetID " << detid << ", signal = " << signal << ", with q_sample = " << q_sample[0] << ", " << q_sample[1] << ", " << q_sample[2] << "\n"; // Update some statistical inforamtion if (signal > maxsignal) maxsignal = signal; ++nummdevents; } g_log.information() << "Imported Matrixworkspace: Max. Signal = " << maxsignal << ", Add " << nummdevents << " MDEvents " << "\n"; // Add experiment info including instrument, goniometer and run number ExperimentInfo_sptr expinfo = boost::make_shared<ExperimentInfo>(); if (usevirtual) expinfo->setInstrument(m_virtualInstrument); else { Geometry::Instrument_const_sptr tmp_inst = dataws->getInstrument(); expinfo->setInstrument(tmp_inst); } 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 (auto property : vec_property) { expinfo->mutableRun().addProperty(property->clone()); } m_outputWS->addExperimentInfo(expinfo); return; }
/// Do the actual work of modifying the log in the workspace. void ChangeLogTime::exec() { // check that a log was specified string logname = this->getProperty("LogName"); if (logname.empty()) { throw std::runtime_error("Failed to supply a LogName"); } // everything will need an offset double offset = this->getProperty("TimeOffset"); // make sure the log is in the input workspace MatrixWorkspace_sptr inputWS = getProperty("InputWorkspace"); Kernel::TimeSeriesProperty<double> * oldlog = dynamic_cast<Kernel::TimeSeriesProperty<double> *>( inputWS->run().getLogData(logname) ); if (!oldlog) { stringstream msg; msg << "InputWorkspace \'" << this->getPropertyValue("InputWorkspace") << "\' does not have LogName \'" << logname << "\'"; throw std::runtime_error(msg.str()); } // Create the new log TimeSeriesProperty<double>* newlog = new TimeSeriesProperty<double>(logname); newlog->setUnits(oldlog->units()); int size = oldlog->realSize(); vector<double> values = oldlog->valuesAsVector(); vector<DateAndTime> times = oldlog->timesAsVector(); for (int i = 0; i < size; i++) { newlog->addValue(times[i] + offset, values[i]); } // Just overwrite if the change is in place MatrixWorkspace_sptr outputWS = getProperty("OutputWorkspace"); if (outputWS != inputWS) { IAlgorithm_sptr duplicate = createChildAlgorithm("CloneWorkspace"); duplicate->initialize(); duplicate->setProperty<Workspace_sptr>("InputWorkspace", boost::dynamic_pointer_cast<Workspace>(inputWS)); duplicate->execute(); Workspace_sptr temp = duplicate->getProperty("OutputWorkspace"); outputWS = boost::dynamic_pointer_cast<MatrixWorkspace>(temp); setProperty("OutputWorkspace", outputWS); } outputWS->mutableRun().addProperty(newlog, true); }
/** Executes the algorithm. Reading in the file and creating and populating * the output workspace * * @throw Exception::FileError If the Nexus file cannot be found/opened * @throw std::invalid_argument If the optional properties are set to invalid *values */ void LoadNexusLogs::exec() { std::string filename = getPropertyValue("Filename"); MatrixWorkspace_sptr workspace = getProperty("Workspace"); // Find the entry name to use (normally "entry" for SNS, "raw_data_1" for // ISIS) std::string entry_name = LoadTOFRawNexus::getEntryName(filename); ::NeXus::File file(filename); // Find the root entry try { file.openGroup(entry_name, "NXentry"); } catch (::NeXus::Exception &) { throw std::invalid_argument("Unknown NeXus file format found in file '" + filename + "'"); } /// Use frequency start for Monitor19 and Special1_19 logs with "No Time" for /// SNAP try { file.openPath("DASlogs"); try { file.openGroup("frequency", "NXlog"); try { file.openData("time"); //----- Start time is an ISO8601 string date and time. ------ try { file.getAttr("start", freqStart); } catch (::NeXus::Exception &) { // Some logs have "offset" instead of start try { file.getAttr("offset", freqStart); } catch (::NeXus::Exception &) { g_log.warning() << "Log entry has no start time indicated.\n"; file.closeData(); throw; } } file.closeData(); } catch (::NeXus::Exception &) { // No time. This is not an SNS SNAP file } file.closeGroup(); } catch (::NeXus::Exception &) { // No time. This is not an SNS frequency group } file.closeGroup(); } catch (::NeXus::Exception &) { // No time. This is not an SNS group } // print out the entry level fields std::map<std::string, std::string> entries = file.getEntries(); std::map<std::string, std::string>::const_iterator iend = entries.end(); for (std::map<std::string, std::string>::const_iterator it = entries.begin(); it != iend; ++it) { std::string group_name(it->first); std::string group_class(it->second); if (group_name == "DASlogs" || group_class == "IXrunlog" || group_class == "IXselog" || group_name == "framelog") { loadLogs(file, group_name, group_class, workspace); } if (group_class == "IXperiods") { loadNPeriods(file, workspace); } } // If there's measurement information, load that info as logs. loadAndApplyMeasurementInfo(&file, *workspace); // Freddie Akeroyd 12/10/2011 // current ISIS implementation contains an additional indirection between // collected frames via an // "event_frame_number" array in NXevent_data (which eliminates frames with no // events). // the proton_log is for all frames and so is longer than the event_index // array, so we need to // filter the proton_charge log based on event_frame_number // This difference will be removed in future for compatibility with SNS, but // the code below will allow current SANS2D files to load if (workspace->mutableRun().hasProperty("proton_log")) { std::vector<int> event_frame_number; this->getLogger().notice() << "Using old ISIS proton_log and event_frame_number indirection..." << std::endl; try { // Find the bank/name corresponding to the first event data entry, i.e. // one with type NXevent_data. file.openPath("/" + entry_name); std::map<std::string, std::string> entries = file.getEntries(); std::map<std::string, std::string>::const_iterator it = entries.begin(); std::string eventEntry; for (; it != entries.end(); ++it) { if (it->second == "NXevent_data") { eventEntry = it->first; break; } } this->getLogger().debug() << "Opening" << " /" + entry_name + "/" + eventEntry + "/event_frame_number" << " to find the event_frame_number\n"; file.openPath("/" + entry_name + "/" + eventEntry + "/event_frame_number"); file.getData(event_frame_number); } catch (const ::NeXus::Exception &) { this->getLogger().warning() << "Unable to load event_frame_number - " "filtering events by time will not work " << std::endl; } file.openPath("/" + entry_name); if (!event_frame_number.empty()) // ISIS indirection - see above comments { Kernel::TimeSeriesProperty<double> *plog = dynamic_cast<Kernel::TimeSeriesProperty<double> *>( workspace->mutableRun().getProperty("proton_log")); if (!plog) throw std::runtime_error( "Could not cast (interpret) proton_log as a time " "series property. Cannot continue."); Kernel::TimeSeriesProperty<double> *pcharge = new Kernel::TimeSeriesProperty<double>("proton_charge"); std::vector<double> pval; std::vector<Mantid::Kernel::DateAndTime> ptime; pval.reserve(event_frame_number.size()); ptime.reserve(event_frame_number.size()); std::vector<Mantid::Kernel::DateAndTime> plogt = plog->timesAsVector(); std::vector<double> plogv = plog->valuesAsVector(); for (auto number : event_frame_number) { ptime.push_back(plogt[number]); pval.push_back(plogv[number]); } pcharge->create(ptime, pval); pcharge->setUnits("uAh"); workspace->mutableRun().addProperty(pcharge, true); } } try { // Read the start and end time strings file.openData("start_time"); Kernel::DateAndTime start(file.getStrData()); file.closeData(); file.openData("end_time"); Kernel::DateAndTime end(file.getStrData()); file.closeData(); workspace->mutableRun().setStartAndEndTime(start, end); } catch (::NeXus::Exception &) { } if (!workspace->run().hasProperty("gd_prtn_chrg")) { // Try pulling it from the main proton_charge entry first try { file.openData("proton_charge"); std::vector<double> values; file.getDataCoerce(values); std::string units; file.getAttr("units", units); double charge = values.front(); if (units.find("picoCoulomb") != std::string::npos) { charge *= 1.e-06 / 3600.; } workspace->mutableRun().setProtonCharge(charge); } catch (::NeXus::Exception &) { // Try and integrate the proton logs try { // Use the DAS logs to integrate the proton charge (if any). workspace->mutableRun().getProtonCharge(); } catch (Exception::NotFoundError &) { // Ignore not found property error. } } } // Close the file file.close(); }
/// Returns the value of a run property from a given workspace /// @param inputWS :: input workspace /// @param pname :: name of the property to retrieve double getRunPropertyDbl(MatrixWorkspace_sptr inputWS, const std::string& pname) { Mantid::Kernel::Property* prop = inputWS->run().getProperty(pname); Mantid::Kernel::PropertyWithValue<double>* dp = dynamic_cast<Mantid::Kernel::PropertyWithValue<double>* >(prop); return *dp; }
/** Execute the algorithm. */ void DgsReduction::exec() { // Reduction property manager const std::string reductionManagerName = this->getProperty("ReductionProperties"); if (reductionManagerName.empty()) { g_log.error() << "ERROR: Reduction Property Manager name is empty" << std::endl; return; } this->reductionManager = boost::make_shared<PropertyManager>(); PropertyManagerDataService::Instance().addOrReplace(reductionManagerName, this->reductionManager); // Put all properties except input files/workspaces into property manager. const std::vector<Property *> props = this->getProperties(); std::vector<Property *>::const_iterator iter = props.begin(); for (; iter != props.end(); ++iter) { if (!boost::contains((*iter)->name(), "Input")) { this->reductionManager->declareProperty((*iter)->clone()); } } // Determine the default facility const FacilityInfo defaultFacility = ConfigService::Instance().getFacility(); // Need to load data to get certain bits of information. Workspace_sptr sampleWS = this->loadInputData("Sample"); MatrixWorkspace_sptr WS = boost::dynamic_pointer_cast<MatrixWorkspace>(sampleWS); this->reductionManager->declareProperty(new PropertyWithValue<std::string>( "InstrumentName", WS->getInstrument()->getName())); // Check the facility for the loaded file and make sure it's the // same as the default. const InstrumentInfo info = ConfigService::Instance().getInstrument(WS->getInstrument()->getName()); if (defaultFacility.name() != info.facility().name()) { std::ostringstream mess; mess << "Default facility must be set to " << info.facility().name(); mess << " in order for reduction to work!"; throw std::runtime_error(mess.str()); } MatrixWorkspace_sptr sampleMonWS = this->getProperty("SampleInputMonitorWorkspace"); const bool showIntermedWS = this->getProperty("ShowIntermediateWorkspaces"); // Get output workspace pointer and name MatrixWorkspace_sptr outputWS = this->getProperty("OutputWorkspace"); std::string outputWsName = this->getPropertyValue("OutputWorkspace"); if (boost::ends_with(outputWsName, "_spe")) { boost::erase_all(outputWsName, "_spe"); } // Load the hard mask if available MatrixWorkspace_sptr hardMaskWS = this->loadHardMask(); if (hardMaskWS && showIntermedWS) { std::string hardMaskName = outputWsName + "_hardmask"; this->declareProperty(new WorkspaceProperty<>("ReductionHardMask", hardMaskName, Direction::Output)); this->setProperty("ReductionHardMask", hardMaskWS); } // Load the grouping file if available MatrixWorkspace_sptr groupingWS = this->loadGroupingFile(""); if (groupingWS && showIntermedWS) { std::string groupName = outputWsName + "_grouping"; this->declareProperty(new WorkspaceProperty<>("ReductionGrouping", groupName, Direction::Output)); this->setProperty("ReductionGrouping", groupingWS); } // This will be diagnostic mask if DgsDiagnose is run and hard mask if not. MatrixWorkspace_sptr maskWS; // Process the sample detector vanadium if present Workspace_sptr detVanWS = this->loadInputData("DetectorVanadium", false); MatrixWorkspace_sptr detVanMonWS = this->getProperty("DetectorVanadiumInputMonitorWorkspace"); bool isProcessedDetVan = this->getProperty("UseProcessedDetVan"); // Process a comparison detector vanadium if present Workspace_sptr detVan2WS = this->loadInputData("DetectorVanadium2", false); MatrixWorkspace_sptr detVan2MonWS = this->getProperty("DetectorVanadium2InputMonitorWorkspace"); IAlgorithm_sptr detVan; Workspace_sptr idetVanWS; if (detVanWS && !isProcessedDetVan) { std::string detVanMaskName = outputWsName + "_diagmask"; IAlgorithm_sptr diag = this->createChildAlgorithm("DgsDiagnose"); diag->setProperty("DetVanWorkspace", detVanWS); diag->setProperty("DetVanMonitorWorkspace", detVanMonWS); diag->setProperty("DetVanCompWorkspace", detVan2WS); diag->setProperty("DetVanCompMonitorWorkspace", detVan2MonWS); diag->setProperty("SampleWorkspace", sampleWS); diag->setProperty("SampleMonitorWorkspace", sampleMonWS); diag->setProperty("HardMaskWorkspace", hardMaskWS); diag->setProperty("ReductionProperties", reductionManagerName); diag->executeAsChildAlg(); maskWS = diag->getProperty("OutputWorkspace"); if (showIntermedWS) { this->declareProperty(new WorkspaceProperty<>("SampleDetVanDiagMask", detVanMaskName, Direction::Output)); this->setProperty("SampleDetVanDiagMask", maskWS); } detVan = this->createChildAlgorithm("DgsProcessDetectorVanadium"); detVan->setProperty("InputWorkspace", detVanWS); detVan->setProperty("InputMonitorWorkspace", detVanMonWS); detVan->setProperty("MaskWorkspace", maskWS); std::string idetVanName = outputWsName + "_idetvan"; detVan->setProperty("ReductionProperties", reductionManagerName); detVan->executeAsChildAlg(); MatrixWorkspace_sptr oWS = detVan->getProperty("OutputWorkspace"); idetVanWS = boost::dynamic_pointer_cast<Workspace>(oWS); if (showIntermedWS) { this->declareProperty(new WorkspaceProperty<>("IntegratedNormWorkspace", idetVanName, Direction::Output)); this->setProperty("IntegratedNormWorkspace", idetVanWS); } } else { idetVanWS = detVanWS; maskWS = boost::dynamic_pointer_cast<MatrixWorkspace>(idetVanWS); detVanWS.reset(); } IAlgorithm_sptr etConv = this->createChildAlgorithm("DgsConvertToEnergyTransfer"); etConv->setProperty("InputWorkspace", sampleWS); etConv->setProperty("InputMonitorWorkspace", sampleMonWS); etConv->setProperty("IntegratedDetectorVanadium", idetVanWS); const double ei = this->getProperty("IncidentEnergyGuess"); etConv->setProperty("IncidentEnergyGuess", ei); if (!maskWS && hardMaskWS) { maskWS = hardMaskWS; } etConv->setProperty("MaskWorkspace", maskWS); if (groupingWS) { etConv->setProperty("GroupingWorkspace", groupingWS); } etConv->setProperty("ReductionProperties", reductionManagerName); std::string tibWsName = this->getPropertyValue("OutputWorkspace") + "_tib"; etConv->executeAsChildAlg(); outputWS = etConv->getProperty("OutputWorkspace"); MatrixWorkspace_sptr tibWS = etConv->getProperty("OutputTibWorkspace"); if (tibWS && showIntermedWS) { this->declareProperty(new WorkspaceProperty<>("SampleTibWorkspace", tibWsName, Direction::Output)); this->setProperty("SampleTibWorkspace", tibWS); } Workspace_sptr absSampleWS = this->loadInputData("AbsUnitsSample", false); // Perform absolute normalisation if necessary if (absSampleWS) { std::string absWsName = outputWsName + "_absunits"; // Collect the other workspaces first. MatrixWorkspace_sptr absSampleMonWS = this->getProperty("AbsUnitsSampleInputMonitorWorkspace"); Workspace_sptr absDetVanWS = this->loadInputData("AbsUnitsDetectorVanadium", false); MatrixWorkspace_sptr absDetVanMonWS = this->getProperty("AbsUnitsDetectorVanadiumInputMonitorWorkspace"); MatrixWorkspace_sptr absGroupingWS = this->loadGroupingFile("AbsUnits"); // Run the absolute normalisation reduction IAlgorithm_sptr absUnitsRed = this->createChildAlgorithm("DgsAbsoluteUnitsReduction"); absUnitsRed->setProperty("InputWorkspace", absSampleWS); absUnitsRed->setProperty("InputMonitorWorkspace", absSampleMonWS); absUnitsRed->setProperty("DetectorVanadiumWorkspace", absDetVanWS); absUnitsRed->setProperty("DetectorVanadiumMonitorWorkspace", absDetVanMonWS); absUnitsRed->setProperty("GroupingWorkspace", absGroupingWS); absUnitsRed->setProperty("MaskWorkspace", maskWS); absUnitsRed->setProperty("ReductionProperties", reductionManagerName); absUnitsRed->executeAsChildAlg(); MatrixWorkspace_sptr absUnitsWS = absUnitsRed->getProperty("OutputWorkspace"); //!!! There is Property outputMaskWorkspace to get masks? It looks like one is using wrong property for masks MatrixWorkspace_sptr absMaskWS = absUnitsRed->getProperty("OutputWorkspace"); IAlgorithm_sptr mask = this->createChildAlgorithm("MaskDetectors"); mask->setProperty("Workspace", outputWS); mask->setProperty("MaskedWorkspace", absMaskWS); mask->executeAsChildAlg(); outputWS = mask->getProperty("Workspace"); // Do absolute normalisation outputWS = divide(outputWS, absUnitsWS); if (showIntermedWS) { this->declareProperty(new WorkspaceProperty<>("AbsUnitsWorkspace", absWsName, Direction::Output)); this->setProperty("AbsUnitsWorkspace", absUnitsWS); this->declareProperty(new WorkspaceProperty<>("AbsUnitsDiagMask", outputWsName+"_absunits_diagmask", Direction::Output)); this->setProperty("AbsUnitsDiagMask", absMaskWS); } } // Convert from DeltaE to powder S(Q,W) const bool doPowderConvert = this->getProperty("DoPowderDataConversion"); if (doPowderConvert) { g_log.notice() << "Converting to powder S(Q,W)" << std::endl; // Collect information std::string sqwWsName = outputWsName + "_pd_sqw"; std::vector<double> qBinning = this->getProperty("PowderMomTransferRange"); const double initialEnergy = boost::lexical_cast<double>(outputWS->run().getProperty("Ei")->value()); IAlgorithm_sptr sofqw = this->createChildAlgorithm("SofQW3"); sofqw->setProperty("InputWorkspace", outputWS); sofqw->setProperty("QAxisBinning", qBinning); sofqw->setProperty("EMode", "Direct"); sofqw->setProperty("EFixed", initialEnergy); sofqw->executeAsChildAlg(); MatrixWorkspace_sptr sqwWS = sofqw->getProperty("OutputWorkspace"); this->declareProperty(new WorkspaceProperty<>("PowderSqwWorkspace", sqwWsName, Direction::Output)); this->setProperty("PowderSqwWorkspace", sqwWS); const bool saveProcNexus = this->getProperty("SavePowderNexusFile"); if (saveProcNexus) { std::string saveProcNexusFilename = this->getProperty("SavePowderNexusFilename"); if (saveProcNexusFilename.empty()) { saveProcNexusFilename = sqwWsName + ".nxs"; } IAlgorithm_sptr saveNxs = this->createChildAlgorithm("SaveNexus"); saveNxs->setProperty("InputWorkspace", sqwWS); saveNxs->setProperty("Filename", saveProcNexusFilename); saveNxs->executeAsChildAlg(); } } this->setProperty("OutputWorkspace", outputWS); }
/** * This extraction strategy gets applied when guides are used to calculate the * collimation length. The instrument * parameter file contains the information about the number of guides to use. * The guide data itself is fetched * from the sample logs. * @param inOutWS: a matrix workspace * @param L1: the distance between sample and source * @param collimationLengthCorrection: The correction to get the collimation * length */ double SANSCollimationLengthEstimator::getCollimationLengthWithGuides( MatrixWorkspace_sptr inOutWS, const double L1, const double collimationLengthCorrection) const { auto lCollim = L1 - collimationLengthCorrection; // Make sure we have guide cutoffs if (!inOutWS->getInstrument()->hasParameter("guide-cutoff")) { throw std::invalid_argument("TOFSANSResolutionByPixel: Could not get a " "GuideCutoff from the instrument"); } // Make sure we have a defined number of guidess if (!inOutWS->getInstrument()->hasParameter("number-of-guides")) { throw std::invalid_argument( "TOFSANSResolutionByPixel: Could not get the number of guides."); } // Make sure we have a guide increment specified if (!inOutWS->getInstrument()->hasParameter( "guide-collimation-length-increment")) { throw std::invalid_argument( "TOFSANSResolutionByPixel: Could not find a guide increment."); } auto numberOfGuides = static_cast<unsigned int>( inOutWS->getInstrument()->getNumberParameter("number-of-guides")[0]); auto guideIncrement = inOutWS->getInstrument()->getNumberParameter( "guide-collimation-length-increment")[0]; // Make sure that all guides are there. They are labelled as Guide1, Guide2, // Guide3, ... // The entry is a numeric TimeSeriesProperty or a numeric entry, if something // else then default std::vector<double> guideValues; for (unsigned int i = 1; i <= numberOfGuides; i++) { auto guideName = "Guide" + boost::lexical_cast<std::string>(i); if (inOutWS->run().hasProperty(guideName)) { auto guideValue = getGuideValue(inOutWS->run().getProperty(guideName)); guideValues.push_back(guideValue); } else { throw std::invalid_argument("TOFSANSResolutionByPixel: Mismatch between " "specified number of Guides and actual " "Guides."); } } auto guideCutoff = inOutWS->getInstrument()->getNumberParameter("guide-cutoff")[0]; // Go through the guides and check in an alternate manner if the guide is // smaller // or larger than the cut off value. We start at the last guide and check that // it is // larger than the cutoff, the next one has to be smaller and so on. For // example in pseudocode // If Guide5 > 130: LCollim+=2.0 else break; // If Guide4 < 130: LCollim+=2.0 else break; // If Guide3 > 130: LCollim+=2.0 else break; // ... unsigned int largerSmallerCounter = 0; for (auto it = guideValues.rbegin(); it != guideValues.rend(); ++it) { bool guideIsLarger = largerSmallerCounter % 2 == 0; if (guideIsLarger && (*it > guideCutoff)) { lCollim += guideIncrement; } else if (!guideIsLarger && (*it < guideCutoff)) { lCollim += guideIncrement; } else { break; } largerSmallerCounter++; } return lCollim; }
void SANSSensitivityCorrection::exec() { // Output log m_output_message = ""; Progress progress(this, 0.0, 1.0, 10); // Reduction property manager const std::string reductionManagerName = getProperty("ReductionProperties"); boost::shared_ptr<PropertyManager> reductionManager; if (PropertyManagerDataService::Instance().doesExist(reductionManagerName)) { reductionManager = PropertyManagerDataService::Instance().retrieve(reductionManagerName); } else { reductionManager = boost::make_shared<PropertyManager>(); PropertyManagerDataService::Instance().addOrReplace(reductionManagerName, reductionManager); } if (!reductionManager->existsProperty("SensitivityAlgorithm")) { auto algProp = make_unique<AlgorithmProperty>("SensitivityAlgorithm"); algProp->setValue(toString()); reductionManager->declareProperty(std::move(algProp)); } progress.report("Loading sensitivity file"); const std::string fileName = getPropertyValue("Filename"); // Look for an entry for the dark current in the reduction table Poco::Path path(fileName); const std::string entryName = "Sensitivity" + path.getBaseName(); MatrixWorkspace_sptr floodWS; std::string floodWSName = "__sensitivity_" + path.getBaseName(); if (reductionManager->existsProperty(entryName)) { std::string wsName = reductionManager->getPropertyValue(entryName); floodWS = boost::dynamic_pointer_cast<MatrixWorkspace>( AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(wsName)); m_output_message += " |Using " + wsName + "\n"; g_log.debug() << "SANSSensitivityCorrection :: Using sensitivity workspace: " << wsName << "\n"; } else { // Load the flood field if we don't have it already // First, try to determine whether we need to load data or a sensitivity // workspace... if (!floodWS && fileCheck(fileName)) { g_log.debug() << "SANSSensitivityCorrection :: Loading sensitivity file: " << fileName << "\n"; IAlgorithm_sptr loadAlg = createChildAlgorithm("Load", 0.1, 0.3); loadAlg->setProperty("Filename", fileName); loadAlg->executeAsChildAlg(); Workspace_sptr floodWS_ws = loadAlg->getProperty("OutputWorkspace"); floodWS = boost::dynamic_pointer_cast<MatrixWorkspace>(floodWS_ws); // Check that it's really a sensitivity file if (!floodWS->run().hasProperty("is_sensitivity")) { // Reset pointer floodWS.reset(); g_log.error() << "A processed Mantid workspace was loaded but it " "wasn't a sensitivity file!\n"; } } // ... if we don't, just load the data and process it if (!floodWS) { // Read in default beam center double center_x = getProperty("BeamCenterX"); double center_y = getProperty("BeamCenterY"); if (isEmpty(center_x) || isEmpty(center_y)) { if (reductionManager->existsProperty("LatestBeamCenterX") && reductionManager->existsProperty("LatestBeamCenterY")) { center_x = reductionManager->getProperty("LatestBeamCenterX"); center_y = reductionManager->getProperty("LatestBeamCenterY"); m_output_message += " |Setting beam center to [" + Poco::NumberFormatter::format(center_x, 1) + ", " + Poco::NumberFormatter::format(center_y, 1) + "]\n"; } else m_output_message += " |No beam center provided: skipping!\n"; } const std::string rawFloodWSName = "__flood_data_" + path.getBaseName(); MatrixWorkspace_sptr rawFloodWS; if (!reductionManager->existsProperty("LoadAlgorithm")) { IAlgorithm_sptr loadAlg = createChildAlgorithm("Load", 0.1, 0.3); loadAlg->setProperty("Filename", fileName); if (!isEmpty(center_x) && loadAlg->existsProperty("BeamCenterX")) loadAlg->setProperty("BeamCenterX", center_x); if (!isEmpty(center_y) && loadAlg->existsProperty("BeamCenterY")) loadAlg->setProperty("BeamCenterY", center_y); loadAlg->setPropertyValue("OutputWorkspace", rawFloodWSName); loadAlg->executeAsChildAlg(); Workspace_sptr tmpWS = loadAlg->getProperty("OutputWorkspace"); rawFloodWS = boost::dynamic_pointer_cast<MatrixWorkspace>(tmpWS); m_output_message += " | Loaded " + fileName + " (Load algorithm)\n"; } else { // Get load algorithm as a string so that we can create a completely // new proxy and ensure that we don't overwrite existing properties IAlgorithm_sptr loadAlg0 = reductionManager->getProperty("LoadAlgorithm"); const std::string loadString = loadAlg0->toString(); IAlgorithm_sptr loadAlg = Algorithm::fromString(loadString); loadAlg->setChild(true); loadAlg->setProperty("Filename", fileName); loadAlg->setPropertyValue("OutputWorkspace", rawFloodWSName); if (!isEmpty(center_x) && loadAlg->existsProperty("BeamCenterX")) loadAlg->setProperty("BeamCenterX", center_x); if (!isEmpty(center_y) && loadAlg->existsProperty("BeamCenterY")) loadAlg->setProperty("BeamCenterY", center_y); loadAlg->execute(); rawFloodWS = loadAlg->getProperty("OutputWorkspace"); m_output_message += " |Loaded " + fileName + "\n"; if (loadAlg->existsProperty("OutputMessage")) { std::string msg = loadAlg->getPropertyValue("OutputMessage"); m_output_message += " |" + Poco::replace(msg, "\n", "\n |") + "\n"; } } // Check whether we just loaded a flood field data set, or the actual // sensitivity if (!rawFloodWS->run().hasProperty("is_sensitivity")) { const std::string darkCurrentFile = getPropertyValue("DarkCurrentFile"); // Look for a dark current subtraction algorithm std::string dark_result; if (reductionManager->existsProperty("DarkCurrentAlgorithm")) { IAlgorithm_sptr darkAlg = reductionManager->getProperty("DarkCurrentAlgorithm"); darkAlg->setChild(true); darkAlg->setProperty("InputWorkspace", rawFloodWS); darkAlg->setProperty("OutputWorkspace", rawFloodWS); // Execute as-is if we use the sample dark current, otherwise check // whether a dark current file was provided. // Otherwise do nothing if (getProperty("UseSampleDC")) { darkAlg->execute(); if (darkAlg->existsProperty("OutputMessage")) dark_result = darkAlg->getPropertyValue("OutputMessage"); } else if (!darkCurrentFile.empty()) { darkAlg->setProperty("Filename", darkCurrentFile); darkAlg->setProperty("PersistentCorrection", false); darkAlg->execute(); if (darkAlg->existsProperty("OutputMessage")) dark_result = darkAlg->getPropertyValue("OutputMessage"); else dark_result = " Dark current subtracted\n"; } } else if (!darkCurrentFile.empty()) { // We need to subtract the dark current for the flood field but no // dark // current subtraction was set for the sample! Use the default dark // current algorithm if we can find it. if (reductionManager->existsProperty("DefaultDarkCurrentAlgorithm")) { IAlgorithm_sptr darkAlg = reductionManager->getProperty("DefaultDarkCurrentAlgorithm"); darkAlg->setChild(true); darkAlg->setProperty("InputWorkspace", rawFloodWS); darkAlg->setProperty("OutputWorkspace", rawFloodWS); darkAlg->setProperty("Filename", darkCurrentFile); darkAlg->setProperty("PersistentCorrection", false); darkAlg->execute(); if (darkAlg->existsProperty("OutputMessage")) dark_result = darkAlg->getPropertyValue("OutputMessage"); } else { // We are running out of options g_log.error() << "No dark current algorithm provided to load [" << getPropertyValue("DarkCurrentFile") << "]: skipped!\n"; dark_result = " No dark current algorithm provided: skipped\n"; } } m_output_message += " |" + Poco::replace(dark_result, "\n", "\n |") + "\n"; // Look for solid angle correction algorithm if (reductionManager->existsProperty("SANSSolidAngleCorrection")) { IAlgorithm_sptr solidAlg = reductionManager->getProperty("SANSSolidAngleCorrection"); solidAlg->setChild(true); solidAlg->setProperty("InputWorkspace", rawFloodWS); solidAlg->setProperty("OutputWorkspace", rawFloodWS); solidAlg->execute(); std::string msg = "Solid angle correction applied\n"; if (solidAlg->existsProperty("OutputMessage")) msg = solidAlg->getPropertyValue("OutputMessage"); m_output_message += " |" + Poco::replace(msg, "\n", "\n |") + "\n"; } // Apply transmission correction as needed double floodTransmissionValue = getProperty("FloodTransmissionValue"); double floodTransmissionError = getProperty("FloodTransmissionError"); if (!isEmpty(floodTransmissionValue)) { g_log.debug() << "SANSSensitivityCorrection :: Applying transmission " "to flood field\n"; IAlgorithm_sptr transAlg = createChildAlgorithm("ApplyTransmissionCorrection"); transAlg->setProperty("InputWorkspace", rawFloodWS); transAlg->setProperty("OutputWorkspace", rawFloodWS); transAlg->setProperty("TransmissionValue", floodTransmissionValue); transAlg->setProperty("TransmissionError", floodTransmissionError); transAlg->setProperty("ThetaDependent", true); transAlg->execute(); rawFloodWS = transAlg->getProperty("OutputWorkspace"); m_output_message += " |Applied transmission to flood field\n"; } // Calculate detector sensitivity IAlgorithm_sptr effAlg = createChildAlgorithm("CalculateEfficiency"); effAlg->setProperty("InputWorkspace", rawFloodWS); const double minEff = getProperty("MinEfficiency"); const double maxEff = getProperty("MaxEfficiency"); const std::string maskFullComponent = getPropertyValue("MaskedFullComponent"); const std::string maskEdges = getPropertyValue("MaskedEdges"); const std::string maskComponent = getPropertyValue("MaskedComponent"); effAlg->setProperty("MinEfficiency", minEff); effAlg->setProperty("MaxEfficiency", maxEff); effAlg->setProperty("MaskedFullComponent", maskFullComponent); effAlg->setProperty("MaskedEdges", maskEdges); effAlg->setProperty("MaskedComponent", maskComponent); effAlg->execute(); floodWS = effAlg->getProperty("OutputWorkspace"); } else { floodWS = rawFloodWS; } // Patch as needed if (reductionManager->existsProperty("SensitivityPatchAlgorithm")) { IAlgorithm_sptr patchAlg = reductionManager->getProperty("SensitivityPatchAlgorithm"); patchAlg->setChild(true); patchAlg->setProperty("Workspace", floodWS); patchAlg->execute(); m_output_message += " |Sensitivity patch applied\n"; } floodWS->mutableRun().addProperty("is_sensitivity", 1, "", true); } std::string floodWSOutputName = getPropertyValue("OutputSensitivityWorkspace"); if (floodWSOutputName.empty()) { setPropertyValue("OutputSensitivityWorkspace", floodWSName); AnalysisDataService::Instance().addOrReplace(floodWSName, floodWS); reductionManager->declareProperty( Kernel::make_unique<WorkspaceProperty<>>(entryName, floodWSName, Direction::InOut)); reductionManager->setPropertyValue(entryName, floodWSName); reductionManager->setProperty(entryName, floodWS); } setProperty("OutputSensitivityWorkspace", floodWS); } progress.report(3, "Loaded flood field"); // Check whether we need to apply the correction to a workspace MatrixWorkspace_sptr inputWS = getProperty("InputWorkspace"); if (inputWS) { // Divide sample data by detector efficiency IAlgorithm_sptr divideAlg = createChildAlgorithm("Divide", 0.6, 0.7); divideAlg->setProperty("LHSWorkspace", inputWS); divideAlg->setProperty("RHSWorkspace", floodWS); divideAlg->executeAsChildAlg(); MatrixWorkspace_sptr outputWS = divideAlg->getProperty("OutputWorkspace"); // Copy over the efficiency's masked pixels to the reduced workspace IAlgorithm_sptr maskAlg = createChildAlgorithm("MaskDetectors", 0.75, 0.85); maskAlg->setProperty("Workspace", outputWS); maskAlg->setProperty("MaskedWorkspace", floodWS); maskAlg->executeAsChildAlg(); setProperty("OutputWorkspace", outputWS); } setProperty("OutputMessage", "Sensitivity correction computed\n" + m_output_message); progress.report("Performed sensitivity correction"); }