2019-02-19 22:56:53 +02:00
|
|
|
/*! \file vswf.h
|
|
|
|
* \brief Vector spherical wavefunctions.
|
|
|
|
*
|
|
|
|
* N.B. for the Legendre polynomial norm definitions, see
|
|
|
|
* <a href="https://www.gnu.org/software/gsl/doc/html/specfunc.html#associated-legendre-polynomials-and-spherical-harmonics">the corresponding section of GSL docs</a>
|
|
|
|
* or <a href="http://git.savannah.gnu.org/cgit/gsl.git/tree/specfunc/legendre_source.c">gsl/specfunc/legendre_source.c</a>.
|
|
|
|
*/
|
2017-12-17 18:44:45 +02:00
|
|
|
#ifndef QPMS_VSWF_H
|
|
|
|
#define QPMS_VSWF_H
|
2019-03-05 18:11:15 +02:00
|
|
|
#include <unistd.h> // ssize_t
|
2017-12-17 18:44:45 +02:00
|
|
|
#include "qpms_types.h"
|
2017-12-18 03:04:12 +02:00
|
|
|
#include <gsl/gsl_sf_legendre.h>
|
2017-12-17 18:44:45 +02:00
|
|
|
|
2019-02-25 18:54:59 +02:00
|
|
|
// Methods for qpms_vswf_spec_t
|
2019-02-19 22:56:53 +02:00
|
|
|
/// Creates a qpms_vswf_set_spec_t structure with an empty list of wave indices.
|
2019-03-03 02:30:12 +02:00
|
|
|
qpms_vswf_set_spec_t *qpms_vswf_set_spec_init(void);
|
2019-02-19 22:56:53 +02:00
|
|
|
/// Appends a VSWF index to a \ref qpms_vswf_set_spec_t, also updating metadata.
|
|
|
|
qpms_errno_t qpms_vswf_set_spec_append(qpms_vswf_set_spec_t *self, qpms_uvswfi_t u);
|
|
|
|
/// Destroys a \ref qpms_vswf_set_spec_t.
|
|
|
|
void qpms_vswf_set_spec_free(qpms_vswf_set_spec_t *);
|
2019-02-21 11:40:30 +02:00
|
|
|
/// Compares two vswf basis specs.
|
|
|
|
/**
|
|
|
|
* Checks whether ilist is the same and of the same length.
|
|
|
|
* If yes, returns true, else returns false.
|
|
|
|
*/
|
|
|
|
bool qpms_vswf_set_spec_isidentical(const qpms_vswf_set_spec_t *a,
|
|
|
|
const qpms_vswf_set_spec_t *b);
|
2019-02-21 13:04:59 +02:00
|
|
|
/// Copies an instance of qpms_vswf_set_spec_t
|
|
|
|
qpms_vswf_set_spec_t *qpms_vswf_set_spec_copy(const qpms_vswf_set_spec_t *orig);
|
2019-03-09 02:33:19 +02:00
|
|
|
/// Creates an instance of qpms_vswf_set_spec_t in the 'traditional' layout.
|
|
|
|
qpms_vswf_set_spec_t *qpms_vswf_set_spec_from_lMax(qpms_l_t lMax,
|
|
|
|
qpms_normalisation_t norm);
|
2019-02-19 22:56:53 +02:00
|
|
|
|
2019-03-05 18:11:15 +02:00
|
|
|
/// Finds the position of a given index in the bspec's ilist.
|
|
|
|
/** If not found, returns -1. */
|
|
|
|
// TODO more consistency in types (here size_t vs. ptrdiff_t).
|
|
|
|
static inline ssize_t qpms_vswf_set_spec_find_uvswfi(const qpms_vswf_set_spec_t *bspec,
|
|
|
|
const qpms_uvswfi_t index) {
|
|
|
|
for(size_t i = 0; i < bspec->n; ++i)
|
|
|
|
if (bspec->ilist[i] == index)
|
|
|
|
return i;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2019-06-24 17:19:25 +03:00
|
|
|
/// Evaluates a set of VSWF basis functions at a given point.
|
2019-02-19 23:35:46 +02:00
|
|
|
/** The list of basis wave indices is specified in \a setspec;
|
|
|
|
* \a setspec->norm must be set as well.
|
|
|
|
*/
|
|
|
|
qpms_errno_t qpms_uvswf_fill(
|
2019-06-24 17:19:25 +03:00
|
|
|
csphvec_t *const target, ///< Target array of size at least setspec->n.
|
2019-02-19 23:35:46 +02:00
|
|
|
const qpms_vswf_set_spec_t *setspec,
|
2019-06-24 17:19:25 +03:00
|
|
|
csph_t kr, ///< Evaluation point.
|
|
|
|
qpms_bessel_t btyp);
|
2019-02-19 23:35:46 +02:00
|
|
|
|
2019-06-23 22:04:00 +03:00
|
|
|
/// Evaluates field specified by SVWF coefficients at a given point.
|
|
|
|
/** SVWF coefficients in \a coeffs must be ordered according to \a setspec->ilist.
|
2019-02-19 23:35:46 +02:00
|
|
|
*/
|
|
|
|
csphvec_t qpms_eval_uvswf(const qpms_vswf_set_spec_t *setspec,
|
2019-06-24 17:19:25 +03:00
|
|
|
const complex double *coeffs, ///< SVWF coefficient vector of size setspec->n.
|
|
|
|
csph_t kr, ///< Evaluation point.
|
2019-02-19 23:35:46 +02:00
|
|
|
qpms_bessel_t btyp);
|
|
|
|
|
2019-02-19 22:56:53 +02:00
|
|
|
/// Electric wave N.
|
2018-01-26 15:07:29 +02:00
|
|
|
csphvec_t qpms_vswf_single_el(int m, int n, sph_t kdlj,
|
2018-05-06 22:13:10 +03:00
|
|
|
qpms_bessel_t btyp, qpms_normalisation_t norm);
|
2019-02-19 22:56:53 +02:00
|
|
|
/// Magnetic wave M.
|
2018-01-26 15:07:29 +02:00
|
|
|
csphvec_t qpms_vswf_single_mg(int m, int n, sph_t kdlj,
|
2018-05-06 22:13:10 +03:00
|
|
|
qpms_bessel_t btyp, qpms_normalisation_t norm);
|
2017-12-17 19:07:19 +02:00
|
|
|
|
2019-02-19 22:56:53 +02:00
|
|
|
/// Set of electric and magnetic VSWF values in spherical coordinate basis.
|
2019-02-19 23:35:46 +02:00
|
|
|
/** This is supposed to contain all the waves up to $l = lMax$.
|
|
|
|
*
|
|
|
|
* For a completely custom set of waves, use \ref qpms_uvswfset_sph_t instead.
|
2019-02-19 22:56:53 +02:00
|
|
|
*/
|
|
|
|
typedef struct qpms_vswfset_sph_t {
|
2017-12-17 19:07:19 +02:00
|
|
|
//qpms_normalisation_t norm;
|
|
|
|
qpms_l_t lMax;
|
|
|
|
//qpms_y_t nelem;
|
|
|
|
//sph_t kdlj
|
|
|
|
csphvec_t *el, *mg;
|
|
|
|
} qpms_vswfset_sph_t;
|
|
|
|
|
2018-01-28 11:18:06 +02:00
|
|
|
qpms_errno_t qpms_legendre_deriv_y_get(double **result, double **result_deriv, double x, qpms_l_t lMax,
|
|
|
|
gsl_sf_legendre_t lnorm, double csphase); // free() result and result_deriv yourself!
|
|
|
|
qpms_errno_t qpms_legendre_deriv_y_fill(double *where, double *where_deriv, double x,
|
2018-01-26 15:07:29 +02:00
|
|
|
qpms_l_t lMax, gsl_sf_legendre_t lnorm, double csphase);
|
2017-12-18 03:04:12 +02:00
|
|
|
|
2019-06-23 22:04:00 +03:00
|
|
|
|
|
|
|
/// Evaluate the zeroth-degree longitudinal VSWF \f$ \mathbf{L}_0^0 \f$.
|
|
|
|
csphvec_t qpms_vswf_L00(
|
2019-06-24 17:19:25 +03:00
|
|
|
csph_t kdrj, //< VSWF evaluation point.
|
2019-06-23 22:04:00 +03:00
|
|
|
qpms_bessel_t btyp,
|
|
|
|
qpms_normalisation_t norm);
|
|
|
|
|
|
|
|
/// Evaluate VSWFs at a given point from \a l = 1 up to a given degree \a lMax.
|
|
|
|
/**
|
|
|
|
* The target arrays \a resultL, \a resultM, \a resultN have to be large enough to contain
|
|
|
|
* \a lMax * (\a lMax + 2) elements. If NULL is passed instead, the corresponding SVWF type
|
|
|
|
* is not evaluated.
|
|
|
|
*
|
|
|
|
* Does not evaluate the zeroth-order wave \f$ \mathbf{L}_0^0 \f$.
|
|
|
|
* If you need that, use qpms_vswf_L00().
|
|
|
|
*/
|
|
|
|
qpms_errno_t qpms_vswf_fill(
|
|
|
|
csphvec_t *resultL, //< Target array for longitudinal VSWFs.
|
|
|
|
csphvec_t *resultM, //< Target array for magnetic VSWFs.
|
|
|
|
csphvec_t *resultN, //< Target array for electric VSWFs.
|
|
|
|
qpms_l_t lMax, //< Maximum multipole degree to be calculated.
|
|
|
|
sph_t kdrj, //< VSWF evaluation point.
|
|
|
|
qpms_bessel_t btyp, qpms_normalisation_t norm);
|
2019-06-24 17:19:25 +03:00
|
|
|
|
2018-02-01 06:40:45 +02:00
|
|
|
// Should give the same results: for consistency checks
|
|
|
|
qpms_errno_t qpms_vswf_fill_alternative(csphvec_t *resultL, csphvec_t *resultM, csphvec_t *resultN, qpms_l_t lMax, sph_t kdrj,
|
|
|
|
qpms_bessel_t btyp, qpms_normalisation_t norm);
|
|
|
|
|
2019-06-24 17:19:25 +03:00
|
|
|
/// Evaluate VSWFs at a given point from \a l = 1 up to a given degree \a lMax (complex \a kr version).
|
|
|
|
/**
|
|
|
|
* The target arrays \a resultL, \a resultM, \a resultN have to be large enough to contain
|
|
|
|
* \a lMax * (\a lMax + 2) elements. If NULL is passed instead, the corresponding SVWF type
|
|
|
|
* is not evaluated.
|
|
|
|
*
|
|
|
|
* Does not evaluate the zeroth-order wave \f$ \mathbf{L}_0^0 \f$.
|
|
|
|
* If you need that, use qpms_vswf_L00().
|
|
|
|
*/
|
|
|
|
qpms_errno_t qpms_vswf_fill_csph(
|
|
|
|
csphvec_t *resultL, //< Target array for longitudinal VSWFs.
|
|
|
|
csphvec_t *resultM, //< Target array for magnetic VSWFs.
|
|
|
|
csphvec_t *resultN, //< Target array for electric VSWFs.
|
|
|
|
qpms_l_t lMax, //< Maximum multipole degree to be calculated.
|
|
|
|
csph_t kdrj, //< VSWF evaluation point.
|
|
|
|
qpms_bessel_t btyp, qpms_normalisation_t norm);
|
|
|
|
|
2018-02-01 06:40:45 +02:00
|
|
|
qpms_errno_t qpms_vecspharm_fill(csphvec_t *const a1target, csphvec_t *const a2target, csphvec_t *const a3target,
|
2018-05-06 22:13:10 +03:00
|
|
|
qpms_l_t lMax, sph_t dir, qpms_normalisation_t norm);
|
2018-02-01 06:40:45 +02:00
|
|
|
qpms_errno_t qpms_vecspharm_dual_fill(csphvec_t *const a1target, csphvec_t *const a2target, csphvec_t *const a3target,
|
2018-05-06 22:13:10 +03:00
|
|
|
qpms_l_t lMax, sph_t dir, qpms_normalisation_t norm);
|
2018-02-01 06:40:45 +02:00
|
|
|
|
2018-02-01 17:04:51 +02:00
|
|
|
qpms_errno_t qpms_planewave2vswf_fill_cart(cart3_t wavedir, ccart3_t amplitude,
|
2018-02-01 06:40:45 +02:00
|
|
|
complex double *targt_longcoeff, complex double *target_mgcoeff, complex double *target_elcoeff,
|
2018-02-01 17:04:51 +02:00
|
|
|
qpms_l_t lMax, qpms_normalisation_t norm);
|
|
|
|
qpms_errno_t qpms_planewave2vswf_fill_sph(sph_t wavedir, csphvec_t amplitude,
|
2018-02-01 06:40:45 +02:00
|
|
|
complex double *targt_longcoeff, complex double *target_mgcoeff, complex double *target_elcoeff,
|
2018-02-01 17:04:51 +02:00
|
|
|
qpms_l_t lMax, qpms_normalisation_t norm);
|
2018-02-01 06:40:45 +02:00
|
|
|
|
|
|
|
|
2018-02-01 17:04:51 +02:00
|
|
|
csphvec_t qpms_eval_vswf(sph_t where,
|
|
|
|
complex double *longcoeffs, complex double *mgcoeffs, complex double *elcoeffs,
|
|
|
|
qpms_l_t lMax, qpms_bessel_t btyp, qpms_normalisation_t norm);
|
2018-02-01 06:40:45 +02:00
|
|
|
|
2019-06-24 17:19:25 +03:00
|
|
|
csphvec_t qpms_eval_vswf_csph(csph_t where,
|
|
|
|
complex double *longcoeffs, complex double *mgcoeffs, complex double *elcoeffs,
|
|
|
|
qpms_l_t lMax, qpms_bessel_t btyp, qpms_normalisation_t norm);
|
2018-01-30 01:09:48 +02:00
|
|
|
|
2017-12-17 19:07:19 +02:00
|
|
|
qpms_vswfset_sph_t *qpms_vswfset_make(qpms_l_t lMax, sph_t kdlj,
|
2018-05-06 22:13:10 +03:00
|
|
|
qpms_bessel_t btyp, qpms_normalisation_t norm);//NI
|
2018-01-28 11:18:06 +02:00
|
|
|
void qpms_vswfset_sph_pfree(qpms_vswfset_sph_t *);//NI
|
2017-12-17 19:07:19 +02:00
|
|
|
|
2017-12-17 18:44:45 +02:00
|
|
|
#endif // QPMS_VSWF_H
|