Examples Overview ================= This page collects short, self-contained recipes for the most common GASFIR use cases. Longer worked examples live on the :doc:`/examples/basic_usage`, :doc:`/examples/advanced_usage`, :doc:`/examples/parameter_fitting`, and :doc:`/examples/performance_optimization` pages. .. contents:: :local: :depth: 1 Minimal end-to-end calculation ------------------------------- Create a pulse, load parameters, compute the ionization probability:: import numpy as np from gasfir import ( create_pulse, get_parameters, get_diabatic_ionization_probability, get_quasi_static_rate_for_field, ) laser = create_pulse(800, 1e14, 0, 30) # 800 nm, 1e14 W/cm², CEP 0, 30 cycles params = get_parameters("He_Hacc5_QS") # Non-adiabatic (GASFIR) probability prob = get_diabatic_ionization_probability(pulse=laser, param_dict=params) print(f"P_NA = {prob:.4e}") # Quasi-static rate over a range of field amplitudes fields = np.linspace(0.01, 0.15, 100) # atomic units rates = get_quasi_static_rate_for_field(fields, params) cos\ :sup:`8` pulse (the default envelope) ------------------------------------------ :func:`gasfir.create_pulse` builds a linearly polarized pulse with a cos\ :sup:`N` intensity envelope; ``N`` defaults to 8. The duration is given in **optical cycles**:: from gasfir import create_pulse, get_parameters, get_diabatic_ionization_probability # 800 nm, 1e14 W/cm², CEP = 0, FWHM = 6 cycles, cos^8 envelope (N=8 default) laser = create_pulse(800, 1e14, 0, 6, N=8) params = get_parameters("Hydrogen_SFA") prob = get_diabatic_ionization_probability(pulse=laser, param_dict=params) The time grid and fields are available through the pulse object:: t = laser.get_tgrid(dt=0.25) # time grid (a.u.) E = laser.get_electric_field(t) # electric field E(t) A = laser.get_vector_potential(t) # vector potential A(t) Two-colour field with ``SumOfPulses`` ------------------------------------- :class:`gasfir.pulse.SumOfPulses` superposes any number of pulses (e.g. a fundamental and its second harmonic). The result behaves like any other :class:`~gasfir.Pulse`:: from gasfir import create_pulse, get_parameters, get_diabatic_ionization_probability from gasfir.pulse import SumOfPulses fundamental = create_pulse(800, 1e14, 0, 6) # 800 nm harmonic = create_pulse(400, 2e13, 0, 6) # 400 nm (SHG) two_colour = SumOfPulses([fundamental, harmonic]) prob = get_diabatic_ionization_probability( pulse=two_colour, param_dict=get_parameters("H_SFA") ) Pump–probe scan with ``TIPTOE`` (``H_diabatic``) ------------------------------------------------ :class:`gasfir.TIPTOE` holds a strong pump fixed and scans a weak probe in delay, producing a :class:`~gasfir.pulse.SumOfPulses` at each delay. :meth:`~gasfir.TIPTOE.return_delay_array` returns a Nyquist-sampled delay grid:: import numpy as np from gasfir import ( TIPTOE, create_pulse, get_parameters, get_diabatic_ionization_probability, ) pump = create_pulse(800, 3e14, 0, 3) # strong pump probe = create_pulse(800, 1e13, 0, 1) # weak probe scanner = TIPTOE(pump, probe) delays = scanner.return_delay_array() # Nyquist-sampled (oversample=4 default) params = get_parameters("H_diabatic") signal = np.array([ get_diabatic_ionization_probability( pulse=scanner.at_delay(tau), param_dict=params ) for tau in delays ]) # `signal` vs `delays` is the simulated TIPTOE trace Increase ``oversample`` for finer delay resolution:: delays_fine = scanner.return_delay_array(oversample=8) Numerical field with ``DataPulse`` ---------------------------------- :class:`gasfir.DataPulse` wraps a numerically sampled field so it can be used anywhere a :class:`~gasfir.Pulse` is accepted. Supply **either** the electric field ``E(t)`` **or** the vector potential ``A(t)`` on a time grid in atomic units. ``A(t)`` must vanish at both ends of the window:: import numpy as np from gasfir import DataPulse, get_parameters, get_diabatic_ionization_probability t = np.linspace(-400, 400, 8001) # atomic units omega = 0.057 # ~800 nm carrier (a.u.) env = np.exp(-(t / 150.0) ** 2) # Gaussian, vanishes at ends A = env * np.sin(omega * t) / omega # vector potential A(t) pulse = DataPulse(t=t, A=A) # E(t) derived as -dA/dt prob = get_diabatic_ionization_probability( pulse=pulse, param_dict=get_parameters("H_SFA") ) If you only have the electric field, pass ``E=`` instead and GASFIR integrates it to obtain ``A`` (make sure the field switches on/off smoothly so the resulting ``A`` returns to zero):: pulse = DataPulse(t=t, E=my_field_array) Retrieval strategies and pipelines (``gasfir[retrieval]``) ---------------------------------------------------------- The three-phase pipeline is **global search → least-squares polish → emcee MCMC**, driven by :func:`gasfir.retrieval.retrieve` and configured with :class:`gasfir.retrieval.RetrievalConfig`. The training data is a DataFrame with ``"pulses"`` and ``"Y"`` (target probabilities) columns. **Full pipeline, known medium** — initial guess and bounds from the stored reference parameters:: from gasfir.retrieval import RetrievalConfig, retrieve cfg = RetrievalConfig(medium_name="Hydrogen_SFA", emcee_nsteps=3000) result = retrieve(data_NA=data, config=cfg) # outputs (JSON, HDF5 chain, corner/trace plots, .tex) saved to ./Hydrogen_SFA/ **Switch the global search strategy** — CMA-ES (default) or differential evolution:: cfg = RetrievalConfig( medium_name="Hydrogen_SFA", global_method="differential_evolution", # default is "cma" de_maxiter=2000, ) **Run only selected phases** via ``run_phases=(global, polish, mcmc)``. For example, a quick CMA-ES + least-squares fit with no MCMC:: result = retrieve(data_NA=data, config=cfg, run_phases=(True, True, False)) …or extend an existing MCMC chain (skip global search and polish, resume emcee from the saved HDF5 backend):: cfg = RetrievalConfig(medium_name="Hydrogen_SFA", emcee_nsteps=6000) result = retrieve(data_NA=data, config=cfg, run_phases=(False, False, True)) **Quick sanity check** with minimal iterations:: cfg = RetrievalConfig(medium_name="Hydrogen_SFA", trial_run=True) **Simultaneous fit to non-adiabatic and quasi-static data** — pass a ``data_QS`` DataFrame (columns ``"field"`` and ``"Y"`` = log QS rate):: cfg = RetrievalConfig(medium_name="Hydrogen_SFA", simultaneous=True) result = retrieve(data_NA=data, data_QS=qs_data, config=cfg) **Cold start for an atom** — ``E_g`` is looked up from the NIST database, no other guess required:: cfg = RetrievalConfig(medium_name="Kr", cma_maxiter=5000) result = retrieve(data_NA=data, config=cfg) **Cold start for a crystal** — ``E_g`` must be supplied; fit the electron density instead of a probability:: cfg = RetrievalConfig( medium_name="MyMaterial", initial_params={"E_g": 0.30}, is_crystal=True, ret_electron_density=True, cma_maxiter=5000, ) result = retrieve(data_NA=data, config=cfg) See :doc:`/examples/parameter_fitting` for fully worked retrieval examples, post-processing of saved chains, and the low-level residual API.