nmr-processing 8.1.0 → 8.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -3
- package/lib/apodization/apodization.d.ts +22 -0
- package/lib/apodization/apodization.js +18 -0
- package/lib/apodization/apodization.js.map +1 -0
- package/lib/apodization/applyWindow.d.ts +28 -0
- package/lib/apodization/applyWindow.js +20 -0
- package/lib/apodization/applyWindow.js.map +1 -0
- package/lib/apodization/compose.d.ts +23 -0
- package/lib/apodization/compose.js +25 -0
- package/lib/apodization/compose.js.map +1 -0
- package/lib/apodization/getFunction.d.ts +2 -0
- package/lib/apodization/getFunction.js +18 -0
- package/lib/apodization/getFunction.js.map +1 -0
- package/lib/apodization/shapes/WindowFunctions.d.ts +12 -0
- package/lib/apodization/shapes/WindowFunctions.js +3 -0
- package/lib/apodization/shapes/WindowFunctions.js.map +1 -0
- package/lib/apodization/shapes/exponential.d.ts +11 -0
- package/lib/apodization/shapes/exponential.js +10 -0
- package/lib/apodization/shapes/exponential.js.map +1 -0
- package/lib/apodization/shapes/lorentzToGauss.d.ts +26 -0
- package/lib/apodization/shapes/lorentzToGauss.js +15 -0
- package/lib/apodization/shapes/lorentzToGauss.js.map +1 -0
- package/lib/apodization/utils/getData.d.ts +4 -0
- package/lib/apodization/utils/getData.js +21 -0
- package/lib/apodization/utils/getData.js.map +1 -0
- package/lib/assignment/utils/buildAssignments.d.ts +2 -2
- package/lib/assignment/utils/exploreTreeRec.js +1 -1
- package/lib/assignment/utils/exploreTreeRec.js.map +1 -1
- package/lib/assignment/utils/getAssignment/checkIDs.d.ts +1 -1
- package/lib/assignment/utils/getAssignment/checkIDs.js.map +1 -1
- package/lib/databases/DatabaseNMREntry.d.ts +2 -0
- package/lib/index.d.ts +3 -0
- package/lib/index.js +3 -0
- package/lib/index.js.map +1 -1
- package/lib/peaks/peaksToRanges.d.ts +16 -0
- package/lib/peaks/peaksToRanges.js +3 -2
- package/lib/peaks/peaksToRanges.js.map +1 -1
- package/lib/peaks/solventSuppression.d.ts +4 -1
- package/lib/peaks/solventSuppression.js +43 -32
- package/lib/peaks/solventSuppression.js.map +1 -1
- package/lib/peaks/util/jAnalyzer.js +26 -31
- package/lib/peaks/util/jAnalyzer.js.map +1 -1
- package/lib/peaks/util/peakOptimizer.js +12 -16
- package/lib/peaks/util/peakOptimizer.js.map +1 -1
- package/lib/prediction/predictAllSpectra.js +7 -9
- package/lib/prediction/predictAllSpectra.js.map +1 -1
- package/lib/prediction/predictCarbon.js +1 -1
- package/lib/prediction/predictCarbon.js.map +1 -1
- package/lib/prediction/utils/queryByHOSE.js +1 -1
- package/lib/prediction/utils/queryByHOSE.js.map +1 -1
- package/lib/ranges/markSolventSignal.d.ts +3 -0
- package/lib/ranges/markSolventSignal.js +107 -0
- package/lib/ranges/markSolventSignal.js.map +1 -0
- package/lib/ranges/rangesToACS.js +8 -4
- package/lib/ranges/rangesToACS.js.map +1 -1
- package/lib/signals/signalsJoin.js +4 -3
- package/lib/signals/signalsJoin.js.map +1 -1
- package/lib/signals/simulation/getPauliMatrix.js.map +1 -1
- package/lib/signals/simulation/splitSpinSystem.js +11 -13
- package/lib/signals/simulation/splitSpinSystem.js.map +1 -1
- package/lib/utilities/rangeFromSignal.d.ts +9 -5
- package/lib/utilities/rangeFromSignal.js +7 -7
- package/lib/utilities/rangeFromSignal.js.map +1 -1
- package/lib/utilities/resurrectRange.js +4 -7
- package/lib/utilities/resurrectRange.js.map +1 -1
- package/lib/xyz/util/formatZone.d.ts +3 -0
- package/lib/xyz/util/formatZone.js +38 -0
- package/lib/xyz/util/formatZone.js.map +1 -0
- package/lib/xyz/xyzAutoZonesPicking.d.ts +1 -2
- package/lib/xyz/xyzAutoZonesPicking.js +2 -34
- package/lib/xyz/xyzAutoZonesPicking.js.map +1 -1
- package/lib/xyz/xyzJResAnalyzer.d.ts +6 -1
- package/lib/xyz/xyzJResAnalyzer.js +9 -8
- package/lib/xyz/xyzJResAnalyzer.js.map +1 -1
- package/lib-esm/apodization/apodization.js +14 -0
- package/lib-esm/apodization/apodization.js.map +1 -0
- package/lib-esm/apodization/applyWindow.js +16 -0
- package/lib-esm/apodization/applyWindow.js.map +1 -0
- package/lib-esm/apodization/compose.js +21 -0
- package/lib-esm/apodization/compose.js.map +1 -0
- package/lib-esm/apodization/getFunction.js +14 -0
- package/lib-esm/apodization/getFunction.js.map +1 -0
- package/lib-esm/apodization/shapes/WindowFunctions.js +2 -0
- package/lib-esm/apodization/shapes/WindowFunctions.js.map +1 -0
- package/lib-esm/apodization/shapes/exponential.js +6 -0
- package/lib-esm/apodization/shapes/exponential.js.map +1 -0
- package/lib-esm/apodization/shapes/lorentzToGauss.js +11 -0
- package/lib-esm/apodization/shapes/lorentzToGauss.js.map +1 -0
- package/lib-esm/apodization/utils/getData.js +17 -0
- package/lib-esm/apodization/utils/getData.js.map +1 -0
- package/lib-esm/assignment/utils/buildAssignments.js +3 -3
- package/lib-esm/assignment/utils/exploreTreeRec.js +1 -1
- package/lib-esm/assignment/utils/exploreTreeRec.js.map +1 -1
- package/lib-esm/assignment/utils/getAssignment/buildAssignments.js +3 -3
- package/lib-esm/assignment/utils/getAssignment/checkIDs.js.map +1 -1
- package/lib-esm/index.js +3 -0
- package/lib-esm/index.js.map +1 -1
- package/lib-esm/peaks/peaksToRanges.js +2 -2
- package/lib-esm/peaks/peaksToRanges.js.map +1 -1
- package/lib-esm/peaks/solventSuppression.js +41 -27
- package/lib-esm/peaks/solventSuppression.js.map +1 -1
- package/lib-esm/peaks/util/jAnalyzer.js +26 -31
- package/lib-esm/peaks/util/jAnalyzer.js.map +1 -1
- package/lib-esm/peaks/util/peakOptimizer.js +12 -16
- package/lib-esm/peaks/util/peakOptimizer.js.map +1 -1
- package/lib-esm/prediction/predictAllSpectra.js +7 -9
- package/lib-esm/prediction/predictAllSpectra.js.map +1 -1
- package/lib-esm/prediction/predictCarbon.js +1 -1
- package/lib-esm/prediction/predictCarbon.js.map +1 -1
- package/lib-esm/prediction/utils/queryByHOSE.js +1 -1
- package/lib-esm/prediction/utils/queryByHOSE.js.map +1 -1
- package/lib-esm/ranges/markSolventSignal.js +100 -0
- package/lib-esm/ranges/markSolventSignal.js.map +1 -0
- package/lib-esm/ranges/rangesToACS.js +8 -4
- package/lib-esm/ranges/rangesToACS.js.map +1 -1
- package/lib-esm/signals/signalsJoin.js +4 -3
- package/lib-esm/signals/signalsJoin.js.map +1 -1
- package/lib-esm/signals/simulation/getPauliMatrix.js.map +1 -1
- package/lib-esm/signals/simulation/splitSpinSystem.js +11 -13
- package/lib-esm/signals/simulation/splitSpinSystem.js.map +1 -1
- package/lib-esm/utilities/rangeFromSignal.js +7 -7
- package/lib-esm/utilities/rangeFromSignal.js.map +1 -1
- package/lib-esm/utilities/resurrectRange.js +4 -7
- package/lib-esm/utilities/resurrectRange.js.map +1 -1
- package/lib-esm/xyz/util/formatZone.js +34 -0
- package/lib-esm/xyz/util/formatZone.js.map +1 -0
- package/lib-esm/xyz/xyzAutoZonesPicking.js +1 -33
- package/lib-esm/xyz/xyzAutoZonesPicking.js.map +1 -1
- package/lib-esm/xyz/xyzJResAnalyzer.js +9 -8
- package/lib-esm/xyz/xyzJResAnalyzer.js.map +1 -1
- package/package.json +14 -14
- package/src/apodization/apodization.ts +34 -0
- package/src/apodization/applyWindow.ts +51 -0
- package/src/apodization/compose.ts +47 -0
- package/src/apodization/getFunction.ts +15 -0
- package/src/apodization/shapes/WindowFunctions.ts +14 -0
- package/src/apodization/shapes/exponential.ts +16 -0
- package/src/apodization/shapes/lorentzToGauss.ts +41 -0
- package/src/apodization/utils/getData.ts +15 -0
- package/src/assignment/utils/buildAssignments.ts +4 -4
- package/src/assignment/utils/exploreTreeRec.ts +1 -1
- package/src/assignment/utils/getAssignment/buildAssignments.ts +3 -3
- package/src/assignment/utils/getAssignment/checkIDs.ts +1 -1
- package/src/databases/DatabaseNMREntry.ts +3 -0
- package/src/index.ts +5 -0
- package/src/peaks/peaksToRanges.ts +2 -2
- package/src/peaks/solventSuppression.ts +68 -40
- package/src/peaks/util/jAnalyzer.ts +26 -30
- package/src/peaks/util/peakOptimizer.ts +11 -15
- package/src/prediction/predictAllSpectra.ts +6 -8
- package/src/prediction/predictCarbon.ts +1 -1
- package/src/prediction/utils/queryByHOSE.ts +1 -1
- package/src/ranges/markSolventSignal.ts +121 -0
- package/src/ranges/rangesToACS.ts +9 -10
- package/src/signals/signalsJoin.ts +5 -7
- package/src/signals/simulation/getPauliMatrix.ts +1 -1
- package/src/signals/simulation/splitSpinSystem.ts +10 -12
- package/src/utilities/rangeFromSignal.ts +19 -11
- package/src/utilities/resurrectRange.ts +4 -7
- package/src/xyz/util/formatZone.ts +36 -0
- package/src/xyz/xyzAutoZonesPicking.ts +1 -35
- package/src/xyz/xyzJResAnalyzer.ts +14 -7
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export interface LorentzToGaussOptions {
|
|
2
|
+
/**
|
|
3
|
+
* size of the shape function
|
|
4
|
+
*/
|
|
5
|
+
length: number;
|
|
6
|
+
/**
|
|
7
|
+
* increment value in time or the independent value
|
|
8
|
+
*/
|
|
9
|
+
dw: number;
|
|
10
|
+
/**
|
|
11
|
+
* Gaussian Broaden Width, Hz
|
|
12
|
+
* @default 0
|
|
13
|
+
*/
|
|
14
|
+
gaussianHz?: number;
|
|
15
|
+
/**
|
|
16
|
+
* Inverse Exponential Width, Hz
|
|
17
|
+
* @default 0
|
|
18
|
+
*/
|
|
19
|
+
exponentialHz?: number;
|
|
20
|
+
/**
|
|
21
|
+
* Location of Gauss Maximum, this value should be between 0 to 1
|
|
22
|
+
* @default 0
|
|
23
|
+
*/
|
|
24
|
+
center?: number;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function lorentzToGauss(options: LorentzToGaussOptions) {
|
|
28
|
+
const { dw, length, gaussianHz = 0, exponentialHz = 0, center = 0 } = options;
|
|
29
|
+
|
|
30
|
+
if (center > 1 || center < 0) {
|
|
31
|
+
throw new Error(
|
|
32
|
+
'The center of gaussian shape should be inside of the window function: 0 - 1',
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const C5 = Math.pow(0.6 * Math.PI * gaussianHz * dw, 2);
|
|
37
|
+
const C2 = center * (length - 1);
|
|
38
|
+
const C6 = Math.PI * dw * exponentialHz;
|
|
39
|
+
|
|
40
|
+
return (i: number) => Math.exp(i * C6 - Math.pow(C2 - i, 2) * C5);
|
|
41
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* generate and scale the data of a window function
|
|
3
|
+
*/
|
|
4
|
+
export function getData(func: (i: number) => number, length: number) {
|
|
5
|
+
const data = new Float64Array(length);
|
|
6
|
+
let max = Number.MIN_SAFE_INTEGER;
|
|
7
|
+
for (let i = 0; i < length; i++) {
|
|
8
|
+
const value = func(i);
|
|
9
|
+
data[i] = value;
|
|
10
|
+
if (value > max) max = value;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
for (let i = 0; i < length; i++) data[i] /= max;
|
|
14
|
+
return data;
|
|
15
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import TreeSet from 'ml-tree-set';
|
|
2
2
|
|
|
3
3
|
import { Targets, NMRSignal1DWithAtomsAndDiaIDs } from '../get1HAssignments';
|
|
4
4
|
|
|
@@ -38,7 +38,7 @@ export interface Predictions1Dassignments {
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
export interface StoreAssignments {
|
|
41
|
-
solutions:
|
|
41
|
+
solutions: TreeSet;
|
|
42
42
|
nSolutions: number;
|
|
43
43
|
}
|
|
44
44
|
|
|
@@ -64,7 +64,7 @@ export async function buildAssignments(props: BuildAssignmentsProps) {
|
|
|
64
64
|
let timeStart = date.getTime();
|
|
65
65
|
|
|
66
66
|
let store: StoreAssignments = {
|
|
67
|
-
solutions: new
|
|
67
|
+
solutions: new TreeSet(comparator),
|
|
68
68
|
nSolutions: 0,
|
|
69
69
|
};
|
|
70
70
|
|
|
@@ -97,7 +97,7 @@ export async function buildAssignments(props: BuildAssignmentsProps) {
|
|
|
97
97
|
let partial = fillPartial(nSources);
|
|
98
98
|
|
|
99
99
|
store = {
|
|
100
|
-
solutions: new
|
|
100
|
+
solutions: new TreeSet(comparator),
|
|
101
101
|
nSolutions: 0,
|
|
102
102
|
};
|
|
103
103
|
|
|
@@ -113,7 +113,7 @@ function addSolution(store: StoreAssignments, props: AddSolutionProps) {
|
|
|
113
113
|
store.nSolutions++;
|
|
114
114
|
let solution: SolutionAssignment = {
|
|
115
115
|
assignment: JSON.parse(JSON.stringify(partial)),
|
|
116
|
-
score
|
|
116
|
+
score,
|
|
117
117
|
};
|
|
118
118
|
|
|
119
119
|
if (store.nSolutions >= maxSolutions) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import TreeSet from 'ml-tree-set';
|
|
2
2
|
import { Values } from 'nmr-correlation';
|
|
3
3
|
import { Molecule } from 'openchemlib';
|
|
4
4
|
import { getConnectivityMatrix } from 'openchemlib-utils';
|
|
@@ -135,7 +135,7 @@ export async function buildAssignments(props: BuildAssignmentInput) {
|
|
|
135
135
|
let lowerBoundScore = minScore;
|
|
136
136
|
|
|
137
137
|
let store: StoreAssignments = {
|
|
138
|
-
solutions: new
|
|
138
|
+
solutions: new TreeSet(comparator),
|
|
139
139
|
nSolutions: 0,
|
|
140
140
|
};
|
|
141
141
|
|
|
@@ -204,7 +204,7 @@ export async function buildAssignments(props: BuildAssignmentInput) {
|
|
|
204
204
|
);
|
|
205
205
|
|
|
206
206
|
store = {
|
|
207
|
-
solutions: new
|
|
207
|
+
solutions: new TreeSet(comparator),
|
|
208
208
|
nSolutions: 0,
|
|
209
209
|
};
|
|
210
210
|
|
|
@@ -42,7 +42,7 @@ export function hasIDs(
|
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
export function addIDs
|
|
45
|
+
export function addIDs<T extends NMRRange[] | NMRZone[]>(data: T) {
|
|
46
46
|
for (const element of data) {
|
|
47
47
|
if (!element.id) element.id = generateID();
|
|
48
48
|
for (let signal of element.signals || []) {
|
package/src/index.ts
CHANGED
|
@@ -37,6 +37,11 @@ export * from './databases/getDatabase';
|
|
|
37
37
|
export * from './databases/carbonImpurities';
|
|
38
38
|
export * from './databases/protonImpurities';
|
|
39
39
|
|
|
40
|
+
export * from './peaks/solventSuppression';
|
|
41
|
+
export * from './ranges/markSolventSignal';
|
|
42
|
+
|
|
43
|
+
export * from './apodization/apodization';
|
|
44
|
+
|
|
40
45
|
export type { NMRSignal1D } from './signals/NMRSignal1D';
|
|
41
46
|
export type { NMRSignal2D, Signal2DProjection } from './xyz/NMRSignal2D';
|
|
42
47
|
export type { NMRRange } from './xy/NMRRange';
|
|
@@ -174,7 +174,7 @@ export function peaksToRanges(
|
|
|
174
174
|
let peaksO = [];
|
|
175
175
|
for (let j = signal.maskPattern.length - 1; j >= 0; j--) {
|
|
176
176
|
sum += computeArea(signal.peaks[j]);
|
|
177
|
-
if (signal.maskPattern[j]
|
|
177
|
+
if (!signal.maskPattern[j]) {
|
|
178
178
|
let peakR = signal.peaks.splice(j, 1)[0];
|
|
179
179
|
peaksO.push({
|
|
180
180
|
x: peakR.x,
|
|
@@ -281,7 +281,7 @@ export function peaksToRanges(
|
|
|
281
281
|
* @private
|
|
282
282
|
*/
|
|
283
283
|
|
|
284
|
-
function detectSignals(
|
|
284
|
+
export function detectSignals(
|
|
285
285
|
data: DataXY,
|
|
286
286
|
peakList: NMRPeak1DIntern[],
|
|
287
287
|
options: OptionsDetectSignals = {},
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { PointXY } from 'cheminfo-types';
|
|
2
|
-
import linearSumAssignment from 'linear-sum-assignment';
|
|
2
|
+
import { linearSumAssignment } from 'linear-sum-assignment';
|
|
3
3
|
import { Matrix } from 'ml-matrix';
|
|
4
4
|
import { gaussianFct } from 'ml-peak-shape-generator';
|
|
5
5
|
import { xFindClosestIndex, xMaxValue } from 'ml-spectra-processing';
|
|
@@ -12,45 +12,47 @@ import { splitSpinSystem } from '../signals/simulation/splitSpinSystem';
|
|
|
12
12
|
|
|
13
13
|
import { NMRPeak1D } from './NMRPeak1D';
|
|
14
14
|
|
|
15
|
-
export function solventSuppression(
|
|
16
|
-
peakList:
|
|
15
|
+
export function solventSuppression<T extends NMRPeak1D>(
|
|
16
|
+
peakList: T[],
|
|
17
17
|
solvent: NMRSignal1D[],
|
|
18
|
-
options:
|
|
18
|
+
options: { markSolventPeaks?: boolean; solventZoneExtension?: number } = {},
|
|
19
19
|
) {
|
|
20
|
-
const peaks = [...peakList];
|
|
21
|
-
sortAscending(peaks);
|
|
22
|
-
const xValues = peaks.map((peak) => peak.x);
|
|
20
|
+
const peaks = [...peakList].sort((a, b) => a.x - b.x);
|
|
23
21
|
|
|
24
|
-
const
|
|
22
|
+
const xValues = peaks.map((peak) => peak.x);
|
|
25
23
|
|
|
26
|
-
|
|
27
|
-
// solventSignals = solventSignals.slice(0, solventSignals.findIndex((signal) => signal.delta > 400));
|
|
24
|
+
const { markSolventPeaks = false, solventZoneExtension = 1.2 } = options;
|
|
28
25
|
|
|
29
|
-
for (const solventSignal of
|
|
30
|
-
|
|
26
|
+
for (const solventSignal of solvent) {
|
|
27
|
+
let solventXYPeaks = solventSignal.peaks
|
|
31
28
|
? solventSignal.peaks
|
|
32
29
|
: getSolventPeaks(solventSignal);
|
|
33
|
-
|
|
30
|
+
solventXYPeaks.sort((a, b) => a.x - b.x);
|
|
31
|
+
|
|
34
32
|
let upIndex = xFindClosestIndex(
|
|
35
33
|
xValues,
|
|
36
|
-
solventXYPeaks[solventXYPeaks.length - 1].x +
|
|
34
|
+
solventXYPeaks[solventXYPeaks.length - 1].x + solventZoneExtension,
|
|
35
|
+
);
|
|
36
|
+
let lowIndex = xFindClosestIndex(
|
|
37
|
+
xValues,
|
|
38
|
+
solventXYPeaks[0].x - solventZoneExtension,
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
const nearPeaks = peaks.filter(
|
|
42
|
+
(peak, index) => index >= lowIndex && index <= upIndex,
|
|
37
43
|
);
|
|
38
|
-
let lowIndex = xFindClosestIndex(xValues, solventXYPeaks[0].x - 1);
|
|
39
|
-
if (upIndex === lowIndex) continue;
|
|
40
|
-
const nearPeaks = peaks.slice(lowIndex, upIndex + 1);
|
|
41
44
|
const amplitudeResiduals = [];
|
|
42
45
|
const deltaResiduals = [];
|
|
43
46
|
const positionResiduals = [];
|
|
44
47
|
for (let peak of nearPeaks) {
|
|
45
|
-
const shiftedSolventPeaks =
|
|
46
|
-
peak,
|
|
47
|
-
|
|
48
|
-
solventXYPeaks,
|
|
49
|
-
);
|
|
48
|
+
const { peaks: shiftedSolventPeaks, delta: currentDelta } =
|
|
49
|
+
getShiftedSolventPeaks(peak, solventSignal, solventXYPeaks);
|
|
50
|
+
|
|
50
51
|
const closestPeaks = getClosestPeaks(shiftedSolventPeaks, nearPeaks);
|
|
51
52
|
let deltaResidual = 0;
|
|
52
53
|
let amplitudeResidual = 0;
|
|
53
54
|
let positionResidual = 0;
|
|
55
|
+
|
|
54
56
|
for (let i = 0; i < closestPeaks.length; i++) {
|
|
55
57
|
amplitudeResidual += Math.abs(
|
|
56
58
|
shiftedSolventPeaks[i].y - closestPeaks[i].y,
|
|
@@ -63,31 +65,50 @@ export function solventSuppression(
|
|
|
63
65
|
amplitudeResidual = Number.MAX_SAFE_INTEGER;
|
|
64
66
|
positionResidual = Number.MAX_SAFE_INTEGER;
|
|
65
67
|
} else {
|
|
66
|
-
positionResidual = gaussianFct(
|
|
68
|
+
positionResidual = gaussianFct(
|
|
69
|
+
Math.abs(solventSignal.delta - currentDelta),
|
|
70
|
+
0.5,
|
|
71
|
+
);
|
|
67
72
|
}
|
|
73
|
+
|
|
68
74
|
amplitudeResiduals.push(amplitudeResidual);
|
|
69
75
|
deltaResiduals.push(deltaResidual);
|
|
70
76
|
positionResiduals.push(positionResidual);
|
|
71
77
|
}
|
|
72
78
|
|
|
73
|
-
const maxAmplitude =
|
|
74
|
-
|
|
75
|
-
|
|
79
|
+
const [maxAmplitude, maxDelta, maxPosition] = [
|
|
80
|
+
amplitudeResiduals,
|
|
81
|
+
deltaResiduals,
|
|
82
|
+
positionResiduals,
|
|
83
|
+
].map((data) => {
|
|
84
|
+
const max = xMaxValue(data);
|
|
85
|
+
return max === 0 ? 1 : max;
|
|
86
|
+
});
|
|
76
87
|
|
|
77
88
|
let minIndex = -1;
|
|
78
89
|
let minScore = Number.MAX_SAFE_INTEGER;
|
|
90
|
+
let score = [];
|
|
79
91
|
for (let i = 0; i < deltaResiduals.length; i++) {
|
|
80
92
|
const value =
|
|
81
93
|
(amplitudeResiduals[i] / maxAmplitude +
|
|
82
94
|
deltaResiduals[i] / maxDelta +
|
|
83
|
-
|
|
95
|
+
1 -
|
|
96
|
+
positionResiduals[i] / maxPosition) /
|
|
84
97
|
3;
|
|
98
|
+
|
|
99
|
+
score.push(value);
|
|
85
100
|
if (minScore > value) {
|
|
86
101
|
minIndex = i;
|
|
87
102
|
minScore = value;
|
|
88
103
|
}
|
|
89
104
|
}
|
|
90
|
-
|
|
105
|
+
|
|
106
|
+
if (minScore < 0 || minIndex < 0) {
|
|
107
|
+
new Error('There is not a correct match with the pattern');
|
|
108
|
+
return peaks;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const { peaks: shiftedSolventPeaks } = getShiftedSolventPeaks(
|
|
91
112
|
nearPeaks[minIndex],
|
|
92
113
|
solventSignal,
|
|
93
114
|
solventXYPeaks,
|
|
@@ -96,7 +117,11 @@ export function solventSuppression(
|
|
|
96
117
|
const { rowAssignments, gain } = linearSumAssignment(diff, {
|
|
97
118
|
maximaze: false,
|
|
98
119
|
});
|
|
99
|
-
|
|
120
|
+
|
|
121
|
+
if (gain < 0) {
|
|
122
|
+
new Error('The gain is below to zero');
|
|
123
|
+
return peaks;
|
|
124
|
+
}
|
|
100
125
|
|
|
101
126
|
if (markSolventPeaks) {
|
|
102
127
|
for (let index of rowAssignments) {
|
|
@@ -131,27 +156,34 @@ function getSolventPeaks(
|
|
|
131
156
|
return peaks.filter((peak) => peak.x < 1000);
|
|
132
157
|
}
|
|
133
158
|
|
|
134
|
-
function getShiftedSolventPeaks(
|
|
135
|
-
peak:
|
|
159
|
+
function getShiftedSolventPeaks<T extends PointXY>(
|
|
160
|
+
peak: T,
|
|
136
161
|
solventSignal: any,
|
|
137
|
-
solventXYPeaks:
|
|
162
|
+
solventXYPeaks: T[],
|
|
138
163
|
) {
|
|
139
164
|
const shiftedSolventPeaks: PointXY[] = JSON.parse(
|
|
140
165
|
JSON.stringify(solventXYPeaks),
|
|
141
166
|
);
|
|
142
167
|
// shift x values of solventPeaks to center it to the current peak.
|
|
143
|
-
|
|
168
|
+
let deltaPPM = peak.x - solventSignal.delta;
|
|
169
|
+
if (solventXYPeaks.length > 1 && solventXYPeaks.length % 2 === 0) {
|
|
170
|
+
deltaPPM += solventXYPeaks[0].x;
|
|
171
|
+
}
|
|
144
172
|
const maxIntensity = shiftedSolventPeaks.reduce(
|
|
145
173
|
(max, current) => (current.y > max ? current.y : max),
|
|
146
174
|
shiftedSolventPeaks[0].y,
|
|
147
175
|
);
|
|
176
|
+
let currentDelta = 0;
|
|
148
177
|
for (let shiftedSolventPeak of shiftedSolventPeaks) {
|
|
149
178
|
shiftedSolventPeak.x += deltaPPM;
|
|
150
179
|
shiftedSolventPeak.y /= maxIntensity;
|
|
180
|
+
currentDelta += shiftedSolventPeak.x;
|
|
151
181
|
}
|
|
152
|
-
return
|
|
182
|
+
return {
|
|
183
|
+
peaks: shiftedSolventPeaks,
|
|
184
|
+
delta: currentDelta / shiftedSolventPeaks.length,
|
|
185
|
+
};
|
|
153
186
|
}
|
|
154
|
-
|
|
155
187
|
function getClosestPeaks(shiftedSolventPeaks: PointXY[], nearPeaks: PointXY[]) {
|
|
156
188
|
const diff = getDiffMatrix(shiftedSolventPeaks, nearPeaks);
|
|
157
189
|
const { rowAssignments, gain } = linearSumAssignment(diff, {
|
|
@@ -169,11 +201,7 @@ function getClosestPeaks(shiftedSolventPeaks: PointXY[], nearPeaks: PointXY[]) {
|
|
|
169
201
|
return assignmentPeaks;
|
|
170
202
|
}
|
|
171
203
|
|
|
172
|
-
function
|
|
173
|
-
return peaks[0].x > peaks[1].x ? peaks.sort((a, b) => a.x - b.x) : peaks;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
function getDiffMatrix(rows: PointXY[], columns: PointXY[]) {
|
|
204
|
+
function getDiffMatrix<T extends PointXY>(rows: T[], columns: T[]) {
|
|
177
205
|
const nbColumns = columns.length;
|
|
178
206
|
const nbRows = rows.length;
|
|
179
207
|
const diff = new Matrix(nbRows, nbColumns);
|
|
@@ -62,10 +62,12 @@ type SignalInternMandatory = MakeMandatory<
|
|
|
62
62
|
function checkSignalForCompilePattern(
|
|
63
63
|
signal: SignalIntern,
|
|
64
64
|
): asserts signal is SignalInternMandatory {
|
|
65
|
-
if (!signal
|
|
65
|
+
if (!('symRank' in signal)) {
|
|
66
66
|
throw new Error('Internal error, symRank was not calculated');
|
|
67
67
|
}
|
|
68
|
-
if (!
|
|
68
|
+
if (!('mask' in signal)) {
|
|
69
|
+
throw new Error('Internal Error, mask was not added');
|
|
70
|
+
}
|
|
69
71
|
}
|
|
70
72
|
|
|
71
73
|
export interface OpitonsCompilePatter {
|
|
@@ -118,10 +120,8 @@ export default {
|
|
|
118
120
|
// Lets check if the signal could be a singulet.
|
|
119
121
|
if (peaks.length === 1 && n === 0) {
|
|
120
122
|
validPattern = true;
|
|
121
|
-
} else {
|
|
122
|
-
|
|
123
|
-
continue;
|
|
124
|
-
}
|
|
123
|
+
} else if (peaks.length <= 1) {
|
|
124
|
+
continue;
|
|
125
125
|
}
|
|
126
126
|
// 1.3 Establish a range for the Heights Hi [peaks.intensity*0.85,peaks.intensity*1.15];
|
|
127
127
|
let ranges = getRanges(peaks);
|
|
@@ -397,7 +397,7 @@ function getRanges(peaks: Peak1DIntern[]): GetRanges {
|
|
|
397
397
|
}
|
|
398
398
|
currentIndex[i] = 0;
|
|
399
399
|
}
|
|
400
|
-
return { values: ranges, currentIndex
|
|
400
|
+
return { values: ranges, currentIndex, active: 0 };
|
|
401
401
|
}
|
|
402
402
|
/**
|
|
403
403
|
* Performs a symmetrization of the signal by using different aproximations to the center.
|
|
@@ -531,20 +531,20 @@ function symmetrize(
|
|
|
531
531
|
if (Math.abs(diffL - diffR) < maxError) {
|
|
532
532
|
avg = Math.min(peaks[left].intensity, peaks[right].intensity);
|
|
533
533
|
avgWidth = Math.min(peaks[left].width, peaks[right].width);
|
|
534
|
-
peaks[left].intensity =
|
|
535
|
-
peaks[
|
|
534
|
+
peaks[left].intensity = avg;
|
|
535
|
+
peaks[right].intensity = avg;
|
|
536
|
+
peaks[left].width = avgWidth;
|
|
537
|
+
peaks[right].width = avgWidth;
|
|
536
538
|
middle = [
|
|
537
539
|
middle[0] + (peaks[right].x + peaks[left].x) / 2,
|
|
538
540
|
middle[1] + 1,
|
|
539
541
|
];
|
|
542
|
+
} else if (Math.max(diffL, diffR) === diffR) {
|
|
543
|
+
mask[right] = false;
|
|
544
|
+
left--;
|
|
540
545
|
} else {
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
left--;
|
|
544
|
-
} else {
|
|
545
|
-
mask[left] = false;
|
|
546
|
-
right++;
|
|
547
|
-
}
|
|
546
|
+
mask[left] = false;
|
|
547
|
+
right++;
|
|
548
548
|
}
|
|
549
549
|
}
|
|
550
550
|
}
|
|
@@ -593,10 +593,8 @@ function symmetrize(
|
|
|
593
593
|
weight += peaks[i].intensity;
|
|
594
594
|
}
|
|
595
595
|
symFactor /= weight;
|
|
596
|
-
} else {
|
|
597
|
-
|
|
598
|
-
symFactor = 1;
|
|
599
|
-
}
|
|
596
|
+
} else if (peaks.length === 1) {
|
|
597
|
+
symFactor = 1;
|
|
600
598
|
}
|
|
601
599
|
let newSumHeights = 0;
|
|
602
600
|
for (const peak of peaks) {
|
|
@@ -606,15 +604,13 @@ function symmetrize(
|
|
|
606
604
|
// Sometimes we need a second opinion after the first symmetrization.
|
|
607
605
|
if (symFactor > 0.8 && symFactor < 0.97 && iteration < 2) {
|
|
608
606
|
return symmetrize(newSignal, maxErrorIter2, 2, key);
|
|
609
|
-
} else {
|
|
607
|
+
} else if (peaks.length > 1) {
|
|
610
608
|
// Center the given pattern at cs and symmetrize x
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
peaks[peaks.length - 1 - i].x = cs - dxi;
|
|
617
|
-
}
|
|
609
|
+
let dxi;
|
|
610
|
+
for (let i = Math.ceil(peaks.length / 2) - 1; i >= 0; i--) {
|
|
611
|
+
dxi = (peaks[i].x - peaks[peaks.length - 1 - i].x) / 2.0;
|
|
612
|
+
peaks[i].x = cs + dxi;
|
|
613
|
+
peaks[peaks.length - 1 - i].x = cs - dxi;
|
|
618
614
|
}
|
|
619
615
|
}
|
|
620
616
|
newSignal.symRank = symFactor;
|
|
@@ -658,7 +654,7 @@ function normalize(signal: SignalInternMandatory, n: number) {
|
|
|
658
654
|
let index = signal.mask2.length - 1;
|
|
659
655
|
for (let i = peaks.length - 1; i >= 0; i--) {
|
|
660
656
|
peaks[i].intensity *= norm;
|
|
661
|
-
while (index >= 0 && signal.mask2[index]
|
|
657
|
+
while (index >= 0 && !signal.mask2[index]) {
|
|
662
658
|
index--;
|
|
663
659
|
}
|
|
664
660
|
if (peaks[i].intensity < 0.75) {
|
|
@@ -689,7 +685,7 @@ function chemicalShift(peaks: Peak1DIntern[], mask: boolean[] = []) {
|
|
|
689
685
|
let area;
|
|
690
686
|
if (mask.length > 0) {
|
|
691
687
|
for (let i = 0; i < peaks.length; i++) {
|
|
692
|
-
if (mask[i]
|
|
688
|
+
if (mask[i]) {
|
|
693
689
|
area = getArea(peaks[i]);
|
|
694
690
|
sum += area;
|
|
695
691
|
cs += area * peaks[i].x;
|
|
@@ -138,7 +138,7 @@ function completeMissingIfNeeded(
|
|
|
138
138
|
}
|
|
139
139
|
}
|
|
140
140
|
}
|
|
141
|
-
if (diagX
|
|
141
|
+
if (!diagX) {
|
|
142
142
|
newSignal = {
|
|
143
143
|
x: {
|
|
144
144
|
delta: thisSignal.y.delta,
|
|
@@ -158,7 +158,7 @@ function completeMissingIfNeeded(
|
|
|
158
158
|
properties.push(tmpProp);
|
|
159
159
|
addedPeaks++;
|
|
160
160
|
}
|
|
161
|
-
if (diagY
|
|
161
|
+
if (!diagY) {
|
|
162
162
|
newSignal = {
|
|
163
163
|
x: {
|
|
164
164
|
delta: thisSignal.y.delta,
|
|
@@ -202,15 +202,13 @@ function checkCrossPeaks(
|
|
|
202
202
|
}
|
|
203
203
|
crossPeaksX.push(i);
|
|
204
204
|
shift += cross.x.delta;
|
|
205
|
-
} else {
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
properties[i][1]++;
|
|
210
|
-
}
|
|
211
|
-
crossPeaksY.push(i);
|
|
212
|
-
shift += cross.y.delta;
|
|
205
|
+
} else if (Math.abs(cross.y.delta - signal.y.delta) < diagonalError) {
|
|
206
|
+
hits++;
|
|
207
|
+
if (updateProperties) {
|
|
208
|
+
properties[i][1]++;
|
|
213
209
|
}
|
|
210
|
+
crossPeaksY.push(i);
|
|
211
|
+
shift += cross.y.delta;
|
|
214
212
|
}
|
|
215
213
|
}
|
|
216
214
|
}
|
|
@@ -278,12 +276,10 @@ function initializeProperties(signals: NMRSignal2D[]) {
|
|
|
278
276
|
let shift = (signals[i].x.delta * 2 + signals[i].y.delta) / 3.0;
|
|
279
277
|
signals[i].x.delta = shift;
|
|
280
278
|
signals[i].y.delta = shift;
|
|
279
|
+
} else if (signals[i].x.delta - signals[i].y.delta > 0) {
|
|
280
|
+
signalsProperties[i][0] = 1;
|
|
281
281
|
} else {
|
|
282
|
-
|
|
283
|
-
signalsProperties[i][0] = 1;
|
|
284
|
-
} else {
|
|
285
|
-
signalsProperties[i][0] = -1;
|
|
286
|
-
}
|
|
282
|
+
signalsProperties[i][0] = -1;
|
|
287
283
|
}
|
|
288
284
|
}
|
|
289
285
|
return signalsProperties;
|
|
@@ -172,14 +172,12 @@ function calculateFrequency(
|
|
|
172
172
|
): number | string {
|
|
173
173
|
if (typeof nucleus === 'string') {
|
|
174
174
|
return getFrequency(nucleus, { nucleus: '1H', frequency });
|
|
175
|
+
} else if (nucleus[0] === nucleus[1]) {
|
|
176
|
+
return `${frequency},${frequency}`;
|
|
175
177
|
} else {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
nucleus: nucleus[0],
|
|
181
|
-
frequency,
|
|
182
|
-
})}`;
|
|
183
|
-
}
|
|
178
|
+
return `${frequency},${getFrequency(nucleus[1], {
|
|
179
|
+
nucleus: nucleus[0],
|
|
180
|
+
frequency,
|
|
181
|
+
})}`;
|
|
184
182
|
}
|
|
185
183
|
}
|