void MDHistoToWorkspace2D::checkW2D(Mantid::DataObjects::Workspace2D_sptr outWS) { size_t nSpectra = outWS->getNumberHistograms(); size_t length = outWS->blocksize(); MantidVec x, y, e; g_log.information() << "W2D has " << nSpectra << " histograms of length " << length; for (size_t i = 0; i < nSpectra; i++) { ISpectrum *spec = outWS->getSpectrum(i); x = spec->dataX(); y = spec->dataY(); e = spec->dataE(); if (x.size() != length) { g_log.information() << "Spectrum " << i << " x-size mismatch, is " << x.size() << " should be " << length << "\n"; } if (y.size() != length) { g_log.information() << "Spectrum " << i << " y-size mismatch, is " << y.size() << " should be " << length << "\n"; } if (e.size() != length) { g_log.information() << "Spectrum " << i << " e-size mismatch, is " << e.size() << " should be " << length << "\n"; } } }
/** 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; }
/** * Apply the created mapping to the workspace */ void CreateSimulationWorkspace::applyDetectorMapping() { size_t wsIndex(0); for (auto iter = m_detGroups.begin(); iter != m_detGroups.end(); ++iter) { ISpectrum *spectrum = m_outputWS->getSpectrum(wsIndex); spectrum->setSpectrumNo( static_cast<specid_t>(wsIndex + 1)); // Ensure a contiguous mapping spectrum->clearDetectorIDs(); spectrum->addDetectorIDs(iter->second); ++wsIndex; } }
/** * Execute the algorithm */ void ExtractMasking::exec() { MatrixWorkspace_const_sptr inputWS = getProperty("InputWorkspace"); const int nHist = static_cast<int>(inputWS->getNumberHistograms()); const int xLength(1), yLength(1); // Create a new workspace for the results, copy from the input to ensure that we copy over the instrument and current masking MatrixWorkspace_sptr outputWS = WorkspaceFactory::Instance().create(inputWS, nHist, xLength, yLength); Progress prog(this,0.0,1.0,nHist); MantidVecPtr xValues; xValues.access() = MantidVec(1, 0.0); PARALLEL_FOR2(inputWS, outputWS) for( int i = 0; i < nHist; ++i ) { PARALLEL_START_INTERUPT_REGION // Spectrum in the output workspace ISpectrum * outSpec = outputWS->getSpectrum(i); // Spectrum in the input workspace const ISpectrum * inSpec = inputWS->getSpectrum(i); // Copy X, spectrum number and detector IDs outSpec->setX(xValues); outSpec->copyInfoFrom(*inSpec); IDetector_const_sptr inputDet; bool inputIsMasked(false); try { inputDet = inputWS->getDetector(i); if( inputDet->isMasked() ) { inputIsMasked = true; } } catch(Kernel::Exception::NotFoundError &) { inputIsMasked = false; } if( inputIsMasked ) { outSpec->dataY()[0] = 0.0; outSpec->dataE()[0] = 0.0; } else { outSpec->dataY()[0] = 1.0; outSpec->dataE()[0] = 1.0; } prog.report(); PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION setProperty("OutputWorkspace", outputWS); }
void ConvertToMatrixWorkspace::exec() { MatrixWorkspace_const_sptr inputWorkspace = getProperty("InputWorkspace"); // Let's see if we have to do anything first. Basically we want to avoid the data copy if we can DataObjects::EventWorkspace_const_sptr eventW = boost::dynamic_pointer_cast<const DataObjects::EventWorkspace>(inputWorkspace); MatrixWorkspace_sptr outputWorkspace; if( eventW ) { g_log.information() << "Converting EventWorkspace to Workspace2D.\n"; const size_t numHists = inputWorkspace->getNumberHistograms(); Progress prog(this,0.0,1.0,numHists*2); // Sort the input workspace in-place by TOF. This can be faster if there are few event lists. eventW->sortAll(TOF_SORT, &prog); // Create the output workspace. This will copy many aspects fron the input one. outputWorkspace = WorkspaceFactory::Instance().create(inputWorkspace); // ...but not the data, so do that here. PARALLEL_FOR2(inputWorkspace,outputWorkspace) for (int64_t i = 0; i < (int64_t)numHists; ++i) { PARALLEL_START_INTERUPT_REGION const ISpectrum * inSpec = inputWorkspace->getSpectrum(i); ISpectrum * outSpec = outputWorkspace->getSpectrum(i); outSpec->copyInfoFrom(*inSpec); outSpec->setX(inSpec->ptrX()); outSpec->dataY() = inSpec->dataY(); outSpec->dataE() = inSpec->dataE(); prog.report("Binning"); PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION outputWorkspace->generateSpectraMap(); } else {
void GatherWorkspaces::execEvent() { // Every process in an MPI job must hit this next line or everything hangs! mpi::communicator included; // The communicator containing all processes // The root process needs to create a workspace of the appropriate size EventWorkspace_sptr outputWorkspace; if (included.rank() == 0) { g_log.debug() << "Total number of spectra is " << totalSpec << "\n"; // Create the workspace for the output outputWorkspace = boost::dynamic_pointer_cast<EventWorkspace>( API::WorkspaceFactory::Instance().create("EventWorkspace", sumSpec, numBins + hist, numBins)); // Copy geometry over. API::WorkspaceFactory::Instance().initializeFromParent( eventW, outputWorkspace, true); setProperty("OutputWorkspace", outputWorkspace); ExperimentInfo_sptr inWS = inputWorkspace; outputWorkspace->copyExperimentInfoFrom(inWS.get()); } for (size_t wi = 0; wi < totalSpec; wi++) { if (included.rank() == 0) { // How do we accumulate the data? std::string accum = this->getPropertyValue("AccumulationMethod"); std::vector<Mantid::DataObjects::EventList> out_values; gather(included, eventW->getEventList(wi), out_values, 0); for (int i = 0; i < included.size(); i++) { size_t index = wi; // accum == "Add" if (accum == "Append") index = wi + i * totalSpec; outputWorkspace->dataX(index) = eventW->readX(wi); outputWorkspace->getOrAddEventList(index) += out_values[i]; const ISpectrum *inSpec = eventW->getSpectrum(wi); ISpectrum *outSpec = outputWorkspace->getSpectrum(index); outSpec->clearDetectorIDs(); outSpec->addDetectorIDs(inSpec->getDetectorIDs()); } } else { gather(included, eventW->getEventList(wi), 0); } } }
/** * Only to be used if the KeepUnGrouped property is true, moves the spectra that were not selected * to be in a group to the end of the output spectrum * @param unGroupedSet :: list of WORKSPACE indexes that were included in a group * @param inputWS :: user selected input workspace for the algorithm * @param outputWS :: user selected output workspace for the algorithm * @param outIndex :: the next spectra index available after the grouped spectra */ void GroupDetectors2::moveOthers(const std::set<int64_t> &unGroupedSet, API::MatrixWorkspace_const_sptr inputWS, API::MatrixWorkspace_sptr outputWS, size_t outIndex) { g_log.debug() << "Starting to copy the ungrouped spectra" << std::endl; double prog4Copy = (1. - 1.*static_cast<double>(m_FracCompl))/static_cast<double>(unGroupedSet.size()); std::set<int64_t>::const_iterator copyFrIt = unGroupedSet.begin(); // go thorugh all the spectra in the input workspace for ( ; copyFrIt != unGroupedSet.end(); ++copyFrIt ) { if( *copyFrIt == USED ) continue; //Marked as not to be used size_t sourceIndex = static_cast<size_t>(*copyFrIt); // The input spectrum we'll copy const ISpectrum * inputSpec = inputWS->getSpectrum(sourceIndex); // Destination of the copying ISpectrum * outputSpec = outputWS->getSpectrum(outIndex); // Copy the data outputSpec->dataX() = inputSpec->dataX(); outputSpec->dataY() = inputSpec->dataY(); outputSpec->dataE() = inputSpec->dataE(); // Spectrum numbers etc. outputSpec->setSpectrumNo(inputSpec->getSpectrumNo()); outputSpec->clearDetectorIDs(); outputSpec->addDetectorIDs( inputSpec->getDetectorIDs() ); // go to the next free index in the output workspace outIndex ++; // make regular progress reports and check for cancelling the algorithm if ( outIndex % INTERVAL == 0 ) { m_FracCompl += INTERVAL*prog4Copy; if ( m_FracCompl > 1.0 ) { m_FracCompl = 1.0; } progress(m_FracCompl); interruption_point(); } } // Refresh the spectraDetectorMap outputWS->generateSpectraMap(); g_log.debug() << name() << " copied " << unGroupedSet.size()-1 << " ungrouped spectra\n"; }
/** 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; }
/** @ throw invalid_argument if the workspaces are not mututially compatible */ void Q1D2::exec() { m_dataWS = getProperty("DetBankWorkspace"); MatrixWorkspace_const_sptr waveAdj = getProperty("WavelengthAdj"); MatrixWorkspace_const_sptr pixelAdj = getProperty("PixelAdj"); MatrixWorkspace_const_sptr wavePixelAdj = getProperty("WavePixelAdj"); const bool doGravity = getProperty("AccountForGravity"); m_doSolidAngle = getProperty("SolidAngleWeighting"); //throws if we don't have common binning or another incompatibility Qhelper helper; helper.examineInput(m_dataWS, waveAdj, pixelAdj); // FIXME: how to examine the wavePixelAdj? g_log.debug() << "All input workspaces were found to be valid\n"; // normalization as a function of wavelength (i.e. centers of x-value bins) double const * const binNorms = waveAdj ? &(waveAdj->readY(0)[0]) : NULL; // error on the wavelength normalization double const * const binNormEs = waveAdj ? &(waveAdj->readE(0)[0]) : NULL; //define the (large number of) data objects that are going to be used in all iterations of the loop below // this will become the output workspace from this algorithm MatrixWorkspace_sptr outputWS = setUpOutputWorkspace(getProperty("OutputBinning")); const MantidVec & QOut = outputWS->readX(0); MantidVec & YOut = outputWS->dataY(0); MantidVec & EOutTo2 = outputWS->dataE(0); // normalisation that is applied to counts in each Q bin MantidVec normSum(YOut.size(), 0.0); // the error on the normalisation MantidVec normError2(YOut.size(), 0.0); const int numSpec = static_cast<int>(m_dataWS->getNumberHistograms()); Progress progress(this, 0.05, 1.0, numSpec+1); PARALLEL_FOR3(m_dataWS, outputWS, pixelAdj) for (int i = 0; i < numSpec; ++i) { PARALLEL_START_INTERUPT_REGION // Get the pixel relating to this spectrum IDetector_const_sptr det; try { det = m_dataWS->getDetector(i); } catch (Exception::NotFoundError&) { g_log.warning() << "Workspace index " << i << " (SpectrumIndex = " << m_dataWS->getSpectrum(i)->getSpectrumNo() << ") 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 detector is masked shouldn't be included 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 = waveLengthCutOff(i); const size_t wavStart = helper.waveLengthCutOff(m_dataWS, getProperty("RadiusCut"), getProperty("WaveCut"), i); if (wavStart >= m_dataWS->readY(i).size()) { // all the spectra in this detector are out of range continue; } const size_t numWavbins = m_dataWS->readY(i).size()-wavStart; // make just one call to new to reduce CPU overhead on each thread, access to these // three "arrays" is via iterators MantidVec _noDirectUseStorage_(3*numWavbins); //normalization term MantidVec::iterator norms = _noDirectUseStorage_.begin(); // the error on these weights, it contributes to the error calculation on the output workspace MantidVec::iterator normETo2s = norms + numWavbins; // the Q values calculated from input wavelength workspace MantidVec::iterator QIn = normETo2s + numWavbins; // the weighting for this input spectrum that is added to the normalization calculateNormalization(wavStart, i, pixelAdj, wavePixelAdj, binNorms, binNormEs, norms, normETo2s); // now read the data from the input workspace, calculate Q for each bin convertWavetoQ(i, doGravity, wavStart, QIn); // Pointers to the counts data and it's error MantidVec::const_iterator YIn = m_dataWS->readY(i).begin()+wavStart; MantidVec::const_iterator EIn = m_dataWS->readE(i).begin()+wavStart; //when finding the output Q bin remember that the input Q bins (from the convert to wavelength) start high and reduce MantidVec::const_iterator loc = QOut.end(); // sum the Q contributions from each individual spectrum into the output array const MantidVec::const_iterator end = m_dataWS->readY(i).end(); for( ; YIn != end; ++YIn, ++EIn, ++QIn, ++norms, ++normETo2s) { //find the output bin that each input y-value will fall into, remembering there is one more bin boundary than bins getQBinPlus1(QOut, *QIn, loc); // ignore counts that are out of the output range if ( (loc != QOut.begin()) && (loc != QOut.end()) ) { // the actual Q-bin to add something to const size_t bin = loc - QOut.begin() - 1; PARALLEL_CRITICAL(q1d_counts_sum) { YOut[bin] += *YIn; normSum[bin] += *norms; //these are the errors squared which will be summed and square rooted at the end EOutTo2[bin] += (*EIn)*(*EIn); normError2[bin] += *normETo2s; } } } PARALLEL_CRITICAL(q1d_spectra_map) { progress.report("Computing I(Q)"); // Add up the detector IDs in the output spectrum at workspace index 0 const ISpectrum * inSpec = m_dataWS->getSpectrum(i); ISpectrum * outSpec = outputWS->getSpectrum(0); outSpec->addDetectorIDs( inSpec->getDetectorIDs() ); } PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION bool doOutputParts = getProperty("OutputParts"); if (doOutputParts) { MatrixWorkspace_sptr ws_sumOfCounts = WorkspaceFactory::Instance().create(outputWS); ws_sumOfCounts->dataX(0) = outputWS->dataX(0); ws_sumOfCounts->dataY(0) = outputWS->dataY(0); for (size_t i = 0; i < outputWS->dataE(0).size(); i++) { ws_sumOfCounts->dataE(0)[i] = sqrt(outputWS->dataE(0)[i]); } MatrixWorkspace_sptr ws_sumOfNormFactors = WorkspaceFactory::Instance().create(outputWS); ws_sumOfNormFactors->dataX(0) = outputWS->dataX(0); for (size_t i = 0; i < ws_sumOfNormFactors->dataY(0).size(); i++) { ws_sumOfNormFactors->dataY(0)[i] = normSum[i]; ws_sumOfNormFactors->dataE(0)[i] = sqrt(normError2[i]); } helper.outputParts(this, ws_sumOfCounts, ws_sumOfNormFactors); } progress.report("Normalizing I(Q)"); //finally divide the number of counts in each output Q bin by its weighting normalize(normSum, normError2, YOut, EOutTo2); outputWS->updateSpectraUsingMap(); setProperty("OutputWorkspace",outputWS); }
/** * Move the user selected spectra in the input workspace into groups in the output workspace * @param inputWS :: user selected input workspace for the algorithm * @param outputWS :: user selected output workspace for the algorithm * @param prog4Copy :: the amount of algorithm progress to attribute to moving a single spectra * @return number of new grouped spectra */ size_t GroupDetectors2::formGroups( API::MatrixWorkspace_const_sptr inputWS, API::MatrixWorkspace_sptr outputWS, const double prog4Copy) { // get "Behaviour" string const std::string behaviour = getProperty("Behaviour"); int bhv = 0; if ( behaviour == "Average" ) bhv = 1; API::MatrixWorkspace_sptr beh = API::WorkspaceFactory::Instance().create( "Workspace2D", static_cast<int>(m_GroupSpecInds.size()), 1, 1); g_log.debug() << name() << ": Preparing to group spectra into " << m_GroupSpecInds.size() << " groups\n"; // where we are copying spectra to, we start copying to the start of the output workspace size_t outIndex = 0; // Only used for averaging behaviour. We may have a 1:1 map where a Divide would be waste as it would be just dividing by 1 bool requireDivide(false); for ( storage_map::const_iterator it = m_GroupSpecInds.begin(); it != m_GroupSpecInds.end() ; ++it ) { // This is the grouped spectrum ISpectrum * outSpec = outputWS->getSpectrum(outIndex); // The spectrum number of the group is the key outSpec->setSpectrumNo(it->first); // Start fresh with no detector IDs outSpec->clearDetectorIDs(); // Copy over X data from first spectrum, the bin boundaries for all spectra are assumed to be the same here outSpec->dataX() = inputWS->readX(0); // the Y values and errors from spectra being grouped are combined in the output spectrum // Keep track of number of detectors required for masking size_t nonMaskedSpectra(0); beh->dataX(outIndex)[0] = 0.0; beh->dataE(outIndex)[0] = 0.0; for( std::vector<size_t>::const_iterator wsIter = it->second.begin(); wsIter != it->second.end(); ++wsIter) { const size_t originalWI = *wsIter; // detectors to add to firstSpecNum const ISpectrum * fromSpectrum = inputWS->getSpectrum(originalWI); // Add up all the Y spectra and store the result in the first one // Need to keep the next 3 lines inside loop for now until ManagedWorkspace mru-list works properly MantidVec &firstY = outSpec->dataY(); MantidVec::iterator fYit; MantidVec::iterator fEit = outSpec->dataE().begin(); MantidVec::const_iterator Yit = fromSpectrum->dataY().begin(); MantidVec::const_iterator Eit = fromSpectrum->dataE().begin(); for (fYit = firstY.begin(); fYit != firstY.end(); ++fYit, ++fEit, ++Yit, ++Eit) { *fYit += *Yit; // Assume 'normal' (i.e. Gaussian) combination of errors *fEit = std::sqrt( (*fEit)*(*fEit) + (*Eit)*(*Eit) ); } // detectors to add to the output spectrum outSpec->addDetectorIDs(fromSpectrum->getDetectorIDs() ); try { Geometry::IDetector_const_sptr det = inputWS->getDetector(originalWI); if( !det->isMasked() ) ++nonMaskedSpectra; } catch(Exception::NotFoundError&) { // If a detector cannot be found, it cannot be masked ++nonMaskedSpectra; } } if( nonMaskedSpectra == 0 ) ++nonMaskedSpectra; // Avoid possible divide by zero if(!requireDivide) requireDivide = (nonMaskedSpectra > 1); beh->dataY(outIndex)[0] = static_cast<double>(nonMaskedSpectra); // make regular progress reports and check for cancelling the algorithm if ( outIndex % INTERVAL == 0 ) { m_FracCompl += INTERVAL*prog4Copy; if ( m_FracCompl > 1.0 ) m_FracCompl = 1.0; progress(m_FracCompl); interruption_point(); } outIndex ++; } // Refresh the spectraDetectorMap outputWS->generateSpectraMap(); if ( bhv == 1 && requireDivide ) { g_log.debug() << "Running Divide algorithm to perform averaging.\n"; Mantid::API::IAlgorithm_sptr divide = createChildAlgorithm("Divide"); divide->initialize(); divide->setProperty<API::MatrixWorkspace_sptr>("LHSWorkspace", outputWS); divide->setProperty<API::MatrixWorkspace_sptr>("RHSWorkspace", beh); divide->setProperty<API::MatrixWorkspace_sptr>("OutputWorkspace", outputWS); divide->execute(); } g_log.debug() << name() << " created " << outIndex << " new grouped spectra\n"; return outIndex; }
/** Load a single bank into the workspace * * @param nexusfilename :: file to open * @param entry_name :: NXentry name * @param bankName :: NXdata bank name * @param WS :: workspace to modify * @param id_to_wi :: det ID to workspace index mapping */ void LoadTOFRawNexus::loadBank(const std::string &nexusfilename, const std::string &entry_name, const std::string &bankName, API::MatrixWorkspace_sptr WS, const detid2index_map &id_to_wi) { g_log.debug() << "Loading bank " << bankName << std::endl; // To avoid segfaults on RHEL5/6 and Fedora m_fileMutex.lock(); // Navigate to the point in the file auto file = new ::NeXus::File(nexusfilename); file->openGroup(entry_name, "NXentry"); file->openGroup("instrument", "NXinstrument"); file->openGroup(bankName, "NXdetector"); size_t m_numPixels = 0; std::vector<uint32_t> pixel_id; if (!m_assumeOldFile) { // Load the pixel IDs file->readData("pixel_id", pixel_id); m_numPixels = pixel_id.size(); if (m_numPixels == 0) { file->close(); m_fileMutex.unlock(); g_log.warning() << "Invalid pixel_id data in " << bankName << std::endl; return; } } else { // Load the x and y pixel offsets std::vector<float> xoffsets; std::vector<float> yoffsets; file->readData("x_pixel_offset", xoffsets); file->readData("y_pixel_offset", yoffsets); m_numPixels = xoffsets.size() * yoffsets.size(); if (0 == m_numPixels) { file->close(); m_fileMutex.unlock(); g_log.warning() << "Invalid (x,y) offsets in " << bankName << std::endl; return; } size_t bankNum = 0; if (bankName.size() > 4) { if (bankName.substr(0, 4) == "bank") { bankNum = boost::lexical_cast<size_t>(bankName.substr(4)); bankNum--; } else { file->close(); m_fileMutex.unlock(); g_log.warning() << "Invalid bank number for " << bankName << std::endl; return; } } // All good, so construct the pixel ID listing size_t numX = xoffsets.size(); size_t numY = yoffsets.size(); for (size_t i = 0; i < numX; i++) { for (size_t j = 0; j < numY; j++) { pixel_id.push_back( static_cast<uint32_t>(j + numY * (i + numX * bankNum))); } } } size_t iPart = 0; if (m_spec_max != Mantid::EMPTY_INT()) { uint32_t ifirst = pixel_id[0]; range_check out_range(m_spec_min, m_spec_max, id_to_wi); auto newEnd = std::remove_if(pixel_id.begin(), pixel_id.end(), out_range); pixel_id.erase(newEnd, pixel_id.end()); // check if beginning or end of array was erased if (ifirst != pixel_id[0]) iPart = m_numPixels - pixel_id.size(); m_numPixels = pixel_id.size(); if (m_numPixels == 0) { file->close(); m_fileMutex.unlock(); g_log.warning() << "No pixels from " << bankName << std::endl; return; }; } // Load the TOF vector std::vector<float> tof; file->readData(m_axisField, tof); size_t m_numBins = tof.size() - 1; if (tof.size() <= 1) { file->close(); m_fileMutex.unlock(); g_log.warning() << "Invalid " << m_axisField << " data in " << bankName << std::endl; return; } // Make a shared pointer MantidVecPtr Xptr; MantidVec &X = Xptr.access(); X.resize(tof.size(), 0); X.assign(tof.begin(), tof.end()); // Load the data. Coerce ints into double. std::string errorsField = ""; std::vector<double> data; file->openData(m_dataField); file->getDataCoerce(data); if (file->hasAttr("errors")) file->getAttr("errors", errorsField); file->closeData(); // Load the errors bool hasErrors = !errorsField.empty(); std::vector<double> errors; if (hasErrors) { try { file->openData(errorsField); file->getDataCoerce(errors); file->closeData(); } catch (...) { g_log.information() << "Error loading the errors field, '" << errorsField << "' for bank " << bankName << ". Will use sqrt(counts). " << std::endl; hasErrors = false; } } /*if (data.size() != m_numBins * m_numPixels) { file->close(); m_fileMutex.unlock(); g_log.warning() << "Invalid size of '" << m_dataField << "' data in " << bankName << std::endl; return; } if (hasErrors && (errors.size() != m_numBins * m_numPixels)) { file->close(); m_fileMutex.unlock(); g_log.warning() << "Invalid size of '" << errorsField << "' errors in " << bankName << std::endl; return; } */ // Have all the data I need m_fileMutex.unlock(); file->close(); for (size_t i = iPart; i < iPart + m_numPixels; i++) { // Find the workspace index for this detector detid_t pixelID = pixel_id[i - iPart]; size_t wi = id_to_wi.find(pixelID)->second; // Set the basic info of that spectrum ISpectrum *spec = WS->getSpectrum(wi); spec->setSpectrumNo(specid_t(wi + 1)); spec->setDetectorID(pixel_id[i - iPart]); // Set the shared X pointer spec->setX(X); // Extract the Y MantidVec &Y = spec->dataY(); Y.assign(data.begin() + i * m_numBins, data.begin() + (i + 1) * m_numBins); MantidVec &E = spec->dataE(); if (hasErrors) { // Copy the errors from the loaded document E.assign(errors.begin() + i * m_numBins, errors.begin() + (i + 1) * m_numBins); } else { // Now take the sqrt(Y) to give E E = Y; std::transform(E.begin(), E.end(), E.begin(), (double (*)(double))sqrt); } } // Done! }
/** * This function deals with the logic necessary for summing a Workspace2D. * @param outSpec The spectrum for the summed output. * @param progress The progress indicator. * @param numSpectra The number of spectra contributed to the sum. * @param numMasked The spectra dropped from the summations because they are * masked. * @param numZeros The number of zero bins in histogram workspace or empty * spectra for event workspace. */ void SumSpectra::doWorkspace2D(ISpectrum &outSpec, Progress &progress, size_t &numSpectra, size_t &numMasked, size_t &numZeros) { // Get references to the output workspaces's data vectors auto &OutputYSum = outSpec.mutableY(); auto &OutputYError = outSpec.mutableE(); std::vector<double> Weight; std::vector<size_t> nZeros; if (m_calculateWeightedSum) { Weight.assign(OutputYSum.size(), 0); nZeros.assign(OutputYSum.size(), 0); } numSpectra = 0; numMasked = 0; numZeros = 0; MatrixWorkspace_sptr in_ws = getProperty("InputWorkspace"); // Clean workspace of any NANs or Inf values auto localworkspace = replaceSpecialValues(in_ws); const auto &spectrumInfo = localworkspace->spectrumInfo(); // Loop over spectra for (const auto wsIndex : this->m_indices) { // Don't go outside the range. if ((wsIndex >= this->m_numberOfSpectra) || (wsIndex < 0)) { g_log.error() << "Invalid index " << wsIndex << " was specified. Sum was aborted.\n"; break; } if (spectrumInfo.hasDetectors(wsIndex)) { // Skip monitors, if the property is set to do so if (!m_keepMonitors && spectrumInfo.isMonitor(wsIndex)) continue; // Skip masked detectors if (spectrumInfo.isMasked(wsIndex)) { numMasked++; continue; } } numSpectra++; const auto &YValues = localworkspace->y(wsIndex); const auto &YErrors = localworkspace->e(wsIndex); // Retrieve the spectrum into a vector for (int i = 0; i < m_yLength; ++i) { if (m_calculateWeightedSum) { if (std::isnormal(YErrors[i])) { const double errsq = YErrors[i] * YErrors[i]; OutputYError[i] += errsq; Weight[i] += 1. / errsq; OutputYSum[i] += YValues[i] / errsq; } else { nZeros[i]++; } } else { OutputYSum[i] += YValues[i]; OutputYError[i] += YErrors[i] * YErrors[i]; } } // Map all the detectors onto the spectrum of the output outSpec.addDetectorIDs( localworkspace->getSpectrum(wsIndex).getDetectorIDs()); progress.report(); } if (m_calculateWeightedSum) { numZeros = 0; for (size_t i = 0; i < Weight.size(); i++) { if (numSpectra > nZeros[i]) OutputYSum[i] *= double(numSpectra - nZeros[i]) / Weight[i]; if (nZeros[i] != 0) numZeros += nZeros[i]; } } }
void GroupDetectors::exec() { // Get the input workspace const MatrixWorkspace_sptr WS = getProperty("Workspace"); std::vector<size_t> indexList = getProperty("WorkspaceIndexList"); std::vector<specid_t> spectraList = getProperty("SpectraList"); const std::vector<detid_t> detectorList = getProperty("DetectorList"); // Could create a Validator to replace the below if ( indexList.empty() && spectraList.empty() && detectorList.empty() ) { g_log.information(name() + ": WorkspaceIndexList, SpectraList, and DetectorList properties are all empty, no grouping done"); return; } // Bin boundaries need to be the same, so check if they actually are if (!API::WorkspaceHelpers::commonBoundaries(WS)) { g_log.error("Can only group if the histograms have common bin boundaries"); throw std::runtime_error("Can only group if the histograms have common bin boundaries"); } // If the spectraList property has been set, need to loop over the workspace looking for the // appropriate spectra number and adding the indices they are linked to the list to be processed if ( ! spectraList.empty() ) { WS->getIndicesFromSpectra(spectraList,indexList); }// End dealing with spectraList else if ( ! detectorList.empty() ) { // Dealing with DetectorList //convert from detectors to workspace indices WS->getIndicesFromDetectorIDs(detectorList, indexList); } if ( indexList.empty() ) { g_log.warning("Nothing to group"); return; } const size_t vectorSize = WS->blocksize(); const specid_t firstIndex = static_cast<specid_t>(indexList[0]); ISpectrum * firstSpectrum = WS->getSpectrum(firstIndex); setProperty("ResultIndex",firstIndex); // loop over the spectra to group Progress progress(this, 0.0, 1.0, static_cast<int>(indexList.size()-1)); for (size_t i = 0; i < indexList.size()-1; ++i) { // The current spectrum const size_t currentIndex = indexList[i+1]; ISpectrum * spec = WS->getSpectrum(currentIndex); // Add the current detector to belong to the first spectrum firstSpectrum->addDetectorIDs(spec->getDetectorIDs()); // Add up all the Y spectra and store the result in the first one // Need to keep the next 3 lines inside loop for now until ManagedWorkspace mru-list works properly MantidVec &firstY = WS->dataY(firstIndex); MantidVec::iterator fYit; MantidVec::iterator fEit = firstSpectrum->dataE().begin(); MantidVec::iterator Yit = spec->dataY().begin(); MantidVec::iterator Eit = spec->dataE().begin(); for (fYit = firstY.begin(); fYit != firstY.end(); ++fYit, ++fEit, ++Yit, ++Eit) { *fYit += *Yit; // Assume 'normal' (i.e. Gaussian) combination of errors *fEit = sqrt( (*fEit)*(*fEit) + (*Eit)*(*Eit) ); } // Now zero the now redundant spectrum and set its spectraNo to indicate this (using -1) // N.B. Deleting spectra would cause issues for ManagedWorkspace2D, hence the the approach taken here spec->dataY().assign(vectorSize,0.0); spec->dataE().assign(vectorSize,0.0); spec->setSpectrumNo(-1); spec->clearDetectorIDs(); progress.report(); } }
/** * This function handles the logic for summing RebinnedOutput workspaces. * @param outputWorkspace the workspace to hold the summed input * @param progress the progress indicator * @param numSpectra * @param numMasked * @param numZeros */ void SumSpectra::doRebinnedOutput(MatrixWorkspace_sptr outputWorkspace, Progress &progress, size_t &numSpectra, size_t &numMasked, size_t &numZeros) { // Get a copy of the input workspace MatrixWorkspace_sptr temp = getProperty("InputWorkspace"); // First, we need to clean the input workspace for nan's and inf's in order // to treat the data correctly later. This will create a new private // workspace that will be retrieved as mutable. IAlgorithm_sptr alg = this->createChildAlgorithm("ReplaceSpecialValues"); alg->setProperty<MatrixWorkspace_sptr>("InputWorkspace", temp); std::string outName = "_" + temp->getName() + "_clean"; alg->setProperty("OutputWorkspace", outName); alg->setProperty("NaNValue", 0.0); alg->setProperty("NaNError", 0.0); alg->setProperty("InfinityValue", 0.0); alg->setProperty("InfinityError", 0.0); alg->executeAsChildAlg(); MatrixWorkspace_sptr localworkspace = alg->getProperty("OutputWorkspace"); // Transform to real workspace types RebinnedOutput_sptr inWS = boost::dynamic_pointer_cast<RebinnedOutput>(localworkspace); RebinnedOutput_sptr outWS = boost::dynamic_pointer_cast<RebinnedOutput>(outputWorkspace); // Get references to the output workspaces's data vectors ISpectrum *outSpec = outputWorkspace->getSpectrum(0); MantidVec &YSum = outSpec->dataY(); MantidVec &YError = outSpec->dataE(); MantidVec &FracSum = outWS->dataF(0); MantidVec Weight; std::vector<size_t> nZeros; if (m_calculateWeightedSum) { Weight.assign(YSum.size(), 0); nZeros.assign(YSum.size(), 0); } numSpectra = 0; numMasked = 0; numZeros = 0; // Loop over spectra std::set<int>::iterator it; // for (int i = m_minSpec; i <= m_maxSpec; ++i) for (it = m_indices.begin(); it != m_indices.end(); ++it) { int i = *it; // Don't go outside the range. if ((i >= m_numberOfSpectra) || (i < 0)) { g_log.error() << "Invalid index " << i << " was specified. Sum was aborted.\n"; break; } try { // Get the detector object for this spectrum Geometry::IDetector_const_sptr det = localworkspace->getDetector(i); // Skip monitors, if the property is set to do so if (!m_keepMonitors && det->isMonitor()) continue; // Skip masked detectors if (det->isMasked()) { numMasked++; continue; } } catch (...) { // if the detector not found just carry on } numSpectra++; // Retrieve the spectrum into a vector const MantidVec &YValues = localworkspace->readY(i); const MantidVec &YErrors = localworkspace->readE(i); const MantidVec &FracArea = inWS->readF(i); if (m_calculateWeightedSum) { for (int k = 0; k < this->m_yLength; ++k) { if (YErrors[k] != 0) { double errsq = YErrors[k] * YErrors[k] * FracArea[k] * FracArea[k]; YError[k] += errsq; Weight[k] += 1. / errsq; YSum[k] += YValues[k] * FracArea[k] / errsq; FracSum[k] += FracArea[k]; } else { nZeros[k]++; FracSum[k] += FracArea[k]; } } } else { for (int k = 0; k < this->m_yLength; ++k) { YSum[k] += YValues[k] * FracArea[k]; YError[k] += YErrors[k] * YErrors[k] * FracArea[k] * FracArea[k]; FracSum[k] += FracArea[k]; } } // Map all the detectors onto the spectrum of the output outSpec->addDetectorIDs(localworkspace->getSpectrum(i)->getDetectorIDs()); progress.report(); } if (m_calculateWeightedSum) { numZeros = 0; for (size_t i = 0; i < Weight.size(); i++) { if (nZeros[i] == 0) YSum[i] *= double(numSpectra) / Weight[i]; else numZeros += nZeros[i]; } } // Create the correct representation outWS->finalize(); }
void GatherWorkspaces::exec() { // Every process in an MPI job must hit this next line or everything hangs! mpi::communicator world; // The communicator containing all processes inputWorkspace = getProperty("InputWorkspace"); // Create a new communicator that includes only those processes that have an // input workspace const int haveWorkspace(inputWorkspace ? 1 : 0); included = world.split(haveWorkspace); // If the present process doesn't have an input workspace then its work is // done if (!haveWorkspace) { g_log.information("No input workspace on this process, so nothing to do."); return; } // Get the number of bins in each workspace and check they're all the same numBins = inputWorkspace->blocksize(); std::vector<std::size_t> all_numBins; all_gather(included, numBins, all_numBins); if (std::count(all_numBins.begin(), all_numBins.end(), numBins) != (int)all_numBins.size()) { // All the processes will error out if all the workspaces don't have the // same number of bins throw Exception::MisMatch<std::size_t>( numBins, 0, "All input workspaces must have the same number of bins"); } // Also check that all workspaces are either histogram or not // N.B. boost mpi doesn't seem to like me using booleans in the all_gather hist = inputWorkspace->isHistogramData(); std::vector<int> all_hist; all_gather(included, hist, all_hist); if (std::count(all_hist.begin(), all_hist.end(), hist) != (int)all_hist.size()) { // All the processes will error out if we don't have either all histogram or // all point-data workspaces throw Exception::MisMatch<int>( hist, 0, "The input workspaces must be all histogram or all point data"); } // How do we accumulate the data? std::string accum = this->getPropertyValue("AccumulationMethod"); // Get the total number of spectra in the combined inputs totalSpec = inputWorkspace->getNumberHistograms(); sumSpec = totalSpec; if (accum == "Append") { reduce(included, totalSpec, sumSpec, std::plus<std::size_t>(), 0); } else if (accum == "Add") { // barrier only helps when memory is too low for communication // included.barrier(); } eventW = boost::dynamic_pointer_cast<const EventWorkspace>(inputWorkspace); if (eventW != NULL) { if (getProperty("PreserveEvents")) { // Input workspace is an event workspace. Use the other exec method this->execEvent(); return; } } // The root process needs to create a workspace of the appropriate size MatrixWorkspace_sptr outputWorkspace; if (included.rank() == 0) { g_log.debug() << "Total number of spectra is " << sumSpec << "\n"; // Create the workspace for the output outputWorkspace = WorkspaceFactory::Instance().create( inputWorkspace, sumSpec, numBins + hist, numBins); setProperty("OutputWorkspace", outputWorkspace); ExperimentInfo_sptr inWS = inputWorkspace; outputWorkspace->copyExperimentInfoFrom(inWS.get()); } for (size_t wi = 0; wi < totalSpec; wi++) { if (included.rank() == 0) { const ISpectrum *inSpec = inputWorkspace->getSpectrum(wi); if (accum == "Add") { outputWorkspace->dataX(wi) = inputWorkspace->readX(wi); reduce(included, inputWorkspace->readY(wi), outputWorkspace->dataY(wi), vplus(), 0); reduce(included, inputWorkspace->readE(wi), outputWorkspace->dataE(wi), eplus(), 0); } else if (accum == "Append") { // Copy over data from own input workspace outputWorkspace->dataX(wi) = inputWorkspace->readX(wi); outputWorkspace->dataY(wi) = inputWorkspace->readY(wi); outputWorkspace->dataE(wi) = inputWorkspace->readE(wi); const int numReqs(3 * (included.size() - 1)); mpi::request reqs[numReqs]; int j(0); // Receive data from all the other processes // This works because the process ranks are ordered the same in // 'included' as // they are in 'world', but in general this is not guaranteed. TODO: // robustify for (int i = 1; i < included.size(); ++i) { size_t index = wi + i * totalSpec; reqs[j++] = included.irecv(i, 0, outputWorkspace->dataX(index)); reqs[j++] = included.irecv(i, 1, outputWorkspace->dataY(index)); reqs[j++] = included.irecv(i, 2, outputWorkspace->dataE(index)); ISpectrum *outSpec = outputWorkspace->getSpectrum(index); outSpec->clearDetectorIDs(); outSpec->addDetectorIDs(inSpec->getDetectorIDs()); } // Make sure everything's been received before exiting the algorithm mpi::wait_all(reqs, reqs + numReqs); } ISpectrum *outSpec = outputWorkspace->getSpectrum(wi); outSpec->clearDetectorIDs(); outSpec->addDetectorIDs(inSpec->getDetectorIDs()); } else { if (accum == "Add") { reduce(included, inputWorkspace->readY(wi), vplus(), 0); reduce(included, inputWorkspace->readE(wi), eplus(), 0); } else if (accum == "Append") { mpi::request reqs[3]; // Send the spectrum to the root process reqs[0] = included.isend(0, 0, inputWorkspace->readX(0)); reqs[1] = included.isend(0, 1, inputWorkspace->readY(0)); reqs[2] = included.isend(0, 2, inputWorkspace->readE(0)); // Make sure the sends have completed before exiting the algorithm mpi::wait_all(reqs, reqs + 3); } } } }
/// Construct from ISpectrum. Histogram1D::Histogram1D(const ISpectrum &other) : ISpectrum(other), m_histogram(other.histogram()) {}
/** 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); } }
/// Construct from ISpectrum. Histogram1D::Histogram1D(const ISpectrum &other) : ISpectrum(other) { dataY() = other.readY(); dataE() = other.readE(); }
/** Executes the algorithm * @throw std::invalid_argument If the input workspaces do not meet the requirements of this algorithm */ void ConjoinWorkspaces::exec() { // Retrieve the input workspaces MatrixWorkspace_const_sptr ws1 = getProperty("InputWorkspace1"); MatrixWorkspace_const_sptr ws2 = getProperty("InputWorkspace2"); event_ws1 = boost::dynamic_pointer_cast<const EventWorkspace>(ws1); event_ws2 = boost::dynamic_pointer_cast<const EventWorkspace>(ws2); //Make sure that we are not mis-matching EventWorkspaces and other types of workspaces if (((event_ws1) && (!event_ws2)) || ((!event_ws1) && (event_ws2))) { const std::string message("Only one of the input workspaces are of type EventWorkspace; please use matching workspace types (both EventWorkspace's or both Workspace2D's)."); g_log.error(message); throw std::invalid_argument(message); } if (event_ws1 && event_ws2) { //Both are event workspaces. Use the special method this->execEvent(); return; } // Check that the input workspaces meet the requirements for this algorithm this->validateInputs(ws1,ws2); // Create the output workspace const size_t totalHists = ws1->getNumberHistograms() + ws2->getNumberHistograms(); MatrixWorkspace_sptr output = WorkspaceFactory::Instance().create("Workspace2D",totalHists,ws1->readX(0).size(), ws1->readY(0).size()); // Copy over stuff from first input workspace WorkspaceFactory::Instance().initializeFromParent(ws1,output,true); // Create the X values inside a cow pointer - they will be shared in the output workspace cow_ptr<MantidVec> XValues; XValues.access() = ws1->readX(0); // Initialize the progress reporting object m_progress = new API::Progress(this, 0.0, 1.0, totalHists); // Loop over the input workspaces in turn copying the data into the output one const int64_t& nhist1 = ws1->getNumberHistograms(); PARALLEL_FOR2(ws1, output) for (int64_t i = 0; i < nhist1; ++i) { PARALLEL_START_INTERUPT_REGION ISpectrum * outSpec = output->getSpectrum(i); const ISpectrum * inSpec = ws1->getSpectrum(i); // Copy X,Y,E outSpec->setX(XValues); outSpec->setData(inSpec->dataY(), inSpec->dataE()); // Copy the spectrum number/detector IDs outSpec->copyInfoFrom(*inSpec); // Propagate masking, if needed if ( ws1->hasMaskedBins(i) ) { const MatrixWorkspace::MaskList& inputMasks = ws1->maskedBins(i); MatrixWorkspace::MaskList::const_iterator it; for (it = inputMasks.begin(); it != inputMasks.end(); ++it) { output->flagMasked(i,(*it).first,(*it).second); } } m_progress->report(); PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION //For second loop we use the offset from the first const int64_t& nhist2 = ws2->getNumberHistograms(); PARALLEL_FOR2(ws2, output) for (int64_t j = 0; j < nhist2; ++j) { PARALLEL_START_INTERUPT_REGION // The spectrum in the output workspace ISpectrum * outSpec = output->getSpectrum(nhist1 + j); // Spectrum in the second workspace const ISpectrum * inSpec = ws2->getSpectrum(j); // Copy X,Y,E outSpec->setX(XValues); outSpec->setData(inSpec->dataY(), inSpec->dataE()); // Copy the spectrum number/detector IDs outSpec->copyInfoFrom(*inSpec); // Propagate masking, if needed if ( ws2->hasMaskedBins(j) ) { const MatrixWorkspace::MaskList& inputMasks = ws2->maskedBins(j); MatrixWorkspace::MaskList::const_iterator it; for (it = inputMasks.begin(); it != inputMasks.end(); ++it) { output->flagMasked(nhist1 + j,(*it).first,(*it).second); } } m_progress->report(); PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION this->fixSpectrumNumbers(ws1,ws2, output); // Delete the second input workspace from the ADS AnalysisDataService::Instance().remove(getPropertyValue("InputWorkspace2")); // Set the result workspace to the first input setProperty("InputWorkspace1",output); }