diff ref struct Rietveld refinement for the Mac · powder diffraction with X-rays, synchrotron and neutrons · started October 2026

Roadmap

Phases

Study, then design, then the core, then the app around it. Each phase ends with a named artefact and a log entry. Only phase 0 is detailed; the later phases are drawn from its feature matrix and their detail is written when phase 0 closes.

PHASE 0 · closed (L022)

The repository, and the study of the programs

Know what the Rietveld programs in use do, and how, before deciding what this one will do.

  • Private repository, site skeleton, brief organised into requirements, working method in CLAUDE.md. done (L006)
  • Choose the five most used programs from the long list, with the evidence (citations, facilities, vendors): FullProf, GSAS-II, TOPAS, Jana2020, MAUD. done (L008) Limited to three, FullProf, GSAS-II and Jana2020, by Josu. L009 Jana2020 dropped, leaving FullProf and GSAS-II. L015
  • Method revised by Josu (L012): FullProf is the baseline; GSAS-II and Jana2020 are read only for what FullProf lacks. Scope: crystal-structure refinement from powder data. L012
  • The FullProf inventory: one entry per capability within the scope, what it does, its .pcr reference and its source (path, page) in manuals/fullprof/; capabilities outside the scope listed in one line each: 199 entries. done (L013, L017)
  • GSAS-II: what FullProf lacks within the scope, in physics and in workflow (projects, sequential and parametric refinement, constraints and restraints, scripting, GUI), each gap with its source: 36 gaps. done (L014, L018)
  • The proposal: the feature set of the app, what is in the first version and what comes later: draft, 59 features (38 in version 1, 11 in version 2, 10 later), its six open questions decided by Josu (L020); Q1, the core's language: Rust, with a Python interface (L021). L019–L021
Done when the FullProf inventory and the GSAS-II gap list are on the site, and the design questions Q1–Q6 each have a logged decision.
PHASE 1 · closed (L035)

Crystallography core

Space groups, unit cells, reflections, structure factors, in Rust (L021), each tested against an independent source: FullProf's own output files in manuals/fullprof/, spglib, the International Tables.

  • The crate drs (library and command line), and the unit cell: metric tensors, reciprocal cell, volume, d(hkl), 2\(\theta\), Cartesian frame, Busing–Levy matrix. Test fullprof_metric: all 13 FullProf .out files, no disagreement. done (L023, core 0.1.0)
  • Space groups from Hall symbols: the 230 types in their 530 settings, symmetry operators, centring, Laue class, point group; each checked against spglib and the International Tables, Vol. A. Tests spglib_530 (all 530 settings, 7388 operators, no disagreement) and fullprof_spacegroups (all 13 FullProf .out files); the International Tables not checked directly. done (L024, core 0.2.0)
  • Wyckoff positions and site symmetry: multiplicities, and the constraints on coordinates and displacement parameters of atoms on special positions, as FullProf derives them. Tests spglib_wyckoff (every Wyckoff position of the 230 standard settings), fullprof_sites (96 multiplicities and 69 anisotropic atoms of the FullProf files), crysfml_symbols. done (L026, core 0.3.0)
  • Reflections: the hkl list within a d or 2\(\theta\) range, systematic absences, multiplicities, equivalent reflections; checked against FullProf's reflection lists for the tutorial structures. Tests fullprof_reflections (9 phases, 14337 reflections, same h k l, multiplicities, d and 2\(\theta\)) and reflection_properties (all 530 settings). done (L028, core 0.4.0)
  • Structure factors: X-ray form factors and anomalous terms, neutron scattering lengths, occupancies, isotropic and anisotropic displacements; checked against FullProf's structure factors for the four reference structures (Y2O3, MgAl2O4, Co-doped YBCO, the QPA phases). Tests fullprof_structure_factors (12026 F\(^{2}\) printed by FullProf for PPH3, citric acid and LaMnO3), gemmi_structure_factors (the four reference structures, 10 phases, X-rays and neutrons, against gemmi), structure_factor_properties (530 settings), cif_structures; drs sf. FullProf's own structure factors (Hkl = −3) of the five reference runs: test fullprof_reference_sf, 11 phases, 1992 reflections, F real and imaginary within FullProf's print and single precision. done (L030, core 0.5.0; L035, core 0.7.0)
Done when the reflections and structure factors of the four reference structures of L020 agree with FullProf's output, from the command line. Met: the reflections (L028) and FullProf's own structure factors of the five reference runs (L035).
PHASE 2

The powder pattern and the refinement

Everything of version 1 (L019, L020) that computes and refines, in the core and on the command line: the calculated pattern, then the least-squares engine around it. The app's features (project document, builder, editor, live plot, graphics: P46, P48–P52, P58) are phase 3. Each step is tested against FullProf: the calculated patterns of its .prf files (85 in manuals/fullprof/), and the four reference tutorials run with FullProf on the Mac.

  • Reading the inputs: FullProf .pcr files (import, Q3) and the data formats of P02 (xy/xye, FullProf's free and instrument formats, GSAS fxye, Panalytical .xrdml, Bruker .raw/.brml), with \(\sigma\) and variable step (P01). Modules pcr (all 151 tutorial .pcr files read; one pattern, constant wavelength) and data (Ins 0, 1, 3, 5, 6, 8, 10, 12); test fullprof_profiles reads the observed data of 80 .prf files as FullProf read them (301429 points, Ins 3, 6, 10). The material holds no .xrdml, .raw or .brml file: those readers wait for an example. done (L033, core 0.6.0); the readers are now the registry of the data module (phase 3, L062).
  • The calculated pattern, as FullProf computes it: peak positions with zero, displacement and transparency (P18); pseudo-Voigt and Thompson–Cox–Hastings profiles with Caglioti widths, Finger–Cox–Jephcoat axial asymmetry and the empirical asymmetry (P15, P17); the instrumental resolution file (P16); Lorentz–polarisation by geometry (P27); background functions (P21); several phases with their scales (P32); simulation with Poisson noise (P04). Checked point by point against Ycal and Backg of FullProf's .prf files. Test fullprof_profiles: 14 .prf files rebuilt from their .pcr, among them the five FullProf runs of the reference refinements (rms relative deviation beyond FullProf's print 2·10\(^{-5}\) to 5·10\(^{-4}\), \(\chi^{2}\) as FullProf's to 0.15%), a Le Bail fit to 2.7·10\(^{-3}\), one .prf not drawn from the state of its .pcr; the others left out with their reason; drs calc, drs simulate. Two FullProf rules not found (the reflection limit past the data, the last 0.06–2.7% of the window when \(X \neq 0\)). done (L033, core 0.6.0; L035, core 0.7.0)
  • Sample terms: isotropic size and strain over the resolution file (P24), preferred orientation along one axis (P28), absorption and microabsorption (P29). Size and strain: module microstructure, drs mic, test fullprof_microstructure (the widths of 9 FullProf runs, 2710 reflections; every row of three .mic files); absorption, Lorentz–polarisation and March–Dollase preferred orientation: test fullprof_corrections (1707 reflections of 11 runs, with Yb2ZrWO8-PO-March, L042); the exponential function has no FullProf reference and surface microabsorption is refused. The peak window: CrysFML's low edge and the parametric resolution file's wavelengths and asymmetry found, the 35 FullProf window experiments compared in fullprof_profiles, 23 with no point set apart (L042); YVO3 at Wdt = 40, the rutile-anatase and MgAl2O4 window edges and 15 points of 12 experiments still differ by rules not found, frozen and listed for Josu. partly done (L039, core 0.8.0; L042, core 0.9.0)
  • The least-squares engine: named parameters (P37), constraints and the automatic symmetry constraints (P38), limits (P39), distance, angle and linear restraints (P40), Levenberg–Marquardt with SVD and analytic derivatives (P42), every cycle reported as an event (Q5), agreement factors and statistics (P43), covariance and the esd of any derived quantity (P44). Modules dual, jacobian, refinable, lsq and drs refine: the codewords of a .pcr become parameters named by the dictionary, with constraints, symmetry constraints and limits, refined by Levenberg–Marquardt on an eigen-decomposition with exact derivatives (test engine_derivatives). Test fullprof_refinements: from the tutorials' starting files, Y2O3, Yb2ZrWO8, MgAl2O4, the Egyptian make-up and rutile + anatase reach FullProf's \(\chi^2\) with every parameter within FullProf's esd; Co-YBCO reaches a lower \(\chi^2\) than FullProf, whose last point is not a minimum; LaB6's window, NdNi-HTO's magnetic phase and YVO3's divergence in FullProf are explained or reported and frozen, with FullProf's halved cell esd's under TCH, for Josu. Restraints (P40): distance, angle and linear restraints, through FullProf's ITnum operators and weighted as FullProf weighs them; test fullprof_restraints (the distances and angles FullProf lists for three structures, three restrained refinements, a linear restraint); FullProf's own restrained refinements (L056) reproduced, every restraint within 0.73\(\sigma\) and every parameter within FullProf's esd, with FullProf's angle restraints at π/180 of their stated weight (inferred, in the compatibility layer, L058). Test esd_profile: the esd's match the \(\chi^2\) surface (ratio 0.88–1.01 in five runs), also at the runs' own peak windows since the default window tapers each peak to zero (L058). The parameter set is also built from the user's addresses (ParameterSet::from_addresses, L058). done (L053, core 0.12.0; L055, core 0.13.0; L058, core 0.14.0)
  • The refinement run as a session and steered (W11, W12; L107): Step n, pause and resume with the Levenberg–Marquardt \(\lambda\) and the history, a session a script resumes (drs refine --session), every stop and divergence as data (\(\chi^2\) rising, a jump of many esd's, an impossible value, a singular matrix named as R24 names it); damping per parameter and per class, maximum shifts from the dictionary, bounds that stop, reflect or wrap, links with an offset, new variables, a plan of steps, all in the control file. A .pcr's lone multiplier imported as damping and its relaxation factors as the classes', checked against FullProf's shift_control runs parameter by parameter (test steering); the first cycle from that start frozen and listed for Josu (L109). One cell for two patterns waits for multi-pattern refinement. done (L110, core 0.24.0)
  • What the Publish and Explore streams asked of the core (L114, L115): a refined state's positions, bonds, angles and parent cell with su's propagated through the covariance (a mode phase's through its amplitudes), charges for valence sums, one su rule rounded up (L116), the CIF's and the results file's missing items, a phase's name; a run's trajectory kept, persisted and rebuilt to the bit, \(\chi^2\) on a grid of two parameters, a state's derived quantities in one call, the scene of a 3D view with polyhedra, the eigen-spectrum, an irrep's displacement, the amplitude sets equivalent under the parent's symmetry (tests publish_requests, explore_requests). FullProf's half step on the cell traced to a factor of its own (½ pseudo-Voigt, ¼ TCH), reproduced cycle by cycle and frozen (L113). done (L115, core 0.25.0)
  • A refinement started from a data file and a structure, with no previous control file (L153, step 1; W2, W3): drs new writes the control file from the data and a CIF, or a formula, space group and cell (Le Bail), with the automatic background in its own file, the widths from the data's peaks, the scale by least squares, the scale and background free and every default stated with its source; on Y2O3 it reaches FullProf's minimum with FullProf's background points, and the automatic background's differences are frozen (test start). done (L155, core 0.26.0)
  • The open requests to the core (L153, step 2): app 12, 13, 15, 16 and Publish P9, Explore E7 found met by earlier versions; built now: a pattern that is not a number refused (the tutorial's TU6), U_eq with its su (P15), the parent cell of a phase refined by its coordinates (P17), bond-valence sums and mean distances with su's in the results file (P18), a file named by its place (app 31), FullProf's exports in Exports/FullProf/ (app 32), E7 on the command line (test open_requests). done (L168, core 0.27.0)
  • The small requests of L170: B with its su in the results file and B ↔ U (Publish P20), a control file opened from another folder (app 33, --base), a phase refined by coordinates described by modes in the 3D scene with its reference in fractions (P19; test small_requests). done (L171, core 0.28.0)
  • Plots (a), the plot set (L170, step 2): several files opened as one set, WinPLOTR's buffers, each member's temperature with its source (header, buffer comment, title, file name, or typed; never guessed), the displacements of a stack or a projection on the linear, √ and log scales (PL1–PL3; test plots). done (L172, core 0.29.0)
  • Plots (b), the map and the arithmetic of members (L170, step 3): a common grid with \(\sigma\) propagated (as measured, interpolated, or averaged over bins), the map of a set with its rows at the temperatures and its colour range, the difference map, the sum, average and difference of members written as an XYDATA file naming them (PL4, PL9; test plots). done (L175, core 0.30.0)
  • Plots (c) and (d), windows, sequential refinements and the projection (L170, step 4): the integral, centroid and strongest peak of named windows per member, against the temperature; FullProf's .seq read as a table; the visible pieces of each curve of a projection, decided by the core (PL5, PL11, PL17; test plots_series). done (L177, core 0.31.0)
  • Plots' file and the module's next requests (L192): the plot set file Plots/{set}.drv read, written and opened, the set as CSV, the map's rows for the members apart, a proposed stack step with its rule, members drawn after Data's operations (PL12, PL18–PL20; test plots_sets). done (L192, core 0.33.0)
  • Plots (e), the view's numbers and the files out (L170, step 5): normalisation as a view and the constant counting time of multi-scan files, a set as CSV wide or long in 2\(\theta\), d or Q and the writers in d and Q, FullProf's temperatures file as a variable's source, a window's value flagged below 2\(\sigma\) (PL6, PL7, PL21, PL22; test plots_views). done (L195, core 0.34.0)
  • Plots' last requests to the core and two of the app's (L199): a CSV of several columns read as a set, each member's file and variable from its # line, the columns not read said; a set in d, Q, sin \(\theta\)/λ and 1/d as a view, each member with its own λ; a results file named a result by its place and its first line (PL8, PL10, app 31 and 32; test plots_tables). done (L199, core 0.35.0)
  • Plots' set file keeps a temperatures file's value with its source, and a plot set is known by its content (PL23, PL24; test plots_sets). done (L202, core 0.36.0)
  • Plots' files written as the view shows the set and the core's CSV read back in d and Q (PL25, PL26; test plots_tables); Explore's modes: the esd's at every cycle, the sign reference named per state, FullProf's reported amplitudes (E14a–c; test explore_requests). done (L212, core 0.38.0)
  • Publish's P21: the equivalent amplitude sets of a mode phase only those of the same structure (case A: 4, not 24; test explore_requests). done (L218, core 0.39.0)
  • Explore's E15, a run's pauses, its stop's facts and the steering's notes as data, in the results file and read back (test explore_stops); Plots' PL27, the set file keeps each view's steps and scale, the map's scale and the normalisation (test plots_sets); PL28 is Publish's. done (L225, core 0.40.0)
  • Explore's E18–E21, before the stream restarts (L372): the cell's su's, the contacts' plausible distances and the valence sums' plausible ranges in a state; the Williamson–Hall axes \(d^*\), \(\beta^*\) with each reflection's breadths, against NdNi-HTO's .mic; a state at given values of free parameters, as a step sets them; the \(\chi^2\) map's contour lines, at the \(k\sigma\) ellipses' levels \(\chi^2_{\min}(1 + k^2/(N-P+C))\) (tests explore_e18_e21, fullprof_microstructure) done (L376, core 0.69.0)
  • Explore's E22: the cell's box for any phase, a Le Bail phase included, its twelve edges in Cartesian Å (Cell::edges, which geometry::scene now uses; test explore_e22) done (L401, core 0.75.0)
  • Plots' PL37 for I08 (R33, L405): the set file keeps the map's and the difference map's colour range as clipped and the regions of the T–x plane saved by name, each region's x with the quantity it was drawn in; a region's block of the map, its rows, columns and range, read off the matrix the core computed, its bounds converted with each member's λ (plots::map_region; drs plots describe, drs plots region; test plots_sets). done (L407, core 0.76.0)
  • Plots' PL38, the Map viewer's page without the app (I08 step 5, R33; L409, L412): the page's data in one JSON in the viewer's shape, the regions' blocks precomputed (plots::page_data), and drs plots show, the app opened onto the set when installed, else one self-contained page beside the set with the viewer's bundle inline, nothing fetched (test plots_page). done (L413, core 0.77.0)
  • After version 2 (L372): the Python scripting interface (P53; Q1, L021), PyO3 bindings over the core, drs.run giving every command of the command line and drs.open a project whose values, pattern, refinement, state, checks, export and results come from the core; a wheel built and tested against the command line (core/python, tests/test_drs.py; L380) done (L381, core 0.70.0); the macOS wheel on the Mac; the app's two large Mac items (requests 49–51): the comparison run against FullProf, prepared, read and compared by the core, FullProf run on the Mac (module compare, drs compare-with; test fullprof_comparison) done (L398, core 0.72.0); against GSAS-II through GSASIIscriptable, the model translated into GSAS-II's terms and checked on a pattern both fit (compare::gsas2; test gsas2_comparison, manuals/gsas2/runs/y2o3_tch) done (L399, core 0.73.0); the per-format data options and an order of preference among the readers, declared by the core and kept in the control file (formats::options, reader_options; test data_format_options) done (L400, core 0.74.0)
  • Plots' PL32, left before the bindings (L372): a WinPLOTR header's temperature read with its unit, never as kelvin by default; case E's t7.dat is 179.99 °C = 453.14 K (L243; test winplotr_header); PL34 is Publish's. done (L383, core 0.71.0)
  • Version 1's partly done features (L230), step A: the wavelength refined (P18), the user's scattering factors (P11), Bragg–Brentano surface micro-absorption (P29), FullProf's CeO2 refinements kept at their Cp and \(\tau\) (test pattern_terms); the FullProf comparisons of λ and of the user's factors wait for runs; the Bérar factor (P43) waits for its paper. done (L233, core 0.41.0); steps B, C and D done (L256, L260, L263), but for ISODISTORT's reader, which waits for a file of ISODISTORT's own partial
  • Version 1's P43, the Bérar factor for correlated residuals (Bérar & Lelann 1991), as FullProf reads the paper: its printed factor reproduced in 58 of the 119 outputs that carry it, 34 within 0.05 % (test berar_factor). done (L244, core 0.42.0)
  • FullProf's runs for P29 and P11 taken in (L239): CeO2 with surface micro-absorption and NaBD4 with the user's complex b rebuilt exactly (test fullprof_profiles); b's imaginary part used and the powder |F|² averaged over h and −h, as FullProf does; the two reference files for λ and f′, f″ written for the merging session. done (L251, core 0.43.0)
  • FullProf's runs of the core's two files taken in: the refined \(\lambda\) reached within FullProf's esd, the user's f′ and f″ rebuilt exactly; FullProf's refinement of \(\lambda\) ends in a worse minimum with U < 0 (test pattern_terms) done (L255)
  • Version 1's step B: the amorphous content with an internal standard (P33; Orlhac et al. 2001, their Table 3 reproduced; test amorphous_content); the file of extracted intensities in FullProf's CODFILn_cltr.int with its cluster rule, LaMnO3's 414 lines and the core's own extraction against FullProf's (P35; test extracted_intensities) done (L256, core 0.44.0)
  • Version 1's step C: the symmetry elements of every operator of the 530 settings, as the International Tables list them (kind, symbol, sense, axis or plane, location, intrinsic translation), all 7388 against cctbx (P09, the app's request 35; test symmetry_elements); single-peak fitting, each parameter with its esd, the esd's calibrated on synthetic peaks and Y2O3's 23 well-determined peaks against FullProf's (P51; test peak_fit); completion for the control file's editor, every key, table, choice, species, space group and address it offers read back by the reader (P49; test completion); FullProf's symbolic names and the CIF's tags as the model's addresses, 2660 of 2702 names on their parameter's number (the app's request 36; test output_names) done (L260, core 0.45.0)
  • Version 1's step D (P13): the symmetry modes of a distorted structure computed from its parent, without tables of irreps (the class sums of the parent's group over a supercell it keeps; the modes H leaves fixed), as AMPLIMODES computes them: the course's ten analyses, 56 irreps with their k, parity, dimension, modes on each orbit and amplitudes, 54 to the printed decimals from the input and all 56 from AMPLIMODES's atom mappings (it adjusts the input), its 12 mode vectors in the computed subspaces (module mode_decomposition, drs decompose; test mode_decomposition) done (L263, core 0.46.0); ISODISTORT's mode CIF read and checked on ISODISTORT 6.12.2's own file of case A against the core's decomposition of the same structures: 7 irreps, 12 modes, each amplitude to ISODISTORT's five decimals (drs isodistort; test isodistort) done (L278, core 0.49.0)
  • Version 2's physics one at a time, each with its FullProf or GSAS-II reference and the gate rule (L153, step 3: P25, P36, P06, P54, P55, P05, P41, P30, P23). P25, anisotropic strain by Stephens' quartic form (−1, 2/m, mmm), against FullProf's run of Nd2NiO4 reflection by reflection (test fullprof_anisotropic_strain) done (L211, core 0.37.0); the rest of P25 against FullProf's runs (needles and platelets, the antiphase domains of Pd3MnD, the quartic form of every Laue class, checked on the tetragonal and monoclinic runs; test fullprof_anisotropic_size) done (L267, core 0.47.0); size by the quadratic form and spherical harmonics wait for a FullProf run that uses them waiting; P45, refinement diagnostics: each parameter's impact on \(\chi^2\) and on the calculated pattern, and the normal probability plot of the weighted residuals, against GSAS-II's definitions (test refinement_diagnostics) done (L272, core 0.48.0); P55, guided refinement: the documented order of refinement (FullProf's manual, p. 14; McCusker et al. 1999, §7) offered for a model as a plan of steps, each naming the values it frees, written to the control file and run (test guided_refinement) done (L302, core 0.52.0); P37, a plan run recorded as one: drs results --plan, every cycle with the step that ran it, so that Publish reads the strategy from the core (test guided_refinement) done (L310, core 0.54.0); P36, the Pawley fit: the intensities refined by least squares with the cell and profile, the coincident reflections tied, against FullProf's Le Bail fits of LaMnO3, the spinel and Co-YBCO and the spinel's own pattern (test pawley) done (L315, core 0.55.0); P06, joint refinement: FullProf's multi-pattern files split by pattern, the patterns tied by their codewords, \(Q = \sum_k W_k S_k\) minimised, against FullProf's joint runs pbb, scor_rxn and prbaco (L320), with P41's results file of a block per pattern (test joint_refinement) done (L322, core 0.57.0); P54, sequential and parametric refinement, with P59's series outputs (a table and a multi-block CIF), against FullProf's sequential D20 run of LaMnO3 and SciPy's fits (test sequential) done (L317, core 0.56.0); P05, time-of-flight neutrons: FullProf's six TOF cases and their variants run on the Mac (L334), the core's TOF calculation, refinement, control file, .pcr export and results file (Publish's P46) against them, every difference counted and frozen (tests fullprof_profiles, fullprof_tof) done (L341, core 0.59.0); Publish's P50, each pattern's model from a joint results file without the data (test joint_refinement) done (L345, core 0.61.0); P41, rigid bodies read and placed as FullProf places them, against the 17 rigid-body files and citric acid's prints, what departs frozen (module rigid_body, drs rigid; test rigid_bodies) done (L345, core 0.61.0); a group's values refined in place of its atoms' coordinates, against PPH3's and citric acid's FullProf refinements, with Publish's P47 (test rigid_refinement) done (L347, core 0.62.0); P23, further background terms: Debye-like terms, the 12-term polynomial with inverse powers of \(2\theta\), Nba = 1's stretch and shift, profiles from files, and FullProf's background held to 0 below 0 and above the largest count, against FullProf's 16 runs of them (L346), with nac_3t2's refinement and Publish's P49 (test background_terms) done (L353, core 0.63.0); a .bac background's \(b_1\)–\(b_4\) as four refinable values, its points kept as read, with the background's further terms in the results file (the app's request 47, Publish's P57; test background_terms) done (L364, core 0.66.0); the Fourier filter (Nba = −2) not reproduced, refused accepted (L357); P30, texture along several axes: each axis's March ratio \(r_j\) and fraction \(f_j\), \(P_h = \sum_j f_j D_j\) averaged over the equivalents (FullProf's Nor = 2), read, calculated, refined and kept in the control file, the .pcr export and the results file (Publish's P48), against FullProf's texture runs (tests texture, fullprof_profiles) done (L360, core 0.65.0); the anvil cell's cone integral (Nor = 3, Wright et al. 1996) up to 3.6 % from FullProf's, frozen for Josu; P41's TLS: a rigid group's \(U = T + A L A^{T} + A S + S^{T} A^{T}\) on its and its satellites' atoms, refined, in the control file, the .pcr export and the results file (Publish's P47.2), every atom's \(\beta\) against FullProf's .ort of hmt, pdd and its variants within the print, with Bérar–Baldinozzi's asymmetry taken at the Bragg angle as FullProf takes it (test tls) done (L367, core 0.67.0); urea's TLS centre, FullProf's not found (\(\beta\) up to \(5.45\cdot10^{-5}\) off, urea_test's \(\chi^2\) 0.31 %), and four numbers the Bragg-angle asymmetry moved, frozen for Josu; the core's small requests that close version 2 (L372): a .bac with \(b_1\)–\(b_4\) written as held and left alone when unchanged (the app's request 48), March–Dollase's density against \(\rho\) (Publish's P59), paths relative across the root (P61) (tests background_terms, texture) done (L374, core 0.68.0)
  • The app's request 45 (L337): a control file moved to another folder (File ▸ Move To…), every path it holds rewritten to reach the same files, its comments, order and formatting kept (control::relocate, drs move; test control_relocate) done (L342, core 0.60.0)
  • Le Bail fit with extracted intensities (P35); quantitative phase analysis with esd's (P33); automatic background points (P22, the core's part). Le Bail: module lebail, test fullprof_le_bail (LBF_lmopr from FullProf's starting values: every parameter within its esd; MgAl2O4s_LeBail against FullProf's \(\chi^2\)). QPA: module qpa, the weight fractions of the Egyptian make-up and rutile + anatase within FullProf's esd's, the esd's from the covariance. Automatic background points: GSAS-II's arPLS in data_ops, against pybaselines (L066). done (L055, L066)
  • The parameter dictionary (L044): one entry per parameter with a readable name, symbol, unit, meaning, equation and its paper, the FullProf and GSAS-II equivalents, range, default and when to refine it; the single source for the core's names, the app's tooltips, the editor's help and the manual's theory. Before the control file. data/parameters.yml, 45 entries, rendered as Parameters: the theory and generated into the core's parameter_table; test parameter_dictionary (every field of Model, Phase, Atom mapped). The papers' references were checked against bibliographic records; their equations were not read (no access from the session). done (L046, core 0.10.0)
  • The default model versus the FullProf-compatibility layer (L043): each rule accepted in L036–L042 checked against its original paper; where FullProf departs from it, the paper's form becomes the default and FullProf's stays in the compatibility layer. powder::Convention, rule by rule: the six papers in manuals/papers/ decide the defaults (Bérar & Baldinozzi's F_b and sign, Finger–Cox–Jephcoat's S/L and H/L, Dollase's exponential and the average over equivalent reflections, TCH and Caglioti unchanged), and importing a .pcr translates its values exactly (scale \(\times 2\), P1 + 3P2, G1 → −G1, the axial pair, the excluded regions), keeping FullProf's peak window and reflection range, which have no exact translation; test default_convention: 47 FullProf runs imported, \(\chi^2\) unchanged. done (L050, core 0.11.0)
  • Our own readable control file, written and read by the core (P47, Q3): a strict subset of TOML 1.0, the parameter dictionary's names with units, comments and order kept, every error at its line and column (module control, drs convert, drs check; test control_file: 62 imported runs to the bit both ways, through our file and through an exported .pcr); the syntax accepted with the extension .drc (L070). The .pcr export: the four faults FullProf found (L069) fixed in core 0.17.0: FullProf gives its own numbers on eight runs; LaB6 waits for a fifth fault, the numbering of its codewords around VARY ratio (L071). done (L066, core 0.16.0). Every editable value and structural edit as core operations (edit, L058). The outputs: distances, angles and bond-valence sums (P12), as FullProf's Bond_Str on 77 of its .dis files, and a CIF ready for deposition, against FullProf's CIFs (module bonds, cif_write; drs bonds, drs cif) done (L083, core 0.20.0); the reflection lists: per reflection FWHM, I calc, I obs partitioned by the model and its \(\sigma\), the forbidden reflections, in the results file and as CSV (L100, L101) done; the summary and the listing of a run (P57), FullProf's .sum and .out in the core's words, the all-points agreement as FullProf's .sum in 55 of its 68 compared runs and the 13 others named (module listing, test fullprof_summary) done (L256, core 0.44.0)
  • Our own files (R27, R28, L086): a file dictionary naming every file of a project started in the app (FullProf's names kept for FullProf projects); a results file of our own in place of .prf, its format chosen with evidence (powder CIF, NeXus/HDF5 or ours). The file dictionary written: 18 kinds, the core's names and the page Files, the names proposed for Josu (L090, core 0.22.0) done; the results file compared, pdCIF recommended (the choice, L091); the names accepted, with reflection notes and Exports added, and pdCIF chosen (L099); the results file written in pdCIF with one structure CIF per phase, read back and read by GSAS-II's importers (results, drs results; L101, core 0.23.0) done
  • Refinement by symmetry modes (R29, P13, L086): mode amplitudes read from AMPLIMODES, ISODISTORT and FullProf's .pcr and refined, checked against FullProf's mode refinements in FP_tests; then the modes computed from the parent and distorted structures. Step 1, a phase as a reference structure plus mode amplitudes refined in the core, read from FullProf's mode .pcr and AMPLIMODES's output, against FullProf's refinement and AMPLIMODES's analyses of the course's cases (L089, core 0.22.0) done; FullProf 8.20's runs of cases A, B, D and E reproduced, the 1–6 % of L093 found (reflection limits, the \(\lambda/2\) widths, the background below its first point) and single excluded-region edge points frozen (L098, core 0.23.0) done; each reflection's parent indices and k-vector (L100) done; ISODISTORT, and the modes computed from the structures, to do
Done when the four reference refinements of L020 (Y2O3, MgAl2O4, Co-doped YBCO, the quantitative-analysis tutorial) are reproduced from the command line, from FullProf's starting files, to within FullProf's esd's.
PHASE 3

The Mac app

The Tauri window: menus, documents, the live plot, the interactive background, the control-file builder and the editor.

  • A walking skeleton, early and alongside phase 2 (L044): a Tauri window that opens a .pcr, calls the core as a library (no server), and draws Yobs, Ycal, the difference and the reflection markers. Built on the Mac, since a cloud session cannot build the app. done (L049, app 0.1.0)
  • The data module (R21, L061), its core first: one registry of readers for drs and the app (module formats, drs data formats|identify|read), 31 formats with readable names: FullProf's list (Ins 0–12 and 14, the numbers only as the .pcr translation), a general table reader (delimiter, decimal mark, header, columns and quantity recognised or chosen), and GSAS-II's (Bruker RAW and BRML, XRDML, Rigaku RAS, RASX and TXT, the GSAS family, xye, qye, chi, powder CIF), recognised by content and then by extension, each scan with its wavelength and metadata. Test data_formats: 50 FullProf data files (389266 points) as FullProf read them, \(\sigma\) against FullProf's sums on 49 (five frozen); 48 banks (219573 points) as GSAS-II's importers read them; 182 files recognised. No example of 20 formats (10 checked on synthetic files against GSAS-II); NeXus/HDF5 and MIDAS zarr recognised, not read (L063). The data operations (module data_ops, drs data op|apply|peaks|background|info): an ordered list kept in the control file and applied to the scan, the file never changed: masking, deleting, smoothing, rebinning, normalising, adding, subtracting, merging, conversion between \(2\theta\), \(d\) and \(Q\) and to another wavelength, peak search and the automatic background; test data_operations against SciPy, pybaselines and GSAS-II's code on four real files, and exact identities (L066, core 0.16.0). Every operation's settings described in a dictionary as the parameters are (operations.yml, the page "Data operations: the settings", drs data settings), a scan written as xys or xye and read back to the bit, and the line of each point in its file (L088, core 0.21.0). The module in the app (plot and table, operations) is the app stream's. core done (L062, L066)
  • The control file of diff-ref-struct (P47): a strict subset of TOML under the parameter dictionary's names, lossless on the 62 imported runs, exported to .pcr (L066, core 0.16.0). Run with FullProf, the export was refused for six of nine runs (L069); after core 0.17.0 eight give FullProf's numbers, LaB6 had one fault left (L071); after core 0.18.0 all nine give FullProf's numbers exactly (L079). Syntax and extension .drc accepted (L070). done (L079)
  • The app as an umbrella of modules (R20–R23, L060, L067), in steps that Josu tries one by one: 0.5.0 the frame (activity bar, dock, menus, project folder, Data and Refine registered) done (L068, app 0.5.0); 0.6.0 the Data module done (L072, app 0.6.0); 0.7.0 the Editor and versions done (L074, app 0.7.0); 0.8.0 several projects in windows, a data file first, the background by hand (R25, R26, L075) — the core's part ready: background points in a file or inline, splines, a function fitted to points, a control file rebased onto new data (L078, core 0.19.0), FullProf's background rules found in its outputs (L082), every file of a FullProf project named by what it is for the sidebar of W5 (formats::project::describe, 73 kinds on 2649 files; L084, core 0.20.0), the background settled on FullProf's eleven variants (L087, core 0.21.0); 0.9.0 a refinement from a previous control file and the rest of Refine on the umbrella — the core's part of W7–W8 ready: FullProf's .prf and .hkl read, per-reflection widths and partitioned intensities, forbidden reflections, k-vectors of a mode phase, each phase's share at a point, the cumulative \(\chi^2\) (L100, core 0.23.0); 0.10.0 W7's diagnostics and W3, a refinement from a previous control file (L112); 0.11.0 the refinement paused and resumed with the engine's state, every stop the core's reason, and W12's steering, restraints and plan in the window built, for Josu to try (L117, app 0.11.0); then Publish. in progress
  • The Publish module (R23, R30, L094): figures, tables, CIFs and supplementary material for papers and theses, from a publication set rebuilt on export, with targets as presets; its own crate publish/ and stream. First its design, for Josu to accept; the core's part of its requests P2–P11 ready (L114, core 0.25.0). in progress
  • The Explore module (R31, L104): the path of a refinement in configuration space and in physical subspaces (cell, peak shape, structure, modes), cycle by cycle, with \(\chi^2\) maps and replay; its own stream. First its design, for Josu to accept; the core's part of its requests E1–E7 ready (L115, core 0.25.0); two refinements' paths compared, each run's ellipse for a pair, the correlations and the stop kept in the results file (E11, E11a–c; L184, core 0.32.0); the \(\chi^2\) grid as a map and the ellipse's outline (E13a, E13b; L192, core 0.33.0). in progress
  • Guardrails (R24, L073): the model checked while it is edited and before every run, each problem marked where it is edited with what is wrong, why and a suggestion; from the syntax to parameters that cannot be refined together, found before the run. The checks in the core (drs check), shown by the app. Core: module check, four levels (file, model, refinement, the normal matrix before the run), each diagnostic with a stable code, its place, what, why, a suggestion and the dictionary entry; correlations explained from the dictionary's correlations; test check_diagnostics (18 broken files, each its own diagnostic; the eight good runs without error; predicted correlations against the engine's) core done (L076, core 0.18.0); in the app to do