/** Process the Transmission workspaces in order to output them to Mantid. @param trans_gp: A vector with the pointers to the workspaces related to the transmission @param name: Name of the transmission. Only two names are allowed: sample/can. @param output_name: The name of the OutputWorkspace, in order to create the workspaces with similar names. */ void LoadCanSAS1D2::processTransmission( std::vector<MatrixWorkspace_sptr> &trans_gp, const std::string &name, const std::string &output_name) { std::string trans_wsname = std::string(output_name).append("_trans_").append(name); const std::string fileName = getPropertyValue("Filename"); std::string propertyWS; if (name == "sample") propertyWS = "TransmissionWorkspace"; else propertyWS = "TransmissionCanWorkspace"; const std::string doc = "The transmission workspace"; if (trans_gp.size() == 1) { MatrixWorkspace_sptr WS = trans_gp[0]; WS->mutableRun().addProperty("Filename", fileName); declareProperty(Kernel::make_unique<WorkspaceProperty<MatrixWorkspace>>( propertyWS, trans_wsname, Direction::Output), doc); setProperty(propertyWS, WS); } else if (trans_gp.size() > 1) { WorkspaceGroup_sptr group(new WorkspaceGroup); for (unsigned int i = 0; i < trans_gp.size(); i++) { MatrixWorkspace_sptr newWork = trans_gp[i]; newWork->mutableRun().addProperty("Filename", fileName); std::stringstream pname; std::stringstream name; pname << propertyWS << i; name << trans_wsname << i; declareProperty(Kernel::make_unique<WorkspaceProperty<MatrixWorkspace>>( pname.str(), name.str(), Direction::Output), doc); setProperty(pname.str(), newWork); group->addWorkspace(newWork); } std::string pname = std::string(propertyWS).append("GP"); declareProperty(Kernel::make_unique<WorkspaceProperty<WorkspaceGroup>>( pname, trans_wsname, Direction::Output), doc); setProperty(pname, group); } }
/** Execute the algorithm. */ void SetGoniometer::exec() { MatrixWorkspace_sptr ws = getProperty("Workspace"); std::string gonioDefined = getPropertyValue("Goniometers"); // Create the goniometer Goniometer gon; if(gonioDefined.compare("Universal") == 0) gon.makeUniversalGoniometer(); else for (size_t i=0; i< NUM_AXES; i++) { std::ostringstream propName; propName << "Axis" << i; std::string axisDesc = getPropertyValue(propName.str()); if (!axisDesc.empty()) { std::vector<std::string> tokens; boost::split( tokens, axisDesc, boost::algorithm::detail::is_any_ofF<char>(",")); if (tokens.size() != 5) throw std::invalid_argument("Wrong number of arguments to parameter " + propName.str() + ". Expected 5 comma-separated arguments."); std::string axisName = tokens[0]; axisName = Strings::strip(axisName); if (axisName.empty()) throw std::invalid_argument("The name must not be empty"); double x=0,y=0,z=0; if (!Strings::convert(tokens[1], x)) throw std::invalid_argument("Error converting string '" + tokens[1] + "' to a number."); if (!Strings::convert(tokens[2], y)) throw std::invalid_argument("Error converting string '" + tokens[2] + "' to a number."); if (!Strings::convert(tokens[3], z)) throw std::invalid_argument("Error converting string '" + tokens[3] + "' to a number."); V3D vec(x,y,z); if (vec.norm() < 1e-4) throw std::invalid_argument("Rotation axis vector should be non-zero!"); int ccw = 0; Strings::convert(tokens[4], ccw); if (ccw != 1 && ccw != -1) throw std::invalid_argument("The ccw parameter must be 1 (ccw) or -1 (cw) but no other value."); // Default to degrees gon.pushAxis( axisName, x, y, z, 0.0, ccw); } } if (gon.getNumberAxes() == 0) g_log.warning() << "Empty goniometer created; will always return an identity rotation matrix." << std::endl; // All went well, copy the goniometer into it. It will throw if the log values cannot be found try { ws->mutableRun().setGoniometer(gon, true); } catch (std::runtime_error &) { g_log.error("No log values for goniometers"); } }
/// 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. */ void LoadAscii::exec() { std::string filename = getProperty("Filename"); std::ifstream file(filename.c_str()); if (!file) { g_log.error("Unable to open file: " + filename); throw Exception::FileError("Unable to open file: ", filename); } std::string sepOption = getProperty("Separator"); m_columnSep = m_separatorIndex[sepOption]; // Process the header information. processHeader(file); // Read the data MatrixWorkspace_sptr outputWS = boost::dynamic_pointer_cast<MatrixWorkspace>(readData(file)); outputWS->mutableRun().addProperty("Filename", filename); setProperty("OutputWorkspace", outputWS); }
/** * Execute the algorithm */ void DefineGaugeVolume::exec() { // Get the XML definition const std::string shapeXML = getProperty("ShapeXML"); // Try creating the shape to make sure the input's valid boost::shared_ptr<Geometry::Object> shape_sptr = Geometry::ShapeFactory().createShape(shapeXML); if ( !shape_sptr->hasValidShape() ) { g_log.error("Invalid shape definition provided. Gauge Volume NOT added to workspace."); throw std::invalid_argument("Invalid shape definition provided."); } // Should we check that the volume defined is within the sample? Is this necessary? // Do we even have a way to do this? progress(0.5); // Add as an entry in the workspace's Run object, just as text. Overwrite if already present. const MatrixWorkspace_sptr workspace = getProperty("Workspace"); workspace->mutableRun().addProperty("GaugeVolume",shapeXML,true); progress(1); }
/** Execute the algorithm. */ void LoadNXSPE::exec() { std::string filename = getProperty("Filename"); // quicly check if it's really nxspe try { ::NeXus::File file(filename); std::string mainEntry = (*(file.getEntries().begin())).first; file.openGroup(mainEntry, "NXentry"); file.openData("definition"); if (identiferConfidence(file.getStrData()) < 1) { throw std::invalid_argument("Not NXSPE"); } file.close(); } catch (...) { throw std::invalid_argument("Not NeXus or not NXSPE"); } // Load the data ::NeXus::File file(filename); std::string mainEntry = (*(file.getEntries().begin())).first; file.openGroup(mainEntry, "NXentry"); file.openGroup("NXSPE_info", "NXcollection"); std::map<std::string, std::string> entries = file.getEntries(); std::vector<double> temporary; double fixed_energy, psi = 0.; if (!entries.count("fixed_energy")) { throw std::invalid_argument("fixed_energy field was not found"); } file.openData("fixed_energy"); file.getData(temporary); fixed_energy = temporary.at(0); file.closeData(); if (entries.count("psi")) { file.openData("psi"); file.getData(temporary); psi = temporary.at(0); file.closeData(); } int kikfscaling = 0; if (entries.count("ki_over_kf_scaling")) { file.openData("ki_over_kf_scaling"); std::vector<int> temporaryint; file.getData(temporaryint); kikfscaling = temporaryint.at(0); file.closeData(); } file.closeGroup(); // NXSPE_Info file.openGroup("data", "NXdata"); entries = file.getEntries(); if (!entries.count("data")) { throw std::invalid_argument("data field was not found"); } file.openData("data"); ::NeXus::Info info = file.getInfo(); std::size_t numSpectra = static_cast<std::size_t>(info.dims.at(0)); std::size_t numBins = static_cast<std::size_t>(info.dims.at(1)); std::vector<double> data; file.getData(data); file.closeData(); if (!entries.count("error")) { throw std::invalid_argument("error field was not found"); } file.openData("error"); std::vector<double> error; file.getData(error); file.closeData(); if (!entries.count("energy")) { throw std::invalid_argument("energy field was not found"); } file.openData("energy"); std::vector<double> energies; file.getData(energies); file.closeData(); if (!entries.count("azimuthal")) { throw std::invalid_argument("azimuthal field was not found"); } file.openData("azimuthal"); std::vector<double> azimuthal; file.getData(azimuthal); file.closeData(); if (!entries.count("azimuthal_width")) { throw std::invalid_argument("azimuthal_width field was not found"); } file.openData("azimuthal_width"); std::vector<double> azimuthal_width; file.getData(azimuthal_width); file.closeData(); if (!entries.count("polar")) { throw std::invalid_argument("polar field was not found"); } file.openData("polar"); std::vector<double> polar; file.getData(polar); file.closeData(); if (!entries.count("polar_width")) { throw std::invalid_argument("polar_width field was not found"); } file.openData("polar_width"); std::vector<double> polar_width; file.getData(polar_width); file.closeData(); // distance might not have been saved in all NXSPE files std::vector<double> distance; if (entries.count("distance")) { file.openData("distance"); file.getData(distance); file.closeData(); } file.closeGroup(); // data group file.closeGroup(); // Main entry file.close(); // check if dimensions of the vectors are correct if ((error.size() != data.size()) || (azimuthal.size() != numSpectra) || (azimuthal_width.size() != numSpectra) || (polar.size() != numSpectra) || (polar_width.size() != numSpectra) || ((energies.size() != numBins) && (energies.size() != numBins + 1))) { throw std::invalid_argument( "incompatible sizes of fields in the NXSPE file"); } MatrixWorkspace_sptr outputWS = boost::dynamic_pointer_cast<MatrixWorkspace>( WorkspaceFactory::Instance().create("Workspace2D", numSpectra, energies.size(), numBins)); // Need to get hold of the parameter map outputWS->getAxis(0)->unit() = UnitFactory::Instance().create("DeltaE"); outputWS->setYUnit("SpectraNumber"); // add logs outputWS->mutableRun().addLogData( new PropertyWithValue<double>("Ei", fixed_energy)); outputWS->mutableRun().addLogData(new PropertyWithValue<double>("psi", psi)); outputWS->mutableRun().addLogData(new PropertyWithValue<std::string>( "ki_over_kf_scaling", kikfscaling == 1 ? "true" : "false")); // Set Goniometer Geometry::Goniometer gm; gm.pushAxis("psi", 0, 1, 0, psi); outputWS->mutableRun().setGoniometer(gm, true); // generate instrument Geometry::Instrument_sptr instrument(new Geometry::Instrument("NXSPE")); outputWS->setInstrument(instrument); Geometry::ObjComponent *source = new Geometry::ObjComponent("source"); source->setPos(0.0, 0.0, -10.0); instrument->add(source); instrument->markAsSource(source); Geometry::ObjComponent *sample = new Geometry::ObjComponent("sample"); instrument->add(sample); instrument->markAsSamplePos(sample); Geometry::Object_const_sptr cuboid( createCuboid(0.1, 0.1, 0.1)); // FIXME: memory hog on rendering. Also, // make each detector separate size for (std::size_t i = 0; i < numSpectra; ++i) { double r = 1.0; if (!distance.empty()) { r = distance.at(i); } Kernel::V3D pos; pos.spherical(r, polar.at(i), azimuthal.at(i)); Geometry::Detector *det = new Geometry::Detector("pixel", static_cast<int>(i + 1), sample); det->setPos(pos); det->setShape(cuboid); instrument->add(det); instrument->markAsDetector(det); } Geometry::ParameterMap &pmap = outputWS->instrumentParameters(); std::vector<double>::iterator itdata = data.begin(), iterror = error.begin(), itdataend, iterrorend; API::Progress prog = API::Progress(this, 0.0, 0.9, numSpectra); for (std::size_t i = 0; i < numSpectra; ++i) { itdataend = itdata + numBins; iterrorend = iterror + numBins; outputWS->dataX(i) = energies; if ((!boost::math::isfinite(*itdata)) || (*itdata <= -1e10)) // masked bin { outputWS->dataY(i) = std::vector<double>(numBins, 0); outputWS->dataE(i) = std::vector<double>(numBins, 0); pmap.addBool(outputWS->getDetector(i)->getComponentID(), "masked", true); } else { outputWS->dataY(i) = std::vector<double>(itdata, itdataend); outputWS->dataE(i) = std::vector<double>(iterror, iterrorend); } itdata = (itdataend); iterror = (iterrorend); prog.report(); } setProperty("OutputWorkspace", outputWS); }
/** * Check if the file is SNS text; load it if it is, return false otherwise. * @return true if the file was a SNS style; false otherwise. */ bool LoadLog::LoadSNSText() { // Get the SNS-specific parameter std::vector<std::string> names = getProperty("Names"); std::vector<std::string> units = getProperty("Units"); // Get the input workspace and retrieve run from workspace. // the log file(s) will be loaded into the run object of the workspace const MatrixWorkspace_sptr localWorkspace = getProperty("Workspace"); // open log file std::ifstream inLogFile(m_filename.c_str()); // Get the first line std::string aLine; if (!Mantid::Kernel::Strings::extractToEOL(inLogFile,aLine)) return false; std::vector<double> cols; bool ret = SNSTextFormatColumns(aLine, cols); // Any error? if (!ret || cols.size() < 2) return false; size_t numCols = static_cast<size_t>(cols.size()-1); if (names.size() != numCols) throw std::invalid_argument("The Names parameter should have one fewer entry as the number of columns in a SNS-style text log file."); if ((!units.empty()) && (units.size() != numCols)) throw std::invalid_argument("The Units parameter should have either 0 entries or one fewer entry as the number of columns in a SNS-style text log file."); // Ok, create all the logs std::vector<TimeSeriesProperty<double>*> props; for(size_t i=0; i < numCols; i++) { TimeSeriesProperty<double>* p = new TimeSeriesProperty<double>(names[i]); if (units.size() == numCols) p->setUnits(units[i]); props.push_back(p); } // Go back to start inLogFile.seekg(0); while(Mantid::Kernel::Strings::extractToEOL(inLogFile,aLine)) { if (aLine.size() == 0) break; if (SNSTextFormatColumns(aLine, cols)) { if (cols.size() == numCols+1) { DateAndTime time(cols[0], 0.0); for(size_t i=0; i<numCols; i++) props[i]->addValue(time, cols[i+1]); } else throw std::runtime_error("Inconsistent number of columns while reading SNS-style text file."); } else throw std::runtime_error("Error while reading columns in SNS-style text file."); } // Now add all the full logs to the workspace for(size_t i=0; i < numCols; i++) { std::string name = props[i]->name(); if (localWorkspace->mutableRun().hasProperty(name)) { localWorkspace->mutableRun().removeLogData(name); g_log.information() << "Log data named " << name << " already existed and was overwritten.\n"; } localWorkspace->mutableRun().addLogData(props[i]); } return true; }
void HFIRLoad::exec() { // 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 the load algorithm isn't in the reduction properties, add it if (!reductionManager->existsProperty("LoadAlgorithm")) { AlgorithmProperty *algProp = new AlgorithmProperty("LoadAlgorithm"); algProp->setValue(toString()); reductionManager->declareProperty(algProp); } const std::string fileName = getPropertyValue("Filename"); // Output log m_output_message = ""; const double wavelength_input = getProperty("Wavelength"); const double wavelength_spread_input = getProperty("WavelengthSpread"); IAlgorithm_sptr loadAlg = createChildAlgorithm("LoadSpice2D", 0, 0.2); loadAlg->setProperty("Filename", fileName); if (!isEmpty(wavelength_input)) { loadAlg->setProperty("Wavelength", wavelength_input); loadAlg->setProperty("WavelengthSpread", wavelength_spread_input); } try { loadAlg->executeAsChildAlg(); } catch (...) { // The only way HFIR SANS can load Nexus files is if it's loading data that // has already // been processed. This will only happen with sensitivity data. // So if we make it here and are still unable to load the file, assume it's // a sensitivity file. // This will cover the special case where the instrument scientist uses a // reduced data set // as a sensitivity data set. g_log.warning() << "Unable to load file as a SPICE file. Trying to load as " "a Nexus file." << std::endl; loadAlg = createChildAlgorithm("Load", 0, 0.2); loadAlg->setProperty("Filename", fileName); loadAlg->executeAsChildAlg(); Workspace_sptr dataWS_tmp = loadAlg->getProperty("OutputWorkspace"); MatrixWorkspace_sptr dataWS = boost::dynamic_pointer_cast<MatrixWorkspace>(dataWS_tmp); dataWS->mutableRun().addProperty("is_sensitivity", 1, "", true); setProperty<MatrixWorkspace_sptr>("OutputWorkspace", dataWS); g_log.notice() << "Successfully loaded " << fileName << " and setting sensitivity flag to True" << std::endl; return; } Workspace_sptr dataWS_tmp = loadAlg->getProperty("OutputWorkspace"); dataWS = boost::dynamic_pointer_cast<MatrixWorkspace>(dataWS_tmp); // Get the sample-detector distance double sdd = 0.0; const double sample_det_dist = getProperty("SampleDetectorDistance"); if (!isEmpty(sample_det_dist)) { sdd = sample_det_dist; } else { Mantid::Kernel::Property *prop = dataWS->run().getProperty("sample-detector-distance"); Mantid::Kernel::PropertyWithValue<double> *dp = dynamic_cast<Mantid::Kernel::PropertyWithValue<double> *>(prop); sdd = *dp; // Modify SDD according to offset if given const double sample_det_offset = getProperty("SampleDetectorDistanceOffset"); if (!isEmpty(sample_det_offset)) { sdd += sample_det_offset; } } dataWS->mutableRun().addProperty("sample_detector_distance", sdd, "mm", true); // Move the detector to its correct position IAlgorithm_sptr mvAlg = createChildAlgorithm("MoveInstrumentComponent", 0.2, 0.4); mvAlg->setProperty<MatrixWorkspace_sptr>("Workspace", dataWS); mvAlg->setProperty("ComponentName", "detector1"); mvAlg->setProperty("Z", sdd / 1000.0); mvAlg->setProperty("RelativePosition", false); mvAlg->executeAsChildAlg(); g_log.information() << "Moving detector to " << sdd / 1000.0 << std::endl; m_output_message += " Detector position: " + Poco::NumberFormatter::format(sdd / 1000.0, 3) + " m\n"; // Compute beam diameter at the detector double src_to_sample = 0.0; try { src_to_sample = HFIRInstrument::getSourceToSampleDistance(dataWS); dataWS->mutableRun().addProperty("source-sample-distance", src_to_sample, "mm", true); m_output_message += " Computed SSD from number of guides: " + Poco::NumberFormatter::format(src_to_sample / 1000.0, 3) + " \n"; } catch (...) { Mantid::Kernel::Property *prop = dataWS->run().getProperty("source-sample-distance"); Mantid::Kernel::PropertyWithValue<double> *dp = dynamic_cast<Mantid::Kernel::PropertyWithValue<double> *>(prop); src_to_sample = *dp; m_output_message += " Could not compute SSD from number of guides, taking: " + Poco::NumberFormatter::format(src_to_sample / 1000.0, 3) + " \n"; }; Mantid::Kernel::Property *prop = dataWS->run().getProperty("sample-aperture-diameter"); Mantid::Kernel::PropertyWithValue<double> *dp = dynamic_cast<Mantid::Kernel::PropertyWithValue<double> *>(prop); double sample_apert = *dp; prop = dataWS->run().getProperty("source-aperture-diameter"); dp = dynamic_cast<Mantid::Kernel::PropertyWithValue<double> *>(prop); double source_apert = *dp; const double beam_diameter = sdd / src_to_sample * (source_apert + sample_apert) + sample_apert; dataWS->mutableRun().addProperty("beam-diameter", beam_diameter, "mm", true); // Move the beam center to its proper position const bool noBeamCenter = getProperty("NoBeamCenter"); if (!noBeamCenter) { m_center_x = getProperty("BeamCenterX"); m_center_y = getProperty("BeamCenterY"); if (isEmpty(m_center_x) && isEmpty(m_center_y)) { if (reductionManager->existsProperty("LatestBeamCenterX") && reductionManager->existsProperty("LatestBeamCenterY")) { m_center_x = reductionManager->getProperty("LatestBeamCenterX"); m_center_y = reductionManager->getProperty("LatestBeamCenterY"); } } moveToBeamCenter(); // Add beam center to reduction properties, as the last beam center position // that was used. // This will give us our default position next time. if (!reductionManager->existsProperty("LatestBeamCenterX")) reductionManager->declareProperty( new PropertyWithValue<double>("LatestBeamCenterX", m_center_x)); else reductionManager->setProperty("LatestBeamCenterX", m_center_x); if (!reductionManager->existsProperty("LatestBeamCenterY")) reductionManager->declareProperty( new PropertyWithValue<double>("LatestBeamCenterY", m_center_y)); else reductionManager->setProperty("LatestBeamCenterY", m_center_y); dataWS->mutableRun().addProperty("beam_center_x", m_center_x, "pixel", true); dataWS->mutableRun().addProperty("beam_center_y", m_center_y, "pixel", true); m_output_message += " Beam center: " + Poco::NumberFormatter::format(m_center_x, 1) + ", " + Poco::NumberFormatter::format(m_center_y, 1) + "\n"; } else { HFIRInstrument::getDefaultBeamCenter(dataWS, m_center_x, m_center_y); dataWS->mutableRun().addProperty("beam_center_x", m_center_x, "pixel", true); dataWS->mutableRun().addProperty("beam_center_y", m_center_y, "pixel", true); m_output_message += " Default beam center: " + Poco::NumberFormatter::format(m_center_x, 1) + ", " + Poco::NumberFormatter::format(m_center_y, 1) + "\n"; } setProperty<MatrixWorkspace_sptr>( "OutputWorkspace", boost::dynamic_pointer_cast<MatrixWorkspace>(dataWS)); setPropertyValue("OutputMessage", m_output_message); }
/** Reads the header of a .peaks file * @param outWS :: the workspace in which to place the information * @param in :: stream of the input file * @param T0 :: Time offset * @return the first word on the next line */ std::string LoadIsawPeaks::readHeader( PeaksWorkspace_sptr outWS, std::ifstream& in, double &T0 ) { std::string tag; std::string r = getWord( in , false ); if( r.length() < 1 ) throw std::logic_error( std::string( "No first line of Peaks file" ) ); if( r.compare( std::string( "Version:" ) ) != 0 ) throw std::logic_error( std::string( "No Version: on first line of Peaks file" ) ); std::string C_version = getWord( in , false ); if( C_version.length() < 1 ) throw std::logic_error( std::string( "No Version for Peaks file" ) ); getWord( in , false ); //tag // cppcheck-suppress unreadVariable std::string C_Facility = getWord( in , false ); getWord( in , false ); //tag std::string C_Instrument = getWord( in , false ); if( C_Instrument.length() < 1 ) throw std::logic_error( std::string( "No Instrument for Peaks file" ) ); // Date: use the current date/time if not found Kernel::DateAndTime C_experimentDate; std::string date; tag = getWord( in , false ); if(tag.empty()) date = Kernel::DateAndTime::getCurrentTime().toISO8601String(); else if(tag == "Date:") date = getWord( in , false ); readToEndOfLine( in , true ); // Now we load the instrument using the name and date MatrixWorkspace_sptr tempWS = WorkspaceFactory::Instance().create("Workspace2D", 1, 1, 1); tempWS->mutableRun().addProperty<std::string>("run_start", date); IAlgorithm_sptr loadInst= createChildAlgorithm("LoadInstrument"); loadInst->setPropertyValue("InstrumentName", C_Instrument); loadInst->setProperty<MatrixWorkspace_sptr> ("Workspace", tempWS); loadInst->executeAsChildAlg(); // Populate the instrument parameters in this workspace - this works around a bug tempWS->populateInstrumentParameters(); Geometry::Instrument_const_sptr instr_old = tempWS->getInstrument() ; boost::shared_ptr< ParameterMap > map(new ParameterMap()); Geometry::Instrument_const_sptr instr ( new Geometry::Instrument(instr_old->baseInstrument(), map )); //std::string s; std::string s = ApplyCalibInfo(in, "", instr_old, instr, T0); outWS->setInstrument( instr); // Now skip all lines on L1, detector banks, etc. until we get to a block of peaks. They start with 0. // readToEndOfLine( in , true ); // readToEndOfLine( in , true ); // s = getWord(in, false); while (s != "0" && in.good()) { readToEndOfLine( in , true ); s = getWord(in, false); } return s; }
/** Executes the algorithm * */ void SumSpectra::exec() { // Try and retrieve the optional properties m_MinSpec = getProperty("StartWorkspaceIndex"); m_MaxSpec = getProperty("EndWorkspaceIndex"); const std::vector<int> indices_list = getProperty("ListOfWorkspaceIndices"); keepMonitors = getProperty("IncludeMonitors"); // Get the input workspace MatrixWorkspace_const_sptr localworkspace = getProperty("InputWorkspace"); numberOfSpectra = static_cast<int>(localworkspace->getNumberHistograms()); this->yLength = static_cast<int>(localworkspace->blocksize()); // Check 'StartSpectrum' is in range 0-numberOfSpectra if ( m_MinSpec > numberOfSpectra ) { g_log.warning("StartWorkspaceIndex out of range! Set to 0."); m_MinSpec = 0; } if (indices_list.empty()) { //If no list was given and no max, just do all. if ( isEmpty(m_MaxSpec) ) m_MaxSpec = numberOfSpectra-1; } //Something for m_MaxSpec was given but it is out of range? if (!isEmpty(m_MaxSpec) && ( m_MaxSpec > numberOfSpectra-1 || m_MaxSpec < m_MinSpec )) { g_log.warning("EndWorkspaceIndex out of range! Set to max Workspace Index"); m_MaxSpec = numberOfSpectra; } //Make the set of indices to sum up from the list this->indices.insert(indices_list.begin(), indices_list.end()); //And add the range too, if any if (!isEmpty(m_MaxSpec)) { for (int i = m_MinSpec; i <= m_MaxSpec; i++) this->indices.insert(i); } //determine the output spectrum id m_outSpecId = this->getOutputSpecId(localworkspace); g_log.information() << "Spectra remapping gives single spectra with spectra number: " << m_outSpecId << "\n"; m_CalculateWeightedSum = getProperty("WeightedSum"); EventWorkspace_const_sptr eventW = boost::dynamic_pointer_cast<const EventWorkspace>(localworkspace); if (eventW) { m_CalculateWeightedSum = false; this->execEvent(eventW, this->indices); } else { //-------Workspace 2D mode ----- // Create the 2D workspace for the output MatrixWorkspace_sptr outputWorkspace = API::WorkspaceFactory::Instance().create(localworkspace, 1,localworkspace->readX(0).size(),this->yLength); size_t numSpectra(0); // total number of processed spectra size_t numMasked(0); // total number of the masked and skipped spectra size_t numZeros(0); // number of spectra which have 0 value in the first column (used in special cases of evaluating how good Puasonian statistics is) Progress progress(this, 0, 1, this->indices.size()); // This is the (only) output spectrum ISpectrum * outSpec = outputWorkspace->getSpectrum(0); // Copy over the bin boundaries outSpec->dataX() = localworkspace->readX(0); //Build a new spectra map outSpec->setSpectrumNo(m_outSpecId); outSpec->clearDetectorIDs(); if (localworkspace->id() == "RebinnedOutput") { this->doRebinnedOutput(outputWorkspace, progress,numSpectra,numMasked,numZeros); } else { this->doWorkspace2D(localworkspace, outSpec, progress,numSpectra,numMasked,numZeros); } // Pointer to sqrt function MantidVec& YError = outSpec->dataE(); typedef double (*uf)(double); uf rs=std::sqrt; //take the square root of all the accumulated squared errors - Assumes Gaussian errors std::transform(YError.begin(), YError.end(), YError.begin(), rs); outputWorkspace->generateSpectraMap(); // set up the summing statistics outputWorkspace->mutableRun().addProperty("NumAllSpectra",int(numSpectra),"",true); outputWorkspace->mutableRun().addProperty("NumMaskSpectra",int(numMasked),"",true); outputWorkspace->mutableRun().addProperty("NumZeroSpectra",int(numZeros),"",true); // Assign it to the output workspace property setProperty("OutputWorkspace", outputWorkspace); } }
/** 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(); }
/** Executes the algorithm. Reading in Log entries from the Nexus file * * @throw Mantid::Kernel::Exception::FileError Thrown if file is not recognised to be a Nexus datafile * @throw std::runtime_error Thrown with Workspace problems */ void LoadMuonLog::exec() { // Retrieve the filename from the properties and perform some initial checks on the filename m_filename = getPropertyValue("Filename"); MuonNexusReader nxload; if ( nxload.readLogData(m_filename) != 0 ) { g_log.error("In LoadMuonLog: " + m_filename + " can not be opened."); throw Exception::FileError("File does not exist:" , m_filename); } // Get the input workspace and retrieve sample from workspace. // the log data will be loaded into the Sample container of the workspace // Also set the sample name at this point, as part of the sample related log data. const MatrixWorkspace_sptr localWorkspace = getProperty("Workspace"); localWorkspace->mutableSample().setName(nxload.getSampleName()); // Attempt to load the content of each NXlog section into the Sample object // Assumes that MuonNexusReader has read all log data // Two cases of double or string data allowed Progress prog(this,0.0,1.0,nxload.numberOfLogs()); for (int i = 0; i < nxload.numberOfLogs(); i++) { std::string logName=nxload.getLogName(i); TimeSeriesProperty<double> *l_PropertyDouble = new TimeSeriesProperty<double>(logName); TimeSeriesProperty<std::string> *l_PropertyString = new TimeSeriesProperty<std::string>(logName); std::vector<double> logTimes; // Read log file into Property which is then stored in Sample object if(!nxload.logTypeNumeric(i)) { std::string logValue; std::time_t logTime; for( int j=0;j<nxload.getLogLength(i);j++) { nxload.getLogStringValues(i,j,logTime,logValue); l_PropertyString->addValue(logTime, logValue); } } else { double logValue; std::time_t logTime; for( int j=0;j<nxload.getLogLength(i);j++) { nxload.getLogValues(i,j,logTime,logValue); l_PropertyDouble->addValue(logTime, logValue); } } // store Property in Sample object and delete unused object if ( nxload.logTypeNumeric(i) ) { localWorkspace->mutableRun().addLogData(l_PropertyDouble); delete l_PropertyString; } else { localWorkspace->mutableRun().addLogData(l_PropertyString); delete l_PropertyDouble; } prog.report(); } // end for // operation was a success and ended normally return; }
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"); }