Skip to content

Commit b33458f

Browse files
committed
feat(mf-parser): add info about number of isotopologues
1 parent 7dca6bb commit b33458f

File tree

5 files changed

+75
-9
lines changed

5 files changed

+75
-9
lines changed

packages/mf-parser/src/__tests__/MF.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ describe('MF', () => {
7070
},
7171
],
7272
monoisotopicMass: 24,
73+
nbIsotopologues: 3,
7374
mass: 24.021471793470496,
7475
charge: 0,
7576
unsaturation: 4,
@@ -205,6 +206,7 @@ describe('MF', () => {
205206
},
206207
],
207208
monoisotopicMass: 137.09712720211002,
209+
nbIsotopologues: 476,
208210
mass: 137.6511082393577,
209211
charge: 0,
210212
unsaturation: 0,
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { test, expect } from 'vitest';
2+
3+
import { MF } from '../../MF';
4+
import { getNumberOfIsotopologues } from '../getNumberOfIsotopologues';
5+
6+
const tests = [
7+
{ mf: 'C2', expected: 3 },
8+
{ mf: 'C1000', expected: 1001 },
9+
{ mf: 'CH', expected: 4 },
10+
{ mf: 'CH2', expected: 6 },
11+
{ mf: 'S', expected: 4 },
12+
{ mf: 'S2', expected: 10 },
13+
];
14+
15+
test.each(tests)(
16+
'getNumberOfIsotopologues $mf to be $expected',
17+
({ mf, expected }) => {
18+
const atoms = new MF(mf).getInfo().atoms;
19+
expect(getNumberOfIsotopologues(atoms)).toBe(expected);
20+
},
21+
);

packages/mf-parser/src/util/__tests__/toDisplay.test.js

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -110,9 +110,10 @@ let tests = [
110110
},
111111
];
112112

113-
test.each(tests)('toDisplay', (aTest) => {
114-
let display = toDisplay(aTest.parsed);
115-
expect(display).toMatchObject(aTest.result);
113+
// eslint-disable-next-line no-unused-vars
114+
test.each(tests)('toDisplay $mf', ({ mf, parsed, result }) => {
115+
let display = toDisplay(parsed);
116+
expect(display).toMatchObject(result);
116117
});
117118

118119
const testsCharges = [
@@ -174,10 +175,10 @@ const testsCharges = [
174175
},
175176
];
176177

177-
test.each(testsCharges)('toDisplay simple charges', (aTest) => {
178-
const parsed = new MFInternal(aTest.mf).parsed;
178+
test.each(testsCharges)('toDisplay simple charges $mf', ({ mf, result }) => {
179+
const parsed = new MFInternal(mf).parsed;
179180
let display = toDisplay(parsed);
180-
expect(display).toMatchObject(aTest.result);
181+
expect(display).toMatchObject(result);
181182
});
182183

183184
const testsParenthesis = [
@@ -243,8 +244,8 @@ const testsParenthesis = [
243244
},
244245
];
245246

246-
test.each(testsParenthesis)('toDisplay parenthesis', (aTest) => {
247-
const parsed = new MFInternal(aTest.mf).parsed;
247+
test.each(testsParenthesis)('toDisplay parenthesis $mf', ({ mf, result }) => {
248+
const parsed = new MFInternal(mf).parsed;
248249
let display = toDisplay(parsed);
249-
expect(display).toMatchObject(aTest.result);
250+
expect(display).toMatchObject(result);
250251
});

packages/mf-parser/src/util/getInfoInternal.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { groupsObject as groups } from 'chemical-groups';
99
import { Kind } from '../Kind';
1010

1111
import { getIsotopeRatioInfo } from './getIsotopeRatioInfo';
12+
import { getNumberOfIsotopologues } from './getNumberOfIsotopologues';
1213
import { partToAtoms } from './partToAtoms';
1314
import { partToMF } from './partToMF';
1415

@@ -65,6 +66,7 @@ export function getInfoInternal(parts, options = {}) {
6566
result.atoms[atom] += part.atoms[atom];
6667
}
6768
}
69+
result.nbIsotopologues = getNumberOfIsotopologues(result.atoms);
6870
return result;
6971
}
7072

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { elementsAndStableIsotopesObject } from 'chemical-elements';
2+
3+
import type { AtomsMap } from './partToAtoms';
4+
5+
/**
6+
* Return the theoretical number of isotopologues for a given MF.
7+
* This method will not take into account possible non natural isotopic distribution (e.g. 13C enrichment)
8+
* @param atoms
9+
* @returns
10+
*/
11+
export function getNumberOfIsotopologues(atoms: AtomsMap) {
12+
let result = 1;
13+
for (const atom in atoms) {
14+
const nbIsotopes = elementsAndStableIsotopesObject[atom]?.isotopes.length;
15+
if (!nbIsotopes) {
16+
throw new Error(`No stable isotopes found for ${atom}`);
17+
}
18+
const nbAtoms = atoms[atom];
19+
result *= getNbCombinationsPerAtom(nbAtoms, nbIsotopes);
20+
}
21+
return result;
22+
}
23+
24+
/**
25+
* Returns the number of isotopologues for one specific atom
26+
*
27+
* @param nbAtoms
28+
* @param nbIsotopes
29+
* @returns
30+
*/
31+
function getNbCombinationsPerAtom(nbAtoms: number, nbIsotopes: number) {
32+
let result = 1;
33+
for (let i = nbAtoms + 1; i < nbAtoms + nbIsotopes; i++) {
34+
result *= i;
35+
}
36+
for (let i = 2; i < nbIsotopes; i++) {
37+
result /= i;
38+
}
39+
return result;
40+
}

0 commit comments

Comments
 (0)