From 2a3f28001ccf75e2d90630ad67340d17d4f037eb Mon Sep 17 00:00:00 2001 From: grabowski Date: Thu, 22 Oct 2026 17:26:14 +0700 Subject: [PATCH] Lamp testbench in Rust around the HPCS 6500 lampbench station / export / label / tm30 / calibrate replace the Python lamp_station.py, lamp_export.py, label_printer.py, tm30.py and calibration.py that lived in HPCS6500-py. The driver is a submodule (HPCS6500/, like mppt-testbench). Workspace crates: tm30 (TM-30-18 port of colour-science 0.4.7), brother-ql (raster protocol, byte-identical to brother_ql) and lamp-label (QR + ID labels for the QL-820NWB). Bundles are byte-identical to lamp_export.py's (golden tests); the station runs end to end in a test against the simulated instrument. --- .gitattributes | 7 + .gitignore | 3 + .gitmodules | 3 + Cargo.lock | 1184 +++++++++++++++++ Cargo.toml | 36 + HPCS6500 | 1 + README.md | 162 +++ crates/brother-ql/Cargo.toml | 14 + crates/brother-ql/src/bitmap.rs | 272 ++++ crates/brother-ql/src/conversion.rs | 254 ++++ crates/brother-ql/src/error.rs | 97 ++ crates/brother-ql/src/labels.rs | 200 +++ crates/brother-ql/src/lib.rs | 37 + crates/brother-ql/src/models.rs | 142 ++ crates/brother-ql/src/network.rs | 247 ++++ crates/brother-ql/src/packbits.rs | 142 ++ crates/brother-ql/src/raster.rs | 201 +++ crates/brother-ql/tests/golden.rs | 171 +++ crates/brother-ql/tests/golden/black_202.png | Bin 0 -> 85 bytes .../tests/golden/black_202_compress.bin | Bin 0 -> 3072 bytes .../brother-ql/tests/golden/black_202_x1.bin | Bin 0 -> 19230 bytes .../brother-ql/tests/golden/black_202_x2.bin | Bin 0 -> 38050 bytes .../brother-ql/tests/golden/checker_202.png | Bin 0 -> 136 bytes .../tests/golden/checker_202_compress.bin | Bin 0 -> 3072 bytes .../tests/golden/checker_202_x1.bin | Bin 0 -> 19230 bytes .../tests/golden/checker_202_x2.bin | Bin 0 -> 38050 bytes crates/brother-ql/tests/golden/corner_bl.png | Bin 0 -> 129 bytes .../brother-ql/tests/golden/corner_bl_x1.bin | Bin 0 -> 19230 bytes .../brother-ql/tests/golden/corner_bl_x2.bin | Bin 0 -> 38050 bytes crates/brother-ql/tests/golden/corner_br.png | Bin 0 -> 128 bytes .../tests/golden/corner_br_rot0.bin | Bin 0 -> 19230 bytes .../brother-ql/tests/golden/corner_br_x1.bin | Bin 0 -> 19230 bytes .../brother-ql/tests/golden/corner_br_x2.bin | Bin 0 -> 38050 bytes crates/brother-ql/tests/golden/corner_tl.png | Bin 0 -> 131 bytes .../tests/golden/corner_tl_rot0.bin | Bin 0 -> 19230 bytes .../tests/golden/corner_tl_rot180.bin | Bin 0 -> 19230 bytes .../tests/golden/corner_tl_rot270.bin | Bin 0 -> 19230 bytes .../tests/golden/corner_tl_rot90.bin | Bin 0 -> 19230 bytes .../brother-ql/tests/golden/corner_tl_x1.bin | Bin 0 -> 19230 bytes .../brother-ql/tests/golden/corner_tl_x2.bin | Bin 0 -> 38050 bytes crates/brother-ql/tests/golden/corner_tr.png | Bin 0 -> 129 bytes .../brother-ql/tests/golden/corner_tr_x1.bin | Bin 0 -> 19230 bytes .../brother-ql/tests/golden/corner_tr_x2.bin | Bin 0 -> 38050 bytes .../tests/golden/diecut62x29_auto_rotate.bin | Bin 0 -> 25647 bytes .../brother-ql/tests/golden/endless29_306.bin | Bin 0 -> 13984 bytes .../brother-ql/tests/golden/endless62_696.bin | Bin 0 -> 28344 bytes .../tests/golden/endless62_dpi600.bin | Bin 0 -> 14394 bytes .../tests/golden/endless62_resize500.bin | Bin 0 -> 26298 bytes .../tests/golden/endless62_rot90.bin | Bin 0 -> 28344 bytes .../brother-ql/tests/golden/label_L0001.png | Bin 0 -> 516 bytes .../tests/golden/label_L0001_x1.bin | Bin 0 -> 19230 bytes .../tests/golden/label_L0001_x2.bin | Bin 0 -> 38050 bytes .../brother-ql/tests/golden/label_L0006.png | Bin 0 -> 574 bytes .../tests/golden/label_L0006_compress_x2.bin | Bin 0 -> 8328 bytes .../tests/golden/label_L0006_nocut.bin | Bin 0 -> 19222 bytes .../tests/golden/label_L0006_x1.bin | Bin 0 -> 19230 bytes .../tests/golden/label_L0006_x2.bin | Bin 0 -> 38050 bytes .../brother-ql/tests/golden/label_L0123.png | Bin 0 -> 614 bytes .../tests/golden/label_L0123_x1.bin | Bin 0 -> 19230 bytes .../tests/golden/label_L0123_x2.bin | Bin 0 -> 38050 bytes .../brother-ql/tests/golden/label_L12345.png | Bin 0 -> 651 bytes .../tests/golden/label_L12345_x1.bin | Bin 0 -> 19230 bytes .../tests/golden/label_L12345_x2.bin | Bin 0 -> 38050 bytes crates/brother-ql/tests/golden/label_L9.png | Bin 0 -> 506 bytes .../brother-ql/tests/golden/label_L9_x1.bin | Bin 0 -> 19230 bytes .../brother-ql/tests/golden/label_L9_x2.bin | Bin 0 -> 38050 bytes crates/brother-ql/tests/golden/manifest.txt | 60 + .../brother-ql/tests/golden/multi_labels.bin | Bin 0 -> 56870 bytes crates/brother-ql/tests/golden/ql1100_102.bin | Bin 0 -> 13962 bytes crates/brother-ql/tests/golden/ql1100_62.bin | Bin 0 -> 9267 bytes crates/brother-ql/tests/golden/ql500_29.bin | Bin 0 -> 28124 bytes .../brother-ql/tests/golden/ql570_62x29.bin | Bin 0 -> 25431 bytes .../golden/ql700_62_compress_ignored.bin | Bin 0 -> 28136 bytes .../tests/golden/ql800_23x23_x2.bin | Bin 0 -> 38050 bytes .../tests/golden/random_1392x150.png | Bin 0 -> 26318 bytes crates/brother-ql/tests/golden/random_202.png | Bin 0 -> 5508 bytes .../tests/golden/random_202_compress.bin | Bin 0 -> 7312 bytes .../tests/golden/random_202_dither.bin | Bin 0 -> 19230 bytes .../tests/golden/random_202_dither_thr100.bin | Bin 0 -> 19230 bytes .../brother-ql/tests/golden/random_202_lq.bin | Bin 0 -> 19230 bytes .../tests/golden/random_202_thr0.bin | Bin 0 -> 19230 bytes .../tests/golden/random_202_thr100.bin | Bin 0 -> 19230 bytes .../tests/golden/random_202_thr50.bin | Bin 0 -> 19230 bytes .../brother-ql/tests/golden/random_202_x1.bin | Bin 0 -> 19230 bytes .../brother-ql/tests/golden/random_202_x2.bin | Bin 0 -> 38050 bytes crates/brother-ql/tests/golden/random_236.png | Bin 0 -> 7377 bytes .../tests/golden/random_271x696.png | Bin 0 -> 24375 bytes .../tests/golden/random_300x696.png | Bin 0 -> 27149 bytes .../tests/golden/random_306x300.png | Bin 0 -> 12044 bytes crates/brother-ql/tests/golden/random_404.png | Bin 0 -> 21065 bytes .../tests/golden/random_404_dpi600.bin | Bin 0 -> 38016 bytes .../golden/random_404_dpi600_compress.bin | Bin 0 -> 14201 bytes .../tests/golden/random_500x200.png | Bin 0 -> 12868 bytes .../tests/golden/random_696x271.png | Bin 0 -> 23916 bytes .../tests/golden/random_696x300.png | Bin 0 -> 26468 bytes crates/brother-ql/tests/golden/round_d24.bin | Bin 0 -> 22392 bytes .../tests/golden/sparse_1164x301.png | Bin 0 -> 6765 bytes .../tests/golden/sparse_696x301.png | Bin 0 -> 4535 bytes crates/brother-ql/tests/golden/white_202.png | Bin 0 -> 126 bytes .../tests/golden/white_202_compress.bin | Bin 0 -> 1456 bytes .../brother-ql/tests/golden/white_202_x1.bin | Bin 0 -> 19230 bytes .../brother-ql/tests/golden/white_202_x2.bin | Bin 0 -> 38050 bytes crates/brother-ql/tests/network.rs | 187 +++ crates/brother-ql/tools/golden.py | 213 +++ crates/lamp-label/Cargo.toml | 15 + crates/lamp-label/src/font5x7.rs | 57 + crates/lamp-label/src/lib.rs | 211 +++ crates/lamp-label/src/qr.rs | 379 ++++++ crates/lamp-label/src/text.rs | 523 ++++++++ crates/lamp-label/tests/golden.rs | 294 ++++ .../tests/golden/label_12345678.png | Bin 0 -> 747 bytes .../lamp-label/tests/golden/label_L0001.png | Bin 0 -> 516 bytes .../lamp-label/tests/golden/label_L0002.png | Bin 0 -> 569 bytes .../lamp-label/tests/golden/label_L0003.png | Bin 0 -> 575 bytes .../lamp-label/tests/golden/label_L0004.png | Bin 0 -> 549 bytes .../lamp-label/tests/golden/label_L0005.png | Bin 0 -> 584 bytes .../lamp-label/tests/golden/label_L0006.png | Bin 0 -> 574 bytes .../lamp-label/tests/golden/label_L0007.png | Bin 0 -> 548 bytes .../lamp-label/tests/golden/label_L0008.png | Bin 0 -> 592 bytes .../lamp-label/tests/golden/label_L0009.png | Bin 0 -> 584 bytes .../lamp-label/tests/golden/label_L0010.png | Bin 0 -> 535 bytes .../lamp-label/tests/golden/label_L0011.png | Bin 0 -> 529 bytes .../lamp-label/tests/golden/label_L0012.png | Bin 0 -> 569 bytes .../lamp-label/tests/golden/label_L0013.png | Bin 0 -> 591 bytes .../lamp-label/tests/golden/label_L0014.png | Bin 0 -> 550 bytes .../lamp-label/tests/golden/label_L0015.png | Bin 0 -> 567 bytes .../lamp-label/tests/golden/label_L0016.png | Bin 0 -> 598 bytes .../lamp-label/tests/golden/label_L0017.png | Bin 0 -> 553 bytes .../lamp-label/tests/golden/label_L0018.png | Bin 0 -> 573 bytes .../lamp-label/tests/golden/label_L0019.png | Bin 0 -> 574 bytes .../lamp-label/tests/golden/label_L0020.png | Bin 0 -> 573 bytes .../lamp-label/tests/golden/label_L0123.png | Bin 0 -> 614 bytes .../tests/golden/label_L0123456789012.png | Bin 0 -> 661 bytes ...12345678901234567890123456789012345678.png | Bin 0 -> 807 bytes .../lamp-label/tests/golden/label_L0999.png | Bin 0 -> 592 bytes .../lamp-label/tests/golden/label_L1000.png | Bin 0 -> 547 bytes .../lamp-label/tests/golden/label_L12345.png | Bin 0 -> 651 bytes .../lamp-label/tests/golden/label_L123456.png | Bin 0 -> 705 bytes crates/lamp-label/tests/golden/label_L9.png | Bin 0 -> 506 bytes ...BCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHI.png | Bin 0 -> 934 bytes .../tests/golden/label_LAMP-7_X.png | Bin 0 -> 637 bytes .../lamp-label/tests/golden/label_LAVA-7.png | Bin 0 -> 604 bytes .../tests/golden/label_WWWWWWWWWW.png | Bin 0 -> 532 bytes ...bel_https___example_com_lamp_L0006_x_1.png | Bin 0 -> 680 bytes .../lamp-label/tests/golden/label_lamp_7.png | Bin 0 -> 617 bytes crates/lamp-label/tests/golden/labels.txt | 35 + .../lamp-label/tests/golden/qr_matrices.txt | 704 ++++++++++ crates/lamp-label/tests/golden/text_info.txt | 10 + crates/lamp-label/tools/golden.py | 161 +++ crates/tm30/Cargo.toml | 12 + crates/tm30/README.md | 134 ++ crates/tm30/data/ciecam02_matrices.csv | 3 + crates/tm30/data/cmf_cie1931_2deg_360_780.csv | 422 ++++++ crates/tm30/data/cmf_cie1931_2deg_380_780.csv | 402 ++++++ .../tm30/data/cmf_cie1964_10deg_380_780.csv | 402 ++++++ crates/tm30/data/d_series_basis_380_780.csv | 402 ++++++ crates/tm30/data/tcs_cie2017_380_780.csv | 402 ++++++ crates/tm30/examples/bench.rs | 38 + crates/tm30/src/cam.rs | 137 ++ crates/tm30/src/cct.rs | 152 +++ crates/tm30/src/colorimetry.rs | 154 +++ crates/tm30/src/data.rs | 139 ++ crates/tm30/src/lib.rs | 374 ++++++ crates/tm30/src/numeric.rs | 162 +++ crates/tm30/tests/golden.rs | 235 ++++ crates/tm30/tests/golden/blackbody_2700K.json | 1183 ++++++++++++++++ crates/tm30/tests/golden/blackbody_4300K.json | 1183 ++++++++++++++++ crates/tm30/tests/golden/blackbody_4700K.json | 1183 ++++++++++++++++ crates/tm30/tests/golden/daylight_10000K.json | 455 +++++++ crates/tm30/tests/golden/daylight_6500K.json | 455 +++++++ crates/tm30/tests/golden/grid_10nm_D50.json | 323 +++++ .../tm30/tests/golden/hpcs_grid_LED_B3.json | 941 +++++++++++++ .../golden/hpcs_grid_blackbody_3000K.json | 941 +++++++++++++ crates/tm30/tests/golden/illuminant_A.json | 435 ++++++ crates/tm30/tests/golden/illuminant_D50.json | 435 ++++++ crates/tm30/tests/golden/illuminant_D65.json | 435 ++++++ crates/tm30/tests/golden/illuminant_FL1.json | 403 ++++++ crates/tm30/tests/golden/illuminant_FL10.json | 403 ++++++ crates/tm30/tests/golden/illuminant_FL11.json | 403 ++++++ crates/tm30/tests/golden/illuminant_FL12.json | 403 ++++++ crates/tm30/tests/golden/illuminant_FL2.json | 403 ++++++ crates/tm30/tests/golden/illuminant_FL3.json | 403 ++++++ crates/tm30/tests/golden/illuminant_FL4.json | 403 ++++++ crates/tm30/tests/golden/illuminant_FL5.json | 403 ++++++ crates/tm30/tests/golden/illuminant_FL6.json | 403 ++++++ crates/tm30/tests/golden/illuminant_FL7.json | 403 ++++++ crates/tm30/tests/golden/illuminant_FL8.json | 403 ++++++ crates/tm30/tests/golden/illuminant_FL9.json | 403 ++++++ crates/tm30/tests/golden/illuminant_HP1.json | 403 ++++++ crates/tm30/tests/golden/illuminant_HP2.json | 403 ++++++ crates/tm30/tests/golden/illuminant_HP3.json | 403 ++++++ crates/tm30/tests/golden/illuminant_HP4.json | 403 ++++++ crates/tm30/tests/golden/illuminant_HP5.json | 403 ++++++ .../tm30/tests/golden/illuminant_LED_B1.json | 403 ++++++ .../tm30/tests/golden/illuminant_LED_B2.json | 403 ++++++ .../tm30/tests/golden/illuminant_LED_B3.json | 403 ++++++ .../tm30/tests/golden/illuminant_LED_B4.json | 403 ++++++ .../tm30/tests/golden/illuminant_LED_B5.json | 403 ++++++ .../tm30/tests/golden/illuminant_LED_BH1.json | 403 ++++++ .../tests/golden/illuminant_LED_RGB1.json | 403 ++++++ .../tm30/tests/golden/illuminant_LED_V1.json | 403 ++++++ .../tm30/tests/golden/illuminant_LED_V2.json | 403 ++++++ .../tests/golden/irregular_grid_FL11.json | 725 ++++++++++ crates/tm30/tests/golden/lamp_L0001.json | 941 +++++++++++++ crates/tm30/tests/golden/lamp_L0002.json | 941 +++++++++++++ crates/tm30/tests/golden/lamp_L0003.json | 941 +++++++++++++ crates/tm30/tests/golden/lamp_L0004.json | 941 +++++++++++++ crates/tm30/tests/golden/lamp_L0005.json | 941 +++++++++++++ crates/tm30/tests/golden/lamp_L0006.json | 941 +++++++++++++ crates/tm30/tests/golden/lamp_L0007.json | 941 +++++++++++++ crates/tm30/tests/golden/lamp_L0008.json | 941 +++++++++++++ crates/tm30/tests/golden/lamp_L0009.json | 941 +++++++++++++ crates/tm30/tests/golden/lamp_L0010.json | 941 +++++++++++++ crates/tm30/tests/golden/lamp_L0011.json | 941 +++++++++++++ crates/tm30/tests/golden/negated_FL2.json | 403 ++++++ .../tm30/tests/golden/noisy_lamp_L0001.json | 941 +++++++++++++ .../tests/golden/partial_400_700_FL4.json | 483 +++++++ crates/tm30/tools/extract_data.py | 162 +++ crates/tm30/tools/golden.py | 214 +++ src/bundle.rs | 346 +++++ src/calibration.rs | 1053 +++++++++++++++ src/main.rs | 492 +++++++ src/measure.rs | 162 +++ src/prompt.rs | 65 + src/pyjson.rs | 137 ++ src/station.rs | 665 +++++++++ tests/golden/bundles/cases.json | 89 ++ tests/golden/bundles/export_avg5/metrics.json | 74 ++ tests/golden/bundles/export_avg5/spd.csv | 351 +++++ tests/golden/bundles/export_avg5/tm30.csv | 17 + .../bundles/external_power/metrics.json | 74 ++ tests/golden/bundles/external_power/spd.csv | 351 +++++ tests/golden/bundles/external_power/tm30.csv | 17 + .../bundles/harmonics_single/metrics.json | 85 ++ tests/golden/bundles/harmonics_single/spd.csv | 351 +++++ .../golden/bundles/harmonics_single/tm30.csv | 17 + .../golden/bundles/station_full/metrics.json | 90 ++ tests/golden/bundles/station_full/spd.csv | 351 +++++ tests/golden/bundles/station_full/tm30.csv | 17 + tests/station.rs | 203 +++ tools/make_bundles.py | 65 + 241 files changed, 46390 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 160000 HPCS6500 create mode 100644 README.md create mode 100644 crates/brother-ql/Cargo.toml create mode 100644 crates/brother-ql/src/bitmap.rs create mode 100644 crates/brother-ql/src/conversion.rs create mode 100644 crates/brother-ql/src/error.rs create mode 100644 crates/brother-ql/src/labels.rs create mode 100644 crates/brother-ql/src/lib.rs create mode 100644 crates/brother-ql/src/models.rs create mode 100644 crates/brother-ql/src/network.rs create mode 100644 crates/brother-ql/src/packbits.rs create mode 100644 crates/brother-ql/src/raster.rs create mode 100644 crates/brother-ql/tests/golden.rs create mode 100644 crates/brother-ql/tests/golden/black_202.png create mode 100644 crates/brother-ql/tests/golden/black_202_compress.bin create mode 100644 crates/brother-ql/tests/golden/black_202_x1.bin create mode 100644 crates/brother-ql/tests/golden/black_202_x2.bin create mode 100644 crates/brother-ql/tests/golden/checker_202.png create mode 100644 crates/brother-ql/tests/golden/checker_202_compress.bin create mode 100644 crates/brother-ql/tests/golden/checker_202_x1.bin create mode 100644 crates/brother-ql/tests/golden/checker_202_x2.bin create mode 100644 crates/brother-ql/tests/golden/corner_bl.png create mode 100644 crates/brother-ql/tests/golden/corner_bl_x1.bin create mode 100644 crates/brother-ql/tests/golden/corner_bl_x2.bin create mode 100644 crates/brother-ql/tests/golden/corner_br.png create mode 100644 crates/brother-ql/tests/golden/corner_br_rot0.bin create mode 100644 crates/brother-ql/tests/golden/corner_br_x1.bin create mode 100644 crates/brother-ql/tests/golden/corner_br_x2.bin create mode 100644 crates/brother-ql/tests/golden/corner_tl.png create mode 100644 crates/brother-ql/tests/golden/corner_tl_rot0.bin create mode 100644 crates/brother-ql/tests/golden/corner_tl_rot180.bin create mode 100644 crates/brother-ql/tests/golden/corner_tl_rot270.bin create mode 100644 crates/brother-ql/tests/golden/corner_tl_rot90.bin create mode 100644 crates/brother-ql/tests/golden/corner_tl_x1.bin create mode 100644 crates/brother-ql/tests/golden/corner_tl_x2.bin create mode 100644 crates/brother-ql/tests/golden/corner_tr.png create mode 100644 crates/brother-ql/tests/golden/corner_tr_x1.bin create mode 100644 crates/brother-ql/tests/golden/corner_tr_x2.bin create mode 100644 crates/brother-ql/tests/golden/diecut62x29_auto_rotate.bin create mode 100644 crates/brother-ql/tests/golden/endless29_306.bin create mode 100644 crates/brother-ql/tests/golden/endless62_696.bin create mode 100644 crates/brother-ql/tests/golden/endless62_dpi600.bin create mode 100644 crates/brother-ql/tests/golden/endless62_resize500.bin create mode 100644 crates/brother-ql/tests/golden/endless62_rot90.bin create mode 100644 crates/brother-ql/tests/golden/label_L0001.png create mode 100644 crates/brother-ql/tests/golden/label_L0001_x1.bin create mode 100644 crates/brother-ql/tests/golden/label_L0001_x2.bin create mode 100644 crates/brother-ql/tests/golden/label_L0006.png create mode 100644 crates/brother-ql/tests/golden/label_L0006_compress_x2.bin create mode 100644 crates/brother-ql/tests/golden/label_L0006_nocut.bin create mode 100644 crates/brother-ql/tests/golden/label_L0006_x1.bin create mode 100644 crates/brother-ql/tests/golden/label_L0006_x2.bin create mode 100644 crates/brother-ql/tests/golden/label_L0123.png create mode 100644 crates/brother-ql/tests/golden/label_L0123_x1.bin create mode 100644 crates/brother-ql/tests/golden/label_L0123_x2.bin create mode 100644 crates/brother-ql/tests/golden/label_L12345.png create mode 100644 crates/brother-ql/tests/golden/label_L12345_x1.bin create mode 100644 crates/brother-ql/tests/golden/label_L12345_x2.bin create mode 100644 crates/brother-ql/tests/golden/label_L9.png create mode 100644 crates/brother-ql/tests/golden/label_L9_x1.bin create mode 100644 crates/brother-ql/tests/golden/label_L9_x2.bin create mode 100644 crates/brother-ql/tests/golden/manifest.txt create mode 100644 crates/brother-ql/tests/golden/multi_labels.bin create mode 100644 crates/brother-ql/tests/golden/ql1100_102.bin create mode 100644 crates/brother-ql/tests/golden/ql1100_62.bin create mode 100644 crates/brother-ql/tests/golden/ql500_29.bin create mode 100644 crates/brother-ql/tests/golden/ql570_62x29.bin create mode 100644 crates/brother-ql/tests/golden/ql700_62_compress_ignored.bin create mode 100644 crates/brother-ql/tests/golden/ql800_23x23_x2.bin create mode 100644 crates/brother-ql/tests/golden/random_1392x150.png create mode 100644 crates/brother-ql/tests/golden/random_202.png create mode 100644 crates/brother-ql/tests/golden/random_202_compress.bin create mode 100644 crates/brother-ql/tests/golden/random_202_dither.bin create mode 100644 crates/brother-ql/tests/golden/random_202_dither_thr100.bin create mode 100644 crates/brother-ql/tests/golden/random_202_lq.bin create mode 100644 crates/brother-ql/tests/golden/random_202_thr0.bin create mode 100644 crates/brother-ql/tests/golden/random_202_thr100.bin create mode 100644 crates/brother-ql/tests/golden/random_202_thr50.bin create mode 100644 crates/brother-ql/tests/golden/random_202_x1.bin create mode 100644 crates/brother-ql/tests/golden/random_202_x2.bin create mode 100644 crates/brother-ql/tests/golden/random_236.png create mode 100644 crates/brother-ql/tests/golden/random_271x696.png create mode 100644 crates/brother-ql/tests/golden/random_300x696.png create mode 100644 crates/brother-ql/tests/golden/random_306x300.png create mode 100644 crates/brother-ql/tests/golden/random_404.png create mode 100644 crates/brother-ql/tests/golden/random_404_dpi600.bin create mode 100644 crates/brother-ql/tests/golden/random_404_dpi600_compress.bin create mode 100644 crates/brother-ql/tests/golden/random_500x200.png create mode 100644 crates/brother-ql/tests/golden/random_696x271.png create mode 100644 crates/brother-ql/tests/golden/random_696x300.png create mode 100644 crates/brother-ql/tests/golden/round_d24.bin create mode 100644 crates/brother-ql/tests/golden/sparse_1164x301.png create mode 100644 crates/brother-ql/tests/golden/sparse_696x301.png create mode 100644 crates/brother-ql/tests/golden/white_202.png create mode 100644 crates/brother-ql/tests/golden/white_202_compress.bin create mode 100644 crates/brother-ql/tests/golden/white_202_x1.bin create mode 100644 crates/brother-ql/tests/golden/white_202_x2.bin create mode 100644 crates/brother-ql/tests/network.rs create mode 100644 crates/brother-ql/tools/golden.py create mode 100644 crates/lamp-label/Cargo.toml create mode 100644 crates/lamp-label/src/font5x7.rs create mode 100644 crates/lamp-label/src/lib.rs create mode 100644 crates/lamp-label/src/qr.rs create mode 100644 crates/lamp-label/src/text.rs create mode 100644 crates/lamp-label/tests/golden.rs create mode 100644 crates/lamp-label/tests/golden/label_12345678.png create mode 100644 crates/lamp-label/tests/golden/label_L0001.png create mode 100644 crates/lamp-label/tests/golden/label_L0002.png create mode 100644 crates/lamp-label/tests/golden/label_L0003.png create mode 100644 crates/lamp-label/tests/golden/label_L0004.png create mode 100644 crates/lamp-label/tests/golden/label_L0005.png create mode 100644 crates/lamp-label/tests/golden/label_L0006.png create mode 100644 crates/lamp-label/tests/golden/label_L0007.png create mode 100644 crates/lamp-label/tests/golden/label_L0008.png create mode 100644 crates/lamp-label/tests/golden/label_L0009.png create mode 100644 crates/lamp-label/tests/golden/label_L0010.png create mode 100644 crates/lamp-label/tests/golden/label_L0011.png create mode 100644 crates/lamp-label/tests/golden/label_L0012.png create mode 100644 crates/lamp-label/tests/golden/label_L0013.png create mode 100644 crates/lamp-label/tests/golden/label_L0014.png create mode 100644 crates/lamp-label/tests/golden/label_L0015.png create mode 100644 crates/lamp-label/tests/golden/label_L0016.png create mode 100644 crates/lamp-label/tests/golden/label_L0017.png create mode 100644 crates/lamp-label/tests/golden/label_L0018.png create mode 100644 crates/lamp-label/tests/golden/label_L0019.png create mode 100644 crates/lamp-label/tests/golden/label_L0020.png create mode 100644 crates/lamp-label/tests/golden/label_L0123.png create mode 100644 crates/lamp-label/tests/golden/label_L0123456789012.png create mode 100644 crates/lamp-label/tests/golden/label_L012345678901234567890123456789012345678.png create mode 100644 crates/lamp-label/tests/golden/label_L0999.png create mode 100644 crates/lamp-label/tests/golden/label_L1000.png create mode 100644 crates/lamp-label/tests/golden/label_L12345.png create mode 100644 crates/lamp-label/tests/golden/label_L123456.png create mode 100644 crates/lamp-label/tests/golden/label_L9.png create mode 100644 crates/lamp-label/tests/golden/label_LABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHI.png create mode 100644 crates/lamp-label/tests/golden/label_LAMP-7_X.png create mode 100644 crates/lamp-label/tests/golden/label_LAVA-7.png create mode 100644 crates/lamp-label/tests/golden/label_WWWWWWWWWW.png create mode 100644 crates/lamp-label/tests/golden/label_https___example_com_lamp_L0006_x_1.png create mode 100644 crates/lamp-label/tests/golden/label_lamp_7.png create mode 100644 crates/lamp-label/tests/golden/labels.txt create mode 100644 crates/lamp-label/tests/golden/qr_matrices.txt create mode 100644 crates/lamp-label/tests/golden/text_info.txt create mode 100644 crates/lamp-label/tools/golden.py create mode 100644 crates/tm30/Cargo.toml create mode 100644 crates/tm30/README.md create mode 100644 crates/tm30/data/ciecam02_matrices.csv create mode 100644 crates/tm30/data/cmf_cie1931_2deg_360_780.csv create mode 100644 crates/tm30/data/cmf_cie1931_2deg_380_780.csv create mode 100644 crates/tm30/data/cmf_cie1964_10deg_380_780.csv create mode 100644 crates/tm30/data/d_series_basis_380_780.csv create mode 100644 crates/tm30/data/tcs_cie2017_380_780.csv create mode 100644 crates/tm30/examples/bench.rs create mode 100644 crates/tm30/src/cam.rs create mode 100644 crates/tm30/src/cct.rs create mode 100644 crates/tm30/src/colorimetry.rs create mode 100644 crates/tm30/src/data.rs create mode 100644 crates/tm30/src/lib.rs create mode 100644 crates/tm30/src/numeric.rs create mode 100644 crates/tm30/tests/golden.rs create mode 100644 crates/tm30/tests/golden/blackbody_2700K.json create mode 100644 crates/tm30/tests/golden/blackbody_4300K.json create mode 100644 crates/tm30/tests/golden/blackbody_4700K.json create mode 100644 crates/tm30/tests/golden/daylight_10000K.json create mode 100644 crates/tm30/tests/golden/daylight_6500K.json create mode 100644 crates/tm30/tests/golden/grid_10nm_D50.json create mode 100644 crates/tm30/tests/golden/hpcs_grid_LED_B3.json create mode 100644 crates/tm30/tests/golden/hpcs_grid_blackbody_3000K.json create mode 100644 crates/tm30/tests/golden/illuminant_A.json create mode 100644 crates/tm30/tests/golden/illuminant_D50.json create mode 100644 crates/tm30/tests/golden/illuminant_D65.json create mode 100644 crates/tm30/tests/golden/illuminant_FL1.json create mode 100644 crates/tm30/tests/golden/illuminant_FL10.json create mode 100644 crates/tm30/tests/golden/illuminant_FL11.json create mode 100644 crates/tm30/tests/golden/illuminant_FL12.json create mode 100644 crates/tm30/tests/golden/illuminant_FL2.json create mode 100644 crates/tm30/tests/golden/illuminant_FL3.json create mode 100644 crates/tm30/tests/golden/illuminant_FL4.json create mode 100644 crates/tm30/tests/golden/illuminant_FL5.json create mode 100644 crates/tm30/tests/golden/illuminant_FL6.json create mode 100644 crates/tm30/tests/golden/illuminant_FL7.json create mode 100644 crates/tm30/tests/golden/illuminant_FL8.json create mode 100644 crates/tm30/tests/golden/illuminant_FL9.json create mode 100644 crates/tm30/tests/golden/illuminant_HP1.json create mode 100644 crates/tm30/tests/golden/illuminant_HP2.json create mode 100644 crates/tm30/tests/golden/illuminant_HP3.json create mode 100644 crates/tm30/tests/golden/illuminant_HP4.json create mode 100644 crates/tm30/tests/golden/illuminant_HP5.json create mode 100644 crates/tm30/tests/golden/illuminant_LED_B1.json create mode 100644 crates/tm30/tests/golden/illuminant_LED_B2.json create mode 100644 crates/tm30/tests/golden/illuminant_LED_B3.json create mode 100644 crates/tm30/tests/golden/illuminant_LED_B4.json create mode 100644 crates/tm30/tests/golden/illuminant_LED_B5.json create mode 100644 crates/tm30/tests/golden/illuminant_LED_BH1.json create mode 100644 crates/tm30/tests/golden/illuminant_LED_RGB1.json create mode 100644 crates/tm30/tests/golden/illuminant_LED_V1.json create mode 100644 crates/tm30/tests/golden/illuminant_LED_V2.json create mode 100644 crates/tm30/tests/golden/irregular_grid_FL11.json create mode 100644 crates/tm30/tests/golden/lamp_L0001.json create mode 100644 crates/tm30/tests/golden/lamp_L0002.json create mode 100644 crates/tm30/tests/golden/lamp_L0003.json create mode 100644 crates/tm30/tests/golden/lamp_L0004.json create mode 100644 crates/tm30/tests/golden/lamp_L0005.json create mode 100644 crates/tm30/tests/golden/lamp_L0006.json create mode 100644 crates/tm30/tests/golden/lamp_L0007.json create mode 100644 crates/tm30/tests/golden/lamp_L0008.json create mode 100644 crates/tm30/tests/golden/lamp_L0009.json create mode 100644 crates/tm30/tests/golden/lamp_L0010.json create mode 100644 crates/tm30/tests/golden/lamp_L0011.json create mode 100644 crates/tm30/tests/golden/negated_FL2.json create mode 100644 crates/tm30/tests/golden/noisy_lamp_L0001.json create mode 100644 crates/tm30/tests/golden/partial_400_700_FL4.json create mode 100644 crates/tm30/tools/extract_data.py create mode 100644 crates/tm30/tools/golden.py create mode 100644 src/bundle.rs create mode 100644 src/calibration.rs create mode 100644 src/main.rs create mode 100644 src/measure.rs create mode 100644 src/prompt.rs create mode 100644 src/pyjson.rs create mode 100644 src/station.rs create mode 100644 tests/golden/bundles/cases.json create mode 100644 tests/golden/bundles/export_avg5/metrics.json create mode 100644 tests/golden/bundles/export_avg5/spd.csv create mode 100644 tests/golden/bundles/export_avg5/tm30.csv create mode 100644 tests/golden/bundles/external_power/metrics.json create mode 100644 tests/golden/bundles/external_power/spd.csv create mode 100644 tests/golden/bundles/external_power/tm30.csv create mode 100644 tests/golden/bundles/harmonics_single/metrics.json create mode 100644 tests/golden/bundles/harmonics_single/spd.csv create mode 100644 tests/golden/bundles/harmonics_single/tm30.csv create mode 100644 tests/golden/bundles/station_full/metrics.json create mode 100644 tests/golden/bundles/station_full/spd.csv create mode 100644 tests/golden/bundles/station_full/tm30.csv create mode 100644 tests/station.rs create mode 100644 tools/make_bundles.py diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..82d8959 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# test data must stay byte-exact on every platform +* text=auto eol=lf +*.png binary +*.bin binary +*.pcap binary +tests/golden/** -text +crates/*/tests/golden/** -text diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..65f63d8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +target/ +*.pyc +__pycache__/ diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..6578cd5 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "HPCS6500"] + path = HPCS6500 + url = https://git.b4l.co.th/B4L/HPCS6500-py.git diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..709393a --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,1184 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "android_system_properties" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae221649c9976a6f6c56ae1facf410f3ddb33cc661c4b7b61020a912d4237fbc" +dependencies = [ + "libc", +] + +[[package]] +name = "anstream" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" + +[[package]] +name = "anstyle-parse" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys 0.61.2", +] + +[[package]] +name = "anyhow" +version = "1.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" + +[[package]] +name = "autocfg" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" + +[[package]] +name = "base64" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac07cdecf99051d9a5238b80f35af32cdeba5b336e55d957b318b50137e18da5" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06" + +[[package]] +name = "block2" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5" +dependencies = [ + "objc2", +] + +[[package]] +name = "brother-ql" +version = "0.1.0" +dependencies = [ + "png", +] + +[[package]] +name = "bumpalo" +version = "3.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" + +[[package]] +name = "bytes" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" + +[[package]] +name = "cc" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877bf67ac8e52449eb2f9e98a344ea163beb70dd1f9eebe3cc5357dcfeaee4df" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600" + +[[package]] +name = "cfg_aliases" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527" + +[[package]] +name = "chrono" +version = "0.4.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" +dependencies = [ + "iana-time-zone", + "num-traits", + "windows-link", +] + +[[package]] +name = "clap" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa8876b300ab35ba921adea3dfd70157a46249b33f95c9084ae5709785478946" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0797fb7aeb1406c84efac526901f7ec3ead2124f946b494e72879d4b54704d" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9c751b79415d4e559e3d1fcf128e09e720eb673a06d26cf6f392d37d75b66e0" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 3.0.9", +] + +[[package]] +name = "clap_lex" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c133bc6a41be0d194c306b5506d15e6feeea7b1d6604bd3f8310dfb2ca96486" + +[[package]] +name = "colorchoice" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" + +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "core_maths" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77745e017f5edba1a9c1d854f6f3a52dac8a12dd5af5d2f54aecf61e43d80d30" +dependencies = [ + "libm", +] + +[[package]] +name = "crc32fast" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ba106e844045ddc02c20768ac4b0b7cb45f2cc2ecbd833ac9f5dacb183c2055" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "ctrlc" +version = "3.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0b1fab2ae45819af2d0731d60f2afe17227ebb1a1538a236da84c93e9a60162" +dependencies = [ + "dispatch2", + "nix 0.31.3", + "windows-sys 0.61.2", +] + +[[package]] +name = "dispatch2" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" +dependencies = [ + "bitflags 2.13.2", + "block2", + "libc", + "objc2", +] + +[[package]] +name = "equivalent" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00d174d5400e5e8fd687ad1049e2f578285fa914201b1af7e8b112a4546bd826" + +[[package]] +name = "fdeflate" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c66915cc5391097de7a2b0b972e8505aa33c0df401fd3a6811dbdb32881ba48" + +[[package]] +name = "flate2" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e634e2e0ebac1ee034020da1ca582e17ffe4e0f5e985823721e168928136dcb" +dependencies = [ + "crc32fast", + "miniz_oxide 0.9.1", + "zlib-rs", +] + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] +name = "fontdue" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e796cb6894e6418daacea84b28dd4f98d3b32c74d5bb452ba1ecfbf5ad8e84ca" +dependencies = [ + "hashbrown 0.15.5", + "ttf-parser", +] + +[[package]] +name = "futures-core" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e" + +[[package]] +name = "futures-task" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd" + +[[package]] +name = "futures-util" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "slab", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.1.5", +] + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hpcs6500" +version = "0.2.0" +dependencies = [ + "chrono", + "clap", + "ctrlc", + "serde", + "serde_json", + "serialport", + "thiserror", +] + +[[package]] +name = "http" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "918d3568bebf352712bc2ef3d46a8bcf1a75b373be6539de198e9105cbbf9ce0" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "indexmap" +version = "2.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855" +dependencies = [ + "equivalent", + "hashbrown 0.17.1", +] + +[[package]] +name = "io-kit-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "617ee6cf8e3f66f3b4ea67a4058564628cde41901316e19f559e14c7c72c5e7b" +dependencies = [ + "core-foundation-sys", + "mach2", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "js-sys" +version = "0.3.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7883d941dae510fb2d978fc3fe018c71c9e2892fd38854de3e8b92c2e5ad9cc5" +dependencies = [ + "cfg-if", + "futures-util", + "wasm-bindgen", +] + +[[package]] +name = "lamp-label" +version = "0.1.0" +dependencies = [ + "brother-ql", + "fontdue", + "png", + "qrcode", +] + +[[package]] +name = "lamp-testbench" +version = "0.1.0" +dependencies = [ + "anyhow", + "chrono", + "clap", + "ctrlc", + "hpcs6500", + "lamp-label", + "serde_json", + "serialport", + "thiserror", + "tm30", + "ureq", +] + +[[package]] +name = "libc" +version = "0.2.191" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65cd87c9a6d60536580b316ad985726104730a5151c99845f2490428ef91240a" + +[[package]] +name = "libm" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + +[[package]] +name = "libudev" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b324152da65df7bb95acfcaab55e3097ceaab02fb19b228a9eb74d55f135e0" +dependencies = [ + "libc", + "libudev-sys", +] + +[[package]] +name = "libudev-sys" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c8469b4a23b962c1396b9b451dda50ef5b283e8dd309d69033475fa9b334324" +dependencies = [ + "libc", + "pkg-config", +] + +[[package]] +name = "log" +version = "0.4.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6" + +[[package]] +name = "mach2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d640282b302c0bb0a2a8e0233ead9035e3bed871f0b7e81fe4a1ec829765db44" +dependencies = [ + "libc", +] + +[[package]] +name = "memchr" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "miniz_oxide" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b63fbc4a50860e98e7b2aa7804ded1db5cbc3aff9193adaff57a6931bf7c4b4c" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "nix" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "libc", +] + +[[package]] +name = "nix" +version = "0.31.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf20d2fde8ff38632c426f1165ed7436270b44f199fc55284c38276f9db47c3d" +dependencies = [ + "bitflags 2.13.2", + "cfg-if", + "cfg_aliases", + "libc", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "objc2" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08849bbd4767dfae9457696856ae1c84fe4e0281bbe4a7abff2d0e06fb7981f8" +dependencies = [ + "objc2-encode", +] + +[[package]] +name = "objc2-encode" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "pkg-config" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6b464fbc74e149a392436b17d523f769e057cb6877f6a5c4618bc6f11800548" + +[[package]] +name = "png" +version = "0.17.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526" +dependencies = [ + "bitflags 1.3.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide 0.8.9", +] + +[[package]] +name = "proc-macro2" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "qrcode" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d68782463e408eb1e668cf6152704bd856c78c5b6417adaee3203d8f4c1fc9ec" + +[[package]] +name = "quote" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustls" +version = "0.23.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48e13bd8c0e9365c43cfa5c9e8f9ad49d3c8444926c9aac819e0e4dc503c8fdf" +dependencies = [ + "log", + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pki-types" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f4925028c7eb5d1fcdaf196971378ed9d2c1c4efc7dc5d011256f76c99c0a96" +dependencies = [ + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4443b1b6d39d7c663139942cc4558262562d2c84123bb6282ef177009ca8b281" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "serde" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.9", +] + +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "foldhash 0.2.0", + "indexmap", + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serialport" +version = "4.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba5f8f29aa20853c4e3e85a33ec580eb66be1f057142e77a333834a318bacf2" +dependencies = [ + "bitflags 2.13.2", + "cfg-if", + "core-foundation", + "core-foundation-sys", + "io-kit-sys", + "libudev", + "mach2", + "nix 0.26.4", + "scopeguard", + "unescaper", + "windows-sys 0.52.0", +] + +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + +[[package]] +name = "simd-adler32" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea" + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "2.0.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "3.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d78c8dee4c7bf0e14673097256fed6142ce9d3b85a408189d07482442145823b" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "2.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09e52cb86a36cede5cb101bf8908837b3e4c6e5e59fe7fd85c23fb56200d189e" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe5197923287db20a58125f0bc85c062f7f2c892de97b18c356f9efb14b28524" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.9", +] + +[[package]] +name = "tm30" +version = "0.1.0" +dependencies = [ + "serde_json", +] + +[[package]] +name = "ttf-parser" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31" +dependencies = [ + "core_maths", +] + +[[package]] +name = "unescaper" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7285e83a80ce76f5e7bce79fa41f68d78ba62d1003cf27bf748ab24413808cf4" +dependencies = [ + "thiserror", +] + +[[package]] +name = "unicode-ident" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2c754d6c33795a1c324727428e5a7dedb5b06195f9890bdbcba760d3e246563" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "ureq" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cde93ff05758a36a851a398a772b0b79a82fbe3c186a46f2696baaeaf84c966b" +dependencies = [ + "base64", + "flate2", + "log", + "percent-encoding", + "rustls", + "rustls-pki-types", + "ureq-proto", + "utf8-zero", + "webpki-roots", +] + +[[package]] +name = "ureq-proto" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841583fc36089d7d59419568ae157f43a5a03a2e5a81ba87c77d1596ef46e922" +dependencies = [ + "base64", + "http", + "httparse", + "log", +] + +[[package]] +name = "utf8-zero" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8c0a043c9540bae7c578c88f91dda8bd82e59ae27c21baca69c8b191aaf5a6e" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasm-bindgen" +version = "0.2.129" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb54f33acc68fd454578d9820b0bde1a1a3d17aa17bb7b6595806d02886d409" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.129" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e29d0c35b16e224a7eeb5cd2d25e3e1968fbd65604117b44d3b789d00ee8535" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.129" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f501a8bc3719dba86ef8ae4728879c08001bea749eb1333ac5b91e040e2a6b7" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 3.0.9", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.129" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23f0c9c52aa7cd7d77769a4cfe2a9adb1b331f489a41d912ce14513d5ab995c6" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "webpki-roots" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c1c8e20c8a38fc7d65abfe74eb7280e4aa667e8eec8bc84996d2874810748d9" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "zeroize" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13084392c5e4bc371903e2935a5eaeed24905a7511356b883835e18a78f6879" + +[[package]] +name = "zlib-rs" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b268e58e7c693d7c271f93ffc4ba3b380412554231c85bf61ca7af91042a4112" + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..15a7236 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,36 @@ +[package] +name = "lamp-testbench" +description = "Lamp testbench around the HPCS 6500: measurement station, lamp bundles, ID labels, LED light calibration" +version.workspace = true +edition.workspace = true +publish.workspace = true +default-run = "lampbench" + +[[bin]] +name = "lampbench" +path = "src/main.rs" + +[workspace] +resolver = "3" +members = [".", "crates/tm30", "crates/brother-ql", "crates/lamp-label"] + +[workspace.package] +version = "0.1.0" +edition = "2024" +publish = false + +[dependencies] +hpcs6500 = { path = "HPCS6500", default-features = false } +tm30 = { path = "crates/tm30" } +lamp-label = { path = "crates/lamp-label" } +anyhow = "1" +thiserror = "2" +clap = { version = "4.5", features = ["derive", "env"] } +serde_json = { version = "1", features = ["preserve_order"] } +chrono = { version = "0.4", default-features = false, features = ["clock", "std"] } +ctrlc = "3.4" +serialport = "4.7" +ureq = "3" + +[profile.release] +strip = true diff --git a/HPCS6500 b/HPCS6500 new file mode 160000 index 0000000..8f667dc --- /dev/null +++ b/HPCS6500 @@ -0,0 +1 @@ +Subproject commit 8f667dc6cf9713cfc7b996c4f1959c72d71b03e1 diff --git a/README.md b/README.md new file mode 100644 index 0000000..5c6507d --- /dev/null +++ b/README.md @@ -0,0 +1,162 @@ +# Lamp testbench + +Measurement station and tools around the **HPCS 6500** spectrophotometer / +integrating sphere, for the [buildfor.life lamp comparison](https://buildfor.life/comparisons) +and for calibrating B4L's tunable-white LED light. Everything is Rust; one +binary, `lampbench`. + +| Part | Role | Where | +|---|---|---| +| **HPCS 6500** | spectrum, photometry, CRI, electrical, built-in AC/DC supply | driver: submodule `HPCS6500/` ([B4L/HPCS6500-py](https://git.b4l.co.th/B4L/HPCS6500-py)) | +| **Brother QL-820NWB** | lamp ID labels, DK-11221 23x23 mm | `crates/brother-ql`, `crates/lamp-label` | +| **TM-30-18** | Rf, Rg and the 16 hue bins from the spectrum | `crates/tm30` | +| **comparison-data** | the published lamp bundles | `--data-repo` (git checkout) | + +Same layout as [mppt-testbench](https://git.b4l.co.th/B4L/mppt-testbench): +the instrument driver is its own repository, pulled in as a submodule. + +## Install + +```bash +git clone --recurse-submodules https://git.b4l.co.th/B4L/lamp-testbench.git +cd lamp-testbench +cargo build --release # target/release/lampbench(.exe) +cargo install --path . # or put lampbench on the PATH +``` + +The instrument is found by its USB IDs (STM32 virtual COM port, VID `0483`, +PID `5741`); `--port COM42` picks one by hand. `hpcs6500` (the driver's CLI, +`cargo install --path HPCS6500`) reads and controls the instrument directly. + +## Lamp station + +```bash +lampbench station # scan -> measure -> commit -> push -> labels +lampbench station --no-push # commit locally only +lampbench station --no-commit # just write the bundle +lampbench station --settle 0 --readings 1 # quick smoke test +lampbench station --simulate --no-commit --data-repo D:/scratch-data # no instrument needed +``` + +Every lamp gets an internal ID (`L0001`, `L0002`, ...) as its primary key; +the EAN is optional metadata, so one barcode can cover daylight and warm +white variants, and unbranded lamps work too. + +1. Every run opens with a fresh ID; it only becomes real once a bundle is + written, so aborting never burns a number. +2. Scan the box's EAN (Enter skips it) or type an existing ID like `L0004` to + re-measure that lamp with everything pre-filled (this also rewrites its + bundle in the current format). EANs are checksum-validated and resolved to + manufacturer / model from previous lamps, the local cache + (`~/.cache/hpcs6500/ean-cache.json`), then upcitemdb.com; GS1-restricted + 20-29 barcodes are flagged as retailer-internal. Lamps already measured + under the same EAN are offered for re-measurement. +3. Confirm the identification and type the **advertised** values from the + packaging (flux, CCT, power, CRI, lifetime, equivalent W). They are + stored under `rated` in metrics.json for claimed-vs-measured comparison. +4. Insert the lamp and press Enter. The procedure: 230 V / 50 Hz from the + built-in supply, 60 s settle, 5 readings averaged (vendor single-test + cycle per reading). +5. `lamps//` is written into the comparison-data checkout, committed and + pushed; the website picks it up automatically (data-driven device list, + auto-bump deploy). An .md page in the web repo is only needed for photos, + buy links or notes. +6. Two ID labels (QR code of the ID plus the ID, DK-11221) print on the + Brother QL-820NWB: one for the box, one for the lamp. Scanning a label at + the station types the ID and lands in the re-measure flow. Set + `HPCS_LABEL_PRINTER=tcp://192.168.1.50` or pass `--printer`. + +Ctrl+C during a measurement switches the supply off and skips the lamp; +at the scan prompt, `q` or Ctrl+C quits. + +Defaults assume `C:\dev\buildfor_life_web\apps\web\comparison-data` with the +comparison-data submodule initialized; override with `--data-repo`. + +## Lamp bundle export + +```bash +lampbench export --name philips-a60-8w --manufacturer Philips --model "A60 8W 927" +lampbench export --name philips-a60-8w --readings 5 +lampbench export --name philips-a60-8w --voltage 230 --frequency 50 --settle 60 # power from the built-in supply +lampbench export --name some-lamp --parse captures/run.pcap # from a USB capture +lampbench export --name x --passive # vendor software drives the instrument +``` + +Output lands in `lamps//` (`--out`): + +| File | | +|---|---| +| `spd.csv` | `wavelength_nm,value`, the full 380-1050 nm spectrum | +| `tm30.csv` | TM-30-18 per hue bin: reference/test a' b' (raw and normalized), Rcs, Rhs, Rf,h | +| `metrics.json` | name, EAN, type, rated values, TM-30 Rf/Rg, CRI Ra + R1-R15, supply, photometric, chromaticity, radiometric, electrical, sensor | + +The files are byte for byte what the former Python `lamp_export.py` wrote +(tested against its output), so re-measured lamps only change where the +measurement changed. + +## Labels + +```bash +lampbench label L0006 # 2 labels on $HPCS_LABEL_PRINTER +lampbench label L0006 --copies 1 --printer tcp://192.168.1.50 +lampbench label L0006 --preview l6.png # render only +``` + +## TM-30 + +```bash +lampbench tm30 lamps/L0011/spd.csv # Rf 83.2 Rg 109.3 CCT 4008 K Duv -0.0370 +lampbench tm30 lamps/L0011/spd.csv --bins # the tm30.csv rows +``` + +`crates/tm30` implements ANSI/IES TM-30-18 (CIE 2017 colour fidelity, 99 CES, +CAM02-UCS, Ohno 2013 CCT) in plain Rust. It reproduces colour-science 0.4.7, +which the Python tools used, on 52 golden cases (the published lamps, CIE +illuminants, blackbodies, odd grids): Rf and Rg agree to 1e-10, every +output to 1e-9 relative or 1e-11 absolute. The spectrum is relative; TM-30 +is invariant to its scale. + +> **Known issue: the spectrum's wavelength axis.** The CCT/Duv that TM-30 +> derives from the spectrum (4008 K / -0.037 for L0011) disagree with the +> instrument's own values (4049 K / +0.0026), because the spectrum's +> chromaticity on the assumed linear 380-1050 nm axis is 0.09-0.13 (xy) off +> the instrument's x, y. The published Rf/Rg inherit this. Details and how +> to confirm the axis: `HPCS6500/PROTOCOL.md`, "Spectral Data". + +## LED light calibration + +Calibrates the mixing table of the B4L tunable-white light (2700 K + 5000 K +LEDs) over its UART, with the HPCS 6500 as the meter: + +```bash +lampbench calibrate COM3 # y-data, then up to 10 mixing-ratio passes until all 45 points are within 5 % +lampbench calibrate COM3 --skip-y # mixing ratios only +lampbench calibrate COM3 --y-only # LED curves only +lampbench calibrate COM3 --read # show the table in the light +lampbench calibrate COM3 --clear # back to firmware defaults +lampbench calibrate COM3 --generate-only # table from calibration_table.json +lampbench calibrate COM3 --write # ... and write it to the light +``` + +Progress and results go to `calibration_table.json` (`--output`), in the +format of the former `calibration.py`. + +## Development + +```bash +cargo test --workspace # everything, including the driver submodule +cargo clippy --workspace --all-targets -- -D warnings +``` + +- `tests/golden/bundles/` are bundles written by the Python `lamp_export.py` + from real readings (the driver's `tests/fixtures/`); `bundle.rs` must + reproduce them byte for byte. +- `tests/station.rs` runs the whole station with scripted answers against the + simulated instrument and a throwaway comparison-data repository. +- The calibration is tested against a simulated light whose CCT follows its + mixing ratio. +- `crates/tm30/tests`, `crates/brother-ql/tests`, `crates/lamp-label/tests` + compare against the Python libraries (colour-science, brother_ql, qrcode); + `tools/` in each crate regenerates the golden data. + +The Python tools these replace are in HPCS6500-py at tag `python-final`. diff --git a/crates/brother-ql/Cargo.toml b/crates/brother-ql/Cargo.toml new file mode 100644 index 0000000..3840e94 --- /dev/null +++ b/crates/brother-ql/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "brother-ql" +description = "Brother QL label printer raster protocol (byte-identical port of the Python brother_ql library)" +version.workspace = true +edition.workspace = true +publish.workspace = true + +[lib] +name = "brother_ql" + +[dependencies] + +[dev-dependencies] +png = "0.17" diff --git a/crates/brother-ql/src/bitmap.rs b/crates/brother-ql/src/bitmap.rs new file mode 100644 index 0000000..841b30d --- /dev/null +++ b/crates/brother-ql/src/bitmap.rs @@ -0,0 +1,272 @@ +//! A minimal 1-bit image type. + +use std::fmt; + +/// A 1-bit image. `true` means black (a printed dot), `false` means white. +/// +/// Pixels are addressed as `(x, y)` with `(0, 0)` in the top-left corner, +/// `x` growing to the right and `y` growing downwards (the same convention as +/// PIL). +#[derive(Clone, PartialEq, Eq, Hash)] +pub struct Bitmap { + width: u32, + height: u32, + /// Row-major pixels, `true` = black. + pixels: Vec, +} + +impl Bitmap { + /// A new all-white bitmap. + pub fn new(width: u32, height: u32) -> Self { + Self::filled(width, height, false) + } + + /// A new bitmap with every pixel set to `black`. + pub fn filled(width: u32, height: u32, black: bool) -> Self { + let len = width as usize * height as usize; + Self { + width, + height, + pixels: vec![black; len], + } + } + + /// Builds a bitmap by evaluating `f(x, y)` (returns `true` for black) for every pixel. + pub fn from_fn(width: u32, height: u32, mut f: impl FnMut(u32, u32) -> bool) -> Self { + let mut pixels = Vec::with_capacity(width as usize * height as usize); + for y in 0..height { + for x in 0..width { + pixels.push(f(x, y)); + } + } + Self { + width, + height, + pixels, + } + } + + /// Width in pixels. + pub fn width(&self) -> u32 { + self.width + } + + /// Height in pixels. + pub fn height(&self) -> u32 { + self.height + } + + /// `(width, height)`. + pub fn size(&self) -> (u32, u32) { + (self.width, self.height) + } + + fn index(&self, x: u32, y: u32) -> usize { + assert!( + x < self.width && y < self.height, + "pixel ({x}, {y}) out of bounds for a {}x{} bitmap", + self.width, + self.height + ); + y as usize * self.width as usize + x as usize + } + + /// Returns `true` if the pixel is black. + /// + /// # Panics + /// If `(x, y)` is outside the bitmap. + pub fn get(&self, x: u32, y: u32) -> bool { + self.pixels[self.index(x, y)] + } + + /// Sets a pixel (`true` = black). + /// + /// # Panics + /// If `(x, y)` is outside the bitmap. + pub fn set(&mut self, x: u32, y: u32, black: bool) { + let i = self.index(x, y); + self.pixels[i] = black; + } + + /// Sets a pixel given signed coordinates; pixels outside the bitmap are ignored. + pub fn set_clipped(&mut self, x: i64, y: i64, black: bool) { + if x >= 0 && y >= 0 && x < i64::from(self.width) && y < i64::from(self.height) { + self.set(x as u32, y as u32, black); + } + } + + /// Fills the rectangle `[x, x + w) x [y, y + h)` (clipped to the bitmap). + pub fn fill_rect(&mut self, x: i64, y: i64, w: u32, h: u32, black: bool) { + let x0 = x.max(0); + let y0 = y.max(0); + let x1 = (x + i64::from(w)).min(i64::from(self.width)); + let y1 = (y + i64::from(h)).min(i64::from(self.height)); + for yy in y0..y1 { + for xx in x0..x1 { + self.set(xx as u32, yy as u32, black); + } + } + } + + /// Copies `src` into this bitmap with its top-left corner at `(x, y)`, + /// overwriting both black and white pixels (like PIL `Image.paste` without + /// a mask). Parts falling outside are clipped. + pub fn paste(&mut self, src: &Bitmap, x: i64, y: i64) { + for sy in 0..src.height { + let dy = y + i64::from(sy); + if dy < 0 || dy >= i64::from(self.height) { + continue; + } + for sx in 0..src.width { + let dx = x + i64::from(sx); + if dx < 0 || dx >= i64::from(self.width) { + continue; + } + self.set(dx as u32, dy as u32, src.get(sx, sy)); + } + } + } + + /// Returns the sub-image `[x, x + w) x [y, y + h)`; pixels outside the + /// source are white. + pub fn crop(&self, x: i64, y: i64, w: u32, h: u32) -> Bitmap { + Bitmap::from_fn(w, h, |cx, cy| { + let sx = x + i64::from(cx); + let sy = y + i64::from(cy); + sx >= 0 + && sy >= 0 + && sx < i64::from(self.width) + && sy < i64::from(self.height) + && self.get(sx as u32, sy as u32) + }) + } + + /// Rotates 90 degrees counter-clockwise (PIL `Image.rotate(90, expand=True)` + /// / `Transpose.ROTATE_90`). + pub fn rotate90(&self) -> Bitmap { + let (w, h) = (self.width, self.height); + Bitmap::from_fn(h, w, |x, y| self.get(w - 1 - y, x)) + } + + /// Rotates 180 degrees. + pub fn rotate180(&self) -> Bitmap { + let (w, h) = (self.width, self.height); + Bitmap::from_fn(w, h, |x, y| self.get(w - 1 - x, h - 1 - y)) + } + + /// Rotates 270 degrees counter-clockwise (= 90 degrees clockwise, PIL + /// `Transpose.ROTATE_270`). + pub fn rotate270(&self) -> Bitmap { + let (w, h) = (self.width, self.height); + Bitmap::from_fn(h, w, |x, y| self.get(y, h - 1 - x)) + } + + /// Mirrors left-right (PIL `Transpose.FLIP_LEFT_RIGHT`). + pub fn flip_horizontal(&self) -> Bitmap { + let w = self.width; + Bitmap::from_fn(w, self.height, |x, y| self.get(w - 1 - x, y)) + } + + /// Nearest-neighbour resize exactly as Pillow does it for mode `"1"` + /// images (Pillow forces `NEAREST` for 1-bit images whatever filter is + /// requested): source coordinate = `floor(scale * 0.5 + i * scale)` with the + /// position accumulated in `f64` like `ImagingScaleAffine`. + pub fn resize_nearest(&self, width: u32, height: u32) -> Bitmap { + if width == self.width && height == self.height { + return self.clone(); + } + let xmap = nearest_map(self.width, width); + let ymap = nearest_map(self.height, height); + Bitmap::from_fn(width, height, |x, y| { + match (xmap[x as usize], ymap[y as usize]) { + (Some(sx), Some(sy)) => self.get(sx, sy), + _ => false, + } + }) + } + + /// Number of black pixels. + pub fn count_black(&self) -> usize { + self.pixels.iter().filter(|&&p| p).count() + } + + /// Row `y` as booleans (`true` = black). + pub fn row(&self, y: u32) -> &[bool] { + let start = self.index(0, y); + &self.pixels[start..start + self.width as usize] + } + + /// All pixels in row-major order (`true` = black). + pub fn pixels(&self) -> &[bool] { + &self.pixels + } +} + +fn nearest_map(src: u32, dst: u32) -> Vec> { + let scale = f64::from(src) / f64::from(dst); + let mut pos = scale * 0.5; + let mut out = Vec::with_capacity(dst as usize); + for _ in 0..dst { + // COORD(v) in Pillow: v < 0 ? -1 : (int)v + let i = if pos < 0.0 { -1 } else { pos as i64 }; + out.push(if i >= 0 && i < i64::from(src) { + Some(i as u32) + } else { + None + }); + pos += scale; + } + out +} + +impl fmt::Debug for Bitmap { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Bitmap") + .field("width", &self.width) + .field("height", &self.height) + .field("black_pixels", &self.count_black()) + .finish() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn rotations_match_pil_direction() { + // single black pixel in the top-left corner of a 3x2 image + let mut b = Bitmap::new(3, 2); + b.set(0, 0, true); + // PIL rotate(90) is counter-clockwise: top-left goes to bottom-left + let r = b.rotate90(); + assert_eq!(r.size(), (2, 3)); + assert!(r.get(0, 2)); + let r = b.rotate270(); + assert!(r.get(1, 0)); + let r = b.rotate180(); + assert!(r.get(2, 1)); + assert_eq!(b.rotate90().rotate90(), b.rotate180()); + assert_eq!(b.rotate90().rotate270(), b); + assert!(b.flip_horizontal().get(2, 0)); + } + + #[test] + fn paste_and_crop_clip() { + let mut b = Bitmap::new(4, 4); + let src = Bitmap::filled(3, 3, true); + b.paste(&src, -1, 2); + assert_eq!(b.count_black(), 4); + assert!(b.get(0, 2) && b.get(1, 3)); + let c = b.crop(-1, 2, 3, 3); + assert_eq!(c.count_black(), 4); + } + + #[test] + fn resize_halves_like_pillow() { + // PIL picks the odd source columns when halving (floor(2*i + 1)). + let b = Bitmap::from_fn(4, 1, |x, _| x % 2 == 1); + let r = b.resize_nearest(2, 1); + assert!(r.get(0, 0) && r.get(1, 0)); + } +} diff --git a/crates/brother-ql/src/conversion.rs b/crates/brother-ql/src/conversion.rs new file mode 100644 index 0000000..6e23e0d --- /dev/null +++ b/crates/brother-ql/src/conversion.rs @@ -0,0 +1,254 @@ +//! Image to raster-instruction conversion (port of `brother_ql.conversion.convert` +//! for black/white images). + +use crate::raster::Raster; +use crate::{Bitmap, Error, FormFactor, Label, Model}; + +/// Rotation applied before rasterising (`rotate=` in brother_ql). +/// Angles are counter-clockwise, as in PIL `Image.rotate`. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +pub enum Rotate { + /// `'auto'`: for die-cut labels, rotate 90 degrees if the image has the + /// printable size transposed. NOTE: for square labels such as 23x23 this is + /// always true, so square images are always rotated 90 degrees CCW (brother_ql + /// behaviour, kept for byte compatibility). Endless labels are not rotated. + #[default] + Auto, + /// No rotation. + R0, + /// 90 degrees counter-clockwise. + R90, + /// 180 degrees. + R180, + /// 270 degrees counter-clockwise (90 clockwise). + R270, +} + +/// Conversion options; `Default` matches the Python `convert()` keyword defaults. +#[derive(Debug, Clone, PartialEq)] +pub struct ConvertOptions { + /// Cut after each label (`ESC i M 0x40`, `ESC i A 1`, cut-at-end bit). Default `true`. + pub cut: bool, + /// PackBits-compress raster lines (only on models with compression). Default `false`. + pub compress: bool, + /// Rotation. Default [`Rotate::Auto`]. + pub rotate: Rotate, + /// 300x600 dpi mode: input is 600x600 dpi and is halved horizontally. Default `false`. + pub dpi_600: bool, + /// High quality flag (bit 6 of the `ESC i z` valid flags). Default `true`. + pub hq: bool, + /// Threshold in percent (0-100), as in brother_ql. Default `70.0`. + /// For a 1-bit input it only matters at the extremes: a value that maps to + /// 0 (i.e. `>= 100`) turns white pixels black. + pub threshold: f64, + /// Floyd-Steinberg dithering instead of thresholding. Default `false`. + /// Has no effect on 1-bit input (there are no grey levels to diffuse), + /// exactly as in brother_ql; accepted for API parity. + pub dither: bool, +} + +impl Default for ConvertOptions { + fn default() -> Self { + Self { + cut: true, + compress: false, + rotate: Rotate::Auto, + dpi_600: false, + hq: true, + threshold: 70.0, + dither: false, + } + } +} + +fn rotate(im: &Bitmap, r: Rotate) -> Bitmap { + match r { + Rotate::Auto | Rotate::R0 => im.clone(), + Rotate::R90 => im.rotate90(), + Rotate::R180 => im.rotate180(), + Rotate::R270 => im.rotate270(), + } +} + +/// brother_ql: `threshold = min(255, max(0, int((100.0 - threshold) / 100.0 * 255)))`. +fn threshold_value(threshold: f64) -> i64 { + let t = (100.0 - threshold) / 100.0 * 255.0; + // Python int() truncates toward zero; f64 -> i64 `as` does the same (saturating). + (t as i64).clamp(0, 255) +} + +/// Converts black/white images into a complete raster instruction stream, +/// byte-for-byte like +/// `brother_ql.conversion.convert(BrotherQLRaster(model), images, label, **opts)`. +/// +/// The emitted stream is: +/// `ESC i a 01` (if mode setting), `num_invalidate_bytes` x `00`, `ESC @`, +/// `ESC i a 01` again, then per image: `ESC i S`, `ESC i z` (print info), +/// `ESC i M 40` + `ESC i A 01` (if cut and cutter), `ESC i K` (expanded +/// mode), `ESC i d` (margin), `M 02` (if compress), one `g 00 ` per +/// raster line, and `1A`. brother_ql ends *every* page with `1A`, never `0C`. +/// +/// Images for die-cut/round labels must be exactly `dots_printable` (or its +/// transpose, or twice that for `dpi_600`); endless images are resized +/// (nearest neighbour, as Pillow does for 1-bit images) to the printable width. +pub fn convert( + model: &Model, + label: &Label, + images: &[Bitmap], + opts: &ConvertOptions, +) -> Result, Error> { + let dots_printable = label.dots_printable; + let right_margin_dots = i64::from(label.offset_r) + i64::from(model.additional_offset_r); + let device_pixel_width = model.pixel_width(); + let threshold = threshold_value(opts.threshold); + + let mut qlr = Raster::new(model); + qlr.add_switch_mode(); + qlr.add_invalidate(); + qlr.add_initialize(); + qlr.add_switch_mode(); + + for image in images { + let dots_expected = if opts.dpi_600 { + (dots_printable.0 * 2, dots_printable.1 * 2) + } else { + dots_printable + }; + + let mut im = image.clone(); + match label.form_factor { + FormFactor::Endless => { + if !matches!(opts.rotate, Rotate::Auto | Rotate::R0) { + im = rotate(&im, opts.rotate); + } + if opts.dpi_600 { + im = resize(&im, im.width() / 2, im.height())?; + } + if im.width() != dots_printable.0 { + let hsize = (f64::from(dots_printable.0) / f64::from(im.width()) + * f64::from(im.height())) as u32; + im = resize(&im, dots_printable.0, hsize)?; + } + if im.width() < device_pixel_width { + let mut new_im = Bitmap::new(device_pixel_width, im.height()); + let x = + i64::from(device_pixel_width) - i64::from(im.width()) - right_margin_dots; + new_im.paste(&im, x, 0); + im = new_im; + } + } + FormFactor::DieCut | FormFactor::RoundDieCut => { + if opts.rotate == Rotate::Auto { + if im.width() == dots_expected.1 && im.height() == dots_expected.0 { + im = im.rotate90(); + } + } else if opts.rotate != Rotate::R0 { + im = rotate(&im, opts.rotate); + } + if im.size() != dots_expected { + return Err(Error::BadImageDimensions { + size: im.size(), + expected: dots_expected, + }); + } + if opts.dpi_600 { + im = resize(&im, im.width() / 2, im.height())?; + } + let mut new_im = Bitmap::new(device_pixel_width, dots_expected.1); + let x = i64::from(device_pixel_width) - i64::from(im.width()) - right_margin_dots; + new_im.paste(&im, x, 0); + im = new_im; + } + } + + // convert("L") -> invert -> point(x < threshold ? 0 : 255, "1"): + // black (inverted 255) always prints; white (inverted 0) prints only + // when the threshold is 0. With dither the threshold is not used and + // Floyd-Steinberg on a pure 0/255 image reproduces it unchanged. + if !opts.dither && threshold == 0 { + im = Bitmap::filled(im.width(), im.height(), true); + } + + qlr.add_status_information(); + let tape_size = label.tape_size; + match label.form_factor { + FormFactor::DieCut | FormFactor::RoundDieCut => { + qlr.mtype = Some(0x0B); + qlr.mwidth = Some(tape_size.0 as u8); + qlr.mlength = Some(tape_size.1 as u8); + } + FormFactor::Endless => { + qlr.mtype = Some(0x0A); + qlr.mwidth = Some(tape_size.0 as u8); + qlr.mlength = Some(0); + } + } + qlr.pquality = opts.hq; + qlr.add_media_and_quality(im.height()); + if opts.cut { + qlr.add_autocut(true); + qlr.add_cut_every(1); + } + qlr.dpi_600 = opts.dpi_600; + qlr.cut_at_end = opts.cut; + qlr.two_color_printing = false; + qlr.add_expanded_mode(); + qlr.add_margins(label.feed_margin as u16); + if opts.compress { + qlr.add_compression(true); + } + qlr.add_raster_data(&im)?; + qlr.add_print(true); + } + + Ok(qlr.data) +} + +fn resize(im: &Bitmap, width: u32, height: u32) -> Result { + if width == 0 || height == 0 { + return Err(Error::BadImageDimensions { + size: (width, height), + expected: (width.max(1), height.max(1)), + }); + } + Ok(im.resize_nearest(width, height)) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{LABEL_23X23, QL_820NWB}; + + #[test] + fn threshold_mapping() { + assert_eq!(threshold_value(70.0), 76); + assert_eq!(threshold_value(100.0), 0); + assert_eq!(threshold_value(0.0), 255); + assert_eq!(threshold_value(-50.0), 255); + assert_eq!(threshold_value(150.0), 0); + } + + #[test] + fn header_and_page_layout_23x23() { + let img = Bitmap::new(202, 202); + let data = convert(&QL_820NWB, &LABEL_23X23, &[img], &ConvertOptions::default()).unwrap(); + let mut expected = b"\x1B\x69\x61\x01".to_vec(); + expected.extend(std::iter::repeat_n(0u8, 400)); + expected.extend_from_slice(b"\x1B\x40\x1B\x69\x61\x01\x1B\x69\x53"); + expected.extend_from_slice(b"\x1B\x69\x7A\xCE\x0B\x17\x17\xCA\x00\x00\x00\x00\x00"); + expected.extend_from_slice( + b"\x1B\x69\x4D\x40\x1B\x69\x41\x01\x1B\x69\x4B\x08\x1B\x69\x64\x00\x00", + ); + assert_eq!(&data[..expected.len()], &expected[..]); + assert_eq!(data.len(), expected.len() + 202 * 93 + 1); + assert_eq!(*data.last().unwrap(), 0x1A); + } + + #[test] + fn wrong_size_rejected() { + let img = Bitmap::new(200, 202); + let err = + convert(&QL_820NWB, &LABEL_23X23, &[img], &ConvertOptions::default()).unwrap_err(); + assert!(matches!(err, Error::BadImageDimensions { .. })); + } +} diff --git a/crates/brother-ql/src/error.rs b/crates/brother-ql/src/error.rs new file mode 100644 index 0000000..f079f75 --- /dev/null +++ b/crates/brother-ql/src/error.rs @@ -0,0 +1,97 @@ +//! Error type. + +use std::fmt; +use std::io; + +/// Errors from conversion and sending. +#[derive(Debug)] +#[non_exhaustive] +pub enum Error { + /// No model with this identifier (Python: `BrotherQLUnknownModel`). + UnknownModel(String), + /// No label with this identifier (Python: `KeyError` from `LabelsManager`). + UnknownLabel(String), + /// Die-cut image has the wrong size (Python: `ValueError("Bad image dimensions")`). + BadImageDimensions { + /// Size of the (possibly rotated) image. + size: (u32, u32), + /// Size required by the label. + expected: (u32, u32), + }, + /// Raster image width differs from the print head width (Python: `BrotherQLRasterError`). + WrongPixelWidth { + /// Width of the raster image. + width: u32, + /// Head width of the model in dots. + expected: u32, + }, + /// Raster height outside the model's `min_max_length_dots` (Python: `BrotherQLRasterError`). + InvalidRasterHeight { + /// Number of raster rows. + height: u32, + /// Minimum allowed rows. + min: u32, + /// Maximum allowed rows. + max: u32, + /// Model identifier. + model: &'static str, + }, + /// A (compressed) raster line does not fit the one-byte length field. + RowTooLong(usize), + /// The printer address could not be parsed. + InvalidAddress(String), + /// Name resolution returned no address. + NoAddress(String), + /// Connecting to every resolved address failed (last error is kept). + Connect { + /// The `host:port` that was tried. + addr: String, + /// Error of the last connection attempt. + source: io::Error, + }, + /// Sending the instructions failed or timed out. + Write(io::Error), +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Error::UnknownModel(m) => write!(f, "unknown printer model {m:?}"), + Error::UnknownLabel(l) => write!(f, "unknown label {l:?}"), + Error::BadImageDimensions { size, expected } => write!( + f, + "bad image dimensions: {}x{}, expecting {}x{}", + size.0, size.1, expected.0, expected.1 + ), + Error::WrongPixelWidth { width, expected } => { + write!(f, "wrong pixel width: {width}, expected {expected}") + } + Error::InvalidRasterHeight { + height, + min, + max, + model, + } => write!( + f, + "invalid raster height: {height}, expected between {min} and {max} dots for the {model} printer" + ), + Error::RowTooLong(n) => { + write!(f, "raster line of {n} bytes does not fit a 1-byte length") + } + Error::InvalidAddress(a) => write!(f, "invalid printer address {a:?}"), + Error::NoAddress(a) => write!(f, "no address found for {a:?}"), + Error::Connect { addr, source } => write!(f, "cannot connect to {addr}: {source}"), + Error::Write(e) => write!(f, "sending to the printer failed: {e}"), + } + } +} + +impl std::error::Error for Error { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + Error::Connect { source, .. } => Some(source), + Error::Write(e) => Some(e), + _ => None, + } + } +} diff --git a/crates/brother-ql/src/labels.rs b/crates/brother-ql/src/labels.rs new file mode 100644 index 0000000..48a028f --- /dev/null +++ b/crates/brother-ql/src/labels.rs @@ -0,0 +1,200 @@ +//! Label media (port of `brother_ql/labels.py`). + +use crate::Error; + +/// Shape of the label media. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum FormFactor { + /// Rectangular die-cut labels. + DieCut = 1, + /// Endless (continuous) tape. + Endless = 2, + /// Round die-cut labels. + RoundDieCut = 3, +} + +/// Colours the media can carry. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum Color { + /// Black on white. + BlackWhite = 0, + /// Black and red on white (DK-22251 "62red"). + BlackRedWhite = 1, +} + +/// A label type, field-for-field like `brother_ql.labels.Label`. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct Label { + /// Identifier such as `"23x23"`, `"62"` or `"d24"`. + pub identifier: &'static str, + /// (width, length) in mm; length is 0 for endless tape. + pub tape_size: (u32, u32), + /// Die-cut, endless or round. + pub form_factor: FormFactor, + /// Total area (width, length) in dots at 300 dpi. + pub dots_total: (u32, u32), + /// Printable area (width, length) in dots at 300 dpi. Images for die-cut + /// labels must have exactly this size. + pub dots_printable: (u32, u32), + /// Offset from the right side of the print head in dots. + pub offset_r: u32, + /// Feed margin sent with `ESC i d`. + pub feed_margin: u32, + /// Models this label is restricted to (empty = any). + pub restricted_to_models: &'static [&'static str], + /// Black/white or black/red/white. + pub color: Color, +} + +const WIDE_102: &[&str] = &["QL-1050", "QL-1060N", "QL-1100", "QL-1100NWB", "QL-1115NWB"]; +const WIDE_103: &[&str] = &["QL-1100", "QL-1100NWB"]; + +const fn label( + identifier: &'static str, + tape_size: (u32, u32), + form_factor: FormFactor, + dots_total: (u32, u32), + dots_printable: (u32, u32), + offset_r: u32, + feed_margin: u32, +) -> Label { + Label { + identifier, + tape_size, + form_factor, + dots_total, + dots_printable, + offset_r, + feed_margin, + restricted_to_models: &[], + color: Color::BlackWhite, + } +} + +const fn restricted(l: Label, models: &'static [&'static str]) -> Label { + Label { + restricted_to_models: models, + ..l + } +} + +use FormFactor::{DieCut, Endless, RoundDieCut}; + +/// DK-11221, 23 mm x 23 mm die-cut: 202 x 202 printable dots, right offset 42. +pub const LABEL_23X23: Label = label("23x23", (23, 23), DieCut, (272, 272), (202, 202), 42, 0); + +/// Every label known to brother_ql 0.12 (`ALL_LABELS`), in the same order. +pub const ALL_LABELS: &[Label] = &[ + label("12", (12, 0), Endless, (142, 0), (106, 0), 29, 35), + label("18", (18, 0), Endless, (256, 0), (234, 0), 171, 14), + label("29", (29, 0), Endless, (342, 0), (306, 0), 6, 35), + label("38", (38, 0), Endless, (449, 0), (413, 0), 12, 35), + label("50", (50, 0), Endless, (590, 0), (554, 0), 12, 35), + label("54", (54, 0), Endless, (636, 0), (590, 0), 0, 35), + label("62", (62, 0), Endless, (732, 0), (696, 0), 12, 35), + Label { + color: Color::BlackRedWhite, + ..label("62red", (62, 0), Endless, (732, 0), (696, 0), 12, 35) + }, + restricted( + label("102", (102, 0), Endless, (1200, 0), (1164, 0), 12, 35), + WIDE_102, + ), + restricted( + label("103", (104, 0), Endless, (1224, 0), (1200, 0), 12, 35), + WIDE_103, + ), + label("17x54", (17, 54), DieCut, (201, 636), (165, 566), 0, 0), + label("17x87", (17, 87), DieCut, (201, 1026), (165, 956), 0, 0), + LABEL_23X23, + label("29x42", (29, 42), DieCut, (342, 495), (306, 425), 6, 0), + label("29x90", (29, 90), DieCut, (342, 1061), (306, 991), 6, 0), + label("39x90", (38, 90), DieCut, (449, 1061), (413, 991), 12, 0), + label("39x48", (39, 48), DieCut, (461, 565), (425, 495), 6, 0), + label("52x29", (52, 29), DieCut, (614, 341), (578, 271), 0, 0), + label("54x29", (54, 29), DieCut, (630, 341), (598, 271), 60, 0), + label("60x86", (60, 87), DieCut, (708, 1024), (672, 954), 18, 0), + label("62x29", (62, 29), DieCut, (732, 341), (696, 271), 12, 0), + label("62x100", (62, 100), DieCut, (732, 1179), (696, 1109), 12, 0), + restricted( + label("102x51", (102, 51), DieCut, (1200, 596), (1164, 526), 12, 0), + WIDE_102, + ), + restricted( + label( + "102x152", + (102, 153), + DieCut, + (1200, 1804), + (1164, 1660), + 12, + 0, + ), + WIDE_102, + ), + restricted( + label( + "103x164", + (104, 164), + DieCut, + (1224, 1941), + (1200, 1822), + 12, + 0, + ), + WIDE_103, + ), + label("d12", (12, 12), RoundDieCut, (142, 142), (94, 94), 113, 35), + label("d24", (24, 24), RoundDieCut, (284, 284), (236, 236), 42, 0), + label("d58", (58, 58), RoundDieCut, (688, 688), (618, 618), 51, 0), +]; + +impl Label { + /// Looks a label up by its brother_ql identifier (exact match, e.g. `"23x23"`). + pub fn lookup(identifier: &str) -> Result<&'static Label, Error> { + ALL_LABELS + .iter() + .find(|l| l.identifier == identifier) + .ok_or_else(|| Error::UnknownLabel(identifier.to_string())) + } + + /// First label whose `tape_size` matches (like `LabelsManager.find_label_by_size`). + pub fn find_by_size(width_mm: u32, length_mm: u32) -> Option<&'static Label> { + ALL_LABELS + .iter() + .find(|l| l.tape_size == (width_mm, length_mm)) + } + + /// Human-readable name, as `Label.name` in Python. + pub fn name(&self) -> String { + let mut out = if self.identifier.contains('x') { + format!("{}mm x {}mm die-cut", self.tape_size.0, self.tape_size.1) + } else if self.identifier.starts_with('d') { + format!("{}mm round die-cut", self.tape_size.0) + } else { + format!("{}mm endless", self.tape_size.0) + }; + if self.color == Color::BlackRedWhite { + out.push_str(" (black/red/white)"); + } + out + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn label_23x23() { + let l = Label::lookup("23x23").unwrap(); + assert_eq!(*l, LABEL_23X23); + assert_eq!(l.dots_printable, (202, 202)); + assert_eq!(l.offset_r, 42); + assert_eq!(l.form_factor, FormFactor::DieCut); + assert_eq!(l.name(), "23mm x 23mm die-cut"); + assert_eq!(ALL_LABELS.len(), 28); + assert_eq!(Label::find_by_size(62, 0).unwrap().identifier, "62"); + assert!(Label::lookup("23").is_err()); + } +} diff --git a/crates/brother-ql/src/lib.rs b/crates/brother-ql/src/lib.rs new file mode 100644 index 0000000..7015625 --- /dev/null +++ b/crates/brother-ql/src/lib.rs @@ -0,0 +1,37 @@ +//! Brother QL label printer raster protocol, a byte-identical Rust port of the +//! Python [`brother_ql`](https://pypi.org/project/brother-ql-next/) library +//! (brother_ql_next 0.12) for black/white images. +//! +//! ```no_run +//! use brother_ql::{Bitmap, ConvertOptions, Label, Model, convert, send_network, DEFAULT_TIMEOUT}; +//! +//! let model = Model::lookup("QL-820NWB")?; +//! let label = Label::lookup("23x23")?; +//! let mut img = Bitmap::new(202, 202); +//! img.fill_rect(10, 10, 50, 50, true); +//! let data = convert(model, label, &[img], &ConvertOptions::default())?; +//! send_network("tcp://192.168.1.50", &data, true, DEFAULT_TIMEOUT)?; +//! # Ok::<(), brother_ql::Error>(()) +//! ``` +//! +//! Not ported: red/black two-colour printing (needs colour input), the +//! USB/linux-kernel backends and status parsing (the network backend never +//! reads a status). + +mod bitmap; +mod conversion; +mod error; +mod labels; +mod models; +mod network; +pub mod packbits; +pub mod raster; + +pub use bitmap::Bitmap; +pub use conversion::{ConvertOptions, Rotate, convert}; +pub use error::Error; +pub use labels::{ALL_LABELS, Color, FormFactor, LABEL_23X23, Label}; +pub use models::{ALL_MODELS, Model, QL_820NWB}; +pub use network::{ + DEFAULT_PORT, DEFAULT_TIMEOUT, Outcome, SendStatus, parse_address, send_network, +}; diff --git a/crates/brother-ql/src/models.rs b/crates/brother-ql/src/models.rs new file mode 100644 index 0000000..fd54900 --- /dev/null +++ b/crates/brother-ql/src/models.rs @@ -0,0 +1,142 @@ +//! Printer models (port of `brother_ql/models.py`). + +use crate::Error; + +/// A Brother QL printer model and the protocol features it supports. +/// +/// Field names and defaults follow `brother_ql.models.Model`. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct Model { + /// Identifier such as `"QL-820NWB"`. + pub identifier: &'static str, + /// Minimum and maximum number of raster rows ("dots") per page. + pub min_max_length_dots: (u32, u32), + /// Minimum and maximum feed amount (informational, unused by `convert`). + pub min_max_feed: (u32, u32), + /// Bytes per raster line: 90 for the 720-dot head of the QL-5xx/6xx/7xx/8xx, + /// 162 (1296 dots) for the wide QL-10xx/11xx. + pub number_bytes_per_row: u32, + /// Extra right offset added to the label's `offset_r`. + pub additional_offset_r: u32, + /// Supports `ESC i a` (switch to raster mode). + pub mode_setting: bool, + /// Has an automatic cutter (`ESC i M`, `ESC i A`). + pub cutting: bool, + /// Supports `ESC i K` (expanded mode: cut at end, 600 dpi, two-colour). + pub expanded_mode: bool, + /// Supports TIFF/PackBits compressed raster lines (`M 0x02`). + pub compression: bool, + /// Supports black/red two-colour printing. + pub two_color: bool, + /// Number of NUL bytes sent as the "invalidate" preamble. + pub num_invalidate_bytes: u32, +} + +const fn model(identifier: &'static str, min_max_length_dots: (u32, u32)) -> Model { + Model { + identifier, + min_max_length_dots, + min_max_feed: (35, 1500), + number_bytes_per_row: 90, + additional_offset_r: 0, + mode_setting: true, + cutting: true, + expanded_mode: true, + compression: true, + two_color: false, + num_invalidate_bytes: 200, + } +} + +const fn no_compression_no_mode(m: Model) -> Model { + Model { + compression: false, + mode_setting: false, + ..m + } +} + +const fn wide(m: Model) -> Model { + Model { + number_bytes_per_row: 162, + additional_offset_r: 44, + ..m + } +} + +/// QL-820NWB (the lamp label printer): 720-dot head, 90 bytes per line, +/// cutter, compression, mode switching, two-colour capable, 400 invalidate bytes. +pub const QL_820NWB: Model = Model { + two_color: true, + num_invalidate_bytes: 400, + ..model("QL-820NWB", (150, 11811)) +}; + +/// Every model known to brother_ql 0.12 (`ALL_MODELS`), in the same order. +pub const ALL_MODELS: &[Model] = &[ + Model { + compression: false, + mode_setting: false, + expanded_mode: false, + cutting: false, + ..model("QL-500", (295, 11811)) + }, + no_compression_no_mode(model("QL-550", (295, 11811))), + no_compression_no_mode(model("QL-560", (295, 11811))), + no_compression_no_mode(model("QL-570", (150, 11811))), + model("QL-580N", (150, 11811)), + model("QL-600", (150, 11811)), + model("QL-650TD", (295, 11811)), + no_compression_no_mode(model("QL-700", (150, 11811))), + model("QL-710W", (150, 11811)), + model("QL-720NW", (150, 11811)), + Model { + two_color: true, + compression: false, + num_invalidate_bytes: 400, + ..model("QL-800", (150, 11811)) + }, + Model { + two_color: true, + num_invalidate_bytes: 400, + ..model("QL-810W", (150, 11811)) + }, + QL_820NWB, + wide(model("QL-1050", (295, 35433))), + wide(model("QL-1060N", (295, 35433))), + wide(model("QL-1100", (301, 35434))), + wide(model("QL-1100NWB", (301, 35434))), + wide(model("QL-1110NWB", (301, 35434))), + wide(model("QL-1115NWB", (301, 35434))), +]; + +impl Model { + /// Looks a model up by its brother_ql identifier (exact match, e.g. `"QL-820NWB"`). + pub fn lookup(identifier: &str) -> Result<&'static Model, Error> { + ALL_MODELS + .iter() + .find(|m| m.identifier == identifier) + .ok_or_else(|| Error::UnknownModel(identifier.to_string())) + } + + /// Width of a raster line in dots (`number_bytes_per_row * 8`). + pub fn pixel_width(&self) -> u32 { + self.number_bytes_per_row * 8 + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn ql820nwb() { + let m = Model::lookup("QL-820NWB").unwrap(); + assert_eq!(*m, QL_820NWB); + assert_eq!(m.pixel_width(), 720); + assert_eq!(m.num_invalidate_bytes, 400); + assert!(m.two_color && m.compression && m.mode_setting && m.cutting && m.expanded_mode); + assert_eq!(ALL_MODELS.len(), 19); + assert!(Model::lookup("QL-9999").is_err()); + } +} diff --git a/crates/brother-ql/src/network.rs b/crates/brother-ql/src/network.rs new file mode 100644 index 0000000..33dd1bb --- /dev/null +++ b/crates/brother-ql/src/network.rs @@ -0,0 +1,247 @@ +//! Network sending (port of `brother_ql.backends.network` + +//! `brother_ql.backends.helpers.send(..., backend_identifier="network")`). +//! +//! What happens on the wire, step by step (identical to the Python code): +//! +//! 1. The address is parsed like `urllib.parse.urlparse`: `tcp://` is +//! prepended if missing, the host is lower-cased (IPv6 in `[...]`), any +//! path/user-info is ignored, and a missing or `0` port becomes **9100** +//! (raw "JetDirect" printing port of the QL-820NWB). +//! 2. The host is resolved (getaddrinfo, any family, TCP) and each address is +//! tried in order until one connects. `TCP_NODELAY` is enabled. +//! 3. All instruction bytes are written with `sendall` semantics. +//! 4. Nothing is ever read back. `send()` returns right after the write, +//! even with `blocking=True`: the Python helper explicitly skips the +//! status loop for the network backend ("doesn't support readback"). The +//! `ESC i S` status requests inside the job are therefore never answered +//! from the host's point of view; completion is *not* detected. +//! 5. The socket is shut down in both directions and closed (Python does this +//! in `__del__` when `send()` returns); shutdown errors are ignored. +//! +//! Differences to Python, all deliberate: the `timeout` argument also bounds +//! each connection attempt (Python uses the OS connect timeout); Python's +//! write timeout is a fixed 10 s for the whole `sendall`, here it is +//! `timeout` (pass [`DEFAULT_TIMEOUT`] for 10 s), also for the whole write, +//! which is issued in 64 KiB `write()` calls so the deadline also works on +//! Windows (the TCP byte stream is the same). The `tcp://` prefix is matched +//! case-insensitively and an empty host is an error (Python would fall back +//! to localhost). +//! +//! Caveat inherited from Python: the job contains one `ESC i S` status +//! request per label, a QL printer answers them on the same socket, and the +//! answers are never read before the socket is closed. + +use std::io::{self, Write}; +use std::net::{Shutdown, SocketAddr, TcpStream, ToSocketAddrs}; +use std::time::{Duration, Instant}; + +use crate::Error; + +/// Default TCP port of the printer (raw printing, 9100). +pub const DEFAULT_PORT: u16 = 9100; + +/// Write timeout used by the Python backend (`settimeout(10)` around `sendall`). +pub const DEFAULT_TIMEOUT: Duration = Duration::from_secs(10); + +/// Outcome of a send, as the Python `status['outcome']` string. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Outcome { + /// `'unknown'` + Unknown, + /// `'sent'`: the bytes were written (always the result for the network backend). + Sent, + /// `'printed'`: the printer reported "Printing completed" (never for network). + Printed, + /// `'error'`: the printer reported an error (never for network). + Error, +} + +/// The status dictionary returned by `brother_ql.backends.helpers.send`. +/// `printer_state` is omitted because the network backend never reads one. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct SendStatus { + /// The instructions were written to the socket. + pub instructions_sent: bool, + /// Always [`Outcome::Sent`] for the network backend. + pub outcome: Outcome, + /// Always `false`: no read-back over the network. + pub did_print: bool, + /// Always `false`: no read-back over the network. + pub ready_for_next_job: bool, +} + +/// Parses `tcp://host[:port]` or `host[:port]` into `(host, port)` like the +/// Python network backend (urlparse; port defaults to 9100). +pub fn parse_address(addr: &str) -> Result<(String, u16), Error> { + let invalid = || Error::InvalidAddress(addr.to_string()); + let rest = match addr.get(..6) { + Some(p) if p.eq_ignore_ascii_case("tcp://") => &addr[6..], + _ => addr, + }; + // netloc ends at the first '/', '?' or '#' + let netloc = rest.split(['/', '?', '#']).next().unwrap_or(""); + // strip user-info + let hostinfo = netloc.rsplit_once('@').map_or(netloc, |(_, h)| h); + let (host, port) = if let Some(after) = hostinfo.strip_prefix('[') { + let (h, tail) = after.split_once(']').ok_or_else(invalid)?; + let port = match tail.strip_prefix(':') { + Some(p) => p, + None if tail.is_empty() => "", + None => return Err(invalid()), + }; + (h, port) + } else { + match hostinfo.split_once(':') { + Some((h, p)) => (h, p), + None => (hostinfo, ""), + } + }; + if host.is_empty() { + return Err(invalid()); + } + let port = if port.is_empty() { + 0 + } else { + if !port.bytes().all(|b| b.is_ascii_digit()) { + return Err(invalid()); + } + port.parse::().map_err(|_| invalid())? + }; + let port = if port == 0 { DEFAULT_PORT } else { port }; + Ok((host.to_ascii_lowercase(), port)) +} + +/// Sends raster instructions to a networked Brother QL printer, mirroring +/// `brother_ql.backends.helpers.send(instructions, addr, "network", blocking)`. +/// +/// `addr` is `tcp://host[:port]` or `host[:port]` (port defaults to 9100). +/// `blocking` is accepted for parity but, exactly like Python, has no effect +/// for the network backend: the function returns as soon as all bytes are +/// written and the socket is closed; it never waits for or reads a printer +/// status. `timeout` bounds each connection attempt and the complete write +/// ([`Duration::ZERO`] = no timeout). +/// +/// Returns `SendStatus { instructions_sent: true, outcome: Sent, did_print: +/// false, ready_for_next_job: false }` on success. +pub fn send_network( + addr: &str, + data: &[u8], + blocking: bool, + timeout: Duration, +) -> Result { + let _ = blocking; // the network backend has no read-back, see module docs + let (host, port) = parse_address(addr)?; + let addrs: Vec = (host.as_str(), port) + .to_socket_addrs() + .map_err(|e| Error::Connect { + addr: format!("{host}:{port}"), + source: e, + })? + .collect(); + if addrs.is_empty() { + return Err(Error::NoAddress(format!("{host}:{port}"))); + } + + let mut stream = None; + let mut last_err = None; + for sa in &addrs { + let res = if timeout.is_zero() { + TcpStream::connect(sa) + } else { + TcpStream::connect_timeout(sa, timeout) + }; + match res { + Ok(s) => { + stream = Some(s); + break; + } + Err(e) => last_err = Some(e), + } + } + let mut stream = match stream { + Some(s) => s, + None => { + return Err(Error::Connect { + addr: format!("{host}:{port}"), + source: last_err.unwrap_or_else(|| io::Error::other("no address")), + }); + } + }; + // Python sets TCP_NODELAY before connect(); before the first write is equivalent. + let _ = stream.set_nodelay(true); + + let result = write_all_deadline(&mut stream, data, timeout); + // dispose(): shutdown(SHUT_RDWR) + close(), errors ignored + let _ = stream.shutdown(Shutdown::Both); + drop(stream); + result.map_err(Error::Write)?; + + Ok(SendStatus { + instructions_sent: true, + outcome: Outcome::Sent, + did_print: false, + ready_for_next_job: false, + }) +} + +/// Largest single `write()`; keeps the deadline effective on Windows. +const WRITE_CHUNK: usize = 64 * 1024; + +/// `socket.sendall` with a total deadline (CPython >= 3.5 semantics). +fn write_all_deadline(stream: &mut TcpStream, data: &[u8], timeout: Duration) -> io::Result<()> { + let deadline = (!timeout.is_zero()).then(|| Instant::now() + timeout); + let mut off = 0; + while off < data.len() { + if let Some(deadline) = deadline { + let remaining = deadline.saturating_duration_since(Instant::now()); + if remaining.is_zero() { + return Err(io::Error::new(io::ErrorKind::TimedOut, "timed out")); + } + stream.set_write_timeout(Some(remaining))?; + } + // Bounded chunks so a stalled printer is noticed per chunk (Windows + // accepts arbitrarily large single sends into its loopback buffers). + let end = data.len().min(off + WRITE_CHUNK); + match stream.write(&data[off..end]) { + Ok(0) => return Err(io::ErrorKind::WriteZero.into()), + Ok(n) => off += n, + Err(e) if e.kind() == io::ErrorKind::Interrupted => {} + Err(e) if e.kind() == io::ErrorKind::WouldBlock => { + return Err(io::Error::new(io::ErrorKind::TimedOut, "timed out")); + } + Err(e) => return Err(e), + } + } + stream.flush() +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn address_parsing() { + assert_eq!( + parse_address("tcp://192.168.1.50").unwrap(), + ("192.168.1.50".into(), 9100) + ); + assert_eq!( + parse_address("192.168.1.50").unwrap(), + ("192.168.1.50".into(), 9100) + ); + assert_eq!( + parse_address("tcp://Printer.local:9101/x").unwrap(), + ("printer.local".into(), 9101) + ); + assert_eq!( + parse_address("tcp://[fe80::1]:9100").unwrap(), + ("fe80::1".into(), 9100) + ); + assert_eq!(parse_address("tcp://[::1]").unwrap(), ("::1".into(), 9100)); + assert_eq!(parse_address("host:0").unwrap(), ("host".into(), 9100)); + assert_eq!(parse_address("host:").unwrap(), ("host".into(), 9100)); + assert!(parse_address("tcp://").is_err()); + assert!(parse_address("host:99999").is_err()); + assert!(parse_address("host:abc").is_err()); + } +} diff --git a/crates/brother-ql/src/packbits.rs b/crates/brother-ql/src/packbits.rs new file mode 100644 index 0000000..72f553a --- /dev/null +++ b/crates/brother-ql/src/packbits.rs @@ -0,0 +1,142 @@ +//! PackBits run-length encoding, a line-for-line port of the `packbits` 0.6 +//! Python package used by brother_ql (its exact run splitting matters for +//! byte-identical output). + +/// Encodes `data` with PackBits exactly like `packbits.encode`. +pub fn encode(data: &[u8]) -> Vec { + if data.is_empty() { + return Vec::new(); + } + if data.len() == 1 { + return vec![0, data[0]]; + } + + const MAX_LENGTH: usize = 127; + #[derive(PartialEq)] + enum State { + Raw, + Rle, + } + + let mut result = Vec::with_capacity(data.len() + data.len() / 128 + 2); + let mut buf: Vec = Vec::with_capacity(MAX_LENGTH); + let mut pos = 0usize; + let mut repeat_count = 0usize; + let mut state = State::Raw; + + fn finish_raw(result: &mut Vec, buf: &mut Vec) { + if buf.is_empty() { + return; + } + result.push((buf.len() - 1) as u8); + result.extend_from_slice(buf); + buf.clear(); + } + fn finish_rle(result: &mut Vec, repeat_count: usize, byte: u8) { + result.push((256 - (repeat_count - 1)) as u8); + result.push(byte); + } + + while pos < data.len() - 1 { + let current_byte = data[pos]; + if data[pos] == data[pos + 1] { + match state { + State::Raw => { + finish_raw(&mut result, &mut buf); + state = State::Rle; + repeat_count = 1; + } + State::Rle => { + if repeat_count == MAX_LENGTH { + finish_rle(&mut result, repeat_count, data[pos]); + repeat_count = 0; + } + repeat_count += 1; + } + } + } else { + match state { + State::Rle => { + repeat_count += 1; + finish_rle(&mut result, repeat_count, data[pos]); + state = State::Raw; + repeat_count = 0; + } + State::Raw => { + if buf.len() == MAX_LENGTH { + finish_raw(&mut result, &mut buf); + } + buf.push(current_byte); + } + } + } + pos += 1; + } + + if state == State::Raw { + buf.push(data[pos]); + finish_raw(&mut result, &mut buf); + } else { + repeat_count += 1; + finish_rle(&mut result, repeat_count, data[pos]); + } + result +} + +/// Decodes PackBits data (like `packbits.decode`). +pub fn decode(data: &[u8]) -> Vec { + let mut result = Vec::new(); + let mut pos = 0usize; + while pos < data.len() { + let header = data[pos] as i8; + pos += 1; + if header >= 0 { + let n = header as usize + 1; + let end = (pos + n).min(data.len()); + result.extend_from_slice(&data[pos..end]); + pos += n; + } else if header == -128 { + // no-op + } else { + if pos < data.len() { + let n = (1 - i32::from(header)) as usize; + result.extend(std::iter::repeat_n(data[pos], n)); + } + pos += 1; + } + } + result +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn known_vectors() { + // Apple's PackBits example (as produced by the Python implementation) + let raw = [ + 0xAA, 0xAA, 0xAA, 0x80, 0x00, 0x2A, 0xAA, 0xAA, 0xAA, 0xAA, 0x80, 0x00, 0x2A, 0x22, + 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, + ]; + let enc = encode(&raw); + assert_eq!( + enc, + [ + 0xFE, 0xAA, 0x02, 0x80, 0x00, 0x2A, 0xFD, 0xAA, 0x03, 0x80, 0x00, 0x2A, 0x22, 0xF7, + 0xAA + ] + ); + assert_eq!(decode(&enc), raw); + assert_eq!(encode(&[]), Vec::::new()); + assert_eq!(encode(&[7]), vec![0, 7]); + assert_eq!(encode(&[0u8; 90]), vec![(256 - 89) as u8, 0]); + } + + #[test] + fn roundtrip_long_runs() { + let mut data = vec![0u8; 300]; + data.extend((0..=255u8).cycle().take(400)); + assert_eq!(decode(&encode(&data)), data); + } +} diff --git a/crates/brother-ql/src/raster.rs b/crates/brother-ql/src/raster.rs new file mode 100644 index 0000000..a7b648b --- /dev/null +++ b/crates/brother-ql/src/raster.rs @@ -0,0 +1,201 @@ +//! Low-level raster command builder (port of `brother_ql.raster.BrotherQLRaster`). +//! +//! Each `add_*` method appends one command to [`Raster::data`]. Commands the +//! model does not support are skipped silently, exactly like the Python class +//! with its default `exception_on_warning = False` (Python logs a warning). + +use crate::{Bitmap, Error, Model, packbits}; + +/// Instruction buffer for one print job. +#[derive(Debug, Clone)] +pub struct Raster { + /// The model the instructions are generated for. + pub model: Model, + /// The instruction bytes generated so far. + pub data: Vec, + /// Page counter. Only reset by `add_initialize`; brother_ql never + /// increments it, so the "starting page" byte of `ESC i z` is always 0. + pub page_number: u32, + /// Bit 3 of `ESC i K`. + pub cut_at_end: bool, + /// Bit 6 of `ESC i K`. + pub dpi_600: bool, + /// Bit 0 of `ESC i K`. + pub two_color_printing: bool, + /// Media type for `ESC i z` (0x0A endless, 0x0B die-cut). + pub mtype: Option, + /// Media width in mm for `ESC i z`. + pub mwidth: Option, + /// Media length in mm for `ESC i z` (0 for endless). + pub mlength: Option, + /// Print quality flag (bit 6 of the `ESC i z` valid flags). + pub pquality: bool, + compression: bool, +} + +impl Raster { + /// A new empty instruction buffer for `model`. + pub fn new(model: &Model) -> Self { + Self { + model: *model, + data: Vec::new(), + page_number: 0, + cut_at_end: true, + dpi_600: false, + two_color_printing: false, + mtype: None, + mwidth: None, + mlength: None, + pquality: true, + compression: false, + } + } + + /// `ESC @` (initialize); resets the page counter. + pub fn add_initialize(&mut self) { + self.page_number = 0; + self.data.extend_from_slice(b"\x1B\x40"); + } + + /// `ESC i S` (status information request). + pub fn add_status_information(&mut self) { + self.data.extend_from_slice(b"\x1B\x69\x53"); + } + + /// `ESC i a 0x01` (switch to raster mode) if the model supports mode setting. + pub fn add_switch_mode(&mut self) { + if self.model.mode_setting { + self.data.extend_from_slice(b"\x1B\x69\x61\x01"); + } + } + + /// `num_invalidate_bytes` NUL bytes (clears the printer's command buffer). + pub fn add_invalidate(&mut self) { + self.data.resize( + self.data.len() + self.model.num_invalidate_bytes as usize, + 0, + ); + } + + /// `ESC i z` print information: valid flags, media type/width/length, + /// raster line count (u32 LE), starting-page flag, 0x00. + pub fn add_media_and_quality(&mut self, rnumber: u32) { + self.data.extend_from_slice(b"\x1B\x69\x7A"); + let mut valid_flags: u8 = 0x80; + valid_flags |= u8::from(self.mtype.is_some()) << 1; + valid_flags |= u8::from(self.mwidth.is_some()) << 2; + valid_flags |= u8::from(self.mlength.is_some()) << 3; + valid_flags |= u8::from(self.pquality) << 6; + self.data.push(valid_flags); + for v in [self.mtype, self.mwidth, self.mlength] { + self.data.push(v.unwrap_or(0)); + } + self.data.extend_from_slice(&rnumber.to_le_bytes()); + self.data.push(if self.page_number == 0 { 0 } else { 1 }); + self.data.push(0); + } + + /// `ESC i M` various mode: auto cut flag in bit 6 (cutter models only). + pub fn add_autocut(&mut self, autocut: bool) { + if self.model.cutting { + self.data.extend_from_slice(b"\x1B\x69\x4D"); + self.data.push(u8::from(autocut) << 6); + } + } + + /// `ESC i A n`: cut every `n` labels (cutter models only). + pub fn add_cut_every(&mut self, n: u8) { + if self.model.cutting { + self.data.extend_from_slice(b"\x1B\x69\x41"); + self.data.push(n); + } + } + + /// `ESC i K` expanded mode: bit 0 two-colour, bit 3 cut at end, bit 6 600 dpi. + pub fn add_expanded_mode(&mut self) { + if !self.model.expanded_mode { + return; + } + if self.two_color_printing && !self.model.two_color { + return; + } + self.data.extend_from_slice(b"\x1B\x69\x4B"); + let mut flags = 0u8; + flags |= u8::from(self.cut_at_end) << 3; + flags |= u8::from(self.dpi_600) << 6; + flags |= u8::from(self.two_color_printing); + self.data.push(flags); + } + + /// `ESC i d` margin (feed) amount in dots, u16 LE. + pub fn add_margins(&mut self, dots: u16) { + self.data.extend_from_slice(b"\x1B\x69\x64"); + self.data.extend_from_slice(&dots.to_le_bytes()); + } + + /// `M 0x02` / `M 0x00` (PackBits compression on/off), compression models only. + pub fn add_compression(&mut self, compression: bool) { + if self.model.compression { + self.compression = compression; + self.data.push(0x4D); + self.data.push(u8::from(compression) << 1); + } + } + + /// Raster line width in dots. + pub fn pixel_width(&self) -> u32 { + self.model.pixel_width() + } + + /// Appends the raster lines of a black/white image that is already + /// `pixel_width()` dots wide (`true` = print a dot). Each line is mirrored + /// left-right, packed MSB-first and sent as `g 0x00 ` + /// (PackBits-compressed if compression was enabled). + pub fn add_raster_data(&mut self, image: &Bitmap) -> Result<(), Error> { + let expected = self.pixel_width(); + if image.width() != expected { + return Err(Error::WrongPixelWidth { + width: image.width(), + expected, + }); + } + let (min, max) = self.model.min_max_length_dots; + if !(min..=max).contains(&image.height()) { + return Err(Error::InvalidRasterHeight { + height: image.height(), + min, + max, + model: self.model.identifier, + }); + } + let row_len = (expected / 8) as usize; + let mut row = vec![0u8; row_len]; + for y in 0..image.height() { + row.fill(0); + for (x, &black) in image.row(y).iter().enumerate() { + if black { + // FLIP_LEFT_RIGHT, then pack MSB first + let fx = expected as usize - 1 - x; + row[fx / 8] |= 0x80 >> (fx % 8); + } + } + self.data.extend_from_slice(b"\x67\x00"); + let payload = if self.compression { + packbits::encode(&row) + } else { + row.clone() + }; + let len = u8::try_from(payload.len()).map_err(|_| Error::RowTooLong(payload.len()))?; + self.data.push(len); + self.data.extend_from_slice(&payload); + } + Ok(()) + } + + /// Print command: `0x1A` (print + feed, last page) or `0x0C` (form feed, + /// more pages follow). Note `convert` always uses `last_page = true`, as + /// brother_ql does. + pub fn add_print(&mut self, last_page: bool) { + self.data.push(if last_page { 0x1A } else { 0x0C }); + } +} diff --git a/crates/brother-ql/tests/golden.rs b/crates/brother-ql/tests/golden.rs new file mode 100644 index 0000000..90881ff --- /dev/null +++ b/crates/brother-ql/tests/golden.rs @@ -0,0 +1,171 @@ +//! Byte-for-byte comparison against Python brother_ql output. +//! +//! The golden data is produced by `tools/golden.py` (brother_ql_next 0.12 + +//! Pillow): each manifest line names the input PNG(s), model, label and +//! `convert()` keyword arguments; `.bin` is what Python produced. + +use std::collections::HashMap; +use std::fs::File; +use std::path::{Path, PathBuf}; + +use brother_ql::{Bitmap, ConvertOptions, Label, Model, Rotate, convert}; + +fn golden_dir() -> PathBuf { + Path::new(env!("CARGO_MANIFEST_DIR")) + .join("tests") + .join("golden") +} + +fn load_png(path: &Path) -> Bitmap { + let mut decoder = png::Decoder::new(File::open(path).unwrap()); + decoder.set_transformations(png::Transformations::EXPAND | png::Transformations::STRIP_16); + let mut reader = decoder.read_info().unwrap(); + let mut buf = vec![0; reader.output_buffer_size()]; + let info = reader.next_frame(&mut buf).unwrap(); + let channels = match info.color_type { + png::ColorType::Grayscale => 1, + png::ColorType::GrayscaleAlpha => 2, + png::ColorType::Rgb => 3, + png::ColorType::Rgba => 4, + png::ColorType::Indexed => panic!("palette not expanded"), + }; + let (w, h) = (info.width, info.height); + Bitmap::from_fn(w, h, |x, y| { + let i = y as usize * info.line_size + x as usize * channels; + buf[i] < 128 + }) +} + +fn parse_bool(v: &str) -> bool { + match v { + "True" | "true" | "1" => true, + "False" | "false" | "0" => false, + _ => panic!("bad bool {v}"), + } +} + +fn parse_options(tokens: &[&str]) -> ConvertOptions { + let mut o = ConvertOptions::default(); + for t in tokens { + let (k, v) = t.split_once('=').unwrap(); + match k { + "cut" => o.cut = parse_bool(v), + "compress" => o.compress = parse_bool(v), + "dpi_600" => o.dpi_600 = parse_bool(v), + "hq" => o.hq = parse_bool(v), + "dither" => o.dither = parse_bool(v), + "threshold" => o.threshold = v.parse().unwrap(), + "rotate" => { + o.rotate = match v { + "auto" => Rotate::Auto, + "0" => Rotate::R0, + "90" => Rotate::R90, + "180" => Rotate::R180, + "270" => Rotate::R270, + _ => panic!("bad rotate {v}"), + } + } + _ => panic!("unknown option {k}"), + } + } + o +} + +fn first_difference(a: &[u8], b: &[u8]) -> Option { + a.iter() + .zip(b) + .position(|(x, y)| x != y) + .or_else(|| (a.len() != b.len()).then_some(a.len().min(b.len()))) +} + +#[test] +fn convert_matches_python_byte_for_byte() { + let dir = golden_dir(); + let manifest = std::fs::read_to_string(dir.join("manifest.txt")) + .expect("golden data missing: run tools/golden.py"); + let mut images: HashMap = HashMap::new(); + let mut failures = Vec::new(); + let mut passed = 0; + let mut label_cases = 0; + for line in manifest.lines() { + let line = line.trim(); + if line.is_empty() || line.starts_with('#') { + continue; + } + let tokens: Vec<&str> = line.split_whitespace().collect(); + let (name, model, label, pngs) = (tokens[0], tokens[1], tokens[2], tokens[3]); + let opts = parse_options(&tokens[4..]); + let bitmaps: Vec = pngs + .split(',') + .map(|p| { + images + .entry(p.to_string()) + .or_insert_with(|| load_png(&dir.join(p))) + .clone() + }) + .collect(); + let model = Model::lookup(model).unwrap(); + let label = Label::lookup(label).unwrap(); + let expected = std::fs::read(dir.join(format!("{name}.bin"))).unwrap(); + let actual = convert(model, label, &bitmaps, &opts) + .unwrap_or_else(|e| panic!("{name}: convert failed: {e}")); + match first_difference(&actual, &expected) { + None => { + passed += 1; + if name.starts_with("label_L") { + label_cases += 1; + } + } + Some(at) => failures.push(format!( + "{name}: differs at byte {at} (rust {} bytes, python {} bytes): rust {:02X?} python {:02X?}", + actual.len(), + expected.len(), + &actual[at..(at + 8).min(actual.len())], + &expected[at..(at + 8).min(expected.len())], + )), + } + } + println!("{passed} golden cases byte-identical ({label_cases} lamp-label cases)"); + assert!( + failures.is_empty(), + "{} mismatches:\n{}", + failures.len(), + failures.join("\n") + ); + assert!(passed >= 50, "too few golden cases ({passed})"); +} + +#[test] +fn convert_rejects_like_python() { + let model = Model::lookup("QL-820NWB").unwrap(); + // d12 has 94 printable rows, below the QL-820NWB minimum of 150 + let d12 = Label::lookup("d12").unwrap(); + let err = convert( + model, + d12, + &[Bitmap::new(94, 94)], + &ConvertOptions::default(), + ) + .unwrap_err(); + assert!( + matches!( + err, + brother_ql::Error::InvalidRasterHeight { height: 94, .. } + ), + "{err}" + ); + let l = Label::lookup("23x23").unwrap(); + let err = convert( + model, + l, + &[Bitmap::new(202, 201)], + &ConvertOptions::default(), + ) + .unwrap_err(); + assert_eq!( + err.to_string(), + "bad image dimensions: 202x201, expecting 202x202" + ); + assert!(Model::lookup("QL-9").is_err()); + assert!(Label::lookup("23").is_err()); +} diff --git a/crates/brother-ql/tests/golden/black_202.png b/crates/brother-ql/tests/golden/black_202.png new file mode 100644 index 0000000000000000000000000000000000000000..b0b432d0f1e24a39032fd825488f82d27dc5b48b GIT binary patch literal 85 zcmeAS@N?(olHy`uVBq!ia0vp^r$CqyNHCm{d&CN)WISCQLn`LHJ=h2mJiOp%u>3=& cP_T**yrO;#j0YB8N&-oFy85}Sb4q9e06oAJv;Y7A literal 0 HcmV?d00001 diff --git a/crates/brother-ql/tests/golden/black_202_compress.bin b/crates/brother-ql/tests/golden/black_202_compress.bin new file mode 100644 index 0000000000000000000000000000000000000000..edd54b421ad62f57c49e5edccfd0d74d11c489a4 GIT binary patch literal 3072 zcmb2nOk`vj1%oOCq#dMzu_B!rES*_(j$2&(6xemrnZ7`AN1(VjhjeBN1A{M9Is?}q s1_t|={~10UV;JR(hQVk$7|jc#<-ur~I9e}^R)?cag3)FX!KR@U03_EoZ2$lO literal 0 HcmV?d00001 diff --git a/crates/brother-ql/tests/golden/black_202_x1.bin b/crates/brother-ql/tests/golden/black_202_x1.bin new file mode 100644 index 0000000000000000000000000000000000000000..57e992814f120fdc2fb157724c6647c89c171a09 GIT binary patch literal 19230 zcmeIwv1!9V0ESVeGk5@jZWP?Pw{#?0n@vi&?LVEX)d45@( zrxF-%W4o0xk7IuS?AP^r`?@hdxBkBMkKLG;W%*i8w+F9(ch2tvf92(ghXqRtWV9A6 zDUi`xu%tjnYr&EN8Lb6N3S_hvEGdxDTCk)*Mr*;60vW9ZOA2JP7Az@{(OR&iKt^l9 zk^&j61xpHKv=%HWkkMMOq(DY%!IAC>L)U literal 0 HcmV?d00001 diff --git a/crates/brother-ql/tests/golden/black_202_x2.bin b/crates/brother-ql/tests/golden/black_202_x2.bin new file mode 100644 index 0000000000000000000000000000000000000000..86232575182aa460cf0970a7eb3514eb80140aaf GIT binary patch literal 38050 zcmeI)F-pT=0EXdo6MBF`|HIhM#mUW05ahptM|AKky+Io~zv3X24o}865RxZf){ObS zSsV`~Fb-pVD`UQn`Sr8i?Y?h!H|ERQk83|Yjrp-GpUd0r#Pj8seWeQUn)a926V N3Qt!*mvv4FO#rb1GEo2k literal 0 HcmV?d00001 diff --git a/crates/brother-ql/tests/golden/checker_202_compress.bin b/crates/brother-ql/tests/golden/checker_202_compress.bin new file mode 100644 index 0000000000000000000000000000000000000000..dfea1c08c9cc830bed7c40fa5882e260fafac617 GIT binary patch literal 3072 zcmb2nOk`vj1%oOCq#dMzu_B!rES*_(j$2&(6xemrnZ7`AN1(VjhjeBN1A{M9Is?}q z1_sfWp$q}X7$6+2m#Y{Sz&N8aqoFgJLPm4RXn8PNCXUt%45M`;!)O=)8%(3=03HTX E0N`v|H~;_u literal 0 HcmV?d00001 diff --git a/crates/brother-ql/tests/golden/checker_202_x1.bin b/crates/brother-ql/tests/golden/checker_202_x1.bin new file mode 100644 index 0000000000000000000000000000000000000000..33f08886e1715d0be11b00426de0820f93c5792a GIT binary patch literal 19230 zcmeIxF-pWh7=Y2(3D&aU+`v<4Ey99qVk9x z%a~s-CUaH-<8CZpWz0`we*eDO?Y`F2jrnm|zhBlLF30>jO>fil`r!I-V)nmyt8Me! z&lB_U2b(+j5hC*=j_qb+QOhQ>UN;thXtJm!S=5p&YDpHgB#T;-MJ>sqmSj;&vZy6l z)RHV}Nfxyvi&~OJEy<#mWKm19s3lp{k}PUT7PTacT9QRA$)c8IQA@I@C0W#xENV#> zwIqvLl0_}aqLyS)OR}gXS=5p&YDpHgB#T;-MJ>sqmSj;&vZy6l)RHV}Nfxyvi&~OJ zEy<#mWKm19s3lp{k}PUT7PTacT9QRA$)c8IQA@I@C0W#xENV#>wIqvLl0_}a^8aeN F`2oHCh;aY_ literal 0 HcmV?d00001 diff --git a/crates/brother-ql/tests/golden/checker_202_x2.bin b/crates/brother-ql/tests/golden/checker_202_x2.bin new file mode 100644 index 0000000000000000000000000000000000000000..b80be8a5861b33fef12db4b8b5bd788582c6b930 GIT binary patch literal 38050 zcmeI)F-pWh06@{$3D&Y;Zr~}j7C{gjJ3)|K!P8iK6bsMf5||?JR|G9wc+-SQAWYu; zq|CfLolM5R5}2>%{jSW*{k*(>p6zxY>+0s^c7OhQfBxolUY@7vWqMpMoIe~GcfWY5 zar4Xf1LN%vZf@lpMCKcgF&Qjs86xX(uy{k0MJ>sqmSj;&vZy6l)RHV}Nfxyvi&~OJ zEy<#mWKm19s3lp{k}PUT7PTacT9QRA$)c8IQA@I@C0W#xENV#>wIqvLl0_}aqLyS) zOR}gXS=5p&YDpHgB#T;-MJ>sqmSj;&vZy6l)RHV}Nfxyvi&~OJEy<#mWKm19s3lp{ zk}PUT7PTacT9QRA$)c8IQA@I@C0W#xENV#>wIqvLl0_}aqLyS)OR}gXS=5p&YDt#k ztL4H!m^M54sq zmSj;&vZy6l)RHV}Nfxyvi&~OJEy<#mWKm19s3lp{k}PUT7PTacT9QRA$)c8IQA@I@ zC0W#xENV#>wIqvLl0_}aqLyS)OR}gXS=5p&YDpHgB#T;-MJ>sqmSj;&vZy6l)RHV} zNfxyvi&~OJEy<#mWKm19s3lp{k}PUT7PTacT9QRA$)c8IQA@I@C0W#xENV#>wIqvL Nl0_}aa(uO1d;wS(4#@xj literal 0 HcmV?d00001 diff --git a/crates/brother-ql/tests/golden/corner_bl.png b/crates/brother-ql/tests/golden/corner_bl.png new file mode 100644 index 0000000000000000000000000000000000000000..992988916ebf52e9f1a820e46a5ad3f12e4ee935 GIT binary patch literal 129 zcmeAS@N?(olHy`uVBq!ia0vp^r$CqyNHCm{d&CN)JUm?-Ln`LHy|9q6!9n1_hUSy? zrfSU5#ljPA?23D@Gp}0PIA~{J-W2JlZn&sFe~(38X4iPleC6l;H6TkEJYD@<);T3K F0RVZ1nK0EXdo6M6u_fAJ_fmrmW>1VR2Qc*G8#siE^rhl)_jlkp9Ns{2uf7Z@b&w9=99ww7&mZ-yc85ye!LgIX^xeo^g2&f5zGWH}7x>WG)UO z79_N>h=Yg)32iLmAYws68;dxISdh@hA`T)JB($-JgNOwQZ7kv-VnIS1i#Ui_kkG~= z4k8vLw6TbThy@94EaD(yK|&jgIEYw~(8eMTA{HdHv513+1qp2|;vix{LK}-Xh**%& z#v%?P79_N>h=Yg)32iLmAYws68;dxISdh@hA`T)JB($-JgNOwQZ7kv-VnIS1i#Ui_ zkkG~=4k8vLw6TbThy@94EaD(yK|&jgIEYw~(8eMTA{HdHv513+1qp2|;vix{LK}-X Ph**%&#v%^leOdN*ZX==S literal 0 HcmV?d00001 diff --git a/crates/brother-ql/tests/golden/corner_br_x2.bin b/crates/brother-ql/tests/golden/corner_br_x2.bin new file mode 100644 index 0000000000000000000000000000000000000000..cd0d2be2f30bef3bccd2e63cf45ccde1b6624465 GIT binary patch literal 38050 zcmeI)F-jc)7)9ZiF5m(Lr^!;Z4yn@F1q7KbWQi%VCLh8H9Joyi!3W3Ya<4E9-~9DE z&R<_H{e3Ed79^Ch zh=URf63SS_L5T$kWh~;L#Dat}7I9EwK|&deI4H3op^QZwlvt2Z#v%?%EJ!G05eFp} zB$Tm;gAxl8%2>ofi3JH|EaITVf`l>_aZqAGLK%xVD6t@+j71!jSddW0A`VI{NGM|w z2PGCHl(C3|5(^T_Sj0hz1qo#=;-K6v%R|4x#7F$UyxmXUo6j#DODt1hj$KPEQ(%r= zODt1hj$KPEQ(%r=ODt1hj$KPEQ(%r=ODt1hj$KPEQ(%r=ODt1hj$KPEQ(%r=ODt1h zj$KPEQ(%r=ODt1hj$KPEQ(%r=ODt1hj$KPEQ(%r=ODt1hj$KPEQ(%r=ODt1hj$KPE zQ(%r=ODt1hj$KPEQ(%r=ODt1hj$KPEQ(%r=ODt1hj$KPEQ(%r=ODt1hj$KPEQ(%r= fODt1hj$KPEQ(%r=ODt1hj$KPEQ(%s_do2%dHgG|= literal 0 HcmV?d00001 diff --git a/crates/brother-ql/tests/golden/corner_tl.png b/crates/brother-ql/tests/golden/corner_tl.png new file mode 100644 index 0000000000000000000000000000000000000000..c84002af579c0725faeb993c5a069ee161088433 GIT binary patch literal 131 zcmeAS@N?(olHy`uVBq!ia0vp^r$CqyNHCm{d&CN)ygXeTLn`LHy|9q6!9d`^f%c=3 zylUCGKI#w79ZQ{8`XMfxZ{P2bv?WE0?`W8x>cvH^kiT~$eYQ+x(Tu!HAk#fv{an^L HB{Ts5V`noh literal 0 HcmV?d00001 diff --git a/crates/brother-ql/tests/golden/corner_tl_rot0.bin b/crates/brother-ql/tests/golden/corner_tl_rot0.bin new file mode 100644 index 0000000000000000000000000000000000000000..0c66895bec4dc3ec6630d566d7d11e601a763dca GIT binary patch literal 19230 zcmeIwF=_%q0EW>`7qGDtGM6#6q)L}AAjn+7BU*T-EU7=%R^)B@4LdAv|1p2x7SB@& zjN@4U%9!6{UhliZ;r9P^V}7mubM2@1G0)3#S$?)Zd%u0WdHV43&9@&Mx;%lfU`c_D z)`BGkGFl6k6v${TSW+OPwO~nsjMjoB1u|L-mK4ZnEm%?@qqSg3fsEFIB?U5C3zihf zXf0S$AfvTlNr8;kf+YnqS__sG$Y?ECQXr$XU`c_D)`BGkGFl6k6v${TSW+OPwO~ns zjMjoB1u|L-mK4ZnEm%?@qqSg3fsEFIB?U5C3zihfXf0S$AfvTlNr8;kf+YnqS__sG Q$Y?ECQXr$Xyco;JAJ&+m*Z=?k literal 0 HcmV?d00001 diff --git a/crates/brother-ql/tests/golden/corner_tl_rot180.bin b/crates/brother-ql/tests/golden/corner_tl_rot180.bin new file mode 100644 index 0000000000000000000000000000000000000000..b93594952580f2938ea871a2d43c4906ec5e4107 GIT binary patch literal 19230 zcmeIwF=_%q0EW@E3wQv*X*`OlC6!&efFN@Pk7$uIxmbT)5G1@Uzhaqr^N;znS$uCL zFpgt=l`+p_-hQ{c-TisGF~8RSx%Sh?n3rX_F5j;^wx6dh7Az@{(OR&iKt^l9k^&j6 z1xpHKv=%HWkkMMOq(DY%!IAs{2uf7Z@b&w9=99ww7&mZ-yc85ye!LgIX^xeo^g2&f5zGWH}7x>WG)UO z79_N>h=Yg)32iLmAYws68;dxISdh@hA`T)JB($-JgNOwQZ7kv-VnIS1i#Ui_kkG~= z4k8vLw6TbThy@94EaD(yK|&jgIEYw~(8eMTA{HdHv513+1qp2|;vix{LK}-Xh**%& z#v%?P79_N>h=Yg)32iLmAYws68;dxISdh@hA`T)JB($-JgNOwQZ7kv-VnIS1i#Ui_ zkkG~=4k8vLw6TbThy@94EaD(yK|&jgIEYw~(8eMTA{HdHv513+1qp2|;vix{LK}-X Ph**%&#v%^leOdN*ZX==S literal 0 HcmV?d00001 diff --git a/crates/brother-ql/tests/golden/corner_tl_rot90.bin b/crates/brother-ql/tests/golden/corner_tl_rot90.bin new file mode 100644 index 0000000000000000000000000000000000000000..46cb002b0add898e6ed96c8af7826ac21adffff5 GIT binary patch literal 19230 zcmeIwF=_%q0EW@E3)rL+GMCXhSlOiu2r^gjh$(U=7wfOE5d`0sU$M-*`N#a-EWVc# z82hol%9y7yum9WK?(crOF^_9Mto{3A%=5BbmY?Sx+t1S$3zihfXf0S$AfvTlNr8;k zf+YnqS__sG$Y?ECQXr$XU`c_D)`BGkGFl6k6v${TSW+OPwO~nsjMjoB1u|L-mK4Zn zEm%?@qqSg3fsEFIB?U5C3zihfXf0S$AfvTlNr8;kf+YnqS__sG$Y?ECQXr$XU`c_D z)`BGkGFl6k6v${TSW+OPwO~nsjMjoB1u|L-mK4ZnEm%?@qqSg3fsEFIB?U5C%e%3B J=7k@NUpGb!q1XTb literal 0 HcmV?d00001 diff --git a/crates/brother-ql/tests/golden/corner_tl_x1.bin b/crates/brother-ql/tests/golden/corner_tl_x1.bin new file mode 100644 index 0000000000000000000000000000000000000000..46cb002b0add898e6ed96c8af7826ac21adffff5 GIT binary patch literal 19230 zcmeIwF=_%q0EW@E3)rL+GMCXhSlOiu2r^gjh$(U=7wfOE5d`0sU$M-*`N#a-EWVc# z82hol%9y7yum9WK?(crOF^_9Mto{3A%=5BbmY?Sx+t1S$3zihfXf0S$AfvTlNr8;k zf+YnqS__sG$Y?ECQXr$XU`c_D)`BGkGFl6k6v${TSW+OPwO~nsjMjoB1u|L-mK4Zn zEm%?@qqSg3fsEFIB?U5C3zihfXf0S$AfvTlNr8;kf+YnqS__sG$Y?ECQXr$XU`c_D z)`BGkGFl6k6v${TSW+OPwO~nsjMjoB1u|L-mK4ZnEm%?@qqSg3fsEFIB?U5C%e%3B J=7k@NUpGb!q1XTb literal 0 HcmV?d00001 diff --git a/crates/brother-ql/tests/golden/corner_tl_x2.bin b/crates/brother-ql/tests/golden/corner_tl_x2.bin new file mode 100644 index 0000000000000000000000000000000000000000..c09f38e469d460096f80e331ed2a25e78f9eb822 GIT binary patch literal 38050 zcmeI)F-ikb07cQU3)rL!(^b literal 0 HcmV?d00001 diff --git a/crates/brother-ql/tests/golden/corner_tr_x1.bin b/crates/brother-ql/tests/golden/corner_tr_x1.bin new file mode 100644 index 0000000000000000000000000000000000000000..0c66895bec4dc3ec6630d566d7d11e601a763dca GIT binary patch literal 19230 zcmeIwF=_%q0EW>`7qGDtGM6#6q)L}AAjn+7BU*T-EU7=%R^)B@4LdAv|1p2x7SB@& zjN@4U%9!6{UhliZ;r9P^V}7mubM2@1G0)3#S$?)Zd%u0WdHV43&9@&Mx;%lfU`c_D z)`BGkGFl6k6v${TSW+OPwO~nsjMjoB1u|L-mK4ZnEm%?@qqSg3fsEFIB?U5C3zihf zXf0S$AfvTlNr8;kf+YnqS__sG$Y?ECQXr$XU`c_D)`BGkGFl6k6v${TSW+OPwO~ns zjMjoB1u|L-mK4ZnEm%?@qqSg3fsEFIB?U5C3zihfXf0S$AfvTlNr8;kf+YnqS__sG Q$Y?ECQXr$Xyco;JAJ&+m*Z=?k literal 0 HcmV?d00001 diff --git a/crates/brother-ql/tests/golden/corner_tr_x2.bin b/crates/brother-ql/tests/golden/corner_tr_x2.bin new file mode 100644 index 0000000000000000000000000000000000000000..ba65572ea8a1a0d137d6192909e0711fa04734a3 GIT binary patch literal 38050 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 literal 0 HcmV?d00001 diff --git a/crates/brother-ql/tests/golden/endless62_dpi600.bin b/crates/brother-ql/tests/golden/endless62_dpi600.bin new file mode 100644 index 0000000000000000000000000000000000000000..43e90258dadf418c05a7d54ca1140da0f9de3fc1 GIT binary patch literal 14394 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 literal 0 HcmV?d00001 diff --git a/crates/brother-ql/tests/golden/endless62_resize500.bin b/crates/brother-ql/tests/golden/endless62_resize500.bin new file mode 100644 index 0000000000000000000000000000000000000000..4f83d9c669cb09875abbe6524a543e375dc3ac6b GIT binary patch literal 26298 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 literal 0 HcmV?d00001 diff --git a/crates/brother-ql/tests/golden/endless62_rot90.bin b/crates/brother-ql/tests/golden/endless62_rot90.bin new file mode 100644 index 0000000000000000000000000000000000000000..022e687ba2809a8f5c5d02e1f95f6a937484b234 GIT binary patch literal 28344 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 literal 0 HcmV?d00001 diff --git a/crates/brother-ql/tests/golden/label_L0001.png b/crates/brother-ql/tests/golden/label_L0001.png new file mode 100644 index 0000000000000000000000000000000000000000..ee365634b142750c5471ea0fbe7e420f22736e40 GIT binary patch literal 516 zcmV+f0{i`mP)vY&xL@O*D&9#}jp_gg{>< zf4=SS0wrujueT7mK`S*zl>!)TpYH4oT@HP9s1XqlJs=|St7v=%^^gv$p z=V^YgFxEGOoCL-nUIIp>M1}{YR15uRQA$-sF+}DF?(9K)Nep8nCJ-AB&XmSbr;B-0 z;3l`>(0&z-&opETXT;O^Y~aOc$i&b|a5R}}rdJw632A;~<4tlKUlv21uT9!4K!o4w z{bVU`9f}Bzj}VJmhkEX9M%(A5kA zMO{(rOQ*TUYOMNL8E24Ur`XZWe>moP?@~U_Hhpt!&f*U!cM?^JPusZw0000ej75fx@p)6h$7*bB8`d9zkOU1MVI5lZu;v z2xOiS1wVnvHj!MYkEfqUDe3p$HYwVxBG7;AF)RK4OTYj5_x;VypFFyLe~120=>Pn# z-+xc(NBXK8c8I%d1503W3Aml%mcZf?a67{-fyE`@c7|I5i%Y=m47UUpmw?+DZg~Y* zPHczmn6~+yJEE6%KAX@GC%QL;C3UA`m)$br#DXu@=5GRQ%VX;u8VQ!&l%C~fTj?-nH7ro9{Y)zAhTWv`aae&B4R3dJn zNHg-X5=lm0LJ=IvlF~8dnmZRcg+El?Vz~t+H^i@o#Zs<>xmj_*ofgdVv>25g7-xP- zt8OVf3yHX0{+f}OP$U_72}K%l3q=}n3q=q|Z9%)Vu)to`EoL=NXoz16%QS%^=JU-Q z%q(x%`FP?np+g&HMc0lYi^NWJA5Jg8&AOj8<3J?PwW$f5+*s`Aw`$2ATEIjci7@IP3_~ibPC~kmhBmavj{$S$I(}bO9vhXs_Ef9t- zPyEMP#ji>LXE6sA9&;17c70e7eFwXxN=qCZ`UVZs&V|5yKG+JiMi9pa4dK}Wi@jn$ zvLEs9{MN8sLGO_zZt3{K62F1?6HWZbbWaoCELiZYk#8QS5*F*Jki`~oDh8U)Zp|$c zKW5mm)CqOegPGq{E0V;05y2!S|F=N%-qx_h@~4PL;G&2li7O$OBVIQP%W}svpKdHD zmK2&G?$&sQ{vJ6gUgzh{`#jU!61J1Lk+={RPl`CqJt?aBt+~CV(=pFyy>~3Wr%}W` zwoDXpfGC+LMck7j&d6gYqKrI}A~@1Q%Eq!>cjsA7vH#TE;&}@~uEZ~f#j{)rbGPD* zD=nDkx*5e8n9ck-t+^%6EGXi>{5d0!q=+)|NQyY(o)mG!Jt=}XVhh@P0}Jfc+~QWV z36=Pzu+#}8G4B_1Ft^z32DI)L&s(bIVDZRXDB_W~P{bo|;fVVgG(|k}77Hu(J&~Q( zq1C^2=4*3HQ&9hIq?c7~(B&p@>J` zLJ{}81?=r?i1Iy=#Vd*TyagfG8VAee#OwISeFuFqa*4l>1+C z<9@mKXk>w>Czd#Tt{O~ju^-2l2lT22Q$cf#g<0T9HJF+clWh)nG^)T;w_<KP4vZYQ38p@`e9mkVp;@x)R5iJ@5HSt*Kme{8S989H*@=dBt{EiAU> z&&9ITbBTJZF*3W6_Z+(wRfDNaYMamqTtH1IHsm3fBkqswam4#$dju@Lt~e!oB;LYS za@B&v+>;`XxFSy04%`Kty~3I08vM=b+JQLQLUsWM3h zy)!RUfM;LVS3RocEu@k6i#Y&<&2B*J%>pHESD3n;~zJnCnJ}*YA}^m^5Uh%^OtT}M#dJ2A7j5PbNuD9L1RMkQ8kz>b*>x; zSXM7yQfSp+ip|28?M%V4dT~F1F>fs@j*&Z6k@zVO|4CScB_)t{$}Pf@5=cAc7GX&V Zq@8k$u%raiPPs)`QUYnG+>&Cs`xn<`UnT$m literal 0 HcmV?d00001 diff --git a/crates/brother-ql/tests/golden/label_L0006.png b/crates/brother-ql/tests/golden/label_L0006.png new file mode 100644 index 0000000000000000000000000000000000000000..7b1f311408e644276448e925d32a8231e3c1ea54 GIT binary patch literal 574 zcmV-E0>S->P){A8qDn8D~)SVJ@6LzygBOb zQ1hDFd#&|fkmOyb|2gVjP{E$P!udQo#ta)GDmz^RAfhCy48fy06rrgHGg0ZG_U#PR zuJNiEBZszdiX|JTyq}mfab*bK%eIg{RTJYbZ;dZP)Sf^fu2T;~Ur096g4wY3f)f#k znDnypN+>z9Iuz&GMjq+3%P~$4%5w%3N%PuiNE=gzIPI^2@)hVc#};w*ax%Rr!WQq| zAq{aOR7+ctls_!^y9B%2~WKJ;UlMS)|5V>yp1 zOYi$V_J`q4Q0E`{bPd z?!NTv?^Ufr`KOtf+w$3#&uv};-xg7QaBdgLFYN->x4%dJEGDx|Qw zmj1dLl`jflVYfjdI4vPj2Kh23^$>wrG2R>(mBzNNh=PU7XL;rC6aexV(^M^?sxbO)1g`|^TgrLr=zRe)#GEz30VgiFcTHZLA!+_o$a{M3r}mC59R>Ao+Tz&>Fo8d2CKC>got z)Q_=&y^_Pi-kc6aztZ?K6hjcLpB2%%*O14uR=LTa1fg2_04!-UDl(FIv0gq^J4T5L`38 zaFoe5u}!uDhCWukk5#Bp<1*9zKn*WkIo}Nw*9@(5Nks@lMdkHDY!W#sNw49C*Ui>;802zn}ZR0fI(1TmS$7 literal 0 HcmV?d00001 diff --git a/crates/brother-ql/tests/golden/label_L0006_nocut.bin b/crates/brother-ql/tests/golden/label_L0006_nocut.bin new file mode 100644 index 0000000000000000000000000000000000000000..5fa0d481ff82b7c35c1a876aaa3717c2eea4aceb GIT binary patch literal 19222 zcmeI3J&qGW6olJyFabytuEYes2}4duMuvohdc7F}1<3BQ z*659_wYMdI`&?c9x~8oi_MbMvuNS4j@NU4Y4Eqnm{_D?IPftH$b;JIB81|n-_!2(q z%5}J@t;^!Fm8NI?cQJ zTMwUWCbWY`0Ef@v5I$PEg}d6Mf^PsnsNex`ur;z^Do;9i7bO=}&az<=l#d4{x20PW z+u=!v+FO_qb($wDiY7EKqSU+a8Q3FR<(9JiCGgU?B=FL5HSp)KJ3?g%yr0q(YT$>! zXu-b#`4Mzm-V^l>kETdJYHukMD$%^lR@A`JTaNG{J`iu8Z_KwBvgGBjf#=4hf#=*J zg6GXbqIu|I4i#0NCYZO+Or-pY_A-^xtDfs3s_%9+dQ=!|SE+=!5t`@Q43Ew3i9n*} zB+d^7&nrb!`NPBW2WazDdrKSKImO}UdgR|+7MI0Tz#Me9xGbgu=AgU9Wib^n2i+|$ Vi>ZJ)=x%XYOa;tAcZ(^@o8KGODy9Gc literal 0 HcmV?d00001 diff --git a/crates/brother-ql/tests/golden/label_L0006_x1.bin b/crates/brother-ql/tests/golden/label_L0006_x1.bin new file mode 100644 index 0000000000000000000000000000000000000000..e5f1a7fce523cab2aab3402b6737691c83a56a6a GIT binary patch literal 19230 zcmeI3&59F26oo5f(SkxR2kb@O#5ikl<<6ZTNM1n%^Ju+x;WOkBdO3?=drtkeiFYAM zoiLHxgh{3#-`t!!b?bD68Frsm!LMhf!0>j!tPHyk!|vZJ)=x%XYOa;tAcgr)7 zWuC%%9*_OFo_U!S{p;Xg6Y6kEx5%;?qm&w1=IIsb68LI<>Iq*@A@uXHpZOweIdt(= zWm(V1D2xQ&&A+tp0|by%-XFeisImq=ZaW=(zhTkac^+d^fm^oo)W|LUezS6TS#@<0 z_2V0z=H2wIhtD+=+QB1$!{=}aA1&R&U2RmsSAg$T@Bld28d)%vM;*M2l8Y*5*)R#p z#{-kw(k+SY@T5cSElh|y&65>H6Pg!M>RtE@?2)ZsAq=Dx>lsC?J#M8Mg1I#s7bxY1I4v%Wy zNS2gxHJTSIaxukoxp*s0XI_3)S;``kz{~QNz)Rzjz)L97!1HFIfiIybpwHmoXyU2M zr<6a6Q$q@76Q7KfW|xl38l8QEC46R}CMQ(k=i8RrPe(c-S)%;mDm?;ai_G|#sg z9-G}0fke$oobC#qSBj?cyNBlw(B`T3mNvLkio;L!$iKNPE{myvIp}V2Sxg1YL3fMG dVk%$`x?5ZpQvq|(-Qu#C3YdfL7E_kjzX7~BEQJ67 literal 0 HcmV?d00001 diff --git a/crates/brother-ql/tests/golden/label_L0006_x2.bin b/crates/brother-ql/tests/golden/label_L0006_x2.bin new file mode 100644 index 0000000000000000000000000000000000000000..a677f862f6c96bf03a3908b0803f498a5eb85c30 GIT binary patch literal 38050 zcmeI5!D<{w5QazSu!aQYXz(8PO|r>3h9_p ztqKxW^$U;qhegu1(C^mQe^*zxX3G21A9sVU?~1_w=RHPcfBLvTefj5y_wWBMz1yFD zL;Eji|MlJe^l2DA55M!eE%A`8un0>?AZ(Odge4>pHp(r+5)ud-G7Yj`JnS zE#t%CPU1f6`Xm~spLoo7mp@1NoHL+1cm(3`IUHiIOt;voHnGI-ApXD-A0Q5G4i*gM zBTsx+kdu0D-G)ifeY`NZnQp1t60aP3Y_SZH$GlpRG@xw~)!2pK!D3`q-s01rBJP2U zBJLrVBmQ+boI#l)K2CKAIpPn4r55%t06!Al%stU4@nVYlp~n^XO z;uo^*^9%FaD=cmLbHrQV;)u7rg(Th<3kvgLSMpF&&+7o&_SrI0`-t!|dFxG|`y}c= zEpecDB`iLA6y{exN3LrL(u=MI3#)4ViejOE4#amLu!O~VDj(A%`ZR3nr zIh{LN0`roqyQSqV5-&7g2}{j#In3RPHkrz~T-i#SGjG2-7N0~Eai9JaaSvP+aZidk z;%%|uh%ZUefH;GLql=xo+-?>8WOqwbDc+O#D`9DeImSMpd9`94*W*ilQe_q_HE-dF zFNZnM&+fU+%&GP}Uwk>tA@sa07Par$SUhh59jru_z1UaDd5bAZyiX!e=Qvne-a--g zyaiswd5-;=JMk>n^A?JDoBp=U<@en47K*s%EgbP>lbesl4|BlY#5sQ_k~oa9q;rTZ zc3BwDXa0KPScx!Ck?1DviJtUa;{H6*8^KanB9dDq9=c_dSP&U4u-HmuLDC}S&DT1e zGm(~BY)ahna$3(fFJ4k;JKwhCF>Ox-C1Y-imraScnZoJ$=Ed7Dkn^d>mK?dKDiVLn zqrDRrVF?L@jdF{ygapDyxkXq)0%4=vA}k?+uu*OimXJW$D7S=IKBxv$$mKs9<);vl zun0>?AZ(Odge4>pHp(r+5)ud-{4W<>9)$Nk1!L;Ji-Ll~VPpZKb4XEA0G~pY#r?%Yhg_Shb$?p1pdgCmaV->`cez}uwzUw!(Qn;IwRX5L)u zfr}!(Jhq3M8nb)8Jhn#=Z;$QSAm;ZRPX(w36VTRcl@u|tOm*6n+tah_Ubz)H;)pHh z8cbA!X|;v|3k+m2HXlpNTS($N)nKYq-#+%~-ra(?1o<>M`v6p06Gt&lmSv2H1z*Fo(muTCojl-J#bvw}0$2 z)K5fz+d)@*s;ylOxhMrirEg_Z<-vAcXR^k8v literal 0 HcmV?d00001 diff --git a/crates/brother-ql/tests/golden/label_L0123.png b/crates/brother-ql/tests/golden/label_L0123.png new file mode 100644 index 0000000000000000000000000000000000000000..688eed0d64b2b4bc428b1f726de2a4a5e5da0f6d GIT binary patch literal 614 zcmV-s0-61ZP) z^TSb>hLmRwFEiJ_L9Idf`>6j8Wy7T)REi)p6roL!;eq#FxO)zFU{9ySP@Gk4p?#Va zyEPcfU^v*;^m(0*hLQ*6IgynI^y3w2Y#5zNv?52I(>ZVfCzqCn1vIq=nI=VU%(7mInZzPgoDCfORm7xGC8j50yy^V!_Y}VU+p)3%5bp;yoqrJ`ClIm^Z zCO7Wm23=dIC*DE8(c;D8rCdf?iw4+#$9_ND82cE2Q1hi!D0hpf4jvxF&n%D90S#(& z=(;t-&wvAVz^+?B&DTIBkUxZc#SnM{g0Yy6opY$^$C2L*^0tKO*HW*eI^09mqc%$o z-MIKQwBw<|Tcp#=d!^9i+aJZmA(Fsr9O^QbGYSPjFEt#EIYcyM^9I}^#Gv~Afy+RcyT5ZyTBQcAsi%-T(jq07*qoM6N<$f+|-Y A`~Uy| literal 0 HcmV?d00001 diff --git a/crates/brother-ql/tests/golden/label_L0123_x1.bin b/crates/brother-ql/tests/golden/label_L0123_x1.bin new file mode 100644 index 0000000000000000000000000000000000000000..81a94ab79ffa69ad888306c50860d70c3b1b86c9 GIT binary patch literal 19230 zcmeI3!HU#C5QclmA%bF#D+Zi5F?tqH-n3rf_a1-M-1EkRh{(g ztbJIr{STX^8aBx^%$J_8E8W!{w%)zlI4gI`K>eaduhhFY_3qQphi7L$v~~6FHR@lY z{?&te_ujb=?k%s`22Z**Ev6-DAX#bAVp@_0l9d)MrX^`0S!vN?T9O8ml@=|gC21g8 zY0+{Av=l>A49en> zOdcCiLD15jbwSKv9VIvC0sEds~b!hsi~t6CO(131{6mb;Jc5fA=E z(5#jRwi~NXCZoJ#%fvRgiii_*)wxk>D9)>{)U1;PuVnT|!89ZnIrA3Gp-i~W{;Za3 z-a>+Z^D+~W;1`$Lg`5ukzL(U(VS<({+IKnEMAff>2>;y^;Sj;o;#-Xtj&tvtp4Oq4 z0gjK2!)(IOCotI88;k$qO0^Tz8Fs=uc}#OTHC4hJn)dAZ>mz}vZ@ zx#6;p(6QjtOQ?X)-SToDHs_U|8;<3VY%BXp#9M1hEm}-V(m=A(q9v*2=|6LD BIG+Fj literal 0 HcmV?d00001 diff --git a/crates/brother-ql/tests/golden/label_L0123_x2.bin b/crates/brother-ql/tests/golden/label_L0123_x2.bin new file mode 100644 index 0000000000000000000000000000000000000000..88dde3190a6e8b370b035679ce2e8364a9644225 GIT binary patch literal 38050 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 literal 0 HcmV?d00001 diff --git a/crates/brother-ql/tests/golden/label_L9_x1.bin b/crates/brother-ql/tests/golden/label_L9_x1.bin new file mode 100644 index 0000000000000000000000000000000000000000..b15fc177b38be19e1145d0f81e41a39359c86ad0 GIT binary patch literal 19230 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 KE~B-%>;C}OLsEJG literal 0 HcmV?d00001 diff --git a/crates/brother-ql/tests/golden/ql1100_62.bin b/crates/brother-ql/tests/golden/ql1100_62.bin new file mode 100644 index 0000000000000000000000000000000000000000..e5a4e9748d749b7b41350e5b138021e1a20b5a29 GIT binary patch literal 9267 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 literal 0 HcmV?d00001 diff --git a/crates/brother-ql/tests/golden/ql570_62x29.bin b/crates/brother-ql/tests/golden/ql570_62x29.bin new file mode 100644 index 0000000000000000000000000000000000000000..99033a49d6126dd1bbd86ee2db12b8014e603fc1 GIT binary patch literal 25431 zcmdqnV{>I~7cJn}w%I|)PRF)w+qP|^W81cE+qT`|c~A13KXG=|{(9BOnDgFQYt;e( z`2XXB&5LcOfNkbJ17a&n<*uT z;G~RGKyQbVMnw&bKc&VE+Iei_k7fQ{_&`BGjlACzFBtIM(~Y8)?f@U8-4(3 zSX%~fOF3O_wgW83K>mSKlD=`&HNE)8ZbU4#HD5a+;0;)Uo>GMKYbhs%xRYXBc5u z%@p~2b#HnZ#FxvgMr8Zjt!RHG^bAU#t!tFn`y=$Uw%MvWS%(k-xLH_q(akoFLi7IX z9K%;;8RF8?Scb7!F6e3fJp^}7rq9G*@}UfH2$i1B+}f_oPAnRK zok9X1uWkstD~Kg=oeRxRZGrZEtveY!jd`aAJ8|eqoorL~CwazEeW?OBxZNIKF>1Ec zG-ifGciXf>m(TRvv2o5z1WAFtr*HD#RdK&aunB;8Azt?h!SoYIXo=0vwNq?&sD$>$ z{ni&Xo!4^@cK??pp_z;kD1VV1-)|gL?8~&Z+Ies8-0(88cs$K0&qwG!BXN!D{fMls zyFC|AO8A#>rk6REi`1dAPQBz6O6&mohOuL3=WHadHe}Q-dxCjA0rH}wUZsuY&g?bP z@pWuFPtVOa4)2K}9Wo@XvTRTWrC?T=au_YBX~B6)o>SPkXW3XfWkPu<{O9Wfjyd! zB%j!dU{v1-fxdZyOUl;o*ER{{A-$2MXQ zTnd3dQe%>xR;C?p6P{lFOYYZb*W&KXJu_3_9NMSHF82$ATm&?IP%r!65F-*4b!E*U zy+)mp4Hi_EHX6ePU-OA8yg2UQd{Ar-1cC0DFtTx*MzS5=s(qQYp(_X5BBm7DDJzoq z4-QGo1e_?&(}|xq=%iue-@vKvzoupbS%l^de7pZI=N>CtMoa157k3l%tO)E5ai$7w z!3Cb-;jf3z=t6QaX1x;={=W!^Botxkz_;!q0eM0$VLeJx&7ALAfPRa5+Gy3-Yv&4J zl-#R}&IoYHt@V;)5!JJy&_=S7yjp5SN>Dm6d5Ga#AY@p=_9}mh#b_=kzbB3ncLMG4 zsq4%V$16mAj2W?&3~uLNVy;O*1-+5-e&bL=J>ldPJ_rFYFb5cy`4_# z$IKfU+kB~d3>J^I9WygL_NeX&$U_JrJR%}RCnNQ)dQ9m2@~kamaojh))o6C_#q#{t z8`nvszY5{zj|skUVCXpY=X3}V(6PIYz8od8U*=+;&3b@gwMU$ScliJIAACCO4#xWZ zGi$~6n4KSb^48+cY&5oW6uddLsOts57wfQB6d5=_*Wi$Dy8kiY!Y5Y4kF*B){v@9) zJE zXOH3$e-_X4nhRBVCY#g7=G^_Y3`w!?x-BrgjZsS9I+U zpNy5ogsAE>@^^mIKUG0J3Wnfkpzw_duZj=C88KRih8D^$JBl}>^KGA}m%mM(3Wxe@ z4Dp%LT9P*b3YZs&ylC4hza%VFJ0pTurjfkH>%$D2-iuYWB&E`A=oz2Zz#y~ve zt3>u1D^6rlaJvc0UC=&;d58s*{l2wjrOacUy!pm~!Pw_FhjckHt;Y;gYf3()-G#gX zWY~4Ocp|Oad#AT<(uU-cfeZi+uket@$F9W`aoCVEg6;@kE;dyq*n0^Mw3-{YO7yX7^3Vq4%j51G4Y;y;(_rxXo6)7rXcPPstLUAqWKU$NGxvXWy#yAMKPp}^zs z=aW_g!7!Ut-1D6r1VoMs1Dp(&@?e+rTIS|5X}VTdwAAXX66Hl@NUNYV<55 zL$L!o`L}t$wlOnK(lHS^QLJlPd>S|VZ%{vqPzT>ZyXAS z`73{j2KT)@GmpG#QcP~7s|XEjpts@^Fzt5`TPNX??0RwCwhOA6SnM|r*Pyy$fygk*bDqyOikgLM zEye@)NfS1}bXw?o6qb);`p(E3_=otKMe{HZBfE=38oUY0X>Jzlx2FfZ%J#unB&0U$ ziQ~p{wf9%CF0Dpua#b4s^JmmgatIio(YlRel}+jP748D>SAJyywrF*3T2ftd9~8$N zA{fGUT&pwXF-5e%V1857iH3UnHDL}wo3yABU@tnOIi9ow5zSENo<2!(ZS(k2x&FUq zTy!53Ge61o#37*_{**(kZ~2?(g!9>w(xiJ*2R<9^sq%)Q>t(4#h$js+BM7sK6`sr= zH<8ZTpYZ;`=#7u%$`A{mow( zF67B~Z@+NwhA-x`6ihqp_|nsZ^!bI$i}mRbAKq2vU1b=aUuSC37TZAi4!dn<(Zs#w z&)ii_B%HSv=iAoq{^vx_jbud*;U8d~Dzn!1h)D65r|qkoVS1}Nb!(#t8> zhH;4+k#dJ^Yz|GBKk_Gixlh_Ijw^SrMiVGWHV%(zta8S_1DJ3#^(X+ZUXM1L@Zr3*ERVZOuXPe5ptSC zm{o~8%;sez6mNXbr@-&SDw-M?Q5jb7!MMWInBV~`p6^Mz0>?{>7iMBMbL0l~Oi1G0 z6_Z|K;0!;>A&h8!1K>c7GO~0aaY62)LW(#KAgYGI_3Q;`9JVq-ANjr4a08wZ;dxVz zfDV1@51^?OnbYh}y@1M|Ds>w?QT(bCf}6leqWOvRs@=Fx?0xe*L-?y&_^WEU}69eDDtt2?`32FXR^m=qv5NYi(;{LfJdvlHDyR!p9YXC zmgI?r%njjpv#vImPizBxr62WANpdNUs|a&&Lg^i^L8&_z*RR8|-kd8j-b3{} zKLdp*{I@>(F%y(WK(c#J^u#ScIG6mB(Z|x zw0@q|n7KUU?_Sk?F)m2rj^VLc-n!P)ae95IT>LfDoPUgI94z~t93YfkO;NchcKsL# z74r7>uL7D9N9Neh`m|h6vV;6+%qqG>!KZe}fOWDJBgM$~8;3}F zT0!E%jfx^l8Zl?ShJD$tH0Y{FU(-M*Lj|vQ&=|#k@fzA!nhoe8NUpQFE0!}5j0f=O zLNkV5ga8GLtRQbfUvZ`0_g?WxvlWfG1wmk zTS?q^jVj1n2*v_48h~XsTOf_FaP&#h&v^zAE~qIq?zVYN4AEwBT1XV>@e5o9PCh`h zEx|jGWm8qO|qcApO|yl3cwU4+%l5Q(B4 z{05|ocWLidZx;7uLI@s;y^1{xNuzBeGx*7=xrWLGjUqQAsKT-o{sJf+Srof}C@nSH zPpT}vcYbQ=cj^kqc!+$^7eEx&`noah=SS*Vkc;-H&99r3pJns|IqqgI@wjWMf zQ~ZKfn~Gcv4WFP3C~RYCQ{!vJ8g$}9Uh&f~6hu!( z2+@F{sZm04^iCVSa_Mm$_tyx<W@X|$hTm3yJOv!%5a0oHcseT53`ZB!<(}eJPkwv)qtO%WjMQggFzfbpN@xo_DL)9Lxyn1YQ|9mE#W29 zy1H|=xo8+~+{e32-$Anac<7Oc6SDBLif}SZM!XX$FlR^TTUw&6lBF6mqb~a5k7=%4 z08YubugRIh3Hf1tg7EtuQ%?}cRVZn*?krhqsYE@ZOQ9OZ=Ep_pi z6D=JL+WrQFKgj{ad`lg|TClkoUg=IITTHawvA2n!;QxjwN{%{MHqKPlnlOp~j*U-r zCBubja_23d`Cv-e+DtnOZNZ{-y4^y6#q60Pdyu3Pu9WshVYX+n?8shYRG;~-1=tK` z9DGBfN)CVeAL47zj#&&_<<}t_w+T*o44N%iD_p#r_eJ80c5YBqQw&3RR#mZ>C5Sc4 zLW9V2p*s~|2G|XbM$-fl1feL;MqiD>pF?IS(|$}of^Qt|RdMcQcycZaY5;$YmBg-u zbi<*&@_gMTm(+3(0wW=<_@8xbh)^PK2Dd!3&ZJ7}5LSTI-`tD8s#Z~b9ZI{c1-#}h z&qWF!dE5qw+9u1EA%;GZYsx=35M8V9P;<;?dGVLB#lb=r$Y;tR&`fWlX4BgdggrS$ z!S?Fp(Z0R8ya=ob8Ecl~A(5R8QDI<(U#2-JW9?oay^i*T|Kz@I z-Xu)WbtkmM99)e+GH(vpaqYE4qs-h_WOtAd2-744<#0poq~m+diSW~TRdUN@Homok zk66gVF_m#JENfc*!>E={<<3$l`XYC@3MW|Lv-yCd>Dyo`d&EsDh5#8L%aGg$+9x7l z7FuFW^{isz`&mahkw|Lk-pW*tZ?!2KjepKJ4l@J-sCBXqb)9~$alSiE94t1T%4v$8 z8VbP&C)u3qaoPzVtavm0tqQY#DLNm7!uEDEC^CzUpSmAw99vAP5we6)#Tse+$8GHF0AT_>P)H#P7H^;GT0CT5-t?axSeQ)dt zsSP@R-2aI#9CRg$1N9c7xybE+_I%@TnaJQ{TbzO86mwKnDY|S= zsLZu=zbQ2D7eww-4Su{i%&X&f`wGg=!5<8UM$9<|*Q zDG6g*De-5GBloW}5Wc==TZ=x;bNg3SrF$e8_RlH;nvj(?xN3Hs+Y)1!rzCa3T-chQ zJ2zRS4Q*x(SV!({2sb4)YbgeEuRZ@WzUwF{ef!PUq8JT4uLf^(`vw(#aop!djYg9f zL$^eiF0$|3n|~qC5o7j)1EbbBEC@!fbvtA|$l?WuvnEp+(O8KUoX4!wVk=w9+*4Sj z(;TW+5<;{8 zoKSdJ4CM**C1&!WR7t!Wbj&Oa2`N|I7p0Me_PyhfH)(4?8KKT=5 zW;O4sIenq86SQ@awWJqIyMd|-4?~DJ`1tjyxDLovI+8x%-T!d=g{Pxf_J5ZR$>YxQ zmF8bI0F2BYweIQYgEGSVE2x;zFgNkw66J0KWa9hEo zo8UJK@J4|Cd(xu5P$OiFzKMiO(97A{;Hd@(YBB~I3O@jlWaB8byh=obf5gl;4!$OH z#3f;%?{^szsu{)?v!H<0FQc!?T}5BqZ6>&u^}sYJL$!@QuUdhM1@b9yXWBze29PnSS z=*hHy!)Yi%Y8iKA_10)nVi13DkSvQ6Y7hm`0x}NZ?QF)p;1DH(2zv0D;Ms!ZFRtKTce{%JrJcWlaeK$d5$?q$1 zTUwwiaLCjjokUDa5Lxps3_)EW7PLM zIehXM>qFdh+ck`nyalQtq(LihkrK)-&0`!S0GxLpyv;e@uYTRlPr)v3Ow!V=7$Hfq zSrKoY)m)zVFy_s{g|GQZ&)z&mr}N&!YMxnqR4@X^Jvd9MpU%MooPPEGGgQKy=sI5W zj=2#k75}w$@F$KrN@XX`eMG1Y@w^wvyGDv&V4~sW_`o5{t-5TfIPo4|ABO6X{wCXjX-igt8f03Ibf z7J3~#VjPB@Xv)vn?5WeAb_IKo}XHp&tb{r$5pi)Fs;nGN|{DEiekRfcn8euI}fe771Ztl7tTM;iCMO1 zke%a_Gi`7Nk_AYkPRnh0cm=*hS9FPG{aSVh4>i@zJdw|9QYM7%2KRL~2!A>UX(UXA zEBQTSm@%3ul7g${qM4IBrevaRLn4@^{nGoXDjDV5{t$+>fAp$%DBL}Qh zG+=j6`PeaTuhegHE>4+Ce??Hm^RmK>7o3^elDl#9Q%fqy&VO+59= ziE5L92WwFkih2PI*x4?bo(z(-lkz%`*5Jh{T`#l_iiF%zI0~kyl8PS2?14dM4V}+x ztrfwoB#o&YC9^dwbL+~#pH&1MEBGSQDGEg*RkDeT4JfnXHZ->zJYE@Mz0m^@Okkeq2>5qiVor;QX=bP3lQCV#ygW5012K|wdDYjHiJ zdJiK2SO4_ae_qS_0uQNoF@15$9Q%4SX5t5tMRB#%8UN<2#nxaqrSq0t{Qxeu)VsVG zll8}|8!VU6JK$8?Wr;NX7uE5XPlhMP+NplF1yUATS+EPcy^qro-X+J0=1Aq7$*0~q zW{W~ORK_}O>3GOZUv*e}b#@e(NqU1s@~m_)NZ)`@(A0weR|*VliTlV=eP`Wi(7BBU zRhbb#q7+p=x;^C8&UbQ1_)-r>K|(A9gBpOVnQ_|rK`);Lynd#6KM@=AB$teC95;`M z|SsU_$AUdaTkg7{pb_l<-8|X`gOzc6F||TO3m~|DUWfDS{rf&Ayc{^ z9F48YjhM*mgE@js!fKy{LS)MDE?;75|zS zzkWC9YhWiGj)5j2?cxBq{L;J3sUcTV!tyAd3i9lyHN^;-)SSEQB&+mh!`V$~%?Fp` zcDno1={h7IZ^zfsmC6UN!FR?-1MrQ5x-p|?T>2};OP;?ZQFG>OWg!JlVRKoYeK(?Wo_*AHU5R)*B$%h^T5nse1e$hCyLv;0boc+S^h7zvnH986{GU z>&Q&MyUfJ^vv@J{_~GbX`V`f`TLPaIVh=WGx0J~7jda#wYWIg;Er$+uf(dK^3!<@h z;Y(a{@~Qi;CSYobvR%e)0VEaqg?knxAJhCDD{8)zgC}~VYH7-PU{Ba{)&c!d>@KfE z4r!)R2Tm_&V#Ha?Ejf#f!<+DijNo5dO^G%>O z$%zcr+Py7K9nLa{E;03J`-9Vav+V?!V;XtJF~UZig?6J<8Z-j-6zjaZi&9$E9QGWy zk%psSWCT$RS+(t1_ks+&T%a@XyITQ$R2U!Gr&}BO>AyO44hn=IrA@gvjEAWut7Pcy z{~RJf7y3ueSWFfqYXJYRSCNvAEgX*0YL?ifaK0=N#tEkV9JAUpmW=6;nn1~VRBF4E zb|S%LdVPxDBC|@xuMb`QkyrA=fB&Mo9!7_?x|q*R3jb<^W8=N~P7Zj7Q|hRI>=N0IC^DnDFP9H< zW6(v<0p$IfVx&^cuKdtHLgDjOfSaBrWl^>3gV^^YU)^ScKnBdSaW)$Vqs9rcNnX!f z6#U;?EMPe#JeDl6-#F}EQoa%aRk|iw<4iL7AoL;vNLI~y%2D{eQMMqU(wSz;91L`( z!g&UFt?}pCuXrHsntZr-^}t$tlGrR)nOqf5=psVz*;Pb=Nx>S=|1EWR997`^EDalB+FEfS$G=Z8;73nnox`(ac`lcSlAf+ zmrjg5KQfWsx=ZW$1of0?pEe`&V&cPEN>H89=j!hyNsIvR9OZs#1`(xG)ENPTC=GV{&O(2I&|sd2s_{G-$Vq5d$_=_CYTUaZV|F~@$My8alzrTX=a$zWB)fl} zKmlMe?E3j_fkw#;=ZEMwv>ZoyDp{QlTn-{}g|T+K>*66@{dAk^@)z0GjY*uxWA(gk!7$ppMyfgEj@McvAf zx;XA{vfo@14{bw86UYB>1d$vcOMDGRaR>Ai?YyzfxPS0x21 z_x{WbP;K_?>;oVads2JZ5g{8BZ4Q}D6$5{dX_#%`Bh&LBt}yF<58=WegJo21ur=|1 zuGf6yP%WlpkpvOmZH5%Ii2MsDScxes9|vR~x?zyAwJ)>9|GNTTkZD4JGihR{U<^#o z31*O{11|2Bq?BC+Ws>^$3;Zmj{-6FCgk+B1bdObj27*D zeWcsBI5?wEopOZzyRy@vZ>N>)+;CUD!l2PM)v8(QLZRN+fUUP(o3qXpk4kL8I$@5$TW7OOQ=Y$?d1h@2)PyFg9cI3hgIVe=S+#^AWW4vLc^0SYkJ@bo?kcpT zG~eqL&?-d4>3aG~CCB;Pcs)}HqmDYZob6>C;eNQLH-M?6s;gV;0)aN>Iu|TZhVqq8 zkn(d&ANT*xtPS0~`NrXskn`!f?g3q6G7#|eUj&Oc0?Nkj_i@@JyGP0qrHL()u#EHg zw(hi`w%I`sBSEwrtBY^8;fxq)+_QYR2r1212_l)Y-@Gi7<%uQ|&wBQz_+@7Vgs8E{0q z5012oyh`;#myO)_#pYAmT}Lu1ZPwI~=%r!+ndDN3c0fdG^G=0+ z>5g$C&kp2kLGW(o@bil{jI z8@g=O$H(`lb10OWpp=txc8xy(0wQ?=kT_iud#f{~5cV zJpJ0JY4&Z;uIZMD0S)O6IWKV^9U|?Be0YH%U=QH+W5NHIl(`VARu4u^hV0Kk|1lra zJN#;tA#&vVxak5DFO(@Sma~LzVpoCq>jTO*w`wSPoMvq`SMjTe=ycEaQh>sIU%8e= z=1t08hIun1iB8{FzOXbEkZ>A9OT_Vv);{`#YFYbd6`@l{LM6G(W&q)gFZOT|`|kEn zQ{#P#d$X7UR!dX*WZ+qPm~D99MADVhTC?RCgF>PL6R}jKpe7lVU+l><^lMWjqylHK z46nvOl?w@VA(aowYzp_&3BHp9?diw&kSz9|P}ZESy4m<(Knwor(bWUTN^#z6tS)pk zn^0MPRRd0`V8K8#G}QEI5taXI0=HC*lkz)02eL=g6pbnK4+7yaMRZOR((9yXKhWux zXYR?*wm|NdS2m^Y*>)9A7yNN|nkMaC*|hNuymZk~w|7r7JlB@Ma+6CAoM0cLxot2B`wb`M)PU zhp|EwiuYMopvnyJsA~_~v5v^X-A6eUIqUJ!BstL-1!QQIHa(sVhKp!?yEzF?E+8z0 zWj9e)uGJN8s{{4&Qr(4U*IIN!ApM8J;qE!#wLl>eYbe5qG8!C3i)MqgWCa_y)d?X^ zT?qf4IXik@dG=vtPVAT1qvPNmkODR%Bd|pRNT?D3yR&yCPM2T3ElfRR)klvPp`uR4 zUIYSp(ikQ2G*>-sBh$FW!)HS+lIR6O5X~-}_a_hD?&M=wkXrQomB!>gU+0?HSj6 z;~?|~nSZbP)$Q&T#d2-gV*8DQ{krgafq}tHkp{bC zUpo?MS$5))ES|d?CuUdFYG~A`mrg6JNsE4NH62-xuFAaSpfX7o#_8qYIdDwcJk;Mz zF$1b!y>cT9DWH5}Y8%WBX-bdu0_XZU{=ljy5D+f9EyaE4*>nuFr#B}65lF2maj65C zr9*wSem!;ZXkB1PsI%gTK&Jn&8$4iuTY&4SscI^Gx0+zXPpz>go|bD1oY`XrYs1^DIJR)Nx&?BC6~H3n!V0^5WK{yx84nfcYg>3c^HR{tz;V z8k*xOI1av~=UY8sLK=K$O4uI)Uj^?A`M9Ni$L3A8gu^Dp6ugk;17TB%G09isg3v$EHks%k41hu@mmHku`%(080xRv%GGs>p z>UnH}ZyaD7b-yUNQCA7M6I=$%Y;Ab^J&uAMsSvlPg#cEEK4JeaF2qng?c_U-n&#g% zRJgWsF@uCtf*eLd_dApe=078mjo4+NkHx>UNK#?05>qSVUD707iGOftS|6W6WRdY@ zmbn0&9G>4`0jTe8AP=s1x$Q1o*4GT<#^++&8{0gj8AkrxMU)8Tu64t@aYqqm$!jKJ zb$*=BZuHcPzcjB^fGtI9FQN0aH?1c%&Z>L9lY>OL<3zR&=_oy@3Ls3RCn9V&cmHFx zQ=4SG?wrL$T3?Dv!QzPCc{b}_sw?O~Bwp7sQr<^R*!rMCph&exWhxQvQGm5rlUr!> zEx0h8y~*Vd_kP#mnfbcsOvJ4k9awdMBgM^7ASR z+wnC1?7;hs`3;{}n4*r4g$%atG3EUnB7o_o2&o-P-sm$D&cWZvVo$Dy!7zK?w|itx}gW<{Tz6Jg=JG{>3t4ap(&Tox~zt0$#8g`Gc!Yfj@0dfT*uiKj>C)6w90{^ou;B$ZD z_vKGgQw&3iL=L53u7t!9U`oI*75%sA?&lWo@xt?|Ed1M8UYJS*OAnIW)c6QnGIwMx zy4PD|lm2O5Mh&)I#*Bx}=Bpr4>RMU%GgvrlMfLyrNe(@woc?J$i&X>R3Wk_IagfX} zV<-k_|It*1_^cglAZB@3qctmIWc;{P7W9I8q7+c!Zs--&+r?XO7wbds0}a810X32C zAVmoC`9XaaPraMc{|2yQCeQ?CeH8h@eb<@pyHF$cYRwI#NNpGTN_~>4~ zkHmg&3n*{{wIvleR{sQjh!!k=Vt!im!;2qL!SAG*ag&axl2u zC=Y2|KJaB)yP}B1qKJ@e30*H=gW52$_LfJ7Fkgp_u@TvwEDtG3k z^HO4|xK0^RbjxHQ9Me_{1UFce(wG+ybgLWXV+ETr@W#0V+lL&bf{ZpKRTYI?f^y3O zcIM$?4P={xXXA&u^PL zIZS(b{{k85PqJIw3DJsL(L~F!1sF(51Qr)CciSqqE>q6a+)Qf;2985H<38pM?S$+% z4&cM$vb&Itcz?~l0zT+wQP}!MirAbfAk-OgU_GhnHgV~3)o#FpQrpLdf%V?V%5j=0 zBBNwIcDFsbXSj zt}4EO-)n6vf(C6AHOvk3`S_w+t3Rl9IKDw6QRd@&KG1Mn8FF$i{sO z*gBi>IsO#k{i#LC{(3RyKyW@BCgo3RpJ`oBl%y;-6uv{x`>m7 zv6CvP0;DLI8!ag-Uf*Ho)AOxes$6%c0FLUrB^tFuO8=pF^&+wdhq?POuI@Juioe8k z@e6+%c}zib1CJ%FgXZHMHhkM1J?Raq5NK7&PEXg3p_0#~0`)edSdQbw*!q(pF!rHg zB7yZ^%T*D_#v%Yl+_KiI>(e0%Yn-LnktIJ%FJ=GFK*3EsfJS|*DNQ)Npi-8pdXw6^ z$BYt8p{MHmIpzfcqygCR*WJpCXb&mq4JPe%JEf@Qe)Z9#)|6!E7D|uh%mCm%Z0e`g z;q6F45x@p|VeK4J8Em;I)qE!hQ!4-ubXx-xb31j`W7vAO^OOrYGjGN}rb(bwMcxWD zm3!vhXxBF=+`Sv>M^`Wc>Yla6>HI~g4ge|zZc2_7&wcqX_V1-)s%iRdu?e1@RwK0OUbRm5%}P?T44;7s=H`|p+>7?GRaYJ_MAuNpYan8;7FD@xtO;ji0(wy zIXD{sr%YjB=$J3*Qb&MQUV1eoVmFY_e=nc{K#oKt*1BTHr0{0CyQ=4`4_2k|^_{Uv z9uuT4Bqau1Id-(LVJv#7x8C?i3Ivr&R5)21GgM*40?oA7N{n^A%d9JZXjK$Y1~KA9 z7-o{#=sUM6u$dx!*8&x!3{+c5d-mK(&mtJtrl_brc?*UikXUC{?h%{^SC|YG~ z^PkWl5Q~GkkF}+hQ9Q!m&8D+;_ww`2q_qd`ptCKdesqoZRWZZXbhU=Y6=$O%5!oNy zldNRP1O~wiLZs?dB-fIP8gEZz z9Jt0Ek~`lx#GPSDppj~wu3^rW(g%GH^?=Xd<(%I?SBGNJ<2S5F%ZZ1Nb#%gVA2)dg zwL4m9)IE87aK6gUXK3E_%cA_4y$w3K`fSR-qeb2SicC)d<#5SDCH8T6zi}APyWVAB z@Bl~cb@sxuYv2?)(D@)($t8A3u;gSxtJ?b$YV8FD0-O}k5kx;|eu@ve1CPuroQWg}DtXa_CQ6d^>x27eG z6v#aP_x)27qhH4>E2&-0Hx6ELH?@TZ6qV0r7A4{f*O>)vS6nhLGa-y9d70O0tBRli zX*w7J#2f*OA=pp&rOo}9u@$e09_$b2-&}CRzp8St}r>e$Na;Uahikp%Fgy zzpGq`CW>HXj4{|9U_a~2njHVXoch8RJZ~U0bn?~JSi4OQmaK(o?lZWMip|mq)j8oA zVcZ`e$UYi+9ihFQ>;hZcL}I43m&51dB{7~lTq~M$elAc0gGW8z$suFq2xs7yf)PPP zg)Mg7!z$uC5F7vXSR}qY8(d94l)SgFvK^zZitET@_ZpIH=7-Ebb2s+F7?~WK~CwHTgf>AeAQ7V6mKs?O>%lXDZj7k?hAS7j=-zF)BOwGz!PP4Co#I44! zqn1!EIBMTt#y$81N_uBj<~)T9)CRV7v2xc}3;~K;Ad>^QXJRQTRPkmfs(KAPNNP`q z64u}D1aXH7&U$9Paj3%U@%(r7!{9$Iq*0`5$tDN4fY|{Iiii+Xwx#RTj9cVhg#J}+ z)9&UUH6{Y)Fn9)wWQ14U{A0`I6UtY;hqbr4_u>HW`B9OUAaGo-=Is6Ye3l+2KgS9w!wB>#(ILa7c3U0MGta>>P?usHirZ+8F1>b#;J$kaxxl|#Ww zL1&I4ZiVTWJHNMt0|@$i7c{4j?sqM45&M~^e(hRUf>FEOUOXQZFkQ~&QH<@4znolm z3i5bc;ATOZ99(9_T5Twj`3o_!f2(wb98S|ZfcKhYeZ3k`6saN0;nI_q-aIK$e9`a^ zHvwrXsFf4^bgsk&m7g&`7>Ta+wQt$rK9g6W$3}!@0-yS!%zXBktb#mcdO^+vVv7BZpt&_|JKv~#@{s0M>uVzGi&O1GM=O|SCvn_D=L#k3LXthq84BfxhmGt>akw0qS?&iSbu_v ztR>2E`%r471c2E4V{exzh3$d(Td&97!Q6sg{=1t4F@>{QlffniveJb19dId7>brGJ zITF%yJ(~hHwoYZBa-nr}jnGl*_ffiYlTs0CcqOcG1MzDEW{1n0_%|#)(wIQP*#8H@ zk5s2^rgNDAzX5CZN|FuX1%7@<|7+6VGzk8}8B2?D320SjqNl!0ER^u)}X1ZqT?Oq@f1 z4)D`Czyv^U9*R~0M>sr1d@?{U0a#P*U9seezKee_3l{M(-=e9F)Id*C263`_53ohD z=ws)p;2BYE1#wcd5YYzE=dS=k82P)#*kOf^X5yF)qU|HU*yo>Z0Wqm(XrJo#G2(u} z>(TLT^tu4BQ>*4`(HoCzNG1)6#|%TqAyTl9=WNR@vNZOL+XdT8gV_AEdyf`^EuM zD&KD!V7N;<(|{!NN9@p@!1-r%4qT2WOjS^*h{PMAXQ2WfKPGDh+T>$RaRA{{A;mI*MkAvRF?lK4|0r{bLJ- zcD5hU=Y=5l;<0_y9%25%%m{M1VFpByp6yPpKoiw{5FBVFeYaah*Qc~Iif?y~B-_i( z?v+*jbW&z&1f`8xpse%;jW78bC=jn{tzvcTBiM6iyt$8)9|1ZOo6Se|B_C1|Z*;6K z7n3uYxtQbAp~&Ei$gIVlgAtAe+MZ+c$i*`jzVB9_e8_Q&#pDgr5Nlb@%ut=KY!Tf% zRb-l2&UY<9>Ac!q+}B~K7VGa4#Gf$&%A<9;V_}F}pta0QoMW9m@Hyl_;399J9}*U> zu%ey0a^=(U3um9!q%JAJZ+9hmx1x9K-O_*z%Yh%PVF zeIPu@)&FVXESTbGyDds^cXyZI7J|FmKyY^_Sa5fD1}C@#C%8*+g6rT;kig(h?t7W< z53Jg?&OY5;T~Bve_f^-aYaLt@A`f}=U7>^5 z6dAI~Phz6z39dQPrq9(`^Fa>>(uINZ(jaTIc$tXa(xi7d5_r{Xaw2V1$;r16bGLZ# zWL1~KKR)GyvC6;OZpP0kAG3_@-Fx*zSn<*#!wX-&5#XwwB6XmZsvp@$7P)74VTjc& z`YHOCJ&)E+F3WZ|WS6V5T|P7aZ=i&u`OUO%+s7O+5^`?c4_2K9Ic>sVF3&QB)oDOHk7cJ)2{Z0-4%Rp+2wqSLh{aA;OuSJ6FVqdCbksHzq0C<7^ zipL`6K&aR-vtcS7?rxC3Z9G-)k|x|$26wyt?i|JOypixQV(CvQF7!tjil?rFO?%6p zei;G|>HrLD_DQ76q@-=p>F78S>-oJ_P3uO$k?c)a=7hSZkCop&s@#TtAYp)9L*ZEV z+%0hBqsVLJ8wN2;(w2J;Q8?-Cw{$+q}nSWI7toePZ zNaB>`swIf|t_A(gsamOlTRl>wtdUXYf>s$fz<&!hQGx#8^)e#e^4I5Gt6n4`rU0OP z|2kUMjHFZrKp&rc<;>w#l_QU`{bS@1!Z8aH_ROB1fhnoUe`lxv|DQSN zD7Qy)H%heRvOm>6NWq&DCYZa7;bZw>V+wSY>+UA>;+UQhl(q?AkrZv1t5Q+eoHb2R zPpp%F{Vs~x-A<$>8+FWT($hkbBY?y^kms!8pUn03IG#S}9S#>KnBtm2kY&4+6SJzH zQAIs`P_}LPbjxr({}Id1>fA*52VG1=i)REb_EHZ4vUn{07q8?0Zh*kK*Lv-{eCD4r zx9}ArRMGJnCZiQ1FFvP9BN766gAnKN+U}d|B_l6;dR2~3T5gH`e79NnFynz2K3tX0 zHpH0wXzBGPa962tSIx522Ra4ran~ODCqiNJG9`HR=C4gVmzmi2-tW&v_X=_sP<3?{l`_XQT?85z!^!7E^Sk*W= zyn+FRw8sj#h%xJ0N6nR^wqT$REw1l|pUQ#Jk@leh{!9#|4!=qN9a36TzH5Qk@-;>N z;BAJYJI-bR0k0X2QU zY70r0cV!YZfEYl0FTM(P|roz>!PBhNE`~nTltF&4vrM~0iOtuJ~_#`eXP-!LT zi@hiRpz)<_ok=_3mlYI~Th1ZEe%Lo@`hoGT>PBJVAO>#Z#l_2NeONC)0?sY-q9*@T z1-{uiP8mWVNgqsvE+f(mO;>qper_sUX$tmCe!S{6m4e#lX6YRiM9VZL&Xi1hHNoE= zw5*E^fPaW&ZkX=*+L`#54DUWxij?IM5&*u5x%u^v)#g2FW~fO;oaxD94u?oezS})c zgm6)J;swRyUTyE-sMwv3mRa!V13M03(mNb>KF3nZC;g*(;2&>~nmJqq;^%XavW)1_ zmXJ~oB{X&+;^R3UW2}Hlmo=MP)kIOr6T=&i{7TvEI^&p)ek*POZOBQn<(SAS&QAQy zfJFAyL1#uyi(~;Lc>?y4ug%CsdHOu~r6B(3_9@|#zlz1Mlout?kkaa4tW+nUOgNFV z{GYnE%E({(*r>3(aCM++YE;tqI)UIHvuh>N@Jp&pq%}A=io5Vw9`YfQvPf+ZIFztu zE$`9S<$br3+PZr0bgzL0XaegVa~EQ;W%0GT4k7RkQ;8D&Raxa9B?*JKLli9W2?7Uo zfl%YW8X}2=q=ZcWlv#sRn^n)8x%9cckiEdjMs18D@OyG}H+VvmxQ1d$zP8PVC*TQ49A=y;HzNHg>lvR-E^p7c^$sp_In8<0?%VqMCV$ zL61=WaSb>2EDr~R$x~w%1+AmY_QIv@;g6V$!pjQ6l~&WcNPZNFpp}#O+92mVLydsZ z%dG`S&!MEKBEQb?l^6MRdsf5l4acgILbA~oHU z9(_fHjhqvtC4Y)=__L*@QS;GOMx0B+Fw7#`89tOFkCT}daTKZmFX&whD)eql(?R&; zr0*oNK)S5F{tH9%3cvro_h2UnB$cxV}YjXN=hT?)}USTKV9PV2;wf2``~|z4B&OQpFXJWy*JC zN~juI?Zw|+2iE0+|ATAtMl2m=3|((kpK1hKyKtTcd4@+mV3=uNe<>lX9>con-x+M@ z$IrQ9zli6)8gpl1_<5eCKJJY>0n!w!)qZK@Tg%KWMe&b>-Zi0TT6PkiTCHSPg=m3a z=&&E|{fkiI`9{`)dwV}bjutQH>o<~$;Y(+t`D#`m8!mQ3E%6j}YvFU-oR#VMnZ!bn zLAE|yV3QHWaKOZbQdhB{0*pASx=#tu<4#z=gTc-Dd@%#5;)6T5HpunSS7U(DL88B= zFpP_xQ@K7dTdGI-WgFUcE0W{eDjlCN5l+O{$U$a;I<`VD255UrKevxUa zs`XT~7QW*|A#*yVUK}&=V%tf2hoco97qa)u+vthhksy^Uuc>PaalYv304Z%0Mu#S$ zU>zLFm2Y6}9LNN6{=qaXmAA*U$>eyVV6hG?53{9ha!HK?J}wau*Cgx^gg5s2z8K3r zEd*OnZ9|fO8De2?2LNxG`3U39kOam1JrEIi))q@7OMQ94`+`e$Thm$ya<>j2V(r{R zT8%iKpwUj&^Fk{NmtSbA=cI3hTy}-%ZO8Awfx?d>K7;tWhjInF=^$Frkc3o3JZ+;c zhEBY~_-t(u=d;2>f5Pn#nqLNp)fqmHYLEO(cf8Rmn(=O>;Si#byE{~(DtVHV)Hs39 zB97C#+s+PhI+0&e*I$M=AgJ*UHovVa8K-rAPY%c0x2s1JHw9<^pe$iqo&5WOA&#?s z1%}Drd5=ruo+n&y(>0vgEqVD@-I1CJ^B#e}0}s(22QOmXxq8*ir~D-$*k{xH(}3 zyu*4xEr0A z`|MY7V#Eo_)Byr`!|qOk*i@>Vs}GRm7$pqd8x7R`7tj3P0AJ!^Uq~IPSrP!PT^xVZ z5#ktLt^9gb;xn~G`z}cgnfc9g#=lj9&!qhB#?9}B$)g|q1RLiBovJp1ex_7fQQ?CB zZs}S9H7{5=-jkz9B(b#R!8$JQYd5^UvA(|fkbiYHU#6|=5?ybVLUE-lV5jxjKR~da z2l)|)0{WIU{v<>ODii{KSU2yO*}dUPQAQ1FhvyY~+*|y`-&|v}|JZn@e^L*Dqmccr zzvit~S@>|yIP&!BD{g8b718BH!jhP?K=&&!5>0}0wn3ewZCnhCc_7K=rkek9@Ja@B zI)MFE75-1Q^f$QZ;4&64pDHo+t)1{2piZcLji{^O9geFdH&8@Qn>tmSOm%m#Q1k@0Wo4>vZ!QAH(!mv^U7_7;pT9SlyjY*tUwqO` z=N6H@c!*$*njvtaCCK*V)%OlZgLyt97WaR|sU4{<8k`jaCaZrrS_|#Zy}r>vZY9q6 z8M6h z6U|MicR1=lzNg-_p0HAXkbWiG(22OrINC=W2(>k?;f8Bw;n&iNgVajD-V=JR2U z7h~ZhMjqce?CdHg{B0eXUwBvo&b@L5Ps%AkFycYACnTHcr0OtXgDzQgW#wAdCCmIZ z7Jz1ece*X-Hig6V$QvGO_(~4WH*WE=F^_;GM;<{r5Zp@5eVB9WB8SEM{3{;ci`lpo zsm_OA<#qE-Nvs}rZe{j&`!)R9>kIjCrF%eg0D;kuA08vVf*(Qtu5I#LY2c=_^Ws`( z2^?*Hz}#V;FA409*n4thP@%Ljdj)?kn$b*hbr)G%zT5%#XQM+*JGqykvVxB3sp2(l zJaC?n^u`?c%t`q|PAz_;PT%dh!39 z6S?youb61>P>d*Ah-)%=UI{7t?h|UB9!!wqDuamk&qXRJ*G$n%1o4`l*MnLTcfNKD zqkj5`dgg$EegDaaxbOlL6;C zUc_c{Nry$V55UFbsZ2BZPKua|IrGoEb2PXfTl=+1tTH3!6s^KF!fe20V|!HB8k_54 zw(*X?w~+P!FyXp{c&IFHq8fJ>pia;)RxMj5be4z?UdWdD@2?6Z?D7Lbqp6aAE>g-e zzx|An`gzl~U$wUcUP~1bAA_pUtgLZx|Mi2tig*}=mh;AODsZXwnw&xeS$~+?Q|w}Y z7!H%VKV=Rf%X32hRV9YJ-PutF>FYh4`E$j#f+tWk+d`gKMsQw2XR=vGZ^1hl3yd~M z`%k5u0w&aGvgd(;OY-Nr-AqB10#lA+ue10__0=)O ztCw7rAhch7f0`HtP(538!F%*^#Nm-Kqks$8bfkVf`3Vp@iRe8| zk9Wa$*LVOb_wr*&j1if6hr=tYA|c~f(c;`a(z2Lf7>{pzq{waSTiB=lEpXdzt*={) z3BY7nm+5A0=9~kTEAQ;b6LmO#Xc;Xg>^dmVCD*Y8<}I&^iFMjj-F9}}Ru7ivS_vhq zLD~Yv8Ntb*{W@duWdkO##O4n#umf7-lJjT@c*etKe#yFN-nNABzyaz*g{Rv|pnvjH z-EfZ_h>xzl${SqV=$mblk@U~@clhDt75^EkrU;pqx&S)yNW2fSM7LzTjEQbTdUpjG zjNNECZPhnPkq+|XmiiyuPBW39);66{%$y>h8?3a|gpOW!iKNjV8Sb$R$g2RF+9Pdj*KLTjIQdj4x0bD5Q`3W&1beuty#b?LU7`BuZKlN&X-YzPsK@)(3Y`A)Eu zsqbSiZ+~|%lC%*+Gq#wZ-C3%b5jqYFeK`N3UwrC$e&ph--R$rv8*;4*m+XKk=Mp~t zoewH-&$%D^S2IKl#@gwp4$ZUps;mvZ8~e==5Xa9Cc;d5@Rh}h8A=q-*E)s|amOEcm zv;gJ_+ZZ(Nzt`QaBUt8fClQCU#c5XB%8of#aiCy^2f4UFy|=TrAsQ96=8|xL_v9!+ zxs%L3SBw-UyQ-FrXZ5RBxACY|CWkNCyvBWg7GC>a8218P<5y7byL7~OC@`P7uD{%P zGupt_OKF%ZWTZCJ!%XN08=B-);B>4kaGbQLN) zTa{G_FpmJ$8%HcY6GJy#st4v**l`*`;N_XIp9G zI%cPz4GT2}4A*%7j#@IYE1iW@5pkp;vpUJTVEpUy1y!s?q#BHIKP|4EJ*6COFxm~b z6?6P)V@%mN0ZHp=@|iFeO&tFrg2Nye+$p8M|V?po_iBhR0(RW_Mz?cv!raRbs@f+BGKb;5j1DNYgEP+7RtJura(yOnV_@GU=2oap^yQ19%b%+04umh!X-apr z$kh8h7|W~=&?1b9Z7XO2?R{w8o}0VmR`HOYBcTRR^`@P~{#+w>7SU4mEa$Z7#_;{e z)SH+R}xE#OC9(TTwOhs$n&J)J(R! zv|$ET0dWN3%+GuxsQ2XP3pKAtzmTGarYipX=&v;rR6xj5l9L%x859}TF8EUaJ7uc- z-gM8ym~e&E3+&j4@P?mDbkjRQzHg?!*7@U~z?~sKCIPELL|3P-%ODu=$njyTbx0R7 zP~={_0T$%r+lOa&IJ~k^?xP{;A43U=gWtrN6&ge%$rVJ=KGPfYBrLQn-EdWsPoEfV zRucM=q0pzNIrEm><&C z3uEKBAU5G7WQkDUd5Kp3gu+6MdiE9t87M{;d7QiDSc?>9;fsf7#4}AUG0ZDUu>&i@N@~eO zG1I)c^@3!TNDhc|*Tvmza<(csG+Nz`KXbGmG?M7cdT3QTY`{PDySE>}!Mn1FF`uf>4@GfUwC|9%xrHxVKT3Slw5KsEmDPOPhnca1zk^XJk&EmS_v)}_zN$l$cyFOP*YtlN@_ zD`PjQDO5d5c-&qn(D>2GbbFEwc4`N&J&}$9S~VZnAoXUv>5G-n_osTuKuL&rh&}D2 zPqAbt&sM`p2r8BqCM#eAMwQH8c;PRGmAunPoir#pUgut)*yve9amAu^kfmulF%>I7 z6T{5~c+~~b(dPFqd*VCRPo9PZr^#Mxi%vghAX?;>{IZe9(F1#E%oo^qtI(*o2!S8VRje`)EDEtqhNTFu}WP>sd{BVHfFDo1kTGwVDOW}j#Q(|yV zjgzI0@3yxj8J%(tY*$*QvyPVwCM1^;h~?Xk*y$01@(J5OZH)$(Hw~*YZz2y<-4y?; zqKLQGhrdhApQ|!{h&X`mo-7xr**iLeya!op5Ze#mX7wMYu+#D;!^dC5`9^{Sk<-SG zVp)%nr*wjgnR_uymD+cmW~HsND3iL`b-T&oTK%P?oH7gX?~P8f}ZTX zF!)iIbE9Aaj(E}7d_C@`UM+S;Y#|a}Y+j$D5)Aq?zoeEEj>?G~pfTdYgx%MG^ZXMJ z1OVJ!vw?zxk&t`%Wj{VkscIwWL7c-GCnf;PZKyPE09)eGuQE%KV~a-$fG6RZ#-T`d zKt-+(H;WGXWJ#E|5I4fbRn0&QVS#(wxGOk8A|8kSzcbt=Q6CPGQvNMamNC^}8X-p}x@@bjSIL z$s=J1yYMc<|DhXer&(Swut0>B0=$~O`W&U+yna!%A2jgH7-sbR2jGZ`fVloVZ* ztX_15qCJV8Z9@H!TVTTPvh(30<=Xx6wKU)+rVh(_i<8Cdx7FX5@{59t@ShY3m=<*T zbvNO|yvrm1gpOFB(Q&-PVT%x`W(6nWHT?@*phsT)cIca#v4;b1Yqa3+k8Q6`?FVdy zBk2ntI6Uadw!UMi6_E=v-LL!;C0|-yNyCjrG3dJnRnwyGH`)hus%8!{eN)9U61k-Q zU-F6h1hl+{RoL<$L>bLKBJ3K^&(B7XMZqh}O?!S8> zM+#>3L|0H`GjpwJ=0)6g*?TXm&Bdv#vcCzCxW>`_z@=9#2zpPBngA6Ah(UTJ^1f-* zn6zkC@f4azwi|mBBkrN2Rh23{1g7B6rAt)xGcg>il9_)6wF<*uH!gRM2+lY QeB(U*`!D6VdH%#1jM$GhQPKkCI&DA&;)>=bHPc%F;)^0 znbdBAE>_WRZ#62yLmr1ejdLXRwND>Ym<$Y+&g_PGcM`|!|7U%9)VMU8)c1$mURY~w zH(BVQa@%$QhtP^#h*{CwrZE1=9SH#b%-8-0_dM3Dx4~lBFBbydJ%9=(#W zl3P7N*~t%Jg(YY({=U=)2Ca3@mC#uf)25m;`1g2CLkQnE7(8$V0@02vSk8)1upmby zc2wnJo;|D6!Xm0fst;I%f*FW3*K&ACVCw@%;_3N~e&xDk3l42{<0jUmC1P!b?*Yn3 z)pM`ewCz`#Vo&0lR!dyN>h>zZHx4d3!d}87%H*k?xo1hPxC9RJi!-Hyk{he`?N(DL zEZ%cO3V>`!GFVqI<^YD2%oWPyG{PU;D7b!z!9CjU9^8;8Mli?~Y~ zb67fT_POUz$5#e9g9d04Wp{3$hO1K+W-B6Bb5UI5XOZnju!$$Kchj9x_I_}^^8q7J zGF&Hf_*ALg5}&6GHvwXO%}Ybh4d6 z{slX5qbTFJ^Lms}uxB!9yj33}KjhBRg2gOR$H_wBjS+9^lZa)Vnvd;PvbhSh{yPU^ zwg1M!NC?Z=^C%~bt2&wTW%n6AFf||sFp1*4s@y?6E1d3f^R9!SJxy)~$e6|5O>w1xq72~DT){melB61T z)>#{tO2Vj#3dQB613Ug6a9|)@YRvPnv(~L<1Sg6@5+txrkR=c^Qcd!ym+O{4PKFqt zm$-3P8z~>n68}5UICdGkG3c@MF~7h&m8$c-wz83UB}r(f6BGkha1byegxDt9m%nAb z{=d8}Vs6GXKkwY<3ZF(ss<%k)>v!N`-TV2iRmxp>wbEYwYiu2Nn-HL8$<+M5lfww+ zY8@-*3Q{_rg(&oMSz*f zn<@BLbC@N4@cP7VHC992$2|Z_`}sy2SsHfPE1q0#E$`lKJ>LK&6$0A#oC_@eD|LWkYI*US& zW=VZo)qW=j!=}?5#Od=9)D4XFb}De^eT2clBn66I!d-etZ?HR)xaEg;z}N+ToxH#? z%)co+nQ#PMEOv$WV;MjxmC-1%N!YbC3c0|IoJ3j5Y_Z5d=dd3Hm(Bh;P*@x856;P1 zs!S`@IkdAs;~Z5g{ngk?Fg!DTV|Z-vb(NpLPOAMQVA$A~qoV+(piEXW0h_9Iny_gQ z*B^m7E}+mY^Kt+$skIWWCV_+aiBXlQH-q>5roWTJf9{Eb5>fI`#C=j8?){U+|JV0- z>Q}2k}RhB*or5YB~NYEqun-L*Amxj<$A~=rz+Ws~qAgGj}Ryd4hxWwo9dc>#1yj zL_lL6kU6|?)r9K@!3nRSht`Ury|8o|%<>FHQ-|JnN2?34jg;I2x zxo6OAdnyI3Vez!*8~_NUB9!w56LXbNS9h0^SRn48^6vkucsNTuY}n$yAWvcxE&D zLJGPSNrRak*Y7(yB$NGIy@dvm*y-*KPe0~?F|~Gc^_6eD)YmAW!#s-9yS9GHmHcEQ zxir;QJ7%p+J8f<`YQO`VFpjJIyk0Usv&cK4fgL}ow5J)xSnr1a8SzdYyD9X~fkG7_ z`GN3)<|^qt11LOkhxroQNa6Op4-;P|ti$f8hAX%06%^=5@wT|m;ucN#_)HUei;gq& z%`c}mUN)|hX2X+iiYmdRJ}AOVpXPQ$@B8al(}IuT1@I3Hs090$=#h{&Ra(Pmg{7$~b{zqE8|{bnT{I{slfF5SVK3 z_>qssh0|@on#_aTV1=nCI21emr2{4D_ddnF4C-IZ2;iC3bMk+F0Btuki{RVQO~<4Y zU#pyH*y0-?zAyxq4Bt3J#jOLU=fif#$)->sw<=hqfHnl>s?o|*(k_vlAry9O*#~Ho z44V4%m{~YUm@3)Xq^4BJD6ltUJ0x@-{muzlaH8d2CJ)d^-OsVuVXN1sfQs)KbW4K{?aiE{*4lN2RLY zm#9d4e){nGKgl5r*TMZ9`8J}!Ylr^3_R|iwEt2yfE;tZ|!t>y@6Bl0Q}(2$jn3D zH0qr0_@JL9t8s-aP7FwJuOs1H;1}(wRfNWKOGjxuPllACb~bmAW)#Y4Z?d8K{XK5R}%MyzFG7yf~EK*_-SOk)GFB#u4*F&M|)kwoku{Wp|YNH#4* zjmJG7(oclyjT zhCN?|we6s@L&H8172YU19iJQUs=zh6WsaXo;~Zy$XibuL3R^!*1cN`K%PO+MjMpa1 z@%s^-vcAn1Gr%*_I-nS!$HR3tCao&P7tXoO-Uz~xr>cwd&@#Ht=z3RsW`e*-ClTk; zMZge~+t~m-a8{+)0UFCAFxVz zF3}9;E!H7{PkeC}e8-`6g<$P!#(LIv-S_9Ve@5}; z!duOb42nT9Brk+(?s~ok2y?M^{}3eqT1;NvHrUT6O>RWG6e#!p6&C}qU%x;mdW?C5 zFcY89T3y~+g=O&s@mdxMTz|$G87fAG{%vEuJW-YUe_~F?*I{|K zI4yn?R9t`K5E2%yB4euUS_p+sbD6wMlx(=Sx96~%LF6qDq=p;MAT{4!csaA+EZLp?BKAF=o5zt&zA5Jmth+^dB; zCToJ2+rlX7MQ=`N!mH4(1^AZ-kMOF43Z}1GxYzg&P0^^C);cF%5d=0(2A1L=ZV8iDU1%ffEm6Cb;^NVmdRlDLN@M(nS z47Rx~MYxw|wBSa`2_om3dht#Z==hfPS<{ORS?8>N-DC@By&4&E^xo|yi3*uO;uKvI ze0L6?xrP?GZtGx-B3DC6?$Ewf;fm*MPwH$(_Pv&#Cr5O)Xve~x^y`3n)49|IW>wSo)(If902Q&K%OH9pM>)uzC zedBxHoRpTZ&unefK)&VJ0z1nmS{MSjfUk~W!JbO$=Yq=B>UMF3VP|V;2VdwDSalLr)IQ4M5Mc}_W^SY_-MMnCzMa< z9SxH7JZ`O$n3iqQAPk_X?8(`e{Z*o2`M|c_hP%lULhX_r%}!|FX00Ot{IAR}zWKg)OVP^WvYEm#V|jXO#t^w@ z#GJ$RFBg$Id4Tr#lR?)FHuL{%1U`jxaw0qs^7Yo(uj7AToVWvEkvunFtMp0$*3$w^u?3sis z$&`PpGF+6K=VKTFhLjBb(gvK6Y3*uf1xZDs)#+7MLWdJVZ)<6K2dVbebP1P_SR=Rg2rHt~HOVsG5s>okDMb?@_D@!rtU zIM;s&h56+aJw@Ki#if0#KKn1JX09=MpaamH1-@|rcaR*EboH4)Zb{e0kK=0vy1&`E ztss#3=t0F16qJ1NcR=Q7AFwi5>=`1AFxo4$`N@{Lc&iiuv~C#xrdaXy};oR zr2c?}7^%NA=C=54<%t8pugY4~E}Kh9nui&&o>h&us+_;ewl=R7+313d5#VkaeQZ~{l?+n z)%Sev6OSITr-QScUIF7+J<6RIdH*u6|X07eMnh}g68EMH?s>HO}3(%vB8 zMKp#GcF$xS^&k|o?w_mXZ7`zNk|$l`HUqr4WfjX))8oEz81Tc4$L7YuHdQ85F6Vyv zi45lSKxzHw+*1RHaVQmQ1?%)#!%R#(6$Z}vdKDZwoWgo0GO zK;vn7KUG{AA5h|wrT0Rh=}MwNsFp!@tkt%l@=eYMs-;S>i>u|~bnD@iWnr4ARjcG? zDa5}4{L|k!0Ei*Oj^=^%PQl*C-s+!U)+!QDtnvS>Gr1WAa~I@AW%x&7_<8O$IO9?7 zc3w09;>}O@Tsn;4Rkt3ey8lg5ZXZHyf8$WYde5L) zHL~?|3V+@nI7z~OlhJ*G@;RsZYz*(1HN^e}PVQmexkw95zj;uXT?8OTi+Vw^yJgec z`BiH~3>rQtXc^79Rl0q=6{JVjV=43*nn+6T&!X^+14Ws?H7qK^$?SrUkV7RVtg4Ww zf{h2)f&xSdSznEpvw{Cfr4g`O@9wT&Oyh$1n-So6Toyig9l0M8jlX?QZigizgQ$T- zR%IjN3v;nPN9-4R-Z=XJ@QnjP7$cgBY$#fo1-zLI(CbK$R~4`N8(*28A|XQmg;_42 z9NKO7L8UOa;6~O?ttacz|Ehfip4Z!&7Asfznp3eoHhqSsr^y1VIJlSER88UQ-8G>E+1FusmlCzL{o*7Zzpb$c*Db$%#j~{Cc9T>?d_$%d_Qf~ldEK=yo;2q zk7Ka7ZJk|PMXUn|F<=0C$H4O`UePpd4X4#w7<&i|7z5@* zMem#jbmgw4l@?zA;beI?qgX}YN=zD{eNfMR9Q>o4?48%}+Wz1-_0~A>I>*(!mR%Sx z_o|du*aM$Z*|qb#2TkFCv_Oz)4vT1MuV!(?HS+>Y1bme?OA4 zOdnw;Hp0|d2Bo~BOsBB8(Qh)yi>@b<#TUu8b#!CAaHu1QoM}_hIlS?Y6(7)x$`1}X z@&a1lP(l^93PDJ11ovFIc1DDNic<~XXx)+=;Tz0KjO|TXN%%RgIYJ9L>&%~F223yC z^|4~Ypgy52$CL$N8PpiEDZp-;s#^P<9A5M3E3GtT3Kt<(L%zSE zhDua&9!c;ezP;!61^c9~n1v*}l*uk9kp_NkAgvJ(sl;LR&S7Dam|2hzPvXGU0fmYER z#py^>dxSslIR@INGuYvm#@%y{)HZQ6;Pk~G*8EbB5t$?Z(!$~_&r#iu4sTb{f$HPSRJ@C zN1JqNsy6Vv3M>3-;VBlJtalx&V5eWiV712)CYW-s!LUZRGvwN^FDx~jmy`(_=I!cs z-Fg0`C>@tbd>SsgE^KfP5%xzv36`l}SFp`wkoO8&sQZcC|R;VmSiLmvjC=!Qi%gf$B!XP_ySHWJ5_f>n#ETcG7 zhVSG+Ap*RPO1PZAHAS@mIx}E&1n}GVstGkS7MzE}~wBrm?u;An7SxLVy+A zx?E(~y|4$e-DiG*@3z4~bb?uOXCJ(xw(Zh)g7$KyNx zPm8&i#@L*2Il+`WZ_cY>4=cfF&X^tOXme2V-oT`OsnDRlL`K0wn5k-mkxz^VYV(n) z;_*tXc;FMgtl9_iYh!BRWPnTg7If+V-9p1IDZO*c&J~j(o@L`!)c~t$>;;X$s;KH& z2(idFKKd&9&@9O~rilFeBRNx2^3Wxzjej;ur!>I>7l@(eR^|zq7HUljk|Q7$*{e}H zN;{8u!(+q~O8S!=_MD}u;gcS2tX^C@6r9|SZuU(An%}UUDAr&MkDV%Ys7LO)9(;RK zfvs?4Z{mIvb$s#~lC0b8F5L7|$5m>yQ2*t?Y!h3YvMipM@@TR{7eI`?E6p~V&k0CpaLQIx^()#(m4@-=lhWq=Xi zXA3I*spgA_2K==^@ zS5R|bH3Y0Nf`76!{D+dVkr`lG4F`T_W{+dL+iYnxQN@ExT<{kH=OjKKhgXi18l#wa zkg!`jGwxB#mA+%w!a5=-PIec*Od&*qGw=e8z;|*$^hW!H&{%9Zy3G^U0ePN%mNPv# z(a{VzK`NEls6`}u#6^&9e>LLsECj3sb@o56rBiMka(7*}r{D<@?N3gXi@ycM&2A~f zCk?>bVlh3Y2+9di8vE?OaY(ni(_W0d8U$rWmYcXqoCBF4?+v#Jo4IQzmr5}p!M&MZ*_?P#$tIj{SsVoBixfW2LKN!GP@ z)89CJ%2-#z&Pj%@Cs?6l31$Oy?u%Rk;P_U5e?VHB3Ax6~AESc=)!b5iN_`YGP0e#i z_b|@=qg6u*W4w32uG0&gQ;eOFZRfc7!Je@Tk zk6qNJAYUm)}fhOG#M6GFIeqoCungRgU29pcekk zZ&>2Aln=Wl|GgRVA&#~>mS3}t3^6B(AT)}_hr(g?SzH1IEb+IU5-hL{C1(CU5^*K! zdhbJ%f!06BEi>+C6u{gJONZ@NmJTyZN?C|EgvB!GXj( zGt-7E=LCJ4)>+;KMiiE^$w{|0kEll9M<5w-z>YC+l+LnO53*hTj&V(~j z2Dri)BqQ&QUOrF6a5eR2?k;&bHDRZ zsH#fX9m9t;dF!+Z`tI&VlbYkOqR}mNMjX!_*VqC}(k)5No&57XgZNJQ8d#li!7slM$Zrn5F|Tv-cp2b9CjRbUr3kf zU3Dk>jC$;#QlsXUV7;piW0a!v+69a?woh*0w&O4G7<1cy{~RQSg4s)JP4=W?z*JVV z8HwGzEz8WTV4@0GMVRYO?8tlE(1e4IaqwTJ^1g96{V~4FXZUL)pr--YB|oG~@b3Ld zk}xee|9{?`S~3?~eb5(<2BoUT9s?0H z_;1vIh53pgm)zl^9j$(Fh$mf9PpE8LzkWZ}CsqV)!_W=|#jyB+cu|lrd4*Y86as$s zL(FGiB}%AtEuppemmH&sbe73U$c5N=+Rn#>r=X~ZEVP8~o{^ihd_WeWu3WTYi2MKD zpF^c&5v=Z;tfCVa+ffD%%LpuZ3aPX^I(L#74UxGH%><0m_D=N#^asURlv+;j2WA878#Ip3`q@z6b(;YIoGzqeRWY_( zKpKEqB$#w|RspJ=?a&wxETW}acU{VMs$;N^70|ibg~xRomw0$`r`I}O7y#m((@t5W zzMbN*@jk_)=-sPv+}$+3nno_|Kk+|H1fL|Bf{mUkjNBNy{MTV`_!hFL%~}arabR}v zq){Vd^o@z49K;VT{L%`VD*jE8RfL>Y&}7WNl}Lp>J0$E0!J4#;kWF)%da5bJuT`O< zjli}bD_^MR2ZvPnds3(g;OrbtUOPzWq6pGE%x1=ddH=viO5zAqo~VW!^1EGtEvZqF z?Ih6AanMS;LjgHEK_sSu$aZThHc@=!x=V2<$`m2-@CCCCA4uGnq&0w#h2Uq-1DmQ^ zDV_aaxA~2S7ety3yjI`svmGP>#<4Mh`l84Le=Gl;ML)X~xazcUWqVHIEwPD;6tn&} zRMdEx!8}l;@9PdejMi%!lpSu0NoEAmJ=5cr-T8h)-SdtFA#C&j_VkrF>Ey51 zRL>%4KUzXF_f4AFTAR2`4s*WsZSj((dE2uF#!AZjL zX*qh_!pKZ9st{{M17G`C?*le>BB-7vrIov~?i?KC<~C$FjG=XKj-en3!ID++y@( zsGK!ysnrr7!y@>uVx}#!TjoyOxr9n_l0W$f(#!B~iYHQJ%;q^c2+f8h=C3x#Y3)z) zi?MsEdM8Cue7AqoEtE*qvvKk09(xR!Eb|IuH3SX#`nSsAnNaW?aZ!m;%oS$4r z=L3_}aj1L=%}?uU)0j#?oySLTY~Hi-KmQ%NPWc0^U#2*`B4)6vFPPs*ImX#uy1L|cTxn(N6n+OGo$ z?MB9~xSwf(ct+JBma{N!zzfVWe%8Urb!CPW3s5gAJsAh&?f>oK!7wdJ)HlCQJ!!)ZLn-ATV z=F9(kVok1p=hL}cIEMHFDx>Q14J2OB4!8s(pcV01;Z^N)HyxrD)=wLofa1>1zQ|VP zug<-EKCb#=mI!J5V4#j1`>i?uY@U0M-$AsIfh)`?Ik0odb+;_r&#ilL;??t;h0E^g zZ{-9jEh*1;`HMj2^i+c)siUVT2q;EZcczj5 z-zYw29k^;o>)6+?)Yka3=5lg0Mi?k}r{LmT(vCh?hoW zQchzylGk{NG3JS#@hiN}yyOU+`Xx1vl@`0E#=t&sghHzOzmK4R7oF2I7xpBs7@9Yf z7PM=foOo$|J}`NF-oHl7>i#x^S72Lsc4*g|wH-4O^J~}TLC57KLnxSM3}6k6y^g?9U zOuoarct|sn>9mfVUb!Y1nRDrd@+Lmk@IH~`A(g>8H_?RRZJrjCB#Vu1#vuGmi%z6G z9y><;Z(?ewk5nz;T*(sA+eF3fflqfih5(tE)|L!|E86vrvTM@}As<@_+?88;ympo$ z{ScazMm%mMh*q+dJO}W$nXrW^^0e-Vb$Y?U=hL9=Zyba&lZf~@wh;wwk1eyyJ{-B2 zU24w1+jRXcd0M@Oi*w8M)YMq2S&}+Ohh_~+xl9Vsg^cIx{Y+^4!(!*sJc{S*LA-d~ zlKP+zwD%32m-Vk)WM1mw|DMgkqkJHK+74y3-s_YDU&%k3NVn6|1E5HZTJpb@?^a_! zOgA?rS`P3paq2~0?rX*Q!R>$88;ldh7T&Fybc2fl?c=PFGa>+%yZyuYVv9itrExEc zsnPgZA^>!6)QDA>+xXFeas!bUtY3{~L=Sg-_uvC)&4Y^1J{6A2ONX~k6HU2X`)tbO z?a7k?n%13hbcn%u^>O|T>skTTr9?zY4ozyxpeOJ6y=O)yJ^ERR0N=F$kZL?Y_t+|L zxyXy2qL+x{mgSo<_o{#^trJGC#C8+RZ@QfrwNiKhLky?ZI2T5R8?dJwhJ{T_!rJKx z0@v*@2PT+_n*NdPMGCxvV=Un|ERACokM;gZ4t|{X-%~5ayI~eeqA{?yPNP@Y5zp;7 zcb`uE$p+r*s2H6id)n1AgD2o{t!GH#Ev2skP6iG)`nUr|eyxI(9&x(uHk&VbF_+2L z+DyiEff2Tfvw-OP?(gJ)wHCjMF7<4B1Y?bvV)g)FjA@V>jLiceQqX`>PkZ#^W3;s; zp|sG1N{=j;k(I@qaS^wdK|69!#^$D~EMUi+voLb^MXyskOSnQOnsTbpk{(KYtFl9K^_hvD7U4ZyW+Tp-(WjLzv-;FjveU zHXBxS6^X6zO?wmRD1%{Uj0{<&mT%6L?Wn9o`MIhWSlq#4t3brB>kMECUXB)5*#E1Y zHJrRH1Fw26{n1-dt)B#6$>Zg{n&2CU_T1V9eDkEThI4Q84z&^z2e%+E_$b2To+wdI zGpBuyJt08mdhPAFuQKxG+pZGsFYOZBrpLYwYnJDOaxYQjZAv9^Ym4e$xMk`8K=s4L zf+T|Pi#_`39K>FC8*7P-dA~Y4TihX(a#~?!D3>05o&aw(-oa zbPzqzGRhFo@L$sKl@Gs}YLMT)GJQk5tHO6JAc=Fx93V#qqpR!6CPFxsMEYnfxO4Eh+p#(gVbFco>OD-$@-KM9&IDKAd>c0bIcVN}ui*U#?miFaj2gfYoTC(%e>krqK9_jMVc%uLNOc6XLIS*h#d&O4k z6HSN!;o+F@)H4%M9j{Q+v9w5t6Sq=TCCjdkk(G{mUg>9Em?}HfV9jD-o5olC66n z;V>;ey|U>6zjV#H9Pw}q8dJ5ct=6dYQf_2)?#OKh!z^m5hMX!Yo5x(*Y=kaM{?y%; zF#l2#5(~vc*}nV10sJ9;Q}{aEZ~7HWcJ!~CW^6-8b`Ytho;=#P3jIx!?oOx~kOKDN z#Y0(116kxw5Yp);kt-{FLXqYkcb<1=^^ zpgu=2esfxpP`+oH)%npV#xvdPv`KYoXJu7w&2IxK zq2!vfu1fey=5))A20Hm|+bUoEED;b4V}f#L0qRl(-=4DjRqtGyHuLRQ1a152c>4xf zC423t?lno1gKL^NcVS}H#|QVfIp!JUsj%pw}12DskW?uwBG|HOCMwe6z5>y0e|}Z z5KthEzTrHxh{L#+fL3ClnfX}I2lDMEUb4(-qV^@~|HENc%idcs1JMUi`;EgLcoFT* zB;ecVzsJH=!gokxlWkE#vKt4k1DdEpvDqX0g8rVBf0lcaxbyH}f5Zjevot)Ff|`AT=bSP1 z_$_CNMd|MBfav66q!N1Z(>WjplK=c&6`ViY1~-8DBf1T!adxWI!>L;@|k*T9Cyn+L4ctpYqR zO;)bJxY)&Abb3rg0>Xpi?kb_}+|%bs<^Fi7gA-2d=r850to!FrEifj9YdY<50z<_Q z)GPofXal#xIN~iR$V97AgR11WVNwg60&AtqH-|{Wb*8;Qkv#P#WVkRz*Fo=L?HH(D zy9hu7R9N>hZ`A8(=TC`276lEK?%Gcp+uxnTNAU8lYm39*S!9B1%gtAnr|(Oi5%mU37bn&a?d-w)JE^R!YEzf~yalPpnP^u- zSpqM5ozTjjx`U7V#-TjPoy%%~QMS(~8O{F5p~^>tuR0~8UkvR*FjwdY1*6*HUTsoY zlu2iX;l$Rs)1}1~d)o(Xi>CUmd!h0|SC-78%E4v9BYDV0|0IX% z{%026w3}3oTDN?^WYG9&dSKdA3Wwl@dV;wl|B&eqi&s#tfVf|RF{ia)7@Oje4_LqE zZFOO9OqbJ2AU9Pn-994SJ81|px{=5luByN#ebetnVCeUq9M&_RW7y2d#IG+TC$lQl zoSw*IDdCLfU6fk{!*t>On8J-*-PRqsQwaXgE*wS16?;iq$V^j|lV7Ag6b!3;)|NiUsEKEFHnd3!TVzWA{} zmh|)~N>&apvlc}u%y^5$q7M()M@nm~GHOeJy{vQ_eyxJh@;QU;gXVHinYn%Zp>?qH zJDIDN``>*FfE0!HE;ztffdW>e(E55a5Hxr{87H#Mp1pgfQVm=9X9Wl4Y%5sO{s~Rc z^d`QnMlwfyZkBd@5E=9yWroRbTj#(3CUIo*YopPC&u`G%{$>Sple<1leMok#X?~-Ff zMEuFfrMTLnK{^OSIFKt ztkV6BLtj9o9k2`n+l>po>^MPjd|HR+Ib9Z|T+S0%y~z#E5H!KJFcY9qteXDG1lypF zxeUCSyciCnV=9IiI>A`hOMeEj*+lG6XcSi90%`D^f$}+(%Sz|d|G_zi-bQQHj0fa| zpO2u6pN3#~cGLvi9Wzt()ifDDs4i8sePj`2?%~80<_uJO{{jiSt+5*EyF9QnK;e5s zDvB~uZylP)xs>U(3mC^C`nU4vGs+{R{cI>)ZmH9mrTosyjhC&U)WqALPV1Mpd6sI{D)nFk-CWmle)!>OGh5|?6_9N zkQBaxHQ}pPf~r5A16A)9M0nx5=-|u#_ihbX=&x?(SLW2DfH~g73*AjBG8@5eyvn=t zdVlF83?}y1KgO(wsR=Otm(YUOm30@=vr)TPC&-3J)y|pC#-EgY$)2OoL;rn&2;sXH zxLBUo_BuDHByld>O}|?6IO~C>(&-9%_cOm(4KiinDSjuY{-xCfyog%su6njoB=Q}E zOsjiZb1#$LcR}j{kHc_FZ!cIL!v*e4F#=Dj{GKmdcltb*%yQ(@Yj9cgC|_8N zC#B_h&T)rxRKU@~X#Ad;m0t(~*KA|-8EE7Ay|7%nxAX+?EARJk+au$kpO!ZPDt2!l zReWg5n86PYGDo8nrLJd*v_X`Bx^g^5=*gs)eM@?M7tOi8tTX-$5d=Q32Fkw zHu+YIE7z8hU0v`lZ)*w@&2p(OOq%*Ap9m+K@=oFJl>51uI0!BlXF^VeqK6~W`y|<| z30$~8Suu@Tok6G|OrVhWog7MGrX3#ALf1aaBIhlf&MHeDzFvEN7T54?jW8Ep5U4nX zg8dbcplIFm#%haW+-wM0=ltkPH8N69T%Vi1Gc$+ShZJ^1P{%$Bn$ro%T$O=>9rh$n z@uzbL09jIphVb8QE{G>9aaxdTUN)Mtd<;s>F4r%jO^@_S*up?p{os=e;43;A?8MuQ?IRw;T&N^rbpVf4JMQN>^9@0{4_ z)~U!EcNJP_QfmgPa_?E7DMaIM-HTEk80;gd(Yf4GZ82<)r95kOB*N=vWy$YMIiZ6Y zG8Bmek;jA;yM_I}akv?Mc*Y&>QqD@>*3cr#b)xEP_{ju@)z83e7?cas@=7S}vVY@9 zjg6D1XFyet3dMo(QqKg4w?Z;}UT>z9mZ$Tg`{ubzqZZ@B!(J?m7p30%v8sy(b%2{23Z8YaUk$#sbvTVu9QHMd>D;# zs|I&acD?@VG$K^Mi~JomXKu*1o8GZHZF15>zT9ncvOmgMjvYQdREhHu8boz&Q!BR6 z_>M;*qf8BHTo_%JQt|e={5?2dKXVRGY0UTL~UvV*ZAy0)e8#W_Eo5a6jWULY{P%molM@9xP>eaxZ=j6bpSw zvQ)}$=KFJ?Ku!U$^|n$~{pq(z^bY)+BPkvi3K3BIT^Qk#Y&~2Og>2f>(MbY2zDTq4 zY=OD~zH-3=SBM@O+nd+7YnkupqjIQ%ZVO|3;4vGh*`>x0(A?vg%2j7S>kpn+PY1M? zu$A3u+*ezTCHy(c)kQTfK5fqCKTLWGk*X`#7yNbKc52jkNP3Q5g>^TI#``oNV~#SR z?_r#`3d{OAg%IdGe}Q)|S$m<|u*8p?H7vLd6!+aZsMz%t@O!l}V$n83Gdq>pgVup; z@*M$OP$(dFSOYvOWZ}#$L!3vjgs~3CCNN2q7-;U`;Xj~tlL>0&SCk9GNudK_sMEx* zDU*j*9aAK3wZ!l~K2*vd9KPHY%y9!5#_BB|E%Sr%6zfLJxwrjb#772dOun(mMQYYo zOR}eaH4r?SkdjI?P`U){7Z{KVjhX4Ltn3y;BS;iN2T2K80@PH@71NQe_P!GrqeL?H z4-N>lU508ZMf-m(oC9}U?HYzB*2MP2wi_EwW81df*o}=wjnmjR8Z>I`q_LeeIN!>g zKX9#U-Ov3#YtL-JdxV~n99i@zj{aer4hcVj^mDwe8$jJyS}SPyulWK1BszNDe~={GlnGF z;CJ&Dw41Wb^a_w}uW*)fVy&YtvW~+tJuA59A#cY$Nya~MNTevLu&0RMCDYA=D|Q@s zI%CS2j7M1y?m6QRY$I>ItYB&8`2`2@KYs?LXv1*TOGzIMTjuW{Jn5%ARnMj|f8KqW zL*I2F{=R+B_B9Ul0Y~a!Sk4Z~%AXZBI>0gA+V;c6`0OeJ_xTTv7?0W$%lq%4Rz{h@ z0QJmpT@?!B)d`g`Zf7NBTj*S7d~frg4&KLdMs1W?XO#Vc{u=ORu?im0KU%yd|9|5T zDeg6gw~4c4OfL7~uPw!x!C@!Z*#dWc*aix7&5z0bo z$dWh{q@bp7Ey@PbS?zonB8S0toy4I$mQwyQO1B!DKqd%2{z&<1%P)s0i6tf<|M-yR=Q z;?`?@dLKeDqx!h&l^U&b$r@qB7C4rHn9`(p8g||$AB`c!P!*{ z_DTU6TK(uotYmy0W=7tWBcDJMIKE6|mOWliB|fSIjs(2A;3=P9v&{p?f()DDK>hjc zc&6hFY1!jvW|=ol2sNd_I1cu5le=1GCuF;25;;{$k7mi*?Am*Rz+7wh`atZNID+Ms z`ZiZb_2r2XvyY+4G893p1K00nS-A_7Jv8!Nz(*_ya7-Oy@MI61z9g+c&9X0%ioL=v zZ}2Clb+n2Zx02jX-%MV(@mt>4?1b*h8T8Ha zJs(g}WzwqtHNc{}?1HiO1CIKd#|bCMHLvP@W(-;O-|rJUbL%Q>q5FO-7+3tnV|~A{ z^R-(Q^kITa;H%#R9wMj$zCECIGc*tZePzog!Js~|rL#aV?o6>cx7U@S-h|AXokt#p z73~9#qT$Cw*ac7jre282rQc(Xi?IFpy(K@Do=T!}^=qv(FqRmn8%njEewd4lp~&EP z5mSebhCCB{QBt*paw3oQ6h;+YJAU^-VI_>w8eh)gG_l$ zq%<8lNu2BR4XEX})_Uhg(SilWnw3lyod)a#d-<*Q-qMv^DoNDabRx0`a=GxAM!U+{ zF<)89B;PCeZXsDe;7Au~*Ay(PF4kIH+?}4fO+D|ln9&&W3 zbZ7npJI=G#D&U&0C*A7}lIS$Ity;v-w;pK6hI$vWNnI>3fh4DqM^z`nFG%=0&OypjTQu*L&#Rt?mPeAqVdezwtC%UTdsjv zJDpkSKI8Sj!>39DL$2?CoAKnhEC0L~8;YNKc8U%lXu9r8I9MScoIos@{(!^1BjF(6 zlkOzf+F^7#<0N%!hxo?e1memd#LEoB-TZ@gVb&Jw?U8pWc5gD>ZNO4y+qGb?6YOlB z5BW_p+&C&CQ-$=^{|2%EruUdasfO{3B z+BR$HnC7*ugch+CMF9(14_8G?SRfAT-xKZxL9s0f@fe+m6&a|^_;II#us}KJLHpN} znT5!cuQX4#Rd4edWv*x+<^Wv75sxoTa}Jd)*U2-`OIX#m+xdcT{Tcl+F6@`hCVu$$ zQ@avT@mg}#N`Om<6X&Ir$m5~+6!n$C4npeBP&9G5XScZ<%TUiO=yN@q4ENObGpqD{ zwI6Vl$p9yV5*wx?`G^5IArry0hn%sh&j@-Z8oJJE$oQr35mMwSHG{1kkS@&kODxml z^;sz++}^J1EDs8}#wlUQ<3^kG$6bqgBV>;8%ET3(uBvu6LtXhFaM<>35(gT-GF6XV zp`>Rx8{Xgadw*n%0s+QD_~l-bOIpa(v!Z8&WZCQ2t#A+?LVWH2< zvok*1CA4^L)^^75Er{RVB&Q;FN!I(wZXin)`k%1t*52CgFQPlevbrxsxLK!_r& z!i%t4%U|9*)iOok;0X*CLU3cQbA%h_06wh9QOwz&-00AD|Em1 z+Ql_-72|?LfmOwP1tC3H6ARRD#xomC(#Y`O)oFyp57)endvMSHFh}J+DYvR% zVK%2fKuc&z3ptdrClkuZ#0TPB_hbMM`g)2rzVnEF$2|R zj6pDr;o!GHdT9H$b`t%4ritinqM|ZwH-9Vk|9|E{HVb~&9#IviA(!s9AVr6w`;HzN zI!!a#O7hgWFLh7U?r5$t2i;fkY}-EO6IlQa$L)swz^Qjp49PBIy49%!pp(pBt$5Ij z##QJ;-9naqP&WAO|eqmQT=Y4MAI$ie2GVgn_{=t466~Jc9yxecc4nY zgLezGWHE&{ZLrsa%b{ExHlKIeCl!pJ=iXGd~X(=fAw3IlNp4(1AaaN4-JDZuUogHNmdWE@G6JvAOKO%gLPAf`#`861e+} z)?^U2@(7>qH0xW+_ES+2?UVm?) zvg|w}b8=rrdS1c|sR@4~{<_h%13-dLX@Z|}LKLEjr?CimD0MbgFGk6`feVvGoW9dw z?Up4$kp5efuN2%CXz!p5UcJsHcO0ViF6?TPGSKD(59;T=HNhi-1371_CmvqStjShy zySB&brx~|h2=k=rRc7?wAuj(Uh#IycSW$9Bb?I%ocmtW{Mma)anp3>tM4P?94|C{t zq&vA&*oofl07gqMx0wkRy8UPEX?6!BbfQ(FPTD>Faj6Wx`77Ay(+#4NXaAoP&=tQ8 z(~`1|^4+C^!UY+!@cU$f(Z1w-i~Esj{4JE&a>VzUP0A z4eiYuTO_X505R$fkx1htjNgt^fS-sj$9EFmR^G%^V0$KCW73bIfmYbM*m9$yULws zlKWKD(Bfbn{K|R;)Ww=_0#ta87f{Zn-<>oLil}dfE!Gu_P($sBrrv$DdPbpe0p94r+`z8_YfP@uxRDbo~Eq0VW-*d5rsAKEFqd?Ih&R`$8-aIVuzkRGF#H!BzV;5T=+o z>Ap)r+A&%s1snQ1vE(hGeJ{3(d4UkD0bN5qaJ`D~mdDODw(ksGT?yyW4Y5VB&vuJ^ zn8Q;I!ag3-Jl%gPo5_WLJWY6yi~jleM!I2`n%pWOqADA`xKQA8+M@EtYl3+-u-%xR z!*Nmcx)bZ0Ov>`YNfmgVQ<`7!TTVm7T^bZnYMk^FsyExi7i{vJ>8xov6WQI4*rocCnkXn_uN{tC5fCUl{79TXx0lO0VQO6_^= zbNxPd7dp`=zlq7?7xQ{VtQ&u;xigkBvqO=|w8AU~n`r$$1~`GanN;bEMK+3sV@wem3Y= zb^;i@QgOYw7=qd|TU6v0tn>8b$;C8y2I89YpL|IcmHI6V7{6gW@1XgncqP9q8J-7i z6&{G|4l)X_q;St~z<0hlzbkL4^zkU<0zL)`ZMnMIpg-btON-n>IN%z(pRQAr_Le1H zr~8*{gq>^7Y9nq}iR(Gli3A|g(pCaHf`GF9=(U6#?EF1TndPs8g7Vf{lS{@^6{0e6 z??q<2@b$e^tblCo2ONcNt2Y+==@0#n+d)Xt2IDVo^y@N(6!x^*@IOvTj#HDrN~MDK zgW+`}IIvH6zPStkE1)6rT!y4f{)7tcA3!3?o}lm86{rkRIsfj%Ex z#oX(Y@W2C{D`rDRtykEMd6`i@M=nVn{-q;f_V&|Hq<^n0LxSg~=lic;PEP-yYn@FJtyIdmZy4uJZSIC(JH>K2c`{l}0E zwjxYF27wTIoj-Es3KsDYm6t>$azs}5)RJt{GeDKLszoennL;=}=KYW!s0+jviXBzE z?yxS7##Wo)%1J2a@t^m0VZ-?chQmpPVFdVpZ&G`S)JqiA!*^=})@0w$X0|uz^EhBr zno;1!`xM{dAVKX}`>pX)q?f!>?i{I=m|isb31iGq>c8df6~5O4QAtb4oPNP_MC$QFaR2jO+z zo}cSGPgdo61Y-#~HbF43Zx7vz$N=oZC=O+660{FE!XT{d^f7SdQj_#vy-yNOm{7*e z$2ix)7uXq6+rF>Q7`Z}2xyzPG%MGj-Q0o9jlmS6+Dz-LxRFO_5D@}RFHWec7?0ANg z-Q{C_Nf;oiko1+HJ%@3!U$PHyG=mP@-v@%iZO)7#ERtVCd?uT z&Ua@mu&7x+M6_YUp1SOlO<`vv|1>Zq1DVxK^2{`ao|?&wc2-HnL}mHtiQCml@g>26 zdyaJ0!=XGpSEc%hK*Q6Ug+7eavIP1g>6LH0vAsxn12 zRN$DdI~e)?SN4KZ;N(EYR>!xm9(t_wEln1Z$*)L3{X=FM-pY)jXB=lOecyRU-?TP1 z3QKs_W&;44RsY%(MV->t(=Nrtv^(7h*w($MX#vb82XEPbt7Y81e;cS znOM_CL77BRnJQ+vl%NCyuNnkp8FXF@3B8T<@7&~s4>+o)h#U=jv{&le@FlruIQ3UF z;#EBv^GFldXV0D!Z%#K%nTzT-)mp`ygOSymBeS9)z0(~Wz2H4pd3#I{+f99b5@*jhRN#xSjfzbe@br)tEa+vKKTxt8%*I@qEmbgRD`DvzN3~AZ}pLUE9kF6_g8S zP$>r*IF?V&%sENp3&fuYe1P&MR>*jh7#E&?K9x}L@-}vk?3xEzrW&1%4XM&ToD6az zGGwbpsA~Vc7v~z9IboV4lQP>^~%UF*6R&3!Qrcj6ZurtB}^AACB0JES41A}g`#)DHD14>?jkEVjt zj`8@~S89Nx!`GBlW-^AXfehWyUck>kIHPg`tColOlV+%;U~>eTy83kiqYmpl6F7kl zK`|8-|7E!Bb^-JNRSedYZTLWeDdhkhIv5qa&?w|mTf;6t&DfJkeD457mO+suimhC5E{Wttl7<)O>3&+6?w$v0 znSo7rh3+Ip_={5yXzGD%Q#`Uu{Bygg#H9gMk zbL$2lB1jhjKjjTQiLaD$u|sUOs5j|>pPhx+Mk7#S*HTS+doQzo2H3agM|Qu}yg-H1 z{f#1HF>7Mg4GlUr^pAtJH_F!@L`Kz;?CUq}61177lN9Byrh&kUMEfvDyvZH1=nz{} zf~{g;lU#7$i)~OLp5Iv5kL~NBe5aRA5VRkqX{^;~+wqkIdF*9tAXM|;m*hJoVVaJ4 zyN(yyIP)}V7G2TXPq7M#IbN{G(e&ybJyhj?z+t%^fBa1xnl4mqcb2U-M%8Q$-x0*rzH|F|X@)^6eUo)dVK_oyBya8 zryh{=quh-(A~Rw{JXEq$f;wJEaHmt8CDqP}-tAw@HYK?rdaHj8f41l?*U+02wF%f9 z;L~WX9Ef)w;O8z8U5D17<}Y>9JP?!}aR*ldLcMRufldQvv>}uguo0Mox!F=(J} zvISYM=)HcmVKz<{WWNV}Nom)zGH6}DV2cO%{!wnqOV!`{Fo#i;+j2wZXvj92vzIjH zWZILtOo_At4rgj}bcB#&_RGWrnteE1CyH)j@~;0xjJc{X%-&ii=mAz*!XqcN*(=+2 z4?D9aN~lt!c=92b%+Z#o&NkG(;srh_-u;e+j7O>$YO>7 zc(G8KnS(=2WnUEW>JYRs^Xlv*Z(xsCF9AP(=l1bl`7adxa*W!zf0IRF^%G6oD3X() z9OSY|ssk@B7{+fb4mkzzgBXN)FQhJbV#-UxpSblp%u_5%!?7g!(Tr+E19YhZf5F#x zP@DGYVny*03glyoRhtE}nw^ZVH5z!6FtndIPAr*1mj}aCcvR`%*DecU2Xrlq?U) zsBbP1Xi<;<-To<3Ce=dpWx=bq@mi-PUAqoODx+p&G-m``FS=FXL2c@Ra#Wu9tqST& z=yEQiHXYlAQHv9PtB=g+!yGDVql$VSQ_E&+@3po^*NyU-qJhUnKPj1c;JWf~?&H$=$CPgSix6bG7d z|G!U!!nBhz0Qpjk1Wn7>x0pB2f~bvTn5}U;agtjt(nWcdN=35Ru)}OylV}7pq+uKa z5~<&6h|r?tJm&q{!IkQ^(hJ;Elsvy_#4_*eu)k#F!>B>=NrDgoo6F?5H}J!cV#1bb z!WdSwKgnsQ?fhy5EV0?Vpj=EhZbSts;7KKQ%j{BOyXidptW|QMIN>x?Lq!{}9Rw3` z76zXSWVnsItNMIu()XVdu3gchQ=QQS4;0wVw+648vX`>_ZPM5TUQ5O=l==jvNK>4D z=?}*VxvyqwFmsf53DqhqqL@*HA}ix>jzn~p3|&;LV(C+vNgos`9UnitRP-tT%e2@F zXAhcuh0`=SOu&aZK$k7z@>Z{Xb-XP-IeJj6tIw2>yqeNPR<2d=?^OkJ@qJfWk2)Xr zV)X7yv>%$cDpXk6x`&OSScY0^(x|%4Izfc}SRG@`P2aHBfyOYah@&V`06W*^2OQO) z>s?H`U%(D_2F}-I&CBb&*XGZ{vmC?vl?xF?+-h8}dh(hqdr%kGB7zZV4}#`e_iKHs zy!>(ww8E9Wc%!Aq2p@NG`BnhUQn=-|Vl0FtgGEtV!ZaAZh9JOJw;X2AEVwawsVIrk z^itMO@fXnq(_YzYo|Jj+}yC-W5W-4G6&H3rj$!AYCxP;ivs3F9U&U zHyEEaB6jyVBg zx|;`h`gl94TzmUuSAaP@juCNa!2b=$!*FWTm~(3^@PbN^+IN<`O*9whktM__0i#W7 zn^HjO!yM8HQBLttp&YQ>IBLaccP~I}6328furT(|T0FL1@s3&ncZ|jFP;s=dC_R$? z^D2fG1f+S}42fu#W};(okw9uHRss?nlwZ1@uUpqe3^Wf;!{`ESuoHNoU*FvP=FJM1 zDH}>pdClxY)tgDfNp~Fg+)GnDvsE4v?_ymb7xy3T<-)ZEm-CltK|3=>-1wqAMfQmFli z1yPSsRnbGrp6Npu)`u{+#!(L5y-$ z417*vAc@PlNGw|iHdn!NT-wgKoy;NiD`iZzMznwkn~SdW%MUn;M~+x}Qe$#@0C2e( zBR1sPfUbKJdy#$LXib1He7iUsm4%Cu_bN3dKQ@@&j|{Kv?uXLt)`$`Y)^z3j(YO87 zX(b%!(}or*mbF%+3H@He2DqpM3l7!~ICSlSI3q!6Q9q(UlbE`2W}Y5=T9eQKx;5r^ zw3>p$#Q2SJM_4`W8E(qf1@7I;B7BH6Vkr zV^Fh)Uov}6?*|;ti7}|eCsROFw0Zbd;wd`AEQP^ddkx>*D_=_SN^3hr;h&WM=ly%7 zvQ5)|WkV}`7s*nzOqd#E{<)TkvxeWCC_Se7lwG}Uhq5Z|>GNlp#d=~^SE=UoV zQas2dAL}*i63q;sJb!)EIs$6fV)U0ycKL0sxFxqVkD{Iw=qj38^7*2bh+iFfcebDa zlROvENSv%q%=MDVB#W;={;Nl3Iar9VH>SiGGWGr`p83XY1g?=?n?3ed>ZfEjQ`k7AR%xSvtf{j#aRfp@hh4{A6WIPnsKDa=a zSGp^hVoM*i;ny`|s_r#!cboqa3sMID`)tWHEiPXh=aoy0QzGe16Q-H-SPldM9swNj zu(Bu1>m1dr2Pya25+wgrmEe{D#EwC++*8t`e$(f#r& zqOqCwA|G&|!RdHm%uYlI$!Z)!s2qN*<%44YdYbEAG5(DL=@A-9UxDv%a13hi$4rSg? z0sLh3kg`@}S=>vJECEP~8M@XA4&_{*l3m69>X%Xf#EiNoYYF0#Vko@lRbDYQzVDuz z9T3hsU7{Cp5&A!taMyz2Z{v*T{ZIb68>c&C0aT0eSp<4a coqm$9qo<;2%jPEPBLUj^>cLcwCICS2KR`28n*aa+ literal 0 HcmV?d00001 diff --git a/crates/brother-ql/tests/golden/ql800_23x23_x2.bin b/crates/brother-ql/tests/golden/ql800_23x23_x2.bin new file mode 100644 index 0000000000000000000000000000000000000000..a677f862f6c96bf03a3908b0803f498a5eb85c30 GIT binary patch literal 38050 zcmeI5!D<{w5QazSu!aQYXz(8PO|r>3h9_p ztqKxW^$U;qhegu1(C^mQe^*zxX3G21A9sVU?~1_w=RHPcfBLvTefj5y_wWBMz1yFD zL;Eji|MlJe^l2DA55M!eE%A`8un0>?AZ(Odge4>pHp(r+5)ud-G7Yj`JnS zE#t%CPU1f6`Xm~spLoo7mp@1NoHL+1cm(3`IUHiIOt;voHnGI-ApXD-A0Q5G4i*gM zBTsx+kdu0D-G)ifeY`NZnQp1t60aP3Y_SZH$GlpRG@xw~)!2pK!D3`q-s01rBJP2U zBJLrVBmQ+boI#l)K2CKAIpPn4r55%t06!Al%stU4@nVYlp~n^XO z;uo^*^9%FaD=cmLbHrQV;)u7rg(Th<3kvgLSMpF&&+7o&_SrI0`-t!|dFxG|`y}c= zEpecDB`iLA6y{exN3LrL(u=MI3#)4ViejOE4#amLu!O~VDj(A%`ZR3nr zIh{LN0`roqyQSqV5-&7g2}{j#In3RPHkrz~T-i#SGjG2-7N0~Eai9JaaSvP+aZidk z;%%|uh%ZUefH;GLql=xo+-?>8WOqwbDc+O#D`9DeImSMpd9`94*W*ilQe_q_HE-dF zFNZnM&+fU+%&GP}Uwk>tA@sa07Par$SUhh59jru_z1UaDd5bAZyiX!e=Qvne-a--g zyaiswd5-;=JMk>n^A?JDoBp=U<@en47K*s%EgbP>lbesl4|BlY#5sQ_k~oa9q;rTZ zc3BwDXa0KPScx!Ck?1DviJtUa;{H6*8^KanB9dDq9=c_dSP&U4u-HmuLDC}S&DT1e zGm(~BY)ahna$3(fFJ4k;JKwhCF>Ox-C1Y-imraScnZoJ$=Ed7Dkn^d>mK?dKDiVLn zqrDRrVF?L@jdF{ygapDyxkXq)0%4=vA}k?+uu*OimXJW$D7S=IKBxv$$mKs9<);vl zun0>?AZ(Odge4>pHp(r+5)ud-{4W<>9)$Nk1!L;Ji-Ll~VPpZKb4XEA0G~pY#r?%Yhg_Shb$?p1pdgCmaV->`cez}uwzUw!(Qn;IwRX5L)u zfr}!(Jhq3M8nb)8Jhn#=Z;$QSAm;ZRPX(w36VTRcl@u|tOm*6n+tah_Ubz)H;)pHh z8cbA!X|;v|3k+m2HXlpNTS($N)nKYq-#+%~-ra(?1o<>M`v6p06Gt&lmSv2H1z*Fo(muTCojl-J#bvw}0$2 z)K5fz+d)@*s;ylOxhMrirEg_Z<-vAcXR^k8v literal 0 HcmV?d00001 diff --git a/crates/brother-ql/tests/golden/random_1392x150.png b/crates/brother-ql/tests/golden/random_1392x150.png new file mode 100644 index 0000000000000000000000000000000000000000..ff8e3ec8bf156ca1116fe61ea65cb95976e03159 GIT binary patch literal 26318 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%0D!hvPXCkuVa0@{?#?^+gHh<@-lF~ad)aY)@g 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 literal 0 HcmV?d00001 diff --git a/crates/brother-ql/tests/golden/random_202_dither.bin b/crates/brother-ql/tests/golden/random_202_dither.bin new file mode 100644 index 0000000000000000000000000000000000000000..04dbfa5fe60889b0d2d33bac50e66b7d51b744c3 GIT binary patch literal 19230 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 V$Mf0)7PeYry*RcT{o5?ve*kd_szv|+ literal 0 HcmV?d00001 diff --git a/crates/brother-ql/tests/golden/random_202_thr0.bin b/crates/brother-ql/tests/golden/random_202_thr0.bin new file mode 100644 index 0000000000000000000000000000000000000000..04dbfa5fe60889b0d2d33bac50e66b7d51b744c3 GIT binary patch literal 19230 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 E0ePfi?EnA( literal 0 HcmV?d00001 diff --git a/crates/brother-ql/tests/golden/random_202_thr50.bin b/crates/brother-ql/tests/golden/random_202_thr50.bin new file mode 100644 index 0000000000000000000000000000000000000000..04dbfa5fe60889b0d2d33bac50e66b7d51b744c3 GIT binary patch literal 19230 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 literal 0 HcmV?d00001 diff --git a/crates/brother-ql/tests/golden/random_236.png b/crates/brother-ql/tests/golden/random_236.png new file mode 100644 index 0000000000000000000000000000000000000000..991ac8e12c553a736f7d67471387e0bb380329c5 GIT binary patch literal 7377 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�-dy(0v&wk>dA9hbJzT zY61@B{9n+}IbuqT6@eBNoan1T*e|!l-guc(uo(^l-Bxy5tbg&|1YV)I*Bu_crYbm| z33%3EIJOwV3#NkS>mUCJ5LQ_D;>Rd2iIbT=owtXNi9=yCwq`@kA7DH#Gq1zhnIt9i z-;-^c??AYt0CV(enbaOeLB0C`*nc@ji|ym=e2Vj9ekM4g16Aj^D68G?@a&%PuM0XxpmI5zy0DES;YJI~|zf!LZ?0maI9bLx(@wzu| zV`<&4tm~n-7zCFE))5$?&L|Jygvg z{Fk=osMvuiOGxCLR@c;wflIC8? zZ=@>BO3T}MSfli{Jy{HFEN4yzv{F)v&U#iE3Rpr0efL< zBrsUG<}^^0Dd8^jd2>aH&e`mfFH0=TLEKWKR9-a_V2Kk(wXv`kshYQUs3fvdb(`wC zS!O?xH6xC&rf7mWeZ9F!@72R&&paG{_T-9-hHC-N!NGl3Ye@J)=m5s3hf1U+l@70K z48JpNSs&DUxZJR5oZ>)8fk(pA0Db+^dcfkcuQ=9@J zA8~VoMIw^%vNVwuo=*}O{@XQi7pv^}K2y&!)VudTj4!vcmHsss00000NkvXXu0mjf D@c@Qo literal 0 HcmV?d00001 diff --git a/crates/brother-ql/tests/golden/random_271x696.png b/crates/brother-ql/tests/golden/random_271x696.png new file mode 100644 index 0000000000000000000000000000000000000000..6449b6aec22d1202674c353919ed4d7418e91559 GIT binary patch literal 24375 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 UtM?U2Q~&?~07*qoM6N<$g5T&$F#rGn literal 0 HcmV?d00001 diff --git a/crates/brother-ql/tests/golden/random_306x300.png b/crates/brother-ql/tests/golden/random_306x300.png new file mode 100644 index 0000000000000000000000000000000000000000..dde15c4b32035fd938230d8129b8abfd4bac29eb GIT binary patch literal 12044 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 UZ7BlQ(EtDd07*qoM6N<$f<-<~jsO4v literal 0 HcmV?d00001 diff --git a/crates/brother-ql/tests/golden/random_404_dpi600.bin b/crates/brother-ql/tests/golden/random_404_dpi600.bin new file mode 100644 index 0000000000000000000000000000000000000000..21fd07555b38368587ec18733ba91904564e2854 GIT binary patch literal 38016 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 literal 0 HcmV?d00001 diff --git a/crates/brother-ql/tests/golden/random_404_dpi600_compress.bin b/crates/brother-ql/tests/golden/random_404_dpi600_compress.bin new file mode 100644 index 0000000000000000000000000000000000000000..0f610f2979e660ed81a3858d176e99ec41cb2eb9 GIT binary patch literal 14201 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 LNkvXXu0mjfG*t>@ literal 0 HcmV?d00001 diff --git a/crates/brother-ql/tests/golden/random_696x300.png b/crates/brother-ql/tests/golden/random_696x300.png new file mode 100644 index 0000000000000000000000000000000000000000..b60c1d61234e84135980cb3086f3268819e7d354 GIT binary patch literal 26468 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 Y{&8`Z)9E)lF`i|9tIbZ}zr>0D53|z@qyPW_ literal 0 HcmV?d00001 diff --git a/crates/brother-ql/tests/golden/sparse_1164x301.png b/crates/brother-ql/tests/golden/sparse_1164x301.png new file mode 100644 index 0000000000000000000000000000000000000000..12ee7a01a76ecc47cd5d3c932d578438c2ac2d13 GIT binary patch literal 6765 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 P00000NkvXXu0mjfW?ujT literal 0 HcmV?d00001 diff --git a/crates/brother-ql/tests/golden/sparse_696x301.png b/crates/brother-ql/tests/golden/sparse_696x301.png new file mode 100644 index 0000000000000000000000000000000000000000..3b8c3f89308695a9daf4521185f8244c32a4d0b7 GIT binary patch literal 4535 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 VJe9G{eHQ=#002ovPDHLkV1mbG-FyH5 literal 0 HcmV?d00001 diff --git a/crates/brother-ql/tests/golden/white_202.png b/crates/brother-ql/tests/golden/white_202.png new file mode 100644 index 0000000000000000000000000000000000000000..bf862c1706a999ce9889e2df8e469139fd7aa03a GIT binary patch literal 126 zcmeAS@N?(olHy`uVBq!ia0vp^r$CqyNHCm{d&CN)Ts>VJLn`LHy`ad*pdfJIK>NR? z9&BZ8Y~^Knug@L7x!*{6s`OL0oq>5%a8iaJ8Khq`hm_k&n}H1WboFyt=akR{0KU8{ A;s5{u literal 0 HcmV?d00001 diff --git a/crates/brother-ql/tests/golden/white_202_compress.bin b/crates/brother-ql/tests/golden/white_202_compress.bin new file mode 100644 index 0000000000000000000000000000000000000000..65a0f1ff853850bfaca00804c1895d3df663c177 GIT binary patch literal 1456 zcmb2nOk`vj1%oOCq#dMzu_B!rES*_(j$2&(6xemrnZ7`AN1(VjhjeBN1A{M9Is?;k QhEZZP3`Wzz2+0Og0D}48Z2$lO literal 0 HcmV?d00001 diff --git a/crates/brother-ql/tests/golden/white_202_x1.bin b/crates/brother-ql/tests/golden/white_202_x1.bin new file mode 100644 index 0000000000000000000000000000000000000000..43daccf056d28ba858bf0ec80942b4abf4e30f34 GIT binary patch literal 19230 zcmeIwF^WPl07cPnH{b$3Og5vnSlQVP3`n-%5-nVlAM4u+7ANH`LO6M2{_Pg$s|3bj zY`-$*Wz73?zpjt>>&859{kZkh&zS$qa$BySd$!Bd77LaX$Y?ECQXr$XU`c_D)`BGk zGFl6k6v${TSW+OPwO~nsjMjoB1u|L-mK4ZnEm%?@qqSg3fsEFIB?U5C3zihfXf0S$ zAfvTlNr8;kf+YnqS__sG$Y?ECQXr$XU`c_D)`BGkGFl6k6v${TSW+OPwO~nsjMjoB z1u|L-mK4ZnEm%?@qqSg3fsEFIB?U5C3zihfXf0S$AfvTlNr8;kf+YnqS__sG$oTsL DLOh|! literal 0 HcmV?d00001 diff --git a/crates/brother-ql/tests/golden/white_202_x2.bin b/crates/brother-ql/tests/golden/white_202_x2.bin new file mode 100644 index 0000000000000000000000000000000000000000..5f46846bd2a3926a12877e1a1bf0eb45bbe93250 GIT binary patch literal 38050 zcmeI)F=_%q0EW@E3*-QTa~Z9Jm7Sdskhy|Kw8)vVSbt!pSiCL2Vj154)9#p;&Eoke zfw3R!R~hp(=I!r$yS+b7H|BBehqeEFjrqGQ*X8`WV|#hpV!@IE8Lb6N3S_hvEGdxD zTCk)*Mr*;60vW9ZOA2JP7Az@{(OR&iKt^l9k^&j61xpHKv=%HWkkMMOq(DY%!IA Vec { + // a real two-label job for L0006 as produced by Python brother_ql + let p = Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/golden/label_L0006_x2.bin"); + std::fs::read(p).expect("golden data") +} + +const SENT: SendStatus = SendStatus { + instructions_sent: true, + outcome: Outcome::Sent, + did_print: false, + ready_for_next_job: false, +}; + +/// 32-byte QL status reply (80 20 42 ...): model QL-820NWB (0x41), 23 mm +/// die-cut media, given status/phase type. +fn status_reply(status_type: u8, phase_type: u8) -> [u8; 32] { + let mut r = [0u8; 32]; + r[0] = 0x80; + r[1] = 0x20; + r[2] = 0x42; + r[3] = 0x34; + r[4] = 0x41; + r[5] = 0x30; + r[10] = 23; // media width + r[11] = 0x0B; // die-cut + r[17] = 23; // media length + r[18] = status_type; + r[19] = phase_type; + r +} + +#[test] +fn sends_exact_bytes_and_closes() { + let data = job(); + for prefix in ["tcp://", ""] { + let listener = TcpListener::bind("127.0.0.1:0").unwrap(); + let port = listener.local_addr().unwrap().port(); + let server = thread::spawn(move || { + let (mut s, _) = listener.accept().unwrap(); + let mut got = Vec::new(); + s.read_to_end(&mut got).unwrap(); // returns only once the client closed + got + }); + let status = send_network( + &format!("{prefix}127.0.0.1:{port}"), + &data, + true, + Duration::from_secs(5), + ) + .unwrap(); + assert_eq!(status, SENT); + let got = server.join().unwrap(); + assert_eq!(got.len(), data.len()); + assert!(got == data, "received bytes differ"); + } +} + +#[test] +fn blocking_does_not_wait_for_status_replies() { + let data = job(); + let n = data.len(); + let listener = TcpListener::bind("127.0.0.1:0").unwrap(); + let port = listener.local_addr().unwrap().port(); + let (tx, rx) = mpsc::channel(); + let server = thread::spawn(move || { + let (mut s, _) = listener.accept().unwrap(); + let mut got = vec![0u8; n]; + s.read_exact(&mut got).unwrap(); + // A real printer answers ESC i S and later reports "printing + // completed" (0x01) and "phase change: waiting to receive" (0x06/0x00). + // Hold them back for a while: the client must not wait for them. + let eof = { + let mut buf = [0u8; 1]; + s.set_read_timeout(Some(Duration::from_secs(3))).unwrap(); + matches!(s.read(&mut buf), Ok(0)) + }; + tx.send(()).unwrap(); + let _ = s.write_all(&status_reply(0x01, 0x00)); + let _ = s.write_all(&status_reply(0x06, 0x00)); + let _ = s.shutdown(Shutdown::Both); + (got, eof) + }); + let t0 = Instant::now(); + let status = send_network( + &format!("tcp://127.0.0.1:{port}"), + &data, + true, + Duration::from_secs(5), + ) + .unwrap(); + let elapsed = t0.elapsed(); + assert_eq!(status, SENT, "network backend never reports printed/ready"); + let (got, eof) = server.join().unwrap(); + rx.recv().unwrap(); + assert!(got == data); + assert!(eof, "client did not close the connection after writing"); + assert!( + elapsed < Duration::from_secs(2), + "send_network waited {elapsed:?}" + ); +} + +#[test] +fn non_blocking_is_identical() { + let data = b"\x1B\x40hello".to_vec(); + let listener = TcpListener::bind("127.0.0.1:0").unwrap(); + let port = listener.local_addr().unwrap().port(); + let server = thread::spawn(move || { + let (mut s, _) = listener.accept().unwrap(); + let mut got = Vec::new(); + s.read_to_end(&mut got).unwrap(); + got + }); + let status = send_network( + &format!("127.0.0.1:{port}"), + &data, + false, + Duration::from_secs(5), + ) + .unwrap(); + assert_eq!(status, SENT); + assert_eq!(server.join().unwrap(), data); +} + +#[test] +fn connection_refused_is_an_error() { + let port = { + let l = TcpListener::bind("127.0.0.1:0").unwrap(); + l.local_addr().unwrap().port() + }; + let err = send_network( + &format!("tcp://127.0.0.1:{port}"), + b"x", + true, + Duration::from_secs(2), + ) + .unwrap_err(); + assert!(matches!(err, Error::Connect { .. }), "{err}"); + let err = send_network("tcp://", b"x", true, Duration::from_secs(2)).unwrap_err(); + assert!(matches!(err, Error::InvalidAddress(_)), "{err}"); +} + +#[test] +fn write_times_out_when_printer_stalls() { + // The fake printer accepts but never reads, so the socket buffers fill up. + let listener = TcpListener::bind("127.0.0.1:0").unwrap(); + let port = listener.local_addr().unwrap().port(); + let (done_tx, done_rx) = mpsc::channel::<()>(); + let server = thread::spawn(move || { + let (s, _) = listener.accept().unwrap(); + let _ = done_rx.recv_timeout(Duration::from_secs(30)); + drop(s); + }); + let data = vec![0u8; 64 << 20]; + let t0 = Instant::now(); + let res = send_network( + &format!("127.0.0.1:{port}"), + &data, + true, + Duration::from_millis(500), + ); + let elapsed = t0.elapsed(); + done_tx.send(()).unwrap(); + server.join().unwrap(); + match res { + Err(Error::Write(e)) => assert_eq!(e.kind(), std::io::ErrorKind::TimedOut, "{e}"), + other => panic!("expected a write timeout, got {other:?}"), + } + assert!(elapsed < Duration::from_secs(5), "timeout took {elapsed:?}"); +} diff --git a/crates/brother-ql/tools/golden.py b/crates/brother-ql/tools/golden.py new file mode 100644 index 0000000..d0d2164 --- /dev/null +++ b/crates/brother-ql/tools/golden.py @@ -0,0 +1,213 @@ +"""Generate golden test data for the Rust brother-ql crate. + +For every case this writes the input image(s) as 1-bit PNG plus the output of +Python ``brother_ql.conversion.convert`` (brother_ql_next 0.12) as ``.bin`` +into ``crates/brother-ql/tests/golden/`` and lists the cases in +``manifest.txt``. ``tests/golden.rs`` re-runs the conversion in Rust and +requires identical bytes. + +Run with a Python that has brother_ql_next, qrcode and pillow, e.g.: + + C:/dev/HPCS/.venv/Scripts/python.exe -W ignore crates/brother-ql/tools/golden.py + +``render_label`` below is a verbatim copy of the HPCS ``label_printer.py`` +function. Pass ``--reference path/to/label_printer.py`` (or set +``LABEL_PRINTER_PY``) to import the original instead and assert both agree. +""" + +import argparse +import importlib.util +import os +import random +import sys +from pathlib import Path + +import qrcode +from PIL import Image, ImageDraw, ImageFont +from brother_ql.conversion import convert +from brother_ql.raster import BrotherQLRaster + +OUT = Path(__file__).resolve().parent.parent / "tests" / "golden" + +# ---- verbatim copy of label_printer.py (HPCS) ------------------------------- +DOTS = (202, 202) +TEXT_HEIGHT = 52 + + +def _font(size): + for name in ("arialbd.ttf", "arial.ttf", "DejaVuSans-Bold.ttf"): + try: + return ImageFont.truetype(name, size) + except OSError: + continue + return ImageFont.load_default(size) + + +def render_label(lamp_id: str) -> Image.Image: + image = Image.new("1", DOTS, 1) + qr = qrcode.QRCode( + error_correction=qrcode.constants.ERROR_CORRECT_M, + box_size=1, + border=2, + ) + qr.add_data(lamp_id.upper()) + qr.make(fit=True) + modules = len(qr.get_matrix()) + qr_size = DOTS[1] - TEXT_HEIGHT + qr.box_size = max(1, qr_size // modules) + qr_img = qr.make_image().get_image().convert("1") + image.paste(qr_img, ((DOTS[0] - qr_img.width) // 2, (qr_size - qr_img.height) // 2)) + + draw = ImageDraw.Draw(image) + size = 44 + while size > 10: + font = _font(size) + box = draw.textbbox((0, 0), lamp_id, font=font) + if box[2] - box[0] <= DOTS[0] - 8: + break + size -= 2 + draw.text( + ((DOTS[0] - (box[2] - box[0])) // 2 - box[0], DOTS[1] - TEXT_HEIGHT + (TEXT_HEIGHT - (box[3] - box[1])) // 2 - box[1]), + lamp_id, + font=font, + fill=0, + ) + return image +# ----------------------------------------------------------------------------- + + +def random_image(w, h, seed, p=0.5): + rng = random.Random(seed) + im = Image.new("1", (w, h), 1) + px = im.load() + for y in range(h): + for x in range(w): + if rng.random() < p: + px[x, y] = 0 + return im + + +def synthetic(): + w, h = 202, 202 + imgs = { + "white_202": Image.new("1", (w, h), 1), + "black_202": Image.new("1", (w, h), 0), + } + chk = Image.new("1", (w, h), 1) + px = chk.load() + for y in range(h): + for x in range(w): + if (x + y) % 2: + px[x, y] = 0 + imgs["checker_202"] = chk + for name, (x, y) in { + "corner_tl": (0, 0), + "corner_tr": (w - 1, 0), + "corner_bl": (0, h - 1), + "corner_br": (w - 1, h - 1), + }.items(): + im = Image.new("1", (w, h), 1) + im.putpixel((x, y), 0) + imgs[name] = im + imgs["random_202"] = random_image(w, h, 1234) + return imgs + + +def main(): + ap = argparse.ArgumentParser() + ap.add_argument("--reference", default=os.environ.get("LABEL_PRINTER_PY")) + args = ap.parse_args() + + reference = None + if args.reference and Path(args.reference).exists(): + spec = importlib.util.spec_from_file_location("label_printer_ref", args.reference) + reference = importlib.util.module_from_spec(spec) + spec.loader.exec_module(reference) + + OUT.mkdir(parents=True, exist_ok=True) + for f in OUT.iterdir(): + if f.suffix in (".png", ".bin") or f.name == "manifest.txt": + f.unlink() + + images = {} + for lamp_id in ("L0001", "L0006", "L0123", "L12345", "L9"): + im = render_label(lamp_id) + if reference is not None: + ref = reference.render_label(lamp_id) + assert ref.tobytes() == im.tobytes(), f"embedded render_label differs for {lamp_id}" + images[f"label_{lamp_id}"] = im + images.update(synthetic()) + images["random_404"] = random_image(404, 404, 404) + images["random_696x300"] = random_image(696, 300, 696) + images["random_500x200"] = random_image(500, 200, 500) + images["random_300x696"] = random_image(300, 696, 300) + images["random_1392x150"] = random_image(1392, 150, 1392) + images["random_306x300"] = random_image(306, 300, 306) + images["random_271x696"] = random_image(271, 696, 2716) + images["random_236"] = random_image(236, 236, 236) + images["sparse_1164x301"] = random_image(1164, 301, 1164, p=0.01) + images["random_696x271"] = random_image(696, 271, 271) + images["sparse_696x301"] = random_image(696, 301, 301, p=0.01) + + for name, im in images.items(): + im.save(OUT / f"{name}.png") + + cases = [] # (case name, model, label, [image names], kwargs) + base = list(images)[:13] # 5 labels + 8 synthetic 202x202 images + for name in base: + for copies in (1, 2): + cases.append((f"{name}_x{copies}", "QL-820NWB", "23x23", [name] * copies, {"cut": True})) + q = "QL-820NWB" + cases += [ + ("label_L0006_nocut", q, "23x23", ["label_L0006"], {"cut": False}), + ("label_L0006_compress_x2", q, "23x23", ["label_L0006"] * 2, {"compress": True}), + ("random_202_compress", q, "23x23", ["random_202"], {"compress": True}), + ("checker_202_compress", q, "23x23", ["checker_202"], {"compress": True}), + ("black_202_compress", q, "23x23", ["black_202"], {"compress": True}), + ("white_202_compress", q, "23x23", ["white_202"], {"compress": True}), + ("corner_tl_rot0", q, "23x23", ["corner_tl"], {"rotate": 0}), + ("corner_tl_rot90", q, "23x23", ["corner_tl"], {"rotate": 90}), + ("corner_tl_rot180", q, "23x23", ["corner_tl"], {"rotate": 180}), + ("corner_tl_rot270", q, "23x23", ["corner_tl"], {"rotate": 270}), + ("corner_br_rot0", q, "23x23", ["corner_br"], {"rotate": 0}), + ("random_202_thr100", q, "23x23", ["random_202"], {"threshold": 100}), + ("random_202_thr0", q, "23x23", ["random_202"], {"threshold": 0}), + ("random_202_thr50", q, "23x23", ["random_202"], {"threshold": 50}), + ("random_202_lq", q, "23x23", ["random_202"], {"hq": False}), + ("random_202_dither", q, "23x23", ["random_202"], {"dither": True}), + ("random_202_dither_thr100", q, "23x23", ["random_202"], {"dither": True, "threshold": 100}), + ("multi_labels", q, "23x23", ["label_L0001", "label_L0006", "label_L12345"], {"cut": True}), + ("random_404_dpi600", q, "23x23", ["random_404"], {"dpi_600": True}), + ("random_404_dpi600_compress", q, "23x23", ["random_404"], {"dpi_600": True, "compress": True}), + ("endless62_696", q, "62", ["random_696x300"], {}), + ("endless62_resize500", q, "62", ["random_500x200"], {}), + ("endless62_rot90", q, "62", ["random_300x696"], {"rotate": 90}), + ("endless62_dpi600", q, "62", ["random_1392x150"], {"dpi_600": True}), + ("endless29_306", q, "29", ["random_306x300"], {"compress": True}), + ("diecut62x29_auto_rotate", q, "62x29", ["random_271x696"], {}), + ("round_d24", q, "d24", ["random_236"], {}), + ("ql1100_102", "QL-1100", "102", ["sparse_1164x301"], {"compress": True}), + ("ql1100_62", "QL-1100", "62", ["sparse_696x301"], {"compress": True}), + ("ql700_62_compress_ignored", "QL-700", "62", ["random_696x300"], {"compress": True}), + ("ql500_29", "QL-500", "29", ["random_306x300"], {}), + ("ql570_62x29", "QL-570", "62x29", ["random_696x271"], {"cut": False}), + ("ql800_23x23_x2", "QL-800", "23x23", ["label_L0006"] * 2, {"compress": True}), + ] + + lines = ["# name model label images options... (generated by tools/golden.py)"] + for name, model, label, imgs, kwargs in cases: + inputs = [Image.open(OUT / f"{i}.png") for i in imgs] + for im in inputs: + assert im.mode == "1", (i, im.mode) + data = convert(qlr=BrotherQLRaster(model), images=inputs, label=label, **kwargs) + (OUT / f"{name}.bin").write_bytes(data) + opts = " ".join(f"{k}={v}" for k, v in kwargs.items()) + lines.append(f"{name} {model} {label} {','.join(i + '.png' for i in imgs)} {opts}".rstrip()) + (OUT / "manifest.txt").write_bytes(("\n".join(lines) + "\n").encode("ascii")) + total = sum(f.stat().st_size for f in OUT.iterdir()) + print(f"{len(cases)} cases, {len(images)} images, {total} bytes in {OUT}") + print("reference render_label checked" if reference else "reference render_label NOT checked") + + +if __name__ == "__main__": + main() diff --git a/crates/lamp-label/Cargo.toml b/crates/lamp-label/Cargo.toml new file mode 100644 index 0000000..e5c7d4a --- /dev/null +++ b/crates/lamp-label/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "lamp-label" +description = "Lamp ID labels (QR code + text) for the Brother QL-820NWB on DK-11221 23x23 mm labels" +version.workspace = true +edition.workspace = true +publish.workspace = true + +[lib] +name = "lamp_label" + +[dependencies] +brother-ql = { path = "../brother-ql" } +fontdue = "0.9.4" +png = "0.17" +qrcode = { version = "0.14", default-features = false } diff --git a/crates/lamp-label/src/font5x7.rs b/crates/lamp-label/src/font5x7.rs new file mode 100644 index 0000000..3793a2f --- /dev/null +++ b/crates/lamp-label/src/font5x7.rs @@ -0,0 +1,57 @@ +//! Tiny embedded 5x7 bitmap font, used only when no TrueType font file is +//! available so that printing never fails because of fonts. + +/// Glyph rows top to bottom; bit 4 is the leftmost column. +pub(crate) fn glyph(c: char) -> [u8; 7] { + match c.to_ascii_uppercase() { + '0' => [0x0E, 0x11, 0x13, 0x15, 0x19, 0x11, 0x0E], + '1' => [0x04, 0x0C, 0x04, 0x04, 0x04, 0x04, 0x0E], + '2' => [0x0E, 0x11, 0x01, 0x02, 0x04, 0x08, 0x1F], + '3' => [0x1F, 0x02, 0x04, 0x02, 0x01, 0x11, 0x0E], + '4' => [0x02, 0x06, 0x0A, 0x12, 0x1F, 0x02, 0x02], + '5' => [0x1F, 0x10, 0x1E, 0x01, 0x01, 0x11, 0x0E], + '6' => [0x06, 0x08, 0x10, 0x1E, 0x11, 0x11, 0x0E], + '7' => [0x1F, 0x01, 0x02, 0x04, 0x08, 0x08, 0x08], + '8' => [0x0E, 0x11, 0x11, 0x0E, 0x11, 0x11, 0x0E], + '9' => [0x0E, 0x11, 0x11, 0x0F, 0x01, 0x02, 0x0C], + 'A' => [0x0E, 0x11, 0x11, 0x1F, 0x11, 0x11, 0x11], + 'B' => [0x1E, 0x11, 0x11, 0x1E, 0x11, 0x11, 0x1E], + 'C' => [0x0E, 0x11, 0x10, 0x10, 0x10, 0x11, 0x0E], + 'D' => [0x1C, 0x12, 0x11, 0x11, 0x11, 0x12, 0x1C], + 'E' => [0x1F, 0x10, 0x10, 0x1E, 0x10, 0x10, 0x1F], + 'F' => [0x1F, 0x10, 0x10, 0x1E, 0x10, 0x10, 0x10], + 'G' => [0x0E, 0x11, 0x10, 0x17, 0x11, 0x11, 0x0F], + 'H' => [0x11, 0x11, 0x11, 0x1F, 0x11, 0x11, 0x11], + 'I' => [0x0E, 0x04, 0x04, 0x04, 0x04, 0x04, 0x0E], + 'J' => [0x07, 0x02, 0x02, 0x02, 0x02, 0x12, 0x0C], + 'K' => [0x11, 0x12, 0x14, 0x18, 0x14, 0x12, 0x11], + 'L' => [0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1F], + 'M' => [0x11, 0x1B, 0x15, 0x15, 0x11, 0x11, 0x11], + 'N' => [0x11, 0x11, 0x19, 0x15, 0x13, 0x11, 0x11], + 'O' => [0x0E, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0E], + 'P' => [0x1E, 0x11, 0x11, 0x1E, 0x10, 0x10, 0x10], + 'Q' => [0x0E, 0x11, 0x11, 0x11, 0x15, 0x12, 0x0D], + 'R' => [0x1E, 0x11, 0x11, 0x1E, 0x14, 0x12, 0x11], + 'S' => [0x0F, 0x10, 0x10, 0x0E, 0x01, 0x01, 0x1E], + 'T' => [0x1F, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04], + 'U' => [0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0E], + 'V' => [0x11, 0x11, 0x11, 0x11, 0x11, 0x0A, 0x04], + 'W' => [0x11, 0x11, 0x11, 0x15, 0x15, 0x15, 0x0A], + 'X' => [0x11, 0x11, 0x0A, 0x04, 0x0A, 0x11, 0x11], + 'Y' => [0x11, 0x11, 0x11, 0x0A, 0x04, 0x04, 0x04], + 'Z' => [0x1F, 0x01, 0x02, 0x04, 0x08, 0x10, 0x1F], + '-' => [0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00], + '_' => [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F], + '.' => [0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C], + ':' => [0x00, 0x0C, 0x0C, 0x00, 0x0C, 0x0C, 0x00], + '/' => [0x01, 0x01, 0x02, 0x04, 0x08, 0x10, 0x10], + ' ' => [0; 7], + // anything else: an empty box (like a .notdef glyph) + _ => [0x1F, 0x11, 0x11, 0x11, 0x11, 0x11, 0x1F], + } +} + +/// Glyph cell: 5 columns + 1 column spacing, 7 rows. +pub(crate) const COLS: u32 = 5; +pub(crate) const ADVANCE: u32 = 6; +pub(crate) const ROWS: u32 = 7; diff --git a/crates/lamp-label/src/lib.rs b/crates/lamp-label/src/lib.rs new file mode 100644 index 0000000..0f68078 --- /dev/null +++ b/crates/lamp-label/src/lib.rs @@ -0,0 +1,211 @@ +//! Lamp ID labels for the Brother QL-820NWB on DK-11221 (23 x 23 mm die-cut) +//! labels: a Rust port of the HPCS `label_printer.py`. +//! +//! Each 202 x 202 dot label carries the lamp ID as a QR code (top 150 dots) +//! and as text (bottom 52 dots). Scanning the QR code types the ID. +//! +//! ```no_run +//! let label = lamp_label::render_label("L0006"); +//! lamp_label::save_png(&label, std::path::Path::new("L0006.png"))?; +//! lamp_label::print_labels("L0006", "tcp://192.168.1.50", 2)?; +//! # Ok::<(), lamp_label::Error>(()) +//! ``` + +mod font5x7; +pub mod qr; +pub mod text; + +use std::fmt; +use std::fs::File; +use std::io::BufWriter; +use std::path::Path; +use std::sync::OnceLock; + +pub use brother_ql::Bitmap; +use brother_ql::{ConvertOptions, DEFAULT_TIMEOUT, LABEL_23X23, QL_820NWB}; +pub use text::{LabelFont, TextLayout}; + +/// Printable area of the 23x23 label in dots (width, height). +pub const DOTS: (u32, u32) = (202, 202); +/// Height of the bottom strip holding the ID text. +pub const TEXT_HEIGHT: u32 = 52; +/// brother_ql model identifier of the label printer. +pub const MODEL: &str = "QL-820NWB"; +/// brother_ql label identifier (DK-11221). +pub const LABEL_ID: &str = "23x23"; +/// Labels printed per lamp by default (one for the box, one for the lamp). +pub const DEFAULT_COPIES: u32 = 2; + +/// Errors of this crate. +#[derive(Debug)] +#[non_exhaustive] +pub enum Error { + /// Conversion or sending failed. + Printer(brother_ql::Error), + /// The ID is too long for a version 40 QR code. + QrDataTooLong(usize), + /// A font file could not be parsed. + Font(String), + /// File I/O failed. + Io(std::io::Error), + /// PNG encoding failed. + Png(png::EncodingError), +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Error::Printer(e) => write!(f, "label printer: {e}"), + Error::QrDataTooLong(n) => write!(f, "lamp ID of {n} bytes does not fit in a QR code"), + Error::Font(e) => write!(f, "font: {e}"), + Error::Io(e) => write!(f, "I/O: {e}"), + Error::Png(e) => write!(f, "PNG: {e}"), + } + } +} + +impl std::error::Error for Error { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + Error::Printer(e) => Some(e), + Error::Io(e) => Some(e), + Error::Png(e) => Some(e), + _ => None, + } + } +} + +impl From for Error { + fn from(e: brother_ql::Error) -> Self { + Error::Printer(e) + } +} + +impl From for Error { + fn from(e: std::io::Error) -> Self { + Error::Io(e) + } +} + +impl From for Error { + fn from(e: png::EncodingError) -> Self { + Error::Png(e) + } +} + +/// The font used by [`render_label`]: [`LabelFont::system`], loaded once. +pub fn default_font() -> &'static LabelFont { + static FONT: OnceLock = OnceLock::new(); + FONT.get_or_init(LabelFont::system) +} + +/// Renders the 202x202 1-bit label for `lamp_id` with the default font. +/// +/// QR code of the upper-cased ID (level M, quiet zone 2, module size +/// `max(1, 150 // (modules + 4))`) centred in the top 150 dots; the ID as +/// given, in the largest font size from 44 down (step 2) whose text box is at +/// most 194 dots wide, centred in the bottom 52 dots. +/// +/// # Panics +/// If the ID is too long for any QR version (thousands of characters); use +/// [`try_render_label`] to get an error instead. +pub fn render_label(lamp_id: &str) -> Bitmap { + try_render_label(lamp_id).expect("lamp ID too long for a QR code") +} + +/// Like [`render_label`] but returns an error for IDs that do not fit a QR code. +pub fn try_render_label(lamp_id: &str) -> Result { + render_label_with_font(lamp_id, default_font()).map(|(b, _)| b) +} + +/// Renders the label with a specific font, also returning the text layout. +pub fn render_label_with_font( + lamp_id: &str, + font: &LabelFont, +) -> Result<(Bitmap, TextLayout), Error> { + let (w, h) = DOTS; + let mut image = Bitmap::new(w, h); + + let upper = lamp_id.to_uppercase(); + let qr = qr::encode(&upper).map_err(|_| Error::QrDataTooLong(upper.len()))?; + let border = 2; + let modules = qr.size as u32 + 2 * border; + let qr_size = h - TEXT_HEIGHT; + let box_size = (qr_size / modules).max(1); + let img_size = modules * box_size; + let x0 = (i64::from(w) - i64::from(img_size)).div_euclid(2); + let y0 = (i64::from(qr_size) - i64::from(img_size)).div_euclid(2); + // the QR image (white quiet zone included) is pasted over the white label + image.fill_rect(x0, y0, img_size, img_size, false); + for r in 0..qr.size { + for c in 0..qr.size { + if qr.get(c, r) { + image.fill_rect( + x0 + i64::from((c as u32 + border) * box_size), + y0 + i64::from((r as u32 + border) * box_size), + box_size, + box_size, + true, + ); + } + } + } + + let layout = text::draw_text( + &mut image, + font, + lamp_id, + (h - TEXT_HEIGHT) as i32, + TEXT_HEIGHT as i32, + ); + Ok((image, layout)) +} + +/// The raster instructions `print_labels` sends: `copies` labels for the +/// QL-820NWB on 23x23 labels with cutting enabled (Python: +/// `convert(BrotherQLRaster('QL-820NWB'), [image] * copies, '23x23', cut=True)`). +pub fn label_instructions(lamp_id: &str, copies: u32) -> Result, Error> { + let image = try_render_label(lamp_id)?; + let images = vec![image; copies as usize]; + let opts = ConvertOptions { + cut: true, + ..ConvertOptions::default() + }; + Ok(brother_ql::convert( + &QL_820NWB, + &LABEL_23X23, + &images, + &opts, + )?) +} + +/// Renders and prints `copies` labels on the QL-820NWB at `printer` +/// (`tcp://host[:port]` or `host`, port 9100 by default). Returns once the +/// job is written to the printer's socket; like the Python version it does +/// not wait for a print confirmation (the network backend has no read-back). +pub fn print_labels(lamp_id: &str, printer: &str, copies: u32) -> Result<(), Error> { + let data = label_instructions(lamp_id, copies)?; + brother_ql::send_network(printer, &data, true, DEFAULT_TIMEOUT)?; + Ok(()) +} + +/// Writes a bitmap as a 1-bit grayscale PNG (white = 1, like PIL mode "1"). +pub fn save_png(bitmap: &Bitmap, path: &Path) -> Result<(), Error> { + let file = BufWriter::new(File::create(path)?); + let mut enc = png::Encoder::new(file, bitmap.width(), bitmap.height()); + enc.set_color(png::ColorType::Grayscale); + enc.set_depth(png::BitDepth::One); + let mut writer = enc.write_header()?; + let stride = bitmap.width().div_ceil(8) as usize; + let mut data = vec![0u8; stride * bitmap.height() as usize]; + for y in 0..bitmap.height() { + for (x, &black) in bitmap.row(y).iter().enumerate() { + if !black { + data[y as usize * stride + x / 8] |= 0x80 >> (x % 8); + } + } + } + writer.write_image_data(&data)?; + writer.finish()?; + Ok(()) +} diff --git a/crates/lamp-label/src/qr.rs b/crates/lamp-label/src/qr.rs new file mode 100644 index 0000000..e8e64ea --- /dev/null +++ b/crates/lamp-label/src/qr.rs @@ -0,0 +1,379 @@ +//! QR encoding that reproduces Python `qrcode` 8.2 exactly. +//! +//! The `qrcode` crate supplies bit packing, Reed-Solomon codewords, module +//! placement and masking. Two decisions are made here the Python way so the +//! module matrices are identical: +//! +//! * **segmentation**: `qrcode.util.optimal_data_chunks(data, minimum=20)` +//! (`QRCode.add_data` default `optimize=20`), not the crate's optimiser; +//! * **mask choice**: `QRCode.best_mask_pattern`, i.e. `util.lost_point` +//! evaluated on matrices whose format/version information is all light +//! ("test" mode), first minimum wins. + +use qrcode::bits::Bits; +use qrcode::canvas::{Canvas, MaskPattern}; +use qrcode::ec::construct_codewords; +use qrcode::{Color, EcLevel, Version}; + +/// QR data segment mode. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Mode { + /// Digits only. + Numeric, + /// `0-9 A-Z $%*+-./:` and space. + Alphanumeric, + /// 8-bit bytes (UTF-8 of the input). + Byte, +} + +/// A data segment with its mode. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct Segment<'a> { + /// Encoding mode. + pub mode: Mode, + /// The bytes of this segment. + pub data: &'a [u8], +} + +const ALPHA_NUM: &[u8] = b"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:"; + +fn is_digit(b: u8) -> bool { + b.is_ascii_digit() +} + +fn is_alnum(b: u8) -> bool { + ALPHA_NUM.contains(&b) +} + +/// One `re.search` step of `_optimal_split`: the first match `(start, end)`. +fn search( + data: &[u8], + class: fn(u8) -> bool, + whole: bool, + minimum: usize, +) -> Option<(usize, usize)> { + if whole { + // ^X+$ ; `$` also matches right before a single trailing newline + let all = |s: &[u8]| !s.is_empty() && s.iter().all(|&b| class(b)); + if all(data) { + return Some((0, data.len())); + } + return match data.strip_suffix(b"\n") { + Some(body) if all(body) => Some((0, body.len())), + _ => None, + }; + } + // X{minimum,}: leftmost start of a run of at least `minimum`, greedy + let mut i = 0; + while i < data.len() { + if class(data[i]) { + let start = i; + while i < data.len() && class(data[i]) { + i += 1; + } + if i - start >= minimum { + return Some((start, i)); + } + } else { + i += 1; + } + } + None +} + +/// `_optimal_split`: alternating (matched, chunk) pieces. +fn optimal_split( + mut data: &[u8], + class: fn(u8) -> bool, + whole: bool, + minimum: usize, +) -> Vec<(bool, &[u8])> { + let mut out = Vec::new(); + while !data.is_empty() { + let Some((start, end)) = search(data, class, whole, minimum) else { + break; + }; + if start > 0 { + out.push((false, &data[..start])); + } + out.push((true, &data[start..end])); + data = &data[end..]; + } + if !data.is_empty() { + out.push((false, data)); + } + out +} + +/// Port of `qrcode.util.optimal_data_chunks(data, minimum)`. +pub fn optimal_segments(data: &[u8], minimum: usize) -> Vec> { + let whole = data.len() <= minimum; + let mut out = Vec::new(); + for (is_num, chunk) in optimal_split(data, is_digit, whole, minimum) { + if is_num { + out.push(Segment { + mode: Mode::Numeric, + data: chunk, + }); + } else { + for (is_alpha, sub) in optimal_split(chunk, is_alnum, whole, minimum) { + out.push(Segment { + mode: if is_alpha { + Mode::Alphanumeric + } else { + Mode::Byte + }, + data: sub, + }); + } + } + } + out +} + +/// A QR symbol: modules without quiet zone, `true` = dark. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct QrMatrix { + /// QR version (1-40). + pub version: u8, + /// Mask pattern number (0-7) chosen like Python qrcode. + pub mask: u8, + /// Modules per side (`4 * version + 17`). + pub size: usize, + /// Row-major modules, `true` = dark. + pub modules: Vec, +} + +impl QrMatrix { + /// Module at column `x`, row `y`. + pub fn get(&self, x: usize, y: usize) -> bool { + self.modules[y * self.size + x] + } +} + +/// The input does not fit in a version 40 QR code at level M. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct DataTooLong; + +const PATTERNS: [MaskPattern; 8] = [ + MaskPattern::Checkerboard, + MaskPattern::HorizontalLines, + MaskPattern::VerticalLines, + MaskPattern::DiagonalLines, + MaskPattern::LargeCheckerboard, + MaskPattern::Fields, + MaskPattern::Diamonds, + MaskPattern::Meadow, +]; + +fn build_bits(segments: &[Segment<'_>], version: i16) -> Option { + let mut bits = Bits::new(Version::Normal(version)); + for s in segments { + let r = match s.mode { + Mode::Numeric => bits.push_numeric_data(s.data), + Mode::Alphanumeric => bits.push_alphanumeric_data(s.data), + Mode::Byte => bits.push_byte_data(s.data), + }; + r.ok()?; + } + bits.push_terminator(EcLevel::M).ok()?; + Some(bits) +} + +/// Encodes `data` exactly like +/// `qrcode.QRCode(error_correction=ERROR_CORRECT_M); add_data(data); make(fit=True)`. +pub fn encode(data: &str) -> Result { + let segments = optimal_segments(data.as_bytes(), 20); + let (version, bits) = (1..=40) + .find_map(|v| build_bits(&segments, v).map(|b| (v, b))) + .ok_or(DataTooLong)?; + let qr_version = Version::Normal(version); + let raw = bits.into_bytes(); + let (codewords, ec) = + construct_codewords(&raw, qr_version, EcLevel::M).map_err(|_| DataTooLong)?; + let mut canvas = Canvas::new(qr_version, EcLevel::M); + canvas.draw_all_functional_patterns(); + canvas.draw_data(&codewords, &ec); + + let n = qr_version.width() as usize; + let mut best = 0usize; + let mut best_lost = 0u64; + for (i, &p) in PATTERNS.iter().enumerate() { + let mut c = canvas.clone(); + c.apply_mask(p); + let mut m = to_bools(c, n); + clear_type_info(&mut m, n, version); + let lost = lost_point(&m, n); + if i == 0 || best_lost > lost { + best_lost = lost; + best = i; + } + } + canvas.apply_mask(PATTERNS[best]); + Ok(QrMatrix { + version: version as u8, + mask: best as u8, + size: n, + modules: to_bools(canvas, n), + }) +} + +fn to_bools(c: Canvas, n: usize) -> Vec { + let v: Vec = c + .into_colors() + .into_iter() + .map(|c| c == Color::Dark) + .collect(); + debug_assert_eq!(v.len(), n * n); + v +} + +/// Python evaluates masks with `makeImpl(test=True)`: format information, +/// the dark module and (version >= 7) version information are all light. +fn clear_type_info(m: &mut [bool], n: usize, version: i16) { + let mut clear = |r: usize, c: usize| m[r * n + c] = false; + for i in 0..15 { + // vertical + let r = if i < 6 { + i + } else if i < 8 { + i + 1 + } else { + n - 15 + i + }; + clear(r, 8); + // horizontal + let c = if i < 8 { + n - i - 1 + } else if i < 9 { + 15 - i + } else { + 15 - i - 1 + }; + clear(8, c); + } + clear(n - 8, 8); + if version >= 7 { + for i in 0..18 { + clear(i / 3, i % 3 + n - 11); + clear(i % 3 + n - 11, i / 3); + } + } +} + +/// Port of `qrcode.util.lost_point` (penalty score used for the mask choice). +pub fn lost_point(m: &[bool], n: usize) -> u64 { + let at = |r: usize, c: usize| m[r * n + c]; + let mut lost = 0u64; + + // level 1: runs of >= 5 same-coloured modules in rows and columns + let runs = |get: &dyn Fn(usize, usize) -> bool| { + let mut sum = 0u64; + for a in 0..n { + let mut prev = get(a, 0); + let mut len = 0u64; + for b in 0..n { + let v = get(a, b); + if v == prev { + len += 1; + } else { + if len >= 5 { + sum += len - 2; + } + len = 1; + prev = v; + } + } + if len >= 5 { + sum += len - 2; + } + } + sum + }; + lost += runs(&|r, c| at(r, c)); + lost += runs(&|c, r| at(r, c)); + + // level 2: 2x2 blocks of one colour + for r in 0..n - 1 { + for c in 0..n - 1 { + let v = at(r, c); + if v == at(r, c + 1) && v == at(r + 1, c) && v == at(r + 1, c + 1) { + lost += 3; + } + } + } + + // level 3: 1:1:3:1:1 finder-like patterns with 4 light modules on one side + const P1: [bool; 11] = [ + true, false, true, true, true, false, true, false, false, false, false, + ]; + const P2: [bool; 11] = [ + false, false, false, false, true, false, true, true, true, false, true, + ]; + if n >= 11 { + for a in 0..n { + for b in 0..=n - 11 { + let row_hit = |p: &[bool; 11]| (0..11).all(|k| at(a, b + k) == p[k]); + if row_hit(&P1) || row_hit(&P2) { + lost += 40; + } + let col_hit = |p: &[bool; 11]| (0..11).all(|k| at(b + k, a) == p[k]); + if col_hit(&P1) || col_hit(&P2) { + lost += 40; + } + } + } + } + + // level 4: dark ratio, 10 points per 5 % away from 50 % + let dark = m.iter().filter(|&&d| d).count() as f64; + let percent = dark / (n * n) as f64; + let rating = ((percent * 100.0 - 50.0).abs() / 5.0) as u64; + lost + rating * 10 +} + +#[cfg(test)] +mod tests { + use super::*; + + fn modes(data: &str) -> Vec<(Mode, String)> { + optimal_segments(data.as_bytes(), 20) + .into_iter() + .map(|s| (s.mode, String::from_utf8_lossy(s.data).into_owned())) + .collect() + } + + #[test] + fn segmentation_like_python() { + assert_eq!(modes("L0006"), [(Mode::Alphanumeric, "L0006".into())]); + assert_eq!(modes("12345"), [(Mode::Numeric, "12345".into())]); + assert_eq!(modes("LAMP_7"), [(Mode::Byte, "LAMP_7".into())]); + assert_eq!( + modes("123\n"), + [(Mode::Numeric, "123".into()), (Mode::Byte, "\n".into())] + ); + let long = format!("L{}", "0123456789".repeat(3)); + assert_eq!( + modes(&long), + [ + (Mode::Byte, "L".into()), + (Mode::Numeric, "0123456789".repeat(3)) + ] + ); + let url = "HTTPS://EXAMPLE.COM/LAMP/L0006?X=1"; + assert_eq!( + modes(url), + [ + (Mode::Alphanumeric, "HTTPS://EXAMPLE.COM/LAMP/L0006".into()), + (Mode::Byte, "?X=1".into()) + ] + ); + } + + #[test] + fn version_1_for_lamp_ids() { + let q = encode("L0006").unwrap(); + assert_eq!((q.version, q.size), (1, 21)); + assert!(encode(&"9".repeat(8000)).is_err()); + } +} diff --git a/crates/lamp-label/src/text.rs b/crates/lamp-label/src/text.rs new file mode 100644 index 0000000..2b849db --- /dev/null +++ b/crates/lamp-label/src/text.rs @@ -0,0 +1,523 @@ +//! Text rendering for the label's ID strip, emulating Pillow's +//! `ImageDraw.text` on a mode `"1"` image (FreeType monochrome rendering with +//! raqm layout) as closely as practical with `fontdue`: +//! +//! * **layout** like Pillow + raqm: unhinted advances and kerning rounded to +//! 1/64 px, glyph origins at the pen position rounded to whole pixels +//! (Pillow's `PIXEL()`), text bbox for the `"la"` anchor (left / ascender +//! line) that always includes the pen origin and the advance end, built from +//! pixel-aligned glyph boxes; ascender = `ceil(hhea ascender)` (FreeType); +//! * **glyphs**: outlines are point-sampled at pixel centres (8x +//! supersampled coverage >= 50 %), i.e. 1-bit without anti-aliasing like +//! FreeType's mono renderer. TrueType hinting is approximated vertically +//! only: the cap height is snapped to `round(cap + 0.23 px)` (matches +//! Arial Bold's hints at every size 10-60 px) and overshoots below 0.555 px +//! are flattened. Horizontal stem snapping is not emulated, so stems and +//! bowls can differ by a pixel from Pillow's output. +//! +//! If no font file can be loaded, a built-in 5x7 bitmap font scaled to the +//! requested size is used instead. + +use std::collections::HashMap; +use std::path::{Path, PathBuf}; + +use brother_ql::Bitmap; + +use crate::Error; +use crate::font5x7; + +/// Supersampling factor for outline point sampling. +const SS: f64 = 8.0; +/// Cap-height snapping bias in px (see `TrueType::warp`). +const CAP_BIAS: f64 = 0.23; +/// Overshoots smaller than this (px) are suppressed. +const OVERSHOOT_LIMIT: f64 = 0.555; + +/// Font files tried in order by [`LabelFont::system`] (after `$LAMP_LABEL_FONT` +/// and `%WINDIR%\Fonts`). Mirrors the Python `_font()` preference: +/// Arial Bold, Arial, DejaVu Sans Bold (plus Liberation Sans Bold). +pub const FONT_CANDIDATES: &[&str] = &[ + "C:/Windows/Fonts/arialbd.ttf", + "C:/Windows/Fonts/arial.ttf", + "/usr/share/fonts/truetype/msttcorefonts/Arial_Bold.ttf", + "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", + "/usr/share/fonts/TTF/DejaVuSans-Bold.ttf", + "/usr/share/fonts/dejavu/DejaVuSans-Bold.ttf", + "/usr/share/fonts/dejavu-sans-fonts/DejaVuSans-Bold.ttf", + "/usr/share/fonts/truetype/liberation/LiberationSans-Bold.ttf", + "/usr/share/fonts/truetype/liberation2/LiberationSans-Bold.ttf", + "/usr/share/fonts/liberation/LiberationSans-Bold.ttf", + "/usr/share/fonts/liberation-sans/LiberationSans-Bold.ttf", + "/usr/share/fonts/TTF/LiberationSans-Bold.ttf", +]; + +/// The font used for the ID text: a TrueType file or the built-in bitmap font. +pub struct LabelFont { + kind: Kind, + name: String, +} + +enum Kind { + TrueType(Box), + Builtin, +} + +struct TrueType { + font: fontdue::Font, + upem: f64, + ascender: f64, + /// Cap height (top of 'H') in font units. + cap: Option, + /// Overshoot of 'O' above the cap height / below the baseline, font units. + overshoot_top: f64, + overshoot_bottom: f64, +} + +impl std::fmt::Debug for LabelFont { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("LabelFont") + .field("name", &self.name) + .finish() + } +} + +fn font_paths() -> Vec { + let mut v = Vec::new(); + if let Some(p) = std::env::var_os("LAMP_LABEL_FONT") { + v.push(PathBuf::from(p)); + } + if let Some(w) = std::env::var_os("WINDIR") { + let fonts = Path::new(&w).join("Fonts"); + v.push(fonts.join("arialbd.ttf")); + v.push(fonts.join("arial.ttf")); + } + v.extend(FONT_CANDIDATES.iter().map(PathBuf::from)); + v +} + +impl LabelFont { + /// The first loadable font of `$LAMP_LABEL_FONT`, `%WINDIR%\Fonts\arialbd.ttf`, + /// `arial.ttf` and [`FONT_CANDIDATES`]; the built-in bitmap font if none loads. + pub fn system() -> LabelFont { + font_paths() + .iter() + .find_map(|p| LabelFont::from_file(p).ok()) + .unwrap_or_else(LabelFont::builtin) + } + + /// Loads a TrueType/OpenType font file. + pub fn from_file(path: &Path) -> Result { + let bytes = std::fs::read(path)?; + let name = path.file_name().map_or_else( + || path.display().to_string(), + |n| n.to_string_lossy().into_owned(), + ); + LabelFont::from_bytes(bytes, &name) + } + + /// Parses font data; `name` is only used for reporting. + pub fn from_bytes(bytes: Vec, name: &str) -> Result { + let font = fontdue::Font::from_bytes(bytes, fontdue::FontSettings::default()) + .map_err(|e| Error::Font(format!("{name}: {e}")))?; + let upem = f64::from(font.units_per_em()); + let units = upem as f32; + let ascender = font + .horizontal_line_metrics(units) + .map_or(upem * 0.9, |m| f64::from(m.ascent)); + let top = |c: char| { + font.has_glyph(c).then(|| { + let b = font.metrics(c, units).bounds; + (f64::from(b.ymin), f64::from(b.ymin + b.height)) + }) + }; + let cap = top('H').map(|(_, t)| t).filter(|&t| t > 0.0); + let (overshoot_top, overshoot_bottom) = match (cap, top('O')) { + (Some(cap), Some((b, t))) => ((t - cap).max(0.0), (-b).max(0.0)), + _ => (0.0, 0.0), + }; + Ok(LabelFont { + kind: Kind::TrueType(Box::new(TrueType { + font, + upem, + ascender, + cap, + overshoot_top, + overshoot_bottom, + })), + name: name.to_string(), + }) + } + + /// The built-in 5x7 bitmap font (digits, A-Z, `- _ . : /`). + pub fn builtin() -> LabelFont { + LabelFont { + kind: Kind::Builtin, + name: "builtin-5x7".to_string(), + } + } + + /// File name of the font, or `"builtin-5x7"`. + pub fn name(&self) -> &str { + &self.name + } + + /// `true` for the built-in bitmap font. + pub fn is_builtin(&self) -> bool { + matches!(self.kind, Kind::Builtin) + } +} + +/// Where and how big the ID text is drawn (values as Pillow reports them). +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct TextLayout { + /// Font name (file name or `builtin-5x7`). + pub font: String, + /// Chosen font size in pixels per em. + pub size: u32, + /// `ImageDraw.textbbox((0, 0), text)` at that size: (x0, y0, x1, y1). + pub bbox: (i32, i32, i32, i32), + /// The `xy` passed to `ImageDraw.text` (anchor "la"). + pub origin: (i32, i32), +} + +/// Vertical "hinting": maps unhinted heights (px above baseline) to snapped +/// ones. The cap height is stretched to a whole pixel; overshoots (round +/// glyphs poking up to one pixel past the baseline or cap height) are +/// flattened when the font's overshoot is below [`OVERSHOOT_LIMIT`] at this size. +struct Warp { + k: f64, + cap_u: f64, + cap_s: f64, + suppress_top: bool, + suppress_bottom: bool, +} + +impl Warp { + fn identity() -> Warp { + Warp { + k: 1.0, + cap_u: f64::INFINITY, + cap_s: f64::INFINITY, + suppress_top: false, + suppress_bottom: false, + } + } + + /// Snapped height -> unhinted height (used for sampling pixel centres). + fn inv(&self, h: f64) -> f64 { + if h < 0.0 { + if self.suppress_bottom && h > -1.0 { + h - 1.0 + } else { + h + } + } else if h <= self.cap_s { + h / self.k + } else if self.suppress_top && h < self.cap_s + 1.0 { + h - self.cap_s + self.cap_u + 1.0 + } else { + h - self.cap_s + self.cap_u + } + } + + /// Unhinted height -> snapped height (used for the glyph boxes). + fn fwd(&self, y: f64) -> f64 { + if y < 0.0 { + if self.suppress_bottom && y > -1.0 { + 0.0 + } else { + y + } + } else if y <= self.cap_u { + y * self.k + } else if self.suppress_top && y < self.cap_u + 1.0 { + self.cap_s + } else { + y - self.cap_u + self.cap_s + } + } +} + +/// 1-bit glyph image in pen-relative pixel coordinates. +#[derive(Default, Clone)] +struct GlyphInk { + /// Columns `x0..x1` relative to the integer pen position. + x0: i32, + x1: i32, + /// Height bands `j0..j1` (band `j` covers `[j, j+1]` px above the baseline). + j0: i32, + j1: i32, + /// Row-major, first row is band `j1 - 1`. + ink: Vec, + /// Pixel-aligned outline box (x0, y0, x1, y1), y up from the baseline, + /// like `FT_Glyph_Get_CBox(FT_GLYPH_BBOX_PIXELS)`; `None` for empty glyphs. + cbox: Option<(i32, i32, i32, i32)>, +} + +impl GlyphInk { + fn is_empty(&self) -> bool { + self.x0 >= self.x1 || self.j0 >= self.j1 + } +} + +/// Pillow `PIXEL()`: 26.6 -> whole pixels, rounding half up. +fn pixel(v: i64) -> i32 { + (v + 32).div_euclid(64) as i32 +} + +impl TrueType { + fn to26(&self, units: f64, size: f64) -> i64 { + (units * size * 64.0 / self.upem).round() as i64 + } + + fn warp(&self, size: f64) -> Warp { + let Some(cap) = self.cap else { + return Warp::identity(); + }; + let cap_u = cap * size / self.upem; + // Arial Bold's hints put the cap height at round(cap + 0.23 px) for + // every size from 10 to 60 px (FreeType 2.14 mono); used for all fonts. + let cap_s = (cap_u + CAP_BIAS + 0.5).floor(); + if cap_s <= 0.0 { + return Warp::identity(); + } + // overshoots below ~0.55 px are flattened by the hints (45 px: yes, 46 px: no) + let suppressed = |units: f64| units * size / self.upem < OVERSHOOT_LIMIT; + Warp { + k: cap_s / cap_u, + cap_u, + cap_s, + suppress_top: suppressed(self.overshoot_top), + suppress_bottom: suppressed(self.overshoot_bottom), + } + } + + fn glyph_ink(&self, index: u16, size: f64, warp: &Warp) -> GlyphInk { + let (m, cov) = self.font.rasterize_indexed(index, (size * SS) as f32); + if m.width == 0 || m.height == 0 { + return GlyphInk::default(); + } + let (w, h) = (m.width as i64, m.height as i64); + let (hx0, hy0) = (i64::from(m.xmin), i64::from(m.ymin)); + let inside = |x: f64, y: f64| { + let col = (x * SS).floor() as i64 - hx0; + let row = (hy0 + h - 1) - (y * SS).floor() as i64; + (0..w).contains(&col) && (0..h).contains(&row) && cov[(row * w + col) as usize] >= 128 + }; + let cx0 = (hx0 as f64 / SS).floor() as i32 - 1; + let cx1 = ((hx0 + w) as f64 / SS).ceil() as i32 + 1; + let j0 = warp.fwd(hy0 as f64 / SS).floor() as i32 - 2; + let j1 = warp.fwd((hy0 + h) as f64 / SS).ceil() as i32 + 2; + let mut pts = Vec::new(); + for j in j0..j1 { + let y = warp.inv(f64::from(j) + 0.5); + for c in cx0..cx1 { + if inside(f64::from(c) + 0.5, y) { + pts.push((c, j)); + } + } + } + if pts.is_empty() { + return GlyphInk::default(); + } + let x0 = pts.iter().map(|p| p.0).min().unwrap(); + let x1 = pts.iter().map(|p| p.0).max().unwrap() + 1; + let j0 = pts.iter().map(|p| p.1).min().unwrap(); + let j1 = pts.iter().map(|p| p.1).max().unwrap() + 1; + let width = (x1 - x0) as usize; + let mut ink = vec![false; width * (j1 - j0) as usize]; + for (c, j) in pts { + ink[(j1 - 1 - j) as usize * width + (c - x0) as usize] = true; + } + let b = m.bounds; + let (bx0, by0) = (f64::from(b.xmin) / SS, f64::from(b.ymin) / SS); + let (bx1, by1) = ( + bx0 + f64::from(b.width) / SS, + by0 + f64::from(b.height) / SS, + ); + const EPS: f64 = 1e-3; + let cbox = Some(( + (bx0 + EPS).floor() as i32, + (warp.fwd(by0) + EPS).floor() as i32, + (bx1 - EPS).ceil() as i32, + (warp.fwd(by1) - EPS).ceil() as i32, + )); + GlyphInk { + x0, + x1, + j0, + j1, + ink, + cbox, + } + } +} + +/// A laid-out line of text at one size. +struct Shaped { + /// (pen x in px, glyph ink) + glyphs: Vec<(i32, GlyphInk)>, + bbox: (i32, i32, i32, i32), + ascender: i32, +} + +fn shape_truetype(tt: &TrueType, text: &str, size: u32) -> Shaped { + let s = f64::from(size); + let units = tt.upem as f32; + let warp = tt.warp(s); + let indices: Vec = text + .chars() + .map(|c| tt.font.lookup_glyph_index(c)) + .collect(); + // raqm/HarfBuzz: unhinted advances, pair kerning added to the first glyph + let advances: Vec = indices + .iter() + .enumerate() + .map(|(i, &g)| { + let adv = f64::from(tt.font.metrics_indexed(g, units).advance_width); + let kern = indices + .get(i + 1) + .and_then(|&n| tt.font.horizontal_kern_indexed(g, n, units)) + .map_or(0, |k| tt.to26(f64::from(k), s)); + tt.to26(adv, s) + kern + }) + .collect(); + + let mut cache: HashMap = HashMap::new(); + let (mut x_min, mut x_max, mut y_min, mut y_max) = (0i32, 0i32, 0i32, 0i32); + let mut position = 0i64; + let mut glyphs = Vec::with_capacity(indices.len()); + for (&g, &adv) in indices.iter().zip(&advances) { + let px = pixel(position); + position += adv; + x_max = x_max.max(pixel(position)); + let ink = cache + .entry(g) + .or_insert_with(|| tt.glyph_ink(g, s, &warp)) + .clone(); + if let Some((bx0, by0, bx1, by1)) = ink.cbox { + x_min = x_min.min(px + bx0); + x_max = x_max.max(px + bx1); + y_min = y_min.min(by0); + y_max = y_max.max(by1); + } + glyphs.push((px, ink)); + } + let ascender = (tt.ascender * s / tt.upem - 1e-9).ceil() as i32; // FreeType FT_PIX_CEIL + Shaped { + glyphs, + bbox: (x_min, ascender - y_max, x_max, ascender - y_min), + ascender, + } +} + +/// Integer scale of the 5x7 font for a nominal size (cap height ~0.716 em, like Arial). +fn builtin_scale(size: u32) -> u32 { + let cap = (f64::from(size) * 0.716).round() as u32; + (cap / font5x7::ROWS).max(1) +} + +fn builtin_bbox(text: &str, size: u32) -> (i32, i32, i32, i32) { + let n = text.chars().count() as u32; + let scale = builtin_scale(size); + let w = if n == 0 { + 0 + } else { + (n * font5x7::ADVANCE - (font5x7::ADVANCE - font5x7::COLS)) * scale + }; + (0, 0, w as i32, (font5x7::ROWS * scale) as i32) +} + +/// Runs the Python size loop: 44, 42, ... down to 12, first size whose text +/// bbox width is <= `max_width` (the last tried size if none fits). +fn choose( + font: &LabelFont, + text: &str, + max_width: i32, +) -> (u32, Option, (i32, i32, i32, i32)) { + let mut size = 44; + let mut last = None; + while size > 10 { + let (shaped, bbox) = match &font.kind { + Kind::TrueType(tt) => { + let s = shape_truetype(tt, text, size); + let b = s.bbox; + (Some(s), b) + } + Kind::Builtin => (None, builtin_bbox(text, size)), + }; + let fits = bbox.2 - bbox.0 <= max_width; + last = Some((size, shaped, bbox)); + if fits { + break; + } + size -= 2; + } + last.expect("loop runs at least once") +} + +/// Draws `text` centred in the strip `[strip_top, strip_top + strip_height)` +/// of `image` exactly following the Python placement rules, and returns the +/// layout. +pub(crate) fn draw_text( + image: &mut Bitmap, + font: &LabelFont, + text: &str, + strip_top: i32, + strip_height: i32, +) -> TextLayout { + let width = image.width() as i32; + let (size, shaped, bbox) = choose(font, text, width - 8); + let (bw, bh) = (bbox.2 - bbox.0, bbox.3 - bbox.1); + let origin = ( + (width - bw).div_euclid(2) - bbox.0, + strip_top + (strip_height - bh).div_euclid(2) - bbox.1, + ); + match (&font.kind, shaped) { + (Kind::TrueType(_), Some(shaped)) => { + let baseline = origin.1 + shaped.ascender; + for (px, ink) in &shaped.glyphs { + if ink.is_empty() { + continue; + } + let w = (ink.x1 - ink.x0) as usize; + for (r, row) in ink.ink.chunks(w).enumerate() { + let j = ink.j1 - 1 - r as i32; + let y = baseline - 1 - j; + for (c, &on) in row.iter().enumerate() { + if on { + let x = origin.0 + px + ink.x0 + c as i32; + image.set_clipped(i64::from(x), i64::from(y), true); + } + } + } + } + } + _ => { + let scale = builtin_scale(size) as i32; + for (i, ch) in text.chars().enumerate() { + let rows = font5x7::glyph(ch); + let gx = origin.0 + i as i32 * font5x7::ADVANCE as i32 * scale; + for (r, bits) in rows.iter().enumerate() { + for c in 0..font5x7::COLS as i32 { + if bits & (0x10 >> c) != 0 { + image.fill_rect( + i64::from(gx + c * scale), + i64::from(origin.1 + r as i32 * scale), + scale as u32, + scale as u32, + true, + ); + } + } + } + } + } + } + TextLayout { + font: font.name().to_string(), + size, + bbox, + origin, + } +} diff --git a/crates/lamp-label/tests/golden.rs b/crates/lamp-label/tests/golden.rs new file mode 100644 index 0000000..243b0ca --- /dev/null +++ b/crates/lamp-label/tests/golden.rs @@ -0,0 +1,294 @@ +//! Comparison against Python `render_label` (qrcode 8.2 + Pillow 12.3). +//! +//! Golden data from `tools/golden.py`: +//! * `qr_matrices.txt`: module matrices, versions and masks; +//! * `label_*.png`: complete Python labels; +//! * `text_info.txt`: Pillow's chosen font size, text bbox and draw origin. + +use std::collections::HashMap; +use std::fs::File; +use std::path::{Path, PathBuf}; + +use lamp_label::{Bitmap, LabelFont, TEXT_HEIGHT, qr, render_label, render_label_with_font}; + +fn golden() -> PathBuf { + Path::new(env!("CARGO_MANIFEST_DIR")) + .join("tests") + .join("golden") +} + +fn load_png(path: &Path) -> Bitmap { + let mut decoder = png::Decoder::new(File::open(path).unwrap()); + decoder.set_transformations(png::Transformations::EXPAND | png::Transformations::STRIP_16); + let mut reader = decoder.read_info().unwrap(); + let mut buf = vec![0; reader.output_buffer_size()]; + let info = reader.next_frame(&mut buf).unwrap(); + let channels = info.color_type.samples(); + Bitmap::from_fn(info.width, info.height, |x, y| { + buf[y as usize * info.line_size + x as usize * channels] < 128 + }) +} + +/// id -> label png file name +fn label_files() -> HashMap { + std::fs::read_to_string(golden().join("labels.txt")) + .unwrap() + .lines() + .filter(|l| !l.is_empty()) + .map(|l| { + let (id, file) = l.split_once('\t').unwrap(); + (id.to_string(), file.to_string()) + }) + .collect() +} + +struct GoldenQr { + id: String, + version: u8, + mask: u8, + modules: Vec>, +} + +fn golden_qr() -> Vec { + let text = std::fs::read_to_string(golden().join("qr_matrices.txt")).unwrap(); + let mut lines = text.lines(); + let mut out = Vec::new(); + while let Some(header) = lines.next() { + if header.is_empty() { + continue; + } + let mut parts = header.rsplitn(4, ' '); + let size: usize = parts + .next() + .unwrap() + .strip_prefix("size=") + .unwrap() + .parse() + .unwrap(); + let mask: u8 = parts + .next() + .unwrap() + .strip_prefix("mask=") + .unwrap() + .parse() + .unwrap(); + let version: u8 = parts + .next() + .unwrap() + .strip_prefix("version=") + .unwrap() + .parse() + .unwrap(); + let id = parts.next().unwrap().to_string(); + let modules = (0..size) + .map(|_| lines.next().unwrap().bytes().map(|b| b == b'1').collect()) + .collect(); + out.push(GoldenQr { + id, + version, + mask, + modules, + }); + } + out +} + +#[test] +fn qr_matrices_match_python() { + let cases = golden_qr(); + assert!(cases.len() >= 28, "golden data missing"); + let mut failures = Vec::new(); + for g in &cases { + let q = qr::encode(&g.id.to_uppercase()).unwrap(); + let same_modules = (0..q.size).all(|r| (0..q.size).all(|c| q.get(c, r) == g.modules[r][c])); + if q.version != g.version || q.mask != g.mask || q.size != g.modules.len() || !same_modules + { + failures.push(format!( + "{}: rust v{} mask {} vs python v{} mask {} (modules equal: {same_modules})", + g.id, q.version, q.mask, g.version, g.mask + )); + } + } + println!( + "QR: {}/{} matrices identical (version, mask and modules)", + cases.len() - failures.len(), + cases.len() + ); + assert!(failures.is_empty(), "{}", failures.join("\n")); +} + +#[test] +fn qr_region_of_label_matches_python() { + let files = label_files(); + let qr_rows = 202 - TEXT_HEIGHT; + let mut checked = 0; + for g in golden_qr() { + let py = load_png(&golden().join(&files[&g.id])); + let rs = render_label(&g.id); + let diff = (0..qr_rows) + .flat_map(|y| (0..202).map(move |x| (x, y))) + .filter(|&(x, y)| py.get(x, y) != rs.get(x, y)) + .count(); + assert_eq!(diff, 0, "{}: {diff} pixels differ in the QR area", g.id); + checked += 1; + } + println!("QR area (rows 0..150) pixel-identical for {checked} labels"); +} + +struct TextGolden { + id: String, + font: String, + size: u32, + bbox: (i32, i32, i32, i32), + origin: (i32, i32), +} + +fn text_golden() -> Vec { + let text = std::fs::read_to_string(golden().join("text_info.txt")).unwrap(); + text.lines() + .filter(|l| !l.is_empty()) + .map(|l| { + let mut f = l.split('\t'); + let id = f.next().unwrap().to_string(); + let mut kv = HashMap::new(); + for p in f { + let (k, v) = p.split_once('=').unwrap(); + kv.insert(k, v); + } + let nums = |s: &str| { + s.split(',') + .map(|n| n.parse::().unwrap()) + .collect::>() + }; + let b = nums(kv["bbox"]); + let o = nums(kv["origin"]); + TextGolden { + id, + font: kv["font"].to_string(), + size: kv["size"].parse().unwrap(), + bbox: (b[0], b[1], b[2], b[3]), + origin: (o[0], o[1]), + } + }) + .collect() +} + +#[test] +fn text_strip_close_to_python_with_arial_bold() { + let arial = Path::new("C:/Windows/Fonts/arialbd.ttf"); + if !arial.exists() { + eprintln!("arialbd.ttf not available, skipping the text comparison"); + return; + } + let font = LabelFont::from_file(arial).unwrap(); + let files = label_files(); + let top = 202 - TEXT_HEIGHT; + let mut report = Vec::new(); + let mut layout_mismatch = Vec::new(); + let mut too_different = Vec::new(); + for g in text_golden() { + assert_eq!(g.font, "arialbd.ttf"); + let (rs, layout) = render_label_with_font(&g.id, &font).unwrap(); + let py = load_png(&golden().join(&files[&g.id])); + let (mut diff, mut ink_py, mut ink_rs) = (0, 0, 0); + for y in top..202 { + for x in 0..202 { + let (p, r) = (py.get(x, y), rs.get(x, y)); + ink_py += usize::from(p); + ink_rs += usize::from(r); + diff += usize::from(p != r); + } + } + report.push(format!( + "{:<16} size py {:>2} rs {:>2} | bbox py {:?} rs {:?} | origin py {:?} rs {:?} | ink py {:>4} rs {:>4} | differing px {:>4} ({:.1} % of ink)", + g.id, + g.size, + layout.size, + g.bbox, + layout.bbox, + g.origin, + layout.origin, + ink_py, + ink_rs, + diff, + 100.0 * diff as f64 / ink_py.max(1) as f64 + )); + if (layout.size, layout.bbox, layout.origin) != (g.size, g.bbox, g.origin) { + layout_mismatch.push(g.id.clone()); + } + // glyph rasterisation may differ (no TrueType hinting), but the text + // must be essentially the same pixels + if diff * 4 >= ink_py { + too_different.push(format!( + "{}: {diff} differing pixels for {ink_py} ink pixels", + g.id + )); + } + } + println!("text strip vs Python (arialbd.ttf):\n{}", report.join("\n")); + assert!(too_different.is_empty(), "{}", too_different.join("\n")); + // chosen size, text bbox and draw origin must be exactly Pillow's + assert!( + layout_mismatch.is_empty(), + "size/bbox/origin differ for {layout_mismatch:?}" + ); +} + +#[test] +fn builtin_font_fallback_renders() { + let font = LabelFont::builtin(); + let (img, layout) = render_label_with_font("L0006", &font).unwrap(); + assert_eq!(layout.font, "builtin-5x7"); + assert_eq!(layout.size, 44); + // 5 glyphs of 5x7 cells at scale 4: 116 x 28, centred in the strip + assert_eq!(layout.bbox, (0, 0, 116, 28)); + assert_eq!(layout.origin, (43, 162)); + let ink: usize = (150..202) + .flat_map(|y| (0..202).map(move |x| (x, y))) + .filter(|&(x, y)| img.get(x, y)) + .count(); + assert!(ink > 500, "text missing ({ink} px)"); + // long IDs shrink + let (_, layout) = render_label_with_font("L0123456789012345", &font).unwrap(); + assert!(layout.size < 44 && layout.bbox.2 <= 194, "{layout:?}"); + // same QR as with the TrueType font + let (img2, _) = render_label_with_font("L0006", &LabelFont::system()).unwrap(); + assert!((0..150).all(|y| (0..202).all(|x| img.get(x, y) == img2.get(x, y)))); +} + +#[test] +fn png_roundtrip_and_preview() { + let label = render_label("L0006"); + let dir = PathBuf::from(env!("CARGO_TARGET_TMPDIR")); + let path = dir.join("lamp_label_L0006.png"); + lamp_label::save_png(&label, &path).unwrap(); + assert_eq!(load_png(&path), label); + println!("preview written to {}", path.display()); +} + +#[test] +fn instructions_for_two_labels() { + let data = lamp_label::label_instructions("L0006", 2).unwrap(); + // Python output for the Python-rendered L0006 label (brother-ql golden data): + // same length and identical command bytes; only raster lines carrying + // text pixels may differ. + let py = std::fs::read( + Path::new(env!("CARGO_MANIFEST_DIR")).join("../brother-ql/tests/golden/label_L0006_x2.bin"), + ) + .unwrap(); + assert_eq!(data.len(), py.len()); + // preamble 4 + 400 + 2 + 4, page header 3 + 13 + 4 + 4 + 4 + 5, 202 lines of 93, 0x1A + let (pre, head, lines) = (410, 33, 202 * 93); + let page = head + lines + 1; + assert_eq!(data.len(), pre + 2 * page); + assert_eq!(data[..pre + head], py[..pre + head]); + for p in 0..2 { + let start = pre + p * page; + assert_eq!(data[start..start + head], py[start..start + head]); + assert_eq!(data[start + page - 1], 0x1A); + for l in 0..202 { + let row = start + head + l * 93; + assert_eq!(data[row..row + 3], [0x67, 0x00, 90]); + } + } +} diff --git a/crates/lamp-label/tests/golden/label_12345678.png b/crates/lamp-label/tests/golden/label_12345678.png new file mode 100644 index 0000000000000000000000000000000000000000..97793a110316b119453013f2085caf1fdd2e6441 GIT binary patch literal 747 zcmV{iMcd)W)jI>GY|3f}Xd<#i3F}95nk15eff_ z#;>4Gb=$Rh)bqD{T^h<{E&f7t{T(!#)mZ&;uS-FVcrxGRs-&dIaA%BZ$9FD(F(yxn zA@XFtiHCYNmlDHJ&Ylf4p>z|^#2C6zO6JjrxD^v(n4jvh3%e$JtU`H;I7w*;nQlU- z>iOx4Nk+rPTnD;S*`#&rr~DYz5}HJSr5xSzHWsnMmF)WkX>V+JY%C zdM~RLz{h#OKGyeIh#vapY{`}u-ol^^bV6NzgbaKDeCuJXwe46fhK)jRfI*uKge}wM zwa*p0nMSUyP8tXUp*FTqNIQ7Qc!*OCfdSg;6o~qkBl+Q|iX5S(U7q~qEMhGz?WC9J zA}7c~?+O-0Ycq>y7D`{rpppvXYx34&XQAeG7GEc(MNLnrni&dLT0XAoXSPkn=Q!|$ znKNjpRYo{W-`yGHby;fX{}4=2Kkt*A-VV`8-ks)J*W%yHx*wbg&O$z{XGjOHb%_0% z(XxU4*~V@sB4Cx@Lfa!`wUbrW3tDY4D*LHd6&GW#sG~0?e@%9!&gSlxo9NoR+t;xC dqx~YJd;`OoQ?7{er0oCz002ovPDHLkV1ki#W6J;l literal 0 HcmV?d00001 diff --git a/crates/lamp-label/tests/golden/label_L0001.png b/crates/lamp-label/tests/golden/label_L0001.png new file mode 100644 index 0000000000000000000000000000000000000000..ee365634b142750c5471ea0fbe7e420f22736e40 GIT binary patch literal 516 zcmV+f0{i`mP)vY&xL@O*D&9#}jp_gg{>< zf4=SS0wrujueT7mK`S*zl>!)TpYH4oT@HP9s1XqlJs=|St7v=%^^gv$p z=V^YgFxEGOoCL-nUIIp>M1}{YR15uRQA$-sF+}DF?(9K)Nep8nCJ-AB&XmSbr;B-0 z;3l`>(0&z-&opETXT;O^Y~aOc$i&b|a5R}}rdJw632A;~<4tlKUlv21uT9!4K!o4w z{bVU`9f}Bzj}VJmhkEX9M%(A5kA zMO{(rOQ*TUYOMNL8E24Ur`XZWe>moP?@~U_Hhpt!&f*U!cM?^JPusZw0000=G`P)F>r@T_ZqOndM-s!q0iCSu1buDl>X2b(5Ay_ond48<_zvnMZ-+;+lFxsR zx<1s!>pkm2NM96n6{z8W+9SpDbt_n!HT@piZlITWO(k33pCjn<)5<_N=hGD$uVWL+MLnW6Z(P~dsz$&DQ z{}7Fg@o3R72S~-st8)BUAr(3n#ZXPN&5@imOK8ecY@F&VEzDA4>FBbmtfuABHdTN& zMefVVs&Lu^KW4D9s?5w%Wf-nP6HD#oC^MK8x-7+}+iCR73Mq>E|Dk7*3yAMq?A<)d zIq~fl+duEWq^@{k9IVCENV#3)ouyR?JKCuL+vFuWR-=6{B9oeH|*;y z6l@mSZL*Mei*vO~PH1@+WqoUXTkkx7^ASU3p+V1~`bF0-T8C%6(mBLL_zUsFn2ae( zqt>X^8RZdDunLw?_X~)yA#BjTXX(=``$qiNB-1y=#+khV&)g9E*RVJ%=P);&>Z2Vl&Ba+?@-l?~X|YCs6WQ1C+P z`AMRfC`QIQokM^-v{K`&#LixnlaVh^D96kJePaP;rmv!L3+g7_PG0o~(0O zx9(rgrT-K?@1#sd z>4G*KrjMb#-Ua~m(&3cb+d%4}$QsM-ZQ%Ci_?#NW5_=nVJAgjhlT^k&cwp@ zA<`*M`;en_IOKvU>MYyz?9)N^u*67(@v~{@Jf!ZwMrT&YqUir0dXe%A@nZ|FmQhV3 z{`$JEhl~T`fYxDL&NU*Ah>T%PgD?<=5hPvPVy{>K#Z&z2{D9`^00000NkvXXu0mjf>5~dk literal 0 HcmV?d00001 diff --git a/crates/lamp-label/tests/golden/label_L0005.png b/crates/lamp-label/tests/golden/label_L0005.png new file mode 100644 index 0000000000000000000000000000000000000000..0fd6c4ed0fcb8d8426afb0ded17e4dbc0a2d3724 GIT binary patch literal 584 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 literal 0 HcmV?d00001 diff --git a/crates/lamp-label/tests/golden/label_L0015.png b/crates/lamp-label/tests/golden/label_L0015.png new file mode 100644 index 0000000000000000000000000000000000000000..1c442007d24182098b73338cb3da5fc8d9b90d02 GIT binary patch literal 567 zcmV-70?7S|P)t7F!5#gD%(zBoc^7w=&W*l$PS^P|eJ?WM&6u_W#O_x1d&d>kMh( z^N+2r4FwHK7aOc%rVy4afldS2QN#ekz4t2SWM^RgCwA;tpf7e^$_`T z%}8U(7IobI^5GC;NT*n%=8|n*QO3zPND>N%K#psU6-w8Jhp(#6$wRvRjV>gUpcMZ<^hL@q zM8ghLtgVa@UHsCWA;y7mh=VmWzzuNd6ILF*M~|^Qt>(IqdPqS1qwgO*42HWQ`CS1( zmHuR(D(22SIrDTj`Q2&|)$m7?d?7vo{f{J6?#0<8q!zwh2Bnut(-7**ooJHk!^bVF zJImV%V74LrC8!v$j{7yF?Ot2C`|`#MZMy~O3#;l`RnL)|@B1ahMED6&p!&5=Y=ufq z;a~R~1#}VTIXy5#gdJfgfj&7h2gNp`GWa$=Wh&xdB?tL2`xcvh?I6xk7FrPGTk}katX#M5kIX*yiJMvM^fs zl?n?z8a-OAR+j}~1$DN@0C#HUjUX677@+2!K2pobZcZs8vQRc?5Ru#aYG{%B7jH zgGNk)wLh4k`+c2^53}JnC*qB)UbdC71Y)>jw()@H1Wq=oRsLdgS9wKJQNN=%k+A}b z$6S?@jjpqtb|@tuf<|~$P?VFUq!dcNgn0FUmjc=iIVZ*1=0&0c>fv-wDh?HwUY@1e zoNrTF5Ao!Z(_KRJTHEtGgQQ!8V*dEi&m4-9n-KxhbYaQAUy)xmXeXfej@NO`m# zEgU+2>G@orV{3qisa5;r+b0hL|EXL2t`K!BQXWA0VItm{XJ?*K0QfPp>bPmNGw}ny zy?16*z5@T+VV;j z7hc$0n5&*p#ad@M-Q@_wB5<%lQi84y{-*K z3v;b^eGSqw<8_d| z%wue?Ymt&3mhb=M8E6uD98}QvVz+9zvlE(LawT za#>l%yo=e(Qf&NK5)0ZXCfQ#4YLc-t3^N9?yxs=MrsJ<9hSeSV52Nuz$}dFYzMn6a zi&xu@cgjtCes5Mdw;SY5!DcYRALQ=Zcp9%*b~TafvV|AmRFKg?q5%h+^}Q)Z;pWa&D3vZo!t>)rSKD?Q^EY;Wl$SQe`dl8wpyou r1u5*+oWyyaS-cZniMoG3#3H`{xAPDmZFt#A00000NkvXXu0mjfcUu9O literal 0 HcmV?d00001 diff --git a/crates/lamp-label/tests/golden/label_L0018.png b/crates/lamp-label/tests/golden/label_L0018.png new file mode 100644 index 0000000000000000000000000000000000000000..0373ebb0e7174402eee4a4711472103e169444ff GIT binary patch literal 573 zcmV-D0>b@?P)Vx71=QA44IuaKt-*G-Cb428$JxO4gro*Q&v7iQiw{&iaBUmjpG%QmqHd* zVZ8g~*vW6FjG%NuYYv>1LL*h5Y68e8xTtK*G`F$AphBx8=y~Qg?G|>YBl-;U!x44| zRDYaY(0MA4asc;t?%zbUOqG@xs8J%Mr^JiqgbcZ?Qir1nFOWy|EZ@j z*=vA)gT~LTyq7|N|2d-=d&WLBx*0Vf4v6S5h~-}tp(At{H~(y`FRAQ7c9>D!J$3g4 z54d`9Uj6!%>1>+=i2fn^2b7CegA}*gAs%7k(;}s76s=jL44@9&Lef8%MkV!EXIT4QMgj00000 LNkvXXu0mjfV?zS8 literal 0 HcmV?d00001 diff --git a/crates/lamp-label/tests/golden/label_L0019.png b/crates/lamp-label/tests/golden/label_L0019.png new file mode 100644 index 0000000000000000000000000000000000000000..1d64fd8bfaec76e4e2d8f72131a9b1c3c8b6a3e9 GIT binary patch literal 574 zcmV-E0>S->P)NA%>=e08eP8#zYd6g~lK~yFmG9?hYAdc0$#HnZu)K{0?eDv z>+0M_U2M?oA4($|Jm(iuBkbiU22)*@VH`7`?4S)Vu2_?X!7z-A(z$3mHED>Yc!O~; ztXTA{jbVtrfG!pbUp%KShDI0#8FnACx(e?$#=-2B7khjVja=wt+?{l%e5DN4x6h2B z^OlUSh#{79$R6U@#?|FEIzEqbuMQSEF#PZU8ci9Z=hx^>RFahD|A*ehej#nzV%W`C zEY3YMqmwpn7@MSE83)E8c6_qd8U7595oe4E6fg#ikW1U@EBjMy2f(D{$Cog^1oVLY zn%&m~jNAN{gFO1gDt-Uz`&YDCq0Z9eCB%6Rzhq}gs9h1#01mE{l-BQx`8wwR5I5Ud zLroc?l^RRT1amaHGK4kMTt}2Z*6pm5&2k}M0DfF~WY+TOtoB{E@3Iv=zTHAhgzu0B z;FMm!HCi3hzZR;2ZDRUyJs%$sVM`F+H2>g+p>xutBSrCaZ2THO0T?zL?c?~|kpKVy M07*qoM6N<$g5$ahkN^Mx literal 0 HcmV?d00001 diff --git a/crates/lamp-label/tests/golden/label_L0020.png b/crates/lamp-label/tests/golden/label_L0020.png new file mode 100644 index 0000000000000000000000000000000000000000..bf93c83624bc26c68dd4c9cf9b33440f42c23dc1 GIT binary patch literal 573 zcmV-D0>b@?P)>fqqPf$-91sk^F&zr3t z0C|1Cv2KORbJc&dRNrQ$?hiF=QP{q)D426(xFe$0YwR_MsLYBX_$;;=HP~cz9_rrf z9_YQ6V9C;lrm#)HEal0QCMSjtjRRcGF;a}Hb7H8ZC@f~SnQh7I#?$gqG!nuwMucP` zs~m5Z{8srOP8vcluT{p8o7AjqMOWwOLl@sREKw|FeClMwP@Ug4{-E(TWUH`;- zef$z{xD|82JYdc!_z=pYNC~h3mI1~v>CjI^ugXTPE0#SJeG)zax7 zSLfw)`%h`0ZC`EsS^~qOy|4;EC^jgUF2U1T0sv0#UI8HVL^zl=#IWRGcpZKBjdasx6Sj!#z=kvzIsCR+k( z^TSb>hLmRwFEiJ_L9Idf`>6j8Wy7T)REi)p6roL!;eq#FxO)zFU{9ySP@Gk4p?#Va zyEPcfU^v*;^m(0*hLQ*6IgynI^y3w2Y#5zNv?52I(>ZVfCzqCn1vIq=nI=VU%(7mInZzPgoDCfORm7xGC8j50yy^V!_Y}VU+p)3%5bp;yoqrJ`ClIm^Z zCO7Wm23=dIC*DE8(c;D8rCdf?iw4+#$9_ND82cE2Q1hi!D0hpf4jvxF&n%D90S#(& z=(;t-&wvAVz^+?B&DTIBkUxZc#SnM{g0Yy6opY$^$C2L*^0tKO*HW*eI^09mqc%$o z-MIKQwBw<|Tcp#=d!^9i+aJZmA(Fsr9O^QbGYSPjFEt#EIYcyM^9I}^#Gv~Afy+RcyT5ZyTBQcAsi%-T(jq07*qoM6N<$f+|-Y A`~Uy| literal 0 HcmV?d00001 diff --git a/crates/lamp-label/tests/golden/label_L0123456789012.png b/crates/lamp-label/tests/golden/label_L0123456789012.png new file mode 100644 index 0000000000000000000000000000000000000000..51e00c8fedaaa3fdb96d4860b521e0599553f243 GIT binary patch literal 661 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 literal 0 HcmV?d00001 diff --git a/crates/lamp-label/tests/golden/label_LABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHI.png b/crates/lamp-label/tests/golden/label_LABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHI.png new file mode 100644 index 0000000000000000000000000000000000000000..76d7de2f13f60014f1fd144f161edf06bc2dd3b8 GIT binary patch literal 934 zcmV;X16lluP)+J+8>qEB#85*u>?sh)#e>HUUZV){vVu5zFvl#ILl6QB zf_N1Io`edukUjL!i#Z7c>wtUkAXHP0VPiEVai(Q2*{MDG!@NsX*W;`A-dC?*z3N0f zM;>;crva9#)3RjaA7-QKY(C6~`_+C`cd}#@MaJvhUVmq;uU)zu8Rb81kg&g)DqoDs z+DTRU-VIhWmJ(OiPN=wsLuzu9fjDL6F)Eu4b+daoIjZrb ze4l+kS0#8T1TTGAauVSjYzX6`4Z%rHJlVsZ9hz0DS>1$3t!lBYz@0|WLRt-(&O8^^ zsWLL7bb4G)`yjPqT$8oQs33(3R$7V$KL-k4*$}NL#hk(0;s7H}Qa<9e=2$$2lS)Qpq#I^9E(3`(NlR`PS8d@P+NuB1yxc>!e{L}?w_ zWHy>z=!T43RgZeDD!~?!3Iq_>MSAuI=THWztwuNp8-g(|bRbux#D#g*G0%l%5K8d$ zf4P!Z2Q=9DlGTHwx02b2w%{eKBOZ!$554BjIUl&PF1_}87Pv3Ky;QCBlv954^2W8= z@Zr(4zpoa?)t!&Oeb+l|WL`{j-rkl8=M@-_WQ1l^p5v6cFAE+xaY^a_axGQ`t21S@ z2Kl^oSd8MPp5$*+lNTG!*lm9**GmrHvT_s^snS^PCwb)d2Kj6ZVo=LrqdfIAAMEdc>&qGKLRU1y!Xu% zUjw-G`xl+tf0#Fbo2GjY@OZktji=i{fnPr}s10xrqqA%s8~`Ud;#$7G4jcm~J8?Jy z?xMSX8CWssOwH(L;1aNMyF(-3<}>H($!NaC;Ro$zdIEGuz)QHew}*=WF5}ftb3AJu zKE$Z|EiU9ITle)k?co(1zxeUa=t7Qna5rDp`F~>`;yst&FX>$V?&hPqoF}w)(5eUtdyU2x2iMG(oq- zA2RE_$E3v2YW`j40cw#Y>`?F1E;7R)IomR%y2IxjrcBrze(2yTG z+d#Kg)A-P+6d8Kyxaj!|mJmZV)B7shR@b2+|DSD$S~8{oq7%$E)@jz|!_4tah@rUM zMrV@9q{vSTb?$sm0!`J38YD!82F+wuhc|yjllsKr;2%{j0_0Y3&6Xj7F4l6g;@xwS zkitBa`-<4@yiz==ko0^*?rtK2o*$6E1NpNVO z5U;l1xpi?eei!Ntt z;-GqnuWK)?e4XYc#Bk&J{t@JNH|)46I1CYYQUNwMuPqxB6?rs~rR!?A9|9z34Sb7B z=fLXJ>7#X!PzUdCYGAY61uKcgvA2T_aXD*k<2t0{)rOjXfyVsL3xuh><=(lRms0)# X2V?BUAOVR100000NkvXXu0mjf$v`XG literal 0 HcmV?d00001 diff --git a/crates/lamp-label/tests/golden/label_LAVA-7.png b/crates/lamp-label/tests/golden/label_LAVA-7.png new file mode 100644 index 0000000000000000000000000000000000000000..24ea7eb8b7b110fe776831cba5648b1a78f215bb GIT binary patch literal 604 zcmV-i0;BzjP)J7}yckCF$}q#( zOn$Wuh7M=}doLPS)HbbDMglojU*Os%Xj?ja62p8L%4Jx(C#xL|PkAvcR%7*2IxFgz zSVd&R5a|^2KBOo+K%19h%h(QFS9=MsL9kL~TH9au3MhYkVkx}bbJKrX&bBQ$7X$uKcVlb`x66K zYiPugyCZs@U2i7T#w8M4hCgDPZqO8Sh8&{cnn?6ad#mG-11= z-~eWhtCBH9)j4j~3FAm_&exj3|ZR z9>M0Op215}7z@?`vG5$MmZ=b_{4%@_Gv5pAl&-ANP)BDm`KyxgAUMa+ru^m z6jp~m9Z01Z3ok3nn3mr(lE}l*%2KHMy^Urc8>e})Dj9=WW@aB@)5~QJFK=(7)0~-@ z#>whs)4ScfU|>;rDkLdXy{oTWTcR!ND76kby_%te&6i^8(ByNI_SMm(&w;c73rm-w z7E`qT8vP4GlA_j>yl9xN!jJ0alt1FP|FfG-yN~z4`A~n|9pby&{-qD_VZ8AE&0raIZ)D7+=OOce2?ubY2}D58g{v_=FcAhn>0E0De9) z*-pdOo$~G1+h;s8bQ#~oyedl_O&?-r@Ee+>EO9cVa!h1h#{cLEQs^ WAPG**r4kPS00003bCeUf(uBpFjdZOOVU~udZ-k&|CbNTjQ|q>o~#HM?LPvPT@LFG9^(a??6AD07-z zIfpR0N)KaFjnP)44-AU-x2A?S02&`xQJ{ zD#JPay|@kJY8h4mg=sYlmtZ|#1B?!U!NH+n{P7@=e7)6v3M8m*Ly7XX3gvq~#N5kS zT<{y1nwno&gQ%k#Uwybxd?as`B4w*IJZK#_XQ>pL^r#_BSUHR{s__q8M?L9}jI_3+4XzxIEvH{9h94VD_ zY6n5k+ANS82$GMdd%P2mClTX_bc!=v`z%o>@XUzgJLd`;Xp(UDmxkw&7LfTp_WEP zxAle{QU)(79~$U^#x)Z)x=4nqCseElQVtkql7%n?#}pkhHdJW6ByhHcFw~)~zEb79 z##XX*t*i2)?BLO9)Jw@WpC#6XMLCMEm>p2rIJD)}Hp+q4*3XeIu(laZCq6_y-OlCJ zHcAScX4zAb)tAT^NN(3$Vw8iZ{xWcrI<~lsUCDdMa*(HUUC>!ZU>JH{vQ4ens-hUu z%hzZo|2;G``*U3^rO(e$AA@TDh}J4Wg8_Pc0ltNyHwn7^iL0CX605qE;pQSimci{E zTE@*ohApte57=FtbWKj91va?%2(`<7(&D8B-pb6!&Ajlp)&*dd0j|QROImatdMi-A z&Dj3{ka%YSpC+ee(J(;C)C6rG#5se$BbVt?iO?Y>#C_rYF$l|Oc#_>JK~o=?e27D# z version= mask= size=`` followed by ``n`` rows of + ``0``/``1`` (1 = dark), quiet zone not included. +* ``label_.png``: the complete 202x202 label from Python ``render_label``. +* ``text_info.txt``: per ID the font, chosen size, PIL text bbox and the draw + origin used by ``render_label``. + +Run with: C:/dev/HPCS/.venv/Scripts/python.exe -W ignore crates/lamp-label/tools/golden.py +""" + +import argparse +import importlib.util +import os +import re +from pathlib import Path + +import qrcode +from PIL import Image, ImageDraw, ImageFont + +OUT = Path(__file__).resolve().parent.parent / "tests" / "golden" +DOTS = (202, 202) +TEXT_HEIGHT = 52 + +QR_IDS = [f"L{i:04d}" for i in range(1, 21)] + [ + "L0999", + "L1000", + "L12345", + "L123456", + # mode / version coverage + "12345678", # numeric mode + "LAMP-7 X", # alphanumeric with space + "lamp_7", # upper-cased, '_' -> byte mode + "https://example.com/lamp/L0006?x=1", # alnum chunk + byte chunk + "L" + "0123456789" * 13, # byte 'L' + numeric chunk, version 4 + "L" + "ABCDEFGHIJ" * 20, # alphanumeric, version 8 (version info) +] +TEXT_IDS = ["L0001", "L0006", "L0123", "L12345", "L9", "L123456", "L0123456789012", "LAVA-7", "WWWWWWWWWW", "lamp_7"] + +# ---- verbatim copy of label_printer.py (HPCS) ------------------------------- +def _font(size): + for name in ("arialbd.ttf", "arial.ttf", "DejaVuSans-Bold.ttf"): + try: + return ImageFont.truetype(name, size) + except OSError: + continue + return ImageFont.load_default(size) + + +def render_label(lamp_id: str) -> Image.Image: + image = Image.new("1", DOTS, 1) + qr = qrcode.QRCode( + error_correction=qrcode.constants.ERROR_CORRECT_M, + box_size=1, + border=2, + ) + qr.add_data(lamp_id.upper()) + qr.make(fit=True) + modules = len(qr.get_matrix()) + qr_size = DOTS[1] - TEXT_HEIGHT + qr.box_size = max(1, qr_size // modules) + qr_img = qr.make_image().get_image().convert("1") + image.paste(qr_img, ((DOTS[0] - qr_img.width) // 2, (qr_size - qr_img.height) // 2)) + + draw = ImageDraw.Draw(image) + size = 44 + while size > 10: + font = _font(size) + box = draw.textbbox((0, 0), lamp_id, font=font) + if box[2] - box[0] <= DOTS[0] - 8: + break + size -= 2 + draw.text( + ((DOTS[0] - (box[2] - box[0])) // 2 - box[0], DOTS[1] - TEXT_HEIGHT + (TEXT_HEIGHT - (box[3] - box[1])) // 2 - box[1]), + lamp_id, + font=font, + fill=0, + ) + return image +# ----------------------------------------------------------------------------- + + +def text_layout(lamp_id): + """Same loop as render_label, returning what it decided.""" + draw = ImageDraw.Draw(Image.new("1", DOTS, 1)) + size = 44 + while size > 10: + font = _font(size) + box = draw.textbbox((0, 0), lamp_id, font=font) + if box[2] - box[0] <= DOTS[0] - 8: + break + size -= 2 + origin = ( + (DOTS[0] - (box[2] - box[0])) // 2 - box[0], + DOTS[1] - TEXT_HEIGHT + (TEXT_HEIGHT - (box[3] - box[1])) // 2 - box[1], + ) + return font, size, box, origin + + +def file_safe(lamp_id): + return re.sub(r"[^A-Za-z0-9_-]", "_", lamp_id)[:40] + + +def main(): + ap = argparse.ArgumentParser() + ap.add_argument("--reference", default=os.environ.get("LABEL_PRINTER_PY")) + args = ap.parse_args() + reference = None + if args.reference and Path(args.reference).exists(): + spec = importlib.util.spec_from_file_location("label_printer_ref", args.reference) + reference = importlib.util.module_from_spec(spec) + spec.loader.exec_module(reference) + + OUT.mkdir(parents=True, exist_ok=True) + for f in OUT.iterdir(): + if f.suffix in (".png", ".txt"): + f.unlink() + + lines = [] + for lamp_id in QR_IDS: + qr = qrcode.QRCode(error_correction=qrcode.constants.ERROR_CORRECT_M, box_size=1, border=2) + qr.add_data(lamp_id.upper()) + qr.make(fit=True) + mask = qr.best_mask_pattern() # deterministic; same choice make() used + qr.make(fit=True) + n = qr.modules_count + lines.append(f"{lamp_id} version={qr.version} mask={mask} size={n}") + for row in qr.modules: + lines.append("".join("1" if m else "0" for m in row)) + (OUT / "qr_matrices.txt").write_bytes(("\n".join(lines) + "\n").encode("utf-8")) + + names = [] + for lamp_id in dict.fromkeys(QR_IDS + TEXT_IDS): + im = render_label(lamp_id) + if reference is not None: + assert reference.render_label(lamp_id).tobytes() == im.tobytes(), lamp_id + name = f"label_{file_safe(lamp_id)}.png" + im.save(OUT / name) + names.append(f"{lamp_id}\t{name}") + (OUT / "labels.txt").write_bytes(("\n".join(names) + "\n").encode("utf-8")) + + info = [] + for lamp_id in TEXT_IDS: + font, size, box, origin = text_layout(lamp_id) + path = Path(getattr(font, "path", "builtin")).name + info.append( + f"{lamp_id}\tfont={path}\tsize={size}\tbbox={box[0]},{box[1]},{box[2]},{box[3]}\torigin={origin[0]},{origin[1]}" + ) + (OUT / "text_info.txt").write_bytes(("\n".join(info) + "\n").encode("utf-8")) + print(f"{len(QR_IDS)} QR matrices, {len(names)} labels, {len(info)} text layouts -> {OUT}") + print("reference render_label checked" if reference else "reference render_label NOT checked") + for line in info: + print(line) + + +if __name__ == "__main__": + main() diff --git a/crates/tm30/Cargo.toml b/crates/tm30/Cargo.toml new file mode 100644 index 0000000..a02366a --- /dev/null +++ b/crates/tm30/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "tm30" +description = "ANSI/IES TM-30-18 colour rendition (Rf, Rg, hue-bin CVG data), a numerically faithful port of colour-science 0.4.7" +version.workspace = true +edition.workspace = true +publish.workspace = true +license = "BSD-3-Clause" + +[dependencies] + +[dev-dependencies] +serde_json = { version = "1", features = ["float_roundtrip"] } diff --git a/crates/tm30/README.md b/crates/tm30/README.md new file mode 100644 index 0000000..4723917 --- /dev/null +++ b/crates/tm30/README.md @@ -0,0 +1,134 @@ +# tm30 + +ANSI/IES TM-30-18 colour rendition metrics (fidelity index Rf, +gamut index Rg, CCT/Duv and the 16 hue-bin values for the colour +vector graphic) from a measured spectrum, in pure Rust (std only). + +This is a numerically faithful port of the HPCS reference script `tm30.py` +(`compute_tm30`), which wraps +`colour.quality.colour_fidelity_index_ANSIIESTM3018` from +[colour-science](https://www.colour-science.org/) 0.4.7. The goal is the same +numbers, not just the same method: every array colour uses on this path is +embedded as it is after colour's own Sprague re-alignment, and the arithmetic +follows colour/numpy's evaluation order. + +```rust +let r = tm30::compute(&wavelengths_nm, &values)?; +println!("Rf {:.1} Rg {:.1} CCT {:.0} K Duv {:.4}", r.rf, r.rg, r.cct_k, r.duv); +for b in &r.bins { + // b.bin (1..=16), b.ref_a/b, b.test_a/b, *_norm, b.rcs_pct, b.rhs, b.rf_h +} +``` + +## API + +```rust +pub const N_BINS: usize = 16; +pub struct HueBin { bin, ref_a, ref_b, test_a, test_b, + ref_a_norm, ref_b_norm, test_a_norm, test_b_norm, + rcs_pct, rhs, rf_h } // all f64 except bin: u32 +pub struct Tm30 { rf, rg, cct_k, duv, bins: Vec } +pub enum Error { NotVisible, InvalidInput(String) } +pub fn compute(wavelengths_nm: &[f64], values: &[f64]) -> Result; +// extras +pub fn compute_detailed(..) -> Result<(Tm30, SampleData), Error>; // + per-sample J'a'b', ΔE, R_f,i +pub fn warm_up(); // build caches up front +pub const VISIBLE_MIN_NM, VISIBLE_MAX_NM, MIN_VISIBLE_POINTS; +``` + +Semantics (same as `tm30.py`): + +* Only samples with 380 <= λ <= 780 nm are used; fewer than 10 such samples + gives `Error::NotVisible` ("spectrum does not cover the visible range"). +* They are resampled with `np.interp` semantics (linear, ends held constant) + onto 380..=780 nm / 1 nm. The input may have any (ascending) grid, e.g. the + HPCS 6500's 350 points over 380-1050 nm. +* CCT/Duv: CIE 1931 2° XYZ -> CIE 1960 uv -> Ohno (2013) with colour's + 1000-25000 K Planckian table (spacing 1.001, 360-780 nm CMFs). +* Reference illuminant: Planckian below 4000 K, CIE D-series above 5000 K + (M1/M2 rounded to 3 decimals, no 1.4388/1.4380 correction), Y-normalised + linear mixture in between. +* 99 CIE 2017 colour evaluation samples, CIE 1964 10° observer, CIECAM02 + (LA = 100, Yb = 20, average surround, illuminant + discounted), CAM02-UCS. +* `rcs_pct` is colour's `R_cs` (already in percent), `rhs` is `R_hs`, + `rf_h` is the mean of the per-sample Rf,i of the samples whose + reference hue falls into the bin (NaN if none) - exactly what `tm30.py` + reports, which is *not* colour's `R_fs` (Rf of the mean ΔE). +* `*_norm` divide by the norm of the bin's reference average (1.0 if that + norm is exactly 0, as in `tm30.py`). + +Deviations from the Python behaviour, on inputs the Python code does not +handle meaningfully: length mismatch, non-finite values inside 380-780 nm, +descending wavelengths and a spectrum with zero luminance return +`Error::InvalidInput` (Python raises, silently produces garbage, or returns +NaN respectively). Negative scale factors behave exactly as in Python. + +## Accuracy + +`tests/golden.rs` compares every output field of 52 cases generated by the +Python reference (11 HPCS lamp measurements, FL1-FL12, A, D50, D65, LED-B1..5, +LED-BH1, LED-RGB1, LED-V1/V2, HP1-HP5, blackbodies 2700/4300/4700 K, daylight +6500/10000 K, 10 nm, HPCS 380-1050 nm, irregular and partial grids, a noisy +lamp with negative values and a negated spectrum; all three reference regimes +are covered). Max deviations (this machine): + +| field | max abs | max rel | +|---|---|---| +| Rf | 8.1e-11 | 1.1e-12 | +| Rg | 2.2e-11 | 1.9e-13 | +| CCT_K | 1.9e-8 K | 4.5e-12 | +| Duv | 1.2e-11 | 2.5e-10 | +| ref_a / ref_b | 2.1e-11 | 4.7e-12 | +| test_a / test_b | 2.7e-13 | 1.8e-13 | +| *_norm | 1.0e-12 | 4.6e-12 | +| Rcs_pct | 4.9e-11 | 4.0e-8 (values ~1e-3 %) | +| Rhs | 1.1e-12 | 7.7e-8 (values ~1e-5) | +| Rf_h | 1.4e-10 | 2.3e-12 | + +The test requires, per value, relative error <= 1e-9 *or* absolute error +<= 1e-11 (the latter only matters for quantities that are themselves close to +zero: Duv of Planckian sources, tiny chroma/hue shifts). NaN must match NaN. + +Bit-exact agreement is not possible: numpy computes the tristimulus +integrals of 2-D batches (Planckian table, 99 samples) with OpenBLAS `dgemm`, +whose blocked FMA kernel order depends on the CPU (`DYNAMIC_ARCH`), and uses +SIMD `sin`/`cos`/`exp`. Single-spectrum integrals reproduce OpenBLAS' +`dgemv` order and match bit for bit. The remaining ulp-level differences in +the Planckian table are amplified ~1000x by Ohno's parabolic/triangular +interpolation into the CCT (still ~1e-12 relative). + +## Performance + +`cargo run -p tm30 --release --example bench` (HPCS-like 350-point input): +~20 ms for the first call (parsing the embedded tables and building the +3438-row Planckian table, cached in `OnceLock`s), ~0.25 ms per call after +that. Call `tm30::warm_up()` at start-up to move the first cost out of the +measurement path. + +## Data provenance and regeneration + +`data/*.csv` are extracted from colour-science 0.4.7 (BSD-3-Clause, +Copyright 2013 Colour Developers) by `tools/extract_data.py`; the underlying +data are CIE publications: + +* `cmf_cie1931_2deg_360_780.csv`, `cmf_cie1931_2deg_380_780.csv` - CIE 1931 + 2° standard observer (CIE 015:2004), as colour aligns it to 360-780 nm and + then 380-780 nm (both are needed, the realignment is not bit-exact). +* `cmf_cie1964_10deg_380_780.csv` - CIE 1964 10° standard observer. +* `d_series_basis_380_780.csv` - CIE D-series S0/S1/S2 (CIE 015:2004), + Sprague-interpolated from 5 nm to 1 nm by colour. +* `tcs_cie2017_380_780.csv` - the 99 CIE 2017 colour evaluation samples + (CIE 224:2017; identical to the ANSI/IES TM-30-18 CES), 1 nm. +* `ciecam02_matrices.csv` - CAT02 and `M_HPE · CAT02⁻¹` as numpy computes it. + +Regenerate (needs a Python with colour-science 0.4.7 + numpy): + +```sh +python -W ignore crates/tm30/tools/extract_data.py +python -W ignore crates/tm30/tools/golden.py --tm30-dir

\ + --lamps-dir /apps/web/comparison-data/lamps +``` + +`tools/golden.py` writes `tests/golden/*.json` (input wavelengths/values and +all outputs of `compute_tm30`; NaN as `null`). diff --git a/crates/tm30/data/ciecam02_matrices.csv b/crates/tm30/data/ciecam02_matrices.csv new file mode 100644 index 0000000..651aa32 --- /dev/null +++ b/crates/tm30/data/ciecam02_matrices.csv @@ -0,0 +1,3 @@ +name,m00,m01,m02,m10,m11,m12,m20,m21,m22 +CAT02,0.7328,0.4296,-0.1624,-0.7036,1.6975,0.0061,0.003,0.0136,0.9834 +HPE_CAT02_INV,0.7409790970135308,0.21802515567573566,0.04100574731073359,0.2853532916858802,0.6242015741188158,0.0904451341953042,-0.009627608738429355,-0.00569803121611342,1.0153256399545427 diff --git a/crates/tm30/data/cmf_cie1931_2deg_360_780.csv b/crates/tm30/data/cmf_cie1931_2deg_360_780.csv new file mode 100644 index 0000000..bbdfce3 --- /dev/null +++ b/crates/tm30/data/cmf_cie1931_2deg_360_780.csv @@ -0,0 +1,422 @@ +wavelength_nm,x_bar,y_bar,z_bar +360.0,0.00012989999999999999,3.916999999999999e-06,0.0006061 +361.0,0.00014584700000000003,4.393581e-06,0.0006808791999999996 +362.0,0.00016380209999999995,4.929604000000002e-06,0.0007651455999999997 +363.0,0.00018400370000000004,5.532136e-06,0.0008600124000000001 +364.0,0.00020669019999999992,6.208245000000001e-06,0.0009665928000000001 +365.0,0.00023209999999999998,6.965000000000001e-06,0.001086 +366.0,0.00026072800000000006,7.813219000000005e-06,0.0012205860000000003 +367.0,0.00029307500000000017,8.767335999999998e-06,0.0013727289999999998 +368.0,0.000329388,9.839844000000007e-06,0.0015435789999999994 +369.0,0.00036991399999999994,1.1043229999999998e-05,0.001734286 +370.0,0.00041489999999999995,1.2390000000000003e-05,0.001946000000000001 +371.0,0.0004641587000000001,1.3886409999999997e-05,0.0021777769999999997 +372.0,0.0005189859999999999,1.5557279999999993e-05,0.0024358089999999993 +373.0,0.000581854,1.744296e-05,0.002731953 +374.0,0.0006552346999999999,1.958374999999999e-05,0.0030780639999999997 +375.0,0.0007416000000000001,2.202e-05,0.003486000000000001 +376.0,0.0008450296000000002,2.483965e-05,0.0039752270000000004 +377.0,0.0009645268000000001,2.804126000000002e-05,0.004540879999999998 +378.0,0.0010949489999999994,3.153104e-05,0.005158319999999997 +379.0,0.0012311539999999993,3.521521000000001e-05,0.005802907 +380.0,0.0013680000000000003,3.899999999999999e-05,0.0064500009999999995 +381.0,0.0015020500000000004,4.282639999999999e-05,0.007083216000000006 +382.0,0.0016423280000000002,4.691459999999999e-05,0.007745487999999999 +383.0,0.001802381999999999,5.1589599999999985e-05,0.008501152 +384.0,0.0019957569999999995,5.717639999999997e-05,0.009414543999999997 +385.0,0.002236000000000001,6.4e-05,0.01054999 +386.0,0.0025353850000000002,7.234421000000004e-05,0.011965800000000002 +387.0,0.0028926030000000005,8.221224000000004e-05,0.013655869999999999 +388.0,0.003300829,9.350816e-05,0.01558805 +389.0,0.0037532359999999996,0.00010613609999999998,0.017730149999999997 +390.0,0.0042429999999999985,0.00012000000000000002,0.020050010000000007 +391.0,0.004762389000000002,0.00013498399999999997,0.022511359999999994 +392.0,0.005330048000000002,0.00015149200000000003,0.02520288 +393.0,0.005978712,0.00017020799999999995,0.028279719999999998 +394.0,0.006741117,0.00019181600000000006,0.03189704 +395.0,0.007649999999999999,0.00021700000000000002,0.036210000000000006 +396.0,0.008751373,0.0002469067000000001,0.041437709999999996 +397.0,0.010028879999999997,0.00028123999999999993,0.04750372 +398.0,0.011421700000000005,0.00031852,0.054119880000000016 +399.0,0.012869010000000007,0.0003572667,0.060998030000000016 +400.0,0.014309999999999996,0.00039599999999999976,0.06785001000000002 +401.0,0.015704429999999995,0.0004337146999999999,0.07448632 +402.0,0.017147440000000003,0.000473024,0.08136156 +403.0,0.01878122,0.0005178760000000002,0.08915363999999996 +404.0,0.020748009999999997,0.0005722187000000001,0.09854047999999999 +405.0,0.02318999999999999,0.0006399999999999999,0.11019999999999999 +406.0,0.02620736,0.0007245600000000001,0.12461330000000001 +407.0,0.029782480000000007,0.0008255000000000001,0.14170170000000004 +408.0,0.033880919999999995,0.0009411599999999998,0.1613035 +409.0,0.03846824,0.0010698799999999996,0.1832568000000001 +410.0,0.04351,0.0012099999999999997,0.20740000000000003 +411.0,0.0489956,0.0013620909999999997,0.23369210000000007 +412.0,0.055022599999999984,0.0015307520000000002,0.2626113999999999 +413.0,0.06171880000000002,0.0017203679999999995,0.29477460000000005 +414.0,0.06921199999999998,0.0019353229999999992,0.3307985000000001 +415.0,0.07763000000000005,0.002180000000000001,0.3712999999999999 +416.0,0.08695811,0.0024548,0.4162090999999999 +417.0,0.09717672000000001,0.002764,0.4654641999999998 +418.0,0.10840629999999998,0.0031177999999999987,0.5196948000000001 +419.0,0.12076719999999994,0.0035264,0.5795303 +420.0,0.13437999999999994,0.004,0.6455999999999998 +421.0,0.14935820000000002,0.004546239999999999,0.7184838000000001 +422.0,0.16539569999999998,0.0051593199999999985,0.7967133000000002 +423.0,0.18198309999999998,0.005829280000000001,0.8778459 +424.0,0.198611,0.00654616,0.9594390000000005 +425.0,0.21477000000000007,0.007300000000000002,1.0390501000000003 +426.0,0.2301867999999999,0.008086507000000003,1.1153672999999995 +427.0,0.2448797,0.008908719999999997,1.1884970999999993 +428.0,0.2587773,0.00976768,1.2581232999999998 +429.0,0.2718078999999999,0.010664430000000004,1.3239296 +430.0,0.28390000000000004,0.011599999999999997,1.3856 +431.0,0.29494380000000003,0.012573170000000002,1.442635200000001 +432.0,0.3048964999999999,0.01358271999999999,1.4948034999999997 +433.0,0.31378730000000005,0.014629679999999996,1.5421903000000001 +434.0,0.3216454000000002,0.015715089999999994,1.5848806999999998 +435.0,0.3285,0.016839999999999997,1.62296 +436.0,0.3343512999999999,0.018007360000000007,1.6564048000000002 +437.0,0.33921009999999996,0.019214480000000006,1.6852959000000007 +438.0,0.3431212999999998,0.02045392,1.7098745000000002 +439.0,0.3461296,0.021718240000000003,1.7303821 +440.0,0.34828000000000003,0.023000000000000007,1.7470600000000005 +441.0,0.34959989999999996,0.024294609999999994,1.7600446000000005 +442.0,0.35014740000000005,0.025610240000000003,1.7696232999999997 +443.0,0.35001299999999996,0.02695857,1.7762637000000001 +444.0,0.34928700000000007,0.028351250000000005,1.7804334 +445.0,0.34806,0.02979999999999999,1.7825999999999986 +446.0,0.3463732999999999,0.03131083000000001,1.7829682000000004 +447.0,0.3442624000000001,0.03288368,1.7816997999999993 +448.0,0.3418087999999999,0.034521119999999995,1.7791982000000002 +449.0,0.3390940999999999,0.036225710000000015,1.7758671000000001 +450.0,0.33619999999999994,0.038,1.7721100000000007 +451.0,0.33319770000000004,0.03984666999999999,1.7682589 +452.0,0.33004109999999987,0.04176800000000002,1.7640389999999986 +453.0,0.32663569999999975,0.04376599999999998,1.7589438000000002 +454.0,0.32288679999999986,0.04584266999999999,1.7524663000000005 +455.0,0.31870000000000004,0.04800000000000001,1.7440999999999998 +456.0,0.31402510000000006,0.050243679999999985,1.733559499999999 +457.0,0.308884,0.05257303999999999,1.7208581000000003 +458.0,0.3032904,0.05498055999999998,1.7059369000000004 +459.0,0.29725789999999985,0.05745871999999998,1.6887371999999994 +460.0,0.29079999999999995,0.060000000000000026,1.6691999999999996 +461.0,0.2839700999999999,0.06260197000000003,1.6475286999999992 +462.0,0.2767214,0.06527752000000002,1.6234127000000005 +463.0,0.26891780000000004,0.06804208,1.5960223000000002 +464.0,0.2604227,0.07091109,1.564527999999999 +465.0,0.25110000000000005,0.07389999999999998,1.528099999999999 +466.0,0.24084750000000008,0.07701599999999999,1.4861113999999997 +467.0,0.22985120000000012,0.08026639999999999,1.4395215000000006 +468.0,0.21840720000000005,0.08366679999999999,1.3898799000000004 +469.0,0.20681150000000006,0.08723280000000001,1.3387362 +470.0,0.19536,0.09097999999999999,1.28764 +471.0,0.18421359999999998,0.09491754999999998,1.2374223 +472.0,0.17332730000000005,0.09904584000000004,1.1878243000000002 +473.0,0.1626881,0.10336739999999996,1.1387611000000002 +474.0,0.15228330000000007,0.10788460000000005,1.0901480000000003 +475.0,0.14210000000000006,0.11260000000000003,1.0418999999999998 +476.0,0.13217860000000003,0.11753199999999997,0.9941976000000001 +477.0,0.12256960000000006,0.12267439999999999,0.9473472999999999 +478.0,0.11327519999999996,0.12799279999999996,0.9014531 +479.0,0.10429789999999996,0.13345279999999998,0.8566193000000001 +480.0,0.09563999999999995,0.13902,0.8129501000000003 +481.0,0.08729955000000002,0.14467639999999998,0.7705173000000001 +482.0,0.07930804,0.15046930000000003,0.7294447999999996 +483.0,0.07171775999999999,0.15646190000000001,0.6899135999999999 +484.0,0.06458099000000003,0.16271770000000002,0.6521048999999999 +485.0,0.05795001000000001,0.1692999999999999,0.6162 +486.0,0.05186211,0.1762431,0.5823286 +487.0,0.04628151999999999,0.1835581,0.5504162000000001 +488.0,0.04115088000000001,0.19127349999999996,0.5203375999999997 +489.0,0.036412830000000014,0.19941799999999996,0.4919672999999998 +490.0,0.03201,0.20802000000000007,0.4651800000000001 +491.0,0.027917199999999993,0.21711989999999998,0.4399246000000001 +492.0,0.024144400000000003,0.2267345000000001,0.4161836000000002 +493.0,0.020687000000000014,0.23685710000000001,0.39388219999999996 +494.0,0.01754040000000001,0.2474812,0.3729459000000001 +495.0,0.014700000000000003,0.25860000000000005,0.35330000000000006 +496.0,0.012161790000000004,0.27018490000000006,0.33485779999999987 +497.0,0.009919960000000005,0.2822939,0.3175520999999999 +498.0,0.00796724,0.2950504999999999,0.3013374999999999 +499.0,0.006296346000000001,0.30857799999999985,0.2861686 +500.0,0.004900000000000001,0.323,0.2720000000000002 +501.0,0.0037771730000000017,0.33840209999999976,0.2588171 +502.0,0.0029453200000000017,0.3546858000000003,0.24648379999999998 +503.0,0.00242488,0.37169860000000005,0.23477180000000003 +504.0,0.002236292999999999,0.3892875,0.2234533000000001 +505.0,0.0024000000000000002,0.40730000000000005,0.2123 +506.0,0.00292552,0.42562989999999995,0.2011692 +507.0,0.0038365600000000006,0.4443096000000002,0.19011960000000006 +508.0,0.005174840000000001,0.4633944,0.1792254 +509.0,0.00698208,0.4829395000000001,0.16856080000000007 +510.0,0.009300000000000004,0.503,0.1582 +511.0,0.012149490000000002,0.5235692999999999,0.14813829999999997 +512.0,0.015535880000000002,0.5445120000000002,0.13837579999999997 +513.0,0.019477520000000012,0.5656899999999999,0.12899419999999992 +514.0,0.023992769999999997,0.5869653000000001,0.12007510000000005 +515.0,0.0291,0.6082,0.11169999999999992 +516.0,0.03481484999999999,0.6293456000000002,0.10390480000000005 +517.0,0.04112015999999999,0.6503067999999997,0.09666748 +518.0,0.04798504000000001,0.6708752,0.08998272000000002 +519.0,0.05537861,0.6908423999999997,0.08384531 +520.0,0.06327000000000002,0.7100000000000003,0.07824999 +521.0,0.07163501,0.7281852000000001,0.07320899 +522.0,0.08046223999999996,0.7454636000000003,0.06867816000000003 +523.0,0.08973996,0.7619693999999999,0.06456784000000003 +524.0,0.09945644999999995,0.7778367999999999,0.060788350000000026 +525.0,0.10959999999999999,0.7932,0.05725000999999999 +526.0,0.12016739999999995,0.8081104000000005,0.053904350000000004 +527.0,0.13111450000000002,0.8224962000000001,0.05074663999999998 +528.0,0.1423679,0.8363067999999997,0.04775275999999998 +529.0,0.15385420000000002,0.8494916000000002,0.04489858999999999 +530.0,0.1655000000000001,0.8620000000000001,0.04216 +531.0,0.17725709999999997,0.8738107999999994,0.03950728 +532.0,0.18914000000000006,0.8849624,0.036935639999999985 +533.0,0.2011694,0.8954936000000003,0.03445836000000001 +534.0,0.2133658,0.9054431999999998,0.032088720000000015 +535.0,0.22574989999999998,0.9148500999999998,0.029839999999999995 +536.0,0.23832090000000014,0.9237348,0.027711809999999996 +537.0,0.25106679999999987,0.9320924000000003,0.02569444 +538.0,0.2639922,0.9399225999999997,0.02378716 +539.0,0.27710170000000006,0.9472252000000001,0.02198925 +540.0,0.29040000000000005,0.9540000000000005,0.02029999999999999 +541.0,0.3038911999999999,0.9602560999999998,0.01871805 +542.0,0.3175726,0.9660073999999998,0.01724036 +543.0,0.33143839999999997,0.9712606000000004,0.015863640000000005 +544.0,0.34548280000000003,0.9760224999999998,0.014584610000000001 +545.0,0.35970000000000013,0.9803000000000002,0.013399999999999994 +546.0,0.37408389999999997,0.9840924,0.012307229999999997 +547.0,0.38863960000000003,0.9874182,0.011301880000000005 +548.0,0.4033784,0.9903127999999998,0.010377920000000002 +549.0,0.4183115,0.9928115999999999,0.009529306000000001 +550.0,0.4334499000000001,0.9949501000000002,0.008749998999999994 +551.0,0.44879529999999995,0.9967108000000006,0.008035199999999994 +552.0,0.46433600000000014,0.9980983,0.007381599999999997 +553.0,0.4800639999999998,0.9991120000000001,0.0067854 +554.0,0.4959713000000001,0.9997481999999996,0.0062428000000000015 +555.0,0.5120500999999997,0.9999999999999999,0.005749999000000003 +556.0,0.5282958999999999,0.9998567,0.0053036 +557.0,0.5446915999999998,0.9993046000000001,0.004899800000000002 +558.0,0.5612094000000001,0.9983254999999999,0.0045342 +559.0,0.5778215,0.9968986999999996,0.0042024 +560.0,0.5945000000000001,0.9949999999999996,0.003900000000000001 +561.0,0.6112209000000001,0.9926004999999998,0.003623200000000002 +562.0,0.6279757999999999,0.9897425999999998,0.0033706 +563.0,0.6447602,0.9864444000000003,0.003141400000000001 +564.0,0.6615696999999999,0.9827240999999997,0.0029347999999999996 +565.0,0.6783999999999999,0.9786,0.0027499990000000017 +566.0,0.6952391999999998,0.9740837000000003,0.002585199999999999 +567.0,0.7120586000000002,0.9691712,0.0024386 +568.0,0.7288283999999999,0.9638568000000001,0.002309399999999999 +569.0,0.7455187999999997,0.9581348999999999,0.0021967999999999996 +570.0,0.7621000000000001,0.9520000000000003,0.0021000000000000003 +571.0,0.7785432,0.9454503999999998,0.0020177329999999994 +572.0,0.7948255999999999,0.9384992000000004,0.0019481999999999998 +573.0,0.8109263999999999,0.9311627999999996,0.0018898000000000003 +574.0,0.8268248000000002,0.9234575999999999,0.001840933 +575.0,0.8424999999999998,0.9153999999999995,0.0017999999999999997 +576.0,0.8579325000000001,0.9070064000000001,0.0017662669999999998 +577.0,0.8730816000000001,0.8982772000000006,0.0017378 +578.0,0.8878944000000003,0.8892047999999999,0.0017111999999999995 +579.0,0.9023181000000001,0.8797815999999992,0.001683067 +580.0,0.9162999999999999,0.87,0.001650000999999999 +581.0,0.9297994999999999,0.8598613,0.0016101330000000001 +582.0,0.9427984000000003,0.8493919999999999,0.0015643999999999996 +583.0,0.9552775999999997,0.838622,0.0015136000000000001 +584.0,0.9672179,0.8275813,0.0014585330000000001 +585.0,0.9785999999999999,0.8163000000000002,0.0013999999999999998 +586.0,0.9893856000000003,0.8047947000000002,0.001336667 +587.0,0.9995487999999997,0.7930820000000002,0.00127 +588.0,1.0090892,0.7811920000000002,0.001205 +589.0,1.0180064000000002,0.7691546999999995,0.001146667 +590.0,1.0262999999999998,0.7569999999999996,0.0011 +591.0,1.0339826999999997,0.7447540999999995,0.0010688 +592.0,1.0409859999999997,0.7324224,0.0010494000000000005 +593.0,1.047188,0.7200036,0.0010355999999999998 +594.0,1.0524667000000003,0.7074965,0.0010212000000000003 +595.0,1.0567,0.6949,0.001 +596.0,1.0597944,0.6822192,0.0009686399999999997 +597.0,1.0617991999999996,0.6694716,0.0009299200000000003 +598.0,1.0628068,0.6566743999999994,0.0008868799999999997 +599.0,1.0629096000000002,0.6438447999999999,0.0008425599999999997 +600.0,1.0622000000000005,0.631,0.0008000000000000001 +601.0,1.0607351999999999,0.6181555,0.0007609600000000003 +602.0,1.0584435999999997,0.6053144,0.00072368 +603.0,1.0552244000000002,0.5924756000000002,0.0006859199999999997 +604.0,1.0509768000000006,0.5796379000000002,0.0006454400000000002 +605.0,1.0456000000000005,0.5668,0.0005999999999999998 +606.0,1.0390369,0.5539611000000001,0.0005478667000000001 +607.0,1.0313608,0.5411372000000001,0.0004915999999999999 +608.0,1.0226661999999995,0.5283528,0.0004354 +609.0,1.0130476999999998,0.5156323,0.00038346669999999986 +610.0,1.0026,0.503,0.00033999999999999997 +611.0,0.9913674999999998,0.4904687999999999,0.00030725330000000006 +612.0,0.9793313999999997,0.47803040000000013,0.0002831600000000002 +613.0,0.9664916000000002,0.4656775999999999,0.00026544000000000003 +614.0,0.9528479000000002,0.4534032,0.00025181330000000014 +615.0,0.9384000000000005,0.44120000000000004,0.00024 +616.0,0.9231940000000001,0.42908,0.0002295467 +617.0,0.9072439999999997,0.41703599999999996,0.00022063999999999992 +618.0,0.8905020000000002,0.40503199999999995,0.00021196000000000002 +619.0,0.8729200000000003,0.39303199999999994,0.00020218669999999995 +620.0,0.8544499000000004,0.381,0.0001900000000000001 +621.0,0.835084,0.36891839999999987,0.00017421329999999993 +622.0,0.8149459999999998,0.3568271999999999,0.00015564000000000008 +623.0,0.7941859999999997,0.34477680000000005,0.00013596 +624.0,0.7729540000000003,0.3328176,0.00011685330000000002 +625.0,0.7514000000000004,0.32100000000000006,0.00010000000000000006 +626.0,0.7295836000000002,0.30933810000000017,8.613333000000003e-05 +627.0,0.7075888,0.29785040000000007,7.460000000000002e-05 +628.0,0.6856022000000002,0.2865935999999999,6.499999999999997e-05 +629.0,0.6638103999999998,0.27562450000000005,5.693333e-05 +630.0,0.6424000000000003,0.265,4.9999989999999995e-05 +631.0,0.6215149000000001,0.2547632000000001,4.4160000000000004e-05 +632.0,0.6011138000000001,0.24488959999999996,3.948000000000002e-05 +633.0,0.5811051999999998,0.2353344,3.5720000000000004e-05 +634.0,0.5613976999999998,0.2260528000000001,3.264e-05 +635.0,0.5418999999999999,0.21700000000000003,2.9999999999999987e-05 +636.0,0.5225995000000001,0.2081616,2.765333e-05 +637.0,0.5035464000000002,0.19954879999999997,2.5559999999999992e-05 +638.0,0.4847435999999998,0.19115520000000003,2.364e-05 +639.0,0.4661938999999999,0.18297440000000004,2.1813330000000002e-05 +640.0,0.44789999999999996,0.17499999999999993,2.0000000000000012e-05 +641.0,0.4298613,0.16722350000000008,1.8133329999999993e-05 +642.0,0.41209800000000013,0.1596464,1.62e-05 +643.0,0.394644,0.15227760000000007,1.4200000000000003e-05 +644.0,0.3775332999999999,0.14512590000000006,1.2133330000000007e-05 +645.0,0.36080000000000007,0.13819999999999996,9.999999999999999e-06 +646.0,0.34445629999999994,0.13150029999999993,7.733333e-06 +647.0,0.32851680000000005,0.12502480000000005,5.400000000000003e-06 +648.0,0.31301920000000005,0.1187792,3.200000000000001e-06 +649.0,0.29800109999999996,0.11276910000000002,1.3333330000000011e-06 +650.0,0.28349999999999986,0.10699999999999994,2.117582368135751e-22 +651.0,0.2695447999999998,0.10147619999999996,-3.1763735522036263e-22 +652.0,0.25611840000000013,0.09618864000000002,5.293955920339377e-23 +653.0,0.2431896000000001,0.09112296000000004,0.0 +654.0,0.23072720000000005,0.08626485000000002,0.0 +655.0,0.2187,0.08159999999999998,0.0 +656.0,0.2070970999999999,0.07712063999999998,0.0 +657.0,0.19592319999999996,0.07282551999999998,0.0 +658.0,0.18517079999999989,0.06871007999999997,0.0 +659.0,0.17483229999999994,0.06476976,0.0 +660.0,0.16489999999999996,0.06099999999999998,0.0 +661.0,0.1553667,0.05739621000000002,0.0 +662.0,0.14623000000000005,0.05395503999999999,0.0 +663.0,0.1374900000000001,0.050673760000000026,0.0 +664.0,0.12914669999999998,0.047549650000000006,0.0 +665.0,0.1212,0.044579999999999995,0.0 +666.0,0.11363969999999993,0.04175872,0.0 +667.0,0.10646500000000002,0.039084960000000016,0.0 +668.0,0.09969044000000005,0.03656384000000001,0.0 +669.0,0.09333061000000001,0.034200480000000005,0.0 +670.0,0.08739999999999995,0.032,0.0 +671.0,0.08190096000000001,0.029962610000000004,0.0 +672.0,0.07680427999999996,0.02807664,0.0 +673.0,0.07207712,0.02632935999999999,0.0 +674.0,0.06768664000000005,0.024708050000000006,0.0 +675.0,0.06359999999999999,0.023200000000000002,0.0 +676.0,0.059806849999999974,0.02180077,0.0 +677.0,0.05628215999999997,0.02050111999999999,0.0 +678.0,0.052971040000000004,0.019281079999999996,0.0 +679.0,0.04981860999999998,0.018120690000000005,0.0 +680.0,0.04677,0.017000000000000005,0.0 +681.0,0.04378405,0.015903789999999998,0.0 +682.0,0.04087536000000002,0.014837179999999998,0.0 +683.0,0.038072639999999984,0.013810680000000002,0.0 +684.0,0.035404609999999996,0.012834779999999995,0.0 +685.0,0.03289999999999999,0.011920000000000004,0.0 +686.0,0.03056419000000001,0.011068309999999998,0.0 +687.0,0.02838055999999999,0.010273389999999997,0.0 +688.0,0.026344839999999998,0.009533310999999997,0.0 +689.0,0.024452750000000006,0.008846157000000002,0.0 +690.0,0.022699999999999998,0.008209999999999995,0.0 +691.0,0.02108428999999999,0.007623780999999999,0.0 +692.0,0.01959988000000001,0.007085424000000001,0.0 +693.0,0.018237320000000008,0.006591475999999997,0.0 +694.0,0.01698717,0.006138484999999998,0.0 +695.0,0.015839999999999996,0.005723000000000003,0.0 +696.0,0.014790639999999999,0.005343058999999996,0.0 +697.0,0.013831320000000001,0.0049957959999999985,0.0 +698.0,0.012948679999999994,0.004676404000000001,0.0 +699.0,0.012129200000000005,0.004380075000000001,0.0 +700.0,0.011359159999999998,0.004101999999999999,0.0 +701.0,0.010629350000000003,0.0038384530000000012,0.0 +702.0,0.009938846000000003,0.003589099,0.0 +703.0,0.009288422000000003,0.003354219,0.0 +704.0,0.008678853999999998,0.003134092999999998,0.0 +705.0,0.008110915999999998,0.002929,0.0 +706.0,0.007582387999999999,0.002738139,0.0 +707.0,0.007088746000000001,0.002559876,0.0 +708.0,0.006627312999999998,0.0023932439999999992,0.0 +709.0,0.006195408000000002,0.002237275,0.0 +710.0,0.005790345999999999,0.002091,0.0 +711.0,0.005409826000000001,0.0019535869999999997,0.0 +712.0,0.005052582999999999,0.0018245799999999993,0.0 +713.0,0.004717512000000001,0.0017035800000000003,0.0 +714.0,0.004403506999999997,0.0015901869999999996,0.0 +715.0,0.004109456999999999,0.0014839999999999996,0.0 +716.0,0.0038339129999999996,0.001384496,0.0 +717.0,0.003575748000000001,0.0012912680000000004,0.0 +718.0,0.0033343419999999984,0.0012040920000000006,0.0 +719.0,0.0031090750000000015,0.0011227440000000004,0.0 +720.0,0.0028993269999999997,0.0010470000000000002,0.0 +721.0,0.002704348000000002,0.0009765895999999995,0.0 +722.0,0.00252302,0.0009111088,0.0 +723.0,0.002354168,0.0008501332000000003,0.0 +724.0,0.0021966159999999993,0.0007932384,0.0 +725.0,0.00204919,0.00074,0.0 +726.0,0.0019109600000000002,0.0006900826999999998,0.0 +727.0,0.0017814379999999993,0.00064331,0.0 +728.0,0.0016601099999999994,0.0005994959999999998,0.0 +729.0,0.0015464589999999998,0.0005584546999999997,0.0 +730.0,0.0014399709999999993,0.00052,0.0 +731.0,0.0013400419999999998,0.00048391360000000003,0.0 +732.0,0.001246275,0.0004500528,0.0 +733.0,0.0011584709999999995,0.0004183451999999997,0.0 +734.0,0.00107643,0.00038871839999999995,0.0 +735.0,0.0009999492999999996,0.0003610999999999999,0.0 +736.0,0.0009287357999999999,0.00033538350000000003,0.0 +737.0,0.0008624332000000006,0.0003114404,0.0 +738.0,0.0008007503000000002,0.0002891656000000001,0.0 +739.0,0.0007433960000000001,0.0002684539,0.0 +740.0,0.0006900786,0.00024919999999999993,0.0 +741.0,0.0006405155999999998,0.00023130189999999993,0.0 +742.0,0.0005945020999999999,0.00021468559999999998,0.0 +743.0,0.0005518646,0.00019928839999999997,0.0 +744.0,0.0005124290000000001,0.00018504750000000004,0.0 +745.0,0.00047602129999999997,0.00017189999999999995,0.0 +746.0,0.0004424536000000001,0.00015977810000000002,0.0 +747.0,0.00041151169999999984,0.00014860440000000004,0.0 +748.0,0.00038298140000000004,0.00013830159999999995,0.0 +749.0,0.0003566491000000001,0.00012879249999999998,0.0 +750.0,0.00033230110000000016,0.00012000000000000006,0.0 +751.0,0.00030975859999999997,0.00011185949999999994,0.0 +752.0,0.0002888871000000001,0.00010432239999999994,0.0 +753.0,0.0002695394,9.73356e-05,0.0 +754.0,0.0002515682,9.084587000000001e-05,0.0 +755.0,0.00023482609999999997,8.480000000000003e-05,0.0 +756.0,0.0002191709999999999,7.914667000000001e-05,0.0 +757.0,0.00020452579999999995,7.3858e-05,0.0 +758.0,0.00019084050000000002,6.891600000000002e-05,0.0 +759.0,0.00017806539999999998,6.430266999999999e-05,0.0 +760.0,0.00016615050000000003,6e-05,0.0 +761.0,0.00015502359999999997,5.5981869999999984e-05,0.0 +762.0,0.00014462189999999998,5.222560000000001e-05,0.0 +763.0,0.0001349098,4.87184e-05,0.0 +764.0,0.000125852,4.544746999999999e-05,0.0 +765.0,0.00011741299999999998,4.239999999999999e-05,0.0 +766.0,0.00010955149999999996,3.956103999999999e-05,0.0 +767.0,0.00010222449999999997,3.691511999999999e-05,0.0 +768.0,9.539445000000002e-05,3.444868000000001e-05,0.0 +769.0,8.902390000000001e-05,3.2148159999999995e-05,0.0 +770.0,8.307526999999999e-05,2.9999999999999994e-05,0.0 +771.0,7.751268999999998e-05,2.7991249999999997e-05,0.0 +772.0,7.231304e-05,2.6113560000000008e-05,0.0 +773.0,6.745778e-05,2.4360239999999994e-05,0.0 +774.0,6.292844000000002e-05,2.2724610000000007e-05,0.0 +775.0,5.870652000000002e-05,2.120000000000001e-05,0.0 +776.0,5.4770279999999985e-05,1.9778550000000007e-05,0.0 +777.0,5.109917999999999e-05,1.8452850000000004e-05,0.0 +778.0,4.767654000000001e-05,1.721687e-05,0.0 +779.0,4.4485669999999984e-05,1.6064590000000005e-05,0.0 +780.0,4.150994000000001e-05,1.499e-05,0.0 diff --git a/crates/tm30/data/cmf_cie1931_2deg_380_780.csv b/crates/tm30/data/cmf_cie1931_2deg_380_780.csv new file mode 100644 index 0000000..dcf908e --- /dev/null +++ b/crates/tm30/data/cmf_cie1931_2deg_380_780.csv @@ -0,0 +1,402 @@ +wavelength_nm,x_bar,y_bar,z_bar +380.0,0.0013680000000000005,3.899999999999999e-05,0.0064500009999999995 +381.0,0.0015020500000000004,4.282639999999996e-05,0.007083216000000004 +382.0,0.0016423280000000004,4.6914599999999986e-05,0.007745487999999997 +383.0,0.0018023819999999986,5.158959999999996e-05,0.008501151999999998 +384.0,0.0019957569999999995,5.7176399999999977e-05,0.009414543999999993 +385.0,0.002236000000000002,6.400000000000001e-05,0.010549990000000006 +386.0,0.002535385000000001,7.234421000000007e-05,0.011965800000000002 +387.0,0.0028926030000000005,8.221224000000004e-05,0.01365586999999999 +388.0,0.003300828999999998,9.350815999999998e-05,0.015588049999999996 +389.0,0.0037532359999999996,0.00010613609999999997,0.01773015 +390.0,0.004242999999999997,0.00012000000000000004,0.020050010000000014 +391.0,0.004762389000000004,0.00013498399999999994,0.022511359999999987 +392.0,0.005330048000000005,0.000151492,0.025202879999999997 +393.0,0.0059787120000000015,0.00017020799999999998,0.02827972 +394.0,0.006741117000000001,0.0001918160000000001,0.031897040000000015 +395.0,0.00765,0.00021700000000000007,0.03620999999999999 +396.0,0.008751373,0.00024690670000000015,0.04143770999999999 +397.0,0.010028879999999995,0.00028123999999999993,0.047503720000000006 +398.0,0.011421700000000005,0.00031852,0.05411988000000003 +399.0,0.012869010000000012,0.00035726670000000004,0.06099802999999999 +400.0,0.014310000000000002,0.00039599999999999965,0.06785001000000004 +401.0,0.015704429999999995,0.0004337146999999997,0.07448632000000002 +402.0,0.01714744000000001,0.00047302399999999995,0.08136155999999996 +403.0,0.018781219999999998,0.0005178760000000002,0.08915363999999992 +404.0,0.020748009999999987,0.0005722187000000002,0.09854047999999996 +405.0,0.02318999999999999,0.0006399999999999999,0.11019999999999998 +406.0,0.026207360000000013,0.0007245600000000003,0.12461330000000001 +407.0,0.029782480000000004,0.0008255000000000001,0.14170170000000007 +408.0,0.03388091999999999,0.0009411599999999996,0.16130349999999993 +409.0,0.03846824000000001,0.0010698799999999996,0.18325680000000014 +410.0,0.04351000000000001,0.0012099999999999995,0.20739999999999997 +411.0,0.04899560000000001,0.0013620909999999993,0.23369210000000007 +412.0,0.05502259999999998,0.0015307519999999998,0.26261139999999983 +413.0,0.06171880000000003,0.001720367999999999,0.2947746000000002 +414.0,0.06921199999999994,0.001935323,0.33079850000000016 +415.0,0.07763000000000005,0.0021800000000000014,0.37129999999999996 +416.0,0.08695811000000003,0.002454800000000001,0.41620909999999967 +417.0,0.09717672000000002,0.002764000000000001,0.4654641999999996 +418.0,0.10840629999999993,0.003117799999999998,0.5196947999999999 +419.0,0.12076719999999994,0.0035263999999999994,0.5795303 +420.0,0.13437999999999994,0.004000000000000001,0.6456 +421.0,0.1493582,0.004546239999999998,0.7184838000000001 +422.0,0.16539569999999998,0.005159319999999998,0.7967133000000003 +423.0,0.18198310000000004,0.005829280000000001,0.8778459000000002 +424.0,0.19861100000000004,0.0065461600000000005,0.9594390000000007 +425.0,0.21477000000000013,0.007300000000000002,1.0390501000000003 +426.0,0.2301867999999999,0.008086507000000001,1.1153672999999993 +427.0,0.2448797000000001,0.008908719999999995,1.1884970999999993 +428.0,0.2587773,0.009767679999999999,1.2581233000000003 +429.0,0.27180789999999994,0.010664430000000003,1.3239295999999994 +430.0,0.28390000000000004,0.011599999999999997,1.3856000000000006 +431.0,0.2949438000000001,0.012573170000000002,1.4426352000000011 +432.0,0.3048964999999999,0.013582719999999994,1.4948035 +433.0,0.31378730000000005,0.014629680000000003,1.542190300000001 +434.0,0.32164540000000025,0.015715089999999994,1.5848806999999998 +435.0,0.3285000000000001,0.016839999999999994,1.6229599999999995 +436.0,0.3343512999999998,0.018007360000000004,1.6564048000000007 +437.0,0.33921009999999996,0.019214480000000006,1.685295900000001 +438.0,0.3431212999999997,0.020453920000000004,1.7098745000000006 +439.0,0.3461296000000001,0.02171824,1.7303820999999993 +440.0,0.3482800000000001,0.023000000000000003,1.747060000000001 +441.0,0.34959989999999996,0.024294609999999987,1.7600446000000005 +442.0,0.3501474000000001,0.02561024,1.7696233 +443.0,0.35001299999999985,0.02695857000000001,1.7762636999999994 +444.0,0.349287,0.02835125,1.7804334000000006 +445.0,0.3480600000000001,0.02979999999999999,1.7825999999999986 +446.0,0.3463732999999999,0.03131083000000001,1.782968200000001 +447.0,0.3442624,0.032883679999999985,1.7816997999999988 +448.0,0.34180879999999986,0.03452112,1.7791982000000002 +449.0,0.3390941,0.03622571000000001,1.7758670999999995 +450.0,0.33619999999999983,0.038000000000000006,1.7721100000000012 +451.0,0.3331977000000001,0.03984666999999998,1.7682589000000004 +452.0,0.3300410999999999,0.04176800000000002,1.764038999999998 +453.0,0.32663569999999975,0.043765999999999965,1.7589438000000006 +454.0,0.32288679999999986,0.04584266999999998,1.7524663000000016 +455.0,0.31870000000000015,0.048,1.7441000000000002 +456.0,0.3140251000000002,0.050243680000000006,1.733559499999999 +457.0,0.308884,0.052573039999999994,1.7208580999999994 +458.0,0.3032903999999999,0.05498055999999996,1.7059369000000006 +459.0,0.29725789999999985,0.05745871999999995,1.6887371999999992 +460.0,0.2908,0.06000000000000005,1.6692000000000005 +461.0,0.28397009999999984,0.06260197000000005,1.6475286999999996 +462.0,0.27672139999999995,0.06527751999999999,1.6234126999999996 +463.0,0.2689178000000002,0.06804208,1.5960223000000002 +464.0,0.2604226999999999,0.07091108999999997,1.5645279999999995 +465.0,0.2511,0.07389999999999998,1.5280999999999993 +466.0,0.2408475000000001,0.07701599999999997,1.4861113999999993 +467.0,0.2298512000000002,0.08026639999999999,1.439521500000001 +468.0,0.2184072,0.08366680000000001,1.3898799000000008 +469.0,0.20681150000000012,0.08723280000000003,1.3387361999999998 +470.0,0.19536,0.09097999999999998,1.2876400000000001 +471.0,0.18421360000000003,0.09491754999999996,1.2374222999999995 +472.0,0.17332730000000005,0.09904584000000007,1.187824300000001 +473.0,0.16268809999999995,0.10336739999999996,1.1387611000000004 +474.0,0.1522833000000001,0.10788460000000005,1.0901480000000006 +475.0,0.1421000000000001,0.11260000000000002,1.0419 +476.0,0.13217860000000006,0.117532,0.9941975999999999 +477.0,0.12256960000000008,0.12267439999999999,0.9473473000000001 +478.0,0.11327519999999991,0.12799279999999993,0.9014530999999998 +479.0,0.10429789999999992,0.13345279999999995,0.8566193000000005 +480.0,0.09563999999999993,0.13901999999999998,0.8129501000000005 +481.0,0.08729955000000002,0.14467639999999996,0.7705172999999997 +482.0,0.07930803999999997,0.15046930000000003,0.7294447999999996 +483.0,0.07171776000000002,0.15646190000000007,0.6899136000000001 +484.0,0.06458099000000005,0.1627177,0.6521048999999994 +485.0,0.05795000999999999,0.1692999999999999,0.6161999999999997 +486.0,0.05186210999999998,0.17624310000000007,0.5823286000000001 +487.0,0.046281519999999986,0.18355810000000003,0.5504162000000001 +488.0,0.041150880000000015,0.19127349999999999,0.5203375999999997 +489.0,0.03641283000000002,0.19941799999999987,0.49196729999999966 +490.0,0.03201,0.20802000000000004,0.46518000000000015 +491.0,0.027917199999999986,0.21711990000000006,0.4399246000000004 +492.0,0.02414440000000001,0.22673450000000003,0.41618360000000004 +493.0,0.020687000000000014,0.23685709999999996,0.3938822000000002 +494.0,0.017540400000000008,0.2474812000000001,0.37294590000000016 +495.0,0.0147,0.2586000000000001,0.35330000000000017 +496.0,0.012161790000000009,0.2701849000000002,0.33485779999999976 +497.0,0.009919960000000005,0.2822939,0.31755209999999995 +498.0,0.007967240000000002,0.2950504999999999,0.3013374999999998 +499.0,0.006296346,0.3085779999999998,0.2861685999999999 +500.0,0.004900000000000001,0.323,0.27200000000000013 +501.0,0.0037771730000000026,0.33840209999999965,0.25881709999999997 +502.0,0.0029453200000000013,0.35468580000000033,0.24648379999999995 +503.0,0.00242488,0.3716986000000001,0.23477179999999992 +504.0,0.0022362929999999994,0.3892875,0.22345330000000013 +505.0,0.0024000000000000002,0.40730000000000005,0.21229999999999988 +506.0,0.00292552,0.42562989999999995,0.20116920000000002 +507.0,0.0038365600000000014,0.4443096000000002,0.1901196000000001 +508.0,0.005174840000000002,0.46339440000000015,0.1792254 +509.0,0.006982079999999999,0.4829395000000003,0.16856080000000007 +510.0,0.009300000000000004,0.503,0.15820000000000004 +511.0,0.012149490000000008,0.5235693000000001,0.1481383 +512.0,0.015535880000000002,0.5445120000000002,0.13837579999999997 +513.0,0.01947752000000001,0.56569,0.1289941999999999 +514.0,0.02399277,0.5869653,0.12007510000000002 +515.0,0.02910000000000001,0.6082000000000002,0.11169999999999995 +516.0,0.03481484999999999,0.6293456000000002,0.10390479999999996 +517.0,0.041120159999999975,0.6503067999999996,0.09666748000000006 +518.0,0.047985040000000014,0.6708751999999998,0.08998272000000003 +519.0,0.05537861000000001,0.6908423999999994,0.08384531000000005 +520.0,0.06327000000000002,0.7100000000000004,0.07824999 +521.0,0.07163501,0.7281852,0.07320898999999999 +522.0,0.08046223999999992,0.7454636000000009,0.06867816000000004 +523.0,0.08973995999999998,0.7619693999999998,0.06456784000000006 +524.0,0.0994564499999999,0.7778367999999998,0.06078835000000003 +525.0,0.1096,0.7932,0.05725000999999996 +526.0,0.12016739999999992,0.8081104000000003,0.053904350000000004 +527.0,0.13111450000000008,0.8224962000000001,0.05074663999999996 +528.0,0.14236789999999996,0.8363067999999992,0.04775275999999996 +529.0,0.15385420000000005,0.8494916000000002,0.044898589999999954 +530.0,0.1655000000000002,0.8620000000000004,0.04215999999999998 +531.0,0.17725709999999995,0.8738107999999996,0.03950727999999999 +532.0,0.18914000000000003,0.8849624000000001,0.03693563999999998 +533.0,0.20116939999999991,0.8954936,0.03445836000000002 +534.0,0.2133658,0.9054431999999999,0.03208872000000002 +535.0,0.2257499,0.9148500999999997,0.029839999999999995 +536.0,0.23832090000000028,0.9237348,0.02771181 +537.0,0.2510667999999999,0.9320924000000005,0.025694439999999995 +538.0,0.2639922000000001,0.9399225999999996,0.023787159999999998 +539.0,0.27710170000000006,0.9472252000000003,0.02198925 +540.0,0.29040000000000005,0.9540000000000005,0.020299999999999988 +541.0,0.3038911999999999,0.9602561000000002,0.018718050000000003 +542.0,0.31757260000000004,0.9660074,0.01724036 +543.0,0.3314383999999999,0.9712606000000007,0.015863640000000012 +544.0,0.3454828000000002,0.9760224999999992,0.014584610000000001 +545.0,0.35970000000000024,0.9803,0.013399999999999987 +546.0,0.3740838999999999,0.9840923999999999,0.012307230000000004 +547.0,0.3886396000000001,0.9874182000000002,0.01130188000000001 +548.0,0.40337840000000014,0.9903128,0.010377920000000002 +549.0,0.4183115000000001,0.9928116,0.009529306 +550.0,0.4334499000000003,0.9949500999999998,0.008749998999999994 +551.0,0.4487952999999998,0.996710800000001,0.008035199999999994 +552.0,0.4643360000000001,0.9980982999999998,0.0073816 +553.0,0.4800639999999999,0.999112,0.0067854 +554.0,0.49597129999999995,0.9997482000000001,0.006242800000000003 +555.0,0.5120501,1.0,0.005749999000000004 +556.0,0.5282958999999999,0.9998567000000005,0.005303600000000001 +557.0,0.5446916,0.9993045999999997,0.004899800000000002 +558.0,0.5612094000000003,0.9983255,0.0045342 +559.0,0.5778215000000002,0.9968986999999998,0.0042024 +560.0,0.5945,0.9949999999999996,0.0039000000000000024 +561.0,0.6112209000000001,0.9926004999999997,0.0036232000000000005 +562.0,0.6279758,0.9897425999999998,0.0033706000000000022 +563.0,0.6447602000000001,0.9864443999999999,0.0031414000000000012 +564.0,0.6615696999999998,0.9827240999999997,0.0029347999999999996 +565.0,0.6783999999999999,0.9786,0.002749999000000003 +566.0,0.6952392,0.9740837000000004,0.0025851999999999993 +567.0,0.7120586000000005,0.9691712000000002,0.0024386000000000004 +568.0,0.7288283999999998,0.9638568,0.002309399999999999 +569.0,0.7455187999999994,0.9581348999999995,0.0021967999999999996 +570.0,0.7620999999999998,0.9520000000000002,0.0021000000000000007 +571.0,0.7785431999999999,0.9454503999999999,0.0020177330000000003 +572.0,0.7948255999999998,0.9384992000000003,0.0019482 +573.0,0.8109263999999998,0.9311627999999997,0.0018897999999999994 +574.0,0.8268248000000002,0.9234575999999997,0.0018409329999999992 +575.0,0.8424999999999995,0.9153999999999993,0.0017999999999999993 +576.0,0.8579324999999999,0.9070063999999999,0.001766266999999999 +577.0,0.8730816000000007,0.8982772000000008,0.0017378000000000007 +578.0,0.8878944000000004,0.8892047999999994,0.0017111999999999995 +579.0,0.9023181000000006,0.8797815999999993,0.001683067 +580.0,0.9162999999999998,0.87,0.0016500009999999986 +581.0,0.9297994999999998,0.8598612999999999,0.001610133 +582.0,0.9427984000000004,0.8493919999999997,0.0015643999999999999 +583.0,0.9552776000000001,0.8386220000000005,0.0015136000000000001 +584.0,0.9672179000000002,0.8275813000000001,0.001458533000000001 +585.0,0.9785999999999998,0.8163000000000004,0.0013999999999999993 +586.0,0.9893856000000003,0.8047947000000002,0.0013366669999999997 +587.0,0.9995487999999996,0.7930820000000003,0.00127 +588.0,1.0090892000000002,0.7811920000000002,0.0012049999999999997 +589.0,1.0180064000000004,0.7691546999999994,0.001146667 +590.0,1.0262999999999995,0.7569999999999996,0.0011 +591.0,1.0339826999999997,0.7447540999999999,0.0010688 +592.0,1.0409859999999995,0.7324224000000005,0.001049400000000001 +593.0,1.0471880000000002,0.7200035999999999,0.0010355999999999998 +594.0,1.0524667,0.7074964999999998,0.0010212000000000005 +595.0,1.0566999999999998,0.6949,0.0010000000000000002 +596.0,1.0597944,0.6822192,0.0009686399999999993 +597.0,1.0617991999999996,0.6694716,0.000929920000000001 +598.0,1.0628068000000002,0.6566743999999989,0.0008868799999999998 +599.0,1.062909600000001,0.6438447999999998,0.0008425599999999994 +600.0,1.0622000000000007,0.6309999999999999,0.0008000000000000001 +601.0,1.0607352,0.6181554999999999,0.0007609600000000003 +602.0,1.0584436,0.6053144,0.0007236799999999998 +603.0,1.0552244,0.5924756000000003,0.0006859199999999995 +604.0,1.0509768000000004,0.5796378999999999,0.0006454400000000003 +605.0,1.0456,0.5668,0.0005999999999999998 +606.0,1.0390369,0.5539611,0.0005478667 +607.0,1.0313608000000003,0.5411372000000001,0.0004916 +608.0,1.0226661999999997,0.5283528000000001,0.00043539999999999996 +609.0,1.0130476999999998,0.5156323,0.00038346669999999976 +610.0,1.0026,0.5029999999999999,0.00034 +611.0,0.9913674999999998,0.4904687999999999,0.00030725330000000006 +612.0,0.9793313999999995,0.47803040000000013,0.00028316000000000024 +613.0,0.9664915999999999,0.4656775999999999,0.00026544 +614.0,0.9528479000000004,0.4534032000000001,0.0002518133000000001 +615.0,0.9383999999999999,0.44120000000000026,0.0002400000000000001 +616.0,0.9231940000000002,0.42908,0.0002295467 +617.0,0.9072439999999998,0.41703599999999996,0.0002206399999999999 +618.0,0.8905020000000001,0.40503200000000017,0.0002119600000000001 +619.0,0.8729200000000003,0.39303199999999994,0.00020218669999999997 +620.0,0.8544499000000004,0.381,0.00019000000000000015 +621.0,0.8350840000000002,0.3689183999999999,0.0001742133 +622.0,0.814946,0.3568271999999999,0.00015564000000000008 +623.0,0.7941859999999997,0.34477679999999994,0.00013596000000000002 +624.0,0.7729540000000001,0.33281760000000005,0.00011685330000000006 +625.0,0.7514000000000007,0.321,0.00010000000000000006 +626.0,0.7295836000000001,0.30933810000000034,8.613333e-05 +627.0,0.7075887999999998,0.29785040000000024,7.460000000000004e-05 +628.0,0.6856022000000002,0.28659359999999995,6.499999999999994e-05 +629.0,0.6638103999999997,0.2756245000000001,5.693332999999998e-05 +630.0,0.6424000000000005,0.2650000000000002,4.9999989999999975e-05 +631.0,0.6215149000000003,0.2547632000000002,4.4160000000000004e-05 +632.0,0.6011138000000004,0.24488960000000004,3.948000000000005e-05 +633.0,0.5811051999999999,0.23533440000000005,3.572000000000002e-05 +634.0,0.5613976999999997,0.2260528000000001,3.263999999999999e-05 +635.0,0.5418999999999998,0.21700000000000005,2.9999999999999984e-05 +636.0,0.5225995000000003,0.20816160000000003,2.7653330000000004e-05 +637.0,0.5035464000000002,0.19954879999999997,2.555999999999998e-05 +638.0,0.48474359999999966,0.1911552,2.364e-05 +639.0,0.46619389999999994,0.18297440000000004,2.1813330000000005e-05 +640.0,0.44789999999999974,0.17499999999999993,2.0000000000000012e-05 +641.0,0.4298613,0.16722350000000008,1.813332999999999e-05 +642.0,0.41209800000000013,0.15964639999999997,1.62e-05 +643.0,0.39464399999999983,0.15227760000000007,1.4200000000000001e-05 +644.0,0.37753329999999996,0.1451259000000001,1.2133330000000013e-05 +645.0,0.36080000000000023,0.13819999999999996,9.999999999999999e-06 +646.0,0.34445629999999994,0.13150029999999988,7.733333e-06 +647.0,0.3285168000000001,0.12502480000000005,5.400000000000004e-06 +648.0,0.3130192,0.11877920000000002,3.200000000000003e-06 +649.0,0.2980010999999999,0.11276910000000007,1.3333330000000028e-06 +650.0,0.28349999999999986,0.10699999999999998,8.470329472543003e-22 +651.0,0.2695447999999999,0.1014762,-1.0587911840678754e-22 +652.0,0.25611840000000013,0.09618863999999999,0.0 +653.0,0.24318960000000006,0.09112296000000006,9.4039548065783e-38 +654.0,0.23072719999999997,0.08626485000000006,-2.350988701644575e-38 +655.0,0.21869999999999992,0.08159999999999999,-1.4693679385278594e-39 +656.0,0.20709709999999987,0.07712064,0.0 +657.0,0.19592320000000005,0.07282551999999995,0.0 +658.0,0.18517079999999983,0.06871007999999995,0.0 +659.0,0.17483229999999994,0.06476976000000004,0.0 +660.0,0.16489999999999994,0.060999999999999985,0.0 +661.0,0.1553667,0.05739621000000002,0.0 +662.0,0.14623000000000014,0.05395504000000001,0.0 +663.0,0.13749000000000008,0.05067376000000004,0.0 +664.0,0.1291467,0.047549650000000006,0.0 +665.0,0.12119999999999999,0.04457999999999998,0.0 +666.0,0.11363969999999993,0.04175872,0.0 +667.0,0.106465,0.03908496000000001,0.0 +668.0,0.09969044000000007,0.03656384,0.0 +669.0,0.09333061,0.03420048000000002,0.0 +670.0,0.08739999999999995,0.032,0.0 +671.0,0.08190095999999998,0.029962610000000008,0.0 +672.0,0.07680427999999997,0.028076639999999986,0.0 +673.0,0.07207712,0.026329359999999982,0.0 +674.0,0.06768664000000005,0.024708050000000002,0.0 +675.0,0.06359999999999999,0.0232,0.0 +676.0,0.05980684999999997,0.02180077000000001,0.0 +677.0,0.056282159999999956,0.020501119999999984,0.0 +678.0,0.05297104000000001,0.019281079999999996,0.0 +679.0,0.04981860999999997,0.018120690000000002,0.0 +680.0,0.04676999999999999,0.017,0.0 +681.0,0.04378404999999999,0.015903789999999998,0.0 +682.0,0.040875360000000034,0.014837180000000005,0.0 +683.0,0.03807263999999997,0.013810679999999999,0.0 +684.0,0.03540461000000001,0.012834779999999992,0.0 +685.0,0.032899999999999985,0.011920000000000004,0.0 +686.0,0.030564189999999998,0.01106831,0.0 +687.0,0.02838055999999999,0.010273389999999992,0.0 +688.0,0.02634484,0.009533310999999997,0.0 +689.0,0.024452750000000013,0.008846157000000004,0.0 +690.0,0.022699999999999998,0.008209999999999995,0.0 +691.0,0.02108429,0.007623780999999998,0.0 +692.0,0.01959988000000001,0.007085424000000003,0.0 +693.0,0.018237320000000005,0.006591475999999998,0.0 +694.0,0.016987170000000003,0.006138484999999998,0.0 +695.0,0.01583999999999999,0.005723000000000002,0.0 +696.0,0.014790639999999999,0.005343058999999998,0.0 +697.0,0.01383132,0.004995795999999999,0.0 +698.0,0.012948679999999995,0.004676404000000002,0.0 +699.0,0.012129200000000003,0.004380075,0.0 +700.0,0.01135916,0.004102,0.0 +701.0,0.010629350000000008,0.0038384530000000004,0.0 +702.0,0.009938846000000003,0.0035890990000000005,0.0 +703.0,0.009288422000000005,0.0033542189999999994,0.0 +704.0,0.008678854,0.003134092999999998,0.0 +705.0,0.008110916,0.0029289999999999993,0.0 +706.0,0.007582387999999997,0.002738139,0.0 +707.0,0.007088746000000002,0.002559876,0.0 +708.0,0.006627312999999999,0.0023932439999999984,0.0 +709.0,0.006195408000000001,0.0022372750000000004,0.0 +710.0,0.005790345999999997,0.002091,0.0 +711.0,0.005409826000000002,0.001953587,0.0 +712.0,0.005052582999999998,0.0018245799999999986,0.0 +713.0,0.004717511999999999,0.0017035800000000003,0.0 +714.0,0.004403506999999996,0.0015901869999999996,0.0 +715.0,0.004109456999999997,0.0014839999999999999,0.0 +716.0,0.003833912999999999,0.001384496,0.0 +717.0,0.003575748000000001,0.0012912680000000006,0.0 +718.0,0.003334341999999998,0.0012040920000000006,0.0 +719.0,0.003109075000000001,0.0011227440000000002,0.0 +720.0,0.0028993269999999997,0.0010469999999999998,0.0 +721.0,0.0027043480000000023,0.0009765895999999997,0.0 +722.0,0.002523020000000001,0.0009111087999999995,0.0 +723.0,0.0023541680000000007,0.0008501332000000003,0.0 +724.0,0.0021966159999999985,0.0007932384000000003,0.0 +725.0,0.00204919,0.0007400000000000001,0.0 +726.0,0.0019109600000000002,0.0006900827,0.0 +727.0,0.0017814379999999996,0.0006433099999999999,0.0 +728.0,0.0016601099999999994,0.0005994959999999996,0.0 +729.0,0.0015464589999999994,0.0005584546999999996,0.0 +730.0,0.0014399709999999993,0.00052,0.0 +731.0,0.001340042,0.00048391359999999987,0.0 +732.0,0.0012462749999999998,0.00045005279999999994,0.0 +733.0,0.0011584709999999997,0.0004183451999999998,0.0 +734.0,0.0010764299999999997,0.00038871839999999995,0.0 +735.0,0.0009999492999999996,0.00036109999999999983,0.0 +736.0,0.0009287358000000005,0.00033538350000000003,0.0 +737.0,0.0008624332000000008,0.00031144040000000004,0.0 +738.0,0.0008007502999999999,0.0002891656000000002,0.0 +739.0,0.0007433960000000001,0.0002684539000000001,0.0 +740.0,0.0006900785999999998,0.0002491999999999999,0.0 +741.0,0.0006405155999999996,0.00023130189999999998,0.0 +742.0,0.0005945020999999998,0.0002146855999999999,0.0 +743.0,0.0005518645999999999,0.00019928839999999989,0.0 +744.0,0.0005124289999999999,0.00018504750000000007,0.0 +745.0,0.0004760213,0.0001719,0.0 +746.0,0.00044245360000000003,0.00015977810000000002,0.0 +747.0,0.0004115116999999998,0.00014860440000000002,0.0 +748.0,0.00038298140000000004,0.0001383015999999999,0.0 +749.0,0.00035664910000000026,0.00012879249999999995,0.0 +750.0,0.00033230110000000016,0.00012000000000000004,0.0 +751.0,0.0003097585999999999,0.00011185949999999995,0.0 +752.0,0.0002888871000000002,0.0001043223999999999,0.0 +753.0,0.00026953940000000004,9.73356e-05,0.0 +754.0,0.00025156820000000004,9.084587000000001e-05,0.0 +755.0,0.00023482609999999992,8.480000000000003e-05,0.0 +756.0,0.00021917099999999983,7.914667000000001e-05,0.0 +757.0,0.0002045258,7.385800000000001e-05,0.0 +758.0,0.00019084049999999996,6.891600000000004e-05,0.0 +759.0,0.0001780653999999999,6.430266999999999e-05,0.0 +760.0,0.00016615050000000006,5.9999999999999995e-05,0.0 +761.0,0.00015502359999999994,5.598186999999995e-05,0.0 +762.0,0.0001446219,5.222560000000002e-05,0.0 +763.0,0.0001349098,4.87184e-05,0.0 +764.0,0.00012585200000000003,4.544746999999998e-05,0.0 +765.0,0.00011741299999999997,4.2399999999999974e-05,0.0 +766.0,0.00010955149999999994,3.956104e-05,0.0 +767.0,0.00010222449999999997,3.6915119999999976e-05,0.0 +768.0,9.539445000000005e-05,3.444868000000003e-05,0.0 +769.0,8.90239e-05,3.214816e-05,0.0 +770.0,8.307526999999999e-05,2.9999999999999984e-05,0.0 +771.0,7.751268999999995e-05,2.799124999999998e-05,0.0 +772.0,7.231304000000001e-05,2.611356000000001e-05,0.0 +773.0,6.745777999999999e-05,2.4360239999999997e-05,0.0 +774.0,6.292844000000005e-05,2.2724610000000013e-05,0.0 +775.0,5.870652000000001e-05,2.1200000000000027e-05,0.0 +776.0,5.4770279999999985e-05,1.9778550000000004e-05,0.0 +777.0,5.109917999999999e-05,1.845285e-05,0.0 +778.0,4.7676540000000027e-05,1.7216870000000002e-05,0.0 +779.0,4.448566999999998e-05,1.606459000000001e-05,0.0 +780.0,4.150994000000001e-05,1.4989999999999999e-05,0.0 diff --git a/crates/tm30/data/cmf_cie1964_10deg_380_780.csv b/crates/tm30/data/cmf_cie1964_10deg_380_780.csv new file mode 100644 index 0000000..5933efc --- /dev/null +++ b/crates/tm30/data/cmf_cie1964_10deg_380_780.csv @@ -0,0 +1,402 @@ +wavelength_nm,x_bar,y_bar,z_bar +380.0,0.00015995200000000004,1.7364e-05,0.0007047760000000002 +381.0,0.00021507999999999998,2.3327000000000002e-05,0.0009482299999999998 +382.0,0.00028748999999999995,3.1149999999999985e-05,0.0012682000000000001 +383.0,0.00038199000000000013,4.135e-05,0.0016861000000000003 +384.0,0.00050455,5.456000000000002e-05,0.0022285000000000004 +385.0,0.00066244,7.156e-05,0.002927800000000001 +386.0,0.0008645000000000004,9.329999999999999e-05,0.0038236999999999993 +387.0,0.0011215000000000008,0.00012086999999999996,0.0049642 +388.0,0.0014461600000000002,0.00015564,0.006406700000000001 +389.0,0.0018535899999999996,0.00019920000000000004,0.008219300000000006 +390.0,0.0023616,0.0002534,0.010482199999999997 +391.0,0.0029906000000000004,0.0003202000000000001,0.013289 +392.0,0.0037644999999999987,0.00040240000000000013,0.016747 +393.0,0.0047101999999999995,0.0005023000000000001,0.020980000000000006 +394.0,0.0058581000000000015,0.0006232,0.026127 +395.0,0.007242300000000001,0.0007684999999999999,0.03234399999999999 +396.0,0.008899600000000002,0.0009417,0.039802000000000004 +397.0,0.010870899999999998,0.0011478000000000003,0.048691000000000026 +398.0,0.013198899999999998,0.0013903000000000003,0.05921 +399.0,0.015929199999999998,0.0016739999999999997,0.07157600000000001 +400.0,0.019109700000000007,0.0020044,0.08601089999999999 +401.0,0.022787999999999992,0.002386,0.10273999999999998 +402.0,0.027011000000000007,0.002822,0.12200000000000001 +403.0,0.031829,0.0033190000000000008,0.14401999999999995 +404.0,0.037278000000000006,0.0038800000000000015,0.16899 +405.0,0.0434,0.004509,0.19712000000000005 +406.0,0.05022299999999999,0.005209000000000001,0.22857000000000002 +407.0,0.057764000000000024,0.005985000000000002,0.2634699999999999 +408.0,0.06603800000000001,0.006833000000000002,0.30189999999999995 +409.0,0.07503300000000002,0.007757,0.3438699999999999 +410.0,0.08473599999999998,0.008756000000000002,0.38936599999999993 +411.0,0.09504099999999999,0.009816,0.43796999999999997 +412.0,0.10583600000000001,0.010918000000000002,0.4892199999999997 +413.0,0.11706600000000002,0.012058,0.5429000000000002 +414.0,0.128682,0.013236999999999999,0.5988100000000001 +415.0,0.140638,0.014455999999999993,0.6567600000000001 +416.0,0.152893,0.015716999999999995,0.7165800000000001 +417.0,0.16541599999999998,0.017025000000000002,0.7781199999999999 +418.0,0.1781909999999999,0.018398999999999995,0.8413100000000001 +419.0,0.19121399999999994,0.019847999999999998,0.9061099999999996 +420.0,0.20449200000000012,0.021391000000000004,0.9725420000000005 +421.0,0.21764999999999993,0.022992000000000002,1.0389 +422.0,0.230267,0.024598000000000002,1.1030999999999997 +423.0,0.24231100000000003,0.026213,1.1651 +424.0,0.253793,0.02784100000000001,1.2249000000000003 +425.0,0.264737,0.029497000000000013,1.2824999999999998 +426.0,0.275195,0.03119499999999999,1.3382000000000003 +427.0,0.28530100000000014,0.032927000000000005,1.3926000000000003 +428.0,0.2951429999999999,0.034738,1.4461 +429.0,0.30486900000000006,0.036654000000000006,1.4993999999999996 +430.0,0.31467900000000004,0.038676,1.5534800000000002 +431.0,0.32435499999999995,0.04079200000000002,1.6071999999999997 +432.0,0.33356999999999987,0.04294600000000002,1.6588999999999996 +433.0,0.342243,0.04511400000000001,1.7082000000000006 +434.0,0.35031199999999996,0.04733299999999998,1.7547999999999995 +435.0,0.357719,0.04960199999999999,1.7985000000000002 +436.0,0.3644819999999998,0.05193400000000001,1.8391999999999997 +437.0,0.37049299999999985,0.054336999999999996,1.8766 +438.0,0.3757270000000001,0.056822000000000004,1.910499999999999 +439.0,0.38015800000000005,0.05939899999999999,1.9408000000000003 +440.0,0.3837340000000001,0.06207699999999999,1.9672799999999995 +441.0,0.3863269999999998,0.06473700000000003,1.9891000000000008 +442.0,0.3878579999999999,0.06728500000000003,2.0057000000000005 +443.0,0.38839600000000024,0.06976400000000005,2.0174 +444.0,0.38797800000000016,0.072218,2.0243999999999995 +445.0,0.386726,0.074704,2.0272999999999994 +446.0,0.38469599999999987,0.07727200000000001,2.0264000000000006 +447.0,0.38200599999999996,0.07997900000000001,2.0223 +448.0,0.37870899999999996,0.08287400000000002,2.0153000000000003 +449.0,0.37491499999999994,0.08600000000000003,2.0060000000000002 +450.0,0.370702,0.08945600000000001,1.9948000000000012 +451.0,0.366089,0.09294699999999996,1.9813999999999998 +452.0,0.361045,0.09627499999999997,1.9653 +453.0,0.3555179999999999,0.09953499999999998,1.9463999999999995 +454.0,0.3494859999999999,0.10282900000000006,1.9248 +455.0,0.34295699999999996,0.10625599999999999,1.9007000000000005 +456.0,0.33589299999999994,0.10990100000000003,1.874100000000001 +457.0,0.3282839999999999,0.11383500000000003,1.8450999999999997 +458.0,0.32015,0.11816699999999997,1.8138999999999994 +459.0,0.311475,0.122932,1.7806000000000006 +460.0,0.302273,0.1282010000000001,1.7453700000000003 +461.0,0.29285800000000006,0.13345700000000002,1.7091000000000003 +462.0,0.283502,0.138323,1.6722999999999997 +463.0,0.27404399999999995,0.14304199999999995,1.6346999999999994 +464.0,0.2642630000000001,0.14778700000000006,1.5956 +465.0,0.25408499999999995,0.15276099999999998,1.5549000000000004 +466.0,0.24339200000000002,0.15810199999999996,1.5121999999999993 +467.0,0.23218699999999998,0.16394099999999995,1.4673000000000005 +468.0,0.22048799999999993,0.170362,1.4198999999999995 +469.0,0.20819800000000002,0.17742500000000005,1.3700000000000003 +470.0,0.195618,0.18518999999999994,1.3175600000000005 +471.0,0.18303400000000009,0.19302499999999995,1.2623999999999997 +472.0,0.170222,0.20031300000000007,1.2049999999999998 +473.0,0.15734800000000004,0.20715599999999995,1.1466000000000003 +474.0,0.14464999999999995,0.213644,1.0879999999999999 +475.0,0.13234900000000005,0.21993999999999989,1.0302000000000002 +476.0,0.12058400000000004,0.22616999999999998,0.9738299999999998 +477.0,0.10945599999999997,0.23246699999999998,0.9194300000000002 +478.0,0.09904200000000003,0.2390249999999999,0.86746 +479.0,0.089388,0.2459969999999999,0.8182799999999998 +480.0,0.08050699999999998,0.25358900000000006,0.772125 +481.0,0.072034,0.2618759999999999,0.7282900000000002 +482.0,0.06371000000000002,0.2706430000000002,0.6860399999999998 +483.0,0.05569399999999998,0.279645,0.64553 +484.0,0.04811699999999999,0.288694,0.6068499999999998 +485.0,0.041072,0.297665,0.5700599999999998 +486.0,0.03464200000000001,0.30646899999999994,0.5352199999999999 +487.0,0.028895999999999998,0.31503499999999995,0.5023400000000001 +488.0,0.023876,0.323335,0.4714 +489.0,0.019628,0.331366,0.44238999999999995 +490.0,0.016172000000000002,0.3391330000000002,0.4152539999999998 +491.0,0.0133,0.34785999999999984,0.39002400000000015 +492.0,0.010759000000000001,0.3583259999999998,0.3663989999999999 +493.0,0.008541999999999994,0.37000100000000014,0.344015 +494.0,0.006660999999999997,0.3824639999999999,0.32268899999999984 +495.0,0.005131999999999998,0.39537900000000004,0.3023559999999999 +496.0,0.003981999999999999,0.40848200000000023,0.28303600000000007 +497.0,0.0032390000000000006,0.4215880000000001,0.26481600000000005 +498.0,0.0029339999999999987,0.43461899999999987,0.2478479999999999 +499.0,0.0031139999999999996,0.44760099999999975,0.23231800000000002 +500.0,0.003816,0.46077700000000016,0.21850200000000009 +501.0,0.005094999999999999,0.4743399999999999,0.20585099999999995 +502.0,0.006935999999999999,0.48819999999999986,0.193596 +503.0,0.009298999999999998,0.50234,0.18173599999999998 +504.0,0.012146999999999998,0.5167400000000001,0.1702809999999999 +505.0,0.015444000000000006,0.5313600000000003,0.15924899999999997 +506.0,0.01915600000000001,0.5461900000000001,0.14867300000000003 +507.0,0.02325,0.5611800000000001,0.138609 +508.0,0.027689999999999992,0.5762900000000001,0.12909600000000007 +509.0,0.032444000000000014,0.5915000000000001,0.120215 +510.0,0.037465,0.6067409999999996,0.11204399999999999 +511.0,0.042955999999999994,0.6221499999999998,0.10471000000000008 +512.0,0.04911399999999999,0.6378299999999999,0.09819599999999999 +513.0,0.05591999999999997,0.65371,0.09236099999999994 +514.0,0.06334899999999999,0.66968,0.08708800000000004 +515.0,0.07135799999999999,0.6856600000000003,0.082248 +516.0,0.07990100000000001,0.7015499999999999,0.07774400000000002 +517.0,0.08890899999999996,0.7172300000000004,0.073456 +518.0,0.09829300000000002,0.7325700000000002,0.06926799999999998 +519.0,0.10794900000000004,0.7474600000000001,0.06506000000000003 +520.0,0.11774900000000003,0.7617569999999999,0.06070899999999999 +521.0,0.12783900000000004,0.77534,0.056457000000000014 +522.0,0.13844999999999996,0.7882200000000001,0.05260899999999999 +523.0,0.14951600000000004,0.8004599999999998,0.049122 +524.0,0.16104100000000002,0.8121399999999999,0.04595399999999999 +525.0,0.172953,0.8233300000000001,0.04304999999999999 +526.0,0.18520900000000004,0.8341200000000003,0.040368 +527.0,0.19775499999999988,0.8445999999999999,0.03783900000000001 +528.0,0.21053800000000006,0.85487,0.03538399999999999 +529.0,0.22346000000000005,0.8650400000000003,0.032948999999999985 +530.0,0.23649100000000003,0.8752109999999999,0.030451000000000006 +531.0,0.24963300000000008,0.88537,0.028029 +532.0,0.262972,0.8953699999999998,0.025861999999999996 +533.0,0.2765150000000001,0.90515,0.02391999999999999 +534.0,0.29026899999999983,0.9146500000000002,0.022173999999999992 +535.0,0.3042129999999998,0.92381,0.02058399999999999 +536.0,0.318361,0.9325499999999999,0.019126999999999998 +537.0,0.33270499999999986,0.9408100000000001,0.017740000000000002 +538.0,0.3472319999999998,0.9485200000000001,0.016403000000000008 +539.0,0.3619260000000001,0.9556000000000001,0.015063999999999994 +540.0,0.3767719999999999,0.9619880000000001,0.013676000000000002 +541.0,0.3916829999999998,0.96754,0.012307999999999998 +542.0,0.4065940000000001,0.97223,0.011056000000000002 +543.0,0.4215390000000001,0.9761699999999998,0.009915000000000002 +544.0,0.43651700000000004,0.9794599999999998,0.008872000000000003 +545.0,0.45158400000000026,0.9822000000000001,0.007917999999999996 +546.0,0.4667820000000002,0.9845199999999997,0.007029999999999999 +547.0,0.4821470000000002,0.9865199999999996,0.006223000000000002 +548.0,0.49773799999999985,0.9883199999999998,0.0054529999999999995 +549.0,0.5136060000000002,0.9900199999999999,0.004714000000000001 +550.0,0.5298259999999998,0.9917610000000004,0.003988 +551.0,0.54644,0.9935300000000004,0.0032889999999999994 +552.0,0.5634259999999999,0.9952299999999996,0.002645999999999999 +553.0,0.5807260000000002,0.9967700000000002,0.0020629999999999997 +554.0,0.5982900000000003,0.99809,0.001533 +555.0,0.6160529999999999,0.99911,0.001091 +556.0,0.6339480000000001,0.9997699999999998,0.0007109999999999999 +557.0,0.6519010000000002,1.0,0.00040700000000000035 +558.0,0.6698240000000002,0.9997100000000003,0.00018400000000000014 +559.0,0.6876320000000002,0.9988500000000005,4.7000000000000085e-05 +560.0,0.7052239999999996,0.9973399999999998,-1.3552527156068805e-20 +561.0,0.722773,0.9952599999999998,1.6940658945086007e-21 +562.0,0.7404829999999998,0.9927400000000003,3.3881317890172014e-21 +563.0,0.7582730000000001,0.9897500000000002,0.0 +564.0,0.7760829999999999,0.9863000000000002,0.0 +565.0,0.7938319999999998,0.9823800000000003,0.0 +566.0,0.8114360000000004,0.9779799999999997,0.0 +567.0,0.8288220000000001,0.9731099999999998,0.0 +568.0,0.8458790000000003,0.9677400000000003,0.0 +569.0,0.8625249999999998,0.9618899999999997,0.0 +570.0,0.8786550000000003,0.9555520000000004,0.0 +571.0,0.8942079999999998,0.9486010000000002,0.0 +572.0,0.9092059999999997,0.9409810000000006,0.0 +573.0,0.9236720000000003,0.9327980000000002,0.0 +574.0,0.937638,0.9241580000000003,0.0 +575.0,0.9511619999999997,0.9151750000000003,0.0 +576.0,0.9642830000000001,0.905954,0.0 +577.0,0.9770679999999996,0.8966080000000005,0.0 +578.0,0.9895899999999995,0.8872490000000001,0.0 +579.0,1.0019100000000003,0.8779860000000004,0.0 +580.0,1.01416,0.8689339999999993,0.0 +581.0,1.0265000000000004,0.8601639999999997,0.0 +582.0,1.0387999999999997,0.8515190000000001,0.0 +583.0,1.0510000000000002,0.8429629999999998,0.0 +584.0,1.0628999999999995,0.8343930000000002,0.0 +585.0,1.0743,0.8256230000000001,0.0 +586.0,1.0852,0.8167639999999999,0.0 +587.0,1.0952,0.8075440000000002,0.0 +588.0,1.1042000000000007,0.7979469999999999,0.0 +589.0,1.1119999999999997,0.787893,0.0 +590.0,1.1185199999999997,0.7774050000000001,0.0 +591.0,1.1238000000000001,0.7664899999999997,0.0 +592.0,1.1279999999999997,0.7553090000000002,0.0 +593.0,1.1311000000000002,0.7438450000000002,0.0 +594.0,1.1332000000000004,0.7321900000000001,0.0 +595.0,1.1342999999999999,0.720353,0.0 +596.0,1.1342999999999996,0.7082810000000003,0.0 +597.0,1.1333,0.696055,0.0 +598.0,1.1312,0.6836210000000001,0.0 +599.0,1.1280999999999999,0.6710480000000003,0.0 +600.0,1.1239899999999996,0.6583410000000002,0.0 +601.0,1.1189000000000002,0.645545,0.0 +602.0,1.1129000000000004,0.632718,0.0 +603.0,1.1058999999999999,0.619815,0.0 +604.0,1.0979999999999999,0.6068870000000002,0.0 +605.0,1.0891,0.5938780000000001,0.0 +606.0,1.0792,0.580781,0.0 +607.0,1.0684000000000002,0.5676529999999997,0.0 +608.0,1.0566999999999998,0.55449,0.0 +609.0,1.0440000000000005,0.541228,0.0 +610.0,1.0304800000000005,0.527963,0.0 +611.0,1.0160000000000002,0.5146340000000001,0.0 +612.0,1.0008,0.5013629999999999,0.0 +613.0,0.9847899999999998,0.48812400000000006,0.0 +614.0,0.9680800000000005,0.47493500000000005,0.0 +615.0,0.95074,0.4618340000000001,0.0 +616.0,0.9327999999999999,0.4488229999999999,0.0 +617.0,0.9143399999999997,0.4359169999999999,0.0 +618.0,0.8953899999999997,0.4231530000000002,0.0 +619.0,0.8760300000000001,0.4105260000000001,0.0 +620.0,0.8562970000000003,0.398057,0.0 +621.0,0.8363499999999997,0.38583500000000015,0.0 +622.0,0.8162900000000002,0.37395100000000003,0.0 +623.0,0.7960500000000001,0.3623110000000001,0.0 +624.0,0.7756100000000004,0.35086300000000004,0.0 +625.0,0.7549300000000001,0.33955399999999997,0.0 +626.0,0.7339899999999999,0.328309,0.0 +627.0,0.7127800000000002,0.3171179999999999,0.0 +628.0,0.6912900000000003,0.30593599999999993,0.0 +629.0,0.6695200000000004,0.29473700000000014,0.0 +630.0,0.6474670000000002,0.283493,0.0 +631.0,0.6251100000000002,0.272222,0.0 +632.0,0.6025200000000003,0.26099000000000017,0.0 +633.0,0.57989,0.24987700000000007,0.0 +634.0,0.5573699999999998,0.23894599999999988,0.0 +635.0,0.5351099999999999,0.22825400000000004,0.0 +636.0,0.5132399999999999,0.21785299999999985,0.0 +637.0,0.49185999999999996,0.20778000000000002,0.0 +638.0,0.4710799999999999,0.19807199999999994,0.0 +639.0,0.45096000000000025,0.18874799999999997,0.0 +640.0,0.4315670000000002,0.17982800000000002,0.0 +641.0,0.41287,0.17128500000000002,0.0 +642.0,0.39475,0.16305899999999995,0.0 +643.0,0.37721000000000005,0.155151,0.0 +644.0,0.36019,0.14753499999999994,0.0 +645.0,0.34368999999999994,0.14021099999999997,0.0 +646.0,0.3276899999999999,0.13317000000000007,0.0 +647.0,0.31216999999999995,0.1264,0.0 +648.0,0.2971100000000001,0.11989200000000003,0.0 +649.0,0.28249999999999986,0.11364,0.0 +650.0,0.2683289999999999,0.107633,0.0 +651.0,0.25459,0.10186999999999999,0.0 +652.0,0.24129999999999996,0.096347,0.0 +653.0,0.22847999999999988,0.091063,0.0 +654.0,0.21614000000000005,0.08600999999999995,0.0 +655.0,0.20429999999999995,0.08118700000000002,0.0 +656.0,0.19295000000000004,0.076583,0.0 +657.0,0.18211000000000002,0.072198,0.0 +658.0,0.17176999999999998,0.068024,0.0 +659.0,0.16191999999999995,0.06405200000000001,0.0 +660.0,0.15256800000000004,0.06028100000000002,0.0 +661.0,0.14367000000000002,0.056696999999999984,0.0 +662.0,0.13519999999999996,0.05329199999999998,0.0 +663.0,0.12713,0.050059000000000006,0.0 +664.0,0.11948,0.046998,0.0 +665.0,0.11220999999999995,0.044095999999999996,0.0 +666.0,0.10530999999999999,0.04134500000000003,0.0 +667.0,0.09878600000000003,0.03875070000000003,0.0 +668.0,0.09261000000000003,0.03629779999999999,0.0 +669.0,0.08677299999999996,0.033983200000000005,0.0 +670.0,0.0812606,0.03180039999999999,0.0 +671.0,0.07604800000000002,0.029739499999999985,0.0 +672.0,0.07111399999999997,0.027791800000000002,0.0 +673.0,0.06645400000000003,0.02595510000000001,0.0 +674.0,0.062061999999999985,0.024226299999999996,0.0 +675.0,0.05793000000000002,0.022601699999999995,0.0 +676.0,0.05405000000000003,0.02107790000000001,0.0 +677.0,0.05041200000000001,0.019650500000000008,0.0 +678.0,0.04700600000000001,0.01831530000000001,0.0 +679.0,0.043822999999999994,0.017068600000000003,0.0 +680.0,0.04085080000000001,0.015905100000000002,0.0 +681.0,0.038071999999999995,0.0148183,0.0 +682.0,0.03546799999999998,0.013800799999999998,0.0 +683.0,0.033031,0.0128495,0.0 +684.0,0.030753,0.011960699999999998,0.0 +685.0,0.028623000000000003,0.0111303,0.0 +686.0,0.026635000000000006,0.0103555,0.0 +687.0,0.024781000000000004,0.009633200000000001,0.0 +688.0,0.023052,0.008959899999999996,0.0 +689.0,0.021441,0.008332400000000002,0.0 +690.0,0.019941299999999988,0.0077488,0.0 +691.0,0.018543999999999998,0.007204600000000006,0.0 +692.0,0.017241000000000006,0.006697499999999999,0.0 +693.0,0.016027,0.006225100000000001,0.0 +694.0,0.014895999999999993,0.0057849999999999985,0.0 +695.0,0.013842,0.0053751,0.0 +696.0,0.012862,0.004994100000000001,0.0 +697.0,0.011949000000000001,0.0046392,0.0 +698.0,0.011100000000000004,0.0043093,0.0 +699.0,0.010310999999999997,0.0040028,0.0 +700.0,0.009576879999999994,0.0037177400000000015,0.0 +701.0,0.008893999999999997,0.00345262,0.0 +702.0,0.008258099999999999,0.0032058299999999994,0.0 +703.0,0.007666400000000002,0.0029762299999999994,0.0 +704.0,0.007116299999999999,0.00276281,0.0 +705.0,0.0066052,0.0025645599999999996,0.0 +706.0,0.006130599999999997,0.002380480000000001,0.0 +707.0,0.005690299999999999,0.00220971,0.0 +708.0,0.005281899999999999,0.0020513199999999997,0.0 +709.0,0.0049032999999999985,0.0019044900000000007,0.0 +710.0,0.00455263,0.0017684699999999999,0.0 +711.0,0.004227500000000001,0.00164236,0.0 +712.0,0.0039258,0.0015253500000000002,0.0 +713.0,0.0036457000000000017,0.0014167199999999994,0.0 +714.0,0.003385899999999998,0.0013159499999999995,0.0 +715.0,0.0031447000000000003,0.00122239,0.0 +716.0,0.0029208,0.0011355500000000001,0.0 +717.0,0.002713,0.0010549400000000003,0.0 +718.0,0.0025202,0.0009801400000000002,0.0 +719.0,0.0023411000000000005,0.0009106600000000007,0.0 +720.0,0.0021749599999999992,0.0008461899999999999,0.0 +721.0,0.0020206,0.0007862900000000003,0.0 +722.0,0.0018772999999999995,0.0007306800000000003,0.0 +723.0,0.0017440999999999993,0.0006789899999999997,0.0 +724.0,0.0016204999999999998,0.0006310099999999997,0.0 +725.0,0.0015056999999999998,0.0005864399999999997,0.0 +726.0,0.0013992000000000006,0.00054511,0.0 +727.0,0.0013003999999999997,0.0005067200000000001,0.0 +728.0,0.0012087,0.0004711100000000003,0.0 +729.0,0.0011236,0.0004380500000000002,0.0 +730.0,0.0010447599999999996,0.0004074100000000001,0.0 +731.0,0.00097156,0.00037896199999999994,0.0 +732.0,0.0009035999999999995,0.000352543,0.0 +733.0,0.0008404800000000002,0.00032800099999999997,0.0 +734.0,0.0007818700000000002,0.0003052080000000001,0.0 +735.0,0.0007274499999999999,0.000284041,0.0 +736.0,0.0006769000000000001,0.00026437499999999996,0.0 +737.0,0.0006299599999999998,0.0002461089999999999,0.0 +738.0,0.0005863700000000002,0.00022914299999999996,0.0 +739.0,0.0005458700000000002,0.00021337599999999996,0.0 +740.0,0.000508258,0.0001987299999999999,0.0 +741.0,0.0004733000000000001,0.000185115,0.0 +742.0,0.00044080000000000004,0.00017245400000000003,0.0 +743.0,0.0004105799999999997,0.000160678,0.0 +744.0,0.0003824899999999999,0.00014973,0.0 +745.0,0.00035638,0.00013955000000000006,0.0 +746.0,0.00033211000000000015,0.00013008600000000001,0.0 +747.0,0.00030955,0.00012129000000000007,0.0 +748.0,0.00028858,0.00011310600000000005,0.0 +749.0,0.00026909000000000004,0.00010550100000000005,0.0 +750.0,0.0002509690000000001,9.842799999999999e-05,0.0 +751.0,0.00023413000000000006,9.185300000000002e-05,0.0 +752.0,0.00021847000000000004,8.573800000000001e-05,0.0 +753.0,0.00020391000000000002,8.004800000000002e-05,0.0 +754.0,0.00019035000000000007,7.475099999999996e-05,0.0 +755.0,0.00017773000000000005,6.981900000000002e-05,0.0 +756.0,0.0001659700000000001,6.522200000000002e-05,0.0 +757.0,0.00015502000000000013,6.0939000000000014e-05,0.0 +758.0,0.00014480000000000008,5.694200000000002e-05,0.0 +759.0,0.00013528000000000005,5.3217e-05,0.0 +760.0,0.00012639000000000001,4.9737000000000015e-05,0.0 +761.0,0.00011809999999999997,4.649099999999998e-05,0.0 +762.0,0.00011037000000000003,4.3464e-05,0.0 +763.0,0.00010315000000000001,4.063500000000001e-05,0.0 +764.0,9.642699999999998e-05,3.800000000000001e-05,0.0 +765.0,9.015099999999997e-05,3.554049999999998e-05,0.0 +766.0,8.429399999999999e-05,3.324479999999998e-05,0.0 +767.0,7.883e-05,3.110059999999999e-05,0.0 +768.0,7.372899999999997e-05,2.9098999999999994e-05,0.0 +769.0,6.896899999999998e-05,2.7230699999999993e-05,0.0 +770.0,6.452580000000003e-05,2.5485999999999986e-05,0.0 +771.0,6.0376e-05,2.385609999999999e-05,0.0 +772.0,5.6500000000000005e-05,2.2333200000000005e-05,0.0 +773.0,5.288e-05,2.091039999999999e-05,0.0 +774.0,4.949800000000002e-05,1.9580799999999997e-05,0.0 +775.0,4.633899999999998e-05,1.8338399999999997e-05,0.0 +776.0,4.3389e-05,1.7177699999999986e-05,0.0 +777.0,4.063400000000001e-05,1.60934e-05,0.0 +778.0,3.8060000000000025e-05,1.508e-05,0.0 +779.0,3.565700000000002e-05,1.4133600000000005e-05,0.0 +780.0,3.341169999999999e-05,1.3249e-05,0.0 diff --git a/crates/tm30/data/d_series_basis_380_780.csv b/crates/tm30/data/d_series_basis_380_780.csv new file mode 100644 index 0000000..4adfb67 --- /dev/null +++ b/crates/tm30/data/d_series_basis_380_780.csv @@ -0,0 +1,402 @@ +wavelength_nm,S0,S1,S2 +380.0,63.39999999999999,38.499999999999986,3.0 +381.0,63.38048,38.14512,2.7728 +382.0,63.65568,37.830639999999995,2.5828800000000003 +383.0,64.08688,37.524159999999995,2.41896 +384.0,64.44288,37.171679999999995,2.2622400000000007 +385.0,64.60000000000001,36.749999999999986,2.1000000000000014 +386.0,64.592,36.26928,1.93392 +387.0,64.37007999999999,35.71016,1.76376 +388.0,64.22335999999999,35.19704,1.5864000000000003 +389.0,64.60863999999998,34.92192,1.3990400000000005 +390.0,65.79999999999998,34.99999999999999,1.2000000000000015 +391.0,67.7272,35.4072,0.9903199999999999 +392.0,70.39616,36.15344,0.7727999999999999 +393.0,73.59711999999999,37.13768,0.5452799999999999 +394.0,76.98047999999997,38.191520000000004,0.3041599999999999 +395.0,80.29999999999995,39.20000000000001,0.04999999999999982 +396.0,83.58304,40.17776,-0.2156800000000001 +397.0,86.83872,41.12408,-0.49712000000000006 +398.0,89.91199999999999,42.0008,-0.7649600000000002 +399.0,92.60528,42.76751999999999,-0.9748000000000003 +400.0,94.79999999999997,43.399999999999984,-1.1000000000000008 +401.0,96.47688,43.883759999999995,-1.14504 +402.0,97.57,44.192,-1.10616 +403.0,98.28311999999998,44.39024,-1.0092800000000002 +404.0,98.95583999999997,44.58768,-0.8976000000000001 +405.0,99.79999999999994,44.85,-0.8000000000000003 +406.0,100.77808,45.16416,-0.71248 +407.0,101.91951999999999,45.54304,-0.63608 +408.0,103.10135999999999,45.92272,-0.5744799999999999 +409.0,104.10519999999997,46.1964,-0.5288799999999998 +410.0,104.79999999999995,46.3,-0.49999999999999967 +411.0,105.22224,46.247279999999996,-0.49144 +412.0,105.35655999999999,46.02712,-0.50728 +413.0,105.31287999999998,45.70096,-0.5391199999999999 +414.0,105.27439999999996,45.37120000000001,-0.5729599999999999 +415.0,105.34999999999992,45.10000000000001,-0.5999999999999999 +416.0,105.51728,44.87536,-0.62176 +417.0,105.79968,44.708560000000006,-0.6371199999999999 +418.0,106.07688,44.54536,-0.65048 +419.0,106.15008000000002,44.294160000000005,-0.6698399999999998 +420.0,105.90000000000002,43.90000000000001,-0.6999999999999995 +421.0,105.37816000000001,43.38352,-0.7399199999999999 +422.0,104.61728,42.752159999999996,-0.7908799999999999 +423.0,103.6524,42.032799999999995,-0.8478399999999999 +424.0,102.54191999999998,41.270239999999994,-0.9024000000000001 +425.0,101.34999999999997,40.499999999999986,-0.95 +426.0,100.08127999999999,39.72016,-0.9918399999999999 +427.0,98.702,38.924,-1.02624 +428.0,97.46832,38.171040000000005,-1.0630399999999998 +429.0,96.75864,37.54608,-1.1178399999999997 +430.0,96.80000000000001,37.10000000000001,-1.199999999999999 +431.0,97.56248,36.82928,-1.3067199999999999 +432.0,99.08752,36.74704,-1.43744 +433.0,101.13655999999997,36.7928,-1.58616 +434.0,103.31199999999997,36.86576,-1.74288 +435.0,105.34999999999992,36.9,-1.8999999999999995 +436.0,107.28815999999999,36.90544,-2.05808 +437.0,109.11416,36.8776,-2.21816 +438.0,110.81376,36.822559999999996,-2.37024 +439.0,112.40536000000002,36.759519999999995,-2.50032 +440.0,113.90000000000002,36.69999999999998,-2.6 +441.0,115.25496000000001,36.632400000000004,-2.66928 +442.0,116.42176,36.54696,-2.70504 +443.0,117.48056000000001,36.45352,-2.7188000000000003 +444.0,118.56496000000001,36.36848,-2.72976 +445.0,119.75000000000003,36.3,-2.750000000000001 +446.0,121.0176,36.245439999999995,-2.77744 +447.0,122.39096,36.20912,-2.8136 +448.0,123.73872,36.16439999999999,-2.85256 +449.0,124.85048000000002,36.06967999999999,-2.88352 +450.0,125.60000000000004,35.899999999999984,-2.899999999999999 +451.0,126.01151999999999,35.658879999999996,-2.90432 +452.0,126.06392,35.340399999999995,-2.89656 +453.0,125.88031999999998,34.97192,-2.8808 +454.0,125.66591999999997,34.59903999999999,-2.8638399999999997 +455.0,125.54999999999997,34.24999999999998,-2.8499999999999996 +456.0,125.5104,33.91968,-2.83856 +457.0,125.56312,33.612320000000004,-2.83 +458.0,125.64663999999999,33.309360000000005,-2.82264 +459.0,125.64815999999999,32.97840000000001,-2.8132800000000002 +460.0,125.49999999999997,32.600000000000016,-2.8000000000000003 +461.0,125.23096,32.18128,-2.78376 +462.0,124.85064000000001,31.723760000000002,-2.76504 +463.0,124.38832000000002,31.238240000000005,-2.74432 +464.0,123.89280000000004,30.742720000000006,-2.7224000000000004 +465.0,123.40000000000006,30.250000000000007,-2.7000000000000006 +466.0,122.90672,29.75872,-2.6771200000000004 +467.0,122.40952,29.26824,-2.6535200000000003 +468.0,121.94552,28.78776,-2.63112 +469.0,121.56552,28.329279999999997,-2.6127200000000004 +470.0,121.30000000000003,27.89999999999999,-2.600000000000001 +471.0,121.14256,27.49992,-2.5921600000000002 +472.0,121.09071999999999,27.130959999999998,-2.5883200000000004 +473.0,121.12288,26.784,-2.5884800000000006 +474.0,121.20303999999999,26.443839999999998,-2.5926400000000007 +475.0,121.29999999999995,26.099999999999998,-2.600000000000002 +476.0,121.41423999999999,25.75376,-2.61024 +477.0,121.55488,25.4052,-2.62448 +478.0,121.64751999999999,25.04984,-2.63472 +479.0,121.58415999999998,24.68248,-2.6289600000000006 +480.0,121.29999999999997,24.3,-2.600000000000001 +481.0,120.80672,23.90184,-2.5492 +482.0,120.10032,23.48664,-2.4759200000000003 +483.0,119.23792,23.059440000000002,-2.3866400000000003 +484.0,118.31472000000001,22.628640000000004,-2.2921600000000004 +485.0,117.40000000000003,22.200000000000006,-2.200000000000001 +486.0,116.4872,21.7728,-2.10928 +487.0,115.57072000000001,21.34704,-2.0198400000000003 +488.0,114.71504,20.924879999999998,-1.9356 +489.0,114.00735999999999,20.508719999999997,-1.8613600000000001 +490.0,113.49999999999999,20.099999999999987,-1.8000000000000003 +491.0,113.19208,19.699920000000002,-1.75208 +492.0,113.09863999999999,19.31088,-1.7192 +493.0,113.15319999999998,18.92784,-1.69632 +494.0,113.24495999999998,18.5424,-1.67504 +495.0,113.29999999999994,18.15,-1.6500000000000006 +496.0,113.32864,17.751839999999998,-1.62208 +497.0,113.32799999999999,17.346239999999998,-1.59072 +498.0,113.29015999999999,16.943039999999996,-1.55776 +499.0,113.21431999999997,16.557839999999995,-1.5268000000000002 +500.0,113.09999999999994,16.199999999999992,-1.5000000000000007 +501.0,112.93679999999999,15.86632,-1.47648 +502.0,112.71256,15.555439999999999,-1.45616 +503.0,112.45032,15.262559999999997,-1.43784 +504.0,112.18848,14.979679999999993,-1.41952 +505.0,111.95,14.699999999999987,-1.4000000000000001 +506.0,111.73024000000001,14.42368,-1.3795199999999999 +507.0,111.53392,14.15256,-1.35784 +508.0,111.3372,13.87144,-1.33616 +509.0,111.10048,13.558319999999998,-1.3164800000000003 +510.0,110.80000000000001,13.2,-1.3000000000000007 +511.0,110.44727999999999,12.79928,-1.2863200000000001 +512.0,110.05120000000001,12.35624,-1.27536 +513.0,109.61512,11.881200000000002,-1.2664 +514.0,109.14464000000002,11.391360000000004,-1.2582400000000002 +515.0,108.65000000000003,10.900000000000007,-1.2500000000000002 +516.0,108.13328,10.40624,-1.24176 +517.0,107.58552,9.908000000000001,-1.2336 +518.0,107.07216000000001,9.424560000000001,-1.22464 +519.0,106.69080000000001,8.983120000000003,-1.2136799999999999 +520.0,106.50000000000001,8.600000000000005,-1.2 +521.0,106.48776,8.27488,-1.18336 +522.0,106.65696,8.013359999999999,-1.16304 +523.0,106.95815999999999,7.793839999999999,-1.14072 +524.0,107.30896,7.580319999999999,-1.1191999999999998 +525.0,107.64999999999998,7.349999999999997,-1.0999999999999996 +526.0,107.9872,7.106719999999999,-1.0827200000000001 +527.0,108.32456,6.84784,-1.06792 +528.0,108.61232,6.58296,-1.05232 +529.0,108.78407999999999,6.33008,-1.0307199999999999 +530.0,108.79999999999995,6.100000000000001,-0.9999999999999999 +531.0,108.66087999999999,5.8880799999999995,-0.96104 +532.0,108.35632,5.69296,-0.91392 +533.0,107.93575999999999,5.5098400000000005,-0.8608 +534.0,107.48159999999999,5.330720000000001,-0.8052799999999999 +535.0,107.04999999999995,5.150000000000003,-0.7499999999999998 +536.0,106.63376,4.96832,-0.69472 +537.0,106.23335999999999,4.78584,-0.6392 +538.0,105.86655999999999,4.599360000000001,-0.5860799999999999 +539.0,105.55175999999999,4.404880000000001,-0.53896 +540.0,105.29999999999997,4.200000000000002,-0.4999999999999999 +541.0,105.11359999999999,3.9847200000000003,-0.46912 +542.0,104.99575999999999,3.75856,-0.44688 +543.0,104.92991999999998,3.5244000000000004,-0.43064 +544.0,104.88847999999996,3.287040000000001,-0.41600000000000004 +545.0,104.84999999999992,3.0500000000000025,-0.40000000000000013 +546.0,104.81584,2.81296,-0.38304 +547.0,104.78952,2.5755999999999997,-0.36504000000000003 +548.0,104.7388,2.34144,-0.34543999999999997 +549.0,104.61808,2.11528,-0.32383999999999996 +550.0,104.40000000000003,1.9,-0.29999999999999993 +551.0,104.08632,1.6958399999999998,-0.27368 +552.0,103.67,1.5042399999999998,-0.24463999999999997 +553.0,103.18368000000001,1.3206399999999998,-0.2136 +554.0,102.68176000000001,1.1374399999999998,-0.18175999999999995 +555.0,102.2,0.9499999999999996,-0.14999999999999997 +556.0,101.73312,0.7592,-0.11823999999999998 +557.0,101.28328,0.56424,-0.08639999999999999 +558.0,100.84904000000002,0.3688800000000001,-0.055360000000000006 +559.0,100.42280000000002,0.17952000000000023,-0.026319999999999996 +560.0,100.00000000000004,6.661338147750939e-16,2.7755575615628914e-17 +561.0,99.58808,-0.17104000000000003,0.023680000000000003 +562.0,99.19544,-0.33392000000000005,0.04464 +563.0,98.8108,-0.49080000000000007,0.0636 +564.0,98.41535999999999,-0.6452800000000002,0.08176 +565.0,97.99999999999999,-0.8,0.1 +566.0,97.56784,-0.95472,0.11824000000000001 +567.0,97.1136,-1.1092000000000002,0.13640000000000002 +568.0,96.67016,-1.26608,0.15536 +569.0,96.28872,-1.4289600000000005,0.17632000000000003 +570.0,96.00000000000001,-1.6000000000000005,0.20000000000000007 +571.0,95.79432,-1.7776800000000001,0.22744 +572.0,95.66816,-1.95968,0.26096 +573.0,95.604,-2.14768,0.29647999999999997 +574.0,95.57263999999999,-2.34448,0.32719999999999994 +575.0,95.54999999999998,-2.5499999999999994,0.34999999999999987 +576.0,95.53696,-2.7632,0.36607999999999996 +577.0,95.5392,-2.9868799999999998,0.37327999999999995 +578.0,95.50863999999999,-3.2017599999999997,0.38527999999999996 +579.0,95.37607999999997,-3.3786400000000003,0.4232799999999999 +580.0,95.09999999999994,-3.500000000000001,0.49999999999999994 +581.0,94.68951999999999,-3.57024,0.6128 +582.0,94.14583999999999,-3.58976,0.76288 +583.0,93.50016,-3.5712800000000002,0.93896 +584.0,92.80448,-3.5360000000000005,1.1222400000000003 +585.0,92.1,-3.5000000000000013,1.3000000000000003 +586.0,91.38448,-3.46208,1.4739200000000001 +587.0,90.65016,-3.42008,1.64376 +588.0,89.96583999999999,-3.39488,1.8064 +589.0,89.42951999999998,-3.4156800000000005,1.95904 +590.0,89.09999999999997,-3.500000000000001,2.1 +591.0,88.97232,-3.64648,2.22784 +592.0,89.05984,-3.85888,2.3404 +593.0,89.29536,-4.11728,2.44296 +594.0,89.56688000000001,-4.388480000000001,2.54432 +595.0,89.80000000000001,-4.650000000000001,2.65 +596.0,90.00528,-4.9048,2.75904 +597.0,90.17936,-5.15248,2.87216 +598.0,90.31744,-5.387359999999999,2.9864800000000002 +599.0,90.42352,-5.604239999999999,3.0968000000000004 +600.0,90.5,-5.799999999999998,3.2 +601.0,90.53624,-5.9723999999999995,3.2969600000000003 +602.0,90.52104,-6.11816,3.38728 +603.0,90.47384000000001,-6.24592,3.4736000000000002 +604.0,90.42704000000002,-6.37008,3.56032 +605.0,90.40000000000003,-6.499999999999999,3.65 +606.0,90.3888,-6.63424,3.7420799999999996 +607.0,90.39744,-6.77352,3.8371999999999997 +608.0,90.40567999999999,-6.9164,3.9319199999999994 +609.0,90.37991999999998,-7.05928,4.020639999999999 +610.0,90.29999999999995,-7.200000000000001,4.099999999999999 +611.0,90.16919999999999,-7.3396,4.17064 +612.0,89.98208,-7.478000000000001,4.23192 +613.0,89.76095999999998,-7.6164000000000005,4.2871999999999995 +614.0,89.54303999999998,-7.756800000000002,4.34208 +615.0,89.34999999999997,-7.900000000000004,4.4 +616.0,89.17712,-8.0456,4.46032 +617.0,89.02976,-8.1944,4.5236 +618.0,88.8792,-8.341199999999999,4.58728 +619.0,88.67864000000002,-8.478,4.64696 +620.0,88.40000000000003,-8.599999999999998,4.7 +621.0,88.0544,-8.7084,4.74816 +622.0,87.64800000000001,-8.8032,4.79328 +623.0,87.1916,-8.888,4.834400000000001 +624.0,86.7032,-8.968799999999998,4.869920000000002 +625.0,86.19999999999999,-9.049999999999997,4.900000000000003 +626.0,85.6824,-9.131200000000002,4.92528 +627.0,85.1436,-9.212,4.944 +628.0,84.63680000000001,-9.2968,4.968319999999999 +629.0,84.24000000000002,-9.391599999999999,5.016639999999998 +630.0,84.00000000000004,-9.499999999999998,5.099999999999997 +631.0,83.90856,-9.62072,5.215999999999999 +632.0,83.9696,-9.7524,5.36512 +633.0,84.14063999999999,-9.894079999999999,5.53824 +634.0,84.35087999999999,-10.044159999999998,5.720160000000001 +635.0,84.54999999999997,-10.199999999999994,5.900000000000002 +636.0,84.74336,-10.36112,6.078880000000001 +637.0,84.93343999999999,-10.529679999999999,6.25744 +638.0,85.08431999999999,-10.68984,6.4272 +639.0,85.14919999999998,-10.818000000000001,6.57696 +640.0,85.09999999999995,-10.900000000000004,6.699999999999998 +641.0,84.93791999999999,-10.9388,6.79656 +642.0,84.65791999999999,-10.93384,6.8652 +643.0,84.29192,-10.896880000000001,6.91384 +644.0,83.89312000000001,-10.847520000000001,6.95568 +645.0,83.50000000000001,-10.800000000000002,6.999999999999999 +646.0,83.1088,-10.75296,7.04576 +647.0,82.71672,-10.70528,7.09264 +648.0,82.35744,-10.67,7.14632 +649.0,82.07616,-10.664719999999997,7.214 +650.0,81.89999999999999,-10.699999999999996,7.3 +651.0,81.83088000000001,-10.77656,7.40472 +652.0,81.88104,-10.899199999999999,7.52992 +653.0,82.0092,-11.05184,7.6691199999999995 +654.0,82.14656,-11.20768,7.81152 +655.0,82.24999999999999,-11.350000000000001,7.949999999999999 +656.0,82.32704,-11.48176,8.0856 +657.0,82.372,-11.600639999999999,8.21792 +658.0,82.40776,-11.71632,8.34704 +659.0,82.47551999999999,-11.845999999999997,8.474159999999998 +660.0,82.6,-11.999999999999995,8.599999999999996 +661.0,82.76768,-12.17288,8.722959999999999 +662.0,82.96856,-12.36072,8.84104 +663.0,83.20143999999999,-12.56256,8.95712 +664.0,83.46432,-12.776800000000001,9.075999999999999 +665.0,83.75000000000001,-13.000000000000002,9.199999999999998 +666.0,84.05632,-13.23136,9.32832 +667.0,84.39144,-13.47416,9.46232 +668.0,84.69656,-13.704559999999999,9.593520000000002 +669.0,84.88368000000001,-13.88696,9.708720000000003 +670.0,84.90000000000002,-13.999999999999998,9.800000000000004 +671.0,84.74776,-14.04544,9.86696 +672.0,84.40696,-14.016960000000001,9.904720000000001 +673.0,83.94816,-13.94048,9.92648 +674.0,83.48895999999999,-13.859200000000001,9.95424 +675.0,83.09999999999998,-13.800000000000002,10.000000000000002 +676.0,82.76719999999999,-13.758080000000001,10.06064 +677.0,82.50456,-13.73728,10.14048 +678.0,82.24231999999999,-13.72128,10.214319999999999 +679.0,81.86408,-13.68128,10.242159999999998 +680.0,81.3,-13.6,10.199999999999998 +681.0,80.57824,-13.48552,10.09536 +682.0,79.71311999999999,-13.34248,9.93032 +683.0,78.73199999999999,-13.17544,9.71928 +684.0,77.68047999999997,-12.991999999999999,9.48624 +685.0,76.59999999999997,-12.799999999999999,9.250000000000002 +686.0,75.49072,-12.59984,9.00944 +687.0,74.33840000000001,-12.38784,8.761280000000001 +688.0,73.25648000000001,-12.19224,8.535120000000001 +689.0,72.41056000000002,-12.05464,8.372959999999999 +690.0,71.90000000000002,-11.999999999999996,8.299999999999999 +691.0,71.71496,-12.02424,8.31288 +692.0,71.87848,-12.13024,8.41472 +693.0,72.27799999999999,-12.29424,8.58056 +694.0,72.72591999999999,-12.47664,8.768799999999999 +695.0,73.09999999999998,-12.649999999999997,8.949999999999998 +696.0,73.41888,-12.8176,9.12736 +697.0,73.6736,-12.979840000000001,9.302159999999999 +698.0,73.87992,-13.12368,9.454559999999999 +699.0,74.08024,-13.233520000000002,9.558959999999999 +700.0,74.30000000000001,-13.300000000000004,9.599999999999998 +701.0,74.50864,-13.31968,9.57608 +702.0,74.67191999999999,-13.28448,9.48016 +703.0,74.82919999999999,-13.21528,9.336239999999998 +704.0,75.04607999999998,-13.14688,9.184319999999998 +705.0,75.34999999999997,-13.099999999999998,9.049999999999994 +706.0,75.72832,-13.0704,8.929120000000001 +707.0,76.2056,-13.062479999999999,8.824240000000001 +708.0,76.62328000000001,-13.05376,8.727360000000001 +709.0,76.73696000000001,-13.00704,8.62248 +710.0,76.40000000000002,-12.899999999999999,8.499999999999998 +711.0,75.65440000000001,-12.74104,8.36608 +712.0,74.51048,-12.533760000000001,8.22536 +713.0,73.06256,-12.28848,8.07664 +714.0,71.46784,-12.022400000000001,7.91792 +715.0,69.85000000000001,-11.750000000000004,7.749999999999998 +716.0,68.20192,-11.47088,7.57392 +717.0,66.50135999999999,-11.18128,7.38664 +718.0,64.9476,-10.912479999999999,7.20936 +719.0,63.823840000000004,-10.709679999999999,7.0740799999999995 +720.0,63.30000000000001,-10.599999999999996,6.999999999999999 +721.0,63.363519999999994,-10.58088,6.98424 +722.0,64.056,-10.658479999999999,7.0301599999999995 +723.0,65.17848,-10.802079999999998,7.11808 +724.0,66.39935999999999,-10.960479999999997,7.215199999999999 +725.0,67.49999999999996,-11.099999999999994,7.3 +726.0,68.51232,-11.2256,7.37568 +727.0,69.42408,-11.33528,7.44088 +728.0,70.23744,-11.430159999999999,7.496879999999999 +729.0,70.98880000000001,-11.517039999999996,7.548879999999998 +730.0,71.70000000000003,-11.599999999999994,7.599999999999996 +731.0,72.32792,-11.67232,7.64584 +732.0,72.82304,-11.72656,7.68168 +733.0,73.25616000000001,-11.7728,7.71352 +734.0,73.74528000000001,-11.827839999999998,7.751359999999999 +735.0,74.35000000000004,-11.899999999999997,7.8 +736.0,75.05167999999999,-11.98656,7.85776 +737.0,75.88016,-12.092,7.9275199999999995 +738.0,76.65264,-12.18864,7.99128 +739.0,77.08312000000001,-12.233279999999999,8.02104 +740.0,77.00000000000001,-12.2,7.999999999999997 +741.0,76.43104,-12.093279999999998,7.93104 +742.0,75.34224,-11.908639999999998,7.81128 +743.0,73.91144,-11.671999999999999,7.65752 +744.0,72.43504000000001,-11.42656,7.4977599999999995 +745.0,71.10000000000004,-11.200000000000001,7.3500000000000005 +746.0,69.8744,-10.987839999999998,7.21136 +747.0,68.78104,-10.7928,7.08352 +748.0,67.73328000000001,-10.60656,6.961679999999999 +749.0,66.57152000000002,-10.412320000000001,6.835839999999999 +750.0,65.20000000000003,-10.200000000000003,6.6999999999999975 +751.0,63.68592,-9.97904,6.560160000000001 +752.0,62.09528,-9.760159999999999,6.42328 +753.0,60.390640000000005,-9.533280000000001,6.282400000000001 +754.0,58.50960000000001,-9.281600000000001,6.125920000000002 +755.0,56.45000000000002,-9.000000000000004,5.950000000000003 +756.0,54.23344,-8.69248,5.757280000000001 +757.0,51.80304,-8.35008,5.542000000000001 +758.0,49.549040000000005,-8.03248,5.342320000000001 +759.0,48.06304000000001,-7.8308800000000005,5.216640000000002 +760.0,47.70000000000002,-7.800000000000002,5.200000000000003 +761.0,48.388000000000005,-7.92784,5.28456 +762.0,50.15384,-8.21728,5.47192 +763.0,52.68767999999999,-8.62272,5.733280000000001 +764.0,55.47311999999999,-9.068159999999999,6.020640000000001 +765.0,58.14999999999997,-9.5,6.3000000000000025 +766.0,60.76016,-9.92416,6.5750399999999996 +767.0,63.312079999999995,-10.34272,6.84728 +768.0,65.6124,-10.721279999999998,7.093520000000001 +769.0,67.42272,-11.015839999999997,7.283760000000002 +770.0,68.6,-11.199999999999996,7.400000000000003 +771.0,69.12567999999999,-11.272,7.44144 +772.0,68.93719999999999,-11.22208,7.4019200000000005 +773.0,68.25872,-11.08816,7.3064 +774.0,67.46383999999999,-10.933440000000001,7.196479999999999 +775.0,66.79999999999998,-10.8,7.099999999999999 +776.0,66.23168,-10.681920000000002,7.01312 +777.0,65.77112,-10.580960000000001,6.9368 +778.0,65.42696,-10.5008,6.874879999999999 +779.0,65.17479999999998,-10.44064,6.8289599999999995 +780.0,64.99999999999996,-10.4,6.799999999999999 diff --git a/crates/tm30/data/tcs_cie2017_380_780.csv b/crates/tm30/data/tcs_cie2017_380_780.csv new file mode 100644 index 0000000..af69e44 --- /dev/null +++ b/crates/tm30/data/tcs_cie2017_380_780.csv @@ -0,0 +1,402 @@ +wavelength_nm,TCS00,TCS01,TCS02,TCS03,TCS04,TCS05,TCS06,TCS07,TCS08,TCS09,TCS10,TCS11,TCS12,TCS13,TCS14,TCS15,TCS16,TCS17,TCS18,TCS19,TCS20,TCS21,TCS22,TCS23,TCS24,TCS25,TCS26,TCS27,TCS28,TCS29,TCS30,TCS31,TCS32,TCS33,TCS34,TCS35,TCS36,TCS37,TCS38,TCS39,TCS40,TCS41,TCS42,TCS43,TCS44,TCS45,TCS46,TCS47,TCS48,TCS49,TCS50,TCS51,TCS52,TCS53,TCS54,TCS55,TCS56,TCS57,TCS58,TCS59,TCS60,TCS61,TCS62,TCS63,TCS64,TCS65,TCS66,TCS67,TCS68,TCS69,TCS70,TCS71,TCS72,TCS73,TCS74,TCS75,TCS76,TCS77,TCS78,TCS79,TCS80,TCS81,TCS82,TCS83,TCS84,TCS85,TCS86,TCS87,TCS88,TCS89,TCS90,TCS91,TCS92,TCS93,TCS94,TCS95,TCS96,TCS97,TCS98 +380.0,0.6359,0.2615,1e-05,0.47376,0.13351,0.04525,0.0583,0.05818,0.04157,0.19983,0.03951,0.24167,0.04337,0.3414,0.16992,0.03466,0.0308,0.0731,0.1202,0.02509,0.12356,0.00012,0.37853,0.2515,0.10281,0.1688,0.06462,0.0458,0.03981,0.03043,0.04401,0.0429,0.17315,0.04389,0.05245,0.03431,0.05028,0.11323,0.04566,0.075,0.4098,0.06598,0.0671,0.0439,0.0554,0.1126,0.1446,0.08776,0.00057,0.07883,0.0995,0.0586,0.0779,0.4719,0.30073,0.2315,0.1347,0.10606,0.4345,0.4371,0.28873,0.17009,0.02353,0.22326,0.00602,0.1249,0.147,0.22149,0.13225,0.31794,0.0504,0.37756,0.1616,0.03388,0.0509,0.2886,0.02805,0.12947,0.56749,0.31684,0.12067,0.7365,0.5957,0.03375,0.01425,0.50252,0.10613,0.4264,0.07275,0.2617,0.02966,0.00526,0.23077,0.06102,0.07372,0.33851,0.1766,0.3104,0.2092 +381.0,0.6359,0.2615,0.000759472,0.474683184,0.133787856,0.046261376,0.0583,0.058388864,0.0415892,0.19983,0.04013528,0.238506992,0.04336512,0.3414,0.170307008,0.034750672,0.031091104,0.0731,0.1202,0.025332624,0.124467696,0.001470288,0.381475488,0.2515,0.101523136,0.1688,0.06465056,0.045684704,0.04003128,0.030675376,0.04394184,0.0429,0.173979056,0.04389,0.05245,0.034604064,0.05027336,0.11364184,0.045668976,0.075002784,0.4098,0.065901712,0.0671,0.0439,0.05534864,0.1126,0.1446,0.087840592,0.001450112,0.079265072,0.100079952,0.05857696,0.0779,0.4719,0.30409872,0.2315,0.1347,0.106598352,0.4345,0.44177272,0.291221392,0.171260752,0.0239812,0.22326,0.006377376,0.1249,0.147,0.223326032,0.133149808,0.321518336,0.0504,0.379555776,0.163942032,0.034000976,0.0509,0.2886,0.028737056,0.131012112,0.568910112,0.320407168,0.127693984,0.7365,0.5957,0.033978288,0.013956016,0.50398984,0.107359696,0.428181152,0.073921936,0.2617,0.029995872,0.007533936,0.232399984,0.061775552,0.075816672,0.34143264,0.1766,0.3104,0.2092 +382.0,0.6359,0.2615,0.00180792,0.476040128,0.134196192,0.047743488,0.0583,0.058694576,0.04161728,0.19983,0.041050992,0.23390896,0.043358048,0.3414,0.170873072,0.034883296,0.031517184,0.0731,0.1202,0.025687664,0.125795744,0.003445808,0.385785024,0.2515,0.099642896,0.1688,0.064693984,0.045516912,0.040355056,0.031034848,0.04384392,0.0429,0.175192624,0.04389,0.05245,0.035047072,0.050263584,0.114226192,0.045682144,0.07500688,0.4098,0.065787232,0.0671,0.0439,0.055271792,0.1126,0.1446,0.087957856,0.002738016,0.079901616,0.100928464,0.058543264,0.0779,0.4719,0.309027968,0.2315,0.1347,0.107385568,0.4345,0.448610256,0.294866,0.172973568,0.024642304,0.22326,0.006905424,0.1249,0.147,0.22601216,0.13446632,0.326752736,0.0504,0.382474768,0.16737,0.034177952,0.0509,0.2886,0.029734976,0.133269136,0.57098688,0.325632848,0.137899824,0.7365,0.5957,0.03431224,0.013523232,0.506139408,0.10915952,0.430786192,0.075638048,0.2617,0.030533776,0.010819504,0.234783616,0.062881584,0.078890544,0.345707648,0.1766,0.3104,0.2092 +383.0,0.6359,0.2615,0.003150688,0.477419552,0.134667008,0.04956128,0.0583,0.059047888,0.04165136,0.19983,0.042170624,0.228261728,0.043349296,0.3414,0.171560656,0.0350444,0.032036544,0.0731,0.1202,0.026120704,0.127412672,0.005839088,0.39093352,0.2515,0.097375136,0.1688,0.064759168,0.0453124,0.040748992,0.03143888,0.04374712,0.0429,0.176658672,0.04389,0.05245,0.03562448,0.050251888,0.114831504,0.045698112,0.075011696,0.4098,0.065648432,0.0671,0.0439,0.055195424,0.1126,0.1446,0.08810376,0.00429616,0.080676,0.101960816,0.058502368,0.0779,0.4719,0.314971856,0.2315,0.1347,0.108348384,0.4345,0.456830832,0.299299488,0.175057904,0.025452048,0.22326,0.007566832,0.1249,0.147,0.229281488,0.136068512,0.333121696,0.0504,0.3860208,0.171553328,0.034393168,0.0509,0.2886,0.031117936,0.13602168,0.573506128,0.331941328,0.150332544,0.7365,0.5957,0.034718992,0.013083008,0.508748016,0.111354624,0.433949152,0.077736,0.2617,0.03131568,0.014937472,0.237677968,0.064231536,0.082668976,0.350905456,0.1766,0.3104,0.2092 +384.0,0.6359,0.2615,0.004770176,0.478184096,0.135091344,0.051486032,0.0583,0.05936992,0.04168664,0.19983,0.043348416,0.222218736,0.043339744,0.3414,0.17227376,0.035211504,0.032579264,0.0731,0.1202,0.026573984,0.1290984,0.008305088,0.396060576,0.2515,0.095060256,0.1688,0.064858752,0.045097568,0.041159008,0.031777392,0.0436988,0.0429,0.17815832,0.04389,0.05245,0.036304048,0.050240272,0.115225136,0.04571456,0.075016272,0.4098,0.065505072,0.0671,0.0439,0.055159856,0.1126,0.1446,0.088264304,0.005896144,0.081481824,0.103035328,0.058460032,0.0779,0.4719,0.321027424,0.2315,0.1347,0.10936336,0.4345,0.465145408,0.303912736,0.17722848,0.026306912,0.22326,0.00829536,0.1249,0.147,0.232687456,0.137737184,0.339753056,0.0504,0.389699632,0.175936736,0.034616944,0.0509,0.2886,0.032978816,0.138901584,0.576111136,0.338378688,0.163396224,0.7365,0.5957,0.035143504,0.012839024,0.511447904,0.113651568,0.437226512,0.079942352,0.2617,0.032385264,0.01956792,0.24067792,0.065646368,0.086688448,0.356308384,0.1766,0.3104,0.2092 +385.0,0.6359,0.2615,0.00663,0.47793,0.1354,0.05337,0.0583,0.05961,0.04172,0.19983,0.04449,0.21622,0.04333,0.3414,0.17295,0.03537,0.0331,0.0731,0.1202,0.02701,0.13071,0.01062,0.40061,0.2515,0.09292,0.1688,0.065,0.04489,0.04155,0.03198,0.04373,0.0429,0.17955,0.04389,0.05245,0.03707,0.05023,0.11525,0.04573,0.07502,0.4098,0.06537,0.0671,0.0439,0.05519,0.1126,0.1446,0.08843,0.00739,0.08225,0.10406,0.05842,0.0779,0.4719,0.32661,0.2315,0.1347,0.11035,0.4345,0.47272,0.30831,0.1793,0.02714,0.22326,0.00905,0.1249,0.147,0.23594,0.13933,0.34608,0.0504,0.39319,0.18016,0.03483,0.0509,0.2886,0.03537,0.14167,0.57857,0.34433,0.17602,0.7365,0.5957,0.03555,0.01292,0.514,0.11586,0.44033,0.08208,0.2617,0.03379,0.02448,0.24352,0.06701,0.09065,0.36145,0.1766,0.3104,0.2092 +386.0,0.6359,0.2615,0.008713344,0.476719408,0.135604496,0.055233424,0.0583,0.059775296,0.041752048,0.19983,0.045607744,0.21021648,0.043320096,0.3414,0.17359768,0.035522336,0.03360504,0.0731,0.1202,0.027432192,0.13226144,0.012818768,0.404662736,0.2515,0.090920784,0.1688,0.06518088,0.044690832,0.041928784,0.032057136,0.043838976,0.0429,0.180856304,0.04389,0.05245,0.03794672,0.05022072,0.1149316,0.045744832,0.075023248,0.4098,0.065241488,0.0671,0.0439,0.055280784,0.1126,0.1446,0.088601888,0.008801088,0.082991616,0.10504952,0.05838192,0.0779,0.4719,0.331808304,0.2315,0.1347,0.111320944,0.4345,0.479678352,0.312551552,0.181300704,0.027960176,0.22326,0.009842864,0.1249,0.147,0.239084224,0.140869232,0.352189904,0.0504,0.396540016,0.184273536,0.035035328,0.0509,0.2886,0.038292064,0.144361568,0.580910736,0.349892768,0.188332624,0.7365,0.5957,0.035944,0.013318544,0.51643792,0.118005152,0.443291792,0.084176896,0.2617,0.035571744,0.029703056,0.246244576,0.068341344,0.094610752,0.366403504,0.1766,0.3104,0.2092 +387.0,0.6359,0.2615,0.011029968,0.474528752,0.135700208,0.05705496,0.0583,0.059861408,0.0417828,0.19983,0.046687984,0.204247328,0.043310256,0.3414,0.174209296,0.03566776,0.034088944,0.0731,0.1202,0.027832624,0.133724672,0.014884528,0.40816944,0.2515,0.089077536,0.1688,0.065401008,0.04450808,0.042295232,0.03200376,0.04403056,0.0429,0.182066992,0.04389,0.05245,0.03895776,0.050212288,0.114290064,0.045759232,0.075026496,0.4098,0.065120992,0.0671,0.0439,0.055432864,0.1126,0.1446,0.08877896,0.01011856,0.08370184,0.105997296,0.058346528,0.0779,0.4719,0.336574016,0.2315,0.1347,0.112270224,0.4345,0.485947152,0.316603888,0.183214704,0.028757408,0.22326,0.010674192,0.1249,0.147,0.242097008,0.142343712,0.358037136,0.0504,0.39972192,0.188234688,0.035231408,0.0509,0.2886,0.041764816,0.14695072,0.583100448,0.355016288,0.200263264,0.7365,0.5957,0.036322592,0.014067888,0.518737056,0.120061824,0.446065152,0.08621712,0.2617,0.03776424,0.035250912,0.248831248,0.069631776,0.098557376,0.371134496,0.1766,0.3104,0.2092 +388.0,0.6359,0.2615,0.013365072,0.471509776,0.1357112,0.058878336,0.0583,0.0598828,0.041812352,0.19983,0.047757264,0.198361936,0.043300416,0.3414,0.174798592,0.035807984,0.034562288,0.0731,0.1202,0.028224816,0.135147904,0.016855168,0.411255184,0.2515,0.087362208,0.1688,0.065652336,0.044332448,0.0426512,0.031841504,0.044296864,0.0429,0.18320888,0.04389,0.05245,0.04010664,0.050204576,0.113261808,0.045773152,0.075029184,0.4098,0.065005856,0.0671,0.0439,0.055632944,0.1126,0.1446,0.088959792,0.011368592,0.084391024,0.106917312,0.058312576,0.0779,0.4719,0.341022448,0.2315,0.1347,0.113207344,0.4345,0.491704352,0.320533264,0.185073664,0.02955192,0.22326,0.01156,0.1249,0.147,0.245025152,0.143776512,0.363711568,0.0504,0.402789424,0.19212536,0.035421328,0.0509,0.2886,0.045682048,0.149487712,0.5851972,0.359842928,0.211691744,0.7365,0.5957,0.036691424,0.015078592,0.520943312,0.122077456,0.448731312,0.088235344,0.2617,0.040457056,0.040922288,0.25131952,0.070900528,0.10253656,0.375712368,0.1766,0.3104,0.2092 +389.0,0.6359,0.2615,0.015403696,0.46795096,0.135683952,0.060793952,0.0583,0.059869152,0.041841264,0.19983,0.048871344,0.192562704,0.043290336,0.3414,0.175396448,0.035947728,0.035048352,0.0731,0.1202,0.028636048,0.136629616,0.018821808,0.414195008,0.2515,0.08569888,0.1688,0.065921984,0.044145536,0.043004208,0.031613648,0.044620368,0.0429,0.184343728,0.04389,0.05245,0.04139328,0.050197264,0.111770032,0.045786672,0.075030432,0.4098,0.06489,0.0671,0.0439,0.055857664,0.1126,0.1446,0.089143824,0.012613024,0.085085168,0.107844528,0.058277504,0.0779,0.4719,0.34541728,0.2315,0.1347,0.114158864,0.4345,0.497347472,0.32450056,0.186953904,0.030385392,0.22326,0.012529088,0.1249,0.147,0.247983536,0.145224112,0.36943552,0.0504,0.405873248,0.196127152,0.035612688,0.0509,0.2886,0.04987232,0.152086224,0.587327552,0.364680928,0.222606624,0.7365,0.5957,0.037064496,0.016190736,0.523163888,0.124154928,0.451462592,0.090311088,0.2617,0.043764032,0.046446544,0.253809232,0.07219408,0.106660864,0.38031248,0.1766,0.3104,0.2092 +390.0,0.6359,0.2615,0.01694,0.46406,0.13565,0.06285,0.0583,0.05984,0.04187,0.19983,0.05006,0.18687,0.04328,0.3414,0.17602,0.03609,0.03556,0.0731,0.1202,0.02908,0.13822,0.02084,0.41716,0.2515,0.08404,0.1688,0.0662,0.04394,0.04336,0.03135,0.04499,0.0429,0.18551,0.04389,0.05245,0.04283,0.05019,0.10979,0.0458,0.07503,0.4098,0.06477,0.0671,0.0439,0.05609,0.1126,0.1446,0.08933,0.01389,0.0858,0.1088,0.05824,0.0779,0.4719,0.34992,0.2315,0.1347,0.11514,0.4345,0.50312,0.3286,0.1889,0.03128,0.22326,0.0136,0.1249,0.147,0.25104,0.14672,0.37534,0.0504,0.40905,0.20034,0.03581,0.0509,0.2886,0.05422,0.15481,0.58956,0.36972,0.23298,0.7365,0.5957,0.03745,0.01731,0.52546,0.12635,0.45435,0.09249,0.2617,0.04777,0.05165,0.25636,0.07354,0.111,0.38504,0.1766,0.3104,0.2092 +391.0,0.6359068,0.261504144,0.017983312,0.459806464,0.135602896,0.065036368,0.058299296,0.05978928,0.041897904,0.19984032,0.051315536,0.18135352,0.04326928,0.341402576,0.176661808,0.036232352,0.036092176,0.073103648,0.120204736,0.029555296,0.139910896,0.022876048,0.42006664,0.25152328,0.082420432,0.168794848,0.066490544,0.043722208,0.043711376,0.031047504,0.045410752,0.042898656,0.1866872,0.043890128,0.052449904,0.04442072,0.050183232,0.107335424,0.045812608,0.075027392,0.40981272,0.06464744,0.067092288,0.043900976,0.056331792,0.11260568,0.144600864,0.08951624,0.015177744,0.086524848,0.109769648,0.058200336,0.07790224,0.471927088,0.354440928,0.231537648,0.134708224,0.116137696,0.434626512,0.50889088,0.332774064,0.190885648,0.032231072,0.223285072,0.014776432,0.124911856,0.147018272,0.254151904,0.1482432,0.381340144,0.05040712,0.412272848,0.20472344,0.036010368,0.050912416,0.288636016,0.058722544,0.157630112,0.591869808,0.374863984,0.242653664,0.736511632,0.595713216,0.037842928,0.018456512,0.527799376,0.128643424,0.457367456,0.09474968,0.261717616,0.052461136,0.0565156,0.258931008,0.07492176,0.115511456,0.389822656,0.176628656,0.310415808,0.209217984 +392.0,0.635934,0.26152072,0.018506992,0.455182816,0.13554304,0.067391296,0.05829648,0.05971576,0.041923872,0.1998816,0.052659024,0.176054336,0.043257456,0.34141288,0.177326912,0.036372544,0.036649648,0.07311824,0.12022368,0.030078336,0.141754064,0.024913568,0.422881504,0.2516164,0.080865968,0.16877424,0.066802576,0.043488048,0.04404712,0.030712384,0.045884384,0.04289328,0.18786576,0.04389064,0.05244952,0.04614176,0.050178016,0.104380128,0.045823232,0.075020704,0.4098636,0.064521616,0.06706144,0.04390488,0.056584064,0.1126284,0.14460432,0.089701072,0.016465792,0.087253744,0.110746112,0.058157296,0.0779112,0.47203544,0.358939888,0.23168824,0.13474112,0.117144704,0.43513256,0.514602832,0.337007024,0.192905344,0.03325624,0.22338536,0.01607488,0.12495928,0.14709136,0.257304272,0.149785952,0.387403728,0.0504356,0.415528864,0.20931424,0.036212608,0.05096208,0.28878008,0.063345248,0.160560992,0.59429088,0.380072128,0.251489344,0.73655816,0.59576608,0.038242064,0.019601552,0.530184992,0.131064016,0.460578672,0.097094144,0.26178808,0.057788896,0.060983328,0.26150168,0.076334128,0.12017096,0.394622128,0.17674328,0.31047904,0.20928992 +393.0,0.6359612,0.261537296,0.018565552,0.450365408,0.135481424,0.069777984,0.058293664,0.05962448,0.04195048,0.19992288,0.054010512,0.171030592,0.043246672,0.341423184,0.177986656,0.036514016,0.0372088,0.073132832,0.120242624,0.030593536,0.143566752,0.026955888,0.425611088,0.25170952,0.079343504,0.168753632,0.067110688,0.043279568,0.044392224,0.030350064,0.046409616,0.042887904,0.18905136,0.043891152,0.052449136,0.04812424,0.0501716,0.101174752,0.045835056,0.075015456,0.40991448,0.064397312,0.067030592,0.043908784,0.056830896,0.11265112,0.144607776,0.089881904,0.01775864,0.08798888,0.111730576,0.058115376,0.07792016,0.472143792,0.363418048,0.231838832,0.134774016,0.118158912,0.435638608,0.520250464,0.341254864,0.19493416,0.034292048,0.223485648,0.017469248,0.125006704,0.147164448,0.260476,0.151339504,0.393492992,0.05046408,0.41878296,0.21392592,0.036415808,0.051011744,0.288924144,0.068113312,0.163508752,0.596671152,0.385339312,0.259601024,0.736604688,0.595818944,0.03864336,0.020864352,0.532553888,0.133486768,0.463731168,0.099475488,0.261858544,0.063896096,0.065190976,0.264070912,0.077768096,0.124997344,0.39944336,0.176857904,0.310542272,0.209361856 +394.0,0.6359544,0.261533152,0.018277952,0.44559048,0.135430288,0.071978512,0.058294368,0.05952096,0.041981808,0.19991256,0.05524288,0.166347648,0.043240288,0.341420608,0.1785956,0.036662208,0.037732112,0.073129184,0.120237888,0.031012736,0.1450592,0.029007088,0.428256112,0.25168624,0.0778012,0.168758784,0.06737624,0.043160688,0.044786288,0.029963184,0.046985248,0.042889248,0.19025112,0.043891024,0.052449232,0.05056608,0.050159664,0.098101456,0.04585312,0.075020368,0.40990176,0.064282128,0.067038304,0.043907808,0.057050768,0.11264544,0.144606912,0.090055616,0.019062048,0.088733696,0.11272488,0.058081696,0.07791792,0.472116704,0.367871888,0.231801184,0.134765792,0.119178,0.435512096,0.525816496,0.345448064,0.196932576,0.035237456,0.223460576,0.018913936,0.124994848,0.147146176,0.263633728,0.152889936,0.399548976,0.05045696,0.421979696,0.21826272,0.036618528,0.050999328,0.288888128,0.073090016,0.166324352,0.598769584,0.390649056,0.267213744,0.736593056,0.595805728,0.039040416,0.022440912,0.534806304,0.13571328,0.466424784,0.101817312,0.261840928,0.070993216,0.069387024,0.266637344,0.079209184,0.130018368,0.404294672,0.176829248,0.310526464,0.209343872 +395.0,0.6359,0.2615,0.01773,0.44102,0.1354,0.07388,0.0583,0.05941,0.04202,0.19983,0.05629,0.16204,0.04324,0.3414,0.17913,0.03682,0.0382,0.0731,0.1202,0.03129,0.14608,0.03107,0.43082,0.2515,0.07621,0.1688,0.06758,0.04317,0.04525,0.02956,0.04761,0.0429,0.19147,0.04389,0.05245,0.05358,0.05014,0.09541,0.04588,0.07504,0.4098,0.06418,0.0671,0.0439,0.05723,0.1126,0.1446,0.09022,0.02038,0.08949,0.11373,0.05806,0.0779,0.4719,0.3723,0.2315,0.1347,0.1202,0.4345,0.53129,0.34955,0.19888,0.03604,0.22326,0.02039,0.1249,0.147,0.26676,0.15443,0.40554,0.0504,0.42509,0.22217,0.03682,0.0509,0.2886,0.0783,0.16893,0.60046,0.39599,0.27447,0.7365,0.5957,0.03943,0.02444,0.53689,0.13764,0.46845,0.10408,0.2617,0.07917,0.07373,0.2692,0.08065,0.13525,0.40918,0.1766,0.3104,0.2092 +396.0,0.6358064,0.261442496,0.016908928,0.43667624,0.13539544,0.075502352,0.058309664,0.05929424,0.042064704,0.199683584,0.05716312,0.158113136,0.043245536,0.341364704,0.179593504,0.036986944,0.038615776,0.073050272,0.120133344,0.031432912,0.146653312,0.03314384,0.43331408,0.25117504,0.0745824,0.168870912,0.06773536,0.043300832,0.045779984,0.02914904,0.04828232,0.042918624,0.192706608,0.043888192,0.052451088,0.057150912,0.050112912,0.093089344,0.045915264,0.075073616,0.40962384,0.06409024,0.067205952,0.043886464,0.057368768,0.11252128,0.144588096,0.090375696,0.021711392,0.090257552,0.114745856,0.058049664,0.07786944,0.471530112,0.376707584,0.230978448,0.134586496,0.121224112,0.432747328,0.5366792,0.353566144,0.200779648,0.036708832,0.22291352,0.021913024,0.124736544,0.146747968,0.26985744,0.155960912,0.411469232,0.05030416,0.428118464,0.225671216,0.037020336,0.050730464,0.288105344,0.083708256,0.171337424,0.601762608,0.401366224,0.281325344,0.736340608,0.595516544,0.03981264,0.026830464,0.538813376,0.13928368,0.469840608,0.106271392,0.261453504,0.088386992,0.078181088,0.271759184,0.082092272,0.14069384,0.414098208,0.176202464,0.310182864,0.208948576 +397.0,0.6356632,0.261353376,0.015820512,0.432602768,0.135419744,0.076774864,0.058324384,0.0591756,0.0421172,0.1994488,0.057821072,0.154589232,0.043258112,0.341311104,0.179970976,0.037164736,0.03896744,0.072975392,0.120027744,0.031412816,0.146684432,0.035226608,0.435747408,0.25066672,0.072922624,0.168979392,0.067849168,0.043557888,0.046389024,0.028729024,0.049000576,0.042947424,0.19395752,0.043885312,0.052452176,0.06131832,0.0500768,0.091184352,0.045960656,0.075124016,0.40935168,0.064015312,0.067367552,0.043865504,0.057464976,0.11239952,0.144569856,0.090524464,0.02305368,0.09103752,0.115773136,0.058052896,0.07782336,0.470971552,0.381098288,0.230172272,0.134412096,0.122250032,0.430038048,0.541989584,0.357473984,0.20261832,0.037211328,0.222380048,0.023477728,0.124485824,0.146361088,0.27291496,0.157478144,0.417316512,0.05016288,0.43104728,0.22866744,0.037219088,0.050474464,0.287351264,0.089312192,0.173496192,0.602599392,0.406777472,0.287780704,0.736098528,0.595232064,0.040186,0.029638032,0.540544288,0.140579488,0.470467728,0.108368448,0.261066464,0.098701616,0.082744896,0.274315712,0.083531776,0.146361984,0.4190524,0.175586624,0.309851792,0.208554336 +398.0,0.635554,0.261284976,0.014530256,0.428774016,0.135484768,0.078039936,0.058335584,0.0590596,0.042171376,0.199265616,0.058461344,0.151358928,0.043271888,0.341270384,0.180332848,0.037345408,0.039312544,0.072918752,0.119945824,0.03136632,0.146619792,0.037322096,0.438126096,0.2502748,0.071263488,0.169062112,0.067959936,0.043906944,0.047016304,0.028351168,0.049763632,0.042969504,0.195229472,0.043883072,0.052452784,0.065884768,0.050039008,0.08961608,0.046007808,0.075177856,0.40914312,0.063943264,0.067490592,0.043849424,0.057526544,0.11230616,0.144555936,0.090662752,0.024411808,0.091824608,0.116808976,0.058059088,0.07778848,0.470548432,0.385471712,0.229554336,0.134278816,0.123275072,0.427961328,0.547212768,0.361378064,0.204457792,0.037705024,0.221971936,0.025176912,0.124294384,0.146065568,0.27598408,0.159003296,0.423167472,0.0500572,0.433960656,0.231616944,0.03741832,0.050280544,0.286777264,0.094991488,0.17563912,0.603338816,0.41221656,0.293811824,0.735914608,0.595013664,0.0405612,0.03267104,0.54223488,0.141833936,0.470941728,0.110488224,0.260767504,0.10964072,0.087391504,0.27686784,0.08499136,0.152217888,0.424026112,0.175114064,0.30959976,0.208250016 +399.0,0.6356068,0.261317616,0.01312328,0.425113664,0.135605232,0.079838448,0.058330144,0.05895296,0.042217552,0.199350112,0.059396176,0.148247824,0.043277664,0.341290224,0.18079064,0.03751632,0.039742128,0.072946592,0.119984064,0.031509504,0.147166032,0.039435984,0.440455344,0.25046008,0.069656272,0.169022112,0.068125264,0.04429056,0.047565584,0.028089712,0.050570528,0.042958944,0.196532544,0.043884112,0.052452272,0.070531216,0.050011136,0.088218848,0.04604352,0.075214016,0.40924296,0.063855216,0.067430912,0.043857104,0.057567952,0.1123508,0.144562656,0.0907852,0.025793136,0.092610416,0.117848816,0.05805144,0.0778056,0.470755792,0.389826016,0.22985,0.134342976,0.124295712,0.428954928,0.552335712,0.365444144,0.206395824,0.03843888,0.222167984,0.027151216,0.124386704,0.146207968,0.2791464,0.160570528,0.429158672,0.05011032,0.436991952,0.235245488,0.037621312,0.050375584,0.287055824,0.100567824,0.178134848,0.60456424,0.417673968,0.299365824,0.736004208,0.595117824,0.04095576,0.035624768,0.544126032,0.143532064,0.472228928,0.11281544,0.260908304,0.120476624,0.092055312,0.279412928,0.086506944,0.158201792,0.428993664,0.175339664,0.309722048,0.208393536 +400.0,0.6359,0.2615,0.01167,0.42157,0.13579,0.08249,0.0583,0.05886,0.04225,0.19983,0.06081,0.14514,0.04327,0.3414,0.18141,0.03767,0.04031,0.0731,0.1202,0.03197,0.14874,0.04157,0.44274,0.2515,0.06814,0.1688,0.06839,0.04467,0.04798,0.02799,0.05142,0.0429,0.19787,0.04389,0.05245,0.07506,0.05,0.08689,0.04606,0.07522,0.4098,0.06374,0.0671,0.0439,0.0576,0.1126,0.1446,0.09089,0.0272,0.09339,0.11889,0.05802,0.0779,0.4719,0.39416,0.2315,0.1347,0.12531,0.4345,0.55735,0.36977,0.20849,0.03956,0.22326,0.02949,0.1249,0.147,0.28245,0.1622,0.43537,0.0504,0.44022,0.23998,0.03783,0.0509,0.2886,0.10593,0.1812,0.60662,0.42314,0.30442,0.7365,0.5957,0.04138,0.03831,0.54636,0.14596,0.4749,0.11546,0.2617,0.13075,0.0967,0.28195,0.0881,0.16428,0.43394,0.1766,0.3104,0.2092 +401.0,0.636418768,0.26182184,0.010198976,0.418176192,0.136038528,0.085924464,0.058246656,0.058781408,0.042269984,0.200670992,0.06266224,0.14205064,0.04325016,0.34159464,0.182177808,0.037808032,0.04100432,0.073372512,0.120579408,0.032719248,0.151252704,0.04371984,0.444985216,0.253331808,0.066707408,0.168407072,0.06875808,0.045046464,0.048272256,0.028042832,0.052310592,0.042796048,0.199235712,0.043900304,0.052445504,0.079507536,0.05000432,0.085680512,0.046058992,0.075198592,0.410784384,0.06360024,0.066514208,0.043975744,0.05762096,0.113040096,0.144666432,0.090981792,0.02862736,0.094164368,0.119933024,0.057966912,0.078067696,0.473931056,0.398474672,0.234414032,0.1353316,0.126318512,0.444290896,0.562256784,0.374333088,0.210728416,0.041036304,0.225190352,0.032178336,0.12580816,0.14840096,0.285884208,0.16388752,0.441781968,0.050917248,0.443626608,0.245733712,0.038044016,0.051831024,0.29133544,0.111084096,0.184792752,0.60943368,0.428607376,0.309003952,0.737378912,0.596727248,0.04183184,0.040756784,0.54890624,0.149056464,0.478832592,0.118394976,0.263093232,0.140501824,0.101346464,0.284480864,0.089765392,0.170458688,0.438864656,0.178824592,0.311600704,0.210619728 +402.0,0.63716784,0.262285376,0.008738096,0.414959856,0.136351328,0.090185696,0.058169664,0.05871856,0.042276736,0.201874176,0.064978384,0.138977808,0.043217568,0.341876384,0.183106528,0.037929248,0.041832464,0.073767712,0.121123664,0.033774,0.154769312,0.045882176,0.447195776,0.25596584,0.065341808,0.167839872,0.069230736,0.045410784,0.048434864,0.028246768,0.053241232,0.042646544,0.200626352,0.043914992,0.052438304,0.083852768,0.050025568,0.08461528,0.046039488,0.075148176,0.41220504,0.063434784,0.065668032,0.044084944,0.057628864,0.11367464,0.144763296,0.091065232,0.030071728,0.094932608,0.120977216,0.057890768,0.07831096,0.476874112,0.402770752,0.238615296,0.136244016,0.127321472,0.458401408,0.567055648,0.379145584,0.213121072,0.042888464,0.227976096,0.035215952,0.127119984,0.150423968,0.28945592,0.165636416,0.448404832,0.05167144,0.447220976,0.252585744,0.03826376,0.053180464,0.295291264,0.116003328,0.18895824,0.613060816,0.43406864,0.313129024,0.738650768,0.598206704,0.04231312,0.04294016,0.55178624,0.152865696,0.484113248,0.121627584,0.265094464,0.14964592,0.105994864,0.28700704,0.0915044,0.176724768,0.443757952,0.182029824,0.31333648,0.212659856 +403.0,0.638094912,0.262855072,0.007353936,0.41185272,0.136719888,0.094931088,0.058074112,0.058667952,0.042276288,0.20332568,0.067559968,0.135911376,0.043177776,0.342226368,0.184118528,0.038041824,0.042736928,0.074260832,0.12178456,0.034998272,0.15882544,0.048046112,0.449374176,0.259186672,0.064110688,0.167137792,0.069860832,0.045766944,0.048528272,0.028575104,0.054208832,0.04246248,0.202020272,0.0439328,0.052427424,0.0882156,0.050055296,0.083688608,0.046009824,0.07508184,0.413953296,0.063254928,0.064618976,0.044219184,0.057637728,0.114455184,0.14488272,0.091146912,0.031518496,0.095700528,0.122026208,0.057802064,0.078614224,0.480541088,0.407046752,0.24378536,0.137370192,0.128321632,0.4757672,0.571748352,0.38410328,0.215601568,0.044958064,0.23141128,0.038578448,0.128740848,0.152922656,0.293112032,0.167424032,0.455147456,0.052622832,0.450921424,0.260031536,0.038486944,0.054861744,0.300195328,0.12077752,0.193430928,0.617117152,0.439508384,0.316867216,0.740230704,0.6000244,0.04281184,0.044980416,0.55484408,0.157069648,0.490115904,0.125058352,0.267536736,0.158459616,0.110690864,0.289532256,0.093298608,0.183140448,0.448648608,0.185969696,0.315488336,0.215151344 +404.0,0.639110144,0.263470848,0.006125216,0.408750864,0.137129968,0.09959784,0.0579688,0.058623264,0.04227856,0.204838944,0.070081072,0.132853264,0.043139904,0.342611872,0.185086528,0.0381592,0.043623232,0.074808352,0.122482336,0.036168784,0.162659008,0.050196288,0.451521696,0.262633664,0.063112768,0.166368512,0.070719328,0.046128704,0.04865176,0.028982,0.055209392,0.042262496,0.203386032,0.043951648,0.052411664,0.092806272,0.050079664,0.082896416,0.04598368,0.075021104,0.415844832,0.063079232,0.06346624,0.044364224,0.057667392,0.115299648,0.145011264,0.091235472,0.032946784,0.096477648,0.12308592,0.05771808,0.078950208,0.484602944,0.411300352,0.249384304,0.138595648,0.129323312,0.494583552,0.576338816,0.389035296,0.218061024,0.046984864,0.235145104,0.042216864,0.130508832,0.155646784,0.296765504,0.169213168,0.46186136,0.053698784,0.454593792,0.267244368,0.038709808,0.056723424,0.305578112,0.125563392,0.197775856,0.620971728,0.444907568,0.320323488,0.74197152,0.601987776,0.04330832,0.047088672,0.55782368,0.1611464,0.49581232,0.12852304,0.270141568,0.167442992,0.115505504,0.292061712,0.095117456,0.189805808,0.453583904,0.190228128,0.317850992,0.217811872 +405.0,0.64015,0.26409,0.00511,0.40559,0.13757,0.10382,0.05786,0.05858,0.04229,0.20628,0.07233,0.12981,0.04311,0.34301,0.18593,0.03829,0.04443,0.07538,0.12316,0.03714,0.16578,0.05232,0.45364,0.26605,0.0624,0.16558,0.07185,0.0465,0.04887,0.02943,0.05624,0.04206,0.2047,0.04397,0.05239,0.09776,0.05009,0.08224,0.04597,0.07498,0.41775,0.06292,0.06228,0.04451,0.05773,0.11615,0.14514,0.09134,0.03434,0.09727,0.12416,0.05765,0.0793,0.48883,0.41553,0.25503,0.13984,0.13033,0.51357,0.58083,0.39383,0.22043,0.0488,0.23893,0.04609,0.13231,0.15842,0.30036,0.17098,0.46845,0.05485,0.45815,0.2737,0.03893,0.05866,0.31111,0.13046,0.20172,0.62422,0.45025,0.32357,0.74377,0.60396,0.04379,0.0494,0.56056,0.16476,0.50054,0.13191,0.27271,0.17691,0.12048,0.2946,0.09694,0.19678,0.45859,0.19451,0.32028,0.22044 +406.0,0.641219392,0.264715232,0.004330176,0.402378784,0.138036352,0.107648624,0.057747392,0.05853912,0.042309744,0.207655504,0.074336656,0.126779072,0.043087504,0.343423328,0.186664784,0.038432816,0.045165968,0.075979872,0.12382112,0.037931472,0.168268128,0.054412912,0.455731968,0.269453152,0.061959936,0.164769312,0.073262208,0.046872368,0.049174224,0.029922496,0.05730088,0.04185472,0.20596184,0.043988016,0.052362112,0.103046944,0.050088192,0.081725568,0.045967584,0.074956656,0.419683296,0.062776,0.061054976,0.044657344,0.057827216,0.117011424,0.14527232,0.091470736,0.035694336,0.0980764,0.125247552,0.057596144,0.079666464,0.493249568,0.41973664,0.260754432,0.141112352,0.131342624,0.53282016,0.58522216,0.398501632,0.222720912,0.050427824,0.242788752,0.050188912,0.134155968,0.161259136,0.30390376,0.172728672,0.474926064,0.056086752,0.461600576,0.279498864,0.039148032,0.060684704,0.316825568,0.135441536,0.205321696,0.626930528,0.455527936,0.326610992,0.745637024,0.60595056,0.044259168,0.05187808,0.563079232,0.16796432,0.504404352,0.135225008,0.275253216,0.186769488,0.125603424,0.297149968,0.09876712,0.204043344,0.46365344,0.198838016,0.322789072,0.223047904 +407.0,0.642315072,0.265344352,0.003810816,0.39910848,0.138523248,0.111051328,0.057631552,0.058501472,0.042338448,0.2089624,0.076082528,0.123757856,0.043073216,0.343851488,0.187287408,0.038588304,0.045825888,0.076608032,0.12446464,0.038529792,0.17008912,0.056470512,0.457799776,0.272836032,0.061809328,0.163940192,0.074985232,0.047248464,0.049570352,0.030470704,0.058392992,0.04164816,0.207173392,0.04400592,0.052327904,0.10867064,0.050074016,0.081359728,0.045977184,0.0749524,0.421646976,0.062648688,0.059795296,0.044805984,0.057966448,0.117883104,0.14541184,0.091640992,0.037006096,0.098897088,0.126348608,0.057557424,0.080050144,0.497857568,0.423921792,0.26654856,0.142413472,0.132362432,0.55228416,0.589516592,0.4030392,0.224929728,0.051854064,0.2467168,0.054498128,0.136045568,0.164160896,0.307392032,0.174457792,0.481280336,0.057411392,0.464936384,0.284616496,0.039363824,0.062796544,0.322718848,0.1405068,0.208573008,0.629077232,0.460734304,0.329461696,0.747569984,0.60795408,0.0447152,0.054515456,0.56536936,0.170735248,0.507357184,0.138450432,0.277763296,0.197015856,0.130878944,0.299715216,0.100595408,0.211591888,0.468768768,0.203203456,0.325373536,0.225628384 +408.0,0.643402592,0.265952992,0.003555216,0.395824096,0.139021424,0.114092672,0.057515872,0.058462704,0.042374832,0.210110736,0.07760648,0.12079872,0.043066608,0.344282528,0.187824432,0.038754192,0.046420768,0.077248992,0.12505368,0.038958672,0.171359872,0.058479472,0.459845664,0.276040752,0.06181912,0.163117472,0.076948656,0.04758696,0.0500476,0.030997952,0.059512944,0.04144792,0.208309104,0.044021984,0.052285776,0.114612896,0.0500508,0.081165808,0.045997664,0.074964944,0.423563376,0.062537216,0.058538496,0.044950224,0.05812888,0.118730864,0.14555184,0.091857168,0.038258736,0.099730176,0.127461344,0.057531584,0.080441104,0.502537888,0.428082944,0.272189808,0.143696912,0.13339272,0.5712224,0.593714864,0.407460048,0.227076384,0.053110304,0.250572608,0.058965024,0.137914448,0.167026016,0.310836544,0.176173392,0.487531328,0.058803472,0.468168272,0.289219088,0.039578336,0.064942384,0.328611808,0.145633984,0.21157608,0.630762496,0.465852432,0.33212232,0.749514864,0.60989032,0.045161472,0.057304832,0.567467328,0.173150976,0.509548256,0.141578736,0.280117216,0.207570944,0.136259024,0.302299424,0.102422256,0.219381152,0.473906656,0.207432736,0.327956,0.228057424 +409.0,0.644440592,0.266511632,0.003550816,0.392603872,0.13952048,0.116927376,0.057404352,0.058416736,0.042415936,0.210987312,0.079000192,0.117979984,0.04306584,0.344701968,0.188327056,0.03892576,0.046976768,0.077883872,0.125542,0.039276912,0.172329824,0.060423392,0.461871872,0.278871552,0.061786352,0.162330272,0.07903312,0.047826176,0.050579488,0.03139304,0.060655936,0.04126296,0.209334336,0.044033808,0.052233568,0.120828272,0.050024704,0.081176448,0.046025904,0.074988608,0.425334816,0.062438224,0.057329376,0.045083104,0.058282752,0.119512384,0.14568256,0.092123424,0.039431456,0.100571984,0.12858256,0.057513504,0.080827024,0.507150768,0.432216176,0.277404176,0.144904752,0.134437488,0.5887316,0.597818576,0.411808256,0.22920096,0.054270384,0.254182096,0.0635216,0.139683328,0.169732736,0.314263696,0.177888032,0.49372232,0.060238432,0.47132696,0.29363064,0.039793328,0.067058064,0.334287568,0.150778368,0.214521232,0.63220024,0.47086248,0.334577904,0.751406464,0.61166104,0.045604864,0.060220048,0.569453696,0.175379824,0.511303088,0.1446192,0.282163056,0.218281312,0.141666784,0.304906272,0.104247664,0.227338496,0.479021904,0.211312336,0.330442944,0.230181744 +410.0,0.6454,0.267,0.00379,0.3895,0.14001,0.11965,0.0573,0.05836,0.04246,0.21152,0.08032,0.11536,0.04307,0.3451,0.18883,0.0391,0.04751,0.0785,0.1259,0.03952,0.17316,0.06229,0.46388,0.2812,0.06158,0.1616,0.08117,0.04793,0.05115,0.03159,0.06182,0.0411,0.21023,0.04404,0.05217,0.12729,0.05,0.08142,0.04606,0.07502,0.4269,0.06235,0.0562,0.0452,0.05841,0.1202,0.1458,0.09245,0.04051,0.10142,0.12971,0.0575,0.0812,0.5116,0.43632,0.28201,0.146,0.1355,0.6042,0.60183,0.41611,0.23133,0.05538,0.25743,0.06811,0.1413,0.1722,0.31769,0.17961,0.49988,0.0617,0.47443,0.29807,0.04001,0.0691,0.3396,0.15591,0.21754,0.63353,0.47575,0.33682,0.7532,0.6132,0.04605,0.06324,0.57138,0.17753,0.51283,0.14757,0.2838,0.22905,0.14705,0.30754,0.10607,0.23541,0.48408,0.2147,0.33277,0.2319 +411.0,0.646271744,0.267412736,0.004280496,0.38650168,0.140481232,0.122205088,0.057204096,0.05829312,0.042508096,0.211703008,0.081534352,0.112927072,0.04308032,0.345474224,0.1893268,0.039278112,0.048011488,0.079094784,0.126124864,0.039665664,0.173789408,0.064074976,0.465871056,0.283006576,0.061220928,0.160935408,0.08338816,0.047901648,0.051769568,0.031600528,0.063007504,0.040961984,0.211002224,0.044040816,0.052095248,0.134013968,0.049976144,0.08190928,0.046101344,0.07506136,0.428255552,0.062274944,0.055161296,0.045300048,0.058514176,0.120789696,0.145909024,0.092854368,0.041491696,0.10227472,0.130843808,0.057492688,0.08155912,0.515859152,0.440396608,0.285974768,0.146979216,0.136581968,0.617490592,0.60575208,0.420346912,0.233456176,0.056414544,0.260295744,0.072700928,0.142755808,0.174412528,0.32110728,0.181336576,0.50598952,0.063184704,0.477462128,0.302489552,0.040228208,0.071057584,0.344516768,0.161035216,0.2206144,0.63470392,0.48050968,0.338872272,0.754883408,0.614492752,0.046495568,0.066375744,0.573224016,0.179559008,0.514042944,0.150403968,0.285009952,0.239907664,0.152411776,0.310204336,0.107883552,0.243589632,0.489074512,0.217568864,0.334919744,0.233194928 +412.0,0.647043712,0.267742112,0.005020416,0.383606256,0.140925744,0.124567552,0.057118112,0.058215824,0.042560672,0.211519696,0.0826296,0.11065456,0.043097488,0.345821008,0.189819152,0.039460512,0.048477408,0.079664192,0.12620936,0.039703952,0.174200192,0.065773312,0.467846224,0.284254432,0.06070688,0.160346992,0.085694336,0.04772856,0.05244368,0.031418272,0.064220064,0.0408524,0.211652784,0.044036144,0.052009216,0.141003616,0.04995344,0.082657888,0.046150784,0.075113744,0.429388336,0.062214576,0.054227056,0.045381824,0.05858848,0.121273744,0.1460128,0.093351248,0.042372496,0.103136096,0.131983744,0.057492224,0.081902304,0.519890928,0.444447264,0.289242608,0.147833632,0.13768528,0.62839488,0.609587664,0.424509648,0.235578704,0.057363584,0.262743808,0.077263024,0.144035248,0.176344976,0.324512144,0.183066992,0.512044128,0.064686992,0.480414912,0.306890768,0.040448096,0.072915264,0.348987808,0.166151424,0.22375328,0.635709856,0.485135072,0.34076448,0.756439424,0.61551664,0.046941232,0.069641792,0.574976928,0.181453936,0.514913056,0.153102096,0.285761536,0.250854464,0.157745744,0.312901824,0.109683616,0.251862992,0.493995216,0.219874016,0.33686736,0.234035904 +413.0,0.6477236,0.267995888,0.006010736,0.380827472,0.141329376,0.126740656,0.057042368,0.058132128,0.042618128,0.211022544,0.083607888,0.108636048,0.043122416,0.346144992,0.190317104,0.039646832,0.048908608,0.08021408,0.126174576,0.03963368,0.174423776,0.067382288,0.469804272,0.285018608,0.060057792,0.159833456,0.088151472,0.047465152,0.053171152,0.031111376,0.065464784,0.040771536,0.212209824,0.044027712,0.051913264,0.148271344,0.049933616,0.083698736,0.046207664,0.075177408,0.43034928,0.062169728,0.053392336,0.04544776,0.058664144,0.121668832,0.146125856,0.093975648,0.043155616,0.104003152,0.1331288,0.0574984,0.082235328,0.523731744,0.44847864,0.291910928,0.148590048,0.138811712,0.637172208,0.613341808,0.428597024,0.237704112,0.058230384,0.264837392,0.08174424,0.145168288,0.178039024,0.327906368,0.184803968,0.518045936,0.0662168,0.483285696,0.311345424,0.040669904,0.074691904,0.353081648,0.171253632,0.22700768,0.636580112,0.489626944,0.342456928,0.75788552,0.616302048,0.047388976,0.0729796,0.57665024,0.183234144,0.515477008,0.155638464,0.2861084,0.261907584,0.163046432,0.315642272,0.11146592,0.260201072,0.49881936,0.221688048,0.338636896,0.2344784 +414.0,0.648331328,0.268191264,0.007253216,0.378179488,0.141675488,0.12872696,0.056976384,0.058048592,0.042681104,0.210306032,0.084470576,0.107008576,0.043156304,0.346455776,0.190830736,0.039836752,0.049305808,0.080756448,0.126058752,0.039452528,0.1744936,0.068901424,0.47174272,0.285442464,0.059322304,0.15938608,0.090859488,0.047200624,0.053950224,0.03079216,0.066751984,0.040717632,0.212717424,0.04401832,0.051809632,0.155836992,0.049918592,0.085072064,0.046270944,0.075252752,0.431227744,0.06214128,0.052640256,0.045502656,0.058791568,0.12200656,0.146269312,0.094773008,0.043849376,0.104874768,0.134277856,0.057511056,0.082568672,0.52746288,0.452500416,0.294170848,0.149296864,0.139962784,0.644371136,0.617020752,0.43260752,0.23983912,0.059018064,0.266699856,0.086086256,0.146212608,0.179577472,0.331291792,0.186550784,0.523997264,0.067793248,0.48607152,0.3159324,0.040893792,0.076427424,0.356939168,0.17633872,0.23043376,0.637349888,0.493990816,0.343882576,0.759260256,0.616911776,0.04784128,0.076300608,0.578257792,0.184919872,0.51577424,0.157982192,0.286156064,0.273103824,0.16831488,0.31843864,0.113226064,0.268572752,0.503521344,0.22315552,0.340282192,0.234630496 +415.0,0.64888,0.26834,0.00874,0.37567,0.14195,0.13053,0.05692,0.05797,0.04275,0.20944,0.08522,0.10584,0.0432,0.34676,0.19137,0.04003,0.04967,0.0813,0.12589,0.03916,0.17444,0.07033,0.47366,0.28563,0.05854,0.159,0.09389,0.04699,0.05478,0.03054,0.06809,0.04069,0.21321,0.04401,0.0517,0.16371,0.04991,0.08681,0.04634,0.07534,0.43209,0.06213,0.05196,0.04555,0.059,0.12231,0.14646,0.09578,0.04446,0.10575,0.13543,0.05753,0.08291,0.53114,0.45652,0.29616,0.14999,0.14114,0.65038,0.62063,0.43654,0.24199,0.05973,0.26842,0.09024,0.14721,0.18102,0.33467,0.18831,0.5299,0.06943,0.48877,0.32072,0.04112,0.07815,0.36066,0.1814,0.23408,0.63805,0.49823,0.34501,0.76059,0.61739,0.0483,0.07955,0.57981,0.18653,0.51584,0.16011,0.28598,0.28446,0.17355,0.3213,0.11496,0.27695,0.50808,0.22438,0.34184,0.23457 +416.0,0.64936208,0.268437664,0.010461184,0.373302704,0.142146496,0.132155984,0.056873952,0.057896,0.04282472,0.208420624,0.085861024,0.105114,0.043253536,0.347055616,0.191944416,0.040226672,0.050002928,0.081843392,0.12566624,0.038761248,0.17428376,0.071666864,0.475557424,0.285567168,0.057702304,0.158682048,0.097232592,0.046828608,0.055662208,0.030356016,0.069481072,0.04069104,0.21369288,0.044002768,0.05158456,0.17187952,0.049908672,0.088925888,0.04641496,0.075439136,0.43293312,0.06213616,0.051358848,0.045589184,0.05928376,0.122576672,0.146701792,0.097007008,0.044987248,0.106628624,0.136584992,0.057555168,0.083258528,0.534741696,0.460538032,0.297855328,0.150668064,0.142344768,0.655106656,0.624172768,0.440394384,0.244161328,0.060370368,0.269982992,0.094183696,0.148154752,0.182356992,0.338041424,0.19008208,0.535754512,0.07112432,0.49138064,0.325744896,0.041348944,0.079852288,0.364220032,0.18642944,0.237971872,0.638697936,0.502341072,0.345862416,0.761864608,0.617725152,0.048765424,0.082734736,0.581306944,0.188079152,0.515697024,0.16202192,0.285565664,0.295950672,0.178739696,0.324223632,0.11666512,0.285313648,0.512487648,0.225342272,0.343295648,0.234283616 +417.0,0.64977224,0.268481488,0.012417296,0.371085552,0.142260176,0.133611776,0.056838528,0.057826288,0.042905248,0.207250384,0.086398928,0.104865248,0.043316896,0.347341392,0.192563264,0.040427232,0.050306608,0.08238656,0.125387936,0.03826352,0.174042256,0.072913408,0.477436592,0.285251088,0.056797792,0.158437216,0.100873152,0.046734832,0.056599472,0.030255616,0.070927584,0.040722496,0.214173024,0.043996832,0.051463744,0.180335824,0.049915216,0.091432816,0.046495744,0.075550288,0.4337588,0.062159728,0.050840576,0.04561992,0.059650624,0.122806672,0.146998656,0.098461168,0.045433056,0.107510752,0.13774288,0.05758672,0.083614048,0.538254064,0.46455472,0.299249728,0.151333248,0.143578112,0.658517808,0.627652288,0.444170784,0.246356752,0.060943664,0.271384032,0.09790424,0.149045968,0.183586624,0.341405728,0.191866928,0.541560416,0.07287464,0.493903776,0.331033344,0.041581024,0.081530784,0.367607728,0.191424192,0.2421272,0.639306592,0.506322224,0.346442128,0.76307736,0.617911168,0.049237616,0.08584704,0.58274528,0.189580384,0.515363888,0.163726224,0.2849068,0.307555664,0.183871232,0.327203472,0.11833968,0.293647152,0.51674136,0.226035888,0.344639296,0.2337664 +418.0,0.65012176,0.268481312,0.014536448,0.3689912,0.142275376,0.134900768,0.056814144,0.057765216,0.042991456,0.205992304,0.086836432,0.104863856,0.043390496,0.347622768,0.193236832,0.040630592,0.050581888,0.082937248,0.125080272,0.037663872,0.173749712,0.074065792,0.47929536,0.284774528,0.05591088,0.158262224,0.104881232,0.046654976,0.057589936,0.030262736,0.072438016,0.040784592,0.214683408,0.043993456,0.051338608,0.189065408,0.04993136,0.094352064,0.046582928,0.07567296,0.43462856,0.062202096,0.050398064,0.045645696,0.060059328,0.123020432,0.14736752,0.100182368,0.045801824,0.10839472,0.138902368,0.057623792,0.083983648,0.541725712,0.468577808,0.300465328,0.152017632,0.144842016,0.66094256,0.631074208,0.447868064,0.248584176,0.06145288,0.272701792,0.101344784,0.149920304,0.184760656,0.344766032,0.193667536,0.5473208,0.07469352,0.496335872,0.336663872,0.041816624,0.0832104,0.370910144,0.196353664,0.246602048,0.639911728,0.510175376,0.34684304,0.764251072,0.617986464,0.049718048,0.088925744,0.584138976,0.191054496,0.514879872,0.165190368,0.284070336,0.319251136,0.188953408,0.330252192,0.119978,0.301920656,0.520814832,0.226551264,0.345903184,0.233088384 +419.0,0.65042752,0.268451136,0.01671368,0.366975408,0.142172816,0.13602528,0.05680128,0.057718624,0.043083104,0.204729504,0.087175536,0.104750624,0.043474816,0.347907344,0.19397576,0.040835072,0.050829248,0.083505856,0.124776608,0.036955904,0.173446048,0.075118336,0.481130288,0.284262128,0.055164928,0.158150992,0.109353312,0.04649704,0.05863024,0.030397296,0.074022928,0.040877088,0.215265712,0.04399416,0.051210352,0.198049872,0.049959184,0.097705792,0.046677472,0.075806352,0.43562384,0.062265184,0.050020592,0.045671312,0.060442752,0.123245152,0.147829664,0.102221408,0.046098832,0.109278208,0.140061696,0.057665104,0.084376848,0.54522616,0.472617536,0.301667408,0.152763216,0.1461388,0.662830752,0.634445008,0.451484704,0.25085304,0.061900496,0.274042752,0.104434048,0.15082688,0.185948688,0.348126736,0.195487904,0.553039984,0.07659824,0.498672048,0.3427324,0.042056144,0.084925616,0.3742472,0.201174896,0.251465216,0.640556784,0.513903728,0.347206992,0.765418384,0.61800424,0.05020856,0.092038368,0.585507792,0.192524928,0.514291136,0.166368032,0.283147552,0.331006128,0.194003744,0.333388752,0.12157296,0.3101,0.524673904,0.22701104,0.347133632,0.232344688 +420.0,0.6507,0.2684,0.01888,0.36501,0.14194,0.13699,0.0568,0.05769,0.04318,0.20352,0.08742,0.1043,0.04357,0.3482,0.19479,0.04104,0.05105,0.0841,0.1245,0.03614,0.17316,0.07607,0.48294,0.2838,0.05464,0.1581,0.11434,0.04621,0.05972,0.03068,0.07569,0.041,0.21595,0.044,0.05108,0.20727,0.05,0.10151,0.04678,0.07595,0.4368,0.06235,0.0497,0.0457,0.06076,0.1235,0.1484,0.10461,0.04633,0.11016,0.14122,0.05771,0.0848,0.5488,0.47668,0.30297,0.1536,0.14747,0.6645,0.63777,0.45502,0.25317,0.06229,0.27548,0.10713,0.1518,0.1872,0.35149,0.19733,0.55872,0.0786,0.50091,0.3493,0.0423,0.0867,0.3777,0.20586,0.25676,0.64127,0.51751,0.34763,0.7666,0.618,0.05071,0.09523,0.58686,0.19401,0.51363,0.16724,0.2822,0.34279,0.19903,0.33662,0.12312,0.31816,0.5283,0.2275,0.34836,0.2316 +421.0,0.650937568,0.268327456,0.02102352,0.36309472,0.14157528,0.137802944,0.056809888,0.05767888,0.043282096,0.202374896,0.08757584,0.103548192,0.043675696,0.348500624,0.195687472,0.041246208,0.051246608,0.084721504,0.1242544,0.035226432,0.17290256,0.076926272,0.484726304,0.283401808,0.054326272,0.15811104,0.119815568,0.045813216,0.060863424,0.031124,0.077441712,0.041154096,0.216745888,0.044011296,0.050948288,0.216711648,0.050054032,0.105770656,0.046890432,0.076104048,0.438165056,0.062456096,0.049434544,0.04573208,0.061018448,0.123788944,0.1490824,0.107348912,0.046500816,0.111040576,0.142377744,0.057758864,0.085253696,0.55244552,0.48076472,0.30439,0.154535104,0.148836064,0.66600744,0.64105216,0.458474368,0.25553736,0.062626336,0.277023744,0.10943552,0.152845856,0.188524384,0.3548544,0.19919264,0.564359264,0.080698704,0.50305152,0.356370864,0.042548576,0.088535952,0.381275472,0.210406032,0.26248784,0.64205552,0.520995088,0.348100464,0.767794608,0.617976192,0.051221712,0.09848736,0.588187184,0.195519072,0.512907312,0.167826528,0.281233984,0.354583136,0.204023024,0.339934848,0.1246184,0.326088432,0.531697504,0.228030336,0.349579632,0.230862144 +422.0,0.65114088,0.268234512,0.023106608,0.36121768,0.141075376,0.138471328,0.056830624,0.057685456,0.043389296,0.201312624,0.087648352,0.102477616,0.043791536,0.348809968,0.196675312,0.041454112,0.051421248,0.085372928,0.124046832,0.034223072,0.172687232,0.077691392,0.48649016,0.283093248,0.05422272,0.158184784,0.125765312,0.045301296,0.062063936,0.031729136,0.079281296,0.041340032,0.217666928,0.044028496,0.050816048,0.226360848,0.05012176,0.110492144,0.047008848,0.07626848,0.43973488,0.062583296,0.049221504,0.045768416,0.061211248,0.124118512,0.14988256,0.110443968,0.046616624,0.11192,0.143535088,0.057811872,0.085739488,0.556169712,0.484872608,0.305960448,0.155579072,0.150237696,0.66745328,0.644294528,0.461847904,0.257958256,0.06291408,0.278694752,0.111345984,0.153975264,0.189937936,0.358219152,0.201075136,0.5699568,0.08289592,0.505097792,0.363954992,0.042802224,0.09043928,0.384992384,0.214802064,0.268654208,0.642920848,0.524360176,0.34861168,0.769004992,0.617941184,0.051743168,0.101800144,0.589484976,0.197061856,0.512137312,0.168138288,0.280265456,0.366368016,0.208978928,0.343326352,0.12606648,0.333870096,0.534865632,0.228625744,0.350795104,0.230148704 +423.0,0.651303952,0.268117968,0.025187616,0.35940288,0.140448432,0.139008192,0.05686064,0.057706352,0.043501456,0.200327072,0.087648064,0.10119488,0.043916656,0.349125712,0.197764192,0.041666496,0.051578208,0.086056032,0.123873664,0.033153632,0.172508624,0.078380352,0.488237056,0.282862128,0.054320608,0.158323568,0.132106256,0.044753056,0.063330608,0.032549232,0.0812088,0.041557968,0.218710448,0.044051216,0.050683728,0.236183168,0.050201808,0.115675152,0.047135104,0.076443792,0.441495184,0.062729776,0.049056224,0.045808112,0.061372528,0.12448752,0.15079744,0.113869184,0.046688192,0.112800704,0.144694192,0.05787024,0.08625528,0.559951504,0.488996656,0.307666016,0.15673224,0.151673648,0.66883968,0.647500016,0.46514288,0.260430512,0.063160224,0.28048096,0.112912528,0.155185232,0.191440688,0.361579504,0.202973072,0.575507536,0.085187296,0.507054384,0.37201232,0.043061552,0.092407008,0.388835456,0.219068736,0.275229056,0.643847856,0.527608464,0.349195056,0.770220176,0.617884496,0.052272144,0.105192608,0.590722048,0.19864352,0.511308832,0.168249328,0.279278448,0.378091776,0.213875472,0.346760416,0.12746832,0.34151072,0.53783856,0.229277552,0.351992816,0.229445744 +424.0,0.651416224,0.267971424,0.027373824,0.35769304,0.139709568,0.139429776,0.056897696,0.057735968,0.043618416,0.19939448,0.087588256,0.099894384,0.044049856,0.349443456,0.198965952,0.04188744,0.051722928,0.086771456,0.123723776,0.032050592,0.172349776,0.079014192,0.489974992,0.282669248,0.054595296,0.158531072,0.13871224,0.044292896,0.06467584,0.033659408,0.083222064,0.041807904,0.219863568,0.044078576,0.050551568,0.246134848,0.050291776,0.12131632,0.04726888,0.076630784,0.443411328,0.062892736,0.048933824,0.045849088,0.061560208,0.124889248,0.1518184,0.1175792,0.04672888,0.113686448,0.145858336,0.057935808,0.086796512,0.563750976,0.493125264,0.309456384,0.157987168,0.1531416,0.67009072,0.650671104,0.468362736,0.262948848,0.063373088,0.282346928,0.114219152,0.15646272,0.19302016,0.364928336,0.204879808,0.581003952,0.087564192,0.508929536,0.380470208,0.04332728,0.094429376,0.392763968,0.223243968,0.282158944,0.644802704,0.530743952,0.349884752,0.77142,0.617782688,0.05280536,0.108697552,0.59185216,0.200265584,0.510395552,0.168268768,0.27823504,0.389686416,0.218680176,0.35018776,0.1288312,0.349027664,0.540670048,0.22995264,0.353147488,0.228717344 +425.0,0.65147,0.26779,0.02972,0.35611,0.13887,0.13975,0.05694,0.05777,0.04374,0.1985,0.08748,0.09871,0.04419,0.34976,0.20029,0.04212,0.05186,0.08752,0.12359,0.03094,0.1722,0.07961,0.49171,0.28249,0.05502,0.15881,0.14548,0.044,0.06611,0.0351,0.08532,0.04209,0.22112,0.04411,0.05042,0.25618,0.05039,0.12741,0.04741,0.07683,0.44546,0.06307,0.04885,0.04589,0.06181,0.12532,0.15294,0.12154,0.04675,0.11458,0.14703,0.05801,0.08736,0.56754,0.49725,0.3113,0.15934,0.15464,0.67117,0.65381,0.47151,0.26551,0.06356,0.28427,0.11533,0.1578,0.19467,0.36826,0.20679,0.58644,0.09002,0.51073,0.38927,0.0436,0.0965,0.39675,0.22735,0.2894,0.64576,0.53377,0.35069,0.77259,0.61762,0.05334,0.11233,0.59284,0.20193,0.50938,0.16828,0.27711,0.4011,0.22337,0.35357,0.13016,0.35643,0.5434,0.23063,0.35424,0.22794 +426.0,0.651466144,0.267573664,0.032196544,0.35464008,0.13792952,0.139975552,0.056987008,0.057808224,0.043866032,0.19765592,0.08732768,0.09760496,0.044336256,0.350075936,0.201738672,0.04236432,0.051991456,0.088302912,0.12347728,0.029828496,0.172067248,0.08017296,0.493442384,0.28234368,0.055590496,0.159159968,0.152383184,0.043860448,0.06763752,0.036866176,0.087504656,0.042404704,0.222493216,0.044145856,0.050289712,0.26629968,0.050497152,0.133952016,0.047558464,0.077041408,0.44765184,0.0632612,0.048802208,0.045931552,0.062115344,0.125785184,0.154166304,0.125751488,0.04675688,0.11548144,0.148209152,0.058093136,0.087946784,0.57132576,0.501371968,0.313221472,0.160797856,0.156169712,0.672159872,0.656918144,0.47458488,0.268116704,0.063725216,0.286265824,0.116249344,0.159205216,0.196402336,0.371572912,0.208702112,0.591814048,0.092554368,0.512458064,0.398395104,0.04388024,0.098622688,0.40080416,0.231376576,0.29693704,0.6467196,0.536688096,0.351607104,0.773732672,0.617403712,0.053874848,0.116072368,0.59368272,0.203639952,0.508271184,0.168289392,0.275916,0.412313008,0.227944544,0.35690152,0.131452736,0.363701552,0.546026624,0.231325184,0.355269392,0.227127232 +427.0,0.651405152,0.267321568,0.034811216,0.3532816,0.136889552,0.140112512,0.05703808,0.057850272,0.043996336,0.196869792,0.087134944,0.09654984,0.044487616,0.350391712,0.203311552,0.042620416,0.052119168,0.089120352,0.123388944,0.028721552,0.171956704,0.080708352,0.495172096,0.282243568,0.056308608,0.159580288,0.159393056,0.043876176,0.069263328,0.038975232,0.08977728,0.042752368,0.223996288,0.044186496,0.050161168,0.276471248,0.050614128,0.140937552,0.047714064,0.077265072,0.449993424,0.063465856,0.048788704,0.045974192,0.062482608,0.12628904,0.15550032,0.130210624,0.046754432,0.116390944,0.149395552,0.05818568,0.08855752,0.575113984,0.505492496,0.315237056,0.1623652,0.157731808,0.67312032,0.659996016,0.47758776,0.270771552,0.063872704,0.28834496,0.116984848,0.160683952,0.198225408,0.374864944,0.210614192,0.597124176,0.095165616,0.514116544,0.40781512,0.044168752,0.100799248,0.404929696,0.235320496,0.304744016,0.647677616,0.539499584,0.352652656,0.774849616,0.617139376,0.054408464,0.119906048,0.594378928,0.20539496,0.507075792,0.168299248,0.274662048,0.423300896,0.232402432,0.360178176,0.13270728,0.3708248,0.54854656,0.232046432,0.356231456,0.226288304 +428.0,0.65127976,0.267029072,0.037435088,0.35199016,0.135759104,0.140175952,0.057091712,0.0578916,0.04413064,0.196130704,0.086913728,0.09564928,0.044642896,0.350703888,0.205020352,0.042891152,0.05224792,0.089974272,0.123318928,0.027646608,0.1718608,0.081233264,0.496905168,0.282170816,0.05708352,0.160074288,0.166392288,0.044025424,0.070996976,0.041327008,0.092137744,0.043133632,0.22562336,0.044231296,0.050035664,0.286675856,0.050738784,0.148344928,0.047877344,0.077501056,0.452465568,0.063682032,0.04880432,0.046017152,0.062885872,0.126828976,0.156937856,0.13488656,0.046754064,0.117310608,0.150592112,0.058288624,0.089189216,0.578878128,0.509602864,0.31732384,0.164040384,0.159324304,0.674036928,0.663046688,0.48052016,0.27347152,0.064010272,0.290489936,0.117597872,0.162231168,0.20013656,0.378131696,0.212521472,0.602364624,0.097848144,0.515711664,0.417484976,0.044465264,0.103025168,0.409105792,0.239167856,0.312787952,0.648612592,0.542207872,0.353691888,0.77592752,0.61681296,0.05493784,0.123805648,0.594892496,0.207200768,0.5057788,0.168396704,0.273326896,0.434048304,0.23673296,0.363359952,0.133927984,0.377810928,0.551001536,0.2327796,0.35711096,0.225404416 +429.0,0.651080128,0.266690176,0.03986928,0.35069808,0.134549616,0.140184032,0.057146144,0.057926208,0.044268624,0.195421456,0.086678752,0.09504896,0.044800816,0.351007664,0.206880752,0.043180288,0.052383472,0.090867232,0.123257952,0.026638464,0.171767776,0.081768736,0.4986496,0.282095824,0.057783872,0.160646688,0.17323128,0.044264352,0.072849504,0.043762464,0.094585488,0.043549296,0.227362272,0.044279296,0.04991488,0.296898144,0.05086792,0.156144064,0.048049184,0.07774936,0.455040512,0.063907328,0.048842736,0.046059312,0.063280336,0.127400112,0.158472352,0.139739216,0.046769296,0.118243072,0.151802832,0.058403088,0.089837632,0.582580912,0.513690992,0.319445904,0.165819648,0.16094416,0.674870416,0.66607408,0.48338384,0.276211728,0.06414704,0.292673952,0.118167776,0.163838304,0.202129472,0.381368128,0.214418272,0.607528352,0.100594992,0.517250784,0.427354672,0.044769056,0.105293808,0.413303568,0.242896336,0.321033568,0.649497248,0.54481704,0.35451896,0.776948144,0.616403904,0.055459376,0.127736608,0.595175824,0.209065216,0.504357968,0.16869712,0.271879264,0.444548192,0.240924208,0.366394848,0.135121248,0.384680816,0.553448352,0.233503008,0.357889104,0.224447488 +430.0,0.6508,0.2663,0.04199,0.34936,0.13327,0.14015,0.0572,0.05795,0.04441,0.19473,0.08644,0.09483,0.04496,0.3513,0.2089,0.04349,0.05253,0.0918,0.1232,0.02572,0.17167,0.08233,0.50041,0.282,0.05832,0.1613,0.1798,0.04456,0.07483,0.04618,0.09712,0.044,0.22921,0.04433,0.0498,0.30712,0.051,0.16431,0.04823,0.07801,0.4577,0.06414,0.0489,0.0461,0.06364,0.128,0.1601,0.14474,0.04681,0.11919,0.15303,0.05853,0.0905,0.5862,0.51775,0.32158,0.1677,0.16259,0.6756,0.66908,0.48618,0.27899,0.06429,0.29488,0.11875,0.1655,0.2042,0.38457,0.2163,0.61261,0.1034,0.51874,0.43737,0.04508,0.1076,0.4175,0.24649,0.32944,0.65031,0.54733,0.355,0.7779,0.6159,0.05597,0.13166,0.5952,0.21099,0.5028,0.16927,0.2703,0.45479,0.24497,0.36925,0.13629,0.39144,0.55592,0.2342,0.35855,0.2234 +431.0,0.65043912,0.265856048,0.043808864,0.34797536,0.131924064,0.140078784,0.05725256,0.0579624,0.044554608,0.194055936,0.086199632,0.094979104,0.0451192,0.351580992,0.211072464,0.043819952,0.052689008,0.092770896,0.123145552,0.024894448,0.171568336,0.082921968,0.502185664,0.281886832,0.058694976,0.162033168,0.186074656,0.044919472,0.07694376,0.048600496,0.099741328,0.044486144,0.231179488,0.04438384,0.049691344,0.317316256,0.051136064,0.172830176,0.048419456,0.078283168,0.46044432,0.064379552,0.048976016,0.046139328,0.063970784,0.128631056,0.161822288,0.14988168,0.046880064,0.120151584,0.154273216,0.058670032,0.091176544,0.58973904,0.521781744,0.323729776,0.169681488,0.164263584,0.67624808,0.672063344,0.48890912,0.281808544,0.064442528,0.2971108,0.119356864,0.167217936,0.206350096,0.387734672,0.21816424,0.617607312,0.106259344,0.520182704,0.44747976,0.045398832,0.1099424,0.421685904,0.249950208,0.337964048,0.651042432,0.549747616,0.355151104,0.778783392,0.615303792,0.056467904,0.13556192,0.59496696,0.212967952,0.501108336,0.17010968,0.268592624,0.464751392,0.24886712,0.3719244,0.13743168,0.398070032,0.558410336,0.23486664,0.359084928,0.222264656 +432.0,0.64999584,0.265355232,0.045298848,0.34653368,0.130516464,0.139976592,0.057302992,0.05796232,0.04470232,0.193396784,0.085961008,0.09551528,0.045277296,0.351850128,0.213394512,0.044170272,0.0528624,0.093778672,0.123093808,0.024168528,0.17146216,0.083550944,0.503977008,0.281755776,0.05890592,0.162845888,0.192031488,0.045350384,0.079196416,0.051027728,0.102449504,0.045008272,0.23328112,0.044441216,0.049589424,0.327462176,0.051276464,0.181688208,0.048617424,0.078569136,0.463270608,0.064625392,0.04907032,0.046177232,0.064265312,0.129294896,0.163639856,0.15515352,0.046984304,0.121128368,0.155532752,0.058823984,0.091867216,0.593196848,0.525786544,0.32589496,0.171763744,0.165966544,0.676828208,0.675023648,0.49157192,0.28466848,0.064608512,0.299365856,0.120007872,0.168992768,0.2085808,0.390859376,0.220008352,0.622517584,0.109168944,0.521582464,0.457634896,0.045725904,0.112319168,0.425849232,0.253277856,0.346564112,0.651685472,0.552070912,0.354966688,0.7795964,0.61461472,0.0569512,0.139447728,0.594473296,0.214992928,0.49928376,0.171224224,0.266756736,0.474412464,0.25260696,0.374411552,0.138544864,0.404558528,0.560920736,0.23549664,0.35948456,0.221040576 +433.0,0.6494748,0.264795216,0.046554512,0.34504384,0.129050304,0.13984256,0.057351024,0.05795056,0.044852752,0.192750192,0.085720144,0.096288816,0.045431952,0.352109264,0.21584656,0.044538192,0.053049792,0.094817808,0.123046624,0.023529408,0.171353104,0.08421656,0.505777792,0.28161416,0.058933824,0.163733808,0.19762536,0.045804416,0.081592592,0.05347688,0.1052432,0.0455664,0.235537312,0.044502592,0.049493984,0.337536816,0.051425184,0.19086888,0.048822832,0.078867584,0.466183696,0.064877312,0.049185824,0.046214336,0.06455984,0.129994736,0.165555664,0.16055664,0.047121744,0.122118752,0.156805328,0.058992016,0.092572368,0.596593616,0.529772784,0.328078464,0.17394272,0.167701344,0.677353056,0.677955232,0.49416744,0.287576176,0.064788896,0.301650672,0.120694,0.17082528,0.210889744,0.3939416,0.221830144,0.627339776,0.112123024,0.522943024,0.467747792,0.046063296,0.114726816,0.42997728,0.256461184,0.355168896,0.652226032,0.554299728,0.354466432,0.780346688,0.613844288,0.057417536,0.143182976,0.593745872,0.217046464,0.497335824,0.172544608,0.264804528,0.483762656,0.25621728,0.376735184,0.139621488,0.410860864,0.563412096,0.2360804,0.359736752,0.219736736 +434.0,0.64888432,0.26417424,0.047740896,0.34352856,0.127527344,0.139671328,0.057396736,0.05792928,0.045005424,0.19211512,0.08546848,0.097060672,0.045580288,0.35236176,0.218399568,0.044919232,0.053249344,0.095880384,0.12300784,0.022952368,0.171244848,0.084913856,0.507577936,0.281475584,0.058765088,0.164690208,0.202814832,0.046212128,0.084135888,0.055983552,0.108120496,0.046160288,0.237978304,0.044568608,0.049404304,0.347520096,0.051588224,0.200358352,0.04903408,0.079177952,0.469194304,0.065135472,0.049327648,0.04625168,0.064913328,0.130735136,0.167574432,0.16610048,0.047287824,0.123119936,0.158085664,0.059173968,0.09329296,0.599962944,0.533753824,0.330287968,0.176212896,0.169471344,0.677839104,0.680849536,0.49669384,0.290540992,0.06498272,0.303975968,0.121387168,0.172717152,0.213273568,0.396979184,0.223627936,0.632074048,0.115115264,0.524267824,0.477712768,0.046413968,0.117161504,0.434058368,0.259484832,0.3636924,0.652650992,0.556433024,0.353700416,0.781047936,0.613011456,0.057864512,0.146573904,0.592830048,0.2191028,0.495280368,0.173955312,0.26275696,0.492794928,0.25974272,0.378937616,0.140649632,0.41691432,0.565821056,0.236608,0.359828944,0.218369216 +435.0,0.64823,0.26349,0.04896,0.342,0.12595,0.13946,0.05744,0.0579,0.04516,0.19149,0.0852,0.09767,0.04572,0.35261,0.22103,0.04531,0.05346,0.09696,0.12298,0.02242,0.17114,0.08564,0.50937,0.28135,0.0584,0.16571,0.20758,0.04653,0.08683,0.05858,0.11108,0.04679,0.24063,0.04464,0.04932,0.35739,0.05177,0.21014,0.04925,0.0795,0.47231,0.0654,0.0495,0.04629,0.06536,0.13152,0.1697,0.17179,0.04748,0.12413,0.15937,0.05937,0.09403,0.60333,0.53774,0.33253,0.17857,0.17128,0.6783,0.6837,0.49915,0.29357,0.06519,0.30635,0.12207,0.17467,0.21573,0.39997,0.2254,0.63672,0.11814,0.52556,0.48744,0.04678,0.11962,0.43808,0.26234,0.37206,0.65295,0.55847,0.35271,0.78171,0.61213,0.05829,0.1495,0.59176,0.22114,0.49313,0.17537,0.26063,0.5015,0.26321,0.38105,0.14162,0.42267,0.5681,0.23707,0.35975,0.21695 +436.0,0.647509408,0.262738752,0.05018144,0.340446976,0.124322976,0.139212832,0.05747984,0.0578624,0.045316384,0.190872128,0.084916352,0.09813768,0.045850512,0.352853728,0.223731024,0.045710496,0.053682976,0.098054656,0.12296192,0.021936736,0.171038032,0.0863988,0.511154368,0.281236416,0.057837536,0.166792832,0.211913488,0.046757312,0.089679072,0.061265968,0.114122064,0.047456576,0.243505536,0.044717552,0.049241472,0.367124832,0.05197024,0.220193536,0.049470608,0.079834336,0.4755288,0.06567088,0.049704384,0.046329152,0.065892192,0.132351264,0.1719336,0.177616528,0.047701792,0.125149696,0.160659088,0.059581136,0.094784672,0.606694752,0.541732784,0.334807536,0.181013536,0.173131088,0.678741184,0.686505824,0.50153688,0.296663264,0.06541352,0.30877376,0.122757328,0.17668496,0.218259872,0.40291216,0.227144464,0.641275312,0.121193792,0.526822064,0.496887504,0.047161152,0.122100896,0.44202704,0.265029216,0.380231216,0.653121136,0.560410784,0.351491168,0.782331264,0.611198336,0.0586928,0.151978,0.59053616,0.2231476,0.490887376,0.176789616,0.258424512,0.509867904,0.266610768,0.383070016,0.142531232,0.428120656,0.570248608,0.237458432,0.359492848,0.215478912 +437.0,0.64671976,0.261916656,0.051402672,0.33886424,0.122650864,0.13893288,0.057515104,0.05781672,0.045474432,0.190259872,0.084618304,0.098465296,0.045971632,0.353093024,0.22649456,0.046120752,0.053919072,0.099162048,0.122952624,0.021505808,0.170939024,0.08719264,0.512931472,0.2811348,0.057065184,0.167938288,0.21579904,0.046879696,0.092686352,0.0640372,0.11724744,0.04816136,0.246619872,0.044802192,0.049168944,0.376706576,0.052188304,0.2305,0.049695952,0.080181744,0.478850016,0.065948432,0.049943344,0.046368976,0.06651728,0.133231296,0.174277024,0.18357312,0.047956064,0.126179952,0.161953968,0.059808496,0.095559008,0.610058176,0.545734384,0.337127104,0.18354352,0.175029664,0.679167856,0.689266112,0.5038556,0.299820176,0.065655376,0.311250192,0.12346048,0.17876384,0.220864624,0.4058044,0.228859984,0.645737856,0.124273984,0.528055904,0.506020432,0.047556976,0.124603456,0.44588392,0.267554144,0.388168416,0.653167552,0.562255088,0.350041472,0.782910448,0.610214688,0.059072256,0.154002816,0.589160832,0.225113264,0.488556624,0.178211568,0.256142768,0.517894896,0.26994336,0.384997584,0.143382128,0.433262384,0.572265856,0.23776584,0.359052272,0.213957056 +438.0,0.645866752,0.26102112,0.052584384,0.337241344,0.120935552,0.138618928,0.057546288,0.05776376,0.04563424,0.189649696,0.084300656,0.098616992,0.046080672,0.35332936,0.229297936,0.046537088,0.054167808,0.1002764,0.122954128,0.0211112,0.170844816,0.0880196,0.514694016,0.281054144,0.056180672,0.169141664,0.219329792,0.0469372,0.095856112,0.066974912,0.120454016,0.048903984,0.249996608,0.044894992,0.049102656,0.38609728,0.052428848,0.241032064,0.049925056,0.080542032,0.482280112,0.066232544,0.050219984,0.04641016,0.067189808,0.134163568,0.176733488,0.189663392,0.048240896,0.127218608,0.163250688,0.060052336,0.096353104,0.61344424,0.549753984,0.339491872,0.186155104,0.17697784,0.679593328,0.69197488,0.50610504,0.303048768,0.065916592,0.313785344,0.124165392,0.18090816,0.223541696,0.40864368,0.230544304,0.65010752,0.127373616,0.529264704,0.51474128,0.04796912,0.127123776,0.44963896,0.269923552,0.395794096,0.653073568,0.564002112,0.348439136,0.783457072,0.60919264,0.059425472,0.155640752,0.587666704,0.227016928,0.486149392,0.1795536,0.253799584,0.525553408,0.273190432,0.386861552,0.144163104,0.438042592,0.574104704,0.237982208,0.358415696,0.21239488 +439.0,0.644958864,0.260049904,0.053656096,0.335563328,0.11917792,0.138268416,0.057574512,0.05770448,0.045796048,0.18903728,0.083956208,0.098562048,0.046174112,0.353564576,0.232113552,0.046954544,0.054428304,0.101390832,0.122969392,0.020730512,0.170757808,0.08887624,0.51643216,0.281006448,0.0553328,0.17039688,0.222652704,0.046999664,0.099192912,0.070196304,0.123738672,0.049683488,0.253662144,0.044997152,0.049042928,0.395250304,0.052698272,0.251758048,0.05015664,0.08091472,0.485827968,0.066522976,0.050537584,0.046453664,0.067835936,0.13515192,0.179306672,0.195894544,0.048552768,0.128262464,0.164543648,0.060312656,0.0971664,0.616884544,0.553803024,0.34190392,0.188841808,0.178976736,0.68003352,0.694624528,0.50828336,0.30636,0.066197888,0.316386256,0.124849504,0.18311944,0.226287248,0.41142632,0.232194864,0.654384944,0.130484208,0.530451984,0.522931568,0.048399824,0.129656896,0.45328184,0.27215136,0.403017456,0.652817184,0.565650816,0.34679568,0.783984256,0.608150832,0.059748768,0.157009408,0.586096656,0.228835952,0.48367992,0.180706992,0.251414,0.53280592,0.276323184,0.3887004,0.14486176,0.4423924,0.575702752,0.238096656,0.35756816,0.210805904 +440.0,0.644,0.259,0.05457,0.33382,0.11738,0.13788,0.0576,0.05764,0.04596,0.18842,0.08358,0.09829,0.04625,0.3538,0.23492,0.04737,0.0547,0.1025,0.123,0.02035,0.17068,0.08976,0.51814,0.281,0.05462,0.1717,0.22587,0.04711,0.1027,0.07378,0.1271,0.0505,0.25764,0.04511,0.04899,0.40413,0.053,0.26265,0.05039,0.0813,0.4895,0.06682,0.0509,0.0465,0.06841,0.1362,0.182,0.20227,0.04889,0.12931,0.16583,0.06059,0.098,0.6204,0.55789,0.34437,0.1916,0.18103,0.6805,0.69721,0.51039,0.30976,0.0665,0.31906,0.1255,0.1854,0.2291,0.41415,0.23381,0.65857,0.1336,0.53162,0.53051,0.04885,0.1322,0.4568,0.27425,0.40977,0.65239,0.5672,0.34519,0.7845,0.6071,0.06004,0.1582,0.58448,0.23055,0.48116,0.1816,0.249,0.53963,0.27932,0.39054,0.14547,0.44627,0.57702,0.2381,0.3565,0.2092 +441.0,0.642987152,0.257867936,0.055347472,0.332007664,0.115545968,0.137455008,0.057621584,0.05757136,0.046125936,0.187797856,0.08317152,0.097788,0.046308736,0.354035968,0.237707696,0.047783488,0.054983056,0.103601472,0.1230452,0.019971776,0.170612464,0.090670816,0.51981832,0.281036176,0.05403488,0.173050576,0.228972064,0.047252896,0.106378512,0.07771904,0.130539184,0.051355392,0.261945264,0.045234752,0.048943904,0.41272344,0.053332608,0.273685808,0.050625216,0.08169864,0.493297248,0.067124688,0.051311328,0.046548944,0.06892368,0.137310944,0.184816144,0.208785056,0.049254624,0.130362368,0.16711112,0.060885312,0.098857312,0.623992336,0.562017632,0.346901616,0.194430768,0.183144704,0.680997072,0.699730624,0.512426144,0.313246592,0.066824016,0.321812416,0.12612256,0.187752992,0.231982512,0.41681392,0.235388848,0.662660784,0.136719232,0.532769248,0.537456704,0.04931856,0.134753168,0.460178128,0.276219568,0.416021936,0.651803504,0.568648512,0.343624256,0.785003376,0.606037968,0.060299376,0.159200272,0.582821536,0.232144928,0.478596016,0.182226096,0.246562096,0.54602984,0.28217984,0.392382736,0.145987008,0.449678432,0.578055472,0.23798624,0.35521,0.207580144 +442.0,0.641919232,0.25665112,0.056014464,0.330117984,0.113679552,0.136994368,0.057638528,0.05749952,0.04629368,0.187170496,0.082729616,0.097022672,0.046350192,0.35427288,0.240465536,0.048194448,0.055277488,0.10469256,0.123104688,0.01959576,0.170556496,0.09160824,0.521466816,0.281117504,0.053585952,0.174447424,0.231955712,0.04742288,0.110229392,0.082010352,0.134056736,0.052251264,0.266591408,0.045372512,0.048904656,0.4210168,0.053695488,0.284839504,0.050862096,0.082110832,0.497221232,0.067438144,0.051775424,0.0466004,0.069378128,0.138488048,0.187757888,0.215435712,0.049648256,0.131420128,0.168387328,0.061198976,0.099741264,0.62766608,0.566189104,0.349508112,0.197334544,0.18532712,0.681530128,0.70218512,0.51439232,0.316818608,0.067170992,0.324649264,0.126719472,0.19018144,0.234936576,0.4194164,0.236929904,0.66665544,0.139839056,0.533900384,0.54374344,0.04980472,0.137315536,0.46340248,0.278055792,0.421739456,0.651065168,0.569995152,0.342102976,0.785494992,0.6049652,0.060526672,0.159987712,0.581130064,0.233606928,0.475994992,0.18256784,0.244106464,0.552006208,0.284899872,0.394234192,0.146410704,0.452613552,0.578801904,0.237749488,0.353696176,0.20595048 +443.0,0.640784592,0.255341984,0.056516256,0.328161024,0.111785856,0.136499088,0.057648032,0.0574268,0.046463424,0.186540576,0.082254512,0.096130384,0.046377648,0.354510912,0.243187136,0.048605088,0.05558336,0.105771568,0.123176016,0.019230624,0.170513328,0.092570384,0.523090912,0.281242672,0.053265184,0.175893232,0.234872,0.047607904,0.114252432,0.086668384,0.137657008,0.053191056,0.271603152,0.045525712,0.048872448,0.42899584,0.054083088,0.29609768,0.051102096,0.082540224,0.501273856,0.06776208,0.05229936,0.046653536,0.069792576,0.139734672,0.190828512,0.222218288,0.050073248,0.132487088,0.169664896,0.06153456,0.100658816,0.631413584,0.570406336,0.352216928,0.200316,0.187590016,0.682098064,0.704575536,0.516292816,0.320468784,0.067541088,0.327580352,0.127302784,0.192690928,0.23796936,0.42196112,0.23843592,0.670552736,0.14296312,0.53501144,0.549397536,0.05030512,0.139892304,0.466450992,0.279791216,0.426914496,0.650212432,0.571237712,0.340660416,0.785968448,0.603868192,0.060724688,0.160712432,0.579398512,0.234916768,0.473364208,0.182655824,0.241634032,0.557577376,0.287462224,0.396088368,0.14674552,0.455113472,0.579281936,0.237384256,0.351964512,0.204311616 +444.0,0.639565792,0.253930688,0.056770848,0.326155584,0.10987088,0.135970528,0.057646176,0.05735616,0.046635488,0.185912576,0.081747648,0.095325136,0.046396304,0.354749984,0.245869936,0.049019328,0.055900832,0.106837696,0.123255424,0.018891328,0.17048408,0.093554928,0.524699648,0.28140768,0.053043936,0.17739296,0.237782608,0.047786208,0.118446432,0.091703376,0.14134648,0.054179328,0.277008896,0.045697392,0.04884752,0.4366496,0.054486848,0.307452896,0.051347536,0.082992096,0.50545648,0.068098656,0.052891776,0.046707072,0.070201344,0.141054176,0.194031456,0.229128144,0.0505328,0.133568928,0.170953424,0.061897104,0.101619168,0.635218848,0.574669808,0.355064624,0.203382496,0.189949712,0.68269568,0.706906112,0.518133872,0.32418576,0.067934064,0.33061728,0.127891376,0.195288416,0.241091104,0.4244544,0.239911696,0.674351472,0.146098624,0.536098896,0.554481552,0.05081488,0.142491872,0.469297504,0.28147328,0.431556976,0.649299696,0.572373472,0.339333696,0.786412864,0.602725184,0.060897984,0.161590192,0.57760912,0.236053648,0.470710384,0.182551888,0.23914208,0.562773664,0.289844336,0.397930624,0.146999936,0.457242512,0.579537568,0.236885824,0.350026128,0.202661632 +445.0,0.63825,0.25241,0.05674,0.32411,0.10794,0.13541,0.05763,0.05729,0.04681,0.18529,0.08121,0.09474,0.04641,0.35499,0.24851,0.04944,0.05623,0.10789,0.12334,0.01859,0.17047,0.09456,0.5263,0.28161,0.0529,0.17895,0.24072,0.04794,0.12281,0.09711,0.14513,0.05522,0.28283,0.04589,0.04883,0.44397,0.0549,0.31889,0.0516,0.08347,0.50977,0.06845,0.05356,0.04676,0.07063,0.14245,0.19737,0.23616,0.05103,0.13467,0.17226,0.06229,0.10263,0.63907,0.57898,0.35808,0.20654,0.19242,0.68332,0.70918,0.51992,0.32796,0.06835,0.33377,0.1285,0.19798,0.24431,0.4269,0.24136,0.67805,0.14925,0.53716,0.55904,0.05133,0.14512,0.47192,0.28313,0.43567,0.64837,0.5734,0.33814,0.78682,0.60152,0.06105,0.16275,0.57575,0.237,0.46804,0.1823,0.23663,0.56762,0.29203,0.39975,0.14718,0.45905,0.5796,0.23625,0.34789,0.201 +446.0,0.636838144,0.2507808,0.056443408,0.322015776,0.105996784,0.13481864,0.057599168,0.0572288,0.046986544,0.184673616,0.08064112,0.09435176,0.046418336,0.355231136,0.25109936,0.049866768,0.056570688,0.108926912,0.123429408,0.018329984,0.17047264,0.095585072,0.527892736,0.281851392,0.052843984,0.180562976,0.243691712,0.048077152,0.12734144,0.102875616,0.149007504,0.056314912,0.28906688,0.046104032,0.04881976,0.45094808,0.055321216,0.33038088,0.051858896,0.083972192,0.51421408,0.068818,0.0543072,0.046812192,0.071076,0.14392592,0.200846912,0.243306384,0.051567424,0.135790352,0.1735844,0.062711616,0.103694368,0.642967456,0.583337536,0.361268336,0.209790208,0.195007072,0.683974944,0.711396912,0.521650528,0.331787488,0.06879,0.337043424,0.129131184,0.200768896,0.247628192,0.429294224,0.242777376,0.68164528,0.152413536,0.538194752,0.56306336,0.05184896,0.147774272,0.474308704,0.284757344,0.439236224,0.647432272,0.574315776,0.337078128,0.787189472,0.600253344,0.061180672,0.164180832,0.573826992,0.237747568,0.465358848,0.181890208,0.234103424,0.572120176,0.294016192,0.4015464,0.147284368,0.460540528,0.579467792,0.235473984,0.34555888,0.199330176 +447.0,0.635332432,0.249046224,0.055873456,0.319870624,0.104044816,0.134197888,0.057553472,0.05717256,0.047164544,0.184064816,0.080041152,0.094171184,0.046420608,0.355473552,0.253632256,0.050299488,0.05692264,0.109947488,0.123523296,0.018116784,0.170493568,0.096629904,0.529479232,0.282132912,0.052886864,0.182230352,0.24672816,0.048214784,0.132037792,0.108993904,0.152978528,0.057465936,0.295711872,0.046339472,0.048816608,0.45757448,0.055748848,0.34190088,0.052123376,0.084495664,0.518787056,0.06920488,0.05513584,0.046863536,0.071537296,0.145485952,0.204464832,0.250557248,0.052148288,0.136929568,0.174926096,0.06315904,0.104815216,0.646908944,0.587741456,0.364631648,0.21313544,0.197716816,0.684663744,0.713557056,0.523324016,0.335662624,0.069255328,0.340441552,0.129788384,0.203658128,0.25104792,0.43163216,0.24415904,0.685133456,0.15558496,0.53920312,0.566552016,0.05236984,0.150451104,0.476456192,0.286360416,0.442247616,0.646495312,0.575119232,0.336155856,0.787520208,0.598926192,0.061289888,0.165914512,0.571843792,0.238291648,0.462671648,0.181317584,0.231567312,0.576277776,0.295799824,0.403315808,0.14731208,0.461723392,0.579143056,0.234556656,0.343038032,0.197654896 +448.0,0.63371888,0.247196208,0.055165904,0.317647552,0.102089328,0.133548816,0.057490336,0.05712464,0.047344224,0.183466096,0.079410544,0.094124368,0.04642128,0.355716528,0.256102352,0.050740608,0.057286192,0.110950544,0.123618704,0.017960944,0.170534176,0.097692336,0.531065888,0.282452992,0.052979024,0.183955808,0.249713488,0.048298336,0.136898384,0.115374432,0.157048352,0.05867728,0.302794064,0.046599632,0.048820576,0.46386056,0.05617632,0.35341104,0.052395216,0.085045456,0.523490832,0.06961272,0.0560544,0.04691288,0.072042672,0.147133104,0.208227232,0.257910432,0.052775392,0.138093104,0.176292032,0.063637104,0.106000464,0.650885472,0.592193536,0.36820248,0.216581232,0.20056336,0.685383664,0.71566344,0.524945744,0.33957736,0.069745776,0.34397544,0.130485104,0.20665456,0.254577088,0.433918336,0.245509344,0.688513792,0.158768944,0.540181488,0.569540352,0.05288936,0.153157936,0.47833848,0.287905648,0.444697968,0.645602352,0.575807888,0.335298544,0.787804784,0.59752184,0.061381424,0.167796752,0.569790432,0.238611888,0.459985888,0.18062168,0.22902192,0.580127856,0.297376496,0.405051536,0.147268992,0.462642736,0.57865392,0.233492528,0.340333504,0.195974736 +449.0,0.631978128,0.245216192,0.054528752,0.31530648,0.10013608,0.132872384,0.05740648,0.0570896,0.047526064,0.182880256,0.078749856,0.094080352,0.046426592,0.355958944,0.258503088,0.051193408,0.057661904,0.11193488,0.123711792,0.017874784,0.170595824,0.098769568,0.532660784,0.282809232,0.053046144,0.185744784,0.252462176,0.048244768,0.141923216,0.1218856,0.161224176,0.059953984,0.310354736,0.046888992,0.048831744,0.46982776,0.056595392,0.36486424,0.052677056,0.085629328,0.528328448,0.0700436,0.05707344,0.046958704,0.072631808,0.148870016,0.212137872,0.265366496,0.053451456,0.13928848,0.177691568,0.064153248,0.107259712,0.65488584,0.596696416,0.372023632,0.220134224,0.203563584,0.686129904,0.717720064,0.526523232,0.343522816,0.070260624,0.347658528,0.131238144,0.209766432,0.258225456,0.436160352,0.246835728,0.691786608,0.161973088,0.541124896,0.572074048,0.05340384,0.155905968,0.479926128,0.28933784,0.44658168,0.644808112,0.576378944,0.334390272,0.78803368,0.596017648,0.0614604,0.169571152,0.567652352,0.238682848,0.457309968,0.179856976,0.226465968,0.583717616,0.298743328,0.406746064,0.147163264,0.46335424,0.578037264,0.23227472,0.337451536,0.194289616 +450.0,0.6301,0.2431,0.0541,0.31282,0.09819,0.13217,0.0573,0.05707,0.04771,0.18231,0.07806,0.09395,0.04644,0.3562,0.26083,0.05166,0.05805,0.1129,0.1238,0.01787,0.17068,0.09986,0.53427,0.2832,0.05304,0.1876,0.25486,0.04801,0.14711,0.12843,0.16551,0.0613,0.31841,0.04721,0.04885,0.47549,0.057,0.37622,0.05297,0.08625,0.5333,0.0705,0.0582,0.047,0.07333,0.1507,0.2162,0.27292,0.05418,0.14052,0.17913,0.06471,0.1086,0.6589,0.60125,0.37612,0.2238,0.20673,0.6869,0.71973,0.52806,0.34749,0.0708,0.3515,0.13206,0.213,0.262,0.43836,0.24814,0.69495,0.1652,0.54203,0.57419,0.05391,0.1587,0.4812,0.29062,0.4479,0.64415,0.57683,0.33335,0.7882,0.5944,0.06153,0.17107,0.56542,0.23849,0.45465,0.17906,0.2239,0.58708,0.2999,0.40839,0.147,0.4639,0.57732,0.2309,0.3344,0.1926 +451.0,0.628088816,0.240854144,0.053865792,0.310191152,0.096254592,0.131443504,0.057171152,0.057065232,0.047895264,0.181757232,0.07734208,0.093755232,0.046460592,0.356439648,0.263081264,0.05214048,0.058450064,0.11384616,0.123882928,0.017956816,0.170788304,0.100963952,0.535895568,0.283625472,0.05296576,0.18952016,0.256939328,0.047603984,0.152453056,0.13499016,0.169905248,0.062717312,0.326937792,0.047562128,0.048875072,0.480844032,0.057388128,0.387456064,0.05327288,0.086902912,0.538400976,0.070984608,0.059436496,0.047036704,0.074139632,0.15262728,0.220415792,0.280557008,0.054965312,0.141786896,0.180606368,0.06530288,0.110023984,0.66292152,0.605850256,0.380488688,0.227581424,0.210066848,0.687696176,0.721694304,0.52955368,0.35147056,0.071365184,0.355501392,0.132955136,0.2163572,0.265901888,0.440510736,0.249415792,0.697999088,0.168443792,0.542896448,0.575904368,0.054405568,0.161533984,0.482157936,0.29175824,0.448661168,0.643634432,0.577159328,0.332187376,0.78830168,0.592670128,0.061590144,0.172326192,0.563093728,0.23803568,0.452008544,0.178233552,0.221327648,0.590220912,0.3008484,0.409973936,0.146778992,0.46429544,0.576509504,0.229370688,0.331188176,0.190907504 +452.0,0.62594592,0.238482368,0.053831104,0.307422512,0.094333568,0.130694496,0.057019856,0.05707536,0.048081344,0.181223536,0.076597104,0.093510368,0.04648856,0.356677728,0.265254912,0.052635328,0.058861712,0.114773504,0.123959744,0.018146864,0.170922256,0.102081456,0.537539888,0.284085712,0.052821024,0.191505328,0.258709968,0.047009776,0.157946864,0.141538112,0.174410912,0.06420824,0.335922704,0.047945712,0.048906816,0.48589056,0.0577572,0.39855064,0.053585136,0.087585536,0.543627152,0.07149984,0.06078744,0.04706864,0.075070512,0.154655744,0.224787312,0.288265552,0.055811392,0.143089664,0.182121232,0.065929424,0.111535024,0.666943552,0.610493536,0.3851328,0.231481232,0.21357864,0.688520064,0.72361432,0.531003504,0.35545592,0.071956976,0.35966456,0.133929104,0.21983968,0.269932048,0.442608336,0.250659024,0.700929952,0.171699584,0.543723328,0.577236672,0.05488832,0.164403216,0.48279584,0.292753968,0.448872928,0.643271392,0.577365008,0.330911344,0.788335824,0.59082616,0.061641424,0.173344272,0.560672272,0.237319888,0.449388448,0.17738616,0.2187516,0.593150896,0.301591376,0.411489696,0.146501152,0.464559456,0.57561608,0.227688608,0.327825024,0.189213456 +453.0,0.623690224,0.236006192,0.053998816,0.304502272,0.092429504,0.129926448,0.05684848,0.057096608,0.048266064,0.18071296,0.075827808,0.093162704,0.046518288,0.356913968,0.26735392,0.053143296,0.0592844,0.115684368,0.12403168,0.018449632,0.171083968,0.10321456,0.539204768,0.284580192,0.052614928,0.193548576,0.260214848,0.046335888,0.163582032,0.148032224,0.179019376,0.065773808,0.345299536,0.048356096,0.04894416,0.490628768,0.058106672,0.409466176,0.053902592,0.08828288,0.548969888,0.072050432,0.062245904,0.047096096,0.076100032,0.156791248,0.229316992,0.296019216,0.056725312,0.144422192,0.183666496,0.066574688,0.113132864,0.670956144,0.615170816,0.390019392,0.23550424,0.217267952,0.689374432,0.725491296,0.532399168,0.35943536,0.072578768,0.363988128,0.134983552,0.22345072,0.274092608,0.444634096,0.251851776,0.703732336,0.174956016,0.544511568,0.578209216,0.055355312,0.167294448,0.483124384,0.293597936,0.448564128,0.643052832,0.577445888,0.329469472,0.788302448,0.588882032,0.061681264,0.174115792,0.558157936,0.236362176,0.446788912,0.176508368,0.216178112,0.5958668,0.302138592,0.412915456,0.146162752,0.464702512,0.574642976,0.225861808,0.324325712,0.187519568 +454.0,0.621350848,0.233457216,0.054351728,0.301416352,0.09054424,0.12914376,0.056660864,0.057122976,0.048446384,0.180230544,0.075037792,0.092642,0.046540896,0.357148128,0.269384128,0.053662064,0.059717408,0.116582272,0.124101216,0.01887376,0.17127584,0.104366544,0.540891168,0.285108352,0.052368752,0.195639264,0.261530368,0.0457536,0.16934672,0.154433856,0.18371848,0.067414176,0.354974048,0.04878592,0.048985584,0.495055536,0.058437504,0.420160432,0.054219088,0.088973184,0.554417664,0.072642224,0.063799168,0.047119712,0.077188032,0.159040672,0.234007232,0.3037836,0.057715712,0.14577464,0.1852292,0.067216992,0.114814944,0.674948256,0.619869856,0.395094864,0.239655808,0.221135104,0.6902632,0.727326192,0.533725152,0.36339712,0.07323528,0.368467936,0.1361172,0.2271936,0.278385248,0.446561456,0.252968608,0.70639264,0.178197408,0.545263328,0.57884336,0.055803424,0.1701888,0.483163808,0.294281184,0.447775168,0.642957712,0.577401248,0.32779352,0.788203552,0.586861024,0.061705184,0.174649792,0.55555592,0.235193904,0.444206816,0.175578016,0.213615424,0.598355664,0.302503808,0.414222976,0.145757232,0.464727568,0.573587632,0.223902208,0.32070864,0.18582784 +455.0,0.61895,0.23086,0.05487,0.29816,0.08868,0.12835,0.05646,0.05715,0.04862,0.17978,0.07423,0.09191,0.04655,0.35738,0.27135,0.05419,0.06016,0.11747,0.12417,0.01943,0.1715,0.10554,0.5426,0.28567,0.0521,0.19777,0.26272,0.04537,0.17523,0.16071,0.1885,0.06913,0.36487,0.04923,0.04903,0.49917,0.05875,0.4306,0.05453,0.08964,0.55996,0.07328,0.06544,0.04714,0.07831,0.16141,0.23886,0.31153,0.05879,0.14714,0.1868,0.06784,0.11658,0.67891,0.62458,0.40032,0.24394,0.22518,0.69119,0.72912,0.53497,0.36733,0.07393,0.3731,0.13733,0.23107,0.28281,0.44837,0.25399,0.7089,0.18141,0.54598,0.57916,0.05623,0.17307,0.48293,0.2948,0.44654,0.64297,0.57723,0.32585,0.78804,0.58478,0.06171,0.17496,0.55287,0.23384,0.44164,0.17458,0.21107,0.60061,0.3027,0.41539,0.14528,0.46464,0.57245,0.22182,0.31699,0.18414 +456.0,0.616489344,0.228218176,0.055565136,0.294737184,0.086840048,0.127546352,0.056246432,0.057177584,0.048786576,0.179361248,0.073405488,0.090966096,0.046546608,0.357609664,0.273251584,0.054727376,0.060611584,0.118348064,0.124237376,0.020135088,0.171757728,0.106735376,0.544331984,0.286266016,0.051805488,0.199942976,0.263779392,0.045171568,0.181223664,0.166831088,0.193367392,0.070923456,0.374965248,0.049689648,0.049077776,0.502978672,0.059042432,0.440767536,0.054835088,0.090282528,0.565589696,0.073965648,0.067177568,0.04715712,0.079472992,0.163902528,0.24387584,0.319246656,0.059952064,0.14851984,0.188380608,0.06844312,0.118430816,0.682835072,0.629295184,0.405698656,0.248357056,0.229401504,0.69215776,0.730873872,0.5361348,0.371224704,0.074662656,0.377880976,0.138625888,0.235076512,0.287362112,0.4500576,0.254914064,0.711251792,0.184586016,0.546660896,0.579178528,0.056633536,0.175929376,0.482425792,0.295152608,0.444873312,0.643089008,0.576929904,0.323643376,0.787809376,0.58263664,0.061696464,0.175035008,0.550099472,0.232305792,0.439089264,0.173520288,0.208542944,0.602640592,0.30273392,0.416412304,0.144732464,0.464452496,0.571237536,0.219620288,0.313179536,0.182456768 +457.0,0.613970544,0.225534992,0.056459056,0.291146672,0.085027344,0.126733728,0.05602104,0.057205488,0.048945824,0.1789732,0.072565248,0.089787904,0.046532208,0.357837488,0.2750896,0.055274256,0.06107152,0.119217008,0.12430288,0.021008192,0.172050128,0.10795328,0.546086688,0.286897872,0.051480448,0.202161616,0.264692048,0.045176528,0.187318192,0.172767824,0.198325616,0.072796608,0.385235296,0.050166816,0.04912968,0.506489968,0.059313632,0.450645536,0.055134272,0.09090112,0.571298128,0.074700752,0.069023904,0.047171456,0.080675792,0.166521168,0.249054352,0.326922336,0.061205632,0.149916432,0.189973616,0.069027008,0.120369904,0.686718064,0.634008176,0.411235712,0.2529056,0.233795232,0.693170432,0.732588736,0.537222048,0.37507192,0.075432288,0.382804608,0.140007792,0.23920656,0.292033488,0.451623616,0.255740416,0.713446336,0.187716176,0.547305648,0.578916256,0.057012912,0.178755968,0.481657664,0.295333216,0.442792128,0.643307792,0.576498528,0.321155392,0.787509728,0.580428352,0.061665424,0.174853632,0.547244336,0.230598896,0.436554432,0.172402208,0.206034512,0.60445816,0.302611952,0.417288816,0.144116272,0.464173152,0.569955216,0.217309808,0.309287072,0.180778528 +458.0,0.611415424,0.222835008,0.057442976,0.28742744,0.08324464,0.125915744,0.055786288,0.057229872,0.049095872,0.178620192,0.071712128,0.088475552,0.046500128,0.358062592,0.276868416,0.055829536,0.061538736,0.120079712,0.124367584,0.022058336,0.172379568,0.109196304,0.547866272,0.287564848,0.051162688,0.204417616,0.265591664,0.045316288,0.193504,0.17851384,0.2033652,0.07475016,0.395606064,0.050655744,0.049183904,0.509699904,0.059563472,0.460221616,0.055423216,0.091478752,0.57707592,0.075489856,0.07096904,0.047183232,0.081932912,0.169272288,0.254398704,0.334528096,0.06255792,0.151321904,0.191568384,0.069574656,0.122395952,0.690547936,0.638709808,0.416891088,0.257591184,0.23836392,0.694230304,0.73426568,0.538218176,0.378860016,0.0762432,0.3878696,0.141476096,0.243465568,0.296827184,0.453046432,0.256448288,0.71547176,0.190787776,0.54791488,0.578396384,0.057365568,0.18153624,0.480637856,0.295369744,0.440327904,0.643615936,0.575935072,0.318507888,0.7871412,0.578172144,0.061613504,0.174517776,0.54430808,0.22874256,0.43403416,0.171213488,0.20355208,0.606051568,0.302355184,0.417993968,0.1434264,0.463811808,0.568605536,0.214896928,0.305328368,0.179107728 +459.0,0.608852464,0.220149824,0.058351456,0.283638288,0.081494656,0.12509688,0.055545136,0.057245776,0.0492344,0.178308304,0.070849568,0.08718944,0.046441008,0.358283616,0.278593712,0.056391776,0.062011952,0.120939856,0.124433008,0.02329128,0.172748848,0.110467728,0.549673776,0.288265504,0.050907328,0.206698816,0.26667168,0.045469328,0.199771488,0.184074896,0.208471904,0.076784352,0.405986912,0.051148112,0.049237728,0.51260016,0.059792192,0.469488576,0.05569624,0.091992704,0.582913392,0.0763384,0.072995696,0.047192608,0.083269232,0.172163408,0.259913296,0.342029136,0.064017248,0.152724976,0.193149792,0.070063264,0.12450632,0.694311728,0.64339032,0.422609744,0.262421648,0.243112608,0.695339056,0.735905824,0.539104144,0.382576512,0.077101472,0.393076272,0.14303024,0.247863056,0.30174992,0.454297488,0.25701016,0.717312784,0.193786896,0.548489472,0.577644112,0.057688544,0.184255872,0.479380528,0.295305952,0.43751688,0.64400176,0.575239296,0.315891504,0.786704592,0.575891536,0.061535904,0.17418344,0.541295424,0.226765344,0.431526688,0.169936688,0.201105408,0.607401776,0.301990896,0.418494,0.142655568,0.463378864,0.567190176,0.212390528,0.301321104,0.177447568 +460.0,0.6063,0.2175,0.05908,0.27982,0.07978,0.12428,0.0553,0.05725,0.04936,0.17804,0.06998,0.08603,0.04635,0.3585,0.28027,0.05696,0.06249,0.1218,0.1245,0.02472,0.17316,0.11177,0.55151,0.289,0.05075,0.209,0.26805,0.04556,0.20611,0.18945,0.21364,0.0789,0.41631,0.05164,0.04929,0.51519,0.06,0.47844,0.05595,0.09243,0.5888,0.07725,0.0751,0.0472,0.0847,0.1752,0.2656,0.3494,0.06559,0.15412,0.19471,0.07048,0.1267,0.698,0.64804,0.42836,0.2674,0.24804,0.6965,0.73751,0.53987,0.38621,0.07801,0.39842,0.14467,0.2524,0.3068,0.45536,0.25741,0.71896,0.1967,0.54903,0.57668,0.05798,0.1869,0.4779,0.29517,0.43439,0.64445,0.57441,0.31343,0.7862,0.5736,0.06143,0.17395,0.53821,0.22469,0.42903,0.16856,0.1987,0.6085,0.30154,0.41877,0.1418,0.46288,0.56571,0.2098,0.29728,0.1758 +461.0,0.603759712,0.214888096,0.05963488,0.275976064,0.078103072,0.123465584,0.05505216,0.057242288,0.04947288,0.177812208,0.069104304,0.08498128,0.04622992,0.358712352,0.281899216,0.057534048,0.062971968,0.122660768,0.124568272,0.02636656,0.1736136,0.113103872,0.55337264,0.289770848,0.05068624,0.211326288,0.269713216,0.045608736,0.21250824,0.194616992,0.218876032,0.08109888,0.426547824,0.052134544,0.049342192,0.5174804,0.060187056,0.487067328,0.056185296,0.092794576,0.594724576,0.078225552,0.07729792,0.047206096,0.086221872,0.17838384,0.271456064,0.356631376,0.06727904,0.155511232,0.196254064,0.070829344,0.128979104,0.70160888,0.652650192,0.43414736,0.27252168,0.253135808,0.697718432,0.739078736,0.540521248,0.38975144,0.078966592,0.403888976,0.146395552,0.257064128,0.311963216,0.456237216,0.257651136,0.720413632,0.199515776,0.549536512,0.575517792,0.058239744,0.189454656,0.47620832,0.294959408,0.430967984,0.64494384,0.573444544,0.31110384,0.785626384,0.57129488,0.061297024,0.173806096,0.53505344,0.2225276,0.426542048,0.167083296,0.196334592,0.609354576,0.301010176,0.41882584,0.140861744,0.462315952,0.564166032,0.207134192,0.293214656,0.174164896 +462.0,0.601236784,0.212320368,0.059992016,0.27211808,0.07646616,0.122654704,0.054803008,0.057221872,0.049573232,0.177622752,0.068223728,0.084055232,0.046082608,0.358920912,0.283483696,0.058113616,0.063456816,0.123523152,0.124637744,0.028249536,0.174110208,0.114470224,0.555260032,0.290580128,0.050715648,0.213680176,0.271678944,0.045613488,0.21895552,0.1995552,0.22418288,0.08338248,0.436665984,0.052633584,0.049395424,0.519479744,0.060353952,0.495365136,0.056402656,0.093088752,0.600676,0.079266496,0.0796004,0.047211472,0.087836912,0.181716848,0.277478624,0.363711856,0.06908736,0.156901984,0.197785824,0.071114176,0.131345312,0.705133536,0.657212528,0.439968528,0.277783104,0.25839112,0.698998944,0.74061264,0.541061376,0.393191856,0.07996992,0.40947208,0.148205936,0.261845088,0.317227344,0.456929952,0.257734368,0.7216724,0.202223216,0.5500092,0.574172384,0.058467408,0.19190648,0.474317376,0.294678784,0.427273424,0.645467696,0.572340672,0.308913008,0.7849832,0.568977264,0.061137744,0.173762496,0.53182816,0.22029088,0.42406056,0.165505168,0.19400912,0.609969168,0.300410944,0.418660528,0.13984176,0.461688848,0.562559456,0.204401408,0.289135408,0.172542448 +463.0,0.598718496,0.20978344,0.060221392,0.268245216,0.074871728,0.121844704,0.054553856,0.057190736,0.049661904,0.177462576,0.067337392,0.083197344,0.045915936,0.359127952,0.285025696,0.058699024,0.063943664,0.124386496,0.124707296,0.030410512,0.174650176,0.115869776,0.557165104,0.291433328,0.050833056,0.216080064,0.273843472,0.04560416,0.22543552,0.204263968,0.229585008,0.08575344,0.446659664,0.053146784,0.049453056,0.521211968,0.060500368,0.503332864,0.056604736,0.093325808,0.606639744,0.0803704,0.08204936,0.047217648,0.089534352,0.185199456,0.283663744,0.370641856,0.07101664,0.158301536,0.199316544,0.071348448,0.1338016,0.708575472,0.661715184,0.445866416,0.283172448,0.263783232,0.700351376,0.742111344,0.541506064,0.396521472,0.081013088,0.415148704,0.15010328,0.266717168,0.322563232,0.457454448,0.2576764,0.722744368,0.204806336,0.550447728,0.572648976,0.058664752,0.194234944,0.472247152,0.29431688,0.423324064,0.645986672,0.57109392,0.306847056,0.784268096,0.566628848,0.060955344,0.173778176,0.52853448,0.21798944,0.421582272,0.16382552,0.191715888,0.61036696,0.299749632,0.418303536,0.138746736,0.460984544,0.56088576,0.201615744,0.28504872,0.17093096 +464.0,0.596181568,0.207252352,0.060448368,0.264346912,0.073322256,0.121030864,0.054305824,0.05715256,0.049740336,0.17731856,0.066443216,0.082309776,0.045741744,0.359336832,0.286527136,0.059290992,0.064431712,0.12524912,0.124775168,0.032902928,0.175233504,0.117302928,0.559077776,0.292337888,0.051025584,0.218553152,0.27603088,0.045635152,0.2319292,0.208749616,0.235118496,0.08821504,0.456543264,0.053688464,0.049519888,0.522709872,0.060625664,0.510973072,0.056795856,0.093526784,0.612599488,0.081532624,0.08470384,0.047226624,0.091295712,0.188830784,0.290006144,0.377429696,0.07306736,0.159723488,0.200862944,0.071554,0.136351968,0.711939968,0.66614488,0.451910304,0.288672832,0.269281504,0.701788288,0.743573968,0.541878992,0.399730528,0.082085856,0.420892528,0.152090944,0.271645408,0.32793184,0.457837184,0.257504272,0.723643376,0.207247136,0.550851456,0.570947168,0.058834816,0.196416288,0.470021248,0.293851776,0.419134144,0.646456368,0.569698608,0.304872944,0.783477792,0.564220192,0.060754704,0.173775136,0.5251716,0.21562992,0.419103344,0.162046432,0.189442656,0.610582192,0.29903088,0.417801744,0.137586832,0.4601804,0.559137664,0.19879392,0.280958512,0.169327552 +465.0,0.59361,0.20471,0.06075,0.26042,0.07182,0.12021,0.05406,0.05711,0.04981,0.17718,0.06554,0.08133,0.04557,0.35955,0.28799,0.05989,0.06492,0.12611,0.12484,0.03577,0.17586,0.11877,0.56099,0.2933,0.05128,0.22112,0.27812,0.04574,0.23842,0.21301,0.24081,0.09077,0.46632,0.05427,0.0496,0.524,0.06073,0.51829,0.05698,0.09371,0.61854,0.08275,0.08761,0.04724,0.09311,0.19261,0.2965,0.38408,0.07524,0.16118,0.20244,0.07175,0.139,0.71523,0.67049,0.45815,0.29427,0.27486,0.70332,0.745,0.5422,0.40281,0.08318,0.42668,0.15417,0.2766,0.3333,0.4581,0.25724,0.72438,0.20953,0.55122,0.56907,0.05898,0.19843,0.46766,0.29327,0.41472,0.64684,0.56815,0.30296,0.78261,0.56173,0.06054,0.1737,0.52174,0.21322,0.41662,0.16017,0.18718,0.61064,0.29826,0.41719,0.13637,0.45926,0.55731,0.19595,0.27687,0.16773 +466.0,0.591009856,0.202162784,0.061099904,0.256477152,0.070366656,0.119383472,0.05381744,0.057062768,0.049872224,0.17704392,0.064629488,0.080276752,0.045405184,0.359767424,0.289416656,0.060495792,0.065407488,0.126969984,0.124901664,0.039024448,0.176528976,0.120270992,0.562899936,0.294322016,0.051595024,0.223780992,0.28012704,0.045905712,0.244898624,0.21703976,0.246657824,0.093419552,0.475959296,0.054893712,0.049695168,0.525093088,0.060815808,0.525284336,0.057159872,0.093885184,0.624449408,0.08402416,0.090775456,0.047258144,0.09498264,0.19653632,0.303137728,0.390586256,0.077535344,0.162679072,0.20405752,0.071947536,0.141748192,0.718441856,0.674743968,0.464576832,0.299957344,0.2805072,0.704949952,0.746389952,0.54247784,0.405753424,0.084293184,0.432495888,0.15633448,0.281566336,0.338652256,0.458250448,0.256890528,0.724954944,0.2116464,0.551553584,0.567030848,0.059100896,0.200265152,0.465174144,0.292578624,0.41010432,0.647123904,0.566446224,0.3011148,0.781665632,0.55916144,0.060313344,0.173565952,0.518243472,0.21077032,0.414128784,0.15819832,0.184926976,0.610545008,0.297443184,0.416467088,0.13509768,0.458225632,0.555403936,0.193090272,0.27279216,0.166138176 +467.0,0.588387856,0.19961728,0.061492672,0.252526336,0.068963648,0.118552864,0.053578976,0.057010896,0.049928864,0.176907296,0.063713872,0.079155664,0.045253296,0.359988992,0.290809376,0.061108144,0.065893344,0.127829776,0.124960016,0.042674992,0.177239056,0.121805296,0.564805904,0.295406288,0.051972496,0.226534864,0.282053232,0.0461272,0.2513568,0.220848848,0.252657168,0.09616488,0.485433264,0.055561984,0.049807456,0.526002208,0.060886448,0.531954944,0.057339296,0.094066048,0.630315744,0.08535712,0.09420528,0.047281248,0.096917232,0.200607376,0.309909024,0.396944736,0.07995304,0.164231456,0.205728784,0.072162288,0.14459968,0.721572432,0.678901504,0.471178656,0.305726688,0.286210832,0.706680656,0.747744304,0.542724384,0.408556032,0.085422528,0.438323104,0.1585756,0.286527728,0.343971952,0.458299648,0.25646616,0.725369888,0.213589616,0.551852368,0.564842576,0.059198592,0.201912624,0.462573072,0.29178232,0.405309424,0.647296992,0.56458568,0.299351216,0.780646496,0.556519008,0.060077664,0.173378816,0.51468624,0.20828968,0.411625792,0.15613608,0.182682288,0.61030552,0.296583472,0.415631056,0.133771616,0.457080624,0.55342112,0.190219584,0.26873312,0.16455184 +468.0,0.585726896,0.197056336,0.06190144,0.24858176,0.06761328,0.117714896,0.053345792,0.056956464,0.049981344,0.176758512,0.062790896,0.077966656,0.045122528,0.36021672,0.292169856,0.061727536,0.0663756,0.128688688,0.125013648,0.046768496,0.177990576,0.123374,0.566699472,0.2965592,0.052370048,0.229404336,0.283846144,0.046397968,0.257777296,0.224375456,0.258837952,0.099008368,0.494742912,0.056286576,0.049940944,0.526745648,0.060941408,0.538325072,0.05752168,0.094267792,0.63612368,0.08674456,0.097947984,0.047311152,0.098916704,0.204824112,0.31681104,0.403157376,0.082494096,0.16584624,0.207465168,0.07240896,0.147557088,0.724623648,0.6829496,0.47800888,0.311565792,0.291945104,0.70852368,0.749062736,0.542955488,0.4112064,0.086560672,0.44413992,0.1608976,0.29145696,0.349226928,0.458266608,0.255985552,0.725634592,0.215342352,0.552116352,0.562508704,0.059274768,0.203350416,0.45987808,0.290879616,0.400351888,0.64731936,0.562563296,0.297570992,0.77954896,0.553780016,0.059836224,0.1731072,0.511069408,0.20578792,0.40910744,0.15398288,0.1804368,0.609929392,0.2956916,0.414717424,0.132399232,0.455807456,0.551355904,0.187353056,0.2646992,0.162968624 +469.0,0.583001856,0.194454912,0.062278368,0.244661824,0.066318112,0.116864688,0.053119168,0.056902192,0.050031024,0.176582928,0.06185672,0.076715968,0.04502176,0.360453248,0.293499536,0.062354688,0.066851776,0.1295456,0.12506072,0.05136448,0.178784416,0.124978784,0.56856992,0.297788512,0.05272624,0.232420208,0.285444416,0.046705696,0.264139952,0.227526464,0.265241696,0.101952736,0.50389896,0.057082448,0.050100432,0.527342448,0.060978928,0.54442896,0.057710384,0.094506256,0.641856736,0.08817992,0.102066528,0.047350256,0.100985776,0.209188608,0.323843456,0.409228016,0.085159872,0.167531904,0.209277392,0.072701952,0.150622816,0.727599024,0.686872656,0.485142784,0.317461136,0.297679616,0.710493664,0.750344688,0.543188192,0.413690768,0.087698816,0.449923056,0.16330912,0.296323392,0.354379824,0.458173088,0.255470144,0.725761536,0.216883808,0.552345536,0.560029632,0.059331264,0.204552288,0.457114368,0.289868592,0.395246352,0.647141408,0.560372832,0.295628448,0.778367504,0.550912704,0.059592384,0.172709744,0.507393216,0.20327528,0.406570208,0.15173664,0.178178752,0.609422064,0.294781248,0.413774192,0.130989808,0.454381648,0.549200208,0.184509168,0.26069616,0.161385408 +470.0,0.5802,0.1918,0.06259,0.24078,0.06508,0.116,0.0529,0.05685,0.05008,0.17637,0.06091,0.07541,0.04496,0.3607,0.2948,0.06299,0.06732,0.1304,0.1251,0.0565,0.17962,0.12662,0.57041,0.2991,0.053,0.2356,0.28681,0.04704,0.27043,0.23025,0.27189,0.105,0.5129,0.05796,0.05029,0.52781,0.061,0.55029,0.05791,0.0948,0.6475,0.08966,0.1066,0.0474,0.10313,0.2137,0.331,0.41516,0.08795,0.1693,0.21118,0.07306,0.1538,0.7305,0.69066,0.49262,0.3234,0.30339,0.7126,0.75159,0.54344,0.416,0.08883,0.45565,0.16581,0.3011,0.3594,0.45804,0.25494,0.72576,0.2182,0.55254,0.55741,0.05937,0.2055,0.4543,0.28875,0.39001,0.64673,0.55801,0.29343,0.7771,0.5479,0.05935,0.17216,0.50366,0.20076,0.40401,0.1494,0.1759,0.60879,0.29386,0.41283,0.12955,0.45279,0.54695,0.1817,0.25673,0.1598 +471.0,0.577328752,0.189098368,0.062847104,0.236940672,0.0638996,0.115122896,0.052688656,0.056800272,0.050130928,0.176116912,0.059953456,0.074049312,0.04494496,0.360956544,0.296073312,0.063633248,0.067779536,0.131252448,0.125131504,0.062171632,0.1804948,0.128296208,0.572218592,0.300496064,0.053194688,0.23894008,0.28793856,0.0474016,0.276641488,0.232568016,0.278773232,0.10815088,0.521724064,0.05892168,0.050512176,0.528163632,0.061009296,0.555911472,0.058125952,0.095168016,0.653041728,0.091188064,0.111549392,0.047460256,0.1053524,0.218352736,0.338264976,0.420954192,0.090861344,0.17116432,0.213190192,0.073504512,0.15709264,0.733324368,0.694308912,0.500420992,0.32937152,0.309062576,0.714843216,0.752799056,0.543726256,0.418132032,0.089950512,0.461301232,0.168386448,0.305767648,0.364269376,0.457883232,0.25440976,0.725633072,0.219288,0.552699888,0.554661616,0.059392608,0.20618872,0.451441408,0.287526,0.384663808,0.646079248,0.555474256,0.290986288,0.775749456,0.544748672,0.059112912,0.171463056,0.499874944,0.198247664,0.401422304,0.1469816,0.173599264,0.608044016,0.292927856,0.411881824,0.128082128,0.45103784,0.544608016,0.178927424,0.252807008,0.15821208 +472.0,0.574391216,0.186352656,0.06306224,0.23315008,0.06277752,0.114234656,0.052485552,0.056753584,0.050186064,0.175820032,0.058988976,0.072636016,0.044983728,0.3612228,0.297321536,0.064284256,0.06822944,0.132103328,0.125155248,0.068377616,0.181406736,0.13000648,0.573993792,0.30197976,0.053310768,0.242441296,0.288820784,0.047793008,0.282767296,0.234489216,0.285888352,0.111406048,0.530354832,0.059971296,0.050769664,0.528419488,0.061010368,0.561302752,0.05836296,0.095627232,0.65847008,0.09276712,0.116923584,0.047531152,0.107654624,0.223141472,0.34562344,0.426611856,0.093890496,0.17313648,0.215322448,0.074054,0.160504448,0.736070688,0.6978156,0.50853608,0.335364192,0.314681584,0.71722496,0.753972016,0.544061008,0.42008352,0.091055952,0.46685744,0.17102688,0.31030664,0.368968128,0.457717968,0.253893632,0.725384752,0.220143552,0.552825312,0.551794624,0.059400528,0.206612336,0.44854664,0.286196416,0.379227168,0.64517912,0.552765056,0.288292752,0.77431768,0.541460816,0.058884464,0.17062568,0.496042528,0.19574408,0.39880296,0.1444884,0.17127464,0.607195152,0.29198808,0.410933184,0.126589552,0.449127136,0.542175984,0.176194816,0.2489328,0.156621184 +473.0,0.57141296,0.183586624,0.063198016,0.229408448,0.06171384,0.113341056,0.052290288,0.056709936,0.0502512,0.175478752,0.058022896,0.0711876,0.045089296,0.361496256,0.29854616,0.064942704,0.068669424,0.132953808,0.125171152,0.07509952,0.182349952,0.131746272,0.575737712,0.303551056,0.053343408,0.246079312,0.289496048,0.048191456,0.288808544,0.236074816,0.293193312,0.114765936,0.5387536,0.061106432,0.051065152,0.528588384,0.06101448,0.566456272,0.058632048,0.096213728,0.663773312,0.094401456,0.122686736,0.047611248,0.110053648,0.228056848,0.353051504,0.43213792,0.097032528,0.17524416,0.217611664,0.074750768,0.164041536,0.738734448,0.701184128,0.516899488,0.341367024,0.320239552,0.719739744,0.755110256,0.54447016,0.421860208,0.092144592,0.472294528,0.173703392,0.314696432,0.37348256,0.457570784,0.253414704,0.725016592,0.220772784,0.552916736,0.548826432,0.059396928,0.206775072,0.445612592,0.284777552,0.373726528,0.644044912,0.549882336,0.285375136,0.772813824,0.53806448,0.058672016,0.169646144,0.492172672,0.193250576,0.396144896,0.14194104,0.168926576,0.606247088,0.291023584,0.409953344,0.125070816,0.447078672,0.539661632,0.173494768,0.245114912,0.155027088 +474.0,0.568432704,0.180836512,0.063200032,0.225712096,0.06070816,0.112450576,0.052101984,0.056668848,0.050333856,0.175094992,0.057064176,0.069728784,0.045277184,0.361772992,0.299748464,0.065608112,0.069099648,0.133805568,0.125179296,0.082304384,0.183316528,0.133509104,0.577455232,0.305208032,0.053291568,0.249815168,0.290032032,0.048563984,0.294771552,0.237420176,0.300623552,0.118230624,0.546868928,0.062320688,0.05140112,0.5286784,0.061036992,0.571354672,0.058947296,0.096972544,0.668940224,0.096096992,0.128776928,0.047698144,0.112573232,0.233086784,0.360519488,0.437538864,0.1002812,0.17752272,0.22010248,0.075648496,0.167711264,0.741309248,0.704423456,0.525410816,0.347369376,0.32573424,0.722377408,0.756215776,0.544984752,0.423473136,0.093216352,0.477586576,0.176378384,0.318917184,0.377803552,0.45747288,0.252999456,0.724528192,0.221188416,0.5529748,0.54577872,0.059385728,0.206688128,0.442629184,0.283293408,0.368191968,0.642707744,0.546826896,0.28228664,0.771251168,0.534603104,0.058484768,0.168524288,0.488278256,0.190765872,0.393439632,0.13936744,0.166557632,0.605200624,0.290006928,0.408891344,0.12352168,0.444924608,0.53707648,0.17081328,0.241361664,0.153429952 +475.0,0.56548,0.17813,0.06304,0.22206,0.05976,0.11157,0.05192,0.05663,0.05044,0.17467,0.05612,0.06828,0.04556,0.36205,0.30093,0.06628,0.06952,0.13466,0.12518,0.08996,0.1843,0.13529,0.57915,0.30695,0.05316,0.25362,0.29048,0.04889,0.30066,0.2386,0.30813,0.1218,0.55466,0.06361,0.05178,0.5287,0.06109,0.57599,0.05932,0.09794,0.67396,0.09786,0.13515,0.04779,0.11523,0.23822,0.368,0.44282,0.10363,0.18,0.22283,0.07679,0.17152,0.74379,0.70754,0.53399,0.35336,0.33116,0.72513,0.75729,0.54563,0.42493,0.09427,0.48271,0.17902,0.32295,0.38192,0.45745,0.25267,0.72392,0.2214,0.553,0.54267,0.05937,0.20636,0.43959,0.28176,0.36265,0.64119,0.5436,0.27907,0.76964,0.53111,0.05833,0.16727,0.48437,0.18829,0.39068,0.13679,0.16417,0.60406,0.28892,0.40771,0.12194,0.44269,0.53443,0.16814,0.23768,0.15183 +476.0,0.562556704,0.175468768,0.06272528,0.218457344,0.058868768,0.110700896,0.051744512,0.056593584,0.050570864,0.174202992,0.05519232,0.066845728,0.045941616,0.362327136,0.302093376,0.066957952,0.069929888,0.135517632,0.125174528,0.098036608,0.185298688,0.137088432,0.58082208,0.308780096,0.05295088,0.25749504,0.290845104,0.049169456,0.306469664,0.23962296,0.315709936,0.125473504,0.562117552,0.064977152,0.052203808,0.528666208,0.061175872,0.58037168,0.059752864,0.099125984,0.678823168,0.099698096,0.14181488,0.047886784,0.118028576,0.243447712,0.375472704,0.44798296,0.10707176,0.1826812,0.225800848,0.078185744,0.175471136,0.74617568,0.710532304,0.542618112,0.359325632,0.336501168,0.727996032,0.758332704,0.546413904,0.426228992,0.095300864,0.487648048,0.181613392,0.326778912,0.38581472,0.457511568,0.252435408,0.723194992,0.221407616,0.552992464,0.53950888,0.059350368,0.205790944,0.436499776,0.280176576,0.357116544,0.639487664,0.540204096,0.275717552,0.767981728,0.527588352,0.0582096,0.165885216,0.480451824,0.185826784,0.38786288,0.134214512,0.161764608,0.602834144,0.287764912,0.406413392,0.120329856,0.440378528,0.531725312,0.165475808,0.2340728,0.15022784 +477.0,0.55966376,0.172853744,0.062247136,0.214907648,0.05803328,0.109844896,0.051575648,0.056559536,0.05072688,0.173694992,0.054283136,0.06542832,0.046423696,0.362604336,0.30324168,0.067641424,0.070329104,0.136379088,0.125164992,0.10648856,0.186311472,0.138904192,0.582472752,0.310701536,0.052661408,0.261441952,0.291140048,0.049395776,0.312197824,0.240497456,0.323361392,0.129249936,0.56923584,0.066424192,0.052673952,0.528586464,0.06129608,0.584503472,0.060247008,0.100535168,0.683521792,0.101621776,0.148780976,0.047988448,0.120978288,0.248759408,0.382914624,0.45302896,0.110597408,0.18556712,0.229016304,0.079840528,0.179567776,0.748465488,0.713399968,0.551271408,0.365252144,0.341742432,0.730972224,0.759343456,0.5473404,0.427369168,0.096304192,0.492385808,0.184142192,0.330390592,0.38947232,0.457662784,0.252301024,0.722355312,0.221213584,0.552952336,0.536302992,0.059326928,0.204984592,0.433361632,0.278544432,0.351605568,0.637599792,0.536643296,0.272216736,0.766277424,0.52404184,0.058124576,0.164353744,0.476526992,0.183379136,0.384985936,0.13164552,0.159344096,0.601529088,0.286540384,0.405006064,0.118695696,0.437994672,0.528966192,0.162820528,0.230541472,0.148624848 +478.0,0.556832016,0.170314,0.061678752,0.211415072,0.057253392,0.109008976,0.051412624,0.056527728,0.050914976,0.173145472,0.053399392,0.064056512,0.047021056,0.362878256,0.304375504,0.068329936,0.07071648,0.137245664,0.125150416,0.115299152,0.187330496,0.140732112,0.584104224,0.312713296,0.052341216,0.265431824,0.291402272,0.049588016,0.317846624,0.241306592,0.331034768,0.133129568,0.575971168,0.067948112,0.053194016,0.528484,0.061463488,0.588404784,0.060815792,0.102209632,0.688043136,0.103633856,0.156004032,0.048092912,0.12407224,0.254145344,0.390300624,0.45796408,0.114202016,0.18869016,0.23251656,0.081802352,0.183816576,0.750653856,0.716148832,0.559874384,0.371129536,0.346877376,0.734052736,0.760323728,0.548438256,0.428356304,0.0972788,0.496898208,0.186576512,0.333763312,0.39288016,0.45793352,0.25229256,0.721402272,0.220825152,0.552879968,0.533072624,0.059303088,0.20394632,0.430170448,0.276863168,0.346145312,0.63554608,0.532917616,0.2686532,0.76453752,0.520502768,0.058082352,0.162779792,0.47260752,0.180948288,0.382040992,0.129106768,0.156909264,0.600163232,0.285247216,0.403450496,0.117035136,0.435562816,0.526161872,0.160164288,0.227094304,0.147020096 +479.0,0.554102352,0.167888096,0.061134848,0.207984576,0.056529264,0.108201936,0.05125432,0.056498,0.051144272,0.172553392,0.052549648,0.062768864,0.047752896,0.363144416,0.305494528,0.069023008,0.071090416,0.13811888,0.12512872,0.124461264,0.18834552,0.142565392,0.585718976,0.314812896,0.052064064,0.269425616,0.291676416,0.049779296,0.323419824,0.242159728,0.338664624,0.13711312,0.582267296,0.069544272,0.0537684,0.528388176,0.061694736,0.592103856,0.061476736,0.104204016,0.6923728,0.105734496,0.163421968,0.048197376,0.127294992,0.259596,0.397604784,0.46279608,0.117881984,0.19209328,0.236354736,0.084133536,0.188225376,0.752733584,0.718786896,0.56833424,0.376949248,0.35190248,0.737230928,0.7612756,0.549744432,0.42919824,0.098224688,0.501156848,0.188882032,0.336872512,0.39602656,0.458361856,0.252442496,0.720336912,0.2202512,0.55277576,0.529842416,0.059283328,0.202682128,0.426918304,0.275129424,0.340768736,0.633353168,0.529025776,0.265151664,0.762775536,0.517012896,0.058092368,0.1613204,0.468708448,0.17853496,0.379017888,0.126628416,0.154460352,0.598760976,0.283889488,0.401695168,0.115343536,0.433114,0.523323472,0.157493888,0.223741856,0.145411824 +480.0,0.5515,0.1656,0.06069,0.20462,0.05586,0.10743,0.0511,0.05647,0.05142,0.17192,0.05174,0.06159,0.04863,0.3634,0.3066,0.06972,0.07145,0.139,0.1251,0.13394,0.18935,0.1444,0.58732,0.317,0.05188,0.2734,0.292,0.04999,0.32892,0.24313,0.34621,0.1412,0.58809,0.07121,0.0544,0.52832,0.062,0.59562,0.06224,0.10655,0.6965,0.10793,0.171,0.0483,0.13064,0.2651,0.4048,0.46753,0.12163,0.1958,0.24056,0.08687,0.1928,0.7547,0.72132,0.57658,0.3827,0.35681,0.7405,0.7622,0.55128,0.4299,0.09914,0.50514,0.19103,0.3397,0.3989,0.45897,0.25277,0.71916,0.2195,0.55264,0.52663,0.05927,0.2012,0.4236,0.27334,0.3355,0.63104,0.52497,0.26179,0.761,0.5136,0.05816,0.16007,0.46484,0.17614,0.37591,0.12423,0.152,0.59734,0.28247,0.39971,0.11362,0.43067,0.52046,0.1548,0.22049,0.1438 +481.0,0.549024288,0.163449136,0.060331584,0.201324016,0.05524336,0.10669464,0.05094968,0.056443312,0.051741008,0.17124936,0.050972192,0.060519648,0.049649536,0.363645072,0.30769528,0.070420208,0.071795392,0.139889728,0.125068352,0.143666112,0.190343968,0.146236432,0.588910416,0.319277744,0.051788272,0.277357872,0.292390784,0.050215328,0.334347504,0.244228064,0.353670256,0.145387856,0.593441728,0.072946224,0.055089056,0.528284064,0.062378288,0.598955328,0.063103632,0.109242064,0.700419872,0.110236256,0.178746912,0.048400608,0.134117616,0.270644096,0.411860032,0.472166592,0.125434,0.199801904,0.245122144,0.090004992,0.197541616,0.756552832,0.723749568,0.584581984,0.388366736,0.36158568,0.743853184,0.763096064,0.553040976,0.430461776,0.10002008,0.508836928,0.193003344,0.342237584,0.401489152,0.459754848,0.253273248,0.717872336,0.218577328,0.5524728,0.523440752,0.059262256,0.199509184,0.420215824,0.271497392,0.330348368,0.628610832,0.520757584,0.258571024,0.759211424,0.510267744,0.058284224,0.159019872,0.461004128,0.173764752,0.372717104,0.121913776,0.149533616,0.595904224,0.280987088,0.397501168,0.111869488,0.428236064,0.517576176,0.152081376,0.217337456,0.14218704 +482.0,0.546679456,0.16143928,0.060057792,0.198100432,0.054677392,0.105997856,0.050803264,0.056417648,0.052107056,0.170544992,0.050248512,0.059561152,0.050810416,0.363879216,0.308782864,0.071123056,0.07212648,0.140788784,0.125037936,0.153580832,0.191326736,0.148074432,0.590493184,0.321648416,0.051794736,0.281297344,0.292863952,0.050457456,0.339703824,0.245477072,0.361036688,0.149674688,0.598320128,0.074753152,0.055835936,0.52828592,0.062829728,0.602116064,0.064067392,0.112280112,0.704127136,0.112668176,0.186660912,0.048498672,0.13773416,0.276215664,0.418759984,0.4767076,0.129283216,0.20409464,0.25003584,0.093537952,0.202450576,0.758291216,0.726077792,0.592304864,0.393935616,0.366217296,0.747282976,0.763963248,0.555027216,0.430884784,0.10086112,0.512235888,0.194784672,0.344476032,0.40378384,0.46071688,0.25395352,0.716474752,0.217489152,0.552274288,0.520281424,0.059259888,0.19761856,0.416764928,0.269606048,0.325324432,0.6260728,0.516395136,0.2555256,0.757412,0.507023808,0.058464912,0.158196672,0.45720392,0.171410288,0.369438752,0.119685168,0.147065824,0.594459072,0.279440096,0.395068576,0.110095616,0.425820016,0.514677232,0.149336208,0.214284144,0.140574736 +483.0,0.544443744,0.159551584,0.05986592,0.194947568,0.054157264,0.105339392,0.050660928,0.056391504,0.052511904,0.169816784,0.049568432,0.058701696,0.052098416,0.36410432,0.309870048,0.071826944,0.072444608,0.141698,0.12501384,0.163540832,0.192301504,0.149918272,0.592074272,0.324118448,0.05190216,0.285241696,0.2934564,0.050703744,0.344987744,0.24684528,0.36834264,0.1540552,0.602754528,0.07663344,0.056639696,0.528328336,0.063346928,0.60509824,0.065119792,0.11562704,0.70762128,0.115250736,0.194794432,0.048595136,0.141506704,0.281795312,0.425462576,0.481149328,0.133156272,0.208644896,0.255260416,0.097425552,0.207530736,0.75991744,0.728305616,0.599731664,0.399385376,0.370682752,0.750782288,0.764798832,0.557210736,0.431165792,0.10165488,0.515334208,0.1963556,0.3464164,0.405771968,0.461830112,0.254788992,0.714966288,0.216244896,0.552044416,0.517150736,0.05925824,0.195545856,0.413248592,0.267650384,0.320428016,0.623425168,0.511896448,0.252572576,0.755594656,0.503856272,0.05869496,0.157490112,0.453436112,0.169077504,0.36607696,0.11753136,0.144608912,0.59300792,0.277832064,0.392444544,0.108309584,0.423418528,0.511767568,0.1465628,0.211320912,0.138969152 +484.0,0.542279712,0.157753248,0.059741888,0.191861184,0.053676576,0.104717248,0.050523072,0.0563628,0.052945552,0.169078096,0.048929472,0.05791744,0.053491056,0.364323744,0.310966592,0.072529792,0.072751936,0.142618176,0.125002304,0.173358272,0.193274272,0.151774992,0.59366112,0.32669664,0.052105504,0.289229568,0.294211728,0.050932272,0.350196704,0.248267248,0.375646512,0.158522272,0.606794608,0.078591328,0.057498336,0.528410272,0.063917248,0.607891296,0.066242272,0.119222848,0.710905024,0.118015216,0.203230752,0.04869184,0.145459168,0.28736016,0.431924928,0.485484976,0.137026128,0.213400912,0.260732592,0.101598032,0.212786656,0.761435904,0.73043288,0.606859584,0.404690816,0.374954608,0.754344,0.765598816,0.559546736,0.43129888,0.10239072,0.518135248,0.197699088,0.348066208,0.407440896,0.463052304,0.255743824,0.713345104,0.21485536,0.551783024,0.514041808,0.059250112,0.193313312,0.409669696,0.2656064,0.31565152,0.620661776,0.50727952,0.249571632,0.753746912,0.500740736,0.058963008,0.156716032,0.449693264,0.1667672,0.362635968,0.115428592,0.1421792,0.591551328,0.276167472,0.389681552,0.106526912,0.4210208,0.508850624,0.143760672,0.20843328,0.137378688 +485.0,0.54016,0.15602,0.05967,0.18884,0.05323,0.10413,0.05039,0.05633,0.0534,0.16834,0.04833,0.05719,0.05497,0.36454,0.31208,0.07323,0.07305,0.14355,0.12501,0.18288,0.19425,0.15365,0.59526,0.32939,0.0524,0.29329,0.29516,0.05113,0.35533,0.2497,0.38299,0.16307,0.61048,0.08063,0.05841,0.52853,0.06453,0.61049,0.06742,0.12302,0.71398,0.12099,0.21203,0.04879,0.14961,0.29289,0.43811,0.48971,0.14087,0.21832,0.2664,0.106,0.21822,0.76285,0.73246,0.61368,0.40983,0.37901,0.75796,0.76636,0.562,0.43128,0.10306,0.52064,0.1988,0.34943,0.40878,0.46435,0.25679,0.71161,0.21333,0.55149,0.51095,0.05923,0.19094,0.40603,0.26346,0.31099,0.61778,0.50256,0.24644,0.75186,0.49766,0.05926,0.15576,0.44597,0.16448,0.35912,0.11336,0.13979,0.59009,0.27445,0.38682,0.10476,0.41862,0.50593,0.14093,0.20561,0.13581 +486.0,0.538087296,0.154352896,0.059657968,0.185889312,0.052815472,0.103578176,0.050261536,0.05629304,0.05387296,0.167606512,0.047770752,0.05652224,0.056529504,0.36475328,0.313211328,0.073927216,0.073338624,0.144493824,0.125045152,0.1920568,0.195230432,0.155544032,0.59687392,0.332200288,0.052792592,0.297423104,0.296309424,0.05130792,0.360392576,0.251156816,0.390364528,0.167696,0.613819936,0.082749312,0.059373296,0.528689648,0.065180544,0.612905936,0.068649408,0.127008576,0.716844704,0.124195136,0.221182592,0.048889152,0.153963632,0.29837248,0.443998336,0.493826608,0.14467768,0.223387008,0.272243296,0.11061936,0.223823744,0.764160096,0.734388768,0.620166928,0.41479072,0.382839776,0.7616192,0.767081376,0.564564208,0.431110816,0.103659968,0.522842272,0.199648752,0.35050352,0.409784736,0.465716256,0.257922944,0.709761248,0.211674496,0.551165392,0.507877152,0.059197472,0.18843568,0.402327808,0.261216928,0.306446576,0.614787792,0.497746288,0.24320192,0.749936512,0.494618656,0.059583648,0.154641856,0.442267088,0.16221576,0.355532976,0.11132928,0.13744528,0.588627536,0.272683184,0.383863904,0.103011776,0.41622088,0.503009824,0.138073216,0.202849504,0.134264544 +487.0,0.536063424,0.152751344,0.0597252,0.183014368,0.052431024,0.103061472,0.050137408,0.056251984,0.054360944,0.166881504,0.047251472,0.055918496,0.058161536,0.36496424,0.314360848,0.074621184,0.073617648,0.14544976,0.1251184,0.200848352,0.196218704,0.157458432,0.598505792,0.335129008,0.05329224,0.301630016,0.29767064,0.051479264,0.365391184,0.25263984,0.39776136,0.17239776,0.616829728,0.08494896,0.060385856,0.528891456,0.065861648,0.6151532,0.069925232,0.13117384,0.71949968,0.127653376,0.230674032,0.048988976,0.158525264,0.303795712,0.449574336,0.497837328,0.148439632,0.228581296,0.278235936,0.115438352,0.229586496,0.76536728,0.736220336,0.626301024,0.419561856,0.386436592,0.765308688,0.767761632,0.567230256,0.430793232,0.10418848,0.524738768,0.20024064,0.35128504,0.410453568,0.467140592,0.259135312,0.707798768,0.209894016,0.550809216,0.504822176,0.05915208,0.185810016,0.398561232,0.258880784,0.302020336,0.611692928,0.492847408,0.239848576,0.747979456,0.491619472,0.05993056,0.153343392,0.438583952,0.159973664,0.3518812,0.10933928,0.135148112,0.58716688,0.270873104,0.380819584,0.101284624,0.413826048,0.500093408,0.13519568,0.200149632,0.132743472 +488.0,0.534062272,0.151193232,0.059787792,0.180218544,0.052071136,0.102578848,0.0500184,0.056205488,0.054857728,0.166176576,0.046771872,0.055349152,0.059849728,0.36517448,0.315536208,0.075310592,0.073888272,0.146418736,0.125233488,0.209092864,0.197218576,0.159397552,0.600161504,0.338183168,0.053870368,0.305939008,0.299233776,0.051633968,0.370323152,0.254139504,0.405222672,0.17716976,0.61954344,0.087232608,0.061446736,0.529121744,0.066564832,0.617222384,0.071234176,0.135472624,0.721944256,0.131389696,0.240569872,0.04909016,0.163307776,0.309139344,0.454796976,0.501737328,0.152132784,0.233865024,0.284332176,0.120406864,0.235514288,0.766474224,0.737956464,0.6320668,0.424120512,0.389775808,0.769022176,0.768398288,0.569965424,0.430322768,0.104636512,0.526327744,0.200555968,0.35177632,0.4107728,0.468592768,0.26040192,0.705722608,0.207998016,0.55042136,0.50178384,0.059088368,0.183081792,0.394732416,0.25645936,0.297710176,0.608493024,0.487878768,0.236461552,0.7459792,0.488646688,0.060293072,0.151938048,0.434916656,0.157755488,0.348167024,0.10737424,0.132913344,0.585704464,0.269016384,0.377725424,0.099591712,0.411431456,0.497185072,0.132294064,0.19749976,0.13125368 +489.0,0.53204848,0.14964936,0.059717984,0.17750536,0.051729088,0.102128944,0.049905712,0.056151792,0.055356272,0.165505968,0.046331712,0.054771648,0.06157488,0.36538584,0.316747408,0.07599384,0.074152096,0.147401952,0.125391776,0.216588096,0.198234048,0.161366672,0.601847856,0.341371568,0.054482256,0.31038744,0.300975872,0.051755072,0.37518264,0.255646048,0.412807664,0.18200552,0.622001472,0.089605296,0.062555456,0.529359552,0.067281136,0.619095968,0.07256024,0.139852208,0.724177312,0.135429696,0.250962432,0.049193664,0.168325808,0.314380256,0.459616736,0.505519328,0.155729616,0.239194512,0.290479776,0.125463936,0.24161896,0.767484128,0.739599232,0.637450016,0.428439888,0.392827024,0.772755584,0.768988544,0.572729072,0.429692784,0.104992784,0.527608,0.200570096,0.35198024,0.410724672,0.470035904,0.261691648,0.703533008,0.205997296,0.550001664,0.498760944,0.058999216,0.180272768,0.39084488,0.253965136,0.293514896,0.60518232,0.482857968,0.233174448,0.743921824,0.485678304,0.060662144,0.150554784,0.43126016,0.155563952,0.344391568,0.10541224,0.130759856,0.584233728,0.267105744,0.374630544,0.09794984,0.409030944,0.494289456,0.129362048,0.194886448,0.129803968 +490.0,0.53,0.1481,0.05944,0.17488,0.0514,0.10171,0.0498,0.05609,0.05585,0.16488,0.04593,0.05416,0.06332,0.3656,0.318,0.07667,0.07441,0.1484,0.1256,0.2232,0.19927,0.16337,0.60357,0.3447,0.0551,0.315,0.30288,0.05184,0.37997,0.25715,0.42055,0.1869,0.62424,0.09207,0.06371,0.52959,0.068,0.62077,0.07389,0.14427,0.7262,0.1398,0.2619,0.0493,0.17359,0.3195,0.464,0.50918,0.15921,0.24453,0.29663,0.13056,0.2479,0.7684,0.74115,0.64244,0.4325,0.39557,0.7765,0.76953,0.57549,0.4289,0.10525,0.52858,0.20027,0.3519,0.4103,0.47144,0.26298,0.70123,0.2039,0.54955,0.49575,0.05888,0.1774,0.3869,0.25141,0.28943,0.60176,0.4778,0.23007,0.7418,0.4827,0.06103,0.14927,0.42761,0.1534,0.34056,0.10344,0.1287,0.58275,0.26514,0.37157,0.09637,0.40662,0.49141,0.1264,0.1923,0.1284 +491.0,0.52791784,0.146542656,0.0589648,0.172347632,0.051082288,0.101320352,0.049700976,0.056020496,0.05633408,0.164301824,0.045564976,0.053519408,0.065073968,0.365818224,0.31929208,0.077339072,0.074661808,0.149412304,0.125871888,0.22890864,0.200332544,0.165409728,0.605330192,0.348169392,0.055728592,0.31977888,0.304948464,0.051898432,0.384694784,0.258639376,0.428440128,0.191850736,0.626283264,0.094626688,0.0649064,0.52981432,0.06871264,0.622259968,0.075215888,0.148704592,0.728016384,0.144525392,0.273356976,0.049408912,0.179091936,0.324488304,0.46793944,0.512722608,0.162566288,0.249843376,0.302746624,0.135669472,0.254337504,0.769224288,0.742609184,0.647029488,0.436292512,0.398001408,0.780239856,0.77002104,0.578235312,0.427947184,0.105407456,0.529245616,0.199660192,0.351538336,0.409502944,0.472789712,0.26425584,0.69881336,0.201710368,0.5490664,0.492745536,0.058730464,0.174472512,0.382895904,0.248797248,0.28544824,0.598233648,0.47271464,0.227129632,0.739617376,0.479711824,0.061391936,0.14806312,0.423963872,0.151261936,0.336682,0.101459248,0.126734976,0.581255984,0.263125856,0.368553056,0.09485344,0.404197936,0.488548496,0.123417712,0.189737968,0.127042112 +492.0,0.525798992,0.144972192,0.058275072,0.169911584,0.050774016,0.100958528,0.04960856,0.055943408,0.056803888,0.163775296,0.045235072,0.052850832,0.066825488,0.36604184,0.320622448,0.078000832,0.074907632,0.150438176,0.126218848,0.233677824,0.201428256,0.167488432,0.607130864,0.351781568,0.056366368,0.324729888,0.307179856,0.051926768,0.389364512,0.260099104,0.436476352,0.19685496,0.62815624,0.097276448,0.066141136,0.530033824,0.069413392,0.623574784,0.076529856,0.153132144,0.729630176,0.149628336,0.285318832,0.04952024,0.184811056,0.329334144,0.471424736,0.516149328,0.165789104,0.255106464,0.308793936,0.140764064,0.260913968,0.769959744,0.743977504,0.65121184,0.439807872,0.400115728,0.783961376,0.770459968,0.580949584,0.426836528,0.105463552,0.529606784,0.198742848,0.35089848,0.40833584,0.474068128,0.26550632,0.696283088,0.199433536,0.54855096,0.48974288,0.058549728,0.171500512,0.378831696,0.24612792,0.281563456,0.594609264,0.467612208,0.224356912,0.73737552,0.476711488,0.061743152,0.146946288,0.420319616,0.149148688,0.332765424,0.09946896,0.124867504,0.579755904,0.261065904,0.365592944,0.093402992,0.401763376,0.485706912,0.120422784,0.18719728,0.12573136 +493.0,0.523659184,0.143393888,0.057461744,0.167588896,0.050475104,0.100619984,0.049521824,0.05586072,0.057251936,0.163300848,0.044936128,0.052169616,0.068559248,0.366272336,0.321984176,0.078656752,0.075145856,0.151477008,0.126668208,0.237570688,0.202564368,0.169607536,0.608972896,0.355533104,0.057027184,0.329843056,0.309558688,0.051997504,0.39400032,0.261529552,0.444617696,0.201911424,0.629892896,0.100014768,0.067406432,0.530237808,0.070075424,0.6247596,0.077822704,0.157530896,0.731050688,0.1551476,0.297706368,0.049633248,0.190784256,0.334031504,0.474468112,0.519468448,0.16887944,0.260279792,0.314718688,0.145817296,0.267591152,0.77060904,0.745253584,0.654990352,0.443044912,0.401922048,0.787638176,0.770845296,0.583624176,0.425573392,0.105422608,0.529671072,0.197541904,0.349985984,0.406816096,0.475258784,0.26672168,0.693638256,0.197068624,0.54800336,0.486727984,0.058340032,0.168487712,0.374701408,0.243429792,0.277755792,0.59090048,0.462501936,0.221709872,0.735086784,0.473704352,0.062077408,0.145841776,0.41667176,0.1470552,0.328832528,0.097480432,0.123091552,0.578240144,0.258983872,0.362687952,0.092012704,0.399314736,0.482884608,0.117439056,0.184676832,0.124464528 +494.0,0.521526016,0.141820224,0.056674896,0.165402848,0.050186832,0.10029872,0.049439328,0.055775472,0.057669664,0.16287624,0.044662624,0.05150208,0.070258848,0.366511232,0.323366464,0.079309232,0.07537392,0.152528,0.127255648,0.240713632,0.2037488,0.17176768,0.610855968,0.35941744,0.05773592,0.335097984,0.3120644,0.0522188,0.398631008,0.26293736,0.45279896,0.207019968,0.631529952,0.102834208,0.068692208,0.530412272,0.070662656,0.625878736,0.079085472,0.161882848,0.7322904,0.161129024,0.310399424,0.049746816,0.197069936,0.338577984,0.477096448,0.522692048,0.171844976,0.26532016,0.32046112,0.150806688,0.274318016,0.771174816,0.746434944,0.658374064,0.446008192,0.403438848,0.791237056,0.771175744,0.586256048,0.424165536,0.105292704,0.52944912,0.19609432,0.348807648,0.404970272,0.47634736,0.26789536,0.690877504,0.194611392,0.54742312,0.483682048,0.058105696,0.165433632,0.37049632,0.240741824,0.273998448,0.587125616,0.457391824,0.219114272,0.732770048,0.470701216,0.062388224,0.144621664,0.413013584,0.144974192,0.324912912,0.095512704,0.12139536,0.576693904,0.256914,0.35982592,0.090671136,0.396850736,0.480079424,0.114499328,0.182177504,0.123235616 +495.0,0.51942,0.14026,0.05601,0.16337,0.04991,0.09999,0.04936,0.05569,0.05805,0.1625,0.04441,0.05087,0.07191,0.36676,0.32476,0.07996,0.07559,0.15359,0.12801,0.2432,0.20499,0.17397,0.61278,0.36343,0.05851,0.34048,0.31468,0.05266,0.40328,0.26432,0.46097,0.21218,0.6331,0.10573,0.06999,0.53055,0.07115,0.62698,0.08031,0.16617,0.73336,0.16761,0.3233,0.04986,0.20369,0.34297,0.47933,0.52583,0.17469,0.27019,0.32597,0.15571,0.28105,0.77166,0.74752,0.66137,0.4487,0.40468,0.79473,0.77145,0.58884,0.42262,0.10508,0.52895,0.19443,0.34737,0.40282,0.47732,0.26902,0.688,0.19206,0.54681,0.48059,0.05785,0.16234,0.36621,0.23809,0.27027,0.5833,0.45229,0.21652,0.73044,0.46771,0.06267,0.14321,0.40934,0.1429,0.32103,0.09358,0.11977,0.57511,0.25488,0.357,0.08937,0.39437,0.47729,0.11163,0.1797,0.12204 +496.0,0.517340448,0.138711136,0.055448432,0.16149208,0.049643872,0.099692816,0.04928384,0.055604608,0.058389872,0.16217296,0.044176784,0.050272032,0.07350456,0.367020192,0.326160112,0.080608992,0.075794528,0.154660928,0.128939392,0.24502408,0.206297792,0.176217152,0.614745744,0.367572,0.059350512,0.345991392,0.317392288,0.053322224,0.407954864,0.265669632,0.46912592,0.217389632,0.634623216,0.108705648,0.071296064,0.530651712,0.071545216,0.6280688,0.081490432,0.170374304,0.73426496,0.174602784,0.33637648,0.049972544,0.210618688,0.34720016,0.481169056,0.528885408,0.177408464,0.274868992,0.331219808,0.160505744,0.28776176,0.77206848,0.748509552,0.6639792,0.451115584,0.405645744,0.7981048,0.771666496,0.591364128,0.420941824,0.104784736,0.528178288,0.192557648,0.345678976,0.400372128,0.478164416,0.270085872,0.685006512,0.189419936,0.54616416,0.47744776,0.057573296,0.159215328,0.36184272,0.235476544,0.266565136,0.579430032,0.44720512,0.213933984,0.728098848,0.464730176,0.06291944,0.141629888,0.405650688,0.140831472,0.317188832,0.091682336,0.118214688,0.573492192,0.252881248,0.354219312,0.088110512,0.391871184,0.47451728,0.108838528,0.177244448,0.120876992 +497.0,0.515288224,0.137173728,0.054993984,0.159771536,0.049388384,0.099406624,0.049210864,0.05551968,0.058687136,0.161894128,0.043961808,0.049702336,0.075036688,0.367293536,0.327560336,0.081256272,0.075988176,0.155737968,0.130049488,0.246196688,0.207683568,0.178511776,0.616753056,0.371844304,0.060264384,0.351632016,0.320181488,0.054227744,0.41266296,0.266991632,0.477259936,0.222647504,0.636115616,0.111766208,0.072606672,0.530713968,0.071864624,0.62915096,0.082622544,0.174482176,0.735011488,0.18211312,0.349587888,0.050084208,0.217852176,0.351263024,0.482619472,0.531861808,0.17999608,0.279342832,0.336192688,0.165177696,0.294424032,0.77240472,0.749404384,0.666206032,0.453252752,0.406339488,0.801350656,0.771823696,0.593819136,0.419137792,0.104408048,0.527139632,0.190488864,0.343741744,0.397635616,0.478871904,0.27108568,0.681898256,0.186697104,0.54548568,0.474252064,0.057276752,0.156067232,0.357395408,0.232908912,0.262879872,0.5755224,0.442144736,0.211352512,0.725749184,0.461762752,0.063134208,0.139880896,0.40194664,0.13876736,0.313392288,0.089820592,0.116726512,0.571839824,0.250918032,0.351490032,0.086893024,0.389353456,0.471761728,0.106131856,0.174812992,0.119744848 +498.0,0.51328216,0.13565408,0.054620256,0.158213552,0.049143856,0.099126352,0.049140048,0.055437312,0.05893472,0.161663856,0.043759792,0.04920616,0.076490176,0.36758088,0.3289528,0.081902992,0.076168784,0.156820448,0.131371904,0.246794416,0.209154624,0.18085496,0.618802528,0.376243008,0.061251136,0.35739008,0.323051008,0.055328304,0.417427376,0.268225872,0.485323632,0.227952496,0.637614016,0.114904848,0.0739136,0.530758544,0.072074832,0.6302596,0.083696736,0.178471248,0.735609216,0.190184496,0.362845776,0.050193712,0.225266784,0.355153568,0.483696128,0.534768928,0.182455696,0.283567232,0.340829488,0.169698288,0.300996624,0.77267088,0.750203536,0.668054064,0.45511168,0.406771552,0.804437632,0.771920576,0.596197664,0.41721288,0.10395552,0.525841616,0.18825072,0.341563152,0.394629984,0.479424672,0.272009568,0.67867392,0.183888992,0.54477504,0.470987408,0.056962448,0.152898016,0.352861296,0.23037752,0.259191488,0.571592048,0.437117792,0.2087668,0.72340512,0.458813728,0.063308416,0.138024304,0.398221712,0.136702768,0.309665664,0.088007648,0.115299376,0.570173936,0.248998656,0.348808192,0.085710016,0.386814288,0.469022656,0.103536384,0.172404416,0.118640384 +499.0,0.511347056,0.134160512,0.054274208,0.156822448,0.048910768,0.09884544,0.049070032,0.055360144,0.059124064,0.161482944,0.043564016,0.048848944,0.077845424,0.367882704,0.330329104,0.082550592,0.076333232,0.157908368,0.13294696,0.246915744,0.21071696,0.183247264,0.62089496,0.380762672,0.062305808,0.363249984,0.326014288,0.056536064,0.422276352,0.269282992,0.493254688,0.233303568,0.639162176,0.118110688,0.075207168,0.53081976,0.07212592,0.63143456,0.084701648,0.18231624,0.736068864,0.198872912,0.376045904,0.050299376,0.232678272,0.358866992,0.484416944,0.537618608,0.184792592,0.287487792,0.345057248,0.17403616,0.307435776,0.77286832,0.750905568,0.669526576,0.456693408,0.406954496,0.807329328,0.771956336,0.598493072,0.415171408,0.103434272,0.5242924,0.185875456,0.3391472,0.391378272,0.47980184,0.272846816,0.675331344,0.18099024,0.54403296,0.467634272,0.056632704,0.14970816,0.348231104,0.227862048,0.255471024,0.567656656,0.432133648,0.206171488,0.721084576,0.455890704,0.063435104,0.136160912,0.394467424,0.134631696,0.30604168,0.086260304,0.11392624,0.568526768,0.24713168,0.346166432,0.084551328,0.38425048,0.466299024,0.101084912,0.1700164,0.11756 +500.0,0.5095,0.1327,0.05392,0.1556,0.04869,0.09856,0.049,0.05529,0.05925,0.16135,0.04337,0.04867,0.07909,0.3682,0.33168,0.0832,0.07648,0.159,0.1348,0.24664,0.21238,0.18569,0.62303,0.3854,0.06343,0.3692,0.32907,0.0578,0.42723,0.27011,0.50101,0.2387,0.64079,0.12138,0.07648,0.53092,0.072,0.6327,0.08563,0.186,0.7364,0.20821,0.3891,0.0504,0.23996,0.3624,0.4848,0.54042,0.18701,0.29107,0.34883,0.17817,0.3137,0.773,0.75151,0.67063,0.458,0.4069,0.81,0.77193,0.6007,0.41302,0.10285,0.5225,0.18339,0.3365,0.3879,0.47999,0.27359,0.67187,0.178,0.54326,0.46418,0.05629,0.1465,0.3435,0.22535,0.2517,0.56373,0.4272,0.20356,0.7188,0.453,0.06351,0.13436,0.39068,0.13255,0.30254,0.08459,0.1126,0.56692,0.24532,0.34356,0.08341,0.38166,0.46359,0.0988,0.16765,0.1165 +501.0,0.507743936,0.131275824,0.053572464,0.154547536,0.048482672,0.098270464,0.048930016,0.055227248,0.059312512,0.16126152,0.04317704,0.048665744,0.08022232,0.36853456,0.332996368,0.083851264,0.07661016,0.160091264,0.13693048,0.246003328,0.214157776,0.188185632,0.62520608,0.3901556,0.06464544,0.375236512,0.332205264,0.059133776,0.432293872,0.27071744,0.508580528,0.244141168,0.642505488,0.124720128,0.0777292,0.531054912,0.071726736,0.634057344,0.086480528,0.189516096,0.736609712,0.218185568,0.401955024,0.050495264,0.247097632,0.36575096,0.48486032,0.543176928,0.189106752,0.294310176,0.352143936,0.18209192,0.31975592,0.773071024,0.752017696,0.671374352,0.459034016,0.406616448,0.812441984,0.771840272,0.602812784,0.410768288,0.102205408,0.520471648,0.180810256,0.333630704,0.38420744,0.479986016,0.274235488,0.668291648,0.174925168,0.542456224,0.460623296,0.055936624,0.14327968,0.338670944,0.222847328,0.247877456,0.55981856,0.422322144,0.200922816,0.716554144,0.45014472,0.06353272,0.132612576,0.38686304,0.130456912,0.299159056,0.08299832,0.111314912,0.565351088,0.243562288,0.340990352,0.082285104,0.379042928,0.460895664,0.096686208,0.165310592,0.115457296 +502.0,0.50608408,0.1298916,0.053244496,0.153667952,0.048289856,0.097976592,0.048859968,0.055172432,0.05931088,0.161215056,0.042983792,0.04884528,0.081238976,0.36888792,0.3342696,0.084504512,0.076724304,0.161178608,0.139340384,0.245047936,0.216063264,0.19073624,0.627422048,0.395029568,0.065980736,0.3813548,0.335425408,0.060524064,0.437474896,0.271100672,0.515951552,0.249626256,0.644319696,0.128136048,0.07895184,0.531222784,0.071325072,0.63551216,0.087250976,0.192855568,0.736705296,0.228791856,0.414555056,0.050584672,0.254047344,0.368918368,0.484613328,0.545893648,0.191082656,0.297199472,0.354988448,0.185790848,0.325571264,0.77308576,0.752429136,0.671769104,0.45979832,0.406112672,0.814645152,0.771686016,0.604824784,0.40842536,0.10150376,0.518214656,0.17815368,0.330547952,0.380314064,0.479784352,0.274778448,0.66459736,0.171771552,0.54162168,0.456961168,0.055574768,0.140052736,0.333746336,0.22035616,0.243999888,0.555929488,0.417505472,0.19825304,0.7143512,0.447328208,0.063502256,0.130916624,0.383019072,0.128351488,0.295900624,0.081488128,0.110065536,0.563819376,0.241860096,0.338457952,0.081174736,0.376399248,0.458216336,0.094750064,0.163002496,0.114429024 +503.0,0.504517264,0.128553296,0.052904048,0.152947088,0.0481144,0.09768256,0.04879072,0.055125216,0.059250688,0.161199232,0.042792304,0.049164256,0.082150672,0.3692628,0.335484592,0.08515928,0.076825808,0.162254112,0.142014448,0.243818544,0.218118272,0.193345728,0.629672656,0.400024176,0.067429712,0.387551248,0.338645392,0.062038352,0.44277216,0.271313024,0.523132816,0.255156464,0.646220144,0.131647168,0.08014544,0.531425216,0.070884928,0.637035856,0.087947504,0.19603112,0.73669416,0.239995504,0.426840048,0.05066832,0.260832976,0.371904496,0.484083776,0.548573408,0.19293648,0.299766208,0.357402,0.189282096,0.331100848,0.773053216,0.752747296,0.671832976,0.460299824,0.405401216,0.816614,0.77146568,0.606739904,0.406006192,0.100747632,0.515737664,0.175435824,0.32726496,0.376231568,0.479398288,0.275224848,0.660792512,0.168550976,0.540756976,0.45320112,0.055208352,0.136825632,0.328733008,0.217877872,0.2400792,0.552067056,0.4127524,0.195540064,0.712188736,0.444555296,0.063423312,0.129301872,0.379158864,0.126234144,0.292745152,0.080057136,0.10884136,0.562329744,0.240187904,0.335962272,0.080080048,0.373729808,0.455550368,0.09298672,0.16073944,0.113409472 +504.0,0.503034528,0.127267552,0.0525044,0.152362704,0.047960064,0.097395248,0.048723712,0.05508464,0.059141296,0.161198208,0.042606736,0.049548672,0.082976368,0.36966256,0.336623184,0.085814688,0.076919712,0.163307456,0.144925312,0.242355952,0.22034944,0.196018976,0.631950544,0.405143264,0.068974448,0.393823776,0.341739136,0.06378632,0.448178864,0.271442336,0.53015008,0.260733952,0.648179952,0.135281168,0.08130848,0.531661888,0.070536064,0.638580352,0.088581152,0.199067232,0.736583424,0.251744192,0.4387528,0.050746688,0.267521088,0.374713824,0.483300704,0.551218208,0.194666064,0.302060704,0.359452352,0.192595344,0.336294752,0.772984832,0.752976496,0.671589728,0.460547648,0.40449608,0.818362528,0.771177504,0.608566944,0.403529024,0.099938944,0.513049872,0.172669968,0.323797568,0.371969952,0.478851424,0.275586288,0.656884784,0.1652792,0.539862912,0.449357232,0.054842096,0.133605728,0.32364112,0.215415264,0.236137072,0.548233104,0.408063488,0.192771808,0.710059872,0.441831104,0.063303888,0.1278032,0.375298176,0.12410648,0.28966,0.078699264,0.107629664,0.560886432,0.238506912,0.333502992,0.0790044,0.371036208,0.45289536,0.091383296,0.158540224,0.11239168 +505.0,0.50163,0.12604,0.05202,0.1519,0.04783,0.09712,0.04866,0.05505,0.05899,0.1612,0.04243,0.04995,0.08373,0.37009,0.33767,0.08647,0.07701,0.16433,0.14805,0.2407,0.22278,0.19876,0.63425,0.41039,0.07062,0.40017,0.34463,0.06583,0.45369,0.27155,0.53702,0.26636,0.65018,0.13906,0.08244,0.53193,0.07038,0.64011,0.08916,0.20198,0.73638,0.26399,0.45024,0.05082,0.27414,0.37735,0.48229,0.55383,0.19627,0.30412,0.36119,0.19575,0.34111,0.77289,0.75312,0.67106,0.46055,0.40341,0.8199,0.77082,0.61031,0.40101,0.09908,0.51016,0.16987,0.32016,0.36754,0.47816,0.27587,0.65288,0.16197,0.53894,0.44544,0.05448,0.1304,0.31848,0.21297,0.23219,0.54443,0.40344,0.18994,0.70796,0.43916,0.06315,0.12644,0.37145,0.12197,0.28662,0.07741,0.10642,0.55949,0.23679,0.33108,0.07795,0.36832,0.45025,0.08993,0.15642,0.11137 +506.0,0.500307232,0.12487344,0.051453984,0.151560432,0.04772568,0.09685752,0.048599424,0.055021408,0.058797728,0.161204272,0.042261552,0.050375104,0.084410448,0.370546464,0.338617648,0.08712488,0.077097648,0.165318208,0.151378432,0.238887952,0.225422768,0.201570192,0.636570304,0.415765568,0.072397104,0.4065864,0.347327456,0.068144224,0.45930616,0.271633392,0.543731824,0.272033376,0.652224272,0.142988832,0.083540736,0.532227424,0.070433728,0.641624736,0.089682832,0.204760288,0.736090464,0.276698144,0.461259808,0.050887904,0.280646768,0.379813984,0.481068128,0.556410336,0.197748944,0.305941568,0.362613856,0.198734512,0.345524288,0.772772,0.753177936,0.67025488,0.460312224,0.402152112,0.821221632,0.77039256,0.61195904,0.398459296,0.098174416,0.50707536,0.167051856,0.316361728,0.362954976,0.477318336,0.276069968,0.648778768,0.1586312,0.537987776,0.441448864,0.05412384,0.127214368,0.313256512,0.210540368,0.228238896,0.540661376,0.3988852,0.187041008,0.705891232,0.43654416,0.062961536,0.12521432,0.367618928,0.119825824,0.283622768,0.076189888,0.105208448,0.558139296,0.23503824,0.328694,0.076915504,0.365583264,0.447616384,0.088626272,0.154383024,0.110342528 +507.0,0.499068544,0.123769856,0.050795168,0.151343088,0.04764872,0.09660896,0.04854176,0.054998736,0.058566048,0.161212352,0.042101424,0.050820096,0.085017472,0.37103328,0.339459712,0.08777872,0.077183888,0.166268752,0.154893648,0.236950944,0.228290032,0.204450528,0.638911216,0.421271856,0.074320512,0.413070528,0.349818512,0.070724432,0.46502432,0.271699024,0.550277536,0.277752544,0.654313264,0.147072848,0.0846136,0.532553376,0.070711408,0.643121776,0.090148544,0.20739792,0.73572096,0.289818944,0.471780608,0.05095024,0.287024336,0.382107696,0.479651056,0.558958928,0.1991036,0.307525648,0.36372712,0.201535936,0.349521968,0.772633376,0.753150176,0.669185696,0.459840544,0.400731216,0.82232568,0.76989488,0.613501424,0.395887552,0.097225872,0.503803104,0.164230064,0.31241256,0.358227648,0.476320048,0.276178928,0.644581472,0.155271776,0.537005376,0.4373844,0.053774992,0.124055232,0.307980048,0.208124352,0.22428704,0.536928576,0.39440128,0.184069504,0.703854336,0.433984816,0.062738592,0.124135632,0.363810464,0.117676224,0.280664032,0.075038096,0.10399224,0.556835104,0.233250944,0.326346512,0.075900048,0.362829568,0.444997808,0.08746744,0.15243312,0.109308032 +508.0,0.497908976,0.122735312,0.050101952,0.151247664,0.04760184,0.09637928,0.048488256,0.054981424,0.058301968,0.161210432,0.041951376,0.051289248,0.085564096,0.371552816,0.340180576,0.08843112,0.077272128,0.167172656,0.158580064,0.234934336,0.231405936,0.207405504,0.641266448,0.426911264,0.07649776,0.419619376,0.352173408,0.07350056,0.47084264,0.271768496,0.556671248,0.283518832,0.656431696,0.151333184,0.085655424,0.532887488,0.071317008,0.644571616,0.090565936,0.209910192,0.735278256,0.303319504,0.481739248,0.051006656,0.293188224,0.384234208,0.478065104,0.56148008,0.200332896,0.308905968,0.364575584,0.20417536,0.353053728,0.772484192,0.753040176,0.667873232,0.459142544,0.39916,0.823218048,0.76932504,0.614943888,0.393309808,0.096236288,0.500352048,0.161419472,0.308326192,0.35336904,0.47518176,0.276205648,0.640293456,0.151904352,0.535993936,0.433256576,0.053437984,0.120928896,0.302657344,0.205723856,0.220348624,0.533236896,0.3899908,0.18103248,0.70184624,0.431487152,0.062487328,0.123157664,0.36003688,0.115521744,0.277719776,0.073950784,0.102760352,0.555557392,0.231416448,0.324036224,0.074905552,0.360057632,0.442391472,0.086447888,0.150585776,0.108260576 +509.0,0.496821088,0.121777168,0.049467536,0.15127608,0.04758808,0.09617472,0.048440672,0.054968752,0.058014368,0.161179632,0.041813648,0.05179656,0.08606776,0.372107712,0.34076168,0.08908176,0.077366448,0.16801904,0.16242264,0.232888128,0.23479864,0.2104408,0.64362768,0.432686352,0.079081728,0.426229824,0.354510864,0.076362128,0.4767596,0.271863328,0.56293448,0.28933448,0.658559088,0.15579616,0.086661008,0.53320016,0.072384368,0.645936416,0.090947248,0.212323584,0.734769232,0.317172544,0.491062128,0.051056672,0.299016992,0.38619704,0.476340032,0.563979712,0.201435232,0.310127328,0.365219168,0.206685264,0.356059088,0.772337008,0.752852576,0.666341488,0.458226304,0.397452384,0.823907136,0.76868056,0.616299632,0.390742464,0.095206944,0.496731552,0.15863496,0.304117584,0.348389552,0.473927712,0.276164288,0.6359216,0.148542768,0.534955296,0.429078592,0.053118416,0.1178416,0.29729424,0.20334208,0.216441488,0.529593056,0.38565648,0.177943296,0.699862624,0.429057648,0.062215984,0.122205856,0.356312736,0.113362384,0.27475928,0.072922992,0.101499104,0.55427608,0.229521712,0.321760816,0.073934896,0.357264336,0.439792496,0.085561696,0.148860352,0.10719272 +510.0,0.4958,0.1209,0.04895,0.15143,0.04761,0.096,0.0484,0.05496,0.05771,0.16111,0.04169,0.05235,0.08654,0.3727,0.34119,0.08973,0.07747,0.1688,0.1664,0.23085,0.23849,0.21356,0.64599,0.4386,0.08218,0.4329,0.35691,0.07923,0.48277,0.272,0.56908,0.2952,0.66068,0.16048,0.08763,0.53347,0.074,0.64719,0.0913,0.21465,0.7342,0.33133,0.4997,0.0511,0.30443,0.388,0.4745,0.56646,0.20241,0.31122,0.3657,0.20908,0.3585,0.7722,0.75259,0.66461,0.4571,0.39562,0.8244,0.76796,0.61757,0.3882,0.09414,0.49295,0.15589,0.2998,0.3433,0.47257,0.27606,0.63147,0.1452,0.53389,0.42486,0.05282,0.1148,0.2919,0.20098,0.21258,0.526,0.3814,0.17481,0.6979,0.4267,0.06193,0.12123,0.35265,0.1112,0.27176,0.07195,0.1002,0.55297,0.22756,0.31952,0.07299,0.35445,0.4372,0.0848,0.14727,0.1061 +511.0,0.49484576,0.120104096,0.048537568,0.151708944,0.047669088,0.095856896,0.048365968,0.054954672,0.057391408,0.161005824,0.041581296,0.052939584,0.086981888,0.3733304,0.341462144,0.090374944,0.077584416,0.169513072,0.170485376,0.228839472,0.242490256,0.21676336,0.648354336,0.44465472,0.085804368,0.439628864,0.359354512,0.082100832,0.488864704,0.272186384,0.575104576,0.301112976,0.662789888,0.1653868,0.088568576,0.53369504,0.076168592,0.648328048,0.091623584,0.21687824,0.733575568,0.345719312,0.50764104,0.051136688,0.309425856,0.389646864,0.472559424,0.568917936,0.203258368,0.31218816,0.366027392,0.211345312,0.360373856,0.772074192,0.75225184,0.662690016,0.455771232,0.393670672,0.824699728,0.767163792,0.618739152,0.385692384,0.093039072,0.489014208,0.15319576,0.295383552,0.338112,0.471101472,0.275884208,0.626938672,0.141886304,0.532796688,0.420603392,0.052543248,0.111810864,0.286487488,0.198636784,0.208770752,0.522455648,0.377221872,0.171632624,0.69595728,0.424413776,0.061629824,0.120234608,0.349055072,0.1090388,0.268716064,0.071028688,0.098862912,0.551638768,0.225531792,0.317316304,0.072070896,0.351620128,0.43461912,0.084151552,0.145816864,0.1049828 +512.0,0.493957296,0.119390352,0.048232512,0.152113264,0.04776672,0.0957476,0.048338576,0.054952304,0.057061728,0.160868832,0.041488656,0.053556288,0.087396416,0.373999376,0.341574176,0.09101592,0.077711728,0.170155376,0.174654864,0.226878256,0.246810416,0.220051744,0.650720928,0.450852464,0.0899796,0.446414576,0.361838368,0.08496096,0.49503544,0.272427696,0.581008368,0.307071232,0.664882816,0.170518464,0.089481184,0.533871808,0.078905648,0.649344096,0.091919056,0.219002512,0.732900896,0.360275104,0.514869088,0.051166736,0.313989104,0.391141568,0.470533824,0.57135176,0.203981456,0.313040608,0.366216144,0.21347376,0.361673168,0.771961712,0.751838096,0.660593712,0.454247504,0.39161264,0.824810048,0.76629232,0.619796048,0.383229008,0.091907408,0.484931248,0.150562832,0.290878752,0.33283672,0.46951944,0.275631888,0.622328736,0.138611712,0.531674496,0.416312656,0.052289024,0.108880496,0.281067984,0.196314016,0.205021104,0.518959136,0.37312288,0.1684172,0.69403328,0.422199312,0.061316768,0.119215744,0.34553464,0.106882464,0.265620416,0.070155904,0.097486672,0.550280032,0.223435568,0.315151424,0.071178032,0.348779072,0.432053712,0.083605888,0.144504176,0.103840976 +513.0,0.493136352,0.118754608,0.048007856,0.152646544,0.047904832,0.095673184,0.048316464,0.054951696,0.056722768,0.16071672,0.041412496,0.054206832,0.087778704,0.374708192,0.341527568,0.091650656,0.07785216,0.1707264,0.178856992,0.22496424,0.251456976,0.223422208,0.65309432,0.457199328,0.094720112,0.453261888,0.364383664,0.087778048,0.501261936,0.272730048,0.58678024,0.313070528,0.666953184,0.175877088,0.090385232,0.533990816,0.082166544,0.650240384,0.092180208,0.220988064,0.732179744,0.374866416,0.521410496,0.051190384,0.318139472,0.392489552,0.468432144,0.573750304,0.204581104,0.313768016,0.366261776,0.215421328,0.36242848,0.771857632,0.751345152,0.658329488,0.452538816,0.389451008,0.824737248,0.765346688,0.620700464,0.380822432,0.090749904,0.480706528,0.148001424,0.286294592,0.32748632,0.467797168,0.275278048,0.61763464,0.13538968,0.530519504,0.41198808,0.05205576,0.106018288,0.27566568,0.194000528,0.201339376,0.515499584,0.369100528,0.165149936,0.6921248,0.420051088,0.060988592,0.11816832,0.342095968,0.104739808,0.262467408,0.0693252,0.096078192,0.548886496,0.221289984,0.313032464,0.070310928,0.345938576,0.429516144,0.083140464,0.143328768,0.102678752 +514.0,0.492386528,0.118189664,0.04781504,0.153313904,0.048085424,0.095633808,0.048297472,0.054951328,0.056375168,0.160576688,0.041352816,0.054903136,0.088118832,0.375458208,0.34132792,0.092276112,0.078004912,0.171227584,0.18302656,0.223081104,0.256432496,0.226869552,0.655481952,0.463703232,0.100023504,0.46017872,0.36701408,0.090519616,0.507517552,0.27309768,0.592401872,0.319105184,0.668996912,0.181462112,0.09130512,0.534042304,0.08586656,0.651026432,0.0923964,0.222783616,0.731415072,0.389327808,0.527317664,0.051208032,0.3219228,0.393697056,0.466258784,0.576097248,0.205059792,0.314349184,0.366146528,0.217123216,0.362693632,0.771752672,0.750767248,0.655902784,0.450656288,0.387188816,0.824488448,0.764328656,0.62139632,0.378485856,0.0895724,0.476344448,0.145520976,0.281638912,0.32207344,0.465894176,0.274786608,0.612847184,0.132234848,0.529326112,0.407627424,0.051840256,0.10323504,0.270311296,0.19167928,0.197733328,0.512060672,0.365150576,0.161807792,0.690228,0.417960224,0.060640736,0.117092976,0.338745776,0.102622432,0.25925448,0.068528736,0.094649472,0.5474512,0.21912432,0.310969424,0.069468464,0.34311456,0.427023616,0.08272656,0.1422828,0.101503168 +515.0,0.49171,0.11769,0.04762,0.15412,0.04831,0.09563,0.04828,0.05495,0.05602,0.16047,0.04131,0.05565,0.08841,0.37625,0.34098,0.09289,0.07817,0.17166,0.18711,0.22122,0.26174,0.23039,0.65789,0.47037,0.10589,0.46717,0.36974,0.09316,0.51378,0.27353,0.59786,0.32517,0.67101,0.18727,0.09226,0.53402,0.08994,0.65171,0.09256,0.22435,0.73061,0.40352,0.53263,0.05122,0.32537,0.39477,0.46402,0.57838,0.20542,0.31477,0.36586,0.21853,0.36251,0.77164,0.7501,0.65332,0.44861,0.38483,0.82407,0.76324,0.62184,0.37623,0.08838,0.47185,0.14313,0.27692,0.31661,0.46378,0.27413,0.60796,0.12916,0.52809,0.40323,0.05164,0.10054,0.26503,0.18934,0.19421,0.50863,0.36127,0.15838,0.68834,0.41592,0.06027,0.11599,0.33549,0.10054,0.25598,0.06776,0.09321,0.54597,0.21696,0.30897,0.06865,0.34032,0.42459,0.08234,0.14136,0.10032 +516.0,0.491104704,0.117254944,0.047428576,0.15506744,0.048578688,0.09566336,0.048263968,0.05494736,0.055659664,0.160400064,0.041285504,0.056449856,0.08865472,0.377081728,0.340485968,0.09349208,0.078349872,0.172023552,0.191088672,0.219394304,0.267383856,0.233984256,0.660320992,0.477199424,0.112331232,0.474231776,0.372559728,0.095681872,0.520039968,0.27402592,0.603156624,0.331261312,0.672988608,0.193288544,0.093253168,0.533923648,0.094378496,0.652290176,0.092672192,0.225684624,0.729768256,0.41738216,0.537347872,0.051226432,0.328471872,0.395713312,0.46172768,0.580596992,0.205664112,0.315037568,0.36541384,0.219638368,0.361881344,0.771520128,0.749343408,0.650590416,0.446406816,0.382380976,0.823486048,0.762082432,0.622025056,0.374058592,0.087175616,0.467230128,0.140834336,0.272147456,0.311106016,0.461454528,0.273306032,0.602975184,0.126172608,0.52681104,0.398799792,0.051454592,0.097937728,0.259830592,0.186984224,0.190774512,0.505206752,0.357459632,0.154880736,0.686460864,0.413930272,0.059877552,0.114851472,0.332332112,0.098496416,0.252645344,0.067016272,0.09176144,0.544442864,0.214798176,0.307035184,0.06785616,0.337559328,0.422219328,0.081970336,0.140558832,0.0991312 +517.0,0.490568272,0.116883008,0.047243216,0.156159184,0.048890912,0.095735024,0.048249184,0.054943136,0.055295968,0.16037096,0.041280896,0.057317552,0.088855024,0.377950192,0.339851328,0.094082336,0.0785472,0.17231976,0.194948432,0.2176136,0.273364496,0.237653088,0.6627788,0.484189968,0.119346912,0.481358608,0.375477344,0.098067888,0.526288256,0.274587408,0.60829432,0.337374688,0.674930784,0.199497248,0.094286752,0.533754496,0.099160064,0.652768224,0.092734048,0.226787104,0.728893024,0.430859136,0.541479456,0.051227584,0.331228352,0.396532272,0.459391664,0.582747024,0.205795184,0.315157456,0.364816976,0.220447728,0.36081672,0.771392752,0.748497632,0.647721488,0.444052976,0.379847088,0.822740448,0.760858368,0.621948224,0.371972112,0.085961984,0.462491808,0.138637344,0.267330272,0.30557104,0.458919488,0.272314368,0.59789552,0.12327848,0.525489744,0.39434056,0.05128296,0.095431648,0.25472,0.184610128,0.187430256,0.501790464,0.353720608,0.151323296,0.68459168,0.411990848,0.059464512,0.11366856,0.329273408,0.096495488,0.249257488,0.06629536,0.090306752,0.542870896,0.212641904,0.305165504,0.067087488,0.334836976,0.419915584,0.081607984,0.139875008,0.097939792 +518.0,0.49010312,0.116569872,0.047040416,0.157400848,0.049248656,0.095846048,0.04823448,0.054936272,0.054930512,0.160403376,0.041296608,0.058207488,0.089004688,0.378857456,0.339077728,0.094658672,0.078761808,0.172548208,0.198631152,0.215873216,0.279688976,0.24139224,0.665267968,0.491348272,0.126942112,0.48855672,0.37844184,0.100316624,0.532502624,0.275182816,0.613259056,0.343505504,0.6768308,0.205900352,0.095381296,0.533513664,0.104232112,0.653156512,0.092738464,0.227615584,0.727987712,0.443806032,0.54505648,0.051223536,0.333651872,0.397232512,0.457020128,0.584817456,0.205815216,0.315117184,0.364061792,0.220905968,0.359352656,0.771251856,0.747557616,0.64472144,0.441559376,0.37723376,0.821839648,0.759569104,0.621563152,0.369983632,0.084744352,0.457639648,0.136549792,0.262477408,0.300016944,0.456141968,0.271125904,0.592714016,0.120491552,0.524120448,0.389851808,0.051123168,0.093032208,0.249724688,0.182227792,0.18418552,0.498368736,0.350049184,0.147721536,0.682728416,0.410094864,0.059027152,0.112456768,0.326322224,0.09454688,0.245808752,0.065590608,0.088854704,0.541257488,0.210504112,0.303368704,0.066343776,0.332165344,0.4176924,0.081227712,0.139304944,0.096750544 +519.0,0.489713248,0.116310336,0.046789216,0.158799152,0.04965472,0.095997472,0.048218416,0.054925488,0.054564816,0.160523552,0.04133272,0.059047584,0.089094752,0.37980736,0.338165568,0.095218368,0.078992576,0.172707856,0.202064032,0.214163792,0.286366576,0.245195712,0.667793216,0.498683616,0.135122512,0.495836192,0.381374576,0.102436,0.538656512,0.275764624,0.618031232,0.34964904,0.678681696,0.212510256,0.09656352,0.533203712,0.10953176,0.65347224,0.09267568,0.228114304,0.72705576,0.456048048,0.548118544,0.051214288,0.335757472,0.397819792,0.454620672,0.586791888,0.205725888,0.314898272,0.363135168,0.220943808,0.357534912,0.77108952,0.74651648,0.641598752,0.438938496,0.374546512,0.820790928,0.7582156,0.6208092,0.368110272,0.0835288,0.452677408,0.13458488,0.257597824,0.294456288,0.453077408,0.269702,0.587420432,0.117828384,0.522695312,0.385331616,0.050972976,0.090752208,0.244877536,0.179854096,0.181050144,0.494925248,0.34643992,0.144093456,0.680865312,0.4082332,0.058560032,0.111242096,0.32348928,0.092662192,0.242286496,0.064893936,0.087416096,0.53960824,0.20839992,0.301654864,0.065624624,0.329559392,0.415566576,0.08079904,0.13884528,0.095568816 +520.0,0.4894,0.1161,0.04647,0.16036,0.05011,0.09619,0.0482,0.05491,0.0542,0.16075,0.04139,0.0598,0.08912,0.3808,0.33712,0.09576,0.07924,0.1728,0.2052,0.21248,0.2934,0.24906,0.67036,0.5062,0.14388,0.5032,0.38422,0.10443,0.54473,0.2763,0.6226,0.3558,0.68048,0.21932,0.09785,0.53283,0.115,0.65373,0.09254,0.22825,0.7261,0.46746,0.5507,0.0512,0.33756,0.3983,0.4522,0.58866,0.20553,0.31449,0.36203,0.22052,0.3554,0.7709,0.74537,0.63836,0.4362,0.37179,0.8196,0.7568,0.61965,0.36636,0.08232,0.44761,0.13275,0.2527,0.2889,0.4497,0.26802,0.58201,0.1153,0.52121,0.38078,0.05083,0.0886,0.2402,0.1775,0.17803,0.49145,0.34289,0.14046,0.679,0.4064,0.05806,0.11004,0.32078,0.09085,0.23869,0.0642,0.086,0.53793,0.20634,0.30003,0.06493,0.32703,0.41355,0.0803,0.13849,0.0944 +521.0,0.489160848,0.115936352,0.046085152,0.162086288,0.050612528,0.096424096,0.04817904,0.054889792,0.053836768,0.161087344,0.041470768,0.060478016,0.089081808,0.381830048,0.33595224,0.096284032,0.079507392,0.17282912,0.208035392,0.21082552,0.300782288,0.252985888,0.67297352,0.513892912,0.153183984,0.51064024,0.386974544,0.10628768,0.550714592,0.27678968,0.626969136,0.361952336,0.682226896,0.226295984,0.09924,0.53239784,0.12059544,0.653936112,0.09233272,0.228027072,0.725122624,0.47800168,0.552821584,0.051181072,0.339069456,0.398678784,0.44976432,0.590421328,0.205231744,0.313895504,0.360750512,0.2196404,0.352965392,0.770681712,0.744118416,0.635009408,0.43334872,0.36896776,0.818270144,0.755325792,0.61808904,0.364727488,0.081120384,0.442444176,0.13104384,0.247791712,0.283356272,0.446015456,0.26608376,0.576487072,0.112908272,0.51966608,0.376199984,0.05069224,0.08657648,0.235694384,0.175164928,0.1751248,0.487943664,0.339400832,0.136839088,0.6771352,0.404595312,0.057528048,0.108852544,0.318191616,0.089113248,0.235035136,0.063507904,0.084611488,0.53622744,0.204328336,0.298493632,0.064260352,0.324581024,0.411646,0.079723696,0.138230576,0.093248656 +522.0,0.48899448,0.115816752,0.045636496,0.163980208,0.051160736,0.096700368,0.04815528,0.054864752,0.053475792,0.161542256,0.041577648,0.061073168,0.088980368,0.382893376,0.334672368,0.096790512,0.079797808,0.172799328,0.210561472,0.209202576,0.308507376,0.25697336,0.675638048,0.521758832,0.162998672,0.51815128,0.38962576,0.107999104,0.556600064,0.277231296,0.631139856,0.368099824,0.68392256,0.233410992,0.100735056,0.531910864,0.126277312,0.654097552,0.092054064,0.227443904,0.724125952,0.487622432,0.55450616,0.051157856,0.340294352,0.398961552,0.447319728,0.592073456,0.204834976,0.313115264,0.359298432,0.218303728,0.350251696,0.770432336,0.742761056,0.63155144,0.430389936,0.36608336,0.816805088,0.753795984,0.616123392,0.363209952,0.079932832,0.437186128,0.129466272,0.242880608,0.277833344,0.442024528,0.263893024,0.570854656,0.110655712,0.518064208,0.371593568,0.050557888,0.084683248,0.231365248,0.172852032,0.17233472,0.484405296,0.335972864,0.133247056,0.675272576,0.402818464,0.056964512,0.107693648,0.315722384,0.0874552,0.231334112,0.062816208,0.083256144,0.534504208,0.202370192,0.297046464,0.063615936,0.322217264,0.40985904,0.079061792,0.138059424,0.092119184 +523.0,0.488892832,0.115737952,0.04512904,0.166049488,0.051749424,0.09701784,0.04812888,0.054835632,0.053116656,0.162112608,0.041712128,0.06167256,0.088820928,0.383977264,0.333303056,0.097282432,0.080116064,0.172719936,0.212803792,0.207613472,0.316556944,0.261026112,0.678364896,0.529786112,0.17328336,0.52571296,0.392161536,0.109573488,0.562385216,0.277616112,0.635127136,0.374235392,0.685576144,0.2405888,0.102323232,0.531393008,0.131973984,0.654229152,0.091709808,0.226532896,0.72311032,0.496335264,0.555781696,0.05113104,0.341259568,0.39915568,0.444868656,0.593624784,0.204346768,0.312160064,0.357682592,0.216549856,0.34727488,0.7701516,0.741301616,0.627985712,0.427325632,0.36313848,0.815205552,0.752217616,0.613789024,0.361784496,0.0787576,0.43184456,0.128006064,0.237973824,0.272337776,0.43775584,0.261472128,0.56512392,0.108537792,0.516410176,0.366967392,0.050422736,0.082916176,0.227201552,0.170556096,0.16965368,0.480843088,0.332611536,0.129730144,0.673420992,0.401072096,0.056372336,0.106530432,0.313361312,0.085877232,0.227628208,0.062127632,0.08194016,0.532780016,0.200461648,0.295681936,0.06299816,0.319938224,0.40818752,0.078314688,0.137958672,0.091018992 +524.0,0.488844224,0.115696672,0.044572864,0.168303888,0.052371232,0.097374752,0.04810032,0.054803712,0.05275832,0.16279024,0.041875488,0.062412352,0.088611968,0.385064192,0.331873904,0.097764432,0.08046824,0.172603264,0.214810592,0.206061568,0.324905232,0.265150144,0.681168544,0.537957952,0.183989408,0.5332968,0.394575632,0.111027472,0.568074688,0.277936768,0.638954416,0.38035136,0.687201728,0.247726368,0.103983728,0.530877792,0.137601536,0.654348512,0.091309312,0.225347728,0.722075008,0.504195696,0.556677152,0.051101504,0.341996864,0.399269408,0.442411584,0.595090112,0.20377592,0.311047264,0.355916432,0.214444704,0.344046464,0.769840704,0.739746416,0.624309104,0.424155488,0.36013368,0.813470496,0.750599808,0.611145856,0.3604168,0.077593408,0.426429552,0.126645376,0.23307808,0.266874848,0.433255552,0.258860752,0.559311184,0.106545152,0.514713024,0.362330576,0.050281504,0.081267264,0.223182016,0.16826704,0.1670716,0.47727104,0.329325168,0.126348512,0.671593408,0.399361248,0.05575624,0.105308336,0.31109176,0.084378944,0.223974784,0.061447536,0.080669536,0.531081904,0.198593504,0.294389168,0.062409024,0.317739904,0.40662576,0.077489184,0.1379052,0.0899568 +525.0,0.48884,0.11569,0.04398,0.17075,0.05302,0.09777,0.04807,0.05477,0.0524,0.16357,0.04207,0.06338,0.08836,0.38614,0.33041,0.09824,0.08086,0.17246,0.21662,0.20455,0.33353,0.26935,0.68406,0.54626,0.19506,0.54088,0.39686,0.11237,0.57367,0.27819,0.64264,0.38644,0.68881,0.25474,0.1057,0.53039,0.14309,0.65447,0.09086,0.22393,0.72102,0.51124,0.55722,0.05107,0.34253,0.39931,0.43995,0.59648,0.20313,0.30979,0.35401,0.21204,0.34058,0.7695,0.7381,0.62052,0.42088,0.35707,0.8116,0.74895,0.60824,0.35908,0.07644,0.42095,0.12537,0.2282,0.26145,0.42856,0.25609,0.55343,0.10467,0.51298,0.35769,0.05013,0.07973,0.21929,0.16598,0.16458,0.4737,0.32612,0.12315,0.6698,0.39769,0.05512,0.104,0.3089,0.08296,0.22042,0.06078,0.07945,0.52943,0.19676,0.29316,0.06185,0.31562,0.40517,0.07659,0.13788,0.08894 +526.0,0.488880576,0.115715808,0.04335408,0.173387808,0.053693408,0.098204208,0.048037952,0.054734608,0.052041792,0.164455584,0.042300624,0.064568208,0.0880656,0.387200544,0.328922944,0.098709488,0.081295568,0.17229584,0.218239936,0.20308112,0.342419744,0.273626016,0.687039696,0.55468544,0.206448112,0.548456608,0.399003504,0.113602,0.579162848,0.278374064,0.646186912,0.39249328,0.69040152,0.261604048,0.107468176,0.529932656,0.14841152,0.65459896,0.090363392,0.222285344,0.719947424,0.517446608,0.557433088,0.051036768,0.3428684,0.399281888,0.437488384,0.597792432,0.2024128,0.30838864,0.351963264,0.209344608,0.336894944,0.769127296,0.7363616,0.616621136,0.417502016,0.353949712,0.80959744,0.747270544,0.605076096,0.357769856,0.075300016,0.415411312,0.124176672,0.223345952,0.25606944,0.423676576,0.2531652,0.547485664,0.102909376,0.511213168,0.353045808,0.049967184,0.078302272,0.215523104,0.163698656,0.162175104,0.470131264,0.322996256,0.120140816,0.668042688,0.396059424,0.05446432,0.102618576,0.306780752,0.081620304,0.216976192,0.060125072,0.078286144,0.527827488,0.194963872,0.29199448,0.061321312,0.313581056,0.403822352,0.075615904,0.137876384,0.08797216 +527.0,0.488967472,0.115772272,0.04269408,0.176216928,0.054388944,0.098678,0.04800432,0.054697712,0.051683616,0.165448688,0.042573568,0.06599224,0.087729648,0.388241904,0.327424576,0.099173472,0.081779744,0.172117056,0.219687472,0.201658032,0.351560544,0.277978832,0.690105456,0.563225872,0.2181168,0.55602072,0.401001136,0.114734528,0.584545856,0.278485472,0.649599216,0.398502192,0.691976704,0.26829552,0.109281312,0.529509008,0.153548864,0.654738912,0.089821728,0.220423456,0.71885944,0.522810224,0.557337616,0.05100192,0.343025008,0.39918888,0.435030656,0.599025584,0.201627888,0.306843744,0.349775712,0.206372816,0.33300888,0.76872064,0.734530416,0.612614512,0.414022992,0.3507744,0.807466032,0.745563216,0.601662624,0.356482096,0.07417592,0.40981848,0.123060784,0.218521664,0.250738416,0.41861656,0.250094608,0.54148472,0.101257472,0.509415456,0.348397072,0.049792576,0.076979936,0.211875312,0.161423136,0.15985112,0.466567328,0.319954096,0.117317024,0.666323392,0.394471616,0.053790096,0.101159072,0.304726912,0.080357792,0.213654608,0.059483472,0.07718152,0.526277696,0.193205888,0.290892416,0.06082328,0.311624224,0.4025836,0.074569888,0.137888752,0.087056192 +528.0,0.489090928,0.115856816,0.0420452,0.179238528,0.05510016,0.099190752,0.047969648,0.054660416,0.05132464,0.166546512,0.042890432,0.067614272,0.087358416,0.389249824,0.325939648,0.099634576,0.082318,0.171933952,0.220991328,0.200283344,0.360932224,0.282412368,0.693271216,0.571868144,0.229930528,0.563549872,0.402834048,0.115736256,0.589820544,0.27854424,0.65289392,0.404460304,0.693546288,0.274728032,0.111126128,0.52913472,0.158420928,0.654904704,0.089241904,0.218381328,0.717755936,0.52735104,0.556963024,0.050966592,0.343000736,0.399038672,0.432578928,0.600189536,0.200783216,0.305168448,0.34745768,0.203171504,0.328937616,0.768280144,0.732610992,0.608499568,0.410445008,0.347546208,0.805206144,0.743836128,0.598041952,0.355189376,0.073067984,0.404180688,0.122009376,0.213734336,0.245462752,0.413411344,0.246906496,0.535439376,0.099709088,0.507592864,0.343751776,0.049601648,0.07575864,0.20833296,0.159166336,0.157601776,0.463018032,0.316999376,0.114745952,0.664652096,0.392929888,0.053101392,0.099694448,0.302727152,0.079174,0.210502944,0.058858992,0.076143536,0.524793024,0.191485904,0.289845792,0.060356608,0.309749072,0.401451088,0.073451872,0.13789704,0.086199824 +529.0,0.489237424,0.11596672,0.0414728,0.182453328,0.055819216,0.099741504,0.047934656,0.05462416,0.050963744,0.167744816,0.043251376,0.069361664,0.086959984,0.390206624,0.3244972,0.100096,0.082916096,0.171758208,0.222184064,0.198959536,0.370512464,0.286931584,0.696556336,0.580597456,0.241709456,0.571016144,0.404478,0.116556704,0.594991552,0.278581808,0.656092304,0.410362096,0.695124432,0.280794064,0.112987264,0.528828112,0.162925232,0.655114736,0.0886324,0.21620496,0.716636032,0.531097776,0.556341552,0.050932304,0.342789264,0.398840224,0.43013472,0.601298288,0.199888224,0.303380112,0.345023088,0.199798512,0.324696432,0.767806608,0.730609648,0.604274944,0.406770384,0.344267536,0.802817216,0.74209952,0.59426776,0.353856576,0.071975808,0.398508496,0.121006688,0.208991648,0.240248368,0.408098848,0.243635824,0.529363712,0.098259184,0.505752352,0.33912088,0.04938856,0.074633984,0.204879728,0.156947776,0.155420672,0.459495696,0.314139776,0.11252024,0.66304144,0.391438,0.052403408,0.098337344,0.300768832,0.078071648,0.20758112,0.058256512,0.075180992,0.523387632,0.18980408,0.288843968,0.059922016,0.30795472,0.400420976,0.072260656,0.137876368,0.085412336 +530.0,0.4894,0.1161,0.04102,0.18586,0.05654,0.10033,0.0479,0.05459,0.0506,0.16904,0.04366,0.07119,0.08654,0.3911,0.32312,0.10056,0.08358,0.1716,0.2233,0.19769,0.38028,0.29154,0.69997,0.5894,0.25332,0.5784,0.40592,0.11717,0.60006,0.27862,0.65921,0.4162,0.69672,0.28642,0.11485,0.5286,0.167,0.65538,0.088,0.21393,0.7155,0.53408,0.5555,0.0509,0.34239,0.3986,0.4277,0.60236,0.19895,0.30149,0.34248,0.1963,0.3203,0.7673,0.72853,0.59994,0.403,0.34094,0.8003,0.74036,0.59038,0.35246,0.0709,0.39281,0.12004,0.2043,0.2351,0.40271,0.24031,0.52327,0.0969,0.5039,0.33451,0.04915,0.0736,0.2015,0.15478,0.1533,0.45601,0.31138,0.11069,0.6615,0.39,0.0517,0.09716,0.29884,0.07705,0.20493,0.05768,0.0743,0.52207,0.18816,0.28788,0.05952,0.30624,0.39949,0.071,0.13781,0.0847 +531.0,0.489582384,0.11625592,0.04068296,0.189455424,0.057259872,0.10095704,0.047866048,0.054558192,0.050233056,0.170431072,0.044125232,0.073115056,0.086099856,0.391926912,0.321819264,0.101027232,0.084315216,0.171465936,0.224371184,0.196479104,0.390216736,0.296238368,0.703505248,0.59826432,0.26472616,0.585696176,0.407168272,0.117588592,0.605020832,0.278660528,0.6622524,0.42196368,0.698332816,0.291590192,0.116703136,0.528450464,0.170645696,0.655699568,0.087348032,0.211571664,0.714350096,0.536319568,0.55445616,0.050869648,0.341816112,0.39832048,0.4252776,0.603372672,0.197971584,0.2994992,0.339827344,0.192697952,0.315762688,0.766758656,0.726371248,0.595495888,0.399133456,0.337564192,0.797657312,0.738618384,0.586392576,0.35099608,0.06984288,0.387089408,0.11910304,0.199663808,0.230020928,0.397261168,0.236941408,0.517166448,0.095621296,0.50203976,0.329916624,0.048886688,0.072649392,0.198182,0.152661408,0.151231216,0.452565248,0.308719808,0.109245568,0.660029488,0.38861936,0.050992528,0.09615616,0.296931728,0.076103712,0.20255688,0.05713136,0.07350208,0.520840528,0.18655312,0.286953328,0.059150752,0.304603872,0.398656688,0.06968112,0.137695296,0.084064032 +532.0,0.489786608,0.116433936,0.04046176,0.193236608,0.05797592,0.101623232,0.047833168,0.054529056,0.04986256,0.171917152,0.044655472,0.075137152,0.085641776,0.392683024,0.320607328,0.101498576,0.08512688,0.171362512,0.225429888,0.195330944,0.400303904,0.301027648,0.707157696,0.607178144,0.275880848,0.592897072,0.408232288,0.117810736,0.609870784,0.27871024,0.66522656,0.427643584,0.699964128,0.296280912,0.118535728,0.52838104,0.173850528,0.656073744,0.086680304,0.209147968,0.713188256,0.53783984,0.553228704,0.050841392,0.341078976,0.398004672,0.422869968,0.604335856,0.196956576,0.297411008,0.33706624,0.189017344,0.311098656,0.766181104,0.724133552,0.590943728,0.395171088,0.334140928,0.794891344,0.736876608,0.582323392,0.349458336,0.068806464,0.381351648,0.118188976,0.195087616,0.225014512,0.391770384,0.233544496,0.511061616,0.094413808,0.500175664,0.325340096,0.048598768,0.07177536,0.19491376,0.150592576,0.149206576,0.449166512,0.306159776,0.108198912,0.658632816,0.387299168,0.050282832,0.095337168,0.295035712,0.0752284,0.200473024,0.056612832,0.072789056,0.519700464,0.184983824,0.286062192,0.058814448,0.303045232,0.397919248,0.068315392,0.13752816,0.083506064 +533.0,0.490025392,0.116633792,0.04035608,0.197193392,0.058685728,0.102330624,0.047802208,0.05450288,0.049487584,0.173493152,0.045264832,0.077276288,0.085164496,0.393371056,0.319491312,0.1019736,0.086023504,0.171298128,0.226525312,0.194252704,0.410520912,0.305908048,0.710905184,0.616129728,0.286743936,0.600007248,0.409122864,0.11789576,0.614600416,0.278768352,0.66813304,0.433224608,0.70160768,0.300514112,0.1203296,0.528377536,0.17668472,0.65649168,0.085999856,0.206670512,0.712018016,0.538689392,0.551828928,0.050814496,0.34018664,0.397651504,0.420480416,0.60524144,0.195905488,0.295218256,0.334185696,0.185279616,0.306319744,0.765565392,0.721812176,0.586283648,0.39110696,0.330668944,0.792007216,0.735129952,0.578178128,0.347854272,0.067794288,0.375597088,0.117290992,0.190573984,0.220081216,0.38625408,0.230129344,0.504964704,0.09325744,0.498312688,0.320768368,0.048290608,0.070964688,0.1916764,0.148570304,0.147210496,0.445817616,0.303695824,0.107442896,0.657306704,0.386046736,0.049571216,0.094672256,0.293137456,0.074410848,0.198668128,0.056126704,0.072159792,0.51863952,0.183447568,0.285210256,0.058510864,0.301560992,0.397274608,0.066921264,0.137313984,0.083024016 +534.0,0.490318016,0.116855648,0.04035888,0.201311776,0.059387616,0.103082096,0.047774208,0.054479824,0.049107008,0.175152352,0.045970992,0.079567184,0.084664576,0.393998368,0.318474176,0.102451024,0.087015088,0.171281504,0.227714816,0.193253184,0.42084656,0.310879008,0.714714832,0.625107712,0.297291344,0.607038944,0.40985544,0.117935184,0.619196768,0.278828624,0.670968,0.438688672,0.703252432,0.304341552,0.122063632,0.528416592,0.179265792,0.656935376,0.085308928,0.204145216,0.710843936,0.538928624,0.550263232,0.05078768,0.339147184,0.397257376,0.418112704,0.606076304,0.1948168,0.292907584,0.331167872,0.181501408,0.301436512,0.76490912,0.71939952,0.581515568,0.386932032,0.32714584,0.789011648,0.733369776,0.573953344,0.346200768,0.066810832,0.369823408,0.116403168,0.186124192,0.21521984,0.380726016,0.226702032,0.498884672,0.092126592,0.496455952,0.31618296,0.047969168,0.070200896,0.18844816,0.146587872,0.145223616,0.44252112,0.301320992,0.10680808,0.656044032,0.384871264,0.04885696,0.094102384,0.29122008,0.073632976,0.197116832,0.055675056,0.071611008,0.517640576,0.181937632,0.28440456,0.05823952,0.300147072,0.396719248,0.065522016,0.137064768,0.082613248 +535.0,0.49068,0.1171,0.04046,0.20558,0.06008,0.10388,0.04775,0.05446,0.04872,0.17689,0.04679,0.08203,0.08414,0.39457,0.31756,0.10293,0.08811,0.17132,0.22905,0.19234,0.43126,0.31594,0.71856,0.6341,0.3075,0.614,0.41045,0.11799,0.62365,0.27889,0.67373,0.44402,0.70489,0.3078,0.12372,0.52848,0.18168,0.65739,0.08461,0.20158,0.70967,0.53861,0.54854,0.05076,0.33797,0.39682,0.41577,0.60683,0.19369,0.29047,0.328,0.1777,0.29646,0.76421,0.71689,0.57664,0.38264,0.32357,0.78591,0.73159,0.56965,0.34451,0.06586,0.36403,0.11552,0.18174,0.21043,0.3752,0.22327,0.49283,0.091,0.49461,0.31157,0.04764,0.06947,0.18521,0.14464,0.14323,0.43928,0.29903,0.10618,0.65484,0.38378,0.04814,0.09359,0.28927,0.07288,0.1958,0.05526,0.07114,0.51669,0.18045,0.28365,0.058,0.2988,0.39625,0.06414,0.13679,0.08227 +536.0,0.491115488,0.117368128,0.04065888,0.209993504,0.060761712,0.104725008,0.047729856,0.054443552,0.048326544,0.1787072,0.0477328,0.08465576,0.083593328,0.395083872,0.316756576,0.103410976,0.089311824,0.171416992,0.23056528,0.191517696,0.441741536,0.3210904,0.722432672,0.643092352,0.317335584,0.6208848,0.41091776,0.11805816,0.627959088,0.278959952,0.67642464,0.449209664,0.706519792,0.310881504,0.125290688,0.528566432,0.183919936,0.657852976,0.083906096,0.198989008,0.708498464,0.537762272,0.546673376,0.050731584,0.336665056,0.396341088,0.413453856,0.607500224,0.192527584,0.287909344,0.324684864,0.17389448,0.291402656,0.763465952,0.71428392,0.5716592,0.378232672,0.319942272,0.782703776,0.729792048,0.565282496,0.342780384,0.064943792,0.3582212,0.114637472,0.177424704,0.205713856,0.369690048,0.21984456,0.48680768,0.089869248,0.492777904,0.30692928,0.047304448,0.06876544,0.181951136,0.14272688,0.141223776,0.436098448,0.29682272,0.10556496,0.653697024,0.382774272,0.047422,0.093140592,0.287283312,0.072147024,0.194716992,0.054883904,0.070745632,0.515786688,0.17898616,0.28294512,0.057792112,0.297517904,0.395864992,0.06279504,0.136491584,0.081993312 +537.0,0.491629632,0.117662192,0.04096024,0.214547632,0.061432768,0.105617744,0.047713968,0.05443056,0.047926864,0.180606592,0.048811472,0.087441488,0.083027376,0.395539136,0.316069072,0.10389416,0.090623104,0.171573888,0.232294592,0.190791104,0.452271472,0.326328528,0.726323104,0.652069728,0.326770576,0.627688768,0.411261264,0.11814984,0.632123856,0.279041712,0.6790564,0.454249248,0.70814008,0.313587152,0.12677,0.528674256,0.1859788,0.6583216,0.083199536,0.196383392,0.707331776,0.536414192,0.544675008,0.050702576,0.33524136,0.395821744,0.411165456,0.6080836,0.191331408,0.285229616,0.321226496,0.170099216,0.286276224,0.762674432,0.711581616,0.566576208,0.37371296,0.316263664,0.779394176,0.727977072,0.560862448,0.341013472,0.064064128,0.352401008,0.113753632,0.173181024,0.201073136,0.36420712,0.216434464,0.480823504,0.08872696,0.490962128,0.302261008,0.046964448,0.068081168,0.17866232,0.140848224,0.139200496,0.432979856,0.294698704,0.104949296,0.652617344,0.381854096,0.046704336,0.092742976,0.285258976,0.071429248,0.193860128,0.054549104,0.070425072,0.51492968,0.177547248,0.282288736,0.057615504,0.296298592,0.395562688,0.061511344,0.136174784,0.081780896 +538.0,0.492237136,0.117982256,0.04131072,0.21922976,0.062090144,0.1065608,0.04770312,0.054420848,0.047519984,0.182581984,0.050041344,0.090372256,0.082439264,0.39593992,0.315503488,0.104378944,0.092053024,0.171799824,0.234289824,0.190166592,0.462828768,0.331655296,0.730206576,0.661020704,0.335803648,0.634419216,0.411553968,0.11825672,0.636134704,0.279152512,0.68162528,0.459122592,0.709743968,0.31594416,0.128137952,0.52878272,0.187941984,0.658775664,0.082493856,0.193773616,0.706173728,0.534618032,0.54255616,0.050671888,0.333715984,0.39526016,0.408908016,0.608570496,0.190101632,0.282422208,0.317610208,0.166336432,0.281092512,0.761833872,0.708777792,0.561390816,0.369073648,0.312532176,0.775986416,0.726139616,0.55639312,0.3392176,0.063225344,0.346569536,0.112860432,0.169011104,0.196507696,0.358767952,0.213050128,0.474887248,0.087551152,0.489167312,0.297551216,0.046624928,0.067402816,0.175322784,0.138996928,0.137143216,0.429928064,0.292652768,0.104326832,0.651595824,0.38102816,0.045987712,0.09241912,0.28318096,0.070711792,0.193217664,0.054257424,0.070177632,0.514101072,0.176134816,0.281685312,0.057469856,0.29513936,0.395339104,0.060306368,0.135845824,0.08163 +539.0,0.49295592,0.11832776,0.04163128,0.224024448,0.06272976,0.107557456,0.047698272,0.054414096,0.047104544,0.184624256,0.051438896,0.093424304,0.081824112,0.396292064,0.315065984,0.104864448,0.093612944,0.17210648,0.236608816,0.18965088,0.473391904,0.337072544,0.734053408,0.66993504,0.34444696,0.641087504,0.411900432,0.1183548,0.639979072,0.279316592,0.68412984,0.463810976,0.711322896,0.317988368,0.129369824,0.528864224,0.189925568,0.659188208,0.081793056,0.19116984,0.70502856,0.532433872,0.540328032,0.050638,0.332109808,0.394653536,0.406685376,0.608949152,0.188837856,0.2794744,0.31381496,0.162631008,0.27586336,0.760943072,0.705865328,0.556101744,0.364304176,0.308744768,0.772486976,0.72427208,0.551874912,0.337403248,0.06243264,0.340725664,0.111947712,0.164916864,0.192016736,0.353391184,0.209702592,0.469010032,0.086315024,0.487398736,0.292781264,0.046291808,0.066713264,0.171907888,0.137163232,0.135030896,0.426947072,0.290678112,0.103708608,0.650624784,0.380308064,0.045272688,0.092209184,0.281028304,0.069976416,0.19277656,0.054010464,0.070003392,0.513276624,0.174751424,0.281141168,0.057354848,0.294037408,0.39518936,0.059195232,0.135511264,0.081537664 +540.0,0.4938,0.1187,0.04187,0.22892,0.06335,0.10861,0.0477,0.05441,0.04668,0.18673,0.05302,0.09658,0.08118,0.3966,0.31476,0.10535,0.09531,0.1725,0.2393,0.18925,0.48394,0.34258,0.73784,0.6788,0.35271,0.6477,0.41237,0.11843,0.64365,0.27955,0.68657,0.4683,0.71287,0.31975,0.13045,0.5289,0.192,0.65954,0.0811,0.18858,0.7039,0.52991,0.538,0.0506,0.33044,0.394,0.4045,0.60921,0.18754,0.27638,0.30983,0.159,0.2706,0.76,0.70284,0.55071,0.3594,0.3049,0.7689,0.72237,0.54731,0.33558,0.06169,0.33487,0.11101,0.1609,0.1876,0.34809,0.2064,0.4632,0.085,0.48566,0.28794,0.04597,0.066,0.1684,0.13534,0.13285,0.42404,0.28877,0.1031,0.6497,0.3797,0.04456,0.09213,0.27879,0.06921,0.19252,0.05381,0.0699,0.51244,0.1734,0.28066,0.05727,0.29299,0.39511,0.0582,0.13518,0.0815 +541.0,0.494775984,0.119103264,0.042030528,0.233910736,0.063953216,0.109718976,0.047708384,0.054408448,0.046247232,0.1889048,0.054798224,0.099841968,0.080509984,0.396865408,0.314584992,0.105835488,0.097144176,0.172978048,0.242392112,0.188968592,0.494454496,0.348174592,0.741554864,0.687599488,0.360583744,0.654253888,0.412962528,0.118491808,0.647149488,0.279851088,0.688948528,0.472582768,0.714382464,0.321244352,0.131377392,0.528889504,0.1941584,0.65982904,0.080416016,0.186010272,0.70279064,0.52707432,0.535579552,0.050558,0.328708224,0.39329976,0.402352224,0.609348432,0.186209008,0.273144352,0.305662512,0.155449872,0.265312784,0.759001648,0.699702816,0.54522008,0.354366512,0.300999392,0.765226496,0.720434544,0.542705696,0.333754432,0.060999296,0.329006368,0.11004912,0.156962208,0.183258576,0.34287032,0.203147152,0.457461024,0.083601536,0.48395232,0.283029232,0.045662272,0.065258464,0.16479376,0.13352624,0.130599376,0.421208624,0.28692752,0.102475264,0.64882304,0.379201968,0.043850768,0.092168256,0.276470784,0.068408592,0.192429456,0.053657904,0.069862176,0.511591472,0.17208256,0.280241024,0.05721464,0.291994928,0.395100064,0.057351184,0.134863376,0.081512624 +542.0,0.495891616,0.119541856,0.04210872,0.23898912,0.064541504,0.1108852,0.04772368,0.054409328,0.045807104,0.191152864,0.056786944,0.103215136,0.079816144,0.39709096,0.314539888,0.106320784,0.099115984,0.173539504,0.245912624,0.188811152,0.504917808,0.353854096,0.745185376,0.696318464,0.368060048,0.660748016,0.413687968,0.11854256,0.650478224,0.280218752,0.69126768,0.476651632,0.715857488,0.32248888,0.132148832,0.5288316,0.196408144,0.660053184,0.079742816,0.183467376,0.701703088,0.523957872,0.5330744,0.050511888,0.326909664,0.3925528,0.400242656,0.609359616,0.184845792,0.269771568,0.301317648,0.151989072,0.260011952,0.757945472,0.696454352,0.539635936,0.349207808,0.297044256,0.761468656,0.718466176,0.53806888,0.33193376,0.060362784,0.323138256,0.109066032,0.153105184,0.178993456,0.337739632,0.199949728,0.451797888,0.082113472,0.482277312,0.278049136,0.045371648,0.064483216,0.161083024,0.131720768,0.128276336,0.418454624,0.285149168,0.101804992,0.647994064,0.37881376,0.043146112,0.09233032,0.27407328,0.067567232,0.192487664,0.053555664,0.069885552,0.510730832,0.170800976,0.279884352,0.057188096,0.29105032,0.395158304,0.056676608,0.134572784,0.08157152 +543.0,0.497151168,0.120022208,0.042112032,0.244155744,0.065120352,0.112108224,0.047744976,0.054412048,0.045361136,0.193488448,0.059003184,0.106675824,0.079105344,0.397277152,0.314620304,0.10680536,0.101220992,0.17417304,0.249894176,0.188782512,0.51530728,0.35961032,0.748721328,0.70493488,0.375168512,0.667175504,0.414533248,0.118587712,0.65364624,0.280654736,0.693530352,0.480503856,0.717290272,0.323507808,0.132776352,0.528724656,0.198686288,0.660205248,0.079079136,0.18094888,0.700640256,0.520575824,0.530486528,0.050462576,0.325076704,0.39175888,0.398169488,0.60923744,0.183450176,0.266272784,0.296812544,0.148606912,0.25470696,0.756825936,0.693097728,0.533965872,0.343936864,0.29303704,0.757621696,0.716468688,0.533402544,0.330127568,0.059780992,0.317270544,0.108069664,0.14932928,0.174805056,0.332691344,0.196804304,0.446208512,0.080540128,0.480632864,0.2730092,0.045101024,0.063674368,0.157268448,0.129920096,0.125889136,0.415778624,0.283435536,0.10112648,0.647219408,0.378523712,0.042447056,0.092533664,0.271616816,0.066686192,0.192657312,0.053506304,0.069958128,0.509856432,0.169562352,0.279586,0.057189312,0.290152432,0.395285104,0.056225792,0.134326192,0.081667856 +544.0,0.49855632,0.12055232,0.042060384,0.249415648,0.06569752,0.113386768,0.047770752,0.054415808,0.044911408,0.195931872,0.061465344,0.110190192,0.078387344,0.397423264,0.31481936,0.107288576,0.10345128,0.174861216,0.254368288,0.188887392,0.525598432,0.365431904,0.75215536,0.713422976,0.381954816,0.673525632,0.415465568,0.118635824,0.656669296,0.28115944,0.695740064,0.48414016,0.718675696,0.324326976,0.133281312,0.528569632,0.200886592,0.660278352,0.078422096,0.178447664,0.699605024,0.516933056,0.527814816,0.050411584,0.323255584,0.39091792,0.39612944,0.608975904,0.1820216,0.26266416,0.29217264,0.145282032,0.249406688,0.755636,0.689638064,0.528220768,0.33857232,0.288981184,0.753677216,0.71444824,0.528708448,0.328346336,0.05925336,0.311409232,0.107073856,0.145634176,0.170693696,0.327711136,0.19370264,0.440686976,0.078892864,0.479014736,0.267925184,0.04485296,0.06283584,0.153355872,0.128120544,0.123453056,0.413180464,0.281788704,0.100503968,0.646508992,0.378313664,0.04175464,0.092652848,0.269130992,0.065769552,0.1928912,0.053513504,0.070063904,0.508968512,0.168376208,0.279339488,0.057217008,0.289296784,0.395481984,0.056059616,0.13414528,0.081790432 +545.0,0.50011,0.12114,0.04197,0.25477,0.06628,0.11472,0.0478,0.05442,0.04446,0.1985,0.06419,0.11374,0.07767,0.39753,0.31513,0.10777,0.1058,0.17559,0.25936,0.18913,0.53577,0.37131,0.75548,0.72176,0.38845,0.67979,0.41646,0.11869,0.65956,0.28173,0.6979,0.48756,0.72001,0.32497,0.13368,0.52837,0.20293,0.66027,0.07777,0.17596,0.6986,0.51304,0.52506,0.05036,0.32147,0.39003,0.39412,0.60857,0.18056,0.25896,0.28742,0.142,0.24412,0.75437,0.68608,0.52241,0.33313,0.28488,0.74963,0.71241,0.52399,0.3266,0.05878,0.30556,0.10609,0.14202,0.16666,0.32279,0.19064,0.43523,0.07718,0.47742,0.26281,0.04463,0.06197,0.14935,0.12632,0.12098,0.41066,0.28021,0.09997,0.64587,0.37817,0.04107,0.09261,0.26664,0.06482,0.19315,0.05358,0.07019,0.50807,0.16725,0.27914,0.05727,0.28848,0.39575,0.05623,0.13405,0.08193 +546.0,0.50181872,0.121792448,0.041836176,0.260211776,0.066872608,0.116108464,0.047833056,0.05442472,0.04400872,0.201199552,0.067188,0.117331632,0.076955392,0.39760208,0.315544768,0.108249552,0.108264016,0.176355488,0.264874816,0.189513312,0.545810192,0.377242976,0.758687248,0.72993232,0.394655008,0.685966944,0.417522544,0.118747536,0.662321264,0.282365664,0.700012384,0.490759104,0.72129336,0.325454144,0.133973296,0.528128976,0.20481888,0.660182848,0.07712464,0.17349208,0.697627104,0.5089236,0.522228544,0.05030768,0.319717696,0.389095808,0.392141216,0.608017472,0.179066736,0.255169008,0.282566848,0.138766992,0.238855584,0.75302656,0.682426784,0.516538544,0.32761728,0.28073624,0.74548464,0.710356112,0.519255744,0.324897088,0.05836272,0.29972768,0.105121952,0.138488256,0.162705408,0.317934432,0.18762176,0.429842272,0.075400448,0.475849632,0.257667968,0.044434432,0.061074656,0.145252032,0.1245188,0.118471792,0.408217456,0.278698352,0.099507168,0.645301504,0.378092544,0.040394592,0.092415552,0.264151936,0.063836,0.193417648,0.053705968,0.070332704,0.507164032,0.16618528,0.278987792,0.05734736,0.287701824,0.396089056,0.056762048,0.134055232,0.082083264 +547.0,0.503687968,0.122518368,0.041652672,0.265735744,0.067481632,0.117552544,0.047870256,0.054430288,0.043559776,0.204038528,0.070468304,0.120965184,0.076245584,0.397645072,0.316053024,0.10872712,0.110838432,0.17715248,0.270905136,0.190039552,0.55571064,0.3832296,0.761772128,0.73792736,0.400577552,0.692054144,0.418657008,0.118810192,0.66495696,0.283070096,0.702079632,0.493735136,0.722527872,0.325794928,0.134163952,0.527849616,0.206552448,0.660019808,0.076487936,0.17105032,0.696687856,0.504608304,0.519326688,0.050254496,0.318014144,0.38811664,0.390193008,0.60731776,0.177543536,0.251302544,0.277629584,0.135588672,0.23362128,0.751605136,0.678683248,0.510611872,0.322043264,0.27655344,0.741247376,0.708289728,0.514515904,0.323246448,0.058002912,0.293917984,0.104174864,0.13504048,0.158831696,0.313150784,0.184653424,0.424528672,0.073555808,0.474304384,0.25250576,0.044267904,0.060149488,0.141067248,0.122717616,0.115932656,0.405852464,0.277252976,0.09911848,0.644802048,0.378081312,0.039730096,0.092059664,0.261677616,0.062818032,0.193680032,0.053890944,0.070488928,0.506252992,0.165183072,0.2788832,0.057448032,0.286962912,0.396499824,0.057678432,0.134177312,0.082247696 +548.0,0.505722016,0.123324128,0.041456928,0.271334432,0.068112336,0.119051504,0.047910976,0.054435616,0.043115392,0.207032064,0.074049888,0.124673056,0.075548576,0.397659344,0.31665064,0.109202848,0.113517168,0.177968432,0.277489296,0.190713072,0.565447008,0.389261264,0.764724528,0.74572112,0.406214256,0.698044304,0.419826032,0.118855488,0.667479216,0.283812208,0.70410464,0.496485488,0.723708144,0.326017072,0.134266768,0.527551136,0.208055056,0.659794128,0.075858192,0.16863128,0.695785008,0.500107328,0.516355072,0.050201392,0.316281952,0.387091712,0.38827248,0.606464608,0.175990096,0.24737232,0.27262552,0.132451472,0.228427056,0.750098912,0.674852352,0.50463864,0.316422048,0.27233448,0.736910832,0.706215104,0.509771824,0.321657248,0.057701744,0.288135488,0.103259216,0.131676704,0.155039344,0.308431056,0.181730928,0.419285632,0.071652288,0.472781616,0.247334032,0.044134016,0.0591948,0.136796464,0.120918512,0.113372,0.403564832,0.2758752,0.098725792,0.644379152,0.37812288,0.03907736,0.091593536,0.259238256,0.061766864,0.193896576,0.05413776,0.070645552,0.505356272,0.164250784,0.278821168,0.057571024,0.28625936,0.396982112,0.059033376,0.134434512,0.082413088 +549.0,0.507924784,0.124215328,0.041304224,0.27699848,0.0687696,0.120604224,0.047954336,0.054439104,0.042677888,0.2101976,0.077955152,0.128505808,0.074874368,0.397643616,0.317335616,0.109677056,0.116293584,0.178788384,0.284680976,0.191538832,0.574989696,0.395327008,0.767532688,0.75328576,0.41155344,0.703928544,0.420976096,0.118849344,0.669902992,0.28454536,0.706090448,0.49900744,0.724826336,0.326148256,0.134300624,0.527260736,0.209226144,0.659525168,0.075232528,0.16622832,0.69492168,0.495430192,0.513312416,0.050149648,0.31439888,0.386019504,0.386375712,0.605449936,0.174405456,0.243390176,0.267572176,0.129335472,0.223283632,0.748498928,0.670936416,0.498628528,0.310769392,0.26808208,0.732463008,0.70413688,0.505021824,0.320138688,0.057460416,0.282384352,0.102387328,0.128396448,0.151328432,0.303762608,0.178847152,0.414106752,0.069697728,0.471277568,0.242164784,0.044037088,0.058211072,0.13243904,0.119124768,0.110800944,0.40135432,0.274567104,0.098208864,0.644043296,0.378199408,0.038436944,0.091106848,0.256858496,0.060683376,0.194018,0.054450256,0.070786176,0.504501552,0.163397856,0.278794816,0.057715376,0.285585808,0.39753536,0.0608916,0.134845712,0.08256664 +550.0,0.5103,0.1252,0.04123,0.28272,0.06946,0.12221,0.048,0.05444,0.04225,0.21355,0.0822,0.1325,0.07423,0.3976,0.3181,0.11015,0.11916,0.1796,0.2925,0.19252,0.58432,0.40142,0.77019,0.7606,0.41659,0.7097,0.42207,0.11877,0.67224,0.28524,0.70804,0.5013,0.72588,0.32621,0.13428,0.527,0.21,0.65923,0.07461,0.16384,0.6941,0.49059,0.5102,0.0501,0.31229,0.3849,0.3845,0.60427,0.17279,0.23937,0.26249,0.12623,0.2182,0.7468,0.66694,0.49259,0.3051,0.2638,0.7279,0.70206,0.50027,0.3187,0.05728,0.27667,0.10157,0.1252,0.1477,0.29914,0.176,0.40899,0.0677,0.46979,0.23701,0.04398,0.0572,0.128,0.11734,0.10823,0.39922,0.27333,0.09749,0.6438,0.3783,0.03781,0.09066,0.25456,0.05957,0.19401,0.05483,0.0709,0.50371,0.16263,0.2788,0.05788,0.28494,0.39816,0.0633,0.13543,0.0827 +551.0,0.512851088,0.12628928,0.04123328,0.288493136,0.070191856,0.123868848,0.048048544,0.054438896,0.041834624,0.217100672,0.086788768,0.136656896,0.073617552,0.397536032,0.318929136,0.110621808,0.122108208,0.180396912,0.300914896,0.193657072,0.59343568,0.407539584,0.772697088,0.767654032,0.4213372,0.71535576,0.4231044,0.118632736,0.674495536,0.285899712,0.70995576,0.503364576,0.72687408,0.326214,0.134210512,0.526773216,0.210373456,0.658913344,0.073992688,0.161473088,0.693320448,0.485606608,0.507023584,0.050052304,0.309979552,0.383735312,0.38264496,0.602927056,0.171146128,0.235326704,0.257400864,0.123139968,0.21318232,0.745003008,0.662870512,0.48652896,0.299425344,0.259492928,0.723230944,0.699989232,0.495528656,0.317349328,0.057161232,0.270999296,0.100813888,0.1220888,0.144156304,0.29456944,0.173195296,0.4039404,0.065665744,0.468319344,0.231879872,0.043963168,0.05616464,0.123492032,0.115566224,0.105667088,0.397160048,0.27216368,0.096581312,0.643646656,0.378424928,0.037198496,0.0902388,0.252356736,0.058430656,0.1938648,0.055275088,0.070985872,0.50298496,0.161946672,0.278837056,0.058063744,0.284324304,0.398857616,0.066272304,0.136205584,0.082812624 +552.0,0.515580976,0.127493568,0.041321888,0.294310032,0.070972736,0.125580544,0.048100496,0.054436096,0.041434432,0.220863424,0.091726128,0.140981056,0.073040096,0.397458624,0.31981136,0.111092768,0.125130048,0.181172672,0.309901936,0.194950752,0.602331568,0.413683504,0.775053648,0.77443704,0.425808816,0.720892544,0.424070832,0.118461168,0.676675776,0.286522048,0.71184,0.505202768,0.727811504,0.326173072,0.134099088,0.526583696,0.210334176,0.658577648,0.073381952,0.15913248,0.692583488,0.480497888,0.503788032,0.050006592,0.307480352,0.382526992,0.38080984,0.601421968,0.169475856,0.23127392,0.2523248,0.120067152,0.208236896,0.743107792,0.658734752,0.48045144,0.293756928,0.25516504,0.718462752,0.697929264,0.490807744,0.316093728,0.057104704,0.265378528,0.100125536,0.119063904,0.140699184,0.290054576,0.170437088,0.398961392,0.063602288,0.466865536,0.226784432,0.043987136,0.05510816,0.118926944,0.113804912,0.10312032,0.395172512,0.27106824,0.095483152,0.643582032,0.378572,0.03660416,0.089835776,0.250262656,0.057269024,0.193572736,0.05578408,0.071041632,0.502329712,0.161347984,0.278905328,0.058265584,0.28374024,0.399629312,0.069823056,0.137190272,0.082903328 +553.0,0.518493344,0.128830016,0.041476256,0.300169568,0.071816656,0.12734568,0.048157008,0.054433536,0.04105456,0.224842176,0.097011808,0.145492336,0.07249584,0.397380016,0.320713424,0.111562848,0.128212608,0.181918832,0.319372656,0.196398592,0.611024336,0.419858944,0.777270448,0.780945168,0.430001952,0.726308048,0.424967424,0.11822504,0.678784896,0.287119744,0.71369624,0.50681896,0.728709408,0.326090304,0.133950224,0.526454896,0.209909616,0.658253232,0.072783136,0.156833392,0.691888608,0.475286928,0.50050192,0.04996192,0.304814432,0.381280352,0.37899496,0.5997664,0.167783984,0.227237056,0.247298816,0.117028336,0.203367872,0.741120736,0.654545632,0.4743636,0.288109552,0.250824992,0.71361624,0.695887296,0.486131952,0.314945888,0.057111536,0.2598184,0.099515024,0.116128288,0.137333424,0.285612432,0.16773936,0.394064624,0.061519472,0.465430608,0.221739312,0.044050944,0.05403672,0.114329296,0.11206544,0.100601552,0.393254256,0.27004312,0.094205232,0.643596768,0.378752112,0.036030304,0.089478112,0.248296976,0.056094112,0.193138192,0.056351392,0.071071792,0.501762064,0.160829136,0.27900912,0.058483664,0.283195776,0.400479648,0.073957728,0.13840656,0.082975472 +554.0,0.521592032,0.130319424,0.041659984,0.306073664,0.072740896,0.129165296,0.04821968,0.054434096,0.040701328,0.229036128,0.102641248,0.150213456,0.071980064,0.397315808,0.321591168,0.112031888,0.131340528,0.182626912,0.329200256,0.197996192,0.619543344,0.426078304,0.779364688,0.787179616,0.433908608,0.731600992,0.425799536,0.117876112,0.680825296,0.28771664,0.71552848,0.508219392,0.729592592,0.325962656,0.13376616,0.526417136,0.209154496,0.657981536,0.07220384,0.154596944,0.691234528,0.469999888,0.497176128,0.049916768,0.302021152,0.380002752,0.37720144,0.597977952,0.166076912,0.223247152,0.242368032,0.11404936,0.198577888,0.73905216,0.650319392,0.46827128,0.282499136,0.246483664,0.708720608,0.693871728,0.48153392,0.313920768,0.057183008,0.254331872,0.098993472,0.113285952,0.134065344,0.281267808,0.165121792,0.389266496,0.059428416,0.46401792,0.216762592,0.044152512,0.05295824,0.109731008,0.110360688,0.098124144,0.39140136,0.26908728,0.092772992,0.643676544,0.378983744,0.035481088,0.089200128,0.246480256,0.05491776,0.192576368,0.056968944,0.071085472,0.501304096,0.160382048,0.279155632,0.058715744,0.282702592,0.401414944,0.078672,0.139879008,0.083035776 +555.0,0.52488,0.13198,0.04185,0.31202,0.07376,0.13104,0.04829,0.05444,0.04038,0.23345,0.10861,0.15516,0.07149,0.39728,0.32241,0.1125,0.1345,0.18329,0.33928,0.19974,0.62791,0.43235,0.78135,0.79314,0.43753,0.73677,0.42657,0.1174,0.6828,0.28833,0.71734,0.50941,0.73048,0.32579,0.13355,0.52649,0.20811,0.65779,0.07165,0.15244,0.69062,0.46466,0.49382,0.04987,0.29914,0.3787,0.37543,0.59607,0.16436,0.21933,0.23757,0.11115,0.19387,0.73691,0.64607,0.46218,0.27694,0.24215,0.7038,0.69189,0.47704,0.31303,0.05732,0.24893,0.09857,0.11054,0.1309,0.27704,0.1626,0.38458,0.05734,0.46263,0.21187,0.04429,0.05188,0.10516,0.1087,0.0957,0.38961,0.2682,0.09121,0.64381,0.37928,0.03496,0.08902,0.24483,0.05375,0.1919,0.05763,0.07109,0.50097,0.16,0.27935,0.05896,0.28227,0.40244,0.08396,0.14163,0.08309 +556.0,0.528357568,0.133821952,0.042048688,0.317998688,0.074880512,0.132968896,0.048368928,0.0544516,0.04009248,0.238105088,0.11491384,0.160335536,0.071028576,0.397281728,0.323163904,0.112968192,0.137682032,0.183905888,0.34957344,0.201628896,0.636121776,0.438670224,0.7832292,0.798821152,0.44087872,0.741813504,0.427272704,0.116799568,0.684714144,0.28895544,0.719131776,0.510395744,0.731372816,0.325581072,0.133307552,0.52667288,0.206776448,0.657679184,0.071122624,0.150366352,0.690043968,0.459281392,0.490438304,0.049821824,0.296164432,0.377373344,0.373680448,0.594042944,0.16263536,0.215496,0.232919712,0.108331872,0.18924832,0.734695104,0.641804736,0.456094272,0.271441504,0.23782704,0.698863232,0.689946656,0.47265768,0.31227536,0.057522128,0.2436184,0.09824736,0.107890816,0.127838528,0.272931824,0.16017696,0.380007584,0.055264224,0.461266928,0.20707032,0.044462176,0.050807168,0.100631936,0.10708464,0.093336368,0.38787696,0.267381408,0.089515344,0.643994496,0.37963792,0.034468288,0.08894104,0.243354416,0.05259528,0.191114048,0.05833176,0.071087328,0.500759728,0.159681984,0.279591328,0.059215792,0.281900144,0.403555328,0.08981104,0.14367568,0.083140864 +557.0,0.532023664,0.135854976,0.042247696,0.324001008,0.076108176,0.13495064,0.048457568,0.054469296,0.03984,0.243026976,0.121543488,0.165743616,0.07059856,0.397331216,0.323850864,0.113437888,0.140877648,0.184475152,0.360035936,0.203660832,0.644176976,0.445033984,0.785006288,0.804221088,0.443961552,0.746731088,0.427904304,0.11603272,0.686572096,0.289588144,0.72090392,0.5111832,0.732270688,0.325342624,0.133043584,0.526966096,0.205162256,0.657652912,0.070622496,0.148378912,0.689504608,0.453876288,0.48703584,0.04977264,0.293062512,0.376023792,0.37195312,0.5918964,0.160905024,0.211753216,0.228428416,0.105596576,0.184715712,0.732408816,0.637530912,0.4500176,0.266011312,0.233516912,0.69391992,0.688045936,0.468392672,0.311655488,0.057788416,0.23840224,0.098025584,0.105338368,0.124881504,0.268945552,0.15785472,0.375550944,0.053212032,0.459928928,0.202371152,0.044666784,0.04974568,0.096163856,0.10551624,0.091039392,0.386198576,0.26663152,0.087684752,0.644226608,0.380054032,0.034006784,0.088979632,0.242057696,0.051458032,0.190231632,0.059070752,0.071081712,0.500673584,0.159427136,0.27987864,0.059482704,0.281595296,0.404761088,0.096199728,0.14603104,0.083193232 +558.0,0.53588264,0.13809824,0.042463744,0.330013168,0.07745792,0.136986704,0.048557648,0.054495072,0.03962888,0.248216064,0.128499776,0.171381056,0.070197664,0.397441504,0.324432544,0.113908624,0.144072704,0.184988096,0.370568752,0.205833408,0.652096336,0.451451424,0.786693936,0.809336304,0.446818064,0.751520032,0.428467584,0.115298672,0.688377168,0.290249648,0.722660864,0.511776816,0.73319448,0.325076256,0.132762016,0.527364272,0.203301024,0.65770512,0.070155648,0.146496032,0.689001248,0.448470464,0.483621856,0.049720736,0.289991952,0.3746572,0.370247632,0.589645136,0.159174688,0.208129072,0.22413712,0.10296384,0.180276864,0.730058448,0.633262208,0.443956608,0.26066576,0.229229664,0.688993728,0.686195616,0.464273104,0.311184896,0.058120464,0.23329248,0.097917248,0.10288624,0.1220348,0.26510096,0.15565072,0.371224464,0.05119368,0.458618288,0.197789184,0.044903232,0.048702432,0.091782816,0.10399872,0.088822656,0.384570832,0.265949952,0.08578288,0.64449608,0.380541824,0.03357984,0.089073744,0.240961616,0.050348624,0.189258096,0.059841104,0.071078176,0.50070656,0.159225328,0.280216832,0.059758816,0.281364768,0.406061888,0.103135216,0.14871904,0.08325104 +559.0,0.539940656,0.140574144,0.042726752,0.336017968,0.078947664,0.139079568,0.048671168,0.054531408,0.0394672,0.253664352,0.135786944,0.177239296,0.069821968,0.397626592,0.324858544,0.11437928,0.14725128,0.1854316,0.381055088,0.208144144,0.659908096,0.457937824,0.788307744,0.8141628,0.449504176,0.756176816,0.428967824,0.114905184,0.69013224,0.290970912,0.724408528,0.512180352,0.734172192,0.324781808,0.132466448,0.527856128,0.201234832,0.657821408,0.06972984,0.144741312,0.688533568,0.44309432,0.480207072,0.049663632,0.287189152,0.373281008,0.368563264,0.587309072,0.157451312,0.204657328,0.220096704,0.100459424,0.175937136,0.72765328,0.629014384,0.437918976,0.255424128,0.224978016,0.684113056,0.684404656,0.460334576,0.310883344,0.058520752,0.22830192,0.097939232,0.100539232,0.119306096,0.261423648,0.15358768,0.367046864,0.049219248,0.457337968,0.193344096,0.04517152,0.047684704,0.087519296,0.10253592,0.08670232,0.382989488,0.265336224,0.083903648,0.644790432,0.381120416,0.033193056,0.089124016,0.240093856,0.049279456,0.18819632,0.060636176,0.071082,0.500848736,0.1590628,0.280612704,0.060041728,0.28122024,0.407463728,0.110638224,0.1517652,0.083317968 +560.0,0.5442,0.1433,0.04305,0.342,0.08059,0.14123,0.0488,0.05458,0.03936,0.25938,0.1434,0.18331,0.06947,0.3979,0.3251,0.11485,0.1504,0.1858,0.3914,0.21059,0.66763,0.4645,0.78986,0.8187,0.45206,0.7607,0.42941,0.11503,0.69184,0.29177,0.72615,0.5124,0.73522,0.32446,0.13216,0.52843,0.199,0.65799,0.06935,0.14313,0.6881,0.43777,0.4768,0.0496,0.28479,0.3719,0.3669,0.5849,0.15574,0.20136,0.21634,0.0981,0.1717,0.7252,0.6248,0.43191,0.2503,0.22077,0.6793,0.68268,0.4566,0.31076,0.05899,0.22344,0.0981,0.0983,0.1167,0.25793,0.15168,0.36303,0.0473,0.45609,0.18905,0.04547,0.0467,0.0834,0.10113,0.08469,0.38145,0.26479,0.08211,0.6451,0.3818,0.03285,0.08907,0.23947,0.04826,0.18706,0.06145,0.0711,0.50109,0.15893,0.28107,0.06033,0.28117,0.40897,0.1187,0.15519,0.0834 +561.0,0.548656624,0.146283792,0.043429488,0.347950544,0.082387936,0.143435824,0.048945888,0.05464152,0.039307328,0.265393184,0.151320352,0.189589456,0.06914552,0.398272592,0.325164528,0.115322864,0.153510256,0.186099296,0.401552544,0.213167968,0.675261456,0.471131168,0.791356176,0.822951664,0.45449264,0.76509112,0.429797984,0.115642592,0.693503424,0.292642656,0.72788416,0.512445296,0.736335008,0.324114112,0.131845488,0.529082032,0.196617696,0.658212016,0.069016416,0.141663584,0.687697456,0.432506432,0.473405072,0.0495304,0.282774624,0.370514528,0.365258992,0.582416624,0.154042656,0.1982404,0.212871056,0.095886592,0.167566224,0.722700208,0.62062568,0.425931424,0.245297584,0.21660616,0.674564848,0.681024944,0.453071392,0.310807616,0.059526064,0.218710416,0.098394528,0.0961676,0.114215936,0.25462096,0.149928512,0.35917424,0.045448208,0.454874784,0.184912032,0.045794832,0.045755392,0.07944376,0.099781872,0.082789904,0.37994832,0.264311056,0.080411984,0.645420496,0.382575968,0.032551056,0.088918496,0.23908648,0.047295408,0.185875648,0.06227848,0.07114032,0.501426848,0.158825408,0.281587632,0.060623712,0.28121672,0.410580128,0.127270608,0.159004496,0.083506048 +562.0,0.55330696,0.14953416,0.043879744,0.353861328,0.08434488,0.145695184,0.049110928,0.054717152,0.03931,0.271726624,0.159530976,0.196071856,0.068852624,0.398754304,0.325055904,0.115799584,0.156573024,0.186334096,0.411457872,0.215875648,0.682805136,0.477827264,0.792802416,0.826921184,0.456814784,0.769351232,0.430137904,0.116790432,0.695125488,0.293589088,0.729610864,0.512325376,0.737518,0.323746816,0.131525616,0.529809552,0.194111024,0.65848832,0.068730208,0.140346112,0.687323248,0.427314784,0.470027056,0.049454976,0.281182432,0.3691256,0.363641312,0.579860496,0.152361728,0.195304832,0.20969864,0.09382272,0.163536944,0.720155888,0.616498448,0.419985568,0.24042208,0.212488384,0.669919328,0.679442976,0.449754064,0.311021536,0.060127104,0.21411736,0.098819568,0.09414152,0.111854,0.25150008,0.1483368,0.355481904,0.04367552,0.453693008,0.180936624,0.046142672,0.044857712,0.075670176,0.09849312,0.081007376,0.378480992,0.263898992,0.07883904,0.64574696,0.383446384,0.03229736,0.088652064,0.238942176,0.046392464,0.184666656,0.063117664,0.071210896,0.50185672,0.158746128,0.282165632,0.060922736,0.281364368,0.412294368,0.136308176,0.16321944,0.08364488 +563.0,0.558142256,0.153055888,0.04433024,0.359713872,0.086460224,0.148004144,0.049296128,0.054805424,0.039364032,0.278448864,0.16799712,0.202743056,0.068593728,0.399362016,0.32480536,0.116284384,0.159581072,0.186521536,0.42106808,0.218705968,0.690249216,0.4845688,0.794204096,0.830620224,0.459032128,0.773485904,0.430432864,0.118209712,0.696707152,0.29459016,0.731323648,0.512054736,0.738748672,0.3233596,0.131201344,0.530581792,0.191510112,0.658797344,0.06848776,0.13916768,0.68697096,0.422191856,0.46666904,0.049375952,0.27979848,0.367730272,0.362048912,0.577217968,0.15069704,0.192539264,0.206800144,0.091899328,0.159609344,0.717567968,0.612423136,0.414069952,0.235670656,0.208410208,0.665369888,0.677936048,0.446633296,0.311377616,0.060788704,0.209661104,0.099358288,0.09221832,0.109610064,0.24855672,0.146893728,0.351944688,0.041998912,0.452544112,0.177121136,0.046505872,0.044016912,0.072098272,0.097257648,0.079340448,0.377040064,0.263554288,0.077354656,0.646076544,0.3843948,0.032085904,0.088333472,0.239015952,0.04555008,0.183489104,0.063961728,0.071325312,0.502354192,0.158693168,0.282797952,0.06122856,0.281610816,0.414107568,0.145701424,0.167844224,0.083830592 +564.0,0.563150272,0.156850496,0.044671216,0.365485856,0.088729888,0.150357344,0.049502048,0.054903536,0.039462464,0.285652544,0.176673424,0.209584816,0.068371392,0.400115328,0.324462656,0.116782944,0.16252872,0.186686496,0.430344768,0.221649728,0.697572656,0.491327216,0.795565296,0.834065184,0.461143232,0.777503296,0.430685024,0.119472272,0.698248416,0.295614832,0.733012512,0.511650976,0.739994224,0.322953584,0.130872672,0.531355632,0.18884672,0.659108368,0.068282592,0.138109968,0.686632192,0.417125808,0.463332704,0.049296768,0.278274448,0.366323104,0.360484352,0.57446656,0.149046752,0.189917376,0.204134048,0.090099296,0.155778304,0.714936128,0.608402624,0.408179296,0.231035232,0.204360192,0.660918848,0.6765048,0.443681968,0.311840096,0.061504784,0.205339168,0.099985408,0.09039264,0.107477248,0.24577144,0.145579456,0.348547712,0.040437984,0.451426736,0.173457328,0.046874432,0.043244352,0.068745728,0.096065536,0.07778264,0.375615616,0.263277824,0.075886992,0.646408128,0.385395936,0.031911328,0.08806872,0.239274288,0.044763056,0.182416512,0.064804272,0.071500128,0.502883824,0.158670368,0.283475072,0.061543664,0.281950384,0.416011488,0.155300192,0.172885888,0.084080384 +565.0,0.56832,0.16092,0.04484,0.37116,0.09115,0.15275,0.04973,0.05501,0.0396,0.29341,0.18552,0.21658,0.06819,0.40103,0.32407,0.1173,0.16541,0.18685,0.43925,0.2247,0.70476,0.49808,0.79689,0.83727,0.46315,0.78141,0.4309,0.12031,0.69975,0.29664,0.73467,0.51113,0.74123,0.32253,0.13054,0.5321,0.18615,0.6594,0.06811,0.13716,0.6863,0.41211,0.46002,0.04922,0.27639,0.3649,0.35895,0.57159,0.14741,0.18742,0.20167,0.08841,0.15204,0.71226,0.60444,0.40231,0.22651,0.20033,0.65657,0.67515,0.44088,0.31238,0.06227,0.20115,0.10068,0.08866,0.10545,0.24313,0.14438,0.34528,0.03901,0.45034,0.16994,0.04724,0.04255,0.06563,0.09491,0.07633,0.3742,0.26307,0.0744,0.64674,0.38643,0.03177,0.08792,0.23969,0.04403,0.18151,0.06564,0.07175,0.50342,0.15868,0.28419,0.06187,0.28238,0.418,0.16498,0.17835,0.08441 +566.0,0.573644128,0.16526784,0.044849504,0.376729056,0.093717504,0.155178976,0.049983424,0.05512704,0.039776512,0.301732288,0.1945132,0.223725552,0.068059648,0.402110048,0.323647184,0.117837808,0.168218368,0.187021632,0.447747232,0.227856336,0.711812928,0.504822576,0.798182032,0.84024112,0.465067184,0.785208032,0.431085056,0.120766416,0.701214592,0.297667008,0.736296288,0.5105024,0.742455872,0.322090432,0.130204928,0.532811696,0.183441216,0.659670592,0.067970528,0.136320784,0.685971968,0.407153328,0.456733888,0.04914576,0.274182112,0.363460832,0.357447744,0.568590432,0.145788992,0.185049728,0.199411312,0.086832144,0.148394272,0.709538912,0.600538816,0.39646336,0.222096192,0.196320624,0.652331328,0.67387264,0.438228592,0.312988768,0.063081248,0.197094896,0.101433968,0.087018656,0.103526784,0.24063384,0.14329856,0.342142064,0.037725248,0.449284784,0.166573088,0.047599232,0.041939584,0.062767616,0.093791472,0.07498576,0.372792512,0.262929616,0.072920176,0.647068768,0.387493792,0.031663312,0.087872288,0.240254832,0.043361072,0.180793424,0.066466944,0.072084128,0.503959872,0.158720256,0.284943376,0.062208,0.2829044,0.420073776,0.174693408,0.184238016,0.084830528 +567.0,0.579113376,0.169894368,0.04468464,0.382185152,0.096425744,0.157640384,0.050266448,0.055257424,0.039991472,0.310622464,0.20362632,0.231026256,0.067994128,0.403355616,0.32322288,0.118399024,0.170948912,0.187213456,0.45581216,0.231119488,0.718732496,0.51155016,0.799443616,0.842986144,0.466909808,0.788899824,0.431243824,0.120807392,0.702644832,0.29869784,0.737891888,0.509779216,0.743671472,0.32163624,0.129868624,0.533486112,0.180738832,0.659916064,0.0678644,0.1355948,0.68564608,0.402263616,0.45347632,0.049074192,0.27163144,0.362004832,0.355979952,0.565470368,0.14418584,0.182807584,0.197358864,0.085364688,0.144840304,0.706770448,0.596700496,0.390640192,0.217793056,0.192332688,0.648208288,0.672672208,0.435726896,0.313656176,0.063934784,0.193173584,0.102236688,0.08546624,0.101705184,0.23828328,0.142338048,0.339133328,0.036592992,0.448262192,0.163359296,0.047948992,0.041417952,0.060172832,0.092709248,0.073751888,0.371394304,0.262854928,0.071451216,0.647392144,0.38858352,0.031592784,0.087937792,0.240956992,0.04276848,0.180289184,0.067284448,0.072512112,0.504499552,0.158790528,0.285736272,0.0625584,0.283528736,0.422234048,0.184392544,0.190546224,0.085353872 +568.0,0.584718704,0.174804816,0.044442096,0.387521808,0.099274064,0.160130352,0.050579952,0.055399568,0.040239632,0.3201616,0.21282288,0.2384356,0.067993648,0.404786784,0.322829936,0.11898728,0.173593456,0.18744376,0.463394608,0.234482,0.725503104,0.518240864,0.80068008,0.845518048,0.468673872,0.792491296,0.431402992,0.120579488,0.704041872,0.299707472,0.739449008,0.508976352,0.744852192,0.321168848,0.12953192,0.534110128,0.178074928,0.660133936,0.067787392,0.134969696,0.685314672,0.397435424,0.450249872,0.049007584,0.268827248,0.360528672,0.35454832,0.562213584,0.142599488,0.18067536,0.195484416,0.083997072,0.141375376,0.703956304,0.592930576,0.384837664,0.21359632,0.188358192,0.644207648,0.671551296,0.43335656,0.314354784,0.06482584,0.189385952,0.103070208,0.083998704,0.099980464,0.23606504,0.141485536,0.336244352,0.035631456,0.44727048,0.160294624,0.048280592,0.04099608,0.057865888,0.091662064,0.072626496,0.369995616,0.2628472,0.070069536,0.64770712,0.389679728,0.031554976,0.088043056,0.241772992,0.042248528,0.180059984,0.068085872,0.073047696,0.505027872,0.15889064,0.286561168,0.06292272,0.284249552,0.4244732,0.19395336,0.197284752,0.085995536 +569.0,0.590451152,0.180006064,0.044277712,0.392734704,0.102263744,0.16264504,0.050923776,0.055550512,0.040514112,0.330456896,0.2220632,0.245886384,0.068053808,0.406430352,0.322502512,0.119606416,0.17614264,0.187732864,0.470435776,0.237933792,0.732103472,0.524867168,0.801897744,0.847851632,0.470348096,0.795989488,0.43159984,0.120345664,0.705406432,0.300661664,0.740957088,0.508111408,0.745965312,0.320689696,0.129195536,0.534670544,0.175486144,0.660325008,0.067733824,0.134428192,0.684968144,0.392658912,0.447057264,0.048948896,0.265937216,0.359028192,0.353154288,0.55879768,0.141027776,0.178628336,0.193749968,0.082715616,0.137996208,0.7010996,0.589236016,0.379051776,0.209500464,0.184386256,0.640336688,0.670513584,0.431093344,0.315051392,0.065749296,0.18573192,0.103914208,0.082611408,0.098347104,0.23396128,0.140722944,0.333462816,0.03486184,0.446306848,0.157372832,0.048583472,0.040687008,0.055869104,0.0906492,0.071606544,0.368583008,0.262908752,0.068890736,0.648010416,0.390757696,0.031544848,0.088068,0.242675472,0.041792176,0.180181984,0.068862576,0.07370592,0.505533472,0.159020352,0.287407664,0.06330272,0.285060528,0.426780512,0.203226416,0.20446824,0.08677232 +570.0,0.5963,0.1855,0.04429,0.39782,0.10539,0.16518,0.0513,0.05571,0.04081,0.34157,0.23131,0.25334,0.06818,0.4083,0.32228,0.12026,0.17859,0.1881,0.4769,0.24147,0.73852,0.53141,0.8031,0.85,0.47193,0.7994,0.43186,0.12027,0.70674,0.30154,0.74241,0.5072,0.74699,0.3202,0.12886,0.53516,0.173,0.66049,0.0677,0.13396,0.6846,0.38793,0.4439,0.0489,0.26307,0.3575,0.3518,0.55521,0.13947,0.17665,0.19213,0.08151,0.1347,0.6982,0.58562,0.37328,0.2055,0.18041,0.6366,0.66956,0.42892,0.31572,0.0667,0.18221,0.10475,0.0813,0.0968,0.23196,0.14004,0.33078,0.0343,0.44537,0.15459,0.04885,0.0405,0.0542,0.08967,0.07069,0.36715,0.26304,0.06799,0.6483,0.3918,0.03156,0.08794,0.24364,0.0414,0.18071,0.06961,0.0745,0.50601,0.15918,0.28827,0.0637,0.28596,0.42915,0.2121,0.2121,0.0877 +571.0,0.602252832,0.191281216,0.044461872,0.402771808,0.108640176,0.167730336,0.051714448,0.055882304,0.041126016,0.35348688,0.240532928,0.2607996,0.06839072,0.410388608,0.322202048,0.120951152,0.180933552,0.188559904,0.482785248,0.245094576,0.744752464,0.537864688,0.804286304,0.85197248,0.473427568,0.802725776,0.43218344,0.120311264,0.708045104,0.30234424,0.743808928,0.506253344,0.747925952,0.319700576,0.12852568,0.535576752,0.170629904,0.660626432,0.06768568,0.133566656,0.684209056,0.383254544,0.440777472,0.048860944,0.260193872,0.355942272,0.35048816,0.55145416,0.13792792,0.17473872,0.19062152,0.08037664,0.131485104,0.69525232,0.582080112,0.367522592,0.201590432,0.176429744,0.632998464,0.66868744,0.426832496,0.316348704,0.06767312,0.178817168,0.10556376,0.08006112,0.095335344,0.230059696,0.139439184,0.328193792,0.03395128,0.444461104,0.151946576,0.049077744,0.040437216,0.052866896,0.0887236,0.069876944,0.365700976,0.263238448,0.067364704,0.64857552,0.392802192,0.031602128,0.087680784,0.244649936,0.041087024,0.181660848,0.070329792,0.075438912,0.506456576,0.159370768,0.289150064,0.064115776,0.286953952,0.431583552,0.220530096,0.220166128,0.08879208 +572.0,0.608297744,0.197344976,0.044800416,0.407584208,0.112003344,0.170291472,0.052172752,0.056071328,0.041460192,0.36620384,0.24970184,0.26825096,0.068700288,0.412692064,0.322303856,0.12168312,0.183170896,0.18912656,0.488085008,0.24881088,0.750797984,0.544224064,0.80545688,0.853778848,0.474839952,0.805970176,0.432571152,0.120481248,0.709323872,0.303070672,0.745153728,0.505282672,0.748769392,0.319192128,0.12819288,0.535917568,0.168391568,0.660732656,0.067689952,0.133247216,0.683793392,0.378636144,0.437688592,0.048832064,0.257301648,0.354352832,0.34922088,0.547530944,0.136402688,0.17289008,0.189217376,0.079310912,0.128349776,0.692252384,0.578614576,0.361779424,0.19776672,0.172444752,0.629533088,0.667893376,0.42482456,0.316924144,0.06866376,0.175550592,0.106341728,0.078891344,0.093949184,0.22825688,0.138920176,0.325700912,0.033820496,0.44358072,0.149441904,0.049263712,0.04050072,0.051877168,0.087809504,0.069166976,0.364238416,0.26350224,0.067029936,0.64883648,0.393757728,0.031671936,0.087293536,0.245688272,0.040864768,0.183055104,0.071022512,0.076531136,0.506871552,0.15959392,0.290048368,0.06455136,0.288046992,0.43408152,0.22846464,0.228654512,0.090062576 +573.0,0.614416336,0.203677136,0.0452672,0.412260368,0.115452352,0.172855888,0.052683136,0.056284352,0.041812848,0.37965024,0.258779792,0.27576088,0.069150816,0.41518392,0.322660144,0.122458608,0.1853044,0.189822416,0.492839648,0.252628304,0.756664944,0.55049344,0.806604656,0.855429136,0.476205376,0.809135056,0.433029184,0.120708352,0.71058072,0.303742944,0.746451568,0.50430048,0.749533232,0.31867544,0.12786136,0.536200384,0.166283712,0.66081448,0.067714784,0.133012176,0.683355248,0.374087664,0.434632272,0.048812064,0.254404064,0.352730112,0.348004,0.543456448,0.134898016,0.17110984,0.187926032,0.078310224,0.125291888,0.689187808,0.57521448,0.356051616,0.194022128,0.1684588,0.626199632,0.667169712,0.422896704,0.317436784,0.069666,0.172403216,0.107065216,0.077786128,0.092636464,0.226555584,0.138496848,0.323302192,0.033912992,0.442732256,0.147078352,0.049408,0.040691424,0.05123888,0.086927488,0.068560368,0.362777776,0.263825552,0.066956288,0.64908512,0.394669104,0.031775664,0.086820208,0.246732928,0.040766112,0.18489176,0.071696752,0.07778792,0.507268448,0.159851472,0.290973072,0.065008064,0.289251472,0.436652128,0.235890944,0.237533136,0.091525152 +574.0,0.620586848,0.210257856,0.045789824,0.416807648,0.1189512,0.175414624,0.05325568,0.056530976,0.042185824,0.3937128,0.267727664,0.28343784,0.069799104,0.417824096,0.323363952,0.123280016,0.187339424,0.190673152,0.497117088,0.256560528,0.762368704,0.556685936,0.807718512,0.856933024,0.4775804,0.812221216,0.433562176,0.120862736,0.711821248,0.304400256,0.747714048,0.503319168,0.750240992,0.318151232,0.12753056,0.53645416,0.164294976,0.660881184,0.067763936,0.132878896,0.682899584,0.369627504,0.431606912,0.048798624,0.2515056,0.351072992,0.34684512,0.539256192,0.133419104,0.1694104,0.186766128,0.077373776,0.12230928,0.686041632,0.571866624,0.350341248,0.190349056,0.164478768,0.622990656,0.666505088,0.421054288,0.317880864,0.07067344,0.16936568,0.107713904,0.076740512,0.091391744,0.224964688,0.13819136,0.321001232,0.034232448,0.441920752,0.14486016,0.049512928,0.041008448,0.050958592,0.086077552,0.06805792,0.361342176,0.264200304,0.06708504,0.64932528,0.3955448,0.031922672,0.08633168,0.247760464,0.040835856,0.187153936,0.072365792,0.079221024,0.507669024,0.160145984,0.291936976,0.065487168,0.290584432,0.439308336,0.242824608,0.24675776,0.093193088 +575.0,0.62679,0.21707,0.04632,0.42123,0.12247,0.17796,0.0539,0.05682,0.04258,0.4083,0.27651,0.29135,0.07069,0.42058,0.32449,0.12415,0.18928,0.1917,0.50097,0.26062,0.76792,0.56281,0.80879,0.8583,0.479,0.81523,0.43417,0.12087,0.71305,0.30507,0.74895,0.50235,0.75091,0.31762,0.1272,0.5367,0.16242,0.66094,0.06784,0.13286,0.68243,0.36527,0.42861,0.04879,0.24861,0.34938,0.34575,0.53495,0.13197,0.1678,0.18575,0.0765,0.1194,0.6828,0.56856,0.34465,0.18674,0.16051,0.6199,0.66589,0.4193,0.31825,0.07168,0.16643,0.10827,0.07575,0.09021,0.22349,0.13802,0.3188,0.03478,0.44115,0.14279,0.04958,0.04145,0.05104,0.08526,0.06766,0.35995,0.26462,0.06738,0.64956,0.39639,0.03212,0.08588,0.24875,0.04111,0.18983,0.07304,0.08084,0.50809,0.16048,0.29295,0.06599,0.29206,0.44206,0.24927,0.25629,0.09508 +576.0,0.633014144,0.224104544,0.046868896,0.425524272,0.12599736,0.180487888,0.054624128,0.057157632,0.042993552,0.423385152,0.285102368,0.299483088,0.071832688,0.423441472,0.326058432,0.12507192,0.191126528,0.192910976,0.504405408,0.264814992,0.773315792,0.568860272,0.809818688,0.859538944,0.48045856,0.81816416,0.43485,0.120755248,0.714268384,0.305750528,0.750159984,0.501400672,0.75153896,0.317081776,0.126869632,0.536938624,0.160671232,0.660992,0.067942032,0.132953696,0.681946048,0.361017472,0.42563648,0.048786272,0.245730096,0.347648672,0.34471888,0.530540608,0.130551184,0.16627488,0.184871376,0.075684928,0.116562784,0.679458272,0.565290256,0.338978528,0.183188032,0.15655336,0.61692544,0.665320736,0.417628688,0.318536,0.07268056,0.16359232,0.108723072,0.074811232,0.089087264,0.222128016,0.137981328,0.316695552,0.035549216,0.440420128,0.140866096,0.049608112,0.042011424,0.051477952,0.084474976,0.067365328,0.358605248,0.265082832,0.067847232,0.649790016,0.397200096,0.03236784,0.085459984,0.249688208,0.041597792,0.19292424,0.073721216,0.082648,0.5085332,0.160855536,0.294013248,0.06651816,0.293683616,0.44490768,0.255197536,0.266109296,0.097200416 +577.0,0.639248256,0.231350496,0.04743744,0.429689328,0.129522432,0.182994448,0.055437296,0.057551232,0.043424928,0.43892912,0.293484352,0.3078388,0.073232656,0.42639544,0.328078784,0.126049168,0.19288096,0.194310096,0.507436048,0.269156224,0.778553184,0.57483256,0.810804096,0.860657936,0.481957776,0.821025936,0.435601024,0.120506672,0.71547736,0.306443984,0.751344928,0.50047656,0.752128112,0.31653632,0.12653936,0.537173024,0.159059632,0.66103872,0.068069104,0.133157696,0.681448128,0.356871744,0.422679232,0.048787424,0.242881184,0.345876512,0.3437508,0.526031808,0.129162736,0.16483224,0.184125152,0.074925264,0.113796768,0.676011808,0.56205192,0.333328096,0.179685648,0.1526108,0.614063312,0.664793232,0.416036384,0.318734144,0.07367,0.160848496,0.109065056,0.073920928,0.088019664,0.220875424,0.138073168,0.314685312,0.036527152,0.439731056,0.139086352,0.0495972,0.042684144,0.05226008,0.083722368,0.067172128,0.357312416,0.265587072,0.068472848,0.65001664,0.397971824,0.032666064,0.085066528,0.250564608,0.042306592,0.19643152,0.074411872,0.08464504,0.509001488,0.161274752,0.295128032,0.067073424,0.295461152,0.447852048,0.260591104,0.276191216,0.099568912 +578.0,0.645472048,0.238792688,0.048013344,0.433720864,0.133014464,0.185472288,0.056348304,0.058008832,0.043874384,0.454853728,0.301616416,0.316392272,0.074938064,0.429412288,0.330635616,0.127084496,0.194545072,0.195922336,0.510108688,0.273654656,0.783642576,0.580733728,0.811737824,0.861667328,0.483476992,0.823817632,0.436397888,0.120220416,0.716681856,0.3071612,0.752513232,0.499591568,0.752693344,0.315983984,0.126208368,0.537415664,0.157581712,0.66108696,0.068223856,0.133485536,0.680938928,0.352847296,0.419737424,0.048791616,0.240041952,0.344061952,0.34285272,0.521442368,0.127809328,0.1634784,0.183521888,0.07421896,0.111099472,0.672446944,0.558834944,0.327699424,0.176225344,0.14868632,0.611308704,0.664297888,0.41452424,0.318834448,0.07464224,0.158190832,0.10927624,0.073075024,0.087002464,0.219738032,0.138312768,0.312770912,0.037721328,0.439086624,0.137453248,0.049548048,0.043470544,0.053397808,0.08300488,0.067081968,0.356089744,0.266126272,0.069291264,0.650242144,0.398708832,0.033021808,0.084753072,0.251355728,0.043274992,0.20034928,0.075121328,0.08684336,0.509510096,0.161741008,0.296304416,0.067656688,0.297406208,0.450902816,0.265442112,0.286500736,0.102199248 +579.0,0.65166208,0.24641456,0.048584208,0.43761248,0.136436016,0.187912928,0.057365872,0.058538752,0.04434272,0.471067936,0.30945264,0.325096944,0.077011232,0.432456896,0.333838368,0.128180464,0.196120464,0.197779616,0.512481408,0.278321488,0.788598768,0.586574256,0.812608832,0.86257824,0.484980048,0.826541648,0.437203472,0.12005088,0.717888112,0.307913776,0.753675776,0.498762496,0.753255776,0.315425248,0.125875536,0.537681104,0.156229232,0.66114528,0.068410128,0.133956096,0.680421888,0.348962768,0.416812256,0.048796368,0.23717512,0.342203712,0.34203424,0.516796048,0.1264972,0.16222256,0.183077264,0.073564416,0.108467856,0.66874704,0.555627728,0.322092992,0.17279952,0.14478456,0.608656256,0.663823184,0.413095056,0.318825152,0.07559088,0.155610448,0.109333104,0.07226928,0.086030704,0.21872472,0.138723888,0.310955392,0.039146064,0.438491952,0.135970704,0.049461776,0.044376704,0.054910576,0.082326512,0.067097648,0.354960112,0.266692432,0.07036144,0.650469088,0.39941704,0.033444592,0.084592816,0.252033808,0.044552112,0.20467576,0.075861184,0.0892592,0.510078304,0.162258224,0.29755544,0.068268512,0.299534944,0.454072704,0.26974456,0.296999216,0.105104944 +580.0,0.6578,0.2542,0.04914,0.44136,0.13976,0.19031,0.0585,0.05915,0.04483,0.48749,0.31696,0.33392,0.07949,0.4355,0.33775,0.12934,0.19761,0.1999,0.5146,0.28317,0.79343,0.59236,0.81341,0.8634,0.48644,0.8292,0.43799,0.12009,0.7191,0.30871,0.75484,0.498,0.75383,0.31486,0.12554,0.53798,0.155,0.66122,0.06863,0.13458,0.6799,0.34523,0.4139,0.0488,0.23426,0.3403,0.3413,0.51211,0.12523,0.16107,0.1828,0.07296,0.1059,0.6649,0.55242,0.31651,0.1694,0.14091,0.6061,0.66336,0.41175,0.3187,0.07651,0.1531,0.10922,0.0715,0.0851,0.21784,0.13932,0.30924,0.0408,0.43795,0.13464,0.04934,0.0454,0.0568,0.08169,0.06722,0.35394,0.26728,0.07171,0.6507,0.4001,0.03394,0.08463,0.25258,0.04617,0.2094,0.07664,0.0919,0.51072,0.16283,0.29889,0.06891,0.30186,0.45737,0.2735,0.30765,0.1083 +581.0,0.663876192,0.262134864,0.049675168,0.444964144,0.142978608,0.1926604,0.059762368,0.059852128,0.045334896,0.504062192,0.324126416,0.34285984,0.082371424,0.438524896,0.34235888,0.130566576,0.199017744,0.202279536,0.516485488,0.288214624,0.798134032,0.5980884,0.8141412,0.86413912,0.487862944,0.831794192,0.438756272,0.12031704,0.72031768,0.30955344,0.756007056,0.497305056,0.754418656,0.314287392,0.125201424,0.538315472,0.153900208,0.661312544,0.0688824,0.135353584,0.679375008,0.341649312,0.410991472,0.048802288,0.231302464,0.338348624,0.340646736,0.507389536,0.124007088,0.160018688,0.182685664,0.07240352,0.103395744,0.660902768,0.549205472,0.310952928,0.166019536,0.137066368,0.603633968,0.66290392,0.410486736,0.318460592,0.077394736,0.150655248,0.108933952,0.070764384,0.08420696,0.217080624,0.140096976,0.307622704,0.042659648,0.437460272,0.133457968,0.049184544,0.046525792,0.05904136,0.08109528,0.067446304,0.353034176,0.267887488,0.073312,0.650936848,0.400756672,0.034506848,0.084868016,0.252990352,0.048130304,0.214500896,0.077460768,0.094759456,0.51143816,0.163459616,0.300309696,0.069583264,0.30438728,0.460795344,0.276715968,0.318421952,0.111797408 +582.0,0.669879888,0.270204768,0.050185664,0.448425344,0.146082864,0.194960448,0.061164704,0.060654752,0.045856224,0.520724208,0.330937616,0.351903552,0.085658144,0.441513808,0.347664416,0.131863536,0.200347232,0.204917216,0.518162448,0.293468736,0.802711296,0.603758368,0.814801424,0.864802368,0.489258352,0.834325792,0.439502128,0.120743456,0.721542016,0.31044784,0.757178912,0.496679808,0.755026544,0.313706704,0.124859328,0.538690304,0.152931472,0.66142424,0.069166656,0.136275216,0.678848848,0.338222656,0.408080384,0.048802736,0.228295872,0.336347952,0.3400724,0.502642048,0.122828528,0.15906744,0.182731168,0.0718928,0.100954672,0.656752304,0.545978384,0.305424384,0.162652384,0.1332576,0.601252384,0.662450048,0.40930336,0.318107648,0.07824032,0.148271792,0.10847064,0.070059664,0.083348224,0.216444512,0.141053248,0.306102032,0.044706368,0.437022944,0.132421888,0.048997248,0.047742304,0.061614608,0.08054256,0.067774128,0.352248944,0.268512672,0.075159184,0.651181424,0.401386992,0.035144768,0.085327872,0.253259968,0.050437392,0.2199592,0.078327248,0.09783288,0.512236176,0.164151088,0.301817376,0.070290368,0.307123248,0.464350656,0.279400032,0.329282736,0.115608288 +583.0,0.675806944,0.278392592,0.0506652,0.451743264,0.1490704,0.197210496,0.06272128,0.061569856,0.046392272,0.537404624,0.337398256,0.361049664,0.089317104,0.44444856,0.353588832,0.133235056,0.20160704,0.207789056,0.519648928,0.298956848,0.80714896,0.609363376,0.815393968,0.865393696,0.49058512,0.836795472,0.440201664,0.121279552,0.722769392,0.31139088,0.758354128,0.49611624,0.755650832,0.313115616,0.124513472,0.539107136,0.152115696,0.661557856,0.069480192,0.137332528,0.678324128,0.33494248,0.405141456,0.048801824,0.22527848,0.33429336,0.339566464,0.49786664,0.121690288,0.158211792,0.182928432,0.07142712,0.09857832,0.65244568,0.542727936,0.2999272,0.159283552,0.129488512,0.59894544,0.661994736,0.408197824,0.317653104,0.079041504,0.145945456,0.107837648,0.069383584,0.082520848,0.21592432,0.1421732,0.30467448,0.046884128,0.436634256,0.131525648,0.048782272,0.049015856,0.064462416,0.08003232,0.068199312,0.351584272,0.269157296,0.077170608,0.65143736,0.401988512,0.035848448,0.085944128,0.253394624,0.05307896,0.225727184,0.079240128,0.101100784,0.513116992,0.164906,0.303410416,0.071033712,0.310072336,0.468031648,0.281587056,0.34019776,0.119753408 +584.0,0.6816576,0.286680096,0.051107616,0.454917904,0.151944976,0.199413264,0.064447936,0.06261072,0.04694088,0.5540296,0.343525216,0.370303856,0.093292464,0.447312512,0.360007008,0.134685776,0.202808288,0.210856896,0.520956768,0.30470888,0.811426704,0.614893264,0.815925152,0.865915264,0.491783488,0.839203392,0.44082088,0.121777008,0.723993568,0.31237648,0.759528784,0.495600032,0.7562836,0.312510928,0.124163776,0.539567168,0.1514848,0.661716032,0.069819088,0.13850608,0.677803648,0.331795104,0.402139968,0.048800672,0.222311248,0.332178848,0.339113248,0.493056992,0.120585808,0.157444704,0.183265136,0.0710064,0.096269408,0.647981536,0.539441648,0.294464576,0.15589408,0.125764304,0.596701376,0.661535584,0.407167568,0.31711552,0.079793008,0.14367264,0.107050176,0.068734304,0.081722272,0.215509168,0.143432112,0.303335168,0.049116128,0.436288128,0.130760848,0.048544976,0.050300768,0.067505984,0.0795648,0.068716336,0.35103552,0.26982552,0.079225952,0.651709056,0.402557152,0.036609248,0.086607184,0.2534076,0.056030208,0.231741808,0.080197888,0.104534528,0.514081648,0.165724912,0.305082656,0.071816016,0.313237024,0.47183008,0.28332656,0.351131824,0.124257568 +585.0,0.68743,0.29505,0.05151,0.45795,0.15471,0.20157,0.06636,0.06379,0.0475,0.57053,0.34933,0.37966,0.09754,0.45009,0.36682,0.13622,0.20396,0.21409,0.5221,0.31075,0.81553,0.62034,0.8164,0.86637,0.49282,0.84155,0.44134,0.12214,0.72521,0.3134,0.7607,0.49512,0.75692,0.31189,0.12381,0.54007,0.15106,0.6619,0.07018,0.13978,0.67729,0.32877,0.39905,0.0488,0.21943,0.33,0.3387,0.48821,0.11951,0.15676,0.18373,0.07063,0.09403,0.64336,0.53611,0.28904,0.15247,0.12209,0.59451,0.66107,0.40621,0.31651,0.08049,0.14145,0.10612,0.06811,0.08095,0.21519,0.14481,0.30208,0.05134,0.43598,0.13012,0.04829,0.05156,0.07068,0.07914,0.06932,0.3506,0.27052,0.08124,0.652,0.40309,0.03742,0.08725,0.25331,0.05927,0.23795,0.0812,0.10811,0.51513,0.16661,0.30683,0.07264,0.31662,0.47574,0.28466,0.36205,0.12914 +586.0,0.69311616,0.30348784,0.051874976,0.460840688,0.157367936,0.203677328,0.06847104,0.065118352,0.048067808,0.586850704,0.354807776,0.389099184,0.102050096,0.452768352,0.374007232,0.137840656,0.205065088,0.217480096,0.523099136,0.317091168,0.819461776,0.62570216,0.816819488,0.866763296,0.493700816,0.843836384,0.441759216,0.122384816,0.726419328,0.314459872,0.761868208,0.4946744,0.757564304,0.311252,0.123451664,0.540614288,0.150830464,0.662109136,0.070561584,0.141149216,0.67678528,0.325866128,0.395872,0.04879936,0.216633024,0.327757312,0.338322784,0.483332048,0.118462368,0.1561544,0.184314896,0.070295648,0.09186016,0.6385856,0.532732656,0.283658064,0.149012448,0.11847032,0.59236608,0.660595056,0.405322464,0.315841008,0.081129168,0.139274768,0.105048688,0.067508704,0.080201632,0.214963264,0.146301264,0.300907072,0.0535368,0.435709712,0.12959872,0.048019712,0.052782336,0.073959712,0.078757904,0.07000616,0.350280624,0.271239024,0.083210528,0.652311104,0.403587648,0.038278016,0.087881584,0.25310656,0.062787744,0.244328448,0.0822488,0.11181664,0.516261808,0.16756672,0.30865456,0.073508336,0.320224784,0.479762272,0.285604384,0.372918368,0.13440304 +587.0,0.698709744,0.311979472,0.05220696,0.463591024,0.15992808,0.205731856,0.07079536,0.066606736,0.048642032,0.602942064,0.359958496,0.398612464,0.106806464,0.45533856,0.381538272,0.139550256,0.20612592,0.221015456,0.523971088,0.323741328,0.82322648,0.630978016,0.817185728,0.867099936,0.49441776,0.846063312,0.442071904,0.122506512,0.727622192,0.31555136,0.763032928,0.4942596,0.758220112,0.310596176,0.123088432,0.541197936,0.150778176,0.662342496,0.070962192,0.142606688,0.676291568,0.3230808,0.392610896,0.048798384,0.21393848,0.32545264,0.337976784,0.47842864,0.117442208,0.155623392,0.185008512,0.07000088,0.08976016,0.63366736,0.529312896,0.27832456,0.145526912,0.114910352,0.59026512,0.660109216,0.404501664,0.315114464,0.081708144,0.137145136,0.103840848,0.066928784,0.079475248,0.21482448,0.14789808,0.29981408,0.055688768,0.435476896,0.129191888,0.047736512,0.053957616,0.077318976,0.07841848,0.070769712,0.350078032,0.271981216,0.085128928,0.65264272,0.404050832,0.039179328,0.088482928,0.252807264,0.066564,0.250853264,0.083345648,0.115641024,0.517475872,0.16860064,0.310557936,0.074424032,0.324053136,0.483897088,0.286179536,0.38370296,0.140043648 +588.0,0.704206928,0.320507424,0.052509664,0.46620544,0.162386784,0.207735264,0.073348,0.06826776,0.049221296,0.618729664,0.364789296,0.408138464,0.111772032,0.457781168,0.389324352,0.141354256,0.207151712,0.224668416,0.52473368,0.330727568,0.826807904,0.636159392,0.817502928,0.867383136,0.495030304,0.848232,0.442310512,0.122521248,0.728813856,0.316675488,0.764191808,0.49386624,0.75888344,0.309919552,0.12271944,0.541813584,0.150931408,0.662596896,0.07137824,0.14413832,0.675811216,0.320405072,0.389236352,0.048797648,0.211286576,0.323079888,0.337650064,0.473497872,0.116444288,0.155161424,0.185802688,0.069745152,0.08773192,0.62860104,0.525836976,0.273041296,0.141994816,0.111414304,0.58819568,0.659608016,0.403745584,0.31434456,0.0822208,0.135057184,0.102505088,0.066368464,0.078768064,0.214765456,0.149582336,0.298797648,0.057732096,0.43527752,0.128892016,0.047445232,0.055047936,0.08069368,0.078120336,0.071606224,0.34999232,0.272748608,0.086961008,0.652998576,0.404476496,0.04011792,0.089118272,0.252417648,0.070587376,0.25747224,0.084491216,0.119561968,0.518766096,0.16971696,0.312536512,0.075389568,0.328109088,0.488139264,0.286424608,0.394368512,0.146086816 +589.0,0.709604672,0.329053136,0.052787968,0.468690096,0.164736048,0.209690992,0.07614432,0.070114624,0.04980456,0.634130864,0.369309776,0.417590784,0.11690288,0.460073216,0.397257312,0.143259216,0.208153904,0.228405936,0.525405072,0.338083008,0.830182928,0.641235888,0.817776048,0.867615536,0.495633568,0.850343888,0.44252808,0.122467344,0.72998776,0.317835616,0.765341808,0.49348304,0.759547808,0.309218368,0.122343568,0.542450832,0.15133384,0.662867616,0.071805408,0.145727632,0.675346624,0.317827904,0.385706288,0.048798032,0.208578912,0.320630256,0.337328304,0.468535424,0.115461808,0.154762496,0.186690304,0.069528544,0.08577792,0.623378,0.522285376,0.267808672,0.13838952,0.107986016,0.58614392,0.659085936,0.403052624,0.313548336,0.082659696,0.133006352,0.101051328,0.065825984,0.07807704,0.214776752,0.151332432,0.297854096,0.059587584,0.435106384,0.128690704,0.047151552,0.056006176,0.084007024,0.077861392,0.072511456,0.350023488,0.27354432,0.088671488,0.653383472,0.40486032,0.041087072,0.089896816,0.251941712,0.074849312,0.264123776,0.085685984,0.123555712,0.5201236,0.17092128,0.314584928,0.076407264,0.33239736,0.49248184,0.28638528,0.404879264,0.152566944 +590.0,0.7149,0.3376,0.05305,0.47105,0.16698,0.2116,0.0792,0.07216,0.05039,0.64908,0.37353,0.42691,0.12216,0.4622,0.40525,0.14527,0.20914,0.2322,0.526,0.34583,0.83334,0.6462,0.81801,0.8678,0.49629,0.8524,0.44276,0.12237,0.73114,0.31903,0.76648,0.4931,0.76021,0.30849,0.12196,0.5431,0.152,0.66315,0.07224,0.14736,0.6749,0.31534,0.382,0.0488,0.20576,0.3181,0.337,0.46354,0.11449,0.15442,0.18766,0.06935,0.0839,0.618,0.51865,0.26263,0.1347,0.10463,0.5841,0.65854,0.40242,0.31274,0.08302,0.13099,0.09949,0.0653,0.0774,0.21485,0.15313,0.29698,0.0612,0.43496,0.12858,0.04686,0.0568,0.0872,0.07764,0.07348,0.35017,0.27437,0.09024,0.6538,0.4052,0.04208,0.09088,0.25139,0.07933,0.27076,0.08693,0.1276,0.52154,0.17222,0.3167,0.07748,0.33692,0.49692,0.2861,0.4152,0.1595 +591.0,0.72008952,0.346135072,0.053303744,0.47328784,0.169140016,0.213459072,0.082529488,0.074414832,0.050974864,0.663539568,0.377458336,0.436086416,0.12751768,0.464159248,0.413258896,0.147388384,0.210111072,0.236033936,0.526528992,0.353971264,0.836286016,0.651049728,0.818208688,0.867940144,0.496988736,0.854400784,0.443001024,0.12222,0.732271312,0.32025384,0.767604496,0.492710928,0.760872352,0.307733904,0.121568528,0.54375744,0.152901312,0.663442384,0.072679792,0.149025552,0.674473088,0.312935984,0.378130544,0.048803296,0.202848224,0.315493424,0.336659392,0.458515792,0.11352784,0.154127552,0.188696128,0.069206848,0.082098624,0.612483792,0.51494008,0.257512816,0.130938736,0.101351504,0.582061056,0.657971072,0.401843568,0.311927664,0.083301072,0.129008176,0.0978304,0.064789632,0.076736016,0.214979456,0.154963984,0.296172576,0.062555952,0.43483776,0.128553232,0.046572976,0.057422544,0.09024688,0.077455712,0.074504928,0.350428768,0.275224816,0.091652464,0.654247328,0.405496528,0.043090912,0.092047728,0.250781584,0.083997008,0.277357728,0.088222832,0.131677408,0.5230124,0.17362056,0.318882512,0.078611328,0.341675232,0.501452912,0.285592704,0.425298688,0.16687336 +592.0,0.725170288,0.354645424,0.053554544,0.47540744,0.171234944,0.215265904,0.086146,0.07688968,0.051556816,0.677469984,0.381103856,0.445097664,0.132949392,0.465947008,0.421235632,0.149616416,0.211069152,0.239889936,0.52700288,0.362510048,0.839024144,0.655782432,0.818375968,0.868039376,0.497727584,0.85634688,0.443251152,0.122016048,0.733381696,0.321508208,0.768713488,0.4923096,0.76153584,0.306949312,0.12116888,0.544421024,0.154019568,0.663744176,0.0731224,0.15071408,0.674067456,0.310609792,0.374104992,0.048807808,0.199838016,0.312813568,0.336300224,0.453465952,0.112573728,0.153879184,0.189785088,0.069096912,0.08037432,0.60684336,0.511161536,0.252463696,0.127113296,0.098155264,0.58002352,0.657379536,0.401319744,0.31112016,0.08350176,0.127060544,0.096081648,0.064293984,0.076084064,0.215159216,0.156822576,0.295429008,0.063636656,0.43473848,0.128603376,0.046293152,0.057863616,0.09311864,0.077307936,0.075579424,0.35079688,0.276108528,0.092881888,0.654725136,0.405750256,0.04411424,0.093409632,0.250134368,0.088822176,0.28389072,0.089563856,0.135770448,0.524539456,0.17513096,0.321132512,0.079804608,0.346661488,0.506079024,0.284889328,0.435145232,0.174679216 +593.0,0.730140096,0.363118816,0.053832944,0.4774104,0.173309712,0.217014016,0.090070832,0.079597888,0.052130768,0.6908532,0.384482096,0.453959392,0.138419824,0.467574928,0.429136688,0.151954688,0.212010032,0.243748576,0.527423968,0.371442832,0.841579072,0.660397616,0.818518528,0.868100608,0.498510912,0.858237776,0.44351592,0.121765536,0.73447464,0.322760976,0.76980256,0.491886112,0.762207088,0.30613648,0.120760912,0.545071808,0.155270224,0.664044048,0.073565088,0.152412928,0.673685264,0.30835544,0.36996936,0.0488128,0.196807568,0.310072192,0.335916896,0.448397392,0.111628176,0.153663776,0.190896608,0.069015056,0.078727776,0.601115648,0.507343472,0.247495936,0.123264256,0.095048864,0.577988304,0.65677048,0.4008408,0.310326176,0.083625008,0.125150992,0.094259696,0.063813296,0.075444752,0.215382256,0.158692928,0.29474616,0.0644524,0.43466376,0.12872296,0.046022128,0.058131968,0.09579976,0.07719536,0.076694,0.351266512,0.27701832,0.093997712,0.655229104,0.405965024,0.045140608,0.094873936,0.249482272,0.093739184,0.290347152,0.09095168,0.139856288,0.526103232,0.17675976,0.323452672,0.081064928,0.351872224,0.510799136,0.284011952,0.444699376,0.182875312 +594.0,0.734997184,0.371543968,0.054181184,0.4792972,0.17542432,0.218694448,0.094328704,0.082553776,0.05269024,0.703685936,0.387611776,0.46271032,0.143891216,0.469063968,0.436926624,0.15440264,0.212925632,0.247591136,0.527789696,0.380759616,0.84398808,0.66489656,0.818644288,0.86812656,0.49933704,0.860072352,0.443798608,0.121477104,0.735555904,0.323964864,0.770866192,0.491429344,0.762896016,0.305296448,0.120344624,0.545683952,0.15653184,0.66432616,0.074005136,0.154108896,0.673328832,0.306167408,0.365792768,0.048817152,0.19388128,0.307286336,0.335504928,0.443319472,0.110693184,0.153467808,0.191992048,0.06895456,0.077159552,0.595350656,0.503528368,0.242626576,0.119450976,0.092041264,0.575959488,0.656151824,0.400396896,0.309553552,0.083676336,0.12328584,0.092383664,0.063348448,0.07481968,0.215641376,0.16056264,0.294120832,0.065033184,0.43461688,0.128904384,0.045760704,0.05824896,0.09828592,0.077116464,0.077837616,0.351827184,0.277949872,0.095114336,0.655752512,0.406146752,0.046158976,0.09629448,0.248868256,0.098661952,0.296725504,0.092384384,0.143910208,0.527678928,0.17851616,0.325847392,0.082398288,0.35729784,0.515615648,0.282978976,0.45391696,0.191399008 +595.0,0.73974,0.37991,0.05463,0.48107,0.17763,0.2203,0.09894,0.08577,0.05323,0.71596,0.39051,0.47137,0.14933,0.47043,0.44457,0.15696,0.21381,0.2514,0.5281,0.39045,0.84628,0.66928,0.81876,0.86812,0.5002,0.86185,0.4441,0.12116,0.73663,0.32509,0.7719,0.49093,0.76361,0.30443,0.11992,0.54624,0.15771,0.66458,0.07444,0.15579,0.673,0.30404,0.36163,0.04882,0.19114,0.30447,0.33506,0.43824,0.10977,0.15328,0.19304,0.06891,0.07567,0.58959,0.49975,0.23787,0.11572,0.08914,0.57394,0.65553,0.39998,0.30881,0.08366,0.12147,0.09047,0.0629,0.07421,0.21593,0.16242,0.29355,0.0654,0.4346,0.12914,0.04551,0.05823,0.10057,0.07707,0.079,0.35247,0.2789,0.0963,0.65629,0.4063,0.04716,0.09758,0.24833,0.10352,0.30302,0.09386,0.14791,0.52925,0.18041,0.32832,0.08381,0.36293,0.52053,0.28181,0.46276,0.2002 +596.0,0.744367488,0.388207136,0.0551812,0.482733904,0.179951888,0.221828672,0.103911936,0.089254176,0.053748384,0.727652656,0.393188624,0.479918416,0.154715136,0.471673664,0.452031008,0.15962696,0.214663472,0.255160992,0.528362368,0.400502448,0.848458544,0.673547056,0.818869056,0.868083776,0.501104544,0.863571776,0.444421808,0.120818976,0.737697664,0.32613992,0.772903056,0.490384,0.764348848,0.303537648,0.119487264,0.546740256,0.158791488,0.664806352,0.074867744,0.157448256,0.67269936,0.301967216,0.35749296,0.04882144,0.188574736,0.301628192,0.334578176,0.433161952,0.10885768,0.153095856,0.194030496,0.068879536,0.074258848,0.583850112,0.496016304,0.233232464,0.112079584,0.086348288,0.571929568,0.654907152,0.399587312,0.30810248,0.08357672,0.119704128,0.088527264,0.06246752,0.073615552,0.216243296,0.16425568,0.293031184,0.065546976,0.434611936,0.129421952,0.045271872,0.058072672,0.102636512,0.077055824,0.080173392,0.353190736,0.279868816,0.097529328,0.656840064,0.40642512,0.048139392,0.09873512,0.247889472,0.108289296,0.309212144,0.095376528,0.151841152,0.530816592,0.182451024,0.330870672,0.085303248,0.368764688,0.525541168,0.280528096,0.471209232,0.209264928 +597.0,0.748879376,0.396427376,0.055835504,0.4842936,0.182417632,0.223278576,0.109247872,0.093012048,0.054244128,0.73875024,0.395660016,0.488346672,0.160030144,0.472797648,0.459283168,0.162402448,0.215485472,0.258862896,0.528583008,0.410896992,0.850527552,0.677698016,0.818974368,0.868020528,0.502064032,0.865239056,0.44476696,0.120455056,0.73876008,0.327112496,0.7738752,0.489788832,0.765111808,0.30262088,0.119047072,0.547184448,0.159767584,0.665005488,0.075286848,0.159077568,0.672427024,0.29994352,0.3533956,0.04882176,0.186194368,0.298766912,0.334057056,0.428088272,0.107955776,0.152912096,0.194956288,0.068861456,0.072925296,0.578147968,0.492335872,0.228719776,0.108537616,0.083668384,0.569929904,0.65428632,0.39921656,0.307436336,0.083428288,0.117989232,0.086563136,0.062050736,0.073036592,0.216577216,0.166062448,0.29256216,0.06547584,0.43465152,0.12974208,0.045047568,0.057779008,0.1044784,0.07707432,0.08134976,0.353984752,0.28085656,0.098792672,0.657400544,0.406522384,0.049093888,0.099729216,0.247570112,0.112949824,0.315288192,0.09693136,0.155691568,0.532377392,0.18464888,0.333499792,0.086881008,0.374797024,0.530648736,0.279153952,0.479252016,0.218578112 +598.0,0.753273584,0.404558256,0.056613568,0.485755856,0.185075536,0.22464256,0.114972368,0.09705824,0.054711952,0.749235104,0.397941568,0.496627328,0.165236992,0.473815712,0.466282448,0.165288256,0.216271152,0.26248488,0.528763008,0.421631536,0.85251528,0.681732416,0.81908288,0.86793336,0.50301672,0.866850656,0.445118192,0.120093856,0.739821376,0.328021152,0.774811184,0.489134144,0.765906688,0.301678512,0.1185984,0.54757048,0.16053912,0.665176784,0.075694192,0.16066336,0.672184928,0.297962304,0.3493904,0.04881952,0.18398024,0.295898912,0.333490976,0.423027152,0.107064912,0.152716096,0.19578376,0.068850816,0.071670224,0.572524704,0.48874128,0.224347088,0.105140688,0.08110888,0.56794144,0.653672688,0.398859568,0.306821632,0.083217376,0.116329936,0.084594688,0.061650112,0.072473792,0.216924656,0.167825856,0.292139616,0.065199664,0.434720864,0.130093168,0.044839264,0.057359904,0.106080048,0.077123136,0.082518688,0.354843728,0.281860144,0.100052816,0.657967184,0.406596688,0.050013184,0.100643872,0.247407872,0.117427792,0.32123752,0.098522912,0.159436304,0.533933472,0.187017536,0.336210352,0.088548928,0.38101848,0.535852704,0.277709808,0.48684336,0.228091696 +599.0,0.757547472,0.412585856,0.057540832,0.487128832,0.18798072,0.225911744,0.121117104,0.101410352,0.055145296,0.759088208,0.40005248,0.504720784,0.17029048,0.474745296,0.472979088,0.168287264,0.217014272,0.266002864,0.528901728,0.43270992,0.854458048,0.685649536,0.819202832,0.867825552,0.503867968,0.868404496,0.445448704,0.119771296,0.740886672,0.328890768,0.775704048,0.488407056,0.766744128,0.300708304,0.118139568,0.547898112,0.160976736,0.66532088,0.076086096,0.162188112,0.671975552,0.296016528,0.34554264,0.04881264,0.181890912,0.293039152,0.332873216,0.417988592,0.106186048,0.152492096,0.196470592,0.068841696,0.070495072,0.56702952,0.485273008,0.22013272,0.10194824,0.078680496,0.565964096,0.653072096,0.398506256,0.306270128,0.082946864,0.11473208,0.08264208,0.061266368,0.071927952,0.217277536,0.169528944,0.291759872,0.064735248,0.434823168,0.130468336,0.04464952,0.0568292,0.107422976,0.077198912,0.083668896,0.355758144,0.282875408,0.1012484,0.658535104,0.406654512,0.05088464,0.101621008,0.247442832,0.1216316,0.327050528,0.100149904,0.16304608,0.535489392,0.189573072,0.339006192,0.090313568,0.387419136,0.541153072,0.276218464,0.493927424,0.23774712 +600.0,0.7617,0.4205,0.05863,0.48842,0.19118,0.22708,0.1277,0.10608,0.05554,0.7683,0.40201,0.5126,0.17516,0.4756,0.47934,0.1714,0.21771,0.2694,0.529,0.44412,0.85638,0.68945,0.81934,0.8677,0.50456,0.8699,0.44574,0.11951,0.74196,0.32974,0.77655,0.4876,0.76763,0.29971,0.11767,0.54817,0.161,0.66544,0.07646,0.16364,0.6718,0.2941,0.3419,0.0488,0.1799,0.2902,0.3322,0.41298,0.10532,0.15223,0.19699,0.06883,0.0694,0.5617,0.48196,0.21609,0.099,0.07639,0.564,0.65249,0.39815,0.30579,0.08262,0.1132,0.08072,0.0609,0.0714,0.21763,0.17116,0.29142,0.0641,0.43496,0.13086,0.04448,0.0562,0.1085,0.0773,0.08479,0.35672,0.2839,0.10233,0.6591,0.4067,0.0517,0.10274,0.24771,0.1255,0.33272,0.10181,0.1665,0.53705,0.19233,0.34189,0.09218,0.39399,0.54655,0.2747,0.50047,0.2475 +601.0,0.76573232,0.428295904,0.059883344,0.48963456,0.194702864,0.228146288,0.134716,0.111068704,0.055895776,0.776873616,0.403827472,0.520259504,0.179837248,0.476385568,0.48535584,0.174623584,0.218356704,0.27267056,0.529061728,0.45582728,0.858284688,0.693135952,0.81949616,0.867558944,0.505102848,0.871338896,0.44599744,0.11930992,0.743043056,0.330563184,0.777350272,0.486714064,0.768562288,0.298686304,0.117190848,0.548387856,0.160609472,0.66553568,0.0768152,0.16501624,0.671657552,0.29220808,0.338477472,0.048782048,0.178016896,0.28738864,0.331472224,0.408004304,0.104467184,0.151929056,0.197340656,0.068814608,0.068383248,0.556552624,0.478810656,0.212223328,0.09630152,0.074237664,0.56205368,0.651930432,0.397789808,0.3053836,0.082240176,0.111735056,0.07883408,0.060551008,0.070890752,0.217979552,0.172715424,0.291118224,0.063307648,0.435130128,0.131260096,0.044331008,0.055481408,0.10931848,0.077427504,0.085873984,0.357724544,0.28493448,0.103305008,0.659659072,0.406733392,0.052457968,0.1039772,0.248234064,0.12902216,0.33824008,0.103499408,0.16979088,0.53861496,0.195296128,0.344862384,0.094150896,0.400723648,0.552043136,0.273170448,0.506471056,0.257331408 +602.0,0.769645184,0.435967936,0.061313728,0.490777936,0.198579616,0.22910928,0.142162128,0.11637864,0.056211792,0.784811824,0.405518848,0.527685728,0.184310112,0.477108912,0.491014128,0.177955856,0.218952592,0.27580736,0.529090048,0.467801216,0.86017936,0.696709136,0.8196736,0.86740464,0.50549064,0.872722336,0.446228832,0.119176656,0.744137696,0.331351552,0.778105264,0.485749584,0.769540208,0.297639232,0.11670288,0.5485512,0.15979176,0.665608384,0.077150832,0.16631272,0.671547968,0.290336144,0.33529384,0.04875888,0.17624136,0.284612832,0.330690656,0.403065232,0.103628192,0.151587296,0.1975176,0.068794016,0.067443344,0.551606384,0.47583616,0.208537968,0.093863248,0.07222456,0.5601288,0.651397248,0.397423888,0.305053792,0.081810736,0.110338896,0.076991168,0.060219472,0.070400912,0.218323216,0.174190416,0.290852576,0.062371984,0.435332784,0.131661328,0.044203024,0.054682944,0.109883328,0.077582016,0.086913088,0.358767008,0.285978864,0.104194336,0.660209584,0.406755728,0.053156144,0.105353392,0.249040432,0.132179872,0.34360464,0.105214512,0.172909984,0.540182592,0.198476976,0.347924272,0.096229408,0.40761144,0.557631424,0.271645728,0.51192576,0.267218016 +603.0,0.773443168,0.443518448,0.062867712,0.491857792,0.202841088,0.229969472,0.150017616,0.122005056,0.056491088,0.792136992,0.407096864,0.534891952,0.188594736,0.477775136,0.496337456,0.181389328,0.21949504,0.27881616,0.529089248,0.479974512,0.862052592,0.7001756,0.8198708,0.867238976,0.505767072,0.874054736,0.446415344,0.119092752,0.745245936,0.33213816,0.778820976,0.484714304,0.770555568,0.2965752,0.116209072,0.548684144,0.158611968,0.665672288,0.077467504,0.16753504,0.671467264,0.288479968,0.332352768,0.048732352,0.174575424,0.281879184,0.329859968,0.3981628,0.1028036,0.151211136,0.197539984,0.068769504,0.06657632,0.546868864,0.473034544,0.205034288,0.091670096,0.070345936,0.5582368,0.650896624,0.397055888,0.304798384,0.081336896,0.109012496,0.075190016,0.059905456,0.069932512,0.21866224,0.175589728,0.290622528,0.06132136,0.43556488,0.13205208,0.04409488,0.05382088,0.110228496,0.077767168,0.087897312,0.359842032,0.287036368,0.104893024,0.660747616,0.406764144,0.05379976,0.106734304,0.2501536,0.135000544,0.34881832,0.106949376,0.175860848,0.541771184,0.201893344,0.35107528,0.098416,0.414648032,0.563317712,0.270137808,0.516866144,0.277153984 +604.0,0.777132992,0.4509544,0.064460496,0.492882608,0.20751576,0.230729024,0.158249664,0.127938272,0.056739104,0.79888328,0.4085732,0.541905776,0.19272384,0.47838752,0.501368864,0.18491352,0.219981488,0.28171056,0.529064448,0.492259088,0.863881424,0.703543664,0.82008384,0.867063552,0.506006624,0.875342336,0.446529616,0.119027328,0.746369536,0.332971888,0.779506768,0.483620864,0.771595568,0.295503088,0.115713664,0.548822208,0.157183296,0.665747952,0.077766816,0.16869472,0.67140944,0.286635792,0.329646176,0.048705344,0.173025008,0.279193056,0.32898752,0.393294688,0.101993968,0.150812336,0.197442048,0.068744112,0.065776736,0.542339264,0.470394768,0.201709008,0.089690144,0.068593312,0.55639312,0.6504356,0.396692848,0.304611856,0.080824816,0.107756096,0.073424224,0.05960896,0.069488192,0.219000384,0.17692384,0.2904284,0.060190816,0.435821856,0.132418752,0.044004416,0.052914336,0.110404064,0.0779884,0.088816016,0.360944496,0.288112112,0.105247152,0.661268928,0.40675344,0.054398656,0.107905776,0.251596128,0.137540336,0.35389128,0.10869672,0.178654912,0.543407696,0.205571792,0.354314128,0.100709552,0.421829584,0.56910648,0.268655968,0.521346768,0.287144992 +605.0,0.78072,0.45828,0.06604,0.49386,0.21263,0.23139,0.16683,0.13417,0.05696,0.80508,0.40996,0.54874,0.19672,0.47895,0.50614,0.18852,0.22041,0.2845,0.52902,0.50458,0.86565,0.70682,0.82031,0.86688,0.50626,0.87659,0.44656,0.11896,0.74751,0.33388,0.78017,0.48248,0.77265,0.29443,0.11522,0.54899,0.15559,0.66585,0.07805,0.1698,0.67137,0.2848,0.32717,0.04868,0.17159,0.27656,0.32808,0.38846,0.1012,0.1504,0.19725,0.06872,0.06504,0.53802,0.46791,0.19856,0.0879,0.06696,0.55461,0.65002,0.39634,0.30449,0.08028,0.10657,0.07169,0.05933,0.06907,0.21934,0.1782,0.29027,0.05901,0.4361,0.13275,0.04393,0.05198,0.11045,0.07825,0.08966,0.36207,0.28921,0.10517,0.66177,0.40672,0.05496,0.10874,0.25339,0.13984,0.35883,0.11045,0.1813,0.54511,0.20953,0.35764,0.10311,0.42915,0.575,0.26721,0.52541,0.29719 +606.0,0.784205504,0.465490912,0.067613984,0.494794192,0.218203808,0.231953952,0.175743872,0.140696288,0.057154048,0.81074192,0.411270416,0.55538704,0.200575712,0.479468448,0.510648448,0.192206112,0.220780736,0.28718144,0.528958048,0.516901584,0.867363632,0.710006592,0.820550336,0.866689824,0.506515552,0.877798656,0.446509248,0.118895264,0.74866824,0.334858032,0.780811984,0.481296576,0.773716304,0.29335816,0.114728864,0.549187968,0.153829632,0.66597824,0.078316784,0.170849168,0.671349024,0.28296968,0.324932,0.04865648,0.170265664,0.273985952,0.327141952,0.383661968,0.100422528,0.149975056,0.196966128,0.068696352,0.064363968,0.53392304,0.465586176,0.19558848,0.086301984,0.065444832,0.552890016,0.649652048,0.395997168,0.304432176,0.07970584,0.105454624,0.069991264,0.059068416,0.068678176,0.219679056,0.179415952,0.290145344,0.05779264,0.436397824,0.133040848,0.043871392,0.051027072,0.110376064,0.078553712,0.090424352,0.36321608,0.290330496,0.104691952,0.662249312,0.406664704,0.055483008,0.109266624,0.255555456,0.14189408,0.363629856,0.112204976,0.183792992,0.54687696,0.213768368,0.361053376,0.105620688,0.436596688,0.58099408,0.265811072,0.529061712,0.307267744 +607.0,0.787591008,0.472583088,0.069173152,0.495688032,0.224250528,0.232424032,0.184970176,0.147509936,0.057322048,0.815889232,0.412516784,0.561853872,0.204285456,0.479947696,0.514895936,0.195968928,0.22109528,0.28975376,0.528880448,0.529186752,0.869026432,0.71310544,0.82080536,0.866494016,0.506764752,0.878969136,0.446365424,0.118833792,0.749844576,0.33591472,0.781434416,0.480077744,0.774790928,0.29229,0.114241072,0.549419184,0.151905488,0.666132448,0.078567024,0.1718416,0.671346944,0.281143008,0.322932848,0.048635072,0.169054544,0.271475504,0.326179808,0.37890344,0.09966232,0.149539856,0.196596544,0.068672544,0.06374616,0.530055984,0.463426064,0.192793248,0.084893696,0.064045536,0.55123472,0.649332864,0.395665008,0.304435744,0.079105536,0.104409536,0.068330336,0.058823776,0.068312592,0.22001584,0.180570688,0.290052288,0.05655104,0.43671328,0.1332876,0.04382792,0.0500636,0.110193296,0.078902288,0.091105952,0.364381632,0.291474368,0.103821104,0.662706096,0.406588224,0.05596768,0.109473264,0.25810936,0.143703904,0.36828616,0.113957216,0.186133648,0.548709744,0.218287584,0.3645544,0.1082452,0.444155072,0.587082672,0.264467888,0.532312944,0.317358624 +608.0,0.790881472,0.479561024,0.07075912,0.496552112,0.230803248,0.232801152,0.19448712,0.154605584,0.057467728,0.820545824,0.413712832,0.568090704,0.20786912,0.480392784,0.518909744,0.199801024,0.221349824,0.29222448,0.528791648,0.54136224,0.870624032,0.716122688,0.821072544,0.866295168,0.507037232,0.880106016,0.44619704,0.11877224,0.751040752,0.336997888,0.782044368,0.478832272,0.775864912,0.29123152,0.11375968,0.54968848,0.149895824,0.666321296,0.078802624,0.172784672,0.671358784,0.279314736,0.321176016,0.048617344,0.167922304,0.269035936,0.325198624,0.374184192,0.098920752,0.149102496,0.19616328,0.068651216,0.063182512,0.526425808,0.461425712,0.190174816,0.083656208,0.06275624,0.549657504,0.64906928,0.395347888,0.304499232,0.078485072,0.103436048,0.066705248,0.058596816,0.067975728,0.220352704,0.181669824,0.289991312,0.05531576,0.437043856,0.133478432,0.043798768,0.049107808,0.109940128,0.079297184,0.091693872,0.365561344,0.2926448,0.102662016,0.6631364,0.406487664,0.056420272,0.109477344,0.261077104,0.145303408,0.372805584,0.115700176,0.188327104,0.550607408,0.22308632,0.368142784,0.110982752,0.451820496,0.593269584,0.263193024,0.535200736,0.327460064 +609.0,0.794082976,0.48643216,0.072443248,0.497399872,0.237901648,0.233085552,0.204272704,0.161978432,0.057595808,0.824736816,0.41487288,0.574020816,0.211354944,0.480808832,0.522725632,0.2036936,0.221538688,0.294604,0.528696928,0.553342768,0.872135952,0.719065776,0.821348288,0.86609648,0.507372352,0.881215056,0.446110336,0.118708128,0.752258928,0.338024016,0.78265072,0.47756952,0.776927536,0.29018976,0.113288448,0.549998416,0.14790384,0.666555424,0.079026304,0.173688464,0.671377744,0.277478384,0.319665984,0.048605216,0.166817824,0.266675488,0.32420304,0.369503024,0.098199504,0.148673056,0.195693616,0.068636208,0.062668464,0.523039312,0.45957888,0.187734304,0.08256504,0.061569824,0.548175728,0.648870016,0.395051408,0.30462168,0.077851408,0.10253608,0.06511264,0.058388736,0.067670944,0.220693408,0.18272112,0.289963856,0.05412336,0.437386992,0.133598944,0.043783136,0.048181376,0.10966408,0.07973912,0.092174592,0.366748576,0.293845712,0.101379568,0.663535264,0.406359024,0.056849104,0.109473424,0.264486928,0.146737392,0.377198608,0.117426576,0.19038032,0.552565552,0.228159456,0.371818128,0.113831024,0.45959152,0.599561856,0.2620004,0.537770768,0.337575184 +610.0,0.7972,0.4932,0.07427,0.49824,0.24557,0.23328,0.2143,0.16962,0.05771,0.82849,0.41601,0.5796,0.21476,0.4812,0.52637,0.20764,0.22166,0.2969,0.5286,0.56506,0.87355,0.72194,0.82163,0.8659,0.50779,0.8823,0.44617,0.11864,0.7535,0.33894,0.78326,0.4763,0.77797,0.28917,0.11283,0.55035,0.146,0.66684,0.07924,0.17456,0.6714,0.27563,0.3184,0.0486,0.16571,0.2644,0.3232,0.36486,0.0975,0.14826,0.19521,0.06863,0.0622,0.5199,0.45788,0.18547,0.0816,0.06048,0.5468,0.64874,0.39478,0.3048,0.07721,0.10171,0.06355,0.0582,0.0674,0.22104,0.18373,0.28997,0.053,0.43774,0.13364,0.04378,0.0473,0.1094,0.08023,0.09254,0.36794,0.29508,0.1001,0.6639,0.4062,0.05726,0.10959,0.26836,0.14804,0.38147,0.11913,0.1923,0.55458,0.2335,0.37558,0.11679,0.46746,0.60596,0.2609,0.54006,0.3477 +611.0,0.800234224,0.499861456,0.07622336,0.499073824,0.253807936,0.233390944,0.22453744,0.177517232,0.057811824,0.831833696,0.41713504,0.584838608,0.218081904,0.481569232,0.529850944,0.211637072,0.221717984,0.299114592,0.528502144,0.576477824,0.874868608,0.724747232,0.821917376,0.865705936,0.50828928,0.883361328,0.4463652,0.118567856,0.754762944,0.33975432,0.783874336,0.47503496,0.778987808,0.288174496,0.112385056,0.550745424,0.14419544,0.66717328,0.07944408,0.175400464,0.671426928,0.27376992,0.317367152,0.048601952,0.164599008,0.2622116,0.32219936,0.360257376,0.096823168,0.147867888,0.194723824,0.068632496,0.06177424,0.517007616,0.45632632,0.183376608,0.080751376,0.059482592,0.545529792,0.6486784,0.394535488,0.305028816,0.076563728,0.10095592,0.062017056,0.058029856,0.067162112,0.221391392,0.184697344,0.290007616,0.051954448,0.438100352,0.133600848,0.04378824,0.04646944,0.109159904,0.08077384,0.092790528,0.369137792,0.296348816,0.098836976,0.664231232,0.406011776,0.057654064,0.109811216,0.272706128,0.14922304,0.38561512,0.120806192,0.194090688,0.556650352,0.23910248,0.379428144,0.11986312,0.47540856,0.612454656,0.259896,0.542087712,0.357817776 +612.0,0.803187792,0.506415104,0.0782948,0.499904432,0.262616848,0.233424672,0.23495448,0.185657584,0.057903008,0.834795024,0.418258832,0.589730224,0.22132224,0.481919504,0.533179664,0.215680944,0.221716144,0.30125104,0.528405088,0.5875576,0.876091552,0.727490048,0.822209904,0.865514768,0.508883552,0.884400096,0.44670472,0.11849296,0.756046832,0.340462928,0.784496448,0.473785712,0.779976352,0.28720584,0.11195464,0.5511872,0.142511184,0.667555536,0.079639264,0.176212112,0.671459344,0.271898256,0.316558256,0.048611424,0.163472144,0.260112736,0.321210624,0.355696912,0.096170112,0.147501696,0.19424752,0.068644096,0.061388192,0.514361888,0.454914352,0.181449376,0.080008128,0.05857304,0.544366304,0.64868544,0.394319968,0.305303632,0.075915872,0.100272288,0.060513088,0.057877776,0.066956928,0.221747104,0.185624864,0.290075152,0.05099776,0.438465776,0.133479712,0.043806928,0.045696848,0.108959088,0.081374464,0.092925552,0.370344064,0.29765368,0.097610336,0.66452896,0.405795664,0.058033152,0.110148704,0.277535664,0.150301808,0.389631344,0.122451136,0.195757264,0.558775568,0.24496064,0.383362384,0.123052672,0.483422496,0.619038304,0.258993104,0.543876336,0.367914384 +613.0,0.80606072,0.512852352,0.08048088,0.50072496,0.27197608,0.23339192,0.24550288,0.194019136,0.057985392,0.837417952,0.419391424,0.59433336,0.224466016,0.482251616,0.536359904,0.219771536,0.221663984,0.303310688,0.528307552,0.598270736,0.877229776,0.730167024,0.822506672,0.86532504,0.509503184,0.885413904,0.44713536,0.118415824,0.75734872,0.341084576,0.78512696,0.472568144,0.780929856,0.286264464,0.111538064,0.551664336,0.140930048,0.667970912,0.079825568,0.17699424,0.67150144,0.270017872,0.31594176,0.048628096,0.16236872,0.258101952,0.320249088,0.351182368,0.095541536,0.147167584,0.193795616,0.068663776,0.061038944,0.51195408,0.453637664,0.179676224,0.07935616,0.057746208,0.543300176,0.64875376,0.394135808,0.305612288,0.075267616,0.099654336,0.05903664,0.057742016,0.066781264,0.222104576,0.186512224,0.290168368,0.050126192,0.43883224,0.133283296,0.043833696,0.044980496,0.108798752,0.082036848,0.092953376,0.371564416,0.298994464,0.096533456,0.664798128,0.405552432,0.0583968,0.110595792,0.28284952,0.151287696,0.393505968,0.12405904,0.19730888,0.560945904,0.251054,0.387381664,0.126366704,0.491469232,0.625690192,0.258188768,0.54544272,0.377966112 +614.0,0.808851648,0.51916048,0.08277312,0.501522928,0.281850432,0.233306208,0.25612512,0.202574688,0.058060576,0.83975456,0.420542096,0.598742496,0.227488032,0.482565088,0.539389664,0.223911008,0.221574784,0.305293376,0.528206496,0.608598192,0.87830136,0.7327744,0.82280688,0.865134112,0.510038336,0.886398272,0.44756688,0.118337248,0.758664368,0.341655504,0.785764912,0.471400576,0.78184264,0.285349328,0.111133568,0.552159392,0.139409152,0.668395008,0.080002512,0.177744048,0.671559776,0.268133648,0.315474144,0.048651168,0.161354976,0.256175328,0.319333312,0.346718704,0.09493792,0.146871792,0.193382192,0.068689536,0.060723776,0.509770592,0.452488576,0.178040992,0.078781152,0.056996896,0.542315488,0.6488716,0.393985168,0.305938704,0.0746188,0.099095424,0.057586112,0.057620096,0.06663024,0.222459888,0.187357584,0.290281504,0.049326464,0.439194944,0.1330236,0.043865504,0.044313024,0.108670336,0.082766832,0.09288784,0.372807088,0.300370048,0.095749776,0.665046496,0.4052832,0.058742848,0.11112176,0.288642176,0.152187584,0.397220352,0.125623664,0.198756576,0.56314768,0.25735496,0.391484544,0.129816336,0.499506608,0.63238192,0.257476032,0.546799024,0.3879432 +615.0,0.81156,0.52533,0.08516,0.50229,0.29221,0.23318,0.26677,0.2113,0.05813,0.84185,0.42172,0.60302,0.23037,0.48286,0.54227,0.2281,0.22146,0.3072,0.5281,0.61852,0.87932,0.73531,0.82311,0.86494,0.51042,0.88735,0.44794,0.11826,0.75999,0.3422,0.78641,0.4703,0.78271,0.28446,0.11074,0.55266,0.13792,0.66881,0.08017,0.17846,0.67164,0.26625,0.31512,0.04868,0.16047,0.25433,0.31848,0.34231,0.09436,0.14662,0.19302,0.06872,0.06044,0.5078,0.45146,0.17653,0.07827,0.05632,0.5414,0.64903,0.39387,0.30627,0.07397,0.09859,0.05616,0.05751,0.0665,0.22281,0.18816,0.29041,0.04859,0.43955,0.13271,0.0439,0.04369,0.10857,0.08357,0.09274,0.37408,0.30178,0.09536,0.66528,0.40499,0.05907,0.11171,0.29491,0.15301,0.40076,0.12714,0.20011,0.56537,0.26384,0.39567,0.13341,0.5075,0.63909,0.25685,0.54796,0.39782 +616.0,0.814187488,0.531360864,0.08763928,0.503028288,0.30304088,0.233022448,0.277405152,0.220179728,0.05819504,0.843728816,0.422933808,0.6071572,0.233114224,0.483138336,0.545011392,0.232334352,0.221325856,0.309034528,0.52798928,0.628013168,0.880286128,0.737776512,0.823416176,0.864742592,0.510659536,0.88826992,0.448269424,0.118181664,0.761323696,0.342710592,0.787063712,0.469279616,0.783530144,0.28359776,0.11035784,0.553163648,0.136477184,0.669214576,0.08032872,0.179144224,0.671744768,0.264369824,0.314868128,0.048714688,0.15970464,0.252566016,0.3177,0.337957872,0.093808736,0.146415824,0.192718144,0.0687556,0.06018496,0.506037568,0.450546864,0.175137024,0.07781312,0.055710832,0.54055232,0.649228608,0.39379168,0.306602736,0.073323872,0.098135744,0.05475728,0.057411168,0.066389632,0.223154768,0.188921232,0.290552688,0.047922496,0.43989584,0.132344016,0.043936416,0.043115488,0.108508032,0.084450352,0.092512704,0.375389872,0.30322624,0.095384976,0.665499136,0.4046776,0.059379792,0.112377344,0.301654912,0.153768416,0.404122768,0.1286064,0.20137472,0.567606544,0.27050024,0.399938,0.137148208,0.515437424,0.645805936,0.256312032,0.548947968,0.407583168 +617.0,0.81673552,0.537253632,0.0902156,0.50373864,0.31432136,0.232844,0.28799832,0.229197536,0.058256912,0.845412992,0.424190944,0.61115608,0.235723056,0.483401776,0.547623184,0.236609616,0.221180064,0.310800928,0.527875232,0.637064256,0.881200736,0.740176784,0.823726032,0.86454144,0.510751424,0.889158864,0.44856224,0.118092624,0.76266328,0.343183376,0.78772664,0.468353344,0.784303136,0.282763104,0.109987184,0.553663856,0.135090288,0.669605792,0.080479088,0.17979848,0.67187768,0.262497472,0.31470744,0.048755296,0.1590664,0.250882112,0.317004448,0.333663968,0.093284736,0.146261584,0.192483136,0.068796656,0.059956224,0.5044768,0.449743904,0.173855424,0.07740272,0.055164928,0.539769616,0.64946704,0.393751008,0.306934368,0.072682656,0.097730016,0.05337712,0.057323056,0.066297904,0.223494256,0.189642864,0.290708528,0.047326832,0.4402312,0.131928816,0.043973936,0.042591776,0.108491472,0.085411648,0.092210576,0.376745776,0.304711024,0.095853056,0.665704528,0.404352832,0.05967352,0.113128272,0.3088744,0.154473856,0.407306768,0.13002256,0.20255616,0.569847504,0.277328,0.404288544,0.141030464,0.523308992,0.652521152,0.255861968,0.54978408,0.417219472 +618.0,0.819203952,0.54299872,0.09283376,0.504417952,0.32602912,0.232656112,0.298498448,0.238330144,0.058316384,0.846949888,0.425502,0.61501776,0.238178448,0.483650256,0.550107056,0.2409272,0.221032112,0.312500288,0.527756704,0.645644224,0.882077184,0.742508256,0.824038848,0.864335088,0.510727792,0.890013248,0.448804576,0.118025024,0.764004304,0.34363088,0.788399728,0.467537072,0.785022448,0.281956608,0.109627648,0.554162944,0.133735952,0.669973888,0.080622016,0.180421856,0.672043952,0.26063616,0.314602672,0.048800704,0.15851128,0.249277248,0.316410336,0.329431984,0.092790176,0.146165024,0.192329648,0.068842032,0.059751008,0.503107712,0.449043744,0.172671904,0.07702416,0.054676704,0.539041472,0.649735952,0.393750416,0.30725144,0.0720476,0.097367648,0.05201744,0.057243504,0.066221536,0.223824704,0.190324096,0.290873248,0.046796928,0.44055272,0.131472096,0.044011216,0.042116784,0.108519792,0.086461344,0.091842608,0.37815376,0.306233008,0.096760736,0.66590192,0.404015664,0.059949648,0.11397632,0.316569488,0.155137296,0.410297408,0.1313828,0.20366392,0.572093024,0.28429376,0.408721088,0.14506592,0.53107792,0.659211728,0.255496304,0.550484672,0.426703216 +619.0,0.821592144,0.548583248,0.09541248,0.505062464,0.3381416,0.232470624,0.308848256,0.247551952,0.058373936,0.848395264,0.426878656,0.61873464,0.2404556,0.483883056,0.552462048,0.245290544,0.220892,0.314132768,0.527631936,0.653718912,0.882932992,0.744766528,0.824353504,0.864121776,0.51064736,0.890827952,0.448981872,0.118028624,0.765341408,0.344069744,0.789084096,0.46684728,0.78567936,0.281178912,0.109278752,0.554667952,0.132379856,0.670307904,0.080758704,0.181012592,0.672249424,0.258788768,0.314510544,0.048849312,0.15796704,0.247750544,0.315936704,0.32526624,0.092327936,0.146135824,0.19227496,0.068890128,0.059566432,0.501919104,0.448438224,0.171570944,0.07666056,0.05424016,0.538355008,0.650022944,0.393792864,0.307536912,0.071419664,0.09704264,0.05067568,0.057169792,0.066156608,0.224140992,0.190963328,0.291041568,0.046323664,0.44085648,0.130983056,0.044046896,0.041687072,0.108589952,0.0876084,0.0914192,0.379618944,0.307789552,0.098077776,0.666098752,0.403663776,0.060205616,0.114941008,0.324742416,0.155769696,0.413075888,0.13267976,0.20470896,0.574347824,0.29135992,0.413234992,0.149266896,0.538698448,0.665848544,0.2552104,0.551064544,0.43600456 +620.0,0.8239,0.554,0.0979,0.50567,0.35063,0.2323,0.319,0.25684,0.05843,0.84979,0.42833,0.6223,0.24254,0.4841,0.55469,0.2497,0.22077,0.3157,0.5275,0.66127,0.88378,0.74695,0.82467,0.8639,0.51055,0.8916,0.44909,0.11813,0.76667,0.34451,0.78978,0.4663,0.78627,0.28043,0.10894,0.55518,0.131,0.6706,0.08089,0.18157,0.6725,0.25696,0.3144,0.0489,0.15739,0.2463,0.3156,0.32117,0.0919,0.14618,0.19233,0.06894,0.0594,0.5009,0.44792,0.17054,0.0763,0.05385,0.5377,0.65032,0.39388,0.30778,0.0708,0.09675,0.04935,0.0571,0.0661,0.22444,0.19156,0.29121,0.0459,0.44114,0.13047,0.04408,0.0413,0.1087,0.08886,0.09095,0.38115,0.30938,0.09978,0.6663,0.4033,0.06044,0.11603,0.33339,0.15638,0.41563,0.13391,0.2057,0.57661,0.2985,0.41783,0.15364,0.54614,0.67241,0.255,0.55154,0.4451 +621.0,0.826128608,0.559250848,0.100290832,0.50624032,0.363459728,0.232156816,0.32892376,0.266176608,0.05848528,0.851150384,0.429860944,0.62572736,0.244434848,0.484302128,0.556798144,0.25415088,0.220676032,0.317205984,0.527361408,0.668301376,0.884620016,0.749061584,0.824989712,0.863668976,0.510427728,0.892330144,0.44912808,0.118319824,0.7679872,0.344955856,0.790486544,0.46590968,0.786797424,0.279709152,0.108611008,0.555692256,0.129597808,0.670847328,0.08101624,0.18209552,0.672801088,0.255156832,0.31426112,0.048952608,0.156786288,0.244922368,0.315411696,0.317144672,0.091506672,0.146297936,0.192496576,0.068991984,0.05924976,0.500040976,0.4474836,0.169572048,0.075937888,0.053502208,0.53707208,0.650626752,0.394011696,0.307980224,0.07019016,0.096486816,0.048039808,0.057033584,0.066050208,0.224722192,0.19211568,0.291378096,0.045524144,0.441403088,0.129938704,0.04411008,0.040955104,0.108851808,0.090219712,0.090442384,0.382759776,0.311006944,0.101889008,0.666507056,0.402934352,0.060653616,0.117242352,0.342500352,0.156974944,0.417959136,0.135076176,0.206642016,0.578869472,0.305706704,0.422505984,0.158182768,0.553397328,0.67888776,0.254862624,0.551929968,0.45397736 +622.0,0.828278992,0.564336,0.10255904,0.506772432,0.3765976,0.232053472,0.338588528,0.275543424,0.058540464,0.852496048,0.43147664,0.62903896,0.246140608,0.484490256,0.558792576,0.2586396,0.220619952,0.318654208,0.527216384,0.674813984,0.885456624,0.751103136,0.825313568,0.863427968,0.510279232,0.893018448,0.449085136,0.118601824,0.769289824,0.34541856,0.791202928,0.465690432,0.787263168,0.279015808,0.108291408,0.556202704,0.128170192,0.671046848,0.081138016,0.182590416,0.673158272,0.25338592,0.314080832,0.049006784,0.15614368,0.243614688,0.315383856,0.313191824,0.091148496,0.146491104,0.192778128,0.069046352,0.059113728,0.499332432,0.447123504,0.168659344,0.07556832,0.053192704,0.536466592,0.650941552,0.394188256,0.3081356,0.06959152,0.096250048,0.04674432,0.056969744,0.066005616,0.224987584,0.192631856,0.291545088,0.045193408,0.44164544,0.129395296,0.044136736,0.040651504,0.109046752,0.091691424,0.089904048,0.38445992,0.312672288,0.104432816,0.66672272,0.402575104,0.060846928,0.11858992,0.352060848,0.157561456,0.420061328,0.13618032,0.20754056,0.581121424,0.31296888,0.427262368,0.16289432,0.56046152,0.685271488,0.254795744,0.552252352,0.462623216 +623.0,0.830352016,0.569265712,0.104757888,0.507270544,0.389987552,0.232006128,0.347969216,0.28492344,0.058595168,0.853824432,0.433178736,0.63218416,0.247671808,0.484665264,0.560682288,0.26315696,0.220614432,0.320050912,0.5270664,0.680843072,0.886285872,0.753081888,0.825645984,0.86317552,0.510120336,0.893668032,0.449023232,0.118922224,0.770574768,0.345873104,0.791926432,0.465659104,0.787680112,0.278347264,0.107980368,0.556688032,0.126726736,0.671199648,0.081254832,0.183056352,0.673578656,0.251658688,0.313862304,0.04906256,0.155508592,0.242370448,0.315526736,0.309311936,0.0908252,0.146753712,0.19316408,0.0691036,0.058990656,0.498761808,0.446833568,0.16779688,0.075195792,0.05291792,0.535877824,0.651268672,0.394406576,0.308253776,0.06900576,0.09603672,0.045463712,0.056908864,0.065964784,0.225238336,0.193110032,0.29171248,0.044903632,0.441868752,0.128847408,0.044160192,0.040387424,0.109282256,0.093278576,0.089344352,0.386273264,0.314381472,0.107325664,0.666942944,0.402243376,0.0610212,0.120013648,0.362053904,0.158140608,0.42194208,0.137230944,0.208397824,0.583335296,0.320292256,0.432101392,0.167763552,0.567346112,0.691560176,0.254793904,0.552528256,0.471030672 +624.0,0.83234864,0.574056224,0.106981136,0.507741536,0.403561584,0.232032784,0.357046304,0.294300976,0.058648512,0.855118896,0.434966512,0.63508216,0.249052048,0.484828192,0.56247824,0.26769048,0.220673472,0.321403936,0.526913696,0.68644376,0.88709896,0.75500816,0.8259932,0.862909952,0.50996968,0.894283936,0.449038128,0.119196864,0.771839152,0.346277728,0.792653216,0.465833536,0.788067456,0.27769968,0.107676848,0.55711456,0.12528576,0.671309648,0.081365648,0.183495488,0.67407008,0.249989216,0.313619296,0.049120256,0.154958944,0.241181248,0.315849056,0.305504688,0.090535904,0.14707576,0.193635872,0.069164528,0.058879744,0.498315264,0.446607632,0.166981696,0.074830784,0.052674736,0.535300416,0.651616192,0.394661696,0.308348432,0.06843472,0.095844192,0.044198784,0.056852064,0.065926592,0.225478128,0.193552048,0.291883312,0.044650496,0.442076064,0.12830312,0.044181088,0.040160864,0.10955424,0.094983888,0.088773216,0.388228528,0.316142016,0.110434672,0.667160128,0.401967328,0.061178352,0.121421856,0.37245776,0.15871024,0.423612112,0.138240608,0.209213888,0.585468048,0.327692912,0.437026576,0.172773264,0.574078864,0.697759024,0.254850464,0.55278048,0.479197568 +625.0,0.83427,0.57872,0.10928,0.50819,0.41726,0.23215,0.3658,0.30366,0.0587,0.85637,0.43684,0.63769,0.2503,0.48498,0.56419,0.27223,0.22081,0.32272,0.52676,0.69166,0.88789,0.75689,0.82636,0.86263,0.50984,0.89487,0.44919,0.11937,0.77308,0.34661,0.79338,0.46623,0.78844,0.27707,0.10738,0.55746,0.12386,0.67138,0.08147,0.18391,0.67464,0.24839,0.31336,0.04918,0.15454,0.24004,0.31636,0.30177,0.09028,0.14745,0.19418,0.06923,0.05878,0.49798,0.44644,0.16621,0.07448,0.05246,0.53473,0.65199,0.39495,0.30843,0.06788,0.09567,0.04295,0.0568,0.06589,0.22571,0.19396,0.29206,0.04443,0.44227,0.12777,0.0442,0.03997,0.10986,0.09681,0.0882,0.39035,0.31796,0.11368,0.66737,0.40177,0.06132,0.12276,0.38325,0.15927,0.42508,0.13922,0.20999,0.58749,0.33518,0.44204,0.17791,0.58068,0.70387,0.25496,0.55303,0.48712 +626.0,0.83611792,0.583258304,0.111635264,0.508616192,0.431047888,0.232370304,0.374209824,0.31298336,0.058750416,0.857589856,0.438801424,0.640024624,0.251419392,0.485121728,0.565822816,0.27677224,0.221033696,0.324002432,0.52660528,0.696502016,0.888661744,0.758728464,0.826746704,0.862335776,0.509741184,0.895426592,0.449470064,0.119451664,0.774294528,0.346879712,0.79410528,0.466860224,0.788799184,0.276457408,0.107089488,0.557727808,0.122445504,0.671411328,0.0815688,0.184302176,0.675294432,0.246868512,0.313076032,0.049241472,0.154237904,0.23894368,0.317069888,0.298108544,0.090057408,0.147877184,0.194797968,0.06930096,0.058689952,0.497746368,0.446326544,0.165475696,0.07413872,0.052270512,0.534165024,0.652389376,0.395271616,0.308499424,0.067342272,0.095512016,0.041717152,0.056752128,0.065854144,0.225935456,0.194336528,0.292243232,0.044239008,0.442451664,0.127254192,0.04421712,0.03981328,0.110201024,0.098760096,0.087632288,0.39264872,0.31983744,0.117069744,0.667578496,0.401659232,0.06144696,0.124029776,0.394406192,0.159824672,0.426347968,0.140174048,0.210730688,0.589401968,0.342743408,0.447139376,0.18317168,0.587147232,0.70988568,0.255121024,0.553292272,0.4947888 +627.0,0.837894816,0.587672912,0.114056928,0.509021984,0.444890832,0.232706128,0.382261616,0.3222548,0.058800768,0.858786592,0.440851456,0.64208128,0.252415808,0.485254784,0.567381648,0.28131408,0.221353872,0.325254432,0.52644928,0.700983552,0.889416272,0.760524048,0.827153104,0.862028,0.509690736,0.895954352,0.449883712,0.119447104,0.775480528,0.347085584,0.794827312,0.467734464,0.789145952,0.275861024,0.106805008,0.557921072,0.121038816,0.671406048,0.081662992,0.184674992,0.676039296,0.245432288,0.312761824,0.04930448,0.154056672,0.237889488,0.317987776,0.294520496,0.08986752,0.148357712,0.19549064,0.06937872,0.058608416,0.497605088,0.446264128,0.16477384,0.073802512,0.0521036,0.533605984,0.652814192,0.395626576,0.308559296,0.06682176,0.09536864,0.040500512,0.056708144,0.065818624,0.226157056,0.194684912,0.29243456,0.044074672,0.442622752,0.126761568,0.044232832,0.039688944,0.110579536,0.100837136,0.087077232,0.395134864,0.321776512,0.120579744,0.667793504,0.401642256,0.0615604,0.125205408,0.405895664,0.160378128,0.42742072,0.141109024,0.211439824,0.591204256,0.350374496,0.452321312,0.188555792,0.593481872,0.715800576,0.255333104,0.553581456,0.502197312 +628.0,0.839600912,0.59197552,0.116452592,0.509405296,0.458728896,0.233173552,0.389929008,0.33145752,0.05885008,0.859954848,0.442991808,0.643945936,0.253306384,0.48537912,0.56887664,0.28584536,0.221783888,0.326482912,0.5262944,0.705145488,0.89014856,0.762285712,0.827584704,0.861704544,0.509664048,0.896456592,0.45040136,0.119344304,0.776633488,0.347267776,0.795542864,0.468870144,0.78949592,0.27527808,0.106525808,0.558034736,0.119652048,0.671365968,0.081752784,0.185029808,0.67688272,0.244094304,0.312422496,0.049368768,0.153946,0.236869856,0.319124624,0.291006208,0.089710832,0.1488852,0.196245472,0.069464,0.05853392,0.497542928,0.446245712,0.164099104,0.073477984,0.051955488,0.533046784,0.653269808,0.396011936,0.308617888,0.066320928,0.095237264,0.039299392,0.05666808,0.065782064,0.226376016,0.195007056,0.292635248,0.043932896,0.44278584,0.126299744,0.044247904,0.039595888,0.110991968,0.103042416,0.086544816,0.397833488,0.323782624,0.124304784,0.668008352,0.4017424,0.06166136,0.12637016,0.417702336,0.160931504,0.428304192,0.14203456,0.21211976,0.592886864,0.358077904,0.457589088,0.194049024,0.599700352,0.721614112,0.255589184,0.55391992,0.509339184 +629.0,0.841235648,0.596181088,0.118676656,0.509761888,0.47249368,0.233789776,0.39718152,0.34057456,0.058896672,0.861084784,0.44522456,0.645752672,0.25411216,0.485494096,0.570319712,0.2903536,0.222338464,0.327696032,0.526144,0.709037824,0.890851248,0.764025296,0.828048944,0.861362288,0.50961752,0.896937472,0.450969168,0.119131984,0.777747968,0.347488848,0.796248176,0.470287024,0.789869648,0.274705216,0.106251008,0.55806384,0.11830248,0.671292768,0.081838256,0.185367424,0.677833664,0.24286944,0.312066688,0.049434016,0.153824528,0.235875584,0.320492112,0.28756608,0.089588304,0.149451088,0.197045504,0.06955736,0.058464864,0.497545328,0.446262896,0.163445968,0.073175456,0.051822016,0.532479184,0.653763424,0.396423856,0.30868528,0.065843056,0.095115008,0.038112672,0.056632016,0.065742784,0.226592976,0.19530448,0.292846416,0.0438092,0.442943888,0.12587688,0.044263296,0.039533312,0.1114328,0.105376416,0.086046,0.400774592,0.325862176,0.128403024,0.66821144,0.401988304,0.0617508,0.127662032,0.429815008,0.16148512,0.429004704,0.142961456,0.212772416,0.594439552,0.365862192,0.462948224,0.199634416,0.605824112,0.727327248,0.255879904,0.554332784,0.516208176 +630.0,0.8428,0.6003,0.12064,0.51009,0.48613,0.23457,0.404,0.34959,0.05894,0.86217,0.44755,0.64759,0.25485,0.4856,0.57172,0.29483,0.22303,0.3289,0.526,0.7127,0.89152,0.76575,0.82855,0.861,0.50953,0.8974,0.45155,0.11881,0.77882,0.34779,0.79694,0.472,0.79028,0.27414,0.10598,0.55801,0.117,0.67119,0.08192,0.18569,0.6789,0.24177,0.3117,0.0495,0.15364,0.2349,0.3221,0.2842,0.0895,0.15005,0.19788,0.06966,0.0584,0.4976,0.44631,0.16281,0.0729,0.0517,0.5319,0.6543,0.39686,0.30877,0.06539,0.095,0.03694,0.0566,0.0657,0.22681,0.19558,0.29307,0.0437,0.4431,0.1255,0.04428,0.0395,0.1119,0.10784,0.08559,0.40398,0.32802,0.13297,0.6684,0.4024,0.06183,0.12916,0.44221,0.16204,0.42953,0.1439,0.2134,0.59586,0.37373,0.4684,0.2053,0.61187,0.73294,0.2562,0.55484,0.5228 +631.0,0.84429712,0.604334816,0.122362736,0.510392336,0.499606544,0.235526144,0.410382016,0.358489808,0.058981312,0.863212336,0.449966576,0.6494492,0.255528016,0.485698448,0.573081792,0.299272176,0.223867312,0.330097536,0.525861936,0.716150896,0.89215592,0.767459552,0.829086816,0.860619232,0.509408944,0.897845104,0.452145104,0.118378528,0.779848208,0.34816096,0.797616496,0.474015776,0.790727104,0.273581616,0.105712576,0.557877392,0.115742576,0.671061616,0.081999216,0.186001344,0.680087328,0.240803344,0.31131976,0.04956664,0.15340296,0.233940784,0.323955008,0.280907344,0.089444656,0.150681808,0.198748848,0.069773744,0.05833864,0.497699168,0.44638584,0.1621884,0.072647376,0.051587792,0.531313264,0.654880304,0.397320288,0.308877184,0.064961488,0.094891744,0.035782224,0.056571968,0.065654112,0.2270308,0.195837872,0.293308624,0.04360336,0.443256848,0.125174224,0.044298896,0.039494192,0.112396944,0.110435328,0.085182912,0.407457408,0.330258304,0.137985104,0.668584608,0.402983184,0.061900512,0.130841456,0.45484664,0.162598656,0.429889456,0.144858592,0.214005424,0.597151312,0.38167144,0.473939152,0.21104264,0.617844784,0.738449936,0.256550672,0.555453104,0.529112864 +632.0,0.845729552,0.60828968,0.123842592,0.510670496,0.512889856,0.236670592,0.416323328,0.3672604,0.05902144,0.864212368,0.452473488,0.651336736,0.256155264,0.48579056,0.57441,0.30367696,0.224860048,0.331291712,0.52572984,0.719412448,0.89275912,0.769155232,0.829659344,0.860220864,0.509240688,0.898274032,0.45274496,0.117825584,0.780830928,0.348592496,0.798275984,0.476341504,0.79121352,0.27302904,0.105448448,0.557664976,0.114531328,0.670909568,0.082076944,0.186304608,0.68140128,0.239977264,0.310922896,0.049633808,0.15311456,0.232994976,0.326063984,0.277687648,0.089421312,0.1513452,0.199649792,0.06990008,0.05828008,0.497835248,0.446488832,0.161578464,0.072414784,0.051483648,0.530721584,0.655505808,0.397804016,0.309012608,0.064557808,0.094789584,0.034639952,0.05654784,0.065605264,0.227258336,0.196081776,0.293564448,0.043517456,0.44341696,0.124904784,0.044320944,0.039514448,0.112925888,0.113164416,0.084830976,0.411216128,0.332579744,0.143462784,0.668772672,0.40374592,0.06196368,0.13271872,0.467688096,0.163163264,0.430092832,0.14584576,0.21459144,0.598312224,0.389675904,0.479561648,0.216857664,0.623756672,0.743855152,0.256931904,0.55618472,0.535145264 +633.0,0.847103744,0.612161584,0.125133248,0.510929776,0.525958448,0.23801264,0.42184112,0.375887872,0.059063488,0.86516912,0.4550632,0.653246992,0.256740112,0.485880032,0.575706128,0.308045584,0.226013024,0.332483648,0.525601264,0.7224988,0.89333352,0.770829792,0.830261632,0.859810096,0.509102672,0.89868672,0.453346656,0.11722936,0.781768128,0.349099552,0.798915312,0.478978832,0.791728976,0.272482384,0.10518792,0.55741392,0.11335248,0.67074984,0.082155792,0.186607472,0.682847712,0.239298064,0.310513712,0.049701616,0.15278096,0.232063008,0.32843112,0.274538592,0.089427008,0.152044592,0.200590336,0.070043136,0.05822408,0.498000368,0.446621024,0.160978928,0.072192992,0.051387264,0.530139104,0.656175712,0.398313984,0.309181632,0.064175968,0.094695104,0.03351528,0.056527712,0.065555936,0.227500672,0.19632,0.293843392,0.043440672,0.443585312,0.124695584,0.044347472,0.039557824,0.113496032,0.116027984,0.08453904,0.415255568,0.334984544,0.149320064,0.668990896,0.404682896,0.062022368,0.134684864,0.480665952,0.163736432,0.430152768,0.146872368,0.215160736,0.599381456,0.397736288,0.485255184,0.222746928,0.62961368,0.749154368,0.257351296,0.557039536,0.540899344 +634.0,0.848428256,0.615943168,0.126327104,0.511177696,0.53880008,0.239559648,0.426965472,0.384358624,0.059111856,0.866081792,0.457724752,0.655157168,0.25728944,0.485971904,0.576969376,0.312382288,0.22732832,0.333673024,0.525472288,0.725417792,0.89388552,0.772470992,0.83088424,0.859394528,0.509115616,0.899082208,0.453953392,0.116709136,0.782660928,0.349700928,0.79953088,0.48192544,0.792255472,0.271942528,0.104931632,0.557185184,0.112183872,0.670604832,0.0822392,0.186919936,0.684432224,0.238770624,0.310098688,0.049770304,0.15241816,0.23114752,0.331058816,0.271456896,0.089457664,0.152787744,0.20158392,0.070208352,0.05817072,0.498187328,0.446786896,0.160389552,0.07196848,0.05129928,0.529586464,0.656887616,0.398854912,0.309389056,0.063811168,0.094611184,0.032411168,0.056511744,0.065509888,0.227768448,0.196563184,0.294153216,0.043371808,0.443767984,0.124549584,0.04438,0.03962064,0.114120576,0.119026272,0.084310784,0.419568368,0.337471424,0.155417584,0.6692768,0.405780512,0.062080176,0.136568048,0.493694448,0.16432112,0.430083744,0.147950176,0.215716032,0.600417168,0.405844912,0.49100264,0.228716512,0.635422528,0.754346384,0.257820928,0.558017232,0.546379584 +635.0,0.84971,0.61963,0.12749,0.51142,0.5514,0.24132,0.43172,0.39266,0.05917,0.86695,0.46045,0.65705,0.25781,0.48607,0.5782,0.31669,0.22881,0.33486,0.52534,0.72818,0.89442,0.77407,0.83152,0.85898,0.50935,0.89946,0.45456,0.11634,0.78351,0.3504,0.80012,0.48518,0.79278,0.27141,0.10468,0.55702,0.11101,0.67049,0.08233,0.18725,0.68616,0.2384,0.30968,0.04984,0.15204,0.23025,0.33395,0.26844,0.08951,0.15358,0.20264,0.0704,0.05812,0.49839,0.44699,0.15981,0.07173,0.05122,0.52908,0.65764,0.39943,0.30964,0.06346,0.09454,0.03133,0.0565,0.06547,0.22807,0.19682,0.2945,0.04331,0.44397,0.12447,0.04442,0.0397,0.11481,0.12216,0.08415,0.42415,0.34004,0.16167,0.66966,0.40703,0.06214,0.13826,0.5067,0.16492,0.4299,0.14909,0.21626,0.60146,0.41399,0.49679,0.23477,0.64119,0.75943,0.25835,0.55912,0.55159 +636.0,0.850951072,0.623226592,0.128616528,0.511657264,0.563735872,0.24330544,0.43610896,0.400782176,0.059238416,0.867774368,0.463239216,0.658938976,0.258308464,0.486174784,0.579401376,0.320967776,0.230468112,0.336046176,0.525204608,0.730804416,0.894937056,0.775628144,0.83216864,0.858567328,0.509783472,0.899821248,0.45515176,0.116114624,0.784314928,0.351191184,0.800682784,0.488744224,0.793304464,0.270884416,0.104432976,0.556916656,0.109835264,0.670404928,0.082428912,0.187599856,0.688034688,0.238191648,0.309246816,0.049910688,0.151641488,0.229368704,0.337108864,0.26548744,0.089583008,0.154419536,0.20375576,0.070618816,0.058071872,0.49860528,0.447230896,0.159239712,0.071473184,0.051148912,0.528622976,0.65843392,0.400038064,0.309940816,0.063123024,0.094481744,0.030272512,0.056492512,0.065436672,0.22840704,0.197093008,0.294884848,0.043255264,0.444193072,0.124460432,0.044468928,0.039795392,0.115566496,0.125429472,0.08406096,0.42900432,0.342692816,0.168100864,0.670146464,0.408437184,0.062202752,0.139796688,0.519645584,0.165534784,0.429614912,0.150299952,0.216794912,0.602509728,0.422156384,0.502612592,0.240903456,0.646923088,0.764404112,0.25893936,0.560357552,0.556533312 +637.0,0.852153264,0.626737664,0.129708368,0.511889696,0.575791888,0.24552752,0.44014048,0.408717392,0.059317328,0.86855624,0.4660936,0.660841072,0.258789792,0.486286432,0.580575968,0.325215984,0.232313024,0.337232288,0.525066464,0.7333076,0.8954368,0.777146832,0.832829872,0.858157296,0.510413072,0.90016712,0.455721776,0.1160456,0.785076128,0.352083072,0.801220512,0.492616912,0.793830416,0.270365824,0.10419072,0.55687792,0.10866592,0.67034936,0.082536272,0.187971072,0.690058592,0.238149504,0.308783072,0.049982496,0.1512132,0.228502688,0.34053808,0.262598832,0.089675648,0.155304272,0.204928016,0.070864976,0.05802672,0.498832608,0.447511184,0.158679248,0.071192672,0.051086224,0.528218544,0.659270032,0.400677664,0.310298032,0.062800928,0.094437024,0.02923952,0.056489472,0.065410416,0.228780512,0.19738384,0.295308112,0.043208592,0.444438192,0.124523424,0.044528512,0.039906864,0.116392032,0.128833424,0.08404688,0.434132048,0.345432464,0.174710144,0.670740976,0.410006736,0.062269088,0.141204144,0.532495312,0.166166992,0.429243488,0.151587648,0.217322736,0.603569616,0.430329728,0.508465584,0.247113488,0.65262736,0.769267808,0.259590336,0.561738096,0.561214304 +638.0,0.853323536,0.630158256,0.130807408,0.512123088,0.587546864,0.24799424,0.44383424,0.416450928,0.05941072,0.869294992,0.469004144,0.662707248,0.25926184,0.48640848,0.58172504,0.329436112,0.234348416,0.33841936,0.52492232,0.735702144,0.895924544,0.77861728,0.833496384,0.857755264,0.511174112,0.900496592,0.456225952,0.116087776,0.785792928,0.35299024,0.8017292,0.49679952,0.794345328,0.269854032,0.103953024,0.556908064,0.107484736,0.670328672,0.082655872,0.188371888,0.692238816,0.2382804,0.308296368,0.050055024,0.150798112,0.227652192,0.344242736,0.259771664,0.089784928,0.156239648,0.206167232,0.071143376,0.057983728,0.499063696,0.447833792,0.158127024,0.07087808,0.051031136,0.527883472,0.660147344,0.401351904,0.310716048,0.062490592,0.094407344,0.028233168,0.056490272,0.06539368,0.229198944,0.197702512,0.295776496,0.0431684,0.444711392,0.124664016,0.044599696,0.040030896,0.117297568,0.132377856,0.08411232,0.439532016,0.348258032,0.181542384,0.671474208,0.411730848,0.062341904,0.14247696,0.5451744,0.16681968,0.428798624,0.152964144,0.21784696,0.604653424,0.438479632,0.514335056,0.2534032,0.658310992,0.774019504,0.260311072,0.56326536,0.565634736 +639.0,0.854470528,0.633480128,0.131966128,0.51236504,0.59897784,0.25071232,0.44721376,0.423965744,0.059523872,0.869989424,0.471958448,0.664461744,0.259733328,0.486545488,0.582849472,0.33363,0.236575728,0.339608512,0.524767696,0.737999248,0.896407408,0.780027328,0.834158496,0.857368032,0.511962032,0.900807824,0.456602608,0.116160032,0.786464208,0.353783488,0.802203088,0.501294368,0.794832,0.26934872,0.103719488,0.557006448,0.106266672,0.670348464,0.082792752,0.188812704,0.69458416,0.238592176,0.307802224,0.050127632,0.150460784,0.226817776,0.348228832,0.257002736,0.089907248,0.157233584,0.207488528,0.071460496,0.057941616,0.499287744,0.44820216,0.15758072,0.070517328,0.050982448,0.52763912,0.661064336,0.402065344,0.311198464,0.062187696,0.094394464,0.027256016,0.056493952,0.065389504,0.229673296,0.198061904,0.2962988,0.043132288,0.445020432,0.124888208,0.04468312,0.040162768,0.118297104,0.136071808,0.08426224,0.445202464,0.35116736,0.188674704,0.67238544,0.41359752,0.0624248,0.143614736,0.557595088,0.167496448,0.42829256,0.1544416,0.218371664,0.605774512,0.446567376,0.520204048,0.259777872,0.663983024,0.77865736,0.261111888,0.564941584,0.569795328 +640.0,0.8556,0.6367,0.13322,0.51262,0.61007,0.25369,0.4503,0.43125,0.05966,0.87064,0.47495,0.66606,0.26021,0.4867,0.58395,0.3378,0.239,0.3408,0.5246,0.74021,0.89689,0.78137,0.83481,0.857,0.5127,0.9011,0.45681,0.11621,0.78709,0.35438,0.80264,0.5061,0.79528,0.26885,0.10349,0.55717,0.105,0.67041,0.08295,0.1893,0.6971,0.23909,0.3073,0.0502,0.15024,0.226,0.3525,0.25429,0.09004,0.15829,0.2089,0.07182,0.0579,0.4995,0.44862,0.15704,0.0701,0.05094,0.5275,0.66202,0.40282,0.31175,0.06189,0.0944,0.02631,0.0565,0.0654,0.23021,0.19847,0.29688,0.0431,0.44537,0.1252,0.04478,0.0403,0.1194,0.13992,0.0845,0.45114,0.35416,0.19616,0.6735,0.4156,0.06252,0.14464,0.56969,0.1682,0.42774,0.15603,0.2189,0.60694,0.45456,0.52606,0.26624,0.66965,0.78318,0.262,0.56677,0.5737 +641.0,0.856713056,0.639822816,0.1345716,0.5128872,0.620819136,0.256937568,0.45310704,0.43829992,0.059818816,0.871249152,0.477981616,0.667495296,0.260693536,0.486871456,0.585027648,0.341948272,0.241631648,0.341993248,0.524419776,0.742346368,0.897372496,0.782647168,0.83545064,0.856651408,0.513397168,0.901374096,0.456852768,0.116248736,0.787672192,0.354791104,0.803042832,0.511209344,0.795690528,0.268358576,0.103264864,0.557400832,0.103695072,0.670512112,0.083127376,0.18983368,0.69978608,0.239774352,0.306766736,0.050272304,0.150130944,0.2251992,0.35705616,0.251633184,0.090182272,0.159405776,0.210397344,0.072220912,0.057859808,0.49970464,0.449090512,0.156507264,0.069620144,0.050905072,0.527467696,0.663014144,0.403613552,0.312377296,0.061598528,0.094425008,0.025395952,0.056508672,0.065425584,0.230808032,0.19892664,0.29751872,0.043074496,0.445759584,0.12560008,0.044892448,0.040443744,0.12060712,0.14391888,0.08482656,0.457339136,0.357238288,0.203974272,0.674820064,0.417740704,0.062627568,0.145567424,0.581427696,0.168931056,0.427158784,0.157735696,0.219433248,0.608152784,0.4624424,0.531897904,0.272786976,0.675314432,0.787586784,0.262976512,0.568755744,0.577356928 +642.0,0.857811616,0.642851856,0.136023728,0.513166608,0.631219744,0.260464,0.45564976,0.445110768,0.06000056,0.871818592,0.481054304,0.668729248,0.26118616,0.48705984,0.58608344,0.346076592,0.244479456,0.343188,0.52422696,0.744419664,0.897855824,0.78385928,0.836079104,0.856322944,0.514067552,0.901630672,0.456736912,0.116273056,0.788212608,0.35501408,0.80341312,0.51661528,0.796062688,0.267875072,0.103044224,0.557703264,0.102358976,0.670656672,0.083325152,0.190414368,0.702642656,0.24064544,0.306186048,0.050344544,0.150142032,0.224415872,0.361897456,0.249031584,0.090332928,0.160578528,0.211977872,0.072662896,0.057821648,0.499904496,0.449616672,0.155984384,0.06907224,0.050878656,0.527544592,0.664046144,0.404444144,0.313086608,0.061313632,0.094470464,0.024514848,0.056520032,0.0654668,0.231467264,0.199432832,0.298214336,0.0430584,0.446189232,0.126089376,0.045022416,0.040594656,0.121920048,0.148065456,0.08524288,0.463793536,0.360403792,0.212084784,0.676351728,0.420019888,0.062747904,0.14638232,0.59277264,0.16969008,0.426566144,0.159565344,0.21997264,0.609418544,0.470200432,0.537711376,0.27941704,0.680978832,0.791876944,0.264042752,0.57090288,0.580773456 +643.0,0.858892656,0.645798816,0.137575376,0.513453456,0.641285952,0.264283872,0.45794672,0.451686736,0.060202544,0.872355552,0.484180032,0.66986048,0.261683344,0.487261264,0.587116672,0.350191152,0.247560944,0.344380672,0.524024624,0.7464392,0.898337632,0.785014192,0.836699168,0.85601248,0.514623856,0.901871888,0.456446176,0.116290496,0.788714544,0.355070176,0.803761408,0.522304976,0.796405488,0.267401088,0.102829024,0.558047056,0.10101896,0.670820752,0.083540848,0.191037456,0.705665312,0.241702048,0.3054984,0.050417504,0.15023136,0.223650864,0.367020512,0.246486944,0.090492144,0.16180152,0.21363072,0.07314136,0.057788208,0.500114592,0.450205072,0.155477984,0.068446496,0.05086424,0.527729168,0.665116864,0.405306736,0.31388592,0.061039696,0.09453832,0.023666944,0.056534912,0.065523456,0.232180976,0.199982304,0.298960832,0.043058224,0.44665504,0.126666272,0.045172944,0.040756928,0.123336576,0.152354512,0.08574752,0.470495056,0.363661536,0.220561616,0.678078992,0.422446112,0.06287896,0.147289856,0.603711984,0.170478624,0.425985904,0.161522832,0.220519552,0.610712624,0.477799024,0.543500528,0.286125344,0.686642832,0.796050544,0.265199312,0.573217856,0.583965024 +644.0,0.859950176,0.648680416,0.139218224,0.513739984,0.65104304,0.268414464,0.46001744,0.458037504,0.060420208,0.872870112,0.4873772,0.671051872,0.262176688,0.487469568,0.588125824,0.354300192,0.250898352,0.345565984,0.523817728,0.748413216,0.89881344,0.786124464,0.837317792,0.855715936,0.51494408,0.902100864,0.45596136,0.116319776,0.78918232,0.355003632,0.804103136,0.528261792,0.796734128,0.266938784,0.102620624,0.558386288,0.099714944,0.670969632,0.083770224,0.191694864,0.708846528,0.242941376,0.304621152,0.050492384,0.150329008,0.222905216,0.372419648,0.244002384,0.09066096,0.163064912,0.215339408,0.073649024,0.057763328,0.500357088,0.450863952,0.154997344,0.067731872,0.050866704,0.528016064,0.666227904,0.406194128,0.314784272,0.06078344,0.094630896,0.022852,0.056554592,0.065594752,0.232938208,0.200564176,0.299748688,0.043082848,0.447150448,0.127327408,0.045347712,0.04093696,0.124851424,0.156778528,0.08633744,0.477434016,0.36701848,0.229510528,0.679972256,0.425032896,0.063017216,0.148594032,0.614248848,0.171298368,0.425445504,0.16361016,0.221075104,0.611995424,0.485195936,0.54926952,0.292904928,0.692303952,0.800108144,0.266445472,0.575708272,0.586951552 +645.0,0.86098,0.65151,0.14094,0.51402,0.66051,0.27287,0.46188,0.46417,0.06065,0.87337,0.49066,0.67239,0.26266,0.48768,0.58911,0.35841,0.25451,0.34674,0.52361,0.75035,0.89928,0.7872,0.83794,0.85543,0.51496,0.90232,0.45528,0.11637,0.78962,0.35485,0.80445,0.53447,0.79706,0.26649,0.10242,0.55869,0.09848,0.67108,0.08401,0.19238,0.71218,0.24436,0.30349,0.05057,0.15039,0.22218,0.37809,0.24158,0.09084,0.16436,0.21709,0.07418,0.05775,0.50065,0.4516,0.15455,0.06692,0.05089,0.5284,0.66738,0.4071,0.31579,0.06055,0.09475,0.02207,0.05658,0.06568,0.23373,0.20117,0.30057,0.04314,0.44767,0.12807,0.04555,0.04114,0.12646,0.16133,0.08701,0.4846,0.37048,0.23898,0.68201,0.42779,0.06316,0.15049,0.62438,0.17215,0.42497,0.16583,0.22164,0.61324,0.49236,0.55502,0.29975,0.69796,0.80405,0.26778,0.57838,0.58975 +646.0,0.86198352,0.654290688,0.142740544,0.514292656,0.66968688,0.277655296,0.463548128,0.47008312,0.060891312,0.873855968,0.494030096,0.67385696,0.263133968,0.487892032,0.590070432,0.362520832,0.25840224,0.347902656,0.52340144,0.752258304,0.899737648,0.788242592,0.83856488,0.855153632,0.514678768,0.902529792,0.454411344,0.116433664,0.79003136,0.354604752,0.804802336,0.540916608,0.797382992,0.26605544,0.102227232,0.558960576,0.097326624,0.671153232,0.084259584,0.19309112,0.715662816,0.245952352,0.302095552,0.05065024,0.15042488,0.221476224,0.384028832,0.239218928,0.091028368,0.165681808,0.218876112,0.074732368,0.057748736,0.500998688,0.452414992,0.154138336,0.066010368,0.050935232,0.528876,0.668571088,0.408020832,0.316909504,0.060340144,0.094896032,0.021321376,0.056611072,0.065779104,0.234553504,0.201798352,0.301421536,0.043233728,0.448211664,0.12889296,0.045781808,0.041367808,0.12815968,0.166003888,0.08776416,0.491980272,0.374046928,0.248917824,0.684194976,0.430715904,0.063307056,0.152944464,0.634083232,0.173031344,0.42457752,0.1681872,0.222213696,0.614449888,0.499281344,0.560745952,0.30665832,0.703609248,0.807875248,0.269200192,0.58123368,0.59236832 +647.0,0.862961936,0.657025456,0.144627776,0.514556976,0.678575712,0.282772672,0.46503408,0.475777616,0.061143024,0.874328032,0.497489392,0.67549904,0.263598864,0.488104944,0.591008752,0.366631712,0.262579824,0.349054112,0.523192064,0.754146,0.900186272,0.789254752,0.839191728,0.8548848,0.514076736,0.902730848,0.453352736,0.116511616,0.790421424,0.354261296,0.805159488,0.547585696,0.797703488,0.265635728,0.102042464,0.559196976,0.09627016,0.671187552,0.084517808,0.193825376,0.719290272,0.247709568,0.3004336,0.050733024,0.15043616,0.220795024,0.390231792,0.236918224,0.091225184,0.167024,0.22068912,0.07530328,0.057759968,0.501409392,0.453309632,0.153764864,0.065005616,0.05100344,0.529434688,0.669798224,0.408952256,0.31814936,0.060154976,0.09506904,0.020606144,0.056647712,0.065891696,0.235404496,0.202446384,0.302298592,0.043368624,0.44877232,0.129794112,0.046045104,0.041622688,0.129945296,0.170794832,0.08859808,0.499558816,0.377719776,0.259282656,0.686528192,0.433808272,0.06345776,0.155944896,0.643344144,0.173938704,0.424286464,0.170685712,0.222794592,0.615625984,0.505949504,0.566441568,0.313627264,0.709247552,0.811582864,0.270700912,0.584268176,0.594814384 +648.0,0.863911072,0.659727984,0.146533408,0.514805616,0.687193664,0.288239328,0.466357472,0.481258112,0.061402256,0.874794496,0.501051648,0.67708976,0.2640484,0.488314176,0.591923152,0.370750512,0.267063088,0.350190528,0.522985648,0.756021616,0.900623296,0.790245952,0.839825616,0.854621248,0.513288384,0.902924944,0.452190608,0.116580128,0.790792048,0.35388528,0.8055344,0.554464464,0.798032544,0.265233136,0.101866096,0.559394736,0.095340896,0.671181872,0.084782352,0.194576512,0.723058368,0.249632064,0.298434848,0.050818688,0.15042552,0.220137664,0.396696272,0.23467984,0.0914316,0.168378592,0.222517488,0.075888192,0.05778664,0.501899696,0.454292192,0.153436832,0.063894544,0.051098768,0.530075056,0.67106344,0.40988848,0.319517376,0.059998528,0.095270928,0.019925152,0.056690752,0.066016848,0.236275168,0.203107616,0.303195088,0.04355232,0.449347376,0.130771824,0.04634336,0.041909408,0.131814992,0.175690816,0.08950912,0.50732872,0.381503824,0.269969808,0.688989808,0.43707768,0.063610064,0.159469488,0.652151536,0.174874064,0.424121168,0.173328784,0.223384448,0.61675896,0.512357744,0.572108544,0.320651328,0.714875936,0.81517368,0.272283232,0.587491232,0.597105488 +649.0,0.864824928,0.662415552,0.14835576,0.515028896,0.695562976,0.294077504,0.467540384,0.486530448,0.061665568,0.8752664,0.504734544,0.67827024,0.264474016,0.488513888,0.592810592,0.374888112,0.271877632,0.351306784,0.522787232,0.757893792,0.90104536,0.791228032,0.840473584,0.854360656,0.512529552,0.90311416,0.45105392,0.1166032,0.791143872,0.353571104,0.805944592,0.561541152,0.7983848,0.264850544,0.101698528,0.559552096,0.094574112,0.671138512,0.085050576,0.195337008,0.726963424,0.25172344,0.296008336,0.050907632,0.1504008,0.219505504,0.403420352,0.232506656,0.091649536,0.169736944,0.224348736,0.076482064,0.057832512,0.50249104,0.455373552,0.15316304,0.062661392,0.051226416,0.530798864,0.672370496,0.410823184,0.321021712,0.05987568,0.095504176,0.0192796,0.056741312,0.06615336,0.23715648,0.203774448,0.304104544,0.043793536,0.449931712,0.131824656,0.046680576,0.042233568,0.133768048,0.1806768,0.09049424,0.515286144,0.385405872,0.28082976,0.691553024,0.440539008,0.063761488,0.16346064,0.660495248,0.175841264,0.424107872,0.176119376,0.223986144,0.617838576,0.518504544,0.57775112,0.327724032,0.72049728,0.818649216,0.273950272,0.590913568,0.599262112 +650.0,0.8657,0.6651,0.15003,0.51522,0.7037,0.3003,0.4686,0.4916,0.06193,0.87575,0.50855,0.67883,0.26487,0.4887,0.59367,0.37905,0.27704,0.3524,0.5226,0.75977,0.90145,0.79221,0.84114,0.8541,0.51194,0.9033,0.45003,0.11656,0.79148,0.35338,0.8064,0.5688,0.79877,0.26449,0.10154,0.55967,0.094,0.67106,0.08532,0.1961,0.731,0.25398,0.2931,0.051,0.15037,0.2189,0.4104,0.2304,0.09188,0.17109,0.22617,0.07708,0.0579,0.5032,0.45656,0.15295,0.0613,0.05139,0.5316,0.67372,0.41175,0.32267,0.05979,0.09577,0.01867,0.0568,0.0663,0.23804,0.20444,0.30502,0.0441,0.45052,0.13295,0.04706,0.0426,0.1358,0.18574,0.09155,0.52342,0.38943,0.29173,0.6942,0.4442,0.06391,0.16785,0.66837,0.17684,0.42427,0.17906,0.2246,0.61886,0.52439,0.58337,0.33484,0.72611,0.82201,0.2757,0.59454,0.6013 +651.0,0.8665372,0.667784016,0.151566096,0.515377504,0.711609872,0.306903248,0.469545888,0.496470608,0.062193744,0.876244016,0.51249904,0.678819264,0.265235904,0.48887168,0.59450344,0.383233264,0.282550576,0.353470896,0.522423952,0.761655968,0.901836608,0.793195152,0.841824544,0.853836176,0.511499504,0.903483024,0.449116272,0.116450064,0.791806704,0.353313824,0.806898448,0.576220432,0.799189024,0.264152192,0.101390624,0.559746176,0.093637296,0.670944032,0.085588784,0.196860832,0.735160368,0.256387712,0.28971776,0.0510956,0.150328208,0.218322576,0.417627904,0.228358672,0.09212232,0.172429504,0.227969744,0.077678032,0.057989328,0.50403336,0.457850256,0.15280024,0.05981864,0.051590416,0.532463264,0.675107632,0.412663456,0.324468864,0.059742656,0.096067744,0.018095792,0.056866624,0.066455792,0.238919616,0.20509968,0.305934912,0.044476976,0.451107616,0.134143936,0.047483712,0.043011728,0.137901136,0.19087264,0.092672976,0.531708816,0.393575888,0.30263728,0.696929056,0.448056944,0.064054544,0.172644768,0.67577552,0.177863984,0.424625616,0.182152736,0.22522312,0.619820816,0.530012032,0.588959776,0.341995904,0.731706224,0.825255008,0.277523024,0.59836616,0.60322672 +652.0,0.867336672,0.670471984,0.152964528,0.515499136,0.719299664,0.313884688,0.470388832,0.501146592,0.062454896,0.876748656,0.516583408,0.678212,0.2655704,0.489027696,0.595312272,0.387436672,0.288410768,0.354519568,0.522259648,0.763557216,0.902204416,0.794187312,0.842527776,0.853566768,0.511216784,0.903663904,0.448321248,0.116260368,0.792129008,0.35338936,0.80744024,0.583783104,0.799644064,0.263838176,0.101250576,0.559775136,0.093505376,0.670787312,0.085855152,0.197614752,0.739437008,0.258934784,0.285861248,0.051194288,0.1502648,0.217774624,0.425096832,0.22638192,0.09237616,0.173747712,0.229737088,0.078272352,0.05810112,0.504998576,0.459244112,0.152716912,0.058223024,0.051829008,0.533377136,0.67653,0.4135584,0.326424976,0.059735008,0.096397088,0.017556592,0.056941152,0.066619728,0.239789328,0.205748976,0.306843248,0.04492976,0.451690256,0.135402864,0.04795416,0.043471888,0.140062352,0.196065616,0.09385976,0.54013312,0.397843904,0.313543408,0.699735568,0.4521084,0.064193984,0.177897648,0.682711936,0.178908144,0.425193088,0.185399424,0.225853808,0.62071344,0.535370704,0.594516224,0.349187968,0.737279376,0.82838368,0.279411232,0.602389152,0.605051168 +653.0,0.868101824,0.673159712,0.15424144,0.515585328,0.726770896,0.321232208,0.471130656,0.505633136,0.062711168,0.877255056,0.520801536,0.677242976,0.265875216,0.489168432,0.596101664,0.39164848,0.29461408,0.35555,0.522104944,0.765477904,0.902552784,0.795189392,0.843246528,0.853284,0.511066144,0.903842464,0.447651184,0.116032912,0.792459712,0.353572656,0.808011552,0.591456656,0.800131904,0.26354736,0.101119328,0.559783696,0.093626176,0.670604272,0.08611624,0.198354512,0.743818288,0.261592176,0.281582096,0.051295296,0.150220272,0.217258272,0.43279656,0.224466368,0.09264008,0.17503096,0.231453552,0.078856912,0.058233712,0.506101952,0.460734368,0.152700144,0.056538288,0.05210488,0.534302768,0.677977728,0.414426064,0.328544768,0.05976736,0.096755072,0.017050752,0.05702256,0.066789904,0.2406396,0.206380672,0.307733824,0.045465024,0.452259616,0.136719472,0.048472048,0.043984208,0.142266608,0.201310992,0.095104464,0.548657104,0.40222992,0.324194336,0.70262608,0.456339936,0.064327104,0.183279168,0.689192832,0.179958064,0.42598936,0.188800992,0.226482256,0.621565824,0.540478016,0.600029872,0.356413792,0.742812368,0.831393232,0.28134512,0.606595264,0.606775696 +654.0,0.868838176,0.67583776,0.155430112,0.51563848,0.734021088,0.328926528,0.47176784,0.50993576,0.06296024,0.877749056,0.525148624,0.676295392,0.266154192,0.489295488,0.596878976,0.395850848,0.301147712,0.356568512,0.521956,0.767421152,0.902881392,0.796203072,0.84397528,0.852977632,0.510987664,0.904017984,0.44709992,0.115836416,0.792815616,0.353799472,0.808590304,0.599203328,0.800645584,0.263278224,0.100996,0.559813216,0.094021216,0.670417072,0.086368768,0.199071952,0.748290208,0.264321248,0.276965504,0.051397504,0.150256624,0.216776,0.440714848,0.222607056,0.09291192,0.176262928,0.233097296,0.079424752,0.058384064,0.507347808,0.462309424,0.152748096,0.054800832,0.052415712,0.53518736,0.679437936,0.415256128,0.3308344,0.059839152,0.097137216,0.016575872,0.057109248,0.066964,0.241459552,0.206986608,0.30859312,0.046089728,0.452805616,0.13808448,0.049037136,0.044552448,0.144492224,0.206601808,0.096399968,0.557235728,0.406727056,0.334237984,0.705614432,0.460729472,0.064452784,0.188296528,0.695239488,0.180994064,0.427029872,0.19235776,0.227094464,0.622422368,0.545352288,0.605488,0.363671856,0.74828224,0.834279664,0.283298688,0.610964336,0.608398464 +655.0,0.86955,0.6785,0.15656,0.51566,0.74105,0.33695,0.4723,0.51406,0.0632,0.87822,0.52962,0.67562,0.26641,0.48941,0.59765,0.40003,0.308,0.35758,0.52181,0.76939,0.90319,0.79723,0.84471,0.85264,0.51094,0.90419,0.44666,0.11571,0.79321,0.35403,0.80916,0.60699,0.80118,0.26303,0.10088,0.55989,0.09471,0.67024,0.08661,0.19976,0.75284,0.26709,0.27208,0.0515,0.15041,0.21633,0.44884,0.2208,0.09319,0.17743,0.23465,0.07997,0.05855,0.50874,0.46396,0.15286,0.05304,0.05276,0.53599,0.6809,0.41604,0.3333,0.05995,0.09754,0.01613,0.0572,0.06714,0.24224,0.20756,0.30941,0.04681,0.45332,0.13949,0.04965,0.04518,0.14672,0.21193,0.09774,0.56583,0.41133,0.34345,0.70871,0.46526,0.06457,0.19265,0.70087,0.182,0.42833,0.19607,0.22768,0.62331,0.55001,0.61088,0.37096,0.75367,0.83704,0.28525,0.61548,0.60992 +656.0,0.870237696,0.681150336,0.15762752,0.515649968,0.747864208,0.345289376,0.472736288,0.518011424,0.06342904,0.878668144,0.534211264,0.675174608,0.26664184,0.489511744,0.598416,0.404184432,0.315162144,0.358584896,0.521667328,0.77138712,0.903478368,0.798271552,0.845450976,0.852270912,0.510939056,0.904358912,0.446342496,0.1156516,0.793646128,0.354273632,0.8097208,0.614797664,0.801735648,0.262803904,0.10077168,0.560009152,0.095705888,0.670074,0.08683872,0.200415088,0.75745856,0.269886224,0.266944032,0.051602464,0.150680912,0.215921344,0.457161696,0.219044192,0.093473904,0.178526768,0.236104272,0.080489872,0.058731712,0.510280992,0.465683504,0.153038384,0.051263936,0.053138352,0.536705408,0.682360096,0.416774112,0.335947584,0.060100464,0.097962496,0.015712416,0.057294592,0.067316736,0.242976576,0.208097648,0.31018016,0.04762928,0.45379984,0.140932384,0.05031352,0.045868864,0.148938432,0.217284336,0.099120832,0.574419184,0.416038096,0.3518264,0.711908864,0.469929632,0.064677968,0.196372384,0.70609264,0.18297048,0.429905024,0.199938,0.228239232,0.624221088,0.55446112,0.616201824,0.378274096,0.758967984,0.839674656,0.287189152,0.62013704,0.611347936 +657.0,0.870901824,0.683792432,0.1586212,0.515610688,0.754469616,0.353925248,0.473085216,0.521796016,0.063646368,0.879094096,0.538914256,0.674961136,0.266849376,0.489601152,0.599178224,0.40831272,0.32261928,0.35958368,0.521528304,0.773413664,0.903746544,0.799327392,0.846198208,0.8518716,0.510994624,0.904525024,0.446163664,0.115685552,0.794126272,0.354523296,0.810272912,0.622608176,0.802311904,0.26260112,0.100671568,0.560170096,0.097018016,0.669925392,0.08705408,0.201034752,0.762136128,0.272698016,0.261586256,0.051704496,0.151091072,0.215550752,0.46566792,0.217338528,0.09376304,0.1795496,0.237455392,0.080982272,0.058929072,0.511970032,0.467475968,0.153285424,0.049481568,0.0535508,0.537332928,0.683814288,0.417455984,0.338782768,0.0602908,0.098403392,0.015322192,0.05739264,0.067493024,0.24366608,0.208597152,0.310900464,0.048549664,0.454243216,0.142408192,0.051030768,0.046620128,0.151135168,0.222652912,0.100538784,0.582982464,0.42085016,0.359312656,0.71520792,0.474736336,0.064776144,0.199401328,0.710918912,0.183900304,0.4317684,0.203961392,0.228774016,0.625154144,0.558718896,0.621449552,0.385609872,0.764168048,0.842184752,0.2891056,0.624929104,0.612689136 +658.0,0.871546752,0.686420208,0.15962152,0.515538048,0.760866464,0.36284712,0.473346784,0.525418928,0.063849296,0.879486048,0.543728288,0.674977424,0.267034752,0.48967864,0.599942128,0.412400848,0.330366896,0.360581584,0.52138992,0.775474448,0.90399448,0.800401232,0.84694824,0.851433488,0.511068432,0.904687776,0.446066032,0.115729344,0.794663616,0.35480384,0.810799984,0.630387168,0.80290472,0.262421456,0.100578736,0.56036688,0.098670304,0.669782544,0.0872532,0.201610336,0.766860656,0.275493328,0.25606512,0.051805328,0.151571552,0.21522128,0.474349184,0.215679024,0.094056256,0.180482912,0.238681632,0.081440992,0.059140672,0.513814192,0.469330032,0.153600544,0.04772152,0.053997088,0.537827088,0.685252,0.418076256,0.341812112,0.060520096,0.098860128,0.014957808,0.057493408,0.067666992,0.244298704,0.209052016,0.311559248,0.049579008,0.454641152,0.1439092,0.051802416,0.047438672,0.153291344,0.228028048,0.101987536,0.591480704,0.425761504,0.366060592,0.718615536,0.47966344,0.06486336,0.202025632,0.715364224,0.184772848,0.433937136,0.208140784,0.22927224,0.62609424,0.562798512,0.626612,0.392965408,0.769252832,0.844565968,0.290978368,0.629841408,0.613944896 +659.0,0.87217816,0.689024304,0.1607468,0.515425248,0.767053072,0.372047632,0.473518112,0.52888504,0.064034544,0.87982792,0.5486552,0.675185152,0.267200928,0.489744608,0.600714512,0.416430576,0.338404112,0.361585488,0.521248016,0.777575552,0.904222176,0.801498192,0.847696512,0.850944816,0.51110568,0.904846288,0.44596008,0.115648976,0.7952748,0.355158784,0.811280176,0.6380948,0.803508896,0.262264352,0.100491744,0.560587104,0.100691632,0.669624416,0.08743256,0.20213104,0.771619344,0.27823344,0.250449024,0.05190408,0.152009232,0.214936848,0.483196928,0.21406072,0.094352272,0.181307104,0.239755472,0.081858512,0.059364752,0.515823152,0.471237296,0.153982224,0.046018992,0.054476976,0.538127488,0.686660432,0.418623328,0.345042496,0.060786912,0.099329824,0.014617584,0.057596096,0.06783656,0.244862528,0.20945456,0.312142112,0.050727152,0.454982368,0.145425568,0.052628384,0.048330736,0.15538584,0.233403424,0.103459888,0.599868624,0.430766288,0.372345088,0.722143872,0.484689424,0.064938256,0.204733376,0.719445376,0.185567632,0.436429392,0.212477056,0.229717104,0.627016016,0.566716128,0.631675488,0.400339584,0.774202096,0.846812064,0.292783056,0.634856432,0.615114656 +660.0,0.8728,0.6916,0.16207,0.51527,0.77303,0.38151,0.4736,0.5322,0.0642,0.88011,0.55369,0.67555,0.26735,0.4898,0.6015,0.42039,0.34672,0.3626,0.5211,0.77972,0.90443,0.80262,0.84844,0.8504,0.51107,0.905,0.44579,0.11537,0.79597,0.35561,0.8117,0.6457,0.80412,0.26213,0.10041,0.56082,0.1031,0.66944,0.08759,0.20259,0.7764,0.28089,0.2448,0.052,0.15234,0.2147,0.4922,0.21248,0.09465,0.18201,0.24066,0.08223,0.0596,0.518,0.47319,0.15443,0.0444,0.05499,0.5382,0.68803,0.41909,0.34848,0.06109,0.09981,0.0143,0.0577,0.068,0.24535,0.2098,0.31264,0.052,0.45526,0.14695,0.05351,0.0493,0.1574,0.23877,0.10495,0.60811,0.43586,0.37835,0.7258,0.4898,0.065,0.20784,0.72318,0.18627,0.43926,0.21697,0.2301,0.6279,0.57049,0.63663,0.40773,0.779,0.84892,0.2945,0.63996,0.6162 +661.0,0.873413136,0.694149728,0.163581616,0.515076784,0.778802032,0.3912056,0.473599744,0.53537048,0.064345392,0.880333344,0.558819104,0.676097184,0.2674824,0.489846208,0.602299472,0.424278224,0.355290528,0.363625632,0.520946032,0.7819064,0.904618672,0.803763776,0.849178384,0.84980288,0.510955904,0.905148976,0.445558896,0.114912512,0.796749104,0.356141056,0.812060128,0.653187344,0.804735728,0.262019472,0.100334128,0.561065984,0.105896736,0.669236896,0.087725456,0.202986704,0.781192064,0.283453584,0.239160624,0.052092576,0.152577024,0.214510928,0.501343744,0.210935664,0.09494872,0.182591328,0.241395264,0.082554768,0.05984592,0.520338304,0.475182208,0.154944768,0.042873728,0.055535408,0.538052288,0.689357008,0.419476048,0.352129488,0.061429008,0.100298976,0.014003936,0.057804608,0.068156272,0.245760384,0.21008784,0.31305232,0.053397104,0.45547424,0.148480864,0.054450896,0.050345968,0.159321008,0.244114496,0.106455616,0.616185328,0.441040752,0.384031264,0.729581024,0.494991856,0.065048592,0.211270576,0.726585072,0.18687592,0.442437856,0.22161808,0.230425136,0.628747408,0.5741332,0.641471952,0.41513224,0.783639184,0.850892416,0.296118768,0.645143904,0.617206352 +662.0,0.874018992,0.696673568,0.16528952,0.514848208,0.784373184,0.40110904,0.473523264,0.538402928,0.064470176,0.880497008,0.564031568,0.676863264,0.267598912,0.4898844,0.603114288,0.428092688,0.364094976,0.364663504,0.52078576,0.784134128,0.90478888,0.804927792,0.84991088,0.849155488,0.510746832,0.905293136,0.445249872,0.114257904,0.797613616,0.3567456,0.812358784,0.660539968,0.8053536,0.261933376,0.100264336,0.56132696,0.109085504,0.669017984,0.08783856,0.203319696,0.785984976,0.285913248,0.2335736,0.052181248,0.152698912,0.21437016,0.510614224,0.209426144,0.095247696,0.183048992,0.241958592,0.082831472,0.060101872,0.522833152,0.477207792,0.155526384,0.04145144,0.056112448,0.537684368,0.69063712,0.419780256,0.355995952,0.061803616,0.100795008,0.013728288,0.057909408,0.068304352,0.246091984,0.210316976,0.313377248,0.054918768,0.455624272,0.1500172,0.055454416,0.051468672,0.161136224,0.249424288,0.107975376,0.624073584,0.446306304,0.389373792,0.733484736,0.50025816,0.065084,0.215006112,0.729677584,0.187380368,0.445971296,0.226420064,0.23069408,0.62956056,0.577652272,0.6461968,0.422542368,0.788112032,0.852731488,0.297628368,0.650398608,0.618138176 +663.0,0.874616768,0.699182688,0.167142064,0.514597392,0.789749776,0.41116744,0.473381824,0.541305776,0.06457584,0.880609952,0.569295952,0.677707504,0.267699424,0.489918112,0.603943024,0.431839152,0.373085024,0.365712176,0.520621008,0.786395936,0.904942528,0.806101488,0.850638736,0.848472256,0.51046632,0.905432736,0.444911568,0.113538656,0.798553888,0.357382144,0.81260672,0.667749552,0.805969712,0.26187512,0.100203104,0.561578096,0.112650032,0.668799952,0.087931424,0.203593968,0.790766928,0.288266512,0.228101536,0.0522656,0.1528156,0.214276352,0.519991024,0.207951424,0.095546272,0.183393376,0.24236552,0.083063776,0.060367744,0.5254656,0.479259376,0.15617904,0.040135632,0.056719888,0.537143808,0.691868912,0.420008864,0.360082976,0.062211904,0.10129648,0.01347168,0.058013888,0.068443232,0.246350784,0.210492032,0.313622096,0.056559232,0.455716624,0.151554976,0.056526016,0.052664256,0.16282992,0.25468184,0.109503536,0.63176096,0.451655216,0.39444216,0.737506928,0.505609584,0.065106928,0.219051008,0.732481456,0.187783376,0.449867616,0.231371568,0.230924384,0.630312832,0.581094944,0.650804608,0.429953856,0.7924124,0.85444248,0.299019648,0.655719392,0.6190032 +664.0,0.875204224,0.701694208,0.169049888,0.514343216,0.794939728,0.42131328,0.473189984,0.544088544,0.064665104,0.880687216,0.574570016,0.678414224,0.267783216,0.489952064,0.6047824,0.435528816,0.382197472,0.366768448,0.520454976,0.788680784,0.905082176,0.807269504,0.851364512,0.847774784,0.510159408,0.905568256,0.444628544,0.112965648,0.79955352,0.357988608,0.812822496,0.674814176,0.806579744,0.261849504,0.100154112,0.561783552,0.11656208,0.66860792,0.088007648,0.20381848,0.79552576,0.290517776,0.222813792,0.052345312,0.153104048,0.214226944,0.529450144,0.206512544,0.095843888,0.18364248,0.242642608,0.08325832,0.060643776,0.528208608,0.4813292,0.156908976,0.038922304,0.057356208,0.536506368,0.693053184,0.420172672,0.36439328,0.062651312,0.101801952,0.013232672,0.058117568,0.068572032,0.246547424,0.210621008,0.313799744,0.058308896,0.455762336,0.153089792,0.057672496,0.0539264,0.164385856,0.259866672,0.111033056,0.639239536,0.457086768,0.399312448,0.74164096,0.511066208,0.065118576,0.223374944,0.735023968,0.188088944,0.454132416,0.236466512,0.231142848,0.630966944,0.584526496,0.655298496,0.437358704,0.796536208,0.856032992,0.300285728,0.661104496,0.619811104 +665.0,0.87578,0.70422,0.17095,0.5141,0.79995,0.43149,0.47296,0.54676,0.06474,0.88074,0.57982,0.67885,0.26785,0.48999,0.60563,0.43917,0.39138,0.36783,0.52029,0.79098,0.90521,0.80842,0.85209,0.84708,0.50985,0.9057,0.44445,0.11267,0.8006,0.35852,0.81302,0.68173,0.80718,0.26186,0.10012,0.56192,0.1208,0.66846,0.08807,0.204,0.80025,0.29267,0.21777,0.05242,0.15367,0.21422,0.53897,0.20511,0.09614,0.18381,0.24281,0.08342,0.06093,0.53104,0.48341,0.15772,0.03781,0.05802,0.53583,0.69419,0.42028,0.36893,0.06312,0.10231,0.01301,0.05822,0.06869,0.24669,0.21071,0.31392,0.06016,0.45577,0.15462,0.0589,0.05525,0.16579,0.26496,0.11256,0.6465,0.4626,0.40403,0.74588,0.51664,0.06512,0.22794,0.73733,0.1883,0.45877,0.2417,0.23137,0.6315,0.58799,0.65968,0.44475,0.80048,0.85751,0.30142,0.66655,0.62057 +666.0,0.876345408,0.706756448,0.172840384,0.513868288,0.804784848,0.441673904,0.472697024,0.549326432,0.064800496,0.880768048,0.585037392,0.679034288,0.267900848,0.490032896,0.606486112,0.442762176,0.400612688,0.368897088,0.520125632,0.793291712,0.905327056,0.809551648,0.852814864,0.846390592,0.509532928,0.905827872,0.444362384,0.112626736,0.801692624,0.35897656,0.813199296,0.688487648,0.807768672,0.261906176,0.100100432,0.561988464,0.125361856,0.668354112,0.088118704,0.204138544,0.804930144,0.294721536,0.213000608,0.05248928,0.154488496,0.214255264,0.548536,0.203742736,0.096434176,0.18389648,0.242868608,0.08354856,0.061225664,0.533952256,0.485495952,0.158608816,0.036805088,0.058709952,0.535119264,0.695277296,0.42033144,0.373697504,0.063618,0.102818928,0.012802704,0.058320768,0.068796608,0.246778784,0.210759344,0.313983232,0.062110176,0.45574072,0.15615224,0.060212256,0.056633408,0.167035168,0.269952576,0.114089536,0.653529008,0.468193008,0.408619184,0.750216832,0.522318368,0.065111472,0.23276704,0.739417008,0.18841632,0.46378072,0.24707088,0.231607456,0.631914736,0.591483136,0.663946128,0.452124352,0.804241792,0.85887912,0.302416448,0.672045504,0.621283328 +667.0,0.876901648,0.709297888,0.174703104,0.513647232,0.809448896,0.45184344,0.472405824,0.551793856,0.0648468,0.880771552,0.590215792,0.678950784,0.267936944,0.490081552,0.607350464,0.446305952,0.409877104,0.369969376,0.519961328,0.795613456,0.905434528,0.810663648,0.853539136,0.845709216,0.50922512,0.905951856,0.444374928,0.112844576,0.802829728,0.359358544,0.8133616,0.695082192,0.808344592,0.26198696,0.100094784,0.561986096,0.130243152,0.668286512,0.088154224,0.204234768,0.809557408,0.296676112,0.208526656,0.05255296,0.15556976,0.214331952,0.558133344,0.202410064,0.096726192,0.183903616,0.24282104,0.083644256,0.061529904,0.53693696,0.487581616,0.1595704,0.035910912,0.059424368,0.534380528,0.696314432,0.420328304,0.378699856,0.064145584,0.10332696,0.01260984,0.058419488,0.068891552,0.246814864,0.210769952,0.313990736,0.064155632,0.455676464,0.157697696,0.061612976,0.058074016,0.16811776,0.27483912,0.115630656,0.66031792,0.473864096,0.41313408,0.754641168,0.528085184,0.065093248,0.237903168,0.741301936,0.188440576,0.469160496,0.252578288,0.231856544,0.632209472,0.595005904,0.668094928,0.459478816,0.8078228,0.86014816,0.303272048,0.677580272,0.62195408 +668.0,0.877447408,0.711857728,0.176527344,0.513452736,0.813948384,0.461939936,0.472099424,0.55417176,0.064880704,0.880761136,0.595319712,0.6786896,0.26795776,0.490139568,0.608220976,0.449808928,0.41911992,0.371045264,0.519799904,0.79793776,0.9055344,0.811743728,0.854263888,0.84505328,0.508859712,0.90607192,0.444427392,0.113254576,0.803999472,0.359633008,0.813519264,0.701504896,0.808903392,0.262106304,0.100105696,0.561919808,0.135424928,0.668275312,0.088179184,0.204295152,0.814119792,0.298531888,0.204417184,0.05261008,0.156818464,0.21444904,0.567741168,0.201111952,0.097015168,0.183844432,0.242685712,0.083711312,0.061843184,0.539972704,0.48965944,0.160609904,0.035128656,0.060162704,0.533669872,0.697299888,0.420278768,0.383940528,0.064701248,0.103833392,0.012430576,0.058515808,0.068974176,0.246805904,0.21074744,0.31395184,0.066290288,0.455585248,0.159250112,0.063109216,0.059568064,0.169019712,0.279587984,0.117176016,0.666852432,0.479612544,0.417447856,0.759148864,0.5339564,0.065067104,0.243121056,0.743010624,0.188372672,0.474918192,0.258216656,0.232138272,0.632400768,0.598556592,0.672126448,0.46680552,0.811217168,0.86132088,0.303977648,0.68315072,0.622590752 +669.0,0.877980528,0.714455648,0.178310704,0.51330632,0.818290032,0.471892352,0.471793664,0.556470864,0.064904528,0.88075088,0.600304032,0.678407616,0.267962176,0.490211424,0.609094928,0.453281104,0.428276256,0.372122752,0.51964536,0.800255584,0.905628912,0.812775808,0.85499048,0.844445184,0.508330464,0.906187984,0.444421936,0.113734176,0.805186576,0.359757952,0.813688288,0.70774568,0.809439632,0.262269808,0.100136848,0.56180416,0.140883424,0.668345632,0.088196944,0.204328176,0.818604256,0.300285264,0.200757232,0.05265936,0.158076448,0.214605488,0.577336672,0.19984856,0.097299984,0.183735808,0.242486304,0.083755248,0.062166464,0.543033728,0.491721184,0.161735808,0.03445872,0.06092488,0.533059936,0.698231824,0.420193392,0.3894228,0.065282992,0.104337984,0.012264192,0.058609408,0.06904376,0.246761824,0.210699008,0.313878624,0.068507344,0.455477152,0.160797408,0.064709296,0.061111472,0.169718064,0.284157248,0.118712896,0.673116304,0.485438032,0.421349632,0.76373776,0.539958736,0.06503544,0.248074704,0.744571952,0.188211568,0.481067008,0.263978784,0.23248024,0.632517104,0.60212584,0.676041328,0.474094864,0.814416816,0.86239952,0.304522128,0.688755648,0.623203664 +670.0,0.8785,0.7171,0.18004,0.51322,0.82248,0.48165,0.4715,0.5587,0.06492,0.88075,0.60514,0.67821,0.26795,0.4903,0.60997,0.45673,0.4373,0.3732,0.5195,0.80256,0.90572,0.81375,0.85572,0.8439,0.50758,0.9063,0.4443,0.1142,0.80638,0.35971,0.81388,0.7138,0.80995,0.26248,0.10019,0.56165,0.1466,0.66851,0.08821,0.20434,0.823,0.30194,0.1976,0.0527,0.15924,0.2148,0.5869,0.19862,0.09758,0.18359,0.24224,0.08378,0.0625,0.5461,0.49376,0.16295,0.0339,0.06171,0.5326,0.69911,0.42008,0.39515,0.06589,0.10484,0.01211,0.0587,0.0691,0.24669,0.21063,0.31378,0.0708,0.45536,0.16234,0.06642,0.0627,0.1702,0.28852,0.12024,0.6791,0.49134,0.42472,0.7684,0.5461,0.065,0.25255,0.74601,0.18796,0.48761,0.26986,0.2329,0.63258,0.6057,0.67984,0.48134,0.81742,0.86339,0.3049,0.69439,0.6238 +671.0,0.879006832,0.719782464,0.181703152,0.51319296,0.826523456,0.49119624,0.47122216,0.560864752,0.06492768,0.880759424,0.609825408,0.678074272,0.267922528,0.490405536,0.61084496,0.460158032,0.446176384,0.374275888,0.519363248,0.804847936,0.905808912,0.814666656,0.856452752,0.843419744,0.50663184,0.906408032,0.444081392,0.114663184,0.807576624,0.35949312,0.81409696,0.719670752,0.810434528,0.262734752,0.100264048,0.561450672,0.152566176,0.668765696,0.088219168,0.204332272,0.82730016,0.303509232,0.194953056,0.052732032,0.160322704,0.215031168,0.596417152,0.197426128,0.097855392,0.183410464,0.241951728,0.083786464,0.062842864,0.549162496,0.495771152,0.164244832,0.033452464,0.062515904,0.532296576,0.699935792,0.419941056,0.401124816,0.06652304,0.10533776,0.01196728,0.058787344,0.069143072,0.246592832,0.210542144,0.31365864,0.073162736,0.455237088,0.163896064,0.068245312,0.064329984,0.170467696,0.292670784,0.12177256,0.68480352,0.497316848,0.427599232,0.773121312,0.552360448,0.064961232,0.256569808,0.747340448,0.18762512,0.494534656,0.275859488,0.23339792,0.632583552,0.60928264,0.683522336,0.488538592,0.820233424,0.864302704,0.305113296,0.70004304,0.624381888 +672.0,0.879501648,0.722499168,0.183312224,0.513229696,0.830425824,0.500509216,0.470964784,0.5629712,0.064928304,0.880781776,0.614353392,0.67799248,0.26788072,0.490528608,0.611718416,0.463568368,0.4548856,0.375349344,0.519235104,0.80711576,0.90589688,0.815524368,0.857188928,0.84300816,0.505484512,0.90651216,0.443772032,0.115118016,0.808772032,0.359105408,0.814342944,0.725360016,0.810892752,0.263032944,0.100358576,0.561195648,0.158771728,0.669118272,0.088225504,0.204307312,0.831497872,0.305004528,0.192835744,0.05275536,0.161314704,0.21529776,0.605874128,0.196266832,0.098126288,0.183202032,0.241628272,0.083775952,0.063194384,0.552211104,0.49774952,0.165615024,0.033118016,0.063340704,0.532161312,0.700709888,0.419779808,0.407349008,0.067182448,0.105829792,0.011835376,0.058871248,0.069173056,0.246473504,0.21043768,0.31351808,0.075590448,0.455112368,0.165479552,0.070189776,0.065998144,0.170520272,0.296595264,0.123322176,0.690226032,0.503366704,0.429976656,0.777890224,0.5587284,0.064919824,0.260093296,0.748579984,0.187212832,0.501830272,0.281975296,0.233977152,0.632517088,0.612890512,0.687088608,0.49568744,0.822861968,0.86514624,0.305162448,0.70570584,0.624952352 +673.0,0.879986704,0.725219392,0.184762976,0.513305552,0.834191632,0.509597472,0.470727568,0.565022848,0.064922208,0.880811968,0.618744976,0.678000288,0.267827312,0.49066744,0.612588432,0.466963104,0.463436496,0.376418,0.51911288,0.809362064,0.905985408,0.81633168,0.857929664,0.842660736,0.504237024,0.906612288,0.443406192,0.115544048,0.80996608,0.358586416,0.814617568,0.7308824,0.811327936,0.263366976,0.100468864,0.560912384,0.16521016,0.669526928,0.08822944,0.204265712,0.835587904,0.306456624,0.191189712,0.052770528,0.162227824,0.215596992,0.615257024,0.195142416,0.098393344,0.18296544,0.241270496,0.08374856,0.063552704,0.555239232,0.499692768,0.167039616,0.032882448,0.064180864,0.532183728,0.701439104,0.4195976,0.4138284,0.067871776,0.106314064,0.011713792,0.058951472,0.06919128,0.246333296,0.210317536,0.31335984,0.07807336,0.454988528,0.16713456,0.072256,0.067697744,0.170378848,0.300322544,0.124926672,0.695379984,0.50948992,0.43201328,0.782674736,0.565145232,0.064875936,0.263287424,0.74973968,0.186740944,0.509468368,0.288211344,0.234626544,0.632419984,0.616436624,0.69053872,0.502788048,0.825326832,0.865941456,0.30506232,0.71135976,0.625508976 +674.0,0.88046528,0.727897696,0.185901248,0.513380928,0.83782488,0.518488688,0.470506752,0.567021536,0.064909392,0.88084024,0.623038,0.678138736,0.267766064,0.490818752,0.613452928,0.4703432,0.471855792,0.377478976,0.518992256,0.811587008,0.906076016,0.817103232,0.8586764,0.842367232,0.503043776,0.906708256,0.443040752,0.1159236,0.811161648,0.357999024,0.814917312,0.736259744,0.8117456,0.263725568,0.100587792,0.56064312,0.171877952,0.669927904,0.088230896,0.204206672,0.839566496,0.30790688,0.18991408,0.052778496,0.163096464,0.215925344,0.62455296,0.19405336,0.0986576,0.182698368,0.24087488,0.083703408,0.063915264,0.55824352,0.501600176,0.168489008,0.03272432,0.065031904,0.532336864,0.70213336,0.419394192,0.420570432,0.068596304,0.106788176,0.011602128,0.059027776,0.069199744,0.246171968,0.210181552,0.31318368,0.080599712,0.454867088,0.168921808,0.074445344,0.069420544,0.170077024,0.303904064,0.126638528,0.700285776,0.515687696,0.433965584,0.787432448,0.571526944,0.064829328,0.266441312,0.750826736,0.186233536,0.517409584,0.294574752,0.235325856,0.63235048,0.619789376,0.693872432,0.509844736,0.827658176,0.866715472,0.304835712,0.71698096,0.62604608 +675.0,0.88094,0.7305,0.18664,0.51343,0.84133,0.5272,0.4703,0.56897,0.06489,0.88086,0.62726,0.67843,0.2677,0.49098,0.61431,0.47371,0.48016,0.37853,0.51887,0.81379,0.90617,0.81785,0.85943,0.84212,0.50201,0.9068,0.44272,0.11624,0.81236,0.35739,0.81524,0.74151,0.81215,0.2641,0.10071,0.56041,0.17877,0.67028,0.08823,0.20413,0.84343,0.30939,0.18894,0.05278,0.16394,0.21628,0.63375,0.193,0.09892,0.1824,0.24044,0.08364,0.06428,0.56122,0.50347,0.16994,0.03263,0.06589,0.5326,0.7028,0.41917,0.42758,0.06936,0.10725,0.0115,0.0591,0.0692,0.24599,0.21003,0.31299,0.08316,0.45475,0.17089,0.07676,0.07116,0.16964,0.30737,0.1285,0.70496,0.52196,0.436,0.79213,0.57781,0.06478,0.26974,0.75185,0.18571,0.52562,0.30107,0.23606,0.63234,0.62287,0.69709,0.51686,0.82988,0.86749,0.3045,0.72255,0.62656 +676.0,0.881411456,0.73302656,0.18700832,0.513455488,0.844712544,0.535717072,0.470109152,0.57087336,0.064864608,0.880874144,0.631407504,0.678872656,0.267629888,0.491151136,0.615158192,0.477065536,0.4883352,0.379570752,0.518746016,0.815967888,0.906268192,0.81857184,0.860189872,0.841919328,0.501128368,0.906887808,0.4424424,0.116489472,0.813557536,0.356762784,0.815587536,0.746639712,0.81254168,0.264489376,0.10083528,0.560207808,0.18587632,0.670588,0.088227504,0.204037392,0.847175264,0.310920592,0.18829472,0.052775136,0.164747312,0.21666016,0.642838912,0.191982112,0.099181136,0.18207384,0.239970624,0.083559296,0.064646496,0.564162848,0.505297632,0.171388848,0.032609472,0.066753328,0.53297136,0.703438896,0.41892744,0.434854496,0.070162816,0.107698032,0.011406928,0.059168,0.069192256,0.245789776,0.20986456,0.31278144,0.085751584,0.454640256,0.173051824,0.079204352,0.072914464,0.169067744,0.31071,0.130522352,0.709407664,0.528302976,0.438094688,0.796761248,0.583991968,0.06472848,0.27313408,0.752823104,0.185175664,0.534081552,0.307693632,0.236829312,0.63238256,0.625691136,0.700193296,0.523831088,0.8319976,0.868270752,0.304056128,0.728060784,0.627053024 +677.0,0.881880224,0.735480672,0.187010976,0.513454192,0.847978032,0.544029712,0.469934368,0.572736048,0.064833648,0.880885648,0.635478576,0.679470768,0.267556352,0.49133192,0.615996112,0.480410704,0.496370736,0.38060152,0.51862008,0.818117744,0.906371248,0.8192692,0.860955024,0.841763456,0.500404464,0.906972128,0.442202832,0.116683248,0.81475136,0.356124816,0.815960528,0.75165736,0.812921696,0.264893136,0.100963584,0.560045824,0.19318752,0.670848048,0.08822392,0.203930032,0.850801264,0.312513904,0.188012112,0.052764128,0.165521904,0.217065312,0.651813264,0.190999296,0.099441824,0.18172224,0.239469936,0.08346208,0.065014544,0.567068992,0.507078768,0.172833216,0.032678288,0.067620144,0.533440848,0.704049264,0.41866824,0.4423888,0.071004336,0.108130624,0.011322432,0.059231552,0.06917672,0.245572896,0.209686496,0.31256,0.0883736,0.454539968,0.17541832,0.08178248,0.074683344,0.168360048,0.313925504,0.132715712,0.713636304,0.53471144,0.44026216,0.801323936,0.590076512,0.064675056,0.276611184,0.75375784,0.184634944,0.542772448,0.314441264,0.237632464,0.632489584,0.628239904,0.70318504,0.530755568,0.834015712,0.869061456,0.30350464,0.73350904,0.627527056 +678.0,0.882349072,0.737824704,0.186755712,0.513431776,0.85113128,0.552150592,0.469775184,0.574562096,0.064797408,0.880887872,0.639499408,0.68017504,0.267482656,0.491519424,0.616821952,0.483748912,0.504279472,0.381619168,0.518489344,0.82023936,0.906480224,0.81995272,0.861726176,0.841646464,0.49986072,0.907052608,0.442065264,0.116769904,0.815942064,0.355508848,0.816358,0.756578448,0.813293632,0.265301936,0.101089648,0.55986584,0.20069816,0.671070976,0.088219616,0.203808112,0.854301904,0.314204256,0.188016704,0.05274752,0.166239376,0.217492544,0.660658576,0.19005232,0.099702912,0.18134592,0.238938288,0.083347424,0.065381552,0.569931776,0.508810944,0.174247984,0.032816864,0.06848648,0.533995616,0.704638592,0.41839344,0.450190064,0.071889056,0.108546176,0.011246416,0.059291024,0.069154944,0.245341136,0.209496272,0.31232608,0.091014576,0.45445248,0.178039776,0.084497488,0.076459424,0.167542352,0.316988368,0.135124112,0.717660304,0.541186944,0.442470752,0.805780624,0.595994576,0.064620352,0.280163728,0.754665216,0.184108144,0.551663424,0.321318336,0.238456096,0.632589008,0.630597232,0.706064384,0.537635168,0.835959344,0.86988536,0.302863632,0.738873216,0.627979008 +679.0,0.88282152,0.740007296,0.186413008,0.51340112,0.854176928,0.560099952,0.46963096,0.576355504,0.064756128,0.880870976,0.6435056,0.680907392,0.26741296,0.491709728,0.617633792,0.48708456,0.512082048,0.382619376,0.518350128,0.822333536,0.90659624,0.82063648,0.862504528,0.841560992,0.499513536,0.907128608,0.442119376,0.11667384,0.817131408,0.3549544,0.816778432,0.761420736,0.813661888,0.265703456,0.101206512,0.559576176,0.20840416,0.671279744,0.088214912,0.203671472,0.857669344,0.316032368,0.188196576,0.052725952,0.166861168,0.217938176,0.669357728,0.189142384,0.09996528,0.18094512,0.23837512,0.083213728,0.06574408,0.57274336,0.51049224,0.175600352,0.03299384,0.069347616,0.534621824,0.70521704,0.41810384,0.458269488,0.072823136,0.108943168,0.01117896,0.059347056,0.069128928,0.245096416,0.209294048,0.31207944,0.093659472,0.454381632,0.180979552,0.087352256,0.078233344,0.166648656,0.319852832,0.137802992,0.721496384,0.547733328,0.444646784,0.810082112,0.60165296,0.064565168,0.283759792,0.755556032,0.183620864,0.56072288,0.328333568,0.239282848,0.632566592,0.63289768,0.708829248,0.544472928,0.837860336,0.870772144,0.302157104,0.744125952,0.62840416 +680.0,0.8833,0.742,0.18611,0.51337,0.85712,0.56789,0.4695,0.57812,0.06471,0.88083,0.64752,0.68161,0.26735,0.4919,0.61843,0.49042,0.51979,0.3836,0.5182,0.8244,0.90672,0.82133,0.86329,0.8415,0.49937,0.9072,0.44242,0.11636,0.81832,0.35449,0.81722,0.7662,0.81403,0.26609,0.10131,0.55912,0.2163,0.67149,0.08821,0.20352,0.8609,0.31803,0.1885,0.0527,0.16737,0.2184,0.6779,0.18827,0.10023,0.18052,0.23778,0.08306,0.0661,0.5755,0.51212,0.17687,0.0332,0.0702,0.5353,0.70579,0.4178,0.46663,0.07381,0.10932,0.01112,0.0594,0.0691,0.24484,0.20908,0.31182,0.0963,0.45433,0.18428,0.09035,0.08,0.1657,0.32249,0.14079,0.72516,0.55435,0.44674,0.8142,0.607,0.06451,0.28737,0.75644,0.18319,0.56992,0.33549,0.2401,0.63235,0.63523,0.71148,0.55127,0.83974,0.87174,0.3014,0.74925,0.6288 +681.0,0.883784768,0.743810208,0.185839168,0.513334272,0.859965904,0.575516848,0.469380096,0.579858944,0.0646592,0.880767824,0.651542304,0.682288544,0.267294064,0.492089488,0.61920944,0.4937544,0.527397392,0.384561776,0.518038816,0.826436384,0.906851648,0.822034688,0.864080912,0.841458768,0.499447472,0.907267328,0.44296488,0.11584136,0.819506128,0.354127952,0.817681136,0.77092488,0.814399632,0.266461376,0.101400352,0.5585068,0.224377312,0.671696448,0.088204976,0.20335392,0.863995728,0.320212816,0.188962976,0.052670096,0.16777416,0.218877648,0.686281424,0.187434576,0.100498192,0.180071104,0.237153504,0.08288648,0.066449168,0.578202096,0.513690608,0.178056592,0.03345568,0.071042,0.536009008,0.706355616,0.417482384,0.47526136,0.074848416,0.109675168,0.011069216,0.059449696,0.069068384,0.244572288,0.208854576,0.311548416,0.09893656,0.454298288,0.187947632,0.09349456,0.081759616,0.164697264,0.324905328,0.14409208,0.728663072,0.561029664,0.44877056,0.81813712,0.612047168,0.064454816,0.2910048,0.757325728,0.182817664,0.579227008,0.342781264,0.240903744,0.631950128,0.637583264,0.714020624,0.558024144,0.841601472,0.872788096,0.300593408,0.754242896,0.629167792 +682.0,0.884276112,0.745437184,0.185585632,0.513292656,0.86271976,0.582979232,0.469269584,0.581575616,0.064603888,0.880685472,0.655575648,0.68295336,0.267245776,0.492277024,0.619970992,0.497087392,0.534901072,0.385504288,0.517866224,0.82844072,0.906991344,0.82275344,0.864876096,0.841432784,0.49977752,0.907330848,0.443767344,0.115101264,0.820688544,0.353885648,0.81816024,0.775601968,0.814772592,0.266815776,0.101476848,0.5577304,0.23262824,0.671896176,0.088199936,0.203173312,0.866956624,0.322598816,0.189593264,0.05263672,0.168064976,0.219369904,0.694493936,0.18663576,0.100770832,0.17959888,0.236495968,0.082693104,0.066790832,0.580847856,0.515201024,0.179155584,0.033770064,0.0718716,0.536731616,0.706913712,0.41715136,0.484154944,0.075937776,0.110007456,0.011026416,0.059496144,0.069034544,0.244293776,0.208618112,0.31126512,0.101565856,0.45428744,0.191994016,0.096789728,0.083510064,0.163646992,0.327097248,0.147720512,0.732018304,0.567766384,0.450750512,0.821888464,0.616790256,0.064399632,0.294682208,0.758221776,0.182507984,0.588615424,0.350202336,0.241688816,0.631360208,0.639966192,0.716454304,0.564733568,0.843450544,0.87391808,0.299742512,0.759097856,0.629507968 +683.0,0.884774256,0.7469264,0.185493136,0.51324328,0.865388416,0.590270736,0.469160912,0.583272928,0.064544016,0.88059344,0.659609232,0.683536496,0.267203888,0.49246256,0.620713744,0.500414944,0.542290112,0.38643384,0.517682912,0.830410096,0.9071384,0.823483152,0.86567048,0.84141208,0.500276608,0.907392448,0.444771728,0.114281488,0.82186512,0.353753024,0.818653184,0.780251456,0.815150832,0.267159856,0.101544144,0.55682608,0.241043808,0.672100464,0.088194496,0.202977824,0.86979552,0.325195856,0.190553072,0.052600304,0.168318672,0.21988056,0.702555808,0.185871904,0.101050192,0.179102336,0.235805952,0.082480368,0.067127376,0.583452016,0.51664552,0.180185776,0.034218848,0.0726888,0.537413984,0.707453888,0.416806336,0.493288768,0.077073776,0.110314304,0.010991056,0.059538832,0.068997744,0.244003424,0.208370448,0.310969744,0.104206432,0.454295952,0.19640208,0.100239536,0.085263472,0.16252712,0.329076368,0.151663264,0.735239856,0.574545024,0.452637424,0.825495808,0.621316224,0.064344128,0.298300896,0.759133584,0.182253184,0.59805376,0.357739648,0.242453968,0.630610528,0.6423724,0.718789664,0.571394432,0.845279056,0.875114784,0.298831536,0.763833056,0.629824544 +684.0,0.88527904,0.748349696,0.18575984,0.513182944,0.867979552,0.59738056,0.46904368,0.58495352,0.064479424,0.880507648,0.663622576,0.683942992,0.26716592,0.492646816,0.621436976,0.503730816,0.549547712,0.387360192,0.5174904,0.832340912,0.907291616,0.824216864,0.866456944,0.841384416,0.500810096,0.907454848,0.445883552,0.113601152,0.823033056,0.35370528,0.819154608,0.784898464,0.815536112,0.267505216,0.10161,0.55585568,0.249614176,0.672324992,0.088188016,0.202766896,0.872531936,0.328004816,0.19208704,0.052561248,0.168652528,0.220415936,0.71049824,0.185140608,0.101339152,0.178579792,0.235081216,0.082249152,0.06746288,0.586037536,0.518017056,0.181179568,0.034912192,0.0734948,0.537984992,0.707959984,0.416446192,0.502632512,0.078249696,0.110592592,0.010962416,0.05957696,0.068956544,0.243699312,0.208111184,0.310661568,0.106887968,0.454320864,0.201136144,0.103848224,0.0870392,0.161299808,0.330862768,0.155892976,0.738342288,0.581345184,0.454370656,0.829026912,0.625762912,0.064287744,0.301709024,0.760064832,0.182037744,0.607509296,0.36537424,0.24320096,0.629757888,0.644777888,0.721038384,0.578001456,0.847069728,0.876352288,0.29783328,0.768480176,0.63012368 +685.0,0.88579,0.74976,0.1865,0.51311,0.8705,0.6043,0.46891,0.58662,0.06441,0.88044,0.6676,0.68412,0.26713,0.49283,0.62214,0.50703,0.55666,0.38829,0.51729,0.83423,0.90745,0.82495,0.86723,0.84134,0.5013,0.90752,0.44704,0.1132,0.82419,0.35373,0.81966,0.78956,0.81593,0.26786,0.10168,0.55486,0.25833,0.67258,0.08818,0.20254,0.87518,0.33103,0.19437,0.05252,0.16914,0.22098,0.71834,0.18444,0.10164,0.17803,0.23432,0.082,0.0678,0.58862,0.51931,0.18216,0.03593,0.07429,0.53839,0.70842,0.41607,0.51216,0.07946,0.11084,0.01094,0.05961,0.06891,0.24338,0.20784,0.31034,0.10963,0.45436,0.20617,0.10762,0.08885,0.15994,0.33247,0.16039,0.74134,0.58815,0.45591,0.83253,0.63023,0.06423,0.30481,0.76102,0.18185,0.61695,0.37309,0.24393,0.62884,0.64717,0.72321,0.58455,0.84881,0.87761,0.29673,0.77306,0.63041 +686.0,0.886305952,0.75115344,0.18770136,0.513025968,0.872953824,0.611026864,0.468759712,0.58827456,0.064335808,0.88039024,0.671540352,0.684076224,0.267096144,0.493010912,0.622821936,0.510310912,0.56362192,0.389220672,0.51708224,0.83607528,0.907613232,0.825684864,0.867989344,0.841276608,0.501749568,0.907587808,0.448239888,0.113054576,0.825334704,0.353832464,0.820167616,0.79422896,0.816333728,0.268221648,0.101753312,0.553829952,0.267183296,0.672865728,0.088170352,0.202296848,0.877737472,0.33428616,0.197367328,0.052477056,0.16976896,0.221569472,0.726062528,0.183769712,0.101953184,0.177452784,0.233521776,0.081732784,0.068137408,0.591192704,0.520523072,0.183122224,0.03726128,0.075072352,0.538623744,0.708834576,0.415677552,0.521857536,0.080702704,0.111056544,0.010923648,0.059638112,0.068858784,0.243045424,0.207556928,0.310004928,0.112421536,0.45441344,0.21150544,0.1115588,0.090688896,0.158461056,0.333896128,0.165157712,0.744246864,0.594953136,0.45726408,0.83599472,0.634702688,0.064170752,0.30762584,0.762006144,0.181689856,0.626345792,0.38087896,0.244636512,0.627846448,0.649564528,0.725307552,0.591037552,0.85050112,0.878883408,0.295532256,0.77756048,0.630683488 +687.0,0.886824896,0.75252368,0.189391136,0.51293208,0.875344336,0.617557696,0.468593952,0.589918688,0.064256896,0.88035728,0.675439632,0.683798976,0.267064048,0.49318848,0.623481904,0.513571264,0.570426672,0.39014824,0.516868112,0.837874416,0.9077808,0.826423152,0.86873544,0.84119392,0.502113968,0.907658048,0.449459088,0.113166288,0.82646568,0.354003104,0.820675984,0.798889776,0.816748192,0.268586976,0.101829024,0.55276368,0.276165808,0.673184224,0.088158896,0.202037104,0.88020024,0.337786016,0.201017632,0.052432864,0.170543552,0.22217968,0.733640368,0.183129344,0.102278752,0.176847696,0.232685712,0.081447568,0.068473536,0.593745376,0.52165608,0.184061056,0.038881808,0.07583976,0.538689824,0.709205088,0.415268496,0.531708928,0.081975056,0.111242944,0.010913056,0.059661472,0.068803744,0.242695264,0.207261968,0.309656144,0.115246592,0.454480832,0.21713856,0.115668576,0.092545792,0.15688048,0.335142928,0.170194864,0.747076896,0.601748224,0.458443984,0.839406768,0.639158544,0.064109808,0.310170256,0.763029824,0.181554864,0.63566624,0.388731408,0.245316608,0.626773408,0.65197096,0.727333824,0.597461232,0.852141536,0.880164784,0.294253856,0.781966016,0.630943904 +688.0,0.8873468,0.75392624,0.191393712,0.512829952,0.877679568,0.623884608,0.468403152,0.591556336,0.064173104,0.88035408,0.679284752,0.683386368,0.267032032,0.493362528,0.624119792,0.516807296,0.577062064,0.391080608,0.516648784,0.839624912,0.907951808,0.82716144,0.869461456,0.841079792,0.502540768,0.907732288,0.450724448,0.11350016,0.827581296,0.354283264,0.821179872,0.803567472,0.817174816,0.268965424,0.101912576,0.551668288,0.28526872,0.67353128,0.08814528,0.20176,0.882584688,0.341535552,0.205522576,0.052388112,0.171429184,0.222816368,0.741099248,0.182517216,0.10261952,0.176214208,0.231810768,0.081144032,0.068810704,0.596297488,0.522702048,0.184999488,0.040884976,0.076592768,0.538524864,0.70951848,0.41484176,0.5416904,0.083272288,0.111396304,0.010908544,0.059679792,0.068743504,0.242328464,0.206954608,0.30929296,0.118129888,0.454560624,0.22304968,0.119953872,0.094436368,0.155168944,0.336212048,0.175486656,0.749844448,0.608518592,0.459431968,0.842818256,0.64370488,0.064046544,0.312449232,0.764095664,0.181435712,0.644879888,0.396633776,0.245970064,0.625633728,0.654394112,0.729298736,0.603816352,0.853722192,0.88143656,0.292873936,0.786301232,0.63119616 +689.0,0.887872224,0.75543728,0.193424128,0.512721824,0.8799692,0.62999816,0.468174112,0.593192384,0.064084192,0.88039832,0.683059552,0.68299504,0.266997936,0.493533136,0.62473584,0.520014848,0.583514096,0.392029616,0.516425536,0.841324288,0.908125216,0.827894688,0.870158032,0.840918064,0.503271248,0.907812608,0.452090928,0.113984112,0.828679952,0.354737744,0.82167272,0.808300528,0.81761512,0.269370752,0.102011488,0.550549456,0.294483072,0.673898496,0.088129104,0.201464576,0.884914096,0.345538448,0.21117152,0.0523436,0.172363056,0.223488816,0.748481968,0.181931248,0.102979248,0.17555184,0.230895904,0.080821616,0.069152432,0.59887848,0.523651696,0.18596984,0.043403424,0.077332816,0.538043184,0.709756832,0.414395984,0.551775632,0.08458896,0.111512544,0.010910752,0.059692672,0.068675904,0.241943744,0.206634128,0.308914496,0.121109744,0.454650896,0.229214,0.124419488,0.096384864,0.153281488,0.337103728,0.181013808,0.752564,0.61524416,0.460204832,0.846303424,0.648492256,0.06398016,0.314481888,0.765207584,0.1813208,0.653954976,0.404571344,0.24659792,0.624442768,0.656839104,0.731214608,0.610097552,0.855231648,0.882677856,0.291360096,0.790604208,0.631446896 +690.0,0.8884,0.7571,0.19529,0.51261,0.88222,0.63589,0.4679,0.59483,0.06399,0.8805,0.68675,0.68273,0.26696,0.4937,0.62533,0.52319,0.58977,0.393,0.5162,0.84297,0.9083,0.82862,0.87082,0.8407,0.50444,0.9079,0.45358,0.11456,0.82976,0.3554,0.82215,0.8131,0.81807,0.26981,0.10213,0.54941,0.3038,0.67428,0.08811,0.20115,0.8872,0.3498,0.2181,0.0523,0.1733,0.2242,0.7558,0.18137,0.10336,0.17486,0.22994,0.08048,0.0695,0.6015,0.5245,0.18699,0.0465,0.07806,0.5372,0.70991,0.41393,0.56194,0.08592,0.11159,0.01092,0.0597,0.0686,0.24154,0.2063,0.30852,0.1242,0.45475,0.23561,0.12907,0.0984,0.1512,0.33782,0.18676,0.75525,0.62191,0.46076,0.8499,0.6536,0.06391,0.3163,0.76637,0.1812,0.66286,0.41253,0.2472,0.62321,0.65931,0.73309,0.6163,0.85666,0.88387,0.2897,0.79489,0.6317 +691.0,0.8889264,0.75890176,0.197025664,0.512496896,0.884433872,0.64157768,0.467584352,0.596469552,0.063891056,0.880656288,0.690361376,0.682573376,0.26691848,0.493862128,0.625904208,0.526335088,0.595844608,0.393984928,0.515974064,0.844565728,0.908475952,0.829338016,0.871448736,0.840428752,0.506015536,0.907993856,0.455179936,0.115238592,0.830822432,0.356257744,0.822610624,0.817933632,0.818539376,0.270278832,0.102266704,0.548252576,0.313218704,0.674678816,0.088088224,0.200818192,0.889434208,0.35429992,0.226192576,0.052257712,0.174245552,0.224942608,0.763013408,0.180833088,0.103761216,0.17414184,0.22894736,0.080121312,0.069851024,0.604144528,0.52524888,0.188053088,0.050124176,0.078772192,0.536016304,0.709981008,0.413445792,0.572161136,0.087265216,0.111630752,0.010935536,0.059702112,0.068516864,0.241119088,0.205953616,0.308111088,0.127374608,0.454856928,0.242225152,0.13390472,0.100465248,0.148950544,0.338365552,0.192717232,0.757906992,0.628509936,0.461109744,0.853584336,0.65898792,0.0638364,0.317900608,0.767578912,0.181073344,0.671592496,0.420507152,0.247773504,0.621938368,0.661809904,0.734926864,0.622426336,0.858014224,0.88501544,0.287914176,0.799135136,0.63195464 +692.0,0.88944792,0.7608384,0.198649872,0.512385712,0.886613328,0.647101488,0.467229072,0.598111776,0.063788384,0.8808664,0.693912032,0.682516608,0.266874592,0.494018608,0.626463152,0.529457936,0.601776704,0.394979248,0.515749584,0.846121472,0.908653488,0.8300484,0.872044096,0.840105632,0.508040768,0.908093888,0.456919728,0.11603832,0.831870976,0.357318704,0.823052912,0.822774912,0.819023056,0.270774784,0.102420976,0.547081408,0.32274616,0.6750988,0.08806456,0.20047344,0.891611168,0.358987632,0.235372656,0.052217152,0.175200944,0.225710848,0.770088928,0.180319936,0.10418288,0.173404448,0.227927808,0.079749552,0.070203584,0.606798688,0.525899328,0.189155968,0.054242896,0.079467728,0.534503024,0.70997088,0.41294792,0.58241384,0.088628048,0.111636304,0.010956304,0.059699312,0.068427184,0.240685344,0.205597808,0.30769136,0.130613328,0.454970544,0.24904584,0.138918272,0.102567728,0.146552384,0.338743888,0.198876896,0.760529808,0.635036272,0.461249888,0.857341776,0.66463368,0.063760304,0.319246592,0.768820464,0.180946512,0.680178368,0.428509616,0.248315984,0.620634368,0.664342592,0.736727936,0.628485232,0.859313472,0.88613112,0.286018096,0.803321392,0.63221064 +693.0,0.88995792,0.76285856,0.20008784,0.512278128,0.888756784,0.652385056,0.466846432,0.5997548,0.063680432,0.881117872,0.697349008,0.68259136,0.266823984,0.494168128,0.626998336,0.532538064,0.60748176,0.395966528,0.515529824,0.847615536,0.908829424,0.830755024,0.872614496,0.839744512,0.51026792,0.90819744,0.4586456,0.116839168,0.83289568,0.358499744,0.82347824,0.827551232,0.819520256,0.271285456,0.102587888,0.54588088,0.332350176,0.675530624,0.088037056,0.200107808,0.893708768,0.363959584,0.245315936,0.052178752,0.176129696,0.226488928,0.776946208,0.179831024,0.104621584,0.172635136,0.226863376,0.079359072,0.070552384,0.609421568,0.526458896,0.190275728,0.058709536,0.080142624,0.532739264,0.709891792,0.412427488,0.592681984,0.08999224,0.111612576,0.010983152,0.059692352,0.068333664,0.24023032,0.20522792,0.307254112,0.133857088,0.45508968,0.256053328,0.144129104,0.104669888,0.144066944,0.338963664,0.2052244,0.763162224,0.641489008,0.461288352,0.861104736,0.6704104,0.063679328,0.320549296,0.770128736,0.18079224,0.6885012,0.43649448,0.248824864,0.619281648,0.66690704,0.738491648,0.634454048,0.86051112,0.88715488,0.284059136,0.807397488,0.63246416 +694.0,0.89044784,0.7648808,0.201250608,0.512175344,0.89086,0.657305584,0.466455072,0.601395104,0.06356464,0.881390944,0.700591264,0.682832032,0.266760176,0.494309088,0.62749592,0.535543712,0.612826176,0.396923328,0.515318784,0.84901352,0.90899912,0.831464128,0.873173216,0.839366912,0.512300992,0.908300512,0.460120432,0.117465936,0.833881104,0.359671344,0.823889888,0.832161632,0.820029696,0.271792208,0.10275968,0.544625952,0.341982912,0.675960128,0.088002672,0.199708496,0.895694208,0.369371376,0.255545376,0.052142912,0.176983488,0.227254848,0.783475008,0.179367472,0.105071968,0.171813264,0.225724944,0.078940432,0.070889984,0.611955008,0.526939264,0.191376688,0.063307616,0.08079152,0.530845824,0.709763024,0.411870256,0.602953408,0.091333712,0.111568128,0.0110176,0.059682272,0.068240224,0.239740496,0.204836352,0.306788544,0.137022688,0.455213216,0.263227456,0.149565136,0.106718848,0.141581824,0.33903616,0.211743344,0.7658676,0.647872944,0.461386096,0.864771936,0.67612496,0.063589792,0.32212712,0.771557088,0.180570368,0.696387712,0.444399024,0.249297184,0.617852528,0.669499888,0.74021344,0.640297744,0.861534528,0.88799336,0.282104416,0.811290944,0.63270896 +695.0,0.89091,0.76684,0.2021,0.51208,0.89292,0.66181,0.46607,0.60303,0.06344,0.88167,0.7036,0.68325,0.26668,0.49444,0.62795,0.53846,0.61775,0.39783,0.51512,0.8503,0.90916,0.83218,0.87373,0.83899,0.5139,0.9084,0.46121,0.11781,0.83482,0.36075,0.82429,0.83652,0.82055,0.27228,0.10293,0.5433,0.35162,0.67638,0.08796,0.19927,0.89754,0.37529,0.26567,0.05211,0.17773,0.22799,0.78958,0.17893,0.10553,0.17093,0.2245,0.07849,0.07121,0.61435,0.52735,0.19243,0.06786,0.08141,0.52892,0.7096,0.41127,0.61321,0.09264,0.11151,0.01106,0.05967,0.06815,0.23921,0.20442,0.30629,0.14004,0.45534,0.27055,0.15524,0.10867,0.13917,0.33897,0.21842,0.76868,0.65419,0.46165,0.86826,0.68162,0.06349,0.32417,0.77313,0.18026,0.70375,0.45219,0.24973,0.61633,0.67212,0.74189,0.646,0.86235,0.8886,0.28021,0.81494,0.63294 +696.0,0.891343616,0.768739104,0.202626016,0.511994992,0.89493776,0.665921008,0.465691616,0.604659072,0.063307104,0.881954944,0.706384976,0.683850368,0.266584032,0.4945608,0.628363328,0.541291184,0.622274736,0.398686144,0.51493408,0.851480752,0.909312256,0.832901024,0.874284064,0.838614048,0.5151024,0.908495648,0.461934512,0.117882592,0.835714496,0.36174312,0.824677488,0.840623136,0.821079792,0.272748752,0.103098864,0.54190848,0.361261824,0.676792208,0.087909456,0.198794752,0.8992496,0.381685632,0.275661344,0.05208016,0.178366032,0.2286928,0.795261824,0.17851824,0.105995376,0.169989424,0.223194208,0.078010048,0.071512224,0.616605856,0.527694304,0.193437104,0.072354528,0.081996544,0.52696672,0.709406528,0.41062928,0.62343376,0.093912896,0.111439472,0.011109792,0.059655776,0.068063168,0.238641264,0.203980464,0.305760496,0.14290528,0.455469248,0.278010592,0.16115128,0.110521088,0.13683744,0.338769952,0.225247696,0.7715968,0.660433456,0.462072384,0.871570848,0.686897472,0.063380464,0.326658784,0.774839408,0.179863792,0.710601824,0.459869168,0.250123776,0.614723104,0.674764336,0.743522,0.6515652,0.862968016,0.888983632,0.278380768,0.818346096,0.633157984 +697.0,0.89175144,0.77059344,0.20276888,0.511921168,0.896913504,0.669597696,0.465317712,0.6062812,0.063165072,0.882247472,0.708920128,0.68466288,0.266470064,0.494672368,0.628731376,0.544026864,0.62635608,0.399497648,0.514760144,0.852544736,0.909454624,0.833624864,0.874834176,0.838236832,0.515858,0.90858736,0.46224512,0.117668688,0.83655968,0.362638144,0.82505168,0.844498912,0.821617216,0.273201536,0.103267568,0.54045752,0.370886576,0.677193984,0.087850016,0.198278528,0.900838208,0.388608944,0.285566896,0.052053312,0.178884096,0.229367168,0.800563328,0.178131984,0.106467584,0.168984816,0.221798096,0.077497232,0.071798784,0.618738528,0.527976496,0.194406208,0.076812976,0.082549744,0.524976784,0.709187952,0.409943408,0.633618704,0.09514512,0.111357056,0.011167712,0.059639632,0.067979344,0.23802976,0.20351512,0.305196432,0.145636528,0.45560064,0.285602688,0.167309024,0.112283888,0.134572064,0.338443264,0.23222144,0.774637344,0.666597168,0.462659552,0.874729776,0.69199624,0.063259968,0.329647856,0.776702496,0.17936936,0.71688792,0.46741416,0.250481904,0.613040528,0.67742248,0.745109008,0.656981088,0.86336528,0.88911488,0.276607376,0.821535568,0.63336504 +698.0,0.892113744,0.772287296,0.202788544,0.511871344,0.898844688,0.673117424,0.464973328,0.607894848,0.06302048,0.882524,0.7113588,0.685548672,0.266350096,0.494770096,0.629085824,0.546729824,0.630278864,0.400222832,0.514606288,0.8535648,0.909592832,0.834356624,0.875390368,0.837885696,0.51639568,0.908671552,0.462385168,0.117245664,0.837385744,0.363465808,0.825413952,0.847953408,0.8221608,0.27361184,0.103424192,0.53893616,0.380583408,0.67760528,0.087787856,0.197750384,0.902236576,0.395708416,0.294711088,0.052030304,0.17929392,0.229975296,0.805244512,0.177771568,0.106943312,0.167963168,0.220377584,0.076976576,0.072054944,0.62064064,0.528205088,0.195282112,0.080930384,0.083064944,0.523105328,0.708958256,0.409243936,0.643698768,0.096374464,0.11127296,0.011227632,0.059623408,0.06790344,0.237405856,0.203042656,0.304622288,0.148087536,0.455731632,0.293300144,0.173660768,0.113864688,0.132511168,0.337987856,0.239327744,0.777711328,0.67268248,0.46340904,0.877566864,0.696617968,0.063136032,0.332901008,0.778610304,0.178839328,0.722898336,0.474922672,0.250791792,0.611277552,0.680117824,0.746648336,0.662318896,0.863687184,0.889155408,0.274996144,0.82435968,0.633550416 +699.0,0.892401888,0.773654912,0.203092928,0.51186368,0.900727792,0.676908112,0.464693824,0.609498416,0.062883408,0.882751488,0.713940192,0.686291744,0.266242928,0.494847184,0.629475472,0.549497744,0.634484128,0.400801536,0.514484112,0.854653664,0.90973608,0.835103904,0.8759664,0.83759912,0.51710088,0.908743424,0.462746816,0.11674832,0.838239648,0.364286992,0.825766304,0.850705984,0.822709104,0.273941904,0.103551696,0.5373288,0.39049368,0.678057376,0.087732576,0.19725512,0.903342304,0.402442128,0.30214256,0.052012336,0.179617264,0.230463184,0.808954016,0.177437472,0.1074184,0.16699688,0.219034272,0.0764864,0.072259344,0.622156752,0.52839,0.195985216,0.084277232,0.083536384,0.521569552,0.70873432,0.408579584,0.653581872,0.097660608,0.111201024,0.011280272,0.059609664,0.067842336,0.236816432,0.202591792,0.304075824,0.150048304,0.455858784,0.3010696,0.180124272,0.115128768,0.130849552,0.337397168,0.246550608,0.780674832,0.678693232,0.464299568,0.879836592,0.700334576,0.063020336,0.3360264,0.780393792,0.178372736,0.729089712,0.482550224,0.2510344,0.609426976,0.682887888,0.748136464,0.667689504,0.864159568,0.889358896,0.273697952,0.826600992,0.633698352 +700.0,0.8926,0.7746,0.20393,0.51191,0.90256,0.68123,0.4645,0.61109,0.06276,0.88291,0.71681,0.68676,0.26616,0.4949,0.62993,0.55239,0.63924,0.4012,0.5144,0.85588,0.90989,0.83587,0.87657,0.8374,0.51821,0.9088,0.46357,0.11627,0.83915,0.36514,0.82611,0.8526,0.82326,0.27417,0.10364,0.53563,0.4007,0.67857,0.08769,0.19682,0.9041,0.40848,0.3073,0.052,0.17987,0.2308,0.8115,0.17713,0.10789,0.16613,0.21783,0.07605,0.0724,0.6232,0.52854,0.19647,0.0866,0.08396,0.5205,0.70853,0.40798,0.66321,0.09904,0.11115,0.01132,0.0596,0.0678,0.23629,0.20218,0.30358,0.1514,0.45598,0.30889,0.18665,0.116,0.1297,0.33667,0.25388,0.78344,0.68463,0.46531,0.8814,0.7029,0.06292,0.33878,0.78195,0.17803,0.73574,0.49039,0.2512,0.60749,0.68575,0.74957,0.67316,0.86492,0.88988,0.2728,0.82814,0.6338 +701.0,0.892711184,0.775133376,0.205261552,0.51200912,0.9043404,0.686048688,0.464390288,0.612667648,0.062649504,0.883000176,0.71994712,0.6869716,0.2660996,0.494929536,0.630445584,0.555398048,0.644509568,0.401423952,0.514352832,0.85723464,0.910053584,0.836651568,0.877199232,0.837287056,0.519667776,0.908841472,0.464811024,0.11579544,0.840112768,0.36601008,0.82644488,0.853663808,0.823810912,0.274298656,0.103689968,0.5338464,0.41118216,0.679138944,0.087659312,0.196441488,0.904523936,0.413864192,0.310221328,0.051993104,0.180045568,0.230989776,0.812926432,0.17684912,0.1083576,0.165356848,0.216756768,0.075664528,0.072479024,0.623786,0.528661392,0.19674296,0.087915744,0.084334864,0.519891968,0.708352896,0.40744128,0.672579712,0.100506928,0.111120496,0.011347424,0.059594448,0.06777608,0.2358228,0.201805072,0.303131824,0.152160576,0.456095184,0.316756448,0.193245792,0.116490128,0.129050928,0.335816832,0.261312096,0.786021776,0.690487888,0.46645,0.882279264,0.704345888,0.062834032,0.341210848,0.783293088,0.177801376,0.742805296,0.498423248,0.251292272,0.605474752,0.688692528,0.750946848,0.678720144,0.865949392,0.890695296,0.272293104,0.82900272,0.633857056 +702.0,0.892731504,0.775229536,0.207132704,0.512160864,0.906067968,0.691417024,0.464370608,0.614229648,0.0625532,0.88301616,0.72337888,0.686901712,0.266063856,0.494934976,0.631028384,0.558533264,0.650345824,0.401464752,0.514344448,0.85873128,0.910227632,0.837446784,0.877854208,0.837266896,0.521494,0.908867552,0.466503808,0.115319424,0.841133424,0.366892688,0.826770992,0.853857888,0.82435968,0.27432192,0.103698912,0.53197896,0.421950288,0.67976352,0.087641696,0.196125184,0.904601856,0.418526416,0.310744688,0.051991824,0.18013648,0.231024176,0.813188032,0.176594848,0.108820432,0.164686528,0.215827264,0.075334976,0.072493424,0.62389288,0.528761088,0.196792432,0.088151424,0.084659824,0.519783968,0.708211456,0.406969456,0.681670048,0.102067664,0.11111544,0.011361232,0.059593488,0.06777176,0.235420656,0.201470656,0.302736048,0.152298816,0.456203552,0.324656784,0.199901888,0.116579248,0.128933808,0.334848016,0.268839104,0.788406288,0.69626344,0.46773728,0.882439104,0.704607488,0.062763792,0.343296928,0.784402944,0.177697008,0.750334176,0.506663472,0.251309392,0.603383232,0.691716064,0.752265056,0.684382496,0.867274464,0.891832528,0.272201584,0.82916072,0.633867456 +703.0,0.892690784,0.775031136,0.209320736,0.512364048,0.907740416,0.6970912,0.464411648,0.615772128,0.062465376,0.882981984,0.72697512,0.686664144,0.266042512,0.494924256,0.631650384,0.56174112,0.6564996,0.401382432,0.514361984,0.86030712,0.91040784,0.83824488,0.878523744,0.837309376,0.523539104,0.908880352,0.468464592,0.114893728,0.84218624,0.367786576,0.827087824,0.853467488,0.824900528,0.274274224,0.103680176,0.53006472,0.432909776,0.680438496,0.0876316,0.1958456,0.904447616,0.4227736,0.309650368,0.051994304,0.180169072,0.230954016,0.812667712,0.176367056,0.109279104,0.164077648,0.21498376,0.075038944,0.072464384,0.62367776,0.528845264,0.196691504,0.087658464,0.084934944,0.520013888,0.708113056,0.406536912,0.690535744,0.1036916,0.111127024,0.01136712,0.059595648,0.06778064,0.235056832,0.20116024,0.302370992,0.152018496,0.45630776,0.33261872,0.206667824,0.116398688,0.129175008,0.33377128,0.276478352,0.79066528,0.701947152,0.46908192,0.882115104,0.704071808,0.062702912,0.345165968,0.78537312,0.177666,0.758083696,0.515021456,0.251276192,0.601259312,0.69476248,0.753519264,0.690083248,0.868770656,0.8931572,0.272389824,0.82884552,0.633846496 +704.0,0.892636544,0.774770656,0.211449088,0.512615152,0.909355104,0.702659056,0.464465248,0.617290208,0.062376352,0.882937888,0.73051528,0.686452736,0.266018208,0.494909856,0.632264224,0.564929456,0.662549776,0.401273152,0.51438496,0.86185576,0.910586848,0.839030016,0.87919008,0.837364576,0.525545248,0.908883552,0.470379376,0.114583872,0.843227616,0.368686704,0.827394416,0.852948448,0.825425936,0.274211408,0.10365576,0.52815888,0.443906624,0.681153552,0.087619664,0.195559616,0.904240896,0.427125504,0.308223008,0.051997664,0.180182544,0.230861376,0.811972032,0.176165504,0.109735216,0.163460208,0.214128576,0.074738592,0.072425824,0.62339184,0.52891952,0.196558256,0.087015584,0.085161344,0.520311168,0.708063776,0.406096928,0.69927264,0.105326656,0.111141488,0.011374688,0.059598368,0.06779232,0.234686128,0.200845904,0.302000016,0.151647296,0.456412288,0.340690176,0.21362648,0.116159488,0.129491968,0.332594944,0.28425944,0.792920832,0.707526064,0.470348,0.881685984,0.703365888,0.062640592,0.347045728,0.786362096,0.177621872,0.765642336,0.52334872,0.251231232,0.599166912,0.697743536,0.754702672,0.69571512,0.870226928,0.894441072,0.272637344,0.82842472,0.633818656 +705.0,0.8926,0.7746,0.21328,0.51291,0.91091,0.70786,0.4645,0.61878,0.06228,0.88291,0.73386,0.68639,0.26598,0.4949,0.63284,0.56804,0.66823,0.4012,0.5144,0.86331,0.91076,0.83979,0.87984,0.8374,0.52735,0.90888,0.47205,0.11443,0.84423,0.36959,0.82769,0.8526,0.82593,0.27417,0.10364,0.5263,0.45484,0.6819,0.0876,0.19524,0.9041,0.43191,0.3073,0.052,0.1802,0.2308,0.8115,0.17599,0.11019,0.16279,0.2132,0.07441,0.0724,0.6232,0.52899,0.19647,0.0866,0.08534,0.5205,0.70807,0.40562,0.70794,0.10694,0.11115,0.01139,0.0596,0.0678,0.23428,0.20051,0.3016,0.1514,0.45652,0.3489,0.22083,0.116,0.1297,0.33133,0.2922,0.79525,0.71299,0.47145,0.8814,0.7029,0.06257,0.34908,0.78747,0.17751,0.77275,0.53155,0.2512,0.59715,0.7006,0.75581,0.70121,0.87151,0.89554,0.2728,0.82814,0.6338 +706.0,0.892578368,0.774500672,0.214863392,0.513247984,0.912405136,0.712748144,0.464520096,0.620240544,0.062177616,0.882894128,0.73703872,0.686449376,0.265930192,0.494894112,0.633383968,0.5710848,0.67359528,0.401156864,0.514408192,0.864684096,0.91092832,0.84052368,0.880474,0.837420352,0.528991472,0.908869632,0.473520528,0.114435248,0.845199248,0.370499344,0.827974528,0.852394176,0.82641192,0.274145808,0.103630912,0.524486208,0.465719824,0.682678576,0.08757384,0.194892464,0.904016032,0.43705696,0.306767136,0.052001408,0.180222,0.230764032,0.811219424,0.17584072,0.110643488,0.162076304,0.212210992,0.074058144,0.072384768,0.62308672,0.529064352,0.196418288,0.086360128,0.08547136,0.520607776,0.70813888,0.405112336,0.716521088,0.10853888,0.111154608,0.011411808,0.059600896,0.06780448,0.233844432,0.200156224,0.301175792,0.151254592,0.456630336,0.357238304,0.228267056,0.115906176,0.129821216,0.329984688,0.300293632,0.797636048,0.7183372,0.47239488,0.881231808,0.702627616,0.062492576,0.351230208,0.788675664,0.177342144,0.779461632,0.5396408,0.251181184,0.595206768,0.703338528,0.756840736,0.706581152,0.872648096,0.8964848,0.272894848,0.82797104,0.633788992 +707.0,0.892575664,0.774488256,0.216185696,0.513630048,0.913841456,0.7173084,0.464522608,0.621671408,0.062068896,0.882892144,0.74004376,0.686636864,0.265868112,0.494893376,0.633894384,0.5740604,0.67862992,0.401151472,0.514407424,0.8659744,0.9110916,0.84123048,0.881092944,0.837422896,0.530463904,0.908852352,0.474781952,0.114612688,0.84613392,0.371416656,0.828247904,0.852368448,0.826871968,0.274142784,0.103629776,0.52271696,0.476531696,0.683491376,0.0875408,0.19451544,0.904005536,0.44258392,0.306700528,0.052001584,0.180261312,0.230759536,0.811184352,0.175718016,0.111096144,0.161316608,0.21115808,0.073681664,0.072382864,0.62307256,0.529150384,0.196411824,0.086330144,0.085556784,0.520621248,0.708276416,0.404572272,0.725016384,0.11012176,0.111155184,0.01144048,0.059601008,0.06780504,0.233377792,0.1997836,0.300726032,0.151236416,0.45674344,0.3657036,0.235939744,0.115894448,0.129836368,0.328562,0.308538992,0.80008288,0.723566832,0.4731664,0.881210784,0.702593568,0.062407952,0.353496208,0.78998456,0.17711552,0.785763216,0.547612416,0.251178832,0.593337632,0.70596072,0.757795584,0.711824048,0.873633856,0.89726784,0.272906704,0.82794992,0.633787616 +708.0,0.89258648,0.77453792,0.21733008,0.514039392,0.915215536,0.721629376,0.46451256,0.623068272,0.061955776,0.88290008,0.74292248,0.686912592,0.265797792,0.49489632,0.63438176,0.57698672,0.68342416,0.40117304,0.514401216,0.867203904,0.91125128,0.84189744,0.881683088,0.83741272,0.531820096,0.908831872,0.475899776,0.114914288,0.847043232,0.372339728,0.82850912,0.85247136,0.827302656,0.27415488,0.10363432,0.521010512,0.487296608,0.684319296,0.0875032,0.194118416,0.90404752,0.44837576,0.30696696,0.05200088,0.180277344,0.23077752,0.81132464,0.175621072,0.11154896,0.160526272,0.210062448,0.073288704,0.07239048,0.6231292,0.529254336,0.19643768,0.08645008,0.085596528,0.52056736,0.708490432,0.404010048,0.73340048,0.11169992,0.11115288,0.011473872,0.05960056,0.0678028,0.232890032,0.199398096,0.300258992,0.15130912,0.456858624,0.374279376,0.243829312,0.11594136,0.12977576,0.327099712,0.316924912,0.802564352,0.728667664,0.47381968,0.88129488,0.70272976,0.062318368,0.355844288,0.791362656,0.176848416,0.79174208,0.555491552,0.25118824,0.591556176,0.708454672,0.758667632,0.716960624,0.874513136,0.89793808,0.27285928,0.8280344,0.63379312 +709.0,0.892597296,0.774587584,0.218454864,0.514451456,0.916522416,0.725880912,0.464502512,0.624425536,0.061842016,0.882908016,0.74576552,0.68719976,0.265726832,0.494899264,0.634866096,0.57990192,0.6881512,0.401194608,0.514397248,0.868416528,0.91141016,0.84250744,0.882225792,0.837402544,0.533160928,0.908813312,0.47699944,0.115258608,0.847944864,0.37326496,0.828756816,0.852574272,0.827693824,0.274166976,0.103638864,0.519388224,0.4980636,0.685134656,0.08746536,0.193719472,0.904089504,0.45421392,0.307233392,0.052000176,0.180203136,0.230795504,0.811464928,0.175548608,0.112003136,0.159734576,0.208964576,0.072894864,0.072398096,0.62318584,0.529381968,0.196463536,0.086570016,0.085590512,0.520513472,0.708789408,0.403445184,0.741628096,0.1132948,0.111150576,0.011507904,0.059600112,0.06780056,0.232400112,0.199011152,0.299790352,0.151381824,0.456974448,0.382937952,0.25190048,0.115988272,0.129715152,0.325650784,0.325432992,0.805030544,0.733624976,0.4744532,0.881378976,0.702865952,0.062228144,0.358206368,0.792744832,0.176575872,0.797565744,0.563333008,0.251197648,0.58987568,0.710811024,0.75944736,0.72203368,0.875373456,0.89858912,0.272811856,0.82811888,0.633798624 +710.0,0.8926,0.7746,0.21966,0.51485,0.91776,0.73017,0.4645,0.62574,0.06173,0.88291,0.74863,0.68745,0.26566,0.4949,0.63536,0.58283,0.69292,0.4012,0.5144,0.86964,0.91157,0.84305,0.88271,0.8374,0.53455,0.9088,0.47816,0.11559,0.84885,0.37419,0.82899,0.8526,0.82804,0.27417,0.10364,0.51786,0.50886,0.68592,0.08743,0.19333,0.9041,0.45996,0.3073,0.052,0.18,0.2308,0.8115,0.1755,0.11246,0.15896,0.20789,0.07251,0.0724,0.6232,0.52954,0.19647,0.0866,0.08554,0.5205,0.70918,0.40289,0.74967,0.11492,0.11115,0.01154,0.0596,0.0678,0.23192,0.19863,0.29933,0.1514,0.45709,0.39166,0.26013,0.116,0.1297,0.32425,0.33405,0.80745,0.73843,0.47513,0.8814,0.7029,0.06214,0.36054,0.79409,0.17632,0.80334,0.57117,0.2512,0.5883,0.71303,0.76013,0.72707,0.87627,0.89928,0.2728,0.82814,0.6338 +711.0,0.8926,0.7746,0.220911936,0.515234832,0.918930896,0.734459552,0.4645,0.627012336,0.06161888,0.88291,0.751496272,0.687680304,0.265595712,0.4949,0.635859216,0.58576256,0.697692448,0.4012,0.514406976,0.870864896,0.91173016,0.843526,0.883137136,0.8374,0.535965568,0.908792192,0.479354224,0.115918672,0.8497548,0.375115104,0.829208384,0.8526,0.828343488,0.27417,0.10364,0.516426704,0.519663552,0.6866756,0.08739624,0.192946128,0.9041,0.465659168,0.3073,0.052,0.179683216,0.2308,0.8115,0.175475824,0.112920816,0.158196272,0.206830016,0.072130736,0.0724,0.6232,0.52973632,0.19647,0.0866,0.085448112,0.5205,0.709665984,0.40234032,0.7575332,0.116571088,0.11115,0.01157104,0.0596,0.0678,0.231445648,0.19825216,0.298874624,0.1514,0.457205664,0.400445616,0.268522832,0.116,0.1297,0.322898704,0.342774848,0.809833472,0.743083536,0.475834272,0.8814,0.7029,0.062052976,0.362862672,0.795412224,0.176073216,0.809028816,0.578986112,0.2512,0.58683016,0.715110176,0.760718624,0.732059504,0.877184,0.899990576,0.2728,0.82814,0.6338 +712.0,0.8926,0.7746,0.22220384,0.515602512,0.920037136,0.738741296,0.4645,0.628242672,0.061508416,0.88291,0.75436008,0.687894592,0.265533712,0.4949,0.63636288,0.58869768,0.70246,0.4012,0.514417536,0.872089184,0.91189048,0.84393472,0.883506128,0.8374,0.537402976,0.908790912,0.480576176,0.116249648,0.850658352,0.376039968,0.82941152,0.8526,0.828605536,0.27417,0.10364,0.515097632,0.530462128,0.687396896,0.08736392,0.192567056,0.9041,0.47131984,0.3073,0.052,0.179256464,0.2308,0.8115,0.175476512,0.11338688,0.157442032,0.205782768,0.071756304,0.0724,0.6232,0.529978256,0.19647,0.0866,0.085317808,0.5205,0.710251232,0.401795248,0.76521784,0.1182472,0.11115,0.011601232,0.0596,0.0678,0.230976192,0.197877056,0.298423552,0.1514,0.457321584,0.409290896,0.277077872,0.116,0.1297,0.321604832,0.351603712,0.812183232,0.747584624,0.47656592,0.8814,0.7029,0.061966848,0.365179808,0.796714576,0.175833856,0.81462464,0.586774912,0.2512,0.585475296,0.717040032,0.761215312,0.736999504,0.878111536,0.90071656,0.2728,0.82814,0.6338 +713.0,0.8926,0.7746,0.223525744,0.515957872,0.921084976,0.74300448,0.4645,0.629435008,0.061398592,0.88291,0.757215568,0.68809744,0.265473152,0.4949,0.636869584,0.59163272,0.707210752,0.4012,0.514429056,0.873310352,0.9120508,0.8442844,0.88382896,0.8374,0.538855744,0.908794112,0.481817888,0.116555504,0.851559984,0.376965072,0.829599376,0.8526,0.828834304,0.27417,0.10364,0.5138236,0.541241824,0.688097152,0.08733264,0.192191504,0.9041,0.476954192,0.3073,0.052,0.178754352,0.2308,0.8115,0.17550312,0.113860384,0.156695552,0.20474576,0.071385952,0.0724,0.6232,0.530276512,0.19647,0.0866,0.085154864,0.5205,0.71093712,0.401253616,0.77272536,0.119947392,0.11115,0.011630784,0.0596,0.0678,0.230510496,0.197504192,0.29797568,0.1514,0.457437664,0.418191776,0.285793712,0.116,0.1297,0.3203544,0.360532816,0.814502672,0.751942832,0.477317328,0.8814,0.7029,0.06188136,0.367494944,0.798000848,0.175599936,0.820118064,0.594529392,0.2512,0.584180272,0.718890688,0.76162912,0.741887024,0.879046832,0.901452144,0.2728,0.82814,0.6338 +714.0,0.8926,0.7746,0.224852768,0.516311472,0.922083376,0.747222704,0.4645,0.630595744,0.061289168,0.88291,0.760048416,0.688300288,0.265412272,0.4949,0.637375968,0.59456144,0.711916464,0.4012,0.514437376,0.87452192,0.91221072,0.84458912,0.884125392,0.8374,0.540307952,0.908797952,0.48305976,0.11680184,0.852457616,0.377891536,0.829772192,0.8526,0.829042352,0.27417,0.10364,0.512527488,0.55198296,0.688799888,0.08730152,0.191816432,0.9041,0.482594624,0.3073,0.052,0.17823208,0.2308,0.8115,0.175557168,0.114343968,0.155952432,0.203712752,0.0710176,0.0724,0.6232,0.530643488,0.19647,0.0866,0.08496672,0.5205,0.711723328,0.400712464,0.7800616,0.121668864,0.11115,0.011660256,0.0596,0.0678,0.23004568,0.197132128,0.297528368,0.1514,0.457553824,0.427146016,0.294671472,0.116,0.1297,0.319119088,0.36955952,0.816799952,0.756174,0.478069216,0.8814,0.7029,0.061795872,0.36981664,0.79928072,0.175366336,0.825484608,0.602237312,0.2512,0.582860048,0.720770944,0.761973568,0.746715264,0.879975808,0.902182848,0.2728,0.82814,0.6338 +715.0,0.8926,0.7746,0.22617,0.51667,0.92304,0.75138,0.4645,0.63173,0.06118,0.88291,0.76285,0.68851,0.26535,0.4949,0.63788,0.59748,0.71656,0.4012,0.51444,0.87572,0.91237,0.84486,0.88441,0.8374,0.54175,0.9088,0.48429,0.11697,0.85335,0.37882,0.82993,0.8526,0.82924,0.27417,0.10364,0.51116,0.56267,0.68952,0.08727,0.19144,0.9041,0.48826,0.3073,0.052,0.17773,0.2308,0.8115,0.17564,0.11484,0.15521,0.20268,0.07065,0.0724,0.6232,0.53109,0.19647,0.0866,0.08476,0.5205,0.71261,0.40017,0.78723,0.12341,0.11115,0.01169,0.0596,0.0678,0.22958,0.19676,0.29708,0.1514,0.45767,0.43615,0.30371,0.116,0.1297,0.31788,0.37868,0.81908,0.76029,0.47881,0.8814,0.7029,0.06171,0.37215,0.80056,0.17513,0.83071,0.60989,0.2512,0.58146,0.72275,0.76226,0.75148,0.88089,0.9029,0.2728,0.82814,0.6338 +716.0,0.8926,0.7746,0.227487392,0.517030144,0.923958464,0.75548656,0.4645,0.632839264,0.061071296,0.88291,0.765625856,0.688722,0.265286864,0.4949,0.638382928,0.600390576,0.721151584,0.4012,0.514437376,0.876907328,0.912528816,0.845099376,0.884681952,0.8374,0.543188096,0.908801024,0.485516256,0.11705656,0.854238192,0.379750032,0.830072368,0.8526,0.829430912,0.27417,0.10364,0.509726944,0.57329768,0.69025336,0.087238368,0.191063344,0.9041,0.493935456,0.3073,0.052,0.177248144,0.2308,0.8115,0.175752272,0.115350144,0.154470048,0.201649984,0.070284096,0.0724,0.6232,0.531622336,0.19647,0.0866,0.084538832,0.5205,0.713598704,0.399627424,0.794227424,0.125172224,0.11115,0.011719776,0.0596,0.0678,0.22911464,0.19638848,0.296631568,0.1514,0.457786128,0.445196864,0.312902896,0.116,0.1297,0.316644256,0.387887936,0.821339776,0.764290704,0.47954752,0.8814,0.7029,0.061624016,0.374491696,0.80183472,0.174893056,0.83580536,0.61748776,0.2512,0.579985232,0.724821728,0.762493104,0.756183456,0.88179488,0.903609392,0.2728,0.82814,0.6338 +717.0,0.8926,0.7746,0.228809904,0.517390112,0.924843136,0.75954744,0.4645,0.633925808,0.060963232,0.88291,0.768378688,0.688934,0.265223072,0.4949,0.638885344,0.60329416,0.725695872,0.4012,0.514429056,0.878085392,0.91268728,0.84531136,0.88494056,0.8374,0.544625344,0.908801152,0.486742288,0.117046064,0.855122864,0.380681472,0.830198976,0.8526,0.829620064,0.27417,0.10364,0.50822232,0.583859104,0.690999472,0.0872068,0.190687024,0.9041,0.499612912,0.3073,0.052,0.176788752,0.2308,0.8115,0.17589472,0.115876224,0.153733552,0.20062392,0.069920432,0.0724,0.6232,0.532246192,0.19647,0.0866,0.084307824,0.5205,0.71468984,0.399085376,0.80105232,0.126956352,0.11115,0.011749424,0.0596,0.0678,0.228650256,0.196017952,0.2961836,0.1514,0.457902144,0.454280336,0.322244272,0.116,0.1297,0.31541648,0.397177296,0.823577872,0.768176272,0.480285808,0.8814,0.7029,0.06153808,0.376840144,0.803102848,0.174656576,0.840776864,0.625029312,0.2512,0.578428192,0.726997408,0.76267888,0.760826624,0.882693152,0.904313904,0.2728,0.82814,0.6338 +718.0,0.8926,0.7746,0.230137696,0.51775184,0.925701248,0.76356208,0.4645,0.634993552,0.060855568,0.88291,0.77110856,0.689146,0.2651588,0.4949,0.63938728,0.606190464,0.7301932,0.4012,0.514417536,0.879253856,0.912845344,0.845505104,0.885199968,0.8374,0.546061552,0.90880064,0.48796816,0.116995888,0.856003536,0.381613952,0.830309424,0.8526,0.829816336,0.27417,0.10364,0.506665376,0.594344688,0.691755904,0.087175072,0.190311024,0.9041,0.505290688,0.3073,0.052,0.17638152,0.2308,0.8115,0.176068928,0.116420224,0.153000096,0.199601856,0.069558768,0.0724,0.6232,0.532972528,0.19647,0.0866,0.084073216,0.5205,0.715884656,0.398543648,0.807705296,0.1287624,0.11115,0.011779152,0.0596,0.0678,0.228186592,0.195648224,0.295735872,0.1514,0.45801808,0.463394448,0.331729328,0.116,0.1297,0.314184784,0.406541856,0.825794128,0.77195848,0.481024416,0.8814,0.7029,0.061452144,0.379194832,0.804364576,0.174420576,0.845625648,0.632511024,0.2512,0.576809952,0.729241888,0.762827616,0.765409072,0.883584944,0.905013696,0.2728,0.82814,0.6338 +719.0,0.8926,0.7746,0.231471008,0.518117968,0.92654104,0.76752976,0.4645,0.636046896,0.060747904,0.88291,0.773815632,0.689358,0.265094368,0.4949,0.639888816,0.609079168,0.734644448,0.4012,0.514406976,0.88041216,0.913002928,0.845691408,0.885479216,0.8374,0.54749648,0.908800128,0.489194032,0.116998352,0.856879408,0.382546912,0.830403232,0.8526,0.830029888,0.27417,0.10364,0.505093232,0.604744672,0.692517296,0.087142864,0.189935344,0.9041,0.510966944,0.3073,0.052,0.176063888,0.2308,0.8115,0.176276816,0.116984144,0.15226904,0.198583872,0.069198704,0.0724,0.6232,0.533813984,0.19647,0.0866,0.083841808,0.5205,0.717184672,0.39800192,0.814187472,0.130590288,0.11115,0.01180928,0.0596,0.0678,0.227723248,0.195278976,0.295288064,0.1514,0.458134016,0.47253304,0.341353104,0.116,0.1297,0.312932528,0.415974976,0.827988224,0.775653008,0.481762624,0.8814,0.7029,0.061366128,0.38155496,0.805620224,0.174185056,0.850352912,0.639929056,0.2512,0.575171632,0.731490048,0.762951072,0.76993032,0.884470496,0.905709008,0.2728,0.82814,0.6338 +720.0,0.8926,0.7746,0.23281,0.51849,0.92737,0.77145,0.4645,0.63709,0.06064,0.88291,0.7765,0.68957,0.26503,0.4949,0.64039,0.61196,0.73905,0.4012,0.5144,0.88156,0.91316,0.84588,0.88579,0.8374,0.54893,0.9088,0.49042,0.11711,0.85775,0.38348,0.83048,0.8526,0.83027,0.27417,0.10364,0.50353,0.61505,0.69328,0.08711,0.18956,0.9041,0.51664,0.3073,0.052,0.17586,0.2308,0.8115,0.17652,0.11757,0.15154,0.19757,0.06884,0.0724,0.6232,0.53478,0.19647,0.0866,0.08362,0.5205,0.71859,0.39746,0.8205,0.13244,0.11115,0.01184,0.0596,0.0678,0.22726,0.19491,0.29484,0.1514,0.45825,0.48169,0.35111,0.116,0.1297,0.31165,0.42547,0.83016,0.77927,0.4825,0.8814,0.7029,0.06128,0.38392,0.80687,0.17395,0.85496,0.64728,0.2512,0.57354,0.7337,0.76306,0.77439,0.88535,0.9064,0.2728,0.82814,0.6338 +721.0,0.8926,0.7746,0.234154656,0.51886792,0.928189392,0.77532272,0.4645,0.638124288,0.060531904,0.88291,0.7791616,0.689782,0.264965632,0.4949,0.640890816,0.614832784,0.743409328,0.4012,0.514396096,0.882697472,0.913316592,0.846071632,0.886131632,0.8374,0.550362064,0.9088,0.491646,0.117317408,0.858615424,0.384413264,0.83054136,0.8526,0.8305352,0.27417,0.10364,0.501968,0.625252944,0.694045424,0.087076496,0.189184976,0.9041,0.522308464,0.3073,0.052,0.175773296,0.2308,0.8115,0.176795216,0.118176368,0.150813008,0.196560224,0.068482688,0.0724,0.6232,0.535875472,0.19647,0.0866,0.083407984,0.5205,0.720100096,0.39691792,0.826643728,0.134311728,0.11115,0.01187128,0.0596,0.0678,0.226796864,0.194541328,0.294391696,0.1514,0.458365984,0.490859504,0.360993648,0.116,0.1297,0.310337536,0.43502064,0.832309584,0.782810288,0.483236624,0.8814,0.7029,0.061193776,0.386289952,0.808113872,0.173715424,0.85944832,0.654561184,0.2512,0.571906256,0.735883872,0.763157328,0.778787984,0.886223424,0.907086672,0.2728,0.82814,0.6338 +722.0,0.8926,0.7746,0.235504976,0.5192524,0.928996368,0.77914776,0.4645,0.639149312,0.060423568,0.88291,0.7818004,0.689994,0.2649012,0.4949,0.64139128,0.617697344,0.74772224,0.4012,0.514395456,0.883824496,0.913472704,0.846261344,0.886505728,0.8374,0.551792512,0.9088,0.492872,0.117622048,0.859475616,0.385346672,0.830590784,0.8526,0.830815856,0.27417,0.10364,0.500404816,0.635346048,0.694814464,0.087042272,0.188810224,0.9041,0.527970848,0.3073,0.052,0.17581176,0.2308,0.8115,0.177095088,0.118798384,0.150087936,0.195554576,0.068126688,0.0724,0.6232,0.537106608,0.19647,0.0866,0.083200896,0.5205,0.721715776,0.396375648,0.832619776,0.13620568,0.11115,0.011903152,0.0596,0.0678,0.226333712,0.194172944,0.293943072,0.1514,0.45848192,0.500035728,0.370997488,0.116,0.1297,0.308991504,0.444620496,0.834437008,0.78627672,0.483972416,0.8814,0.7029,0.061107424,0.388664672,0.809351856,0.173481376,0.863819248,0.661769904,0.2512,0.570267312,0.738043968,0.763241136,0.783124192,0.887090704,0.907769056,0.2728,0.82814,0.6338 +723.0,0.8926,0.7746,0.236860976,0.51964048,0.929810464,0.78292536,0.4645,0.640175136,0.060315232,0.88291,0.7844164,0.690206,0.264836928,0.4949,0.641891344,0.620553504,0.751987632,0.4012,0.514397056,0.88494168,0.913628496,0.846476096,0.886902384,0.8374,0.55322184,0.9088,0.494098,0.117990848,0.860331008,0.3862804,0.830622448,0.8526,0.831145632,0.27417,0.10364,0.498844832,0.645321552,0.695584144,0.087007728,0.188435952,0.9041,0.533625952,0.3073,0.052,0.175956624,0.2308,0.8115,0.17743328,0.11944848,0.149365264,0.194552848,0.067772288,0.0724,0.6232,0.538471424,0.19647,0.0866,0.083020208,0.5205,0.723428656,0.395833376,0.838429824,0.138121792,0.11115,0.011935424,0.0596,0.0678,0.22587104,0.19380488,0.293494528,0.1514,0.458597856,0.509212272,0.381113808,0.116,0.1297,0.307627632,0.454262192,0.836542592,0.789662832,0.484707808,0.8814,0.7029,0.061021152,0.391044352,0.81058392,0.173247648,0.868074896,0.668903904,0.2512,0.568629248,0.740179584,0.763336624,0.7873984,0.887952224,0.90844712,0.2728,0.82814,0.6338 +724.0,0.8926,0.7746,0.238222656,0.52002736,0.93066,0.786656,0.4645,0.641216,0.060207296,0.88291,0.7870096,0.690418,0.264773136,0.4949,0.642390928,0.623401104,0.756203904,0.4012,0.514398976,0.886049984,0.913784208,0.846755408,0.88730464,0.8374,0.554650848,0.9088,0.495324,0.118366768,0.86118232,0.387214768,0.830626832,0.8526,0.831575328,0.27417,0.10364,0.497292288,0.655171856,0.696350224,0.086973504,0.18806248,0.9041,0.539272736,0.3073,0.052,0.176173808,0.2308,0.8115,0.177831792,0.120146016,0.148645792,0.19355472,0.067419968,0.0724,0.6232,0.53996352,0.19647,0.0866,0.08289784,0.5205,0.725226096,0.395291424,0.844075872,0.140059904,0.11115,0.011967776,0.0596,0.0678,0.225409648,0.193437216,0.293046704,0.1514,0.458713872,0.518382496,0.391334128,0.116,0.1297,0.30627168,0.463937888,0.838626816,0.792956624,0.48544352,0.8814,0.7029,0.06093528,0.393429392,0.811809984,0.17301392,0.872217744,0.675961264,0.2512,0.566998704,0.74229424,0.763479632,0.791610368,0.888808544,0.909120784,0.2728,0.82814,0.6338 +725.0,0.8926,0.7746,0.23959,0.52041,0.93156,0.79034,0.4645,0.64228,0.0601,0.88291,0.78958,0.69063,0.26471,0.4949,0.64289,0.62624,0.76037,0.4012,0.5144,0.88715,0.91394,0.84712,0.8877,0.8374,0.55608,0.9088,0.49655,0.11871,0.86203,0.38815,0.8306,0.8526,0.83213,0.27417,0.10364,0.49575,0.66489,0.69711,0.08694,0.18769,0.9041,0.54491,0.3073,0.052,0.17644,0.2308,0.8115,0.1783,0.1209,0.14793,0.19256,0.06707,0.0724,0.6232,0.54158,0.19647,0.0866,0.08285,0.5205,0.7271,0.39475,0.84956,0.14202,0.11115,0.012,0.0596,0.0678,0.22495,0.19307,0.2926,0.1514,0.45883,0.52754,0.40165,0.116,0.1297,0.30494,0.47364,0.84069,0.79615,0.48618,0.8814,0.7029,0.06085,0.39582,0.81303,0.17278,0.87625,0.68294,0.2512,0.56538,0.74439,0.76369,0.79576,0.88966,0.90979,0.2728,0.82814,0.6338 +726.0,0.8926,0.7746,0.240962992,0.52078888,0.932509168,0.79397728,0.4645,0.643367072,0.059993296,0.88291,0.792127616,0.690841984,0.264647504,0.4949,0.643388576,0.629070016,0.764485872,0.4012,0.514400512,0.88824168,0.91409584,0.84756752,0.888089552,0.8374,0.5575092,0.9088,0.497776,0.119027456,0.862873952,0.389086032,0.830543952,0.8526,0.832804512,0.27417,0.10364,0.494219792,0.674469904,0.697863456,0.086907136,0.187318496,0.9041,0.550536304,0.3073,0.052,0.176763968,0.2308,0.8115,0.178833728,0.121707696,0.147217792,0.19156872,0.06672232,0.0724,0.6232,0.543328704,0.19647,0.0866,0.082874144,0.5205,0.72905576,0.394209056,0.854884096,0.14400224,0.11115,0.012032128,0.0596,0.0678,0.224492016,0.192703216,0.292154352,0.1514,0.45894624,0.536679008,0.412053648,0.116,0.1297,0.303629856,0.483361696,0.842732192,0.79924648,0.486917152,0.8814,0.7029,0.06076528,0.398216,0.814243984,0.172545904,0.880173312,0.689837856,0.2512,0.563775008,0.746462912,0.763967136,0.799847328,0.890506592,0.9104548,0.2728,0.82814,0.6338 +727.0,0.8926,0.7746,0.242341616,0.52116368,0.933516384,0.79756784,0.4645,0.644481376,0.059887232,0.88291,0.79465248,0.69105392,0.264585728,0.4949,0.643886624,0.631890944,0.768551232,0.4012,0.514400576,0.8893252,0.914251696,0.848110176,0.888474144,0.8374,0.55893856,0.9088,0.499002,0.119323328,0.863714208,0.3900228,0.830455488,0.8526,0.833614992,0.27417,0.10364,0.492704032,0.683905792,0.698609904,0.086874928,0.186948032,0.9041,0.556150352,0.3073,0.052,0.177155264,0.2308,0.8115,0.1794404,0.12257536,0.146509264,0.190580848,0.066377008,0.0724,0.6232,0.545218704,0.19647,0.0866,0.082980368,0.5205,0.731101696,0.393668576,0.860050144,0.146006672,0.11115,0.012064144,0.0596,0.0678,0.22403584,0.19233688,0.291709808,0.1514,0.459062656,0.545793792,0.422537008,0.116,0.1297,0.302342752,0.493096032,0.844753552,0.802249872,0.487655008,0.8814,0.7029,0.060681152,0.400617312,0.81545192,0.172311568,0.883989536,0.696652784,0.2512,0.562186608,0.748509824,0.764321984,0.80387232,0.891348464,0.9111152,0.2728,0.82814,0.6338 +728.0,0.8926,0.7746,0.24372576,0.52153568,0.93453936,0.80111176,0.4645,0.64560624,0.059781568,0.88291,0.797154544,0.691265856,0.264524272,0.4949,0.644384352,0.634702832,0.772566512,0.4012,0.51440032,0.8904,0.914407632,0.848687472,0.888841136,0.8374,0.56036744,0.9088,0.500228,0.11957048,0.864550544,0.390960528,0.830357504,0.8526,0.834471152,0.27417,0.10364,0.491198432,0.69319248,0.699351152,0.0868432,0.186578368,0.9041,0.56175032,0.3073,0.052,0.17759024,0.2308,0.8115,0.180069152,0.123464384,0.145803936,0.189596576,0.066033616,0.0724,0.6232,0.547245424,0.19647,0.0866,0.083115472,0.5205,0.733227072,0.393128576,0.865060992,0.148033904,0.11115,0.01209608,0.0596,0.0678,0.223580784,0.191970944,0.291266144,0.1514,0.459178992,0.554878096,0.433090768,0.116,0.1297,0.301072528,0.502835568,0.846753872,0.805151984,0.488393344,0.8814,0.7029,0.060597424,0.403023664,0.816653856,0.172077232,0.88770016,0.703382752,0.2512,0.560609088,0.750535296,0.764707712,0.807835552,0.892185136,0.9117712,0.2728,0.82814,0.6338 +729.0,0.8926,0.7746,0.245115264,0.52190728,0.935510896,0.80460912,0.4645,0.646714624,0.059675904,0.88291,0.799633728,0.691477872,0.264462496,0.4949,0.64488208,0.63750584,0.776532592,0.4012,0.514400064,0.89146512,0.914563728,0.849203568,0.889173328,0.8374,0.5617948,0.9088,0.501454,0.119732992,0.86538256,0.391899536,0.8302852,0.8526,0.835231552,0.27417,0.10364,0.489695392,0.702325328,0.70009048,0.086811632,0.186209104,0.9041,0.567334128,0.3073,0.052,0.178034256,0.2308,0.8115,0.180641584,0.124314768,0.145101008,0.188616224,0.065691424,0.0724,0.6232,0.549399664,0.19647,0.0866,0.083195696,0.5205,0.735414848,0.392589056,0.86991992,0.150084816,0.11115,0.012128016,0.0596,0.0678,0.223125728,0.191605328,0.29082296,0.1514,0.459294848,0.56392552,0.443705008,0.116,0.1297,0.299807424,0.512572704,0.848732752,0.807940656,0.48913176,0.8814,0.7029,0.060513776,0.405434656,0.817849872,0.171843296,0.891306464,0.71002576,0.2512,0.559032368,0.752547008,0.76504904,0.811737904,0.893015808,0.9124228,0.2728,0.82814,0.6338 +730.0,0.8926,0.7746,0.24651,0.52228,0.93639,0.80806,0.4645,0.64779,0.05957,0.88291,0.80209,0.69169,0.2644,0.4949,0.64538,0.6403,0.78045,0.4012,0.5144,0.89252,0.91472,0.8496,0.88946,0.8374,0.56322,0.9088,0.50268,0.11979,0.86621,0.39284,0.83026,0.8526,0.83581,0.27417,0.10364,0.48819,0.7113,0.70083,0.08678,0.18584,0.9041,0.5729,0.3073,0.052,0.17847,0.2308,0.8115,0.18111,0.12509,0.1444,0.18764,0.06535,0.0724,0.6232,0.55168,0.19647,0.0866,0.08317,0.5205,0.73766,0.39205,0.87463,0.15216,0.11115,0.01216,0.0596,0.0678,0.22267,0.19124,0.29038,0.1514,0.45941,0.57293,0.45437,0.116,0.1297,0.29854,0.5223,0.85069,0.81061,0.48987,0.8814,0.7029,0.06043,0.40785,0.81904,0.17161,0.89481,0.71658,0.2512,0.55745,0.75455,0.7653,0.81558,0.89384,0.91307,0.2728,0.82814,0.6338 +731.0,0.8926,0.7746,0.247909968,0.52265336,0.937183568,0.811464528,0.4645,0.64883552,0.059463904,0.88291,0.804523392,0.691902224,0.264336864,0.4949,0.64587808,0.643085136,0.784318512,0.4012,0.5144,0.893564832,0.914876464,0.849886304,0.889701648,0.8374,0.564643152,0.9088,0.503905984,0.119744032,0.867032944,0.393781904,0.8302792,0.8526,0.836219424,0.27417,0.10364,0.486683392,0.720112352,0.701569152,0.086748368,0.185471104,0.9041,0.578446688,0.3073,0.052,0.17890032,0.2308,0.8115,0.181480608,0.125795216,0.143701008,0.186667856,0.065009408,0.0724,0.6232,0.554093616,0.19647,0.0866,0.083046352,0.5205,0.739972128,0.391511424,0.879193728,0.154259504,0.11115,0.012192016,0.0596,0.0678,0.222213728,0.190874992,0.289937312,0.1514,0.459524496,0.581886112,0.4650768,0.116,0.1297,0.297272784,0.532010528,0.852625776,0.813163728,0.490608128,0.8814,0.7029,0.060346144,0.410269632,0.82022424,0.171377296,0.898212768,0.723043984,0.2512,0.555863504,0.756543456,0.765468912,0.819361968,0.894657824,0.913712816,0.2728,0.82814,0.6338 +732.0,0.8926,0.7746,0.2493152,0.52302728,0.93788504,0.81482288,0.4645,0.64984896,0.059357568,0.88291,0.806933904,0.692114576,0.264273072,0.4949,0.646376352,0.645861152,0.788138112,0.4012,0.5144,0.8945996,0.915033232,0.850052752,0.889896736,0.8374,0.56606416,0.9088,0.50513192,0.1195924,0.867851424,0.394725328,0.830347264,0.8526,0.836444192,0.27417,0.10364,0.485175552,0.72875872,0.702307872,0.0867168,0.185102368,0.9041,0.5839728,0.3073,0.052,0.17931424,0.2308,0.8115,0.181743632,0.126423344,0.143003936,0.185699776,0.064669536,0.0724,0.6232,0.556641424,0.19647,0.0866,0.082815792,0.5205,0.742353472,0.390973376,0.883613792,0.156383504,0.11115,0.01222408,0.0596,0.0678,0.221756784,0.190510304,0.289494864,0.1514,0.459638272,0.590788496,0.475816288,0.116,0.1297,0.296006368,0.541697488,0.854540112,0.815602864,0.491346144,0.8814,0.7029,0.060262224,0.412693424,0.821402656,0.171145232,0.90151664,0.729416352,0.2512,0.554272768,0.758527616,0.765549072,0.823084112,0.895469216,0.91435128,0.2728,0.82814,0.6338 +733.0,0.8926,0.7746,0.250725472,0.5234016,0.938528352,0.818134992,0.4645,0.65084288,0.059251232,0.88291,0.809321696,0.692326848,0.2642088,0.4949,0.646874624,0.648627648,0.791908512,0.4012,0.5144,0.895624848,0.91518984,0.8501484,0.890053024,0.8374,0.567483488,0.9088,0.506357856,0.119363008,0.868665424,0.395669872,0.830444048,0.8526,0.83655992,0.27417,0.10364,0.483666752,0.737235728,0.703046112,0.086685072,0.184734032,0.9041,0.589477472,0.3073,0.052,0.17977192,0.2308,0.8115,0.181943776,0.127007712,0.142309264,0.184735776,0.064330864,0.0724,0.6232,0.559357712,0.19647,0.0866,0.082522512,0.5205,0.744849216,0.390435648,0.887892976,0.158531824,0.11115,0.012256144,0.0596,0.0678,0.22129984,0.190146096,0.289052736,0.1514,0.459751728,0.59963176,0.486578496,0.116,0.1297,0.294741232,0.551353248,0.856433488,0.81794264,0.49208408,0.8814,0.7029,0.060178224,0.415121376,0.822574992,0.170913568,0.904724032,0.73569568,0.2512,0.552678832,0.760502336,0.765576832,0.826746336,0.896274608,0.914985344,0.2728,0.82814,0.6338 +734.0,0.8926,0.7746,0.252140464,0.52377592,0.939171184,0.821400704,0.4645,0.65183872,0.059145296,0.88291,0.811687008,0.69253872,0.264144368,0.4949,0.647372576,0.651384064,0.795629232,0.4012,0.5144,0.896641456,0.915345568,0.850256608,0.890184112,0.8374,0.568901936,0.9088,0.507583872,0.119101216,0.869474944,0.396614896,0.830535472,0.8526,0.836694848,0.27417,0.10364,0.482158032,0.745540336,0.703783552,0.086652864,0.184366496,0.9041,0.594960144,0.3073,0.052,0.18036784,0.2308,0.8115,0.18215664,0.12760472,0.141617792,0.183775856,0.063994192,0.0724,0.6232,0.5622928,0.19647,0.0866,0.082241472,0.5205,0.747526,0.38989792,0.89203408,0.160704064,0.11115,0.012288128,0.0596,0.0678,0.220844016,0.189782608,0.288611088,0.1514,0.459865504,0.608410624,0.497353104,0.116,0.1297,0.293478816,0.560969888,0.858306624,0.820206096,0.492822016,0.8814,0.7029,0.060094144,0.417553568,0.823740848,0.170681904,0.907837664,0.741880608,0.2512,0.551084096,0.762466656,0.765614112,0.83034832,0.89707472,0.915614928,0.2728,0.82814,0.6338 +735.0,0.8926,0.7746,0.25356,0.52415,0.93985,0.82462,0.4645,0.65285,0.05904,0.88291,0.81403,0.69275,0.26408,0.4949,0.64787,0.65413,0.7993,0.4012,0.5144,0.89765,0.9155,0.85043,0.8903,0.8374,0.57032,0.9088,0.50881,0.11884,0.87028,0.39756,0.8306,0.8526,0.83693,0.27417,0.10364,0.48065,0.75367,0.70452,0.08662,0.184,0.9041,0.60042,0.3073,0.052,0.18116,0.2308,0.8115,0.18243,0.12825,0.14093,0.18282,0.06366,0.0724,0.6232,0.56548,0.19647,0.0866,0.08202,0.5205,0.75043,0.38936,0.89604,0.1629,0.11115,0.01232,0.0596,0.0678,0.22039,0.18942,0.28817,0.1514,0.45998,0.61712,0.50813,0.116,0.1297,0.29222,0.57054,0.86016,0.82241,0.49356,0.8814,0.7029,0.06001,0.41999,0.8249,0.17045,0.91086,0.74797,0.2512,0.54949,0.76442,0.7657,0.83389,0.89787,0.91624,0.2728,0.82814,0.6338 +736.0,0.8926,0.7746,0.254984096,0.524524,0.940557008,0.827793072,0.4645,0.653873712,0.05893528,0.88291,0.816350704,0.69296072,0.264015632,0.4949,0.648366928,0.65686536,0.802920944,0.4012,0.5144,0.898650416,0.915653184,0.850657248,0.890399744,0.8374,0.571737536,0.9088,0.510036224,0.118577232,0.871080576,0.398505248,0.830642144,0.8526,0.837248128,0.27417,0.10364,0.479142048,0.76162264,0.70525568,0.086586496,0.18363448,0.9041,0.605855728,0.3073,0.052,0.18213688,0.2308,0.8115,0.182753872,0.128936064,0.140245792,0.181868224,0.063328192,0.0724,0.6232,0.56890152,0.19647,0.0866,0.081847984,0.5205,0.753546064,0.38882192,0.899913664,0.165119808,0.11115,0.01235176,0.0596,0.0678,0.219937648,0.18905824,0.28772944,0.1514,0.460095152,0.625755088,0.518899888,0.116,0.1297,0.290964096,0.580057136,0.861993648,0.824552144,0.494298,0.8814,0.7029,0.059925776,0.422430528,0.826052496,0.17021792,0.913792928,0.753962928,0.2512,0.547895712,0.766363056,0.765825936,0.837371792,0.898660384,0.916860608,0.2728,0.82814,0.6338 +737.0,0.8926,0.7746,0.256412672,0.524898,0.941294112,0.830920032,0.4645,0.65491048,0.058831152,0.88291,0.818649216,0.693170848,0.2639512,0.4949,0.648863344,0.659589968,0.806492112,0.4012,0.5144,0.899642768,0.91580496,0.85094112,0.890482784,0.8374,0.573154528,0.9088,0.511262576,0.118311488,0.871876624,0.399450592,0.830660688,0.8526,0.83765352,0.27417,0.10364,0.477633792,0.769396448,0.705990752,0.086552272,0.183269952,0.9041,0.611266192,0.3073,0.052,0.1833024,0.2308,0.8115,0.183130976,0.129664912,0.139565264,0.180920576,0.062998864,0.0724,0.6232,0.572528112,0.19647,0.0866,0.081727952,0.5205,0.756848016,0.388283648,0.903657936,0.167363584,0.11115,0.012383344,0.0596,0.0678,0.21948704,0.188697296,0.287289456,0.1514,0.460211008,0.63431128,0.529653616,0.116,0.1297,0.289710672,0.589514848,0.863807728,0.82662824,0.495036,0.8814,0.7029,0.059841424,0.424875056,0.827198272,0.169985648,0.916638432,0.75985848,0.2512,0.546300912,0.768296336,0.765993792,0.840794016,0.899445968,0.917476784,0.2728,0.82814,0.6338 +738.0,0.8926,0.7746,0.257846128,0.525272,0.942049296,0.834001392,0.4645,0.655955728,0.058727424,0.88291,0.820925408,0.693380576,0.263886928,0.4949,0.64935928,0.662303856,0.81001376,0.4012,0.5144,0.90062696,0.915956016,0.851263632,0.890559024,0.8374,0.5745708,0.9088,0.512488848,0.118070944,0.872668352,0.400396256,0.830662992,0.8526,0.838118912,0.27417,0.10364,0.476125456,0.776990656,0.706725024,0.086517728,0.182906224,0.9041,0.616649856,0.3073,0.052,0.18461928,0.2308,0.8115,0.18354496,0.13042432,0.138887936,0.179976848,0.062671536,0.0724,0.6232,0.576404704,0.19647,0.0866,0.08164368,0.5205,0.760392928,0.387745376,0.907276288,0.16963144,0.11115,0.012415008,0.0596,0.0678,0.219037712,0.188337232,0.286849792,0.1514,0.460327344,0.642783872,0.540380544,0.116,0.1297,0.288460128,0.59890688,0.865602048,0.828657456,0.495774,0.8814,0.7029,0.059757152,0.427323344,0.828337728,0.169753376,0.919398496,0.765656432,0.2512,0.544705312,0.770219216,0.766190528,0.84415728,0.900226432,0.91808864,0.2728,0.82814,0.6338 +739.0,0.8926,0.7746,0.259285104,0.525646,0.94279944,0.837037872,0.4645,0.657000736,0.058623776,0.88291,0.82317904,0.693590224,0.263823136,0.4949,0.649854816,0.665007184,0.813486288,0.4012,0.5144,0.901602752,0.916107472,0.851590464,0.890641904,0.8374,0.575986032,0.9088,0.51371472,0.11789296,0.87345608,0.40134264,0.830663136,0.8526,0.838592064,0.27417,0.10364,0.47461744,0.784405184,0.707458176,0.086483504,0.182542976,0.9041,0.62200496,0.3073,0.052,0.1860232,0.2308,0.8115,0.183964544,0.131190928,0.138213008,0.17903672,0.062345408,0.0724,0.6232,0.580600976,0.19647,0.0866,0.081564208,0.5205,0.7642656,0.387207424,0.91077248,0.171923536,0.11115,0.012447152,0.0596,0.0678,0.218588864,0.187978128,0.286410048,0.1514,0.46044376,0.651168224,0.551069472,0.116,0.1297,0.287213104,0.608227232,0.867376208,0.830666832,0.496512,0.8814,0.7029,0.05967328,0.429775072,0.829471504,0.169521424,0.92207504,0.771356944,0.2512,0.543108432,0.772130656,0.766391184,0.847462384,0.901001216,0.918696336,0.2728,0.82814,0.6338 +740.0,0.8926,0.7746,0.26073,0.52602,0.94353,0.84003,0.4645,0.65804,0.05852,0.88291,0.82541,0.6938,0.26376,0.4949,0.65035,0.6677,0.81691,0.4012,0.5144,0.90257,0.91626,0.8519,0.89074,0.8374,0.5774,0.9088,0.51494,0.1178,0.87424,0.40229,0.83067,0.8526,0.83904,0.27417,0.10364,0.47311,0.79164,0.70819,0.08645,0.18218,0.9041,0.62733,0.3073,0.052,0.18747,0.2308,0.8115,0.18437,0.13195,0.13754,0.1781,0.06202,0.0724,0.6232,0.58514,0.19647,0.0866,0.08147,0.5205,0.7685,0.38667,0.91415,0.17424,0.11115,0.01248,0.0596,0.0678,0.21814,0.18762,0.28597,0.1514,0.46056,0.65946,0.56171,0.116,0.1297,0.28597,0.61747,0.86913,0.83267,0.49725,0.8814,0.7029,0.05959,0.43223,0.8306,0.16929,0.92467,0.77696,0.2512,0.54151,0.77403,0.76658,0.85071,0.90177,0.9193,0.2728,0.82814,0.6338 +741.0,0.8926,0.7746,0.262180752,0.526394,0.944246112,0.842977984,0.4645,0.659075376,0.058416144,0.88291,0.827618384,0.694009872,0.26369752,0.4949,0.6508448,0.670382128,0.820284992,0.4012,0.5144,0.903528832,0.916413472,0.852199616,0.89085336,0.8374,0.578812752,0.9088,0.516164704,0.117792816,0.875020112,0.403238272,0.830680544,0.8526,0.839474016,0.27417,0.10364,0.471603104,0.798694688,0.708920544,0.086417152,0.181817344,0.9041,0.632623952,0.3073,0.052,0.188961728,0.2308,0.8115,0.184768064,0.13270656,0.136869008,0.177166704,0.061695408,0.0724,0.6232,0.58997616,0.19647,0.0866,0.081367696,0.5205,0.773053808,0.386133056,0.917411776,0.176580896,0.11115,0.01251352,0.0596,0.0678,0.217691232,0.187262848,0.285529696,0.1514,0.460676128,0.667655376,0.57229336,0.116,0.1297,0.284730768,0.626629456,0.870863632,0.834659952,0.497988,0.8814,0.7029,0.05950728,0.434688032,0.831723152,0.169059056,0.927185376,0.782465184,0.2512,0.539910096,0.775917376,0.766762368,0.853900528,0.90253288,0.919899632,0.2728,0.82814,0.6338 +742.0,0.8926,0.7746,0.263637408,0.526768,0.944948976,0.845882192,0.4645,0.660107248,0.058312224,0.88291,0.829804208,0.694219856,0.263635808,0.4949,0.6513392,0.673053456,0.82361144,0.4012,0.5144,0.90447936,0.916568016,0.852490832,0.890983584,0.8374,0.58022432,0.9088,0.517388768,0.117879344,0.875796512,0.404187456,0.830694112,0.8526,0.839896592,0.27417,0.10364,0.470096816,0.805569216,0.709649824,0.086385008,0.181455024,0.9041,0.637885696,0.3073,0.052,0.19049,0.2308,0.8115,0.18516016,0.13346168,0.136199936,0.176236768,0.061371536,0.0724,0.6232,0.595080784,0.19647,0.0866,0.08125872,0.5205,0.777902688,0.385596576,0.920560848,0.17894632,0.11115,0.012547808,0.0596,0.0678,0.217242512,0.186906752,0.285089072,0.1514,0.460792144,0.675750752,0.582810784,0.116,0.1297,0.283495488,0.63570024,0.872577248,0.836634576,0.498726,0.8814,0.7029,0.059425152,0.437149024,0.832841008,0.168828576,0.929623136,0.787872352,0.2512,0.538308672,0.777792736,0.766939488,0.85703448,0.903289792,0.9204952,0.2728,0.82814,0.6338 +743.0,0.8926,0.7746,0.265099744,0.527142,0.94564008,0.84874248,0.4645,0.66113616,0.058208224,0.88291,0.831967792,0.69442992,0.263574416,0.4949,0.6518332,0.675713744,0.826889408,0.4012,0.5144,0.905421488,0.91672296,0.852776128,0.891125568,0.8374,0.581634528,0.9088,0.518612432,0.118028912,0.876568912,0.40513752,0.83070984,0.8526,0.840310608,0.27417,0.10364,0.468591008,0.812264224,0.710377824,0.086353344,0.181093024,0.9041,0.6431144,0.3073,0.052,0.192049632,0.2308,0.8115,0.185548256,0.1342168,0.135533264,0.175310432,0.061048864,0.0724,0.6232,0.600317728,0.19647,0.0866,0.081144944,0.5205,0.782910208,0.385060576,0.92360008,0.181336304,0.11115,0.012582416,0.0596,0.0678,0.216794112,0.186551296,0.284648528,0.1514,0.46090808,0.683742368,0.593253408,0.116,0.1297,0.282263888,0.644676304,0.874271024,0.83856344,0.499464,0.8814,0.7029,0.059343424,0.439612976,0.833953344,0.168598576,0.931985216,0.79318096,0.2512,0.536706128,0.779656336,0.767112688,0.860112192,0.904041184,0.921086928,0.2728,0.82814,0.6338 +744.0,0.8926,0.7746,0.26656736,0.527516,0.946323024,0.851558448,0.4645,0.662163472,0.058104144,0.88291,0.834109616,0.694639984,0.263512624,0.4949,0.6523268,0.678362672,0.830118896,0.4012,0.5144,0.906355056,0.916877184,0.853061344,0.891269952,0.8374,0.583043136,0.9088,0.519836096,0.11819032,0.877336832,0.406088384,0.830725568,0.8526,0.840723584,0.27417,0.10364,0.46708544,0.818780752,0.711104544,0.08632176,0.180731344,0.9041,0.648309424,0.3073,0.052,0.193641264,0.2308,0.8115,0.185937232,0.13497552,0.134869792,0.174388096,0.060728192,0.0724,0.6232,0.605491312,0.19647,0.0866,0.081031088,0.5205,0.787877168,0.384525056,0.926532192,0.183750848,0.11115,0.012616624,0.0596,0.0678,0.216346512,0.18619584,0.284208704,0.1514,0.461024016,0.691626544,0.603612592,0.116,0.1297,0.281035488,0.653551408,0.8759452,0.840400144,0.500202,0.8814,0.7029,0.059261776,0.442079968,0.83505976,0.168369056,0.934273536,0.798390288,0.2512,0.535103104,0.781508656,0.767285488,0.863133904,0.904787776,0.921675136,0.2728,0.82814,0.6338 +745.0,0.8926,0.7746,0.26804,0.52789,0.947,0.85433,0.4645,0.66319,0.058,0.88291,0.83623,0.69485,0.26345,0.4949,0.65282,0.681,0.8333,0.4012,0.5144,0.90728,0.91703,0.85335,0.89141,0.8374,0.58445,0.9088,0.52106,0.11833,0.8781,0.40704,0.83074,0.8526,0.84114,0.27417,0.10364,0.46558,0.82512,0.71183,0.08629,0.18037,0.9041,0.65347,0.3073,0.052,0.19526,0.2308,0.8115,0.18633,0.13574,0.13421,0.17347,0.06041,0.0724,0.6232,0.61045,0.19647,0.0866,0.08092,0.5205,0.79265,0.38399,0.92936,0.18619,0.11115,0.01265,0.0596,0.0678,0.2159,0.18584,0.28377,0.1514,0.46114,0.6994,0.61388,0.116,0.1297,0.27981,0.66232,0.8776,0.84211,0.50094,0.8814,0.7029,0.05918,0.44455,0.83616,0.16814,0.93649,0.8035,0.2512,0.5335,0.78335,0.76746,0.8661,0.90553,0.92226,0.2728,0.82814,0.6338 +746.0,0.8926,0.7746,0.269517712,0.528264,0.94766968,0.857057552,0.4645,0.6642152,0.057895776,0.88291,0.838328976,0.695059984,0.263386608,0.4949,0.653312816,0.683625648,0.836433008,0.4012,0.5144,0.908196368,0.917181552,0.853639936,0.891546848,0.8374,0.585855088,0.9088,0.52228408,0.118454688,0.87885848,0.407992384,0.830754,0.8526,0.841556688,0.27417,0.10364,0.464074768,0.831283072,0.71255416,0.086258128,0.180008976,0.9041,0.658595104,0.3073,0.052,0.196893488,0.2308,0.8115,0.186724608,0.136508816,0.13355376,0.172556096,0.060094176,0.0724,0.6232,0.615174656,0.19647,0.0866,0.080809776,0.5205,0.797211968,0.383455424,0.932086496,0.188653824,0.11115,0.012682624,0.0596,0.0678,0.215454496,0.185483824,0.283332352,0.1514,0.461256,0.707059936,0.62404784,0.116,0.1297,0.278587488,0.670977664,0.879235536,0.843693488,0.501678,0.8814,0.7029,0.059098128,0.447022928,0.837254144,0.167911424,0.93863648,0.808510352,0.2512,0.531896784,0.785180272,0.76763472,0.869011088,0.906267808,0.92284152,0.2728,0.82814,0.6338 +747.0,0.8926,0.7746,0.271000464,0.528638,0.94833144,0.85974136,0.4645,0.6652388,0.057791424,0.88291,0.840406672,0.69526992,0.263322336,0.4949,0.65380528,0.686239504,0.839518208,0.4012,0.5144,0.909104128,0.91733176,0.853930128,0.891681248,0.8374,0.587258288,0.9088,0.523508352,0.118565632,0.879612192,0.40894552,0.830768,0.8526,0.841972048,0.27417,0.10364,0.462569728,0.837271264,0.713276944,0.086226144,0.179648224,0.9041,0.66368384,0.3073,0.052,0.198535552,0.2308,0.8115,0.187120096,0.13728128,0.132901104,0.171646432,0.059780784,0.0724,0.6232,0.619654128,0.19647,0.0866,0.080699424,0.5205,0.801553088,0.382921376,0.93471456,0.191142304,0.11115,0.012714416,0.0596,0.0678,0.215010032,0.185127216,0.282895808,0.1514,0.461372,0.714603648,0.634108768,0.116,0.1297,0.277367888,0.679520064,0.880851904,0.84515304,0.502416,0.8814,0.7029,0.059016144,0.449498656,0.838342224,0.167683376,0.940714816,0.81342152,0.2512,0.530293568,0.786999456,0.767808848,0.871867712,0.907001344,0.923419808,0.2728,0.82814,0.6338 +748.0,0.8926,0.7746,0.272488336,0.529012,0.94898536,0.862382288,0.4645,0.6662608,0.057687152,0.88291,0.842462928,0.695479856,0.263257664,0.4949,0.654297344,0.68884152,0.842555888,0.4012,0.5144,0.910003648,0.917481088,0.8542204,0.891806848,0.8374,0.588659888,0.9088,0.524732624,0.118659936,0.880361584,0.409899456,0.830782,0.8526,0.842386048,0.27417,0.10364,0.461065248,0.843086736,0.713998608,0.08619408,0.179287952,0.9041,0.668735056,0.3073,0.052,0.200156816,0.2308,0.8115,0.187516304,0.138057344,0.132251648,0.170740768,0.059469392,0.0724,0.6232,0.62372896,0.19647,0.0866,0.080589152,0.5205,0.805513168,0.382387648,0.937247344,0.193655824,0.11115,0.012745808,0.0596,0.0678,0.214566368,0.184770608,0.282460144,0.1514,0.461488,0.7220292,0.644054736,0.116,0.1297,0.276151488,0.687943424,0.882449472,0.846451952,0.503154,0.8814,0.7029,0.05893408,0.451976944,0.839424224,0.167455648,0.942726912,0.818234368,0.2512,0.528690032,0.78880752,0.767982576,0.874670736,0.90773008,0.923994416,0.2728,0.82814,0.6338 +749.0,0.8926,0.7746,0.273981488,0.529386,0.94963152,0.864981536,0.4645,0.6672812,0.05758328,0.88291,0.844497424,0.695689872,0.263193392,0.4949,0.654788928,0.691431696,0.845546368,0.4012,0.5144,0.910895488,0.917630336,0.854510432,0.891914928,0.8374,0.590060368,0.9088,0.525956576,0.11873752,0.881107376,0.410854272,0.830796,0.8526,0.842798688,0.27417,0.10364,0.459561888,0.848732128,0.714719552,0.086162016,0.17892848,0.9041,0.673747472,0.3073,0.052,0.20171712,0.2308,0.8115,0.187912992,0.138836928,0.131604752,0.169838704,0.05915928,0.0724,0.6232,0.627190272,0.19647,0.0866,0.08047928,0.5205,0.808881968,0.38185392,0.939688128,0.196194944,0.11115,0.01277752,0.0596,0.0678,0.214123104,0.18441472,0.28202496,0.1514,0.461604,0.729335152,0.653877584,0.116,0.1297,0.274938768,0.696244464,0.88402872,0.847540464,0.503892,0.8814,0.7029,0.058852016,0.454457472,0.840500144,0.16722792,0.944674688,0.822950176,0.2512,0.527085616,0.790604384,0.768156224,0.8774212,0.908453136,0.924564624,0.2728,0.82814,0.6338 +750.0,0.8926,0.7746,0.27548,0.52976,0.95027,0.86754,0.4645,0.6683,0.05748,0.88291,0.84651,0.6959,0.26313,0.4949,0.65528,0.69401,0.84849,0.4012,0.5144,0.91178,0.91778,0.8548,0.892,0.8374,0.59146,0.9088,0.52718,0.1188,0.88185,0.41181,0.83081,0.8526,0.84321,0.27417,0.10364,0.45806,0.85421,0.71544,0.08613,0.17857,0.9041,0.67872,0.3073,0.052,0.20319,0.2308,0.8115,0.18831,0.13962,0.13096,0.16894,0.05885,0.0724,0.6232,0.62991,0.19647,0.0866,0.08037,0.5205,0.81153,0.38132,0.94204,0.19876,0.11115,0.01281,0.0596,0.0678,0.21368,0.18406,0.28159,0.1514,0.46172,0.73652,0.66357,0.116,0.1297,0.27373,0.70442,0.88559,0.84839,0.50463,0.8814,0.7029,0.05877,0.45694,0.84157,0.167,0.94656,0.82757,0.2512,0.52548,0.79239,0.76833,0.88012,0.90917,0.92513,0.2728,0.82814,0.6338 +751.0,0.8926,0.7746,0.276983808,0.530134,0.950900864,0.870057952,0.4645,0.6693172,0.057377296,0.88291,0.848500816,0.696110224,0.263067392,0.4949,0.655770576,0.696576304,0.851387104,0.4012,0.5144,0.912657184,0.917929968,0.855089152,0.89206232,0.8374,0.59285872,0.9088,0.528402928,0.118843632,0.882589392,0.412766624,0.830824,0.8526,0.843619968,0.27417,0.10364,0.456559504,0.859522464,0.716159984,0.086098,0.178212496,0.9041,0.683651888,0.3073,0.052,0.204574528,0.2308,0.8115,0.18870736,0.140406576,0.130317488,0.168044704,0.058541648,0.0724,0.6232,0.631893456,0.19647,0.0866,0.080261296,0.5205,0.813461728,0.38078592,0.944305664,0.201350976,0.11115,0.012843152,0.0596,0.0678,0.21323712,0.183706368,0.281155328,0.1514,0.461836,0.743581904,0.673126016,0.116,0.1297,0.27252496,0.71246672,0.887133424,0.84900688,0.505368,0.8814,0.7029,0.058688016,0.459424432,0.842633792,0.16677192,0.948384576,0.832094304,0.2512,0.523873296,0.794164928,0.768503872,0.882767696,0.9098808,0.92569064,0.2728,0.82814,0.6338 +752.0,0.8926,0.7746,0.278492896,0.530508,0.95152416,0.872535808,0.4645,0.6703328,0.057275232,0.88291,0.850469968,0.696320576,0.263005664,0.4949,0.656260624,0.69913048,0.854237968,0.4012,0.5144,0.913527168,0.918080288,0.85537792,0.892101168,0.8374,0.594256608,0.9088,0.529625344,0.118860656,0.883325664,0.413724176,0.830838,0.8526,0.844028528,0.27417,0.10364,0.455060368,0.864671856,0.716879728,0.086066,0.177856032,0.9041,0.688542336,0.3073,0.052,0.205865936,0.2308,0.8115,0.189105104,0.141196624,0.129677248,0.167152768,0.058234192,0.0724,0.6232,0.63312304,0.19647,0.0866,0.080153232,0.5205,0.814658608,0.380251648,0.946487824,0.203967984,0.11115,0.012877008,0.0596,0.0678,0.212794448,0.183353888,0.280720944,0.1514,0.461952,0.75051936,0.682539856,0.116,0.1297,0.271323408,0.720381664,0.888659152,0.849391232,0.506106,0.8814,0.7029,0.05860608,0.461910624,0.843691504,0.166543648,0.950150112,0.836523728,0.2512,0.522265472,0.79593024,0.768677856,0.885364896,0.91058544,0.926246496,0.2728,0.82814,0.6338 +753.0,0.8926,0.7746,0.280007104,0.530882,0.952140016,0.874973744,0.4645,0.6713468,0.057173568,0.88291,0.85241768,0.696530848,0.262944336,0.4949,0.656750352,0.701672496,0.857043232,0.4012,0.5144,0.914389632,0.918230688,0.855666128,0.892119936,0.8374,0.595653216,0.9088,0.53084728,0.1188776,0.884058336,0.414682448,0.830852,0.8526,0.844436048,0.27417,0.10364,0.453562512,0.869660928,0.717598592,0.086034,0.177500368,0.9041,0.693390784,0.3073,0.052,0.207072704,0.2308,0.8115,0.189503168,0.141990352,0.129039248,0.166264432,0.057927856,0.0724,0.6232,0.633711744,0.19647,0.0866,0.080045568,0.5205,0.815230768,0.379717376,0.948589184,0.206610592,0.11115,0.012911344,0.0596,0.0678,0.212352176,0.183002288,0.28028688,0.1514,0.462068,0.757330816,0.691806416,0.116,0.1297,0.270125376,0.728162128,0.8901672,0.849577984,0.506844,0.8814,0.7029,0.058524144,0.464398576,0.844743296,0.166315376,0.951858368,0.840858992,0.2512,0.520656928,0.797684352,0.76885192,0.887912256,0.91128456,0.926797952,0.2728,0.82814,0.6338 +754.0,0.8926,0.7746,0.281526192,0.531256,0.952748592,0.87737176,0.4645,0.6723592,0.057071904,0.88291,0.854344272,0.69674072,0.262882608,0.4949,0.65724008,0.704202352,0.859803696,0.4012,0.5144,0.915244016,0.918380688,0.855953536,0.892124704,0.8374,0.597047824,0.9088,0.532068816,0.118935904,0.884786608,0.41564112,0.830866,0.8526,0.844843088,0.27417,0.10364,0.452065776,0.87449264,0.718315536,0.086002,0.177145104,0.9041,0.698196832,0.3073,0.052,0.208212912,0.2308,0.8115,0.189901472,0.14278808,0.128403488,0.165380096,0.05762304,0.0724,0.6232,0.633852448,0.19647,0.0866,0.079937904,0.5205,0.815367328,0.379183424,0.950612384,0.20927808,0.11115,0.01294576,0.0596,0.0678,0.211910624,0.182651088,0.279853216,0.1514,0.462184,0.764014752,0.700921216,0.116,0.1297,0.268930944,0.735805632,0.891657488,0.849623216,0.507582,0.8814,0.7029,0.058442128,0.466888368,0.845789408,0.166087424,0.953511104,0.845100816,0.2512,0.519048304,0.799424624,0.769025984,0.890410416,0.9119792,0.927345648,0.2728,0.82814,0.6338 +755.0,0.8926,0.7746,0.28305,0.53163,0.95335,0.87973,0.4645,0.67337,0.05697,0.88291,0.85625,0.69695,0.26282,0.4949,0.65773,0.70672,0.86252,0.4012,0.5144,0.91609,0.91853,0.85624,0.89212,0.8374,0.59844,0.9088,0.53329,0.11906,0.88551,0.4166,0.83088,0.8526,0.84525,0.27417,0.10364,0.45057,0.87917,0.71903,0.08597,0.17679,0.9041,0.70296,0.3073,0.052,0.2093,0.2308,0.8115,0.1903,0.14359,0.12777,0.1645,0.05732,0.0724,0.6232,0.63369,0.19647,0.0866,0.07983,0.5205,0.81521,0.37865,0.95256,0.21197,0.11115,0.01298,0.0596,0.0678,0.21147,0.1823,0.27942,0.1514,0.4623,0.77057,0.70988,0.116,0.1297,0.26774,0.74331,0.89313,0.84957,0.50832,0.8814,0.7029,0.05836,0.46938,0.84683,0.16586,0.95511,0.84925,0.2512,0.51744,0.80115,0.7692,0.89286,0.91267,0.92789,0.2728,0.82814,0.6338 +756.0,0.8926,0.7746,0.284578528,0.532003984,0.953944304,0.882048944,0.4645,0.6743792,0.056867904,0.88291,0.858134944,0.69715872,0.262756608,0.4949,0.658220064,0.709225328,0.865192496,0.4012,0.5144,0.916927712,0.918678704,0.85652552,0.8921056,0.8374,0.599829792,0.9088,0.534510784,0.119244176,0.88622864,0.417559104,0.830894,0.8526,0.845656736,0.27417,0.10364,0.449075216,0.883695824,0.719742096,0.085938,0.176435104,0.9041,0.707679616,0.3073,0.052,0.21032648,0.2308,0.8115,0.190698752,0.144396096,0.127138736,0.16362408,0.057018656,0.0724,0.6232,0.6332252,0.19647,0.0866,0.079721888,0.5205,0.814758416,0.378117072,0.95443456,0.214686432,0.11115,0.013014144,0.0596,0.0678,0.211030256,0.181949088,0.278987184,0.1514,0.462416,0.776995904,0.718678576,0.116,0.1297,0.266552512,0.750673408,0.894584912,0.849422192,0.509057984,0.8814,0.7029,0.058277776,0.471873328,0.847865072,0.165633056,0.956656624,0.853307472,0.2512,0.515831952,0.802860864,0.769374,0.895261664,0.913356864,0.928430944,0.2728,0.82814,0.6338 +757.0,0.8926,0.7746,0.286111744,0.53237792,0.954531616,0.884329024,0.4645,0.6753868,0.056765568,0.88291,0.8599992,0.697366848,0.262692336,0.4949,0.658710272,0.711718256,0.867821632,0.4012,0.5144,0.917757152,0.918826768,0.856810048,0.892081616,0.8374,0.601217056,0.9088,0.53573112,0.11949088,0.886942496,0.418518368,0.830908,0.8526,0.846063328,0.27417,0.10364,0.447581552,0.888072928,0.720451552,0.085906,0.176080368,0.9041,0.712355104,0.3073,0.052,0.211281024,0.2308,0.8115,0.191097648,0.145206432,0.126509568,0.162752352,0.056718976,0.0724,0.6232,0.632468304,0.19647,0.0866,0.079613488,0.5205,0.814021808,0.377584656,0.956238544,0.217427312,0.11115,0.013048224,0.0596,0.0678,0.210591376,0.181598288,0.27855472,0.1514,0.462532,0.783291936,0.727313296,0.116,0.1297,0.265368816,0.757894288,0.8960224,0.849185424,0.50979592,0.8814,0.7029,0.058195424,0.474368256,0.848894656,0.165406576,0.958152528,0.857274192,0.2512,0.514224208,0.804555872,0.769548,0.897616096,0.91403992,0.928968512,0.2728,0.82814,0.6338 +758.0,0.8926,0.7746,0.28764968,0.532751856,0.955111808,0.886570624,0.4645,0.6763928,0.056663232,0.88291,0.861842976,0.697574576,0.262627664,0.4949,0.65920048,0.714198544,0.870407568,0.4012,0.5144,0.918578672,0.918974432,0.857093776,0.892052432,0.8374,0.60260232,0.9088,0.536951056,0.119774624,0.887651952,0.419478032,0.830922,0.8526,0.8464696,0.27417,0.10364,0.446088368,0.892304992,0.721159728,0.085874,0.175726032,0.9041,0.716985792,0.3073,0.052,0.212194928,0.2308,0.8115,0.191497104,0.146020768,0.12588296,0.161884624,0.056420976,0.0724,0.6232,0.631554608,0.19647,0.0866,0.079505088,0.5205,0.813132,0.37705272,0.957974288,0.220192912,0.11115,0.013082224,0.0596,0.0678,0.210153376,0.181247888,0.278122656,0.1514,0.462648,0.789457888,0.735780576,0.116,0.1297,0.26418712,0.764971328,0.897442448,0.848901376,0.510533856,0.8814,0.7029,0.058113152,0.476864544,0.84991872,0.165180576,0.959599152,0.861151152,0.2512,0.512616544,0.80624232,0.769722,0.899923728,0.914718656,0.92950264,0.2728,0.82814,0.6338 +759.0,0.8926,0.7746,0.289192416,0.533125872,0.95568464,0.888774144,0.4645,0.6773972,0.056561296,0.88291,0.863666512,0.697782224,0.262563392,0.4949,0.659690448,0.716665872,0.872950304,0.4012,0.5144,0.919392832,0.919122096,0.857377024,0.892023888,0.8374,0.603986464,0.9088,0.538170672,0.120053648,0.888357648,0.420438496,0.830936,0.8526,0.846875232,0.27417,0.10364,0.444594704,0.896396096,0.721868784,0.085842,0.175372496,0.9041,0.72157096,0.3073,0.052,0.213116032,0.2308,0.8115,0.19189776,0.146838704,0.125259632,0.161020576,0.056124656,0.0724,0.6232,0.630661072,0.19647,0.0866,0.079397168,0.5205,0.812261632,0.376521184,0.959644032,0.222983712,0.11115,0.013116144,0.0596,0.0678,0.209716256,0.180898368,0.277691072,0.1514,0.462764,0.79549384,0.744077056,0.116,0.1297,0.263004704,0.771903488,0.898844976,0.848623808,0.511271872,0.8814,0.7029,0.05803128,0.479361872,0.850937184,0.164955056,0.960997856,0.864939392,0.2512,0.51100856,0.807931488,0.769896,0.90218488,0.915392192,0.930033168,0.2728,0.82814,0.6338 +760.0,0.8926,0.7746,0.29074,0.5335,0.95625,0.89094,0.4645,0.6784,0.05646,0.88291,0.86547,0.69799,0.2625,0.4949,0.66018,0.71912,0.87545,0.4012,0.5144,0.9202,0.91927,0.85766,0.892,0.8374,0.60537,0.9088,0.53939,0.1203,0.88906,0.4214,0.83095,0.8526,0.84728,0.27417,0.10364,0.4431,0.90035,0.72258,0.08581,0.17502,0.9041,0.72611,0.3073,0.052,0.21407,0.2308,0.8115,0.1923,0.14766,0.12464,0.16016,0.05583,0.0724,0.6232,0.62991,0.19647,0.0866,0.07929,0.5205,0.81153,0.37599,0.96125,0.2258,0.11115,0.01315,0.0596,0.0678,0.20928,0.18055,0.27726,0.1514,0.46288,0.8014,0.7522,0.116,0.1297,0.26182,0.77869,0.90023,0.84839,0.51201,0.8814,0.7029,0.05795,0.48186,0.85195,0.16473,0.96235,0.86864,0.2512,0.5094,0.80963,0.77007,0.9044,0.91606,0.93056,0.2728,0.82814,0.6338 +761.0,0.8926,0.7746,0.292292384,0.53387424,0.956808,0.893068608,0.4645,0.6794012,0.05635928,0.88291,0.867253568,0.698197872,0.262437392,0.4949,0.660669168,0.72156088,0.877907136,0.4012,0.5144,0.92100016,0.91941808,0.857942672,0.891981376,0.8374,0.606752816,0.9088,0.540609024,0.120518144,0.889758928,0.42236248,0.830964,0.8526,0.847683952,0.27417,0.10364,0.441604368,0.904169792,0.72329312,0.085778,0.174668496,0.9041,0.73060248,0.3073,0.052,0.215048288,0.2308,0.8115,0.19270376,0.14848472,0.124024,0.159302944,0.055537024,0.0724,0.6232,0.629323344,0.19647,0.0866,0.07918352,0.5205,0.810958288,0.375459184,0.962794416,0.228641648,0.11115,0.013183776,0.0596,0.0678,0.20884464,0.18020272,0.27682944,0.1514,0.462996,0.807176448,0.760147328,0.116,0.1297,0.260633344,0.785330224,0.90159768,0.84820744,0.51274824,0.8814,0.7029,0.05786928,0.484358848,0.8529572,0.164505424,0.963657024,0.872254064,0.2512,0.507790944,0.811336512,0.770243984,0.90656976,0.91672224,0.9310832,0.2728,0.82814,0.6338 +762.0,0.8926,0.7746,0.29384952,0.534248656,0.957358688,0.895160384,0.4645,0.6804008,0.056259152,0.88291,0.869017376,0.698405856,0.262375664,0.4949,0.661158,0.723988464,0.880322128,0.4012,0.5144,0.921793392,0.919566352,0.858225056,0.891969152,0.8374,0.60813504,0.9088,0.541827776,0.120708864,0.890454432,0.423325952,0.830978,0.8526,0.84808712,0.27417,0.10364,0.440107728,0.907858752,0.724008368,0.085746,0.174318032,0.9041,0.735047952,0.3073,0.052,0.216054608,0.2308,0.8115,0.193109104,0.149312848,0.12341176,0.158449424,0.055245776,0.0724,0.6232,0.628938288,0.19647,0.0866,0.079077808,0.5205,0.81058256,0.37492872,0.964279408,0.231508592,0.11115,0.013217424,0.0596,0.0678,0.208410256,0.179856608,0.276399456,0.1514,0.463112,0.812823328,0.767917136,0.116,0.1297,0.25944448,0.791823648,0.902948128,0.848088096,0.513486656,0.8814,0.7029,0.057789152,0.486858304,0.8539588,0.164281376,0.964920352,0.875782672,0.2512,0.506181424,0.81305208,0.77041792,0.908694768,0.917378896,0.9316028,0.2728,0.82814,0.6338 +763.0,0.8926,0.7746,0.295411456,0.534622992,0.957902336,0.89721584,0.4645,0.6813988,0.056159424,0.88291,0.870761424,0.69861392,0.262314336,0.4949,0.661646272,0.726402608,0.88269552,0.4012,0.5144,0.922579584,0.919714624,0.85850712,0.891962688,0.8374,0.609515984,0.9088,0.543046048,0.120865904,0.891146496,0.424290224,0.830992,0.8526,0.848489328,0.27417,0.10364,0.438610768,0.911419872,0.724724336,0.085714,0.173968368,0.9041,0.739446144,0.3073,0.052,0.217037728,0.2308,0.8115,0.193515648,0.150144576,0.12280264,0.157599424,0.054956048,0.0724,0.6232,0.628734672,0.19647,0.0866,0.078972416,0.5205,0.810383392,0.374398656,0.9657072,0.234400736,0.11115,0.013251152,0.0596,0.0678,0.207976592,0.179511216,0.275969792,0.1514,0.463228,0.818341808,0.775508944,0.116,0.1297,0.258255536,0.798170752,0.904281696,0.848025472,0.514224992,0.8814,0.7029,0.057709424,0.48935832,0.8549548,0.164057648,0.9661412,0.8792272,0.2512,0.504571424,0.814768928,0.770591856,0.910775856,0.918030352,0.9321188,0.2728,0.82814,0.6338 +764.0,0.8926,0.7746,0.296978272,0.534996848,0.958439344,0.899235536,0.4645,0.6823952,0.056059776,0.88291,0.872485632,0.698821984,0.262252608,0.4949,0.662133664,0.728803152,0.885027952,0.4012,0.5144,0.923358496,0.919862576,0.858788784,0.891960064,0.8374,0.610894528,0.9088,0.54426352,0.120983664,0.89183504,0.425254976,0.831006,0.8526,0.848890336,0.27417,0.10364,0.437114608,0.914855952,0.725438704,0.085682,0.173619104,0.9041,0.743796896,0.3073,0.052,0.217917328,0.2308,0.8115,0.193922752,0.150980224,0.1221956,0.156752944,0.05466752,0.0724,0.6232,0.628652016,0.19647,0.0866,0.078866624,0.5205,0.810302224,0.373869072,0.967080032,0.23731792,0.11115,0.01328528,0.0596,0.0678,0.207543248,0.179165824,0.275540048,0.1514,0.463344,0.823733568,0.782923152,0.116,0.1297,0.257069952,0.804372576,0.905598864,0.848000368,0.514962848,0.8814,0.7029,0.057629776,0.491858896,0.8559452,0.16383392,0.967320688,0.882589168,0.2512,0.502960944,0.816474336,0.770765872,0.912813984,0.918677248,0.9326312,0.2728,0.82814,0.6338 +765.0,0.8926,0.7746,0.29855,0.53537,0.95897,0.90122,0.4645,0.68339,0.05596,0.88291,0.87419,0.69903,0.26219,0.4949,0.66262,0.73119,0.88732,0.4012,0.5144,0.92413,0.92001,0.85907,0.89196,0.8374,0.61227,0.9088,0.54548,0.12106,0.89252,0.42622,0.83102,0.8526,0.84929,0.27417,0.10364,0.43562,0.91817,0.72615,0.08565,0.17327,0.9041,0.7481,0.3073,0.052,0.21864,0.2308,0.8115,0.19433,0.15182,0.12159,0.15591,0.05438,0.0724,0.6232,0.62865,0.19647,0.0866,0.07876,0.5205,0.8103,0.37334,0.9684,0.24026,0.11115,0.01332,0.0596,0.0678,0.20711,0.17882,0.27511,0.1514,0.46346,0.829,0.79016,0.116,0.1297,0.25589,0.81043,0.9069,0.848,0.5157,0.8814,0.7029,0.05755,0.49436,0.85693,0.16361,0.96846,0.88587,0.2512,0.50135,0.81816,0.77094,0.91481,0.91932,0.93314,0.2728,0.82814,0.6338 +766.0,0.8926,0.7746,0.300126624,0.53574248,0.959494336,0.903169648,0.4645,0.684383184,0.055860144,0.88291,0.875874672,0.699238,0.262126608,0.4949,0.663105296,0.733563088,0.88957208,0.4012,0.5144,0.924894192,0.920156944,0.859350784,0.891963136,0.8374,0.613642512,0.9088,0.546695504,0.121093056,0.893201408,0.427185328,0.831034,0.8526,0.84968832,0.27417,0.10364,0.43412688,0.921365328,0.726858464,0.085618,0.172921088,0.9041,0.75235512,0.3073,0.052,0.219219904,0.2308,0.8115,0.194737472,0.152663856,0.120985968,0.15507056,0.054093504,0.0724,0.6232,0.628748784,0.19647,0.0866,0.07865264,0.5205,0.810396304,0.37281144,0.969669008,0.243226944,0.11115,0.01335528,0.0596,0.0678,0.206676864,0.17847384,0.274679696,0.1514,0.463575984,0.834141872,0.79721896,0.116,0.1297,0.25471544,0.816343376,0.908185216,0.848030704,0.51643648,0.8814,0.7029,0.057470128,0.496861472,0.8579092,0.163385904,0.9695604,0.889070896,0.2512,0.499738608,0.819826992,0.771114224,0.916764544,0.919958544,0.933645216,0.2728,0.82814,0.6338 +767.0,0.8926,0.7746,0.301708176,0.536114192,0.960012416,0.90508488,0.4645,0.68537472,0.055760224,0.88291,0.877539744,0.699446,0.262062336,0.4949,0.663589472,0.735922288,0.89178464,0.4012,0.5144,0.925651104,0.920303424,0.85963112,0.891969728,0.8374,0.615011904,0.9088,0.547909968,0.121077904,0.893879296,0.428150944,0.831048,0.8526,0.850085248,0.27417,0.10364,0.432635328,0.924445072,0.727563936,0.085586,0.172572288,0.9041,0.756561984,0.3073,0.052,0.219671568,0.2308,0.8115,0.195145168,0.153511776,0.12038344,0.154234544,0.053807968,0.0724,0.6232,0.628956432,0.19647,0.0866,0.078544496,0.5205,0.810598992,0.372283456,0.97088896,0.246218736,0.11115,0.013391152,0.0596,0.0678,0.206243712,0.178127296,0.274249072,0.1514,0.46369192,0.839160288,0.804099984,0.116,0.1297,0.253546496,0.822113392,0.909454656,0.848094992,0.517172192,0.8814,0.7029,0.057390144,0.49936312,0.8588828,0.163161568,0.97062304,0.89219312,0.2512,0.498126784,0.821474528,0.771288576,0.918678336,0.920592912,0.93414688,0.2728,0.82814,0.6338 +768.0,0.8926,0.7746,0.303294448,0.536485584,0.960524336,0.906966272,0.4645,0.686364656,0.055660224,0.88291,0.879185456,0.699654,0.261997664,0.4949,0.664072928,0.738267888,0.89395816,0.4012,0.5144,0.926400896,0.920449424,0.859911056,0.89197888,0.8374,0.616378896,0.9088,0.549123632,0.121035632,0.894553504,0.42911688,0.831062,0.8526,0.850480976,0.27417,0.10364,0.431145376,0.927413056,0.728267008,0.085554,0.172223888,0.9041,0.760720288,0.3073,0.052,0.219967552,0.2308,0.8115,0.195553104,0.154363776,0.119782832,0.153402208,0.053523632,0.0724,0.6232,0.62924472,0.19647,0.0866,0.078435952,0.5205,0.81088048,0.371755792,0.972061472,0.249235088,0.11115,0.013427424,0.0596,0.0678,0.20581104,0.177780752,0.273818528,0.1514,0.463807856,0.844055824,0.810803408,0.116,0.1297,0.252382992,0.827740688,0.910708496,0.84818416,0.517907584,0.8814,0.7029,0.05731008,0.501865008,0.8598508,0.162937232,0.97164944,0.895237904,0.2512,0.49651464,0.823103904,0.771462848,0.920551888,0.92122304,0.934644944,0.2728,0.82814,0.6338 +769.0,0.8926,0.7746,0.30488512,0.536857376,0.961030176,0.908814464,0.4645,0.687353072,0.055560144,0.88291,0.880812128,0.699862,0.261933392,0.4949,0.664556304,0.740600368,0.89609312,0.4012,0.5144,0.927143808,0.920594944,0.860190672,0.891989312,0.8374,0.617744688,0.9088,0.550336896,0.12099936,0.895223792,0.430083216,0.831076,0.8526,0.850875824,0.27417,0.10364,0.429656944,0.93027344,0.7289688,0.085522,0.171876368,0.9041,0.764829712,0.3073,0.052,0.220070816,0.2308,0.8115,0.19596136,0.155219856,0.119184864,0.152573952,0.053240896,0.0724,0.6232,0.629573328,0.19647,0.0866,0.078327648,0.5205,0.811201328,0.371228048,0.973187984,0.2522756,0.11115,0.013463776,0.0596,0.0678,0.205379648,0.177434848,0.273388704,0.1514,0.463923872,0.8488288,0.817329792,0.116,0.1297,0.251224288,0.833225904,0.911946896,0.848285808,0.518643376,0.8814,0.7029,0.057230016,0.504367296,0.8608132,0.162713296,0.97264128,0.898206448,0.2512,0.494902336,0.8247184,0.77163672,0.9223856,0.921848768,0.935139328,0.2728,0.82814,0.6338 +770.0,0.8926,0.7746,0.30648,0.53723,0.96153,0.91063,0.4645,0.68834,0.05546,0.88291,0.88242,0.70007,0.26187,0.4949,0.66504,0.74292,0.89819,0.4012,0.5144,0.92788,0.92074,0.86047,0.892,0.8374,0.61911,0.9088,0.55155,0.12099,0.89589,0.43105,0.83109,0.8526,0.85127,0.27417,0.10364,0.42817,0.93303,0.72967,0.08549,0.17153,0.9041,0.76889,0.3073,0.052,0.21997,0.2308,0.8115,0.19637,0.15608,0.11859,0.15175,0.05296,0.0724,0.6232,0.62991,0.19647,0.0866,0.07822,0.5205,0.81153,0.3707,0.97427,0.25534,0.11115,0.0135,0.0596,0.0678,0.20495,0.17709,0.27296,0.1514,0.46404,0.85348,0.82368,0.116,0.1297,0.25007,0.83857,0.91317,0.84839,0.51938,0.8814,0.7029,0.05715,0.50687,0.86177,0.16249,0.9736,0.9011,0.2512,0.49329,0.82632,0.77181,0.92418,0.92247,0.93563,0.2728,0.82814,0.6338 +771.0,0.8926,0.7746,0.308065872,0.5376004,0.962020496,0.912401904,0.4645,0.689317712,0.05536056,0.88291,0.883998192,0.700276336,0.261807888,0.4949,0.665520112,0.745209568,0.900236112,0.4012,0.5144,0.928604288,0.92088344,0.860746848,0.89201088,0.8374,0.620463936,0.9088,0.552753248,0.1210052,0.896547216,0.432009424,0.831103888,0.8526,0.8516604,0.27417,0.10364,0.4266964,0.935672384,0.730364896,0.085458256,0.17118744,0.9041,0.772873664,0.3073,0.052,0.219669856,0.2308,0.8115,0.196775648,0.156936944,0.118002608,0.150936528,0.052682992,0.0724,0.6232,0.63025272,0.19647,0.0866,0.07811376,0.5205,0.81186456,0.370175872,0.975304096,0.258401248,0.11115,0.01353584,0.0596,0.0678,0.204525376,0.176748816,0.272535728,0.1514,0.464155312,0.85798496,0.829821072,0.116,0.1297,0.248929248,0.843744784,0.914369696,0.84849608,0.520111488,0.8814,0.7029,0.05707064,0.509353072,0.862714128,0.162269056,0.974521776,0.903903536,0.2512,0.491690528,0.82789608,0.771981344,0.925924992,0.923082288,0.936113408,0.2728,0.82814,0.6338 +772.0,0.8926,0.7746,0.309616208,0.537962704,0.962494976,0.914107872,0.4645,0.690270816,0.055263344,0.88291,0.885524896,0.70047768,0.261748144,0.4949,0.665989008,0.747434848,0.9022056,0.4012,0.5144,0.929306336,0.921022944,0.861016896,0.89202208,0.8374,0.621785136,0.9088,0.553927392,0.121048432,0.897185584,0.43294592,0.83111744,0.8526,0.852040896,0.27417,0.10364,0.425259696,0.938176976,0.731042528,0.08542728,0.170854208,0.9041,0.776725888,0.3073,0.052,0.219148912,0.2308,0.8115,0.197171584,0.157776176,0.117431632,0.150146048,0.052414112,0.0724,0.6232,0.63060552,0.19647,0.0866,0.078010592,0.5205,0.81220896,0.369663952,0.976281632,0.261405248,0.11115,0.013570704,0.0596,0.0678,0.20411264,0.176416672,0.272122688,0.1514,0.464268016,0.862293104,0.835686128,0.116,0.1297,0.247819792,0.848692528,0.915529616,0.84860528,0.520826144,0.8814,0.7029,0.0569932,0.511776688,0.86363144,0.162054032,0.975398,0.906585664,0.2512,0.49012968,0.829423344,0.772147968,0.927599568,0.92367664,0.936582384,0.2728,0.82814,0.6338 +773.0,0.8926,0.7746,0.311170944,0.538325408,0.962963536,0.91578224,0.4645,0.69122224,0.055166208,0.88291,0.88703304,0.700679024,0.2616888,0.4949,0.666457984,0.749646848,0.904138448,0.4012,0.5144,0.930001664,0.921162128,0.861286464,0.892032,0.8374,0.623105136,0.9088,0.555101136,0.121108064,0.897819872,0.433882816,0.831130992,0.8526,0.852420672,0.27417,0.10364,0.423824672,0.940586768,0.73171904,0.085396304,0.170521696,0.9041,0.780528592,0.3073,0.052,0.218543888,0.2308,0.8115,0.197568,0.158619328,0.116863616,0.149359488,0.052146832,0.0724,0.6232,0.630918,0.19647,0.0866,0.077907984,0.5205,0.812514,0.369152112,0.977219568,0.264433088,0.11115,0.013605488,0.0596,0.0678,0.203701024,0.176085488,0.271710528,0.1514,0.46438064,0.866484608,0.841379424,0.116,0.1297,0.246715136,0.853503952,0.916674576,0.848702,0.5215412,0.8814,0.7029,0.05691576,0.514199904,0.864543152,0.161839408,0.976243984,0.909196832,0.2512,0.488568992,0.830935888,0.772314192,0.929237184,0.924266592,0.93704784,0.2728,0.82814,0.6338 +774.0,0.8926,0.7746,0.31279664,0.538702672,0.963442976,0.917481968,0.4645,0.692210224,0.055065552,0.88291,0.888577424,0.700888688,0.261626576,0.4949,0.66694584,0.751930608,0.906100976,0.4012,0.5144,0.930716112,0.921306992,0.861566112,0.8920384,0.8374,0.624476496,0.9088,0.55632232,0.121162976,0.89847472,0.434858992,0.831145104,0.8526,0.852815008,0.27417,0.10364,0.422332608,0.94297128,0.732421312,0.085364048,0.170175584,0.9041,0.784418416,0.3073,0.052,0.218064544,0.2308,0.8115,0.197981856,0.15950248,0.11627608,0.148545088,0.051870272,0.0724,0.6232,0.6311196,0.19647,0.0866,0.077801696,0.5205,0.8127108,0.368620112,0.978145104,0.267619968,0.11115,0.013641712,0.0596,0.0678,0.203272608,0.175741744,0.271281968,0.1514,0.464497424,0.870692112,0.84707384,0.116,0.1297,0.24557112,0.858329296,0.917845856,0.8487644,0.522285376,0.8814,0.7029,0.05683512,0.51672128,0.865484624,0.161615984,0.977084528,0.91182024,0.2512,0.486944304,0.832490512,0.772487216,0.93089312,0.924874704,0.937527936,0.2728,0.82814,0.6338 +775.0,0.8926,0.7746,0.31452,0.5391,0.96394,0.91923,0.4645,0.69325,0.05496,0.88291,0.89018,0.70111,0.26156,0.4949,0.66746,0.75432,0.90812,0.4012,0.5144,0.93146,0.92146,0.86186,0.89204,0.8374,0.62592,0.9088,0.55761,0.1212,0.89916,0.43589,0.83116,0.8526,0.85323,0.27417,0.10364,0.42076,0.94536,0.73316,0.08533,0.16981,0.9041,0.78845,0.3073,0.052,0.21784,0.2308,0.8115,0.19842,0.16044,0.11566,0.14769,0.05158,0.0724,0.6232,0.63117,0.19647,0.0866,0.07769,0.5205,0.81276,0.36806,0.97907,0.27102,0.11115,0.01368,0.0596,0.0678,0.20282,0.17538,0.27083,0.1514,0.46462,0.87497,0.85284,0.116,0.1297,0.24437,0.86323,0.91906,0.84878,0.52307,0.8814,0.7029,0.05675,0.51938,0.86647,0.16138,0.97793,0.91449,0.2512,0.48523,0.83411,0.77267,0.93259,0.92551,0.93803,0.2728,0.82814,0.6338 +776.0,0.8926,0.7746,0.316327552,0.539514512,0.964451504,0.921016464,0.4645,0.694333952,0.054850304,0.88291,0.891830624,0.701341296,0.26148968,0.4949,0.667996704,0.756798496,0.910184048,0.4012,0.5144,0.932228448,0.92162,0.862166,0.892036864,0.8374,0.627425136,0.9088,0.558954608,0.121223216,0.899870928,0.436968048,0.831175568,0.8526,0.85366264,0.27417,0.10364,0.419118544,0.947744944,0.733929776,0.085294416,0.169427728,0.9041,0.792597904,0.3073,0.052,0.21785592,0.2308,0.8115,0.198879056,0.16142448,0.115019792,0.146800368,0.051278112,0.0724,0.6232,0.631071216,0.19647,0.0866,0.07757376,0.5205,0.812663568,0.367475872,0.979991472,0.274605152,0.11115,0.013720032,0.0596,0.0678,0.202346672,0.17500296,0.270358048,0.1514,0.464747488,0.879297504,0.858651232,0.116,0.1297,0.2431204,0.868182544,0.920309424,0.848749424,0.52388928,0.8814,0.7029,0.05666104,0.522156208,0.867492432,0.161133264,0.978777344,0.917193216,0.2512,0.48343896,0.835783616,0.772861136,0.934318752,0.926168144,0.938550576,0.2728,0.82814,0.6338 +777.0,0.8926,0.7746,0.318245424,0.539952128,0.964984736,0.92286664,0.4645,0.6954776,0.054734928,0.88291,0.89355272,0.701585904,0.26141456,0.4949,0.668563664,0.759401408,0.912322368,0.4012,0.5144,0.933032384,0.921789328,0.862488464,0.89202848,0.8374,0.629013456,0.9088,0.560375456,0.121233024,0.900617632,0.438108656,0.831192032,0.8526,0.854119152,0.27417,0.10364,0.417384672,0.950160528,0.73474168,0.085256784,0.169023216,0.9041,0.796920672,0.3073,0.052,0.218138928,0.2308,0.8115,0.19936568,0.162470128,0.114346336,0.145863408,0.050960272,0.0724,0.6232,0.63080712,0.19647,0.0866,0.077451344,0.5205,0.81240576,0.366859392,0.980923008,0.278427488,0.11115,0.013762368,0.0596,0.0678,0.201845744,0.174605248,0.269859328,0.1514,0.46488168,0.883735568,0.864588624,0.116,0.1297,0.241804416,0.873256432,0.921611856,0.84866768,0.52475496,0.8814,0.7029,0.05656696,0.525089664,0.868566512,0.160872208,0.979638784,0.919968192,0.2512,0.481545472,0.837535168,0.773063392,0.936103984,0.926858512,0.93909712,0.2728,0.82814,0.6338 +778.0,0.8926,0.7746,0.320101936,0.540374384,0.965495088,0.924629856,0.4645,0.696580688,0.054623872,0.88291,0.895201776,0.701822192,0.26134152,0.4949,0.669110944,0.76190456,0.914360608,0.4012,0.5144,0.9338036,0.921952976,0.862799248,0.892017216,0.8374,0.630545616,0.9088,0.561747264,0.121233152,0.901335776,0.439210784,0.831207936,0.8526,0.854559504,0.27417,0.10364,0.41571104,0.952428592,0.735524624,0.085220432,0.168632304,0.9041,0.80105712,0.3073,0.052,0.218580256,0.2308,0.8115,0.199836464,0.163482976,0.113698,0.144960688,0.050654112,0.0724,0.6232,0.630452304,0.19647,0.0866,0.077333408,0.5205,0.812059392,0.366264672,0.981796544,0.282138784,0.11115,0.013803264,0.0596,0.0678,0.201361616,0.174221696,0.269377808,0.1514,0.465010912,0.887937632,0.870196096,0.116,0.1297,0.240536592,0.8780572,0.922858368,0.848557856,0.52559072,0.8814,0.7029,0.05647608,0.52792176,0.869599632,0.160619952,0.980449664,0.922597328,0.2512,0.479716784,0.83921584,0.773258848,0.937802096,0.92752192,0.939622624,0.2728,0.82814,0.6338 +779.0,0.8926,0.7746,0.321633008,0.54072216,0.96591384,0.926073712,0.4645,0.697488976,0.054532496,0.88291,0.896555152,0.70201688,0.2612812,0.4949,0.669561744,0.763962912,0.916029808,0.4012,0.5144,0.934437056,0.922087824,0.863055072,0.892006912,0.8374,0.631807296,0.9088,0.562877312,0.12123064,0.90192632,0.440118992,0.83122104,0.8526,0.854922096,0.27417,0.10364,0.414332528,0.954272576,0.736169248,0.08519048,0.168310192,0.9041,0.804450848,0.3073,0.052,0.218993184,0.2308,0.8115,0.200224608,0.164318544,0.113164624,0.144217808,0.050402192,0.0724,0.6232,0.630127728,0.19647,0.0866,0.077236352,0.5205,0.811742544,0.365774912,0.98250624,0.28520368,0.11115,0.01383696,0.0596,0.0678,0.200962688,0.173905904,0.268981168,0.1514,0.465117264,0.891368096,0.874768688,0.116,0.1297,0.239493248,0.881975248,0.92388112,0.848457392,0.5262792,0.8814,0.7029,0.0564012,0.530254736,0.870449232,0.160412096,0.981109744,0.924744304,0.2512,0.478210176,0.840596432,0.773419904,0.939191328,0.928067248,0.940054688,0.2728,0.82814,0.6338 +780.0,0.8926,0.7746,0.32268,0.54096,0.9662,0.92706,0.4645,0.69811,0.05447,0.88291,0.89748,0.70215,0.26124,0.4949,0.66987,0.76537,0.91717,0.4012,0.5144,0.93487,0.92218,0.86323,0.892,0.8374,0.63267,0.9088,0.56365,0.12123,0.90233,0.44074,0.83123,0.8526,0.85517,0.27417,0.10364,0.41339,0.95553,0.73661,0.08517,0.16809,0.9041,0.80677,0.3073,0.052,0.21926,0.2308,0.8115,0.20049,0.16489,0.1128,0.14371,0.05023,0.0724,0.6232,0.62991,0.19647,0.0866,0.07717,0.5205,0.81153,0.36544,0.98299,0.2873,0.11115,0.01386,0.0596,0.0678,0.20069,0.17369,0.26871,0.1514,0.46519,0.89371,0.87789,0.116,0.1297,0.23878,0.88465,0.92458,0.84839,0.52675,0.8814,0.7029,0.05635,0.53185,0.87103,0.16027,0.98156,0.92621,0.2512,0.47718,0.84154,0.77353,0.94014,0.92844,0.94035,0.2728,0.82814,0.6338 diff --git a/crates/tm30/examples/bench.rs b/crates/tm30/examples/bench.rs new file mode 100644 index 0000000..849c185 --- /dev/null +++ b/crates/tm30/examples/bench.rs @@ -0,0 +1,38 @@ +//! Timing of `tm30::compute` on an HPCS 6500-like input (350 points, +//! 380-1050 nm). Run with `cargo run -p tm30 --release --example bench`. + +use std::time::Instant; + +fn main() { + // Warm-white LED-like spectrum: blue pump + broad phosphor, on the HPCS + // 6500 wavelength grid. + let wl: Vec = (0..350).map(|i| 380.0 + 670.0 * i as f64 / 349.0).collect(); + let values: Vec = wl + .iter() + .map(|&w| { + let blue = (-((w - 450.0) / 12.0).powi(2)).exp(); + let phosphor = 1.6 * (-((w - 600.0) / 70.0).powi(2)).exp(); + blue + phosphor + }) + .collect(); + + let t0 = Instant::now(); + let first = tm30::compute(&wl, &values).expect("valid spectrum"); + let cold = t0.elapsed(); + + let n = 200; + let t1 = Instant::now(); + let mut rf = 0.0; + for _ in 0..n { + rf += tm30::compute(&wl, &values).expect("valid spectrum").rf; + } + let warm = t1.elapsed() / n; + assert!((rf / n as f64 - first.rf).abs() < 1e-12); + + println!( + "Rf {:.2} Rg {:.2} CCT {:.0} K Duv {:.4}", + first.rf, first.rg, first.cct_k, first.duv + ); + println!("first call (parses tables, builds Planckian table): {cold:?}"); + println!("per call afterwards (mean of {n}): {warm:?}"); +} diff --git a/crates/tm30/src/cam.rs b/crates/tm30/src/cam.rs new file mode 100644 index 0000000..a657cf6 --- /dev/null +++ b/crates/tm30/src/cam.rs @@ -0,0 +1,137 @@ +//! CIECAM02 (forward, colour-science 0.4.7 formulation) and CAM02-UCS, for +//! the CIE 2017 colour fidelity viewing conditions: `L_A = 100`, `Y_b = 20`, +//! "Average" surround, illuminant discounted (`D = 1`), `XYZ_w` normalised to +//! `Y_w = 100`. + +use crate::data::Mat3; +use crate::numeric::{np_remainder, np_sign, sdiv, spow}; + +const L_A: f64 = 100.0; +const Y_B: f64 = 20.0; +/// "Average" surround: F = 1, c = 0.69, N_c = 1. +const SURROUND_C: f64 = 0.69; +const SURROUND_N_C: f64 = 1.0; +/// CAM02-UCS coefficients (Luo et al. 2006): K_L = 1, c_1 = 0.007, c_2 = 0.0228. +const UCS_C1: f64 = 0.007; +const UCS_C2: f64 = 0.0228; + +fn vecmul(m: &Mat3, v: [f64; 3]) -> [f64; 3] { + [ + m[0][0] * v[0] + m[0][1] * v[1] + m[0][2] * v[2], + m[1][0] * v[0] + m[1][1] * v[1] + m[1][2] * v[2], + m[2][0] * v[0] + m[2][1] * v[1] + m[2][2] * v[2], + ] +} + +/// `luminance_level_adaptation_factor(L_A)`. +fn f_l() -> f64 { + let k = 1.0 / (5.0 * L_A + 1.0); + let k4 = k.powf(4.0); + 0.2 * k4 * (5.0 * L_A) + 0.1 * ((1.0 - k4) * (1.0 - k4)) * spow(5.0 * L_A, 1.0 / 3.0) +} + +/// Adapting state for one irradiating illuminant (the parts of +/// `XYZ_to_CIECAM02` that depend only on the white point). +pub(crate) struct Adaptation<'m> { + cat02: &'m Mat3, + hpe: &'m Mat3, + y_w: f64, + rgb_w: [f64; 3], + f_l: f64, + f_l_4: f64, + n: f64, + n_bb: f64, + n_cb: f64, + z: f64, + a_w: f64, +} + +/// CIECAM02 correlates needed downstream. +#[derive(Debug, Clone, Copy)] +pub(crate) struct Jmh { + pub j: f64, + pub m: f64, + pub h: f64, +} + +impl<'m> Adaptation<'m> { + pub(crate) fn new(xyz_w: [f64; 3], cat02: &'m Mat3, hpe: &'m Mat3) -> Self { + let y_w = xyz_w[1]; + let n = sdiv(Y_B, y_w); + let f_l = f_l(); + let n_bb = 0.725 * spow(sdiv(1.0, n), 0.2); + let n_cb = n_bb; + let z = 1.48 + n.sqrt(); + let rgb_w = vecmul(cat02, xyz_w); + let mut s = Self { + cat02, + hpe, + y_w, + rgb_w, + f_l, + f_l_4: spow(f_l, 0.25), + n, + n_bb, + n_cb, + z, + a_w: 0.0, + }; + let rgb_aw = s.compressed(rgb_w); + s.a_w = achromatic_response(rgb_aw, n_bb); + s + } + + /// Full chromatic adaptation (D = 1), HPE conversion and post-adaptation + /// non-linear response compression. + fn compressed(&self, rgb: [f64; 3]) -> [f64; 3] { + let d = 1.0; + let mut rgb_c = [0.0; 3]; + for i in 0..3 { + rgb_c[i] = (self.y_w * sdiv(d, self.rgb_w[i]) + 1.0 - d) * rgb[i]; + } + let rgb_p = vecmul(self.hpe, rgb_c); + rgb_p.map(|x| { + let f_l_rgb = spow(self.f_l * x.abs() / 100.0, 0.42); + 400.0 * np_sign(x) * f_l_rgb / (27.13 + f_l_rgb) + 0.1 + }) + } + + /// `XYZ_to_CIECAM02(XYZ, XYZ_w, 100, 20, Average, discount_illuminant=True)` + /// restricted to J, M, h. + pub(crate) fn xyz_to_jmh(&self, xyz: [f64; 3]) -> Jmh { + let rgb = vecmul(self.cat02, xyz); + let rgb_a = self.compressed(rgb); + let [ra, ga, ba] = rgb_a; + + // Opponent colour dimensions. + let a = ra - 12.0 * ga / 11.0 + ba / 11.0; + let b = (ra + ga - 2.0 * ba) / 9.0; + + let h = np_remainder(b.atan2(a).to_degrees(), 360.0); + let e_t = 1.0 / 4.0 * ((2.0 + h * std::f64::consts::PI / 180.0).cos() + 3.8); + + let a_resp = achromatic_response(rgb_a, self.n_bb); + let j = 100.0 * spow(sdiv(a_resp, self.a_w), SURROUND_C * self.z); + + let t = 50000.0 / 13.0 + * SURROUND_N_C + * self.n_cb + * sdiv(e_t * spow(a * a + b * b, 0.5), ra + ga + 21.0 * ba / 20.0); + let c = spow(t, 0.9) * spow(j / 100.0, 0.5) * spow(1.64 - 0.29_f64.powf(self.n), 0.73); + let m = c * self.f_l_4; + Jmh { j, m, h } + } +} + +fn achromatic_response(rgb: [f64; 3], n_bb: f64) -> f64 { + let [r, g, b] = rgb; + (2.0 * r + g + 1.0 / 20.0 * b - 0.305) * n_bb +} + +/// `JMh_CIECAM02_to_CAM02UCS`: `[J', a', b']`. +pub(crate) fn jmh_to_cam02ucs(jmh: Jmh) -> [f64; 3] { + let j_p = (1.0 + 100.0 * UCS_C1) * jmh.j / (1.0 + UCS_C1 * jmh.j); + let m_p = 1.0 / UCS_C2 * (UCS_C2 * jmh.m).ln_1p(); + let h = jmh.h.to_radians(); + [j_p, m_p * h.cos(), m_p * h.sin()] +} diff --git a/crates/tm30/src/cct.rs b/crates/tm30/src/cct.rs new file mode 100644 index 0000000..b4cb891 --- /dev/null +++ b/crates/tm30/src/cct.rs @@ -0,0 +1,152 @@ +//! Correlated colour temperature by Ohno (2013), as implemented by +//! colour-science 0.4.7 `uv_to_CCT_Ohno2013(uv, start=1000, end=25000)`: +//! a single Planckian table (spacing 1.001, slightly decreasing towards high +//! CCT), nearest-row search, then the triangular solution, or the parabolic +//! one when |Duv| >= 0.002. + +use std::sync::OnceLock; + +use crate::colorimetry::{ + integration_k, msds_row_to_xyz, planck_prefactor, planck_sample, wl_m, xyz_to_uv, +}; +use crate::data::{N_WL_DEFAULT, WL_DEFAULT_START, tables}; +use crate::numeric::np_sign; + +const CCT_MINIMAL_OHNO2013: f64 = 1000.0; +const CCT_MAXIMAL_OHNO2013: f64 = 100000.0; +const SPACING: f64 = 1.001; +/// TM-30 / CIE 2017 temperature range. +const START: f64 = 1000.0; +const END: f64 = 25000.0; + +/// Planckian table rows: `[T, u, v]`. +fn planckian_table() -> &'static [[f64; 3]] { + static TABLE: OnceLock> = OnceLock::new(); + TABLE.get_or_init(|| { + let mut ti = vec![START, START + 1.0]; + let mut next_ti = START + 1.0; + let mut next_spacing = SPACING; + loop { + next_ti *= next_spacing; + if next_ti >= END { + break; + } + ti.push(next_ti); + let d = + (next_ti - CCT_MINIMAL_OHNO2013) / (CCT_MAXIMAL_OHNO2013 - CCT_MINIMAL_OHNO2013); + let d = d.clamp(0.0, 1.0); + next_spacing = SPACING * (1.0 - d) + (1.0 + (SPACING - 1.0) / 10.0) * d; + } + ti.push(END - 1.0); + ti.push(END); + + // CCT_to_uv_Planck1900(Ti, cmfs) with colour's default observer + // shape (360-780 nm / 1 nm). + let cmf = &tables().cmf2_default; + let k = integration_k(cmf); + let wl: Vec<(f64, f64)> = (0..N_WL_DEFAULT) + .map(|i| { + let l = wl_m(WL_DEFAULT_START + i); + (l, planck_prefactor(l)) + }) + .collect(); + let mut spd = vec![0.0; N_WL_DEFAULT]; + ti.iter() + .map(|&t| { + for (s, &(l, pre)) in spd.iter_mut().zip(&wl) { + *s = planck_sample(pre, l, t); + } + let [u, v] = xyz_to_uv(msds_row_to_xyz(&spd, cmf, k)); + [t, u, v] + }) + .collect() + }) +} + +/// Force construction of the cached Planckian table. +pub(crate) fn warm_up() { + let _ = planckian_table(); +} + +/// `uv_to_CCT_Ohno2013(uv, start=1000, end=25000)` -> `(CCT, Duv)`. +pub(crate) fn uv_to_cct_ohno2013(uv: [f64; 2]) -> (f64, f64) { + let table = planckian_table(); + let [u, v] = uv; + + // np.argmin over the euclidean distances (first minimum; first NaN wins). + let dist = |row: &[f64; 3]| { + let du = row[1] - u; + let dv = row[2] - v; + (du * du + dv * dv).sqrt() + }; + let mut index = 0; + let mut best = dist(&table[0]); + if !best.is_nan() { + for (i, row) in table.iter().enumerate().skip(1) { + let d = dist(row); + if d.is_nan() { + index = i; + break; + } + if d < best { + best = d; + index = i; + } + } + } + if index == 0 { + index += 1; + } else if index == table.len() - 1 { + index -= 1; + } + + let [tip, uip, vip] = table[index - 1]; + let dip = dist(&table[index - 1]); + let [ti, _, _] = table[index]; + let di = dist(&table[index]); + let [tin, uin, vin] = table[index + 1]; + let din = dist(&table[index + 1]); + + // Triangular solution. + let l = (uin - uip).hypot(vin - vip); + let x = (dip * dip - din * din + l * l) / (2.0 * l); + let t_t = tip + (tin - tip) * (x / l); + let vtx = vip + (vin - vip) * (x / l); + let sign = np_sign(v - vtx); + let d_uv_t = (dip * dip - x * x).sqrt() * sign; + + // Parabolic solution. + let xx = (tin - ti) * (tip - tin) * (ti - tip); + let inv_x = 1.0 / xx; + let a = (tip * (din - di) + ti * (dip - din) + tin * (di - dip)) * inv_x; + let b = -(tip * tip * (din - di) + ti * ti * (dip - din) + tin * tin * (di - dip)) * inv_x; + let c = + -(dip * (tin - ti) * ti * tin + di * (tip - tin) * tip * tin + din * (ti - tip) * tip * ti) + * inv_x; + let t_p = -b / (2.0 * a); + let d_uv_p = (a * (t_p * t_p) + b * t_p + c) * sign; + + if d_uv_t.abs() >= 0.002 { + (t_p, d_uv_p) + } else { + (t_t, d_uv_t) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn table_shape_matches_colour() { + // colour 0.4.7: planckian_table(cmfs, 1000, 25000, 1.001).shape == (3438, 3) + let t = planckian_table(); + assert_eq!(t.len(), 3438); + assert_eq!(t[0][0], 1000.0); + assert_eq!(t[1][0], 1001.0); + assert_eq!(t[t.len() - 2][0], 24999.0); + assert_eq!(t[t.len() - 1][0], 25000.0); + assert!((t[0][1] - 0.447962884).abs() < 1e-8); + assert!((t[0][2] - 0.354629625).abs() < 1e-8); + } +} diff --git a/crates/tm30/src/colorimetry.rs b/crates/tm30/src/colorimetry.rs new file mode 100644 index 0000000..77f3324 --- /dev/null +++ b/crates/tm30/src/colorimetry.rs @@ -0,0 +1,154 @@ +//! Spectral colorimetry on the TM-30 path: tristimulus integration, CIE UCS +//! chromaticities, Planck's law and the CIE D-series / TM-30 reference +//! illuminant. + +use crate::data::{N_WL, WL_START, tables}; +use crate::numeric::{np_round3, np_sum, sdiv}; + +/// `colour.colorimetry.blackbody.CONSTANT_C1`. +const CONSTANT_C1: f64 = 3.741771e-16; +/// `colour.colorimetry.blackbody.CONSTANT_C2`. +const CONSTANT_C2: f64 = 1.4388e-2; + +/// Weight of colour's implicit illuminant E (constant 100) in the +/// "Integration" tristimulus method. +const ILLUMINANT_E: f64 = 100.0; + +/// Precomputed normalisation of colour's `sd_to_XYZ_integration` for a CMF +/// table and illuminant E: `k = 100 / (sum(y_bar * S) * d_w)`. +pub(crate) fn integration_k(cmf: &[[f64; 3]]) -> f64 { + let ys: Vec = cmf.iter().map(|c| c[1] * ILLUMINANT_E).collect(); + sdiv(100.0, np_sum(&ys) * 1.0) +} + +/// colour's `sd_to_XYZ_integration` for a single spectrum (illuminant E, +/// 1 nm, `k` from [`integration_k`]): `XYZ = k * dot(R * S, cmfs) * d_w`. +/// +/// numpy evaluates the `(1, N) @ (N, 3)` product with OpenBLAS `dgemv` +/// (row-major, transposed), whose 3-row path sums pairs of products per +/// 4-sample block without FMA contraction; this reproduces that order, which +/// matches numpy bit for bit. +pub(crate) fn sd_to_xyz(r: &[f64], cmf: &[[f64; 3]], k: f64) -> [f64; 3] { + debug_assert_eq!(r.len(), cmf.len()); + let x: Vec = r.iter().map(|&ri| ri * ILLUMINANT_E).collect(); + let n = x.len(); + let mut t = [0.0_f64; 3]; + let mut i = 0; + while i < (n & !3) { + for (c, tc) in t.iter_mut().enumerate() { + *tc += cmf[i][c] * x[i] + cmf[i + 1][c] * x[i + 1]; + *tc += cmf[i + 2][c] * x[i + 2] + cmf[i + 3][c] * x[i + 3]; + } + i += 4; + } + while i < n { + for (c, tc) in t.iter_mut().enumerate() { + *tc += cmf[i][c] * x[i]; + } + i += 1; + } + t.map(|v| k * (0.0 + 1.0 * v) * 1.0) +} + +/// colour's `msds_to_XYZ_integration` row for a 2-D batch (numpy `dgemm`; +/// OpenBLAS's blocked FMA kernel order is not reproduced, a plain +/// sequential sum is used instead, which agrees to ~1 ulp). +pub(crate) fn msds_row_to_xyz(r: &[f64], cmf: &[[f64; 3]], k: f64) -> [f64; 3] { + debug_assert_eq!(r.len(), cmf.len()); + let mut acc = [0.0_f64; 3]; + for (&ri, c) in r.iter().zip(cmf) { + let w = ri * ILLUMINANT_E; + acc[0] += w * c[0]; + acc[1] += w * c[1]; + acc[2] += w * c[2]; + } + acc.map(|v| k * v * 1.0) +} + +/// `UCS_to_uv(XYZ_to_UCS(XYZ))`. +pub(crate) fn xyz_to_uv(xyz: [f64; 3]) -> [f64; 2] { + let [x, y, z] = xyz; + let u_ = 2.0 / 3.0 * x; + let v_ = y; + let w_ = 1.0 / 2.0 * (-x + 3.0 * y + z); + let s = u_ + v_ + w_; + [sdiv(u_, s), sdiv(v_, s)] +} + +/// Per-wavelength factor of `planck_law`: `(c1 * n**-2 * l**-5) / pi` with +/// `l` in metres. +pub(crate) fn planck_prefactor(l: f64) -> f64 { + (CONSTANT_C1 * 1.0 * l.powf(-5.0)) / std::f64::consts::PI +} + +/// `planck_law(l, t) * 1e-9` given the precomputed prefactor for `l` +/// (metres), i.e. one sample of colour's `sd_blackbody`. +pub(crate) fn planck_sample(prefactor: f64, l: f64, t: f64) -> f64 { + let d = 1.0 / (CONSTANT_C2 / (1.0 * l * t)).exp_m1(); + prefactor * d * 1e-9 +} + +/// Wavelength in metres as colour computes it: `wavelengths * 1e-9`. +pub(crate) fn wl_m(nm: usize) -> f64 { + nm as f64 * 1e-9 +} + +/// `sd_blackbody(T, SpectralShape(380, 780, 1)).values`. +fn sd_blackbody(t: f64) -> Vec { + (0..N_WL) + .map(|i| { + let l = wl_m(WL_START + i); + planck_sample(planck_prefactor(l), l, t) + }) + .collect() +} + +/// `CCT_to_xy_CIE_D(CCT)` (no 1.4388/1.4380 correction, as in cfi2017). +fn cct_to_xy_cie_d(cct: f64) -> [f64; 2] { + let cct_3 = cct.powf(3.0); + let cct_2 = cct * cct; + let x = if cct <= 7000.0 { + -4.607 * 1e9 / cct_3 + 2.9678 * 1e6 / cct_2 + 0.09911 * 1e3 / cct + 0.244063 + } else { + -2.0064 * 1e9 / cct_3 + 1.9018 * 1e6 / cct_2 + 0.24748 * 1e3 / cct + 0.23704 + }; + // daylight_locus_function + let y = -3.000 * (x * x) + 2.870 * x - 0.275; + [x, y] +} + +/// `sd_CIE_illuminant_D_series(xy, M1_M2_rounding=True, shape=380-780/1)`. +fn sd_cie_illuminant_d_series(xy: [f64; 2]) -> Vec { + let [x, y] = xy; + let m = 0.0241 + 0.2562 * x - 0.7341 * y; + let m1 = np_round3((-1.3515 - 1.7703 * x + 5.9114 * y) / m); + let m2 = np_round3((0.0300 - 31.4424 * x + 30.0717 * y) / m); + tables() + .d_basis + .iter() + .map(|s| s[0] + m1 * s[1] + m2 * s[2]) + .collect() +} + +/// colour's `sd_reference_illuminant(CCT, SpectralShape(380, 780, 1))`. +pub(crate) fn sd_reference_illuminant(cct: f64) -> Vec { + if cct < 4000.0 { + sd_blackbody(cct) + } else if cct <= 5000.0 { + let t = tables(); + let k2 = integration_k(&t.cmf2); + let planck = sd_blackbody(cct); + let daylight = sd_cie_illuminant_d_series(cct_to_xy_cie_d(cct)); + let yp = sd_to_xyz(&planck, &t.cmf2, k2)[1]; + let yd = sd_to_xyz(&daylight, &t.cmf2, k2)[1]; + let m = (cct - 4000.0) / 1000.0; + planck + .iter() + .zip(&daylight) + .map(|(&p, &d)| (1.0 - m) * (p / yp) + m * (d / yd)) + .collect() + } else { + // `CCT > 5000` (and NaN, which colour would fail on anyway). + sd_cie_illuminant_d_series(cct_to_xy_cie_d(cct)) + } +} diff --git a/crates/tm30/src/data.rs b/crates/tm30/src/data.rs new file mode 100644 index 0000000..4795fc9 --- /dev/null +++ b/crates/tm30/src/data.rs @@ -0,0 +1,139 @@ +//! Embedded spectral tables (extracted by `tools/extract_data.py`). +//! +//! All tables are the *effective* arrays colour-science 0.4.7 works with on +//! the TM-30 path (after its Sprague re-alignment), stored as CSV with +//! shortest round-trip float formatting, parsed once on first use. + +use std::sync::OnceLock; + +/// First wavelength of the TM-30 working grid (nm). +pub(crate) const WL_START: usize = 380; +/// Last wavelength of the TM-30 working grid (nm). +pub(crate) const WL_END: usize = 780; +/// Number of samples of the 380..=780 nm / 1 nm working grid. +pub(crate) const N_WL: usize = WL_END - WL_START + 1; +/// First wavelength of colour's default spectral shape (Planckian table). +pub(crate) const WL_DEFAULT_START: usize = 360; +/// Number of samples of colour's default spectral shape 360..=780 nm / 1 nm. +pub(crate) const N_WL_DEFAULT: usize = WL_END - WL_DEFAULT_START + 1; +/// Number of CIE 2017 test colour samples. +pub(crate) const N_TCS: usize = 99; + +const CMF_1931_360_780: &str = include_str!("../data/cmf_cie1931_2deg_360_780.csv"); +const CMF_1931_380_780: &str = include_str!("../data/cmf_cie1931_2deg_380_780.csv"); +const CMF_1964_380_780: &str = include_str!("../data/cmf_cie1964_10deg_380_780.csv"); +const D_SERIES_380_780: &str = include_str!("../data/d_series_basis_380_780.csv"); +const TCS_380_780: &str = include_str!("../data/tcs_cie2017_380_780.csv"); +const CIECAM02_MATRICES: &str = include_str!("../data/ciecam02_matrices.csv"); + +pub(crate) type Mat3 = [[f64; 3]; 3]; + +pub(crate) struct Tables { + /// CIE 1931 2° CMFs on 360..=780 nm (used for the Ohno Planckian table). + pub cmf2_default: Vec<[f64; 3]>, + /// CIE 1931 2° CMFs on 380..=780 nm (test CCT, reference normalisation). + pub cmf2: Vec<[f64; 3]>, + /// CIE 1964 10° CMFs on 380..=780 nm (all CIECAM02 colorimetry). + pub cmf10: Vec<[f64; 3]>, + /// CIE D-series basis functions S0, S1, S2 on 380..=780 nm. + pub d_basis: Vec<[f64; 3]>, + /// CIE 2017 TCS reflectances, `tcs[sample][wavelength]`. + pub tcs: Vec>, + /// CAT02 matrix. + pub cat02: Mat3, + /// `MATRIX_XYZ_TO_HPE @ inv(CAT02)` exactly as computed by numpy. + pub hpe_cat02_inv: Mat3, +} + +fn parse_rows(csv: &str, name: &str) -> Vec> { + csv.lines() + .skip(1) + .filter(|l| !l.trim().is_empty()) + .map(|line| { + line.split(',') + .map(|field| { + field + .trim() + .parse::() + .unwrap_or_else(|e| panic!("{name}: bad number {field:?}: {e}")) + }) + .collect() + }) + .collect() +} + +/// Parse a `wavelength,c1,c2,c3` table and check the wavelength column. +fn parse_tristimulus(csv: &str, name: &str, start: usize, n: usize) -> Vec<[f64; 3]> { + let rows = parse_rows(csv, name); + assert_eq!(rows.len(), n, "{name}: unexpected row count"); + rows.iter() + .enumerate() + .map(|(i, r)| { + assert_eq!(r.len(), 4, "{name}: unexpected column count"); + assert_eq!(r[0], (start + i) as f64, "{name}: unexpected wavelength"); + [r[1], r[2], r[3]] + }) + .collect() +} + +fn parse_tcs() -> Vec> { + let rows = parse_rows(TCS_380_780, "tcs"); + assert_eq!(rows.len(), N_WL, "tcs: unexpected row count"); + let mut tcs = vec![vec![0.0; N_WL]; N_TCS]; + for (w, r) in rows.iter().enumerate() { + assert_eq!(r.len(), N_TCS + 1, "tcs: unexpected column count"); + assert_eq!(r[0], (WL_START + w) as f64, "tcs: unexpected wavelength"); + for (s, sample) in tcs.iter_mut().enumerate() { + sample[w] = r[s + 1]; + } + } + tcs +} + +fn parse_matrices() -> (Mat3, Mat3) { + let mut cat02 = None; + let mut hpe = None; + for line in CIECAM02_MATRICES.lines().skip(1) { + let mut fields = line.split(','); + let Some(name) = fields.next() else { continue }; + let v: Vec = fields + .map(|f| { + f.trim() + .parse::() + .expect("ciecam02 matrices: bad number") + }) + .collect(); + assert_eq!(v.len(), 9, "ciecam02 matrices: expected 9 values"); + let m = [[v[0], v[1], v[2]], [v[3], v[4], v[5]], [v[6], v[7], v[8]]]; + match name.trim() { + "CAT02" => cat02 = Some(m), + "HPE_CAT02_INV" => hpe = Some(m), + other => panic!("ciecam02 matrices: unknown matrix {other}"), + } + } + ( + cat02.expect("CAT02 missing"), + hpe.expect("HPE_CAT02_INV missing"), + ) +} + +pub(crate) fn tables() -> &'static Tables { + static TABLES: OnceLock = OnceLock::new(); + TABLES.get_or_init(|| { + let (cat02, hpe_cat02_inv) = parse_matrices(); + Tables { + cmf2_default: parse_tristimulus( + CMF_1931_360_780, + "cmf 1931 360-780", + WL_DEFAULT_START, + N_WL_DEFAULT, + ), + cmf2: parse_tristimulus(CMF_1931_380_780, "cmf 1931 380-780", WL_START, N_WL), + cmf10: parse_tristimulus(CMF_1964_380_780, "cmf 1964 380-780", WL_START, N_WL), + d_basis: parse_tristimulus(D_SERIES_380_780, "d-series basis", WL_START, N_WL), + tcs: parse_tcs(), + cat02, + hpe_cat02_inv, + } + }) +} diff --git a/crates/tm30/src/lib.rs b/crates/tm30/src/lib.rs new file mode 100644 index 0000000..c576e5f --- /dev/null +++ b/crates/tm30/src/lib.rs @@ -0,0 +1,374 @@ +//! ANSI/IES TM-30-18 colour rendition metrics from a measured spectrum. +//! +//! A pure-Rust port of the HPCS `tm30.py` reference (which wraps +//! `colour.quality.colour_fidelity_index_ANSIIESTM3018` from colour-science +//! 0.4.7). It reproduces the Python numbers to floating-point rounding +//! level: the same CIE tables (embedded, see `data/` and `README.md`), the +//! same Ohno (2013) Planckian table and search, the same reference +//! illuminant construction (Planckian < 4000 K, mixture 4000-5000 K, +//! CIE D-series > 5000 K with M1/M2 rounded to 3 decimals), CIECAM02 with +//! the CIE 2017 viewing conditions and CAM02-UCS. +//! +//! ``` +//! // A flat (equal-energy) spectrum on a 2 nm grid. +//! let wl: Vec = (0..=200).map(|i| 380.0 + 2.0 * i as f64).collect(); +//! let v = vec![1.0; wl.len()]; +//! let r = tm30::compute(&wl, &v).unwrap(); +//! assert_eq!(r.bins.len(), tm30::N_BINS); +//! assert!(r.rf > 90.0 && r.cct_k > 5000.0); +//! ``` + +mod cam; +mod cct; +mod colorimetry; +mod data; +mod numeric; + +use cam::{Adaptation, Jmh, jmh_to_cam02ucs}; +use colorimetry::{integration_k, msds_row_to_xyz, sd_reference_illuminant, sd_to_xyz, xyz_to_uv}; +use data::{N_TCS, N_WL, WL_END, WL_START, tables}; +use numeric::{np_interp, np_mean, np_sum}; + +/// Number of TM-30 hue bins. +pub const N_BINS: usize = 16; + +/// Lower bound of the wavelength range used (nm, inclusive). +pub const VISIBLE_MIN_NM: f64 = WL_START as f64; +/// Upper bound of the wavelength range used (nm, inclusive). +pub const VISIBLE_MAX_NM: f64 = WL_END as f64; +/// Minimum number of input samples inside 380..=780 nm. +pub const MIN_VISIBLE_POINTS: usize = 10; + +/// Per hue bin data for the TM-30 colour vector graphic. +#[derive(Debug, Clone, Copy, PartialEq)] +pub struct HueBin { + /// Hue bin number, 1..=16. + pub bin: u32, + /// Reference CAM02-UCS a' average of the bin's samples. + pub ref_a: f64, + /// Reference CAM02-UCS b' average. + pub ref_b: f64, + /// Test CAM02-UCS a' average. + pub test_a: f64, + /// Test CAM02-UCS b' average. + pub test_b: f64, + /// `ref_a` divided by the reference average's norm (unit circle). + pub ref_a_norm: f64, + /// `ref_b` normalised the same way. + pub ref_b_norm: f64, + /// `test_a` normalised by the *reference* norm. + pub test_a_norm: f64, + /// `test_b` normalised by the *reference* norm. + pub test_b_norm: f64, + /// Local chroma shift R_cs,hj in percent. + pub rcs_pct: f64, + /// Local hue shift R_hs,hj (radians-like, CAM02-UCS). + pub rhs: f64, + /// Local colour fidelity: mean of the per-sample R_f,i of the bin's + /// samples (NaN if the bin holds no sample). + pub rf_h: f64, +} + +/// TM-30-18 results. +#[derive(Debug, Clone, PartialEq)] +pub struct Tm30 { + /// Fidelity index R_f. + pub rf: f64, + /// Gamut index R_g. + pub rg: f64, + /// Correlated colour temperature (Ohno 2013, 1000-25000 K), kelvin. + pub cct_k: f64, + /// Distance from the Planckian locus Duv. + pub duv: f64, + /// The 16 hue bins, in bin order. + pub bins: Vec, +} + +/// Errors returned by [`compute`]. +#[derive(Debug, Clone, PartialEq)] +pub enum Error { + /// Fewer than [`MIN_VISIBLE_POINTS`] samples within 380..=780 nm. + NotVisible, + /// Malformed input (length mismatch, non-finite or unsorted data, no + /// usable signal). + InvalidInput(String), +} + +impl std::fmt::Display for Error { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Error::NotVisible => f.write_str("spectrum does not cover the visible range"), + Error::InvalidInput(msg) => write!(f, "invalid input: {msg}"), + } + } +} + +impl std::error::Error for Error {} + +/// Detailed per-sample data (the 99 CIE 2017 colour evaluation samples), +/// exposed for diagnostics. +#[derive(Debug, Clone, PartialEq)] +pub struct SampleData { + /// Hue bin index 0..=15 of each sample (from its reference hue), or + /// `None` if outside (only possible for degenerate input). + pub bins: Vec>, + /// CAM02-UCS J', a', b' under the test source. + pub test_jab: Vec<[f64; 3]>, + /// CAM02-UCS J', a', b' under the reference illuminant. + pub ref_jab: Vec<[f64; 3]>, + /// Colour difference ΔE'_i per sample. + pub delta_e: Vec, + /// Special fidelity index R_f,i per sample. + pub r_s: Vec, +} + +/// Compute TM-30-18 quantities from a measured spectrum. +/// +/// `wavelengths_nm` must be ascending (any step, e.g. the HPCS 6500's 350 +/// points over 380-1050 nm); `values` are relative spectral powers. Only +/// samples within 380..=780 nm are used; they are linearly resampled +/// (`np.interp` semantics, ends held constant) onto a 1 nm grid. +pub fn compute(wavelengths_nm: &[f64], values: &[f64]) -> Result { + compute_detailed(wavelengths_nm, values).map(|(r, _)| r) +} + +/// Pre-build the cached Planckian table and parse the embedded data, so +/// that the first [`compute`] call is not slower than the others. +pub fn warm_up() { + let _ = tables(); + cct::warm_up(); +} + +/// Resample onto the 380..=780 nm / 1 nm grid exactly like `tm30.py`. +fn resample(wavelengths_nm: &[f64], values: &[f64]) -> Result, Error> { + if wavelengths_nm.len() != values.len() { + return Err(Error::InvalidInput(format!( + "{} wavelengths but {} values", + wavelengths_nm.len(), + values.len() + ))); + } + let (xp, fp): (Vec, Vec) = wavelengths_nm + .iter() + .zip(values) + .filter(|&(&w, _)| (VISIBLE_MIN_NM..=VISIBLE_MAX_NM).contains(&w)) + .map(|(&w, &v)| (w, v)) + .unzip(); + if xp.len() < MIN_VISIBLE_POINTS { + return Err(Error::NotVisible); + } + if xp.windows(2).any(|w| w[1] < w[0]) { + return Err(Error::InvalidInput("wavelengths are not ascending".into())); + } + if let Some(v) = fp.iter().find(|v| !v.is_finite()) { + return Err(Error::InvalidInput(format!( + "non-finite spectral value {v} within 380-780 nm" + ))); + } + let grid: Vec = (0..N_WL).map(|i| (WL_START + i) as f64).collect(); + Ok(np_interp(&grid, &xp, &fp)) +} + +/// CIE 2017 TCS colorimetry under one irradiating spectrum +/// (`tcs_colorimetry_data`): returns `(JMh, J'a'b')` for the 99 samples. +fn tcs_colorimetry(sd: &[f64]) -> (Vec, Vec<[f64; 3]>) { + let t = tables(); + let k_int = integration_k(&t.cmf10); + let xyz_t = sd_to_xyz(sd, &t.cmf10, k_int); + let k = 100.0 / xyz_t[1]; + let xyz_w = xyz_t.map(|c| k * c); + let sd_k: Vec = sd.iter().map(|&v| v * k).collect(); + + let adaptation = Adaptation::new(xyz_w, &t.cat02, &t.hpe_cat02_inv); + let mut buf = vec![0.0; N_WL]; + let mut jmh = Vec::with_capacity(N_TCS); + let mut jab = Vec::with_capacity(N_TCS); + for rho in &t.tcs { + for ((b, &r), &s) in buf.iter_mut().zip(rho).zip(&sd_k) { + *b = r * s; + } + let xyz = msds_row_to_xyz(&buf, &t.cmf10, k_int); + let s = adaptation.xyz_to_jmh(xyz); + jmh.push(s); + jab.push(jmh_to_cam02ucs(s)); + } + (jmh, jab) +} + +/// `delta_E_to_R_f`. +fn delta_e_to_r_f(delta_e: f64) -> f64 { + const C_F: f64 = 6.73; + 10.0 * ((100.0 - C_F * delta_e) / 10.0).exp().ln_1p() +} + +/// Like [`compute`], additionally returning the per-sample data. +pub fn compute_detailed( + wavelengths_nm: &[f64], + values: &[f64], +) -> Result<(Tm30, SampleData), Error> { + let sd = resample(wavelengths_nm, values)?; + let t = tables(); + + // CCT_reference_illuminant: CIE 1931 2° XYZ -> uv -> Ohno (2013). + let xyz = sd_to_xyz(&sd, &t.cmf2, integration_k(&t.cmf2)); + // An all-zero spectrum makes colour return NaN everywhere (and a CCT + // outside its table); report it instead. A negative luminance is kept: + // TM-30 is scale invariant and colour handles a negative scale exactly + // like the positive one. + if !(xyz[1].is_finite() && xyz[1] != 0.0) { + return Err(Error::InvalidInput( + "spectrum has no luminous power within 380-780 nm".into(), + )); + } + let (cct_k, duv) = cct::uv_to_cct_ohno2013(xyz_to_uv(xyz)); + if !cct_k.is_finite() { + return Err(Error::InvalidInput("CCT could not be determined".into())); + } + let sd_ref = sd_reference_illuminant(cct_k); + + let (_test_jmh, test_jab) = tcs_colorimetry(&sd); + let (ref_jmh, ref_jab) = tcs_colorimetry(&sd_ref); + + let delta_e: Vec = test_jab + .iter() + .zip(&ref_jab) + .map(|(a, b)| { + let d = [a[0] - b[0], a[1] - b[1], a[2] - b[2]]; + (d[0] * d[0] + d[1] * d[1] + d[2] * d[2]).sqrt() + }) + .collect(); + let r_s: Vec = delta_e.iter().map(|&d| delta_e_to_r_f(d)).collect(); + let rf = delta_e_to_r_f(np_mean(&delta_e)); + + // Hue bins from the reference hue angles. + let sample_bins: Vec> = ref_jmh + .iter() + .map(|s| { + let b = (s.h / 22.5).floor(); + (b >= 0.0 && b < N_BINS as f64).then_some(b as usize) + }) + .collect(); + + // Per-bin a'b' averages (np.nanmean along the sample axis: sequential + // accumulation in sample order). + let mut sum_test = [[0.0_f64; 2]; N_BINS]; + let mut sum_ref = [[0.0_f64; 2]; N_BINS]; + let mut count = [0_usize; N_BINS]; + for (i, b) in sample_bins.iter().enumerate() { + if let Some(b) = *b { + sum_test[b][0] += test_jab[i][1]; + sum_test[b][1] += test_jab[i][2]; + sum_ref[b][0] += ref_jab[i][1]; + sum_ref[b][1] += ref_jab[i][2]; + count[b] += 1; + } + } + let avg_test: Vec<[f64; 2]> = (0..N_BINS) + .map(|j| sum_test[j].map(|s| s / count[j] as f64)) + .collect(); + let avg_ref: Vec<[f64; 2]> = (0..N_BINS) + .map(|j| sum_ref[j].map(|s| s / count[j] as f64)) + .collect(); + + let rg = 100.0 * (averages_area(&avg_test) / averages_area(&avg_ref)); + + let mut bins = Vec::with_capacity(N_BINS); + for j in 0..N_BINS { + let angle = (22.5 * j as f64 + 11.25) / 180.0 * std::f64::consts::PI; + let (sin, cos) = (angle.sin(), angle.cos()); + let [ra, rb] = avg_ref[j]; + let [ta, tb] = avg_test[j]; + let average_norm = (ra * ra + rb * rb).sqrt(); + let a_delta = ta - ra; + let b_delta = tb - rb; + let rcs_pct = 100.0 * (a_delta * cos + b_delta * sin) / average_norm; + let rhs = (-a_delta * sin + b_delta * cos) / average_norm; + + let members: Vec = sample_bins + .iter() + .zip(&r_s) + .filter(|&(b, _)| *b == Some(j)) + .map(|(_, &r)| r) + .collect(); + let rf_h = if members.is_empty() { + f64::NAN + } else { + np_mean(&members) + }; + + // tm30.py: `norm = average_norms[j] if average_norms[j] else 1.0` + let norm = if average_norm == 0.0 { + 1.0 + } else { + average_norm + }; + bins.push(HueBin { + bin: j as u32 + 1, + ref_a: ra, + ref_b: rb, + test_a: ta, + test_b: tb, + ref_a_norm: ra / norm, + ref_b_norm: rb / norm, + test_a_norm: ta / norm, + test_b_norm: tb / norm, + rcs_pct, + rhs, + rf_h, + }); + } + + Ok(( + Tm30 { + rf, + rg, + cct_k, + duv, + bins, + }, + SampleData { + bins: sample_bins, + test_jab, + ref_jab, + delta_e, + r_s, + }, + )) +} + +/// Area of the polygon formed by the hue bin averages (`averages_area`). +fn averages_area(averages: &[[f64; 2]]) -> f64 { + let n = averages.len(); + let triangles: Vec = (0..n) + .map(|i| { + let u = averages[i]; + let v = averages[(i + 1) % n]; + (u[0] * v[1] - u[1] * v[0]) / 2.0 + }) + .collect(); + np_sum(&triangles) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn not_visible() { + let wl: Vec = (0..20).map(|i| 800.0 + i as f64).collect(); + let v = vec![1.0; wl.len()]; + assert_eq!(compute(&wl, &v), Err(Error::NotVisible)); + assert_eq!( + Error::NotVisible.to_string(), + "spectrum does not cover the visible range" + ); + } + + #[test] + fn length_mismatch() { + assert!(matches!( + compute(&[400.0, 500.0], &[1.0]), + Err(Error::InvalidInput(_)) + )); + } +} diff --git a/crates/tm30/src/numeric.rs b/crates/tm30/src/numeric.rs new file mode 100644 index 0000000..201ab26 --- /dev/null +++ b/crates/tm30/src/numeric.rs @@ -0,0 +1,162 @@ +//! Small re-implementations of the numpy / colour-science primitives whose +//! exact floating-point behaviour matters for reproducing the Python results. + +/// `numpy` pairwise summation of a contiguous float64 array (the algorithm +/// behind `np.sum` / `np.add.reduce` / `ndarray.mean` along a contiguous +/// axis): blocks of up to 128 values are summed with 8 interleaved +/// accumulators, larger arrays are split recursively. +pub(crate) fn np_sum(a: &[f64]) -> f64 { + // `np.add.reduce` starts from the additive identity. + 0.0 + pairwise_sum(a) +} + +fn pairwise_sum(a: &[f64]) -> f64 { + const PW_BLOCKSIZE: usize = 128; + let n = a.len(); + if n < 8 { + let mut res = -0.0; + for &x in a { + res += x; + } + res + } else if n <= PW_BLOCKSIZE { + let mut r = [a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7]]; + let mut i = 8; + while i < n - (n % 8) { + for (j, acc) in r.iter_mut().enumerate() { + *acc += a[i + j]; + } + i += 8; + } + let mut res = ((r[0] + r[1]) + (r[2] + r[3])) + ((r[4] + r[5]) + (r[6] + r[7])); + while i < n { + res += a[i]; + i += 1; + } + res + } else { + let mut n2 = n / 2; + n2 -= n2 % 8; + pairwise_sum(&a[..n2]) + pairwise_sum(&a[n2..]) + } +} + +/// `ndarray.mean()` of a contiguous 1-D array. +pub(crate) fn np_mean(a: &[f64]) -> f64 { + np_sum(a) / a.len() as f64 +} + +/// colour's `sdiv` in its default "Ignore Zero Conversion" mode: +/// `np.nan_to_num(a / b, nan=0, posinf=0, neginf=0)`. +pub(crate) fn sdiv(a: f64, b: f64) -> f64 { + let c = a / b; + if c.is_finite() { c } else { 0.0 } +} + +/// `np.sign`: -1, 0 or 1 (NaN for NaN). +pub(crate) fn np_sign(x: f64) -> f64 { + if x > 0.0 { + 1.0 + } else if x < 0.0 { + -1.0 + } else if x == 0.0 { + 0.0 + } else { + f64::NAN + } +} + +/// colour's `spow` (safe power): `np.sign(a) * np.abs(a) ** p`. +pub(crate) fn spow(a: f64, p: f64) -> f64 { + np_sign(a) * a.abs().powf(p) +} + +/// `np.around(x, 3)`: `rint(x * 1000) / 1000` (round half to even). +pub(crate) fn np_round3(x: f64) -> f64 { + (x * 1000.0).round_ties_even() / 1000.0 +} + +/// Python / numpy float modulo (`np.remainder`) for a positive divisor. +pub(crate) fn np_remainder(a: f64, b: f64) -> f64 { + let m = a % b; + if m != 0.0 { + if (b < 0.0) != (m < 0.0) { m + b } else { m } + } else { + 0.0_f64.copysign(b) + } +} + +/// `np.interp(x, xp, fp)` for an ascending `xp` (left/right fill with the +/// end values), reproducing numpy's evaluation order and its NaN fallback. +pub(crate) fn np_interp(x: &[f64], xp: &[f64], fp: &[f64]) -> Vec { + debug_assert_eq!(xp.len(), fp.len()); + let n = xp.len(); + let lval = fp[0]; + let rval = fp[n - 1]; + x.iter() + .map(|&xv| { + if xv.is_nan() { + return xv; + } + if n == 1 { + return if xv < xp[0] { + lval + } else if xv > xp[0] { + rval + } else { + fp[0] + }; + } + if xv > xp[n - 1] { + return rval; + } + if xv < xp[0] { + return lval; + } + // Largest j with xp[j] <= x (numpy's binary_search_with_guess + // returns exactly this index for sorted input). + let j = xp.partition_point(|&v| v <= xv) - 1; + if j == n - 1 || xp[j] == xv { + return fp[j]; + } + let slope = (fp[j + 1] - fp[j]) / (xp[j + 1] - xp[j]); + let mut r = slope * (xv - xp[j]) + fp[j]; + if r.is_nan() { + r = slope * (xv - xp[j + 1]) + fp[j + 1]; + if r.is_nan() && fp[j] == fp[j + 1] { + r = fp[j]; + } + } + r + }) + .collect() +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn pairwise_matches_naive_for_small() { + let a: Vec = (0..300).map(|i| (i as f64).sqrt()).collect(); + let naive: f64 = a.iter().sum(); + assert!((np_sum(&a) - naive).abs() < 1e-9); + assert_eq!(np_sum(&[1.0, 2.0, 3.0]), 6.0); + } + + #[test] + fn interp_edges() { + let xp = [1.0, 2.0, 4.0]; + let fp = [10.0, 20.0, 40.0]; + let r = np_interp(&[0.0, 1.0, 1.5, 3.0, 4.0, 5.0], &xp, &fp); + assert_eq!(r, vec![10.0, 10.0, 15.0, 30.0, 40.0, 40.0]); + } + + #[test] + fn remainder_and_round() { + assert_eq!(np_remainder(-30.0, 360.0), 330.0); + assert_eq!(np_remainder(370.0, 360.0), 10.0); + assert_eq!(np_round3(1.2345678), 1.235); + assert_eq!(np_round3(-0.2504999), -0.25); + } +} diff --git a/crates/tm30/tests/golden.rs b/crates/tm30/tests/golden.rs new file mode 100644 index 0000000..484b250 --- /dev/null +++ b/crates/tm30/tests/golden.rs @@ -0,0 +1,235 @@ +//! Golden tests: every case in `tests/golden/*.json` was produced by the +//! Python reference (`tools/golden.py` -> HPCS `tm30.py` -> colour-science +//! 0.4.7). Every output field is compared; NaN (encoded as `null`) must +//! match NaN. + +use std::collections::BTreeMap; +use std::path::{Path, PathBuf}; + +use serde_json::Value; + +/// Target agreement: relative difference (|a-b| / max(|a|,|b|)). +const REL_TOL: f64 = 1e-9; +/// Absolute floor for quantities that are naturally ~0 (Duv of Planckian +/// sources, hue / chroma shifts close to zero), where a relative measure is +/// meaningless. Far below any displayed precision. +const ABS_TOL: f64 = 1e-11; + +fn golden_dir() -> PathBuf { + Path::new(env!("CARGO_MANIFEST_DIR")) + .join("tests") + .join("golden") +} + +fn golden_files() -> Vec { + let mut files: Vec = std::fs::read_dir(golden_dir()) + .expect("tests/golden exists") + .map(|e| e.unwrap().path()) + .filter(|p| p.extension().is_some_and(|e| e == "json")) + .collect(); + files.sort(); + files +} + +fn num(v: &Value) -> f64 { + match v { + Value::Null => f64::NAN, + Value::Number(n) => n.as_f64().unwrap(), + other => panic!("expected number or null, got {other}"), + } +} + +fn nums(v: &Value) -> Vec { + v.as_array().unwrap().iter().map(num).collect() +} + +#[derive(Default, Clone, Copy)] +struct Dev { + max_abs: f64, + max_rel: f64, + /// Worst `min(rel / REL_TOL, abs / ABS_TOL)` (must stay <= 1). + worst: f64, + n: usize, +} + +struct Checker { + devs: BTreeMap<&'static str, Dev>, + failures: Vec, +} + +impl Checker { + fn check(&mut self, case: &str, field: &'static str, expected: f64, got: f64) { + let dev = self.devs.entry(field).or_default(); + dev.n += 1; + if expected.is_nan() || got.is_nan() { + if expected.is_nan() != got.is_nan() { + self.failures + .push(format!("{case}: {field}: expected {expected}, got {got}")); + } + return; + } + let abs = (expected - got).abs(); + let scale = expected.abs().max(got.abs()); + let rel = if scale > 0.0 { abs / scale } else { 0.0 }; + dev.max_abs = dev.max_abs.max(abs); + dev.max_rel = dev.max_rel.max(rel); + let score = (rel / REL_TOL).min(abs / ABS_TOL); + dev.worst = dev.worst.max(score); + if score > 1.0 { + self.failures.push(format!( + "{case}: {field}: expected {expected:e}, got {got:e} (abs {abs:e}, rel {rel:e})" + )); + } + } +} + +#[test] +fn golden_cases_match_python() { + let files = golden_files(); + assert!( + files.len() >= 40, + "expected the golden set, found {}", + files.len() + ); + + let mut checker = Checker { + devs: BTreeMap::new(), + failures: Vec::new(), + }; + for path in &files { + let doc: Value = serde_json::from_str(&std::fs::read_to_string(path).unwrap()).unwrap(); + let case = doc["name"].as_str().unwrap().to_owned(); + let wl = nums(&doc["wavelengths"]); + let values = nums(&doc["values"]); + let exp = &doc["expected"]; + + let got = tm30::compute(&wl, &values).unwrap_or_else(|e| panic!("{case}: {e}")); + + checker.check(&case, "Rf", num(&exp["Rf"]), got.rf); + checker.check(&case, "Rg", num(&exp["Rg"]), got.rg); + checker.check(&case, "CCT_K", num(&exp["CCT_K"]), got.cct_k); + checker.check(&case, "Duv", num(&exp["Duv"]), got.duv); + + let bins = exp["bins"].as_array().unwrap(); + assert_eq!(bins.len(), tm30::N_BINS, "{case}"); + assert_eq!(got.bins.len(), tm30::N_BINS, "{case}"); + for (e, g) in bins.iter().zip(&got.bins) { + assert_eq!(e["bin"].as_u64().unwrap(), u64::from(g.bin), "{case}"); + let c = &mut checker; + c.check(&case, "ref_a", num(&e["ref_a"]), g.ref_a); + c.check(&case, "ref_b", num(&e["ref_b"]), g.ref_b); + c.check(&case, "test_a", num(&e["test_a"]), g.test_a); + c.check(&case, "test_b", num(&e["test_b"]), g.test_b); + c.check(&case, "ref_a_norm", num(&e["ref_a_norm"]), g.ref_a_norm); + c.check(&case, "ref_b_norm", num(&e["ref_b_norm"]), g.ref_b_norm); + c.check(&case, "test_a_norm", num(&e["test_a_norm"]), g.test_a_norm); + c.check(&case, "test_b_norm", num(&e["test_b_norm"]), g.test_b_norm); + c.check(&case, "Rcs_pct", num(&e["Rcs_pct"]), g.rcs_pct); + c.check(&case, "Rhs", num(&e["Rhs"]), g.rhs); + c.check(&case, "Rf_h", num(&e["Rf_h"]), g.rf_h); + } + } + + println!("{} golden cases", files.len()); + println!( + "{:<12} {:>12} {:>12} {:>12} {:>6}", + "field", "max_abs", "max_rel", "worst_score", "n" + ); + for (field, d) in &checker.devs { + println!( + "{field:<12} {:>12.3e} {:>12.3e} {:>12.3e} {:>6}", + d.max_abs, d.max_rel, d.worst, d.n + ); + } + assert!( + checker.failures.is_empty(), + "{} mismatches:\n{}", + checker.failures.len(), + checker.failures.join("\n") + ); +} + +#[test] +fn not_visible_error() { + // Entirely outside 380-780 nm. + let wl: Vec = (0..100).map(|i| 790.0 + 2.0 * i as f64).collect(); + let v = vec![1.0; wl.len()]; + let err = tm30::compute(&wl, &v).unwrap_err(); + assert_eq!(err, tm30::Error::NotVisible); + assert_eq!(err.to_string(), "spectrum does not cover the visible range"); + + // Only 9 points inside the range (tm30.py requires at least 10). + let mut wl: Vec = (0..9).map(|i| 400.0 + 40.0 * i as f64).collect(); + wl.extend((0..50).map(|i| 800.0 + i as f64)); + let v = vec![1.0; wl.len()]; + assert_eq!(tm30::compute(&wl, &v), Err(tm30::Error::NotVisible)); + + // Exactly 10 points inside is accepted. + let wl: Vec = (0..10).map(|i| 380.0 + 40.0 * i as f64).collect(); + let v = vec![1.0; wl.len()]; + assert!(tm30::compute(&wl, &v).is_ok()); +} + +#[test] +fn invalid_input_errors() { + use tm30::Error; + let wl: Vec = (0..=40).map(|i| 380.0 + 10.0 * i as f64).collect(); + let ok = vec![1.0; wl.len()]; + assert!(matches!( + tm30::compute(&wl, &ok[1..]), + Err(Error::InvalidInput(_)) + )); + + let mut nan = ok.clone(); + nan[5] = f64::NAN; + assert!(matches!( + tm30::compute(&wl, &nan), + Err(Error::InvalidInput(_)) + )); + + let zeros = vec![0.0; wl.len()]; + assert!(matches!( + tm30::compute(&wl, &zeros), + Err(Error::InvalidInput(_)) + )); + + let mut unsorted = wl.clone(); + unsorted.swap(3, 4); + assert!(matches!( + tm30::compute(&unsorted, &ok), + Err(Error::InvalidInput(_)) + )); +} + +#[test] +fn hpcs_grid_ignores_infrared_tail() { + // The HPCS 6500 delivers 350 points over 380-1050 nm; anything past + // 780 nm must not influence the result. + let path = golden_dir().join("lamp_L0003.json"); + let doc: Value = serde_json::from_str(&std::fs::read_to_string(path).unwrap()).unwrap(); + let wl = nums(&doc["wavelengths"]); + let mut values = nums(&doc["values"]); + assert_eq!(wl.len(), 350); + let a = tm30::compute(&wl, &values).unwrap(); + for (w, v) in wl.iter().zip(values.iter_mut()) { + if *w > 780.0 { + *v = 1e6; + } + } + let b = tm30::compute(&wl, &values).unwrap(); + assert_eq!(a, b); +} + +#[test] +fn scale_invariance() { + let path = golden_dir().join("illuminant_FL2.json"); + let doc: Value = serde_json::from_str(&std::fs::read_to_string(path).unwrap()).unwrap(); + let wl = nums(&doc["wavelengths"]); + let values = nums(&doc["values"]); + let a = tm30::compute(&wl, &values).unwrap(); + let scaled: Vec = values.iter().map(|v| v * 1234.5).collect(); + let b = tm30::compute(&wl, &scaled).unwrap(); + assert!((a.rf - b.rf).abs() < 1e-9); + assert!((a.rg - b.rg).abs() < 1e-9); + assert!((a.cct_k - b.cct_k).abs() < 1e-6); +} diff --git a/crates/tm30/tests/golden/blackbody_2700K.json b/crates/tm30/tests/golden/blackbody_2700K.json new file mode 100644 index 0000000..cc7f74e --- /dev/null +++ b/crates/tm30/tests/golden/blackbody_2700K.json @@ -0,0 +1,1183 @@ +{ + "name": "blackbody_2700K", + "source": "sd_blackbody(2700, (360, 830, 1))", + "generator": "crates/tm30/tools/golden.py (tm30.py + colour-science 0.4.7, numpy 2.5.1)", + "wavelengths": [ + 360.0, + 361.0, + 362.0, + 363.0, + 364.0, + 365.0, + 366.0, + 367.0, + 368.0, + 369.0, + 370.0, + 371.0, + 372.0, + 373.0, + 374.0, + 375.0, + 376.0, + 377.0, + 378.0, + 379.0, + 380.0, + 381.0, + 382.0, + 383.0, + 384.0, + 385.0, + 386.0, + 387.0, + 388.0, + 389.0, + 390.0, + 391.0, + 392.0, + 393.0, + 394.0, + 395.0, + 396.0, + 397.0, + 398.0, + 399.0, + 400.0, + 401.0, + 402.0, + 403.0, + 404.0, + 405.0, + 406.0, + 407.0, + 408.0, + 409.0, + 410.0, + 411.0, + 412.0, + 413.0, + 414.0, + 415.0, + 416.0, + 417.0, + 418.0, + 419.0, + 420.0, + 421.0, + 422.0, + 423.0, + 424.0, + 425.0, + 426.0, + 427.0, + 428.0, + 429.0, + 430.0, + 431.0, + 432.0, + 433.0, + 434.0, + 435.0, + 436.0, + 437.0, + 438.0, + 439.0, + 440.0, + 441.0, + 442.0, + 443.0, + 444.0, + 445.0, + 446.0, + 447.0, + 448.0, + 449.0, + 450.0, + 451.0, + 452.0, + 453.0, + 454.0, + 455.0, + 456.0, + 457.0, + 458.0, + 459.0, + 460.0, + 461.0, + 462.0, + 463.0, + 464.0, + 465.0, + 466.0, + 467.0, + 468.0, + 469.0, + 470.0, + 471.0, + 472.0, + 473.0, + 474.0, + 475.0, + 476.0, + 477.0, + 478.0, + 479.0, + 480.0, + 481.0, + 482.0, + 483.0, + 484.0, + 485.0, + 486.0, + 487.0, + 488.0, + 489.0, + 490.0, + 491.0, + 492.0, + 493.0, + 494.0, + 495.0, + 496.0, + 497.0, + 498.0, + 499.0, + 500.0, + 501.0, + 502.0, + 503.0, + 504.0, + 505.0, + 506.0, + 507.0, + 508.0, + 509.0, + 510.0, + 511.0, + 512.0, + 513.0, + 514.0, + 515.0, + 516.0, + 517.0, + 518.0, + 519.0, + 520.0, + 521.0, + 522.0, + 523.0, + 524.0, + 525.0, + 526.0, + 527.0, + 528.0, + 529.0, + 530.0, + 531.0, + 532.0, + 533.0, + 534.0, + 535.0, + 536.0, + 537.0, + 538.0, + 539.0, + 540.0, + 541.0, + 542.0, + 543.0, + 544.0, + 545.0, + 546.0, + 547.0, + 548.0, + 549.0, + 550.0, + 551.0, + 552.0, + 553.0, + 554.0, + 555.0, + 556.0, + 557.0, + 558.0, + 559.0, + 560.0, + 561.0, + 562.0, + 563.0, + 564.0, + 565.0, + 566.0, + 567.0, + 568.0, + 569.0, + 570.0, + 571.0, + 572.0, + 573.0, + 574.0, + 575.0, + 576.0, + 577.0, + 578.0, + 579.0, + 580.0, + 581.0, + 582.0, + 583.0, + 584.0, + 585.0, + 586.0, + 587.0, + 588.0, + 589.0, + 590.0, + 591.0, + 592.0, + 593.0, + 594.0, + 595.0, + 596.0, + 597.0, + 598.0, + 599.0, + 600.0, + 601.0, + 602.0, + 603.0, + 604.0, + 605.0, + 606.0, + 607.0, + 608.0, + 609.0, + 610.0, + 611.0, + 612.0, + 613.0, + 614.0, + 615.0, + 616.0, + 617.0, + 618.0, + 619.0, + 620.0, + 621.0, + 622.0, + 623.0, + 624.0, + 625.0, + 626.0, + 627.0, + 628.0, + 629.0, + 630.0, + 631.0, + 632.0, + 633.0, + 634.0, + 635.0, + 636.0, + 637.0, + 638.0, + 639.0, + 640.0, + 641.0, + 642.0, + 643.0, + 644.0, + 645.0, + 646.0, + 647.0, + 648.0, + 649.0, + 650.0, + 651.0, + 652.0, + 653.0, + 654.0, + 655.0, + 656.0, + 657.0, + 658.0, + 659.0, + 660.0, + 661.0, + 662.0, + 663.0, + 664.0, + 665.0, + 666.0, + 667.0, + 668.0, + 669.0, + 670.0, + 671.0, + 672.0, + 673.0, + 674.0, + 675.0, + 676.0, + 677.0, + 678.0, + 679.0, + 680.0, + 681.0, + 682.0, + 683.0, + 684.0, + 685.0, + 686.0, + 687.0, + 688.0, + 689.0, + 690.0, + 691.0, + 692.0, + 693.0, + 694.0, + 695.0, + 696.0, + 697.0, + 698.0, + 699.0, + 700.0, + 701.0, + 702.0, + 703.0, + 704.0, + 705.0, + 706.0, + 707.0, + 708.0, + 709.0, + 710.0, + 711.0, + 712.0, + 713.0, + 714.0, + 715.0, + 716.0, + 717.0, + 718.0, + 719.0, + 720.0, + 721.0, + 722.0, + 723.0, + 724.0, + 725.0, + 726.0, + 727.0, + 728.0, + 729.0, + 730.0, + 731.0, + 732.0, + 733.0, + 734.0, + 735.0, + 736.0, + 737.0, + 738.0, + 739.0, + 740.0, + 741.0, + 742.0, + 743.0, + 744.0, + 745.0, + 746.0, + 747.0, + 748.0, + 749.0, + 750.0, + 751.0, + 752.0, + 753.0, + 754.0, + 755.0, + 756.0, + 757.0, + 758.0, + 759.0, + 760.0, + 761.0, + 762.0, + 763.0, + 764.0, + 765.0, + 766.0, + 767.0, + 768.0, + 769.0, + 770.0, + 771.0, + 772.0, + 773.0, + 774.0, + 775.0, + 776.0, + 777.0, + 778.0, + 779.0, + 780.0, + 781.0, + 782.0, + 783.0, + 784.0, + 785.0, + 786.0, + 787.0, + 788.0, + 789.0, + 790.0, + 791.0, + 792.0, + 793.0, + 794.0, + 795.0, + 796.0, + 797.0, + 798.0, + 799.0, + 800.0, + 801.0, + 802.0, + 803.0, + 804.0, + 805.0, + 806.0, + 807.0, + 808.0, + 809.0, + 810.0, + 811.0, + 812.0, + 813.0, + 814.0, + 815.0, + 816.0, + 817.0, + 818.0, + 819.0, + 820.0, + 821.0, + 822.0, + 823.0, + 824.0, + 825.0, + 826.0, + 827.0, + 828.0, + 829.0, + 830.0 + ], + "values": [ + 7.341491931876161, + 7.543426586730608, + 7.74945725859922, + 7.959630447149406, + 8.173992465244396, + 8.392589426762413, + 8.615467234494368, + 8.842671568125423, + 9.074247872304907, + 9.310241344809578, + 9.550696924804914, + 9.795659281208723, + 10.045172801161785, + 10.2992815786096, + 10.55802940299957, + 10.821459748097633, + 11.089615760928435, + 11.36254025084248, + 11.640275678714698, + 11.922864146277275, + 12.210347385590566, + 12.502766748655892, + 12.800163197172445, + 13.102577292442382, + 13.410049185426788, + 13.722618606955079, + 14.040324858091266, + 14.363206800659153, + 14.691302847929244, + 15.024650955469932, + 15.36328861216489, + 15.70725283139916, + 16.056580142416088, + 16.41130658184655, + 16.771467685412933, + 17.137098479809467, + 17.5082334747597, + 17.88490665525427, + 18.26715147396881, + 18.655000843863796, + 19.04848713096833, + 19.447642147347356, + 19.852497144254787, + 20.263082805472603, + 20.679429240836754, + 21.10156597995084, + 21.52952196608794, + 21.963325550280977, + 22.403004485602466, + 22.848585921633042, + 23.30009639912012, + 23.75756184482578, + 24.221007566564367, + 24.690458248429984, + 25.16593794621307, + 25.6474700830062, + 26.135077444999, + 26.628782177461556, + 27.128605780915226, + 27.63456910749196, + 28.146692357479452, + 28.66499507605277, + 29.189496150191815, + 29.7202138057824, + 30.257165604901537, + 30.800368443285485, + 31.34983854797856, + 31.9055914751636, + 32.467642108170764, + 33.03600465566487, + 33.6106926500097, + 34.19171894580755, + 34.77909571861292, + 35.372834463819444, + 35.9729459957167, + 36.579440446718486, + 37.19232726675788, + 37.81161522284886, + 38.43731239881394, + 39.06942619517314, + 39.70796332919552, + 40.35292983511045, + 41.0043310644755, + 41.6621716867014, + 42.32645568973036, + 42.997186380866836, + 43.67436638775825, + 44.357997659524095, + 45.04808146803081, + 45.74461840931165, + 46.44760840512788, + 47.157050704669956, + 47.87294388639758, + 48.59528586001485, + 49.32407386857877, + 50.05930449074074, + 50.800973643115306, + 51.54907658277884, + 52.30360790989068, + 53.06456157043831, + 53.83193085910369, + 54.60570842224699, + 55.3858862610067, + 56.1724557345142, + 56.965407563219614, + 57.76473183232722, + 58.57041799533852, + 59.382454877698926, + 60.2008306805491, + 61.0255329845756, + 61.85654875395915, + 62.69386434042077, + 63.537465487360144, + 64.38733733408546, + 65.24346442013365, + 66.10583068967647, + 66.97441949601222, + 67.84921360613926, + 68.73019520541072, + 69.61734590226696, + 70.51064673304404, + 71.41007816685557, + 72.31562011054767, + 73.22725191372149, + 74.14495237382381, + 75.06869974130407, + 75.998471724832, + 76.9342454965792, + 77.87599769755602, + 78.82370444300851, + 79.77734132786921, + 80.7368834322586, + 81.70230532704018, + 82.67358107942258, + 83.65068425860812, + 84.63358794148698, + 85.62226471837376, + 86.61668669878415, + 87.6168255172512, + 88.62265233917917, + 89.6341378667308, + 90.65125234474834, + 91.67396556670792, + 92.70224688069985, + 93.73606519544073, + 94.77538898630768, + 95.82018630139977, + 96.87042476762136, + 97.92607159678374, + 98.98709359173004, + 100.05345715247434, + 101.12512828235758, + 102.20207259421767, + 103.28425531657312, + 104.37164129981564, + 105.46419502241349, + 106.56188059712312, + 107.66466177720613, + 108.77250196265184, + 109.88536420640304, + 111.00321122058398, + 112.12600538272858, + 113.25370874200867, + 114.38628302545928, + 115.52368964420005, + 116.66588969965386, + 117.81284398975637, + 118.96451301516113, + 120.12085698543443, + 121.2818358252396, + 122.4474091805119, + 123.61753642462132, + 124.7921766645196, + 125.97128874687475, + 127.15483126419065, + 128.3427625609064, + 129.53504073948162, + 130.73162366646216, + 131.93246897852308, + 133.13753408849408, + 134.3467761913626, + 135.5601522702517, + 136.77761910237768, + 137.99913326497995, + 139.22465114122684, + 140.4541289260963, + 141.68752263222612, + 142.92478809573845, + 144.16588098203633, + 145.41075679156677, + 146.65937086555698, + 147.91167839171897, + 149.16763440992017, + 150.42719381782317, + 151.6903113764929, + 152.95694171596784, + 154.22703934079686, + 155.50055863554425, + 156.77745387025405, + 158.0576792058808, + 159.34118869968367, + 160.62793631058258, + 161.91787590447385, + 163.21096125951289, + 164.50714607135086, + 165.80638395833836, + 167.10862846668564, + 168.41383307558158, + 169.72195120227516, + 171.03293620711324, + 172.34674139853718, + 173.6633200380381, + 174.98262534506927, + 176.30461050191553, + 177.62922865852036, + 178.95643293727102, + 180.28617643773552, + 181.6184122413601, + 182.95309341612256, + 184.2901730211372, + 185.62960411121992, + 186.97133974140363, + 188.31533297141422, + 189.66153687009665, + 191.00990451979646, + 192.36038902069794, + 193.71294349511464, + 195.06752109173374, + 196.42407498981524, + 197.7825584033457, + 199.14292458514333, + 200.50512683091983, + 201.8691184832936, + 203.23485293575575, + 204.6022836365934, + 205.97136409276231, + 207.34204787371522, + 208.71428861518206, + 210.08804002290535, + 211.46325587632717, + 212.83989003222948, + 214.21789642833124, + 215.59722908683273, + 216.97784211791839, + 218.35968972321308, + 219.74272619918736, + 221.12690594052037, + 222.51218344341763, + 223.89851330887578, + 225.28585024590961, + 226.6741490747269, + 228.06336472986118, + 229.45345226325344, + 230.84436684729647, + 232.23606377782463, + 233.62849847706394, + 235.02162649653505, + 236.41540351991108, + 237.80978536582964, + 239.20472799066195, + 240.6001874912349, + 241.99612010751193, + 243.392482225224, + 244.78923037846315, + 246.1863212522275, + 247.58371168492275, + 248.98135867082306, + 250.3792193624855, + 251.77725107312287, + 253.1754112789322, + 254.5736576213844, + 255.97194790946546, + 257.3702401218799, + 258.76849240921234, + 260.16666309604307, + 261.56471068302636, + 262.9625938489276, + 264.3602714526147, + 265.7577025350147, + 267.1548463210251, + 268.55166222138763, + 269.9481098345228, + 271.34414894832094, + 272.73973954189677, + 274.13484178730596, + 275.52941605121845, + 276.9234228965578, + 278.3168230840994, + 279.7095775740309, + 281.101647527476, + 282.4929943079817, + 283.8835794829634, + 285.2733648251197, + 286.66231231380556, + 288.0503841363744, + 289.43754268947635, + 290.823750580328, + 292.20897062794603, + 293.5931658643398, + 294.9762995356771, + 296.35833510341, + 297.7392362453668, + 299.11896685681506, + 300.4974910514857, + 301.87477316256417, + 303.2507777436537, + 304.6254695696996, + 305.9988136378857, + 307.37077516849695, + 308.74131960575113, + 310.11041261859737, + 311.4780201014874, + 312.84410817511105, + 314.2086431871059, + 315.5715917127345, + 316.93292055553115, + 318.292596747922, + 319.650587551813, + 321.0068604591498, + 322.3613831924518, + 323.71412370531283, + 325.0650501828785, + 326.41413104229514, + 327.7613349331278, + 329.1066307377563, + 330.4499875717421, + 331.79137478416817, + 333.1307619579533, + 334.4681189101444, + 335.8034156921747, + 337.13662259010647, + 338.4677101248435, + 339.79664905231874, + 341.1234103636602, + 342.44796528533277, + 343.7702852792539, + 345.0903420428887, + 346.40810750932, + 347.7235538472974, + 349.0366534612624, + 350.3473789913546, + 351.6557033133888, + 352.96159953882, + 354.2650410146805, + 355.566001323498, + 356.86445428319354, + 358.16037394695866, + 359.45373460311265, + 360.74451077493825, + 362.03267722050253, + 363.31820893245236, + 364.6010811377947, + 365.8812692976588, + 367.1587491070367, + 368.4334964945103, + 369.7054876219533, + 370.97469888422444, + 372.24110690883833, + 373.50468855561746, + 374.7654209163312, + 376.02328131431966, + 377.27824730409344, + 378.53029667092767, + 379.7794074304322, + 381.02555782811015, + 382.2687263389013, + 383.5088916667077, + 384.7460327439087, + 385.98012873085815, + 387.21115901536916, + 388.43910321218374, + 389.6639411624288, + 390.885652933062, + 392.10421881629765, + 393.3196193290262, + 394.5318352122176, + 395.74084743031216, + 396.9466371706003, + 398.14918584258936, + 399.3484750773599, + 400.5444867269085, + 401.73720286347896, + 402.9266057788868, + 404.11267798382545, + 405.29540220716865, + 406.4747613952582, + 407.6507387111834, + 408.8233175340476, + 409.99248145823185, + 411.15821429263684, + 412.3205000599284, + 413.4793229957674, + 414.6346675480268, + 415.78651837600927, + 416.93486034964906, + 418.0796785487066, + 419.2209582619563, + 420.3586849863684, + 421.492844426276, + 422.62342249254004, + 423.7504053017101, + 424.87377917516517, + 425.99353063826294, + 427.10964641946987, + 428.2221134494923, + 429.33091886039546, + 430.436049984721, + 431.53749435459554, + 432.63523970083133, + 433.7292739520265, + 434.81958523365495, + 435.90616186715107, + 436.98899236899297, + 438.06806544977496, + 439.1433700132795, + 440.21489515554106, + 441.28263016390974, + 442.3465645161027, + 443.40668787925887, + 444.46299010898656, + 445.5154612484051, + 446.5640915271845, + 447.60887136058045, + 448.64979134846885, + 449.6868422743695, + 450.7200151044737, + 451.7493009866673, + 452.77469124954433, + 453.7961774014265, + 454.81375112937627, + 455.82740429820194, + 456.8371289494701, + 457.84291730050927, + 458.84476174340966, + 459.84265484402596, + 460.8365893409771, + 461.8265581446389, + 462.8125543361397, + 463.7945711663561, + 464.7726020549002, + 465.74664058910935, + 466.71668052303926, + 467.68271577644646, + 468.64474043377385, + 469.6027487431403, + 470.55673511531944, + 471.5066941227258, + 472.45262049839704, + 473.3945091349741, + 474.33235508368483, + 475.2661535533231, + 476.19589990923106, + 477.1215896722773, + 478.0432185178393, + 478.96078227478364, + 479.87427692444516, + 480.78369859960696, + 481.68904358348374, + 482.590308308701, + 483.4874893562772, + 484.3805834546051, + 485.26958747843656, + 486.15449844786275, + 487.0353135273012, + 487.91203002448, + 488.7846453894231, + 489.65315721343586, + 490.5175632280985, + 491.3778613042491, + 492.23404945097707, + 493.086125814615 + ], + "expected": { + "Rf": 100.0002702589043, + "Rg": 100.00002641906866, + "CCT_K": 2699.9909223665945, + "Duv": 1.7872986820373983e-06, + "bins": [ + { + "bin": 1, + "ref_a": 24.323138422607915, + "ref_b": 5.461609039893966, + "test_a": 24.323127074973932, + "test_b": 5.461595215248737, + "ref_a_norm": 0.9757049971241893, + "ref_b_norm": 0.21908847205383886, + "test_a_norm": 0.9757045419221102, + "test_b_norm": 0.21908791748825612, + "Rcs_pct": -5.5464587699330556e-05, + "Rhs": -4.551042403416234e-07, + "Rf_h": 100.00025894853208 + }, + { + "bin": 2, + "ref_a": 20.756217693402284, + "ref_b": 15.140541218110233, + "test_a": 20.75621031769526, + "test_b": 15.140540522786557, + "ref_a_norm": 0.8079000605994275, + "ref_b_norm": 0.5893195161229953, + "test_a_norm": 0.8078997735127222, + "test_b_norm": 0.5893194890587176, + "Rcs_pct": -2.5373997863422086e-05, + "Rhs": 1.3699370326533976e-07, + "Rf_h": 100.00029627941537 + }, + { + "bin": 3, + "ref_a": 14.974605071564724, + "ref_b": 22.65308894930779, + "test_a": 14.974599462951163, + "test_b": 22.653099758758326, + "ref_a_norm": 0.5514465790308699, + "ref_b_norm": 0.8342102076066622, + "test_a_norm": 0.5514463724911485, + "test_b_norm": 0.8342106056695487, + "Rcs_pct": 2.162298727259293e-05, + "Rhs": 3.9288339280892655e-07, + "Rf_h": 100.0002911168357 + }, + { + "bin": 4, + "ref_a": 2.7471653801214417, + "ref_b": 20.019209725029366, + "test_a": 2.7471644570696556, + "test_b": 20.019225990776174, + "ref_a_norm": 0.13595236855301812, + "ref_b_norm": 0.990715374608078, + "test_a_norm": 0.13595232287281353, + "test_b_norm": 0.9907161795711941, + "Rcs_pct": 7.805842097229671e-05, + "Rhs": 2.018429858051782e-07, + "Rf_h": 100.0003229455378 + }, + { + "bin": 5, + "ref_a": -2.887682717442889, + "ref_b": 16.38185205301735, + "test_a": -2.8876845944522067, + "test_b": 16.381868930119843, + "ref_a_norm": -0.17359688230502426, + "ref_b_norm": 0.9848167963910727, + "test_a_norm": -0.17359699514393265, + "test_b_norm": 0.984817810980507, + "Rcs_pct": 0.00010171081618901153, + "Rhs": -8.72658390641716e-08, + "Rf_h": 100.00030744192975 + }, + { + "bin": 6, + "ref_a": -10.96355041893717, + "ref_b": 16.126100687449814, + "test_a": -10.963549847340296, + "test_b": 16.126124187453886, + "ref_a_norm": -0.5622329399476821, + "ref_b_norm": 0.8269789122086404, + "test_a_norm": -0.5622329106350434, + "test_b_norm": 0.826980117336165, + "Rcs_pct": 9.857416862846627e-05, + "Rhs": -6.939055479862642e-07, + "Rf_h": 100.00027273723407 + }, + { + "bin": 7, + "ref_a": -17.882654217657382, + "ref_b": 14.441588010201274, + "test_a": -17.882640377875852, + "test_b": 14.441618505077145, + "ref_a_norm": -0.7779857137243547, + "ref_b_norm": 0.6282819663501465, + "test_a_norm": -0.7779851116240075, + "test_b_norm": 0.628283293031157, + "Rcs_pct": 2.3643633600049157e-05, + "Rhs": -1.4376039756599396e-06, + "Rf_h": 100.00022112417683 + }, + { + "bin": 8, + "ref_a": -21.392005976614175, + "ref_b": 4.89808261357095, + "test_a": -21.39200880327171, + "test_b": 4.898113459672046, + "ref_a_norm": -0.9747744880056065, + "ref_b_norm": 0.22319206422587562, + "test_a_norm": -0.9747746168085648, + "test_b_norm": 0.22319346979730428, + "Rcs_pct": 4.0054142812732e-05, + "Rhs": -1.3534355571888133e-06, + "Rf_h": 100.00022845821007 + }, + { + "bin": 9, + "ref_a": -24.04448259120652, + "ref_b": -4.271432446284247, + "test_a": -24.04447864693449, + "test_b": -4.271404700813456, + "ref_a_norm": -0.9845846737085324, + "ref_b_norm": -0.17490860555805302, + "test_a_norm": -0.984584512196644, + "test_b_norm": -0.17490746942359048, + "Rcs_pct": -3.800573209648802e-05, + "Rhs": -1.0827945510854087e-06, + "Rf_h": 100.00024320479629 + }, + { + "bin": 10, + "ref_a": -17.362087970520427, + "ref_b": -11.695208561263494, + "test_a": -17.362098911750824, + "test_b": -11.695188370755753, + "ref_a_norm": -0.8293843842134945, + "ref_b_norm": -0.5586783897939874, + "test_a_norm": -0.8293849068744584, + "test_b_norm": -0.5586774252964075, + "Rcs_pct": -1.0126943614085948e-05, + "Rhs": -1.0923253023394868e-06, + "Rf_h": 100.0002722415442 + }, + { + "bin": 11, + "ref_a": -10.41976161720632, + "ref_b": -16.120283206123606, + "test_a": -10.419780872714634, + "test_b": -16.12027188303616, + "ref_a_norm": -0.5428469040097209, + "ref_b_norm": -0.8398316729006242, + "test_a_norm": -0.5428479071797989, + "test_b_norm": -0.8398310829924105, + "Rcs_pct": 6.684068016919152e-06, + "Rhs": -1.1618408795867454e-06, + "Rf_h": 100.00029063495619 + }, + { + "bin": 12, + "ref_a": -5.9727260083462586, + "ref_b": -21.225179949482573, + "test_a": -5.972752720377821, + "test_b": -21.22517863957172, + "ref_a_norm": -0.27087771649203884, + "ref_b_norm": -0.96261376611186, + "test_a_norm": -0.2708789279479306, + "test_b_norm": -0.9626137067042025, + "Rcs_pct": 1.780771640454548e-05, + "Rhs": -1.199767965501375e-06, + "Rf_h": 100.00026600154479 + }, + { + "bin": 13, + "ref_a": 3.8465784418849407, + "ref_b": -17.744864538653417, + "test_a": 3.846553957028152, + "test_b": -17.74487725659999, + "ref_a_norm": 0.2118510763066425, + "ref_b_norm": -0.9773019602291388, + "test_a_norm": 0.2118497277982623, + "test_b_norm": -0.9773026606725878, + "Rcs_pct": 4.2390369031038575e-05, + "Rhs": -1.4592469077839495e-06, + "Rf_h": 100.0002644956327 + }, + { + "bin": 14, + "ref_a": 10.189323990498634, + "ref_b": -13.57365392611256, + "test_a": 10.18929084225982, + "test_b": -13.57367152908736, + "ref_a_norm": 0.6003424674886698, + "ref_b_norm": -0.7997430348115672, + "test_a_norm": 0.600340514435111, + "test_b_norm": -0.799744071957244, + "Rcs_pct": -2.227033069633979e-05, + "Rhs": -2.2001119507684065e-06, + "Rf_h": 100.00019772249665 + }, + { + "bin": 15, + "ref_a": 19.43408090739905, + "ref_b": -12.736794603733204, + "test_a": 19.434059640329657, + "test_b": -12.736823757126523, + "ref_a_norm": 0.8363798224703503, + "ref_b_norm": -0.5481503375575585, + "test_a_norm": 0.8363789072046472, + "test_b_norm": -0.5481515922250699, + "Rcs_pct": -6.395969751993803e-06, + "Rhs": -1.5517122891455096e-06, + "Rf_h": 100.00020307090033 + }, + { + "bin": 16, + "ref_a": 17.391304120540077, + "ref_b": -3.8395586341276413, + "test_a": 17.391283776218074, + "test_b": -3.8395727286721635, + "ref_a_norm": 0.9764854725530274, + "ref_b_norm": -0.2155832133838135, + "test_a_norm": 0.9764843302617566, + "test_b_norm": -0.21558400476310702, + "Rcs_pct": -9.659520231364277e-05, + "Rhs": -9.990231341503479e-07, + "Rf_h": 100.00024651816383 + } + ] + } +} \ No newline at end of file diff --git a/crates/tm30/tests/golden/blackbody_4300K.json b/crates/tm30/tests/golden/blackbody_4300K.json new file mode 100644 index 0000000..dee5150 --- /dev/null +++ b/crates/tm30/tests/golden/blackbody_4300K.json @@ -0,0 +1,1183 @@ +{ + "name": "blackbody_4300K", + "source": "sd_blackbody(4300, (360, 830, 1))", + "generator": "crates/tm30/tools/golden.py (tm30.py + colour-science 0.4.7, numpy 2.5.1)", + "wavelengths": [ + 360.0, + 361.0, + 362.0, + 363.0, + 364.0, + 365.0, + 366.0, + 367.0, + 368.0, + 369.0, + 370.0, + 371.0, + 372.0, + 373.0, + 374.0, + 375.0, + 376.0, + 377.0, + 378.0, + 379.0, + 380.0, + 381.0, + 382.0, + 383.0, + 384.0, + 385.0, + 386.0, + 387.0, + 388.0, + 389.0, + 390.0, + 391.0, + 392.0, + 393.0, + 394.0, + 395.0, + 396.0, + 397.0, + 398.0, + 399.0, + 400.0, + 401.0, + 402.0, + 403.0, + 404.0, + 405.0, + 406.0, + 407.0, + 408.0, + 409.0, + 410.0, + 411.0, + 412.0, + 413.0, + 414.0, + 415.0, + 416.0, + 417.0, + 418.0, + 419.0, + 420.0, + 421.0, + 422.0, + 423.0, + 424.0, + 425.0, + 426.0, + 427.0, + 428.0, + 429.0, + 430.0, + 431.0, + 432.0, + 433.0, + 434.0, + 435.0, + 436.0, + 437.0, + 438.0, + 439.0, + 440.0, + 441.0, + 442.0, + 443.0, + 444.0, + 445.0, + 446.0, + 447.0, + 448.0, + 449.0, + 450.0, + 451.0, + 452.0, + 453.0, + 454.0, + 455.0, + 456.0, + 457.0, + 458.0, + 459.0, + 460.0, + 461.0, + 462.0, + 463.0, + 464.0, + 465.0, + 466.0, + 467.0, + 468.0, + 469.0, + 470.0, + 471.0, + 472.0, + 473.0, + 474.0, + 475.0, + 476.0, + 477.0, + 478.0, + 479.0, + 480.0, + 481.0, + 482.0, + 483.0, + 484.0, + 485.0, + 486.0, + 487.0, + 488.0, + 489.0, + 490.0, + 491.0, + 492.0, + 493.0, + 494.0, + 495.0, + 496.0, + 497.0, + 498.0, + 499.0, + 500.0, + 501.0, + 502.0, + 503.0, + 504.0, + 505.0, + 506.0, + 507.0, + 508.0, + 509.0, + 510.0, + 511.0, + 512.0, + 513.0, + 514.0, + 515.0, + 516.0, + 517.0, + 518.0, + 519.0, + 520.0, + 521.0, + 522.0, + 523.0, + 524.0, + 525.0, + 526.0, + 527.0, + 528.0, + 529.0, + 530.0, + 531.0, + 532.0, + 533.0, + 534.0, + 535.0, + 536.0, + 537.0, + 538.0, + 539.0, + 540.0, + 541.0, + 542.0, + 543.0, + 544.0, + 545.0, + 546.0, + 547.0, + 548.0, + 549.0, + 550.0, + 551.0, + 552.0, + 553.0, + 554.0, + 555.0, + 556.0, + 557.0, + 558.0, + 559.0, + 560.0, + 561.0, + 562.0, + 563.0, + 564.0, + 565.0, + 566.0, + 567.0, + 568.0, + 569.0, + 570.0, + 571.0, + 572.0, + 573.0, + 574.0, + 575.0, + 576.0, + 577.0, + 578.0, + 579.0, + 580.0, + 581.0, + 582.0, + 583.0, + 584.0, + 585.0, + 586.0, + 587.0, + 588.0, + 589.0, + 590.0, + 591.0, + 592.0, + 593.0, + 594.0, + 595.0, + 596.0, + 597.0, + 598.0, + 599.0, + 600.0, + 601.0, + 602.0, + 603.0, + 604.0, + 605.0, + 606.0, + 607.0, + 608.0, + 609.0, + 610.0, + 611.0, + 612.0, + 613.0, + 614.0, + 615.0, + 616.0, + 617.0, + 618.0, + 619.0, + 620.0, + 621.0, + 622.0, + 623.0, + 624.0, + 625.0, + 626.0, + 627.0, + 628.0, + 629.0, + 630.0, + 631.0, + 632.0, + 633.0, + 634.0, + 635.0, + 636.0, + 637.0, + 638.0, + 639.0, + 640.0, + 641.0, + 642.0, + 643.0, + 644.0, + 645.0, + 646.0, + 647.0, + 648.0, + 649.0, + 650.0, + 651.0, + 652.0, + 653.0, + 654.0, + 655.0, + 656.0, + 657.0, + 658.0, + 659.0, + 660.0, + 661.0, + 662.0, + 663.0, + 664.0, + 665.0, + 666.0, + 667.0, + 668.0, + 669.0, + 670.0, + 671.0, + 672.0, + 673.0, + 674.0, + 675.0, + 676.0, + 677.0, + 678.0, + 679.0, + 680.0, + 681.0, + 682.0, + 683.0, + 684.0, + 685.0, + 686.0, + 687.0, + 688.0, + 689.0, + 690.0, + 691.0, + 692.0, + 693.0, + 694.0, + 695.0, + 696.0, + 697.0, + 698.0, + 699.0, + 700.0, + 701.0, + 702.0, + 703.0, + 704.0, + 705.0, + 706.0, + 707.0, + 708.0, + 709.0, + 710.0, + 711.0, + 712.0, + 713.0, + 714.0, + 715.0, + 716.0, + 717.0, + 718.0, + 719.0, + 720.0, + 721.0, + 722.0, + 723.0, + 724.0, + 725.0, + 726.0, + 727.0, + 728.0, + 729.0, + 730.0, + 731.0, + 732.0, + 733.0, + 734.0, + 735.0, + 736.0, + 737.0, + 738.0, + 739.0, + 740.0, + 741.0, + 742.0, + 743.0, + 744.0, + 745.0, + 746.0, + 747.0, + 748.0, + 749.0, + 750.0, + 751.0, + 752.0, + 753.0, + 754.0, + 755.0, + 756.0, + 757.0, + 758.0, + 759.0, + 760.0, + 761.0, + 762.0, + 763.0, + 764.0, + 765.0, + 766.0, + 767.0, + 768.0, + 769.0, + 770.0, + 771.0, + 772.0, + 773.0, + 774.0, + 775.0, + 776.0, + 777.0, + 778.0, + 779.0, + 780.0, + 781.0, + 782.0, + 783.0, + 784.0, + 785.0, + 786.0, + 787.0, + 788.0, + 789.0, + 790.0, + 791.0, + 792.0, + 793.0, + 794.0, + 795.0, + 796.0, + 797.0, + 798.0, + 799.0, + 800.0, + 801.0, + 802.0, + 803.0, + 804.0, + 805.0, + 806.0, + 807.0, + 808.0, + 809.0, + 810.0, + 811.0, + 812.0, + 813.0, + 814.0, + 815.0, + 816.0, + 817.0, + 818.0, + 819.0, + 820.0, + 821.0, + 822.0, + 823.0, + 824.0, + 825.0, + 826.0, + 827.0, + 828.0, + 829.0, + 830.0 + ], + "values": [ + 1810.8092576881004, + 1832.449055176484, + 1854.1549261114017, + 1875.9249286892439, + 1897.757120375705, + 1919.649558385579, + 1941.6003001550707, + 1963.6074038065462, + 1985.6689286056717, + 2007.7829354109265, + 2029.9474871154132, + 2052.1606490809645, + 2074.4204895645157, + 2096.725080136696, + 2119.0724960926714, + 2141.4608168551813, + 2163.888126369768, + 2186.3525134922324, + 2208.8520723682705, + 2231.384902805325, + 2253.949110636677, + 2276.542808077726, + 2299.16411407456, + 2321.811154644771, + 2344.4820632105666, + 2367.1749809242415, + 2389.8880569859407, + 2412.619448953869, + 2435.3673230469067, + 2458.1298544396536, + 2480.905227550079, + 2503.691636319618, + 2526.4872844859374, + 2549.2903858483637, + 2572.099164525954, + 2594.911855208412, + 2617.726703399774, + 2640.541965654986, + 2663.3559098094306, + 2686.166815201438, + 2708.9729728879124, + 2731.7726858530486, + 2754.564269210276, + 2777.3460503974716, + 2800.1163693655244, + 2822.8735787603077, + 2845.6160440981803, + 2868.342143934973, + 2891.050270028715, + 2913.7388274960226, + 2936.406234962261, + 2959.0509247056743, + 2981.671342795359, + 3004.265949223358, + 3026.833218030806, + 3049.371637428326, + 3071.8797099106396, + 3094.3559523656177, + 3116.7988961776937, + 3139.2070873258303, + 3161.5790864761298, + 3183.913469069062, + 3206.20882540153, + 3228.463760703758, + 3250.6768952111347, + 3272.8468642310645, + 3294.972318204941, + 3317.0519227653112, + 3339.084358788291, + 3361.0683224413733, + 3383.0025252266487, + 3404.885694019556, + 3426.7165711032335, + 3448.4939141985706, + 3470.21649649002, + 3491.88310664725, + 3513.492548842758, + 3535.0436427654377, + 3556.535223630321, + 3577.9661421844166, + 3599.335264708839, + 3620.641473017265, + 3641.8836644507587, + 3663.06075186916, + 3684.1716636389447, + 3705.215343617792, + 3726.1907511358268, + 3747.096860973669, + 3767.932663337332, + 3788.69716383008, + 3809.3893834212745, + 3830.0083584122967, + 3850.5531403996647, + 3871.022796235321, + 3891.416407984244, + 3911.733072879441, + 3931.971903274318, + 3952.1320265926174, + 3972.21258527586, + 3992.2127367284684, + 4012.1316532605506, + 4031.968522028476, + 4051.7225449732678, + 4071.3929387568764, + 4090.978934696416, + 4110.479778696427, + 4129.894731179134, + 4149.223067012984, + 4168.464075439234, + 4187.617059996836, + 4206.68133844569, + 4225.656242688155, + 4244.541118689054, + 4263.335326394123, + 4282.038239647013, + 4300.649246104826, + 4319.167747152306, + 4337.593157814752, + 4355.924906669587, + 4374.162435756773, + 4392.305200488064, + 4410.35266955505, + 4428.304324836243, + 4446.159661303083, + 4463.918186924929, + 4481.579422573199, + 4499.142901924518, + 4516.608171363132, + 4533.974789882384, + 4551.242328985544, + 4568.410372585854, + 4585.478516905878, + 4602.446370376268, + 4619.313553533843, + 4636.079698919175, + 4652.744450973609, + 4669.307465935752, + 4685.768411737606, + 4702.126967900143, + 4718.3828254286, + 4734.535686707384, + 4750.585265394581, + 4766.531286316325, + 4782.373485360741, + 4798.111609371751, + 4813.7454160427105, + 4829.27467380975, + 4844.699161745104, + 4860.0186694502445, + 4875.232996948957, + 4890.341954580377, + 4905.345362891922, + 4920.24305253231, + 4935.034864144503, + 4949.720648258758, + 4964.300265185722, + 4978.77358490957, + 4993.140486981348, + 5007.40086041234, + 5021.554603567674, + 5035.601624060033, + 5049.541838643617, + 5063.375173108303, + 5077.101562173995, + 5090.7209493853, + 5104.233287006395, + 5117.638535916229, + 5130.936665504065, + 5144.127653565214, + 5157.211486197283, + 5170.188157696593, + 5183.057670455121, + 5195.8200348577375, + 5208.475269179837, + 5221.02339948545, + 5233.4644595257, + 5245.798490637727, + 5258.02554164411, + 5270.145668752639, + 5282.158935456707, + 5294.065412436022, + 5305.865177457968, + 5317.558315279391, + 5329.144917548882, + 5340.625082709679, + 5351.998915902993, + 5363.2665288719445, + 5374.428039866089, + 5385.483573546376, + 5396.433260890835, + 5407.277239100706, + 5418.0156515072595, + 5428.648647479123, + 5439.176382330258, + 5449.599017228549, + 5459.916719104945, + 5470.129660563298, + 5480.238019790747, + 5490.241980468782, + 5500.141731684933, + 5509.937467845068, + 5519.629388586388, + 5529.217698690988, + 5538.702608000135, + 5548.084331329199, + 5557.363088383181, + 5566.539103672983, + 5575.612606432256, + 5584.583830534982, + 5593.453014413712, + 5602.220400978429, + 5610.886237536148, + 5619.450775711149, + 5627.914271365879, + 5636.276984522584, + 5644.539179285573, + 5652.701123764163, + 5660.763089996335, + 5668.725353873037, + 5676.5881950632265, + 5684.351896939495, + 5692.0167465045, + 5699.583034317968, + 5707.051054424463, + 5714.421104281782, + 5721.693484690053, + 5728.868499721562, + 5735.94645665114, + 5742.927665887382, + 5749.812440904391, + 5756.601098174352, + 5763.2939571006755, + 5769.891339951822, + 5776.393571795885, + 5782.800980435751, + 5789.11389634496, + 5795.3326526043, + 5801.457584838927, + 5807.489031156319, + 5813.4273320847615, + 5819.272830512526, + 5825.025871627787, + 5830.686802859059, + 5836.255973816403, + 5841.733736233222, + 5847.120443908706, + 5852.416452650981, + 5857.622120220814, + 5862.7378062760345, + 5867.763872316515, + 5872.70068162989, + 5877.5485992378035, + 5882.307991842822, + 5886.979227776021, + 5891.562676945093, + 5896.058710783176, + 5900.467702198214, + 5904.790025522973, + 5909.026056465671, + 5913.1761720611685, + 5917.24075062282, + 5921.2201716948575, + 5925.114816005405, + 5928.9250654201, + 5932.651302896245, + 5936.2939124376, + 5939.853279049703, + 5943.329788695794, + 5946.723828253336, + 5950.035785471008, + 5953.266048926376, + 5956.415007984038, + 5959.483052754376, + 5962.47057405283, + 5965.377963359698, + 5968.2056127805745, + 5970.95391500719, + 5973.623263278885, + 5976.214051344603, + 5978.726673425347, + 5981.16152417726, + 5983.518998655103, + 5985.7994922763555, + 5988.00340078578, + 5990.131120220452, + 5992.183046875398, + 5994.159577269597, + 5996.061108112598, + 5997.888036271535, + 5999.640758738686, + 6001.319672599498, + 6002.925175001044, + 6004.457663121044, + 6005.9175341372475, + 6007.305185197366, + 6008.621013389435, + 6009.865415712595, + 6011.038789048404, + 6012.141530132528, + 6013.174035526869, + 6014.136701592246, + 6015.029924461323, + 6015.854100012164, + 6016.609623842055, + 6017.296891241859, + 6017.916297170726, + 6018.468236231256, + 6018.953102645039, + 6019.3712902286225, + 6019.723192369881, + 6020.00920200479, + 6020.229711594554, + 6020.3851131032, + 6020.475797975476, + 6020.5021571151865, + 6020.464580863889, + 6020.363458979952, + 6020.199180618024, + 6019.9721343088195, + 6019.682707939307, + 6019.331288733237, + 6018.918263232003, + 6018.4440172759405, + 6017.908935985858, + 6017.313403744986, + 6016.657804181262, + 6015.942520149916, + 6015.167933716426, + 6014.334426139775, + 6013.442377856076, + 6012.492168462439, + 6011.48417670125, + 6010.418780444716, + 6009.296356679676, + 6008.117281492865, + 6006.881930056276, + 6005.59067661302, + 6004.243894463357, + 6002.8419559510485, + 6001.3852324500485, + 5999.874094351408, + 5998.308911050505, + 5996.690050934585, + 5995.017881370461, + 5993.292768692673, + 5991.515078191696, + 5989.685174102634, + 5987.803419593988, + 5985.870176756824, + 5983.885806594119, + 5981.850669010391, + 5979.765122801569, + 5977.629525645127, + 5975.444234090426, + 5973.209603549341, + 5970.92598828711, + 5968.593741413392, + 5966.213214873615, + 5963.78475944047, + 5961.3087247057365, + 5958.785459072226, + 5956.215309746027, + 5953.598622728919, + 5950.93574281101, + 5948.227013563632, + 5945.47277733235, + 5942.67337523029, + 5939.829147131571, + 5936.940431665008, + 5934.007566207983, + 5931.030886880503, + 5928.010728539475, + 5924.947424773159, + 5921.841307895803, + 5918.69270894248, + 5915.501957664073, + 5912.269382522492, + 5908.995310686021, + 5905.680068024865, + 5902.323979106864, + 5898.927367193361, + 5895.490554235281, + 5892.013860869321, + 5888.497606414341, + 5884.942108867893, + 5881.347684902926, + 5877.714649864648, + 5874.043317767497, + 5870.334001292345, + 5866.587011783777, + 5862.8026592475235, + 5858.9812523481205, + 5855.12309840659, + 5851.228503398349, + 5847.297771951218, + 5843.331207343585, + 5839.329111502695, + 5835.291785003045, + 5831.219527064981, + 5827.112635553341, + 5822.971406976262, + 5818.7961364841285, + 5814.587117868603, + 5810.344643561815, + 5806.06900463562, + 5801.760490801047, + 5797.419390407783, + 5793.045990443813, + 5788.640576535176, + 5784.203432945808, + 5779.734842577498, + 5775.235086969952, + 5770.704446300966, + 5766.143199386702, + 5761.551623682036, + 5756.929995281054, + 5752.278588917605, + 5747.597677965934, + 5742.887534441499, + 5738.148429001764, + 5733.380630947153, + 5728.584408222081, + 5723.760027416049, + 5718.907753764869, + 5714.027851151917, + 5709.1205821095355, + 5704.186207820435, + 5699.2249881192465, + 5694.2371814941325, + 5689.223045088443, + 5684.182834702505, + 5679.116804795423, + 5674.025208486991, + 5668.908297559687, + 5663.766322460678, + 5658.599532303986, + 5653.408174872613, + 5648.192496620825, + 5642.952742676458, + 5637.689156843272, + 5632.401981603426, + 5627.0914581199295, + 5621.75782623924, + 5616.401324493855, + 5611.022190104996, + 5605.620658985342, + 5600.196965741794, + 5594.75134367835, + 5589.284024798956, + 5583.795239810473, + 5578.285218125674, + 5572.754187866276, + 5567.2023758660325, + 5561.630007673867, + 5556.03730755708, + 5550.42449850456, + 5544.791802230059, + 5539.139439175523, + 5533.467628514445, + 5527.776588155244, + 5522.06653474476, + 5516.337683671684, + 5510.590249070107, + 5504.824443823052, + 5499.040479566097, + 5493.238566690993, + 5487.418914349302, + 5481.581730456139, + 5475.727221693883, + 5469.855593515927, + 5463.9670501504825 + ], + "expected": { + "Rf": 99.03620440608341, + "Rg": 100.30350300096443, + "CCT_K": 4299.73725258116, + "Duv": 8.413244817936664e-06, + "bins": [ + { + "bin": 1, + "ref_a": 21.408086968795132, + "ref_b": 4.866281711007158, + "test_a": 21.352384413643417, + "test_b": 4.837736265576641, + "ref_a_norm": 0.9751249073815587, + "ref_b_norm": 0.22165607369099238, + "test_a_norm": 0.9725876910010196, + "test_b_norm": 0.22035584659119728, + "Rcs_pct": -0.27421262028238147, + "Rhs": -0.0007802572399564611, + "Rf_h": 99.33389260503162 + }, + { + "bin": 2, + "ref_a": 20.633588191119767, + "ref_b": 14.251259734187265, + "test_a": 20.528144857330826, + "test_b": 14.2970472525139, + "ref_a_norm": 0.8228174942845975, + "ref_b_norm": 0.5683057021526499, + "test_a_norm": 0.818612669661095, + "test_b_norm": 0.5701315974235096, + "Rcs_pct": -0.248177083840289, + "Rhs": 0.0038542518288526163, + "Rf_h": 99.16579238070047 + }, + { + "bin": 3, + "ref_a": 14.628579084638053, + "ref_b": 22.245173331571426, + "test_a": 14.4703918278608, + "test_b": 22.35982585654582, + "ref_a_norm": 0.5494486330652576, + "ref_b_norm": 0.8355274978256071, + "test_a_norm": 0.5435071283229496, + "test_b_norm": 0.8398338404143288, + "Rcs_pct": 0.027966982851533626, + "Rhs": 0.0073326564000590014, + "Rf_h": 98.66161065881694 + }, + { + "bin": 4, + "ref_a": 3.864717742127668, + "ref_b": 22.102267426518083, + "test_a": 3.726445232143026, + "test_b": 22.254804645351214, + "ref_a_norm": 0.17224285589001287, + "ref_b_norm": 0.9850545155446232, + "test_a_norm": 0.16608032253053312, + "test_b_norm": 0.9918527988745913, + "Rcs_pct": 0.5465405604507331, + "Rhs": 0.007370401292971966, + "Rf_h": 98.57621583848461 + }, + { + "bin": 5, + "ref_a": -2.176307217477011, + "ref_b": 19.14793061783907, + "test_a": -2.2961605561376173, + "test_b": 19.31395124368825, + "ref_a_norm": -0.11293048769020256, + "ref_b_norm": 0.9936028909730754, + "test_a_norm": -0.11914978240996757, + "test_b_norm": 1.0022178466618756, + "Rcs_pct": 0.9662745940493582, + "Rhs": 0.004419098236152333, + "Rf_h": 98.60117977698458 + }, + { + "bin": 6, + "ref_a": -11.08566002070759, + "ref_b": 17.259634533317517, + "test_a": -11.155515968731576, + "test_b": 17.389571667011612, + "ref_a_norm": -0.5404188384771377, + "ref_b_norm": 0.8413961486832593, + "test_a_norm": -0.5438242712814384, + "test_b_norm": 0.8477305008765291, + "Rcs_pct": 0.7158778458943699, + "Rhs": -0.0006876636305288321, + "Rf_h": 98.9991276712021 + }, + { + "bin": 7, + "ref_a": -18.171418102713538, + "ref_b": 11.395922646799296, + "test_a": -18.209598192458913, + "test_b": 11.5442686809867, + "ref_a_norm": -0.8471845926612653, + "ref_b_norm": 0.5312986598490214, + "test_a_norm": -0.8489646179513044, + "test_b_norm": 0.5382148220239044, + "Rcs_pct": 0.5322450768898671, + "Rhs": -0.0047616496170036215, + "Rf_h": 98.94059335342342 + }, + { + "bin": 8, + "ref_a": -22.68619540404993, + "ref_b": 3.767797906803832, + "test_a": -22.703101886623692, + "test_b": 3.9086560508269743, + "ref_a_norm": -0.9864870886279402, + "ref_b_norm": 0.16383901846132484, + "test_a_norm": -0.9872222505392297, + "test_b_norm": 0.16996409752073022, + "Rcs_pct": 0.19159796273795704, + "Rhs": -0.005863964408763387, + "Rf_h": 99.00399158797327 + }, + { + "bin": 9, + "ref_a": -19.340286831287113, + "ref_b": -1.982758423005599, + "test_a": -19.35598485012031, + "test_b": -1.830183814384454, + "ref_a_norm": -0.9947859311905495, + "ref_b_norm": -0.10198505334288592, + "test_a_norm": -0.9955933736250416, + "test_b_norm": -0.09413723415399551, + "Rcs_pct": -0.07391059181621672, + "Rhs": -0.00785454974828428, + "Rf_h": 98.94007162903895 + }, + { + "bin": 10, + "ref_a": -18.653288881374742, + "ref_b": -10.837409208320604, + "test_a": -18.66265235915438, + "test_b": -10.717289721094188, + "ref_a_norm": -0.8646587382680907, + "ref_b_norm": -0.5023596981612214, + "test_a_norm": -0.8650927750180831, + "test_b_norm": -0.4967916524976864, + "Rcs_pct": -0.2732552058512623, + "Rhs": -0.0048707986674746415, + "Rf_h": 99.12400383934165 + }, + { + "bin": 11, + "ref_a": -12.595288529402438, + "ref_b": -18.27775138233712, + "test_a": -12.578385945625136, + "test_b": -18.21298967997079, + "ref_a_norm": -0.5674258695398969, + "ref_b_norm": -0.8234244850481992, + "test_a_norm": -0.5666643972421471, + "test_b_norm": -0.8205069285990305, + "Rcs_pct": -0.28489108715599404, + "Rhs": -0.0009877664401232837, + "Rf_h": 99.30647109043656 + }, + { + "bin": 12, + "ref_a": -5.564945884671567, + "ref_b": -23.654026008910638, + "test_a": -5.491195834378208, + "test_b": -23.674443979709235, + "ref_a_norm": -0.22901175360324266, + "ref_b_norm": -0.9734236573617715, + "test_a_norm": -0.22597675044309848, + "test_b_norm": -0.9742639090721227, + "Rcs_pct": 0.023200676551349216, + "Rhs": 0.0031406114021936943, + "Rf_h": 99.38949742052675 + }, + { + "bin": 13, + "ref_a": 3.4515419882439695, + "ref_b": -15.400246212322173, + "test_a": 3.4806511565146594, + "test_b": -15.427352077249301, + "ref_a_norm": 0.21869713816524208, + "ref_b_norm": -0.9757927862811515, + "test_a_norm": 0.2205415577947449, + "test_b_norm": -0.9775102722938517, + "Rcs_pct": 0.20443134200073676, + "Rhs": 0.0014739147242272598, + "Rf_h": 99.41631768933979 + }, + { + "bin": 14, + "ref_a": 13.73215374858763, + "ref_b": -18.736006911494158, + "test_a": 13.778470344026179, + "test_b": -18.810314687261275, + "ref_a_norm": 0.5911513176314295, + "ref_b_norm": -0.8065606732680591, + "test_a_norm": 0.5931451866867127, + "test_b_norm": -0.8097595261471648, + "Rcs_pct": 0.37674832588571966, + "Rhs": -0.0001193459090618278, + "Rf_h": 99.33396427504786 + }, + { + "bin": 15, + "ref_a": 15.184265247200255, + "ref_b": -11.192603236371296, + "test_a": 15.169372302614612, + "test_b": -11.219229212748935, + "ref_a_norm": 0.804949564955456, + "ref_b_norm": -0.593343237829523, + "test_a_norm": 0.8041600589062693, + "test_b_norm": -0.5947547363612448, + "Rcs_pct": 0.012773627954767936, + "Rhs": -0.0016122441966532103, + "Rf_h": 99.33039104029581 + }, + { + "bin": 16, + "ref_a": 19.960424228482765, + "ref_b": -3.763864025325927, + "test_a": 19.9113957759769, + "test_b": -3.7465961406160453, + "ref_a_norm": 0.9826818632806648, + "ref_b_norm": -0.18530071661826045, + "test_a_norm": 0.9802681184368311, + "test_b_norm": -0.18445059254637783, + "Rcs_pct": -0.253321639241843, + "Rhs": 0.0003628909173706643, + "Rf_h": 99.16151750592961 + } + ] + } +} \ No newline at end of file diff --git a/crates/tm30/tests/golden/blackbody_4700K.json b/crates/tm30/tests/golden/blackbody_4700K.json new file mode 100644 index 0000000..0c7f08d --- /dev/null +++ b/crates/tm30/tests/golden/blackbody_4700K.json @@ -0,0 +1,1183 @@ +{ + "name": "blackbody_4700K", + "source": "sd_blackbody(4700, (360, 830, 1))", + "generator": "crates/tm30/tools/golden.py (tm30.py + colour-science 0.4.7, numpy 2.5.1)", + "wavelengths": [ + 360.0, + 361.0, + 362.0, + 363.0, + 364.0, + 365.0, + 366.0, + 367.0, + 368.0, + 369.0, + 370.0, + 371.0, + 372.0, + 373.0, + 374.0, + 375.0, + 376.0, + 377.0, + 378.0, + 379.0, + 380.0, + 381.0, + 382.0, + 383.0, + 384.0, + 385.0, + 386.0, + 387.0, + 388.0, + 389.0, + 390.0, + 391.0, + 392.0, + 393.0, + 394.0, + 395.0, + 396.0, + 397.0, + 398.0, + 399.0, + 400.0, + 401.0, + 402.0, + 403.0, + 404.0, + 405.0, + 406.0, + 407.0, + 408.0, + 409.0, + 410.0, + 411.0, + 412.0, + 413.0, + 414.0, + 415.0, + 416.0, + 417.0, + 418.0, + 419.0, + 420.0, + 421.0, + 422.0, + 423.0, + 424.0, + 425.0, + 426.0, + 427.0, + 428.0, + 429.0, + 430.0, + 431.0, + 432.0, + 433.0, + 434.0, + 435.0, + 436.0, + 437.0, + 438.0, + 439.0, + 440.0, + 441.0, + 442.0, + 443.0, + 444.0, + 445.0, + 446.0, + 447.0, + 448.0, + 449.0, + 450.0, + 451.0, + 452.0, + 453.0, + 454.0, + 455.0, + 456.0, + 457.0, + 458.0, + 459.0, + 460.0, + 461.0, + 462.0, + 463.0, + 464.0, + 465.0, + 466.0, + 467.0, + 468.0, + 469.0, + 470.0, + 471.0, + 472.0, + 473.0, + 474.0, + 475.0, + 476.0, + 477.0, + 478.0, + 479.0, + 480.0, + 481.0, + 482.0, + 483.0, + 484.0, + 485.0, + 486.0, + 487.0, + 488.0, + 489.0, + 490.0, + 491.0, + 492.0, + 493.0, + 494.0, + 495.0, + 496.0, + 497.0, + 498.0, + 499.0, + 500.0, + 501.0, + 502.0, + 503.0, + 504.0, + 505.0, + 506.0, + 507.0, + 508.0, + 509.0, + 510.0, + 511.0, + 512.0, + 513.0, + 514.0, + 515.0, + 516.0, + 517.0, + 518.0, + 519.0, + 520.0, + 521.0, + 522.0, + 523.0, + 524.0, + 525.0, + 526.0, + 527.0, + 528.0, + 529.0, + 530.0, + 531.0, + 532.0, + 533.0, + 534.0, + 535.0, + 536.0, + 537.0, + 538.0, + 539.0, + 540.0, + 541.0, + 542.0, + 543.0, + 544.0, + 545.0, + 546.0, + 547.0, + 548.0, + 549.0, + 550.0, + 551.0, + 552.0, + 553.0, + 554.0, + 555.0, + 556.0, + 557.0, + 558.0, + 559.0, + 560.0, + 561.0, + 562.0, + 563.0, + 564.0, + 565.0, + 566.0, + 567.0, + 568.0, + 569.0, + 570.0, + 571.0, + 572.0, + 573.0, + 574.0, + 575.0, + 576.0, + 577.0, + 578.0, + 579.0, + 580.0, + 581.0, + 582.0, + 583.0, + 584.0, + 585.0, + 586.0, + 587.0, + 588.0, + 589.0, + 590.0, + 591.0, + 592.0, + 593.0, + 594.0, + 595.0, + 596.0, + 597.0, + 598.0, + 599.0, + 600.0, + 601.0, + 602.0, + 603.0, + 604.0, + 605.0, + 606.0, + 607.0, + 608.0, + 609.0, + 610.0, + 611.0, + 612.0, + 613.0, + 614.0, + 615.0, + 616.0, + 617.0, + 618.0, + 619.0, + 620.0, + 621.0, + 622.0, + 623.0, + 624.0, + 625.0, + 626.0, + 627.0, + 628.0, + 629.0, + 630.0, + 631.0, + 632.0, + 633.0, + 634.0, + 635.0, + 636.0, + 637.0, + 638.0, + 639.0, + 640.0, + 641.0, + 642.0, + 643.0, + 644.0, + 645.0, + 646.0, + 647.0, + 648.0, + 649.0, + 650.0, + 651.0, + 652.0, + 653.0, + 654.0, + 655.0, + 656.0, + 657.0, + 658.0, + 659.0, + 660.0, + 661.0, + 662.0, + 663.0, + 664.0, + 665.0, + 666.0, + 667.0, + 668.0, + 669.0, + 670.0, + 671.0, + 672.0, + 673.0, + 674.0, + 675.0, + 676.0, + 677.0, + 678.0, + 679.0, + 680.0, + 681.0, + 682.0, + 683.0, + 684.0, + 685.0, + 686.0, + 687.0, + 688.0, + 689.0, + 690.0, + 691.0, + 692.0, + 693.0, + 694.0, + 695.0, + 696.0, + 697.0, + 698.0, + 699.0, + 700.0, + 701.0, + 702.0, + 703.0, + 704.0, + 705.0, + 706.0, + 707.0, + 708.0, + 709.0, + 710.0, + 711.0, + 712.0, + 713.0, + 714.0, + 715.0, + 716.0, + 717.0, + 718.0, + 719.0, + 720.0, + 721.0, + 722.0, + 723.0, + 724.0, + 725.0, + 726.0, + 727.0, + 728.0, + 729.0, + 730.0, + 731.0, + 732.0, + 733.0, + 734.0, + 735.0, + 736.0, + 737.0, + 738.0, + 739.0, + 740.0, + 741.0, + 742.0, + 743.0, + 744.0, + 745.0, + 746.0, + 747.0, + 748.0, + 749.0, + 750.0, + 751.0, + 752.0, + 753.0, + 754.0, + 755.0, + 756.0, + 757.0, + 758.0, + 759.0, + 760.0, + 761.0, + 762.0, + 763.0, + 764.0, + 765.0, + 766.0, + 767.0, + 768.0, + 769.0, + 770.0, + 771.0, + 772.0, + 773.0, + 774.0, + 775.0, + 776.0, + 777.0, + 778.0, + 779.0, + 780.0, + 781.0, + 782.0, + 783.0, + 784.0, + 785.0, + 786.0, + 787.0, + 788.0, + 789.0, + 790.0, + 791.0, + 792.0, + 793.0, + 794.0, + 795.0, + 796.0, + 797.0, + 798.0, + 799.0, + 800.0, + 801.0, + 802.0, + 803.0, + 804.0, + 805.0, + 806.0, + 807.0, + 808.0, + 809.0, + 810.0, + 811.0, + 812.0, + 813.0, + 814.0, + 815.0, + 816.0, + 817.0, + 818.0, + 819.0, + 820.0, + 821.0, + 822.0, + 823.0, + 824.0, + 825.0, + 826.0, + 827.0, + 828.0, + 829.0, + 830.0 + ], + "values": [ + 3994.4753181019855, + 4033.372862158385, + 4072.2757941601776, + 4111.180553927585, + 4150.083606233975, + 4188.9814413521835, + 4227.870575582345, + 4266.747551761526, + 4305.608939755205, + 4344.451336930883, + 4383.271368614032, + 4422.065688526575, + 4460.830979208135, + 4499.5639524202115, + 4538.261349533585, + 4576.919941899113, + 4615.536531202204, + 4654.1079498011195, + 4692.631061049398, + 4731.102759602654, + 4769.519971709848, + 4807.879655489533, + 4846.1788011909475, + 4884.41443144058, + 4922.583601474158, + 4960.683399354433, + 4998.710946174991, + 5036.6633962503065, + 5074.537937292298, + 5112.3317905736185, + 5150.042211077956, + 5187.666487637508, + 5225.201943057983, + 5262.64593423127, + 5299.995852236089, + 5337.249122426792, + 5374.4032045106305, + 5411.455592613694, + 5448.403815335696, + 5485.2454357939905, + 5521.978051656884, + 5558.599295166597, + 5595.106833152064, + 5631.49836703179, + 5667.771632807, + 5703.9244010453385, + 5739.954476855292, + 5775.859699851614, + 5811.637944111896, + 5847.287118124603, + 5882.805164728681, + 5918.190061045075, + 5953.439818400211, + 5988.552482241841, + 6023.526132047281, + 6058.358881224367, + 6093.048877005286, + 6127.594300333462, + 6161.993365743766, + 6196.24432123614, + 6230.345448142943, + 6264.295060990124, + 6298.091507352458, + 6331.733167702968, + 6365.218455256831, + 6398.545815809798, + 6431.713727571461, + 6464.720700993425, + 6497.565278592554, + 6530.246034769605, + 6562.761575623222, + 6595.110538759615, + 6627.291593097987, + 6659.303438671865, + 6691.144806426586, + 6722.814458013044, + 6754.311185577736, + 6785.633811549445, + 6816.781188422611, + 6847.752198537465, + 6878.5457538572755, + 6909.160795742537, + 6939.5962947225435, + 6969.851250264305, + 6999.924690538938, + 7029.815672185761, + 7059.5232800741305, + 7089.046627063097, + 7118.384853759208, + 7147.5371282723245, + 7176.502645969723, + 7205.280629228518, + 7233.870327186631, + 7262.271015492209, + 7290.4819960518635, + 7318.50259677757, + 7346.332171332495, + 7373.970098875856, + 7401.415783806755, + 7428.668655507288, + 7455.728168084872, + 7482.593800113893, + 7509.26505437686, + 7535.741457605108, + 7562.022560218976, + 7588.107936067847, + 7613.997182169821, + 7639.689918451368, + 7665.185787486824, + 7690.484454237862, + 7715.5856057931305, + 7740.488951107922, + 7765.194220744191, + 7789.7011666106855, + 7814.009561703552, + 7838.119199847225, + 7862.029895435899, + 7885.741483175435, + 7909.253817825868, + 7932.566773944544, + 7955.680245629971, + 7978.594146266368, + 8001.3084082690475, + 8023.822982830581, + 8046.137839667893, + 8068.252966770314, + 8090.16837014848, + 8111.884073584448, + 8133.400118382693, + 8154.7165631223215, + 8175.833483410348, + 8196.7509716362, + 8217.46913672742, + 8237.988103906597, + 8258.308014449605, + 8278.42902544514, + 8298.3513095556, + 8318.075054779349, + 8337.60046421435, + 8356.927755823293, + 8376.057162200088, + 8394.988930337926, + 8413.723321398795, + 8432.260610484504, + 8450.601086409328, + 8468.745051474141, + 8486.692821242217, + 8504.444724316525, + 8522.001102118813, + 8539.362308670172, + 8556.528710373374, + 8573.500685796827, + 8590.278625460222, + 8606.86293162191, + 8623.254018067939, + 8639.4523099029, + 8655.458243342426, + 8671.272265507509, + 8686.89483422047, + 8702.32641780284, + 8717.567494874862, + 8732.618554156914, + 8747.480094272578, + 8762.152623553626, + 8776.636659846725, + 8790.932730321962, + 8805.0413712832, + 8818.963127980194, + 8832.698554422584, + 8846.248213195611, + 8859.612675277762, + 8872.792519860137, + 8885.78833416768, + 8898.600713282194, + 8911.230259967217, + 8923.677584494688, + 8935.943304473398, + 8948.02804467932, + 8959.93243688771, + 8971.65711970698, + 8983.202738414451, + 8994.569944793851, + 9005.759396974636, + 9016.771759273079, + 9027.607702035159, + 9038.267901481253, + 9048.753039552585, + 9059.063803759424, + 9069.200887031075, + 9079.164987567645, + 9088.956808693516, + 9098.577058712597, + 9108.026450765305, + 9117.305702687268, + 9126.415536869757, + 9135.356680121866, + 9144.129863534276, + 9152.735822344937, + 9161.175295806179, + 9169.449027053732, + 9177.557762977258, + 9185.502254092637, + 9193.283254415846, + 9200.901521338536, + 9208.357815505195, + 9215.652900691968, + 9222.787543687036, + 9229.762514172713, + 9236.578584608962, + 9243.236530118666, + 9249.737128374347, + 9256.081159486499, + 9262.269405893487, + 9268.302652252918, + 9274.181685334603, + 9279.907293915003, + 9285.480268673175, + 9290.901402088233, + 9296.1714883383, + 9301.291323200836, + 9306.261703954591, + 9311.08342928282, + 9315.757299178085, + 9320.284114848384, + 9324.664678624737, + 9328.899793870136, + 9332.990264889919, + 9336.9368968435, + 9340.740495657472, + 9344.401867940029, + 9347.921820896754, + 9351.30116224775, + 9354.540700146068, + 9357.641243097376, + 9360.603599881068, + 9363.428579472487, + 9366.116990966528, + 9368.669643502417, + 9371.0873461898, + 9373.370908036026, + 9375.521137874659, + 9377.538844295155, + 9379.424835573798, + 9381.179919605771, + 9382.804903838438, + 9384.300595205706, + 9385.667800063638, + 9386.907324127113, + 9388.01997240763, + 9389.006549152264, + 9389.867857783685, + 9390.60470084122, + 9391.217879923082, + 9391.708195629632, + 9392.076447507587, + 9392.323433995467, + 9392.449952369878, + 9392.45679869293, + 9392.344767760625, + 9392.114653052198, + 9391.767246680527, + 9391.303339343449, + 9390.723720276057, + 9390.029177203909, + 9389.220496297254, + 9388.298462126128, + 9387.263857616339, + 9386.117464006444, + 9384.860060805539, + 9383.492425751992, + 9382.015334772957, + 9380.429561944904, + 9378.73587945481, + 9376.935057562378, + 9375.027864562928, + 9373.015066751223, + 9370.89742838604, + 9368.67571165556, + 9366.350676643546, + 9363.92308129632, + 9361.393681390431, + 9358.763230501243, + 9356.032479972078, + 9353.20217888424, + 9350.273074027698, + 9347.245909872545, + 9344.121428541086, + 9340.900369780731, + 9337.583470937476, + 9334.171466930167, + 9330.665090225333, + 9327.0650708128, + 9323.372136181833, + 9319.587011298045, + 9315.710418580848, + 9311.74307788159, + 9307.685706462311, + 9303.539018975056, + 9299.303727441864, + 9294.980541235298, + 9290.570167059568, + 9286.073308932275, + 9281.490668166642, + 9276.822943354418, + 9272.070830349197, + 9267.235022250432, + 9262.316209387836, + 9257.315079306438, + 9252.2323167521, + 9247.06860365751, + 9241.82461912878, + 9236.50103943247, + 9231.098537983109, + 9225.617785331206, + 9220.059449151766, + 9214.424194233197, + 9208.712682466816, + 9202.925572836632, + 9197.063521409706, + 9191.12718132693, + 9185.11720279419, + 9179.034233074013, + 9172.87891647759, + 9166.651894357205, + 9160.353805099154, + 9153.98528411696, + 9147.546963845041, + 9141.039473732739, + 9134.463440238747, + 9127.819486825909, + 9121.10823395636, + 9114.330299087092, + 9107.48629666579, + 9100.576838127066, + 9093.602531889086, + 9086.56398335042, + 9079.46179488732, + 9072.296565851271, + 9065.06889256693, + 9057.779368330263, + 9050.428583407134, + 9043.017125032096, + 9035.545577407518, + 9028.014521702982, + 9020.424536055054, + 9012.776195567172, + 9005.07007231002, + 8997.306735322003, + 8989.48675061008, + 8981.61068115082, + 8973.679086891778, + 8965.692524753009, + 8957.651548629, + 8949.55670939065, + 8941.408554887661, + 8933.207629951059, + 8924.954476395993, + 8916.649633024754, + 8908.29363562998, + 8899.887016998131, + 8891.430306913155, + 8882.924032160368, + 8874.36871653049, + 8865.764880823981, + 8857.113042855488, + 8848.413717458501, + 8839.66741649026, + 8830.87464883673, + 8822.035920417897, + 8813.151734193108, + 8804.222590166677, + 8795.24898539361, + 8786.231413985563, + 8777.170367116842, + 8768.066333030676, + 8758.919797045628, + 8749.731241562087, + 8740.50114606897, + 8731.229987150567, + 8721.918238493517, + 8712.566370893903, + 8703.17485226451, + 8693.744147642235, + 8684.274719195546, + 8674.767026232154, + 8665.221525206773, + 8655.63866972896, + 8646.01891057119, + 8636.362695676886, + 8626.670470168685, + 8616.942676356766, + 8607.179753747288, + 8597.382139050895, + 8587.550266191422, + 8577.684566314574, + 8567.785467796784, + 8557.853396254131, + 8547.888774551386, + 8537.892022811051, + 8527.863558422609, + 8517.803796051752, + 8507.713147649778, + 8497.59202246295, + 8487.440827042066, + 8477.259965251995, + 8467.049838281342, + 8456.810844652147, + 8446.543380229708, + 8436.247838232362, + 8425.924609241463, + 8415.574081211293, + 8405.196639479129, + 8394.792666775307, + 8384.36254323337, + 8373.90664640024, + 8363.425351246475, + 8352.91903017656, + 8342.388053039205, + 8331.832787137784, + 8321.253597240699, + 8310.65084559188, + 8300.024891921263, + 8289.376093455348, + 8278.704804927775, + 8268.011378589908, + 8257.296164221509, + 8246.559509141396, + 8235.801758218146, + 8225.023253880827, + 8214.224336129759, + 8203.40534254729, + 8192.566608308603, + 8181.708466192553, + 8170.831246592503, + 8159.935277527188, + 8149.020884651614, + 8138.088391267955, + 8127.138118336463, + 8116.17038448641, + 8105.185506027003, + 8094.183796958383, + 8083.165568982551, + 8072.131131514354, + 8061.080791692475, + 8050.014854390406, + 8038.933622227448, + 8027.837395579702, + 8016.7264725910845, + 8005.6011491843, + 7994.4617190718745, + 7983.308473767147, + 7972.141702595261, + 7960.961692704186, + 7949.768729075681, + 7938.563094536341, + 7927.345069768518, + 7916.1149333213525, + 7904.872961621733, + 7893.619428985255, + 7882.354607627193, + 7871.078767673438, + 7859.792177171457, + 7848.495102101192, + 7837.187806385987, + 7825.870551903507, + 7814.5435984966125, + 7803.207203984228, + 7791.86162417222, + 7780.5071128642485, + 7769.1439218725545, + 7757.772301028813 + ], + "expected": { + "Rf": 97.85713419915655, + "Rg": 100.82858876198473, + "CCT_K": 4699.577192342564, + "Duv": 1.0209239388541723e-05, + "bins": [ + { + "bin": 1, + "ref_a": 23.636511777397562, + "ref_b": 5.11248976124546, + "test_a": 23.567249473242605, + "test_b": 5.045147099079162, + "ref_a_norm": 0.9773979967859405, + "ref_b_norm": 0.2114075587078915, + "test_a_norm": 0.9745339177724471, + "test_b_norm": 0.2086228591837209, + "Rcs_pct": -0.33523144652347314, + "Rhs": -0.002172438206630345, + "Rf_h": 98.64840824331739 + }, + { + "bin": 2, + "ref_a": 17.910026772338078, + "ref_b": 12.152531412399055, + "test_a": 17.74424666568894, + "test_b": 12.257607518435167, + "ref_a_norm": 0.8274908233861066, + "ref_b_norm": 0.5614792402322488, + "test_a_norm": 0.8198313419852185, + "test_b_norm": 0.5663340355157668, + "Rcs_pct": -0.36714462839084133, + "Rhs": 0.00829199461889564, + "Rf_h": 98.49869730695885 + }, + { + "bin": 3, + "ref_a": 14.595569662545534, + "ref_b": 22.141342876092185, + "test_a": 14.294334659053385, + "test_b": 22.39254678362233, + "ref_a_norm": 0.5503767650675445, + "ref_b_norm": 0.8349164128664527, + "test_a_norm": 0.5390176505841565, + "test_b_norm": 0.8443889307054484, + "Rcs_pct": 0.15653248546864956, + "Rhs": 0.014707407458696026, + "Rf_h": 97.29631566106711 + }, + { + "bin": 4, + "ref_a": 3.9964918011412065, + "ref_b": 22.04620696054027, + "test_a": 3.702258641443747, + "test_b": 22.38367180648311, + "ref_a_norm": 0.17837088146453714, + "ref_b_norm": 0.9839633268804098, + "test_a_norm": 0.16523870688173298, + "test_b_norm": 0.9990250122357832, + "Rcs_pct": 1.2210319126483908, + "Rhs": 0.015818232576585163, + "Rf_h": 96.90566262895729 + }, + { + "bin": 5, + "ref_a": -2.1064401334271814, + "ref_b": 19.163995326946214, + "test_a": -2.3822454353474463, + "test_b": 19.53569095425031, + "ref_a_norm": -0.10925851406340632, + "ref_b_norm": 0.9940133686750176, + "test_a_norm": -0.12356420306943047, + "test_b_norm": 1.0132927734293493, + "Rcs_pct": 2.169985787283246, + "Rhs": 0.010269583921332962, + "Rf_h": 96.83507982795172 + }, + { + "bin": 6, + "ref_a": -10.943401478568706, + "ref_b": 17.412356936989106, + "test_a": -11.139257935942283, + "test_b": 17.693899492456335, + "ref_a_norm": -0.5321189638491584, + "ref_b_norm": 0.8466695980794977, + "test_a_norm": -0.5416424136983569, + "test_b_norm": 0.8603595036530124, + "Rcs_pct": 1.6673685731538421, + "Rhs": 0.00031275512440196053, + "Rf_h": 97.66262242443501 + }, + { + "bin": 7, + "ref_a": -18.01823851185505, + "ref_b": 11.64726730413398, + "test_a": -18.16475582778679, + "test_b": 11.97210158275622, + "ref_a_norm": -0.8398165170440574, + "ref_b_norm": 0.5428703507284117, + "test_a_norm": -0.8466455787124041, + "test_b_norm": 0.55801063163376, + "Rcs_pct": 1.408964664833705, + "Rhs": -0.008794660112132858, + "Rf_h": 97.53615614160695 + }, + { + "bin": 8, + "ref_a": -22.447083292068804, + "ref_b": 4.09523833880642, + "test_a": -22.54582135953215, + "test_b": 4.403938458806165, + "ref_a_norm": -0.9837621273077827, + "ref_b_norm": 0.17947723219078815, + "test_a_norm": -0.9880894053790643, + "test_b_norm": 0.19300627214665708, + "Rcs_pct": 0.6883515398084273, + "Rhs": -0.012424873174323723, + "Rf_h": 97.71768806427482 + }, + { + "bin": 9, + "ref_a": -18.684391870849687, + "ref_b": -2.70639532164565, + "test_a": -18.76428054770934, + "test_b": -2.3552392199130034, + "ref_a_norm": -0.9896717803132417, + "ref_b_norm": -0.14335190006281295, + "test_a_norm": -0.9939033105445205, + "test_b_norm": -0.1247519217080557, + "Rcs_pct": 0.05215467976970182, + "Rhs": -0.01906811558160578, + "Rf_h": 97.50824591487402 + }, + { + "bin": 10, + "ref_a": -19.745529279198088, + "ref_b": -12.154806827573443, + "test_a": -19.81560645281825, + "test_b": -11.882912533975192, + "ref_a_norm": -0.8515868538458209, + "ref_b_norm": -0.5242135350760951, + "test_a_norm": -0.8546091481062472, + "test_b_norm": -0.5124872550260641, + "Rcs_pct": -0.4001826302867961, + "Rhs": -0.011429142253469384, + "Rf_h": 97.99932569190598 + }, + { + "bin": 11, + "ref_a": -12.844328002762472, + "ref_b": -18.147287737120998, + "test_a": -12.838347060565257, + "test_b": -17.97444814421491, + "ref_a_norm": -0.5777177679725868, + "ref_b_norm": -0.8162365959504465, + "test_a_norm": -0.5774487545546948, + "test_b_norm": -0.8084625416122577, + "Rcs_pct": -0.6613345793856353, + "Rhs": -0.004095356697895776, + "Rf_h": 98.37362100529862 + }, + { + "bin": 12, + "ref_a": -5.924072849386776, + "ref_b": -23.61902063164395, + "test_a": -5.754377598823854, + "test_b": -23.647184280482975, + "ref_a_norm": -0.24328220176997464, + "ref_b_norm": -0.9699555506836142, + "test_a_norm": -0.2363133755525306, + "test_b_norm": -0.9711121391783258, + "Rcs_pct": -0.022518557973863765, + "Rhs": 0.007060561397630704, + "Rf_h": 98.6302299157896 + }, + { + "bin": 13, + "ref_a": 3.0174775756376824, + "ref_b": -15.506088153187207, + "test_a": 3.12297671064751, + "test_b": -15.542463205614874, + "ref_a_norm": 0.1910163476321541, + "ref_b_norm": -0.9815868555238869, + "test_a_norm": 0.19769479310284502, + "test_b_norm": -0.9838895170965061, + "Rcs_pct": 0.3561316653619326, + "Rhs": 0.006100894025932805, + "Rf_h": 98.57596175439592 + }, + { + "bin": 14, + "ref_a": 13.156721747077988, + "ref_b": -19.023096977238726, + "test_a": 13.328097103343847, + "test_b": -19.14567986310402, + "ref_a_norm": 0.5688266206218099, + "ref_b_norm": -0.8224574613145483, + "test_a_norm": 0.5762359788674699, + "test_b_norm": -0.8277572928419811, + "Rcs_pct": 0.852306775245044, + "Rhs": 0.0032162275912691464, + "Rf_h": 98.39373975761568 + }, + { + "bin": 15, + "ref_a": 12.204643861372968, + "ref_b": -9.441198494524327, + "test_a": 12.156476929769664, + "test_b": -9.283531961967205, + "ref_a_norm": 0.790960751969857, + "ref_b_norm": -0.6118668881736276, + "test_a_norm": 0.7878391408131719, + "test_b_norm": -0.6016488072063856, + "Rcs_pct": -0.827238644219208, + "Rhs": 0.006761749582592546, + "Rf_h": 97.57094518197265 + }, + { + "bin": 16, + "ref_a": 22.614543436554076, + "ref_b": -4.589432224559074, + "test_a": 22.603736206129227, + "test_b": -4.634598824608815, + "ref_a_norm": 0.9800223615794847, + "ref_b_norm": -0.19888733193486582, + "test_a_norm": 0.9795540201551793, + "test_b_norm": -0.2008446687331721, + "Rcs_pct": -0.00774849088863125, + "Rhs": -0.0020110959998516265, + "Rf_h": 98.94951159842492 + } + ] + } +} \ No newline at end of file diff --git a/crates/tm30/tests/golden/daylight_10000K.json b/crates/tm30/tests/golden/daylight_10000K.json new file mode 100644 index 0000000..47e127e --- /dev/null +++ b/crates/tm30/tests/golden/daylight_10000K.json @@ -0,0 +1,455 @@ +{ + "name": "daylight_10000K", + "source": "sd_CIE_illuminant_D_series(CCT_to_xy_CIE_D(10000*1.4388/1.4380))", + "generator": "crates/tm30/tools/golden.py (tm30.py + colour-science 0.4.7, numpy 2.5.1)", + "wavelengths": [ + 300.0, + 305.0, + 310.0, + 315.0, + 320.0, + 325.0, + 330.0, + 335.0, + 340.0, + 345.0, + 350.0, + 355.0, + 360.0, + 365.0, + 370.0, + 375.0, + 380.0, + 385.0, + 390.0, + 395.0, + 400.0, + 405.0, + 410.0, + 415.0, + 420.0, + 425.0, + 430.0, + 435.0, + 440.0, + 445.0, + 450.0, + 455.0, + 460.0, + 465.0, + 470.0, + 475.0, + 480.0, + 485.0, + 490.0, + 495.0, + 500.0, + 505.0, + 510.0, + 515.0, + 520.0, + 525.0, + 530.0, + 535.0, + 540.0, + 545.0, + 550.0, + 555.0, + 560.0, + 565.0, + 570.0, + 575.0, + 580.0, + 585.0, + 590.0, + 595.0, + 600.0, + 605.0, + 610.0, + 615.0, + 620.0, + 625.0, + 630.0, + 635.0, + 640.0, + 645.0, + 650.0, + 655.0, + 660.0, + 665.0, + 670.0, + 675.0, + 680.0, + 685.0, + 690.0, + 695.0, + 700.0, + 705.0, + 710.0, + 715.0, + 720.0, + 725.0, + 730.0, + 735.0, + 740.0, + 745.0, + 750.0, + 755.0, + 760.0, + 765.0, + 770.0, + 775.0, + 780.0, + 785.0, + 790.0, + 795.0, + 800.0, + 805.0, + 810.0, + 815.0, + 820.0, + 825.0, + 830.0 + ], + "values": [ + 0.06008, + 4.92104, + 9.782, + 30.199800000000003, + 50.6176, + 72.4788, + 94.33999999999999, + 94.76599999999999, + 95.192, + 98.1464, + 101.1008, + 99.40119999999999, + 97.7016, + 103.41320000000002, + 109.1248, + 105.03739999999999, + 100.95, + 100.72419999999998, + 100.4984, + 119.6384, + 138.7784, + 145.1238, + 151.4692, + 150.8512, + 150.2332, + 142.3616, + 134.49, + 143.09679999999997, + 151.7036, + 157.2072, + 162.7108, + 160.9858, + 159.2608, + 154.7646, + 150.26839999999999, + 148.4612, + 146.654, + 140.4984, + 134.34279999999998, + 132.12980000000002, + 129.9168, + 127.22399999999999, + 124.53119999999998, + 120.0536, + 115.576, + 115.4342, + 115.29239999999999, + 112.49659999999999, + 109.7008, + 108.0594, + 106.418, + 103.209, + 100.0, + 97.16, + 94.32000000000001, + 92.861, + 91.402, + 88.1076, + 84.8132, + 84.1562, + 83.4992, + 82.53080000000001, + 81.5624, + 79.79919999999998, + 78.036, + 75.3106, + 72.5852, + 72.138, + 71.6908, + 70.08080000000001, + 68.4708, + 67.929, + 67.38719999999999, + 67.31240000000001, + 67.23760000000001, + 65.56479999999999, + 63.892, + 60.34479999999999, + 56.7976, + 57.105799999999995, + 57.413999999999994, + 58.8672, + 60.32040000000001, + 55.201, + 50.081599999999995, + 53.669200000000004, + 57.256800000000005, + 59.532, + 61.807199999999995, + 57.1504, + 52.4936, + 45.2244, + 37.9552, + 46.2936, + 54.632, + 53.343999999999994, + 52.056, + 52.4188, + 52.7816, + 50.843799999999995, + 48.906000000000006, + 45.9244, + 42.94279999999999, + 45.1304, + 47.318, + 48.4934, + 49.6688 + ], + "expected": { + "Rf": 99.99210779924667, + "Rg": 100.00186042541752, + "CCT_K": 10001.55264159118, + "Duv": 0.00305309456192554, + "bins": [ + { + "bin": 1, + "ref_a": 22.18838088403679, + "ref_b": 4.799264696646001, + "test_a": 22.188520710286628, + "test_b": 4.798446827645167, + "ref_a_norm": 0.9773979943072114, + "ref_b_norm": 0.21140757016776976, + "test_a_norm": 0.9774041536523596, + "test_b_norm": 0.21137154304505182, + "Rcs_pct": -9.875479140922549e-05, + "Rhs": -3.65365002854078e-05, + "Rf_h": 99.99314185101497 + }, + { + "bin": 2, + "ref_a": 21.90994680755508, + "ref_b": 13.492408657268621, + "test_a": 21.909653927911684, + "test_b": 13.492212320307129, + "ref_a_norm": 0.8514958325226968, + "ref_b_norm": 0.524361370808796, + "test_a_norm": 0.8514844502131926, + "test_b_norm": 0.5243537404797062, + "Rcs_pct": -0.0013703228180926522, + "Rhs": -2.0714426495737255e-08, + "Rf_h": 99.99620041852005 + }, + { + "bin": 3, + "ref_a": 12.787207145707102, + "ref_b": 19.296561081623867, + "test_a": 12.786917468422585, + "test_b": 19.296815372213008, + "ref_a_norm": 0.5523902498110285, + "ref_b_norm": 0.8335856356210258, + "test_a_norm": 0.55237773613969, + "test_b_norm": 0.8335966206344427, + "Rcs_pct": 0.00021814815453883758, + "Rhs": 1.650768392004511e-05, + "Rf_h": 99.99449203157278 + }, + { + "bin": 4, + "ref_a": 4.845979263670448, + "ref_b": 21.4548724836471, + "test_a": 4.845963979167345, + "test_b": 21.45494383353854, + "ref_a_norm": 0.22031843244807647, + "ref_b_norm": 0.9754280026345472, + "test_a_norm": 0.22031773755080575, + "test_b_norm": 0.9754312464982499, + "Rcs_pct": 0.0003045966038851729, + "Rhs": 1.3143914288665618e-06, + "Rf_h": 99.99342815569689 + }, + { + "bin": 5, + "ref_a": -1.9771713361437273, + "ref_b": 22.099668211917926, + "test_a": -1.9775837629732882, + "test_b": 22.10084386693833, + "ref_a_norm": -0.0891101930608291, + "ref_b_norm": 0.9960217736037007, + "test_a_norm": -0.08912878094632683, + "test_b_norm": 0.9960747598289843, + "Rcs_pct": 0.005559442638961152, + "Rhs": 7.893624737003795e-06, + "Rf_h": 99.98788014288363 + }, + { + "bin": 6, + "ref_a": -10.933143884607434, + "ref_b": 17.459252297941575, + "test_a": -10.933662599603819, + "test_b": 17.459837284710108, + "ref_a_norm": -0.530735686571021, + "ref_b_norm": 0.8475373920954679, + "test_a_norm": -0.5307608669365816, + "test_b_norm": 0.8475657895406593, + "Rcs_pct": 0.003760107430568532, + "Rhs": 5.159933548185024e-06, + "Rf_h": 99.99414432231491 + }, + { + "bin": 7, + "ref_a": -18.458653808432654, + "ref_b": 11.06047032852331, + "test_a": -18.459589860385137, + "test_b": 11.061053885283826, + "ref_a_norm": -0.8577946072914588, + "ref_b_norm": 0.5139926183338551, + "test_a_norm": -0.8578381066888319, + "test_b_norm": 0.5140197368793034, + "Rcs_pct": 0.005123468368302473, + "Rhs": 1.6187238646207667e-06, + "Rf_h": 99.99266475432061 + }, + { + "bin": 8, + "ref_a": -19.359818172583513, + "ref_b": 2.95690071064537, + "test_a": -19.36023911467728, + "test_b": 2.958306038150122, + "ref_a_norm": -0.9885363559636104, + "ref_b_norm": 0.15098302201964936, + "test_a_norm": -0.9885578497896235, + "test_b_norm": 0.15105477978710866, + "Rcs_pct": 0.003508007413392976, + "Rhs": -6.61857246404508e-05, + "Rf_h": 99.98993698744763 + }, + { + "bin": 9, + "ref_a": -17.34756228260965, + "ref_b": -4.0906645168098015, + "test_a": -17.348117812857765, + "test_b": -4.089429972734792, + "ref_a_norm": -0.9733059099746574, + "ref_b_norm": -0.22951166769557554, + "test_a_norm": -0.9733370786694199, + "test_b_norm": -0.22944240211089248, + "Rcs_pct": 0.0017056751811937037, + "Rhs": -7.401537659369243e-05, + "Rf_h": 99.99014828881192 + }, + { + "bin": 10, + "ref_a": -15.247579240244248, + "ref_b": -10.538936071737847, + "test_a": -15.248699801029943, + "test_b": -10.537044406837277, + "ref_a_norm": -0.8226232185175713, + "ref_b_norm": -0.5685868802177835, + "test_a_norm": -0.8226836739712239, + "test_b_norm": -0.56848482287187, + "Rcs_pct": -0.0006433150840366035, + "Rhs": -0.0001184448323123706, + "Rf_h": 99.98539300539889 + }, + { + "bin": 11, + "ref_a": -15.449477144532276, + "ref_b": -23.900159103111296, + "test_a": -15.450474632886824, + "test_b": -23.89840749058577, + "ref_a_norm": -0.5428714818687844, + "ref_b_norm": -0.8398157858563925, + "test_a_norm": -0.5429065321152177, + "test_b_norm": -0.8397542368163509, + "Rcs_pct": -0.0031703282882718188, + "Rhs": -6.333802933100343e-05, + "Rf_h": 99.98672712794286 + }, + { + "bin": 12, + "ref_a": -2.421484236018484, + "ref_b": -18.821977395974585, + "test_a": -2.421948161530651, + "test_b": -18.821848069451377, + "ref_a_norm": -0.12760031395796165, + "ref_b_norm": -0.9918256701042929, + "test_a_norm": -0.12762476055155295, + "test_b_norm": -0.9918188552323566, + "Rcs_pct": -0.0001914632267107102, + "Rhs": -2.5306374710897864e-05, + "Rf_h": 99.99524427837768 + }, + { + "bin": 13, + "ref_a": 3.2763903513870067, + "ref_b": -16.80036188663644, + "test_a": 3.2761280392280767, + "test_b": -16.800162845884355, + "ref_a_norm": 0.19141304936640335, + "ref_b_norm": -0.9815095743456886, + "test_a_norm": 0.19139772458368767, + "test_b_norm": -0.9814979460007056, + "Rcs_pct": -0.0014394626389645422, + "Rhs": -1.2761743745637245e-05, + "Rf_h": 99.99550495618061 + }, + { + "bin": 14, + "ref_a": 13.452165680845233, + "ref_b": -15.995505897616043, + "test_a": 13.451770491729658, + "test_b": -15.995843390143026, + "ref_a_norm": 0.6436391555120018, + "ref_b_norm": -0.7653291040407371, + "test_a_norm": 0.6436202470927441, + "test_b_norm": -0.7653452518796956, + "Rcs_pct": 0.00029214825054357135, + "Rhs": -2.4693034682405967e-05, + "Rf_h": 99.99310443491726 + }, + { + "bin": 15, + "ref_a": 13.41601592408982, + "ref_b": -7.809342321264181, + "test_a": 13.415642030323333, + "test_b": -7.809097749759966, + "ref_a_norm": 0.8642458256858581, + "ref_b_norm": -0.5030697295450893, + "test_a_norm": 0.8642217398373645, + "test_b_norm": -0.5030539745025495, + "Rcs_pct": -0.0028779683764082646, + "Rhs": -2.815413476524658e-07, + "Rf_h": 99.99700722994918 + }, + { + "bin": 16, + "ref_a": 25.331243453732935, + "ref_b": -3.6577874837770095, + "test_a": 25.33120087985063, + "test_b": -3.6585851285175033, + "ref_a_norm": 0.9897348234650585, + "ref_b_norm": -0.1429159865815921, + "test_a_norm": 0.9897331600309691, + "test_b_norm": -0.1429471519200747, + "Rcs_pct": 0.00044485842505622347, + "Rhs": -3.0891025134651155e-05, + "Rf_h": 99.99422981302662 + } + ] + } +} \ No newline at end of file diff --git a/crates/tm30/tests/golden/daylight_6500K.json b/crates/tm30/tests/golden/daylight_6500K.json new file mode 100644 index 0000000..8bdbb5e --- /dev/null +++ b/crates/tm30/tests/golden/daylight_6500K.json @@ -0,0 +1,455 @@ +{ + "name": "daylight_6500K", + "source": "sd_CIE_illuminant_D_series(CCT_to_xy_CIE_D(6500*1.4388/1.4380))", + "generator": "crates/tm30/tools/golden.py (tm30.py + colour-science 0.4.7, numpy 2.5.1)", + "wavelengths": [ + 300.0, + 305.0, + 310.0, + 315.0, + 320.0, + 325.0, + 330.0, + 335.0, + 340.0, + 345.0, + 350.0, + 355.0, + 360.0, + 365.0, + 370.0, + 375.0, + 380.0, + 385.0, + 390.0, + 395.0, + 400.0, + 405.0, + 410.0, + 415.0, + 420.0, + 425.0, + 430.0, + 435.0, + 440.0, + 445.0, + 450.0, + 455.0, + 460.0, + 465.0, + 470.0, + 475.0, + 480.0, + 485.0, + 490.0, + 495.0, + 500.0, + 505.0, + 510.0, + 515.0, + 520.0, + 525.0, + 530.0, + 535.0, + 540.0, + 545.0, + 550.0, + 555.0, + 560.0, + 565.0, + 570.0, + 575.0, + 580.0, + 585.0, + 590.0, + 595.0, + 600.0, + 605.0, + 610.0, + 615.0, + 620.0, + 625.0, + 630.0, + 635.0, + 640.0, + 645.0, + 650.0, + 655.0, + 660.0, + 665.0, + 670.0, + 675.0, + 680.0, + 685.0, + 690.0, + 695.0, + 700.0, + 705.0, + 710.0, + 715.0, + 720.0, + 725.0, + 730.0, + 735.0, + 740.0, + 745.0, + 750.0, + 755.0, + 760.0, + 765.0, + 770.0, + 775.0, + 780.0, + 785.0, + 790.0, + 795.0, + 800.0, + 805.0, + 810.0, + 815.0, + 820.0, + 825.0, + 830.0 + ], + "values": [ + 0.0341, + 1.6643, + 3.2945, + 11.765250000000002, + 20.236, + 28.644750000000002, + 37.0535, + 38.50115, + 39.94879999999999, + 42.43025, + 44.911699999999996, + 45.775, + 46.6383, + 49.3637, + 52.0891, + 51.0323, + 49.9755, + 52.31184999999999, + 54.648199999999996, + 68.70154999999998, + 82.7549, + 87.12044999999999, + 91.48599999999999, + 92.45889999999999, + 93.4318, + 90.05704999999999, + 86.6823, + 95.7736, + 104.8649, + 110.93625, + 117.0076, + 117.4099, + 117.81219999999999, + 116.33655, + 114.8609, + 115.39189999999999, + 115.9229, + 112.3668, + 108.8107, + 109.0826, + 109.3545, + 108.5781, + 107.8017, + 106.29575, + 104.7898, + 106.23965000000001, + 107.6895, + 106.0475, + 104.40549999999999, + 104.22585, + 104.0462, + 102.02310000000001, + 100.0, + 98.1671, + 96.3342, + 96.0611, + 95.788, + 92.23679999999999, + 88.6856, + 89.3459, + 90.00619999999999, + 89.80265000000001, + 89.59909999999999, + 88.6489, + 87.69870000000002, + 85.49365, + 83.2886, + 83.4939, + 83.6992, + 81.86300000000001, + 80.0268, + 80.1207, + 80.2146, + 81.24619999999999, + 82.2778, + 80.28099999999999, + 78.2842, + 74.00274999999999, + 69.72130000000001, + 70.6652, + 71.6091, + 72.97904999999999, + 74.349, + 67.9765, + 61.60399999999999, + 65.7448, + 69.8856, + 72.48629999999999, + 75.087, + 69.33985, + 63.5927, + 55.00545, + 46.418200000000006, + 56.6118, + 66.80539999999999, + 65.0941, + 63.382799999999996, + 63.843399999999995, + 64.304, + 61.87794999999999, + 59.4519, + 55.70545, + 51.959, + 54.699799999999996, + 57.440599999999996, + 58.87655, + 60.3125 + ], + "expected": { + "Rf": 99.9924786737848, + "Rg": 100.0011835231251, + "CCT_K": 6501.833595790215, + "Duv": 0.0032142511335876423, + "bins": [ + { + "bin": 1, + "ref_a": 23.82098448657007, + "ref_b": 4.87679865972495, + "test_a": 23.821154453326805, + "test_b": 4.876499299682636, + "ref_a_norm": 0.9796799988941125, + "ref_b_norm": 0.20056694584809243, + "test_a_norm": 0.9796869890767452, + "test_b_norm": 0.20055463413838584, + "Rcs_pct": 0.00044539728222520874, + "Rhs": -1.343886063756478e-05, + "Rf_h": 99.99604941483143 + }, + { + "bin": 2, + "ref_a": 18.62450560525995, + "ref_b": 11.890753671989799, + "test_a": 18.6241452089483, + "test_b": 11.891080814566378, + "ref_a_norm": 0.8428653239676316, + "ref_b_norm": 0.538124563324273, + "test_a_norm": 0.8428490139747429, + "test_b_norm": 0.5381393683955934, + "Rcs_pct": -0.0005336006540544123, + "Rhs": 2.137131346054759e-05, + "Rf_h": 99.99541739381802 + }, + { + "bin": 3, + "ref_a": 13.41229488368166, + "ref_b": 20.708136922053775, + "test_a": 13.412031109030194, + "test_b": 20.70842340562642, + "ref_a_norm": 0.5436201231493497, + "ref_b_norm": 0.8393313777686892, + "test_a_norm": 0.5436094319731, + "test_b_norm": 0.8393429893710578, + "Rcs_pct": 0.00037149952394282626, + "Rhs": 1.5340448805088747e-05, + "Rf_h": 99.9944065710728 + }, + { + "bin": 4, + "ref_a": 4.497250086937527, + "ref_b": 22.85791920520157, + "test_a": 4.497498609001025, + "test_b": 22.858186643767006, + "ref_a_norm": 0.1930470793178648, + "ref_b_norm": 0.9811894950349, + "test_a_norm": 0.19305774727218733, + "test_b_norm": 0.9812009749910859, + "Rcs_pct": 0.001334058669074099, + "Rhs": -8.223344222519277e-06, + "Rf_h": 99.99476132806481 + }, + { + "bin": 5, + "ref_a": -1.5586795188179994, + "ref_b": 21.50037593581726, + "test_a": -1.5590319755016309, + "test_b": 21.501574102503596, + "ref_a_norm": -0.07230569860211343, + "ref_b_norm": 0.9973825173671635, + "test_a_norm": -0.07232204874107996, + "test_b_norm": 0.9974380992095189, + "Rcs_pct": 0.005770360671572851, + "Rhs": 5.19249610758116e-06, + "Rf_h": 99.98837914169252 + }, + { + "bin": 6, + "ref_a": -10.217046983959596, + "ref_b": 16.76273968019651, + "test_a": -10.21752051666128, + "test_b": 16.763071299032166, + "ref_a_norm": -0.5204538412781571, + "ref_b_norm": 0.8538898050092945, + "test_a_norm": -0.5204779629166255, + "test_b_norm": 0.8539066975905979, + "Rcs_pct": 0.002744693233183563, + "Rhs": 1.0671394054397755e-05, + "Rf_h": 99.99410466329093 + }, + { + "bin": 7, + "ref_a": -17.900786589543717, + "ref_b": 11.626028528186552, + "test_a": -17.901705684689993, + "test_b": 11.625888693436936, + "ref_a_norm": -0.8386465611395261, + "ref_b_norm": 0.5446760004707818, + "test_a_norm": -0.8386896204754904, + "test_b_norm": 0.5446694492540904, + "Rcs_pct": 0.003216286839649242, + "Rhs": 2.9369622917808765e-05, + "Rf_h": 99.99379414369255 + }, + { + "bin": 8, + "ref_a": -24.003468458180524, + "ref_b": 2.988107839784543, + "test_a": -24.004174105303594, + "test_b": 2.9887792076094732, + "ref_a_norm": -0.9923404654642813, + "ref_b_norm": 0.12353299398190501, + "test_a_norm": -0.9923696380063988, + "test_b_norm": 0.12356074936488434, + "Rcs_pct": 0.0034026806503831735, + "Rhs": -2.1530790442358142e-05, + "Rf_h": 99.99250082185397 + }, + { + "bin": 9, + "ref_a": -15.682829138461875, + "ref_b": -2.5913518818427894, + "test_a": -15.683488583671732, + "test_b": -2.5904694462259132, + "ref_a_norm": -0.9866220266595951, + "ref_b_norm": -0.16302446598628445, + "test_a_norm": -0.9866635129988057, + "test_b_norm": -0.1629689511037953, + "Rcs_pct": 0.0029858774534086, + "Rhs": -6.254176286453215e-05, + "Rf_h": 99.99138628893799 + }, + { + "bin": 10, + "ref_a": -17.34510818830174, + "ref_b": -10.667088018297028, + "test_a": -17.346245812857198, + "test_b": -10.66543795555791, + "ref_a_norm": -0.851807880237721, + "ref_b_norm": -0.5238543071932504, + "test_a_norm": -0.8518637482986504, + "test_b_norm": -0.5237732735998702, + "Rcs_pct": 0.0001432742604412497, + "Rhs": -9.84156021002078e-05, + "Rf_h": 99.98665763011813 + }, + { + "bin": 11, + "ref_a": -14.294616636351853, + "ref_b": -21.235090875195265, + "test_a": -14.295661031186077, + "test_b": -21.23353386698508, + "ref_a_norm": -0.5584238743718227, + "ref_b_norm": -0.8295557705974702, + "test_a_norm": -0.5584646739976216, + "test_b_norm": -0.8294949455624743, + "Rcs_pct": -0.002790711065419409, + "Rhs": -6.771622791120693e-05, + "Rf_h": 99.98773249529462 + }, + { + "bin": 12, + "ref_a": -3.7486150572267056, + "ref_b": -20.755101033422942, + "test_a": -3.7489067528403037, + "test_b": -20.754904500984047, + "ref_a_norm": -0.1777360812284449, + "ref_b_norm": -0.984078190709232, + "test_a_norm": -0.17774991162566653, + "test_b_norm": -0.9840688723596575, + "Rcs_pct": -0.0006441123452762918, + "Rhs": -1.5382569836263055e-05, + "Rf_h": 99.99737317021643 + }, + { + "bin": 13, + "ref_a": 1.903150415638521, + "ref_b": -15.820468782733457, + "test_a": 1.9030872159876644, + "test_b": -15.820181790253374, + "ref_a_norm": 0.11943562419036355, + "ref_b_norm": -0.9928419469755789, + "test_a_norm": 0.11943165798270773, + "test_b_norm": -0.9928239362467816, + "Rcs_pct": -0.0018438426422545185, + "Rhs": -3.7627920702582303e-07, + "Rf_h": 99.99488962788963 + }, + { + "bin": 14, + "ref_a": 12.608405843070699, + "ref_b": -18.774763719510062, + "test_a": 12.608193315166195, + "test_b": -18.774368795940585, + "ref_a_norm": 0.5575101679314969, + "ref_b_norm": -0.8301701106718997, + "test_a_norm": 0.5575007705128855, + "test_b_norm": -0.830152648202157, + "Rcs_pct": -0.0019740438994589617, + "Rhs": 1.8879603746129435e-06, + "Rf_h": 99.99425612441722 + }, + { + "bin": 15, + "ref_a": 12.088472495367219, + "ref_b": -8.349869751429393, + "test_a": 12.088193380397145, + "test_b": -8.348583245418363, + "ref_a_norm": 0.82279927261926, + "ref_b_norm": -0.5683320833607906, + "test_a_norm": 0.8227802747190338, + "test_b_norm": -0.5682445176066805, + "Rcs_pct": -0.006444510315110062, + "Rhs": 6.22535957654064e-05, + "Rf_h": 99.98875609879286 + }, + { + "bin": 16, + "ref_a": 22.585949520225732, + "ref_b": -3.8918436838877772, + "test_a": 22.585994282355948, + "test_b": -3.891768192820436, + "ref_a_norm": 0.985476808341529, + "ref_b_norm": -0.16981007102346227, + "test_a_norm": 0.9854787614159914, + "test_b_norm": -0.16980677717495546, + "Rcs_pct": 0.0001272948718502314, + "Rhs": 3.6115840571578373e-06, + "Rf_h": 99.99559860282885 + } + ] + } +} \ No newline at end of file diff --git a/crates/tm30/tests/golden/grid_10nm_D50.json b/crates/tm30/tests/golden/grid_10nm_D50.json new file mode 100644 index 0000000..6fce2e7 --- /dev/null +++ b/crates/tm30/tests/golden/grid_10nm_D50.json @@ -0,0 +1,323 @@ +{ + "name": "grid_10nm_D50", + "source": "D50 sampled every 10 nm", + "generator": "crates/tm30/tools/golden.py (tm30.py + colour-science 0.4.7, numpy 2.5.1)", + "wavelengths": [ + 380.0, + 390.0, + 400.0, + 410.0, + 420.0, + 430.0, + 440.0, + 450.0, + 460.0, + 470.0, + 480.0, + 490.0, + 500.0, + 510.0, + 520.0, + 530.0, + 540.0, + 550.0, + 560.0, + 570.0, + 580.0, + 590.0, + 600.0, + 610.0, + 620.0, + 630.0, + 640.0, + 650.0, + 660.0, + 670.0, + 680.0, + 690.0, + 700.0, + 710.0, + 720.0, + 730.0, + 740.0, + 750.0, + 760.0, + 770.0, + 780.0 + ], + "values": [ + 24.488, + 29.871, + 49.308, + 56.513, + 60.034, + 57.818, + 74.825, + 87.247, + 90.612, + 91.368, + 95.109, + 91.963, + 95.724, + 96.613, + 97.129, + 102.099, + 100.755, + 102.317, + 100.0, + 97.735, + 98.918, + 93.499, + 97.688, + 99.269, + 99.042, + 95.722, + 98.857, + 95.667, + 98.19, + 103.003, + 99.133, + 87.381, + 91.604, + 92.889, + 76.854, + 86.511, + 92.58, + 78.23, + 57.692, + 82.923, + 78.274 + ], + "expected": { + "Rf": 99.9832723174942, + "Rg": 99.99985232380979, + "CCT_K": 5001.064836407116, + "Duv": 0.0032066894884178465, + "bins": [ + { + "bin": 1, + "ref_a": 23.476902397290555, + "ref_b": 4.934814612361608, + "test_a": 23.47590488354907, + "test_b": 4.933441044796805, + "ref_a_norm": 0.9786143669015133, + "ref_b_norm": 0.20570347807937106, + "test_a_norm": 0.9785727864041343, + "test_b_norm": 0.20564622210368572, + "Rcs_pct": -0.0051951626515016934, + "Rhs": -4.8043865544036956e-05, + "Rf_h": 99.98392440612294 + }, + { + "bin": 2, + "ref_a": 17.83894735047625, + "ref_b": 12.025027476598268, + "test_a": 17.8373699978495, + "test_b": 12.02524225686417, + "ref_a_norm": 0.8291990350997083, + "ref_b_norm": 0.5589534508254805, + "test_a_norm": 0.8291257157916563, + "test_b_norm": 0.5589634343511755, + "Rcs_pct": -0.00554162269436133, + "Rhs": 4.903502329826525e-05, + "Rf_h": 99.98777796643758 + }, + { + "bin": 3, + "ref_a": 14.547664221552239, + "ref_b": 22.064293382121082, + "test_a": 14.546154102498923, + "test_b": 22.064844936634533, + "ref_a_norm": 0.550452873345259, + "ref_b_norm": 0.8348662373254462, + "test_a_norm": 0.5503957336313275, + "test_b_norm": 0.8348871069827404, + "Rcs_pct": -0.0014392638324301301, + "Rhs": 5.910449615570723e-05, + "Rf_h": 99.98786214138754 + }, + { + "bin": 4, + "ref_a": 4.076717109026536, + "ref_b": 21.998266602307645, + "test_a": 4.076170171524599, + "test_b": 21.999791491118437, + "ref_a_norm": 0.18221734962954564, + "ref_b_norm": 0.9832582760872058, + "test_a_norm": 0.18219290312041816, + "test_b_norm": 0.9833264341639502, + "Rcs_pct": 0.0062079161073660075, + "Rhs": 3.727375744951626e-05, + "Rf_h": 99.98559377631918 + }, + { + "bin": 5, + "ref_a": -2.054258575968485, + "ref_b": 19.16102293825853, + "test_a": -2.055199201002889, + "test_b": 19.163110889562127, + "ref_a_norm": -0.1065993982477314, + "ref_b_norm": 0.9943020508342632, + "test_a_norm": -0.1066482090760357, + "test_b_norm": 0.9944103986124532, + "Rcs_pct": 0.011578842622494784, + "Rhs": 2.6735338988320904e-05, + "Rf_h": 99.98117482025822 + }, + { + "bin": 6, + "ref_a": -10.828082553293017, + "ref_b": 17.50437009420907, + "test_a": -10.828359044187073, + "test_b": 17.505865074733812, + "ref_a_norm": -0.5260751363126394, + "ref_b_norm": 0.8504380935456959, + "test_a_norm": -0.5260885694374853, + "test_b_norm": 0.8505107261728917, + "Rcs_pct": 0.006785486667582358, + "Rhs": -2.9183290508430915e-05, + "Rf_h": 99.98808815724074 + }, + { + "bin": 7, + "ref_a": -17.88444758203982, + "ref_b": 11.801800126314143, + "test_a": -17.88495216505877, + "test_b": 11.804003956358029, + "ref_a_norm": -0.8346509266584013, + "ref_b_norm": 0.5507792939356669, + "test_a_norm": -0.8346744750896522, + "test_b_norm": 0.5508821446823781, + "Rcs_pct": 0.00767206183189115, + "Rhs": -7.243446305559115e-05, + "Rf_h": 99.98450649697875 + }, + { + "bin": 8, + "ref_a": -22.255349205247978, + "ref_b": 4.3023968277173275, + "test_a": -22.25519077423656, + "test_b": 4.304875640387898, + "ref_a_norm": -0.9818217199390649, + "ref_b_norm": 0.18980545370430352, + "test_a_norm": -0.981814730562862, + "test_b_norm": 0.18991480953139844, + "Rcs_pct": 0.0014479186223318838, + "Rhs": -0.00010861814519514624, + "Rf_h": 99.98327216874497 + }, + { + "bin": 9, + "ref_a": -18.6309347775359, + "ref_b": -2.5538984750008566, + "test_a": -18.631625430252008, + "test_b": -2.5509699724113073, + "ref_a_norm": -0.9907351240732684, + "ref_b_norm": -0.13580837208186233, + "test_a_norm": -0.9907718508351059, + "test_b_norm": -0.13565264342889619, + "Rcs_pct": 0.0005639914352866351, + "Rhs": -0.00015990140635973644, + "Rf_h": 99.9795247527471 + }, + { + "bin": 10, + "ref_a": -19.80275334617307, + "ref_b": -11.994426214565234, + "test_a": -19.80451901544621, + "test_b": -11.991335724144333, + "ref_a_norm": -0.8553364599157997, + "ref_b_norm": -0.5180729102536704, + "test_a_norm": -0.8554127241240675, + "test_b_norm": -0.5179394233041636, + "Rcs_pct": -0.001075000396151897, + "Rhs": -0.00015336046611234212, + "Rf_h": 99.97556450320567 + }, + { + "bin": 11, + "ref_a": -12.900334771940969, + "ref_b": -19.322573550217715, + "test_a": -12.902280548703203, + "test_b": -19.31981707257897, + "ref_a_norm": -0.5552548884177753, + "ref_b_norm": -0.831680232353856, + "test_a_norm": -0.5553386383419516, + "test_b_norm": -0.8315615883255587, + "Rcs_pct": -0.005211993932032823, + "Rhs": -0.00013555060743284557, + "Rf_h": 99.97751686694453 + }, + { + "bin": 12, + "ref_a": -3.128242899681709, + "ref_b": -20.746804281216868, + "test_a": -3.129532980418883, + "test_b": -20.74672351134386, + "ref_a_norm": -0.14909657211816565, + "ref_b_norm": -0.9888226393962734, + "test_a_norm": -0.14915805922828998, + "test_b_norm": -0.988818789787537, + "Rcs_pct": 0.0008219900530086618, + "Rhs": -6.10566739524769e-05, + "Rf_h": 99.99154886307903 + }, + { + "bin": 13, + "ref_a": 2.7176102058558462, + "ref_b": -15.57869260910705, + "test_a": 2.7162031381174128, + "test_b": -15.578860737296393, + "ref_a_norm": 0.17184890000570494, + "ref_b_norm": -0.9851233199791939, + "test_a_norm": 0.1717599236534075, + "test_b_norm": -0.985133951615893, + "Rcs_pct": -0.0006931072440349296, + "Rhs": -8.934082606449256e-05, + "Rf_h": 99.98800552430676 + }, + { + "bin": 14, + "ref_a": 13.613424128801427, + "ref_b": -17.947106267304473, + "test_a": 13.611480034455715, + "test_b": -17.948205812283046, + "ref_a_norm": 0.604340777156097, + "ref_b_norm": -0.7967259410025287, + "test_a_norm": 0.6042544729701232, + "test_b_norm": -0.7967747531059776, + "Rcs_pct": -0.0007362255981711318, + "Rhs": -9.887785973898523e-05, + "Rf_h": 99.9835749193685 + }, + { + "bin": 15, + "ref_a": 12.877324738057629, + "ref_b": -8.259933165250223, + "test_a": 12.875100968305514, + "test_b": -8.259239572344033, + "ref_a_norm": 0.8417235542388836, + "ref_b_norm": -0.5399087499193371, + "test_a_norm": 0.841578198008639, + "test_b_norm": -0.5398634133686118, + "Rcs_pct": -0.014604692645798237, + "Rhs": -4.30596304531343e-05, + "Rf_h": 99.97616121923275 + }, + { + "bin": 16, + "ref_a": 22.83244776608982, + "ref_b": -4.132109648046074, + "test_a": 22.83109690443548, + "test_b": -4.133074838051117, + "ref_a_norm": 0.9840155542122202, + "ref_b_norm": -0.17808253442832928, + "test_a_norm": 0.9839573357989744, + "test_b_norm": -0.1781241314567102, + "Rcs_pct": -0.004898458509821487, + "Rhs": -5.215560213193481e-05, + "Rf_h": 99.98550150831167 + } + ] + } +} \ No newline at end of file diff --git a/crates/tm30/tests/golden/hpcs_grid_LED_B3.json b/crates/tm30/tests/golden/hpcs_grid_LED_B3.json new file mode 100644 index 0000000..8d613b6 --- /dev/null +++ b/crates/tm30/tests/golden/hpcs_grid_LED_B3.json @@ -0,0 +1,941 @@ +{ + "name": "hpcs_grid_LED_B3", + "source": "LED-B3 linearly resampled on 380-1050 nm / 350 points (0 beyond 780)", + "generator": "crates/tm30/tools/golden.py (tm30.py + colour-science 0.4.7, numpy 2.5.1)", + "wavelengths": [ + 380.0, + 381.91977077363896, + 383.8395415472779, + 385.75931232091693, + 387.6790830945559, + 389.59885386819485, + 391.5186246418338, + 393.43839541547277, + 395.3581661891117, + 397.2779369627507, + 399.1977077363897, + 401.11747851002866, + 403.0372492836676, + 404.9570200573066, + 406.87679083094554, + 408.79656160458455, + 410.7163323782235, + 412.63610315186247, + 414.55587392550143, + 416.4756446991404, + 418.39541547277935, + 420.3151862464183, + 422.2349570200573, + 424.1547277936963, + 426.07449856733524, + 427.9942693409742, + 429.91404011461316, + 431.8338108882522, + 433.75358166189113, + 435.6733524355301, + 437.59312320916905, + 439.512893982808, + 441.43266475644697, + 443.3524355300859, + 445.27220630372494, + 447.1919770773639, + 449.11174785100286, + 451.0315186246418, + 452.9512893982808, + 454.8710601719198, + 456.79083094555875, + 458.7106017191977, + 460.63037249283667, + 462.55014326647563, + 464.46991404011465, + 466.38968481375355, + 468.30945558739256, + 470.2292263610315, + 472.1489971346705, + 474.06876790830944, + 475.9885386819484, + 477.9083094555874, + 479.8280802292264, + 481.74785100286533, + 483.6676217765043, + 485.58739255014325, + 487.50716332378227, + 489.42693409742117, + 491.3467048710602, + 493.26647564469914, + 495.1862464183381, + 497.10601719197706, + 499.025787965616, + 500.94555873925503, + 502.865329512894, + 504.78510028653295, + 506.7048710601719, + 508.62464183381087, + 510.5444126074499, + 512.4641833810888, + 514.3839541547278, + 516.3037249283668, + 518.2234957020057, + 520.1432664756447, + 522.0630372492836, + 523.9828080229227, + 525.9025787965616, + 527.8223495702006, + 529.7421203438396, + 531.6618911174785, + 533.5816618911175, + 535.5014326647564, + 537.4212034383954, + 539.3409742120343, + 541.2607449856733, + 543.1805157593124, + 545.1002865329513, + 547.0200573065903, + 548.9398280802293, + 550.8595988538682, + 552.7793696275071, + 554.6991404011461, + 556.6189111747851, + 558.538681948424, + 560.458452722063, + 562.3782234957021, + 564.297994269341, + 566.21776504298, + 568.1375358166189, + 570.0573065902579, + 571.9770773638968, + 573.8968481375358, + 575.8166189111748, + 577.7363896848137, + 579.6561604584527, + 581.5759312320916, + 583.4957020057307, + 585.4154727793696, + 587.3352435530086, + 589.2550143266476, + 591.1747851002865, + 593.0945558739255, + 595.0143266475645, + 596.9340974212034, + 598.8538681948423, + 600.7736389684814, + 602.6934097421204, + 604.6131805157593, + 606.5329512893983, + 608.4527220630373, + 610.3724928366762, + 612.2922636103152, + 614.2120343839541, + 616.1318051575931, + 618.051575931232, + 619.971346704871, + 621.8911174785101, + 623.810888252149, + 625.730659025788, + 627.6504297994269, + 629.5702005730659, + 631.4899713467048, + 633.4097421203438, + 635.3295128939828, + 637.2492836676217, + 639.1690544412608, + 641.0888252148998, + 643.0085959885387, + 644.9283667621776, + 646.8481375358166, + 648.7679083094556, + 650.6876790830945, + 652.6074498567335, + 654.5272206303725, + 656.4469914040114, + 658.3667621776503, + 660.2865329512895, + 662.2063037249284, + 664.1260744985673, + 666.0458452722063, + 667.9656160458453, + 669.8853868194842, + 671.8051575931232, + 673.7249283667622, + 675.6446991404011, + 677.56446991404, + 679.4842406876791, + 681.4040114613181, + 683.323782234957, + 685.243553008596, + 687.163323782235, + 689.0830945558739, + 691.0028653295128, + 692.9226361031518, + 694.8424068767908, + 696.7621776504297, + 698.6819484240688, + 700.6017191977078, + 702.5214899713467, + 704.4412607449856, + 706.3610315186247, + 708.2808022922636, + 710.2005730659025, + 712.1203438395415, + 714.0401146131805, + 715.9598853868195, + 717.8796561604585, + 719.7994269340975, + 721.7191977077364, + 723.6389684813753, + 725.5587392550143, + 727.4785100286533, + 729.3982808022922, + 731.3180515759312, + 733.2378223495703, + 735.1575931232092, + 737.077363896848, + 738.9971346704871, + 740.9169054441261, + 742.836676217765, + 744.756446991404, + 746.676217765043, + 748.5959885386819, + 750.5157593123208, + 752.43553008596, + 754.3553008595989, + 756.2750716332378, + 758.1948424068768, + 760.1146131805158, + 762.0343839541547, + 763.9541547277937, + 765.8739255014327, + 767.7936962750716, + 769.7134670487105, + 771.6332378223495, + 773.5530085959886, + 775.4727793696275, + 777.3925501432665, + 779.3123209169055, + 781.2320916905444, + 783.1518624641833, + 785.0716332378223, + 786.9914040114613, + 788.9111747851002, + 790.8309455587392, + 792.7507163323783, + 794.6704871060172, + 796.5902578796561, + 798.5100286532952, + 800.4297994269341, + 802.349570200573, + 804.269340974212, + 806.189111747851, + 808.1088825214899, + 810.028653295129, + 811.948424068768, + 813.8681948424069, + 815.7879656160458, + 817.7077363896848, + 819.6275071633238, + 821.5472779369627, + 823.4670487106017, + 825.3868194842407, + 827.3065902578796, + 829.2263610315185, + 831.1461318051576, + 833.0659025787966, + 834.9856733524355, + 836.9054441260745, + 838.8252148997135, + 840.7449856733524, + 842.6647564469913, + 844.5845272206304, + 846.5042979942693, + 848.4240687679082, + 850.3438395415473, + 852.2636103151863, + 854.1833810888252, + 856.1031518624642, + 858.0229226361032, + 859.9426934097421, + 861.862464183381, + 863.78223495702, + 865.702005730659, + 867.6217765042979, + 869.541547277937, + 871.461318051576, + 873.3810888252149, + 875.3008595988538, + 877.2206303724929, + 879.1404011461318, + 881.0601719197707, + 882.9799426934097, + 884.8997134670487, + 886.8194842406876, + 888.7392550143267, + 890.6590257879657, + 892.5787965616046, + 894.4985673352436, + 896.4183381088825, + 898.3381088825215, + 900.2578796561604, + 902.1776504297994, + 904.0974212034383, + 906.0171919770773, + 907.9369627507164, + 909.8567335243553, + 911.7765042979943, + 913.6962750716332, + 915.6160458452722, + 917.5358166189112, + 919.4555873925501, + 921.3753581661891, + 923.295128939828, + 925.214899713467, + 927.134670487106, + 929.054441260745, + 930.974212034384, + 932.8939828080229, + 934.8137535816619, + 936.7335243553008, + 938.6532951289398, + 940.5730659025788, + 942.4928366762177, + 944.4126074498568, + 946.3323782234957, + 948.2521489971347, + 950.1719197707736, + 952.0916905444126, + 954.0114613180516, + 955.9312320916905, + 957.8510028653295, + 959.7707736389684, + 961.6905444126074, + 963.6103151862465, + 965.5300859598854, + 967.4498567335244, + 969.3696275071633, + 971.2893982808023, + 973.2091690544412, + 975.1289398280802, + 977.0487106017192, + 978.9684813753581, + 980.8882521489971, + 982.808022922636, + 984.7277936962751, + 986.6475644699141, + 988.567335243553, + 990.487106017192, + 992.4068767908309, + 994.3266475644699, + 996.2464183381088, + 998.1661891117478, + 1000.0859598853868, + 1002.0057306590257, + 1003.9255014326648, + 1005.8452722063037, + 1007.7650429799427, + 1009.6848137535817, + 1011.6045845272206, + 1013.5243553008596, + 1015.4441260744985, + 1017.3638968481375, + 1019.2836676217764, + 1021.2034383954154, + 1023.1232091690545, + 1025.0429799426934, + 1026.9627507163323, + 1028.8825214899712, + 1030.8022922636103, + 1032.7220630372494, + 1034.6418338108883, + 1036.5616045845272, + 1038.4813753581661, + 1040.401146131805, + 1042.320916905444, + 1044.240687679083, + 1046.1604584527222, + 1048.080229226361, + 1050.0 + ], + "values": [ + 0.0, + 0.0, + 0.0, + 0.001518624641833867, + 0.0053581661891117845, + 0.009197707736389702, + 0.013037249283667621, + 0.016876790830945537, + 0.02214899713467037, + 0.03366762177650412, + 0.04518624641833821, + 0.06340974212034393, + 0.08644699140401144, + 0.10948424068767895, + 0.16255014326647507, + 0.21630372492836752, + 0.29441260744985775, + 0.4134383954154732, + 0.5324641833810888, + 0.7488825214899698, + 0.9946131805157565, + 1.2737535816618837, + 1.7229799426934136, + 2.1722063037249297, + 2.7718624641833802, + 3.4898567335243507, + 4.207851002865321, + 5.314613180515774, + 6.439598853868204, + 7.83527220630373, + 9.732005730659022, + 11.628739255014313, + 13.71171919770771, + 15.858022922636065, + 17.763696275071634, + 18.21292263610315, + 18.66214899713467, + 17.98495702005732, + 16.337793696275092, + 14.690630372492816, + 12.903782234957008, + 11.106876790830942, + 9.601203438395418, + 8.691232091690551, + 7.781260744985659, + 7.110315186246429, + 6.530544412607446, + 5.978280802292263, + 5.628882521489972, + 5.279484240687682, + 5.121862464183381, + 5.144899713467049, + 5.167936962750717, + 5.397220630372493, + 5.646790830945558, + 5.931604584527218, + 6.2963610315186305, + 6.661117478510022, + 7.06896848137536, + 7.495157593123209, + 7.9194842406876775, + 8.326475644699137, + 8.733467048710596, + 9.106418338108886, + 9.444297994269343, + 9.7821776504298, + 10.058681948424068, + 10.327449856733521, + 10.578796561604587, + 10.78613180515759, + 10.993467048710603, + 11.177335243553014, + 11.350114613180516, + 11.522034383954157, + 11.683295128939825, + 11.844555873925502, + 12.009426934097416, + 12.17836676217765, + 12.347306590257883, + 12.52289398280802, + 12.69951289398281, + 12.878137535816615, + 13.062435530085962, + 13.246733524355296, + 13.431031518624641, + 13.615329512893986, + 13.799426934097417, + 13.979885386819484, + 14.160343839541554, + 14.332206303724927, + 14.493467048710595, + 14.654727793696273, + 14.80951289398281, + 14.963094555873923, + 15.111174785100287, + 15.24171919770774, + 15.372263610315185, + 15.493065902578799, + 15.608252148997133, + 15.722865329512896, + 15.818853868194841, + 15.914842406876792, + 16.004297994269344, + 16.084928366762178, + 16.165558739255015, + 16.239885386819484, + 16.312836676217767, + 16.38080229226361, + 16.430716332378225, + 16.480630372492836, + 16.511747851002866, + 16.530945558739255, + 16.549856733524354, + 16.530659025787966, + 16.511461318051577, + 16.47214899713467, + 16.403037249283667, + 16.333925501432667, + 16.22189111747851, + 16.099025787965612, + 15.96573065902579, + 15.789111747850999, + 15.612492836676221, + 15.408710601719196, + 15.186017191977085, + 14.963323782234959, + 14.699025787965612, + 14.434097421203441, + 14.154555873925498, + 13.851232091690552, + 13.547908309455588, + 13.223724928366773, + 12.893524355300862, + 12.560028653295124, + 12.210630372492844, + 11.861232091690542, + 11.507478510028642, + 11.150401146131808, + 10.793323782234971, + 10.436246418338113, + 10.079169054441257, + 9.72346704871061, + 9.370229226361031, + 9.016991404011453, + 8.672435530085963, + 8.330716332378238, + 7.9918624641833675, + 7.669340974212033, + 7.346819484240697, + 7.036848137535818, + 6.737363896848132, + 6.437879656160463, + 6.156446991404009, + 5.876160458452713, + 5.603610315186247, + 5.346361031518634, + 5.089111747851005, + 4.85151862464183, + 4.621146131805162, + 4.393696275071632, + 4.186361031518619, + 3.9790257879656172, + 3.7817191977077442, + 3.5935816618911205, + 3.405444126074497, + 3.2349283667621824, + 3.0659885386819488, + 2.9030659025787933, + 2.753323782234959, + 2.6035816618911243, + 2.4674498567335195, + 2.3369054441260744, + 2.207965616045849, + 2.092779369627508, + 1.977593123209167, + 1.8681661891117496, + 1.7644985673352427, + 1.6608309455587358, + 1.574355300859599, + 1.4898853868194872, + 1.407650429799428, + 1.3308595988538672, + 1.2540687679083111, + 1.185186246418338, + 1.1199140401146115, + 1.0552722063037254, + 0.9976790830945583, + 0.9400859598853879, + 0.8861604584527217, + 0.8362464183381103, + 0.7863323782234959, + 0.7464756446991396, + 0.7080802292263616, + 0.6696848137535836, + 0.6312893982808009, + 0.5928939828080229, + 0.5595988538681959, + 0.5288825214899716, + 0.49839541547277894, + 0.4715186246418343, + 0.44464183381088807, + 0.41951289398280733, + 0.3964756446991405, + 0.3734383954154737, + 0.35366762177650457, + 0.3344699140401144, + 0.3162177650429803, + 0.3008595988538682, + 0.2855014326647561, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "expected": { + "Rf": 85.39608440997756, + "Rg": 97.79901082615568, + "CCT_K": 4102.572546457284, + "Duv": -0.0005918293873569399, + "bins": [ + { + "bin": 1, + "ref_a": 21.493666916247566, + "ref_b": 4.988185298005295, + "test_a": 19.41097854228106, + "test_b": 4.237499470445516, + "ref_a_norm": 0.974111333673113, + "ref_b_norm": 0.22606881609277588, + "test_a_norm": 0.8797221185849977, + "test_b_norm": 0.19204709353128077, + "Rcs_pct": -9.921286159730345, + "Rhs": -0.014953582335886877, + "Rf_h": 83.43067035334865 + }, + { + "bin": 2, + "ref_a": 20.63264122214867, + "ref_b": 14.362443467915396, + "test_a": 18.457550148603204, + "test_b": 14.547217674747431, + "ref_a_norm": 0.8207317079984009, + "ref_b_norm": 0.5713138047395909, + "test_a_norm": 0.734210249469538, + "test_b_norm": 0.5786638113981913, + "Rcs_pct": -6.785651866683025, + "Rhs": 0.054180054062923894, + "Rf_h": 85.11040715718623 + }, + { + "bin": 3, + "ref_a": 14.624466286187028, + "ref_b": 22.296118311220997, + "test_a": 11.64139182435677, + "test_b": 23.23971627484961, + "ref_a_norm": 0.548463457760392, + "ref_b_norm": 0.8361745245470678, + "test_a_norm": 0.4365887881433909, + "test_b_norm": 0.87156241438454, + "Rcs_pct": -3.2730281224740065, + "Rhs": 0.11268084637599964, + "Rf_h": 78.27637136688796 + }, + { + "bin": 4, + "ref_a": 3.7835635835821586, + "ref_b": 22.124798665256026, + "test_a": 1.978548631191576, + "test_b": 22.819525335377946, + "ref_a_norm": 0.16856307415851382, + "ref_b_norm": 0.9856908694059366, + "test_a_norm": 0.0881471216957889, + "test_b_norm": 1.016641918761578, + "Rcs_pct": 1.4667959559860229, + "Rhs": 0.08490903267057567, + "Rf_h": 86.29149821537418 + }, + { + "bin": 5, + "ref_a": -2.2119239655497234, + "ref_b": 19.128119843037165, + "test_a": -3.2899391546021723, + "test_b": 19.620323618759137, + "ref_a_norm": -0.11487180981200852, + "ref_b_norm": 0.9933803235974195, + "test_a_norm": -0.17085635435330937, + "test_b_norm": 1.0189419339394075, + "Rcs_pct": 3.5992493989313443, + "Rhs": 0.049921994423317684, + "Rf_h": 89.6242538327369 + }, + { + "bin": 6, + "ref_a": -11.148255869529082, + "ref_b": 17.167746757148034, + "test_a": -11.395131694955836, + "test_b": 18.062910150418126, + "ref_a_norm": -0.5446181008983001, + "ref_b_norm": 0.8386841623483354, + "test_a_norm": -0.5566785563430942, + "test_b_norm": 0.8824149658876544, + "Rcs_pct": 4.3061264306303055, + "Rhs": -0.01426763049959886, + "Rf_h": 92.84210402416262 + }, + { + "bin": 7, + "ref_a": -18.229900705740313, + "ref_b": 11.246987320567925, + "test_a": -17.46494877376272, + "test_b": 11.84786608591247, + "ref_a_norm": -0.8510620753579872, + "ref_b_norm": 0.5250650853821418, + "test_a_norm": -0.8153503296229732, + "test_b_norm": 0.5531170828848845, + "Rcs_pct": -1.4108376591675187, + "Rhs": -0.04316476638745592, + "Rf_h": 92.61160143553771 + }, + { + "bin": 8, + "ref_a": -22.79105010923753, + "ref_b": 3.578396849279519, + "test_a": -21.636083632428402, + "test_b": 3.971223899818209, + "ref_a_norm": -0.9878974171569176, + "ref_b_norm": 0.15510864958051526, + "test_a_norm": -0.9378344146241776, + "test_b_norm": 0.1721360716061134, + "Rcs_pct": -4.5779170730822605, + "Rhs": -0.026467052171126923, + "Rf_h": 91.0006755636468 + }, + { + "bin": 9, + "ref_a": -19.358693284334183, + "ref_b": -2.1384744785301306, + "test_a": -18.04586295685151, + "test_b": -2.381655291584643, + "ref_a_norm": -0.9939539260717375, + "ref_b_norm": -0.10979796376335532, + "test_a_norm": -0.926547885844662, + "test_b_norm": -0.1222838542276901, + "Rcs_pct": -6.367497567363852, + "Rhs": 0.025396243673878865, + "Rf_h": 89.70289506809974 + }, + { + "bin": 10, + "ref_a": -20.139427962408828, + "ref_b": -11.276798405229234, + "test_a": -17.65706749011864, + "test_b": -12.151386070481754, + "ref_a_norm": -0.8725296791959833, + "ref_b_norm": -0.48856111073452657, + "test_a_norm": -0.7649827721746437, + "test_b_norm": -0.5264521420198199, + "Rcs_pct": -6.837085600484762, + "Rhs": 0.09125510128690958, + "Rf_h": 81.0361401131765 + }, + { + "bin": 11, + "ref_a": -12.058854551175639, + "ref_b": -17.35828200020298, + "test_a": -9.734965421006237, + "test_b": -19.17100989729602, + "ref_a_norm": -0.5705391851500262, + "ref_b_norm": -0.8212703806958729, + "test_a_norm": -0.4605892885757623, + "test_b_norm": -0.9070357652037534, + "Rcs_pct": 1.0226421345501167, + "Rhs": 0.1390686925333672, + "Rf_h": 79.19396726731712 + }, + { + "bin": 12, + "ref_a": -5.355977172011339, + "ref_b": -23.677114212953057, + "test_a": -3.7712182513193846, + "test_b": -25.272516238095125, + "ref_a_norm": -0.2206344682336243, + "ref_b_norm": -0.9753565663014043, + "test_a_norm": -0.15535180728941117, + "test_b_norm": -1.0410776599751252, + "Rcs_pct": 5.172226594151094, + "Rhs": 0.07684982224769742, + "Rf_h": 83.829879348362 + }, + { + "bin": 13, + "ref_a": 3.6850044440296124, + "ref_b": -15.344231315979924, + "test_a": 3.322462452613831, + "test_b": -16.78914509029956, + "ref_a_norm": 0.23351608976056143, + "ref_b_norm": -0.9723529378898063, + "test_a_norm": 0.21054206367856199, + "test_b_norm": -1.063916087879208, + "Rcs_pct": 8.53217795906143, + "Rhs": -0.04039567102906844, + "Rf_h": 87.95061618493018 + }, + { + "bin": 14, + "ref_a": 14.02948917300974, + "ref_b": -18.58441067316398, + "test_a": 13.749287604757338, + "test_b": -20.179170222784244, + "ref_a_norm": 0.602503180254292, + "ref_b_norm": -0.7981164813380714, + "test_a_norm": 0.5904697887385768, + "test_b_norm": -0.8666041994964497, + "Rcs_pct": 5.02600623362309, + "Rhs": -0.048055136914487415, + "Rf_h": 87.73965073854671 + }, + { + "bin": 15, + "ref_a": 15.409047312947784, + "ref_b": -11.033367769942632, + "test_a": 14.089060309833355, + "test_b": -13.346786740827616, + "ref_a_norm": 0.8130614631507036, + "ref_b_norm": -0.5821778569640356, + "test_a_norm": 0.7434120849448022, + "test_b_norm": -0.7042458716275917, + "Rcs_pct": 0.9906013856897832, + "Rhs": -0.14019096610637147, + "Rf_h": 81.37159838982325 + }, + { + "bin": 16, + "ref_a": 20.095661758951227, + "ref_b": -3.591713352543728, + "test_a": 18.892653659571067, + "test_b": -5.8060695129771736, + "ref_a_norm": 0.9844004172431393, + "ref_b_norm": -0.17594265694121258, + "test_a_norm": 0.9254702018970731, + "test_b_norm": -0.28441448306978706, + "Rcs_pct": -3.6636084293313274, + "Rhs": -0.11788428509370821, + "Rf_h": 80.93358190054737 + } + ] + } +} \ No newline at end of file diff --git a/crates/tm30/tests/golden/hpcs_grid_blackbody_3000K.json b/crates/tm30/tests/golden/hpcs_grid_blackbody_3000K.json new file mode 100644 index 0000000..5157307 --- /dev/null +++ b/crates/tm30/tests/golden/hpcs_grid_blackbody_3000K.json @@ -0,0 +1,941 @@ +{ + "name": "hpcs_grid_blackbody_3000K", + "source": "sd_blackbody(3000) on 380-1050 nm / 350 points", + "generator": "crates/tm30/tools/golden.py (tm30.py + colour-science 0.4.7, numpy 2.5.1)", + "wavelengths": [ + 380.0, + 381.91977077363896, + 383.8395415472779, + 385.75931232091693, + 387.6790830945559, + 389.59885386819485, + 391.5186246418338, + 393.43839541547277, + 395.3581661891117, + 397.2779369627507, + 399.1977077363897, + 401.11747851002866, + 403.0372492836676, + 404.9570200573066, + 406.87679083094554, + 408.79656160458455, + 410.7163323782235, + 412.63610315186247, + 414.55587392550143, + 416.4756446991404, + 418.39541547277935, + 420.3151862464183, + 422.2349570200573, + 424.1547277936963, + 426.07449856733524, + 427.9942693409742, + 429.91404011461316, + 431.8338108882522, + 433.75358166189113, + 435.6733524355301, + 437.59312320916905, + 439.512893982808, + 441.43266475644697, + 443.3524355300859, + 445.27220630372494, + 447.1919770773639, + 449.11174785100286, + 451.0315186246418, + 452.9512893982808, + 454.8710601719198, + 456.79083094555875, + 458.7106017191977, + 460.63037249283667, + 462.55014326647563, + 464.46991404011465, + 466.38968481375355, + 468.30945558739256, + 470.2292263610315, + 472.1489971346705, + 474.06876790830944, + 475.9885386819484, + 477.9083094555874, + 479.8280802292264, + 481.74785100286533, + 483.6676217765043, + 485.58739255014325, + 487.50716332378227, + 489.42693409742117, + 491.3467048710602, + 493.26647564469914, + 495.1862464183381, + 497.10601719197706, + 499.025787965616, + 500.94555873925503, + 502.865329512894, + 504.78510028653295, + 506.7048710601719, + 508.62464183381087, + 510.5444126074499, + 512.4641833810888, + 514.3839541547278, + 516.3037249283668, + 518.2234957020057, + 520.1432664756447, + 522.0630372492836, + 523.9828080229227, + 525.9025787965616, + 527.8223495702006, + 529.7421203438396, + 531.6618911174785, + 533.5816618911175, + 535.5014326647564, + 537.4212034383954, + 539.3409742120343, + 541.2607449856733, + 543.1805157593124, + 545.1002865329513, + 547.0200573065903, + 548.9398280802293, + 550.8595988538682, + 552.7793696275071, + 554.6991404011461, + 556.6189111747851, + 558.538681948424, + 560.458452722063, + 562.3782234957021, + 564.297994269341, + 566.21776504298, + 568.1375358166189, + 570.0573065902579, + 571.9770773638968, + 573.8968481375358, + 575.8166189111748, + 577.7363896848137, + 579.6561604584527, + 581.5759312320916, + 583.4957020057307, + 585.4154727793696, + 587.3352435530086, + 589.2550143266476, + 591.1747851002865, + 593.0945558739255, + 595.0143266475645, + 596.9340974212034, + 598.8538681948423, + 600.7736389684814, + 602.6934097421204, + 604.6131805157593, + 606.5329512893983, + 608.4527220630373, + 610.3724928366762, + 612.2922636103152, + 614.2120343839541, + 616.1318051575931, + 618.051575931232, + 619.971346704871, + 621.8911174785101, + 623.810888252149, + 625.730659025788, + 627.6504297994269, + 629.5702005730659, + 631.4899713467048, + 633.4097421203438, + 635.3295128939828, + 637.2492836676217, + 639.1690544412608, + 641.0888252148998, + 643.0085959885387, + 644.9283667621776, + 646.8481375358166, + 648.7679083094556, + 650.6876790830945, + 652.6074498567335, + 654.5272206303725, + 656.4469914040114, + 658.3667621776503, + 660.2865329512895, + 662.2063037249284, + 664.1260744985673, + 666.0458452722063, + 667.9656160458453, + 669.8853868194842, + 671.8051575931232, + 673.7249283667622, + 675.6446991404011, + 677.56446991404, + 679.4842406876791, + 681.4040114613181, + 683.323782234957, + 685.243553008596, + 687.163323782235, + 689.0830945558739, + 691.0028653295128, + 692.9226361031518, + 694.8424068767908, + 696.7621776504297, + 698.6819484240688, + 700.6017191977078, + 702.5214899713467, + 704.4412607449856, + 706.3610315186247, + 708.2808022922636, + 710.2005730659025, + 712.1203438395415, + 714.0401146131805, + 715.9598853868195, + 717.8796561604585, + 719.7994269340975, + 721.7191977077364, + 723.6389684813753, + 725.5587392550143, + 727.4785100286533, + 729.3982808022922, + 731.3180515759312, + 733.2378223495703, + 735.1575931232092, + 737.077363896848, + 738.9971346704871, + 740.9169054441261, + 742.836676217765, + 744.756446991404, + 746.676217765043, + 748.5959885386819, + 750.5157593123208, + 752.43553008596, + 754.3553008595989, + 756.2750716332378, + 758.1948424068768, + 760.1146131805158, + 762.0343839541547, + 763.9541547277937, + 765.8739255014327, + 767.7936962750716, + 769.7134670487105, + 771.6332378223495, + 773.5530085959886, + 775.4727793696275, + 777.3925501432665, + 779.3123209169055, + 781.2320916905444, + 783.1518624641833, + 785.0716332378223, + 786.9914040114613, + 788.9111747851002, + 790.8309455587392, + 792.7507163323783, + 794.6704871060172, + 796.5902578796561, + 798.5100286532952, + 800.4297994269341, + 802.349570200573, + 804.269340974212, + 806.189111747851, + 808.1088825214899, + 810.028653295129, + 811.948424068768, + 813.8681948424069, + 815.7879656160458, + 817.7077363896848, + 819.6275071633238, + 821.5472779369627, + 823.4670487106017, + 825.3868194842407, + 827.3065902578796, + 829.2263610315185, + 831.1461318051576, + 833.0659025787966, + 834.9856733524355, + 836.9054441260745, + 838.8252148997135, + 840.7449856733524, + 842.6647564469913, + 844.5845272206304, + 846.5042979942693, + 848.4240687679082, + 850.3438395415473, + 852.2636103151863, + 854.1833810888252, + 856.1031518624642, + 858.0229226361032, + 859.9426934097421, + 861.862464183381, + 863.78223495702, + 865.702005730659, + 867.6217765042979, + 869.541547277937, + 871.461318051576, + 873.3810888252149, + 875.3008595988538, + 877.2206303724929, + 879.1404011461318, + 881.0601719197707, + 882.9799426934097, + 884.8997134670487, + 886.8194842406876, + 888.7392550143267, + 890.6590257879657, + 892.5787965616046, + 894.4985673352436, + 896.4183381088825, + 898.3381088825215, + 900.2578796561604, + 902.1776504297994, + 904.0974212034383, + 906.0171919770773, + 907.9369627507164, + 909.8567335243553, + 911.7765042979943, + 913.6962750716332, + 915.6160458452722, + 917.5358166189112, + 919.4555873925501, + 921.3753581661891, + 923.295128939828, + 925.214899713467, + 927.134670487106, + 929.054441260745, + 930.974212034384, + 932.8939828080229, + 934.8137535816619, + 936.7335243553008, + 938.6532951289398, + 940.5730659025788, + 942.4928366762177, + 944.4126074498568, + 946.3323782234957, + 948.2521489971347, + 950.1719197707736, + 952.0916905444126, + 954.0114613180516, + 955.9312320916905, + 957.8510028653295, + 959.7707736389684, + 961.6905444126074, + 963.6103151862465, + 965.5300859598854, + 967.4498567335244, + 969.3696275071633, + 971.2893982808023, + 973.2091690544412, + 975.1289398280802, + 977.0487106017192, + 978.9684813753581, + 980.8882521489971, + 982.808022922636, + 984.7277936962751, + 986.6475644699141, + 988.567335243553, + 990.487106017192, + 992.4068767908309, + 994.3266475644699, + 996.2464183381088, + 998.1661891117478, + 1000.0859598853868, + 1002.0057306590257, + 1003.9255014326648, + 1005.8452722063037, + 1007.7650429799427, + 1009.6848137535817, + 1011.6045845272206, + 1013.5243553008596, + 1015.4441260744985, + 1017.3638968481375, + 1019.2836676217764, + 1021.2034383954154, + 1023.1232091690545, + 1025.0429799426934, + 1026.9627507163323, + 1028.8825214899712, + 1030.8022922636103, + 1032.7220630372494, + 1034.6418338108883, + 1036.5616045845272, + 1038.4813753581661, + 1040.401146131805, + 1042.320916905444, + 1044.240687679083, + 1046.1604584527222, + 1048.080229226361, + 1050.0 + ], + "values": [ + 49.6314849410213, + 51.56640967361729, + 53.54954532014713, + 55.58114841747607, + 57.66145188395817, + 59.79066489774875, + 61.96897280297109, + 64.19653704324628, + 66.47349512206164, + 68.79996058941953, + 71.17602305417832, + 73.60174822147297, + 76.07717795457205, + 78.60233036051488, + 81.17719989884456, + 83.80175751274221, + 86.4759507818438, + 89.19970409601255, + 91.97291884932835, + 94.7954736535474, + 97.66722457027855, + 100.5880053611153, + 103.55762775496177, + 106.57588173178723, + 109.64253582204437, + 112.75733742098798, + 115.92001311713236, + 119.13026903409741, + 122.38779118508609, + 125.69224583924148, + 129.04327989915166, + 132.4405212887731, + 135.8835793510551, + 139.37204525455437, + 142.9054924083481, + 146.48347688455257, + 150.10553784778472, + 153.77119799089928, + 157.47996397636652, + 161.2313268826567, + 165.02476265502295, + 168.85973256007117, + 172.73568364353204, + 176.65204919067702, + 180.60824918882545, + 184.60369079140435, + 188.63776878304913, + 192.70986604524163, + 196.81935402200037, + 200.96559318515858, + 205.1479334987784, + 209.3657148822703, + 213.6182676718043, + 217.90491307961415, + 222.2249636507914, + 226.57772371722226, + 230.96248984831507, + 235.37855129817902, + 239.82519044894673, + 244.30168324992715, + 248.8072996523156, + 253.34130403917626, + 257.9029556504542, + 262.49150900276857, + 267.1062143037615, + 271.74631786080386, + 276.4110624838306, + 281.09968788213496, + 285.8114310549571, + 290.5455266756924, + 295.3012074695922, + 300.0777045848046, + 304.87424795664805, + 309.6900666649969, + 314.52438928468433, + 319.37644422883255, + 324.24546008503046, + 329.1306659443028, + 334.0312917227902, + 338.9465684761055, + 343.8757287063209, + 348.8180066615578, + 353.7726386281539, + 358.7388632154027, + 363.715921632843, + 368.7030579601181, + 373.6995194093935, + 378.7045565803637, + 383.7174237078595, + 388.7373789020923, + 393.76368438156294, + 398.7956066986696, + 403.8324169580665, + 408.8733910278181, + 413.9178097434116, + 418.96495910467337, + 424.01413046566745, + 429.0646207176412, + 434.11573246506856, + 439.166774194906, + 444.2170604390925, + 449.2659119304199, + 454.31265575182016, + 459.3566254791826, + 464.39716131777595, + 469.4336102323656, + 474.46532607113585, + 479.49166968349175, + 484.51200903185776, + 489.52571929755976, + 494.5321829808937, + 499.53078999548677, + 504.5209377570458, + 509.5020312666078, + 514.4734831883841, + 519.4347139223207, + 524.3851516714533, + 529.3242325041936, + 534.2514004116329, + 539.166107359975, + 544.0678133382102, + 548.9559864011312, + 553.830102707798, + 558.6896465555608, + 563.5341104097483, + 568.3629949291172, + 573.1758089871818, + 577.9720696895143, + 582.751302387137, + 587.5130406860837, + 592.2568264532637, + 596.982209818703, + 601.6887491742813, + 606.3760111690546, + 611.0435707012667, + 615.6910109071498, + 620.3179231465998, + 624.9239069858343, + 629.5085701771243, + 634.0715286356834, + 638.6124064138245, + 643.1308356724503, + 647.6264566499983, + 652.0989176288919, + 656.5478748996219, + 660.972992722513, + 665.3739432872771, + 669.7504066704283, + 674.1020707906449, + 678.4286313621618, + 682.7297918462524, + 687.0052634009071, + 691.2547648287633, + 695.4780225233532, + 699.674770413781, + 703.8447499078494, + 707.9877098337483, + 712.1034063803531, + 716.1916030361967, + 720.2520705271977, + 724.2845867531917, + 728.2889367233379, + 732.2649124904664, + 736.2123130844086, + 740.1309444443908, + 744.0206193505325, + 747.8811573545127, + 751.7123847094625, + 755.5141342991246, + 759.2862455663465, + 763.0285644409458, + 766.740943267004, + 770.4232407296345, + 774.075321781269, + 777.6970575675172, + 781.2883253526267, + 784.8490084446062, + 788.3789961200392, + 791.8781835486293, + 795.3464717175369, + 798.7837673555101, + 802.1899828568805, + 805.5650362054466, + 808.9088508982662, + 812.2213558694226, + 815.5024854137627, + 818.752179110667, + 821.9703817478686, + 825.1570432453432, + 828.3121185793268, + 831.4355677064481, + 834.5273554880434, + 837.5874516146553, + 840.6158305307384, + 843.6124713596234, + 846.5773578287199, + 849.5104781950193, + 852.4118251708984, + 855.281395850244, + 858.1191916349377, + 860.9252181616821, + 863.6994852292346, + 866.4420067260254, + 869.1528005581926, + 871.8318885780666, + 874.4792965130794, + 877.095053895156, + 879.6791939905778, + 882.2317537303272, + 884.7527736409484, + 887.2422977759096, + 889.7003736474999, + 892.1270521592645, + 894.5223875389697, + 896.886437272151, + 899.2192620361998, + 901.5209256350399, + 903.7914949343825, + 906.0310397975695, + 908.2396330220198, + 910.4173502762604, + 912.564270037591, + 914.6804735303425, + 916.7660446647646, + 918.8210699765418, + 920.8456385669216, + 922.8398420434895, + 924.8037744615817, + 926.7375322663191, + 928.6412142353029, + 930.5149214219425, + 932.3587570994347, + 934.172826705392, + 935.9572377871111, + 937.7120999475078, + 939.4375247916838, + 941.1336258741597, + 942.8005186467573, + 944.4383204071218, + 946.047150247916, + 947.6271290066404, + 949.1783792161272, + 950.7010250556666, + 952.1951923027846, + 953.6610082856797, + 955.0986018362773, + 956.5081032439537, + 957.889644209885, + 959.2433578020335, + 960.5693784107808, + 961.867841705177, + 963.1388845898347, + 964.382645162442, + 965.5992626718966, + 966.7888774770694, + 967.9516310061779, + 969.087665716776, + 970.1971250563506, + 971.2801534235301, + 972.3368961298877, + 973.3674993623463, + 974.3721101461795, + 975.3508763085941, + 976.3039464429048, + 977.2314698732922, + 978.1335966201233, + 979.0104773658603, + 979.8622634215254, + 980.6891066937309, + 981.4911596522759, + 982.2685752982753, + 983.0215071328564, + 983.7501091263916, + 984.4545356882616, + 985.1349416371673, + 985.791482171949, + 986.4243128429497, + 987.0335895238753, + 987.6194683841841, + 988.1821058619752, + 988.7216586373761, + 989.2382836064337, + 989.7321378554973, + 990.2033786360736, + 990.6521633401865, + 991.0786494761855, + 991.4829946450468, + 991.8653565171261, + 992.225892809371, + 992.5647612629949, + 992.882119621595, + 993.1781256097133, + 993.4529369118359, + 993.706711151825, + 993.9396058727867, + 994.1517785173432, + 994.3433864083397, + 994.5145867299568, + 994.6655365092205, + 994.7963925979323, + 994.9073116549739, + 994.9984501290194, + 995.0699642416272, + 995.1220099707081, + 995.1547430343755, + 995.1683188751657, + 995.1628926446153, + 995.1386191882141, + 995.0956530306931, + 995.0341483616852, + 994.9542590217111, + 994.8561384885192, + 994.739939863753, + 994.6058158599564, + 994.4539187878997, + 994.2844005442236, + 994.0974125994101, + 993.8931059860588, + 993.6716312874664, + 993.4331386265153, + 993.1777776548598, + 992.9056975424013, + 992.617046967052, + 992.3119741047926, + 991.9906266199956, + 991.6531516560317, + 991.299695826156, + 990.930405204635, + 990.5454253181719, + 990.1449011375558, + 989.7289770695896, + 989.2977969492548, + 988.8515040321319, + 988.3902409870491, + 987.9141498889846, + 987.4233722121891, + 986.9180488235472, + 986.398319976163, + 985.8643253031615, + 985.3162038117224, + 984.7540938773078, + 984.1781332381246, + 983.5884589897747, + 982.9852075801157, + 982.3685148043298, + 981.7385158001713, + 981.0953450434271, + 980.4391363435489, + 979.7700228394827, + 979.0881369956787 + ], + "expected": { + "Rf": 99.9999404466453, + "Rg": 100.00020892298296, + "CCT_K": 2999.993738385895, + "Duv": 2.527007121615376e-06, + "bins": [ + { + "bin": 1, + "ref_a": 23.977919673617148, + "ref_b": 5.025826327691377, + "test_a": 23.977911678030395, + "test_b": 5.025790348792663, + "ref_a_norm": 0.9787317202561051, + "ref_b_norm": 0.2051443876018193, + "test_a_norm": 0.9787313938919132, + "test_b_norm": 0.20514291901363857, + "Rcs_pct": -6.066005365188216e-05, + "Rhs": -1.3766991753388021e-06, + "Rf_h": 100.00002596533349 + }, + { + "bin": 2, + "ref_a": 20.533247514182666, + "ref_b": 15.081050158444745, + "test_a": 20.53323811205277, + "test_b": 15.081057688135719, + "ref_a_norm": 0.8059679768620203, + "ref_b_norm": 0.5919591373337706, + "test_a_norm": 0.8059676078110163, + "test_b_norm": 0.5919594328880806, + "Rcs_pct": -1.4265351829400396e-05, + "Rhs": 4.5077817977717796e-07, + "Rf_h": 100.00010979403507 + }, + { + "bin": 3, + "ref_a": 14.806820628027964, + "ref_b": 22.930348737830425, + "test_a": 14.806804572745335, + "test_b": 22.93039794888169, + "ref_a_norm": 0.5424643414850465, + "ref_b_norm": 0.8400788285733636, + "test_a_norm": 0.5424637532819111, + "test_b_norm": 0.840080631474958, + "Rcs_pct": 0.0001172269736754126, + "Rhs": 1.4907114918684568e-06, + "Rf_h": 99.9999952506379 + }, + { + "bin": 4, + "ref_a": 2.716086439399598, + "ref_b": 20.47559285752593, + "test_a": 2.716069083652604, + "test_b": 20.475665457086464, + "ref_a_norm": 0.13149807770251556, + "ref_b_norm": 0.9913164255476368, + "test_a_norm": 0.13149723743199485, + "test_b_norm": 0.9913199404220215, + "Rcs_pct": 0.00032834084125179163, + "Rhs": 1.5098429338451931e-06, + "Rf_h": 99.99991624645564 + }, + { + "bin": 5, + "ref_a": -2.940166482506493, + "ref_b": 16.861430156777654, + "test_a": -2.9401826038614396, + "test_b": 16.86149796384434, + "ref_a_norm": -0.1717803122659738, + "ref_b_norm": 0.985135282241888, + "test_a_norm": -0.17178125416208864, + "test_b_norm": 0.9851392438947938, + "Rcs_pct": 0.00040692856724410046, + "Rhs": 1.5091770399701245e-07, + "Rf_h": 99.99994249768572 + }, + { + "bin": 6, + "ref_a": -12.720583405557853, + "ref_b": 17.000378351966575, + "test_a": -12.720589092236102, + "test_b": 17.00046893741518, + "ref_a_norm": -0.5991043891514255, + "ref_b_norm": 0.8006709254740659, + "test_a_norm": -0.5991046569782845, + "test_b_norm": 0.8006751917988189, + "Rcs_pct": 0.0003696116018671311, + "Rhs": -2.1475531424521534e-06, + "Rf_h": 99.99982598600765 + }, + { + "bin": 7, + "ref_a": -18.66726319837078, + "ref_b": 13.268820142492949, + "test_a": -18.667255621707557, + "test_b": 13.268943176704765, + "ref_a_norm": -0.8150723996259367, + "ref_b_norm": 0.5793591143392993, + "test_a_norm": -0.8150720688045942, + "test_b_norm": 0.5793644864063878, + "Rcs_pct": 0.0002709492670712323, + "Rhs": -4.650505029749752e-06, + "Rf_h": 99.99961608444593 + }, + { + "bin": 8, + "ref_a": -21.454441703188817, + "ref_b": 5.81316994741631, + "test_a": -21.45445798835348, + "test_b": 5.813276652992987, + "ref_a_norm": -0.9651969424729813, + "ref_b_norm": 0.2615241140713576, + "test_a_norm": -0.9651976751133994, + "test_b_norm": 0.2615289145643174, + "Rcs_pct": 0.00016550926552716128, + "Rhs": -4.5653217785923566e-06, + "Rf_h": 99.99971021530266 + }, + { + "bin": 9, + "ref_a": -22.56418178910898, + "ref_b": -3.728941328110815, + "test_a": -22.5641939870357, + "test_b": -3.7288473580402615, + "ref_a_norm": -0.9866181631342824, + "ref_b_norm": -0.16304784627076357, + "test_a_norm": -0.9866186964882577, + "test_b_norm": -0.16304373743228381, + "Rcs_pct": -2.7848889390952563e-05, + "Rhs": -4.13394049927232e-06, + "Rf_h": 99.99979408790834 + }, + { + "bin": 10, + "ref_a": -18.138151750806145, + "ref_b": -11.848435202343946, + "test_a": -18.138196709271842, + "test_b": -11.848352393371503, + "ref_a_norm": -0.8372047464600949, + "ref_b_norm": -0.5468895798099359, + "test_a_norm": -0.837206821613142, + "test_b_norm": -0.5468857575867165, + "Rcs_pct": -3.9808674509672646e-05, + "Rhs": -4.3309557203316795e-06, + "Rf_h": 99.99979188149966 + }, + { + "bin": 11, + "ref_a": -10.989344163529712, + "ref_b": -15.749942004188728, + "test_a": -10.9893992442997, + "test_b": -15.74989347622865, + "ref_a_norm": -0.5722170572465619, + "ref_b_norm": -0.8201022127735571, + "test_a_norm": -0.5722199253118118, + "test_b_norm": -0.8200996859142562, + "Rcs_pct": -5.075950441342222e-05, + "Rhs": -3.7885569119022477e-06, + "Rf_h": 99.9999400706674 + }, + { + "bin": 12, + "ref_a": -6.738130113701561, + "ref_b": -21.15580993409248, + "test_a": -6.738177473389229, + "test_b": -21.15580128496962, + "ref_a_norm": -0.30347913883299216, + "ref_b_norm": -0.9528380829360178, + "test_a_norm": -0.3034812718694557, + "test_b_norm": -0.9528376933875358, + "Rcs_pct": 3.4071353348639173e-06, + "Rhs": -2.1680479048292833e-06, + "Rf_h": 100.00009330304174 + }, + { + "bin": 13, + "ref_a": 3.140000075381524, + "ref_b": -18.091771778600368, + "test_a": 3.1399669761079396, + "test_b": -18.091804967222387, + "ref_a_norm": 0.1710031191208372, + "ref_b_norm": -0.9852704873540792, + "test_a_norm": 0.17100131654794304, + "test_b_norm": -0.9852722947928526, + "Rcs_pct": 0.00014210448177820405, + "Rhs": -2.1205507737651178e-06, + "Rf_h": 100.00011542850079 + }, + { + "bin": 14, + "ref_a": 9.195915239651905, + "ref_b": -14.070998289447374, + "test_a": 9.195859736334171, + "test_b": -14.071027867663329, + "ref_a_norm": 0.547067948301649, + "ref_b_norm": -0.8370882032026399, + "test_a_norm": 0.5470646463914676, + "test_b_norm": -0.8370899628201978, + "Rcs_pct": -3.7137448018051166e-05, + "Rhs": -3.723029115016219e-06, + "Rf_h": 99.99999646231082 + }, + { + "bin": 15, + "ref_a": 18.268111183819318, + "ref_b": -11.932033222898948, + "test_a": 18.268074707789726, + "test_b": -11.932095550246302, + "ref_a_norm": 0.837231934943391, + "ref_b_norm": -0.5468479561184675, + "test_a_norm": 0.8372302632381705, + "test_b_norm": -0.5468508125958066, + "Rcs_pct": 1.9700168934567813e-05, + "Rhs": -3.3038237646135215e-06, + "Rf_h": 99.999909284548 + }, + { + "bin": 16, + "ref_a": 16.784863949608233, + "ref_b": -3.807441345888433, + "test_a": 16.78483549373106, + "test_b": -3.8074587102455086, + "ref_a_norm": 0.9752244391482773, + "ref_b_norm": -0.22121775084275702, + "test_a_norm": 0.9752227858213905, + "test_b_norm": -0.22121875973657001, + "Rcs_pct": -0.0001424733255350465, + "Rhs": -1.3120562759872044e-06, + "Rf_h": 100.00003290022211 + } + ] + } +} \ No newline at end of file diff --git a/crates/tm30/tests/golden/illuminant_A.json b/crates/tm30/tests/golden/illuminant_A.json new file mode 100644 index 0000000..eb52ffa --- /dev/null +++ b/crates/tm30/tests/golden/illuminant_A.json @@ -0,0 +1,435 @@ +{ + "name": "illuminant_A", + "source": "colour.SDS_ILLUMINANTS['A'] (300.0, 780.0, 5.0)", + "generator": "crates/tm30/tools/golden.py (tm30.py + colour-science 0.4.7, numpy 2.5.1)", + "wavelengths": [ + 300.0, + 305.0, + 310.0, + 315.0, + 320.0, + 325.0, + 330.0, + 335.0, + 340.0, + 345.0, + 350.0, + 355.0, + 360.0, + 365.0, + 370.0, + 375.0, + 380.0, + 385.0, + 390.0, + 395.0, + 400.0, + 405.0, + 410.0, + 415.0, + 420.0, + 425.0, + 430.0, + 435.0, + 440.0, + 445.0, + 450.0, + 455.0, + 460.0, + 465.0, + 470.0, + 475.0, + 480.0, + 485.0, + 490.0, + 495.0, + 500.0, + 505.0, + 510.0, + 515.0, + 520.0, + 525.0, + 530.0, + 535.0, + 540.0, + 545.0, + 550.0, + 555.0, + 560.0, + 565.0, + 570.0, + 575.0, + 580.0, + 585.0, + 590.0, + 595.0, + 600.0, + 605.0, + 610.0, + 615.0, + 620.0, + 625.0, + 630.0, + 635.0, + 640.0, + 645.0, + 650.0, + 655.0, + 660.0, + 665.0, + 670.0, + 675.0, + 680.0, + 685.0, + 690.0, + 695.0, + 700.0, + 705.0, + 710.0, + 715.0, + 720.0, + 725.0, + 730.0, + 735.0, + 740.0, + 745.0, + 750.0, + 755.0, + 760.0, + 765.0, + 770.0, + 775.0, + 780.0 + ], + "values": [ + 0.930483, + 1.12821, + 1.35769, + 1.62219, + 1.92508, + 2.2698, + 2.65981, + 3.09861, + 3.58968, + 4.13648, + 4.74238, + 5.4107, + 6.14462, + 6.9472, + 7.82135, + 8.7698, + 9.7951, + 10.8996, + 12.0853, + 13.3543, + 14.708, + 16.148, + 17.6753, + 19.2907, + 20.995, + 22.7883, + 24.6709, + 26.6425, + 28.7027, + 30.8508, + 33.0859, + 35.4068, + 37.8121, + 40.3002, + 42.8693, + 45.5174, + 48.2423, + 51.0418, + 53.9132, + 56.8539, + 59.8611, + 62.932, + 66.0635, + 69.2525, + 72.4959, + 75.7903, + 79.1326, + 82.5193, + 85.947, + 89.4124, + 92.912, + 96.4423, + 100.0, + 103.582, + 107.184, + 110.803, + 114.436, + 118.08, + 121.731, + 125.386, + 129.043, + 132.697, + 136.346, + 139.988, + 143.618, + 147.235, + 150.836, + 154.418, + 157.979, + 161.516, + 165.028, + 168.51, + 171.963, + 175.383, + 178.769, + 182.118, + 185.429, + 188.701, + 191.931, + 195.118, + 198.261, + 201.359, + 204.409, + 207.411, + 210.365, + 213.268, + 216.12, + 218.92, + 221.667, + 224.361, + 227.0, + 229.585, + 232.115, + 234.589, + 237.008, + 239.37, + 241.675 + ], + "expected": { + "Rf": 99.99869291550083, + "Rg": 100.00142490961754, + "CCT_K": 2855.658424436243, + "Duv": 5.602647302014208e-07, + "bins": [ + { + "bin": 1, + "ref_a": 24.136909279209537, + "ref_b": 5.229907397606012, + "test_a": 24.137018759075897, + "test_b": 5.229857888375308, + "ref_a_norm": 0.9773210976977805, + "ref_b_norm": 0.2117627729200895, + "test_a_norm": 0.9773255306175851, + "test_b_norm": 0.21176076825515341, + "Rcs_pct": 0.00039566517656954746, + "Rhs": -2.8309656136092595e-06, + "Rf_h": 99.99914960196838 + }, + { + "bin": 2, + "ref_a": 20.635749303334617, + "ref_b": 15.117385918248889, + "test_a": 20.63579074873976, + "test_b": 15.117494792519082, + "ref_a_norm": 0.8066937954547886, + "ref_b_norm": 0.5909696442075071, + "test_a_norm": 0.8066954156407429, + "test_b_norm": 0.590973900326195, + "Rcs_pct": 0.00037117082385003115, + "Rhs": 2.638706267201798e-06, + "Rf_h": 99.9994710754886 + }, + { + "bin": 3, + "ref_a": 14.883650579138424, + "ref_b": 22.814856273616257, + "test_a": 14.883616086070193, + "test_b": 22.815123318109993, + "ref_a_norm": 0.5463810094158151, + "ref_b_norm": 0.8375367410148374, + "test_a_norm": 0.5463797431701896, + "test_b_norm": 0.8375465442576152, + "Rcs_pct": 0.0007447610094472131, + "Rhs": 6.499234633723335e-06, + "Rf_h": 99.99861265505554 + }, + { + "bin": 4, + "ref_a": 2.7313615072020565, + "ref_b": 20.27457142594694, + "test_a": 2.7312555695770624, + "test_b": 20.27491693656199, + "ref_a_norm": 0.13351246430088187, + "ref_b_norm": 0.9910471340336471, + "test_a_norm": 0.13350728593348604, + "test_b_norm": 0.9910640230370015, + "Rcs_pct": 0.0015554236527902362, + "Rhs": 8.37374762130058e-06, + "Rf_h": 99.99800522273162 + }, + { + "bin": 5, + "ref_a": -2.916946634944088, + "ref_b": 16.648697650654817, + "test_a": -2.9170369010753667, + "test_b": 16.648995447888737, + "ref_a_norm": -0.17257691611880005, + "ref_b_norm": 0.9849960446737461, + "test_a_norm": -0.17258225658351048, + "test_b_norm": 0.9850136634150843, + "Rcs_pct": 0.001832207514385362, + "Rhs": 1.8006032572946633e-06, + "Rf_h": 99.99835089928493 + }, + { + "bin": 6, + "ref_a": -12.78811185147957, + "ref_b": 16.67776522160597, + "test_a": -12.788216323142862, + "test_b": 16.678121997181808, + "ref_a_norm": -0.6084862388576454, + "ref_b_norm": 0.7935644253120704, + "test_a_norm": -0.6084912098471239, + "test_b_norm": 0.7935814014717083, + "Rcs_pct": 0.0016876894655425449, + "Rhs": -5.298222271354322e-06, + "Rf_h": 99.99794401089322 + }, + { + "bin": 7, + "ref_a": -18.858176701885924, + "ref_b": 12.829907885756011, + "test_a": -18.858307387056858, + "test_b": 12.830382647229602, + "ref_a_norm": -0.8267970724158379, + "ref_b_norm": 0.5625003120395573, + "test_a_norm": -0.8268028020321441, + "test_b_norm": 0.5625211269572806, + "Rcs_pct": 0.001632815053854683, + "Rhs": -1.4123767303124144e-05, + "Rf_h": 99.99713439230325 + }, + { + "bin": 8, + "ref_a": -21.43131842553025, + "ref_b": 5.397620101060722, + "test_a": -21.43141604529075, + "test_b": 5.3979967879530255, + "ref_a_norm": -0.9697173902639312, + "ref_b_norm": 0.24422977504741347, + "test_a_norm": -0.9697218073313981, + "test_b_norm": 0.24424681925453587, + "Rcs_pct": 0.0007657354610068032, + "Rhs": -1.5854980347317808e-05, + "Rf_h": 99.99783109559098 + }, + { + "bin": 9, + "ref_a": -22.605603031423193, + "ref_b": -4.097787913662709, + "test_a": -22.605739585711888, + "test_b": -4.097475149876053, + "ref_a_norm": -0.9839641677943557, + "ref_b_norm": -0.17836624259304473, + "test_a_norm": -0.9839701116537983, + "test_b_norm": -0.17835262878417507, + "Rcs_pct": 0.0003173727493836111, + "Rhs": -1.451181280226966e-05, + "Rf_h": 99.99815349325311 + }, + { + "bin": 10, + "ref_a": -17.988122649657015, + "ref_b": -12.152577514803381, + "test_a": -17.988304389346204, + "test_b": -12.152289452130033, + "ref_a_norm": -0.8286222905114721, + "ref_b_norm": -0.5598080918203322, + "test_a_norm": -0.8286306623444013, + "test_b_norm": -0.559794822222562, + "Rcs_pct": -4.112688453262384e-05, + "Rhs": -1.5684408484632164e-05, + "Rf_h": 99.99813643492921 + }, + { + "bin": 11, + "ref_a": -10.731221135729598, + "ref_b": -15.926586201616235, + "test_a": -10.731364910326578, + "test_b": -15.926424013221872, + "ref_a_norm": -0.5587849573216191, + "ref_b_norm": -0.8293125897217988, + "test_a_norm": -0.5587924438025164, + "test_b_norm": -0.8293041444168446, + "Rcs_pct": -0.00028627484994255437, + "Rhs": -1.091674141050841e-05, + "Rf_h": 99.99897621405914 + }, + { + "bin": 12, + "ref_a": -6.3973210833032175, + "ref_b": -21.19469432764121, + "test_a": -6.397326691976124, + "test_b": -21.19468166250686, + "ref_a_norm": -0.28895999942073014, + "ref_b_norm": -0.9573411715448007, + "test_a_norm": -0.2889602527583536, + "test_b_norm": -0.9573405994745284, + "Rcs_pct": -5.116543839038093e-05, + "Rhs": -3.600751857156605e-07, + "Rf_h": 99.99991204399312 + }, + { + "bin": 13, + "ref_a": 3.455764185404833, + "ref_b": -17.941587719437408, + "test_a": 3.4558346842791927, + "test_b": -17.941691875644658, + "ref_a_norm": 0.18913549607111174, + "ref_b_norm": -0.9819509988415586, + "test_a_norm": 0.189139354505559, + "test_b_norm": -0.9819566993566603, + "Rcs_pct": 0.000634372452134341, + "Rhs": 2.672180384374638e-06, + "Rf_h": 99.99956247217781 + }, + { + "bin": 14, + "ref_a": 9.649406737373276, + "ref_b": -13.851337352612092, + "test_a": 9.649461083704963, + "test_b": -13.851343113959588, + "ref_a_norm": 0.5716110122170811, + "ref_b_norm": -0.8205247410725433, + "test_a_norm": 0.5716142315820132, + "test_b_norm": -0.8205250823629214, + "Rcs_pct": 0.00020723559039248677, + "Rhs": 2.487193337050201e-06, + "Rf_h": 99.99957407223089 + }, + { + "bin": 15, + "ref_a": 19.086325322231154, + "ref_b": -13.206748447027783, + "test_a": 19.086419070045523, + "test_b": -13.206959414811967, + "ref_a_norm": 0.822330518304195, + "ref_b_norm": -0.5690101217601969, + "test_a_norm": 0.822334557410072, + "test_b_norm": -0.5690192112650851, + "Rcs_pct": 0.0008408252146359298, + "Rhs": -5.3136401121213934e-06, + "Rf_h": 99.9988534915704 + }, + { + "bin": 16, + "ref_a": 17.05724171424712, + "ref_b": -4.0672592476200915, + "test_a": 17.057296374586834, + "test_b": -4.067190784471482, + "ref_a_norm": 0.9727289193841027, + "ref_b_norm": -0.23194492750184473, + "test_a_norm": 0.9727320365172285, + "test_b_norm": -0.23194102323140756, + "Rcs_pct": 0.0002295552910066237, + "Rhs": 4.437373480797696e-06, + "Rf_h": 99.99918968710665 + } + ] + } +} \ No newline at end of file diff --git a/crates/tm30/tests/golden/illuminant_D50.json b/crates/tm30/tests/golden/illuminant_D50.json new file mode 100644 index 0000000..0b4bb20 --- /dev/null +++ b/crates/tm30/tests/golden/illuminant_D50.json @@ -0,0 +1,435 @@ +{ + "name": "illuminant_D50", + "source": "colour.SDS_ILLUMINANTS['D50'] (300.0, 780.0, 5.0)", + "generator": "crates/tm30/tools/golden.py (tm30.py + colour-science 0.4.7, numpy 2.5.1)", + "wavelengths": [ + 300.0, + 305.0, + 310.0, + 315.0, + 320.0, + 325.0, + 330.0, + 335.0, + 340.0, + 345.0, + 350.0, + 355.0, + 360.0, + 365.0, + 370.0, + 375.0, + 380.0, + 385.0, + 390.0, + 395.0, + 400.0, + 405.0, + 410.0, + 415.0, + 420.0, + 425.0, + 430.0, + 435.0, + 440.0, + 445.0, + 450.0, + 455.0, + 460.0, + 465.0, + 470.0, + 475.0, + 480.0, + 485.0, + 490.0, + 495.0, + 500.0, + 505.0, + 510.0, + 515.0, + 520.0, + 525.0, + 530.0, + 535.0, + 540.0, + 545.0, + 550.0, + 555.0, + 560.0, + 565.0, + 570.0, + 575.0, + 580.0, + 585.0, + 590.0, + 595.0, + 600.0, + 605.0, + 610.0, + 615.0, + 620.0, + 625.0, + 630.0, + 635.0, + 640.0, + 645.0, + 650.0, + 655.0, + 660.0, + 665.0, + 670.0, + 675.0, + 680.0, + 685.0, + 690.0, + 695.0, + 700.0, + 705.0, + 710.0, + 715.0, + 720.0, + 725.0, + 730.0, + 735.0, + 740.0, + 745.0, + 750.0, + 755.0, + 760.0, + 765.0, + 770.0, + 775.0, + 780.0 + ], + "values": [ + 0.019, + 1.035, + 2.051, + 4.914, + 7.778, + 11.263, + 14.748, + 16.348, + 17.948, + 19.479, + 21.01, + 22.476, + 23.942, + 25.451, + 26.961, + 25.724, + 24.488, + 27.179, + 29.871, + 39.589, + 49.308, + 52.91, + 56.513, + 58.273, + 60.034, + 58.926, + 57.818, + 66.321, + 74.825, + 81.036, + 87.247, + 88.93, + 90.612, + 90.99, + 91.368, + 93.238, + 95.109, + 93.536, + 91.963, + 93.843, + 95.724, + 96.169, + 96.613, + 96.871, + 97.129, + 99.614, + 102.099, + 101.427, + 100.755, + 101.536, + 102.317, + 101.159, + 100.0, + 98.868, + 97.735, + 98.327, + 98.918, + 96.208, + 93.499, + 95.593, + 97.688, + 98.478, + 99.269, + 99.155, + 99.042, + 97.382, + 95.722, + 97.29, + 98.857, + 97.262, + 95.667, + 96.929, + 98.19, + 100.597, + 103.003, + 101.068, + 99.133, + 93.257, + 87.381, + 89.492, + 91.604, + 92.246, + 92.889, + 84.872, + 76.854, + 81.683, + 86.511, + 89.546, + 92.58, + 85.405, + 78.23, + 67.961, + 57.692, + 70.307, + 82.923, + 80.599, + 78.274 + ], + "expected": { + "Rf": 99.9832901493645, + "Rg": 99.99983345768199, + "CCT_K": 5001.067238721512, + "Duv": 0.003206776575092496, + "bins": [ + { + "bin": 1, + "ref_a": 23.476902397290555, + "ref_b": 4.934814612361608, + "test_a": 23.475905619487904, + "test_b": 4.93343812288507, + "ref_a_norm": 0.9786143669015133, + "ref_b_norm": 0.20570347807937106, + "test_a_norm": 0.9785728170811079, + "test_b_norm": 0.20564610030632277, + "Rcs_pct": -0.005194530047760248, + "Rhs": -4.816930738548327e-05, + "Rf_h": 99.9839228703664 + }, + { + "bin": 2, + "ref_a": 17.83894735047625, + "ref_b": 12.025027476598268, + "test_a": 17.837367424860794, + "test_b": 12.025236710712873, + "ref_a_norm": 0.8291990350997083, + "ref_b_norm": 0.5589534508254805, + "test_a_norm": 0.8291255961926849, + "test_b_norm": 0.5589631765521466, + "Rcs_pct": -0.005565889532046267, + "Rhs": 4.888711686800449e-05, + "Rf_h": 99.98774482339923 + }, + { + "bin": 3, + "ref_a": 14.547664221552239, + "ref_b": 22.064293382121082, + "test_a": 14.546149429750127, + "test_b": 22.064842715001987, + "ref_a_norm": 0.550452873345259, + "ref_b_norm": 0.8348662373254462, + "test_a_norm": 0.5503955568243871, + "test_b_norm": 0.8348870229208595, + "Rcs_pct": -0.001456076189696359, + "Rhs": 5.920480347510379e-05, + "Rf_h": 99.98784937492641 + }, + { + "bin": 4, + "ref_a": 4.076717109026536, + "ref_b": 21.998266602307645, + "test_a": 4.076166231334031, + "test_b": 21.999789542951614, + "ref_a_norm": 0.18221734962954564, + "ref_b_norm": 0.9832582760872058, + "test_a_norm": 0.1821927270054062, + "test_b_norm": 0.9833263470865824, + "Rcs_pct": 0.006195939853868955, + "Rhs": 3.7429500509186814e-05, + "Rf_h": 99.98561707932677 + }, + { + "bin": 5, + "ref_a": -2.054258575968485, + "ref_b": 19.16102293825853, + "test_a": -2.055199500099042, + "test_b": 19.163108325017934, + "ref_a_norm": -0.1065993982477314, + "ref_b_norm": 0.9943020508342632, + "test_a_norm": -0.10664822459670595, + "test_b_norm": 0.9944102655333603, + "Rcs_pct": 0.01156609321421135, + "Rhs": 2.677652387631138e-05, + "Rf_h": 99.98120224919917 + }, + { + "bin": 6, + "ref_a": -10.828082553293017, + "ref_b": 17.50437009420907, + "test_a": -10.828354034540771, + "test_b": 17.5058653726995, + "ref_a_norm": -0.5260751363126394, + "ref_b_norm": 0.8504380935456959, + "test_a_norm": -0.526088326047176, + "test_b_norm": 0.8505107406493551, + "Rcs_pct": 0.006773168300435089, + "Rhs": -2.9393704846565135e-05, + "Rf_h": 99.98808734213112 + }, + { + "bin": 7, + "ref_a": -17.88444758203982, + "ref_b": 11.801800126314143, + "test_a": -17.88494337227294, + "test_b": 11.804004144841127, + "ref_a_norm": -0.8346509266584013, + "ref_b_norm": 0.5507792939356669, + "test_a_norm": -0.8346740647383227, + "test_b_norm": 0.550882153478713, + "Rcs_pct": 0.007638431063998727, + "Rhs": -7.266975592455702e-05, + "Rf_h": 99.98452357318033 + }, + { + "bin": 8, + "ref_a": -22.255349205247978, + "ref_b": 4.3023968277173275, + "test_a": -22.255179526855017, + "test_b": 4.304878130428077, + "ref_a_norm": -0.9818217199390649, + "ref_b_norm": 0.18980545370430352, + "test_a_norm": -0.9818142343709851, + "test_b_norm": 0.18991491938254068, + "Rcs_pct": 0.0014013959428971934, + "Rhs": -0.00010882268781150778, + "Rf_h": 99.98325074316794 + }, + { + "bin": 9, + "ref_a": -18.6309347775359, + "ref_b": -2.5538984750008566, + "test_a": -18.63161578440114, + "test_b": -2.5509714932484395, + "ref_a_norm": -0.9907351240732684, + "ref_b_norm": -0.13580837208186233, + "test_a_norm": -0.9907713378987788, + "test_b_norm": -0.13565272430228137, + "Rcs_pct": 0.0005152611568235503, + "Rhs": -0.0001597220180207308, + "Rf_h": 99.97953815977952 + }, + { + "bin": 10, + "ref_a": -19.80275334617307, + "ref_b": -11.994426214565234, + "test_a": -19.80450778099068, + "test_b": -11.991341290613356, + "ref_a_norm": -0.8553364599157997, + "ref_b_norm": -0.5180729102536704, + "test_a_norm": -0.8554122388764227, + "test_b_norm": -0.5179396637355735, + "Rcs_pct": -0.0011019896098213666, + "Rhs": -0.0001528909655539891, + "Rf_h": 99.97563020595287 + }, + { + "bin": 11, + "ref_a": -12.900334771940969, + "ref_b": -19.322573550217715, + "test_a": -12.902268902100746, + "test_b": -19.319823265146887, + "ref_a_norm": -0.5552548884177753, + "ref_b_norm": -0.831680232353856, + "test_a_norm": -0.5553381370500812, + "test_b_norm": -0.8315618548654329, + "Rcs_pct": -0.00521768223557674, + "Rhs": -0.00013498571685560063, + "Rf_h": 99.97759787759166 + }, + { + "bin": 12, + "ref_a": -3.128242899681709, + "ref_b": -20.746804281216868, + "test_a": -3.1295228205293357, + "test_b": -20.746724255192817, + "ref_a_norm": -0.14909657211816565, + "ref_b_norm": -0.9888226393962734, + "test_a_norm": -0.1491575749932887, + "test_b_norm": -0.9888188252404521, + "Rcs_pct": 0.000816020266496709, + "Rhs": -6.057482687032535e-05, + "Rf_h": 99.99161741874514 + }, + { + "bin": 13, + "ref_a": 2.7176102058558462, + "ref_b": -15.57869260910705, + "test_a": 2.7162101579268594, + "test_b": -15.578861662878905, + "ref_a_norm": 0.17184890000570494, + "ref_b_norm": -0.9851233199791939, + "test_a_norm": 0.17176036755317248, + "test_b_norm": -0.985134010145382, + "Rcs_pct": -0.0006787067031015733, + "Rhs": -8.891687424588761e-05, + "Rf_h": 99.98804851663168 + }, + { + "bin": 14, + "ref_a": 13.613424128801427, + "ref_b": -17.947106267304473, + "test_a": 13.611478159638267, + "test_b": -17.948211404985702, + "ref_a_norm": 0.604340777156097, + "ref_b_norm": -0.7967259410025287, + "test_a_norm": 0.6042543897413468, + "test_b_norm": -0.7967750013828429, + "Rcs_pct": -0.0007202060743431581, + "Rhs": -9.908499717342722e-05, + "Rf_h": 99.983547959729 + }, + { + "bin": 15, + "ref_a": 12.877324738057629, + "ref_b": -8.259933165250223, + "test_a": 12.875106255916956, + "test_b": -8.259244789845068, + "ref_a_norm": 0.8417235542388836, + "ref_b_norm": -0.5399087499193371, + "test_a_norm": 0.8415785436322205, + "test_b_norm": -0.5398637544094417, + "Rcs_pct": -0.014557007881929485, + "Rhs": -4.315117736605328e-05, + "Rf_h": 99.9762059950624 + }, + { + "bin": 16, + "ref_a": 22.83244776608982, + "ref_b": -4.132109648046074, + "test_a": 22.831096464131445, + "test_b": -4.133082083208234, + "ref_a_norm": 0.9840155542122202, + "ref_b_norm": -0.17808253442832928, + "test_a_norm": 0.9839573168230843, + "test_b_norm": -0.17812444370300848, + "Rcs_pct": -0.004894228014100552, + "Rhs": -5.246555071765966e-05, + "Rf_h": 99.98547585324518 + } + ] + } +} \ No newline at end of file diff --git a/crates/tm30/tests/golden/illuminant_D65.json b/crates/tm30/tests/golden/illuminant_D65.json new file mode 100644 index 0000000..9546b70 --- /dev/null +++ b/crates/tm30/tests/golden/illuminant_D65.json @@ -0,0 +1,435 @@ +{ + "name": "illuminant_D65", + "source": "colour.SDS_ILLUMINANTS['D65'] (300.0, 780.0, 5.0)", + "generator": "crates/tm30/tools/golden.py (tm30.py + colour-science 0.4.7, numpy 2.5.1)", + "wavelengths": [ + 300.0, + 305.0, + 310.0, + 315.0, + 320.0, + 325.0, + 330.0, + 335.0, + 340.0, + 345.0, + 350.0, + 355.0, + 360.0, + 365.0, + 370.0, + 375.0, + 380.0, + 385.0, + 390.0, + 395.0, + 400.0, + 405.0, + 410.0, + 415.0, + 420.0, + 425.0, + 430.0, + 435.0, + 440.0, + 445.0, + 450.0, + 455.0, + 460.0, + 465.0, + 470.0, + 475.0, + 480.0, + 485.0, + 490.0, + 495.0, + 500.0, + 505.0, + 510.0, + 515.0, + 520.0, + 525.0, + 530.0, + 535.0, + 540.0, + 545.0, + 550.0, + 555.0, + 560.0, + 565.0, + 570.0, + 575.0, + 580.0, + 585.0, + 590.0, + 595.0, + 600.0, + 605.0, + 610.0, + 615.0, + 620.0, + 625.0, + 630.0, + 635.0, + 640.0, + 645.0, + 650.0, + 655.0, + 660.0, + 665.0, + 670.0, + 675.0, + 680.0, + 685.0, + 690.0, + 695.0, + 700.0, + 705.0, + 710.0, + 715.0, + 720.0, + 725.0, + 730.0, + 735.0, + 740.0, + 745.0, + 750.0, + 755.0, + 760.0, + 765.0, + 770.0, + 775.0, + 780.0 + ], + "values": [ + 0.0341, + 1.6643, + 3.2945, + 11.7652, + 20.236, + 28.6447, + 37.0535, + 38.5011, + 39.9488, + 42.4302, + 44.9117, + 45.775, + 46.6383, + 49.3637, + 52.0891, + 51.0323, + 49.9755, + 52.3118, + 54.6482, + 68.7015, + 82.7549, + 87.1204, + 91.486, + 92.4589, + 93.4318, + 90.057, + 86.6823, + 95.7736, + 104.865, + 110.936, + 117.008, + 117.41, + 117.812, + 116.336, + 114.861, + 115.392, + 115.923, + 112.367, + 108.811, + 109.082, + 109.354, + 108.578, + 107.802, + 106.296, + 104.79, + 106.239, + 107.689, + 106.047, + 104.405, + 104.225, + 104.046, + 102.023, + 100.0, + 98.1671, + 96.3342, + 96.0611, + 95.788, + 92.2368, + 88.6856, + 89.3459, + 90.0062, + 89.8026, + 89.5991, + 88.6489, + 87.6987, + 85.4936, + 83.2886, + 83.4939, + 83.6992, + 81.863, + 80.0268, + 80.1207, + 80.2146, + 81.2462, + 82.2778, + 80.281, + 78.2842, + 74.0027, + 69.7213, + 70.6652, + 71.6091, + 72.979, + 74.349, + 67.9765, + 61.604, + 65.7448, + 69.8856, + 72.4863, + 75.087, + 69.3398, + 63.5927, + 55.0054, + 46.4182, + 56.6118, + 66.8054, + 65.0941, + 63.3828 + ], + "expected": { + "Rf": 99.99244522554164, + "Rg": 100.00121956215816, + "CCT_K": 6501.83224982686, + "Duv": 0.0032141045445623906, + "bins": [ + { + "bin": 1, + "ref_a": 23.82098448657007, + "ref_b": 4.87679865972495, + "test_a": 23.821160302854967, + "test_b": 4.8765061128000555, + "ref_a_norm": 0.9796799988941125, + "ref_b_norm": 0.20056694584809243, + "test_a_norm": 0.9796872296489073, + "test_b_norm": 0.20055491433985567, + "Rcs_pct": 0.00047445870527523186, + "Rhs": -1.3210976460986435e-05, + "Rf_h": 99.99605279472277 + }, + { + "bin": 2, + "ref_a": 18.62450560525995, + "ref_b": 11.890753671989799, + "test_a": 18.624146960395258, + "test_b": 11.891087639908301, + "ref_a_norm": 0.8428653239676316, + "ref_b_norm": 0.538124563324273, + "test_a_norm": 0.8428490932377279, + "test_b_norm": 0.5381396772813245, + "Rcs_pct": -0.0005098494059486001, + "Rhs": 2.1584106404644453e-05, + "Rf_h": 99.9953663488081 + }, + { + "bin": 3, + "ref_a": 13.41229488368166, + "ref_b": 20.708136922053775, + "test_a": 13.412035699930033, + "test_b": 20.70842867846364, + "ref_a_norm": 0.5436201231493497, + "ref_b_norm": 0.8393313777686892, + "test_a_norm": 0.5436096180490518, + "test_b_norm": 0.839343203086939, + "Rcs_pct": 0.0003996071760181326, + "Rhs": 1.5304466487483893e-05, + "Rf_h": 99.99437869743511 + }, + { + "bin": 4, + "ref_a": 4.497250086937527, + "ref_b": 22.85791920520157, + "test_a": 4.497505240525093, + "test_b": 22.85818791759557, + "ref_a_norm": 0.1930470793178648, + "ref_b_norm": 0.9811894950349, + "test_a_norm": 0.19305803193422033, + "test_b_norm": 0.9812010296709188, + "Rcs_pct": 0.0013449750673735648, + "Rhs": -8.491869048160494e-06, + "Rf_h": 99.99473421016543 + }, + { + "bin": 5, + "ref_a": -1.5586795188179994, + "ref_b": 21.50037593581726, + "test_a": -1.5590285200318565, + "test_b": 21.501575110842797, + "ref_a_norm": -0.07230569860211343, + "ref_b_norm": 0.9973825173671635, + "test_a_norm": -0.07232188844503898, + "test_b_norm": 0.99743814598544, + "Rcs_pct": 0.0057718211644451085, + "Rhs": 5.026154580549775e-06, + "Rf_h": 99.98834348039617 + }, + { + "bin": 6, + "ref_a": -10.217046983959596, + "ref_b": 16.76273968019651, + "test_a": -10.21752366701954, + "test_b": 16.763070105182695, + "ref_a_norm": -0.5204538412781571, + "ref_b_norm": 0.8538898050092945, + "test_a_norm": -0.5204781233950945, + "test_b_norm": 0.8539066367762017, + "Rcs_pct": 0.0027485524069864745, + "Rhs": 1.0838613693084403e-05, + "Rf_h": 99.99408013594328 + }, + { + "bin": 7, + "ref_a": -17.900786589543717, + "ref_b": 11.626028528186552, + "test_a": -17.901714573540993, + "test_b": 11.625883549212347, + "ref_a_norm": -0.8386465611395261, + "ref_b_norm": 0.5446760004707818, + "test_a_norm": -0.8386900369155326, + "test_b_norm": 0.5446692082486888, + "Rcs_pct": 0.0032375230209792287, + "Rhs": 2.9801373276962557e-05, + "Rf_h": 99.99373084755142 + }, + { + "bin": 8, + "ref_a": -24.003468458180524, + "ref_b": 2.988107839784543, + "test_a": -24.004187731857947, + "test_b": 2.9887719661165426, + "ref_a_norm": -0.9923404654642813, + "ref_b_norm": 0.12353299398190501, + "test_a_norm": -0.9923702013492053, + "test_b_norm": 0.12356044999038028, + "Rcs_pct": 0.0034520919767941057, + "Rhs": -2.1127265605905687e-05, + "Rf_h": 99.9924518819128 + }, + { + "bin": 9, + "ref_a": -15.682829138461875, + "ref_b": -2.5913518818427894, + "test_a": -15.683498486181422, + "test_b": -2.590471501753139, + "ref_a_norm": -0.9866220266595951, + "ref_b_norm": -0.16302446598628445, + "test_a_norm": -0.9866641359753168, + "test_b_norm": -0.1629690804190113, + "Rcs_pct": 0.003049500887327366, + "Rhs": -6.253646909230542e-05, + "Rf_h": 99.9913408723485 + }, + { + "bin": 10, + "ref_a": -17.34510818830174, + "ref_b": -10.667088018297028, + "test_a": -17.346258473664765, + "test_b": -10.665436755235996, + "ref_a_norm": -0.851807880237721, + "ref_b_norm": -0.5238543071932504, + "test_a_norm": -0.8518643700633312, + "test_b_norm": -0.5237732146527795, + "Rcs_pct": 0.0001916971793549633, + "Rhs": -9.881004876344647e-05, + "Rf_h": 99.98660145516835 + }, + { + "bin": 11, + "ref_a": -14.294616636351853, + "ref_b": -21.235090875195265, + "test_a": -14.295672963416688, + "test_b": -21.233533565349557, + "ref_a_norm": -0.5584238743718227, + "ref_b_norm": -0.8295557705974702, + "test_a_norm": -0.5584651401341132, + "test_b_norm": -0.8294949337789839, + "Rcs_pct": -0.002765793670910907, + "Rhs": -6.811035279568195e-05, + "Rf_h": 99.98768382951182 + }, + { + "bin": 12, + "ref_a": -3.7486150572267056, + "ref_b": -20.755101033422942, + "test_a": -3.7489130274456035, + "test_b": -20.754904452646418, + "ref_a_norm": -0.1777360812284449, + "ref_b_norm": -0.984078190709232, + "test_a_norm": -0.17775020912854164, + "test_b_norm": -0.9840688700677869, + "Rcs_pct": -0.000638533135403464, + "Rhs": -1.5674803398836643e-05, + "Rf_h": 99.99734076653297 + }, + { + "bin": 13, + "ref_a": 1.903150415638521, + "ref_b": -15.820468782733457, + "test_a": 1.9030860882842735, + "test_b": -15.82018097391874, + "ref_a_norm": 0.11943562419036355, + "ref_b_norm": -0.9928419469755789, + "test_a_norm": 0.11943158721165502, + "test_b_norm": -0.9928238850162348, + "Rcs_pct": -0.0018502479336261132, + "Rhs": -4.3569582992788047e-07, + "Rf_h": 99.99488322294361 + }, + { + "bin": 14, + "ref_a": 12.608405843070699, + "ref_b": -18.774763719510062, + "test_a": 12.608197253376927, + "test_b": -18.774364125850727, + "ref_a_norm": 0.5575101679314969, + "ref_b_norm": -0.8301701106718997, + "test_a_norm": 0.5575009446500884, + "test_b_norm": -0.8301524417032059, + "Rcs_pct": -0.0019815391150970006, + "Rhs": 2.1474748375376244e-06, + "Rf_h": 99.99425017617709 + }, + { + "bin": 15, + "ref_a": 12.088472495367219, + "ref_b": -8.349869751429393, + "test_a": 12.088196540398116, + "test_b": -8.348577535004525, + "ref_a_norm": 0.82279927261926, + "ref_b_norm": -0.5683320833607906, + "test_a_norm": 0.8227804898038182, + "test_b_norm": -0.5682441289285944, + "Rcs_pct": -0.006448220466365075, + "Rhs": 6.269626448663806e-05, + "Rf_h": 99.9887294477191 + }, + { + "bin": 16, + "ref_a": 22.585949520225732, + "ref_b": -3.8918436838877772, + "test_a": 22.58599775884995, + "test_b": -3.891759058186969, + "ref_a_norm": 0.985476808341529, + "ref_b_norm": -0.16981007102346227, + "test_a_norm": 0.9854789131034026, + "test_b_norm": -0.16980637860993494, + "Rcs_pct": 0.00013439653204384277, + "Rhs": 4.032083508483764e-06, + "Rf_h": 99.99555479243523 + } + ] + } +} \ No newline at end of file diff --git a/crates/tm30/tests/golden/illuminant_FL1.json b/crates/tm30/tests/golden/illuminant_FL1.json new file mode 100644 index 0000000..8b33f94 --- /dev/null +++ b/crates/tm30/tests/golden/illuminant_FL1.json @@ -0,0 +1,403 @@ +{ + "name": "illuminant_FL1", + "source": "colour.SDS_ILLUMINANTS['FL1'] (380.0, 780.0, 5.0)", + "generator": "crates/tm30/tools/golden.py (tm30.py + colour-science 0.4.7, numpy 2.5.1)", + "wavelengths": [ + 380.0, + 385.0, + 390.0, + 395.0, + 400.0, + 405.0, + 410.0, + 415.0, + 420.0, + 425.0, + 430.0, + 435.0, + 440.0, + 445.0, + 450.0, + 455.0, + 460.0, + 465.0, + 470.0, + 475.0, + 480.0, + 485.0, + 490.0, + 495.0, + 500.0, + 505.0, + 510.0, + 515.0, + 520.0, + 525.0, + 530.0, + 535.0, + 540.0, + 545.0, + 550.0, + 555.0, + 560.0, + 565.0, + 570.0, + 575.0, + 580.0, + 585.0, + 590.0, + 595.0, + 600.0, + 605.0, + 610.0, + 615.0, + 620.0, + 625.0, + 630.0, + 635.0, + 640.0, + 645.0, + 650.0, + 655.0, + 660.0, + 665.0, + 670.0, + 675.0, + 680.0, + 685.0, + 690.0, + 695.0, + 700.0, + 705.0, + 710.0, + 715.0, + 720.0, + 725.0, + 730.0, + 735.0, + 740.0, + 745.0, + 750.0, + 755.0, + 760.0, + 765.0, + 770.0, + 775.0, + 780.0 + ], + "values": [ + 1.87, + 2.36, + 2.94, + 3.47, + 5.17, + 19.49, + 6.13, + 6.24, + 7.01, + 7.79, + 8.56, + 43.67, + 16.94, + 10.72, + 11.35, + 11.89, + 12.37, + 12.75, + 13.0, + 13.15, + 13.23, + 13.17, + 13.13, + 12.85, + 12.52, + 12.2, + 11.83, + 11.5, + 11.22, + 11.05, + 11.03, + 11.18, + 11.53, + 27.74, + 17.05, + 13.55, + 14.33, + 15.01, + 15.52, + 18.29, + 19.55, + 15.48, + 14.91, + 14.15, + 13.22, + 12.19, + 11.12, + 10.03, + 8.95, + 7.96, + 7.02, + 6.2, + 5.42, + 4.73, + 4.15, + 3.64, + 3.2, + 2.81, + 2.47, + 2.18, + 1.93, + 1.72, + 1.67, + 1.43, + 1.29, + 1.19, + 1.08, + 0.96, + 0.88, + 0.81, + 0.77, + 0.75, + 0.73, + 0.68, + 0.69, + 0.64, + 0.68, + 0.69, + 0.61, + 0.52, + 0.43 + ], + "expected": { + "Rf": 80.68635150076496, + "Rg": 89.83122589763414, + "CCT_K": 6425.332064634875, + "Duv": 0.007191578880652916, + "bins": [ + { + "bin": 1, + "ref_a": 23.84545563235572, + "ref_b": 4.906172452718242, + "test_a": 19.196227550388294, + "test_b": 3.3710504271902475, + "ref_a_norm": 0.9794828836931113, + "ref_b_norm": 0.20152736923859008, + "test_a_norm": 0.788509836296467, + "test_b_norm": 0.13847024961095286, + "Rcs_pct": -19.960538761394243, + "Rhs": -0.024588501442399557, + "Rf_h": 64.59135692073266 + }, + { + "bin": 2, + "ref_a": 18.638426643931336, + "ref_b": 11.906702780414134, + "test_a": 15.239327251756684, + "test_b": 11.876659898824421, + "ref_a_norm": 0.842720483642813, + "ref_b_norm": 0.5383513596609776, + "test_a_norm": 0.689033118370697, + "test_b_norm": 0.5369929965229844, + "Rcs_pct": -12.854104014370607, + "Rhs": 0.08425468766468491, + "Rf_h": 76.32490250303407 + }, + { + "bin": 3, + "ref_a": 13.437851168100572, + "ref_b": 20.705789280444236, + "test_a": 9.227529768831102, + "test_b": 21.32604918707949, + "ref_a_norm": 0.5443926566963092, + "ref_b_norm": 0.8388305164543876, + "test_a_norm": 0.3738246080238658, + "test_b_norm": 0.8639584133324938, + "Rcs_pct": -7.386944787143087, + "Rhs": 0.1557824608247402, + "Rf_h": 70.61853696747318 + }, + { + "bin": 4, + "ref_a": 4.500166433308781, + "ref_b": 22.850186739742863, + "test_a": 2.027644608702062, + "test_b": 23.806474278526455, + "ref_a_norm": 0.19323052278636993, + "ref_b_norm": 0.9811533850849756, + "test_a_norm": 0.08706407497830874, + "test_b_norm": 1.0222149644269158, + "Rcs_pct": 1.956054611850115, + "Rhs": 0.11213720601915415, + "Rf_h": 81.79794154233632 + }, + { + "bin": 5, + "ref_a": -1.5455095435706714, + "ref_b": 21.477147820771552, + "test_a": -3.038540869239471, + "test_b": 22.643252905260333, + "ref_a_norm": -0.07177505353580191, + "ref_b_norm": 0.9974208448242561, + "test_a_norm": -0.14111296463205078, + "test_b_norm": 1.0515759648723555, + "Rcs_pct": 6.664170000533863, + "Rhs": 0.05744046276810292, + "Rf_h": 86.5670385816704 + }, + { + "bin": 6, + "ref_a": -10.214152992326397, + "ref_b": 16.735602933463987, + "test_a": -9.659384323889181, + "test_b": 17.40524137640265, + "ref_a_norm": -0.5209612254290433, + "ref_b_norm": 0.8535803427911572, + "test_a_norm": -0.4926658821386288, + "test_b_norm": 0.8877344879356257, + "Rcs_pct": 1.2678083356570764, + "Rhs": -0.04250174449214606, + "Rf_h": 91.91278107565986 + }, + { + "bin": 7, + "ref_a": -17.90146696240191, + "ref_b": 11.589220763399673, + "test_a": -16.403192936120337, + "test_b": 11.79684392025738, + "ref_a_norm": -0.8394435498861129, + "ref_b_norm": 0.5434468939598434, + "test_a_norm": -0.7691858179379145, + "test_b_norm": 0.5531828513647448, + "Rcs_pct": -5.300816102011461, + "Rhs": -0.04712825723873676, + "Rf_h": 88.98677601301469 + }, + { + "bin": 8, + "ref_a": -24.016703343553253, + "ref_b": 2.9355783668624964, + "test_a": -21.371682571257505, + "test_b": 3.661146050517676, + "ref_a_norm": -0.9926125049533571, + "ref_b_norm": 0.12132771740299805, + "test_a_norm": -0.883293559014555, + "test_b_norm": 0.15131549489617746, + "Rcs_pct": -10.136808787828123, + "Rhs": -0.05073863912298229, + "Rf_h": 81.36325095864356 + }, + { + "bin": 9, + "ref_a": -15.676294344694927, + "ref_b": -2.6302452225859736, + "test_a": -13.837755995725079, + "test_b": -2.6764596636557663, + "ref_a_norm": -0.9862145075057146, + "ref_b_norm": -0.1654718863893829, + "test_a_norm": -0.870549851529586, + "test_b_norm": -0.1683792923896231, + "Rcs_pct": -11.287498527147196, + "Rhs": 0.02541659598945924, + "Rf_h": 86.93160766242093 + }, + { + "bin": 10, + "ref_a": -19.7412555043754, + "ref_b": -12.01550386426426, + "test_a": -17.12795602587164, + "test_b": -12.971250840454308, + "ref_a_norm": -0.8542160922316222, + "ref_b_norm": -0.5199181356449656, + "test_a_norm": -0.7411370396929601, + "test_b_norm": -0.5612738866498752, + "Rcs_pct": -7.104577175136221, + "Rhs": 0.09720940582307314, + "Rf_h": 79.63284614306279 + }, + { + "bin": 11, + "ref_a": -12.846383680356727, + "ref_b": -18.95754527063295, + "test_a": -10.824372778241674, + "test_b": -19.96202912162869, + "ref_a_norm": -0.5609731228833786, + "ref_b_norm": -0.8278340144029296, + "test_a_norm": -0.47267638517982113, + "test_b_norm": -0.8716975994241856, + "Rcs_pct": -1.2583801109012647, + "Rhs": 0.09778535641729073, + "Rf_h": 83.11379784707698 + }, + { + "bin": 12, + "ref_a": -3.7268362334707743, + "ref_b": -20.756183680588947, + "test_a": -3.2965530791692075, + "test_b": -21.774859756281227, + "ref_a_norm": -0.17672687943314744, + "ref_b_norm": -0.9842599301433649, + "test_a_norm": -0.1563228170143517, + "test_b_norm": -1.0325656330861108, + "Rcs_pct": 4.3396887298056175, + "Rhs": 0.029435979223099373, + "Rf_h": 90.69751508783315 + }, + { + "bin": 13, + "ref_a": 1.9320755209129488, + "ref_b": -15.813168027714688, + "test_a": 0.8214106968825274, + "test_b": -17.07722891601317, + "ref_a_norm": 0.12127953710017789, + "ref_b_norm": -0.9926183928785355, + "test_a_norm": 0.05156129147579834, + "test_b_norm": -1.0719655600776932, + "Rcs_pct": 6.4221178641368155, + "Rhs": -0.08385849348387965, + "Rf_h": 86.3889380300713 + }, + { + "bin": 14, + "ref_a": 12.644137752458889, + "ref_b": -18.745395882492314, + "test_a": 10.227768158658787, + "test_b": -20.945620238816783, + "ref_a_norm": 0.5591992435318452, + "ref_b_norm": -0.8290332960945611, + "test_a_norm": 0.45233295692534276, + "test_b_norm": -0.9263403501416207, + "Rcs_pct": 2.153613075089739, + "Rhs": -0.14291697258429717, + "Rf_h": 76.18103310538777 + }, + { + "bin": 15, + "ref_a": 12.134844305768967, + "ref_b": -8.333707532823212, + "test_a": 8.774575546452754, + "test_b": -10.981149400115354, + "ref_a_norm": 0.8243271705458667, + "ref_b_norm": -0.5661136952060475, + "test_a_norm": 0.5960621208390525, + "test_b_norm": -0.7459559913789034, + "Rcs_pct": -8.988042599041204, + "Rhs": -0.27635067113028994, + "Rf_h": 69.88863172005391 + }, + { + "bin": 16, + "ref_a": 22.602055439637944, + "ref_b": -3.85468361471771, + "test_a": 19.79836415491462, + "test_b": -5.659498435447576, + "ref_a_norm": 0.9857668262702481, + "ref_b_norm": -0.16811830425353003, + "test_a_norm": 0.8634865377821345, + "test_b_norm": -0.24683356015526875, + "Rcs_pct": -10.457412241115028, + "Rhs": -0.10105846518897006, + "Rf_h": 76.1742320974876 + } + ] + } +} \ No newline at end of file diff --git a/crates/tm30/tests/golden/illuminant_FL10.json b/crates/tm30/tests/golden/illuminant_FL10.json new file mode 100644 index 0000000..3ed2461 --- /dev/null +++ b/crates/tm30/tests/golden/illuminant_FL10.json @@ -0,0 +1,403 @@ +{ + "name": "illuminant_FL10", + "source": "colour.SDS_ILLUMINANTS['FL10'] (380.0, 780.0, 5.0)", + "generator": "crates/tm30/tools/golden.py (tm30.py + colour-science 0.4.7, numpy 2.5.1)", + "wavelengths": [ + 380.0, + 385.0, + 390.0, + 395.0, + 400.0, + 405.0, + 410.0, + 415.0, + 420.0, + 425.0, + 430.0, + 435.0, + 440.0, + 445.0, + 450.0, + 455.0, + 460.0, + 465.0, + 470.0, + 475.0, + 480.0, + 485.0, + 490.0, + 495.0, + 500.0, + 505.0, + 510.0, + 515.0, + 520.0, + 525.0, + 530.0, + 535.0, + 540.0, + 545.0, + 550.0, + 555.0, + 560.0, + 565.0, + 570.0, + 575.0, + 580.0, + 585.0, + 590.0, + 595.0, + 600.0, + 605.0, + 610.0, + 615.0, + 620.0, + 625.0, + 630.0, + 635.0, + 640.0, + 645.0, + 650.0, + 655.0, + 660.0, + 665.0, + 670.0, + 675.0, + 680.0, + 685.0, + 690.0, + 695.0, + 700.0, + 705.0, + 710.0, + 715.0, + 720.0, + 725.0, + 730.0, + 735.0, + 740.0, + 745.0, + 750.0, + 755.0, + 760.0, + 765.0, + 770.0, + 775.0, + 780.0 + ], + "values": [ + 1.11, + 0.8, + 0.62, + 0.57, + 1.48, + 12.16, + 2.12, + 2.7, + 3.74, + 5.14, + 6.75, + 34.39, + 14.86, + 10.4, + 10.76, + 10.67, + 10.11, + 9.27, + 8.29, + 7.29, + 7.91, + 16.64, + 16.73, + 10.44, + 5.94, + 3.34, + 2.35, + 1.88, + 1.59, + 1.47, + 1.8, + 5.71, + 40.98, + 73.69, + 33.61, + 8.24, + 3.38, + 2.47, + 2.14, + 4.86, + 11.45, + 14.79, + 12.16, + 8.97, + 6.52, + 8.31, + 44.12, + 34.55, + 12.09, + 12.15, + 10.52, + 4.43, + 1.95, + 2.19, + 3.19, + 2.77, + 2.29, + 2.0, + 1.52, + 1.35, + 1.47, + 1.79, + 1.74, + 1.02, + 1.14, + 3.32, + 4.49, + 2.05, + 0.49, + 0.24, + 0.21, + 0.21, + 0.24, + 0.24, + 0.21, + 0.17, + 0.21, + 0.22, + 0.17, + 0.12, + 0.09 + ], + "expected": { + "Rf": 79.56750526577619, + "Rg": 99.2291970428991, + "CCT_K": 4998.734114560273, + "Duv": 0.0033830977769216952, + "bins": [ + { + "bin": 1, + "ref_a": 23.478048548906422, + "ref_b": 4.936029320096617, + "test_a": 21.334629951559386, + "test_b": 3.650071461515925, + "ref_a_norm": 0.978606195346642, + "ref_b_norm": 0.20574234962488896, + "test_a_norm": 0.8892647530962074, + "test_b_norm": 0.15214137317489423, + "Rcs_pct": -9.808180324522974, + "Rhs": -0.035141397979372456, + "Rf_h": 80.64163950414984 + }, + { + "bin": 2, + "ref_a": 17.83960936345097, + "ref_b": 12.025749276090735, + "test_a": 17.618767668834742, + "test_b": 11.825388001970724, + "ref_a_norm": 0.8291930990230103, + "ref_b_norm": 0.5589622568050694, + "test_a_norm": 0.8189282773320438, + "test_b_norm": 0.5496493743070844, + "Rcs_pct": -1.3708847611232395, + "Rhs": -0.0020405494212637453, + "Rf_h": 91.54573056608551 + }, + { + "bin": 3, + "ref_a": 14.548311940161327, + "ref_b": 22.06455529358777, + "test_a": 11.67578941345396, + "test_b": 22.826993992709497, + "ref_a_norm": 0.55046540107182, + "ref_b_norm": 0.8348579772768782, + "test_a_norm": 0.44177758414463675, + "test_b_norm": 0.8637064186651966, + "Rcs_pct": -3.6397113399949164, + "Rhs": 0.10639795230681547, + "Rf_h": 78.75691316591744 + }, + { + "bin": 4, + "ref_a": 4.0765091347059546, + "ref_b": 21.998256825337414, + "test_a": 0.35339496846738416, + "test_b": 23.74174945540553, + "ref_a_norm": 0.18220844070602263, + "ref_b_norm": 0.9832599270464957, + "test_a_norm": 0.01579575662166173, + "test_b_norm": 1.0611891216121465, + "Rcs_pct": 4.396630281808363, + "Rhs": 0.17841834268460446, + "Rf_h": 71.36383996937295 + }, + { + "bin": 5, + "ref_a": -2.054326416312341, + "ref_b": 19.16069469267776, + "test_a": -4.528320720207391, + "test_b": 20.89169454571495, + "ref_a_norm": -0.1066046840877035, + "ref_b_norm": 0.994301484123684, + "test_a_norm": -0.2349870964966041, + "test_b_norm": 1.084127857879876, + "Rcs_pct": 11.314655135013192, + "Rhs": 0.10839132417167013, + "Rf_h": 75.64945029216233 + }, + { + "bin": 6, + "ref_a": -10.828656173533247, + "ref_b": 17.503525680508954, + "test_a": -11.716955732083225, + "test_b": 18.969720255122915, + "ref_a_norm": -0.5261136471084243, + "ref_b_norm": 0.850414269827519, + "test_a_norm": -0.5692719589971879, + "test_b_norm": 0.921649791822031, + "Rcs_pct": 8.320764524771935, + "Rhs": -0.0036915106999815114, + "Rf_h": 87.05456873888518 + }, + { + "bin": 7, + "ref_a": -17.885205521125236, + "ref_b": 11.800516679875843, + "test_a": -16.370232151831484, + "test_b": 13.428811603303464, + "ref_a_norm": -0.8346891905349909, + "ref_b_norm": 0.5507213044762672, + "test_a_norm": -0.763986514303272, + "test_b_norm": 0.6267126130459507, + "Rcs_pct": -1.6568617785616169, + "Rhs": -0.10246476618396348, + "Rf_h": 82.72153711751575 + }, + { + "bin": 8, + "ref_a": -22.256526198656072, + "ref_b": 4.300785776390535, + "test_a": -20.670583550861394, + "test_b": 5.664985391754845, + "ref_a_norm": -0.9818368318039067, + "ref_b_norm": 0.1897272666573442, + "test_a_norm": -0.9118736717476239, + "test_b_norm": 0.2499083306896226, + "Rcs_pct": -5.687809439236694, + "Rhs": -0.07267383718650906, + "Rf_h": 84.68556771969051 + }, + { + "bin": 9, + "ref_a": -18.631238026086677, + "ref_b": -2.555202190011908, + "test_a": -16.292387172610905, + "test_b": -2.0165719282833097, + "ref_a_norm": -0.9907260915108704, + "ref_b_norm": -0.13587424921446478, + "test_a_norm": -0.8663564408496248, + "test_b_norm": -0.10723229567253278, + "Rcs_pct": -12.756769063710811, + "Rhs": -0.0038282912393842712, + "Rf_h": 82.40904698894653 + }, + { + "bin": 10, + "ref_a": -19.802367592246632, + "ref_b": -11.99569767098627, + "test_a": -15.053306832469303, + "test_b": -13.550881034287931, + "ref_a_norm": -0.8553076514577993, + "ref_b_norm": -0.5181204699273555, + "test_a_norm": -0.6501853100936319, + "test_b_norm": -0.5852922474360506, + "Rcs_pct": -13.323435356580807, + "Rhs": 0.16981115879204436, + "Rf_h": 65.47520384695693 + }, + { + "bin": 11, + "ref_a": -12.899473288119605, + "ref_b": -19.32315722831776, + "test_a": -9.042346525041822, + "test_b": -20.582528169442565, + "ref_a_norm": -0.5552176385179455, + "ref_b_norm": -0.8317051003081297, + "test_a_norm": -0.38919963413688496, + "test_b_norm": -0.8859107988147052, + "Rcs_pct": -4.71642702575841, + "Rhs": 0.16815399828825112, + "Rf_h": 71.70431557405588 + }, + { + "bin": 12, + "ref_a": -3.1267019351858623, + "ref_b": -20.746825733951585, + "test_a": -0.9169277287715565, + "test_b": -22.099014178161323, + "ref_a_norm": -0.1490246083311743, + "ref_b_norm": -0.9888334875557866, + "test_a_norm": -0.04370253336605678, + "test_b_norm": -1.053281381044015, + "Rcs_pct": 4.2662227765897995, + "Rhs": 0.11587150112119247, + "Rf_h": 81.24856085153684 + }, + { + "bin": 13, + "ref_a": 2.719435982264411, + "ref_b": -15.57819868362037, + "test_a": 3.289433992712317, + "test_b": -16.946481147391577, + "ref_a_norm": 0.17196623160832197, + "ref_b_norm": -0.9851028449793621, + "test_a_norm": 0.2080106211509462, + "test_b_norm": -1.0716275437055138, + "Rcs_pct": 9.189406246467914, + "Rhs": 0.018471675367692522, + "Rf_h": 82.8017102608967 + }, + { + "bin": 14, + "ref_a": 13.615717141905293, + "ref_b": -17.945652593830204, + "test_a": 15.291949151044584, + "test_b": -19.00830893861863, + "ref_a_norm": 0.604436459884668, + "ref_b_norm": -0.7966533537003971, + "test_a_norm": 0.6788486800409792, + "test_b_norm": -0.8438273829802105, + "Rcs_pct": 8.05649863277831, + "Rhs": 0.03566301340448031, + "Rf_h": 82.4897167342872 + }, + { + "bin": 15, + "ref_a": 12.879380505158682, + "ref_b": -8.25859554619101, + "test_a": 12.113561341455846, + "test_b": -10.228374020414362, + "ref_a_norm": 0.8418024448444471, + "ref_b_norm": -0.5397857388389504, + "test_a_norm": 0.7917481395107734, + "test_b_norm": -0.6685313982081278, + "Rcs_pct": 2.990862212613324, + "Rhs": -0.1348567855591888, + "Rf_h": 81.0017165925025 + }, + { + "bin": 16, + "ref_a": 22.833779955015594, + "ref_b": -4.13047720948513, + "test_a": 23.214490581355108, + "test_b": -6.288328842486212, + "ref_a_norm": 0.9840296997490656, + "ref_b_norm": -0.1780043539123803, + "test_a_norm": 1.0004365567857105, + "test_b_norm": -0.270997721576794, + "Rcs_pct": 3.4233709922236293, + "Rhs": -0.08800570715783108, + "Rf_h": 82.3965310325132 + } + ] + } +} \ No newline at end of file diff --git a/crates/tm30/tests/golden/illuminant_FL11.json b/crates/tm30/tests/golden/illuminant_FL11.json new file mode 100644 index 0000000..ec3345a --- /dev/null +++ b/crates/tm30/tests/golden/illuminant_FL11.json @@ -0,0 +1,403 @@ +{ + "name": "illuminant_FL11", + "source": "colour.SDS_ILLUMINANTS['FL11'] (380.0, 780.0, 5.0)", + "generator": "crates/tm30/tools/golden.py (tm30.py + colour-science 0.4.7, numpy 2.5.1)", + "wavelengths": [ + 380.0, + 385.0, + 390.0, + 395.0, + 400.0, + 405.0, + 410.0, + 415.0, + 420.0, + 425.0, + 430.0, + 435.0, + 440.0, + 445.0, + 450.0, + 455.0, + 460.0, + 465.0, + 470.0, + 475.0, + 480.0, + 485.0, + 490.0, + 495.0, + 500.0, + 505.0, + 510.0, + 515.0, + 520.0, + 525.0, + 530.0, + 535.0, + 540.0, + 545.0, + 550.0, + 555.0, + 560.0, + 565.0, + 570.0, + 575.0, + 580.0, + 585.0, + 590.0, + 595.0, + 600.0, + 605.0, + 610.0, + 615.0, + 620.0, + 625.0, + 630.0, + 635.0, + 640.0, + 645.0, + 650.0, + 655.0, + 660.0, + 665.0, + 670.0, + 675.0, + 680.0, + 685.0, + 690.0, + 695.0, + 700.0, + 705.0, + 710.0, + 715.0, + 720.0, + 725.0, + 730.0, + 735.0, + 740.0, + 745.0, + 750.0, + 755.0, + 760.0, + 765.0, + 770.0, + 775.0, + 780.0 + ], + "values": [ + 0.91, + 0.63, + 0.46, + 0.37, + 1.29, + 12.68, + 1.59, + 1.79, + 2.46, + 3.33, + 4.49, + 33.94, + 12.13, + 6.95, + 7.19, + 7.12, + 6.72, + 6.13, + 5.46, + 4.79, + 5.66, + 14.29, + 14.96, + 8.97, + 4.72, + 2.33, + 1.47, + 1.1, + 0.89, + 0.83, + 1.18, + 4.9, + 39.59, + 72.84, + 32.61, + 7.52, + 2.83, + 1.96, + 1.67, + 4.43, + 11.28, + 14.76, + 12.73, + 9.74, + 7.33, + 9.72, + 55.27, + 42.58, + 13.18, + 13.16, + 12.26, + 5.11, + 2.07, + 2.34, + 3.58, + 3.01, + 2.48, + 2.14, + 1.54, + 1.33, + 1.46, + 1.94, + 2.0, + 1.2, + 1.35, + 4.1, + 5.58, + 2.51, + 0.57, + 0.27, + 0.23, + 0.21, + 0.24, + 0.24, + 0.2, + 0.24, + 0.32, + 0.26, + 0.16, + 0.12, + 0.09 + ], + "expected": { + "Rf": 80.14806264977813, + "Rg": 100.9613884356507, + "CCT_K": 4000.699316695891, + "Duv": 0.000154237942531646, + "bins": [ + { + "bin": 1, + "ref_a": 21.534053290620133, + "ref_b": 5.053585696736461, + "test_a": 19.940668068850904, + "test_b": 3.9056279677503465, + "ref_a_norm": 0.9735505608229065, + "ref_b_norm": 0.22847167334574373, + "test_a_norm": 0.9015139100667733, + "test_b_norm": 0.1765727170381438, + "Rcs_pct": -8.077747080951433, + "Rhs": -0.036848079021806986, + "Rf_h": 81.69864138699103 + }, + { + "bin": 2, + "ref_a": 20.62507579605772, + "ref_b": 14.421738069109516, + "test_a": 20.519750607150677, + "test_b": 14.266682021301463, + "ref_a_norm": 0.8195270337259007, + "ref_b_norm": 0.5730405229932928, + "test_a_norm": 0.8153419902140554, + "test_b_norm": 0.5668794487660803, + "Rcs_pct": -0.6902645950326755, + "Rhs": -0.0027976603999945106, + "Rf_h": 92.69598199966805 + }, + { + "bin": 3, + "ref_a": 14.615395277189476, + "ref_b": 22.321973372539844, + "test_a": 12.174400800180106, + "test_b": 23.092771921227527, + "ref_a_norm": 0.5477811531046525, + "ref_b_norm": 0.8366216637783996, + "test_a_norm": 0.4562933251000848, + "test_b_norm": 0.8655109897120274, + "Rcs_pct": -2.6807317289239547, + "Rhs": 0.09211939842208465, + "Rf_h": 80.9259429275031 + }, + { + "bin": 4, + "ref_a": 3.736163971569656, + "ref_b": 22.134381528835362, + "test_a": 0.2167285185220803, + "test_b": 23.917134119728548, + "ref_a_norm": 0.16644017310603096, + "ref_b_norm": 0.9860515548268429, + "test_a_norm": 0.00965491140493863, + "test_b_norm": 1.0654703523130857, + "Rcs_pct": 4.730550036918292, + "Rhs": 0.1692665156363245, + "Rf_h": 72.34218812453666 + }, + { + "bin": 5, + "ref_a": -2.230734277566569, + "ref_b": 19.11367062435309, + "test_a": -4.752115175353902, + "test_b": 20.978184233997446, + "ref_a_norm": -0.11592202345469897, + "ref_b_norm": 0.9932583170948874, + "test_a_norm": -0.2469477482623956, + "test_b_norm": 1.090149368872052, + "Rcs_pct": 12.059116823096048, + "Rhs": 0.10960559575386483, + "Rf_h": 75.08315104549725 + }, + { + "bin": 6, + "ref_a": -11.177820690697972, + "ref_b": 17.114853916021826, + "test_a": -12.364802280908782, + "test_b": 18.726579959041235, + "ref_a_norm": -0.5468154178172248, + "ref_b_norm": 0.8372531868182849, + "test_a_norm": -0.6048821780697502, + "test_b_norm": 0.9160983100321489, + "Rcs_pct": 9.78174875547669, + "Rhs": 0.004476743158446503, + "Rf_h": 85.35904249030229 + }, + { + "bin": 7, + "ref_a": -18.253925799154096, + "ref_b": 11.16192659417812, + "test_a": -17.122926190000513, + "test_b": 13.058162135409987, + "ref_a_norm": -0.8531414388165253, + "ref_b_norm": 0.5216796769801074, + "test_a_norm": -0.8002814324556508, + "test_b_norm": 0.6103048382622113, + "Rcs_pct": 0.5286012509711869, + "Rhs": -0.10305657454281009, + "Rf_h": 82.92316332807208 + }, + { + "bin": 8, + "ref_a": -22.840170261092695, + "ref_b": 3.4715684003557246, + "test_a": -21.752493975808783, + "test_b": 5.01291580860449, + "ref_a_norm": -0.9886452794682653, + "ref_b_norm": 0.15026813163513986, + "test_a_norm": -0.9415648062168337, + "test_b_norm": 0.21698592847142686, + "Rcs_pct": -3.315983869042425, + "Rhs": -0.07462077776525704, + "Rf_h": 85.36870813324033 + }, + { + "bin": 9, + "ref_a": -19.3610990027732, + "ref_b": -2.2281484175655657, + "test_a": -18.08673726001779, + "test_b": -1.1089101146248912, + "ref_a_norm": -0.9934429234163967, + "ref_b_norm": -0.11432916475634447, + "test_a_norm": -0.9280537812488157, + "test_b_norm": -0.05689960605651412, + "Rcs_pct": -7.533665923615173, + "Rhs": -0.043569277031015104, + "Rf_h": 87.80663399682783 + }, + { + "bin": 10, + "ref_a": -20.087697186814637, + "ref_b": -11.374583960721276, + "test_a": -15.621827186217237, + "test_b": -12.309353698821846, + "ref_a_norm": -0.8701790471937452, + "ref_b_norm": -0.49273565511842715, + "test_a_norm": -0.6767220040160047, + "test_b_norm": -0.5332289497196531, + "Rcs_pct": -13.835678357085825, + "Rhs": 0.14114791852047454, + "Rf_h": 68.28243435650182 + }, + { + "bin": 11, + "ref_a": -11.959029103702564, + "ref_b": -17.411182807601225, + "test_a": -8.460583147582156, + "test_b": -18.379475801181744, + "ref_a_norm": -0.5661700308369788, + "ref_b_norm": -0.824288478739121, + "test_a_norm": -0.4005449422380258, + "test_b_norm": -0.8701298651326856, + "Rcs_pct": -5.390064929474432, + "Rhs": 0.16318033792556047, + "Rf_h": 74.23333672054656 + }, + { + "bin": 12, + "ref_a": -7.899904980899336, + "ref_b": -24.369728820707117, + "test_a": -4.644222543699326, + "test_b": -25.723852969842962, + "ref_a_norm": -0.3083708035356244, + "ref_b_norm": -0.9512662337783221, + "test_a_norm": -0.18128605863760472, + "test_b_norm": -1.0041241292803105, + "Rcs_pct": 2.7049242055950073, + "Rhs": 0.13495491101435503, + "Rf_h": 74.78953391229516 + }, + { + "bin": 13, + "ref_a": 3.373263244633737, + "ref_b": -17.974767350031367, + "test_a": 3.295124337283678, + "test_b": -19.652406760902704, + "ref_a_norm": 0.18444670105795574, + "ref_b_norm": -0.9828425176338462, + "test_a_norm": 0.18017414281397068, + "test_b_norm": -1.0745741829262856, + "Rcs_pct": 8.913553230204883, + "Rhs": -0.022086422356343734, + "Rf_h": 82.31987402636771 + }, + { + "bin": 14, + "ref_a": 10.365135926944294, + "ref_b": -14.459034121252602, + "test_a": 13.227693524434784, + "test_b": -14.645456730911656, + "ref_a_norm": 0.5826239633197431, + "ref_b_norm": -0.8127418516143946, + "test_a_norm": 0.7435282355295748, + "test_b_norm": -0.8232206606196507, + "Rcs_pct": 9.810643526645837, + "Rhs": 0.12796529847131397, + "Rf_h": 80.36990026788312 + }, + { + "bin": 15, + "ref_a": 15.527150560160058, + "ref_b": -10.949892107199762, + "test_a": 15.138432200943534, + "test_b": -12.881895991004772, + "ref_a_norm": 0.8172268926032334, + "ref_b_norm": -0.5763160643310777, + "test_a_norm": 0.7967678202467487, + "test_b_norm": -0.6780015296933117, + "Rcs_pct": 3.9482320725686884, + "Rhs": -0.09591482605799767, + "Rf_h": 82.77297375610138 + }, + { + "bin": 16, + "ref_a": 20.16425145845188, + "ref_b": -3.5016848993407703, + "test_a": 20.18126357794085, + "test_b": -5.558316347342718, + "ref_a_norm": 0.9852541321137537, + "ref_b_norm": -0.17109732655063342, + "test_a_norm": 0.9860853685748273, + "test_b_norm": -0.27158727712252445, + "Rcs_pct": 2.0419881302010534, + "Rhs": -0.09839689816049653, + "Rf_h": 81.23942198536625 + } + ] + } +} \ No newline at end of file diff --git a/crates/tm30/tests/golden/illuminant_FL12.json b/crates/tm30/tests/golden/illuminant_FL12.json new file mode 100644 index 0000000..1e8a51f --- /dev/null +++ b/crates/tm30/tests/golden/illuminant_FL12.json @@ -0,0 +1,403 @@ +{ + "name": "illuminant_FL12", + "source": "colour.SDS_ILLUMINANTS['FL12'] (380.0, 780.0, 5.0)", + "generator": "crates/tm30/tools/golden.py (tm30.py + colour-science 0.4.7, numpy 2.5.1)", + "wavelengths": [ + 380.0, + 385.0, + 390.0, + 395.0, + 400.0, + 405.0, + 410.0, + 415.0, + 420.0, + 425.0, + 430.0, + 435.0, + 440.0, + 445.0, + 450.0, + 455.0, + 460.0, + 465.0, + 470.0, + 475.0, + 480.0, + 485.0, + 490.0, + 495.0, + 500.0, + 505.0, + 510.0, + 515.0, + 520.0, + 525.0, + 530.0, + 535.0, + 540.0, + 545.0, + 550.0, + 555.0, + 560.0, + 565.0, + 570.0, + 575.0, + 580.0, + 585.0, + 590.0, + 595.0, + 600.0, + 605.0, + 610.0, + 615.0, + 620.0, + 625.0, + 630.0, + 635.0, + 640.0, + 645.0, + 650.0, + 655.0, + 660.0, + 665.0, + 670.0, + 675.0, + 680.0, + 685.0, + 690.0, + 695.0, + 700.0, + 705.0, + 710.0, + 715.0, + 720.0, + 725.0, + 730.0, + 735.0, + 740.0, + 745.0, + 750.0, + 755.0, + 760.0, + 765.0, + 770.0, + 775.0, + 780.0 + ], + "values": [ + 0.96, + 0.64, + 0.4, + 0.33, + 1.19, + 12.48, + 1.12, + 0.94, + 1.08, + 1.37, + 1.78, + 29.05, + 7.9, + 2.65, + 2.71, + 2.65, + 2.49, + 2.33, + 2.1, + 1.91, + 3.01, + 10.83, + 11.88, + 6.88, + 3.43, + 1.49, + 0.92, + 0.71, + 0.6, + 0.63, + 1.1, + 4.56, + 34.4, + 65.4, + 29.48, + 7.16, + 3.08, + 2.47, + 2.27, + 5.09, + 11.96, + 15.32, + 14.27, + 11.86, + 9.28, + 12.31, + 68.53, + 53.02, + 14.67, + 14.38, + 14.71, + 6.46, + 2.57, + 2.75, + 4.18, + 3.44, + 2.81, + 2.42, + 1.64, + 1.36, + 1.49, + 2.14, + 2.34, + 1.42, + 1.61, + 5.04, + 6.98, + 3.19, + 0.71, + 0.3, + 0.26, + 0.23, + 0.28, + 0.28, + 0.21, + 0.17, + 0.21, + 0.19, + 0.15, + 0.1, + 0.05 + ], + "expected": { + "Rf": 77.66672530326227, + "Rg": 102.41356724545297, + "CCT_K": 3002.536949565647, + "Duv": 0.00013292749217839529, + "bins": [ + { + "bin": 1, + "ref_a": 23.975226567658982, + "ref_b": 5.022329344472518, + "test_a": 22.152650094255122, + "test_b": 3.4994316073368434, + "ref_a_norm": 0.9787557501492054, + "ref_b_norm": 0.20502970894450004, + "test_a_norm": 0.9043515647123512, + "test_b_norm": 0.14285949700075132, + "Rcs_pct": -8.51033365447757, + "Rhs": -0.0464600922577543, + "Rf_h": 78.22787065149652 + }, + { + "bin": 2, + "ref_a": 20.531509660140014, + "ref_b": 15.080318377819866, + "test_a": 19.408404331843208, + "test_b": 15.312262127569038, + "ref_a_norm": 0.8059577768626139, + "ref_b_norm": 0.5919730246511856, + "test_a_norm": 0.761870640136669, + "test_b_norm": 0.601077901593963, + "Rcs_pct": -3.1598715876336962, + "Rhs": 0.03206392932567378, + "Rf_h": 86.84507197877812 + }, + { + "bin": 3, + "ref_a": 14.805518706365346, + "ref_b": 22.93214202966844, + "test_a": 12.471197834680439, + "test_b": 24.092626231824767, + "ref_a_norm": 0.5424007402439379, + "ref_b_norm": 0.8401198944096183, + "test_a_norm": 0.456882806432918, + "test_b_norm": 0.8826342772404183, + "Rcs_pct": -1.2161801005135993, + "Rhs": 0.09472528884675553, + "Rf_h": 80.61248365171859 + }, + { + "bin": 4, + "ref_a": 2.987528622410749, + "ref_b": 21.852048078495194, + "test_a": -0.48747761416030394, + "test_b": 24.622708331097737, + "ref_a_norm": 0.13545611817112416, + "ref_b_norm": 0.9907833466757555, + "test_a_norm": -0.022102491274608185, + "test_b_norm": 1.1164065389602602, + "Rcs_pct": 9.247121801672547, + "Rhs": 0.17903903398065368, + "Rf_h": 68.52680869364306 + }, + { + "bin": 5, + "ref_a": -2.6139790184651623, + "ref_b": 15.740722726381124, + "test_a": -5.21596954452937, + "test_b": 18.212229667211083, + "ref_a_norm": -0.16382121242673858, + "ref_b_norm": 0.9864900457475653, + "test_a_norm": -0.3268910916000656, + "test_b_norm": 1.1413823615265948, + "Rcs_pct": 18.372945860269667, + "Rhs": 0.12971854540717773, + "Rf_h": 72.48687806619886 + }, + { + "bin": 6, + "ref_a": -12.719445814976504, + "ref_b": 17.005712452184596, + "test_a": -14.324194363547837, + "test_b": 19.398684094258865, + "ref_a_norm": -0.5989495498085279, + "ref_b_norm": 0.8007867611194391, + "test_a_norm": -0.674516004094686, + "test_b_norm": 0.9134700736295923, + "Rcs_pct": 13.56752227820096, + "Rhs": 0.0002277162597035865, + "Rf_h": 79.40891315085294 + }, + { + "bin": 7, + "ref_a": -18.664092358911997, + "ref_b": 13.276123121079301, + "test_a": -18.774066699765044, + "test_b": 17.348452224427565, + "ref_a_norm": -0.8148753179659995, + "ref_b_norm": 0.5796362792043052, + "test_a_norm": -0.8196768038484853, + "test_b_norm": 0.7574343959913009, + "Rcs_pct": 10.277163077898429, + "Rhs": -0.14516616860243303, + "Rf_h": 72.55357318535336 + }, + { + "bin": 8, + "ref_a": -21.454756814798557, + "ref_b": 5.820120798189364, + "test_a": -20.113234921361073, + "test_b": 8.374500341329046, + "ref_a_norm": -0.9651189425777715, + "ref_b_norm": 0.2618118153895353, + "test_a_norm": -0.9047720366484409, + "test_b_norm": 0.3767178059303751, + "Rcs_pct": -3.6770310357171274, + "Rhs": -0.12447120146303867, + "Rf_h": 79.81154434033425 + }, + { + "bin": 9, + "ref_a": -22.56343926819563, + "ref_b": -3.722686923435771, + "test_a": -21.937416968774738, + "test_b": -1.3061787022702178, + "ref_a_norm": -0.9866612614044169, + "ref_b_norm": -0.1627868398975948, + "test_a_norm": -0.9592863588342864, + "test_b_norm": -0.057116998462999724, + "Rcs_pct": -4.7464064886124895, + "Rhs": -0.09829884650402732, + "Rf_h": 82.35654136254027 + }, + { + "bin": 10, + "ref_a": -18.140637294634306, + "ref_b": -11.84323048747173, + "test_a": -15.567546138592212, + "test_b": -10.944367262810003, + "ref_a_norm": -0.8373490289355752, + "ref_b_norm": -0.54666864162914, + "test_a_norm": -0.718578373534629, + "test_b_norm": -0.5051782443464038, + "Rcs_pct": -12.180502048558958, + "Rhs": 0.03148743615403931, + "Rf_h": 77.68339596032153 + }, + { + "bin": 11, + "ref_a": -10.993650723441528, + "ref_b": -15.746869379263497, + "test_a": -7.4034842111607295, + "test_b": -15.288501191497243, + "ref_a_norm": -0.5724429355197438, + "ref_b_norm": -0.8199445625001355, + "test_a_norm": -0.38550180840966425, + "test_b_norm": -0.7960771832687495, + "Rcs_pct": -12.370392610569228, + "Rhs": 0.14217586104047034, + "Rf_h": 74.54247093262018 + }, + { + "bin": 12, + "ref_a": -6.7437328054329555, + "ref_b": -21.15505960340024, + "test_a": -5.047901108533404, + "test_b": -21.910125590650136, + "ref_a_norm": -0.3037179904706148, + "ref_b_norm": -0.952761975660496, + "test_a_norm": -0.22734269358107007, + "test_b_norm": -0.9867679380757769, + "Rcs_pct": 1.8452466118594189, + "Rhs": 0.08154200113375762, + "Rf_h": 80.45104302216573 + }, + { + "bin": 13, + "ref_a": 3.134796149739345, + "ref_b": -18.094184491150525, + "test_a": 2.9828091193403874, + "test_b": -19.77563244939146, + "ref_a_norm": 0.1707058810207398, + "ref_b_norm": -0.9853220296862002, + "test_a_norm": 0.16242940029004307, + "test_b_norm": -1.076885576848879, + "Rcs_pct": 8.818951798775053, + "Rhs": -0.025980612375114318, + "Rf_h": 82.39322196652974 + }, + { + "bin": 14, + "ref_a": 9.188299665937155, + "ref_b": -14.074584117560253, + "test_a": 8.74025343155444, + "test_b": -15.310449451366718, + "ref_a_norm": 0.5466527009816281, + "ref_b_norm": -0.8373594356723346, + "test_a_norm": 0.5199964432304854, + "test_b_norm": -0.9108865459470907, + "Rcs_pct": 4.632613454364505, + "Rhs": -0.06301334208638354, + "Rf_h": 76.77559137587053 + }, + { + "bin": 15, + "ref_a": 18.262260591127156, + "ref_b": -11.937725756291359, + "test_a": 17.867983934337055, + "test_b": -14.17156247535926, + "ref_a_norm": 0.8370322337060172, + "ref_b_norm": -0.5471535796621596, + "test_a_norm": 0.8189609621301696, + "test_b_norm": -0.6495392251503407, + "Rcs_pct": 4.185670375074711, + "Rhs": -0.09517041351975798, + "Rf_h": 79.24328496802751 + }, + { + "bin": 16, + "ref_a": 16.780657182686266, + "ref_b": -3.810541258067397, + "test_a": 15.815668978310782, + "test_b": -5.491886858072326, + "ref_a_norm": 0.9751735858744889, + "ref_b_norm": -0.22144181495980111, + "test_a_norm": 0.9190952691945945, + "test_b_norm": -0.3191497771689803, + "Rcs_pct": -3.5938909738502844, + "Rhs": -0.10677086797216107, + "Rf_h": 76.81650190272609 + } + ] + } +} \ No newline at end of file diff --git a/crates/tm30/tests/golden/illuminant_FL2.json b/crates/tm30/tests/golden/illuminant_FL2.json new file mode 100644 index 0000000..b73d2c6 --- /dev/null +++ b/crates/tm30/tests/golden/illuminant_FL2.json @@ -0,0 +1,403 @@ +{ + "name": "illuminant_FL2", + "source": "colour.SDS_ILLUMINANTS['FL2'] (380.0, 780.0, 5.0)", + "generator": "crates/tm30/tools/golden.py (tm30.py + colour-science 0.4.7, numpy 2.5.1)", + "wavelengths": [ + 380.0, + 385.0, + 390.0, + 395.0, + 400.0, + 405.0, + 410.0, + 415.0, + 420.0, + 425.0, + 430.0, + 435.0, + 440.0, + 445.0, + 450.0, + 455.0, + 460.0, + 465.0, + 470.0, + 475.0, + 480.0, + 485.0, + 490.0, + 495.0, + 500.0, + 505.0, + 510.0, + 515.0, + 520.0, + 525.0, + 530.0, + 535.0, + 540.0, + 545.0, + 550.0, + 555.0, + 560.0, + 565.0, + 570.0, + 575.0, + 580.0, + 585.0, + 590.0, + 595.0, + 600.0, + 605.0, + 610.0, + 615.0, + 620.0, + 625.0, + 630.0, + 635.0, + 640.0, + 645.0, + 650.0, + 655.0, + 660.0, + 665.0, + 670.0, + 675.0, + 680.0, + 685.0, + 690.0, + 695.0, + 700.0, + 705.0, + 710.0, + 715.0, + 720.0, + 725.0, + 730.0, + 735.0, + 740.0, + 745.0, + 750.0, + 755.0, + 760.0, + 765.0, + 770.0, + 775.0, + 780.0 + ], + "values": [ + 1.18, + 1.48, + 1.84, + 2.15, + 3.44, + 15.69, + 3.85, + 3.74, + 4.19, + 4.62, + 5.06, + 34.98, + 11.81, + 6.27, + 6.63, + 6.93, + 7.19, + 7.4, + 7.54, + 7.62, + 7.65, + 7.62, + 7.62, + 7.45, + 7.28, + 7.15, + 7.05, + 7.04, + 7.16, + 7.47, + 8.04, + 8.88, + 10.01, + 24.88, + 16.64, + 14.59, + 16.16, + 17.56, + 18.62, + 21.47, + 22.79, + 19.29, + 18.66, + 17.73, + 16.54, + 15.21, + 13.8, + 12.36, + 10.95, + 9.65, + 8.4, + 7.32, + 6.31, + 5.43, + 4.68, + 4.02, + 3.45, + 2.96, + 2.55, + 2.19, + 1.89, + 1.64, + 1.53, + 1.27, + 1.1, + 0.99, + 0.88, + 0.76, + 0.68, + 0.61, + 0.56, + 0.54, + 0.51, + 0.47, + 0.47, + 0.43, + 0.46, + 0.47, + 0.4, + 0.33, + 0.27 + ], + "expected": { + "Rf": 70.20781906305379, + "Rg": 86.43829403927003, + "CCT_K": 4225.108266234531, + "Duv": 0.0018621252165094363, + "bins": [ + { + "bin": 1, + "ref_a": 21.44150569987737, + "ref_b": 4.911710850800025, + "test_a": 16.168126568827844, + "test_b": 3.371924328142029, + "ref_a_norm": 0.9747517901272056, + "ref_b_norm": 0.22329117233739448, + "test_a_norm": 0.7350188245435725, + "test_b_norm": 0.15329097317306012, + "Rcs_pct": -24.878292526800465, + "Rhs": -0.021885583512081308, + "Rf_h": 60.35070543403967 + }, + { + "bin": 2, + "ref_a": 20.635169564608816, + "ref_b": 14.292768265389933, + "test_a": 15.009402988490473, + "test_b": 14.751771239986297, + "ref_a_norm": 0.82206386812768, + "ref_b_norm": 0.5693952903905657, + "test_a_norm": 0.5979445838994997, + "test_b_norm": 0.5876810505146769, + "Rcs_pct": -17.6189350353636, + "Rhs": 0.13971805684388874, + "Rf_h": 61.40655822137029 + }, + { + "bin": 3, + "ref_a": 14.628925569603425, + "ref_b": 22.26452256690993, + "test_a": 7.921265503505507, + "test_b": 23.902806028585434, + "ref_a_norm": 0.5491242372455207, + "ref_b_norm": 0.8357407325657432, + "test_a_norm": 0.2973396000229725, + "test_b_norm": 0.8972367837968591, + "Rcs_pct": -8.875195169721376, + "Rhs": 0.24351665020742566, + "Rf_h": 52.6920029392565 + }, + { + "bin": 4, + "ref_a": 3.835519445060082, + "ref_b": 22.11129922974916, + "test_a": -0.23280081833055, + "test_b": 24.154981655413774, + "ref_a_norm": 0.17091192885142428, + "ref_b_norm": 0.9852863099507094, + "test_a_norm": -0.010373676230558399, + "test_b_norm": 1.07635342884642, + "Rcs_pct": 5.395022266931121, + "Rhs": 0.1955685665638469, + "Rf_h": 68.43722661711175 + }, + { + "bin": 5, + "ref_a": -2.1896569983462593, + "ref_b": 19.141537391803148, + "test_a": -4.32496456361688, + "test_b": 20.885987380138207, + "ref_a_norm": -0.1136517613201618, + "ref_b_norm": 0.9935206475704593, + "test_a_norm": -0.2244825745190134, + "test_b_norm": 1.0840644239970645, + "Rcs_pct": 11.042602218760873, + "Rhs": 0.09103701570093099, + "Rf_h": 79.64398650227432 + }, + { + "bin": 6, + "ref_a": -11.110069918888163, + "ref_b": 17.22633455214125, + "test_a": -10.471008611815796, + "test_b": 18.74344691822782, + "ref_a_norm": -0.5419996069285619, + "ref_b_norm": 0.8403787396699682, + "test_a_norm": -0.5108232975294993, + "test_b_norm": 0.9143903626470153, + "Rcs_pct": 4.421778598507902, + "Rhs": -0.06704080851257976, + "Rf_h": 87.5761514709081 + }, + { + "bin": 7, + "ref_a": -18.195188593305904, + "ref_b": 11.341780805069275, + "test_a": -15.366736336726074, + "test_b": 12.595693256153485, + "ref_a_norm": -0.848631003347337, + "ref_b_norm": 0.528985274046161, + "test_a_norm": -0.7167108386228853, + "test_b_norm": 0.5874682612389842, + "Rcs_pct": -7.7196201395928625, + "Rhs": -0.12191774334345938, + "Rf_h": 76.84965255972465 + }, + { + "bin": 8, + "ref_a": -22.72718403807425, + "ref_b": 3.698593182290253, + "test_a": -19.051288813943362, + "test_b": 4.94914539188827, + "ref_a_norm": -0.9870154023076927, + "ref_b_norm": 0.16062563807619118, + "test_a_norm": -0.8273755103875893, + "test_b_norm": 0.2149356788711857, + "Rcs_pct": -14.597709281299553, + "Rhs": -0.08441068651114254, + "Rf_h": 72.81568281316467 + }, + { + "bin": 9, + "ref_a": -19.34913651987008, + "ref_b": -2.039171712629464, + "test_a": -16.043949788236674, + "test_b": -1.5094621968538244, + "ref_a_norm": -0.9944924933423362, + "ref_b_norm": -0.10480782740684566, + "test_a_norm": -0.8246149698503379, + "test_b_norm": -0.07758221263329221, + "Rcs_pct": -17.19248284655656, + "Rhs": 0.006438978541526419, + "Rf_h": 76.23588711921641 + }, + { + "bin": 10, + "ref_a": -20.19059925839228, + "ref_b": -11.169472867275275, + "test_a": -15.11614626554033, + "test_b": -12.3731508921473, + "ref_a_norm": -0.8750302756952433, + "ref_b_norm": -0.48406819418002106, + "test_a_norm": -0.655111097244303, + "test_b_norm": -0.5362337936490059, + "Rcs_pct": -15.387445979190643, + "Rhs": 0.16555465998347502, + "Rf_h": 62.39561559761673 + }, + { + "bin": 11, + "ref_a": -12.16646596983228, + "ref_b": -17.30142734213172, + "test_a": -8.402886110495205, + "test_b": -18.894689447143964, + "ref_a_norm": -0.5752210401151883, + "ref_b_norm": -0.8179980165066422, + "test_a_norm": -0.3972819141099486, + "test_b_norm": -0.893326208562884, + "Rcs_pct": -3.6224579053580275, + "Rhs": 0.18980107732666204, + "Rf_h": 69.72091464664942 + }, + { + "bin": 12, + "ref_a": -5.488851063738376, + "ref_b": -23.66221352505178, + "test_a": -3.018223745513694, + "test_b": -25.399554871361985, + "ref_a_norm": -0.2259670919429864, + "ref_b_norm": -0.9741349359092045, + "test_a_norm": -0.12425537415520334, + "test_b_norm": -1.0456584600819752, + "Rcs_pct": 5.030624793518598, + "Rhs": 0.11371090301337923, + "Rf_h": 76.64358892974491 + }, + { + "bin": 13, + "ref_a": 3.538118811028049, + "ref_b": -15.379355619950259, + "test_a": 2.620549926198063, + "test_b": -17.319472658585592, + "ref_a_norm": 0.22419987261004892, + "ref_b_norm": -0.9745431838156983, + "test_a_norm": 0.16605631156042633, + "test_b_norm": -1.0974825242230486, + "Rcs_pct": 10.923384940567608, + "Rhs": -0.08101062433621685, + "Rf_h": 81.40090148306182 + }, + { + "bin": 14, + "ref_a": 13.843460665470982, + "ref_b": -18.679468563263917, + "test_a": 11.871759134004922, + "test_b": -21.856487165054602, + "ref_a_norm": 0.595416865010529, + "ref_b_norm": -0.8034169259239151, + "test_a_norm": 0.5106126117265082, + "test_b_norm": -0.9400627041487624, + "Rcs_pct": 6.650209348533657, + "Rhs": -0.14642848644919484, + "Rf_h": 71.4405875637361 + }, + { + "bin": 15, + "ref_a": 15.26876386478876, + "ref_b": -11.132723084889403, + "test_a": 11.493185633754575, + "test_b": -14.588476319460835, + "ref_a_norm": 0.8080264387977029, + "ref_b_norm": -0.5891462248066283, + "test_a_norm": 0.608221984459389, + "test_b_norm": -0.7720254679609351, + "Rcs_pct": -6.452906845131275, + "Rhs": -0.2630639406587859, + "Rf_h": 63.656538232435295 + }, + { + "bin": 16, + "ref_a": 20.01194727333166, + "ref_b": -3.699076972051818, + "test_a": 16.0741918720872, + "test_b": -6.432073793519327, + "ref_a_norm": 0.983342121626454, + "ref_b_norm": -0.1817643304809396, + "test_a_norm": 0.7898496694518533, + "test_b_norm": -0.316057653170311, + "Rcs_pct": -16.357522139388895, + "Rhs": -0.16946141895260983, + "Rf_h": 65.3578438523645 + } + ] + } +} \ No newline at end of file diff --git a/crates/tm30/tests/golden/illuminant_FL3.json b/crates/tm30/tests/golden/illuminant_FL3.json new file mode 100644 index 0000000..adf84b3 --- /dev/null +++ b/crates/tm30/tests/golden/illuminant_FL3.json @@ -0,0 +1,403 @@ +{ + "name": "illuminant_FL3", + "source": "colour.SDS_ILLUMINANTS['FL3'] (380.0, 780.0, 5.0)", + "generator": "crates/tm30/tools/golden.py (tm30.py + colour-science 0.4.7, numpy 2.5.1)", + "wavelengths": [ + 380.0, + 385.0, + 390.0, + 395.0, + 400.0, + 405.0, + 410.0, + 415.0, + 420.0, + 425.0, + 430.0, + 435.0, + 440.0, + 445.0, + 450.0, + 455.0, + 460.0, + 465.0, + 470.0, + 475.0, + 480.0, + 485.0, + 490.0, + 495.0, + 500.0, + 505.0, + 510.0, + 515.0, + 520.0, + 525.0, + 530.0, + 535.0, + 540.0, + 545.0, + 550.0, + 555.0, + 560.0, + 565.0, + 570.0, + 575.0, + 580.0, + 585.0, + 590.0, + 595.0, + 600.0, + 605.0, + 610.0, + 615.0, + 620.0, + 625.0, + 630.0, + 635.0, + 640.0, + 645.0, + 650.0, + 655.0, + 660.0, + 665.0, + 670.0, + 675.0, + 680.0, + 685.0, + 690.0, + 695.0, + 700.0, + 705.0, + 710.0, + 715.0, + 720.0, + 725.0, + 730.0, + 735.0, + 740.0, + 745.0, + 750.0, + 755.0, + 760.0, + 765.0, + 770.0, + 775.0, + 780.0 + ], + "values": [ + 0.82, + 1.02, + 1.26, + 1.44, + 2.57, + 14.36, + 2.7, + 2.45, + 2.73, + 3.0, + 3.28, + 31.85, + 9.47, + 4.02, + 4.25, + 4.44, + 4.59, + 4.72, + 4.8, + 4.86, + 4.87, + 4.85, + 4.88, + 4.77, + 4.67, + 4.62, + 4.62, + 4.73, + 4.99, + 5.48, + 6.25, + 7.34, + 8.78, + 23.82, + 16.14, + 14.59, + 16.63, + 18.49, + 19.95, + 23.11, + 24.69, + 21.41, + 20.85, + 19.93, + 18.67, + 17.22, + 15.65, + 14.04, + 12.45, + 10.95, + 9.51, + 8.27, + 7.11, + 6.09, + 5.22, + 4.45, + 3.8, + 3.23, + 2.75, + 2.33, + 1.99, + 1.7, + 1.55, + 1.27, + 1.09, + 0.96, + 0.83, + 0.71, + 0.62, + 0.54, + 0.49, + 0.46, + 0.43, + 0.39, + 0.39, + 0.35, + 0.38, + 0.39, + 0.33, + 0.28, + 0.21 + ], + "expected": { + "Rf": 63.19778338658768, + "Rg": 84.41179198429043, + "CCT_K": 3447.3244899976953, + "Duv": 0.000743226934525114, + "bins": [ + { + "bin": 1, + "ref_a": 21.94160351974977, + "ref_b": 5.530930055836527, + "test_a": 15.926537601641845, + "test_b": 3.8086806415923187, + "ref_a_norm": 0.9696672224894509, + "ref_b_norm": 0.24442888051454467, + "test_a_norm": 0.7038428830489584, + "test_b_norm": 0.16831736002147402, + "Rcs_pct": -27.556522033827733, + "Rhs": -0.022789302987542226, + "Rf_h": 55.02171738911249 + }, + { + "bin": 2, + "ref_a": 20.256423549029194, + "ref_b": 14.927046207598268, + "test_a": 13.326919493546331, + "test_b": 15.670520851902511, + "ref_a_norm": 0.8050319147201971, + "ref_b_norm": 0.5932315031098174, + "test_a_norm": 0.5296391779745195, + "test_b_norm": 0.622778713899594, + "Rcs_pct": -21.256514126930988, + "Rhs": 0.17756761482569922, + "Rf_h": 52.486754689794886 + }, + { + "bin": 3, + "ref_a": 14.597230588667905, + "ref_b": 23.155884382248217, + "test_a": 6.6059382573278755, + "test_b": 25.679746736846806, + "ref_a_norm": 0.5332736214287349, + "ref_b_norm": 0.845942814076863, + "test_a_norm": 0.24133157286387288, + "test_b_norm": 0.938145866542808, + "Rcs_pct": -8.553027566243001, + "Rhs": 0.2939662132786603, + "Rf_h": 43.01164348790252 + }, + { + "bin": 4, + "ref_a": 3.316550846746281, + "ref_b": 22.624087178474447, + "test_a": -1.7830098702119193, + "test_b": 25.578420583748912, + "ref_a_norm": 0.1450436063956005, + "ref_b_norm": 0.9894252635968813, + "test_a_norm": -0.0779768481668849, + "test_b_norm": 1.1186279176181193, + "Rcs_pct": 8.321092895628283, + "Rhs": 0.24394136644206482, + "Rf_h": 59.101565162166175 + }, + { + "bin": 5, + "ref_a": -2.459436280601042, + "ref_b": 16.577431257176915, + "test_a": -4.736494527690048, + "test_b": 18.940350406864603, + "ref_a_norm": -0.14675421640781136, + "ref_b_norm": 0.9891729878876239, + "test_a_norm": -0.2826259612471722, + "test_b_norm": 1.130168040690002, + "Rcs_pct": 16.479313485185287, + "Rhs": 0.10575423710725176, + "Rf_h": 75.49079092390846 + }, + { + "bin": 6, + "ref_a": -12.547433038572542, + "ref_b": 17.790683608144555, + "test_a": -11.645405540084255, + "test_b": 20.140973494984056, + "ref_a_norm": -0.5763552146748991, + "ref_b_norm": 0.8171992820096278, + "test_a_norm": -0.5349213810823491, + "test_b_norm": 0.9251577646820112, + "Rcs_pct": 6.674479314846927, + "Rhs": -0.09442949292814448, + "Rf_h": 81.96532259233045 + }, + { + "bin": 7, + "ref_a": -18.162833778901028, + "ref_b": 12.176502489175482, + "test_a": -14.71794049010156, + "test_b": 15.29575076480441, + "ref_a_norm": -0.8306133746748208, + "ref_b_norm": 0.5568495504274974, + "test_a_norm": -0.6730732862262714, + "test_b_norm": 0.6994974085870805, + "Rcs_pct": -5.173889246695727, + "Rhs": -0.20613194296902643, + "Rf_h": 67.23708932361353 + }, + { + "bin": 8, + "ref_a": -20.904662056000344, + "ref_b": 4.9270968246788245, + "test_a": -16.668193325457693, + "test_b": 6.230221065152909, + "ref_a_norm": -0.9733303906363165, + "ref_b_norm": 0.22940782607347002, + "test_a_norm": -0.7760785167064034, + "test_b_norm": 0.29008187201740954, + "Rcs_pct": -18.162481532118797, + "Rhs": -0.09799014276759675, + "Rf_h": 68.05205831616712 + }, + { + "bin": 9, + "ref_a": -21.15739395003704, + "ref_b": -3.08172761808492, + "test_a": -16.663319611468893, + "test_b": -2.1887544094686926, + "ref_a_norm": -0.9895578492140875, + "ref_b_norm": -0.14413626559193637, + "test_a_norm": -0.7793643562355285, + "test_b_norm": -0.10237078871842333, + "Rcs_pct": -21.430272428232136, + "Rhs": 4.37512843187824e-05, + "Rf_h": 67.72389821785953 + }, + { + "bin": 10, + "ref_a": -17.89426679083414, + "ref_b": -10.986787344079431, + "test_a": -11.972362228691079, + "test_b": -11.566225290410726, + "ref_a_norm": -0.8521907692186877, + "ref_b_norm": -0.5232312040183204, + "test_a_norm": -0.5701679032895102, + "test_b_norm": -0.5508261692085954, + "Rcs_pct": -21.916250175365715, + "Rhs": 0.1796278843493894, + "Rf_h": 55.299157156392866 + }, + { + "bin": 11, + "ref_a": -11.696949550713507, + "ref_b": -17.24521390184183, + "test_a": -6.358266082725774, + "test_b": -18.806657119480445, + "ref_a_norm": -0.5613318566742739, + "ref_b_norm": -0.8275908087228933, + "test_a_norm": -0.30513060605855213, + "test_b_norm": -0.9025238343505083, + "Rcs_pct": -8.003325473724022, + "Rhs": 0.2546541130296794, + "Rf_h": 59.388163677843494 + }, + { + "bin": 12, + "ref_a": -7.68788374186335, + "ref_b": -23.86426257661041, + "test_a": -3.9485698308754174, + "test_b": -26.094965734607687, + "ref_a_norm": -0.3066319071562265, + "ref_b_norm": -0.9518281743643311, + "test_a_norm": -0.1574890487986764, + "test_b_norm": -1.040799962518653, + "Rcs_pct": 5.816589192953315, + "Rhs": 0.1636346549557265, + "Rf_h": 66.68367217510365 + }, + { + "bin": 13, + "ref_a": 2.381520197394699, + "ref_b": -18.424037385665343, + "test_a": 2.8207209472961914, + "test_b": -20.32008769747726, + "ref_a_norm": 0.12819504041958857, + "ref_b_norm": -0.9917489761082792, + "test_a_norm": 0.15183681257316065, + "test_b_norm": -1.0938116193838667, + "Rcs_pct": 10.471381914621432, + "Rhs": 0.0032760681884188526, + "Rf_h": 82.34842258205313 + }, + { + "bin": 14, + "ref_a": 8.028123970338934, + "ref_b": -14.582576635749481, + "test_a": 6.542635753627454, + "test_b": -17.47432259853496, + "ref_a_norm": 0.4822741592398461, + "ref_b_norm": -0.8760203395638138, + "test_a_norm": 0.39303630199921097, + "test_b_norm": -1.0497364353902099, + "Rcs_pct": 9.486175770613587, + "Rhs": -0.17071005840010728, + "Rf_h": 73.0563273769912 + }, + { + "bin": 15, + "ref_a": 16.54327447560949, + "ref_b": -11.391660449608125, + "test_a": 12.860031701619093, + "test_b": -15.400410136654198, + "ref_a_norm": 0.8236196353365476, + "ref_b_norm": -0.5671425713946119, + "test_a_norm": 0.6402465628022976, + "test_b_norm": -0.7667212557879713, + "Rcs_pct": -4.158916133261492, + "Rhs": -0.2678202319737723, + "Rf_h": 60.79009280131925 + }, + { + "bin": 16, + "ref_a": 20.727726013825222, + "ref_b": -2.9321574752652233, + "test_a": 16.33032112389099, + "test_b": -5.8893689919089045, + "ref_a_norm": 0.9901421487236542, + "ref_b_norm": -0.1400661462342173, + "test_a_norm": 0.7800826408151038, + "test_b_norm": -0.2813290982515741, + "Rcs_pct": -17.846423856743712, + "Rhs": -0.17952920104536, + "Rf_h": 60.89249970246921 + } + ] + } +} \ No newline at end of file diff --git a/crates/tm30/tests/golden/illuminant_FL4.json b/crates/tm30/tests/golden/illuminant_FL4.json new file mode 100644 index 0000000..effe16e --- /dev/null +++ b/crates/tm30/tests/golden/illuminant_FL4.json @@ -0,0 +1,403 @@ +{ + "name": "illuminant_FL4", + "source": "colour.SDS_ILLUMINANTS['FL4'] (380.0, 780.0, 5.0)", + "generator": "crates/tm30/tools/golden.py (tm30.py + colour-science 0.4.7, numpy 2.5.1)", + "wavelengths": [ + 380.0, + 385.0, + 390.0, + 395.0, + 400.0, + 405.0, + 410.0, + 415.0, + 420.0, + 425.0, + 430.0, + 435.0, + 440.0, + 445.0, + 450.0, + 455.0, + 460.0, + 465.0, + 470.0, + 475.0, + 480.0, + 485.0, + 490.0, + 495.0, + 500.0, + 505.0, + 510.0, + 515.0, + 520.0, + 525.0, + 530.0, + 535.0, + 540.0, + 545.0, + 550.0, + 555.0, + 560.0, + 565.0, + 570.0, + 575.0, + 580.0, + 585.0, + 590.0, + 595.0, + 600.0, + 605.0, + 610.0, + 615.0, + 620.0, + 625.0, + 630.0, + 635.0, + 640.0, + 645.0, + 650.0, + 655.0, + 660.0, + 665.0, + 670.0, + 675.0, + 680.0, + 685.0, + 690.0, + 695.0, + 700.0, + 705.0, + 710.0, + 715.0, + 720.0, + 725.0, + 730.0, + 735.0, + 740.0, + 745.0, + 750.0, + 755.0, + 760.0, + 765.0, + 770.0, + 775.0, + 780.0 + ], + "values": [ + 0.57, + 0.7, + 0.87, + 0.98, + 2.01, + 13.75, + 1.95, + 1.59, + 1.76, + 1.93, + 2.1, + 30.28, + 8.03, + 2.55, + 2.7, + 2.82, + 2.91, + 2.99, + 3.04, + 3.08, + 3.09, + 3.09, + 3.14, + 3.06, + 3.0, + 2.98, + 3.01, + 3.14, + 3.41, + 3.9, + 4.69, + 5.81, + 7.32, + 22.59, + 15.11, + 13.88, + 16.33, + 18.68, + 20.64, + 24.28, + 26.26, + 23.28, + 22.94, + 22.14, + 20.91, + 19.43, + 17.74, + 16.0, + 14.42, + 12.56, + 10.93, + 9.52, + 8.18, + 7.01, + 6.0, + 5.11, + 4.36, + 3.69, + 3.13, + 2.64, + 2.24, + 1.91, + 1.7, + 1.39, + 1.18, + 1.03, + 0.88, + 0.74, + 0.64, + 0.54, + 0.49, + 0.46, + 0.42, + 0.37, + 0.37, + 0.33, + 0.35, + 0.36, + 0.31, + 0.26, + 0.19 + ], + "expected": { + "Rf": 56.837303202318516, + "Rg": 83.53535660111531, + "CCT_K": 2939.53486990894, + "Duv": -0.0007410061280834144, + "bins": [ + { + "bin": 1, + "ref_a": 24.04302150966405, + "ref_b": 5.10997829018846, + "test_a": 17.57341860898924, + "test_b": 2.7305872878775825, + "ref_a_norm": 0.9781519334170307, + "ref_b_norm": 0.20789130610134932, + "test_a_norm": 0.714946471358451, + "test_b_norm": 0.11108958305959374, + "Rcs_pct": -27.7033122228718, + "Rhs": -0.043592866727611944, + "Rf_h": 50.164101307282245 + }, + { + "bin": 2, + "ref_a": 20.575230038336223, + "ref_b": 15.09760023355214, + "test_a": 12.763464016203361, + "test_b": 16.214741917960943, + "ref_a_norm": 0.8062349501664928, + "ref_b_norm": 0.5915954742305191, + "test_a_norm": 0.5001329635626106, + "test_b_norm": 0.6353703758272488, + "Rcs_pct": -23.01944678460636, + "Rhs": 0.20645865248449682, + "Rf_h": 46.398225941422844 + }, + { + "bin": 3, + "ref_a": 14.83826877702542, + "ref_b": 22.885389501010224, + "test_a": 5.646371099267796, + "test_b": 26.193514134767515, + "ref_a_norm": 0.5440283050036825, + "ref_b_norm": 0.8390668646507383, + "test_a_norm": 0.2070177959919816, + "test_b_norm": 0.9603555044703959, + "Rcs_pct": -8.63851886941317, + "Rhs": 0.3475983551570802, + "Rf_h": 33.96316195640967 + }, + { + "bin": 4, + "ref_a": 2.722606049734931, + "ref_b": 20.39505163570701, + "test_a": -2.7101089576544912, + "test_b": 24.460381709136072, + "ref_a_norm": 0.13231966667499653, + "ref_b_norm": 0.9912070953191456, + "test_a_norm": -0.13171230335166464, + "test_b_norm": 1.1887836489642623, + "Rcs_pct": 14.227009351287556, + "Rhs": 0.29750394323147883, + "Rf_h": 52.472472477741185 + }, + { + "bin": 5, + "ref_a": -2.9307939633559266, + "ref_b": 16.775914295948922, + "test_a": -5.5728573403752595, + "test_b": 19.674175822424875, + "ref_a_norm": -0.17209595990562995, + "ref_b_norm": 0.9850801899257542, + "test_a_norm": -0.3272376855556337, + "test_b_norm": 1.155265848041859, + "Rcs_pct": 19.718223763120914, + "Rhs": 0.11895914604948242, + "Rf_h": 70.40374870481806 + }, + { + "bin": 6, + "ref_a": -12.748159953653811, + "ref_b": 16.870126975051445, + "test_a": -11.788338115407848, + "test_b": 20.178663319853385, + "ref_a_norm": -0.6028885365240408, + "ref_b_norm": 0.7978254273510591, + "test_a_norm": -0.5574964497062042, + "test_b_norm": 0.9542933915283157, + "Rcs_pct": 10.487986526160048, + "Rhs": -0.12467108414609135, + "Rf_h": 75.7958240519802 + }, + { + "bin": 7, + "ref_a": -18.74456763651917, + "ref_b": 13.090954284380043, + "test_a": -14.909792030473088, + "test_b": 18.698988245552897, + "ref_a_norm": -0.819852877801606, + "ref_b_norm": 0.5725742386454572, + "test_a_norm": -0.6521268529977549, + "test_b_norm": 0.8178593191569488, + "Rcs_pct": -0.3186003480703912, + "Rhs": -0.29713067748021565, + "Rf_h": 53.939581859616396 + }, + { + "bin": 8, + "ref_a": -21.446065560336635, + "ref_b": 5.644249019263171, + "test_a": -16.283019073473497, + "test_b": 7.522393584943156, + "ref_a_norm": -0.9670684601939038, + "ref_b_norm": 0.2545163910206804, + "test_a_norm": -0.7342509579852653, + "test_b_norm": 0.33920765376273, + "Rcs_pct": -21.182153346618012, + "Rhs": -0.1284843853530388, + "Rf_h": 60.501470795133294 + }, + { + "bin": 9, + "ref_a": -22.581724104152443, + "ref_b": -3.8800856161994943, + "test_a": -17.143204446239228, + "test_b": -2.01142473636149, + "ref_a_norm": -0.985557255536085, + "ref_b_norm": -0.16934254060979462, + "test_a_norm": -0.748198385880673, + "test_b_norm": -0.08778666472686619, + "Rcs_pct": -24.870884761948506, + "Rhs": -0.033682384281910435, + "Rf_h": 59.00447255481244 + }, + { + "bin": 10, + "ref_a": -18.07750182004975, + "ref_b": -11.973740159351394, + "test_a": -11.408574510622127, + "test_b": -12.31964035067702, + "ref_a_norm": -0.8337052978428275, + "ref_b_norm": -0.55220963080048, + "test_a_norm": -0.5261451004137769, + "test_b_norm": -0.5681619910825396, + "Rcs_pct": -24.686430159691053, + "Rhs": 0.18413519337224704, + "Rf_h": 49.33311362479498 + }, + { + "bin": 11, + "ref_a": -10.884563311180324, + "ref_b": -15.823426281232113, + "test_a": -4.2502497932852545, + "test_b": -16.63956510475005, + "ref_a_norm": -0.5667394501766059, + "ref_b_norm": -0.8238970782892233, + "test_a_norm": -0.22130279020798943, + "test_b_norm": -0.8663919450913882, + "Rcs_pct": -15.6581135247433, + "Rhs": 0.3108289687906074, + "Rf_h": 51.37674532980499 + }, + { + "bin": 12, + "ref_a": -6.600974058951491, + "ref_b": -21.173045753659117, + "test_a": -2.2907668488116038, + "test_b": -23.001721259701384, + "ref_a_norm": -0.29763399824549197, + "ref_b_norm": -0.9546800527341096, + "test_a_norm": -0.1032893161177373, + "test_b_norm": -1.0371339447652217, + "Rcs_pct": 4.2954796997646145, + "Rhs": 0.2066963599033793, + "Rf_h": 61.37658768833385 + }, + { + "bin": 13, + "ref_a": 3.2672709269195903, + "ref_b": -18.032144067817775, + "test_a": 3.7467378113965877, + "test_b": -20.3665854235673, + "ref_a_norm": 0.17828848040412848, + "ref_b_norm": -0.9839782608143265, + "test_a_norm": 0.2044520352942949, + "test_b_norm": -1.1113640856260867, + "Rcs_pct": 13.004239825600827, + "Rhs": 0.0008090879364807859, + "Rf_h": 79.19803258984062 + }, + { + "bin": 14, + "ref_a": 9.38069712506772, + "ref_b": -13.982957445745487, + "test_a": 7.928964221520651, + "test_b": -17.21324048617001, + "ref_a_norm": 0.5571123958690091, + "ref_b_norm": -0.8304371007903565, + "test_a_norm": 0.47089509396980284, + "test_b_norm": -1.0222811290104812, + "Rcs_pct": 11.161271326028224, + "Rhs": -0.17826989804557833, + "Rf_h": 70.29843942669612 + }, + { + "bin": 15, + "ref_a": 18.9123581744298, + "ref_b": -13.437178883292924, + "test_a": 15.574614373010576, + "test_b": -18.602676404125877, + "ref_a_norm": 0.8151915871907778, + "ref_b_norm": -0.5791913985664675, + "test_a_norm": 0.6713226607449009, + "test_b_norm": -0.8018431738660223, + "Rcs_pct": 0.40760581910651206, + "Rhs": -0.26505747827661, + "Rf_h": 56.84750090404851 + }, + { + "bin": 16, + "ref_a": 16.888801082158455, + "ref_b": -4.179200924944297, + "test_a": 12.394017060707634, + "test_b": -6.883408874607942, + "ref_a_norm": 0.9707212368227607, + "ref_b_norm": -0.24020882660986811, + "test_a_norm": 0.712373572987508, + "test_b_norm": -0.39563916608473776, + "Rcs_pct": -22.306063093694913, + "Rhs": -0.20284491801476331, + "Rf_h": 59.894339093919584 + } + ] + } +} \ No newline at end of file diff --git a/crates/tm30/tests/golden/illuminant_FL5.json b/crates/tm30/tests/golden/illuminant_FL5.json new file mode 100644 index 0000000..c4b1beb --- /dev/null +++ b/crates/tm30/tests/golden/illuminant_FL5.json @@ -0,0 +1,403 @@ +{ + "name": "illuminant_FL5", + "source": "colour.SDS_ILLUMINANTS['FL5'] (380.0, 780.0, 5.0)", + "generator": "crates/tm30/tools/golden.py (tm30.py + colour-science 0.4.7, numpy 2.5.1)", + "wavelengths": [ + 380.0, + 385.0, + 390.0, + 395.0, + 400.0, + 405.0, + 410.0, + 415.0, + 420.0, + 425.0, + 430.0, + 435.0, + 440.0, + 445.0, + 450.0, + 455.0, + 460.0, + 465.0, + 470.0, + 475.0, + 480.0, + 485.0, + 490.0, + 495.0, + 500.0, + 505.0, + 510.0, + 515.0, + 520.0, + 525.0, + 530.0, + 535.0, + 540.0, + 545.0, + 550.0, + 555.0, + 560.0, + 565.0, + 570.0, + 575.0, + 580.0, + 585.0, + 590.0, + 595.0, + 600.0, + 605.0, + 610.0, + 615.0, + 620.0, + 625.0, + 630.0, + 635.0, + 640.0, + 645.0, + 650.0, + 655.0, + 660.0, + 665.0, + 670.0, + 675.0, + 680.0, + 685.0, + 690.0, + 695.0, + 700.0, + 705.0, + 710.0, + 715.0, + 720.0, + 725.0, + 730.0, + 735.0, + 740.0, + 745.0, + 750.0, + 755.0, + 760.0, + 765.0, + 770.0, + 775.0, + 780.0 + ], + "values": [ + 1.87, + 2.35, + 2.92, + 3.45, + 5.1, + 18.91, + 6.0, + 6.11, + 6.85, + 7.58, + 8.31, + 40.76, + 16.06, + 10.32, + 10.91, + 11.4, + 11.83, + 12.17, + 12.4, + 12.54, + 12.58, + 12.52, + 12.47, + 12.2, + 11.89, + 11.61, + 11.33, + 11.1, + 10.96, + 10.97, + 11.16, + 11.54, + 12.12, + 27.78, + 17.73, + 14.47, + 15.2, + 15.77, + 16.1, + 18.54, + 19.5, + 15.39, + 14.64, + 13.72, + 12.69, + 11.57, + 10.45, + 9.35, + 8.29, + 7.32, + 6.41, + 5.63, + 4.9, + 4.26, + 3.72, + 3.25, + 2.83, + 2.49, + 2.19, + 1.93, + 1.71, + 1.52, + 1.48, + 1.26, + 1.13, + 1.05, + 0.96, + 0.85, + 0.78, + 0.72, + 0.68, + 0.67, + 0.65, + 0.61, + 0.62, + 0.59, + 0.62, + 0.64, + 0.55, + 0.47, + 0.4 + ], + "expected": { + "Rf": 77.89169336745758, + "Rg": 87.43272704289573, + "CCT_K": 6342.693872583665, + "Duv": 0.010803976772156637, + "bins": [ + { + "bin": 1, + "ref_a": 23.87265953558795, + "ref_b": 4.9390298042181575, + "test_a": 18.603221318910904, + "test_b": 3.134170908890933, + "ref_a_norm": 0.9792615681203302, + "ref_b_norm": 0.20260005232603429, + "test_a_norm": 0.763108092489184, + "test_b_norm": 0.1285643568292973, + "Rcs_pct": -22.6443794882173, + "Rhs": -0.03044366920182976, + "Rf_h": 59.638424790882645 + }, + { + "bin": 2, + "ref_a": 18.65390346015735, + "ref_b": 11.924451052353875, + "test_a": 14.798308097193791, + "test_b": 11.734295566457929, + "ref_a_norm": 0.8425593539881446, + "ref_b_norm": 0.5386035044511689, + "test_a_norm": 0.6684098551877011, + "test_b_norm": 0.5300145630697579, + "Rcs_pct": -14.95717764149495, + "Rhs": 0.08961083386831828, + "Rf_h": 72.90933195457764 + }, + { + "bin": 3, + "ref_a": 13.466388397451379, + "ref_b": 20.702853840388833, + "test_a": 8.741244867315306, + "test_b": 21.25959569335891, + "ref_a_norm": 0.5452596833111713, + "ref_b_norm": 0.8382671875693342, + "test_a_norm": 0.35393665082464093, + "test_b_norm": 0.8608098974241897, + "Rcs_pct": -8.754980351729309, + "Rhs": 0.17160334621307796, + "Rf_h": 67.09907449140957 + }, + { + "bin": 4, + "ref_a": 4.503438172646038, + "ref_b": 22.841213478525557, + "test_a": 1.724757699877955, + "test_b": 23.836360702360505, + "ref_a_norm": 0.19343887812091295, + "ref_b_norm": 0.981112328141545, + "test_a_norm": 0.07408455089298303, + "test_b_norm": 1.0238574831018201, + "Rcs_pct": 1.8638944660677832, + "Rhs": 0.12540013334341357, + "Rf_h": 79.7878276543994 + }, + { + "bin": 5, + "ref_a": -1.5307155159621548, + "ref_b": 21.450688409269702, + "test_a": -3.1333431159158924, + "test_b": 22.645855759342297, + "ref_a_norm": -0.07117874002116178, + "ref_b_norm": 0.9974635767630814, + "test_a_norm": -0.14570141395913597, + "test_b_norm": 1.0530392243641484, + "Rcs_pct": 6.904642957206586, + "Rhs": 0.06224847066790751, + "Rf_h": 85.73451145415164 + }, + { + "bin": 6, + "ref_a": -10.210858872202833, + "ref_b": 16.704849685200923, + "test_a": -9.451786736895063, + "test_b": 17.413294083309616, + "ref_a_norm": -0.5215370135462523, + "ref_b_norm": 0.8532286583919086, + "test_a_norm": -0.48276611097386307, + "test_b_norm": 0.889413663030355, + "Rcs_pct": 0.8546772401372217, + "Rhs": -0.052340138789281114, + "Rf_h": 90.66960332395827 + }, + { + "bin": 7, + "ref_a": -17.902129801397887, + "ref_b": 11.54765320809248, + "test_a": -15.99144535940055, + "test_b": 11.813374012830097, + "ref_a_norm": -0.8403417213785884, + "ref_b_norm": 0.5420570000567015, + "test_a_norm": -0.7506525128424089, + "test_b_norm": 0.5545301683856384, + "Rcs_pct": -6.764413041429917, + "Rhs": -0.06019971492043447, + "Rf_h": 86.35547212332729 + }, + { + "bin": 8, + "ref_a": -24.03135883617434, + "ref_b": 2.8763931971795134, + "test_a": -20.756005785853162, + "test_b": 3.766480098568168, + "ref_a_norm": -0.9929128148104396, + "ref_b_norm": 0.11884503433130754, + "test_a_norm": -0.857583804126411, + "test_b_norm": 0.15562109417497152, + "Rcs_pct": -12.555404833304188, + "Rhs": -0.06247079843836521, + "Rf_h": 77.03673440838986 + }, + { + "bin": 9, + "ref_a": -15.668831874589918, + "ref_b": -2.6740820986511826, + "test_a": -13.413555859608447, + "test_b": -2.7372484918020143, + "ref_a_norm": -0.985747740039494, + "ref_b_norm": -0.1682301786453024, + "test_a_norm": -0.8438652274995192, + "test_b_norm": -0.17220406322031373, + "Rcs_pct": -13.838101342444014, + "Rhs": 0.0315774325570736, + "Rf_h": 84.26069245091726 + }, + { + "bin": 10, + "ref_a": -19.718604156365064, + "ref_b": -12.066032308918006, + "test_a": -16.545694288247795, + "test_b": -13.195722541538833, + "ref_a_norm": -0.8529780800537976, + "ref_b_norm": -0.5219467357381757, + "test_a_norm": -0.7157258412021547, + "test_b_norm": -0.5708143431020264, + "Rcs_pct": -8.697167781538697, + "Rhs": 0.11688518887024324, + "Rf_h": 75.73302475522127 + }, + { + "bin": 11, + "ref_a": -12.82673710651211, + "ref_b": -18.981122966435358, + "test_a": -10.406116540966051, + "test_b": -20.084043212063264, + "ref_a_norm": -0.5599069802880396, + "ref_b_norm": -0.828555473957374, + "test_a_norm": -0.45424313608327094, + "test_b_norm": -0.8766996542816549, + "Rcs_pct": -1.8673263597736591, + "Rhs": 0.11460374905663404, + "Rf_h": 80.55537687435293 + }, + { + "bin": 12, + "ref_a": -3.702346608781836, + "ref_b": -20.757278848803203, + "test_a": -3.1157411561264805, + "test_b": -21.839217110349402, + "ref_a_norm": -0.17559252471302939, + "ref_b_norm": -0.9844629323976114, + "test_a_norm": -0.1477713768502489, + "test_b_norm": -1.035776407607603, + "Rcs_pct": 4.489986447688759, + "Rhs": 0.03729733471022076, + "Rf_h": 89.72061272563607 + }, + { + "bin": 13, + "ref_a": 1.9644982793014634, + "ref_b": -15.80485632673549, + "test_a": 0.7761685921093605, + "test_b": -17.166936166805836, + "ref_a_norm": 0.12334793303188686, + "ref_b_norm": -0.9923634855317688, + "test_a_norm": 0.04873447461353955, + "test_b_norm": -1.0778864583270522, + "Rcs_pct": 6.932330922436761, + "Rhs": -0.08986448603910198, + "Rf_h": 85.29550435872937 + }, + { + "bin": 14, + "ref_a": 12.68410623135542, + "ref_b": -18.71231759441638, + "test_a": 9.823843346932236, + "test_b": -21.21784045976325, + "ref_a_norm": 0.5610913020949659, + "ref_b_norm": -0.8277539191772972, + "test_a_norm": 0.4345653493094529, + "test_b_norm": -0.9385876713790051, + "Rcs_pct": 2.186084390111578, + "Rhs": -0.1667784184459203, + "Rf_h": 72.26867153665846 + }, + { + "bin": 15, + "ref_a": 12.18652001638465, + "ref_b": -8.315724446307796, + "test_a": 8.400332455698845, + "test_b": -11.282411167482257, + "ref_a_norm": 0.8260148528151908, + "ref_b_norm": -0.5636483504177925, + "test_a_norm": 0.5693831682599797, + "test_b_norm": -0.7647334257342073, + "Rcs_pct": -10.166456511136564, + "Rhs": -0.3097730544017192, + "Rf_h": 66.11243748207937 + }, + { + "bin": 16, + "ref_a": 22.619928195569663, + "ref_b": -3.813018752685578, + "test_a": 19.34953882496955, + "test_b": -5.9899069370120905, + "ref_a_norm": 0.9860880398516595, + "ref_b_norm": -0.1662238781328125, + "test_a_norm": 0.8435194244199625, + "test_b_norm": -0.2611226498751208, + "Rcs_pct": -12.13153675247351, + "Rhs": -0.12088907554716534, + "Rf_h": 71.89660031105873 + } + ] + } +} \ No newline at end of file diff --git a/crates/tm30/tests/golden/illuminant_FL6.json b/crates/tm30/tests/golden/illuminant_FL6.json new file mode 100644 index 0000000..dafe7a6 --- /dev/null +++ b/crates/tm30/tests/golden/illuminant_FL6.json @@ -0,0 +1,403 @@ +{ + "name": "illuminant_FL6", + "source": "colour.SDS_ILLUMINANTS['FL6'] (380.0, 780.0, 5.0)", + "generator": "crates/tm30/tools/golden.py (tm30.py + colour-science 0.4.7, numpy 2.5.1)", + "wavelengths": [ + 380.0, + 385.0, + 390.0, + 395.0, + 400.0, + 405.0, + 410.0, + 415.0, + 420.0, + 425.0, + 430.0, + 435.0, + 440.0, + 445.0, + 450.0, + 455.0, + 460.0, + 465.0, + 470.0, + 475.0, + 480.0, + 485.0, + 490.0, + 495.0, + 500.0, + 505.0, + 510.0, + 515.0, + 520.0, + 525.0, + 530.0, + 535.0, + 540.0, + 545.0, + 550.0, + 555.0, + 560.0, + 565.0, + 570.0, + 575.0, + 580.0, + 585.0, + 590.0, + 595.0, + 600.0, + 605.0, + 610.0, + 615.0, + 620.0, + 625.0, + 630.0, + 635.0, + 640.0, + 645.0, + 650.0, + 655.0, + 660.0, + 665.0, + 670.0, + 675.0, + 680.0, + 685.0, + 690.0, + 695.0, + 700.0, + 705.0, + 710.0, + 715.0, + 720.0, + 725.0, + 730.0, + 735.0, + 740.0, + 745.0, + 750.0, + 755.0, + 760.0, + 765.0, + 770.0, + 775.0, + 780.0 + ], + "values": [ + 1.05, + 1.31, + 1.63, + 1.9, + 3.11, + 14.8, + 3.43, + 3.3, + 3.68, + 4.07, + 4.45, + 32.61, + 10.74, + 5.48, + 5.78, + 6.03, + 6.25, + 6.41, + 6.52, + 6.58, + 6.59, + 6.56, + 6.56, + 6.42, + 6.28, + 6.2, + 6.19, + 6.3, + 6.6, + 7.12, + 7.94, + 9.07, + 10.49, + 25.22, + 17.46, + 15.63, + 17.22, + 18.53, + 19.43, + 21.97, + 23.01, + 19.41, + 18.56, + 17.42, + 16.09, + 14.64, + 13.15, + 11.68, + 10.25, + 8.95, + 7.74, + 6.69, + 5.71, + 4.87, + 4.16, + 3.55, + 3.02, + 2.57, + 2.2, + 1.87, + 1.6, + 1.37, + 1.29, + 1.05, + 0.91, + 0.81, + 0.71, + 0.61, + 0.54, + 0.48, + 0.44, + 0.43, + 0.4, + 0.37, + 0.38, + 0.35, + 0.39, + 0.41, + 0.33, + 0.26, + 0.21 + ], + "expected": { + "Rf": 66.61433558039634, + "Rg": 83.5112774593122, + "CCT_K": 4148.934694024666, + "Duv": 0.006102207908591839, + "bins": [ + { + "bin": 1, + "ref_a": 21.47438287073422, + "ref_b": 4.959011365891934, + "test_a": 15.636479799992552, + "test_b": 3.156525498251128, + "ref_a_norm": 0.9743575380345323, + "ref_b_norm": 0.22500530677138497, + "test_a_norm": 0.7094742630397428, + "test_b_norm": 0.14322108494259322, + "Rcs_pct": -27.5748927312308, + "Rhs": -0.028536597523491383, + "Rf_h": 55.80261150080031 + }, + { + "bin": 2, + "ref_a": 20.634410044667813, + "ref_b": 14.335877861928793, + "test_a": 14.430262907979595, + "test_b": 14.64117477936148, + "ref_a_norm": 0.8212501165635109, + "ref_b_norm": 0.5705683535251668, + "test_a_norm": 0.5743248810877807, + "test_b_norm": 0.5827191796687455, + "Rcs_pct": -19.856019249675136, + "Rhs": 0.14728735331442863, + "Rf_h": 57.442299857927814 + }, + { + "bin": 3, + "ref_a": 14.626967481311295, + "ref_b": 22.284177992890204, + "test_a": 7.273158234881256, + "test_b": 23.89911583119115, + "ref_a_norm": 0.5487344680091519, + "ref_b_norm": 0.8359967007223851, + "test_a_norm": 0.2728544122261326, + "test_b_norm": 0.8965815113948756, + "Rcs_pct": -10.289631783555418, + "Rhs": 0.26304500040667567, + "Rf_h": 48.4290067588813 + }, + { + "bin": 4, + "ref_a": 3.803852978366538, + "ref_b": 22.119867303351143, + "test_a": -0.6738627108643154, + "test_b": 24.2355900406971, + "ref_a_norm": 0.16947780061068565, + "ref_b_norm": 0.9855340050450642, + "test_a_norm": -0.030023444859817037, + "test_b_norm": 1.0797984359435975, + "Rcs_pct": 5.353240406940984, + "Rhs": 0.21405796315824263, + "Rf_h": 65.66916012077391 + }, + { + "bin": 5, + "ref_a": -2.203424500140753, + "ref_b": 19.13359885373665, + "test_a": -4.490707969743655, + "test_b": 20.940022955803343, + "ref_a_norm": -0.11440385819558045, + "ref_b_norm": 0.9934343245680438, + "test_a_norm": -0.2331617524156139, + "test_b_norm": 1.087225551270259, + "Rcs_pct": 11.515757040583875, + "Rhs": 0.09817823396306985, + "Rf_h": 78.1844742137563 + }, + { + "bin": 6, + "ref_a": -11.134104339446427, + "ref_b": 17.190445613048706, + "test_a": -10.273665145868407, + "test_b": 18.794523423065478, + "ref_a_norm": -0.5436254905391797, + "ref_b_norm": 0.8393279013806441, + "test_a_norm": -0.5016143269621691, + "test_b_norm": 0.9176474104985851, + "Rcs_pct": 4.178013994411565, + "Rhs": -0.07844299382239116, + "Rf_h": 86.2920166450318 + }, + { + "bin": 7, + "ref_a": -18.217449470654927, + "ref_b": 11.283667993942686, + "test_a": -14.832305220655579, + "test_b": 12.657305901779996, + "ref_a_norm": -0.85013564942941, + "ref_b_norm": 0.5265637450197606, + "test_a_norm": -0.6921644795342441, + "test_b_norm": 0.5906659431206095, + "Rcs_pct": -9.573495425175574, + "Rhs": -0.14106310947169023, + "Rf_h": 73.13396792425401 + }, + { + "bin": 8, + "ref_a": -22.76745356894645, + "ref_b": 3.624782376023594, + "test_a": -18.36864096324274, + "test_b": 5.093786991561544, + "ref_a_norm": -0.9875622119352324, + "ref_b_norm": 0.15722874278449034, + "test_a_norm": -0.7967590949497451, + "test_b_norm": 0.2209483609258201, + "Rcs_pct": -17.470580777248475, + "Rhs": -0.09971910508031064, + "Rf_h": 67.8662600334712 + }, + { + "bin": 9, + "ref_a": -19.355854829182498, + "ref_b": -2.0999626619016887, + "test_a": -15.393091256960593, + "test_b": -1.4699482209071788, + "ref_a_norm": -0.9941661529449654, + "ref_b_norm": -0.10785944714584565, + "test_a_norm": -0.7906284920979455, + "test_b_norm": -0.07550029594168577, + "Rcs_pct": -20.593969899505012, + "Rhs": 0.007970848609672142, + "Rf_h": 71.90117873538085 + }, + { + "bin": 10, + "ref_a": -20.160065800004045, + "ref_b": -11.235040792360143, + "test_a": -14.06996666906654, + "test_b": -12.665921339567078, + "ref_a_norm": -0.8735126284537527, + "ref_b_norm": -0.48680148719145905, + "test_a_norm": -0.6096355879627406, + "test_b_norm": -0.5487999072459125, + "Rcs_pct": -18.496126387610495, + "Rhs": 0.1981520311601613, + "Rf_h": 55.477195148736804 + }, + { + "bin": 11, + "ref_a": -12.101017525818357, + "ref_b": -17.33599921224681, + "test_a": -7.618906108544666, + "test_b": -19.086860081639283, + "ref_a_norm": -0.5723767399664063, + "ref_b_norm": -0.8199907728416393, + "test_a_norm": -0.36037338440463257, + "test_b_norm": -0.9028062909928569, + "Rcs_pct": -4.892416688056499, + "Rhs": 0.22228418457269764, + "Rf_h": 64.92074600291897 + }, + { + "bin": 12, + "ref_a": -5.407439678165485, + "ref_b": -23.67124778576976, + "test_a": -2.5041957450768906, + "test_b": -25.509047437903305, + "ref_a_norm": -0.22270224417716003, + "ref_b_norm": -0.974886511568632, + "test_a_norm": -0.1031338388367782, + "test_b_norm": -1.0505752166189668, + "Rcs_pct": 5.0907729105339845, + "Rhs": 0.13203706580038707, + "Rf_h": 73.76205230717126 + }, + { + "bin": 13, + "ref_a": 3.6287582362270157, + "ref_b": -15.357617437694259, + "test_a": 2.742176943630915, + "test_b": -17.43542962674284, + "ref_a_norm": 0.22995198922234197, + "ref_b_norm": -0.9732019742338628, + "test_a_norm": 0.17376992401764466, + "test_b_norm": -1.1048715468529904, + "Rcs_pct": 11.817900150950909, + "Rhs": -0.08079000189741321, + "Rf_h": 80.14739558179907 + }, + { + "bin": 14, + "ref_a": 13.958677200003653, + "ref_b": -18.620643741125384, + "test_a": 11.692762762303158, + "test_b": -22.166890046583916, + "ref_a_norm": 0.5998128213342788, + "ref_b_norm": -0.800140349790593, + "test_a_norm": 0.5024451043002568, + "test_b_norm": -0.9525247033468732, + "Rcs_pct": 7.260835413123608, + "Rhs": -0.1656185087468662, + "Rf_h": 67.66290059755661 + }, + { + "bin": 15, + "ref_a": 15.355796646481554, + "ref_b": -11.071054438311299, + "test_a": 11.214658778960198, + "test_b": -14.875790937487771, + "ref_a_norm": 0.8111614336950944, + "ref_b_norm": -0.5848223050514737, + "test_a_norm": 0.5924081246300554, + "test_b_norm": -0.7858053985734362, + "Rcs_pct": -7.022650497720961, + "Rhs": -0.2886441617411452, + "Rf_h": 59.9922503313349 + }, + { + "bin": 16, + "ref_a": 20.06416845530512, + "ref_b": -3.632426485094434, + "test_a": 15.723384973455486, + "test_b": -6.75077887412359, + "ref_a_norm": 0.9840043190754723, + "ref_b_norm": -0.17814460429891285, + "test_a_norm": 0.7711198577121045, + "test_b_norm": -0.3310775417410663, + "Rcs_pct": -17.895821011929915, + "Rhs": -0.19152607205170172, + "Rf_h": 61.42080507539294 + } + ] + } +} \ No newline at end of file diff --git a/crates/tm30/tests/golden/illuminant_FL7.json b/crates/tm30/tests/golden/illuminant_FL7.json new file mode 100644 index 0000000..fa587f5 --- /dev/null +++ b/crates/tm30/tests/golden/illuminant_FL7.json @@ -0,0 +1,403 @@ +{ + "name": "illuminant_FL7", + "source": "colour.SDS_ILLUMINANTS['FL7'] (380.0, 780.0, 5.0)", + "generator": "crates/tm30/tools/golden.py (tm30.py + colour-science 0.4.7, numpy 2.5.1)", + "wavelengths": [ + 380.0, + 385.0, + 390.0, + 395.0, + 400.0, + 405.0, + 410.0, + 415.0, + 420.0, + 425.0, + 430.0, + 435.0, + 440.0, + 445.0, + 450.0, + 455.0, + 460.0, + 465.0, + 470.0, + 475.0, + 480.0, + 485.0, + 490.0, + 495.0, + 500.0, + 505.0, + 510.0, + 515.0, + 520.0, + 525.0, + 530.0, + 535.0, + 540.0, + 545.0, + 550.0, + 555.0, + 560.0, + 565.0, + 570.0, + 575.0, + 580.0, + 585.0, + 590.0, + 595.0, + 600.0, + 605.0, + 610.0, + 615.0, + 620.0, + 625.0, + 630.0, + 635.0, + 640.0, + 645.0, + 650.0, + 655.0, + 660.0, + 665.0, + 670.0, + 675.0, + 680.0, + 685.0, + 690.0, + 695.0, + 700.0, + 705.0, + 710.0, + 715.0, + 720.0, + 725.0, + 730.0, + 735.0, + 740.0, + 745.0, + 750.0, + 755.0, + 760.0, + 765.0, + 770.0, + 775.0, + 780.0 + ], + "values": [ + 2.56, + 3.18, + 3.84, + 4.53, + 6.15, + 19.37, + 7.37, + 7.05, + 7.71, + 8.41, + 9.15, + 44.14, + 17.52, + 11.35, + 12.0, + 12.58, + 13.08, + 13.45, + 13.71, + 13.88, + 13.95, + 13.93, + 13.82, + 13.64, + 13.43, + 13.25, + 13.08, + 12.93, + 12.78, + 12.6, + 12.44, + 12.33, + 12.26, + 29.52, + 17.05, + 12.44, + 12.58, + 12.72, + 12.83, + 15.46, + 16.75, + 12.83, + 12.67, + 12.45, + 12.19, + 11.89, + 11.6, + 11.35, + 11.12, + 10.95, + 10.76, + 10.42, + 10.11, + 10.04, + 10.02, + 10.11, + 9.87, + 8.65, + 7.27, + 6.44, + 5.83, + 5.41, + 5.04, + 4.57, + 4.12, + 3.77, + 3.46, + 3.08, + 2.73, + 2.47, + 2.25, + 2.06, + 1.9, + 1.75, + 1.62, + 1.54, + 1.45, + 1.32, + 1.17, + 0.99, + 0.81 + ], + "expected": { + "Rf": 91.50869346468996, + "Rg": 98.87497602816629, + "CCT_K": 6489.960061083189, + "Duv": 0.003264676588044968, + "bins": [ + { + "bin": 1, + "ref_a": 23.825015547519147, + "ref_b": 4.881654598476364, + "test_a": 22.6516177651795, + "test_b": 4.210286137009446, + "ref_a_norm": 0.9796474204886955, + "ref_b_norm": 0.20072601109433985, + "test_a_norm": 0.9313991367306649, + "test_b_norm": 0.17312038875332883, + "Rcs_pct": -5.270679626655804, + "Rhs": -0.01766241483335448, + "Rf_h": 90.06087358388218 + }, + { + "bin": 2, + "ref_a": 18.626798446208436, + "ref_b": 11.893394281714265, + "test_a": 17.53944289937631, + "test_b": 11.831547345432073, + "ref_a_norm": 0.8428411721886541, + "ref_b_norm": 0.53816239042101, + "test_a_norm": 0.7936395862948434, + "test_b_norm": 0.5353638878000204, + "Rcs_pct": -4.24643883010463, + "Rhs": 0.025008066650656448, + "Rf_h": 92.2602668733799 + }, + { + "bin": 3, + "ref_a": 13.416515030615493, + "ref_b": 20.70775418776164, + "test_a": 11.68510710763039, + "test_b": 21.18550410114834, + "ref_a_norm": 0.5437476847674886, + "ref_b_norm": 0.8392487445984032, + "test_a_norm": 0.4735767761997332, + "test_b_norm": 0.8586111057413004, + "Rcs_pct": -2.2885653111438464, + "Rhs": 0.06910212963371802, + "Rf_h": 87.73050857457427 + }, + { + "bin": 4, + "ref_a": 4.497732194468745, + "ref_b": 22.856648188462042, + "test_a": 2.9777220871568804, + "test_b": 23.534744487354903, + "ref_a_norm": 0.1930773385970052, + "ref_b_norm": 0.9811835410973307, + "test_a_norm": 0.12782678710324563, + "test_b_norm": 1.0102926616589603, + "Rcs_pct": 1.5820045869681665, + "Rhs": 0.069675688147247, + "Rf_h": 88.53755230038237 + }, + { + "bin": 5, + "ref_a": -1.5564921163978616, + "ref_b": 21.49654049251981, + "test_a": -2.747187202526903, + "test_b": 22.502536949132164, + "ref_a_norm": -0.07221757211737939, + "ref_b_norm": 0.9973889022229349, + "test_a_norm": -0.12746302267021295, + "test_b_norm": 1.044064770921431, + "Rcs_pct": 5.655685770779722, + "Rhs": 0.04507791445669155, + "Rf_h": 89.02101722683231 + }, + { + "bin": 6, + "ref_a": -10.216553964629892, + "ref_b": 16.758257946109868, + "test_a": -10.352388481198771, + "test_b": 17.394801155071843, + "ref_a_norm": -0.5205370027417338, + "ref_b_norm": 0.8538391117632478, + "test_a_norm": -0.5274578189355724, + "test_b_norm": 0.8862712112026281, + "Rcs_pct": 3.0811304612515866, + "Rhs": -0.012263860685343214, + "Rf_h": 95.04935272594383 + }, + { + "bin": 7, + "ref_a": -17.900885124314406, + "ref_b": 11.619945883088482, + "test_a": -17.408242555551602, + "test_b": 12.075728814475376, + "ref_a_norm": -0.8387780978069008, + "ref_b_norm": 0.5444734177528203, + "test_a_norm": -0.8156944461407436, + "test_b_norm": 0.5658299449606443, + "Rcs_pct": -0.7328304104046548, + "Rhs": -0.030581893132728483, + "Rf_h": 95.15602484621732 + }, + { + "bin": 8, + "ref_a": -24.005640425956276, + "ref_b": 2.9794232616988148, + "test_a": -23.09040277042542, + "test_b": 3.7437224982272013, + "ref_a_norm": -0.9923857795497559, + "ref_b_norm": 0.12316843973771517, + "test_a_norm": -0.9545501368365873, + "test_b_norm": 0.15476433471043977, + "Rcs_pct": -3.0944588123054926, + "Rhs": -0.03837015643101397, + "Rf_h": 91.91991305647048 + }, + { + "bin": 9, + "ref_a": -15.681738097110351, + "ref_b": -2.597786790941883, + "test_a": -14.905298900248942, + "test_b": -2.316965597372676, + "ref_a_norm": -0.98655500547319, + "ref_b_norm": -0.16342956028758726, + "test_a_norm": -0.9377083807326355, + "test_b_norm": -0.145762797047248, + "Rcs_pct": -5.13546650724566, + "Rhs": -0.007797797588457849, + "Rf_h": 93.87609522663926 + }, + { + "bin": 10, + "ref_a": -19.75796450515429, + "ref_b": -11.977979598701992, + "test_a": -18.493445265528035, + "test_b": -12.19380808293665, + "ref_a_norm": -0.8551315311295581, + "ref_b_norm": -0.5184110960116667, + "test_a_norm": -0.8004027014850723, + "test_b_norm": -0.5277522273886771, + "Rcs_pct": -4.031570423048023, + "Rhs": 0.03817257552298703, + "Rf_h": 90.65971842930655 + }, + { + "bin": 11, + "ref_a": -12.860910077714637, + "ref_b": -18.94000009671232, + "test_a": -11.510994893966597, + "test_b": -19.430537611464484, + "ref_a_norm": -0.5617636012945685, + "ref_b_norm": -0.8272978038533385, + "test_a_norm": -0.5027994058774372, + "test_b_norm": -0.8487244462287302, + "Rcs_pct": -1.4943149758896752, + "Rhs": 0.06093094140053765, + "Rf_h": 89.54655981386743 + }, + { + "bin": 12, + "ref_a": -3.745028714574225, + "ref_b": -20.755288084882153, + "test_a": -2.740833936195919, + "test_b": -21.31126020711961, + "ref_a_norm": -0.177569853430874, + "ref_b_norm": -0.9841081989052514, + "test_a_norm": -0.129956141173141, + "test_b_norm": -1.0104695156751766, + "Rcs_pct": 1.6565817003245082, + "Rhs": 0.051841665905153274, + "Rf_h": 91.84358886625594 + }, + { + "bin": 13, + "ref_a": 1.9079141173395253, + "ref_b": -15.819274038988182, + "test_a": 2.282215652025648, + "test_b": -16.400980309623545, + "ref_a_norm": 0.11973921144181265, + "ref_b_norm": -0.9928053793384144, + "test_a_norm": 0.14323008568895826, + "test_b_norm": -1.029312814082785, + "Rcs_pct": 4.038879684387614, + "Rhs": 0.015917256485141695, + "Rf_h": 94.52465661008777 + }, + { + "bin": 14, + "ref_a": 12.614288986715366, + "ref_b": -18.76992516605142, + "test_a": 12.523626755624798, + "test_b": -19.693893162587337, + "ref_a_norm": 0.5577884486420331, + "ref_b_norm": -0.8299831604083988, + "test_a_norm": 0.5537794755414731, + "test_b_norm": -0.8708398964420685, + "Rcs_pct": 3.1743868350215356, + "Rhs": -0.026032125668300272, + "Rf_h": 92.4034214021567 + }, + { + "bin": 15, + "ref_a": 12.096137752427511, + "ref_b": -8.347212669849775, + "test_a": 11.652622397162306, + "test_b": -9.196689321296702, + "ref_a_norm": 0.8230522006493847, + "ref_b_norm": -0.5679657340070834, + "test_a_norm": 0.7928742796762572, + "test_b_norm": -0.6257663015670347, + "Rcs_pct": 0.7020250536324284, + "Rhs": -0.06482537008702735, + "Rf_h": 92.56961452295765 + }, + { + "bin": 16, + "ref_a": 22.588599076378774, + "ref_b": -3.8857026585061076, + "test_a": 22.071100044653353, + "test_b": -4.82548561063591, + "ref_a_norm": 0.9855249382501239, + "ref_b_norm": -0.16953051668383864, + "test_a_norm": 0.9629468137917985, + "test_b_norm": -0.21053259621672843, + "Rcs_pct": -1.4145183228435354, + "Rhs": -0.04461900964287579, + "Rf_h": 92.18821746212613 + } + ] + } +} \ No newline at end of file diff --git a/crates/tm30/tests/golden/illuminant_FL8.json b/crates/tm30/tests/golden/illuminant_FL8.json new file mode 100644 index 0000000..5bbb376 --- /dev/null +++ b/crates/tm30/tests/golden/illuminant_FL8.json @@ -0,0 +1,403 @@ +{ + "name": "illuminant_FL8", + "source": "colour.SDS_ILLUMINANTS['FL8'] (380.0, 780.0, 5.0)", + "generator": "crates/tm30/tools/golden.py (tm30.py + colour-science 0.4.7, numpy 2.5.1)", + "wavelengths": [ + 380.0, + 385.0, + 390.0, + 395.0, + 400.0, + 405.0, + 410.0, + 415.0, + 420.0, + 425.0, + 430.0, + 435.0, + 440.0, + 445.0, + 450.0, + 455.0, + 460.0, + 465.0, + 470.0, + 475.0, + 480.0, + 485.0, + 490.0, + 495.0, + 500.0, + 505.0, + 510.0, + 515.0, + 520.0, + 525.0, + 530.0, + 535.0, + 540.0, + 545.0, + 550.0, + 555.0, + 560.0, + 565.0, + 570.0, + 575.0, + 580.0, + 585.0, + 590.0, + 595.0, + 600.0, + 605.0, + 610.0, + 615.0, + 620.0, + 625.0, + 630.0, + 635.0, + 640.0, + 645.0, + 650.0, + 655.0, + 660.0, + 665.0, + 670.0, + 675.0, + 680.0, + 685.0, + 690.0, + 695.0, + 700.0, + 705.0, + 710.0, + 715.0, + 720.0, + 725.0, + 730.0, + 735.0, + 740.0, + 745.0, + 750.0, + 755.0, + 760.0, + 765.0, + 770.0, + 775.0, + 780.0 + ], + "values": [ + 1.21, + 1.5, + 1.81, + 2.13, + 3.17, + 13.08, + 3.83, + 3.45, + 3.86, + 4.42, + 5.09, + 34.1, + 12.42, + 7.68, + 8.6, + 9.46, + 10.24, + 10.84, + 11.33, + 11.71, + 11.98, + 12.17, + 12.28, + 12.32, + 12.35, + 12.44, + 12.55, + 12.68, + 12.77, + 12.72, + 12.6, + 12.43, + 12.22, + 28.96, + 16.51, + 11.79, + 11.76, + 11.77, + 11.84, + 14.61, + 16.11, + 12.34, + 12.53, + 12.72, + 12.92, + 13.12, + 13.34, + 13.61, + 13.87, + 14.07, + 14.2, + 14.16, + 14.13, + 14.34, + 14.5, + 14.46, + 14.0, + 12.58, + 10.99, + 9.98, + 9.22, + 8.62, + 8.07, + 7.39, + 6.71, + 6.16, + 5.63, + 5.03, + 4.46, + 4.02, + 3.66, + 3.36, + 3.09, + 2.85, + 2.65, + 2.51, + 2.37, + 2.15, + 1.89, + 1.61, + 1.32 + ], + "expected": { + "Rf": 95.50168891791436, + "Rg": 101.63457471151808, + "CCT_K": 4994.74123669448, + "Duv": 0.003243057802911453, + "bins": [ + { + "bin": 1, + "ref_a": 23.480281143576022, + "ref_b": 4.938329548493439, + "test_a": 23.48693791639685, + "test_b": 4.561764983827416, + "ref_a_norm": 0.9785908294204929, + "ref_b_norm": 0.2058154235573996, + "test_a_norm": 0.9788682646350103, + "test_b_norm": 0.19012129164247113, + "Rcs_pct": -0.2789668874382727, + "Rhs": -0.015446698496207245, + "Rf_h": 97.22018112001263 + }, + { + "bin": 2, + "ref_a": 17.840653986970327, + "ref_b": 12.027413616966063, + "test_a": 17.713975622659344, + "test_b": 11.984944763307794, + "ref_a_norm": 0.8291724154281395, + "ref_b_norm": 0.5589929386790721, + "test_a_norm": 0.8232848394796941, + "test_b_norm": 0.5570191320016931, + "Rcs_pct": -0.5991928726942841, + "Rhs": 0.001629801668797915, + "Rf_h": 98.04054384888207 + }, + { + "bin": 3, + "ref_a": 14.549056574038039, + "ref_b": 22.06559594089347, + "test_a": 13.969934837791216, + "test_b": 22.331701197640808, + "ref_a_norm": 0.5504669432514051, + "ref_b_norm": 0.8348569604354116, + "test_a_norm": 0.528555737511021, + "test_b_norm": 0.8449251147875106, + "Rcs_pct": -0.38018492831835893, + "Rhs": 0.023812068601511468, + "Rf_h": 95.53718373939056 + }, + { + "bin": 4, + "ref_a": 4.075506373991542, + "ref_b": 21.998941503984838, + "test_a": 3.2901992977358114, + "test_b": 22.516726188516266, + "ref_a_norm": 0.18215962620396597, + "ref_b_norm": 0.9832689716355497, + "test_a_norm": 0.14705938826078024, + "test_b_norm": 1.006411976684026, + "Rcs_pct": 1.585060197266431, + "Rhs": 0.03894077302065564, + "Rf_h": 93.30649022368056 + }, + { + "bin": 5, + "ref_a": -2.055040083135477, + "ref_b": 19.16082489235112, + "test_a": -2.712781893733294, + "test_b": 19.758175982837745, + "ref_a_norm": -0.10664058074374624, + "ref_b_norm": 0.9942976347847945, + "test_a_norm": -0.1407722598468493, + "test_b_norm": 1.0252955056877362, + "Rcs_pct": 3.7061015772620247, + "Rhs": 0.02742846384350077, + "Rf_h": 93.61110527420041 + }, + { + "bin": 6, + "ref_a": -10.83025249080319, + "ref_b": 17.502422879116434, + "test_a": -11.183063483958819, + "test_b": 18.008764275668337, + "ref_a_norm": -0.5261937075883273, + "ref_b_norm": 0.8503647347429513, + "test_a_norm": -0.543335221576494, + "test_b_norm": 0.8749656068817446, + "Rcs_pct": 2.9978192540261546, + "Rhs": 0.0005851357233847785, + "Rf_h": 95.56476491077471 + }, + { + "bin": 7, + "ref_a": -17.88709140683529, + "ref_b": 11.798633885484053, + "test_a": -17.851607658275555, + "test_b": 12.421664740043578, + "ref_a_norm": -0.8347562679745275, + "ref_b_norm": 0.5506196264911366, + "test_a_norm": -0.8331003094484727, + "test_b_norm": 0.5796952821780277, + "Rcs_pct": 1.4776689611515892, + "Rhs": -0.025095525425612636, + "Rf_h": 95.56573452395341 + }, + { + "bin": 8, + "ref_a": -22.259155156314122, + "ref_b": 4.298217742494155, + "test_a": -22.08968254291453, + "test_b": 4.894083193824708, + "ref_a_norm": -0.9818620988211796, + "ref_b_norm": 0.18959646330685684, + "test_a_norm": -0.9743865798845126, + "test_b_norm": 0.21588037653491507, + "Rcs_pct": -0.2204141840952653, + "Rhs": -0.027237276602067293, + "Rf_h": 95.77667224387189 + }, + { + "bin": 9, + "ref_a": -18.632068918233934, + "ref_b": -2.5570466293446725, + "test_a": -18.37134364440308, + "test_b": -2.0509443787112915, + "ref_a_norm": -0.9907137009726655, + "ref_b_norm": -0.135964564152002, + "test_a_norm": -0.9768502861201532, + "test_b_norm": -0.10905384178424046, + "Rcs_pct": -1.8847054715880804, + "Rhs": -0.023689022315498687, + "Rf_h": 95.92210954908477 + }, + { + "bin": 10, + "ref_a": -19.80180433756542, + "ref_b": -11.99762559764812, + "test_a": -19.222511541212178, + "test_b": -11.884655606548362, + "ref_a_norm": -0.8552642166344183, + "ref_b_norm": -0.5181921648816344, + "test_a_norm": -0.8302438502461332, + "test_b_norm": -0.5133128524061628, + "Rcs_pct": -2.351447510950823, + "Rhs": 0.009843570732291921, + "Rf_h": 95.71583192230483 + }, + { + "bin": 11, + "ref_a": -12.8977409704859, + "ref_b": -19.32395195185696, + "test_a": -12.196626921904063, + "test_b": -19.420657161314708, + "ref_a_norm": -0.5551502629113778, + "ref_b_norm": -0.8317500739942427, + "test_a_norm": -0.5249726023976697, + "test_b_norm": -0.8359125023278725, + "Rcs_pct": -1.3304877210786914, + "Rhs": 0.02740432896677285, + "Rf_h": 94.48748959215646 + }, + { + "bin": 12, + "ref_a": -3.1232592721929944, + "ref_b": -20.74698826917924, + "test_a": -2.371722914604854, + "test_b": -21.025386438925924, + "ref_a_norm": -0.14886302217893901, + "ref_b_norm": -0.9888578262964564, + "test_a_norm": -0.11304275760341156, + "test_b_norm": -1.0021270394183235, + "Rcs_pct": 0.6026061961718137, + "Rhs": 0.037720683296672296, + "Rf_h": 94.49670003850284 + }, + { + "bin": 13, + "ref_a": 2.723352528879152, + "ref_b": -15.577259864422752, + "test_a": 3.2484720236332514, + "test_b": -15.848857023877706, + "ref_a_norm": 0.1722166296987875, + "ref_b_norm": -0.9850591009960725, + "test_a_norm": 0.20542360845629018, + "test_b_norm": -1.0022340891553716, + "Rcs_pct": 2.332333575672414, + "Rhs": 0.029218242001400538, + "Rf_h": 95.88933067964301 + }, + { + "bin": 14, + "ref_a": 13.620680455814743, + "ref_b": -17.9429269009068, + "test_a": 14.043855632544075, + "test_b": -18.335063287835514, + "ref_a_norm": 0.6046345353534599, + "ref_b_norm": -0.7965030311668034, + "test_a_norm": 0.6234196707352703, + "test_b_norm": -0.8139103261161984, + "Rcs_pct": 2.4910098824186604, + "Rhs": 0.00594829432168838, + "Rf_h": 95.53625300674427 + }, + { + "bin": 15, + "ref_a": 12.88342908422043, + "ref_b": -8.25550616209417, + "test_a": 13.156491541738458, + "test_b": -8.494568475318678, + "ref_a_norm": 0.8419712382334039, + "ref_b_norm": -0.5395224128687414, + "test_a_norm": 0.8598166995596206, + "test_b_norm": -0.5551458614525592, + "Rcs_pct": 2.3517881780550867, + "Rhs": -0.0030760156294672714, + "Rf_h": 96.8758122547014 + }, + { + "bin": 16, + "ref_a": 22.83650256497141, + "ref_b": -4.127265436079328, + "test_a": 23.12646862549328, + "test_b": -4.689783457461917, + "ref_a_norm": 0.9840576473436042, + "ref_b_norm": -0.1778497869117938, + "test_a_norm": 0.9965527007570953, + "test_b_norm": -0.2020894952092987, + "Rcs_pct": 1.6983896963141476, + "Rhs": -0.021336285105414153, + "Rf_h": 95.49205763955483 + } + ] + } +} \ No newline at end of file diff --git a/crates/tm30/tests/golden/illuminant_FL9.json b/crates/tm30/tests/golden/illuminant_FL9.json new file mode 100644 index 0000000..44c2783 --- /dev/null +++ b/crates/tm30/tests/golden/illuminant_FL9.json @@ -0,0 +1,403 @@ +{ + "name": "illuminant_FL9", + "source": "colour.SDS_ILLUMINANTS['FL9'] (380.0, 780.0, 5.0)", + "generator": "crates/tm30/tools/golden.py (tm30.py + colour-science 0.4.7, numpy 2.5.1)", + "wavelengths": [ + 380.0, + 385.0, + 390.0, + 395.0, + 400.0, + 405.0, + 410.0, + 415.0, + 420.0, + 425.0, + 430.0, + 435.0, + 440.0, + 445.0, + 450.0, + 455.0, + 460.0, + 465.0, + 470.0, + 475.0, + 480.0, + 485.0, + 490.0, + 495.0, + 500.0, + 505.0, + 510.0, + 515.0, + 520.0, + 525.0, + 530.0, + 535.0, + 540.0, + 545.0, + 550.0, + 555.0, + 560.0, + 565.0, + 570.0, + 575.0, + 580.0, + 585.0, + 590.0, + 595.0, + 600.0, + 605.0, + 610.0, + 615.0, + 620.0, + 625.0, + 630.0, + 635.0, + 640.0, + 645.0, + 650.0, + 655.0, + 660.0, + 665.0, + 670.0, + 675.0, + 680.0, + 685.0, + 690.0, + 695.0, + 700.0, + 705.0, + 710.0, + 715.0, + 720.0, + 725.0, + 730.0, + 735.0, + 740.0, + 745.0, + 750.0, + 755.0, + 760.0, + 765.0, + 770.0, + 775.0, + 780.0 + ], + "values": [ + 0.9, + 1.12, + 1.36, + 1.6, + 2.59, + 12.8, + 3.05, + 2.56, + 2.86, + 3.3, + 3.82, + 32.62, + 10.77, + 5.84, + 6.57, + 7.25, + 7.86, + 8.35, + 8.75, + 9.06, + 9.31, + 9.48, + 9.61, + 9.68, + 9.74, + 9.88, + 10.04, + 10.26, + 10.48, + 10.63, + 10.78, + 10.96, + 11.18, + 27.71, + 16.29, + 12.28, + 12.74, + 13.21, + 13.65, + 16.57, + 18.14, + 14.55, + 14.65, + 14.66, + 14.61, + 14.5, + 14.39, + 14.4, + 14.47, + 14.62, + 14.72, + 14.55, + 14.4, + 14.58, + 14.88, + 15.51, + 15.47, + 13.2, + 10.57, + 9.18, + 8.25, + 7.57, + 7.03, + 6.35, + 5.72, + 5.25, + 4.8, + 4.29, + 3.8, + 3.43, + 3.12, + 2.86, + 2.64, + 2.43, + 2.26, + 2.14, + 2.02, + 1.83, + 1.61, + 1.38, + 1.12 + ], + "expected": { + "Rf": 91.04435254223048, + "Rg": 99.70375778923442, + "CCT_K": 4147.971519232706, + "Duv": 3.834042302772977e-05, + "bins": [ + { + "bin": 1, + "ref_a": 21.474798124586883, + "ref_b": 4.959662288845205, + "test_a": 20.624018444790877, + "test_b": 4.416580637371922, + "ref_a_norm": 0.9743520167872397, + "ref_b_norm": 0.22502921450922403, + "test_a_norm": 0.9357505411392918, + "test_b_norm": 0.20038857764161586, + "Rcs_pct": -4.266690889853531, + "Rhs": -0.016636399625055347, + "Rf_h": 92.29646108141574 + }, + { + "bin": 2, + "ref_a": 20.634390604802718, + "ref_b": 14.336437545015995, + "test_a": 19.452080139067196, + "test_b": 14.394207134108923, + "ref_a_norm": 0.8212394268760633, + "ref_b_norm": 0.5705837394671137, + "test_a_norm": 0.7741840043115502, + "test_b_norm": 0.572882943022294, + "Rcs_pct": -3.7847784901537165, + "Rhs": 0.028054309967632824, + "Rf_h": 91.79904088350527 + }, + { + "bin": 3, + "ref_a": 14.62696058239479, + "ref_b": 22.284369051930145, + "test_a": 12.823494561645562, + "test_b": 22.90124733936898, + "ref_a_norm": 0.548730999061903, + "ref_b_norm": 0.8359989776719381, + "test_a_norm": 0.48107390066710487, + "test_b_norm": 0.85914119078307, + "Rcs_pct": -1.8346222957292428, + "Rhs": 0.06911194610257887, + "Rf_h": 86.9733779933774 + }, + { + "bin": 4, + "ref_a": 3.8034631343410354, + "ref_b": 22.119890540251564, + "test_a": 2.268320641496065, + "test_b": 22.996290809342284, + "ref_a_norm": 0.1694607573143801, + "ref_b_norm": 0.9855369357514902, + "test_a_norm": 0.10106350979693692, + "test_b_norm": 1.0245843638623902, + "Rcs_pct": 2.4953501685579194, + "Rhs": 0.07470078890926177, + "Rf_h": 87.60849266933461 + }, + { + "bin": 5, + "ref_a": -2.203554209033358, + "ref_b": 19.133381352717517, + "test_a": -3.216260652860676, + "test_b": 20.00218389044994, + "ref_a_norm": -0.1144117882012863, + "ref_b_norm": 0.993433411316825, + "test_a_norm": -0.16699300208123713, + "test_b_norm": 1.0385429219103433, + "Rcs_pct": 5.45008299441547, + "Rhs": 0.04277045165151041, + "Rf_h": 90.3987719728256 + }, + { + "bin": 6, + "ref_a": -11.134370990057205, + "ref_b": 17.1898585256909, + "test_a": -11.304908626392077, + "test_b": 17.973787098377013, + "ref_a_norm": -0.543647741564529, + "ref_b_norm": 0.8393134891634871, + "test_a_norm": -0.5519744266487603, + "test_b_norm": 0.8775896520890158, + "Rcs_pct": 3.6451524720645545, + "Rhs": -0.014341711136881066, + "Rf_h": 94.15875292084522 + }, + { + "bin": 7, + "ref_a": -18.21768842067807, + "ref_b": 11.282763355603166, + "test_a": -17.589407933639013, + "test_b": 12.095382488850216, + "ref_a_norm": -0.8501576387116268, + "ref_b_norm": 0.5265282417309362, + "test_a_norm": -0.8208379224569872, + "test_b_norm": 0.5644504164624484, + "Rcs_pct": -0.33100216548695216, + "Rhs": -0.04782029751333864, + "Rf_h": 92.43585847910592 + }, + { + "bin": 8, + "ref_a": -22.76794157112604, + "ref_b": 3.6236739411036467, + "test_a": -21.921224026989748, + "test_b": 4.363985802497227, + "ref_a_norm": -0.9875701992963359, + "ref_b_norm": 0.15717856552913131, + "test_a_norm": -0.9508434266454946, + "test_b_norm": 0.18928994152743772, + "Rcs_pct": -2.9756459328770437, + "Rhs": -0.03865940281569829, + "Rf_h": 92.25271048307923 + }, + { + "bin": 9, + "ref_a": -19.355886814147926, + "ref_b": -2.1009007669177446, + "test_a": -18.514273847317416, + "test_b": -1.582968279589199, + "ref_a_norm": -0.9941610042363551, + "ref_b_norm": -0.10790689345802616, + "test_a_norm": -0.9509339074716135, + "test_b_norm": -0.0813047394635724, + "Rcs_pct": -4.758632301052527, + "Rhs": -0.017657812837124472, + "Rf_h": 92.80048409709133 + }, + { + "bin": 10, + "ref_a": -20.159570852108484, + "ref_b": -11.236044651252266, + "test_a": -18.681878843712767, + "test_b": -11.398050860087432, + "ref_a_norm": -0.87348904970866, + "ref_b_norm": -0.4868437942903885, + "test_a_norm": -0.8094624988636724, + "test_b_norm": -0.4938633211662561, + "Rcs_pct": -4.933629122603806, + "Rhs": 0.041407769062416125, + "Rf_h": 89.24986594736743 + }, + { + "bin": 11, + "ref_a": -12.100080089418258, + "ref_b": -17.336526422604372, + "test_a": -10.69942692199412, + "test_b": -17.847774015996677, + "ref_a_norm": -0.5723352210391186, + "ref_b_norm": -0.8200197526633755, + "test_a_norm": -0.5060841603640832, + "test_b_norm": -0.8442018243693132, + "Rcs_pct": -1.670045943101675, + "Rhs": 0.06852058294666862, + "Rf_h": 89.02018095999424 + }, + { + "bin": 12, + "ref_a": -5.40634350368827, + "ref_b": -23.67136466096169, + "test_a": -4.067232450392699, + "test_b": -24.36875853135096, + "ref_a_norm": -0.22265829240703014, + "ref_b_norm": -0.9748965508311053, + "test_a_norm": -0.16750749034150092, + "test_b_norm": -1.003618463933754, + "Rcs_pct": 1.7410641861686784, + "Rhs": 0.059694462144418134, + "Rf_h": 89.34563268806194 + }, + { + "bin": 13, + "ref_a": 3.629961320333195, + "ref_b": -15.357314340226713, + "test_a": 4.008461141982153, + "test_b": -16.02123228217366, + "ref_a_norm": 0.23002849424566296, + "ref_b_norm": -0.9731838941510864, + "test_a_norm": 0.2540138032786997, + "test_b_norm": -1.0152559800527394, + "Rcs_pct": 4.594298423111295, + "Rhs": 0.0153165812590814, + "Rf_h": 94.08782860328029 + }, + { + "bin": 14, + "ref_a": 13.960192504790864, + "ref_b": -18.61981537859308, + "test_a": 14.126925141929787, + "test_b": -19.5952827228057, + "ref_a_norm": 0.5998715897813425, + "ref_b_norm": -0.8000962915632123, + "test_a_norm": 0.6070361164936093, + "test_b_norm": -0.8420122713286627, + "Rcs_pct": 3.8832261219869673, + "Rhs": -0.0173301843977565, + "Rf_h": 92.16749331006449 + }, + { + "bin": 15, + "ref_a": 15.356945375150058, + "ref_b": -11.070220389389053, + "test_a": 15.032496228968572, + "test_b": -12.0536198405526, + "ref_a_norm": 0.8112030851350277, + "ref_b_norm": -0.5847645292486651, + "test_a_norm": 0.7940646411331538, + "test_b_norm": -0.636710840784996, + "Rcs_pct": 1.4609729015041177, + "Rhs": -0.05271338884137485, + "Rf_h": 92.35282965236965 + }, + { + "bin": 16, + "ref_a": 20.06485642892714, + "ref_b": -3.631540595006173, + "test_a": 19.679822909445104, + "test_b": -4.570425802499742, + "ref_a_norm": 0.9840130044189106, + "ref_b_norm": -0.1780966230293797, + "test_a_norm": 0.9651303380191011, + "test_b_norm": -0.224141071794948, + "Rcs_pct": -0.9537014922968016, + "Rhs": -0.048843543062012065, + "Rf_h": 92.43963081119162 + } + ] + } +} \ No newline at end of file diff --git a/crates/tm30/tests/golden/illuminant_HP1.json b/crates/tm30/tests/golden/illuminant_HP1.json new file mode 100644 index 0000000..17f47fa --- /dev/null +++ b/crates/tm30/tests/golden/illuminant_HP1.json @@ -0,0 +1,403 @@ +{ + "name": "illuminant_HP1", + "source": "colour.SDS_ILLUMINANTS['HP1'] (380.0, 780.0, 5.0)", + "generator": "crates/tm30/tools/golden.py (tm30.py + colour-science 0.4.7, numpy 2.5.1)", + "wavelengths": [ + 380.0, + 385.0, + 390.0, + 395.0, + 400.0, + 405.0, + 410.0, + 415.0, + 420.0, + 425.0, + 430.0, + 435.0, + 440.0, + 445.0, + 450.0, + 455.0, + 460.0, + 465.0, + 470.0, + 475.0, + 480.0, + 485.0, + 490.0, + 495.0, + 500.0, + 505.0, + 510.0, + 515.0, + 520.0, + 525.0, + 530.0, + 535.0, + 540.0, + 545.0, + 550.0, + 555.0, + 560.0, + 565.0, + 570.0, + 575.0, + 580.0, + 585.0, + 590.0, + 595.0, + 600.0, + 605.0, + 610.0, + 615.0, + 620.0, + 625.0, + 630.0, + 635.0, + 640.0, + 645.0, + 650.0, + 655.0, + 660.0, + 665.0, + 670.0, + 675.0, + 680.0, + 685.0, + 690.0, + 695.0, + 700.0, + 705.0, + 710.0, + 715.0, + 720.0, + 725.0, + 730.0, + 735.0, + 740.0, + 745.0, + 750.0, + 755.0, + 760.0, + 765.0, + 770.0, + 775.0, + 780.0 + ], + "values": [ + 1.9, + 2.2, + 2.5, + 2.7, + 3.1, + 4.3, + 3.8, + 4.2, + 4.8, + 5.19, + 5.89, + 7.39, + 7.89, + 5.69, + 12.89, + 6.69, + 4.3, + 20.78, + 12.99, + 6.69, + 1.4, + 1.5, + 3.2, + 18.18, + 56.24, + 2.9, + 2.1, + 13.39, + 2.1, + 2.0, + 2.2, + 2.3, + 2.6, + 5.1, + 11.39, + 15.48, + 20.78, + 55.64, + 254.03, + 56.14, + 111.78, + 297.98, + 142.55, + 334.84, + 189.4, + 117.78, + 79.92, + 108.09, + 46.85, + 38.16, + 32.47, + 28.37, + 25.37, + 22.98, + 20.38, + 19.78, + 17.78, + 16.78, + 19.18, + 17.98, + 13.69, + 9.99, + 8.19, + 7.59, + 6.99, + 6.79, + 6.49, + 6.39, + 6.09, + 5.99, + 5.79, + 5.79, + 5.79, + 5.79, + 6.39, + 5.99, + 5.59, + 31.97, + 27.87, + 5.89, + 6.69 + ], + "expected": { + "Rf": 34.49133955456195, + "Rg": 54.238088602828604, + "CCT_K": 1962.2467646128093, + "Duv": 0.0008317336845445266, + "bins": [ + { + "bin": 1, + "ref_a": 26.522392695676434, + "ref_b": 5.538917270016329, + "test_a": 11.979886218177473, + "test_b": 4.628841379743432, + "ref_a_norm": 0.9788814180412501, + "ref_b_norm": 0.20442888595683206, + "test_a_norm": 0.44215045542003684, + "test_b_norm": 0.17084004696265226, + "Rcs_pct": -53.297068509106495, + "Rhs": 0.07176757746247336, + "Rf_h": 15.249343574169036 + }, + { + "bin": 2, + "ref_a": 20.64134418827906, + "ref_b": 13.925478425443089, + "test_a": 6.530193885694615, + "test_b": 16.175814357446516, + "ref_a_norm": 0.8289870017450796, + "ref_b_norm": 0.5592678704679032, + "test_a_norm": 0.2622622732675516, + "test_b_norm": 0.6496446996208244, + "Rcs_pct": -42.10037142374142, + "Rhs": 0.3900009765551438, + "Rf_h": 17.615999445996422 + }, + { + "bin": 3, + "ref_a": 13.872125145026702, + "ref_b": 22.34326869343094, + "test_a": 0.4704416056747909, + "test_b": 26.024971627773915, + "ref_a_norm": 0.527469617379876, + "ref_b_norm": 0.8495738948091138, + "test_a_norm": 0.017887933618723043, + "test_b_norm": 0.9895658872242398, + "Rcs_pct": -16.67093271308394, + "Rhs": 0.501477068880314, + "Rf_h": 10.01242160292253 + }, + { + "bin": 4, + "ref_a": 2.952021728153385, + "ref_b": 18.856994407623603, + "test_a": -2.257697013425893, + "test_b": 21.53978166398952, + "ref_a_norm": 0.154664116316497, + "ref_b_norm": 0.9879671103452974, + "test_a_norm": -0.11828663392336891, + "test_b_norm": 1.128525330602894, + "Rcs_pct": 8.46073837094865, + "Rhs": 0.2951276265623474, + "Rf_h": 59.81691336123931 + }, + { + "bin": 5, + "ref_a": -1.954581068472175, + "ref_b": 11.97670830236876, + "test_a": -2.1653034234957795, + "test_b": 13.043935185580805, + "ref_a_norm": -0.16106769572564547, + "ref_b_norm": 0.9869433607829939, + "test_a_norm": -0.1784323191270496, + "test_b_norm": 1.0748884338567812, + "Rcs_pct": 8.964290312582582, + "Rhs": -0.00012626559385446256, + "Rf_h": 86.80230951575427 + }, + { + "bin": 6, + "ref_a": -10.189843644693763, + "ref_b": 13.84710460132965, + "test_a": -5.925967544140233, + "test_b": 15.061669711337274, + "ref_a_norm": -0.5926980656619317, + "ref_b_norm": 0.8054247345100622, + "test_a_norm": -0.3446872810866236, + "test_b_norm": 0.8760706066571636, + "Rcs_pct": -7.904751345295263, + "Rhs": -0.24546217454831967, + "Rf_h": 67.91442096597942 + }, + { + "bin": 7, + "ref_a": -18.137998406674225, + "ref_b": 11.572915402138298, + "test_a": -9.00725506390704, + "test_b": 13.653968031396388, + "ref_a_norm": -0.8430176914359037, + "ref_b_norm": 0.5378858354019741, + "test_a_norm": -0.4186391022812735, + "test_b_norm": 0.6346089767287603, + "Rcs_pct": -29.912140282859102, + "Rhs": -0.3161944644848351, + "Rf_h": 36.674789227044634 + }, + { + "bin": 8, + "ref_a": -18.75333954171441, + "ref_b": 4.109891440949631, + "test_a": -8.43384068394474, + "test_b": 3.8319940467700078, + "ref_a_norm": -0.976817320397588, + "ref_b_norm": 0.2140745724537971, + "test_a_norm": -0.4392989120271601, + "test_b_norm": 0.19959955122762058, + "Rcs_pct": -53.00140794276933, + "Rhs": -0.09066775162642542, + "Rf_h": 26.808698567767802 + }, + { + "bin": 9, + "ref_a": -25.28798391663808, + "ref_b": -6.202879104203643, + "test_a": -13.234960310935383, + "test_b": -9.466108436952936, + "ref_a_norm": -0.9712093684433988, + "ref_b_norm": -0.2382275438478402, + "test_a_norm": -0.5083013927614785, + "test_b_norm": -0.36355500806139524, + "Rcs_pct": -42.956315337919676, + "Rhs": 0.21322819817053737, + "Rf_h": 19.19704055206871 + }, + { + "bin": 10, + "ref_a": -18.563353752229023, + "ref_b": -13.964628854573254, + "test_a": -7.8103216045588395, + "test_b": -17.178127367978774, + "ref_a_norm": -0.7991289499102557, + "ref_b_norm": -0.6011596471947631, + "test_a_norm": -0.3362244875370668, + "test_b_norm": -0.7394967023859655, + "Rcs_pct": -30.803504387473176, + "Rhs": 0.37219899767339104, + "Rf_h": 25.752332736364355 + }, + { + "bin": 11, + "ref_a": -10.830689828633624, + "ref_b": -17.149427752721262, + "test_a": -3.1524680439698103, + "test_b": -19.57836922884756, + "ref_a_norm": -0.5339743932376466, + "ref_b_norm": -0.8455006489450421, + "test_a_norm": -0.15542289896711192, + "test_b_norm": -0.9652522595484009, + "Rcs_pct": -11.074211664081941, + "Rhs": 0.38128449438505146, + "Rf_h": 43.85225188598025 + }, + { + "bin": 12, + "ref_a": -4.468061401408513, + "ref_b": -20.150889438571983, + "test_a": -0.7316583363144833, + "test_b": -21.65047014288559, + "ref_a_norm": -0.21647271351455957, + "ref_b_norm": -0.9762886685318249, + "test_a_norm": -0.035448050328407615, + "test_b_norm": -1.0489417220674162, + "Rcs_pct": 3.594088565020806, + "Rhs": 0.19172023265264387, + "Rf_h": 58.400892217943465 + }, + { + "bin": 13, + "ref_a": 3.4939200010968703, + "ref_b": -12.583437581201393, + "test_a": 1.1250311848351677, + "test_b": -14.397952910756814, + "ref_a_norm": 0.26753870053320045, + "ref_b_norm": -0.9635471154629681, + "test_a_norm": 0.08614661502141892, + "test_b_norm": -1.1024893560450157, + "Rcs_pct": 10.088466401544613, + "Rhs": -0.20501297390839346, + "Rf_h": 77.05150280621464 + }, + { + "bin": 14, + "ref_a": 12.934690300090042, + "ref_b": -22.003557838957814, + "test_a": 3.2729902715781187, + "test_b": -28.045914091535433, + "ref_a_norm": 0.5067703923925617, + "ref_b_norm": -0.8620810689223426, + "test_a_norm": 0.1282330327006851, + "test_b_norm": -1.0988155540976927, + "Rcs_pct": -1.3466558523249845, + "Rhs": -0.4462649447976786, + "Rf_h": 19.545609528012314 + }, + { + "bin": 15, + "ref_a": 16.18189855240571, + "ref_b": -10.759914142954427, + "test_a": 7.911157770431405, + "test_b": -16.15500040969368, + "ref_a_norm": 0.8327151457289224, + "ref_b_norm": -0.5537016218810088, + "test_a_norm": 0.4071055614614459, + "test_b_norm": -0.8313309762042065, + "Rcs_pct": -19.96388309487055, + "Rhs": -0.4672963875097732, + "Rf_h": 33.35343779913493 + }, + { + "bin": 16, + "ref_a": 19.633908762069808, + "ref_b": -3.6665025430120437, + "test_a": 9.120101016970796, + "test_b": -8.676651866092985, + "ref_a_norm": 0.9830066430304568, + "ref_b_norm": -0.1835699859944214, + "test_a_norm": 0.4566141155810288, + "test_b_norm": -0.4344120433170876, + "Rcs_pct": -46.73411848983852, + "Rhs": -0.34871628521512715, + "Rf_h": 25.338050603208952 + } + ] + } +} \ No newline at end of file diff --git a/crates/tm30/tests/golden/illuminant_HP2.json b/crates/tm30/tests/golden/illuminant_HP2.json new file mode 100644 index 0000000..d0c31a0 --- /dev/null +++ b/crates/tm30/tests/golden/illuminant_HP2.json @@ -0,0 +1,403 @@ +{ + "name": "illuminant_HP2", + "source": "colour.SDS_ILLUMINANTS['HP2'] (380.0, 780.0, 5.0)", + "generator": "crates/tm30/tools/golden.py (tm30.py + colour-science 0.4.7, numpy 2.5.1)", + "wavelengths": [ + 380.0, + 385.0, + 390.0, + 395.0, + 400.0, + 405.0, + 410.0, + 415.0, + 420.0, + 425.0, + 430.0, + 435.0, + 440.0, + 445.0, + 450.0, + 455.0, + 460.0, + 465.0, + 470.0, + 475.0, + 480.0, + 485.0, + 490.0, + 495.0, + 500.0, + 505.0, + 510.0, + 515.0, + 520.0, + 525.0, + 530.0, + 535.0, + 540.0, + 545.0, + 550.0, + 555.0, + 560.0, + 565.0, + 570.0, + 575.0, + 580.0, + 585.0, + 590.0, + 595.0, + 600.0, + 605.0, + 610.0, + 615.0, + 620.0, + 625.0, + 630.0, + 635.0, + 640.0, + 645.0, + 650.0, + 655.0, + 660.0, + 665.0, + 670.0, + 675.0, + 680.0, + 685.0, + 690.0, + 695.0, + 700.0, + 705.0, + 710.0, + 715.0, + 720.0, + 725.0, + 730.0, + 735.0, + 740.0, + 745.0, + 750.0, + 755.0, + 760.0, + 765.0, + 770.0, + 775.0, + 780.0 + ], + "values": [ + 2.64, + 2.77, + 3.42, + 3.68, + 4.33, + 5.5, + 5.94, + 7.2, + 9.02, + 10.27, + 12.48, + 16.82, + 16.04, + 15.26, + 22.58, + 20.07, + 15.13, + 25.27, + 28.04, + 15.99, + 10.4, + 11.1, + 13.44, + 22.62, + 49.71, + 17.21, + 17.12, + 27.26, + 20.02, + 21.54, + 23.36, + 25.66, + 29.69, + 43.12, + 98.3, + 125.6, + 134.57, + 149.7, + 166.12, + 98.77, + 30.47, + 1.17, + 0.39, + 1.65, + 21.41, + 76.11, + 126.16, + 161.96, + 160.06, + 158.19, + 153.69, + 147.4, + 140.6, + 134.92, + 127.59, + 124.65, + 118.02, + 113.94, + 118.1, + 115.16, + 102.85, + 90.54, + 83.34, + 79.44, + 76.97, + 74.85, + 73.12, + 71.51, + 70.13, + 69.04, + 67.48, + 66.7, + 66.31, + 65.14, + 65.7, + 64.79, + 64.1, + 83.04, + 86.25, + 63.93, + 64.92 + ], + "expected": { + "Rf": 82.46203215116815, + "Rg": 104.42891028527828, + "CCT_K": 2505.877919319432, + "Duv": 0.0007169978712424309, + "bins": [ + { + "bin": 1, + "ref_a": 25.21009690740788, + "ref_b": 5.5804859593889615, + "test_a": 26.382407836326024, + "test_b": 4.904946812407616, + "ref_a_norm": 0.9763651756897543, + "ref_b_norm": 0.21612737841447824, + "test_a_norm": 1.021767760625469, + "test_b_norm": 0.1899643334904448, + "Rcs_pct": 3.942603013805422, + "Rhs": -0.03451793426749361, + "Rf_h": 85.47992830341362 + }, + { + "bin": 2, + "ref_a": 20.595253728173194, + "ref_b": 14.188100295146329, + "test_a": 20.934497793331552, + "test_b": 13.766315306157107, + "ref_a_norm": 0.823502765826575, + "ref_b_norm": 0.5673122550024644, + "test_a_norm": 0.8370674652294281, + "test_b_norm": 0.5504471505662121, + "Rcs_pct": 0.1908885351942188, + "Rhs": -0.021558965055136582, + "Rf_h": 90.3984150440704 + }, + { + "bin": 3, + "ref_a": 15.105309662502535, + "ref_b": 22.37474726237849, + "test_a": 13.024211873428184, + "test_b": 23.446426146301274, + "ref_a_norm": 0.5595327892039128, + "ref_b_norm": 0.8288082153343376, + "test_a_norm": 0.48244450193645727, + "test_b_norm": 0.8685054799684283, + "Rcs_pct": -0.9820888485483371, + "Rhs": 0.0861511868903411, + "Rf_h": 80.30027581046143 + }, + { + "bin": 4, + "ref_a": 3.0574919889473438, + "ref_b": 20.10043179010946, + "test_a": 0.8515015817756874, + "test_b": 21.52801230689014, + "ref_a_norm": 0.1503809764884453, + "ref_b_norm": 0.9886281211407966, + "test_a_norm": 0.04188061319924162, + "test_b_norm": 1.0588428438303137, + "Rcs_pct": 4.769819566851549, + "Rhs": 0.12011377209222505, + "Rf_h": 81.3917863609288 + }, + { + "bin": 5, + "ref_a": -2.5395388893782984, + "ref_b": 15.856966985210441, + "test_a": -3.693139639905981, + "test_b": 16.85732041103808, + "ref_a_norm": -0.15813768514117096, + "ref_b_norm": 0.9874170712207642, + "test_a_norm": -0.22997267574855051, + "test_b_norm": 1.0497093148028855, + "Rcs_pct": 7.510962703825652, + "Rhs": 0.058302087546079025, + "Rf_h": 82.31486308106543 + }, + { + "bin": 6, + "ref_a": -10.971520181894952, + "ref_b": 15.572069753452462, + "test_a": -11.042870508199615, + "test_b": 16.92286866145962, + "ref_a_norm": -0.575963678796822, + "ref_b_norm": 0.8174752844623692, + "test_a_norm": -0.5797093034450455, + "test_b_norm": 0.8883871631694235, + "Rcs_pct": 6.104202985481701, + "Rhs": -0.03628215590304667, + "Rf_h": 89.64081473228838 + }, + { + "bin": 7, + "ref_a": -18.202152811694067, + "ref_b": 13.728145361774743, + "test_a": -18.31081705034748, + "test_b": 15.587459971652954, + "ref_a_norm": -0.7983858491454217, + "ref_b_norm": 0.6021461914554839, + "test_a_norm": -0.8031520980252415, + "test_b_norm": 0.6836997576184056, + "Rcs_pct": 4.927172486495525, + "Rhs": -0.06516132603858357, + "Rf_h": 86.48698606471135 + }, + { + "bin": 8, + "ref_a": -21.31331882011686, + "ref_b": 4.186966442496566, + "test_a": -17.940049334037187, + "test_b": 5.020914276096417, + "ref_a_norm": -0.981245148649001, + "ref_b_norm": 0.19276399625656215, + "test_a_norm": -0.8259429948062501, + "test_b_norm": 0.23115817000550587, + "Rcs_pct": -14.482773478366344, + "Rhs": -0.06795438766918872, + "Rf_h": 75.85619344174779 + }, + { + "bin": 9, + "ref_a": -24.127254466756185, + "ref_b": -4.894500885169529, + "test_a": -22.66048431170445, + "test_b": -4.088918979432187, + "ref_a_norm": -0.9800375866815455, + "ref_b_norm": -0.1988122951213331, + "test_a_norm": -0.9204580814811479, + "test_b_norm": -0.16608994174038957, + "Rcs_pct": -6.4818516172471545, + "Rhs": -0.02047021768107513, + "Rf_h": 87.6386696279278 + }, + { + "bin": 10, + "ref_a": -18.849105653919334, + "ref_b": -13.114612004013484, + "test_a": -15.588467718832922, + "test_b": -14.25618478055868, + "ref_a_norm": -0.8208604757856944, + "ref_b_norm": -0.5711287764531598, + "test_a_norm": -0.678862820517452, + "test_b_norm": -0.6208431761548794, + "Rcs_pct": -9.044689474704214, + "Rhs": 0.120225683071457, + "Rf_h": 75.34360945067854 + }, + { + "bin": 11, + "ref_a": -10.517149370990213, + "ref_b": -16.623010706716475, + "test_a": -6.713643731393289, + "test_b": -17.90125230371982, + "ref_a_norm": -0.5346617082357045, + "ref_b_norm": -0.8450661854236498, + "test_a_norm": -0.3413023909134328, + "test_b_norm": -0.910048321902272, + "Rcs_pct": -5.339400915677452, + "Rhs": 0.19687453731457388, + "Rf_h": 71.68309744133607 + }, + { + "bin": 12, + "ref_a": -4.636131216412637, + "ref_b": -18.275747349661007, + "test_a": -1.4246223423795608, + "test_b": -19.362843165085895, + "ref_a_norm": -0.24588835452631433, + "ref_b_norm": -0.9692981569714973, + "test_a_norm": -0.07555826771015958, + "test_b_norm": -1.026954894623997, + "Rcs_pct": 2.3319128119643606, + "Rhs": 0.17830551347411452, + "Rf_h": 75.47364363348022 + }, + { + "bin": 13, + "ref_a": 4.42171779723458, + "ref_b": -17.431766839234676, + "test_a": 5.978222613175973, + "test_b": -18.286164526208253, + "ref_a_norm": 0.24587188569289917, + "ref_b_norm": -0.9693023345818467, + "test_a_norm": 0.3324221342015075, + "test_b_norm": -1.016811556124485, + "Rcs_pct": 6.348146102455615, + "Rhs": 0.07561862042299582, + "Rf_h": 87.00943316986962 + }, + { + "bin": 14, + "ref_a": 12.674379697104948, + "ref_b": -15.63396887548457, + "test_a": 15.315870852089242, + "test_b": -16.118689429532477, + "ref_a_norm": 0.6297476574718758, + "ref_b_norm": -0.7767997733706447, + "test_a_norm": 0.760994543460624, + "test_b_norm": -0.8008839211344886, + "Rcs_pct": 9.294210003570653, + "Rhs": 0.0957473618237436, + "Rf_h": 81.66650677521812 + }, + { + "bin": 15, + "ref_a": 16.378763181982784, + "ref_b": -10.472530882162987, + "test_a": 18.485437979199414, + "test_b": -11.555882884232537, + "ref_a_norm": 0.8425020106570933, + "ref_b_norm": -0.5386931984337238, + "test_a_norm": 0.9508665881734264, + "test_b_norm": -0.5944193988709469, + "Rcs_pct": 12.106167141703967, + "Rhs": 0.01386949130918807, + "Rf_h": 82.94626419044468 + }, + { + "bin": 16, + "ref_a": 17.851592977256075, + "ref_b": -3.513805127379676, + "test_a": 19.194597353625664, + "test_b": -4.191649731598001, + "ref_a_norm": 0.9811734615215516, + "ref_b_norm": -0.193128554092388, + "test_a_norm": 1.0549887369695181, + "test_b_norm": -0.2303847887344142, + "Rcs_pct": 7.9665266441696865, + "Rhs": -0.022139720683295193, + "Rf_h": 86.96873436152991 + } + ] + } +} \ No newline at end of file diff --git a/crates/tm30/tests/golden/illuminant_HP3.json b/crates/tm30/tests/golden/illuminant_HP3.json new file mode 100644 index 0000000..ca4cc99 --- /dev/null +++ b/crates/tm30/tests/golden/illuminant_HP3.json @@ -0,0 +1,403 @@ +{ + "name": "illuminant_HP3", + "source": "colour.SDS_ILLUMINANTS['HP3'] (380.0, 780.0, 5.0)", + "generator": "crates/tm30/tools/golden.py (tm30.py + colour-science 0.4.7, numpy 2.5.1)", + "wavelengths": [ + 380.0, + 385.0, + 390.0, + 395.0, + 400.0, + 405.0, + 410.0, + 415.0, + 420.0, + 425.0, + 430.0, + 435.0, + 440.0, + 445.0, + 450.0, + 455.0, + 460.0, + 465.0, + 470.0, + 475.0, + 480.0, + 485.0, + 490.0, + 495.0, + 500.0, + 505.0, + 510.0, + 515.0, + 520.0, + 525.0, + 530.0, + 535.0, + 540.0, + 545.0, + 550.0, + 555.0, + 560.0, + 565.0, + 570.0, + 575.0, + 580.0, + 585.0, + 590.0, + 595.0, + 600.0, + 605.0, + 610.0, + 615.0, + 620.0, + 625.0, + 630.0, + 635.0, + 640.0, + 645.0, + 650.0, + 655.0, + 660.0, + 665.0, + 670.0, + 675.0, + 680.0, + 685.0, + 690.0, + 695.0, + 700.0, + 705.0, + 710.0, + 715.0, + 720.0, + 725.0, + 730.0, + 735.0, + 740.0, + 745.0, + 750.0, + 755.0, + 760.0, + 765.0, + 770.0, + 775.0, + 780.0 + ], + "values": [ + 3.15, + 7.49, + 10.87, + 12.57, + 12.97, + 21.29, + 26.29, + 30.18, + 43.06, + 29.58, + 23.18, + 35.28, + 26.29, + 24.29, + 22.91, + 26.2, + 29.31, + 25.3, + 28.14, + 24.05, + 21.82, + 20.51, + 23.05, + 26.98, + 30.96, + 30.72, + 27.13, + 29.55, + 34.22, + 29.98, + 41.21, + 173.14, + 141.37, + 64.98, + 33.83, + 34.26, + 33.32, + 52.8, + 74.29, + 47.97, + 49.2, + 96.07, + 85.41, + 175.18, + 153.73, + 120.22, + 98.9, + 90.22, + 70.07, + 66.84, + 57.61, + 53.03, + 49.85, + 48.16, + 42.76, + 50.64, + 48.42, + 41.27, + 43.44, + 40.48, + 35.16, + 34.94, + 24.68, + 24.7, + 21.49, + 19.49, + 18.48, + 17.55, + 17.36, + 17.09, + 16.32, + 16.07, + 16.58, + 15.78, + 17.66, + 20.46, + 16.59, + 17.81, + 16.07, + 14.83, + 14.61 + ], + "expected": { + "Rf": 83.24152081770636, + "Rg": 97.14478671128319, + "CCT_K": 3146.297680945549, + "Duv": 0.0024009206065169764, + "bins": [ + { + "bin": 1, + "ref_a": 23.8286476669202, + "ref_b": 4.8303407413370385, + "test_a": 20.917374718487313, + "test_b": 3.809241836928173, + "ref_a_norm": 0.9800662997374675, + "ref_b_norm": 0.1986707027191188, + "test_a_norm": 0.8603263738306616, + "test_b_norm": 0.15667316098286455, + "Rcs_pct": -12.563247074718026, + "Rhs": -0.017830470044692407, + "Rf_h": 77.14912913047641 + }, + { + "bin": 2, + "ref_a": 20.436662292904483, + "ref_b": 15.035253926029613, + "test_a": 17.6954805249, + "test_b": 15.515450591370442, + "ref_a_norm": 0.8054949233583872, + "ref_b_norm": 0.5926026733350649, + "test_a_norm": 0.6974534062806798, + "test_b_norm": 0.6115292461091308, + "Rcs_pct": -7.931819787083003, + "Rhs": 0.07576152094532172, + "Rf_h": 80.8115180457146 + }, + { + "bin": 3, + "ref_a": 14.734334069327955, + "ref_b": 23.02223974682943, + "test_a": 12.037954826798478, + "test_b": 24.011180642447115, + "ref_a_norm": 0.5390563082276398, + "ref_b_norm": 0.8422697291010688, + "test_a_norm": 0.4404091462167492, + "test_b_norm": 0.8784501785016788, + "Rcs_pct": -2.472248254905588, + "Rhs": 0.10212289825619245, + "Rf_h": 80.42443006546664 + }, + { + "bin": 4, + "ref_a": 3.3127079493736726, + "ref_b": 22.351855010913866, + "test_a": 1.0698798363652258, + "test_b": 23.909931878937062, + "ref_a_norm": 0.14660591120299277, + "ref_b_norm": 0.9891949791625209, + "test_a_norm": 0.04734818483400814, + "test_b_norm": 1.058148621455085, + "Rcs_pct": 4.826449559082257, + "Rhs": 0.11080270526803299, + "Rf_h": 80.87413406330091 + }, + { + "bin": 5, + "ref_a": -2.3811605516959413, + "ref_b": 16.2399152177074, + "test_a": -4.037701281252853, + "test_b": 17.84675333268641, + "ref_a_norm": -0.14507281462816743, + "ref_b_norm": 0.9894209814107751, + "test_a_norm": -0.24599798156487648, + "test_b_norm": 1.0873180038630397, + "Rcs_pct": 11.570548193369973, + "Rhs": 0.0798871565191306, + "Rf_h": 83.50393732641962 + }, + { + "bin": 6, + "ref_a": -12.65806127413736, + "ref_b": 17.28974834620605, + "test_a": -13.473688410341495, + "test_b": 18.791383664725966, + "ref_a_norm": -0.5907235232675229, + "ref_b_norm": 0.806874041631285, + "test_a_norm": -0.6287870248683193, + "test_b_norm": 0.8769520169869135, + "Rcs_pct": 7.941465545378824, + "Rhs": -0.007284592178976972, + "Rf_h": 87.01355090730374 + }, + { + "bin": 7, + "ref_a": -18.494916716671508, + "ref_b": 13.667140244368627, + "test_a": -17.65851732996257, + "test_b": 16.329035970077427, + "ref_a_norm": -0.8042388169036485, + "ref_b_norm": 0.5943062555496281, + "test_a_norm": -0.7678685610365655, + "test_b_norm": 0.71005697246068, + "Rcs_pct": 3.4066890221311255, + "Rhs": -0.11644943524083183, + "Rf_h": 80.9397301322769 + }, + { + "bin": 8, + "ref_a": -21.468343960045637, + "ref_b": 6.194014661401569, + "test_a": -21.470251782778277, + "test_b": 7.96504436061574, + "ref_a_norm": -0.9608090121871495, + "ref_b_norm": 0.2772111868232482, + "test_a_norm": -0.960894396196209, + "test_b_norm": 0.3564730665016682, + "Rcs_pct": 1.554696900933394, + "Rhs": -0.07772222729186382, + "Rf_h": 87.893260453675 + }, + { + "bin": 9, + "ref_a": -20.547782456881503, + "ref_b": -3.287155581873763, + "test_a": -19.841831329732802, + "test_b": -1.7910364208210794, + "ref_a_norm": -0.9874443022833965, + "ref_b_norm": -0.15796755960657236, + "test_a_norm": -0.9535191125624946, + "test_b_norm": -0.08607005221283776, + "Rcs_pct": -4.7299834582748295, + "Rhs": -0.0638975407623483, + "Rf_h": 88.62749284314974 + }, + { + "bin": 10, + "ref_a": -20.1962190763613, + "ref_b": -13.0470097623176, + "test_a": -18.41886034411629, + "test_b": -12.19156019699632, + "ref_a_norm": -0.8399707882131948, + "ref_b_norm": -0.5426316199305973, + "test_a_norm": -0.7660495552528707, + "test_b_norm": -0.507053047379828, + "Rcs_pct": -8.12296547529825, + "Rhs": 0.011485934695797447, + "Rf_h": 84.3508670948744 + }, + { + "bin": 11, + "ref_a": -11.407626981811614, + "ref_b": -17.394928663613094, + "test_a": -9.351017401689946, + "test_b": -16.911910660530616, + "ref_a_norm": -0.5483944915578085, + "ref_b_norm": -0.8362197567799105, + "test_a_norm": -0.4495278853107806, + "test_b_norm": -0.8129998169417638, + "Rcs_pct": -7.423401784543071, + "Rhs": 0.06930427137930445, + "Rf_h": 84.51904519858525 + }, + { + "bin": 12, + "ref_a": -5.628091883415613, + "ref_b": -18.855629745352342, + "test_a": -5.652802561019612, + "test_b": -19.163781162275146, + "ref_a_norm": -0.28601432769132173, + "ref_b_norm": -0.9582253411151687, + "test_a_norm": -0.2872701010489904, + "test_b_norm": -0.973885305835719, + "Rcs_pct": 1.56040521182765, + "Rhs": 0.001823463535369356, + "Rf_h": 89.63536725776353 + }, + { + "bin": 13, + "ref_a": 2.8589216209958943, + "ref_b": -18.219329907726333, + "test_a": 2.5670600071803, + "test_b": -19.245858857637657, + "ref_a_norm": 0.1550200291387481, + "ref_b_norm": -0.987911327278831, + "test_a_norm": 0.13919434313676016, + "test_b_norm": -1.0435730658023197, + "Rcs_pct": 5.150477564723718, + "Rhs": -0.02638066637555819, + "Rf_h": 89.94687382949515 + }, + { + "bin": 14, + "ref_a": 8.777379308922018, + "ref_b": -14.263130651140767, + "test_a": 7.02985835537061, + "test_b": -15.238850030436852, + "ref_a_norm": 0.5241003767078458, + "ref_b_norm": -0.8516565006707187, + "test_a_norm": 0.4197552917084795, + "test_b_norm": -0.9099170447639223, + "Rcs_pct": -0.9529151177836751, + "Rhs": -0.11912759142780915, + "Rf_h": 85.02493463010806 + }, + { + "bin": 15, + "ref_a": 17.94572234908664, + "ref_b": -12.242751467720971, + "test_a": 15.99949787430031, + "test_b": -14.28085774785957, + "ref_a_norm": 0.8260766572473346, + "ref_b_norm": -0.5635577666495866, + "test_a_norm": 0.7364881426637314, + "test_b_norm": -0.6573757802274788, + "Rcs_pct": -2.236763182268364, + "Rhs": -0.12777953929969738, + "Rf_h": 79.18254901052585 + }, + { + "bin": 16, + "ref_a": 16.551557269364356, + "ref_b": -3.9768453174424905, + "test_a": 14.401987640067375, + "test_b": -4.831736840924205, + "ref_a_norm": 0.9723276596052066, + "ref_b_norm": -0.23362132258563498, + "test_a_norm": 0.8460503569443053, + "test_b_norm": -0.2838422571306796, + "Rcs_pct": -11.405330140649202, + "Rhs": -0.07389143300931729, + "Rf_h": 79.89076314330991 + } + ] + } +} \ No newline at end of file diff --git a/crates/tm30/tests/golden/illuminant_HP4.json b/crates/tm30/tests/golden/illuminant_HP4.json new file mode 100644 index 0000000..e8e15b2 --- /dev/null +++ b/crates/tm30/tests/golden/illuminant_HP4.json @@ -0,0 +1,403 @@ +{ + "name": "illuminant_HP4", + "source": "colour.SDS_ILLUMINANTS['HP4'] (380.0, 780.0, 5.0)", + "generator": "crates/tm30/tools/golden.py (tm30.py + colour-science 0.4.7, numpy 2.5.1)", + "wavelengths": [ + 380.0, + 385.0, + 390.0, + 395.0, + 400.0, + 405.0, + 410.0, + 415.0, + 420.0, + 425.0, + 430.0, + 435.0, + 440.0, + 445.0, + 450.0, + 455.0, + 460.0, + 465.0, + 470.0, + 475.0, + 480.0, + 485.0, + 490.0, + 495.0, + 500.0, + 505.0, + 510.0, + 515.0, + 520.0, + 525.0, + 530.0, + 535.0, + 540.0, + 545.0, + 550.0, + 555.0, + 560.0, + 565.0, + 570.0, + 575.0, + 580.0, + 585.0, + 590.0, + 595.0, + 600.0, + 605.0, + 610.0, + 615.0, + 620.0, + 625.0, + 630.0, + 635.0, + 640.0, + 645.0, + 650.0, + 655.0, + 660.0, + 665.0, + 670.0, + 675.0, + 680.0, + 685.0, + 690.0, + 695.0, + 700.0, + 705.0, + 710.0, + 715.0, + 720.0, + 725.0, + 730.0, + 735.0, + 740.0, + 745.0, + 750.0, + 755.0, + 760.0, + 765.0, + 770.0, + 775.0, + 780.0 + ], + "values": [ + 9.8, + 13.3, + 19.97, + 25.81, + 24.69, + 47.66, + 54.44, + 63.82, + 85.52, + 60.54, + 38.37, + 88.2, + 44.94, + 35.64, + 30.75, + 33.77, + 40.81, + 33.77, + 35.28, + 32.55, + 29.44, + 26.16, + 29.96, + 32.83, + 33.58, + 41.16, + 32.93, + 32.13, + 34.45, + 30.12, + 41.13, + 187.1, + 101.37, + 123.96, + 42.47, + 34.73, + 31.82, + 54.67, + 57.45, + 70.43, + 69.5, + 49.37, + 183.35, + 162.15, + 109.35, + 72.38, + 70.6, + 58.08, + 44.13, + 50.2, + 40.8, + 37.91, + 36.71, + 38.3, + 31.24, + 35.31, + 45.62, + 35.82, + 89.91, + 36.01, + 32.57, + 39.26, + 23.27, + 25.3, + 20.02, + 17.54, + 16.25, + 15.2, + 15.15, + 15.22, + 14.26, + 12.63, + 14.75, + 13.19, + 17.63, + 23.38, + 16.02, + 24.46, + 22.05, + 16.11, + 12.91 + ], + "expected": { + "Rf": 77.92180095237877, + "Rg": 95.18060785813896, + "CCT_K": 4004.3137022276496, + "Duv": 0.0011935445188656327, + "bins": [ + { + "bin": 1, + "ref_a": 21.53266990175657, + "ref_b": 5.051236578198079, + "test_a": 18.042550574326377, + "test_b": 3.8506650316995543, + "ref_a_norm": 0.9735709166482328, + "ref_b_norm": 0.22838491687657425, + "test_a_norm": 0.8157698316773097, + "test_b_norm": 0.1741026775463273, + "Rcs_pct": -16.53589209218352, + "Rhs": -0.02245375684095971, + "Rf_h": 72.71866664729811 + }, + { + "bin": 2, + "ref_a": 20.625435277575367, + "ref_b": 14.41961359102568, + "test_a": 17.135202027850344, + "test_b": 14.969777026415722, + "ref_a_norm": 0.8195713665445541, + "ref_b_norm": 0.5729771157212931, + "test_a_norm": 0.680883615447907, + "test_b_norm": 0.5948383851925703, + "Rcs_pct": -10.316918006117925, + "Rhs": 0.09522776744545318, + "Rf_h": 75.86420397041186 + }, + { + "bin": 3, + "ref_a": 14.615807059674609, + "ref_b": 22.32106404319544, + "test_a": 10.219754828166302, + "test_b": 23.723931092970446, + "ref_a_norm": 0.5478075748448216, + "ref_b_norm": 0.8366043634494356, + "test_a_norm": 0.38304139381893815, + "test_b_norm": 0.8891845044727301, + "Rcs_pct": -4.7820396114848185, + "Rhs": 0.1662100338586776, + "Rf_h": 68.4882427346622 + }, + { + "bin": 4, + "ref_a": 3.7379162592152007, + "ref_b": 22.134070046312743, + "test_a": 0.32390757090095523, + "test_b": 24.310769493817116, + "ref_a_norm": 0.16651834909804764, + "ref_b_norm": 0.9860383559546052, + "test_a_norm": 0.014429577932307718, + "test_b_norm": 1.083006927036816, + "Rcs_pct": 6.543429983740519, + "Rhs": 0.1680840578318453, + "Rf_h": 71.70124466359772 + }, + { + "bin": 5, + "ref_a": -2.2300617056765133, + "ref_b": 19.114238823610535, + "test_a": -4.799123611250504, + "test_b": 21.456191963102437, + "ref_a_norm": -0.11588414346765415, + "ref_b_norm": 0.9932627372919856, + "test_a_norm": -0.24938427832267004, + "test_b_norm": 1.114961268288047, + "Rcs_pct": 14.540471214569491, + "Rhs": 0.10719276159673449, + "Rf_h": 75.52271214939815 + }, + { + "bin": 6, + "ref_a": -11.176808986056272, + "ref_b": 17.11679924042796, + "test_a": -11.97091865692345, + "test_b": 19.076143292807, + "ref_a_norm": -0.5467371572577343, + "ref_b_norm": 0.8373042940733862, + "test_a_norm": -0.5855827047250344, + "test_b_norm": 0.9331497360617041, + "Rcs_pct": 10.127400234917468, + "Rhs": -0.020949982247000325, + "Rf_h": 84.39338804668948 + }, + { + "bin": 7, + "ref_a": -18.25315595150376, + "ref_b": 11.165047316455624, + "test_a": -17.665087710318076, + "test_b": 13.598724279711059, + "ref_a_norm": -0.8530667263605539, + "ref_b_norm": 0.5218018401428725, + "test_a_norm": -0.825583180462095, + "test_b_norm": 0.6355404640597065, + "Rcs_pct": 4.033806053991363, + "Rhs": -0.10983924953096671, + "Rf_h": 83.00459548412206 + }, + { + "bin": 8, + "ref_a": -22.83849639564624, + "ref_b": 3.4754719633308637, + "test_a": -21.384823555568886, + "test_b": 5.781645899242716, + "ref_a_norm": -0.9886185244526211, + "ref_b_norm": 0.15044405308659506, + "test_a_norm": -0.9256928452267292, + "test_b_norm": 0.25027226568674227, + "Rcs_pct": -4.224106180167285, + "Rhs": -0.11018623251045155, + "Rf_h": 81.54408233687654 + }, + { + "bin": 9, + "ref_a": -19.3611082232335, + "ref_b": -2.224848866295984, + "test_a": -17.977024052483348, + "test_b": -0.17133700011739889, + "ref_a_norm": -0.9934621453912715, + "ref_b_norm": -0.11416201502501615, + "test_a_norm": -0.9224416638247519, + "test_b_norm": -0.008791688045897804, + "Rcs_pct": -9.021257394889235, + "Rhs": -0.08949025707384185, + "Rf_h": 82.82488995700996 + }, + { + "bin": 10, + "ref_a": -20.08968837419721, + "ref_b": -11.370972401841597, + "test_a": -16.81318695426473, + "test_b": -10.572818714159842, + "ref_a_norm": -0.8702670559277351, + "ref_b_norm": -0.4925801979037244, + "test_a_norm": -0.7283319899697184, + "test_b_norm": -0.4580049049963041, + "Rcs_pct": -13.722369780154487, + "Rhs": 0.0501065922789682, + "Rf_h": 76.0152062906534 + }, + { + "bin": 11, + "ref_a": -11.962746174062092, + "ref_b": -17.409211532655025, + "test_a": -9.520598383665138, + "test_b": -17.310332303544048, + "ref_a_norm": -0.5663331363521611, + "ref_b_norm": -0.8241764244805383, + "test_a_norm": -0.45071844408611517, + "test_b_norm": -0.8194953434705674, + "Rcs_pct": -6.8124258135254, + "Rhs": 0.09352943408743411, + "Rf_h": 81.16005753447747 + }, + { + "bin": 12, + "ref_a": -7.904003573304995, + "ref_b": -24.36876002144646, + "test_a": -5.5026982904284125, + "test_b": -25.26676282839791, + "ref_a_norm": -0.30852666450687366, + "ref_b_norm": -0.951215694408089, + "test_a_norm": -0.2147935705732054, + "test_b_norm": -0.9862685392324861, + "Rcs_pct": 1.6092894760939924, + "Rhs": 0.09877050960116818, + "Rf_h": 80.6533765232271 + }, + { + "bin": 13, + "ref_a": 3.36870036453182, + "ref_b": -17.975782389877335, + "test_a": 3.4685253009484778, + "test_b": -19.158520365652194, + "ref_a_norm": 0.18419562993526667, + "ref_b_norm": -0.9828896020981962, + "test_a_norm": 0.18965391207876317, + "test_b_norm": -1.0475599921364298, + "Rcs_pct": 6.449262464846481, + "Rhs": -0.007263164434838426, + "Rf_h": 85.39029412985549 + }, + { + "bin": 14, + "ref_a": 10.359694253251915, + "ref_b": -14.461223072588352, + "test_a": 9.941098771335804, + "test_b": -15.786663883516075, + "ref_a_norm": 0.5823636040246826, + "ref_b_norm": -0.8129284302491718, + "test_a_norm": 0.5588325260297317, + "test_b_norm": -0.8874372399402466, + "Rcs_pct": 4.887864462210474, + "Rhs": -0.06096025305960627, + "Rf_h": 88.91846918885004 + }, + { + "bin": 15, + "ref_a": 15.52293541971343, + "ref_b": -10.952866611875276, + "test_a": 13.28438178309659, + "test_b": -13.05651667768877, + "ref_a_norm": 0.8170794323493688, + "ref_b_norm": -0.5765251089342365, + "test_a_norm": 0.6992488748397588, + "test_b_norm": -0.6872547586533058, + "Rcs_pct": -3.645443067330584, + "Rhs": -0.1575314892147547, + "Rf_h": 76.58684650437823 + }, + { + "bin": 16, + "ref_a": 20.16183428534444, + "ref_b": -3.5048895013016783, + "test_a": 17.71081419521186, + "test_b": -4.835395242523553, + "ref_a_norm": 0.9852242613421153, + "ref_b_norm": -0.17126924669327967, + "test_a_norm": 0.8654531917231735, + "test_b_norm": -0.23628548071022198, + "Rcs_pct": -10.47856640697674, + "Rhs": -0.08713314185124435, + "Rf_h": 75.99404167297625 + } + ] + } +} \ No newline at end of file diff --git a/crates/tm30/tests/golden/illuminant_HP5.json b/crates/tm30/tests/golden/illuminant_HP5.json new file mode 100644 index 0000000..49a0324 --- /dev/null +++ b/crates/tm30/tests/golden/illuminant_HP5.json @@ -0,0 +1,403 @@ +{ + "name": "illuminant_HP5", + "source": "colour.SDS_ILLUMINANTS['HP5'] (380.0, 780.0, 5.0)", + "generator": "crates/tm30/tools/golden.py (tm30.py + colour-science 0.4.7, numpy 2.5.1)", + "wavelengths": [ + 380.0, + 385.0, + 390.0, + 395.0, + 400.0, + 405.0, + 410.0, + 415.0, + 420.0, + 425.0, + 430.0, + 435.0, + 440.0, + 445.0, + 450.0, + 455.0, + 460.0, + 465.0, + 470.0, + 475.0, + 480.0, + 485.0, + 490.0, + 495.0, + 500.0, + 505.0, + 510.0, + 515.0, + 520.0, + 525.0, + 530.0, + 535.0, + 540.0, + 545.0, + 550.0, + 555.0, + 560.0, + 565.0, + 570.0, + 575.0, + 580.0, + 585.0, + 590.0, + 595.0, + 600.0, + 605.0, + 610.0, + 615.0, + 620.0, + 625.0, + 630.0, + 635.0, + 640.0, + 645.0, + 650.0, + 655.0, + 660.0, + 665.0, + 670.0, + 675.0, + 680.0, + 685.0, + 690.0, + 695.0, + 700.0, + 705.0, + 710.0, + 715.0, + 720.0, + 725.0, + 730.0, + 735.0, + 740.0, + 745.0, + 750.0, + 755.0, + 760.0, + 765.0, + 770.0, + 775.0, + 780.0 + ], + "values": [ + 0.34, + 7.11, + 11.49, + 14.97, + 14.95, + 29.14, + 38.08, + 51.56, + 62.56, + 55.61, + 41.98, + 50.02, + 42.14, + 39.04, + 40.52, + 45.29, + 51.01, + 49.18, + 49.05, + 46.12, + 45.73, + 39.46, + 44.39, + 46.14, + 49.54, + 59.76, + 48.47, + 48.38, + 48.7, + 44.25, + 54.42, + 128.93, + 81.26, + 67.36, + 48.48, + 51.41, + 48.88, + 68.52, + 80.85, + 65.96, + 59.43, + 67.57, + 128.34, + 131.85, + 101.7, + 77.05, + 66.27, + 77.09, + 60.51, + 65.23, + 57.86, + 56.2, + 54.32, + 56.34, + 45.74, + 50.79, + 56.66, + 51.99, + 84.31, + 47.48, + 47.46, + 61.78, + 34.51, + 38.74, + 30.98, + 25.45, + 22.88, + 20.82, + 21.05, + 20.81, + 18.69, + 17.54, + 19.58, + 16.42, + 23.77, + 35.39, + 21.37, + 34.58, + 30.21, + 19.71, + 15.61 + ], + "expected": { + "Rf": 90.14162383066547, + "Rg": 97.45299607385583, + "CCT_K": 4041.0695415708938, + "Duv": -0.0016859381838345406, + "bins": [ + { + "bin": 1, + "ref_a": 21.51839208880925, + "ref_b": 5.027463531397327, + "test_a": 19.557943760881468, + "test_b": 4.566125762494176, + "ref_a_norm": 0.9737760256595103, + "ref_b_norm": 0.2275087951064062, + "test_a_norm": 0.8850594722385345, + "test_b_norm": 0.20663178639520396, + "Rcs_pct": -9.108479207560185, + "Rhs": -0.0031681218677379747, + "Rf_h": 85.41027815028502 + }, + { + "bin": 2, + "ref_a": 20.628703529241076, + "ref_b": 14.3980947586504, + "test_a": 18.786672157466054, + "test_b": 14.823814530446937, + "ref_a_norm": 0.8200154638790786, + "ref_b_norm": 0.5723413657942081, + "test_a_norm": 0.7467925292596155, + "test_b_norm": 0.5892642323067542, + "Rcs_pct": -5.148080416796494, + "Rhs": 0.05475133210714862, + "Rf_h": 87.09813417407997 + }, + { + "bin": 3, + "ref_a": 14.619607852756078, + "ref_b": 22.31178929099372, + "test_a": 12.494009760077494, + "test_b": 22.98537728410452, + "ref_a_norm": 0.5480666239758437, + "ref_b_norm": 0.8364346810622579, + "test_a_norm": 0.46838121911977404, + "test_b_norm": 0.8616864594309441, + "Rcs_pct": -2.327475257398671, + "Rhs": 0.08028512907429794, + "Rf_h": 84.68871922395988 + }, + { + "bin": 4, + "ref_a": 3.755431696033001, + "ref_b": 22.130790146253307, + "test_a": 2.438430648722726, + "test_b": 23.018149852315418, + "ref_a_norm": 0.16730094790554698, + "ref_b_norm": 0.9859058742242615, + "test_a_norm": 0.10862979064808559, + "test_b_norm": 1.025436914054968, + "Rcs_pct": 2.7325287022573788, + "Rhs": 0.06525593071254625, + "Rf_h": 88.98643869714736 + }, + { + "bin": 5, + "ref_a": -2.223250264580545, + "ref_b": 19.119793329480082, + "test_a": -3.207286507470118, + "test_b": 20.038181058260477, + "ref_a_norm": -0.11550180554239632, + "ref_b_norm": 0.9933072701417455, + "test_a_norm": -0.16662423857822248, + "test_b_norm": 1.0410191461064287, + "Rcs_pct": 5.676859756979328, + "Rhs": 0.040832004573994496, + "Rf_h": 90.60719558341569 + }, + { + "bin": 6, + "ref_a": -11.166365768161649, + "ref_b": 17.13630533917806, + "test_a": -11.435449201488725, + "test_b": 17.888711325287684, + "ref_a_norm": -0.5459423664649852, + "ref_b_norm": 0.8378227333383906, + "test_a_norm": -0.559098307208568, + "test_b_norm": 0.8746091250013188, + "Rcs_pct": 3.7895815878488848, + "Rhs": -0.009498659238581222, + "Rf_h": 94.00578682003848 + }, + { + "bin": 7, + "ref_a": -18.244977932013246, + "ref_b": 11.196364964855587, + "test_a": -17.99657701454371, + "test_b": 12.069728864700725, + "ref_a_norm": -0.8523105866747943, + "ref_b_norm": 0.5230360062577603, + "test_a_norm": -0.8407065862485984, + "test_b_norm": 0.5638350305498909, + "Rcs_pct": 1.3018349697423752, + "Rhs": -0.04036998613124123, + "Rf_h": 93.56448395243272 + }, + { + "bin": 8, + "ref_a": -22.82118084698473, + "ref_b": 3.5147058947587704, + "test_a": -22.27475128702764, + "test_b": 4.246609002415317, + "ref_a_norm": -0.988347244496596, + "ref_b_norm": 0.1522160448046993, + "test_a_norm": -0.9646822924717128, + "test_b_norm": 0.18391354654841033, + "Rcs_pct": -1.7026360785166708, + "Rhs": -0.03570524624681822, + "Rf_h": 93.55872747085576 + }, + { + "bin": 9, + "ref_a": -19.360802148248276, + "ref_b": -2.1917787547514487, + "test_a": -18.90392850305898, + "test_b": -1.589704152322095, + "ref_a_norm": -0.9936530266430313, + "ref_b_norm": -0.11248850004841975, + "test_a_norm": -0.9702049341074206, + "test_b_norm": -0.08158826944909224, + "Rcs_pct": -2.902587995045527, + "Rhs": -0.025731995409449638, + "Rf_h": 94.31147315783147 + }, + { + "bin": 10, + "ref_a": -20.109281466228556, + "ref_b": -11.334832445142103, + "test_a": -18.947425995491507, + "test_b": -11.070813968902277, + "ref_a_norm": -0.8711427556033304, + "ref_b_norm": -0.4910298355088378, + "test_a_norm": -0.8208106749623356, + "test_b_norm": -0.4795924411241596, + "Rcs_pct": -4.820387144038109, + "Rhs": 0.01845315989529921, + "Rf_h": 91.07581155406054 + }, + { + "bin": 11, + "ref_a": -11.999805616973639, + "ref_b": -17.389558909856557, + "test_a": -11.392481885904415, + "test_b": -17.42406804081723, + "ref_a_norm": -0.5679576635669648, + "ref_b_norm": -0.8230577697801987, + "test_a_norm": -0.5392126839950505, + "test_b_norm": -0.8246911066872921, + "Rcs_pct": -1.4611784994011687, + "Rhs": 0.02480801038637743, + "Rf_h": 93.47836772413297 + }, + { + "bin": 12, + "ref_a": -7.945030683937738, + "ref_b": -24.359082264707368, + "test_a": -7.542190866638954, + "test_b": -24.789867454685414, + "ref_a_norm": -0.31008592234104737, + "ref_b_norm": -0.9507085361802017, + "test_a_norm": -0.29436352160125795, + "test_b_norm": -0.9675216144777168, + "Rcs_pct": 1.3422731489277744, + "Rhs": 0.018700368077330935, + "Rf_h": 93.66445016239425 + }, + { + "bin": 13, + "ref_a": 3.322658084279731, + "ref_b": -17.986044768767545, + "test_a": 2.6462186047636447, + "test_b": -18.670781366883716, + "ref_a_norm": 0.18166154921280792, + "ref_b_norm": -0.983361114513688, + "test_a_norm": 0.1446781941155784, + "test_b_norm": -1.0207981026302237, + "Rcs_pct": 2.950255223217351, + "Rhs": -0.043576324366257406, + "Rf_h": 91.62871419995827 + }, + { + "bin": 14, + "ref_a": 10.304639839895433, + "ref_b": -14.483413677994008, + "test_a": 9.6505796610724, + "test_b": -15.129562008050994, + "ref_a_norm": 0.5797226751429211, + "ref_b_norm": -0.8148138559972672, + "test_a_norm": 0.5429262880335203, + "test_b_norm": -0.8511651350579401, + "Rcs_pct": 0.9782006546630149, + "Rhs": -0.05079076630228647, + "Rf_h": 93.24018962103241 + }, + { + "bin": 15, + "ref_a": 15.48017415157469, + "ref_b": -10.983067403936753, + "test_a": 13.880321638785796, + "test_b": -12.135726134906973, + "ref_a_norm": 0.8155783210215366, + "ref_b_norm": -0.5786466990139071, + "test_a_norm": 0.7312895389001983, + "test_b_norm": -0.6393749223084673, + "Rcs_pct": -3.634476782525765, + "Rhs": -0.09732201060264081, + "Rf_h": 85.87597224095254 + }, + { + "bin": 16, + "ref_a": 20.137182473317214, + "ref_b": -3.537439927009866, + "test_a": 18.554642149896633, + "test_b": -4.107375149945439, + "ref_a_norm": 0.9849187000037043, + "ref_b_norm": -0.17301778631982664, + "test_a_norm": 0.907515937223352, + "test_b_norm": -0.20089357577566685, + "Rcs_pct": -7.047719365611888, + "Rhs": -0.042440693893664595, + "Rf_h": 86.63191580916988 + } + ] + } +} \ No newline at end of file diff --git a/crates/tm30/tests/golden/illuminant_LED_B1.json b/crates/tm30/tests/golden/illuminant_LED_B1.json new file mode 100644 index 0000000..ba040df --- /dev/null +++ b/crates/tm30/tests/golden/illuminant_LED_B1.json @@ -0,0 +1,403 @@ +{ + "name": "illuminant_LED_B1", + "source": "colour.SDS_ILLUMINANTS['LED-B1'] (380.0, 780.0, 5.0)", + "generator": "crates/tm30/tools/golden.py (tm30.py + colour-science 0.4.7, numpy 2.5.1)", + "wavelengths": [ + 380.0, + 385.0, + 390.0, + 395.0, + 400.0, + 405.0, + 410.0, + 415.0, + 420.0, + 425.0, + 430.0, + 435.0, + 440.0, + 445.0, + 450.0, + 455.0, + 460.0, + 465.0, + 470.0, + 475.0, + 480.0, + 485.0, + 490.0, + 495.0, + 500.0, + 505.0, + 510.0, + 515.0, + 520.0, + 525.0, + 530.0, + 535.0, + 540.0, + 545.0, + 550.0, + 555.0, + 560.0, + 565.0, + 570.0, + 575.0, + 580.0, + 585.0, + 590.0, + 595.0, + 600.0, + 605.0, + 610.0, + 615.0, + 620.0, + 625.0, + 630.0, + 635.0, + 640.0, + 645.0, + 650.0, + 655.0, + 660.0, + 665.0, + 670.0, + 675.0, + 680.0, + 685.0, + 690.0, + 695.0, + 700.0, + 705.0, + 710.0, + 715.0, + 720.0, + 725.0, + 730.0, + 735.0, + 740.0, + 745.0, + 750.0, + 755.0, + 760.0, + 765.0, + 770.0, + 775.0, + 780.0 + ], + "values": [ + 0.0, + 0.01, + 0.01, + 0.02, + 0.04, + 0.07, + 0.15, + 0.28, + 0.53, + 0.92, + 1.54, + 2.52, + 4.16, + 6.39, + 7.89, + 7.57, + 6.25, + 5.16, + 4.37, + 3.84, + 3.7, + 3.88, + 4.26, + 4.79, + 5.41, + 6.05, + 6.7, + 7.34, + 7.98, + 8.64, + 9.31, + 10.02, + 10.76, + 11.53, + 12.38, + 13.28, + 14.23, + 15.2, + 16.2, + 17.19, + 18.14, + 19.02, + 19.78, + 20.38, + 20.8, + 21.0, + 20.97, + 20.71, + 20.23, + 19.56, + 18.76, + 17.82, + 16.78, + 15.66, + 14.49, + 13.31, + 12.15, + 11.02, + 9.95, + 8.93, + 7.98, + 7.1, + 6.3, + 5.57, + 4.89, + 4.26, + 3.72, + 3.25, + 2.83, + 2.47, + 2.15, + 1.87, + 1.63, + 1.42, + 1.25, + 1.1, + 0.97, + 0.86, + 0.76, + 0.68, + 0.61 + ], + "expected": { + "Rf": 84.12969850751313, + "Rg": 96.11064304715322, + "CCT_K": 2734.7403465554503, + "Duv": -0.0006625318872610033, + "bins": [ + { + "bin": 1, + "ref_a": 24.280132086547074, + "ref_b": 5.408937098610144, + "test_a": 21.591071535805423, + "test_b": 4.8075846946704495, + "ref_a_norm": 0.9760732583703736, + "ref_b_norm": 0.2174419331551342, + "test_a_norm": 0.8679717009174832, + "test_b_norm": 0.1932672705853414, + "Rcs_pct": -11.07406590438311, + "Rhs": -0.002620585553238343, + "Rf_h": 80.07057373321364 + }, + { + "bin": 2, + "ref_a": 20.728303482646645, + "ref_b": 15.137250118779702, + "test_a": 17.884025072612665, + "test_b": 15.535624011877314, + "ref_a_norm": 0.80758328908048, + "ref_b_norm": 0.5897535342818674, + "test_a_norm": 0.6967690241620396, + "test_b_norm": 0.6052743461582906, + "Rcs_pct": -8.351579281848952, + "Rhs": 0.0744701904161442, + "Rf_h": 80.39202066706625 + }, + { + "bin": 3, + "ref_a": 14.953420083055576, + "ref_b": 22.693191807862306, + "test_a": 11.68911551269857, + "test_b": 23.858642673487555, + "ref_a_norm": 0.5502246955164468, + "ref_b_norm": 0.8350166372257701, + "test_a_norm": 0.4301116392175152, + "test_b_norm": 0.8779004620709421, + "Rcs_pct": -3.107464145862864, + "Rhs": 0.12369533291535047, + "Rf_h": 76.1249098182959 + }, + { + "bin": 4, + "ref_a": 2.7436427517778226, + "ref_b": 20.08021904817262, + "test_a": 1.2540160909124423, + "test_b": 20.684383778023975, + "ref_a_norm": 0.1353762863406827, + "ref_b_norm": 0.9907942577026804, + "test_a_norm": 0.061875417741315934, + "test_b_norm": 1.0206048361434414, + "Rcs_pct": 1.4898468411488728, + "Rhs": 0.07790432536660603, + "Rf_h": 87.47368765927723 + }, + { + "bin": 5, + "ref_a": -2.8947048858716515, + "ref_b": 16.445261491730776, + "test_a": -3.7354497383292133, + "test_b": 16.964192919162564, + "ref_a_norm": -0.173355532020732, + "ref_b_norm": 0.984859309504565, + "test_a_norm": -0.22370531790143847, + "test_b_norm": 1.0159366169440165, + "Rcs_pct": 4.0302921632089905, + "Rhs": 0.0433194469474945, + "Rf_h": 92.69867250026557 + }, + { + "bin": 6, + "ref_a": -12.478044261316356, + "ref_b": 16.71168175230954, + "test_a": -12.399821763534508, + "test_b": 17.63658810716702, + "ref_a_norm": -0.5982888800912176, + "ref_b_norm": 0.8012804851980339, + "test_a_norm": -0.594538320338763, + "test_b_norm": 0.8456272734966158, + "Rcs_pct": 3.4789307517859904, + "Rhs": -0.02775623197200506, + "Rf_h": 92.61344492492461 + }, + { + "bin": 7, + "ref_a": -17.592126956204417, + "ref_b": 13.175368008802009, + "test_a": -16.062930313813975, + "test_b": 14.349488098338242, + "ref_a_norm": -0.800408799525612, + "ref_b_norm": 0.5994545467689513, + "test_a_norm": -0.7308332188228673, + "test_b_norm": 0.6528748099187212, + "Rcs_pct": -2.817127306654944, + "Rhs": -0.0830714470737371, + "Rf_h": 86.56688259576224 + }, + { + "bin": 8, + "ref_a": -21.40233106972439, + "ref_b": 5.014636351339698, + "test_a": -20.102904893753685, + "test_b": 5.310748162193928, + "ref_a_norm": -0.973631822435419, + "ref_b_norm": 0.22812512869275245, + "test_a_norm": -0.9145185103523097, + "test_b_norm": 0.24159580537312997, + "Rcs_pct": -5.534946771564605, + "Rhs": -0.024744276494919035, + "Rf_h": 89.9172186085351 + }, + { + "bin": 9, + "ref_a": -24.02935571709725, + "ref_b": -4.1661613914557085, + "test_a": -22.24380873453704, + "test_b": -4.398205684132331, + "ref_a_norm": -0.985300615247858, + "ref_b_norm": -0.17082944006286727, + "test_a_norm": -0.9120859789012512, + "test_b_norm": -0.18034419306044158, + "Rcs_pct": -6.995160141262653, + "Rhs": 0.023615396667846632, + "Rf_h": 87.37077981281243 + }, + { + "bin": 10, + "ref_a": -17.403316910775256, + "ref_b": -11.618376706583868, + "test_a": -15.256326180174478, + "test_b": -12.815290162186269, + "ref_a_norm": -0.8316935674327643, + "ref_b_norm": -0.5552349141498234, + "test_a_norm": -0.729090231003669, + "test_b_norm": -0.6124346552625015, + "Rcs_pct": -5.353308286301608, + "Rhs": 0.10456320609526559, + "Rf_h": 82.3952395195385 + }, + { + "bin": 11, + "ref_a": -10.492504519847726, + "ref_b": -16.076933128094645, + "test_a": -8.124403877218894, + "test_b": -17.41450689080737, + "ref_a_norm": -0.546543598681109, + "ref_b_norm": -0.8374306507053003, + "test_a_norm": -0.4231917102150946, + "test_b_norm": -0.9071034706113197, + "Rcs_pct": -1.0599804863188615, + "Rhs": 0.14127149166994377, + "Rf_h": 80.55572267483866 + }, + { + "bin": 12, + "ref_a": -6.073226212902036, + "ref_b": -21.21971628046086, + "test_a": -5.410552323562591, + "test_b": -22.759481352169818, + "ref_a_norm": -0.2751588291286285, + "ref_b_norm": -0.9613987823752235, + "test_a_norm": -0.2451351538870593, + "test_b_norm": -1.0311607078184952, + "Rcs_pct": 6.256414113636306, + "Rhs": 0.043056655239731005, + "Rf_h": 84.79569624110914 + }, + { + "bin": 13, + "ref_a": 3.754362977320948, + "ref_b": -17.79240767344944, + "test_a": 2.832352668294976, + "test_b": -19.02976568646164, + "ref_a_norm": 0.20646295377959742, + "ref_b_norm": -0.9784544183131905, + "test_a_norm": 0.15575901999198585, + "test_b_norm": -1.0465002071174607, + "Rcs_pct": 5.684646128254565, + "Rhs": -0.063004746767096, + "Rf_h": 88.08292269755711 + }, + { + "bin": 14, + "ref_a": 10.06389839321009, + "ref_b": -13.639766293337932, + "test_a": 8.64013549743553, + "test_b": -15.777124123811678, + "ref_a_norm": 0.593716785717339, + "ref_b_norm": -0.8046740820714132, + "test_a_norm": 0.5097223039493992, + "test_b_norm": -0.9307668913840367, + "Rcs_pct": 5.817750546513087, + "Rhs": -0.1398922706430525, + "Rf_h": 81.15771032977116 + }, + { + "bin": 15, + "ref_a": 19.353533611480067, + "ref_b": -12.846833503531244, + "test_a": 17.64745895295636, + "test_b": -14.525027616901133, + "ref_a_norm": 0.8331518094660919, + "ref_b_norm": -0.5530443584228816, + "test_a_norm": 0.7597068656450773, + "test_b_norm": -0.6252890704355806, + "Rcs_pct": -2.0930227477112044, + "Rhs": -0.10087310724086052, + "Rf_h": 83.41891442327842 + }, + { + "bin": 16, + "ref_a": 17.314186528951637, + "ref_b": -3.892788107663637, + "test_a": 15.370171635582494, + "test_b": -6.238520692313535, + "ref_a_norm": 0.9756447865869282, + "ref_b_norm": -0.21935644600910895, + "test_a_norm": 0.8661006279519576, + "test_b_norm": -0.3515371732476601, + "Rcs_pct": -8.165211770204047, + "Rhs": -0.15101191681164758, + "Rf_h": 77.70731167555729 + } + ] + } +} \ No newline at end of file diff --git a/crates/tm30/tests/golden/illuminant_LED_B2.json b/crates/tm30/tests/golden/illuminant_LED_B2.json new file mode 100644 index 0000000..84556dd --- /dev/null +++ b/crates/tm30/tests/golden/illuminant_LED_B2.json @@ -0,0 +1,403 @@ +{ + "name": "illuminant_LED_B2", + "source": "colour.SDS_ILLUMINANTS['LED-B2'] (380.0, 780.0, 5.0)", + "generator": "crates/tm30/tools/golden.py (tm30.py + colour-science 0.4.7, numpy 2.5.1)", + "wavelengths": [ + 380.0, + 385.0, + 390.0, + 395.0, + 400.0, + 405.0, + 410.0, + 415.0, + 420.0, + 425.0, + 430.0, + 435.0, + 440.0, + 445.0, + 450.0, + 455.0, + 460.0, + 465.0, + 470.0, + 475.0, + 480.0, + 485.0, + 490.0, + 495.0, + 500.0, + 505.0, + 510.0, + 515.0, + 520.0, + 525.0, + 530.0, + 535.0, + 540.0, + 545.0, + 550.0, + 555.0, + 560.0, + 565.0, + 570.0, + 575.0, + 580.0, + 585.0, + 590.0, + 595.0, + 600.0, + 605.0, + 610.0, + 615.0, + 620.0, + 625.0, + 630.0, + 635.0, + 640.0, + 645.0, + 650.0, + 655.0, + 660.0, + 665.0, + 670.0, + 675.0, + 680.0, + 685.0, + 690.0, + 695.0, + 700.0, + 705.0, + 710.0, + 715.0, + 720.0, + 725.0, + 730.0, + 735.0, + 740.0, + 745.0, + 750.0, + 755.0, + 760.0, + 765.0, + 770.0, + 775.0, + 780.0 + ], + "values": [ + 0.0, + 0.0, + 0.0, + 0.01, + 0.02, + 0.05, + 0.11, + 0.24, + 0.5, + 0.96, + 1.71, + 2.82, + 4.71, + 7.87, + 10.56, + 10.24, + 7.94, + 6.25, + 5.23, + 4.36, + 4.0, + 4.17, + 4.59, + 5.21, + 5.96, + 6.72, + 7.44, + 8.11, + 8.74, + 9.39, + 10.06, + 10.75, + 11.49, + 12.25, + 13.05, + 13.86, + 14.7, + 15.5, + 16.28, + 17.0, + 17.69, + 18.31, + 18.83, + 19.24, + 19.51, + 19.59, + 19.48, + 19.19, + 18.72, + 18.1, + 17.34, + 16.47, + 15.51, + 14.49, + 13.42, + 12.33, + 11.26, + 10.24, + 9.25, + 8.3, + 7.42, + 6.6, + 5.85, + 5.17, + 4.55, + 3.99, + 3.49, + 3.04, + 2.65, + 2.31, + 2.01, + 1.75, + 1.52, + 1.32, + 1.15, + 1.0, + 0.87, + 0.76, + 0.67, + 0.59, + 0.52 + ], + "expected": { + "Rf": 84.34733207675345, + "Rg": 96.53858249879536, + "CCT_K": 2998.8293567548126, + "Duv": -0.0009382909537549365, + "bins": [ + { + "bin": 1, + "ref_a": 23.97915388755696, + "ref_b": 5.027428544445078, + "test_a": 21.50243524549314, + "test_b": 4.432103502172079, + "ref_a_norm": 0.9787207086963913, + "ref_b_norm": 0.20519691608022192, + "test_a_norm": 0.8776322451096874, + "test_b_norm": 0.18089843790996066, + "Rcs_pct": -10.388647503515516, + "Rhs": -0.0041102088123457945, + "Rf_h": 81.24796121748878 + }, + { + "bin": 2, + "ref_a": 20.534043910556658, + "ref_b": 15.081384300256559, + "test_a": 17.879575569196913, + "test_b": 15.404201156019957, + "ref_a_norm": 0.8059726731907872, + "ref_b_norm": 0.591952743105137, + "test_a_norm": 0.7017833106713988, + "test_b_norm": 0.6046234846952487, + "Rcs_pct": -7.959080200229574, + "Rhs": 0.06841984501057638, + "Rf_h": 81.67619629219601 + }, + { + "bin": 3, + "ref_a": 14.807417241068373, + "ref_b": 22.92952516106735, + "test_a": 11.674309695808759, + "test_b": 24.051094987128124, + "ref_a_norm": 0.5424935172196838, + "ref_b_norm": 0.8400599882000194, + "test_a_norm": 0.42770708928400525, + "test_b_norm": 0.8811505004643498, + "Rcs_pct": -2.960641021397683, + "Rhs": 0.11827009220686152, + "Rf_h": 76.97026347240579 + }, + { + "bin": 4, + "ref_a": 2.7162139287694647, + "ref_b": 20.474087922231792, + "test_a": 1.2697450996271702, + "test_b": 20.907360055450184, + "ref_a_norm": 0.13151364225762502, + "ref_b_norm": 0.9913143607857869, + "test_a_norm": 0.06147851648282784, + "test_b_norm": 1.0122925303344925, + "Rcs_pct": 0.6911904663328504, + "Rhs": 0.07278205832367587, + "Rf_h": 87.51036326786442 + }, + { + "bin": 5, + "ref_a": -2.939990098756877, + "ref_b": 16.859828821013984, + "test_a": -3.7843907504237837, + "test_b": 17.275236951167813, + "ref_a_norm": -0.17178614425084196, + "ref_b_norm": 0.9851342652874423, + "test_a_norm": -0.22112519890075072, + "test_b_norm": 1.009406918790511, + "Rcs_pct": 3.343183333175963, + "Rhs": 0.043655658761541524, + "Rf_h": 92.24464281188973 + }, + { + "bin": 6, + "ref_a": -12.72110484241996, + "ref_b": 16.997932382940867, + "test_a": -12.536648644843039, + "test_b": 17.909663940821222, + "ref_a_norm": -0.5991753949412286, + "ref_b_norm": 0.800617790270128, + "test_a_norm": -0.5904873433606802, + "test_b_norm": 0.8435611606015859, + "Rcs_pct": 3.0879284639370352, + "Rhs": -0.031081909141038266, + "Rf_h": 92.5498872844645 + }, + { + "bin": 7, + "ref_a": -18.668717080506205, + "ref_b": 13.265471835601673, + "test_a": -17.107713710392233, + "test_b": 14.147798095273352, + "ref_a_norm": -0.8151627380437267, + "ref_b_norm": 0.5792320005878943, + "test_a_norm": -0.7470020939142863, + "test_b_norm": 0.6177584556506727, + "Rcs_pct": -3.5269352731950634, + "Rhs": -0.06990160159619924, + "Rf_h": 87.08898215297634 + }, + { + "bin": 8, + "ref_a": -21.45429647151378, + "ref_b": 5.809983484342103, + "test_a": -20.1990447347491, + "test_b": 6.027568886176166, + "ref_a_norm": -0.9652326737114465, + "ref_b_norm": 0.26139220646349093, + "test_a_norm": -0.9087586713284257, + "test_b_norm": 0.27118141299616516, + "Rcs_pct": -5.347909080798207, + "Rhs": -0.020618640984517166, + "Rf_h": 90.40333307010968 + }, + { + "bin": 9, + "ref_a": -22.564521635070896, + "ref_b": -3.731807599356716, + "test_a": -20.840333956680837, + "test_b": -4.232690133207512, + "ref_a_norm": -0.9865983906702526, + "ref_b_norm": -0.16316744628407837, + "test_a_norm": -0.911210983118514, + "test_b_norm": -0.1850677510990482, + "Rcs_pct": -6.966632213590068, + "Rhs": 0.03618685021409618, + "Rf_h": 87.24344867143996 + }, + { + "bin": 10, + "ref_a": -18.13701203902219, + "ref_b": -11.850819908497424, + "test_a": -15.787059666220602, + "test_b": -13.291023288079032, + "ref_a_norm": -0.8371386106118205, + "ref_b_norm": -0.5469908103642241, + "test_a_norm": -0.7286733430066318, + "test_b_norm": -0.6134653682234465, + "Rcs_pct": -5.325428840425487, + "Rhs": 0.11553164884913902, + "Rf_h": 80.34672395453201 + }, + { + "bin": 11, + "ref_a": -10.987369776327254, + "ref_b": -15.751349294295325, + "test_a": -8.424826964888087, + "test_b": -17.351889739471307, + "ref_a_norm": -0.5721135208035061, + "ref_b_norm": -0.8201744444408252, + "test_a_norm": -0.4386816422095158, + "test_b_norm": -0.9035147568103002, + "Rcs_pct": -0.4835842667686087, + "Rhs": 0.1572459491263811, + "Rf_h": 78.72013092673527 + }, + { + "bin": 12, + "ref_a": -6.73556059295356, + "ref_b": -21.15615282903148, + "test_a": -5.727165616899922, + "test_b": -22.814102380185762, + "ref_a_norm": -0.30336959854486173, + "ref_b_norm": -0.9528729646068932, + "test_a_norm": -0.25795149639311454, + "test_b_norm": -1.0275469999451683, + "Rcs_pct": 6.437856251394521, + "Rhs": 0.05911358765467181, + "Rf_h": 84.22109654124172 + }, + { + "bin": 13, + "ref_a": 3.142386586548557, + "ref_b": -18.090664652555994, + "test_a": 2.5466691045046246, + "test_b": -19.24637178522403, + "ref_a_norm": 0.17113944895951286, + "ref_b_norm": -0.9852468162901284, + "test_a_norm": 0.1386957127085493, + "test_b_norm": -1.0481884933867796, + "Rcs_pct": 5.540281146768162, + "Rhs": -0.04409965100925057, + "Rf_h": 89.39612161728057 + }, + { + "bin": 14, + "ref_a": 9.199406119969233, + "ref_b": -14.06935346814885, + "test_a": 8.081833966036967, + "test_b": -16.181335982152156, + "ref_a_norm": 0.5472582587336102, + "ref_b_norm": -0.8369637974535439, + "test_a_norm": 0.4807756420305021, + "test_b_norm": -0.9626023286822475, + "Rcs_pct": 6.7528857997492775, + "Rhs": -0.12507930360596342, + "Rf_h": 82.18196146718284 + }, + { + "bin": 15, + "ref_a": 18.27079282503619, + "ref_b": -11.929423343033529, + "test_a": 16.548401641187443, + "test_b": -14.001035256670306, + "ref_a_norm": 0.83732343493657, + "ref_b_norm": -0.5467078427332313, + "test_a_norm": 0.7583887922981578, + "test_b_norm": -0.6416467553459866, + "Rcs_pct": -1.2886522908904432, + "Rhs": -0.12279255866649459, + "Rf_h": 81.05119744685643 + }, + { + "bin": 16, + "ref_a": 16.78679181808261, + "ref_b": -3.8060201667767544, + "test_a": 15.250805158060741, + "test_b": -6.12857462530907, + "ref_a_norm": 0.9752477271272282, + "ref_b_norm": -0.2211150622033143, + "test_a_norm": 0.8860128384529986, + "test_b_norm": -0.3560465000479737, + "Rcs_pct": -6.119644765089141, + "Rhs": -0.14974763126821417, + "Rf_h": 79.28830222371093 + } + ] + } +} \ No newline at end of file diff --git a/crates/tm30/tests/golden/illuminant_LED_B3.json b/crates/tm30/tests/golden/illuminant_LED_B3.json new file mode 100644 index 0000000..ab9c01b --- /dev/null +++ b/crates/tm30/tests/golden/illuminant_LED_B3.json @@ -0,0 +1,403 @@ +{ + "name": "illuminant_LED_B3", + "source": "colour.SDS_ILLUMINANTS['LED-B3'] (380.0, 780.0, 5.0)", + "generator": "crates/tm30/tools/golden.py (tm30.py + colour-science 0.4.7, numpy 2.5.1)", + "wavelengths": [ + 380.0, + 385.0, + 390.0, + 395.0, + 400.0, + 405.0, + 410.0, + 415.0, + 420.0, + 425.0, + 430.0, + 435.0, + 440.0, + 445.0, + 450.0, + 455.0, + 460.0, + 465.0, + 470.0, + 475.0, + 480.0, + 485.0, + 490.0, + 495.0, + 500.0, + 505.0, + 510.0, + 515.0, + 520.0, + 525.0, + 530.0, + 535.0, + 540.0, + 545.0, + 550.0, + 555.0, + 560.0, + 565.0, + 570.0, + 575.0, + 580.0, + 585.0, + 590.0, + 595.0, + 600.0, + 605.0, + 610.0, + 615.0, + 620.0, + 625.0, + 630.0, + 635.0, + 640.0, + 645.0, + 650.0, + 655.0, + 660.0, + 665.0, + 670.0, + 675.0, + 680.0, + 685.0, + 690.0, + 695.0, + 700.0, + 705.0, + 710.0, + 715.0, + 720.0, + 725.0, + 730.0, + 735.0, + 740.0, + 745.0, + 750.0, + 755.0, + 760.0, + 765.0, + 770.0, + 775.0, + 780.0 + ], + "values": [ + 0.0, + 0.0, + 0.01, + 0.02, + 0.05, + 0.11, + 0.25, + 0.56, + 1.2, + 2.37, + 4.24, + 7.17, + 12.11, + 17.7, + 18.87, + 14.58, + 9.9, + 7.53, + 6.02, + 5.11, + 5.17, + 5.82, + 6.77, + 7.88, + 8.94, + 9.82, + 10.52, + 11.06, + 11.51, + 11.93, + 12.37, + 12.83, + 13.31, + 13.79, + 14.26, + 14.68, + 15.08, + 15.42, + 15.72, + 15.97, + 16.18, + 16.37, + 16.5, + 16.55, + 16.5, + 16.32, + 16.0, + 15.54, + 14.96, + 14.27, + 13.48, + 12.62, + 11.71, + 10.78, + 9.85, + 8.93, + 8.04, + 7.2, + 6.42, + 5.69, + 5.02, + 4.42, + 3.88, + 3.39, + 2.95, + 2.56, + 2.22, + 1.92, + 1.65, + 1.43, + 1.23, + 1.06, + 0.91, + 0.78, + 0.68, + 0.58, + 0.5, + 0.43, + 0.37, + 0.32, + 0.28 + ], + "expected": { + "Rf": 85.38454466499574, + "Rg": 97.80916983177697, + "CCT_K": 4102.468462648342, + "Duv": -0.0006011925463278111, + "bins": [ + { + "bin": 1, + "ref_a": 21.493700038778744, + "ref_b": 4.988242897626086, + "test_a": 19.411233459420643, + "test_b": 4.23669712832581, + "ref_a_norm": 0.9741108355243191, + "ref_b_norm": 0.2260709625628928, + "test_a_norm": 0.8797318660630308, + "test_b_norm": 0.1920103366144972, + "Rcs_pct": -9.921040251160099, + "Rhs": -0.014993737027753664, + "Rf_h": 83.4297296336035 + }, + { + "bin": 2, + "ref_a": 20.632629880562934, + "ref_b": 14.362498686856105, + "test_a": 18.45702290929628, + "test_b": 14.547321804053496, + "ref_a_norm": 0.8207305308064994, + "ref_b_norm": 0.5713154958532822, + "test_a_norm": 0.734188627292972, + "test_b_norm": 0.5786674415800666, + "Rcs_pct": -6.787244076173993, + "Rhs": 0.05419302496408906, + "Rf_h": 85.10699708123433 + }, + { + "bin": 3, + "ref_a": 14.624451736408473, + "ref_b": 22.296146038282902, + "test_a": 11.639461010289333, + "test_b": 23.24160604115465, + "ref_a_norm": 0.548462599352322, + "ref_b_norm": 0.8361750875933188, + "test_a_norm": 0.4365161276350898, + "test_b_norm": 0.8716327895369569, + "Rcs_pct": -3.2712125689449016, + "Rhs": 0.11277933316853155, + "Rf_h": 78.25955648281744 + }, + { + "bin": 4, + "ref_a": 3.7835162288529713, + "ref_b": 22.124812911061632, + "test_a": 1.9767958833820278, + "test_b": 22.820844592301984, + "ref_a_norm": 0.16856091893229183, + "ref_b_norm": 0.9856912379689197, + "test_a_norm": 0.08806901054193811, + "test_b_norm": 1.0167004190320679, + "Rcs_pct": 1.471015601652765, + "Rhs": 0.08499487005989027, + "Rf_h": 86.27543627383668 + }, + { + "bin": 5, + "ref_a": -2.2119448982587593, + "ref_b": 19.128112735900892, + "test_a": -3.291537129347195, + "test_b": 19.62157489511573, + "ref_a_norm": -0.1148729246833131, + "ref_b_norm": 0.9933801946760877, + "test_a_norm": -0.17093938327734817, + "test_b_norm": 1.0190071628226152, + "Rcs_pct": 3.607257660089089, + "Rhs": 0.04998958384536367, + "Rf_h": 89.60652362320151 + }, + { + "bin": 6, + "ref_a": -11.148284468239948, + "ref_b": 17.1677040233428, + "test_a": -11.39696704723814, + "test_b": 18.065201098368796, + "ref_a_norm": -0.5446200371740401, + "ref_b_norm": 0.8386829049817024, + "test_a_norm": -0.5567687687393653, + "test_b_norm": 0.8825277576813949, + "Rcs_pct": 4.320513630231583, + "Rhs": -0.014257593906489615, + "Rf_h": 92.82495255458217 + }, + { + "bin": 7, + "ref_a": -18.22992331946901, + "ref_b": 11.24691605814716, + "test_a": -17.466247703984767, + "test_b": 11.849761625225947, + "ref_a_norm": -0.851063853070619, + "ref_b_norm": 0.5250622039307264, + "test_a_norm": -0.8154116618671606, + "test_b_norm": 0.5532060453574581, + "Rcs_pct": -1.400783305815979, + "Rhs": -0.043208045094353754, + "Rf_h": 92.60981186463823 + }, + { + "bin": 8, + "ref_a": -22.791094414999094, + "ref_b": 3.5783056508914783, + "test_a": -21.63679053114567, + "test_b": 3.972900051049529, + "ref_a_norm": -0.9878980690861981, + "ref_b_norm": 0.1551044973421503, + "test_a_norm": -0.9378638514556913, + "test_b_norm": 0.17220850467458537, + "Rcs_pct": -4.5735997870242, + "Rhs": -0.026536550256921917, + "Rf_h": 90.99812250246637 + }, + { + "bin": 9, + "ref_a": -19.358695818866227, + "ref_b": -2.138550289677423, + "test_a": -18.04586460164093, + "test_b": -2.3804357614617597, + "ref_a_norm": -0.9939535028340915, + "ref_b_norm": -0.10980179508477993, + "test_a_norm": -0.9265474544514658, + "test_b_norm": -0.12222117055378294, + "Rcs_pct": -6.368796010434018, + "Rhs": 0.02533100833660028, + "Rf_h": 89.70008985728177 + }, + { + "bin": 10, + "ref_a": -20.13938161720979, + "ref_b": -11.276882541572865, + "test_a": -17.656286839488484, + "test_b": -12.150025595206047, + "ref_a_norm": -0.8725276460495388, + "ref_b_norm": -0.48856474174795994, + "test_a_norm": -0.7649489287630226, + "test_b_norm": -0.5263931849311432, + "Rcs_pct": -6.8432077360174866, + "Rhs": 0.09122073401834997, + "Rf_h": 81.03131409186874 + }, + { + "bin": 11, + "ref_a": -12.058765085586693, + "ref_b": -17.35832814592787, + "test_a": -9.731732854037412, + "test_b": -19.17316472214909, + "ref_a_norm": -0.5705353071141365, + "ref_b_norm": -0.8212730747663521, + "test_a_norm": -0.46043663287440445, + "test_b_norm": -0.9071382803680387, + "Rcs_pct": 1.0226763109395476, + "Rhs": 0.1392478542695392, + "Rf_h": 79.16884516152162 + }, + { + "bin": 12, + "ref_a": -5.355869302207186, + "ref_b": -23.677128262453852, + "test_a": -3.7674158046964528, + "test_b": -25.27491515765099, + "ref_a_norm": -0.22063011639956076, + "ref_b_norm": -0.9753575507153858, + "test_a_norm": -0.15519523360534182, + "test_b_norm": -1.0411769142543283, + "Rcs_pct": 5.178895056909215, + "Rhs": 0.07701829069718949, + "Rf_h": 83.80246099547927 + }, + { + "bin": 13, + "ref_a": 3.6851177309438863, + "ref_b": -15.344206524702424, + "test_a": 3.3244804449878362, + "test_b": -16.79067652102979, + "ref_a_norm": 0.23352323391202867, + "ref_b_norm": -0.9723512221534295, + "test_a_norm": 0.21066991105112162, + "test_b_norm": -1.0640129751722587, + "Rcs_pct": 8.544203602075124, + "Rhs": -0.04029652358328651, + "Rf_h": 87.94260428346455 + }, + { + "bin": 14, + "ref_a": 14.029630985391613, + "ref_b": -18.584341686033618, + "test_a": 13.751613797545424, + "test_b": -20.18083538621383, + "ref_a_norm": 0.6025084842906558, + "ref_b_norm": -0.7981124772598013, + "test_a_norm": 0.5905689176241928, + "test_b_norm": -0.866674579889353, + "Rcs_pct": 5.037403705700088, + "Rhs": -0.04801845020143831, + "Rf_h": 87.73068838779997 + }, + { + "bin": 15, + "ref_a": 15.409151371662551, + "ref_b": -11.033295046254093, + "test_a": 14.09068326252373, + "test_b": -13.348982703712437, + "ref_a_norm": 0.8130651404504684, + "ref_b_norm": -0.5821727212642827, + "test_a_norm": 0.7434960621488671, + "test_b_norm": -0.7043601711139392, + "Rcs_pct": 1.003913542136679, + "Rhs": -0.14024566059771024, + "Rf_h": 81.36354336083727 + }, + { + "bin": 16, + "ref_a": 20.095720713781855, + "ref_b": -3.5916327530650496, + "test_a": 18.894048104618967, + "test_b": -5.809030994271718, + "ref_a_norm": 0.9844011904551454, + "ref_b_norm": -0.1759383307596512, + "test_a_norm": 0.9255365215116712, + "test_b_norm": -0.2845589420552688, + "Rcs_pct": -3.654277080031794, + "Rhs": -0.11801742392669783, + "Rf_h": 80.91962503699635 + } + ] + } +} \ No newline at end of file diff --git a/crates/tm30/tests/golden/illuminant_LED_B4.json b/crates/tm30/tests/golden/illuminant_LED_B4.json new file mode 100644 index 0000000..349c702 --- /dev/null +++ b/crates/tm30/tests/golden/illuminant_LED_B4.json @@ -0,0 +1,403 @@ +{ + "name": "illuminant_LED_B4", + "source": "colour.SDS_ILLUMINANTS['LED-B4'] (380.0, 780.0, 5.0)", + "generator": "crates/tm30/tools/golden.py (tm30.py + colour-science 0.4.7, numpy 2.5.1)", + "wavelengths": [ + 380.0, + 385.0, + 390.0, + 395.0, + 400.0, + 405.0, + 410.0, + 415.0, + 420.0, + 425.0, + 430.0, + 435.0, + 440.0, + 445.0, + 450.0, + 455.0, + 460.0, + 465.0, + 470.0, + 475.0, + 480.0, + 485.0, + 490.0, + 495.0, + 500.0, + 505.0, + 510.0, + 515.0, + 520.0, + 525.0, + 530.0, + 535.0, + 540.0, + 545.0, + 550.0, + 555.0, + 560.0, + 565.0, + 570.0, + 575.0, + 580.0, + 585.0, + 590.0, + 595.0, + 600.0, + 605.0, + 610.0, + 615.0, + 620.0, + 625.0, + 630.0, + 635.0, + 640.0, + 645.0, + 650.0, + 655.0, + 660.0, + 665.0, + 670.0, + 675.0, + 680.0, + 685.0, + 690.0, + 695.0, + 700.0, + 705.0, + 710.0, + 715.0, + 720.0, + 725.0, + 730.0, + 735.0, + 740.0, + 745.0, + 750.0, + 755.0, + 760.0, + 765.0, + 770.0, + 775.0, + 780.0 + ], + "values": [ + 0.0, + 0.0, + 0.0, + 0.01, + 0.03, + 0.08, + 0.21, + 0.54, + 1.31, + 2.75, + 5.04, + 8.31, + 13.37, + 20.61, + 25.91, + 24.12, + 17.47, + 11.9, + 8.62, + 6.34, + 4.89, + 4.25, + 4.19, + 4.7, + 5.77, + 7.27, + 8.94, + 10.6, + 12.11, + 13.36, + 14.3, + 15.02, + 15.54, + 15.9, + 16.15, + 16.33, + 16.42, + 16.44, + 16.36, + 16.2, + 15.98, + 15.7, + 15.36, + 14.93, + 14.44, + 13.86, + 13.24, + 12.57, + 11.84, + 11.12, + 10.38, + 9.65, + 8.91, + 8.19, + 7.51, + 6.86, + 6.21, + 5.6, + 5.05, + 4.54, + 4.05, + 3.62, + 3.23, + 2.87, + 2.53, + 2.24, + 1.99, + 1.76, + 1.55, + 1.37, + 1.21, + 1.07, + 0.95, + 0.85, + 0.75, + 0.67, + 0.61, + 0.55, + 0.5, + 0.45, + 0.42 + ], + "expected": { + "Rf": 77.01489073451978, + "Rg": 95.48050994275931, + "CCT_K": 5105.847634900008, + "Duv": 0.0005183936640995037, + "bins": [ + { + "bin": 1, + "ref_a": 24.429627739019857, + "ref_b": 5.563568891481263, + "test_a": 20.982017715681533, + "test_b": 4.4557469854189, + "ref_a_norm": 0.9750345967143299, + "ref_b_norm": 0.22205300090321672, + "test_a_norm": 0.8374336850408051, + "test_b_norm": 0.17783764498587953, + "Rcs_pct": -14.358293676342926, + "Rhs": -0.016521164083413416, + "Rf_h": 72.97349191001292 + }, + { + "bin": 2, + "ref_a": 17.793954251895165, + "ref_b": 11.998364602506557, + "test_a": 15.019807003079306, + "test_b": 12.131100978446428, + "ref_a_norm": 0.8291198450027608, + "ref_b_norm": 0.5590709101917196, + "test_a_norm": 0.6998568096823196, + "test_b_norm": 0.5652558403026742, + "Rcs_pct": -10.404212279998454, + "Rhs": 0.07695727609527232, + "Rf_h": 79.59738883503852 + }, + { + "bin": 3, + "ref_a": 14.49133615816406, + "ref_b": 22.074201323565415, + "test_a": 9.899266209614906, + "test_b": 23.56158701074592, + "ref_a_norm": 0.5487925333247512, + "ref_b_norm": 0.8359585847199621, + "test_a_norm": 0.37488905936186256, + "test_b_norm": 0.8922864588641901, + "Rcs_pct": -4.978067787595255, + "Rhs": 0.17588954423779637, + "Rf_h": 66.55900371541189 + }, + { + "bin": 4, + "ref_a": 4.061226309909171, + "ref_b": 22.030321804224744, + "test_a": 0.7716193833911106, + "test_b": 23.24867736135438, + "ref_a_norm": 0.1812923465168738, + "ref_b_norm": 0.9834292476301515, + "test_a_norm": 0.03444493804532806, + "test_b_norm": 1.0378164009155946, + "Rcs_pct": 2.4693611179448975, + "Rhs": 0.1546361839422503, + "Rf_h": 75.73789445554223 + }, + { + "bin": 5, + "ref_a": -2.076984505218802, + "ref_b": 19.213113120887506, + "test_a": -4.007256451814331, + "test_b": 20.09513240239614, + "ref_a_norm": -0.10747627775661847, + "ref_b_norm": 0.994207649195872, + "test_a_norm": -0.20736072241994288, + "test_b_norm": 1.039848889680778, + "Rcs_pct": 6.425074532070993, + "Rhs": 0.08906102876362375, + "Rf_h": 82.97135162070803 + }, + { + "bin": 6, + "ref_a": -10.820085458070144, + "ref_b": 17.57356859266115, + "test_a": -11.20204396311849, + "test_b": 18.90224071511591, + "ref_a_norm": -0.5242935859234263, + "ref_b_norm": 0.8515375715489921, + "test_a_norm": -0.542801609271466, + "test_b_norm": 0.9159191583948452, + "Rcs_pct": 6.381383989834682, + "Rhs": -0.020379634208441234, + "Rf_h": 88.54465877344713 + }, + { + "bin": 7, + "ref_a": -17.863984813996588, + "ref_b": 11.89772071439477, + "test_a": -16.497931444271103, + "test_b": 12.806362745566735, + "ref_a_norm": -0.8322997045070458, + "ref_b_norm": 0.5543258986169455, + "test_a_norm": -0.7686540046365135, + "test_b_norm": 0.5966603778454863, + "Rcs_pct": -2.939968890631176, + "Rhs": -0.0705594893389524, + "Rf_h": 87.85143841354181 + }, + { + "bin": 8, + "ref_a": -20.62938349606797, + "ref_b": 2.9558410537485607, + "test_a": -18.514786831295954, + "test_b": 3.2713743642136173, + "ref_a_norm": -0.9898903827961393, + "ref_b_norm": 0.1418345164186513, + "test_a_norm": -0.8884225467675161, + "test_b_norm": 0.15697522043148435, + "Rcs_pct": -9.65643551898277, + "Rhs": -0.0346451724358326, + "Rf_h": 84.72684345087318 + }, + { + "bin": 9, + "ref_a": -18.75541525751099, + "ref_b": -2.730058650267297, + "test_a": -15.920808505809541, + "test_b": -3.3104826625017836, + "ref_a_norm": -0.9895714161485137, + "ref_b_norm": -0.1440430919614858, + "test_a_norm": -0.8400121673133272, + "test_b_norm": -0.17466736787686252, + "Rcs_pct": -14.071100995587337, + "Rhs": 0.05921340105655548, + "Rf_h": 79.04750737963052 + }, + { + "bin": 10, + "ref_a": -19.833023716160113, + "ref_b": -11.901273962726155, + "test_a": -15.232651058292356, + "test_b": -14.395636391337353, + "ref_a_norm": -0.8574650816324481, + "ref_b_norm": -0.5145421593815799, + "test_a_norm": -0.6585716111726655, + "test_b_norm": -0.6223839445818505, + "Rcs_pct": -10.546019103973892, + "Rhs": 0.20016645905990219, + "Rf_h": 63.23450887813762 + }, + { + "bin": 11, + "ref_a": -12.944314473848145, + "ref_b": -19.275514964027778, + "test_a": -8.252919351956857, + "test_b": -22.120517848803416, + "ref_a_norm": -0.557498990800704, + "ref_b_norm": -0.8301776166918718, + "test_a_norm": -0.3554451816796555, + "test_b_norm": -0.9527091142301878, + "Rcs_pct": -1.0373865062845402, + "Rhs": 0.23607645497373364, + "Rf_h": 62.02348368207611 + }, + { + "bin": 12, + "ref_a": -3.189453051639944, + "ref_b": -20.750651276004632, + "test_a": -0.6489759804066143, + "test_b": -22.408902870143407, + "ref_a_norm": -0.15191969250618095, + "ref_b_norm": -0.9883928404378632, + "test_a_norm": -0.03091195568361675, + "test_b_norm": -1.067378506067873, + "Rcs_pct": 5.3860539869608, + "Rhs": 0.13409194603289581, + "Rf_h": 78.42309035512805 + }, + { + "bin": 13, + "ref_a": 2.638220440956579, + "ref_b": -15.60519008554288, + "test_a": 3.383499200637146, + "test_b": -17.376257278442015, + "ref_a_norm": 0.16669503976552152, + "ref_b_norm": -0.9860085008343342, + "test_a_norm": 0.21378521864242583, + "test_b_norm": -1.0979127646193145, + "Rcs_pct": 11.894089289556126, + "Rhs": 0.024353915437233326, + "Rf_h": 84.3434781214181 + }, + { + "bin": 14, + "ref_a": 13.515834981857509, + "ref_b": -18.027872657474177, + "test_a": 13.28542872739122, + "test_b": -20.42017848168322, + "ref_a_norm": 0.5998559943603995, + "ref_b_norm": -0.8001079839808477, + "test_a_norm": 0.5896301686481699, + "test_b_norm": -0.9062826295666634, + "Rcs_pct": 8.25998270278371, + "Rhs": -0.06748993592930619, + "Rf_h": 80.82922438869534 + }, + { + "bin": 15, + "ref_a": 12.771436579107572, + "ref_b": -8.307921625282166, + "test_a": 11.792494568722583, + "test_b": -11.6687974859548, + "ref_a_norm": 0.8382489842541995, + "ref_b_norm": -0.545287667563464, + "test_a_norm": 0.7739964515993083, + "test_b_norm": -0.765877634789387, + "Rcs_pct": 6.9129191077473475, + "Rhs": -0.21911064906634686, + "Rf_h": 73.8095031432343 + }, + { + "bin": 16, + "ref_a": 21.696597881956226, + "ref_b": -3.5144507456073732, + "test_a": 20.122556166286675, + "test_b": -5.6553302479579095, + "ref_a_norm": 0.9871336175538821, + "ref_b_norm": -0.15989753311100904, + "test_a_norm": 0.9155191874287887, + "test_b_norm": -0.2573014735536613, + "Rcs_pct": -5.123581282456041, + "Rhs": -0.10950363327353226, + "Rf_h": 80.32426551000091 + } + ] + } +} \ No newline at end of file diff --git a/crates/tm30/tests/golden/illuminant_LED_B5.json b/crates/tm30/tests/golden/illuminant_LED_B5.json new file mode 100644 index 0000000..3ceec95 --- /dev/null +++ b/crates/tm30/tests/golden/illuminant_LED_B5.json @@ -0,0 +1,403 @@ +{ + "name": "illuminant_LED_B5", + "source": "colour.SDS_ILLUMINANTS['LED-B5'] (380.0, 780.0, 5.0)", + "generator": "crates/tm30/tools/golden.py (tm30.py + colour-science 0.4.7, numpy 2.5.1)", + "wavelengths": [ + 380.0, + 385.0, + 390.0, + 395.0, + 400.0, + 405.0, + 410.0, + 415.0, + 420.0, + 425.0, + 430.0, + 435.0, + 440.0, + 445.0, + 450.0, + 455.0, + 460.0, + 465.0, + 470.0, + 475.0, + 480.0, + 485.0, + 490.0, + 495.0, + 500.0, + 505.0, + 510.0, + 515.0, + 520.0, + 525.0, + 530.0, + 535.0, + 540.0, + 545.0, + 550.0, + 555.0, + 560.0, + 565.0, + 570.0, + 575.0, + 580.0, + 585.0, + 590.0, + 595.0, + 600.0, + 605.0, + 610.0, + 615.0, + 620.0, + 625.0, + 630.0, + 635.0, + 640.0, + 645.0, + 650.0, + 655.0, + 660.0, + 665.0, + 670.0, + 675.0, + 680.0, + 685.0, + 690.0, + 695.0, + 700.0, + 705.0, + 710.0, + 715.0, + 720.0, + 725.0, + 730.0, + 735.0, + 740.0, + 745.0, + 750.0, + 755.0, + 760.0, + 765.0, + 770.0, + 775.0, + 780.0 + ], + "values": [ + 0.0, + 0.01, + 0.01, + 0.03, + 0.07, + 0.16, + 0.35, + 0.78, + 1.67, + 3.3, + 5.94, + 9.92, + 16.15, + 25.15, + 32.34, + 31.18, + 23.46, + 16.39, + 12.08, + 9.08, + 7.21, + 6.48, + 6.49, + 7.05, + 8.1, + 9.45, + 10.88, + 12.22, + 13.38, + 14.29, + 14.98, + 15.48, + 15.81, + 16.01, + 16.1, + 16.13, + 16.1, + 15.98, + 15.77, + 15.5, + 15.15, + 14.76, + 14.31, + 13.79, + 13.22, + 12.59, + 11.91, + 11.2, + 10.47, + 9.73, + 9.0, + 8.27, + 7.57, + 6.9, + 6.25, + 5.65, + 5.08, + 4.55, + 4.06, + 3.61, + 3.22, + 2.86, + 2.54, + 2.26, + 2.0, + 1.75, + 1.54, + 1.36, + 1.2, + 1.05, + 0.93, + 0.82, + 0.72, + 0.64, + 0.56, + 0.49, + 0.44, + 0.39, + 0.35, + 0.31, + 0.27 + ], + "expected": { + "Rf": 79.5691048492081, + "Rg": 94.12549747208713, + "CCT_K": 6590.664429465209, + "Duv": 0.0009487153208891814, + "bins": [ + { + "bin": 1, + "ref_a": 23.79425151868596, + "ref_b": 4.844212561131337, + "test_a": 20.61202973516683, + "test_b": 3.950309306576371, + "ref_a_norm": 0.9798988107097553, + "ref_b_norm": 0.19949516477751342, + "test_a_norm": 0.8488480256646251, + "test_b_norm": 0.16268229275503746, + "Rcs_pct": -13.571451601475475, + "Rhs": -0.010538783154091494, + "Rf_h": 74.51809918440918 + }, + { + "bin": 2, + "ref_a": 22.143688780638108, + "ref_b": 14.058011561158173, + "test_a": 18.9492091352518, + "test_b": 14.433836270200548, + "ref_a_norm": 0.8442382329686573, + "ref_b_norm": 0.5359681016571407, + "test_a_norm": 0.7224472397068036, + "test_b_norm": 0.5502965900770701, + "Rcs_pct": -9.33050282990965, + "Rhs": 0.07957715321757707, + "Rf_h": 78.12060984097693 + }, + { + "bin": 3, + "ref_a": 12.001112735921543, + "ref_b": 18.51486893619952, + "test_a": 8.954329446304058, + "test_b": 19.161032754036935, + "ref_a_norm": 0.5439189026850149, + "ref_b_norm": 0.8391377880312204, + "test_a_norm": 0.40583145528961895, + "test_b_norm": 0.8684234653252016, + "Rcs_pct": -5.236712458089816, + "Rhs": 0.13108576690805201, + "Rf_h": 76.64152445208737 + }, + { + "bin": 4, + "ref_a": 4.494012997822085, + "ref_b": 22.866449820584368, + "test_a": 1.6792081920777444, + "test_b": 23.687638203228428, + "ref_a_norm": 0.1928440066119929, + "ref_b_norm": 0.9812294273582676, + "test_a_norm": 0.07205703139997309, + "test_b_norm": 1.0164677005828997, + "Rcs_pct": 1.0996809796079434, + "Rhs": 0.1253407334230647, + "Rf_h": 79.0538767187271 + }, + { + "bin": 5, + "ref_a": -1.5735582603354834, + "ref_b": 21.52622300560894, + "test_a": -2.9910338173452256, + "test_b": 21.72584743034775, + "ref_a_norm": -0.07290507208780493, + "ref_b_norm": 0.9973388844639881, + "test_a_norm": -0.13857862245540575, + "test_b_norm": 1.0065877527410143, + "Rcs_pct": 2.188342795565333, + "Rhs": 0.06260728682191326, + "Rf_h": 84.18130658136359 + }, + { + "bin": 6, + "ref_a": -10.220630079392246, + "ref_b": 16.79289639620513, + "test_a": -10.148540957915452, + "test_b": 17.295828910183975, + "ref_a_norm": -0.5199048956369814, + "ref_b_norm": 0.8542241506142866, + "test_a_norm": -0.5162378529119421, + "test_b_norm": 0.8798074144797727, + "Rcs_pct": 1.923440670642649, + "Rhs": -0.017262334460035424, + "Rf_h": 91.99917508600645 + }, + { + "bin": 7, + "ref_a": -17.900405932384565, + "ref_b": 11.666964444190057, + "test_a": -16.718745493507388, + "test_b": 11.937907570634934, + "ref_a_norm": -0.8377650330744545, + "ref_b_norm": 0.5460309051306146, + "test_a_norm": -0.7824616058562072, + "test_b_norm": 0.5587114375243932, + "Rcs_pct": -3.893819285133399, + "Rhs": -0.0412684152996692, + "Rf_h": 90.6208011427199 + }, + { + "bin": 8, + "ref_a": -23.989228593666184, + "ref_b": 3.0465660195208435, + "test_a": -21.629066745616107, + "test_b": 2.7186861831573466, + "ref_a_norm": -0.9920321024489075, + "ref_b_norm": 0.12598534720673052, + "test_a_norm": -0.8944317852440851, + "test_b_norm": 0.11242645671768148, + "Rcs_pct": -9.837016278886601, + "Rhs": -0.005742517102106452, + "Rf_h": 83.264341821321 + }, + { + "bin": 9, + "ref_a": -15.690397787769538, + "ref_b": -2.5479489319553656, + "test_a": -13.288371599397701, + "test_b": -3.9597529202949038, + "ref_a_norm": -0.9870700658667709, + "ref_b_norm": -0.160289379154604, + "test_a_norm": -0.8359605669209866, + "test_b_norm": -0.24910481102641618, + "Rcs_pct": -13.087894109125935, + "Rhs": 0.11658886906155817, + "Rf_h": 80.27191170096603 + }, + { + "bin": 10, + "ref_a": -17.367668943745457, + "ref_b": -10.621080144130223, + "test_a": -13.52841821883808, + "test_b": -13.392321425898183, + "ref_a_norm": -0.8531177684480347, + "ref_b_norm": -0.5217183849149323, + "test_a_norm": -0.6645298225610875, + "test_b_norm": -0.6578446080592513, + "Rcs_pct": -8.117746873918572, + "Rhs": 0.217958667023116, + "Rf_h": 67.02197129560902 + }, + { + "bin": 11, + "ref_a": -14.313723733011496, + "ref_b": -21.210895387988234, + "test_a": -10.049302225513216, + "test_b": -24.238479529749988, + "ref_a_norm": -0.5593753777451609, + "ref_b_norm": -0.8289144628804943, + "test_a_norm": -0.39272325869384767, + "test_b_norm": -0.9472314050363234, + "Rcs_pct": 0.5789985408581344, + "Rhs": 0.20429954394067373, + "Rf_h": 63.83865706331949 + }, + { + "bin": 12, + "ref_a": -3.7724928617533715, + "ref_b": -20.753752350528693, + "test_a": -1.7775709038976049, + "test_b": -22.25770212522626, + "ref_a_norm": -0.17884337250160073, + "ref_b_norm": -0.983877557479717, + "test_a_norm": -0.08426968239934864, + "test_b_norm": -1.0551756247356807, + "Rcs_pct": 5.147768322954697, + "Rhs": 0.10666604606579912, + "Rf_h": 82.09528234106217 + }, + { + "bin": 13, + "ref_a": 2.885644510037255, + "ref_b": -16.67721559549916, + "test_a": 3.356135021443908, + "test_b": -18.37491491199708, + "ref_a_norm": 0.17049573310895313, + "ref_b_norm": -0.9853584144825885, + "test_a_norm": 0.19829424549814828, + "test_b_norm": -1.0856654649727213, + "Rcs_pct": 10.38028993749634, + "Rhs": 0.007695436987821358, + "Rf_h": 85.4967171491161 + }, + { + "bin": 14, + "ref_a": 14.368652651039472, + "ref_b": -17.32531089936218, + "test_a": 13.399156110802373, + "test_b": -19.177055977902832, + "ref_a_norm": 0.6383706614261523, + "ref_b_norm": -0.769729107303561, + "test_a_norm": 0.595297858243263, + "test_b_norm": -0.8519984584591199, + "Rcs_pct": 4.447449820856929, + "Rhs": -0.08152012955512608, + "Rf_h": 84.08120177153117 + }, + { + "bin": 15, + "ref_a": 12.037122972230456, + "ref_b": -8.367407212708798, + "test_a": 11.124575847901255, + "test_b": -11.886266095679247, + "ref_a_norm": 0.8211048091435319, + "ref_b_norm": -0.5707774455962359, + "test_a_norm": 0.7588559782488548, + "test_b_norm": -0.8108142017355711, + "Rcs_pct": 8.159926525131596, + "Rhs": -0.23416686605088727, + "Rf_h": 72.79538135752526 + }, + { + "bin": 16, + "ref_a": 22.56845229469445, + "ref_b": -3.933055667851942, + "test_a": 20.897572395678278, + "test_b": -5.311870460784217, + "ref_a_norm": 0.9851519533594456, + "ref_b_norm": -0.17168467838473184, + "test_a_norm": 0.9122151575681018, + "test_b_norm": -0.23187232744640268, + "Rcs_pct": -5.97933078750912, + "Rhs": -0.07326042323951996, + "Rf_h": 84.0622552740602 + } + ] + } +} \ No newline at end of file diff --git a/crates/tm30/tests/golden/illuminant_LED_BH1.json b/crates/tm30/tests/golden/illuminant_LED_BH1.json new file mode 100644 index 0000000..b939db5 --- /dev/null +++ b/crates/tm30/tests/golden/illuminant_LED_BH1.json @@ -0,0 +1,403 @@ +{ + "name": "illuminant_LED_BH1", + "source": "colour.SDS_ILLUMINANTS['LED-BH1'] (380.0, 780.0, 5.0)", + "generator": "crates/tm30/tools/golden.py (tm30.py + colour-science 0.4.7, numpy 2.5.1)", + "wavelengths": [ + 380.0, + 385.0, + 390.0, + 395.0, + 400.0, + 405.0, + 410.0, + 415.0, + 420.0, + 425.0, + 430.0, + 435.0, + 440.0, + 445.0, + 450.0, + 455.0, + 460.0, + 465.0, + 470.0, + 475.0, + 480.0, + 485.0, + 490.0, + 495.0, + 500.0, + 505.0, + 510.0, + 515.0, + 520.0, + 525.0, + 530.0, + 535.0, + 540.0, + 545.0, + 550.0, + 555.0, + 560.0, + 565.0, + 570.0, + 575.0, + 580.0, + 585.0, + 590.0, + 595.0, + 600.0, + 605.0, + 610.0, + 615.0, + 620.0, + 625.0, + 630.0, + 635.0, + 640.0, + 645.0, + 650.0, + 655.0, + 660.0, + 665.0, + 670.0, + 675.0, + 680.0, + 685.0, + 690.0, + 695.0, + 700.0, + 705.0, + 710.0, + 715.0, + 720.0, + 725.0, + 730.0, + 735.0, + 740.0, + 745.0, + 750.0, + 755.0, + 760.0, + 765.0, + 770.0, + 775.0, + 780.0 + ], + "values": [ + 0.0, + 0.01, + 0.02, + 0.04, + 0.08, + 0.17, + 0.41, + 0.93, + 1.84, + 3.05, + 4.29, + 5.69, + 7.06, + 7.91, + 7.74, + 6.62, + 5.13, + 3.85, + 2.94, + 2.34, + 1.99, + 1.92, + 2.19, + 2.87, + 4.03, + 5.64, + 7.49, + 9.25, + 10.82, + 12.11, + 13.08, + 13.66, + 14.01, + 14.19, + 14.28, + 14.27, + 14.19, + 14.03, + 13.82, + 13.59, + 13.35, + 13.2, + 13.19, + 13.46, + 14.31, + 16.15, + 19.49, + 25.07, + 33.87, + 40.75, + 35.59, + 21.59, + 11.11, + 7.27, + 5.58, + 4.64, + 3.98, + 3.48, + 3.07, + 2.73, + 2.42, + 2.15, + 1.91, + 1.7, + 1.5, + 1.33, + 1.18, + 1.05, + 0.93, + 0.83, + 0.74, + 0.65, + 0.57, + 0.51, + 0.46, + 0.41, + 0.37, + 0.34, + 0.3, + 0.28, + 0.25 + ], + "expected": { + "Rf": 85.31784179689399, + "Rg": 106.6361658372705, + "CCT_K": 2852.284747502689, + "Duv": -0.000256706396738265, + "bins": [ + { + "bin": 1, + "ref_a": 24.140776024095125, + "ref_b": 5.234806618950599, + "test_a": 23.573737359877473, + "test_b": 4.223572753317501, + "ref_a_norm": 0.97728705740769, + "ref_b_norm": 0.21191981366408003, + "test_a_norm": 0.9543317246115717, + "test_b_norm": 0.17098219973198533, + "Rcs_pct": -3.05007847977746, + "Rhs": -0.035672645892246585, + "Rf_h": 88.86415071710879 + }, + { + "bin": 2, + "ref_a": 20.638242835218424, + "ref_b": 15.118091397173526, + "test_a": 20.00505574827513, + "test_b": 15.257280059398003, + "ref_a_norm": 0.8067146888335136, + "ref_b_norm": 0.5909411229727098, + "test_a_norm": 0.7819644555944127, + "test_b_norm": 0.5963817769679212, + "Rcs_pct": -1.755640142781422, + "Rhs": 0.018274231316007413, + "Rf_h": 92.75084947189922 + }, + { + "bin": 3, + "ref_a": 14.885523157662371, + "ref_b": 22.811800609279544, + "test_a": 13.145214489794041, + "test_b": 24.12092214001679, + "ref_a_norm": 0.5464805642737008, + "ref_b_norm": 0.8374717863134838, + "test_a_norm": 0.4825899738823551, + "test_b_norm": 0.8855325407285467, + "Rcs_pct": 0.44653466489802246, + "Rhs": 0.07982420895194728, + "Rf_h": 84.12080929110567 + }, + { + "bin": 4, + "ref_a": 2.731708079217902, + "ref_b": 20.269495617997322, + "test_a": 0.9088716272519188, + "test_b": 22.020150801726306, + "ref_a_norm": 0.13356194456866122, + "ref_b_norm": 0.9910404668645161, + "test_a_norm": 0.04443764061854087, + "test_b_norm": 1.0766355977596862, + "Rcs_pct": 6.656315529907835, + "Rhs": 0.10411058708981291, + "Rf_h": 82.160360397079 + }, + { + "bin": 5, + "ref_a": -2.9163657689999822, + "ref_b": 16.643356631691354, + "test_a": -4.924413115575524, + "test_b": 18.26037922565339, + "ref_a_norm": -0.17259729496680484, + "ref_b_norm": 0.9849924739662439, + "test_a_norm": -0.29143819752720335, + "test_b_norm": 1.0806916241156281, + "Rcs_pct": 11.704502776281009, + "Rhs": 0.09788742992176025, + "Rf_h": 81.70059359527377 + }, + { + "bin": 6, + "ref_a": -12.789759845180335, + "ref_b": 16.66972610776782, + "test_a": -14.726376818146237, + "test_b": 18.769461128920675, + "ref_a_norm": -0.608720361660172, + "ref_b_norm": 0.7933848506874261, + "test_a_norm": -0.7008923960416674, + "test_b_norm": 0.8933203832493101, + "Rcs_pct": 13.430139713369629, + "Rhs": 0.021117038579974996, + "Rf_h": 79.87518811738217 + }, + { + "bin": 7, + "ref_a": -18.862907066475543, + "ref_b": 12.819040994451226, + "test_a": -19.52499031676473, + "test_b": 16.000634241309534, + "ref_a_norm": -0.8270841905930927, + "ref_b_norm": 0.562078056564183, + "test_a_norm": -0.8561146357541095, + "test_b_norm": 0.7015817643490259, + "Rcs_pct": 10.164204042412464, + "Rhs": -0.09986464264386202, + "Rf_h": 77.9981509736698 + }, + { + "bin": 8, + "ref_a": -21.430640966894444, + "ref_b": 5.387386789324544, + "test_a": -22.079935439156618, + "test_b": 7.75394841439785, + "ref_a_norm": -0.9698251447194983, + "ref_b_norm": 0.24380153541313926, + "test_a_norm": -0.9992084051875348, + "test_b_norm": 0.35089823747024645, + "Rcs_pct": 4.971219944849075, + "Rhs": -0.0993064792107481, + "Rf_h": 83.36910188101163 + }, + { + "bin": 9, + "ref_a": -22.60654944357702, + "ref_b": -4.106743824167885, + "test_a": -22.71003706741167, + "test_b": -2.164085075107313, + "ref_a_norm": -0.9838969990224046, + "ref_b_norm": -0.17873638497716846, + "test_a_norm": -0.9884010549280173, + "test_b_norm": -0.09418672302650856, + "Rcs_pct": -1.2077309041970758, + "Rhs": -0.08380376162128095, + "Rf_h": 86.77115143403682 + }, + { + "bin": 10, + "ref_a": -17.984393328268244, + "ref_b": -12.159891547151208, + "test_a": -17.009879500392845, + "test_b": -11.208606635497745, + "ref_a_norm": -0.8284121179111416, + "ref_b_norm": -0.5601190613592585, + "test_a_norm": -0.7835232495824543, + "test_b_norm": -0.5163001827340298, + "Rcs_pct": -6.166819455442944, + "Rhs": -0.011495146984696248, + "Rf_h": 88.68102435068458 + }, + { + "bin": 11, + "ref_a": -10.724850850023985, + "ref_b": -15.93075988407564, + "test_a": -8.814907794398415, + "test_b": -16.052967310804735, + "ref_a_norm": -0.5584560659842472, + "ref_b_norm": -0.8295340995796363, + "test_a_norm": -0.4590030013203034, + "test_b_norm": -0.8358975893586141, + "Rcs_pct": -4.996211393044294, + "Rhs": 0.08622756661775388, + "Rf_h": 85.58525852513188 + }, + { + "bin": 12, + "ref_a": -6.388784713627041, + "ref_b": -21.195500557943014, + "test_a": -5.646092305839782, + "test_b": -22.296025886440038, + "ref_a_norm": -0.2885964932653947, + "ref_b_norm": -0.9574508154860578, + "test_a_norm": -0.2550473232636165, + "test_b_norm": -1.007164143574347, + "Rcs_pct": 4.221298204982975, + "Rhs": 0.04260312129272747, + "Rf_h": 84.1834946668356 + }, + { + "bin": 13, + "ref_a": 3.4636514496480357, + "ref_b": -17.93773869594088, + "test_a": 2.991494328748695, + "test_b": -19.517841370129513, + "ref_a_norm": 0.18959088814623756, + "ref_b_norm": -0.9818631753619855, + "test_a_norm": 0.16374628767266136, + "test_b_norm": -1.0683537110630041, + "Rcs_pct": 7.9786612880980945, + "Rhs": -0.04222147018364505, + "Rf_h": 85.4817170756592 + }, + { + "bin": 14, + "ref_a": 9.660527074954043, + "ref_b": -13.845797523925203, + "test_a": 9.599959281573414, + "test_b": -15.259592383369144, + "ref_a_norm": 0.5722082220435429, + "ref_b_norm": -0.8201083773659233, + "test_a_norm": 0.5686206963221686, + "test_b_norm": -0.9038496718708681, + "Rcs_pct": 6.763521917475189, + "Rhs": -0.04950708912215173, + "Rf_h": 85.04355420014745 + }, + { + "bin": 15, + "ref_a": 19.093513185395555, + "ref_b": -13.197164519294256, + "test_a": 19.630401646451606, + "test_b": -15.068270923894486, + "ref_a_norm": 0.8226238834213441, + "ref_b_norm": -0.5685859182434848, + "test_a_norm": 0.8457551566715628, + "test_b_norm": -0.6492005647939229, + "Rcs_pct": 6.402004877024328, + "Rhs": -0.0541775820435353, + "Rf_h": 85.05005757762021 + }, + { + "bin": 16, + "ref_a": 17.064179576759663, + "ref_b": -4.0626070029893375, + "test_a": 16.68883111176417, + "test_b": -5.743840998688215, + "ref_a_norm": 0.9728099769121091, + "ref_b_norm": -0.23160472538413757, + "test_a_norm": 0.9514117766690947, + "test_b_norm": -0.32745001329749, + "Rcs_pct": -0.22885517427249466, + "Rhs": -0.098178229357401, + "Rf_h": 86.21741370851278 + } + ] + } +} \ No newline at end of file diff --git a/crates/tm30/tests/golden/illuminant_LED_RGB1.json b/crates/tm30/tests/golden/illuminant_LED_RGB1.json new file mode 100644 index 0000000..32590af --- /dev/null +++ b/crates/tm30/tests/golden/illuminant_LED_RGB1.json @@ -0,0 +1,403 @@ +{ + "name": "illuminant_LED_RGB1", + "source": "colour.SDS_ILLUMINANTS['LED-RGB1'] (380.0, 780.0, 5.0)", + "generator": "crates/tm30/tools/golden.py (tm30.py + colour-science 0.4.7, numpy 2.5.1)", + "wavelengths": [ + 380.0, + 385.0, + 390.0, + 395.0, + 400.0, + 405.0, + 410.0, + 415.0, + 420.0, + 425.0, + 430.0, + 435.0, + 440.0, + 445.0, + 450.0, + 455.0, + 460.0, + 465.0, + 470.0, + 475.0, + 480.0, + 485.0, + 490.0, + 495.0, + 500.0, + 505.0, + 510.0, + 515.0, + 520.0, + 525.0, + 530.0, + 535.0, + 540.0, + 545.0, + 550.0, + 555.0, + 560.0, + 565.0, + 570.0, + 575.0, + 580.0, + 585.0, + 590.0, + 595.0, + 600.0, + 605.0, + 610.0, + 615.0, + 620.0, + 625.0, + 630.0, + 635.0, + 640.0, + 645.0, + 650.0, + 655.0, + 660.0, + 665.0, + 670.0, + 675.0, + 680.0, + 685.0, + 690.0, + 695.0, + 700.0, + 705.0, + 710.0, + 715.0, + 720.0, + 725.0, + 730.0, + 735.0, + 740.0, + 745.0, + 750.0, + 755.0, + 760.0, + 765.0, + 770.0, + 775.0, + 780.0 + ], + "values": [ + 0.0, + 0.0, + 0.0, + 0.01, + 0.02, + 0.05, + 0.11, + 0.24, + 0.5, + 0.94, + 1.6, + 2.43, + 3.38, + 4.59, + 5.84, + 5.56, + 4.0, + 3.14, + 2.8, + 2.68, + 3.03, + 3.98, + 5.53, + 7.84, + 10.96, + 14.61, + 18.01, + 20.24, + 20.57, + 19.22, + 16.93, + 14.58, + 12.61, + 11.09, + 9.93, + 9.11, + 8.6, + 8.31, + 8.21, + 8.24, + 8.42, + 8.74, + 9.25, + 10.0, + 11.1, + 12.74, + 15.35, + 19.43, + 26.01, + 36.47, + 51.1, + 62.69, + 52.07, + 28.62, + 15.5, + 9.58, + 6.54, + 4.95, + 4.01, + 3.37, + 2.89, + 2.51, + 2.18, + 1.92, + 1.67, + 1.44, + 1.25, + 1.09, + 0.93, + 0.82, + 0.71, + 0.61, + 0.53, + 0.45, + 0.4, + 0.35, + 0.3, + 0.27, + 0.24, + 0.21, + 0.17 + ], + "expected": { + "Rf": 71.14146474625642, + "Rg": 106.88363391516455, + "CCT_K": 2839.501992197297, + "Duv": 0.004259448166250124, + "bins": [ + { + "bin": 1, + "ref_a": 24.15549223591464, + "ref_b": 5.253421306217166, + "test_a": 28.15979659135276, + "test_b": 5.797796728447621, + "ref_a_norm": 0.9771576565997636, + "ref_b_norm": 0.2125156797708312, + "test_a_norm": 1.1391430395535622, + "test_b_norm": 0.23453719797058553, + "Rcs_pct": 16.316906431844004, + "Rhs": -0.010003399619911507, + "Rf_h": 68.45520870053508 + }, + { + "bin": 2, + "ref_a": 20.647734472482828, + "ref_b": 15.120694081835282, + "test_a": 25.90334756480809, + "test_b": 14.00297041707985, + "ref_a_norm": 0.8067957148515117, + "ref_b_norm": 0.590830495571478, + "test_a_norm": 1.012155103188108, + "test_b_norm": 0.5471562288225229, + "Rcs_pct": 14.648596844824018, + "Rhs": -0.15040538887227733, + "Rf_h": 62.91053444274136 + }, + { + "bin": 3, + "ref_a": 14.892653886342172, + "ref_b": 22.800058806806234, + "test_a": 21.04905909457535, + "test_b": 20.462950540579012, + "ref_a_norm": 0.5468614791752869, + "ref_b_norm": 0.8372231020428289, + "test_a_norm": 0.7729260130233734, + "test_b_norm": 0.7514039798624691, + "Rcs_pct": 5.423873350000067, + "Rhs": -0.2356443400213043, + "Rf_h": 54.46591642713789 + }, + { + "bin": 4, + "ref_a": 2.733018125633377, + "ref_b": 20.25009336318757, + "test_a": 6.09722633885254, + "test_b": 18.144104277879435, + "ref_a_norm": 0.13375059441725629, + "ref_b_norm": 0.9910150243528252, + "test_a_norm": 0.29839086666470044, + "test_b_norm": 0.8879504711563703, + "Rcs_pct": -6.896447297684185, + "Rhs": -0.1815836524534185, + "Rf_h": 72.64464543955485 + }, + { + "bin": 5, + "ref_a": -2.914146343760383, + "ref_b": 16.622954466084916, + "test_a": -2.5822004622246664, + "test_b": 15.215397431607501, + "ref_a_norm": -0.1726752256310549, + "ref_b_norm": 0.9849788152306953, + "test_a_norm": -0.1530060590107143, + "test_b_norm": 0.9015752383865286, + "Rcs_pct": -8.563826455148941, + "Rhs": -0.003019998435203248, + "Rf_h": 83.30360219504875 + }, + { + "bin": 6, + "ref_a": -12.796032694491096, + "ref_b": 16.639044944547372, + "test_a": -16.05306604508589, + "test_b": 14.957317025145414, + "ref_a_norm": -0.6096140015420448, + "ref_b_norm": 0.7926984099415716, + "test_a_norm": -0.7647818712573818, + "test_b_norm": 0.7125794456556352, + "Rcs_pct": 1.959016536199613, + "Rhs": 0.1735290801316499, + "Rf_h": 74.70655124954557 + }, + { + "bin": 7, + "ref_a": -18.88094603919688, + "ref_b": 12.777599241438015, + "test_a": -23.174708824881307, + "test_b": 10.80271410730602, + "ref_a_norm": -0.828177654305688, + "ref_b_norm": 0.5604656750495325, + "test_a_norm": -1.0165155895241316, + "test_b_norm": 0.47384100409749474, + "Rcs_pct": 10.847118135187104, + "Rhs": 0.1766607321280677, + "Rf_h": 67.638126136616 + }, + { + "bin": 8, + "ref_a": -21.428010684590646, + "ref_b": 5.348385820842016, + "test_a": -26.066066447406342, + "test_b": 5.476283420401191, + "ref_a_norm": -0.9702342331170238, + "ref_b_norm": 0.2421683977892673, + "test_a_norm": -1.1802397507745976, + "test_b_norm": 0.2479594453695749, + "Rcs_pct": 20.710009785926196, + "Rhs": 0.03529026984009941, + "Rf_h": 65.9585508742287 + }, + { + "bin": 9, + "ref_a": -22.61012402199246, + "ref_b": -4.140819544380621, + "test_a": -26.81864387611828, + "test_b": -3.261964532944759, + "ref_a_norm": -0.9836402599896878, + "ref_b_norm": -0.180143939469024, + "test_a_norm": -1.1667294619532642, + "test_b_norm": -0.14190986471998016, + "Rcs_pct": 17.21120963318702, + "Rhs": -0.07321834909244912, + "Rf_h": 69.77974485845012 + }, + { + "bin": 10, + "ref_a": -17.970165353305383, + "ref_b": -12.187688368457072, + "test_a": -22.24716670241688, + "test_b": -9.905866186810657, + "ref_a_norm": -0.8276116812972888, + "ref_b_norm": -0.5613010822903115, + "test_a_norm": -1.0245879588025961, + "test_b_norm": -0.4562123056961396, + "Rcs_pct": 10.539559298996746, + "Rhs": -0.19681228072506224, + "Rf_h": 65.22782235170423 + }, + { + "bin": 11, + "ref_a": -10.70056766872173, + "ref_b": -15.94658819543842, + "test_a": -14.841151034000223, + "test_b": -13.917638770090976, + "ref_a_norm": -0.5572034807010885, + "ref_b_norm": -0.8303759877878163, + "test_a_norm": -0.7728133001698355, + "test_b_norm": -0.7247238656789413, + "Rcs_pct": 3.1939868634758604, + "Rhs": -0.23797018710134404, + "Rf_h": 67.7343699791072 + }, + { + "bin": 12, + "ref_a": -6.356188536881843, + "ref_b": -21.198505062414306, + "test_a": -10.319007440846239, + "test_b": -19.671897350527317, + "ref_a_norm": -0.2872084710551369, + "ref_b_norm": -0.957868098515746, + "test_a_norm": -0.4662709944324489, + "test_b_norm": -0.8888873462476365, + "Rcs_pct": -3.272194110900305, + "Rhs": -0.18907936437322717, + "Rf_h": 69.51920690052688 + }, + { + "bin": 13, + "ref_a": 3.4937583790946296, + "ref_b": -17.92300150910603, + "test_a": 1.696855100956693, + "test_b": -17.135218610635217, + "ref_a_norm": 0.1913303221711864, + "ref_b_norm": -0.9815257041045182, + "test_a_norm": 0.09292566855410225, + "test_b_norm": -0.9383839812345953, + "Rcs_pct": -6.15105623240983, + "Rhs": -0.08809730318379082, + "Rf_h": 86.29758354634869 + }, + { + "bin": 14, + "ref_a": 9.702886637808735, + "ref_b": -13.824627045906851, + "test_a": 10.477669209848212, + "test_b": -11.879119871318665, + "ref_a_norm": 0.5744810480176268, + "ref_b_norm": -0.8185178834140213, + "test_a_norm": 0.6203537785344032, + "test_b_norm": -0.7033297912200841, + "Rcs_pct": -7.028987477591189, + "Rhs": 0.10213685667931231, + "Rf_h": 81.94026033789224 + }, + { + "bin": 15, + "ref_a": 19.120884165337205, + "ref_b": -13.160621882207971, + "test_a": 21.474027587903276, + "test_b": -10.71615016783224, + "ref_a_norm": 0.8237398464857693, + "ref_b_norm": -0.5669679579231981, + "test_a_norm": 0.9251147612074174, + "test_b_norm": -0.46165856232584446, + "Rcs_pct": 2.578339558963718, + "Rhs": 0.14388244732339536, + "Rf_h": 76.2173372757061 + }, + { + "bin": 16, + "ref_a": 17.09058405948216, + "ref_b": -4.044871305697893, + "test_a": 19.74993638510887, + "test_b": -3.1133975903719024, + "ref_a_norm": 0.9731172878570223, + "ref_b_norm": -0.23031010415045408, + "test_a_norm": 1.124537608752044, + "test_b_norm": -0.1772731118268812, + "Rcs_pct": 13.816381797659803, + "Rhs": 0.0815585405510147, + "Rf_h": 77.53804255490721 + } + ] + } +} \ No newline at end of file diff --git a/crates/tm30/tests/golden/illuminant_LED_V1.json b/crates/tm30/tests/golden/illuminant_LED_V1.json new file mode 100644 index 0000000..26f8c53 --- /dev/null +++ b/crates/tm30/tests/golden/illuminant_LED_V1.json @@ -0,0 +1,403 @@ +{ + "name": "illuminant_LED_V1", + "source": "colour.SDS_ILLUMINANTS['LED-V1'] (380.0, 780.0, 5.0)", + "generator": "crates/tm30/tools/golden.py (tm30.py + colour-science 0.4.7, numpy 2.5.1)", + "wavelengths": [ + 380.0, + 385.0, + 390.0, + 395.0, + 400.0, + 405.0, + 410.0, + 415.0, + 420.0, + 425.0, + 430.0, + 435.0, + 440.0, + 445.0, + 450.0, + 455.0, + 460.0, + 465.0, + 470.0, + 475.0, + 480.0, + 485.0, + 490.0, + 495.0, + 500.0, + 505.0, + 510.0, + 515.0, + 520.0, + 525.0, + 530.0, + 535.0, + 540.0, + 545.0, + 550.0, + 555.0, + 560.0, + 565.0, + 570.0, + 575.0, + 580.0, + 585.0, + 590.0, + 595.0, + 600.0, + 605.0, + 610.0, + 615.0, + 620.0, + 625.0, + 630.0, + 635.0, + 640.0, + 645.0, + 650.0, + 655.0, + 660.0, + 665.0, + 670.0, + 675.0, + 680.0, + 685.0, + 690.0, + 695.0, + 700.0, + 705.0, + 710.0, + 715.0, + 720.0, + 725.0, + 730.0, + 735.0, + 740.0, + 745.0, + 750.0, + 755.0, + 760.0, + 765.0, + 770.0, + 775.0, + 780.0 + ], + "values": [ + 0.01, + 0.03, + 0.14, + 0.61, + 2.62, + 8.43, + 16.51, + 17.9, + 11.26, + 5.94, + 3.31, + 2.25, + 2.07, + 2.29, + 2.68, + 3.15, + 3.64, + 4.18, + 4.83, + 5.57, + 6.4, + 7.27, + 8.08, + 8.73, + 9.21, + 9.54, + 9.75, + 9.91, + 10.06, + 10.26, + 10.51, + 10.82, + 11.17, + 11.55, + 11.92, + 12.3, + 12.68, + 13.07, + 13.52, + 14.06, + 14.7, + 15.46, + 16.38, + 17.39, + 18.5, + 19.51, + 20.52, + 21.52, + 22.38, + 23.07, + 23.51, + 23.71, + 23.67, + 23.35, + 22.81, + 22.01, + 21.03, + 19.91, + 18.69, + 17.39, + 16.05, + 14.69, + 13.36, + 12.04, + 10.8, + 9.62, + 8.54, + 7.57, + 6.68, + 5.86, + 5.12, + 4.46, + 3.88, + 3.37, + 2.94, + 2.54, + 2.21, + 1.9, + 1.65, + 1.44, + 1.22 + ], + "expected": { + "Rf": 87.40227499670121, + "Rg": 101.99359743128507, + "CCT_K": 2725.1353468122957, + "Duv": -0.0019451515113612736, + "bins": [ + { + "bin": 1, + "ref_a": 24.291933494347198, + "ref_b": 5.423445269783677, + "test_a": 24.316356953127922, + "test_b": 5.306995830399406, + "ref_a_norm": 0.9759718578923219, + "ref_b_norm": 0.21789660989150272, + "test_a_norm": 0.9769531140137387, + "test_b_norm": 0.21321804547287243, + "Rcs_pct": 0.004965892118745242, + "Rhs": -0.004780100687918423, + "Rf_h": 92.00472391931135 + }, + { + "bin": 2, + "ref_a": 20.73595605343819, + "ref_b": 15.138282542113616, + "test_a": 20.79081247108082, + "test_b": 15.492488241920373, + "ref_a_norm": 0.8076677993055854, + "ref_b_norm": 0.5896377921782767, + "test_a_norm": 0.8098044628865184, + "test_b_norm": 0.603434143662007, + "Rcs_pct": 0.9441413047895768, + "Rhs": 0.010284180335823383, + "Rf_h": 94.22740317966917 + }, + { + "bin": 3, + "ref_a": 14.959219889422693, + "ref_b": 22.68235785007494, + "test_a": 14.931871970718754, + "test_b": 23.275781316609727, + "ref_a_norm": 0.5505566799660914, + "ref_b_norm": 0.8347977851819653, + "test_a_norm": 0.5495501716430023, + "test_b_norm": 0.8566380453000998, + "Rcs_pct": 1.7600326549417213, + "Rhs": 0.012970679488218784, + "Rf_h": 94.18661135104001 + }, + { + "bin": 4, + "ref_a": 2.744614713721124, + "ref_b": 20.06360331086559, + "test_a": 2.2189557831408924, + "test_b": 21.94605544442389, + "ref_a_norm": 0.13553345730619396, + "ref_b_norm": 0.9907727700894036, + "test_a_norm": 0.1095755799147903, + "test_b_norm": 1.0837312624413837, + "Rcs_pct": 8.610819032815435, + "Rhs": 0.043594406263082135, + "Rf_h": 85.81803015210764 + }, + { + "bin": 5, + "ref_a": -2.8927957442201673, + "ref_b": 16.427970836569386, + "test_a": -3.491568227466292, + "test_b": 17.679609127010657, + "ref_a_norm": -0.17342149278649568, + "ref_b_norm": 0.9848476967733149, + "test_a_norm": -0.2093175694768369, + "test_b_norm": 1.0598827147799448, + "Rcs_pct": 8.059621833632828, + "Rhs": 0.020567737816712804, + "Rf_h": 90.08465676928014 + }, + { + "bin": 6, + "ref_a": -12.481443190115826, + "ref_b": 16.686258036496433, + "test_a": -13.286636142437564, + "test_b": 17.62174889047256, + "ref_a_norm": -0.5989782841072364, + "ref_b_norm": 0.8007652684575868, + "test_a_norm": -0.6376190955591402, + "test_b_norm": 0.8456590117513407, + "Rcs_pct": 5.879546795366832, + "Rhs": 0.007187033094137112, + "Rf_h": 91.63060583663557 + }, + { + "bin": 7, + "ref_a": -17.606404368111182, + "ref_b": 13.143623062282316, + "test_a": -18.346737191806415, + "test_b": 15.112938046394666, + "ref_a_norm": -0.8013345965627797, + "ref_b_norm": 0.598216402609931, + "test_a_norm": -0.8350299662813413, + "test_b_norm": 0.6878474365964579, + "Rcs_pct": 7.781301043396587, + "Rhs": -0.05580533667283079, + "Rf_h": 85.47539104405307 + }, + { + "bin": 8, + "ref_a": -21.39957451581042, + "ref_b": 4.982722730823428, + "test_a": -22.384538301883957, + "test_b": 6.478953612666154, + "ref_a_norm": -0.9739469661879827, + "ref_b_norm": 0.22677589610279195, + "test_a_norm": -1.0187750766974977, + "test_b_norm": 0.2948730223802723, + "Rcs_pct": 5.725184122986823, + "Rhs": -0.05804312857603689, + "Rf_h": 87.82182376464858 + }, + { + "bin": 9, + "ref_a": -24.033542076050725, + "ref_b": -4.195071635834407, + "test_a": -25.06008665608581, + "test_b": -1.9552794112068899, + "ref_a_norm": -0.9851055280098112, + "ref_b_norm": -0.17195086124969214, + "test_a_norm": -1.0271823362198162, + "test_b_norm": -0.08014451430790466, + "Rcs_pct": 2.335778435072505, + "Rhs": -0.09825109179119804, + "Rf_h": 83.34371506935615 + }, + { + "bin": 10, + "ref_a": -17.392050616646547, + "ref_b": -11.63952140921492, + "test_a": -18.841841860347134, + "test_b": -8.94038591085631, + "ref_a_norm": -0.8310604855190737, + "ref_b_norm": -0.5561820470033185, + "test_a_norm": -0.9003372051796004, + "test_b_norm": -0.42720675207169734, + "Rcs_pct": -1.4053347421202473, + "Rhs": -0.14572712175803398, + "Rf_h": 79.25365871633241 + }, + { + "bin": 11, + "ref_a": -10.472589979545097, + "ref_b": -16.088915092995304, + "test_a": -12.253571916076185, + "test_b": -13.471208933325693, + "ref_a_norm": -0.5455300283525646, + "ref_b_norm": -0.8380912767507187, + "test_a_norm": -0.638303556985776, + "test_b_norm": -0.701731759354118, + "Rcs_pct": -6.183658414270978, + "Rhs": -0.15289565873906533, + "Rf_h": 78.67404841595159 + }, + { + "bin": 12, + "ref_a": -6.045794361430085, + "ref_b": -21.22131411563845, + "test_a": -7.732734135177502, + "test_b": -19.711551901005393, + "ref_a_norm": -0.2739904060985276, + "ref_b_norm": -0.9617324250361761, + "test_a_norm": -0.35044112308313274, + "test_b_norm": -0.8933112486662813, + "Rcs_pct": -5.219168765657565, + "Rhs": -0.08833004722549909, + "Rf_h": 84.20107133486145 + }, + { + "bin": 13, + "ref_a": 3.7795521158976357, + "ref_b": -17.77949134268055, + "test_a": 3.057598977501098, + "test_b": -17.92258669034859, + "ref_a_norm": 0.20793298604156615, + "ref_b_norm": -0.9781430740519701, + "test_a_norm": 0.16821455717867442, + "test_b_norm": -0.9860154996772496, + "Rcs_pct": -0.002752190249293503, + "Rhs": -0.04049108443975082, + "Rf_h": 93.41621022317837 + }, + { + "bin": 14, + "ref_a": 10.098275474531759, + "ref_b": -13.621743908509181, + "test_a": 9.46891721879173, + "test_b": -12.235471057150162, + "ref_a_norm": 0.5955357549396535, + "ref_b_norm": -0.8033288022898576, + "test_a_norm": 0.5584199776066906, + "test_b_norm": -0.721574739314593, + "Rcs_pct": -8.859644010777899, + "Rhs": 0.014559482828120671, + "Rf_h": 86.92319847697603 + }, + { + "bin": 15, + "ref_a": 19.375625526566203, + "ref_b": -12.816727310606495, + "test_a": 19.396926339699657, + "test_b": -13.718326675861016, + "ref_a_norm": 0.8340387274707728, + "ref_b_norm": -0.5517059008918918, + "test_a_norm": 0.8349556373819166, + "test_b_norm": -0.5905159401473626, + "Rcs_pct": 2.2324085280996906, + "Rhs": -0.03175996044020077, + "Rf_h": 92.65137595186246 + }, + { + "bin": 16, + "ref_a": 17.335351150569675, + "ref_b": -3.878218920081843, + "test_a": 16.437054724224215, + "test_b": -1.7062694369933484, + "ref_a_norm": 0.9758770911949222, + "ref_b_norm": -0.21832064236104093, + "test_a_norm": 0.9253083489780105, + "test_b_norm": -0.09605281372758045, + "Rcs_pct": -7.345034807516706, + "Rhs": 0.11005301438751473, + "Rf_h": 82.92767045128039 + } + ] + } +} \ No newline at end of file diff --git a/crates/tm30/tests/golden/illuminant_LED_V2.json b/crates/tm30/tests/golden/illuminant_LED_V2.json new file mode 100644 index 0000000..f264e74 --- /dev/null +++ b/crates/tm30/tests/golden/illuminant_LED_V2.json @@ -0,0 +1,403 @@ +{ + "name": "illuminant_LED_V2", + "source": "colour.SDS_ILLUMINANTS['LED-V2'] (380.0, 780.0, 5.0)", + "generator": "crates/tm30/tools/golden.py (tm30.py + colour-science 0.4.7, numpy 2.5.1)", + "wavelengths": [ + 380.0, + 385.0, + 390.0, + 395.0, + 400.0, + 405.0, + 410.0, + 415.0, + 420.0, + 425.0, + 430.0, + 435.0, + 440.0, + 445.0, + 450.0, + 455.0, + 460.0, + 465.0, + 470.0, + 475.0, + 480.0, + 485.0, + 490.0, + 495.0, + 500.0, + 505.0, + 510.0, + 515.0, + 520.0, + 525.0, + 530.0, + 535.0, + 540.0, + 545.0, + 550.0, + 555.0, + 560.0, + 565.0, + 570.0, + 575.0, + 580.0, + 585.0, + 590.0, + 595.0, + 600.0, + 605.0, + 610.0, + 615.0, + 620.0, + 625.0, + 630.0, + 635.0, + 640.0, + 645.0, + 650.0, + 655.0, + 660.0, + 665.0, + 670.0, + 675.0, + 680.0, + 685.0, + 690.0, + 695.0, + 700.0, + 705.0, + 710.0, + 715.0, + 720.0, + 725.0, + 730.0, + 735.0, + 740.0, + 745.0, + 750.0, + 755.0, + 760.0, + 765.0, + 770.0, + 775.0, + 780.0 + ], + "values": [ + 0.01, + 0.06, + 0.26, + 1.15, + 4.47, + 11.98, + 19.89, + 20.24, + 14.39, + 8.95, + 5.78, + 4.65, + 4.86, + 5.78, + 6.97, + 8.1, + 9.05, + 9.82, + 10.52, + 11.21, + 11.87, + 12.5, + 12.98, + 13.23, + 13.3, + 13.21, + 13.05, + 12.88, + 12.74, + 12.68, + 12.7, + 12.77, + 12.91, + 13.04, + 13.16, + 13.26, + 13.35, + 13.42, + 13.52, + 13.64, + 13.83, + 14.07, + 14.42, + 14.82, + 15.26, + 15.64, + 16.03, + 16.4, + 16.67, + 16.88, + 16.93, + 16.85, + 16.62, + 16.23, + 15.72, + 15.07, + 14.31, + 13.45, + 12.57, + 11.64, + 10.69, + 9.78, + 8.87, + 8.0, + 7.17, + 6.37, + 5.65, + 5.01, + 4.42, + 3.88, + 3.39, + 2.95, + 2.58, + 2.24, + 1.95, + 1.7, + 1.47, + 1.3, + 1.1, + 0.96, + 0.84 + ], + "expected": { + "Rf": 94.13034422268701, + "Rg": 99.35726071554775, + "CCT_K": 4072.0031708244155, + "Duv": 0.0009839134171622573, + "bins": [ + { + "bin": 1, + "ref_a": 21.5060867171481, + "ref_b": 5.007649330915021, + "test_a": 21.557581923302045, + "test_b": 5.208036801982339, + "ref_a_norm": 0.973945705154785, + "ref_b_norm": 0.2267813118635409, + "test_a_norm": 0.9762777674927324, + "test_b_norm": 0.23585625512865963, + "Rcs_pct": 0.40576860179117874, + "Rhs": 0.008445607982451024, + "Rf_h": 96.38391861015214 + }, + { + "bin": 2, + "ref_a": 20.630920648407702, + "ref_b": 14.380110712747545, + "test_a": 21.036284334360513, + "test_b": 14.393706475244537, + "ref_a_norm": 0.8203798075987003, + "ref_b_norm": 0.5718190022063968, + "test_a_norm": 0.836498922608487, + "test_b_norm": 0.5723596319345374, + "Rcs_pct": 1.37029120918879, + "Rhs": -0.008505783291600615, + "Rf_h": 96.61477906598672 + }, + { + "bin": 3, + "ref_a": 14.622294834728901, + "ref_b": 22.303904625594615, + "test_a": 15.127811319217063, + "test_b": 22.10561841543097, + "ref_a_norm": 0.5482726226863643, + "ref_b_norm": 0.8362996659168385, + "test_a_norm": 0.5672272978515265, + "test_b_norm": 0.8288647932297719, + "Rcs_pct": 0.434878258768598, + "Rhs": -0.01989083036212275, + "Rf_h": 95.69314220880628 + }, + { + "bin": 4, + "ref_a": 3.769770709177344, + "ref_b": 22.127817724956213, + "test_a": 4.219662830874597, + "test_b": 22.165617201936684, + "ref_a_norm": 0.1679436790236388, + "ref_b_norm": 0.9857965919377105, + "test_a_norm": 0.18798642005763544, + "test_b_norm": 0.987480562587123, + "Rcs_pct": 0.5561758427983128, + "Rhs": -0.019329099008818133, + "Rf_h": 95.18000601010866 + }, + { + "bin": 5, + "ref_a": -2.217523432762202, + "ref_b": 19.124082564681437, + "test_a": -2.10661583016451, + "test_b": 19.284154879390456, + "ref_a_norm": -0.11518274385686728, + "ref_b_norm": 0.9933443187120985, + "test_a_norm": -0.10942197407511271, + "test_b_norm": 1.0016588051122437, + "Rcs_pct": 0.7030855443592059, + "Rhs": -0.007272154034939679, + "Rf_h": 95.81532579603898 + }, + { + "bin": 6, + "ref_a": -11.157340095902983, + "ref_b": 17.152251674891072, + "test_a": -11.33149120032817, + "test_b": 17.00371406149607, + "ref_a_norm": -0.5452761023870739, + "ref_b_norm": 0.8382565073803849, + "test_a_norm": -0.5537871305202254, + "test_b_norm": 0.8309972493319863, + "Rcs_pct": -0.13073785919348146, + "Rhs": 0.011109688947665881, + "Rf_h": 96.96149806443553 + }, + { + "bin": 7, + "ref_a": -18.237593596836113, + "ref_b": 11.222035534667716, + "test_a": -18.664431924418686, + "test_b": 11.310144313459473, + "ref_a_norm": -0.8516812234756594, + "ref_b_norm": 0.5240602003386672, + "test_a_norm": -0.8716142364102659, + "test_b_norm": 0.5281748107515961, + "Rcs_pct": 1.885964960265469, + "Rhs": 0.007653015116047939, + "Rf_h": 96.48888368661963 + }, + { + "bin": 8, + "ref_a": -22.806196021133083, + "ref_b": 3.54697595002376, + "test_a": -23.33073606006459, + "test_b": 3.7733062482550697, + "ref_a_norm": -0.988120775782414, + "ref_b_norm": 0.15367931697909307, + "test_a_norm": -1.0108474466273745, + "test_b_norm": 0.1634854972672986, + "Rcs_pct": 2.4203075107480765, + "Rhs": -0.005184003750154394, + "Rf_h": 95.66959381950386 + }, + { + "bin": 9, + "ref_a": -19.359967811921063, + "ref_b": -2.1647198155949408, + "test_a": -19.99812391779566, + "test_b": -1.5967133632439834, + "ref_a_norm": -0.9938068017864939, + "ref_b_norm": -0.11112173830038952, + "test_a_norm": -1.0265653210557895, + "test_b_norm": -0.0819642168990673, + "Rcs_pct": 2.644072326775447, + "Rhs": -0.03498813787647739, + "Rf_h": 94.02468783317269 + }, + { + "bin": 10, + "ref_a": -20.12481056130306, + "ref_b": -11.305332729571061, + "test_a": -21.109820983356716, + "test_b": -10.460363966002118, + "ref_a_norm": -0.8718507259643083, + "ref_b_norm": -0.48977169337917903, + "test_a_norm": -0.9145235277247978, + "test_b_norm": -0.45316580197509876, + "Rcs_pct": 1.5143994318402398, + "Rhs": -0.054144424751414046, + "Rf_h": 91.08164683152931 + }, + { + "bin": 11, + "ref_a": -12.0299229068276, + "ref_b": -17.37361268314809, + "test_a": -13.395555882028669, + "test_b": -16.174749123322908, + "ref_a_norm": -0.5692751459445191, + "ref_b_norm": -0.8221470721287321, + "test_a_norm": -0.6338990772269889, + "test_b_norm": -0.7654149356659371, + "Rcs_pct": -1.1267914948570674, + "Rhs": -0.0852515213632363, + "Rf_h": 87.63501102287803 + }, + { + "bin": 12, + "ref_a": -5.321142286273294, + "ref_b": -23.68114067834624, + "test_a": -6.619848530473959, + "test_b": -22.884465322297572, + "ref_a_norm": -0.21923319531172367, + "ref_b_norm": -0.9756724891444933, + "test_a_norm": -0.27274041319271836, + "test_b_norm": -0.9428491451074037, + "Rcs_pct": -2.175391231859829, + "Rhs": -0.058882608450850145, + "Rf_h": 89.51290258211499 + }, + { + "bin": 13, + "ref_a": 3.7226296360305824, + "ref_b": -15.335302892174731, + "test_a": 2.9233589985441455, + "test_b": -14.868166402903348, + "ref_a_norm": 0.23589810067345363, + "ref_b_norm": -0.9717777966688975, + "test_a_norm": 0.18524938088618065, + "test_b_norm": -0.9421759771626502, + "Rcs_pct": -3.8914103897884287, + "Rhs": -0.043900490338888085, + "Rf_h": 93.24110412552977 + }, + { + "bin": 14, + "ref_a": 14.076555709238233, + "ref_b": -18.560229885620448, + "test_a": 13.888209363138756, + "test_b": -18.077244948739335, + "ref_a_norm": 0.6042878763662225, + "ref_b_norm": -0.7967660650886187, + "test_a_norm": 0.5962024174047597, + "test_b_norm": -0.7760321620051238, + "Rcs_pct": -2.1731650677642342, + "Rhs": 0.0047963259395274686, + "Rf_h": 95.91225919335012 + }, + { + "bin": 15, + "ref_a": 15.444352398883035, + "ref_b": -11.008382636531257, + "test_a": 15.035474112391139, + "test_b": -10.290067980568562, + "ref_a_norm": 0.8143140573366874, + "ref_b_norm": -0.5804245136310683, + "test_a_norm": 0.7927556696600264, + "test_b_norm": -0.5425508814557436, + "Rcs_pct": -3.896660689632505, + "Rhs": 0.01951357579625696, + "Rf_h": 93.84954376149082 + }, + { + "bin": 16, + "ref_a": 20.116352896451094, + "ref_b": -3.5647524053199855, + "test_a": 19.769486951738866, + "test_b": -2.604852923991758, + "ref_a_norm": 0.9846592625997848, + "ref_b_norm": -0.17448821328802738, + "test_a_norm": 0.9676807990035543, + "test_b_norm": -0.12750286160326374, + "Rcs_pct": -2.5818614569266516, + "Rhs": 0.04277020739665758, + "Rf_h": 92.45699411917165 + } + ] + } +} \ No newline at end of file diff --git a/crates/tm30/tests/golden/irregular_grid_FL11.json b/crates/tm30/tests/golden/irregular_grid_FL11.json new file mode 100644 index 0000000..7042f85 --- /dev/null +++ b/crates/tm30/tests/golden/irregular_grid_FL11.json @@ -0,0 +1,725 @@ +{ + "name": "irregular_grid_FL11", + "source": "FL11 linearly resampled on 242 random wavelengths 371-802 nm", + "generator": "crates/tm30/tools/golden.py (tm30.py + colour-science 0.4.7, numpy 2.5.1)", + "wavelengths": [ + 371.3, + 372.9504299008177, + 373.2058235432587, + 376.75918502565406, + 378.08281655531016, + 387.61860585499056, + 389.5711781607729, + 395.47811691210933, + 399.09085032146936, + 399.1668677102434, + 399.858430991484, + 401.49187544695565, + 401.52574932915405, + 401.7045117444466, + 403.4241530886501, + 403.8147549201823, + 404.3734124078725, + 404.88909196827336, + 410.54958639281483, + 419.36206720877726, + 420.23750508615274, + 420.3210426758975, + 421.0164959126884, + 422.778614736642, + 424.9212547517555, + 426.2680756552127, + 426.38295810165465, + 429.94636403328406, + 430.03475333875576, + 430.8631685140244, + 430.9115063531931, + 431.9166496648927, + 432.4791267262809, + 433.4153914201698, + 437.586303689894, + 442.7937017540068, + 444.0429543828449, + 451.0364619832037, + 451.1395600295637, + 453.1969317344829, + 460.9467581170085, + 461.97404988161156, + 462.95533170350683, + 465.7493690695069, + 467.1377478130718, + 468.90120580590457, + 470.93919824425257, + 470.94404633098907, + 472.2268729101304, + 475.1391683899389, + 476.12263269325035, + 477.7457231166851, + 478.4378788441262, + 478.53469875542794, + 481.95625626997133, + 486.0678745122259, + 486.63971420626626, + 487.2482652499527, + 488.5136577705397, + 488.7008857005593, + 492.0340407869246, + 494.07213771525073, + 495.2191529590522, + 497.9257865018447, + 501.1509145435751, + 504.718621213073, + 509.7101054993036, + 513.1611274899385, + 519.1829606026839, + 521.9127837910586, + 528.3150354523273, + 531.6682901606104, + 532.6770852106112, + 534.3693550583184, + 537.3762224213162, + 538.1696284149767, + 538.3901544351032, + 543.1375670317677, + 545.115536206241, + 547.5756627961905, + 548.2616040955212, + 549.6971139960992, + 550.598005265101, + 551.1449133162538, + 551.6664833845444, + 552.183738160428, + 554.6578312185911, + 559.0982398775617, + 559.8502542014201, + 560.0608359770372, + 560.3531855222863, + 562.1816475148237, + 563.91607892094, + 565.6933193147017, + 566.2620243107182, + 567.6104431045709, + 567.6311260078608, + 567.8055803299711, + 568.9456104573702, + 574.1010000098895, + 576.6003890813972, + 578.6516385722188, + 578.9761080483956, + 585.5329387560205, + 586.6224846469131, + 586.931800663485, + 590.4269551928875, + 590.9081661291888, + 591.4028868026352, + 594.4582570794829, + 596.5777731800044, + 598.8814451830968, + 599.8385460080918, + 600.0541244655792, + 600.8346429710026, + 602.4148583700207, + 605.1319142898639, + 608.0921472841856, + 608.6091835565767, + 608.9062173522493, + 608.9832168550242, + 609.1565276454867, + 610.1796300191984, + 610.5790923893072, + 612.3710186745159, + 616.0902367578576, + 617.7237032623264, + 619.8182038390822, + 620.2245123140096, + 621.596462764196, + 622.1205761759152, + 622.3217210902766, + 622.730762136432, + 624.5335888609615, + 625.1853218721221, + 625.8954032232227, + 626.105152380921, + 626.9366480160973, + 638.2780430730476, + 639.4340773926688, + 641.5898515990751, + 641.6894813817698, + 642.412510846948, + 644.6182290239494, + 648.3460108360891, + 650.3081462648961, + 650.4306827647507, + 650.713663002283, + 653.8600333346312, + 654.1367128563472, + 655.8387805758991, + 658.332341123019, + 659.0059304932754, + 660.8337397037441, + 665.4052557028617, + 669.5535397074433, + 670.5541359128842, + 670.8413630910087, + 671.0642482763017, + 671.7210592750607, + 673.6497151523331, + 678.0357195369772, + 680.1030273709496, + 681.4013398193317, + 684.3013406866214, + 684.8326782180138, + 685.6442823315845, + 685.7572811758837, + 686.115205232604, + 687.6871908441477, + 691.4025574279735, + 692.9791096034353, + 696.5272125819374, + 696.623065990856, + 703.4894151159467, + 703.6240376483363, + 703.8201967916989, + 703.8432734369869, + 704.3182795082396, + 705.7714316944893, + 705.9031568603323, + 707.5388217281156, + 707.9405842490481, + 711.8373683117082, + 712.6366132542089, + 713.64564053455, + 713.8631349375546, + 713.8691161544749, + 716.4040867773415, + 716.693013996249, + 718.1493016249794, + 718.188631425209, + 722.6130551321405, + 724.2152821551273, + 724.3578676015433, + 725.0465925064889, + 726.679809773023, + 727.5278878819435, + 732.7616384812284, + 733.8331133723198, + 736.5330075868198, + 738.4231267075122, + 739.2978467827945, + 739.5074612577816, + 740.2300597007898, + 743.0840691544008, + 743.1956423514264, + 743.2581599055206, + 743.6390733564888, + 745.7791691009413, + 751.0440152203769, + 751.1692297136415, + 751.3696813153622, + 751.4268564953088, + 751.8706076894669, + 752.1972891782683, + 754.7053913004863, + 755.661532988286, + 757.3566731576427, + 761.0436020771874, + 762.082330568681, + 762.8071654666967, + 762.9669489976877, + 763.5258560958436, + 765.4819285198992, + 768.892406435308, + 770.9929547735538, + 771.1026904097172, + 774.8270294170727, + 776.8395609352353, + 777.0787054004427, + 777.1045461788945, + 779.3722728354419, + 782.4526339827135, + 784.9835687548078, + 785.7303946301881, + 788.7439594726859, + 793.8272347634781, + 794.117869948665, + 794.3997398048172, + 796.8069085217464, + 801.7 + ], + "values": [ + 0.91, + 0.91, + 0.91, + 0.91, + 0.91, + 0.5409674009303209, + 0.4745799425337218, + 0.4579735118281164, + 1.1227164591503624, + 1.1367036586847898, + 1.263951302433056, + 4.688492268164962, + 4.765656971812932, + 5.1728777538494, + 9.090220735944898, + 9.980011708175237, + 11.252633465133506, + 12.427351503726719, + 1.6119834557125934, + 2.374517005976153, + 2.5013258849905764, + 2.515861425606165, + 2.636870288807784, + 2.9434789641757075, + 3.3162983268054567, + 3.6241935520093524, + 3.650846279583879, + 4.477556455721901, + 4.694697165271446, + 9.5740625476036, + 9.8587724203073, + 15.779066526218013, + 19.09205641779464, + 24.60665546480002, + 22.658543304682333, + 9.235724982848952, + 7.941499259372658, + 7.175489532235148, + 7.1740461595861085, + 7.145242955717239, + 6.608282542192994, + 6.487062113969835, + 6.371270858986194, + 6.029584544686077, + 5.8435417930483755, + 5.607238422008788, + 5.334147435270157, + 5.333497791647465, + 5.1615990300425265, + 4.814215299849369, + 4.985338088625562, + 5.267755822303207, + 5.388190918877959, + 5.405037583444462, + 9.036498321970523, + 14.43309518463827, + 14.509721703639679, + 14.59126754349366, + 14.760830141252317, + 14.785918683874947, + 12.523219137264322, + 10.081579017129624, + 8.783719984805611, + 6.483081473432007, + 4.1698628481711095, + 2.4644990601511094, + 1.5198618541197795, + 1.2360765657445505, + 0.9243156546872754, + 0.8670465945072969, + 1.0620524816629084, + 2.4212078794941037, + 3.1717513966946984, + 4.4308001633889145, + 21.38623115909209, + 26.89088194310854, + 28.42089147074619, + 60.45482076125541, + 71.91039568458477, + 52.11621714185124, + 46.59713344743648, + 35.04702078738557, + 29.609209579722926, + 26.864824979038474, + 24.247586376355954, + 21.65200191097233, + 9.237002945109722, + 3.675850994847129, + 2.970461559067986, + 2.8194145399955297, + 2.768545719122192, + 2.4503933324206795, + 2.148602267756443, + 1.9197874797472991, + 1.8868025899783458, + 1.8085942999348883, + 1.807394691544076, + 1.797276340861675, + 1.7311545934725279, + 3.9337520054590054, + 6.622533041514197, + 9.432744843939698, + 9.877268026302033, + 14.543626865055684, + 14.101271233353279, + 13.975688930625099, + 12.47468079465329, + 12.186916654745115, + 11.891073692024163, + 10.063962266469222, + 8.979513327237859, + 7.869143421747321, + 7.407820824099733, + 7.355871494546861, + 7.728959340139247, + 8.484302300869913, + 10.921739180659742, + 37.88946175893043, + 42.59966220041357, + 45.30564007899125, + 46.00710554927082, + 47.58596685038363, + 54.8140990112745, + 53.800263515938276, + 49.2523546040787, + 36.16940786379725, + 26.564624817521043, + 14.248961426196487, + 13.179101950743961, + 13.173614148943216, + 13.17151769529634, + 13.170713115638893, + 13.169076951454272, + 13.161865644556155, + 13.126642063018016, + 12.998827419819909, + 12.961072571434215, + 12.811403357102495, + 3.1169498115870775, + 2.4140809452573886, + 2.155851986350057, + 2.161231994615571, + 2.200275585735189, + 2.319384367293269, + 3.1698106873501057, + 3.544871325801845, + 3.5309021648184187, + 3.4986424177397315, + 3.13995619985204, + 3.1084147343764155, + 2.9210892589546913, + 2.6567718409599883, + 2.5853713677128076, + 2.423305700145403, + 2.0913693156565936, + 1.593575235106805, + 1.5167262916588615, + 1.5046627501776346, + 1.49530157239533, + 1.4677155104474495, + 1.3867119636020098, + 1.4089287079614081, + 1.4698906276111592, + 1.5945286226558455, + 1.8729287059156559, + 1.9239371089293271, + 1.9477313879790135, + 1.9490873741106043, + 1.9533824627912482, + 1.9722462901297726, + 1.7755908115242347, + 1.5233424634503536, + 1.2458163774581226, + 1.2486919797256815, + 3.2691783137706922, + 3.3432207065849635, + 3.45110823543439, + 3.4638003903428056, + 3.725053729531771, + 4.328343781568818, + 4.367334430658353, + 4.851491231522228, + 4.970412937718246, + 4.451855856611137, + 3.9611194619157377, + 3.3415767117862925, + 3.208035148341472, + 3.2043626811524053, + 1.9652143303915015, + 1.8531105694554015, + 1.2880709695079755, + 1.2728110070189094, + 0.41321669207156897, + 0.317083070692363, + 0.3085279439074043, + 0.269627259948089, + 0.2565615218158164, + 0.24977689694445235, + 0.21895344607508652, + 0.21466754651072095, + 0.2191980455209191, + 0.23053876024507325, + 0.23578708069676713, + 0.23704476754668985, + 0.24, + 0.24, + 0.24, + 0.24, + 0.24, + 0.23376664719246945, + 0.20835212176301504, + 0.20935383770913177, + 0.2109574505228975, + 0.2114148519624705, + 0.21496486151573482, + 0.21757831342614645, + 0.2376431304038906, + 0.2505845278125762, + 0.2777067705222835, + 0.30747677507375104, + 0.29501203317582847, + 0.28631401439963977, + 0.28439661202774735, + 0.2776897268498774, + 0.2503614296020169, + 0.18215187129384047, + 0.15205636181156934, + 0.15117847672226253, + 0.12138376466341833, + 0.10896263438858796, + 0.10752776759734388, + 0.10737272292663329, + 0.09376636298734865, + 0.09, + 0.09, + 0.09, + 0.09, + 0.09, + 0.09, + 0.09, + 0.09, + 0.09 + ], + "expected": { + "Rf": 80.08402265614828, + "Rg": 100.46420953966124, + "CCT_K": 4033.9621179352316, + "Duv": 0.0014197711913853366, + "bins": [ + { + "bin": 1, + "ref_a": 21.52118049843812, + "ref_b": 5.032043903438641, + "test_a": 19.875652040941773, + "test_b": 3.861818357769575, + "ref_a_norm": 0.9737366285342227, + "ref_b_norm": 0.22767735559516064, + "test_a_norm": 0.899283866406425, + "test_b_norm": 0.17472991260767604, + "Rcs_pct": -8.335170688266608, + "Rhs": -0.03740505937861187, + "Rf_h": 81.3611044794709 + }, + { + "bin": 2, + "ref_a": 20.628124786139086, + "ref_b": 14.402242814341895, + "test_a": 20.49267229234165, + "test_b": 14.199917740839185, + "ref_a_norm": 0.8199305374874851, + "ref_b_norm": 0.5724630238674667, + "test_a_norm": 0.8145465465918135, + "test_b_norm": 0.564420969246208, + "Rcs_pct": -0.8944550982553693, + "Rhs": -0.003695538961570137, + "Rf_h": 92.62911964514306 + }, + { + "bin": 3, + "ref_a": 14.618926698489487, + "ref_b": 22.31358444454619, + "test_a": 12.155858196351945, + "test_b": 23.02357361052235, + "ref_a_norm": 0.5480179092643133, + "ref_b_norm": 0.8364665989300295, + "test_a_norm": 0.4556851629036882, + "test_b_norm": 0.8630818755753917, + "Rcs_pct": -2.9167531657267993, + "Rhs": 0.09155852826704322, + "Rf_h": 80.92138995077234 + }, + { + "bin": 4, + "ref_a": 3.7520881885548776, + "ref_b": 22.131437658133944, + "test_a": 0.24510190244750069, + "test_b": 23.84727162022984, + "ref_a_norm": 0.16715140749984644, + "ref_b_norm": 0.9859312384597723, + "test_a_norm": 0.010919020533674908, + "test_b_norm": 1.062369756796099, + "Rcs_pct": 4.449034695752298, + "Rhs": 0.16814284061535226, + "Rf_h": 72.65283898154053 + }, + { + "bin": 5, + "ref_a": -2.224562066998667, + "ref_b": 19.11874775652138, + "test_a": -4.702960328093524, + "test_b": 20.905375225029335, + "ref_a_norm": -0.11557528190418888, + "ref_b_norm": 0.9932987235533766, + "test_a_norm": -0.24433841328462752, + "test_b_norm": 1.0861214756778728, + "Rcs_pct": 11.615962973503837, + "Rhs": 0.10818016331417031, + "Rf_h": 75.59923381392525 + }, + { + "bin": 6, + "ref_a": -11.168404959756822, + "ref_b": 17.132569815077623, + "test_a": -12.288235621035236, + "test_b": 18.69189854515506, + "ref_a_norm": -0.5460958944508755, + "ref_b_norm": 0.8377226713321648, + "test_a_norm": -0.600851692508691, + "test_b_norm": 0.9139683859765527, + "Rcs_pct": 9.381668628125455, + "Rhs": 0.0031679327307197426, + "Rf_h": 85.82578875583691 + }, + { + "bin": 7, + "ref_a": -18.246606034399527, + "ref_b": 11.190364969189984, + "test_a": -17.028661479288967, + "test_b": 13.034520628921637, + "ref_a_norm": -0.8524563216307074, + "ref_b_norm": 0.5227984503724583, + "test_a_norm": -0.7955556282391617, + "test_b_norm": 0.6089548647349734, + "Rcs_pct": 0.05547417295014111, + "Rhs": -0.10324877193389595, + "Rf_h": 83.00169246242548 + }, + { + "bin": 8, + "ref_a": -22.82456785237659, + "ref_b": 3.507181808526478, + "test_a": -21.63991069467708, + "test_b": 5.017564587087921, + "ref_a_norm": -0.9883996020299787, + "ref_b_norm": 0.15187569491850886, + "test_a_norm": -0.9370989740932163, + "test_b_norm": 0.21728160958460493, + "Rcs_pct": -3.755483980185119, + "Rhs": -0.0741574143796294, + "Rf_h": 85.33166065112488 + }, + { + "bin": 9, + "ref_a": -19.360915219717157, + "ref_b": -2.198108324622839, + "test_a": -17.99612151574314, + "test_b": -1.1342347582645769, + "ref_a_norm": -0.9936167398686655, + "ref_b_norm": -0.11280857348962796, + "test_a_norm": -0.9235744998533325, + "test_b_norm": -0.058209781405624945, + "Rcs_pct": -7.93480939428685, + "Rhs": -0.03988512844446431, + "Rf_h": 87.61595711108521 + }, + { + "bin": 10, + "ref_a": -20.10558195316891, + "ref_b": -11.341741347552945, + "test_a": -15.52805828709372, + "test_b": -12.3529545944959, + "ref_a_norm": -0.8709760389785688, + "ref_b_norm": -0.491325492443861, + "test_a_norm": -0.6726772063312285, + "test_b_norm": -0.5351313623976135, + "Rcs_pct": -14.054221612349872, + "Rhs": 0.1465921783684203, + "Rf_h": 67.48644961844725 + }, + { + "bin": 11, + "ref_a": -11.99274199580292, + "ref_b": -17.393305446239598, + "test_a": -8.413008517799293, + "test_b": -18.415444269782636, + "ref_a_norm": -0.5676482368791935, + "ref_b_norm": -0.8232712063275036, + "test_a_norm": -0.3982099718020887, + "test_b_norm": -0.8716517435918786, + "Rcs_pct": -5.390790984912549, + "Rhs": 0.1677615549344586, + "Rf_h": 73.67499586333705 + }, + { + "bin": 12, + "ref_a": -7.9371892138337845, + "ref_b": -24.360929234164896, + "test_a": -4.6512576257552105, + "test_b": -25.72399585202873, + "ref_a_norm": -0.3097880315391565, + "ref_b_norm": -0.9508056455002224, + "test_a_norm": -0.18153831353205432, + "test_b_norm": -1.0040060560018154, + "Rcs_pct": 2.7157900746888446, + "Rhs": 0.1361643208533769, + "Rf_h": 74.63408810225636 + }, + { + "bin": 13, + "ref_a": 3.3315090028219907, + "ref_b": -17.984068881310172, + "test_a": 3.2473466311976047, + "test_b": -19.648941933384325, + "ref_a_norm": 0.18214877564676776, + "ref_b_norm": -0.9832709817392067, + "test_a_norm": 0.17754723534358244, + "test_b_norm": -1.0742971767114338, + "Rcs_pct": 8.837943618035625, + "Rhs": -0.02227145268558106, + "Rf_h": 82.3491833157033 + }, + { + "bin": 14, + "ref_a": 10.315243897932653, + "ref_b": -14.479133053472603, + "test_a": 13.140544620690243, + "test_b": -14.6899239820823, + "ref_a_norm": 0.5802323151008204, + "ref_b_norm": -0.8144510178720032, + "test_a_norm": 0.7391554385327547, + "test_b_norm": -0.8263080044560983, + "Rcs_pct": 9.815168075543665, + "Rhs": 0.12555235902642392, + "Rf_h": 80.60852157645995 + }, + { + "bin": 15, + "ref_a": 15.488426190478814, + "ref_b": -10.977235282075705, + "test_a": 15.050570570742625, + "test_b": -12.946757895600088, + "ref_a_norm": 0.8158687481007793, + "ref_b_norm": -0.5782371363657538, + "test_a_norm": 0.7928042538823379, + "test_b_norm": -0.6819837617033303, + "Rcs_pct": 3.846111074803298, + "Rhs": -0.09907611277455092, + "Rf_h": 82.55473847657916 + }, + { + "bin": 16, + "ref_a": 20.14195778368154, + "ref_b": -3.5311523424250546, + "test_a": 20.11559673947661, + "test_b": -5.638109970619553, + "ref_a_norm": 0.9849780286861712, + "ref_b_norm": -0.1726797122000848, + "test_a_norm": 0.9836889261255395, + "test_b_norm": -0.27571373666942733, + "Rcs_pct": 1.8836608195944, + "Rhs": -0.10130574601390284, + "Rf_h": 80.88596355611779 + } + ] + } +} \ No newline at end of file diff --git a/crates/tm30/tests/golden/lamp_L0001.json b/crates/tm30/tests/golden/lamp_L0001.json new file mode 100644 index 0000000..5aeb0de --- /dev/null +++ b/crates/tm30/tests/golden/lamp_L0001.json @@ -0,0 +1,941 @@ +{ + "name": "lamp_L0001", + "source": "L0001/spd.csv", + "generator": "crates/tm30/tools/golden.py (tm30.py + colour-science 0.4.7, numpy 2.5.1)", + "wavelengths": [ + 380.0, + 381.92, + 383.84, + 385.76, + 387.68, + 389.6, + 391.52, + 393.44, + 395.36, + 397.28, + 399.2, + 401.12, + 403.04, + 404.96, + 406.88, + 408.8, + 410.72, + 412.64, + 414.56, + 416.48, + 418.4, + 420.32, + 422.23, + 424.15, + 426.07, + 427.99, + 429.91, + 431.83, + 433.75, + 435.67, + 437.59, + 439.51, + 441.43, + 443.35, + 445.27, + 447.19, + 449.11, + 451.03, + 452.95, + 454.87, + 456.79, + 458.71, + 460.63, + 462.55, + 464.47, + 466.39, + 468.31, + 470.23, + 472.15, + 474.07, + 475.99, + 477.91, + 479.83, + 481.75, + 483.67, + 485.59, + 487.51, + 489.43, + 491.35, + 493.27, + 495.19, + 497.11, + 499.03, + 500.95, + 502.87, + 504.79, + 506.7, + 508.62, + 510.54, + 512.46, + 514.38, + 516.3, + 518.22, + 520.14, + 522.06, + 523.98, + 525.9, + 527.82, + 529.74, + 531.66, + 533.58, + 535.5, + 537.42, + 539.34, + 541.26, + 543.18, + 545.1, + 547.02, + 548.94, + 550.86, + 552.78, + 554.7, + 556.62, + 558.54, + 560.46, + 562.38, + 564.3, + 566.22, + 568.14, + 570.06, + 571.98, + 573.9, + 575.82, + 577.74, + 579.66, + 581.58, + 583.5, + 585.42, + 587.34, + 589.26, + 591.17, + 593.09, + 595.01, + 596.93, + 598.85, + 600.77, + 602.69, + 604.61, + 606.53, + 608.45, + 610.37, + 612.29, + 614.21, + 616.13, + 618.05, + 619.97, + 621.89, + 623.81, + 625.73, + 627.65, + 629.57, + 631.49, + 633.41, + 635.33, + 637.25, + 639.17, + 641.09, + 643.01, + 644.93, + 646.85, + 648.77, + 650.69, + 652.61, + 654.53, + 656.45, + 658.37, + 660.29, + 662.21, + 664.13, + 666.05, + 667.97, + 669.89, + 671.81, + 673.72, + 675.64, + 677.56, + 679.48, + 681.4, + 683.32, + 685.24, + 687.16, + 689.08, + 691.0, + 692.92, + 694.84, + 696.76, + 698.68, + 700.6, + 702.52, + 704.44, + 706.36, + 708.28, + 710.2, + 712.12, + 714.04, + 715.96, + 717.88, + 719.8, + 721.72, + 723.64, + 725.56, + 727.48, + 729.4, + 731.32, + 733.24, + 735.16, + 737.08, + 739.0, + 740.92, + 742.84, + 744.76, + 746.68, + 748.6, + 750.52, + 752.44, + 754.36, + 756.28, + 758.19, + 760.11, + 762.03, + 763.95, + 765.87, + 767.79, + 769.71, + 771.63, + 773.55, + 775.47, + 777.39, + 779.31, + 781.23, + 783.15, + 785.07, + 786.99, + 788.91, + 790.83, + 792.75, + 794.67, + 796.59, + 798.51, + 800.43, + 802.35, + 804.27, + 806.19, + 808.11, + 810.03, + 811.95, + 813.87, + 815.79, + 817.71, + 819.63, + 821.55, + 823.47, + 825.39, + 827.31, + 829.23, + 831.15, + 833.07, + 834.99, + 836.91, + 838.83, + 840.74, + 842.66, + 844.58, + 846.5, + 848.42, + 850.34, + 852.26, + 854.18, + 856.1, + 858.02, + 859.94, + 861.86, + 863.78, + 865.7, + 867.62, + 869.54, + 871.46, + 873.38, + 875.3, + 877.22, + 879.14, + 881.06, + 882.98, + 884.9, + 886.82, + 888.74, + 890.66, + 892.58, + 894.5, + 896.42, + 898.34, + 900.26, + 902.18, + 904.1, + 906.02, + 907.94, + 909.86, + 911.78, + 913.7, + 915.62, + 917.54, + 919.46, + 921.38, + 923.3, + 925.21, + 927.13, + 929.05, + 930.97, + 932.89, + 934.81, + 936.73, + 938.65, + 940.57, + 942.49, + 944.41, + 946.33, + 948.25, + 950.17, + 952.09, + 954.01, + 955.93, + 957.85, + 959.77, + 961.69, + 963.61, + 965.53, + 967.45, + 969.37, + 971.29, + 973.21, + 975.13, + 977.05, + 978.97, + 980.89, + 982.81, + 984.73, + 986.65, + 988.57, + 990.49, + 992.41, + 994.33, + 996.25, + 998.17, + 1000.09, + 1002.01, + 1003.93, + 1005.85, + 1007.77, + 1009.68, + 1011.6, + 1013.52, + 1015.44, + 1017.36, + 1019.28, + 1021.2, + 1023.12, + 1025.04, + 1026.96, + 1028.88, + 1030.8, + 1032.72, + 1034.64, + 1036.56, + 1038.48, + 1040.4, + 1042.32, + 1044.24, + 1046.16, + 1048.08, + 1050.0 + ], + "values": [ + 0.173954, + 0.266255, + 0.36761, + 0.475484, + 0.588793, + 0.711825, + 0.859452, + 1.02066, + 1.17508, + 1.33937, + 1.51489, + 1.7049, + 1.91109, + 2.13056, + 2.36004, + 2.59258, + 2.83133, + 3.07465, + 3.32401, + 3.58211, + 3.84338, + 4.10513, + 4.36389, + 4.61194, + 4.84417, + 5.06707, + 5.27714, + 5.48244, + 5.68101, + 5.86675, + 6.04176, + 6.19296, + 6.31636, + 6.41876, + 6.49622, + 6.54376, + 6.55781, + 6.52994, + 6.45722, + 6.33781, + 6.17428, + 5.97071, + 5.73037, + 5.45992, + 5.16722, + 4.86511, + 4.56307, + 4.27054, + 3.99017, + 3.72361, + 3.47269, + 3.23981, + 3.02713, + 2.83346, + 2.65746, + 2.49517, + 2.34634, + 2.21013, + 2.08613, + 1.97317, + 1.86921, + 1.77487, + 1.69002, + 1.61577, + 1.55214, + 1.49715, + 1.44736, + 1.40751, + 1.37707, + 1.35754, + 1.34825, + 1.34778, + 1.35726, + 1.37632, + 1.40814, + 1.45304, + 1.50707, + 1.57352, + 1.65211, + 1.74205, + 1.84199, + 1.95239, + 2.07322, + 2.20528, + 2.34857, + 2.50144, + 2.66389, + 2.83537, + 3.01512, + 3.20287, + 3.39768, + 3.59574, + 3.79758, + 4.00148, + 4.20716, + 4.41504, + 4.62188, + 4.82736, + 5.03069, + 5.23103, + 5.42729, + 5.61932, + 5.80546, + 5.98719, + 6.16375, + 6.33542, + 6.50026, + 6.65556, + 6.80347, + 6.94454, + 7.0826, + 7.21254, + 7.34254, + 7.47942, + 7.61179, + 7.73903, + 7.86399, + 7.99002, + 8.11767, + 8.24569, + 8.37502, + 8.50726, + 8.64522, + 8.78531, + 8.9269, + 9.06876, + 9.21281, + 9.36286, + 9.5166, + 9.67051, + 9.82156, + 9.97156, + 10.1237, + 10.2823, + 10.4464, + 10.6113, + 10.7764, + 10.9416, + 11.1085, + 11.2778, + 11.4481, + 11.618, + 11.7879, + 11.9598, + 12.134, + 12.308, + 12.4815, + 12.6531, + 12.825, + 12.9982, + 13.1738, + 13.3506, + 13.5258, + 13.6995, + 13.8731, + 14.0475, + 14.2227, + 14.4001, + 14.5677, + 14.7326, + 14.9057, + 15.0711, + 15.2247, + 15.3673, + 15.4972, + 15.6169, + 15.7289, + 15.8361, + 15.939, + 16.0379, + 16.1292, + 16.2064, + 16.2694, + 16.3198, + 16.3591, + 16.3888, + 16.4081, + 16.4141, + 16.4101, + 16.3969, + 16.3724, + 16.3378, + 16.2935, + 16.2589, + 16.2205, + 16.1564, + 16.0838, + 16.0027, + 15.9111, + 15.811, + 15.7016, + 15.5826, + 15.4552, + 15.3185, + 15.1741, + 15.0211, + 14.8595, + 14.6916, + 14.519, + 14.3478, + 14.1758, + 14.0016, + 13.8249, + 13.6746, + 13.5225, + 13.3341, + 13.1394, + 12.9419, + 12.7423, + 12.5413, + 12.3383, + 12.1338, + 11.9285, + 11.7237, + 11.5191, + 11.314, + 11.1091, + 10.906, + 10.705, + 10.5061, + 10.3087, + 10.1423, + 9.97381, + 9.77352, + 9.57275, + 9.37371, + 9.17485, + 8.97375, + 8.77104, + 8.56603, + 8.36264, + 8.16237, + 7.96558, + 7.77154, + 7.57926, + 7.38733, + 7.22354, + 7.06244, + 6.87544, + 6.68959, + 6.50539, + 6.32182, + 6.1418, + 5.96715, + 5.7978, + 5.63467, + 5.47532, + 5.31959, + 5.16722, + 5.01664, + 4.88891, + 4.76312, + 4.61919, + 4.48082, + 4.34759, + 4.21797, + 4.09113, + 3.96696, + 3.8455, + 3.72647, + 3.60996, + 3.49657, + 3.38756, + 3.29712, + 3.20885, + 3.10628, + 3.00287, + 2.89988, + 2.79898, + 2.70299, + 2.61084, + 2.52174, + 2.43512, + 2.3494, + 2.26465, + 2.18032, + 2.1076, + 2.03671, + 1.95905, + 1.88515, + 1.81499, + 1.74591, + 1.67679, + 1.60838, + 1.54088, + 1.47626, + 1.41434, + 1.36356, + 1.31493, + 1.26002, + 1.20649, + 1.15499, + 1.10544, + 1.05814, + 1.01309, + 0.970437, + 0.931136, + 0.894492, + 0.859432, + 0.828634, + 0.796794, + 0.759111, + 0.720384, + 0.682213, + 0.64496, + 0.609387, + 0.577019, + 0.547821, + 0.521528, + 0.500481, + 0.479917, + 0.45703, + 0.435907, + 0.416153, + 0.397855, + 0.380334, + 0.363872, + 0.348588, + 0.33412, + 0.321791, + 0.309198, + 0.294714, + 0.280217, + 0.26571, + 0.251674, + 0.237682, + 0.223798, + 0.210622, + 0.197621, + 0.186491, + 0.175749, + 0.163828, + 0.152451, + 0.141729, + 0.132162, + 0.123236, + 0.115076, + 0.107027, + 0.09876, + 0.0916038, + 0.083752, + 0.0751364, + 0.0668978, + 0.0590985, + 0.0523388, + 0.0449385, + 0.0377408, + 0.0302384, + 0.0237588, + 0.0181567 + ], + "expected": { + "Rf": 72.38329929879201, + "Rg": 119.8372775942548, + "CCT_K": 2158.0397133551915, + "Duv": -0.052023715296819206, + "bins": [ + { + "bin": 1, + "ref_a": 26.115062257912303, + "ref_b": 5.276522593470199, + "test_a": 25.719846321713124, + "test_b": 5.386075429177029, + "ref_a_norm": 0.9801925377316355, + "ref_b_norm": 0.19804693629343573, + "test_a_norm": 0.9653586572825209, + "test_b_norm": 0.20215884960180394, + "Rcs_pct": -1.3746657104320956, + "Rhs": 0.006926850560708237, + "Rf_h": 88.65535678247258 + }, + { + "bin": 2, + "ref_a": 20.001104831141127, + "ref_b": 13.328858198674363, + "test_a": 17.44270802833978, + "test_b": 16.010158145625503, + "ref_a_norm": 0.832150357775343, + "ref_b_norm": 0.5545500717287563, + "test_a_norm": 0.7257076970945344, + "test_b_norm": 0.6661061447055059, + "Rcs_pct": -2.652660435027867, + "Rhs": 0.1518918585456357, + "Rf_h": 72.49090164831904 + }, + { + "bin": 3, + "ref_a": 15.807069588084772, + "ref_b": 23.32498729841534, + "test_a": 10.136866993234957, + "test_b": 29.98875779883528, + "ref_a_norm": 0.5610007078844208, + "ref_b_norm": 0.8278153210427908, + "test_a_norm": 0.3597624168885599, + "test_b_norm": 1.064315827799139, + "Rcs_pct": 8.484098044101925, + "Rhs": 0.2987161654426336, + "Rf_h": 41.08216605395147 + }, + { + "bin": 4, + "ref_a": 3.1499026365111904, + "ref_b": 19.02391709005675, + "test_a": -1.4649383267174183, + "test_b": 25.18181917776837, + "ref_a_norm": 0.16335188588758906, + "ref_b_norm": 0.9865678696252823, + "test_a_norm": -0.07597074131895924, + "test_b_norm": 1.305912635231418, + "Rcs_pct": 26.651911707284654, + "Rhs": 0.29702518318787835, + "Rf_h": 48.19472777800929 + }, + { + "bin": 5, + "ref_a": -2.4468221137436132, + "ref_b": 14.887824770388088, + "test_a": -5.047654700950897, + "test_b": 19.394216308614574, + "ref_a_norm": -0.16217487777119435, + "ref_b_norm": 0.986762032619769, + "test_a_norm": -0.3345575387601235, + "test_b_norm": 1.2854447577741825, + "Rcs_pct": 32.65738091844998, + "Rhs": 0.11080026746365267, + "Rf_h": 64.54133666924353 + }, + { + "bin": 6, + "ref_a": -10.943217205796538, + "ref_b": 14.235561158561461, + "test_a": -12.611601170313463, + "test_b": 19.659770713595467, + "ref_a_norm": -0.6094583022885663, + "ref_b_norm": 0.7928181240180743, + "test_a_norm": -0.7023752607531535, + "test_b_norm": 1.0949074899238678, + "Rcs_pct": 30.28000242160553, + "Rhs": -0.09057423197814342, + "Rf_h": 61.64837462087425 + }, + { + "bin": 7, + "ref_a": -18.90915422946678, + "ref_b": 12.055087069208147, + "test_a": -20.482336359458117, + "test_b": 18.063919995052053, + "ref_a_norm": -0.8432170660454256, + "ref_b_norm": 0.5375732317831164, + "test_a_norm": -0.9133700725685415, + "test_b_norm": 0.8055254843588323, + "Rcs_pct": 20.719638853725094, + "Rhs": -0.183819233383651, + "Rf_h": 57.8574595144496 + }, + { + "bin": 8, + "ref_a": -17.661483695468846, + "ref_b": 3.685335895179641, + "test_a": -16.725533291715532, + "test_b": 7.6327811870748805, + "ref_a_norm": -0.9789155170010111, + "ref_b_norm": 0.20426553937128855, + "test_a_norm": -0.9270389935347215, + "test_b_norm": 0.4230589043783418, + "Rcs_pct": -0.8195262580011178, + "Rhs": -0.2247099195169248, + "Rf_h": 71.57056525086124 + }, + { + "bin": 9, + "ref_a": -25.243112953400587, + "ref_b": -5.365667651317104, + "test_a": -25.767642232793097, + "test_b": -2.718067468750532, + "ref_a_norm": -0.9781469832574565, + "ref_b_norm": -0.20791459579437155, + "test_a_norm": -0.9984720015392796, + "test_b_norm": -0.10532256856579195, + "Rcs_pct": -0.008023287357238581, + "Rhs": -0.10458596455410286, + "Rf_h": 79.04825164549948 + }, + { + "bin": 10, + "ref_a": -18.873803780173787, + "ref_b": -13.50137709515617, + "test_a": -18.936780631333907, + "test_b": -12.59575557108608, + "ref_a_norm": -0.8133238278652302, + "ref_b_norm": -0.5818112675315334, + "test_a_norm": -0.8160376726338322, + "test_b_norm": -0.5427855590345763, + "Rcs_pct": -1.942504250581066, + "Rhs": -0.033956422084268384, + "Rf_h": 88.58537160888947 + }, + { + "bin": 11, + "ref_a": -11.50556084240589, + "ref_b": -16.973809199291978, + "test_a": -10.200724333124539, + "test_b": -17.398996378304986, + "ref_a_norm": -0.5610879263957349, + "ref_b_norm": -0.8277562073780748, + "test_a_norm": -0.4974553906761611, + "test_b_norm": -0.8484911716158176, + "Rcs_pct": -1.811185002148857, + "Rhs": 0.06442824871779783, + "Rf_h": 79.37819124595464 + }, + { + "bin": 12, + "ref_a": -5.525064160174467, + "ref_b": -20.201334502962833, + "test_a": -3.338377037898077, + "test_b": -20.810182377844825, + "ref_a_norm": -0.2638110526161154, + "ref_b_norm": -0.9645743768717772, + "test_a_norm": -0.1594010014843974, + "test_b_norm": -0.9936456770592905, + "Rcs_pct": 0.8143312809089416, + "Rhs": 0.10807537059114716, + "Rf_h": 74.10816069805898 + }, + { + "bin": 13, + "ref_a": 2.70831577332035, + "ref_b": -13.072432148511325, + "test_a": 4.2461019077599484, + "test_b": -14.51614908734479, + "ref_a_norm": 0.20286955093154918, + "ref_b_norm": -0.9792057727080818, + "test_a_norm": 0.31805921441013774, + "test_b_norm": -1.0873490734039022, + "Rcs_pct": 12.853774603764831, + "Rhs": 0.09187861503776662, + "Rf_h": 81.85913770820962 + }, + { + "bin": 14, + "ref_a": 13.218131407837134, + "ref_b": -19.8831282429124, + "test_a": 16.439957328312744, + "test_b": -22.715525312093334, + "ref_a_norm": 0.5536185378172014, + "ref_b_norm": -0.8327703852714408, + "test_a_norm": 0.6885591357097082, + "test_b_norm": -0.9514004302888444, + "Rcs_pct": 17.36062569529985, + "Rhs": 0.046291684860111544, + "Rf_h": 70.94303420179887 + }, + { + "bin": 15, + "ref_a": 16.26971401755112, + "ref_b": -10.574958459083005, + "test_a": 17.721350521095495, + "test_b": -12.657216526577917, + "ref_a_norm": 0.8384519912054851, + "ref_b_norm": -0.5449754659097575, + "test_a_norm": 0.9132613895508008, + "test_b_norm": -0.6522836472958234, + "Rcs_pct": 12.181897277633274, + "Rhs": -0.0476616171032001, + "Rf_h": 82.10427690792586 + }, + { + "bin": 16, + "ref_a": 18.30330409719438, + "ref_b": -3.2805078148339084, + "test_a": 18.567596206910952, + "test_b": -3.368866845236011, + "ref_a_norm": 0.9843151329296822, + "ref_b_norm": -0.1764191573656947, + "test_a_norm": 0.9985282346585558, + "test_b_norm": -0.18117092952081695, + "Rcs_pct": 1.4867025724443015, + "Rhs": -0.0018876295924399051, + "Rf_h": 91.79390516084133 + } + ] + } +} \ No newline at end of file diff --git a/crates/tm30/tests/golden/lamp_L0002.json b/crates/tm30/tests/golden/lamp_L0002.json new file mode 100644 index 0000000..e7ddabc --- /dev/null +++ b/crates/tm30/tests/golden/lamp_L0002.json @@ -0,0 +1,941 @@ +{ + "name": "lamp_L0002", + "source": "L0002/spd.csv", + "generator": "crates/tm30/tools/golden.py (tm30.py + colour-science 0.4.7, numpy 2.5.1)", + "wavelengths": [ + 380.0, + 381.92, + 383.84, + 385.76, + 387.68, + 389.6, + 391.52, + 393.44, + 395.36, + 397.28, + 399.2, + 401.12, + 403.04, + 404.96, + 406.88, + 408.8, + 410.72, + 412.64, + 414.56, + 416.48, + 418.4, + 420.32, + 422.23, + 424.15, + 426.07, + 427.99, + 429.91, + 431.83, + 433.75, + 435.67, + 437.59, + 439.51, + 441.43, + 443.35, + 445.27, + 447.19, + 449.11, + 451.03, + 452.95, + 454.87, + 456.79, + 458.71, + 460.63, + 462.55, + 464.47, + 466.39, + 468.31, + 470.23, + 472.15, + 474.07, + 475.99, + 477.91, + 479.83, + 481.75, + 483.67, + 485.59, + 487.51, + 489.43, + 491.35, + 493.27, + 495.19, + 497.11, + 499.03, + 500.95, + 502.87, + 504.79, + 506.7, + 508.62, + 510.54, + 512.46, + 514.38, + 516.3, + 518.22, + 520.14, + 522.06, + 523.98, + 525.9, + 527.82, + 529.74, + 531.66, + 533.58, + 535.5, + 537.42, + 539.34, + 541.26, + 543.18, + 545.1, + 547.02, + 548.94, + 550.86, + 552.78, + 554.7, + 556.62, + 558.54, + 560.46, + 562.38, + 564.3, + 566.22, + 568.14, + 570.06, + 571.98, + 573.9, + 575.82, + 577.74, + 579.66, + 581.58, + 583.5, + 585.42, + 587.34, + 589.26, + 591.17, + 593.09, + 595.01, + 596.93, + 598.85, + 600.77, + 602.69, + 604.61, + 606.53, + 608.45, + 610.37, + 612.29, + 614.21, + 616.13, + 618.05, + 619.97, + 621.89, + 623.81, + 625.73, + 627.65, + 629.57, + 631.49, + 633.41, + 635.33, + 637.25, + 639.17, + 641.09, + 643.01, + 644.93, + 646.85, + 648.77, + 650.69, + 652.61, + 654.53, + 656.45, + 658.37, + 660.29, + 662.21, + 664.13, + 666.05, + 667.97, + 669.89, + 671.81, + 673.72, + 675.64, + 677.56, + 679.48, + 681.4, + 683.32, + 685.24, + 687.16, + 689.08, + 691.0, + 692.92, + 694.84, + 696.76, + 698.68, + 700.6, + 702.52, + 704.44, + 706.36, + 708.28, + 710.2, + 712.12, + 714.04, + 715.96, + 717.88, + 719.8, + 721.72, + 723.64, + 725.56, + 727.48, + 729.4, + 731.32, + 733.24, + 735.16, + 737.08, + 739.0, + 740.92, + 742.84, + 744.76, + 746.68, + 748.6, + 750.52, + 752.44, + 754.36, + 756.28, + 758.19, + 760.11, + 762.03, + 763.95, + 765.87, + 767.79, + 769.71, + 771.63, + 773.55, + 775.47, + 777.39, + 779.31, + 781.23, + 783.15, + 785.07, + 786.99, + 788.91, + 790.83, + 792.75, + 794.67, + 796.59, + 798.51, + 800.43, + 802.35, + 804.27, + 806.19, + 808.11, + 810.03, + 811.95, + 813.87, + 815.79, + 817.71, + 819.63, + 821.55, + 823.47, + 825.39, + 827.31, + 829.23, + 831.15, + 833.07, + 834.99, + 836.91, + 838.83, + 840.74, + 842.66, + 844.58, + 846.5, + 848.42, + 850.34, + 852.26, + 854.18, + 856.1, + 858.02, + 859.94, + 861.86, + 863.78, + 865.7, + 867.62, + 869.54, + 871.46, + 873.38, + 875.3, + 877.22, + 879.14, + 881.06, + 882.98, + 884.9, + 886.82, + 888.74, + 890.66, + 892.58, + 894.5, + 896.42, + 898.34, + 900.26, + 902.18, + 904.1, + 906.02, + 907.94, + 909.86, + 911.78, + 913.7, + 915.62, + 917.54, + 919.46, + 921.38, + 923.3, + 925.21, + 927.13, + 929.05, + 930.97, + 932.89, + 934.81, + 936.73, + 938.65, + 940.57, + 942.49, + 944.41, + 946.33, + 948.25, + 950.17, + 952.09, + 954.01, + 955.93, + 957.85, + 959.77, + 961.69, + 963.61, + 965.53, + 967.45, + 969.37, + 971.29, + 973.21, + 975.13, + 977.05, + 978.97, + 980.89, + 982.81, + 984.73, + 986.65, + 988.57, + 990.49, + 992.41, + 994.33, + 996.25, + 998.17, + 1000.09, + 1002.01, + 1003.93, + 1005.85, + 1007.77, + 1009.68, + 1011.6, + 1013.52, + 1015.44, + 1017.36, + 1019.28, + 1021.2, + 1023.12, + 1025.04, + 1026.96, + 1028.88, + 1030.8, + 1032.72, + 1034.64, + 1036.56, + 1038.48, + 1040.4, + 1042.32, + 1044.24, + 1046.16, + 1048.08, + 1050.0 + ], + "values": [ + 0.0, + 0.00173501, + 0.0141204, + 0.0431285, + 0.0896217, + 0.153065, + 0.237699, + 0.33388, + 0.429872, + 0.5368, + 0.656583, + 0.792128, + 0.944333, + 1.11338, + 1.29868, + 1.49927, + 1.72128, + 1.96704, + 2.2412, + 2.54845, + 2.88773, + 3.25844, + 3.65909, + 4.08734, + 4.54137, + 5.03432, + 5.5693, + 6.15379, + 6.78897, + 7.46713, + 8.25135, + 9.05817, + 9.79608, + 10.5172, + 11.1984, + 11.804, + 12.3017, + 12.6559, + 12.8447, + 12.8561, + 12.6927, + 12.3737, + 11.926, + 11.3915, + 10.8135, + 10.2387, + 9.6982, + 9.21543, + 8.79008, + 8.41625, + 8.0863, + 7.79117, + 7.52402, + 7.26948, + 7.01693, + 6.76108, + 6.50316, + 6.25056, + 6.00731, + 5.77813, + 5.56901, + 5.38952, + 5.24793, + 5.14759, + 5.08957, + 5.07014, + 5.07401, + 5.10707, + 5.16223, + 5.23684, + 5.32855, + 5.4361, + 5.55854, + 5.69466, + 5.85579, + 6.03218, + 6.20971, + 6.39986, + 6.60353, + 6.81771, + 7.04014, + 7.26931, + 7.50152, + 7.73838, + 7.97752, + 8.21664, + 8.45502, + 8.69153, + 8.92768, + 9.1621, + 9.39251, + 9.61036, + 9.81719, + 10.0144, + 10.2057, + 10.3923, + 10.5715, + 10.7409, + 10.9012, + 11.054, + 11.1971, + 11.3311, + 11.4555, + 11.5699, + 11.6751, + 11.7757, + 11.868, + 11.9501, + 12.025, + 12.0917, + 12.1579, + 12.2342, + 12.3131, + 12.3858, + 12.4543, + 12.519, + 12.5843, + 12.6557, + 12.733, + 12.8128, + 12.8962, + 12.9859, + 13.0877, + 13.196, + 13.3089, + 13.4217, + 13.5343, + 13.6533, + 13.7792, + 13.9085, + 14.0371, + 14.1654, + 14.2981, + 14.4401, + 14.5902, + 14.7431, + 14.8958, + 15.0501, + 15.2079, + 15.3699, + 15.5344, + 15.6991, + 15.8655, + 16.0361, + 16.2129, + 16.3927, + 16.5744, + 16.7573, + 16.9429, + 17.134, + 17.3343, + 17.5423, + 17.7542, + 17.9709, + 18.1922, + 18.4198, + 18.6546, + 18.8971, + 19.1303, + 19.365, + 19.6174, + 19.8673, + 20.1106, + 20.3499, + 20.5817, + 20.8033, + 21.0174, + 21.2286, + 21.4406, + 21.656, + 21.8704, + 22.075, + 22.2691, + 22.4514, + 22.6232, + 22.7861, + 22.9394, + 23.0784, + 23.2059, + 23.3219, + 23.4253, + 23.5184, + 23.6003, + 23.6792, + 23.7495, + 23.7977, + 23.83, + 23.8465, + 23.8461, + 23.8342, + 23.8118, + 23.7772, + 23.7325, + 23.6737, + 23.6013, + 23.5111, + 23.4046, + 23.2846, + 23.1523, + 23.0176, + 22.875, + 22.7215, + 22.5615, + 22.4284, + 22.2887, + 22.1026, + 21.9021, + 21.6894, + 21.4686, + 21.245, + 21.0154, + 20.7765, + 20.5285, + 20.2719, + 20.0097, + 19.7456, + 19.4773, + 19.2068, + 18.9344, + 18.6603, + 18.3832, + 18.1464, + 17.9037, + 17.6097, + 17.3126, + 17.0157, + 16.716, + 16.4111, + 16.1023, + 15.7891, + 15.4751, + 15.1615, + 14.8479, + 14.5354, + 14.2229, + 13.9097, + 13.6421, + 13.3748, + 13.0609, + 12.7476, + 12.4371, + 12.1282, + 11.8251, + 11.527, + 11.2328, + 10.9435, + 10.6552, + 10.3699, + 10.0906, + 9.81625, + 9.58554, + 9.36005, + 9.10208, + 8.85099, + 8.60601, + 8.36604, + 8.1315, + 7.90436, + 7.68357, + 7.46703, + 7.25444, + 7.0467, + 6.84745, + 6.68252, + 6.5201, + 6.33238, + 6.14523, + 5.95994, + 5.7806, + 5.6072, + 5.43784, + 5.27123, + 5.10482, + 4.9396, + 4.7759, + 4.6152, + 4.48006, + 4.34852, + 4.20145, + 4.05864, + 3.91894, + 3.78205, + 3.64734, + 3.51549, + 3.38588, + 3.2588, + 3.13455, + 3.03038, + 2.92902, + 2.81429, + 2.70332, + 2.59597, + 2.49249, + 2.39306, + 2.29647, + 2.20318, + 2.11317, + 2.02782, + 1.94608, + 1.87593, + 1.80441, + 1.7191, + 1.63222, + 1.54737, + 1.46716, + 1.39241, + 1.32364, + 1.26045, + 1.20253, + 1.15567, + 1.11081, + 1.06137, + 1.01538, + 0.972699, + 0.931743, + 0.892749, + 0.854441, + 0.817074, + 0.780997, + 0.750032, + 0.719565, + 0.685491, + 0.652801, + 0.621426, + 0.591266, + 0.562313, + 0.534466, + 0.507634, + 0.482014, + 0.460176, + 0.438661, + 0.414758, + 0.392029, + 0.369727, + 0.348956, + 0.328772, + 0.308439, + 0.288415, + 0.268044, + 0.249802, + 0.231758, + 0.212132, + 0.194042, + 0.178806, + 0.1652, + 0.151731, + 0.138667, + 0.12534, + 0.113376, + 0.102013 + ], + "expected": { + "Rf": 89.22235652053783, + "Rg": 107.794145809586, + "CCT_K": 3302.606999164301, + "Duv": -0.027884023559389598, + "bins": [ + { + "bin": 1, + "ref_a": 23.06228504028278, + "ref_b": 5.111976796411115, + "test_a": 23.361276750135037, + "test_b": 5.416755317843782, + "ref_a_norm": 0.9763032407825085, + "ref_b_norm": 0.21640698241408787, + "test_a_norm": 0.9889605544349064, + "test_b_norm": 0.2293092710500957, + "Rcs_pct": 1.4931218564462425, + "Rhs": 0.010185055381404916, + "Rf_h": 93.37679877312728 + }, + { + "bin": 2, + "ref_a": 20.34027770654904, + "ref_b": 14.980511329753895, + "test_a": 19.748571045797956, + "test_b": 16.026734361172167, + "ref_a_norm": 0.805189315927886, + "ref_b_norm": 0.5930178458660271, + "test_a_norm": 0.7817660427418597, + "test_b_norm": 0.6344335836022156, + "Rcs_pct": 0.35336111899311373, + "Rhs": 0.04744920074077499, + "Rf_h": 89.83640509054416 + }, + { + "bin": 3, + "ref_a": 14.66143518044539, + "ref_b": 23.099317524057312, + "test_a": 13.10493477163385, + "test_b": 25.17641901813648, + "ref_a_norm": 0.5358831414560995, + "ref_b_norm": 0.8442921643028213, + "test_a_norm": 0.47899223558734044, + "test_b_norm": 0.9202113127402725, + "Rcs_pct": 3.1517571087424248, + "Rhs": 0.08948147843428221, + "Rf_h": 81.29334855891142 + }, + { + "bin": 4, + "ref_a": 3.316227329424619, + "ref_b": 22.502834861627402, + "test_a": 1.8836258595589617, + "test_b": 24.05909440964605, + "ref_a_norm": 0.14579465391869886, + "ref_b_norm": 0.9893148734799891, + "test_a_norm": 0.08281174751501695, + "test_b_norm": 1.0577342849593634, + "Rcs_pct": 5.481739618101613, + "Rhs": 0.07512067253541072, + "Rf_h": 85.42851598023903 + }, + { + "bin": 5, + "ref_a": -2.422587647679764, + "ref_b": 16.424874094297536, + "test_a": -3.1623261538118532, + "test_b": 17.52667154742186, + "ref_a_norm": -0.14591640060398525, + "ref_b_norm": 0.9892969241005338, + "test_a_norm": -0.19047205592004496, + "test_b_norm": 1.0556599796162, + "Rcs_pct": 7.378028515559755, + "Rhs": 0.030752741022185812, + "Rf_h": 89.34336756118215 + }, + { + "bin": 6, + "ref_a": -12.59768809193046, + "ref_b": 17.563947508620437, + "test_a": -13.10747779349664, + "test_b": 19.174218603514998, + "ref_a_norm": -0.5828304377415757, + "ref_b_norm": 0.8125937981808398, + "test_a_norm": -0.6064157934633361, + "test_b_norm": 0.8870927856356233, + "Rcs_pct": 7.504696579014966, + "Rhs": -0.021778913241988784, + "Rf_h": 88.09105067179252 + }, + { + "bin": 7, + "ref_a": -18.249827577961938, + "ref_b": 11.874248646479325, + "test_a": -18.57028904118945, + "test_b": 12.974500853965914, + "ref_a_norm": -0.8381946097221974, + "ref_b_norm": 0.5453712462466765, + "test_a_norm": -0.8529130540446718, + "test_b_norm": 0.595904626121666, + "Rcs_pct": 4.031278082692027, + "Rhs": -0.03383984023107154, + "Rf_h": 90.06691863190787 + }, + { + "bin": 8, + "ref_a": -22.605294909086695, + "ref_b": 6.240759531181509, + "test_a": -22.084463968370827, + "test_b": 6.964942612555458, + "ref_a_norm": -0.9639399520969434, + "ref_b_norm": 0.26611983907883, + "test_a_norm": -0.941730564691763, + "test_b_norm": 0.2970006131442202, + "Rcs_pct": -1.5758100097249599, + "Rhs": -0.03462024519145011, + "Rf_h": 90.52776316682521 + }, + { + "bin": 9, + "ref_a": -20.517141477076574, + "ref_b": -2.967983976071647, + "test_a": -20.505984212682307, + "test_b": -3.239407524595391, + "ref_a_norm": -0.9896983252548369, + "ref_b_norm": -0.14316851954173118, + "test_a_norm": -0.989160125238145, + "test_b_norm": -0.1562613488575892, + "Rcs_pct": 0.20264256330488042, + "Rhs": 0.012946251886390935, + "Rf_h": 93.99122684695584 + }, + { + "bin": 10, + "ref_a": -17.771453509913574, + "ref_b": -11.247196926017375, + "test_a": -17.35535413365079, + "test_b": -11.801870559648155, + "ref_a_norm": -0.8449921966289664, + "ref_b_norm": -0.5347786342367783, + "test_a_norm": -0.825207617626011, + "test_b_norm": -0.5611521040169731, + "Rcs_pct": -0.1797961481838133, + "Rhs": 0.032920461860078125, + "Rf_h": 91.74122414581237 + }, + { + "bin": 11, + "ref_a": -12.963074631950235, + "ref_b": -19.355397572494585, + "test_a": -11.547217290580928, + "test_b": -20.84580842680803, + "ref_a_norm": -0.5564665028736889, + "ref_b_norm": -0.8308700446998475, + "test_a_norm": -0.49568792944960893, + "test_b_norm": -0.8948489802141619, + "Rcs_pct": 1.9429774507801447, + "Rhs": 0.08608032899325543, + "Rf_h": 85.59156834963665 + }, + { + "bin": 12, + "ref_a": -5.904186330864348, + "ref_b": -18.810951223945303, + "test_a": -4.2470229784883, + "test_b": -19.984982567186975, + "ref_a_norm": -0.2994652753415954, + "ref_b_norm": -0.9541071998809056, + "test_a_norm": -0.215412562267304, + "test_b_norm": -1.0136550528383277, + "Rcs_pct": 4.20057868002626, + "Rhs": 0.09405487357005371, + "Rf_h": 86.06801496625258 + }, + { + "bin": 13, + "ref_a": 2.5957590943941296, + "ref_b": -18.33391695345533, + "test_a": 4.027469001752538, + "test_b": -19.05563743943754, + "ref_a_norm": 0.14018428761864846, + "ref_b_norm": -0.9901254291779664, + "test_a_norm": 0.2175039564095789, + "test_b_norm": -1.029102032363408, + "Rcs_pct": 5.331199776700167, + "Rhs": 0.06823003496925498, + "Rf_h": 88.99277499790817 + }, + { + "bin": 14, + "ref_a": 8.370959164610108, + "ref_b": -14.44024775476775, + "test_a": 9.938193871526439, + "test_b": -15.179866503668167, + "ref_a_norm": 0.5015215140613669, + "ref_b_norm": -0.8651451733284964, + "test_a_norm": 0.5954177937643167, + "test_b_norm": -0.9094572655848905, + "Rcs_pct": 8.901013616298016, + "Rhs": 0.053453423860791965, + "Rf_h": 88.0920184740265 + }, + { + "bin": 15, + "ref_a": 16.806629668817017, + "ref_b": -11.167833309449989, + "test_a": 17.930142442889327, + "test_b": -11.721519338675437, + "ref_a_norm": 0.8328861701583553, + "ref_b_norm": -0.553444331038766, + "test_a_norm": 0.8885640942847659, + "test_b_norm": -0.5808833503685844, + "Rcs_pct": 6.153880435009379, + "Rhs": 0.0081182865168315, + "Rf_h": 91.24253607308947 + }, + { + "bin": 16, + "ref_a": 19.047107877138007, + "ref_b": -3.2172870794964443, + "test_a": 19.666911461546146, + "test_b": -3.8843704584330836, + "ref_a_norm": 0.9860325322813739, + "ref_b_norm": -0.16655283030552656, + "test_a_norm": 1.018118584494297, + "test_b_norm": -0.20108646751798848, + "Rcs_pct": 3.820670612085186, + "Rhs": -0.027610404798322406, + "Rf_h": 91.32592522208625 + } + ] + } +} \ No newline at end of file diff --git a/crates/tm30/tests/golden/lamp_L0003.json b/crates/tm30/tests/golden/lamp_L0003.json new file mode 100644 index 0000000..b6451ba --- /dev/null +++ b/crates/tm30/tests/golden/lamp_L0003.json @@ -0,0 +1,941 @@ +{ + "name": "lamp_L0003", + "source": "L0003/spd.csv", + "generator": "crates/tm30/tools/golden.py (tm30.py + colour-science 0.4.7, numpy 2.5.1)", + "wavelengths": [ + 380.0, + 381.92, + 383.84, + 385.76, + 387.68, + 389.6, + 391.52, + 393.44, + 395.36, + 397.28, + 399.2, + 401.12, + 403.04, + 404.96, + 406.88, + 408.8, + 410.72, + 412.64, + 414.56, + 416.48, + 418.4, + 420.32, + 422.23, + 424.15, + 426.07, + 427.99, + 429.91, + 431.83, + 433.75, + 435.67, + 437.59, + 439.51, + 441.43, + 443.35, + 445.27, + 447.19, + 449.11, + 451.03, + 452.95, + 454.87, + 456.79, + 458.71, + 460.63, + 462.55, + 464.47, + 466.39, + 468.31, + 470.23, + 472.15, + 474.07, + 475.99, + 477.91, + 479.83, + 481.75, + 483.67, + 485.59, + 487.51, + 489.43, + 491.35, + 493.27, + 495.19, + 497.11, + 499.03, + 500.95, + 502.87, + 504.79, + 506.7, + 508.62, + 510.54, + 512.46, + 514.38, + 516.3, + 518.22, + 520.14, + 522.06, + 523.98, + 525.9, + 527.82, + 529.74, + 531.66, + 533.58, + 535.5, + 537.42, + 539.34, + 541.26, + 543.18, + 545.1, + 547.02, + 548.94, + 550.86, + 552.78, + 554.7, + 556.62, + 558.54, + 560.46, + 562.38, + 564.3, + 566.22, + 568.14, + 570.06, + 571.98, + 573.9, + 575.82, + 577.74, + 579.66, + 581.58, + 583.5, + 585.42, + 587.34, + 589.26, + 591.17, + 593.09, + 595.01, + 596.93, + 598.85, + 600.77, + 602.69, + 604.61, + 606.53, + 608.45, + 610.37, + 612.29, + 614.21, + 616.13, + 618.05, + 619.97, + 621.89, + 623.81, + 625.73, + 627.65, + 629.57, + 631.49, + 633.41, + 635.33, + 637.25, + 639.17, + 641.09, + 643.01, + 644.93, + 646.85, + 648.77, + 650.69, + 652.61, + 654.53, + 656.45, + 658.37, + 660.29, + 662.21, + 664.13, + 666.05, + 667.97, + 669.89, + 671.81, + 673.72, + 675.64, + 677.56, + 679.48, + 681.4, + 683.32, + 685.24, + 687.16, + 689.08, + 691.0, + 692.92, + 694.84, + 696.76, + 698.68, + 700.6, + 702.52, + 704.44, + 706.36, + 708.28, + 710.2, + 712.12, + 714.04, + 715.96, + 717.88, + 719.8, + 721.72, + 723.64, + 725.56, + 727.48, + 729.4, + 731.32, + 733.24, + 735.16, + 737.08, + 739.0, + 740.92, + 742.84, + 744.76, + 746.68, + 748.6, + 750.52, + 752.44, + 754.36, + 756.28, + 758.19, + 760.11, + 762.03, + 763.95, + 765.87, + 767.79, + 769.71, + 771.63, + 773.55, + 775.47, + 777.39, + 779.31, + 781.23, + 783.15, + 785.07, + 786.99, + 788.91, + 790.83, + 792.75, + 794.67, + 796.59, + 798.51, + 800.43, + 802.35, + 804.27, + 806.19, + 808.11, + 810.03, + 811.95, + 813.87, + 815.79, + 817.71, + 819.63, + 821.55, + 823.47, + 825.39, + 827.31, + 829.23, + 831.15, + 833.07, + 834.99, + 836.91, + 838.83, + 840.74, + 842.66, + 844.58, + 846.5, + 848.42, + 850.34, + 852.26, + 854.18, + 856.1, + 858.02, + 859.94, + 861.86, + 863.78, + 865.7, + 867.62, + 869.54, + 871.46, + 873.38, + 875.3, + 877.22, + 879.14, + 881.06, + 882.98, + 884.9, + 886.82, + 888.74, + 890.66, + 892.58, + 894.5, + 896.42, + 898.34, + 900.26, + 902.18, + 904.1, + 906.02, + 907.94, + 909.86, + 911.78, + 913.7, + 915.62, + 917.54, + 919.46, + 921.38, + 923.3, + 925.21, + 927.13, + 929.05, + 930.97, + 932.89, + 934.81, + 936.73, + 938.65, + 940.57, + 942.49, + 944.41, + 946.33, + 948.25, + 950.17, + 952.09, + 954.01, + 955.93, + 957.85, + 959.77, + 961.69, + 963.61, + 965.53, + 967.45, + 969.37, + 971.29, + 973.21, + 975.13, + 977.05, + 978.97, + 980.89, + 982.81, + 984.73, + 986.65, + 988.57, + 990.49, + 992.41, + 994.33, + 996.25, + 998.17, + 1000.09, + 1002.01, + 1003.93, + 1005.85, + 1007.77, + 1009.68, + 1011.6, + 1013.52, + 1015.44, + 1017.36, + 1019.28, + 1021.2, + 1023.12, + 1025.04, + 1026.96, + 1028.88, + 1030.8, + 1032.72, + 1034.64, + 1036.56, + 1038.48, + 1040.4, + 1042.32, + 1044.24, + 1046.16, + 1048.08, + 1050.0 + ], + "values": [ + 0.574534, + 0.593195, + 0.611392, + 0.628949, + 0.646054, + 0.663012, + 0.680794, + 0.699299, + 0.717191, + 0.735801, + 0.755009, + 0.775806, + 0.798571, + 0.821728, + 0.844341, + 0.865867, + 0.887788, + 0.910494, + 0.935025, + 0.960746, + 0.987042, + 1.01406, + 1.04092, + 1.06655, + 1.09044, + 1.1144, + 1.13908, + 1.16457, + 1.19043, + 1.21609, + 1.2418, + 1.26879, + 1.29676, + 1.3261, + 1.35656, + 1.38744, + 1.41821, + 1.44902, + 1.48079, + 1.51345, + 1.54686, + 1.58032, + 1.61251, + 1.64327, + 1.67428, + 1.70672, + 1.74084, + 1.77716, + 1.81309, + 1.84823, + 1.88315, + 1.91774, + 1.95369, + 1.9905, + 2.02761, + 2.06486, + 2.10291, + 2.14238, + 2.18289, + 2.2236, + 2.2636, + 2.30364, + 2.34461, + 2.38627, + 2.42833, + 2.47062, + 2.50722, + 2.54366, + 2.5798, + 2.61582, + 2.65249, + 2.68901, + 2.7252, + 2.76056, + 2.79616, + 2.83126, + 2.86572, + 2.89967, + 2.93388, + 2.96867, + 3.00302, + 3.0369, + 3.06948, + 3.10108, + 3.13321, + 3.16567, + 3.19867, + 3.23245, + 3.267, + 3.30179, + 3.33653, + 3.36956, + 3.40151, + 3.43355, + 3.46592, + 3.49845, + 3.53045, + 3.5614, + 3.5915, + 3.62184, + 3.65197, + 3.68179, + 3.71185, + 3.74114, + 3.76929, + 3.79737, + 3.82403, + 3.84999, + 3.87565, + 3.90048, + 3.92632, + 3.95497, + 3.98521, + 4.01609, + 4.04734, + 4.07796, + 4.10912, + 4.14159, + 4.17558, + 4.21078, + 4.24687, + 4.2839, + 4.32305, + 4.36272, + 4.40237, + 4.44067, + 4.47858, + 4.51774, + 4.55803, + 4.59845, + 4.63786, + 4.6767, + 4.71621, + 4.75707, + 4.79857, + 4.83971, + 4.88055, + 4.92196, + 4.96334, + 5.00491, + 5.04535, + 5.08529, + 5.12549, + 5.16607, + 5.20732, + 5.24776, + 5.28738, + 5.32624, + 5.36447, + 5.40262, + 5.44175, + 5.48257, + 5.52415, + 5.56593, + 5.60784, + 5.64994, + 5.69236, + 5.73532, + 5.77736, + 5.81837, + 5.85991, + 5.90105, + 5.94203, + 5.98372, + 6.02533, + 6.06652, + 6.10693, + 6.14737, + 6.18856, + 6.23177, + 6.27633, + 6.32009, + 6.36299, + 6.40485, + 6.44658, + 6.48872, + 6.53046, + 6.5709, + 6.61067, + 6.65017, + 6.68953, + 6.72959, + 6.76977, + 6.80973, + 6.85036, + 6.89114, + 6.93116, + 6.97095, + 7.00969, + 7.04785, + 7.08646, + 7.12458, + 7.16293, + 7.20103, + 7.23898, + 7.27677, + 7.31457, + 7.3527, + 7.39042, + 7.42987, + 7.47008, + 7.51037, + 7.55172, + 7.59278, + 7.63469, + 7.6774, + 7.71909, + 7.75959, + 7.79799, + 7.83594, + 7.87349, + 7.9112, + 7.94993, + 7.9886, + 8.02793, + 8.06759, + 8.1073, + 8.14753, + 8.1866, + 8.22497, + 8.26388, + 8.30302, + 8.34222, + 8.38108, + 8.41877, + 8.45726, + 8.49591, + 8.53355, + 8.56901, + 8.60267, + 8.63661, + 8.6716, + 8.70752, + 8.74282, + 8.77742, + 8.81101, + 8.84372, + 8.87634, + 8.90735, + 8.93766, + 8.97008, + 9.00325, + 9.03791, + 9.0733, + 9.10809, + 9.14369, + 9.17866, + 9.21255, + 9.24558, + 9.27761, + 9.31041, + 9.34477, + 9.3791, + 9.41501, + 9.45237, + 9.48902, + 9.52496, + 9.56082, + 9.59658, + 9.63262, + 9.66924, + 9.7045, + 9.73784, + 9.7701, + 9.80146, + 9.83265, + 9.86501, + 9.8979, + 9.93053, + 9.96319, + 9.99577, + 10.0291, + 10.0625, + 10.0963, + 10.1302, + 10.1622, + 10.1923, + 10.2194, + 10.2448, + 10.2719, + 10.3014, + 10.3316, + 10.3609, + 10.3883, + 10.4132, + 10.4386, + 10.4645, + 10.4917, + 10.5188, + 10.5451, + 10.5712, + 10.5962, + 10.6228, + 10.6511, + 10.6782, + 10.7054, + 10.7304, + 10.7502, + 10.7671, + 10.7814, + 10.7935, + 10.8061, + 10.821, + 10.838, + 10.8561, + 10.8741, + 10.8942, + 10.9182, + 10.9419, + 10.9667, + 10.9936, + 11.0204, + 11.0474, + 11.0718, + 11.0934, + 11.1166, + 11.1426, + 11.1719, + 11.1993, + 11.2244, + 11.2487, + 11.2705, + 11.2935, + 11.3171, + 11.3398, + 11.3618, + 11.3825, + 11.4002, + 11.4153, + 11.4312, + 11.4479, + 11.4664, + 11.4863, + 11.5045, + 11.5192, + 11.5304, + 11.5436, + 11.5582, + 11.5735, + 11.5897, + 11.6043, + 11.6164, + 11.6287, + 11.6429, + 11.6607, + 11.6806, + 11.7029, + 11.7265, + 11.7497, + 11.7744 + ], + "expected": { + "Rf": 99.04901074256658, + "Rg": 100.05935362628591, + "CCT_K": 3241.5882554693685, + "Duv": 0.0008071669304338566, + "bins": [ + { + "bin": 1, + "ref_a": 23.12214792896163, + "ref_b": 5.181386852483368, + "test_a": 23.304763263041295, + "test_b": 5.206620534358886, + "ref_a_norm": 0.9758000554716002, + "ref_b_norm": 0.21866470163614013, + "test_a_norm": 0.9835067812339461, + "test_b_norm": 0.21972961257129775, + "Rcs_pct": 0.7766397005071579, + "Rhs": -0.0004590586405230252, + "Rf_h": 98.68771571248247 + }, + { + "bin": 2, + "ref_a": 20.377137533849435, + "ref_b": 15.00238537017731, + "test_a": 20.55393874699272, + "test_b": 14.93921922165821, + "ref_a_norm": 0.8052888073097462, + "ref_b_norm": 0.5928827344607419, + "test_a_norm": 0.8122758553103089, + "test_b_norm": 0.5903864568398641, + "Rcs_pct": 0.4422660552654422, + "Rhs": -0.005957374871422469, + "Rf_h": 98.7068731185099 + }, + { + "bin": 3, + "ref_a": 14.689407627901987, + "ref_b": 23.07145215316767, + "test_a": 14.881730256345968, + "test_b": 22.96021652290364, + "ref_a_norm": 0.5370725907166725, + "ref_b_norm": 0.8435360290472966, + "test_a_norm": 0.5441042706133928, + "test_b_norm": 0.8394690435268984, + "Rcs_pct": 0.05250171648545887, + "Rhs": -0.00810612425081663, + "Rf_h": 98.4712785916525 + }, + { + "bin": 4, + "ref_a": 3.315249153057379, + "ref_b": 22.446618094905702, + "test_a": 3.402940492626609, + "test_b": 22.349302573500058, + "ref_a_norm": 0.14610981204207127, + "ref_b_norm": 0.9892683775523357, + "test_a_norm": 0.14997454876340086, + "test_b_norm": 0.9849794834496882, + "Rcs_pct": -0.3452511473613117, + "Rhs": -0.004627198620492464, + "Rf_h": 99.10383873708146 + }, + { + "bin": 5, + "ref_a": -2.406648594492534, + "ref_b": 16.355376409657868, + "test_a": -2.3552006287133485, + "test_b": 16.282489071759716, + "ref_a_norm": -0.14557961849707435, + "ref_b_norm": 0.9893465392258904, + "test_a_norm": -0.14246750015635595, + "test_b_norm": 0.984937540392923, + "Rcs_pct": -0.4931425325932529, + "Rhs": -0.002192166857357179, + "Rf_h": 99.36942077500002 + }, + { + "bin": 6, + "ref_a": -12.620484039790819, + "ref_b": 17.46081183372417, + "test_a": -12.624732205422609, + "test_b": 17.374673187387106, + "ref_a_norm": -0.5857924394404694, + "ref_b_norm": 0.8104611143629187, + "test_a_norm": -0.5859896223140222, + "test_b_norm": 0.8064629025979186, + "Rcs_pct": -0.32148426511408945, + "Rhs": 0.0023852390093684625, + "Rf_h": 99.24765964783528 + }, + { + "bin": 7, + "ref_a": -18.392998495587573, + "ref_b": 13.904647895184686, + "test_a": -18.470002720600746, + "test_b": 13.798234766674952, + "ref_a_norm": -0.7977063445427647, + "ref_b_norm": 0.6030460910048419, + "test_a_norm": -0.8010460261539137, + "test_b_norm": 0.5984309420515473, + "Rcs_pct": 0.021280439503404136, + "Rhs": 0.005692783801831717, + "Rf_h": 99.08611493959883 + }, + { + "bin": 8, + "ref_a": -21.473495001020567, + "ref_b": 6.422763199630777, + "test_a": -21.507765684888568, + "test_b": 6.385552125174787, + "ref_a_norm": -0.9580627766772817, + "ref_b_norm": 0.2865583988394284, + "test_a_norm": -0.9595917996213179, + "test_b_norm": 0.28489818724766114, + "Rcs_pct": 0.11757519828567244, + "Rhs": 0.0019266086700822208, + "Rf_h": 99.46611107365652 + }, + { + "bin": 9, + "ref_a": -20.52922341511598, + "ref_b": -3.089558423086407, + "test_a": -20.56649450880618, + "test_b": -3.0897400605430563, + "ref_a_norm": -0.9888643377231165, + "ref_b_norm": -0.14881976205941913, + "test_a_norm": -0.9906596348287556, + "test_b_norm": -0.14882851128483518, + "Rcs_pct": 0.1762507864365192, + "Rhs": -0.00034166397895077697, + "Rf_h": 99.61679365405314 + }, + { + "bin": 10, + "ref_a": -20.281216847061717, + "ref_b": -12.852926479457208, + "test_a": -20.313950613352443, + "test_b": -12.831052522950301, + "ref_a_norm": -0.8446655021624718, + "ref_b_norm": -0.5352944885356276, + "test_a_norm": -0.846028787381013, + "test_b_norm": -0.5343834891317696, + "Rcs_pct": 0.06274060810360375, + "Rhs": -0.0015148690076706188, + "Rf_h": 99.38228412878466 + }, + { + "bin": 11, + "ref_a": -11.554551029250614, + "ref_b": -17.29217949901903, + "test_a": -11.580448025431968, + "test_b": -17.256684195321903, + "ref_a_norm": -0.5555797429957563, + "ref_b_norm": -0.8314632578609648, + "test_a_norm": -0.5568249533415651, + "test_b_norm": -0.8297565302126395, + "Rcs_pct": -0.07272903740796259, + "Rhs": -0.0019835616407458275, + "Rf_h": 99.53007756730511 + }, + { + "bin": 12, + "ref_a": -5.800806660362923, + "ref_b": -18.82886208963189, + "test_a": -5.672455229858283, + "test_b": -18.762352442953638, + "ref_a_norm": -0.2944247961867811, + "ref_b_norm": -0.9556746514323651, + "test_a_norm": -0.2879102119264868, + "test_b_norm": -0.9522988986596509, + "Rcs_pct": -0.45818209709005076, + "Rhs": 0.005730831654967538, + "Rf_h": 98.88100252061405 + }, + { + "bin": 13, + "ref_a": 2.6942921798894597, + "ref_b": -18.291535952242693, + "test_a": 2.8412421697371157, + "test_b": -18.198363300870966, + "ref_a_norm": 0.14572483413134615, + "ref_b_norm": -0.9893251602569256, + "test_a_norm": 0.15367284476508197, + "test_b_norm": -0.9842857776435374, + "Rcs_pct": -0.3391972335607963, + "Rhs": 0.00877842661486482, + "Rf_h": 98.79059142227663 + }, + { + "bin": 14, + "ref_a": 8.524913196811829, + "ref_b": -14.37423562266014, + "test_a": 8.687036698827715, + "test_b": -14.253724992131625, + "ref_a_norm": 0.5101056098231239, + "ref_b_norm": -0.8601117757750901, + "test_a_norm": 0.519806601018366, + "test_b_norm": -0.8529007758204035, + "Rcs_pct": -0.06061453977752802, + "Rhs": 0.012072296313187889, + "Rf_h": 98.60046883837998 + }, + { + "bin": 15, + "ref_a": 17.750433453159086, + "ref_b": -12.428192176164567, + "test_a": 17.91768808545105, + "test_b": -12.293735053577995, + "ref_a_norm": 0.8191692848599592, + "ref_b_norm": -0.5735518134763615, + "test_a_norm": 0.8268879615833009, + "test_b_norm": -0.5673467174011462, + "Rcs_pct": 0.29704784702291187, + "Rhs": 0.00944761585374929, + "Rf_h": 98.52563677318031 + }, + { + "bin": 16, + "ref_a": 18.334303573456072, + "ref_b": -3.497280303175343, + "test_a": 18.490987706070523, + "test_b": -3.4251152173976362, + "ref_a_norm": 0.9822889779551865, + "ref_b_norm": -0.18737225992060633, + "test_a_norm": 0.990683575321321, + "test_b_norm": -0.18350590262655234, + "Rcs_pct": 0.7479008642090019, + "Rhs": 0.005429771026142733, + "Rf_h": 98.76976458329537 + } + ] + } +} \ No newline at end of file diff --git a/crates/tm30/tests/golden/lamp_L0004.json b/crates/tm30/tests/golden/lamp_L0004.json new file mode 100644 index 0000000..c9addfa --- /dev/null +++ b/crates/tm30/tests/golden/lamp_L0004.json @@ -0,0 +1,941 @@ +{ + "name": "lamp_L0004", + "source": "L0004/spd.csv", + "generator": "crates/tm30/tools/golden.py (tm30.py + colour-science 0.4.7, numpy 2.5.1)", + "wavelengths": [ + 380.0, + 381.92, + 383.84, + 385.76, + 387.68, + 389.6, + 391.52, + 393.44, + 395.36, + 397.28, + 399.2, + 401.12, + 403.04, + 404.96, + 406.88, + 408.8, + 410.72, + 412.64, + 414.56, + 416.48, + 418.4, + 420.32, + 422.23, + 424.15, + 426.07, + 427.99, + 429.91, + 431.83, + 433.75, + 435.67, + 437.59, + 439.51, + 441.43, + 443.35, + 445.27, + 447.19, + 449.11, + 451.03, + 452.95, + 454.87, + 456.79, + 458.71, + 460.63, + 462.55, + 464.47, + 466.39, + 468.31, + 470.23, + 472.15, + 474.07, + 475.99, + 477.91, + 479.83, + 481.75, + 483.67, + 485.59, + 487.51, + 489.43, + 491.35, + 493.27, + 495.19, + 497.11, + 499.03, + 500.95, + 502.87, + 504.79, + 506.7, + 508.62, + 510.54, + 512.46, + 514.38, + 516.3, + 518.22, + 520.14, + 522.06, + 523.98, + 525.9, + 527.82, + 529.74, + 531.66, + 533.58, + 535.5, + 537.42, + 539.34, + 541.26, + 543.18, + 545.1, + 547.02, + 548.94, + 550.86, + 552.78, + 554.7, + 556.62, + 558.54, + 560.46, + 562.38, + 564.3, + 566.22, + 568.14, + 570.06, + 571.98, + 573.9, + 575.82, + 577.74, + 579.66, + 581.58, + 583.5, + 585.42, + 587.34, + 589.26, + 591.17, + 593.09, + 595.01, + 596.93, + 598.85, + 600.77, + 602.69, + 604.61, + 606.53, + 608.45, + 610.37, + 612.29, + 614.21, + 616.13, + 618.05, + 619.97, + 621.89, + 623.81, + 625.73, + 627.65, + 629.57, + 631.49, + 633.41, + 635.33, + 637.25, + 639.17, + 641.09, + 643.01, + 644.93, + 646.85, + 648.77, + 650.69, + 652.61, + 654.53, + 656.45, + 658.37, + 660.29, + 662.21, + 664.13, + 666.05, + 667.97, + 669.89, + 671.81, + 673.72, + 675.64, + 677.56, + 679.48, + 681.4, + 683.32, + 685.24, + 687.16, + 689.08, + 691.0, + 692.92, + 694.84, + 696.76, + 698.68, + 700.6, + 702.52, + 704.44, + 706.36, + 708.28, + 710.2, + 712.12, + 714.04, + 715.96, + 717.88, + 719.8, + 721.72, + 723.64, + 725.56, + 727.48, + 729.4, + 731.32, + 733.24, + 735.16, + 737.08, + 739.0, + 740.92, + 742.84, + 744.76, + 746.68, + 748.6, + 750.52, + 752.44, + 754.36, + 756.28, + 758.19, + 760.11, + 762.03, + 763.95, + 765.87, + 767.79, + 769.71, + 771.63, + 773.55, + 775.47, + 777.39, + 779.31, + 781.23, + 783.15, + 785.07, + 786.99, + 788.91, + 790.83, + 792.75, + 794.67, + 796.59, + 798.51, + 800.43, + 802.35, + 804.27, + 806.19, + 808.11, + 810.03, + 811.95, + 813.87, + 815.79, + 817.71, + 819.63, + 821.55, + 823.47, + 825.39, + 827.31, + 829.23, + 831.15, + 833.07, + 834.99, + 836.91, + 838.83, + 840.74, + 842.66, + 844.58, + 846.5, + 848.42, + 850.34, + 852.26, + 854.18, + 856.1, + 858.02, + 859.94, + 861.86, + 863.78, + 865.7, + 867.62, + 869.54, + 871.46, + 873.38, + 875.3, + 877.22, + 879.14, + 881.06, + 882.98, + 884.9, + 886.82, + 888.74, + 890.66, + 892.58, + 894.5, + 896.42, + 898.34, + 900.26, + 902.18, + 904.1, + 906.02, + 907.94, + 909.86, + 911.78, + 913.7, + 915.62, + 917.54, + 919.46, + 921.38, + 923.3, + 925.21, + 927.13, + 929.05, + 930.97, + 932.89, + 934.81, + 936.73, + 938.65, + 940.57, + 942.49, + 944.41, + 946.33, + 948.25, + 950.17, + 952.09, + 954.01, + 955.93, + 957.85, + 959.77, + 961.69, + 963.61, + 965.53, + 967.45, + 969.37, + 971.29, + 973.21, + 975.13, + 977.05, + 978.97, + 980.89, + 982.81, + 984.73, + 986.65, + 988.57, + 990.49, + 992.41, + 994.33, + 996.25, + 998.17, + 1000.09, + 1002.01, + 1003.93, + 1005.85, + 1007.77, + 1009.68, + 1011.6, + 1013.52, + 1015.44, + 1017.36, + 1019.28, + 1021.2, + 1023.12, + 1025.04, + 1026.96, + 1028.88, + 1030.8, + 1032.72, + 1034.64, + 1036.56, + 1038.48, + 1040.4, + 1042.32, + 1044.24, + 1046.16, + 1048.08, + 1050.0 + ], + "values": [ + 0.0, + 0.0, + 0.00255847, + 0.0210863, + 0.065981, + 0.143599, + 0.270733, + 0.427104, + 0.588985, + 0.774048, + 0.985239, + 1.22928, + 1.51043, + 1.8292, + 2.18545, + 2.57401, + 3.00084, + 3.46377, + 3.96494, + 4.50652, + 5.08274, + 5.69404, + 6.33362, + 6.98997, + 7.6521, + 8.32141, + 8.98806, + 9.64954, + 10.291, + 10.8872, + 11.4421, + 11.872, + 12.1407, + 12.2709, + 12.2558, + 12.086, + 11.7698, + 11.3215, + 10.7705, + 10.1515, + 9.49823, + 8.83597, + 8.18367, + 7.55855, + 6.96897, + 6.42542, + 5.92934, + 5.48097, + 5.07145, + 4.69341, + 4.34235, + 4.01609, + 3.71597, + 3.43772, + 3.18021, + 2.94261, + 2.72637, + 2.53448, + 2.36541, + 2.21833, + 2.09141, + 1.98509, + 1.89909, + 1.83159, + 1.78091, + 1.74462, + 1.71928, + 1.70914, + 1.71347, + 1.73166, + 1.76334, + 1.809, + 1.87068, + 1.95062, + 2.06045, + 2.19321, + 2.33421, + 2.49431, + 2.6737, + 2.87152, + 3.08595, + 3.31648, + 3.56146, + 3.82053, + 4.09311, + 4.37759, + 4.67351, + 4.97975, + 5.2949, + 5.61696, + 5.94496, + 6.27378, + 6.60218, + 6.92854, + 7.25159, + 7.57097, + 7.88258, + 8.18441, + 8.47608, + 8.75857, + 9.03008, + 9.29029, + 9.53534, + 9.76402, + 9.97609, + 10.1739, + 10.3556, + 10.5194, + 10.6669, + 10.7984, + 10.9199, + 11.0355, + 11.1478, + 11.2536, + 11.3488, + 11.4333, + 11.5099, + 11.5831, + 11.6541, + 11.7216, + 11.7866, + 11.8514, + 11.9206, + 11.9915, + 12.0645, + 12.1369, + 12.2076, + 12.2803, + 12.3545, + 12.4266, + 12.4937, + 12.559, + 12.6264, + 12.703, + 12.7878, + 12.8742, + 12.9605, + 13.0464, + 13.134, + 13.2263, + 13.3229, + 13.4213, + 13.5234, + 13.6302, + 13.7421, + 13.8583, + 13.9797, + 14.1068, + 14.2413, + 14.3828, + 14.5312, + 14.686, + 14.8457, + 15.0121, + 15.1858, + 15.3664, + 15.5533, + 15.7475, + 15.9366, + 16.1294, + 16.3399, + 16.5504, + 16.756, + 16.9582, + 17.1554, + 17.3479, + 17.5369, + 17.7258, + 17.9161, + 18.1082, + 18.2991, + 18.4822, + 18.6546, + 18.8175, + 18.9729, + 19.1213, + 19.2638, + 19.3956, + 19.5168, + 19.6271, + 19.7252, + 19.8135, + 19.8926, + 19.9679, + 20.0357, + 20.0868, + 20.1231, + 20.1451, + 20.152, + 20.1461, + 20.1313, + 20.1055, + 20.0685, + 20.0171, + 19.9495, + 19.8665, + 19.7695, + 19.6623, + 19.5464, + 19.4261, + 19.2974, + 19.1596, + 19.016, + 18.8959, + 18.771, + 18.6046, + 18.4246, + 18.2353, + 18.0387, + 17.8373, + 17.6303, + 17.4159, + 17.1956, + 16.971, + 16.743, + 16.511, + 16.2753, + 16.0385, + 15.8005, + 15.5616, + 15.3218, + 15.1178, + 14.9098, + 14.6607, + 14.4091, + 14.1571, + 13.9017, + 13.6399, + 13.3744, + 13.1073, + 12.8415, + 12.5759, + 12.31, + 12.0437, + 11.7787, + 11.5155, + 11.2911, + 11.0677, + 10.8051, + 10.5421, + 10.2801, + 10.0195, + 9.76374, + 9.51197, + 9.26428, + 9.02117, + 8.78145, + 8.54667, + 8.31672, + 8.09038, + 7.89926, + 7.71237, + 7.49921, + 7.29237, + 7.09135, + 6.89393, + 6.69966, + 6.50905, + 6.32228, + 6.13982, + 5.96215, + 5.79012, + 5.62404, + 5.48424, + 5.34629, + 5.18695, + 5.02807, + 4.87088, + 4.71682, + 4.56644, + 4.41979, + 4.27713, + 4.13787, + 4.00137, + 3.86759, + 3.73579, + 3.62365, + 3.51405, + 3.39099, + 3.27133, + 3.1546, + 3.04035, + 2.92869, + 2.82067, + 2.71582, + 2.61272, + 2.51103, + 2.42408, + 2.33904, + 2.24445, + 2.15353, + 2.06616, + 1.98218, + 1.90077, + 1.82201, + 1.74677, + 1.67517, + 1.60778, + 1.54386, + 1.48856, + 1.4322, + 1.36482, + 1.29579, + 1.22812, + 1.16438, + 1.10525, + 1.05143, + 1.00173, + 0.954845, + 0.916886, + 0.881104, + 0.842756, + 0.808086, + 0.775126, + 0.742455, + 0.709876, + 0.677829, + 0.646861, + 0.617464, + 0.592636, + 0.568499, + 0.541518, + 0.515341, + 0.490225, + 0.466008, + 0.443091, + 0.421363, + 0.400605, + 0.380486, + 0.363731, + 0.347198, + 0.328446, + 0.310027, + 0.291902, + 0.274443, + 0.257333, + 0.240552, + 0.22455, + 0.209217, + 0.196433, + 0.184286, + 0.170098, + 0.156471, + 0.143804, + 0.132403, + 0.121075, + 0.110491, + 0.100871, + 0.092404, + 0.0847517 + ], + "expected": { + "Rf": 67.24125771006523, + "Rg": 114.57741538875685, + "CCT_K": 2434.1904147724877, + "Duv": -0.052142527240925135, + "bins": [ + { + "bin": 1, + "ref_a": 25.31926554064602, + "ref_b": 5.696050670854714, + "test_a": 24.111694074166884, + "test_b": 5.408243553598857, + "ref_a_norm": 0.9756162259190091, + "ref_b_norm": 0.21948343838100626, + "test_a_norm": 0.9290854008142064, + "test_b_norm": 0.20839349214701988, + "Rcs_pct": -4.780028952973748, + "Rhs": -0.0017991423733849908, + "Rf_h": 86.9044966575473 + }, + { + "bin": 2, + "ref_a": 19.800028648413715, + "ref_b": 14.033054147050713, + "test_a": 15.769992598103196, + "test_b": 16.789938030283434, + "ref_a_norm": 0.8158683084214428, + "ref_b_norm": 0.5782377567346615, + "test_a_norm": 0.6498090186280568, + "test_b_norm": 0.6918362888513115, + "Rcs_pct": -7.496129034501049, + "Rhs": 0.18671132578275035, + "Rf_h": 65.80296742576813 + }, + { + "bin": 3, + "ref_a": 15.61079335654892, + "ref_b": 24.122194939114507, + "test_a": 7.865758016879823, + "test_b": 30.45155649114465, + "ref_a_norm": 0.5433080510774396, + "ref_b_norm": 0.8395334190098893, + "test_a_norm": 0.27375480289763265, + "test_b_norm": 1.0598164636224399, + "Rcs_pct": 3.3402896798375767, + "Rhs": 0.34650803718461803, + "Rf_h": 32.14646510192676 + }, + { + "bin": 4, + "ref_a": 3.0726615988119597, + "ref_b": 19.919984867717222, + "test_a": -2.9431816718042123, + "test_b": 25.754879591175477, + "ref_a_norm": 0.15244726052792937, + "ref_b_norm": 0.9883116071146435, + "test_a_norm": -0.1460232338230949, + "test_b_norm": 1.2778045068221837, + "Rcs_pct": 22.57016699591498, + "Rhs": 0.3492127305194869, + "Rf_h": 43.200033638500095 + }, + { + "bin": 5, + "ref_a": -2.5265642320096955, + "ref_b": 15.692547463877709, + "test_a": -6.049520234406139, + "test_b": 19.856310139787436, + "ref_a_norm": -0.15895699883971812, + "ref_b_norm": 0.9872855070950195, + "test_a_norm": -0.3806012800697552, + "test_b_norm": 1.249245686241933, + "Rcs_pct": 30.016734195728738, + "Rhs": 0.1662795528108003, + "Rf_h": 62.209757601708866 + }, + { + "bin": 6, + "ref_a": -10.971458112259793, + "ref_b": 15.337732368829638, + "test_a": -13.003523938757573, + "test_b": 20.25810571438091, + "ref_a_norm": -0.5817975868155147, + "ref_b_norm": 0.8133336141926286, + "test_a_norm": -0.6895545487443585, + "test_b_norm": 1.0742525649266517, + "Rcs_pct": 27.681273925749725, + "Rhs": -0.05536216290065539, + "Rf_h": 63.97574481757434 + }, + { + "bin": 7, + "ref_a": -18.33287433340206, + "ref_b": 13.42976990463379, + "test_a": -19.840936315268607, + "test_b": 19.100725820145858, + "ref_a_norm": -0.806705761702064, + "ref_b_norm": 0.5909533095234281, + "test_a_norm": -0.8730653661836716, + "test_b_norm": 0.8404937104559116, + "Rcs_pct": 19.38132133047374, + "Rhs": -0.17061783949221848, + "Rf_h": 60.2040751860808 + }, + { + "bin": 8, + "ref_a": -21.27311392694406, + "ref_b": 3.8958460176874192, + "test_a": -19.583503013979758, + "test_b": 7.1765593652757165, + "ref_a_norm": -0.9836411892113722, + "ref_b_norm": 0.18013886556442352, + "test_a_norm": -0.905515772620259, + "test_b_norm": 0.331834794508614, + "Rcs_pct": -4.702985099167631, + "Rhs": -0.16402264688596085, + "Rf_h": 72.23803308588867 + }, + { + "bin": 9, + "ref_a": -24.1565667477894, + "ref_b": -5.139687608496572, + "test_a": -23.33585588741126, + "test_b": -3.1331584323023662, + "ref_a_norm": -0.9781059903389651, + "ref_b_norm": -0.20810735610024086, + "test_a_norm": -0.9448751832771309, + "test_b_norm": -0.12686244131097094, + "Rcs_pct": -4.844238301057818, + "Rhs": -0.07320080768238162, + "Rf_h": 80.74143909243692 + }, + { + "bin": 10, + "ref_a": -19.232620428532666, + "ref_b": -12.805073283805827, + "test_a": -16.812017522879156, + "test_b": -12.9971324491165, + "ref_a_norm": -0.8323832054507617, + "ref_b_norm": -0.5542005045861244, + "test_a_norm": -0.7276200914893317, + "test_b_norm": -0.5625127792577714, + "Rcs_pct": -8.248929337286775, + "Rhs": 0.06511467143399755, + "Rf_h": 79.06183286064181 + }, + { + "bin": 11, + "ref_a": -11.021505513236653, + "ref_b": -16.648050536791427, + "test_a": -6.7564395375550745, + "test_b": -17.84351600414797, + "ref_a_norm": -0.5520206127643031, + "ref_b_norm": -0.8338304642331817, + "test_a_norm": -0.33840149053564544, + "test_b_norm": -0.8937062751227346, + "Rcs_pct": -6.88955082473812, + "Rhs": 0.21088302694801858, + "Rf_h": 64.4065928345639 + }, + { + "bin": 12, + "ref_a": -5.283741988143532, + "ref_b": -21.169006769535528, + "test_a": 0.40921523143887184, + "test_b": -22.691897152384268, + "ref_a_norm": -0.24216852691189272, + "ref_b_norm": -0.9702342008882823, + "test_a_norm": 0.01875546724458432, + "test_b_norm": -1.0400324842810613, + "Rcs_pct": 1.7553382907329271, + "Rhs": 0.26952738235596146, + "Rf_h": 52.5392360930155 + }, + { + "bin": 13, + "ref_a": 3.7453202310907634, + "ref_b": -14.608570957331969, + "test_a": 6.647773596869409, + "test_b": -16.102162097363664, + "ref_a_norm": 0.24834628236425985, + "ref_b_norm": -0.968671318887811, + "test_a_norm": 0.4408033911431358, + "test_b_norm": -1.0677089936692385, + "Rcs_pct": 13.468121295695031, + "Rhs": 0.1694378075344476, + "Rf_h": 75.40993854262702 + }, + { + "bin": 14, + "ref_a": 13.011498869190666, + "ref_b": -15.414833648583118, + "test_a": 15.84239885115364, + "test_b": -17.561940261529973, + "ref_a_norm": 0.6450224620660133, + "ref_b_norm": -0.7641636103808519, + "test_a_norm": 0.7853594128343894, + "test_b_norm": -0.8706026922825163, + "Rcs_pct": 16.646789460226284, + "Rhs": 0.05755152451260279, + "Rf_h": 75.61639023937637 + }, + { + "bin": 15, + "ref_a": 16.576996223304487, + "ref_b": -10.246147995290025, + "test_a": 18.62077757563617, + "test_b": -12.827051563666874, + "ref_a_norm": 0.8506278387281897, + "ref_b_norm": -0.5257682759359001, + "test_a_norm": 0.9555019239453196, + "test_b_norm": -0.6582041162269128, + "Rcs_pct": 16.07770256266957, + "Rhs": -0.051851456819931564, + "Rf_h": 76.62203823499584 + }, + { + "bin": 16, + "ref_a": 18.035310108749773, + "ref_b": -3.3801147525423407, + "test_a": 18.087087802994777, + "test_b": -4.315874338137058, + "ref_a_norm": 0.9828870488915088, + "ref_b_norm": -0.18420925362570864, + "test_a_norm": 0.9857088259936496, + "test_b_norm": -0.23520621303540137, + "Rcs_pct": 1.2716570679438997, + "Rhs": -0.04946656573083323, + "Rf_h": 88.60585658294039 + } + ] + } +} \ No newline at end of file diff --git a/crates/tm30/tests/golden/lamp_L0005.json b/crates/tm30/tests/golden/lamp_L0005.json new file mode 100644 index 0000000..b399b4e --- /dev/null +++ b/crates/tm30/tests/golden/lamp_L0005.json @@ -0,0 +1,941 @@ +{ + "name": "lamp_L0005", + "source": "L0005/spd.csv", + "generator": "crates/tm30/tools/golden.py (tm30.py + colour-science 0.4.7, numpy 2.5.1)", + "wavelengths": [ + 380.0, + 381.92, + 383.84, + 385.76, + 387.68, + 389.6, + 391.52, + 393.44, + 395.36, + 397.28, + 399.2, + 401.12, + 403.04, + 404.96, + 406.88, + 408.8, + 410.72, + 412.64, + 414.56, + 416.48, + 418.4, + 420.32, + 422.23, + 424.15, + 426.07, + 427.99, + 429.91, + 431.83, + 433.75, + 435.67, + 437.59, + 439.51, + 441.43, + 443.35, + 445.27, + 447.19, + 449.11, + 451.03, + 452.95, + 454.87, + 456.79, + 458.71, + 460.63, + 462.55, + 464.47, + 466.39, + 468.31, + 470.23, + 472.15, + 474.07, + 475.99, + 477.91, + 479.83, + 481.75, + 483.67, + 485.59, + 487.51, + 489.43, + 491.35, + 493.27, + 495.19, + 497.11, + 499.03, + 500.95, + 502.87, + 504.79, + 506.7, + 508.62, + 510.54, + 512.46, + 514.38, + 516.3, + 518.22, + 520.14, + 522.06, + 523.98, + 525.9, + 527.82, + 529.74, + 531.66, + 533.58, + 535.5, + 537.42, + 539.34, + 541.26, + 543.18, + 545.1, + 547.02, + 548.94, + 550.86, + 552.78, + 554.7, + 556.62, + 558.54, + 560.46, + 562.38, + 564.3, + 566.22, + 568.14, + 570.06, + 571.98, + 573.9, + 575.82, + 577.74, + 579.66, + 581.58, + 583.5, + 585.42, + 587.34, + 589.26, + 591.17, + 593.09, + 595.01, + 596.93, + 598.85, + 600.77, + 602.69, + 604.61, + 606.53, + 608.45, + 610.37, + 612.29, + 614.21, + 616.13, + 618.05, + 619.97, + 621.89, + 623.81, + 625.73, + 627.65, + 629.57, + 631.49, + 633.41, + 635.33, + 637.25, + 639.17, + 641.09, + 643.01, + 644.93, + 646.85, + 648.77, + 650.69, + 652.61, + 654.53, + 656.45, + 658.37, + 660.29, + 662.21, + 664.13, + 666.05, + 667.97, + 669.89, + 671.81, + 673.72, + 675.64, + 677.56, + 679.48, + 681.4, + 683.32, + 685.24, + 687.16, + 689.08, + 691.0, + 692.92, + 694.84, + 696.76, + 698.68, + 700.6, + 702.52, + 704.44, + 706.36, + 708.28, + 710.2, + 712.12, + 714.04, + 715.96, + 717.88, + 719.8, + 721.72, + 723.64, + 725.56, + 727.48, + 729.4, + 731.32, + 733.24, + 735.16, + 737.08, + 739.0, + 740.92, + 742.84, + 744.76, + 746.68, + 748.6, + 750.52, + 752.44, + 754.36, + 756.28, + 758.19, + 760.11, + 762.03, + 763.95, + 765.87, + 767.79, + 769.71, + 771.63, + 773.55, + 775.47, + 777.39, + 779.31, + 781.23, + 783.15, + 785.07, + 786.99, + 788.91, + 790.83, + 792.75, + 794.67, + 796.59, + 798.51, + 800.43, + 802.35, + 804.27, + 806.19, + 808.11, + 810.03, + 811.95, + 813.87, + 815.79, + 817.71, + 819.63, + 821.55, + 823.47, + 825.39, + 827.31, + 829.23, + 831.15, + 833.07, + 834.99, + 836.91, + 838.83, + 840.74, + 842.66, + 844.58, + 846.5, + 848.42, + 850.34, + 852.26, + 854.18, + 856.1, + 858.02, + 859.94, + 861.86, + 863.78, + 865.7, + 867.62, + 869.54, + 871.46, + 873.38, + 875.3, + 877.22, + 879.14, + 881.06, + 882.98, + 884.9, + 886.82, + 888.74, + 890.66, + 892.58, + 894.5, + 896.42, + 898.34, + 900.26, + 902.18, + 904.1, + 906.02, + 907.94, + 909.86, + 911.78, + 913.7, + 915.62, + 917.54, + 919.46, + 921.38, + 923.3, + 925.21, + 927.13, + 929.05, + 930.97, + 932.89, + 934.81, + 936.73, + 938.65, + 940.57, + 942.49, + 944.41, + 946.33, + 948.25, + 950.17, + 952.09, + 954.01, + 955.93, + 957.85, + 959.77, + 961.69, + 963.61, + 965.53, + 967.45, + 969.37, + 971.29, + 973.21, + 975.13, + 977.05, + 978.97, + 980.89, + 982.81, + 984.73, + 986.65, + 988.57, + 990.49, + 992.41, + 994.33, + 996.25, + 998.17, + 1000.09, + 1002.01, + 1003.93, + 1005.85, + 1007.77, + 1009.68, + 1011.6, + 1013.52, + 1015.44, + 1017.36, + 1019.28, + 1021.2, + 1023.12, + 1025.04, + 1026.96, + 1028.88, + 1030.8, + 1032.72, + 1034.64, + 1036.56, + 1038.48, + 1040.4, + 1042.32, + 1044.24, + 1046.16, + 1048.08, + 1050.0 + ], + "values": [ + 1.4212, + 1.7419, + 2.10394, + 2.5039, + 2.93606, + 3.39889, + 3.93454, + 4.49359, + 5.01257, + 5.54877, + 6.10222, + 6.68219, + 7.29638, + 7.93514, + 8.5931, + 9.24619, + 9.90701, + 10.5765, + 11.2605, + 11.9645, + 12.6711, + 13.3723, + 14.0493, + 14.6832, + 15.2642, + 15.8132, + 16.3287, + 16.8228, + 17.2915, + 17.7187, + 18.0902, + 18.382, + 18.592, + 18.7226, + 18.7717, + 18.7254, + 18.576, + 18.3075, + 17.9185, + 17.4157, + 16.8156, + 16.1356, + 15.3893, + 14.5937, + 13.7699, + 12.9462, + 12.1419, + 11.3762, + 10.6482, + 9.95964, + 9.31169, + 8.70815, + 8.15366, + 7.64294, + 7.17184, + 6.7373, + 6.33889, + 5.97612, + 5.64597, + 5.34316, + 5.06612, + 4.81743, + 4.5986, + 4.41061, + 4.25218, + 4.12103, + 4.00659, + 3.91643, + 3.84879, + 3.80346, + 3.78055, + 3.77986, + 3.80314, + 3.85078, + 3.92727, + 4.03001, + 4.1484, + 4.28763, + 4.44921, + 4.63099, + 4.83077, + 5.04765, + 5.27833, + 5.52389, + 5.78306, + 6.05418, + 6.33638, + 6.628, + 6.92813, + 7.23399, + 7.54393, + 7.85199, + 8.15893, + 8.46237, + 8.76243, + 9.05838, + 9.34514, + 9.62164, + 9.88696, + 10.1422, + 10.3832, + 10.6101, + 10.8211, + 11.0168, + 11.1993, + 11.3703, + 11.5257, + 11.6629, + 11.7837, + 11.8895, + 11.9867, + 12.0839, + 12.1791, + 12.2662, + 12.3425, + 12.4078, + 12.466, + 12.5214, + 12.5754, + 12.6259, + 12.6736, + 12.7215, + 12.774, + 12.8267, + 12.8787, + 12.9257, + 12.9679, + 13.0099, + 13.0493, + 13.0835, + 13.1099, + 13.1311, + 13.152, + 13.1756, + 13.1982, + 13.2152, + 13.2243, + 13.2288, + 13.2301, + 13.229, + 13.2249, + 13.2152, + 13.2011, + 13.1834, + 13.1637, + 13.1405, + 13.1139, + 13.0846, + 13.0521, + 13.0183, + 12.9848, + 12.952, + 12.9178, + 12.8833, + 12.8484, + 12.8136, + 12.7792, + 12.7453, + 12.7269, + 12.7075, + 12.6719, + 12.6317, + 12.5835, + 12.5284, + 12.4656, + 12.3945, + 12.3165, + 12.2371, + 12.1585, + 12.0817, + 12.0042, + 11.9194, + 11.8265, + 11.7284, + 11.6272, + 11.5246, + 11.4206, + 11.3115, + 11.1987, + 11.0818, + 10.9611, + 10.8384, + 10.7141, + 10.6129, + 10.5113, + 10.3846, + 10.2555, + 10.1236, + 9.98873, + 9.85281, + 9.71633, + 9.57892, + 9.44182, + 9.3028, + 9.16146, + 9.0168, + 8.86908, + 8.7203, + 8.57196, + 8.42654, + 8.28341, + 8.14124, + 8.00103, + 7.88435, + 7.76788, + 7.62763, + 7.48411, + 7.33895, + 7.19535, + 7.05608, + 6.92023, + 6.78589, + 6.65214, + 6.51794, + 6.38389, + 6.25089, + 6.11966, + 5.99129, + 5.86632, + 5.74305, + 5.62101, + 5.51761, + 5.41342, + 5.2914, + 5.17006, + 5.05095, + 4.93334, + 4.81606, + 4.69915, + 4.58222, + 4.46642, + 4.35285, + 4.2409, + 4.13, + 4.01949, + 3.90912, + 3.81533, + 3.72338, + 3.61776, + 3.51387, + 3.41173, + 3.31158, + 3.21455, + 3.12043, + 3.02806, + 2.9375, + 2.84828, + 2.76111, + 2.67621, + 2.5926, + 2.52159, + 2.45227, + 2.37415, + 2.29974, + 2.22875, + 2.16007, + 2.09361, + 2.02931, + 1.96636, + 1.90426, + 1.84288, + 1.78329, + 1.72633, + 1.6787, + 1.63161, + 1.57766, + 1.52388, + 1.47098, + 1.41934, + 1.36869, + 1.32023, + 1.27303, + 1.22641, + 1.1799, + 1.13381, + 1.0896, + 1.05327, + 1.01825, + 0.979388, + 0.941846, + 0.904806, + 0.868271, + 0.832064, + 0.796383, + 0.76247, + 0.731021, + 0.701246, + 0.676909, + 0.653443, + 0.626491, + 0.599819, + 0.573896, + 0.548988, + 0.525677, + 0.503604, + 0.482191, + 0.461504, + 0.441348, + 0.423077, + 0.407844, + 0.392133, + 0.373466, + 0.35349, + 0.333593, + 0.315277, + 0.29785, + 0.282291, + 0.267882, + 0.254207, + 0.243396, + 0.232792, + 0.220971, + 0.210188, + 0.20019, + 0.190529, + 0.181201, + 0.172511, + 0.164088, + 0.156279, + 0.149948, + 0.143313, + 0.135445, + 0.127207, + 0.119077, + 0.111116, + 0.103413, + 0.0961485, + 0.0889833, + 0.0820498, + 0.0763345, + 0.0709253, + 0.06507, + 0.0600421, + 0.0555066, + 0.0511544, + 0.0467442, + 0.0422355, + 0.0375999, + 0.0324369, + 0.0277513, + 0.0233159, + 0.0184905, + 0.0141661, + 0.010318, + 0.0065234, + 0.00339913, + 0.00142989, + 0.0003136, + 1.21648e-05, + 0.0 + ], + "expected": { + "Rf": 72.42846923570649, + "Rg": 115.48226172022527, + "CCT_K": 4242.020225454432, + "Duv": -0.061811178268578196, + "bins": [ + { + "bin": 1, + "ref_a": 21.43410030670144, + "ref_b": 4.90142850266573, + "test_a": 21.754364677788764, + "test_b": 6.028959887700748, + "ref_a_norm": 0.9748367120906379, + "ref_b_norm": 0.22292013089964466, + "test_a_norm": 0.9894025423351167, + "test_b_norm": 0.27420098581954466, + "Rcs_pct": 2.4290350400222676, + "Rhs": 0.047453855159103865, + "Rf_h": 83.53674808568866 + }, + { + "bin": 2, + "ref_a": 20.63505113818434, + "ref_b": 14.283337677544614, + "test_a": 18.25222692435521, + "test_b": 16.891133889352687, + "ref_a_norm": 0.8222381933674561, + "ref_b_norm": 0.5691435261582284, + "test_a_norm": 0.7272905693673594, + "test_b_norm": 0.6730555364318426, + "Rcs_pct": -2.121564435516107, + "Rhs": 0.13914975248617142, + "Rf_h": 69.77968032788063 + }, + { + "bin": 3, + "ref_a": 14.629113610798417, + "ref_b": 22.260093628513623, + "test_a": 10.384327641547301, + "test_b": 26.11873592756626, + "ref_a_norm": 0.5492054713971743, + "ref_b_norm": 0.8356873519369594, + "test_a_norm": 0.38984792306958044, + "test_b_norm": 0.9805483133857796, + "Rcs_pct": 3.1913177195830578, + "Rhs": 0.21298139703299326, + "Rf_h": 57.54160217933594 + }, + { + "bin": 4, + "ref_a": 3.8423149103576013, + "ref_b": 22.109218102792415, + "test_a": -0.9720534930269555, + "test_b": 25.385903109075425, + "ref_a_norm": 0.17122151182532394, + "ref_b_norm": 0.9852325582765982, + "test_a_norm": -0.04331671727439753, + "test_b_norm": 1.131248429864524, + "Rcs_pct": 10.13558853588513, + "Rhs": 0.23890222059233687, + "Rf_h": 59.58909922550171 + }, + { + "bin": 5, + "ref_a": -2.186571142791434, + "ref_b": 19.142977633613715, + "test_a": -5.886837111970642, + "test_b": 21.93731981339119, + "ref_a_norm": -0.1134852290405945, + "ref_b_norm": 0.993539683550488, + "test_a_norm": -0.30553273337531833, + "test_b_norm": 1.1385688372257725, + "Rcs_pct": 17.970906861711207, + "Rhs": 0.16006358109743493, + "Rf_h": 67.34382626976937 + }, + { + "bin": 6, + "ref_a": -11.104600804688529, + "ref_b": 17.233883700252907, + "test_a": -13.97297513106531, + "test_b": 19.346249262977278, + "ref_a_norm": -0.5416434405814599, + "ref_b_norm": 0.8406083411881414, + "test_a_norm": -0.681552669768544, + "test_b_norm": 0.9436421171233145, + "Rcs_pct": 16.339885679194687, + "Rhs": 0.05908777364453933, + "Rf_h": 75.25377187782897 + }, + { + "bin": 7, + "ref_a": -18.189968167341636, + "ref_b": 11.354085705300378, + "test_a": -19.7206081839055, + "test_b": 12.529259563187352, + "ref_a_norm": -0.8483051075881072, + "ref_b_norm": 0.5295077378470778, + "test_a_norm": -0.9196878462484812, + "test_b_norm": 0.5843130006588837, + "Rcs_pct": 8.980075067009068, + "Rhs": -0.00591078587114994, + "Rf_h": 80.20887812533893 + }, + { + "bin": 8, + "ref_a": -22.71806289835211, + "ref_b": 3.7143225742842416, + "test_a": -24.447871024049007, + "test_b": 3.7241303377402764, + "ref_a_norm": -0.9868965798659958, + "ref_b_norm": 0.16135408469821927, + "test_a_norm": -1.0620412667485428, + "test_b_norm": 0.16178014427267345, + "Rcs_pct": 7.378392289449014, + "Rhs": 0.014242128202517721, + "Rf_h": 80.82561555010895 + }, + { + "bin": 9, + "ref_a": -19.347306328963583, + "ref_b": -2.026321281934058, + "test_a": -20.06625868011774, + "test_b": -2.2169511268986613, + "ref_a_norm": -0.9945601047642705, + "ref_b_norm": -0.10416428376023783, + "test_a_norm": -1.0315182897191424, + "test_b_norm": -0.1139637274324231, + "Rcs_pct": 3.8159820415743932, + "Rhs": 0.002400965905842326, + "Rf_h": 84.18920436335856 + }, + { + "bin": 10, + "ref_a": -20.196747504457814, + "ref_b": -11.155645978902756, + "test_a": -19.571913022466653, + "test_b": -11.983094867927717, + "ref_a_norm": -0.8753463645436907, + "ref_b_norm": -0.48349637235468895, + "test_a_norm": -0.8482654401457509, + "test_b_norm": -0.5193587990495737, + "Rcs_pct": -0.25928689544241135, + "Rhs": 0.04486387349837399, + "Rf_h": 78.41799259263864 + }, + { + "bin": 11, + "ref_a": -12.180252597877518, + "ref_b": -17.29419405143065, + "test_a": -8.685736053966526, + "test_b": -19.136347393141005, + "ref_a_norm": -0.5758178906963753, + "ref_b_norm": -0.8175779820628593, + "test_a_norm": -0.4106156398276985, + "test_b_norm": -0.9046652442554165, + "Rcs_pct": -1.937104087873796, + "Rhs": 0.18574374203064478, + "Rf_h": 70.11612314013637 + }, + { + "bin": 12, + "ref_a": -5.5063114456196685, + "ref_b": -23.660299840104926, + "test_a": 0.33801652790105613, + "test_b": -25.549448307177354, + "ref_a_norm": -0.22666642762606753, + "ref_b_norm": -0.973972448577082, + "test_a_norm": 0.013914396164214258, + "test_b_norm": -1.051738942266285, + "Rcs_pct": 2.9337241934789535, + "Rhs": 0.2511296210166835, + "Rf_h": 57.44257228382194 + }, + { + "bin": 13, + "ref_a": 3.5184320625342473, + "ref_b": -15.384072281892932, + "test_a": 8.171211821546612, + "test_b": -15.810559390232124, + "ref_a_norm": 0.22294961668953173, + "ref_b_norm": -0.9748299689781756, + "test_a_norm": 0.517778519273329, + "test_b_norm": -1.0018548299495602, + "Rcs_pct": 8.40238513904124, + "Rhs": 0.2838915590622778, + "Rf_h": 68.25214199751044 + }, + { + "bin": 14, + "ref_a": 13.818253230994431, + "ref_b": -18.69223347630265, + "test_a": 19.465715586791525, + "test_b": -18.5055601512992, + "ref_a_norm": 0.5944537830128539, + "ref_b_norm": -0.8041297779971259, + "test_a_norm": 0.8374045601990865, + "test_b_norm": -0.7960991924823818, + "Rcs_pct": 12.82990320691419, + "Rhs": 0.2064677427813491, + "Rf_h": 61.93860124627672 + }, + { + "bin": 15, + "ref_a": 15.249684263415222, + "ref_b": -11.146224476355433, + "test_a": 18.69153846700258, + "test_b": -10.85760757482259, + "ref_a_norm": 0.8073350187996868, + "ref_b_norm": -0.5900933548343934, + "test_a_norm": 0.9895505571780975, + "test_b_norm": -0.5748136593600464, + "Rcs_pct": 14.301773907584508, + "Rhs": 0.11393813158884211, + "Rf_h": 76.24421565028895 + }, + { + "bin": 16, + "ref_a": 20.000399536628798, + "ref_b": -3.7137039513672825, + "test_a": 21.4803892244034, + "test_b": -2.9898158247964486, + "ref_a_norm": 0.9831945245209823, + "ref_b_norm": -0.18256102254303758, + "test_a_norm": 1.0559489589862838, + "test_b_norm": -0.14697559130668933, + "Rcs_pct": 6.441410516864719, + "Rhs": 0.049095353201348696, + "Rf_h": 81.87695242384159 + } + ] + } +} \ No newline at end of file diff --git a/crates/tm30/tests/golden/lamp_L0006.json b/crates/tm30/tests/golden/lamp_L0006.json new file mode 100644 index 0000000..a561e6d --- /dev/null +++ b/crates/tm30/tests/golden/lamp_L0006.json @@ -0,0 +1,941 @@ +{ + "name": "lamp_L0006", + "source": "L0006/spd.csv", + "generator": "crates/tm30/tools/golden.py (tm30.py + colour-science 0.4.7, numpy 2.5.1)", + "wavelengths": [ + 380.0, + 381.92, + 383.84, + 385.76, + 387.68, + 389.6, + 391.52, + 393.44, + 395.36, + 397.28, + 399.2, + 401.12, + 403.04, + 404.96, + 406.88, + 408.8, + 410.72, + 412.64, + 414.56, + 416.48, + 418.4, + 420.32, + 422.23, + 424.15, + 426.07, + 427.99, + 429.91, + 431.83, + 433.75, + 435.67, + 437.59, + 439.51, + 441.43, + 443.35, + 445.27, + 447.19, + 449.11, + 451.03, + 452.95, + 454.87, + 456.79, + 458.71, + 460.63, + 462.55, + 464.47, + 466.39, + 468.31, + 470.23, + 472.15, + 474.07, + 475.99, + 477.91, + 479.83, + 481.75, + 483.67, + 485.59, + 487.51, + 489.43, + 491.35, + 493.27, + 495.19, + 497.11, + 499.03, + 500.95, + 502.87, + 504.79, + 506.7, + 508.62, + 510.54, + 512.46, + 514.38, + 516.3, + 518.22, + 520.14, + 522.06, + 523.98, + 525.9, + 527.82, + 529.74, + 531.66, + 533.58, + 535.5, + 537.42, + 539.34, + 541.26, + 543.18, + 545.1, + 547.02, + 548.94, + 550.86, + 552.78, + 554.7, + 556.62, + 558.54, + 560.46, + 562.38, + 564.3, + 566.22, + 568.14, + 570.06, + 571.98, + 573.9, + 575.82, + 577.74, + 579.66, + 581.58, + 583.5, + 585.42, + 587.34, + 589.26, + 591.17, + 593.09, + 595.01, + 596.93, + 598.85, + 600.77, + 602.69, + 604.61, + 606.53, + 608.45, + 610.37, + 612.29, + 614.21, + 616.13, + 618.05, + 619.97, + 621.89, + 623.81, + 625.73, + 627.65, + 629.57, + 631.49, + 633.41, + 635.33, + 637.25, + 639.17, + 641.09, + 643.01, + 644.93, + 646.85, + 648.77, + 650.69, + 652.61, + 654.53, + 656.45, + 658.37, + 660.29, + 662.21, + 664.13, + 666.05, + 667.97, + 669.89, + 671.81, + 673.72, + 675.64, + 677.56, + 679.48, + 681.4, + 683.32, + 685.24, + 687.16, + 689.08, + 691.0, + 692.92, + 694.84, + 696.76, + 698.68, + 700.6, + 702.52, + 704.44, + 706.36, + 708.28, + 710.2, + 712.12, + 714.04, + 715.96, + 717.88, + 719.8, + 721.72, + 723.64, + 725.56, + 727.48, + 729.4, + 731.32, + 733.24, + 735.16, + 737.08, + 739.0, + 740.92, + 742.84, + 744.76, + 746.68, + 748.6, + 750.52, + 752.44, + 754.36, + 756.28, + 758.19, + 760.11, + 762.03, + 763.95, + 765.87, + 767.79, + 769.71, + 771.63, + 773.55, + 775.47, + 777.39, + 779.31, + 781.23, + 783.15, + 785.07, + 786.99, + 788.91, + 790.83, + 792.75, + 794.67, + 796.59, + 798.51, + 800.43, + 802.35, + 804.27, + 806.19, + 808.11, + 810.03, + 811.95, + 813.87, + 815.79, + 817.71, + 819.63, + 821.55, + 823.47, + 825.39, + 827.31, + 829.23, + 831.15, + 833.07, + 834.99, + 836.91, + 838.83, + 840.74, + 842.66, + 844.58, + 846.5, + 848.42, + 850.34, + 852.26, + 854.18, + 856.1, + 858.02, + 859.94, + 861.86, + 863.78, + 865.7, + 867.62, + 869.54, + 871.46, + 873.38, + 875.3, + 877.22, + 879.14, + 881.06, + 882.98, + 884.9, + 886.82, + 888.74, + 890.66, + 892.58, + 894.5, + 896.42, + 898.34, + 900.26, + 902.18, + 904.1, + 906.02, + 907.94, + 909.86, + 911.78, + 913.7, + 915.62, + 917.54, + 919.46, + 921.38, + 923.3, + 925.21, + 927.13, + 929.05, + 930.97, + 932.89, + 934.81, + 936.73, + 938.65, + 940.57, + 942.49, + 944.41, + 946.33, + 948.25, + 950.17, + 952.09, + 954.01, + 955.93, + 957.85, + 959.77, + 961.69, + 963.61, + 965.53, + 967.45, + 969.37, + 971.29, + 973.21, + 975.13, + 977.05, + 978.97, + 980.89, + 982.81, + 984.73, + 986.65, + 988.57, + 990.49, + 992.41, + 994.33, + 996.25, + 998.17, + 1000.09, + 1002.01, + 1003.93, + 1005.85, + 1007.77, + 1009.68, + 1011.6, + 1013.52, + 1015.44, + 1017.36, + 1019.28, + 1021.2, + 1023.12, + 1025.04, + 1026.96, + 1028.88, + 1030.8, + 1032.72, + 1034.64, + 1036.56, + 1038.48, + 1040.4, + 1042.32, + 1044.24, + 1046.16, + 1048.08, + 1050.0 + ], + "values": [ + 0.0669453, + 0.163875, + 0.313751, + 0.511868, + 0.755586, + 1.0572, + 1.47399, + 1.98458, + 2.53148, + 3.16485, + 3.89114, + 4.71973, + 5.66192, + 6.72009, + 7.89749, + 9.1821, + 10.5907, + 12.124, + 13.7944, + 15.6171, + 17.5852, + 19.7007, + 21.9446, + 24.2857, + 26.6967, + 29.1927, + 31.7418, + 34.3268, + 36.8831, + 39.319, + 41.6882, + 43.6426, + 44.9828, + 45.8038, + 46.0636, + 45.7236, + 44.797, + 43.3186, + 41.3762, + 39.0963, + 36.6166, + 34.0631, + 31.5347, + 29.1115, + 26.8459, + 24.7802, + 22.9186, + 21.2544, + 19.7441, + 18.3524, + 17.0529, + 15.8312, + 14.6898, + 13.616, + 12.6089, + 11.6733, + 10.8191, + 10.0561, + 9.38411, + 8.7985, + 8.2961, + 7.87779, + 7.54223, + 7.28474, + 7.0951, + 6.965, + 6.87107, + 6.82273, + 6.81647, + 6.85261, + 6.93125, + 7.05107, + 7.21512, + 7.42497, + 7.70844, + 8.04881, + 8.40537, + 8.80086, + 9.2363, + 9.70982, + 10.2168, + 10.7529, + 11.3089, + 11.8855, + 12.4838, + 13.0986, + 13.7266, + 14.3625, + 15.0024, + 15.6426, + 16.2794, + 16.9017, + 17.5088, + 18.0996, + 18.6757, + 19.2328, + 19.7619, + 20.2581, + 20.7218, + 21.1582, + 21.5639, + 21.9379, + 22.2755, + 22.5737, + 22.8325, + 23.0587, + 23.2452, + 23.3903, + 23.4995, + 23.572, + 23.6232, + 23.6861, + 23.7386, + 23.7502, + 23.7374, + 23.6998, + 23.6434, + 23.5765, + 23.5028, + 23.4193, + 23.3304, + 23.2373, + 23.1452, + 23.0501, + 22.95, + 22.8418, + 22.7265, + 22.6117, + 22.4943, + 22.369, + 22.2317, + 22.0863, + 21.9411, + 21.8044, + 21.6739, + 21.5391, + 21.3982, + 21.2522, + 21.1031, + 20.9562, + 20.8107, + 20.665, + 20.5196, + 20.3779, + 20.241, + 20.1076, + 19.9785, + 19.8512, + 19.7257, + 19.6057, + 19.4925, + 19.389, + 19.2923, + 19.2021, + 19.1202, + 19.0468, + 18.9819, + 18.926, + 18.8996, + 18.877, + 18.8386, + 18.7999, + 18.7577, + 18.7136, + 18.6669, + 18.6186, + 18.5694, + 18.5234, + 18.4832, + 18.4504, + 18.4205, + 18.3865, + 18.3476, + 18.3037, + 18.2571, + 18.2095, + 18.1606, + 18.1075, + 18.0531, + 17.9959, + 17.934, + 17.8698, + 17.803, + 17.7564, + 17.7091, + 17.6361, + 17.5555, + 17.467, + 17.3702, + 17.2684, + 17.1626, + 17.0515, + 16.9357, + 16.8119, + 16.6794, + 16.5378, + 16.3875, + 16.2316, + 16.0723, + 15.9147, + 15.756, + 15.5943, + 15.43, + 15.2924, + 15.1537, + 14.9785, + 14.7946, + 14.605, + 14.411, + 14.2173, + 14.0226, + 13.8246, + 13.6239, + 13.4209, + 13.2176, + 13.0154, + 12.813, + 12.6123, + 12.4117, + 12.211, + 12.0103, + 11.839, + 11.6652, + 11.4581, + 11.2511, + 11.0464, + 10.8412, + 10.6323, + 10.4203, + 10.2057, + 9.99083, + 9.77735, + 9.56494, + 9.35455, + 9.14557, + 8.93746, + 8.76077, + 8.58575, + 8.38115, + 8.17659, + 7.97268, + 7.76892, + 7.56779, + 7.37057, + 7.17686, + 6.98644, + 6.79795, + 6.61191, + 6.42891, + 6.24883, + 6.09658, + 5.9467, + 5.7761, + 5.61235, + 5.45454, + 5.29872, + 5.14378, + 4.98911, + 4.83568, + 4.68665, + 4.54268, + 4.40534, + 4.27449, + 4.16466, + 4.0553, + 3.92899, + 3.80348, + 3.68079, + 3.56245, + 3.44853, + 3.33833, + 3.23081, + 3.12464, + 3.01954, + 2.91594, + 2.8132, + 2.72563, + 2.63881, + 2.54206, + 2.44968, + 2.35992, + 2.2717, + 2.18279, + 2.09435, + 2.00787, + 1.925, + 1.84601, + 1.78039, + 1.71697, + 1.64524, + 1.57448, + 1.50643, + 1.44145, + 1.38011, + 1.32255, + 1.26745, + 1.21516, + 1.1648, + 1.1165, + 1.07485, + 1.03236, + 0.982946, + 0.931908, + 0.881221, + 0.833176, + 0.787097, + 0.745055, + 0.706045, + 0.668745, + 0.638866, + 0.610578, + 0.580288, + 0.553642, + 0.529344, + 0.50625, + 0.484188, + 0.462953, + 0.442639, + 0.423579, + 0.407689, + 0.391627, + 0.372637, + 0.352837, + 0.332526, + 0.312197, + 0.29295, + 0.275388, + 0.258521, + 0.242349, + 0.229266, + 0.216255, + 0.201291, + 0.186376, + 0.170702, + 0.155421, + 0.14132, + 0.128523, + 0.117341, + 0.106461, + 0.0965479, + 0.0866375, + 0.0756172, + 0.0657833, + 0.0566462, + 0.0477552, + 0.0381855, + 0.0296612, + 0.0229959, + 0.0181043, + 0.0139494 + ], + "expected": { + "Rf": 66.2261955710554, + "Rg": 113.31608017250115, + "CCT_K": 5663.99730371379, + "Duv": -0.058905469260830165, + "bins": [ + { + "bin": 1, + "ref_a": 24.137871836687623, + "ref_b": 5.245217921445655, + "test_a": 23.831141713435752, + "test_b": 6.791190434233697, + "ref_a_norm": 0.9771943907006746, + "ref_b_norm": 0.2123467041965502, + "test_a_norm": 0.9647767692165353, + "test_b_norm": 0.27493364963627764, + "Rcs_pct": 0.003108697057946774, + "Rhs": 0.06380691260669989, + "Rf_h": 78.11672512297143 + }, + { + "bin": 2, + "ref_a": 18.80488318569917, + "ref_b": 12.0863628519726, + "test_a": 16.11370737850314, + "test_b": 14.74133380274794, + "ref_a_norm": 0.8412291523950644, + "ref_b_norm": 0.5406787522741039, + "test_a_norm": 0.7208404469254511, + "test_b_norm": 0.6594478475404204, + "Rcs_pct": -3.41149763297898, + "Rhs": 0.16563727474528947, + "Rf_h": 64.21506127669781 + }, + { + "bin": 3, + "ref_a": 13.73614831592917, + "ref_b": 20.670927713097903, + "test_a": 9.025580591342578, + "test_b": 24.53417274634546, + "ref_a_norm": 0.5534591036443446, + "ref_b_norm": 0.8328763537243681, + "test_a_norm": 0.3636601490507679, + "test_b_norm": 0.988534845761772, + "Rcs_pct": 2.3978656595508734, + "Rhs": 0.24429128788404997, + "Rf_h": 54.385433932796836 + }, + { + "bin": 4, + "ref_a": 3.986049101838091, + "ref_b": 22.173704076869456, + "test_a": -1.8498340634360653, + "test_b": 25.5173101015619, + "ref_a_norm": 0.17692866699142445, + "ref_b_norm": 0.9842236772180588, + "test_a_norm": -0.08210854072222798, + "test_b_norm": 1.1326362385737467, + "Rcs_pct": 9.502520333758477, + "Rhs": 0.283013734788424, + "Rf_h": 53.03071562371346 + }, + { + "bin": 5, + "ref_a": -1.595677678530143, + "ref_b": 21.584238839112253, + "test_a": -6.9105734631112625, + "test_b": 24.616255366461893, + "ref_a_norm": -0.07372671446045784, + "ref_b_norm": 0.9972784824585689, + "test_a_norm": -0.3192962359053247, + "test_b_norm": 1.137369817794669, + "Rcs_pct": 18.53077566257054, + "Rhs": 0.21352050822640167, + "Rf_h": 57.91443753438172 + }, + { + "bin": 6, + "ref_a": -9.410261405559504, + "ref_b": 16.34174116665616, + "test_a": -11.703426716652366, + "test_b": 17.827004915213216, + "ref_a_norm": -0.4990194099639093, + "ref_b_norm": 0.866590807982217, + "test_a_norm": -0.6206243209406863, + "test_b_norm": 0.9453532788109068, + "Rcs_pct": 13.304866981161725, + "Rhs": 0.05735270391245155, + "Rf_h": 79.29145385666864 + }, + { + "bin": 7, + "ref_a": -17.782814058235182, + "ref_b": 12.339796201656608, + "test_a": -19.047190740943496, + "test_b": 12.758803903916373, + "ref_a_norm": -0.8215729501607355, + "ref_b_norm": 0.5701034007653222, + "test_a_norm": -0.8799876463907766, + "test_b_norm": 0.5894617201493235, + "Rcs_pct": 5.932495083820079, + "Rhs": 0.01635761208324874, + "Rf_h": 78.95856981040056 + }, + { + "bin": 8, + "ref_a": -24.181339838997125, + "ref_b": 2.325391437407178, + "test_a": -25.282877025448848, + "test_b": 1.1894550908381312, + "ref_a_norm": -0.9954079991393834, + "ref_b_norm": 0.09572311763272964, + "test_a_norm": -1.040752009605472, + "test_b_norm": 0.0489630897179617, + "Rcs_pct": 3.5350309116214627, + "Rhs": 0.054707724693380526, + "Rf_h": 77.6749248247379 + }, + { + "bin": 9, + "ref_a": -15.608146987850896, + "ref_b": -3.07803880663944, + "test_a": -14.605122413099265, + "test_b": -4.339389890864708, + "ref_a_norm": -0.9811040665209425, + "ref_b_norm": -0.1934807759341222, + "test_a_norm": -0.9180554874759573, + "test_b_norm": -0.27276736126723516, + "Rcs_pct": -4.636907281346477, + "Rhs": 0.09006328341669734, + "Rf_h": 78.93304537659641 + }, + { + "bin": 10, + "ref_a": -19.98347128613966, + "ref_b": -11.452541507066172, + "test_a": -16.297261829974268, + "test_b": -14.649278421760709, + "ref_a_norm": -0.8676175047710867, + "ref_b_norm": -0.4972322047241042, + "test_a_norm": -0.7075742467891736, + "test_b_norm": -0.6360241526105858, + "Rcs_pct": -5.596243083732057, + "Rhs": 0.20431655723011566, + "Rf_h": 60.166996690230135 + }, + { + "bin": 11, + "ref_a": -13.152287300778541, + "ref_b": -19.04418234301879, + "test_a": -7.123091197937318, + "test_b": -22.22953929345084, + "ref_a_norm": -0.5682706714506753, + "ref_b_norm": -0.8228416882784918, + "test_a_norm": -0.3077672898474948, + "test_b_norm": -0.9604713561557245, + "Rcs_pct": -3.0293037828462475, + "Rhs": 0.2930635923580632, + "Rf_h": 51.070934843310475 + }, + { + "bin": 12, + "ref_a": -3.4619450431168515, + "ref_b": -20.760474255403157, + "test_a": 3.5340876143841546, + "test_b": -22.566408203880897, + "ref_a_norm": -0.16448524863841626, + "ref_b_norm": -0.9863795430666424, + "test_a_norm": 0.16791291390303684, + "test_b_norm": -1.0721837631915463, + "Rcs_pct": 1.930785152720271, + "Rhs": 0.34275079798824787, + "Rf_h": 50.52187461801259 + }, + { + "bin": 13, + "ref_a": 2.2819731618288905, + "ref_b": -15.716754039587299, + "test_a": 8.037629789805495, + "test_b": -16.459138524342286, + "ref_a_norm": 0.14368701920500257, + "ref_b_norm": -0.9896231810704422, + "test_a_norm": 0.5060984437892706, + "test_b_norm": -1.0363682591909027, + "Rcs_pct": 11.654984607631548, + "Rhs": 0.34632827833902585, + "Rf_h": 60.610861156202624 + }, + { + "bin": 14, + "ref_a": 13.076433819156223, + "ref_b": -18.38981536231859, + "test_a": 19.133709095242263, + "test_b": -18.216568627266636, + "ref_a_norm": 0.5795011753277554, + "ref_b_norm": -0.814971403052739, + "test_a_norm": 0.8479381353063525, + "test_b_norm": -0.8072937221213196, + "Rcs_pct": 14.275182601895281, + "Rhs": 0.22746266602519696, + "Rf_h": 59.13894282083309 + }, + { + "bin": 15, + "ref_a": 12.67005034053983, + "ref_b": -8.135393293395426, + "test_a": 16.22061946545897, + "test_b": -8.016121356041813, + "ref_a_norm": 0.8414695497474654, + "ref_b_norm": -0.5403045408358121, + "test_a_norm": 1.0772772792032321, + "test_b_norm": -0.5323832066086447, + "Rcs_pct": 19.16661038861162, + "Rhs": 0.13759410390034538, + "Rf_h": 75.90520693288063 + }, + { + "bin": 16, + "ref_a": 22.797108190154802, + "ref_b": -3.422857409327071, + "test_a": 23.79931219830089, + "test_b": -2.4307183314980056, + "ref_a_norm": 0.9889153990387736, + "ref_b_norm": -0.14848007793634627, + "test_a_norm": 1.0323899910075067, + "test_b_norm": -0.10544209242215688, + "Rcs_pct": 3.4242945421581332, + "Rhs": 0.050692494837224385, + "Rf_h": 80.12814101747786 + } + ] + } +} \ No newline at end of file diff --git a/crates/tm30/tests/golden/lamp_L0007.json b/crates/tm30/tests/golden/lamp_L0007.json new file mode 100644 index 0000000..8effa67 --- /dev/null +++ b/crates/tm30/tests/golden/lamp_L0007.json @@ -0,0 +1,941 @@ +{ + "name": "lamp_L0007", + "source": "L0007/spd.csv", + "generator": "crates/tm30/tools/golden.py (tm30.py + colour-science 0.4.7, numpy 2.5.1)", + "wavelengths": [ + 380.0, + 381.92, + 383.84, + 385.76, + 387.68, + 389.6, + 391.52, + 393.44, + 395.36, + 397.28, + 399.2, + 401.12, + 403.04, + 404.96, + 406.88, + 408.8, + 410.72, + 412.64, + 414.56, + 416.48, + 418.4, + 420.32, + 422.23, + 424.15, + 426.07, + 427.99, + 429.91, + 431.83, + 433.75, + 435.67, + 437.59, + 439.51, + 441.43, + 443.35, + 445.27, + 447.19, + 449.11, + 451.03, + 452.95, + 454.87, + 456.79, + 458.71, + 460.63, + 462.55, + 464.47, + 466.39, + 468.31, + 470.23, + 472.15, + 474.07, + 475.99, + 477.91, + 479.83, + 481.75, + 483.67, + 485.59, + 487.51, + 489.43, + 491.35, + 493.27, + 495.19, + 497.11, + 499.03, + 500.95, + 502.87, + 504.79, + 506.7, + 508.62, + 510.54, + 512.46, + 514.38, + 516.3, + 518.22, + 520.14, + 522.06, + 523.98, + 525.9, + 527.82, + 529.74, + 531.66, + 533.58, + 535.5, + 537.42, + 539.34, + 541.26, + 543.18, + 545.1, + 547.02, + 548.94, + 550.86, + 552.78, + 554.7, + 556.62, + 558.54, + 560.46, + 562.38, + 564.3, + 566.22, + 568.14, + 570.06, + 571.98, + 573.9, + 575.82, + 577.74, + 579.66, + 581.58, + 583.5, + 585.42, + 587.34, + 589.26, + 591.17, + 593.09, + 595.01, + 596.93, + 598.85, + 600.77, + 602.69, + 604.61, + 606.53, + 608.45, + 610.37, + 612.29, + 614.21, + 616.13, + 618.05, + 619.97, + 621.89, + 623.81, + 625.73, + 627.65, + 629.57, + 631.49, + 633.41, + 635.33, + 637.25, + 639.17, + 641.09, + 643.01, + 644.93, + 646.85, + 648.77, + 650.69, + 652.61, + 654.53, + 656.45, + 658.37, + 660.29, + 662.21, + 664.13, + 666.05, + 667.97, + 669.89, + 671.81, + 673.72, + 675.64, + 677.56, + 679.48, + 681.4, + 683.32, + 685.24, + 687.16, + 689.08, + 691.0, + 692.92, + 694.84, + 696.76, + 698.68, + 700.6, + 702.52, + 704.44, + 706.36, + 708.28, + 710.2, + 712.12, + 714.04, + 715.96, + 717.88, + 719.8, + 721.72, + 723.64, + 725.56, + 727.48, + 729.4, + 731.32, + 733.24, + 735.16, + 737.08, + 739.0, + 740.92, + 742.84, + 744.76, + 746.68, + 748.6, + 750.52, + 752.44, + 754.36, + 756.28, + 758.19, + 760.11, + 762.03, + 763.95, + 765.87, + 767.79, + 769.71, + 771.63, + 773.55, + 775.47, + 777.39, + 779.31, + 781.23, + 783.15, + 785.07, + 786.99, + 788.91, + 790.83, + 792.75, + 794.67, + 796.59, + 798.51, + 800.43, + 802.35, + 804.27, + 806.19, + 808.11, + 810.03, + 811.95, + 813.87, + 815.79, + 817.71, + 819.63, + 821.55, + 823.47, + 825.39, + 827.31, + 829.23, + 831.15, + 833.07, + 834.99, + 836.91, + 838.83, + 840.74, + 842.66, + 844.58, + 846.5, + 848.42, + 850.34, + 852.26, + 854.18, + 856.1, + 858.02, + 859.94, + 861.86, + 863.78, + 865.7, + 867.62, + 869.54, + 871.46, + 873.38, + 875.3, + 877.22, + 879.14, + 881.06, + 882.98, + 884.9, + 886.82, + 888.74, + 890.66, + 892.58, + 894.5, + 896.42, + 898.34, + 900.26, + 902.18, + 904.1, + 906.02, + 907.94, + 909.86, + 911.78, + 913.7, + 915.62, + 917.54, + 919.46, + 921.38, + 923.3, + 925.21, + 927.13, + 929.05, + 930.97, + 932.89, + 934.81, + 936.73, + 938.65, + 940.57, + 942.49, + 944.41, + 946.33, + 948.25, + 950.17, + 952.09, + 954.01, + 955.93, + 957.85, + 959.77, + 961.69, + 963.61, + 965.53, + 967.45, + 969.37, + 971.29, + 973.21, + 975.13, + 977.05, + 978.97, + 980.89, + 982.81, + 984.73, + 986.65, + 988.57, + 990.49, + 992.41, + 994.33, + 996.25, + 998.17, + 1000.09, + 1002.01, + 1003.93, + 1005.85, + 1007.77, + 1009.68, + 1011.6, + 1013.52, + 1015.44, + 1017.36, + 1019.28, + 1021.2, + 1023.12, + 1025.04, + 1026.96, + 1028.88, + 1030.8, + 1032.72, + 1034.64, + 1036.56, + 1038.48, + 1040.4, + 1042.32, + 1044.24, + 1046.16, + 1048.08, + 1050.0 + ], + "values": [ + 7.65453e-05, + 0.00573809, + 0.0323325, + 0.0899079, + 0.182169, + 0.304299, + 0.468838, + 0.658778, + 0.856732, + 1.0862, + 1.34785, + 1.65035, + 2.00432, + 2.41366, + 2.88649, + 3.42693, + 4.04355, + 4.74347, + 5.5351, + 6.42968, + 7.43385, + 8.56098, + 9.81607, + 11.192, + 12.6827, + 14.3139, + 16.1075, + 18.1027, + 20.3329, + 22.8219, + 25.9101, + 29.3586, + 32.8126, + 36.5561, + 40.5351, + 44.632, + 48.6947, + 52.5042, + 55.8454, + 58.507, + 60.3133, + 61.141, + 60.9102, + 59.6678, + 57.5565, + 54.8276, + 51.7486, + 48.5827, + 45.4909, + 42.6063, + 40.011, + 37.7404, + 35.8039, + 34.1287, + 32.6315, + 31.2354, + 29.8896, + 28.5683, + 27.2505, + 25.9248, + 24.5993, + 23.3166, + 22.1206, + 21.0491, + 20.122, + 19.3446, + 18.672, + 18.1407, + 17.7369, + 17.4472, + 17.2564, + 17.1434, + 17.0972, + 17.1049, + 17.1459, + 17.2285, + 17.3491, + 17.4945, + 17.672, + 17.8813, + 18.1199, + 18.3859, + 18.6718, + 18.9832, + 19.3208, + 19.6765, + 20.0431, + 20.4164, + 20.7931, + 21.1687, + 21.5416, + 21.8959, + 22.2333, + 22.5538, + 22.858, + 23.1443, + 23.4079, + 23.6481, + 23.8694, + 24.0747, + 24.26, + 24.4248, + 24.569, + 24.6932, + 24.7968, + 24.8859, + 24.9547, + 25.0005, + 25.0302, + 25.0429, + 25.0495, + 25.0886, + 25.13, + 25.1432, + 25.1493, + 25.1452, + 25.1376, + 25.1342, + 25.1374, + 25.1444, + 25.1558, + 25.1722, + 25.2028, + 25.2427, + 25.2893, + 25.3374, + 25.3823, + 25.4323, + 25.4843, + 25.5319, + 25.57, + 25.5988, + 25.6281, + 25.6671, + 25.7161, + 25.7637, + 25.8058, + 25.8384, + 25.8624, + 25.8814, + 25.8929, + 25.8958, + 25.893, + 25.8883, + 25.8868, + 25.883, + 25.8768, + 25.867, + 25.8538, + 25.8405, + 25.8306, + 25.8212, + 25.8099, + 25.7998, + 25.7914, + 25.7882, + 25.7909, + 25.7988, + 25.8322, + 25.8655, + 25.8781, + 25.8822, + 25.8704, + 25.8449, + 25.8052, + 25.7502, + 25.6821, + 25.6098, + 25.5388, + 25.474, + 25.4103, + 25.3356, + 25.2479, + 25.1465, + 25.0352, + 24.9181, + 24.7952, + 24.6651, + 24.5289, + 24.3826, + 24.2256, + 24.0619, + 23.8938, + 23.7611, + 23.626, + 23.4438, + 23.2522, + 23.0526, + 22.8435, + 22.6289, + 22.4075, + 22.1786, + 21.9463, + 21.7051, + 21.4573, + 21.2012, + 20.9358, + 20.666, + 20.3911, + 20.1185, + 19.8471, + 19.5754, + 19.3046, + 19.0791, + 18.852, + 18.5739, + 18.2858, + 17.9905, + 17.6937, + 17.4014, + 17.1132, + 16.8239, + 16.5325, + 16.2383, + 15.9454, + 15.6557, + 15.3674, + 15.0813, + 14.7956, + 14.5111, + 14.2275, + 13.987, + 13.7435, + 13.456, + 13.1687, + 12.8856, + 12.6065, + 12.3268, + 12.0455, + 11.7622, + 11.48, + 11.2006, + 10.9254, + 10.6534, + 10.3841, + 10.117, + 9.88937, + 9.66353, + 9.40087, + 9.14133, + 8.88605, + 8.63396, + 8.38617, + 8.1421, + 7.90278, + 7.66962, + 7.44208, + 7.21898, + 7.00177, + 6.78982, + 6.61167, + 6.43804, + 6.23946, + 6.04722, + 5.86256, + 5.68348, + 5.50842, + 5.33613, + 5.1659, + 5.00014, + 4.8406, + 4.68716, + 4.54063, + 4.41901, + 4.29966, + 4.16291, + 4.02667, + 3.89014, + 3.75404, + 3.62058, + 3.49027, + 3.36358, + 3.242, + 3.12391, + 3.00915, + 2.8966, + 2.80025, + 2.70488, + 2.59752, + 2.49443, + 2.39421, + 2.29738, + 2.20284, + 2.10992, + 2.02075, + 1.9354, + 1.85317, + 1.7855, + 1.72001, + 1.64671, + 1.57718, + 1.51042, + 1.4467, + 1.38515, + 1.32559, + 1.26906, + 1.21468, + 1.16335, + 1.11425, + 1.07152, + 1.02729, + 0.974108, + 0.918747, + 0.86344, + 0.811792, + 0.763925, + 0.720675, + 0.681858, + 0.646341, + 0.617549, + 0.590002, + 0.559121, + 0.529449, + 0.501852, + 0.475652, + 0.450707, + 0.426104, + 0.402752, + 0.38097, + 0.363142, + 0.346161, + 0.32586, + 0.30444, + 0.283281, + 0.262832, + 0.242857, + 0.223307, + 0.204383, + 0.186521, + 0.172201, + 0.159415, + 0.145596, + 0.132675, + 0.119765, + 0.105957, + 0.0919631, + 0.0791472, + 0.0684043, + 0.0603321, + 0.0541161, + 0.047719, + 0.0389463, + 0.0287361, + 0.017758, + 0.00865738, + 0.00292152, + 0.000522782, + 9.0514e-05, + 0.0, + 0.0 + ], + "expected": { + "Rf": 82.95259755330265, + "Rg": 103.54865605474023, + "CCT_K": 7971.408129908118, + "Duv": -0.02879956235826263, + "bins": [ + { + "bin": 1, + "ref_a": 23.482869738648983, + "ref_b": 4.439511825880721, + "test_a": 25.018453335975245, + "test_b": 6.431311785366751, + "ref_a_norm": 0.9825946423527376, + "ref_b_norm": 0.1857626679925102, + "test_a_norm": 1.0468481272295966, + "test_b_norm": 0.26910563205998334, + "Rcs_pct": 7.927827787953667, + "Rhs": 0.06920631932726815, + "Rf_h": 74.90988914306404 + }, + { + "bin": 2, + "ref_a": 22.005596243444362, + "ref_b": 13.76920992227529, + "test_a": 22.728331436086403, + "test_b": 15.583669519996926, + "ref_a_norm": 0.8477261531777264, + "ref_b_norm": 0.5304341327803989, + "test_a_norm": 0.8755682310676688, + "test_b_norm": 0.6003329366054122, + "Rcs_pct": 6.198353643770171, + "Rhs": 0.04265050161573028, + "Rf_h": 77.5482239883905 + }, + { + "bin": 3, + "ref_a": 11.654856135365176, + "ref_b": 18.54388299414296, + "test_a": 13.265433430742833, + "test_b": 19.093977534533895, + "ref_a_norm": 0.5321290359986146, + "ref_b_norm": 0.8466632678031952, + "test_a_norm": 0.6056636153736449, + "test_b_norm": 0.8717790885466279, + "Rcs_pct": 6.1736665134586195, + "Rhs": -0.0471881658208797, + "Rf_h": 83.32692937585968 + }, + { + "bin": 4, + "ref_a": 4.454277197937342, + "ref_b": 22.9592962636539, + "test_a": 5.39917056765465, + "test_b": 22.82339213897038, + "ref_a_norm": 0.19045638572640128, + "ref_b_norm": 0.9816956581018561, + "test_a_norm": 0.23085822155658575, + "test_b_norm": 0.9758846572946949, + "Rcs_pct": 0.21826631060784757, + "Rhs": -0.040759195902217826, + "Rf_h": 89.46489353931761 + }, + { + "bin": 5, + "ref_a": -1.772441538931332, + "ref_b": 21.836697882394965, + "test_a": -0.5785314684596293, + "test_b": 20.516629589530545, + "ref_a_norm": -0.08090195683323384, + "ref_b_norm": 0.9967220642589155, + "test_a_norm": -0.02640669768787314, + "test_b_norm": 0.9364683939964655, + "Rcs_pct": -6.972741053870161, + "Rhs": -0.0416932400873743, + "Rf_h": 86.62470415436573 + }, + { + "bin": 6, + "ref_a": -10.844808637633825, + "ref_b": 17.131269348836568, + "test_a": -10.396785788032924, + "test_b": 15.903180728411904, + "ref_a_norm": -0.5348762290781177, + "ref_b_norm": 0.8449304229149125, + "test_a_norm": -0.5127793179806022, + "test_b_norm": 0.7843599294912671, + "Rcs_pct": -6.263891073139241, + "Rhs": 0.0152782530421519, + "Rf_h": 87.36502187121428 + }, + { + "bin": 7, + "ref_a": -18.40696637908179, + "ref_b": 10.60733158088937, + "test_a": -18.127540051611, + "test_b": 8.540685927514154, + "ref_a_norm": -0.8664314468566428, + "ref_b_norm": 0.4992960523556188, + "test_a_norm": -0.8532786137273614, + "test_b_norm": 0.40201729676291137, + "Rcs_pct": -6.498136197518105, + "Rhs": 0.07357700663143972, + "Rf_h": 82.8001183367942 + }, + { + "bin": 8, + "ref_a": -24.870458620994196, + "ref_b": 3.164501604781179, + "test_a": -26.43660351170149, + "test_b": -0.45703014060182295, + "ref_a_norm": -0.9920020549825301, + "ref_b_norm": 0.12622172123068615, + "test_a_norm": -1.054470502937509, + "test_b_norm": -0.0182294522821244, + "Rcs_pct": 3.308710828765653, + "Rhs": 0.15386257434572215, + "Rf_h": 70.57107534599287 + }, + { + "bin": 9, + "ref_a": -12.302765561282534, + "ref_b": -2.6325314011006005, + "test_a": -12.409832354570387, + "test_b": -5.233900355069523, + "ref_a_norm": -0.9778638537174422, + "ref_b_norm": -0.20924216494978473, + "test_a_norm": -0.9863738709625984, + "test_b_norm": -0.41600743716421995, + "Rcs_pct": 4.868440318809349, + "Rhs": 0.20113211348176482, + "Rf_h": 80.3045859853857 + }, + { + "bin": 10, + "ref_a": -16.492792832685804, + "ref_b": -11.071085471152355, + "test_a": -16.62371516102908, + "test_b": -13.521572354557502, + "ref_a_norm": -0.8302827924222576, + "ref_b_norm": -0.5573423405838628, + "test_a_norm": -0.8368737050390612, + "test_b_norm": -0.6807051398979685, + "Rcs_pct": 7.401684271910183, + "Rhs": 0.09891070405992683, + "Rf_h": 81.66696392099401 + }, + { + "bin": 11, + "ref_a": -15.194870674921905, + "ref_b": -24.218117016214794, + "test_a": -15.949798924318978, + "test_b": -26.031181045295625, + "ref_a_norm": -0.5314707278634504, + "ref_b_norm": -0.8470766585287863, + "test_a_norm": -0.5578758401395248, + "test_b_norm": -0.9104921676050807, + "Rcs_pct": 6.739796312576242, + "Rhs": 0.01327672068758082, + "Rf_h": 85.53336122721569 + }, + { + "bin": 12, + "ref_a": -2.129404041470915, + "ref_b": -18.841457629017253, + "test_a": -1.5853829708265592, + "test_b": -19.072202398073642, + "ref_a_norm": -0.11230201659700799, + "ref_b_norm": -0.9936741201562236, + "test_a_norm": -0.08361104855393875, + "test_b_norm": -1.005843301006629, + "Rcs_pct": 0.6338023258165522, + "Rhs": 0.030513768547939857, + "Rf_h": 93.24852869483682 + }, + { + "bin": 13, + "ref_a": 3.565232468441208, + "ref_b": -16.71319310293632, + "test_a": 4.342352210072228, + "test_b": -16.70351217132951, + "ref_a_norm": 0.20862455071257133, + "ref_b_norm": -0.9779958061464159, + "test_a_norm": 0.2540987963284613, + "test_b_norm": -0.9774293129303837, + "Rcs_pct": 0.8315977012911819, + "Rhs": 0.04471098808144166, + "Rf_h": 90.6617137159113 + }, + { + "bin": 14, + "ref_a": 15.147703190677978, + "ref_b": -17.70330805937641, + "test_a": 16.31853720340087, + "test_b": -15.617642814665436, + "ref_a_norm": 0.6501339632714963, + "ref_b_norm": -0.7598196034592006, + "test_a_norm": 0.7003857372495507, + "test_b_norm": -0.6703036026151893, + "Rcs_pct": -4.6511444738008345, + "Rhs": 0.0915152484749382, + "Rf_h": 81.9490018308905 + }, + { + "bin": 15, + "ref_a": 13.089596581745946, + "ref_b": -7.962062936482063, + "test_a": 15.365178180644554, + "test_b": -7.539020534835222, + "ref_a_norm": 0.8543584641034702, + "ref_b_norm": -0.5196841490893863, + "test_a_norm": 1.0028857611546536, + "test_b_norm": -0.4920721555291211, + "Rcs_pct": 10.815553239908008, + "Rhs": 0.10547587861295166, + "Rf_h": 82.05345505732826 + }, + { + "bin": 16, + "ref_a": 24.370891505389828, + "ref_b": -4.006634730914093, + "test_a": 25.024596015329493, + "test_b": -1.3590301290630447, + "ref_a_norm": 0.986753832146305, + "ref_b_norm": -0.16222476612583486, + "test_a_norm": 1.0132216956683116, + "test_b_norm": -0.055025815840945624, + "Rcs_pct": 0.5045813215235608, + "Rhs": 0.11030277653168427, + "Rf_h": 76.44402680339701 + } + ] + } +} \ No newline at end of file diff --git a/crates/tm30/tests/golden/lamp_L0008.json b/crates/tm30/tests/golden/lamp_L0008.json new file mode 100644 index 0000000..20c92c3 --- /dev/null +++ b/crates/tm30/tests/golden/lamp_L0008.json @@ -0,0 +1,941 @@ +{ + "name": "lamp_L0008", + "source": "L0008/spd.csv", + "generator": "crates/tm30/tools/golden.py (tm30.py + colour-science 0.4.7, numpy 2.5.1)", + "wavelengths": [ + 380.0, + 381.92, + 383.84, + 385.76, + 387.68, + 389.6, + 391.52, + 393.44, + 395.36, + 397.28, + 399.2, + 401.12, + 403.04, + 404.96, + 406.88, + 408.8, + 410.72, + 412.64, + 414.56, + 416.48, + 418.4, + 420.32, + 422.23, + 424.15, + 426.07, + 427.99, + 429.91, + 431.83, + 433.75, + 435.67, + 437.59, + 439.51, + 441.43, + 443.35, + 445.27, + 447.19, + 449.11, + 451.03, + 452.95, + 454.87, + 456.79, + 458.71, + 460.63, + 462.55, + 464.47, + 466.39, + 468.31, + 470.23, + 472.15, + 474.07, + 475.99, + 477.91, + 479.83, + 481.75, + 483.67, + 485.59, + 487.51, + 489.43, + 491.35, + 493.27, + 495.19, + 497.11, + 499.03, + 500.95, + 502.87, + 504.79, + 506.7, + 508.62, + 510.54, + 512.46, + 514.38, + 516.3, + 518.22, + 520.14, + 522.06, + 523.98, + 525.9, + 527.82, + 529.74, + 531.66, + 533.58, + 535.5, + 537.42, + 539.34, + 541.26, + 543.18, + 545.1, + 547.02, + 548.94, + 550.86, + 552.78, + 554.7, + 556.62, + 558.54, + 560.46, + 562.38, + 564.3, + 566.22, + 568.14, + 570.06, + 571.98, + 573.9, + 575.82, + 577.74, + 579.66, + 581.58, + 583.5, + 585.42, + 587.34, + 589.26, + 591.17, + 593.09, + 595.01, + 596.93, + 598.85, + 600.77, + 602.69, + 604.61, + 606.53, + 608.45, + 610.37, + 612.29, + 614.21, + 616.13, + 618.05, + 619.97, + 621.89, + 623.81, + 625.73, + 627.65, + 629.57, + 631.49, + 633.41, + 635.33, + 637.25, + 639.17, + 641.09, + 643.01, + 644.93, + 646.85, + 648.77, + 650.69, + 652.61, + 654.53, + 656.45, + 658.37, + 660.29, + 662.21, + 664.13, + 666.05, + 667.97, + 669.89, + 671.81, + 673.72, + 675.64, + 677.56, + 679.48, + 681.4, + 683.32, + 685.24, + 687.16, + 689.08, + 691.0, + 692.92, + 694.84, + 696.76, + 698.68, + 700.6, + 702.52, + 704.44, + 706.36, + 708.28, + 710.2, + 712.12, + 714.04, + 715.96, + 717.88, + 719.8, + 721.72, + 723.64, + 725.56, + 727.48, + 729.4, + 731.32, + 733.24, + 735.16, + 737.08, + 739.0, + 740.92, + 742.84, + 744.76, + 746.68, + 748.6, + 750.52, + 752.44, + 754.36, + 756.28, + 758.19, + 760.11, + 762.03, + 763.95, + 765.87, + 767.79, + 769.71, + 771.63, + 773.55, + 775.47, + 777.39, + 779.31, + 781.23, + 783.15, + 785.07, + 786.99, + 788.91, + 790.83, + 792.75, + 794.67, + 796.59, + 798.51, + 800.43, + 802.35, + 804.27, + 806.19, + 808.11, + 810.03, + 811.95, + 813.87, + 815.79, + 817.71, + 819.63, + 821.55, + 823.47, + 825.39, + 827.31, + 829.23, + 831.15, + 833.07, + 834.99, + 836.91, + 838.83, + 840.74, + 842.66, + 844.58, + 846.5, + 848.42, + 850.34, + 852.26, + 854.18, + 856.1, + 858.02, + 859.94, + 861.86, + 863.78, + 865.7, + 867.62, + 869.54, + 871.46, + 873.38, + 875.3, + 877.22, + 879.14, + 881.06, + 882.98, + 884.9, + 886.82, + 888.74, + 890.66, + 892.58, + 894.5, + 896.42, + 898.34, + 900.26, + 902.18, + 904.1, + 906.02, + 907.94, + 909.86, + 911.78, + 913.7, + 915.62, + 917.54, + 919.46, + 921.38, + 923.3, + 925.21, + 927.13, + 929.05, + 930.97, + 932.89, + 934.81, + 936.73, + 938.65, + 940.57, + 942.49, + 944.41, + 946.33, + 948.25, + 950.17, + 952.09, + 954.01, + 955.93, + 957.85, + 959.77, + 961.69, + 963.61, + 965.53, + 967.45, + 969.37, + 971.29, + 973.21, + 975.13, + 977.05, + 978.97, + 980.89, + 982.81, + 984.73, + 986.65, + 988.57, + 990.49, + 992.41, + 994.33, + 996.25, + 998.17, + 1000.09, + 1002.01, + 1003.93, + 1005.85, + 1007.77, + 1009.68, + 1011.6, + 1013.52, + 1015.44, + 1017.36, + 1019.28, + 1021.2, + 1023.12, + 1025.04, + 1026.96, + 1028.88, + 1030.8, + 1032.72, + 1034.64, + 1036.56, + 1038.48, + 1040.4, + 1042.32, + 1044.24, + 1046.16, + 1048.08, + 1050.0 + ], + "values": [ + 0.0, + 0.0, + 0.00235407, + 0.0238872, + 0.0765528, + 0.165658, + 0.308773, + 0.481918, + 0.65961, + 0.862422, + 1.09211, + 1.35334, + 1.65196, + 1.99044, + 2.37038, + 2.78568, + 3.2388, + 3.72811, + 4.25583, + 4.8281, + 5.4395, + 6.08707, + 6.76392, + 7.45777, + 8.15872, + 8.87293, + 9.59272, + 10.3208, + 11.0516, + 11.7708, + 12.5094, + 13.1745, + 13.6934, + 14.0988, + 14.371, + 14.4853, + 14.4288, + 14.189, + 13.7741, + 13.2059, + 12.5192, + 11.7523, + 10.9397, + 10.1163, + 9.31376, + 8.56355, + 7.8802, + 7.27172, + 6.72819, + 6.23875, + 5.79561, + 5.39043, + 5.02123, + 4.67877, + 4.35805, + 4.05762, + 3.77623, + 3.51611, + 3.27873, + 3.06385, + 2.87373, + 2.7118, + 2.5776, + 2.47069, + 2.38846, + 2.32839, + 2.28392, + 2.25934, + 2.25365, + 2.26508, + 2.29387, + 2.34028, + 2.40528, + 2.49046, + 2.6079, + 2.75053, + 2.90401, + 3.08043, + 3.28096, + 3.50428, + 3.74894, + 4.01396, + 4.29668, + 4.59783, + 4.91726, + 5.25261, + 5.60291, + 5.96688, + 6.34137, + 6.72575, + 7.11773, + 7.51206, + 7.9075, + 8.30013, + 8.69001, + 9.07559, + 9.45367, + 9.82119, + 10.1781, + 10.5237, + 10.8547, + 11.1721, + 11.4717, + 11.7538, + 12.0195, + 12.2688, + 12.4984, + 12.7059, + 12.8936, + 13.0633, + 13.2217, + 13.3718, + 13.5166, + 13.6535, + 13.7765, + 13.885, + 13.9854, + 14.0846, + 14.1829, + 14.2785, + 14.3723, + 14.4657, + 14.5617, + 14.6574, + 14.7521, + 14.8438, + 14.9348, + 15.0304, + 15.1282, + 15.2244, + 15.3158, + 15.4052, + 15.4997, + 15.6044, + 15.7181, + 15.8327, + 15.9454, + 16.0586, + 16.1757, + 16.3001, + 16.4295, + 16.5604, + 16.693, + 16.8305, + 16.977, + 17.13, + 17.289, + 17.4532, + 17.6224, + 17.798, + 17.9819, + 18.1749, + 18.3752, + 18.5848, + 18.8047, + 19.0334, + 19.2705, + 19.5164, + 19.7535, + 19.9935, + 20.2527, + 20.5089, + 20.7571, + 21.0005, + 21.238, + 21.4701, + 21.6964, + 21.9213, + 22.1487, + 22.3791, + 22.6086, + 22.8278, + 23.0323, + 23.2246, + 23.4058, + 23.5774, + 23.7399, + 23.8877, + 24.0224, + 24.1402, + 24.2424, + 24.3339, + 24.4149, + 24.4954, + 24.5673, + 24.6146, + 24.6445, + 24.659, + 24.6572, + 24.6421, + 24.6135, + 24.5691, + 24.5102, + 24.4332, + 24.3396, + 24.2295, + 24.1043, + 23.9691, + 23.8242, + 23.6756, + 23.5202, + 23.3532, + 23.1768, + 23.0266, + 22.8706, + 22.6654, + 22.4472, + 22.2188, + 21.9801, + 21.7373, + 21.4885, + 21.2306, + 20.9633, + 20.6872, + 20.4056, + 20.1229, + 19.8387, + 19.5546, + 19.2671, + 18.9765, + 18.6833, + 18.4331, + 18.1795, + 17.8757, + 17.5688, + 17.2615, + 16.9487, + 16.6291, + 16.3042, + 15.9763, + 15.6492, + 15.3222, + 14.9975, + 14.6742, + 14.3505, + 14.0273, + 13.7507, + 13.4763, + 13.1571, + 12.8384, + 12.5215, + 12.2036, + 11.8898, + 11.5817, + 11.2792, + 10.9849, + 10.6955, + 10.4105, + 10.1291, + 9.84979, + 9.61226, + 9.38047, + 9.11816, + 8.86484, + 8.61963, + 8.37793, + 8.14033, + 7.90783, + 7.67996, + 7.45686, + 7.23874, + 7.02784, + 6.82606, + 6.65842, + 6.49427, + 6.30563, + 6.11905, + 5.93527, + 5.75694, + 5.58386, + 5.41441, + 5.2488, + 5.08485, + 4.9241, + 4.76646, + 4.61047, + 4.47811, + 4.34793, + 4.20103, + 4.05925, + 3.92146, + 3.78599, + 3.6539, + 3.52511, + 3.39856, + 3.27463, + 3.15298, + 3.0491, + 2.94723, + 2.8326, + 2.72067, + 2.61237, + 2.5083, + 2.40842, + 2.3123, + 2.22142, + 2.13449, + 2.05164, + 1.97252, + 1.9037, + 1.83381, + 1.75188, + 1.6682, + 1.58545, + 1.50637, + 1.43087, + 1.36126, + 1.29688, + 1.23775, + 1.18994, + 1.14464, + 1.09615, + 1.05128, + 1.00956, + 0.969786, + 0.931044, + 0.892824, + 0.855824, + 0.819462, + 0.788105, + 0.756553, + 0.72056, + 0.686625, + 0.655348, + 0.626445, + 0.598651, + 0.571904, + 0.545501, + 0.520326, + 0.500079, + 0.480231, + 0.458527, + 0.436609, + 0.413529, + 0.39013, + 0.367104, + 0.345344, + 0.324909, + 0.30481, + 0.287975, + 0.271934, + 0.254048, + 0.237291, + 0.22057, + 0.203268, + 0.186058, + 0.169591, + 0.153681, + 0.140372, + 0.128209 + ], + "expected": { + "Rf": 70.81842557080213, + "Rg": 114.15720812864069, + "CCT_K": 2443.5849600875645, + "Duv": -0.05138863156076942, + "bins": [ + { + "bin": 1, + "ref_a": 25.304677933039773, + "ref_b": 5.680905997599094, + "test_a": 24.21195069083772, + "test_b": 5.5411931961644125, + "ref_a_norm": 0.9757140763898617, + "ref_b_norm": 0.21904803385257587, + "test_a_norm": 0.9335799953044386, + "test_b_norm": 0.2136608976332411, + "Rcs_pct": -4.237546467167398, + "Rhs": 0.00293632753935819, + "Rf_h": 88.20984844262198 + }, + { + "bin": 2, + "ref_a": 19.78998560900307, + "ref_b": 14.035508267466435, + "test_a": 16.207820335370922, + "test_b": 16.668189888819505, + "ref_a_norm": 0.8156821408802416, + "ref_b_norm": 0.5785003414424451, + "test_a_norm": 0.6680363417820421, + "test_b_norm": 0.6870113542136926, + "Rcs_pct": -6.247750668376445, + "Rhs": 0.17225122072881785, + "Rf_h": 68.73357066069185 + }, + { + "bin": 3, + "ref_a": 15.605606777042368, + "ref_b": 24.142126282281545, + "test_a": 8.677606379535844, + "test_b": 30.14986630415219, + "ref_a_norm": 0.5428645594997761, + "ref_b_norm": 0.8398202605552654, + "test_a_norm": 0.3018636206872293, + "test_b_norm": 1.048808554772691, + "Rcs_pct": 3.98744682347037, + "Rhs": 0.3164926324757621, + "Rf_h": 37.43905956362215 + }, + { + "bin": 4, + "ref_a": 3.070600679151805, + "ref_b": 19.944631328099284, + "test_a": -2.1765556860249506, + "test_b": 25.27538127457977, + "ref_a_norm": 0.1521634831233909, + "ref_b_norm": 0.9883553381268082, + "test_a_norm": -0.10785912236854701, + "test_b_norm": 1.2525204199049977, + "Rcs_pct": 20.8361329967669, + "Rhs": 0.3065623949081127, + "Rf_h": 49.23903508741133 + }, + { + "bin": 5, + "ref_a": -2.5283976550914784, + "ref_b": 15.714957718534201, + "test_a": -5.510872327196974, + "test_b": 19.551273935930606, + "ref_a_norm": -0.15884831716571557, + "ref_b_norm": 0.9873029991515372, + "test_a_norm": -0.3462243344228533, + "test_b_norm": 1.2283221972281602, + "Rcs_pct": 27.294332931293713, + "Rhs": 0.13675512666154496, + "Rf_h": 66.22113183823171 + }, + { + "bin": 6, + "ref_a": -10.971588545232438, + "ref_b": 15.36947802053562, + "test_a": -12.625531960354555, + "test_b": 19.977651474506942, + "ref_a_norm": -0.5810063880370409, + "ref_b_norm": 0.8138989968418388, + "test_a_norm": -0.6685918535032352, + "test_b_norm": 1.0579273071363833, + "Rcs_pct": 25.15620020096342, + "Rhs": -0.06275021219920524, + "Rf_h": 66.8643685653943 + }, + { + "bin": 7, + "ref_a": -18.31532785167816, + "ref_b": 13.470070086304105, + "test_a": -19.54337586326706, + "test_b": 18.66226863011495, + "ref_a_norm": -0.8055897692835199, + "ref_b_norm": 0.5924737324352237, + "test_a_norm": -0.8596047955138224, + "test_b_norm": 0.8208497713931917, + "Rcs_pct": 17.179078209819355, + "Rhs": -0.1598785958622435, + "Rf_h": 63.731625187523775 + }, + { + "bin": 8, + "ref_a": -21.278790217491355, + "ref_b": 3.9349489067545558, + "test_a": -19.662251585517502, + "test_b": 6.909186102545491, + "ref_a_norm": -0.9833280413247971, + "ref_b_norm": 0.18184048818769183, + "test_a_norm": -0.9086251211654518, + "test_b_norm": 0.31928490144048893, + "Rcs_pct": -4.6453449654617645, + "Rhs": -0.1493772741414339, + "Rf_h": 74.16049259478112 + }, + { + "bin": 9, + "ref_a": -24.15277901583816, + "ref_b": -5.107099972625705, + "test_a": -23.519056880354558, + "test_b": -3.459340881246181, + "ref_a_norm": -0.9783672658662099, + "ref_b_norm": -0.2068755497430204, + "test_a_norm": -0.9526968039866301, + "test_b_norm": -0.1401290459149502, + "Rcs_pct": -3.819880807791303, + "Rhs": -0.06045592979855917, + "Rf_h": 83.25241147362108 + }, + { + "bin": 10, + "ref_a": -19.24333082380685, + "ref_b": -12.781672952088028, + "test_a": -17.34842512384054, + "test_b": -13.015655267708107, + "ref_a_norm": -0.8329923740437629, + "ref_b_norm": -0.5532844700377337, + "test_a_norm": -0.7509669693954559, + "test_b_norm": -0.5634129392906501, + "Rcs_pct": -6.257455537891263, + "Rhs": 0.053992387576927744, + "Rf_h": 82.46595320147664 + }, + { + "bin": 11, + "ref_a": -11.047097682234714, + "ref_b": -16.635270646043853, + "test_a": -7.539454895379709, + "test_b": -17.88666938190233, + "ref_a_norm": -0.5532056794785486, + "ref_b_norm": -0.8330447023975829, + "test_a_norm": -0.37755339802994103, + "test_b_norm": -0.8957110160197091, + "Rcs_pct": -4.548204344300861, + "Rhs": 0.18086507281765551, + "Rf_h": 69.74116637974268 + }, + { + "bin": 12, + "ref_a": -5.319347440428119, + "ref_b": -21.168036921054647, + "test_a": -0.6380866214985048, + "test_b": -22.679675631993955, + "ref_a_norm": -0.24371431026374724, + "ref_b_norm": -0.9698470678270188, + "test_a_norm": -0.029234947066085384, + "test_b_norm": -1.0391051845284356, + "Rcs_pct": 2.608449337715269, + "Rhs": 0.2238697906640351, + "Rf_h": 58.97838901229049 + }, + { + "bin": 13, + "ref_a": 3.7150477215029363, + "ref_b": -14.623650824756291, + "test_a": 6.103621306709806, + "test_b": -16.101499617203864, + "ref_a_norm": 0.24622262274570297, + "ref_b_norm": -0.9692132995621898, + "test_a_norm": 0.4045303745860524, + "test_b_norm": -1.067160845051808, + "Rcs_pct": 12.694982115202643, + "Rhs": 0.13615729458848314, + "Rf_h": 78.86058176123562 + }, + { + "bin": 14, + "ref_a": 12.966323431382717, + "ref_b": -15.444631136029074, + "test_a": 15.321433209706889, + "test_b": -17.560078255585683, + "ref_a_norm": 0.6429836967620401, + "ref_b_norm": -0.765879863750328, + "test_a_norm": 0.7597706332873325, + "test_b_norm": -0.8707822299789072, + "Rcs_pct": 15.210647531669856, + "Rhs": 0.03882415678476746, + "Rf_h": 78.40933488416722 + }, + { + "bin": 15, + "ref_a": 16.550541275109033, + "ref_b": -10.276651364053198, + "test_a": 18.26993824750567, + "test_b": -12.631020728116946, + "ref_a_norm": 0.8495504182369203, + "ref_b_norm": -0.5275074282637863, + "test_a_norm": 0.9378082215760583, + "test_b_norm": -0.6483587916528892, + "Rcs_pct": 14.052510164388785, + "Rhs": -0.051450827896448365, + "Rf_h": 79.22627714226047 + }, + { + "bin": 16, + "ref_a": 18.01078193874554, + "ref_b": -3.3980783712882636, + "test_a": 18.016908760372196, + "test_b": -4.350759141176737, + "ref_a_norm": 0.9826634665530587, + "ref_b_norm": -0.18539825107569266, + "test_a_norm": 0.9829977443095201, + "test_b_norm": -0.2373762601949485, + "Rcs_pct": 1.0468261239936534, + "Rhs": -0.0509140518936801, + "Rf_h": 89.6609963029149 + } + ] + } +} \ No newline at end of file diff --git a/crates/tm30/tests/golden/lamp_L0009.json b/crates/tm30/tests/golden/lamp_L0009.json new file mode 100644 index 0000000..c08fcc8 --- /dev/null +++ b/crates/tm30/tests/golden/lamp_L0009.json @@ -0,0 +1,941 @@ +{ + "name": "lamp_L0009", + "source": "L0009/spd.csv", + "generator": "crates/tm30/tools/golden.py (tm30.py + colour-science 0.4.7, numpy 2.5.1)", + "wavelengths": [ + 380.0, + 381.92, + 383.84, + 385.76, + 387.68, + 389.6, + 391.52, + 393.44, + 395.36, + 397.28, + 399.2, + 401.12, + 403.04, + 404.96, + 406.88, + 408.8, + 410.72, + 412.64, + 414.56, + 416.48, + 418.4, + 420.32, + 422.23, + 424.15, + 426.07, + 427.99, + 429.91, + 431.83, + 433.75, + 435.67, + 437.59, + 439.51, + 441.43, + 443.35, + 445.27, + 447.19, + 449.11, + 451.03, + 452.95, + 454.87, + 456.79, + 458.71, + 460.63, + 462.55, + 464.47, + 466.39, + 468.31, + 470.23, + 472.15, + 474.07, + 475.99, + 477.91, + 479.83, + 481.75, + 483.67, + 485.59, + 487.51, + 489.43, + 491.35, + 493.27, + 495.19, + 497.11, + 499.03, + 500.95, + 502.87, + 504.79, + 506.7, + 508.62, + 510.54, + 512.46, + 514.38, + 516.3, + 518.22, + 520.14, + 522.06, + 523.98, + 525.9, + 527.82, + 529.74, + 531.66, + 533.58, + 535.5, + 537.42, + 539.34, + 541.26, + 543.18, + 545.1, + 547.02, + 548.94, + 550.86, + 552.78, + 554.7, + 556.62, + 558.54, + 560.46, + 562.38, + 564.3, + 566.22, + 568.14, + 570.06, + 571.98, + 573.9, + 575.82, + 577.74, + 579.66, + 581.58, + 583.5, + 585.42, + 587.34, + 589.26, + 591.17, + 593.09, + 595.01, + 596.93, + 598.85, + 600.77, + 602.69, + 604.61, + 606.53, + 608.45, + 610.37, + 612.29, + 614.21, + 616.13, + 618.05, + 619.97, + 621.89, + 623.81, + 625.73, + 627.65, + 629.57, + 631.49, + 633.41, + 635.33, + 637.25, + 639.17, + 641.09, + 643.01, + 644.93, + 646.85, + 648.77, + 650.69, + 652.61, + 654.53, + 656.45, + 658.37, + 660.29, + 662.21, + 664.13, + 666.05, + 667.97, + 669.89, + 671.81, + 673.72, + 675.64, + 677.56, + 679.48, + 681.4, + 683.32, + 685.24, + 687.16, + 689.08, + 691.0, + 692.92, + 694.84, + 696.76, + 698.68, + 700.6, + 702.52, + 704.44, + 706.36, + 708.28, + 710.2, + 712.12, + 714.04, + 715.96, + 717.88, + 719.8, + 721.72, + 723.64, + 725.56, + 727.48, + 729.4, + 731.32, + 733.24, + 735.16, + 737.08, + 739.0, + 740.92, + 742.84, + 744.76, + 746.68, + 748.6, + 750.52, + 752.44, + 754.36, + 756.28, + 758.19, + 760.11, + 762.03, + 763.95, + 765.87, + 767.79, + 769.71, + 771.63, + 773.55, + 775.47, + 777.39, + 779.31, + 781.23, + 783.15, + 785.07, + 786.99, + 788.91, + 790.83, + 792.75, + 794.67, + 796.59, + 798.51, + 800.43, + 802.35, + 804.27, + 806.19, + 808.11, + 810.03, + 811.95, + 813.87, + 815.79, + 817.71, + 819.63, + 821.55, + 823.47, + 825.39, + 827.31, + 829.23, + 831.15, + 833.07, + 834.99, + 836.91, + 838.83, + 840.74, + 842.66, + 844.58, + 846.5, + 848.42, + 850.34, + 852.26, + 854.18, + 856.1, + 858.02, + 859.94, + 861.86, + 863.78, + 865.7, + 867.62, + 869.54, + 871.46, + 873.38, + 875.3, + 877.22, + 879.14, + 881.06, + 882.98, + 884.9, + 886.82, + 888.74, + 890.66, + 892.58, + 894.5, + 896.42, + 898.34, + 900.26, + 902.18, + 904.1, + 906.02, + 907.94, + 909.86, + 911.78, + 913.7, + 915.62, + 917.54, + 919.46, + 921.38, + 923.3, + 925.21, + 927.13, + 929.05, + 930.97, + 932.89, + 934.81, + 936.73, + 938.65, + 940.57, + 942.49, + 944.41, + 946.33, + 948.25, + 950.17, + 952.09, + 954.01, + 955.93, + 957.85, + 959.77, + 961.69, + 963.61, + 965.53, + 967.45, + 969.37, + 971.29, + 973.21, + 975.13, + 977.05, + 978.97, + 980.89, + 982.81, + 984.73, + 986.65, + 988.57, + 990.49, + 992.41, + 994.33, + 996.25, + 998.17, + 1000.09, + 1002.01, + 1003.93, + 1005.85, + 1007.77, + 1009.68, + 1011.6, + 1013.52, + 1015.44, + 1017.36, + 1019.28, + 1021.2, + 1023.12, + 1025.04, + 1026.96, + 1028.88, + 1030.8, + 1032.72, + 1034.64, + 1036.56, + 1038.48, + 1040.4, + 1042.32, + 1044.24, + 1046.16, + 1048.08, + 1050.0 + ], + "values": [ + 0.0, + 0.0, + 0.0, + 0.000708105, + 0.0137126, + 0.0528357, + 0.130714, + 0.239916, + 0.351957, + 0.47484, + 0.609594, + 0.759688, + 0.92786, + 1.11488, + 1.32525, + 1.5587, + 1.82081, + 2.11505, + 2.44542, + 2.81629, + 3.23046, + 3.69317, + 4.2095, + 4.78235, + 5.41475, + 6.12133, + 6.90418, + 7.77361, + 8.72485, + 9.7423, + 10.9151, + 12.0903, + 13.1104, + 14.0354, + 14.8114, + 15.3828, + 15.7117, + 15.7658, + 15.5479, + 15.0876, + 14.4397, + 13.6753, + 12.8565, + 12.0423, + 11.2793, + 10.6044, + 10.0321, + 9.56104, + 9.16401, + 8.81352, + 8.48704, + 8.16803, + 7.8489, + 7.51834, + 7.17534, + 6.82447, + 6.4774, + 6.14935, + 5.85102, + 5.59231, + 5.37925, + 5.21908, + 5.11339, + 5.06023, + 5.05543, + 5.08969, + 5.14457, + 5.22565, + 5.32806, + 5.44953, + 5.58961, + 5.74487, + 5.91751, + 6.10945, + 6.34302, + 6.60079, + 6.8574, + 7.13116, + 7.4228, + 7.73024, + 8.04872, + 8.37505, + 8.7028, + 9.0333, + 9.3663, + 9.69586, + 10.0219, + 10.3418, + 10.655, + 10.9613, + 11.2597, + 11.5446, + 11.8183, + 12.0819, + 12.337, + 12.5812, + 12.8111, + 13.0258, + 13.2273, + 13.4196, + 13.5993, + 13.7674, + 13.922, + 14.0634, + 14.1925, + 14.3121, + 14.4193, + 14.5126, + 14.5958, + 14.6684, + 14.7398, + 14.8235, + 14.9119, + 14.995, + 15.0755, + 15.1529, + 15.2302, + 15.3099, + 15.3939, + 15.4806, + 15.5722, + 15.6736, + 15.7895, + 15.9152, + 16.0481, + 16.1832, + 16.3202, + 16.4637, + 16.6139, + 16.7662, + 16.917, + 17.0694, + 17.2303, + 17.4046, + 17.5894, + 17.7769, + 17.9641, + 18.1542, + 18.3491, + 18.55, + 18.7527, + 18.955, + 19.1596, + 19.3699, + 19.5881, + 19.8105, + 20.0367, + 20.2668, + 20.5016, + 20.7434, + 20.9952, + 21.2564, + 21.5238, + 21.798, + 22.0799, + 22.3708, + 22.6721, + 22.9841, + 23.284, + 23.5875, + 23.9163, + 24.243, + 24.561, + 24.8745, + 25.1803, + 25.4767, + 25.7641, + 26.0485, + 26.3355, + 26.6277, + 26.9193, + 27.197, + 27.4587, + 27.7068, + 27.944, + 28.1714, + 28.388, + 28.5886, + 28.7762, + 28.9488, + 29.104, + 29.2452, + 29.3717, + 29.4935, + 29.6057, + 29.6938, + 29.7629, + 29.8124, + 29.8405, + 29.8519, + 29.8478, + 29.827, + 29.7895, + 29.7298, + 29.6484, + 29.5446, + 29.4216, + 29.2847, + 29.1351, + 28.9773, + 28.8071, + 28.6237, + 28.4303, + 28.27, + 28.1036, + 27.8784, + 27.6327, + 27.3713, + 27.0973, + 26.8156, + 26.5262, + 26.2252, + 25.9131, + 25.5917, + 25.2655, + 24.9366, + 24.6045, + 24.2721, + 23.9347, + 23.5914, + 23.2419, + 22.9424, + 22.6367, + 22.2665, + 21.8906, + 21.5129, + 21.13, + 20.7395, + 20.3423, + 19.9392, + 19.5359, + 19.1316, + 18.7281, + 18.3246, + 17.9201, + 17.5164, + 17.1711, + 16.8294, + 16.4297, + 16.0297, + 15.6313, + 15.2328, + 14.8423, + 14.4594, + 14.0834, + 13.716, + 13.3543, + 12.9992, + 12.6505, + 12.3062, + 12.0137, + 11.728, + 11.4026, + 11.089, + 10.7868, + 10.4901, + 10.1969, + 9.90705, + 9.62188, + 9.345, + 9.07824, + 8.82166, + 8.57506, + 8.36732, + 8.16029, + 7.91955, + 7.67969, + 7.442, + 7.21107, + 6.98641, + 6.76759, + 6.55404, + 6.34269, + 6.13505, + 5.9309, + 5.73034, + 5.56101, + 5.39566, + 5.20977, + 5.03014, + 4.85464, + 4.68193, + 4.51167, + 4.34521, + 4.18411, + 4.02777, + 3.87665, + 3.74916, + 3.62373, + 3.48205, + 3.34478, + 3.21293, + 3.08715, + 2.96735, + 2.85072, + 2.73744, + 2.62814, + 2.52248, + 2.41982, + 2.33142, + 2.24232, + 2.13848, + 2.03468, + 1.93299, + 1.83375, + 1.73818, + 1.64816, + 1.56473, + 1.48863, + 1.42815, + 1.37289, + 1.31339, + 1.25856, + 1.20812, + 1.15955, + 1.11229, + 1.06597, + 1.02068, + 0.976876, + 0.940242, + 0.904803, + 0.864055, + 0.82406, + 0.785296, + 0.747025, + 0.709964, + 0.673881, + 0.639097, + 0.606073, + 0.579219, + 0.553654, + 0.525392, + 0.498309, + 0.472032, + 0.447074, + 0.423412, + 0.4003, + 0.37727, + 0.353284, + 0.332482, + 0.313038, + 0.292436, + 0.273473, + 0.255321, + 0.23756, + 0.219709, + 0.202175, + 0.184447, + 0.168188, + 0.152814 + ], + "expected": { + "Rf": 85.57633333632175, + "Rg": 109.03525236637346, + "CCT_K": 3126.5591184283076, + "Duv": -0.02988113095143269, + "bins": [ + { + "bin": 1, + "ref_a": 23.8481354695577, + "ref_b": 4.856038228707849, + "test_a": 23.89079128798164, + "test_b": 4.872551902653544, + "ref_a_norm": 0.9798919379911113, + "ref_b_norm": 0.19952891985881147, + "test_a_norm": 0.9816446155803251, + "test_b_norm": 0.20020744736829565, + "Rcs_pct": 0.18513745311156438, + "Rhs": 0.00032355935838058666, + "Rf_h": 93.94112214156088 + }, + { + "bin": 2, + "ref_a": 20.449310095329412, + "ref_b": 15.041810777150866, + "test_a": 19.269278631378143, + "test_b": 16.274581280118575, + "ref_a_norm": 0.8055465948768648, + "ref_b_norm": 0.5925324324307392, + "test_a_norm": 0.7590623700691723, + "test_b_norm": 0.6410941724748245, + "Rcs_pct": -1.1670763146906544, + "Rhs": 0.06620286277533792, + "Rf_h": 87.04253398867661 + }, + { + "bin": 3, + "ref_a": 14.743848719744593, + "ref_b": 23.01107956162063, + "test_a": 12.219439831464227, + "test_b": 25.6666755167977, + "ref_a_norm": 0.5394886278274436, + "ref_b_norm": 0.8419928862198672, + "test_a_norm": 0.4471185884231482, + "test_b_norm": 0.9391631600849266, + "Rcs_pct": 2.947608562203885, + "Rhs": 0.13078779254564982, + "Rf_h": 74.17196843542611 + }, + { + "bin": 4, + "ref_a": 2.98208781002983, + "ref_b": 22.000803793403357, + "test_a": 0.6893235223212155, + "test_b": 24.291311630672027, + "ref_a_norm": 0.13431625938580663, + "ref_b_norm": 0.9909385159860347, + "test_a_norm": 0.031047830554630146, + "test_b_norm": 1.0941053120009128, + "Rcs_pct": 8.103780392298114, + "Rhs": 0.12141099838390124, + "Rf_h": 77.76910600231366 + }, + { + "bin": 5, + "ref_a": -2.6411556104875404, + "ref_b": 15.902242631718849, + "test_a": -3.8546365449764033, + "test_b": 17.47789792795958, + "ref_a_norm": -0.16384257302018906, + "ref_b_norm": 0.9864864982685391, + "test_a_norm": -0.2391201665963199, + "test_b_norm": 1.0842313705902857, + "Rcs_pct": 11.055266197942899, + "Rhs": 0.05476207710697097, + "Rf_h": 85.30538562399786 + }, + { + "bin": 6, + "ref_a": -12.6661520539633, + "ref_b": 17.252683217246336, + "test_a": -13.44820653505244, + "test_b": 19.509596227072453, + "ref_a_norm": -0.5917945446368995, + "ref_b_norm": 0.806088839358296, + "test_a_norm": -0.6283341008924694, + "test_b_norm": 0.9115375029496365, + "Rcs_pct": 10.79776492174532, + "Rhs": -0.02820260792952084, + "Rf_h": 83.45209156389723 + }, + { + "bin": 7, + "ref_a": -18.51701263480538, + "ref_b": 13.615877169378134, + "test_a": -19.24560913889828, + "test_b": 15.846837727788621, + "ref_a_norm": -0.8056421521953241, + "ref_b_norm": 0.5924025005062741, + "test_a_norm": -0.8373420849661247, + "test_b_norm": 0.6894676103697474, + "Rcs_pct": 8.028401651587743, + "Rhs": -0.06309515023010671, + "Rf_h": 83.53732482538587 + }, + { + "bin": 8, + "ref_a": -21.466927298264707, + "ref_b": 6.144803981207129, + "test_a": -20.687276174419484, + "test_b": 7.4059260649027285, + "ref_a_norm": -0.9613890160597628, + "ref_b_norm": 0.2751929501270718, + "test_a_norm": -0.9264726064400202, + "test_b_norm": 0.3316718724399711, + "Rcs_pct": -2.3227009458425982, + "Rhs": -0.06220554925389188, + "Rf_h": 87.66571629671147 + }, + { + "bin": 9, + "ref_a": -20.551562771317805, + "ref_b": -3.329307332425394, + "test_a": -20.225675750471822, + "test_b": -3.2017978246302254, + "ref_a_norm": -0.9871311059936017, + "ref_b_norm": -0.1599130375543189, + "test_a_norm": -0.9714781252983516, + "test_b_norm": -0.15378851053634393, + "Rcs_pct": -1.6547049008470265, + "Rhs": -0.0029531009043131913, + "Rf_h": 92.9607329760184 + }, + { + "bin": 10, + "ref_a": -20.1778100913754, + "ref_b": -13.088183756459166, + "test_a": -19.059804684501774, + "test_b": -13.762427490492884, + "ref_a_norm": -0.8389636692213026, + "ref_b_norm": -0.5441874325328809, + "test_a_norm": -0.7924786485915928, + "test_b_norm": -0.5722214954214092, + "Rcs_pct": -2.307599122939474, + "Rhs": 0.049135165144358714, + "Rf_h": 88.22329424869986 + }, + { + "bin": 11, + "ref_a": -11.37586678412891, + "ref_b": -17.416524810696902, + "test_a": -9.213319737849307, + "test_b": -18.768585401566725, + "ref_a_norm": -0.5468498865026123, + "ref_b_norm": -0.8372306740869448, + "test_a_norm": -0.4428939744604237, + "test_b_norm": -0.9022256493879355, + "Rcs_pct": -0.37134633619158847, + "Rhs": 0.12254545545535066, + "Rf_h": 80.90649719102427 + }, + { + "bin": 12, + "ref_a": -5.590481104609111, + "ref_b": -18.860947424462783, + "test_a": -3.1287228920452144, + "test_b": -20.224193973752985, + "ref_a_norm": -0.2841842314219823, + "ref_b_norm": -0.9587696921633982, + "test_a_norm": -0.15904422066200677, + "test_b_norm": -1.0280684100374824, + "Rcs_pct": 4.355355744545266, + "Rhs": 0.1362549897282458, + "Rf_h": 80.65318586070153 + }, + { + "bin": 13, + "ref_a": 2.8947627909204994, + "ref_b": -18.203370662979225, + "test_a": 4.894174809876978, + "test_b": -19.193936383417835, + "ref_a_norm": 0.15705007028445966, + "ref_b_norm": -0.9875906416241732, + "test_a_norm": 0.26552451906817426, + "test_b_norm": -1.0413319763215116, + "Rcs_pct": 7.387102516410985, + "Rhs": 0.09590572837524108, + "Rf_h": 84.76114138741647 + }, + { + "bin": 14, + "ref_a": 8.831595883829587, + "ref_b": -14.238804492266802, + "test_a": 10.738484743399184, + "test_b": -15.244943950094058, + "ref_a_norm": 0.5270921474212564, + "ref_b_norm": -0.849808136067694, + "test_a_norm": 0.6409001337812903, + "test_b_norm": -0.909857102801152, + "Rcs_pct": 11.315722059057242, + "Rhs": 0.06126646385501722, + "Rf_h": 85.31916788205297 + }, + { + "bin": 15, + "ref_a": 17.98758091411547, + "ref_b": -12.202739349915184, + "test_a": 19.310257206846607, + "test_b": -13.264515585790235, + "ref_a_norm": 0.8275424426014124, + "ref_b_norm": -0.5614031578939397, + "test_a_norm": 0.8883939142519867, + "test_b_norm": -0.6102515774745102, + "Rcs_pct": 7.773487739035908, + "Rhs": -0.006808710205753734, + "Rf_h": 88.41157319229939 + }, + { + "bin": 16, + "ref_a": 16.58202958481358, + "ref_b": -3.9550099125610516, + "test_a": 17.298333631938153, + "test_b": -4.894538544279577, + "ref_a_norm": 0.9727148370971966, + "ref_b_norm": -0.2320039777481721, + "test_a_norm": 1.014733793277866, + "test_b_norm": -0.2871174628180102, + "Rcs_pct": 5.196368126961452, + "Rhs": -0.04585700321615207, + "Rf_h": 90.62165078234413 + } + ] + } +} \ No newline at end of file diff --git a/crates/tm30/tests/golden/lamp_L0010.json b/crates/tm30/tests/golden/lamp_L0010.json new file mode 100644 index 0000000..b99d924 --- /dev/null +++ b/crates/tm30/tests/golden/lamp_L0010.json @@ -0,0 +1,941 @@ +{ + "name": "lamp_L0010", + "source": "L0010/spd.csv", + "generator": "crates/tm30/tools/golden.py (tm30.py + colour-science 0.4.7, numpy 2.5.1)", + "wavelengths": [ + 380.0, + 381.92, + 383.84, + 385.76, + 387.68, + 389.6, + 391.52, + 393.44, + 395.36, + 397.28, + 399.2, + 401.12, + 403.04, + 404.96, + 406.88, + 408.8, + 410.72, + 412.64, + 414.56, + 416.48, + 418.4, + 420.32, + 422.23, + 424.15, + 426.07, + 427.99, + 429.91, + 431.83, + 433.75, + 435.67, + 437.59, + 439.51, + 441.43, + 443.35, + 445.27, + 447.19, + 449.11, + 451.03, + 452.95, + 454.87, + 456.79, + 458.71, + 460.63, + 462.55, + 464.47, + 466.39, + 468.31, + 470.23, + 472.15, + 474.07, + 475.99, + 477.91, + 479.83, + 481.75, + 483.67, + 485.59, + 487.51, + 489.43, + 491.35, + 493.27, + 495.19, + 497.11, + 499.03, + 500.95, + 502.87, + 504.79, + 506.7, + 508.62, + 510.54, + 512.46, + 514.38, + 516.3, + 518.22, + 520.14, + 522.06, + 523.98, + 525.9, + 527.82, + 529.74, + 531.66, + 533.58, + 535.5, + 537.42, + 539.34, + 541.26, + 543.18, + 545.1, + 547.02, + 548.94, + 550.86, + 552.78, + 554.7, + 556.62, + 558.54, + 560.46, + 562.38, + 564.3, + 566.22, + 568.14, + 570.06, + 571.98, + 573.9, + 575.82, + 577.74, + 579.66, + 581.58, + 583.5, + 585.42, + 587.34, + 589.26, + 591.17, + 593.09, + 595.01, + 596.93, + 598.85, + 600.77, + 602.69, + 604.61, + 606.53, + 608.45, + 610.37, + 612.29, + 614.21, + 616.13, + 618.05, + 619.97, + 621.89, + 623.81, + 625.73, + 627.65, + 629.57, + 631.49, + 633.41, + 635.33, + 637.25, + 639.17, + 641.09, + 643.01, + 644.93, + 646.85, + 648.77, + 650.69, + 652.61, + 654.53, + 656.45, + 658.37, + 660.29, + 662.21, + 664.13, + 666.05, + 667.97, + 669.89, + 671.81, + 673.72, + 675.64, + 677.56, + 679.48, + 681.4, + 683.32, + 685.24, + 687.16, + 689.08, + 691.0, + 692.92, + 694.84, + 696.76, + 698.68, + 700.6, + 702.52, + 704.44, + 706.36, + 708.28, + 710.2, + 712.12, + 714.04, + 715.96, + 717.88, + 719.8, + 721.72, + 723.64, + 725.56, + 727.48, + 729.4, + 731.32, + 733.24, + 735.16, + 737.08, + 739.0, + 740.92, + 742.84, + 744.76, + 746.68, + 748.6, + 750.52, + 752.44, + 754.36, + 756.28, + 758.19, + 760.11, + 762.03, + 763.95, + 765.87, + 767.79, + 769.71, + 771.63, + 773.55, + 775.47, + 777.39, + 779.31, + 781.23, + 783.15, + 785.07, + 786.99, + 788.91, + 790.83, + 792.75, + 794.67, + 796.59, + 798.51, + 800.43, + 802.35, + 804.27, + 806.19, + 808.11, + 810.03, + 811.95, + 813.87, + 815.79, + 817.71, + 819.63, + 821.55, + 823.47, + 825.39, + 827.31, + 829.23, + 831.15, + 833.07, + 834.99, + 836.91, + 838.83, + 840.74, + 842.66, + 844.58, + 846.5, + 848.42, + 850.34, + 852.26, + 854.18, + 856.1, + 858.02, + 859.94, + 861.86, + 863.78, + 865.7, + 867.62, + 869.54, + 871.46, + 873.38, + 875.3, + 877.22, + 879.14, + 881.06, + 882.98, + 884.9, + 886.82, + 888.74, + 890.66, + 892.58, + 894.5, + 896.42, + 898.34, + 900.26, + 902.18, + 904.1, + 906.02, + 907.94, + 909.86, + 911.78, + 913.7, + 915.62, + 917.54, + 919.46, + 921.38, + 923.3, + 925.21, + 927.13, + 929.05, + 930.97, + 932.89, + 934.81, + 936.73, + 938.65, + 940.57, + 942.49, + 944.41, + 946.33, + 948.25, + 950.17, + 952.09, + 954.01, + 955.93, + 957.85, + 959.77, + 961.69, + 963.61, + 965.53, + 967.45, + 969.37, + 971.29, + 973.21, + 975.13, + 977.05, + 978.97, + 980.89, + 982.81, + 984.73, + 986.65, + 988.57, + 990.49, + 992.41, + 994.33, + 996.25, + 998.17, + 1000.09, + 1002.01, + 1003.93, + 1005.85, + 1007.77, + 1009.68, + 1011.6, + 1013.52, + 1015.44, + 1017.36, + 1019.28, + 1021.2, + 1023.12, + 1025.04, + 1026.96, + 1028.88, + 1030.8, + 1032.72, + 1034.64, + 1036.56, + 1038.48, + 1040.4, + 1042.32, + 1044.24, + 1046.16, + 1048.08, + 1050.0 + ], + "values": [ + 0.0704409, + 0.155122, + 0.273341, + 0.411353, + 0.564648, + 0.738328, + 0.961669, + 1.21962, + 1.48368, + 1.78492, + 2.12931, + 2.52891, + 2.99284, + 3.52035, + 4.11275, + 4.76721, + 5.4988, + 6.31526, + 7.22856, + 8.24828, + 9.37811, + 10.6253, + 11.9939, + 13.4805, + 15.0889, + 16.8542, + 18.7884, + 20.9213, + 23.2567, + 25.7738, + 28.7203, + 31.7624, + 34.5303, + 37.224, + 39.7482, + 41.9861, + 43.8454, + 45.2124, + 46.0265, + 46.2567, + 45.9028, + 45.0077, + 43.6355, + 41.8902, + 39.8947, + 37.7977, + 35.7127, + 33.74, + 31.9051, + 30.2182, + 28.6774, + 27.2761, + 26.0129, + 24.8517, + 23.7587, + 22.7103, + 21.701, + 20.7343, + 19.8119, + 18.935, + 18.113, + 17.3729, + 16.7343, + 16.2062, + 15.7878, + 15.4694, + 15.2106, + 15.0353, + 14.9302, + 14.887, + 14.8966, + 14.9473, + 15.0361, + 15.1606, + 15.321, + 15.5202, + 15.7425, + 15.9871, + 16.2571, + 16.5482, + 16.8557, + 17.1781, + 17.5062, + 17.8447, + 18.1947, + 18.5489, + 18.9052, + 19.2582, + 19.6042, + 19.942, + 20.272, + 20.5824, + 20.8758, + 21.1497, + 21.4072, + 21.6507, + 21.8759, + 22.0823, + 22.2715, + 22.4457, + 22.6001, + 22.7363, + 22.8545, + 22.9559, + 23.041, + 23.1125, + 23.1621, + 23.1893, + 23.2002, + 23.1986, + 23.1953, + 23.2243, + 23.2559, + 23.2578, + 23.2513, + 23.2379, + 23.2231, + 23.2124, + 23.2057, + 23.2017, + 23.2037, + 23.2142, + 23.2389, + 23.269, + 23.301, + 23.3314, + 23.3598, + 23.3933, + 23.4298, + 23.4617, + 23.4839, + 23.4977, + 23.5113, + 23.5335, + 23.5612, + 23.5825, + 23.5941, + 23.5974, + 23.5942, + 23.5887, + 23.5781, + 23.5591, + 23.5348, + 23.5083, + 23.4808, + 23.4467, + 23.4054, + 23.3575, + 23.3066, + 23.2568, + 23.2107, + 23.1654, + 23.1175, + 23.0696, + 23.0231, + 22.9802, + 22.9391, + 22.9009, + 22.8887, + 22.8745, + 22.8379, + 22.7958, + 22.7414, + 22.678, + 22.6032, + 22.5163, + 22.4214, + 22.3243, + 22.2298, + 22.1408, + 22.0533, + 21.9574, + 21.851, + 21.7352, + 21.6119, + 21.4831, + 21.3489, + 21.2085, + 21.0652, + 20.9173, + 20.763, + 20.6016, + 20.4351, + 20.3025, + 20.1691, + 19.9973, + 19.8193, + 19.6349, + 19.4418, + 19.2438, + 19.0427, + 18.8376, + 18.6303, + 18.4165, + 18.1936, + 17.962, + 17.7242, + 17.4833, + 17.2409, + 17.0015, + 16.762, + 16.5214, + 16.2822, + 16.0817, + 15.8799, + 15.6352, + 15.3854, + 15.1328, + 14.88, + 14.6293, + 14.3789, + 14.126, + 13.8717, + 13.6166, + 13.3635, + 13.1147, + 12.869, + 12.6268, + 12.3868, + 12.1482, + 11.91, + 11.7072, + 11.5028, + 11.2614, + 11.0211, + 10.7843, + 10.5485, + 10.3111, + 10.0734, + 9.83601, + 9.60202, + 9.37035, + 9.13922, + 8.91047, + 8.68344, + 8.4601, + 8.27107, + 8.08346, + 7.86524, + 7.64897, + 7.43632, + 7.22666, + 7.02113, + 6.819, + 6.6212, + 6.42867, + 6.23952, + 6.0541, + 5.87268, + 5.69509, + 5.54572, + 5.4002, + 5.23459, + 5.07414, + 4.91967, + 4.7692, + 4.62212, + 4.47892, + 4.33872, + 4.20152, + 4.06787, + 3.93774, + 3.81273, + 3.70892, + 3.60785, + 3.49201, + 3.37611, + 3.2602, + 3.14581, + 3.03412, + 2.92559, + 2.81903, + 2.71377, + 2.61024, + 2.5096, + 2.41249, + 2.3315, + 2.25319, + 2.16592, + 2.08098, + 1.99743, + 1.91505, + 1.83423, + 1.75661, + 1.68257, + 1.61202, + 1.54345, + 1.48604, + 1.43031, + 1.3677, + 1.308, + 1.25133, + 1.19753, + 1.14719, + 1.09977, + 1.05442, + 1.01113, + 0.969224, + 0.929058, + 0.89469, + 0.859059, + 0.81664, + 0.772148, + 0.727921, + 0.687024, + 0.648887, + 0.613539, + 0.580742, + 0.549823, + 0.525414, + 0.502825, + 0.478494, + 0.456394, + 0.436076, + 0.416935, + 0.398771, + 0.381003, + 0.36364, + 0.347348, + 0.333628, + 0.319235, + 0.301626, + 0.283026, + 0.264275, + 0.24689, + 0.231773, + 0.217265, + 0.203283, + 0.188755, + 0.175992, + 0.164599, + 0.152248, + 0.140831, + 0.129962, + 0.118847, + 0.108203, + 0.0978513, + 0.088184, + 0.0791352, + 0.0717788, + 0.0649564, + 0.0570148, + 0.0490038, + 0.0418132, + 0.0348619, + 0.0277877, + 0.0202911, + 0.0124369, + 0.00695575, + 0.00316684 + ], + "expected": { + "Rf": 85.4599478008346, + "Rg": 106.82105137250961, + "CCT_K": 6671.950551730577, + "Duv": -0.030555152167187953, + "bins": [ + { + "bin": 1, + "ref_a": 23.77074772539363, + "ref_b": 4.815349260407046, + "test_a": 24.84010385464047, + "test_b": 6.243272668301622, + "ref_a_norm": 0.9800924187343087, + "ref_b_norm": 0.19854181106137897, + "test_a_norm": 1.024183073656462, + "test_b_norm": 0.25741656429918686, + "Rcs_pct": 5.47293599187704, + "Rhs": 0.04914183129634947, + "Rf_h": 80.68739952112084 + }, + { + "bin": 2, + "ref_a": 22.132918839232083, + "ref_b": 14.037977826172348, + "test_a": 21.98969937705481, + "test_b": 15.736057207730394, + "ref_a_norm": 0.8444659823829852, + "ref_b_norm": 0.535609190173152, + "test_a_norm": 0.8390015443347367, + "test_b_norm": 0.6003982170307347, + "Rcs_pct": 3.1451340562952095, + "Rhs": 0.0569059861625201, + "Rf_h": 80.28428124097668 + }, + { + "bin": 3, + "ref_a": 11.976026213957356, + "ref_b": 18.51742411562301, + "test_a": 12.180476285596235, + "test_b": 19.66550054106383, + "ref_a_norm": 0.5430647120486894, + "ref_b_norm": 0.8396908469951747, + "test_a_norm": 0.5523357020498222, + "test_b_norm": 0.8917515040322542, + "Rcs_pct": 4.843754039808797, + "Rhs": 0.02121480489934126, + "Rf_h": 84.78882074343872 + }, + { + "bin": 4, + "ref_a": 4.491148579212282, + "ref_b": 22.873872220946907, + "test_a": 3.723771847592699, + "test_b": 23.584969544242426, + "ref_a_norm": 0.1926654412740695, + "ref_b_norm": 0.981264504473013, + "test_a_norm": 0.15974580523591564, + "test_b_norm": 1.0117698144544456, + "Rcs_pct": 2.349685660858956, + "Rhs": 0.038238385209932495, + "Rf_h": 90.09456622966862 + }, + { + "bin": 5, + "ref_a": -1.5868645985089844, + "ref_b": 21.549001996159177, + "test_a": -2.0634309816163063, + "test_b": 21.59591418688596, + "ref_a_norm": -0.07344095919641669, + "ref_b_norm": 0.997299566585843, + "test_a_norm": -0.09549671135640198, + "test_b_norm": 0.999470688361587, + "Rcs_pct": 0.6432268070812112, + "Rhs": 0.02120839222036919, + "Rf_h": 91.58715463051242 + }, + { + "bin": 6, + "ref_a": -10.223990098346974, + "ref_b": 16.819505972719494, + "test_a": -10.610612650763333, + "test_b": 16.6089231316328, + "ref_a_norm": -0.5194289802584076, + "ref_b_norm": 0.8545136245067779, + "test_a_norm": -0.539071307394366, + "test_b_norm": 0.8438149804985775, + "Rcs_pct": 0.2017094878310413, + "Rhs": 0.02227584627308485, + "Rf_h": 91.64501554705069 + }, + { + "bin": 7, + "ref_a": -17.900242198325806, + "ref_b": 11.703151983731606, + "test_a": -18.068530835428813, + "test_b": 10.775632097292377, + "ref_a_norm": -0.8369878720107697, + "ref_b_norm": 0.5472214379087167, + "test_a_norm": -0.8448567905813582, + "test_b_norm": 0.5038520305343823, + "Rcs_pct": -1.7551985087753417, + "Rhs": 0.04043208125920307, + "Rf_h": 88.89965538416794 + }, + { + "bin": 8, + "ref_a": -23.97681059341231, + "ref_b": 3.098306168084643, + "test_a": -25.23681830016381, + "test_b": 0.9355388031634615, + "ref_a_norm": -0.9917540988052392, + "ref_b_norm": 0.12815540372145023, + "test_a_norm": -1.0438718649621912, + "test_b_norm": 0.03869674154591825, + "Rcs_pct": 3.366381868327954, + "Rhs": 0.09790741084864807, + "Rf_h": 79.6848939764553 + }, + { + "bin": 9, + "ref_a": -15.697228336437052, + "ref_b": -2.509473360011409, + "test_a": -15.853297019522781, + "test_b": -4.280124825868833, + "ref_a_norm": -0.9874610675844115, + "ref_b_norm": -0.15786272519202985, + "test_a_norm": -0.9972788357351492, + "test_b_norm": -0.2692485921311571, + "Rcs_pct": 3.1359427137855063, + "Rhs": 0.10733026718884171, + "Rf_h": 85.4087697816738 + }, + { + "bin": 10, + "ref_a": -17.387791080354155, + "ref_b": -10.58014134998164, + "test_a": -16.93935768196364, + "test_b": -12.683857851898443, + "ref_a_norm": -0.8542799696162753, + "ref_b_norm": -0.5198131717380928, + "test_a_norm": -0.8322479778479356, + "test_b_norm": -0.6231709163206864, + "Rcs_pct": 3.9103554588257725, + "Rhs": 0.09817914261717707, + "Rf_h": 82.4972345947285 + }, + { + "bin": 11, + "ref_a": -14.330676734045857, + "ref_b": -21.18930913947698, + "test_a": -13.315664735269383, + "test_b": -23.24169009245573, + "ref_a_norm": -0.5602217268202898, + "ref_b_norm": -0.8283426928503037, + "test_a_norm": -0.5205423882062972, + "test_b_norm": -0.9085753589629401, + "Rcs_pct": 4.466636438683382, + "Rhs": 0.07756704530177913, + "Rf_h": 82.93841201733196 + }, + { + "bin": 12, + "ref_a": -3.793445918785176, + "ref_b": -20.752438688224405, + "test_a": -2.314526848250725, + "test_b": -21.57952741953776, + "ref_a_norm": -0.1798156843377708, + "ref_b_norm": -0.9837003200498307, + "test_a_norm": -0.1097124456356107, + "test_b_norm": -1.0229057099283814, + "Rcs_pct": 2.4775605892574375, + "Rhs": 0.076404816763847, + "Rf_h": 88.36976568694377 + }, + { + "bin": 13, + "ref_a": 2.855499880788632, + "ref_b": -16.6859343270672, + "test_a": 4.91270320048402, + "test_b": -16.958691050137723, + "ref_a_norm": 0.16867997905454465, + "ref_b_norm": -0.9856708703548858, + "test_a_norm": 0.290203014377285, + "test_b_norm": -1.0017831450021588, + "Rcs_pct": 3.951064990135031, + "Rhs": 0.11604465542511679, + "Rf_h": 85.66406917087093 + }, + { + "bin": 14, + "ref_a": 14.33927321585496, + "ref_b": -17.357696011203327, + "test_a": 16.345935028176754, + "test_b": -16.417432032361596, + "ref_a_norm": 0.6368895503045522, + "ref_b_norm": -0.7709550575181834, + "test_a_norm": 0.7260169363320278, + "test_b_norm": -0.729192529275822, + "Rcs_pct": 1.4792249457262263, + "Rhs": 0.09730873065290084, + "Rf_h": 84.22433355331182 + }, + { + "bin": 15, + "ref_a": 11.991612433584514, + "ref_b": -8.382758201925103, + "test_a": 14.294311513432381, + "test_b": -8.55061474683789, + "ref_a_norm": 0.8195968563872261, + "ref_b_norm": -0.5729406539949637, + "test_a_norm": 0.9769806058622686, + "test_b_norm": -0.5844132309562772, + "Rcs_pct": 13.723362741446678, + "Rhs": 0.07789862725121367, + "Rf_h": 81.22926471570952 + }, + { + "bin": 16, + "ref_a": 22.553112700703736, + "ref_b": -3.969520935572553, + "test_a": 23.477137960771586, + "test_b": -2.5360994931011853, + "ref_a_norm": 0.9848614836084623, + "ref_b_norm": -0.1733431801500663, + "test_a_norm": 1.0252123167993825, + "test_b_norm": -0.11074775985473462, + "Rcs_pct": 2.7363742543509377, + "Rhs": 0.06926472388715063, + "Rf_h": 83.5401923342264 + } + ] + } +} \ No newline at end of file diff --git a/crates/tm30/tests/golden/lamp_L0011.json b/crates/tm30/tests/golden/lamp_L0011.json new file mode 100644 index 0000000..f07ecab --- /dev/null +++ b/crates/tm30/tests/golden/lamp_L0011.json @@ -0,0 +1,941 @@ +{ + "name": "lamp_L0011", + "source": "L0011/spd.csv", + "generator": "crates/tm30/tools/golden.py (tm30.py + colour-science 0.4.7, numpy 2.5.1)", + "wavelengths": [ + 380.0, + 381.92, + 383.84, + 385.76, + 387.68, + 389.6, + 391.52, + 393.44, + 395.36, + 397.28, + 399.2, + 401.12, + 403.04, + 404.96, + 406.88, + 408.8, + 410.72, + 412.64, + 414.56, + 416.48, + 418.4, + 420.32, + 422.23, + 424.15, + 426.07, + 427.99, + 429.91, + 431.83, + 433.75, + 435.67, + 437.59, + 439.51, + 441.43, + 443.35, + 445.27, + 447.19, + 449.11, + 451.03, + 452.95, + 454.87, + 456.79, + 458.71, + 460.63, + 462.55, + 464.47, + 466.39, + 468.31, + 470.23, + 472.15, + 474.07, + 475.99, + 477.91, + 479.83, + 481.75, + 483.67, + 485.59, + 487.51, + 489.43, + 491.35, + 493.27, + 495.19, + 497.11, + 499.03, + 500.95, + 502.87, + 504.79, + 506.7, + 508.62, + 510.54, + 512.46, + 514.38, + 516.3, + 518.22, + 520.14, + 522.06, + 523.98, + 525.9, + 527.82, + 529.74, + 531.66, + 533.58, + 535.5, + 537.42, + 539.34, + 541.26, + 543.18, + 545.1, + 547.02, + 548.94, + 550.86, + 552.78, + 554.7, + 556.62, + 558.54, + 560.46, + 562.38, + 564.3, + 566.22, + 568.14, + 570.06, + 571.98, + 573.9, + 575.82, + 577.74, + 579.66, + 581.58, + 583.5, + 585.42, + 587.34, + 589.26, + 591.17, + 593.09, + 595.01, + 596.93, + 598.85, + 600.77, + 602.69, + 604.61, + 606.53, + 608.45, + 610.37, + 612.29, + 614.21, + 616.13, + 618.05, + 619.97, + 621.89, + 623.81, + 625.73, + 627.65, + 629.57, + 631.49, + 633.41, + 635.33, + 637.25, + 639.17, + 641.09, + 643.01, + 644.93, + 646.85, + 648.77, + 650.69, + 652.61, + 654.53, + 656.45, + 658.37, + 660.29, + 662.21, + 664.13, + 666.05, + 667.97, + 669.89, + 671.81, + 673.72, + 675.64, + 677.56, + 679.48, + 681.4, + 683.32, + 685.24, + 687.16, + 689.08, + 691.0, + 692.92, + 694.84, + 696.76, + 698.68, + 700.6, + 702.52, + 704.44, + 706.36, + 708.28, + 710.2, + 712.12, + 714.04, + 715.96, + 717.88, + 719.8, + 721.72, + 723.64, + 725.56, + 727.48, + 729.4, + 731.32, + 733.24, + 735.16, + 737.08, + 739.0, + 740.92, + 742.84, + 744.76, + 746.68, + 748.6, + 750.52, + 752.44, + 754.36, + 756.28, + 758.19, + 760.11, + 762.03, + 763.95, + 765.87, + 767.79, + 769.71, + 771.63, + 773.55, + 775.47, + 777.39, + 779.31, + 781.23, + 783.15, + 785.07, + 786.99, + 788.91, + 790.83, + 792.75, + 794.67, + 796.59, + 798.51, + 800.43, + 802.35, + 804.27, + 806.19, + 808.11, + 810.03, + 811.95, + 813.87, + 815.79, + 817.71, + 819.63, + 821.55, + 823.47, + 825.39, + 827.31, + 829.23, + 831.15, + 833.07, + 834.99, + 836.91, + 838.83, + 840.74, + 842.66, + 844.58, + 846.5, + 848.42, + 850.34, + 852.26, + 854.18, + 856.1, + 858.02, + 859.94, + 861.86, + 863.78, + 865.7, + 867.62, + 869.54, + 871.46, + 873.38, + 875.3, + 877.22, + 879.14, + 881.06, + 882.98, + 884.9, + 886.82, + 888.74, + 890.66, + 892.58, + 894.5, + 896.42, + 898.34, + 900.26, + 902.18, + 904.1, + 906.02, + 907.94, + 909.86, + 911.78, + 913.7, + 915.62, + 917.54, + 919.46, + 921.38, + 923.3, + 925.21, + 927.13, + 929.05, + 930.97, + 932.89, + 934.81, + 936.73, + 938.65, + 940.57, + 942.49, + 944.41, + 946.33, + 948.25, + 950.17, + 952.09, + 954.01, + 955.93, + 957.85, + 959.77, + 961.69, + 963.61, + 965.53, + 967.45, + 969.37, + 971.29, + 973.21, + 975.13, + 977.05, + 978.97, + 980.89, + 982.81, + 984.73, + 986.65, + 988.57, + 990.49, + 992.41, + 994.33, + 996.25, + 998.17, + 1000.09, + 1002.01, + 1003.93, + 1005.85, + 1007.77, + 1009.68, + 1011.6, + 1013.52, + 1015.44, + 1017.36, + 1019.28, + 1021.2, + 1023.12, + 1025.04, + 1026.96, + 1028.88, + 1030.8, + 1032.72, + 1034.64, + 1036.56, + 1038.48, + 1040.4, + 1042.32, + 1044.24, + 1046.16, + 1048.08, + 1050.0 + ], + "values": [ + 0.0, + 0.00191776, + 0.0227579, + 0.0770541, + 0.164492, + 0.286831, + 0.451499, + 0.640854, + 0.836693, + 1.05988, + 1.31437, + 1.60802, + 1.94939, + 2.34304, + 2.79363, + 3.30068, + 3.87482, + 4.52086, + 5.24959, + 6.06931, + 6.97822, + 7.98503, + 9.09105, + 10.2977, + 11.6088, + 13.052, + 14.6353, + 16.3801, + 18.2898, + 20.3351, + 22.6947, + 25.0558, + 27.0923, + 28.9141, + 30.3982, + 31.4208, + 31.8933, + 31.7581, + 31.0403, + 29.8268, + 28.2507, + 26.4657, + 24.6143, + 22.8195, + 21.1731, + 19.7391, + 18.5276, + 17.5271, + 16.6799, + 15.929, + 15.227, + 14.5388, + 13.8525, + 13.1544, + 12.4423, + 11.7303, + 11.0424, + 10.4051, + 9.83967, + 9.35748, + 8.96453, + 8.6677, + 8.46717, + 8.35741, + 8.3278, + 8.36286, + 8.42977, + 8.53573, + 8.67254, + 8.83685, + 9.02735, + 9.24085, + 9.47965, + 9.74758, + 10.0757, + 10.4401, + 10.8059, + 11.1959, + 11.6104, + 12.0445, + 12.4919, + 12.9465, + 13.3995, + 13.8537, + 14.3083, + 14.7584, + 15.2009, + 15.6339, + 16.0555, + 16.4656, + 16.8646, + 17.2417, + 17.6015, + 17.9427, + 18.2652, + 18.5704, + 18.853, + 19.1137, + 19.3571, + 19.5838, + 19.7922, + 19.983, + 20.1552, + 20.3092, + 20.4428, + 20.5618, + 20.662, + 20.7423, + 20.8085, + 20.8594, + 20.9048, + 20.9737, + 21.0476, + 21.1054, + 21.1569, + 21.2001, + 21.2417, + 21.2894, + 21.345, + 21.4045, + 21.4713, + 21.5483, + 21.6429, + 21.7463, + 21.8546, + 21.963, + 22.0731, + 22.1913, + 22.3156, + 22.4396, + 22.5573, + 22.6722, + 22.7903, + 22.9199, + 23.0599, + 23.1999, + 23.3381, + 23.4739, + 23.6072, + 23.743, + 23.8774, + 24.009, + 24.1386, + 24.269, + 24.4031, + 24.5386, + 24.6739, + 24.8069, + 24.9394, + 25.0733, + 25.2127, + 25.3591, + 25.5083, + 25.6629, + 25.8244, + 25.9913, + 26.1625, + 26.3387, + 26.5181, + 26.697, + 26.8776, + 27.0529, + 27.2175, + 27.375, + 27.5229, + 27.6591, + 27.7851, + 27.9083, + 28.0339, + 28.1642, + 28.2929, + 28.4076, + 28.5057, + 28.5881, + 28.6579, + 28.7162, + 28.7642, + 28.7977, + 28.8215, + 28.8338, + 28.8324, + 28.8227, + 28.803, + 28.7989, + 28.7876, + 28.7358, + 28.6675, + 28.5862, + 28.4902, + 28.3845, + 28.2679, + 28.1377, + 27.9935, + 27.833, + 27.6566, + 27.4633, + 27.2572, + 27.041, + 26.8144, + 26.585, + 26.3469, + 26.0975, + 25.8405, + 25.6234, + 25.4004, + 25.1173, + 24.8219, + 24.5175, + 24.2064, + 23.8921, + 23.5731, + 23.2465, + 22.9134, + 22.5724, + 22.2277, + 21.8799, + 21.527, + 21.1745, + 20.8206, + 20.4671, + 20.1135, + 19.8119, + 19.5046, + 19.1373, + 18.7691, + 18.4034, + 18.0349, + 17.6586, + 17.2759, + 16.8898, + 16.5081, + 16.1317, + 15.7579, + 15.3869, + 15.0172, + 14.6483, + 14.3342, + 14.0227, + 13.6597, + 13.2993, + 12.9449, + 12.5943, + 12.2502, + 11.9119, + 11.5783, + 11.2512, + 10.9315, + 10.6195, + 10.3144, + 10.015, + 9.76276, + 9.51691, + 9.23785, + 8.96866, + 8.7079, + 8.45195, + 8.20142, + 7.95593, + 7.71442, + 7.47895, + 7.24994, + 7.02876, + 6.81539, + 6.636, + 6.45803, + 6.25255, + 6.0484, + 5.84716, + 5.65146, + 5.46213, + 5.27899, + 5.10073, + 4.92601, + 4.75394, + 4.58507, + 4.41866, + 4.27689, + 4.13975, + 3.98729, + 3.8405, + 3.69847, + 3.55805, + 3.41907, + 3.28248, + 3.15002, + 3.0228, + 2.90079, + 2.79916, + 2.70048, + 2.58838, + 2.47806, + 2.36986, + 2.26491, + 2.16513, + 2.07043, + 1.9818, + 1.89777, + 1.81719, + 1.73926, + 1.67202, + 1.60467, + 1.52668, + 1.44884, + 1.37306, + 1.30111, + 1.23427, + 1.17312, + 1.11668, + 1.06352, + 1.01957, + 0.977867, + 0.932468, + 0.890124, + 0.850335, + 0.811285, + 0.773359, + 0.736995, + 0.702003, + 0.668531, + 0.640765, + 0.614075, + 0.584256, + 0.556399, + 0.528725, + 0.501396, + 0.474882, + 0.449735, + 0.426112, + 0.404105, + 0.385923, + 0.366996, + 0.345289, + 0.323411, + 0.301877, + 0.2817, + 0.26297, + 0.244031, + 0.224813, + 0.207067, + 0.192563, + 0.179594, + 0.165, + 0.149655, + 0.134009, + 0.118428, + 0.102761, + 0.0875628, + 0.0736798, + 0.0631096, + 0.0543055 + ], + "expected": { + "Rf": 83.20061325202079, + "Rg": 109.31103632866656, + "CCT_K": 4008.2366766485848, + "Duv": -0.03704734699519552, + "bins": [ + { + "bin": 1, + "ref_a": 21.531163532077905, + "ref_b": 5.048686995910635, + "test_a": 21.785435212283737, + "test_b": 5.5367242062084765, + "ref_a_norm": 0.9735929931108287, + "ref_b_norm": 0.22829078773681985, + "test_a_norm": 0.9850906126345529, + "test_b_norm": 0.25035878269749345, + "Rcs_pct": 1.558194823167353, + "Rhs": 0.01940089033013908, + "Rf_h": 90.05821262659362 + }, + { + "bin": 2, + "ref_a": 20.625817180519245, + "ref_b": 14.417308930209545, + "test_a": 19.420268711813595, + "test_b": 15.785857325760526, + "ref_a_norm": 0.8196193522586226, + "ref_b_norm": 0.5729084720993014, + "test_a_norm": 0.7717138149221365, + "test_b_norm": 0.6272912264735373, + "Rcs_pct": -0.9618559036371136, + "Rhs": 0.07183249823645123, + "Rf_h": 84.17518952057907 + }, + { + "bin": 3, + "ref_a": 14.616244523298993, + "ref_b": 22.320079042365585, + "test_a": 12.28587803535944, + "test_b": 24.732093830745352, + "ref_a_norm": 0.5478359706649715, + "ref_b_norm": 0.8365857692105267, + "test_a_norm": 0.4604907853206492, + "test_b_norm": 0.9269912396953657, + "Rcs_pct": 2.664301651917275, + "Rhs": 0.12285145569824632, + "Rf_h": 75.0638369003622 + }, + { + "bin": 4, + "ref_a": 3.739811023650333, + "ref_b": 22.13373328438182, + "test_a": 1.1377035867914689, + "test_b": 23.965935429992424, + "ref_a_norm": 0.16660288010227498, + "ref_b_norm": 0.9860240769583809, + "test_a_norm": 0.05068296046604451, + "test_b_norm": 1.067645889520008, + "Rcs_pct": 5.743861787035952, + "Rhs": 0.12961617658092814, + "Rf_h": 77.80838663500623 + }, + { + "bin": 5, + "ref_a": -2.229334231861381, + "ref_b": 19.11485580553453, + "test_a": -3.971195975926115, + "test_b": 20.593142480558022, + "ref_a_norm": -0.11584315895634167, + "ref_b_norm": 0.9932675181052766, + "test_a_norm": -0.20635572724413187, + "test_b_norm": 1.0700839038361878, + "Rcs_pct": 9.29985065124262, + "Rhs": 0.07378726123979826, + "Rf_h": 82.60519942543387 + }, + { + "bin": 6, + "ref_a": -11.175708979042474, + "ref_b": 17.11891056115798, + "test_a": -12.328931941535203, + "test_b": 18.632412283904394, + "ref_a_norm": -0.5466521549101321, + "ref_b_norm": 0.8373597921635054, + "test_a_norm": -0.6030612667365668, + "test_b_norm": 0.9113916929360695, + "Rcs_pct": 9.289449923522541, + "Rhs": 0.005772541977559086, + "Rf_h": 86.38512883357566 + }, + { + "bin": 7, + "ref_a": -18.252314370889888, + "ref_b": 11.16843290144685, + "test_a": -18.417179191912663, + "test_b": 11.923132364681464, + "ref_a_norm": -0.8529855793801452, + "ref_b_norm": 0.5219344799584698, + "test_a_norm": -0.8606902086135644, + "test_b_norm": 0.5572038570809544, + "Rcs_pct": 2.6000781148040937, + "Rhs": -0.025044952663644236, + "Rf_h": 88.69890817104836 + }, + { + "bin": 8, + "ref_a": -22.836673859359276, + "ref_b": 3.47970648377201, + "test_a": -23.218033125624956, + "test_b": 3.418572800889572, + "ref_a_norm": -0.9885894562211018, + "ref_b_norm": 0.15063494630551813, + "test_a_norm": -1.0050983292725928, + "test_b_norm": 0.14798849635883407, + "Rcs_pct": 1.5675362912649822, + "Rhs": 0.00581632051277042, + "Rf_h": 90.64984214190741 + }, + { + "bin": 9, + "ref_a": -19.36111163364288, + "ref_b": -2.2212707528961957, + "test_a": -19.115162836473623, + "test_b": -2.846058634598173, + "ref_a_norm": -0.993482954807069, + "ref_b_norm": -0.11398078130902325, + "test_a_norm": -0.9808625049916581, + "test_b_norm": -0.14604072304100216, + "Rcs_pct": -0.6123367054712685, + "Rhs": 0.03390604655978708, + "Rf_h": 90.30786756541741 + }, + { + "bin": 10, + "ref_a": -20.09183984579758, + "ref_b": -11.367057735506402, + "test_a": -18.799073917593997, + "test_b": -12.629289978589364, + "ref_a_norm": -0.8703623482626497, + "ref_b_norm": -0.49241180197749734, + "test_a_norm": -0.814360767637839, + "test_b_norm": -0.5470906879119929, + "Rcs_pct": -1.6185651130561012, + "Rhs": 0.07657664328628215, + "Rf_h": 83.14694382650767 + }, + { + "bin": 11, + "ref_a": -11.966769234438049, + "ref_b": -17.407076748900195, + "test_a": -9.11510818827123, + "test_b": -19.455034011149888, + "ref_a_norm": -0.5665096626479182, + "ref_b_norm": -0.8240550965357485, + "test_a_norm": -0.43151135979763056, + "test_b_norm": -0.9210058737276101, + "Rcs_pct": 0.5610586552362422, + "Rhs": 0.16610995240834442, + "Rf_h": 75.3335125540531 + }, + { + "bin": 12, + "ref_a": -7.90844091045402, + "ref_b": -24.367711874038044, + "test_a": -4.180966111071847, + "test_b": -26.36030988927084, + "ref_a_norm": -0.30869538491826315, + "ref_b_norm": -0.9511609534301569, + "test_a_norm": -0.16319840504611444, + "test_b_norm": -1.0289393446787478, + "Rcs_pct": 4.789884861442973, + "Rhs": 0.15787510759631254, + "Rf_h": 70.7229628325106 + }, + { + "bin": 13, + "ref_a": 3.3637531072497553, + "ref_b": -17.976884412196853, + "test_a": 6.244321704267421, + "test_b": -18.810313367600482, + "ref_a_norm": 0.18392338528539948, + "ref_b_norm": -0.9829405823065597, + "test_a_norm": 0.3414271945775971, + "test_b_norm": -1.0285108337445552, + "Rcs_pct": 7.542210070824177, + "Rhs": 0.14558710273383052, + "Rf_h": 79.56492813945194 + }, + { + "bin": 14, + "ref_a": 10.353790713765369, + "ref_b": -14.463599970908737, + "test_a": 13.157778991347373, + "test_b": -14.9329550627646, + "ref_a_norm": 0.5820809755368568, + "ref_b_norm": -0.8131308246020817, + "test_a_norm": 0.7397187216658085, + "test_b_norm": -0.8395175536072788, + "Rcs_pct": 10.951860268543005, + "Rhs": 0.11641131447604423, + "Rf_h": 80.76920338085374 + }, + { + "bin": 15, + "ref_a": 15.518360149768192, + "ref_b": -10.956096746269367, + "test_a": 17.531345907934767, + "test_b": -11.491167957596804, + "ref_a_norm": 0.8169192454724592, + "ref_b_norm": -0.5767520666427717, + "test_a_norm": 0.9228870662239842, + "test_b_norm": -0.6049193450158138, + "Rcs_pct": 10.375792424605516, + "Rhs": 0.035452330839052956, + "Rf_h": 85.76628657712249 + }, + { + "bin": 16, + "ref_a": 20.15920768488482, + "ref_b": -3.50836906480488, + "test_a": 21.29959014330147, + "test_b": -4.00311939559416, + "ref_a_norm": 0.985191784642476, + "ref_b_norm": -0.17145596365531582, + "test_a_norm": 1.040922914900381, + "test_b_norm": -0.1956346897720278, + "Rcs_pct": 5.937730768123732, + "Rhs": -0.012841534525834813, + "Rf_h": 87.77368585773596 + } + ] + } +} \ No newline at end of file diff --git a/crates/tm30/tests/golden/negated_FL2.json b/crates/tm30/tests/golden/negated_FL2.json new file mode 100644 index 0000000..11b106b --- /dev/null +++ b/crates/tm30/tests/golden/negated_FL2.json @@ -0,0 +1,403 @@ +{ + "name": "negated_FL2", + "source": "-1 * FL2 (scale invariance incl. sign)", + "generator": "crates/tm30/tools/golden.py (tm30.py + colour-science 0.4.7, numpy 2.5.1)", + "wavelengths": [ + 380.0, + 385.0, + 390.0, + 395.0, + 400.0, + 405.0, + 410.0, + 415.0, + 420.0, + 425.0, + 430.0, + 435.0, + 440.0, + 445.0, + 450.0, + 455.0, + 460.0, + 465.0, + 470.0, + 475.0, + 480.0, + 485.0, + 490.0, + 495.0, + 500.0, + 505.0, + 510.0, + 515.0, + 520.0, + 525.0, + 530.0, + 535.0, + 540.0, + 545.0, + 550.0, + 555.0, + 560.0, + 565.0, + 570.0, + 575.0, + 580.0, + 585.0, + 590.0, + 595.0, + 600.0, + 605.0, + 610.0, + 615.0, + 620.0, + 625.0, + 630.0, + 635.0, + 640.0, + 645.0, + 650.0, + 655.0, + 660.0, + 665.0, + 670.0, + 675.0, + 680.0, + 685.0, + 690.0, + 695.0, + 700.0, + 705.0, + 710.0, + 715.0, + 720.0, + 725.0, + 730.0, + 735.0, + 740.0, + 745.0, + 750.0, + 755.0, + 760.0, + 765.0, + 770.0, + 775.0, + 780.0 + ], + "values": [ + -1.18, + -1.48, + -1.84, + -2.15, + -3.44, + -15.69, + -3.85, + -3.74, + -4.19, + -4.62, + -5.06, + -34.98, + -11.81, + -6.27, + -6.63, + -6.93, + -7.19, + -7.4, + -7.54, + -7.62, + -7.65, + -7.62, + -7.62, + -7.45, + -7.28, + -7.15, + -7.05, + -7.04, + -7.16, + -7.47, + -8.04, + -8.88, + -10.01, + -24.88, + -16.64, + -14.59, + -16.16, + -17.56, + -18.62, + -21.47, + -22.79, + -19.29, + -18.66, + -17.73, + -16.54, + -15.21, + -13.8, + -12.36, + -10.95, + -9.65, + -8.4, + -7.32, + -6.31, + -5.43, + -4.68, + -4.02, + -3.45, + -2.96, + -2.55, + -2.19, + -1.89, + -1.64, + -1.53, + -1.27, + -1.1, + -0.99, + -0.88, + -0.76, + -0.68, + -0.61, + -0.56, + -0.54, + -0.51, + -0.47, + -0.47, + -0.43, + -0.46, + -0.47, + -0.4, + -0.33, + -0.27 + ], + "expected": { + "Rf": 70.20781906305379, + "Rg": 86.43829403927003, + "CCT_K": 4225.108266234531, + "Duv": 0.0018621252165094363, + "bins": [ + { + "bin": 1, + "ref_a": 21.44150569987737, + "ref_b": 4.911710850800025, + "test_a": 16.168126568827844, + "test_b": 3.371924328142029, + "ref_a_norm": 0.9747517901272056, + "ref_b_norm": 0.22329117233739448, + "test_a_norm": 0.7350188245435725, + "test_b_norm": 0.15329097317306012, + "Rcs_pct": -24.878292526800465, + "Rhs": -0.021885583512081308, + "Rf_h": 60.35070543403967 + }, + { + "bin": 2, + "ref_a": 20.635169564608816, + "ref_b": 14.292768265389933, + "test_a": 15.009402988490473, + "test_b": 14.751771239986297, + "ref_a_norm": 0.82206386812768, + "ref_b_norm": 0.5693952903905657, + "test_a_norm": 0.5979445838994997, + "test_b_norm": 0.5876810505146769, + "Rcs_pct": -17.6189350353636, + "Rhs": 0.13971805684388874, + "Rf_h": 61.40655822137029 + }, + { + "bin": 3, + "ref_a": 14.628925569603425, + "ref_b": 22.26452256690993, + "test_a": 7.921265503505507, + "test_b": 23.902806028585434, + "ref_a_norm": 0.5491242372455207, + "ref_b_norm": 0.8357407325657432, + "test_a_norm": 0.2973396000229725, + "test_b_norm": 0.8972367837968591, + "Rcs_pct": -8.875195169721376, + "Rhs": 0.24351665020742566, + "Rf_h": 52.6920029392565 + }, + { + "bin": 4, + "ref_a": 3.835519445060082, + "ref_b": 22.11129922974916, + "test_a": -0.23280081833055, + "test_b": 24.154981655413774, + "ref_a_norm": 0.17091192885142428, + "ref_b_norm": 0.9852863099507094, + "test_a_norm": -0.010373676230558399, + "test_b_norm": 1.07635342884642, + "Rcs_pct": 5.395022266931121, + "Rhs": 0.1955685665638469, + "Rf_h": 68.43722661711175 + }, + { + "bin": 5, + "ref_a": -2.1896569983462593, + "ref_b": 19.141537391803148, + "test_a": -4.32496456361688, + "test_b": 20.885987380138207, + "ref_a_norm": -0.1136517613201618, + "ref_b_norm": 0.9935206475704593, + "test_a_norm": -0.2244825745190134, + "test_b_norm": 1.0840644239970645, + "Rcs_pct": 11.042602218760873, + "Rhs": 0.09103701570093099, + "Rf_h": 79.64398650227432 + }, + { + "bin": 6, + "ref_a": -11.110069918888163, + "ref_b": 17.22633455214125, + "test_a": -10.471008611815796, + "test_b": 18.74344691822782, + "ref_a_norm": -0.5419996069285619, + "ref_b_norm": 0.8403787396699682, + "test_a_norm": -0.5108232975294993, + "test_b_norm": 0.9143903626470153, + "Rcs_pct": 4.421778598507902, + "Rhs": -0.06704080851257976, + "Rf_h": 87.5761514709081 + }, + { + "bin": 7, + "ref_a": -18.195188593305904, + "ref_b": 11.341780805069275, + "test_a": -15.366736336726074, + "test_b": 12.595693256153485, + "ref_a_norm": -0.848631003347337, + "ref_b_norm": 0.528985274046161, + "test_a_norm": -0.7167108386228853, + "test_b_norm": 0.5874682612389842, + "Rcs_pct": -7.7196201395928625, + "Rhs": -0.12191774334345938, + "Rf_h": 76.84965255972465 + }, + { + "bin": 8, + "ref_a": -22.72718403807425, + "ref_b": 3.698593182290253, + "test_a": -19.051288813943362, + "test_b": 4.94914539188827, + "ref_a_norm": -0.9870154023076927, + "ref_b_norm": 0.16062563807619118, + "test_a_norm": -0.8273755103875893, + "test_b_norm": 0.2149356788711857, + "Rcs_pct": -14.597709281299553, + "Rhs": -0.08441068651114254, + "Rf_h": 72.81568281316467 + }, + { + "bin": 9, + "ref_a": -19.34913651987008, + "ref_b": -2.039171712629464, + "test_a": -16.043949788236674, + "test_b": -1.5094621968538244, + "ref_a_norm": -0.9944924933423362, + "ref_b_norm": -0.10480782740684566, + "test_a_norm": -0.8246149698503379, + "test_b_norm": -0.07758221263329221, + "Rcs_pct": -17.19248284655656, + "Rhs": 0.006438978541526419, + "Rf_h": 76.23588711921641 + }, + { + "bin": 10, + "ref_a": -20.19059925839228, + "ref_b": -11.169472867275275, + "test_a": -15.11614626554033, + "test_b": -12.3731508921473, + "ref_a_norm": -0.8750302756952433, + "ref_b_norm": -0.48406819418002106, + "test_a_norm": -0.655111097244303, + "test_b_norm": -0.5362337936490059, + "Rcs_pct": -15.387445979190643, + "Rhs": 0.16555465998347502, + "Rf_h": 62.39561559761673 + }, + { + "bin": 11, + "ref_a": -12.16646596983228, + "ref_b": -17.30142734213172, + "test_a": -8.402886110495205, + "test_b": -18.894689447143964, + "ref_a_norm": -0.5752210401151883, + "ref_b_norm": -0.8179980165066422, + "test_a_norm": -0.3972819141099486, + "test_b_norm": -0.893326208562884, + "Rcs_pct": -3.6224579053580275, + "Rhs": 0.18980107732666204, + "Rf_h": 69.72091464664942 + }, + { + "bin": 12, + "ref_a": -5.488851063738376, + "ref_b": -23.66221352505178, + "test_a": -3.018223745513694, + "test_b": -25.399554871361985, + "ref_a_norm": -0.2259670919429864, + "ref_b_norm": -0.9741349359092045, + "test_a_norm": -0.12425537415520334, + "test_b_norm": -1.0456584600819752, + "Rcs_pct": 5.030624793518598, + "Rhs": 0.11371090301337923, + "Rf_h": 76.64358892974491 + }, + { + "bin": 13, + "ref_a": 3.538118811028049, + "ref_b": -15.379355619950259, + "test_a": 2.620549926198063, + "test_b": -17.319472658585592, + "ref_a_norm": 0.22419987261004892, + "ref_b_norm": -0.9745431838156983, + "test_a_norm": 0.16605631156042633, + "test_b_norm": -1.0974825242230486, + "Rcs_pct": 10.923384940567608, + "Rhs": -0.08101062433621685, + "Rf_h": 81.40090148306182 + }, + { + "bin": 14, + "ref_a": 13.843460665470982, + "ref_b": -18.679468563263917, + "test_a": 11.871759134004922, + "test_b": -21.856487165054602, + "ref_a_norm": 0.595416865010529, + "ref_b_norm": -0.8034169259239151, + "test_a_norm": 0.5106126117265082, + "test_b_norm": -0.9400627041487624, + "Rcs_pct": 6.650209348533657, + "Rhs": -0.14642848644919484, + "Rf_h": 71.4405875637361 + }, + { + "bin": 15, + "ref_a": 15.26876386478876, + "ref_b": -11.132723084889403, + "test_a": 11.493185633754575, + "test_b": -14.588476319460835, + "ref_a_norm": 0.8080264387977029, + "ref_b_norm": -0.5891462248066283, + "test_a_norm": 0.608221984459389, + "test_b_norm": -0.7720254679609351, + "Rcs_pct": -6.452906845131275, + "Rhs": -0.2630639406587859, + "Rf_h": 63.656538232435295 + }, + { + "bin": 16, + "ref_a": 20.01194727333166, + "ref_b": -3.699076972051818, + "test_a": 16.0741918720872, + "test_b": -6.432073793519327, + "ref_a_norm": 0.983342121626454, + "ref_b_norm": -0.1817643304809396, + "test_a_norm": 0.7898496694518533, + "test_b_norm": -0.316057653170311, + "Rcs_pct": -16.357522139388895, + "Rhs": -0.16946141895260983, + "Rf_h": 65.3578438523645 + } + ] + } +} \ No newline at end of file diff --git a/crates/tm30/tests/golden/noisy_lamp_L0001.json b/crates/tm30/tests/golden/noisy_lamp_L0001.json new file mode 100644 index 0000000..111f5d7 --- /dev/null +++ b/crates/tm30/tests/golden/noisy_lamp_L0001.json @@ -0,0 +1,941 @@ +{ + "name": "noisy_lamp_L0001", + "source": "first lamp + 1% gaussian noise (negative values)", + "generator": "crates/tm30/tools/golden.py (tm30.py + colour-science 0.4.7, numpy 2.5.1)", + "wavelengths": [ + 380.0, + 381.92, + 383.84, + 385.76, + 387.68, + 389.6, + 391.52, + 393.44, + 395.36, + 397.28, + 399.2, + 401.12, + 403.04, + 404.96, + 406.88, + 408.8, + 410.72, + 412.64, + 414.56, + 416.48, + 418.4, + 420.32, + 422.23, + 424.15, + 426.07, + 427.99, + 429.91, + 431.83, + 433.75, + 435.67, + 437.59, + 439.51, + 441.43, + 443.35, + 445.27, + 447.19, + 449.11, + 451.03, + 452.95, + 454.87, + 456.79, + 458.71, + 460.63, + 462.55, + 464.47, + 466.39, + 468.31, + 470.23, + 472.15, + 474.07, + 475.99, + 477.91, + 479.83, + 481.75, + 483.67, + 485.59, + 487.51, + 489.43, + 491.35, + 493.27, + 495.19, + 497.11, + 499.03, + 500.95, + 502.87, + 504.79, + 506.7, + 508.62, + 510.54, + 512.46, + 514.38, + 516.3, + 518.22, + 520.14, + 522.06, + 523.98, + 525.9, + 527.82, + 529.74, + 531.66, + 533.58, + 535.5, + 537.42, + 539.34, + 541.26, + 543.18, + 545.1, + 547.02, + 548.94, + 550.86, + 552.78, + 554.7, + 556.62, + 558.54, + 560.46, + 562.38, + 564.3, + 566.22, + 568.14, + 570.06, + 571.98, + 573.9, + 575.82, + 577.74, + 579.66, + 581.58, + 583.5, + 585.42, + 587.34, + 589.26, + 591.17, + 593.09, + 595.01, + 596.93, + 598.85, + 600.77, + 602.69, + 604.61, + 606.53, + 608.45, + 610.37, + 612.29, + 614.21, + 616.13, + 618.05, + 619.97, + 621.89, + 623.81, + 625.73, + 627.65, + 629.57, + 631.49, + 633.41, + 635.33, + 637.25, + 639.17, + 641.09, + 643.01, + 644.93, + 646.85, + 648.77, + 650.69, + 652.61, + 654.53, + 656.45, + 658.37, + 660.29, + 662.21, + 664.13, + 666.05, + 667.97, + 669.89, + 671.81, + 673.72, + 675.64, + 677.56, + 679.48, + 681.4, + 683.32, + 685.24, + 687.16, + 689.08, + 691.0, + 692.92, + 694.84, + 696.76, + 698.68, + 700.6, + 702.52, + 704.44, + 706.36, + 708.28, + 710.2, + 712.12, + 714.04, + 715.96, + 717.88, + 719.8, + 721.72, + 723.64, + 725.56, + 727.48, + 729.4, + 731.32, + 733.24, + 735.16, + 737.08, + 739.0, + 740.92, + 742.84, + 744.76, + 746.68, + 748.6, + 750.52, + 752.44, + 754.36, + 756.28, + 758.19, + 760.11, + 762.03, + 763.95, + 765.87, + 767.79, + 769.71, + 771.63, + 773.55, + 775.47, + 777.39, + 779.31, + 781.23, + 783.15, + 785.07, + 786.99, + 788.91, + 790.83, + 792.75, + 794.67, + 796.59, + 798.51, + 800.43, + 802.35, + 804.27, + 806.19, + 808.11, + 810.03, + 811.95, + 813.87, + 815.79, + 817.71, + 819.63, + 821.55, + 823.47, + 825.39, + 827.31, + 829.23, + 831.15, + 833.07, + 834.99, + 836.91, + 838.83, + 840.74, + 842.66, + 844.58, + 846.5, + 848.42, + 850.34, + 852.26, + 854.18, + 856.1, + 858.02, + 859.94, + 861.86, + 863.78, + 865.7, + 867.62, + 869.54, + 871.46, + 873.38, + 875.3, + 877.22, + 879.14, + 881.06, + 882.98, + 884.9, + 886.82, + 888.74, + 890.66, + 892.58, + 894.5, + 896.42, + 898.34, + 900.26, + 902.18, + 904.1, + 906.02, + 907.94, + 909.86, + 911.78, + 913.7, + 915.62, + 917.54, + 919.46, + 921.38, + 923.3, + 925.21, + 927.13, + 929.05, + 930.97, + 932.89, + 934.81, + 936.73, + 938.65, + 940.57, + 942.49, + 944.41, + 946.33, + 948.25, + 950.17, + 952.09, + 954.01, + 955.93, + 957.85, + 959.77, + 961.69, + 963.61, + 965.53, + 967.45, + 969.37, + 971.29, + 973.21, + 975.13, + 977.05, + 978.97, + 980.89, + 982.81, + 984.73, + 986.65, + 988.57, + 990.49, + 992.41, + 994.33, + 996.25, + 998.17, + 1000.09, + 1002.01, + 1003.93, + 1005.85, + 1007.77, + 1009.68, + 1011.6, + 1013.52, + 1015.44, + 1017.36, + 1019.28, + 1021.2, + 1023.12, + 1025.04, + 1026.96, + 1028.88, + 1030.8, + 1032.72, + 1034.64, + 1036.56, + 1038.48, + 1040.4, + 1042.32, + 1044.24, + 1046.16, + 1048.08, + 1050.0 + ], + "values": [ + 0.5453554216008005, + 0.24792618513574294, + 0.2864476428600886, + 0.35703020371347705, + 0.8506453563404788, + 0.663604942033018, + 0.8684545319821, + 0.9679475826071613, + 0.9652971901696067, + 1.2921500149457124, + 1.7936543339217699, + 1.613677044221842, + 1.9249636606471179, + 1.9963508598132864, + 2.2671027801864154, + 2.4677914832778947, + 2.813032064912369, + 3.1497651772905817, + 3.5158668782266034, + 3.4362231780308345, + 3.7067696426290615, + 4.33621571200596, + 4.27351860892673, + 4.6107463387094665, + 4.657570849173851, + 4.894154756708831, + 5.348676423978722, + 5.532700431076364, + 5.84584348954998, + 5.983242415199149, + 6.224370108576785, + 6.14210264590153, + 6.165825580208871, + 6.278175662146519, + 6.638920845710629, + 6.526713920382358, + 6.720034016889225, + 6.5819910366581125, + 6.298699600812516, + 5.93651428796073, + 6.145793204117674, + 5.966322116153378, + 5.739302076711518, + 5.611549654491431, + 5.131931418600654, + 4.716973767517189, + 4.698242592291026, + 4.168552080099767, + 3.858636426209516, + 3.689469926950953, + 3.7488410045803198, + 3.213304399895535, + 2.8471786136862205, + 2.7638330095155648, + 2.7242887049365248, + 2.5668123301489034, + 2.4173407888440885, + 2.2510829533469803, + 1.9271720373463845, + 2.344954701568824, + 2.0109138638172466, + 1.6803216933967142, + 1.7633120030951823, + 1.6265216229583623, + 1.7008538312019938, + 1.4185665449137213, + 1.3777628901480852, + 1.4758104502798477, + 1.065786249404564, + 1.2551702348484088, + 1.624900144413397, + 1.2710533675635787, + 1.362690326355507, + 1.2029237730197535, + 1.3528554393437615, + 1.4837289361360018, + 1.3254643342718229, + 1.75687384435553, + 1.7602094931435461, + 1.742262039018851, + 1.8525474916208522, + 1.845662219832019, + 2.3109033604237568, + 2.050229840646995, + 2.4501406852862946, + 2.707773330412885, + 2.6749432620831843, + 2.725331288845762, + 3.1074125366051426, + 3.512022946308676, + 3.1481943800548806, + 3.4199601171866187, + 3.846804976339234, + 3.9208259553048252, + 4.703000997049231, + 4.350244155561139, + 4.920442748384943, + 4.903600288109004, + 5.157495221752436, + 5.075425636830895, + 5.40891620402872, + 5.840999123533478, + 5.944358078374631, + 5.7879909786785495, + 6.3918831302214905, + 6.224085758009058, + 6.49454966395334, + 6.580751401737383, + 7.0783269981076185, + 7.0452665771395555, + 7.1575212179072025, + 7.267243037430282, + 7.5682775699646765, + 7.551673703488912, + 7.975250935392335, + 7.876103518667443, + 7.692387318678556, + 7.696692922450508, + 8.270347306786208, + 8.016572168633465, + 8.407586114427172, + 8.758677089614691, + 8.484225027110003, + 8.508782663023581, + 8.855149230808518, + 8.909867766661197, + 9.157560992043718, + 9.340063530466402, + 9.192683899028182, + 9.4387189984302, + 10.082060093689318, + 10.307433889384885, + 9.853889989869128, + 10.167882734450483, + 10.46356297761499, + 10.434483046122672, + 10.904512866562975, + 10.991298684423537, + 10.937560995618584, + 11.184413513612439, + 11.4947142052223, + 11.664027910828649, + 12.027854468483236, + 11.929268024947117, + 12.323580523346536, + 12.735712249697217, + 12.480923272359549, + 12.508624407263522, + 12.756088558454232, + 12.965446931205275, + 13.346380940282831, + 13.26518103709863, + 13.645408929022008, + 13.732296630167676, + 13.700867173646204, + 14.074634734128422, + 14.0166584654046, + 14.585976611102788, + 14.53580149124191, + 14.66763502673162, + 14.871968915539638, + 15.383716814838182, + 15.026249159035286, + 15.555462566491483, + 15.615869900592221, + 15.293971281828837, + 15.607649413009286, + 15.856943186968829, + 16.234562416546694, + 16.00655591485063, + 16.317643278044024, + 16.21385736940332, + 16.315720973055424, + 16.168664921271322, + 16.391792838821896, + 16.744486075693356, + 16.08988491342065, + 16.367806346128663, + 16.656302533962954, + 16.402864564829876, + 16.40148216977564, + 16.309791570300522, + 16.192847606535018, + 16.138972091355164, + 16.26595488493571, + 16.052782389074835, + 16.15318356197244, + 15.899188942098167, + 15.627590410662702, + 15.813024742733877, + 15.62014707325854, + 15.504033141053595, + 15.509022162974123, + 15.159594694867852, + 15.24753849981161, + 14.938879169935552, + 14.922061503921077, + 14.897251446561517, + 14.75038455654482, + 14.319415835741527, + 13.977895640234369, + 14.25951373294831, + 13.910416722204667, + 13.495324368086884, + 13.315511427984209, + 13.209108275453566, + 12.998021430785812, + 12.840879906698634, + 12.572726820414037, + 12.663697078955082, + 12.62211649326545, + 12.24054233714328, + 11.74463465561313, + 11.856806444991932, + 11.447483105006294, + 10.807896048491045, + 11.259385017232274, + 10.97519453865023, + 10.423678159362586, + 10.696690439015494, + 10.415675880799714, + 10.118363170409337, + 9.70193823038893, + 9.710594140217072, + 9.378413773023523, + 9.323611017158123, + 9.323399246067734, + 8.899903296035326, + 8.59237494115713, + 8.49147750296854, + 8.63765448193255, + 8.361310225504882, + 8.219681630723352, + 7.804342771297438, + 7.5133056225473105, + 7.540789735815707, + 7.567361019562632, + 6.9989862039494595, + 6.864624563528695, + 6.716688562475295, + 6.419869583820905, + 6.312989119703392, + 6.118607625590668, + 5.966147570490692, + 5.795549033600284, + 5.649410859784361, + 5.672569575831347, + 5.318588146765684, + 5.207583723649856, + 4.9415463906110935, + 4.661986516467027, + 4.8459504615678135, + 4.991318755702628, + 4.804169533403984, + 4.481613443643415, + 4.5311663574007985, + 4.095379622430777, + 3.983808437038917, + 4.052961250179712, + 3.622903953384483, + 3.403503409694699, + 3.405218797845082, + 3.449845375708257, + 3.302705921952876, + 3.1095603190978953, + 3.0592165362124084, + 2.890621549096419, + 2.886511729041452, + 2.6475261037727944, + 2.507518409479103, + 2.5681638822823545, + 2.623204826085835, + 2.230592243120556, + 2.5947649227299547, + 2.065161224687839, + 2.2668115236051745, + 2.083250791855044, + 1.8220136440972399, + 1.78633874391315, + 1.8418117099632867, + 1.8747422129023499, + 1.56898376419711, + 1.8114741264850749, + 1.6850030337175428, + 1.6469801566439943, + 1.413412117217328, + 1.1517225947976613, + 1.2048537911887356, + 1.1749698883099515, + 1.4792965649928864, + 1.274473161411588, + 1.0552724866487355, + 1.095383374657857, + 0.6218753745272292, + 1.126529321091678, + 0.9379957065304115, + 1.066942242548534, + 1.0527666207138757, + 1.0566082323367465, + 0.7744623450664437, + 0.9764330734009883, + 0.7507793776882276, + 0.8104532693277038, + 0.599173363360422, + 0.4935566964655351, + 0.5520988027165603, + 0.7587992829254306, + 0.32356305600709034, + 0.6168872094325119, + 0.5596248974908146, + 0.32030496947350917, + 0.5856379095264607, + 0.4431205633921064, + 0.48805695295599894, + 0.6618772722452989, + 0.4615747450353673, + 0.08659599126732487, + 0.270833772459754, + 0.30808689316712534, + 0.10569851309417974, + 0.36314261284125016, + 0.29892245669533124, + 0.2955184450733182, + 0.4928502639589154, + 0.39366727621181924, + 0.1927381393182026, + 0.1272374839994576, + 0.16520082947405715, + 0.42536802119058775, + 0.34863764862314983, + 0.43443976876542717, + 0.15213973458388788, + 0.3106978351316271, + 0.18203205354082658, + 0.3150031306906286, + 0.2176395893876707, + 0.06147665211713431, + -0.15288661743694343, + -0.14834456578907668, + 0.20078926249959456, + -0.03323407054499297, + 0.2507267857200565, + -0.02435845093768929, + 0.35675647061372284, + 0.018441532474515444, + -0.044601156517043876, + 0.032982744563187644, + -0.12736383908879145, + -0.09709590370360706, + 0.016187720445118414 + ], + "expected": { + "Rf": 72.47485948140613, + "Rg": 119.38111304502854, + "CCT_K": 2167.402520413509, + "Duv": -0.05154116223532573, + "bins": [ + { + "bin": 1, + "ref_a": 26.097046584192945, + "ref_b": 5.262013185119905, + "test_a": 25.674522880009597, + "test_b": 5.348032086407478, + "ref_a_norm": 0.980271716412549, + "ref_b_norm": 0.1976546533770335, + "test_a_norm": 0.9644006470412096, + "test_b_norm": 0.2008857429847045, + "Rcs_pct": -1.4935756911644607, + "Rhs": 0.006265297161262439, + "Rf_h": 88.7602554642485 + }, + { + "bin": 2, + "ref_a": 19.99148867160726, + "ref_b": 13.336293698479441, + "test_a": 17.397619030780568, + "test_b": 15.990499208814683, + "ref_a_norm": 0.8318844255981913, + "ref_b_norm": 0.554948918772861, + "test_a_norm": 0.7239485038826516, + "test_b_norm": 0.6653955324620491, + "Rcs_pct": -2.838458807880947, + "Rhs": 0.15179898824296614, + "Rf_h": 72.4946806437725 + }, + { + "bin": 3, + "ref_a": 15.798580936678434, + "ref_b": 23.360366678902114, + "test_a": 10.094369537063837, + "test_b": 29.972636942185535, + "ref_a_norm": 0.5602115672358245, + "ref_b_norm": 0.8283495638528345, + "test_a_norm": 0.3579424380760255, + "test_b_norm": 1.0628181089726627, + "Rcs_pct": 8.25787630879437, + "Rhs": 0.2984443786512616, + "Rf_h": 41.13579866563478 + }, + { + "bin": 4, + "ref_a": 3.146531186212088, + "ref_b": 19.060882498275234, + "test_a": -1.4719302203254956, + "test_b": 25.176957603310537, + "ref_a_norm": 0.16287364212010538, + "ref_b_norm": 0.9866469361947727, + "test_a_norm": -0.07619140626401004, + "test_b_norm": 1.3032328426692625, + "Rcs_pct": 26.38635197812351, + "Rhs": 0.2962343269539026, + "Rf_h": 48.38496153172893 + }, + { + "bin": 5, + "ref_a": -2.4505940362775136, + "ref_b": 14.920642761237048, + "test_a": -5.032891818984542, + "test_b": 19.389092154577252, + "ref_a_norm": -0.16207044417960473, + "ref_b_norm": 0.9867791906619361, + "test_a_norm": -0.33285113753470047, + "test_b_norm": 1.2823008344968356, + "Rcs_pct": 32.316093877461874, + "Rhs": 0.10984577756124964, + "Rf_h": 64.78775000507581 + }, + { + "bin": 6, + "ref_a": -10.94519856623889, + "ref_b": 14.279160991485774, + "test_a": -12.55374381808494, + "test_b": 19.658019467607552, + "ref_a_norm": -0.6083559908275689, + "ref_b_norm": 0.7936642794180716, + "test_a_norm": -0.697762147742459, + "test_b_norm": 1.0926319736046177, + "Rcs_pct": 29.8253952206866, + "Rhs": -0.0917590488970683, + "Rf_h": 62.05387683775908 + }, + { + "bin": 7, + "ref_a": -18.887590486968204, + "ref_b": 12.108529390866801, + "test_a": -20.389666308636563, + "test_b": 18.077980227598992, + "ref_a_norm": -0.8418568709253954, + "ref_b_norm": 0.5397008512830993, + "test_a_norm": -0.9088073298521124, + "test_b_norm": 0.8057709572620338, + "Rcs_pct": 20.348790290554188, + "Rhs": -0.18403352579691631, + "Rf_h": 58.227653655102216 + }, + { + "bin": 8, + "ref_a": -17.676278457063137, + "ref_b": 3.730409964368773, + "test_a": -16.64014799399707, + "test_b": 7.621544830274941, + "ref_a_norm": -0.9784482527772738, + "ref_b_norm": 0.206492170885726, + "test_a_norm": -0.9210945488458218, + "test_b_norm": 0.4218810673728879, + "Rcs_pct": -1.4231379418194028, + "Rhs": -0.22243941180570811, + "Rf_h": 71.7236050179908 + }, + { + "bin": 9, + "ref_a": -25.240362310520993, + "ref_b": -5.326442302591451, + "test_a": -25.677236330984186, + "test_b": -2.7109869751104525, + "ref_a_norm": -0.9784505664277444, + "ref_b_norm": -0.20648120751590468, + "test_a_norm": -0.995386124939977, + "test_b_norm": -0.10509226090900387, + "Rcs_pct": -0.3169855738211002, + "Rhs": -0.1027447499913118, + "Rf_h": 79.25917733394792 + }, + { + "bin": 10, + "ref_a": -18.887451181785476, + "ref_b": -13.477983766183426, + "test_a": -18.861781284167236, + "test_b": -12.611047646203557, + "ref_a_norm": -0.8139994526414126, + "ref_b_norm": -0.5808656394550126, + "test_a_norm": -0.8128931475921236, + "test_b_norm": -0.5435029736116072, + "Rcs_pct": -2.1677443999274915, + "Rhs": -0.030451291129381598, + "Rf_h": 88.59637321299031 + }, + { + "bin": 11, + "ref_a": -11.534689676218749, + "ref_b": -16.962905432667434, + "test_a": -10.150424849229037, + "test_b": -17.406770116402935, + "ref_a_norm": -0.562307153987059, + "ref_b_norm": -0.8269284519080075, + "test_a_norm": -0.49482531987809497, + "test_b_norm": -0.848566510154278, + "Rcs_pct": -1.949951039950089, + "Rhs": 0.06813055550601721, + "Rf_h": 79.12974784664695 + }, + { + "bin": 12, + "ref_a": -5.570355310815754, + "ref_b": -20.200226341048523, + "test_a": -3.3165685115860275, + "test_b": -20.816716018942753, + "ref_a_norm": -0.2658349376970278, + "ref_b_norm": -0.9640185609725662, + "test_a_norm": -0.1582771177869946, + "test_b_norm": -0.9934393942891887, + "Rcs_pct": 0.7872030532539134, + "Rhs": 0.11123084640574482, + "Rf_h": 73.94053796085824 + }, + { + "bin": 13, + "ref_a": 2.6749094231080672, + "ref_b": -13.091038289684615, + "test_a": 4.233345387994121, + "test_b": -14.519171361961103, + "ref_a_norm": 0.20019487833533833, + "ref_b_norm": -0.9797560975509666, + "test_a_norm": 0.31683093923838995, + "test_b_norm": -1.0866400631092703, + "Rcs_pct": 12.758478681097912, + "Rhs": 0.09354290443879752, + "Rf_h": 81.88317342598697 + }, + { + "bin": 14, + "ref_a": 12.159807539783609, + "ref_b": -16.70440659445249, + "test_a": 14.524173271445989, + "test_b": -18.724553882770692, + "ref_a_norm": 0.5885245453747189, + "ref_b_norm": -0.808479350071157, + "test_a_norm": 0.7029578752422843, + "test_b_norm": -0.9062527943101107, + "Rcs_pct": 14.487139951457966, + "Rhs": 0.040827821220509354, + "Rf_h": 78.93369770369928 + }, + { + "bin": 15, + "ref_a": 17.439839937726205, + "ref_b": -10.687211010005196, + "test_a": 19.04510799466717, + "test_b": -13.100788393503155, + "ref_a_norm": 0.8526387845138872, + "ref_b_norm": -0.5225008164038415, + "test_a_norm": 0.9311208009645248, + "test_b_norm": -0.6405013080335954, + "Rcs_pct": 13.081297242210354, + "Rhs": -0.05451155085957221, + "Rf_h": 79.56678114445705 + }, + { + "bin": 16, + "ref_a": 18.265731510644432, + "ref_b": -3.300552476297597, + "test_a": 18.524190891086302, + "test_b": -3.4047325447185064, + "ref_a_norm": 0.9840636118556848, + "ref_b_norm": -0.1778167816083292, + "test_a_norm": 0.99798807315018, + "test_b_norm": -0.18342946754723663, + "Rcs_pct": 1.4751887382382232, + "Rhs": -0.002788312114562408, + "Rf_h": 91.86380075337156 + } + ] + } +} \ No newline at end of file diff --git a/crates/tm30/tests/golden/partial_400_700_FL4.json b/crates/tm30/tests/golden/partial_400_700_FL4.json new file mode 100644 index 0000000..368d79a --- /dev/null +++ b/crates/tm30/tests/golden/partial_400_700_FL4.json @@ -0,0 +1,483 @@ +{ + "name": "partial_400_700_FL4", + "source": "FL4 on 400-700 nm / 2.5 nm", + "generator": "crates/tm30/tools/golden.py (tm30.py + colour-science 0.4.7, numpy 2.5.1)", + "wavelengths": [ + 400.0, + 402.5, + 405.0, + 407.5, + 410.0, + 412.5, + 415.0, + 417.5, + 420.0, + 422.5, + 425.0, + 427.5, + 430.0, + 432.5, + 435.0, + 437.5, + 440.0, + 442.5, + 445.0, + 447.5, + 450.0, + 452.5, + 455.0, + 457.5, + 460.0, + 462.5, + 465.0, + 467.5, + 470.0, + 472.5, + 475.0, + 477.5, + 480.0, + 482.5, + 485.0, + 487.5, + 490.0, + 492.5, + 495.0, + 497.5, + 500.0, + 502.5, + 505.0, + 507.5, + 510.0, + 512.5, + 515.0, + 517.5, + 520.0, + 522.5, + 525.0, + 527.5, + 530.0, + 532.5, + 535.0, + 537.5, + 540.0, + 542.5, + 545.0, + 547.5, + 550.0, + 552.5, + 555.0, + 557.5, + 560.0, + 562.5, + 565.0, + 567.5, + 570.0, + 572.5, + 575.0, + 577.5, + 580.0, + 582.5, + 585.0, + 587.5, + 590.0, + 592.5, + 595.0, + 597.5, + 600.0, + 602.5, + 605.0, + 607.5, + 610.0, + 612.5, + 615.0, + 617.5, + 620.0, + 622.5, + 625.0, + 627.5, + 630.0, + 632.5, + 635.0, + 637.5, + 640.0, + 642.5, + 645.0, + 647.5, + 650.0, + 652.5, + 655.0, + 657.5, + 660.0, + 662.5, + 665.0, + 667.5, + 670.0, + 672.5, + 675.0, + 677.5, + 680.0, + 682.5, + 685.0, + 687.5, + 690.0, + 692.5, + 695.0, + 697.5, + 700.0 + ], + "values": [ + 2.01, + 7.879999999999999, + 13.75, + 7.85, + 1.95, + 1.77, + 1.59, + 1.675, + 1.76, + 1.845, + 1.93, + 2.015, + 2.1, + 16.19, + 30.28, + 19.155, + 8.03, + 5.289999999999999, + 2.55, + 2.625, + 2.7, + 2.76, + 2.82, + 2.865, + 2.91, + 2.95, + 2.99, + 3.015, + 3.04, + 3.06, + 3.08, + 3.085, + 3.09, + 3.09, + 3.09, + 3.115, + 3.14, + 3.1, + 3.06, + 3.0300000000000002, + 3.0, + 2.99, + 2.98, + 2.995, + 3.01, + 3.075, + 3.14, + 3.2750000000000004, + 3.41, + 3.6550000000000002, + 3.9, + 4.295, + 4.69, + 5.25, + 5.81, + 6.5649999999999995, + 7.32, + 14.955, + 22.59, + 18.85, + 15.11, + 14.495000000000001, + 13.88, + 15.105, + 16.33, + 17.505, + 18.68, + 19.66, + 20.64, + 22.46, + 24.28, + 25.270000000000003, + 26.26, + 24.770000000000003, + 23.28, + 23.11, + 22.94, + 22.54, + 22.14, + 21.525, + 20.91, + 20.17, + 19.43, + 18.585, + 17.74, + 16.869999999999997, + 16.0, + 15.21, + 14.42, + 13.49, + 12.56, + 11.745000000000001, + 10.93, + 10.225, + 9.52, + 8.85, + 8.18, + 7.595, + 7.01, + 6.505, + 6.0, + 5.555, + 5.11, + 4.735, + 4.36, + 4.025, + 3.69, + 3.41, + 3.13, + 2.885, + 2.64, + 2.4400000000000004, + 2.24, + 2.075, + 1.91, + 1.805, + 1.7, + 1.545, + 1.39, + 1.285, + 1.18 + ], + "expected": { + "Rf": 56.8356555516847, + "Rg": 83.5377468871798, + "CCT_K": 2939.564218078963, + "Duv": -0.0007601824311253511, + "bins": [ + { + "bin": 1, + "ref_a": 24.04298939659253, + "ref_b": 5.109936969080378, + "test_a": 17.57500752244677, + "test_b": 2.731364778678295, + "ref_a_norm": 0.9781522187996382, + "ref_b_norm": 0.20788996333961068, + "test_a_norm": 0.715012277380866, + "test_b_norm": 0.11112139487088903, + "Rcs_pct": -27.696239241330268, + "Rhs": -0.04357313165312099, + "Rf_h": 50.175221885017095 + }, + { + "bin": 2, + "ref_a": 20.57520933860629, + "ref_b": 15.097592622486312, + "test_a": 12.763843232637116, + "test_b": 16.215539663051427, + "ref_a_norm": 0.8062348085375289, + "ref_b_norm": 0.5915956672444906, + "test_a_norm": 0.5001482383734174, + "test_b_norm": 0.6354021628855292, + "Rcs_pct": -23.016409683430574, + "Rhs": 0.2064763570572338, + "Rf_h": 46.39965141829197 + }, + { + "bin": 3, + "ref_a": 14.838253269418317, + "ref_b": 22.885412454689412, + "test_a": 5.645547432443409, + "test_b": 26.1959934793031, + "ref_a_norm": 0.5440275205555183, + "ref_b_norm": 0.8390673732652314, + "test_a_norm": 0.20698751504537172, + "test_b_norm": 0.9604460257061286, + "Rcs_pct": -8.632673331136198, + "Rhs": 0.3476728889321639, + "Rf_h": 33.95336183518188 + }, + { + "bin": 4, + "ref_a": 2.7226029318275513, + "ref_b": 20.3950919565657, + "test_a": -2.712288039936026, + "test_b": 24.464182359259265, + "ref_a_norm": 0.13231926078257533, + "ref_b_norm": 0.9912071495030454, + "test_a_norm": -0.13181795416375722, + "test_b_norm": 1.188966076391613, + "Rcs_pct": 14.242843024032233, + "Rhs": 0.29764274515432176, + "Rf_h": 52.44410114844987 + }, + { + "bin": 5, + "ref_a": -2.930798625857884, + "ref_b": 16.775957012934022, + "test_a": -5.573714109580976, + "test_b": 19.676358999181744, + "ref_a_norm": -0.17209580034487695, + "ref_b_norm": 0.9850802178014013, + "test_a_norm": -0.3272871708478766, + "test_b_norm": 1.1553911346761714, + "Rcs_pct": 19.731477480830716, + "Rhs": 0.11898340021898522, + "Rf_h": 70.39040542510631 + }, + { + "bin": 6, + "ref_a": -12.748146318978613, + "ref_b": 16.87019184943558, + "test_a": -11.78933428355901, + "test_b": 20.180578609653065, + "ref_a_norm": -0.6028866503532788, + "ref_b_norm": 0.7978268526602771, + "test_a_norm": -0.5575424126979608, + "test_b_norm": 0.954382004703846, + "Rcs_pct": 10.49789428933711, + "Rhs": -0.12467973800468658, + "Rf_h": 75.78688716496266 + }, + { + "bin": 7, + "ref_a": -18.744529199655993, + "ref_b": 13.09104265233394, + "test_a": -14.912113779708292, + "test_b": 18.703792999400406, + "ref_a_norm": -0.8198505122855705, + "ref_b_norm": 0.5725776257461406, + "test_a_norm": -0.6522278575969211, + "test_b_norm": 0.8180687873730705, + "Rcs_pct": -0.29855618377684795, + "Rhs": -0.29724459830638217, + "Rf_h": 53.92293934162444 + }, + { + "bin": 8, + "ref_a": -21.446070057267512, + "ref_b": 5.644332766876604, + "test_a": -16.283941349885396, + "test_b": 7.525472983229173, + "ref_a_norm": -0.9670675438125093, + "ref_b_norm": 0.2545198729066958, + "test_a_norm": -0.7342916964632479, + "test_b_norm": 0.33934612050064766, + "Rcs_pct": -21.17543447550209, + "Rhs": -0.12860865004893252, + "Rf_h": 60.499472445759956 + }, + { + "bin": 9, + "ref_a": -22.581715646267394, + "ref_b": -3.88001108912216, + "test_a": -17.14456813775265, + "test_b": -2.0048128260252125, + "ref_a_norm": -0.9855577878047015, + "ref_b_norm": -0.1693394428286065, + "test_a_norm": -0.7482585872302145, + "test_b_norm": -0.08749817439608476, + "Rcs_pct": -24.870600238761963, + "Rhs": -0.03397393395390041, + "Rf_h": 59.00154187239486 + }, + { + "bin": 10, + "ref_a": -18.077532004978845, + "ref_b": -11.973678599856552, + "test_a": -11.41002327863737, + "test_b": -12.312880226221385, + "ref_a_norm": -0.8337070293646541, + "ref_b_norm": -0.5522070166051529, + "test_a_norm": -0.5262121295094034, + "test_b_norm": -0.5678504562181708, + "Rcs_pct": -24.698163577662296, + "Rhs": 0.18384205783503504, + "Rf_h": 49.33283019472565 + }, + { + "bin": 11, + "ref_a": -10.884615313886929, + "ref_b": -15.823390416257256, + "test_a": -4.250886066042329, + "test_b": -16.63459350885252, + "ref_a_norm": -0.5667421601341195, + "ref_b_norm": -0.8238952141665298, + "test_a_norm": -0.22133592066218297, + "test_b_norm": -0.8661330865898542, + "Rcs_pct": -15.677791754154242, + "Rhs": 0.31066089664508967, + "Rf_h": 51.38058308300528 + }, + { + "bin": 12, + "ref_a": -6.6010425307741825, + "ref_b": -21.173037687896805, + "test_a": -2.2867445579623205, + "test_b": -22.99798769997993, + "ref_a_norm": -0.2976369154379854, + "ref_b_norm": -0.9546791432562887, + "test_a_norm": -0.10310789446567621, + "test_b_norm": -1.0369650079348838, + "Rcs_pct": 4.275403551904815, + "Rhs": 0.2068443762184149, + "Rf_h": 61.368412083415556 + }, + { + "bin": 13, + "ref_a": 3.2672074517581193, + "ref_b": -18.032174106938147, + "test_a": 3.7498032183046064, + "test_b": -20.364684396357518, + "ref_a_norm": 0.1782848392296918, + "ref_b_norm": -0.9839789205571646, + "test_a_norm": 0.2046191047827933, + "test_b_norm": -1.1112592442253053, + "Rcs_pct": 12.997222828548407, + "Rhs": 0.000997100693977174, + "Rf_h": 79.20423020367551 + }, + { + "bin": 14, + "ref_a": 9.380605657392541, + "ref_b": -13.983001520660213, + "test_a": 7.9312837067062, + "test_b": -17.208518459426386, + "ref_a_norm": 0.5571074386603216, + "ref_b_norm": -0.8304404263939321, + "test_a_norm": 0.4710332480130747, + "test_b_norm": -1.0220015628217682, + "Rcs_pct": 11.145700568302333, + "Rhs": -0.17799373912943445, + "Rf_h": 70.32701733753734 + }, + { + "bin": 15, + "ref_a": 18.912298870098123, + "ref_b": -13.43725695130802, + "test_a": 15.578595164686872, + "test_b": -18.600364001860985, + "ref_a_norm": 0.8151891408635289, + "ref_b_norm": -0.5791948416709023, + "test_a_norm": 0.6714943379115459, + "test_b_norm": -0.8017436089908458, + "Rcs_pct": 0.41636084177903526, + "Rhs": -0.2648750924416619, + "Rf_h": 56.87508556756948 + }, + { + "bin": 16, + "ref_a": 16.888743478210728, + "ref_b": -4.179238875339611, + "test_a": 12.394084159756094, + "test_b": -6.874214425093358, + "ref_a_norm": 0.9707205371536406, + "ref_b_norm": -0.24021165406396758, + "test_a_norm": 0.7123793459595198, + "test_b_norm": -0.39511175759434836, + "Rcs_pct": -22.315772656695664, + "Rhs": -0.2023236076556252, + "Rf_h": 59.906609839428086 + } + ] + } +} \ No newline at end of file diff --git a/crates/tm30/tools/extract_data.py b/crates/tm30/tools/extract_data.py new file mode 100644 index 0000000..760ddbf --- /dev/null +++ b/crates/tm30/tools/extract_data.py @@ -0,0 +1,162 @@ +"""Extract the spectral tables used by the TM-30-18 path of colour-science. + +Writes plain CSV files into ``crates/tm30/data`` containing the *effective* +arrays colour-science 0.4.7 uses when ``colour_fidelity_index_ANSIIESTM3018`` +is called on a 380-780 nm / 1 nm spectral distribution (which is what +``tm30.py`` always builds). "Effective" matters: colour re-aligns its 1 nm +CMFs and 5 nm D-series basis functions with a Sprague interpolator, which is +not bit-exact even on the original nodes, so the arrays are dumped exactly as +the pipeline sees them (same reshape calls, same order). + +Usage (from the repository root, with a Python that has colour-science 0.4.7): + + python -W ignore crates/tm30/tools/extract_data.py + +Values are written with ``repr`` (shortest round-trip), so Rust's +``str::parse::`` recovers the identical doubles. +""" + +from __future__ import annotations + +import os +import sys +import warnings + +import numpy as np + +with warnings.catch_warnings(): + warnings.simplefilter("ignore") + import colour + from colour.appearance.ciecam02 import CAT_INVERSE_CAT02, MATRIX_XYZ_TO_HPE + from colour.adaptation import CAT_CAT02 + from colour.colorimetry import ( + MSDS_CMFS, + SDS_BASIS_FUNCTIONS_CIE_ILLUMINANT_D_SERIES, + SDS_ILLUMINANTS, + SPECTRAL_SHAPE_DEFAULT, + SpectralShape, + reshape_msds, + reshape_sd, + ) + from colour.quality.cfi2017 import load_TCS_CIE2017 + +HERE = os.path.dirname(os.path.abspath(__file__)) +DATA = os.path.normpath(os.path.join(HERE, "..", "data")) + +SHAPE = SpectralShape(380, 780, 1) + + +def fmt(x: float) -> str: + return repr(float(x)) + + +def write_csv(name: str, header: list[str], rows) -> None: + path = os.path.join(DATA, name) + with open(path, "w", newline="\n") as f: + f.write(",".join(header) + "\n") + for row in rows: + f.write(",".join(fmt(v) for v in row) + "\n") + print(f"wrote {path}") + + +def main() -> int: + assert colour.__version__ == "0.4.7", colour.__version__ + os.makedirs(DATA, exist_ok=True) + + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + + # --- CIE 1931 2 degree observer ------------------------------------- + # handle_spectral_arguments() reshapes the default observer to + # SPECTRAL_SHAPE_DEFAULT (360-780 nm, 1 nm); this array feeds the + # Ohno (2013) Planckian table (CCT_to_uv_Planck1900). + cmfs_2_default = reshape_msds( + MSDS_CMFS["CIE 1931 2 Degree Standard Observer"], + SPECTRAL_SHAPE_DEFAULT, + copy=False, + ) + assert cmfs_2_default.shape == SpectralShape(360, 780, 1) + # sd_to_XYZ_integration() then re-aligns *that* array to the test + # shape (380-780 nm) for the test SPD CCT and the reference mixing + # normalisation. + cmfs_2_test = reshape_msds(cmfs_2_default, SHAPE, copy=False) + + # --- CIE 1964 10 degree observer ------------------------------------ + cmfs_10 = reshape_msds( + MSDS_CMFS["CIE 1964 10 Degree Standard Observer"], SHAPE, copy=False + ) + + # --- Illuminant E (implicit weighting in the integration) ----------- + for shape in (SPECTRAL_SHAPE_DEFAULT, SHAPE): + E = reshape_sd(SDS_ILLUMINANTS["E"], shape, copy=False) + assert np.all(E.values == 100.0), "illuminant E is not exactly 100" + E2 = reshape_sd( + reshape_sd(SDS_ILLUMINANTS["E"], SPECTRAL_SHAPE_DEFAULT, copy=False), + SHAPE, + copy=False, + ) + assert np.all(E2.values == 100.0) + + # --- CIE D-series basis functions ----------------------------------- + basis = [ + reshape_sd(SDS_BASIS_FUNCTIONS_CIE_ILLUMINANT_D_SERIES[n], SHAPE, copy=False) + for n in ("S0", "S1", "S2") + ] + + # --- CIE 2017 test colour samples ----------------------------------- + tcs = load_TCS_CIE2017(SHAPE) + assert tcs.shape == SHAPE and tcs.values.shape == (401, 99) + + wl_default = cmfs_2_default.wavelengths + write_csv( + "cmf_cie1931_2deg_360_780.csv", + ["wavelength_nm", "x_bar", "y_bar", "z_bar"], + ( + [w, *v] + for w, v in zip(wl_default, cmfs_2_default.values, strict=True) + ), + ) + write_csv( + "cmf_cie1931_2deg_380_780.csv", + ["wavelength_nm", "x_bar", "y_bar", "z_bar"], + ([w, *v] for w, v in zip(SHAPE.wavelengths, cmfs_2_test.values, strict=True)), + ) + write_csv( + "cmf_cie1964_10deg_380_780.csv", + ["wavelength_nm", "x_bar", "y_bar", "z_bar"], + ([w, *v] for w, v in zip(SHAPE.wavelengths, cmfs_10.values, strict=True)), + ) + write_csv( + "d_series_basis_380_780.csv", + ["wavelength_nm", "S0", "S1", "S2"], + ( + [w, a, b, c] + for w, a, b, c in zip( + SHAPE.wavelengths, + basis[0].values, + basis[1].values, + basis[2].values, + strict=True, + ) + ), + ) + write_csv( + "tcs_cie2017_380_780.csv", + ["wavelength_nm", *[f"TCS{i:02d}" for i in range(99)]], + ([w, *v] for w, v in zip(SHAPE.wavelengths, tcs.values, strict=True)), + ) + + # CIECAM02 matrices exactly as colour uses them: CAT02 (literal) and the + # numpy product MATRIX_XYZ_TO_HPE @ inv(CAT02) used by RGB_to_rgb(). + hpe_cat02_inv = np.matmul(MATRIX_XYZ_TO_HPE, CAT_INVERSE_CAT02) + path = os.path.join(DATA, "ciecam02_matrices.csv") + with open(path, "w", newline="\n") as f: + f.write("name,m00,m01,m02,m10,m11,m12,m20,m21,m22\n") + for name, m in (("CAT02", CAT_CAT02), ("HPE_CAT02_INV", hpe_cat02_inv)): + f.write(name + "," + ",".join(fmt(v) for v in np.ravel(m)) + "\n") + print(f"wrote {path}") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/crates/tm30/tools/golden.py b/crates/tm30/tools/golden.py new file mode 100644 index 0000000..4339a58 --- /dev/null +++ b/crates/tm30/tools/golden.py @@ -0,0 +1,214 @@ +"""Generate golden test vectors for the ``tm30`` crate. + +Every case runs the production Python reference ``compute_tm30`` (HPCS +``tm30.py`` on colour-science 0.4.7) and writes one JSON file into +``crates/tm30/tests/golden`` holding the exact input (wavelengths, values) +and every output field. NaN is encoded as ``null``. Floats are written with +``repr`` so they round-trip exactly. + +Usage (from the repository root): + + python -W ignore crates/tm30/tools/golden.py [--tm30-dir DIR] [--lamps-dir DIR] + +``--tm30-dir`` is the folder containing ``tm30.py`` (defaults to the HPCS +scratch copy), ``--lamps-dir`` the buildfor.life ``comparison-data/lamps`` +folder with ``L*/spd.csv`` files (read only). +""" + +from __future__ import annotations + +import argparse +import csv +import glob +import json +import math +import os +import sys +import warnings + +import numpy as np + +HERE = os.path.dirname(os.path.abspath(__file__)) +OUT = os.path.normpath(os.path.join(HERE, "..", "tests", "golden")) + +DEFAULT_TM30_DIR = os.path.join( + os.path.expanduser("~"), "AppData", "Local", "hermes", "cache", "scratch", "hpcs-py" +) +DEFAULT_LAMPS_DIR = "C:/dev/buildfor_life_web/apps/web/comparison-data/lamps" + +# HPCS 6500 grid: 350 points, 380..1050 nm. +HPCS_GRID = np.linspace(380.0, 1050.0, 350) + + +def clean(x): + x = float(x) + return None if math.isnan(x) else x + + +def read_lamp_csv(path): + wl, vals = [], [] + with open(path, newline="") as f: + reader = csv.DictReader(f) + for row in reader: + wl.append(float(row["wavelength_nm"])) + vals.append(float(row["value"])) + return np.array(wl), np.array(vals) + + +def build_cases(lamps_dir): + import colour + from colour.colorimetry import SDS_ILLUMINANTS, SpectralShape, sd_blackbody + from colour.colorimetry import sd_CIE_illuminant_D_series + from colour.temperature import CCT_to_xy_CIE_D + + cases = [] + + # Real lamps measured with the HPCS 6500 (380-1050 nm, ~1.92 nm steps). + for path in sorted(glob.glob(os.path.join(lamps_dir, "L*", "spd.csv"))): + lamp = os.path.basename(os.path.dirname(path)) + wl, vals = read_lamp_csv(path) + cases.append((f"lamp_{lamp}", f"{lamp}/spd.csv", wl, vals)) + + # colour-science illuminant library. + names = ( + [f"FL{i}" for i in range(1, 13)] + + ["A", "D50", "D65"] + + [k for k in SDS_ILLUMINANTS.keys() if k.startswith("LED-")] + + [f"HP{i}" for i in range(1, 6)] + ) + for name in names: + sd = SDS_ILLUMINANTS[name] + cases.append( + ( + "illuminant_" + name.replace("-", "_").replace(".", "_"), + f"colour.SDS_ILLUMINANTS[{name!r}] {sd.shape}", + sd.wavelengths, + sd.values, + ) + ) + + # Planckian radiators, covering the < 4000 K (pure Planckian reference) + # and 4000-5000 K (Planckian / daylight mixture) regimes. + shape = SpectralShape(360, 830, 1) + for T in (2700, 4300, 4700): + sd = sd_blackbody(T, shape) + cases.append((f"blackbody_{T}K", f"sd_blackbody({T}, {shape})", sd.wavelengths, sd.values)) + + # CIE daylight (> 5000 K regime). + for T in (6500, 10000): + xy = CCT_to_xy_CIE_D(T * 1.4388 / 1.4380) + sd = sd_CIE_illuminant_D_series(xy) + cases.append((f"daylight_{T}K", f"sd_CIE_illuminant_D_series(CCT_to_xy_CIE_D({T}*1.4388/1.4380))", sd.wavelengths, sd.values)) + + # Grid variations. + # Coarse 10 nm grid. + d50 = SDS_ILLUMINANTS["D50"] + wl10 = np.arange(380.0, 781.0, 10.0) + cases.append(("grid_10nm_D50", "D50 sampled every 10 nm", wl10, d50[wl10])) + # HPCS 6500 grid (380-1050 nm, 670/349 nm steps), blackbody and LED. + bb = sd_blackbody(3000, SpectralShape(360, 1100, 1)) + cases.append(("hpcs_grid_blackbody_3000K", "sd_blackbody(3000) on 380-1050 nm / 350 points", HPCS_GRID, bb[HPCS_GRID])) + led = SDS_ILLUMINANTS["LED-B3"] + cases.append( + ( + "hpcs_grid_LED_B3", + "LED-B3 linearly resampled on 380-1050 nm / 350 points (0 beyond 780)", + HPCS_GRID, + np.interp(HPCS_GRID, led.wavelengths, led.values, right=0.0), + ) + ) + # Irregular, non-uniform grid. + rng = np.random.default_rng(20180) + wl_irr = np.sort(np.concatenate([[371.3], rng.uniform(372.0, 800.0, 240), [801.7]])) + fl11 = SDS_ILLUMINANTS["FL11"] + cases.append( + ( + "irregular_grid_FL11", + "FL11 linearly resampled on 242 random wavelengths 371-802 nm", + wl_irr, + np.interp(wl_irr, fl11.wavelengths, fl11.values), + ) + ) + # Partial coverage (400-700 nm only): np.interp holds the end values. + fl4 = SDS_ILLUMINANTS["FL4"] + wl_p = np.arange(400.0, 701.0, 2.5) + cases.append( + ( + "partial_400_700_FL4", + "FL4 on 400-700 nm / 2.5 nm", + wl_p, + np.interp(wl_p, fl4.wavelengths, fl4.values), + ) + ) + # Negated spectrum: colour normalises by Y, so a negative scale must give + # exactly the positive-scale result. + fl2 = SDS_ILLUMINANTS["FL2"] + cases.append(("negated_FL2", "-1 * FL2 (scale invariance incl. sign)", fl2.wavelengths, -fl2.values)) + # Noisy real lamp with negative values (dark-noise like). + if cases and cases[0][0].startswith("lamp_"): + _, _, wl, vals = cases[0] + noise = rng.normal(0.0, 0.01 * float(np.max(vals)), vals.shape) + cases.append(("noisy_" + cases[0][0], "first lamp + 1% gaussian noise (negative values)", wl, vals + noise)) + + return cases + + +def main() -> int: + ap = argparse.ArgumentParser() + ap.add_argument("--tm30-dir", default=DEFAULT_TM30_DIR) + ap.add_argument("--lamps-dir", default=DEFAULT_LAMPS_DIR) + args = ap.parse_args() + + sys.path.insert(0, args.tm30_dir) + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + import colour # noqa: F401 + from tm30 import compute_tm30 + + cases = build_cases(args.lamps_dir) + + os.makedirs(OUT, exist_ok=True) + for old in glob.glob(os.path.join(OUT, "*.json")): + os.remove(old) + + for name, source, wl, vals in cases: + wl = [float(x) for x in np.asarray(wl, dtype=float)] + vals = [float(x) for x in np.asarray(vals, dtype=float)] + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + res = compute_tm30(wl, vals) + expected = { + "Rf": clean(res["Rf"]), + "Rg": clean(res["Rg"]), + "CCT_K": clean(res["CCT_K"]), + "Duv": clean(res["Duv"]), + "bins": [ + {k: (v if k == "bin" else clean(v)) for k, v in b.items()} + for b in res["bins"] + ], + } + doc = { + "name": name, + "source": source, + "generator": "crates/tm30/tools/golden.py (tm30.py + colour-science " + + __import__("colour").__version__ + + ", numpy " + + np.__version__ + + ")", + "wavelengths": wl, + "values": vals, + "expected": expected, + } + path = os.path.join(OUT, name + ".json") + with open(path, "w", newline="\n") as f: + json.dump(doc, f, indent=1, allow_nan=False) + print( + f"{name:32s} CCT={expected['CCT_K']:9.2f} Duv={expected['Duv']: .5f} " + f"Rf={expected['Rf']:6.2f} Rg={expected['Rg']:6.2f}" + ) + print(f"{len(cases)} cases -> {OUT}") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/src/bundle.rs b/src/bundle.rs new file mode 100644 index 0000000..e98ae66 --- /dev/null +++ b/src/bundle.rs @@ -0,0 +1,346 @@ +//! The per-lamp data bundle for the buildfor.life comparison pages: +//! +//! ```text +//! /spd.csv full spectrum, wavelength_nm,value (380-1050 nm) +//! /tm30.csv TM-30-18 hue-bin data for the colour vector graphic +//! /metrics.json photometric / colorimetric / CRI / TM-30 / electrical summary +//! ``` +//! +//! Byte for byte what the former `lamp_export.py` wrote, so re-measured +//! lamps only change where the measurement changed. + +use crate::pyjson; +use anyhow::{Context, Result, bail}; +use hpcs6500::{PsuSettings, Reading, pyfmt}; +use serde_json::{Map, Value, json}; +use std::path::Path; + +/// Scalars grouped as in metrics.json; keys missing from a reading are left out. +pub const SCALAR_GROUPS: [(&str, &[&str]); 5] = [ + ( + "photometric", + &["Phi_lm", "eta_lm_W", "CCT_K", "Duv", "SDCM", "TLCI"], + ), + ( + "chromaticity", + &[ + "x", "y", "u", "v", "u_prime", "v_prime", "CIE_X", "CIE_Y", "CIE_Z", + ], + ), + ( + "radiometric", + &[ + "Phi_e_mW", + "Phi_euv_mW", + "Phi_eb_mW", + "Phi_ey_mW", + "Phi_er_mW", + "Phi_efr_mW", + "Phi_eir_mW", + "Phi_e_total", + ], + ), + ( + "electrical", + &[ + "Voltage_V", + "Current_A", + "Power_W", + "Freq_Hz", + "PF", + "UThd", + "AThd", + ], + ), + ("sensor", &["PeakSignal", "DarkSignal", "Compensate"]), +]; + +/// Identification of the lamp (what the station asks for). +#[derive(Debug, Clone, Default)] +pub struct LampMeta { + pub name: String, + pub ean: String, + /// led, halogen, cfl, incandescent, ... + pub lamp_type: String, + pub dimmable: Option, + pub variant: String, + pub manufacturer: String, + pub model: String, + pub notes: String, + /// Advertised values from the packaging, keyed like the measured ones. + pub rated: Map, +} + +/// Element-wise average of the scalars and spectra; everything else +/// (strings, harmonics lists) comes from the first reading. +pub fn average(readings: &[Reading]) -> Reading { + let mut out = readings[0].clone(); + let n = readings.len() as f64; + if readings.len() == 1 { + return out; + } + for (name, _) in readings[0].scalars() { + let sum = readings + .iter() + .fold(0.0, |s, r| s + r.get(name).unwrap_or(0.0)); + out.set(name, sum / n); + } + for (i, v) in out.spectrum.iter_mut().enumerate() { + *v = readings + .iter() + .fold(0.0, |s, r| s + r.spectrum.get(i).copied().unwrap_or(0.0)) + / n; + } + out +} + +/// Write the bundle into `dir`; returns the TM-30 result. +/// `measured_at` is the local time, ISO 8601 with offset, to the second. +pub fn write( + reading: &Reading, + dir: &Path, + meta: &LampMeta, + n_readings: usize, + supply: Option<&PsuSettings>, + measured_at: &str, +) -> Result { + let nm = reading.spectrum_nm(); + let spectrum = &reading.spectrum; + if spectrum.is_empty() || spectrum.iter().cloned().fold(f64::NEG_INFINITY, f64::max) <= 0.0 { + bail!("reading contains no spectrum data"); + } + let tm = tm30::compute(&nm, spectrum).context("TM-30")?; + std::fs::create_dir_all(dir).with_context(|| dir.display().to_string())?; + std::fs::write(dir.join("spd.csv"), spd_csv(&nm, spectrum))?; + std::fs::write(dir.join("tm30.csv"), tm30_csv(&tm))?; + let m = metrics(reading, meta, n_readings, supply, &tm, measured_at); + std::fs::write(dir.join("metrics.json"), pyjson::file_text(&m))?; + Ok(tm) +} + +pub fn spd_csv(nm: &[f64], values: &[f64]) -> String { + let mut s = String::from("wavelength_nm,value\r\n"); + for (wl, v) in nm.iter().zip(values) { + s.push_str(&format!("{},{}\r\n", pyfmt::fixed(*wl, 2), pyfmt::g(*v, 6))); + } + s +} + +pub fn tm30_csv(tm: &tm30::Tm30) -> String { + let mut s = String::from( + "bin,ref_a,ref_b,test_a,test_b,ref_a_norm,ref_b_norm,test_a_norm,test_b_norm,Rcs_pct,Rhs,Rf_h\r\n", + ); + for b in &tm.bins { + let cells: Vec = [ + b.ref_a, + b.ref_b, + b.test_a, + b.test_b, + b.ref_a_norm, + b.ref_b_norm, + b.test_a_norm, + b.test_b_norm, + b.rcs_pct, + b.rhs, + b.rf_h, + ] + .iter() + .map(|v| pyfmt::g(*v, 6)) + .collect(); + s.push_str(&format!("{},{}\r\n", b.bin, cells.join(","))); + } + s +} + +fn get(r: &Reading, k: &str) -> Value { + r.get(k).map(pyjson::num).unwrap_or(Value::Null) +} + +pub fn metrics( + r: &Reading, + meta: &LampMeta, + n_readings: usize, + supply: Option<&PsuSettings>, + tm: &tm30::Tm30, + measured_at: &str, +) -> Value { + let mut m = Map::new(); + m.insert("name".into(), json!(meta.name)); + if !meta.ean.is_empty() { + m.insert("ean".into(), json!(meta.ean)); + } + if !meta.lamp_type.is_empty() { + m.insert("type".into(), json!(meta.lamp_type)); + } + if let Some(d) = meta.dimmable { + m.insert("dimmable".into(), json!(d)); + } + if !meta.variant.is_empty() { + m.insert("variant".into(), json!(meta.variant)); + } + if !meta.rated.is_empty() { + m.insert("rated".into(), Value::Object(meta.rated.clone())); + } + m.insert("manufacturer".into(), json!(meta.manufacturer)); + m.insert("model".into(), json!(meta.model)); + m.insert("notes".into(), json!(meta.notes)); + m.insert("instrument".into(), json!(r.device)); + m.insert("measured_at".into(), json!(measured_at)); + m.insert("instrument_date".into(), json!(r.test_date)); + m.insert("instrument_time".into(), json!(r.test_time)); + m.insert("readings_averaged".into(), json!(n_readings)); + m.insert("tm30".into(), json!({"Rf": pyjson::num(pyfmt::round(tm.rf, 1)), "Rg": pyjson::num(pyfmt::round(tm.rg, 1))})); + let mut cri = Map::new(); + cri.insert("Ra".into(), get(r, "Ra")); + for i in 1..=15 { + cri.insert(format!("R{i}"), get(r, &format!("R{i}"))); + } + m.insert("cri".into(), Value::Object(cri)); + if let Some(s) = supply { + m.insert( + "supply".into(), + json!({ + "ac_voltage": pyjson::num(s.ac_voltage), + "ac_frequency": pyjson::num(s.ac_frequency), + "dc_voltage": pyjson::num(s.dc_voltage), + "dc_current": pyjson::num(s.dc_current), + "mode": s.mode.as_str(), + }), + ); + } + for (group, keys) in SCALAR_GROUPS { + let g: Map = keys + .iter() + .filter_map(|k| r.get(k).map(|v| (k.to_string(), pyjson::num(v)))) + .collect(); + m.insert(group.into(), Value::Object(g)); + } + Value::Object(m) +} + +/// `2026-07-09T16:22:57+07:00` +pub fn now_iso() -> String { + chrono::Local::now() + .format("%Y-%m-%dT%H:%M:%S%:z") + .to_string() +} + +#[cfg(test)] +mod tests { + use super::*; + use hpcs6500::Mode; + use std::path::PathBuf; + + fn root() -> PathBuf { + PathBuf::from(env!("CARGO_MANIFEST_DIR")) + } + + fn reading(name: &str) -> Reading { + let fx = root().join("HPCS6500/tests/fixtures"); + let meas = std::fs::read(fx.join(format!("{name}_meas.bin"))).unwrap(); + let elec = std::fs::read(fx.join(format!("{name}_elec.bin"))).ok(); + Reading::parse(&meas, elec.as_deref()).unwrap() + } + + fn meta(m: &Value) -> LampMeta { + let s = |k: &str| m.get(k).and_then(|v| v.as_str()).unwrap_or("").to_string(); + LampMeta { + name: s("name"), + ean: s("ean"), + lamp_type: s("type"), + dimmable: m.get("dimmable").and_then(|d| d.as_bool()), + variant: s("variant"), + manufacturer: s("manufacturer"), + model: s("model"), + notes: s("notes"), + rated: m + .get("rated") + .and_then(|r| r.as_object()) + .cloned() + .unwrap_or_default(), + } + } + + /// The bundles of the former lamp_export.py, byte for byte. + #[test] + fn bundles_match_python() { + let golden = root().join("tests/golden/bundles"); + let cases: Value = + serde_json::from_str(&std::fs::read_to_string(golden.join("cases.json")).unwrap()) + .unwrap(); + let stamp = cases["measured_at"].as_str().unwrap(); + let out = std::env::temp_dir().join(format!("lampbench-bundles-{}", std::process::id())); + for c in cases["cases"].as_array().unwrap() { + let name = c["case"].as_str().unwrap(); + let rs: Vec = c["readings"] + .as_array() + .unwrap() + .iter() + .map(|n| reading(n.as_str().unwrap())) + .collect(); + let supply = c["supply"].as_object().map(|s| PsuSettings { + ac_voltage: s["ac_voltage"].as_f64().unwrap(), + ac_frequency: s["ac_frequency"].as_f64().unwrap(), + dc_voltage: s["dc_voltage"].as_f64().unwrap(), + dc_current: s["dc_current"].as_f64().unwrap(), + mode: if s["mode"] == "DC" { + Mode::Dc + } else { + Mode::Ac + }, + }); + let avg = average(&rs); + write( + &avg, + &out.join(name), + &meta(&c["meta"]), + rs.len(), + supply.as_ref(), + stamp, + ) + .unwrap(); + for f in ["spd.csv", "tm30.csv", "metrics.json"] { + let want = std::fs::read(golden.join(name).join(f)).unwrap(); + let got = std::fs::read(out.join(name).join(f)).unwrap(); + // metrics.json takes the platform's line ends (Python text mode); the CSVs are always CRLF + let norm = |b: Vec| { + if f.ends_with(".json") { + String::from_utf8(b).unwrap().replace("\r\n", "\n") + } else { + String::from_utf8(b).unwrap() + } + }; + let (w, g) = (norm(want), norm(got)); + if w != g { + let line = w + .lines() + .zip(g.lines()) + .position(|(a, b)| a != b) + .unwrap_or(0); + panic!( + "{name}/{f} differs at line {}: python {:?} rust {:?}", + line + 1, + w.lines().nth(line), + g.lines().nth(line) + ); + } + } + } + let _ = std::fs::remove_dir_all(&out); + } + + #[test] + fn empty_spectrum_is_refused() { + let r = reading("r03"); + let e = write( + &r, + &std::env::temp_dir().join("lampbench-empty"), + &LampMeta::default(), + 1, + None, + "x", + ) + .unwrap_err(); + assert!(e.to_string().contains("no spectrum"), "{e}"); + } +} diff --git a/src/calibration.rs b/src/calibration.rs new file mode 100644 index 0000000..976ffcd --- /dev/null +++ b/src/calibration.rs @@ -0,0 +1,1053 @@ +//! Calibration of the B4L tunable-white LED light (2700 K + 5000 K LEDs, +//! mixing table for CCT / lumen targets) with the HPCS 6500 as the meter. +//! +//! The light speaks 5-byte UART frames: ` <4 payload bytes>`, answered +//! by `C0 ...` (ACK) or `C1 ...` (NAK); anything else it sends is a +//! diagnostic message and skipped. Its firmware interpolates a 9 x 5 mixing +//! ratio table (CCT x lumen) and two LED output curves (y27, y50: lumen at +//! 0, 11, 33, 65, 150 mA). +//! +//! Procedure: y-data first (lumen of each LED alone at the five drive +//! currents), then up to 10 passes over the 45 grid points, each pass +//! correcting the mixing ratios in proportion to the CCT error, until every +//! point is within 5 %. + +use anyhow::{Context, Result}; +use hpcs6500::{Hpcs6500, Transport, pyfmt}; +use serde_json::{Map, Value, json}; +use std::collections::BTreeMap; +use std::io::{Read, Write}; +use std::path::PathBuf; +use std::time::{Duration, Instant}; + +pub const CCT_POINTS: [i64; 9] = [2600, 2900, 3200, 3500, 3800, 4100, 4400, 4700, 5000]; +pub const LUMEN_POINTS: [i64; 5] = [200, 375, 550, 725, 900]; + +pub const CMD_SET_COLOR: u8 = 0x81; +pub const CMD_SET_INTENSITY: u8 = 0x82; +pub const CMD_PROFILE_OFF: u8 = 0x84; +pub const CMD_CAL_START: u8 = 0x8A; +pub const CMD_CAL_WRITE: u8 = 0x8B; +pub const CMD_CAL_COMMIT: u8 = 0x8C; +pub const CMD_CAL_CLEAR: u8 = 0x8D; +pub const CMD_CAL_READ: u8 = 0x8E; +pub const CMD_CAL_WRITE_Y: u8 = 0x8F; +pub const RSP_ACK: u8 = 0xC0; +pub const RSP_NAK: u8 = 0xC1; + +/// Firmware defaults of the LED curves (lumen at the drive points). +pub const Y27_DEFAULT: [i64; 5] = [0, 39, 179, 369, 844]; +pub const Y50_DEFAULT: [i64; 5] = [0, 51, 217, 441, 969]; +/// Drive currents of the curve points (mA). +pub const X_DATA: [i64; 5] = [0, 11, 33, 65, 150]; + +/// Firmware default mixing ratios (rows: CCT_POINTS, columns: LUMEN_POINTS). +pub const DEFAULT_MIXING: [[i64; 5]; 9] = [ + [0, 0, 0, 0, 0], + [32, 38, 36, 37, 36], + [84, 72, 70, 71, 71], + [142, 100, 99, 99, 99], + [175, 131, 126, 127, 126], + [155, 154, 154, 157, 153], + [206, 170, 184, 184, 185], + [242, 223, 208, 216, 217], + [255, 255, 255, 255, 255], +]; + +pub type Table = Vec>; + +/// The light's UART. +pub trait Link { + fn write(&mut self, frame: &[u8; 5]) -> std::io::Result<()>; + /// One 5-byte message, or None when nothing complete arrived in `timeout`. + fn read5(&mut self, timeout: Duration) -> std::io::Result>; + fn clear(&mut self) -> std::io::Result<()>; +} + +/// A serial port as the light's link. +pub struct SerialLink(Box); + +impl SerialLink { + pub fn open(port: &str, baud: u32) -> Result { + let p = serialport::new(port, baud) + .timeout(Duration::from_secs(1)) + .open() + .with_context(|| format!("opening {port}"))?; + std::thread::sleep(Duration::from_millis(500)); // let the connection settle + let mut l = SerialLink(p); + l.clear()?; + println!("Connected to {port}"); + Ok(l) + } +} + +impl Link for SerialLink { + fn write(&mut self, frame: &[u8; 5]) -> std::io::Result<()> { + self.0.write_all(frame)?; + self.0.flush() + } + fn read5(&mut self, timeout: Duration) -> std::io::Result> { + self.0.set_timeout(timeout).map_err(std::io::Error::other)?; + let mut b = [0u8; 5]; + let mut got = 0; + let end = Instant::now() + timeout; + while got < 5 && Instant::now() < end { + match self.0.read(&mut b[got..]) { + Ok(n) => got += n, + Err(e) if e.kind() == std::io::ErrorKind::TimedOut => break, + Err(e) => return Err(e), + } + } + Ok((got == 5).then_some(b)) + } + fn clear(&mut self) -> std::io::Result<()> { + self.0 + .clear(serialport::ClearBuffer::Input) + .map_err(std::io::Error::other) + } +} + +/// A light reading: lumen (1 decimal) and CCT (whole kelvin). +#[derive(Debug, Clone, Copy, PartialEq)] +pub struct Measurement { + pub lumen: f64, + pub cct: i64, +} + +/// Something that measures the light. +pub trait Meter { + fn measure(&mut self) -> Option; +} + +/// The HPCS 6500 as meter: one single-test reading, the light powers itself. +pub struct HpcsMeter(pub Hpcs6500); + +impl Meter for HpcsMeter { + fn measure(&mut self) -> Option { + match self.0.take_single_reading() { + Ok(r) => Some(Measurement { + lumen: pyfmt::round(r.flux_lm(), 1), + cct: r.cct_k().round_ties_even() as i64, + }), + Err(e) => { + println!(" (measurement failed: {e})"); + None + } + } + } +} + +/// How long to wait in the procedure; tests make it instant. +pub trait Clock { + fn sleep(&mut self, d: Duration); +} + +pub struct RealClock; +impl Clock for RealClock { + fn sleep(&mut self, d: Duration) { + std::thread::sleep(d); + } +} + +#[derive(Debug, Clone, PartialEq)] +pub struct Point { + pub target_cct: i64, + pub target_lumen: i64, + pub measured_cct: i64, + pub measured_lumen: f64, +} + +pub struct Calibrator { + pub link: L, + pub meter: M, + pub clock: C, + pub output: PathBuf, + /// (cct, lumen) -> measurement of the current pass. + pub measurements: BTreeMap<(i64, i64), Point>, + /// Insertion order of `measurements` (the JSON file keeps it). + order: Vec<(i64, i64)>, +} + +fn s(secs: f64) -> Duration { + Duration::from_secs_f64(secs) +} + +impl Calibrator { + pub fn new(link: L, meter: M, clock: C, output: PathBuf) -> Self { + Calibrator { + link, + meter, + clock, + output, + measurements: BTreeMap::new(), + order: vec![], + } + } + + fn store(&mut self, key: (i64, i64), p: Point) { + if self.measurements.insert(key, p).is_none() { + self.order.push(key); + } + } + + fn clear_measurements(&mut self) { + self.measurements.clear(); + self.order.clear(); + } + + /// Send a command; wait for its ACK, skipping diagnostic messages. + pub fn send(&mut self, cmd: u8, payload: [u8; 4], timeout: f64) -> bool { + let _ = self.link.clear(); + let f = [cmd, payload[0], payload[1], payload[2], payload[3]]; + if self.link.write(&f).is_err() { + println!("Write failed"); + return false; + } + let end = Instant::now() + s(timeout); + while Instant::now() < end { + let Ok(Some(r)) = self + .link + .read5(s(0.1).min(end.saturating_duration_since(Instant::now()))) + else { + continue; + }; + if r[0] == RSP_ACK { + if r[1] == cmd { + return true; + } + println!("ACK mismatch: sent 0x{cmd:02x}, got {}", hex(&r)); + } else if r[0] == RSP_NAK { + println!("NAK received: {}", hex(&r)); + return false; + } + } + println!("Timeout waiting for response"); + false + } + + pub fn set_intensity(&mut self, v: i64) -> bool { + self.send( + CMD_SET_INTENSITY, + [(v & 0xFF) as u8, ((v >> 8) & 0xFF) as u8, 0, 0], + 2.0, + ) + } + pub fn set_color(&mut self, cct: i64) -> bool { + self.send( + CMD_SET_COLOR, + [(cct & 0xFF) as u8, ((cct >> 8) & 0xFF) as u8, 0, 0], + 2.0, + ) + } + pub fn disable_profile(&mut self) -> bool { + self.send(CMD_PROFILE_OFF, [0; 4], 2.0) + } + pub fn cal_start(&mut self) -> bool { + let r = self.send(CMD_CAL_START, [0; 4], 5.0); + println!(" cal_start result: {}", if r { "True" } else { "False" }); + r + } + pub fn cal_write(&mut self, index: u8, value: u8) -> bool { + let r = self.send(CMD_CAL_WRITE, [index, value, 0, 0], 2.0); + if !r { + println!(" cal_write failed at index {index}, value {value}"); + } + r + } + pub fn cal_write_y(&mut self, table: u8, index: u8, value: i64) -> bool { + self.send( + CMD_CAL_WRITE_Y, + [ + table, + index, + (value & 0xFF) as u8, + ((value >> 8) & 0xFF) as u8, + ], + 2.0, + ) + } + pub fn cal_commit(&mut self) -> bool { + self.send(CMD_CAL_COMMIT, [0; 4], 5.0) + } + pub fn cal_clear(&mut self) -> bool { + self.send(CMD_CAL_CLEAR, [0; 4], 2.0) + } + + /// (index, value, valid) of one table entry. + pub fn cal_read(&mut self, index: u8) -> Option<(u8, u8, u8)> { + self.link.write(&[CMD_CAL_READ, index, 0, 0, 0]).ok()?; + let r = self.link.read5(s(1.0)).ok().flatten()?; + (r[0] == RSP_ACK).then_some((r[1], r[2], r[3])) + } + + pub fn read_table(&mut self, verbose: bool) -> Option<(Table, bool)> { + if verbose { + println!("Reading calibration table from device..."); + } + let mut table = vec![]; + let mut valid = None; + for i in 0..CCT_POINTS.len() { + let mut row = vec![]; + for j in 0..LUMEN_POINTS.len() { + let index = (i * LUMEN_POINTS.len() + j) as u8; + let Some(r) = self.cal_read(index) else { + if verbose { + println!(" Failed to read index {index}"); + } + return None; + }; + row.push(r.1 as i64); + valid.get_or_insert(r.2); + } + table.push(row); + } + let valid = valid.unwrap_or(0) != 0; + if verbose { + println!( + " Read complete ({})", + if valid { "calibrated" } else { "defaults" } + ); + } + Some((table, valid)) + } + + pub fn write_table( + &mut self, + table: &Table, + y27: Option<&[i64]>, + y50: Option<&[i64]>, + verbose: bool, + ) -> bool { + if verbose { + println!("Writing calibration to device..."); + } + let _ = self.link.clear(); + self.clock.sleep(s(0.1)); + if !self.cal_start() { + if verbose { + println!(" Failed to start calibration write"); + } + return false; + } + self.clock.sleep(s(1.0)); // flash erase + let mut index = 0u8; + for row in table { + for &v in row { + if !self.cal_write(index, v.clamp(0, 255) as u8) { + if verbose { + println!(" Failed to write mixing ratio index {index}"); + } + return false; + } + index += 1; + self.clock.sleep(s(0.05)); + } + } + for (t, (name, values)) in [ + ("y27", y27.unwrap_or(&Y27_DEFAULT)), + ("y50", y50.unwrap_or(&Y50_DEFAULT)), + ] + .iter() + .enumerate() + { + for (i, &v) in values.iter().enumerate() { + if !self.cal_write_y(t as u8, i as u8, v) { + if verbose { + println!(" Failed to write {name}[{i}]"); + } + return false; + } + self.clock.sleep(s(0.05)); + } + } + self.clock.sleep(s(0.5)); + if !self.cal_commit() { + if verbose { + println!(" Failed to commit calibration"); + } + return false; + } + if verbose { + println!(" Calibration written successfully!"); + } + true + } + + fn set_test_point(&mut self, cct: i64, lumen: i64) -> bool { + if !self.set_color(cct) { + return false; + } + self.clock.sleep(s(0.2)); + self.set_intensity(lumen) + } + + /// One pass over the grid, ordered by lumen with CCT in a snake pattern + /// so the drive current never jumps far. True if every point measured. + pub fn measure_all_points(&mut self) -> bool { + let total = CCT_POINTS.len() * LUMEN_POINTS.len(); + let mut order = vec![]; + for (i, &lumen) in LUMEN_POINTS.iter().enumerate() { + let mut ccts = CCT_POINTS.to_vec(); + if i % 2 == 1 { + ccts.reverse(); + } + order.extend(ccts.into_iter().map(|c| (c, lumen))); + } + let mut ok = 0; + for (n, (cct, lumen)) in order.into_iter().enumerate() { + print!(" [{}/{total}] CCT={cct}K, Lumen={lumen}", n + 1); + let _ = std::io::stdout().flush(); + if !self.set_test_point(cct, lumen) { + println!(" - FAILED to set"); + continue; + } + self.clock.sleep(s(4.0)); + for attempt in 0..3 { + let Some(m) = self.meter.measure() else { + if attempt < 2 { + self.clock.sleep(s(2.0)); + continue; + } + println!(" - NO READING"); + break; + }; + let cct_dev = (m.cct - cct).abs() as f64 / cct as f64; + let lumen_dev = if lumen > 0 { + (m.lumen - lumen as f64).abs() / lumen as f64 + } else { + 0.0 + }; + if cct_dev > 0.6 || lumen_dev > 0.6 { + if attempt < 2 { + self.clock.sleep(s(4.0)); + continue; + } + println!( + " - IMPLAUSIBLE ({:.0}%/{:.0}%)", + cct_dev * 100.0, + lumen_dev * 100.0 + ); + break; + } + self.store( + (cct, lumen), + Point { + target_cct: cct, + target_lumen: lumen, + measured_cct: m.cct, + measured_lumen: m.lumen, + }, + ); + let ce = (m.cct - cct) as f64 / cct as f64 * 100.0; + let le = (m.lumen - lumen as f64) / lumen as f64 * 100.0; + println!(" -> CCT:{ce:+5.1}% Lum:{le:+5.1}%"); + ok += 1; + break; + } + } + ok == total + } + + /// Print the % error table; (all within 5 %, max CCT error, max lumen error). + pub fn print_deviation_table(&self) -> (bool, f64, f64) { + println!("\n{}", "=".repeat(70)); + println!("DEVIATION TABLE (% error from target)"); + println!("{}", "=".repeat(70)); + let mut header = String::from(" |"); + for l in LUMEN_POINTS { + header += &format!(" {l:4}lm |"); + } + println!("{header}"); + println!("{}", "-".repeat(header.len())); + let (mut max_c, mut max_l, mut all_ok) = (0.0f64, 0.0f64, true); + let (mut cd, mut ld) = (vec![], vec![]); + for cct in CCT_POINTS { + let mut row = format!("{cct:5}K |"); + for lumen in LUMEN_POINTS { + if let Some(m) = self.measurements.get(&(cct, lumen)) { + let c = (m.measured_cct - cct) as f64 / cct as f64 * 100.0; + let l = (m.measured_lumen - lumen as f64) / lumen as f64 * 100.0; + cd.push(c); + ld.push(l); + max_c = max_c.max(c.abs()); + max_l = max_l.max(l.abs()); + if c.abs() > 5.0 || l.abs() > 5.0 { + all_ok = false; + } + row += &format!("{c:+4.1}/{l:+4.1}|"); + } else { + row += " --- |"; + all_ok = false; + } + } + println!("{row}"); + } + let std = |v: &[f64]| { + if v.len() < 2 { + return 0.0; + } + let mean = v.iter().sum::() / v.len() as f64; + (v.iter().map(|x| (x - mean).powi(2)).sum::() / v.len() as f64).sqrt() + }; + println!("{}", "-".repeat(header.len())); + println!("Format: CCT%/Lumen% | Max CCT: {max_c:.1}% | Max Lumen: {max_l:.1}%"); + println!( + "Standard deviation | CCT: {:.2}% | Lumen: {:.2}%", + std(&cd), + std(&ld) + ); + (all_ok, max_c, max_l) + } + + fn led_curve(&mut self, cct: i64, defaults: &[i64; 5]) -> Option> { + if !self.set_color(cct) { + println!(" Failed to set color to {cct}K"); + return None; + } + self.clock.sleep(s(0.5)); + let mut out = vec![]; + for (i, &target) in defaults.iter().enumerate() { + let ma = X_DATA[i]; + print!(" Point {}/5: {ma:3}mA (intensity={target:3})", i + 1); + let _ = std::io::stdout().flush(); + if ma == 0 { + out.push(0); + println!(" -> 0 lm (zero point)"); + continue; + } + if !self.set_intensity(target) { + println!(" - FAILED to set intensity"); + return None; + } + self.clock + .sleep(s(if i == defaults.len() - 1 { 5.0 } else { 2.0 })); + let mut reading = None; + for _ in 0..3 { + reading = self.meter.measure(); + if reading.is_some_and(|r| r.lumen > 0.0) { + break; + } + self.clock.sleep(s(1.0)); + } + let Some(r) = reading else { + println!(" - NO READING"); + return None; + }; + let actual = r.lumen.round_ties_even() as i64; + let dev = if target > 0 { + (actual - target) as f64 / target as f64 * 100.0 + } else { + 0.0 + }; + out.push(actual); + println!(" -> {actual:4} lm ({dev:+5.1}%)"); + } + Some(out) + } + + /// Lumen of each LED alone at the five drive currents. + pub fn calibrate_y_data(&mut self) -> Option<(Vec, Vec)> { + let bar = "=".repeat(70); + println!("\n{bar}\nY-DATA CALIBRATION\n{bar}"); + println!("Measuring lumen output at fixed drive currents"); + println!("Drive points (mA): {}", list(&X_DATA)); + println!("{bar}"); + println!("\nClearing existing calibration to use default tables..."); + self.clock.sleep(s(0.2)); + let _ = self.link.clear(); + if !self.cal_clear() { + println!("Failed to clear calibration"); + return None; + } + self.clock.sleep(s(1.0)); + println!("\n--- Calibrating 2700K LED (pure warm) ---"); + let y27 = self.led_curve(2600, &Y27_DEFAULT)?; + println!("\nTurning off LEDs, waiting 10s for thermal stabilization..."); + self.set_intensity(0); + self.clock.sleep(s(10.0)); + println!("\n--- Calibrating 5000K LED (pure cool) ---"); + let y50 = self.led_curve(5000, &Y50_DEFAULT)?; + println!("\n{bar}\nY-DATA CALIBRATION RESULTS\n{bar}"); + println!(" mA points: {}", list(&X_DATA)); + println!( + " y27 (2700K): {} (default: {})", + list(&y27), + list(&Y27_DEFAULT) + ); + println!( + " y50 (5000K): {} (default: {})", + list(&y50), + list(&Y50_DEFAULT) + ); + Some((y27, y50)) + } + + fn measurements_json(&self) -> Value { + let mut m = Map::new(); + for k in &self.order { + let p = &self.measurements[k]; + m.insert( + format!("{},{}", k.0, k.1), + json!({"target_cct": p.target_cct, "target_lumen": p.target_lumen, + "measured_cct": p.measured_cct, "measured_lumen": crate::pyjson::num(p.measured_lumen)}), + ); + } + Value::Object(m) + } + + fn save_json(&self, v: &Value) { + if let Err(e) = std::fs::write(&self.output, crate::pyjson::file_text(v)) { + println!("ERROR writing {}: {e}", self.output.display()); + } + } + + pub fn save(&self) { + self.save_json(&json!({"measurements": self.measurements_json(), "cct_points": CCT_POINTS, "lumen_points": LUMEN_POINTS})); + } + + /// Load the measurements of a previous run from the output file. + pub fn load(&mut self) -> Option { + let saved: Value = + serde_json::from_str(&std::fs::read_to_string(&self.output).ok()?).ok()?; + self.clear_measurements(); + if let Some(m) = saved.get("measurements").and_then(|m| m.as_object()) { + for (k, v) in m { + let mut it = k.split(',').filter_map(|x| x.trim().parse::().ok()); + let (Some(c), Some(l)) = (it.next(), it.next()) else { + continue; + }; + let i = |f: &str| v.get(f).and_then(|x| x.as_f64()).unwrap_or(0.0); + self.store( + (c, l), + Point { + target_cct: i("target_cct") as i64, + target_lumen: i("target_lumen") as i64, + measured_cct: i("measured_cct") as i64, + measured_lumen: i("measured_lumen"), + }, + ); + } + } + Some(saved) + } + + /// New mixing ratios: each measured point's ratio moves by its CCT error + /// / 10 K per ratio unit, at most 30 units per pass. + pub fn generate_table(&mut self, verbose: bool) -> Table { + if verbose { + println!("\nGenerating calibration table..."); + } + let baseline = match self.read_table(verbose) { + Some((t, _)) => { + if verbose { + println!("Using current device values as baseline"); + } + t + } + None => { + if verbose { + println!("Using firmware defaults as baseline"); + } + DEFAULT_MIXING.iter().map(|r| r.to_vec()).collect() + } + }; + const K_PER_RATIO: f64 = 10.0; + let mut corrections: Vec<((i64, i64), Value, f64)> = vec![]; + for k in self.order.clone() { + let m = &self.measurements[&k]; + let i = CCT_POINTS.iter().position(|&c| c == k.0).expect("grid cct"); + let j = LUMEN_POINTS + .iter() + .position(|&l| l == k.1) + .expect("grid lumen"); + let cct_error = m.target_cct - m.measured_cct; + let lumen_error = m.target_lumen as f64 - m.measured_lumen; + let dr = cct_error as f64 / K_PER_RATIO; + // Python's max(-30, min(30, dr)) keeps the int literal when it clamps + let (adj, adj_json) = if dr > 30.0 { + (30.0, json!(30)) + } else if dr < -30.0 { + (-30.0, json!(-30)) + } else { + (dr, crate::pyjson::num(dr)) + }; + let pct = if m.target_lumen > 0 { + 100.0 * lumen_error / m.target_lumen as f64 + } else { + 0.0 + }; + corrections.push(( + k, + json!({"cct_error": cct_error, "lumen_error": crate::pyjson::num(lumen_error), + "lumen_error_pct": crate::pyjson::num(pct), "mixing_adjust": adj_json, "baseline_ratio": baseline[i][j]}), + adj, + )); + } + let mut table = baseline.clone(); + for (k, _, adj) in &corrections { + let i = CCT_POINTS.iter().position(|&c| c == k.0).expect("grid cct"); + let j = LUMEN_POINTS + .iter() + .position(|&l| l == k.1) + .expect("grid lumen"); + table[i][j] = ((baseline[i][j] as f64 + adj).round_ties_even() as i64).clamp(0, 255); + } + if verbose { + println!("\nCorrection summary:"); + println!( + "{:>5} {:>5} | {:>8} {:>8} | {:>4} {:>6} {:>4}", + "CCT", "Lumen", "CCT err", "Lum err", "Base", "Adj", "New" + ); + println!("{}", "-".repeat(65)); + for (i, cct) in CCT_POINTS.iter().enumerate() { + for (j, lumen) in LUMEN_POINTS.iter().enumerate() { + if let Some((_, c, adj)) = + corrections.iter().find(|(k, _, _)| *k == (*cct, *lumen)) + { + println!( + "{cct:>5} {lumen:>5} | {:>+7.0}K {:>+7.0}lm | {:>4} {adj:>+6.1} {:>4}", + c["cct_error"].as_i64().unwrap_or(0) as f64, + c["lumen_error"].as_f64().unwrap_or(0.0), + c["baseline_ratio"], + table[i][j] + ); + } + } + } + println!("\nCalibrated mixing_ratios table:"); + println!("const uint8_t mixing_ratios[NUM_CCT][NUM_LUMEN] = {{"); + for (i, (cct, row)) in CCT_POINTS.iter().zip(&table).enumerate() { + let values: Vec = row.iter().map(|v| format!("{v:3}")).collect(); + let mut comment = format!("// {cct}K"); + if i == 0 { + comment += " (pure 2700K)"; + } else if i == CCT_POINTS.len() - 1 { + comment += " (pure 5000K)"; + } + let comma = if i < CCT_POINTS.len() - 1 { "," } else { "" }; + println!(" {{{}}}{comma} {comment}", values.join(", ")); + } + println!("}};"); + } + let mut corr = Map::new(); + for (k, c, _) in &corrections { + corr.insert(format!("{},{}", k.0, k.1), c.clone()); + } + self.save_json(&json!({ + "measurements": self.measurements_json(), + "corrections": corr, + "cct_points": CCT_POINTS, + "lumen_points": LUMEN_POINTS, + "baseline_table": baseline, + "calibrated_table": table, + })); + if verbose { + println!("\nCalibration saved to {}", self.output.display()); + } + table + } + + /// Full calibration: y-data (unless skipped), then mixing-ratio passes. + pub fn run(&mut self, skip_y: bool) { + let bar = "=".repeat(70); + println!("{bar}\nLED Light Full Calibration\n{bar}"); + println!("Phase 1: Y-data calibration (LED lumen curves)"); + println!("Phase 2: Mixing ratio calibration (CCT/lumen targeting)\n{bar}"); + println!("\nDisabling profile mode..."); + self.disable_profile(); + self.clock.sleep(s(0.5)); + let (mut y27, mut y50) = (None, None); + if !skip_y { + let Some((a, b)) = self.calibrate_y_data() else { + println!("\nY-data calibration failed, aborting."); + return; + }; + println!("\nWriting y-data to device..."); + let defaults: Table = DEFAULT_MIXING.iter().map(|r| r.to_vec()).collect(); + if !self.write_table(&defaults, Some(&a), Some(&b), false) { + println!("Failed to write y-data, aborting."); + return; + } + println!("Y-data written, proceeding to mixing ratio calibration..."); + self.clock.sleep(s(1.0)); + (y27, y50) = (Some(a), Some(b)); + } + println!("\n{bar}\nMIXING RATIO CALIBRATION\n{bar}"); + println!("Target: < 5% deviation on all points"); + println!("Maximum passes: 10"); + let max_passes = 10; + for pass in 1..=max_passes { + println!("\n{bar}\nPASS {pass}/{max_passes}\n{bar}"); + self.clear_measurements(); + println!("\nMeasuring all points..."); + self.measure_all_points(); + let (converged, max_c, max_l) = self.print_deviation_table(); + self.save(); + if converged { + println!("\n*** CONVERGED after {pass} pass(es)! ***"); + println!("All points within 5% tolerance."); + break; + } + if pass == max_passes { + println!("\n*** MAX PASSES REACHED ***"); + println!("Best achieved: CCT {max_c:.1}%, Lumen {max_l:.1}%"); + break; + } + println!("\nCalculating and applying corrections..."); + let table = self.generate_table(false); + if self.write_table(&table, y27.as_deref(), y50.as_deref(), false) { + println!("Corrections applied, starting next pass..."); + self.clock.sleep(s(1.0)); + } else { + println!("Failed to write calibration, stopping."); + break; + } + } + println!("\n{bar}\nCalibration complete!\n{bar}"); + } + + /// Only the y-data, written with the default mixing ratios. + pub fn run_y_only(&mut self) { + self.disable_profile(); + self.clock.sleep(s(0.5)); + let Some((y27, y50)) = self.calibrate_y_data() else { + return; + }; + println!("\nWriting y-data calibration (with default mixing ratios)..."); + let defaults: Table = DEFAULT_MIXING.iter().map(|r| r.to_vec()).collect(); + if self.write_table(&defaults, Some(&y27), Some(&y50), true) { + println!("Y-data calibration saved successfully!"); + self.save_json(&json!({"y27_cal": y27, "y50_cal": y50, "x_data": X_DATA})); + } else { + println!("Failed to write y-data calibration"); + } + } +} + +fn hex(b: &[u8]) -> String { + b.iter().map(|x| format!("{x:02x}")).collect() +} + +/// `[0, 11, 33]` like Python prints a list of ints. +fn list(v: &[i64]) -> String { + format!( + "[{}]", + v.iter() + .map(|x| x.to_string()) + .collect::>() + .join(", ") + ) +} + +/// y-data of a saved file, if there is any. +pub fn saved_curve(saved: &Value, key: &str) -> Option> { + let a = saved.get(key)?.as_array()?; + let v: Vec = a + .iter() + .filter_map(|x| x.as_f64().map(|f| f as i64)) + .collect(); + (!v.is_empty()).then_some(v) +} + +/// Print the table read from the light. +pub fn print_table(table: &Table, valid: bool) { + println!( + "\nCalibration status: {}", + if valid { "CALIBRATED" } else { "DEFAULTS" } + ); + println!("\nMixing ratios table:"); + for (cct, row) in CCT_POINTS.iter().zip(table) { + let values: Vec = row.iter().map(|v| format!("{v:3}")).collect(); + println!(" {cct}K: [{}]", values.join(", ")); + } +} + +#[cfg(test)] +mod tests { + use super::*; + use std::cell::RefCell; + use std::collections::VecDeque; + use std::path::Path; + use std::rc::Rc; + + /// A tunable-white light whose CCT follows the mixing ratio linearly + /// (9.41 K per unit, plus a small lumen-dependent shift). + struct Light { + table: Table, + staged: Vec, + calibrated: bool, + cct: i64, + intensity: i64, + out: VecDeque<[u8; 5]>, + frames: usize, + } + + #[derive(Clone)] + struct FakeLink(Rc>); + + impl Link for FakeLink { + fn write(&mut self, f: &[u8; 5]) -> std::io::Result<()> { + let mut l = self.0.borrow_mut(); + l.frames += 1; + // a diagnostic message now and then, which must be skipped + if l.frames.is_multiple_of(7) { + l.out.push_back([0x55, 1, 2, 3, 4]); + } + let v16 = f[1] as i64 | (f[2] as i64) << 8; + match f[0] { + CMD_SET_COLOR => l.cct = v16, + CMD_SET_INTENSITY => l.intensity = v16, + CMD_CAL_START => l.staged = vec![0; 45], + CMD_CAL_WRITE => l.staged[f[1] as usize] = f[2] as i64, + CMD_CAL_COMMIT => { + let s = l.staged.clone(); + l.table = s.chunks(5).map(|c| c.to_vec()).collect(); + l.calibrated = true; + } + CMD_CAL_CLEAR => { + l.table = DEFAULT_MIXING.iter().map(|r| r.to_vec()).collect(); + l.calibrated = false; + } + CMD_CAL_READ => { + let i = f[1] as usize; + let v = l.table[i / 5][i % 5] as u8; + let c = l.calibrated as u8; + l.out.push_back([RSP_ACK, f[1], v, c, 0]); + return Ok(()); + } + _ => {} + } + l.out.push_back([RSP_ACK, f[0], 0, 0, 0]); + Ok(()) + } + fn read5(&mut self, _t: Duration) -> std::io::Result> { + Ok(self.0.borrow_mut().out.pop_front()) + } + fn clear(&mut self) -> std::io::Result<()> { + self.0.borrow_mut().out.clear(); + Ok(()) + } + } + + struct FakeMeter(Rc>); + impl Meter for FakeMeter { + fn measure(&mut self) -> Option { + let l = self.0.borrow(); + let i = CCT_POINTS.iter().position(|&c| c == l.cct)?; + let j = LUMEN_POINTS + .iter() + .position(|&x| x == l.intensity) + .unwrap_or(2); + let ratio = l.table[i][j] as f64; + let cct = 2600.0 + ratio * 2400.0 / 255.0 + (l.intensity as f64 - 550.0) * 0.1; + Some(Measurement { + lumen: pyfmt::round(l.intensity as f64 * 0.98, 1), + cct: cct.round_ties_even() as i64, + }) + } + } + + struct NoClock; + impl Clock for NoClock { + fn sleep(&mut self, _d: Duration) {} + } + + fn rig(out: &Path) -> (Rc>, Calibrator) { + let light = Rc::new(RefCell::new(Light { + table: DEFAULT_MIXING.iter().map(|r| r.to_vec()).collect(), + staged: vec![], + calibrated: false, + cct: 2600, + intensity: 0, + out: VecDeque::new(), + frames: 0, + })); + let cal = Calibrator::new( + FakeLink(light.clone()), + FakeMeter(light.clone()), + NoClock, + out.to_path_buf(), + ); + (light, cal) + } + + #[test] + fn full_calibration_converges_and_writes_the_table() { + let dir = std::env::temp_dir().join(format!("lampbench-cal-{}", std::process::id())); + std::fs::create_dir_all(&dir).unwrap(); + let out = dir.join("calibration_table.json"); + let (light, mut cal) = rig(&out); + cal.run(false); + let l = light.borrow(); + assert!(l.calibrated, "table committed to the light"); + // every grid point now within 5 % of its target CCT + for (i, &cct) in CCT_POINTS.iter().enumerate() { + for (j, &lm) in LUMEN_POINTS.iter().enumerate() { + let got = + 2600.0 + l.table[i][j] as f64 * 2400.0 / 255.0 + (lm as f64 - 550.0) * 0.1; + assert!( + (got - cct as f64).abs() / (cct as f64) < 0.05, + "{cct} K / {lm} lm -> {got}" + ); + } + } + let saved: Value = serde_json::from_str(&std::fs::read_to_string(&out).unwrap()).unwrap(); + assert_eq!(saved["measurements"].as_object().unwrap().len(), 45); + assert_eq!(saved["measurements"]["2600,200"]["target_cct"], 2600); + // y-data measured from the light: 0.98 lm per intensity unit + drop(l); + let (_, mut cal2) = rig(&out); + let (y27, y50) = cal2.calibrate_y_data().unwrap(); + assert_eq!(y27, vec![0, 38, 175, 362, 827]); + assert_eq!(y50[4], 950); + let _ = std::fs::remove_dir_all(&dir); + } + + #[test] + fn generate_table_clamps_like_python() { + let dir = std::env::temp_dir().join(format!("lampbench-gen-{}", std::process::id())); + std::fs::create_dir_all(&dir).unwrap(); + let out = dir.join("c.json"); + let (_, mut cal) = rig(&out); + cal.store( + (3500, 550), + Point { + target_cct: 3500, + target_lumen: 550, + measured_cct: 3000, + measured_lumen: 500.0, + }, + ); + cal.store( + (4100, 200), + Point { + target_cct: 4100, + target_lumen: 200, + measured_cct: 4123, + measured_lumen: 210.5, + }, + ); + let t = cal.generate_table(false); + assert_eq!(t[3][2], 99 + 30, "clamped to +30"); + assert_eq!(t[5][0], 153, "155 - 2.3 rounds to 153"); + let saved: Value = serde_json::from_str(&std::fs::read_to_string(&out).unwrap()).unwrap(); + let c = &saved["corrections"]["3500,550"]; + assert_eq!( + c["mixing_adjust"], + json!(30), + "int like Python's min(30, dr)" + ); + assert_eq!(c["cct_error"], json!(500)); + assert_eq!( + saved["corrections"]["4100,200"]["mixing_adjust"], + json!(-2.3) + ); + let text = std::fs::read_to_string(&out).unwrap(); + assert!(text.contains("\"lumen_error\": -10.5")); + // the file round-trips into measurements + let (_, mut again) = rig(&out); + again.load().unwrap(); + assert_eq!(again.measurements.len(), 2); + let _ = std::fs::remove_dir_all(&dir); + } +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..87bc40e --- /dev/null +++ b/src/main.rs @@ -0,0 +1,492 @@ +//! `lampbench`: the lamp testbench around the HPCS 6500. +//! +//! ```text +//! lampbench station barcode-driven measurement station (comparison database) +//! lampbench export one measurement -> one lamp bundle (spd.csv, tm30.csv, metrics.json) +//! lampbench label L0006 print / preview the ID labels +//! lampbench tm30 spd.csv TM-30-18 of a spectrum +//! lampbench calibrate calibrate the B4L tunable-white LED light +//! ``` + +mod bundle; +mod calibration; +mod measure; +mod prompt; +mod pyjson; +mod station; + +use anyhow::{Context, Result, bail}; +use clap::{Parser, Subcommand}; +use hpcs6500::{Hpcs6500, Mode, pyfmt}; +use measure::{Psu, Source}; +use std::path::PathBuf; +use std::sync::Arc; +use std::sync::atomic::{AtomicBool, Ordering}; + +#[derive(Parser)] +#[command( + name = "lampbench", + version, + about = "Lamp testbench: HPCS 6500 measurements, lamp bundles, ID labels, LED calibration" +)] +struct Cli { + #[command(subcommand)] + command: Cmd, +} + +#[derive(clap::Args, Clone)] +struct Instrument { + /// COM port of the HPCS 6500 (auto-detect if omitted) + #[arg(long)] + port: Option, + /// Use the simulated instrument: replays a USB capture, or the built-in sample without one + #[arg(long, value_name = "PCAP", num_args = 0..=1, default_missing_value = "")] + simulate: Option, +} + +impl Instrument { + fn source(&self) -> Source { + match &self.simulate { + Some(p) if p.is_empty() => Source::Simulate(None), + Some(p) => Source::Simulate(Some(PathBuf::from(p))), + None => Source::Port(self.port.clone()), + } + } +} + +#[derive(Subcommand)] +enum Cmd { + /// Scan a barcode, measure, write the bundle, commit, print labels + Station { + /// comparison-data checkout (bundles land in lamps//) + #[arg( + long, + default_value = r"C:\dev\buildfor_life_web\apps\web\comparison-data" + )] + data_repo: PathBuf, + #[command(flatten)] + instrument: Instrument, + #[arg(long, default_value_t = 5)] + readings: usize, + #[arg(long, default_value_t = 230.0)] + voltage: f64, + #[arg(long, default_value_t = 50.0)] + frequency: f64, + /// Seconds of stabilization after PSU on (procedure: 60) + #[arg(long, default_value_t = 60.0)] + settle: f64, + #[arg(long, default_value_t = 1.0)] + interval: f64, + /// Write the bundle but skip git entirely + #[arg(long)] + no_commit: bool, + /// Commit locally but do not push + #[arg(long)] + no_push: bool, + /// QL-820NWB address, e.g. tcp://192.168.1.50 + #[arg(long, env = "HPCS_LABEL_PRINTER", default_value = "")] + printer: String, + /// Skip printing the two ID labels after each lamp + #[arg(long)] + no_labels: bool, + /// EAN cache file (default: ~/.cache/hpcs6500/ean-cache.json) + #[arg(long)] + cache: Option, + /// Do not look EANs up on upcitemdb.com + #[arg(long)] + no_lookup: bool, + }, + /// Export a lamp measurement bundle + Export { + /// Lamp slug, becomes the output directory name + #[arg(long)] + name: String, + #[arg(long, default_value = "")] + manufacturer: String, + #[arg(long, default_value = "")] + model: String, + #[arg(long, default_value = "")] + notes: String, + /// Output base directory + #[arg(long, default_value = "lamps")] + out: PathBuf, + #[command(flatten)] + instrument: Instrument, + /// Number of readings to average + #[arg(long, default_value_t = 1)] + readings: usize, + /// Read without controlling the instrument + #[arg(long)] + passive: bool, + /// Export from a pcap capture instead of the device + #[arg(long, value_name = "PCAP")] + parse: Option, + /// Supply mode (default ac when --voltage is given) + #[arg(long, help_heading = "Power supply")] + mode: Option, + /// Supply voltage (V) + #[arg(long, help_heading = "Power supply")] + voltage: Option, + /// AC frequency (Hz) + #[arg(long, help_heading = "Power supply")] + frequency: Option, + /// DC current limit (A) + #[arg(long, help_heading = "Power supply")] + current: Option, + /// Power the lamp from the built-in supply (implied by --mode/--voltage/--frequency/--current) + #[arg(long, help_heading = "Power supply")] + psu: bool, + /// Seconds to wait after PSU on before the first reading + #[arg(long, default_value_t = 0.0, help_heading = "Power supply")] + settle: f64, + /// Seconds to wait between readings + #[arg(long, default_value_t = 1.0)] + interval: f64, + }, + /// Print lamp ID labels (QR + ID) on the Brother QL-820NWB + Label { + /// e.g. L0006 + lamp_id: String, + /// tcp:// of the QL-820NWB + #[arg(long, env = "HPCS_LABEL_PRINTER", default_value = "")] + printer: String, + #[arg(long, default_value_t = 2)] + copies: u32, + /// Write the rendered label to a PNG instead of printing + #[arg(long, value_name = "PNG")] + preview: Option, + }, + /// ANSI/IES TM-30-18 (Rf, Rg, hue bins) of a spectrum CSV (wavelength_nm,value) + Tm30 { + spd_csv: PathBuf, + /// Print the 16 hue bins as tm30.csv + #[arg(long)] + bins: bool, + }, + /// Calibrate the B4L tunable-white LED light (CCT / lumen mixing table) + Calibrate { + /// Serial port of the light + #[arg(default_value = "COM3")] + light_port: String, + #[arg(long, short, default_value_t = 115_200)] + baudrate: u32, + #[command(flatten)] + instrument: Instrument, + /// Calibration file + #[arg(long, short, default_value = "calibration_table.json")] + output: PathBuf, + /// Only generate the table from the measurements in the calibration file + #[arg(long, short)] + generate_only: bool, + /// Generate the table from the file and write it to the light + #[arg(long, short)] + write: bool, + /// Clear the calibration on the light (back to defaults) + #[arg(long, short)] + clear: bool, + /// Read the calibration table from the light + #[arg(long)] + read: bool, + /// Skip the y-data calibration (only mixing ratios) + #[arg(long)] + skip_y: bool, + /// Only the y-data calibration + #[arg(long)] + y_only: bool, + }, +} + +fn main() { + let cancel = Arc::new(AtomicBool::new(false)); + { + let c = cancel.clone(); + let _ = ctrlc::set_handler(move || c.store(true, Ordering::SeqCst)); + } + if let Err(e) = run(Cli::parse(), cancel) { + if prompt::is_interrupt(&e) { + println!("\nStopped."); + } else { + println!("ERROR: {e:#}"); + } + std::process::exit(1); + } +} + +fn run(cli: Cli, cancel: Arc) -> Result<()> { + match cli.command { + Cmd::Station { + data_repo, + instrument, + readings, + voltage, + frequency, + settle, + interval, + no_commit, + no_push, + printer, + no_labels, + cache, + no_lookup, + } => { + let cache = cache.unwrap_or_else(|| { + home() + .join(".cache") + .join("hpcs6500") + .join("ean-cache.json") + }); + station::run( + station::Options { + data_repo, + source: instrument.source(), + readings, + voltage, + frequency, + settle, + interval, + no_commit, + no_push, + printer, + no_labels, + cache, + lookup: !no_lookup, + }, + cancel, + ) + } + Cmd::Export { + name, + manufacturer, + model, + notes, + out, + instrument, + readings, + passive, + parse, + mode, + voltage, + frequency, + current, + psu, + settle, + interval, + } => { + let psu = Psu { + mode, + voltage, + frequency, + current, + enable: psu + || mode.is_some() + || voltage.is_some() + || frequency.is_some() + || current.is_some(), + settle, + interval, + }; + let (list, supply) = if let Some(p) = parse { + let list = hpcs6500::pcap::readings(&hpcs6500::pcap::read_messages(&p)?); + if list.is_empty() { + bail!("no measurement blocks in {}", p.display()); + } + println!("Using {} reading(s) from capture", list.len()); + (list, None) + } else { + measure::readings(&instrument.source(), readings, passive, &psu, cancel)? + }; + let reading = bundle::average(&list); + let dir = out.join(&name); + let meta = bundle::LampMeta { + name, + manufacturer, + model, + notes, + ..Default::default() + }; + let tm = bundle::write( + &reading, + &dir, + &meta, + list.len(), + supply.as_ref(), + &bundle::now_iso(), + )?; + let shown = dir.display().to_string().replace('\\', "/"); + println!("\nWrote {shown}/spd.csv, tm30.csv, metrics.json"); + println!( + " {:.0} lm {:.1} lm/W {:.0} K Ra {:.1}", + reading.flux_lm(), + reading.efficacy_lm_w(), + reading.cct_k(), + reading.ra() + ); + println!(" TM-30: Rf {:.1} Rg {:.1}", tm.rf, tm.rg); + Ok(()) + } + Cmd::Label { + lamp_id, + printer, + copies, + preview, + } => { + let id = lamp_id.to_uppercase(); + if let Some(png) = preview { + lamp_label::save_png(&lamp_label::render_label(&id), &png)?; + println!("Wrote {}", png.display()); + return Ok(()); + } + if printer.is_empty() { + bail!( + "no printer configured. Pass --printer tcp:// or set HPCS_LABEL_PRINTER." + ); + } + lamp_label::print_labels(&id, &printer, copies)?; + println!("Printed {copies} label(s) for {id} on {printer}"); + Ok(()) + } + Cmd::Tm30 { spd_csv, bins } => { + let text = + std::fs::read_to_string(&spd_csv).with_context(|| spd_csv.display().to_string())?; + let (mut nm, mut v) = (vec![], vec![]); + for line in text.lines().skip(1) { + let mut it = line.split(','); + if let (Some(a), Some(b)) = (it.next(), it.next()) + && let (Ok(a), Ok(b)) = (a.trim().parse::(), b.trim().parse::()) + { + nm.push(a); + v.push(b); + } + } + let tm = tm30::compute(&nm, &v)?; + if bins { + print!("{}", bundle::tm30_csv(&tm)); + } else { + println!( + "Rf {} Rg {} CCT {} K Duv {}", + pyfmt::fixed(tm.rf, 1), + pyfmt::fixed(tm.rg, 1), + pyfmt::fixed(tm.cct_k, 0), + pyfmt::fixed(tm.duv, 4) + ); + } + Ok(()) + } + Cmd::Calibrate { + light_port, + baudrate, + instrument, + output, + generate_only, + write, + clear, + read, + skip_y, + y_only, + } => calibrate( + light_port, + baudrate, + instrument, + output, + generate_only, + write, + clear, + read, + skip_y, + y_only, + cancel, + ), + } +} + +#[allow(clippy::too_many_arguments)] +fn calibrate( + light_port: String, + baudrate: u32, + instrument: Instrument, + output: PathBuf, + generate_only: bool, + write: bool, + clear: bool, + read: bool, + skip_y: bool, + y_only: bool, + cancel: Arc, +) -> Result<()> { + use calibration::{Calibrator, HpcsMeter, RealClock, SerialLink}; + // the light is only needed for these; the meter for the measuring modes + let measuring = !(read || clear || generate_only || write); + if (generate_only || write) && !output.exists() { + println!("No calibration file found: {}", output.display()); + return Ok(()); + } + let link = SerialLink::open(&light_port, baudrate)?; + macro_rules! with_meter { + ($meter:expr) => {{ + let mut cal = Calibrator::new(link, $meter, RealClock, output); + if read { + if let Some((t, valid)) = cal.read_table(true) { + calibration::print_table(&t, valid); + } + } else if clear { + println!( + "{}", + if cal.cal_clear() { + "Calibration cleared successfully" + } else { + "Failed to clear calibration" + } + ); + } else if y_only { + cal.run_y_only(); + } else if generate_only || write { + let saved = cal.load().unwrap_or_default(); + let table = cal.generate_table(true); + if write { + let y27 = calibration::saved_curve(&saved, "y27_cal"); + let y50 = calibration::saved_curve(&saved, "y50_cal"); + cal.write_table(&table, y27.as_deref(), y50.as_deref(), true); + } + } else { + cal.run(skip_y); + } + Ok(()) + }}; + } + if !measuring { + // no measurements: a meter that is never asked + struct NoMeter; + impl calibration::Meter for NoMeter { + fn measure(&mut self) -> Option { + None + } + } + return with_meter!(NoMeter); + } + match instrument.source() { + Source::Port(port) => { + let port = port + .or_else(hpcs6500::find_port) + .context("HPCS 6500 not found. Connect it or pass --port.")?; + let mut dev = Hpcs6500::open(&port).with_context(|| format!("opening {port}"))?; + dev.set_cancel_flag(cancel); + with_meter!(HpcsMeter(dev)) + } + Source::Simulate(p) => { + let sim = match p { + Some(p) => hpcs6500::sim::Simulator::from_pcap(p)?, + None => hpcs6500::sim::Simulator::sample(), + }; + let mut dev = Hpcs6500::with_transport(sim, "simulator"); + dev.set_cancel_flag(cancel); + with_meter!(HpcsMeter(dev)) + } + } +} + +fn home() -> PathBuf { + std::env::var_os("USERPROFILE") + .or_else(|| std::env::var_os("HOME")) + .map(PathBuf::from) + .unwrap_or_else(|| PathBuf::from(".")) +} diff --git a/src/measure.rs b/src/measure.rs new file mode 100644 index 0000000..f3461b4 --- /dev/null +++ b/src/measure.rs @@ -0,0 +1,162 @@ +//! Taking readings for a bundle: configure and power the lamp from the +//! instrument's supply, settle, run the vendor single-test cycle per +//! reading, and always switch the supply off again. + +use anyhow::{Context, Result, anyhow, bail}; +use hpcs6500::sim::Simulator; +use hpcs6500::{Error as DevError, Hpcs6500, Mode, PsuSettings, Reading, Transport, pyfmt}; +use std::path::PathBuf; +use std::sync::Arc; +use std::sync::atomic::AtomicBool; +use std::time::Duration; + +/// Supply settings for a measurement. +#[derive(Debug, Clone, Default)] +pub struct Psu { + pub mode: Option, + pub voltage: Option, + pub frequency: Option, + pub current: Option, + /// Power the lamp from the supply (switch on before, off after). + pub enable: bool, + /// Seconds to wait after power-on before the first reading. + pub settle: f64, + /// Seconds between readings. + pub interval: f64, +} + +/// Where readings come from. +#[derive(Debug, Clone)] +pub enum Source { + /// The serial port (auto-detected when `None`). + Port(Option), + /// The simulated instrument, replaying a capture or the built-in sample. + Simulate(Option), +} + +fn ok(r: &hpcs6500::Result<()>) -> &'static str { + if r.is_ok() { "OK" } else { "FAILED" } +} + +/// Open the source and take `count` readings. Returns the readings and the +/// supply settings read back from the instrument. +pub fn readings( + source: &Source, + count: usize, + passive: bool, + psu: &Psu, + cancel: Arc, +) -> Result<(Vec, Option)> { + match source { + Source::Port(port) => { + let port = port.clone().or_else(hpcs6500::find_port).ok_or_else(|| { + anyhow!("HPCS 6500 not found. Connect the device or specify --port.") + })?; + let mut dev = Hpcs6500::open(&port).with_context(|| format!("opening {port}"))?; + dev.set_cancel_flag(cancel); + take(&mut dev, count, passive, psu) + } + Source::Simulate(path) => { + let sim = match path { + Some(p) => Simulator::from_pcap(p)?, + None => Simulator::sample(), + }; + let mut dev = Hpcs6500::with_transport(sim, "simulator"); + dev.set_cancel_flag(cancel); + take(&mut dev, count, passive, psu) + } + } +} + +/// The measurement on an open instrument (any transport). +pub fn take( + dev: &mut Hpcs6500, + count: usize, + passive: bool, + psu: &Psu, +) -> Result<(Vec, Option)> { + if let Ok(name) = dev.identify() { + println!("Device: {name}"); + } + let r = run(dev, count, passive, psu); + // the supply goes off whatever happened, also on Ctrl+C + if psu.enable { + let _ = dev.psu_off(); + println!("PSU off"); + } + r +} + +fn run( + dev: &mut Hpcs6500, + count: usize, + passive: bool, + psu: &Psu, +) -> Result<(Vec, Option)> { + if let Some(m) = psu.mode { + let r = dev.set_mode(m); + println!("Mode {m}: {}", ok(&r)); + } + if let Some(v) = psu.voltage { + let r = if psu.mode == Some(Mode::Dc) { + dev.set_dc_voltage(v as f32) + } else { + dev.set_ac_voltage(v as f32) + }; + println!("Voltage {} V: {}", pyfmt::g(v, 6), ok(&r)); + } + if let Some(f) = psu.frequency { + let r = dev.set_ac_frequency(f as f32); + println!("Frequency {} Hz: {}", pyfmt::g(f, 6), ok(&r)); + } + if let Some(a) = psu.current { + let r = dev.set_dc_current(a as f32); + println!("DC current limit {} A: {}", pyfmt::g(a, 6), ok(&r)); + } + let supply = dev.read_psu_settings().ok(); + + if psu.enable { + dev.psu_on().context("failed to turn PSU on")?; + println!("PSU on"); + if psu.settle > 0.0 { + println!("Settling {} s ...", pyfmt::g(psu.settle, 6)); + dev.pause(Duration::from_secs_f64(psu.settle))?; + } else { + dev.pause(Duration::from_millis(200))?; + } + } + + let mut readings = vec![]; + for i in 0..count { + println!("Reading {}/{count} ...", i + 1); + let r = if passive { + dev.read_current() + } else { + // vendor single-shot cycle (verified from USB captures): test config, + // trigger (8C 0E 02), poll, read, reset; auto-PSU stays off, we hold the supply + dev.send_test_config(false) + .and_then(|_| dev.take_single_reading()) + }; + match r { + Ok(r) => readings.push(r), + Err(DevError::Cancelled) => bail!(DevError::Cancelled), + Err(e) => bail!("failed to get reading: {e}"), + } + if i + 1 < count { + if psu.enable && !passive { + // the single test ends with an instrument reset; keep the lamp powered + let _ = dev.psu_on(); + } + if psu.interval > 0.0 { + dev.pause(Duration::from_secs_f64(psu.interval))?; + } + } + } + Ok((readings, supply)) +} + +/// Did this error come from Ctrl+C? +pub fn is_cancel(e: &anyhow::Error) -> bool { + e.chain() + .any(|c| matches!(c.downcast_ref::(), Some(DevError::Cancelled))) +} diff --git a/src/prompt.rs b/src/prompt.rs new file mode 100644 index 0000000..dbe09f7 --- /dev/null +++ b/src/prompt.rs @@ -0,0 +1,65 @@ +//! Console prompts that end cleanly on Ctrl+C and end of input. + +use std::io::{BufRead, Write}; +use std::sync::Arc; +use std::sync::atomic::{AtomicBool, Ordering}; + +/// Ctrl+C at a prompt. +#[derive(Debug, thiserror::Error)] +#[error("interrupted")] +pub struct Interrupted; + +/// End of input (stdin closed). +#[derive(Debug, thiserror::Error)] +#[error("end of input")] +pub struct EndOfInput; + +pub struct Console { + input: Box, + cancel: Arc, +} + +impl Console { + pub fn stdin(cancel: Arc) -> Self { + Console { + input: Box::new(std::io::BufReader::new(std::io::stdin())), + cancel, + } + } + + /// Print `text`, read one line (without the line end). + pub fn input(&mut self, text: &str) -> anyhow::Result { + print!("{text}"); + let _ = std::io::stdout().flush(); + let mut s = String::new(); + let n = self.input.read_line(&mut s); + if self.cancel.swap(false, Ordering::SeqCst) { + println!(); + return Err(Interrupted.into()); + } + match n { + Ok(0) => { + println!(); + Err(EndOfInput.into()) + } + Ok(_) => Ok(s.trim_end_matches(['\r', '\n']).to_string()), + Err(e) => Err(e.into()), + } + } + + /// `label [default]: ` -> the answer, or the default on an empty answer. + pub fn ask(&mut self, label: &str, default: &str) -> anyhow::Result { + let text = if default.is_empty() { + format!("{label}: ") + } else { + format!("{label} [{default}]: ") + }; + let t = self.input(&text)?.trim().to_string(); + Ok(if t.is_empty() { default.to_string() } else { t }) + } +} + +/// Was this error a Ctrl+C (at a prompt or during a measurement)? +pub fn is_interrupt(e: &anyhow::Error) -> bool { + e.downcast_ref::().is_some() || crate::measure::is_cancel(e) +} diff --git a/src/pyjson.rs b/src/pyjson.rs new file mode 100644 index 0000000..11950d0 --- /dev/null +++ b/src/pyjson.rs @@ -0,0 +1,137 @@ +//! JSON text exactly like Python's `json.dump(obj, f, indent=2)`: two-space +//! indent, `", "`/`": "` separators, `ensure_ascii` escapes, floats as +//! `repr` (`230.0`, `1e-05`, `NaN`), keys in insertion order. + +use hpcs6500::pyfmt; +use serde_json::Value; + +/// Serialize like `json.dumps(v, indent=2)` (no trailing newline). +pub fn dumps(v: &Value) -> String { + let mut out = String::new(); + write(&mut out, v, 0); + out +} + +/// The file content as Python writes it in text mode: `\r\n` line ends on +/// Windows, `\n` elsewhere. +pub fn file_text(v: &Value) -> String { + let s = dumps(v); + if cfg!(windows) { + s.replace('\n', "\r\n") + } else { + s + } +} + +fn write(out: &mut String, v: &Value, level: usize) { + match v { + Value::Null => out.push_str("null"), + Value::Bool(b) => out.push_str(if *b { "true" } else { "false" }), + Value::Number(n) => { + if let Some(i) = n.as_i64() { + out.push_str(&i.to_string()); + } else if let Some(u) = n.as_u64() { + out.push_str(&u.to_string()); + } else { + out.push_str(&float(n.as_f64().unwrap_or(f64::NAN))); + } + } + Value::String(s) => string(out, s), + Value::Array(a) if a.is_empty() => out.push_str("[]"), + Value::Array(a) => { + out.push('['); + for (i, x) in a.iter().enumerate() { + if i > 0 { + out.push(','); + } + newline(out, level + 1); + write(out, x, level + 1); + } + newline(out, level); + out.push(']'); + } + Value::Object(o) if o.is_empty() => out.push_str("{}"), + Value::Object(o) => { + out.push('{'); + for (i, (k, x)) in o.iter().enumerate() { + if i > 0 { + out.push(','); + } + newline(out, level + 1); + string(out, k); + out.push_str(": "); + write(out, x, level + 1); + } + newline(out, level); + out.push('}'); + } + } +} + +fn newline(out: &mut String, level: usize) { + out.push('\n'); + out.extend(std::iter::repeat_n(' ', level * 2)); +} + +/// `repr`, with Python's spellings of the non-finite values. +pub fn float(x: f64) -> String { + if x.is_nan() { + "NaN".into() + } else if x.is_infinite() { + if x > 0.0 { + "Infinity".into() + } else { + "-Infinity".into() + } + } else { + pyfmt::repr(x) + } +} + +/// A JSON number that keeps NaN (serde_json cannot hold it): non-finite +/// values become null, which only matters for broken readings. +pub fn num(x: f64) -> Value { + serde_json::Number::from_f64(x) + .map(Value::Number) + .unwrap_or(Value::Null) +} + +fn string(out: &mut String, s: &str) { + out.push('"'); + for c in s.chars() { + match c { + '"' => out.push_str("\\\""), + '\\' => out.push_str("\\\\"), + '\n' => out.push_str("\\n"), + '\r' => out.push_str("\\r"), + '\t' => out.push_str("\\t"), + '\u{8}' => out.push_str("\\b"), + '\u{c}' => out.push_str("\\f"), + ' '..='~' => out.push(c), + _ => { + let mut buf = [0u16; 2]; + for u in c.encode_utf16(&mut buf) { + out.push_str(&format!("\\u{u:04x}")); + } + } + } + } + out.push('"'); +} + +#[cfg(test)] +mod tests { + use super::*; + use serde_json::json; + + #[test] + fn like_python() { + let v = json!({"name": "L0001", "rated": {"Phi_lm": 1050, "Power_W": 9.5}, "e": {}, "l": [], "x": 230.0, + "s": "Café \"q\" \u{1F4A1}\t", "n": null, "b": false, "tiny": 1e-5}); + assert_eq!( + dumps(&v), + "{\n \"name\": \"L0001\",\n \"rated\": {\n \"Phi_lm\": 1050,\n \"Power_W\": 9.5\n },\n \"e\": {},\n \"l\": [],\n \"x\": 230.0,\n \"s\": \"Caf\\u00e9 \\\"q\\\" \\ud83d\\udca1\\t\",\n \"n\": null,\n \"b\": false,\n \"tiny\": 1e-05\n}" + ); + assert_eq!(dumps(&json!([1, [2.5]])), "[\n 1,\n [\n 2.5\n ]\n]"); + } +} diff --git a/src/station.rs b/src/station.rs new file mode 100644 index 0000000..f3b49bf --- /dev/null +++ b/src/station.rs @@ -0,0 +1,665 @@ +//! The lamp measurement station: scan a barcode, measure, commit, label. +//! +//! Every lamp gets an internal ID (L0001, L0002, ...) as its primary key; +//! the EAN barcode is optional metadata, so one barcode can cover several +//! versions (daylight / warm white in the same box art) and unbranded lamps +//! work too. +//! +//! 1. Every run opens with a freshly allocated ID. It only becomes real once +//! the bundle is written, so aborting never burns a number. +//! 2. Scan the box (a keyboard-wedge scanner types EAN + Enter), press Enter +//! for a lamp without a barcode, or type an existing ID to re-measure +//! that lamp with everything pre-filled. EANs are checksum-validated and +//! looked up in previous lamps, the local cache, then upcitemdb.com +//! (GS1-restricted 20-29 barcodes are retailer-internal and skip it). +//! 3. Confirm the identification and type the advertised values from the +//! packaging (stored under "rated" in metrics.json). +//! 4. Insert the lamp: the built-in supply powers it per the published +//! procedure (230 V / 50 Hz, 60 s settle, 5 readings averaged) and the +//! bundle is written to `/lamps//`. +//! 5. The bundle is committed to comparison-data and pushed; the website +//! picks it up automatically. +//! 6. Two ID labels (QR + ID, DK-11221 23x23 mm) print on the QL-820NWB. + +use crate::bundle::{self, LampMeta}; +use crate::measure::{self, Psu, Source}; +use crate::prompt::{Console, EndOfInput, is_interrupt}; +use anyhow::{Context, Result, bail}; +use hpcs6500::{Mode, pyfmt}; +use serde_json::{Map, Value, json}; +use std::collections::BTreeMap; +use std::path::{Path, PathBuf}; +use std::process::Command; +use std::sync::Arc; +use std::sync::atomic::AtomicBool; + +pub const LOOKUP_URL: &str = "https://api.upcitemdb.com/prod/trial/lookup?upc="; + +/// Advertised values typed from the packaging; keys match the measured +/// metrics they are compared against on the site. +pub const RATED_FIELDS: [(&str, &str); 6] = [ + ("Phi_lm", "Rated flux (lm)"), + ("CCT_K", "Rated CCT (K)"), + ("Power_W", "Rated power (W)"), + ("Ra", "Rated CRI (Ra)"), + ("lifetime_h", "Rated lifetime (h)"), + ("W_equiv", "Incandescent equivalent (W)"), +]; + +/// Canonical spellings for brands; extended at runtime by the database and +/// the cache, so the first accepted spelling of a new brand sticks. +pub const BRAND_SEED: [&str; 13] = [ + "Philips", + "OSRAM", + "LAMPTAN", + "TKL", + "ST", + "IKEA", + "Panasonic", + "Toshiba", + "GE", + "Sylvania", + "Xiaomi", + "Opple", + "EVE", +]; + +pub struct Options { + pub data_repo: PathBuf, + pub source: Source, + pub readings: usize, + pub voltage: f64, + pub frequency: f64, + pub settle: f64, + pub interval: f64, + pub no_commit: bool, + pub no_push: bool, + pub printer: String, + pub no_labels: bool, + pub cache: PathBuf, + pub lookup: bool, +} + +/// `L0042` -> 42. +pub fn parse_id(s: &str) -> Option { + let d = s.strip_prefix('L')?; + (d.len() >= 4 && d.bytes().all(|b| b.is_ascii_digit())) + .then(|| d.parse().ok()) + .flatten() +} + +/// A valid EAN-13 (UPC-A gets a leading zero), or None. +pub fn ean_normalize(code: &str) -> Option { + let mut d: String = code.chars().filter(|c| c.is_ascii_digit()).collect(); + if d.len() == 12 { + d.insert(0, '0'); + } + if d.len() != 13 { + return None; + } + let digits: Vec = d.chars().map(|c| c.to_digit(10).expect("digit")).collect(); + let sum: u32 = digits[..12] + .iter() + .enumerate() + .map(|(i, x)| x * if i % 2 == 1 { 3 } else { 1 }) + .sum(); + ((10 - sum % 10) % 10 == digits[12]).then_some(d) +} + +/// GS1 prefixes 20-29 are retailer-internal, never publicly resolvable. +pub fn is_restricted(ean: &str) -> bool { + ean.get(..2) + .and_then(|p| p.parse::().ok()) + .is_some_and(|p| (20..=29).contains(&p)) +} + +/// `{id: metrics}` of every measured lamp. +pub fn lamp_index(data_repo: &Path) -> BTreeMap { + let mut lamps = BTreeMap::new(); + let Ok(dir) = std::fs::read_dir(data_repo.join("lamps")) else { + return lamps; + }; + for e in dir.flatten() { + let name = e.file_name().to_string_lossy().to_string(); + if parse_id(&name).is_none() { + continue; + } + if let Ok(text) = std::fs::read_to_string(e.path().join("metrics.json")) + && let Ok(v) = serde_json::from_str::(&text) + { + lamps.insert(name, v); + } + } + lamps +} + +pub fn next_lamp_id(data_repo: &Path) -> String { + let max = std::fs::read_dir(data_repo.join("lamps")) + .into_iter() + .flatten() + .flatten() + .filter_map(|e| parse_id(&e.file_name().to_string_lossy())) + .max() + .unwrap_or(0); + format!("L{:04}", max + 1) +} + +fn s<'a>(v: &'a Value, k: &str) -> &'a str { + v.get(k).and_then(|x| x.as_str()).unwrap_or("") +} + +pub struct Cache { + path: PathBuf, +} + +impl Cache { + pub fn new(path: PathBuf) -> Self { + Cache { path } + } + pub fn load(&self) -> Map { + std::fs::read_to_string(&self.path) + .ok() + .and_then(|t| serde_json::from_str::(&t).ok()) + .and_then(|v| v.as_object().cloned()) + .unwrap_or_default() + } + pub fn save(&self, m: &Map) -> Result<()> { + if let Some(d) = self.path.parent() { + std::fs::create_dir_all(d)?; + } + std::fs::write( + &self.path, + crate::pyjson::file_text(&Value::Object(m.clone())), + )?; + Ok(()) + } +} + +/// The manufacturer in its canonical capitalization. +pub fn canonical_brand(name: &str, lamps: &BTreeMap, cache: &Cache) -> String { + let name = name.split_whitespace().collect::>().join(" "); + if name.is_empty() { + return name; + } + let mut brands: BTreeMap = BRAND_SEED + .iter() + .map(|b| (b.to_lowercase(), b.to_string())) + .collect(); + for entry in cache.load().values() { + let b = s(entry, "manufacturer"); + if !b.is_empty() { + brands + .entry(b.to_lowercase()) + .or_insert_with(|| b.to_string()); + } + } + for m in lamps.values() { + let b = s(m, "manufacturer"); + if !b.is_empty() { + brands.insert(b.to_lowercase(), b.to_string()); // the database wins + } + } + brands.get(&name.to_lowercase()).cloned().unwrap_or(name) +} + +/// Best-effort (manufacturer, model, source) for an EAN. +pub fn lookup_ean( + ean: &str, + lamps: &BTreeMap, + cache: &Cache, + online: bool, +) -> (String, String, String) { + for m in lamps.values() { + if s(m, "ean") == ean && (!s(m, "manufacturer").is_empty() || !s(m, "model").is_empty()) { + return ( + s(m, "manufacturer").into(), + s(m, "model").into(), + format!("previous lamp {}", s(m, "name")), + ); + } + } + if let Some(c) = cache.load().get(ean) { + return ( + s(c, "manufacturer").into(), + s(c, "model").into(), + "local cache".into(), + ); + } + if is_restricted(ean) { + return ( + String::new(), + String::new(), + "retailer-internal barcode, not resolvable".into(), + ); + } + if online { + match online_lookup(ean) { + Ok(Some((b, t))) => return (b, t, "upcitemdb.com (verify against packaging)".into()), + Ok(None) => {} + Err(e) => println!(" (online lookup failed: {e})"), + } + } + (String::new(), String::new(), "no match".into()) +} + +fn online_lookup(ean: &str) -> Result> { + let agent: ureq::Agent = ureq::Agent::config_builder() + .timeout_global(Some(std::time::Duration::from_secs(10))) + .build() + .into(); + let body = agent + .get(format!("{LOOKUP_URL}{ean}")) + .header("User-Agent", "hpcs6500-lamp-station") + .call()? + .body_mut() + .read_to_string()?; + let v: Value = serde_json::from_str(&body)?; + let item = v + .get("items") + .and_then(|i| i.get(0)) + .cloned() + .unwrap_or(json!({})); + let (b, t) = (s(&item, "brand").to_string(), s(&item, "title").to_string()); + Ok((!b.is_empty() || !t.is_empty()).then_some((b, t))) +} + +/// Advertised values from the box; Enter skips a field. +fn prompt_rated(con: &mut Console, previous: Option<&Value>) -> Result> { + println!(" Advertised values from the packaging (Enter to skip):"); + let mut rated = Map::new(); + for (key, label) in RATED_FIELDS { + let default = match previous.and_then(|p| p.get(key)) { + Some(Value::Number(n)) => match n.as_i64() { + Some(i) => i.to_string(), + None => pyfmt::repr(n.as_f64().unwrap_or(0.0)), + }, + Some(Value::String(t)) => t.clone(), + _ => String::new(), + }; + let raw = con.ask(&format!(" {label}"), &default)?; + if raw.is_empty() { + continue; + } + match raw.trim().parse::() { + Ok(v) if v.is_finite() && v == v.trunc() && v.abs() < 9e15 => { + rated.insert(key.into(), json!(v as i64)); + } + Ok(v) if v.is_finite() => { + rated.insert(key.into(), crate::pyjson::num(v)); + } + _ => println!(" (not a number, skipped: '{raw}')"), + } + } + Ok(rated) +} + +fn git(repo: &Path, args: &[&str]) -> Result { + let out = Command::new("git") + .arg("-C") + .arg(repo) + .args(args) + .output() + .context("running git")?; + if !out.status.success() { + bail!( + "git {}: {}", + args.join(" "), + String::from_utf8_lossy(&out.stderr).trim() + ); + } + Ok(String::from_utf8_lossy(&out.stdout).to_string()) +} + +fn commit_bundle(repo: &Path, id: &str, label: &str, existed: bool, push: bool) -> Result<()> { + let path = format!("lamps/{id}"); + git(repo, &["add", &path])?; + if git(repo, &["status", "--porcelain", &path])? + .trim() + .is_empty() + { + println!("No data changes to commit."); + return Ok(()); + } + let verb = if existed { "Re-measure" } else { "Add" }; + let msg = format!("{verb} lamp {id} ({label})"); + git(repo, &["commit", "-m", &msg])?; + println!("Committed to comparison-data: {verb} lamp {id} ({label})"); + if push { + git(repo, &["push"])?; + println!("Pushed."); + } + Ok(()) +} + +/// One lamp: identify, measure, write, commit, label. +#[allow(clippy::too_many_arguments)] +fn measure_one( + con: &mut Console, + opts: &Options, + cache: &Cache, + cancel: &Arc, + new_id: &str, + mut ean: String, + lamps: &BTreeMap, + existing_id: Option, +) -> Result<()> { + let mut lamp_id = new_id.to_string(); + let mut previous: Option<&Value> = None; + if let Some(id) = existing_id { + previous = lamps.get(&id); + ean = previous + .map(|p| s(p, "ean").to_string()) + .unwrap_or_default(); + println!( + " Re-measuring {id}{}", + if ean.is_empty() { + String::new() + } else { + format!(" (EAN {ean})") + } + ); + lamp_id = id; + } else if !ean.is_empty() { + let same: Vec<(&String, &Value)> = + lamps.iter().filter(|(_, m)| s(m, "ean") == ean).collect(); + if !same.is_empty() { + println!(" Lamps already measured with this EAN:"); + for (i, m) in &same { + let variant = if s(m, "variant").is_empty() { + String::new() + } else { + format!(", {}", s(m, "variant")) + }; + println!( + " {i}: {} {}{variant}", + s(m, "manufacturer"), + s(m, "model") + ); + } + let choice = con.ask( + &format!("Re-measure one of these (type its ID) or Enter to continue as {new_id}"), + "", + )?; + if !choice.is_empty() { + let up = choice.to_uppercase(); + let Some((id, m)) = same.iter().find(|(i, _)| **i == up) else { + println!(" Unknown ID '{choice}', aborting this run."); + return Ok(()); + }; + lamp_id = id.to_string(); + previous = Some(m); + println!(" Re-measuring {lamp_id}"); + } + } + } + + let (mut manufacturer, mut model) = (String::new(), String::new()); + if let Some(p) = previous { + (manufacturer, model) = (s(p, "manufacturer").into(), s(p, "model").into()); + } else if !ean.is_empty() { + let (m, md, source) = lookup_ean(&ean, lamps, cache, opts.lookup); + println!( + " Lookup: {} / {} ({source})", + if m.is_empty() { "?" } else { &m }, + if md.is_empty() { "?" } else { &md } + ); + (manufacturer, model) = (m, md); + } + let prev = |k: &str| previous.map(|p| s(p, k).to_string()).unwrap_or_default(); + + manufacturer = con.ask( + "Manufacturer", + &canonical_brand(&manufacturer, lamps, cache), + )?; + let canon = canonical_brand(&manufacturer, lamps, cache); + if canon != manufacturer { + println!(" Using canonical brand name: {canon}"); + manufacturer = canon; + } + model = con.ask("Model", &model)?; + let type_default = previous + .and_then(|p| p.get("type")) + .and_then(|t| t.as_str()) + .unwrap_or("led") + .to_string(); + let lamp_type = con + .ask( + "Type (led / halogen / cfl / incandescent / ...)", + &type_default, + )? + .to_lowercase() + .trim() + .to_string(); + let dim_default = match previous + .and_then(|p| p.get("dimmable")) + .and_then(|d| d.as_bool()) + { + None => "", + Some(true) => "y", + Some(false) => "n", + }; + let dim = con + .ask("Dimmable? (y / n, Enter if unknown)", dim_default)? + .to_lowercase(); + let dimmable = if dim.starts_with('y') { + Some(true) + } else if dim.starts_with('n') { + Some(false) + } else { + None + }; + let variant = con + .ask( + "Variant (e.g. daylight / warm white, Enter if none)", + &prev("variant"), + )? + .to_lowercase(); + let notes_default = if let Some(n) = previous.and_then(|p| p.get("notes")) { + n.as_str().unwrap_or("").to_string() + } else if !ean.is_empty() && is_restricted(&ean) && manufacturer.is_empty() { + "retailer-internal barcode, brand unknown".into() + } else { + String::new() + }; + let notes = con.ask("Notes", ¬es_default)?; + let rated = prompt_rated(con, previous.and_then(|p| p.get("rated")))?; + + if !ean.is_empty() && (!manufacturer.is_empty() || !model.is_empty()) { + let mut c = cache.load(); + c.insert( + ean.clone(), + json!({"manufacturer": manufacturer, "model": model}), + ); + cache.save(&c)?; + } + + con.input("Insert the lamp, close the sphere, press Enter to start ... ")?; + + let psu = Psu { + mode: Some(Mode::Ac), + voltage: Some(opts.voltage), + frequency: Some(opts.frequency), + current: None, + enable: true, + settle: opts.settle, + interval: opts.interval, + }; + let (readings, supply) = + measure::readings(&opts.source, opts.readings, false, &psu, cancel.clone())?; + let reading = bundle::average(&readings); + let meta = LampMeta { + name: lamp_id.clone(), + ean: ean.clone(), + lamp_type, + dimmable, + variant: variant.clone(), + manufacturer: manufacturer.clone(), + model: model.clone(), + notes, + rated: rated.clone(), + }; + let out_dir = opts.data_repo.join("lamps").join(&lamp_id); + let tm = bundle::write( + &reading, + &out_dir, + &meta, + readings.len(), + supply.as_ref(), + &bundle::now_iso(), + )?; + + println!( + "\n {:.0} lm {:.1} lm/W {:.0} K Ra {:.1} TM-30 Rf {:.1} / Rg {:.1}", + reading.flux_lm(), + reading.efficacy_lm_w(), + reading.cct_k(), + reading.ra(), + tm.rf, + tm.rg + ); + let rated_num = |k: &str| rated.get(k).and_then(|v| v.as_f64()).filter(|v| *v != 0.0); + if let Some(flux) = rated_num("Phi_lm") { + print!( + " vs advertised: {:+.1} % flux", + reading.flux_lm() / flux * 100.0 - 100.0 + ); + if let Some(cct) = rated_num("CCT_K") { + print!(", {:+.0} K CCT", reading.cct_k() - cct); + } + println!(); + } + println!(); + + let mut parts: Vec = [&manufacturer, &model] + .iter() + .filter(|x| !x.is_empty()) + .map(|x| x.to_string()) + .collect(); + if !variant.is_empty() { + parts.push(variant); + } + if !ean.is_empty() { + parts.push(format!("EAN {ean}")); + } + if !opts.no_commit { + let label = if parts.is_empty() { + "unidentified".to_string() + } else { + parts.join(", ") + }; + commit_bundle( + &opts.data_repo, + &lamp_id, + &label, + previous.is_some(), + !opts.no_push, + )?; + } + println!(" The lamp publishes automatically (auto-bump deploy); add an .md under"); + println!(" src/content/comparisons/lamps/ only for photos, buy links, or notes."); + + // two ID labels on the QL-820NWB: one for the box, one for the lamp + if !opts.no_labels { + if opts.printer.is_empty() { + println!(" (no label printer configured; set HPCS_LABEL_PRINTER or use --printer,"); + println!(" reprint later with: lampbench label {lamp_id})"); + } else { + match lamp_label::print_labels(&lamp_id, &opts.printer, 2) { + Ok(()) => println!(" Printed 2 ID labels for {lamp_id}."), + Err(e) => { + println!(" Label printing failed ({e}); reprint later with:"); + println!(" lampbench label {lamp_id}"); + } + } + } + } + Ok(()) +} + +pub fn run(opts: Options, cancel: Arc) -> Result<()> { + // in a submodule checkout .git is a file, not a directory + if !opts.data_repo.join(".git").exists() { + bail!( + "{} is not a git checkout of comparison-data.", + opts.data_repo.display() + ); + } + let cache = Cache::new(opts.cache.clone()); + let mut con = Console::stdin(cancel.clone()); + println!("Lamp station ready. Every run starts a new lamp ID; the EAN is optional"); + println!("(scan it, or press Enter to skip). 'q' quits."); + loop { + // a fresh ID opens every run; it only becomes real once a bundle is written + let lamps = lamp_index(&opts.data_repo); + let new_id = next_lamp_id(&opts.data_repo); + println!("\n--- New lamp {new_id} ---"); + let code = match con + .input("Scan EAN (Enter to skip, L#### re-measures an existing lamp, q quits): ") + { + Ok(c) => c.trim().to_string(), + Err(_) => break, + }; + if ["q", "quit", "exit"].contains(&code.to_lowercase().as_str()) { + break; + } + let mut existing = None; + let mut ean = String::new(); + if parse_id(&code.to_uppercase()).is_some() { + let id = code.to_uppercase(); + if !lamps.contains_key(&id) { + println!(" No lamp {id} in the database."); + continue; + } + existing = Some(id); + } else if !code.is_empty() && !["n", "none"].contains(&code.to_lowercase().as_str()) { + match ean_normalize(&code) { + Some(e) => ean = e, + None => { + println!(" Not a valid EAN-13/UPC-A: '{code}' (Enter would skip the EAN)"); + continue; + } + } + } + match measure_one( + &mut con, &opts, &cache, &cancel, &new_id, ean, &lamps, existing, + ) { + Ok(()) => {} + Err(e) if e.downcast_ref::().is_some() => break, + Err(e) if is_interrupt(&e) => { + println!("\n Aborted; lamp skipped. (The supply is switched off.)") + } + Err(e) => println!(" ERROR: {e:#}"), + } + } + println!("Bye."); + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn ean_checks() { + assert_eq!( + ean_normalize("8718696844984").as_deref(), + Some("8718696844984") + ); + assert_eq!( + ean_normalize("871869684498 4").as_deref(), + Some("8718696844984") + ); + assert_eq!(ean_normalize("8718696844985"), None); + assert_eq!( + ean_normalize("036000291452").as_deref(), + Some("0036000291452") + ); // UPC-A + assert_eq!(ean_normalize("123"), None); + assert!(is_restricted("2001234567890")); + assert!(!is_restricted("8850646092349")); + assert_eq!(parse_id("L0042"), Some(42)); + assert_eq!(parse_id("L12345"), Some(12345)); + assert_eq!(parse_id("L042"), None); + assert_eq!(parse_id("X0042"), None); + } +} diff --git a/tests/golden/bundles/cases.json b/tests/golden/bundles/cases.json new file mode 100644 index 0000000..f5dcb90 --- /dev/null +++ b/tests/golden/bundles/cases.json @@ -0,0 +1,89 @@ +{ + "measured_at": "2026-07-09T16:22:57+07:00", + "cases": [ + { + "case": "export_avg5", + "readings": [ + "r01", + "r04", + "r05", + "r06", + "r02" + ], + "meta": { + "name": "philips-a60", + "manufacturer": "Philips", + "model": "A60 8W 927", + "notes": "" + }, + "supply": null + }, + { + "case": "station_full", + "readings": [ + "r05", + "r06", + "r04" + ], + "meta": { + "name": "L0042", + "ean": "8718696844984", + "type": "led", + "dimmable": false, + "variant": "cool white", + "manufacturer": "Philips", + "model": "MyCare 9.5W Caf\u00e9 \u00fc \u0e44\u0e1f", + "notes": "box says \"warm\"\tok", + "rated": { + "Phi_lm": 1050, + "Power_W": 9.5, + "lifetime_h": 15000 + } + }, + "supply": { + "ac_voltage": 230.0, + "ac_frequency": 50.0, + "dc_voltage": 24.0, + "dc_current": 5.0, + "mode": "AC" + } + }, + { + "case": "harmonics_single", + "readings": [ + "r02" + ], + "meta": { + "name": "L0007", + "ean": "", + "type": "halogen", + "dimmable": true, + "variant": "", + "manufacturer": "", + "model": "", + "notes": "", + "rated": {} + }, + "supply": { + "ac_voltage": 230.0, + "ac_frequency": 50.0, + "dc_voltage": 24.0, + "dc_current": 5.0, + "mode": "AC" + } + }, + { + "case": "external_power", + "readings": [ + "r07" + ], + "meta": { + "name": "dc-strip", + "manufacturer": "", + "model": "", + "notes": "powered externally" + }, + "supply": null + } + ] +} \ No newline at end of file diff --git a/tests/golden/bundles/export_avg5/metrics.json b/tests/golden/bundles/export_avg5/metrics.json new file mode 100644 index 0000000..227c064 --- /dev/null +++ b/tests/golden/bundles/export_avg5/metrics.json @@ -0,0 +1,74 @@ +{ + "name": "philips-a60", + "manufacturer": "Philips", + "model": "A60 8W 927", + "notes": "", + "instrument": "HPCS6500", + "measured_at": "2026-07-09T16:22:57+07:00", + "instrument_date": "2026-02-04", + "instrument_time": "15:38:14", + "readings_averaged": 5, + "tm30": { + "Rf": 82.8, + "Rg": 102.6 + }, + "cri": { + "Ra": 83.00858001708984, + "R1": 82.17662658691407, + "R2": 93.99931488037109, + "R3": 93.30018768310546, + "R4": 76.5554412841797, + "R5": 81.44241180419922, + "R6": 89.34300079345704, + "R7": 83.15747680664063, + "R8": 64.09416198730469, + "R9": 4.789063262939453, + "R10": 84.07984313964843, + "R11": 76.13002166748046, + "R12": 60.050942993164064, + "R13": 86.5272430419922, + "R14": 96.78124694824218, + "R15": 75.97555694580078 + }, + "photometric": { + "Phi_lm": 480.47785034179685, + "eta_lm_W": 57.135939025878905, + "CCT_K": 5652.32763671875, + "Duv": 0.0055332078598439695, + "SDCM": 4.718670845031738, + "TLCI": 67.89999389648438 + }, + "chromaticity": { + "x": 0.3289025008678436, + "y": 0.3489073276519775, + "u": 0.20149995386600494, + "v": 0.3206336498260498, + "u_prime": 0.20149995386600494, + "v_prime": 0.48095048069953916, + "CIE_X": 663.1466796875, + "CIE_Y": 703.4814453125, + "CIE_Z": 649.60947265625 + }, + "radiometric": { + "Phi_e_mW": 1493.6589111328126, + "Phi_euv_mW": 0.0, + "Phi_eb_mW": 470.34068603515624, + "Phi_ey_mW": 681.030615234375, + "Phi_er_mW": 331.6043762207031, + "Phi_efr_mW": 11.389583778381347, + "Phi_eir_mW": 0.0, + "Phi_e_total": 1494.364990234375 + }, + "electrical": { + "Voltage_V": 230.29462585449218, + "Current_A": 0.06532531827688218, + "Power_W": 8.404675102233886, + "Freq_Hz": 50.02176513671875, + "PF": 0.5586463570594787 + }, + "sensor": { + "PeakSignal": 53125.4, + "DarkSignal": 2234.8, + "Compensate": 2834.0 + } +} \ No newline at end of file diff --git a/tests/golden/bundles/export_avg5/spd.csv b/tests/golden/bundles/export_avg5/spd.csv new file mode 100644 index 0000000..6aa5d44 --- /dev/null +++ b/tests/golden/bundles/export_avg5/spd.csv @@ -0,0 +1,351 @@ +wavelength_nm,value +380.00,0.000349989 +381.92,0.00483611 +383.84,0.0160743 +385.76,0.0344528 +387.68,0.0595032 +389.60,0.0884034 +391.52,0.125467 +393.44,0.167817 +395.36,0.211468 +397.28,0.261103 +399.20,0.318486 +401.12,0.385365 +403.04,0.463185 +404.96,0.552476 +406.88,0.653943 +408.80,0.769326 +410.72,0.901583 +412.64,1.05217 +414.56,1.22158 +416.48,1.41013 +418.40,1.61743 +420.32,1.84663 +422.23,2.09922 +424.15,2.37704 +426.07,2.68042 +427.99,3.00916 +429.91,3.36805 +431.83,3.75894 +433.75,4.18192 +435.67,4.64312 +437.59,5.2016 +439.51,5.81317 +441.43,6.42468 +443.35,7.09671 +445.27,7.82733 +447.19,8.61316 +449.11,9.44029 +451.03,10.2881 +452.95,11.1289 +454.87,11.9291 +456.79,12.6465 +458.71,13.2365 +460.63,13.6597 +462.55,13.8732 +464.47,13.8675 +466.39,13.6584 +468.31,13.2731 +470.23,12.7559 +472.15,12.1477 +474.07,11.4941 +475.99,10.8423 +477.91,10.2226 +479.83,9.65732 +481.75,9.15363 +483.67,8.70812 +485.59,8.31637 +487.51,7.96727 +489.43,7.64964 +491.35,7.35193 +493.27,7.06379 +495.19,6.77947 +497.11,6.49952 +499.03,6.22794 +500.95,5.96942 +502.87,5.72682 +504.79,5.50173 +506.70,5.28802 +508.62,5.09988 +510.54,4.93933 +512.46,4.80644 +514.38,4.7008 +516.30,4.62154 +518.22,4.5641 +520.14,4.52692 +522.06,4.49814 +523.98,4.48688 +525.90,4.49522 +527.82,4.51233 +529.74,4.53681 +531.66,4.56752 +533.58,4.60427 +535.50,4.64767 +537.42,4.69671 +539.34,4.75317 +541.26,4.81654 +543.18,4.88506 +545.10,4.95903 +547.02,5.03626 +548.94,5.11667 +550.86,5.19991 +552.78,5.28579 +554.70,5.37357 +556.62,5.46053 +558.54,5.54453 +560.46,5.62461 +562.38,5.7017 +564.30,5.77487 +566.22,5.84592 +568.14,5.91392 +570.06,5.97812 +571.98,6.0385 +573.90,6.09349 +575.82,6.14387 +577.74,6.19034 +579.66,6.23339 +581.58,6.27306 +583.50,6.30817 +585.42,6.33993 +587.34,6.36943 +589.26,6.39663 +591.17,6.42233 +593.09,6.45112 +595.01,6.47876 +596.93,6.50223 +598.85,6.52435 +600.77,6.54392 +602.69,6.56168 +604.61,6.57953 +606.53,6.59926 +608.45,6.62242 +610.37,6.64727 +612.29,6.67315 +614.21,6.70048 +616.13,6.72931 +618.05,6.76 +619.97,6.79003 +621.89,6.81868 +623.81,6.8474 +625.73,6.87624 +627.65,6.90616 +629.57,6.93676 +631.49,6.96569 +633.41,6.9938 +635.33,7.02035 +637.25,7.04539 +639.17,7.06939 +641.09,7.09232 +643.01,7.1142 +644.93,7.13482 +646.85,7.15419 +648.77,7.17269 +650.69,7.18928 +652.61,7.20383 +654.53,7.21743 +656.45,7.23071 +658.37,7.24443 +660.29,7.25858 +662.21,7.2721 +664.13,7.28552 +666.05,7.29919 +667.97,7.31272 +669.89,7.32712 +671.81,7.34178 +673.72,7.35729 +675.64,7.3732 +677.56,7.38921 +679.48,7.4075 +681.40,7.42868 +683.32,7.45557 +685.24,7.4829 +687.16,7.50422 +689.08,7.52079 +691.00,7.53258 +692.92,7.53913 +694.84,7.54075 +696.76,7.53737 +698.68,7.52993 +700.60,7.52091 +702.52,7.51073 +704.44,7.501 +706.36,7.49162 +708.28,7.48149 +710.20,7.46878 +712.12,7.4511 +714.04,7.42755 +715.96,7.39964 +717.88,7.36925 +719.80,7.33708 +721.72,7.30326 +723.64,7.26723 +725.56,7.22859 +727.48,7.18722 +729.40,7.14517 +731.32,7.11295 +733.24,7.07867 +735.16,7.03047 +737.08,6.9773 +739.00,6.91969 +740.92,6.85961 +742.84,6.79838 +744.76,6.73534 +746.68,6.67011 +748.60,6.60305 +750.52,6.53246 +752.44,6.45886 +754.36,6.38241 +756.28,6.30303 +758.19,6.22218 +760.11,6.13986 +762.03,6.05723 +763.95,5.9751 +765.87,5.89259 +767.79,5.80988 +769.71,5.74033 +771.63,5.66936 +773.55,5.58306 +775.47,5.49582 +777.39,5.40821 +779.31,5.32035 +781.23,5.23302 +783.15,5.14594 +785.07,5.05858 +786.99,4.97164 +788.91,4.8848 +790.83,4.7984 +792.75,4.71309 +794.67,4.62851 +796.59,4.54414 +798.51,4.45922 +800.43,4.37354 +802.35,4.28697 +804.27,4.21402 +806.19,4.14114 +808.11,4.05526 +810.03,3.96973 +811.95,3.88399 +813.87,3.79771 +815.79,3.7112 +817.71,3.62492 +819.63,3.53892 +821.55,3.45354 +823.47,3.36889 +825.39,3.28476 +827.31,3.20083 +829.23,3.11759 +831.15,3.03488 +833.07,2.96454 +834.99,2.89571 +836.91,2.81655 +838.83,2.73836 +840.74,2.66171 +842.66,2.58579 +844.58,2.51105 +846.50,2.43775 +848.42,2.36543 +850.34,2.29522 +852.26,2.22704 +854.18,2.16095 +856.10,2.09742 +858.02,2.03556 +859.94,1.9836 +861.86,1.93296 +863.78,1.8752 +865.70,1.81864 +867.62,1.7636 +869.54,1.70956 +871.46,1.65632 +873.38,1.60399 +875.30,1.55222 +877.22,1.50169 +879.14,1.45317 +881.06,1.4066 +882.98,1.36233 +884.90,1.32519 +886.82,1.28854 +888.74,1.24646 +890.66,1.20447 +892.58,1.16263 +894.50,1.12119 +896.42,1.08057 +898.34,1.04128 +900.26,1.00357 +902.18,0.966894 +904.10,0.931244 +906.02,0.896543 +907.94,0.862263 +909.86,0.83332 +911.78,0.804874 +913.70,0.772641 +915.62,0.741735 +917.54,0.711998 +919.46,0.683282 +921.38,0.655367 +923.30,0.628354 +925.21,0.602323 +927.13,0.577235 +929.05,0.552911 +930.97,0.532575 +932.89,0.51299 +934.81,0.491135 +936.73,0.470223 +938.65,0.450316 +940.57,0.431547 +942.49,0.413897 +944.41,0.397301 +946.33,0.381468 +948.25,0.366205 +950.17,0.351438 +952.09,0.336986 +954.01,0.324354 +955.93,0.311324 +957.85,0.295755 +959.77,0.279619 +961.69,0.263628 +963.61,0.248491 +965.53,0.234237 +967.45,0.221016 +969.37,0.209104 +971.29,0.198092 +973.21,0.189503 +975.13,0.181538 +977.05,0.172594 +978.97,0.164553 +980.89,0.157496 +982.81,0.150827 +984.73,0.144015 +986.65,0.137052 +988.57,0.129869 +990.49,0.123145 +992.41,0.117916 +994.33,0.112869 +996.25,0.107184 +998.17,0.101477 +1000.09,0.0955527 +1002.01,0.0894594 +1003.93,0.0835585 +1005.85,0.0781945 +1007.77,0.0733733 +1009.68,0.0689658 +1011.60,0.0653379 +1013.52,0.0616523 +1015.44,0.0575474 +1017.36,0.0538378 +1019.28,0.0503168 +1021.20,0.0468593 +1023.12,0.0431563 +1025.04,0.0391101 +1026.96,0.0348429 +1028.88,0.0309126 +1030.80,0.0279664 +1032.72,0.0252084 +1034.64,0.0222505 +1036.56,0.0194355 +1038.48,0.0165936 +1040.40,0.0136962 +1042.32,0.0105769 +1044.24,0.00740189 +1046.16,0.00445013 +1048.08,0.0025752 +1050.00,0.00133693 diff --git a/tests/golden/bundles/export_avg5/tm30.csv b/tests/golden/bundles/export_avg5/tm30.csv new file mode 100644 index 0000000..8362460 --- /dev/null +++ b/tests/golden/bundles/export_avg5/tm30.csv @@ -0,0 +1,17 @@ +bin,ref_a,ref_b,test_a,test_b,ref_a_norm,ref_b_norm,test_a_norm,test_b_norm,Rcs_pct,Rhs,Rf_h +1,23.8371,4.89622,25.5118,6.79164,0.97955,0.201203,1.04837,0.279093,8.26956,0.0629661,76.4852 +2,18.6336,11.9013,19.8407,13.1208,0.842769,0.538276,0.897363,0.593431,7.60361,0.0155293,82.0527 +3,13.4292,20.7065,15.7389,20.9186,0.544131,0.839,0.637718,0.847591,5.91377,-0.0730423,81.9168 +4,4.49918,22.8528,6.4235,22.2737,0.193169,0.981166,0.275788,0.956302,-0.826745,-0.0858824,85.2916 +5,-1.54991,21.4849,0.327296,19.7631,-0.0719522,0.997408,0.0151943,0.917475,-9.53987,-0.0698778,81.6785 +6,-10.215,16.7447,-9.43817,15.3233,-0.520787,0.853686,-0.48118,0.78122,-8.22583,0.00732842,85.7358 +7,-17.9011,11.6016,-17.8302,9.70021,-0.839174,0.543863,-0.835848,0.454728,-5.22859,0.0722652,84.9754 +8,-24.0121,2.95328,-25.6462,-0.439301,-0.992521,0.122071,-1.06006,-0.0181582,3.88881,0.150712,72.8266 +9,-15.6784,-2.61717,-16.5964,-4.97434,-0.986352,-0.16465,-1.04411,-0.312943,8.55747,0.134176,81.8404 +10,-19.7479,-12.0004,-21.0779,-14.0434,-0.854584,-0.519313,-0.91214,-0.607722,9.69735,0.041533,82.0481 +11,-12.8522,-18.9505,-14.4627,-19.9885,-0.561291,-0.827618,-0.631625,-0.87295,7.6767,-0.0332958,85.8973 +12,-3.73426,-20.7558,-5.06453,-20.7655,-0.177071,-0.984198,-0.24015,-0.984656,1.27551,-0.0617776,90.7988 +13,1.9222,-15.8157,1.9317,-15.5901,0.12065,-0.992695,0.121246,-0.978535,-1.37717,0.00334723,91.2131 +14,12.6319,-18.7554,13.1674,-17.2585,0.558623,-0.829422,0.582304,-0.763226,-4.1883,0.0564666,86.4487 +15,12.1191,-8.33928,13.7307,-8.1159,0.823807,-0.56687,0.93336,-0.551686,8.26541,0.0734899,81.0217 +16,22.5965,-3.86726,23.3155,-1.51365,0.985669,-0.168691,1.01703,-0.0660258,1.07311,0.106812,79.2261 diff --git a/tests/golden/bundles/external_power/metrics.json b/tests/golden/bundles/external_power/metrics.json new file mode 100644 index 0000000..ee37a70 --- /dev/null +++ b/tests/golden/bundles/external_power/metrics.json @@ -0,0 +1,74 @@ +{ + "name": "dc-strip", + "manufacturer": "", + "model": "", + "notes": "powered externally", + "instrument": "HPCS6500", + "measured_at": "2026-07-09T16:22:57+07:00", + "instrument_date": "2026-02-05", + "instrument_time": "17:57:56", + "readings_averaged": 1, + "tm30": { + "Rf": 82.1, + "Rg": 109.9 + }, + "cri": { + "Ra": 83.53800201416016, + "R1": 81.74681854248047, + "R2": 89.89591979980469, + "R3": 94.66126251220703, + "R4": 81.88838958740234, + "R5": 81.9393081665039, + "R6": 84.4315185546875, + "R7": 86.51227569580078, + "R8": 67.2285385131836, + "R9": 12.525043487548828, + "R10": 75.23241424560547, + "R11": 80.69010925292969, + "R12": 53.97742462158203, + "R13": 84.02236938476562, + "R14": 97.37865447998047, + "R15": 76.29852294921875 + }, + "photometric": { + "Phi_lm": 182.61920166015625, + "eta_lm_W": 0.0, + "CCT_K": 4936.84375, + "Duv": 0.002135422546416521, + "SDCM": 1.5234547853469849, + "TLCI": 71.05938720703125 + }, + "chromaticity": { + "x": 0.3473931849002838, + "y": 0.35774698853492737, + "u": 0.21059946715831757, + "v": 0.32531434297561646, + "u_prime": 0.21059946715831757, + "v_prime": 0.4879715144634247, + "CIE_X": 259.6396484375, + "CIE_Y": 267.3780212402344, + "CIE_Z": 220.3765106201172 + }, + "radiometric": { + "Phi_e_mW": 558.6363525390625, + "Phi_euv_mW": 0.0, + "Phi_eb_mW": 152.54922485351562, + "Phi_ey_mW": 257.9691162109375, + "Phi_er_mW": 144.27931213378906, + "Phi_efr_mW": 5.738129138946533, + "Phi_eir_mW": 0.0, + "Phi_e_total": 560.5353393554688 + }, + "electrical": { + "Voltage_V": 0.0, + "Current_A": 0.0, + "Power_W": 0.0, + "Freq_Hz": 0.0, + "PF": 0.0 + }, + "sensor": { + "PeakSignal": 55124.0, + "DarkSignal": 2518.0, + "Compensate": 2834.0 + } +} \ No newline at end of file diff --git a/tests/golden/bundles/external_power/spd.csv b/tests/golden/bundles/external_power/spd.csv new file mode 100644 index 0000000..dd4815c --- /dev/null +++ b/tests/golden/bundles/external_power/spd.csv @@ -0,0 +1,351 @@ +wavelength_nm,value +380.00,0.0127516 +381.92,0.0198729 +383.84,0.0280456 +385.76,0.0372354 +387.68,0.0458637 +389.60,0.0555703 +391.52,0.0694203 +393.44,0.0877175 +395.36,0.10759 +397.28,0.130742 +399.20,0.156692 +401.12,0.188518 +403.04,0.225401 +404.96,0.266486 +406.88,0.311904 +408.80,0.361827 +410.72,0.418749 +412.64,0.483755 +414.56,0.557749 +416.48,0.642327 +418.40,0.736962 +420.32,0.842222 +422.23,0.959372 +424.15,1.08748 +426.07,1.22694 +427.99,1.38257 +429.91,1.55662 +431.83,1.75592 +433.75,1.98427 +435.67,2.24307 +437.59,2.56713 +439.51,2.92726 +441.43,3.2811 +443.35,3.65163 +445.27,4.02356 +447.19,4.3754 +449.11,4.68466 +451.03,4.92422 +452.95,5.07375 +454.87,5.11863 +456.79,5.05461 +458.71,4.88937 +460.63,4.63875 +462.55,4.32859 +464.47,3.98765 +466.39,3.64831 +468.31,3.33287 +470.23,3.05645 +472.15,2.82354 +474.07,2.63151 +475.99,2.47483 +477.91,2.34741 +479.83,2.24 +481.75,2.14338 +483.67,2.05061 +485.59,1.95662 +487.51,1.8595 +489.43,1.7598 +491.35,1.65877 +493.27,1.55951 +495.19,1.46615 +497.11,1.38368 +499.03,1.31492 +500.95,1.26071 +502.87,1.22134 +504.79,1.19592 +506.70,1.18122 +508.62,1.17779 +510.54,1.18258 +512.46,1.19369 +514.38,1.20931 +516.30,1.22792 +518.22,1.24908 +520.14,1.27239 +522.06,1.29921 +523.98,1.32894 +525.90,1.3587 +527.82,1.39036 +529.74,1.42475 +531.66,1.46217 +533.58,1.5025 +535.50,1.54596 +537.42,1.59038 +539.34,1.63591 +541.26,1.68198 +543.18,1.72764 +545.10,1.77328 +547.02,1.81797 +548.94,1.86176 +550.86,1.9039 +552.78,1.94394 +554.70,1.98124 +556.62,2.0167 +558.54,2.05074 +560.46,2.08357 +562.38,2.11449 +564.30,2.14278 +566.22,2.16894 +568.14,2.19369 +570.06,2.21677 +571.98,2.23732 +573.90,2.25624 +575.82,2.27366 +577.74,2.29117 +579.66,2.30806 +581.58,2.32423 +583.50,2.33864 +585.42,2.35112 +587.34,2.36317 +589.26,2.37417 +591.17,2.38517 +593.09,2.39768 +595.01,2.41045 +596.93,2.42181 +598.85,2.43301 +600.77,2.44349 +602.69,2.45349 +604.61,2.46461 +606.53,2.47648 +608.45,2.48869 +610.37,2.50104 +612.29,2.51299 +614.21,2.52617 +616.13,2.53985 +618.05,2.5535 +619.97,2.56653 +621.89,2.57811 +623.81,2.58981 +625.73,2.60193 +627.65,2.61388 +629.57,2.6256 +631.49,2.63668 +633.41,2.6478 +635.33,2.65996 +637.25,2.67304 +639.17,2.68592 +641.09,2.69685 +643.01,2.70641 +644.93,2.71465 +646.85,2.72281 +648.77,2.7312 +650.69,2.7388 +652.61,2.74545 +654.53,2.75114 +656.45,2.75604 +658.37,2.76051 +660.29,2.76554 +662.21,2.77136 +664.13,2.77754 +666.05,2.78302 +667.97,2.78749 +669.89,2.7914 +671.81,2.79575 +673.72,2.80097 +675.64,2.80645 +677.56,2.81169 +679.48,2.81677 +681.40,2.82234 +683.32,2.83039 +685.24,2.83891 +687.16,2.84523 +689.08,2.85039 +691.00,2.85423 +692.92,2.85698 +694.84,2.85957 +696.76,2.86154 +698.68,2.86338 +700.60,2.8655 +702.52,2.86739 +704.44,2.86921 +706.36,2.87048 +708.28,2.87029 +710.20,2.86925 +712.12,2.86762 +714.04,2.86576 +715.96,2.8641 +717.88,2.86255 +719.80,2.85972 +721.72,2.85585 +723.64,2.85035 +725.56,2.84321 +727.48,2.83524 +729.40,2.82621 +731.32,2.81981 +733.24,2.81334 +735.16,2.80323 +737.08,2.79262 +739.00,2.78091 +740.92,2.76763 +742.84,2.75346 +744.76,2.7383 +746.68,2.72258 +748.60,2.70553 +750.52,2.68694 +752.44,2.66699 +754.36,2.64509 +756.28,2.62182 +758.19,2.59794 +760.11,2.57342 +762.03,2.54894 +763.95,2.52412 +765.87,2.49834 +767.79,2.47207 +769.71,2.45007 +771.63,2.42686 +773.55,2.39592 +775.47,2.363 +777.39,2.32998 +779.31,2.2978 +781.23,2.26722 +783.15,2.23668 +785.07,2.20501 +786.99,2.17199 +788.91,2.13793 +790.83,2.10306 +792.75,2.06789 +794.67,2.03309 +796.59,1.99925 +798.51,1.96579 +800.43,1.93148 +802.35,1.89608 +804.27,1.8651 +806.19,1.83338 +808.11,1.79629 +810.03,1.75975 +811.95,1.72458 +813.87,1.69014 +815.79,1.65543 +817.71,1.61992 +819.63,1.58289 +821.55,1.5452 +823.47,1.50805 +825.39,1.47259 +827.31,1.43832 +829.23,1.40479 +831.15,1.37059 +833.07,1.34079 +834.99,1.31092 +836.91,1.27587 +838.83,1.24079 +840.74,1.20603 +842.66,1.17184 +844.58,1.13899 +846.50,1.10735 +848.42,1.07693 +850.34,1.04731 +852.26,1.01788 +854.18,0.98953 +856.10,0.961995 +858.02,0.934597 +859.94,0.91109 +861.86,0.887674 +863.78,0.86015 +865.70,0.833833 +867.62,0.8094 +869.54,0.785552 +871.46,0.762468 +873.38,0.739331 +875.30,0.716612 +877.22,0.694622 +879.14,0.673412 +881.06,0.653047 +882.98,0.632791 +884.90,0.615673 +886.82,0.598679 +888.74,0.57915 +890.66,0.559961 +892.58,0.540537 +894.50,0.520535 +896.42,0.500454 +898.34,0.481064 +900.26,0.463466 +902.18,0.447636 +904.10,0.432509 +906.02,0.417203 +907.94,0.401882 +909.86,0.388718 +911.78,0.376504 +913.70,0.36322 +915.62,0.35017 +917.54,0.336774 +919.46,0.322679 +921.38,0.308847 +923.30,0.295478 +925.21,0.283027 +927.13,0.271487 +929.05,0.260827 +930.97,0.252124 +932.89,0.243437 +934.81,0.233065 +936.73,0.222627 +938.65,0.212282 +940.57,0.202949 +942.49,0.194291 +944.41,0.186002 +946.33,0.178649 +948.25,0.17138 +950.17,0.165025 +952.09,0.158829 +954.01,0.153046 +955.93,0.147216 +957.85,0.139798 +959.77,0.132409 +961.69,0.125687 +963.61,0.11935 +965.53,0.113866 +967.45,0.109203 +969.37,0.104639 +971.29,0.100141 +973.21,0.095685 +975.13,0.0909515 +977.05,0.0862067 +978.97,0.0823861 +980.89,0.0786927 +982.81,0.0746361 +984.73,0.0705994 +986.65,0.0668975 +988.57,0.0642885 +990.49,0.0623986 +992.41,0.0605949 +994.33,0.058452 +996.25,0.0554474 +998.17,0.0525455 +1000.09,0.0499588 +1002.01,0.0474978 +1003.93,0.0451222 +1005.85,0.0427836 +1007.77,0.040732 +1009.68,0.0395093 +1011.60,0.0388028 +1013.52,0.0379491 +1015.44,0.0367954 +1017.36,0.0348648 +1019.28,0.0330665 +1021.20,0.0313772 +1023.12,0.0298331 +1025.04,0.0286528 +1026.96,0.0268847 +1028.88,0.024801 +1030.80,0.0227592 +1032.72,0.0206606 +1034.64,0.0185722 +1036.56,0.0172613 +1038.48,0.0168033 +1040.40,0.0161983 +1042.32,0.0150743 +1044.24,0.013724 +1046.16,0.012221 +1048.08,0.0112937 +1050.00,0.0107075 diff --git a/tests/golden/bundles/external_power/tm30.csv b/tests/golden/bundles/external_power/tm30.csv new file mode 100644 index 0000000..b02b4fa --- /dev/null +++ b/tests/golden/bundles/external_power/tm30.csv @@ -0,0 +1,17 @@ +bin,ref_a,ref_b,test_a,test_b,ref_a_norm,ref_b_norm,test_a_norm,test_b_norm,Rcs_pct,Rhs,Rf_h +1,24.194,5.30758,25.3877,6.89524,0.976772,0.21428,1.02497,0.278378,5.97734,0.0534641,78.0536 +2,18.8368,12.1186,18.7172,13.7904,0.840992,0.541048,0.835654,0.615689,3.70297,0.065027,78.9914 +3,13.7918,20.6633,13.3499,22.5585,0.555152,0.831749,0.537366,0.908034,5.35474,0.0571707,79.3008 +4,4.00106,22.1466,2.64982,23.2262,0.177784,0.984069,0.117743,1.03204,3.53358,0.0682465,86.4029 +5,-1.7494,19.9855,-2.77389,20.545,-0.0871999,0.996191,-0.138266,1.02408,3.73111,0.0446452,87.6302 +6,-10.1887,17.3743,-10.838,17.7509,-0.505861,0.862615,-0.538097,0.881312,3.34557,0.0164162,90.2709 +7,-17.7969,12.2543,-18.4508,11.5209,-0.823633,0.567123,-0.853896,0.533181,0.630543,0.0450353,86.2201 +8,-24.2144,2.21301,-25.5951,0.165895,-0.99585,0.0910129,-1.05263,0.00682266,3.92658,0.0936501,78.5718 +9,-15.5974,-3.15957,-15.625,-4.89775,-0.980093,-0.198538,-0.981828,-0.30776,2.301,0.106785,84.4575 +10,-19.953,-11.5419,-19.1744,-13.9822,-0.865611,-0.500716,-0.831835,-0.606582,3.07318,0.10679,77.2816 +11,-13.1113,-19.0908,-11.439,-21.3903,-0.56613,-0.824316,-0.493921,-0.923604,4.2438,0.115201,79.1803 +12,-3.41035,-20.7596,-0.905198,-21.7942,-0.162105,-0.986773,-0.0430271,-1.03595,2.50039,0.126385,81.5547 +13,2.34978,-15.6965,5.13967,-16.0504,0.148051,-0.98898,0.323832,-1.01128,5.61605,0.168053,80.7737 +14,13.1602,-18.321,16.2522,-17.6607,0.583402,-0.812183,0.720469,-0.782909,5.18091,0.130231,77.8198 +15,12.769,-8.09612,15.5862,-8.15662,0.844546,-0.535482,1.03088,-0.539484,15.7154,0.100194,78.1031 +16,22.8351,-3.34293,23.9488,-1.92221,0.989454,-0.14485,1.03771,-0.08329,3.5317,0.0697912,81.5972 diff --git a/tests/golden/bundles/harmonics_single/metrics.json b/tests/golden/bundles/harmonics_single/metrics.json new file mode 100644 index 0000000..da2122c --- /dev/null +++ b/tests/golden/bundles/harmonics_single/metrics.json @@ -0,0 +1,85 @@ +{ + "name": "L0007", + "type": "halogen", + "dimmable": true, + "manufacturer": "", + "model": "", + "notes": "", + "instrument": "HPCS6500", + "measured_at": "2026-07-09T16:22:57+07:00", + "instrument_date": "2026-02-04", + "instrument_time": "16:29:39", + "readings_averaged": 1, + "tm30": { + "Rf": 82.8, + "Rg": 102.6 + }, + "cri": { + "Ra": 83.03077697753906, + "R1": 82.11673736572266, + "R2": 93.9566421508789, + "R3": 93.32406616210938, + "R4": 76.64042663574219, + "R5": 81.5961685180664, + "R6": 89.55091094970703, + "R7": 83.03118896484375, + "R8": 64.03005981445312, + "R9": 4.829061031341553, + "R10": 84.0609130859375, + "R11": 76.2067642211914, + "R12": 60.158180236816406, + "R13": 86.46263885498047, + "R14": 96.80621337890625, + "R15": 75.96227264404297 + }, + "supply": { + "ac_voltage": 230.0, + "ac_frequency": 50.0, + "dc_voltage": 24.0, + "dc_current": 5.0, + "mode": "AC" + }, + "photometric": { + "Phi_lm": 479.5904235839844, + "eta_lm_W": 57.03839111328125, + "CCT_K": 5661.3740234375, + "Duv": 0.005495334509760141, + "SDCM": 4.661009311676025, + "TLCI": 67.88436889648438 + }, + "chromaticity": { + "x": 0.3286939859390259, + "y": 0.34864285588264465, + "u": 0.20145727694034576, + "v": 0.32052600383758545, + "u_prime": 0.20145727694034576, + "v_prime": 0.4807890057563782, + "CIE_X": 662.0042114257812, + "CIE_Y": 702.18212890625, + "CIE_Z": 649.8577880859375 + }, + "radiometric": { + "Phi_e_mW": 1492.0255126953125, + "Phi_euv_mW": 0.0, + "Phi_eb_mW": 470.2662658691406, + "Phi_ey_mW": 679.6720581054688, + "Phi_er_mW": 330.6041564941406, + "Phi_efr_mW": 11.205649375915527, + "Phi_eir_mW": 0.0, + "Phi_e_total": 1491.7479248046875 + }, + "electrical": { + "Voltage_V": 230.289794921875, + "Current_A": 0.06533221900463104, + "Power_W": 8.404895782470703, + "Freq_Hz": 50.02182388305664, + "PF": 0.5585951805114746, + "UThd": 0.8112547993659973, + "AThd": 109.011474609375 + }, + "sensor": { + "PeakSignal": 53165.0, + "DarkSignal": 2310.0, + "Compensate": 2834.0 + } +} \ No newline at end of file diff --git a/tests/golden/bundles/harmonics_single/spd.csv b/tests/golden/bundles/harmonics_single/spd.csv new file mode 100644 index 0000000..8f7738a --- /dev/null +++ b/tests/golden/bundles/harmonics_single/spd.csv @@ -0,0 +1,351 @@ +wavelength_nm,value +380.00,0.00012437 +381.92,0.00325128 +383.84,0.0121374 +385.76,0.0277415 +387.68,0.0499055 +389.60,0.0770335 +391.52,0.113006 +393.44,0.155736 +395.36,0.200766 +397.28,0.251532 +399.20,0.309992 +401.12,0.378357 +403.04,0.457739 +404.96,0.549033 +406.88,0.651834 +408.80,0.766103 +410.72,0.89645 +412.64,1.04439 +414.56,1.21227 +416.48,1.40185 +418.40,1.61142 +420.32,1.84377 +422.23,2.09783 +424.15,2.37553 +426.07,2.67843 +427.99,3.00636 +429.91,3.36508 +431.83,3.7554 +433.75,4.17804 +435.67,4.63919 +437.59,5.19895 +439.51,5.81118 +441.43,6.42285 +443.35,7.09515 +445.27,7.82478 +447.19,8.60823 +449.11,9.43156 +451.03,10.2756 +452.95,11.1145 +454.87,11.9149 +456.79,12.6327 +458.71,13.223 +460.63,13.6467 +462.55,13.8619 +464.47,13.8602 +466.39,13.656 +468.31,13.276 +470.23,12.7626 +472.15,12.1576 +474.07,11.505 +475.99,10.8536 +477.91,10.2334 +479.83,9.66753 +481.75,9.16456 +483.67,8.72063 +485.59,8.32902 +487.51,7.97934 +489.43,7.66042 +491.35,7.36116 +493.27,7.07295 +495.19,6.78887 +497.11,6.50904 +499.03,6.23842 +500.95,5.98105 +502.87,5.73951 +504.79,5.5147 +506.70,5.30024 +508.62,5.11031 +510.54,4.94715 +512.46,4.81164 +514.38,4.70412 +516.30,4.6232 +518.22,4.56477 +520.14,4.52716 +522.06,4.49757 +523.98,4.48574 +525.90,4.49328 +527.82,4.50975 +529.74,4.53441 +531.66,4.56592 +533.58,4.60312 +535.50,4.64601 +537.42,4.69397 +539.34,4.74984 +541.26,4.8129 +543.18,4.88137 +545.10,4.95458 +547.02,5.03094 +548.94,5.11027 +550.86,5.19323 +552.78,5.27894 +554.70,5.36574 +556.62,5.45106 +558.54,5.53401 +560.46,5.61319 +562.38,5.69013 +564.30,5.76408 +566.22,5.83525 +568.14,5.90377 +570.06,5.96844 +571.98,6.02758 +573.90,6.08097 +575.82,6.12977 +577.74,6.17567 +579.66,6.21891 +581.58,6.25922 +583.50,6.29479 +585.42,6.32698 +587.34,6.35762 +589.26,6.38562 +591.17,6.41223 +593.09,6.44115 +595.01,6.46769 +596.93,6.48953 +598.85,6.50949 +600.77,6.52767 +602.69,6.54609 +604.61,6.56516 +606.53,6.58662 +608.45,6.61081 +610.37,6.63582 +612.29,6.66216 +614.21,6.68962 +616.13,6.71879 +618.05,6.74956 +619.97,6.77916 +621.89,6.80681 +623.81,6.83487 +625.73,6.86371 +627.65,6.89415 +629.57,6.92539 +631.49,6.95379 +633.41,6.98066 +635.33,7.00707 +637.25,7.03273 +639.17,7.05778 +641.09,7.08091 +643.01,7.10164 +644.93,7.12056 +646.85,7.13904 +648.77,7.15693 +650.69,7.17338 +652.61,7.18816 +654.53,7.20251 +656.45,7.21699 +658.37,7.23194 +660.29,7.24629 +662.21,7.25935 +664.13,7.272 +666.05,7.28479 +667.97,7.29768 +669.89,7.31153 +671.81,7.32651 +673.72,7.34241 +675.64,7.35813 +677.56,7.3732 +679.48,7.38972 +681.40,7.41038 +683.32,7.4381 +685.24,7.46643 +687.16,7.4891 +689.08,7.50523 +691.00,7.51547 +692.92,7.52156 +694.84,7.52337 +696.76,7.52165 +698.68,7.51663 +700.60,7.50879 +702.52,7.49846 +704.44,7.48704 +706.36,7.47491 +708.28,7.46264 +710.20,7.44957 +712.12,7.43222 +714.04,7.40958 +715.96,7.38246 +717.88,7.35219 +719.80,7.32075 +721.72,7.28764 +723.64,7.25152 +725.56,7.21202 +727.48,7.16895 +729.40,7.12555 +731.32,7.09348 +733.24,7.06023 +735.16,7.0133 +737.08,6.96061 +739.00,6.90334 +740.92,6.84409 +742.84,6.78359 +744.76,6.72074 +746.68,6.65452 +748.60,6.58609 +750.52,6.51548 +752.44,6.44292 +754.36,6.36742 +756.28,6.28835 +758.19,6.20696 +760.11,6.12408 +762.03,6.04174 +763.95,5.96018 +765.87,5.87764 +767.79,5.79497 +769.71,5.72498 +771.63,5.65348 +773.55,5.56674 +775.47,5.47926 +777.39,5.39248 +779.31,5.30597 +781.23,5.21974 +783.15,5.13292 +785.07,5.04519 +786.99,4.95836 +788.91,4.87262 +790.83,4.78664 +792.75,4.70125 +794.67,4.61637 +796.59,4.53143 +798.51,4.44683 +800.43,4.36164 +802.35,4.2745 +804.27,4.20141 +806.19,4.12886 +808.11,4.04329 +810.03,3.95809 +811.95,3.87164 +813.87,3.78356 +815.79,3.69546 +817.71,3.60807 +819.63,3.52274 +821.55,3.43901 +823.47,3.35653 +825.39,3.27403 +827.31,3.19068 +829.23,3.10716 +831.15,3.02401 +833.07,2.95399 +834.99,2.8852 +836.91,2.80614 +838.83,2.728 +840.74,2.6514 +842.66,2.57594 +844.58,2.50181 +846.50,2.42922 +848.42,2.35736 +850.34,2.28699 +852.26,2.21866 +854.18,2.15275 +856.10,2.08984 +858.02,2.029 +859.94,1.97794 +861.86,1.92754 +863.78,1.86968 +865.70,1.81322 +867.62,1.75827 +869.54,1.70454 +871.46,1.65163 +873.38,1.5998 +875.30,1.5483 +877.22,1.49811 +879.14,1.44982 +881.06,1.40312 +882.98,1.35849 +884.90,1.3205 +886.82,1.28288 +888.74,1.24007 +890.66,1.19758 +892.58,1.15609 +894.50,1.11548 +896.42,1.07556 +898.34,1.03672 +900.26,0.998743 +902.18,0.961315 +904.10,0.924942 +906.02,0.889715 +907.94,0.855423 +909.86,0.826954 +911.78,0.798934 +913.70,0.767269 +915.62,0.736874 +917.54,0.707128 +919.46,0.678713 +921.38,0.651975 +923.30,0.626551 +925.21,0.602139 +927.13,0.57811 +929.05,0.553469 +930.97,0.532404 +932.89,0.512057 +934.81,0.489179 +936.73,0.467825 +938.65,0.447807 +940.57,0.429395 +942.49,0.412061 +944.41,0.395608 +946.33,0.379753 +948.25,0.364275 +950.17,0.349777 +952.09,0.334972 +954.01,0.321767 +955.93,0.308504 +957.85,0.292831 +959.77,0.276846 +961.69,0.261265 +963.61,0.246135 +965.53,0.231452 +967.45,0.217818 +969.37,0.205109 +971.29,0.193366 +973.21,0.18465 +975.13,0.176894 +977.05,0.168529 +978.97,0.160908 +980.89,0.154111 +982.81,0.147506 +984.73,0.140508 +986.65,0.133633 +988.57,0.126815 +990.49,0.12034 +992.41,0.11526 +994.33,0.110217 +996.25,0.104319 +998.17,0.0986741 +1000.09,0.0931682 +1002.01,0.0872736 +1003.93,0.0809993 +1005.85,0.07483 +1007.77,0.069364 +1009.68,0.064749 +1011.60,0.0614614 +1013.52,0.0582413 +1015.44,0.0541198 +1017.36,0.0501878 +1019.28,0.0461407 +1021.20,0.0425238 +1023.12,0.0389367 +1025.04,0.0348234 +1026.96,0.0307412 +1028.88,0.02715 +1030.80,0.0247482 +1032.72,0.0224838 +1034.64,0.0198648 +1036.56,0.0171769 +1038.48,0.0140465 +1040.40,0.0110774 +1042.32,0.00785347 +1044.24,0.00472714 +1046.16,0.00212014 +1048.08,0.000720481 +1050.00,8.16882e-05 diff --git a/tests/golden/bundles/harmonics_single/tm30.csv b/tests/golden/bundles/harmonics_single/tm30.csv new file mode 100644 index 0000000..f0b82df --- /dev/null +++ b/tests/golden/bundles/harmonics_single/tm30.csv @@ -0,0 +1,17 @@ +bin,ref_a,ref_b,test_a,test_b,ref_a_norm,ref_b_norm,test_a_norm,test_b_norm,Rcs_pct,Rhs,Rf_h +1,23.8322,4.89044,25.5143,6.78835,0.979588,0.201015,1.04873,0.279026,8.30334,0.0630229,76.4441 +2,18.6309,11.8982,19.8479,13.1157,0.842797,0.538232,0.897851,0.593308,7.63743,0.015208,82.0393 +3,13.4241,20.707,15.7508,20.9107,0.543979,0.839099,0.638262,0.847352,5.92434,-0.0738084,81.8363 +4,4.49861,22.8543,6.44068,22.2658,0.193133,0.981173,0.276509,0.955907,-0.851417,-0.0867033,85.1735 +5,-1.55246,21.4895,0.339439,19.7562,-0.0720553,0.997401,0.0157546,0.916955,-9.60308,-0.0704284,81.5541 +6,-10.2156,16.75,-9.43359,15.3207,-0.520687,0.853748,-0.480829,0.780893,-8.27205,0.00733577,85.6792 +7,-17.901,11.6088,-17.832,9.70121,-0.839017,0.544105,-0.835783,0.454695,-5.23628,0.0725445,84.9471 +8,-24.0094,2.96356,-25.6481,-0.43544,-0.992468,0.122504,-1.0602,-0.0179996,3.90235,0.151018,72.7844 +9,-15.6797,-2.60957,-16.6033,-4.96949,-0.986432,-0.164172,-1.04454,-0.312638,8.59555,0.134277,81.8143 +10,-19.7518,-11.9916,-21.0921,-14.0327,-0.854798,-0.518961,-0.912802,-0.607292,9.73027,0.0412196,82.0354 +11,-12.8556,-18.9464,-14.4795,-19.9788,-0.561476,-0.827493,-0.632401,-0.872584,7.6896,-0.033921,85.838 +12,-3.73856,-20.7556,-5.08464,-20.7591,-0.17727,-0.984162,-0.241097,-0.984329,1.26154,-0.0625677,90.6907 +13,1.91647,-15.8171,1.91568,-15.5877,0.120285,-0.992739,0.120235,-0.978341,-1.41314,0.00276032,91.1775 +14,12.6248,-18.7612,13.1529,-17.2582,0.558288,-0.829647,0.581642,-0.763184,-4.22874,0.0563433,86.4173 +15,12.1099,-8.34251,13.7213,-8.11653,0.823504,-0.56731,0.93308,-0.551943,8.25711,0.0736542,80.9915 +16,22.5933,-3.87457,23.3147,-1.51543,0.985612,-0.169025,1.01708,-0.0661093,1.07904,0.107078,79.1926 diff --git a/tests/golden/bundles/station_full/metrics.json b/tests/golden/bundles/station_full/metrics.json new file mode 100644 index 0000000..bc5f00a --- /dev/null +++ b/tests/golden/bundles/station_full/metrics.json @@ -0,0 +1,90 @@ +{ + "name": "L0042", + "ean": "8718696844984", + "type": "led", + "dimmable": false, + "variant": "cool white", + "rated": { + "Phi_lm": 1050, + "Power_W": 9.5, + "lifetime_h": 15000 + }, + "manufacturer": "Philips", + "model": "MyCare 9.5W Caf\u00e9 \u00fc \u0e44\u0e1f", + "notes": "box says \"warm\"\tok", + "instrument": "HPCS6500", + "measured_at": "2026-07-09T16:22:57+07:00", + "instrument_date": "2026-02-04", + "instrument_time": "16:04:22", + "readings_averaged": 3, + "tm30": { + "Rf": 82.8, + "Rg": 102.5 + }, + "cri": { + "Ra": 83.03523508707683, + "R1": 82.2739028930664, + "R2": 94.10517883300781, + "R3": 93.21258036295573, + "R4": 76.49050394694011, + "R5": 81.4281005859375, + "R6": 89.39029439290364, + "R7": 83.1925786336263, + "R8": 64.188720703125, + "R9": 4.96781063079834, + "R10": 84.26158396402995, + "R11": 76.07496897379558, + "R12": 60.12171173095703, + "R13": 86.65864817301433, + "R14": 96.72717539469402, + "R15": 76.09520975748698 + }, + "supply": { + "ac_voltage": 230.0, + "ac_frequency": 50.0, + "dc_voltage": 24.0, + "dc_current": 5.0, + "mode": "AC" + }, + "photometric": { + "Phi_lm": 479.6871032714844, + "eta_lm_W": 57.07930119832357, + "CCT_K": 5654.930013020833, + "Duv": 0.00552134479706486, + "SDCM": 4.698563575744629, + "TLCI": 67.9216817220052 + }, + "chromaticity": { + "x": 0.32883302370707196, + "y": 0.3488210042317708, + "u": 0.20148508747418722, + "v": 0.32059840361277264, + "u_prime": 0.20148508747418722, + "v_prime": 0.4808976153532664, + "CIE_X": 662.0794474283854, + "CIE_Y": 702.3236897786459, + "CIE_Z": 649.0183308919271 + }, + "radiometric": { + "Phi_e_mW": 1491.6316731770833, + "Phi_euv_mW": 0.0, + "Phi_eb_mW": 469.9439392089844, + "Phi_ey_mW": 679.7555135091146, + "Phi_er_mW": 331.15210978190106, + "Phi_efr_mW": 11.503878593444824, + "Phi_eir_mW": 0.0, + "Phi_e_total": 1492.3549397786458 + }, + "electrical": { + "Voltage_V": 230.29657999674478, + "Current_A": 0.06530716021855672, + "Power_W": 8.4038724899292, + "Freq_Hz": 50.021812438964844, + "PF": 0.5587416887283325 + }, + "sensor": { + "PeakSignal": 53061.0, + "DarkSignal": 2236.6666666666665, + "Compensate": 2834.0 + } +} \ No newline at end of file diff --git a/tests/golden/bundles/station_full/spd.csv b/tests/golden/bundles/station_full/spd.csv new file mode 100644 index 0000000..f0b866f --- /dev/null +++ b/tests/golden/bundles/station_full/spd.csv @@ -0,0 +1,351 @@ +wavelength_nm,value +380.00,0.000365606 +381.92,0.0052701 +383.84,0.0174624 +385.76,0.0369744 +387.68,0.0630038 +389.60,0.0924528 +391.52,0.129915 +393.44,0.17215 +395.36,0.215405 +397.28,0.264549 +399.20,0.321514 +401.12,0.388303 +403.04,0.466088 +404.96,0.555115 +406.88,0.656321 +408.80,0.771487 +410.72,0.903509 +412.64,1.05381 +414.56,1.22285 +416.48,1.41098 +418.40,1.61749 +420.32,1.84539 +422.23,2.09653 +424.15,2.373 +426.07,2.67501 +427.99,3.0024 +429.91,3.36028 +431.83,3.75018 +433.75,4.17195 +435.67,4.63166 +437.59,5.18756 +439.51,5.79644 +441.43,6.40441 +443.35,7.07131 +445.27,7.79616 +447.19,8.57664 +449.11,9.3994 +451.03,10.2441 +452.95,11.0834 +454.87,11.8836 +456.79,12.603 +458.71,13.1972 +460.63,13.6254 +462.55,13.8458 +464.47,13.8481 +466.39,13.6468 +468.31,13.2686 +470.23,12.7571 +472.15,12.1536 +474.07,11.5036 +475.99,10.8538 +477.91,10.2349 +479.83,9.66925 +481.75,9.16429 +483.67,8.7167 +485.59,8.32288 +487.51,7.97234 +489.43,7.65421 +491.35,7.35693 +493.27,7.06942 +495.19,6.78593 +497.11,6.50668 +499.03,6.23555 +500.95,5.9772 +502.87,5.73427 +504.79,5.50867 +506.70,5.29416 +508.62,5.10508 +510.54,4.94335 +512.46,4.80941 +514.38,4.70291 +516.30,4.62301 +518.22,4.56511 +520.14,4.52752 +522.06,4.4981 +523.98,4.48587 +525.90,4.49319 +527.82,4.50912 +529.74,4.53248 +531.66,4.56252 +533.58,4.59904 +535.50,4.64247 +537.42,4.69146 +539.34,4.747 +541.26,4.80906 +543.18,4.87636 +545.10,4.9496 +547.02,5.02659 +548.94,5.10692 +550.86,5.18972 +552.78,5.27489 +554.70,5.36223 +556.62,5.44919 +558.54,5.53354 +560.46,5.61387 +562.38,5.69069 +564.30,5.76287 +566.22,5.83302 +568.14,5.90044 +570.06,5.96431 +571.98,6.02501 +573.90,6.08041 +575.82,6.13156 +577.74,6.17863 +579.66,6.22191 +581.58,6.26121 +583.50,6.29569 +585.42,6.32684 +587.34,6.35555 +589.26,6.38227 +591.17,6.4077 +593.09,6.43663 +595.01,6.46485 +596.93,6.48889 +598.85,6.51145 +600.77,6.53127 +602.69,6.54893 +604.61,6.56654 +606.53,6.58564 +608.45,6.60829 +610.37,6.63313 +612.29,6.65904 +614.21,6.68654 +616.13,6.71518 +618.05,6.74523 +619.97,6.77501 +621.89,6.8038 +623.81,6.83309 +625.73,6.86293 +627.65,6.89347 +629.57,6.92434 +631.49,6.95343 +633.41,6.98175 +635.33,7.00832 +637.25,7.03308 +639.17,7.05641 +641.09,7.07872 +643.01,7.1005 +644.93,7.12156 +646.85,7.1415 +648.77,7.16026 +650.69,7.17672 +652.61,7.19094 +654.53,7.20409 +656.45,7.21726 +658.37,7.23105 +660.29,7.24528 +662.21,7.25866 +664.13,7.27171 +666.05,7.28519 +667.97,7.29889 +669.89,7.31371 +671.81,7.32813 +673.72,7.34297 +675.64,7.35832 +677.56,7.37432 +679.48,7.39331 +681.40,7.41502 +683.32,7.44201 +685.24,7.46915 +687.16,7.49027 +689.08,7.50719 +691.00,7.51955 +692.92,7.5266 +694.84,7.52866 +696.76,7.52509 +698.68,7.51701 +700.60,7.5076 +702.52,7.49724 +704.44,7.4881 +706.36,7.47958 +708.28,7.46992 +710.20,7.45709 +712.12,7.43947 +714.04,7.41602 +715.96,7.38839 +717.88,7.35827 +719.80,7.32592 +721.72,7.29185 +723.64,7.2557 +725.56,7.21711 +727.48,7.17589 +729.40,7.13404 +731.32,7.10174 +733.24,7.06725 +735.16,7.01878 +737.08,6.96538 +739.00,6.90749 +740.92,6.84683 +742.84,6.78526 +744.76,6.72237 +746.68,6.65787 +748.60,6.59162 +750.52,6.52145 +752.44,6.44783 +754.36,6.37136 +756.28,6.2922 +758.19,6.21157 +760.11,6.1295 +762.03,6.04717 +763.95,5.96545 +765.87,5.88354 +767.79,5.80118 +769.71,5.73171 +771.63,5.66075 +773.55,5.57428 +775.47,5.48691 +777.39,5.39926 +779.31,5.31135 +781.23,5.22406 +783.15,5.1373 +785.07,5.05031 +786.99,4.96372 +788.91,4.87709 +790.83,4.7909 +792.75,4.70567 +794.67,4.62128 +796.59,4.53732 +798.51,4.45255 +800.43,4.36692 +802.35,4.2806 +804.27,4.2077 +806.19,4.13485 +808.11,4.04907 +810.03,3.96349 +811.95,3.87812 +813.87,3.79244 +815.79,3.70668 +817.71,3.62118 +819.63,3.53542 +821.55,3.45007 +823.47,3.36513 +825.39,3.28073 +827.31,3.19686 +829.23,3.11396 +831.15,3.03173 +833.07,2.96166 +834.99,2.89317 +836.91,2.81428 +838.83,2.73634 +840.74,2.65972 +842.66,2.58348 +844.58,2.50853 +846.50,2.43512 +848.42,2.36289 +850.34,2.29287 +852.26,2.22463 +854.18,2.1583 +856.10,2.09442 +858.02,2.03205 +859.94,1.97967 +861.86,1.92886 +863.78,1.87128 +865.70,1.8152 +867.62,1.76081 +869.54,1.70742 +871.46,1.65477 +873.38,1.6029 +875.30,1.55129 +877.22,1.50061 +879.14,1.45181 +881.06,1.40512 +882.98,1.36101 +884.90,1.3243 +886.82,1.28827 +888.74,1.24682 +890.66,1.20538 +892.58,1.16375 +894.50,1.12204 +896.42,1.08097 +898.34,1.04122 +900.26,1.00321 +902.18,0.966682 +904.10,0.931466 +906.02,0.897212 +907.94,0.863274 +909.86,0.834488 +911.78,0.806232 +913.70,0.77413 +915.62,0.743313 +917.54,0.713611 +919.46,0.684714 +921.38,0.656447 +923.30,0.629011 +925.21,0.602572 +927.13,0.577308 +929.05,0.553133 +930.97,0.532903 +932.89,0.51344 +934.81,0.491842 +936.73,0.471207 +938.65,0.451653 +940.57,0.433122 +942.49,0.41551 +944.41,0.398834 +946.33,0.382978 +948.25,0.367794 +950.17,0.352984 +952.09,0.338755 +954.01,0.326487 +955.93,0.313683 +957.85,0.298334 +959.77,0.282348 +961.69,0.266334 +963.61,0.251037 +965.53,0.236595 +967.45,0.223076 +969.37,0.211188 +971.29,0.200452 +973.21,0.192062 +975.13,0.184205 +977.05,0.175077 +978.97,0.166767 +980.89,0.159442 +982.81,0.152627 +984.73,0.145832 +986.65,0.138907 +988.57,0.131661 +990.49,0.124845 +992.41,0.119552 +994.33,0.1145 +996.25,0.108742 +998.17,0.102876 +1000.09,0.0967195 +1002.01,0.0904836 +1003.93,0.0847852 +1005.85,0.0797888 +1007.77,0.0751852 +1009.68,0.0708111 +1011.60,0.0669758 +1013.52,0.0630191 +1015.44,0.0588567 +1017.36,0.0552771 +1019.28,0.0520897 +1021.20,0.0489097 +1023.12,0.0454581 +1025.04,0.0417723 +1026.96,0.0376737 +1028.88,0.0336676 +1030.80,0.0305725 +1032.72,0.0275745 +1034.64,0.0244492 +1036.56,0.0215368 +1038.48,0.0185852 +1040.40,0.0154897 +1042.32,0.0121245 +1044.24,0.00879848 +1046.16,0.0056708 +1048.08,0.00352862 +1050.00,0.00202557 diff --git a/tests/golden/bundles/station_full/tm30.csv b/tests/golden/bundles/station_full/tm30.csv new file mode 100644 index 0000000..176faa6 --- /dev/null +++ b/tests/golden/bundles/station_full/tm30.csv @@ -0,0 +1,17 @@ +bin,ref_a,ref_b,test_a,test_b,ref_a_norm,ref_b_norm,test_a_norm,test_b_norm,Rcs_pct,Rhs,Rf_h +1,23.8357,4.89461,25.5144,6.7909,0.97956,0.20115,1.04855,0.279081,8.28657,0.0629746,76.4786 +2,18.6329,11.9004,19.8481,13.1165,0.842777,0.538263,0.897739,0.593268,7.62587,0.0151991,82.0646 +3,13.4278,20.7067,15.7532,20.9087,0.544088,0.839028,0.638313,0.847214,5.9155,-0.0737974,81.8536 +4,4.49902,22.8532,6.4428,22.2638,0.193158,0.981168,0.276612,0.955863,-0.85372,-0.0867864,85.1654 +5,-1.55064,21.4862,0.342398,19.7527,-0.0719818,0.997406,0.0158943,0.916933,-9.607,-0.0704882,81.5458 +6,-10.2152,16.7462,-9.43137,15.3167,-0.520759,0.853703,-0.4808,0.780825,-8.27966,0.00726374,85.6756 +7,-17.9011,11.6037,-17.8305,9.69668,-0.83913,0.543931,-0.835818,0.45454,-5.24169,0.072486,84.9545 +8,-24.0114,2.95619,-25.6477,-0.440784,-0.992506,0.122194,-1.06014,-0.0182197,3.89417,0.15091,72.8073 +9,-15.6788,-2.61501,-16.6028,-4.97269,-0.986375,-0.164514,-1.0445,-0.312839,8.59478,0.134135,81.8305 +10,-19.749,-11.9979,-21.092,-14.035,-0.854645,-0.519213,-0.912761,-0.607367,9.72975,0.0410105,82.054 +11,-12.8532,-18.9493,-14.4815,-19.9774,-0.561344,-0.827583,-0.632459,-0.872483,7.6843,-0.0341847,85.8291 +12,-3.73546,-20.7558,-5.08623,-20.7576,-0.177126,-0.984188,-0.241176,-0.984273,1.2579,-0.062803,90.6592 +13,1.92061,-15.8161,1.9149,-15.5855,0.120549,-0.992707,0.12019,-0.978234,-1.42652,0.00247188,91.1834 +14,12.63,-18.757,13.1517,-17.2546,0.55853,-0.829484,0.581603,-0.763042,-4.2426,0.0560974,86.4346 +15,12.1165,-8.34016,13.7212,-8.11295,0.823723,-0.566992,0.932812,-0.551545,8.21223,0.0734496,81.0338 +16,22.5956,-3.86931,23.3134,-1.5113,0.985653,-0.168785,1.01696,-0.0659251,1.06421,0.106992,79.2134 diff --git a/tests/station.rs b/tests/station.rs new file mode 100644 index 0000000..8899968 --- /dev/null +++ b/tests/station.rs @@ -0,0 +1,203 @@ +//! The station end to end: scripted answers on stdin, the simulated +//! instrument, a throwaway comparison-data repository. + +use std::io::Write; +use std::path::Path; +use std::process::{Command, Stdio}; + +fn git(dir: &Path, args: &[&str]) -> String { + let o = Command::new("git") + .arg("-C") + .arg(dir) + .args(args) + .output() + .unwrap(); + assert!( + o.status.success(), + "git {args:?}: {}", + String::from_utf8_lossy(&o.stderr) + ); + String::from_utf8_lossy(&o.stdout).to_string() +} + +/// A valid EAN-13 with the given 12 leading digits. +fn ean(d12: &str) -> String { + let sum: u32 = d12 + .chars() + .enumerate() + .map(|(i, c)| c.to_digit(10).unwrap() * if i % 2 == 1 { 3 } else { 1 }) + .sum(); + format!("{d12}{}", (10 - sum % 10) % 10) +} + +#[test] +fn station_measures_commits_and_re_measures() { + let tmp = std::env::temp_dir().join(format!("lampbench-station-{}", std::process::id())); + let _ = std::fs::remove_dir_all(&tmp); + let repo = tmp.join("comparison-data"); + std::fs::create_dir_all(repo.join("lamps")).unwrap(); + git(&repo, &["init", "-q"]); + git(&repo, &["config", "user.name", "Test"]); + git(&repo, &["config", "user.email", "test@example.com"]); + std::fs::write(repo.join("README.md"), "data\n").unwrap(); + git(&repo, &["add", "."]); + git(&repo, &["commit", "-qm", "init"]); + + // --interval 0.5 keeps the runs in different seconds, so the re-measure changes measured_at + let internal = ean("200123456789"); + let answers = [ + // lamp 1: no barcode + "", + "philips", // manufacturer -> canonical "Philips" + "Test A60", // model + "", // type: led + "y", // dimmable + "Warm White", // variant -> lower case + "", // notes + "806", + "2700", + "8.5", + "", + "", + "60", // rated: flux, CCT, W, Ra, lifetime, equivalent + "", // insert the lamp + // lamp 2: retailer-internal EAN (no online lookup) + &internal, + "", + "Shop bulb", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + // re-measure lamp 1, everything pre-filled + "L0001", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + // a bad barcode, then quit + "12345", + "q", + ] + .join("\n") + + "\n"; + + let mut child = Command::new(env!("CARGO_BIN_EXE_lampbench")) + .args([ + "station", + "--simulate", + "--settle", + "0", + "--readings", + "2", + "--interval", + "0.5", + "--no-push", + "--no-labels", + "--no-lookup", + ]) + .arg("--data-repo") + .arg(&repo) + .arg("--cache") + .arg(tmp.join("ean-cache.json")) + .env_remove("HPCS_LABEL_PRINTER") + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn() + .unwrap(); + child + .stdin + .take() + .unwrap() + .write_all(answers.as_bytes()) + .unwrap(); + let out = child.wait_with_output().unwrap(); + let text = String::from_utf8_lossy(&out.stdout); + assert!( + out.status.success(), + "{text}\n{}", + String::from_utf8_lossy(&out.stderr) + ); + assert!(text.contains("--- New lamp L0001 ---"), "{text}"); + assert!( + text.contains("Using canonical brand name: Philips") || text.contains("Manufacturer"), + "{text}" + ); + assert!( + text.contains("Lookup: ? / ? (retailer-internal barcode, not resolvable)"), + "{text}" + ); + assert!(text.contains("Re-measuring L0001"), "{text}"); + assert!(text.contains("Not a valid EAN-13/UPC-A: '12345'"), "{text}"); + assert!(text.contains("PSU off"), "{text}"); + assert!(text.trim_end().ends_with("Bye."), "{text}"); + + let m: serde_json::Value = serde_json::from_str( + &std::fs::read_to_string(repo.join("lamps/L0001/metrics.json")).unwrap(), + ) + .unwrap(); + assert_eq!(m["manufacturer"], "Philips"); + assert_eq!(m["variant"], "warm white"); + assert_eq!(m["dimmable"], true); + assert_eq!(m["type"], "led"); + assert_eq!( + m["rated"], + serde_json::json!({"Phi_lm": 806, "CCT_K": 2700, "Power_W": 8.5, "W_equiv": 60}) + ); + assert_eq!(m["readings_averaged"], 2); + assert_eq!(m["supply"]["ac_voltage"], 230.0); + let m2: serde_json::Value = serde_json::from_str( + &std::fs::read_to_string(repo.join("lamps/L0002/metrics.json")).unwrap(), + ) + .unwrap(); + assert_eq!(m2["ean"], internal.as_str()); + assert_eq!(m2["notes"], "retailer-internal barcode, brand unknown"); + assert_eq!( + std::fs::read_to_string(repo.join("lamps/L0001/spd.csv")) + .unwrap() + .lines() + .count(), + 351 + ); + assert_eq!( + std::fs::read_to_string(repo.join("lamps/L0001/tm30.csv")) + .unwrap() + .lines() + .count(), + 17 + ); + + let log = git(&repo, &["log", "--format=%s"]); + let subjects: Vec<&str> = log.lines().collect(); + assert_eq!( + subjects[0], "Re-measure lamp L0001 (Philips, Test A60, warm white)", + "{log}" + ); + assert_eq!( + subjects[1], + format!("Add lamp L0002 (Shop bulb, EAN {internal})"), + "{log}" + ); + assert_eq!( + subjects[2], "Add lamp L0001 (Philips, Test A60, warm white)", + "{log}" + ); + let _ = std::fs::remove_dir_all(&tmp); +} diff --git a/tools/make_bundles.py b/tools/make_bundles.py new file mode 100644 index 0000000..bd5d63b --- /dev/null +++ b/tools/make_bundles.py @@ -0,0 +1,65 @@ +"""Golden lamp bundles from the former lamp_export.write_bundle (Python). + +Usage: python make_bundles.py +Run it next to hpcs6500.py, lamp_export.py and tm30.py from HPCS6500-py tag +python-final (colour-science 0.4.7), e.g. + python tools/make_bundles.py HPCS6500/tests/fixtures tests/golden/bundles +Each case: readings parsed from the driver's fixture blocks, averaged, written +with a fixed measured_at. Writes //{spd.csv,tm30.csv,metrics.json} +and /cases.json describing the inputs. +""" +import datetime as _dt +import json +import sys +from pathlib import Path + +sys.path.insert(0, str(Path(__file__).parent)) +import hpcs6500 as h # noqa: E402 +import lamp_export as le # noqa: E402 + +FIX = Path(sys.argv[1]) +OUT = Path(sys.argv[2]) +OUT.mkdir(parents=True, exist_ok=True) +STAMP = "2026-07-09T16:22:57+07:00" + + +class FixedDatetime(_dt.datetime): + @classmethod + def now(cls, tz=None): + return _dt.datetime.fromisoformat(STAMP) + + +le.datetime = FixedDatetime +dev = h.HPCS6500.__new__(h.HPCS6500) + + +def reading(name): + meas = (FIX / f"{name}_meas.bin").read_bytes() + r = dev._parse_measurement(meas) + e = FIX / f"{name}_elec.bin" + if e.exists(): + r.update(dev._parse_electrical(e.read_bytes())) + return r + + +supply = {"ac_voltage": 230.0, "ac_frequency": 50.0, "dc_voltage": 24.0, "dc_current": 5.0, "mode": "AC"} +cases = [ + {"case": "export_avg5", "readings": ["r01", "r04", "r05", "r06", "r02"], + "meta": {"name": "philips-a60", "manufacturer": "Philips", "model": "A60 8W 927", "notes": ""}, "supply": None}, + {"case": "station_full", "readings": ["r05", "r06", "r04"], + "meta": {"name": "L0042", "ean": "8718696844984", "type": "led", "dimmable": False, "variant": "cool white", + "manufacturer": "Philips", "model": "MyCare 9.5W Caf\u00e9 \u00fc \u0e44\u0e1f", "notes": "box says \"warm\"\tok", + "rated": {"Phi_lm": 1050, "Power_W": 9.5, "lifetime_h": 15000}}, + "supply": supply}, + {"case": "harmonics_single", "readings": ["r02"], + "meta": {"name": "L0007", "ean": "", "type": "halogen", "dimmable": True, "variant": "", "manufacturer": "", + "model": "", "notes": "", "rated": {}}, "supply": supply}, + {"case": "external_power", "readings": ["r07"], + "meta": {"name": "dc-strip", "manufacturer": "", "model": "", "notes": "powered externally"}, "supply": None}, +] +for c in cases: + rs = [reading(n) for n in c["readings"]] + avg = le.average_readings(rs) + tm = le.write_bundle(avg, OUT / c["case"], c["meta"], len(rs), c["supply"]) + print(c["case"], round(tm["Rf"], 2), round(tm["Rg"], 2)) +(OUT / "cases.json").write_text(json.dumps({"measured_at": STAMP, "cases": cases}, indent=1))