Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

nmr-processing

Package Overview
Dependencies
Maintainers
4
Versions
268
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

nmr-processing - npm Package Compare versions

Comparing version 1.5.2 to 2.0.0

src/prediction/predictAll.js

22

CHANGELOG.md
# Changelog
## [2.0.0](https://www.github.com/cheminfo/nmr-processing/compare/v1.5.2...v2.0.0) (2021-07-23)
### ⚠ BREAKING CHANGES
* use plural name diaIDs instead diaID
* use plural names signals and js instead of signal and j in ranges
* use integration instead of integral
### Features
* **prediction:** prediction 2D ([#68](https://www.github.com/cheminfo/nmr-processing/issues/68)) ([fed091b](https://www.github.com/cheminfo/nmr-processing/commit/fed091b48e21cf29624d7322ddc952d590f16495))
* predictor returns molecule ([9d7ba24](https://www.github.com/cheminfo/nmr-processing/commit/9d7ba24225aa0fb9a3c4d5fb25f55032c081bdb3))
* use integration instead of integral ([80ccc25](https://www.github.com/cheminfo/nmr-processing/commit/80ccc25ec21fcb6df5130af40aaf03ce3ea73f17))
* use plural name diaIDs instead diaID ([8cbcefc](https://www.github.com/cheminfo/nmr-processing/commit/8cbcefc3c3225039cf4f236e2ef908233ccc9ad6))
* use plural names signals and js instead of signal and j in ranges ([2328a13](https://www.github.com/cheminfo/nmr-processing/commit/2328a13f4084b00927c19ff3ec012c692a00d22a))
### Bug Fixes
* database in json format ([9adb6bf](https://www.github.com/cheminfo/nmr-processing/commit/9adb6bfec39eb22b4f238e538cb972462204e2e0))
### [1.5.2](https://www.github.com/cheminfo/nmr-processing/compare/v1.5.1...v1.5.2) (2021-07-22)

@@ -4,0 +26,0 @@

8

package.json
{
"name": "nmr-processing",
"version": "1.5.2",
"version": "2.0.0",
"description": "",

@@ -47,3 +47,3 @@ "main": "lib/index.js",

"cheminfo-build": "^1.1.11",
"eslint": "^7.30.0",
"eslint": "^7.31.0",
"eslint-config-cheminfo": "^5.2.4",

@@ -58,3 +58,3 @@ "esm": "^3.2.25",

"prettier": "^2.3.2",
"rollup": "^2.53.2"
"rollup": "^2.53.3"
},

@@ -79,3 +79,3 @@ "dependencies": {

"ml-sparse-matrix": "^2.1.0",
"ml-spectra-processing": "^6.7.1",
"ml-spectra-processing": "^6.8.0",
"openchemlib-utils": "^1.2.0",

@@ -82,0 +82,0 @@ "spectrum-generator": "^4.7.1"

@@ -15,2 +15,5 @@ /**

export * from './prediction/predictCarbon';
export * from './prediction/predictCOSY';
export * from './prediction/predictHSQC';
export * from './prediction/predictHMBC';
export * from './xyz/xyzAutoPeaksPicking';

@@ -17,0 +20,0 @@ export * from './constants/gyromagneticRatio';

@@ -8,7 +8,7 @@ // import { Ranges } from 'spectra-data-ranges';

/**
* This function clustering peaks and calculate the integral value for each range from the peak list returned from extractPeaks function.
* This function clustering peaks and calculate the integration value for each range from the peak list returned from extractPeaks function.
* @param {Object} data - spectra data
* @param {Array} peakList - nmr signals
* @param {Object} [options={}] - options object with some parameter for GSD, detectSignal functions.
* @param {Number} [options.integrationSum=100] - Number of hydrogens or some number to normalize the integral data. If it's zero return the absolute integral value
* @param {Number} [options.integrationSum=100] - Number of hydrogens or some number to normalize the integration data. If it's zero return the absolute integration value
* @param {String} [options.integralType='sum'] - option to chose between approx area with peaks or the sum of the points of given range ('sum', 'peaks')

@@ -133,4 +133,4 @@ * @param {Number} [options.frequencyCluster=16] - distance limit to clustering peaks.

to: signal.integralData.to,
integral: signal.integralData.value,
signal: [
integration: signal.integralData.value,
signals: [
{

@@ -143,9 +143,9 @@ kind: signal.kind || 'signal',

if (keepPeaks) {
ranges[i].signal[0].peak = signal.peaks;
ranges[i].signals[0].peak = signal.peaks;
}
if (signal.nmrJs) {
ranges[i].signal[0].j = signal.nmrJs;
ranges[i].signals[0].js = signal.nmrJs;
}
if (!signal.asymmetric || signal.multiplicity === 'm') {
ranges[i].signal[0].delta = signal.delta1;
ranges[i].signals[0].delta = signal.delta1;
}

@@ -164,3 +164,3 @@ }

* @param {object} [options = {}]
* @param {number} [options.integrationSum='100'] - Number of hydrogens or some number to normalize the integration data, If it's zero return the absolute integral value
* @param {number} [options.integrationSum='100'] - Number of hydrogens or some number to normalize the integration data, If it's zero return the absolute integration value
* @param {string} [options.integralType='sum'] - option to chose between approx area with peaks or the sum of the points of given range

@@ -238,3 +238,3 @@ * @param {number} [options.frequencyCluster=16] - distance limit to clustering the peaks.

peaks = signals[i].peaks;
let integral = signals[i].integralData;
let integration = signals[i].integralData;
let chemicalShift = 0;

@@ -251,10 +251,10 @@ let integralPeaks = 0;

if (integralType === 'sum') {
integral.value = xyIntegration(data, {
from: integral.from,
to: integral.to,
integration.value = xyIntegration(data, {
from: integration.from,
to: integration.to,
});
} else {
integral.value = integralPeaks;
integration.value = integralPeaks;
}
spectrumIntegral += integral.value;
spectrumIntegral += integration.value;
}

@@ -265,4 +265,4 @@

for (let i = 0; i < signals.length; i++) {
let integral = signals[i].integralData;
integral.value *= integralFactor;
let integration = signals[i].integralData;
integration.value *= integralFactor;
}

@@ -269,0 +269,0 @@ }

import fetch from 'cross-fetch';
import { addDiastereotopicMissingChirality } from 'openchemlib-utils';
import { signalsToRanges } from '../signals/signalsToRanges';
import { createInputJSON } from './utils/createInputJSON';
import { flatGroupedDiaIDs } from './utils/flatGroupedDiaIDs';
import { getFilteredIDiaIDs } from './utils/getFilteredIDiaIDs';
import { queryByHose } from './utils/queryByHOSE';

@@ -22,18 +22,34 @@

/**
* Make a query to a hose code based database to predict carbon chemical shift
* @param {Molecule} molecule - openchemlib molecule instance.
* @param {object} options
* @param {string} options.url - url of a custom database.
* @param {object} options.database - custom database, each entry in the levels should has
* an array as value [median] or [median, mean, sd, min, max, nb] for statistic purpose.
* @param {number} options.maxSphereSize - max level to take into account in the query. If is not specified
* the max level in the database will be used.
* @returns {Promise<object>} - object with molfile, diaIDs, signals, joined signals by diaIDs and ranges.
*/
export async function predictCarbon(molecule, options = {}) {
let { levels = [3, 2, 1, 0], url, database } = options;
let { url, database } = options;
database = database || (await loadDB(url));
molecule.addImplicitHydrogens();
molecule.addMissingChirality();
addDiastereotopicMissingChirality(molecule);
const maxLevel = database.length - 1;
const molfile = molecule.toMolfile();
let { maxSphereSize = maxLevel } = options;
const inputJSON = createInputJSON(molecule, {
levels,
});
if (maxSphereSize > maxLevel) maxSphereSize = maxLevel;
let predictions = queryByHose(inputJSON, database, {
levels,
const { groupedDiaIDs, carbonDiaIDs, molfile } = getFilteredIDiaIDs(
molecule,
{
maxSphereSize,
},
);
let predictions = queryByHose(carbonDiaIDs, database, {
maxSphereSize,
});

@@ -45,6 +61,7 @@

molfile,
diaIDs: inputJSON.diaIDs.map((e) => e.diaId),
diaIDs: flatGroupedDiaIDs(groupedDiaIDs),
joinedSignals,
signals,
ranges: signalsToRanges(joinedSignals),
molecule,
};

@@ -56,9 +73,10 @@ }

for (const prediction of predictions) {
const { atomIDs, nbAtoms, delta, diaIDs } = prediction;
const { atomIDs, nbAtoms, delta, diaIDs, statistic } = prediction;
signals.push({
delta,
assignment: atomIDs,
diaID: diaIDs,
diaIDs: diaIDs,
nbAtoms,
j: [],
statistic,
js: [],
});

@@ -72,3 +90,3 @@ }

for (let signal of signals) {
let diaID = signal.diaID[0];
let diaID = signal.diaIDs[0];
if (!joinedSignals[diaID]) {

@@ -75,0 +93,0 @@ joinedSignals[diaID] = JSON.parse(JSON.stringify(signal));

@@ -17,3 +17,3 @@ import fetch from 'cross-fetch';

* @param {function} [options.cache] A callback receiving a molfile and the result
* @return {Promise<Array>}
* @returns {Promise<object>} - object with molfile, diaIDs, signals, joined signals by diaIDs and ranges.
*/

@@ -53,2 +53,3 @@ export async function predictProton(molecule, options = {}) {

ranges: signalsToRanges(joinedSignals),
molecule,
};

@@ -67,17 +68,17 @@ }

assignment: [atom],
diaID: [diaIDs[atom]],
diaIDs: [diaIDs[atom]],
nbAtoms: 1,
delta: Number(fields[2]),
j: [],
js: [],
};
for (let i = 0; i < couplings.length; i += 3) {
let linked = Number(couplings[i] - 1);
signal.j.push({
signal.js.push({
coupling: Number(couplings[i + 2]),
assignment: [linked],
diaID: [diaIDs[linked]],
diaIDs: [diaIDs[linked]],
multiplicity: 'd',
distance: distanceMatrix[atom][linked],
});
signal.j.sort((a, b) => b.coupling - a.coupling);
signal.js.sort((a, b) => b.coupling - a.coupling);
}

@@ -84,0 +85,0 @@ signals.push(signal);

@@ -1,18 +0,18 @@

export function queryByHose(input, db, options) {
const { levels } = options;
export function queryByHose(diaIDs, db, options) {
const { maxSphereSize } = options;
levels.sort((a, b) => b - a);
const toReturn = [];
for (const element of input.diaIDs) {
for (const element of diaIDs) {
let res;
let k = 0;
while (!res && k < levels.length) {
if (db[levels[k]]) {
res = db[levels[k]][element.hose[levels[k]]];
let level;
for (let k = maxSphereSize; !res && k >= 0; k--) {
if (db[k]) {
res = db[k][element.hose[k]];
level = k;
}
k++;
}
if (!res) {
res = [null];
k = 0;
level = null;
}

@@ -25,3 +25,12 @@

atom.nbAtoms = 1;
atom.level = level;
if (res.length > 1) {
atom.statistic = {
mean: res[1],
sd: res[2],
min: res[3],
max: res[4],
nb: res[5],
};
}
toReturn.push(atom);

@@ -28,0 +37,0 @@ }

@@ -98,4 +98,4 @@ import { signalJoinCouplings } from '../signal/signalJoinCouplings';

if (Array.isArray(range.signal)) {
range.signal = range.signal.filter(
if (Array.isArray(range.signals)) {
range.signals = range.signals.filter(
(signal) => !uselessKind(signal.kind, options.filter),

@@ -105,4 +105,4 @@ );

if (Array.isArray(range.signal) && range.signal.length > 0) {
let signals = range.signal;
if (Array.isArray(range.signals) && range.signals.length > 0) {
let signals = range.signals;
if (signals.length > 1) {

@@ -153,15 +153,15 @@ if (options.ascending === true) {

function getIntegral(range, options) {
let integral = '';
let integration = '';
if (range.pubIntegral) {
integral = range.pubIntegral;
} else if (range.integral) {
integral =
range.integral.toFixed(0) + options.nucleus[options.nucleus.length - 1];
integration = range.pubIntegral;
} else if (range.integration) {
integration =
range.integration.toFixed(0) + options.nucleus[options.nucleus.length - 1];
}
return integral;
return integration;
}
function pushIntegral(range, parenthesis, options) {
let integral = getIntegral(range, options);
if (integral.length > 0) parenthesis.push(integral);
let integration = getIntegral(range, options);
if (integration.length > 0) parenthesis.push(integration);
}

@@ -221,4 +221,4 @@

function pushCoupling(signal, parenthesis, options) {
if (Array.isArray(signal.j) && signal.j.length > 0) {
signal.j.sort(function (a, b) {
if (Array.isArray(signal.js) && signal.js.length > 0) {
signal.js.sort(function (a, b) {
return b.coupling - a.coupling;

@@ -228,3 +228,3 @@ });

let values = [];
for (let j of signal.j) {
for (let j of signal.js) {
if (j.coupling !== undefined) {

@@ -231,0 +231,0 @@ values.push(j.coupling.toFixed(options.nbDecimalJ));

@@ -21,9 +21,9 @@ import sum from 'ml-array-sum';

if (!signal.j || signal.j.length < 2) return signal;
if (!signal.js || signal.js.length < 2) return signal;
// we group the couplings that are less than the expected tolerance
let currentGroup = [signal.j[0]];
let currentGroup = [signal.js[0]];
let groups = [currentGroup];
for (let i = 1; i < signal.j.length; i++) {
let currentJ = signal.j[i];
for (let i = 1; i < signal.js.length; i++) {
let currentJ = signal.js[i];
if (

@@ -40,3 +40,3 @@ currentGroup[currentGroup.length - 1].coupling - currentJ.coupling <

signal.j = [];
signal.js = [];
for (let group of groups) {

@@ -50,6 +50,6 @@ let coupling = sum(group.map((group) => group.coupling)) / group.length;

);
let diaID = distinctValues(
let diaIDs = distinctValues(
group
.filter((group) => group.diaID && group.diaID.length > 0)
.map((group) => group.diaID)
.filter((group) => group.diaIDs && group.diaIDs.length > 0)
.map((group) => group.diaIDs)
.flat(),

@@ -64,6 +64,6 @@ );

};
if (diaID.length > 0) newJ.diaID = diaID;
if (diaIDs.length > 0) newJ.diaIDs = diaIDs;
if (distances.length === 1 && distances[0]) newJ.distance = distances[0];
if (assignment.length > 0) newJ.assignment = assignment;
signal.j.push(newJ);
signal.js.push(newJ);
}

@@ -70,0 +70,0 @@

@@ -7,3 +7,3 @@ /**

export function signalMultiplicityPattern(signal) {
let js = signal.j;
let js = signal.js;
let pattern = '';

@@ -10,0 +10,0 @@ if (js && js.length > 0) {

/**
* Ensure that assignment and diaID are arrays and coupling are sorted
* Ensure that assignment and diaIDs are arrays and coupling are sorted
* @param {object} signal

@@ -12,7 +12,7 @@ * @returns signal

}
if (signal.diaID && !Array.isArray(signal.diaID)) {
signal.diaID = [signal.diaID];
if (signal.diaIDs && !Array.isArray(signal.diaIDs)) {
signal.diaIDs = [signal.diaIDs];
}
if (signal.j) {
let couplings = signal.j;
if (signal.js) {
let couplings = signal.js;
for (let coupling of couplings) {

@@ -22,9 +22,9 @@ if (coupling.assignment && !Array.isArray(coupling.assignment)) {

}
if (coupling.diaID && !Array.isArray(coupling.diaID)) {
coupling.diaID = [coupling.diaID];
if (coupling.diaIDs && !Array.isArray(coupling.diaIDs)) {
coupling.diaIDs = [coupling.diaIDs];
}
}
signal.j = signal.j.sort((a, b) => b.coupling - a.coupling);
signal.js = signal.js.sort((a, b) => b.coupling - a.coupling);
}
return signal;
}

@@ -14,7 +14,7 @@ import mean from 'ml-array-mean';

for (let signal of signals) {
if (!signal.diaID || !signal.diaID.length === 1) return signals;
for (let coupling of signal.j) {
if (!signal.diaIDs || !signal.diaIDs.length === 1) return signals;
for (let coupling of signal.js) {
if (
!coupling.diaID ||
!coupling.diaID.length === 1 ||
!coupling.diaIDs ||
!coupling.diaIDs.length === 1 ||
coupling.multiplicity !== 'd'

@@ -31,7 +31,7 @@ ) {

signal = signalNormalize(signal); // we have a copy
signal.j = signal.j.sort((a, b) =>
a.diaID + a.distance < b.diaID + b.distance ? 1 : -1,
signal.js = signal.js.sort((a, b) =>
a.diaIDs + a.distance < b.diaIDs + b.distance ? 1 : -1,
);
let id = `${signal.diaID[0]} ${signal.j
.map((j) => `${j.diaID[0]} ${j.distance}`)
let id = `${signal.diaIDs[0]} ${signal.js
.map((j) => `${j.diaIDs[0]} ${j.distance}`)
.sort()

@@ -51,9 +51,9 @@ .join(' ')}`;

// joining couplings only if diaID and distance are equal
const j = [];
for (let i = 0; i < group[0].j.length; i++) {
j.push({
diaID: group[0].j[i].diaID,
distance: group[0].j[i].distance,
multiplicity: group[0].j[i].multiplicity,
coupling: mean(group.map((item) => item.j[i].coupling)),
const js = [];
for (let i = 0; i < group[0].js.length; i++) {
js.push({
diaIDs: group[0].js[i].diaIDs,
distance: group[0].js[i].distance,
multiplicity: group[0].js[i].multiplicity,
coupling: mean(group.map((item) => item.js[i].coupling)),
});

@@ -65,3 +65,3 @@ }

delta: mean(group.map((item) => item.delta)),
diaID: group[0].diaID,
diaIDs: group[0].diaIDs,
assignment: group

@@ -71,3 +71,3 @@ .map((item) => item.assignment)

.filter((item) => item),
j,
js,
});

@@ -78,4 +78,4 @@ }

signal = signalNormalize(signalJoinCouplings(signal, { tolerance }));
if (signal.j) {
signal.multiplicity = signal.j.reduce((multiplicity, jCoupling) => {
if (signal.js) {
signal.multiplicity = signal.js.reduce((multiplicity, jCoupling) => {
return `${multiplicity}${jCoupling.multiplicity}`;

@@ -82,0 +82,0 @@ }, '');

@@ -8,3 +8,3 @@ export function signalsToRanges(signals, options = {}) {

let halfWidth =
(signal.original.j || []).reduce(
(signal.original.js || []).reduce(
(total, j) => (total += j.coupling / frequency),

@@ -26,10 +26,10 @@ 0,

to: signal.to,
integral: signal.original.nbAtoms,
signal: [signal.original],
integration: signal.original.nbAtoms,
signals: [signal.original],
};
ranges.push(range);
} else {
range.integral += signal.original.nbAtoms;
range.integration += signal.original.nbAtoms;
if (signal.to > range.to) range.to = signal.to;
range.signal.push(signal.original);
range.signals.push(signal.original);
}

@@ -36,0 +36,0 @@ }

@@ -18,3 +18,3 @@ import Matrix from 'ml-matrix';

for (let i = 0; i < nSpins; i++) {
let { assignment: signalAssignment, j: jCoupling } = signals[i];
let { assignment: signalAssignment, js: jCoupling } = signals[i];
for (let k = 0; k < jCoupling.length; k++) {

@@ -21,0 +21,0 @@ let { coupling, assignment } = jCoupling[k];

@@ -25,3 +25,3 @@ import { peaksFilterImpurities } from '../peaks/peaksFilterImpurities';

* @param {Boolean} [options.peakPicking.optimize=true] - if it's true adjust an train of gaussian or lorentzian shapes to spectrum.
* @param {Number} [options.ranges.integrationSum=100] - Number of hydrogens or some number to normalize the integral data. If it's zero return the absolute integral value
* @param {Number} [options.ranges.integrationSum=100] - Number of hydrogens or some number to normalize the integration data. If it's zero return the absolute integration value
* @param {String} [options.ranges.integralType='sum'] - option to chose between approx area with peaks or the sum of the points of given range ('sum', 'peaks')

@@ -37,3 +37,3 @@ * @param {Number} [options.ranges.frequencyCluster=16] - distance limit to clustering peaks.

* @param {string} [options.impurities.error=0.025] - tolerance in ppm to assign a impurity.
* @returns {array} - Array of ranges with {from, to, integral, signals: [{delta, j, multiplicity, peaks}]}
* @returns {array} - Array of ranges with {from, to, integration, signals: [{delta, j, multiplicity, peaks}]}
*/

@@ -40,0 +40,0 @@

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc