int LoadIsawPeaks::findPixelID(Instrument_const_sptr inst, std::string bankName, int col, int row) { boost::shared_ptr<const IComponent> parent = inst->getComponentByName(bankName); if (parent->type().compare("RectangularDetector") == 0) { boost::shared_ptr<const RectangularDetector> RDet = boost::dynamic_pointer_cast< const RectangularDetector>(parent); boost::shared_ptr<Detector> pixel = RDet->getAtXY(col, row); return pixel->getID(); } else { std::vector<Geometry::IComponent_const_sptr> children; boost::shared_ptr<const Geometry::ICompAssembly> asmb = boost::dynamic_pointer_cast<const Geometry::ICompAssembly>(parent); asmb->getChildren(children, false); int col0 = (col%2==0 ? col/2+75 : (col-1)/2); boost::shared_ptr<const Geometry::ICompAssembly> asmb2 = boost::dynamic_pointer_cast<const Geometry::ICompAssembly>(children[col0]); std::vector<Geometry::IComponent_const_sptr> grandchildren; asmb2->getChildren(grandchildren,false); Geometry::IComponent_const_sptr first = grandchildren[row-1]; Geometry::IDetector_const_sptr det = boost::dynamic_pointer_cast<const Geometry::IDetector>(first); return det->getID(); } }
/** Get the list of banks, given the settings * * @return map with key = bank number; value = pointer to the rectangular *detector */ std::map<int, RectangularDetector_const_sptr> ConvertToDetectorFaceMD::getBanks() { Instrument_const_sptr inst = in_ws->getInstrument(); std::vector<int> bankNums = this->getProperty("BankNumbers"); std::sort(bankNums.begin(), bankNums.end()); std::map<int, RectangularDetector_const_sptr> banks; if (bankNums.empty()) { // --- Find all rectangular detectors ---- // Get all children std::vector<IComponent_const_sptr> comps; inst->getChildren(comps, true); for (auto &comp : comps) { // Retrieve it RectangularDetector_const_sptr det = boost::dynamic_pointer_cast<const RectangularDetector>(comp); if (det) { std::string name = det->getName(); if (name.size() < 5) continue; std::string bank = name.substr(4, name.size() - 4); int bankNum; if (Mantid::Kernel::Strings::convert(bank, bankNum)) banks[bankNum] = det; g_log.debug() << "Found bank " << bank << ".\n"; } } } else { // -- Find detectors using the numbers given --- for (auto &bankNum : bankNums) { std::string bankName = "bank" + Mantid::Kernel::Strings::toString(bankNum); IComponent_const_sptr comp = inst->getComponentByName(bankName); RectangularDetector_const_sptr det = boost::dynamic_pointer_cast<const RectangularDetector>(comp); if (det) banks[bankNum] = det; } } for (auto &bank : banks) { RectangularDetector_const_sptr det = bank.second; // Track the largest detector if (det->xpixels() > m_numXPixels) m_numXPixels = det->xpixels(); if (det->ypixels() > m_numYPixels) m_numYPixels = det->ypixels(); } if (banks.empty()) throw std::runtime_error("No RectangularDetectors with a name like " "'bankXX' found in the instrument."); return banks; }
void AnvredCorrection::scale_init(IDetector_const_sptr det, Instrument_const_sptr inst, int& bank, double& L2, double& depth, double& pathlength, std::string bankName) { bankName = det->getParent()->getParent()->getName(); std::string bankNameStr = bankName; // Take out the "bank" part of the bank name and convert to an int bankNameStr.erase(remove_if(bankNameStr.begin(), bankNameStr.end(), not1(std::ptr_fun (::isdigit))), bankNameStr.end()); Strings::convert(bankNameStr, bank); IComponent_const_sptr sample = inst->getSample(); double cosA = inst->getComponentByName(bankName)->getDistance(*sample) / L2; pathlength = depth / cosA; }
/** Execute the algorithm. */ void CreateChunkingFromInstrument::exec() { // get the instrument Instrument_const_sptr inst = this->getInstrument(); // setup the output workspace ITableWorkspace_sptr strategy = WorkspaceFactory::Instance().createTable("TableWorkspace"); strategy->addColumn("str", "BankName"); this->setProperty("OutputWorkspace", strategy); // get the correct level of grouping string groupLevel = this->getPropertyValue(PARAM_CHUNK_BY); vector<string> groupNames = getGroupNames(this->getPropertyValue(PARAM_CHUNK_NAMES)); if (groupLevel.compare("All") == 0) { return; // nothing to do } else if (inst->getName().compare("SNAP") == 0 && groupLevel.compare("Group") == 0) { groupNames.clear(); groupNames.push_back("East"); groupNames.push_back("West"); } // set up a progress bar with the "correct" number of steps int maxBankNum = this->getProperty(PARAM_MAX_BANK_NUM); Progress progress(this, .2, 1., maxBankNum); // search the instrument for the bank names int maxRecurseDepth = this->getProperty(PARAM_MAX_RECURSE); map<string, vector<string>> grouping; // cppcheck-suppress syntaxError PRAGMA_OMP(parallel for schedule(dynamic, 1) ) for (int num = 0; num < maxBankNum; ++num) { PARALLEL_START_INTERUPT_REGION ostringstream mess; mess << "bank" << num; IComponent_const_sptr comp = inst->getComponentByName(mess.str(), maxRecurseDepth); PARALLEL_CRITICAL(grouping) if (comp) { // get the name of the correct parent string parent; if (groupNames.empty()) { parent = parentName(comp, groupLevel); } else { parent = parentName(comp, groupNames); } // add it to the correct chunk if (!parent.empty()) { if (grouping.count(parent) == 0) grouping[parent] = vector<string>(); grouping[parent].push_back(comp->getName()); } } progress.report(); PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION // check to see that something happened if (grouping.empty()) throw std::runtime_error("Failed to find any banks in the instrument"); // fill in the table workspace for (auto group = grouping.begin(); group != grouping.end(); ++group) { stringstream banks; for (auto bank = group->second.begin(); bank != group->second.end(); ++bank) banks << (*bank) << ","; // remove the trailing comma string banksStr = banks.str(); banksStr = banksStr.substr(0, banksStr.size() - 1); // add it to the table TableRow row = strategy->appendRow(); row << banksStr; } }
/** Execute the algorithm. */ void SaveIsawPeaks::exec() { // Section header std::string header = "2 SEQN H K L COL ROW CHAN L2 2_THETA AZ WL D IPK INTI SIGI RFLG"; std::string filename = getPropertyValue("Filename"); PeaksWorkspace_sptr ws = getProperty("InputWorkspace"); std::vector<Peak> peaks = ws->getPeaks(); // We must sort the peaks first by run, then bank #, and save the list of workspace indices of it typedef std::map<int, std::vector<size_t> > bankMap_t; typedef std::map<int, bankMap_t> runMap_t; std::set<int> uniqueBanks; runMap_t runMap; for (size_t i=0; i < peaks.size(); ++i) { Peak & p = peaks[i]; int run = p.getRunNumber(); int bank = 0; std::string bankName = p.getBankName(); if (bankName.size() <= 4) { g_log.information() << "Could not interpret bank number of peak " << i << "(" << bankName << ")\n"; continue; } // Take out the "bank" part of the bank name and convert to an int bankName = bankName.substr(4, bankName.size()-4); Strings::convert(bankName, bank); // Save in the map runMap[run][bank].push_back(i); // Track unique bank numbers uniqueBanks.insert(bank); } Instrument_const_sptr inst = ws->getInstrument(); if (!inst) throw std::runtime_error("No instrument in PeaksWorkspace. Cannot save peaks file."); double l1; V3D beamline; double beamline_norm; V3D samplePos; inst->getInstrumentParameters(l1, beamline, beamline_norm, samplePos); std::ofstream out; bool append = getProperty("AppendFile"); if (append) { out.open( filename.c_str(), std::ios::app); } else { out.open( filename.c_str()); out << "Version: 2.0 Facility: SNS " ; out << " Instrument: " << inst->getName() << " Date: " ; //TODO: The experiment date might be more useful than the instrument date. // For now, this allows the proper instrument to be loaded back after saving. Kernel::DateAndTime expDate = inst->getValidFromDate() + 1.0; out << expDate.to_ISO8601_string() << std::endl; out << "6 L1 T0_SHIFT" << std::endl; out << "7 "<< std::setw( 10 ) ; out << std::setprecision( 4 ) << std::fixed << ( l1*100 ) ; out << std::setw( 12 ) << std::setprecision( 3 ) << std::fixed ; // Time offset of 0.00 for now out << "0.000" << std::endl; // ============================== Save .detcal info ========================================= if (true) { out << "4 DETNUM NROWS NCOLS WIDTH HEIGHT DEPTH DETD CenterX CenterY CenterZ BaseX BaseY BaseZ UpX UpY UpZ" << std::endl; // Here would save each detector... std::set<int>::iterator it; for (it = uniqueBanks.begin(); it != uniqueBanks.end(); it++) { // Build up the bank name int bank = *it; std::ostringstream mess; mess << "bank" << bank; std::string bankName = mess.str(); // Retrieve it RectangularDetector_const_sptr det = boost::dynamic_pointer_cast<const RectangularDetector>(inst->getComponentByName(bankName)); if (det) { // Center of the detector V3D center = det->getPos(); // Distance to center of detector double detd = (center - inst->getSample()->getPos()).norm(); // Base unit vector (along the horizontal, X axis) V3D base = det->getAtXY(det->xpixels()-1,0)->getPos() - det->getAtXY(0,0)->getPos(); base.normalize(); // Up unit vector (along the vertical, Y axis) V3D up = det->getAtXY(0,det->ypixels()-1)->getPos() - det->getAtXY(0,0)->getPos(); up.normalize(); // Write the line out << "5 " << std::setw(6) << std::right << bank << " " << std::setw(6) << std::right << det->xpixels() << " " << std::setw(6) << std::right << det->ypixels() << " " << std::setw(7) << std::right << std::fixed << std::setprecision(4) << 100.0*det->xsize() << " " << std::setw(7) << std::right << std::fixed << std::setprecision(4) << 100.0*det->ysize() << " " << " 0.2000 " << std::setw(6) << std::right << std::fixed << std::setprecision(2) << 100.0*detd << " " << std::setw(9) << std::right << std::fixed << std::setprecision(4) << 100.0*center.X() << " " << std::setw(9) << std::right << std::fixed << std::setprecision(4) << 100.0*center.Y() << " " << std::setw(9) << std::right << std::fixed << std::setprecision(4) << 100.0*center.Z() << " " << std::setw(8) << std::right << std::fixed << std::setprecision(5) << base.X() << " " << std::setw(8) << std::right << std::fixed << std::setprecision(5) << base.Y() << " " << std::setw(8) << std::right << std::fixed << std::setprecision(5) << base.Z() << " " << std::setw(8) << std::right << std::fixed << std::setprecision(5) << up.X() << " " << std::setw(8) << std::right << std::fixed << std::setprecision(5) << up.Y() << " " << std::setw(8) << std::right << std::fixed << std::setprecision(5) << up.Z() << " " << std::endl; } } } } // ============================== Save all Peaks ========================================= // Sequence number int seqNum = 1; // Go in order of run numbers runMap_t::iterator runMap_it; for (runMap_it = runMap.begin(); runMap_it != runMap.end(); runMap_it++) { // Start of a new run int run = runMap_it->first; bankMap_t & bankMap = runMap_it->second; bankMap_t::iterator bankMap_it; for (bankMap_it = bankMap.begin(); bankMap_it != bankMap.end(); bankMap_it++) { // Start of a new bank. int bank = bankMap_it->first; std::vector<size_t> & ids = bankMap_it->second; if (ids.size() > 0) { // Write the bank header out << "0 NRUN DETNUM CHI PHI OMEGA MONCNT" << std::endl; out << "1" << std::setw( 5 ) << run << std::setw( 7 ) << std::right << bank; // Determine goniometer angles by calculating from the goniometer matrix of a peak in the list Goniometer gon(peaks[ids[0]].getGoniometerMatrix()); std::vector<double> angles = gon.getEulerAngles("yzy"); double phi = angles[2]; double chi = angles[1]; double omega = angles[0]; out << std::setw( 7 ) << std::fixed << std::setprecision( 2 ) << chi << " "; out << std::setw( 7 ) << std::fixed << std::setprecision( 2 ) << phi << " "; out << std::setw( 7 ) << std::fixed << std::setprecision( 2 ) << omega << " "; out << std::setw( 7 ) << (int)( 0 ) << std::endl; out << header << std::endl; // Go through each peak at this run / bank for (size_t i=0; i < ids.size(); i++) { size_t wi = ids[i]; Peak & p = peaks[wi]; // Sequence (run) number out << "3" << std::setw( 7 ) << seqNum; // HKL is flipped by -1 due to different q convention in ISAW vs mantid. out << std::setw( 5 ) << Utils::round(-p.getH()) << std::setw( 5 ) << Utils::round(-p.getK()) << std::setw( 5 ) << Utils::round(-p.getL()); // Row/column out << std::setw( 8 ) << std::fixed << std::setprecision( 2 ) << static_cast<double>(p.getCol()) << " "; out << std::setw( 8 ) << std::fixed << std::setprecision( 2 ) << static_cast<double>(p.getRow()) << " "; out << std::setw( 8 ) << std::fixed << std::setprecision( 0 ) << p.getTOF() << " "; out << std::setw( 9 ) << std::fixed << std::setprecision( 3 ) << (p.getL2()*100.0) << " "; // This is the scattered beam direction V3D dir = p.getDetPos() - inst->getSample()->getPos(); double scattering, azimuth; // Two-theta = polar angle = scattering angle = between +Z vector and the scattered beam scattering = dir.angle( V3D(0.0, 0.0, 1.0) ); // "Azimuthal" angle: project the beam onto the XY plane, and measure the angle between that and the +X axis (right-handed) azimuth = atan2( dir.Y(), dir.X() ); out << std::setw( 9 ) << std::fixed << std::setprecision( 5 ) << scattering << " "; //two-theta scattering out << std::setw( 9 ) << std::fixed << std::setprecision( 5 ) << azimuth << " "; out << std::setw( 10 ) << std::fixed << std::setprecision( 6 ) << p.getWavelength() << " "; out << std::setw( 9 ) << std::fixed << std::setprecision( 4 ) << p.getDSpacing() << " "; out << std::setw( 8 ) << std::fixed << int(p.getBinCount()) << std::setw( 10 ) << " " << std::fixed << std::setprecision( 2 ) << p.getIntensity() << " "; out << std::setw( 7 ) << std::fixed << std::setprecision( 2 ) << p.getSigmaIntensity() << " "; int thisReflag = 310; out << std::setw( 5 ) << thisReflag; out << std::endl; // Count the sequence seqNum++; } } } } out.flush(); out.close(); // //REMOVE: // std::string line; // std::ifstream myfile (filename.c_str()); // if (myfile.is_open()) // { // while ( myfile.good() ) // { // getline (myfile,line); // std::cout << line << std::endl; // } // myfile.close(); // } }
/** Read one peak in a line of an ISAW peaks file. * * @param outWS :: workspace to add peaks to * @param lastStr [in,out] :: last word (the one at the start of the line) * @param in :: input stream * @param seqNum [out] :: the sequence number of the peak * @param bankName :: the bank number from the ISAW file. * @return the Peak the Peak object created */ Mantid::DataObjects::Peak readPeak( PeaksWorkspace_sptr outWS, std::string & lastStr, std::ifstream& in, int & seqNum, std::string bankName) { double h ; double k ; double l ; double col ; double row ; double wl ; double IPK ; double Inti ; double SigI ; seqNum = -1; std::string s = lastStr; if( s.length() < 1 && in.good() )//blank line { readToEndOfLine( in , true ); s = getWord( in , false );; } if( s.length() < 1 ) throw std::runtime_error("Empty peak line encountered."); if( s.compare( "2" ) == 0 ) { readToEndOfLine( in , true ); for( s = getWord( in , false ) ; s.length() < 1 && in.good() ; s = getWord( in , true ) ) { s = getWord( in , false ); } } if( s.length() < 1 ) throw std::runtime_error("Empty peak line encountered."); if( s.compare( "3" ) != 0 ) throw std::runtime_error("Empty peak line encountered."); seqNum = atoi( getWord( in , false ).c_str() ); h = strtod( getWord( in , false ).c_str() , 0 ) ; k = strtod( getWord( in , false ).c_str() , 0 ) ; l = strtod( getWord( in , false ).c_str() , 0 ) ; col = strtod( getWord( in , false ).c_str() , 0 ) ; row = strtod( getWord( in , false ).c_str() , 0 ) ; strtod( getWord( in , false ).c_str() , 0 ) ; //chan strtod( getWord( in , false ).c_str() , 0 ) ; //L2 strtod( getWord( in , false ).c_str() , 0 ) ; //ScatAng strtod( getWord( in , false ).c_str() , 0 ) ; //Az wl = strtod( getWord( in , false ).c_str() , 0 ) ; strtod( getWord( in , false ).c_str() , 0 ) ; //D IPK = strtod( getWord( in , false ).c_str() , 0 ) ; Inti = strtod( getWord( in , false ).c_str() , 0 ) ; SigI = strtod( getWord( in , false ).c_str() , 0 ) ; atoi( getWord( in , false ).c_str() ) ; // iReflag // Finish the line and get the first word of next line readToEndOfLine( in , true ); lastStr = getWord( in , false ); // Find the detector ID from row/col Instrument_const_sptr inst = outWS->getInstrument(); if (!inst) throw std::runtime_error("No instrument in PeaksWorkspace!"); IComponent_const_sptr bank = inst->getComponentByName(bankName); if (!bank) throw std::runtime_error("Bank named " + bankName + " not found!"); RectangularDetector_const_sptr rect = boost::dynamic_pointer_cast<const RectangularDetector>(bank); if (!rect) throw std::runtime_error("Bank named " + bankName + " is not a RectangularDetector!"); IDetector_sptr det = rect->getAtXY(int(col), int(row)); if (!det) throw std::runtime_error("Detector not found on " + bankName + "!"); //Create the peak object Peak peak(outWS->getInstrument(), det->getID(), wl); // HKL's are flipped by -1 because of the internal Q convention peak.setHKL(-h,-k,-l); peak.setIntensity(Inti); peak.setSigmaIntensity(SigI); peak.setBinCount(IPK); // Return the peak return peak; }
/** Execute the algorithm. */ void CreateGroupingWorkspace::exec() { MatrixWorkspace_sptr inWS = getProperty("InputWorkspace"); std::string InstrumentName = getPropertyValue("InstrumentName"); std::string InstrumentFilename = getPropertyValue("InstrumentFilename"); std::string OldCalFilename = getPropertyValue("OldCalFilename"); std::string GroupNames = getPropertyValue("GroupNames"); std::string grouping = getPropertyValue("GroupDetectorsBy"); int numGroups = getProperty("FixedGroupCount"); std::string componentName = getPropertyValue("ComponentName"); // Some validation int numParams = 0; if (inWS) numParams++; if (!InstrumentName.empty()) numParams++; if (!InstrumentFilename.empty()) numParams++; if (numParams > 1) throw std::invalid_argument("You must specify exactly ONE way to get an " "instrument (workspace, instrument name, or " "IDF file). You specified more than one."); if (numParams == 0) throw std::invalid_argument("You must specify exactly ONE way to get an " "instrument (workspace, instrument name, or " "IDF file). You specified none."); if (!OldCalFilename.empty() && !GroupNames.empty()) throw std::invalid_argument("You must specify either to use the " "OldCalFilename parameter OR GroupNames but " "not both!"); bool sortnames = false; // ---------- Get the instrument one of 3 ways --------------------------- Instrument_const_sptr inst; if (inWS) { inst = inWS->getInstrument(); } else { Algorithm_sptr childAlg = createChildAlgorithm("LoadInstrument", 0.0, 0.2); MatrixWorkspace_sptr tempWS = boost::make_shared<Workspace2D>(); childAlg->setProperty<MatrixWorkspace_sptr>("Workspace", tempWS); childAlg->setPropertyValue("Filename", InstrumentFilename); childAlg->setProperty("RewriteSpectraMap", Mantid::Kernel::OptionalBool(true)); childAlg->setPropertyValue("InstrumentName", InstrumentName); childAlg->executeAsChildAlg(); inst = tempWS->getInstrument(); } if (GroupNames.empty() && OldCalFilename.empty()) { if (grouping.compare("All") == 0) { GroupNames = inst->getName(); } else if (inst->getName().compare("SNAP") == 0 && grouping.compare("Group") == 0) { GroupNames = "East,West"; } else { sortnames = true; GroupNames = ""; int maxRecurseDepth = this->getProperty("MaxRecursionDepth"); // cppcheck-suppress syntaxError PRAGMA_OMP(parallel for schedule(dynamic, 1) ) for (int num = 0; num < 300; ++num) { PARALLEL_START_INTERUPT_REGION std::ostringstream mess; mess << grouping << num; IComponent_const_sptr comp = inst->getComponentByName(mess.str(), maxRecurseDepth); PARALLEL_CRITICAL(GroupNames) if (comp) GroupNames += mess.str() + ","; PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION } } // --------------------------- Create the output -------------------------- auto outWS = boost::make_shared<GroupingWorkspace>(inst); this->setProperty("OutputWorkspace", outWS); // This will get the grouping std::map<detid_t, int> detIDtoGroup; Progress prog(this, 0.2, 1.0, outWS->getNumberHistograms()); // Make the grouping one of three ways: if (!GroupNames.empty()) detIDtoGroup = makeGroupingByNames(GroupNames, inst, prog, sortnames); else if (!OldCalFilename.empty()) detIDtoGroup = readGroupingFile(OldCalFilename, prog); else if ((numGroups > 0) && !componentName.empty()) detIDtoGroup = makeGroupingByNumGroups(componentName, numGroups, inst, prog); g_log.information() << detIDtoGroup.size() << " entries in the detectorID-to-group map.\n"; setProperty("NumberGroupedSpectraResult", static_cast<int>(detIDtoGroup.size())); if (detIDtoGroup.empty()) { g_log.warning() << "Creating empty group workspace\n"; setProperty("NumberGroupsResult", static_cast<int>(0)); } else { size_t numNotFound = 0; // Make the groups, if any std::map<detid_t, int>::const_iterator it_end = detIDtoGroup.end(); std::map<detid_t, int>::const_iterator it; std::unordered_set<int> groupCount; for (it = detIDtoGroup.begin(); it != it_end; ++it) { int detID = it->first; int group = it->second; groupCount.insert(group); try { outWS->setValue(detID, double(group)); } catch (std::invalid_argument &) { numNotFound++; } } setProperty("NumberGroupsResult", static_cast<int>(groupCount.size())); if (numNotFound > 0) g_log.warning() << numNotFound << " detector IDs (out of " << detIDtoGroup.size() << ") were not found in the instrument\n."; } }
/** Executes the algorithm. * * @throw std::runtime_error Thrown with Workspace problems */ void RotateInstrumentComponent::exec() { // Get the workspace MatrixWorkspace_sptr WS = getProperty("Workspace"); const std::string ComponentName = getProperty("ComponentName"); const int DetID = getProperty("DetectorID"); const double X = getProperty("X"); const double Y = getProperty("Y"); const double Z = getProperty("Z"); const double angle = getProperty("Angle"); const bool RelativeRotation = getProperty("RelativeRotation"); if (X + Y + Z == 0.0) throw std::invalid_argument("The rotation axis must not be a zero vector"); Instrument_const_sptr inst = WS->getInstrument(); IComponent_const_sptr comp; // Find the component to move if (DetID != -1) { comp = inst->getDetector(DetID); if (comp == 0) { std::ostringstream mess; mess<<"Detector with ID "<<DetID<<" was not found."; g_log.error(mess.str()); throw std::runtime_error(mess.str()); } } else if (!ComponentName.empty()) { comp = inst->getComponentByName(ComponentName); if (comp == 0) { std::ostringstream mess; mess<<"Component with name "<<ComponentName<<" was not found."; g_log.error(mess.str()); throw std::runtime_error(mess.str()); } } else { g_log.error("DetectorID or ComponentName must be given."); throw std::invalid_argument("DetectorID or ComponentName must be given."); } // First set new relative or absolute rotation Quat Rot; if (RelativeRotation) { Quat Rot0 = comp->getRelativeRot(); Rot = Rot0 * Quat(angle,V3D(X,Y,Z)); } else { Rot = Quat(angle,V3D(X,Y,Z)); // Then find the corresponding relative position boost::shared_ptr<const IComponent> parent = comp->getParent(); if (parent) { Quat rot0 = parent->getRelativeRot(); rot0.inverse(); Rot = Rot * rot0; } } //Need to get the address to the base instrument component Geometry::ParameterMap& pmap = WS->instrumentParameters(); // Add a parameter for the new rotation pmap.addQuat(comp.get(), "rot", Rot); return; }