[us-commits] [ehb54/ultrascan3] e7d7d7: somo hplc saxs cyclic fit default

emre brookes noreply at github.com
Mon Aug 17 20:19:28 MDT 2026


  Branch: refs/heads/main
  Home:   https://github.com/ehb54/ultrascan3
  Commit: e7d7d74166bcf0202b1e1313a89ae95f28c3d867
      https://github.com/ehb54/ultrascan3/commit/e7d7d74166bcf0202b1e1313a89ae95f28c3d867
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/src/us_hydrodyn_saxs_hplc.cpp
    M us_somo/develop/src/us_hydrodyn_saxs_hplc_options.cpp
    M us_somo/develop/src/us_hydrodyn_settings.cpp
    M us_somo/etc/somo.config.new
    M us_somo/etc/somo.defaults.new

  Log Message:
  -----------
  somo hplc saxs cyclic fit default

(cherry picked from commit 23217df32eb9c68071477b35b91c8fec2700f461)


  Commit: 7438262147dd1359ba28bc1488a4106c04ea56bd
      https://github.com/ehb54/ultrascan3/commit/7438262147dd1359ba28bc1488a4106c04ea56bd
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/src/us_hydrodyn_dad.cpp
    M us_somo/develop/src/us_hydrodyn_dad_makeiq.cpp
    M us_somo/develop/src/us_hydrodyn_dad_modes.cpp
    M us_somo/develop/src/us_hydrodyn_dad_options.cpp
    M us_somo/develop/src/us_hydrodyn_mals.cpp
    M us_somo/develop/src/us_hydrodyn_mals_makeiq.cpp
    M us_somo/develop/src/us_hydrodyn_mals_modes.cpp
    M us_somo/develop/src/us_hydrodyn_mals_options.cpp
    M us_somo/develop/src/us_hydrodyn_mals_saxs.cpp
    M us_somo/develop/src/us_hydrodyn_mals_saxs_makeiq.cpp
    M us_somo/develop/src/us_hydrodyn_mals_saxs_modes.cpp
    M us_somo/develop/src/us_hydrodyn_mals_saxs_options.cpp
    M us_somo/develop/src/us_hydrodyn_saxs_hplc.cpp
    M us_somo/develop/src/us_hydrodyn_saxs_hplc_makeiq.cpp
    M us_somo/develop/src/us_hydrodyn_saxs_hplc_modes.cpp
    M us_somo/develop/src/us_hydrodyn_saxs_hplc_options.cpp

  Log Message:
  -----------
  somo smoothing -> smoothing radius

(cherry picked from commit 467b139eb8e4ea286425423605382e86abcc4d93)


  Commit: f1f8287f2cd7c1abc01382a2f090b42557238179
      https://github.com/ehb54/ultrascan3/commit/f1f8287f2cd7c1abc01382a2f090b42557238179
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/src/us_hydrodyn_dad_options.cpp
    M us_somo/develop/src/us_hydrodyn_mals_options.cpp
    M us_somo/develop/src/us_hydrodyn_mals_saxs_options.cpp
    M us_somo/develop/src/us_hydrodyn_saxs.cpp
    M us_somo/develop/src/us_hydrodyn_saxs_hplc_bl.cpp
    M us_somo/develop/src/us_hydrodyn_saxs_hplc_options.cpp

  Log Message:
  -----------
  somo more smoothing->smoothing radius

(cherry picked from commit 8e831017ea17956e3fa307390f41e7e0fe89092f)


  Commit: e488e8dde2a2dc1ee7950f1dabe8b464995bbc43
      https://github.com/ehb54/ultrascan3/commit/e488e8dde2a2dc1ee7950f1dabe8b464995bbc43
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/src/us_hydrodyn_dad.cpp
    M us_somo/develop/src/us_hydrodyn_dad_util.cpp

  Log Message:
  -----------
  somo uv vis support alternate format loads

(cherry picked from commit 685dfdc0eed41b0d5a219a19b45829952ae8bd23)


  Commit: ab91198e70eef4fb3dfe8f638456ab92d2786f86
      https://github.com/ehb54/ultrascan3/commit/ab91198e70eef4fb3dfe8f638456ab92d2786f86
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/include/us_hydrodyn_saxs.h
    A us_somo/develop/include/us_hydrodyn_saxs_iqq_extrap_c0_conc.h
    M us_somo/develop/include/us_hydrodyn_saxs_iqq_load_csv.h
    M us_somo/develop/libus_somo.pro
    A us_somo/develop/src/us_hydrodyn_saxs_iqq_extrap_c0.cpp
    A us_somo/develop/src/us_hydrodyn_saxs_iqq_extrap_c0_conc.cpp
    M us_somo/develop/src/us_hydrodyn_saxs_iqq_load_csv.cpp
    M us_somo/develop/src/us_hydrodyn_saxs_loads.cpp

  Log Message:
  -----------
  Add extrapolation to zero concentration for I(q) CSV load dialog

Adds a Zimm-plot-style q-pointwise linear extrapolation to zero
concentration in US_Hydrodyn_Saxs_Iqq_Load_Csv: select >=3 curves,
assign each a concentration via a new modal dialog, and add the
resulting intercept curve (with fit-derived intercept SE as error
bars) to the plot.

Co-Authored-By: Claude Sonnet 4.6 <noreply at anthropic.com>
(cherry picked from commit 72352e626deaa05e5ae3b7f742897c42960f6602)


  Commit: e1446e72008b6ed2bf63412f637c439da3f91108
      https://github.com/ehb54/ultrascan3/commit/e1446e72008b6ed2bf63412f637c439da3f91108
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    A us_somo/somo/doc/manual/somo/DAWN_head.png
    A us_somo/somo/doc/manual/somo/MALS_angles.png
    A us_somo/somo/doc/manual/somo/WyattRayleigh ratios csv.png
    M us_somo/somo/doc/manual/somo/mals_parameters.html
    M us_somo/somo/doc/manual/somo/mals_saxs_options.html
    M us_somo/somo/doc/manual/somo/saxs_hplc_options.html
    M us_somo/somo/doc/manual/somo/somo-HPLC-SAXS_EMG_option.png
    M us_somo/somo/doc/manual/somo/somo-HPLC-SAXS_GaussFit1.png
    M us_somo/somo/doc/manual/somo/somo-HPLC-SAXS_GaussFit2.png
    A us_somo/somo/doc/manual/somo/somo-HPLC-SAXS_options_Min_Gauss.png
    M us_somo/somo/doc/manual/somo/somo-HPLC-SAXS_options_new.png
    M us_somo/somo/doc/manual/somo/somo-HPLC-SAXS_options_new_Gaussians.png
    M us_somo/somo/doc/manual/somo/somo-HPLC-SAXS_options_new_baseline.png
    M us_somo/somo/doc/manual/somo/somo-HPLC-SAXS_skewedGaussian1.png
    M us_somo/somo/doc/manual/somo/somo-HPLC-SAXS_skewedGaussian11.png
    M us_somo/somo/doc/manual/somo/somo-HPLC-SAXS_skewedGaussian11a.png
    M us_somo/somo/doc/manual/somo/somo-HPLC-SAXS_skewedGaussian11b.png
    M us_somo/somo/doc/manual/somo/somo-HPLC-SAXS_skewedGaussian11c.png
    M us_somo/somo/doc/manual/somo/somo-HPLC-SAXS_skewedGaussian12.png
    M us_somo/somo/doc/manual/somo/somo-HPLC-SAXS_skewedGaussian2.png
    M us_somo/somo/doc/manual/somo/somo-HPLC-SAXS_skewedGaussian3.png
    M us_somo/somo/doc/manual/somo/somo-HPLC-SAXS_skewedGaussian4.png
    M us_somo/somo/doc/manual/somo/somo-HPLC-SAXS_skewedGaussian5.png
    A us_somo/somo/doc/manual/somo/somo-HPLC-SAXS_skewedGaussian6a.png
    M us_somo/somo/doc/manual/somo/somo-HPLC-SAXS_skewedGaussian8.png
    M us_somo/somo/doc/manual/somo/somo-HPLC-SAXS_skewedGaussian9a.png
    M us_somo/somo/doc/manual/somo/somo-HPLC-SAXS_skewedGaussian_adv_sel.png
    M us_somo/somo/doc/manual/somo/somo-HPLC-SAXS_smoothing.png
    A us_somo/somo/doc/manual/somo/somo-MALS_Concs.png
    A us_somo/somo/doc/manual/somo/somo-MALS_Concs2.png
    A us_somo/somo/doc/manual/somo/somo-MALS_Concs3.png
    A us_somo/somo/doc/manual/somo/somo-MALS_Concs4.png
    A us_somo/somo/doc/manual/somo/somo-MALS_Gauss1anew.png
    A us_somo/somo/doc/manual/somo/somo-MALS_Gauss1bnew.png
    A us_somo/somo/doc/manual/somo/somo-MALS_Gauss1cnew.png
    A us_somo/somo/doc/manual/somo/somo-MALS_Gauss1dnew.png
    A us_somo/somo/doc/manual/somo/somo-MALS_Gauss1enew.png
    A us_somo/somo/doc/manual/somo/somo-MALS_GaussFit.png
    A us_somo/somo/doc/manual/somo/somo-MALS_Gauss_all_Idash_t_selected.png
    A us_somo/somo/doc/manual/somo/somo-MALS_Gaussian_final.png
    A us_somo/somo/doc/manual/somo/somo-MALS_Gaussian_init.png
    A us_somo/somo/doc/manual/somo/somo-MALS_Gaussian_options.png
    A us_somo/somo/doc/manual/somo/somo-MALS_Gaussian_start.png
    A us_somo/somo/doc/manual/somo/somo-MALS_GlobalFit_done.png
    A us_somo/somo/doc/manual/somo/somo-MALS_GlobalGauss_done.png
    A us_somo/somo/doc/manual/somo/somo-MALS_GlobalGauss_start_pop_up.png
    A us_somo/somo/doc/manual/somo/somo-MALS_GlobalGaussianSDreminder.png
    A us_somo/somo/doc/manual/somo/somo-MALS_GlobalGaussian_init.png
    A us_somo/somo/doc/manual/somo/somo-MALS_I_hash_q_example.png
    A us_somo/somo/doc/manual/somo/somo-MALS_I_starq_NoGauss_movieframe155.png
    A us_somo/somo/doc/manual/somo/somo-MALS_I_starq_NoGauss_movieframe316.png
    A us_somo/somo/doc/manual/somo/somo-MALS_I_starq_NoGauss_movieframe99.png
    A us_somo/somo/doc/manual/somo/somo-MALS_Istarq_file_view_selected.png
    A us_somo/somo/doc/manual/somo/somo-MALS_MakeIdash_final.png
    A us_somo/somo/doc/manual/somo/somo-MALS_MakeIdash_final_kin.png
    A us_somo/somo/doc/manual/somo/somo-MALS_MakeIdash_final_kin_cropped.png
    A us_somo/somo/doc/manual/somo/somo-MALS_MakeIdash_final_kin_zoom.png
    A us_somo/somo/doc/manual/somo/somo-MALS_MakeIstar_final_kin.png
    A us_somo/somo/doc/manual/somo/somo-MALS_MakeIstar_sel_kin_dots_err.png
    A us_somo/somo/doc/manual/somo/somo-MALS_Messages.png
    A us_somo/somo/doc/manual/somo/somo-MALS_Movie_selected.png
    A us_somo/somo/doc/manual/somo/somo-MALS_Plot_Options_demo.png
    A us_somo/somo/doc/manual/somo/somo-MALS_Produced_data.png
    A us_somo/somo/doc/manual/somo/somo-MALS_R_theta_csv_loaded.png
    A us_somo/somo/doc/manual/somo/somo-MALS_R_theta_kin_shown.png
    A us_somo/somo/doc/manual/somo/somo-MALS_R_theta_shown.png
    A us_somo/somo/doc/manual/somo/somo-MALS_Residuals_twocurvesSD.png
    A us_somo/somo/doc/manual/somo/somo-MALS_Residuals_twocurves_percent.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_MALS_data_loglog.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_Make_scaled_popup.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_Messages.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_Plot_Options_demo.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_Plot_Options_demo2.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_Produced_data.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_Produced_data_buttons.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_SAXS_common_times.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_SAXS_common_times_scroll1.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_SAXS_common_times_scroll2.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_SAXS_data_loading.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_bottom line.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_commons times_popup.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_commontimes_all_dots.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_cropping_buttons.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_cropvis_results.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_cropvis_results1.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_cropvis_select.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_exclude_q_vis_demo1.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_exclude_q_vis_demo2.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_fitting_methods.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_generating_joined_excl_q_popup.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_initial.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_joined.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_joined_scroll.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_loadMALS.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_make_scaled.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_make_scaled_popup1.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_make_scaled_popup2.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_make_scaled_view_MALS_file.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_minimize_popup.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_options.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_options1.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_other_MALS_data_popup.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_plot_buttons.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_polynomials.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_q_exclude_buttons.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_remove_panel.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_scale1.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_scale2.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_scale3.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_scale4.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_scale5.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_scale6.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_scale7.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_scale8.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_scaled_MALS_generated_popup.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_scaled_SAXS_generated_popup.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_scroll_warning.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_second_set_buttons.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_second_set_buttons1.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_selections_buttons.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_top_buttons.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_viewselected.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_weighting_methods.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SD_eval_applied.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SD_eval_buttons.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SD_eval_comparisonD2.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SD_eval_define_1region.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SD_eval_define_2regions.png
    A us_somo/somo/doc/manual/somo/somo-MALS_Select_Istarq_for_norm.png
    A us_somo/somo/doc/manual/somo/somo-MALS_Selected_Istarq_normalized.png
    A us_somo/somo/doc/manual/somo/somo-MALS_Selected_Istarq_normalized_ave.png
    A us_somo/somo/doc/manual/somo/somo-MALS_Selected_normalized_ave.png
    A us_somo/somo/doc/manual/somo/somo-MALS_Selected_orig_and_norm_files.png
    A us_somo/somo/doc/manual/somo/somo-MALS_UV_data_pop_up.png
    A us_somo/somo/doc/manual/somo/somo-MALS_adjust_times_pop_up.png
    A us_somo/somo/doc/manual/somo/somo-MALS_adjust_times_pop_up2.png
    A us_somo/somo/doc/manual/somo/somo-MALS_angles_pop_up.png
    A us_somo/somo/doc/manual/somo/somo-MALS_commands1.png
    A us_somo/somo/doc/manual/somo/somo-MALS_conc_chrom_Gauss_fit.png
    A us_somo/somo/doc/manual/somo/somo-MALS_conc_chrom_fit_module.png
    A us_somo/somo/doc/manual/somo/somo-MALS_conc_chrom_init_Gauss.png
    A us_somo/somo/doc/manual/somo/somo-MALS_conc_used_pop_up.png
    A us_somo/somo/doc/manual/somo/somo-MALS_conc_util_add_MALS_data.png
    A us_somo/somo/doc/manual/somo/somo-MALS_conc_util_buttons.png
    A us_somo/somo/doc/manual/somo/somo-MALS_conc_util_loaded_data.png
    A us_somo/somo/doc/manual/somo/somo-MALS_conc_util_pop_up.png
    A us_somo/somo/doc/manual/somo/somo-MALS_conc_util_pop_up2.png
    A us_somo/somo/doc/manual/somo/somo-MALS_conc_util_pop_up3.png
    A us_somo/somo/doc/manual/somo/somo-MALS_conc_util_repeak.png
    A us_somo/somo/doc/manual/somo/somo-MALS_conc_util_timeshift.png
    A us_somo/somo/doc/manual/somo/somo-MALS_conc_util_timeshift_set.png
    A us_somo/somo/doc/manual/somo/somo-MALS_crop_I_dash_chromatograms.png
    A us_somo/somo/doc/manual/somo/somo-MALS_cropping_buttons.png
    A us_somo/somo/doc/manual/somo/somo-MALS_inconsistent times_pop_up.png
    A us_somo/somo/doc/manual/somo/somo-MALS_incorrect processing_param_pop_up.png
    A us_somo/somo/doc/manual/somo/somo-MALS_info_panel.png
    A us_somo/somo/doc/manual/somo/somo-MALS_initial.png
    A us_somo/somo/doc/manual/somo/somo-MALS_main1.png
    A us_somo/somo/doc/manual/somo/somo-MALS_make_Istar_q_enterparam_popup.png
    A us_somo/somo/doc/manual/somo/somo-MALS_make_Istar_q_enterparam_popup1.png
    A us_somo/somo/doc/manual/somo/somo-MALS_make_Istar_q_noGauss_popup.png
    A us_somo/somo/doc/manual/somo/somo-MALS_no_Gaussians_pop_up.png
    A us_somo/somo/doc/manual/somo/somo-MALS_no_conc_pop_up.png
    A us_somo/somo/doc/manual/somo/somo-MALS_no_conc_pop_up2.png
    A us_somo/somo/doc/manual/somo/somo-MALS_options.png
    A us_somo/somo/doc/manual/somo/somo-MALS_options_conc_detector.png
    A us_somo/somo/doc/manual/somo/somo-MALS_options_new_Gaussians.png
    A us_somo/somo/doc/manual/somo/somo-MALS_options_new_misc.png
    A us_somo/somo/doc/manual/somo/somo-MALS_param.png
    A us_somo/somo/doc/manual/somo/somo-MALS_plot_buttons.png
    A us_somo/somo/doc/manual/somo/somo-MALS_processing_param_pop_up.png
    A us_somo/somo/doc/manual/somo/somo-MALS_processing_param_pop_up2.png
    A us_somo/somo/doc/manual/somo/somo-MALS_remove_panel.png
    A us_somo/somo/doc/manual/somo/somo-MALS_resulting_I_starq_NoGauss.png
    A us_somo/somo/doc/manual/somo/somo-MALS_scattering_angles.png
    A us_somo/somo/doc/manual/somo/somo-MALS_second_set_buttons.png
    A us_somo/somo/doc/manual/somo/somo-MALS_selected_Ihash_EMG_GMG.png
    A us_somo/somo/doc/manual/somo/somo-MALS_selections_buttons.png
    A us_somo/somo/doc/manual/somo/somo-MALS_set_conc_detector.png
    A us_somo/somo/doc/manual/somo/somo-MALS_seven_Gaussians1.png
    A us_somo/somo/doc/manual/somo/somo-MALS_seven_Gaussians2.png
    A us_somo/somo/doc/manual/somo/somo-MALS_seven_Gaussians_GlobFit_Final.png
    A us_somo/somo/doc/manual/somo/somo-MALS_seven_Gaussians_GlobFit_Init.png
    A us_somo/somo/doc/manual/somo/somo-MALS_seven_Gaussians_GlobFit_by_q.png
    A us_somo/somo/doc/manual/somo/somo-MALS_seven_Gaussians_GlobFit_saving_warning.png
    A us_somo/somo/doc/manual/somo/somo-MALS_seven_Gaussians_GlobGauss.png
    A us_somo/somo/doc/manual/somo/somo-MALS_seven_Gaussians_scroll1.png
    A us_somo/somo/doc/manual/somo/somo-MALS_seven_Gaussians_scroll2.png
    A us_somo/somo/doc/manual/somo/somo-MALS_six_Gaussians1.png
    A us_somo/somo/doc/manual/somo/somo-MALS_six_Gaussians2.png
    A us_somo/somo/doc/manual/somo/somo-MALS_timeshift_pop_up.png
    A us_somo/somo/doc/manual/somo/somo-MALS_timeshift_pop_up2.png
    A us_somo/somo/doc/manual/somo/somo-MALS_top_buttons.png
    A us_somo/somo/doc/manual/somo/somo-mals_Residuals_twocurves.png
    M us_somo/somo/doc/manual/somo/somo_mals.html
    A us_somo/somo/doc/manual/somo/somo_mals_dctr.html
    A us_somo/somo/doc/manual/somo/somo_mals_options.html
    M us_somo/somo/doc/manual/somo/somo_mals_saxs.html
    M us_somo/somo/doc/manual/somo/somo_saxs_hplc.html
    M us_somo/somo/doc/manual/somo/somo_saxs_hplc_skewedGauss.html
    M us_somo/somo/doc/manual/somo/somo_uv_vis.html
    A us_somo/somo/doc/manual/somo_mals.html

  Log Message:
  -----------
  updates

(cherry picked from commit 49c520dd6e3d16b673ad0910be2babff8248d06c)


  Commit: 83812c32b6170758681426f592f85149c1224c39
      https://github.com/ehb54/ultrascan3/commit/83812c32b6170758681426f592f85149c1224c39
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    A test_data/extrap_c0_test_iqq.csv
    A test_data/extrap_c0_test_iqq_poisson.csv
    A test_data/gen_extrap_c0_test_iqq.py
    M us_somo/develop/src/us_hydrodyn_saxs_iqq_extrap_c0.cpp
    M us_somo/develop/src/us_hydrodyn_saxs_iqq_extrap_c0_conc.cpp

  Log Message:
  -----------
  Fix conc_csv name-key mismatch, widen conc dialog, fix cancel flow, raw test data

- do_extrap_c0: prepopulation lookup and write-back now also try the
  dequoted curve name against conc_csv, fixing concentrations not being
  found for curves pushed in from SAXS Hplc (to_saxs() keys conc_csv by
  the bare unquoted plotted name, while curves selected via the "just
  plotted curves" load path are quoted to match the CSV-row convention).
- Cancelling the concentration-assignment dialog now raises/shows the
  main plot window and logs a message instead of silently returning.
- The concentration-assignment dialog is now sized to the longest
  selected curve name instead of a fixed width.
- Regenerated the synthetic test CSVs to use raw, concentration-
  proportional intensities (I(0) scales with c, plus a small
  structure-factor-like nonlinearity) instead of pre-normalized
  intensities, since load_iqq_csv curves are expected to be raw.

Co-Authored-By: Claude Sonnet 4.6 <noreply at anthropic.com>
(cherry picked from commit 1ecc8ce4ff282a725727bdc3f76ceb6b57104f78)


  Commit: 453997ee9d045b0b324ae9e050aee9154f996dee
      https://github.com/ehb54/ultrascan3/commit/453997ee9d045b0b324ae9e050aee9154f996dee
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/src/us_hydrodyn_saxs_loads.cpp

  Log Message:
  -----------
  Parse Conc:/PSV:/I0se: header tags when loading .dat/.txt/.sprr directly

load_saxs() and load_sans() (the main SAXS/SANS window's direct file
loader, used when picking individual .dat/.txt/.sprr files rather than
going through the HPLC module) never read the Conc:/PSV:/I0se: header
comment line, so conc_csv was never populated for curves loaded this
way -- do_extrap_c0's concentration pre-population had nothing to find.
Reuses the exact regexes already established in
US_Hydrodyn_Saxs_Hplc::load_file() and calls update_conc_csv() right
after the curve is plotted, keyed by the same name plot_one_iqq() uses.

Co-Authored-By: Claude Sonnet 4.6 <noreply at anthropic.com>
(cherry picked from commit e54705492a8105b4997dc81f9b3ed185ab60a43b)


  Commit: 5bcec47256f2a2c9a0210a36550e3ce0086d287a
      https://github.com/ehb54/ultrascan3/commit/5bcec47256f2a2c9a0210a36550e3ce0086d287a
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/src/us_hydrodyn_saxs_iqq_extrap_c0.cpp

  Log Message:
  -----------
  Normalize by concentration before per-q regression in do_extrap_c0

Raw SAXS intensity is dominated by a term directly proportional to
concentration, so fitting raw I(q) vs c trivially extrapolates to ~0
at c=0 -- confirmed on real asyn data, where the output curve was
just noise oscillating around zero. The standard SAXS technique (the
Zimm-plot analogue) fits I(q,c)/c against c instead; its c=0 intercept
recovers the ideal, structure-factor-free dilute-limit curve.

Concentration (x-axis) stays the real, distinct entered values --
only the intensity (y-axis) is divided by each curve's own
concentration. Curves with concentration <= 0 are excluded from the
regression (can't normalize by zero) with a warning. Output curve is
now in concentration-normalized units, noted in the summary message.

Validated against the 6 real asyn .dat files: the normalized
intercept now produces a smooth, positive, Guinier-shaped curve
instead of near-zero noise.

Co-Authored-By: Claude Sonnet 4.6 <noreply at anthropic.com>
(cherry picked from commit 2d5bca3b5b3a7110db6eefcdb28ef3ff644fad9c)


  Commit: e6dd622e498cb0737196bd2d3b2759cd3202e3ed
      https://github.com/ehb54/ultrascan3/commit/e6dd622e498cb0737196bd2d3b2759cd3202e3ed
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/src/us_hydrodyn_saxs_iqq_extrap_c0.cpp

  Log Message:
  -----------
  Tag extrap_c0 output curve as concentration-normalized (Conc:1)

The extrapolated curve is I(q)/c extrapolated to c=0, i.e. already
concentration-normalized -- mark it conc=1 in conc_csv per SOMO's
existing Conc:1-means-normalized convention, so anything downstream
that respects conc_csv (e.g. selecting it for a further extrapolation)
treats it correctly rather than as a raw curve with concentration 1.

Co-Authored-By: Claude Sonnet 4.6 <noreply at anthropic.com>
(cherry picked from commit 0df3387554c95a4ed1d6c69615a7e992e584a4ef)


  Commit: f0de9a1a24aabf066eb46de10d36c9eb4dd2d2ff
      https://github.com/ehb54/ultrascan3/commit/f0de9a1a24aabf066eb46de10d36c9eb4dd2d2ff
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/src/us_hydrodyn_saxs_iqq_load_csv.cpp

  Log Message:
  -----------
  Don't clear the plot before extrapolate-to-zero-conc has been confirmed

load_iqq_csv() clears the entire plot right after the load dialog
closes, whenever "Clear plot" is checked (the default) -- this
happened unconditionally before the new concentration-assignment
dialog even opened, so cancelling that dialog left the user with an
empty plot and no way to recover the previously plotted curves.

run_ift already avoids this exact problem by force-disabling "Clear
plot" while it's active; set_extrapolate_c0() now does the same, so
the plot is left untouched until/unless the extrapolation actually
completes.

Co-Authored-By: Claude Sonnet 4.6 <noreply at anthropic.com>
(cherry picked from commit 243154e9c162112ff1cc51a473c9da664e041c38)


  Commit: b0d1074b4720e6b91e0e9ec9cd3be69ea4a08210
      https://github.com/ehb54/ultrascan3/commit/b0d1074b4720e6b91e0e9ec9cd3be69ea4a08210
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/include/us_hydrodyn_saxs_hplc.h
    M us_somo/develop/src/us_hydrodyn_saxs.cpp
    M us_somo/develop/src/us_hydrodyn_saxs_hplc.cpp

  Log Message:
  -----------
  Propagate concentrations when pushing curves from SOMO SAS to HPLC

US_Hydrodyn_Saxs::saxs_hplc() (the "Hplc/Saxs" button in SOMO SAS) added
curves to the HPLC window via add_plot() with no concentration at all,
so f_conc in HPLC was always 0/unknown for curves arriving this way --
the reverse direction of the to_saxs() push, which already carried
concentration across.

- US_Hydrodyn_Saxs_Hplc::add_plot() (both overloads) gains an optional
  trailing conc parameter (default -1, meaning "not specified", fully
  backward compatible with existing callers); when >= 0 it's written to
  f_conc, overriding the previous "preserve existing or default 0e0"
  fallback.
- saxs_hplc() now looks up each plotted curve's concentration via the
  SAXS window's own get_conc_csv_values() and passes it through.
- update_csv_conc() (HPLC's own "Solution Concentrations" table) now
  backfills new rows from f_conc instead of seeding them blank, so a
  propagated concentration is also visible in that window, not just
  used internally.

Co-Authored-By: Claude Sonnet 4.6 <noreply at anthropic.com>
(cherry picked from commit 5e5d55ff38ee408d8bfb00d765599dbcf1acdb7f)


  Commit: a5b477eb4e1da534c8e3be3e8193c785b55fe1a2
      https://github.com/ehb54/ultrascan3/commit/a5b477eb4e1da534c8e3be3e8193c785b55fe1a2
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/src/us_hydrodyn_dad_conc.cpp
    M us_somo/develop/src/us_hydrodyn_dad_conc_load.cpp
    M us_somo/develop/src/us_hydrodyn_mals_conc.cpp
    M us_somo/develop/src/us_hydrodyn_mals_conc_load.cpp
    M us_somo/develop/src/us_hydrodyn_mals_saxs_conc.cpp
    M us_somo/develop/src/us_hydrodyn_mals_saxs_conc_load.cpp
    M us_somo/develop/src/us_hydrodyn_saxs_buffer_conc.cpp
    M us_somo/develop/src/us_hydrodyn_saxs_buffer_conc_load.cpp
    M us_somo/develop/src/us_hydrodyn_saxs_hplc_conc.cpp
    M us_somo/develop/src/us_hydrodyn_saxs_hplc_conc_load.cpp

  Log Message:
  -----------
  Fix "No such signal QHeaderView::released(int)" warning in conc dialogs

QHeaderView::released(int) is a Qt3/Qt4 signal name that doesn't exist
in Qt5 (it's the column/row header click handler in the various
"Concentrations" table dialogs across DAD, MALS, MALS+SAXS, SAXS,
SAXS buffer, and SAXS Hplc/Kin). The connect() silently failed at
runtime with a console warning, and the header-click slot (col/row
_header_released) never fired.

us_hydrodyn_saxs_conc.cpp already had the correct fix, properly guarded
behind #if QT_VERSION < 0x040000 / #else sectionClicked(int) / #endif --
the other 10 copy-pasted variants of this dialog never got that fix and
had the broken signal name unconditionally. Replaced with
sectionClicked(int) (the Qt5 equivalent) in all of them, matching the
already-proven-working pattern.

Co-Authored-By: Claude Sonnet 4.6 <noreply at anthropic.com>
(cherry picked from commit c7ebdda2f2175331c0231fbc2fe4e7cc9eebbeda)


  Commit: 8b7f2758868445e7176e7a99d00f8e15e417e826
      https://github.com/ehb54/ultrascan3/commit/8b7f2758868445e7176e7a99d00f8e15e417e826
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    R test_data/extrap_c0_test_iqq.csv
    R test_data/extrap_c0_test_iqq_poisson.csv
    R test_data/gen_extrap_c0_test_iqq.py

  Log Message:
  -----------
  Remove test data from top-level test_data/

Synthetic CSV fixtures and the generator script do not belong committed
to the repo, least of all in a top-level directory.

(cherry picked from commit 7f1178ad2883095f6ddaee0b8da45ee644b1d378)


  Commit: fc4a2ca4b6d0f2ae5ea4069dc8363d34bc497347
      https://github.com/ehb54/ultrascan3/commit/fc4a2ca4b6d0f2ae5ea4069dc8363d34bc497347
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/include/us_hydrodyn_dad_fit.h
    M us_somo/develop/include/us_hydrodyn_dad_options.h
    M us_somo/develop/include/us_hydrodyn_mals_fit.h
    M us_somo/develop/include/us_hydrodyn_mals_options.h
    M us_somo/develop/include/us_hydrodyn_mals_saxs_fit.h
    M us_somo/develop/include/us_hydrodyn_mals_saxs_options.h
    M us_somo/develop/src/us_hydrodyn_dad.cpp
    M us_somo/develop/src/us_hydrodyn_dad_fit.cpp
    M us_somo/develop/src/us_hydrodyn_dad_options.cpp
    M us_somo/develop/src/us_hydrodyn_dad_util.cpp
    M us_somo/develop/src/us_hydrodyn_mals.cpp
    M us_somo/develop/src/us_hydrodyn_mals_fit.cpp
    M us_somo/develop/src/us_hydrodyn_mals_options.cpp
    M us_somo/develop/src/us_hydrodyn_mals_saxs.cpp
    M us_somo/develop/src/us_hydrodyn_mals_saxs_fit.cpp
    M us_somo/develop/src/us_hydrodyn_mals_saxs_options.cpp
    M us_somo/develop/src/us_hydrodyn_mals_saxs_util.cpp
    M us_somo/develop/src/us_hydrodyn_mals_util.cpp

  Log Message:
  -----------
  Roll out per-amplitude Gaussian minimum to dad/mals/mals_saxs fit modules

HPLC's Gaussian fit split its single amplitude-and-width floor
(hplc_ampl_width_min) into two independent minimums: the pre-existing
one continues to bound width, while the new hplc_ampl_min bounds
amplitude. The sibling dad/mals/mals_saxs SAXS fit modules were never
updated to match, so their amplitude clamp (in setup_run and
lock_zeros) still reuses the combined width_min value.

Add the same ampl_min gparam, options-dialog widget, and fit-module
member to dad, mals, and mals_saxs, and repoint their amplitude clamp
logic at it, mirroring hplc_fit.cpp/hplc_options.cpp/hplc.cpp exactly.

(cherry picked from commit 768ca91ff963992cfbb912f512740052402f1fac)


  Commit: a8b09fc57895d9cdee9a8f7d13937c15c0cbf9be
      https://github.com/ehb54/ultrascan3/commit/a8b09fc57895d9cdee9a8f7d13937c15c0cbf9be
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/src/us_hydrodyn_saxs_hplc.cpp

  Log Message:
  -----------
  Fix SIGSEGV in HPLC SAXS get_peak: use file, not wheel_file, for end-range clamp

get_peak() operates on its `file` argument, but the gauss-fit-end range
clamp compared the typed value against f_qs[ wheel_file ].back() instead
of f_qs[ file ].back(). During Repeak, wheel_file is stale or empty (it is
never set in repeak()), so f_qs[ wheel_file ] default-inserts an empty
vector and .back() dereferences nullptr-8 (0xfffffffffffffff8), crashing.

The check is now symmetric with the start-range clamp above and with its
own body on the next line, both of which key on `file`.

Co-Authored-By: Claude Fable 5 <noreply at anthropic.com>
(cherry picked from commit f087cb2f504871f6f79df846004b7ea6f0926d57)


  Commit: 60e7a3010157adf3e83d93001aac6ddde8941eb0
      https://github.com/ehb54/ultrascan3/commit/60e7a3010157adf3e83d93001aac6ddde8941eb0
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/src/us_hydrodyn_saxs_hplc_ciq.cpp
    M us_somo/develop/src/us_hydrodyn_saxs_hplc_options.cpp
    M us_somo/somo/doc/manual/somo/saxs_hplc_ciq.html
    M us_somo/somo/doc/manual/somo/somo_saxs_hplc.html

  Log Message:
  -----------
  HPLC/KIN Make I(q): clarify the top-% peak average retains concentration

Relabel the "average and normalize" checkbox to "average", add a tooltip,
and update the manual, to make explicit that the existing per-peak "_avg"
curve is scaled to the mean concentration of the averaged frames (the
concentration-scaled result, for Guinier/MW) while "_avg_n" is normalized
to concentration 1.0. No change to the averaging computation.

Co-Authored-By: Claude Opus 4.8 <noreply at anthropic.com>
(cherry picked from commit c48d229f1006f0bd3360ff1fdf821482d198087d)


  Commit: 11b1c559a69cc8667517e7b2ba9262e5db4d5b16
      https://github.com/ehb54/ultrascan3/commit/11b1c559a69cc8667517e7b2ba9262e5db4d5b16
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/src/us_hydrodyn_saxs_hplc_ciq.cpp
    M us_somo/develop/src/us_hydrodyn_saxs_hplc_options.cpp

  Log Message:
  -----------
  Format Make I(q) average tooltip with HTML line breaks

Qt renders the tooltip as rich text, so split the single run-on line into
per-suffix lines with <br> for readability.

Co-Authored-By: Claude Opus 4.8 <noreply at anthropic.com>
(cherry picked from commit 36a225651effc35e6944ed6c878c58c8ba575af1)


  Commit: 72cdaaa4b996bff8a55e29257e8c19be52ae60ce
      https://github.com/ehb54/ultrascan3/commit/72cdaaa4b996bff8a55e29257e8c19be52ae60ce
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/include/us_vector.h
    M us_somo/develop/src/us_hydrodyn_dad_util.cpp
    M us_somo/develop/src/us_hydrodyn_mals_saxs_util.cpp
    M us_somo/develop/src/us_hydrodyn_mals_util.cpp
    M us_somo/develop/src/us_hydrodyn_saxs_buffer.cpp
    M us_somo/develop/src/us_hydrodyn_saxs_hplc_util.cpp
    M us_somo/develop/src/us_vector.cpp
    M us_somo/somo/doc/manual/somo/somo_mals.html
    M us_somo/somo/doc/manual/somo/somo_mals_saxs.html
    M us_somo/somo/doc/manual/somo/somo_saxs_hplc.html
    M us_somo/somo/doc/manual/somo/somo_uv_vis.html

  Log Message:
  -----------
  Fix Crop Common dropping points due to 6-sig-fig q rounding

Crop Common built the shared grid via US_Vector::intersection(), which
matches q values by exact double equality. Because .dat files store q to
6 significant figures, the same physical q point is rounded slightly
differently between files (e.g. 0.00547318 vs 0.00547317), so those
points missed the exact match and were dropped, leaving "holes" in the
common grid. On a set of 7 AlphaSyn HPLC curves this cut the common grid
from ~1053 points to 803.

Add US_Vector::canonical_map(), which clusters q values whose relative
gap is <= reltol (1e-4) and maps each to a canonical representative. A
cluster/tolerance merge (rather than fixed-grid rounding) is used so that
near-identical values never straddle a bin boundary. crop_common() snaps
the grids through this map before intersecting and uses the same map for
the per-curve filter; retained points keep their original q/I/sd values.

Applied to all five crop_common paths: SAXS HPLC/KIN, MALS, DAD (UV/Vis),
MALS-SAXS, and SAXS Buffer. Manual pages updated accordingly. On the 7
test curves the common grid is restored to 1045 points with no
over-merging (min real relative gap 8.3e-4, well above the 1e-4 tol).

Fixes ehb54/ultrascan-tickets#962

Co-Authored-By: Claude Opus 4.8 <noreply at anthropic.com>
(cherry picked from commit e4097b6c1c59016b3be6e5cce40619c1bbbe0689)


  Commit: 67a51f95783c0c068a3103a4ef0ec219d9ec5ea9
      https://github.com/ehb54/ultrascan3/commit/67a51f95783c0c068a3103a4ef0ec219d9ec5ea9
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/include/us_saxs_util.h
    M us_somo/develop/src/us_saxs_util_static.cpp

  Log Message:
  -----------
  Add US_Saxs_Util::recompute_errors: standalone I(q) error reassessment

Reproduces the spirit of BayesApp's error-assessment stage (Larsen &
Pedersen, J. Appl. Cryst. 2021) without a BIFT fit. A local weighted
quadratic smoother of I(q) supplies residuals and an effective DoF
(hat-trace); a reduced chi-square and two-sided chi-square p-value
(clean-room regularized incomplete gamma) drive the same significance +
>10% gate as bift.f. Rescales sigma in three modes: constant, non-constant
(per-bin, triangular-smoothed) and intensity-dependent.

Standalone approximation only: no p(r) model, no Ng, no Dmax. Documented
as such in the header.

Implements ehb54/ultrascan-tickets#966

Co-Authored-By: Claude Fable 5 <noreply at anthropic.com>
(cherry picked from commit 0febd2d9418b15f336c31d64e3a6dba485aa3bdb)


  Commit: 594fe20f9823a2ff9fc847e5f33fce4498a03424
      https://github.com/ehb54/ultrascan3/commit/594fe20f9823a2ff9fc847e5f33fce4498a03424
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/include/us_saxs_util.h
    M us_somo/develop/src/us_saxs_util_static.cpp

  Log Message:
  -----------
  Guard recompute_errors mode 'I' against negative/zero-crossing intensities

On background-subtracted or extrapolated curves I(q) crosses zero, and the
signed intensity term sigma+a*I could go negative, blowing up the a search
and emitting negative sigma (observed factors -13..1087 on real data). Use
sigma+a*|I| so the term is always >= sigma > 0. Add a general safety clamp
so no mode ever writes a non-positive or non-finite sigma (degenerate factor
falls back to 1). Modes C and N are unchanged.

Implements ehb54/ultrascan-tickets#966

Co-Authored-By: Claude Fable 5 <noreply at anthropic.com>
(cherry picked from commit 17b63846933b108cf79aa0781ecab9fe533859f5)


  Commit: f35defbfd26be62b9c001bc8336309dae4823817
      https://github.com/ehb54/ultrascan3/commit/f35defbfd26be62b9c001bc8336309dae4823817
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/include/us_hydrodyn_saxs_hplc.h
    M us_somo/develop/src/us_hydrodyn_saxs_hplc_gui.cpp
    M us_somo/develop/src/us_hydrodyn_saxs_hplc_modes.cpp

  Log Message:
  -----------
  Add "SD rescale" button to HPLC/KIN s.d.util mode

Third button in the s.d.util row (alongside "SD eval."/"SD apply") that runs
US_Saxs_Util::recompute_errors on the selected curves. Prompts for the mode
(constant / non-constant / intensity-dependent) via US_Static::getItem (avoids
the OSX QInputDialog-in-slot bug), rescales each curve's SD in place, and logs
the verdict/chi2r/p per curve.

Undo: one full-restore crop_undo_data record per invocation, so the existing
"Crop undo" restores the original SDs. Enabled only for selected q-space curves
that already carry usable errors (all_selected_have_errors: count + matching
size + is_nonzero_vector). Curves lacking usable SDs are skipped with a message.

Implements ehb54/ultrascan-tickets#966

Co-Authored-By: Claude Fable 5 <noreply at anthropic.com>
(cherry picked from commit 1e0ed9e1faa70de51dffaff5c11c397b7fa02903)


  Commit: 8b271168f96e0b1880eaba2c710b8f868c6d492e
      https://github.com/ehb54/ultrascan3/commit/8b271168f96e0b1880eaba2c710b8f868c6d492e
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/include/us_hydrodyn_saxs_hplc.h
    M us_somo/develop/src/us_hydrodyn_saxs_hplc_modes.cpp

  Log Message:
  -----------
  Relax SD rescale gate: accept curves with some zero SDs

recompute_errors already excludes individual zero/negative points, so the
gate need only reject all-zero (placeholder) error vectors. Replace the strict
is_nonzero_vector (all non-zero) test with sd_has_usable_errors (at least one
positive value) in both the enable helper and the per-curve skip. Curves with
a few masked/zero-error points are now processed instead of skipped wholesale.

Implements ehb54/ultrascan-tickets#966

Co-Authored-By: Claude Fable 5 <noreply at anthropic.com>
(cherry picked from commit 5a703361099d4bb8304d7a5477af0bfbc32fb3d7)


  Commit: a6023d9d7b3b7d99436d7db24fa924bffb141d5c
      https://github.com/ehb54/ultrascan3/commit/a6023d9d7b3b7d99436d7db24fa924bffb141d5c
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/src/us_hydrodyn_saxs_hplc_modes.cpp

  Log Message:
  -----------
  Show applied scale factor in SD rescale log

The per-curve log now reports the applied factor, not just reduced chi-square:
"factor X" for constant mode (X = sqrt(chi2r)), or "factor median X (min..max)"
for the per-point non-constant / intensity modes. Captures scale_factors from
recompute_errors for the summary.

Implements ehb54/ultrascan-tickets#966

Co-Authored-By: Claude Fable 5 <noreply at anthropic.com>
(cherry picked from commit b29844fdcf97dde3af2de461f20571d1663441dc)


  Commit: 8edd07ed0f01d08dde239c8a5e099d4ca3251666
      https://github.com/ehb54/ultrascan3/commit/8edd07ed0f01d08dde239c8a5e099d4ca3251666
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/src/us_hydrodyn_saxs_hplc_modes.cpp

  Log Message:
  -----------
  Display SD rescale p-value as fixed-point (3 decimals)

Fixed-point 'f' with 3 decimals instead of 'g' scientific notation, so tiny
p-values read as 0.000 rather than e.g. 8.71e-31, while keeping the 0.003
significance threshold legible.

Implements ehb54/ultrascan-tickets#966

Co-Authored-By: Claude Fable 5 <noreply at anthropic.com>
(cherry picked from commit 7a16b4d8ffd418112c7a52a607c5d2da07f36e88)


  Commit: af6583836254ecf8e8d892046d513c1efa43298c
      https://github.com/ehb54/ultrascan3/commit/af6583836254ecf8e8d892046d513c1efa43298c
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/somo/doc/manual/somo/somo_saxs_hplc.html

  Log Message:
  -----------
  Document "SD rescale" in HPLC/KIN manual (S.D. Util section)

Add a subsection to the S.D. Util documentation in somo_saxs_hplc.html
describing the new "SD rescale" button: purpose (assess/rescale existing
I(q) errors, vs the baseline-fluctuation SD estimation of eval/apply), the
BayesApp-based method and significance gate, the three modes (constant /
non-constant / intensity-dependent), verdict/factor reporting in Messages,
and undo. Updates the button count (two -> three) and cross-links the
SAS IFT / BayesApp module.

Implements ehb54/ultrascan-tickets#966

Co-Authored-By: Claude Fable 5 <noreply at anthropic.com>
(cherry picked from commit bd64fd69edefe841b82676a7f5e8fa1faa437d88)


  Commit: 74ad6e7883e00a73bdbf492eeee6c9bc1dddb861
      https://github.com/ehb54/ultrascan3/commit/74ad6e7883e00a73bdbf492eeee6c9bc1dddb861
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/somo/doc/manual/somo/somo_saxs_hplc.html

  Log Message:
  -----------
  Update last-edited dates on HPLC manual page

Bump "Last updated" (header) and "Last modified" (footer) to July 2026 / July
13, 2026 to reflect the SD rescale documentation addition.

Implements ehb54/ultrascan-tickets#966

Co-Authored-By: Claude Fable 5 <noreply at anthropic.com>
(cherry picked from commit a92ff44060c764135af406f73ec97b7635aaec33)


  Commit: c13477427138bde8333cba604db74d266afd1248
      https://github.com/ehb54/ultrascan3/commit/c13477427138bde8333cba604db74d266afd1248
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/etc/somo.residue.new

  Log Message:
  -----------
  Fix deoxynucleotide C2' hybridization: C4H1 -> C4H2

Deoxyribose C2' is bonded to C1', C3' and two hydrogens, so it is a CH2
(C4H2, 14.03). It was typed C4H1 (13.02), the ribose value, where C2'
carries O2' and only one hydrogen.

The deoxy blocks were created by copying the corresponding ribo block and
deleting the O2' atom line, but C2' was never retyped. Every deoxy residue
therefore came out 1.01 Da light, and since residue mass is the sum of its
atom hybrid masses, the error propagated into MW, vbar-weighted quantities
and bead masses for every DNA run.

Corrected in all 22 affected blocks (DA/DC/DG/DT, both the primed and the
starred atom-naming variants, with and without phosphate). Each deoxy
residue is now exactly 16.00 Da below its ribo counterpart, i.e. the loss
of one oxygen and nothing else; previously the gap was 17.01 Da:

  A ->DA   266.27 -> 250.27  (-16.00, was -17.01)
  C ->DC   242.24 -> 226.24  (-16.00, was -17.01)
  G ->DG   282.27 -> 266.27  (-16.00, was -17.01)
  U ->DT   243.22 -> 241.25  (-1.97 = -O +CH2, was -2.98)

Ribose C2' (A/C/G/U, and sugars such as LMT) is untouched.

Co-Authored-By: Claude Fable 5 <noreply at anthropic.com>
(cherry picked from commit 53f39f42b231277e413ace83e548826caa3ab7a4)


  Commit: e72f1ea8918a6d6c85b50da8eebda6f2c01fa687
      https://github.com/ehb54/ultrascan3/commit/e72f1ea8918a6d6c85b50da8eebda6f2c01fa687
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/etc/somo.atom.new
    M us_somo/etc/somo.hybrid.new
    M us_somo/etc/somo.residue.new
    M us_somo/etc/somo.saxs_atoms.new

  Log Message:
  -----------
  Add molybdenum cluster support to the SOMO parameter files

Adopts the additive part of Mattia's updated parameter files: support for
polyoxomolybdate clusters, which previously could not be typed at all.

  somo.hybrid      O2H02- (oxide O2-), MO+5, MO+6
  somo.atom        MO1-MO6 as MO+6, MO7/MO8 as MO+5; O2H02- oxide, O2H2
                   water and further O1H0 entries for the O1-O27 cluster
                   oxygens (38 rows)
  somo.saxs_atoms  Cromer-Mann form factors for MO+5 and MO+6, both the
                   9- and 11-parameter variants, matching the MO+3 rows
  somo.residue     two new residues, Molybdenum Cluster Subunit 1 (MO2)
                   and Subunit 2 (MO6)

Purely additive - no existing row is modified, so no current result can
change. Verified: every hybrid referenced by somo.residue resolves in
somo.hybrid; every (atom name, hybrid) pair used by the two new residues
exists in somo.atom; and the new electron counts are correct for Z minus
formal charge (O2- 10, MO+5 37, MO+6 36).

Mattia's copy of somo.residue predates 78465e20, so it is missing glucose;
GLC is deliberately retained here and only his new blocks were taken.

Co-Authored-By: Claude Fable 5 <noreply at anthropic.com>
(cherry picked from commit 4ae31a8922b1bca3ae30d07dd6f66d2b5ac7c3bb)


  Commit: a9aa09407e096821c9b10d7d9cebe126eeaefa35
      https://github.com/ehb54/ultrascan3/commit/a9aa09407e096821c9b10d7d9cebe126eeaefa35
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/etc/somo.atom.new

  Log Message:
  -----------
  Fix SAXS excluded volume for four hydroxyl entries in somo.atom

O10, O1A, O1B and O1N carried 9.13 A^3 as their O2H1 excluded volume, the
value belonging to a bare oxygen (O1H0/O2H0), rather than the 14.28 A^3 used
by every other hydroxyl. The four rows sit directly below O1H0/O2H0 rows for
the same atom names, so this reads as a copy-paste slip.

All 43 O2H1 rows in the file now use 14.28; before this change 39 did and
these 4 did not. Affects the excluded-volume term in SAXS curve computation
for structures containing those atom names.

>From Mattia's updated parameter files.

Co-Authored-By: Claude Fable 5 <noreply at anthropic.com>
(cherry picked from commit b112dfd5c5fe820c5ddbac261d394c8ea900d844)


  Commit: 28513ea99afa5c73f156a8b3d2272c2778436309
      https://github.com/ehb54/ultrascan3/commit/28513ea99afa5c73f156a8b3d2272c2778436309
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/etc/somo.residue.new

  Log Message:
  -----------
  Fix NDP ionized-state vbar: 0.599 -> 0.589

NADPH (NDP) declared vbar 0.589 for the neutral form but 0.599 for both
ionized states. 0.599 is NAD's vbar, and the NDP header otherwise matches
NAD's line, so the two ionized values were carried over when the entry was
copied from NAD.

Every other multi-state residue in the file repeats the same vbar across all
of its protonation states; NDP was the only one of the 20 that did not. It
now uses 0.589 throughout, so vbar no longer jumps by 1.7% as a function of
pH for NADPH-containing models.

>From Mattia's updated parameter files.

Co-Authored-By: Claude Fable 5 <noreply at anthropic.com>
(cherry picked from commit 1f0b373b0887e359bf2dd08e7ef193f0800b2f56)


  Commit: 9824edf652a077a177249c8fcd75334812927028
      https://github.com/ehb54/ultrascan3/commit/9824edf652a077a177249c8fcd75334812927028
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/etc/somo.atom.new
    M us_somo/etc/somo.hybrid.new

  Log Message:
  -----------
  Set MO+3 radius to 0.69, completing the Mo series

Mattia changed the Mo(III) radius from 0.83 to 0.69 A in both somo.atom and
somo.hybrid when adding the MO+5 and MO+6 entries, and has confirmed 0.69 is
the value to use.

This makes the three Mo radii one consistently sourced set: 0.69 (+3), 0.61
(+5) and 0.73 (+6) are Shannon effective ionic radii, six-coordinate for
Mo(III) and Mo(V) and seven-coordinate for Mo(VI). The previous 0.83
corresponds to no standard Mo radius; it entered in 623ce9cc (2020) with the
multi-pKa support files, with no stated source.

Note for anyone reading the table later: the radius rises from +3 to +6
rather than falling, because the Mo(VI) value is seven-coordinate while the
other two are six-coordinate. That is intentional, not a transcription error.

Unlike the rest of this branch this change is not additive. It alters bead
radii, and hence hydrodynamic results, for existing structures containing
Mo(III).

Co-Authored-By: Claude Fable 5 <noreply at anthropic.com>
(cherry picked from commit f00f0bfd2facda5de8de10142e040f2c8b2db1e9)


  Commit: cb2ddab2bd73029d48eec94ae894f8b049fa6412
      https://github.com/ehb54/ultrascan3/commit/cb2ddab2bd73029d48eec94ae894f8b049fa6412
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/etc/somo.atom.new

  Log Message:
  -----------
  Complete the SAXS excluded volume fix: 31 further rows in somo.atom

Extends the O2H1 correction to every other row carrying the same mistake.

Throughout somo.atom a hybrid's excluded volume is the bare heavy-atom value
plus 5.15 A^3 per attached hydrogen, 5.15 being hydrogen's own excluded volume
in somo.saxs_atoms. These 31 rows carried the bare value despite the hybrid
having hydrogens, i.e. the hydrogen contribution was omitted:

  C4H3  16.44 -> 31.89  x20   C13 C15 C1Q C1R C1T C1U C2 C20 C22 C25 C28
                              C2A C3 C35 C36 C38 C3P C4 C42 C5
  C4H2  16.44 -> 26.74  x8    C14 C15 C16 C17 C18 C19 C1P C21
  C3H2  16.44 -> 26.74  x2    CBB CBC
  C4H1  16.44 -> 21.59  x1    C40

With the four O2H1 rows already corrected earlier on this branch, all 35 rows
of this error class are now consistent. The number of hybrids carrying more
than one excluded volume drops from 6 to 2.

Four rows deviate from the rule in some other way and are deliberately left
untouched, since they need a judgement call rather than arithmetic:

  SG   S2H1   25.1   rule gives 25.01  - looks like a dropped digit, but the
                                         effect is negligible either way
  NE2  N3H1+  12.79  rule gives  7.64  - carries the two-hydrogen value while
                                         its mass 15.02 says one hydrogen
  B    B4H0    2.14  rule gives 29.65  - 2.14 is boron's volume in
                                         somo.saxs_atoms; B1/B2 use 29.65
  OW   O2H2   24     rule gives 19.43  - water oxygen; 24 may well be
                                         deliberate for explicit water

Affects the excluded-volume term in SAXS curve computation for structures
containing these atom names.

Co-Authored-By: Claude Fable 5 <noreply at anthropic.com>
(cherry picked from commit be9437cf7e072474c7e06337c0716df2ad1d3c34)


  Commit: 423cb795720c1c37ee6a486b4875c87755d11650
      https://github.com/ehb54/ultrascan3/commit/423cb795720c1c37ee6a486b4875c87755d11650
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/include/us_hydrodyn_dad.h
    M us_somo/develop/libus_somo.pro
    M us_somo/develop/src/us_hydrodyn.cpp
    M us_somo/develop/src/us_hydrodyn_dad.cpp
    A us_somo/develop/src/us_hydrodyn_dad_script.cpp
    M us_somo/develop/src/us_hydrodyn_dad_util.cpp
    M us_somo/develop/src/us_hydrodyn_script.cpp

  Log Message:
  -----------
  Add gui_script commands for the UV-Vis module

The UV-Vis module had no scripted path: gui_script knew nothing about it
and us_saxs_cmds_t does not reach it, so every change to the module could
only be exercised by hand in the GUI.

Add a "dad" command family to gui_script_run(): open, settimes,
lambdarange, lambdas, load, list, select, makealambda and save. Together
these load a wavelength list and an absorption matrix, build the A(t)
curves, make A(lambda) and write the results, with no interaction.

That needs the module to run without dialogs, so US_Hydrodyn_Dad gains a
script_mode plus the values dad_load() would otherwise prompt for. With
it set, the wavelength confirmation, the wavelength crop and the start
time and interval dialogs are all answered from the script. The
non-interactive entry points live in a new us_hydrodyn_dad_script.cpp.

Also add saxs_options iqscaleangstrom and iqscalenm, since whether q
values are converted from 1/nm on load was otherwise unreachable from a
script.

dad open reaches US_Hydrodyn_Saxs::dad() through the meta-object rather
than making the slot public, so no interface widens for scripting alone.

Fix an unrelated crash found by the first script run: US_Hydrodyn's
constructor initialises around thirty *_widget flags but misses
dad_widget, mals_widget and mals_saxs_widget, added later with those
windows, and nulls no window pointer. US_Hydrodyn_Saxs::dad(), mals()
and mals_saxs() test the flag and then dereference the matching window,
so an indeterminate read is a segmentation fault. Interactive runs
survive on zeroed heap; the headless run did not.

Refs ehb54/ultrascan-tickets#994

Co-Authored-By: Claude Opus 5 <noreply at anthropic.com>
(cherry picked from commit 6c91cf6a276ec740abe198a0a3421a3eddd91daf)


  Commit: b441643ba9b56c66d857d7461f9dc583071573da
      https://github.com/ehb54/ultrascan3/commit/b441643ba9b56c66d857d7461f9dc583071573da
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/include/us_hydrodyn.h
    M us_somo/develop/include/us_hydrodyn_pdb_parsing.h
    M us_somo/develop/src/us_hydrodyn_load.cpp
    M us_somo/develop/src/us_hydrodyn_other.cpp
    M us_somo/develop/src/us_hydrodyn_pdb_parsing.cpp
    M us_somo/develop/src/us_hydrodyn_pdb_tool.cpp
    M us_somo/develop/src/us_hydrodyn_saxs_1d.cpp
    M us_somo/develop/src/us_saxs_util_best.cpp
    M us_somo/develop/src/us_saxs_util_dmd.cpp
    M us_somo/develop/src/us_saxs_util_hydro.cpp
    M us_somo/develop/src/us_saxs_util_loads.cpp
    M us_somo/somo/doc/manual/somo/somo_pdb_parsing.html
    M us_somo/somo/doc/manual/somo/somo_pdb_parsing_expert_mode.html

  Log Message:
  -----------
  somo: ask about open RasMol windows on exit, and skip heavy water

Two housekeeping fixes for ehb54/ultrascan-tickets#1000.

RasMol viewers are started by model_viewer() with startDetached(), so nothing
held on to them.  closeEvent() only ever looked at the legacy `rasmol` QProcess
member, which is allocated but never started - its one launch() call sits inside
#if defined( TODO_FIX_MOVIE_FRAME ) and uses a Qt3 API - so the check never
fired and every viewer SOMO opened was left behind.  Track the detached pids and
ask on exit whether to close them or leave them open.  Liveness and termination
go through small portable helpers rather than QProcess, since a detached child
has no QProcess to ask.

"Skip solvent water molecules" now means light and heavy water everywhere.  The
main GUI reader already listed DOD, but the headless reader, the hydro reader,
1D SAXS, the PDB editor and the BEST/DMD exclusion lists each tested for HOH
alone, so the same structure parsed differently depending on the route - 5PTI,
63 D2O residues, keeps 728 atoms instead of 539 through those paths.  All of
them now share one definition in us_hydrodyn_pdb_parsing.h.  WAT stays out of
it: that is SOMO's own explicit hydration water, not solvent to discard.

(cherry picked from commit fbd25903bcbb082bfa6ecbdb0ab776e277329c8a)


  Commit: fc4bcadd1e2381af336a5f7b57ca17099d5c139b
      https://github.com/ehb54/ultrascan3/commit/fc4bcadd1e2381af336a5f7b57ca17099d5c139b
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/include/us_hydrodyn_pdb_parsing.h
    M us_somo/develop/src/us_hydrodyn_load.cpp
    M us_somo/develop/src/us_hydrodyn_pdb_parsing.cpp
    M us_somo/develop/src/us_hydrodyn_settings.cpp
    M us_somo/develop/src/us_saxs_util_hydro.cpp
    M us_somo/develop/src/us_saxs_util_loads.cpp
    M us_somo/etc/somo.config.new
    M us_somo/etc/somo.defaults.new
    M us_somo/somo/doc/manual/somo/somo_pdb_parsing.html
    M us_somo/somo/doc/manual/somo/somo_pdb_parsing_expert_mode.html

  Log Message:
  -----------
  somo: add a "Skip deuterium atoms" PDB parsing option

Neutron structures carry deuterium where an X-ray structure carries hydrogen -
5PTI has 103 of them in the protein, on top of its D2O.  The hydrogen test the
readers apply matches names beginning with H only, so those deuteriums survived
parsing and arrived as unknown atoms; somo.residue codes them no better than it
codes hydrogens.

New option below "Skip hydrogen atoms", default on, applied in the same four
readers.  Unlike the hydrogen option it is live rather than greyed out, so the
old behaviour is still reachable, with the deuteriums then falling to the
missing atoms setting.

Deuterium is recognized from the wwPDB element field (columns 77-78) where the
file supplies it and from the atom name otherwise - a name test alone cannot
tell a deuterium from the second letter of a two-letter element, "CD  " being
cadmium.

Persisted through the JSON config alongside the other parsing options, and added
to the somo.config/somo.defaults templates.  Configs written before this option
existed simply take the default, since load_config_json() lays down the
hard-coded defaults before reading.

(cherry picked from commit 10d48cec080b53d282c4412ccfa6b46a44349c9f)


  Commit: ab36a145d97c1bd480c4372d0610a2ac6406108b
      https://github.com/ehb54/ultrascan3/commit/ab36a145d97c1bd480c4372d0610a2ac6406108b
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/include/us_hydrodyn.h
    M us_somo/develop/src/us_hydrodyn.cpp
    M us_somo/develop/src/us_hydrodyn_script.cpp

  Log Message:
  -----------
  somo: close RasMol viewers a gui_script opened, rather than orphaning them

A gui_script never reaches closeEvent() - "exit" calls exit(0) directly, and
gui_script_error() calls exit(-1) - so the exit prompt was not a hang risk
(guiFlag is false for the duration of a script in any case).  But it also meant
nothing cleaned up: auto_view_pdb is on by default, so any script that loads a
PDB without saying "norasmol" left a RasMol process behind on every run.

Route all three script exits through gui_script_exit(), which closes the
tracked viewers and says so on stdout.  A script that wants them kept says

   rasmol leaveopen

and "rasmol close" spells out the default.  A script that runs off the end
without "exit" hands back to the GUI, where the interactive prompt still
applies - the viewers belong to whoever is now at the keyboard.

(cherry picked from commit f6627f7cd8c199bd5ffafc5c584bc570f9969003)


  Commit: 3c28cfaa63a7704c9869fdf0b6200c2e1d3847c4
      https://github.com/ehb54/ultrascan3/commit/3c28cfaa63a7704c9869fdf0b6200c2e1d3847c4
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    A us_somo/develop/include/us_hydrodyn_perceive.h
    A us_somo/develop/include/us_hydrodyn_perceive_elements.h
    A us_somo/develop/include/us_hydrodyn_perceive_hybrid.h
    A us_somo/develop/include/us_hydrodyn_perceive_saxs.h
    A us_somo/develop/include/us_hydrodyn_perceive_somo.h
    M us_somo/develop/libus_somo.pro
    A us_somo/develop/perceiver/.gitignore
    A us_somo/develop/perceiver/DECISIONS.md
    A us_somo/develop/perceiver/README.md
    A us_somo/develop/perceiver/data/ref/f0_WaasKirf.dat
    A us_somo/develop/perceiver/data/ref/it1992.cpp
    A us_somo/develop/perceiver/data/ref/somo.saxs_atoms.generated
    A us_somo/develop/perceiver/pdb_lite.h
    A us_somo/develop/perceiver/residue_oracle.h
    A us_somo/develop/perceiver/tests/coverage.cpp
    A us_somo/develop/perceiver/tests/emit_residue.cpp
    A us_somo/develop/perceiver/tests/regression.cpp
    A us_somo/develop/perceiver/tests/tests_unit.cpp
    A us_somo/develop/perceiver/tinytest.h
    A us_somo/develop/perceiver/tools/gen_saxs_entries.py
    A us_somo/develop/src/us_hydrodyn_perceive.cpp
    A us_somo/develop/src/us_hydrodyn_perceive_somo.cpp
    M us_somo/develop/src/us_hydrodyn_script.cpp

  Log Message:
  -----------
  Perceive hybridization/vdW radius/electron count for non-coded residues

Phases A and B of ehb54/ultrascan-tickets#978.

SOMO needs an atom's hybridization, vdW radius and electron count to build a
bead model, and today they come only from the hand-curated somo.residue. For a
residue that table does not code, SOMO synthesises a "<RESNAME>_NC<n>"
placeholder and models it as a generic ABB average bead. This adds a chemical
perceiver that derives the real per-atom chemistry from element + coordinates,
so such a residue can be given a proper entry instead of an averaged one.

somo.residue remains the master: perception runs only for residues SOMO itself
recorded in unknown_residues.

Phase A - core compiled into libus_somo:
  include/us_hydrodyn_perceive{,_elements,_hybrid,_saxs}.h
  src/us_hydrodyn_perceive.cpp
Pipeline: spatial-grid bond perception (honouring CONECT where present, and
H-/ion-agnostic so implicit-H inference is identical with or without explicit
hydrogens) -> ring detection + planarity aromaticity -> Kekule bond orders ->
per-element classification -> emit a somo.residue block plus any somo.hybrid
rows for novel types.

The core is deliberately Qt-free, so the standalone harness in
us_somo/develop/perceiver builds the very same sources without Qt: 23 unit
tests plus a regression that takes residues somo.residue DOES code, pretends
they are unknown, and checks they are reproduced - 41,219 atoms over 8 demo
structures, 99.83% geometric perception, 0.17% genuine error. The residual is
protonation/tautomer state, which heavy-atom geometry cannot resolve in
principle. The harness reads us_somo/etc directly so it cannot drift from the
real tables.

us_hydrodyn_perceive_somo.{h,cpp} is the only Qt-aware layer: it converts
PDB_model/PDB_chain/PDB_atom, reads CONECT and HETNAM from the source file,
and returns tentative entries. It converts the whole model rather than one
residue because bond perception needs surrounding context (peptide links,
disulfides, metal coordination) to get coordination numbers, and hence
implicit-H counts, right. Instances are de-duplicated back to the base residue
name so one confirmation covers all instances of the same chemistry.

Phase B - headless "perceive <pdbfile>" gui_script command, so the whole path
is exercisable against real structures with no GUI:
  us3_somo _pad -I -g <script>
Entries carry a REVIEW block naming every atom whose perception was uncertain
(ambiguous protonation, assumed oxidation state, estimated vbar), which is what
the confirmation UI in ehb54/ultrascan-tickets#979 will present to the user.

No existing behaviour changes: nothing calls the perceiver outside the new
command.

Co-Authored-By: Claude Opus 4.8 <noreply at anthropic.com>
(cherry picked from commit 74123ff052110d14c1b81d7e4b8e1b30cdf87a20)


  Commit: a8d3ff41490671e82da2a30ae4ebe279c137c725
      https://github.com/ehb54/ultrascan3/commit/a8d3ff41490671e82da2a30ae4ebe279c137c725
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/include/us_hydrodyn_perceive_somo.h
    M us_somo/develop/perceiver/README.md
    A us_somo/develop/perceiver/examples/perceive.somo
    M us_somo/develop/src/us_hydrodyn_perceive_somo.cpp
    M us_somo/develop/src/us_hydrodyn_script.cpp

  Log Message:
  -----------
  Add "perceive compare" hand-testing sub-command

Part of ehb54/ultrascan-tickets#978.

"perceive compare <pdb>" runs perception over the residues somo.residue DOES
code and diffs the result against the curated types, reporting exact-match and
physics-match rates, a curated->perceived difference histogram, and the first
differing atoms. It is the interactive equivalent of the standalone regression
harness, but run inside SOMO against the user's own installed ~/ultrascan/etc
tables - so it also reveals when an installed table is out of date.

Cross-validation on 1HEL: the in-SOMO path and the standalone harness agree
exactly (1000 atoms scored, 984 exact 98.40%, 995 physics 99.50%), despite
using different PDB parsers and different copies of the tables. The five
physics differences are all known, explainable categories: the chain
N-terminus (a real -NH3+, where the perceiver is chemically right and the
residue template cannot know), the His tautomer and its charge, and the
Asp carboxylate protonation convention.

Also adds examples/perceive.somo documenting the invocation, including the
gotchas that cost time otherwise: the throwaway "_pad" argument is required on
macOS and must be omitted on Linux, "-I" avoids blocking config dialogs, and
the first run after rebuilding libus_somo only re-installs configs and exits,
so it must be run twice.

Co-Authored-By: Claude Opus 4.8 <noreply at anthropic.com>
(cherry picked from commit 894686fd90e20d5b1ba8cb1bc37a048d6a32e299)


  Commit: 990df0ddeb7da273e5b4da8b6edefd8bb7ebaed8
      https://github.com/ehb54/ultrascan3/commit/990df0ddeb7da273e5b4da8b6edefd8bb7ebaed8
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/perceiver/README.md

  Log Message:
  -----------
  Correct perceiver README: tables are read from us_somo/etc, not copied

Co-Authored-By: Claude Opus 4.8 <noreply at anthropic.com>
(cherry picked from commit 3969e7dbd75c4a6428f04e9b5e819dbe7ab7dea2)


  Commit: 2af5dc769da3ece9ec6dc2012ac464307a4c08f9
      https://github.com/ehb54/ultrascan3/commit/2af5dc769da3ece9ec6dc2012ac464307a4c08f9
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    A us_somo/develop/perceiver/tools/psv_model.py

  Log Message:
  -----------
  Add psv group-contribution probe (analysis for ticket #980)

Tests Mattia's suggestion that a rough psv can be suggested for a non-coded
residue from similarity to the hybridizations already in somo.residue, by
fitting a Cohn-Edsall / Durchschlag-Zipper style group-contribution model over
the ~100 genuine polyatomic residues somo.residue codes and scoring it
leave-one-out.

Result (MAE in vbar, cm^3/g; typical vbar ~0.73):
  global mean                     0.110
  sum-of-vdW-spheres (emitted now) 0.193   <- worst option available
  residue-type group average      0.070
  hybrid group-contribution       0.054   (organic only: 0.036, metals: 0.222)

So the estimate the perceiver currently emits is worse than guessing the mean,
the group-contribution model is good for organic residues, and it should not
be trusted for metal-containing ones. Findings recorded on
ehb54/ultrascan-tickets#980.

NOT pushed: this belongs with the #980 work rather than the #978 PR.

Co-Authored-By: Claude Opus 4.8 <noreply at anthropic.com>
(cherry picked from commit 64bc533aaafe3c536d6ea31313aa4a9638f172ad)


  Commit: 27652fdb900e20c4d5ea34b5f7f9ce5611bc01d2
      https://github.com/ehb54/ultrascan3/commit/27652fdb900e20c4d5ea34b5f7f9ce5611bc01d2
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/perceiver/DECISIONS.md
    M us_somo/develop/src/us_hydrodyn_perceive.cpp

  Log Message:
  -----------
  Remove the psv/molvol estimate from generated entries

The tentative entry emitted a vbar (and molvol) from a sum of vdW spheres.
Fitting a group-contribution model over the ~100 polyatomic residues
somo.residue codes, scored leave-one-out (perceiver/tools/psv_model.py),
shows that estimate is the WORST option available: mean absolute error 0.193
in vbar, against 0.110 for simply assuming the global mean. Summing spheres
ignores bond overlap and runs systematically high.

vbar enters hydrodynamics through the buoyancy term (1 - vbar*rho), so
emitting a number worse than a guess is actively misleading. Both fields are
now left at 0 = unset, and the entry says why and points at
ehb54/ultrascan-tickets#980, where the tiered replacement is tracked
(group-contribution for organic residues, MAE 0.036; residue-type group
average for out-of-domain cases such as metal-containing residues, where the
fit degrades to 0.222 - worse than that average; always user-overridable).

0 rather than omission because the header must keep its 7 fields to parse,
0 reads unambiguously as unset (the convention somo.saxs_atoms already uses
for F and SE), and it fails loudly: a 0 vbar is obviously wrong if used,
whereas a plausible-looking 0.80 is not.

The entry now reports the residue mass instead, since what decides whether an
imprecise psv matters is its mass fraction of the model - molecular vbar is
mass-weighted, so a 616 Da heme in a 50 kDa protein shifts it ~0.5% even with
a 0.34 vbar error.

Also tightens the REVIEW block to genuinely uncertain atoms: a confident
classification carrying an informational note was being listed as uncertain,
disagreeing with the flagged count callers report.

Co-Authored-By: Claude Opus 4.8 <noreply at anthropic.com>
(cherry picked from commit 8491edd5fef0b4cf3f5c6ed8b9fb9267073055fe)


  Commit: 9c5b6831ab862461ff1e3b0a94028aa441b8762f
      https://github.com/ehb54/ultrascan3/commit/9c5b6831ab862461ff1e3b0a94028aa441b8762f
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/include/us_hydrodyn_perceive.h
    M us_somo/develop/src/us_hydrodyn_perceive.cpp

  Log Message:
  -----------
  Fix bead colour field in generated residue entries

emit_residue() wrote the residue's atom count into the bead line's COLOUR
field. The bead line is hydration, colour, placing_method, chain, volume
(US_Hydrodyn::read_residue_file, us_hydrodyn_load.cpp:509), so a generated
entry's colour was whatever the atom count happened to be:

  - 6 atoms  -> colour 6, RESERVED brown, which marks a bead as buried and
                EXCLUDES it from the hydrodynamic computation
  - 7 atoms  -> colour 7, reserved for fused beads
  - 8 atoms  -> colour 8, reserved for beads found exposed on re-check
  - >15      -> out of range entirely

Six- to eight-atom ligands are common (glycerol has 6, phosphate 5), so this
silently dropped beads from models built with a generated entry.

Emit DEFAULT_BEAD_COLOR instead, defined once in us_hydrodyn_perceive.h with
the documented colour list from the SOMO manual (somo_residue.html, Panel 3)
and helpers bead_color_is_reserved() / bead_color_is_selectable() for the
residue-definition UI. Default is 10 (light green), which the manual records
as the Automatic Bead Builder's colour for non-coded residues; it is a single
named constant so the policy can be changed in one place.

Also spell out the remaining bead-line fields rather than emitting bare zeros.

Refs ehb54/ultrascan-tickets#978

Co-Authored-By: Claude Opus 4.8 <noreply at anthropic.com>
(cherry picked from commit cc7774a574a51cd1104b396d05ff4f8b4004483b)


  Commit: dc57245d0a1c641408e2c347cc4413aee5dce68a
      https://github.com/ehb54/ultrascan3/commit/dc57245d0a1c641408e2c347cc4413aee5dce68a
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    A us_somo/develop/include/us_hydrodyn_grid_volume.h
    M us_somo/develop/perceiver/DECISIONS.md
    A us_somo/develop/perceiver/Makefile
    M us_somo/develop/perceiver/README.md
    A us_somo/develop/perceiver/tests/grid_volume.cpp
    A us_somo/develop/perceiver/tools/calibrate_3v_context.py
    A us_somo/develop/perceiver/tools/hydration_table.py
    A us_somo/develop/perceiver/tools/psv_durchschlag.py
    A us_somo/develop/perceiver/tools/recalc_ligand_volumes.py
    A us_somo/develop/src/us_hydrodyn_grid_volume.cpp

  Log Message:
  -----------
  Native grid volume + analysis tools for vbar/molvol/hydration

Groundwork for filling the three fields a generated residue entry currently
leaves at zero: psv (vbar), anhydrous molar volume, and hydration.

Native grid volume (us_hydrodyn_grid_volume.h/.cpp, Qt-free)

  accessible A = { v : |v - c_i| > r_i + probe for every atom i }
  excluded   E = { v : v not in A, and dist(v, A) > probe }
  volume       = |E| * grid^3

probe 0 gives the bare van der Waals union, probe 1.4 the solvent-excluded
volume. Interior cavities are deliberately not counted, which is what lets
V(complex) - V(complex minus ligand) measure a bound ligand in context. Only
the accessible/blocked boundary is dilated -- the nearest accessible voxel to
any blocked voxel is always a boundary one -- so the cost is a surface rather
than a volume, and a 0.25 A grid runs in about a second for a 1300-atom
protein.

This removes what would otherwise be a new external dependency on 3V
(vossvolvox). 3V is retained only as the validation oracle: tests/grid_volume.cpp
reproduces Volume.exe to within 0.8% on an isolated residue, a whole protein,
and a bound-ligand difference, and adds analytic checks (single sphere,
coincident spheres, and a sealed hollow shell whose cavity must not be counted).
10 checks, 0 failures.

Analysis tools (prototypes, not built into libus_somo)

  psv_durchschlag.py      Durchschlag & Zipper atomic volume increments, no
                          fitting. Self-tests against the papers' own worked
                          values before reporting anything.
  hydration_table.py      derives a hybrid-type -> waters lookup from
                          somo.residue; 36 of 48 types unanimous, 7 weak and
                          flagged for review rather than silently defaulted.
  calibrate_3v_context.py calibrates the in-context difference method against
                          residues whose volume we already know.
  recalc_ligand_volumes.py recomputes prosthetic-group volumes, guarded on
                          elemental formula and on reproducing the stored value.

DECISIONS.md records the findings behind these, including why the anhydrous
volume field wants a 1.4 A probe rather than 0, and the measured-versus-
calculated trap in the Durchschlag 1986 tables.

The perceiver's hand-written test Makefile is force-added: the repository root
ignores "Makefile" for the qmake-generated ones, which left the documented
"make unit" impossible from a fresh clone.

Refs ehb54/ultrascan-tickets#980

Co-Authored-By: Claude Opus 4.8 <noreply at anthropic.com>
(cherry picked from commit 901c01d2b81385f3c9f57e349b6a2acf4dc996c3)


  Commit: 90b66109a993d724c19c7f27ccd06367e8531b66
      https://github.com/ehb54/ultrascan3/commit/90b66109a993d724c19c7f27ccd06367e8531b66
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/perceiver/.gitignore
    M us_somo/develop/perceiver/DECISIONS.md
    M us_somo/develop/perceiver/tools/calibrate_3v_context.py
    M us_somo/develop/perceiver/tools/psv_durchschlag.py
    M us_somo/develop/perceiver/tools/recalc_ligand_volumes.py

  Log Message:
  -----------
  Remove local filesystem paths from perceiver files

The repository is public, so absolute paths from a personal workspace should
not appear in it. Five places carried them, all written by me:

  .gitignore                 a home-directory path naming where the demo PDBs
                             were copied from
  DECISIONS.md               the local clone location
  psv_durchschlag.py         where the source PDFs happened to sit
  calibrate_3v_context.py    a hardcoded default path to Volume.exe
  recalc_ligand_volumes.py   the same

The two tools now resolve Volume.exe from $VOLUME_EXE, else PATH, which is
also what makes them runnable by anyone rather than only where that binary
was built. Behaviour is otherwise unchanged; self-tests still pass.

Refs ehb54/ultrascan-tickets#980

Co-Authored-By: Claude Opus 4.8 <noreply at anthropic.com>
(cherry picked from commit 6fc6d85ed01956401dc09c0a967453ea48a37ccb)


  Commit: 9af5da1ecb9fca159164755b7adc548c56d8be1e
      https://github.com/ehb54/ultrascan3/commit/9af5da1ecb9fca159164755b7adc548c56d8be1e
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/include/us_hydrodyn_perceive.h
    M us_somo/develop/perceiver/DECISIONS.md
    M us_somo/develop/perceiver/Makefile
    A us_somo/develop/perceiver/tests/sssr.cpp
    A us_somo/develop/perceiver/tests/sssr_real.cpp
    M us_somo/develop/src/us_hydrodyn_perceive.cpp

  Log Message:
  -----------
  Add SSSR ring perception and expose the perceived bond graph

Prerequisite for the Durchschlag & Zipper volume increments, which charge a
ring-formation decrement once per ring (3-ring 2.1 through >=9-ring 14.1).
The perceiver exposed only an "aromatic" flag and never returned Bonds at all,
so ring sizes and the topology needed to classify a nitrogen or oxygen
environment were unavailable to any caller.

Bonds gains "rings", the smallest set of smallest rings. find_sssr() is
declared in the header so it can be unit-tested on hand-built adjacency with
no geometry involved. A new perceive(atoms, bonds_out, explicit_bonds)
overload hands the graph back; the existing signature delegates to it, so
current callers are unaffected.

SSSR is kept separate from find_rings(), which enumerates every simple 5- or
6-cycle and feeds aromaticity. That is the right input for "is this atom in a
flat conjugated ring" but the wrong one for anything charged per ring: a fused
bicyclic has three simple cycles and circuit rank two. Keeping them apart also
leaves the validated perception untouched, confirmed by the regression figure
holding at 99.833%.

Method is the standard one for molecule-sized graphs: smallest cycle through
each bond, then greedy smallest-first acceptance while a candidate covers a
bond no accepted ring covers, until the circuit rank is reached. Rings beyond
max_ring (12) are not sought, since the consumer charges a single large-ring
term for everything from nine up.

Tests

  sssr.cpp      35 checks on hand-built graphs: acyclic shapes, every ring size
                3 to 9, ring with substituent, fused bicyclics (naphthalene,
                indole, purine) giving two rings rather than three cycles,
                spiro, bridged, three-fused, disconnected components,
                macrocycle beyond max_ring, idempotency, and that every
                reported ring is a genuine cycle. Also checks the arithmetic
                the counts drive: one 6-ring decrement reproduces the published
                phenylalanine volume, one 5-ring the proline one.

  sssr_real.cpp 18 checks on real coordinates through the whole perception
                path, over all eight demo structures. Phe {6}, Tyr {6},
                Trp {5,6}, His {5}, Pro {5}, DA/DG {5,5,6}, DC/DT {5,6}, and
                Ala/Gly/Leu/Ser/Arg ring-free, with every instance of a type
                giving an identical signature.

Some demo structures carry physically impossible geometry, which produces
spurious small rings: 1AO6 models LYS536/NZ 0.73 A from LEU583/CG, shorter
than any covalent bond, and 6LYZ has two oxygens 1.22 A apart. This yields 13
cross-residue and 12 three-membered rings across the demo set, none of them
inside a residue, so no residue's own ring count is affected. The tests assert
this as such: a cross-residue ring must be closed by an inter-residue bond that
is neither a backbone link nor a disulfide, and no three-membered ring may lie
within a single residue.

Refs ehb54/ultrascan-tickets#980

Co-Authored-By: Claude Opus 4.8 <noreply at anthropic.com>
(cherry picked from commit 0d1e1d24187f9a7e110f0e465f8acef746ffd5f9)


  Commit: e3a33a0717a72f0e90b4f6b2b8e8550605329377
      https://github.com/ehb54/ultrascan3/commit/e3a33a0717a72f0e90b4f6b2b8e8550605329377
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    A us_somo/develop/include/us_hydrodyn_psv.h
    M us_somo/develop/perceiver/DECISIONS.md
    M us_somo/develop/perceiver/Makefile
    A us_somo/develop/perceiver/tests/psv.cpp
    A us_somo/develop/src/us_hydrodyn_psv.cpp

  Log Message:
  -----------
  Add the Durchschlag & Zipper psv engine

Computes partial specific volume from published atomic volume increments,
consuming the perceived atoms and the bond/ring graph added in the previous
commit. Returns molar volume, vbar and a labelled decomposition -- atomic sum,
covolume, ring decrement, electrostriction, ring and charge counts -- so a
value can be audited rather than taken on trust. Atoms whose environment
cannot be classified are reported for review rather than guessed.

The covolume defaults off, since a residue is a monomeric unit and SOMO
already adds one structure-level covolume in calc_vbar_updated; a flag turns
it on for a standalone molecule. Only rings lying entirely inside the residue
are charged, which is both correct chemistry and immunity to the spurious
cross-residue rings that clashing coordinates produce.

Two rules a naive implementation gets wrong, both verified against the
published tables:

  The hydroxyl increment is topological, not a running count. A second
  NEIGHBOURING hydroxyl takes 0.4 but an isolated one is a fresh 2.3, so
  hydroxyls are clustered by whether their carrier atoms are bonded.
  1,2-ethanediol comes out at 53.5 and 1,8-octanediol at 152.0, exactly the
  published calculated volumes; a running count reproduces neither.

  Guanidinium charges only the terminal nitrogens. Table 1's footnote limits
  the 8.0 increment "in Arg only to the two terminal N", so arginine's NE
  takes the amine value.

Tests reproduce urea 44.2, glycerol 70.0 and all seven published group
increments exactly, and give mean absolute error of 1.64% against the stored
somo.residue vbar over the fifteen charge-neutral amino acids, none worse
than 6%.

Arginine and histidine sit outside that: the perceiver assigns them no formal
charge while somo.residue stores them protonated, so they lose an
electrostriction term. Arginine is essentially always protonated at
physiological pH, so that is a perception gap for the deferred pH layer rather
than ambiguous chemistry.

Refs ehb54/ultrascan-tickets#980

Co-Authored-By: Claude Opus 4.8 <noreply at anthropic.com>
(cherry picked from commit edb0798874626def9c02b95641b4332e1548bac9)


  Commit: ed82128ad27431a229a087382731cbebd27c63ed
      https://github.com/ehb54/ultrascan3/commit/ed82128ad27431a229a087382731cbebd27c63ed
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    A us_somo/develop/include/us_hydrodyn_hydration.h
    M us_somo/develop/include/us_hydrodyn_perceive.h
    A us_somo/develop/include/us_hydrodyn_residue_builder.h
    M us_somo/develop/perceiver/DECISIONS.md
    M us_somo/develop/perceiver/Makefile
    A us_somo/develop/perceiver/tests/builder.cpp
    M us_somo/develop/perceiver/tests/emit_residue.cpp
    A us_somo/develop/perceiver/tests/hydration.cpp
    A us_somo/develop/src/us_hydrodyn_hydration.cpp
    M us_somo/develop/src/us_hydrodyn_perceive.cpp
    A us_somo/develop/src/us_hydrodyn_residue_builder.cpp

  Log Message:
  -----------
  Fill in psv, anhydrous volume and hydration for generated entries

A generated somo.residue entry left vbar, molvol and hydration at zero. This
computes all three and emits a complete entry, with anything still unset
stated as "NOT SET" in the header so a partly filled entry always looks
partly filled.

Hydration lookup (us_hydrodyn_hydration.h/.cpp)

  Derived at run time from whatever somo.residue is loaded rather than
  embedded, so it cannot drift from the user's own tables. 1581 observations
  give 48 hybrid types, 41 of them confident and 7 flagged; flagged types are
  surfaced for review rather than silently defaulted, and ties break toward
  the lower water count, since under-hydrating a proposal the user will edit
  is safer than over-hydrating one they may accept unchanged.

  The per-atom values in somo.residue are a hand distribution of a
  per-residue Kuntz total rather than a per-atom rule, so this is a starting
  point for editing and says so. The residue total is the quantity with
  literature backing; tests confirm the totals reproduce Kuntz for 14 of 14
  applicable residues, with Asp and Glu deliberately low because SOMO stores
  them protonated.

  One test records a gap Mattia suspected: every nucleotide entry carries
  zero hydration. It is asserted as the current state, so it turns red the day
  someone fills those in, which is when models built on the old values need
  revisiting.

Orchestration (us_hydrodyn_residue_builder.h/.cpp)

  perceive, then psv, volume and hydration, then emit. emit_residue takes an
  optional Properties argument rather than including the new headers, which
  include it in turn.

  A generated tryptophan entry now gives vbar 0.753 against a stored 0.738,
  molvol 224.29 against 228.2, and hydration 2.0 against 2.0. Over twelve
  residues treated as unknown, computed molvol is within 2.32% of the stored
  values on average and never worse than 4.6%.

The volume convention factor is specific to the radius set. The 1.204/1.131
measured previously came from 3V's default radii; this pipeline uses SOMO's
own, which are smaller, so the right factors are 1.248 and 1.179. The factor
tracks polarity as much as size, hydrophobics sitting near 1.26 to 1.29 and
polar residues near 1.16 to 1.21, so the band split is placed below the
hydrophobic cluster rather than at the midpoint, where it separated leucine
from isoleucine and cost both 8%.

Also corrects a comment that described the residue header's ASA field as a
molecular weight column.

Refs ehb54/ultrascan-tickets#980

Co-Authored-By: Claude Opus 4.8 <noreply at anthropic.com>
(cherry picked from commit b5710a31a1277ea592fa2c59e5538bb4596967c8)


  Commit: 0f80d31def8c0c0f5b7a9cc86ab0e58e7e8f23e1
      https://github.com/ehb54/ultrascan3/commit/0f80d31def8c0c0f5b7a9cc86ab0e58e7e8f23e1
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/include/us_hydrodyn_perceive_somo.h
    M us_somo/develop/libus_somo.pro
    M us_somo/develop/perceiver/DECISIONS.md
    M us_somo/develop/src/us_hydrodyn_perceive_somo.cpp
    M us_somo/develop/src/us_hydrodyn_script.cpp

  Log Message:
  -----------
  Wire the computed properties into SOMO and add a headless perceive

libus_somo.pro did not list the four sources added since the perceiver work
resumed, so the grid volume, psv engine, hydration lookup and residue builder
were never compiled into the library at all. Registered, and the symbols are
confirmed present in the built dylib.

The Qt adapter now takes the bond graph from the new perceive overload and
goes through somo_residue_builder, so a proposal made inside SOMO carries
vbar, molvol and hydration rather than zeros. Tentative gained those three
fields for callers that want the numbers instead of the text block. The
hydration lookup is built from SOMO's own loaded residue_list, so a proposal
is always consistent with the user's tables rather than a snapshot compiled
into the binary.

"perceive auto <pdb>" is the headless sub-command: every default accepted,
nothing prompted, nothing written back to somo.residue. It also prints how
many atoms were flagged, since in a pipeline nobody is watching the REVIEW
block go past.

Defaults are pinnable through gparams in the same way as covolume:
perceive_psv, perceive_volume, perceive_hydration, perceive_volume_probe,
perceive_volume_grid and perceive_bead_color. A reserved bead colour is a
hard error rather than a silent substitution, because two of the reserved
values exclude a bead from the hydrodynamic computation and accepting one
would quietly produce a model missing beads.

Verified end to end through us3_somo -g on 2CMD, whose citrate is genuinely
not coded: vbar 0.542, molvol 186.56, and seven review flags. On the residue
basis SOMO stores, that vbar corresponds to 0.607 for the free molecule
against a literature value near 0.59 to 0.62. The proposed hydration of zero
for a triacid is plainly too low, and all four hydroxyl oxygens come back
flagged at 49% agreement, which is the intended behaviour: propose, then say
what cannot be supported.

Refs ehb54/ultrascan-tickets#980

Co-Authored-By: Claude Opus 4.8 <noreply at anthropic.com>
(cherry picked from commit 670110805dc743ff825a2cc7e71c70592d373829)


  Commit: f2c6ac8bbd1abf6e1bcdc68e3f5ee7af36f2c172
      https://github.com/ehb54/ultrascan3/commit/f2c6ac8bbd1abf6e1bcdc68e3f5ee7af36f2c172
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/include/us_hydrodyn_perceive_somo.h
    M us_somo/develop/perceiver/DECISIONS.md
    M us_somo/develop/src/us_hydrodyn_perceive_somo.cpp
    M us_somo/develop/src/us_hydrodyn_script.cpp

  Log Message:
  -----------
  Add perceive validate: predict the coded residues as if unknown

Rebuilds every residue somo.residue does code, pretending it is unknown, and
reports computed vbar, molvol and hydration against the stored values with a
summary. The same idea as perceive compare, which does this for atom typing,
but for the computed properties, and it exercises the whole pipeline
including perception. That makes it the only end-to-end measure of accuracy.
Chain termini and residues with unmodelled atoms are counted and skipped
rather than quietly averaged in.

Over seven structures and 1157 rebuilt residue instances, ordinary amino
acids give mean absolute errors of about 2.7% on vbar and 2.1% on molvol,
matching what the standalone harness claimed.

The ligand rows are the interesting ones. Heme's computed volume is 32.6%
above the stored value and NAD's is 28.1% above. Earlier work in this branch
reached the same conclusion by a completely different route, using 3V both on
the isolated molecule and by difference in context, and arrived at comparable
numbers. Two independent methods agree the stored ligand volumes are around
30% low. NAD's computed vbar of 0.619 is also closer to the measured 0.620
than the stored 0.599 is.

Heme's vbar comes out 24% low, which is the expected failure: it is a
metalloporphyrin, Durchschlag and Zipper publish no increment for iron, and
the engine reports the atom for review rather than inventing a value.

Hydration is much the weakest of the three, around half the residues within
half a water and systematically low, the misses being the polar and charged
side chains. A per-type majority cannot express residue-specific hydration.
This also confirms the pH coupling from the runtime side: residue_list
carries pH-adjusted hydration, so aspartate reads 6.0 and glutamate 7.0,
exactly the charged-carboxylate values, where the raw file fields give 1.0.

The lookup counts one vote per residue name, since residue_list holds several
entries for residues with ionization variants and counting each weights them
more heavily purely for being pH-aware, which was enough to flip a borderline
type and cost serine and threonine a water each.

Refs ehb54/ultrascan-tickets#980

Co-Authored-By: Claude Opus 4.8 <noreply at anthropic.com>
(cherry picked from commit 00118929e83385759ef54c44a775754120cc5bbc)


  Commit: c9dfd6ff18aafb0756b97fd4ebc642c9cddb75d2
      https://github.com/ehb54/ultrascan3/commit/c9dfd6ff18aafb0756b97fd4ebc642c9cddb75d2
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/include/us_hydrodyn.h
    A us_somo/develop/include/us_hydrodyn_perceive_dialog.h
    M us_somo/develop/libus_somo.pro
    M us_somo/develop/perceiver/DECISIONS.md
    A us_somo/develop/perceiver/run_dialog_test.sh
    A us_somo/develop/perceiver/tests/dialog_qt.cpp
    M us_somo/develop/src/us_hydrodyn.cpp
    A us_somo/develop/src/us_hydrodyn_perceive_dialog.cpp

  Log Message:
  -----------
  Add a GUI review dialog for non-coded residues

Everything built so far was reachable only from gui_script. A user working in
SOMO saw none of it, and a non-coded residue still fell silently to the
Automatic Bead Builder's averaged generic bead. This makes it visible and
correctable.

US_Hydrodyn_Perceive_Dialog presents one modal review per non-coded residue,
in the order Mattia laid out: view the residue in RasMol, confirm the
perceived atom table, edit the proposed per-atom hydration, check the
anhydrous volume, see the bead count and position, choose a bead colour, and
check the psv, with the somo.residue entry rebuilt live below so what is on
screen is exactly what Accept returns.

Only hydration is editable in the atom table. Name, hybrid, mass and radius
are perceived, and editing them would desynchronise the entry from the
geometry it came from. Hydration is editable because it is the weakest of the
three computed numbers; the residue total is shown beneath it and updates
live, with a note that the total is the quantity with literature backing while
the per-atom split is convention.

The colour combo is built from the manual's table and shows index, name and
meaning. The four reserved colours are never offered, since two of them mark a
bead for exclusion from the hydrodynamic computation and the other two are
assigned automatically during model generation.

Appending to somo.residue is opt-in and off by default, so accepting an entry
is per-session unless the user asks otherwise. After a save the user is told
to reload the structure, since hot-reloading the residue table would
invalidate indices the loaded model already holds.

The trigger is a Lookup Tables menu item rather than a hook inside model
building: check_for_missing_atoms runs per model and inside batch paths, so
opening a modal dialog from there would be invasive and wrong for scripted
runs. Skip leaves the residue to the Automatic Bead Builder exactly as before.

Testing a widget needs a widget test: run_dialog_test.sh builds the dialog
against the real library and exercises it under an offscreen Qt platform, so
it needs no display. Eighteen checks cover the proposal round-tripping through
parse and rebuild, a hydration edit propagating to both the atom line and the
bead total, a nonsense edit being rejected and the previous value restored,
read-only columns actually being read-only, the colour combo offering twelve
of the sixteen colours and defaulting to the configured one, and nothing being
marked accepted or saved until the user acts.

Refs ehb54/ultrascan-tickets#980

Co-Authored-By: Claude Opus 4.8 <noreply at anthropic.com>
(cherry picked from commit 39fd984788128ab669b66be14b38729293be1a92)


  Commit: e85d9069ee6c2edbdab816a0d037b981b7c93cbe
      https://github.com/ehb54/ultrascan3/commit/e85d9069ee6c2edbdab816a0d037b981b7c93cbe
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/include/us_hydrodyn_hydration.h
    M us_somo/develop/perceiver/DECISIONS.md
    M us_somo/develop/perceiver/tests/builder.cpp
    M us_somo/develop/src/us_hydrodyn_hydration.cpp
    M us_somo/develop/src/us_hydrodyn_perceive_somo.cpp
    M us_somo/develop/src/us_hydrodyn_residue_builder.cpp

  Log Message:
  -----------
  Propose hydration from pH 7 chemistry rules rather than type averages

Mattia supplied the chemistry: at pH 7 an acidic side chain is a carboxylate,
with one oxygen double-bonded and neutral and the other deprotonated and
charged; an aliphatic amine is protonated; and the water a carboxylate carries
depends on the length of the aliphatic chain linking it to the backbone, which
is what separates aspartate from glutamate. No general pH machinery, just the
pH 7 assumption.

The residue table confirms this exactly. The ionised hydration is field 15 of
an atom line, not 13 as the layout first suggests, and reading it gives
aspartate 5 waters on its carboxylate against glutamate's 6, lysine 3 on its
ammonium, arginine 1 on each terminal guanidinium nitrogen. So aspartate's
runtime total of 6 and glutamate's 7 are carboxylate plus backbone amide, and
the difference between them really is the extra methylene.

The rules replace the previous per-hybrid-type majority vote, which could not
express residue-specific hydration and systematically under-predicted the
polar and charged side chains. Anything the rules do not recognise still falls
back to the observed averages and is flagged, so a novel group never receives
a confident-looking number by accident.

Hydration within half a water improves from roughly 69 of 145 residue types to
136 of 145 across seven structures, 48% to 94%, with lysozyme and both
ribonucleases now exact on every type. All fifteen applicable coded residues
reproduce exactly in the unit tests, including the aspartate/glutamate
methylene difference. Partial specific volume and anhydrous volume are
unchanged, and perception still scores 99.833%.

Validation also has to skip chain termini at both ends, not just the carboxy
end. An amino-terminal residue has a free protonated backbone nitrogen rather
than an amide, so an amino-terminal lysine genuinely carries two ammonium
groups and six waters where the tabulated internal residue has four. The rules
were right and the comparison was wrong.

Two rule edges the coded residues exposed: a disulfide sulfur has two heavy
neighbours just as a thioether does, so both partners must be carbon before it
counts as hydrated; and proline's tertiary ring amide nitrogen carries no
hydrogen, so amide nitrogens are identified by their carbonyl neighbour rather
than by hydrogen count.

Refs ehb54/ultrascan-tickets#980

Co-Authored-By: Claude Opus 4.8 <noreply at anthropic.com>
(cherry picked from commit fbf7da800e6866e0b3c203cfbe900c5af41f4050)


  Commit: e57988fd0d8b7c019f905b9b80631001bf0cbf61
      https://github.com/ehb54/ultrascan3/commit/e57988fd0d8b7c019f905b9b80631001bf0cbf61
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/include/us_hydrodyn_psv.h
    M us_somo/develop/perceiver/DECISIONS.md
    M us_somo/develop/perceiver/tests/psv.cpp
    M us_somo/develop/src/us_hydrodyn_psv.cpp

  Log Message:
  -----------
  Measure pH 7 ionisation for psv, and leave it off

The pH 7 assumption transformed hydration, so the same reasoning was applied
to partial specific volume: charge the carboxyl as a carboxylate, protonate
the guanidinium, and take an electrostriction term for each. Implemented as an
option and measured against the stored values.

The measurement says not to use it. Aspartate moves from 1.3% low to 11.0%
low, glutamate from 1.2% to 9.0%, while arginine improves from 15.9% high to
9.7%. Mean absolute error goes from 6.23% to 9.05%: a clear net loss.

The reason the symmetry with hydration breaks is visible in the residue table.
It lists the same vbar for the protonated and deprotonated state of every
ionisable residue, so ionisation there changes mass, radius, protons and
hydration but never volume. Those values descend from densitometry on real
amino acids at neutral pH and already contain whatever ionisation was present,
whereas the Durchschlag and Zipper electrostriction is an explicit correction
to a neutral-basis increment sum. Applying both counts it twice.

Hydration was different precisely because the table does carry two hydration
numbers per ionisable atom, with the pH 7 value in its own field. There the
assumption had a ground truth to match, and matching it took hydration from
48% to 94% of residue types within half a water.

The option stays, off by default, with the measured numbers in the header
comment and a test that asserts the default is whichever setting actually
measures better. If the reference values are ever placed on a single stated
ionisation basis, flipping it will be a one-line change and the test will
report whether it helped.

This does not explain arginine, which is still 15.9% high untouched and 9.7%
high with electrostriction. It is the known outlier of the scheme: the six
published residue-volume sets in Perkins 1986 disagree with each other about
arginine by 17%.

Refs ehb54/ultrascan-tickets#980

Co-Authored-By: Claude Opus 4.8 <noreply at anthropic.com>
(cherry picked from commit 3e1508f51183466c7aa40e80697f4fd817310078)


  Commit: aaed7ac36e466f01301a60b7642568f3f817c854
      https://github.com/ehb54/ultrascan3/commit/aaed7ac36e466f01301a60b7642568f3f817c854
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/perceiver/DECISIONS.md

  Log Message:
  -----------
  Correct the record on the vbar ionisation design

An earlier note inferred that the identical vbar for the protonated and
deprotonated states meant the stored values already absorbed whatever
ionisation the underlying measurements carried. Mattia has corrected this: the
amino acid vbar values were recalculated by him at pH 7, and setting the
ionised value equal to the base is a deliberate statement that at pH 7 the
volume does not change.

There is also no stored "pH 7 value" anywhere. SOMO derives the species
fractions at run time from the stored pKa by Henderson-Hasselbalch, in
basic_fractions(), and mixes the base and ionised values by those fractions.
For aspartate at pH 7 that is 99.95% deprotonated, which is why the runtime
hydration is effectively the fully ionised value. The field described earlier
as "the pH 7 one" is the fully ionised one; pH 7 merely sits almost entirely
at that end.

This also reframes arginine. Its 0.698 is Mattia's recalculated pH 7 value,
which he states is better than the published sets, so the calculation being
16% high means it is reproducing a published-style number while the reference
is deliberately better than those, rather than the reference being uncertain.

The decision to leave the electrostriction option off is unchanged, and so is
the measurement behind it. Only the explanation changes: the correction
overshoots relative to a recalculated pH 7 reference.

What this confirms is that the implemented design is the intended one. Work at
pH 7 for a non-coded residue, since its pKa cannot be known, and assume the
hydrations determined for the amino acids, every carboxyl deprotonated and
every amine protonated. That is what the hydration rules already do.

Refs ehb54/ultrascan-tickets#980

Co-Authored-By: Claude Opus 4.8 <noreply at anthropic.com>
(cherry picked from commit 8a415144544fffc27d929ee9cdb7cc46e9620c0a)


  Commit: 593ad18770203fdded42e0a77da0a4538ede13c5
      https://github.com/ehb54/ultrascan3/commit/593ad18770203fdded42e0a77da0a4538ede13c5
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/include/us_hydrodyn_psv.h
    M us_somo/develop/perceiver/DECISIONS.md
    M us_somo/develop/perceiver/tests/psv.cpp
    M us_somo/develop/src/us_hydrodyn_psv.cpp

  Log Message:
  -----------
  Implement the published metal and ion volumes

The engine reported "no volume increment for this element" for every metal.
That was wrong: Durchschlag and Zipper tabulate them, and the values had
already been extracted into the Python prototype and then never carried across
to the C++ implementation.

Table 2 supplies atomic volumes for a metal bonded into a complex, such as a
haem iron or B12's cobalt. Table 3 supplies aqueous volumes for free monatomic
ions, including iron at -32.3 and -55.1 for the divalent and trivalent forms.
Those ion values already contain the ionisation contribution, so
electrostriction is not charged a second time on top of them, and a test
asserts an isolated magnesium comes out at exactly its tabulated value with no
electrostriction term.

The trivalent iron value of -55.1 is -0.99 mL/g, the same sign and order as the
figure quoted from another compilation. Negative because electrostriction
draws water inward around the ion more than the bare ion displaces.

The effect on haem is real but small: its partial specific volume moves from
24.3% low to 23.0% low. Iron is about a percent of a 616 dalton molecule, so it
was never going to close that gap. The bulk of the error is most likely the
porphyrin itself, four fused pyrrole rings and a heavily conjugated macrocycle,
which is not what Traube-style additivity was built for.

Refs ehb54/ultrascan-tickets#980

Co-Authored-By: Claude Opus 4.8 <noreply at anthropic.com>
(cherry picked from commit f355b4f83f28e5c3f287ee030841d44f257043b1)


  Commit: b994a6df61b027c399a2120683dc53f2f888f5e1
      https://github.com/ehb54/ultrascan3/commit/b994a6df61b027c399a2120683dc53f2f888f5e1
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/include/us_hydrodyn_perceive_dialog.h
    M us_somo/develop/perceiver/DECISIONS.md
    M us_somo/develop/src/us_hydrodyn.cpp
    M us_somo/develop/src/us_hydrodyn_perceive_dialog.cpp
    M us_somo/develop/src/us_hydrodyn_script.cpp

  Log Message:
  -----------
  Fix cross-structure state leak and add Skip all remaining

Two defects found while preparing structures for GUI testing, both visible
only when perceive is run over more than the demo set.

Running perceive twice in one session reported the previous structure's
non-coded residues against the new one. Ubiquitin alone has none, but after
malate dehydrogenase it reported two, which were citrate's. SOMO fills
unknown_residues during model building and never clears it, so the set
accumulates across loads. The emitted entries were still right, since a stale
name absent from the new model produces nothing, but the reported counts
described a structure that was no longer open. Both the script command and the
GUI slot now intersect that set with the residue names actually present in the
loaded model.

The second is a usability failure with real consequences. 5PTI is a neutron
structure carrying heavy water and explicit deuteriums, so its residues have
more atoms than the table's entries and SOMO matches none of them: fifty-five
non-coded instances across eighteen types, which meant eighteen modal dialogs
in succession with no way out but to dismiss each one. The dialog now offers
Skip all remaining, which abandons the review and leaves everything to the
Automatic Bead Builder, with a tooltip naming the likely cause so a user
seeing an implausible count suspects the file rather than the tool. The caller
honours it and reports how many residues went unreviewed.

Worth noting that the perceiver itself handles these structures correctly, as
it excludes hydrogens from bond perception by design. It is SOMO's residue
matching that fails on the atom count. Making that match hydrogen-agnostic
would be the real fix.

Refs ehb54/ultrascan-tickets#980

Co-Authored-By: Claude Opus 4.8 <noreply at anthropic.com>
(cherry picked from commit 18f170ffb8e37948c975e05f7f8b56c4698bb646)


  Commit: cb0b567de8a88851843964a6086b0c350818fc00
      https://github.com/ehb54/ultrascan3/commit/cb0b567de8a88851843964a6086b0c350818fc00
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/perceiver/.gitignore
    M us_somo/develop/perceiver/README.md
    A us_somo/develop/perceiver/data/non-coded/1MBO.pdb
    A us_somo/develop/perceiver/data/non-coded/2CMD.pdb
    A us_somo/develop/perceiver/data/non-coded/3PTB.pdb
    A us_somo/develop/perceiver/data/non-coded/5PTI.pdb
    A us_somo/develop/perceiver/data/non-coded/README.md
    M us_somo/develop/perceiver/examples/perceive.somo

  Log Message:
  -----------
  perceiver: add tracked test structures containing non-coded residues

The demo structures under perceiver/data/ are all fully coded, so nothing in
the tree exercised the path the perceiver exists for. Add four structures that
do, tracked in git since they are copies of nothing else here (the parent
data/*.pdb ignore rule is deliberately non-recursive).

  1MBO  SO4 only -- heme and O2 are coded, so it also shows selectivity
  2CMD  citrate, 13 atoms, 3 flagged for review -- the clean first test
  3PTB  benzamidine -- the only case reaching SSSR/ring-decrement and
        electrostriction; its Ca2+ is coded and correctly left alone
  5PTI  neutron/deuterated -- 50 instances across 18 types, the stress case
        for "Skip all remaining" (residue matching fails on atom count, not
        chemistry: the perceiver excludes hydrogens by design)

data/non-coded/README.md records the expected scan output for each so a
regression is visible without rerunning everything.

Also correct the example gui_script: paths must be absolute, since SOMO
changes directory during startup and a shell-relative path fails to resolve.

(cherry picked from commit b14eb3c1403d622b64d9c2bcaf59cb85955629ed)


  Commit: 9dce2a8639dd81e9538c83b42bf592f1b4d76bfa
      https://github.com/ehb54/ultrascan3/commit/9dce2a8639dd81e9538c83b42bf592f1b4d76bfa
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/perceiver/tests/dialog_qt.cpp
    M us_somo/develop/src/us_hydrodyn.cpp
    M us_somo/develop/src/us_hydrodyn_perceive_dialog.cpp

  Log Message:
  -----------
  perceiver: fix the review dialog never appearing from the GUI menu

Lookup Tables -> Perceive Non-Coded Residues... appeared to do nothing:
the dialog was constructed as a CHILD WIDGET of the main window, not as a
window. A QFrame given a parent and no window flag is an ordinary child, so
setWindowTitle and setWindowModality were silently ignored and the
setGeometry( x, y, 0, 0 ) idiom the other 116 SOMO dialogs use -- which a
window manager expands to the layout minimum -- left it 0 x 0, positioned by
a screen-coordinate global inside (and clipped by) the parent. The caller
then waited on isVisible(), which for a child never goes false, so SOMO sat
in the wait loop with nothing on screen.

Measured, with the dialog built the way the slot builds it:
  before   isWindow 0,    0 x 0
  after    isWindow 1, 1154 x 718

Every other SOMO dialog avoids this by passing no parent at all. Keeping the
parent and adding Qt::Window is better on macOS: the dialog then also stays
stacked above its owner. Adds fixWinButtons/raise/activateWindow to match
what the other dialogs do on show.

Also make the slot incapable of failing silently again: every exit path now
writes to the text window, including both "nothing to do" cases, and the
message boxes get a parent so they cannot open behind the main window.

dialog_qt.cpp gained the check that catches this -- it constructed the dialog
with no parent, i.e. exactly the case that works. Building it with a parent
and asserting isWindow() plus a non-degenerate size after show() reproduces
the failure offscreen (3 failures on the old code, 21/21 on the new).

(cherry picked from commit fb9664846f9c72140d61c2fcc88b3aa887c033a8)


  Commit: e8bb66fdff163f9a9dbe39fead661e6e7bea3d38
      https://github.com/ehb54/ultrascan3/commit/e8bb66fdff163f9a9dbe39fead661e6e7bea3d38
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/include/us_hydrodyn.h
    M us_somo/develop/include/us_hydrodyn_perceive.h
    M us_somo/develop/perceiver/README.md
    M us_somo/develop/perceiver/examples/perceive.somo
    M us_somo/develop/perceiver/tests/builder.cpp
    M us_somo/develop/src/us_hydrodyn.cpp
    M us_somo/develop/src/us_hydrodyn_perceive.cpp
    M us_somo/develop/src/us_hydrodyn_script.cpp

  Log Message:
  -----------
  perceiver: make an accepted entry actually take effect

Accepting an entry in the review dialog only printed it. The bead builder
still saw a non-coded residue and fell back to a generic averaged bead --
the outcome this feature exists to prevent. Three separate defects, each of
which alone was enough to break it:

1. ASA was emitted as 0. Every SOMO residue loader -- read_residue_file
   (us_hydrodyn_load.cpp:534), US_AddResidue (:1288), US_Saxs_Util (:693) --
   skips a record whose ASA is zero, and skips it SILENTLY. The entry parsed,
   never entered residue_list or multi_residue_map, and the residue went on
   being reported non-coded with nothing to indicate why. All 127 coded
   residues have ASA > 0. Emit 18 A^2/atom, the coded-residue mean, labelled
   a placeholder in the REVIEW block: nothing computes with the tabulated
   residue ASA (it appears only in info dumps), but it may not be zero.
   Properties::asa lets a caller supply a measured value later.

2. The block was not a valid record. The table is strictly positional -- one
   free-text comment line, then header, atoms, beads -- and has no comment
   syntax. The emitted block's ~20 '#' lines were consumed two at a time as
   comment/header pairs, silently creating zero-atom residues named "#".
   Ticking "add to somo.residue" would have written that into the user's own
   table. perceived_table_record() collapses the block to one comment line.

3. Nothing applied the entry. apply_perceived_entries() puts accepted entries
   into a session overlay (<table>.perceived), re-runs read_residue_file on
   it and re-reads the structure, so the atoms rebind. The user's table is
   written only when they tick the box. Novel hybrid rows, previously dropped
   on the floor, are injected into hybrid_to_protons/electrons first, since
   read_residue_file rejects atoms whose hybrid it cannot resolve.

Adds "perceive apply <pdb>" -- the headless equivalent of accepting every
entry -- reporting the non-coded count after the fact. That assertion is what
found (1) and (2); the GUI path had no way to tell "file written" from
"entry in effect". builder.cpp now checks the emitted ASA is positive.

Verified: 1MBO SO4 and 2CMD CIT both apply, 0 types still non-coded, and a
fresh perceive of 1MBO reports every residue already coded. Suites green
(54/35/18/60/5/37/55/21), regression 99.833%.

(cherry picked from commit dfa109153157c58937f05c55b23b8eec154dc55b)


  Commit: f9f9f9a85f6e2d90f2a2016eef695e12bdec0e04
      https://github.com/ehb54/ultrascan3/commit/f9f9f9a85f6e2d90f2a2016eef695e12bdec0e04
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/include/us_hydrodyn_perceive_dialog.h
    M us_somo/develop/perceiver/tests/dialog_qt.cpp
    M us_somo/develop/src/us_hydrodyn_perceive_dialog.cpp

  Log Message:
  -----------
  perceiver: stop the review dialog overriding the emitted ASA

The dialog does not write the perceiver's block -- refresh_entry() rebuilds
the whole entry from its widgets, and its header format string hardcoded the
ASA slot to 0:

    s += QString( "%1\t0\t%2\t0\t%3\t1\t%4\n" )

so fixing the emitter changed nothing for anyone using the GUI. A run shows
both the new REVIEW line about the ASA placeholder AND a header reading
"SO4 0 61.75 0 5 1 0.390" -- one binary, two emitters, and the loaders drop a
zero-ASA record silently, so the residue stayed non-coded after acceptance.

"perceive apply" could not catch this: it uses the Tentative block directly
and never constructs a dialog, so it exercised the half that was already
right. The dialog now parses type and ASA out of the proposed header and
writes them back untouched, editing only what it owns -- molvol, vbar,
hydration and colour. Anything it hardcodes silently overrides perception,
so it should hold nothing it does not edit.

The dialog test could not catch it either: its fixture block carried ASA 0,
so any assertion would have passed vacuously. The fixture now carries 54.00
and the test parses the rebuilt header and asserts the ASA field is positive
and still 54.0, alongside molvol -- the two fields the loaders gate on.

25 checks, 0 failures; Qt-free suites unchanged (54/35/18/60/37/55).

(cherry picked from commit 2f95e97d15f10253a1b9946b9a863eb233b6e6f2)


  Commit: 13351141f45ff96ec4477d6e46925670532c8014
      https://github.com/ehb54/ultrascan3/commit/13351141f45ff96ec4477d6e46925670532c8014
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/include/us_hydrodyn.h
    M us_somo/develop/src/us_hydrodyn_beads.cpp
    M us_somo/develop/src/us_hydrodyn_core.cpp
    M us_somo/develop/src/us_hydrodyn_fractal_dimension.cpp
    M us_somo/develop/src/us_hydrodyn_load.cpp
    M us_somo/develop/src/us_hydrodyn_saxs_1d.cpp
    M us_somo/develop/src/us_hydrodyn_saxs_2d.cpp
    M us_somo/develop/src/us_hydrodyn_saxs_iqq.cpp

  Log Message:
  -----------
  somo: derive an atom-table entry instead of dropping the atom

somo.atom is keyed by ATOM NAME, so an atom whose name that table has never
seen resolves to nothing and is dropped from both the ASA and the excluded
volume -- reported once, then ignored. That is routine for a non-coded
ligand: 1MBO's sulfate sulfur is named "S", and the table carries only the
Fe-S cluster names S1..S4B.

    Chain A Molecule 2 Atom S Residue SO4 154 Hybrid S name missing from
    Atom file. Atom skipped for SAS.

ensure_atom_entry() derives one instead. It prefers another atom with the
SAME HYBRID -- which fixes element, mass and radius exactly, leaving only the
excluded volume a convention -- and falls back to the same ELEMENT. The
derived entry goes into the map, so it is also the memo: the next lookup is
an ordinary hit.

Excluded volume takes the value that key uses MOST OFTEN in the table rather
than whichever row is found first, because it is not a function of the
hybrid: C4H3 appears with both 31.89 and 16.44 A^3 depending on atom name.
For sulfur the question does not arise -- every S row is 19.86.

It reports what it did, once per atom name. A silent substitution here would
be the same class of defect as the silent skip it replaces:

    Note: S (S) is not in the atom table; using the hybrid match:
    mw 32.065, radius 0.43, excluded volume 19.86 A^3

Applied at all six lookup sites, not only the two a bead build reaches: bead
building, SAS, fractal dimension, and the SAXS 1D/2D/I(q) paths.

Verified on 1MBO: the fallback fires once for S, nothing is skipped, and the
perceived SO4 entry still applies cleanly (0 types still non-coded).

(cherry picked from commit 57804dfa39b133200c82b059fbd356cb6ee7663f)


  Commit: f1e0db9fb28d1c7eb374c0a0546192e77e890c7c
      https://github.com/ehb54/ultrascan3/commit/f1e0db9fb28d1c7eb374c0a0546192e77e890c7c
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/perceiver/README.md
    M us_somo/develop/perceiver/examples/perceive.somo
    M us_somo/develop/src/us_hydrodyn_load.cpp
    M us_somo/develop/src/us_hydrodyn_script.cpp

  Log Message:
  -----------
  perceiver: add "perceive build" so bead-build defects are testable headlessly

"perceive apply" cannot cover the model builder. A clean load takes calc_mw(),
not the excluded-volume path, so the somo.atom lookup -- and anything else
that only bites at bead-build time -- was exercised solely by clicking
through the GUI. That is how the atom-table skip reached the user in the
first place.

  perceive build [somo|somo_o|vdw|grid|a2b] <pdb>

is apply plus what the user does next: select the model, call the same
function the button does (calc_somo / calc_somo_o / calc_vdw_beads /
calc_grid_pdb), report the bead count, and FAIL the script if the build
fails or yields no beads. vdw is the sharpest of the four for a perceived
residue: it relies on atomic hydration, which the perceiver only proposes.

Two things this immediately caught in the harness itself:

- Counting bead_models[current_model] reported 0 beads for a build that had
  plainly succeeded (rc 0, three overlap-reduction stages, a written bead
  model). The build walks current_model as its loop variable and leaves it
  ONE PAST the last model, so that index is out of range right afterwards.
  Count bead_model, the model just built.

- ensure_atom_entry's report went out through editor_msg(), which only ever
  writes to the GUI text widget -- so in a gui_script run the substitution
  was completely silent, and its absence from a log proved nothing. It now
  also goes to stdout. A silent substitution is the same defect class as the
  silent skip it replaces.

Verified on 1MBO/2CMD against the reference tables: the fallback fires once
during the first build ("atom table: S (S) is not in the atom table; using
the hybrid match ... 19.86 A^3") and all four methods build --
somo 305, somo_o 305, vdw 1267, grid 331 beads. The 305 matches the count
from the user's GUI session.

Docs record that a script using "perceive build" must set "somo overwrite"
first -- without it the bead-model write calls setSomoGridFile(), which
raises a modal dialog and hangs a headless run (batch suppresses those
prompts, a gui_script does not) -- and that there is no equivalent flag for
the hydrodynamic calculations.

(cherry picked from commit ba5015a5511fb573d07cf81b27f13e979bb95cd0)


  Commit: bd6412bb43db3c7a5cc683fb20637b36b95349ec
      https://github.com/ehb54/ultrascan3/commit/bd6412bb43db3c7a5cc683fb20637b36b95349ec
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    A us_somo/develop/perceiver/GUI_TESTING.md
    M us_somo/develop/src/us_hydrodyn_perceive_dialog.cpp
    M us_somo/somo/doc/manual/somo/somo.html
    A us_somo/somo/doc/manual/somo/somo_perceive.html

  Log Message:
  -----------
  perceiver: dedicated help page for the non-coded residue dialog

The review dialog's Help button pointed at somo_residue.html, which documents
the residue table editor and says nothing about perception. Point it at a new
somo_perceive.html and link that from the Lookup Tables list in somo.html,
beside Add/Edit Residue.

The page follows the manual's conventions and uses the dialog's actual
labels -- Skip this residue, Also append this entry to somo.residue, Flagged
for review -- rather than paraphrases. It reserves an <img> slot for
somo-perceive.png next to the HTML.

Its substance is what a GUI tester cannot get from the interface itself:

- perceive BEFORE building, or the Automatic Bead Builder's _NC placeholders
  are already in the model
- what Accept actually does. An accepted entry goes to somo.residue.perceived
  and becomes the active table IMMEDIATELY, but only for this session:
  residue_filename is reset to somo.residue at every start and is not stored
  in the config, and the next session's first Accept REBUILDS that file from
  somo.residue, discarding what an earlier session accepted. Tick the
  checkbox, or re-select the file by hand before accepting anything new
- what each computed number is worth, and that hydration is the weakest --
  which is why vdW models are where a weak proposal becomes a real problem
- that ASA is a placeholder which nonetheless may not be zero

Also adds perceiver/GUI_TESTING.md, the same ground as a cheat sheet for
someone testing only through the GUI, with the four test structures and what
to be sceptical of in a proposed entry.

Note US_Help::show_help() falls back to underconstruction.html when the file
is missing, so "under construction" means help_dir points at an installed
release rather than at this tree.

(cherry picked from commit 26495b76b360b4c7ad8b70a164531dc54439f8ab)


  Commit: a7ac63c79bdacda4184688db31492c81a80cbefb
      https://github.com/ehb54/ultrascan3/commit/a7ac63c79bdacda4184688db31492c81a80cbefb
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    A us_somo/develop/perceiver/data/non-coded/8RATNC.pdb
    A us_somo/develop/perceiver/data/non-coded/8RAT_gap3.pdb
    A us_somo/develop/perceiver/data/non-coded/8RAT_run3.pdb
    A us_somo/develop/perceiver/tools/make_noncoded_variant.py

  Log Message:
  -----------
  perceiver: chain-embedded test residues with a known answer

Every non-coded structure in the test set so far is a free ligand -- citrate,
benzamidine, sulfate -- so nothing exercises a non-coded residue INSIDE a
chain, and nothing has a ground truth to check the computed numbers against.

us_somo/somo/demo/8RATNC.pdb is 8RAT with LYS 31 renamed to LYD, done by hand
upstream. That trick is the useful one: the atoms are untouched, so whatever
the perceiver derives can be compared directly against the coded entry for
the residue it really is. Add it here and generalise it.

  tools/make_noncoded_variant.py IN.pdb OUT.pdb A:31=LYZ ...

renames residues by chain and resSeq, refusing to write if a spec matched
nothing -- a silently unmodified file would quietly pass any test built on
it. Two shapes beyond the single-residue case, both aimed at the chain
handling rather than the chemistry:

  8RAT_run3.pdb   LYS31/SER32/ARG33 -> LYZ/SEZ/ARZ, an unbroken run
  8RAT_gap3.pdb   LYS31/ARG33/LEU35 -> LYZ/ARZ/LEZ, alternating with coded

Coded values to check against (somo.residue.new):
  LYS vbar 0.818 molvol 167.30 hydration 4.0
  SER vbar 0.628 molvol  95.40 hydration 2.0
  ARG vbar 0.698 molvol 194.00 hydration 3.0
  LEU vbar 0.898 molvol 164.00 hydration 1.0

Expect a systematic offset rather than a match: the perceiver treats a
residue as an isolated unit, while the coded amino-acid entries describe it
in a chain.

(cherry picked from commit a2e127b4d827e58300de76c52522b858b3657e9a)


  Commit: 386ffa92bb78ee712e9ef6911b8edcbcfef66409
      https://github.com/ehb54/ultrascan3/commit/386ffa92bb78ee712e9ef6911b8edcbcfef66409
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/perceiver/GUI_TESTING.md
    M us_somo/somo/doc/manual/somo/somo_perceive.html

  Log Message:
  -----------
  perceiver: record the measured accuracy in the help page

The help page said what each computed number is worth in general terms.
Now there are numbers, from residues where the answer is known: rename a
residue the table already codes, leave its atoms untouched, and the coded
entry becomes the answer key.

  really  psv perceived/coded    volume perceived/coded   hydration
  SER     0.632 / 0.628  +0.6%   97.95 /  95.40  +2.7%    2.0 / 2.0
  LEU     0.892 / 0.898  -0.7%  158.61 / 164.00  -3.3%    1.0 / 1.0
  LYS     0.871 / 0.818  +6.5%  172.85 / 167.30  +3.3%    4.0 / 4.0
  ARG     0.809 / 0.698 +15.9%  196.19 / 194.00  +1.1%    3.0 / 3.0

Hydration was exact on all four -- the quantity with the least theoretical
backing, and the one a tester is most able to sanity-check. Volume within
+-3.3%. psv splits by charge: neutral side chains +-0.7%, charged ones high.
The arginine +15.9% is reproduced independently by the isolated-residue
validation and matches the reading that the tabulated Arg psv was measured
unprotonated while the increments assume protonation -- so the help page
tells the user to treat a perceived psv for a charged group as provisional.

Chain embedding caused no difficulty: one non-coded residue, three in a row
and three alternating with coded ones gave identical values and built
cleanly (244/242/242 beads). The residuals track charge, not chain context
-- the opposite of what was expected, since the perceiver sees the real
bonded neighbours and so perceives backbone N and C as amide and carbonyl.

Same table added to the GUI cheat sheet, with the three new test files.

(cherry picked from commit cdd288a85403d8acde8bccbb73c6c2c01266521c)


  Commit: 6857cecb525088dc9c21a108542a13270192fcdc
      https://github.com/ehb54/ultrascan3/commit/6857cecb525088dc9c21a108542a13270192fcdc
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    A us_somo/somo/doc/manual/somo/somo-perceive.png
    M us_somo/somo/doc/manual/somo/somo_perceive.html

  Log Message:
  -----------
  perceiver: add the review dialog screenshot to the help page

The page referenced somo-perceive.png without the file existing, so it
rendered a broken image. Adds it, with a caption.

The screenshot is citrate rather than benzamidine deliberately: benzamidine
has 0 atoms flagged and an empty-looking review box, while citrate shows the
Flagged for review box populated with the carboxyl/carboxylate protonation
and pH 7 hydration notes -- the part of the dialog the page spends most of
its words on, and the part a tester most needs to recognise.

Verified: every SRC and href on the page resolves, all three tables close.
(cherry picked from commit d78eaba38000ea86a71fde17cb204f085409417f)


  Commit: 4d3df1019a3ab1ec766cde2a7cb484248d686dc8
      https://github.com/ehb54/ultrascan3/commit/4d3df1019a3ab1ec766cde2a7cb484248d686dc8
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/include/us_hydrodyn.h
    M us_somo/develop/src/us_hydrodyn.cpp
    M us_somo/develop/src/us_hydrodyn_perceive_dialog.cpp
    M us_somo/develop/src/us_hydrodyn_script.cpp

  Log Message:
  -----------
  wip: mattia review items 1-3

(cherry picked from commit 64b54a4df90fa2200154bbb7fecc3176213d95ef)


  Commit: c15e0db3ffd6f88fbc7dc037b3308d94e7d2e1ba
      https://github.com/ehb54/ultrascan3/commit/c15e0db3ffd6f88fbc7dc037b3308d94e7d2e1ba
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/src/us_hydrodyn.cpp

  Log Message:
  -----------
  wip: fix coded-test, map operator[] inserts on read

(cherry picked from commit 80e08e9dc5f268df0224b53014c5fe76bd609b11)


  Commit: 7ae8eae45adbf0218c510c0177e3893f231e30fa
      https://github.com/ehb54/ultrascan3/commit/7ae8eae45adbf0218c510c0177e3893f231e30fa
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/include/us_hydrodyn.h
    M us_somo/develop/include/us_hydrodyn_perceive_dialog.h
    M us_somo/develop/src/us_hydrodyn.cpp
    M us_somo/develop/src/us_hydrodyn_perceive_dialog.cpp

  Log Message:
  -----------
  wip: revisit accepted entries + reset-all

(cherry picked from commit c3dfad80e43d0d95d71045119cfe2b9b50243ed1)


  Commit: 35b3f5560da01e850284074087dea20d9ae739da
      https://github.com/ehb54/ultrascan3/commit/35b3f5560da01e850284074087dea20d9ae739da
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/include/us_hydrodyn.h

  Log Message:
  -----------
  fix: perceived_entries member must not live in a slots block (moc)

(cherry picked from commit 93a8250cbe4f4c68d26de4826e678b9a54643e3c)


  Commit: bc5fe0a85cc53a252bdda9450116f3d886bf15e8
      https://github.com/ehb54/ultrascan3/commit/bc5fe0a85cc53a252bdda9450116f3d886bf15e8
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/src/us_hydrodyn.cpp

  Log Message:
  -----------
  fix: raw newline inside a string literal from a scripted edit

(cherry picked from commit cdd317c12649f7998590441633172f998bd7ef39)


  Commit: 5bf0bc01ca589ccbed29876f64911df8c28075ee
      https://github.com/ehb54/ultrascan3/commit/5bf0bc01ca589ccbed29876f64911df8c28075ee
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/include/us_hydrodyn_perceive_elements.h
    M us_somo/develop/perceiver/tests/tests_unit.cpp
    M us_somo/develop/src/us_hydrodyn_perceive_somo.cpp
    M us_somo/develop/src/us_hydrodyn_psv.cpp

  Log Message:
  -----------
  perceiver: never compute a psv from unidentified elements

A PDB with an empty element column (77-78) produced psv values of 0.001,
-0.068, -0.087 -- meaningless numbers that still look like numbers.
1AO6-compl_monA.pdb in the demo set is such a file, which is how it surfaced.

Two independent defects, either alone enough:

1. The atom-name fallback used norm_element(), which only strips
   non-alphabetics. So the alpha carbon "CA" became CALCIUM, "NE2" became
   NEON, and "CB", "CG", "OD1" matched no element at all. Every atomic volume
   increment then evaluated to zero and the sum collapsed to roughly the
   electrostriction terms. element_from_atom_name() takes the leading letter,
   accepting a two-letter element only when the atom name equals the residue
   name -- HETATM "CA" in residue "CA" is calcium, "CA" in "ALA" is carbon.

2. somo_psv::compute() reported ok on a residue containing atoms it had no
   increment for. It now counts them, records why in the review block, and
   returns ok == false, so the caller emits no psv rather than a plausible
   figure. An unidentified element is not a small error; it is not a volume.

The grid volume was unaffected and still looked sensible (Ala 77.45 A^3),
which is precisely why this was not obvious from the output.

tests_unit.cpp gains the case that catches it: CA/CB/CG1/OD1/NE2/NZ/SD/OXT
must resolve by leading letter, while CA-in-CA, FE-in-FE, ZN-in-ZN, MG-in-MG
resolve as the two-letter element. 69 checks, 0 failures.

(cherry picked from commit f7a45de8f2384fb01f344630a2c4d70e974b3150)


  Commit: bcf439527abd06606dd9d1a75160adec9b52e785
      https://github.com/ehb54/ultrascan3/commit/bcf439527abd06606dd9d1a75160adec9b52e785
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/include/us_hydrodyn_perceive_elements.h
    M us_somo/develop/perceiver/tests/tests_unit.cpp

  Log Message:
  -----------
  perceiver: element inference must key on the residue, not the atom name

The previous rule took the leading letter unless the atom name equalled the
residue name. That is right for proteins and wrong for ligands -- exactly the
population this code exists for. Six of fifteen test cases failed:

    FE in HEM -> F   (fluorine)      CU in CUA -> C
    CL in CIT -> C                   SE in MSE -> S
    NA in XYZ -> N                   BR in LIG -> B

so a heme iron contributed a fluorine volume, silently.

The discriminator is the RESIDUE. In a standard residue the naming convention
is fixed and the element is always the leading letter: CA is the alpha carbon,
NE2 a nitrogen, SD a sulfur. In a ligand it is not, and a two-letter atom name
that matches a known element is that element.

Residual ambiguity, stated in the header: a ligand carbon named bare "CA"
reads as calcium. Ligand carbons are normally C1/CAA/CB1, and the psv now
refuses to compute rather than guessing when an element cannot be resolved,
so the failure is visible either way.

Answers the question directly: with this, a PDB with no element column is
handled correctly for proteins AND for ligands with two-letter elements.
Without it, only proteins were safe.

79 checks, 0 failures.

(cherry picked from commit cf4246cc29f0abb38781388293af0d633ac2df95)


  Commit: ce30c44be40989a1cb6814c52703c8650ae4db9e
      https://github.com/ehb54/ultrascan3/commit/ce30c44be40989a1cb6814c52703c8650ae4db9e
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/include/us_hydrodyn_residue_builder.h
    M us_somo/develop/perceiver/tests/builder.cpp
    M us_somo/develop/src/us_hydrodyn_residue_builder.cpp

  Log Message:
  -----------
  perceiver: emit psv at the table temperature, not the increments'

The Durchschlag & Zipper increments describe 25 C. somo.residue is a 20 C
table -- SOMO itself converts with tc_vbar() using 4.25e-4 cm^3 g^-1 K^-1.
The perceiver applied no conversion at all, so every generated entry was
5 K x 4.25e-4 = 0.0021 cm^3/g high: about +0.3%, small enough to read as
method noise and not noise at all.

Found by comparing against Mattia Rocco's independent recalculation. Matching
the temperature reference collapses the disagreement:

    residue        vs his 25 C     vs his 20 C
    GLY ALA VAL    -0.07 .. +0.02%   +0.20 .. +0.33%
    LEU ILE THR
    CYS MET PHE
    TRP ASN GLN
    SER            +0.07%            +0.41%
    ASP            +0.16%            +0.52%

14 of 20 residues agree to within +-0.07% once the reference matches.

His conversion itself is exact, which was the other possibility Mattia raised:
the dv/dT implied by his 25 C and 20 C columns is 4.2500e-04 for all 20
residues with ZERO spread, and equals SOMO's tc_vbar coefficient. No rounding
error there -- the discrepancy was entirely on this side.

The temperatures and the coefficient are Options fields rather than literals,
so a table at another reference temperature is a parameter change.

builder.cpp gains the check: ALA psv 0.7413 at 25 C -> 0.7392 at 20 C, which
is Rocco's tabulated 20 C value exactly. 57 checks, 0 failures.

(cherry picked from commit cd05f6908b8f9fe815785b83e87ae31d869ac939)


  Commit: bcfe8be56ce83329c0476b2b2e295101925c9002
      https://github.com/ehb54/ultrascan3/commit/bcfe8be56ce83329c0476b2b2e295101925c9002
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/include/us_hydrodyn_perceive_elements.h
    M us_somo/develop/perceiver/tests/tests_unit.cpp

  Log Message:
  -----------
  perceiver: protein atom names win over two-letter elements

Keying element inference on the residue name alone broke modified residues --
the very population this feature exists for. MSE, PTR, CGU and any renamed
residue carry protein atom names (CA, CB, CD, NE) under a NON-standard
residue name, so they took the ligand branch and every backbone CA became
CALCIUM. That changed the hybrid, the radius, the grid volume and the
hydration as well as the psv: alanine came back as vbar 0.171, molvol 83.9,
hydration 4.0 instead of 0.739 / 87.4 / 1.0.

Caught by re-running the 20-residue comparison rather than trusting the unit
tests, which used real residue names and so never entered that branch.

Resolution order is now explicit:
  1. lone ion            atom name == residue name  ("CA" in residue "CA")
  2. standard residue    leading letter
  3. protein atom name   leading letter, whatever the residue is called
  4. two-letter element  FE, CL, SE, BR, CU, ZN, MG
  5. leading letter

Step 3 is the one that makes modified and renamed residues work, and it is
why "SE in MSE" still resolves to selenium while "CA in MSE" resolves to
carbon: the collision set is atom NAMES, not residues.

86 checks, 0 failures, with MSE/PTR/CGU/renamed cases in the suite.

(cherry picked from commit e95f8708da6bdf9072a82b2a4b5334f77670f1f0)


  Commit: fadfdc6efab90b10347861fd5f530fdd5c7ca596
      https://github.com/ehb54/ultrascan3/commit/fadfdc6efab90b10347861fd5f530fdd5c7ca596
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/perceiver/Makefile
    A us_somo/develop/perceiver/data/psv/1BEB.pdb
    A us_somo/develop/perceiver/data/psv/2CGA.pdb
    A us_somo/develop/perceiver/data/psv/README.md
    A us_somo/develop/perceiver/data/psv_measured.txt
    A us_somo/develop/perceiver/tests/protein_psv.cpp

  Log Message:
  -----------
  perceiver: whole-protein psv, incumbent table vs D&Z increments vs D&Z+pH7

Mattia's question was whether to substitute somo.residue's amino-acid psv set with
one derived from the atomic volume increments. The residue-level four-way table
localised the differences but could not say which is right; this compares all three
against measured protein psv, using SOMO's own aggregation (calc_vbar_updated).

Measured values mined from Durchschlag Table 5 + the albumin table, taking only the
CORRECTED columns (phi, phi(0), v(0)) -- the apparent columns vary 5.7% at constant
pH purely from cosolvent, so they cannot be compared against a computed value.

Two guards the first run needed:
 - explicit H/D are stripped. D&Z is a united-atom scheme and so is somo.residue
   (ALA: N 15.02, CA 13.02, CB 15.04), so explicit hydrogens double count. The psv
   guard already refused them; the tool must not hand them over in the first place.
 - a structure whose usable residues fall below 95% is EXCLUDED, not reported. Before
   this, 2AAS averaged a handful of surviving residues into a confident-looking
   +13.7%. With H stripped it agrees with 8RAT to four decimals.

All three columns are gated on table membership so they cover identical residues;
otherwise a ligand the table cannot represent (1BEB's SO4) would count for D&Z only.

Co-Authored-By: Claude Opus 5 <noreply at anthropic.com>
(cherry picked from commit ad6a2302da74ee7c1ecab449fdb7f593cbf19f60)


  Commit: 54a518afca8ab6995588716107a73f6722a463ef
      https://github.com/ehb54/ultrascan3/commit/54a518afca8ab6995588716107a73f6722a463ef
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/perceiver/pdb_lite.h
    M us_somo/develop/perceiver/tests/protein_psv.cpp

  Log Message:
  -----------
  perceiver: strip hydrogens and index MODELs in pdb_lite, as SOMO does

Mattia: 'US-SOMO should strip them away! Why isn't it doing it in its tests?
Also the multiple models in NMR-style files. It should correctly recognize them
and perform the calculations anyway.'

He is right, and SOMO itself was never the problem:
 - US_Hydrodyn::read_pdb strips H by name (us_hydrodyn_load.cpp:1489-1492,
   including the ^\dH form that catches 1HB / HD21)
 - it keeps every MODEL in model_vector, with a workaround for files whose
   MODEL tag is missing

perceiver/pdb_lite.h did neither properly: it passed hydrogens straight through
and silently kept only model 1. That is not confined to the psv test -- 2AAS is
the one demo file with hydrogens (7840, 245 in model 1) and it drives regress,
coverage and sssrreal, so every one of those has been perceiving a structure
SOMO would never have handed it.

Fixed at the reader so every test inherits it, rather than patching one test:
 - is_hydrogen_atom() reproduces SOMO's name rule, with one deliberate
   divergence -- an explicit element column wins, so a mercury named HG survives
   where SOMO's name rule would drop it. The perceiver exists for such ligands.
 - MODELs are indexed on the atom; model_count()/model_of() split them. protein_psv
   now computes every model and reports the ensemble spread instead of assuming
   model 1, since which model to use is a later choice (his point exactly).

Effect: 2AAS goes from unusable to agreeing with 8RAT -- the same protein solved
by a different method -- to four decimals, and across its 32 NMR models the psv
spread is 0.0005 cm3/g (0.07%), which is the precision check that ensemble buys.
Regression unchanged and healthy: 97.894% exact, 99.833% geometric perception.

Co-Authored-By: Claude Opus 5 <noreply at anthropic.com>
(cherry picked from commit 17dd65468fbc3f2c188106285b6d777acf5c8fb6)


  Commit: 2dcf9d9dcc7c7cd3077cdb68543285cc62c3a11b
      https://github.com/ehb54/ultrascan3/commit/2dcf9d9dcc7c7cd3077cdb68543285cc62c3a11b
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/perceiver/pdb_lite.h

  Log Message:
  -----------
  perceiver: recognize deuterium too, matching somo-dev's new skip option

somo-dev 10d48cec added a 'Skip deuterium atoms' parsing option (default on) with
pdb_parse_is_deuterium() in us_hydrodyn_pdb_parsing.h. pdb_lite's hydrogen test
already stripped D via the element column but not via the atom name, so a neutron
structure without col 77-78 would have leaked deuteriums into the perceiver.

Aligned with their helper, including its rationale: the element column wins over
the name because a name test alone cannot tell a deuterium from the second letter
of a two-letter element -- their example is 'CD' (cadmium), mine was 'HG'
(mercury). Same conclusion reached independently, now spelled the same way.

5PTI (data/non-coded) is the case: 229 deuteriums, all carrying an element column,
so behaviour there is unchanged -- this closes the no-element-column path.

Co-Authored-By: Claude Opus 5 <noreply at anthropic.com>
(cherry picked from commit c18f890853e48ded035a956bbff0cb7f78cf35d1)


  Commit: befb24f1511b6f1ac909a97ec6524292bbcd7f0d
      https://github.com/ehb54/ultrascan3/commit/befb24f1511b6f1ac909a97ec6524292bbcd7f0d
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/perceiver/tests/protein_psv.cpp

  Log Message:
  -----------
  perceiver: allow a tabulated vbar to be overridden, to test candidate values

Mattia asked which of the three competing arginine values fares better. An argv
token RES=vbar now replaces that residue's vbar in the [table] column only; the
D&Z columns are computed from coordinates and stay untouched, so the run asks
exactly one question -- which tabulated value best predicts measured protein psv.

Result over 7 proteins, mean |error| of [table]:
    ARG 0.698  (somo.residue)      0.84%
    ARG 0.7686 (Rocco recalc)      1.37%
    ARG 0.809  (D&Z increments)    1.67%
Monotonic: every step up is worse. The incumbent value wins and should stay.

Co-Authored-By: Claude Opus 5 <noreply at anthropic.com>
(cherry picked from commit 0c1fcd9179ba31a2df164eb1bb7c14af3c7b1f19)


  Commit: d1d1422f9d04e9d391b0c454d2c5b22b735da650
      https://github.com/ehb54/ultrascan3/commit/d1d1422f9d04e9d391b0c454d2c5b22b735da650
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/perceiver/tests/protein_psv.cpp

  Log Message:
  -----------
  perceiver: show per-residue D&Z spread and a sequence-only cross-check

Mattia's point: psv is a composition property, so an experimental structure may
be unnecessary -- a sequence-correct model (AF2) would do, and then verifying the
protein's SOURCE and processed form matters more than the coordinates.

Measured rather than assumed. Per-residue D&Z psv across 7 proteins:
  ALA SER TRP MET HIS ARG  SD exactly 0.000 -- fully context-independent
  most others                SD 0.1-1.0%
  CYS 2.21%, TYR 1.23%, LYS 1.00%  -- real chemistry, not noise: free thiol vs
  disulfide for CYS, termini for LYS. Sequence-only averages over these.

Recomputing every protein from composition alone, using corpus-mean per-residue
values, against the full structure-based calculation:
  mean |diff| 0.076%, worst +0.116%
An order of magnitude below the effect being measured (table 0.84% vs D&Z 3.07%).

So structures are not the bottleneck after all: a correct sequence suffices, and
the binding constraint moves to source/isoform/processing verification.

Caveat: the per-residue means come from these same proteins, so the check is
mildly circular; the six zero-SD residues are exempt by construction.

Co-Authored-By: Claude Opus 5 <noreply at anthropic.com>
(cherry picked from commit 80159a145019f75db9608c30f77b1b4a74fa9606)


  Commit: e9748b6a027f1fa45f80d82db269184fd068bf90
      https://github.com/ehb54/ultrascan3/commit/e9748b6a027f1fa45f80d82db269184fd068bf90
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    A us_somo/develop/perceiver/data/psv/candidates.fasta
    M us_somo/develop/perceiver/tests/protein_psv.cpp

  Log Message:
  -----------
  perceiver: score proteins from UniProt mature sequences, no structures needed

Follows the sequence-only validation: composition reproduces the structural answer
to 0.076%, so any protein with a known MATURE sequence can join the validation set.
PROTEIN_PSV_FASTA=<file> reads records of '>label measured_psv' + one-letter sequence.

The processed form comes from UniProt MOLECULE_PROCESSING rather than guesswork,
which matters because the tables measure different forms of the same gene product:
  pepsinogen    = PROPEP + CHAIN (activation peptide RETAINED), P00791 16..385
  papain        = CHAIN only, propeptide removed,               P00784 134..345
  carboxypep A  = CHAIN only, 94-residue activation peptide off, P00730 111..419
  chymotrypsinogen A = full zymogen 1..245
  a-chymotrypsin     = chains A+B+C, dipeptides 14-15/147-148 excised, 241 residues

Eight new proteins, table column vs measured:
  catalase -0.04, pepsinogen -0.06, a-chymotrypsin +0.05, chymotrypsinogen +0.18,
  calmodulin +0.93, papain +1.05, carboxypeptidase A -1.51, a-lactalbumin +4.02
Excluding a-lactalbumin: bias +0.09%, mean |err| 0.55% -- better than the
structure-based set. Combined 14 proteins: bias +0.46%, mean |err| 0.69%.

Two things worth noting. The chymotrypsinogen/a-chymotrypsin pair differ by four
excised residues out of 245; measured +0.30%, calculated +0.18% -- the method
resolves it, and in the right direction. And a-lactalbumin, the one bad case, is
the entry Table 6 annotates '~12% carbohydrate content'; a carbohydrate correction
explains roughly half the 4% and it should stay excluded.

Co-Authored-By: Claude Opus 5 <noreply at anthropic.com>
(cherry picked from commit c2290b2405b9902ebfc422c684ce3db21e4bab41)


  Commit: bd07e054b10b4775c0ebe0b7a1d4549424679d55
      https://github.com/ehb54/ultrascan3/commit/bd07e054b10b4775c0ebe0b7a1d4549424679d55
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/src/us_hydrodyn_perceive.cpp
    M us_somo/develop/src/us_hydrodyn_perceive_dialog.cpp

  Log Message:
  -----------
  perceiver: white dialog background, and one review line per atom

Two of three items from Mattia's Linux GUI testing (2026-08-10).

Background: the dialog is mostly close reading -- a generated table entry and a
list of flags -- and SOMO's global frame grey is hard going, more so on Linux
where it renders darker. Only this frame's background changes; every label here
calls AUTFBACK and paints its own, and the global palette is untouched.

Review list: two independent streams feed it, perception ambiguity notes and the
psv/volume/hydration reviews, both keyed "NAME (HYB)". Emitted raw, an atom with
one of each appeared twice, so citrate showed six entries for three atoms and read
as flagging far more waters than it does. Now grouped by atom, first-appearance
order, notes joined:

  before                                          after
  O2 (O2H1): carboxyl -OH                         O2 (O2H1): carboxyl -OH; carboxylate at pH 7, 5 waters
  O4 (O2H1): carboxylate O (symmetric...)         O4 (O2H1): carboxylate O (symmetric...); carboxylate at pH 7, 5 waters
  O6 (O2H1): carboxylate O (symmetric...)         O6 (O2H1): carboxylate O (symmetric...); carboxylate at pH 7, 5 waters
  O2 (O2H1): carboxylate at pH 7, 5 waters
  O4 (O2H1): carboxylate at pH 7, 5 waters
  O6 (O2H1): carboxylate at pH 7, 5 waters

The third item -- hydration on the wrong oxygen -- is a real inconsistency but
needs a convention decision, so it is not touched here.

Tests unchanged: unit 86/0, psv 60/0, hydration 37/0, regression 97.894% exact.

Co-Authored-By: Claude Opus 5 <noreply at anthropic.com>
(cherry picked from commit 45c7a165c46eac6c86500795ccaf86169ebdfbd8)


  Commit: 069cc9bd31b3393077ced9e21c6fd81b5c11a612
      https://github.com/ehb54/ultrascan3/commit/069cc9bd31b3393077ced9e21c6fd81b5c11a612
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/src/us_hydrodyn_perceive_dialog.cpp

  Log Message:
  -----------
  perceiver: pin the dialog foreground too, not just the background

Mattia: the font colour came out different on Linux and macOS.

Cause: PALET_LABEL and PALET_FRAME construct a whole QPalette from a single
configured colour, and Qt derives the remaining roles itself. That derivation is
not identical across Qt versions and platforms, so the text colour drifted.

perceive_palette() now names every role this dialog relies on -- Window, Base,
AlternateBase, WindowText, Text, ButtonText -- and is applied to the frame, all
labels, the info line, the checkbox and both read-only text views. Nothing is
derived, so both platforms render the same.

Push buttons deliberately keep PALET_PUSHB: they are controls users recognise by
their SOMO styling, and they are not the surface being read.

libus_somo builds clean.

Co-Authored-By: Claude Opus 5 <noreply at anthropic.com>
(cherry picked from commit cd3273186cd71d1e13df7e48c645aa592a704e9b)


  Commit: 0c1521843ba1f0df3d40e3f8dfed9b2bc89f0b91
      https://github.com/ehb54/ultrascan3/commit/0c1521843ba1f0df3d40e3f8dfed9b2bc89f0b91
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/src/us_hydrodyn_perceive_dialog.cpp

  Log Message:
  -----------
  perceiver: make the review list's length visible, and fix the flagged count

Mattia, testing on Linux: "I didn't get from the actual perceiver that there were
more lines to be scrolled, likely the grey bkg fooled me. It should be evident".

Three things were hiding it:
 - the box had no frame, so on the old grey it blended into the dialog. White needs
   the border more than grey did: both text views are now StyledPanel|Sunken.
 - no scrollbar until you tried to scroll. Both views now keep a vertical scrollbar
   permanently, so a list longer than its box says so without being discovered.
 - the summary quoted tent_.flagged, which counts only atoms the PERCEPTION step
   found ambiguous, while the box also carries psv, volume and hydration notes. The
   two disagreed -- a "0 atom(s) flagged" line could sit above a box with entries in
   it. The REVIEW lines are now extracted once, before the summary, and the same
   count feeds both; the label reads "Flagged for review - N item(s), scroll for all".
   Wording moves from "atom(s)" to "item(s)", which is what they are.

Also AUTFBACK on the two text views and the checkbox. Per ehb54, SOMO needs it
per-field for backgrounds to render consistently, and those three were given a
palette without it.

libus_somo builds clean.

Co-Authored-By: Claude Opus 5 <noreply at anthropic.com>
(cherry picked from commit cf0adf435b6dbfef0b6f699a42947e0162aa5270)


  Commit: d0f26f6e0505280cf77c8afa6a844bfda0d1ad84
      https://github.com/ehb54/ultrascan3/commit/d0f26f6e0505280cf77c8afa6a844bfda0d1ad84
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/include/us_hydrodyn_hydration.h
    M us_somo/develop/include/us_hydrodyn_perceive.h
    M us_somo/develop/include/us_hydrodyn_perceive_dialog.h
    M us_somo/develop/src/us_hydrodyn_hydration.cpp
    M us_somo/develop/src/us_hydrodyn_perceive.cpp
    M us_somo/develop/src/us_hydrodyn_perceive_dialog.cpp
    M us_somo/develop/src/us_hydrodyn_residue_builder.cpp

  Log Message:
  -----------
  perceiver: emit both protonation states for ionizable atoms

Option (b), per ehb54. An ionizable atom now gets the 16-field atom line the coded
residues use -- protonated species in fields 1-8, deprotonated in 10-16 -- plus
vbar_ionized and pKa in the residue header.

The convention was read off somo.residue rather than assumed, and it is the same
for acids and bases: primary = protonated, alternate = deprotonated.
    ASP  OD2  O2H1  ...0  |  O1H0-  ...5     COOH  -> COO-
    LYS  NZ   N4H3+ ...3  |  N3H2   ...1     NH3+  -> NH2
    ARG  NH2  N3H2+ ...1  |  N3H1   ...0     guanidinium+ -> neutral

This also fixes what Mattia found on citrate. The old code put the pH-7 water count
on an O2H1 primary -- a row that exists nowhere in somo.residue, since an O2H1 is a
hydroxyl and carries 1 -- and summed those into a bead total of 16. Now the neutral
-COOH carries 0, the alternate carries 5, and the bead total reads 1 for the
neutral state. The 16 was never wrong arithmetic; it was the ionized total written
into a neutral record.

pKa is a CONVENTION value from whichever coded residue shares the group (carboxyl
3.67/4.25 by chain length, the same discriminator the 5-vs-6-water rule already
uses). It is not a prediction: citrate's three carboxyls all come out short-chain
and are proposed at 3.67 where the real values are ~3.13/4.76/6.40 -- which is why
it is presented for the user to accept or change, and labelled as convention in the
REVIEW block.

Alternate mass and radius are resolved from somo.hybrid, not hard-coded; an
alternate type missing from the table is reported and the alternate is not written.

Dialog: three columns on the same row -- Ionized, Ionized hydration (edit), pKa
(edit) -- blank and uneditable for non-ionizable atoms. pKa is per residue, as
somo.residue stores it in the header, so editing it on any row updates them all.
Bad input reverts rather than clamps.

Citrate now emits a 9-field header and 16 fields on exactly the three carboxyl
oxygens. Tests unchanged: unit 86/0, hydration 37/0, psv 60/0, regression 97.894%
exact. libus_somo builds clean.

Co-Authored-By: Claude Opus 5 <noreply at anthropic.com>
(cherry picked from commit 9290eb14043008f1964676f85f19d12d16a8ef85)


  Commit: 3a7d71bdb0724129cbecb1b6ed7c502f1cc118fe
      https://github.com/ehb54/ultrascan3/commit/3a7d71bdb0724129cbecb1b6ed7c502f1cc118fe
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/src/us_hydrodyn_perceive_dialog.cpp

  Log Message:
  -----------
  perceiver: RasMol shows the structure again, without solvent

Mattia, 2026-08-10: "The 'view Residue in RasMol' was better before, where it was
showed together with the structure (solvent molecules should be, however,
discarded... usually unchecking the H atoms remove waters from visualization)".

Reverts the residue-only view to whole-structure-with-context, but fixes the two
things that made the first version of it unusable:

 - solvent and hydrogens are dropped. Waters buried the residue in a haze of
   oxygens; his own workaround was that unchecking H removes them, so both go.
   Solvent is matched by residue name, hydrogen by the same rule the readers use --
   element column when present, atom name otherwise, including the 1HB form.
 - the view centres ON the residue, not on the model, and zooms in. Centring on the
   model is why 1MBO's sulfate was lost inside the surrounding wireframe and why
   this was reduced to residue-only in the first place.

Protein is thin grey wireframe (15), the residue spacefilled in cpk at wireframe 40,
so it reads as the subject with the fold as context.

The residue-present check still runs against the filtered file, so a structure whose
residue was entirely solvent-named would still report rather than open an empty view.

libus_somo builds clean.

Co-Authored-By: Claude Opus 5 <noreply at anthropic.com>
(cherry picked from commit 8956bda1bed8ba8995b859bd1bff18ae7902ee40)


  Commit: 590f686412b06ac7ed5fb16dc75ff1c1ab3af960
      https://github.com/ehb54/ultrascan3/commit/590f686412b06ac7ed5fb16dc75ff1c1ab3af960
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/somo/doc/manual/somo/somo_perceive.html

  Log Message:
  -----------
  perceiver: bring the help page up to date

Seven commits of user-visible change had landed since the page was last touched.
Documents what a reviewer now actually sees:

 - the ionizable columns (Ionized / Ionized hydration / pKa), why they exist -- the
   coded ionizable residues are already stored this way, so an entry written the same
   way lets US-SOMO pick the state by pH -- and which of them are editable.
 - that the proposed pKa is a CONVENTION value from whichever coded residue shares
   the group, not a prediction, with citrate as the cautionary case: all three
   carboxyls proposed at 3.67 where the real values are ~3.13/4.76/6.40.
 - that the pKa is one value per residue, so editing it anywhere changes the entry.
 - RasMol now shows the residue inside the structure with solvent and hydrogens
   removed, centred on the residue.
 - the review box gives its item count and scrolls, one line per atom.
 - Reset this residue, and revisiting an accepted entry.

Co-Authored-By: Claude Opus 5 <noreply at anthropic.com>
(cherry picked from commit 8b715d0c3744e8b6afbd371165322e84614a3a1b)


  Commit: d8dae41bfdd6dabee48ae07db498d964dfce0df3
      https://github.com/ehb54/ultrascan3/commit/d8dae41bfdd6dabee48ae07db498d964dfce0df3
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/src/us_hydrodyn_hydration.cpp
    M us_somo/develop/src/us_hydrodyn_perceive_dialog.cpp

  Log Message:
  -----------
  perceiver: readable table headers, and stop flagging plain carbonyl oxygens

Two things from Mattia's screenshot of 8RAT_gap3 / LYZ.

Headers unreadable: QHeaderView paints its sections with Button/ButtonText, not
Window/WindowText. perceive_palette() set only the text, so the section background
stayed inherited and the headers came out dark on dark. Button is now an explicit
light grey, and the palette is applied to the table and its header widget -- neither
inherits the frame's -- with the header in bold so it reads as one.

Spurious review flag: an oxygen with no hydrogen that is not part of a carboxyl --
a backbone carbonyl, an ester, an ether, a phosphate O -- matched no rule and fell
through to "no pH 7 rule for this group", so nearly every entry was flagged for its
own backbone. Every O1H0 in somo.residue carries 0 waters (36 backbone O, plus
O2/O4/O6/OP1/OP2 and the rest), so that is a confident zero and is now stated as one.

LYZ in 8RAT_gap3 goes from 3 flagged items to 1, the remaining one being the real
ASA placeholder note.

Tests unchanged: unit 86/0, hydration 37/0, psv 60/0. libus_somo builds clean.

Co-Authored-By: Claude Opus 5 <noreply at anthropic.com>
(cherry picked from commit bb17af1bcaf6164b068ae745e30cca99b1222cb1)


  Commit: 503d9d6e075af6f6c468c53d3929af030ff3919d
      https://github.com/ehb54/ultrascan3/commit/503d9d6e075af6f6c468c53d3929af030ff3919d
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/src/us_hydrodyn_core.cpp
    M us_somo/develop/src/us_hydrodyn_perceive_dialog.cpp

  Log Message:
  -----------
  perceiver: show both hydration totals, and point at the module from the load

Two from Mattia's testing.

Hydration total read 1 for 2CMD. That is the PROTONATED total and it is correct as
far as it goes -- since ionizable atoms started carrying their waters in the
deprotonated alternate, citrate's three carboxyls contribute 0 each and only the
central hydroxyl's 1 remains. But at pH 7 citrate is deprotonated, so the number
that matters is 16, and showing only the neutral one is misleading. The label now
gives both, and only when the entry actually has an ionizable atom:

    Residue hydration total: 1.00 waters neutral, 16.00 ionized

Missing perceiver warning: no such message has ever existed in this branch -- I
searched the history for one and there is none -- so this is a gap rather than a
regression, but the gap is real. The load reports non-coded residues, the bead
builder then represents each by a single crude bead, and nothing told the user an
entry could be derived from the coordinates first. check_for_missing_atoms now says
so once unknown_residues is final, naming the residues it means.

libus_somo builds clean.

Co-Authored-By: Claude Opus 5 <noreply at anthropic.com>
(cherry picked from commit 71f1ee61a3daf2baf4560952ef17abf67f8c6c8e)


  Commit: 9c78c064d798a860b57d4941a83bc343994fcace
      https://github.com/ehb54/ultrascan3/commit/9c78c064d798a860b57d4941a83bc343994fcace
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/src/us_hydrodyn_perceive.cpp
    M us_somo/develop/src/us_hydrodyn_perceive_dialog.cpp

  Log Message:
  -----------
  perceiver: fix the ionization index, respect the 2-pKa limit, reword the total

Accepting a citrate entry failed with "Duplicate ionization index". Three separate
constraints in the residue-file format, none of which the emitter was honouring:

 1. the ionization index must be UNIQUE within a residue. Every ionizable atom was
    written with index 1, so citrate's second carboxyl collided. Now counts from 1.
 2. the header is a vbar followed by one (vbar, pKa) PAIR per ionization, and each
    atom's index must match a declared pKa, which it then consumes. Only one pair was
    being written no matter how many atoms were ionizable.
 3. at most TWO are supported -- the loader rejects a third outright. Citrate has
    three carboxyls and simply cannot be written in two states.

For (3) the entry now collapses to the single state that is true at pH 7, the
deprotonated one, applied to the primary fields so the TYPES and the WATERS agree --
unlike the original bug, where the types were neutral and the waters ionized. The
REVIEW block says the entry is not pH-switchable and why. Silently emitting a record
the loader refuses is the one option not on the table.

Verified both paths: a single-carboxyl residue emits ASP's exact shape (header
"0.593 0.593 3.67", one 16-field line at index 1); citrate emits 8-field lines with
O1H0- and 5 waters, and the collapse note.

Hydration total reworded as Mattia reads it -- "16 waters proposed, 1 for non-ionized
and 15 for ionized atoms" -- split by atom category rather than by state, and
coloured, since it is the number most worth checking.

Tests unchanged: unit 86/0, hydration 37/0, psv 60/0, regression 97.894% exact.

Co-Authored-By: Claude Opus 5 <noreply at anthropic.com>
(cherry picked from commit c4bced72a8e5f15e3372a0ae7faaf2ef444fb0f9)


  Commit: f108df8633d7c4085a0b413abb9ed3268c8d540f
      https://github.com/ehb54/ultrascan3/commit/f108df8633d7c4085a0b413abb9ed3268c8d540f
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/include/us_hydrodyn_perceive_dialog.h
    M us_somo/develop/src/us_hydrodyn_perceive.cpp
    M us_somo/develop/src/us_hydrodyn_perceive_dialog.cpp

  Log Message:
  -----------
  perceiver: keep the ionizable columns populated when an entry is collapsed

Mattia: "now the ionizable fields are empty, I suppose because the three pKs are not
anymore supported even at this stage. I would left this in at this stage".

He is right that they should not go blank. The file cannot hold three ionizations,
but the dialog is the review surface, not the storage, and blanking the columns
throws away what the perceiver actually found.

The perceiver now records each ionization it had to drop as a machine-readable
comment -- "# ION <atom> <hybrid> <waters> <pKa>" -- which the loader ignores and the
dialog keeps, so this needs no new plumbing. The dialog fills the columns from it and
marks them display-only: shown so the reviewer can see what was perceived, greyed
from editing because they are not part of what gets written, and skipped when the
entry is rebuilt. The emitted record stays 8-field and loadable.

Also colours the water counts in the editable cells themselves, not only the summary
("I meant in the editable fields").

While there: refresh_entry() was writing a hardcoded ionization index of 1 and a
single header pKa pair, the same two bugs just fixed in the emitter. It now numbers
indices from 1 and writes one pair per emitted ionization, so an entry edited in the
dialog round-trips as loadably as one written headless.

Tests unchanged: unit 86/0, hydration 37/0, psv 60/0. libus_somo builds clean.

Co-Authored-By: Claude Opus 5 <noreply at anthropic.com>
(cherry picked from commit 5bacee9b80ee3cab0f37294dcc06962d3dca17b5)


  Commit: 154cb217a37fe5be0a7f1d93aa9c00046180f73f
      https://github.com/ehb54/ultrascan3/commit/154cb217a37fe5be0a7f1d93aa9c00046180f73f
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/src/us_hydrodyn_perceive_dialog.cpp

  Log Message:
  -----------
  perceiver: split the hydration total onto two lines

As one line the caveat was the widest widget in the dialog, so the window
grew to fit it (Mattia, 2026-08-12). Break before the parenthetical: the
number and its ionized/non-ionized split stay together on line 1, the
caveat moves to line 2. Both the ionizable and non-ionizable variants.

Co-Authored-By: Claude Opus 5 <noreply at anthropic.com>
(cherry picked from commit 202cb61cc4073b43f24166a205c8d0e2a159d04c)


  Commit: 6f0798d1da70561c81cb76edccbf9ed98a40b058
      https://github.com/ehb54/ultrascan3/commit/6f0798d1da70561c81cb76edccbf9ed98a40b058
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/include/us_hydrodyn_perceive_dialog.h
    M us_somo/develop/perceiver/tests/tests_unit.cpp
    M us_somo/develop/src/us_hydrodyn_perceive.cpp
    M us_somo/develop/src/us_hydrodyn_perceive_dialog.cpp
    M us_somo/somo/doc/manual/somo/somo_perceive.html

  Log Message:
  -----------
  perceiver: phosphate convention for residues with >2 ionizable groups

somo.residue holds at most two ionizations per residue, so citrate's three
carboxyls used to collapse the whole entry to its pH 7 state -- correct at
pH 7 and frozen everywhere else.

Adopt the convention the coded table already uses for phosphate (ehb54 and
Mattia, 2026-08-12: "assume the first oxygen to be always deprotonated").
The lowest-pKa groups are written permanently deprotonated in the primary
fields; the two highest keep real switchable slots. Lowest-first is what
makes it defensible: that group is already fully ionized wherever the entry
is usable. Phosphate (2.15/7.20/12.35) reproduces the hand-written entry
exactly; citrate keeps its 2-/3- transition instead of being frozen.

The pKa becomes per-group rather than per-residue -- two switchable groups
can differ (citrate 4.76 and 6.40) and the header stores one pair per
ionization, selected by the atom's ionization index. One predicate now
drives both the atom line and the header pair so an index can never
reference a pair that was not declared.

Also fixes the bead hydration, which summed the protonated column while the
coded residues count ionizable atoms ionized (Asp's OD2 is 0/5 and Asp's
second bead is written 5). 2CMD's citrate emitted a bead of 1 against the 16
its own review dialog computed for the same entry; both now say 16.

6 new unit tests; regression unchanged at 99.833% geometric perception.
Help page updated: per-group pKa, and the convention documented.

Co-Authored-By: Claude Opus 5 <noreply at anthropic.com>
(cherry picked from commit fa2ad021f3ad467403b337a3166ef384eb0242c0)


  Commit: 7219ae0dee09d8a702752d60b7d6093119ef7965
      https://github.com/ehb54/ultrascan3/commit/7219ae0dee09d8a702752d60b7d6093119ef7965
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/version.sh

  Log Message:
  -----------
  somo: fix version.sh to read the current US_Version definition

version.sh extracted the version with

  sed -n '/0x0500/,/define/p' $us3/utils/us_defines.h | grep US_Vers

which depended on a 0x0500-delimited block that utils/us_defines.h no longer
has -- the version is now a plain '#define US_Version QString("4.2.0-dev")'.
The sed range matched nothing, so US_Version_string was generated empty and
every SOMO build carried a blank version.

Read the define directly instead, anchored so it cannot also match
US_Version_string.  Also strip the padding that BSD/macOS 'wc -l' puts in
front of the revision count (SOMO_Revision was 'SOMOgit- 185'), and silence
the grep errors on the first run, when include/us_version.h does not exist yet.

Before: US_Version_string ""          SOMO_Revision "SOMOgit- 185"
After:  US_Version_string "4.2.0-dev"  SOMO_Revision "SOMOgit-185"
(cherry picked from commit 6357594151cf1e07f30e20a832b5aaf623a789c1)
(cherry picked from commit 23a60b9ad635e383d834167a461cd0fddf3185c3)


  Commit: e660154cc960ba0d9a7bc71ca63ad2b4483881ef
      https://github.com/ehb54/ultrascan3/commit/e660154cc960ba0d9a7bc71ca63ad2b4483881ef
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M .gitignore

  Log Message:
  -----------
  somo: ignore the generated us_somo us_revision.h

main untracked us_somo/develop/include/us_revision.h (f57e5fb62) because it is
a build artifact -- libus_somo.pro regenerates it every build via the revision
extra-target -- but no ignore rule was added, so it shows up untracked after
every build.  That is how it gets committed by accident; somo-dev tracks the
generated header for exactly this reason.

The sibling artifact us_version.h and programs/us/us_revision.h are already
ignored here; add the missing us_somo one alongside them.

(cherry picked from commit c96829fb61a6bfae932c70c15ba0f5d5f8e82b2b)
(cherry picked from commit 169ba28af6e86d80a588fd5949dc79ef12e93f96)


  Commit: 4fabf4c087fe5a19e30d8614dcba4b2992e37841
      https://github.com/ehb54/ultrascan3/commit/4fabf4c087fe5a19e30d8614dcba4b2992e37841
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/src/us_hydrodyn_saxs_iqq_load_csv.cpp

  Log Message:
  -----------
  somo: hold back the extrapolate-to-zero-concentration control

The extrapolation code is merged and maintained, but the feature is not being
released yet.  Hide and disable its only user-facing control -- the
"Extrap. to zero conc" checkbox in the I(q) CSV load dialog -- so the code
travels with main without being offered.

Also clear the caller's *extrapolate_c0 flag here.  set_extrapolate_c0() is the
only thing that maintains it and it can no longer run, so a value left over from
an earlier session would otherwise stand with no way to clear it.

There is no manual page for this feature and no gui_script command for it on
this branch, so the checkbox is the whole surface.  To expose it later, restore
setEnabled(true)/setChecked(*extrapolate_c0) and drop the setVisible(false).

(cherry picked from commit 48a8da73386fe26bd0dc83714be122730146f0f9)


  Commit: 18ddf6844deea6f8c9ef06afaeedc1610210a88c
      https://github.com/ehb54/ultrascan3/commit/18ddf6844deea6f8c9ef06afaeedc1610210a88c
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/src/us_hydrodyn_perceive_dialog.cpp

  Log Message:
  -----------
  somo/perceive: hold back writing perceived entries into somo.residue

Perception itself is released: an uncoded residue is perceived and used for the
run through the session overlay, as before.  What is held back is the permanent
write into the user's own residue table.

- Disable the " Also append this entry to somo.residue " checkbox, and say why
  in the tooltip.  Left visible rather than hidden, so it is evident that the
  table is deliberately not being touched.
- Force save_requested_ false in accept_entry(), so the append cannot fire
  whatever state the disabled box is in.  That guards the single writer, at
  us_hydrodyn.cpp:2406.

The entry stays in the dialog's read-only box and in the log, so it can still be
copied out by hand.  To release: restore cb_save->isChecked() and its
setEnabled, and revert the tooltip.

(cherry picked from commit 0465d69edc58be59f68e1875b0461aa8b63f5ef9)


  Commit: 3a08b43d7d63f1ed405372947e037d921306271b
      https://github.com/ehb54/ultrascan3/commit/3a08b43d7d63f1ed405372947e037d921306271b
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    A us_somo/develop/perceiver/data/ref/cctbx_LICENSE.txt
    M us_somo/develop/perceiver/data/ref/it1992.cpp

  Log Message:
  -----------
  perceiver: retain the cctbx copyright notice on the vendored it1992.cpp

data/ref/it1992.cpp is a verbatim copy of cctbx's transcription of International
Tables Vol. C Table 6.1.1.4, carrying none of its copyright or license.  The
cctbx license is BSD-style and its condition (1) requires source redistributions
to retain the copyright notice, the conditions and the disclaimer.

Add the notice and vendor the full license text alongside as cctbx_LICENSE.txt.
The file is not compiled -- gen_saxs_entries.py parses it -- but it is
redistributed in source form, which is exactly what condition (1) covers.

Reported-by: aaron-auc


  Commit: 3cace687794aa91751658f87a10fb8457b857c6b
      https://github.com/ehb54/ultrascan3/commit/3cace687794aa91751658f87a10fb8457b857c6b
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/perceiver/tests/regression.cpp

  Log Message:
  -----------
  perceiver: fail the regression test when it scores nothing

The regression target scores against demo PDB structures that are NOT committed
to the repository.  read_pdb() returns an empty list for a missing file, so it
scored 0 atoms, every percentage divided by zero and printed 0.000%, and it
exited 0 -- reporting 'genuine perception errors remaining: 0 (0.000%)' having
looked at nothing.  Confirmed by running it from a clean checkout: it passed,
with 0 atoms scored, on all eight demo structures.

A test that reports success because it examined nothing is worse than no test.
Name any input that yielded no atoms, and exit 2 when nothing was scored at all,
saying that the demo structures are absent.

Committing the structures is a separate call: that is a data decision about size
and provenance, not a code fix.

Reported-by: aaron-auc


  Commit: ca3fc42d25957af2c3ac1fef4d9c3f9b4cebb4ce
      https://github.com/ehb54/ultrascan3/commit/ca3fc42d25957af2c3ac1fef4d9c3f9b4cebb4ce
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    A .github/workflows/somo-module-tests.yml

  Log Message:
  -----------
  somo: run the perceiver suite in CI, and assert the vacuous-pass guard

The perceiver tests were only ever run by hand, so a change could pass CI while
breaking the behaviour they cover.

The workflow runs the perceiver unit tests -- Qt-free, standalone -- and asserts
the guard added alongside it: with no input, bin/regression must FAIL rather than
report 0.000% and exit 0.

The regression target proper stays out of CI until it has structures to score.

(An equivalent job for the in-process grpy module is deliberately absent: that
module is not part of this merge, see the licence note on the ticket.)


  Commit: 2a584cacd1e8a82e9c492a57d4fb5f5655e84795
      https://github.com/ehb54/ultrascan3/commit/2a584cacd1e8a82e9c492a57d4fb5f5655e84795
  Author: ehb54 <brookes at uthscsa.edu>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    M us_somo/develop/src/us_hydrodyn_load.cpp

  Log Message:
  -----------
  somo: silence the per-atom debug dump at the end of calc_mw()

It printed "end of calc_mw()" and then one CSV row per atom on every PDB load
-- thousands of lines for a large structure -- which slows a debug cycle when
stdout is a terminal or an editor shell.

Commented rather than deleted: it is diagnostic, not dead, and is the thing to
re-enable when ionization or net-charge numbers look wrong. Left with a note
of the caveat that made it misleading anyway -- its pH is hardwired to 7 rather
than read from the form, so it does not describe the pH actually in use; the
already-commented call immediately above is the variant that does.

Matches the several other commented-out info_* diagnostics around it.

Co-Authored-By: Claude Opus 5 <noreply at anthropic.com>
(cherry picked from commit faf147fa301e7485b3f1f68bb4c54fceee7f4c70)


  Commit: aabbfce4341e05ae22094eca86391082b6a3fba3
      https://github.com/ehb54/ultrascan3/commit/aabbfce4341e05ae22094eca86391082b6a3fba3
  Author: emre brookes <ehb54 at users.noreply.github.com>
  Date:   2026-08-17 (Mon, 17 Aug 2026)

  Changed paths:
    A .github/workflows/somo-module-tests.yml
    M .gitignore
    M us_somo/develop/include/us_hydrodyn.h
    M us_somo/develop/include/us_hydrodyn_dad.h
    M us_somo/develop/include/us_hydrodyn_dad_fit.h
    M us_somo/develop/include/us_hydrodyn_dad_options.h
    A us_somo/develop/include/us_hydrodyn_grid_volume.h
    A us_somo/develop/include/us_hydrodyn_hydration.h
    M us_somo/develop/include/us_hydrodyn_mals_fit.h
    M us_somo/develop/include/us_hydrodyn_mals_options.h
    M us_somo/develop/include/us_hydrodyn_mals_saxs_fit.h
    M us_somo/develop/include/us_hydrodyn_mals_saxs_options.h
    M us_somo/develop/include/us_hydrodyn_pdb_parsing.h
    A us_somo/develop/include/us_hydrodyn_perceive.h
    A us_somo/develop/include/us_hydrodyn_perceive_dialog.h
    A us_somo/develop/include/us_hydrodyn_perceive_elements.h
    A us_somo/develop/include/us_hydrodyn_perceive_hybrid.h
    A us_somo/develop/include/us_hydrodyn_perceive_saxs.h
    A us_somo/develop/include/us_hydrodyn_perceive_somo.h
    A us_somo/develop/include/us_hydrodyn_psv.h
    A us_somo/develop/include/us_hydrodyn_residue_builder.h
    M us_somo/develop/include/us_hydrodyn_saxs.h
    M us_somo/develop/include/us_hydrodyn_saxs_hplc.h
    A us_somo/develop/include/us_hydrodyn_saxs_iqq_extrap_c0_conc.h
    M us_somo/develop/include/us_hydrodyn_saxs_iqq_load_csv.h
    M us_somo/develop/include/us_saxs_util.h
    M us_somo/develop/include/us_vector.h
    M us_somo/develop/libus_somo.pro
    A us_somo/develop/perceiver/.gitignore
    A us_somo/develop/perceiver/DECISIONS.md
    A us_somo/develop/perceiver/GUI_TESTING.md
    A us_somo/develop/perceiver/Makefile
    A us_somo/develop/perceiver/README.md
    A us_somo/develop/perceiver/data/non-coded/1MBO.pdb
    A us_somo/develop/perceiver/data/non-coded/2CMD.pdb
    A us_somo/develop/perceiver/data/non-coded/3PTB.pdb
    A us_somo/develop/perceiver/data/non-coded/5PTI.pdb
    A us_somo/develop/perceiver/data/non-coded/8RATNC.pdb
    A us_somo/develop/perceiver/data/non-coded/8RAT_gap3.pdb
    A us_somo/develop/perceiver/data/non-coded/8RAT_run3.pdb
    A us_somo/develop/perceiver/data/non-coded/README.md
    A us_somo/develop/perceiver/data/psv/1BEB.pdb
    A us_somo/develop/perceiver/data/psv/2CGA.pdb
    A us_somo/develop/perceiver/data/psv/README.md
    A us_somo/develop/perceiver/data/psv/candidates.fasta
    A us_somo/develop/perceiver/data/psv_measured.txt
    A us_somo/develop/perceiver/data/ref/cctbx_LICENSE.txt
    A us_somo/develop/perceiver/data/ref/f0_WaasKirf.dat
    A us_somo/develop/perceiver/data/ref/it1992.cpp
    A us_somo/develop/perceiver/data/ref/somo.saxs_atoms.generated
    A us_somo/develop/perceiver/examples/perceive.somo
    A us_somo/develop/perceiver/pdb_lite.h
    A us_somo/develop/perceiver/residue_oracle.h
    A us_somo/develop/perceiver/run_dialog_test.sh
    A us_somo/develop/perceiver/tests/builder.cpp
    A us_somo/develop/perceiver/tests/coverage.cpp
    A us_somo/develop/perceiver/tests/dialog_qt.cpp
    A us_somo/develop/perceiver/tests/emit_residue.cpp
    A us_somo/develop/perceiver/tests/grid_volume.cpp
    A us_somo/develop/perceiver/tests/hydration.cpp
    A us_somo/develop/perceiver/tests/protein_psv.cpp
    A us_somo/develop/perceiver/tests/psv.cpp
    A us_somo/develop/perceiver/tests/regression.cpp
    A us_somo/develop/perceiver/tests/sssr.cpp
    A us_somo/develop/perceiver/tests/sssr_real.cpp
    A us_somo/develop/perceiver/tests/tests_unit.cpp
    A us_somo/develop/perceiver/tinytest.h
    A us_somo/develop/perceiver/tools/calibrate_3v_context.py
    A us_somo/develop/perceiver/tools/gen_saxs_entries.py
    A us_somo/develop/perceiver/tools/hydration_table.py
    A us_somo/develop/perceiver/tools/make_noncoded_variant.py
    A us_somo/develop/perceiver/tools/psv_durchschlag.py
    A us_somo/develop/perceiver/tools/psv_model.py
    A us_somo/develop/perceiver/tools/recalc_ligand_volumes.py
    M us_somo/develop/src/us_hydrodyn.cpp
    M us_somo/develop/src/us_hydrodyn_beads.cpp
    M us_somo/develop/src/us_hydrodyn_core.cpp
    M us_somo/develop/src/us_hydrodyn_dad.cpp
    M us_somo/develop/src/us_hydrodyn_dad_conc.cpp
    M us_somo/develop/src/us_hydrodyn_dad_conc_load.cpp
    M us_somo/develop/src/us_hydrodyn_dad_fit.cpp
    M us_somo/develop/src/us_hydrodyn_dad_makeiq.cpp
    M us_somo/develop/src/us_hydrodyn_dad_modes.cpp
    M us_somo/develop/src/us_hydrodyn_dad_options.cpp
    A us_somo/develop/src/us_hydrodyn_dad_script.cpp
    M us_somo/develop/src/us_hydrodyn_dad_util.cpp
    M us_somo/develop/src/us_hydrodyn_fractal_dimension.cpp
    A us_somo/develop/src/us_hydrodyn_grid_volume.cpp
    A us_somo/develop/src/us_hydrodyn_hydration.cpp
    M us_somo/develop/src/us_hydrodyn_load.cpp
    M us_somo/develop/src/us_hydrodyn_mals.cpp
    M us_somo/develop/src/us_hydrodyn_mals_conc.cpp
    M us_somo/develop/src/us_hydrodyn_mals_conc_load.cpp
    M us_somo/develop/src/us_hydrodyn_mals_fit.cpp
    M us_somo/develop/src/us_hydrodyn_mals_makeiq.cpp
    M us_somo/develop/src/us_hydrodyn_mals_modes.cpp
    M us_somo/develop/src/us_hydrodyn_mals_options.cpp
    M us_somo/develop/src/us_hydrodyn_mals_saxs.cpp
    M us_somo/develop/src/us_hydrodyn_mals_saxs_conc.cpp
    M us_somo/develop/src/us_hydrodyn_mals_saxs_conc_load.cpp
    M us_somo/develop/src/us_hydrodyn_mals_saxs_fit.cpp
    M us_somo/develop/src/us_hydrodyn_mals_saxs_makeiq.cpp
    M us_somo/develop/src/us_hydrodyn_mals_saxs_modes.cpp
    M us_somo/develop/src/us_hydrodyn_mals_saxs_options.cpp
    M us_somo/develop/src/us_hydrodyn_mals_saxs_util.cpp
    M us_somo/develop/src/us_hydrodyn_mals_util.cpp
    M us_somo/develop/src/us_hydrodyn_other.cpp
    M us_somo/develop/src/us_hydrodyn_pdb_parsing.cpp
    M us_somo/develop/src/us_hydrodyn_pdb_tool.cpp
    A us_somo/develop/src/us_hydrodyn_perceive.cpp
    A us_somo/develop/src/us_hydrodyn_perceive_dialog.cpp
    A us_somo/develop/src/us_hydrodyn_perceive_somo.cpp
    A us_somo/develop/src/us_hydrodyn_psv.cpp
    A us_somo/develop/src/us_hydrodyn_residue_builder.cpp
    M us_somo/develop/src/us_hydrodyn_saxs.cpp
    M us_somo/develop/src/us_hydrodyn_saxs_1d.cpp
    M us_somo/develop/src/us_hydrodyn_saxs_2d.cpp
    M us_somo/develop/src/us_hydrodyn_saxs_buffer.cpp
    M us_somo/develop/src/us_hydrodyn_saxs_buffer_conc.cpp
    M us_somo/develop/src/us_hydrodyn_saxs_buffer_conc_load.cpp
    M us_somo/develop/src/us_hydrodyn_saxs_hplc.cpp
    M us_somo/develop/src/us_hydrodyn_saxs_hplc_bl.cpp
    M us_somo/develop/src/us_hydrodyn_saxs_hplc_ciq.cpp
    M us_somo/develop/src/us_hydrodyn_saxs_hplc_conc.cpp
    M us_somo/develop/src/us_hydrodyn_saxs_hplc_conc_load.cpp
    M us_somo/develop/src/us_hydrodyn_saxs_hplc_gui.cpp
    M us_somo/develop/src/us_hydrodyn_saxs_hplc_makeiq.cpp
    M us_somo/develop/src/us_hydrodyn_saxs_hplc_modes.cpp
    M us_somo/develop/src/us_hydrodyn_saxs_hplc_options.cpp
    M us_somo/develop/src/us_hydrodyn_saxs_hplc_util.cpp
    M us_somo/develop/src/us_hydrodyn_saxs_iqq.cpp
    A us_somo/develop/src/us_hydrodyn_saxs_iqq_extrap_c0.cpp
    A us_somo/develop/src/us_hydrodyn_saxs_iqq_extrap_c0_conc.cpp
    M us_somo/develop/src/us_hydrodyn_saxs_iqq_load_csv.cpp
    M us_somo/develop/src/us_hydrodyn_saxs_loads.cpp
    M us_somo/develop/src/us_hydrodyn_script.cpp
    M us_somo/develop/src/us_hydrodyn_settings.cpp
    M us_somo/develop/src/us_saxs_util_best.cpp
    M us_somo/develop/src/us_saxs_util_dmd.cpp
    M us_somo/develop/src/us_saxs_util_hydro.cpp
    M us_somo/develop/src/us_saxs_util_loads.cpp
    M us_somo/develop/src/us_saxs_util_static.cpp
    M us_somo/develop/src/us_vector.cpp
    M us_somo/develop/version.sh
    M us_somo/etc/somo.atom.new
    M us_somo/etc/somo.config.new
    M us_somo/etc/somo.defaults.new
    M us_somo/etc/somo.hybrid.new
    M us_somo/etc/somo.residue.new
    M us_somo/etc/somo.saxs_atoms.new
    A us_somo/somo/doc/manual/somo/DAWN_head.png
    A us_somo/somo/doc/manual/somo/MALS_angles.png
    A us_somo/somo/doc/manual/somo/WyattRayleigh ratios csv.png
    M us_somo/somo/doc/manual/somo/mals_parameters.html
    M us_somo/somo/doc/manual/somo/mals_saxs_options.html
    M us_somo/somo/doc/manual/somo/saxs_hplc_ciq.html
    M us_somo/somo/doc/manual/somo/saxs_hplc_options.html
    M us_somo/somo/doc/manual/somo/somo-HPLC-SAXS_EMG_option.png
    M us_somo/somo/doc/manual/somo/somo-HPLC-SAXS_GaussFit1.png
    M us_somo/somo/doc/manual/somo/somo-HPLC-SAXS_GaussFit2.png
    A us_somo/somo/doc/manual/somo/somo-HPLC-SAXS_options_Min_Gauss.png
    M us_somo/somo/doc/manual/somo/somo-HPLC-SAXS_options_new.png
    M us_somo/somo/doc/manual/somo/somo-HPLC-SAXS_options_new_Gaussians.png
    M us_somo/somo/doc/manual/somo/somo-HPLC-SAXS_options_new_baseline.png
    M us_somo/somo/doc/manual/somo/somo-HPLC-SAXS_skewedGaussian1.png
    M us_somo/somo/doc/manual/somo/somo-HPLC-SAXS_skewedGaussian11.png
    M us_somo/somo/doc/manual/somo/somo-HPLC-SAXS_skewedGaussian11a.png
    M us_somo/somo/doc/manual/somo/somo-HPLC-SAXS_skewedGaussian11b.png
    M us_somo/somo/doc/manual/somo/somo-HPLC-SAXS_skewedGaussian11c.png
    M us_somo/somo/doc/manual/somo/somo-HPLC-SAXS_skewedGaussian12.png
    M us_somo/somo/doc/manual/somo/somo-HPLC-SAXS_skewedGaussian2.png
    M us_somo/somo/doc/manual/somo/somo-HPLC-SAXS_skewedGaussian3.png
    M us_somo/somo/doc/manual/somo/somo-HPLC-SAXS_skewedGaussian4.png
    M us_somo/somo/doc/manual/somo/somo-HPLC-SAXS_skewedGaussian5.png
    A us_somo/somo/doc/manual/somo/somo-HPLC-SAXS_skewedGaussian6a.png
    M us_somo/somo/doc/manual/somo/somo-HPLC-SAXS_skewedGaussian8.png
    M us_somo/somo/doc/manual/somo/somo-HPLC-SAXS_skewedGaussian9a.png
    M us_somo/somo/doc/manual/somo/somo-HPLC-SAXS_skewedGaussian_adv_sel.png
    M us_somo/somo/doc/manual/somo/somo-HPLC-SAXS_smoothing.png
    A us_somo/somo/doc/manual/somo/somo-MALS_Concs.png
    A us_somo/somo/doc/manual/somo/somo-MALS_Concs2.png
    A us_somo/somo/doc/manual/somo/somo-MALS_Concs3.png
    A us_somo/somo/doc/manual/somo/somo-MALS_Concs4.png
    A us_somo/somo/doc/manual/somo/somo-MALS_Gauss1anew.png
    A us_somo/somo/doc/manual/somo/somo-MALS_Gauss1bnew.png
    A us_somo/somo/doc/manual/somo/somo-MALS_Gauss1cnew.png
    A us_somo/somo/doc/manual/somo/somo-MALS_Gauss1dnew.png
    A us_somo/somo/doc/manual/somo/somo-MALS_Gauss1enew.png
    A us_somo/somo/doc/manual/somo/somo-MALS_GaussFit.png
    A us_somo/somo/doc/manual/somo/somo-MALS_Gauss_all_Idash_t_selected.png
    A us_somo/somo/doc/manual/somo/somo-MALS_Gaussian_final.png
    A us_somo/somo/doc/manual/somo/somo-MALS_Gaussian_init.png
    A us_somo/somo/doc/manual/somo/somo-MALS_Gaussian_options.png
    A us_somo/somo/doc/manual/somo/somo-MALS_Gaussian_start.png
    A us_somo/somo/doc/manual/somo/somo-MALS_GlobalFit_done.png
    A us_somo/somo/doc/manual/somo/somo-MALS_GlobalGauss_done.png
    A us_somo/somo/doc/manual/somo/somo-MALS_GlobalGauss_start_pop_up.png
    A us_somo/somo/doc/manual/somo/somo-MALS_GlobalGaussianSDreminder.png
    A us_somo/somo/doc/manual/somo/somo-MALS_GlobalGaussian_init.png
    A us_somo/somo/doc/manual/somo/somo-MALS_I_hash_q_example.png
    A us_somo/somo/doc/manual/somo/somo-MALS_I_starq_NoGauss_movieframe155.png
    A us_somo/somo/doc/manual/somo/somo-MALS_I_starq_NoGauss_movieframe316.png
    A us_somo/somo/doc/manual/somo/somo-MALS_I_starq_NoGauss_movieframe99.png
    A us_somo/somo/doc/manual/somo/somo-MALS_Istarq_file_view_selected.png
    A us_somo/somo/doc/manual/somo/somo-MALS_MakeIdash_final.png
    A us_somo/somo/doc/manual/somo/somo-MALS_MakeIdash_final_kin.png
    A us_somo/somo/doc/manual/somo/somo-MALS_MakeIdash_final_kin_cropped.png
    A us_somo/somo/doc/manual/somo/somo-MALS_MakeIdash_final_kin_zoom.png
    A us_somo/somo/doc/manual/somo/somo-MALS_MakeIstar_final_kin.png
    A us_somo/somo/doc/manual/somo/somo-MALS_MakeIstar_sel_kin_dots_err.png
    A us_somo/somo/doc/manual/somo/somo-MALS_Messages.png
    A us_somo/somo/doc/manual/somo/somo-MALS_Movie_selected.png
    A us_somo/somo/doc/manual/somo/somo-MALS_Plot_Options_demo.png
    A us_somo/somo/doc/manual/somo/somo-MALS_Produced_data.png
    A us_somo/somo/doc/manual/somo/somo-MALS_R_theta_csv_loaded.png
    A us_somo/somo/doc/manual/somo/somo-MALS_R_theta_kin_shown.png
    A us_somo/somo/doc/manual/somo/somo-MALS_R_theta_shown.png
    A us_somo/somo/doc/manual/somo/somo-MALS_Residuals_twocurvesSD.png
    A us_somo/somo/doc/manual/somo/somo-MALS_Residuals_twocurves_percent.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_MALS_data_loglog.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_Make_scaled_popup.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_Messages.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_Plot_Options_demo.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_Plot_Options_demo2.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_Produced_data.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_Produced_data_buttons.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_SAXS_common_times.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_SAXS_common_times_scroll1.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_SAXS_common_times_scroll2.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_SAXS_data_loading.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_bottom line.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_commons times_popup.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_commontimes_all_dots.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_cropping_buttons.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_cropvis_results.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_cropvis_results1.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_cropvis_select.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_exclude_q_vis_demo1.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_exclude_q_vis_demo2.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_fitting_methods.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_generating_joined_excl_q_popup.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_initial.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_joined.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_joined_scroll.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_loadMALS.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_make_scaled.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_make_scaled_popup1.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_make_scaled_popup2.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_make_scaled_view_MALS_file.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_minimize_popup.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_options.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_options1.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_other_MALS_data_popup.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_plot_buttons.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_polynomials.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_q_exclude_buttons.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_remove_panel.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_scale1.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_scale2.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_scale3.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_scale4.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_scale5.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_scale6.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_scale7.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_scale8.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_scaled_MALS_generated_popup.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_scaled_SAXS_generated_popup.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_scroll_warning.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_second_set_buttons.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_second_set_buttons1.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_selections_buttons.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_top_buttons.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_viewselected.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SAXS_weighting_methods.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SD_eval_applied.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SD_eval_buttons.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SD_eval_comparisonD2.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SD_eval_define_1region.png
    A us_somo/somo/doc/manual/somo/somo-MALS_SD_eval_define_2regions.png
    A us_somo/somo/doc/manual/somo/somo-MALS_Select_Istarq_for_norm.png
    A us_somo/somo/doc/manual/somo/somo-MALS_Selected_Istarq_normalized.png
    A us_somo/somo/doc/manual/somo/somo-MALS_Selected_Istarq_normalized_ave.png
    A us_somo/somo/doc/manual/somo/somo-MALS_Selected_normalized_ave.png
    A us_somo/somo/doc/manual/somo/somo-MALS_Selected_orig_and_norm_files.png
    A us_somo/somo/doc/manual/somo/somo-MALS_UV_data_pop_up.png
    A us_somo/somo/doc/manual/somo/somo-MALS_adjust_times_pop_up.png
    A us_somo/somo/doc/manual/somo/somo-MALS_adjust_times_pop_up2.png
    A us_somo/somo/doc/manual/somo/somo-MALS_angles_pop_up.png
    A us_somo/somo/doc/manual/somo/somo-MALS_commands1.png
    A us_somo/somo/doc/manual/somo/somo-MALS_conc_chrom_Gauss_fit.png
    A us_somo/somo/doc/manual/somo/somo-MALS_conc_chrom_fit_module.png
    A us_somo/somo/doc/manual/somo/somo-MALS_conc_chrom_init_Gauss.png
    A us_somo/somo/doc/manual/somo/somo-MALS_conc_used_pop_up.png
    A us_somo/somo/doc/manual/somo/somo-MALS_conc_util_add_MALS_data.png
    A us_somo/somo/doc/manual/somo/somo-MALS_conc_util_buttons.png
    A us_somo/somo/doc/manual/somo/somo-MALS_conc_util_loaded_data.png
    A us_somo/somo/doc/manual/somo/somo-MALS_conc_util_pop_up.png
    A us_somo/somo/doc/manual/somo/somo-MALS_conc_util_pop_up2.png
    A us_somo/somo/doc/manual/somo/somo-MALS_conc_util_pop_up3.png
    A us_somo/somo/doc/manual/somo/somo-MALS_conc_util_repeak.png
    A us_somo/somo/doc/manual/somo/somo-MALS_conc_util_timeshift.png
    A us_somo/somo/doc/manual/somo/somo-MALS_conc_util_timeshift_set.png
    A us_somo/somo/doc/manual/somo/somo-MALS_crop_I_dash_chromatograms.png
    A us_somo/somo/doc/manual/somo/somo-MALS_cropping_buttons.png
    A us_somo/somo/doc/manual/somo/somo-MALS_inconsistent times_pop_up.png
    A us_somo/somo/doc/manual/somo/somo-MALS_incorrect processing_param_pop_up.png
    A us_somo/somo/doc/manual/somo/somo-MALS_info_panel.png
    A us_somo/somo/doc/manual/somo/somo-MALS_initial.png
    A us_somo/somo/doc/manual/somo/somo-MALS_main1.png
    A us_somo/somo/doc/manual/somo/somo-MALS_make_Istar_q_enterparam_popup.png
    A us_somo/somo/doc/manual/somo/somo-MALS_make_Istar_q_enterparam_popup1.png
    A us_somo/somo/doc/manual/somo/somo-MALS_make_Istar_q_noGauss_popup.png
    A us_somo/somo/doc/manual/somo/somo-MALS_no_Gaussians_pop_up.png
    A us_somo/somo/doc/manual/somo/somo-MALS_no_conc_pop_up.png
    A us_somo/somo/doc/manual/somo/somo-MALS_no_conc_pop_up2.png
    A us_somo/somo/doc/manual/somo/somo-MALS_options.png
    A us_somo/somo/doc/manual/somo/somo-MALS_options_conc_detector.png
    A us_somo/somo/doc/manual/somo/somo-MALS_options_new_Gaussians.png
    A us_somo/somo/doc/manual/somo/somo-MALS_options_new_misc.png
    A us_somo/somo/doc/manual/somo/somo-MALS_param.png
    A us_somo/somo/doc/manual/somo/somo-MALS_plot_buttons.png
    A us_somo/somo/doc/manual/somo/somo-MALS_processing_param_pop_up.png
    A us_somo/somo/doc/manual/somo/somo-MALS_processing_param_pop_up2.png
    A us_somo/somo/doc/manual/somo/somo-MALS_remove_panel.png
    A us_somo/somo/doc/manual/somo/somo-MALS_resulting_I_starq_NoGauss.png
    A us_somo/somo/doc/manual/somo/somo-MALS_scattering_angles.png
    A us_somo/somo/doc/manual/somo/somo-MALS_second_set_buttons.png
    A us_somo/somo/doc/manual/somo/somo-MALS_selected_Ihash_EMG_GMG.png
    A us_somo/somo/doc/manual/somo/somo-MALS_selections_buttons.png
    A us_somo/somo/doc/manual/somo/somo-MALS_set_conc_detector.png
    A us_somo/somo/doc/manual/somo/somo-MALS_seven_Gaussians1.png
    A us_somo/somo/doc/manual/somo/somo-MALS_seven_Gaussians2.png
    A us_somo/somo/doc/manual/somo/somo-MALS_seven_Gaussians_GlobFit_Final.png
    A us_somo/somo/doc/manual/somo/somo-MALS_seven_Gaussians_GlobFit_Init.png
    A us_somo/somo/doc/manual/somo/somo-MALS_seven_Gaussians_GlobFit_by_q.png
    A us_somo/somo/doc/manual/somo/somo-MALS_seven_Gaussians_GlobFit_saving_warning.png
    A us_somo/somo/doc/manual/somo/somo-MALS_seven_Gaussians_GlobGauss.png
    A us_somo/somo/doc/manual/somo/somo-MALS_seven_Gaussians_scroll1.png
    A us_somo/somo/doc/manual/somo/somo-MALS_seven_Gaussians_scroll2.png
    A us_somo/somo/doc/manual/somo/somo-MALS_six_Gaussians1.png
    A us_somo/somo/doc/manual/somo/somo-MALS_six_Gaussians2.png
    A us_somo/somo/doc/manual/somo/somo-MALS_timeshift_pop_up.png
    A us_somo/somo/doc/manual/somo/somo-MALS_timeshift_pop_up2.png
    A us_somo/somo/doc/manual/somo/somo-MALS_top_buttons.png
    A us_somo/somo/doc/manual/somo/somo-mals_Residuals_twocurves.png
    A us_somo/somo/doc/manual/somo/somo-perceive.png
    M us_somo/somo/doc/manual/somo/somo.html
    M us_somo/somo/doc/manual/somo/somo_mals.html
    A us_somo/somo/doc/manual/somo/somo_mals_dctr.html
    A us_somo/somo/doc/manual/somo/somo_mals_options.html
    M us_somo/somo/doc/manual/somo/somo_mals_saxs.html
    M us_somo/somo/doc/manual/somo/somo_pdb_parsing.html
    M us_somo/somo/doc/manual/somo/somo_pdb_parsing_expert_mode.html
    A us_somo/somo/doc/manual/somo/somo_perceive.html
    M us_somo/somo/doc/manual/somo/somo_saxs_hplc.html
    M us_somo/somo/doc/manual/somo/somo_saxs_hplc_skewedGauss.html
    M us_somo/somo/doc/manual/somo/somo_uv_vis.html
    A us_somo/somo/doc/manual/somo_mals.html

  Log Message:
  -----------
  Merge pull request #517 from ehb54/ehb54-issue-1009-somo-merge

SOMO: merge the somo-dev backlog and the perceiver into main (GRPY excluded)


Compare: https://github.com/ehb54/ultrascan3/compare/ecd796cb83c9...aabbfce4341e

To unsubscribe from these emails, change your notification settings at https://github.com/ehb54/ultrascan3/settings/notifications


More information about the us-commits mailing list