/** Read the specified number of entries from input file into the * the array that is passed * @param[in] nEntries the number of numbers to read * @param[out] output the contents of this will be replaced by the data read from the file */ void LoadRKH::readNumEntrys(const int nEntries, MantidVec & output) { output.resize(nEntries); for( int i = 0; i < nEntries; ++i ) { m_fileIn >> output[i]; } }
/** Load the event_workspace field * * @param wksp_cls * @param progressStart * @param progressRange * @return */ API::MatrixWorkspace_sptr LoadNexusProcessed::loadEventEntry(NXData & wksp_cls, NXDouble & xbins, const double& progressStart, const double& progressRange) { NXDataSetTyped<int64_t> indices_data = wksp_cls.openNXDataSet<int64_t>("indices"); indices_data.load(); boost::shared_array<int64_t> indices = indices_data.sharedBuffer(); int numspec = indices_data.dim0()-1; int num_xbins = xbins.dim0(); if (num_xbins < 2) num_xbins = 2; EventWorkspace_sptr ws = boost::dynamic_pointer_cast<EventWorkspace> (WorkspaceFactory::Instance().create("EventWorkspace", numspec, num_xbins, num_xbins-1)); // Set the YUnit label ws->setYUnit(indices_data.attributes("units")); std::string unitLabel = indices_data.attributes("unit_label"); if (unitLabel.empty()) unitLabel = indices_data.attributes("units"); ws->setYUnitLabel(unitLabel); //Handle optional fields. // TODO: Handle inconsistent sizes boost::shared_array<int64_t> pulsetimes; if (wksp_cls.isValid("pulsetime")) { NXDataSetTyped<int64_t> pulsetime = wksp_cls.openNXDataSet<int64_t>("pulsetime"); pulsetime.load(); pulsetimes = pulsetime.sharedBuffer(); } boost::shared_array<double> tofs; if (wksp_cls.isValid("tof")) { NXDouble tof = wksp_cls.openNXDouble("tof"); tof.load(); tofs = tof.sharedBuffer(); } boost::shared_array<float> error_squareds; if (wksp_cls.isValid("error_squared")) { NXFloat error_squared = wksp_cls.openNXFloat("error_squared"); error_squared.load(); error_squareds = error_squared.sharedBuffer(); } boost::shared_array<float> weights; if (wksp_cls.isValid("weight")) { NXFloat weight = wksp_cls.openNXFloat("weight"); weight.load(); weights = weight.sharedBuffer(); } // What type of event lists? EventType type = TOF; if (tofs && pulsetimes && weights && error_squareds) type = WEIGHTED; else if ((tofs && weights && error_squareds)) type = WEIGHTED_NOTIME; else if (pulsetimes && tofs) type = TOF; else throw std::runtime_error("Could not figure out the type of event list!"); // Create all the event lists PARALLEL_FOR_NO_WSP_CHECK() for (int wi=0; wi < numspec; wi++) { PARALLEL_START_INTERUPT_REGION int64_t index_start = indices[wi]; int64_t index_end = indices[wi+1]; if (index_end >= index_start) { EventList & el = ws->getEventList(wi); el.switchTo(type); // Allocate all the required memory el.reserve(index_end - index_start); el.clearDetectorIDs(); for (long i=index_start; i<index_end; i++) switch (type) { case TOF: el.addEventQuickly( TofEvent( tofs[i], DateAndTime(pulsetimes[i])) ); break; case WEIGHTED: el.addEventQuickly( WeightedEvent( tofs[i], DateAndTime(pulsetimes[i]), weights[i], error_squareds[i]) ); break; case WEIGHTED_NOTIME: el.addEventQuickly( WeightedEventNoTime( tofs[i], weights[i], error_squareds[i]) ); break; } // Set the X axis if (this->m_shared_bins) el.setX(this->m_xbins); else { MantidVec x; x.resize(xbins.dim0()); for (int i=0; i < xbins.dim0(); i++) x[i] = xbins(wi, i); el.setX(x); } } progress(progressStart + progressRange*(1.0/numspec)); PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION // Clean up some stuff ws->doneAddingEventLists(); return ws; }
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"; }
/** Reads the header information from a file containing 2D data * @param[in] initalLine the second line in the file * @param[out] outWrksp the workspace that the data will be writen to * @param[out] axis0Data x-values for the workspace * @return a progress bar object * @throw NotFoundError if there is compulsulary data is missing from the file * @throw invalid_argument if there is an inconsistency in the header information */ Progress LoadRKH::read2DHeader(const std::string & initalLine, MatrixWorkspace_sptr & outWrksp, MantidVec & axis0Data) { const std::string XUnit(readUnit(initalLine)); std::string fileLine; std::getline(m_fileIn, fileLine); const std::string YUnit(readUnit(fileLine)); std::getline(m_fileIn, fileLine); const std::string intensityUnit(readUnit(fileLine)); // the next line should contain just "1", but I'm not enforcing that std::getline(m_fileIn, fileLine); std::string title; std::getline(m_fileIn, title); std::getline(m_fileIn, fileLine); boost::trim(fileLine); const int nAxis0Boundaries = boost::lexical_cast<int>(fileLine); axis0Data.resize(nAxis0Boundaries); readNumEntrys(nAxis0Boundaries, axis0Data); std::getline(m_fileIn, fileLine); boost::trim(fileLine); int nAxis1Boundaries; try { nAxis1Boundaries = boost::lexical_cast<int>(fileLine); } catch(boost::bad_lexical_cast &) { // using readNumEntrys() above broke the sequence of getline()s and so try again in case we just read the end of a line std::getline(m_fileIn, fileLine); boost::trim(fileLine); nAxis1Boundaries = boost::lexical_cast<int>(fileLine); } MantidVec axis1Data(nAxis1Boundaries); readNumEntrys(nAxis1Boundaries, axis1Data); std::getline(m_fileIn, fileLine); // check for the file pointer being left at the end of a line if ( fileLine.size() < 5 ) { std::getline(m_fileIn, fileLine); } Poco::StringTokenizer wsDimensions(fileLine, " ", Poco::StringTokenizer::TOK_TRIM); if ( wsDimensions.count() < 2 ) { throw Exception::NotFoundError("Input file", "dimensions"); } const int nAxis0Values = boost::lexical_cast<int>(wsDimensions[0]); const int nAxis1Values = boost::lexical_cast<int>(wsDimensions[1]); Progress prog(this, 0.05, 1.0, 2*nAxis1Values); // we now have all the data we need to create the output workspace outWrksp = WorkspaceFactory::Instance().create( "Workspace2D", nAxis1Values, nAxis0Boundaries, nAxis0Values); outWrksp->getAxis(0)->unit() = UnitFactory::Instance().create(XUnit); outWrksp->setYUnitLabel(intensityUnit); NumericAxis* const axis1 = new Mantid::API::NumericAxis(nAxis1Boundaries); axis1->unit() = Mantid::Kernel::UnitFactory::Instance().create(YUnit); outWrksp->replaceAxis(1, axis1); for ( int i = 0; i < nAxis1Boundaries; ++i ) { axis1->setValue(i, axis1Data[i]); } outWrksp->setTitle(title); // move over the next line which is there to help with loading from Fortran routines std::getline(m_fileIn, fileLine); return prog; }
/** * Get a data array covering the specified range of data, at the specified * resolution. NOTE: The calling code is responsible for deleting the * DataArray that is constructed in and returned by this method. * * @param xMin Left edge of region to be covered. * @param xMax Right edge of region to be covered. * @param yMin Bottom edge of region to be covered. * @param yMax Top edge of region to be covered. * @param numRows Number of rows to return. If the number of rows is less * than the actual number of data rows in [yMin,yMax], the * data will be subsampled, and only the specified number * of rows will be returned. * @param numCols The specrum data will be rebinned using the specified * number of colums. * @param isLogX Flag indicating whether or not the data should be * binned logarithmically. */ DataArray_const_sptr MatrixWSDataSource::getDataArray( double xMin, double xMax, double yMin, double yMax, size_t numRows, size_t numCols, bool isLogX ) { /* Since we're rebinning, the columns can be arbitrary */ /* but rows must be aligned to get whole spectra */ size_t first_row; SVUtils::CalculateInterval( m_totalYMin, m_totalYMax, m_totalRows, first_row, yMin, yMax, numRows ); std::vector<float> newData(numRows * numCols); MantidVec xScale; xScale.resize(numCols + 1); if ( isLogX ) { for ( size_t i = 0; i < numCols+1; i++ ) { xScale[i] = xMin * exp ( (double)i / (double)numCols * log(xMax/xMin) ); } } else { double dx = (xMax - xMin) / ((double)numCols + 1.0); for ( size_t i = 0; i < numCols+1; i++ ) { xScale[i] = xMin + (double)i * dx; } } // Choose spectra from required range of spectrum indexes double yStep = (yMax - yMin) / (double)numRows; double dYIndex; MantidVec yVals; MantidVec err; yVals.resize(numCols); err.resize(numCols); size_t index = 0; for ( size_t i = 0; i < numRows; i++ ) { double midY = yMin + ((double)i + 0.5) * yStep; SVUtils::Interpolate( m_totalYMin, m_totalYMax, midY, 0.0, (double)m_totalRows, dYIndex ); size_t sourceRow = (size_t)dYIndex; yVals.clear(); err.clear(); yVals.resize(numCols, 0); err.resize(numCols, 0); m_matWs->generateHistogram( sourceRow, xScale, yVals, err, true ); for ( size_t col = 0; col < numCols; col++ ) { newData[index] = (float)yVals[col]; index++; } } // The calling code is responsible for deleting the DataArray when it is done with it DataArray_const_sptr newDataArray( new DataArray( xMin, xMax, yMin, yMax, isLogX, numRows, numCols, newData) ); return newDataArray; }