UI Category Membership Tidying¶
Status¶
Implemented 2026-09-13 (proposed, extended with the Reconstruct 3D and
Post-processing categories and the export_manifoldem_starproject removal,
and implemented the same day). This note is the single design,
implementation, review, and validation record for the change. See
"Implementation and Validation Record" at the end.
Objective¶
Four things, each in its own commit:
- Introduce a user-facing Reconstruct 3D Workflows category containing
exactly
reconstruct3Dandbootstrap_rec3D, which are currently listed under Refine 3D Workflows. - Introduce a user-facing Post-processing category containing exactly
postprocessandpostprocess_nu, currently split between Refine 3D Workflows and Filtering. - Relocate six
simple_execprograms whose UI category disagrees with what they do, so that every program is found where a user would look for it. - Remove the
export_manifoldem_starprojectprogram.
The categories and the relocations follow the pattern established by
../completed/heterogeneity_analysis_ui_and_algorithm_docs_refactoring.md:
move the Fortran construction to the module that owns the target category,
leave execution routing and commanders untouched, and assert the result in
simple_test_ui_visibility. The removal follows the ppca_volvar removal in
that same note.
Apart from the removal, program names, command-line contracts, execution
routing, commanders, algorithms, and project artifacts remain unchanged.
Descriptor wording is not touched except for one summary that is factually
wrong (automask); the broader wording pass is a separate note.
Current State¶
The category survey behind this note (all 19 simple_exec categories, from
the generated complete UI JSON) found the taxonomy sound overall, with these
misplacements:
| Program | Current UI module (category) | Target UI module (category) | Execution router (unchanged) | Commander module (unchanged) |
|---|---|---|---|---|
reconstruct3D |
simple_ui_refine3D (Refine 3D Workflows) |
simple_ui_reconstruct3D (Reconstruct 3D Workflows, new) |
simple_exec_refine3D |
simple_commanders_refine3D |
bootstrap_rec3D |
simple_ui_refine3D (Refine 3D Workflows) |
simple_ui_reconstruct3D (Reconstruct 3D Workflows, new) |
simple_exec_refine3D |
simple_commanders_refine3D |
postprocess |
simple_ui_refine3D (Refine 3D Workflows) |
simple_ui_postprocess (Post-processing, new) |
simple_exec_refine3D |
simple_commanders_volops |
postprocess_nu |
simple_ui_filter (Filtering) |
simple_ui_postprocess (Post-processing, new) |
simple_exec_filter |
simple_commanders_postprocess_nu |
automask |
simple_ui_refine3D (Refine 3D Workflows) |
simple_ui_mask (Masking) |
simple_exec_refine3D |
simple_commanders_mask |
ptcl3D_state_consensus |
simple_ui_project (Project Management) |
simple_ui_heterogeneity (Heterogeneity Analysis) |
simple_exec_project |
simple_commanders_project_core |
cls_split |
simple_ui_denoise (Denoising) |
simple_ui_cluster2D (Cluster2D Workflows) |
simple_exec_denoise |
simple_commanders_denoise |
fractionate_movies |
simple_ui_other (Other Utilities) |
simple_ui_preproc (Pre-processing) |
simple_exec_other |
simple_commanders_misc |
split |
simple_ui_other (Other Utilities) |
simple_ui_image (General Image Processing) |
simple_exec_other |
simple_commanders_distr |
split_stack |
simple_ui_other (Other Utilities) |
simple_ui_image (General Image Processing) |
simple_exec_other |
simple_commanders_project_ptcl |
Rationale per program:
reconstruct3Dandbootstrap_rec3Dare reconstruction workflows, not refinement:reconstruct3Dbuilds volumes from already-oriented particles and is invoked internally byabinitio3D,refine3D, andrefine3D_states;bootstrap_rec3Dis the complete final-reconstruction sequence (sigma2 seeding plus ML-regularized reconstruction). Listing them under Refine 3D Workflows hides the step users run after refinement or heterogeneity analysis.sigma2_convertandcenterwere considered and deliberately left where they are.postprocess("Filter and sharpen a reconstructed density map for interpretation") andpostprocess_nu("Nonuniform evidence-bounded postprocessing of even/odd half-maps") are the uniform and nonuniform variants of the same final step, yet a user finds one under Refine 3D and the other under Filtering.nu_filt3Dwas considered and left in Filtering: it is a local low-pass filter applied by name, not a sharpening/interpretation step.automaskperforms envelope masking (exec_automaskcallsmskvol%automask3Dand writesautomask3D_masked_vol.mrc); its commander already lives in the masking module and its help text says "automated envelope masking". Only its UI registration and its summary ("Create a spherical mask from the estimated particle diameter", which describesauto_spher_mask, not this program) place it elsewhere. Masking rather than Post-processing because it is also used ahead of refinement.ptcl3D_state_consensusbuilds a consensus particle-state assignment from a file table of projects, i.e. it post-processesrefine3D_states/classify3D_refsruns. It is the fourth heterogeneity-analysis program.cls_split("Split classes with latent clustering") splits 2D/3D particle classes into subclasses by diffusion-map or kPCA embedding and k-medoids, then regenerates class averages throughmake_cavgs. It operates on class memberships, likesample_classesandbootstrap_cavgs, and has nothing to do with denoising beyond sharing the PCA machinery; its commander's module name is historical.reimport_particles("Re-import denoised particle stack") was briefly considered for Denoising during review and rejected: it replaces the project particle stack while preserving particle/class metadata, and a denoised stack is only its typical input. It stays in Project Management.fractionate_moviesre-generates micrographs from selected movie frames; it is a pre-processing step with a distributed workflow, likemotion_correct.splitandsplit_stackare stack utilities; their counterpartstack("Combine image files or stacks into one stack") is in General Image Processing.
Note that the split UI object is named split_ in simple_ui_other.f90
(type(ui_program), target :: split_, constructor new_split_); the
relocation must keep that spelling.
export_manifoldem_starproject exports a particles3D_manifoldem.star file
for ManifoldEM. It is defined in these places and nowhere else:
| Item | Location |
|---|---|
UI object, constructor new_export_manifoldem_starproject, registration |
src/main/ui/simple/simple_ui_project.f90 |
Execution case, xexport_manifoldem_starproject instance, and the commander import |
src/main/exec/simple_exec_project.f90 |
commander_export_manifoldem_starproject and exec_export_manifoldem_starproject |
src/main/commanders/simple/simple_commanders_starproject.f90 |
export_manifoldem_ptcls3D (type-bound procedure, no other caller) |
src/main/star/simple_starproject.f90 |
| Generated symbol indexes | doc/code_overview/fortran-indexes/ |
No test, script, algorithm chapter, or user guide references it; the only prose mentions are in a rejected refactoring note and a completed implementation note, which are historical records and stay as they are.
Two further findings from the survey are recorded here as decisions, not as part of this change:
extract_subproj("extraction of a subproject of time-series of metallic nanoparticles") is a nanoparticle time-series program registered undersimple_execProject Management. The natural home is thesingle_execTime-series Pre-processing category, but that changes the executable and is therefore a command-line contract change, out of scope for a mechanical move. Decide separately whether to move it (with a deprecation alias) or leave it.mini_stream("standalone mini_stream for a quick look") sits in Validation. No othersimple_execcategory fits better, and the stream programs live in the separatesimple_streamexecutable. Leave it; fix its summary in the wording pass.
Near-duplicate pairs were checked and are not duplicates: automask
(envelope) and auto_spher_mask (spherical) differ; noisevol (volumes,
nstates; called internally by simple_commanders_abinitio2D) and
simulate_noise (2D images, nptcls; its summary "images or volumes" is
wrong) differ. Both pairs stay.
Proposed Target Design¶
New category contracts¶
Two new descriptors, one per new module:
! src/main/ui/simple/simple_ui_reconstruct3D.f90
type(category_descriptor), parameter :: UI_CATEGORY = &
category_descriptor('reconstruct3d', 'Reconstruct 3D Workflows', 68)
! src/main/ui/simple/simple_ui_postprocess.f90
type(category_descriptor), parameter :: UI_CATEGORY = &
category_descriptor('postprocess', 'Post-processing', 69)
Orders 68 and 69 sit after Heterogeneity Analysis (65) and before
Denoising (70), so the listing reads Refine 3D → Heterogeneity Analysis →
Reconstruct 3D → Post-processing → Denoising: final maps, then their
interpretation, after either refinement path. simple_exec orders 10 to 190
in steps of 10 plus 65 are taken; 68 and 69 are free. Both identifiers are
the lowercase suffix of their module name, as the UI policy requires
(compare simple_ui_refine3D → refine3d). The category identifier
postprocess coincides with the program name postprocess; the two are
separate namespaces (ui_program%category versus the ui_hash key) and
nothing in the registry, JSON writer, or validator conflates them. The
heading "Reconstruct 3D Workflows" parallels "Refine 3D Workflows"; "3D
Reconstruction" was avoided because single_exec already uses that heading
for nano3d. "Post-processing" parallels "Pre-processing" (preproc, 20).
Add src/main/ui/simple/simple_ui_reconstruct3D.f90 owning its descriptor,
the reconstruct3D and bootstrap_rec3D ui_program objects, their
existing new_* constructors moved mechanically from
simple_ui_refine3D.f90, and construct_reconstruct3D_programs. Add
src/main/ui/simple/simple_ui_postprocess.f90 owning its descriptor, the
postprocess and postprocess_nu objects, their constructors moved
mechanically from simple_ui_refine3D.f90 and simple_ui_filter.f90, and
construct_postprocess_programs. Each module needs only
use simple_ui_modules.
Import and call both constructors from
src/main/ui/simple_ui_simple_group.f90 immediately after
construct_heterogeneity_programs, in the order reconstruct3D then
postprocess, matching the visible order. The recursive CMake glob picks up
the new files; no source list is edited.
UI ownership for the relocations¶
For each remaining row of the table, cut the
type(ui_program), target :: <name> declaration, the new_<name>
constructor, and the call new_<name>(prgtab) line from the source module
and paste them into the target module. Each constructor's final
add_ui_program(...) call already passes the module-local UI_CATEGORY, so
the category follows the module automatically. Program names, display names,
summaries, help, input bindings, defaults, requirements, ordering, and
visibility must not be edited in the relocation pass, with the single
exception below.
All source and target modules depend only on simple_ui_modules; no
module-private helper is referenced by any of the moved constructors, so no
use statement changes.
Place each pasted constructor call at the end of the target module's
construct_*_programs list. Registry order is not display order (programs
are listed alphabetically within a category), so this is a legibility choice
only.
Apart from the two new lines, simple_ui_simple_group.f90 needs no change:
every other target module is already imported and constructed there.
The one wording change¶
Replace the automask summary
Create a spherical mask from the estimated particle diameter
with
Create an automatic envelope mask for a 3D volume
in the same commit as its relocation, because the old summary is false and
would become more visible next to auto_spher_mask in the Masking listing.
display_name falls back to summary, so this also corrects the GUI title.
No other descriptor text changes.
Execution ownership¶
Nothing moves. simple_exec_refine3D, simple_exec_filter,
simple_exec_denoise, simple_exec_project, and simple_exec_other keep
their case branches and commander instances. After the change simple_exec_refine3D routes
programs presented under four headings (Refine 3D, Reconstruct 3D,
Post-processing, Masking); that asymmetry is expected under the
UI-versus-execution split and is not a reason to touch the routers. The
internal reconstruct3D invocations from abinitio3D, refine3D, and
refine3D_states go through cline%set('prg', ...) and are unaffected by
presentation.
export_manifoldem_starproject removal¶
Delete, in one commit separate from the moves:
- the
export_manifoldem_starprojectobject,new_export_manifoldem_starproject, and its call inconstruct_project_programs(simple_ui_project.f90); - the
case( 'export_manifoldem_starproject' )branch and thexexport_manifoldem_starprojectinstance (simple_exec_project.f90). The router currently importssimple_commanders_starprojecttwice, once with the ManifoldEM commander and once without; delete the two-line import that names it and keep the one-line import, which then covers everything the router still uses; commander_export_manifoldem_starprojectandexec_export_manifoldem_starproject(simple_commanders_starproject.f90);- the
export_manifoldem_ptcls3Dtype-bound procedure and its binding in thestarprojecttype (simple_starproject.f90). The helpers it calls (initialise,propagate_optics,propagate_optics_box,get_stkname_and_ind) have other callers and stay.
Regenerate the Fortran indexes under doc/code_overview/fortran-indexes/
with scripts/gen_fortran_indexes.pl rather than editing them by hand.
simple_exec prg=export_manifoldem_starproject will then fail with the
standard unknown-program error; there is no deprecation alias because the
program has no documented workflow or test coverage. export_starproject
and export_relion remain the supported STAR exports.
Heterogeneity Analysis membership¶
The completed heterogeneity note fixed the category at exactly three
programs. This note supersedes that count: after the move the category holds
classify3D_refs, flex_pca, ptcl3D_state_consensus, refine3D_states.
Update the count_prgs_in_category('heterogeneity') assertion from 3 to 4
and add one line to doc/algorithms/heterogeneity_analysis/README.md noting
that ptcl3D_state_consensus combines state assignments across runs (no
algorithm chapter is needed for a metadata utility).
Compatibility¶
Command names and accepted arguments of the surviving programs are
unchanged. The complete UI JSON changes category,
category_display_name, and category_order for the ten moved programs,
summary and display_name for automask, and drops the
export_manifoldem_starproject descriptor. The external-client audit from
the heterogeneity note still holds: the bundled nice/ client does not key
on category identifiers.
Implementation Sequence¶
- Add
simple_ui_reconstruct3D.f90, relocatereconstruct3Dandbootstrap_rec3Dinto it, and register the constructor insimple_ui_simple_group.f90. - Add
simple_ui_postprocess.f90, relocatepostprocessandpostprocess_nuinto it, and register the constructor. - Relocate the other six constructors and objects; fix the
automasksummary. - Extend
simple_test_ui_visibility(see Validation Criteria). - Regenerate the complete UI JSON and diff it against the previous build; the diff must be limited to the fields named under Compatibility, minus the dropped descriptor.
- Inspect
simple_exec prg=listfor the two new headings and the ten programs under their new headings. - In a separate commit, remove
export_manifoldem_starprojectas listed above. Regenerate and diff the UI JSON again; the diff must be exactly the dropped descriptor. - Update the heterogeneity README line and regenerate the Fortran indexes.
- Record completed validation here, then move this note to
doc/refactoring_notes/completed/.
Validation Criteria¶
Registry assertions in production/tests/simple_test_ui_visibility.f90,
using the existing helpers:
assert_registered_categoryfor each moved program with its new identifier, heading, and order:reconstruct3Dandbootstrap_rec3D→reconstruct3d/ Reconstruct 3D Workflows / 68;postprocessandpostprocess_nu→postprocess/ Post-processing / 69;automask→mask/ Masking / 100;ptcl3D_state_consensus→heterogeneity/ Heterogeneity Analysis / 65;fractionate_movies→preproc/ Pre-processing / 20;splitandsplit_stack→image/ General Image Processing / 90;cls_split→cluster2d/ Cluster2D Workflows / 30;count_prgs_in_category('reconstruct3d')equals 2,count_prgs_in_category('postprocess')equals 2, andcount_prgs_in_category('heterogeneity')equals 4;assert_program_not_registered('export_manifoldem_starproject');- the anchors
refine3D(60),icm2D(70),filter(80),new_project(10),reimport_particles(10),stack(90),motion_correct(20),abinitio2D(30), andexport_starproject(10) keep their categories, so a mistaken move or deletion in the other direction is caught.
Inspection criteria, checked in steps 5 to 7 and recorded here:
- the JSON diffs are limited to the fields named under Compatibility;
- the two new headings appear between Heterogeneity Analysis and Denoising
in that order, the ten programs appear under their new headings in
prg=list, and no heading has gone empty (Other Utilitiesretainscif2pdbandsigma2_convert;Refine 3D Workflowsretainsrefine3Dandrefine3D_auto;Filteringretainsfilter,nu_filt3D,uniform_filter2D,uniform_filter3D;Denoisingretainsicm2D,icm3D,ppca_denoise,ppca_denoise_classes,denoise_project,map_params_from_den); - command dispatch for the ten moved names resolves through the existing routers;
simple_exec prg=export_manifoldem_starprojectreports an unknown program.
Category-order uniqueness and per-category metadata consistency are enforced
at registration by validate_category_metadata; no test is needed.
Compilation and runtime execution remain user-owned under repository policy.
Explicit Non-Goals¶
- Adding
sigma2_convertorcenterto Reconstruct 3D Workflows, ornu_filt3Dorautomaskto Post-processing; each new category holds exactly its two named programs. - Moving
extract_subprojbetween executables, or movingmini_stream. - Removing or merging
noisevol/simulate_noiseorautomask/auto_spher_mask. - Touching execution routers, commanders, or the
split_object name. - Removing
export_starproject,export_relion, or any STAR helper that has a surviving caller. - Any descriptor wording other than the
automasksummary. The wording pass (copy-pastedgen_pspecs_and_thumbssummary; identical summaries oncluster_stack/match_cavgs/match_stacks;volanalyze"emsemble";simulate_noise"images or volumes"; lowercase summaries onextract_subproj,prune_project,replace_project_field,bootstrap_rec3D,auto_spher_mask,check_refpick,mini_stream) is a separate note underdoc/policies/ui_layer_policy.md's category-review rule. - Renumbering existing categories.
Implementation and Validation Record¶
Implemented on master on 2026-09-13, in the working tree alongside the
heterogeneity-analysis refactor (not yet committed; the sequence above still
applies when committing).
Source changes:
- Added
src/main/ui/simple/simple_ui_reconstruct3D.f90(reconstruct3d/ Reconstruct 3D Workflows / 68) holdingreconstruct3Dandbootstrap_rec3D, andsrc/main/ui/simple/simple_ui_postprocess.f90(postprocess/ Post-processing / 69) holdingpostprocessandpostprocess_nu; both constructors registered insimple_ui_simple_group.f90directly afterconstruct_heterogeneity_programs. - Relocated
automask→simple_ui_mask,ptcl3D_state_consensus→simple_ui_heterogeneity,cls_split→simple_ui_cluster2D,fractionate_movies→simple_ui_preproc,split_andsplit_stack→simple_ui_image. (reimport_particleswas moved tosimple_ui_denoisein a first pass and moved back tosimple_ui_projecton review; its category is unchanged, but its declaration, constructor call, and constructor now sit last in that module rather than at their original positions.) Each pasted constructor call sits at the end of its targetconstruct_*_programslist. automasksummary changed to "Create an automatic envelope mask for a 3D volume".- Removed
export_manifoldem_starprojectfromsimple_ui_project.f90,simple_exec_project.f90(the duplicatedsimple_commanders_starprojectimport collapsed to the one-line form),simple_commanders_starproject.f90, and theexport_manifoldem_ptcls3Dbinding and body insimple_starproject.f90. No other symbol lost its last caller. simple_test_ui_visibility.f90: category assertions for the ten moved programs, counts forreconstruct3d(2),postprocess(2), andheterogeneity(4), negative assertion forexport_manifoldem_starproject, and anchorsfilter,new_project,export_starproject,stack,motion_correctalongside the existingrefine3Dandicm2D.doc/algorithms/heterogeneity_analysis/README.md: one bullet forptcl3D_state_consensus.doc/code_overview/code_base_map.md: the two new modules. Fortran indexes regenerated withperl scripts/gen_fortran_indexes.pl --root src --out doc/code_overview/fortran-indexes.
Static validation performed (no compilation or executable run, per repository policy):
- Nine of the ten relocated constructor blocks are byte-identical to their
pre-move definitions.
automaskdiffers in exactly two lines: the summary replacement described above, and itssubroutine new_automask( prgtab )header, which was unindented insimple_ui_refine3D.f90and now carries the standard four-space indent. One trailing-whitespace comment line inside the movedsplit_block was stripped so thatgit diff --checkpasses. - No moved constructor references a module-level object of its source
module; every touched UI module still depends only on
simple_ui_modules; no duplicate object or constructor names in any UI module; subroutine/end-subroutine and module/end-module pairs balance in every edited unit. - Every moved program still has its
casebranch in its original router (simple_exec_refine3D,simple_exec_filter,simple_exec_denoise,simple_exec_project,simple_exec_other). - Repository-wide scan finds no remaining reference to
export_manifoldem_starproject,commander_export_manifoldem_starproject, orexport_manifoldem_ptcls3Doutside historical notes. git diff --checkpasses.
Outstanding for the maintainer: rebuild; run simple_test_ui_visibility;
inspect simple_exec prg=list for the two new headings between Heterogeneity
Analysis and Denoising; regenerate the complete UI JSON and diff it against
the previous build (expected: category fields for ten programs, summary and
display_name for automask, one dropped descriptor); confirm
prg=export_manifoldem_starproject reports an unknown program. Record the
outcome here.