Skip to content

Commit

Permalink
add new beamline type
Browse files Browse the repository at this point in the history
  • Loading branch information
tizayi committed Apr 30, 2024
1 parent 1eeea23 commit 4ce5c2a
Show file tree
Hide file tree
Showing 5 changed files with 192 additions and 136 deletions.
9 changes: 9 additions & 0 deletions src/presets/beamlines.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"I22": {
"minWavelength": 0.062,
"maxWavelength": 0.335,
"minCameraLength": 1.9,
"maxCameraLength": 9.9,
"cameraLengthStep": 0.25
}
}
42 changes: 8 additions & 34 deletions src/presets/preset.test.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,12 @@
import { expect, test } from "vitest";
import { defaultConfig, detectorList, presetList } from "./presetManager";
import { detectorRecord } from "./presetManager";

test("Test detectors exist and are valid", () => {
expect(detectorList).toBeTruthy();
for (const detector in detectorList) {
expect(detectorList[detector]).toHaveProperty("resolution.width");
expect(detectorList[detector]).toHaveProperty("resolution.height");
expect(detectorList[detector]).toHaveProperty("pixelSize.width");
expect(detectorList[detector]).toHaveProperty("pixelSize.height");
}
});

test("Test beamstop and camera tube are valid", () => {
for (const preset in presetList) {
expect(presetList[preset]).toHaveProperty("beamstop.diameter");
expect(presetList[preset]).toHaveProperty("beamstop.centre.x");
expect(presetList[preset]).toHaveProperty("beamstop.centre.y");
expect(presetList[preset]).toHaveProperty("beamstop.clearance");
expect(presetList[preset]).toHaveProperty("cameraTube.centre.x");
expect(presetList[preset]).toHaveProperty("cameraTube.centre.y");
expect(presetList[preset]).toHaveProperty("cameraTube.diameter");
}
});

test("Test presets exist and are valid", () => {
expect(presetList).toBeTruthy();
expect(defaultConfig).toBeTruthy();
for (const preset in presetList) {
expect(Object.keys(detectorList)).toContain(presetList[preset].detector);
expect(presetList[preset]).toHaveProperty("angle");
expect(presetList[preset]).toHaveProperty("cameraLength");
expect(presetList[preset]).toHaveProperty("minWavelength");
expect(presetList[preset]).toHaveProperty("maxWavelength");
expect(presetList[preset]).toHaveProperty("minCameraLength");
expect(presetList[preset]).toHaveProperty("maxCameraLength");
test("Test detectors exist anordetectorRecordd are valid", () => {
expect(detectorRecord).toBeTruthy();
for (const detector in detectorRecord) {
expect(detectorRecord[detector]).toHaveProperty("resolution.width");
expect(detectorRecord[detector]).toHaveProperty("resolution.height");
expect(detectorRecord[detector]).toHaveProperty("pixelSize.width");
expect(detectorRecord[detector]).toHaveProperty("pixelSize.height");
}
});
22 changes: 4 additions & 18 deletions src/presets/presetConfigs.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"I22 SAXS Isotropic": {
"detector": "Pilatus P3-2M",
"beamline": "I22",
"beamstop": {
"centre": {
"x": 738,
Expand All @@ -15,18 +16,11 @@
"y": 840
},
"diameter": 310
},
"angle": 90,
"wavelength": null,
"cameraLength": 1.9,
"minWavelength": 0.062,
"maxWavelength": 0.335,
"minCameraLength": 1.9,
"maxCameraLength": 9.9,
"cameraLengthStep": 0.25
}
},
"I22 SAXS Anisotropic": {
"detector": "Pilatus P3-2M",
"beamline": "I22",
"beamstop": {
"centre": {
"x": 738,
Expand All @@ -41,14 +35,6 @@
"y": 840
},
"diameter": 310
},
"angle": 90,
"wavelength": null,
"cameraLength": 1.9,
"minWavelength": 0.062,
"maxWavelength": 0.335,
"minCameraLength": 1.9,
"maxCameraLength": 9.9,
"cameraLengthStep": 0.25
}
}
}
164 changes: 91 additions & 73 deletions src/presets/presetManager.ts
Original file line number Diff line number Diff line change
@@ -1,91 +1,109 @@
import {unit} from "mathjs";
import detectorDataRecord from "../presets/detectors.json";
import presetData from "../presets/presetConfigs.json";
import {
BeamlineConfig,
Beamstop,
CircularDevice,
Detector,
SimpleVector2,
import detectorData from "./detectors.json";
import presetConfigData from "./presetConfigs.json";
import beamlineData from "./beamlines.json"
import {
AppBeamline,
AppDetector,
AppConfig,
IOBeamline,
IODetector,
IOPresetConfig
} from "../utils/types";

export interface AppDataFormat extends BeamlineConfig {
detector: string;
beamstop: Beamstop;
cameraTube: CircularDevice;
// todo use OOP composition over inheritance
// https://en.wikipedia.org/wiki/Composition_over_inheritance
// beamlineConfig: BeamlineConfig;
}

interface DetectorData {
readonly resolution: { height: number; width: number };
readonly pixelSize: { height: number; width: number };
}

interface CircularDeviceData {
readonly centre: SimpleVector2;
readonly diameter: number;
/**
* Creates an internal detector with pixel size units from an IODetector
* @param detectorData IOdetector input
* @returns AppDetector output
*/
export function createInternalDetector(detectorData: IODetector): AppDetector {
return {
...detectorData,
pixelSize: {
height: unit(detectorData.pixelSize.height, "mm"),
width: unit(detectorData.pixelSize.height, "mm"),
},
}
}

export interface BeamlineData {
readonly angle: number | null;
readonly cameraLength: number | null;
readonly minWavelength: number;
readonly maxWavelength: number;
readonly minCameraLength: number;
readonly maxCameraLength: number;
readonly wavelength: number | null;
readonly cameraLengthStep: number;
}
/**
* Holds all the preset detectors as AppDetectors
*/
export const detectorRecord: Record<string, AppDetector> = Object.fromEntries(
Object.entries(detectorData as Record<string, IODetector>).map(
([key, value]) => [
key,
createInternalDetector(value)
],
),
);

interface BeamstopData extends CircularDeviceData {
readonly clearance: number | null;
}

export interface AppData extends BeamlineData {
readonly detector: string;
readonly beamstop: BeamstopData;
readonly cameraTube: CircularDeviceData;
/**
* Creates an internal beamline with units from an IODetector
* @param beamlineData Input IOBeamline
* @returns AppBeamline with correct data
*/
export function createInternalBeamline(beamlineData: IOBeamline): AppBeamline {
return {
minWavelength: unit(beamlineData.minWavelength, "nm"),
maxWavelength: unit(beamlineData.maxWavelength, "nm"),
minCameraLength: unit(beamlineData.minCameraLength, "m"),
maxCameraLength: unit(beamlineData.maxCameraLength, "m"),
cameraLengthStep: unit(beamlineData.cameraLengthStep, "m"),
}
}

export const detectorList: Record<string, Detector> = Object.fromEntries(
Object.entries(detectorDataRecord as Record<string, DetectorData>).map(
/**
* Holds all the preset beamlines as AppBeamlines
*/
export const beamlineRecord: Record<string, AppBeamline> = Object.fromEntries(
Object.entries(beamlineData as Record<string, IOBeamline>).map(
([key, value]) => [
key,
{
...value,
pixelSize: {
height: unit(value.pixelSize.height, "mm"),
width: unit(value.pixelSize.height, "mm"),
},
},
createInternalBeamline(value)
],
),
);
)

/**
* Creates internal AppConfig from IOPresetConfig
* @param preset input IOPresetConfig
* @returns
*/
function createPresetConfigRecord(preset: IOPresetConfig):AppConfig{
return {
...preset,
beamstop: {
...preset.beamstop,
diameter: unit(preset.beamstop.diameter, "mm"),
},
cameraTube: {
...preset.cameraTube,
diameter: unit(preset.cameraTube.diameter, "mm"),
},
wavelength: unit(NaN, "nm"),
angle: unit(90, "deg"),
cameraLength:
beamlineRecord[preset.beamline].minCameraLength.toNumber("m"),
}
}

export const presetList: Record<string, AppDataFormat> = Object.fromEntries(
Object.entries(presetData as Record<string, AppData>).map(([key, value]) => [
key,
{
...value,
beamstop: {
...value.beamstop,
diameter: unit(value.beamstop.diameter, "mm"),
},
cameraTube: {
...value.cameraTube,
diameter: unit(value.cameraTube.diameter, "mm"),
},
minWavelength: unit(value.minWavelength, "nm"),
maxWavelength: unit(value.maxWavelength, "nm"),
minCameraLength: unit(value.minCameraLength, "m"),
maxCameraLength: unit(value.maxCameraLength, "m"),
cameraLengthStep: unit(value.cameraLengthStep, "m"),

wavelength: unit(value.wavelength ?? NaN, "nm"),
angle: unit(value.angle ?? NaN, "deg"),
},
/**
* Holds the internal app configurations
*/
export const presetConfigRecord: Record<string, AppConfig> = Object.fromEntries(
Object.entries(presetConfigData as Record<string, IOPresetConfig>).map(
([key, value]) => [
key,
createPresetConfigRecord(value)
]),
);
export const defaultConfig = presetList[Object.keys(presetList)[0]];

/**
* Sets how the app is configured by default
*/
export const defaultConfig = presetConfigRecord[
Object.keys(presetConfigRecord)[0]];
91 changes: 80 additions & 11 deletions src/utils/types.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,100 @@
import { Unit } from "mathjs";

export interface Detector {
readonly resolution: { height: number; width: number };
readonly pixelSize: { height: Unit; width: Unit };
}

/**
* Represnts a simple vector
*/
export interface SimpleVector2 {
x?: number | null;
y?: number | null;
}

export interface CircularDevice {
/**
* Internal Detector type
*/
export interface AppDetector {
readonly resolution: { height: number; width: number };
readonly pixelSize: { height: Unit; width: Unit };
}

/**
* Internal Circular Device (eg Camera Tube or Beamstop)
*/
export interface AppCircularDevice {
centre: SimpleVector2;
diameter: Unit;
}

export interface Beamstop extends CircularDevice {
/**
* Internal Beamstop type
*/
export interface AppBeamstop extends AppCircularDevice {
clearance: number | null;
}

export interface BeamlineConfig {
angle: Unit;
cameraLength: number | null;
/**
* Internal Beamline type (contains all immutable information about a beamline)
*/
export interface AppBeamline {
readonly minWavelength: Unit;
readonly maxWavelength: Unit;
readonly minCameraLength: Unit;
readonly maxCameraLength: Unit;
wavelength: Unit;
readonly cameraLengthStep: Unit;
}

/**
* Internal Full AppConfig
*/
export interface AppConfig {
detector: string;
beamstop: AppBeamstop;
cameraTube: AppCircularDevice;
beamline: string;
wavelength: Unit;
angle: Unit;
cameraLength: number | null;
}

/**
* External Detector type used in IO
*/
export interface IODetector {
readonly resolution: { height: number; width: number };
readonly pixelSize: { height: number; width: number };
}

/**
* External CircularTube type used in IO
*/
export interface IOCircularDevice {
readonly centre: SimpleVector2;
readonly diameter: number;
}

/**
* External Beamline type for use in
*/
export interface IOBeamline {
readonly minWavelength: number;
readonly maxWavelength: number;
readonly minCameraLength: number;
readonly maxCameraLength: number;
readonly cameraLengthStep: number;
}

/**
* External Beamstop type
*/
export interface IOBeamstop extends IOCircularDevice {
readonly clearance: number | null;
}

/**
* External Preset Config type
*/
export interface IOPresetConfig {
readonly detector: string;
readonly beamline: string;
readonly beamstop: IOBeamstop;
readonly cameraTube: IOCircularDevice;
}

0 comments on commit 4ce5c2a

Please sign in to comment.