Skip to content

Commit 8c23c24

Browse files
committed
comments in propagation code
1 parent 8a5e69f commit 8c23c24

1 file changed

Lines changed: 83 additions & 15 deletions

File tree

WrightSim/mixed/propagate.py

Lines changed: 83 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,26 @@
11
import numpy as np
22

33
def 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

5056
muladd_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

6176
dot_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):
7799
pulse_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

109152
runge_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__
111172
pycuda::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

Comments
 (0)