📄 maxwell_op.c
字号:
/* Copyright (C) 1999, 2000, 2001, 2002, Massachusetts Institute of Technology. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include <stdlib.h>#include <stdio.h>#include <math.h>#include "../config.h"#include <check.h>#include "maxwell.h"/**************************************************************************//* assign a = v going from transverse to cartesian coordinates. Here, a = (a[0],a[1],a[2]) is in cartesian coordinates. (v[0],v[vstride]) is in the transverse basis of k.m and k.n. */static void assign_t2c(scalar *a, const k_data k, const scalar *v, int vstride){ scalar v0 = v[0], v1 = v[vstride]; ASSIGN_SCALAR(a[0], SCALAR_RE(v0)*k.mx + SCALAR_RE(v1)*k.nx, SCALAR_IM(v0)*k.mx + SCALAR_IM(v1)*k.nx); ASSIGN_SCALAR(a[1], SCALAR_RE(v0)*k.my + SCALAR_RE(v1)*k.ny, SCALAR_IM(v0)*k.my + SCALAR_IM(v1)*k.ny); ASSIGN_SCALAR(a[2], SCALAR_RE(v0)*k.mz + SCALAR_RE(v1)*k.nz, SCALAR_IM(v0)*k.mz + SCALAR_IM(v1)*k.nz);}/* assign a = k x v (cross product), going from transverse to cartesian coordinates. Here, a = (a[0],a[1],a[2]) and k = (k.kx,k.ky,k.kz) are in cartesian coordinates. (v[0],v[vstride]) is in the transverse basis of k.m and k.n. */static void assign_cross_t2c(scalar *a, const k_data k, const scalar *v, int vstride){ scalar v0 = v[0], v1 = v[vstride]; /* Note that k x m = |k| n, k x n = - |k| m. Therefore, k x v = k x (v0 m + v1 n) = (v0 n - v1 m) * |k|. */ ASSIGN_SCALAR(a[0], (SCALAR_RE(v0)*k.nx - SCALAR_RE(v1)*k.mx) * k.kmag, (SCALAR_IM(v0)*k.nx - SCALAR_IM(v1)*k.mx) * k.kmag); ASSIGN_SCALAR(a[1], (SCALAR_RE(v0)*k.ny - SCALAR_RE(v1)*k.my) * k.kmag, (SCALAR_IM(v0)*k.ny - SCALAR_IM(v1)*k.my) * k.kmag); ASSIGN_SCALAR(a[2], (SCALAR_RE(v0)*k.nz - SCALAR_RE(v1)*k.mz) * k.kmag, (SCALAR_IM(v0)*k.nz - SCALAR_IM(v1)*k.mz) * k.kmag);#ifdef DEBUG { real num; num = SCALAR_NORMSQR(a[0])+SCALAR_NORMSQR(a[1])+SCALAR_NORMSQR(a[2]); CHECK(!BADNUM(num), "yikes, crazy number!"); }#endif}/* assign v = scale * k x a (cross product), going from cartesian to transverse coordinates. Here, a = (a[0],a[1],a[2]) and k = (k.kx,k.ky,k.kz) are in cartesian coordinates. (v[0],v[vstride]) is in the transverse basis of k.m and k.n. */static void assign_cross_c2t(scalar *v, int vstride, const k_data k, const scalar *a, real scale){ scalar a0 = a[0], a1 = a[1], a2 = a[2]; scalar at0, at1; /* First, compute at0 = a*m and at1 = a*n. (Components of a that are parallel to k are killed anyway by the cross product.) */ ASSIGN_SCALAR(at0, SCALAR_RE(a0)*k.mx + SCALAR_RE(a1)*k.my + SCALAR_RE(a2)*k.mz, SCALAR_IM(a0)*k.mx + SCALAR_IM(a1)*k.my + SCALAR_IM(a2)*k.mz); ASSIGN_SCALAR(at1, SCALAR_RE(a0)*k.nx + SCALAR_RE(a1)*k.ny + SCALAR_RE(a2)*k.nz, SCALAR_IM(a0)*k.nx + SCALAR_IM(a1)*k.ny + SCALAR_IM(a2)*k.nz); /* Now, k x a = k x (at0*m + at1*n) = (at0*n - at1*m) * |k|. */ scale *= k.kmag; /* combine scale factor and |k|*/ ASSIGN_SCALAR(v[0], - scale * SCALAR_RE(at1), - scale * SCALAR_IM(at1)); ASSIGN_SCALAR(v[vstride], scale * SCALAR_RE(at0), scale * SCALAR_IM(at0));#ifdef DEBUG { real dummy = SCALAR_NORMSQR(v[0]) + SCALAR_NORMSQR(v[vstride]); CHECK(!BADNUM(dummy), "yikes, crazy number!"); }#endif}/* compute a = u x v, where a and u are in cartesian coordinates and v is in transverse coordinates. */static void assign_ucross_t2c(scalar *a, const real u[3], const k_data k, const scalar *v, int vstride){ scalar v0 = v[0], v1 = v[vstride]; real vx_r, vy_r, vz_r;#ifdef SCALAR_COMPLEX real vx_i, vy_i, vz_i;#endif /* Note that v = (vx,vy,vz) = (v0 m + v1 n). */ vx_r = SCALAR_RE(v0)*k.mx + SCALAR_RE(v1)*k.nx; vy_r = SCALAR_RE(v0)*k.my + SCALAR_RE(v1)*k.ny; vz_r = SCALAR_RE(v0)*k.mz + SCALAR_RE(v1)*k.nz;#ifdef SCALAR_COMPLEX vx_i = SCALAR_IM(v0)*k.mx + SCALAR_IM(v1)*k.nx; vy_i = SCALAR_IM(v0)*k.my + SCALAR_IM(v1)*k.ny; vz_i = SCALAR_IM(v0)*k.mz + SCALAR_IM(v1)*k.nz;#endif ASSIGN_SCALAR(a[0], u[1] * vz_r - u[2] * vy_r, u[1] * vz_i - u[2] * vy_i); ASSIGN_SCALAR(a[1], u[2] * vx_r - u[0] * vz_r, u[2] * vx_i - u[0] * vz_i); ASSIGN_SCALAR(a[2], u[0] * vy_r - u[1] * vx_r, u[0] * vy_i - u[1] * vx_i);}/**************************************************************************/void maxwell_compute_fft(int dir, maxwell_data *d, scalar *array, int howmany, int stride, int dist){#ifdef HAVE_FFTW# ifdef SCALAR_COMPLEX# ifndef HAVE_MPI fftwnd(dir < 0 ? d->plan : d->iplan, howmany, (fftw_complex *) array, stride, dist, 0, 0, 0);# else /* HAVE_MPI */ CHECK(stride == howmany && dist == 1, "weird strides and dists don't work with fftwnd_mpi"); fftwnd_mpi(dir < 0 ? d->plan : d->iplan, howmany, (fftw_complex *) array, (fftw_complex *) NULL, FFTW_TRANSPOSED_ORDER);# endif /* HAVE_MPI */# else /* not SCALAR_COMPLEX */# ifndef HAVE_MPI if (dir > 0) rfftwnd_real_to_complex(d->iplan, howmany, (fftw_real *) array, stride, dist, 0, 0, 0); else rfftwnd_complex_to_real(d->plan, howmany, (fftw_complex *) array, stride, dist, 0, 0, 0);# else /* HAVE_MPI */ CHECK(stride == howmany && dist == 1, "weird strides and dists don't work with rfftwnd_mpi"); rfftwnd_mpi(dir < 0 ? d->plan : d->iplan, howmany, array, (scalar *) NULL, FFTW_TRANSPOSED_ORDER);# endif /* HAVE_MPI */# endif /* not SCALAR_COMPLEX */#else /* not HAVE_FFTW */# error only FFTW ffts are supported#endif /* not HAVE_FFTW */}/**************************************************************************//* assigns newv = matrix * oldv. matrix is symmetric and so is stored in "packed" format. */void assign_symmatrix_vector(scalar_complex *newv, const symmetric_matrix matrix, const scalar_complex *oldv){ scalar_complex v0 = oldv[0], v1 = oldv[1], v2 = oldv[2];#if defined(WITH_HERMITIAN_EPSILON) newv[0].re = matrix.m00 * v0.re; newv[0].im = matrix.m00 * v0.im; CACCUMULATE_SUM_MULT(newv[0], matrix.m01, v1); CACCUMULATE_SUM_MULT(newv[0], matrix.m02, v2); newv[1].re = matrix.m11 * v1.re; newv[1].im = matrix.m11 * v1.im; CACCUMULATE_SUM_CONJ_MULT(newv[1], matrix.m01, v0); CACCUMULATE_SUM_MULT(newv[1], matrix.m12, v2); newv[2].re = matrix.m22 * v2.re; newv[2].im = matrix.m22 * v2.im; CACCUMULATE_SUM_CONJ_MULT(newv[2], matrix.m02, v0); CACCUMULATE_SUM_CONJ_MULT(newv[2], matrix.m12, v1);#else newv[0].re = matrix.m00 * v0.re + matrix.m01 * v1.re + matrix.m02 * v2.re; newv[0].im = matrix.m00 * v0.im + matrix.m01 * v1.im + matrix.m02 * v2.im; newv[1].re = matrix.m01 * v0.re + matrix.m11 * v1.re + matrix.m12 * v2.re; newv[1].im = matrix.m01 * v0.im + matrix.m11 * v1.im + matrix.m12 * v2.im; newv[2].re = matrix.m02 * v0.re + matrix.m12 * v1.re + matrix.m22 * v2.re; newv[2].im = matrix.m02 * v0.im + matrix.m12 * v1.im + matrix.m22 * v2.im;#endif#ifdef DEBUG { real dummy; dummy = CSCALAR_NORMSQR(newv[0]) + CSCALAR_NORMSQR(newv[1]) + CSCALAR_NORMSQR(newv[2]); CHECK(!BADNUM(dummy), "yikes, crazy number!"); }#endif}/* compute the D field in position space from Hin, which holds the H field in Fourier space, for the specified bands; this amounts to taking the curl and then Fourier transforming. The output array, dfield, is fft_output_size x cur_num_bands x 3, where fft_output_size is the local spatial indices and 3 is the field components. Note: actually, this computes just (k+G) x H, whereas the actual D field is i/omega i(k+G) x H...so, we are really computing -omega*D, here. */void maxwell_compute_d_from_H(maxwell_data *d, evectmatrix Hin, scalar_complex *dfield, int cur_band_start, int cur_num_bands){ scalar *fft_data = (scalar *) dfield; int i, j, b; CHECK(Hin.c == 2, "fields don't have 2 components!"); CHECK(d, "null maxwell data pointer!"); CHECK(dfield, "null field output data!"); CHECK(cur_band_start >= 0 && cur_band_start + cur_num_bands <= Hin.p, "invalid range of bands for computing fields"); /* first, compute fft_data = curl(Hin) (really (k+G) x H) : */ for (i = 0; i < d->other_dims; ++i) for (j = 0; j < d->last_dim; ++j) { int ij = i * d->last_dim + j; int ij2 = i * d->last_dim_size + j; k_data cur_k = d->k_plus_G[ij]; for (b = 0; b < cur_num_bands; ++b) assign_cross_t2c(&fft_data[3 * (ij2*cur_num_bands + b)], cur_k, &Hin.data[ij * 2 * Hin.p + b + cur_band_start], Hin.p); } /* now, convert to position space via FFT: */ maxwell_compute_fft(+1, d, fft_data, cur_num_bands*3, cur_num_bands*3, 1);}/* Compute E (output in dfield) from D (input in dfield); this amounts to just dividing by the dielectric tensor. dfield is in position
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -