/** Validates input properties. * @return A map of input properties as keys and (error) messages as values. */ std::map<std::string, std::string> NormaliseToMonitor::validateInputs() { std::map<std::string, std::string> issues; // Check where the monitor spectrum should come from const Property *monSpecProp = getProperty("MonitorSpectrum"); const Property *monIDProp = getProperty("MonitorID"); MatrixWorkspace_const_sptr monWS = getProperty("MonitorWorkspace"); // something has to be set if (monSpecProp->isDefault() && !monWS && monIDProp->isDefault()) { const std::string mess("Either MonitorSpectrum, MonitorID or " "MonitorWorkspace has to be provided."); issues["MonitorSpectrum"] = mess; issues["MonitorID"] = mess; issues["MonitorWorkspace"] = mess; } const double intMin = getProperty("IntegrationRangeMin"); const double intMax = getProperty("IntegrationRangeMax"); if (!isEmpty(intMin) && !isEmpty(intMax)) { if (intMin > intMax) { issues["IntegrationRangeMin"] = "Range minimum set to a larger value than maximum."; issues["IntegrationRangeMax"] = "Range maximum set to a smaller value than minimum."; } } if (monWS && monSpecProp->isDefault()) { const int monIndex = getProperty("MonitorWorkspaceIndex"); if (monIndex < 0) { issues["MonitorWorkspaceIndex"] = "A workspace index cannot be negative."; } else if (monWS->getNumberHistograms() <= static_cast<size_t>(monIndex)) { issues["MonitorWorkspaceIndex"] = "The MonitorWorkspace must contain the MonitorWorkspaceIndex."; } MatrixWorkspace_const_sptr inWS = getProperty("InputWorkspace"); if (monWS->getInstrument()->getName() != inWS->getInstrument()->getName()) { issues["MonitorWorkspace"] = "The Input and Monitor workspaces must come " "from the same instrument."; } if (monWS->getAxis(0)->unit()->unitID() != inWS->getAxis(0)->unit()->unitID()) { issues["MonitorWorkspace"] = "The Input and Monitor workspaces must have the same unit"; } } return issues; }
/** * Set default background and rebinning properties for a given instument * and analyser * * @param ws :: Mantid workspace containing the loaded instument */ void ISISCalibration::calSetDefaultResolution(MatrixWorkspace_const_sptr ws) { auto inst = ws->getInstrument(); auto analyser = inst->getStringParameter("analyser"); if(analyser.size() > 0) { auto comp = inst->getComponentByName(analyser[0]); if(!comp) return; auto params = comp->getNumberParameter("resolution", true); //Set the default instrument resolution if(params.size() > 0) { double res = params[0]; // Set default rebinning bounds QPair<double, double> peakRange(-res*10, res*10); auto resPeak = m_uiForm.ppResolution->getRangeSelector("ResPeak"); setRangeSelector(resPeak, m_properties["ResELow"], m_properties["ResEHigh"], peakRange); // Set default background bounds QPair<double, double> backgroundRange(-res*9, -res*8); auto resBackground = m_uiForm.ppResolution->getRangeSelector("ResBackground"); setRangeSelector(resBackground, m_properties["ResStart"], m_properties["ResEnd"], backgroundRange); } } }
void ALCDataLoadingPresenter::updateAvailableInfo() { Workspace_sptr loadedWs; double firstGoodData = 0, timeZero = 0; try //... to load the first run { IAlgorithm_sptr load = AlgorithmManager::Instance().create("LoadMuonNexus"); load->setChild(true); // Don't want workspaces in the ADS load->setProperty("Filename", m_view->firstRun()); // We need logs only but we have to use LoadMuonNexus // (can't use LoadMuonLogs as not all the logs would be // loaded), so we load the minimum amount of data, i.e., one spectrum load->setPropertyValue("SpectrumMin", "1"); load->setPropertyValue("SpectrumMax", "1"); load->setPropertyValue("OutputWorkspace", "__NotUsed"); load->execute(); loadedWs = load->getProperty("OutputWorkspace"); firstGoodData = load->getProperty("FirstGoodData"); timeZero = load->getProperty("TimeZero"); } catch (...) { m_view->setAvailableLogs(std::vector<std::string>()); // Empty logs list m_view->setAvailablePeriods( std::vector<std::string>()); // Empty period list m_view->setTimeLimits(0, 0); // "Empty" time limits return; } // Set logs MatrixWorkspace_const_sptr ws = MuonAnalysisHelper::firstPeriod(loadedWs); std::vector<std::string> logs; const auto &properties = ws->run().getProperties(); for (auto it = properties.begin(); it != properties.end(); ++it) { logs.push_back((*it)->name()); } m_view->setAvailableLogs(logs); // Set periods size_t numPeriods = MuonAnalysisHelper::numPeriods(loadedWs); std::vector<std::string> periods; for (size_t i = 0; i < numPeriods; i++) { std::stringstream buffer; buffer << i + 1; periods.push_back(buffer.str()); } m_view->setAvailablePeriods(periods); // Set time limits if this is the first data loaded (will both be zero) if (auto timeLimits = m_view->timeRange()) { if (std::abs(timeLimits->first) < 0.0001 && std::abs(timeLimits->second) < 0.0001) { m_view->setTimeLimits(firstGoodData - timeZero, ws->readX(0).back()); } } // Update number of detectors for this new first run m_numDetectors = ws->getInstrument()->getNumberDetectors(); }
/** Initialise a workspace from its parent * This sets values such as title, instrument, units, sample, spectramap. * This does NOT copy any data. * * @param parent :: the parent workspace * @param child :: the child workspace * @param differentSize :: A flag to indicate if the two workspace will be different sizes */ void WorkspaceFactoryImpl::initializeFromParent(const MatrixWorkspace_const_sptr parent, const MatrixWorkspace_sptr child, const bool differentSize) const { child->setTitle(parent->getTitle()); child->setComment(parent->getComment()); child->setInstrument(parent->getInstrument()); // This call also copies the SHARED POINTER to the parameter map // This call will (should) perform a COPY of the parameter map. child->instrumentParameters(); child->m_sample = parent->m_sample; child->m_run = parent->m_run; child->setYUnit(parent->m_YUnit); child->setYUnitLabel(parent->m_YUnitLabel); child->isDistribution(parent->isDistribution()); // Only copy the axes over if new sizes are not given if ( !differentSize ) { // Only copy mask map if same size for now. Later will need to check continued validity. child->m_masks = parent->m_masks; } // Same number of histograms = copy over the spectra data if (parent->getNumberHistograms() == child->getNumberHistograms()) { for (size_t wi=0; wi<parent->getNumberHistograms(); wi++) { ISpectrum * childSpec = child->getSpectrum(wi); const ISpectrum * parentSpec = parent->getSpectrum(wi); // Copy spectrum number and detector IDs childSpec->copyInfoFrom(*parentSpec); } } // deal with axis for (size_t i = 0; i < parent->m_axes.size(); ++i) { const size_t newAxisLength = child->getAxis(i)->length(); const size_t oldAxisLength = parent->getAxis(i)->length(); if ( !differentSize || newAxisLength == oldAxisLength ) { // Need to delete the existing axis created in init above delete child->m_axes[i]; // Now set to a copy of the parent workspace's axis child->m_axes[i] = parent->m_axes[i]->clone(child.get()); } else { if (! parent->getAxis(i)->isSpectra()) // WHY??? { delete child->m_axes[i]; // Call the 'different length' clone variant child->m_axes[i] = parent->m_axes[i]->clone(newAxisLength,child.get()); } } } return; }
// read the monitors list from the workspace and try to do it once for any // particular ws; bool MonIDPropChanger::monitorIdReader( MatrixWorkspace_const_sptr inputWS) const { // no workspace if (!inputWS) return false; // no instrument Geometry::Instrument_const_sptr pInstr = inputWS->getInstrument(); if (!pInstr) return false; // are these monitors really there? std::vector<detid_t> monitorIDList = pInstr->getMonitors(); { const auto &specInfo = inputWS->spectrumInfo(); std::set<detid_t> idsInWorkspace; size_t i = 0; // Loop over spectra, but finish early if we find everything while (i < specInfo.size() && idsInWorkspace.size() < monitorIDList.size()) { if (specInfo.isMonitor(i)) idsInWorkspace.insert(specInfo.detector(i).getID()); ++i; } monitorIDList = std::vector<detid_t>(idsInWorkspace.begin(), idsInWorkspace.end()); } if (monitorIDList.empty()) { if (iExistingAllowedValues.empty()) { return false; } else { iExistingAllowedValues.clear(); return true; } } // are known values the same as the values we have just identified? if (iExistingAllowedValues.size() != monitorIDList.size()) { iExistingAllowedValues.clear(); iExistingAllowedValues.assign(monitorIDList.begin(), monitorIDList.end()); return true; } // the monitor list has the same size as before. Is it equivalent to the // existing one? bool values_redefined = false; for (size_t i = 0; i < monitorIDList.size(); i++) { if (iExistingAllowedValues[i] != monitorIDList[i]) { values_redefined = true; iExistingAllowedValues[i] = monitorIDList[i]; } } return values_redefined; }
double ConvertSpectrumAxis::getEfixed(const Mantid::Geometry::IDetector &detector, MatrixWorkspace_const_sptr inputWS, int emode) const { double efixed(0); double efixedProp = getProperty("Efixed"); if (efixedProp != EMPTY_DBL()) { efixed = efixedProp; g_log.debug() << "Detector: " << detector.getID() << " Efixed: " << efixed << "\n"; } else { if (emode == 1) { if (inputWS->run().hasProperty("Ei")) { Kernel::Property *p = inputWS->run().getProperty("Ei"); Kernel::PropertyWithValue<double> *doublep = dynamic_cast<Kernel::PropertyWithValue<double> *>(p); if (doublep) { efixed = (*doublep)(); } else { efixed = 0.0; g_log.warning() << "Efixed could not be found for detector " << detector.getID() << ", set to 0.0\n"; } } else { efixed = 0.0; g_log.warning() << "Efixed could not be found for detector " << detector.getID() << ", set to 0.0\n"; } } else if (emode == 2) { std::vector<double> efixedVec = detector.getNumberParameter("Efixed"); if (efixedVec.empty()) { int detid = detector.getID(); IDetector_const_sptr detectorSingle = inputWS->getInstrument()->getDetector(detid); efixedVec = detectorSingle->getNumberParameter("Efixed"); } if (!efixedVec.empty()) { efixed = efixedVec.at(0); g_log.debug() << "Detector: " << detector.getID() << " EFixed: " << efixed << "\n"; } else { efixed = 0.0; g_log.warning() << "Efixed could not be found for detector " << detector.getID() << ", set to 0.0\n"; } } } return efixed; }
/** Test a workspace for compatibility with others on the basis of the arguments provided. @param ws : Workspace to test @param xUnitID : Unit id for the x axis @param YUnit : Y Unit @param dist : flag indicating that the workspace should be a distribution @param instrument : name of the instrument @throws an invalid argument if a full match is not acheived. */ void MergeRuns::testCompatibility(MatrixWorkspace_const_sptr ws, const std::string &xUnitID, const std::string &YUnit, const bool dist, const std::string instrument) const { std::string errors; if (ws->getAxis(0)->unit()->unitID() != xUnitID) errors += "different X units; "; if (ws->YUnit() != YUnit) errors += "different Y units; "; if (ws->isDistribution() != dist) errors += "not all distribution or all histogram type; "; if (ws->getInstrument()->getName() != instrument) errors += "different instrument names; "; if (errors.length() > 0) { g_log.error("Input workspaces are not compatible: " + errors); throw std::invalid_argument("Input workspaces are not compatible: " + errors); } }
double ConvertSpectrumAxis2::getEfixed(IDetector_const_sptr detector, MatrixWorkspace_const_sptr inputWS, int emode) const { double efixed(0); double efixedProp = getProperty("Efixed"); if (efixedProp != EMPTY_DBL()) { efixed = efixedProp; g_log.debug() << "Detector: " << detector->getID() << " Efixed: " << efixed << "\n"; } else { if (emode == 1) { if (inputWS->run().hasProperty("Ei")) { efixed = inputWS->run().getLogAsSingleValue("Ei"); } else { throw std::invalid_argument("Could not retrieve Efixed from the " "workspace. Please provide a value."); } } else if (emode == 2) { std::vector<double> efixedVec = detector->getNumberParameter("Efixed"); if (efixedVec.empty()) { int detid = detector->getID(); IDetector_const_sptr detectorSingle = inputWS->getInstrument()->getDetector(detid); efixedVec = detectorSingle->getNumberParameter("Efixed"); } if (!efixedVec.empty()) { efixed = efixedVec.at(0); g_log.debug() << "Detector: " << detector->getID() << " EFixed: " << efixed << "\n"; } else { g_log.warning() << "Efixed could not be found for detector " << detector->getID() << ", please provide a value\n"; throw std::invalid_argument("Could not retrieve Efixed from the " "detector. Please provide a value."); } } } return efixed; }
/** Executes the algorithm * * @throw Exception::FileError If the grouping file cannot be opened or read successfully * @throw runtime_error If unable to run one of the Child Algorithms successfully */ void ReadGroupsFromFile::exec() { MatrixWorkspace_const_sptr ws = getProperty("InstrumentWorkspace"); // Get the instrument. Instrument_const_sptr inst = ws->getInstrument(); // Create a copy (without the data) of the workspace - it will contain the Workspace2D_sptr localWorkspace = boost::dynamic_pointer_cast<Workspace2D>(WorkspaceFactory::Instance().create(ws, ws->getNumberHistograms(), 2, 1)); if (!localWorkspace) throw std::runtime_error("Failed when creating a Workspace2D from the input!"); const std::string groupfile=getProperty("GroupingFilename"); if ( ! groupfile.empty() ) { std::string filename(groupfile); std::transform(filename.begin(), filename.end(), filename.begin(), tolower); if ( filename.find(".xml") != std::string::npos ) { readXMLGroupingFile(groupfile); } else { readGroupingFile(groupfile); } } // Get the instrument. const int64_t nHist=localWorkspace->getNumberHistograms(); // Determine whether the user wants to see unselected detectors or not const std::string su=getProperty("ShowUnselected"); bool showunselected=(!su.compare("True")); bool success=false; for (int64_t i=0;i<nHist;i++) { ISpectrum * spec = localWorkspace->getSpectrum(i); const std::set<detid_t> & dets = spec->getDetectorIDs(); if (dets.empty()) // Nothing { spec->dataY()[0]=0.0; continue; } // Find the first detector ID in the list calmap::const_iterator it=calibration.find(*dets.begin()); if (it==calibration.end()) //Could not find the detector { spec->dataY()[0]=0.0; continue; } if (showunselected) { if (((*it).second).second==0) spec->dataY()[0]=0.0; else spec->dataY()[0]=static_cast<double>(((*it).second).first); } else spec->dataY()[0]=static_cast<double>(((*it).second).first); if (!success) success=true; //At least one detector is found in the cal file } progress(1); calibration.clear(); if (!success) //Do some cleanup { localWorkspace.reset(); throw std::runtime_error("Fail to found a detector in "+groupfile+" existing in instrument "+inst->getName()); } setProperty("OutputWorkspace",localWorkspace); return; }
/** * Execute the algorithm */ void ExtractMask::exec() { MatrixWorkspace_const_sptr inputWS = getProperty("InputWorkspace"); Geometry::Instrument_const_sptr instr = inputWS->getInstrument(); // convert input to a mask workspace DataObjects::MaskWorkspace_const_sptr inputMaskWS = boost::dynamic_pointer_cast<const DataObjects::MaskWorkspace>(inputWS); bool inputWSIsSpecial = bool(inputMaskWS); if (inputWSIsSpecial) { g_log.notice() << "Input workspace is a MaskWorkspace.\n"; } DataObjects::MaskWorkspace_sptr maskWS; // List masked of detector IDs std::vector<detid_t> detectorList; if (instr) { const int nHist = static_cast<int>(inputWS->getNumberHistograms()); // Create a new workspace for the results, copy from the input to ensure that we copy over the instrument and current masking maskWS = DataObjects::MaskWorkspace_sptr(new DataObjects::MaskWorkspace(inputWS)); maskWS->setTitle(inputWS->getTitle()); Progress prog(this,0.0,1.0,nHist); MantidVecPtr xValues; xValues.access() = MantidVec(1, 0.0); PARALLEL_FOR2(inputWS, maskWS) for( int i = 0; i < nHist; ++i ) { PARALLEL_START_INTERUPT_REGION bool inputIsMasked(false); IDetector_const_sptr inputDet; try { inputDet = inputWS->getDetector(i); if (inputWSIsSpecial) { inputIsMasked = inputMaskWS->isMaskedIndex(i); } // special workspaces can mysteriously have the mask bit set // but only check if we haven't already decided to mask the spectrum if( !inputIsMasked && inputDet->isMasked() ) { inputIsMasked = true; } if (inputIsMasked) { detid_t id = inputDet->getID(); PARALLEL_CRITICAL(name) { detectorList.push_back(id); } } } catch(Kernel::Exception::NotFoundError &) { inputIsMasked = false; } maskWS->setMaskedIndex(i, inputIsMasked); prog.report(); PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION // Clear all the "masked" bits on the output masked workspace Geometry::ParameterMap & pmap = maskWS->instrumentParameters(); pmap.clearParametersByName("masked"); } else // no instrument { // TODO should fill this in throw std::runtime_error("No instrument");
/** Executes the algorithm * * @throw Exception::FileError If the grouping file cannot be opened or read successfully * @throw runtime_error If unable to run one of the Child Algorithms successfully */ void CreateDummyCalFile::exec() { // Get the input workspace MatrixWorkspace_const_sptr inputW = getProperty("InputWorkspace"); if (!inputW) throw std::invalid_argument("No InputWorkspace"); //Get some stuff from the input workspace Instrument_const_sptr inst = inputW->getInstrument(); std::string instname = inst->getName(); // Check that the instrument is in store // Get only the first 3 letters std::string instshort=instname; std::transform(instshort.begin(),instshort.end(),instshort.begin(),toupper); instshort=instshort+"_Definition.xml"; // Determine the search directory for XML instrument definition files (IDFs) std::string directoryName = Kernel::ConfigService::Instance().getInstrumentDirectory(); // Set up the DOM parser and parse xml file DOMParser pParser; Document* pDoc; try { pDoc = pParser.parse(directoryName+instshort); } catch(...) { g_log.error("Unable to parse file " + m_filename); throw Kernel::Exception::FileError("Unable to parse File:" , m_filename); } // Get pointer to root element Element* pRootElem = pDoc->documentElement(); if ( !pRootElem->hasChildNodes() ) { g_log.error("XML file: " + m_filename + "contains no root element."); throw Kernel::Exception::InstrumentDefinitionError("No root element in XML instrument file", m_filename); } // Handle used in the singleton constructor for instrument file should append the value // of the last-modified tag inside the file to determine if it is already in memory so that // changes to the instrument file will cause file to be reloaded. auto temp = instshort + pRootElem->getAttribute("last-modified");// Generate the mangled name by hand (old-style) // If instrument not in store, insult the user if (!API::InstrumentDataService::Instance().doesExist(temp)) { Mantid::Geometry::IDFObject idf(directoryName+instshort); temp = idf.getMangledName(); // new style. if (!API::InstrumentDataService::Instance().doesExist(temp)) { g_log.error("Instrument "+instshort+" is not present in data store."); throw std::runtime_error("Instrument "+instshort+" is not present in data store."); } } // Get the names of groups groups=instname; // Split the names of the group and insert in a vector, throw if group empty std::vector<std::string> vgroups; boost::split( vgroups, instname, boost::algorithm::detail::is_any_ofF<char>(",/*")); if (vgroups.empty()) { g_log.error("Could not determine group names. Group names should be separated by / or ,"); throw std::runtime_error("Could not determine group names. Group names should be separated by / or ,"); } // Assign incremental number to each group std::map<std::string,int> group_map; int index=0; for (std::vector<std::string>::const_iterator it=vgroups.begin(); it!=vgroups.end(); ++it) group_map[(*it)]=++index; // Not needed anymore vgroups.clear(); // Find Detectors that belong to groups typedef boost::shared_ptr<const Geometry::ICompAssembly> sptr_ICompAss; typedef boost::shared_ptr<const Geometry::IComponent> sptr_IComp; typedef boost::shared_ptr<const Geometry::IDetector> sptr_IDet; std::queue< std::pair<sptr_ICompAss,int> > assemblies; sptr_ICompAss current=boost::dynamic_pointer_cast<const Geometry::ICompAssembly>(inst); sptr_IDet currentDet; sptr_IComp currentIComp; sptr_ICompAss currentchild; int top_group, child_group; if (current.get()) { top_group=group_map[current->getName()]; // Return 0 if not in map assemblies.push(std::make_pair(current,top_group)); } std::string filename=getProperty("CalFilename"); // Plan to overwrite file, so do not check if it exists bool overwrite=false; int number=0; Progress prog(this,0.0,0.8,assemblies.size()); while(!assemblies.empty()) //Travel the tree from the instrument point { current=assemblies.front().first; top_group=assemblies.front().second; assemblies.pop(); int nchilds=current->nelements(); if (nchilds!=0) { for (int i=0; i<nchilds; ++i) { currentIComp=(*(current.get()))[i]; // Get child currentDet=boost::dynamic_pointer_cast<const Geometry::IDetector>(currentIComp); if (currentDet.get())// Is detector { if (overwrite) // Map will contains udet as the key instrcalib[currentDet->getID()]=std::make_pair(number++,top_group); else // Map will contains the entry number as the key instrcalib[number++]=std::make_pair(currentDet->getID(),top_group); } else // Is an assembly, push in the queue { currentchild=boost::dynamic_pointer_cast<const Geometry::ICompAssembly>(currentIComp); if (currentchild.get()) { child_group=group_map[currentchild->getName()]; if (child_group==0) child_group=top_group; assemblies.push(std::make_pair(currentchild,child_group)); } } } } prog.report(); } // Write the results in a file saveGroupingFile(filename,overwrite); progress(0.2); return; }
/** Constructor with workspace argument * * This constructor directly takes a matrix workspace and extracts instrument *and run information. * * @param matrixWorkspace :: Workspace with a valid POLDI instrument and run *information */ PoldiInstrumentAdapter::PoldiInstrumentAdapter( const MatrixWorkspace_const_sptr &matrixWorkspace) { initializeFromInstrumentAndRun(matrixWorkspace->getInstrument(), matrixWorkspace->run()); }
void SANSDirectBeamScaling::exec() { MatrixWorkspace_const_sptr inputWS = getProperty("InputWorkspace"); const double beamRadius = getProperty("BeamRadius"); const double attTrans = getProperty("AttenuatorTransmission"); const double attTransErr = getProperty("AttenuatorTransmissionError"); // Extract the required spectra into separate workspaces std::vector<detid_t> udet; std::vector<size_t> index; udet.push_back(getProperty("BeamMonitor")); // Convert UDETs to workspace indices inputWS->getIndicesFromDetectorIDs(udet,index); if (index.size() < 1) { g_log.debug() << "inputWS->getIndicesFromDetectorIDs() returned empty\n"; throw std::invalid_argument("Could not find the incident beam monitor spectra\n"); } const int64_t numHists = inputWS->getNumberHistograms(); Progress progress(this,0.0,1.0,numHists); // Number of X bins const int64_t xLength = inputWS->readY(0).size(); // Monitor counts double monitor = 0.0; const MantidVec& MonIn = inputWS->readY(index[0]); for (int64_t j = 0; j < xLength; j++) monitor += MonIn[j]; const V3D sourcePos = inputWS->getInstrument()->getSource()->getPos(); double counts = 0.0; double error = 0.0; int nPixels = 0; // Sample-detector distance for the contributing pixels double sdd = 0.0; for (int64_t i = 0; i < int64_t(numHists); ++i) { IDetector_const_sptr det; try { det = inputWS->getDetector(i); } catch (Exception::NotFoundError&) { g_log.warning() << "Spectrum index " << i << " has no detector assigned to it - discarding" << std::endl; continue; } // Skip if we have a monitor or if the detector is masked. if ( det->isMonitor() || det->isMasked() ) continue; const MantidVec& YIn = inputWS->readY(i); const MantidVec& EIn = inputWS->readE(i); // Sum up all the counts V3D pos = det->getPos() - V3D(sourcePos.X(), sourcePos.Y(), 0.0); const double pixelDistance = pos.Z(); pos.setZ(0.0); if (pos.norm() <= beamRadius) { // Correct data for all X bins for (int64_t j = 0; j < xLength; j++) { counts += YIn[j]; error += EIn[j]*EIn[j]; } nPixels += 1; sdd += pixelDistance; } progress.report("Absolute Scaling"); } // Get the average SDD for the counted pixels, and transform to mm. sdd = sdd/nPixels*1000.0; error = std::sqrt(error); // Transform from m to mm double sourceAperture = getProperty("SourceApertureRadius"); sourceAperture *= 1000.0; // Transform from m to mm double sampleAperture = getProperty("SampleApertureRadius"); sampleAperture *= 1000.0; //TODO: replace this by some meaningful value const double KCG2FluxPerMon_SUGAR = 1.0; // Solid angle correction scale in 1/(cm^2)/steradian double solidAngleCorrScale = sdd/(M_PI*sourceAperture*sampleAperture); solidAngleCorrScale = solidAngleCorrScale*solidAngleCorrScale*100.0; // Scaling factor in n/(monitor count)/(cm^2)/steradian double scale = counts/monitor*solidAngleCorrScale/KCG2FluxPerMon_SUGAR; double scaleErr = std::abs(error/monitor)*solidAngleCorrScale/KCG2FluxPerMon_SUGAR; scaleErr = std::abs(scale/attTrans)*sqrt( (scaleErr/scale)*(scaleErr/scale) +(attTransErr/attTrans)*(attTransErr/attTrans) ); scale /= attTrans; std::vector<double> output; output.push_back(scale); output.push_back(scaleErr); setProperty("ScaleFactor", output); }
void FindDetectorsInShape::exec() { // Get the input workspace const MatrixWorkspace_const_sptr WS = getProperty("Workspace"); bool includeMonitors = getProperty("IncludeMonitors"); std::string shapeXML = getProperty("ShapeXML"); //convert into a Geometry object Geometry::ShapeFactory sFactory; boost::shared_ptr<Geometry::Object> shape_sptr = sFactory.createShape(shapeXML); //get the instrument out of the workspace Instrument_const_sptr instrument_sptr = WS->getInstrument(); //To get all the detector ID's detid2det_map allDetectors; instrument_sptr->getDetectors(allDetectors); std::vector<int> foundDets; //progress detid2det_map::size_type objCmptCount = allDetectors.size(); int iprogress_step = static_cast<int>(objCmptCount / 100); if (iprogress_step == 0) iprogress_step = 1; int iprogress=0; //Now go through all detid2det_map::iterator it; detid2det_map::const_iterator it_end = allDetectors.end(); for (it = allDetectors.begin(); it != it_end; it++) { Geometry::IDetector_const_sptr det = it->second; //attempt to dynamic cast up to an IDetector boost::shared_ptr<const Geometry::IDetector> detector_sptr = boost::dynamic_pointer_cast<const Geometry::IDetector>(it->second); if (detector_sptr) { if ((includeMonitors) || (!detector_sptr->isMonitor())) { //check if the centre of this item is within the user defined shape if (shape_sptr->isValid(detector_sptr->getPos())) { //shape encloses this objectComponent g_log.debug()<<"Detector contained in shape " << detector_sptr->getID() << std::endl; foundDets.push_back(detector_sptr->getID()); } } } iprogress++; if (iprogress % iprogress_step == 0) { progress(static_cast<double>(iprogress)/static_cast<double>(objCmptCount)); interruption_point(); } } setProperty("DetectorList",foundDets); }
void Qxy::exec() { MatrixWorkspace_const_sptr inputWorkspace = getProperty("InputWorkspace"); MatrixWorkspace_const_sptr waveAdj = getProperty("WavelengthAdj"); MatrixWorkspace_const_sptr pixelAdj = getProperty("PixelAdj"); const bool doGravity = getProperty("AccountForGravity"); const bool doSolidAngle = getProperty("SolidAngleWeighting"); //throws if we don't have common binning or another incompatibility Qhelper helper; helper.examineInput(inputWorkspace, waveAdj, pixelAdj); g_log.debug() << "All input workspaces were found to be valid\n"; // Create the output Qx-Qy grid MatrixWorkspace_sptr outputWorkspace = this->setUpOutputWorkspace(inputWorkspace); // Will also need an identically-sized workspace to hold the solid angle/time bin masked weight MatrixWorkspace_sptr weights = WorkspaceFactory::Instance().create(outputWorkspace); // Copy the X values from the output workspace to the solidAngles one cow_ptr<MantidVec> axis; axis.access() = outputWorkspace->readX(0); for ( size_t i = 0; i < weights->getNumberHistograms(); ++i ) weights->setX(i,axis); const size_t numSpec = inputWorkspace->getNumberHistograms(); const size_t numBins = inputWorkspace->blocksize(); // the samplePos is often not (0, 0, 0) because the instruments components are moved to account for the beam centre const V3D samplePos = inputWorkspace->getInstrument()->getSample()->getPos(); // Set the progress bar (1 update for every one percent increase in progress) Progress prog(this, 0.05, 1.0, numSpec); // PARALLEL_FOR2(inputWorkspace,outputWorkspace) for (int64_t i = 0; i < int64_t(numSpec); ++i) { // PARALLEL_START_INTERUPT_REGION // Get the pixel relating to this spectrum IDetector_const_sptr det; try { det = inputWorkspace->getDetector(i); } catch (Exception::NotFoundError&) { g_log.warning() << "Spectrum index " << i << " has no detector assigned to it - discarding" << std::endl; // Catch if no detector. Next line tests whether this happened - test placed // outside here because Mac Intel compiler doesn't like 'continue' in a catch // in an openmp block. } // If no detector found or if it's masked or a monitor, skip onto the next spectrum if ( !det || det->isMonitor() || det->isMasked() ) continue; //get the bins that are included inside the RadiusCut/WaveCutcut off, those to calculate for const size_t wavStart = helper.waveLengthCutOff(inputWorkspace, getProperty("RadiusCut"), getProperty("WaveCut"), i); if (wavStart >= inputWorkspace->readY(i).size()) { // all the spectra in this detector are out of range continue; } V3D detPos = det->getPos()-samplePos; // these will be re-calculated if gravity is on but without gravity there is no need double phi = atan2(detPos.Y(),detPos.X()); double a = cos(phi); double b = sin(phi); double sinTheta = sin( inputWorkspace->detectorTwoTheta(det)/2.0 ); // Get references to the data for this spectrum const MantidVec& X = inputWorkspace->readX(i); const MantidVec& Y = inputWorkspace->readY(i); const MantidVec& E = inputWorkspace->readE(i); const MantidVec& axis = outputWorkspace->readX(0); // the solid angle of the detector as seen by the sample is used for normalisation later on double angle = det->solidAngle(samplePos); // some bins are masked completely or partially, the following vector will contain the fractions MantidVec maskFractions; if ( inputWorkspace->hasMaskedBins(i) ) { // go through the set and convert it to a vector const MatrixWorkspace::MaskList& mask = inputWorkspace->maskedBins(i); maskFractions.resize(numBins, 1.0); MatrixWorkspace::MaskList::const_iterator it, itEnd(mask.end()); for (it = mask.begin(); it != itEnd; ++it) { // The weight for this masked bin is 1 minus the degree to which this bin is masked maskFractions[it->first] -= it->second; } } double maskFraction(1); // this object is not used if gravity correction is off, but it is only constructed once per spectrum GravitySANSHelper grav; if (doGravity) { grav = GravitySANSHelper(inputWorkspace, det); } for (int j = static_cast<int>(numBins)-1; j >= static_cast<int>(wavStart); --j) { if( j < 0 ) break; // Be careful with counting down. Need a better fix but this will work for now const double binWidth = X[j+1]-X[j]; // Calculate the wavelength at the mid-point of this bin const double wavLength = X[j]+(binWidth)/2.0; if (doGravity) { // SANS instruments must have their y-axis pointing up, show the detector position as where the neutron would be without gravity sinTheta = grav.calcComponents(wavLength, a, b); } // Calculate |Q| for this bin const double Q = 4.0*M_PI*sinTheta/wavLength; // Now get the x & y components of Q. const double Qx = a*Q; // Test whether they're in range, if not go to next spectrum. if ( Qx < axis.front() || Qx >= axis.back() ) break; const double Qy = b*Q; if ( Qy < axis.front() || Qy >= axis.back() ) break; // Find the indices pointing to the place in the 2D array where this bin's contents should go const MantidVec::difference_type xIndex = std::upper_bound(axis.begin(),axis.end(),Qx) - axis.begin() - 1; const int yIndex = static_cast<int>( std::upper_bound(axis.begin(),axis.end(),Qy) - axis.begin() - 1); // PARALLEL_CRITICAL(qxy) /* Write to shared memory - must protect */ { // the data will be copied to this bin in the output array double & outputBinY = outputWorkspace->dataY(yIndex)[xIndex]; double & outputBinE = outputWorkspace->dataE(yIndex)[xIndex]; if ( boost::math::isnan(outputBinY)) { outputBinY = outputBinE = 0; } // Add the contents of the current bin to the 2D array. outputBinY += Y[j]; // add the errors in quadranture outputBinE = std::sqrt( (outputBinE*outputBinE) + (E[j]*E[j]) ); // account for masked bins if ( ! maskFractions.empty() ) { maskFraction = maskFractions[j]; } // add the total weight for this bin in the weights workspace, // in an equivalent bin to where the data was stored // first take into account the product of contributions to the weight which have // no errors double weight = 0.0; if(doSolidAngle) weight = maskFraction*angle; else weight = maskFraction; // then the product of contributions which have errors, i.e. optional // pixelAdj and waveAdj contributions if (pixelAdj && waveAdj) { weights->dataY(yIndex)[xIndex] += weight*pixelAdj->readY(i)[0]*waveAdj->readY(0)[j]; const double pixelYSq = pixelAdj->readY(i)[0]*pixelAdj->readY(i)[0]; const double pixelESq = pixelAdj->readE(i)[0]*pixelAdj->readE(i)[0]; const double waveYSq = waveAdj->readY(0)[j]*waveAdj->readY(0)[j]; const double waveESq = waveAdj->readE(0)[j]*waveAdj->readE(0)[j]; // add product of errors from pixelAdj and waveAdj (note no error on weight is assumed) weights->dataE(yIndex)[xIndex] += weight*weight*(waveESq*pixelYSq + pixelESq*waveYSq); } else if (pixelAdj) { weights->dataY(yIndex)[xIndex] += weight*pixelAdj->readY(i)[0]; const double pixelE = weight*pixelAdj->readE(i)[0]; // add error from pixelAdj weights->dataE(yIndex)[xIndex] += pixelE*pixelE; } else if(waveAdj) { weights->dataY(yIndex)[xIndex] += weight*waveAdj->readY(0)[j]; const double waveE = weight*waveAdj->readE(0)[j]; // add error from waveAdj weights->dataE(yIndex)[xIndex] += waveE*waveE; } else weights->dataY(yIndex)[xIndex] += weight; } } // loop over single spectrum prog.report("Calculating Q"); // PARALLEL_END_INTERUPT_REGION } // loop over all spectra // PARALLEL_CHECK_INTERUPT_REGION // take sqrt of error weight values // left to be executed here for computational efficiency size_t numHist = weights->getNumberHistograms(); for (size_t i = 0; i < numHist; i++) { for (size_t j = 0; j < weights->dataE(i).size(); j++) { weights->dataE(i)[j] = sqrt(weights->dataE(i)[j]); } } bool doOutputParts = getProperty("OutputParts"); if (doOutputParts) { // copy outputworkspace before it gets further modified MatrixWorkspace_sptr ws_sumOfCounts = WorkspaceFactory::Instance().create(outputWorkspace); for (size_t i = 0; i < ws_sumOfCounts->getNumberHistograms(); i++) { ws_sumOfCounts->dataX(i) = outputWorkspace->dataX(i); ws_sumOfCounts->dataY(i) = outputWorkspace->dataY(i); ws_sumOfCounts->dataE(i) = outputWorkspace->dataE(i); } helper.outputParts(this, ws_sumOfCounts, weights); } // Divide the output data by the solid angles outputWorkspace /= weights; outputWorkspace->isDistribution(true); // Count of the number of empty cells MatrixWorkspace::const_iterator wsIt(*outputWorkspace); int emptyBins = 0; for (;wsIt != wsIt.end(); ++wsIt) { if (wsIt->Y() < 1.0e-12) ++emptyBins; } // Log the number of empty bins g_log.notice() << "There are a total of " << emptyBins << " (" << (100*emptyBins)/(outputWorkspace->size()) << "%) empty Q bins.\n"; }
void EQSANSMonitorTOF::exec() { MatrixWorkspace_const_sptr inputWS = getProperty("InputWorkspace"); // Now create the output workspace MatrixWorkspace_sptr outputWS = getProperty("OutputWorkspace"); if ( outputWS != inputWS ) { outputWS = WorkspaceFactory::Instance().create(inputWS); setProperty("OutputWorkspace",outputWS); } // Get the nominal sample-to-detector distance (in mm) // const double MD = MONITORPOS/1000.0; // Get the monitor const std::vector<detid_t> monitor_list = inputWS->getInstrument()->getMonitors(); if (monitor_list.size() != 1) { g_log.error() << "EQSANS workspace does not have exactly ones monitor! This should not happen" << std::endl; } IDetector_const_sptr mon; try { mon = inputWS->getInstrument()->getDetector(monitor_list[0]); } catch (Exception::NotFoundError&) { g_log.error() << "Spectrum index " << monitor_list[0] << " has no detector assigned to it - discarding" << std::endl; return; } // Get the source to monitor distance in mm double source_z = inputWS->getInstrument()->getSource()->getPos().Z(); double monitor_z = mon->getPos().Z(); double source_to_monitor = (monitor_z - source_z)*1000.0; // Calculate the frame width double frequency = dynamic_cast<TimeSeriesProperty<double>*>(inputWS->run().getLogData("frequency"))->getStatistics().mean; double tof_frame_width = 1.0e6/frequency; // Determine whether we need frame skipping or not by checking the chopper speed bool frame_skipping = false; const double chopper_speed = dynamic_cast<TimeSeriesProperty<double>*>(inputWS->run().getLogData("Speed1"))->getStatistics().mean; if (std::fabs(chopper_speed-frequency/2.0)<1.0) frame_skipping = true; // Get TOF offset // this is the call to the chopper code to say where // the start of the data frame is relative to the native facility frame double frame_tof0 = getTofOffset(inputWS, frame_skipping, source_to_monitor); // Calculate the frame width // none of this changes in response to just looking at the monitor double tmp_frame_width = frame_skipping ? tof_frame_width * 2.0 : tof_frame_width; double frame_offset=0.0; if (frame_tof0 >= tmp_frame_width) frame_offset = tmp_frame_width * ( (int)( frame_tof0/tmp_frame_width ) ); // Find the new binning first const MantidVec XIn = inputWS->readX(0); // Copy here to avoid holding on to reference for too long (problem with managed workspaces) // Since we are swapping the low-TOF and high-TOF regions around the cutoff value, // there is the potential for having an overlap between the two regions. We exclude // the region beyond a single frame by considering only the first 1/60 sec of the // TOF histogram. (Bins 1 to 1666, as opposed to 1 to 2000) const int nTOF = static_cast<int>(XIn.size()); // Loop through each bin to find the cutoff where the TOF distribution wraps around int cutoff = 0; double threshold = frame_tof0-frame_offset; int tof_bin_range = 0; double frame = 1000000.0/frequency; for (int i=0; i<nTOF; i++) { if (XIn[i] < threshold) cutoff = i; if (XIn[i] < frame) tof_bin_range = i; } g_log.information() << "Cutoff=" << cutoff << "; Threshold=" << threshold << std::endl; g_log.information() << "Low TOFs: old = [" << (cutoff+1) << ", " << (tof_bin_range-2) << "] -> new = [0, " << (tof_bin_range-3-cutoff) << "]" << std::endl; g_log.information() << "High bin boundary of the Low TOFs: old = " << tof_bin_range-1 << "; new = " << (tof_bin_range-2-cutoff) << std::endl; g_log.information() << "High TOFs: old = [0, " << (cutoff-1) << "] -> new = [" << (tof_bin_range-1-cutoff) << ", " << (tof_bin_range-2) << "]" << std::endl; g_log.information() << "Overlap: new = [" << (tof_bin_range-1) << ", " << (nTOF-2) << "]" << std::endl; // Keep a copy of the input data since we may end up overwriting it // if the input workspace is equal to the output workspace. // This is necessary since we are shuffling around the TOF bins. MantidVec YCopy = MantidVec(inputWS->readY(0)); MantidVec& YIn = YCopy; MantidVec ECopy = MantidVec(inputWS->readE(0)); MantidVec& EIn = ECopy; MantidVec& XOut = outputWS->dataX(0); MantidVec& YOut = outputWS->dataY(0); MantidVec& EOut = outputWS->dataE(0); // Here we modify the TOF according to the offset we calculated. // Since this correction will change the order of the TOF bins, // we do it in sequence so that we obtain a valid distribution // as our result (with increasing TOF values). // Move up the low TOFs for (int i=0; i<cutoff; i++) { XOut[i+tof_bin_range-1-cutoff] = XIn[i] + frame_offset + tmp_frame_width; YOut[i+tof_bin_range-1-cutoff] = YIn[i]; EOut[i+tof_bin_range-1-cutoff] = EIn[i]; } // Get rid of extra bins for (int i=tof_bin_range-1; i<nTOF-1; i++) { XOut[i] = XOut[i-1]+10.0; YOut[i] = 0.0; EOut[i] = 0.0; } XOut[nTOF-1] = XOut[nTOF-2]+10.0; // Move down the high TOFs for (int i=cutoff+1; i<tof_bin_range-1; i++) { XOut[i-cutoff-1] = XIn[i] + frame_offset; YOut[i-cutoff-1] = YIn[i]; EOut[i-cutoff-1] = EIn[i]; } // Don't forget the low boundary XOut[tof_bin_range-2-cutoff] = XIn[tof_bin_range] + frame_offset; // Zero out the cutoff bin, which no longer makes sense because // len(x) = len(y)+1 YOut[tof_bin_range-2-cutoff] = 0.0; EOut[tof_bin_range-2-cutoff] = 0.0; setProperty("OutputWorkspace",outputWS); }
void SofQWCentre::exec() { using namespace Geometry; MatrixWorkspace_const_sptr inputWorkspace = getProperty("InputWorkspace"); // Do the full check for common binning if (!WorkspaceHelpers::commonBoundaries(*inputWorkspace)) { g_log.error( "The input workspace must have common binning across all spectra"); throw std::invalid_argument( "The input workspace must have common binning across all spectra"); } std::vector<double> verticalAxis; MatrixWorkspace_sptr outputWorkspace = setUpOutputWorkspace( inputWorkspace, getProperty("QAxisBinning"), verticalAxis); setProperty("OutputWorkspace", outputWorkspace); // Holds the spectrum-detector mapping std::vector<specnum_t> specNumberMapping; std::vector<detid_t> detIDMapping; m_EmodeProperties.initCachedValues(*inputWorkspace, this); int emode = m_EmodeProperties.m_emode; // Get a pointer to the instrument contained in the workspace Instrument_const_sptr instrument = inputWorkspace->getInstrument(); // Get the distance between the source and the sample (assume in metres) IComponent_const_sptr source = instrument->getSource(); IComponent_const_sptr sample = instrument->getSample(); V3D beamDir = sample->getPos() - source->getPos(); beamDir.normalize(); try { double l1 = source->getDistance(*sample); g_log.debug() << "Source-sample distance: " << l1 << '\n'; } catch (Exception::NotFoundError &) { g_log.error("Unable to calculate source-sample distance"); throw Exception::InstrumentDefinitionError( "Unable to calculate source-sample distance", inputWorkspace->getTitle()); } // Conversion constant for E->k. k(A^-1) = sqrt(energyToK*E(meV)) const double energyToK = 8.0 * M_PI * M_PI * PhysicalConstants::NeutronMass * PhysicalConstants::meV * 1e-20 / (PhysicalConstants::h * PhysicalConstants::h); // Loop over input workspace bins, reassigning data to correct bin in output // qw workspace const size_t numHists = inputWorkspace->getNumberHistograms(); const size_t numBins = inputWorkspace->blocksize(); Progress prog(this, 0.0, 1.0, numHists); for (int64_t i = 0; i < int64_t(numHists); ++i) { try { // Now get the detector object for this histogram IDetector_const_sptr spectrumDet = inputWorkspace->getDetector(i); if (spectrumDet->isMonitor()) continue; const double efixed = m_EmodeProperties.getEFixed(*spectrumDet); // For inelastic scattering the simple relationship q=4*pi*sinTheta/lambda // does not hold. In order to // be completely general we must calculate the momentum transfer by // calculating the incident and final // wave vectors and then use |q| = sqrt[(ki - kf)*(ki - kf)] DetectorGroup_const_sptr detGroup = boost::dynamic_pointer_cast<const DetectorGroup>(spectrumDet); std::vector<IDetector_const_sptr> detectors; if (detGroup) { detectors = detGroup->getDetectors(); } else { detectors.push_back(spectrumDet); } const size_t numDets = detectors.size(); // cache to reduce number of static casts const double numDets_d = static_cast<double>(numDets); const auto &Y = inputWorkspace->y(i); const auto &E = inputWorkspace->e(i); const auto &X = inputWorkspace->x(i); // Loop over the detectors and for each bin calculate Q for (size_t idet = 0; idet < numDets; ++idet) { IDetector_const_sptr det = detectors[idet]; // Calculate kf vector direction and then Q for each energy bin V3D scatterDir = (det->getPos() - sample->getPos()); scatterDir.normalize(); for (size_t j = 0; j < numBins; ++j) { const double deltaE = 0.5 * (X[j] + X[j + 1]); // Compute ki and kf wave vectors and therefore q = ki - kf double ei(0.0), ef(0.0); if (emode == 1) { ei = efixed; ef = efixed - deltaE; if (ef < 0) { std::string mess = "Energy transfer requested in Direct mode exceeds incident " "energy.\n Found for det ID: " + std::to_string(idet) + " bin No " + std::to_string(j) + " with Ei=" + boost::lexical_cast<std::string>(efixed) + " and energy transfer: " + boost::lexical_cast<std::string>(deltaE); throw std::runtime_error(mess); } } else { ei = efixed + deltaE; ef = efixed; if (ef < 0) { std::string mess = "Incident energy of a neutron is negative. Are you trying to " "process Direct data in Indirect mode?\n Found for det ID: " + std::to_string(idet) + " bin No " + std::to_string(j) + " with efied=" + boost::lexical_cast<std::string>(efixed) + " and energy transfer: " + boost::lexical_cast<std::string>(deltaE); throw std::runtime_error(mess); } } if (ei < 0) throw std::runtime_error( "Negative incident energy. Check binning."); const V3D ki = beamDir * sqrt(energyToK * ei); const V3D kf = scatterDir * (sqrt(energyToK * (ef))); const double q = (ki - kf).norm(); // Test whether it's in range of the Q axis if (q < verticalAxis.front() || q > verticalAxis.back()) continue; // Find which q bin this point lies in const MantidVec::difference_type qIndex = std::upper_bound(verticalAxis.begin(), verticalAxis.end(), q) - verticalAxis.begin() - 1; // Add this spectra-detector pair to the mapping specNumberMapping.push_back( outputWorkspace->getSpectrum(qIndex).getSpectrumNo()); detIDMapping.push_back(det->getID()); // And add the data and it's error to that bin, taking into account // the number of detectors contributing to this bin outputWorkspace->mutableY(qIndex)[j] += Y[j] / numDets_d; // Standard error on the average outputWorkspace->mutableE(qIndex)[j] = sqrt((pow(outputWorkspace->e(qIndex)[j], 2) + pow(E[j], 2)) / numDets_d); } } } catch (Exception::NotFoundError &) { // Get to here if exception thrown when calculating distance to detector // Presumably, if we get to here the spectrum will be all zeroes anyway // (from conversion to E) continue; } prog.report(); } // If the input workspace was a distribution, need to divide by q bin width if (inputWorkspace->isDistribution()) this->makeDistribution(outputWorkspace, verticalAxis); // Set the output spectrum-detector mapping SpectrumDetectorMapping outputDetectorMap(specNumberMapping, detIDMapping); outputWorkspace->updateSpectraUsing(outputDetectorMap); // Replace any NaNs in outputWorkspace with zeroes if (this->getProperty("ReplaceNaNs")) { auto replaceNans = this->createChildAlgorithm("ReplaceSpecialValues"); replaceNans->setChild(true); replaceNans->initialize(); replaceNans->setProperty("InputWorkspace", outputWorkspace); replaceNans->setProperty("OutputWorkspace", outputWorkspace); replaceNans->setProperty("NaNValue", 0.0); replaceNans->setProperty("InfinityValue", 0.0); replaceNans->setProperty("BigNumberThreshold", DBL_MAX); replaceNans->execute(); } }