/** Execute the algorithm. */ void EditInstrumentGeometry::exec() { // Lots of things have to do with the input workspace MatrixWorkspace_sptr workspace = getProperty("Workspace"); Geometry::Instrument_const_sptr originstrument = workspace->getInstrument(); // Get and check the primary flight path double l1 = this->getProperty("PrimaryFlightPath"); if (isEmpty(l1)) { // Use the original L1 if (!originstrument) { std::string errmsg( "It is not supported that L1 is not given, ", "while there is no instrument associated to input workspace."); g_log.error(errmsg); throw std::runtime_error(errmsg); } Geometry::IComponent_const_sptr source = originstrument->getSource(); Geometry::IComponent_const_sptr sample = originstrument->getSample(); l1 = source->getDistance(*sample); g_log.information() << "Retrieve L1 from input data workspace. \n"; } g_log.information() << "Using L1 = " << l1 << "\n"; // Get spectra number in case they are in a funny order std::vector<int32_t> specids = this->getProperty("SpectrumIDs"); if (specids.empty()) // they are using the order of the input workspace { size_t numHist = workspace->getNumberHistograms(); for (size_t i = 0; i < numHist; ++i) { specids.push_back(workspace->getSpectrum(i).getSpectrumNo()); g_log.information() << "Add spectrum " << workspace->getSpectrum(i).getSpectrumNo() << ".\n"; } } // Get the detector ids - empsy means ignore it const vector<int> vec_detids = getProperty("DetectorIDs"); const bool renameDetID(!vec_detids.empty()); // Get individual detector geometries ordered by input spectrum Numbers const std::vector<double> l2s = this->getProperty("L2"); const std::vector<double> tths = this->getProperty("Polar"); std::vector<double> phis = this->getProperty("Azimuthal"); // empty list of L2 and 2-theta is not allowed if (l2s.empty()) { throw std::runtime_error("User must specify L2 for all spectra. "); } if (tths.empty()) { throw std::runtime_error("User must specify 2theta for all spectra."); } // empty list of phi means that they are all zero if (phis.empty()) { phis.assign(l2s.size(), 0.); } // Validate for (size_t ib = 0; ib < l2s.size(); ib++) { g_log.information() << "Detector " << specids[ib] << " L2 = " << l2s[ib] << " 2Theta = " << tths[ib] << '\n'; if (specids[ib] < 0) { // Invalid spectrum Number : less than 0. stringstream errmsgss; errmsgss << "Detector ID = " << specids[ib] << " cannot be less than 0."; throw std::invalid_argument(errmsgss.str()); } if (l2s[ib] <= 0.0) { throw std::invalid_argument("L2 cannot be less or equal to 0"); } } // Keep original instrument and set the new instrument, if necessary const auto spec2indexmap = workspace->getSpectrumToWorkspaceIndexMap(); // ??? Condition: spectrum has 1 and only 1 detector size_t nspec = workspace->getNumberHistograms(); // Initialize another set of L2/2-theta/Phi/DetectorIDs vector ordered by // workspace index std::vector<double> storL2s(nspec, 0.); std::vector<double> stor2Thetas(nspec, 0.); std::vector<double> storPhis(nspec, 0.); vector<int> storDetIDs(nspec, 0); // Map the properties from spectrum Number to workspace index for (size_t i = 0; i < specids.size(); i++) { // Find spectrum's workspace index auto it = spec2indexmap.find(specids[i]); if (it == spec2indexmap.end()) { stringstream errss; errss << "Spectrum Number " << specids[i] << " is not found. " << "Instrument won't be edited for this spectrum. \n"; g_log.error(errss.str()); throw std::runtime_error(errss.str()); } // Store and set value size_t workspaceindex = it->second; storL2s[workspaceindex] = l2s[i]; stor2Thetas[workspaceindex] = tths[i]; storPhis[workspaceindex] = phis[i]; if (renameDetID) storDetIDs[workspaceindex] = vec_detids[i]; g_log.debug() << "workspace index = " << workspaceindex << " is for Spectrum " << specids[i] << '\n'; } // Generate a new instrument // Name of the new instrument std::string name = std::string(getProperty("InstrumentName")); if (name.empty()) { // Use the original L1 if (!originstrument) { std::string errmsg( "It is not supported that InstrumentName is not given, ", "while there is no instrument associated to input workspace."); g_log.error(errmsg); throw std::runtime_error(errmsg); } name = originstrument->getName(); } // Create a new instrument from scratch any way. auto instrument = boost::make_shared<Geometry::Instrument>(name); if (!bool(instrument)) { stringstream errss; errss << "Trying to use a Parametrized Instrument as an Instrument."; g_log.error(errss.str()); throw std::runtime_error(errss.str()); } // Set up source and sample information Geometry::ObjComponent *samplepos = new Geometry::ObjComponent("Sample", instrument.get()); instrument->add(samplepos); instrument->markAsSamplePos(samplepos); samplepos->setPos(0.0, 0.0, 0.0); Geometry::ObjComponent *source = new Geometry::ObjComponent("Source", instrument.get()); instrument->add(source); instrument->markAsSource(source); source->setPos(0.0, 0.0, -1.0 * l1); // Add/copy detector information auto indexInfo = workspace->indexInfo(); std::vector<detid_t> detIDs; for (size_t i = 0; i < workspace->getNumberHistograms(); i++) { // Create a new detector. // (Instrument will take ownership of pointer so no need to delete.) detid_t newdetid; if (renameDetID) newdetid = storDetIDs[i]; else newdetid = detid_t(i) + 100; Geometry::Detector *detector = new Geometry::Detector("det", newdetid, samplepos); // Set up new detector parameters related to new instrument double l2 = storL2s[i]; double tth = stor2Thetas[i]; double phi = storPhis[i]; Kernel::V3D pos; pos.spherical(l2, tth, phi); detector->setPos(pos); // Add new detector to spectrum and instrument // Good and do some debug output g_log.debug() << "Orignal spectrum " << indexInfo.spectrumNumber(i) << "has " << indexInfo.detectorIDs(i).size() << " detectors. \n"; detIDs.push_back(newdetid); instrument->add(detector); instrument->markAsDetector(detector); } // ENDFOR workspace index indexInfo.setDetectorIDs(std::move(detIDs)); workspace->setIndexInfo(indexInfo); // Add the new instrument workspace->setInstrument(instrument); }
/** Execute the algorithm. */ void LoadNXSPE::exec() { std::string filename = getProperty("Filename"); // quicly check if it's really nxspe try { ::NeXus::File file(filename); std::string mainEntry = (*(file.getEntries().begin())).first; file.openGroup(mainEntry, "NXentry"); file.openData("definition"); if (identiferConfidence(file.getStrData()) < 1) { throw std::invalid_argument("Not NXSPE"); } file.close(); } catch (...) { throw std::invalid_argument("Not NeXus or not NXSPE"); } // Load the data ::NeXus::File file(filename); std::string mainEntry = (*(file.getEntries().begin())).first; file.openGroup(mainEntry, "NXentry"); file.openGroup("NXSPE_info", "NXcollection"); std::map<std::string, std::string> entries = file.getEntries(); std::vector<double> temporary; double fixed_energy, psi = 0.; if (!entries.count("fixed_energy")) { throw std::invalid_argument("fixed_energy field was not found"); } file.openData("fixed_energy"); file.getData(temporary); fixed_energy = temporary.at(0); file.closeData(); if (entries.count("psi")) { file.openData("psi"); file.getData(temporary); psi = temporary.at(0); file.closeData(); } int kikfscaling = 0; if (entries.count("ki_over_kf_scaling")) { file.openData("ki_over_kf_scaling"); std::vector<int> temporaryint; file.getData(temporaryint); kikfscaling = temporaryint.at(0); file.closeData(); } file.closeGroup(); // NXSPE_Info file.openGroup("data", "NXdata"); entries = file.getEntries(); if (!entries.count("data")) { throw std::invalid_argument("data field was not found"); } file.openData("data"); ::NeXus::Info info = file.getInfo(); std::size_t numSpectra = static_cast<std::size_t>(info.dims.at(0)); std::size_t numBins = static_cast<std::size_t>(info.dims.at(1)); std::vector<double> data; file.getData(data); file.closeData(); if (!entries.count("error")) { throw std::invalid_argument("error field was not found"); } file.openData("error"); std::vector<double> error; file.getData(error); file.closeData(); if (!entries.count("energy")) { throw std::invalid_argument("energy field was not found"); } file.openData("energy"); std::vector<double> energies; file.getData(energies); file.closeData(); if (!entries.count("azimuthal")) { throw std::invalid_argument("azimuthal field was not found"); } file.openData("azimuthal"); std::vector<double> azimuthal; file.getData(azimuthal); file.closeData(); if (!entries.count("azimuthal_width")) { throw std::invalid_argument("azimuthal_width field was not found"); } file.openData("azimuthal_width"); std::vector<double> azimuthal_width; file.getData(azimuthal_width); file.closeData(); if (!entries.count("polar")) { throw std::invalid_argument("polar field was not found"); } file.openData("polar"); std::vector<double> polar; file.getData(polar); file.closeData(); if (!entries.count("polar_width")) { throw std::invalid_argument("polar_width field was not found"); } file.openData("polar_width"); std::vector<double> polar_width; file.getData(polar_width); file.closeData(); // distance might not have been saved in all NXSPE files std::vector<double> distance; if (entries.count("distance")) { file.openData("distance"); file.getData(distance); file.closeData(); } file.closeGroup(); // data group file.closeGroup(); // Main entry file.close(); // check if dimensions of the vectors are correct if ((error.size() != data.size()) || (azimuthal.size() != numSpectra) || (azimuthal_width.size() != numSpectra) || (polar.size() != numSpectra) || (polar_width.size() != numSpectra) || ((energies.size() != numBins) && (energies.size() != numBins + 1))) { throw std::invalid_argument( "incompatible sizes of fields in the NXSPE file"); } MatrixWorkspace_sptr outputWS = boost::dynamic_pointer_cast<MatrixWorkspace>( WorkspaceFactory::Instance().create("Workspace2D", numSpectra, energies.size(), numBins)); // Need to get hold of the parameter map outputWS->getAxis(0)->unit() = UnitFactory::Instance().create("DeltaE"); outputWS->setYUnit("SpectraNumber"); // add logs outputWS->mutableRun().addLogData( new PropertyWithValue<double>("Ei", fixed_energy)); outputWS->mutableRun().addLogData(new PropertyWithValue<double>("psi", psi)); outputWS->mutableRun().addLogData(new PropertyWithValue<std::string>( "ki_over_kf_scaling", kikfscaling == 1 ? "true" : "false")); // Set Goniometer Geometry::Goniometer gm; gm.pushAxis("psi", 0, 1, 0, psi); outputWS->mutableRun().setGoniometer(gm, true); // generate instrument Geometry::Instrument_sptr instrument(new Geometry::Instrument("NXSPE")); outputWS->setInstrument(instrument); Geometry::ObjComponent *source = new Geometry::ObjComponent("source"); source->setPos(0.0, 0.0, -10.0); instrument->add(source); instrument->markAsSource(source); Geometry::ObjComponent *sample = new Geometry::ObjComponent("sample"); instrument->add(sample); instrument->markAsSamplePos(sample); Geometry::Object_const_sptr cuboid( createCuboid(0.1, 0.1, 0.1)); // FIXME: memory hog on rendering. Also, // make each detector separate size for (std::size_t i = 0; i < numSpectra; ++i) { double r = 1.0; if (!distance.empty()) { r = distance.at(i); } Kernel::V3D pos; pos.spherical(r, polar.at(i), azimuthal.at(i)); Geometry::Detector *det = new Geometry::Detector("pixel", static_cast<int>(i + 1), sample); det->setPos(pos); det->setShape(cuboid); instrument->add(det); instrument->markAsDetector(det); } Geometry::ParameterMap &pmap = outputWS->instrumentParameters(); std::vector<double>::iterator itdata = data.begin(), iterror = error.begin(), itdataend, iterrorend; API::Progress prog = API::Progress(this, 0.0, 0.9, numSpectra); for (std::size_t i = 0; i < numSpectra; ++i) { itdataend = itdata + numBins; iterrorend = iterror + numBins; outputWS->dataX(i) = energies; if ((!boost::math::isfinite(*itdata)) || (*itdata <= -1e10)) // masked bin { outputWS->dataY(i) = std::vector<double>(numBins, 0); outputWS->dataE(i) = std::vector<double>(numBins, 0); pmap.addBool(outputWS->getDetector(i)->getComponentID(), "masked", true); } else { outputWS->dataY(i) = std::vector<double>(itdata, itdataend); outputWS->dataE(i) = std::vector<double>(iterror, iterrorend); } itdata = (itdataend); iterror = (iterrorend); prog.report(); } setProperty("OutputWorkspace", outputWS); }