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

spectrum-generator

Package Overview
Dependencies
Maintainers
6
Versions
56
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

spectrum-generator - npm Package Compare versions

Comparing version 3.2.2 to 4.0.0

4

History.md

@@ -0,1 +1,5 @@

# [4.0.0](https://github.com/cheminfo/spectrum-generator/compare/v3.2.2...v4.0.0) (2020-03-18)
## [3.2.2](https://github.com/cheminfo/spectrum-generator/compare/v3.2.1...v3.2.2) (2020-03-13)

@@ -2,0 +6,0 @@

146

lib/index.js

@@ -67,7 +67,6 @@ 'use strict';

{
start: 0,
end: 1000,
pointsPerUnit: 5,
from: 0,
to: 1000,
nbPoints: 10001,
peakWidthFct: () => 5,
maxSize: 1e7,
shape: {

@@ -83,7 +82,7 @@ kind: 'gaussian',

);
this.start = options.start;
this.end = options.end;
this.pointsPerUnit = options.pointsPerUnit;
this.from = options.from;
this.to = options.to;
this.nbPoints = options.nbPoints;
this.interval = (this.to - this.from) / (this.nbPoints - 1);
this.peakWidthFct = options.peakWidthFct;
this.maxSize = options.maxSize;
this.maxPeakHeight = Number.MIN_SAFE_INTEGER;

@@ -94,11 +93,11 @@ this.shape = mlPeakShapeGenerator.getShape(options.shape.kind, options.shape.options);

});
this.shapeFactor = this.shape.data.length / this.shape.fwhm;
this.shapeFactor = (this.shape.data.length - 1) / this.shape.fwhm;
this.shapeLength = this.shape.data.length;
this.shapeHalfLength = Math.floor(this.shape.data.length / 2);
assertNumber(this.from, 'from');
assertNumber(this.to, 'to');
assertInteger(this.nbPoints, 'nbPoints');
assertInteger(this.start, 'start');
assertInteger(this.end, 'end');
assertInteger(this.pointsPerUnit, 'pointsPerUnit');
assertInteger(this.maxSize, 'maxSize');
if (this.end <= this.start) {
throw new RangeError('end option must be larger than start');
if (this.to <= this.from) {
throw new RangeError('to option must be larger than from');
}

@@ -113,6 +112,2 @@

get size() {
return (this.end - this.start) * this.pointsPerUnit + 1;
}
addPeaks(peaks) {

@@ -129,11 +124,26 @@ if (!Array.isArray(peaks)) {

addPeak(peak, options = {}) {
if (!Array.isArray(peak) || peak.length !== 2) {
throw new Error('peak must be an array with two values');
if (
typeof peak !== 'object' ||
(peak.length !== 2 && (peak.x === undefined || peak.y === undefined))
) {
throw new Error(
'peak must be an array with two values or an object with {x,y}',
);
}
let xPosition;
let intensity;
if (Array.isArray(peak)) {
[xPosition, intensity] = peak;
} else {
xPosition = peak.x;
intensity = peak.y;
}
const [value, intensity] = peak;
if (intensity > this.maxPeakHeight) this.maxPeakHeight = intensity;
let { width = this.peakWidthFct(value), widthLeft, widthRight } = options;
let {
width = this.peakWidthFct(xPosition),
widthLeft,
widthRight,
} = options;

@@ -143,40 +153,36 @@ if (!widthLeft) widthLeft = width;

const firstValue = value - (widthLeft / 2) * this.shapeFactor;
const lastValue = value + (widthRight / 2) * this.shapeFactor;
const firstValue = xPosition - (widthLeft / 2) * this.shapeFactor;
const lastValue = xPosition + (widthRight / 2) * this.shapeFactor;
const firstPoint = Math.floor(firstValue * this.pointsPerUnit);
const lastPoint = Math.ceil(lastValue * this.pointsPerUnit);
const middlePoint = value * this.pointsPerUnit;
const firstPoint = Math.max(
0,
Math.floor((firstValue - this.from) / this.interval),
);
const lastPoint = Math.min(
this.nbPoints - 1,
Math.ceil((lastValue - this.from) / this.interval),
);
const middlePoint = (xPosition - this.from) / this.interval;
// PEAK SHAPE MAY BE ASYMETRC (widthLeft and widthRight) !
// PEAK SHAPE MAY BE ASYMMETRC (widthLeft and widthRight) !
// we calculate the left part of the shape
for (let j = firstPoint; j < middlePoint; j++) {
let index = j - this.start * this.pointsPerUnit;
for (let index = firstPoint; index < middlePoint; index++) {
let ratio = ((xPosition - this.data.x[index]) / widthLeft) * 2;
let shapeIndex = Math.round(
this.shapeHalfLength - (ratio * this.shape.fwhm) / 2,
);
if (index >= 0 && index < this.size) {
let shapeIndex = Math.ceil(
((this.shape.fwhm / widthLeft) * (j - middlePoint)) /
this.pointsPerUnit +
(this.shapeFactor * this.shape.fwhm - 1) / 2,
);
if (shapeIndex >= 0 && shapeIndex < this.shape.data.length) {
this.data.y[index] += this.shape.data[shapeIndex] * intensity;
}
if (shapeIndex >= 0 && shapeIndex < this.shapeHalfLength) {
this.data.y[index] += this.shape.data[shapeIndex] * intensity;
}
}
// we calculate the right part of the gaussian
for (let j = Math.ceil(middlePoint); j <= lastPoint; j++) {
let index = j - this.start * this.pointsPerUnit;
for (let index = Math.ceil(middlePoint); index <= lastPoint; index++) {
let ratio = ((this.data.x[index] - xPosition) / widthRight) * 2;
if (index >= 0 && index < this.size) {
let shapeIndex = Math.floor(
((this.shape.fwhm / widthRight) * (j - middlePoint)) /
this.pointsPerUnit +
(this.shapeFactor * this.shape.fwhm - 1) / 2,
);
if (shapeIndex >= 0 && shapeIndex < this.shape.data.length) {
this.data.y[index] += this.shape.data[shapeIndex] * intensity;
}
let shapeIndex = Math.round(
this.shapeHalfLength - (ratio * this.shape.fwhm) / 2,
);
if (shapeIndex >= 0 && shapeIndex <= this.shapeHalfLength) {
this.data.y[index] += this.shape.data[shapeIndex] * intensity;
}

@@ -226,27 +232,11 @@ }

reset() {
if (this.size > this.maxSize) {
throw new Error(
`Generated array has size ${this.size} larger than maxSize: ${this.maxSize}`,
);
}
const spectrum = (this.data = {
x: [],
y: new Array(this.size).fill(0),
x: new Float64Array(this.nbPoints),
y: new Float64Array(this.nbPoints),
});
const interval = 1 / this.pointsPerUnit;
const js = [];
for (let j = 0; j < this.pointsPerUnit; j++) {
js.push(j * interval);
for (let i = 0; i < this.nbPoints; i++) {
spectrum.x[i] = this.from + i * this.interval;
}
for (let i = this.start; i < this.end; i++) {
for (let j = 0; j < this.pointsPerUnit; j++) {
spectrum.x.push(i + js[j]);
}
}
spectrum.x.push(this.end);
return this;

@@ -262,2 +252,8 @@ }

function assertNumber(value, name) {
if (!Number.isFinite(value)) {
throw new TypeError(`${name} option must be a number`);
}
}
function generateSpectrum(peaks, options = {}) {

@@ -264,0 +260,0 @@ const generator = new SpectrumGenerator(options);

{
"name": "spectrum-generator",
"version": "3.2.2",
"version": "4.0.0",
"description": "generate a spectrum from discrete peaks",

@@ -5,0 +5,0 @@ "main": "lib/index.js",

@@ -10,6 +10,5 @@ # spectrum-generator

In order to increase the speed a `shape` is first generated and then the peaks in the final
spectrum are resulting from sampling the `shape`. A `shape` will therefore be generated with
spectrum are resulting from sampling the `shape`. A `shape` will therefore be generated with
much more points (typically fwhm:1000).
## Installation

@@ -35,3 +34,7 @@

];
const spectrum = generateSpectrum(peaks, { pointsPerUnit: 1 });
const spectrum = generateSpectrum(peaks, {
from: 0, // default value: 0
to: 1000, // default value: 1000
nbPoints: 10001, // default value: 10001
});
```

@@ -50,4 +53,4 @@

];
const spectrum = generateSpectrum(peaks, {
pointsPerUnit: 1000,
const spectrum = generateSpectrum(peaks, {
nbPoints: 1001,
from: 0,

@@ -60,8 +63,5 @@ to: 10,

length: 10001,
}
}
},
},
});
```

@@ -76,5 +76,6 @@

generator.addPeak([5, 20]);
generator.addPeak({ x: 5, y: 20 }); // we may either add an array of 2 elements or an object with x,y values
generator.addPeak([30, 56]);
generator.addPeaks([
[40, 12],
[40, 12], // it can also be an array of objects with x,y properties
[10, 1],

@@ -81,0 +82,0 @@ ]);

@@ -6,3 +6,3 @@ export interface SpectrumGeneratorOptions {

*/
start?: number;
from?: number;

@@ -13,3 +13,3 @@ /**

*/
end?: number;
to?: number;

@@ -35,12 +35,6 @@ /**

/**
* Number of values between each unit of the x axis.
* @default `5`
* Number of points in the final spectrum.
* @default `10001`
*/
pointsPerUnit?: number;
/**
* Maximum array size.
* @default `1e7`
*/
maxSize?: number;
nbPoints?: number;
}

@@ -101,2 +95,7 @@

export interface XYObject {
x: number;
y: number;
}
export class SpectrumGenerator {

@@ -107,4 +106,5 @@ /**

* import SG from 'spectrum-generator';
* const sg = new SG({start: 0, end: 100, pointsPerUnit: 5, peakWidthFct: (x) => 1 + 3 * x / 1000 });
* sg.addPeak( [5, 50] );
* const sg = new SG({from: 0, to: 100, nbPoints: 1001, peakWidthFct: (x) => 1 + 3 * x / 1000 });
* sg.addPeak([5, 50]);
* sg.addPeak({x:10, y:50}); // either an array of an object with x,y properties
* sg.addPeak([20, 100], { width: 3 });

@@ -121,5 +121,5 @@ * sg.addPeak([35, 100], { widthLeft: 10, widthRight: 30 });

* const spectrum=SG.generateSpectrum([ [20,3], [30,2], [40,2] ], {
* start: 0,
* end: 100,
* pointsPerUnit: 1,
* from: 0,
* to: 100,
* nbPoints: 101,
* noise: {

@@ -141,3 +141,3 @@ * percent: 10,

*/
addPeaks(peaks: number[][]): this;
addPeaks(peaks: number[][] | XYObject[]): this;

@@ -149,3 +149,3 @@ /**

*/
addPeak(peak: number[], options?: PeakOptions): this;
addPeak(peak: number[] | XYObject, options?: PeakOptions): this;

@@ -156,3 +156,3 @@ /**

*/
addBaseline(baslineFct: (y: number) => number): this;
addBaseline(baselineFct: (y: number) => number): this;

@@ -159,0 +159,0 @@ /**

import { SpectrumGenerator } from '..';
const numberReg = /^\w+ option must be a number$/;
const integerReg = /^\w+ option must be an integer$/;
const endStartReg = /^end option must be larger than start$/;
const endStartReg = /^to option must be larger than from$/;
const peakWidthReg = /^peakWidthFct option must be a function$/;
const addPeaksReg = /^peaks must be an array$/;
const addPeakReg = /^peak must be an array with two values$/;
const addPeakReg = /^peak must be an array with two values or an object with {x,y}$/;
describe('errors', () => {
it('wrong options', () => {
expect(() => new SpectrumGenerator({ start: 0.5 })).toThrow(integerReg);
expect(() => new SpectrumGenerator({ start: false })).toThrow(integerReg);
expect(() => new SpectrumGenerator({ from: 'abc' })).toThrow(numberReg);
expect(() => new SpectrumGenerator({ from: false })).toThrow(numberReg);
expect(() => new SpectrumGenerator({ end: 0.5 })).toThrow(integerReg);
expect(() => new SpectrumGenerator({ end: false })).toThrow(integerReg);
expect(() => new SpectrumGenerator({ to: 'abc' })).toThrow(numberReg);
expect(() => new SpectrumGenerator({ to: false })).toThrow(numberReg);
expect(() => new SpectrumGenerator({ pointsPerUnit: 0.5 })).toThrow(
expect(() => new SpectrumGenerator({ nbPoints: 0.5 })).toThrow(integerReg);
expect(() => new SpectrumGenerator({ nbPoints: false })).toThrow(
integerReg,
);
expect(() => new SpectrumGenerator({ pointsPerUnit: false })).toThrow(
integerReg,
);
expect(() => new SpectrumGenerator({ start: 0, end: 0 })).toThrow(
expect(() => new SpectrumGenerator({ from: 0, to: 0 })).toThrow(
endStartReg,
);
expect(() => new SpectrumGenerator({ start: 0, end: -10 })).toThrow(
expect(() => new SpectrumGenerator({ from: 0, to: -10 })).toThrow(
endStartReg,

@@ -29,0 +28,0 @@ );

@@ -11,4 +11,4 @@ /* eslint-disable jest/expect-expect */

assertSimple({
start: 0,
end: 10,
from: 0,
to: 10,
peak: 5,

@@ -18,6 +18,6 @@ });

it('should work from positive start', () => {
it('should work from positive from', () => {
assertSimple({
start: 5,
end: 15,
from: 5,
to: 15,
peak: 10,

@@ -27,6 +27,6 @@ });

it('should work from negative start', () => {
it('should work from negative from', () => {
assertSimple({
start: -15,
end: -5,
from: -15,
to: -5,
peak: -10,

@@ -38,23 +38,12 @@ });

describe('generateSpectrum with one peak and small window', () => {
it('should work from 11', () => {
const spectrum = generateSpectrum([[12, 1]], {
start: 11,
end: 13,
pointsPerUnit: 10,
it('should work with shape 9/3, peak width 0.2', () => {
const spectrum = generateSpectrum([[10, 1]], {
from: 9,
to: 11,
nbPoints: 21,
peakWidthFct: () => 0.1,
});
let max = XY.maxYPoint(spectrum);
expect(max.x).toBe(12);
expect(max.y).toBe(1);
});
it('should work from 0 to 10 low res', () => {
const spectrum = generateSpectrum([[5, 1]], {
start: 0,
end: 10,
pointsPerUnit: 1,
peakWidthFct: () => 0.1,
shape: {
kind: 'gaussian',
options: {
length: 9,
fwhm: 3,

@@ -64,83 +53,76 @@ },

});
checkSymmetry(spectrum);
expect(spectrum.y[9]).toBeCloseTo(0.0625, 3);
let max = XY.maxYPoint(spectrum);
expect(max.x).toBe(5);
expect(max.x).toBe(10);
expect(max.y).toBe(1);
});
it('should work from 10 to 20 low res', () => {
const spectrum = generateSpectrum([[15, 1]], {
start: 10,
end: 20,
pointsPerUnit: 1,
peakWidthFct: () => 2,
it('should work with shape 17/4, peak width 0.2', () => {
const spectrum = generateSpectrum([[10, 1]], {
from: 9,
to: 11,
nbPoints: 21,
peakWidthFct: () => 0.4,
shape: {
kind: 'gaussian',
options: {
fwhm: 3,
length: 17,
fwhm: 4,
},
},
});
for (let i = 0; i <= Math.floor(spectrum.y.length / 2); i++) {
expect(spectrum.y[i]).toStrictEqual(
spectrum.y[spectrum.y.length - i - 1],
);
}
expect(spectrum.y[8]).toBe(0.5);
checkSymmetry(spectrum);
let max = XY.maxYPoint(spectrum);
expect(max.x).toBe(15);
expect(max.x).toBe(10);
expect(max.y).toBe(1);
});
it('should work from 10 to 20 high res width 2', () => {
const spectrum = generateSpectrum([[15, 1]], {
start: 10,
end: 20,
pointsPerUnit: 1,
peakWidthFct: () => 2,
it('should work from 11', () => {
const spectrum = generateSpectrum([[10, 1]], {
from: 9,
to: 11,
nbPoints: 21,
peakWidthFct: () => 0.1,
shape: {
kind: 'gaussian',
options: {
fwhm: 1000,
length: 10,
fwhm: 3,
},
},
});
for (let i = 0; i <= Math.floor(spectrum.y.length / 2); i++) {
expect(spectrum.y[i]).toStrictEqual(
spectrum.y[spectrum.y.length - i - 1],
);
}
expect(spectrum.y[4] + spectrum.y[6]).toBeCloseTo(1, 2);
let max = XY.maxYPoint(spectrum);
expect(max.x).toBe(15);
expect(spectrum.y[9]).toBeCloseTo(0.15749, 4);
expect(max.x).toBe(10);
expect(max.y).toBe(1);
});
it('should work from 10 to 20 high res width 4', () => {
const spectrum = generateSpectrum([[15, 1]], {
start: 10,
end: 20,
pointsPerUnit: 1,
peakWidthFct: () => 4,
it('should work from 0 to 10 low res', () => {
const spectrum = generateSpectrum([[5, 1]], {
from: 0,
to: 10,
nbPoints: 101,
peakWidthFct: () => 0.2,
shape: {
kind: 'gaussian',
options: {
factor: 2,
fwhm: 1000,
fwhm: 4,
length: 13,
},
},
});
for (let i = 0; i <= Math.floor(spectrum.y.length / 2); i++) {
expect(spectrum.y[i]).toStrictEqual(
spectrum.y[spectrum.y.length - i - 1],
);
}
expect(spectrum.y[3] + spectrum.y[7]).toBeCloseTo(1, 2);
let max = XY.maxYPoint(spectrum);
expect(max.x).toBe(15);
expect(spectrum.y[49]).toBe(0.5);
expect(max.x).toBe(5);
expect(max.y).toBe(1);
});
it('should work from 10 to 20 high res width 4 and pointsPerUnit 10', () => {
it('should work from 10 to 20 low res', () => {
const spectrum = generateSpectrum([[15, 1]], {
start: 10,
end: 20,
pointsPerUnit: 10,
from: 10,
to: 20,
nbPoints: 101,
peakWidthFct: () => 2,

@@ -150,13 +132,9 @@ shape: {

options: {
factor: 2,
fwhm: 1000,
fwhm: 500,
length: 1501,
},
},
});
for (let i = 0; i <= Math.floor(spectrum.y.length / 2); i++) {
expect(spectrum.y[i]).toStrictEqual(
spectrum.y[spectrum.y.length - i - 1],
);
}
expect(spectrum.y[40] + spectrum.y[60]).toBeCloseTo(1, 2);
checkSymmetry(spectrum);
expect(spectrum.y[40]).toBe(0.5);
let max = XY.maxYPoint(spectrum);

@@ -166,44 +144,41 @@ expect(max.x).toBe(15);

});
});
describe('generateSpectrum check large size', () => {
let data = [];
for (let i = 0; i < 10000; i++) {
data.push([i, Math.random()]);
}
it('should throw error for huge array', () => {
expect(() =>
generateSpectrum(data, {
start: 0,
end: 10000,
pointsPerUnit: 1000,
peakWidthFct: () => 0.1,
}),
).toThrow(
'Generated array has size 10000001 larger than maxSize: 10000000',
);
it('not integer from / to', () => {
const spectrum = generateSpectrum([[2, 1]], {
from: 1.5,
to: 2.5,
nbPoints: 11,
peakWidthFct: () => 0.1,
});
checkSymmetry(spectrum);
expect(spectrum.y[5]).toBe(1);
let max = XY.maxYPoint(spectrum);
expect(max.x).toBe(2);
expect(max.y).toBe(1);
});
it('should throw for simple array is maxSize=1', () => {
expect(() =>
generateSpectrum([[1, 1]], {
start: 0,
end: 2,
pointsPerUnit: 1,
maxSize: 1,
peakWidthFct: () => 0.1,
}),
).toThrow('Generated array has size 3 larger than maxSize: 1');
it('not integer from / to not integer', () => {
const spectrum = generateSpectrum([[2.5, 1]], {
from: 1.7,
to: 3.7,
nbPoints: 11,
peakWidthFct: () => 0.1,
});
expect(spectrum.y[3]).toBe(spectrum.y[5]);
let max = XY.maxYPoint(spectrum);
expect(max.x).toBe(2.5);
expect(max.y).toBe(1);
});
});
function assertSimple({ start, end, peak }) {
function assertSimple({ from, to, peak }) {
const spectrum = generateSpectrum([[peak, 1]], {
start,
end,
pointsPerUnit: 1,
from,
to,
nbPoints: 11,
peakWidthFct: simplepeakWidthFct,
});
assertSize(spectrum, end - start + 1);
assertInterval(spectrum, start);
assertSize(spectrum, to - from + 1);
assertInterval(spectrum, from);
}

@@ -216,4 +191,4 @@

function assertInterval(spectrum, start) {
let expected = start;
function assertInterval(spectrum, from) {
let expected = from;
for (const value of spectrum.x) {

@@ -224,1 +199,7 @@ expect(value).toBe(expected);

}
function checkSymmetry(spectrum) {
for (let i = 0; i <= Math.floor(spectrum.y.length / 2); i++) {
expect(spectrum.y[i]).toStrictEqual(spectrum.y[spectrum.y.length - i - 1]);
}
}

@@ -7,5 +7,5 @@ /* eslint-disable jest/expect-expect */

const generator = new SpectrumGenerator({
start: 0,
end: 2,
pointsPerUnit: 5,
from: 0,
to: 2,
nbPoints: 11,
});

@@ -16,10 +16,10 @@

const spectrum = generator.getSpectrum();
expectValue(spectrum, 0, 1);
expect(spectrum.y[0]).toBe(1);
});
it('end half peak', () => {
it('to half peak', () => {
const generator = new SpectrumGenerator({
start: 0,
end: 2,
pointsPerUnit: 5,
from: 0,
to: 2,
nbPoints: 11,
});

@@ -30,3 +30,3 @@

const spectrum = generator.getSpectrum();
expectValue(spectrum, 2 * 5, 1);
expect(spectrum.y[2 * 5]).toBe(1);
});

@@ -36,5 +36,5 @@

const generator = new SpectrumGenerator({
start: 0,
end: 2,
pointsPerUnit: 5,
from: 0,
to: 2,
nbPoints: 11,
});

@@ -45,3 +45,3 @@

const spectrum = generator.getSpectrum();
expectValue(spectrum, 1 * 5, 1);
expect(spectrum.y[1 * 5]).toBe(1);
});

@@ -51,7 +51,7 @@

const generator = new SpectrumGenerator({
start: 0,
end: 100,
pointsPerUnit: 2,
from: 0,
to: 100,
nbPoints: 201,
});
generator.addPeak([35, 100], { widthLeft: 10, widthRight: 30 });
generator.addPeak([50, 100], { widthLeft: 10, widthRight: 30 });
const spectrum = generator.getSpectrum();

@@ -63,5 +63,5 @@ expect(spectrum).toMatchSnapshot();

const generator = new SpectrumGenerator({
start: 0,
end: 2,
pointsPerUnit: 10,
from: 0,
to: 2,
nbPoints: 21,
peakWidthFct: (x) => 1 + (3 * x) / 1000,

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

expect(spectrum.y[1.5 * 10]).toBeCloseTo(0.5, 2);
expectValue(spectrum, 1 * 10, 1);
expect(spectrum.y[1 * 10]).toBe(1);
});

@@ -81,5 +81,5 @@

const generator = new SpectrumGenerator({
start: 0,
end: 5,
pointsPerUnit: 5,
from: 0,
to: 5,
nbPoints: 26,
});

@@ -112,14 +112,31 @@

expectValue(spectrum, 0, 1);
expectValue(spectrum, 50 * 5, 12);
expectValue(spectrum, 100 * 5, 10);
expectValue(spectrum, 14 * 5, 2);
expect(spectrum.y[0]).toBe(1);
expect(spectrum.y[50 * 10]).toBe(12);
expect(spectrum.y[100 * 10]).toBe(10);
expect(spectrum.y[14 * 10]).toBe(2);
});
it('full generation with {x,y}', () => {
const generator = new SpectrumGenerator();
generator.addPeak({ x: 0, y: 1 });
generator.addPeak({ x: 50, y: 12 });
generator.addPeaks([
{ x: 100, y: 10 },
{ x: 14, y: 2 },
]);
const spectrum = generator.getSpectrum();
expect(spectrum.y[0]).toBe(1);
expect(spectrum.y[50 * 10]).toBe(12);
expect(spectrum.y[100 * 10]).toBe(10);
expect(spectrum.y[14 * 10]).toBe(2);
});
it('full generation with threshold', () => {
const generator = new SpectrumGenerator({
pointsPerUnit: 10000,
start: -1000,
end: 1000,
maxSize: 1e8,
from: -1000,
to: 1000,
nbPoints: 20000001,
peakWidthFct: () => 0.001,

@@ -160,5 +177,1 @@ });

});
function expectValue(spectrum, index, value) {
expect(spectrum.y[index]).toBe(value);
}

@@ -12,7 +12,6 @@ import normed from 'ml-array-normed';

{
start: 0,
end: 1000,
pointsPerUnit: 5,
from: 0,
to: 1000,
nbPoints: 10001,
peakWidthFct: () => 5,
maxSize: 1e7,
shape: {

@@ -28,7 +27,7 @@ kind: 'gaussian',

);
this.start = options.start;
this.end = options.end;
this.pointsPerUnit = options.pointsPerUnit;
this.from = options.from;
this.to = options.to;
this.nbPoints = options.nbPoints;
this.interval = (this.to - this.from) / (this.nbPoints - 1);
this.peakWidthFct = options.peakWidthFct;
this.maxSize = options.maxSize;
this.maxPeakHeight = Number.MIN_SAFE_INTEGER;

@@ -39,11 +38,11 @@ this.shape = getShape(options.shape.kind, options.shape.options);

});
this.shapeFactor = this.shape.data.length / this.shape.fwhm;
this.shapeFactor = (this.shape.data.length - 1) / this.shape.fwhm;
this.shapeLength = this.shape.data.length;
this.shapeHalfLength = Math.floor(this.shape.data.length / 2);
assertNumber(this.from, 'from');
assertNumber(this.to, 'to');
assertInteger(this.nbPoints, 'nbPoints');
assertInteger(this.start, 'start');
assertInteger(this.end, 'end');
assertInteger(this.pointsPerUnit, 'pointsPerUnit');
assertInteger(this.maxSize, 'maxSize');
if (this.end <= this.start) {
throw new RangeError('end option must be larger than start');
if (this.to <= this.from) {
throw new RangeError('to option must be larger than from');
}

@@ -58,6 +57,2 @@

get size() {
return (this.end - this.start) * this.pointsPerUnit + 1;
}
addPeaks(peaks) {

@@ -74,11 +69,26 @@ if (!Array.isArray(peaks)) {

addPeak(peak, options = {}) {
if (!Array.isArray(peak) || peak.length !== 2) {
throw new Error('peak must be an array with two values');
if (
typeof peak !== 'object' ||
(peak.length !== 2 && (peak.x === undefined || peak.y === undefined))
) {
throw new Error(
'peak must be an array with two values or an object with {x,y}',
);
}
let xPosition;
let intensity;
if (Array.isArray(peak)) {
[xPosition, intensity] = peak;
} else {
xPosition = peak.x;
intensity = peak.y;
}
const [value, intensity] = peak;
if (intensity > this.maxPeakHeight) this.maxPeakHeight = intensity;
let { width = this.peakWidthFct(value), widthLeft, widthRight } = options;
let {
width = this.peakWidthFct(xPosition),
widthLeft,
widthRight,
} = options;

@@ -88,40 +98,36 @@ if (!widthLeft) widthLeft = width;

const firstValue = value - (widthLeft / 2) * this.shapeFactor;
const lastValue = value + (widthRight / 2) * this.shapeFactor;
const firstValue = xPosition - (widthLeft / 2) * this.shapeFactor;
const lastValue = xPosition + (widthRight / 2) * this.shapeFactor;
const firstPoint = Math.floor(firstValue * this.pointsPerUnit);
const lastPoint = Math.ceil(lastValue * this.pointsPerUnit);
const middlePoint = value * this.pointsPerUnit;
const firstPoint = Math.max(
0,
Math.floor((firstValue - this.from) / this.interval),
);
const lastPoint = Math.min(
this.nbPoints - 1,
Math.ceil((lastValue - this.from) / this.interval),
);
const middlePoint = (xPosition - this.from) / this.interval;
// PEAK SHAPE MAY BE ASYMETRC (widthLeft and widthRight) !
// PEAK SHAPE MAY BE ASYMMETRC (widthLeft and widthRight) !
// we calculate the left part of the shape
for (let j = firstPoint; j < middlePoint; j++) {
let index = j - this.start * this.pointsPerUnit;
for (let index = firstPoint; index < middlePoint; index++) {
let ratio = ((xPosition - this.data.x[index]) / widthLeft) * 2;
let shapeIndex = Math.round(
this.shapeHalfLength - (ratio * this.shape.fwhm) / 2,
);
if (index >= 0 && index < this.size) {
let shapeIndex = Math.ceil(
((this.shape.fwhm / widthLeft) * (j - middlePoint)) /
this.pointsPerUnit +
(this.shapeFactor * this.shape.fwhm - 1) / 2,
);
if (shapeIndex >= 0 && shapeIndex < this.shape.data.length) {
this.data.y[index] += this.shape.data[shapeIndex] * intensity;
}
if (shapeIndex >= 0 && shapeIndex < this.shapeHalfLength) {
this.data.y[index] += this.shape.data[shapeIndex] * intensity;
}
}
// we calculate the right part of the gaussian
for (let j = Math.ceil(middlePoint); j <= lastPoint; j++) {
let index = j - this.start * this.pointsPerUnit;
for (let index = Math.ceil(middlePoint); index <= lastPoint; index++) {
let ratio = ((this.data.x[index] - xPosition) / widthRight) * 2;
if (index >= 0 && index < this.size) {
let shapeIndex = Math.floor(
((this.shape.fwhm / widthRight) * (j - middlePoint)) /
this.pointsPerUnit +
(this.shapeFactor * this.shape.fwhm - 1) / 2,
);
if (shapeIndex >= 0 && shapeIndex < this.shape.data.length) {
this.data.y[index] += this.shape.data[shapeIndex] * intensity;
}
let shapeIndex = Math.round(
this.shapeHalfLength - (ratio * this.shape.fwhm) / 2,
);
if (shapeIndex >= 0 && shapeIndex <= this.shapeHalfLength) {
this.data.y[index] += this.shape.data[shapeIndex] * intensity;
}

@@ -171,27 +177,11 @@ }

reset() {
if (this.size > this.maxSize) {
throw new Error(
`Generated array has size ${this.size} larger than maxSize: ${this.maxSize}`,
);
}
const spectrum = (this.data = {
x: [],
y: new Array(this.size).fill(0),
x: new Float64Array(this.nbPoints),
y: new Float64Array(this.nbPoints),
});
const interval = 1 / this.pointsPerUnit;
const js = [];
for (let j = 0; j < this.pointsPerUnit; j++) {
js.push(j * interval);
for (let i = 0; i < this.nbPoints; i++) {
spectrum.x[i] = this.from + i * this.interval;
}
for (let i = this.start; i < this.end; i++) {
for (let j = 0; j < this.pointsPerUnit; j++) {
spectrum.x.push(i + js[j]);
}
}
spectrum.x.push(this.end);
return this;

@@ -207,2 +197,8 @@ }

function assertNumber(value, name) {
if (!Number.isFinite(value)) {
throw new TypeError(`${name} option must be a number`);
}
}
export function generateSpectrum(peaks, options = {}) {

@@ -209,0 +205,0 @@ const generator = new SpectrumGenerator(options);

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

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

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc