API Reference
- class kdellipspy.AxitraForwardModel(input_ctl_path: str, axitra_dir: str | None = None)[source]
Bases:
objectForward model using axitra python wrapper.
Main workflow: 1) Build invariant geometry from input.ctl 2) Apply ellipse model (a1,a2,theta,np,tp,dmax,vr) 3) Build Axitra instance with model/stations/sources 4) Compute Green functions: moment.green(ap) 5) Convolve: moment.conv(ap, hist, …)
- apply_ellipse_model_to_geometry(geometry: FaultGeometry, model: numpy.ndarray, keep_all_sources: bool = False) FaultGeometry[source]
Apply 7-parameter ellipse model to an existing geometry instance.
keep_all_sources=Truekeeps the full source set (zero moment outside the ellipse) so the Green’s functions can be cached for the fixed mesh.
- build_axitra(geometry: FaultGeometry, fmax: float | None = None, duration: float | None = None, xl: float = 0.0, latlon: bool = True, freesurface: bool = True, ikmax: int = 100000, id: int | None = None, aw: float | None = 0.5)[source]
- build_geometry(slip_geom: float = 1.0) FaultGeometry[source]
- build_geometry_with_ellipse_slip(model: numpy.ndarray) FaultGeometry[source]
Build fault geometry with ellipse-to-subfault slip mapping.
- Model parameters (7):
model[0]: a1 - semi-axis 1 (km) model[1]: a2 - semi-axis 2 (km) model[2]: theta - rotation angle (fraction of pi) model[3]: np - position fraction [0,1] model[4]: tp - position angle (fraction of 2pi) model[5]: dmax - maximum slip (m) model[6]: vr - rupture velocity (km/s)
- Returns:
FaultGeometry with slip distribution applied from ellipse parameters.
- conv(ap, geometry: FaultGeometry, source_type: int | None = None, t0: float | None = 3, t1: float = 0.0, unit: int | None = None, sfunc=None, quiet: bool = True)[source]
- estimate_total_moment_and_mw(model: numpy.ndarray, geometry: FaultGeometry | None = None) Tuple[float, float][source]
Estimate total scalar moment (N.m) and Mw for a 7-parameter ellipse model.
- classmethod from_config(cfg: ConfigParser, axitra_dir: str | None = None) AxitraForwardModel[source]
Create AxitraForwardModel directly from a ConfigParser object. (Crea AxitraForwardModel directamente desde un objeto ConfigParser.)
- classmethod from_params(params: dict, axitra_dir: str | None = None) AxitraForwardModel[source]
Create AxitraForwardModel from a dictionary of parameters instead of an input.ctl file.
This allows building the forward model programmatically without file I/O.
Parameters:
- paramsdict
Dictionary containing all configuration sections: - ‘observed_data’: Dictionary with time window and sampling parameters - ‘source_position’: Dictionary with event location and focal mechanism - ‘fault_plane’: Dictionary with fault geometry discretization - ‘ellipse’: Dictionary with ellipse model and frequency band - ‘inversion_params’: Dictionary with inversion parameter ranges - ‘inversion_process’: Dictionary with algorithm settings - ‘moment_tensor’: Dictionary with moment tensor components - ‘stations’: List of station dictionaries (lat, lon, height, name, use_n, use_e, use_z) - ‘velocity_model’: List of velocity layer dictionaries
- axitra_dirstr, optional
Path to axitra directory. If not provided, assumes it’s a sibling folder.
Returns:
- AxitraForwardModel
Initialized forward model instance with all configuration loaded from params.
Example:
>>> params = { ... 'observed_data': {'Time window start (t1)': 0.0, ...}, ... 'source_position': {'Latitude': -20.0, 'Longitude': -70.0, ...}, ... 'fault_plane': {'Length along strike (Lx)': 100000.0, ...}, ... 'ellipse': {'Number of ellipses': 1, ...}, ... 'stations': [ ... {'latitude': -19.5, 'longitude': -69.5, 'height': 0.0, 'name': 'SL01'}, ... ... ... ], ... 'velocity_model': [ ... {'thickness': 10000.0, 'vp': 5500.0, 'vs': 3200.0, 'rho': 2700.0, 'qp': 100.0, 'qs': 50.0}, ... ... ... ], ... 'inversion_params': {...}, ... 'inversion_process': {...}, ... 'moment_tensor': {...}, ... } >>> fm = AxitraForwardModel.from_params(params, axitra_dir='/path/to/axitra')
- plot(synthetic: numpy.ndarray, time: numpy.ndarray | None = None, show: bool = True, save_path: str | Path | None = None, dpi: int = 300)[source]
Plot synthetic seismograms generated by this forward model. (Grafica los sismogramas sintéticos generados por este modelo forward.)
- select_source_function() dict[source]
Interactive prompt to select source time function, rise time and output type, mirroring the axitra Fortran convms behavior.
- Source types (passed directly to moment.conv as source_type):
0 : Dirac 1 : Ricker -> requires rise time (t0) 2 : Smooth step -> requires rise time (t0) 3 : From file <axi_id.sou> -> sfunc array must be supplied externally 4 : Triangle -> requires rise time (t0) 5 : Ramp -> requires rise time (t0) 7 : True step -> requires rise time (t0) 8 : Trapezoid -> requires rise time (t0) AND flat time (t1) +10: compute only the source time function, no convolution
- Returns a dict with keys:
source_type : int (may include +10 flag) t0 : float (rise time, or delta for Dirac) t1 : float (flat time for Trapezoid, 0.0 otherwise) unit : int (1=disp, 2=vel, 3=acc) sfunc : None (caller must set this for source_type=3)
- class kdellipspy.BaseInversionModel(input_ctl_path: str | Path | None = None, axitra_dir: str | Path | None = None, observed_waveforms: numpy.ndarray | None = None, time_array: numpy.ndarray | None = None, azi_times_array: numpy.ndarray | None = None, axitra_aw: float = 0.5, axitra_ikmax: int = 100000, config: ConfigParser | None = None)[source]
Bases:
objectAbstract base class for kinematic inversion drivers (NA and MCMC). (Clase base abstracta para los motores de inversión cinemática NA y MCMC.)
Sub-classes must call
super().__init__(...)and then implement eitherrun_na_searchorrun_mcmc_search.- Parameters:
- best_synthetics
- Type:
np.ndarray | None — Updated whenever a new best misfit is found
- clear_green_cache() None[source]
Clean up the cached Green’s-function axitra files (call at end of run).
- classmethod from_config(config: ConfigParser, axitra_dir: str | Path | None = None, observed_waveforms: numpy.ndarray | None = None, time_array: numpy.ndarray | None = None, azi_times_array: numpy.ndarray | None = None, **kwargs) BaseInversionModel[source]
Create an inversion model directly from a ConfigParser object.
- classmethod from_params(params: Dict[str, Any], axitra_dir: str | Path | None = None, observed_waveforms: numpy.ndarray | None = None, time_array: numpy.ndarray | None = None, azi_times_array: numpy.ndarray | None = None, **kwargs) BaseInversionModel[source]
Create an inversion model from a dictionary of parameters.
- objective_function(model: numpy.ndarray) float[source]
Evaluate the forward model and return L2 misfit for one parameter vector. (Evalúa el modelo forward y retorna el desajuste L2 para un vector de parámetros.)
Side-effects
Updates
self._best_misfit_seenandself.best_syntheticswhen improved.Cleans axitra temporary files unless the active config sets
keep_axitra_files=True.
- class kdellipspy.ConfigParser(filepath: str | Path | None = None)[source]
Bases:
objectParses and stores the inversion configuration from the ‘input.ctl’ file.
- classmethod from_dict(params: Dict[str, Any]) ConfigParser[source]
Create a ConfigParser instance from a dictionary of parameters.
- class kdellipspy.DataPreprocessor(cfg: ConfigParser)[source]
Bases:
objectUtility to prepare raw seismic data for axitra inversion. (Utilidad para preparar datos sísmicos crudos para la inversión con axitra.)
- plot_record_section(raw_dir: Path, t_start: Any | None = None, t_end: Any | None = None, freqmin: float = 0.05, freqmax: float = 0.5, scale: float = 2.0, components: List[str] = ['Z'], station_names: List[str] | None = None)[source]
Visualizes waveforms from SAC files in a record section, similar to the provided notebook. (Visualiza formas de onda de archivos SAC en una sección de registro, similar al notebook proporcionado.)
- process_raw_files(raw_dir: Path, output_dir: Path, freq1: float, freq2: float, t_start: Any = 0.0, t_end: Any | None = None, data_start_time: Any | None = None, units: int = 2, station_indices: List[int] | None = None, station_names: List[str] | None = None) Dict[str, numpy.ndarray][source]
Loads concatenated raw velocity files, filters, trims with zero-padding, and saves Axitra-ready files. Supports UTCDateTime or float for timing.
If station_names is provided, it filters the stations by name. (Si se proporciona station_names, filtra las estaciones por nombre.)
- class kdellipspy.DynamicInversionConfig(dynamic_root: 'Optional[str | Path]' = None, compile_sources: 'bool' = False, input_file: 'str' = 'input_dynamic_ellipse.txt', run_script: 'str' = 'run_dyn_inversion.sh', compile_script: 'str' = 'compile_dyn_src.sh', event_dir: 'str' = 'Evento')[source]
Bases:
object- compile_script: str = 'compile_dyn_src.sh'
- compile_sources: bool = False
- dynamic_root: str | Path | None = None
- event_dir: str = 'Evento'
- input_file: str = 'input_dynamic_ellipse.txt'
- run_script: str = 'run_dyn_inversion.sh'
- class kdellipspy.DynamicInversionModel(dynamic_root: str | Path | None = None)[source]
Bases:
object- run_dynamic_search(config: DynamicInversionConfig | None = None) dict[source]
- class kdellipspy.EllipseParams(num_ellipses: int, initial_slip: int, slip_shape: int, freq1: float, freq2: float, t0: float, source_type: int, zerophase: bool = True)[source]
Bases:
objectSection 4: Ellipse Parameters & Frequency Band
- freq1: float
- freq2: float
- classmethod from_dict(params: Dict) EllipseParams[source]
- initial_slip: int
- num_ellipses: int
- slip_shape: int
- source_type: int
- t0: float
- zerophase: bool = True
- class kdellipspy.EllipticalSlipMapper(config: ConfigParser)[source]
Bases:
objectApply ellipse-based slip factors to fault geometry source points.
- apply_to_geometry(geom: FaultGeometry, model: numpy.ndarray, keep_all_sources: bool = False) FaultGeometry[source]
Apply the ellipse slip model to
geom.When
keep_all_sourcesis True the source-point set is NOT pruned to the subfaults inside the ellipse: every source point is kept with zero moment/slip outside the ellipse. This keeps the source set (positions and indices) constant across models, which lets the caller compute the Green’s functions once for the full mesh and reuse them viaconv.
- class kdellipspy.FaultGeometry(length_strike_m: float, length_dip_m: float, hypo_strike_m: float, hypo_dip_m: float, nx: int, ny: int, strike_deg: float, dip_deg: float, rake_deg: float, source_depth_m: float, source_lat: float, source_lon: float, rupture_velocity_km_s: float, mt_enabled: bool, subfaults: List[kdellipspy.core.geometry.Subfault], source_points: List[kdellipspy.core.geometry.SourcePoint])[source]
Bases:
object- dip_deg: float
- hypo_dip_m: float
- hypo_strike_m: float
- length_dip_m: float
- length_strike_m: float
- moment_magnitude_mw() float[source]
Return moment magnitude Mw from total moment (Hanks & Kanamori, M0 in N.m).
- mt_enabled: bool
- property nsources: int
- property nsubfaults: int
- nx: int
- ny: int
- plot(title: str = '2D Slip Distribution', show: bool = True, save_path: str | None = None) Tuple[Any, Any][source]
Visualización 2D de la distribución de slip interpolada.
- rake_deg: float
- rupture_velocity_km_s: float
- source_depth_m: float
- source_lat: float
- source_lon: float
- source_points: List[SourcePoint]
- strike_deg: float
- class kdellipspy.FaultPlaneParams(lx: float, ly: float, hx: float, hy: float, nx: int, ny: int)[source]
Bases:
objectSection 3: Fault Plane Parameters
- classmethod from_dict(params: Dict) FaultPlaneParams[source]
- hx: float
- hy: float
- lx: float
- ly: float
- nx: int
- ny: int
- class kdellipspy.GeometryBuilder(config: ConfigParser)[source]
Bases:
objectBuild fault geometry from input.ctl through ConfigParser.
- build(slip_geom: float = 1.0) FaultGeometry[source]
- classmethod from_config(config: ConfigParser) GeometryBuilder[source]
- classmethod from_input_ctl(input_ctl_path: str) GeometryBuilder[source]
- classmethod from_params(params: dict) GeometryBuilder[source]
- class kdellipspy.InversionParam(name: str, min_val: float, max_val: float, flag: int)[source]
Bases:
objectSingle parameter for inversion
- flag: int
- max_val: float
- min_val: float
- name: str
- class kdellipspy.InversionParams(parameters: List[InversionParam])[source]
Bases:
objectSection 5: Parameters to Invert
- classmethod from_dict(params: Dict, param_lines: List[str]) InversionParams[source]
- parameters: List[InversionParam]
- class kdellipspy.InversionProcessParams(algorithm_type: int, num_iterations: int, ss1: int, ss_other: int, cells_resample: int, misfit_time_window: float = 0.0, n_jobs: int = 1, mcmc_total_steps: int = 500, mcmc_burn_in: int = 0, mcmc_proposal_scale: float = 0.08, mcmc_thin: int = 1, mcmc_chains: int = 1)[source]
Bases:
objectSection 6: Inversion Process Parameters
- algorithm_type: int
- cells_resample: int
- classmethod from_dict(params: Dict) InversionProcessParams[source]
- mcmc_burn_in: int = 0
- mcmc_chains: int = 1
- mcmc_proposal_scale: float = 0.08
- mcmc_thin: int = 1
- mcmc_total_steps: int = 500
- misfit_time_window: float = 0.0
- n_jobs: int = 1
- num_iterations: int
- ss1: int
- ss_other: int
- class kdellipspy.MCMCConfig(total_steps: int = 500, burn_in: int = 0, proposal_scale: float = 0.08, thin: int = 1, random_seed: int | None = None, keep_axitra_files: bool = False, chains: int = 1)[source]
Bases:
objectHyperparameters for the MCMC search with PyMC + ArviZ. (Hiperparámetros para la búsqueda MCMC con PyMC + ArviZ.)
PyMC runs a Metropolis sampler with a uniform prior on the parameter box. ArviZ is used for posterior summary statistics.
- total_steps
- Type:
Total number of MCMC steps per chain (tune + draws)
- burn_in
- Type:
Number of tuning steps (excluded from posterior)
- proposal_scale
each parameter’s range, e.g. 0.08 → 8 % of width per param
- Type:
Metropolis proposal standard deviation as a fraction of
- thin
- Type:
Thinning factor applied to the posterior draws
- random_seed
- Type:
Optional seed for reproducibility
- keep_axitra_files
- Type:
Keep temporary axitra files (useful for debugging)
- chains
Warning: chains > 1 may fail when axitra uses shared temp files.
- Type:
Number of parallel MCMC chains.
- burn_in: int = 0
- chains: int = 1
- keep_axitra_files: bool = False
- proposal_scale: float = 0.08
- random_seed: int | None = None
- thin: int = 1
- total_steps: int = 500
- class kdellipspy.MCMCInversionModel(input_ctl_path: str | Path | None = None, axitra_dir: str | Path | None = None, observed_waveforms: numpy.ndarray | None = None, time_array: numpy.ndarray | None = None, azi_times_array: numpy.ndarray | None = None, axitra_aw: float = 0.5, axitra_ikmax: int = 100000, config: ConfigParser | None = None)[source]
Bases:
BaseInversionModelKinematic Inversion Model using MCMC (Metropolis, PyMC + ArviZ). (Modelo de Inversión Cinemática usando MCMC — PyMC + ArviZ.)
Integrates observed data, arrival times, and event configuration to sample the posterior distribution of kinematic rupture model parameters. (Integra los datos observados, tiempos de llegada y configuración del evento para muestrear la distribución posterior de los parámetros del modelo cinemático.)
- Parameters:
input_ctl_path (Path to input.ctl configuration file (optional if config is provided))
axitra_dir (Path to axitra binary directory (optional))
observed_waveforms (3-component seismograms, shape (nsta, 3, npts))
time_array (Time vector, shape (npts,))
azi_times_array (P/S arrival time table, shape (nsta, 3))
config (ConfigParser object (optional if input_ctl_path is provided))
- best_synthetics
Synthetic seismograms of the best model found so far (nsta, 3, npts).
- Type:
np.ndarray | None
Example
>>> # Using a config file path: >>> model = MCMCInversionModel( ... "path/to/run/input.ctl", ... axitra_dir="path/to/axitra", ... observed_waveforms=obs, ... time_array=t, ... azi_times_array=azi, ... ) >>> # Or using a ConfigParser object: >>> cfg = ConfigParser("path/to/input.ctl") >>> model = MCMCInversionModel( ... config=cfg, ... observed_waveforms=obs, ... time_array=t, ... azi_times_array=azi, ... ) >>> result = model.run_mcmc_search() >>> print(result.best_model.misfit)
- run_mcmc_search(mc_config: MCMCConfig | None = None) NAResult[source]
Run the PyMC Metropolis sampler and return posterior models. (Ejecuta el muestreador Metropolis de PyMC y retorna los modelos posteriores.)
- Parameters:
mc_config (MCMCConfig, optional) – MCMC hyperparameters. If
None, values are read fromself.cfg.inversion_process(input.ctl).- Returns:
Container with posterior samples, the best model (minimum misfit), ArviZ summary in
extra_metadata, and JSON/CSV export helpers.- Return type:
- Raises:
ImportError – If
pymc(orarviz/pytensor) is not installed.ValueError – If
burn_in >= total_steps.
- class kdellipspy.MisfitCalculator(observed_waveforms: numpy.ndarray, time_array: numpy.ndarray, azi_times_path: Path | None = None, azi_times_array: numpy.ndarray | None = None, time_window_s: float = 20.0, station_flags: numpy.ndarray | None = None)[source]
Bases:
objectL2 waveform misfit calculator with P/S arrival-time windows. (Calculador de desajuste L2 de formas de onda con ventanas de llegada P/S.)
- Parameters:
- class kdellipspy.MomentTensor(flag: int, mrr: float, mtt: float, mpp: float, mrt: float, mrp: float, mtp: float, exponent: float, scaling_mode: str = 'no_mt')[source]
Bases:
objectSection 7: Moment Tensor (Full MT)
- exponent: float
- flag: int
- classmethod from_dict(params: Dict) MomentTensor[source]
- mpp: float
- mrp: float
- mrr: float
- mrt: float
- mtp: float
- mtt: float
- scaling_mode: str = 'no_mt'
- class kdellipspy.NAConfig(n_samples_initial: int = 30, n_samples_iteration: int = 30, n_iterations: int = 10, n_cells_resample: int = 7, n_jobs: int = 1, random_seed: int | None = None, keep_axitra_files: bool = False)[source]
Bases:
objectHyperparameters for the Neighbourhood Algorithm search. (Hiperparámetros para la búsqueda con el Algoritmo Neighbourhood.)
- n_samples_initial
- Type:
Number of random samples drawn in the first iteration (ni)
- n_samples_iteration
- Type:
Samples drawn around the best Voronoi cells per iteration (ns)
- n_iterations
- Type:
Number of NA iterations after the initial random stage (n)
- n_cells_resample
- Type:
Number of best Voronoi cells to resample from (nr)
- n_jobs
- Type:
Number of parallel workers for objective function evaluation (-1 for all)
- random_seed
- Type:
Optional seed for reproducibility
- keep_axitra_files
- Type:
Keep temporary axitra files (useful for debugging)
- keep_axitra_files: bool = False
- n_cells_resample: int = 7
- n_iterations: int = 10
- n_jobs: int = 1
- n_samples_initial: int = 30
- n_samples_iteration: int = 30
- random_seed: int | None = None
- class kdellipspy.NAInversionModel(input_ctl_path: str | Path | None = None, axitra_dir: str | Path | None = None, observed_waveforms: numpy.ndarray | None = None, time_array: numpy.ndarray | None = None, azi_times_array: numpy.ndarray | None = None, axitra_aw: float = 0.5, axitra_ikmax: int = 100000, config: ConfigParser | None = None)[source]
Bases:
BaseInversionModelKinematic Inversion Model using the Neighbourhood Algorithm (NA). (Modelo de Inversión Cinemática utilizando el Algoritmo Neighbourhood — NA.)
Integrates observed data, arrival times, and event configuration to evaluate kinematic rupture models. Communicates with axitra to simulate synthetic seismograms and compute misfit against real data. (Integra los datos observados, tiempos de llegada y configuración del evento para evaluar distintos modelos de ruptura cinemática. Se comunica con axitra para simular sismogramas sintéticos y calcular el desajuste con los datos reales.)
- Parameters:
input_ctl_path (Path to input.ctl configuration file (optional if config is provided))
axitra_dir (Path to axitra binary directory (optional))
observed_waveforms (3-component seismograms, shape (nsta, 3, npts))
time_array (Time vector, shape (npts,))
azi_times_array (P/S arrival time table, shape (nsta, 3))
config (ConfigParser object (optional if input_ctl_path is provided))
- best_synthetics
Synthetic seismograms of the best model found so far (nsta, 3, npts). Set to None until the first objective function evaluation.
- Type:
np.ndarray | None
- param_names
- Type:
List[str] — Human-readable parameter labels
- param_ranges
- Type:
np.ndarray, shape (n_params, 2) — [min, max] per parameter
Example
>>> # Using a config file path: >>> model = NAInversionModel( ... "path/to/run/input.ctl", ... axitra_dir="path/to/axitra", ... observed_waveforms=obs, ... time_array=t, ... azi_times_array=azi, ... ) >>> # Or using a ConfigParser object: >>> cfg = ConfigParser("path/to/input.ctl") >>> model = NAInversionModel( ... config=cfg, ... observed_waveforms=obs, ... time_array=t, ... azi_times_array=azi, ... ) >>> result = model.run_na_search() >>> print(result.best_model.misfit)
- run_na_search(na_config: NAConfig | None = None) NAResult[source]
Run the Neighbourhood Algorithm search and return all sampled models. (Ejecuta la búsqueda con el Algoritmo Neighbourhood y retorna todos los modelos.)
- Parameters:
na_config (NAConfig, optional) – Search hyperparameters. If
None, values are read fromself.cfg.inversion_process(input.ctl).- Returns:
Container with every evaluated model, the best model, and JSON/CSV export helpers.
- Return type:
- Raises:
ImportError – If
neighpyis not installed.
- class kdellipspy.NAModel(model: numpy.ndarray, misfit: float, iteration: int)[source]
Bases:
objectSingle sampled model and its objective value. (Modelo muestreado individual y su valor objetivo.)
- model
- Type:
Parameter vector (np.ndarray)
- misfit
- Type:
Objective/misfit value (float)
- iteration
- Type:
Iteration index at which this model was sampled (int)
- iteration: int
- misfit: float
- model: numpy.ndarray
- class kdellipspy.NAResult(all_models: List[NAModel], param_names: Sequence[str] | None = None, extra_metadata: Dict[str, Any] | None = None, best_synthetics: numpy.ndarray | None = None, observed: numpy.ndarray | None = None, time: numpy.ndarray | None = None, config: ConfigParser | None = None, azi_times_array: numpy.ndarray | None = None)[source]
Bases:
objectContainer for all sampled models with export helpers. (Contenedor de todos los modelos muestreados con exportadores.)
- Parameters:
all_models (List of NAModel instances)
param_names (Parameter name labels (optional, defaults to 7-param names))
extra_metadata (Algorithm-specific metadata written to JSON export)
best_synthetics (Synthetic waveforms of the best model (optional))
observed (Observed waveforms used for inversion (optional))
time (Time array used for inversion (optional))
config (ConfigParser instance (optional))
- export_csv(filepath: Path) None[source]
Export all models as CSV (iteration, misfit, param columns). (Exporta todos los modelos como CSV con columnas de iteración, misfit y parámetros.)
- export_results(filepath: Path) None[source]
Export all models + metadata as JSON. (Exporta todos los modelos y metadatos como JSON.)
- plot(show: bool = True, save_path: str | None = None) Tuple[Any, Any][source]
Grafica el resumen de resultados de la búsqueda NA.
- plot_appraisal(samples: np.ndarray | None = None, show: bool = True, save_path: str | None = None, bins: int = 40, title: str | None = None, **run_kwargs: Any) Tuple[Any, Any][source]
Corner plot of the posterior uncertainty (1D marginals + 2D trade-offs). (Gráfico ‘corner’ de la incertidumbre: marginales 1D y trade-offs 2D.)
If
samplesis not given and the appraisal has not been run yet, it is executed viarun_appraisal()(extra kwargs are forwarded there, e.g.n_resample,temperature,seed).
- plot_azimuthal(show: bool = True, save_path: str | None = None, ax: Any | None = None) Tuple[Any, Any][source]
Diagrama polar (radar) de la cobertura azimutal de las estaciones respecto al epicentro, con el mayor hueco azimutal sombreado.
ax(eje polar) permite componerlo dentro deplot_yolo.
- plot_convergence(show: bool = True, save_path: str | None = None, fig: Any | None = None) Tuple[Any, Any][source]
Grafica la convergencia detallada por cada parámetro.
- plot_elipse(show: bool = True, save_path: str | None = None, title: str | None = None) Tuple[Any, Any][source]
Alias por compatibilidad con el nombre en español.
- plot_ellipse(show: bool = True, save_path: str | None = None, title: str | None = None, fig: Any | None = None) Tuple[Any, Any][source]
Grafica la distribución de slip de la elipse para el mejor misfit. Requiere que config y best_model estén presentes en el objeto.
- plot_ellipse_depth(show: bool = True, save_path: str | None = None) Tuple[Any, Any][source]
Secciones transversales de la elipse de slip en profundidad (estilo legacy plot_geometry): corte N–S y corte E–O, coloreados por slip, con hipocentro.
- plot_ellipse_map(show: bool = True, save_path: str | None = None, pad: float = 0.25, fig: Any | None = None) Tuple[Any, Any][source]
Mapa cartopy de la elipse de slip proyectada a la superficie (footprint coloreado por slip + borde + hipocentro + estaciones).
- plot_fit(show: bool = True, save_path: str | None = None, rotate: bool = True, mark_windows: bool = True, fig: Any | None = None) Tuple[Any, Any][source]
Grafica el mejor ajuste de formas de onda encontrado. Requiere que best_synthetics, observed y time estén presentes en el objeto.
Por defecto rota a R/T/Z y sombrea la ventana del misfit (P→R,Z ; S→T), consistente con cómo se calcula el misfit. Si no hay datos de azimut/ tiempos disponibles, cae a las componentes N/E/Z sin ventana.
- plot_misfit_breakdown(show: bool = True, save_path: str | None = None, window_s='auto', fig: Any | None = None) Tuple[Any, Any][source]
Visualiza la contribución al misfit por estación/componente (heatmaps).
- plot_yolo(save_path: str | Path = 'dashboard.pdf', show: bool = False, dpi: int = 200) Path | None[source]
🎲 YOLO: arma un DASHBOARD de una sola página con todos los paneles encajados (GridSpec):
┌───────────────── título (evento · misfit · Mw) ─────────────────┐ │ mapa elipse (cartopy) │ ajuste R/T/Z (7 est, ventanas)│ │ azimutal (radar) │ heatmap mf │ (panel alto) │ │ convergencia de parámetros │ appraisal (corner) │ └─────────────────────────────────────────────────────────────────┘
Cada panel se renderiza con su método y se compone como imagen, así se reaprovecha todo el código existente (cartopy, corner, etc.). El appraisal se corre automáticamente si no estaba.
- run_appraisal(n_resample: int = 20000, n_walkers: int = 1, temperature: float | None = None, bounds: numpy.ndarray | None = None, seed: int | None = None, verbose: bool = True, save: bool = True) numpy.ndarray | None[source]
Run the NA appraisal stage to approximate the posterior. (Ejecuta la etapa de ‘appraisal’ del NA para aproximar la posterior.)
Reuses the models already evaluated during the NA search (
all_models) and resamples their Voronoi cells withneighpy.NAAppraiser— it does NOT evaluate the forward model again. Populatesappraisal_samples,appraisal_meanandappraisal_covariance.- Parameters:
n_resample (length of the resampling random walk (more = smoother PDFs).)
n_walkers (parallel walkers (>1 uses neighpy's multiprocessing).)
temperature (misfit-to-log-posterior scale,
log_ppd = -misfit / T.) – IfNone,T = 2 * best_misfit(auto-scale). SMALLER T → narrower posterior (more trust in the data). NOTE: the misfit here is the normalized L2 misfit, not a noise-calibrated chi-square, sotemperatureimplicitly sets the assumed noise level. Tune it (or pass an explicit value) if you need calibrated uncertainties.bounds ((n_params, 2) optional; derived from the config if
None.)seed (forwarded to
NAAppraiser/NAAppraiser.run.)verbose (forwarded to
NAAppraiser/NAAppraiser.run.)save (forwarded to
NAAppraiser/NAAppraiser.run.)
- Returns:
Posterior ensemble, shape (n_samples, n_params), or
Noneifsave=False.- Return type:
np.ndarray | None
- class kdellipspy.ObservedDataParams(t1: float, t2: float, npts: int, delta: float, units: int)[source]
Bases:
objectSection 1: Observed Data Parameters
- delta: float
- classmethod from_dict(params: Dict) ObservedDataParams[source]
- npts: int
- t1: float
- t2: float
- units: int
- class kdellipspy.SourcePoint(index: int, subfault_index: int, x_m: float, y_m: float, z_m: float, rupture_time_s: float, moment: float = 0.0, displacement: float = 0.0, strike_deg: float = 0.0, dip_deg: float = 0.0, rake_deg: float = 0.0, width: float = 0.0, length: float = 0.0, mu_pa: float = 0.0, basis_slot: int = 0)[source]
Bases:
object- basis_slot: int = 0
- dip_deg: float = 0.0
- displacement: float = 0.0
- index: int
- length: float = 0.0
- moment: float = 0.0
- mu_pa: float = 0.0
- rake_deg: float = 0.0
- rupture_time_s: float
- strike_deg: float = 0.0
- subfault_index: int
- width: float = 0.0
- x_m: float
- y_m: float
- z_m: float
- class kdellipspy.SourcePosition(event_name: str, origin_time: str | None, latitude: float, longitude: float, depth: float, strike: float, dip: float, rake: float)[source]
Bases:
objectSection 2: Source Position & Focal Mechanism
- depth: float
- dip: float
- event_name: str
- classmethod from_dict(params: Dict) SourcePosition[source]
- latitude: float
- longitude: float
- origin_time: str | None
- rake: float
- strike: float
- class kdellipspy.StationGeometry(ref_lat: float, ref_lon: float, stations: List[kdellipspy.core.geometry.Station])[source]
Bases:
object- property nstations: int
- ref_lat: float
- ref_lon: float
- class kdellipspy.StationParams(stations: List[Station] = <factory>)[source]
Bases:
objectSection 8: Station Parameters
- classmethod from_lines(station_lines: List[str]) StationParams[source]
- class kdellipspy.Subfault(index: int, x_m: float, y_m: float, z_m: float, rupture_time_s: float, mu_pa: float = 0.0, area_m2: float = 0.0, slip_m: float = 0.0, lat: float = 0.0, lon: float = 0.0)[source]
Bases:
object- area_m2: float = 0.0
- index: int
- lat: float = 0.0
- lon: float = 0.0
- mu_pa: float = 0.0
- rupture_time_s: float
- slip_m: float = 0.0
- x_m: float
- y_m: float
- z_m: float
- class kdellipspy.UTMProjection(lat0_deg: float, lon0_deg: float)[source]
Bases:
objectUTM (Universal Transverse Mercator) projection using pyproj.
Automatically detects the UTM zone based on the center coordinates. Uses WGS84 ellipsoid for accurate geodetic transformations. This replaces the legacy Lambert conformal projection with a faster (C-native) and more standard approach.
- class kdellipspy.VelocityLayer(thickness: float, vp: float, vs: float, rho: float, qp: float, qs: float)[source]
Bases:
objectSingle velocity layer
- qp: float
- qs: float
- rho: float
- thickness: float
- vp: float
- vs: float
- class kdellipspy.VelocityModel(layers: List[VelocityLayer] = <factory>)[source]
Bases:
objectSection 9: Velocity Model 1D
- classmethod from_lines(layer_lines: List[str]) VelocityModel[source]
- layers: List[VelocityLayer]
- kdellipspy.bandpass_filter_waveforms(synthetic: numpy.ndarray, time: numpy.ndarray, freq1: float, freq2: float, corners: int = 4, zerophase: bool = True) numpy.ndarray[source]
Apply Butterworth bandpass filter to synthetic waveforms.
This ensures synthetic waveforms match the frequency band of observed data, maintaining consistency in the misfit calculation.
- Parameters:
synthetic – waveform array with shape (n_stations, 3, npts)
time – time array with shape (npts,)
freq1 – low frequency cutoff (Hz)
freq2 – high frequency cutoff (Hz)
corners – filter order (default 4 = 4th order)
zerophase – if True, apply filter forward-backward for zero phase distortion
- Returns:
filtered waveforms with same shape as input
- Return type:
filtered_synthetic
- Raises:
ValueError – if time array has < 2 points or freq2 >= Nyquist frequency
- kdellipspy.build_azi_times_array(input_ctl_path: str | Path | None = None, model_name: str = 'iasp91', p_shift_s: float = -1.0, s_shift_s: float = -1.0, use_iris: bool = False, config: ConfigParser | None = None) numpy.ndarray[source]
Build legacy-compatible azi_times values as an array with columns: [azimuth_rad, tP, tS].
This reproduces the old script behavior while avoiding IRIS network requirements by default (use_iris=False).
- kdellipspy.build_geometry_from_input_ctl(input_ctl_path: str, slip_geom: float = 1.0) FaultGeometry[source]
- kdellipspy.build_station_geometry(ref_lat: float, ref_lon: float, station_data: List[Tuple[str, float, float, float]]) StationGeometry[source]
- kdellipspy.integrate_waveforms(waveforms: numpy.ndarray, delta: float, baseline_samples: int | None = None, steps: int = 1) numpy.ndarray[source]
Integrate waveforms along the last axis using a digital filter (Matlab integraf.m logic). Cleanest results for seismic signals.
- Parameters:
waveforms – array with shape (…, npts)
delta – sampling interval in seconds
baseline_samples – Number of samples at the start for pre-event baseline correction.
steps – Number of integration steps (1 for velocity, 2 for displacement).
- Returns:
Integrated waveforms with the same shape as the input.
- kdellipspy.load_and_filter_observed_data(freq1: float | None = None, freq2: float | None = None, input_ctl_path: str | Path | None = None, data_dir: str | Path = 'DATA', prefer_raw: bool = False, config: ConfigParser | None = None) Tuple[numpy.ndarray, numpy.ndarray][source]
Load observed data with two supported user workflows:
Flat files in DATA: - real_disp_x/y/z (if input.ctl units=1) - real_vel_x/y/z (if input.ctl units=2) Each file must contain 2 columns: time and data, and total rows must be npts * nstations.
RAW files in DATA/RAW: - .sac or .mseed files - station name extracted from waveform metadata - bandpass filtering using input.ctl frequency band - response removal attempted when inventory files are present in RAW
- Returns:
ndarray with shape (n_stations, 3, npts) time_array: ndarray with shape (npts,)
- Return type:
observed_waveforms
- kdellipspy.parse_velocity_model(filepath: str) List[Dict[str, float]][source]
Compatibility helper for existing code path.
- kdellipspy.precompute_greens_functions(params, v_model)[source]
Compatibility shim for legacy calls.
- kdellipspy.read_input_ctl(filepath: str) Dict[str, Any][source]
Compatibility helper returning a flat dictionary used by the pipeline.
- kdellipspy.validate_input_ctl(filepath: str) Dict[str, Any][source]
Return a concise parse summary for smoke testing.
- kdellipspy.write_azi_times_file(input_ctl_path: str | Path | None = None, output_path: str | Path | None = None, model_name: str = 'iasp91', p_shift_s: float = -1.0, s_shift_s: float = -1.0, use_iris: bool = False, config: ConfigParser | None = None) Path[source]
Write Event/azi_times.txt with legacy-compatible 3-column format.
Core Configuration & Parsing
- class kdellipspy.core.config_parser.ConfigParser(filepath: str | Path | None = None)[source]
Bases:
objectParses and stores the inversion configuration from the ‘input.ctl’ file.
- classmethod from_dict(params: Dict[str, Any]) ConfigParser[source]
Create a ConfigParser instance from a dictionary of parameters.
- class kdellipspy.core.config_parser.EllipseParams(num_ellipses: int, initial_slip: int, slip_shape: int, freq1: float, freq2: float, t0: float, source_type: int, zerophase: bool = True)[source]
Bases:
objectSection 4: Ellipse Parameters & Frequency Band
- freq1: float
- freq2: float
- classmethod from_dict(params: Dict) EllipseParams[source]
- initial_slip: int
- num_ellipses: int
- slip_shape: int
- source_type: int
- t0: float
- zerophase: bool = True
- class kdellipspy.core.config_parser.FaultPlaneParams(lx: float, ly: float, hx: float, hy: float, nx: int, ny: int)[source]
Bases:
objectSection 3: Fault Plane Parameters
- classmethod from_dict(params: Dict) FaultPlaneParams[source]
- hx: float
- hy: float
- lx: float
- ly: float
- nx: int
- ny: int
- class kdellipspy.core.config_parser.InversionParam(name: str, min_val: float, max_val: float, flag: int)[source]
Bases:
objectSingle parameter for inversion
- flag: int
- max_val: float
- min_val: float
- name: str
- class kdellipspy.core.config_parser.InversionParams(parameters: List[InversionParam])[source]
Bases:
objectSection 5: Parameters to Invert
- classmethod from_dict(params: Dict, param_lines: List[str]) InversionParams[source]
- parameters: List[InversionParam]
- class kdellipspy.core.config_parser.InversionProcessParams(algorithm_type: int, num_iterations: int, ss1: int, ss_other: int, cells_resample: int, misfit_time_window: float = 0.0, n_jobs: int = 1, mcmc_total_steps: int = 500, mcmc_burn_in: int = 0, mcmc_proposal_scale: float = 0.08, mcmc_thin: int = 1, mcmc_chains: int = 1)[source]
Bases:
objectSection 6: Inversion Process Parameters
- algorithm_type: int
- cells_resample: int
- classmethod from_dict(params: Dict) InversionProcessParams[source]
- mcmc_burn_in: int = 0
- mcmc_chains: int = 1
- mcmc_proposal_scale: float = 0.08
- mcmc_thin: int = 1
- mcmc_total_steps: int = 500
- misfit_time_window: float = 0.0
- n_jobs: int = 1
- num_iterations: int
- ss1: int
- ss_other: int
- class kdellipspy.core.config_parser.MomentTensor(flag: int, mrr: float, mtt: float, mpp: float, mrt: float, mrp: float, mtp: float, exponent: float, scaling_mode: str = 'no_mt')[source]
Bases:
objectSection 7: Moment Tensor (Full MT)
- exponent: float
- flag: int
- classmethod from_dict(params: Dict) MomentTensor[source]
- mpp: float
- mrp: float
- mrr: float
- mrt: float
- mtp: float
- mtt: float
- scaling_mode: str = 'no_mt'
- class kdellipspy.core.config_parser.ObservedDataParams(t1: float, t2: float, npts: int, delta: float, units: int)[source]
Bases:
objectSection 1: Observed Data Parameters
- delta: float
- classmethod from_dict(params: Dict) ObservedDataParams[source]
- npts: int
- t1: float
- t2: float
- units: int
- class kdellipspy.core.config_parser.SourcePosition(event_name: str, origin_time: str | None, latitude: float, longitude: float, depth: float, strike: float, dip: float, rake: float)[source]
Bases:
objectSection 2: Source Position & Focal Mechanism
- depth: float
- dip: float
- event_name: str
- classmethod from_dict(params: Dict) SourcePosition[source]
- latitude: float
- longitude: float
- origin_time: str | None
- rake: float
- strike: float
- class kdellipspy.core.config_parser.Station(latitude: float, longitude: float, height: float, name: str, use_n: bool = True, use_e: bool = True, use_z: bool = True)[source]
Bases:
objectIndividual station parameters
- height: float
- latitude: float
- longitude: float
- name: str
- use_e: bool = True
- use_n: bool = True
- use_z: bool = True
- class kdellipspy.core.config_parser.StationParams(stations: List[Station] = <factory>)[source]
Bases:
objectSection 8: Station Parameters
- classmethod from_lines(station_lines: List[str]) StationParams[source]
- class kdellipspy.core.config_parser.VelocityLayer(thickness: float, vp: float, vs: float, rho: float, qp: float, qs: float)[source]
Bases:
objectSingle velocity layer
- qp: float
- qs: float
- rho: float
- thickness: float
- vp: float
- vs: float
- class kdellipspy.core.config_parser.VelocityModel(layers: List[VelocityLayer] = <factory>)[source]
Bases:
objectSection 9: Velocity Model 1D
- classmethod from_lines(layer_lines: List[str]) VelocityModel[source]
- layers: List[VelocityLayer]
- kdellipspy.core.config_parser.parse_velocity_model(filepath: str) List[Dict[str, float]][source]
Compatibility helper for existing code path.
Forward Modeling
- class kdellipspy.core.forward_model.AxitraForwardModel(input_ctl_path: str, axitra_dir: str | None = None)[source]
Bases:
objectForward model using axitra python wrapper.
Main workflow: 1) Build invariant geometry from input.ctl 2) Apply ellipse model (a1,a2,theta,np,tp,dmax,vr) 3) Build Axitra instance with model/stations/sources 4) Compute Green functions: moment.green(ap) 5) Convolve: moment.conv(ap, hist, …)
- apply_ellipse_model_to_geometry(geometry: FaultGeometry, model: numpy.ndarray, keep_all_sources: bool = False) FaultGeometry[source]
Apply 7-parameter ellipse model to an existing geometry instance.
keep_all_sources=Truekeeps the full source set (zero moment outside the ellipse) so the Green’s functions can be cached for the fixed mesh.
- build_axitra(geometry: FaultGeometry, fmax: float | None = None, duration: float | None = None, xl: float = 0.0, latlon: bool = True, freesurface: bool = True, ikmax: int = 100000, id: int | None = None, aw: float | None = 0.5)[source]
- build_geometry(slip_geom: float = 1.0) FaultGeometry[source]
- build_geometry_with_ellipse_slip(model: numpy.ndarray) FaultGeometry[source]
Build fault geometry with ellipse-to-subfault slip mapping.
- Model parameters (7):
model[0]: a1 - semi-axis 1 (km) model[1]: a2 - semi-axis 2 (km) model[2]: theta - rotation angle (fraction of pi) model[3]: np - position fraction [0,1] model[4]: tp - position angle (fraction of 2pi) model[5]: dmax - maximum slip (m) model[6]: vr - rupture velocity (km/s)
- Returns:
FaultGeometry with slip distribution applied from ellipse parameters.
- conv(ap, geometry: FaultGeometry, source_type: int | None = None, t0: float | None = 3, t1: float = 0.0, unit: int | None = None, sfunc=None, quiet: bool = True)[source]
- estimate_total_moment_and_mw(model: numpy.ndarray, geometry: FaultGeometry | None = None) Tuple[float, float][source]
Estimate total scalar moment (N.m) and Mw for a 7-parameter ellipse model.
- classmethod from_config(cfg: ConfigParser, axitra_dir: str | None = None) AxitraForwardModel[source]
Create AxitraForwardModel directly from a ConfigParser object. (Crea AxitraForwardModel directamente desde un objeto ConfigParser.)
- classmethod from_params(params: dict, axitra_dir: str | None = None) AxitraForwardModel[source]
Create AxitraForwardModel from a dictionary of parameters instead of an input.ctl file.
This allows building the forward model programmatically without file I/O.
Parameters:
- paramsdict
Dictionary containing all configuration sections: - ‘observed_data’: Dictionary with time window and sampling parameters - ‘source_position’: Dictionary with event location and focal mechanism - ‘fault_plane’: Dictionary with fault geometry discretization - ‘ellipse’: Dictionary with ellipse model and frequency band - ‘inversion_params’: Dictionary with inversion parameter ranges - ‘inversion_process’: Dictionary with algorithm settings - ‘moment_tensor’: Dictionary with moment tensor components - ‘stations’: List of station dictionaries (lat, lon, height, name, use_n, use_e, use_z) - ‘velocity_model’: List of velocity layer dictionaries
- axitra_dirstr, optional
Path to axitra directory. If not provided, assumes it’s a sibling folder.
Returns:
- AxitraForwardModel
Initialized forward model instance with all configuration loaded from params.
Example:
>>> params = { ... 'observed_data': {'Time window start (t1)': 0.0, ...}, ... 'source_position': {'Latitude': -20.0, 'Longitude': -70.0, ...}, ... 'fault_plane': {'Length along strike (Lx)': 100000.0, ...}, ... 'ellipse': {'Number of ellipses': 1, ...}, ... 'stations': [ ... {'latitude': -19.5, 'longitude': -69.5, 'height': 0.0, 'name': 'SL01'}, ... ... ... ], ... 'velocity_model': [ ... {'thickness': 10000.0, 'vp': 5500.0, 'vs': 3200.0, 'rho': 2700.0, 'qp': 100.0, 'qs': 50.0}, ... ... ... ], ... 'inversion_params': {...}, ... 'inversion_process': {...}, ... 'moment_tensor': {...}, ... } >>> fm = AxitraForwardModel.from_params(params, axitra_dir='/path/to/axitra')
- plot(synthetic: numpy.ndarray, time: numpy.ndarray | None = None, show: bool = True, save_path: str | Path | None = None, dpi: int = 300)[source]
Plot synthetic seismograms generated by this forward model. (Grafica los sismogramas sintéticos generados por este modelo forward.)
- select_source_function() dict[source]
Interactive prompt to select source time function, rise time and output type, mirroring the axitra Fortran convms behavior.
- Source types (passed directly to moment.conv as source_type):
0 : Dirac 1 : Ricker -> requires rise time (t0) 2 : Smooth step -> requires rise time (t0) 3 : From file <axi_id.sou> -> sfunc array must be supplied externally 4 : Triangle -> requires rise time (t0) 5 : Ramp -> requires rise time (t0) 7 : True step -> requires rise time (t0) 8 : Trapezoid -> requires rise time (t0) AND flat time (t1) +10: compute only the source time function, no convolution
- Returns a dict with keys:
source_type : int (may include +10 flag) t0 : float (rise time, or delta for Dirac) t1 : float (flat time for Trapezoid, 0.0 otherwise) unit : int (1=disp, 2=vel, 3=acc) sfunc : None (caller must set this for source_type=3)
Fault Geometry & Kinematics
- class kdellipspy.core.geometry.EllipticalSlipMapper(config: ConfigParser)[source]
Bases:
objectApply ellipse-based slip factors to fault geometry source points.
- apply_to_geometry(geom: FaultGeometry, model: numpy.ndarray, keep_all_sources: bool = False) FaultGeometry[source]
Apply the ellipse slip model to
geom.When
keep_all_sourcesis True the source-point set is NOT pruned to the subfaults inside the ellipse: every source point is kept with zero moment/slip outside the ellipse. This keeps the source set (positions and indices) constant across models, which lets the caller compute the Green’s functions once for the full mesh and reuse them viaconv.
- class kdellipspy.core.geometry.FaultGeometry(length_strike_m: float, length_dip_m: float, hypo_strike_m: float, hypo_dip_m: float, nx: int, ny: int, strike_deg: float, dip_deg: float, rake_deg: float, source_depth_m: float, source_lat: float, source_lon: float, rupture_velocity_km_s: float, mt_enabled: bool, subfaults: List[kdellipspy.core.geometry.Subfault], source_points: List[kdellipspy.core.geometry.SourcePoint])[source]
Bases:
object- dip_deg: float
- hypo_dip_m: float
- hypo_strike_m: float
- length_dip_m: float
- length_strike_m: float
- moment_magnitude_mw() float[source]
Return moment magnitude Mw from total moment (Hanks & Kanamori, M0 in N.m).
- mt_enabled: bool
- property nsources: int
- property nsubfaults: int
- nx: int
- ny: int
- plot(title: str = '2D Slip Distribution', show: bool = True, save_path: str | None = None) Tuple[Any, Any][source]
Visualización 2D de la distribución de slip interpolada.
- rake_deg: float
- rupture_velocity_km_s: float
- source_depth_m: float
- source_lat: float
- source_lon: float
- source_points: List[SourcePoint]
- strike_deg: float
- class kdellipspy.core.geometry.GeometryBuilder(config: ConfigParser)[source]
Bases:
objectBuild fault geometry from input.ctl through ConfigParser.
- build(slip_geom: float = 1.0) FaultGeometry[source]
- classmethod from_config(config: ConfigParser) GeometryBuilder[source]
- classmethod from_input_ctl(input_ctl_path: str) GeometryBuilder[source]
- classmethod from_params(params: dict) GeometryBuilder[source]
- class kdellipspy.core.geometry.SourcePoint(index: int, subfault_index: int, x_m: float, y_m: float, z_m: float, rupture_time_s: float, moment: float = 0.0, displacement: float = 0.0, strike_deg: float = 0.0, dip_deg: float = 0.0, rake_deg: float = 0.0, width: float = 0.0, length: float = 0.0, mu_pa: float = 0.0, basis_slot: int = 0)[source]
Bases:
object- basis_slot: int = 0
- dip_deg: float = 0.0
- displacement: float = 0.0
- index: int
- length: float = 0.0
- moment: float = 0.0
- mu_pa: float = 0.0
- rake_deg: float = 0.0
- rupture_time_s: float
- strike_deg: float = 0.0
- subfault_index: int
- width: float = 0.0
- x_m: float
- y_m: float
- z_m: float
- class kdellipspy.core.geometry.Station(index: int, name: str, x_m: float, y_m: float, z_m: float, lat: float, lon: float)[source]
Bases:
object- index: int
- lat: float
- lon: float
- name: str
- x_m: float
- y_m: float
- z_m: float
- class kdellipspy.core.geometry.StationGeometry(ref_lat: float, ref_lon: float, stations: List[kdellipspy.core.geometry.Station])[source]
Bases:
object- property nstations: int
- ref_lat: float
- ref_lon: float
- class kdellipspy.core.geometry.Subfault(index: int, x_m: float, y_m: float, z_m: float, rupture_time_s: float, mu_pa: float = 0.0, area_m2: float = 0.0, slip_m: float = 0.0, lat: float = 0.0, lon: float = 0.0)[source]
Bases:
object- area_m2: float = 0.0
- index: int
- lat: float = 0.0
- lon: float = 0.0
- mu_pa: float = 0.0
- rupture_time_s: float
- slip_m: float = 0.0
- x_m: float
- y_m: float
- z_m: float
- class kdellipspy.core.geometry.UTMProjection(lat0_deg: float, lon0_deg: float)[source]
Bases:
objectUTM (Universal Transverse Mercator) projection using pyproj.
Automatically detects the UTM zone based on the center coordinates. Uses WGS84 ellipsoid for accurate geodetic transformations. This replaces the legacy Lambert conformal projection with a faster (C-native) and more standard approach.
- kdellipspy.core.geometry.build_geometry_from_input_ctl(input_ctl_path: str, slip_geom: float = 1.0) FaultGeometry[source]
- kdellipspy.core.geometry.build_station_geometry(ref_lat: float, ref_lon: float, station_data: List[Tuple[str, float, float, float]]) StationGeometry[source]
Plotting Utilities (Object-Oriented)
Unified plotting functions for kdellipspy.
- kdellipspy.core.plotting.plot_azimuthal_coverage(station_lats, station_lons, station_names, ev_lat: float, ev_lon: float, show: bool = True, save_path: str | Path | None = None, dpi: int = 200, ax: Any | None = None) Tuple[Any, Any][source]
Diagrama polar (radar) de la cobertura azimutal de las estaciones respecto al epicentro. Ángulo = azimut evento→estación (N arriba, horario), radio = distancia epicentral (km). Sombrea el mayor hueco azimutal (gap).
Si se pasa
ax(debe ser un eje polar) dibuja ahí y no guarda/abre figura (modo composición, p. ej. desdeplot_yolo).
- kdellipspy.core.plotting.plot_ellipse_map(lats, lons, slip, ev_lat: float, ev_lon: float, station_lats=None, station_lons=None, station_names=None, pad: float = 0.25, show: bool = True, save_path: str | Path | None = None, dpi: int = 200, fig: Any | None = None) Tuple[Any, Any][source]
Mapa cartopy de la elipse de slip proyectada a la superficie: footprint (subfallas coloreadas por slip) + contorno del borde a 0.15*max_slip, hipocentro/epicentro y estaciones dentro del recuadro.
- kdellipspy.core.plotting.plot_misfit_contribution(num: numpy.ndarray, den: numpy.ndarray, station_names: List[str], total_E: float, mode_label: str = '', show: bool = True, save_path: str | Path | None = None, dpi: int = 200, fig: Any | None = None) Tuple[Any, Any][source]
Visualiza la ‘tabla’ de contribución al misfit como dos heatmaps estaciones×(R,T,Z): (izq) %% del residuo total que aporta cada componente; (der) misfit local num/den (calidad de ajuste). Anotados.
- kdellipspy.core.plotting.plot_na_results(source_data: list[dict[str, float]], param_names: list[str], show: bool = True, save_path: str | Path | None = None, dpi: int = 300) Tuple[Any, Any][source]
Plot summary of NA results.
- kdellipspy.core.plotting.plot_parameter_convergence(rows: list[dict], param_names: list[str], misfits: numpy.ndarray, iterations: numpy.ndarray, show: bool = True, save_path: str | Path | None = None, dpi: int = 300, fig: Any | None = None) Tuple[Any, Any][source]
Plot convergence for each parameter.
- kdellipspy.core.plotting.plot_record_section(waveforms: numpy.ndarray, time: numpy.ndarray, station_names: List[str], distances: numpy.ndarray, comp_name: str = 'Z', scale: float = 1.0, show: bool = True, save_path: str | Path | None = None, dpi: int = 300) Tuple[Any, Any][source]
Plot waveforms as a record section.
- kdellipspy.core.plotting.plot_slip_distribution(geometry: FaultGeometry, title: str = '2D Slip Distribution', show: bool = True, save_path: str | Path | None = None, dpi: int = 300, fig: Any | None = None) Tuple[Any, Any][source]
Plot 2D slip distribution on the fault-plane subfault grid (no interpolation).
- kdellipspy.core.plotting.plot_stations_map(cfg: ConfigParser, show: bool = True, save_path: str | Path | None = None, dpi: int = 300, use_cartopy: bool = True) Tuple[Any, Any][source]
Plot station locations on a map using Cartopy for geographic features if available.
- kdellipspy.core.plotting.plot_synthetic_components(time: numpy.ndarray, synthetic: numpy.ndarray, station_names: List[str], show: bool = True, save_path: str | Path | None = None, dpi: int = 300) Tuple[Any, Any][source]
Plot purely synthetic seismograms.
- kdellipspy.core.plotting.plot_uncertainty_corner(samples: numpy.ndarray, param_names: List[str], bounds: numpy.ndarray | None = None, truths: numpy.ndarray | None = None, mean: numpy.ndarray | None = None, bins: int = 40, show: bool = True, save_path: str | Path | None = None, dpi: int = 300, title: str | None = None) Tuple[Any, Any][source]
Corner plot of the NA appraisal posterior (1D marginals + 2D trade-offs). (Gráfico ‘corner’ de la posterior del appraisal NA: marginales 1D en la diagonal y densidades 2D —trade-offs entre parámetros— en el triángulo inferior.)
- Parameters:
samples (np.ndarray, shape (n_samples, n_params)) – Posterior ensemble, e.g.
NAAppraiser.samples.param_names (list of str — axis labels (one per parameter).)
bounds (np.ndarray, shape (n_params, 2), optional) – [min, max] per parameter, used to fix the axis ranges.
truths (np.ndarray, shape (n_params,), optional) – Reference values marked in red (e.g. the best-fit model).
mean (np.ndarray, shape (n_params,), optional) – Posterior mean, marked with a green cross on the 2D panels.
bins (int — histogram bins for 1D and 2D panels.)
- Return type:
(fig, axes)
- kdellipspy.core.plotting.plot_waveform_fit(observed: numpy.ndarray, synthetic: numpy.ndarray, time: numpy.ndarray, station_names: List[str], misfit: float | None = None, show: bool = True, save_path: str | Path | None = None, dpi: int = 300, azimuths: numpy.ndarray | None = None, tp_s: numpy.ndarray | None = None, ts_s: numpy.ndarray | None = None, window_s: float | None = None, station_flags: numpy.ndarray | None = None, rotate: bool = False, mark_windows: bool = False, fig: Any | None = None) Tuple[Any, Any][source]
Plot observed vs synthetic waveforms.
- Parameters:
rotate (if True and
azimuths(rad, one per station) is given, rotate the) – N/E components to Radial/Transverse and label columns R / T / Z, matching how the L2 misfit is computed (P -> R+Z, S -> T).mark_windows (if True and
tp_s,ts_s(s) andwindow_s(>0) are) – given, shade the misfit window per component: P window [tP, tP+window_s] on R and Z, S window [tS, tS+window_s] on T.station_flags ((nsta, 3) booleans (use_n, use_e, use_z). Components that are) – NOT used in the misfit are drawn translucent and tagged “no usada”.
Inversion Base & Results Persistence
Base module for kinematic inversion: shared dataclasses, misfit logic and abstract model. (Módulo base para inversión cinemática: dataclasses compartidos, lógica de misfit y modelo base.)
Exports
NAModel : Single sampled model + misfit
MisfitCalculator : L2 waveform misfit with P/S time windows
NAResult : Container for all sampled models with export helpers
BaseInversionModel : Abstract base class for NA and MCMC inversion drivers
Dependencies (solo stdlib + numpy)
numpy, pathlib, csv, json, datetime, logging, os, time, copy
- class kdellipspy.inversion.base.BaseInversionModel(input_ctl_path: str | Path | None = None, axitra_dir: str | Path | None = None, observed_waveforms: numpy.ndarray | None = None, time_array: numpy.ndarray | None = None, azi_times_array: numpy.ndarray | None = None, axitra_aw: float = 0.5, axitra_ikmax: int = 100000, config: ConfigParser | None = None)[source]
Bases:
objectAbstract base class for kinematic inversion drivers (NA and MCMC). (Clase base abstracta para los motores de inversión cinemática NA y MCMC.)
Sub-classes must call
super().__init__(...)and then implement eitherrun_na_searchorrun_mcmc_search.- Parameters:
- best_synthetics
- Type:
np.ndarray | None — Updated whenever a new best misfit is found
- azi_times_array: numpy.ndarray | None
- best_synthetics: numpy.ndarray | None
- checkpoint_path: str | Path | None
- clear_green_cache() None[source]
Clean up the cached Green’s-function axitra files (call at end of run).
- classmethod from_config(config: ConfigParser, axitra_dir: str | Path | None = None, observed_waveforms: numpy.ndarray | None = None, time_array: numpy.ndarray | None = None, azi_times_array: numpy.ndarray | None = None, **kwargs) BaseInversionModel[source]
Create an inversion model directly from a ConfigParser object.
- classmethod from_params(params: Dict[str, Any], axitra_dir: str | Path | None = None, observed_waveforms: numpy.ndarray | None = None, time_array: numpy.ndarray | None = None, azi_times_array: numpy.ndarray | None = None, **kwargs) BaseInversionModel[source]
Create an inversion model from a dictionary of parameters.
- misfit_calc: MisfitCalculator | None
- objective_function(model: numpy.ndarray) float[source]
Evaluate the forward model and return L2 misfit for one parameter vector. (Evalúa el modelo forward y retorna el desajuste L2 para un vector de parámetros.)
Side-effects
Updates
self._best_misfit_seenandself.best_syntheticswhen improved.Cleans axitra temporary files unless the active config sets
keep_axitra_files=True.
- param_names: List[str]
- plot_fit(show: bool = True, save_path: str | None = None) Tuple[Any, Any][source]
Grafica el mejor ajuste de formas de onda encontrado hasta ahora.
- use_full_signal: bool
- use_green_cache: bool
- class kdellipspy.inversion.base.MisfitCalculator(observed_waveforms: numpy.ndarray, time_array: numpy.ndarray, azi_times_path: Path | None = None, azi_times_array: numpy.ndarray | None = None, time_window_s: float = 20.0, station_flags: numpy.ndarray | None = None)[source]
Bases:
objectL2 waveform misfit calculator with P/S arrival-time windows. (Calculador de desajuste L2 de formas de onda con ventanas de llegada P/S.)
- Parameters:
- class kdellipspy.inversion.base.NAModel(model: numpy.ndarray, misfit: float, iteration: int)[source]
Bases:
objectSingle sampled model and its objective value. (Modelo muestreado individual y su valor objetivo.)
- model
- Type:
Parameter vector (np.ndarray)
- misfit
- Type:
Objective/misfit value (float)
- iteration
- Type:
Iteration index at which this model was sampled (int)
- iteration: int
- misfit: float
- model: numpy.ndarray
- class kdellipspy.inversion.base.NAResult(all_models: List[NAModel], param_names: Sequence[str] | None = None, extra_metadata: Dict[str, Any] | None = None, best_synthetics: numpy.ndarray | None = None, observed: numpy.ndarray | None = None, time: numpy.ndarray | None = None, config: ConfigParser | None = None, azi_times_array: numpy.ndarray | None = None)[source]
Bases:
objectContainer for all sampled models with export helpers. (Contenedor de todos los modelos muestreados con exportadores.)
- Parameters:
all_models (List of NAModel instances)
param_names (Parameter name labels (optional, defaults to 7-param names))
extra_metadata (Algorithm-specific metadata written to JSON export)
best_synthetics (Synthetic waveforms of the best model (optional))
observed (Observed waveforms used for inversion (optional))
time (Time array used for inversion (optional))
config (ConfigParser instance (optional))
- export_csv(filepath: Path) None[source]
Export all models as CSV (iteration, misfit, param columns). (Exporta todos los modelos como CSV con columnas de iteración, misfit y parámetros.)
- export_results(filepath: Path) None[source]
Export all models + metadata as JSON. (Exporta todos los modelos y metadatos como JSON.)
- plot(show: bool = True, save_path: str | None = None) Tuple[Any, Any][source]
Grafica el resumen de resultados de la búsqueda NA.
- plot_appraisal(samples: np.ndarray | None = None, show: bool = True, save_path: str | None = None, bins: int = 40, title: str | None = None, **run_kwargs: Any) Tuple[Any, Any][source]
Corner plot of the posterior uncertainty (1D marginals + 2D trade-offs). (Gráfico ‘corner’ de la incertidumbre: marginales 1D y trade-offs 2D.)
If
samplesis not given and the appraisal has not been run yet, it is executed viarun_appraisal()(extra kwargs are forwarded there, e.g.n_resample,temperature,seed).
- plot_azimuthal(show: bool = True, save_path: str | None = None, ax: Any | None = None) Tuple[Any, Any][source]
Diagrama polar (radar) de la cobertura azimutal de las estaciones respecto al epicentro, con el mayor hueco azimutal sombreado.
ax(eje polar) permite componerlo dentro deplot_yolo.
- plot_convergence(show: bool = True, save_path: str | None = None, fig: Any | None = None) Tuple[Any, Any][source]
Grafica la convergencia detallada por cada parámetro.
- plot_elipse(show: bool = True, save_path: str | None = None, title: str | None = None) Tuple[Any, Any][source]
Alias por compatibilidad con el nombre en español.
- plot_ellipse(show: bool = True, save_path: str | None = None, title: str | None = None, fig: Any | None = None) Tuple[Any, Any][source]
Grafica la distribución de slip de la elipse para el mejor misfit. Requiere que config y best_model estén presentes en el objeto.
- plot_ellipse_depth(show: bool = True, save_path: str | None = None) Tuple[Any, Any][source]
Secciones transversales de la elipse de slip en profundidad (estilo legacy plot_geometry): corte N–S y corte E–O, coloreados por slip, con hipocentro.
- plot_ellipse_map(show: bool = True, save_path: str | None = None, pad: float = 0.25, fig: Any | None = None) Tuple[Any, Any][source]
Mapa cartopy de la elipse de slip proyectada a la superficie (footprint coloreado por slip + borde + hipocentro + estaciones).
- plot_fit(show: bool = True, save_path: str | None = None, rotate: bool = True, mark_windows: bool = True, fig: Any | None = None) Tuple[Any, Any][source]
Grafica el mejor ajuste de formas de onda encontrado. Requiere que best_synthetics, observed y time estén presentes en el objeto.
Por defecto rota a R/T/Z y sombrea la ventana del misfit (P→R,Z ; S→T), consistente con cómo se calcula el misfit. Si no hay datos de azimut/ tiempos disponibles, cae a las componentes N/E/Z sin ventana.
- plot_misfit_breakdown(show: bool = True, save_path: str | None = None, window_s='auto', fig: Any | None = None) Tuple[Any, Any][source]
Visualiza la contribución al misfit por estación/componente (heatmaps).
- plot_yolo(save_path: str | Path = 'dashboard.pdf', show: bool = False, dpi: int = 200) Path | None[source]
🎲 YOLO: arma un DASHBOARD de una sola página con todos los paneles encajados (GridSpec):
┌───────────────── título (evento · misfit · Mw) ─────────────────┐ │ mapa elipse (cartopy) │ ajuste R/T/Z (7 est, ventanas)│ │ azimutal (radar) │ heatmap mf │ (panel alto) │ │ convergencia de parámetros │ appraisal (corner) │ └─────────────────────────────────────────────────────────────────┘
Cada panel se renderiza con su método y se compone como imagen, así se reaprovecha todo el código existente (cartopy, corner, etc.). El appraisal se corre automáticamente si no estaba.
- run_appraisal(n_resample: int = 20000, n_walkers: int = 1, temperature: float | None = None, bounds: numpy.ndarray | None = None, seed: int | None = None, verbose: bool = True, save: bool = True) numpy.ndarray | None[source]
Run the NA appraisal stage to approximate the posterior. (Ejecuta la etapa de ‘appraisal’ del NA para aproximar la posterior.)
Reuses the models already evaluated during the NA search (
all_models) and resamples their Voronoi cells withneighpy.NAAppraiser— it does NOT evaluate the forward model again. Populatesappraisal_samples,appraisal_meanandappraisal_covariance.- Parameters:
n_resample (length of the resampling random walk (more = smoother PDFs).)
n_walkers (parallel walkers (>1 uses neighpy's multiprocessing).)
temperature (misfit-to-log-posterior scale,
log_ppd = -misfit / T.) – IfNone,T = 2 * best_misfit(auto-scale). SMALLER T → narrower posterior (more trust in the data). NOTE: the misfit here is the normalized L2 misfit, not a noise-calibrated chi-square, sotemperatureimplicitly sets the assumed noise level. Tune it (or pass an explicit value) if you need calibrated uncertainties.bounds ((n_params, 2) optional; derived from the config if
None.)seed (forwarded to
NAAppraiser/NAAppraiser.run.)verbose (forwarded to
NAAppraiser/NAAppraiser.run.)save (forwarded to
NAAppraiser/NAAppraiser.run.)
- Returns:
Posterior ensemble, shape (n_samples, n_params), or
Noneifsave=False.- Return type:
np.ndarray | None
Kinematic Inversion (NA & MCMC)
Neighbourhood Algorithm (NA) inversion driver. (Motor de inversión con el Algoritmo Neighbourhood — NA.)
This module contains ONLY the NA search implementation.
For MCMC inversion, see inversion_mcmc.py.
Exports
NAConfig : NA search hyperparameters
NAInversionModel : Full inversion driver; call
run_na_search()
Dependencies
inversion_base (NAModel, NAResult, BaseInversionModel) neighpy (pip install neighpy) config_parser, forward_model (from this package)
- class kdellipspy.inversion.kinematic.model_na.NAConfig(n_samples_initial: int = 30, n_samples_iteration: int = 30, n_iterations: int = 10, n_cells_resample: int = 7, n_jobs: int = 1, random_seed: int | None = None, keep_axitra_files: bool = False)[source]
Bases:
objectHyperparameters for the Neighbourhood Algorithm search. (Hiperparámetros para la búsqueda con el Algoritmo Neighbourhood.)
- n_samples_initial
- Type:
Number of random samples drawn in the first iteration (ni)
- n_samples_iteration
- Type:
Samples drawn around the best Voronoi cells per iteration (ns)
- n_iterations
- Type:
Number of NA iterations after the initial random stage (n)
- n_cells_resample
- Type:
Number of best Voronoi cells to resample from (nr)
- n_jobs
- Type:
Number of parallel workers for objective function evaluation (-1 for all)
- random_seed
- Type:
Optional seed for reproducibility
- keep_axitra_files
- Type:
Keep temporary axitra files (useful for debugging)
- keep_axitra_files: bool = False
- n_cells_resample: int = 7
- n_iterations: int = 10
- n_jobs: int = 1
- n_samples_initial: int = 30
- n_samples_iteration: int = 30
- random_seed: int | None = None
- class kdellipspy.inversion.kinematic.model_na.NAInversionModel(input_ctl_path: str | Path | None = None, axitra_dir: str | Path | None = None, observed_waveforms: numpy.ndarray | None = None, time_array: numpy.ndarray | None = None, azi_times_array: numpy.ndarray | None = None, axitra_aw: float = 0.5, axitra_ikmax: int = 100000, config: ConfigParser | None = None)[source]
Bases:
BaseInversionModelKinematic Inversion Model using the Neighbourhood Algorithm (NA). (Modelo de Inversión Cinemática utilizando el Algoritmo Neighbourhood — NA.)
Integrates observed data, arrival times, and event configuration to evaluate kinematic rupture models. Communicates with axitra to simulate synthetic seismograms and compute misfit against real data. (Integra los datos observados, tiempos de llegada y configuración del evento para evaluar distintos modelos de ruptura cinemática. Se comunica con axitra para simular sismogramas sintéticos y calcular el desajuste con los datos reales.)
- Parameters:
input_ctl_path (Path to input.ctl configuration file (optional if config is provided))
axitra_dir (Path to axitra binary directory (optional))
observed_waveforms (3-component seismograms, shape (nsta, 3, npts))
time_array (Time vector, shape (npts,))
azi_times_array (P/S arrival time table, shape (nsta, 3))
config (ConfigParser object (optional if input_ctl_path is provided))
- best_synthetics
Synthetic seismograms of the best model found so far (nsta, 3, npts). Set to None until the first objective function evaluation.
- Type:
np.ndarray | None
- param_names
- Type:
List[str] — Human-readable parameter labels
- param_ranges
- Type:
np.ndarray, shape (n_params, 2) — [min, max] per parameter
Example
>>> # Using a config file path: >>> model = NAInversionModel( ... "path/to/run/input.ctl", ... axitra_dir="path/to/axitra", ... observed_waveforms=obs, ... time_array=t, ... azi_times_array=azi, ... ) >>> # Or using a ConfigParser object: >>> cfg = ConfigParser("path/to/input.ctl") >>> model = NAInversionModel( ... config=cfg, ... observed_waveforms=obs, ... time_array=t, ... azi_times_array=azi, ... ) >>> result = model.run_na_search() >>> print(result.best_model.misfit)
- run_na_search(na_config: NAConfig | None = None) NAResult[source]
Run the Neighbourhood Algorithm search and return all sampled models. (Ejecuta la búsqueda con el Algoritmo Neighbourhood y retorna todos los modelos.)
- Parameters:
na_config (NAConfig, optional) – Search hyperparameters. If
None, values are read fromself.cfg.inversion_process(input.ctl).- Returns:
Container with every evaluated model, the best model, and JSON/CSV export helpers.
- Return type:
- Raises:
ImportError – If
neighpyis not installed.
- class kdellipspy.inversion.kinematic.model_na.NAModel(model: numpy.ndarray, misfit: float, iteration: int)[source]
Bases:
objectSingle sampled model and its objective value. (Modelo muestreado individual y su valor objetivo.)
- model
- Type:
Parameter vector (np.ndarray)
- misfit
- Type:
Objective/misfit value (float)
- iteration
- Type:
Iteration index at which this model was sampled (int)
- iteration: int
- misfit: float
- model: numpy.ndarray
- class kdellipspy.inversion.kinematic.model_na.NAResult(all_models: List[NAModel], param_names: Sequence[str] | None = None, extra_metadata: Dict[str, Any] | None = None, best_synthetics: numpy.ndarray | None = None, observed: numpy.ndarray | None = None, time: numpy.ndarray | None = None, config: ConfigParser | None = None, azi_times_array: numpy.ndarray | None = None)[source]
Bases:
objectContainer for all sampled models with export helpers. (Contenedor de todos los modelos muestreados con exportadores.)
- Parameters:
all_models (List of NAModel instances)
param_names (Parameter name labels (optional, defaults to 7-param names))
extra_metadata (Algorithm-specific metadata written to JSON export)
best_synthetics (Synthetic waveforms of the best model (optional))
observed (Observed waveforms used for inversion (optional))
time (Time array used for inversion (optional))
config (ConfigParser instance (optional))
- export_csv(filepath: Path) None[source]
Export all models as CSV (iteration, misfit, param columns). (Exporta todos los modelos como CSV con columnas de iteración, misfit y parámetros.)
- export_results(filepath: Path) None[source]
Export all models + metadata as JSON. (Exporta todos los modelos y metadatos como JSON.)
- plot(show: bool = True, save_path: str | None = None) Tuple[Any, Any][source]
Grafica el resumen de resultados de la búsqueda NA.
- plot_appraisal(samples: np.ndarray | None = None, show: bool = True, save_path: str | None = None, bins: int = 40, title: str | None = None, **run_kwargs: Any) Tuple[Any, Any][source]
Corner plot of the posterior uncertainty (1D marginals + 2D trade-offs). (Gráfico ‘corner’ de la incertidumbre: marginales 1D y trade-offs 2D.)
If
samplesis not given and the appraisal has not been run yet, it is executed viarun_appraisal()(extra kwargs are forwarded there, e.g.n_resample,temperature,seed).
- plot_azimuthal(show: bool = True, save_path: str | None = None, ax: Any | None = None) Tuple[Any, Any][source]
Diagrama polar (radar) de la cobertura azimutal de las estaciones respecto al epicentro, con el mayor hueco azimutal sombreado.
ax(eje polar) permite componerlo dentro deplot_yolo.
- plot_convergence(show: bool = True, save_path: str | None = None, fig: Any | None = None) Tuple[Any, Any][source]
Grafica la convergencia detallada por cada parámetro.
- plot_elipse(show: bool = True, save_path: str | None = None, title: str | None = None) Tuple[Any, Any][source]
Alias por compatibilidad con el nombre en español.
- plot_ellipse(show: bool = True, save_path: str | None = None, title: str | None = None, fig: Any | None = None) Tuple[Any, Any][source]
Grafica la distribución de slip de la elipse para el mejor misfit. Requiere que config y best_model estén presentes en el objeto.
- plot_ellipse_depth(show: bool = True, save_path: str | None = None) Tuple[Any, Any][source]
Secciones transversales de la elipse de slip en profundidad (estilo legacy plot_geometry): corte N–S y corte E–O, coloreados por slip, con hipocentro.
- plot_ellipse_map(show: bool = True, save_path: str | None = None, pad: float = 0.25, fig: Any | None = None) Tuple[Any, Any][source]
Mapa cartopy de la elipse de slip proyectada a la superficie (footprint coloreado por slip + borde + hipocentro + estaciones).
- plot_fit(show: bool = True, save_path: str | None = None, rotate: bool = True, mark_windows: bool = True, fig: Any | None = None) Tuple[Any, Any][source]
Grafica el mejor ajuste de formas de onda encontrado. Requiere que best_synthetics, observed y time estén presentes en el objeto.
Por defecto rota a R/T/Z y sombrea la ventana del misfit (P→R,Z ; S→T), consistente con cómo se calcula el misfit. Si no hay datos de azimut/ tiempos disponibles, cae a las componentes N/E/Z sin ventana.
- plot_misfit_breakdown(show: bool = True, save_path: str | None = None, window_s='auto', fig: Any | None = None) Tuple[Any, Any][source]
Visualiza la contribución al misfit por estación/componente (heatmaps).
- plot_yolo(save_path: str | Path = 'dashboard.pdf', show: bool = False, dpi: int = 200) Path | None[source]
🎲 YOLO: arma un DASHBOARD de una sola página con todos los paneles encajados (GridSpec):
┌───────────────── título (evento · misfit · Mw) ─────────────────┐ │ mapa elipse (cartopy) │ ajuste R/T/Z (7 est, ventanas)│ │ azimutal (radar) │ heatmap mf │ (panel alto) │ │ convergencia de parámetros │ appraisal (corner) │ └─────────────────────────────────────────────────────────────────┘
Cada panel se renderiza con su método y se compone como imagen, así se reaprovecha todo el código existente (cartopy, corner, etc.). El appraisal se corre automáticamente si no estaba.
- run_appraisal(n_resample: int = 20000, n_walkers: int = 1, temperature: float | None = None, bounds: numpy.ndarray | None = None, seed: int | None = None, verbose: bool = True, save: bool = True) numpy.ndarray | None[source]
Run the NA appraisal stage to approximate the posterior. (Ejecuta la etapa de ‘appraisal’ del NA para aproximar la posterior.)
Reuses the models already evaluated during the NA search (
all_models) and resamples their Voronoi cells withneighpy.NAAppraiser— it does NOT evaluate the forward model again. Populatesappraisal_samples,appraisal_meanandappraisal_covariance.- Parameters:
n_resample (length of the resampling random walk (more = smoother PDFs).)
n_walkers (parallel walkers (>1 uses neighpy's multiprocessing).)
temperature (misfit-to-log-posterior scale,
log_ppd = -misfit / T.) – IfNone,T = 2 * best_misfit(auto-scale). SMALLER T → narrower posterior (more trust in the data). NOTE: the misfit here is the normalized L2 misfit, not a noise-calibrated chi-square, sotemperatureimplicitly sets the assumed noise level. Tune it (or pass an explicit value) if you need calibrated uncertainties.bounds ((n_params, 2) optional; derived from the config if
None.)seed (forwarded to
NAAppraiser/NAAppraiser.run.)verbose (forwarded to
NAAppraiser/NAAppraiser.run.)save (forwarded to
NAAppraiser/NAAppraiser.run.)
- Returns:
Posterior ensemble, shape (n_samples, n_params), or
Noneifsave=False.- Return type:
np.ndarray | None
MCMC inversion driver using PyMC + ArviZ. (Motor de inversión MCMC usando PyMC + ArviZ.)
This module contains ONLY the MCMC search implementation.
For Neighbourhood Algorithm inversion, see inversion_na.py.
Exports
MCMCConfig : MCMC sampling hyperparameters
MCMCInversionModel : Full inversion driver; call
run_mcmc_search()
Dependencies
inversion_base (NAModel, NAResult, BaseInversionModel) pymc (pip install pymc) — includes arviz and pytensor config_parser, forward_model (from this package)
- class kdellipspy.inversion.kinematic.model_mcmc.MCMCConfig(total_steps: int = 500, burn_in: int = 0, proposal_scale: float = 0.08, thin: int = 1, random_seed: int | None = None, keep_axitra_files: bool = False, chains: int = 1)[source]
Bases:
objectHyperparameters for the MCMC search with PyMC + ArviZ. (Hiperparámetros para la búsqueda MCMC con PyMC + ArviZ.)
PyMC runs a Metropolis sampler with a uniform prior on the parameter box. ArviZ is used for posterior summary statistics.
- total_steps
- Type:
Total number of MCMC steps per chain (tune + draws)
- burn_in
- Type:
Number of tuning steps (excluded from posterior)
- proposal_scale
each parameter’s range, e.g. 0.08 → 8 % of width per param
- Type:
Metropolis proposal standard deviation as a fraction of
- thin
- Type:
Thinning factor applied to the posterior draws
- random_seed
- Type:
Optional seed for reproducibility
- keep_axitra_files
- Type:
Keep temporary axitra files (useful for debugging)
- chains
Warning: chains > 1 may fail when axitra uses shared temp files.
- Type:
Number of parallel MCMC chains.
- burn_in: int = 0
- chains: int = 1
- keep_axitra_files: bool = False
- proposal_scale: float = 0.08
- random_seed: int | None = None
- thin: int = 1
- total_steps: int = 500
- class kdellipspy.inversion.kinematic.model_mcmc.MCMCInversionModel(input_ctl_path: str | Path | None = None, axitra_dir: str | Path | None = None, observed_waveforms: numpy.ndarray | None = None, time_array: numpy.ndarray | None = None, azi_times_array: numpy.ndarray | None = None, axitra_aw: float = 0.5, axitra_ikmax: int = 100000, config: ConfigParser | None = None)[source]
Bases:
BaseInversionModelKinematic Inversion Model using MCMC (Metropolis, PyMC + ArviZ). (Modelo de Inversión Cinemática usando MCMC — PyMC + ArviZ.)
Integrates observed data, arrival times, and event configuration to sample the posterior distribution of kinematic rupture model parameters. (Integra los datos observados, tiempos de llegada y configuración del evento para muestrear la distribución posterior de los parámetros del modelo cinemático.)
- Parameters:
input_ctl_path (Path to input.ctl configuration file (optional if config is provided))
axitra_dir (Path to axitra binary directory (optional))
observed_waveforms (3-component seismograms, shape (nsta, 3, npts))
time_array (Time vector, shape (npts,))
azi_times_array (P/S arrival time table, shape (nsta, 3))
config (ConfigParser object (optional if input_ctl_path is provided))
- best_synthetics
Synthetic seismograms of the best model found so far (nsta, 3, npts).
- Type:
np.ndarray | None
Example
>>> # Using a config file path: >>> model = MCMCInversionModel( ... "path/to/run/input.ctl", ... axitra_dir="path/to/axitra", ... observed_waveforms=obs, ... time_array=t, ... azi_times_array=azi, ... ) >>> # Or using a ConfigParser object: >>> cfg = ConfigParser("path/to/input.ctl") >>> model = MCMCInversionModel( ... config=cfg, ... observed_waveforms=obs, ... time_array=t, ... azi_times_array=azi, ... ) >>> result = model.run_mcmc_search() >>> print(result.best_model.misfit)
- run_mcmc_search(mc_config: MCMCConfig | None = None) NAResult[source]
Run the PyMC Metropolis sampler and return posterior models. (Ejecuta el muestreador Metropolis de PyMC y retorna los modelos posteriores.)
- Parameters:
mc_config (MCMCConfig, optional) – MCMC hyperparameters. If
None, values are read fromself.cfg.inversion_process(input.ctl).- Returns:
Container with posterior samples, the best model (minimum misfit), ArviZ summary in
extra_metadata, and JSON/CSV export helpers.- Return type:
- Raises:
ImportError – If
pymc(orarviz/pytensor) is not installed.ValueError – If
burn_in >= total_steps.
- class kdellipspy.inversion.kinematic.model_mcmc.NAModel(model: numpy.ndarray, misfit: float, iteration: int)[source]
Bases:
objectSingle sampled model and its objective value. (Modelo muestreado individual y su valor objetivo.)
- model
- Type:
Parameter vector (np.ndarray)
- misfit
- Type:
Objective/misfit value (float)
- iteration
- Type:
Iteration index at which this model was sampled (int)
- iteration: int
- misfit: float
- model: numpy.ndarray
- class kdellipspy.inversion.kinematic.model_mcmc.NAResult(all_models: List[NAModel], param_names: Sequence[str] | None = None, extra_metadata: Dict[str, Any] | None = None, best_synthetics: numpy.ndarray | None = None, observed: numpy.ndarray | None = None, time: numpy.ndarray | None = None, config: ConfigParser | None = None, azi_times_array: numpy.ndarray | None = None)[source]
Bases:
objectContainer for all sampled models with export helpers. (Contenedor de todos los modelos muestreados con exportadores.)
- Parameters:
all_models (List of NAModel instances)
param_names (Parameter name labels (optional, defaults to 7-param names))
extra_metadata (Algorithm-specific metadata written to JSON export)
best_synthetics (Synthetic waveforms of the best model (optional))
observed (Observed waveforms used for inversion (optional))
time (Time array used for inversion (optional))
config (ConfigParser instance (optional))
- export_csv(filepath: Path) None[source]
Export all models as CSV (iteration, misfit, param columns). (Exporta todos los modelos como CSV con columnas de iteración, misfit y parámetros.)
- export_results(filepath: Path) None[source]
Export all models + metadata as JSON. (Exporta todos los modelos y metadatos como JSON.)
- plot(show: bool = True, save_path: str | None = None) Tuple[Any, Any][source]
Grafica el resumen de resultados de la búsqueda NA.
- plot_appraisal(samples: np.ndarray | None = None, show: bool = True, save_path: str | None = None, bins: int = 40, title: str | None = None, **run_kwargs: Any) Tuple[Any, Any][source]
Corner plot of the posterior uncertainty (1D marginals + 2D trade-offs). (Gráfico ‘corner’ de la incertidumbre: marginales 1D y trade-offs 2D.)
If
samplesis not given and the appraisal has not been run yet, it is executed viarun_appraisal()(extra kwargs are forwarded there, e.g.n_resample,temperature,seed).
- plot_azimuthal(show: bool = True, save_path: str | None = None, ax: Any | None = None) Tuple[Any, Any][source]
Diagrama polar (radar) de la cobertura azimutal de las estaciones respecto al epicentro, con el mayor hueco azimutal sombreado.
ax(eje polar) permite componerlo dentro deplot_yolo.
- plot_convergence(show: bool = True, save_path: str | None = None, fig: Any | None = None) Tuple[Any, Any][source]
Grafica la convergencia detallada por cada parámetro.
- plot_elipse(show: bool = True, save_path: str | None = None, title: str | None = None) Tuple[Any, Any][source]
Alias por compatibilidad con el nombre en español.
- plot_ellipse(show: bool = True, save_path: str | None = None, title: str | None = None, fig: Any | None = None) Tuple[Any, Any][source]
Grafica la distribución de slip de la elipse para el mejor misfit. Requiere que config y best_model estén presentes en el objeto.
- plot_ellipse_depth(show: bool = True, save_path: str | None = None) Tuple[Any, Any][source]
Secciones transversales de la elipse de slip en profundidad (estilo legacy plot_geometry): corte N–S y corte E–O, coloreados por slip, con hipocentro.
- plot_ellipse_map(show: bool = True, save_path: str | None = None, pad: float = 0.25, fig: Any | None = None) Tuple[Any, Any][source]
Mapa cartopy de la elipse de slip proyectada a la superficie (footprint coloreado por slip + borde + hipocentro + estaciones).
- plot_fit(show: bool = True, save_path: str | None = None, rotate: bool = True, mark_windows: bool = True, fig: Any | None = None) Tuple[Any, Any][source]
Grafica el mejor ajuste de formas de onda encontrado. Requiere que best_synthetics, observed y time estén presentes en el objeto.
Por defecto rota a R/T/Z y sombrea la ventana del misfit (P→R,Z ; S→T), consistente con cómo se calcula el misfit. Si no hay datos de azimut/ tiempos disponibles, cae a las componentes N/E/Z sin ventana.
- plot_misfit_breakdown(show: bool = True, save_path: str | None = None, window_s='auto', fig: Any | None = None) Tuple[Any, Any][source]
Visualiza la contribución al misfit por estación/componente (heatmaps).
- plot_yolo(save_path: str | Path = 'dashboard.pdf', show: bool = False, dpi: int = 200) Path | None[source]
🎲 YOLO: arma un DASHBOARD de una sola página con todos los paneles encajados (GridSpec):
┌───────────────── título (evento · misfit · Mw) ─────────────────┐ │ mapa elipse (cartopy) │ ajuste R/T/Z (7 est, ventanas)│ │ azimutal (radar) │ heatmap mf │ (panel alto) │ │ convergencia de parámetros │ appraisal (corner) │ └─────────────────────────────────────────────────────────────────┘
Cada panel se renderiza con su método y se compone como imagen, así se reaprovecha todo el código existente (cartopy, corner, etc.). El appraisal se corre automáticamente si no estaba.
- run_appraisal(n_resample: int = 20000, n_walkers: int = 1, temperature: float | None = None, bounds: numpy.ndarray | None = None, seed: int | None = None, verbose: bool = True, save: bool = True) numpy.ndarray | None[source]
Run the NA appraisal stage to approximate the posterior. (Ejecuta la etapa de ‘appraisal’ del NA para aproximar la posterior.)
Reuses the models already evaluated during the NA search (
all_models) and resamples their Voronoi cells withneighpy.NAAppraiser— it does NOT evaluate the forward model again. Populatesappraisal_samples,appraisal_meanandappraisal_covariance.- Parameters:
n_resample (length of the resampling random walk (more = smoother PDFs).)
n_walkers (parallel walkers (>1 uses neighpy's multiprocessing).)
temperature (misfit-to-log-posterior scale,
log_ppd = -misfit / T.) – IfNone,T = 2 * best_misfit(auto-scale). SMALLER T → narrower posterior (more trust in the data). NOTE: the misfit here is the normalized L2 misfit, not a noise-calibrated chi-square, sotemperatureimplicitly sets the assumed noise level. Tune it (or pass an explicit value) if you need calibrated uncertainties.bounds ((n_params, 2) optional; derived from the config if
None.)seed (forwarded to
NAAppraiser/NAAppraiser.run.)verbose (forwarded to
NAAppraiser/NAAppraiser.run.)save (forwarded to
NAAppraiser/NAAppraiser.run.)
- Returns:
Posterior ensemble, shape (n_samples, n_params), or
Noneifsave=False.- Return type:
np.ndarray | None
Signal Processing & SAC
- kdellipspy.core.signal_utils.bandpass_filter_waveforms(synthetic: numpy.ndarray, time: numpy.ndarray, freq1: float, freq2: float, corners: int = 4, zerophase: bool = True) numpy.ndarray[source]
Apply Butterworth bandpass filter to synthetic waveforms.
This ensures synthetic waveforms match the frequency band of observed data, maintaining consistency in the misfit calculation.
- Parameters:
synthetic – waveform array with shape (n_stations, 3, npts)
time – time array with shape (npts,)
freq1 – low frequency cutoff (Hz)
freq2 – high frequency cutoff (Hz)
corners – filter order (default 4 = 4th order)
zerophase – if True, apply filter forward-backward for zero phase distortion
- Returns:
filtered waveforms with same shape as input
- Return type:
filtered_synthetic
- Raises:
ValueError – if time array has < 2 points or freq2 >= Nyquist frequency
- kdellipspy.core.signal_utils.build_azi_times_array(input_ctl_path: str | Path | None = None, model_name: str = 'iasp91', p_shift_s: float = -1.0, s_shift_s: float = -1.0, use_iris: bool = False, config: ConfigParser | None = None) numpy.ndarray[source]
Build legacy-compatible azi_times values as an array with columns: [azimuth_rad, tP, tS].
This reproduces the old script behavior while avoiding IRIS network requirements by default (use_iris=False).
- kdellipspy.core.signal_utils.integrate_waveforms(waveforms: numpy.ndarray, delta: float, baseline_samples: int | None = None, steps: int = 1) numpy.ndarray[source]
Integrate waveforms along the last axis using a digital filter (Matlab integraf.m logic). Cleanest results for seismic signals.
- Parameters:
waveforms – array with shape (…, npts)
delta – sampling interval in seconds
baseline_samples – Number of samples at the start for pre-event baseline correction.
steps – Number of integration steps (1 for velocity, 2 for displacement).
- Returns:
Integrated waveforms with the same shape as the input.
- kdellipspy.core.signal_utils.load_and_filter_observed_data(freq1: float | None = None, freq2: float | None = None, input_ctl_path: str | Path | None = None, data_dir: str | Path = 'DATA', prefer_raw: bool = False, config: ConfigParser | None = None) Tuple[numpy.ndarray, numpy.ndarray][source]
Load observed data with two supported user workflows:
Flat files in DATA: - real_disp_x/y/z (if input.ctl units=1) - real_vel_x/y/z (if input.ctl units=2) Each file must contain 2 columns: time and data, and total rows must be npts * nstations.
RAW files in DATA/RAW: - .sac or .mseed files - station name extracted from waveform metadata - bandpass filtering using input.ctl frequency band - response removal attempted when inventory files are present in RAW
- Returns:
ndarray with shape (n_stations, 3, npts) time_array: ndarray with shape (npts,)
- Return type:
observed_waveforms
- kdellipspy.core.signal_utils.write_azi_times_file(input_ctl_path: str | Path | None = None, output_path: str | Path | None = None, model_name: str = 'iasp91', p_shift_s: float = -1.0, s_shift_s: float = -1.0, use_iris: bool = False, config: ConfigParser | None = None) Path[source]
Write Event/azi_times.txt with legacy-compatible 3-column format.
SAC/MiniSEED waveform processor for seismic inversion.
Implements robust signal processing following Boore (2001) and Boore & Bommer (2005) standards for seismic data preprocessing: - Zero-phase bandpass filtering with padding - Polynomial baseline correction - Multi-step integration with proper detrending - Station and component extraction from metadata
This module bridges ObsPy with inversion workflows in kdellipspy.
- class kdellipspy.core.sac_processor.ProcessingConfig(freq_min: float = 0.04, freq_max: float = 0.2, filter_corners: int = 4, zerophase: bool = True, zeropad_duration: float = 100.0, taper_percentage: float = 0.05, taper_type: str = 'cosine', polynomial_degree_vel: int = 1, polynomial_degree_disp: int = 2)[source]
Bases:
objectConfiguration for waveform processing pipeline.
- class kdellipspy.core.sac_processor.WaveformExtractor(raw_dir: Path, config: ProcessingConfig | None = None)[source]
Bases:
objectExtract and process waveforms from SAC/MiniSEED files in DATA/RAW/.
Handles: - Reading multiple files (*.sac, *.mseed) - Grouping by station and component - Preprocessing with full pipeline - Validation and error handling
- get_station_waveforms(station: str) Dict[str, obspy.Trace][source]
Get preprocessed waveforms for a station, keyed by component.
- Parameters:
station – Station name (e.g., ‘AC01’).
- Returns:
Dict mapping component (‘E’, ‘N’, ‘Z’) to preprocessed Trace.
- Raises:
ValueError – If station not found or components incomplete.
- preprocess_station(station: str, event_time: obspy.UTCDateTime, target_mode: str = 'VEL', time_window: Tuple[float, float] | None = None) Dict[str, numpy.ndarray][source]
Preprocess all components for a station.
- Parameters:
station – Station name.
event_time – Event origin time.
target_mode – ‘VEL’ or ‘DISP’.
time_window – (t_start, t_end) relative to event_time. If None, uses full trace.
- Returns:
Dict mapping component to data array.
- kdellipspy.core.sac_processor.acausal_bandpass(tr: obspy.Trace, freq_min: float, freq_max: float, corners: int = 4, zerophase: bool = True, zeropad_duration: float = 100.0) obspy.Trace[source]
Apply zero-phase bandpass filter with manual padding (Boore 2001, §3.2).
Manual padding avoids ObsPy’s automatic tapering, which can degrade low-frequency content. Critical for periods > 5 s.
- Parameters:
tr – ObsPy Trace.
freq_min – Low-frequency cutoff (Hz).
freq_max – High-frequency cutoff (Hz).
corners – Filter order.
zerophase – Apply forward-backward filtering.
zeropad_duration – Padding duration (seconds).
- Returns:
Filtered Trace (modifies in-place).
- kdellipspy.core.sac_processor.polynomial_baseline_correction(tr: obspy.Trace, degree: int = 1) obspy.Trace[source]
Apply polynomial baseline correction to waveform.
References: - Boore (2001): Effect of baseline corrections on displacements and response spectra. - Graizer (2010): Baseline correction of strong-motion records.
Typical usage: - degree=1 (linear): After ACC→VEL integration. - degree=2 (quadratic): After VEL→DISP integration (preserves static offset).
- Parameters:
tr – ObsPy Trace.
degree – Polynomial degree for fit.
- Returns:
Modified Trace (operates in-place, but returns for chaining).
- kdellipspy.core.sac_processor.process_trace(tr: obspy.Trace, event_time: obspy.UTCDateTime, target_mode: str = 'VEL', config: ProcessingConfig | None = None) obspy.Trace[source]
Complete preprocessing pipeline for seismic waveforms.
Follows Boore (2001) and Boore & Bommer (2005) standards:
Pre-event baseline correction (mean of window before earthquake).
Linear detrending.
Cosine taper BEFORE integration (critical for long-period signals).
Multi-step numerical integration (cumtrapz) with polynomial baseline correction: - ACC→VEL: Linear polynomial correction (degree=1). - VEL→DISP: Quadratic polynomial correction (degree=2) to preserve static offset.
Bandpass filtering with zero-phase and padding.
Trim to desired time window.
- Parameters:
tr – ObsPy Trace.
event_time – Event origin time (UTCDateTime).
target_mode – Target output (‘VEL’ or ‘DISP’).
config – ProcessingConfig instance. If None, uses defaults.
- Returns:
Processed Trace (modifies in-place).
- Raises:
ValueError – If target_mode not in (‘VEL’, ‘DISP’).
- class kdellipspy.core.data_preprocessor.DataPreprocessor(cfg: ConfigParser)[source]
Bases:
objectUtility to prepare raw seismic data for axitra inversion. (Utilidad para preparar datos sísmicos crudos para la inversión con axitra.)
- plot_record_section(raw_dir: Path, t_start: Any | None = None, t_end: Any | None = None, freqmin: float = 0.05, freqmax: float = 0.5, scale: float = 2.0, components: List[str] = ['Z'], station_names: List[str] | None = None)[source]
Visualizes waveforms from SAC files in a record section, similar to the provided notebook. (Visualiza formas de onda de archivos SAC en una sección de registro, similar al notebook proporcionado.)
- process_raw_files(raw_dir: Path, output_dir: Path, freq1: float, freq2: float, t_start: Any = 0.0, t_end: Any | None = None, data_start_time: Any | None = None, units: int = 2, station_indices: List[int] | None = None, station_names: List[str] | None = None) Dict[str, numpy.ndarray][source]
Loads concatenated raw velocity files, filters, trims with zero-padding, and saves Axitra-ready files. Supports UTCDateTime or float for timing.
If station_names is provided, it filters the stations by name. (Si se proporciona station_names, filtra las estaciones por nombre.)
Command Line Interface
kdellipspy CLI
Corre la inversión cinemática (Neighbourhood Algorithm) de KDEllipsPy.
Lee input.ctl + DATA/ de la carpeta del proyecto (por defecto el
directorio actual) y guarda la solución y las figuras en output/:
<proyecto>/ ├── input.ctl ├── DATA/ └── output/
├── inversion_result.joblib ← la solución ├── best_model_live.txt ├── misfit_breakdown.txt └── figures/ ← PNGs + all_plots.pdf
- Ejemplos:
kdellipspy # usa ./input.ctl + ./DATA → ./output kdellipspy ruta/al/proyecto kdellipspy –freq1 0.06 –freq2 0.15 kdellipspy –no-plots python -m kdellipspy # equivalente sin instalar el comando