def LGSSystem( system:str, # Name of the atomic system to be loaded from file fixed_params:dict={}, # Values for system parameters that will be held fixed):
LGSSystem creates numerical models for the chosen laser guide star atomic system.
def diagram( name:str| pathlib._local.Path, # Name of built-in LGS system definition, or directory of supplied system kind:str='Toy', # "Toy" to show level diagram and pumped transitions, "ToScale" to show hyperfine structure to scale, "NotToScale" to show unscaled hf structure):
Draw a level diagram for the system of the specified kind.
Substitute the free parameter values into the operator and write it explicitly as a block matrix, with 2\times2 blocks for the velocity space, each block being 4\times4 on the density matrix space:
def stationary_model( vg:Union[int, Iterable, pylgs.velocitygroups.VelocityGroups]=6, # Specification of velocity groups solver:pymor.solvers.interface.Solver |dict|None=None, # output='total_flux' # Operator to be applied to solution to obtain the output)->pylgs.pymor.models.StationaryModel: # Model for the steady-state LGS system
Return a pyMOR StationaryModel for the steady state cw LGS system.
mu = Mu(IntensitySI1=46.)
An integer can be supplied for vg to get that many evenly spaced velocity groups:
model = lgs.stationary_model(vg=30)
Solve the model and calculate the return flux by supplying values for all free parameters:
Solve the model and return the steady-state density matrix:
sol = model.solve({'IntensitySI1': 1e3})
The solution can be visualized in several ways. Plot the flux for each velocity bin:
model.flux_distribution(sol).visualize()
Plot the real and imaginary parts of the density-matrix elements for each velocity bin:
sol.visualize()
Plot just the level populations:
model.level_population(sol).visualize()
Plot the total atomic population:
model.population(sol).visualize()
Note that the above visualizations plot the contribution to the quantity from each velocity group. If the velocity groups are not all of the same width, this will cause the plots to appear distorted. In this case one can instead plot the velocity distribution of the quantities using flux_distribution, population_distribution, etc. To plot the velocity distribution of the density-matrix elements, use velocity_normalize(sol).
Table 1: Operators that can be applied to the solution of an LGS model
Description
population
Fraction of total atomic population in each velocity group
total_population
Total atomic population (should equal 1)
population_distribution
Atomic population per unit velocity interval
level_population
Population of each atomic level in each velocity group
total_level_population
Total atomic population in each level
level_population_distribution
Level population per unit velocity interval
flux
Return flux on each transition from each velocity group
total_flux
Total return flux
integrated_flux
Integral of return flux over velocity groups
flux_distribution
Return flux per unit velocity interval
velocity_sum
Sum over velocity groups
velocity_normalize
Normalize by velocity-group width
Check that the atomic population summed over all velocity groups is approximately 1:
def adaptive_stationary_model( mu, # Parameter values to use during velocity-group refinement vg:int=20, # Initial velocity groups solver:NoneType=None, # Solver to use for the linear system rtol:float=0.02, # Global error tolerance for the return flux integral atol:int=0, # Absolute tolerance for the return flux integral refine_fraction:float=0.2, # Fraction of velocity groups to refine at each iteration return_intermediate:bool=False, # Whether to return intermediate integration results max_iterations:int=50, # Maximum number of refinement iterations max_velocity_groups:int=500, # Maximum number of velocity groups allowed during refinement use_initial_guess:bool=True, # Whether to use the initial guess when solving the refined model reuse_ilu:bool=True, # Whether to reuse the ILU factorization from the previous model)->pylgs.pymor.models.StationaryModel: # Steady-state LGS model with more velocity groups in regions that produce more return flux
Create a StationaryModel with narrower velocity bins in velocity regions with higher flux.
Create a model with adaptively refined velocity groups using a particular value for the intensity parameter during refinement:
def instationary_model( vg:Union[int, Iterable, pylgs.velocitygroups.VelocityGroups]=6, # Specification of velocity groups T:float=1e-06, # Final time (seconds) num_values:int=100, # Number of time step values to return initial_rho:NoneType=None, # Initial density matrix. `None` means to use the thermal distribution time_stepper:NoneType=None, # Solver to use. `None` means to use the default `BDFTimeStepper` preconditioner:NoneType=None, **kwargs)->pylgs.pymor.models.InstationaryModel: # Model for the LGS system dynamics
The numpy model is currently much faster for explicit methods than the xarray model. However, it requires Kronecker-expanding the DM x VG product-space operators. It might be a little faster if this wasn’t necessary, but no more than a factor of 2 or 3. It seems like BlockOperator and BlockVectorArray are designed for this, but it looks like they are not optimized for speed. It could be implemented by optimizing XarrayMatrixOperator so that all apply operations can bypass xarray and use numpy instead. Note that sparse DataArrays currently use COO format, would want to switch to CSR, but need to enforce 2D matrices or allow N-D CSR arrays.
Evaluating the coefficients at a given time also could be sped up a little (use lambdify to convert ExpressionFunctions to GenericFunctions), but it is not the dominant source of computation time.
# def to_dense_matrix(op):# a = to_matrix(op)# try: a = a.todense()# except: pass# return a
def numpy_instationary_model( vg, *, T:float=1e-06, # Final time (seconds) num_values:int=100, # Number of time step values to return initial_rho:NoneType=None, # Initial density matrix. `None` means to use the thermal distribution time_stepper:NoneType=None, # Solver to use. `None` means to use the default `BDFTimeStepper` preconditioner:NoneType=None): # Model for the LGS system dynamics
def stationary_floquet_model( mu, # Parameter specification for parameters modulated at a frequency `nu` time, # List of time values to use for reconstruction n_vector, # Number of terms in the system Fourier series nu:str='nu', # Name of the frequency variable n_operator:NoneType=None, # Number of terms in the operator Fourier series. `None` defaults to `n_vector` - 1 vg:Union[int, Iterable, pylgs.velocitygroups.VelocityGroups]=6, # Specification of velocity groups solver:NoneType=None)->pylgs.pymor.models.StationaryFloquetModel: # Model for the Fourier coefficients of the periodic LGS system
Return a StationaryFloquetModel for the Fourier coefficients of the periodic state of a modulated LGS system.
The StationaryFloquetModel solves for the periodic state of a modulated system after the transient dynamics have died out.
Build a stationary Floquet model for six Fourier harmonics of a system with sinusoidally modulated intensity:
def adaptive_stationary_floquet_model( mu, # Parameter specification for parameters modulated at a frequency `nu` time, # List of time values to use for reconstruction n_vector, # Number of terms in the system Fourier series mu_refine:NoneType=None, # Additional parameter specifications used during velocity-group refinement nu:str='nu', # Name of the frequency variable n_operator:NoneType=None, # Number of terms in the operator Fourier series. `None` defaults to `n_vector` - 1 vg:int=20, # Initial (number of) velocity groups solver:NoneType=None, # Steady-state solver or options for the default solver rtol:float=0.02, # Global error tolerance for the return flux integral refine_fraction:float=0.2, # Fraction of velocity groups to refine at each iteration max_iterations:int=50, # Maximum number of refinement iterations max_velocity_groups:int=500, # Maximum number of velocity groups allowed during refinement return_intermediate:bool=False, # Whether to return intermediate results from the refinement process atol:int=0, # Absolute error tolerance for the return flux integral)->pylgs.pymor.models.StationaryFloquetModel: # Steady-state LGS model with more velocity groups in regions that produce more return flux
Create a StationaryModel with narrower velocity bins in velocity regions with higher flux.
Create a model with adaptively refined velocity groups using a particular value for the intensity parameter during refinement:
mu = {'nu': 1e8}model, sol = lgs.adaptive_stationary_floquet_model( mu={'IntensitySI1': "5000.*sin(nu*t)**2"}, mu_refine=mu, time=np.linspace(0, T, num_values), n_vector=20, rtol=.04, solver={'rtol': .01})