- ...
- Added
pyr_max_side_ldtoModulatedPyramidand its derived classes to cap the radial support of the pyramid surface in lambda/D units, forcing values outside the support radius to zero and enabling a central fifth pupil. - Added
compute_single_im(bool, default True) toImCalibratorto optionally skip populating theout_single_imper-mode output (the output itself is always present, empty when disabled). When True (default, unchanged behavior) this costs an O(nmodes) Python loop on everytrigger_code()call (not just push-pull events) plus roughly double the fixed memory (one extra Intmat per mode); set to False to skip that loop/memory when nothing downstream consumesout_single_im(onlyout_intmatis used elsewhere in this codebase) -- needed for large-nmodes, long calibrations.
IFunc.inverse()now computes the pseudoinverse via the smaller of the two Gram matrices (specula.lib.fast_pinv) instead of callingxp.linalg.pinvdirectly on the full influence-function matrix. Mathematically identical result (including in the rank-deficient case), but substantially faster for the typical case of many pixels and few modes -- measured 3x-8x on real KL/zonal influence-function bases, with the speedup growing with pixel count. Added test_fast_pinv.py.
- Added IntValue, FloatValue and StringValue as specialized containers for scalars and strings, to be used in place of BaseValue where needed.
- Added DisplayRecorder processing object
- Added Phasescreen data object.
- Added Phase Extractor processing object.
- Added CLOSE gain optimizer processing object.
- Added RoundToMultiple processing object.
- Added EfReplay class (specula.ef_replay): replays a list of existing ElectricField/Layer outputs (e.g. an ElectricFieldCombinator or a DM's out_layer) exactly as they were in a past run, by targeting the existing object(s) directly with Simul.build_targeted_replay instead of synthesizing new off-axis sources like FieldAnalyser does. Complements FieldAnalyser for cases where a disturbance was injected downstream of AtmoPropagation (see FieldAnalyser's new "Limitation" tutorial section) and the exact original direction/sensor is what's needed. Added docs/tutorials/ef_replay_tutorial.rst and test_ef_replay.py
- Removed simul_params argument from IirFilter, Integrator and other related processing objects
- Outputs for SpeculaInput and derived objects like TerminalInput must be typed with :int, :float or :str
- Added "window" and "subplot" arguments to all displays to enable multi-plot windows
- Renamed MmsePistonUnwrapper to SoftLimiter and moved the module to specula.processing_objects.soft_limiter
- Added stroke thresholding for dm class
- Added open_loop_estimate parameter to OpticalGainEstimator.
- Enabled start and end time (start_time and end_time parameters) in FieldAnalyser.
- Added "out_window_id" output to all displays to support video recording
- Added "beam_center" for uplink beam in pixel. Used for Fresnel propagation to indicate if beam is not located in the center.
- Added pupil_mask parameter to SprintShSynim, forwarded to BaseSprintEstimator as the WFS-side pupil (previously silently fell back to dm.mask, e.g. missing spider obscuration); added regression test in test_sprint.py
- Enabled pyr_tlt_coeffs for the modulated_pyramid, allowing to correctly set different tilt coefficients for the pyramid faces
- Extracted FieldAnalyser's shared replay machinery (params loading, replay precision/downsampling checks, temp-simulation execution) into a new BaseReplayAnalyser base class, reused by EfReplay; pure refactor, no behavior change (mock patch targets for Simul/specula in test_field_analyser.py moved to specula.base_replay_analyser accordingly)
- Added "out_slopes_map" output to Slopec (and thus to all its subclasses, e.g. PyrSlopec, ShSlopec): a 2d remap of the slopes vector (shape (2, size_x, size_y) for a single subaperture, reusing the existing single_mask/display_map/get2d() machinery), useful to store slopes in DataStore with a (timesteps, 2, size_x, size_y) shape instead of a flat vector. Added "out_pixels_subap" (raw, pre-threshold pixel intensities of the 4 pyramid pupils, shape (4, size_x, size_y)) and "out_pixels_subap_sum" (their sum, shape (size_x, size_y), e.g. for scintillation analysis) outputs to PyrSlopec. Added PupData.local_display_map() helper. No changes needed to DataStore, which already saves whatever shape an output's get_value() returns.
- Fixed Simul.build_targeted_replay/FieldAnalyser silently dropping disturbances injected downstream of the replay target via ElectricFieldCombinator/PhaseScreenCube (SPECULA #696: e.g. a phase screen summed onto an AtmoPropagation source's output before the WFS), which could bias off-axis FieldAnalyser results with a spurious, direction-independent term. build_targeted_replay now raises ValueError by default (opt-out via on_missing_downstream_consumers='warn'/'ignore') when such a silently-dropped ElectricField/Layer-producing consumer is detected; FieldAnalyser exposes the same on_missing_downstream_consumers parameter (default 'error'). Added regression tests in test_simul.py and test_field_analyser.py, and a new "Limitation" section in docs/tutorials/field_analyser_tutorial.rst
- Fixed RandomGenerator objects with no explicit
seednot being reproducible across a replay (e.g. via Simul.build_targeted_replay/FieldAnalyser): the actually-resolved seed is now recorded in replay_params.yml at the end of a run and re-injected on replay (Simul.inject_recorded_seeds), leaving fresh, non-replay runs unaffected (still ambient-random by default). Added RandomGenerator.get_resolved_seed() / BaseProcessingObj.get_resolved_seed() hook and DataSource random_seeds parameter; added tests in test_generators.py, test_simul.py and test_field_analyser.py - Fixed BaseOperation using stale/uninitialized input values when in_value1 or in_value2 had never been generated
- Fixed vecWeiPixRadT extraction in ShSlopec
- Fixed output_names in PhaseScreenCube
- Fixed PhaseScreenCube crash on GPU due to np.searchsorted called on a cupy array
- Fixed start_time bug in WindowedIntegration
- Fixed SprintShSynim's _plot_debug_info passing GPU (cupy) arrays directly to matplotlib without cpuArray() conversion, crashing on GPU
- Corrected SprintShSynim's docstring/perturbation labels for enable_wpup_magn_xy: params [4]/[5] are anamorphosis_90/anamorphosis_45 (functional in SynIM via compute_im_synim), not independent magn_x/magn_y as previously (incorrectly) documented as "not yet implemented"
- Added regression test (test_sprint_anamorphic_magnification_is_functional) verifying enable_wpup_magn_xy's anamorphosis_90/anamorphosis_45 parameters actually affect the computed nominal IM
- SPRINT logger lever changed to debug for intermediate steps
- Bumped synim requirement to 1.2.3 (was 1.1.3)
- Optimization of the compute_ifs_covmat function
- Added Fraunhofer far field propagation
- Fixed silent misparsing/confusing errors in split_output() when an object, alias or output name contained a reserved '.', '-' or ':' character; added early validation of YAML section names in Simul
- Fixed A size in get_pyr_tlt, adding a round (rather than flooring by default) to avoid cases where the pyramid tilt mask (pyr_tlt) and the focal plane mask (fp_mask) could be of different sizes when using an odd number of pixels across the pupil
- Updated calculation of power loss such that reference PSF also uses Fresnel propagation
- Fixed ModulatedPyramid/ModulatedDoubleRoof.calc_pyr_geometry producing pupils smaller than the requested pup_diam pixels whenever pup_dist was large enough to trigger the fft_res_min increase (roughly pup_dist > 1.73 * pup_diam with default pup_margin): fft_totsize grew with the bumped fft_res, but toccd_side (the internal CCD side the FFT-plane pupils are rebinned to via toccd()) stayed frozen at the value computed from the pre-bump, nominal fft_res, shrinking the sub-pupils after rebinning. toccd_side is now recomputed from the final fft_res returned by calc_geometry. Added regression test in test_pyr.py
- CiaoCiao WFS and slope computer
- Chromatic effects in atmospheric propagation
- Phasescreen cube processing object
- SpatioTempArray data object
- Interactive inputs, dynamic versions of pupil calibrators and dark calibrators for hardware-in-the-loop simulations
- Multi-rate modal reconstructor: selection of multiple reconstruction matrices depending on which inputs are valid at a given time
- Multi-rate complementary filter
- Separated modal reconstructor with explicit Pseudo-Open Loop algorithm into its own processing object
- PupilstopController: processing object for generation of pupilstop-like layers
- MMSE piston unwrapper processing object
- Added script to plot influence functions
- New parameters and interface changes:
- Using the standard Python logging module instead of print(), verbose parameters removed, added --log-level command line argument
- Added optional downsampling in DataStore
- FieldAnalyzer support custom influence functions and optional displays
- Added band limit factor in AtmoPropagation
- Added layer height parameter in AtmoRandomPhase
- ElectrictFieldCombinator optionally accepts an input EF list instead of two separate EFs
- Added scaling factor to PhaseScreenCube
- Added computation of PSF profile and metrics to Psf and PsfCoronograph
- Added optional wavelength parameter (and tolerance) in ElectricField
- Removed value2_is_shorter parameter from BaseOperation, now automatically derived
- Removed unused parameters tag_template from rec, subap and sn calibrators.
- Other updates and bugfixes:
- Support for python 3.14
- Changed phase unwrapping algorithm in ModalAnalysis, can run on GPU as well
- Fixed SH-like normalzation in pyramid slope computer
- Fixed #380 (wrong error message during initialization)
- Calculation precision handling
- Fixed SynIM dependency to version 1.1.3
- remove_piston flag in IFunc inverse method
- Many other minor bugfixes