11import numpy as np
22
33def runge_kutta (t , efields , n_recorded , hamiltonian ):
4- """
5- Evolves the hamiltonian in time, given the three 1d array of E-field points
6- for each E-field and the hamiltonian
7-
8- H[pulse_permutations, t, ij_to, ij_from] is a rank 4 array of the hamiltonian 2D
9- matrix for each time point and necessary pulse permutations
4+ """ Evolves the hamiltonian in time using the runge_kutta method.
105
11- Uses Runge-Kutta method to integrate
12- --> assumes eqaully spaced t-points (t_int is spacing)
6+ Parameters
7+ ----------
8+ t : 1-D array of float
9+ Time points, equally spaced array.
10+ Shape T, number of timepoints
11+ efields : ndarray <Complex>
12+ Time dependant electric fields for all pulses.
13+ SHape M x T where M is number of electric fields, T is number of time points.
14+ n_recorded : int
15+ Number of timesteps to record at the end of the simulation.
16+ hamiltonian : Hamiltonian
17+ The hamiltonian object which contains the inital conditions and the
18+ function to use to obtain the matrices.
1319
14- Unlike earlier implementations, delays, phase, etc., must be incorporated
15- externally to the function. Rotating wave may still be specified.
20+ Returns
21+ -------
22+ ndarray : <Complex>
23+ 2-D array of recorded density vector elements for each time step in n_recorded.
1624 """
1725 # can only call on n_recorded and t after efield_object.E is called
1826 dt = np .abs (t [1 ]- t [0 ])
@@ -25,11 +33,10 @@ def runge_kutta(t, efields, n_recorded, hamiltonian):
2533 emitted_index = 0
2634 rho_i = hamiltonian .rho .copy ()
2735 for k in range (len (t )- 1 ):
28- # now sum over p equivalent pulse permutations (e.g. TRIVE near-
29- # diagonal has 2 permutations)
3036 # calculate delta rho based on previous rho values
3137 temp_delta_rho = np .dot (H [k ], rho_i )
3238 temp_rho_i = rho_i + temp_delta_rho * dt
39+ # second order term
3340 delta_rho = np .dot (H [k + 1 ], temp_rho_i )
3441 rho_i += dt / 2 * (temp_delta_rho + delta_rho )
3542 # if we are close enough to final coherence emission, start
@@ -44,10 +51,18 @@ def runge_kutta(t, efields, n_recorded, hamiltonian):
4451 for rec ,native in enumerate (hamiltonian .recorded_indices ):
4552 rho_emitted [rec , emitted_index ] = rho_i [native ]
4653
47- # rho_emitted[s,t], s is out_group index, t is time index
4854 return rho_emitted
4955
5056muladd_cuda_source = """
57+ /*
58+ * muladd: Linear combination of two vectors with two scalar multiples
59+ *
60+ * computes a*b + c*d where a and c are vectors, b and d are scalars
61+ * Values are stored in out.
62+ * If out is the same as a or c, this is an in place operation.
63+ * len defines the length to perform the computation.
64+ * Generalizes to n-D array, given it is stored in contiguous memory.
65+ */
5166__device__ void muladd(pycuda::complex<double>* a, double b, pycuda::complex<double>* c, double d,
5267 int len, pycuda::complex<double>* out)
5368{
@@ -59,6 +74,13 @@ def runge_kutta(t, efields, n_recorded, hamiltonian):
5974"""
6075
6176dot_cuda_source = """
77+ /*
78+ * dot: Matrix multiplied by a vector.
79+ *
80+ * Expects a square NxN matrix and an N-length column vector.
81+ * Values are written to out. DO NOT use in place, invalid results will be returned.
82+ *
83+ */
6284__device__ void dot(pycuda::complex<double>* mat, pycuda::complex<double>* vec, int len,
6385 pycuda::complex<double>* out)
6486{
@@ -77,6 +99,16 @@ def runge_kutta(t, efields, n_recorded, hamiltonian):
7799pulse_cuda_source = """
78100#include <math.h>
79101
102+ /*
103+ * calc_efield_params: convert efield params into appropriate values
104+ *
105+ * Converts FWHM to standard deviation
106+ * Converts frequency into the rotating frame
107+ * Converts area of peak to height
108+ *
109+ * Performs calculaiton on N contiguous sets of paramters, operation in place.
110+ *
111+ */
80112__device__ void calc_efield_params(double* params, int n)
81113{
82114 for(int i=0; i < n; i++)
@@ -90,9 +122,20 @@ def runge_kutta(t, efields, n_recorded, hamiltonian):
90122 }
91123}
92124
125+ /*
126+ * calc_efield: Convert parameters, phase matching, and time into an electric field
127+ *
128+ * Converts n electric fields at a time, places the complex electric
129+ * field value into out, in contiguous fashion.
130+ * The length of the phase_matiching array must be at least n.
131+ *
132+ */
93133__device__ void calc_efield(double* params, int* phase_matching, double t, int n,
94134 pycuda::complex<double>* out)
95135{
136+ //TODO: ensure phase matching is done correctly for cases where
137+ // it is not equal to +/- 1 (or 0, though why would you have 0)
138+ // NISE took the sign, so far I have only taken the value
96139 for(int i=0; i < n; i++)
97140 {
98141 // Complex phase and magnitude
@@ -107,12 +150,31 @@ def runge_kutta(t, efields, n_recorded, hamiltonian):
107150
108151
109152runge_kutta_cuda_source = """
153+ /*
154+ * runge_kutta: Propagate electric fields over time using Runge-Kutta integration
155+ *
156+ * Parameters
157+ * ----------
158+ * time_start: inital simulation time
159+ * time_end: final simulation time
160+ * dt: time step
161+ * nEFields: number of electric fields
162+ * *efparams: pointer to array of parameters for those electric fields
163+ * *phase_matiching: array of phase matching conditions
164+ * n_recorded: number of output values to record
165+ * ham: Hamiltonian struct containing inital values, passed to matrix generator.
166+ *
167+ * Output:
168+ * *out: array of recorded values. expects enough memory for n_recorded * ham.nRecorded
169+ * complex values
170+ */
110171__device__
111172pycuda::complex<double>* runge_kutta(const double time_start, const double time_end, const double dt,
112173 const int nEFields, double* efparams, int* phase_matching,
113174 const int n_recorded, Hamiltonian ham,
114175 pycuda::complex<double> *out)
115176{
177+ // Allocate arrays and pointers for the Hamiltonians for the current and next step.
116178 //pycuda::complex<double> *H_cur = (pycuda::complex<double>*)malloc(ham.nStates * ham.nStates * sizeof(pycuda::complex<double>));
117179 //pycuda::complex<double> *H_next = (pycuda::complex<double>*)malloc(ham.nStates * ham.nStates * sizeof(pycuda::complex<double>));
118180 //TODO: either figure out why dynamically allocated arrays weren't working, or use a #define to statically allocate
@@ -122,27 +184,32 @@ def runge_kutta(t, efields, n_recorded, hamiltonian):
122184 pycuda::complex<double>* H_cur = buf1;
123185 pycuda::complex<double>* H_next = buf2;
124186
187+ // Track indices in arrays.
125188 int out_index = 0;
126189 int index=0;
127190
191+ // determine number of points.
128192 int npoints = (int)((time_end-time_start)/dt);
129193
194+ // Allocate vectors used in computation.
130195 pycuda::complex<double>* rho_i = (pycuda::complex<double>*)malloc(ham.nStates * sizeof(pycuda::complex<double>));
131196 pycuda::complex<double>* temp_delta_rho = (pycuda::complex<double>*)malloc(ham.nStates * sizeof(pycuda::complex<double>));
132197 pycuda::complex<double>* temp_rho_i = (pycuda::complex<double>*)malloc(ham.nStates * sizeof(pycuda::complex<double>));
133198 pycuda::complex<double>* delta_rho = (pycuda::complex<double>*)malloc(ham.nStates * sizeof(pycuda::complex<double>));
134199 pycuda::complex<double>* efields = (pycuda::complex<double>*)malloc(nEFields * sizeof(pycuda::complex<double>));
135200
136- // Inital rho vector
201+ // Inital rho vector.
137202 //TODO: Use the inital condition from the hamiltonian
138203 rho_i[0] = 1.;
139204 for(int i=1; i<ham.nStates; i++) rho_i[i] = 0.;
140205
206+ // Convert from given units to simulation units.
141207 calc_efield_params(efparams, nEFields);
142208
209+ // Compute the first set of electric fields.
143210 calc_efield(efparams, phase_matching, time_start, nEFields, efields);
144211
145-
212+ // Compute the inital matrix, stored in H_next, to be swapped
146213 Hamiltonian_matrix(ham, efields, time_start, H_next);
147214 for(double t = time_start; t < time_end; t += dt)
148215 {
@@ -186,6 +253,7 @@ def runge_kutta(t, efields, n_recorded, hamiltonian):
186253 free(temp_rho_i);
187254 free(delta_rho);
188255 free(efields);
256+
189257 return out;
190258}
191259"""
0 commit comments