Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
1b4bc5e
first complete solution
trishorts Feb 17, 2026
3151b09
this is cool
trishorts Feb 17, 2026
3b1a4ab
save
trishorts Feb 17, 2026
24fd9a7
this actually works despite what my computer says
trishorts Feb 17, 2026
01b32fc
mo better
trishorts Feb 18, 2026
9bd19dc
with mods like alkylation
trishorts Feb 18, 2026
63a09b7
lets build a model
trishorts Feb 18, 2026
4d6841f
lets see what this does
trishorts Feb 18, 2026
7b4f44f
i think there is more coming
trishorts Feb 18, 2026
83da05a
hmmm
trishorts Feb 18, 2026
8b04804
maybe
trishorts Feb 18, 2026
fa40eb7
this generates intermediate analysis
trishorts Feb 18, 2026
8a8931b
full analysis final no mods
trishorts Feb 18, 2026
03eed9d
working quite well
trishorts Feb 19, 2026
08465b0
update spectral library reader for internal ions
trishorts Feb 20, 2026
1cf80b3
unit test confirms read library spectrum with internal ions
trishorts Feb 20, 2026
e26d772
update library spectrum ToString to write internal ions
trishorts Feb 20, 2026
34bc221
test library spectrum writer for proper handling of internal ions
trishorts Feb 20, 2026
cd0c2bd
confirm spectrum similarity is correctly computed from library spectr…
trishorts Feb 20, 2026
961864a
create decoy spectra that include internal ions
trishorts Feb 20, 2026
4b799ea
test decoy library generation with internal ions
trishorts Feb 20, 2026
0a19699
summary comment
trishorts Feb 20, 2026
e721e74
add local internal fragment model infrastructure and unit tests
trishorts Feb 20, 2026
a5fc101
local model to predict internal ions with unit tests
trishorts Feb 20, 2026
13057a5
that was harder than it needed to be
trishorts Feb 20, 2026
b3bf111
i dont think this will help
trishorts Feb 20, 2026
23b034e
join library spectra and retention times produces by separate models
trishorts Feb 23, 2026
a4ebfc1
fix koina fragmentintensitymodel and local internalfragmentintensitym…
trishorts Feb 23, 2026
d805238
dissarray
trishorts Feb 23, 2026
3a1b896
not working but compiling
trishorts Feb 23, 2026
2e2d7f2
j
trishorts Feb 23, 2026
85c739d
this aint workin
trishorts Feb 23, 2026
6e014bb
fix broke tests
trishorts Feb 24, 2026
18f147e
everything working about to move to a nce aware model
trishorts Feb 24, 2026
5d413ae
v
trishorts Feb 24, 2026
207d4a1
Merge remote-tracking branch 'upstream/master' into intenenalIonsSquared
trishorts Jun 3, 2026
2b5c454
refactor(predictions): port internal-ion models to rewritten Koina API
trishorts Jun 3, 2026
96dcae1
refactor(internal-ions): drop unused HasPhosphorylation/HasMetalOnTer…
trishorts Jun 3, 2026
62b5a53
fix(internal-ions): exclude terminal spans and tolerate duplicate spe…
trishorts Jun 3, 2026
e57fdbd
test(internal-ions): fix relocated msp path and guard local-data eval…
trishorts Jun 3, 2026
6c385d2
fix(internal-ions): harden observed-fragment analysis pipeline
trishorts Jun 3, 2026
12ce7a4
refactor(internal-ions): idempotent generation, shared charge set, dr…
trishorts Jun 3, 2026
8cc2975
refactor(spectral-library): revert cosmetic churn from internal-ion c…
trishorts Jun 3, 2026
905e29e
test(internal-ions): flag Step11 analysis harness for removal
trishorts Jun 3, 2026
f03ec80
test(internal-ions): cover observed-fragment analysis pipeline
trishorts Jun 3, 2026
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
71 changes: 57 additions & 14 deletions mzLib/Omics/SpectralLibrary/LibrarySpectrum.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,47 +63,90 @@ public override string ToString()
{
StringBuilder spectrum = new StringBuilder();
spectrum.Append("Name: " + Name);
spectrum.Append("\nMW: " + PrecursorMz);
spectrum.Append("\nMW: " + PrecursorMz.ToString(CultureInfo.InvariantCulture));
spectrum.Append("\nComment: ");
spectrum.Append("Parent=" + PrecursorMz);
spectrum.Append(" RT=" + RetentionTime);
spectrum.Append("Parent=" + PrecursorMz.ToString(CultureInfo.InvariantCulture));
spectrum.Append(" RT=" + RetentionTime?.ToString(CultureInfo.InvariantCulture));
spectrum.Append("\nNum peaks: " + MatchedFragmentIons.Count);

double maxIntensity = MatchedFragmentIons.Select(b => b.Intensity).Max();

foreach (MatchedFragmentIon matchedIon in MatchedFragmentIons)
{
double intensityFraction = matchedIon.Intensity / maxIntensity;
var product = matchedIon.NeutralTheoreticalProduct;

string neutralLoss = null;
if (matchedIon.NeutralTheoreticalProduct.NeutralLoss != 0)
if (product.NeutralLoss != 0)
{
neutralLoss = "-" + matchedIon.NeutralTheoreticalProduct.NeutralLoss;
neutralLoss = "-" + product.NeutralLoss.ToString(CultureInfo.InvariantCulture);
}

spectrum.Append("\n" + matchedIon.Mz + "\t" + intensityFraction + "\t" + "\"" +
matchedIon.NeutralTheoreticalProduct.ProductType.ToString() +
matchedIon.NeutralTheoreticalProduct.FragmentNumber.ToString() + "^" +
matchedIon.Charge + neutralLoss + "/" + 0 + "ppm" + "\"");
string ionAnnotation;
if (product.IsInternalFragment)
{
// Internal fragment format: bIb[31-34]^1/0ppm
ionAnnotation = $"{product.ProductType}I{product.SecondaryProductType}[{product.FragmentNumber}-{product.SecondaryFragmentNumber}]^{matchedIon.Charge}{neutralLoss}/0ppm";
}
else
{
// Standard ion format: b3^1/0ppm or b3^1-97.976895573/0ppm
ionAnnotation = $"{product.ProductType}{product.FragmentNumber}^{matchedIon.Charge}{neutralLoss}/0ppm";
}

spectrum.Append("\n" + matchedIon.Mz.ToString(CultureInfo.InvariantCulture) + "\t" +
intensityFraction.ToString(CultureInfo.InvariantCulture) + "\t\"" + ionAnnotation + "\"");
}

return spectrum.ToString();
}

// For decoy library spectrum generation, we use the predicted m/z value of the decoy sequence and we use the decoy's corresponding target's library spectrum's intensity values as decoy's intensities
/// <summary>
/// Generates a decoy library spectrum from a target spectrum by matching fragment ions.
/// For each target ion, finds the corresponding decoy theoretical product with matching properties
/// and creates a new matched fragment ion using the decoy's m/z but preserving the target's intensity.
/// </summary>
/// <remarks>
/// Matching logic:
/// <list type="bullet">
/// <item><description>Standard ions: Match by ProductType and FragmentNumber</description></item>
/// <item><description>Internal fragment ions: Additionally require matching SecondaryProductType and SecondaryFragmentNumber</description></item>
/// </list>
/// This prevents false matches between standard and internal ions (e.g., b2 vs bIb[2-5]).
/// </remarks>
/// <param name="targetSpectrum">The target library spectrum containing matched fragment ions to reverse</param>
/// <param name="decoyPeptideTheorProducts">Theoretical products from the decoy peptide sequence</param>
/// <returns>A list of matched fragment ions for the decoy spectrum, preserving target intensities with decoy m/z values</returns>

public static List<MatchedFragmentIon> GetDecoyLibrarySpectrumFromTargetByReverse(LibrarySpectrum targetSpectrum, List<Product> decoyPeptideTheorProducts)
{
var decoyFragmentIons = new List<MatchedFragmentIon>();
foreach (var targetIon in targetSpectrum.MatchedFragmentIons)
{
foreach (var decoyPeptideTheorIon in decoyPeptideTheorProducts)
{
if (targetIon.NeutralTheoreticalProduct.ProductType == decoyPeptideTheorIon.ProductType && targetIon.NeutralTheoreticalProduct.FragmentNumber == decoyPeptideTheorIon.FragmentNumber)
var targetProduct = targetIon.NeutralTheoreticalProduct;

// Check primary properties
bool primaryMatch = targetProduct.ProductType == decoyPeptideTheorIon.ProductType
&& targetProduct.FragmentNumber == decoyPeptideTheorIon.FragmentNumber;

if (!primaryMatch) continue;

// For internal fragments, also check secondary properties
if (targetProduct.IsInternalFragment || decoyPeptideTheorIon.IsInternalFragment)
{
double decoyFragmentMz = decoyPeptideTheorIon.NeutralMass.ToMz(targetIon.Charge);
Product temProduct = decoyPeptideTheorIon;
decoyFragmentIons.Add(new MatchedFragmentIon(temProduct, decoyFragmentMz, targetIon.Intensity, targetIon.Charge));
// Both must be internal fragments with matching secondary properties
if (targetProduct.IsInternalFragment != decoyPeptideTheorIon.IsInternalFragment)
continue;
if (targetProduct.SecondaryProductType != decoyPeptideTheorIon.SecondaryProductType)
continue;
if (targetProduct.SecondaryFragmentNumber != decoyPeptideTheorIon.SecondaryFragmentNumber)
continue;
}

double decoyFragmentMz = decoyPeptideTheorIon.NeutralMass.ToMz(targetIon.Charge);
decoyFragmentIons.Add(new MatchedFragmentIon(decoyPeptideTheorIon, decoyFragmentMz, targetIon.Intensity, targetIon.Charge));
}
}
return decoyFragmentIons;
Expand Down
Loading
Loading