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.
Files changed (162) hide show
  1. package/README.md +23 -3
  2. package/lib/apodization/apodization.d.ts +22 -0
  3. package/lib/apodization/apodization.js +18 -0
  4. package/lib/apodization/apodization.js.map +1 -0
  5. package/lib/apodization/applyWindow.d.ts +28 -0
  6. package/lib/apodization/applyWindow.js +20 -0
  7. package/lib/apodization/applyWindow.js.map +1 -0
  8. package/lib/apodization/compose.d.ts +23 -0
  9. package/lib/apodization/compose.js +25 -0
  10. package/lib/apodization/compose.js.map +1 -0
  11. package/lib/apodization/getFunction.d.ts +2 -0
  12. package/lib/apodization/getFunction.js +18 -0
  13. package/lib/apodization/getFunction.js.map +1 -0
  14. package/lib/apodization/shapes/WindowFunctions.d.ts +12 -0
  15. package/lib/apodization/shapes/WindowFunctions.js +3 -0
  16. package/lib/apodization/shapes/WindowFunctions.js.map +1 -0
  17. package/lib/apodization/shapes/exponential.d.ts +11 -0
  18. package/lib/apodization/shapes/exponential.js +10 -0
  19. package/lib/apodization/shapes/exponential.js.map +1 -0
  20. package/lib/apodization/shapes/lorentzToGauss.d.ts +26 -0
  21. package/lib/apodization/shapes/lorentzToGauss.js +15 -0
  22. package/lib/apodization/shapes/lorentzToGauss.js.map +1 -0
  23. package/lib/apodization/utils/getData.d.ts +4 -0
  24. package/lib/apodization/utils/getData.js +21 -0
  25. package/lib/apodization/utils/getData.js.map +1 -0
  26. package/lib/assignment/utils/buildAssignments.d.ts +2 -2
  27. package/lib/assignment/utils/exploreTreeRec.js +1 -1
  28. package/lib/assignment/utils/exploreTreeRec.js.map +1 -1
  29. package/lib/assignment/utils/getAssignment/checkIDs.d.ts +1 -1
  30. package/lib/assignment/utils/getAssignment/checkIDs.js.map +1 -1
  31. package/lib/databases/DatabaseNMREntry.d.ts +2 -0
  32. package/lib/index.d.ts +3 -0
  33. package/lib/index.js +3 -0
  34. package/lib/index.js.map +1 -1
  35. package/lib/peaks/peaksToRanges.d.ts +16 -0
  36. package/lib/peaks/peaksToRanges.js +3 -2
  37. package/lib/peaks/peaksToRanges.js.map +1 -1
  38. package/lib/peaks/solventSuppression.d.ts +4 -1
  39. package/lib/peaks/solventSuppression.js +43 -32
  40. package/lib/peaks/solventSuppression.js.map +1 -1
  41. package/lib/peaks/util/jAnalyzer.js +26 -31
  42. package/lib/peaks/util/jAnalyzer.js.map +1 -1
  43. package/lib/peaks/util/peakOptimizer.js +12 -16
  44. package/lib/peaks/util/peakOptimizer.js.map +1 -1
  45. package/lib/prediction/predictAllSpectra.js +7 -9
  46. package/lib/prediction/predictAllSpectra.js.map +1 -1
  47. package/lib/prediction/predictCarbon.js +1 -1
  48. package/lib/prediction/predictCarbon.js.map +1 -1
  49. package/lib/prediction/utils/queryByHOSE.js +1 -1
  50. package/lib/prediction/utils/queryByHOSE.js.map +1 -1
  51. package/lib/ranges/markSolventSignal.d.ts +3 -0
  52. package/lib/ranges/markSolventSignal.js +107 -0
  53. package/lib/ranges/markSolventSignal.js.map +1 -0
  54. package/lib/ranges/rangesToACS.js +8 -4
  55. package/lib/ranges/rangesToACS.js.map +1 -1
  56. package/lib/signals/signalsJoin.js +4 -3
  57. package/lib/signals/signalsJoin.js.map +1 -1
  58. package/lib/signals/simulation/getPauliMatrix.js.map +1 -1
  59. package/lib/signals/simulation/splitSpinSystem.js +11 -13
  60. package/lib/signals/simulation/splitSpinSystem.js.map +1 -1
  61. package/lib/utilities/rangeFromSignal.d.ts +9 -5
  62. package/lib/utilities/rangeFromSignal.js +7 -7
  63. package/lib/utilities/rangeFromSignal.js.map +1 -1
  64. package/lib/utilities/resurrectRange.js +4 -7
  65. package/lib/utilities/resurrectRange.js.map +1 -1
  66. package/lib/xyz/util/formatZone.d.ts +3 -0
  67. package/lib/xyz/util/formatZone.js +38 -0
  68. package/lib/xyz/util/formatZone.js.map +1 -0
  69. package/lib/xyz/xyzAutoZonesPicking.d.ts +1 -2
  70. package/lib/xyz/xyzAutoZonesPicking.js +2 -34
  71. package/lib/xyz/xyzAutoZonesPicking.js.map +1 -1
  72. package/lib/xyz/xyzJResAnalyzer.d.ts +6 -1
  73. package/lib/xyz/xyzJResAnalyzer.js +9 -8
  74. package/lib/xyz/xyzJResAnalyzer.js.map +1 -1
  75. package/lib-esm/apodization/apodization.js +14 -0
  76. package/lib-esm/apodization/apodization.js.map +1 -0
  77. package/lib-esm/apodization/applyWindow.js +16 -0
  78. package/lib-esm/apodization/applyWindow.js.map +1 -0
  79. package/lib-esm/apodization/compose.js +21 -0
  80. package/lib-esm/apodization/compose.js.map +1 -0
  81. package/lib-esm/apodization/getFunction.js +14 -0
  82. package/lib-esm/apodization/getFunction.js.map +1 -0
  83. package/lib-esm/apodization/shapes/WindowFunctions.js +2 -0
  84. package/lib-esm/apodization/shapes/WindowFunctions.js.map +1 -0
  85. package/lib-esm/apodization/shapes/exponential.js +6 -0
  86. package/lib-esm/apodization/shapes/exponential.js.map +1 -0
  87. package/lib-esm/apodization/shapes/lorentzToGauss.js +11 -0
  88. package/lib-esm/apodization/shapes/lorentzToGauss.js.map +1 -0
  89. package/lib-esm/apodization/utils/getData.js +17 -0
  90. package/lib-esm/apodization/utils/getData.js.map +1 -0
  91. package/lib-esm/assignment/utils/buildAssignments.js +3 -3
  92. package/lib-esm/assignment/utils/exploreTreeRec.js +1 -1
  93. package/lib-esm/assignment/utils/exploreTreeRec.js.map +1 -1
  94. package/lib-esm/assignment/utils/getAssignment/buildAssignments.js +3 -3
  95. package/lib-esm/assignment/utils/getAssignment/checkIDs.js.map +1 -1
  96. package/lib-esm/index.js +3 -0
  97. package/lib-esm/index.js.map +1 -1
  98. package/lib-esm/peaks/peaksToRanges.js +2 -2
  99. package/lib-esm/peaks/peaksToRanges.js.map +1 -1
  100. package/lib-esm/peaks/solventSuppression.js +41 -27
  101. package/lib-esm/peaks/solventSuppression.js.map +1 -1
  102. package/lib-esm/peaks/util/jAnalyzer.js +26 -31
  103. package/lib-esm/peaks/util/jAnalyzer.js.map +1 -1
  104. package/lib-esm/peaks/util/peakOptimizer.js +12 -16
  105. package/lib-esm/peaks/util/peakOptimizer.js.map +1 -1
  106. package/lib-esm/prediction/predictAllSpectra.js +7 -9
  107. package/lib-esm/prediction/predictAllSpectra.js.map +1 -1
  108. package/lib-esm/prediction/predictCarbon.js +1 -1
  109. package/lib-esm/prediction/predictCarbon.js.map +1 -1
  110. package/lib-esm/prediction/utils/queryByHOSE.js +1 -1
  111. package/lib-esm/prediction/utils/queryByHOSE.js.map +1 -1
  112. package/lib-esm/ranges/markSolventSignal.js +100 -0
  113. package/lib-esm/ranges/markSolventSignal.js.map +1 -0
  114. package/lib-esm/ranges/rangesToACS.js +8 -4
  115. package/lib-esm/ranges/rangesToACS.js.map +1 -1
  116. package/lib-esm/signals/signalsJoin.js +4 -3
  117. package/lib-esm/signals/signalsJoin.js.map +1 -1
  118. package/lib-esm/signals/simulation/getPauliMatrix.js.map +1 -1
  119. package/lib-esm/signals/simulation/splitSpinSystem.js +11 -13
  120. package/lib-esm/signals/simulation/splitSpinSystem.js.map +1 -1
  121. package/lib-esm/utilities/rangeFromSignal.js +7 -7
  122. package/lib-esm/utilities/rangeFromSignal.js.map +1 -1
  123. package/lib-esm/utilities/resurrectRange.js +4 -7
  124. package/lib-esm/utilities/resurrectRange.js.map +1 -1
  125. package/lib-esm/xyz/util/formatZone.js +34 -0
  126. package/lib-esm/xyz/util/formatZone.js.map +1 -0
  127. package/lib-esm/xyz/xyzAutoZonesPicking.js +1 -33
  128. package/lib-esm/xyz/xyzAutoZonesPicking.js.map +1 -1
  129. package/lib-esm/xyz/xyzJResAnalyzer.js +9 -8
  130. package/lib-esm/xyz/xyzJResAnalyzer.js.map +1 -1
  131. package/package.json +14 -14
  132. package/src/apodization/apodization.ts +34 -0
  133. package/src/apodization/applyWindow.ts +51 -0
  134. package/src/apodization/compose.ts +47 -0
  135. package/src/apodization/getFunction.ts +15 -0
  136. package/src/apodization/shapes/WindowFunctions.ts +14 -0
  137. package/src/apodization/shapes/exponential.ts +16 -0
  138. package/src/apodization/shapes/lorentzToGauss.ts +41 -0
  139. package/src/apodization/utils/getData.ts +15 -0
  140. package/src/assignment/utils/buildAssignments.ts +4 -4
  141. package/src/assignment/utils/exploreTreeRec.ts +1 -1
  142. package/src/assignment/utils/getAssignment/buildAssignments.ts +3 -3
  143. package/src/assignment/utils/getAssignment/checkIDs.ts +1 -1
  144. package/src/databases/DatabaseNMREntry.ts +3 -0
  145. package/src/index.ts +5 -0
  146. package/src/peaks/peaksToRanges.ts +2 -2
  147. package/src/peaks/solventSuppression.ts +68 -40
  148. package/src/peaks/util/jAnalyzer.ts +26 -30
  149. package/src/peaks/util/peakOptimizer.ts +11 -15
  150. package/src/prediction/predictAllSpectra.ts +6 -8
  151. package/src/prediction/predictCarbon.ts +1 -1
  152. package/src/prediction/utils/queryByHOSE.ts +1 -1
  153. package/src/ranges/markSolventSignal.ts +121 -0
  154. package/src/ranges/rangesToACS.ts +9 -10
  155. package/src/signals/signalsJoin.ts +5 -7
  156. package/src/signals/simulation/getPauliMatrix.ts +1 -1
  157. package/src/signals/simulation/splitSpinSystem.ts +10 -12
  158. package/src/utilities/rangeFromSignal.ts +19 -11
  159. package/src/utilities/resurrectRange.ts +4 -7
  160. package/src/xyz/util/formatZone.ts +36 -0
  161. package/src/xyz/xyzAutoZonesPicking.ts +1 -35
  162. 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 treeSet from 'ml-tree-set';
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: treeSet;
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 treeSet(comparator),
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 treeSet(comparator),
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: score,
116
+ score,
117
117
  };
118
118
 
119
119
  if (store.nSolutions >= maxSolutions) {
@@ -1,4 +1,4 @@
1
- import treeSet from 'ml-tree-set';
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 treeSet(comparator),
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 treeSet(comparator),
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(data: NMRRange[] | NMRZone[]) {
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 || []) {
@@ -1,6 +1,9 @@
1
+ import { OCLMolecule } from 'cheminfo-types';
2
+
1
3
  import { NMRRange } from '../xy/NMRRange';
2
4
 
3
5
  export interface DatabaseNMREntry {
6
+ ocl?: OCLMolecule;
4
7
  smiles?: string;
5
8
  solvent: string;
6
9
  nucleus: string;
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] === false) {
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: NMRPeak1D[],
15
+ export function solventSuppression<T extends NMRPeak1D>(
16
+ peakList: T[],
17
17
  solvent: NMRSignal1D[],
18
- options: any = {},
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 { markSolventPeaks = false } = options;
22
+ const xValues = peaks.map((peak) => peak.x);
25
23
 
26
- let solventSignals = solvent; //addDummySignals(solvent);
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 solventSignals) {
30
- const solventXYPeaks = solventSignal.peaks
26
+ for (const solventSignal of solvent) {
27
+ let solventXYPeaks = solventSignal.peaks
31
28
  ? solventSignal.peaks
32
29
  : getSolventPeaks(solventSignal);
33
- sortAscending(solventXYPeaks);
30
+ solventXYPeaks.sort((a, b) => a.x - b.x);
31
+
34
32
  let upIndex = xFindClosestIndex(
35
33
  xValues,
36
- solventXYPeaks[solventXYPeaks.length - 1].x + 1,
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 = getShiftedSolventPeaks(
46
- peak,
47
- solventSignal,
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(solventSignal.delta - peak.x, 0.5);
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 = xMaxValue(amplitudeResiduals);
74
- const maxDelta = xMaxValue(deltaResiduals);
75
- const maxPosition = xMaxValue(positionResiduals);
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
- (1 - positionResiduals[i]) / maxPosition) /
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
- const shiftedSolventPeaks = getShiftedSolventPeaks(
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
- if (gain === -1) return peaks;
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: PointXY,
159
+ function getShiftedSolventPeaks<T extends PointXY>(
160
+ peak: T,
136
161
  solventSignal: any,
137
- solventXYPeaks: PointXY[],
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
- const deltaPPM = peak.x - solventSignal.delta;
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 shiftedSolventPeaks;
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 sortAscending(peaks: PointXY[]) {
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.symRank) {
65
+ if (!('symRank' in signal)) {
66
66
  throw new Error('Internal error, symRank was not calculated');
67
67
  }
68
- if (!signal.mask) throw new Error('Internal Error, mask was not added');
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
- if (peaks.length <= 1) {
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: currentIndex, active: 0 };
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 = peaks[right].intensity = avg;
535
- peaks[left].width = peaks[right].width = avgWidth;
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
- if (Math.max(diffL, diffR) === diffR) {
542
- mask[right] = false;
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
- if (peaks.length === 1) {
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
- if (peaks.length > 1) {
612
- let dxi;
613
- for (let i = Math.ceil(peaks.length / 2) - 1; i >= 0; i--) {
614
- dxi = (peaks[i].x - peaks[peaks.length - 1 - i].x) / 2.0;
615
- peaks[i].x = cs + dxi;
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] === false) {
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] === true) {
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 === false) {
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 === false) {
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
- if (Math.abs(cross.y.delta - signal.y.delta) < diagonalError) {
207
- hits++;
208
- if (updateProperties) {
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
- if (signals[i].x.delta - signals[i].y.delta > 0) {
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
- if (nucleus[0] === nucleus[1]) {
177
- return `${frequency},${frequency}`;
178
- } else {
179
- return `${frequency},${getFrequency(nucleus[1], {
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
  }
@@ -119,7 +119,7 @@ function formatSignals(predictions: Prediction[]) {
119
119
  const signal = {
120
120
  delta: delta || NaN,
121
121
  atoms,
122
- diaIDs: diaIDs,
122
+ diaIDs,
123
123
  multiplicity: 's',
124
124
  nbAtoms,
125
125
  statistic,
@@ -40,7 +40,7 @@ export function queryByHose(
40
40
  delta: res ? res[0] : null,
41
41
  atoms: [atomNumber],
42
42
  nbAtoms: 1,
43
- level: level,
43
+ level,
44
44
  statistic:
45
45
  res && res.length > 1
46
46
  ? {