Spaces:
Sleeping
Sleeping
| import { describe, it, expect } from 'vitest' | |
| import { | |
| convertWavelength, | |
| interpolateData, | |
| parseDIF, | |
| extractMetadata, | |
| } from './xrd-processing' | |
| // --------------------------------------------------------------------------- | |
| // convertWavelength | |
| // --------------------------------------------------------------------------- | |
| describe('convertWavelength', () => { | |
| it('returns same angle when wavelengths match', () => { | |
| const result = convertWavelength(10.0, 0.6199, 0.6199) | |
| expect(result).toBeCloseTo(10.0, 5) | |
| }) | |
| it('returns null for physically impossible conversion', () => { | |
| // Large angle with large wavelength ratio can exceed sin > 1 | |
| const result = convertWavelength(80.0, 0.5, 2.0) | |
| expect(result).toBeNull() | |
| }) | |
| it('converts Cu Ka to synchrotron wavelength', () => { | |
| const cuKa = 1.5406 | |
| const synchrotron = 0.6199 | |
| const theta = 20.0 | |
| const result = convertWavelength(theta, cuKa, synchrotron) | |
| expect(result).not.toBeNull() | |
| // Shorter wavelength -> smaller 2theta | |
| expect(result).toBeLessThan(theta) | |
| expect(result).toBeGreaterThan(0) | |
| }) | |
| it('converts synchrotron to Cu Ka wavelength', () => { | |
| const cuKa = 1.5406 | |
| const synchrotron = 0.6199 | |
| const theta = 10.0 | |
| const result = convertWavelength(theta, synchrotron, cuKa) | |
| expect(result).not.toBeNull() | |
| // Longer wavelength -> larger 2theta | |
| expect(result).toBeGreaterThan(theta) | |
| }) | |
| it('handles zero angle', () => { | |
| const result = convertWavelength(0, 1.0, 2.0) | |
| expect(result).toBeCloseTo(0, 5) | |
| }) | |
| }) | |
| // --------------------------------------------------------------------------- | |
| // interpolateData | |
| // --------------------------------------------------------------------------- | |
| describe('interpolateData', () => { | |
| it('returns same data when target size matches', () => { | |
| const x = [1, 2, 3] | |
| const y = [10, 20, 30] | |
| const result = interpolateData(x, y, 3) | |
| expect(result.x).toEqual(x) | |
| expect(result.y).toEqual(y) | |
| }) | |
| it('interpolates to larger size with linear strategy', () => { | |
| const x = [0, 10] | |
| const y = [0, 100] | |
| const result = interpolateData(x, y, 11, 0, 10, 'linear') | |
| expect(result.x).toHaveLength(11) | |
| expect(result.y).toHaveLength(11) | |
| // Midpoint should be ~50 | |
| expect(result.y[5]).toBeCloseTo(50, 0) | |
| }) | |
| it('sets out-of-range values to zero', () => { | |
| const x = [5, 10, 15] | |
| const y = [100, 200, 300] | |
| const result = interpolateData(x, y, 20, 0, 20, 'linear') | |
| // Points before x=5 should be 0 | |
| expect(result.y[0]).toBe(0) | |
| // Points after x=15 should be 0 | |
| expect(result.y[19]).toBe(0) | |
| }) | |
| it('supports cubic interpolation', () => { | |
| const x = [0, 2, 4, 6, 8, 10] | |
| const y = [0, 4, 16, 36, 64, 100] | |
| const result = interpolateData(x, y, 11, 0, 10, 'cubic') | |
| expect(result.x).toHaveLength(11) | |
| expect(result.y).toHaveLength(11) | |
| }) | |
| it('handles single point input', () => { | |
| const x = [5] | |
| const y = [100] | |
| const result = interpolateData(x, y, 10, 0, 10, 'linear') | |
| expect(result.x).toHaveLength(10) | |
| }) | |
| }) | |
| // --------------------------------------------------------------------------- | |
| // parseDIF | |
| // --------------------------------------------------------------------------- | |
| describe('parseDIF', () => { | |
| it('parses space-separated data', () => { | |
| const text = '5.0 100.0\n10.0 200.0\n15.0 300.0\n' | |
| const result = parseDIF(text) | |
| expect(result.x).toEqual([5.0, 10.0, 15.0]) | |
| expect(result.y).toEqual([100.0, 200.0, 300.0]) | |
| }) | |
| it('skips comment lines', () => { | |
| const text = '# This is a comment\n5.0 100.0\n10.0 200.0\n' | |
| const result = parseDIF(text) | |
| expect(result.x).toHaveLength(2) | |
| }) | |
| it('skips metadata lines', () => { | |
| const text = 'CELL PARAMETERS: 5.0 5.0 5.0 90 90 90\nSPACE GROUP: Fm-3m\n5.0 100.0\n' | |
| const result = parseDIF(text) | |
| expect(result.x).toEqual([5.0]) | |
| }) | |
| it('skips lines starting with underscore', () => { | |
| const text = '_cell_length_a 5.431\n5.0 100.0\n' | |
| const result = parseDIF(text) | |
| expect(result.x).toEqual([5.0]) | |
| }) | |
| it('handles empty input', () => { | |
| const result = parseDIF('') | |
| expect(result.x).toEqual([]) | |
| expect(result.y).toEqual([]) | |
| }) | |
| it('handles tab-separated data', () => { | |
| const text = '5.0\t100.0\n10.0\t200.0\n' | |
| const result = parseDIF(text) | |
| expect(result.x).toEqual([5.0, 10.0]) | |
| expect(result.y).toEqual([100.0, 200.0]) | |
| }) | |
| it('skips lines starting with letters', () => { | |
| const text = 'Header line\n5.0 100.0\nAnother header\n10.0 200.0\n' | |
| const result = parseDIF(text) | |
| expect(result.x).toEqual([5.0, 10.0]) | |
| }) | |
| }) | |
| // --------------------------------------------------------------------------- | |
| // extractMetadata | |
| // --------------------------------------------------------------------------- | |
| describe('extractMetadata', () => { | |
| it('detects wavelength from numeric pattern', () => { | |
| const text = '_diffrn_radiation_wavelength 0.6199\n' | |
| const result = extractMetadata(text) | |
| expect(result.wavelength).toBeCloseTo(0.6199, 4) | |
| }) | |
| it('detects Cu Ka radiation', () => { | |
| const text = 'Radiation: Cu Ka\n' | |
| const result = extractMetadata(text) | |
| expect(result.wavelength).toBeCloseTo(1.5406, 4) | |
| }) | |
| it('detects Mo Ka radiation', () => { | |
| const text = 'Radiation: Mo Ka\n' | |
| const result = extractMetadata(text) | |
| expect(result.wavelength).toBeCloseTo(0.7107, 4) | |
| }) | |
| it('extracts space group number', () => { | |
| const text = '_symmetry_Int_Tables_number 225\n' | |
| const result = extractMetadata(text) | |
| expect(result.spaceGroup).toBe('225') | |
| }) | |
| it('extracts cell parameters', () => { | |
| const text = 'CELL PARAMETERS: 5.431 5.431 5.431 90.0 90.0 90.0\n' | |
| const result = extractMetadata(text) | |
| expect(result.cellParams).not.toBeNull() | |
| expect(result.cellParams).toContain('5.431') | |
| }) | |
| it('returns null for missing data', () => { | |
| const result = extractMetadata('Some random text without metadata\n') | |
| expect(result.wavelength).toBeNull() | |
| expect(result.spaceGroup).toBeNull() | |
| expect(result.cellParams).toBeNull() | |
| }) | |
| it('rejects wavelengths outside X-ray range', () => { | |
| const text = 'wavelength: 0.001\n' | |
| const result = extractMetadata(text) | |
| expect(result.wavelength).toBeNull() | |
| }) | |
| }) | |