fullwave25 1.4.2.dev3__tar.gz → 1.4.2.dev4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (417) hide show
  1. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.bumpversion.toml +1 -1
  2. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/PKG-INFO +35 -7
  3. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/README.md +34 -6
  4. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/__init__.py +1 -1
  5. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/beamformer/beamformer.py +18 -9
  6. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/solver/input_file_writer.py +22 -5
  7. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/solver/solver.py +137 -14
  8. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/transducer.py +266 -50
  9. fullwave25-1.4.2.dev4/fullwave/ultra/attenuation_parameters.py +215 -0
  10. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/ultra/backend.py +85 -5
  11. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/ultra/backend_2d.py +45 -7
  12. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/ultra/binary.py +28 -1
  13. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/ultra/factory.py +4 -1
  14. fullwave25-1.4.2.dev4/fullwave/ultra/medium_to_aexp.py +167 -0
  15. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/ultra/writer_2d.py +54 -14
  16. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/ultra/writer_3d.py +54 -14
  17. fullwave25-1.4.2.dev4/fullwave/utils/signal_filter.py +126 -0
  18. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/pyproject.toml +1 -1
  19. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/uv.lock +1 -1
  20. fullwave25-1.4.2.dev3/fullwave/ultra/medium_to_aexp.py +0 -50
  21. fullwave25-1.4.2.dev3/fullwave/utils/signal_filter.py +0 -161
  22. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/.gitignore +0 -0
  23. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/20260911_1813_dead-code.md +0 -0
  24. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/20260916_1311_commit_message_of_the_input_generation_speedup.md +0 -0
  25. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/20260916_1311_pull_request_of_the_input_generation_speedup.md +0 -0
  26. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/20260916_1405_commit_message_of_the_relaxation_memory_estimate.md +0 -0
  27. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/20260916_1405_pull_request_of_the_relaxation_memory_estimate.md +0 -0
  28. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/20260916_2152_commit_message_of_the_cuda_version_choice.md +0 -0
  29. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/20260916_2152_pull_request_of_the_cuda_version_choice.md +0 -0
  30. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/20260916_2203_commit_message_of_the_cuda_version_tests.md +0 -0
  31. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/20260916_2213_commit_message_of_the_blackwell_version_choice.md +0 -0
  32. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/20260916_2213_pull_request_of_the_blackwell_version_choice.md +0 -0
  33. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/CLAUDE.md +0 -0
  34. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/matrix_imaging/20260909_1844_acquire_the_reflection_matrix.py +0 -0
  35. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/matrix_imaging/20260909_1900_test_on_a_synthetic_acquisition.py +0 -0
  36. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/matrix_imaging/20260909_1913_analyze_the_reflection_matrix.py +0 -0
  37. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/matrix_imaging/20260909_2107_redraw_the_figures_of_an_analysis.py +0 -0
  38. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/matrix_imaging/20260909_2121_write_the_result_tables.py +0 -0
  39. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/matrix_imaging/20260910_1126_synthesize_plane_waves_from_the_multistatic_matrix.py +0 -0
  40. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/matrix_imaging/20260910_1137_scan_the_speed_of_sound.py +0 -0
  41. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/matrix_imaging/20260910_1141_compare_the_laws_with_the_truth.py +0 -0
  42. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/matrix_imaging/20260910_1146_evaluate_the_reverberation_filter.py +0 -0
  43. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/matrix_imaging/20260910_1208_compare_plane_waves_with_the_synthesis.py +0 -0
  44. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/matrix_imaging/figures.py +0 -0
  45. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/matrix_imaging/ground_truth.py +0 -0
  46. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/matrix_imaging/matrix_imaging.py +0 -0
  47. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/matrix_imaging/pipeline.py +0 -0
  48. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/matrix_imaging/reflection_matrix.py +0 -0
  49. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/matrix_imaging/speed_of_sound.py +0 -0
  50. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/matrix_imaging/synthetic.py +0 -0
  51. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260821_0206_band_anchor_cross_check.py +0 -0
  52. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260821_0233_delivered_power_law_end_to_end.py +0 -0
  53. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260821_0317_reword_deliver_in_the_library.py +0 -0
  54. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260821_1220_relaxation_low_frequency_rolloff.py +0 -0
  55. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260825_1937_what_fails_the_pml_golden_tests.py +0 -0
  56. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260825_2329_does_the_wrapper_read_the_record.py +0 -0
  57. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260826_0002_what_the_new_default_table_holds.py +0 -0
  58. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260828_1422_what_the_candidate_tables_hold.py +0 -0
  59. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260828_1427_what_the_deployment_needs.py +0 -0
  60. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260828_1510_where_the_unstretched_ramp_reaches.py +0 -0
  61. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260828_1517_the_blast_radius_of_the_ramp.py +0 -0
  62. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260830_1458_the_3d_region_trimmed_kernel_against_the_reference.py +0 -0
  63. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260830_1505_the_multi_node_kernel_against_the_multi_gpu_one.py +0 -0
  64. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260830_1631_the_3d_multi_node_against_the_multi_gpu_one.py +0 -0
  65. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260830_1642_the_selective_absorbing_layer.py +0 -0
  66. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260830_1728_the_layer_against_the_taper.py +0 -0
  67. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260830_1757_what_the_margin_outside_the_layer_does.py +0 -0
  68. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260830_1808_the_layer_in_3d_and_on_the_multi_node_builds.py +0 -0
  69. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260830_1832_where_the_3d_residual_sits.py +0 -0
  70. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260830_1837_inside_the_layer_at_the_corner.py +0 -0
  71. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260830_1840_inside_the_3d_layer_at_the_corner.py +0 -0
  72. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260830_1912_both_absorbers_on_one_method.py +0 -0
  73. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260830_1922_the_layer_on_the_reflection_method.py +0 -0
  74. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260830_2011_whole_domain_animation.py +0 -0
  75. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260830_2032_the_example_source_kind.py +0 -0
  76. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260830_2148_drive_scale_of_the_strong_beta_cells.py +0 -0
  77. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260830_2159_profile_the_input_map_build.py +0 -0
  78. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260830_2201_build_then_extend_equivalence.py +0 -0
  79. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260830_2304_the_transmit_methods_launch_what_they_say.py +0 -0
  80. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260830_2322_the_unscaled_added_drive_follows_the_courant_number.py +0 -0
  81. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_0033_the_three_dimensional_arrays.py +0 -0
  82. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_0054_the_elevation_lens_of_a_linear_array.py +0 -0
  83. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_0115_run_every_example.sh +0 -0
  84. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_0124_move_the_notebooks_to_the_transmit_interface.py +0 -0
  85. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_0137_the_air_region_at_four_mechanisms.py +0 -0
  86. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_0148_the_element_records_its_own_transmit.py +0 -0
  87. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_0150_the_absorbing_layer_of_a_point_source.py +0 -0
  88. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_0152_the_exponential_absorbing_layer_against_its_thickness.py +0 -0
  89. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_0202_the_rebuilt_exponential_absorbing_layer.py +0 -0
  90. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_0216_where_the_three_dimensional_layer_leaks.py +0 -0
  91. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_0222_the_absorbing_layer_away_from_the_source.py +0 -0
  92. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_1037_where_the_near_field_brightness_comes_from.py +0 -0
  93. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_1040_the_aperture_transit_wedge_in_the_channel_data.py +0 -0
  94. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_1043_the_transmit_in_the_recorded_trace_and_its_removal.py +0 -0
  95. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_1048_the_receive_row_against_the_reference_subtraction.py +0 -0
  96. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_1052_the_backing_behind_the_array_face.py +0 -0
  97. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_1056_the_transmit_beam_with_the_air_backing.py +0 -0
  98. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_1105_the_shipped_transducer_stack_in_the_solver.py +0 -0
  99. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_1119_where_the_stack_puts_the_source_and_what_it_costs_the_depth.py +0 -0
  100. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_1121_the_depth_the_image_reads_with_the_stack.py +0 -0
  101. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_1123_the_depth_the_beamformer_puts_one_point_at.py +0 -0
  102. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_1142_the_transmit_offset_the_beamformer_needs.py +0 -0
  103. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_1145_the_depth_shift_the_offset_fix_makes.py +0 -0
  104. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_1154_the_two_offset_rules_on_the_same_recording.py +0 -0
  105. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_1212_what_the_pinned_release_carries.py +0 -0
  106. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_1228_the_low_cut_against_the_near_field_haze.py +0 -0
  107. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_1301_run_the_beamforming_notebooks.py +0 -0
  108. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_1432_point_dataset_generator_at_the_local_fullwave.py +0 -0
  109. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_1437_the_aperture_width_the_reference_geometry_reports.py +0 -0
  110. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_1454_calibrate_the_ats539_plane_wave.py +0 -0
  111. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_1508_show_the_b_mode_in_the_hdf5.py +0 -0
  112. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_1534_the_comet_behind_each_wire.py +0 -0
  113. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_1547_read_the_calibration_trials.py +0 -0
  114. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_1605_what_the_medium_holds_in_the_near_field.py +0 -0
  115. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_1607_sweep_one_generator_knob.py +0 -0
  116. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_1715_assert_the_ats539_rate_chain.py +0 -0
  117. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_1717_measure_every_layer_of_the_stack.py +0 -0
  118. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_1720_where_the_trailing_energy_lands.py +0 -0
  119. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_1725_offer_the_requested_absorption_to_the_backing.py +0 -0
  120. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_1727_let_a_sweep_carry_a_switch.py +0 -0
  121. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_1731_expose_the_exponential_absorbing_layer.py +0 -0
  122. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_1746_point_the_solver_at_an_older_binary.py +0 -0
  123. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_1756_measure_the_point_targets.py +0 -0
  124. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_1802_rederive_the_near_field_bounce.py +0 -0
  125. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_1810_does_the_shelf_move_with_depth.py +0 -0
  126. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_1812_find_the_repeat_delay_in_the_raw_rf.py +0 -0
  127. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_1937_give_each_source_row_its_own_launch_delay.py +0 -0
  128. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_1943_baffle_the_element_plane.py +0 -0
  129. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_1952_take_the_cell_size_from_the_grid.py +0 -0
  130. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_2058_run_the_ats539_through_the_batched_solver.py +0 -0
  131. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_2105_queue_the_remaining_candidates.py +0 -0
  132. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_2122_the_simulator_asks_for_a_clamped_source.py +0 -0
  133. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_2126_rename_the_source_types_to_hard_and_soft.py +0 -0
  134. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_2140_bind_the_source_type_to_its_entrance.py +0 -0
  135. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_2225_how_redundant_are_the_absorbing_layer_files.py +0 -0
  136. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_2239_skip_the_constant_absorbing_layer_maps.py +0 -0
  137. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_2246_count_the_files_a_run_writes.py +0 -0
  138. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_2352_run_the_map_tiers_end_to_end.py +0 -0
  139. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260831_2355_draw_the_absorbing_layer_map_cost.py +0 -0
  140. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260901_1502_can_the_transmit_reach_the_harmonic_band.py +0 -0
  141. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260901_1504_contrast_harmonic_imaging.py +0 -0
  142. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260901_1507_where_each_band_puts_its_largest_sample.py +0 -0
  143. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260901_1519_is_the_harmonic_tail_cumulative.py +0 -0
  144. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260901_1537_does_the_cancellation_work.py +0 -0
  145. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260901_1612_does_a_sparse_bubble_cloud_localize.py +0 -0
  146. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260901_1619_calibrate_the_bubble_scatter_range.py +0 -0
  147. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260901_1622_draw_the_sweep_b_modes.py +0 -0
  148. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260901_1654_where_the_bright_region_sits.py +0 -0
  149. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260901_1701_where_one_bubble_images.py +0 -0
  150. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260901_1702_does_the_portable_example_reproduce_the_evaluation.py +0 -0
  151. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260901_1753_does_the_ported_solver_still_march_the_same.py +0 -0
  152. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260901_1755_do_the_ranks_agree_on_the_bubbles.py +0 -0
  153. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260901_1817_does_the_air_region_reach_every_solver.py +0 -0
  154. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260901_1818_does_the_air_region_reach_every_rank.py +0 -0
  155. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260902_1317_what_the_abdomen_volume_holds.py +0 -0
  156. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260902_1319_art_wave_in_the_abdomen.py +0 -0
  157. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260902_1324_art_figures_from_the_field.py +0 -0
  158. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260902_1744_art_final_animations.py +0 -0
  159. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260904_1216_art_wire_visibility.py +0 -0
  160. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260904_2327_b_mode_of_the_abdomen.py +0 -0
  161. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260905_0038_two_against_three_dimensions.py +0 -0
  162. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260909_1934_probe_the_reverberation_filter_on_speckle.py +0 -0
  163. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260909_1939_probe_the_ideal_profile_on_speckle.py +0 -0
  164. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260909_2044_probe_the_correction_bases_on_a_flat_speckle.py +0 -0
  165. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260909_2342_measure_the_wall_delay_screen.py +0 -0
  166. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1134_find_the_first_non_finite_value_of_the_plane_wave_correction.py +0 -0
  167. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1234_print_the_summaries_of_analyses.py +0 -0
  168. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/a_maps_checks.py +0 -0
  169. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/b_effective_frequency.py +0 -0
  170. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/c_composed_steps.py +0 -0
  171. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/check_element_centers.py +0 -0
  172. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/check_plane_wave_law.py +0 -0
  173. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/d2_gate_quarter_period.py +0 -0
  174. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/d_gate_cases.py +0 -0
  175. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/e_plate_crash.py +0 -0
  176. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/f_patch_grid.py +0 -0
  177. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/g_frequency_scan.py +0 -0
  178. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/gouy_check.py +0 -0
  179. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/h_pulse_and_wires.py +0 -0
  180. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/i_phase_slope.py +0 -0
  181. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_2a8c46c5-7d0_a0200910_001.sh +0 -0
  182. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_2a8c46c5-7d0_a0200910_002.sh +0 -0
  183. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_2a8c46c5-7d0_a0200910_003.sh +0 -0
  184. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_2a8c46c5-7d0_a0200910_004.sh +0 -0
  185. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_2a8c46c5-7d0_a0200910_005.sh +0 -0
  186. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_2a8c46c5-7d0_a16f7afd_001.sh +0 -0
  187. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_2a8c46c5-7d0_a16f7afd_002.sh +0 -0
  188. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_2a8c46c5-7d0_a16f7afd_003.sh +0 -0
  189. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_2a8c46c5-7d0_a16f7afd_004.sh +0 -0
  190. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_2a8c46c5-7d0_a16f7afd_005.sh +0 -0
  191. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_2a8c46c5-7d0_a16f7afd_006.sh +0 -0
  192. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_2a8c46c5-7d0_a16f7afd_007.sh +0 -0
  193. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_2a8c46c5-7d0_a16f7afd_008.sh +0 -0
  194. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_2a8c46c5-7d0_a16f7afd_009.sh +0 -0
  195. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_2a8c46c5-7d0_a16f7afd_010.sh +0 -0
  196. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_2a8c46c5-7d0_a3e03828_001.sh +0 -0
  197. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_2a8c46c5-7d0_a3e03828_002.sh +0 -0
  198. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_2a8c46c5-7d0_a3e03828_003.sh +0 -0
  199. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_2a8c46c5-7d0_a3e03828_004.sh +0 -0
  200. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_2a8c46c5-7d0_a3e03828_005.sh +0 -0
  201. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_2a8c46c5-7d0_a86c0b02_001.sh +0 -0
  202. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_2a8c46c5-7d0_a86c0b02_002.sh +0 -0
  203. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_2a8c46c5-7d0_a86c0b02_003.sh +0 -0
  204. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_2a8c46c5-7d0_a86c0b02_004.sh +0 -0
  205. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_2a8c46c5-7d0_a86c0b02_005.sh +0 -0
  206. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_2a8c46c5-7d0_a86c0b02_006.sh +0 -0
  207. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_2a8c46c5-7d0_a86c0b02_007.sh +0 -0
  208. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_2a8c46c5-7d0_a86c0b02_008.sh +0 -0
  209. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_47c5d913-2f0_a86c7568_001.sh +0 -0
  210. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_714887dd-b46_a09af998_001.sh +0 -0
  211. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_714887dd-b46_a09af998_002.sh +0 -0
  212. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_714887dd-b46_a09af998_003.sh +0 -0
  213. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_714887dd-b46_a09af998_004.sh +0 -0
  214. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_714887dd-b46_a09af998_005.sh +0 -0
  215. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_714887dd-b46_a09af998_006.sh +0 -0
  216. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_714887dd-b46_a09af998_007.sh +0 -0
  217. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_714887dd-b46_a09af998_008.sh +0 -0
  218. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_714887dd-b46_a09af998_009.sh +0 -0
  219. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_714887dd-b46_a3c684a5_001.sh +0 -0
  220. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_714887dd-b46_a3c684a5_002.sh +0 -0
  221. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_714887dd-b46_a3c684a5_003.sh +0 -0
  222. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_714887dd-b46_a3c684a5_004.sh +0 -0
  223. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_714887dd-b46_a3c684a5_005.sh +0 -0
  224. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_714887dd-b46_a3c684a5_006.sh +0 -0
  225. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_714887dd-b46_a3c684a5_007.sh +0 -0
  226. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_714887dd-b46_a99b1764_001.sh +0 -0
  227. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_714887dd-b46_a99b1764_002.sh +0 -0
  228. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_714887dd-b46_a99b1764_003.sh +0 -0
  229. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_714887dd-b46_a99b1764_004.sh +0 -0
  230. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_714887dd-b46_a99b1764_005.sh +0 -0
  231. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_714887dd-b46_a99b1764_006.sh +0 -0
  232. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_714887dd-b46_a99b1764_007.sh +0 -0
  233. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_714887dd-b46_a99b1764_008.sh +0 -0
  234. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_714887dd-b46_a99b1764_009.sh +0 -0
  235. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_714887dd-b46_a99b1764_010.sh +0 -0
  236. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_714887dd-b46_a99b1764_011.sh +0 -0
  237. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_714887dd-b46_a99b1764_012.sh +0 -0
  238. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_714887dd-b46_a99b1764_013.sh +0 -0
  239. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_714887dd-b46_a99b1764_014.sh +0 -0
  240. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_714887dd-b46_a99b1764_015.sh +0 -0
  241. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/inline_commands/wf_714887dd-b46_a99b1764_016.sh +0 -0
  242. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/instrumented_guard_run.py +0 -0
  243. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/instrumented_plane_wave_nan.py +0 -0
  244. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/j_wires_in_wall.py +0 -0
  245. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/origin_checks.py +0 -0
  246. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/origin_das.py +0 -0
  247. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/quick_checks.py +0 -0
  248. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/scan_checks.py +0 -0
  249. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/scan_checks_2.py +0 -0
  250. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/scan_checks_3.py +0 -0
  251. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/scan_checks_4.py +0 -0
  252. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1239_matrix_imaging_agent_checks/toy_plane_wave.py +0 -0
  253. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1241_check_that_the_records_load.py +0 -0
  254. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1241_locate_the_non_finite_values_of_an_analysis.py +0 -0
  255. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1241_measure_the_wire_depth_against_the_time_origin.py +0 -0
  256. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1241_print_the_time_origin_scans.py +0 -0
  257. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1241_test_the_entropy_the_antisymmetry_and_the_filter_linearity.py +0 -0
  258. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1247_time_the_phase_reversal_per_patch_against_batched.py +0 -0
  259. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1248_compare_the_synthesis_on_the_card_and_the_host.py +0 -0
  260. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1250_save_and_compare_the_local_laws_of_a_subset.py +0 -0
  261. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1254_analyze_the_2.5mhz_stage_2.sh +0 -0
  262. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1256_print_the_per_depth_curves_of_a_reverberation_test.py +0 -0
  263. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1302_print_the_durations_of_a_chain_log.py +0 -0
  264. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1314_print_the_gouy_points_of_a_speed_of_sound_scan.py +0 -0
  265. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1445_fit_the_moveout_speed_of_the_point_sources.py +0 -0
  266. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1456_fit_the_depth_offset_of_the_reference_arrivals.py +0 -0
  267. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1502_print_the_laws_and_gates_of_an_analysis.py +0 -0
  268. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1503_analyze_with_the_ramp_removal_off_or_every_law_one.py +0 -0
  269. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1504_measure_the_anti_diagonal_share_of_the_clean_clutter.py +0 -0
  270. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1508_estimate_the_speed_with_smaller_windows.py +0 -0
  271. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1553_focus_the_clutter_records_in_sub_bands.py +0 -0
  272. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1553_print_the_band_and_the_screens_of_the_records.py +0 -0
  273. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1554_predict_the_phase_speed_of_the_stencil.py +0 -0
  274. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1556_compute_the_moveout_truth_with_an_eikonal_solver.py +0 -0
  275. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1556_fit_the_height_offset_on_three_grids.py +0 -0
  276. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1600_measure_the_flat_and_the_screen_correction_on_point_targets.py +0 -0
  277. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1604_predict_the_arrivals_from_the_stencil.py +0 -0
  278. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1604_prototype_the_broadband_correction.py +0 -0
  279. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1605_scan_the_time_origin_with_other_element_planes.py +0 -0
  280. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1607_measure_the_local_far_field_structure_of_the_clutter.py +0 -0
  281. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1608_score_the_speed_scans_against_the_eikonal_truth.py +0 -0
  282. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1610_compare_the_unwrapped_law_delays_with_the_truth.py +0 -0
  283. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1611_compare_the_arrival_models_at_the_point_sources.py +0 -0
  284. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1613_compare_the_sensor_pixel_with_the_element_center.py +0 -0
  285. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1613_measure_the_order_of_the_clutter_from_the_contrast_scaling.py +0 -0
  286. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1613_scan_the_speed_of_sound_at_one_time_origin.py +0 -0
  287. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1615_locate_the_source_and_sensor_pixels_of_the_array.py +0 -0
  288. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1617_check_the_data_level_correction_and_the_pulse_band.py +0 -0
  289. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1617_test_local_and_notch_filters_on_the_clutter.py +0 -0
  290. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1621_compute_the_moveout_truth_with_a_chosen_arrival_model.py +0 -0
  291. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1622_measure_the_tilt_spread_of_the_wall_interfaces.py +0 -0
  292. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1623_tabulate_the_broadband_correction_runs.py +0 -0
  293. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1626_measure_the_ghost_depths_of_the_plate.py +0 -0
  294. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1626_score_the_product_of_the_transducer_laws.py +0 -0
  295. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1630_test_the_local_filter_with_padded_windows.py +0 -0
  296. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1632_fit_the_time_origin_and_the_speed_of_the_phantom_scans.py +0 -0
  297. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1634_fit_the_reference_speed_at_the_sensor_row.py +0 -0
  298. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1646_split_the_clutter_into_orders_and_predict_its_floor.py +0 -0
  299. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1652_tabulate_the_pulse_band_check.py +0 -0
  300. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260910_1659_check_the_plane_wave_transform_of_the_elements.py +0 -0
  301. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260916_1103_compare_two_b_mode_roots.py +0 -0
  302. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260916_1214_binary_cache_lookup_order.py +0 -0
  303. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260916_1253_signal_of_old_against_new.py +0 -0
  304. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260916_1300_read_the_numexpr_pool_limit.py +0 -0
  305. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260916_1332_gpu_memory_of_the_relaxation_kernel.py +0 -0
  306. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260916_1401_relaxation_regions_against_the_kernel.py +0 -0
  307. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260916_1420_released_binary_carries_the_fix.py +0 -0
  308. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260916_1601_stable_courant_number_of_the_stencil_table.py +0 -0
  309. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260916_1602_fast_layer_in_a_small_3d_run.py +0 -0
  310. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260916_1719_p4_1_pulse_energy_above_the_trace_nyquist.py +0 -0
  311. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260916_1933_l7_4_run_at_8_ppw_stability_and_trace_sampling.py +0 -0
  312. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260916_1946_l7_4_trace_sampling_by_field_modulus.py +0 -0
  313. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260916_2004_pulse_bands_of_the_two_abdomen_arrays.py +0 -0
  314. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260916_2155_cuda_version_choice_before_and_after.py +0 -0
  315. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260916_2155_gpu_architectures_in_cached_binaries.py +0 -0
  316. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260916_2155_mutation_check_of_the_cuda_version_tests.py +0 -0
  317. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260916_2155_verify_the_cuda_version_test_findings.py +0 -0
  318. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260916_2212_mutation_check_of_the_blackwell_version_choice.py +0 -0
  319. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260925_1321_selected_cuda_tag.py +0 -0
  320. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260925_1326_release_binary_bit_identity.py +0 -0
  321. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/scratch/20260925_1331_summarize_release_check.py +0 -0
  322. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/settings.local.json +0 -0
  323. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/skills/fullwave25/SKILL.md +0 -0
  324. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/three_dimensional/convex_transducer_3d.py +0 -0
  325. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/three_dimensional/linear_transducer_3d.py +0 -0
  326. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/three_dimensional/matrix_transducer_3d.py +0 -0
  327. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/three_dimensional/patch.py +0 -0
  328. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/three_dimensional/ruff.toml +0 -0
  329. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/three_dimensional/superseded/convex_transducer_3d.py +0 -0
  330. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/three_dimensional/superseded/linear_transducer_3d.py +0 -0
  331. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/three_dimensional/superseded/matrix_transducer_3d.py +0 -0
  332. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/three_dimensional/test_patch.py +0 -0
  333. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/transducer_stack/README.md +0 -0
  334. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/transducer_stack/superseded/full_synthetic_aperture_with_stack.py +0 -0
  335. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.claude/transducer_stack/superseded/plane_wave_compounding_with_stack.py +0 -0
  336. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.gitignore +0 -0
  337. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.pre-commit-config.yaml +0 -0
  338. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/.python-version +0 -0
  339. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/20260120_0844.log +0 -0
  340. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/CITATION.cff +0 -0
  341. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/CONTRIBUTING.md +0 -0
  342. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/LICENSE +0 -0
  343. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/Makefile +0 -0
  344. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/attenuation.png +0 -0
  345. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/beamformer.m +0 -0
  346. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/debug_solver_bin/fullwave2_2d_2_relax_multi_gpu_cuda124 +0 -0
  347. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/debug_solver_bin/fullwave2_2d_exponential_attenuation_multi_gpu +0 -0
  348. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/debug_solver_bin/fullwave2_2d_exponential_attenuation_multi_gpu_cuda124 +0 -0
  349. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/debug_solver_bin/fullwave2_2d_exponential_attenuation_multi_gpu_cuda124_ +0 -0
  350. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/debug_solver_bin/fullwave2_3d_exponential_attenuation_multi_gpu_cuda124 +0 -0
  351. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/debug_solver_bin/fullwave2_3d_exponential_attenuation_multi_gpu_cuda124_ +0 -0
  352. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/docker/Dockerfile +0 -0
  353. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/docker/Dockerfile.dockerignore +0 -0
  354. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/docker/README.md +0 -0
  355. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/experiments/__init__.py +0 -0
  356. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/experiments/exp_scatterer_diameter.py +0 -0
  357. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/beamformer/__init__.py +0 -0
  358. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/constants/__init__.py +0 -0
  359. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/constants/material_properties.py +0 -0
  360. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/grid.py +0 -0
  361. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/medium.py +0 -0
  362. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/medium_builder/__init__.py +0 -0
  363. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/medium_builder/domain.py +0 -0
  364. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/medium_builder/medium_builder.py +0 -0
  365. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/medium_builder/presets/__init__.py +0 -0
  366. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/medium_builder/presets/data/.keep +0 -0
  367. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/medium_builder/presets/data/abdominal_wall/i2365f_etfw1.mat +0 -0
  368. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/medium_builder/presets/domain_abdominal_wall.py +0 -0
  369. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/medium_builder/presets/domain_background.py +0 -0
  370. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/medium_builder/presets/domain_scatterer.py +0 -0
  371. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/medium_builder/presets/domain_simple.py +0 -0
  372. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/medium_builder/presets/domain_water_gel.py +0 -0
  373. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/sensor.py +0 -0
  374. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/solver/__init__.py +0 -0
  375. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/solver/binary_manager.py +0 -0
  376. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/solver/binary_markers.py +0 -0
  377. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/solver/bins/_gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_cuda118 +0 -0
  378. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/solver/bins/_gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_cuda124 +0 -0
  379. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/solver/bins/_gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_cuda129 +0 -0
  380. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/solver/bins/_gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_cuda130 +0 -0
  381. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/solver/bins/_gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_cuda118 +0 -0
  382. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/solver/bins/_gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_cuda124 +0 -0
  383. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/solver/bins/_gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_cuda129 +0 -0
  384. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/solver/bins/_gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_cuda130 +0 -0
  385. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/solver/bins/database/relaxation_params_database_num_relax=3_20260828_1513.mat +0 -0
  386. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/solver/bins/database/relaxation_params_database_num_relax=3_20260828_1513_invalid_cells.json +0 -0
  387. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/solver/bins/database/relaxation_params_database_num_relax=4_20260828_1456.mat +0 -0
  388. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/solver/bins/database/relaxation_params_database_num_relax=4_20260828_1456_invalid_cells.json +0 -0
  389. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/solver/cuda_utils.py +0 -0
  390. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/solver/launcher.py +0 -0
  391. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/solver/pml_builder.py +0 -0
  392. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/solver/shipped_database.py +0 -0
  393. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/solver/source_type.py +0 -0
  394. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/solver/utils.py +0 -0
  395. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/source.py +0 -0
  396. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/transmit.py +0 -0
  397. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/ultra/__init__.py +0 -0
  398. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/ultra/dat_io.py +0 -0
  399. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/ultra/dat_io_3d.py +0 -0
  400. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/ultra/errors.py +0 -0
  401. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/ultra/stencil.py +0 -0
  402. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/ultra/time_axis.py +0 -0
  403. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/utils/__init__.py +0 -0
  404. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/utils/check_functions.py +0 -0
  405. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/utils/coordinates.py +0 -0
  406. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/utils/gpu_memory.py +0 -0
  407. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/utils/memory_tempfile.py +0 -0
  408. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/utils/numerical.py +0 -0
  409. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/utils/plot_utils.py +0 -0
  410. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/utils/pulse.py +0 -0
  411. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/utils/relaxation_parameters.py +0 -0
  412. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/utils/scatterer.py +0 -0
  413. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/fullwave/utils/signal_process.py +0 -0
  414. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/logs/20260815_0356_sweep.log +0 -0
  415. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/ruff.log +0 -0
  416. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/ruff.toml +0 -0
  417. {fullwave25-1.4.2.dev3 → fullwave25-1.4.2.dev4}/signal_filter_example.png +0 -0
@@ -1,5 +1,5 @@
1
1
  [tool.bumpversion]
2
- current_version = "1.4.2-dev3"
2
+ current_version = "1.4.2-dev4"
3
3
  parse = """(?x)
4
4
  (?P<major>0|[1-9]\\d*)\\.
5
5
  (?P<minor>0|[1-9]\\d*)\\.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: fullwave25
3
- Version: 1.4.2-dev3
3
+ Version: 1.4.2-dev4
4
4
  Summary: Fullwave 2.5: Ultrasound wave propagation simulation with heterogeneous power law attenuation modelling capabilities
5
5
  Author: Masashi Sode, Gianmarco Pinton
6
6
  Maintainer: Masashi Sode
@@ -261,6 +261,8 @@ grid = fullwave.Grid(domain_size=(4.5e-2, 4.5e-2), f0=5.208e6, duration=6.7e-5,
261
261
 
262
262
  transducer = fullwave.Transducer.l7_4(grid)
263
263
  transducer.plane_wave(angle_deg=2.5)
264
+ maps = transducer.fill_probe_above_face(sound_speed=sound_speed_map, density=density_map, alpha_coeff=alpha_coeff_map, alpha_power=alpha_power_map)
265
+ medium = fullwave.Medium(grid, beta=beta_map, **maps)
264
266
 
265
267
  solver = fullwave.Solver(work_dir="./outputs/my_run", grid=grid, medium=medium, transducer=transducer)
266
268
  recorded = solver.run()
@@ -270,9 +272,11 @@ The arrays are `l7_4` (linear, 128 elements, 5.208 MHz), `c5_2v` (curved, 49.57
270
272
 
271
273
  The transmits are `plane_wave(angle_deg=...)`, `focus(focus_m=...)`, `diverging(virtual_source_m=...)` and `synthetic_aperture(element)`. Each takes `apodization` and `pulse`. Set `transducer.active_source_elements` first to use part of the aperture.
272
274
 
273
- The source type is `"hard_released_after"` by default: the transducer assigns its pressure while the drive signal plays, then the source cells evolve freely. `"hard"` assigns it for the whole run, so the cells stay at zero pressure after the drive ends. `"soft"` adds the signal to the field, and is what the calibrated setups use. Pass `source_type=` to `Transducer.l7_4`, `c5_2v`, `p4_1c` or `fullwave.Solver`.
275
+ The flat arrays (`l7_4`, `p4_1c`, `LinearTransducer`, `make_p4_1c_trasnducer`) share one layout. The source is one wavelength of rows (at least 8) with its first row on grid row 0, the sponge directly behind it. The receiver row is directly in front of the last source row, and the probe face (depth 0) is the row after it, where the medium starts. The array is centered in the grid, so make the grid wider than the array (the calibrated L7-4 uses 45 mm for its 38.09 mm). `transducer.fill_probe_above_face(...)` sets the cells above the face between the first and the last element edge (the source, kerf and receiver cells) to the probe fill (1540 m/s, 1000 kg/m3, attenuation 0.005 dB/MHz/cm, power 1.0), and the columns beside the array on the same rows to water (the same values with power 1.999), with no scatterers; pass its result to `fullwave.Medium`, or register `transducer.probe_fill_domain()` last in a `MediumBuilder`. `transducer.face_row_px` is the face row and `transducer.face_depth_m` its depth: start the tissue there (for an `AbdominalWallDomain`, pass `start_depth=transducer.face_depth_m`) and measure targets and focus depths from it. `Beamformer(..., face_row_px=...)` measures its depths from there. The curved `c5_2v` keeps its own layout, and `transducer.make_surface_reflective_with_air()` returns the air behind it.
274
276
 
275
- `transducer.apply_transducer_stack(...)` paints a probe's backing, matching layer, lens and standoff onto the medium maps before the `Medium` is built. `fullwave.TransducerStack` holds the values.
277
+ The source type is `"hard"` by default for the named arrays: the transducer assigns its pressure for the whole run, so the source cells stay at zero pressure after the drive ends and the face stays reflective. `"hard_released_after"` assigns it while the drive signal plays, then the source cells evolve freely. `"soft"` adds the signal to the field. Pass `source_type=` to `Transducer.l7_4`, `c5_2v`, `p4_1c` or `fullwave.Solver`.
278
+
279
+ `transducer.apply_transducer_stack(...)` still paints a probe's backing, matching layer, lens and standoff onto the medium maps before the `Medium` is built, for a calibrated stack. `fullwave.TransducerStack` holds the values.
276
280
 
277
281
  ### Transmit batches
278
282
 
@@ -297,6 +301,7 @@ recorded = solver.run_batch(sources) # [n_transmits, n_sensors, n_t]
297
301
  | I want to | example |
298
302
  | ---------------------------------- | ----------------------------------------------------------------------------------------------------------- |
299
303
  | send one plane wave | [simple_plane_wave.py](examples/simple_plane_wave/simple_plane_wave.py) |
304
+ | do the same with fullwave2-ultra | [simple_plane_wave_ultra.py](examples/simple_plane_wave/simple_plane_wave_ultra.py) |
300
305
  | do the same in 3D | [simple_plane_wave_3d.py](examples/wave_3d/simple_plane_wave_3d.py) |
301
306
  | compound plane waves into a B-mode | [plane_wave_compounding.py](examples/linear_transducer/plane_wave_compounding.py) |
302
307
  | run a transmit sequence as batches | [transmit_batch_basics.py](examples/transmit_batch/transmit_batch_basics.py) |
@@ -395,7 +400,7 @@ Please see the following examples for more advanced usage.
395
400
 
396
401
  The fullwave2-ultra backend is optimized for speed at ppw = 6 (`Grid.ppw`); a larger ppw runs, but more slowly, and gives a warning.
397
402
 
398
- fullwave25 does not ship the fullwave2-ultra binaries. Get them from <https://github.com/pinton-lab/fullwave2-ultra> or contact the Pinton lab.
403
+ fullwave25 does not ship the fullwave2-ultra binaries. Obtain them from the Pinton lab.
399
404
 
400
405
  Point the solver to the binary with `path_fullwave_simulation_bin` or with the environment variable `FW2U_BATCH_BIN`. Either can be the binary file or the folder that contains it. The binary name is `bench_2d_batch` for a 2D grid and `bench_3d_opt` for a 3D grid.
401
406
 
@@ -407,7 +412,7 @@ import fullwave
407
412
  solver = fullwave.Solver(
408
413
  work_dir=Path("./outputs/ultra"),
409
414
  grid=grid, # 2D or 3D fullwave.Grid
410
- medium=medium, # fullwave.Medium with alpha_power == 1 everywhere
415
+ medium=medium, # fullwave.Medium; alpha_power other than 1 is converted to power 1 at f0
411
416
  source=source,
412
417
  sensor=sensor,
413
418
  path_fullwave_simulation_bin=Path("/path/to/fullwave2-ultra/bin"),
@@ -431,17 +436,40 @@ Supported now:
431
436
  - `run_batch` in 3D.
432
437
  - Velocity sources, and sources that are not pressure sources.
433
438
  - Sparse-grid sensors, `is_static_map`, and `record_whole_domain`.
434
- - Media other than `fullwave.Medium` (exponential attenuation), and `alpha_power` other than 1.
439
+ - Media other than `fullwave.Medium` (exponential attenuation).
435
440
  - `use_pml=False`, `m_spatial_order` other than 8, `use_gpu=False`, and an invalid `source_type`.
436
441
  - In 2D, a binary that does not read the files for air cells, for the additive channel, or for releasing the source (with such a binary, pad `p0` to `grid.nt`).
437
442
  - In 3D, air cells with a binary that does not read `icczero.dat` and `nzero0.dat`, and additive sources with a binary that does not read `ncoords_add.dat` and `icmat_add.dat`.
438
443
 
439
444
  This list will grow as the backend does.
440
445
 
441
- The backend runs the exponential attenuation model (frequency-independent: the same attenuation at every frequency). Set the width of its absorbing sponge, in cells, with `ultra_sponge_thickness_px`; the default is 6 wavelengths in 2D and 4 wavelengths in 3D. `exponential_attenuation_pml_thickness_px` no longer sets this width with `use_ultra=True`; a script that relied on it now gets the default width until it passes `ultra_sponge_thickness_px`.
446
+ Unless `ultra_attenuation_parameters` is set (below), the backend runs the exponential attenuation model (frequency-independent: the same attenuation at every frequency); a frequency-dependent attenuation is available only with `ultra_attenuation_parameters` and a compatible binary. Without it, cells with an `alpha_power` other than 1 are converted to power 1 with the same attenuation at `f0` (`alpha_coeff * f0_MHz**(alpha_power - 1)`), with one warning that names the converted range. Set the width of its absorbing sponge, in cells, with `ultra_sponge_thickness_px`; the default is 6 wavelengths in 2D and 4 wavelengths in 3D. `exponential_attenuation_pml_thickness_px` no longer sets this width with `use_ultra=True`; a script that relied on it now gets the default width until it passes `ultra_sponge_thickness_px`.
442
447
 
443
448
  Options that only tune the native solver are ignored with a warning, once per process: `pml_layer_thickness_px`, `n_transition_layer`, `pml_alpha_entrance`, `exponential_attenuation_pml_thickness_px` (use `ultra_sponge_thickness_px` instead), `use_gpu_pml`, `save_gpu_memory`, `write_maps_the_solver_does_not_read`, `use_isotropic_relaxation=False`, and a `cuda_device_id` that lists more than one device (the run uses the first one listed). `use_exponential_attenuation=False`, the native default, also warns that the backend runs the exponential attenuation model, whose attenuation is frequency-independent, not the relaxation model, whose attenuation is frequency-dependent. Pass `use_exponential_attenuation=True` to silence it.
444
449
 
450
+ #### Attenuation modes
451
+
452
+ A 2D or 3D run has three attenuation modes. Each needs `use_ultra=True`; the last two need the power-law attenuation binaries from the Pinton lab and `use_exponential_attenuation=False`.
453
+
454
+ ```python
455
+ # 1. Default: frequency-independent attenuation (as described above).
456
+ solver = fullwave.Solver(..., use_ultra=True, path_fullwave_simulation_bin=bin_folder)
457
+
458
+ # 2. Power-law attenuation alpha_coeff * f**alpha_power.
459
+ solver = fullwave.Solver(
460
+ ...,
461
+ use_ultra=True,
462
+ use_exponential_attenuation=False,
463
+ path_fullwave_simulation_bin=bin_folder,
464
+ ultra_attenuation_parameters="centered", # or "author", or the path of a settings file
465
+ )
466
+
467
+ # 3. The same with any number of materials (more GPU memory).
468
+ solver = fullwave.Solver(..., ultra_attenuation_parameters="centered", ultra_unlimited_materials=True)
469
+ ```
470
+
471
+ `bin_folder` is the folder of the binaries. With `ultra_attenuation_parameters` it gives the power-law build of the grid dimension; without it, `bench_2d_batch` or `bench_3d_opt`. A name looks for `attenuation_parameters_<name>_v1.dat` next to the binary, then in the `params` folder beside `bin_folder`; the error lists the places searched. "centered" is the recommended band. `UltraUnsupportedError` is raised without `use_ultra=True`, with `use_exponential_attenuation=True`, for a missing settings file, for a binary that does not read `alpha_power.dat`, and, with `ultra_unlimited_materials=True`, for a binary that does not support it. The run directory then gets `alpha_coeff.dat`, `alpha_power.dat`, `f0.dat` and a copy of the settings file as `attenuation_parameters.dat`, and `Aexp.dat` holds the sponge only. The environment variable `FW2U_BATCH_BIN` is not used in modes 2 and 3.
472
+
445
473
  ---
446
474
 
447
475
  ## Attention
@@ -220,6 +220,8 @@ grid = fullwave.Grid(domain_size=(4.5e-2, 4.5e-2), f0=5.208e6, duration=6.7e-5,
220
220
 
221
221
  transducer = fullwave.Transducer.l7_4(grid)
222
222
  transducer.plane_wave(angle_deg=2.5)
223
+ maps = transducer.fill_probe_above_face(sound_speed=sound_speed_map, density=density_map, alpha_coeff=alpha_coeff_map, alpha_power=alpha_power_map)
224
+ medium = fullwave.Medium(grid, beta=beta_map, **maps)
223
225
 
224
226
  solver = fullwave.Solver(work_dir="./outputs/my_run", grid=grid, medium=medium, transducer=transducer)
225
227
  recorded = solver.run()
@@ -229,9 +231,11 @@ The arrays are `l7_4` (linear, 128 elements, 5.208 MHz), `c5_2v` (curved, 49.57
229
231
 
230
232
  The transmits are `plane_wave(angle_deg=...)`, `focus(focus_m=...)`, `diverging(virtual_source_m=...)` and `synthetic_aperture(element)`. Each takes `apodization` and `pulse`. Set `transducer.active_source_elements` first to use part of the aperture.
231
233
 
232
- The source type is `"hard_released_after"` by default: the transducer assigns its pressure while the drive signal plays, then the source cells evolve freely. `"hard"` assigns it for the whole run, so the cells stay at zero pressure after the drive ends. `"soft"` adds the signal to the field, and is what the calibrated setups use. Pass `source_type=` to `Transducer.l7_4`, `c5_2v`, `p4_1c` or `fullwave.Solver`.
234
+ The flat arrays (`l7_4`, `p4_1c`, `LinearTransducer`, `make_p4_1c_trasnducer`) share one layout. The source is one wavelength of rows (at least 8) with its first row on grid row 0, the sponge directly behind it. The receiver row is directly in front of the last source row, and the probe face (depth 0) is the row after it, where the medium starts. The array is centered in the grid, so make the grid wider than the array (the calibrated L7-4 uses 45 mm for its 38.09 mm). `transducer.fill_probe_above_face(...)` sets the cells above the face between the first and the last element edge (the source, kerf and receiver cells) to the probe fill (1540 m/s, 1000 kg/m3, attenuation 0.005 dB/MHz/cm, power 1.0), and the columns beside the array on the same rows to water (the same values with power 1.999), with no scatterers; pass its result to `fullwave.Medium`, or register `transducer.probe_fill_domain()` last in a `MediumBuilder`. `transducer.face_row_px` is the face row and `transducer.face_depth_m` its depth: start the tissue there (for an `AbdominalWallDomain`, pass `start_depth=transducer.face_depth_m`) and measure targets and focus depths from it. `Beamformer(..., face_row_px=...)` measures its depths from there. The curved `c5_2v` keeps its own layout, and `transducer.make_surface_reflective_with_air()` returns the air behind it.
233
235
 
234
- `transducer.apply_transducer_stack(...)` paints a probe's backing, matching layer, lens and standoff onto the medium maps before the `Medium` is built. `fullwave.TransducerStack` holds the values.
236
+ The source type is `"hard"` by default for the named arrays: the transducer assigns its pressure for the whole run, so the source cells stay at zero pressure after the drive ends and the face stays reflective. `"hard_released_after"` assigns it while the drive signal plays, then the source cells evolve freely. `"soft"` adds the signal to the field. Pass `source_type=` to `Transducer.l7_4`, `c5_2v`, `p4_1c` or `fullwave.Solver`.
237
+
238
+ `transducer.apply_transducer_stack(...)` still paints a probe's backing, matching layer, lens and standoff onto the medium maps before the `Medium` is built, for a calibrated stack. `fullwave.TransducerStack` holds the values.
235
239
 
236
240
  ### Transmit batches
237
241
 
@@ -256,6 +260,7 @@ recorded = solver.run_batch(sources) # [n_transmits, n_sensors, n_t]
256
260
  | I want to | example |
257
261
  | ---------------------------------- | ----------------------------------------------------------------------------------------------------------- |
258
262
  | send one plane wave | [simple_plane_wave.py](examples/simple_plane_wave/simple_plane_wave.py) |
263
+ | do the same with fullwave2-ultra | [simple_plane_wave_ultra.py](examples/simple_plane_wave/simple_plane_wave_ultra.py) |
259
264
  | do the same in 3D | [simple_plane_wave_3d.py](examples/wave_3d/simple_plane_wave_3d.py) |
260
265
  | compound plane waves into a B-mode | [plane_wave_compounding.py](examples/linear_transducer/plane_wave_compounding.py) |
261
266
  | run a transmit sequence as batches | [transmit_batch_basics.py](examples/transmit_batch/transmit_batch_basics.py) |
@@ -354,7 +359,7 @@ Please see the following examples for more advanced usage.
354
359
 
355
360
  The fullwave2-ultra backend is optimized for speed at ppw = 6 (`Grid.ppw`); a larger ppw runs, but more slowly, and gives a warning.
356
361
 
357
- fullwave25 does not ship the fullwave2-ultra binaries. Get them from <https://github.com/pinton-lab/fullwave2-ultra> or contact the Pinton lab.
362
+ fullwave25 does not ship the fullwave2-ultra binaries. Obtain them from the Pinton lab.
358
363
 
359
364
  Point the solver to the binary with `path_fullwave_simulation_bin` or with the environment variable `FW2U_BATCH_BIN`. Either can be the binary file or the folder that contains it. The binary name is `bench_2d_batch` for a 2D grid and `bench_3d_opt` for a 3D grid.
360
365
 
@@ -366,7 +371,7 @@ import fullwave
366
371
  solver = fullwave.Solver(
367
372
  work_dir=Path("./outputs/ultra"),
368
373
  grid=grid, # 2D or 3D fullwave.Grid
369
- medium=medium, # fullwave.Medium with alpha_power == 1 everywhere
374
+ medium=medium, # fullwave.Medium; alpha_power other than 1 is converted to power 1 at f0
370
375
  source=source,
371
376
  sensor=sensor,
372
377
  path_fullwave_simulation_bin=Path("/path/to/fullwave2-ultra/bin"),
@@ -390,17 +395,40 @@ Supported now:
390
395
  - `run_batch` in 3D.
391
396
  - Velocity sources, and sources that are not pressure sources.
392
397
  - Sparse-grid sensors, `is_static_map`, and `record_whole_domain`.
393
- - Media other than `fullwave.Medium` (exponential attenuation), and `alpha_power` other than 1.
398
+ - Media other than `fullwave.Medium` (exponential attenuation).
394
399
  - `use_pml=False`, `m_spatial_order` other than 8, `use_gpu=False`, and an invalid `source_type`.
395
400
  - In 2D, a binary that does not read the files for air cells, for the additive channel, or for releasing the source (with such a binary, pad `p0` to `grid.nt`).
396
401
  - In 3D, air cells with a binary that does not read `icczero.dat` and `nzero0.dat`, and additive sources with a binary that does not read `ncoords_add.dat` and `icmat_add.dat`.
397
402
 
398
403
  This list will grow as the backend does.
399
404
 
400
- The backend runs the exponential attenuation model (frequency-independent: the same attenuation at every frequency). Set the width of its absorbing sponge, in cells, with `ultra_sponge_thickness_px`; the default is 6 wavelengths in 2D and 4 wavelengths in 3D. `exponential_attenuation_pml_thickness_px` no longer sets this width with `use_ultra=True`; a script that relied on it now gets the default width until it passes `ultra_sponge_thickness_px`.
405
+ Unless `ultra_attenuation_parameters` is set (below), the backend runs the exponential attenuation model (frequency-independent: the same attenuation at every frequency); a frequency-dependent attenuation is available only with `ultra_attenuation_parameters` and a compatible binary. Without it, cells with an `alpha_power` other than 1 are converted to power 1 with the same attenuation at `f0` (`alpha_coeff * f0_MHz**(alpha_power - 1)`), with one warning that names the converted range. Set the width of its absorbing sponge, in cells, with `ultra_sponge_thickness_px`; the default is 6 wavelengths in 2D and 4 wavelengths in 3D. `exponential_attenuation_pml_thickness_px` no longer sets this width with `use_ultra=True`; a script that relied on it now gets the default width until it passes `ultra_sponge_thickness_px`.
401
406
 
402
407
  Options that only tune the native solver are ignored with a warning, once per process: `pml_layer_thickness_px`, `n_transition_layer`, `pml_alpha_entrance`, `exponential_attenuation_pml_thickness_px` (use `ultra_sponge_thickness_px` instead), `use_gpu_pml`, `save_gpu_memory`, `write_maps_the_solver_does_not_read`, `use_isotropic_relaxation=False`, and a `cuda_device_id` that lists more than one device (the run uses the first one listed). `use_exponential_attenuation=False`, the native default, also warns that the backend runs the exponential attenuation model, whose attenuation is frequency-independent, not the relaxation model, whose attenuation is frequency-dependent. Pass `use_exponential_attenuation=True` to silence it.
403
408
 
409
+ #### Attenuation modes
410
+
411
+ A 2D or 3D run has three attenuation modes. Each needs `use_ultra=True`; the last two need the power-law attenuation binaries from the Pinton lab and `use_exponential_attenuation=False`.
412
+
413
+ ```python
414
+ # 1. Default: frequency-independent attenuation (as described above).
415
+ solver = fullwave.Solver(..., use_ultra=True, path_fullwave_simulation_bin=bin_folder)
416
+
417
+ # 2. Power-law attenuation alpha_coeff * f**alpha_power.
418
+ solver = fullwave.Solver(
419
+ ...,
420
+ use_ultra=True,
421
+ use_exponential_attenuation=False,
422
+ path_fullwave_simulation_bin=bin_folder,
423
+ ultra_attenuation_parameters="centered", # or "author", or the path of a settings file
424
+ )
425
+
426
+ # 3. The same with any number of materials (more GPU memory).
427
+ solver = fullwave.Solver(..., ultra_attenuation_parameters="centered", ultra_unlimited_materials=True)
428
+ ```
429
+
430
+ `bin_folder` is the folder of the binaries. With `ultra_attenuation_parameters` it gives the power-law build of the grid dimension; without it, `bench_2d_batch` or `bench_3d_opt`. A name looks for `attenuation_parameters_<name>_v1.dat` next to the binary, then in the `params` folder beside `bin_folder`; the error lists the places searched. "centered" is the recommended band. `UltraUnsupportedError` is raised without `use_ultra=True`, with `use_exponential_attenuation=True`, for a missing settings file, for a binary that does not read `alpha_power.dat`, and, with `ultra_unlimited_materials=True`, for a binary that does not support it. The run directory then gets `alpha_coeff.dat`, `alpha_power.dat`, `f0.dat` and a copy of the settings file as `attenuation_parameters.dat`, and `Aexp.dat` holds the sponge only. The environment variable `FW2U_BATCH_BIN` is not used in modes 2 and 3.
431
+
404
432
  ---
405
433
 
406
434
  ## Attention
@@ -66,7 +66,7 @@ try:
66
66
  __version__ = version("fullwave")
67
67
  except PackageNotFoundError:
68
68
  # Update via bump-my-version, not manually
69
- __version__ = "1.4.2-dev3"
69
+ __version__ = "1.4.2-dev4"
70
70
 
71
71
  VERSION = __version__ # for convenience
72
72
  logger.info("Fullwave version: %s", __version__)
@@ -14,12 +14,13 @@ class Beamformer:
14
14
  For faster implementations, consider using libraries such as
15
15
  mach beamformer: https://github.com/Forest-Neurotech/mach
16
16
 
17
- Conventions: ``axial_position_m`` is measured from the top of the grid
18
- (row 0), not from the array. ``transducer_coordinates`` must be the
19
- receiver positions in grid points (for example from
20
- ``Transducer.element_id_to_receiver_center``). The time origin is the
21
- mean receiver row, so the array depth is subtracted from the two-way
22
- travel time.
17
+ Conventions: ``axial_position_m`` is the depth below the probe face, so
18
+ depth 0 is the face row ``face_row_px`` (``Transducer.face_row_px``, the
19
+ first medium row, one row in front of the receiver row).
20
+ ``transducer_coordinates`` must be the receiver positions in grid points
21
+ (for example from ``Transducer.element_id_to_receiver_center``). The time
22
+ origin is the mean receiver row, so the array depth is subtracted from the
23
+ two-way travel time.
23
24
 
24
25
  References
25
26
  ----------
@@ -38,6 +39,7 @@ class Beamformer:
38
39
  axial_position_m: np.ndarray,
39
40
  num_elements: int,
40
41
  transducer_coordinates: np.ndarray,
42
+ face_row_px: int,
41
43
  f_number: float = 1.0,
42
44
  ) -> None:
43
45
  """Initialize the beamformer with simulation and transducer parameters.
@@ -53,11 +55,14 @@ class Beamformer:
53
55
  lateral_position_m : np.ndarray
54
56
  Lateral positions (m) where the beamformed image will be computed.
55
57
  axial_position_m : np.ndarray
56
- Axial positions (m) from the top of the grid where the image is computed.
58
+ Depths (m) below the probe face where the image is computed.
57
59
  num_elements : int
58
60
  Number of transducer elements.
59
61
  transducer_coordinates : np.ndarray
60
62
  Receiver coordinates [n_elements, 2] in grid points (row, column).
63
+ face_row_px : int
64
+ Grid row of the probe face (depth 0), for example
65
+ ``Transducer.face_row_px``.
61
66
  f_number : float, optional
62
67
  F-number for aperture calculation, by default 1.0.
63
68
 
@@ -69,6 +74,7 @@ class Beamformer:
69
74
  self.axial_position_m = axial_position_m
70
75
  self.num_elements = num_elements
71
76
  self.transducer_coordinates = transducer_coordinates
77
+ self.face_row_px = face_row_px
72
78
  self.f_number = f_number
73
79
 
74
80
  def run(self, signals: np.ndarray) -> np.ndarray:
@@ -83,7 +89,9 @@ class Beamformer:
83
89
  Returns
84
90
  -------
85
91
  np.ndarray
86
- Beamformed image. Shape: [n_axial, n_lateral, n_transmit].
92
+ Beamformed image. Shape: [n_axial, n_lateral, n_transmit]. Row 0
93
+ of the first axis is the first depth of ``axial_position_m``, which
94
+ is measured from the probe face.
87
95
 
88
96
  """
89
97
  # signals: [n_elements, n_time, n_transmit]
@@ -110,12 +118,13 @@ class Beamformer:
110
118
  desc="Lateral positions",
111
119
  total=len(self.lateral_position_m),
112
120
  ):
113
- for i_axial, axial in tqdm(
121
+ for i_axial, depth in tqdm(
114
122
  enumerate(self.axial_position_m),
115
123
  desc="Axial positions",
116
124
  total=len(self.axial_position_m),
117
125
  leave=False,
118
126
  ):
127
+ axial = self.face_row_px * self.dx + depth
119
128
  fcen = np.array(
120
129
  [
121
130
  int(axial / self.dx),
@@ -293,6 +293,7 @@ class InputFileWriter:
293
293
  _incoords_vel,
294
294
  )
295
295
  self._queue_coords_write(simulation_dir / "icc.dat", self.source.incoords)
296
+ self._save_drive_params(simulation_dir, members)
296
297
  self._copy_simulation_bin_file(simulation_dir)
297
298
 
298
299
  if not self.use_exponential_attenuation:
@@ -1275,8 +1276,6 @@ class InputFileWriter:
1275
1276
  "ncoords_w",
1276
1277
  "ncoordsout",
1277
1278
  "ncoordszero",
1278
- "nTic",
1279
- "hold_source",
1280
1279
  "modT",
1281
1280
  "modX",
1282
1281
  "modY",
@@ -1374,6 +1373,27 @@ class InputFileWriter:
1374
1373
  save_path = simulation_dir / f"{var_name}.dat"
1375
1374
  self._queue_v_abs_write(np.float32, save_path, var)
1376
1375
 
1376
+ def _save_drive_params(
1377
+ self,
1378
+ simulation_dir: Path,
1379
+ members: Sequence[fullwave.Source] | None = None,
1380
+ ) -> None:
1381
+ """Write the drive length and the hold flag of this transmit.
1382
+
1383
+ Every transmit folder gets its own files, never a link to the shared
1384
+ static-map files, and a flag left by an earlier run is removed when the
1385
+ hold is off. The members of a batch share one length, which can exceed the
1386
+ length of the source, so the drive length is the one of the members.
1387
+ """
1388
+ drive_length_file = simulation_dir / "nTic.dat"
1389
+ hold_flag_file = simulation_dir / "hold_source.dat"
1390
+ drive_length_file.unlink(missing_ok=True)
1391
+ hold_flag_file.unlink(missing_ok=True)
1392
+ drive_source = self.source if members is None else members[0]
1393
+ self._queue_v_abs_write(np.int32, drive_length_file, drive_source.icmat.shape[1])
1394
+ if self._holds_the_source:
1395
+ self._queue_v_abs_write(np.int32, hold_flag_file, 1)
1396
+
1377
1397
  def _save_coords_params(self, simulation_dir: Path) -> None:
1378
1398
  var_list = [
1379
1399
  ("nX", self.grid.nx),
@@ -1382,11 +1402,8 @@ class InputFileWriter:
1382
1402
  ("ncoords", self.source.n_sources),
1383
1403
  ("ncoordsout", self.sensor.n_sensors),
1384
1404
  ("ncoordszero", self.medium.n_air),
1385
- ("nTic", self.source.icmat.shape[1]),
1386
1405
  ("modT", self.sensor.sampling_modulus_time),
1387
1406
  ]
1388
- if self._holds_the_source:
1389
- var_list.append(("hold_source", 1))
1390
1407
  n_sources_add = getattr(self.source, "n_sources_add", 0)
1391
1408
  if n_sources_add > 0:
1392
1409
  var_list.append(("ncoords_add", n_sources_add))
@@ -1,6 +1,7 @@
1
1
  """solver module."""
2
2
 
3
3
  import contextlib
4
+ import copy
4
5
  import logging
5
6
  import os
6
7
  import time
@@ -22,6 +23,7 @@ from fullwave.solver.source_type import (
22
23
  is_hard_held,
23
24
  is_soft,
24
25
  )
26
+ from fullwave.ultra import attenuation_parameters as power_law_attenuation
25
27
  from fullwave.ultra import backend, binary, factory
26
28
  from fullwave.utils import (
27
29
  check_functions,
@@ -470,10 +472,12 @@ class Solver:
470
472
  verify_gpu: bool = True,
471
473
  use_gpu_pml: bool = False,
472
474
  pml_alpha_entrance: float | None = None,
473
- source_type: str = HARD_RELEASED_AFTER,
475
+ source_type: str | None = None,
474
476
  write_maps_the_solver_does_not_read: bool = False,
475
477
  use_ultra: bool = False,
476
478
  ultra_sponge_thickness_px: int | None = None,
479
+ ultra_attenuation_parameters: str | Path | None = None,
480
+ ultra_unlimited_materials: bool = False,
477
481
  ) -> None:
478
482
  """Initialize a Solver instance for the fullwave simulation.
479
483
 
@@ -599,12 +603,14 @@ class Solver:
599
603
  relaxation path. Set it to True for a solver binary that predates
600
604
  that record. Such a binary stops with an error on kappax.dat rather
601
605
  than returning a wrong answer.
602
- source_type : str, optional
603
- How the source drives the field. "hard_released_after", the default,
604
- assigns the source pressure while the drive signal plays, then lets the
605
- source cells evolve freely. "hard" assigns it for the whole run, so the
606
- cells stay at zero pressure after the signal ends. "soft" adds the signal
607
- to the field. ``use_ultra`` follows the same three values.
606
+ source_type : str | None, optional
607
+ How the source drives the field. None, the default, takes the type of the
608
+ ``transducer`` when one is given, and "hard_released_after" otherwise. A
609
+ value that differs from the transducer's type raises ValueError.
610
+ "hard_released_after" assigns the source pressure while the drive signal
611
+ plays, then lets the source cells evolve freely. "hard" assigns it for the
612
+ whole run, so the cells stay at zero pressure after the signal ends.
613
+ "soft" adds the signal to the field. ``use_ultra`` follows the same three values.
608
614
  use_ultra : bool, optional
609
615
  Experimental. Run a user-supplied fullwave2-ultra binary (not shipped; pass it
610
616
  as ``path_fullwave_simulation_bin`` or set ``FW2U_BATCH_BIN``): ``bench_2d_batch``
@@ -620,6 +626,13 @@ class Solver:
620
626
  Width of the absorbing sponge of the ``use_ultra`` backend, in cells.
621
627
  None, the default, gives 6 wavelengths in 2D and 4 wavelengths in 3D.
622
628
  Used only with ``use_ultra=True``.
629
+ ultra_attenuation_parameters : str | Path, optional
630
+ Power-law attenuation for the ``use_ultra`` backend. Give "centered", "author",
631
+ or the path of a parameter file. Needs ``use_ultra=True`` and
632
+ ``use_exponential_attenuation=False``.
633
+ ultra_unlimited_materials : bool, optional
634
+ If True, allow any number of distinct materials (uses more GPU memory). Needs
635
+ ``ultra_attenuation_parameters``.
623
636
 
624
637
  Raises
625
638
  ------
@@ -630,9 +643,28 @@ class Solver:
630
643
  and transducer) are defined simultaneously.
631
644
 
632
645
  """
646
+ source_type = self._resolve_source_type(source_type=source_type, transducer=transducer)
633
647
  self.ultra = None
648
+ power_law_attenuation.check_unlimited_materials(
649
+ unlimited_materials=ultra_unlimited_materials,
650
+ parameters=ultra_attenuation_parameters,
651
+ use_ultra=use_ultra,
652
+ )
653
+ if ultra_attenuation_parameters is not None:
654
+ request = power_law_attenuation.check_request(
655
+ parameters=ultra_attenuation_parameters,
656
+ use_ultra=use_ultra,
657
+ use_exponential_attenuation=use_exponential_attenuation,
658
+ binary=path_fullwave_simulation_bin,
659
+ is_3d=grid.is_3d,
660
+ unlimited_materials=ultra_unlimited_materials,
661
+ )
662
+ ultra_attenuation_parameters = request.parameter_file
663
+ path_fullwave_simulation_bin = request.binary
634
664
  if use_ultra:
635
665
  self._init_ultra(
666
+ attenuation_parameters=ultra_attenuation_parameters,
667
+ unlimited_materials=ultra_unlimited_materials,
636
668
  work_dir=work_dir,
637
669
  grid=grid,
638
670
  medium=medium,
@@ -813,7 +845,12 @@ class Solver:
813
845
  logger.error(error_msg)
814
846
  raise ValueError(error_msg)
815
847
  self.source_type = source_type
816
- if is_soft(source_type) and self.source.p0_additive is not None:
848
+ source_is_the_transducers = source is None and transducer is not None
849
+ if is_soft(source_type) and source_is_the_transducers:
850
+ logger.info(
851
+ "source_type=%s, the transducer's source is driven by addition", source_type
852
+ )
853
+ elif is_soft(source_type) and self.source.p0_additive is not None:
817
854
  error_msg = (
818
855
  "this source already carries an additive signal. source_type='soft' "
819
856
  "converts a hard source into a soft one, and this source holds no "
@@ -824,7 +861,7 @@ class Solver:
824
861
  raise ValueError(error_msg)
825
862
  if not is_soft(source_type) and self.source.p0_additive is not None:
826
863
  self._warn_if_the_additive_signal_was_not_scaled()
827
- if is_soft(source_type):
864
+ if is_soft(source_type) and not source_is_the_transducers:
828
865
  self.source = as_additive_source(
829
866
  self.source,
830
867
  self.grid,
@@ -898,11 +935,15 @@ class Solver:
898
935
  verify_gpu: bool,
899
936
  nbdy: int | None,
900
937
  options: dict,
938
+ attenuation_parameters: Path | None,
939
+ unlimited_materials: bool,
901
940
  ) -> None:
902
941
  """Set up the experimental fullwave2-ultra backend (see ``fullwave.ultra``)."""
903
942
  backend.warn_experimental()
904
943
  backend.warn_ppw_above_speed_optimum(ppw=grid.ppw)
905
- backend.check_solver_options(**options)
944
+ backend.check_solver_options(
945
+ **options, has_attenuation_parameters=attenuation_parameters is not None
946
+ )
906
947
  binary_name = binary.BINARY_NAME_3D if grid.is_3d else binary.BINARY_NAME_2D
907
948
  ultra_binary = binary.resolve_binary(path_fullwave_simulation_bin, name=binary_name)
908
949
  self._check_input(grid, medium, source, sensor, transducer, ultra_binary)
@@ -924,8 +965,48 @@ class Solver:
924
965
  cuda_device_id=cuda_device_id,
925
966
  verify_gpu=verify_gpu,
926
967
  source_type=options["source_type"],
968
+ attenuation_parameters=attenuation_parameters,
969
+ unlimited_materials=unlimited_materials,
927
970
  )
928
971
 
972
+ @staticmethod
973
+ def _resolve_source_type(
974
+ *, source_type: str | None, transducer: fullwave.Transducer | None
975
+ ) -> str:
976
+ """Return the source type of the run.
977
+
978
+ Parameters
979
+ ----------
980
+ source_type : str | None
981
+ The Solver's own argument.
982
+ transducer : fullwave.Transducer | None
983
+ The transducer that drives the run, if any.
984
+
985
+ Returns
986
+ -------
987
+ str
988
+ The transducer's type when the argument is None and a transducer is given,
989
+ the argument when it is given, and "hard_released_after" otherwise.
990
+
991
+ Raises
992
+ ------
993
+ ValueError
994
+ If the argument differs from the transducer's type.
995
+ """
996
+ if transducer is None:
997
+ return HARD_RELEASED_AFTER if source_type is None else source_type
998
+ if source_type is None:
999
+ return transducer.source_type
1000
+ if source_type != transducer.source_type:
1001
+ error_msg = (
1002
+ f"Solver source_type {source_type!r} differs from the transducer's "
1003
+ f"source_type {transducer.source_type!r}. Set the source type in one "
1004
+ "place, on the Transducer, and leave the Solver's source_type unset."
1005
+ )
1006
+ logger.error(error_msg)
1007
+ raise ValueError(error_msg)
1008
+ return source_type
1009
+
929
1010
  def _warn_if_the_additive_signal_was_not_scaled(self) -> None:
930
1011
  """Say so when an additive signal was built by hand and may carry no scale.
931
1012
 
@@ -1541,8 +1622,10 @@ class Solver:
1541
1622
  Parameters
1542
1623
  ----------
1543
1624
  sources : Sequence[fullwave.Source]
1544
- The transmits, in order. Each one must have the same source coordinates,
1545
- the same signal kinds and the same signal length as the Solver's source.
1625
+ The transmits, in order. Each one must have the same source coordinates
1626
+ and the same signal kinds as the Solver's source. The signals may differ in
1627
+ length and are padded with trailing zeros to the longest drive; with
1628
+ ``use_ultra=True`` they must have one length.
1546
1629
  The Solver's ``source_type`` applies to every transmit.
1547
1630
  simulation_dir_name : str | Path
1548
1631
  The directory name of the simulation under the work directory.
@@ -1604,7 +1687,7 @@ class Solver:
1604
1687
  highpass_cutoff_mhz=highpass_cutoff_mhz,
1605
1688
  bandpass_cutoff_mhz=bandpass_cutoff_mhz,
1606
1689
  )
1607
- members = self._batch_members(sources)
1690
+ members = self._batch_members(self._pad_to_longest_drive(sources))
1608
1691
  # The sensor and the sizing below need the extended grid and medium.
1609
1692
  self.pml_builder.run(use_pml=self.use_pml)
1610
1693
  sensor = self._output_sensor(
@@ -1647,6 +1730,43 @@ class Solver:
1647
1730
  return [path for run_paths in outputs for path in run_paths]
1648
1731
  return np.concatenate(outputs, axis=0)
1649
1732
 
1733
+ def _pad_to_longest_drive(self, sources: Sequence[fullwave.Source]) -> list[fullwave.Source]:
1734
+ """Return the transmits with every signal padded with zeros to the longest drive.
1735
+
1736
+ The longest drive is the longest signal among the transmits and the Solver's
1737
+ source. The transmits are copied; the given sources stay as they are.
1738
+
1739
+ Parameters
1740
+ ----------
1741
+ sources : Sequence[fullwave.Source]
1742
+ The transmits, in order.
1743
+
1744
+ Returns
1745
+ -------
1746
+ list[fullwave.Source]
1747
+ The transmits, with signals of equal length.
1748
+
1749
+ """
1750
+ names = ("p0", "p0_additive", "u0", "v0", "w0")
1751
+ reference = [self.source] if getattr(self, "source", None) is not None else []
1752
+ padded = []
1753
+ for source in sources:
1754
+ member = copy.copy(source)
1755
+ for name in names:
1756
+ signal = getattr(member, name, None)
1757
+ if signal is None:
1758
+ continue
1759
+ length = max(
1760
+ np.shape(getattr(other, name, None))[-1]
1761
+ for other in [*sources, *reference]
1762
+ if getattr(other, name, None) is not None
1763
+ )
1764
+ if np.shape(signal)[-1] < length:
1765
+ pad = [(0, 0)] * (np.ndim(signal) - 1) + [(0, length - np.shape(signal)[-1])]
1766
+ setattr(member, name, np.pad(signal, pad))
1767
+ padded.append(member)
1768
+ return padded
1769
+
1650
1770
  def _batch_members(self, sources: Sequence[fullwave.Source]) -> list[fullwave.Source]:
1651
1771
  """Check the transmits of a batch against the Solver's source and return them.
1652
1772
 
@@ -1730,7 +1850,10 @@ class Solver:
1730
1850
  return f"the {kind} signal is present in only one of them"
1731
1851
  if expected is None:
1732
1852
  continue
1733
- if np.shape(found) != np.shape(expected):
1853
+ if (
1854
+ np.shape(found)[:-1] != np.shape(expected)[:-1]
1855
+ or np.shape(found)[-1] < np.shape(expected)[-1]
1856
+ ):
1734
1857
  return f"the {kind} signal shape {np.shape(found)} != {np.shape(expected)}"
1735
1858
  expected_coords = getattr(self.source, coords, None)
1736
1859
  found_coords = getattr(member, coords, None)