diff --git a/docs/.gitignore b/docs/.gitignore index e35d885..89627db 100644 --- a/docs/.gitignore +++ b/docs/.gitignore @@ -1 +1,2 @@ _build +API_MAP.md diff --git a/docs/API_MAP.md b/docs/API_MAP.md deleted file mode 100644 index cdcc0dc..0000000 --- a/docs/API_MAP.md +++ /dev/null @@ -1,1327 +0,0 @@ -# API Map - -_Generated by `utils/generate_api_map.py`. Do not edit manually._ -_Re-run `py utils/generate_api_map.py` whenever public APIs change._ - -## docs/conf.py - -- **class Mock** (line 22) -- `def autodoc_skip_member(app, what, name, obj, skip, options)` (line 227): Custom function to skip certain members during autodoc processing. -- `def setup(app)` (line 239): Custom setup function for Sphinx. - -## experiments/Colormap-VTK_To_USD/colormap_vtk_to_usd.py - -- `def create_example_mesh_with_data(time_step)` (line 49): Create a sphere mesh with synthetic data for demonstration. - -## experiments/Convert_VTK_To_USD/convert_vtk_to_usd_using_class.py - -- `def create_deformed_pv_mesh(base, time_step, num_steps=10)` (line 236): Return a sinusoidally scaled copy of base with a synthetic pressure field. -- `def verify_usd_file(usd_path)` (line 314): Verify USD file integrity. - -## experiments/DisplacementField_To_USD/displacement_field_to_usd.py - -- `def generate_sample_displacement_fields(output_dir, n_timesteps=10, size=(32, 32, 32))` (line 81): Generate synthetic time-varying displacement fields for demonstration. - -## experiments/Heart-Create_Statistical_Model/5-compute_pca_model.py - -- `def generate_pc_variation(pc_index, std_dev_multiplier=3.0)` (line 155): Generate shape variations along a principal component. - -## experiments/LongitudinalRegistration/0-cardiacGatedCT_segment_and_landmark.py - -- `def segment_images(src_data_dirs, src_data_files)` (line 64): Segment each image with SegmentHeartSimpleware and save labelmaps. - -## experiments/LongitudinalRegistration/3-run_registration_method_comparison.py - -- **class MethodSpec** (line 49): Registration method plus optional ICON checkpoint. -- **class ImageArtifacts** (line 58): Input files associated with one image volume. -- `def nii_stem(path)` (line 67): Return a stable stem for ``.nii.gz`` or single-suffix files. -- `def timepoint_from_name(path)` (line 74): Extract the gated time-point tag from a filename. -- `def first_existing(paths)` (line 82): Return the first existing path from a candidate list. -- `def landmark_candidates(image_file, segmentation_dir, artifact_dir)` (line 90): Return likely landmark CSV paths for an image. -- `def labelmap_candidates(image_file, segmentation_dir, artifact_dir)` (line 114): Return likely labelmap paths for an image. -- `def image_artifacts(image_file, segmentation_dir, artifact_dir=None)` (line 132): Find landmarks and labelmaps associated with one image. -- `def read_landmarks(path)` (line 150): Read physical LPS landmarks from ``Name,X,Y,Z`` CSV. -- `def write_landmarks(path, landmarks)` (line 163): Write physical LPS landmarks to ``Name,X,Y,Z`` CSV. -- `def transform_landmarks(landmarks, transform)` (line 173): Apply an ITK physical-space transform to landmark coordinates. -- `def landmark_errors(source, target)` (line 186): Return per-landmark Euclidean errors in millimeters. -- `def summarize_errors(errors, prefix)` (line 196): Summarize landmark errors for one comparison mode. -- `def write_error_details(path, subject_id, method_name, timepoint, mode, errors)` (line 214): Append per-landmark errors to the detail CSV. -- `def dice_by_label(labelmap_a, labelmap_b)` (line 243): Compute Dice scores for labels present in either 3D labelmap. -- `def summarize_dice(scores)` (line 265): Summarize per-label Dice scores. -- `def discover_subjects(reference_dir, timepoint_base_dir, reference_pattern, timepoint_pattern, exclude_tokens, segmentation_dir, segmentation_base_dir)` (line 277): Discover reference and time-point files for each subject. -- `def build_method_specs(method_names, finetuned_weights_path)` (line 329): Map output method labels to registrar methods and optional weights. -- `def configure_registrar(method_spec, fixed_image, fixed_labelmap, ants_iterations, greedy_iterations, icon_iterations)` (line 361): Create and configure the time-series registrar. -- `def write_summary(path, rows)` (line 384): Write experiment summary rows. -- `def run_method_for_subject(subject_id, reference_artifacts, timepoint_artifacts, method_spec, output_dir, run_resegmentation, ants_iterations, greedy_iterations, icon_iterations, error_detail_file)` (line 396): Run one registration method for one subject and return summary rows. -- `def parse_iterations(value)` (line 561): Parse comma-separated multi-resolution iteration counts. -- `def main()` (line 566): Run the longitudinal registration comparison experiment. - -## experiments/LongitudinalRegistration/experiment_recon_4d.py - -- `def register_time_series(reference_image_file, source_image_dir, source_image_files, registration_method)` (line 75) - -## experiments/LongitudinalRegistration/uniGradICON/scripts/prepare_l2r_datasets.py - -- `def generate_oasis_json(data_dir, output_dir)` (line 31): Generate JSON for OASIS brain MRI (unpaired, with segmentations). -- `def generate_lungct_json(data_dir, output_dir)` (line 57): Generate JSON for LungCT (paired). -- `def generate_abdomenmrct_json(data_dir, output_dir)` (line 89): Generate JSON for AbdomenMRCT cross-modality dataset (unpaired, with segmentations). -- `def main()` (line 122) - -## experiments/LongitudinalRegistration/uniGradICON/src/unigradicon/__init__.py - -- **class GradientICONSparse** (line 23) - - `def __init__(self, network, similarity, lmbda, use_label=False, apply_intensity_conservation_loss=False, dice_loss_weight=0.0, loss_function_masking=False)` (line 24) - - `def forward(self, image_A, image_B, label_A=None, label_B=None, mask_A=None, mask_B=None, segmentation_A=None, segmentation_B=None)` (line 35) - - `def compute_jacobian_determinant(self, phi)` (line 254) - - `def dice_loss(self, pred, target, epsilon=1e-06)` (line 277): Compute Dice loss between one-hot encoded prediction and target. - - `def clean(self)` (line 298) -- `def make_network(input_shape, include_last_step=False, lmbda=1.5, loss_fn=icon.LNCC(sigma=5), use_label=False, apply_intensity_conservation_loss=False, dice_loss_weight=0.0, loss_function_masking=False)` (line 324) -- `def make_sim(similarity, sigma=5, mind_radius=2, mind_dilation=2)` (line 340) -- `def get_multigradicon(loss_fn=icon.LNCC(sigma=5), apply_intensity_conservation_loss=False, weights_location=None, dice_loss_weight=0.0, loss_function_masking=False)` (line 350) -- `def get_unigradicon(loss_fn=icon.LNCC(sigma=5), apply_intensity_conservation_loss=False, weights_location=None, dice_loss_weight=0.0, loss_function_masking=False)` (line 369) -- `def get_model_from_model_zoo(model_name='unigradicon', loss_fn=icon.LNCC(sigma=5), apply_intensity_conservation_loss=False, dice_loss_weight=0.0, loss_function_masking=False, weights_location=None)` (line 387) -- `def quantile(arr, q)` (line 407) -- `def apply_mask(image, mask)` (line 412) -- `def preprocess(image, modality='ct', mask=None, ct_window=None, quantile_range=None)` (line 427): Preprocess a medical image for registration. -- `def main()` (line 470) -- `def warp_command()` (line 669) -- `def maybe_cast(img)` (line 711): If an itk image is of a type that can't be used with InterpolateImageFunctions, cast it -- `def compute_jacobian_map_command()` (line 729) - -## experiments/LongitudinalRegistration/uniGradICON/src/unigradicon/finetuning/config.py - -- `def set_reproducibility_seed(seed)` (line 26): Seed Python, NumPy, and PyTorch (CPU and GPU) at startup. -- **class ConfigSections** (line 36) -- **class ExperimentKeys** (line 42) -- **class TrainingKeys** (line 47) -- **class DatasetKeys** (line 69) -- **class DatasetTypes** (line 84) -- **class JsonKeys** (line 89) -- **class ExperimentConfig** (line 134) - - `def from_dict(cls, raw)` (line 139) -- **class TrainingConfig** (line 147) - - `def from_dict(cls, raw)` (line 169) - - `def network_input_shape(self)` (line 178): ``input_shape`` with the [1, 1] batch+channel prefix that -- **class DatasetConfig** (line 185): ``name``/``type``/``json_file`` are YAML-required and validated in - - `def from_dict(cls, raw)` (line 205) -- **class FinetuningConfigSchema** (line 215) - - `def from_dict(cls, raw)` (line 221) -- **class DataLoaderBundle** (line 237) -- **class ConfigValidator** (line 244) - - `def __init__(self, config)` (line 245) - - `def validate(self)` (line 248) -- `def validate_config(config)` (line 345) -- `def load_config(config_path)` (line 349) -- **class DatasetJsonCache** (line 358): Memoizes JSON parsing + path resolution across the multiple validators - - `def __init__(self)` (line 362) - - `def load_content(self, json_path)` (line 366) - - `def load_entries(self, json_path)` (line 378) - - `def entry_field_sets(self, json_path)` (line 418) -- `def required_data_fields(training)` (line 428) -- `def determine_data_fields(dataset_configs, config_dir, json_cache=None)` (line 437) -- `def validate_paired_datasets_have_pairs(schema, config_dir, json_cache)` (line 452): Catches missing-pairs at config-validation time so we don't spend -- `def validate_training_data_compatibility(fields_per_dataset, data_fields)` (line 484) -- `def create_dataset_from_config(dataset_config, input_shape, config_dir='', use_label=False, data_fields=frozenset(), json_cache=None)` (line 519): Build a ``Dataset`` (random pairing) or ``PairedDataset`` (subject-based -- `def create_data_loaders(config_path, config=None)` (line 663): Create training and validation dataloaders from YAML config. - -## experiments/LongitudinalRegistration/uniGradICON/src/unigradicon/finetuning/dataset.py - -- **class Fields** (line 22) -- **class CacheNames** (line 30) -- **class PairKeys** (line 42) -- **class DatasetParams** (line 54): Shared defaults for ``Dataset.__init__`` (via ``_DEFAULTS``) and -- **class DatasetEntry** (line 92) - - `def from_dict(cls, item, idx, dataset_name)` (line 100) -- **class ImageReader** (line 129) - - `def read(self, path)` (line 130) -- **class ImagePreprocessor** (line 138) - - `def __init__(self, reader, input_shape, is_ct, ct_window, quantile_range, modality_map)` (line 139) - - `def preprocess_image(self, path)` (line 155) - - `def preprocess_label_map(self, path)` (line 178) -- **class DatasetCache** (line 185): Cache path is partitioned by a signature hashed from every - - `def __init__(self, dataset_name, cache_dir, enabled, signature)` (line 191) - - `def path(self, cache_name)` (line 214) - - `def load(self, cache_name)` (line 219) - - `def save(self, cache_name, payload)` (line 233) - - `def write_metadata(self, meta)` (line 244): Sidecar ``_meta.json`` describing the params behind the -- **class RandomPairSampler** (line 260) - - `def __init__(self, keys)` (line 261) - - `def sample_partner(self, anchor)` (line 267) -- **class SubjectPairSampler** (line 277): Pair only images sharing the same ``subject_id``. - - `def __init__(self, entries, keys, dataset_name)` (line 280) - - `def sample_partner(self, anchor)` (line 302) -- **class Dataset** (line 306): 3D medical-image registration dataset. - - `def __init__(self, input_shape, name, data, cache_dir=_DEFAULTS.cache_dir, maximum_images=_DEFAULTS.maximum_images, shuffle=_DEFAULTS.shuffle, is_ct=_DEFAULTS.is_ct, ct_window=_DEFAULTS.ct_window, quantile_range=_DEFAULTS.quantile_range, use_cache=_DEFAULTS.use_cache, use_compression=_DEFAULTS.use_compression, use_label=False)` (line 320) - - `def has_segmentation(self)` (line 539) - - `def has_mask(self)` (line 543) - - `def get_image(self, key)` (line 556) -- **class PairedDataset** (line 603): Variant of ``Dataset`` that pairs only within ``subject_id``. JSON - - `def __init__(self, **kwargs)` (line 608) - -## experiments/LongitudinalRegistration/uniGradICON/src/unigradicon/finetuning/finetune.py - -- `def loss_to_dict(loss_object)` (line 33) -- `def augment(batch)` (line 50): Apply random affine augmentation to all spatial data in a batch dict. -- `def finetune_multi(config, data_loader, val_data_loaders_dict, data_fields)` (line 304): Unified finetuning loop. -- `def main(argv=None)` (line 432) - -## experiments/LongitudinalRegistration/uniGradICON/src/unigradicon/finetuning/visualization.py - -- `def render_for_tensorboard(im, max_samples=MAX_DISPLAY_SAMPLES, normalize=True)` (line 42): Prepare image tensor for TensorBoard as an RGB image batch. -- `def segmentation_labels_for_tensorboard(im, max_samples=MAX_DISPLAY_SAMPLES)` (line 59): Convert one-hot or label-map segmentations to integer label images. -- `def labels_to_color_image(labels)` (line 108) -- `def render_segmentation_overlay_for_tensorboard(image, segmentation, alpha=DEFAULT_OVERLAY_ALPHA)` (line 116): Blend a rendered segmentation over its image for TensorBoard. -- `def render_mask_overlay_for_tensorboard(image, mask, alpha=DEFAULT_OVERLAY_ALPHA, color=DEFAULT_MASK_OVERLAY_COLOR)` (line 134): Blend a binary ROI mask over its image as a single solid color. -- `def add_eval_composite_panel(writer, step, moving, fixed, warped, moving_seg=None, fixed_seg=None, warped_seg=None, moving_mask=None, fixed_mask=None, tag='eval')` (line 162): Write a single composite eval panel under ``{tag}`` (default ``"eval"``). - -## experiments/LongitudinalRegistration/uniGradICON/src/unigradicon/unicarl.py - -- `def get_unicarl()` (line 24) -- `def main()` (line 41) - -## experiments/LongitudinalRegistration/uniGradICON/tests/finetuning/conftest.py - -- `def fake_image_reader(monkeypatch)` (line 9): Replace ITK-backed ``ImageReader`` with a deterministic fake so tests - -## experiments/LongitudinalRegistration/uniGradICON/tests/finetuning/test_cache.py - -- `def test_cache_disabled_returns_none_paths(tmp_path)` (line 25) -- `def test_cache_save_and_load_roundtrip(tmp_path)` (line 31) -- `def test_cache_atomic_write_no_partial_file_visible(tmp_path)` (line 41): The save path uses tmp + os.replace; tmp file should not linger. -- `def test_cache_load_returns_none_on_corrupt_file(tmp_path, caplog)` (line 51): A truncated/garbage cache file should not propagate; it should warn -- `def test_cache_write_metadata_skips_when_already_present(tmp_path)` (line 67) -- `def test_dataset_cache_signature_changes_with_quantile_range(tmp_path, fake_image_reader)` (line 84) -- `def test_dataset_cache_signature_stable_for_identical_params(tmp_path, fake_image_reader)` (line 97) -- `def test_dataset_cache_signature_changes_with_input_shape(tmp_path, fake_image_reader)` (line 108) -- `def test_dataset_skip_save_on_clean_cache_hit(tmp_path, fake_image_reader)` (line 119): Second construction with identical params must not rewrite cache files. -- `def test_dataset_rebuilds_when_cache_corrupt(tmp_path, fake_image_reader, caplog)` (line 144): A garbage cache file triggers warning + rebuild, not an exception. -- `def test_dataset_metadata_sidecar_describes_signature(tmp_path, fake_image_reader)` (line 163) -- `def test_dataset_segmentation_cache_written_under_signature_dir(tmp_path, fake_image_reader)` (line 180): Aux maps are persisted as their own ``.trch`` cache file beside images. -- `def test_dataset_segmentation_cache_round_trips(tmp_path, fake_image_reader, monkeypatch)` (line 191): A second construction with identical params loads aux maps from cache -- `def test_dataset_compresses_in_memory_when_enabled(tmp_path, fake_image_reader)` (line 212): With ``use_compression=True`` the in-memory store holds blosc bytes, -- `def test_dataset_skips_compression_by_default(tmp_path, fake_image_reader)` (line 223): The default ``use_compression=False`` keeps tensors uncompressed. -- `def test_dataset_compression_roundtrip_returns_equal_tensor(tmp_path, fake_image_reader)` (line 232): ``get_image`` must return tensors that are equal regardless of whether -- `def test_dataset_compression_signature_partitions_cache(tmp_path, fake_image_reader)` (line 247): Toggling ``use_compression`` produces a different cache signature so -- `def test_dataset_rebuilds_aux_cache_when_keys_outgrow_cache(tmp_path, fake_image_reader)` (line 261): If a previous run wrote an aux cache for a smaller key set (e.g. some -- `def test_dataset_indexing_anchor_is_deterministic(tmp_path, fake_image_reader)` (line 284): ds[i] anchor must be self.keys[i] regardless of RNG state. - -## experiments/LongitudinalRegistration/uniGradICON/tests/finetuning/test_cli.py - -- `def isolate_cwd(tmp_path, monkeypatch)` (line 20): Run inside a temp dir so footsteps' results/ dir doesn't pollute the -- `def mock_finetune_multi(monkeypatch)` (line 33): Capture the (config, data_loader, val_loaders, data_fields) call so the -- `def test_cli_requires_config_arg()` (line 92): ``unigradicon-finetune`` (no args) must fail with a non-zero exit. -- `def test_cli_rejects_unknown_argument()` (line 99) -- `def test_cli_rejects_missing_config_file(tmp_path, isolate_cwd)` (line 104) -- `def test_cli_starts_finetuning_with_valid_config(tmp_path, isolate_cwd, fake_image_reader, mock_finetune_multi)` (line 110): Happy path: a valid YAML drives main() through to ``finetune_multi`` -- `def test_cli_propagates_invalid_config_errors(tmp_path, isolate_cwd, fake_image_reader, mock_finetune_multi)` (line 126): Schema-validation failures must surface as ValueError before training -- `def test_cli_propagates_paired_without_subject_id_error(tmp_path, isolate_cwd, fake_image_reader, mock_finetune_multi)` (line 138): The fast-fail validator catches paired-without-subject_id before any -- `def test_cli_seed_is_applied_before_data_loader_build(tmp_path, isolate_cwd, fake_image_reader, mock_finetune_multi)` (line 156): When 'seed' is in the YAML, set_reproducibility_seed must run before - -## experiments/LongitudinalRegistration/uniGradICON/tests/finetuning/test_config.py - -- `def test_training_config_lambda_alias()` (line 8): The YAML key 'lambda' must map to the dataclass field 'lmbda'. -- `def test_training_config_unknown_keys_silently_dropped_in_from_dict()` (line 14): from_dict drops unknown keys; ConfigValidator handles the warning. -- `def test_training_config_defaults_when_empty_dict()` (line 21) -- `def test_training_config_network_input_shape_property()` (line 28) -- `def test_dataset_config_post_init_rejects_empty_required_fields()` (line 33) -- `def test_dataset_config_from_dict_coerces_lists_to_tuples()` (line 42) -- `def test_validate_rejects_missing_experiment()` (line 64) -- `def test_validate_rejects_missing_datasets()` (line 69) -- `def test_validate_rejects_empty_datasets_list()` (line 74) -- `def test_validate_rejects_invalid_similarity()` (line 82) -- `def test_validate_accepts_valid_similarities_case_insensitive(sim)` (line 88) -- `def test_validate_rejects_negative_learning_rate()` (line 92) -- `def test_validate_rejects_non_positive_int_keys(key)` (line 101) -- `def test_validate_rejects_negative_non_negative_keys(key)` (line 109) -- `def test_validate_rejects_bad_input_shape(shape)` (line 122) -- `def test_validate_rejects_bad_gpus(gpus)` (line 134) -- `def test_validate_accepts_valid_gpus()` (line 139) -- `def test_validate_rejects_bad_samples_per_epoch(spe)` (line 144) -- `def test_validate_accepts_null_or_positive_samples_per_epoch()` (line 149) -- `def test_paired_check_message_when_no_subject_id_field(tmp_path)` (line 154): When no entry has a subject_id at all, the error message names the -- `def test_load_entries_tolerates_null_optional_field(tmp_path)` (line 166): ``{"segmentation": null}`` should be treated as absent, not crash. -- `def test_validate_rejects_zero_dataset_weight()` (line 180) -- `def test_validate_rejects_unknown_dataset_type()` (line 187) -- `def test_validate_warns_on_unknown_training_key(caplog)` (line 194) -- `def test_paired_check_raises_when_no_subject_id_anywhere(tmp_path)` (line 217) -- `def test_paired_check_raises_when_each_subject_has_only_one_image(tmp_path)` (line 227) -- `def test_paired_check_passes_when_at_least_one_subject_has_two_images(tmp_path)` (line 238) -- `def test_paired_check_skips_unpaired_datasets(tmp_path)` (line 249): An 'unpaired' dataset with no subject_id should not trigger the check. -- `def test_required_fields_empty_for_image_only_training()` (line 262) -- `def test_required_fields_includes_segmentation_when_dice_loss_set()` (line 267) -- `def test_required_fields_includes_mask_when_loss_function_masking()` (line 272) -- `def test_required_fields_includes_mask_when_roi_masking()` (line 277) - -## experiments/LongitudinalRegistration/uniGradICON/tests/finetuning/test_pipeline.py - -- `def test_pipeline_rejects_zero_iterations_per_epoch(tmp_path, fake_image_reader)` (line 62): ``samples_per_epoch < batch_size * num_gpus`` would yield zero -- `def test_pipeline_starts_minimal_config(tmp_path, fake_image_reader)` (line 73): Smallest possible valid config: images only, single dataset, 1 epoch. -- `def test_pipeline_train_batch_shape(tmp_path, fake_image_reader)` (line 85): The train loader must yield batches with image_A / image_B at the -- `def test_pipeline_val_batch_shape(tmp_path, fake_image_reader)` (line 103): The validation loader uses batch_size=1 by default. -- `def test_pipeline_with_segmentation_includes_seg_in_batch(tmp_path, fake_image_reader)` (line 116): When dice_loss_weight > 0, batches include segmentation tensors. -- `def test_pipeline_iterates_full_epoch(tmp_path, fake_image_reader)` (line 130): The train loader iterates exactly samples_per_epoch / effective_batch -- `def test_pipeline_seed_yields_reproducible_first_batch(tmp_path, fake_image_reader)` (line 142): With seed set and num_workers=0, two independent runs must produce - -## experiments/LongitudinalRegistration/uniGradICON/tests/finetuning/test_samplers.py - -- `def test_random_pair_sampler_rejects_short_keys()` (line 8) -- `def test_random_pair_sampler_partner_is_never_anchor()` (line 13) -- `def test_random_pair_sampler_full_coverage()` (line 24): Every non-anchor key must be reachable as a partner for every anchor. -- `def test_random_pair_sampler_uniformity()` (line 39): Each non-anchor key should be picked with equal probability. -- `def test_subject_pair_sampler_rejects_when_no_subject_has_pair()` (line 60) -- `def test_subject_pair_sampler_partner_respects_subject()` (line 66) -- `def test_subject_pair_sampler_filters_keys_without_pairs()` (line 86): Keys missing from the entry list (or without subject_id) are dropped. - -## experiments/LongitudinalRegistration/uniGradICON/tests/test_command_arguments.py - -- **class TestCommandInterface** (line 11) - - `def __init__(self, methodName='runTest')` (line 12) - - `def test_register_unigradicon_inference(self)` (line 20) - - `def test_register_multigradicon_inference(self)` (line 64) - -## experiments/LongitudinalRegistration/uniGradICON/tests/test_itk_interface.py - -- **class TestItkInterface** (line 15) - - `def __init__(self, methodName='runTest')` (line 16) - - `def test_register_pair(self)` (line 22) - - `def test_preprocessing_mri(self)` (line 66) - - `def test_preprocessing_ct(self)` (line 85) - - `def test_itk_registration(self)` (line 104) - - `def test_register_pair_with_mask_masking(self)` (line 171): Test register_pair_with_mask with loss_function_masking (mask_A/B only). - - `def test_register_pair_with_mask_dice(self)` (line 190): Test register_pair_with_mask with dice_loss_weight (segmentation_A/B only). - - `def test_register_pair_with_mask_both(self)` (line 209): Test register_pair_with_mask with both mask and segmentation. - - `def test_register_pair_with_mask_images_only(self)` (line 230): ``register_pair_with_mask`` with no mask or segmentation kwargs - - `def test_itk_warp(self)` (line 248) - -## experiments/LongitudinalRegistration/uniGradICON/tests/test_requirements_sync.py - -- **class TestImports** (line 4) - - `def test_requirements_match_cfg(self)` (line 6) - -## experiments/LongitudinalRegistration/uniGradICON/training/dataset.py - -- **class COPDDataset** (line 13) - - `def __init__(self, phase='train', scale='2xdown', data_path=f'{DATASET_DIR}/half_res_preprocessed_transposed_SI', ROI_only=False, data_num=-1, desired_shape=None, device='cpu')` (line 14) - - `def process(self, img, desired_shape=None, device='cpu', seg=None)` (line 46) -- **class OAIDataset** (line 65) - - `def __init__(self, phase='train', scale='2xdownsample', data_path=f'{DATASET_DIR}/OAI', data_num=1000, desired_shape=None, device='cpu')` (line 66) - - `def process(self, img, desired_shape=None, device='cpu')` (line 93) -- **class HCPDataset** (line 114) - - `def __init__(self, phase='train', scale='2xdown', data_path=f'{DATASET_DIR}/HCP', data_num=1000, desired_shape=None, device='cpu')` (line 115) - - `def process(self, img, desired_shape=None, device='cpu')` (line 141) -- **class L2rAbdomenDataset** (line 161) - - `def __init__(self, data_path=f'{DATASET_DIR}/AbdomenCTCT', data_num=1000, desired_shape=None, device='cpu')` (line 162) - - `def process(self, img, desired_shape=None, device='cpu')` (line 180) -- **class L2rThoraxCBCTDataset** (line 198) - - `def __init__(self, data_path=f'{DATASET_DIR}/ThoraxCBCT', data_num=1000, desired_shape=None, device='cpu')` (line 199) - - `def process(self, img, desired_shape=None, device='cpu')` (line 224) -- **class ACDCDataset** (line 239) - - `def __init__(self, data_path=f'{DATASET_DIR}/ACDC', desired_shape=None)` (line 240) - - `def process(self, img, desired_shape=None)` (line 260) - -## experiments/LongitudinalRegistration/uniGradICON/training/dataset_multi.py - -- **class COPDDataset** (line 16) - - `def __init__(self, scale='2xdown', data_path=f'{DATASET_DIR}/half_res_preprocessed_transposed_SI', ROI_only=False, data_num=-1, desired_shape=None, device='cpu', return_labels=False)` (line 17) - - `def pack_and_process_image(self, img, seg=None)` (line 45) - - `def process(self, img, desired_shape=None, device='cpu', seg=None)` (line 50) -- **class BratsRegDataset** (line 72) - - `def __init__(self, data_path=f'{DATASET_DIR}/BraTS-Reg/BraTSReg_Training_Data_v3/', data_num=1000, desired_shape=None, device='cpu', return_labels=False, randomization='random')` (line 73) - - `def pack_and_process_image(self, image)` (line 118) - - `def process(self, img, desired_shape=None, device='cpu')` (line 123) -- **class L2rAbdomenDataset** (line 154) - - `def __init__(self, data_path=f'{DATASET_DIR}/AbdomenCTCT', data_num=1000, desired_shape=None, device='cpu', return_labels=False, randomization='random', augmentation=True)` (line 155) - - `def pack_and_process_image(self, case_path, invert=False)` (line 189) - - `def process(self, img, desired_shape=None, device='cpu')` (line 196) -- **class HCPDataset** (line 225) - - `def __init__(self, scale='2xdown', data_path=f'{DATASET_DIR}/ICON_brain_preprocessed_data', data_num=1000, desired_shape=None, device='cpu', return_labels=False, randomization='random')` (line 226) - - `def pack_and_process_image(self, image)` (line 259) - - `def process(self, img, desired_shape=None, device='cpu')` (line 264) -- **class ABCDFAMDDataset** (line 296) - - `def __init__(self, phase='train', data_path=f'{DATASET_DIR}/dti_scalars', data_num=1000, desired_shape=None, device='cpu', return_labels=False, randomization='random')` (line 297) - - `def pack_and_process_image(self, image)` (line 341) - - `def process(self, img, desired_shape=None, device='cpu')` (line 346) -- **class ABCDDataset** (line 378) - - `def __init__(self, phase='train', data_path=f'{DATASET_DIR}', data_num=1000, desired_shape=None, device='cpu', return_labels=False)` (line 379) - - `def pack_and_process_image(self, image)` (line 438) - - `def process(self, img, desired_shape=None, device='cpu')` (line 443) -- **class OAIMMDataset** (line 465) - - `def __init__(self, data_path=f'{DATASET_DIR}/oai', data_num=1000, desired_shape=None, device='cpu', return_labels=False)` (line 466) - - `def pack_and_process_image(self, image)` (line 491) - - `def process(self, img, desired_shape=None, device='cpu')` (line 496) -- **class L2rMRCTDataset** (line 518) - - `def __init__(self, data_path=f'{DATASET_DIR}/AbdomenMRCT/', data_num=1000, desired_shape=None, device='cpu', phase='train', augmentation=True, return_labels=False)` (line 519) - - `def pack(self, image)` (line 568) - - `def process_label(self, label, desired_shape=None, device='cpu')` (line 571) - - `def process_ct(self, img, desired_shape=None, device='cpu')` (line 577) - - `def process_mr(self, img, desired_shape=None, device='cpu')` (line 584) -- **class UKBiobankDataset** (line 612) - - `def __init__(self, data_path=f'{DATASET_DIR}/uk-biobank/', data_num=1000, desired_shape=None, device='cpu', phase='train', return_labels=False, randomization='random')` (line 613) - - `def pack_and_process_image(self, image)` (line 648) - - `def process(self, img, desired_shape=None, device='cpu')` (line 653) -- **class PancreasDataset** (line 691) - - `def __init__(self, phase='train', data_path=f'{DATASET_DIR}/pancreas/', data_num=1000, desired_shape=(175, 175, 175), device='cpu', return_labels=False)` (line 692) - - `def process(self, img, desired_shape=None, device='cpu')` (line 731) - - `def process_training_data(self, ct_img_arr, cb_img_arr)` (line 739) -- **class L2rThoraxCBCTDataset** (line 759) - - `def __init__(self, data_path=f'{DATASET_DIR}/ThoraxCBCT', data_num=1000, desired_shape=None, device='cpu', return_labels=False)` (line 760) - - `def pack_and_process_image(self, image)` (line 786) - - `def process(self, img, desired_shape=None, device='cpu')` (line 791) - -## experiments/LongitudinalRegistration/uniGradICON/training/train.py - -- `def write_stats(writer, stats, ite, prefix='')` (line 15) -- `def get_dataset()` (line 26) -- `def augment(image_A, image_B)` (line 37) -- `def train_kernel(optimizer, net, moving_image, fixed_image, writer, ite)` (line 85) -- `def train(net, optimizer, data_loader, val_data_loader, epochs=200, eval_period=-1, save_period=-1, step_callback=lambda net: None, unwrapped_net=None, data_augmenter=None)` (line 94): A training function intended for long running experiments, with tensorboard logging -- `def train_two_stage(input_shape, data_loader, val_data_loader, GPUS, epochs, eval_period, save_period, resume_from)` (line 195) - -## experiments/LongitudinalRegistration/uniGradICON/training/train_multi.py - -- `def write_stats(writer, stats, ite, prefix='')` (line 14) -- `def get_multi_training_set()` (line 25) -- `def get_multi_finetuning_set()` (line 49) -- `def augment(image_A, image_B, label_A, label_B)` (line 86) -- `def train_kernel(optimizer, net, moving_image, fixed_image, moving_label, fixed_label, writer, ite)` (line 136) -- `def train(net, optimizer, data_loader, val_data_loader, epochs=200, eval_period=-1, save_period=-1, step_callback=lambda net: None, unwrapped_net=None, data_augmenter=None)` (line 145): A training function intended for long running experiments, with tensorboard logging -- `def train_two_stage(input_shape, data_loader, val_data_loader, GPUS, epochs, eval_period, save_period, resume_from)` (line 245) -- `def finetune(net, data_loader, val_data_loader, GPUS, epochs, eval_period, save_period)` (line 317) - -## experiments/Lung-GatedCT_To_USD/data_dirlab_4d_ct.py - -- **class DataDirLab4DCT** (line 10): This class is used to store the data for the DirLab 4DCT dataset. - - `def __init__(self)` (line 15): Define the variables specific to DirLab data - - `def get_case_names(self)` (line 30): Get the case names - - `def fix_image(self, input_image)` (line 34): Fix DirLab_4DCT intensities to conform to HU - -## experiments/Lung-VesselsAirways/0-GenData.py - -- `def add_tube_to_patch(patch, patch_size, tube_i_range, tube_r_range)` (line 21) -- `def add_noise_to_patch(patch, patch_size, noise_point_mean, noise_point_stddev, noise_edge_intensity_range, noise_edge_spread_range, noise_slope_intensity_range)` (line 80) -- `def gen_training_patch(p_size, p_depth)` (line 154) -- `def get_training_data(patch_size, patch_depth)` (line 219) -- **class TubeDataset** (line 252) - - `def __init__(self, patch_size, patch_depth)` (line 253) -- `def extract_patch(image, x, r, t, patch_size=16, patch_depth=7)` (line 309) -- `def step(image, model, x, r, t)` (line 347) - -## experiments/Reconstruct4DCT/reconstruct_4d_ct.py - -- `def register_slices(reg_tool, reg_tool_name, fixed_image, images, files_indx, reference_image_num, reference_image_reg_use_identity, portion_of_prior_to_use=0.0)` (line 62) - -## results/icon_finetuned/icon_finetuned_model/finetune.py - -- `def loss_to_dict(loss_object)` (line 33) -- `def augment(batch)` (line 50): Apply random affine augmentation to all spatial data in a batch dict. -- `def finetune_multi(config, data_loader, val_data_loaders_dict, data_fields)` (line 304): Unified finetuning loop. -- `def main(argv=None)` (line 432) - -## results/results/icon_finetuned/icon_finetuned_model/finetune.py - -- `def loss_to_dict(loss_object)` (line 33) -- `def augment(batch)` (line 50): Apply random affine augmentation to all spatial data in a batch dict. -- `def finetune_multi(config, data_loader, val_data_loaders_dict, data_fields)` (line 304): Unified finetuning loop. -- `def main(argv=None)` (line 432) - -## results/results/icon_finetuned/icon_finetuned_model-1/finetune.py - -- `def loss_to_dict(loss_object)` (line 33) -- `def augment(batch)` (line 50): Apply random affine augmentation to all spatial data in a batch dict. -- `def finetune_multi(config, data_loader, val_data_loaders_dict, data_fields)` (line 304): Unified finetuning loop. -- `def main(argv=None)` (line 432) - -## src/physiomotion4d/anatomy_taxonomy.py - -- **class AnatomyGroup** (line 26): One named anatomy group together with the organ labels it contains. -- **class AnatomyTaxonomy** (line 38): Mapping of anatomical groups to the organs each group contains. - - `def __init__(self)` (line 58) - - `def add_group(self, name)` (line 61): Ensure a group exists and return it. - - `def add_organ(self, group, label_id, organ_name)` (line 74): Add one organ label to the named group. - - `def group_names(self)` (line 104): Return group names in the order they were first added. - - `def labels_in_group(self, group)` (line 108): Return ``{label_id: organ_name}`` for *group*; empty dict if absent. - - `def all_labels(self)` (line 113): Return the union of every group's organs as a single id→name dict. - - `def group_for_label(self, label_name)` (line 120): Return the group containing *label_name*. - - `def group_for_id(self, label_id)` (line 132): Return the group containing *label_id*; :data:`OTHER_GROUP` if absent. - - `def fill_other_group(self, id_range=range(1, 256), name_template='other_{id}')` (line 139): Populate the ``other`` group with any ids not already claimed. - -## src/physiomotion4d/cli/convert_image_4d_to_3d.py - -- `def main()` (line 20): CLI entry point for 4D-to-3D image conversion. - -## src/physiomotion4d/cli/convert_image_to_usd.py - -- `def main()` (line 14): Command-line interface for the Image-to-USD workflow. - -## src/physiomotion4d/cli/convert_image_to_vtk.py - -- `def main()` (line 30): CLI entry point for image to VTK conversion. - -## src/physiomotion4d/cli/convert_vtk_to_usd.py - -- `def main()` (line 22): Command-line interface for VTK to USD conversion. - -## src/physiomotion4d/cli/create_statistical_model.py - -- `def main()` (line 19): Command-line interface for create statistical model workflow. - -## src/physiomotion4d/cli/download_data.py - -- `def main(argv=None)` (line 16): Download a supported PhysioMotion4D example dataset. - -## src/physiomotion4d/cli/fit_statistical_model_to_patient.py - -- `def main()` (line 17): Command-line interface for heart model to patient registration. - -## src/physiomotion4d/cli/reconstruct_highres_4d_ct.py - -- `def main()` (line 17): Command-line interface for high-resolution 4D CT reconstruction. - -## src/physiomotion4d/cli/visualize_pca_modes.py - -- `def main()` (line 103): Command-line interface for visualizing PCA modes. - -## src/physiomotion4d/contour_tools.py - -- **class ContourTools** (line 20): Tools for creating and manipulating contours. - - `def __init__(self, log_level=logging.INFO)` (line 25): Initialize ContourTools. - - `def extract_contours(self, mask_image)` (line 33): Make contours from a mask image. - - `def transform_contours(self, contours, tfm, with_deformation_magnitude=False)` (line 75): Transform contours using a given transform. - - `def merge_meshes(self, meshes)` (line 96): Merge multiple fixed meshes into a single mesh. - - `def create_reference_image(self, mesh, spatial_resolution=0.5, buffer_factor=0.25, ptype=itk.F)` (line 139): Create a reference image from a mesh. - - `def create_mask_from_mesh(self, mesh, reference_image)` (line 168) - - `def create_distance_map(self, mesh, reference_image, squared_distance=False, negative_inside=True, zero_inside=False, norm_to_max_distance=0.0)` (line 257) - - `def create_deformation_field(self, points, point_displacements, reference_image, blur_sigma=2.5, ptype=itk.D)` (line 324): Create a displacement map from model points and displacements. - -## src/physiomotion4d/convert_image_4d_to_3d.py - -- **class ConvertImage4DTo3D** (line 34): Split a 3D/4D ITK image (X, Y, Z [, T]) into a list of 3D ITK images. - - `def __init__(self, log_level=logging.INFO)` (line 37): Initialize the 4D-to-3D image converter. - - `def load_image_4d(self, filename)` (line 62): Load a 3D or 4D image and populate ``self.img_3d`` with 3D frames. - - `def get_3d_image(self, index)` (line 269): Return the 3D ITK image at the given time index. - - `def get_number_of_3d_images(self)` (line 273): Return the number of 3D images currently held. - - `def save_3d_images(self, directory, basename, suffix='mha')` (line 277): Write each held 3D image to ``{directory}/{basename}_{i:03d}.{suffix}``. - -## src/physiomotion4d/convert_vtk_to_usd.py - -- **class ConvertVTKToUSD** (line 45): Advanced VTK to USD converter with colormap and anatomical labeling support. - - `def __init__(self, data_basename, input_polydata, mask_ids=None, compute_normals=False, convert_to_surface=True, times_per_second=24.0, separate_by='none', solid_color=(0.8, 0.8, 0.8), segmenter=None, log_level=logging.INFO)` (line 75): Initialize converter. - - `def from_files(cls, data_basename, vtk_files, *, extract_surface=True, separate_by='none', times_per_second=24.0, solid_color=(0.8, 0.8, 0.8), time_codes=None, static_merge=False, mask_ids=None, segmenter=None, log_level=logging.INFO)` (line 154): Create a converter by loading VTK files from disk. - - `def supports_mesh_type(self, mesh)` (line 256): Check if mesh type is supported for conversion. - - `def inspect_file(cls, vtk_file, *, extract_surface=True)` (line 285): Summarize a VTK file using the same low-level reader as conversion. - - `def list_available_arrays(self)` (line 357): List all point data arrays available across all time steps. - - `def set_colormap(self, color_by_array=None, colormap='plasma', intensity_range=None)` (line 403): Configure colormap for visualization. - - `def compute_von_mises_stress(self, stress_array_name='stress', output_name='von_mises_stress')` (line 437): Add a scalar von Mises stress array derived from a 9-component - - `def convert(self, output_usd_file, convert_to_surface=None, compute_normals=None)` (line 538): Convert VTK meshes to USD. - -## src/physiomotion4d/data_download_tools.py - -- **class DataDownloadTools** (line 20): Download and verify optional PhysioMotion4D example datasets. - - `def DownloadSlicerHeartCTData(dirname)` (line 30): Download the Slicer-Heart-CT 4-D CT sample into ``dirname``. - - `def VerifySlicerHeartCTData(dirname)` (line 80): Return True when Slicer-Heart-CT has the expected 4-D CT file. - - `def VerifyCHOPValve4DData(dirname)` (line 85): Return True when CHOP-Valve4D files referenced by the repo exist. - - `def VerifyDirLab4DCTData(dirname)` (line 107): Return True when a supported DirLab-4DCT case layout exists. - - `def VerifyKCLHeartModelData(dirname)` (line 122): Return True when KCL-Heart-Model has its expected mesh inputs. - -## src/physiomotion4d/image_tools.py - -- **class ImageTools** (line 19): Utilities for medical image format conversions and processing. - - `def __init__(self, log_level=logging.INFO)` (line 35): Initialize ImageTools. - - `def imreadVD3(self, filename)` (line 43): Read an ITK vector image with double precision vectors. - - `def imwriteVD3(self, image, filename, compression=True)` (line 69): Write an ITK vector image with double precision vectors. - - `def convert_itk_image_to_sitk(self, itk_image)` (line 93): Convert an ITK image to a SimpleITK image. - - `def convert_sitk_image_to_itk(self, sitk_image)` (line 151): Convert a SimpleITK image to an ITK image. - - `def convert_array_to_image_of_vectors(self, arr_data, reference_image, ptype=itk.D)` (line 218): Convert a numpy array to an ITK image of vector type. - - `def flip_image(self, in_image, in_mask=None, flip_x=False, flip_y=False, flip_z=False, flip_and_make_identity=False)` (line 249): Flip the image and mask. - -## src/physiomotion4d/landmark_tools.py - -- **class LandmarkTools** (line 28): Read and write anatomical landmarks in LPS world coordinates. - - `def __init__(self, log_level=logging.INFO)` (line 51): Initialize the LandmarkTools class. - - `def read_landmarks_3dslicer(self, path)` (line 59): Read landmarks from a 3D Slicer Markups JSON (``.mrk.json``) file. - - `def write_landmarks_3dslicer(self, landmarks, path)` (line 112): Write landmarks to a 3D Slicer Markups JSON file in LPS. - - `def read_landmarks_csv(self, path)` (line 148): Read landmarks from a CSV file with header ``Name,x,y,z`` (LPS). - - `def write_landmarks_csv(self, landmarks, path)` (line 192): Write landmarks to a CSV file with header ``Name,x,y,z`` (LPS). - -## src/physiomotion4d/physiomotion4d_base.py - -- **class ClassNameFilter** (line 38): Filter to show logs only from specific class names. - - `def __init__(self)` (line 51) - - `def filter(self, record)` (line 56): Filter log records based on class name. -- **class PhysioMotion4DBase** (line 68): Base class providing standardized logging and debug settings. - - `def __init__(self, class_name=None, log_level=logging.INFO, log_to_file=None)` (line 106): Initialize the base class with logging configuration. - - `def set_log_level(cls, log_level)` (line 197): Set the logging level for all PhysioMotion4D classes. - - `def set_log_classes(cls, class_names)` (line 223): Set which classes should show their logging output. - - `def set_log_all_classes(cls)` (line 242): Enable logging output from all PhysioMotion4D classes. - - `def get_log_classes(cls)` (line 256): Get the list of classes currently showing logs. - - `def log_debug(self, message, *args)` (line 272): Log a debug message with optional %-style formatting. - - `def log_info(self, message, *args)` (line 285): Log an info message with optional %-style formatting. - - `def log_warning(self, message, *args)` (line 298): Log a warning message with optional %-style formatting. - - `def log_error(self, message, *args)` (line 311): Log an error message with optional %-style formatting. - - `def log_critical(self, message, *args)` (line 324): Log a critical message with optional %-style formatting. - - `def log_section(self, title, *args, width=70, char='=')` (line 362): Log a formatted section header with optional %-style formatting. - - `def log_progress(self, current, total, prefix='Progress')` (line 390): Log progress information. - -## src/physiomotion4d/register_images_ants.py - -- **class RegisterImagesANTS** (line 24): ANTs-based deformable image registration implementation. - - `def __init__(self, log_level=logging.INFO)` (line 70): Initialize the ANTs image registration class. - - `def set_number_of_iterations(self, number_of_iterations)` (line 85): Set the number of iterations for ANTs registration. - - `def set_transform_type(self, transform_type)` (line 94): Set the type of transform to use for registration. - - `def set_metric(self, metric)` (line 106): Set the similarity metric to use for registration. - - `def itk_affine_transform_to_ANTS_transform(self, itk_tfm)` (line 316): Convert ITK affine/rigid transform to ANTs affine transform. - - `def itk_transform_to_ANTSfile(self, itk_tfm, reference_image, output_filename)` (line 409): Convert ITK transform to ANTs transform file. - - `def registration_method(self, moving_image, moving_mask=None, moving_labelmap=None, moving_image_pre=None, initial_forward_transform=None)` (line 509): Register moving image to fixed image using ANTs registration algorithm. - -## src/physiomotion4d/register_images_base.py - -- **class RegisterImagesBase** (line 29): Base class for deformable image registration algorithms. - - `def __init__(self, log_level=logging.INFO)` (line 75): Initialize the base image registration class. - - `def set_modality(self, modality)` (line 108): Set the imaging modality for registration optimization. - - `def set_fixed_image(self, fixed_image)` (line 124): Set the fixed/target image for registration. - - `def set_mask_dilation(self, mask_dilation_mm)` (line 145): Set the dilation of the fixed and moving image masks. - - `def set_fixed_mask(self, fixed_mask)` (line 153): Set a binary mask for the fixed image region of interest. - - `def set_fixed_labelmap(self, fixed_labelmap)` (line 194): Set the fixed image labelmap (multi-label segmentation). - - `def preprocess(self, image, modality='ct')` (line 207): Preprocess the image based on modality-specific requirements. - - `def registration_method(self, moving_image, moving_mask=None, moving_labelmap=None, moving_image_pre=None, initial_forward_transform=None)` (line 228): Main registration method to align moving image to fixed image. - - `def register(self, moving_image, moving_mask=None, moving_labelmap=None, moving_image_pre=None, initial_forward_transform=None)` (line 263): Register a moving image to the fixed image. - - `def get_registered_image(self)` (line 350): Get the registered image. - -## src/physiomotion4d/register_images_greedy.py - -- **class RegisterImagesGreedy** (line 39): Greedy-based deformable image registration implementation. - - `def __init__(self, log_level=logging.INFO)` (line 67): Initialize the Greedy image registration class. - - `def set_number_of_iterations(self, number_of_iterations)` (line 80): Set the number of iterations per resolution level. - - `def set_transform_type(self, transform_type)` (line 88): Set the type of transform: Deformable, Affine, or Rigid. - - `def set_metric(self, metric)` (line 99): Set the similarity metric (CC→NCC, Mattes→NMI, MeanSquares→SSD). - - `def registration_method(self, moving_image, moving_mask=None, moving_labelmap=None, moving_image_pre=None, initial_forward_transform=None)` (line 260): Register moving image to fixed image using Greedy. - -## src/physiomotion4d/register_images_icon.py - -- **class RegisterImagesICON** (line 30): ICON-based deformable image registration implementation. - - `def __init__(self, log_level=logging.INFO)` (line 66): Initialize the ICON image registration class. - - `def set_weights_path(self, weights_path)` (line 84): Set a custom weights file for the uniGradICON network. - - `def set_number_of_iterations(self, number_of_iterations)` (line 98): Set the number of iterations for ICON registration. - - `def set_multi_modality(self, enable)` (line 106): Enable or disable multi-modality registration. - - `def set_mass_preservation(self, enable)` (line 123): Enable or disable mass preservation constraint. - - `def preprocess(self, image, modality='ct')` (line 140): Preprocess the image for ICON registration. - - `def registration_method(self, moving_image, moving_mask=None, moving_labelmap=None, moving_image_pre=None, initial_forward_transform=None)` (line 160): Register moving image to fixed image using ICON registration algorithm. - - `def create_mask(labelmap, dilation_mm=5.0)` (line 350): Create a binary registration mask from a labelmap. - -## src/physiomotion4d/register_models_distance_maps.py - -- **class RegisterModelsDistanceMaps** (line 61): Register anatomical models using mask-based deformable registration. - - `def __init__(self, moving_model, fixed_model, reference_image, roi_dilation_mm=20, log_level=logging.INFO)` (line 118): Initialize mask-based model registration. - - `def register(self, transform_type='Deformable', use_ICON=False, icon_iterations=50)` (line 225): Perform mask-based registration of moving model to fixed model. - -## src/physiomotion4d/register_models_icp.py - -- **class RegisterModelsICP** (line 52): Register anatomical models using Iterative Closest Point (ICP) algorithm. - - `def __init__(self, fixed_model, log_level=logging.INFO)` (line 100): Initialize ICP-based model registration. - - `def register(self, moving_model, transform_type='Affine', max_iterations=2000)` (line 130): Perform ICP alignment of moving model to fixed model. - -## src/physiomotion4d/register_models_icp_itk.py - -- **class RegisterModelsICPITK** (line 14): Register shape models using model to distance map minimization. - - `def __init__(self, fixed_model, reference_image=None, point_subsample_step=4, log_level=logging.INFO)` (line 39): Initialize the ICP-ITK model registration. - - `def set_reference_image(self, reference_image)` (line 121): Set the reference image for registration. - - `def set_fixed_model(self, fixed_model)` (line 132): Set the average model for registration. - - `def register(self, moving_model, initial_transform=None, transform_type='Affine', method='L-BFGS-B', scale_bound=0.2, skew_bound=0.03, versor_bound=0.15, translation_bound=15, max_iterations=500)` (line 270): Optimize affine alignment to minimize mean distance. - -## src/physiomotion4d/register_models_pca.py - -- **class RegisterModelsPCA** (line 19): Register PCA-based shape models to medical images using mean distance optimization. - - `def __init__(self, pca_template_model, pca_eigenvectors, pca_std_deviations, pca_number_of_modes=0, pca_template_model_point_subsample=4, post_pca_transform=None, fixed_distance_map=None, fixed_model=None, reference_image=None, log_level=logging.INFO)` (line 77): Initialize the PCA-based model-to-image registration. - - `def from_json(cls, pca_template_model, pca_json_filename, pca_number_of_modes=0, pca_template_model_point_subsample=4, post_pca_transform=None, fixed_distance_map=None, fixed_model=None, reference_image=None, log_level=logging.INFO)` (line 183): Create RegisterModelsPCA from PCA model JSON file. - - `def from_pca_model(cls, pca_template_model, pca_model, pca_number_of_modes=0, pca_template_model_point_subsample=4, post_pca_transform=None, fixed_distance_map=None, fixed_model=None, reference_image=None, log_level=logging.INFO)` (line 290): Create RegisterModelsPCA from a PCA model dictionary. - - `def set_fixed_model(self, fixed_model, reference_image)` (line 371): Set the fixed model for registration. - - `def set_fixed_distance_map(self, fixed_distance_map)` (line 397): Set the reference image for registration. - - `def set_pca_template_model(self, pca_template_model)` (line 408): Set the average model for registration. - - `def transform_template_model(self)` (line 639): Create the final registered model by applying PCA deformation. - - `def transform_point(self, point, include_post_pca_transform=True)` (line 702): Transform an arbitrary point using nearest neighbor interpolation. - - `def compute_pca_transforms(self, reference_image)` (line 739): Compute PCA transforms. - - `def register(self, pca_number_of_modes=0, pca_coefficient_bounds=3.5, method='L-BFGS-B', max_iterations=100)` (line 776): Optimize PCA coefficients to deform the model to better match - -## src/physiomotion4d/register_time_series_images.py - -- **class RegisterTimeSeriesImages** (line 31): Register a time series of images to a fixed image. - - `def __init__(self, registration_method='ANTS', log_level=logging.INFO)` (line 90): Initialize the time series image registration class. - - `def set_number_of_iterations_ANTS(self, number_of_iterations_ANTS)` (line 127): Set the number of iterations for ANTs registration. - - `def set_number_of_iterations_ICON(self, number_of_iterations_ICON)` (line 138): Set the number of iterations for ICON registration. - - `def set_number_of_iterations_greedy(self, number_of_iterations_greedy)` (line 146): Set the number of iterations for Greedy registration. - - `def set_smooth_prior_transform_sigma(self, smooth_prior_transform_sigma)` (line 157): Set the sigma for smoothing the prior transform. - - `def set_mask_dilation(self, mask_dilation_mm)` (line 167): Set the dilation of the fixed and moving image masks. - - `def set_modality(self, modality)` (line 177): Set the imaging modality for registration optimization. - - `def set_fixed_image(self, fixed_image)` (line 187): Set the fixed image for registration. - - `def set_fixed_mask(self, fixed_mask)` (line 198): Set a binary mask for the fixed image region of interest. - - `def register_time_series(self, moving_images, moving_masks=None, moving_labelmaps=None, reference_frame=0, register_reference=True, prior_weight=0.0)` (line 208): Register a time series of images to the fixed image. - - `def reconstruct_time_series(self, moving_images, inverse_transforms, upsample_to_fixed_resolution=False)` (line 617): Reconstruct time series images using inverse transforms. - - `def registration_method(self, moving_image, moving_mask=None, moving_labelmap=None, moving_image_pre=None, initial_forward_transform=None)` (line 747): Registration method required by RegisterImagesBase. - -## src/physiomotion4d/segment_anatomy_base.py - -- **class SegmentAnatomyBase** (line 19): Base class for anatomy segmentation that provides common functionality for - - `def __init__(self, log_level=logging.INFO)` (line 50): Initialize the SegmentAnatomyBase class. - - `def label_to_type(self, label_name)` (line 92): Return the anatomy group ('heart', 'lung', etc.) for a label name. - - `def set_target_spacing(self, target_spacing)` (line 108): Set the target isotropic spacing for image resampling. - - `def preprocess_input(self, input_image)` (line 120): Preprocess the input image for segmentation. - - `def postprocess_labelmap(self, labelmap_image, input_image)` (line 242): Resample the labelmap to match the input image spacing. - - `def segment_connected_component(self, preprocessed_image, labelmap_image, lower_threshold, upper_threshold, labelmap_ids=None, mask_id=0, use_mid_slice=True, hole_fill=2)` (line 338): Segment connected components based on intensity thresholding. - - `def segment_contrast_agent(self, preprocessed_image, labelmap_image)` (line 445): Include contrast-enhanced blood in the labelmap. - - `def create_anatomy_group_masks(self, labelmap_image)` (line 492): Create binary masks for different anatomical groups from the labelmap. - - `def segmentation_method(self, preprocessed_image)` (line 538): Abstract method for image segmentation - must be implemented by subclasses. - - `def dilate_mask(self, mask, dilation)` (line 560): Dilate a binary mask using morphological operations. - - `def segment(self, input_image, contrast_enhanced_study=False)` (line 583): Perform complete chest CT segmentation. - -## src/physiomotion4d/segment_chest_total_segmentator.py - -- **class SegmentChestTotalSegmentator** (line 21): Chest CT segmentation using TotalSegmentator deep learning model. - - `def __init__(self, log_level=logging.INFO)` (line 50): Initialize the TotalSegmentator-based chest segmentation. - - `def segmentation_method(self, preprocessed_image)` (line 209): Run TotalSegmentator on the preprocessed image and return result. - -## src/physiomotion4d/segment_heart_simpleware.py - -- **class SegmentHeartSimpleware** (line 23): Heart CT segmentation using Simpleware Medical's ASCardio module. - - `def __init__(self, log_level=logging.INFO)` (line 58): Initialize the Simpleware Medical based heart segmentation. - - `def set_trim_branches(self, trim_branches)` (line 118): Enable trimming of pulmonary and great-vessel branches. - - `def set_simpleware_executable_path(self, path)` (line 133): Set the path to the Simpleware Medical console executable. - - `def segmentation_method(self, preprocessed_image)` (line 146): Run Simpleware Medical ASCardio segmentation on the preprocessed image. - - `def get_landmarks(self)` (line 392): Get the landmarks. - - `def trim_branches(self, labelmap_image)` (line 396): Trim pulmonary and great-vessel branches back to the cardiac region. - -## src/physiomotion4d/test_tools.py - -- `def set_create_baseline_if_missing(value)` (line 29): Set whether to create baseline files when missing (used by pytest conftest). -- **class TestTools** (line 35): Utilities for pytest image comparison: baseline directory, result directory, - - `def __init__(self, class_name, results_dir=None, baselines_dir=None, *, log_level=logging.INFO)` (line 45): Initialize test helpers. - - `def running_as_test()` (line 103): True when the script is run as a test (e.g. by pytest experiment tests). - - `def image_pass_fail_and_pixels_above_tolerance(self)` (line 121): Return (pass, value) for number of pixels above tolerance from the most - - `def image_pass_fail_and_total_absolute_error(self)` (line 136): Return (pass, value) for total absolute error from the most recent - - `def image_difference(self)` (line 151): Return the difference image (itk.Image) from the most recent - - `def transform_pass_fail_and_number_of_values_above_tolerance(self)` (line 158): Return (pass, value) for number of values above tolerance from the most recent compare_result_to_baseline_transform call. - - `def transform_pass_fail_and_total_absolute_error(self)` (line 174): Return (pass, value) for total absolute error from the most recent compare_result_to_baseline_transform call. - - `def transform_difference(self)` (line 188): Return the difference transform (itk.Transform) from the most recent compare_result_to_baseline_transform call. - - `def write_result_image(self, image, filename)` (line 194): Write the image to the configured result artifact directory. - - `def write_result_transform(self, transform, filename)` (line 198): Write the transform to the configured result artifact directory. - - `def compare_result_to_baseline_transform(self, filename, *, per_value_absolute_error_tol=0.0, max_number_of_values_above_tol=0, total_absolute_error_tol=0.0)` (line 204): Compare the transform to the baseline transform. - - `def compare_result_to_baseline_image(self, filename, *, per_pixel_absolute_error_tol=0.0, max_number_of_pixels_above_tol=0, total_absolute_error_tol=0.0)` (line 282): Load a 3D result image and a 3D baseline image (.mha), compare the full - - `def save_screenshot_mesh(self, mesh, filename, *, camera_position='iso', window_size=(800, 600), color='pink', opacity=0.9)` (line 389): Render a PyVista mesh off-screen and save a PNG. - - `def save_screenshot_openusd(self, usd_file, filename, *, prim_path='/World', time_code=None)` (line 438): Render USD mesh geometry off-screen and save a PNG. - - `def save_screenshot_image_slice(self, image, filename, *, axis=0, slice_fraction=0.5, colormap='gray', vmin=None, vmax=None, overlay_mask=None, overlay_alpha=0.4)` (line 507): Extract one slice from an ITK image and save a PNG via matplotlib. - -## src/physiomotion4d/transform_tools.py - -- **class TransformTools** (line 41): Utilities for transforming and manipulating ITK transforms. - - `def __init__(self, log_level=logging.INFO)` (line 74): Initialize the TransformTools class. - - `def combine_displacement_field_transforms(self, tfm1, tfm2, reference_image, tfm1_weight=1.0, tfm2_weight=1.0, mode='compose', tfm1_blur_sigma=0.0, tfm2_blur_sigma=0.0)` (line 82): Compose two displacement field transforms. - - `def convert_transform_to_displacement_field(self, tfm, reference_image, np_component_type=np.float64, use_reference_image_as_mask=False)` (line 166): Generate a dense deformation field from an ITK transform. - - `def convert_transform_to_displacement_field_transform(self, tfm, reference_image)` (line 254): Convert an ITK transform to a displacement field transform. - - `def invert_displacement_field_transform(self, tfm)` (line 271): Invert a displacement field transform. - - `def transform_pvcontour(self, contour, tfm, with_deformation_magnitude=False)` (line 293): Transform PyVista contour meshes using an ITK transform. - - `def transform_dataset(self, mesh, tfm, with_deformation_magnitude=False)` (line 337): Transform a PyVista dataset while preserving mesh topology and data arrays. - - `def transform_image(self, img, tfm, reference_image, interpolation_method='linear')` (line 384): Transform an ITK image using a specified transform and interpolation. - - `def convert_vtk_matrix_to_itk_transform(self, vtk_mat)` (line 461): Convert a VTK matrix to an ITK transform. - - `def smooth_transform(self, tfm, sigma, reference_image)` (line 496): Smooth a transform using Gaussian filtering to reduce noise. - - `def combine_transforms_with_masks(self, transform1, transform2, mask1, mask2, reference_image, max_iter=10, jacobian_threshold=0.1)` (line 555): Combine two transforms using spatial masks with folding correction. - - `def compute_jacobian_determinant_from_field(self, field)` (line 645): Compute Jacobian determinant of a displacement field. - - `def detect_folding_in_field(self, jacobian_det, threshold=0.1)` (line 674): Detect spatial folding in a transform. - - `def reduce_folding_in_field(self, field, jacobian_det, reduction_factor=0.8, threshold=0.1)` (line 698): Reduce folding by scaling displacement field in problematic regions. - - `def generate_grid_image(self, reference_image, grid_size=60, line_width=3)` (line 744): Generate a grid image. - - `def convert_field_to_grid_visualization(self, tfm, reference_image, grid_size=60, line_width=3)` (line 777): Generate a visual deformation grid for transform visualization. - - `def convert_itk_transform_to_usd_visualization(self, tfm, reference_image, output_filename, visualization_type='arrows', subsample_factor=4, arrow_scale=1.0, magnitude_threshold=0.0)` (line 813): Convert an ITK transform to a USD visualization for NVIDIA Omniverse. - -## src/physiomotion4d/usd_anatomy_tools.py - -- **class USDAnatomyTools** (line 207): Apply OmniSurface materials to anatomy mesh prims in a USD stage. - - `def __init__(self, stage, log_level=logging.INFO)` (line 216): Initialize USDAnatomyTools. - - `def get_anatomy_types(self)` (line 233): Return list of registered render-param keys (groups + organ overrides). - - `def get_anatomy_diffuse_color(self, anatomy_type)` (line 237): Return the diffuse reflection RGB color for the given group/organ. - - `def apply_anatomy_material_to_mesh(self, mesh_path, anatomy_type)` (line 264): Apply an anatomic OmniSurface material to a single mesh prim by type. - - `def apply_anatomy_material_to_prim(self, prim, material_params)` (line 288): Corrected material application with Omniverse-specific fixes - - `def enhance_meshes(self, segmentator)` (line 359): Apply per-organ OmniSurface materials to every matching mesh prim. - -## src/physiomotion4d/usd_tools.py - -- **class USDTools** (line 28): Utilities for manipulating Universal Scene Description (USD) files. - - `def __init__(self, log_level=logging.INFO)` (line 64): Initialize the USDTools class. - - `def load_usd_as_vtk(self, usd_file, prim_path='/World', time_code=None)` (line 72): Load USD mesh geometry as a PyVista ``PolyData``. - - `def get_subtree_bounding_box(self, prim)` (line 218): Compute the axis-aligned bounding box of a USD primitive subtree. - - `def save_usd_file_arrangement(self, new_stage_name, usd_file_names)` (line 278): Create a spatial grid arrangement of objects from multiple USD files. - - `def merge_usd_files(self, output_filename, input_filenames_list)` (line 404): Merge multiple USD files into a single comprehensive USD file. - - `def merge_usd_files_flattened(self, output_filename, input_filenames_list)` (line 609): Merge multiple USD files using references and flattening. - - `def list_mesh_primvars(self, stage_or_path, mesh_path, time_code=None)` (line 737): List all primvars on a USD mesh with metadata. - - `def pick_color_primvar(self, primvar_infos, keywords=('strain', 'stress'))` (line 832): Select a primvar for coloring based on keywords and preferences. - - `def apply_colormap_from_primvar(self, stage_or_path, mesh_path, source_primvar, *, cmap='viridis', time_codes=None, intensity_range=None, use_sigmoid_scale=False, write_default_at_t0=True, bind_vertex_color_material=True)` (line 886): Apply colormap visualization by converting a primvar to displayColor. - - `def set_solid_display_color(self, stage_or_path, mesh_path, color, *, time_codes=None, bind_vertex_color_material=True)` (line 1182): Set a constant (solid) displayColor for a mesh. - - `def list_mesh_paths_under(self, stage_or_path, parent_path='/World/Meshes')` (line 1275): List paths of all mesh prims under a parent path. - - `def repair_mesh_primvar_element_sizes(self, stage_or_path, mesh_path, *, time_code=None, save=True)` (line 1302): Repair missing/incorrect primvar elementSize metadata for a mesh. - -## src/physiomotion4d/vtk_to_usd/converter.py - -- `def convert_vtk_file(vtk_file, output_usd_file, *, data_basename=None, mesh_name='Mesh', extract_surface=True, settings=None, material=None)` (line 15): Convert one VTK file to one USD stage. - -## src/physiomotion4d/vtk_to_usd/data_structures.py - -- **class DataType** (line 13): Data type enumeration for generic arrays. -- **class GenericArray** (line 29): Generic data array that can be converted to USD primvar. -- **class MaterialData** (line 79): Material properties for USD conversion. -- **class MeshData** (line 97): Mesh geometry data for USD conversion. -- **class VolumeData** (line 119): Volume data for USD conversion. -- **class TimeStepData** (line 133): Data for a single time step. -- **class ConversionSettings** (line 143): Settings for VTK to USD conversion. - -## src/physiomotion4d/vtk_to_usd/material_manager.py - -- **class MaterialManager** (line 16): Manages creation and binding of USD materials. - - `def __init__(self, stage, materials_scope_path='/World/Looks')` (line 23): Initialize material manager. - - `def create_material(self, mat_data, time_code=None)` (line 37): Create a UsdPreviewSurface material. - - `def bind_material(self, geom_prim, material)` (line 133): Bind a material to a geometry prim. - - `def get_or_create_material(self, mat_data, time_code=None)` (line 152): Get existing material from cache or create new one. - - `def create_default_material(self, name='default', color=(0.8, 0.8, 0.8))` (line 168): Create a simple default material. - -## src/physiomotion4d/vtk_to_usd/mesh_utils.py - -- `def cell_type_name_for_vertex_count(count)` (line 27): Return a readable name for a cell type given its vertex count. -- `def split_mesh_data_by_cell_type(mesh_data, mesh_name)` (line 32): Split MeshData into one mesh per distinct face vertex count (cell type). -- `def split_mesh_data_by_connectivity(mesh_data, mesh_name)` (line 280): Split MeshData into one mesh per connected component. - -## src/physiomotion4d/vtk_to_usd/primvar_derivations.py - -- `def compute_von_mises_stress(stress_tensor)` (line 49): Compute scalar von Mises stress from a row-major 9-component tensor. -- `def derive_von_mises_from_stress(array)` (line 107): Derive a scalar VonMises primvar from any 9-component stress tensor. -- `def derive_primvars(arrays)` (line 147): Apply every registered derivation to every array in ``arrays``. - -## src/physiomotion4d/vtk_to_usd/usd_mesh_converter.py - -- **class UsdMeshConverter** (line 25): Converts MeshData to UsdGeomMesh with full feature support. - - `def __init__(self, stage, settings, material_mgr)` (line 36): Initialize mesh converter. - - `def create_mesh(self, mesh_data, mesh_path, time_code=None, bind_material=True)` (line 57): Create a UsdGeomMesh from MeshData. - - `def create_time_varying_mesh(self, mesh_data_sequence, mesh_path, time_codes, bind_material=True)` (line 329): Create a mesh with time-varying attributes. - -## src/physiomotion4d/vtk_to_usd/usd_utils.py - -- `def lps_to_usd(point)` (line 20): Convert LPS (Left-Posterior-Superior) coordinates to USD's right-handed Y-up frame. -- `def lps_points_to_usd(points)` (line 58): Convert array of LPS points (mm) to USD Y-up coordinates (m). -- `def lps_normals_to_usd(normals)` (line 82): Convert array of LPS normals to USD Y-up coordinates. -- `def numpy_to_vt_array(array, data_type)` (line 105): Convert numpy array to appropriate VtArray type. -- `def get_sdf_value_type(data_type, num_components)` (line 177): Get appropriate SDF value type for primvar creation. -- `def sanitize_primvar_name(name)` (line 224): Sanitize a name to be USD-compliant. -- `def create_primvar(geom, array, array_name_prefix='', time_code=None)` (line 259): Create a USD primvar from a GenericArray. -- `def triangulate_face(face_counts, face_indices)` (line 373): Triangulate polygonal faces using fan triangulation. -- `def compute_mesh_extent(points)` (line 424): Compute bounding box extent for a mesh. -- `def add_framing_camera(stage, *, parent_path='/World', name='Camera', bounds_min=None, bounds_max=None, focal_length_mm=50.0, horizontal_aperture_mm=36.0, distance_factor=3.0)` (line 436): Define a USD camera that frames stage geometry with tight clipping planes. - -## src/physiomotion4d/vtk_to_usd/vtk_reader.py - -- **class VTKReader** (line 20): Base class for VTK file readers. -- **class PolyDataReader** (line 235): Reader for VTK PolyData files (.vtp). - - `def read(filename)` (line 239): Read a VTP file and return MeshData. -- **class LegacyVTKReader** (line 295): Reader for legacy VTK files (.vtk). - - `def read(filename, extract_surface=True)` (line 307): Read a legacy VTK file and return MeshData. -- **class UnstructuredGridReader** (line 468): Reader for VTK UnstructuredGrid files (.vtu). - - `def read(filename, extract_surface=True)` (line 472): Read a VTU file and return MeshData. -- `def read_vtk_file(filename, extract_surface=True)` (line 581): Auto-detect VTK file format and read appropriately. -- `def validate_time_series_topology(mesh_data_sequence, filenames=None)` (line 609): Validate topology consistency across a time series of meshes. - -## src/physiomotion4d/workflow_convert_image_to_usd.py - -- **class WorkflowConvertImageToUSD** (line 42): Complete workflow for converting 4D CT images to dynamic USD models. - - `def __init__(self, input_filenames, contrast_enhanced, output_directory, project_name, reference_image_filename=None, number_of_registration_iterations=1, segmentation_method='ChestTotalSegmentator', registration_method='ICON', times_per_second=24.0, log_level=logging.INFO, save_registered_images=True, save_registration_transforms=True, save_labelmaps=True)` (line 61): Initialize the image-to-USD workflow. - - `def process(self)` (line 239): Execute the complete workflow from 4D CT to dynamic USD models. - -## src/physiomotion4d/workflow_convert_image_to_vtk.py - -- **class WorkflowConvertImageToVTK** (line 59): Segment a CT image and produce per-anatomy-group VTK surfaces and meshes. - - `def __init__(self, segmentation_method='ChestTotalSegmentator', log_level=logging.INFO)` (line 105): Initialize the workflow. - - `def run_workflow(self, input_image, contrast_enhanced_study=False, anatomy_groups=None)` (line 255): Segment the CT image and extract per-anatomy-group VTK objects. - - `def save_surfaces(surfaces, output_dir, prefix='')` (line 358): Save each group surface to its own VTP file. - - `def save_meshes(meshes, output_dir, prefix='')` (line 385): Save each group voxel mesh to its own VTU file. - - `def save_combined_surface(surfaces, output_dir, prefix='')` (line 411): Merge all group surfaces into a single VTP file. - - `def save_combined_mesh(meshes, output_dir, prefix='')` (line 446): Merge all group meshes into a single VTU file. - -## src/physiomotion4d/workflow_convert_vtk_to_usd.py - -- **class WorkflowConvertVTKToUSD** (line 23): Workflow to convert one or more VTK files to USD with configurable - - `def __init__(self, vtk_files, output_usd, *, separate_by_connectivity=True, separate_by_cell_type=False, mesh_name='Mesh', times_per_second=60.0, extract_surface=True, time_series_pattern='\\.t(\\d+)\\.(vtk|vtp|vtu)$', appearance='solid', solid_color=(0.8, 0.8, 0.8), anatomy_type='heart', colormap_primvar=None, colormap_name='viridis', colormap_intensity_range=None, log_level=logging.INFO)` (line 29): Initialize the VTK-to-USD workflow. - - `def discover_time_series(self, paths, pattern='\\.t(\\d+)\\.(vtk|vtp|vtu)$')` (line 93): Discover and sort time-series VTK files by extracted time index. - - `def run(self)` (line 129): Run the full workflow: convert VTK to USD, then apply the chosen appearance. - -## src/physiomotion4d/workflow_create_statistical_model.py - -- **class WorkflowCreateStatisticalModel** (line 35): Create a PCA statistical shape model from a sample of meshes aligned to a reference. - - `def __init__(self, sample_meshes, reference_mesh, pca_number_of_components=15, reference_spatial_resolution=1.0, reference_buffer_factor=0.25, solve_for_surface_pca=True, log_level=logging.INFO)` (line 57): Initialize the create-statistical-model workflow. - - `def set_pca_number_of_components(self, n)` (line 103): Set number of PCA components to retain. - - `def run_workflow(self)` (line 313): Run the full pipeline and return a dictionary of results (no file I/O). - -## src/physiomotion4d/workflow_fine_tune_icon_registration.py - -- **class WorkflowFineTuneICONRegistration** (line 53): Fine-tune uniGradICON on paired 3D images and apply the fine-tuned weights. - - `def __init__(self, subject_image_files, output_dir, fine_tune_name, subject_ids=None, subject_segmentation_files=None, subject_mask_files=None, subject_landmark_files=None, epochs=2000, batch_size=4, learning_rate=5e-05, input_shape=(175, 175, 175), similarity='lncc', lambda_value=1.5, dice_loss_weight=0.5, lncc_sigma=5, ct_window=(-1000.0, 1000.0), is_ct=True, gpus=None, eval_period=10, save_period=50, mask_dilation_mm=5.0, mask_dir=None, unigradicon_src_path=None, log_level=logging.INFO)` (line 135): Initialize the ICON fine-tuning workflow. - - `def uses_segmentations(self)` (line 313): Whether at least one segmentation file is supplied for training. - - `def uses_masks(self)` (line 321): Whether the dataset will have a ``mask`` field on every kept entry. - - `def prepare_dataset(self)` (line 387): Write the uniGradICON dataset JSON from the configured file lists. - - `def prepare_config(self, dataset_json_path=None)` (line 492): Write the uniGradICON fine-tuning YAML config. - - `def expected_weights_path(self)` (line 557): Return the path uniGradICON writes its final checkpoint to. - - `def run_fine_tuning(self)` (line 572): Build configs and launch ``unigradicon.finetuning.finetune``. - - `def apply_registration(self, reference_image, moving_images, weights_path=None, reference_segmentation=None, reference_landmarks=None, moving_segmentations=None, moving_landmarks=None, number_of_iterations=20, modality='ct')` (line 629): Register each moving image to the reference using fine-tuned ICON weights. - -## src/physiomotion4d/workflow_fit_statistical_model_to_patient.py - -- **class WorkflowFitStatisticalModelToPatient** (line 56): Register anatomical models using multi-stage ICP, mask-based, and image-based - - `def __init__(self, template_model, patient_models=None, patient_image=None, segmentation_method='HeartSimplewareTrimmedBranches', log_level=logging.INFO)` (line 135): Initialize the model-to-image-and-model registration pipeline. - - `def set_mask_dilation_mm(self, mask_dilation_mm)` (line 363): Set mask dilation amount for auto-generated masks. - - `def set_roi_dilation_mm(self, roi_dilation_mm)` (line 372): Set ROI mask dilation amount. - - `def set_use_pca_registration(self, use_pca_registration, pca_model=None, pca_number_of_modes=0, pca_uses_surface=True)` (line 381): Set whether to use PCA-based registration and provide the PCA model. - - `def set_use_mask_to_mask_registration(self, use_mask_to_mask_registration)` (line 416): Set whether to use mask-to-mask registration. - - `def set_use_mask_to_image_registration(self, use_mask_to_image_registration, template_labelmap=None, template_labelmap_organ_mesh_ids=None, template_labelmap_organ_extra_ids=None, template_labelmap_background_ids=None)` (line 427): Set whether to use mask-to-image registration. - - `def register_model_to_model_icp(self)` (line 501): Perform ICP alignment of template model to patient model. - - `def register_model_to_model_pca(self)` (line 559): Perform PCA-based registration after ICP alignment. - - `def register_mask_to_mask(self, use_ICON_refinement=False)` (line 685): Perform mask-based deformable registration of model to patient model. - - `def register_labelmap_to_image(self, use_ICON_refinement=False)` (line 753): Perform labelmap-to-image refinement. - - `def transform_model(self, base_model=None)` (line 873): Apply registration transforms to the model. - - `def run_workflow(self, use_ICON_registration_refinement=False)` (line 938): Execute the complete multi-stage registration workflow. - -## src/physiomotion4d/workflow_reconstruct_highres_4d_ct.py - -- **class WorkflowReconstructHighres4DCT** (line 35): Reconstruct high-resolution 4D CT from time series and reference image. - - `def __init__(self, time_series_images, fixed_image, reference_frame=0, register_reference=False, registration_method='ANTS_ICON', log_level=logging.INFO)` (line 92): Initialize the high-resolution 4D CT reconstruction workflow. - - `def set_number_of_iterations_ANTS(self, number_of_iterations_ANTS)` (line 174): Set the number of iterations for ANTs registration. - - `def set_number_of_iterations_ICON(self, number_of_iterations_ICON)` (line 185): Set the number of iterations for ICON registration. - - `def set_prior_weight(self, prior_weight)` (line 193): Set the weight for temporal smoothing with prior transforms. - - `def set_modality(self, modality)` (line 209): Set the imaging modality for registration optimization. - - `def set_mask_dilation(self, mask_dilation_mm)` (line 217): Set the dilation of the fixed and moving image masks. - - `def set_fixed_mask(self, fixed_mask)` (line 225): Set a binary mask for the fixed image region of interest. - - `def set_moving_masks(self, moving_masks)` (line 233): Set binary masks for the moving images. - - `def register_time_series(self)` (line 255): Register time series images to the fixed image. - - `def reconstruct_time_series(self, upsample_to_fixed_resolution=False)` (line 317): Reconstruct high-resolution time series using inverse transforms. - - `def run_workflow(self, upsample_to_fixed_resolution=False)` (line 369): Execute the complete high-resolution 4D CT reconstruction workflow. - -## tests/conftest.py - -- `def pytest_addoption(parser)` (line 53): Add custom command-line options for pytest. -- `def pytest_configure(config)` (line 111): Configure pytest with custom markers and settings. -- `def pytest_collection_modifyitems(config, items)` (line 148): Automatically skip experiment and tutorial tests unless their opt-in flags -- `def pytest_runtest_logreport(report)` (line 213): Collect test timing information after each test completes. -- `def pytest_terminal_summary(terminalreporter, exitstatus, config)` (line 238): Print comprehensive test timing report after all tests complete. -- `def test_directories()` (line 400): Set up test directories for data and results. -- `def download_test_data(test_directories)` (line 425): Download Slicer-Heart-CT data. -- `def test_images(download_test_data, test_directories)` (line 452): Convert and resample 4D NRRD data; return pre-resampled time points. -- `def test_labelmaps(segmenter_total_segmentator, test_images, test_directories)` (line 505): Segment each time point with TotalSegmentator and return result dicts. -- `def test_transforms(registrar_ANTS, test_images, test_directories)` (line 546): Perform ANTs registration and return results. -- `def segmenter_total_segmentator()` (line 601): Create a SegmentChestTotalSegmentator instance. -- `def segmenter_simpleware()` (line 607): Create a SegmentHeartSimpleware instance. -- `def contour_tools()` (line 613): Create a ContourTools instance. -- `def registrar_ANTS()` (line 619): Create a RegisterImagesANTS instance. -- `def registrar_greedy()` (line 625): Create a RegisterImagesGreedy instance. -- `def registrar_ICON()` (line 631): Create a RegisterImagesICON instance. -- `def transform_tools()` (line 637): Create a TransformTools instance. - -## tests/test_anatomy_taxonomy.py - -- `def test_add_organ_creates_group_lazily()` (line 14) -- `def test_group_names_preserve_insertion_order()` (line 23) -- `def test_labels_in_group_unknown_returns_empty_dict()` (line 31) -- `def test_labels_in_group_returns_copy_not_alias()` (line 37): Caller mutation of the returned dict must not corrupt the taxonomy. -- `def test_all_labels_merges_every_group()` (line 46) -- `def test_group_for_label_finds_by_organ_name()` (line 58) -- `def test_group_for_label_unknown_falls_back_to_other()` (line 67) -- `def test_group_for_id_finds_by_id()` (line 73) -- `def test_fill_other_group_only_claims_unassigned_ids()` (line 82) -- `def test_fill_other_group_idempotent_for_already_claimed_other()` (line 100): Calling fill_other_group twice must not duplicate or overwrite. -- `def test_anatomy_group_dataclass_default_organs()` (line 110) -- `def test_segment_anatomy_base_default_taxonomy_seeded()` (line 116): SegmentAnatomyBase seeds contrast (135) and soft_tissue (133). - -## tests/test_cli_smoke.py - -- `def test_cli_help(module_name, monkeypatch, capsys)` (line 27): Each CLI module exits successfully for --help. -- `def test_convert_image_to_usd_help_includes_fps(monkeypatch, capsys)` (line 44): Image-to-USD CLI exposes playback FPS for animated USD output. -- `def test_convert_image_to_usd_cli_passes_fps(monkeypatch, tmp_path)` (line 60): Image-to-USD CLI forwards --fps as times_per_second. - -## tests/test_contour_tools.py - -- **class TestContourTools** (line 21): Test suite for ContourTools functionality. - - `def test_contour_tools_initialization(self, contour_tools)` (line 24): Test that ContourTools initializes correctly. - - `def test_extract_contours_from_heart_mask(self, contour_tools, test_labelmaps, test_directories)` (line 29): Test extracting contours from heart mask. - - `def test_extract_contours_from_lung_mask(self, contour_tools, test_labelmaps, test_directories)` (line 62): Test extracting contours from lung mask. - - `def test_extract_contours_multiple_anatomy(self, contour_tools, test_labelmaps, test_directories)` (line 91): Test extracting contours from multiple anatomical structures. - - `def test_create_mask_from_mesh(self, contour_tools, test_labelmaps, test_images, test_directories)` (line 129): Test creating a mask from extracted mesh. - - `def test_merge_meshes(self, contour_tools, test_labelmaps, test_directories)` (line 170): Test merging multiple meshes. - - `def test_transform_contours_identity(self, contour_tools, test_labelmaps, test_directories)` (line 220): Test transforming contours with identity transform. - - `def test_transform_contours_with_deformation(self, contour_tools, test_labelmaps, test_directories)` (line 266): Test transforming contours with deformation magnitude calculation. - - `def test_contours_from_both_time_points(self, contour_tools, test_labelmaps, test_directories)` (line 315): Test extracting contours from both time points. - -## tests/test_convert_image_4d_to_3d.py - -- **class TestConvertImage4DTo3D** (line 16): Test suite for converting a 4D image to a 3D time series. - - `def test_convert_4d_to_3d(self, download_test_data, test_directories)` (line 19): Test conversion of 4D image to 3D time series. - - `def test_slice_files_created(self, download_test_data, test_directories)` (line 42): Test that all expected slice files are present after conversion. - - `def test_load_image_4d(self, download_test_data)` (line 65): Test loading a 4D image. - - `def test_save_3d_images(self, download_test_data, test_directories)` (line 76): Test saving 3D images from a 4D source. - -## tests/test_convert_vtk_to_usd.py - -- **class TestConvertVTKToUSD** (line 36): Test suite for VTK to USD PolyMesh conversion. - - `def contour_meshes(self, contour_tools, test_labelmaps, test_directories)` (line 40): Extract or load contour meshes for USD conversion testing. - - `def test_converter_initialization(self)` (line 78): Test that ConvertVTKToUSD initializes correctly. - - `def test_supports_mesh_type(self, contour_meshes)` (line 89): Test that converter correctly identifies supported mesh types. - - `def test_convert_single_time_point(self, contour_meshes, test_directories)` (line 102): Test converting a single time point to USD. - - `def test_convert_multiple_time_points(self, contour_meshes, test_directories)` (line 135): Test converting multiple time points to USD. - - `def test_convert_with_deformation(self, contour_tools, test_labelmaps, test_directories)` (line 170): Test converting meshes with deformation magnitude. - - `def test_convert_with_colormap(self, contour_meshes, test_directories)` (line 211): Test converting meshes with colormap visualization. - - `def test_convert_unstructured_grid_to_surface(self, test_directories)` (line 250): Test converting UnstructuredGrid to surface mesh. - - `def test_usd_file_structure(self, contour_meshes, test_directories)` (line 298): Test the structure of generated USD file. - - `def test_time_varying_topology(self, contour_meshes, test_directories)` (line 330): Test handling of time-varying topology. - - `def test_batch_conversion(self, contour_tools, test_labelmaps, test_directories)` (line 371): Test converting multiple anatomy structures in batch. -- **class TestSyntheticConversion** (line 424): Synthetic (no-disk-data) tests for ConvertVTKToUSD. - - `def test_single_frame_prim_has_time_sample(self, tmp_path)` (line 437): Single-frame _convert_unified() must author one time sample, not a static prim. - - `def test_static_merge_prim_names_use_data_basename(self, tmp_path)` (line 453): Static-merge prims must be named {data_basename}_{i}, not Mesh_{i}. - - `def test_mask_ids_basic_produces_per_label_prims(self, tmp_path)` (line 485): mask_ids must produce one USD prim per label grouped under /Anatomy - - `def test_structured_grid_extracts_surface(self, tmp_path)` (line 511): StructuredGrid input is surface-extracted when convert_to_surface is true. - - `def test_mask_ids_missing_label_filters_time_codes(self, tmp_path)` (line 527): Time codes for a label must be filtered to frames where it actually appears. - - `def test_mask_ids_missing_boundary_labels_falls_back(self, tmp_path)` (line 562): Mesh without boundary_labels array falls back to a 'default' prim. - - `def test_mask_ids_groups_by_segmenter_type(self, tmp_path)` (line 577): When a segmenter is supplied, labels are grouped under their - -## tests/test_download_data_cli.py - -- `def test_download_data_cli_uses_default_dataset_and_directory(monkeypatch, capsys)` (line 14): Default CLI arguments route Slicer-Heart-CT to data/Slicer-Heart-CT. -- `def test_download_data_cli_uses_requested_directory(monkeypatch, tmp_path)` (line 34): The --directory option controls where Slicer-Heart-CT is stored. - -## tests/test_download_heart_data.py - -- **class TestDataDownloadTools** (line 16): Synthetic tests for dataset verification helpers. - - `def test_verify_slicer_heart_ct_data(self, tmp_path)` (line 19): Verify Slicer data by expected `TruncalValve_4DCT.seq.nrrd` filename. - - `def test_verify_kcl_heart_model_data(self, tmp_path)` (line 29): Verify KCL data by expected average mesh and input mesh filenames. - - `def test_verify_dirlab_4dct_data(self, tmp_path)` (line 41): Verify DirLab data by supported Case1 phase image layouts. - - `def test_verify_chop_valve_4d_data(self, tmp_path)` (line 52): Verify CHOP data by expected CT or valve time-series paths. -- **class TestDownloadHeartData** (line 63): Test suite for downloading and converting Slicer-Heart-CT data. - - `def test_directories_created(self, test_directories)` (line 66): Test that directories are created successfully. - - `def test_data_downloaded(self, download_test_data, test_directories)` (line 90): Test that the TruncalValve 4D CT data file is downloaded. - -## tests/test_experiments.py - -- `def get_scripts_in_subdir(subdir_name)` (line 56): Get all Python scripts in a subdirectory, sorted alphanumerically. -- `def execute_script(script_path, timeout=3600)` (line 74): Execute a Python experiment script. -- `def run_experiment_scripts(subdir_name, timeout_per_script=3600)` (line 176): Run all Python scripts in an experiment subdirectory in alphanumeric order. -- `def test_experiment_colormap_vtk_to_usd()` (line 297): Test Colormap-VTK_To_USD experiment scripts. -- `def test_experiment_reconstruct_4dct()` (line 329): Test Reconstruct4DCT experiment scripts. -- `def test_experiment_heart_vtk_series_to_usd()` (line 346): Test Heart-VTKSeries_To_USD experiment scripts. -- `def test_experiment_heart_gated_ct_to_usd()` (line 365): Test Heart-GatedCT_To_USD experiment scripts. -- `def test_experiment_convert_vtk_to_usd()` (line 387): Test Convert_VTK_To_USD experiment scripts. -- `def test_experiment_create_statistical_model()` (line 405): Test Heart-Create_Statistical_Model experiment scripts. -- `def test_experiment_heart_statistical_model_to_patient()` (line 428): Test Heart-Statistical_Model_To_Patient experiment scripts. -- `def test_experiment_lung_gated_ct_to_usd()` (line 461): Test Lung-GatedCT_To_USD experiment scripts. -- `def test_experiment_structure()` (line 505): Validate the structure of the experiments directory. -- `def test_list_scripts_in_subdir(subdir_name)` (line 559): List all scripts in each experiment subdirectory. - -## tests/test_image_tools.py - -- **class TestImageTools** (line 22): Test suite for ImageTools conversions. - - `def image_tools(self)` (line 26): Create ImageTools instance. - - `def test_itk_to_sitk_scalar_image(self, image_tools)` (line 30): Test conversion of scalar ITK image to SimpleITK. - - `def test_sitk_to_itk_scalar_image(self, image_tools)` (line 65): Test conversion of scalar SimpleITK image to ITK. - - `def test_roundtrip_scalar_image(self, image_tools)` (line 97): Test roundtrip conversion: ITK -> SimpleITK -> ITK. - - `def test_itk_to_sitk_vector_image(self, image_tools)` (line 133): Test conversion of vector ITK image to SimpleITK. - - `def test_sitk_to_itk_vector_image(self, image_tools)` (line 171): Test conversion of vector SimpleITK image to ITK. - - `def test_roundtrip_vector_image(self, image_tools)` (line 202): Test roundtrip conversion for vector images: ITK -> SimpleITK -> ITK. - - `def test_imwrite_imread_vd3(self, image_tools, test_transforms, test_images, test_directories)` (line 240): Test reading and writing double precision vector images. -- **class TestFlipImage** (line 333): Unit tests for ImageTools.flip_image (axis flips and direction reset). - - `def image_tools(self)` (line 337) - - `def test_flip_x_flips_along_last_array_axis(self, image_tools)` (line 340): flip_x flips the image along the x (last) array dimension. - - `def test_flip_y_flips_along_middle_array_axis(self, image_tools)` (line 353): flip_y flips the image along the y (middle) array dimension. - - `def test_flip_z_flips_along_first_array_axis(self, image_tools)` (line 367): flip_z flips the image along the z (first) array dimension. - - `def test_flip_xy_combines_flips(self, image_tools)` (line 379): flip_x and flip_y together flip both axes. - - `def test_no_flip_returns_same_image(self, image_tools)` (line 389): With no flip flags, image is returned unchanged. - - `def test_mask_flipped_in_lockstep_with_image(self, image_tools)` (line 400): When a mask is provided, it is flipped with the same axes as the image. - - `def test_flip_and_make_identity_sets_direction_to_identity(self, image_tools)` (line 421): flip_and_make_identity flips as needed and sets direction matrix to identity. - - `def test_flip_and_make_identity_with_mask_sets_both_directions_to_identity(self, image_tools)` (line 437): With mask and flip_and_make_identity, both image and mask get identity direction. - -## tests/test_import_public_api.py - -- `def test_public_api_exports_are_importable()` (line 9): Every name in physiomotion4d.__all__ resolves from the package. - -## tests/test_register_images_ants.py - -- **class TestRegisterImagesANTS** (line 24): Test suite for ANTs-based image registration. - - `def test_registrar_initialization(self, registrar_ANTS)` (line 27): Test that RegisterImagesANTS initializes correctly. - - `def test_set_modality(self, registrar_ANTS)` (line 35): Test setting imaging modality. - - `def test_set_fixed_image(self, registrar_ANTS, test_images)` (line 45): Test setting fixed image. - - `def test_register_without_mask(self, registrar_ANTS, test_images, test_directories)` (line 58): Test basic registration without masks. - - `def test_register_with_mask(self, registrar_ANTS, test_images, test_directories)` (line 112): Test registration with binary masks. - - `def test_transform_application(self, registrar_ANTS, test_images, test_directories)` (line 205): Test applying registration transforms to images. - - `def test_preprocess_images(self, registrar_ANTS, test_images)` (line 259): Test image preprocessing. - - `def test_registration_with_initial_transform(self, registrar_ANTS, test_images, test_directories)` (line 277): Test registration with initial transform. - - `def test_multiple_registrations(self, registrar_ANTS, test_images)` (line 312): Test running multiple registrations in sequence. - - `def test_transform_types(self, registrar_ANTS, test_images)` (line 340): Test that transforms are correct ITK types. - - `def test_image_conversion_cycle_scalar(self, registrar_ANTS, test_images)` (line 368): Test round-trip conversion: ITK image -> ANTs -> ITK for scalar images. - - `def test_image_conversion_cycle_different_dtypes(self, registrar_ANTS, test_images)` (line 444): Test round-trip conversion with different data types. - - `def test_image_conversion_preserves_metadata(self, registrar_ANTS)` (line 476): Test that image conversion preserves all metadata. - - `def test_transform_conversion_cycle_affine(self, registrar_ANTS, test_images)` (line 523): Test round-trip conversion: ITK affine transform -> ANTs -> ITK. - - `def test_transform_conversion_cycle_displacement_field(self, registrar_ANTS, test_images)` (line 629): Test round-trip conversion: ITK displacement field -> ANTs -> ITK. - - `def test_transform_conversion_with_composite(self, registrar_ANTS, test_images)` (line 713): Test conversion of composite transforms. - -## tests/test_register_images_greedy.py - -- **class TestRegisterImagesGreedy** (line 21): Test suite for Greedy-based image registration. - - `def test_registrar_initialization(self, registrar_greedy)` (line 24): Test that RegisterImagesGreedy initializes correctly. - - `def test_set_modality(self, registrar_greedy)` (line 34): Test setting imaging modality. - - `def test_set_transform_type_and_metric(self, registrar_greedy)` (line 44): Test setting transform type and metric. - - `def test_set_fixed_image(self, registrar_greedy, test_images)` (line 71): Test setting fixed image. - - `def test_register_affine_without_mask(self, registrar_greedy, test_images, test_directories)` (line 82): Test affine registration without masks. - - `def test_register_affine_with_mask(self, registrar_greedy, test_images, test_directories)` (line 127): Test affine registration with binary masks. - - `def test_transform_application(self, registrar_greedy, test_images, test_directories)` (line 187): Test applying registration transform to moving image. - -## tests/test_register_images_icon.py - -- **class TestRegisterImagesICON** (line 23): Test suite for ICON-based image registration. - - `def test_registrar_initialization(self, registrar_ICON)` (line 26): Test that RegisterImagesICON initializes correctly. - - `def test_set_modality(self, registrar_ICON)` (line 39): Test setting imaging modality. - - `def test_set_number_of_iterations(self, registrar_ICON)` (line 49): Test setting number of iterations. - - `def test_set_fixed_image(self, registrar_ICON, test_images)` (line 61): Test setting fixed image. - - `def test_set_mass_preservation(self, registrar_ICON)` (line 74): Test setting mass preservation flag. - - `def test_set_multi_modality(self, registrar_ICON)` (line 86): Test setting multi-modality flag. - - `def test_register_without_mask(self, registrar_ICON, test_images, test_directories)` (line 96): Test basic ICON registration without masks. - - `def test_register_with_mask(self, registrar_ICON, test_images, test_directories)` (line 151): Test ICON registration with binary masks. - - `def test_transform_application(self, registrar_ICON, test_images, test_directories)` (line 245): Test applying ICON registration transforms to images. - - `def test_inverse_consistency(self, registrar_ICON, test_images)` (line 299): Test ICON's inverse consistency property. - - `def test_preprocess_images(self, registrar_ICON, test_images)` (line 345): Test image preprocessing for ICON. - - `def test_registration_with_initial_transform(self, registrar_ICON, test_images, test_directories)` (line 363): Test ICON registration with initial transform. - - `def test_transform_types(self, registrar_ICON, test_images)` (line 399): Test that ICON transforms are correct ITK types. - - `def test_different_iteration_counts(self, registrar_ICON, test_images)` (line 440): Test ICON with different iteration counts. - -## tests/test_register_models_pca.py - -- `def test_itk_template_points_are_distinct_objects()` (line 39): Cached ITK points are distinct per template vertex. -- `def test_set_fixed_model_requires_reference_image()` (line 53): set_fixed_model fails clearly when reference_image is None. -- `def test_transform_template_model_applies_post_pca_transform_after_deformation()` (line 63): Post-PCA transform is applied after PCA deformation. - -## tests/test_register_time_series_images.py - -- **class TestRegisterTimeSeriesImages** (line 24): Test suite for time series image registration. - - `def test_registrar_initialization_ANTS(self)` (line 29): Test that RegisterTimeSeriesImages initializes correctly with ANTs. - - `def test_registrar_initialization_ICON(self)` (line 43): Test that RegisterTimeSeriesImages initializes correctly with ICON. - - `def test_registrar_initialization_greedy(self)` (line 57): Test that RegisterTimeSeriesImages initializes correctly with Greedy. - - `def test_registrar_initialization_invalid_method(self)` (line 73): Test that invalid registration method raises error. - - `def test_set_modality(self)` (line 80): Test setting imaging modality. - - `def test_set_fixed_image(self, test_images)` (line 88): Test setting fixed image. - - `def test_set_number_of_iterations(self)` (line 99): Test setting number of iterations. - - `def test_register_time_series_basic(self, test_images, test_directories)` (line 127): Test basic time series registration without prior transform. - - `def test_register_time_series_with_prior(self, test_images, test_directories)` (line 209): Test time series registration with prior transform usage. - - `def test_register_time_series_identity_start(self, test_images)` (line 270): Test time series registration with identity for starting image. - - `def test_register_time_series_different_starting_indices(self, test_images)` (line 296): Test time series registration with different starting indices. - - `def test_register_time_series_error_no_fixed_image(self)` (line 326): Test that error is raised if fixed image not set. - - `def test_register_time_series_error_invalid_starting_index(self, test_images)` (line 337): Test that error is raised for invalid starting index. - - `def test_register_time_series_error_invalid_prior_portion(self, test_images)` (line 360): Test that error is raised for invalid prior portion value. - - `def test_transform_application_time_series(self, test_images, test_directories)` (line 385): Test applying transforms from time series registration. - - `def test_register_time_series_ICON(self, test_images)` (line 437): Test time series registration with ICON method. - - `def test_register_time_series_with_mask(self, test_images, test_directories)` (line 462): Test time series registration with fixed image mask. - - `def test_bidirectional_registration(self, test_images)` (line 507): Test that bidirectional registration works correctly. - -## tests/test_segment_chest_total_segmentator.py - -- **class TestSegmentChestTotalSegmentator** (line 21): Test suite for TotalSegmentator chest CT segmentation. - - `def test_segmenter_initialization(self, segmenter_total_segmentator)` (line 24): Test that SegmentChestTotalSegmentator initializes correctly. - - `def test_segment_single_image(self, segmenter_total_segmentator, test_images, test_directories)` (line 55): Test segmentation on a single time point. - - `def test_segment_multiple_images(self, segmenter_total_segmentator, test_images, test_directories)` (line 113): Test segmentation on two time points. - - `def test_anatomy_group_masks(self, segmenter_total_segmentator, test_images)` (line 144): Test that anatomy group masks are created correctly. - - `def test_contrast_detection(self, segmenter_total_segmentator, test_images)` (line 188): Test contrast detection functionality. - - `def test_preprocessing(self, segmenter_total_segmentator, test_images)` (line 219): Test preprocessing functionality. - - `def test_postprocessing(self, segmenter_total_segmentator, test_images)` (line 243): Test postprocessing functionality. - -## tests/test_segment_heart_simpleware.py - -- **class TestSegmentHeartSimpleware** (line 33): Test suite for SegmentHeartSimpleware (Simpleware Medical ASCardio). - - `def test_segmenter_initialization(self, segmenter_simpleware)` (line 36): Test that SegmentHeartSimpleware initializes correctly. - - `def test_set_simpleware_executable_path(self, segmenter_simpleware)` (line 69): Test setting custom Simpleware executable path. - - `def test_segment_single_image(self, segmenter_simpleware, test_images, test_directories)` (line 82): Test segmentation on a cardiac CT time point. - - `def test_anatomy_group_masks(self, segmenter_simpleware, test_images)` (line 146): Test that anatomy group masks are created (heart, vessels, etc.). - - `def test_contrast_detection(self, segmenter_simpleware, test_images)` (line 183): Test contrast mask is returned (base class behavior). - - `def test_postprocessing(self, segmenter_simpleware, test_images)` (line 199): Test that output labelmap matches input size and spacing. - -## tests/test_transform_tools.py - -- **class TestTransformTools** (line 23): Test suite for TransformTools functionality. - - `def test_contour(self, test_images)` (line 27): Create a simple test contour mesh. - - `def test_transform_tools_initialization(self, transform_tools)` (line 33): Test that TransformTools initializes correctly. - - `def test_transform_image_linear(self, transform_tools, test_transforms, test_images, test_directories)` (line 40): Test transforming image with linear interpolation. - - `def test_transform_image_nearest(self, transform_tools, test_transforms, test_images, test_directories)` (line 80): Test transforming image with nearest neighbor interpolation. - - `def test_transform_image_sinc(self, transform_tools, test_transforms, test_images, test_directories)` (line 114): Test transforming image with sinc interpolation. - - `def test_transform_image_invalid_method(self, transform_tools, test_transforms, test_images)` (line 148): Test that invalid interpolation method raises error. - - `def test_transform_pvcontour_without_deformation(self, transform_tools, test_contour, test_transforms)` (line 171): Test transforming PyVista contour without deformation magnitude. - - `def test_transform_pvcontour_with_deformation(self, transform_tools, test_contour, test_transforms, test_directories)` (line 206): Test transforming PyVista contour with deformation magnitude. - - `def test_transform_dataset_preserves_unstructured_grid_topology(self, transform_tools)` (line 249): Transform UnstructuredGrid points with image shape (Z, Y, X) = (3, 3, 3). - - `def test_convert_transform_to_displacement_field(self, transform_tools, test_transforms, test_images, test_directories)` (line 286): Test converting transform to deformation field image. - - `def test_convert_vtk_matrix_to_itk_transform(self, transform_tools)` (line 327): Test converting VTK matrix to ITK transform. - - `def test_compute_jacobian_determinant_from_field(self, transform_tools, test_transforms, test_images, test_directories)` (line 359): Test computing Jacobian determinant from deformation field. - - `def test_detect_folding_in_field(self, transform_tools, test_transforms, test_images)` (line 410): Test detecting spatial folding in deformation field. - - `def test_interpolate_transforms(self, transform_tools, test_transforms, test_images)` (line 440): Test temporal interpolation between transforms. - - `def test_combine_displacement_field_transforms(self, transform_tools, test_transforms, test_images)` (line 477): Test composing two transforms with various weights. - - `def test_smooth_transform(self, transform_tools, test_transforms, test_images)` (line 591): Test smoothing a transform. - - `def test_combine_transforms_with_masks(self, transform_tools, test_transforms, test_images)` (line 617): Test combining transforms with spatial masks. - - `def test_multiple_transform_applications(self, transform_tools, test_transforms, test_images)` (line 664): Test applying multiple transforms in sequence. - - `def test_identity_transform(self, transform_tools, test_images)` (line 692): Test that identity transform doesn't change the image. - -## tests/test_tutorials.py - -- **class TestTutorial01HeartGatedCTToUSD** (line 78): End-to-end test for tutorial_01_heart_gated_ct_to_usd.py. - - `def test_run(self, test_directories)` (line 83) -- **class TestTutorial02CTToVTK** (line 105): End-to-end test for tutorial_02_ct_to_vtk.py. - - `def test_run(self, test_directories)` (line 110) -- **class TestTutorial03CreateStatisticalModel** (line 131): End-to-end test for tutorial_03_create_statistical_model.py. - - `def test_run(self, test_directories)` (line 136) -- **class TestTutorial04FitStatisticalModelToPatient** (line 158): End-to-end test for tutorial_04_fit_statistical_model_to_patient.py. - - `def test_run(self, test_directories)` (line 163) -- **class TestTutorial05VTKToUSD** (line 201): End-to-end test for tutorial_05_vtk_to_usd.py. - - `def test_run(self, test_directories)` (line 206) -- **class TestTutorial06ReconstructHighres4DCT** (line 241): End-to-end test for tutorial_06_reconstruct_highres_4d_ct.py. - - `def test_run(self, test_directories)` (line 246) - -## tests/test_usd_merge.py - -- `def analyze_usd_file(filepath)` (line 17): Analyze a USD file for materials and time samples. -- **class TestUSDMerge** (line 72): Test suite for USD file merging. - - `def test_data_files(self)` (line 76): Locate test USD files with materials and time-varying data. - - `def output_dir(self, tmp_path_factory)` (line 91): Create temporary output directory for test results. - - `def input_stats(self, test_data_files)` (line 97): Analyze input USD files. - - `def test_merge_usd_files_copy_method(self, test_data_files, input_stats, output_dir)` (line 103): Test merge_usd_files() manual copy method. - - `def test_merge_usd_files_flattened_method(self, test_data_files, input_stats, output_dir)` (line 164): Test merge_usd_files_flattened() composition method. - - `def test_both_methods_produce_equivalent_results(self, test_data_files, output_dir)` (line 225): Verify both merge methods produce equivalent results. - -## tests/test_usd_time_preservation.py - -- `def get_time_metadata(filepath)` (line 17): Extract time metadata from a USD file. -- `def get_mesh_time_samples(filepath, mesh_name='inferior_vena_cava')` (line 41): Get time sample data for a specific mesh in a USD file. -- **class TestUSDTimePreservation** (line 87): Test suite for USD time-varying data preservation. - - `def test_data_files(self)` (line 91): Locate test USD files with time-varying data. - - `def output_dir(self, tmp_path_factory)` (line 106): Create temporary output directory for test results. - - `def source_metadata(self, test_data_files)` (line 112): Get time metadata from source file. - - `def source_time_samples(self, test_data_files)` (line 117): Get time sample data from source file. - - `def test_merge_copy_preserves_time_metadata(self, test_data_files, source_metadata, output_dir)` (line 123): Test that merge_usd_files() preserves time metadata. - - `def test_merge_flattened_preserves_time_metadata(self, test_data_files, source_metadata, output_dir)` (line 155): Test that merge_usd_files_flattened() preserves time metadata. - - `def test_merge_copy_preserves_time_samples(self, test_data_files, source_time_samples, output_dir)` (line 187): Test that merge_usd_files() preserves actual time sample data. - - `def test_merge_flattened_preserves_time_samples(self, test_data_files, source_time_samples, output_dir)` (line 228): Test that merge_usd_files_flattened() preserves actual time sample data. - - `def test_animation_range_matches_actual_motion(self, test_data_files, source_time_samples, output_dir)` (line 269): Test that the full animation range is accessible. - -## tests/test_vtk_to_usd_library.py - -- `def get_data_dir()` (line 27): Get the data directory path. -- `def check_kcl_heart_data()` (line 34): Check if KCL Heart Model data is available. -- `def get_or_create_average_surface(test_directories)` (line 41): Get or create average_surface.vtp from average_mesh.vtk. -- `def kcl_average_surface(test_directories)` (line 68): Fixture providing the KCL average heart surface. -- **class TestFromFilesValidation** (line 81): Synthetic tests for ConvertVTKToUSD.from_files(). - - `def test_time_codes_length_mismatch_raises(self, tmp_path)` (line 84): from_files() must reject time_codes whose length != len(vtk_files). - - `def test_time_codes_non_monotone_raises(self, tmp_path)` (line 94): from_files() must reject time_codes that decrease between frames. - - `def test_time_codes_equal_consecutive_is_valid(self, tmp_path)` (line 104): Equal consecutive time codes are non-decreasing and must not raise. - - `def test_from_files_single_file_writes_static_mesh(self, tmp_path)` (line 116): A single-file converter writes a static mesh with no time range. - - `def test_openusd_screenshot_uses_vtk_loader(self, tmp_path)` (line 128): Render a tiny OpenUSD mesh through TestTools without USD imaging plugins. - - `def test_from_files_static_merge_writes_separate_meshes(self, tmp_path)` (line 168): static_merge=True treats files as static objects, not time samples. -- **class TestSyntheticConversion** (line 187): Synthetic ConvertVTKToUSD tests that do not require downloaded data. - - `def test_inspect_file_reports_public_summary(self, tmp_path)` (line 190): inspect_file() reports geometry, bounds, arrays, and cell types. - - `def test_inspect_file_reports_empty_mesh(self, tmp_path)` (line 210): inspect_file() reports empty meshes without raising. - - `def test_file_primvar_preservation(self, tmp_path)` (line 226): Point arrays in a VTP file are preserved as USD primvars. - - `def test_time_series_conversion(self, tmp_path)` (line 245): Multiple VTP files write point time samples and stage time metadata. -- **class TestVTKToUSDConversion** (line 268): Test ConvertVTKToUSD on optional real VTK data. - - `def test_single_file_conversion(self, test_directories, kcl_average_surface)` (line 271): Test converting a single VTK file to USD. - - `def test_conversion_with_material(self, test_directories, kcl_average_surface)` (line 290): Test conversion with a custom solid color material. - - `def test_conversion_settings(self, test_directories, kcl_average_surface)` (line 318): Test that ConvertVTKToUSD applies correct default stage metadata. -- **class TestIntegration** (line 335): Integration tests combining multiple features. - - `def test_end_to_end_conversion(self, test_directories, kcl_average_surface)` (line 338): Test complete conversion workflow with all features. -- **class TestUnitScaling** (line 361): Verify that VTK mm coordinates are converted to USD meter coordinates. - - `def test_mm_to_m_point_scaling(self, tmp_path)` (line 364): Points written to USD must be 0.001x their original mm values. - - `def test_normals_remain_unit_length(self, tmp_path)` (line 384): Normal vectors must not be scaled. - - `def test_stage_meters_per_unit(self, tmp_path)` (line 404): Stage metersPerUnit metadata must be 1.0. - -## tests/test_workflow_convert_image_to_usd.py - -- `def test_create_usd_files_passes_times_per_second(monkeypatch, tmp_path)` (line 14): Workflow forwards FPS to VTK-to-USD for shape (X, Y, Z, T) outputs. - -## tests/test_workflow_fine_tune_icon_registration.py - -- `def two_subject_dataset(tmp_path)` (line 43): Two patients, two frames each, with matching labelmaps on disk. -- `def test_init_requires_output_dir_and_name(tmp_path)` (line 80): output_dir and fine_tune_name are required positional args. -- `def test_init_rejects_empty_image_files(tmp_path)` (line 88): Empty subject list raises immediately. -- `def test_init_rejects_mismatched_companion_lengths(tmp_path)` (line 98): Mask/seg/landmark lists must match subject_image_files shape exactly. -- `def test_init_rejects_duplicate_subject_ids(tmp_path)` (line 109): Duplicate subject IDs collapse paired groups, so reject them up front. -- `def test_init_rejects_mismatched_subject_ids_length(tmp_path)` (line 120): subject_ids must have one entry per subject. -- `def test_uses_segmentations_and_uses_masks_flags(tmp_path)` (line 131): The two helper flags reflect supplied companions independently. -- `def test_create_mask_thresholds_and_dilates()` (line 160): Single-voxel labelmap becomes a binary mask whose dilation grows it. -- `def test_prepare_dataset_uses_real_subject_ids(two_subject_dataset)` (line 185): Subject IDs round-trip from the caller into every dataset entry. -- `def test_prepare_dataset_skips_frames_with_missing_segmentation(tmp_path)` (line 207): A frame with no seg available is dropped when use_label is required. -- `def test_prepare_dataset_uses_explicit_mask_over_derived(tmp_path)` (line 234): When subject_mask_files supplies a mask, it overrides the derived one. -- `def test_prepare_dataset_mask_only_no_segmentations(tmp_path)` (line 263): Mask-only input: entries have ``mask`` but no ``segmentation`` field. -- `def test_prepare_dataset_derives_mask_next_to_labelmap_by_default(two_subject_dataset)` (line 286): Derived masks land next to each labelmap when ``mask_dir`` is not set. -- `def test_prepare_dataset_derives_mask_under_explicit_mask_dir(two_subject_dataset, tmp_path)` (line 312): Explicit ``mask_dir`` collects every derived mask in that single folder. -- `def test_prepare_dataset_raises_on_missing_image_file(tmp_path)` (line 336): Image existence is a hard requirement; missing image aborts the build. -- `def test_prepare_config_emits_uniGradICON_yaml(two_subject_dataset)` (line 353): YAML config matches uniGradICON's expected structure when seg is present. -- `def test_prepare_config_flags_off_when_no_companions(tmp_path)` (line 390): Without seg or mask, ``use_label`` and ``loss_function_masking`` are False. -- `def test_prepare_config_requires_dataset_json(tmp_path)` (line 411): Calling prepare_config without first preparing the dataset is an error. -- `def test_expected_weights_path_layout(tmp_path)` (line 428): Weights land at ``output_dir//_model/checkpoints/...``. -- `def test_run_fine_tuning_invokes_unigradicon_subprocess(monkeypatch, two_subject_dataset)` (line 447): run_fine_tuning launches the uniGradICON finetune module with the YAML path. -- `def test_run_fine_tuning_without_unigradicon_src(monkeypatch, two_subject_dataset)` (line 489): When unigradicon_src_path is None, PYTHONPATH is not prefixed. -- `def test_apply_registration_rejects_empty_moving(tmp_path)` (line 519): apply_registration validates inputs before touching the registrar. -- `def test_apply_registration_rejects_mismatched_companions(tmp_path)` (line 533): moving_segmentations / moving_landmarks length must match moving_images. - -## tests/test_workflow_fit_statistical_model_to_patient.py - -- `def test_auto_generate_mask_accumulates_multilabel_models(monkeypatch)` (line 19): Multi-model masks accumulate label IDs instead of overwriting prior labels. -- `def test_transform_model_applies_staged_transform()` (line 64): Transform helper updates mesh points with image shape (Z, Y, X) = (3, 3, 3). -- `def test_fit_workflow_default_segmentation_method_is_trimmed_branches()` (line 96): Default segmentation_method must match the KCL-Heart-Model fit contract. -- `def test_fit_workflow_routes_default_to_image_to_vtk_with_trimmed_branches(monkeypatch)` (line 106): When patient_models is omitted, the workflow must invoke -- `def test_image_to_vtk_segmenter_dispatch_for_trimmed_branches()` (line 163): WorkflowConvertImageToVTK('HeartSimplewareTrimmedBranches') must -- `def test_transform_model_preserves_unstructured_grid_topology()` (line 180): Transform helper preserves cells with image shape (Z, Y, X) = (3, 3, 3). - -## utils/ai_agent_github_reviews.py - -- `def git_fetch(repo_root, remote, branch)` (line 71): Run ``git fetch ``, printing progress. -- `def get_repo_root()` (line 85) -- `def get_repo_slug(repo_root)` (line 99): Derive owner/repo from the git remote URL (upstream, falling back to origin). -- `def parse_github_datetime(iso_str)` (line 124): Parse GitHub API timestamps (may end with Z). -- `def get_remote_reflog_cutoff(repo_root, remote, head_ref)` (line 140): Latest reflog time for refs/remotes// (when the ref last -- `def filter_since_cutoff(thread_comments, reviews, cutoff)` (line 180): Keep thread comments with created_at > cutoff and reviews with -- `def fetch_review_threads(pr_number, repo)` (line 394): Return all review threads for a PR via GraphQL, paginating both the -- `def fetch_pr_data(pr_number, repo)` (line 453) -- `def fetch_reviews(pr_number, repo)` (line 459) -- `def resolve_review_threads(thread_ids, repo)` (line 464): Mark each thread in *thread_ids* as resolved via the GitHub GraphQL API. -- `def build_prompt(pr_number, pr_data, reviews, thread_comments, summary_filename, agent, repo_root)` (line 580) -- `def invoke_ai_agent(prompt, repo_root, agent)` (line 712): Invoke the selected AI agent non-interactively. -- `def invoke_claude(prompt, repo_root)` (line 722): Invoke Claude Code non-interactively via stdin. -- `def invoke_codex(prompt, repo_root)` (line 754): Invoke Codex CLI non-interactively. -- `def parse_args()` (line 832) -- `def main()` (line 903) - -## utils/generate_api_map.py - -- `def first_docstring_line(node)` (line 47): Return the first non-empty line of a class or function docstring. -- `def format_arg(arg, default)` (line 65): Format one argument, appending ``=default`` when a default is present. -- `def format_signature(node)` (line 76): Reconstruct a readable signature string from an AST function node. -- `def is_public(name)` (line 104): Return True for public names; also allow ``__init__``. -- `def module_all_names(tree)` (line 109): Return the names listed in ``__all__`` if defined at module level, else None. -- **class MethodEntry** (line 130): A single public method within a class. - - `def __init__(self, signature, lineno, summary)` (line 135) -- **class ClassEntry** (line 141): A public class with its public methods. - - `def __init__(self, name, lineno, summary)` (line 146) -- **class FunctionEntry** (line 153): A public module-level function. - - `def __init__(self, signature, lineno, summary)` (line 158) -- **class ModuleEntry** (line 164): All public symbols extracted from one source file. - - `def __init__(self, rel_path)` (line 169) -- `def parse_module(path, root)` (line 180): Parse *path* and return a :class:`ModuleEntry`, or ``None`` on error / empty. -- `def find_python_files(root)` (line 234): Return sorted .py files under *root*, skipping non-source directories. -- `def render_markdown(modules)` (line 250): Render *modules* to a Markdown string. -- `def main()` (line 295) - -## utils/setup_feature_worktree.py - -- `def run(cmd, *, cwd=None, capture=False, description='')` (line 38): Run a command, raising on failure with a helpful message. -- `def require_tool(name)` (line 82): Ensure a tool is on PATH. Returns its resolved path. -- `def check_prerequisites()` (line 100): Check that git and py.exe are available on PATH. -- `def get_repo_root()` (line 119): Return the absolute path to the repository root. -- `def get_current_branch()` (line 140): Return the name of the currently checked-out branch. -- `def branch_exists(branch_name)` (line 162): Return True if a local branch with this name already exists. -- `def sanitize_name(raw)` (line 177): Convert a raw feature name into a safe branch name and folder name. -- `def create_worktree(worktree_path, branch_name, base_branch)` (line 219): Create a new git branch and worktree. -- `def create_venv(worktree_path, py_path)` (line 262): Create a virtual environment inside the worktree. -- `def install_uv(venv_dir)` (line 283): Install uv into the venv using pip. -- `def detect_dependency_mode(worktree_path)` (line 318): Auto-detect the best dependency installation mode for the project. -- `def install_dependencies(uv_exe, worktree_path, mode)` (line 339): Install project dependencies using uv. -- `def print_summary(branch_name, worktree_path, venv_dir)` (line 411): Print a formatted summary of the created worktree environment. -- `def parse_args()` (line 441): Parse and return command-line arguments. -- `def main()` (line 500): Main entry point for the worktree setup script. diff --git a/utils/setup_feature_worktree.py b/utils/setup_feature_worktree.py index 7dd86b5..c7a38bc 100644 --- a/utils/setup_feature_worktree.py +++ b/utils/setup_feature_worktree.py @@ -22,6 +22,7 @@ from __future__ import annotations import argparse +import os import re import shutil import subprocess @@ -97,13 +98,40 @@ def require_tool(name: str) -> str: return path +def require_no_active_venv() -> None: + """Abort if a virtual environment is active in the invoking shell or interpreter. + + The script creates a fresh per-worktree venv and runs ``uv pip install`` inside + it. uv honors the parent shell's ``VIRTUAL_ENV`` env var, so an active outer + venv silently hijacks the install and the new worktree's venv is left empty. + Refuse to run in that case and tell the user how to recover. + + Raises: + SystemExit: If ``VIRTUAL_ENV`` is set or this script is being run by a + venv's Python rather than the base interpreter. + """ + active_venv = os.environ.get("VIRTUAL_ENV") + running_in_venv = sys.prefix != getattr(sys, "base_prefix", sys.prefix) + + if active_venv or running_in_venv: + location = active_venv or sys.prefix + print("[ERROR] A Python virtual environment is currently active:") + print(f" {location}") + print() + print(" Deactivate it before running this script, then re-run.") + print(" PowerShell : deactivate") + print(" cmd.exe : venv\\Scripts\\deactivate.bat") + sys.exit(1) + + def check_prerequisites() -> tuple[str, str]: - """Check that git and py.exe are available on PATH. + """Check that git and py.exe are available on PATH and no venv is active. Returns: Tuple of (git_path, py_path). """ print("[*] Checking prerequisites...") + require_no_active_venv() git_path = require_tool("git") py_path = require_tool("py") print(f" git : {git_path}")