def psi(time, L=0, M=1000, aperiodicity=0,kind=0): """Return the probability amplitude the M-site lattice at the given time. The initial condition is amplitude 1 at the central site, zero at all other sites. Parameters ---------- time : float End time of the integration. L : float Nonlinearity parameter. M : int Number of lattice sites. (Default 101.) aperiodicity : float Aperiodicity parameter, defined in terms of the hoppings as (b/a - 1). (Default 0, which corresponds to a periodic chain.) Returns ------- y : float Amplitude at the central site, $|\psi_{M/2}|$. """ integrator = complex_ode(dnls_rhs(M, L, aperiodicity,kind)) central_site_index = (M - 1)/2 ic = np.zeros(shape=(M,)) ic[central_site_index] = 1 integrator.set_initial_value(ic) y= integrator.integrate(time) integrator = complex_ode(dnls_rhs(M, L, aperiodicity,kind)) return y
def mod_manifold_polar(x, y, lmbda, A, s, p, m, k): ''' def manifold_polar(x,y,lambda,A,s,p,m,k,mu): return omega, alpha Returns "omega", the orthogonal basis for the manifold evaluated at x(2) and "gamma" the radial equation evaluated at x(2). Input "x" is the interval on which the manifold is solved, "y" is the initializing vector, "lambda" is the point in the complex plane where the Evans function is evaluated, "A" is a function handle to the Evans matrix, s,p,m are structures explained in the STABLAB documentation, and k is the dimension of the manifold sought.''' def ode_f(x, y): return m['method'](x, y, lmbda, A, s, p, m['n'], k) omega = np.zeros((m['n'], k, len(x)), dtype=complex) alpha = np.zeros((k, k, len(x)), dtype=complex) omega[:, :, 0], alpha[:, :, 0] = y, np.eye(k) t0, y0 = x[0], y.reshape(m['n'] * k, order='F') y0 = np.concatenate((y0, (np.eye(k)).reshape(k * k, order='F'))) test = complex_ode(ode_f).set_integrator('dopri5', atol=m['options']['AbsTol'], rtol=m['options']['RelTol'], nsteps=5000) test.set_initial_value(y0, t0) for j in range(1, len(x)): test.integrate(x[j]) omega[:, :, j] = test.y[0:k * m['n']].reshape(m['n'], k, order='F') alpha[:, :, j] = test.y[k * m['n']:].reshape(k, k, order='F') return omega, alpha
def psi(t,M=10,steps=1, L=0, aperiodicity=0,kind=0): """ Parameters ---------- time : float End time of the integration. L : float Nonlinearity parameter. M : int Number of lattice sites. (Default 101.) aperiodicity : float Aperiodicity parameter, defined in terms of the hoppings as (b/a - 1). (Default 0, which corresponds to a periodic chain.) kind: 0(periodic),1 (fib),2 (TM),3 (RS) Returns ------- y : float wavefn at time t """ r = integrate.complex_ode(dnls_rhs(M, L, aperiodicity,kind)) central_site_index = (M - 1)/2 ic = np.zeros(shape=(M,)) ic[central_site_index] = 1.0 r.set_initial_value(ic) dt = float(t)/steps wavefn = np.ones((steps,M), dtype=np.complex) t_arr=np.ones((steps), dtype=np.float) for idx in xrange(steps): #steps are needed here if r.successful(): #essentially it's an saying **if True:** wavefn[idx,:] = r.y[:] t_arr[idx]=r.t else: raise ValueError("Integration failed at t = {}".format(r.t)) #i don't understand this line r.integrate(r.t + dt)#note that if dt is too big, then you will get an error. So, steps should at least be same as return wavefn,t_arr #time units
def _run_solout_break_test(self, integrator): # Check correct usage of stopping via solout ts = [] ys = [] t0 = 0.0 tend = 20.0 y0 = [0.0] def solout(t, y): ts.append(t) ys.append(y.copy()) if t > tend / 2.0: return -1 def rhs(t, y): return [1.0 / (t - 10.0 - 1j)] ig = complex_ode(rhs).set_integrator(integrator) ig.set_solout(solout) ig.set_initial_value(y0, t0) ret = ig.integrate(tend) assert_array_equal(ys[0], y0) assert_array_equal(ys[-1], ret) assert_equal(ts[0], t0) assert_(ts[-1] > tend / 2.0) assert_(ts[-1] < tend)
def update_el_state(self, state: state.State): self.d_old = self.d_new self.d_new = state.drv_coupling self.E_old = self.E_new self.E_new = state.ad_energy dv_ave = 0.5 * (self.d_new.dot(state.v) + self.d_old.dot(state.v)) E_ave = 0.5 * (self.E_new + self.E_old) H = np.diag(E_ave) - 1j * dv_ave if self.using_ode: def liouville(t, rho): rho_ = rho.reshape(H.shape) return (-1j * (H.dot(rho_) - rho_.dot(H))).flatten() r = complex_ode(liouville) r.set_initial_value(state.rho_el.flatten()) state.rho_el = r.integrate(self.dt).reshape(H.shape) else: # Verlet integration drho = -1j * (H.dot(state.rho_el) - state.rho_el.dot(H)) rho_el_old_tmp = state.rho_el state.rho_el = 2 * state.rho_el - self.rho_el_old + drho * dt**2 self.rho_el_old = rho_el_old_tmp self.update_hopping_prob(state, dv_ave)
def psi(t,M=10,steps=1, L=0, aperiodicity=0,kind=0): r = integrate.complex_ode(dnls_rhs(M, L, aperiodicity,kind)) central_site_index = (M - 1)/2 ic = np.zeros(shape=(M,)) ic[central_site_index] = 1.0 r.set_initial_value(ic) dt = t/steps wavefn = np.ones((steps,M), dtype=np.complex) t_arr=np.ones((steps), dtype=np.float) for idx in xrange(steps): if r.successful(): #essentially, **if True:** if abs(r.y[0])< 1e-8 and abs(r.y[-1])<1e-8: #to make sure the lattice is big enough so that wavefn doesn't touch the boundary. wavefn[idx,:] = r.y[:] t_arr[idx]=r.t else: #raise ValueError("wavefunction touching the boundary at t = {}".format(r.t)) print ("wfn touching the boundary at t = {} for p={}, U={}".format(r.t,aperiodicity,L)) wave_fn_truncated=wavefn[0:idx,:] t_arr_truncated=t_arr[0:idx] return wave_fn_truncated, t_arr_truncated else: raise ValueError("Integration failed at t = {}".format(r.t)) r.integrate(r.t + dt) #print r.t return wavefn,t_arr
def _evolve_cont(i,H,T,atol=1E-9,rtol=1E-9): """ This function evolves the ith local basis state under the Hamiltonian H up to period T. This is used to construct the stroboscpoic evolution operator """ nsteps=_np.iinfo(_np.int32).max # huge number to make sure solver is successful. psi0=_np.zeros((H.Ns,),dtype=_np.complex128) psi0[i]=1.0 solver=complex_ode(H._hamiltonian__SO) solver.set_integrator('dop853', atol=atol,rtol=rtol,nsteps=nsteps) solver.set_initial_value(psi0,t=0.0) t_list = [0,T] nsteps = 1 while True: for t in t_list[1:]: solver.integrate(t) if solver.successful(): if t == T: return solver.y continue else: break nsteps *= 10 t_list = _np.linspace(0,T,num=nsteps+1,endpoint=True)
def _evolve_cont(i,H,T,atol=1E-9,rtol=1E-9): """This function evolves the i-th local basis state under the Hamiltonian H up to period T. It is used to construct the stroboscpoic evolution operator. """ nsteps=_np.iinfo(_np.int32).max # huge number to make sure solver is successful. psi0=_np.zeros((H.Ns,),dtype=_np.complex128) psi0[i]=1.0 solver=complex_ode(H._hamiltonian__SO) solver.set_integrator('dop853', atol=atol,rtol=rtol,nsteps=nsteps) solver.set_initial_value(psi0,t=0.0) t_list = [0,T] nsteps = 1 while True: for t in t_list[1:]: solver.integrate(t) if solver.successful(): if t == T: return solver.y continue else: break nsteps *= 10 t_list = _np.linspace(0,T,num=nsteps+1,endpoint=True)
def system(n,y0,tf,f,args = []): """ Integration of the differential system between t = 0 and tf : - n : number of step - y0 : initial(s) condition(s) - tf : endpoint - k : tested eigenvalue - f : defined differential system in scipy.integrate fashion """ sol = complex_ode(f) # complex_ode doesn't accept args in set_f_params method sol.set_f_params(args,) sol.set_initial_value(y0,0) #sol.set_integrator('zvode', method='bdf') dt = tf/(n*1.) y = np.zeros((n,len(y0))) y[0] = y0 for i in range(0,n): y[i] = sol.integrate(sol.t+dt) print("i : {}, y : {}".format(i,y)) return y
def _run_solout_break_test(self, integrator): # Check correct usage of stopping via solout ts = [] ys = [] t0 = 0.0 tend = 20.0 y0 = [0.0] def solout(t, y): ts.append(t) ys.append(y.copy()) if t > tend/2.0: return -1 def rhs(t, y): return [1.0/(t - 10.0 - 1j)] ig = complex_ode(rhs).set_integrator(integrator) ig.set_solout(solout) ig.set_initial_value(y0, t0) ret = ig.integrate(tend) assert_array_equal(ys[0], y0) assert_array_equal(ys[-1], ret) assert_equal(ts[0], t0) assert_(ts[-1] > tend/2.0) assert_(ts[-1] < tend)
def prepare_integrator(simparameters, inifield): """ prepare an integration scipy can understand """ # only pass the necessary subset of the simparameters dict to GNLSE ... simpsub = dict( (k, simparameters[k]) for k in ('gamma', 'raman', 'linop', 'W', 'dz', 'dt', 'RW', 'fr')) # the line below creates a new function handle as some of the scipy integrator functions # seem not to wrap additional parameters (simpsub in this case) of the RHS function # correctly (as SCIPY 0.14.0.dev-a3e9c7f) GNLSE_RHS2 = funcpartial(GNLSE_RHS, simp=simpsub) integrator = complex_ode(GNLSE_RHS2) # available types dop853 dopri5 lsoda vode # zvode also available, but do not use, as complex ode handling already wrapped above integrator.set_integrator(simparameters['integratortype'], atol=simparameters['abstol'], rtol=simparameters['reltol'], nsteps=simparameters['nsteps']) integrator.set_initial_value(np.fft.ifft(inifield)) return integrator
def k_int(mani,k_radii,k_powers,p,m,e): # time interval tspan = [0,2*np.pi] # initial condition ynot = np.array([0,0]) out = np.zeros((len(k_powers)),dtype=np.complex) for j in range(len(k_powers)): # 1:length(k_powers) pre_k_ode = lambda t,y: k_ode(t,y,mani,k_radii[j],k_powers[j],p,e) # solve ode integrator = complex_ode(pre_k_ode).set_integrator('dopri5', atol=m['k_int_options']['AbsTol'], rtol=m['k_int_options']['RelTol']) integrator.set_initial_value(ynot,tspan[0]) integrator.integrate(tspan[-1]) Y = integrator.y Y = np.array([Y.T]).T # gather output out[j] = Y[0,-1]+Y[1,-1]*1j return out
def manifold_polar(x,y,lamda,A,s,p,m,k,mu): """ Returns "Omega", the orthogonal basis for the manifold evaluated at x[-1] and "gamma" the radial equation evaluated at x[-1]. Input "x" is the interval on which the manifold is solved, "y" is the initializing vector, "lambda" is the point in the complex plane where the Evans function is evaluated, "A" is a function handle to the Evans matrix, s, p,and m are structures explained in the STABLAB documentation, and k is the dimension of the manifold sought. """ def ode_f(x,y): return m['method'](x,y,lamda,A,s,p,m['n'],k,mu,m['damping']) t0 = x[0] y0 = y.reshape(m['n']*k,1,order='F') y0 = np.concatenate((y0,np.array([[0.0]],dtype=np.complex)),axis=0) y0 = y0.T[0] #initiate integrator object if 'options' in m: try: integrator = complex_ode(ode_f).set_integrator('dopri5', atol=m['options']['AbsTol'], rtol=m['options']['RelTol'], nsteps=m['options']['nsteps']) except KeyError: integrator = complex_ode(ode_f).set_integrator('dopri5',atol=1e-6, rtol=1e-5, nsteps=10000) else: integrator = complex_ode(ode_f).set_integrator('dopri5',atol=1e-6, rtol=1e-5, nsteps=10000) integrator.set_initial_value(y0,t0) # set initial time and initial value integrator.integrate(x[-1]) Y = integrator.y Y = np.array([Y.T]).T omega = Y[0:k*m['n'],-1].reshape(m['n'],k,order = 'F') gamma = np.exp(Y[m['n']*k,-1]) return omega, gamma
def manifold_compound(x, z, lamda, s, p, m, A, k, pmMU): """ manifold_compound(x,z,lambda,s,p,m,A,k,pmMU) Returns the vector representing the manifold evaluated at x(2). Input "x" is the interval the manifold is computed on, "z" is the initializing vector for the ode solver, "lambda" is the point on the complex plane where the Evans function is computed, s,p,m are structures explained in the STABLAB documentation, "A" is the function handle to the desired Evans matrix, "k" is the dimension of the manifold sought, and "pmMU" is 1 or -1 depending on if respectively the growth or decay manifold is sought. """ eigenVals,eigenVects = np.linalg.eig(A(x[0],lamda,s,p)) ind = np.argmax(np.real(pmMU*eigenVals)) MU = eigenVals[ind] # Solve the ODE def ode_f(x,y): return capa(x,y,lamda,s,p,A,m['n'],k,MU) if 'options' in m: try: integrator = complex_ode(ode_f).set_integrator('dopri5', atol=m['options']['AbsTol'], rtol=m['options']['RelTol'], nsteps=m['options']['nsteps']) except KeyError: integrator = complex_ode(ode_f).set_integrator('dopri5',atol=1e-6, rtol=1e-5, nsteps=10000) else: integrator = complex_ode(ode_f).set_integrator('dopri5',atol=1e-6, rtol=1e-5, nsteps=10000) x0 = x[0] z0 = z.T[0] integrator.set_initial_value(z0,x0) integrator.integrate(x[-1]) Z = integrator.y out = Z return out
def _testcase_one_mode(h_sys, rho0, g, w, L, timesteps): """Integration of the single environment-mode case for debugging. The exact reduced dynamics is described by the reduced density operator p00 as well as three auxiliary states (p01, p10, p11). Their equations of motion read :param h_sys: @todo :param rho0: @todo :param g: @todo :param w: @todo :param L: @todo :param timesteps: @todo :returns: @todo """ from numpy import dot from scipy.integrate import complex_ode dim = h_sys.shape[0] adj = lambda A: np.conj(np.transpose(A)) prop = sp.lil_matrix((dim**2 * 4, dim**2 * 4), dtype=complex) i = [[(slice(m*dim**2, (m+1)*dim**2), slice(n*dim**2, (n+1)*dim**2)) for n in range(4)] for m in range(4)] prop[i[0][0]] += -1.j * commutator(h_sys) prop[i[0][2]] += -multiply_raveled(adj(L), 'l') + multiply_raveled(adj(L), 'r') prop[i[0][1]] += multiply_raveled(L, 'l') - multiply_raveled(L, 'r') prop[i[1][1]] += -1.j * commutator(h_sys) - np.conj(w) * np.identity(dim**2) prop[i[1][0]] += np.conj(g) * multiply_raveled(adj(L), 'r') prop[i[1][3]] += -multiply_raveled(adj(L), 'l') - multiply_raveled(adj(L), 'r') prop[i[2][2]] += -1.j * commutator(h_sys) - w * np.identity(dim**2) prop[i[2][0]] += g * multiply_raveled(L, 'l') prop[i[2][3]] += -multiply_raveled(L, 'l') - multiply_raveled(L, 'r') prop[i[3][3]] += -1.j * commutator(h_sys) - (w + np.conj(w)) * np.identity(dim**2) prop[i[3][1]] += g * multiply_raveled(L, 'l') prop[i[3][2]] += np.conj(g) * multiply_raveled(adj(L), 'r') print('CORRECT') print(prop) y0 = np.zeros((4, dim, dim), dtype=complex) y0[0] = rho0 rho = np.empty((len(timesteps), dim, dim), dtype=complex) rho[0] = rho0 r = complex_ode(lambda t, y: prop.dot(y))\ .set_integrator('vode', atol=1e-10, rtol=1e-10, nsteps=100) \ .set_initial_value(y0.ravel()) for i, t in enumerate(timesteps[1:]): r.integrate(t) rho[i + 1] = r.y.reshape((4, dim, dim))[0] return timesteps, rho
def test_evolve(): def ifunc(t, y): return -1j * np.cos(t) * M.dot(y) def func(t, y): return -np.cos(t) * M.dot(y) M = np.random.uniform( -1, 1, size=(4, 4)) + 1j * np.random.uniform(-1, 1, size=(4, 4)) M = (M.T.conj() + M) / 2.0 M = np.asarray(M) H = hamiltonian([], [[M, np.cos, ()]]) psi0 = np.random.uniform( -1, 1, size=(4, )) + 1j * np.random.uniform(-1, 1, size=(4, )) psi0 /= np.linalg.norm(psi0) isolver = complex_ode(ifunc) isolver.set_integrator("dop853", atol=1e-9, rtol=1e-9, nsteps=np.iinfo(np.int32).max) isolver.set_initial_value(psi0, 0) solver = complex_ode(func) solver.set_integrator("dop853", atol=1e-9, rtol=1e-9, nsteps=np.iinfo(np.int32).max) solver.set_initial_value(psi0, 0) times = np.arange(0, 100.1, 10) ipsi_t = H.evolve(psi0, 0, times, iterate=True) psi_t = H.evolve(psi0, 0, times, iterate=True, imag_time=True) for i, (ipsi, psi) in enumerate(zip(ipsi_t, psi_t)): solver.integrate(times[i]) solver._y /= np.linalg.norm(solver.y) np.testing.assert_allclose(psi - solver.y, 0, atol=1e-10) isolver.integrate(times[i]) np.testing.assert_allclose(ipsi - isolver.y, 0, atol=1e-10)
def solve_ODE(self, H=None): """Iteratively solve the ODE dy/dt = f(t,y) on a discretized time-grid. Returns: -------- t: (N,) ndarray Time array. phi_a: (N,2) ndarray Overlap <phi_a|psi>. phi_b: (N,2) ndarray Overlap <phi_b|psi>. """ if H is None: H = self.H # set initial conditions self.get_c_eigensystem() # calculate eigensystem for all times if self.init_state_method == 'gain': self._find_gain_state() elif self.init_state_method == 'energy': self._find_lower_energy_state() self.eVec0 = self._get_init_state() # create ode object to solve Schroedinger equation (SE) ode_kwargs = {'rtol': 1e-9, 'atol': 1e-9} SE = complex_ode(lambda t, phi: -1j*H(t).dot(phi)) SE.set_integrator('dopri5', **ode_kwargs) SE.set_initial_value(self.eVec0, t=0.0) # iterate SE for n, tn in enumerate(self.t): if SE.successful(): self.Psi[n,:] = SE.y SE.integrate(SE.t + self.dt) else: raise Exception("ODE convergence error!") if self.calc_adiabatic_state: self._get_adiabatic_state() # replace projection of states by dot product via Einstein sum projection = np.einsum('ijk,ij -> ik', self.eVecs_l, self.Psi) # use alternative means to obtain coefficients: # (c1, c2) = X^-1^T psi # from scipy.linalg import inv # projection = [np.einsum('jk,j -> k', inv(self.eVecs_r[n,:]).T, self.Psi[n,:]) # for n, _ in enumerate(self.t)] # projection = np.asarray(projection) self.phi_a, self.phi_b = [projection[:,n] for n in (0,1)] return self.t, self.phi_a, self.phi_b
def _start_integrator(self, ham, small_step): """ Initialize a stepping integrator. """ self.sparse_ham = issparse(ham) evo_eq = calc_evo_eq(self.isdop, self.sparse_ham) self.stepper = complex_ode(evo_eq(ham)) int_mthd, step_fct = ('dopri5', 150) if small_step else ('dop853', 50) first_step = norm(ham, 'f') / step_fct self.stepper.set_integrator(int_mthd, nsteps=0, first_step=first_step) self.stepper.set_initial_value(self.p0.A.reshape(-1), self.t0) self.update_to = self._update_to_integrate self.solved = False
def adiabatic(n, T, M, H_driver, H_problem, ground_state_prob, normalise=True, sprs=True): N = 2**n psi0 = np.ones(N) * (1 / np.sqrt(N)) newschro = lambda t, y: schrodinger(t, y, T, H_driver, H_problem) r = complex_ode(newschro) r.set_integrator("dop853") r.set_initial_value(psi0, 0) # r.set_f_params(T, H_driver, H_problem) # print(r.f_params) psiN = r.integrate(T) return np.abs(np.dot(np.conjugate(ground_state_prob), psiN)) ** 2
def sol(kx, ky): def ham_k(t): return ham(kx, ky, t) def f(y_vec, t): y_1, y_2 = y_vec fun = -1j * np.dot( ham_k(t), np.array([ [y_1],[y_2] ]) ) return [fun[0,0], fun[1,0]] y_result = complex_ode(f, y0, t_output) return np.array([y_result.real, y_result.imag])
def _integrator(self, f, **kwargs): from scipy.integrate import complex_ode defaults = { 'nsteps': 1e9, 'with_jacobian': False, 'method': 'bdf', } defaults.update(kwargs) r = complex_ode(f).set_integrator('vode', atol=self.error_abs, rtol=self.error_rel, **defaults) return r
def Propagate_SAM(self, L, betta2=-1, gamma=1, Tr=0, n=50, abtol=1e-10, reltol=1e-9, param='fin_res'): """Propagate Using the Step Adaptative Method""" def deriv_2(dt, field_in): # computes the second-order derivative of field_in field_fft = np.fft.fft(field_in) freq = 1./dt*np.fft.fftfreq(len(field_in)) # print freq omega = 2.*np.pi*freq # field_fft*=np.exp(1j*0.5*beta2z*omega**2) field_fft *= -omega**2 out_field = np.fft.ifft(field_fft) return out_field def deriv_1(dt, field_in): # computes the second-order derivative of field_in field_fft = np.fft.fft(field_in) freq = 1./dt*np.fft.fftfreq(len(field_in)) # print freq omega = 2.*np.pi*freq # field_fft*=np.exp(1j*0.5*beta2z*omega**2) field_fft *= 1j*omega out_field = np.fft.ifft(field_fft) return out_field if Tr==0: def NLS_1d(Z, A): # time second order derivative dAdT2 = deriv_2(self.TimeStep, A) # dAAdT = deriv_1(self.TimeStep,abs(A)**2) dAdz = -1j*betta2/2*dAdT2+1j*gamma*abs(A)**2*A#-1j*gamma*Tr*dAAdT return dAdz else: def NLS_1d(Z, A): # time second order derivative dAdT2 = deriv_2(self.TimeStep, A) dAAdT = deriv_1(self.TimeStep,abs(A)**2) dAdz = -1j*betta2/2*dAdT2+1j*gamma*abs(A)**2*A-1j*gamma*Tr*dAAdT*A return dAdz dz =float(L)/n # r = complex_ode(NLS_1d).set_integrator('zvode', method='bdf', with_jacobian=False, atol=abtol, rtol=reltol) r = complex_ode(NLS_1d).set_integrator('dopri5', atol=abtol, rtol=reltol) # r = complex_ode(NLS_1d).set_integrator('lsoda', method='BDF', atol=abtol, rtol=reltol, with_jacobian=False) r.set_initial_value(self.Sig, 0) sol=np.ndarray(shape=(n+1, len(self.Sig)), dtype=complex) sol[0] = self.Sig for it in range(1, n+1): sol[it] = r.integrate(r.t+dz) if param == 'map': return sol elif param == 'fin_res': return sol[-2, :] else: print ('wrong parameter')
def central_amplitude(time, L, M=101, aperiodicity=0): integrator = complex_ode(dnls_rhs(M, L, aperiodicity)) central_site_index = (M - 1)/2 ic = np.zeros(shape=(M,)) ic[central_site_index] = 1 integrator.set_initial_value(ic) y = integrator.integrate(time) return np.abs(y[central_site_index])
def f(df, u, h, theta): dt = h / 1e1 df_args = functools.partial(df, theta = theta) r = si.complex_ode(df_args) sol = [] for v in u: x0 = [0., v * 1j] r.set_initial_value(x0, 0) while r.successful() and r.t < h: r.integrate(r.t + dt) sol.append(r.y) return np.array(sol).T
def compare_performance(func, y0, t0, tf, y_ref, problem_name, tol_boundary=(0,6), is_complex=False, nsteps=10e5, solout=(lambda t: t)): print 'RUNNING COMPARISON TEST FOR ' + problem_name tol = [1.e-3,1.e-5,1.e-7,1.e-9,1.e-11,1.e-13] a, b = tol_boundary tol = tol[a:b] extrap = {} dopri5 = {} dop853 = {} for method in [extrap, dopri5, dop853]: for diagnostic in ['runtime','fe_seq','fe_tot','yerr','nstp']: method[diagnostic] = np.zeros(len(tol)) def func2(t,y): return func(y,t) for i in range(len(tol)): print 'Tolerance: ', tol[i] for method, name in [(extrap,'ParEx'), (dopri5,'DOPRI5'), (dop853,'DOP853')]: print 'running ' + name start_time = time.time() if name == 'ParEx': y, infodict = parex.solve(func, [t0, tf], y0, solver=parex.Solvers.EXPLICIT_MIDPOINT, atol=tol[i], rtol=tol[i], max_steps=nsteps, adaptive=True, diagnostics=True) y[-1] = solout(y[-1]) method['yerr'][i] = relative_error(y[-1], y_ref) else: # scipy solvers DOPRI5 and DOP853 if is_complex: r = complex_ode(func2, jac=None).set_integrator(name.lower(), atol=tol[i], rtol=tol[i], verbosity=10, nsteps=nsteps) else: r = ode(func2, jac=None).set_integrator(name.lower(), atol=tol[i], rtol=tol[i], verbosity=10, nsteps=nsteps) r.set_initial_value(y0, t0) r.integrate(r.t+(tf-t0)) assert r.t == tf, "Integration did not converge. Try increasing the max number of steps" y = solout(r.y) method['yerr'][i] = relative_error(y, y_ref) method['runtime'][i] = time.time() - start_time method['fe_seq'][i], method['fe_tot'][i], method['nstp'][i] = infodict['fe_seq'], infodict['nfe'], infodict['nst'] print 'Runtime: ', method['runtime'][i], ' s Error: ', method['yerr'][i], ' fe_seq: ', method['fe_seq'][i], ' fe_tot: ', method['fe_tot'][i], ' nstp: ', method['nstp'][i] print '' print '' for method, name in [(extrap,'ParEx'), (dopri5,'DOPRI5'), (dop853,'DOP853')]: print "Final data: " + name print method['runtime'], method['fe_seq'], method['fe_tot'], method['yerr'], method['nstp'] print '' print '' return (extrap, dopri5, dop853)
def _setup_integrator(self, t0, name, **params): if (self.is_ensemble): func = vonNeumann else: func = schroedinger if (name == 'zvode'): I = ode(_wrap(func, self.H)) else: I = complex_ode(_wrap(func, self.H)) I.set_integrator(name, **params) I.set_initial_value(self.state.as_vector(), t0) return I
def _integrator(self, f, **kwargs): from scipy.integrate import complex_ode defaults = { 'nsteps': 1e9, 'with_jacobian': False, 'method': 'bdf', } defaults.update(kwargs) r = complex_ode(f).set_integrator('vode', atol=self.error_abs, rtol=self.error_rel, **defaults) return r
def integrate(self, end_z, dz): steps = int(end_z / dz) self.z = np.arange(0, stop=end_z, step=dz) self._allocate_storage(steps) f = complex_ode(self.qpm_coupled_system) f.set_initial_value(self.A) i = 0 while f.successful() and f.t <= end_z: self.solution[i] = f.integrate(f.t + dz) i += 1 self.A_1_solution = np.transpose(self.solution)[0] self.A_2_solution = np.transpose(self.solution)[1] return [self.A_1_solution, self.A_2_solution, self.z]
def plot_this(ynot,tspan,ode,rp): sol = stablab.Struct() sol.t = [] sol.y = [] def updateSol(tVal,yVals): sol.t.append(tVal) sol.y.append(yVals) return None integrator = complex_ode(ode) integrator.set_integrator('dopri5',atol=1e-10,rtol=1e-10) integrator.set_solout(updateSol) integrator.set_initial_value(ynot,tspan[0]) integrator.integrate(tspan[-1]) sol.t, sol.y = np.array(sol.t), np.array(sol.y) return sol
def _do_problem(self, problem, integrator, method='adams'): # ode has callback arguments in different order than odeint f = lambda t, z: problem.f(z, t) jac = None if hasattr(problem, 'jac'): jac = lambda t, z: problem.jac(z, t) ig = complex_ode(f, jac) ig.set_integrator(integrator, atol=problem.atol/10, rtol=problem.rtol/10, method=method) ig.set_initial_value(problem.z0, t=0.0) z = ig.integrate(problem.stop_t) assert_(ig.successful(), (problem, method)) assert_(problem.verify(array([z]), problem.stop_t), (problem, method))
def solve_equations(self): time_stamps = np.concatenate((np.linspace(0, time_limit / 100, num=10**3), np.linspace(time_limit / 100, time_limit, num=10**3))) self.initial_conditions() ode = complex_ode(self.ode_sys()).set_integrator('dopri5', method='bdf') ode.set_initial_value(self.ode_init) for t in tqdm(time_stamps[1:]): dt = t - ode.t solution = ode.integrate(ode.t + dt) self.decompose_ode_sol(sol=solution) self.append_quantities(t)
def _do_problem(self, problem, integrator, method='adams'): # ode has callback arguments in different order than odeint f = lambda t, z: problem.f(z, t) jac = None if hasattr(problem, 'jac'): jac = lambda t, z: problem.jac(z, t) ig = complex_ode(f, jac) ig.set_integrator(integrator, atol=problem.atol / 10, rtol=problem.rtol / 10, method=method) ig.set_initial_value(problem.z0, t=0.0) z = ig.integrate(problem.stop_t) assert_(ig.successful(), (problem, method)) assert_(problem.verify(array([z]), problem.stop_t), (problem, method))
def __init__(self,myhamgen,param): self.hamgen = myhamgen self.param=param #Set up the solver self.norm=0 #self.r=ode(self.func).set_integrator('zvode', method='bdf',rtol=1e-6) #self.r=complex_ode(self.func).set_integrator('dopri5',rtol=1e-6) self.r=complex_ode(self.func).set_integrator('dopri5',rtol=1e-6,nsteps=100000) #Generate basis vectors self.b=[] for x in range(0,param.numneu): self.b.append(np.zeros(param.numneu)) self.b[x][x]=1.0 self.splines=Splines.Spline()
def adiabatic(n, T, H_driver, H_problem, ground_state_prob, normalise=True, sprs=True, n_steps=16384): # print(T) N = 2**n psi0 = np.ones(N) * (1 / np.sqrt(N)) newschro = lambda t, y: schrodinger(t, y, T, H_driver, H_problem) r = complex_ode(newschro) r.set_integrator("dop853", nsteps=n_steps) r.set_initial_value(psi0, 0) # r.set_f_params(T, H_driver, H_problem) psiN = r.integrate(T) # print(np.abs(np.conjugate(ground_state_prob).dot(psiN)) ** 2) return np.abs(np.conjugate(ground_state_prob).dot(psiN))**2, r.successful()
def psi_old(t,M=10,steps=1, L=0, aperiodicity=0,kind=0): """ Parameters ---------- time : float End time of the integration. L : float Nonlinearity parameter. M : int Number of lattice sites. (Default 101.) aperiodicity : float Aperiodicity parameter, defined in terms of the hoppings as (b/a - 1). (Default 0, which corresponds to a periodic chain.) kind: 0(periodic),fib,tm,rs Returns ------- y : float wavefn at time t """ r = integrate.complex_ode(dnls_rhs(M, L, aperiodicity,kind)) central_site_index = (M - 1)/2 ic = np.zeros(shape=(M,)) ic[central_site_index] = 1.0 r.set_initial_value(ic) dt = float(t)/steps wavefn = np.zeros((steps,M), dtype=np.complex) t_arr=np.zeros((steps), dtype=np.float) for idx in xrange(steps): if r.successful(): #essentially, **if True:** if abs(r.y[0])< 1e-10 and abs(r.y[-1])<1e-10: #to make sure the lattice is big enough so that wavefn doesn't touch the boundary. wavefn[idx,:] = r.y[:] t_arr[idx]=r.t #print "y" else: print ("wfn touching the boundary at t = {} for p={}".format(r.t,aperiodicity)) wave_fn_truncated=wavefn[0:idx,:] t_arr_truncated=t_arr[0:idx] return wave_fn_truncated, t_arr_truncated else: raise ValueError("Integration failed at t = {}".format(r.t)) r.integrate(r.t + dt)#note that if dt is too big, then you will get an error. So, steps should at least be same as return wavefn,t_arr #time units
def manifold_polar(x, y, lmbda, A, s, p, m, k, mu): def ode_f(x, y): return m['method'](x, y, lmbda, A, s, p, m['n'], k, mu, m['damping']) t0 = x[0] y0 = y.reshape(m['n'] * k, 1, order='F') y0 = np.concatenate((y0, np.array([[1.0]])), axis=0) y0 = y0.T[0] #initiate integrator object test = complex_ode(ode_f).set_integrator('dopri5', atol=1e-5) test.set_initial_value(y0, t0) # set initial time and initial value test.integrate(0) Y = test.y Y = np.array([Y.T]).T omega = Y[0:k * m['n'], 0].reshape(m['n'], k, order='F') gamma = Y[-1, 0] gamma = np.exp(gamma) return omega, gamma
def solve(x, t, A0, fvec, callbackFunc): """ solve implements numerical integration scheme for complex field based on the explicit higher-order Runge-Kutta method "DOP853" (hard-coded). Args: x (numpy-array): discrete x-domain t (numpy-array): discrete t-domain A0 (numpy-array): initial condition fvec (object): right-hand-side of first order propagation equation callbaclFunc (object): callback function facilitating the measurement at distinct values of t. It takes 4 paramters in the form callbackFunc(n, tCurr, x, Ax), where: n (int): current propagation step t_curr (float): current time coordinate x (numpy-array): discrete x-domain Ax (numpy-array): field configuration at t_curr Returns: (t_fin,A_fin) t_fin (float): final time coordinate A_fin (numpy-array): final field configuration """ dt = t[1]-t[0] it = 0 solver = complex_ode(lambda t, A: fvec(A)) solver.set_integrator('dop853') solver.set_initial_value(A0, t.min()) while solver.successful() and solver.t < t.max(): solver.integrate(solver.t+dt,step=1) callbackFunc(it, solver.t, x, solver.y) it += 1 return solver.t, solver.y
def prepare_integrator(simparameters, inifield): """ prepare an integration scipy can understand """ # only pass the necessary subset of the simparameters dict to GNLSE ... simpsub = dict( (k, simparameters[k]) for k in ('gamma','raman','linop','W','dz','dt','RW','fr')) # the line below creates a new function handle as some of the scipy integrator functions # seem not to wrap additional parameters (simpsub in this case) of the RHS function # correctly (as SCIPY 0.14.0.dev-a3e9c7f) GNLSE_RHS2 = funcpartial( GNLSE_RHS, simp=simpsub) integrator = complex_ode(GNLSE_RHS2) # available types dop853 dopri5 lsoda vode # zvode also available, but do not use, as complex ode handling already wrapped above integrator.set_integrator(simparameters['integratortype'], atol=simparameters['abstol'], rtol=simparameters['reltol'], nsteps=simparameters['nsteps']) integrator.set_initial_value(np.fft.ifft( inifield)) return integrator
def DGLloesen(A_0, w, v0, t0, t1, N): # Startwerte: x = np.zeros((36,N))*1j # für RK5 y0 = np.array(v0) x[:,0] = y0 # Imaginärteil ist 0 # x ist complexes 36xN array #Integration mit Runge-Kutta 5: t = np.linspace(t0,t1,N) r = complex_ode(f).set_integrator('dopri5') r.set_initial_value(y0, t0) i = 1 print('Runge-Kutta(5) für',N-1,'Werte:') with tqdm(total=N-1) as pbar: while r.successful() and r.t < t[N-1]: r.integrate(t[i]) pbar.update(1) x[:,i] = r.y i += 1 return x
def _start_integrator(self, ham, small_step): """Initialize a stepping integrator. """ if self._timedep: H0 = ham(0.0) else: H0 = ham # set complex ode with governing equation evo_eq = _calc_evo_eq(self._isdop, issparse(H0), False, self._timedep) self._stepper = complex_ode(evo_eq(ham)) # 5th order stpper or 8th order stepper int_mthd, step_fct = ('dopri5', 150) if small_step else ('dop853', 50) if isinstance(H0, LinearOperator): # approx norm doesn't need to be very accurate nrm0 = norm_fro_approx(H0, tol=0.1) else: nrm0 = norm(H0, 'f') first_step = nrm0 / step_fct self._stepper.set_integrator(int_mthd, nsteps=0, first_step=first_step) # Set step_callback to be evaluated with args (t, y) at each step if self._int_step_callback is not None: def solout(t, y): self._int_step_callback(t, y, self._ham) self._stepper.set_solout(solout) self._stepper.set_initial_value(self._p0.A.reshape(-1), self.t0) # assign the correct update_to method self._update_method = self._update_to_integrate
def _start_integrator(self, ham, small_step): """Initialize a stepping integrator. """ self._sparse_ham = issparse(ham) # set complex ode with governing equation evo_eq = _calc_evo_eq(self._isdop, self._sparse_ham) self._stepper = complex_ode(evo_eq(ham)) # 5th order stpper or 8th order stepper int_mthd, step_fct = ('dopri5', 150) if small_step else ('dop853', 50) first_step = norm(ham, 'f') / step_fct self._stepper.set_integrator(int_mthd, nsteps=0, first_step=first_step) # Set step_callback to be evaluated with args (t, y) at each step if self._int_step_callback is not None: self._stepper.set_solout(self._int_step_callback) self._stepper.set_initial_value(self._p0.A.reshape(-1), self.t0) # assign the correct update_to method self._update_method = self._update_to_integrate self._solved = False
def power_expansion2(R_lambda,k_radii,lambda_powers,k_powers,s,p,m,c,e): """ # function out = power_expansion2(R_lambda,k_radii,lambda_powers,k_powers,s,p,m,c,e) # # Returns the double contour integral of $D(lambda,kappa)/(lambda^r # kappa^s)$ evaluated on a contour in lambda of radius R_lambda and in # kappa of radius k_radii(j) for the jth power in kappa, s = k_powers(j). # # # Example: St. Venant's equation # # [s,e,m,c] = emcset(s,'periodic',[2,1],'balanced_polar_periodic','Aper'); # # m.k_int_options = odeset('AbsTol',10^(-10), 'RelTol',10^(-8)); # m.lambda_int_options = odeset('AbsTol',10^(-8), 'RelTol',10^(-6)); # # st.k_int_options = m.k_int_options; # st.lambda_int_options = m.lambda_int_options; # # R_lambda = 0.01; # k_radii = 9*[0.001, 0.001, 0.001 0.001]; # k_powers = [0 1 2 3 ]; # lambda_powers = [0 1 2 3]; # # st.R_lambda = R_lambda; # st.k_radii = k_radii; # # s_time = tic; # out = power_expansion2(R_lambda,k_radii,lambda_powers,k_powers,s,p,m,c,e); # st.time = toc(s_time); # # coef = out.'; # # aa=coef(3,1); # bb=coef(2,2); # cc=coef(1,3); # dd=coef(4,1); # ee=coef(3,2); # ff = coef(2,3); # gg = coef(1,4); # # alpha1=(-bb+sqrt(bb^2-4*aa*cc))/(2*aa); # alpha2=(-bb-sqrt(bb^2-4*aa*cc))/(2*aa); # beta1=-(dd*alpha1^3+alpha1^2*ee+alpha1*ff+gg)/(2*aa*alpha1+bb); # beta2=-(dd*alpha2^3+alpha2^2*ee+alpha2*ff+gg)/(2*aa*alpha2+bb); """ # input error checking if len(k_radii) != len(k_powers): raise ValueError("Input k_radii must have the same number of entries as k_powers") # HELPER FUNCTIONS: #-------------------------------------------------------------------------- # lambda_ode #-------------------------------------------------------------------------- def lambda_ode(t,y,k_radii,k_powers,lambda_powers,R_lambda,p,s,e,m,c): lamda = R_lambda*np.exp(1j*t) # get manifolds from Evans solver e.evans = 'bpspm' mani = c.evans(1,0,lamda,s,p,m,e) # $\int_{|z| = R_k}D(lamda,k)/k^{r+1} dk$, r = k_powers temp = k_int(mani,k_radii,k_powers,p,m,e) len_lambda_powers = len(lambda_powers) totlen = len_lambda_powers*len(k_powers) mat = np.zeros((len(k_powers),len_lambda_powers),dtype=np.complex) for j in range(len_lambda_powers): # 1:len mat[:,j] = (1j*temp*lamda**(-lambda_powers[j]))/(2*np.pi*1j) pre_out = np.reshape(mat,(totlen)) out = np.zeros((2*totlen),dtype=np.complex) out[:totlen] = np.real(pre_out) out[totlen:2*totlen] = np.imag(pre_out) return out #-------------------------------------------------------------------------- # k_int #-------------------------------------------------------------------------- def k_int(mani,k_radii,k_powers,p,m,e): # time interval tspan = [0,2*np.pi] # initial condition ynot = np.array([0,0]) out = np.zeros((len(k_powers)),dtype=np.complex) for j in range(len(k_powers)): # 1:length(k_powers) pre_k_ode = lambda t,y: k_ode(t,y,mani,k_radii[j],k_powers[j],p,e) # solve ode integrator = complex_ode(pre_k_ode).set_integrator('dopri5', atol=m['k_int_options']['AbsTol'], rtol=m['k_int_options']['RelTol']) integrator.set_initial_value(ynot,tspan[0]) integrator.integrate(tspan[-1]) Y = integrator.y Y = np.array([Y.T]).T # gather output out[j] = Y[0,-1]+Y[1,-1]*1j return out #-------------------------------------------------------------------------- # k_ode #-------------------------------------------------------------------------- def k_ode(t,y,mani,R_k,kpow,p,e): # Floquet parameter kappa = R_k*np.exp(1j*t) # Evans function D = np.linalg.det(np.vstack([ np.hstack([mani.sigh[:e.kl,:e.kl], np.exp(1j*kappa*p.X)*mani.phi[:e.kl,:e.kr]]), np.hstack([mani.sigh[e.kl:2*e.kl,:e.kl], mani.phi[e.kl:2*e.kl,:e.kl]]) ])) # integrand temp = (1j*D*np.exp(-1j*kpow*t)/R_k**kpow)/(2*np.pi*1j) out = np.zeros((2)) # split into real and imaginary parts out[0] = np.real(temp) out[1] = np.imag(temp) return out # Begin power_expansion2 len_lambda_powers = len(lambda_powers) totlen = len_lambda_powers*len(k_powers) # time interval tspan = [0,2*np.pi] # initial condition ynot = np.zeros((2*totlen),dtype=np.complex) pre_lambda_ode = lambda t,y: lambda_ode(t,y,k_radii,k_powers,lambda_powers, R_lambda,p,s,e,m,c) integrator = complex_ode(pre_lambda_ode).set_integrator('dopri5', atol=m['lambda_int_options']['AbsTol'], rtol=m['lambda_int_options']['RelTol']) integrator.set_initial_value(ynot,tspan[0]) integrator.integrate(tspan[-1]) Y = integrator.y Y = np.array([Y.T]).T out = np.reshape(Y[:totlen,-1]+1j*Y[totlen:2*totlen,-1],(len(k_powers), len_lambda_powers)) return out
for problem in problems: results[problem.name] = {} reference_file = "./reference_data/" + problem.name + ".txt" y_ref = np.loadtxt(reference_file) for solver in solvers: results[problem.name][solver] = {} for tol in tols: print(problem.name, solver, tol) results[problem.name][solver][tol] = {} start = time.time() if 'scipy' in solver: solver_name = solver.split()[-1].lower() if problem in [kdv, burgers]: r = integrate.complex_ode(problem.rhs_reversed).set_integrator(solver_name, atol=tol, rtol=tol, verbosity=10, nsteps=1e6) else: r = integrate.ode(problem.rhs_reversed).set_integrator(solver_name, atol=tol, rtol=tol, verbosity=10, nsteps=1e7) t0 = problem.output_times[0] tf = problem.output_times[-1] r.set_initial_value(problem.y0, t0) r.integrate(r.t+(tf-t0)) assert r.t == tf, "Integration failed. Try increasing the maximum allowed steps." y = r.y results[problem.name][solver][tol]['fe_seq'] = None results[problem.name][solver][tol]['mean_order'] = None else:
def Propagate_SAM(self, simulation_parameters, Pump, Seed=[0], Normalized_Units=False): start_time = time.time() T = simulation_parameters['slow_time'] abtol = simulation_parameters['absolute_tolerance'] reltol = simulation_parameters['relative_tolerance'] out_param = simulation_parameters['output'] nmax = simulation_parameters['max_internal_steps'] detuning = simulation_parameters['detuning_array'] eps = simulation_parameters['noise_level'] J = simulation_parameters['electro-optical coupling'] if Normalized_Units == False: pump = Pump * np.sqrt(1. / (hbar * self.w0)) if Seed[0] == 0: seed = self.seed_level(Pump, detuning[0]) * np.sqrt( 2 * self.g0 / self.kappa) else: seed = Seed * np.sqrt(2 * self.g0 / self.kappa) ### renormalization T_rn = (self.kappa / 2) * T f0 = pump * np.sqrt(8 * self.g0 * self.kappa_ex / self.kappa**3) J *= 2 / self.kappa print('f0^2 = ' + str(np.round(max(abs(f0)**2), 2))) print('xi [' + str(detuning[0] * 2 / self.kappa) + ',' + str(detuning[-1] * 2 / self.kappa) + ']') else: pump = Pump if Seed[0] == 0: seed = self.seed_level(Pump, detuning[0], Normalized_Units) else: seed = Seed T_rn = T f0 = pump print('f0^2 = ' + str(np.round(max(abs(f0)**2), 2))) print('xi [' + str(detuning[0]) + ',' + str(detuning[-1]) + ']') detuning *= self.kappa / 2 noise_const = self.noise(eps) # set the noise level nn = len(detuning) ### define the rhs function def LLE_1d(Time, A): A = A - noise_const #self.noise(eps) A_dir = np.fft.ifft(A) * len(A) ## in the direct space dAdT = -1 * ( 1 + 1j * (self.Dint + dOm_curr) * 2 / self.kappa) * A + 1j * np.fft.fft( A_dir * np.abs(A_dir)**2) / len(A) + 1j * np.fft.fft( J * 2 / self.kappa * np.cos(self.phi) * A_dir / self.N_points) + f0 #*len(A) return dAdT t_st = float(T_rn) / len(detuning) r = complex_ode(LLE_1d).set_integrator('dop853', atol=abtol, rtol=reltol, nsteps=nmax) # set the solver #r = ode(LLE_1d).set_integrator('zvode', atol=abtol, rtol=reltol,nsteps=nmax)# set the solver r.set_initial_value(seed, 0) # seed the cavity sol = np.ndarray(shape=(len(detuning), self.N_points), dtype='complex') # define an array to store the data sol[0, :] = seed #printProgressBar(0, nn, prefix = 'Progress:', suffix = 'Complete', length = 50, fill='elapsed time = ' + str((time.time() - start_time)) + ' s') for it in range(1, len(detuning)): self.printProgressBar(it + 1, nn, prefix='Progress:', suffix='Complete,', time='elapsed time = ' + '{:04.1f}'.format(time.time() - start_time) + ' s', length=50) #self.print('elapsed time = ', (time.time() - start_time)) dOm_curr = detuning[it] # detuning value sol[it] = r.integrate(r.t + t_st) if out_param == 'map': if Normalized_Units == False: return sol / np.sqrt(2 * self.g0 / self.kappa) else: detuning /= self.kappa / 2 return sol elif out_param == 'fin_res': return sol[-1, :] / np.sqrt(2 * self.g0 / self.kappa) else: print('wrong parameter')
def NeverStopSAM(self, T_step, detuning_0=-1, Pump_P=2., nmax=1000, abtol=1e-10, reltol=1e-9, out_param='fin_res'): self.Pump = self.Pump / abs(self.Pump) def deriv_1(dt, field_in): # computes the first-order derivative of field_in field_fft = np.fft.fft(field_in) omega = 2. * np.pi * np.fft.fftfreq(len(field_in), dt) out_field = np.fft.ifft(-1j * omega * field_fft) return out_field def deriv_2(dt, field_in): # computes the second-order derivative of field_in field_fft = np.fft.fft(field_in) omega = 2. * np.pi * np.fft.fftfreq(len(field_in), dt) field_fft *= -omega**2 out_field = np.fft.ifft(field_fft) return out_field def disp(field_in, Dint_in): # computes the dispersion term in Fourier space field_fft = np.fft.fft(field_in) out_field = np.fft.ifft(Dint_in * field_fft) return out_field ### define the rhs function def LLE_1d(Z, A): # for nomalized if np.size(self.Dint) == 1 and self.Dint == 1: dAdt2 = deriv_2(self.TimeStep, A) dAdT = 1j * dAdt2 / 2 + 1j * self.gamma * self.L / self.Tr * np.abs( A)**2 * A - (self.kappa / 2 + 1j * dOm_curr) * A + np.sqrt( self.kappa / 2 / self.Tr) * self.Pump * Pump_P**.5 elif np.size(self.Dint) == 1 and self.Dint == -1: dAdt2 = deriv_2(self.TimeStep, A) dAdT = -1j * dAdt2 / 2 + 1j * self.gamma * self.L / self.Tr * np.abs( A)**2 * A - (self.kappa / 2 + 1j * dOm_curr) * A + np.sqrt( self.kappa / 2 / self.Tr) * self.Pump * Pump_P**.5 else: # with out raman Disp_int = disp(A, self.Dint) if self.Traman == 0: dAdT = -1j * Disp_int + 1j * self.gamma * self.L / self.Tr * np.abs( A )**2 * A - (self.kappa / 2 + 1j * dOm_curr) * A + np.sqrt( self.kappa / 2 / self.Tr) * self.Pump * Pump_P**.5 else: # with raman dAAdt = deriv_1(self.TimeStep, abs(A)**2) dAdT = -1j * Disp_int + 1j * self.gamma * self.L / self.Tr * np.abs( A )**2 * A - ( self.kappa / 2 + 1j * dOm_curr ) * A - 1j * self.gamma * self.Traman * dAAdt * A + np.sqrt( self.kappa / 2 / self.Tr) * self.Pump * Pump_P**.5 return dAdT r = complex_ode(LLE_1d).set_integrator('dopri5', atol=abtol, rtol=reltol, nsteps=nmax) # set the solver r.set_initial_value(self.seed, 0) # seed the cavity img = mpimg.imread('phase_space.png') xx = np.linspace(-1, 5, np.size(img, axis=1)) yy = np.linspace(11, 0, np.size(img, axis=0)) XX, YY = np.meshgrid(xx, yy) fig = plt.figure(figsize=(11, 7)) plt.subplots_adjust(top=0.95, bottom=0.1, left=0.06, right=0.986, hspace=0.2, wspace=0.16) ax1 = plt.subplot(221) ax1.pcolormesh(XX, YY, img[:, :, 1]) plt.xlabel('Detuning') plt.ylabel('f^2') plt.title('Choose the region') plt.xlim(min(xx), max(xx)) dot = plt.plot(detuning_0, Pump_P, 'rx') ax2 = plt.subplot(222) line, = plt.plot(abs(self.seed)**2) plt.ylim(0, 1.1) plt.ylabel('$|\Psi|^2$') ax3 = plt.subplot(224) line2, = plt.semilogy(self.mu, np.abs(np.fft.fft(self.seed))**2) plt.ylabel('PSD') plt.xlabel('mode number') ### widjets axcolor = 'lightgoldenrodyellow' resetax = plt.axes([0.4, 0.025, 0.1, 0.04]) button = Button(resetax, 'Stop', color=axcolor, hovercolor='0.975') axboxf = plt.axes([0.1, 0.35, 0.1, 0.075]) text_box_f = TextBox(axboxf, 'f^2', initial=str(Pump_P)) axboxd = plt.axes([0.1, 0.25, 0.1, 0.075]) text_box_d = TextBox(axboxd, 'Detuning', initial=str(detuning_0)) Run = True def setup(event): global Run Run = False button.on_clicked(setup) def onclick(event): if event.inaxes == ax1: ix, iy = event.xdata, event.ydata text_box_d.set_val(np.round(ix, 4)) text_box_f.set_val(np.round(iy, 4)) ax1.plot([ix], [iy], 'rx') fig.canvas.mpl_connect('button_press_event', onclick) while Run: dOm_curr = float(text_box_d.text) # get the detuning value Pump_P = float(text_box_f.text) Field = r.integrate(r.t + T_step) F_mod_sq = np.abs(Field)**2 F_sp = np.abs(np.fft.fft(Field))**2 line.set_ydata(F_mod_sq) line2.set_ydata(F_sp) ax2.set_ylim(0, max(F_mod_sq)) ax3.set_ylim(min(F_sp), max(F_sp)) plt.pause(1e-10)
t = np.array([], dtype=np.complex64) x = np.arange(-dom, dom, grid) L = len(x) mu = 0 sigma = 0.1 #A_0 = 0.2*np.sin(2*np.pi*x) + 0.1*1j*np.cos(2*np.pi*x+np.pi/6) + 0.1*np.random.random() #A_0 = np.random.normal(mu, sigma, dom*2) #A_0 = 1/np.cos((2*np.pi*x/L)**2) + 0.8/np.cos((2*np.pi*x/L)**2) + 0.01*np.random.random() #A_0 = np.cos(2*np.pi*x/L) + 0.1*np.random.normal(mu, sigma, dom*2) A_0 = np.sqrt(1 - (20 * np.pi / L)**2) * np.exp( 1j * 20 * np.pi * x / L) + 0.1 * np.random.normal(mu, sigma, dom * 2) L = len(A_0) r = complex_ode(dAdt) r.set_initial_value(A_0, t0) while r.successful() and r.t < t1: t = np.append(t, r.t + dt) sol.append(r.integrate(r.t + dt)) sol = np.array(sol) #abs_sol = sol[:,0:L/2]**2 + sol[:,L/2:L]**2 #abs_sol = np.array([abs_sol,abs_sol]) #abs_sol = abs_A2.flatten() X, T = np.meshgrid(x, t) fig = plt.figure(figsize=(15, 6))
def NLSE(pulse, fiber, nsaves=200, atol=1e-4, rtol=1e-4, reload_fiber=False, raman=False, shock=True, integrator='lsoda', print_status=True): """Propagate an laser pulse through a fiber according to the NLSE. This function propagates an optical input field (often a laser pulse) through a nonlinear material using the generalized nonlinear Schrodinger equation, which takes into account dispersion and nonlinearity. It is a "one dimensional" calculation, in that it doesn't capture things like self focusing and other geometric effects. It's most appropriate for analyzing light propagating through optical fibers. This code is based on the Matlab code found at www.scgbook.info, which is based on Eqs. (3.13), (3.16) and (3.17) of the book "Supercontinuum Generation in Optical Fibers" Edited by J. M. Dudley and J. R. Taylor (Cambridge 2010). The original Matlab code was written by J.C. Travers, M.H. Frosz and J.M. Dudley (2009). They ask that you cite the book in publications using their code. Parameters ---------- pulse : pulse object This is the input pulse. fiber : fiber object This defines the media ("fiber") through which the pulse propagates. nsaves : int The number of equidistant grid points along the fiber to return the field. Note that the integrator usually takes finer steps than this, the nsaves parameters simply determines what is returned by this function. atol : float Absolute tolerance for the integrator. Smaller values produce more accurate results but require longer integration times. 1e-4 works well. rtol : float Relative tolerance for the integrator. 1e-4 work well. reload_fiber : boolean This determines if the fiber information is reloaded at each step. This should be set to True if the fiber properties (gamma, dispersion) vary as a function of length. raman : boolean Determines if the Raman effect will be included. Default is False. shock : boolean Determines if the self-steepening (shock) term will be taken into account. This is especially important for situations where the slowly varying envelope approximation starts to break down, which can occur for large bandwidths (short pulses). integrator : string Selects the integrator that will be passes to scipy.integrate.ode. options are 'lsoda' (default), 'vode', 'dopri5', 'dopri853'. 'lsoda' is a good option, and seemed fastest in early tests. I think 'dopri5' and 'dopri853' are simpler Runge-Kutta methods, and they seem to take longer for the same result. 'vode' didn't seem to produce good results with "method='adams'", but things werereasonable with "method='bdf'" For more information, see: docs.scipy.org/doc/scipy/reference/generated/scipy.integrate.ode.html print_status : boolean This determines if the propagation status will be printed. Default is True. Returns ------- results : PulseData object This object contains all of the results. Use ``z, f, t, AW, AT = results.get_results()`` to unpack the z-coordinates, frequency grid, time grid, amplitude at each z-position in the freuqency domain, and amplitude at each z-position in the time domain. """ # get the pulse info from the pulse object: t = pulse.t_ps # time array in picoseconds at = pulse.at # amplitude for those times in sqrt(W) w0 = pulse.centerfrequency_THz * 2 * pi # center freq (angular!) n = t.size # number of time/frequency points dt = t[1] - t[0] # time step v = 2 * pi * linspace(-0.5 / dt, 0.5 / dt, n) # *angular* frequency grid flength = fiber.length # get length of fiber def load_fiber(fiber, z=0): # gets the fiber info from the fiber object gamma = fiber.get_gamma(z) # gamma should be in 1/(W m), not 1/(W km) b = fiber.get_B(pulse, z) loss = np.log(10**(fiber.get_alpha(z) * 0.1)) # convert from dB/m lin_operator = 1j * b - loss * 0.5 # linear operator if w0 > 0 and shock: # if w0>0 then include shock gamma = gamma / w0 w = v + w0 # for shock w is true freq else: w = 1 + v * 0 # set w to 1 when no shock # some fft shifts to things line up later: lin_operator = fftshift(lin_operator) w = fftshift(w) return lin_operator, w, gamma lin_operator, w, gamma = load_fiber(fiber) # load fiber info # Raman response: if raman == 'dudley' or raman: fr = 0.18 t1 = 0.0122 t2 = 0.032 rt = (t1**2 + t2**2) / t1 / t2**2 * exp(-t / t2) * sin(t / t1) rt[t < 0] = 0 # heaviside step function rw = n * ifft(fftshift(rt)) # frequency domain Raman elif not raman: fr = 0 else: raise ValueError('Raman method not supported') # define function to return the RHS of Eq. (3.13): def rhs(z, aw): nonlocal lin_operator, w, gamma if reload_fiber: lin_operator, w, gamma = load_fiber(fiber, z) at = fft(aw * exp(lin_operator * z)) # time domain field it = np.abs(at)**2 # time domain intensity if np.isclose(fr, 0): # no Raman case m = ifft(at * it) # response function else: rs = dt * fr * fft(ifft(it) * rw) # Raman convolution m = ifft(at * ((1 - fr) * it + rs)) # response function r = 1j * gamma * w * m * exp( -lin_operator * z) # full RHS of Eq. (3.13) return r z = linspace(0, flength, nsaves) # select output z points aw = ifft(at.astype('complex128')) # ensure integrator knows it's complex # set up the integrator: r = complex_ode(rhs).set_integrator(integrator, atol=atol, rtol=rtol) r.set_initial_value(aw, z[0]) # intialize array for results: AW = np.zeros((z.size, aw.size), dtype='complex128') AW[0] = aw # store initial pulse as first row start_time = time.time() # start the timer for count, zi in enumerate(z[1:]): if print_status: print('% 6.1f%% - %.3e m - %.1f seconds' % ((zi / z[-1]) * 100, zi, time.time() - start_time)) if not r.successful(): raise Exception('Integrator failed! Check the input parameters.') AW[count + 1] = r.integrate(zi) # process the output: AT = np.zeros_like(AW) for i in range(len(z)): AW[i] = AW[i] * exp( lin_operator.transpose() * z[i]) # change variables AT[i, :] = fft(AW[i]) # time domain output AW[i, :] = fftshift(AW[i]) # Below is the original dudley scaling factor that I think gives units # of sqrt(J/Hz) for the AW array. Removing this gives units that agree # with PyNLO, that seem to be sqrt(J*Hz) = sqrt(Watts) -DH 2021-12-15 # AW[i, :] = AW[i, :] * dt * n pulse_out = pulse.create_cloned_pulse() pulse_out.at = AT[-1] results = PulseData(z, AW, AT, pulse, pulse_out, fiber) return results
def psi(tf,M=10, L=0, aperiodicity=0,kind=0): """ Parameters ---------- time : float End time of the integration. L : float Nonlinearity parameter. M : int Number of lattice sites. (Default 101.) aperiodicity : float Aperiodicity parameter, defined in terms of the hoppings as (b/a - 1). (Default 0, which corresponds to a periodic chain.) kind: 0(periodic),fib,tm,rs Returns ------- y : float wavefn at time t """ def delta(t): if -0.1<t<1: return 1e0 elif 1<=t<=10: return 1e-1 elif 1e1<t<=1e2: return 1e0 elif 1e2<t<=1e3: return 1e1 elif 1e3<t<=1e4: return 1e2 elif 1e4<t<=1e5: return 1e3 else: return 1e4 r = integrate.complex_ode(dnls_rhs(M, L, aperiodicity,kind)).set_integrator('dopri5', nsteps=10000) central_site_index = (M - 1)/2 ic = np.zeros(shape=(M,)) ic[central_site_index] = 1.0 r.set_initial_value(ic) steps=int(np.ceil(90 * (np.log(tf)/np.log(10.0)))+2)#+ int(1e3) #dt = float(tf)/steps wavefn = np.zeros((steps,M), dtype=np.complex) t_arr=np.zeros((steps), dtype=np.float) idx=0 #for idx in xrange(steps): while r.t<tf: if r.successful(): #essentially, **if True:** if abs(r.y[0])< 1e-10 and abs(r.y[-1])<1e-10: #to make sure the lattice is big enough so that wavefn doesn't touch the boundary. wavefn[idx,:] = r.y[:] t_arr[idx]=r.t else: print ("wfn touching the boundary at t = {} for p={}".format(r.t,aperiodicity)) wave_fn_truncated=wavefn[0:idx,:] t_arr_truncated=t_arr[0:idx] return wave_fn_truncated, t_arr_truncated else: raise ValueError("Integration failed at t = {}".format(r.t)) r.integrate(r.t + delta(r.t)) idx+=1 return wavefn,t_arr
def compare_performance_dense(func, y0, t, y_ref, problem_name, tol_boundary=(0,6), is_complex=False, nsteps=10e5, solout=(lambda y,t: y)): print 'RUNNING COMPARISON TEST FOR ' + problem_name tol = [1.e-3,1.e-5,1.e-7,1.e-9,1.e-11,1.e-13] a, b = tol_boundary tol = tol[a:b] t0, tf = t[0], t[-1] py_runtime = np.zeros(len(tol)) py_fe_seq = np.zeros(len(tol)) py_fe_tot = np.zeros(len(tol)) py_yerr = np.zeros(len(tol)) py_nstp = np.zeros(len(tol)) dopri5_runtime = np.zeros(len(tol)) dopri5_fe_seq = np.zeros(len(tol)) dopri5_fe_tot = np.zeros(len(tol)) dopri5_yerr = np.zeros(len(tol)) dopri5_nstp = np.zeros(len(tol)) dop853_runtime = np.zeros(len(tol)) dop853_fe_seq = np.zeros(len(tol)) dop853_fe_tot = np.zeros(len(tol)) dop853_yerr = np.zeros(len(tol)) dop853_nstp = np.zeros(len(tol)) # This is necessary because multiprocessing uses pickle, which can't handle # Fortran function pointers def func2(t,y): return func(y,t) for i in range(len(tol)): print 'Tolerance: ', tol[i] # run Python extrapolation code print 'running ParEx' start_time = time.time() y, infodict = ex_p.ex_midpoint_explicit_parallel(func, None, y0, t, atol=tol[i], rtol=tol[i], mxstep=nsteps, adaptive="order", full_output=True) py_runtime[i] = time.time() - start_time py_fe_seq[i], py_fe_tot[i], py_nstp[i] = infodict['fe_seq'], infodict['nfe'], infodict['nst'] y[1:] = solout(y[1:],t[1:]) py_yerr[i] = relative_error(y[1:], y_ref) print 'Runtime: ', py_runtime[i], ' s Error: ', py_yerr[i], ' fe_seq: ', py_fe_seq[i], ' fe_tot: ', py_fe_tot[i], ' nstp: ', py_nstp[i] print '' # run DOPRI5 (scipy) print 'running DOPRI5 (scipy)' dopri5_d_solout = DenseSolout(t) start_time = time.time() if is_complex: r = complex_ode(func2).set_integrator('dopri5', atol=tol[i], rtol=tol[i], verbosity=10, nsteps=nsteps) else: r = ode(func2).set_integrator('dopri5', atol=tol[i], rtol=tol[i], verbosity=10, nsteps=nsteps) r.set_solout(dopri5_d_solout.solout, dense_components=tuple(range(len(y0)))) r.set_initial_value(y0, t0) r.integrate(r.t+(tf-t0)) assert r.t == tf, "Integration did not converge. Try increasing the max number of steps" dopri5_runtime[i] = time.time() - start_time y = np.array(dopri5_d_solout.dense_output) y[1:] = solout(y[1:],t[1:]) dopri5_yerr[i] = relative_error(y[1:], y_ref) print 'Runtime: ', dopri5_runtime[i], ' s Error: ', dopri5_yerr[i], ' fe_seq: ', dopri5_fe_seq[i], ' fe_tot: ', dopri5_fe_tot[i], ' nstp: ', dopri5_nstp[i] print '' # run DOP853 (scipy) print 'running DOP853 (scipy)' dop853_d_solout = DenseSolout(t) start_time = time.time() if is_complex: r = complex_ode(func2, jac=None).set_integrator('dop853', atol=tol[i], rtol=tol[i], verbosity=10, nsteps=nsteps) else: r = ode(func2, jac=None).set_integrator('dop853', atol=tol[i], rtol=tol[i], verbosity=10, nsteps=nsteps) r.set_solout(dop853_d_solout.solout, dense_components=tuple(range(len(y0)))) r.set_initial_value(y0, t0) r.integrate(r.t+(tf-t0)) assert r.t == tf, "Integration did not converge. Try increasing the max number of steps" dop853_runtime[i] = time.time() - start_time y = np.array(dop853_d_solout.dense_output) y[1:] = solout(y[1:],t[1:]) dop853_yerr[i] = relative_error(y[1:], y_ref) print 'Runtime: ', dop853_runtime[i], ' s Error: ', dop853_yerr[i], ' fe_seq: ', dop853_fe_seq[i], ' fe_tot: ', dop853_fe_tot[i], ' nstp: ', dop853_nstp[i] print '' print '' print "Final data: ParEx" print py_runtime, py_fe_seq, py_fe_tot, py_yerr, py_nstp print "Final data: DOPRI5 (scipy)" print dopri5_runtime, dopri5_fe_seq, dopri5_fe_tot, dopri5_yerr, dopri5_nstp print "Final data: DOP853 (scipy)" print dop853_runtime, dop853_fe_seq, dop853_fe_tot, dop853_yerr, dop853_nstp print '' print '' # plot performance graphs import matplotlib matplotlib.use('agg') import matplotlib.pyplot as plt plt.hold('true') py_line, = plt.loglog(py_yerr, py_runtime, "s-") dopri5_line, = plt.loglog(dopri5_yerr, dopri5_runtime, "s-") dop853_line, = plt.loglog(dop853_yerr, dop853_runtime, "s-") plt.legend([py_line, dopri5_line, dop853_line], ["ParEx", "DOPRI5 (scipy)", "DOP853 (scipy)"], loc=1) plt.xlabel('Error') plt.ylabel('Wall clock time (seconds)') plt.title(problem_name) plt.show() plt.savefig('images/' + problem_name + '_err_vs_time.png') plt.close()
def laser_simulation(uvt, alpha1, alpha2, alpha3, alphap,K): # parameters of the Maxwell equation """ D = 1 K = 0.1 E0 = 1 tau = 0.1 g0 = 0.3 Gamma = 0.2 """ D = -0.4 E0 = 4.23 tau = 0.1 g0 = 1.73 Gamma = 0.1 Z = 1.5 # cavity length T = 60 n = 256 # t slices Rnd = 500 # round trips t2 = np.linspace(-T/2,T/2,n+1) t_dis = t2[0:n].reshape([1,n]) # time discretization new = np.concatenate((np.linspace(0,n//2-1,n//2), np.linspace(-n//2,-1,n//2)),0) k = (2*np.pi/T)*new ts=[] ys=[] t0=0.0 tend=1 # waveplates & polarizer W4 = np.array([[np.exp(-1j*np.pi/4), 0],[0, np.exp(1j*np.pi/4)]]); # quarter waveplate W2 = np.array([[-1j, 0],[0, 1j]]); # half waveplate WP = np.array([[1, 0], [0, 0]]); # polarizer # waveplate settings R1 = np.array([[np.cos(alpha1), -np.sin(alpha1)], [np.sin(alpha1), np.cos(alpha1)]]) R2 = np.array([[np.cos(alpha2), -np.sin(alpha2)], [np.sin(alpha2), np.cos(alpha2)]]) R3 = np.array([[np.cos(alpha3), -np.sin(alpha3)], [np.sin(alpha3), np.cos(alpha3)]]) RP = np.array([[np.cos(alphap), -np.sin(alphap)], [np.sin(alphap), np.cos(alphap)]]) J1 = np.matmul(np.matmul(R1,W4),np.transpose(R1)) J2 = np.matmul(np.matmul(R2,W4),np.transpose(R2)) J3 = np.matmul(np.matmul(R3,W2),np.transpose(R3)) JP = np.matmul(np.matmul(RP,WP),np.transpose(RP)) # transfer function Transf = np.matmul(np.matmul(np.matmul(J1,JP),J2),J3) urnd=np.zeros([Rnd, n], dtype=complex) vrnd=np.zeros([Rnd, n], dtype=complex) t_dis=t_dis.reshape(n,) energy=np.zeros([1,Rnd]) # definition of the rhs of the ode def mlock_CNLS_rhs(ts, uvt): [ut_rhs,vt_rhs] = np.split(uvt,2) u = np.fft.ifft(ut_rhs) v = np.fft.ifft(vt_rhs) # calculation of the energy function E = np.trapz(np.conj(u)*u+np.conj(v)*v,t_dis) # u of the rhs urhs = -1j*0.5*D*(k**2)*ut_rhs - 1j*K*ut_rhs + \ 1j*np.fft.fft((np.conj(u)*u+ (2/3)*np.conj(v)*v)*u + \ (1/3)*(v**2)*np.conj(u)) + \ 2*g0/(1+E/E0)*(1-tau*(k**2))*ut_rhs - Gamma*ut_rhs # v of the rhs vrhs = -1j*0.5*D*(k**2)*vt_rhs + 1j*K*vt_rhs + \ 1j*np.fft.fft((np.conj(v)*v+(2/3)*np.conj(u)*u)*v + \ (1/3)*(u**2)*np.conj(v) ) + \ 2*g0/(1+E/E0)*(1-tau*(k**2))*vt_rhs - Gamma*vt_rhs return np.concatenate((urhs, vrhs),axis=0) # definition of the solution output for the ode integration def solout(t,y): ts.append(t) ys.append(y.copy()) start = time.time() uv_list = [] norms = [] change_norm = 100 jrnd = 0 # solving the ode for Rnd rounds while(jrnd < Rnd and change_norm > 1e-6): ts = [] ys = [] t0 = Z*jrnd tend = Z*(jrnd+1) uvtsol = complex_ode(mlock_CNLS_rhs) uvtsol.set_integrator(method='adams', name='dop853') # alternative 'dopri5' uvtsol.set_solout(solout) uvtsol.set_initial_value(uvt, t0) sol = uvtsol.integrate(tend) assert_equal(ts[0], t0) assert_equal(ts[-1], tend) u=np.fft.ifft(sol[0:n]) v=np.fft.ifft(sol[n:2*n]) urnd[jrnd,:]=u vrnd[jrnd,:]=v energy[0, jrnd]=np.trapz(np.abs(u)**2+np.abs(v)**2,t_dis) uvplus=np.matmul(Transf,np.transpose(np.concatenate((u.reshape(n,1), v.reshape(n,1)),axis=1))) uv_list.append(np.concatenate((uvplus[0,:], uvplus[1,:]), axis=0)) uvt=np.concatenate((np.fft.fft(uvplus[0,:]), np.fft.fft(uvplus[1,:])), axis=0) if jrnd > 0: phi=np.sqrt(np.abs(np.vstack(uv_list)[:,:n])**2 + \ np.abs(np.vstack(uv_list)[:,n:2*n])**2) change_norm=np.linalg.norm((phi[-1,:]-phi[len(phi)-2,:]))/ \ np.linalg.norm(phi[len(phi)-2,:]) norms.append(change_norm) jrnd += 1 kur = np.abs(np.fft.fftshift(np.fft.fft(phi[-1,:]))) #M4 = kurtosis(kur) M4 = moment(kur,4)/np.std(kur)**4 end = time.time() print(end-start) E = np.sqrt(np.trapz(phi[-1,:]**2, t_dis)) states = np.array([E, M4, alpha1, alpha2, alpha3, alphap]) """ surface plot # create meshgrid X, Y = np.meshgrid(t_dis,np.arange(0,len(norms))) # figure urnd fig_urand = plt.figure() ax = fig_urand.gca(projection='3d') # plot the surface surf = ax.plot_surface(X, Y, np.abs(urnd[:len(norms),:]), cmap=cm.coolwarm, linewidth=0, antialiased=False) # Add a color bar which maps values to colors. fig_urand.colorbar(surf, shrink=0.5, aspect=5) # figure vrnd fig_vrand = plt.figure() ax = fig_vrand.gca(projection='3d') # plot the surface surf = ax.plot_surface(X, Y, np.abs(vrnd[:len(norms),:]), cmap=cm.coolwarm, linewidth=0, antialiased=False) # Add a color bar which maps values to colors. fig_vrand.colorbar(surf, shrink=0.5, aspect=5) plt.show() """ return (uvt,states)
x = np.zeros((6,N))*1j # für RK5 y0 = np.array(psi_0) x[:,0] = y0 # Imaginärteil ist 0 # x ist complexes 36xN array t0 = 0 t1 = 30*np.pi t = np.linspace(t0,t1,N) #Ausgabe: print('E_0*a:', E_0_n, '// w:', w, '// Intervall für t: [',t0,';',t1,']' ) #Integration mit Runge-Kutta 5: r = complex_ode(f).set_integrator('dopri5') r.set_initial_value(y0, t0) i = 1 print('Runge-Kutta(5) für',N-1,'Werte:') with tqdm(total=N-1) as pbar: while r.successful() and r.t < t1: r.integrate(t[i]) pbar.update(1) x[:,i] = r.y i += 1 # Stromoperator Erwartungswert: J = np.zeros((6,6)) for i in range(0,6): # Alle Zeilen (jede i-te Zeile bestimmt alpha des i-ten End-Zustandes) for j in range(0,6): # Alle Spalten (Multiplikation von J mit |j>)
def BS_mc_evolution( p0, gamma, length, dispersion, s_wl, p1_wl, p2_wl, s_0 = np.array([0,1,0], dtype=np.complex64), a_p = r_[1,1], ## Losses terms (for completeness) alpha_l = Q_('0 1/m'), # Loss alpha_2p = Q_('0 1/(W m)'), # NL loss s_fca = Q_('0 m**2'), t_fca = Q_(1, 'as'), # TPA w0_wl = 1550 * nm, ## FCA defined at 1550 nn vary_pump = False, grid_size = 100): """ Bragg Scattering MultiChannel Simulation requires Units and Dispersion wl1, wl2: define the pump frequency comb (i.e. p_w and dw) s_wl: is the input signal wavelength. dispersion: is the dispersion (Dispersion) s_0: input fields. Size of the array determines the channels a_p: are the pump fields amplitudes normalized to p0 """ # Simulation units u_l = Q_('mm') u_p = Q_('W') # Obtain angular frequency p_w = 2*pi*c_light*(1/p1_wl + 1/p2_wl)/2 s_w = 2*pi*c_light/s_wl dw = (1/p1_wl - 1/p2_wl)*2*pi*c_light # Channel separation z = length.to(u_l).magnitude dz = z/grid_size # signal is centered at len(s_0)/2 n_ch = len(s_0) n_order = np.floor(n_ch / 2) a_s = s_0 # Generate a dimensionless phasematching function. phasematching = generatePhasematching(p_w, s_w, dw, dispersion, k_unit = 1/u_l) # Effective nonlinearity nl_eff = gamma * p0 a_p = a_p * sqrt(nl_eff.to(1/u_l).magnitude) p_out = np.zeros((gridsize + 1, len(a_p)), dtype= np.complex64) if varying_pump: ## Simulate pumps ode_pump = complex_ode(f) ode.set_initial_value(a_p) i = 1 for zi in np.arange(dz, z, dz): output [i,:] = ode.integrate(zi) i += 1 if not ode.successful(): raise Exception() # Use it to generate the coupling matrix coefficients k_dict = generateCoefficients(a_p = a_p, phasematching = phasematching, n_order= n_order, kappa_limit = 1e3/dz) # Losses #a2p_eff = alpha_2p * p0 #h_nup = Q_('h*c')/w0_wl #fca = [alpha_2p*t_fca/(2*h_nup)*s_fca*(wl/w0_wl)**2 * p0**2 \ # for wl in [s_wl, i_wl, p1_wl, p2_wl]] #fca = zeros(4) * Q_('1/m') # FCA formula may be wrong ## There is a BUG in scipy for functions accepting external arguments in complex_ode. ## I just make them global and unitless #args = ( dk.to(1/u_l).magnitude, # nl_eff.to(1/u_l).magnitude, # alpha_l.to(1/u_l).magnitude, # a2p_eff.to(1/u_l).magnitude, # r_[ [f.to(1/u_l).magnitude for f in fca] ] ) ## Compute simulation parameters ### print(k_dict) # Define a f(z, x) = dx/dz f = lambda z, x: np.dot(x, interactionMatrixZ(k_dict, z, n_ch)) # Build the output array output = np.zeros((grid_size+1, n_ch), dtype= np.complex64) output[0,:] = a_s # Finally, simulate ode = complex_ode(f) ode.set_initial_value(a_s) i = 1 for zi in np.arange(dz, z, dz): output [i,:] = ode.integrate(zi) i += 1 if not ode.successful(): raise Exception() return (output, dz)
# ## Starting state and times # In[207]: rho0= ls[0] ti = 0 tf = 1 dt = 101 ts = np.linspace(ti, tf, dt) # ## Initiate scipy integrator and evolve # In[208]: stepper = complex_ode(leq) stepper.set_integrator('dop853', nsteps=0, first_step=0.01) stepper.set_initial_value(np.asarray(rho0).reshape(-1), ti) # array for population values xs = np.empty((d, len(ts)), dtype=float) for i, t in enumerate(ts): stepper.integrate(t) rhot = np.asmatrix(stepper.y.reshape(d, d)) xs[:, i] = np.diag(rhot).real # In[209]: plt.plot(ts, xs[0, :], label='1')
def gnlse(t, at, w0, gamma, betas, loss, fr, rt, flength, nsaves=200, atol=1e-4, rtol=1e-4, integrator='lsoda'): """ This function propagates an optical input field (often a laser pulse) through a nonlinear material using the generalized nonlinear Schrodinger equation, which takes into account dispersion and nonlinearity. It is a "one dimensional" calculation, in that it doesn't capture things like self focusing and other geometric effects. It's most appropriate for analyzing light propagating through optical fibers. This code is based on the Matlab code found at www.scgbook.info, which is based on Eqs. (3.13), (3.16) and (3.17) of the book "Supercontinuum Generation in Optical Fibers" Edited by J. M. Dudley and J. R. Taylor (Cambridge 2010). The original Matlab code was written by J.C. Travers, M.H. Frosz and J.M. Dudley (2009). They ask that you please cite this chapter in any publication using this code. 2018-02-01 - First Python port by Dan Hickstein ([email protected]) 2020-01-11 - General clean up and PEP8 Parameters ---------- t : 1D numpy array of length n The time grid. Should be evenly spaced. at : 1D numpy array of length n The temporal pulse envelope. Matches the time grid T. Can be complex. w0 : float The "carrier frequency" for the moving reference frame gamma : float The effective nonlinearity, in units of [1/(W m)]. note that the gammas for fibers are often described in units of 1/(W km) (per kilometer rather than per meter). betas : list of floats the coefficients of the dispersion expansion. Given as betas = [beta2, beta3, beta4, ...] In units of [ps^2/m, ps^3/m, ps^4/m ...] Note that this betas array is used to generate the b array. Those who want to include an aibitrary dispersion could hack this function and supply the b array. b is to so-called wavenumber (often written as k) and is equal to (refractive index)*2*pi/wavelength. rt : numpy array The time domain Raman response. Matches the time grid T. flength : float the fiber length [meters] nsaves : int the number of equidistant grid points along the fiber to return the field. Note that the integrator usually takes finer steps than this, the nsaves parameters simply determines what is returned by this function integrator : string Selects the integrator that will be passes to scipy.integrate.ode. options are 'lsoda' (default), 'vode', 'dopri5', 'dopri853'. 'lsoda' is a good option, and seemed fastest in early tests. I think 'dopri5' and 'dopri853' are simpler Runge-Kutta methods, and they seem to take longer for the same result. 'vode' didn't seem to produce good results with "method='adams'", but things werereasonable with "method='bdf'" For more information, see: docs.scipy.org/doc/scipy/reference/generated/scipy.integrate.ode.html Returns ------- z : 1D numpy array of length nsaves an array of the z-coordinate along the fiber where the results are returned AT : 2D numpy array, with dimensions nsaves x n The time domain field at every step. Complex. AW : 2D numpy array, with dimensions nsaves x n The frequency domain field at every step. Complex. v : 1D numpy array of length n The frequency grid. """ n = t.size # number of time/frequency points dt = t[1] - t[0] # time step v = 2 * pi * linspace(-0.5 / dt, 0.5 / dt, n) # *angular* frequency grid alpha = log10(10**(loss / 10.)) # attenuation coefficient b = np.zeros_like(v) for i in range(len(betas)): # Taylor expansion of GVD b += betas[i] / factorial(i + 2) * v**(i + 2) lin_operator = 1j * b - alpha * 0.5 # linear operator if np.nonzero(w0): # if w0>0 then include shock gamma = gamma / w0 w = v + w0 # for shock w is true freq else: w = 1 # set w to 1 when no shock rw = n * ifft(fftshift(rt)) # frequency domain Raman # shift to fft space -- Back to time domain, right? lin_operator = fftshift(lin_operator) w = fftshift(w) # define function to return the RHS of Eq. (3.13): def rhs(z, aw): at = fft(aw * exp(lin_operator * z)) # time domain field it = np.abs(at)**2 # time domain intensity if rt.size == 1 or np.isclose(fr, 0): # no Raman case m = ifft(at * it) # response function else: rs = dt * fr * fft(ifft(it) * rw) # Raman convolution m = ifft(at * ((1 - fr) * it + rs)) # response function r = 1j * gamma * w * m * exp( -lin_operator * z) # full RHS of Eq. (3.13) return r z = linspace(0, flength, nsaves) # select output z points aw = ifft(at.astype('complex128')) # ensure integrator knows it's complex r = complex_ode(rhs).set_integrator(integrator, atol=atol, rtol=rtol) r.set_initial_value(aw, z[0]) # set up the integrator # intialize array for results: AW = np.zeros((z.size, aw.size), dtype='complex128') AW[0] = aw # store initial pulse as first row start_time = time.time() # start the timer for count, zi in enumerate(z[1:]): print('% 6.1f%% complete - %.1f seconds' % ((zi / z[-1]) * 100, time.time() - start_time)) if not r.successful(): print('integrator failed!') break AW[count + 1] = r.integrate(zi) # process the output: AT = np.zeros_like(AW) for i in range(len(z)): AW[i] = AW[i] * exp( lin_operator.transpose() * z[i]) # change variables AT[i, :] = fft(AW[i]) # time domain output AW[i, :] = fftshift(AW[i]) / dt # scale AT = fft(AW, axis=1) return z, AT, AW, v + w0
psi_t = np.zeros((N_TIMES, 2)).astype(np.complex) psi_t[0] = psi_0 one = np.eye(psi_0.shape[0]) for t in range(1, np.shape(times)[0]): time = times[t] delta_t = times[t] - times[t-1] propagator = np.linalg.inv(one + 1j * delta_t / 2 * hamiltonian(time - delta_t / 2.0)) propagator = propagator.dot(one - 1j * delta_t / 2 * hamiltonian(time - delta_t / 2.0)) psi_t[t] = propagator.dot(psi_t[t-1]) plot_evolution(times, psi_t) # Create a complex_ode instance to solve the system of differential # equations defined by `hamiltonian`, and set the solver method to dopri5 (an alternative more precise RK-8 is dop853) solver = complex_ode(rhs) solver.set_integrator('dopri5') solver.set_initial_value(psi_0, t0) psi_t = np.zeros((N_TIMES, 2)).astype(np.complex) psi_t[0] = psi_0 # Repeatedly call the `integrate` method to advance the # solution to time t[k], and save the solution in sol[k]. for i in range(1, times.shape[0]): time = times[i] if not solver.successful(): break psi_t[i] = solver.integrate(time)