nmr-processing 8.0.0 → 8.3.0
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/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 +5 -1
- package/lib/index.js +5 -1
- package/lib/index.js.map +1 -1
- package/lib/peaks/NMRPeak1D.d.ts +0 -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 +6 -0
- package/lib/peaks/solventSuppression.js +158 -0
- package/lib/peaks/solventSuppression.js.map +1 -0
- package/lib/peaks/util/jAnalyzer.d.ts +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/ranges/rangesToXY.js +27 -3
- package/lib/ranges/rangesToXY.js.map +1 -1
- package/lib/signals/addDummySignals.d.ts +2 -0
- package/lib/signals/addDummySignals.js +56 -0
- package/lib/signals/addDummySignals.js.map +1 -0
- package/lib/signals/hackSignalsToXY.js +2 -48
- package/lib/signals/hackSignalsToXY.js.map +1 -1
- package/lib/signals/simulation/getPauliMatrix.js.map +1 -1
- package/lib/signals/simulation/simulate1D.d.ts +1 -39
- package/lib/signals/simulation/simulate1D.js +13 -240
- package/lib/signals/simulation/simulate1D.js.map +1 -1
- package/lib/signals/simulation/simulateXYPeaks.d.ts +47 -0
- package/lib/signals/simulation/simulateXYPeaks.js +246 -0
- package/lib/signals/simulation/simulateXYPeaks.js.map +1 -0
- package/lib/signals/simulation/splitSpinSystem.js +11 -13
- package/lib/signals/simulation/splitSpinSystem.js.map +1 -1
- package/lib/utilities/getFrequency.d.ts +1 -1
- package/lib/utilities/getFrequency.js +4 -4
- package/lib/utilities/getFrequency.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 +5 -1
- 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 +154 -0
- package/lib-esm/peaks/solventSuppression.js.map +1 -0
- 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/ranges/rangesToXY.js +27 -3
- package/lib-esm/ranges/rangesToXY.js.map +1 -1
- package/lib-esm/signals/addDummySignals.js +52 -0
- package/lib-esm/signals/addDummySignals.js.map +1 -0
- package/lib-esm/signals/hackSignalsToXY.js +2 -48
- package/lib-esm/signals/hackSignalsToXY.js.map +1 -1
- package/lib-esm/signals/simulation/getPauliMatrix.js.map +1 -1
- package/lib-esm/signals/simulation/simulate1D.js +14 -238
- package/lib-esm/signals/simulation/simulate1D.js.map +1 -1
- package/lib-esm/signals/simulation/simulateXYPeaks.js +239 -0
- package/lib-esm/signals/simulation/simulateXYPeaks.js.map +1 -0
- package/lib-esm/signals/simulation/splitSpinSystem.js +11 -13
- package/lib-esm/signals/simulation/splitSpinSystem.js.map +1 -1
- package/lib-esm/utilities/getFrequency.js +1 -1
- package/lib-esm/utilities/getFrequency.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 +16 -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 +7 -1
- package/src/peaks/NMRPeak1D.ts +0 -1
- package/src/peaks/peaksToRanges.ts +2 -2
- package/src/peaks/solventSuppression.ts +214 -0
- package/src/peaks/util/jAnalyzer.ts +27 -31
- 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/ranges/rangesToXY.ts +33 -4
- package/src/signals/addDummySignals.ts +77 -0
- package/src/signals/hackSignalsToXY.ts +2 -72
- package/src/signals/simulation/getPauliMatrix.ts +1 -1
- package/src/signals/simulation/simulate1D.ts +14 -319
- package/src/signals/simulation/simulateXYPeaks.ts +332 -0
- package/src/signals/simulation/splitSpinSystem.ts +10 -12
- package/src/utilities/getFrequency.ts +1 -1
- 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
- package/lib/constants/gyromagneticRatio.d.ts +0 -6
- package/lib/constants/gyromagneticRatio.js +0 -26
- package/lib/constants/gyromagneticRatio.js.map +0 -1
- package/lib-esm/constants/gyromagneticRatio.js +0 -23
- package/lib-esm/constants/gyromagneticRatio.js.map +0 -1
- package/src/constants/gyromagneticRatio.ts +0 -49
package/src/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export * from '
|
|
1
|
+
export * from 'gyromagnetic-ratio';
|
|
2
2
|
export * from './constants/impurities';
|
|
3
3
|
export * from './constants/couplingPatterns';
|
|
4
4
|
|
|
@@ -37,6 +37,12 @@ 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
|
+
export * from './apodization/compose';
|
|
45
|
+
|
|
40
46
|
export type { NMRSignal1D } from './signals/NMRSignal1D';
|
|
41
47
|
export type { NMRSignal2D, Signal2DProjection } from './xyz/NMRSignal2D';
|
|
42
48
|
export type { NMRRange } from './xy/NMRRange';
|
package/src/peaks/NMRPeak1D.ts
CHANGED
|
@@ -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 = {},
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { PointXY } from 'cheminfo-types';
|
|
2
|
+
import { linearSumAssignment } from 'linear-sum-assignment';
|
|
3
|
+
import { Matrix } from 'ml-matrix';
|
|
4
|
+
import { gaussianFct } from 'ml-peak-shape-generator';
|
|
5
|
+
import { xFindClosestIndex, xMaxValue } from 'ml-spectra-processing';
|
|
6
|
+
|
|
7
|
+
import { NMRSignal1D } from '../signals/NMRSignal1D';
|
|
8
|
+
import { addDummySignals } from '../signals/addDummySignals';
|
|
9
|
+
import { signalsToSpinSystem } from '../signals/simulation/signalsToSpinSystem';
|
|
10
|
+
import { simulateXYPeaks } from '../signals/simulation/simulateXYPeaks';
|
|
11
|
+
import { splitSpinSystem } from '../signals/simulation/splitSpinSystem';
|
|
12
|
+
|
|
13
|
+
import { NMRPeak1D } from './NMRPeak1D';
|
|
14
|
+
|
|
15
|
+
export function solventSuppression<T extends NMRPeak1D>(
|
|
16
|
+
peakList: T[],
|
|
17
|
+
solvent: NMRSignal1D[],
|
|
18
|
+
options: { markSolventPeaks?: boolean; solventZoneExtension?: number } = {},
|
|
19
|
+
) {
|
|
20
|
+
const peaks = [...peakList].sort((a, b) => a.x - b.x);
|
|
21
|
+
|
|
22
|
+
const xValues = peaks.map((peak) => peak.x);
|
|
23
|
+
|
|
24
|
+
const { markSolventPeaks = false, solventZoneExtension = 1.2 } = options;
|
|
25
|
+
|
|
26
|
+
for (const solventSignal of solvent) {
|
|
27
|
+
let solventXYPeaks = solventSignal.peaks
|
|
28
|
+
? solventSignal.peaks
|
|
29
|
+
: getSolventPeaks(solventSignal);
|
|
30
|
+
solventXYPeaks.sort((a, b) => a.x - b.x);
|
|
31
|
+
|
|
32
|
+
let upIndex = xFindClosestIndex(
|
|
33
|
+
xValues,
|
|
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,
|
|
43
|
+
);
|
|
44
|
+
const amplitudeResiduals = [];
|
|
45
|
+
const deltaResiduals = [];
|
|
46
|
+
const positionResiduals = [];
|
|
47
|
+
for (let peak of nearPeaks) {
|
|
48
|
+
const { peaks: shiftedSolventPeaks, delta: currentDelta } =
|
|
49
|
+
getShiftedSolventPeaks(peak, solventSignal, solventXYPeaks);
|
|
50
|
+
|
|
51
|
+
const closestPeaks = getClosestPeaks(shiftedSolventPeaks, nearPeaks);
|
|
52
|
+
let deltaResidual = 0;
|
|
53
|
+
let amplitudeResidual = 0;
|
|
54
|
+
let positionResidual = 0;
|
|
55
|
+
|
|
56
|
+
for (let i = 0; i < closestPeaks.length; i++) {
|
|
57
|
+
amplitudeResidual += Math.abs(
|
|
58
|
+
shiftedSolventPeaks[i].y - closestPeaks[i].y,
|
|
59
|
+
);
|
|
60
|
+
deltaResidual += Math.abs(shiftedSolventPeaks[i].x - closestPeaks[i].x);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (closestPeaks.length === 0) {
|
|
64
|
+
deltaResidual = Number.MAX_SAFE_INTEGER;
|
|
65
|
+
amplitudeResidual = Number.MAX_SAFE_INTEGER;
|
|
66
|
+
positionResidual = Number.MAX_SAFE_INTEGER;
|
|
67
|
+
} else {
|
|
68
|
+
positionResidual = gaussianFct(
|
|
69
|
+
Math.abs(solventSignal.delta - currentDelta),
|
|
70
|
+
0.5,
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
amplitudeResiduals.push(amplitudeResidual);
|
|
75
|
+
deltaResiduals.push(deltaResidual);
|
|
76
|
+
positionResiduals.push(positionResidual);
|
|
77
|
+
}
|
|
78
|
+
|
|
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
|
+
});
|
|
87
|
+
|
|
88
|
+
let minIndex = -1;
|
|
89
|
+
let minScore = Number.MAX_SAFE_INTEGER;
|
|
90
|
+
let score = [];
|
|
91
|
+
for (let i = 0; i < deltaResiduals.length; i++) {
|
|
92
|
+
const value =
|
|
93
|
+
(amplitudeResiduals[i] / maxAmplitude +
|
|
94
|
+
deltaResiduals[i] / maxDelta +
|
|
95
|
+
1 -
|
|
96
|
+
positionResiduals[i] / maxPosition) /
|
|
97
|
+
3;
|
|
98
|
+
|
|
99
|
+
score.push(value);
|
|
100
|
+
if (minScore > value) {
|
|
101
|
+
minIndex = i;
|
|
102
|
+
minScore = value;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
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(
|
|
112
|
+
nearPeaks[minIndex],
|
|
113
|
+
solventSignal,
|
|
114
|
+
solventXYPeaks,
|
|
115
|
+
);
|
|
116
|
+
const diff = getDiffMatrix(shiftedSolventPeaks, nearPeaks);
|
|
117
|
+
const { rowAssignments, gain } = linearSumAssignment(diff, {
|
|
118
|
+
maximaze: false,
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
if (gain < 0) {
|
|
122
|
+
new Error('The gain is below to zero');
|
|
123
|
+
return peaks;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (markSolventPeaks) {
|
|
127
|
+
for (let index of rowAssignments) {
|
|
128
|
+
peaks[index + lowIndex].kind = 'solvent';
|
|
129
|
+
}
|
|
130
|
+
} else {
|
|
131
|
+
rowAssignments.sort((a, b) => b - a);
|
|
132
|
+
for (let index of rowAssignments) {
|
|
133
|
+
peaks.splice(index + lowIndex, 1);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return peaks;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function getSolventPeaks(
|
|
142
|
+
signal: NMRSignal1D,
|
|
143
|
+
options: { frequency?: number; maxClusterSize?: number } = {},
|
|
144
|
+
) {
|
|
145
|
+
let signals = addDummySignals([signal]);
|
|
146
|
+
let spinSystem = signalsToSpinSystem(signals);
|
|
147
|
+
|
|
148
|
+
const { frequency = 400, maxClusterSize = 8 } = options;
|
|
149
|
+
|
|
150
|
+
spinSystem.clusters = splitSpinSystem(spinSystem, {
|
|
151
|
+
frequency,
|
|
152
|
+
maxClusterSize,
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
const peaks = simulateXYPeaks(spinSystem);
|
|
156
|
+
return peaks.filter((peak) => peak.x < 1000);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function getShiftedSolventPeaks<T extends PointXY>(
|
|
160
|
+
peak: T,
|
|
161
|
+
solventSignal: any,
|
|
162
|
+
solventXYPeaks: T[],
|
|
163
|
+
) {
|
|
164
|
+
const shiftedSolventPeaks: PointXY[] = JSON.parse(
|
|
165
|
+
JSON.stringify(solventXYPeaks),
|
|
166
|
+
);
|
|
167
|
+
// shift x values of solventPeaks to center it to the current peak.
|
|
168
|
+
let deltaPPM = peak.x - solventSignal.delta;
|
|
169
|
+
if (solventXYPeaks.length > 1 && solventXYPeaks.length % 2 === 0) {
|
|
170
|
+
deltaPPM += solventXYPeaks[0].x;
|
|
171
|
+
}
|
|
172
|
+
const maxIntensity = shiftedSolventPeaks.reduce(
|
|
173
|
+
(max, current) => (current.y > max ? current.y : max),
|
|
174
|
+
shiftedSolventPeaks[0].y,
|
|
175
|
+
);
|
|
176
|
+
let currentDelta = 0;
|
|
177
|
+
for (let shiftedSolventPeak of shiftedSolventPeaks) {
|
|
178
|
+
shiftedSolventPeak.x += deltaPPM;
|
|
179
|
+
shiftedSolventPeak.y /= maxIntensity;
|
|
180
|
+
currentDelta += shiftedSolventPeak.x;
|
|
181
|
+
}
|
|
182
|
+
return {
|
|
183
|
+
peaks: shiftedSolventPeaks,
|
|
184
|
+
delta: currentDelta / shiftedSolventPeaks.length,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
function getClosestPeaks(shiftedSolventPeaks: PointXY[], nearPeaks: PointXY[]) {
|
|
188
|
+
const diff = getDiffMatrix(shiftedSolventPeaks, nearPeaks);
|
|
189
|
+
const { rowAssignments, gain } = linearSumAssignment(diff, {
|
|
190
|
+
maximaze: false,
|
|
191
|
+
});
|
|
192
|
+
if (gain === -1) return [];
|
|
193
|
+
|
|
194
|
+
const assignmentPeaks = [];
|
|
195
|
+
let maxValue = Number.MIN_SAFE_INTEGER;
|
|
196
|
+
for (let index of rowAssignments) {
|
|
197
|
+
if (maxValue < nearPeaks[index].y) maxValue = nearPeaks[index].y;
|
|
198
|
+
assignmentPeaks.push({ ...nearPeaks[index] });
|
|
199
|
+
}
|
|
200
|
+
assignmentPeaks.forEach((peak, i, arr) => (arr[i].y /= maxValue));
|
|
201
|
+
return assignmentPeaks;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function getDiffMatrix<T extends PointXY>(rows: T[], columns: T[]) {
|
|
205
|
+
const nbColumns = columns.length;
|
|
206
|
+
const nbRows = rows.length;
|
|
207
|
+
const diff = new Matrix(nbRows, nbColumns);
|
|
208
|
+
for (let r = 0; r < nbRows; r++) {
|
|
209
|
+
for (let c = 0; c < nbColumns; c++) {
|
|
210
|
+
diff.set(r, c, Math.abs(rows[r].x - columns[c].x));
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return diff;
|
|
214
|
+
}
|
|
@@ -29,7 +29,7 @@ interface IntergralData {
|
|
|
29
29
|
to: number;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
export type Peak1DIntern = Omit<NMRPeak1D, 'y' | 'shape'
|
|
32
|
+
export type Peak1DIntern = Omit<NMRPeak1D, 'y' | 'shape'> & {
|
|
33
33
|
intensity: number;
|
|
34
34
|
};
|
|
35
35
|
|
|
@@ -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
|
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { NMRRangeWithIds, NMRSignal1DWithId } from '../assignment/nmrAssigment';
|
|
2
|
+
import generateID from '../assignment/utils/generateID';
|
|
3
|
+
import { addIDs } from '../assignment/utils/getAssignment/checkIDs';
|
|
4
|
+
import { NMRPeak1D } from '../peaks/NMRPeak1D';
|
|
5
|
+
import { detectSignals } from '../peaks/peaksToRanges';
|
|
6
|
+
import { solventSuppression } from '../peaks/solventSuppression';
|
|
7
|
+
import { SignalIntern } from '../peaks/util/jAnalyzer';
|
|
8
|
+
import { NMRSignal1D } from '../signals/NMRSignal1D';
|
|
9
|
+
import { NMRRange } from '../xy/NMRRange';
|
|
10
|
+
|
|
11
|
+
interface NMRPeak1DWithSignalID extends NMRPeak1D {
|
|
12
|
+
signalID: string;
|
|
13
|
+
rangeID: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function markSolventPeaks<T extends NMRRange>(
|
|
17
|
+
input: T[],
|
|
18
|
+
solventSignals: NMRSignal1D[],
|
|
19
|
+
options: any = {},
|
|
20
|
+
) {
|
|
21
|
+
const { frequency = 400 } = options;
|
|
22
|
+
const ranges = addIDs([...input]) as NMRRangeWithIds[];
|
|
23
|
+
|
|
24
|
+
let peakList: NMRPeak1DWithSignalID[] = [];
|
|
25
|
+
for (const range of ranges) {
|
|
26
|
+
const rangeID = range.id;
|
|
27
|
+
for (const signal of range.signals || []) {
|
|
28
|
+
const signalID = signal.id;
|
|
29
|
+
for (let peak of signal.peaks || []) {
|
|
30
|
+
peakList.push({
|
|
31
|
+
...peak,
|
|
32
|
+
rangeID,
|
|
33
|
+
signalID,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const peaks = solventSuppression(peakList, solventSignals, {
|
|
40
|
+
markSolventPeaks: true,
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const signalsWithSolvent = getSignalIDsWithSolvent(peaks);
|
|
44
|
+
for (let range of ranges) {
|
|
45
|
+
if (!range.signals) continue;
|
|
46
|
+
for (let signal of range.signals) {
|
|
47
|
+
if (!signalsWithSolvent.includes(signal.id)) continue;
|
|
48
|
+
const signalPeaks = [];
|
|
49
|
+
const solventSignalPeaks = [];
|
|
50
|
+
for (let peak of peaks) {
|
|
51
|
+
if (peak.signalID === signal.id) {
|
|
52
|
+
const { signalID, rangeID, ...newPeak } = peak;
|
|
53
|
+
if (peak.kind === 'solvent') {
|
|
54
|
+
solventSignalPeaks.push(newPeak);
|
|
55
|
+
} else {
|
|
56
|
+
signalPeaks.push(newPeak);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
const newSignals =
|
|
61
|
+
signalPeaks.length > 0
|
|
62
|
+
? detectSignals({ x: [], y: [] }, signalPeaks, {
|
|
63
|
+
integralType: 'peak',
|
|
64
|
+
frequency,
|
|
65
|
+
})
|
|
66
|
+
: [];
|
|
67
|
+
solventSignalPeaks.sort((a, b) => a.x - b.x);
|
|
68
|
+
const lowPPMValue = solventSignalPeaks[0].x;
|
|
69
|
+
const highPPMValue = solventSignalPeaks[solventSignalPeaks.length - 1].x;
|
|
70
|
+
const newSolventSignals = detectSignals(
|
|
71
|
+
{ x: [], y: [] },
|
|
72
|
+
solventSignalPeaks,
|
|
73
|
+
{
|
|
74
|
+
integralType: 'peak',
|
|
75
|
+
frequencyCluster: (highPPMValue - lowPPMValue) * frequency,
|
|
76
|
+
frequency,
|
|
77
|
+
},
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
range.signals = [
|
|
81
|
+
...adaptSignals(newSignals),
|
|
82
|
+
...adaptSignals(newSolventSignals),
|
|
83
|
+
...range.signals.filter((currSignal) => currSignal.id !== signal.id),
|
|
84
|
+
];
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return ranges as T[];
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function getSignalIDsWithSolvent(solventPeaks: NMRPeak1DWithSignalID[]) {
|
|
91
|
+
const uniqueSignalID = new Set();
|
|
92
|
+
for (let peak of solventPeaks) {
|
|
93
|
+
if (peak.kind !== 'solvent') continue;
|
|
94
|
+
uniqueSignalID.add(peak.signalID);
|
|
95
|
+
}
|
|
96
|
+
return Array.from(uniqueSignalID);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function adaptSignals(signals: SignalIntern[]) {
|
|
100
|
+
const newSignals = [];
|
|
101
|
+
for (let signal of signals) {
|
|
102
|
+
const signalResult: NMRSignal1DWithId = {
|
|
103
|
+
id: generateID(),
|
|
104
|
+
delta: signal.delta,
|
|
105
|
+
kind: signal.kind || 'signal',
|
|
106
|
+
multiplicity: signal.multiplicity,
|
|
107
|
+
integration: signal.integralData.value,
|
|
108
|
+
};
|
|
109
|
+
signalResult.peaks = signal.peaks.map((peak) => {
|
|
110
|
+
const newResult: any = {
|
|
111
|
+
y: peak.intensity,
|
|
112
|
+
...peak,
|
|
113
|
+
};
|
|
114
|
+
delete newResult.intensity;
|
|
115
|
+
return newResult as NMRPeak1D;
|
|
116
|
+
});
|
|
117
|
+
signalResult.js = signal.nmrJs || [];
|
|
118
|
+
newSignals.push(signalResult);
|
|
119
|
+
}
|
|
120
|
+
return newSignals;
|
|
121
|
+
}
|
|
@@ -72,12 +72,12 @@ export function rangesToACS(
|
|
|
72
72
|
if (!options.nucleus) options.nucleus = '1H';
|
|
73
73
|
const nucleus = options.nucleus.toLowerCase().replace(/[0-9]/g, '');
|
|
74
74
|
const defaultOptions = globalOptions[nucleus];
|
|
75
|
-
options =
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
options,
|
|
80
|
-
|
|
75
|
+
options = {
|
|
76
|
+
...defaultOptions,
|
|
77
|
+
ascending: false,
|
|
78
|
+
format: 'IMJA',
|
|
79
|
+
...options,
|
|
80
|
+
};
|
|
81
81
|
|
|
82
82
|
ranges = JSON.parse(JSON.stringify(ranges));
|
|
83
83
|
if (options.ascending === true) {
|
|
@@ -188,14 +188,13 @@ function pushDelta(range: NMRRange, acsRanges: string[], options: any) {
|
|
|
188
188
|
acsRanges.push(strings);
|
|
189
189
|
}
|
|
190
190
|
|
|
191
|
-
function getIntegral(range: NMRRange, options:
|
|
191
|
+
function getIntegral(range: NMRRange, options: { nucleus: string[] }) {
|
|
192
192
|
let integration = '';
|
|
193
193
|
if (range.pubIntegral) {
|
|
194
194
|
integration = String(range.pubIntegral);
|
|
195
195
|
} else if (range.integration) {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
options.nucleus[options.nucleus.length - 1];
|
|
196
|
+
const { nucleus } = options;
|
|
197
|
+
integration = range.integration.toFixed(0) + nucleus[nucleus.length - 1];
|
|
199
198
|
}
|
|
200
199
|
return integration;
|
|
201
200
|
}
|