Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Waters dda and lockmass fixes #2770

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 23 additions & 36 deletions pwiz/data/vendor_readers/Waters/SpectrumList_Waters.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,30 +108,12 @@ PWIZ_API_DECL SpectrumPtr SpectrumList_Waters::spectrum(size_t index, bool getBi

PWIZ_API_DECL bool SpectrumList_Waters::isLockMassFunction(int function) const
{
if (lockmassFunction_ == LOCKMASS_FUNCTION_UNINIT) // See if we can figure out which is the lockmass function
if (lockmassFunction_ == LOCKMASS_FUNCTION_UNINIT)
{
bool hasChromMS = false;
const set<int>& functionsWithChromFiles = rawdata_->FunctionsWithChromFiles();
int apparentLockmassFunction = LOCKMASS_FUNCTION_UNINIT;
BOOST_FOREACH(int tryFunction, rawdata_->FunctionIndexList())
if (!rawdata_->Info.TryGetLockMassFunction(lockmassFunction_))
{
int msLevel;
CVID spectrumType;
translateFunctionType(WatersToPwizFunctionType(rawdata_->Info.GetFunctionType(tryFunction)), msLevel, spectrumType);
if (cv::cvIsA(spectrumType, MS_mass_spectrum))
{
// Function has MS data - but does it have a _CHRO*.dat file? We've observed that lockmass functions don't
if (functionsWithChromFiles.find(tryFunction) == functionsWithChromFiles.end())
{
apparentLockmassFunction = tryFunction; // No _CHRO*.DAT file, might be lockmass (value is 0-based)
}
else
{
hasChromMS = true; // At least one function does have a _CHRO*.dat file
}
}
lockmassFunction_ = LOCKMASS_FUNCTION_UNKNOWN;
}
lockmassFunction_ = hasChromMS ? apparentLockmassFunction : LOCKMASS_FUNCTION_UNKNOWN;
}
return function == lockmassFunction_;
}
Expand Down Expand Up @@ -293,9 +275,10 @@ PWIZ_API_DECL SpectrumPtr SpectrumList_Waters::spectrum(size_t index, DetailLeve
if (msLevel > 1 && isMS)
{
double setMass = 0;
double ddaPrecursorMass = 0;
if (useDDAProcessor_)
{
setMass = ie.setMass;
getDDAPrecursorMasses(index, setMass, ddaPrecursorMass);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this mean only the DDA processing mode will get lockmass-corrected m/zs? I suppose that is the most important case but it would be nice to be consistent to always provide all lockmass-corrected m/zs for all m/zs when lockmass is applied. Was an SDK function that just takes an m/z and returns the lockmass-corrected m/z not feasible?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the only other cases where you could lm correct the setmass would be for SONAR data. If you applied the correction to SONAR data then you would introduce a change that the SONAR quad window positions would vary slightly from spectrum to spectrum as lockmass correction varies over time.

There is an SDK function which returns a lockmass correction
int getLockMassCorrection(const CMassLynxBaseProcessor mlLockMassProcessor, const float retentionTime, float* pGain);
though that gives a 'gain' you have to multiply with your m/z to get the lockmass corrected version, a method which takes the uncorrected m/z and returns the corrected version would be nicer. The correction we are applying isn't quite as simple as that though. The lockmass correction which is used is the correction for the RT of the survey scan proceeding the MSMS spectrum, though in practice this will only make a tiny difference. The rationale behind this is that the setmass was selected based on measurements of the survey scan.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good to know about the SDK function. I'd like to use for the setMass even when DDA processing mode hasn't been applied. But you're right that's probably the only situation it makes sense. It would probably be undesirable for the m/z bounds of DIA isolation windows to change, for example.

}
else if (!hasSonarFunctions())
{
Expand Down Expand Up @@ -328,7 +311,7 @@ PWIZ_API_DECL SpectrumPtr SpectrumList_Waters::spectrum(size_t index, DetailLeve
precursor.activation.set(MS_collision_energy, collisionEnergy, UO_electronvolt);


double precursorMass = useDDAProcessor_ ? ie.precursorMass : setMass;
double precursorMass = useDDAProcessor_ ? ddaPrecursorMass : setMass;
SelectedIon selectedIon(precursorMass);

precursor.selectedIons.push_back(selectedIon);
Expand Down Expand Up @@ -373,9 +356,9 @@ PWIZ_API_DECL SpectrumPtr SpectrumList_Waters::spectrum(size_t index, DetailLeve

if (useDDAProcessor_)
{
getDDAScan(index, masses, intensities);
getDDAScan(index, doCentroid, masses, intensities);
}
else if (ie.block >= 0 && !doCentroid && !isLockMassFunction(ie.function)) // Lockmass won't have IMS
else if (ie.block >= 0 && !doCentroid)
{
MassLynxRawScanReader& scanReader = rawdata_->GetCompressedDataClusterForBlock(ie.function, ie.block);
scanReader.ReadScan(ie.function, ie.block, ie.scan, masses, intensities);
Expand Down Expand Up @@ -770,14 +753,9 @@ PWIZ_API_DECL void SpectrumList_Waters::createIndex()
size_ = index_.size();
}

PWIZ_API_DECL void SpectrumList_Waters::getDDAScan(unsigned int index, vector<float>& masses, vector<float>& intensities) const
PWIZ_API_DECL void SpectrumList_Waters::getDDAScan(unsigned int index, bool doCentroid, vector<float>& masses, vector<float>& intensities) const
{
using namespace boost::spirit::karma;

float setMass, precursorMass, retentionTime;
int function, startScan, endScan;
bool isMS1;
rawdata_->GetDDAScan(index, retentionTime, function, startScan, endScan, isMS1, setMass, precursorMass, masses, intensities);
rawdata_->GetDDAScan(index, doCentroid, masses, intensities);
}

PWIZ_API_DECL void SpectrumList_Waters::createDDAIndex()
Expand All @@ -793,17 +771,14 @@ PWIZ_API_DECL void SpectrumList_Waters::createDDAIndex()

float setMass, precursorMass, retentionTime;
int function, startScan, endScan;
vector<float> masses, intensities;
bool isMS1;
rawdata_->GetDDAScan(i, retentionTime, function, startScan, endScan, isMS1, setMass, precursorMass, masses, intensities);
rawdata_->GetDDAScanInfo(i, retentionTime, function, startScan, endScan, isMS1, setMass, precursorMass);

ie.function = function;
ie.process = 0;
ie.block = -1; // The SDK DDA processor doesn't yet support ion mobility data
ie.scan = startScan; // While it might combine multiple scans, use the first for getting the metadata
ie.index = i;
ie.setMass = setMass;
ie.precursorMass = precursorMass;

std::back_insert_iterator<std::string> sink(ie.id);
if (startScan == endScan)
Expand All @@ -822,6 +797,18 @@ PWIZ_API_DECL void SpectrumList_Waters::createDDAIndex()
}
}

PWIZ_API_DECL void SpectrumList_Waters::getDDAPrecursorMasses(int index, double& setMass, double& precursorMass) const
{
// We get updated precursor mass at the point of reading each scan to ensure the lockmass
// correction is applied, which might not be the case when the index is created
float retentionTime, fSetMass, fPrecursorMass;
int function, startScan, endScan;
bool isMS1;
rawdata_->GetDDAScanInfo(index, retentionTime, function, startScan, endScan, isMS1, fSetMass, fPrecursorMass);

setMass = fSetMass;
precursorMass = fPrecursorMass;
}

} // detail
} // msdata
Expand Down
5 changes: 2 additions & 3 deletions pwiz/data/vendor_readers/Waters/SpectrumList_Waters.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,6 @@ class PWIZ_API_DECL SpectrumList_Waters : public SpectrumListIonMobilityBase
int process;
int scan;
int block; // block < 0 is not ion mobility
float setMass; // DDA-only
float precursorMass; // DDA-only
};

mutable vector<IndexEntry> index_;
Expand All @@ -117,7 +115,8 @@ class PWIZ_API_DECL SpectrumList_Waters : public SpectrumListIonMobilityBase

void createIndex();
void createDDAIndex();
void getDDAScan(unsigned int index, vector<float>& masses, vector<float>& intensities) const;
void getDDAScan(unsigned int index, bool doCentroid, vector<float>& masses, vector<float>& intensities) const;
void getDDAPrecursorMasses(int index, double& setMass, double& precursorMass) const;

#endif // PWIZ_READER_WATERS

Expand Down
22 changes: 14 additions & 8 deletions pwiz_aux/msrc/utility/vendor_api/Waters/WatersRawFile.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ class MassLynxRawProcessorWithProgress : public MassLynxRawProcessor
public:
MassLynxRawProcessorWithProgress(const string& rawpath, IterationListenerRegistry* ilr = nullptr) : ilr_(ilr), numSpectra_(100), lastSpectrum_(0)
{
SetRawPath(rawpath);
SetRawData(rawpath);
}

void SetNumSpectra(int numSpectra) { numSpectra_ = numSpectra; }
Expand Down Expand Up @@ -135,7 +135,7 @@ struct PWIZ_API_DECL RawData
hasIonMobility_(false),
hasSONAR_(false)
{
LockMass.SetRawReader(Reader);
LockMass.SetRawData(Reader);

// Count the number of _FUNC[0-9]{3}.DAT files, starting with _FUNC001.DAT
// For functions over 100, the names become _FUNC0100.DAT
Expand Down Expand Up @@ -409,10 +409,16 @@ struct PWIZ_API_DECL RawData
return DDAProcessor.GetScanCount();
}

bool GetDDAScan(const int& nWhichIndex, float& RT, int& function, int& startScan, int& endScan, bool& isMS1, float& setMass, float& precursorMass, vector<float>& masses, vector<float>& intensities)
bool GetDDAScan(const int& nWhichIndex, bool doCentroid, vector<float>& masses, vector<float>& intensities)
{
MassLynxParameters parameters;
bool success = DDAProcessor.GetScan(nWhichIndex, masses, intensities, parameters);
return DDAProcessor.SetCentroid(doCentroid).GetScan(nWhichIndex, masses, intensities, parameters);
}

bool GetDDAScanInfo(const int& nWhichIndex, float& RT, int& function, int& startScan, int& endScan, bool& isMS1, float& setMass, float& precursorMass)
{
MassLynxParameters parameters;
bool success = DDAProcessor.GetScanInfo(nWhichIndex, parameters);

if (success)
{
Expand All @@ -433,9 +439,9 @@ struct PWIZ_API_DECL RawData

bool GetIsolationWindow(float& lowerOffset, float& upperOffset)
{
MassLynxParameters parameters = DDAProcessor.GetParameters();
float lowerOffsetParam = lexical_cast<float>(parameters.Get(DDAParameter::LOWEROFFSET));
float upperOffsetParam = lexical_cast<float>(parameters.Get(DDAParameter::UPPEROFFSET));
MassLynxParameters parameters = DDAProcessor.GetQuadIsolationWindowParameters();
float lowerOffsetParam = lexical_cast<float>(parameters.Get(DDAIsolationWindowParameter::LOWEROFFSET));
float upperOffsetParam = lexical_cast<float>(parameters.Get(DDAIsolationWindowParameter::UPPEROFFSET));

if (lowerOffsetParam == 0 && upperOffsetParam == 0)
return false;
Expand All @@ -458,7 +464,7 @@ struct PWIZ_API_DECL RawData

private:
MassLynxLockMassProcessor LockMass;
MassLynxDDAProcessor DDAProcessor;
Extended::MassLynxDDAProcessor DDAProcessor;
MassLynxScanProcessor ScanProcessor;
mutable MassLynxRawProcessorWithProgress PeakPicker;
mutable int workingDriftTimeFunctionIndex_;
Expand Down
Binary file modified pwiz_aux/msrc/utility/vendor_api_Waters.7z
Binary file not shown.