-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathSASAbs.py
More file actions
11099 lines (10254 loc) · 500 KB
/
Copy pathSASAbs.py
File metadata and controls
11099 lines (10254 loc) · 500 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
"""SAXSAbs Workbench — GUI for SAXS absolute intensity calibration.
Part of the saxsabs package.
Repository: https://github.com/D-sudoasd/SASAbs
License: BSD-3-Clause
"""
import tkinter as tk
import tkinter.font as tkfont
from tkinter import ttk, filedialog, messagebox
import argparse
import hashlib
import os
import sys
import logging
import numpy as np
import fabio
import pyFAI
import matplotlib
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
from pathlib import Path
import traceback
import math
import pandas as pd
import datetime
from io import StringIO
import re
import json
import concurrent.futures
import threading
import uuid
from types import SimpleNamespace
APP_NAME = "SAXSAbs Workbench"
def _read_package_version() -> str:
"""Keep the legacy GUI version aligned with the packaged library version."""
version_file = Path(__file__).resolve().parent / "src" / "saxsabs" / "__init__.py"
try:
text = version_file.read_text(encoding="utf-8")
except OSError:
return "2.0.0"
match = re.search(r'^__version__\s*=\s*"([^"]+)"', text, re.MULTILINE)
return match.group(1) if match else "2.0.0"
APP_VERSION = _read_package_version()
DEFAULT_STANDARD_THICKNESS_MM = 1.055
DEFAULT_SAMPLE_MU_CM_INV = None
DEFAULT_SAMPLE_THICKNESS_MODE = "fixed"
WORKBENCH_FORMULA_VERSION = "v3_nist_blank_exposure_matched"
MAX_BATCH_WORKERS = 32
MAX_OUTPUT_STEM_LENGTH = 120
DEFAULT_LEGACY_RESUME_ENABLED = False
WORKBENCH_MIN_SIZE = (900, 600)
logger = logging.getLogger(__name__)
SUPPORTED_LANGUAGES = ("en", "zh")
I18N = {
"en": {
"app_title": f"{APP_NAME} v{APP_VERSION}",
"header_title": f"{APP_NAME} | Absolute Intensity Calibration",
"theme_toggle": "🌓 Theme",
"lang_toggle_to_zh": "中文",
"lang_toggle_to_en": "English",
"tab1": "\U0001f4d0 1. K-Factor Calibration",
"tab2": "\U0001f4e6 2. Batch Processing",
"tab3": "\U0001f4c8 3. External 1D \u2192 Abs",
"tab4": "\u2753 4. Help",
"t1_guide_title": "Quick Start",
"t1_guide_text": "① Select standard/background/dark/geometry files\n② Verify auto-loaded Time, I0, T\n③ Set standard thickness (mm)\n④ Run calibration to obtain K\n⑤ Check Std Dev and valid points",
"t1_files_title": "1. Calibration Files (Required)",
"t1_phys_title": "2. Physical Parameters",
"t1_run_btn": "\u25b6 Run K Calibration",
"t1_hist_btn": "K History",
"t1_report_title": "Analysis Report",
"t1_plot_tip": "Plot: dashed=net signal; blue=K-corrected; orange=NIST/reference",
"plot_preset_label": "Figure preset:",
"plot_format_label": "Format:",
"plot_export_btn": "Export Figure",
"plot_export_title": "Export publication figure",
"plot_export_success": "Figure exported: {path}",
"plot_export_error": "Figure export failed:\n{err}",
"tip_plot_preset": "Controls figure size, DPI, font size, line width, and export layout.",
"tip_plot_format": "PNG/TIFF are high-DPI raster formats; PDF/SVG/EPS are vector formats.",
"tip_plot_export": "Save the current plot with the selected publication preset and tight bounding box.",
"t2_guide_title": "Batch Workflow",
"t2_guide_text": "① Ensure K, BG/Dark, and poni are ready\n② Select thickness logic\n③ Select one or more integration modes\n④ Add sample files and run dry-check\n⑤ Start batch and review batch_report.csv",
"t2_mid_title": "Sample Queue",
"t2_add_btn": "Add Files",
"t2_add_folder_btn": "Add Folder",
"t2_clear_btn": "Clear Queue",
"t2_check_btn": "Dry Check",
"t2_group_btn": "Detect Groups / 机时分组",
"t2_run_btn": "\u25b6 Start Batch Processing",
"t3_guide_title": "External 1D Workflow",
"t3_guide_text": "① Obtain K in Tab1\n② Select pipeline mode (scaled/raw)\n③ Import external 1D files\n④ Select correction formula and X-axis type\n⑤ Dry-check then batch-export absolute intensity",
"t3_mid_title": "External 1D Queue",
"t3_add_btn": "Add 1D Files",
"t3_clear_btn": "Clear Queue",
"t3_check_btn": "Dry Check",
"t3_run_btn": "\u25b6 Start External 1D Calibration",
"queue_files": "Queue files",
"queue_dedup": "deduplicated",
"out_auto_prefix": "Output directories will be created",
"out_write_prefix": "Output directories under",
"out_none_mode": "Output: no integration mode selected",
"msg_help_title": "Help",
"msg_help_copied": "Help text has been copied to clipboard.",
"msg_preview_title": "Dry Check",
"msg_ext_done_title": "External 1D Completed",
"msg_ext_error_title": "External 1D Error",
"msg_calib_error_title": "Calibration Error",
"msg_k_history_title": "K History",
"msg_batch_error_title": "Batch Processing Error",
"msg_iq_preview_error_title": "I-Q Preview Error",
"msg_ichi_preview_error_title": "I-chi Preview Error",
"msg_warning_title": "Warning",
"msg_input_error_title": "Input Error",
"confirm_clear_title": "Confirm clear",
"confirm_clear_t2_queue": "Clear the current Tab2 sample queue? This does not delete files on disk.",
"confirm_clear_t3_queue": "Clear the current Tab3 1D queue? This does not delete files on disk.",
"confirm_clear_ref_lib": "Clear all auto BG/Dark reference candidates? This does not delete files on disk.",
"help_panel_title": "Program Help",
"help_panel_intro": "Goal: obtain a reliable K factor in Tab1, then process robust batches in Tab2.",
"help_scroll_label": "Help text:",
"help_copy_btn": "Copy Help Text",
"help_copy_tooltip": "Copy full help text for sharing or records.",
"hint_prefix": "Note",
"session_error_title": "Session Error",
"session_error_body": "Failed to read session:\n{err}",
"session_loaded_title": "Session Loaded",
# --- Tab1 labels ---
"lbl_t1_std_file": "Standard (GC):",
"lbl_t1_bg_file": "Background:",
"lbl_t1_dark_file": "Dark image:",
"lbl_t1_poni_file": "Geometry (.poni):",
"lbl_i0_semantic": "I0 mode:",
"cb_solid_angle": "SolidAngle correction",
# --- Tab1 hints ---
"hint_t1_files": "Standard recommended: Glassy Carbon (GC); BG/Dark/poni must share the same geometry and energy.",
"hint_t1_phys": "Time(s)=exposure; I0=incident monitor; T=transmission(0–1). Normalisation follows selected I0 mode.",
# --- Tab1 tooltips ---
"tip_t1_guide": "Follow steps 1–5 to avoid missing key parameters.",
"tip_t1_std_entry": "Standard sample 2D image for absolute calibration (GC recommended).",
"tip_t1_std_btn": "Browse to select standard file.",
"tip_t1_bg_entry": "Empty-cell / air / background 2D image for subtraction.",
"tip_t1_bg_btn": "Browse to select background image.",
"tip_t1_bg_multi": "Multi-select BG images & average (normalised); for capillary blanks / repeats.",
"tip_t1_dark_entry": "Detector dark-current / electronic noise image.",
"tip_t1_dark_btn": "Browse to select dark image.",
"tip_t1_poni_entry": "pyFAI geometry file; controls q conversion accuracy.",
"tip_t1_poni_btn": "Browse to select .poni file.",
"tip_t1_std_exp": "Standard exposure time (s).",
"tip_t1_std_i0": "Standard I0 (monitor reading).",
"tip_t1_std_t": "Standard transmission; should be in 0–1.",
"tip_t1_std_thk": "Standard thickness (mm); for volume normalisation.",
"tip_t1_bg_exp": "Background exposure time (s).",
"tip_t1_bg_i0": "Background I0 (monitor reading).",
"tip_t1_bg_t": "Background transmission.",
"tip_t1_norm_mode": "rate: I0 is count rate; integrated: I0 is integrated counts.",
"tip_t1_norm_hint": "Choose according to beamline output. Wrong choice adds exposure-related systematic error.",
"tip_t1_solid_angle": "Shared by Tab1 calibration & Tab2 batch. Must be consistent or K is invalid.",
"tip_t1_calibrate": "Run 2D BG subtraction + 1D integration + NIST matching; writes K factor.",
"tip_t1_history": "View historical K factor trend to monitor instrument drift.",
"tip_t1_report": "Displays calibration key metrics: K, valid points, Q overlap range and dispersion.",
"tip_t1_plot": "If the blue line tracks the red dots, K calibration quality is good.",
# --- Tab2 labels ---
"lf_t2_global": "1. Global Settings",
"lbl_t2_k_factor": "K factor:",
"lbl_t2_bg_file": "Background:",
"lbl_t2_i0_semantic": "I0 mode:",
"lf_t2_thickness": "2. Thickness Strategy",
"rb_t2_auto_thk": "Auto thickness (d = −ln(T)/μ)",
"lbl_t2_mu": " μ(cm⁻¹):",
"btn_t2_mu_est": "μ est.",
"rb_t2_fix_thk": "Fixed thickness (mm):",
"lf_t2_integration": "3. Integration Modes (post BG subtraction)",
"cb_t2_full_ring": "I-Q full ring",
"cb_t2_sector": "I-Q sector",
"btn_t2_iq_preview": "Preview I-Q",
"lbl_t2_multi_sector": " Multi-sector:",
"lbl_t2_sector_example": " e.g. -25~25;45~65",
"cb_t2_sec_save_each": "Save sectors separately",
"cb_t2_sec_save_sum": "Save merged sector",
"cb_t2_texture": "I-chi texture",
"btn_t2_chi_preview": "Preview I-chi",
"lf_t2_correction": "4. Correction Parameters",
"cb_t2_solid_angle": "Apply Solid Angle correction",
"lbl_t2_error_model": "Error model:",
"lbl_t2_mask": "Mask file:",
"lbl_t2_flat": "Flat file:",
"lf_t2_execution": "5. Reference Matching & Execution",
"rb_t2_ref_fixed": "Fixed BG/Dark",
"rb_t2_ref_auto": "Auto-match BG/Dark",
"btn_t2_bg_lib": "BG Library",
"btn_t2_dark_lib": "Dark Library",
"btn_t2_bg_lib_folder": "BG Folder",
"btn_t2_dark_lib_folder": "Dark Folder",
"btn_t2_clear_lib": "Clear Lib",
"lbl_t2_workers": "Workers:",
"cb_t2_resume": "Resume (skip existing output)",
"cb_t2_overwrite": "Force overwrite",
"cb_t2_strict": "Strict instrument consistency",
"cb_t2_export_cal2d": "Export calibrated 2D package",
"cb_t2_cal2d_flat": "Apply flat into exported 2D",
"lbl_t2_cal2d_dtype": "Cal2D dtype:",
"lbl_t2_tolerance": "Tolerance(%):",
"lbl_t2_outdir": "Output dir:",
# --- Tab2 hints ---
"hint_t2_global": "K from Tab1. I0 mode selects normalisation formula; BG path for quick confirmation.",
"hint_t2_thickness": (
"Formal output uses fixed thickness; each frame still uses its own T "
"for normalization."
),
"hint_t2_integration": "Multi-select & output to different folders: full-ring / sector / texture run simultaneously.",
"hint_t2_correction": "Recommend enabling solid angle. Optional mask / flat / polarisation & error model.",
"hint_t2_execution": "Fix BG/Dark, or auto-match the closest BG/Dark by metadata.",
"hint_t2_queue": "Add multiple files. Dry Check verifies headers and fixed thickness.",
# --- Tab2 tooltips ---
"tip_t2_guide": "Pre-check before running batch significantly reduces mid-run failures.",
"tip_t2_k_factor": "Absolute intensity scale factor. Must be > 0.",
"tip_t2_bg_label": "Current background path (shared from Tab1).",
"tip_t2_norm_mode": "Global: rate means I0 is count rate; integrated means I0 is integrated counts.",
"tip_t2_norm_hint": "Affects normalisation factors in both calibration and batch.",
"tip_t2_auto_thk": (
"Disabled for formal output; per-frame Beer-Lambert thickness is "
"diagnostic-only."
),
"tip_t2_mu": "Read-only diagnostic linear attenuation coefficient, unit cm⁻¹.",
"tip_t2_mu_est": (
"Open the provenance-aware NIST 30 keV or xraydb/Elam diagnostic calculator."
),
"tip_t2_fix_thk": "Required for formal constant-thickness and in-situ processing.",
"tip_t2_fix_thk_val": "Uniform thickness for all samples, in mm.",
"tip_t2_mu_label": "Larger μ → smaller thickness for same T.",
"tip_t2_full": "Recommended for isotropic samples. Can be combined with other modes.",
"tip_t2_sector": "Integrate a specified azimuthal sector, highlighting directional structure.",
"tip_t2_sec_min": "Sector start angle (°). Supports wrap-around ±180° (e.g. 170 to −170).",
"tip_t2_sec_max": "Sector end angle (°). Same as start (mod 360) is invalid.",
"tip_t2_sec_preview": "Open 2D preview of I-Q integration region (sector or full ring).",
"tip_t2_sec_multi": "Multi-sector list. '-25~25;45~65' or '-25,25 45,65'; empty = use single sector above.",
"tip_t2_sec_each": "Each sector outputs to its own subfolder (sector_XX_*).",
"tip_t2_sec_sum": "Merge all sectors by pixel weight into one I-Q and save separately.",
"tip_t2_texture": "Output I vs azimuthal angle chi in a given q range. Runs alongside I-Q.",
"tip_t2_qmin": "Texture analysis q minimum (Å⁻¹).",
"tip_t2_qmax": "Texture analysis q maximum (Å⁻¹), must exceed q_min.",
"tip_t2_chi_preview": "Open 2D preview of I-chi q-ring band range.",
"tip_t2_solid_angle": "Must match Tab1 calibration. Mismatch will block batch.",
"tip_t2_error_model": "azimuthal: azimuthal scatter; poisson: counting stats; none: no errors.",
"tip_t2_polarization": "Enable only when the beam polarization factor is known. Disabled passes None; enabled values must be -1 to 1.",
"tip_t2_mask": "Mask image: non-zero pixels are excluded.",
"tip_t2_flat": "Flat-field correction image (optional).",
"tip_t2_ref_fixed": "All samples use Tab1 BG/Dark.",
"tip_t2_ref_auto": "Auto-select BG & Dark closest in exposure/I0/T/time.",
"tip_t2_bg_lib": "Select background file library for auto-matching.",
"tip_t2_dark_lib": "Select dark file library for auto-matching.",
"tip_t2_bg_lib_folder": "Recursively add background candidates from a folder.",
"tip_t2_dark_lib_folder": "Recursively add dark candidates from a folder.",
"tip_t2_clear_lib": "Clear BG/Dark libraries.",
"tip_t2_workers": "Parallel threads; 1 = serial. Suggest 1–8.",
"tip_t2_resume": "Skip existing output files; supports resume after interruption.",
"tip_t2_overwrite": "Ignore existing output and recalculate.",
"tip_t2_strict": "Check energy/wavelength/distance/pixel/size consistency; stop on mismatch.",
"tip_t2_tolerance": "Consistency tolerance %, e.g. 0.5 means 0.5%.",
"tip_t2_export_cal2d": "Write detector-space absolute-calibrated 2D EDF plus PONI, mask and metadata for pyFAI/pydidas reintegration.",
"tip_t2_cal2d_flat": "If enabled, flat correction is baked into the exported 2D image. Do not pass flat again to pyFAI.",
"tip_t2_cal2d_dtype": "Float32 is compact; float64 preserves more numerical precision.",
"tip_t2_add": "Multi-select TIFF files.",
"tip_t2_add_folder": "Recursively add 2D image files from a folder (.tif/.tiff/.edf/.cbf).",
"tip_t2_clear": "Clear queue; does not delete files on disk.",
"tip_t2_check": "Batch-check each file's exp/mon/T and thickness availability.",
"tip_t2_group": "Auto-detect files from the same experimental run (机时) using timestamps. Creates logical groups for output organization and smarter BG/Dark matching.",
"tip_t2_listbox": "Current sample queue.",
"tip_t2_run": "Run batch. Single-file failure does not abort the batch.",
"tip_t2_progress": "Batch processing progress.",
"tip_t2_outdir": "Optional. Empty = output next to sample files.",
"tip_t2_out_label": "Output files and batch_report.csv will be written here.",
# --- Tab3 labels ---
"lf_t3_global": "1. Global & Formula",
"lbl_t3_k_factor": "K factor:",
"lbl_t3_pipeline": "Pipeline:",
"rb_t3_scaled": "Scale only",
"rb_t3_raw": "Raw 1D full correction",
"rb_t3_kd_formula": "Ext. 1D w/o thickness: I_abs = I_rel × K / d",
"lbl_t3_thk": "Fixed thickness(mm):",
"rb_t3_k_formula": "Ext. 1D w/ thickness: I_abs = I_rel × K",
"lbl_t3_x_type": "X-axis type:",
"lbl_t3_i0_semantic": "I0 mode:",
"lf_t3_execution": "2. Execution Strategy",
"cb_t3_resume": "Resume (skip existing output)",
"cb_t3_overwrite": "Force overwrite",
"lbl_t3_formats": "Supported: .dat .txt .chi .csv (need X & I columns; Error optional)",
"lf_t3_raw_params": "3. Raw 1D Correction Params (raw pipeline)",
"btn_t3_meta_from_batch": "Generate metadata from Tab2 report",
"cb_t3_meta_thk": "Prefer thk_mm from metadata",
"cb_t3_sync_bg": "Sync BG params with Tab1 global (bg_exp/bg_i0/bg_t)",
"lbl_t3_sample_params": "Sample fixed params exp/i0/T:",
"lbl_t3_bg_params": "BG fixed params exp/i0/T:",
"lbl_t3_outdir": "Output dir:",
# --- Tab3 hints ---
"hint_t3_global": "K from Tab1. Choose pipeline, then formula. Raw pipeline uses exp/I0/T and BG1D/Dark1D.",
"hint_t3_execution": "Recommend dry-check first. Resume to avoid redundant overwrites.",
"hint_t3_raw": "Only active when pipeline = Raw 1D. Can use Tab2's batch_report.csv or metadata.csv directly.",
"hint_t3_queue": "Click 'Dry Check' to verify column parsing for each file.",
# --- Tab3 tooltips ---
"tip_t3_guide": "For data already integrated in pyFAI or other software; absolute calibration only.",
"tip_t3_k": "Must be > 0. Uses latest Tab1 calibration value.",
"tip_t3_scaled": "For external 1D already BG-subtracted & normalised; just apply absolute scale.",
"tip_t3_raw": "For external 1D with raw integrated intensity; full 1D-level BG subtraction & normalisation here.",
"tip_t3_kd": "For external integrated result still in relative intensity (not divided by thickness).",
"tip_t3_thk": "Only used in K/d mode. Unit: mm.",
"tip_t3_k_only": "For external integrated result already divided by thickness.",
"tip_t3_x_mode": "'auto' requires explicit Q units (Å⁻¹ or nm⁻¹) or Chi. q_nm⁻¹ is converted to Å⁻¹; 2theta requires wavelength; unknown axes are blocked.",
"tip_t3_resume": "Skip if output exists; for resuming large batches.",
"tip_t3_overwrite": "Ignore existing results and recalculate.",
"tip_t3_meta": "Optional. Supports metadata.csv or Tab2's batch_report.csv.",
"tip_t3_bg1d": "Required (raw pipeline). BG 1D integrated the same way as the sample.",
"tip_t3_dark1d": "Optional. Not supplied → treated as zero.",
"tip_t3_meta_from_batch": "One-click: generate Tab3 metadata.csv from Tab2 batch_report.csv; auto-fill path.",
"tip_t3_meta_thk": "If enabled and sample's metadata has thk_mm, overrides fixed thickness.",
"tip_t3_sync_bg": "When enabled, Tab3 BG params auto-update from Tab1/global, avoiding stale values.",
"tip_t3_add": "Multi-select external integration result files.",
"tip_t3_clear": "Clear queue only; does not delete files on disk.",
"tip_t3_check": "Check column recognition, point count, and X-axis type inference.",
"tip_t3_listbox": "Current external 1D file list for conversion.",
"tip_t3_run": "Batch-convert external 1D relative intensity to absolute using chosen formula.",
"tip_t3_progress": "External 1D batch progress.",
"tip_t3_outdir": "Optional. Empty = output next to first input file.",
# --- Window titles ---
"title_t3_dryrun": "External 1D Dry Check Results",
"title_k_history": "K Factor History Trend",
"title_t2_dryrun": "Batch Dry Check Results",
"title_iq_preview": "I-Q 2D Preview – {name}",
"title_ichi_preview": "I-chi 2D Preview – {name}",
"title_mu_tool": "Universal μ Calculator (any energy)",
# --- Standard selector ---
"lbl_t1_std_type": "Standard:",
"opt_std_srm3600": "NIST SRM 3600 (GC)",
"opt_std_water": "Water (H\u2082O)",
"opt_std_lupolen": "Lupolen (user curve)",
"opt_std_custom": "Custom (user file)",
"lbl_t1_water_temp": "Water T (°C):",
"lbl_t1_std_ref_file": "Ref. curve file:",
"hint_t1_std_water": "Water: q-independent, dΣ/dΩ = 0.01632 cm\u207b\xb9 at 20 \u00b0C (Orthaber et al. 2000)",
"hint_t1_std_lupolen": "Lupolen: batch-dependent; load your beamline calibration curve.",
# --- Buffer subtraction ---
"lf_t3_buffer": "Buffer / Solvent Subtraction",
"cb_t3_buffer_enable": "Enable buffer subtraction",
"lbl_t3_buffer_file": "Buffer 1D file:",
"lbl_t3_alpha": "\u03b1 (scale):",
"lbl_t3_buffer_status": "(not loaded)",
"lbl_t2_alpha": "BG \u03b1-scale:",
"cb_t2_buffer_enable": "Enable BG \u03b1-scaling",
# --- Output format ---
"lbl_output_format": "Output format:",
"opt_fmt_tsv": "TSV (tab-separated)",
"opt_fmt_csv": "CSV (comma-separated)",
"opt_fmt_cansas_xml": "canSAS 1D XML",
"opt_fmt_nxcansas_h5": "NXcanSAS HDF5",
# --- Mu tool new keys ---
"lbl_mu_energy": "Energy (keV):",
"lbl_mu_energy_or_wl": "or wavelength (Å):",
"lbl_mu_preset": "Preset material:",
"lbl_mu_custom_comp": "Custom (El:wt%, ...)",
"lbl_mu_result_murho": "\u03bc/\u03c1 (cm\xb2/g):",
"lbl_mu_result_mu": "\u03bc_linear (cm\u207b\xb9):",
"btn_mu_add_row": "+ Element",
"btn_mu_del_row": "- Element",
"lbl_mu_contrib": "Element contributions",
# --- Messagebox bodies ---
"msg_meta_gen_title": "Metadata Generated",
"msg_batch_done_title": "Batch Completed",
"msg_k_history_empty": "No K history yet; run calibration first.",
"msg_k_history_file_empty": "History file is empty.",
"msg_k_history_read_error": "Failed to read history: {e}",
# --- Dry-run panel labels ---
"pre_k_factor": "K factor:",
"pre_pipeline": "Pipeline:",
"pre_corr_mode": "Correction mode:",
"pre_fixed_thk": "Fixed thickness(mm):",
"pre_x_mode": "X-axis mode:",
"pre_i0_semantic": "I0 mode:",
"pre_warning_header": "[Dry-Check Warnings]",
"pre_pass_t3": "[Dry-Check Passed] No obvious issues with parameters.",
"pre_i0_norm": "I0 normalisation mode:",
"pre_integ_mode": "Integration mode:",
"pre_integ_none": "None",
"pre_sector_output": "Sector output:",
"pre_sector_list": "Sector list:",
"pre_ref_mode": "Reference mode:",
"pre_error_model": "Error model:",
"pre_workers": "Workers:",
"pre_pass_t2": "[Dry-Check Passed] No obvious configuration issues.",
# --- Status / health labels ---
"status_ok": "OK",
"status_fail": "FAIL",
"status_no_match": "No match",
"status_match_fail": "Match failed",
# --- Lib info ---
"var_bg_lib": "BG lib: {n}",
"var_dark_lib": "Dark lib: {n}",
# --- Mu tool ---
"lbl_mu_wt_pct": "Wt% fraction",
"lbl_mu_density": "Density ρ (g/cm³):",
"btn_mu_apply": "Apply to batch",
# --- File row labels (Tab3) ---
"lbl_t3_bg1d_file": "BG 1D file:",
"lbl_t3_dark1d_file": "Dark 1D file:",
# --- Report messages ---
"rpt_start_calib": "Start calibration (robust mode)...",
"rpt_i0_norm_mode": "I0 normalisation mode: {mode} (norm={formula})",
"rpt_solid_angle": "SolidAngle correction: {state}",
"rpt_calib_ok": "Calibration succeeded (robust estimate)",
# --- Ext 1D done messagebox ---
"msg_ext_done_body": "External 1D absolute calibration completed.\nSuccess: {ok}\nSkipped: {skip}\nFailed: {fail}\nOutput dir: {out_dir}\nReport: {report}\nMeta: {meta}",
# --- Dry-run warnings (Tab3) ---
"warn_k_le_zero": "K factor ≤ 0.",
"warn_kd_thk_le_zero": "K/d mode: fixed thickness must be > 0 mm.",
"warn_meta_read_fail": "metadata CSV read failed: {e}",
"warn_raw_no_meta": "Raw pipeline: no metadata CSV; fixed sample params will be used for all.",
"warn_raw_no_bg1d": "Raw pipeline: BG 1D file is missing.",
"warn_bg1d_read_fail": "BG 1D read failed: {e}",
"warn_dark1d_read_fail": "Dark 1D read failed: {e}",
"warn_bg_norm_invalid": "BG normalisation factor ≤ 0; check BG exp/i0/T.",
# --- Dry-run warnings (Tab2) ---
"warn_no_integ_mode": "No integration mode selected (check at least one).",
"warn_sector_no_output": "Sector mode: no output selected (save each / merge).",
"warn_sector_angle_invalid": "Sector angle range invalid: {e}",
"warn_texture_q_invalid": "Texture q range invalid: qmin must be < qmax.",
"warn_auto_thk_mu": "Auto thickness mode: μ must be > 0.",
"warn_fix_thk_le_zero": "Fixed thickness must be > 0 mm.",
"warn_auto_bg_empty": "Auto-match mode: BG library is empty.",
"warn_auto_dark_empty": "Auto-match mode: Dark library is empty.",
"warn_inst_issues": "Instrument consistency found {n} issues (see details below).",
"warn_bg_norm_mismatch": "BG_Norm vs sample Norm_s magnitude mismatch (BG/sample median={ratio:.3g}, BG_Norm={bg_norm:.6g}, SampleMed={med:.6g}).",
# --- Dry-run ext 1D status/reason ---
"reason_norm_invalid": "Sample normalisation factor invalid (exp/i0/T)",
"reason_thk_invalid": "Thickness invalid (fixed thickness or metadata thk_mm)",
# --- Ext 1D messagebox ---
"msg_t3_queue_empty": "Queue is empty; please add external 1D files first.",
# --- Preview info labels ---
"info_iq_sector": "Sector mode({n}): {desc}",
"info_iq_full": "Full ring (valid pixels)",
"info_iq_title": "Tab2 I-Q Integration Preview",
"info_ichi_title": "Tab2 I-chi (q-ring) Preview",
"info_iq_line1": "Sample: {name} | Mode: {mode} | Coverage: {pct:.2f}%",
"info_iq_line2": "Angle convention (pyFAI chi): 0° right, +90° down, -90° up, ±180° left.",
"info_ichi_line1": "Sample: {name} | q range: [{qmin:.4g}, {qmax:.4g}] Å⁻¹ | Coverage: {pct:.2f}%",
"info_ichi_line2": "q-map unit: {src} (corresponds to Tab2 radial_chi q selection).",
# --- Mu tool messagebox ---
"msg_mu_wt_warn": "Total wt% = {w_tot}",
"msg_mu_fail": "μ estimation failed: {e}",
},
"zh": {
"app_title": f"{APP_NAME} v{APP_VERSION}",
"header_title": f"{APP_NAME}|绝对强度校正",
"theme_toggle": "🌓 切换深色/浅色模式",
"lang_toggle_to_zh": "中文",
"lang_toggle_to_en": "English",
"tab1": "\U0001f4d0 1. K 因子标定",
"tab2": "\U0001f4e6 2. 批处理",
"tab3": "\U0001f4c8 3. 外部 1D \u2192 绝对强度",
"tab4": "\u2753 4. 帮助",
"t1_guide_title": "快速流程(新手)",
"t1_guide_text": "① 选择标准样/本底/暗场/几何文件\n② 核对自动读取的 Time、I0、T\n③ 填写标准样厚度(mm)\n④ 点击运行标定,得到 K 因子\n⑤ 查看报告中的 Std Dev 与点数",
"t1_files_title": "1. 标定文件(必须)",
"t1_phys_title": "2. 物理参数(核心输入)",
"t1_run_btn": "\u25b6 运行 K 因子标定",
"t1_hist_btn": "K 历史",
"t1_report_title": "分析报告(建议重点看 Std Dev)",
"t1_plot_tip": "图示说明:虚线=净信号;蓝线=K 校正后;橙色=NIST/参考点",
"plot_preset_label": "图像预设:",
"plot_format_label": "格式:",
"plot_export_btn": "导出图像",
"plot_export_title": "导出论文级图像",
"plot_export_success": "图像已导出: {path}",
"plot_export_error": "图像导出失败:\n{err}",
"tip_plot_preset": "控制图像尺寸、DPI、字号、线宽和导出版式。",
"tip_plot_format": "PNG/TIFF 是高分辨率位图;PDF/SVG/EPS 是矢量格式。",
"tip_plot_export": "按当前预设保存图像,并自动使用 tight bounding box 避免标签裁切。",
"t2_guide_title": "批处理工作流(推荐顺序)",
"t2_guide_text": "① 先确认 K 因子和 BG/暗场/poni 已就绪\n② 选择厚度逻辑(自动/固定)\n③ 选择一个或多个积分模式(可同时勾选)\n④ 添加样品文件并点击预检查\n⑤ 启动批处理并查看 batch_report.csv",
"t2_mid_title": "样品队列",
"t2_add_btn": "添加文件",
"t2_add_folder_btn": "添加文件夹",
"t2_clear_btn": "清空队列",
"t2_check_btn": "预检查",
"t2_group_btn": "检测机时分组",
"t2_run_btn": "\u25b6 开始批处理",
"t3_guide_title": "外部 1D 绝对强度校正流程",
"t3_guide_text": "① 先在 Tab1 得到可信 K 因子\n② 选择流程:仅比例缩放 / 原始1D完整校正\n③ 导入外部1D文件(原始模式还需 BG1D/Dark1D 与参数)\n④ 选择校正公式(K/d 或 K)与 X 轴类型\n⑤ 先预检查,再批量输出绝对强度表格",
"t3_mid_title": "外部 1D 文件队列",
"t3_add_btn": "添加1D文件",
"t3_clear_btn": "清空队列",
"t3_check_btn": "预检查",
"t3_run_btn": "\u25b6 开始外部 1D 绝对强度校正",
"queue_files": "队列文件",
"queue_dedup": "去重后",
"out_auto_prefix": "输出目录将自动创建",
"out_write_prefix": "输出目录将写入",
"out_none_mode": "输出目录: 未选择积分模式",
"msg_help_title": "帮助",
"msg_help_copied": "帮助文本已复制到剪贴板。",
"msg_preview_title": "预检查",
"msg_ext_done_title": "外部1D校正完成",
"msg_ext_error_title": "外部1D校正错误",
"msg_calib_error_title": "标定错误",
"msg_k_history_title": "K 历史",
"msg_batch_error_title": "批处理错误",
"msg_iq_preview_error_title": "I-Q 预览错误",
"msg_ichi_preview_error_title": "I-chi 预览错误",
"msg_warning_title": "警告",
"msg_input_error_title": "输入错误",
"confirm_clear_title": "确认清空",
"confirm_clear_t2_queue": "确认清空当前 Tab2 样品队列?这不会删除磁盘文件。",
"confirm_clear_t3_queue": "确认清空当前 Tab3 1D 队列?这不会删除磁盘文件。",
"confirm_clear_ref_lib": "确认清空所有自动 BG/Dark 候选库?这不会删除磁盘文件。",
"help_panel_title": "程序帮助(新手版)",
"help_panel_intro": "目标:先在 Tab1 得到可靠 K 因子,再在 Tab2 做稳健批处理。",
"help_scroll_label": "帮助文本(可滚动):",
"help_copy_btn": "复制帮助文本",
"help_copy_tooltip": "复制完整帮助内容,方便发给同事或存档。",
"hint_prefix": "注释",
"session_error_title": "会话错误",
"session_error_body": "读取会话失败:\n{err}",
"session_loaded_title": "会话已加载",
# --- Tab1 labels ---
"lbl_t1_std_file": "标准样 (GC):",
"lbl_t1_bg_file": "背景图像:",
"lbl_t1_dark_file": "暗场图像:",
"lbl_t1_poni_file": "几何文件 (.poni):",
"lbl_i0_semantic": "I0 语义:",
"cb_solid_angle": "SolidAngle修正",
# --- Tab1 hints ---
"hint_t1_files": "标准样建议用玻璃碳(GC);背景/暗场/poni 应与样品保持同一实验几何与能量。",
"hint_t1_phys": "Time(s)=曝光时间;I0=入射强度监测值;T=透过率(0~1)。归一化按下方 I0 语义选择公式。",
# --- Tab1 tooltips ---
"tip_t1_guide": "按 1~5 步执行,基本不会漏关键参数。",
"tip_t1_std_entry": "用于绝对强度标定的标准样二维图像(推荐 GC)。",
"tip_t1_std_btn": "点击选择标准样文件。",
"tip_t1_bg_entry": "空样品/空气或本底散射图像,用于 2D 本底扣除。",
"tip_t1_bg_btn": "点击选择背景图像。",
"tip_t1_bg_multi": "多选背景图并合并扣除(归一化后平均),适用于空毛细管/空白重复。",
"tip_t1_dark_entry": "探测器暗电流/本底噪声图像。",
"tip_t1_dark_btn": "点击选择暗场图像。",
"tip_t1_poni_entry": "pyFAI 几何标定文件,决定 q 转换精度。",
"tip_t1_poni_btn": "点击选择 .poni 文件。",
"tip_t1_std_exp": "标准样曝光时间(秒)。",
"tip_t1_std_i0": "标准样 I0(监测器读数)。",
"tip_t1_std_t": "标准样透过率,建议在 0~1 之间。",
"tip_t1_std_thk": "标准样厚度(mm),用于体积归一化。",
"tip_t1_bg_exp": "背景图曝光时间(秒)。",
"tip_t1_bg_i0": "背景图 I0(监测器读数)。",
"tip_t1_bg_t": "背景图透过率。",
"tip_t1_norm_mode": "rate: I0 是每秒计数率;integrated: I0 是曝光积分计数。",
"tip_t1_norm_hint": "请按线站实际输出选择。选错会引入曝光时间相关系统误差。",
"tip_t1_solid_angle": "Tab1标定与Tab2批处理共用此设置。两者必须一致,否则 K 因子无效。",
"tip_t1_calibrate": "执行 2D 扣背景 + 1D 积分 + NIST 匹配,自动写入 K 因子。",
"tip_t1_history": "查看历史 K 因子趋势,监控仪器漂移。",
"tip_t1_report": "会显示标定关键指标:K、有效点数、Q 重叠区间和离散度。",
"tip_t1_plot": "若蓝线与红点趋势一致,通常说明 K 标定质量较好。",
# --- Tab2 labels ---
"lf_t2_global": "1. 全局配置",
"lbl_t2_k_factor": "K 因子:",
"lbl_t2_bg_file": "背景文件:",
"lbl_t2_i0_semantic": "I0 语义:",
"lf_t2_thickness": "2. 厚度策略",
"rb_t2_auto_thk": "自动厚度 (d = -ln(T)/μ)",
"lbl_t2_mu": " μ(cm⁻¹):",
"btn_t2_mu_est": "μ估算",
"rb_t2_fix_thk": "固定厚度 (mm):",
"lf_t2_integration": "3. 积分模式(2D 扣背景后)",
"cb_t2_full_ring": "I-Q 全环",
"cb_t2_sector": "I-Q 扇区",
"btn_t2_iq_preview": "预览I-Q",
"lbl_t2_multi_sector": " 多扇区:",
"lbl_t2_sector_example": " 例:-25~25;45~65",
"cb_t2_sec_save_each": "分扇区分别保存",
"cb_t2_sec_save_sum": "扇区合并保存",
"cb_t2_texture": "I-chi 织构",
"btn_t2_chi_preview": "预览I-chi",
"lf_t2_correction": "4. 修正参数",
"cb_t2_solid_angle": "应用 Solid Angle 修正",
"lbl_t2_error_model": "误差模型:",
"lbl_t2_mask": "Mask 文件:",
"lbl_t2_flat": "Flat 文件:",
"lf_t2_execution": "5. 参考匹配与执行",
"rb_t2_ref_fixed": "固定 BG/Dark",
"rb_t2_ref_auto": "自动匹配 BG/Dark",
"btn_t2_bg_lib": "选择 BG 库",
"btn_t2_dark_lib": "选择 Dark 库",
"btn_t2_bg_lib_folder": "BG文件夹",
"btn_t2_dark_lib_folder": "Dark文件夹",
"btn_t2_clear_lib": "清空库",
"lbl_t2_workers": "并行线程:",
"cb_t2_resume": "断点续跑(跳过已存在输出)",
"cb_t2_overwrite": "强制覆盖输出",
"cb_t2_strict": "严格仪器一致性校验",
"cb_t2_export_cal2d": "导出校正后2D数据包",
"cb_t2_cal2d_flat": "将 flat 写入导出2D",
"lbl_t2_cal2d_dtype": "Cal2D精度:",
"lbl_t2_tolerance": "阈值(%):",
"lbl_t2_outdir": "输出根目录:",
# --- Tab2 hints ---
"hint_t2_global": "K 因子来自 Tab1 标定结果。I0 语义决定归一化公式;BG 路径仅用于快速确认。",
"hint_t2_thickness": "正式输出使用固定厚度;每帧仍使用自己的 T 做透射归一化。",
"hint_t2_integration": "可多选并一次性输出到不同文件夹:全环/扇区/织构可同时运行。",
"hint_t2_correction": "建议开启 solid angle。可选 mask/flat/polarization 与误差模型。",
"hint_t2_execution": "可固定 BG/Dark,或按元数据自动匹配最接近的 BG/Dark。",
"hint_t2_queue": '可一次添加多个文件。先点"预检查",确认头信息与固定厚度。',
# --- Tab2 tooltips ---
"tip_t2_guide": "先预检查再正式跑批,可显著减少中途失败。",
"tip_t2_k_factor": "绝对强度比例因子。必须大于 0。",
"tip_t2_bg_label": "当前启用的背景图路径(由 Tab1 共享)。",
"tip_t2_norm_mode": "全局生效:rate 表示 I0 为计数率;integrated 表示 I0 为积分计数。",
"tip_t2_norm_hint": "该设置会影响标定与批处理的所有归一化因子。",
"tip_t2_auto_thk": "正式输出已禁用;逐帧 Beer-Lambert 厚度仅用于诊断。",
"tip_t2_mu": "只读诊断线性衰减系数 mu,单位 cm^-1。",
"tip_t2_mu_est": "打开带溯源的 NIST 30 keV 或 xraydb/Elam 诊断计算器。",
"tip_t2_fix_thk": "恒厚与原位样品的正式处理必须使用固定厚度。",
"tip_t2_fix_thk_val": "所有样品统一厚度值,单位 mm。",
"tip_t2_mu_label": "mu 越大,按同样 T 算出的厚度越小。",
"tip_t2_full": "对各向同性样品优先推荐。可与其他模式同时勾选。",
"tip_t2_sector": "仅对指定方位角扇区积分,突出方向性结构。可多选并行输出。",
"tip_t2_sec_min": "扇区起始角(度)。支持跨 ±180°(例如 170 到 -170)。",
"tip_t2_sec_max": "扇区结束角(度)。与起始角相同(模360)无效。",
"tip_t2_sec_preview": "弹出2D窗口预览 I-Q 积分区域(扇区或全环),用于确认选区。",
"tip_t2_sec_multi": "多扇区列表。支持 `-25~25;45~65`、`-25,25 45,65` 等格式;留空时使用上方单扇区。",
"tip_t2_sec_each": "每个扇区输出到独立子文件夹(sector_XX_*)。",
"tip_t2_sec_sum": "将所有扇区按像素权重合并成一条 I-Q,并单独输出。",
"tip_t2_texture": "在给定 q 范围内输出 I 随方位角 chi 的分布。可与 I-Q 同时输出。",
"tip_t2_qmin": "织构分析 q 最小值(A^-1)。",
"tip_t2_qmax": "织构分析 q 最大值(A^-1),需大于 q_min。",
"tip_t2_chi_preview": "弹出2D窗口预览 I-chi 使用的 q 环带范围。",
"tip_t2_solid_angle": "必须与 Tab1 标定时保持一致。若不一致程序会阻断批处理。",
"tip_t2_error_model": "azimuthal: 方位离散;poisson: 计数统计;none: 不计算误差。",
"tip_t2_polarization": "仅在已知束线偏振因子时启用。未启用时传入 None;启用后数值必须在 -1 到 1。",
"tip_t2_mask": "掩膜图:非零像素视为无效区域。",
"tip_t2_flat": "平场校正图(可选)。",
"tip_t2_ref_fixed": "全批次统一使用 Tab1 指定的 BG/Dark。",
"tip_t2_ref_auto": "按曝光/I0/T/时间与样品最接近原则自动选 BG 和 Dark。",
"tip_t2_bg_lib": "选择可供自动匹配的背景文件集合。",
"tip_t2_dark_lib": "选择可供自动匹配的暗场文件集合。",
"tip_t2_bg_lib_folder": "递归添加文件夹中的背景候选图像。",
"tip_t2_dark_lib_folder": "递归添加文件夹中的暗场候选图像。",
"tip_t2_clear_lib": "清空 BG/Dark 库。",
"tip_t2_workers": "并行线程数,1 表示串行。建议 1~8。",
"tip_t2_resume": "已存在输出文件时自动跳过,支持中断后续跑。",
"tip_t2_overwrite": "忽略已存在输出并重新计算。",
"tip_t2_strict": "检查能量/波长/距离/像素/尺寸一致性,不一致则停止。",
"tip_t2_tolerance": "一致性阈值百分比,例如 0.5 表示 0.5%。",
"tip_t2_export_cal2d": "导出 detector-space 绝对强度2D图、PONI、mask 和 metadata,供 pyFAI/pydidas 后续重新积分。",
"tip_t2_cal2d_flat": "开启后 flat 会烧入导出2D图;后续 pyFAI 不应再次传入 flat。",
"tip_t2_cal2d_dtype": "float32 文件更小;float64 保留更多数值精度。",
"tip_t2_add": "支持多选 TIFF 文件。",
"tip_t2_add_folder": "递归添加文件夹中的二维图像(.tif/.tiff/.edf/.cbf)。",
"tip_t2_clear": "清空队列,不会删除磁盘文件。",
"tip_t2_check": "批量检查每个文件的 exp/mon/T 和厚度可用性。",
"tip_t2_group": "根据时间戳自动识别同一次机时(实验轮次)的文件。可用于按组输出子目录和优先匹配同组BG/Dark。",
"tip_t2_listbox": "显示当前待处理样品列表。",
"tip_t2_run": "执行批处理。单文件失败不会中断整批。",
"tip_t2_progress": "显示批处理进度。",
"tip_t2_outdir": "可选。不填时默认输出到样品所在目录。",
"tip_t2_out_label": "输出文件与 batch_report.csv 会写入该目录。",
# --- Tab3 labels ---
"lf_t3_global": "1. 全局与公式",
"lbl_t3_k_factor": "K 因子:",
"lbl_t3_pipeline": "流程:",
"rb_t3_scaled": "仅比例缩放",
"rb_t3_raw": "原始1D完整校正",
"rb_t3_kd_formula": "外部1D未除厚度: I_abs = I_rel * K / d",
"lbl_t3_thk": "固定厚度(mm):",
"rb_t3_k_formula": "外部1D已除厚度: I_abs = I_rel * K",
"lbl_t3_x_type": "X轴类型:",
"lbl_t3_i0_semantic": "I0语义:",
"lf_t3_execution": "2. 执行策略",
"cb_t3_resume": "断点续跑(跳过已存在输出)",
"cb_t3_overwrite": "强制覆盖输出",
"lbl_t3_formats": "支持格式: .dat .txt .chi .csv(列至少包含 X 与 I;Error 可选)",
"lf_t3_raw_params": "3. 原始1D校正参数(raw流程)",
"btn_t3_meta_from_batch": "由 Tab2 报告生成 metadata",
"cb_t3_meta_thk": "优先使用 metadata 中的 thk_mm",
"cb_t3_sync_bg": "BG参数跟随 Tab1 全局(bg_exp/bg_i0/bg_t)",
"lbl_t3_sample_params": "样品固定参数 exp/i0/T:",
"lbl_t3_bg_params": "BG固定参数 exp/i0/T:",
"lbl_t3_outdir": "输出根目录:",
# --- Tab3 hints ---
"hint_t3_global": "K 来自 Tab1。先选流程,再选公式。原始1D流程会用到 exp/I0/T 与 BG1D/Dark1D。",
"hint_t3_execution": "建议先预检查。可断点续跑,避免重复覆盖。",
"hint_t3_raw": "仅当流程=原始1D完整校正时生效。可直接使用 Tab2 的 batch_report.csv 或 metadata.csv。",
"hint_t3_queue": '建议先点"预检查"确认每个文件的列解析情况。',
# --- Tab3 tooltips ---
"tip_t3_guide": "适合你在 pyFAI/其他软件完成积分后,仅在本程序做绝对标定。",
"tip_t3_k": "必须 >0。优先使用 Tab1 最新标定值。",
"tip_t3_scaled": "适合外部1D已做过本底/归一化,仅需绝对强度映射。",
"tip_t3_raw": "适合外部1D是原始积分强度,需要在本页完成1D级扣本底和归一化。",
"tip_t3_kd": "适用于外部积分结果仍是相对强度(尚未除厚度)。",
"tip_t3_thk": "仅在 K/d 模式下使用。单位 mm。",
"tip_t3_k_only": "适用于外部积分结果已经做了厚度归一化。",
"tip_t3_x_mode": "auto 要求明确的 Q 单位(Å⁻¹或nm⁻¹)或 Chi;q_nm⁻¹会换算为Å⁻¹,2theta必须提供波长,未知轴阻止输出。",
"tip_t3_resume": "输出存在时跳过,适合大批量中断后继续。",
"tip_t3_overwrite": "忽略已存在结果并重算。",
"tip_t3_meta": "可选。支持 metadata.csv,或直接选择 Tab2 的 batch_report.csv。",
"tip_t3_bg1d": "必填(raw流程)。与样品同积分方式得到的 BG 1D。",
"tip_t3_dark1d": "可选。未提供则按 0 处理。",
"tip_t3_meta_from_batch": "从 Tab2 的 batch_report.csv 一键生成 Tab3 可用 metadata.csv,并自动回填路径。",
"tip_t3_meta_thk": "开启后,若某样品 metadata 含 thk_mm,则覆盖固定厚度。",
"tip_t3_sync_bg": "开启后 Tab3 的 BG 参数会随 Tab1/全局变化自动更新,避免陈旧值。",
"tip_t3_add": "支持多选外部积分结果文件。",
"tip_t3_clear": "仅清空队列,不删除磁盘文件。",
"tip_t3_check": "检查列识别、点数和坐标类型推断。",
"tip_t3_listbox": "当前待转换的外部1D文件列表。",
"tip_t3_run": "将外部1D相对强度按选定公式批量转换为绝对强度。",
"tip_t3_progress": "显示外部1D批处理进度。",
"tip_t3_outdir": "可选。不填时默认输出到首个输入文件所在目录。",
# --- Window titles ---
"title_t3_dryrun": "外部1D预检查结果",
"title_k_history": "K 因子历史趋势",
"title_t2_dryrun": "批处理预检查结果",
"title_iq_preview": "I-Q 2D预览 - {name}",
"title_ichi_preview": "I-chi 2D预览 - {name}",
"title_mu_tool": "通用 μ 计算器(任意能量)",
# --- 标准样选择 ---
"lbl_t1_std_type": "标准样品:",
"opt_std_srm3600": "NIST SRM 3600 (GC)",
"opt_std_water": "纯水 (H\u2082O)",
"opt_std_lupolen": "Lupolen (用户曲线)",
"opt_std_custom": "自定义 (用户文件)",
"lbl_t1_water_temp": "水温 (°C):",
"lbl_t1_std_ref_file": "参考曲线文件:",
"hint_t1_std_water": "水标准: q无关, dΣ/dΩ=0.01632 cm\u207b\xb9 (20 \u00b0C) (Orthaber et al. 2000)",
"hint_t1_std_lupolen": "Lupolen: 批次相关; 请加载光束线标定曲线。",
# --- 缓冲液扣除 ---
"lf_t3_buffer": "缓冲液/溶剂扣除",
"cb_t3_buffer_enable": "启用缓冲液扣除",
"lbl_t3_buffer_file": "缓冲液1D文件:",
"lbl_t3_alpha": "\u03b1 (缩放):",
"lbl_t3_buffer_status": "(未加载)",
"lbl_t2_alpha": "背景 \u03b1缩放:",
"cb_t2_buffer_enable": "启用背景 \u03b1-缩放",
# --- 输出格式 ---
"lbl_output_format": "输出格式:",
"opt_fmt_tsv": "TSV (制表符分隔)",
"opt_fmt_csv": "CSV (逗号分隔)",
"opt_fmt_cansas_xml": "canSAS 1D XML",
"opt_fmt_nxcansas_h5": "NXcanSAS HDF5",
# --- μ 计算器新键 ---
"lbl_mu_energy": "能量 (keV):",
"lbl_mu_energy_or_wl": "或波长 (Å):",
"lbl_mu_preset": "预设材料:",
"lbl_mu_custom_comp": "自定义 (El:wt%, ...)",
"lbl_mu_result_murho": "\u03bc/\u03c1 (cm\xb2/g):",
"lbl_mu_result_mu": "\u03bc_linear (cm\u207b\xb9):",
"btn_mu_add_row": "+ 元素",
"btn_mu_del_row": "- 元素",
"lbl_mu_contrib": "各元素贡献",
# --- Messagebox bodies ---
"msg_meta_gen_title": "metadata 已生成",
"msg_batch_done_title": "批处理完成",
"msg_k_history_empty": "尚无 K 历史记录,请先运行一次标定。",
"msg_k_history_file_empty": "历史文件为空。",
"msg_k_history_read_error": "读取历史失败: {e}",
# --- Dry-run panel labels ---
"pre_k_factor": "K 因子:",
"pre_pipeline": "流程:",
"pre_corr_mode": "校正模式:",
"pre_fixed_thk": "固定厚度(mm):",
"pre_x_mode": "X轴模式:",
"pre_i0_semantic": "I0语义:",
"pre_warning_header": "[预检查警告]",
"pre_pass_t3": "[预检查通过] 参数未见明显问题。",
"pre_i0_norm": "I0 归一化模式:",
"pre_integ_mode": "积分模式:",
"pre_integ_none": "无",
"pre_sector_output": "扇区输出:",
"pre_sector_list": "扇区列表:",
"pre_ref_mode": "参考模式:",
"pre_error_model": "误差模型:",
"pre_workers": "并行线程:",
"pre_pass_t2": "[预检查通过] 未发现明显配置问题。",
# --- Status / health labels ---
"status_ok": "正常",
"status_fail": "失败",
"status_no_match": "无匹配",
"status_match_fail": "匹配失败",
# --- Lib info ---
"var_bg_lib": "BG库: {n}",
"var_dark_lib": "Dark库: {n}",
# --- Mu tool ---
"lbl_mu_wt_pct": "质量分数 (wt%)",
"lbl_mu_density": "密度 rho (g/cm3):",
"btn_mu_apply": "应用到批处理",
# --- File row labels (Tab3) ---
"lbl_t3_bg1d_file": "BG 1D 文件:",
"lbl_t3_dark1d_file": "Dark 1D 文件:",
# --- Report messages ---
"rpt_start_calib": "开始标定(稳健模式)...",
"rpt_i0_norm_mode": "I0 归一化模式: {mode} (norm={formula})",
"rpt_solid_angle": "SolidAngle 修正: {state}",
"rpt_calib_ok": "标定成功(稳健估计)",
# --- Ext 1D done messagebox ---
"msg_ext_done_body": "外部1D绝对强度校正完成。\n成功: {ok}\n跳过: {skip}\n失败: {fail}\n输出目录: {out_dir}\n报告: {report}\n元数据: {meta}",
# --- Dry-run warnings (Tab3) ---
"warn_k_le_zero": "K 因子 <= 0。",
"warn_kd_thk_le_zero": "K/d 模式下固定厚度必须 > 0 mm。",
"warn_meta_read_fail": "metadata CSV 读取失败: {e}",
"warn_raw_no_meta": "raw流程未提供 metadata CSV,将全部使用固定样品参数。",
"warn_raw_no_bg1d": "raw流程缺少 BG 1D 文件。",
"warn_bg1d_read_fail": "BG 1D 读取失败: {e}",
"warn_dark1d_read_fail": "Dark 1D 读取失败: {e}",
"warn_bg_norm_invalid": "BG 归一化因子 <=0,请检查 BG exp/i0/T。",
# --- Dry-run warnings (Tab2) ---
"warn_no_integ_mode": "未选择积分模式(至少勾选一种)。",
"warn_sector_no_output": "扇区模式未勾选任何输出(分别保存/合并保存)。",
"warn_sector_angle_invalid": "扇区角度范围无效:{e}",
"warn_texture_q_invalid": "织构 q 范围无效:qmin 必须 < qmax。",
"warn_auto_thk_mu": "自动厚度模式下 mu 必须 > 0。",
"warn_fix_thk_le_zero": "固定厚度必须 > 0 mm。",
"warn_auto_bg_empty": "自动匹配模式下 BG 库为空。",
"warn_auto_dark_empty": "自动匹配模式下 Dark 库为空。",
"warn_inst_issues": "仪器一致性发现 {n} 项问题(见下方详情)。",
"warn_bg_norm_mismatch": "BG_Norm 与样品 Norm_s 量级差异过大 (BG/样品中位={ratio:.3g}, BG_Norm={bg_norm:.6g}, SampleMed={med:.6g})。",
# --- Dry-run ext 1D status/reason ---
"reason_norm_invalid": "样品归一化因子无效(exp/i0/T)",
"reason_thk_invalid": "厚度无效(固定厚度或metadata thk_mm)",
# --- Ext 1D messagebox ---
"msg_t3_queue_empty": "队列为空,请先添加外部1D文件。",
# --- Preview info labels ---
"info_iq_sector": "扇区模式({n}): {desc}",
"info_iq_full": "全环 (有效像素)",
"info_iq_title": "Tab2 I-Q 积分区域预览",
"info_ichi_title": "Tab2 I-chi (q环带) 预览",
"info_iq_line1": "样品: {name} | 模式: {mode} | 覆盖像素: {pct:.2f}%",
"info_iq_line2": "角度定义(pyFAI chi):0°向右,+90°向下,-90°向上,±180°向左。",
"info_ichi_line1": "样品: {name} | q区间: [{qmin:.4g}, {qmax:.4g}] A^-1 | 覆盖像素: {pct:.2f}%",
"info_ichi_line2": "q 映射单位: {src}(用于对应 Tab2 radial_chi 的 q 选区)。",
# --- Mu tool messagebox ---
"msg_mu_wt_warn": "总 wt% = {w_tot}",
"msg_mu_fail": "μ 估算失败: {e}",
},
}
# Safety-critical copy is kept together so the legacy bilingual dictionaries
# cannot silently drift back to the scientifically ambiguous labels.
I18N["en"].update({
"lbl_k_record_readonly": "Read-only; from Tab1 (preflight must verify it)",
"lbl_mu_data_source": "Data source and model",
"title_mu_tool": "Material \u03bc calculator and provenance",
"opt_mu_source_nist": "NIST 30 keV composition model (recommended)",
"opt_mu_source_elam": "xraydb/Elam diagnostic",
"cb_mu_porosity_risk": "Porosity/EBM risk",
"btn_mu_apply": "Calculate \u03bc (diagnostic only)",
"btn_mu_export_json": "Export provenance JSON",
"title_mu_export": "Export material attenuation provenance",
"msg_mu_export_requires_calculation": "Calculate mu before exporting provenance.",
"msg_mu_geometry_changed": (
"The PONI path, content, or photon energy changed after calculation. "
"Recalculate mu before exporting provenance."
),
"msg_mu_export_success": "Provenance JSON exported:\n{path}",
"warn_k_missing_invalid": "K factor is missing or not a finite positive number.",
"lbl_mu_density": "Density \u03c1 (Elam only, g/cm3):",
"tip_t2_k_factor": (
"Read-only K from Tab1. Formal output still requires the active complete "
"CalibrationRecord to pass preflight identity checks."
),
"tip_t3_k_factor": (
"Read-only K from Tab1. Default or legacy K values cannot pass formal preflight."
),
"t3_guide_text": (
"1. Obtain a provenance-backed K in Tab1\n"
"2. Import an explicitly relative external 1D profile\n"
"3. Choose K/d or K scaling and X-axis semantics\n"
"4. Dry-check correction state and calibration identity\n"
"5. Export absolute intensity with a correction ledger"
),
"hint_t3_global": (
"Formal output accepts reduced relative (scaled) profiles only. Raw-count "
"correction is disabled until it shares the validated 2D reduction kernel."
),
"lf_t3_raw_params": "3. Disabled legacy raw-1D parameters",
"rb_t2_auto_thk": "Disabled diagnostic: per-frame Beer-Lambert",
"hint_t2_thickness": (
"Formal output requires fixed d for constant-thickness/in-situ samples; every "
"frame still uses its own T for normalization. Per-frame d is diagnostic-only."
),
"tip_t2_auto_thk": (
"Disabled for formal output. Diagnostic d=-ln(T)/mu can turn T drift into false "
"thickness drift for constant-thickness in-situ series."
),
"tip_t2_fix_thk": (
"Recommended for constant-thickness and in-situ series. Per-frame T normalization "
"remains active."
),
"cb_t2_resume": "Disabled: exists-only resume",
"tip_t2_resume": (
"Disabled because ordinary 1D outputs were skipped by existence only, without "
"processing-signature or content validation."
),
"cb_t3_resume": "Disabled: exists-only resume",
"hint_t3_execution": (
"Dry Check is mandatory before running. Exists-only resume is disabled for formal "
"output."
),
"tip_t3_resume": (
"Disabled because it has no processing-signature or content validation."
),
"lbl_mu_source": (
"Source: xraydb mu_elam / Elam database (diagnostic composition model)"
),
"rb_t3_raw": "Disabled: legacy raw 1D correction",
"hint_t3_raw": (
"Formal raw-1D correction is disabled until dark-exposure matching and the NIST "
"blank convention share the validated 2D reduction kernel."
),
"tip_t3_raw": (
"Disabled for scientific safety. Reintegrate a strict calibrated-2D package or "
"provide an explicitly relative external profile."
),
"tip_t2_mu_est": (
"Open the provenance-aware diagnostic calculator: bundled NIST 30 keV "
"composition snapshot or xraydb/Elam comparison."
),
"tip_t2_mu": (
"Read-only diagnostic mu. Formal fixed-thickness output does not consume this "
"field or its provenance."
),
"tip_t2_mu_label": (
"Diagnostic attenuation result only; fixed d is the formal thickness input."
),
"lbl_t3_alpha_uncertainty": "u(\u03b1), optional:",
"hint_t3_alpha_uncertainty": (
"Leave u(\u03b1) blank when unknown; combined uncertainty stays NaN and is "
"never assumed to be zero."
),
})
I18N["zh"].update({
"lbl_k_record_readonly": "\u53ea\u8bfb\uff1b\u7531 Tab1 \u751f\u6210\uff08\u987b\u901a\u8fc7\u9884\u68c0\uff09",
"lbl_mu_data_source": "\u6570\u636e\u6e90\u4e0e\u6a21\u578b",
"title_mu_tool": "\u6750\u6599 \u03bc \u8ba1\u7b97\u4e0e\u6eaf\u6e90",
"opt_mu_source_nist": "NIST 30 keV \u6210\u5206\u6a21\u578b\uff08\u63a8\u8350\uff09",
"opt_mu_source_elam": "xraydb/Elam \u8bca\u65ad\u6a21\u578b",
"cb_mu_porosity_risk": "\u5b54\u9699/EBM \u98ce\u9669",
"btn_mu_apply": "\u8ba1\u7b97 \u03bc\uff08\u4ec5\u8bca\u65ad\uff09",
"btn_mu_export_json": "\u5bfc\u51fa\u6eaf\u6e90 JSON",
"title_mu_export": "\u5bfc\u51fa\u6750\u6599\u8870\u51cf\u6eaf\u6e90",
"msg_mu_export_requires_calculation": "\u8bf7\u5148\u8ba1\u7b97 mu\uff0c\u518d\u5bfc\u51fa\u6eaf\u6e90\u3002",
"msg_mu_geometry_changed": (
"\u8ba1\u7b97\u540e PONI \u8def\u5f84\u3001\u6587\u4ef6\u5185\u5bb9\u6216\u5149\u5b50\u80fd\u91cf\u5df2\u53d8\u66f4\u3002"
"\u8bf7\u91cd\u65b0\u8ba1\u7b97 mu \u540e\u518d\u5bfc\u51fa\u6eaf\u6e90\u3002"
),
"msg_mu_export_success": "\u6eaf\u6e90 JSON \u5df2\u5bfc\u51fa\uff1a\n{path}",
"warn_k_missing_invalid": "K \u56e0\u5b50\u7f3a\u5931\u6216\u4e0d\u662f\u6709\u9650\u6b63\u6570\u3002",
"lbl_mu_density": "\u5bc6\u5ea6 \u03c1\uff08\u4ec5 Elam\uff0cg/cm3\uff09:",
"tip_t2_k_factor": (
"K \u4e3a Tab1 \u53ea\u8bfb\u7ed3\u679c\u3002\u6b63\u5f0f\u8f93\u51fa\u4ecd\u5fc5\u987b\u7531\u5f53\u524d\u5b8c\u6574 CalibrationRecord "
"\u901a\u8fc7\u9884\u68c0\u8eab\u4efd\u6821\u9a8c\u3002"
),
"tip_t3_k_factor": (
"K \u4e3a Tab1 \u53ea\u8bfb\u7ed3\u679c\uff1b\u9ed8\u8ba4\u503c\u6216\u65e7\u7248\u65e0\u6eaf\u6e90 K \u65e0\u6cd5\u901a\u8fc7\u6b63\u5f0f\u9884\u68c0\u3002"
),
"t3_guide_text": (
"1. \u5148\u5728 Tab1 \u83b7\u5f97\u6709\u6eaf\u6e90 K\n"
"2. \u5bfc\u5165\u660e\u786e\u6807\u8bb0\u4e3a relative \u7684\u5916\u90e8 1D\n"
"3. \u9009\u62e9 K/d \u6216 K \u7f29\u653e\u53ca X \u8f74\u8bed\u4e49\n"
"4. \u9884\u68c0\u6821\u6b63\u72b6\u6001\u4e0e\u6807\u5b9a\u8eab\u4efd\n"
"5. \u5bfc\u51fa\u5e26\u6821\u6b63 ledger \u7684\u7edd\u5bf9\u5f3a\u5ea6"
),
"hint_t3_global": (
"\u6b63\u5f0f\u8f93\u51fa\u53ea\u63a5\u53d7\u5df2\u5f52\u4e00\u5316\u7684 relative\uff08scaled\uff09\u66f2\u7ebf\u3002"
"raw counts \u6821\u6b63\u5728\u5171\u4eab\u5df2\u9a8c\u8bc1 2D \u6838\u5fc3\u524d\u4fdd\u6301\u7981\u7528\u3002"
),
"lf_t3_raw_params": "3. \u5df2\u7981\u7528\u7684\u65e7\u7248 raw 1D \u53c2\u6570",
"rb_t2_auto_thk": "\u5df2\u7981\u7528\u8bca\u65ad\uff1a\u9010\u5e27 Beer-Lambert",
"hint_t2_thickness": (
"\u539f\u4f4d/\u6052\u539a\u6837\u54c1\u7684\u6b63\u5f0f\u8f93\u51fa\u5fc5\u987b\u4f7f\u7528\u56fa\u5b9a d\uff1b"
"\u6bcf\u5e27\u4ecd\u4f7f\u7528\u5404\u81ea T \u505a\u900f\u5c04\u5f52\u4e00\u5316\u3002"
"\u9010\u5e27 d=-ln(T)/mu \u4ec5\u4f5c\u8bca\u65ad\u3002"
),
"tip_t2_auto_thk": (
"\u6b63\u5f0f\u8f93\u51fa\u5df2\u7981\u7528\u3002\u5bf9\u6052\u539a\u539f\u4f4d\u5e8f\u5217\uff0cT \u6f02\u79fb\u4f1a\u88ab\u8bef\u5f53\u6210\u539a\u5ea6\u6f02\u79fb\u3002"
),
"tip_t2_fix_thk": (
"\u63a8\u8350\u7528\u4e8e\u539f\u4f4d\u548c\u6052\u539a\u5e8f\u5217\uff1b\u56fa\u5b9a d \u4e0d\u4f1a\u5173\u95ed\u9010\u5e27 T \u900f\u5c04\u5f52\u4e00\u5316\u3002"
),
"cb_t2_resume": "\u5df2\u7981\u7528\uff1a\u4ec5\u6309\u5b58\u5728\u6027\u7eed\u8dd1",
"tip_t2_resume": (
"\u666e\u901a1D\u4ec5\u6309\u6587\u4ef6\u5b58\u5728\u6027\u8df3\u8fc7\uff0c\u4e0d\u6821\u9a8c\u7b7e\u540d\u6216\u5185\u5bb9\uff1b\u6821\u6b632D\u5305\u53e6\u6709\u72ec\u7acb\u5b8c\u6574\u6027\u6821\u9a8c\u3002"
"\u9664\u975e\u5df2\u5ba1\u8ba1\u65e7\u8f93\u51fa\uff0c\u5426\u5219\u4fdd\u6301\u5173\u95ed\u3002"
),
"cb_t3_resume": "\u5df2\u7981\u7528\uff1a\u4ec5\u6309\u5b58\u5728\u6027\u7eed\u8dd1",
"hint_t3_execution": (
"\u6b63\u5f0f\u8fd0\u884c\u524d\u5fc5\u987b\u9884\u68c0\u67e5\u3002\u65e7\u7248\u7eed\u8dd1\u53ea\u68c0\u67e5\u8f93\u51fa\u662f\u5426\u5b58\u5728\uff0c\u9ed8\u8ba4\u5173\u95ed\u3002"
),
"tip_t3_resume": (
"\u65e7\u7248/\u4e0d\u5b89\u5168\uff1a\u4ec5\u6309\u8f93\u51fa\u5b58\u5728\u6027\u8df3\u8fc7\uff0c\u4e0d\u6821\u9a8c\u5904\u7406\u7b7e\u540d\u6216\u6587\u4ef6\u5185\u5bb9\u3002"
"\u9664\u975e\u5df2\u5ba1\u8ba1\u65e7\u8f93\u51fa\uff0c\u5426\u5219\u4fdd\u6301\u5173\u95ed\u3002"
),