Merging carrier and signal simulation
A large amount of changes here, hopefully for the better:
BaseSimulation is gone. CarrierSignalMatrixSimulation replaces it effectively. This new class embodies the simulation methodology of Finesse, solving two sparse matrices, can be plane-wave or modal.
CarrierSignalMatrixSimulation has two matrix solvers, one for the carrier and one for the signal. sim.carrier
and sim.signal
. These hold all the information regards node indicies, views of the RHS output, solving, filling, workspaces, etc.
Detector workspaces are now stored in the single CarrierSignalMatrixSimulation
object as it should be, rather than in the model.
CarrierSignalMatrixSimulation contains common workspaces and beam tracing between the two matrix solvers. No need for all the annoying duplicated code and weird work arounds.
Matrix filling methods are now split, you specify one for carrier and one for signal. Looks like this now:
ws = MirrorWorkspace(self, sim, refill)
ws.carrier.set_fill_function(mirror_carrier_fill)
ws.signal.set_fill_function(mirror_signal_fill)
This change means nearly every file needed updating slightly.
Getting some output now looks like, weird DC
in the name gone:
ws.sim.carrier.get_out(self.p1.i, f1.index, k)
ws.carrier
is a ConnectorMatrixSimulationInfo
which contains details on the matrix specific connections indices for accessing fill functions, and points to fill functions. ws.sim.carrier
is a reference to the MatrixSystemSolver
for actually doing filling, solving. KLU class inherits from this solver class to do its job. Dense matrix solver and Lee's code unfortunately do not work
sim.frequencies
has been renamed to sim.optical_frequencies
which is a FrequencyContainer
.
Optical and signal connections objects now have to be both stored at once. Given all the purely optical filling is identical between carrier and signal, fill methods should be abstracted enough to be used between them:
cdef class MirrorOpticalConnections:
cdef public:
int P1i_P1o_idx
int P2i_P2o_idx
int P1i_P2o_idx
int P2i_P1o_idx
cdef readonly:
SubCCSView1DArray P1i_P1o
SubCCSView1DArray P2i_P2o
SubCCSView1DArray P1i_P2o
SubCCSView1DArray P2i_P1o
cdef:
mirror_optical_connections opt_conn_ptrs
cdef class MirrorSignalConnections(MirrorOpticalConnections):
cdef public:
int P1i_Fz_idx, P2i_Fz_idx, P1o_Fz_idx, P2o_Fz_idx
int Z_P1o_idx, Z_P2o_idx
cdef readonly:
SubCCSView2DArray P1i_Fz
SubCCSView2DArray P1o_Fz
SubCCSView2DArray P2i_Fz
SubCCSView2DArray P2o_Fz
SubCCSView2DArray Z_P1o
SubCCSView2DArray Z_P2o
cdef:
mirror_signal_connections sig_conn_ptrs
These new abstract fill methods can look something like this:
cdef inline void mirror_fill_optical_2_optical(
mirror_optical_connections *conn,
MirrorWorkspace ws,
frequency_info_t *freq,
double r,
complex_t it,
double phi
):
cdef double phase_shift = 2.0 * phi * (1 + freq.f / ws.sim.model_data.f0)
cdef complex_t tuning = cexp(1.0j * phase_shift)
cdef complex_t ctuning = conj(tuning)
# Reflections
(<SubCCSView>conn.P1i_P1o[freq.index]).fill_za_zm_2(
r * tuning, ws.K11.ptr, ws.K11.stride1, ws.K11.stride2
)
(<SubCCSView>conn.P2i_P2o[freq.index]).fill_za_zm_2(
r * ctuning, ws.K22.ptr, ws.K22.stride1, ws.K22.stride2
)
# Transmission
(<SubCCSView>conn.P1i_P2o[freq.index]).fill_za_zm_2(
it, ws.K12.ptr, ws.K12.stride1, ws.K12.stride2
)
(<SubCCSView>conn.P2i_P1o[freq.index]).fill_za_zm_2(
it, ws.K21.ptr, ws.K21.stride1, ws.K21.stride2
)