def solve_ide_implicit_from_kicks(kicks): A = np.zeros((len(kicks), len(kicks)), dtype=np.complex128) omega = ion.HydrogenBoundState(1, 0).energy / hbar prefactor = -((electron_charge / hbar)**2) kernel = lambda td: ide.hydrogen_kernel_LEN( td, omega_b=ion.HydrogenBoundState(1, 0).energy / hbar) def element(n, m): rv = (prefactor * kicks[n].amplitude * kicks[m].amplitude * kernel(kicks[n].time - kicks[m].time)) if m == n: rv -= 1 elif m == n - 1: # first subdiagonal rv += 1 return rv for n in range(len(kicks)): for m in range(n + 1): A[n, m] = element(n, m) b = np.zeros(len(kicks)) b[0] = 1 a = linalg.solve_triangular(A, b, lower=True) return a, kicks
def iterative(pulse, tb=3, t_pts=200, tols=(1e-3, 1e-6), maxiter=100, processes=2): omega = ion.HydrogenBoundState(1, 0).energy / hbar t = np.linspace(-pulse.pulse_width * tb, pulse.pulse_width * tb, t_pts) solvers = [ CIDESolver( y_initial=1, x=t, c=functools.partial(c, omega=omega), d=functools.partial(d, pulse=pulse), k=functools.partial(k, pulse=pulse), lower_bound=functools.partial(lower, t=t), upper_bound=upper, f=f, global_error_tolerance=tol, max_iterations=maxiter, ) for tol in tols ] return si.utils.multi_map(run, solvers, processes=processes)
def analytic(): omega_b = ion.HydrogenBoundState(1, 0).energy / hbar m = electron_mass a = bohr_radius thingy = (a**2) * m * omega_b prefactor = (1j * 3 * (a**4) * m * pi / (16 * (((2 * (a**2) * m * omega_b) + hbar)**6))) first = 96 * (thingy**5) second = 336 * (thingy**4) * hbar third = 560 * (thingy**3) * (hbar**2) fourth = 840 * (thingy**2) * (hbar**3) fifth = -210 * thingy * (hbar**4) sixth = -7 * (hbar**5) seventh = (512 * np.sqrt(2) * (a**3) * omega_b * np.sqrt(-(m**3) * omega_b * (hbar**7))) # print(prefactor * first) # print(prefactor * second) # print(prefactor * third) # print(prefactor * fourth) # print(prefactor * fifth) # print(prefactor * sixth) # print(prefactor * seventh) return prefactor * (first + second + third + fourth + fifth + sixth + seventh)
def kernel(time_difference, alpha, omega_b=ion.HydrogenBoundState(1, 0).energy / u.hbar): prefactor = 8 * u.pi * (u.bohr_radius**3) * np.exp( 1j * omega_b * time_difference) result, *errs = si.math.complex_quad(kernel_integrand, 0, 20 / u.bohr_radius, args=(time_difference, alpha)) return prefactor * result
def analytic_b2( td, eta=1 * atomic_electric_field * atomic_time, omega=ion.HydrogenBoundState(1, 0).energy / hbar, ): return ( np.abs( (1 + (alpha(eta) * kernel(td, omega))) / ((1 + (alpha(eta) * kernel(0, omega))) ** 2) ) ** 2 )
def construct_A(kicks): # A = np.zeros((len(kicks), len(kicks)), dtype = np.complex128) A = np.tri(len(kicks), dtype=np.complex128) # A = sparse.csr_matrix((len(kicks), len(kicks)), dtype = np.complex128) print("size of A", si.utils.bytes_to_str(A.nbytes)) omega = ion.HydrogenBoundState(1, 0).energy / hbar prefactor = ide.hydrogen_prefactor_LEN(electron_charge) def kernel(td): return ide.hydrogen_kernel_LEN(td) * np.exp(1j * omega * td) # tds = np.linspace(0, kicks[-1].time + (100 * asec), num = 1000) # kinterp = interp.interp1d(tds, kernel(tds), kind = 'cubic', fill_value = 0, bounds_error = False, assume_sorted = True) # kernel = lambda td: ide.hydrogen_kernel_LEN(td) * np.exp(1j * omega * td) # time_delays = {(n, m): kicks[n].time - kicks[m].time for n in range(len(kicks)) for m in range(n + 1)} # kernel_dict = {(n, m): kernel(time_delays[n, m]) for n in range(len(kicks)) for m in range(n + 1)} times = np.array([kick.time for kick in kicks]) amplitudes = np.array([kick.amplitude for kick in kicks]) # def element(n, m): # rv = prefactor * amplitudes[n] * amplitudes[m] * kernel(time_delays[n, m]) # if m == n: # rv -= 1 # elif m == n - 1: # first subdiagonal # rv += 1 # # return rv # # with si.utils.BlockTimer() as timer: # for n in range(len(kicks)): # for m in range(n + 1): # A[n, m] = element(n, m) for idx in range(len(kicks)): A[idx, :] *= amplitudes[idx] # row idx A[:, idx] *= amplitudes[idx] # column idx A[idx, :idx + 1] *= kernel(times[idx] - times[:idx + 1]) # A[idx, :] *= kinterp(times[idx] - times) A *= prefactor A[np.arange(len(kicks)), np.arange(len(kicks))] -= 1 # diagonal A[np.arange(len(kicks) - 1) + 1, np.arange(len(kicks) - 1)] += 1 # first subdiagonal A = sparse.csr_matrix(A, dtype=np.complex128) print("size of A", si.utils.bytes_to_str(A.data.nbytes)) return A
def kick_delay_scan(eta=0.1 * atomic_time * atomic_electric_field): delays = np.linspace(1, 1000, 100) * asec kickss = [(ide.delta_kick(0, eta), ide.delta_kick(delay, -eta)) for delay in delays] solns = [solve_ide_implicit_from_kicks(kicks) for kicks in kickss] alpha = ((electron_charge / hbar)**2) * (eta**2) omega = ion.HydrogenBoundState(1, 0).energy / hbar kernel = lambda td: ide.hydrogen_kernel_LEN(td) * np.exp(1j * omega * td) analytic = (1 + (alpha * kernel(delays))) / ((1 + (alpha * kernel(0)))**2) ime_limit = np.abs(solns[-1][0][-1])**2 ana_limit = np.abs(1 / ((1 + (alpha * kernel(0)))**2))**2 print(ime_limit) print(ana_limit) print() si.vis.xy_plot( f"kick_delay_scan__eta={eta / atomic_time * atomic_electric_field:.3f}au", delays, [np.abs(soln[0][-1])**2 for soln in solns], np.abs(analytic)**2, line_labels=["IME", "Analytic"], line_kwargs=[None, { "linestyle": "--" }], x_label=r"Kick Delay $ \Delta $", x_unit="asec", y_label=r"$ \left| a(t_f) \right|^2 $", title= f"Delta-Kick Model Kick Delay Scan, $\eta = {eta / atomic_time * atomic_electric_field:.3f} \, \mathrm{{a.u.}}$", vlines=[93 * asec, 150 * asec], hlines=[ime_limit, ana_limit], x_lower_limit=0, **PLOT_KWARGS, )
def iterative(): pw = 200 * asec omega = ion.HydrogenBoundState(1, 0).energy / hbar efield = ion.potentials.GaussianPulse.from_number_of_cycles( pulse_width=pw, fluence=1 * Jcm2, phase=0).get_electric_field_amplitude kern = ide.hydrogen_kernel_LEN t = np.linspace(-pw * 3, pw * 3, 200) solver = IDESolver( y_initial=1, x=t, c=lambda x, y: -1j * omega * y, d=lambda x: -((electron_charge / hbar)**2) * efield(x), k=lambda x, s: efield(s) * kern(x - s), lower_bound=lambda x: t[0], upper_bound=lambda x: x, f=lambda y: y, global_error_tolerance=1e-6, ) solver.solve() return solver
def solve_ide_implicit_from_kicks_v2(kicks): b = np.empty(len(kicks), dtype=np.complex128) b[0] = 1 omega = ion.HydrogenBoundState(1, 0).energy / hbar prefactor = ide.hydrogen_prefactor_LEN(electron_charge) def kernel(td): return ide.hydrogen_kernel_LEN(td) * np.exp(1j * omega * td) times = np.array([kick.time for kick in kicks]) amplitudes = np.array([kick.amplitude for kick in kicks]) k0 = kernel(0) for n in range(1, len(b)): a_n = amplitudes[n] sum_pre = prefactor * a_n t_n = times[n] s = sum_pre * np.sum( amplitudes[:n] * kernel(times[n] - times[:n]) * b[:n]) b[n] = (b[n - 1] + s) / (1 - (prefactor * k0 * a_n * a_n)) return b, kicks
if __name__ == "__main__": with si.utils.LogManager("simulacra", "ionization", stdout_logs=True, stdout_level=logging.DEBUG) as logger: anim_kwargs = dict(length=10, target_dir=OUT_DIR) epot_axman = animation.animators.ElectricPotentialPlotAxis( show_electric_field=True, show_vector_potential=False, show_y_label=False, show_ticks_right=True, ) test_state_axman = animation.animators.TestStateStackplotAxis( states=tuple( ion.HydrogenBoundState(n, l) for n in range(5) for l in range(n))[:8]) wavefunction_axman = animation.animators.WavefunctionStackplotAxis( states=( ion.HydrogenBoundState(1, 0), ion.HydrogenBoundState(2, 0), ion.HydrogenBoundState(3, 1), )) animators = [ animation.animators.PolarAnimator( postfix="g2", axman_wavefunction=animation.animators. SphericalHarmonicPhiSliceMeshAxis(shading="flat"), axman_lower_right=deepcopy(epot_axman),
# x_lower_limit = 0, # y_unit = bohr_radius ** 2, # y_label = r'$ \left| \left< wavenumber | \hat{z} | b \right> \right|^2 $', # legend_kwargs = {'loc': 'upper right'}, # font_size_legend = 8, # **PLOT_KWARGS # ) tds = np.linspace(0, 10000, 10000) * asec print(9 * pi / 32) print(integrate(integrand_from_bessels, 0 * asec) / (bohr_radius**2)) print(integrate(integrand_from_hecht, 0 * asec) / (bohr_radius**2)) omega_b = ion.HydrogenBoundState(1, 0).energy / hbar kernel_from_bessels = integrate(integrand_from_bessels, tds) * np.exp( 1j * omega_b * tds) kernel_from_hecht = integrate(integrand_from_hecht, tds) * np.exp( 1j * omega_b * tds) # si.vis.xy_plot( # f'kernel', # tds, # np.abs(kernel_from_bessels), # np.real(kernel_from_bessels), # np.imag(kernel_from_bessels), # np.abs(kernel_from_hecht), # np.real(kernel_from_hecht), # np.imag(kernel_from_hecht), # line_labels = [
if __name__ == "__main__": with si.utils.LogManager("simulacra", "ionization", stdout_logs=True, stdout_level=logging.INFO) as logger: specs = [] bound = 100 radial_points = bound * 4 angular_points = 100 t_init = 0 t_final = 1000 dt = 1 initial_state = ion.HydrogenBoundState( 1, 0, 0) + ion.HydrogenBoundState(2, 1, 0) window = ion.potentials.LinearRampTimeWindow(ramp_on_time=t_init * asec, ramp_time=200 * asec) e_field = ion.SineWave.from_frequency(1 / (50 * asec), amplitude=1 * atomic_electric_field, window=window) mask = ion.RadialCosineMask(inner_radius=(bound - 25) * bohr_radius, outer_radius=bound * bohr_radius) animators = [ src.ionization.animators.CylindricalSliceAnimator( postfix="_nm", target_dir=OUT_DIR, distance_unit="nm"), src.ionization.animators.CylindricalSliceAnimator(
"ionization", stdout_level=logging.DEBUG) def run(spec): with logman as logger: sim = spec.to_sim() sim.info().log() sim.run() sim.info().log() if __name__ == "__main__": with logman as logger: state_a = ion.HydrogenBoundState(1, 0) state_b = ion.HydrogenBoundState(3, 1) amplitudes = [0.001] cycles = [1] gauges = ["LEN"] dt = 1 bound = 100 ppbr = 10 plot_radius = 50 shading = "flat" animator_kwargs = dict(target_dir=OUT_DIR,
OUT_DIR = os.path.join(os.getcwd(), "out", FILE_NAME) if __name__ == "__main__": with si.utils.LogManager("simulacra", "ionization", stdout_logs=True, stdout_level=logging.DEBUG) as logger: bound = 100 points_per_bohr_radius = 4 sim = ion.SphericalHarmonicSpecification( "test", r_bound=bound * bohr_radius, r_points=bound * points_per_bohr_radius, l_bound=50, initial_state=ion.HydrogenBoundState(1, 0), use_numeric_eigenstates=True, numeric_eigenstate_max_energy=10 * eV, numeric_eigenstate_max_angular_momentum=5, ).to_sim() print(sim.info()) print() # for wavenumber, v in sim.mesh.analytic_to_numeric.items(): # print(f'{wavenumber} -> {v}') print() a_state = ion.HydrogenBoundState(1, 0) print(a_state) print(sim.mesh.get_g_for_state(a_state))
FILE_NAME = os.path.splitext(os.path.basename(__file__))[0] OUT_DIR = os.path.join(os.getcwd(), "out", FILE_NAME) if __name__ == "__main__": # test_states = [ion.HydrogenBoundState(n, l) for n in range(6) for l in range(n)] l_bound = 1 bound = 100 points_per_bohr_radius = 4 spec_kwargs = { "r_bound": bound * bohr_radius, "r_points": bound * points_per_bohr_radius, "l_bound": 100, "initial_state": ion.HydrogenBoundState(1, 0), "time_initial": 0 * asec, "time_final": 200 * asec, "time_step": 1 * asec, } OUT_DIR = os.path.join( OUT_DIR, "bound={}_ppbr={}".format(bound, points_per_bohr_radius) ) sim = ion.SphericalHarmonicSpecification("eig", **spec_kwargs).to_sim() with si.utils.LogManager( "simulacra", "ionization", stdout_logs=True, stdout_level=logging.INFO,
OUT_DIR = os.path.join(os.getcwd(), "out", FILE_NAME) PLOT_KWARGS = dict(fig_width=si.vis.points_to_inches(500)) def get_omega_min(sim_result): return sim_result.electric_potential[0].omega_min def get_omega_carrier(sim_result): return sim_result.electric_potential[0].omega_carrier if __name__ == "__main__": with si.utils.LogManager("simulacra", "ionization") as logger: states = list(ion.HydrogenBoundState(n, 0) for n in range(1, 10)) transition_energies = set( np.abs(a.energy - b.energy) for a, b in itertools.product(states, repeat=2)) transition_frequencies = [energy / h for energy in transition_energies] print(sorted(transition_energies)) for energy in sorted(transition_energies): print(energy / eV, energy / h / THz) jp_names = [ "hyd__omega_min_scan__sinc.job", "hyd__omega_min_scan__gaussian__fixed_bounds.job", ] for jp_name in jp_names: jp = clu.JobProcessor.load(jp_name) jp.job_dir_path = OUT_DIR
import os import numpy as np import scipy.sparse.linalg as sparsealg import simulacra as si from simulacra.units import * import ionization as ion FILE_NAME = os.path.splitext(os.path.basename(__file__))[0] OUT_DIR = os.path.join(os.getcwd(), "out", FILE_NAME) if __name__ == "__main__": n_max = 5 test_states = [ ion.HydrogenBoundState(n, l) for n in range(n_max + 1) for l in range(n) ] # test_states += [ion.HydrogenCoulombState(energy = e * eV, l = l) for e in range(0, 10) for l in range(10)] l_max = 10 bound = 200 points_per_bohr_radius = 4 spec_kwargs = { "r_bound": bound * bohr_radius, "r_points": bound * points_per_bohr_radius, "l_bound": 100, "initial_state": ion.HydrogenBoundState(1, 0), "time_initial": -1000 * asec, "time_final": 1000 * asec,
import os import numpy as np import simulacra as si from simulacra.units import * import ionization as ion FILE_NAME = os.path.splitext(os.path.basename(__file__))[0] OUT_DIR = os.path.join(os.getcwd(), "out", FILE_NAME) PLOT_KWARGS = dict(target_dir=OUT_DIR, img_format="png", fig_dpi_scale=6) time_field_unit = atomic_electric_field * atomic_time hydrogen_omega = np.abs(ion.HydrogenBoundState(1).energy / hbar) def new_amplitude( initial_amplitude, initial_phase, kick_amplitude, test_mass=electron_mass, test_charge=proton_charge, omega=hydrogen_omega, ): amp = test_charge * kick_amplitude / (test_mass * omega) return np.sqrt((initial_amplitude**2) + (amp**2) + (2 * initial_amplitude * amp * np.cos(initial_phase)))
file_logs=False, file_mode="w", file_dir=OUT_DIR, file_name="log", ) as logger: bound = 70 points_per_bohr_radius = 4 dt = 0.1 store_every = int(1 / dt) spec_kwargs = dict( r_bound=bound * bohr_radius, r_points=bound * points_per_bohr_radius, l_bound=70, initial_state=ion.HydrogenBoundState(1, 0), time_initial=0 * asec, time_final=500 * asec, time_step=dt * asec, use_numeric_eigenstates=True, numeric_eigenstate_max_energy=200 * eV, numeric_eigenstate_max_angular_momentum=50, electric_potential=ion.SineWave.from_photon_energy( rydberg + 5 * eV, amplitude=0.5 * atomic_electric_field), mask=ion.RadialCosineMask(inner_radius=0.8 * bound * bohr_radius, outer_radius=bound * bohr_radius), ) analytic_test_states = [ ion.HydrogenBoundState(n, l) for n in range(6) for l in range(n) ]
) # pulse = ion.potentials.SincPulse( # pulse_width = pw, # fluence = flu, # window = ion.potentials.LogisticWindow( # window_time = tb * pw, # window_width = .2 * pw # ) # ) shared_spec_kwargs = dict( time_initial=-tb * pulse.pulse_width, time_final=tb * pulse.pulse_width, electric_potential=pulse, kernel=ide.hydrogen_kernel_LEN, kernel_kwargs={"omega_b": ion.HydrogenBoundState(1, 0).energy / hbar}, time_step_min=min_dt, ) specs = [] for method, dt in itertools.product(methods, max_dts): spec = ide.IntegroDifferentialEquationSpecification( f"{method}_dt={dt / asec:3f}as", evolution_method=method, time_step=dt, time_step_max=dt, **shared_spec_kwargs, ) specs.append(spec)
window=ion.potentials.LogisticWindow(window_time=0.9 * t_bound * asec, window_width=10 * asec), ) # # efield += ion.SineWave.from_photon_energy(rydberg + 30 * eV, amplitude = .05 * atomic_electric_field, # window = ion.potentials.LogisticWindow(window_time = .9 * t_bound * asec, window_width = 10 * asec)) # efield = ion.SineWave(twopi * (c / (800 * nm)), amplitude = .01 * atomic_electric_field, # window = window) spec_kwargs = dict( r_bound=bound * bohr_radius, r_points=bound * points_per_bohr_radius, l_bound=20, initial_state=ion.HydrogenBoundState(1, 0), time_initial=-t_bound * asec, time_final=(t_bound + t_extra) * asec, time_step=1 * asec, use_numeric_eigenstates=True, numeric_eigenstate_max_energy=50 * eV, numeric_eigenstate_max_angular_momentum=5, electric_potential=efield, electric_potential_dc_correction=True, mask=ion.RadialCosineMask(inner_radius=0.8 * bound * bohr_radius, outer_radius=bound * bohr_radius), store_data_every=-1, ) sim = ion.SphericalHarmonicSpecification( f"PWTest_amp={amp}aef_phase={phase / pi:3f}pi__tB={t_bound}pw__tE={t_extra}asec",
) sim.plot_angular_momentum_vs_time(target_dir=spec.out_dir_mod) sim.plot_angular_momentum_vs_time( target_dir=spec.out_dir_mod, log=True, name_postfix="_log" ) if __name__ == "__main__": with log as logger: bound = 200 r_points = bound * 4 l_bound = 128 dt = 1 initial_states = [ ion.HydrogenBoundState(1, 0), ion.HydrogenBoundState(2, 0), ion.HydrogenBoundState(2, 1), ] pulse_widths = [10, 50, 100, 250, 500, 1000, 1500, 2000] fluences = [0.1, 1, 5, 10, 20] specs = [] for initial_state in initial_states: for pulse_width in pulse_widths: for fluence in fluences: t_step = dt * asec if pulse_width < 60: t_step /= 10
FILE_NAME = os.path.splitext(os.path.basename(__file__))[0] OUT_DIR = os.path.join(os.getcwd(), "out", FILE_NAME) si.utils.ensure_dir_exists(OUT_DIR) logger = logging.getLogger("simulacra") logger.setLevel(logging.DEBUG) stdout_handler = logging.StreamHandler(sys.stdout) stdout_handler.setLevel(logging.DEBUG) stdout_handler.setFormatter(si.utils.LOG_FORMATTER) logger.addHandler(stdout_handler) if __name__ == "__main__": bs = ion.HydrogenBoundState(5, 0) logger.info(bs) logger.info(repr(bs)) # bss = ion.Superposition({ion.HydrogenBoundState(n, l, 0): 1 for n in range(3) for l in range(n)}) # # logger.info(bss) # logger.info(repr(bss)) try: bs2 = ion.HydrogenBoundState(2, 3, 5) except ion.IllegalQuantumState as err: logger.exception("expected excepted") print(ion.HydrogenBoundState(1, 0, 0) < ion.HydrogenBoundState(3, 2, 1)) print(ion.HydrogenBoundState(1, 0, 0) <= ion.HydrogenBoundState(3, 2, 1))
if __name__ == "__main__": with logman as logger: with si.utils.BlockTimer() as timer: r_bound = 200 points_per_r = 8 r_points = r_bound * points_per_r l_bound = 500 dt = 0.5 t_bound = 15 n_max = 3 shading = "flat" initial_states = [ion.HydrogenBoundState(1, 0)] pulse_types = [ion.potentials.SincPulse] pulse_widths = [93, 200] fluences = [1, 5, 10] phases = np.linspace(0, pi / 2, 3) # used by all sims mask = ion.RadialCosineMask( inner_radius=(r_bound - 25) * bohr_radius, outer_radius=r_bound * bohr_radius, ) out_dir_mod = os.path.join( OUT_DIR, f"R={r_bound}br_PPR={points_per_r}_L={l_bound}_dt={dt}as_T={t_bound}pw", )
sim = ion.ElectricFieldSimulation(spec) sim.info().log() sim.run() sim.info().log() # sim.plot_wavefunction_vs_time(target_dir = OUT_DIR) if __name__ == "__main__": with si.utils.LogManager("simulacra", "ionization", stdout_logs=True, stdout_level=logging.DEBUG) as logger: states = [ ion.HydrogenBoundState(n, l) for n in range(3) for l in range(n) ] bound = 225 angular_points = 50 dt = 2.5 * asec specs = [] for amp in (1, 2): for period in (100, 200): for state in states: prefix = "{}_{}_amp={}_per={}__".format( state.n, state.l, amp, period) t_init = 0 t_final = 20 * period * asec
cos_kicks = ide.decompose_potential_into_kicks(cos_pulse, times) sin_kicks = ide.decompose_potential_into_kicks(sin_pulse, times) max_cos_kick = max(k.amplitude for k in cos_kicks) max_sin_kick = max(k.amplitude for k in sin_kicks) return max_cos_kick, max_sin_kick if __name__ == "__main__": with si.utils.LogManager("simulacra", "ionization", stdout_level=logging.DEBUG) as logger: delta_t = np.linspace(0, 500, 500) * asec omega_alpha = ion.HydrogenBoundState(1).energy / hbar eta = 0.2 * time_field_unit tau_alpha = ide.gaussian_tau_alpha_LEN(bohr_radius, electron_mass) B = ide.gaussian_prefactor_LEN(bohr_radius, electron_charge) cos_eta, sin_eta = get_cosine_and_sine_etas(pulse_width=200 * asec, fluence=0.001 * Jcm2) print(cos_eta / time_field_unit, sin_eta / time_field_unit) cos_beta = B * (cos_eta**2) sin_beta = B * (sin_eta**2) si.vis.xy_plot( "delta_t_scan",