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.
Files changed (199) hide show
  1. package/lib/apodization/apodization.d.ts +22 -0
  2. package/lib/apodization/apodization.js +18 -0
  3. package/lib/apodization/apodization.js.map +1 -0
  4. package/lib/apodization/applyWindow.d.ts +28 -0
  5. package/lib/apodization/applyWindow.js +20 -0
  6. package/lib/apodization/applyWindow.js.map +1 -0
  7. package/lib/apodization/compose.d.ts +23 -0
  8. package/lib/apodization/compose.js +25 -0
  9. package/lib/apodization/compose.js.map +1 -0
  10. package/lib/apodization/getFunction.d.ts +2 -0
  11. package/lib/apodization/getFunction.js +18 -0
  12. package/lib/apodization/getFunction.js.map +1 -0
  13. package/lib/apodization/shapes/WindowFunctions.d.ts +12 -0
  14. package/lib/apodization/shapes/WindowFunctions.js +3 -0
  15. package/lib/apodization/shapes/WindowFunctions.js.map +1 -0
  16. package/lib/apodization/shapes/exponential.d.ts +11 -0
  17. package/lib/apodization/shapes/exponential.js +10 -0
  18. package/lib/apodization/shapes/exponential.js.map +1 -0
  19. package/lib/apodization/shapes/lorentzToGauss.d.ts +26 -0
  20. package/lib/apodization/shapes/lorentzToGauss.js +15 -0
  21. package/lib/apodization/shapes/lorentzToGauss.js.map +1 -0
  22. package/lib/apodization/utils/getData.d.ts +4 -0
  23. package/lib/apodization/utils/getData.js +21 -0
  24. package/lib/apodization/utils/getData.js.map +1 -0
  25. package/lib/assignment/utils/buildAssignments.d.ts +2 -2
  26. package/lib/assignment/utils/exploreTreeRec.js +1 -1
  27. package/lib/assignment/utils/exploreTreeRec.js.map +1 -1
  28. package/lib/assignment/utils/getAssignment/checkIDs.d.ts +1 -1
  29. package/lib/assignment/utils/getAssignment/checkIDs.js.map +1 -1
  30. package/lib/databases/DatabaseNMREntry.d.ts +2 -0
  31. package/lib/index.d.ts +5 -1
  32. package/lib/index.js +5 -1
  33. package/lib/index.js.map +1 -1
  34. package/lib/peaks/NMRPeak1D.d.ts +0 -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 +6 -0
  39. package/lib/peaks/solventSuppression.js +158 -0
  40. package/lib/peaks/solventSuppression.js.map +1 -0
  41. package/lib/peaks/util/jAnalyzer.d.ts +1 -1
  42. package/lib/peaks/util/jAnalyzer.js +26 -31
  43. package/lib/peaks/util/jAnalyzer.js.map +1 -1
  44. package/lib/peaks/util/peakOptimizer.js +12 -16
  45. package/lib/peaks/util/peakOptimizer.js.map +1 -1
  46. package/lib/prediction/predictAllSpectra.js +7 -9
  47. package/lib/prediction/predictAllSpectra.js.map +1 -1
  48. package/lib/prediction/predictCarbon.js +1 -1
  49. package/lib/prediction/predictCarbon.js.map +1 -1
  50. package/lib/prediction/utils/queryByHOSE.js +1 -1
  51. package/lib/prediction/utils/queryByHOSE.js.map +1 -1
  52. package/lib/ranges/markSolventSignal.d.ts +3 -0
  53. package/lib/ranges/markSolventSignal.js +107 -0
  54. package/lib/ranges/markSolventSignal.js.map +1 -0
  55. package/lib/ranges/rangesToACS.js +8 -4
  56. package/lib/ranges/rangesToACS.js.map +1 -1
  57. package/lib/ranges/rangesToXY.js +27 -3
  58. package/lib/ranges/rangesToXY.js.map +1 -1
  59. package/lib/signals/addDummySignals.d.ts +2 -0
  60. package/lib/signals/addDummySignals.js +56 -0
  61. package/lib/signals/addDummySignals.js.map +1 -0
  62. package/lib/signals/hackSignalsToXY.js +2 -48
  63. package/lib/signals/hackSignalsToXY.js.map +1 -1
  64. package/lib/signals/simulation/getPauliMatrix.js.map +1 -1
  65. package/lib/signals/simulation/simulate1D.d.ts +1 -39
  66. package/lib/signals/simulation/simulate1D.js +13 -240
  67. package/lib/signals/simulation/simulate1D.js.map +1 -1
  68. package/lib/signals/simulation/simulateXYPeaks.d.ts +47 -0
  69. package/lib/signals/simulation/simulateXYPeaks.js +246 -0
  70. package/lib/signals/simulation/simulateXYPeaks.js.map +1 -0
  71. package/lib/signals/simulation/splitSpinSystem.js +11 -13
  72. package/lib/signals/simulation/splitSpinSystem.js.map +1 -1
  73. package/lib/utilities/getFrequency.d.ts +1 -1
  74. package/lib/utilities/getFrequency.js +4 -4
  75. package/lib/utilities/getFrequency.js.map +1 -1
  76. package/lib/utilities/rangeFromSignal.d.ts +9 -5
  77. package/lib/utilities/rangeFromSignal.js +7 -7
  78. package/lib/utilities/rangeFromSignal.js.map +1 -1
  79. package/lib/utilities/resurrectRange.js +4 -7
  80. package/lib/utilities/resurrectRange.js.map +1 -1
  81. package/lib/xyz/util/formatZone.d.ts +3 -0
  82. package/lib/xyz/util/formatZone.js +38 -0
  83. package/lib/xyz/util/formatZone.js.map +1 -0
  84. package/lib/xyz/xyzAutoZonesPicking.d.ts +1 -2
  85. package/lib/xyz/xyzAutoZonesPicking.js +2 -34
  86. package/lib/xyz/xyzAutoZonesPicking.js.map +1 -1
  87. package/lib/xyz/xyzJResAnalyzer.d.ts +6 -1
  88. package/lib/xyz/xyzJResAnalyzer.js +9 -8
  89. package/lib/xyz/xyzJResAnalyzer.js.map +1 -1
  90. package/lib-esm/apodization/apodization.js +14 -0
  91. package/lib-esm/apodization/apodization.js.map +1 -0
  92. package/lib-esm/apodization/applyWindow.js +16 -0
  93. package/lib-esm/apodization/applyWindow.js.map +1 -0
  94. package/lib-esm/apodization/compose.js +21 -0
  95. package/lib-esm/apodization/compose.js.map +1 -0
  96. package/lib-esm/apodization/getFunction.js +14 -0
  97. package/lib-esm/apodization/getFunction.js.map +1 -0
  98. package/lib-esm/apodization/shapes/WindowFunctions.js +2 -0
  99. package/lib-esm/apodization/shapes/WindowFunctions.js.map +1 -0
  100. package/lib-esm/apodization/shapes/exponential.js +6 -0
  101. package/lib-esm/apodization/shapes/exponential.js.map +1 -0
  102. package/lib-esm/apodization/shapes/lorentzToGauss.js +11 -0
  103. package/lib-esm/apodization/shapes/lorentzToGauss.js.map +1 -0
  104. package/lib-esm/apodization/utils/getData.js +17 -0
  105. package/lib-esm/apodization/utils/getData.js.map +1 -0
  106. package/lib-esm/assignment/utils/buildAssignments.js +3 -3
  107. package/lib-esm/assignment/utils/exploreTreeRec.js +1 -1
  108. package/lib-esm/assignment/utils/exploreTreeRec.js.map +1 -1
  109. package/lib-esm/assignment/utils/getAssignment/buildAssignments.js +3 -3
  110. package/lib-esm/assignment/utils/getAssignment/checkIDs.js.map +1 -1
  111. package/lib-esm/index.js +5 -1
  112. package/lib-esm/index.js.map +1 -1
  113. package/lib-esm/peaks/peaksToRanges.js +2 -2
  114. package/lib-esm/peaks/peaksToRanges.js.map +1 -1
  115. package/lib-esm/peaks/solventSuppression.js +154 -0
  116. package/lib-esm/peaks/solventSuppression.js.map +1 -0
  117. package/lib-esm/peaks/util/jAnalyzer.js +26 -31
  118. package/lib-esm/peaks/util/jAnalyzer.js.map +1 -1
  119. package/lib-esm/peaks/util/peakOptimizer.js +12 -16
  120. package/lib-esm/peaks/util/peakOptimizer.js.map +1 -1
  121. package/lib-esm/prediction/predictAllSpectra.js +7 -9
  122. package/lib-esm/prediction/predictAllSpectra.js.map +1 -1
  123. package/lib-esm/prediction/predictCarbon.js +1 -1
  124. package/lib-esm/prediction/predictCarbon.js.map +1 -1
  125. package/lib-esm/prediction/utils/queryByHOSE.js +1 -1
  126. package/lib-esm/prediction/utils/queryByHOSE.js.map +1 -1
  127. package/lib-esm/ranges/markSolventSignal.js +100 -0
  128. package/lib-esm/ranges/markSolventSignal.js.map +1 -0
  129. package/lib-esm/ranges/rangesToACS.js +8 -4
  130. package/lib-esm/ranges/rangesToACS.js.map +1 -1
  131. package/lib-esm/ranges/rangesToXY.js +27 -3
  132. package/lib-esm/ranges/rangesToXY.js.map +1 -1
  133. package/lib-esm/signals/addDummySignals.js +52 -0
  134. package/lib-esm/signals/addDummySignals.js.map +1 -0
  135. package/lib-esm/signals/hackSignalsToXY.js +2 -48
  136. package/lib-esm/signals/hackSignalsToXY.js.map +1 -1
  137. package/lib-esm/signals/simulation/getPauliMatrix.js.map +1 -1
  138. package/lib-esm/signals/simulation/simulate1D.js +14 -238
  139. package/lib-esm/signals/simulation/simulate1D.js.map +1 -1
  140. package/lib-esm/signals/simulation/simulateXYPeaks.js +239 -0
  141. package/lib-esm/signals/simulation/simulateXYPeaks.js.map +1 -0
  142. package/lib-esm/signals/simulation/splitSpinSystem.js +11 -13
  143. package/lib-esm/signals/simulation/splitSpinSystem.js.map +1 -1
  144. package/lib-esm/utilities/getFrequency.js +1 -1
  145. package/lib-esm/utilities/getFrequency.js.map +1 -1
  146. package/lib-esm/utilities/rangeFromSignal.js +7 -7
  147. package/lib-esm/utilities/rangeFromSignal.js.map +1 -1
  148. package/lib-esm/utilities/resurrectRange.js +4 -7
  149. package/lib-esm/utilities/resurrectRange.js.map +1 -1
  150. package/lib-esm/xyz/util/formatZone.js +34 -0
  151. package/lib-esm/xyz/util/formatZone.js.map +1 -0
  152. package/lib-esm/xyz/xyzAutoZonesPicking.js +1 -33
  153. package/lib-esm/xyz/xyzAutoZonesPicking.js.map +1 -1
  154. package/lib-esm/xyz/xyzJResAnalyzer.js +9 -8
  155. package/lib-esm/xyz/xyzJResAnalyzer.js.map +1 -1
  156. package/package.json +16 -14
  157. package/src/apodization/apodization.ts +34 -0
  158. package/src/apodization/applyWindow.ts +51 -0
  159. package/src/apodization/compose.ts +47 -0
  160. package/src/apodization/getFunction.ts +15 -0
  161. package/src/apodization/shapes/WindowFunctions.ts +14 -0
  162. package/src/apodization/shapes/exponential.ts +16 -0
  163. package/src/apodization/shapes/lorentzToGauss.ts +41 -0
  164. package/src/apodization/utils/getData.ts +15 -0
  165. package/src/assignment/utils/buildAssignments.ts +4 -4
  166. package/src/assignment/utils/exploreTreeRec.ts +1 -1
  167. package/src/assignment/utils/getAssignment/buildAssignments.ts +3 -3
  168. package/src/assignment/utils/getAssignment/checkIDs.ts +1 -1
  169. package/src/databases/DatabaseNMREntry.ts +3 -0
  170. package/src/index.ts +7 -1
  171. package/src/peaks/NMRPeak1D.ts +0 -1
  172. package/src/peaks/peaksToRanges.ts +2 -2
  173. package/src/peaks/solventSuppression.ts +214 -0
  174. package/src/peaks/util/jAnalyzer.ts +27 -31
  175. package/src/peaks/util/peakOptimizer.ts +11 -15
  176. package/src/prediction/predictAllSpectra.ts +6 -8
  177. package/src/prediction/predictCarbon.ts +1 -1
  178. package/src/prediction/utils/queryByHOSE.ts +1 -1
  179. package/src/ranges/markSolventSignal.ts +121 -0
  180. package/src/ranges/rangesToACS.ts +9 -10
  181. package/src/ranges/rangesToXY.ts +33 -4
  182. package/src/signals/addDummySignals.ts +77 -0
  183. package/src/signals/hackSignalsToXY.ts +2 -72
  184. package/src/signals/simulation/getPauliMatrix.ts +1 -1
  185. package/src/signals/simulation/simulate1D.ts +14 -319
  186. package/src/signals/simulation/simulateXYPeaks.ts +332 -0
  187. package/src/signals/simulation/splitSpinSystem.ts +10 -12
  188. package/src/utilities/getFrequency.ts +1 -1
  189. package/src/utilities/rangeFromSignal.ts +19 -11
  190. package/src/utilities/resurrectRange.ts +4 -7
  191. package/src/xyz/util/formatZone.ts +36 -0
  192. package/src/xyz/xyzAutoZonesPicking.ts +1 -35
  193. package/src/xyz/xyzJResAnalyzer.ts +14 -7
  194. package/lib/constants/gyromagneticRatio.d.ts +0 -6
  195. package/lib/constants/gyromagneticRatio.js +0 -26
  196. package/lib/constants/gyromagneticRatio.js.map +0 -1
  197. package/lib-esm/constants/gyromagneticRatio.js +0 -23
  198. package/lib-esm/constants/gyromagneticRatio.js.map +0 -1
  199. package/src/constants/gyromagneticRatio.ts +0 -49
@@ -49,13 +49,21 @@ function checkForSignals(
49
49
  if (!range.signals) throw new Error('range has not signals');
50
50
  }
51
51
  }
52
+
53
+ const defaultFromTo = (nucleus = '') => {
54
+ switch (nucleus.toUpperCase()) {
55
+ case '13C':
56
+ return { from: -5, to: 206 };
57
+ default:
58
+ return { from: -0.5, to: 10.5 };
59
+ }
60
+ };
61
+
52
62
  export function rangesToXY(ranges: NMRRange[], options: any = {}) {
53
63
  checkForSignals(ranges);
54
64
  let {
55
65
  frequency = 400,
56
66
  lineWidth = 1,
57
- from = 0,
58
- to = 10,
59
67
  nbPoints = 16 * 1024,
60
68
  shape = { kind: 'gaussian' },
61
69
  } = options;
@@ -66,9 +74,10 @@ export function rangesToXY(ranges: NMRRange[], options: any = {}) {
66
74
  }
67
75
  };
68
76
 
77
+ const { from, to } = getFromTo(ranges, options);
69
78
  const spectrumOptions = {
70
- from,
71
79
  to,
80
+ from,
72
81
  nbPoints,
73
82
  shape,
74
83
  lineWidth,
@@ -139,7 +148,7 @@ function peaksOfMultiplet(delta: number, options: any) {
139
148
  const {
140
149
  frequency,
141
150
  lineWidth,
142
- intensities = [1, 2, 5, 4, 5, 3, 4, 2, 1],
151
+ intensities = [1, 2, 5, 4, 5, 7, 5, 4, 5, 2, 1],
143
152
  } = options;
144
153
 
145
154
  const lineWidthPpm = lineWidth / frequency;
@@ -182,3 +191,23 @@ function normalizeSpectrum(
182
191
  }
183
192
  }
184
193
  }
194
+
195
+ function getFromTo(ranges: NMRRange[], options: any) {
196
+ const { from: defaultFrom, to: defaultTo } = defaultFromTo(options.nucleus);
197
+
198
+ let rangesFrom = Number.MAX_SAFE_INTEGER;
199
+ let rangesTo = Number.MIN_SAFE_INTEGER;
200
+ for (const range of ranges) {
201
+ for (const signal of range.signals || []) {
202
+ if (rangesFrom > signal.delta) rangesFrom = signal.delta;
203
+ if (rangesTo < signal.delta) rangesTo = signal.delta;
204
+ }
205
+ }
206
+
207
+ const {
208
+ from = Math.min(rangesFrom - 0.5, defaultFrom),
209
+ to = Math.max(rangesTo + 0.5, defaultTo),
210
+ } = options;
211
+
212
+ return { from, to };
213
+ }
@@ -0,0 +1,77 @@
1
+ import { couplingPatterns } from '../constants/couplingPatterns';
2
+
3
+ import { NMRSignal1D } from './NMRSignal1D';
4
+ import type { Jcoupling } from './jcoupling';
5
+
6
+ export function addDummySignals(signals: NMRSignal1D[]) {
7
+ let newSignals: NMRSignal1D[] = JSON.parse(JSON.stringify(signals));
8
+
9
+ signals.forEach((signal, s) => {
10
+ const { js: jCouplings = [], atoms: signalAssignment = [s] } = signal;
11
+
12
+ let { newCouplings, tempSignals } = checkCouplings(
13
+ jCouplings,
14
+ newSignals,
15
+ signalAssignment,
16
+ );
17
+
18
+ if (tempSignals.length > 0) newSignals.push(...tempSignals);
19
+
20
+ newSignals[s].js = newCouplings;
21
+ newSignals[s].atoms = signalAssignment;
22
+ });
23
+
24
+ return newSignals.sort((a, b) => a.delta - b.delta);
25
+ }
26
+
27
+ function checkCouplings(
28
+ jCouplings: Jcoupling[],
29
+ signals: NMRSignal1D[],
30
+ signalAssignment: number[],
31
+ ) {
32
+ let newSignalAssignment = signals.length - 1;
33
+ let tempSignals: NMRSignal1D[] = [];
34
+ const newCouplings = jCouplings.reduce<Jcoupling[]>(
35
+ (newCouplings, jCoupling) => {
36
+ const { atoms = [], multiplicity, coupling } = jCoupling;
37
+ if (atoms.length === 0) {
38
+ if (coupling && multiplicity) {
39
+ let tempCouplings: Jcoupling[] = [];
40
+ const nbLinks = couplingPatterns.indexOf(multiplicity);
41
+ for (let i = 0; i < nbLinks; i++) {
42
+ newSignalAssignment++;
43
+ tempCouplings.push({
44
+ coupling,
45
+ atoms: [newSignalAssignment],
46
+ });
47
+ tempSignals.push(
48
+ formatSignal(coupling, [newSignalAssignment], signalAssignment),
49
+ );
50
+ }
51
+ } else {
52
+ newCouplings.push(jCoupling);
53
+ }
54
+ }
55
+ return newCouplings;
56
+ },
57
+ [],
58
+ );
59
+ return { newCouplings, tempSignals };
60
+ }
61
+
62
+ function formatSignal(
63
+ coupling: number,
64
+ newSignalAssignment: number[],
65
+ signalAssignment: number[],
66
+ ) {
67
+ return {
68
+ delta: 100000,
69
+ atoms: newSignalAssignment,
70
+ js: [
71
+ {
72
+ coupling,
73
+ atoms: signalAssignment,
74
+ },
75
+ ],
76
+ };
77
+ }
@@ -1,7 +1,5 @@
1
- import { couplingPatterns } from '../constants/couplingPatterns';
2
-
3
1
  import type { NMRSignal1D } from './NMRSignal1D';
4
- import type { Jcoupling } from './jcoupling';
2
+ import { addDummySignals } from './addDummySignals';
5
3
  import { OptionsSignalsToXY, signalsToXY } from './signalsToXY';
6
4
 
7
5
  /**
@@ -13,74 +11,6 @@ export function hackSignalsToXY(
13
11
  signals: NMRSignal1D[],
14
12
  options: OptionsSignalsToXY = {},
15
13
  ) {
16
- let newSignals = JSON.parse(JSON.stringify(signals));
17
-
18
- signals.forEach((signal, s) => {
19
- const { js: jCouplings = [], atoms: signalAssignment = [s] } = signal;
20
-
21
- let { newCouplings, tempSignals } = checkCouplings(
22
- jCouplings,
23
- newSignals,
24
- signalAssignment,
25
- );
26
-
27
- if (tempSignals.length > 0) newSignals.push(...tempSignals);
28
-
29
- newSignals[s].js = newCouplings;
30
- newSignals[s].atoms = signalAssignment;
31
- });
32
-
14
+ let newSignals = addDummySignals(signals);
33
15
  return signalsToXY(newSignals, options);
34
16
  }
35
-
36
- function checkCouplings(
37
- jCouplings: Jcoupling[],
38
- signals: NMRSignal1D[],
39
- signalAssignment: number[],
40
- ) {
41
- let newSignalAssignment = signals.length - 1;
42
- let tempSignals: NMRSignal1D[] = [];
43
- const newCouplings = jCouplings.reduce<Jcoupling[]>(
44
- (newCouplings, jCoupling) => {
45
- const { atoms = [], multiplicity, coupling } = jCoupling;
46
- if (atoms.length === 0) {
47
- if (coupling && multiplicity) {
48
- let tempCouplings: Jcoupling[] = [];
49
- const nbLinks = couplingPatterns.indexOf(multiplicity);
50
- for (let i = 0; i < nbLinks; i++) {
51
- newSignalAssignment++;
52
- tempCouplings.push({
53
- coupling,
54
- atoms: [newSignalAssignment],
55
- });
56
- tempSignals.push(
57
- formatSignal(coupling, [newSignalAssignment], signalAssignment),
58
- );
59
- }
60
- } else {
61
- newCouplings.push(jCoupling);
62
- }
63
- }
64
- return newCouplings;
65
- },
66
- [],
67
- );
68
- return { newCouplings, tempSignals };
69
- }
70
-
71
- function formatSignal(
72
- coupling: number,
73
- newSignalAssignment: number[],
74
- signalAssignment: number[],
75
- ) {
76
- return {
77
- delta: 100000,
78
- atoms: newSignalAssignment,
79
- js: [
80
- {
81
- coupling,
82
- atoms: signalAssignment,
83
- },
84
- ],
85
- };
86
- }
@@ -2,7 +2,7 @@ import { SparseMatrix } from 'ml-sparse-matrix';
2
2
 
3
3
  function createPauli(mult: number) {
4
4
  const spin = (mult - 1) / 2;
5
- const prjs = new Array(mult);
5
+ const prjs: number[] = new Array(mult);
6
6
  const temp = new Array(mult);
7
7
  for (let i = 0; i < mult; i++) {
8
8
  prjs[i] = mult - 1 - i - spin;
@@ -1,54 +1,10 @@
1
- import binarySearch from 'binary-search';
2
1
  import { DataXY } from 'cheminfo-types';
3
- import { Matrix, EVD } from 'ml-matrix';
4
- import type { Matrix as MatrixClassType } from 'ml-matrix';
5
- import type { Shape1D } from 'ml-peak-shape-generator';
6
- import { SparseMatrix } from 'ml-sparse-matrix';
7
- import { SpectrumGenerator } from 'spectrum-generator';
2
+ import { generateSpectrum } from 'spectrum-generator';
8
3
 
9
4
  import type { SpinSystem } from '../spinSystem';
10
5
 
11
- import getPauliMatrix from './getPauliMatrix';
12
-
13
- const smallValue = 1e-2;
14
-
15
- interface Simulate1DOptions {
16
- /**
17
- * The linewidth of the output spectrum, expresed in Hz.
18
- * @default 1
19
- */
20
- lineWidth?: number;
21
- /**
22
- * Maximum number of atoms on each cluster that can be considered to be simulated together. It affects the the quality and speed of the simulation.
23
- * @default 8
24
- */
25
- maxClusterSize?: number;
26
- /**
27
- * The frequency in Mhz of the fake spectrometer that records the spectrum.
28
- * @default 400
29
- */
30
- frequency?: number;
31
- /**
32
- * The low limit of the ordinate variable.
33
- * @default 0
34
- */
35
- from?: number;
36
- /**
37
- * The upper limit of the ordinate variable.
38
- * @default 10
39
- */
40
- to?: number;
41
- /**
42
- * Number of points of the output spectrum.
43
- * @default 16K
44
- */
45
- nbPoints?: number;
46
- /**
47
- * Shape options
48
- * @default {kind:'gaussian'}
49
- */
50
- shape?: Shape1D;
51
- }
6
+ import type { Simulate1DOptions } from './simulateXYPeaks';
7
+ import { simulateXYPeaks } from './simulateXYPeaks';
52
8
 
53
9
  /**
54
10
  * This function simulates a one dimensional nmr spectrum. This function returns an array containing the relative intensities of the spectrum in the specified simulation window (from-to).
@@ -63,7 +19,6 @@ export default function simulate1D(
63
19
  ): DataXY {
64
20
  let {
65
21
  lineWidth = 1,
66
- maxClusterSize = 8,
67
22
  frequency: frequencyMHz = 400,
68
23
  from = 0,
69
24
  to = 10,
@@ -75,277 +30,17 @@ export default function simulate1D(
75
30
 
76
31
  let peakWidth = lineWidth / frequencyMHz;
77
32
 
78
- let spectrumGenerator = new SpectrumGenerator({
79
- from,
80
- to,
81
- nbPoints,
82
- shape,
83
- peakWidthFct: () => peakWidth,
84
- });
85
-
86
- const chemicalShifts = spinSystem.chemicalShifts.slice();
87
- for (let i = 0; i < chemicalShifts.length; i++) {
88
- chemicalShifts[i] = chemicalShifts[i] * frequencyMHz;
89
- }
90
-
91
- const multiplicity = spinSystem.multiplicity;
92
- for (const cluster of spinSystem.clusters) {
93
- let clusterFake = cluster.map((cluster) =>
94
- cluster < 0 ? -cluster - 1 : cluster,
95
- );
96
-
97
- let weight = 1;
98
- let sumI = 0;
99
- let frequencies: number[] = [];
100
- let intensities: number[] = [];
101
- if (cluster.length > maxClusterSize) {
102
- // This is a single spin, but the cluster exceeds the maxClusterSize criteria
103
- // we use the simple multiplicity algorithm
104
- // Add the central peak. It will be split with every single J coupling.
105
- let index = 0;
106
- while (cluster[index++] < 0);
107
- index = cluster[index - 1];
108
- frequencies.push(-chemicalShifts[index]);
109
- for (let i = 0; i < cluster.length; i++) {
110
- if (cluster[i] < 0) {
111
- let jc = spinSystem.couplingConstants.get(index, clusterFake[i]) / 2;
112
- let currentSize = frequencies.length;
113
- for (let j = 0; j < currentSize; j++) {
114
- frequencies.push(frequencies[j] + jc);
115
- frequencies[j] -= jc;
116
- }
117
- }
118
- }
119
-
120
- frequencies.sort((a, b) => a - b);
121
- sumI = frequencies.length;
122
- weight = 1;
123
-
124
- for (let i = 0; i < sumI; i++) {
125
- intensities.push(1);
126
- }
127
- } else {
128
- const hamiltonian = getHamiltonian(
129
- chemicalShifts,
130
- spinSystem.couplingConstants,
131
- multiplicity,
132
- spinSystem.connectivity,
133
- clusterFake,
134
- );
135
- const hamSize = hamiltonian.rows;
136
- // TODO: add support for sparse matrix in matrix types.
137
- // @ts-expect-error sparse matrix not supported
138
- const evd = new EVD(hamiltonian);
139
- const V = evd.eigenvectorMatrix;
140
- const diagB = evd.realEigenvalues;
141
- const assignmentMatrix = new SparseMatrix(hamSize, hamSize);
142
- const multLen = cluster.length;
143
- weight = 0;
144
- for (let n = 0; n < multLen; n++) {
145
- const L = getPauliMatrix(multiplicity[clusterFake[n]]);
146
-
147
- let temp = 1;
148
- for (let j = 0; j < n; j++) {
149
- temp *= multiplicity[clusterFake[j]];
150
- }
151
- const A = SparseMatrix.eye(temp);
152
-
153
- temp = 1;
154
- for (let j = n + 1; j < multLen; j++) {
155
- temp *= multiplicity[clusterFake[j]];
156
- }
157
- const B = SparseMatrix.eye(temp);
158
- const tempMat = A.kroneckerProduct(L.m).kroneckerProduct(B);
159
- if (cluster[n] >= 0) {
160
- assignmentMatrix.add(tempMat.mul(cluster[n] + 1));
161
- weight++;
162
- } else {
163
- assignmentMatrix.add(tempMat.mul(cluster[n]));
164
- }
165
- }
33
+ const xyPeaks = simulateXYPeaks(spinSystem, options);
166
34
 
167
- let rhoip = Matrix.zeros(hamSize, hamSize);
168
- assignmentMatrix.forEachNonZero((i, j, v) => {
169
- if (v > 0) {
170
- for (let k = 0; k < V.columns; k++) {
171
- let element = V.get(j, k);
172
- if (element !== 0) {
173
- rhoip.set(i, k, rhoip.get(i, k) + element);
174
- }
175
- }
176
- }
177
- return v;
178
- });
179
-
180
- let rhoip2 = rhoip.clone();
181
- assignmentMatrix.forEachNonZero((i: number, j: number, v: number) => {
182
- if (v < 0) {
183
- for (let k = 0; k < V.columns; k++) {
184
- let element = V.get(j, k);
185
- if (element !== 0) {
186
- rhoip2.set(i, k, rhoip2.get(i, k) + element);
187
- }
188
- }
189
- }
190
- return v;
191
- });
192
- const tV = V.transpose();
193
-
194
- rhoip = tV.mmul(rhoip);
195
- const sparseRhoip = new SparseMatrix(rhoip.to2DArray(), {
196
- threshold: smallValue,
197
- });
198
- triuTimesAbs(sparseRhoip, smallValue);
199
-
200
- rhoip2 = tV.mmul(rhoip2);
201
- const sparseRhoip2 = new SparseMatrix(rhoip2.to2DArray(), {
202
- threshold: smallValue,
203
- });
204
- sparseRhoip2.forEachNonZero((i, j, v) => {
205
- return v;
206
- });
207
- triuTimesAbs(sparseRhoip2, smallValue);
208
- sparseRhoip2.forEachNonZero((i, j, v) => {
209
- let val = rhoip.get(i, j);
210
- val = Math.min(Math.abs(val), Math.abs(v));
211
- val *= val;
212
-
213
- sumI += val;
214
- let valFreq = diagB[i] - diagB[j];
215
- let insertIn = binarySearch(
216
- frequencies,
217
- valFreq,
218
- (a: number, b: number) => a - b,
219
- );
220
- if (insertIn < 0) {
221
- frequencies.splice(-1 - insertIn, 0, valFreq);
222
- intensities.splice(-1 - insertIn, 0, val);
223
- } else {
224
- intensities[insertIn] += val;
225
- }
226
- });
227
- }
228
-
229
- const numFreq = frequencies.length;
230
-
231
- if (numFreq > 0) {
232
- weight /= sumI;
233
- const diff = lineWidth / 64;
234
- let valFreq = frequencies[0];
235
- let inte = intensities[0];
236
- let count = 1;
237
- for (let i = 1; i < numFreq; i++) {
238
- if (Math.abs(frequencies[i] - valFreq / count) < diff) {
239
- inte += intensities[i];
240
- valFreq += frequencies[i];
241
- count++;
242
- } else {
243
- spectrumGenerator.addPeak({
244
- x: -valFreq / count / frequencyMHz,
245
- y: inte * weight,
246
- });
247
- valFreq = frequencies[i];
248
- inte = intensities[i];
249
- count = 1;
250
- }
251
- }
252
-
253
- spectrumGenerator.addPeak({
254
- x: -valFreq / count / frequencyMHz,
255
- y: inte * weight,
256
- });
257
- }
258
- }
259
- return spectrumGenerator.getSpectrum();
260
- }
261
-
262
- function triuTimesAbs(A: SparseMatrix, val: number) {
263
- A.forEachNonZero((i, j, v) => {
264
- if (i > j) return 0;
265
- if (Math.abs(v) <= val) return 0;
266
- return v;
35
+ return generateSpectrum(xyPeaks, {
36
+ generator: {
37
+ from,
38
+ to,
39
+ nbPoints,
40
+ },
41
+ peakOptions: {
42
+ shape,
43
+ width: peakWidth,
44
+ },
267
45
  });
268
46
  }
269
- /**
270
- * Create a hamiltonian matrix for the given spinsystem
271
- * @param {Array} chemicalShifts - An array containing the chemical shift in Hz
272
- * @param {Array} couplingConstants - An array containing the coupling constants in Hz
273
- * @param {Array} multiplicity - An array specifiying the multiplicities of each scalar coupling
274
- * @param {Array} conMatrix - A one step connectivity matrix for the given spin system
275
- * @param {Array} cluster - An binary array specifiying the spins to be considered for this hamiltonial
276
- * @return {object}
277
- */
278
- function getHamiltonian(
279
- chemicalShifts: number[],
280
- couplingConstants: MatrixClassType,
281
- multiplicity: number[],
282
- conMatrix: MatrixClassType,
283
- cluster: number[],
284
- ) {
285
- let hamSize = 1;
286
- for (const element of cluster) {
287
- hamSize *= multiplicity[element];
288
- }
289
-
290
- const clusterHam = new SparseMatrix(hamSize, hamSize);
291
-
292
- for (let pos = 0; pos < cluster.length; pos++) {
293
- let n = cluster[pos];
294
-
295
- const L = getPauliMatrix(multiplicity[n]);
296
-
297
- let A1, B1;
298
- let temp = 1;
299
- for (let i = 0; i < pos; i++) {
300
- temp *= multiplicity[cluster[i]];
301
- }
302
- A1 = SparseMatrix.eye(temp);
303
-
304
- temp = 1;
305
- for (let i = pos + 1; i < cluster.length; i++) {
306
- temp *= multiplicity[cluster[i]];
307
- }
308
- B1 = SparseMatrix.eye(temp);
309
-
310
- const alpha = chemicalShifts[n];
311
- const kronProd = A1.kroneckerProduct(L.z).kroneckerProduct(B1);
312
- clusterHam.add(kronProd.mul(alpha));
313
- for (let pos2 = 0; pos2 < cluster.length; pos2++) {
314
- const k = cluster[pos2];
315
- if (conMatrix.get(n, k) === 1) {
316
- const S = getPauliMatrix(multiplicity[k]);
317
-
318
- let A2, B2;
319
- let temp = 1;
320
- for (let i = 0; i < pos2; i++) {
321
- temp *= multiplicity[cluster[i]];
322
- }
323
- A2 = SparseMatrix.eye(temp);
324
-
325
- temp = 1;
326
- for (let i = pos2 + 1; i < cluster.length; i++) {
327
- temp *= multiplicity[cluster[i]];
328
- }
329
- B2 = SparseMatrix.eye(temp);
330
-
331
- const kron1 = A1.kroneckerProduct(L.x)
332
- .kroneckerProduct(B1)
333
- .mmul(A2.kroneckerProduct(S.x).kroneckerProduct(B2));
334
- kron1.add(
335
- A1.kroneckerProduct(L.y)
336
- .kroneckerProduct(B1)
337
- .mul(-1)
338
- .mmul(A2.kroneckerProduct(S.y).kroneckerProduct(B2)),
339
- );
340
- kron1.add(
341
- A1.kroneckerProduct(L.z)
342
- .kroneckerProduct(B1)
343
- .mmul(A2.kroneckerProduct(S.z).kroneckerProduct(B2)),
344
- );
345
-
346
- clusterHam.add(kron1.mul(couplingConstants.get(n, k) / 2));
347
- }
348
- }
349
- }
350
- return clusterHam;
351
- }