2 * \brief Modern interface for finite lattice calculations, including symmetries.
4 * N.B. Only "reasonably normalised" waves are supported now in most of the
5 * functions defined here, i.e. those that can be rotated by the usual
6 * Wigner matrices, i.e. the "power" or "spharm" -normalised ones.
8 * TODO FIXME check whether Condon-Shortley phase can have some nasty influence
9 * here; I fear that yes.
11 #ifndef QPMS_SCATSYSTEM_H
12 #define QPMS_SCATSYSTEM_H
13 #include "qpms_types.h"
17 /// Overrides the number of threads spawned by the paralellized functions.
18 /** TODO MORE DOC which are those? */
19 void qpms_scatsystem_set_nthreads(long n
);
21 /// A particle, defined by its T-matrix and position.
22 typedef struct qpms_particle_t
{
23 // Does it make sense to ever use other than cartesian coords for this?
24 cart3_t pos
; ///< Particle position in cartesian coordinates.
25 const qpms_tmatrix_t
*tmatrix
; ///< T-matrix; not owned by qpms_particle_t.
28 struct qpms_finite_group_t
;
29 typedef struct qpms_finite_group_t qpms_finite_group_t
;
31 /// A particle, defined by its T-matrix INDEX and position, to be used in qpms_scatsys_t.
32 typedef struct qpms_particle_tid_t
{
33 // Does it make sense to ever use other than cartesian coords for this?
34 cart3_t pos
; ///< Particle position in cartesian coordinates.
35 qpms_ss_tmi_t tmatrix_id
; ///< T-matrix index
36 } qpms_particle_tid_t
;
39 typedef qpms_gmi_t qpms_ss_orbit_pi_t
; ///< Auxilliary type used in qpms_ss_orbit_type_t for labeling particles inside orbits.
40 typedef qpms_ss_tmi_t qpms_ss_oti_t
; ///< Auxilliary type used for labeling orbit types.
42 /// Structure describing a particle's "orbit type" under symmetry group actions in a system.
44 * Each particle has its orbit with respect to a symmetry group of the system in which the particle lies,
45 * i.e. a set of particles onto which the group operations map the original particle.
47 * (TODO DOC improve the following explanation:)
48 * Typically, there will be only a small number of different (T-matrix, particle
49 * <a href="https://en.wikipedia.org/wiki/Group_action#Fixed_points_and_stabilizer_subgroups">stabiliser</a>)
50 * pairs in the system. We can group the particles accordingly, into the same "orbit types"
51 * that will allow to do certain operations only once for each "orbit type", saving memory and (perhaps) time.
53 * Each particle will then have assigned:
55 * 2. an ID inside that orbit.
58 * TODO DOC how the process of assigning the particle IDs actually work, orbit type (non-)uniqueness.
61 * Memory is managed by qpms_scatspec_t; qpms_ss_orbit_type_t does not own anything.
64 typedef struct qpms_ss_orbit_type_t
{
65 qpms_ss_orbit_pi_t size
; ///< Size of the orbit (a divisor of the group order), i.e. number of particles on the orbit.
66 size_t bspecn
; ///< Individual particle's coefficient vector length. The same as ss->tm[this.tmatrices[0]]->spec->n.
67 /// Action of the group elements onto the elements in this orbit.
68 /** Its size is sym->order * this.size
69 * and its values lie between 0 and \a this.size − 1.
71 * Action of the group element g onto the pi-th particle
72 * is given by action[g + pi*sym->order].
75 qpms_ss_orbit_pi_t
*action
;
76 /// T-matrix IDs of the particles on this orbit (type).
78 * We save all the tmi's of the particles on the orbit here to make the number of array lookups
79 * and pointer dereferences constant.
81 * The size of this array is \a size.
83 qpms_ss_tmi_t
*tmatrices
;
84 /// Sizes of the per-orbit irrep bases.
86 * The order of the irreps corresponds to the order in \a ss->sym->irreps.
87 * The size of this array is (obviously) \a ss->sym->nirreps.
89 * TODO different type?
93 //The following are pretty redundant, TODO reduce them at some point.
94 /// Cumulative sums of irbase_sizes.
95 size_t *irbase_cumsizes
;
97 size_t *irbase_offsets
;
98 /// Per-orbit irreducible representation orthonormal bases.
99 /** This also defines the unitary operator that transforms the orbital excitation coefficients
100 * in the symmetry-adapted basis.
102 * The size is (\a this->size * \a this->tmatrices[0].spec->n)**2.
106 complex double *irbases
;
108 size_t instance_count
;
109 /// Cumulative sum of the preceding ot->siza * ot->instance_count;
110 qpms_ss_pi_t p_offset
;
111 } qpms_ss_orbit_type_t
;
114 typedef ptrdiff_t qpms_ss_osn_t
; ///< "serial number" of av orbit in a given type.
116 /// Auxillary type used in qpms_scatsys_t that identifies the particle's orbit and its id inside that orbit.
117 typedef struct qpms_ss_particle_orbitinfo
{
118 qpms_ss_oti_t t
; ///< Orbit type.
119 #define QPMS_SS_P_ORBITINFO_UNDEF (-1) ///< This labels that the particle has not yet been assigned to an orbit.
120 qpms_ss_osn_t osn
; ///< "Serial number" of the orbit in the given type. TODO type and more doc.
121 qpms_ss_orbit_pi_t p
; ///< Order (sija, ei rankki) of the particle inside that orbit type.
122 } qpms_ss_particle_orbitinfo_t
;
124 struct qpms_trans_calculator
;
126 typedef struct qpms_scatsys_t
{
127 qpms_qpms_epsmu_generator_t
*medium
; ///< Optical properties of the background medium.
128 qpms_abstract_tmatrix_t
**tm
; ///< T-matrices in the system
129 qpms_ss_tmi_t tm_count
; ///< Number of all different T-matrices
130 qpms_ss_tmi_t tm_capacity
; ///< Capacity of tm[].
131 qpms_particle_tid_t
*p
; ///< Particles.
132 qpms_ss_pi_t p_count
; ///< Size of particles array.
133 qpms_ss_pi_t p_capacity
; ///< Capacity of p[].
135 //TODO the index types do not need to be so big.
136 const struct qpms_finite_group_t
*sym
; ///< Symmetry group of the array
137 qpms_ss_pi_t
*p_sym_map
; ///< Which particles map onto which by the symmetry ops.
138 ///< p_sym_map[idi + pi * sym->order] gives the index of pi-th particle under the idi'th sym op.
139 qpms_ss_tmi_t
*tm_sym_map
; ///< Which t-matrices map onto which by the symmetry ops. Lookup by tm_sum_map[idi + tmi * sym->order].
141 qpms_ss_oti_t orbit_type_count
;
142 qpms_ss_orbit_type_t
*orbit_types
; ///< (Array length is \a orbit_type_count.)
144 qpms_ss_particle_orbitinfo_t
*p_orbitinfo
; ///< Orbit type identification of each particle. (Array length is \a p_count.)
146 size_t fecv_size
; ///< Number of elements of a full excitation coefficient vector size.
147 size_t *saecv_sizes
; ///< Number of elements of symmetry-adjusted coefficient vector sizes (order as in sym->irreps).
149 size_t *fecv_pstarts
; ///< Indices of where pi'th particle's excitation coeffs start in a full excitation coefficient vector.
150 size_t *saecv_ot_offsets
; ///< TODO DOC. In the packed vector, saecv_ot_offsets[iri * orbit_type_count + oti] indicates start of ot
151 /**< TODO maybe move it to qpms_ss_orbit_type_t, ffs. */
152 //size_t **saecv_pstarts; ///< NI. Indices of where pi'th particle's excitation coeff start in a symmetry-adjusted e.c.v.
153 ///**< First index is irrep index as in sym->irreps, second index is particle index. */
155 // TODO shifted origin of the symmetry group etc.
156 // TODO some indices for fast operations here.
158 size_t max_bspecn
; ///< Maximum tm[...]->spec->n. Mainly for workspace allocation.
160 /// Particles grouped by orbit (in the order corresponding to the packed memory layout).
161 qpms_ss_pi_t
*p_by_orbit
;
163 // We keep the p_orbitinfo arrays in this chunk in order to avoid memory fragmentation
166 double lenscale
; // radius of the array, used as a relative tolerance measure
167 struct qpms_trans_calculator
*c
;
171 typedef struct qpms_scatsys_at_omega_t
{
172 const qpms_scatsys_t
*ss
; ///< Parent scattering system.
173 /// T-matrices from \a ss, evaluated at \a omega.
174 /** The T-matrices are in the same order as in \a ss,
175 * i.e in the order corresponding to TODO WHAT E7ACTLY??
178 complex double omega
; ///< Angular frequency
179 complex double eps
; ///< Background medium relative electric permittivity
180 complex double mu
; ///< Background medium relative magnetic permeability
181 complex double wavenumber
; ///< Background medium wavenumber
182 complex double refractive_index
; ///< Background medium refractive index
183 } qpms_scatsys_at_omega_t
;
185 void qpms_scatsys_at_omega_free(qpms_scatsys_at_omega_t
*);
187 /// Convenience function to access pi'th particle's bspec.
188 static inline const qpms_vswf_set_spec_t
*qpms_ss_bspec_pi(const qpms_scatsys_t
*ss
, qpms_ss_pi_t pi
) {
189 return ss
->tm
[ss
->p
[pi
].tmatrix_id
]->spec
;
192 /// Creates a new scatsys by applying a symmetry group, copying particles if needed.
193 /** In fact, it copies everything except the vswf set specs, so keep them alive until scatsys is destroyed.
194 * The following fields must be filled:
200 qpms_scatsys_t
*qpms_scatsys_apply_symmetry(const qpms_scatsys_t
*orig
, const struct qpms_finite_group_t
*sym
);
201 /// Destroys the result of qpms_scatsys_apply_symmetry or qpms_scatsys_load.
202 void qpms_scatsys_free(qpms_scatsys_t
*s
);
204 /// Creates a "full" transformation matrix U that takes a full vector and projects it onto an symmetry adapted basis.
205 /** Mostly as a reference and a debugging tool, as multiplicating these big matrices would be inefficient.
207 * TODO doc about shape etc.
209 complex double *qpms_scatsys_irrep_transform_matrix(complex double *target_U
,
210 const qpms_scatsys_t
*ss
, qpms_iri_t iri
);
212 /// Projects a "big" matrix onto an irrep (slow reference implementation).
214 complex double *qpms_scatsys_irrep_pack_matrix_stupid(complex double *target_packed
,
215 const complex double *orig_full
, const qpms_scatsys_t
*ss
,
218 /// Transforms a big "packed" matrix into the full basis (slow reference implementation).
220 complex double *qpms_scatsys_irrep_unpack_matrix_stupid(complex double *target_full
,
221 const complex double *orig_packed
, const qpms_scatsys_t
*ss
,
222 qpms_iri_t iri
, bool add
);
224 /// Projects a "big" matrix onto an irrep.
226 complex double *qpms_scatsys_irrep_pack_matrix(complex double *target_packed
,
227 const complex double *orig_full
, const qpms_scatsys_t
*ss
,
230 /// Transforms a big "packed" matrix into the full basis.
232 complex double *qpms_scatsys_irrep_unpack_matrix(complex double *target_full
,
233 const complex double *orig_packed
, const qpms_scatsys_t
*ss
,
234 qpms_iri_t iri
, bool add
);
236 /// Projects a "big" vector onto an irrep.
238 complex double *qpms_scatsys_irrep_pack_vector(complex double *target_packed
,
239 const complex double *orig_full
, const qpms_scatsys_t
*ss
,
242 /// Transforms a big "packed" vector into the full basis.
244 complex double *qpms_scatsys_irrep_unpack_vector(complex double *target_full
,
245 const complex double *orig_packed
, const qpms_scatsys_t
*ss
,
246 qpms_iri_t iri
, bool add
);
248 /// Global translation matrix.
250 * The diagonal (particle self-) block are filled with zeros (even for regular Bessel waves).
251 * This may change in the future.
253 complex double *qpms_scatsys_build_translation_matrix_full(
254 /// Target memory with capacity for ss->fecv_size**2 elements. If NULL, new will be allocated.
255 complex double *target
,
256 const qpms_scatsys_t
*ss
,
257 complex double k
///< Wave number to use in the translation matrix.
260 /// As qpms_scatsys_build_translation_full() but with choice of Bessel function type.
261 /** Might be useful for evaluation of cross sections and testing.
263 complex double *qpms_scatsys_build_translation_matrix_e_full(
264 /// Target memory with capacity for ss->fecv_size**2 elements. If NULL, new will be allocated.
265 complex double *target
,
266 const qpms_scatsys_t
*ss
,
267 complex double k
, ///< Wave number to use in the translation matrix.
271 /// Global translation matrix with selectable Bessel function, projected on an irrep.
273 * The diagonal (particle self-) blocks are currently filled with zeros.
274 * This may change in the future.
276 complex double *qpms_scatsys_build_translation_matrix_e_irrep_packed(
277 /// Target memory with capacity for ss->fecv_size**2 elements. If NULL, new will be allocated.
278 complex double *target
,
279 const qpms_scatsys_t
*ss
,
281 complex double k
, ///< Wave number to use in the translation matrix.
285 /// Creates the full \f$ (I - TS) \f$ matrix of the scattering system.
286 complex double *qpms_scatsys_build_modeproblem_matrix_full(
287 /// Target memory with capacity for ss->fecv_size**2 elements. If NULL, new will be allocated.
288 complex double *target
,
289 const qpms_scatsys_t
*ss
,
290 complex double k
///< Wave number to use in the translation matrix.
292 /// Creates the mode problem matrix \f$ (I - TS) \f$ directly in the irrep-packed form.
293 complex double *qpms_scatsys_build_modeproblem_matrix_irrep_packed(
294 /// Target memory with capacity for ss->fecv_size**2 elements. If NULL, new will be allocated.
295 complex double *target
,
296 const qpms_scatsys_t
*ss
, qpms_iri_t iri
,
297 complex double k
///< Wave number to use in the translation matrix.
299 /// Alternative implementation of qpms_scatsys_build_modeproblem_matrix_irrep_packed().
300 complex double *qpms_scatsys_build_modeproblem_matrix_irrep_packed_orbitorderR(
301 /// Target memory with capacity for ss->fecv_size**2 elements. If NULL, new will be allocated.
302 complex double *target
,
303 const qpms_scatsys_t
*ss
, qpms_iri_t iri
,
304 complex double k
///< Wave number to use in the translation matrix.
306 /// Alternative (serial reference) implementation of qpms_scatsys_build_modeproblem_matrix_irrep_packed().
307 complex double *qpms_scatsys_build_modeproblem_matrix_irrep_packed_orbitorder_serial(
308 /// Target memory with capacity for ss->fecv_size**2 elements. If NULL, new will be allocated.
309 complex double *target
,
310 const qpms_scatsys_t
*ss
, qpms_iri_t iri
,
311 complex double k
///< Wave number to use in the translation matrix.
314 /// LU factorisation (LAPACKE_zgetrf) result holder.
315 typedef struct qpms_ss_LU
{
316 const qpms_scatsys_t
*ss
;
317 bool full
; ///< true if full matrix; false if irrep-packed.
318 qpms_iri_t iri
; ///< Irrep index if `full == false`.
319 /// LU decomposition array.
321 /// Pivot index array, size at least max(1,min(m, n)).
324 void qpms_ss_LU_free(qpms_ss_LU
);
326 /// Builds an LU-factorised mode/scattering problem \f$ (I - TS) \f$ matrix from scratch.
327 qpms_ss_LU
qpms_scatsys_build_modeproblem_matrix_full_LU(
328 complex double *target
, ///< Pre-allocated target array. Optional (if NULL, new one is allocated).
329 int *target_piv
, ///< Pre-allocated pivot array. Optional (if NULL, new one is allocated).
330 const qpms_scatsys_t
*ss
,
331 complex double k
///< Wave number to use in the translation matrix.
334 /// Builds an irrep-packed LU-factorised mode/scattering problem matrix from scratch.
335 qpms_ss_LU
qpms_scatsys_build_modeproblem_matrix_irrep_packed_LU(
336 complex double *target
, ///< Pre-allocated target array. Optional (if NULL, new one is allocated).
337 int *target_piv
, ///< Pre-allocated pivot array. Optional (if NULL, new one is allocated).
338 const qpms_scatsys_t
*ss
, qpms_iri_t iri
,
339 complex double k
///< Wave number to use in the translation matrix.
342 /// Computes LU factorisation of a pre-calculated mode/scattering problem matrix, replacing its contents.
343 qpms_ss_LU
qpms_scatsys_modeproblem_matrix_full_factorise(
344 complex double *modeproblem_matrix_full
, ///< Pre-calculated mode problem matrix (I-TS). Mandatory.
345 int *target_piv
, ///< Pre-allocated pivot array. Optional (if NULL, new one is allocated).
346 const qpms_scatsys_t
*ss
349 /// Computes LU factorisation of a pre-calculated irrep-packed mode/scattering problem matrix, replacing its contents.
350 qpms_ss_LU
qpms_scatsys_modeproblem_matrix_irrep_packed_factorise(
351 complex double *modeproblem_matrix_irrep_packed
, ///< Pre-calculated mode problem matrix (I-TS). Mandatory.
352 int *target_piv
, ///< Pre-allocated pivot array. Optional (if NULL, new one is allocated).
353 const qpms_scatsys_t
*ss
, qpms_iri_t iri
356 /// Solves a (possibly partial, irrep-packed) scattering problem \f$ (I-TS)f = Ta_\mathrm{inc} \f$ using a pre-factorised \f$ (I-TS) \f$.
357 complex double *qpms_scatsys_scatter_solve(
358 complex double *target_f
, ///< Target (full or irrep-packed, depending on `ludata.full`) array for \a f. If NULL, a new one is allocated.
359 const complex double *a_inc
, ///< Incident field expansion coefficient vector \a a (full or irrep-packed, depending on `ludata.full`).
360 qpms_ss_LU ludata
///< Pre-factorised \f$ I - TS \f$ matrix data.
364 /// NOT IMPLEMENTED Dumps a qpms_scatsys_t structure to a file.
365 qpms_errno_t
qpms_scatsys_dump(qpms_scatsys_t
*ss
, char *path
);
367 /// NOT IMPLEMENTED Reads a qpms_scatsys_t structure from a file.
368 qpms_scatsys_t
*qpms_scatsys_load(char *path
);
370 struct qpms_finite_group_t
;
372 /// Constructs a "full matrix action" of a point group element for an orbit type.
373 /** TODO detailed doc */
374 complex double *qpms_orbit_action_matrix(
375 /// Target array. If NULL, a new one is allocated.
376 /** The size of the array is (orbit->size * bspec->n)**2
377 * (it makes sense to assume all the T-matrices share their spec).
379 complex double *target
,
380 /// The orbit (type).
381 const qpms_ss_orbit_type_t
*orbit
,
382 /// Base spec of the t-matrices (we don't know it from orbit, as it has
383 /// only T-matrix indices.
384 const qpms_vswf_set_spec_t
*bspec
,
385 /// The symmetry group used to generate the orbit (must have rep3d filled).
386 const struct qpms_finite_group_t
*sym
,
387 /// The index of the operation in sym to represent.
390 /// Constructs a dense matrix representation of a irrep projector for an orbit type.
391 /** TODO detailed doc */
392 complex double *qpms_orbit_irrep_projector_matrix(
393 /// Target array. If NULL, a new one is allocated.
394 /** The size of the array is (orbit->size * bspec->n)**2
395 * (it makes sense to assume all the T-matrices share their spec).
397 complex double *target
,
398 /// The orbit (type).
399 const qpms_ss_orbit_type_t
*orbit
,
400 /// Base spec of the t-matrices (we don't know it from orbit, as it has
401 /// only T-matrix indices.
402 const qpms_vswf_set_spec_t
*bspec
,
403 /// The symmetry group used to generate the orbit (must have rep3d filled).
404 const struct qpms_finite_group_t
*sym
,
405 /// The index of the irreducible representation of sym.
406 const qpms_iri_t iri
);
409 complex double *qpms_orbit_irrep_basis(
410 /// Here theh size of theh basis shall be saved,
412 /// Target array. If NULL, a new one is allocated.
413 /** The size of the array is basis_size * (orbit->size * bspec->n)
414 * (it makes sense to assume all the T-matrices share their spec).
416 complex double *target
,
417 /// The orbit (type).
418 const qpms_ss_orbit_type_t
*orbit
,
419 /// Base spec of the t-matrices (we don't know it from orbit, as it has
420 /// only T-matrix indices.
421 const qpms_vswf_set_spec_t
*bspec
,
422 /// The symmetry group used to generate the orbit (must have rep3d filled).
423 const struct qpms_finite_group_t
*sym
,
424 /// The index of the irreducible representation of sym.
425 const qpms_iri_t iri
);
428 /// Creates an incident field vector in the full basis, given a function that evaluates the field expansions at points.
429 /** TODO detailed doc!
430 * \returns target_full if target_full was not NULL, otherwise the newly allocated array. */
431 complex double *qpms_scatsys_incident_field_vector_full(
432 /// Target array. If NULL, a new one is allocated.
433 /** The length of the array is ss->fecv_size. */
434 complex double *target_full
,
435 const qpms_scatsys_t
*ss
,
436 qpms_incfield_t field_at_point
,
437 const void *args
, ///< Pointer passed as the last argument to (*field_at_point)()
438 bool add
///< If true, add to target_full; rewrite target_full if false.
441 /// Applies T-matrices onto an incident field vector in the full basis.
442 complex double *qpms_scatsys_apply_Tmatrices_full(
443 complex double *target_full
, /// Target vector array. If NULL, a new one is allocated.
444 const complex double *inc_full
, /// Incident field coefficient vector. Must not be NULL.
445 const qpms_scatsys_t
*ss
450 /// Creates a (partial) incident field vector in the symmetry-adapted basis, given a function that evaluates the field expansions at points.
451 /** TODO detailed doc! */
452 complex double *qpms_scatsys_incident_field_vector_irrep_packed(
453 /// Target array. If NULL, a new one is allocated.
454 /** The length of the array is ss->fecv_size. */
455 complex double *target_full
,
456 const qpms_scatsys_t
*ss
,
457 const qpms_iri_t iri
, ///< The index of given irreducible representation of ss->sym.
458 qpms_incfield_t field_at_point
,
459 const void *args
, ///< Pointer passed as the last argument to (*field_at_point)()
460 bool add
///< If true, add to target_full; rewrite target_full if false.
464 /// Evaluates scattered fields (corresponding to a given excitation vector) at a given point.
466 * By scattered field, one assumes a linear combination of positive-Hankel-type
469 * \return Complex electric field at the point defined by \a where.
471 ccart3_t
qpms_scatsys_eval_E(const qpms_scatsys_t
*ss
,
472 const complex double *coeff_vector
, ///< A full-length excitation vector (outgoing wave coefficients).
473 cart3_t where
, ///< Evaluation point.
474 complex double k
///< Wave number.
479 /** Evaluates partial scattered fields (corresponding to a given irrep-reduced excitation vector)
482 * \return Complex electric field at the point defined by \a where.
484 ccart3_t
qpms_scatsys_eval_E_irrep(const qpms_scatsys_t
*ss
,
485 qpms_iri_t iri
, ///< Irreducible representation
486 const complex double *coeff_vector
, ///< A reduced excitation vector, corresponding to \a iri.
487 cart3_t where
, ///< Evaluation point.
488 complex double k
///< Wave number.
492 #endif //QPMS_SCATSYSTEM_H