Skip to content

Commit

Permalink
feat(octochemdb): add searchInsilicoSpectra by masses and mf
Browse files Browse the repository at this point in the history
  • Loading branch information
lpatiny committed Dec 5, 2023
1 parent d894dc5 commit 9f5e637
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 23 deletions.
17 changes: 10 additions & 7 deletions packages/ms-spectrum/src/MSComparator.js
Original file line number Diff line number Diff line change
Expand Up @@ -145,14 +145,17 @@ function normalizeAndCacheData(cache, dataXY, options = {}) {
}

function returnSimilarity(aligned, options) {
if (options.minNbCommonPeaks) {
let commonPeaks = 0;
for (let i = 0; i < aligned.ys[0].length; i++) {
if (aligned.ys[0][i] !== 0 && aligned.ys[1][i] !== 0) {
commonPeaks++;
}
let commonPeaks = 0;
for (let i = 0; i < aligned.ys[0].length; i++) {
if (aligned.ys[0][i] !== 0 && aligned.ys[1][i] !== 0) {
commonPeaks++;
}
if (commonPeaks < options.minNbCommonPeaks) return 0;
}
if (
commonPeaks === 0 ||
(options.minNbCommonPeaks && commonPeaks < options.minNbCommonPeaks)
) {
return 0;
}

const vector1 = new Float64Array(aligned.x.length);
Expand Down
17 changes: 14 additions & 3 deletions packages/octochemdb/src/OctoChemDB.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import { compoundsFromMF } from './compoundsFromMF.js';
import { massSpectra } from './massSpectra.js';
import { mfsFromEMs } from './mfsFromEMs.js';
import { pubmedCompounds } from './pubmedCompounds.js';
import { searchInSilicoSpectra } from './searchInSilicoSpectra.js';
import { searchInSilicoSpectraByMF } from './searchInSilicoSpectraByMF.js';
import { searchInSilicoSpectraByMasses } from './searchInSilicoSpectraByMasses.js';
import { searchMasses } from './searchMasses.js';

export class OctoChemDB {
Expand Down Expand Up @@ -45,8 +46,18 @@ export class OctoChemDB {
return massSpectra({ baseURL: this.baseURL, ...options });
}

async searchInSilicoSpectra(options = {}) {
return searchInSilicoSpectra({ baseURL: this.baseURL, ...options });
async searchInSilicoSpectraByMF(spectrum, mf, options = {}) {
return searchInSilicoSpectraByMF(spectrum, mf, {
baseURL: this.baseURL,
...options,
});
}

async searchInSilicoSpectraByMasses(spectrum, masses, options = {}) {
return searchInSilicoSpectraByMasses(spectrum, masses, {
baseURL: this.baseURL,
...options,
});
}

async pubmedCompounds(pubmedID, options = {}) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { readFileSync } from 'fs';
import { join } from 'path';

import { searchInSilicoSpectra } from '../searchInSilicoSpectra.js';
import { searchInSilicoSpectraByMF } from '../searchInSilicoSpectraByMF.js';

test('searchInsilicoSpectra', async () => {
const mdma = JSON.parse(
readFileSync(join(__dirname, 'data/mdma.json'), 'utf8'),
);

const results = await searchInSilicoSpectra(mdma, 'C11H15NO2', {
const results = await searchInSilicoSpectraByMF(mdma, 'C11H15NO2', {
precision: 50,
});
expect(results.length).toBeGreaterThan(5);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { readFileSync } from 'fs';
import { join } from 'path';

import { Spectrum } from 'ms-spectrum';

import { OctoChemDB } from '../OctoChemDB.js';

test('searchInSilicoSpectraByMasses', async () => {
const mdma = JSON.parse(
readFileSync(join(__dirname, 'data/mdma.json'), 'utf8'),
);
// by default peaks over 1%
const spectrum = new Spectrum(mdma).getPeaksAsDataXY();
const octoChemDB = new OctoChemDB();

const results = await octoChemDB.searchInSilicoSpectraByMasses(
spectrum,
194.1174,
{
precision: 20,
ionizations: 'H+',
},
);
expect(results.length).toBeGreaterThan(5);
});
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import { MSComparator } from 'ms-spectrum';
import { fetchJSON } from './utils/fetchJSON.js';

/**
*
* @param {object} spectrum - The experimental spectrum to compare to
* @param {string} mf - Molecular formula of the non ionized molecule
* @param {object} [options={}]
* @param {string} [options.baseURL='https://octochemdb.cheminfo.org/'] - URL of the webservice
* @param {number|string|number[]} [options.masses] - Observed fragment masses
* @param {string} [options.mf] - Molecular formula of the non ionized molecule (not available for inSilicoFragments)
* @param {number} [options.precision=100] - Precision (accuracy) of the monoisotopic mass in ppm
* @param {number} [options.limit=1000] - Maximal number of entries to return
Expand All @@ -16,7 +16,7 @@ import { fetchJSON } from './utils/fetchJSON.js';
* @param {string} [options.route='inSilicoFragments/v1/search'] - Route to use
*/

export async function searchInSilicoSpectra(spectrum, mf, options = {}) {
export async function searchInSilicoSpectraByMF(spectrum, mf, options = {}) {
const {
route = 'inSilicoFragments/v1/search',
baseURL = 'https://octochemdb.cheminfo.org/',
Expand Down Expand Up @@ -56,8 +56,8 @@ export async function searchInSilicoSpectra(spectrum, mf, options = {}) {
);
if (similarity > 0) {
finals.push({
...result,
similarity,
data: result.data,
});
}
}
Expand Down
77 changes: 77 additions & 0 deletions packages/octochemdb/src/searchInSilicoSpectraByMasses.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { MSComparator } from 'ms-spectrum';

import { searchWithIonizations } from './utils/searchWithIonizations.js';

/**
* @param {object} spectrum - The experimental spectrum to compare to
* @param {number|string|number[]} [masses] - List of experimental monoisotopic mass
* @param {object} [options={}]
* @param {string} [options.baseURL='https://octochemdb.cheminfo.org/'] - URL of the webservice
* @param {string} [options.mf] - Molecular formula of the non ionized molecule (not available for inSilicoFragments)
* @param {number} [options.precision=100] - Precision (accuracy) of the monoisotopic mass in ppm
* @param {string} [options.ionizations="H+"] - Comma separated list of allowed ionizations
* @param {number} [options.limit=1000] - Maximal number of entries to return
* @param {number} [options.massPower=1000] - Maximal number of entries to return
* @param {number} [options.massPower=3] - High power will give more weight to the mass. If you would prefer to observe fragments you should use a number less than 1
* @param {number} [options.intensityPower=0.6] - How important is the intensity. By default we don't give to much importance to it
* @param {string} [options.route='inSilicoFragments/v1/search'] - Route to use
*/

export async function searchInSilicoSpectraByMasses(
spectrum,
masses,
options = {},
) {
const {
route = 'inSilicoFragments/v1/search',
baseURL = 'https://octochemdb.cheminfo.org/',
precision = 100,
limit = 10000,
massPower = 3,
intensityPower = 0.6,
ionizations = 'H+',
} = options;

if (!route) {
throw new Error('route is mandatory');
}
if (!masses) {
throw new Error('masses is mandatory');
}

const realURL = new URL(route, baseURL).toString();

let results = await searchWithIonizations({
precision,
realURL,
masses,
limit,
ionizations,
});

const msComparator = new MSComparator({
delta: (mass) => mass * 1e-6 * precision,
massPower,
intensityPower,
});

const finals = [];

// filter MDMA
// results = results.filter(result => result.data.ocl.idCode === 'dg~D@MBdie]v\\kahHBjh@@')

for (const result of results) {
const similarity = msComparator.getSimilarityToMasses(
spectrum,
result.data.spectrum.data.x,
);
if (similarity >= 0) {
finals.push({
...result,
similarity,
});
}
}
finals.sort((a, b) => b.similarity - a.similarity);
return finals;
}
10 changes: 5 additions & 5 deletions packages/octochemdb/src/searchMasses.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,24 @@ import { parseMasses } from './utils/parseMasses.js';
* @param {number} [options.precision=100] - Precision (accuracy) of the monoisotopic mass in ppm
* @param {number} [options.limit=1000] - Maximal number of entries to return
* @param {string} [options.modifications=''] - Comma separated list of allowed modifications
* @param {string} [options.url='massBank/v1/search'] - Route to use
* @param {string} [options.route='massBank/v1/search'] - Route to use
* @param {string} [options.link='https://massbank.eu/MassBank/RecordDisplay?id='] - Link to the database source
*/

export async function searchMasses(options = {}) {
const {
url = '',
route = 'massBank/v1/search',
baseURL = 'https://octochemdb.cheminfo.org/',
precision = 100,
limit = 1000,
mf = '',
link = '',
} = options;

if (url === '') {
throw new Error('url is mandatory');
if (route === '') {
throw new Error('route is mandatory');
}
const realURL = new URL(url, baseURL).toString();
const realURL = new URL(route, baseURL).toString();
const masses = parseMasses(options.masses);

const modifications = preprocessIonizations(options.modifications);
Expand Down
3 changes: 1 addition & 2 deletions packages/octochemdb/src/utils/searchWithIonizations.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export async function searchWithIonizations(options) {
fields,
precision = 100,
limit = 1000,
searchParams,
searchParams = {},
ranges,
} = options;

Expand All @@ -30,7 +30,6 @@ export async function searchWithIonizations(options) {
precision,
ionizations,
});

const promises = [];
for (let ionization of ionizations) {
for (let mass of masses) {
Expand Down

0 comments on commit 9f5e637

Please sign in to comment.