File size: 6,320 Bytes
6d08d46 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 | 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()
})
})
|