diff --git a/qpms/qpms_c.pyx b/qpms/qpms_c.pyx index e62f859..09032a6 100644 --- a/qpms/qpms_c.pyx +++ b/qpms/qpms_c.pyx @@ -1427,7 +1427,6 @@ cdef class ScatteringSystem: self.s, iri, 0) return target_np def pack_matrix(self, fullmatrix, iri): - (iri < self.nirreps) cdef size_t flen = self.s[0].fecv_size cdef size_t rlen = self.saecv_sizes[iri] fullmatrix = np.array(fullmatrix, dtype=complex, copy=False, order='C') @@ -1442,7 +1441,6 @@ cdef class ScatteringSystem: self.s, iri) return target_np def unpack_matrix(self, packedmatrix, iri): - (iri < self.nirreps) cdef size_t flen = self.s[0].fecv_size cdef size_t rlen = self.saecv_sizes[iri] packedmatrix = np.array(packedmatrix, dtype=complex, copy=False, order='C') @@ -1457,7 +1455,13 @@ cdef class ScatteringSystem: self.s, iri, 0) return target_np - + def modeproblem_matrix_full(self, double k): + cdef size_t flen = self.s[0].fecv_size + cdef np.ndarray[np.complex_t, ndim=2] target = np.empty( + (flen,flen),dtype=complex, order='C') + cdef cdouble[:,::1] target_view = target + qpms_scatsys_build_modeproblem_matrix_full(&target_view[0][0], self.s, k) + return target def tlm2uvswfi(t, l, m): diff --git a/qpms/qpms_cdefs.pxd b/qpms/qpms_cdefs.pxd index 0d943f8..a9691ed 100644 --- a/qpms/qpms_cdefs.pxd +++ b/qpms/qpms_cdefs.pxd @@ -285,6 +285,10 @@ cdef extern from "scatsystem.h": const cdouble *orig_full, const qpms_scatsys_t *ss, qpms_iri_t iri) cdouble *qpms_scatsys_irrep_unpack_vector(cdouble *target_full, const cdouble *orig_packed, const qpms_scatsys_t *ss, qpms_iri_t iri, bint add) + cdouble *qpms_scatsys_build_modeproblem_matrix_full(cdouble *target, + const qpms_scatsys_t *ss, double k) + cdouble *qpms_scatsys_build_modeproblem_matrix_irrep_packed(cdouble *target, + const qpms_scatsys_t *ss, qpms_iri_t iri, double k) diff --git a/qpms/qpms_error.h b/qpms/qpms_error.h index 70aa7f9..48111d1 100644 --- a/qpms/qpms_error.h +++ b/qpms/qpms_error.h @@ -19,4 +19,10 @@ void qpms_pr_debug_at_flf(const char *filename, unsigned int linenum, //void qpms_error_at_line(const char *filename, unsigned int linenum, // const char *fmt, ...); +#define QPMS_CRASHING_MALLOC(pointer, size) {(pointer) = malloc(size); if(!pointer) qpms_pr_debug_at_flf(__FILE__,__LINE__,__func__, "Allocation of %zd bytes for " #pointer " failed.", (size_t) (size));} + +#define QPMS_WTF qpms_pr_error_at_flf(__FILE__,__LINE__,__func__,"Unexpected error.") + +#define QPMS_ENSURE_SUCCESS(x) {if(x) QPMS_WTF;} + #endif diff --git a/qpms/scatsystem.c b/qpms/scatsystem.c index 763fef9..0a38109 100644 --- a/qpms/scatsystem.c +++ b/qpms/scatsystem.c @@ -13,6 +13,7 @@ #include "wigner.h" #include #include "qpms_error.h" +#include "translations.h" #define SQ(x) ((x)*(x)) #define QPMS_SCATSYS_LEN_RTOL 1e-13 @@ -413,6 +414,9 @@ static void add_orbit_type(qpms_scatsys_t *ss, const qpms_ss_orbit_type_t *ot_cu qpms_scatsys_t *qpms_scatsys_apply_symmetry(const qpms_scatsys_t *orig, const qpms_finite_group_t *sym) { // TODO check data sanity + qpms_l_t lMax = 0; // the overall lMax of all base specs. + qpms_normalisation_t normalisation = QPMS_NORMALISATION_UNDEF; + // First, determine the rough radius of the array double lenscale = 0; { @@ -468,6 +472,11 @@ qpms_scatsys_t *qpms_scatsys_apply_symmetry(const qpms_scatsys_t *orig, const qp } tm_dupl_remap[i] = j; ss->max_bspecn = MAX(ss->tm[i]->spec->n, ss->max_bspecn); + if (normalisation == QPMS_NORMALISATION_UNDEF) + normalisation = ss->tm[i]->spec->norm; + // We expect all bspec norms to be the same. + else assert(normalisation == ss->tm[i]->spec->norm); + lMax = MAX(lMax, ss->tm[i]->spec->lMax); } // Copy particles, remapping the t-matrix indices @@ -630,7 +639,8 @@ qpms_scatsys_t *qpms_scatsys_apply_symmetry(const qpms_scatsys_t *orig, const qp ss->saecv_sizes[iri] += ot->instance_count * ot->irbase_sizes[iri]; } } - + + ss->c = qpms_trans_calculator_init(lMax, normalisation); return ss; } @@ -646,6 +656,7 @@ void qpms_scatsys_free(qpms_scatsys_t *ss) { free(ss->p_orbitinfo); free(ss->orbit_types); free(ss->saecv_sizes); + qpms_trans_calculator_free(ss->c); } free(ss); } @@ -796,7 +807,7 @@ complex double *qpms_scatsys_irrep_pack_matrix(complex double *target_packed, // Workspace for the intermediate particle-orbit matrix result complex double *tmp = malloc(sizeof(complex double) * SQ(ss->max_bspecn) - * ss->sym->order); if (!tmp) abort; + * ss->sym->order); if (!tmp) abort(); const complex double one = 1, zero = 0; @@ -875,7 +886,7 @@ complex double *qpms_scatsys_irrep_unpack_matrix(complex double *target_full, // Workspace for the intermediate particle-orbit matrix result complex double *tmp = malloc(sizeof(complex double) * SQ(ss->max_bspecn) - * ss->sym->order); if (!tmp) abort; + * ss->sym->order); if (!tmp) abort(); const complex double one = 1, zero = 0; @@ -1021,4 +1032,61 @@ complex double *qpms_scatsys_irrep_unpack_vector(complex double *target_full, return target_full; } +complex double *qpms_scatsys_build_modeproblem_matrix_full( + /// Target memory with capacity for ss->fecv_size**2 elements. If NULL, new will be allocated. + complex double *target, + const qpms_scatsys_t *ss, + double k ///< Wave number to use in the translation matrix. + ) +{ + const size_t full_len = ss->fecv_size; + if(!target) + QPMS_CRASHING_MALLOC(target, SQ(full_len) * sizeof(complex double)); + complex double *tmp; + QPMS_CRASHING_MALLOC(tmp, SQ(ss->max_bspecn) * sizeof(complex double)); + memset(target, 0, SQ(full_len) * sizeof(complex double)); //unnecessary? + complex double one = 1, zero = 0; + { // Non-diagonal part; M[piR, piC] = T[piR] S(piR<-piC) + size_t fullvec_offsetR = 0; + for(qpms_ss_pi_t piR = 0; piR < ss->p_count; ++piR) { + const qpms_vswf_set_spec_t *bspecR = ss->tm[ss->p[piR].tmatrix_id]->spec; + const cart3_t posR = ss->p[piR].pos; + size_t fullvec_offsetC = 0; + // dest particle T-matrix + const complex double *tmmR = ss->tm[ss->p[piR].tmatrix_id]->m; + for(qpms_ss_pi_t piC = 0; piC < ss->p_count; ++piC) { + if(piC == piR) continue; // The diagonal will be dealt with later. + const qpms_vswf_set_spec_t *bspecC = ss->tm[ss->p[piC].tmatrix_id]->spec; + const cart3_t posC = ss->p[piC].pos; + QPMS_ENSURE_SUCCESS(qpms_trans_calculator_get_trans_array_lc3p(ss->c, + tmp, // tmp is S(piR<-piC) + bspecR, bspecC->n, bspecC, 1, + k, posR, posC)); + cblas_zgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, + bspecR->n /*m*/, bspecC->n /*n*/, bspecR->n /*k*/, + &one/*alpha*/, tmmR/*a*/, bspecR->n/*lda*/, + tmp/*b*/, bspecC->n/*ldb*/, &zero/*beta*/, + target + fullvec_offsetR*full_len + fullvec_offsetC /*c*/, + full_len /*ldc*/); + fullvec_offsetC += bspecC->n; + } + fullvec_offsetR += bspecR->n; + } + } + // diagonal part M[pi,pi] = -1 + for (size_t i = 0; i < full_len; ++i) target[full_len * i + i] = -1; + + free(tmp); + return target; +} + + + + +complex double *qpms_scatsys_build_modeproblem_matrix_irrep_packed( + /// Target memory with capacity for ss->saecv_sizes[iri]**2 elements. If NULL, new will be allocated. + complex double *target, + const qpms_scatsys_t *ss, qpms_iri_t iri, + double k ///< Wave number to use in the translation matrix. + ); diff --git a/qpms/scatsystem.h b/qpms/scatsystem.h index 445dab8..31a0e37 100644 --- a/qpms/scatsystem.h +++ b/qpms/scatsystem.h @@ -370,6 +370,7 @@ typedef struct qpms_ss_particle_orbitinfo { qpms_ss_orbit_pi_t p; ///< Order (sija, ei rankki) of the particle inside that orbit type. } qpms_ss_particle_orbitinfo_t; +struct qpms_trans_calculator; typedef struct qpms_scatsys_t { // TODO does bspec belong here? @@ -410,6 +411,7 @@ typedef struct qpms_scatsys_t { char *otspace; char *otspace_end; double lenscale; // radius of the array, used as a relative tolerance measure + struct qpms_trans_calculator *c; } qpms_scatsys_t; /// Creates a new scatsys by applying a symmetry group, copying particles if needed. @@ -448,6 +450,19 @@ complex double *qpms_scatsys_irrep_unpack_vector(complex double *target_full, const complex double *orig_packed, const qpms_scatsys_t *ss, qpms_iri_t iri, bool add); +complex double *qpms_scatsys_build_modeproblem_matrix_full( + /// Target memory with capacity for ss->fecv_size**2 elements. If NULL, new will be allocated. + complex double *target, + const qpms_scatsys_t *ss, + double k ///< Wave number to use in the translation matrix. + ); +complex double *qpms_scatsys_build_modeproblem_irrep_packed( + /// Target memory with capacity for ss->fecv_size**2 elements. If NULL, new will be allocated. + complex double *target, + const qpms_scatsys_t *ss, qpms_iri_t iri, + double k ///< Wave number to use in the translation matrix. + ); + /// NOT IMPLEMENTED Dumps a qpms_scatsys_t structure to a file. qpms_errno_t qpms_scatsys_dump(qpms_scatsys_t *ss, char *path); @@ -512,6 +527,7 @@ complex double *qpms_orbit_irrep_basis( const qpms_iri_t iri); + #if 0 // Abstract types that describe T-matrix/particle/scatsystem symmetries // To be implemented later. See also the thoughts in the beginning of groups.h. diff --git a/qpms/translations.c b/qpms/translations.c index 04b2da5..dc9c60d 100644 --- a/qpms/translations.c +++ b/qpms/translations.c @@ -1185,7 +1185,7 @@ qpms_errno_t qpms_trans_calculator_get_trans_array(const qpms_trans_calculator * = (srct == destt) ? A[desty][srcy] : B[desty][srcy]; } } - return QPMS_SUCCESS; + return retval; } /// Version with \a k and cartesian particle positions diff --git a/tests/scatsys.py b/tests/scatsys.py index e79bd2f..7206cd2 100644 --- a/tests/scatsys.py +++ b/tests/scatsys.py @@ -19,7 +19,7 @@ packedvectors = [(iri, ss.pack_vector(fullvector, iri)) for iri in range(ss.nirr unpackedvectors = np.array([ss.unpack_vector(v[1], v[0]) for v in packedvectors]) rec_fullvector = np.sum(unpackedvectors, axis=0) thediff = np.amax(abs(rec_fullvector-fullvector)) -assert(thediff < 1e-14) +assert(thediff < 1e-8) packedmatrices = list() for iri in range(ss.nirreps): @@ -35,4 +35,11 @@ for iri, m in packedmatrices: print (m.shape) repackedmatrix = ss.pack_matrix(fullmatrix,iri) print(np.amax(abs(repackedmatrix-m))) - + +k = 1.7 +modematrix_full = ss.modeproblem_matrix_full(k) +modematrix_packed_list = [(iri, ss.pack_matrix(modematrix_full,iri)) for iri in range(ss.nirreps)] +modematrix_full_rec = np.empty((ss.fecv_size, ss.fecv_size), dtype=complex) +for iri, m in modematrix_packed_list: + modematrix_full_rec += ss.unpack_matrix(m,iri) +print(np.amax(abs(modematrix_full-modematrix_full_rec)))