Skip to content

Commit

Permalink
initial stab at re-implementing cylindrical support; compiles, and fl…
Browse files Browse the repository at this point in the history
…ux.cpp passes, but cylindrical.cpp still fails
  • Loading branch information
stevengj committed Jun 20, 2008
1 parent 1a47119 commit c12ff75
Show file tree
Hide file tree
Showing 7 changed files with 190 additions and 35 deletions.
8 changes: 4 additions & 4 deletions src/anisotropic_averaging.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ void structure_chunk::set_mu(material_function &mu) {

FOR_MAGNETIC_COMPONENTS(c) if (v.has_field(c)) {
direction c_d = component_direction(c);
LOOP_OVER_DIRECTIONS(v.dim,da) // make sure no off-diagonal terms
LOOP_OVER_FIELD_DIRECTIONS(v.dim,da) // make sure no off-diagonal terms
if (da != c_d) { delete[] invmu[c][da]; invmu[c][da] = NULL; }
if (!invmu[c][c_d]) invmu[c][c_d] = new double[v.ntot()];
if (!invmu[c][c_d]) abort("Memory allocation error.\n");
Expand All @@ -211,7 +211,7 @@ void structure_chunk::set_mu(material_function &mu) {
invmu[c][c_d][i] = 1/mu.mu(here); // TODO - support aniso. averaging
trivial = trivial && (invmu[c][c_d][i] == 1.0);
}
if (trivial) LOOP_OVER_DIRECTIONS(v.dim,da) { // don't store invmu == 1
if (trivial) LOOP_OVER_FIELD_DIRECTIONS(v.dim,da) { // don't store invmu=1
delete[] invmu[c][da];
invmu[c][da] = NULL;
}
Expand Down Expand Up @@ -261,7 +261,7 @@ void structure_chunk::set_epsilon(material_function &epsilon,
}
break;
}
LOOP_OVER_DIRECTIONS(v.dim,da) // make sure no off-diagonal terms
LOOP_OVER_FIELD_DIRECTIONS(v.dim,da) // make sure no off-diagonal terms
if (da != c_d) { delete[] inveps[c][da]; inveps[c][da] = NULL; }
if (!inveps[c][c_d]) inveps[c][c_d] = new double[v.ntot()];
if (!have_other_direction) {
Expand Down Expand Up @@ -290,7 +290,7 @@ void structure_chunk::set_epsilon(material_function &epsilon,
}
#else // really no averaging at all
direction c_d = component_direction(c);
LOOP_OVER_DIRECTIONS(v.dim,da) // make sure no off-diagonal terms
LOOP_OVER_FIELD_DIRECTIONS(v.dim,da) // make sure no off-diagonal terms
if (da != c_d) { delete[] inveps[c][da]; inveps[c][da] = NULL; }
if (!inveps[c][c_d]) inveps[c][c_d] = new double[v.ntot()];
LOOP_OVER_VOL(v, c, i) {
Expand Down
16 changes: 13 additions & 3 deletions src/fields.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ fields_chunk::~fields_chunk() {
delete[] f_prev[c][cmp];
delete[] f_minus_p[c][cmp];
}
delete[] f_rderiv_int;
FOR_FIELD_TYPES(ft)
for (int ip=0;ip<3;ip++)
for (int io=0;io<2;io++)
Expand Down Expand Up @@ -206,6 +207,7 @@ fields_chunk::fields_chunk(structure_chunk *the_s, const char *od,
f_prev[c][cmp] = NULL;
f_minus_p[c][cmp] = NULL;
}
f_rderiv_int = NULL;
FOR_FIELD_TYPES(ft) {
for (int ip=0;ip<3;ip++)
num_connections[ft][ip][Incoming]
Expand Down Expand Up @@ -271,16 +273,24 @@ fields_chunk::fields_chunk(const fields_chunk &thef)
memcpy(f_minus_p[c][cmp], thef.f_minus_p[c][cmp],
sizeof(double) * v.ntot());
}
f_rderiv_int = NULL;
figure_out_step_plan();
}

static inline bool cross_negative(direction a, direction b) {
if (a >= R) a = direction(a - 3);
if (b >= R) b = direction(b - 3);
return ((3+b-a)%3) == 2;
}

static inline direction cross(direction a, direction b) {
if (a < R && b < R) return (direction)((3+2*a-b)%3);
return (direction) (2 + (3+2*(a-2)-(b-2))%3);
if (a == b) abort("bug - cross expects different directions");
bool dcyl = a >= R || b >= R;
if (a >= R) a = direction(a - 3);
if (b >= R) b = direction(b - 3);
direction c = direction((3+2*a-b)%3);
if (dcyl && c < Z) return direction(c + 3);
return c;
}

/* Call this whenever we modify the structure_chunk (fields_chunk::s) to
Expand All @@ -306,7 +316,7 @@ void fields_chunk::figure_out_step_plan() {
(is_B(c1) && is_electric(c2))) {
const direction dc2 = component_direction(c2);
if (dc1 != dc2 && v.has_field(c2) && v.has_field(c1) &&
has_direction(v.dim,cross(dc1,dc2))) {
has_field_direction(v.dim,cross(dc1,dc2))) {
direction d_deriv = cross(dc1,dc2);
if (cross_negative(dc2, dc1)) {
minus_component[c1] = c2;
Expand Down
3 changes: 3 additions & 0 deletions src/meep.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -645,8 +645,11 @@ class fields_chunk {
we save backup copies of (some of) the fields to resume timestepping */
double *f_backup[NUM_FIELD_COMPONENTS][2];

// used to store D-P and B-P, e.g. when P implements dispersive media
double *f_minus_p[NUM_FIELD_COMPONENTS][2];

double *f_rderiv_int; // cache of helper field for 1/r d(rf)/dr derivative

dft_chunk *dft_chunks;

double **zeroes[NUM_FIELD_TYPES]; // Holds pointers to metal points.
Expand Down
9 changes: 9 additions & 0 deletions src/meep/vec.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,10 +95,14 @@ component first_field_component(field_type ft);
s = (boundary_side) ((s+1) % 2), \
loop_stop_bi = High)

// only loop over directions where we have coordinates
#define LOOP_OVER_DIRECTIONS(dim, d) for (direction d = start_at_direction(dim), \
loop_stop_directi = stop_at_direction(dim); \
d < loop_stop_directi; d = (direction) (d+1))

// loop over all directions in which we might have fields
#define LOOP_OVER_FIELD_DIRECTIONS(dim, d) for (direction d = dim == Dcyl ? Z : X; d < (dim == Dcyl ? NO_DIRECTION : R); d = direction(d+1))

// loop over indices idx from is to ie (inclusive) in v
#define LOOP_OVER_IVECS(v, is, ie, idx) \
for (int loop_is1 = (is).yucky_val(0), \
Expand Down Expand Up @@ -169,6 +173,11 @@ inline bool has_direction(ndim dim, direction d) {
return false;
}

inline bool has_field_direction(ndim dim, direction d) {
LOOP_OVER_FIELD_DIRECTIONS(dim, dd) if (dd == d) return true;
return false;
}

// true if d is polar while dim is cartesian, or vice versa
inline bool coordinate_mismatch(ndim dim, direction d) {
return (d != NO_DIRECTION &&
Expand Down
185 changes: 159 additions & 26 deletions src/step_db.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,36 +61,169 @@ void fields_chunk::step_db(field_type ft) {
v.ntot()*sizeof(double));
}

if (v.dim != Dcyl) {
DOCMP FOR_FT_COMPONENTS(ft, cc)
if (f[cc][cmp]) {
const component c_p=plus_component[cc], c_m=minus_component[cc];
const direction d_deriv_p = plus_deriv_direction[cc];
const direction d_deriv_m = minus_deriv_direction[cc];
const direction d_c = component_direction(cc);
const bool have_p = have_plus_deriv[cc];
const bool have_m = have_minus_deriv[cc];
const direction dsig0 = cycle_direction(v.dim,d_c,1);
const bool have_pml = s->sigsize[dsig0] > 1;
const direction dsig = have_pml ? dsig0 : NO_DIRECTION;
int stride_p = have_p?v.stride(d_deriv_p):0;
int stride_m = have_m?v.stride(d_deriv_m):0;
RESTRICT const double *f_p = have_p?f[c_p][cmp]:NULL;
RESTRICT const double *f_m = have_m?f[c_m][cmp]:NULL;
RESTRICT double *the_f = f[cc][cmp];
DOCMP FOR_FT_COMPONENTS(ft, cc)
if (f[cc][cmp]) {
const component c_p=plus_component[cc], c_m=minus_component[cc];
const direction d_deriv_p = plus_deriv_direction[cc];
const direction d_deriv_m = minus_deriv_direction[cc];
const direction d_c = component_direction(cc);
const bool have_p = have_plus_deriv[cc];
const bool have_m = have_minus_deriv[cc];
const direction dsig0 = cycle_direction(v.dim,d_c,1);
const bool have_pml = s->sigsize[dsig0] > 1;
const direction dsig = have_pml ? dsig0 : NO_DIRECTION;
int stride_p = have_p?v.stride(d_deriv_p):0;
int stride_m = have_m?v.stride(d_deriv_m):0;
double *f_p = have_p?f[c_p][cmp]:NULL;
double *f_m = have_m?f[c_m][cmp]:NULL;
double *the_f = f[cc][cmp];

if (ft == D_stuff) { // strides are opposite sign for H curl
stride_p = -stride_p;
stride_m = -stride_m;
}

if (ft == D_stuff) { // strides are opposite sign for H curl
stride_p = -stride_p;
stride_m = -stride_m;
if (v.dim == Dcyl) switch (d_c) {
case R:
f_p = NULL; // im/r Fz term will be handled separately
break;
case P:
break; // curl works normally for phi component
case Z: {
f_m = NULL; // im/r Fr term will be handled separately

/* Here we do a somewhat cool hack: the update of the z
component gives a 1/r d(r Fp)/dr term, rather than
just the derivative dg/dr expected in step_curl.
Rather than duplicating all of step_curl to handle
this bloody derivative, however, we define a new
array f_rderiv_int which is the integral of 1/r d(r Fp)/dr,
so that we can pass it to the unmodified step_curl
and get the correct derivative. (More precisely,
the derivative and integral are replaced by differences
and sums, but you get the idea). */
if (!f_rderiv_int) f_rderiv_int = new double[v.ntot()];
double ir0 = (v.origin_r() + rshift) * v.a
+ 0.5 * v.iyee_shift(c_p).in_direction(R);
for (int iz = 0; iz <= v.nz(); ++iz) f_rderiv_int[iz] = 0;
int sr = v.nz() + 1;
for (int ir = 1; ir <= v.nr(); ++ir) {
double rinv = 1.0 / ((ir+ir0)-0.5);
for (int iz = 0; iz <= v.nz(); ++iz) {
int idx = ir*sr + iz;
f_rderiv_int[idx] = f_rderiv_int[idx - sr] +
rinv * (f_p[idx] * (ir+ir0) - f_p[idx - sr] * ((ir-1)+ir0));
}
}
f_p = f_rderiv_int;
break;
}
default: abort("bug - non-cylindrical field component in Dcyl");
}

step_curl(the_f, cc, f_p, f_m, stride_p, stride_m, v, Courant,
dsig, s->sig[dsig], s->siginv[dsig],
dt, s->conductivity[cc][d_c], s->condinv[cc][d_c]);
}

// in cylindrical coordinates, we now have to add the i*m/r terms... */
if (v.dim == Dcyl && m != 0) DOCMP FOR_FT_COMPONENTS(ft, cc) {
if (f[cc][cmp]) {
const direction d_c = component_direction(cc);
if (d_c != R && d_c != Z) break;
const component c_p=plus_component[cc], c_m=minus_component[cc];
const double *g = d_c == R ? f[c_p][1-cmp] : f[c_m][1-cmp];
double *the_f = f[cc][cmp];
const double *cndinv = s->condinv[cc][d_c];
const direction dsig = cycle_direction(v.dim,d_c,1);
const double the_m =
m * (1-2*cmp) * (1-2*(ft==H_stuff)) * (1-2*(d_c==R)) * Courant;
const double ir0 = (v.origin_r() + rshift) * v.a
+ 0.5 * v.iyee_shift(cc).in_direction(R);
int sr = v.nz() + 1;
if (cndinv) { // conductivity, possibly including PML
for (int ir = ir0 <= 0.5; ir <= v.nr(); ++ir) {
double rinv = the_m / ((ir+ir0)-0.5);
for (int iz = 0; iz <= v.nz(); ++iz) {
int idx = ir*sr + iz;
the_f[idx] += rinv * g[idx] * cndinv[idx];
}
}
}
else if (s->sigsize[dsig] > 1) { // PML
const double *siginv = s->siginv[dsig];
int dk = v.iyee_shift(cc).in_direction(dsig);
for (int ir = ir0 <= 0.5; ir <= v.nr(); ++ir) {
double rinv = the_m / ((ir+ir0)-0.5);
for (int iz = 0; iz <= v.nz(); ++iz) {
int idx = ir*sr + iz;
the_f[idx] += rinv * g[idx] * siginv[dk + 2*(dsig==Z ? iz : ir)];
}
}
}
else { // no PML, no conductivity
for (int ir = ir0 <= 0.5; ir <= v.nr(); ++ir) {
double rinv = the_m / ((ir+ir0)-0.5);
for (int iz = 0; iz <= v.nz(); ++iz) {
int idx = ir*sr + iz;
the_f[idx] += rinv * g[idx];
}
}
}
}
}

step_curl(the_f, cc, f_p, f_m, stride_p, stride_m, v, Courant,
dsig, s->sig[dsig], s->siginv[dsig],
dt, s->conductivity[cc][d_c], s->condinv[cc][d_c]);
// deal with annoying r=0 boundary conditions for m=0 and m=1
if (v.dim == Dcyl && v.origin_r() == 0.0 && (m == 0 || fabs(m) == 1)) DOCMP {
if (m == 0 && ft == D_stuff && f[Dz][cmp]) {
// d(Dz)/dt = (1/r) * d(r*Hp)/dr
double *the_f = f[Dz][cmp];
const double *g = f[Hp][cmp];
const double *cndinv = s->condinv[Dz][Z];
const direction dsig = cycle_direction(v.dim,Z,1);
if (cndinv) // conductivity, possibly including PML
for (int iz = 0; iz < v.nz(); ++iz)
the_f[iz] += g[iz] * (Courant * 4) * cndinv[iz];
else if (s->sigsize[dsig] > 1) { // PML
const double *siginv = s->siginv[dsig];
int dk = v.iyee_shift(Dz).in_direction(dsig);
for (int iz = 0; iz < v.nz(); ++iz)
the_f[iz] += g[iz] * (Courant * 4) * siginv[dk + 2*(dsig==Z)*iz];
}
else // no PML, no conductivity
for (int iz = 0; iz < v.nz(); ++iz)
the_f[iz] += g[iz] * (Courant * 4);
// Note: old code was missing factor of 4??
}
else if (m == 1) {
// D_stuff: d(Dp)/dt = d(Hr)/dz - d(Hz)/dr
// H_stuff: d(Hr)/dt = d(Ep)/dz - i*m*Ez/r
component cc = ft == D_stuff ? Dp : Hr;
direction d_c = component_direction(cc);
double *the_f = f[cc][cmp];
if (!the_f) continue;
const double *f_p = f[ft == D_stuff ? Hr : Ep][cmp];
const double *f_m = ft == D_stuff ? f[Hz][cmp]
: (f[Ez][1-cmp] + (v.nz()+1));
const double *cndinv = s->condinv[cc][d_c];
const direction dsig = cycle_direction(v.dim,d_c,1);
int sd = ft == D_stuff ? +1 : -1;
double f_m_mult = ft == D_stuff ? 2 : (1-2*cmp);
if (cndinv) // conductivity, possibly including PML
for (int iz = (ft == D_stuff); iz < v.nz() + (ft == D_stuff); ++iz)
the_f[iz] += (sd*Courant) * (f_p[iz]-f_p[iz-sd] - f_m_mult*f_m[iz])
* cndinv[iz];
else if (s->sigsize[dsig] > 1) { // PML
const double *siginv = s->siginv[dsig];
int dk = v.iyee_shift(cc).in_direction(dsig);
for (int iz = (ft == D_stuff); iz < v.nz() + (ft == D_stuff); ++iz)
the_f[iz] += (sd*Courant) * (f_p[iz]-f_p[iz-sd] - f_m_mult*f_m[iz])
* siginv[dk + 2*(dsig==Z)*iz];
}
} else if (v.dim == Dcyl) {
} else {
abort("Unsupported dimension.\n");
else // no PML, no conductivity
for (int iz = (ft == D_stuff); iz < v.nz() + (ft == D_stuff); ++iz)
the_f[iz] += (sd*Courant) * (f_p[iz]-f_p[iz-sd] - f_m_mult*f_m[iz]);
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/step_generic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace meep {

/* update step for df/dt = curl g,
i.e. f += dt curl g = dt/dx (dg1 - dg2)
where dgk = g[i+sk] - g[i].
where dgk = gk[i] - gk[i+sk].
g = (g1,g2), where g1 or g2 may be NULL. Note that dt/dx and/or s1
and s2 may be negative to flip signs of derivatives.
Expand Down
2 changes: 1 addition & 1 deletion src/structure.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -521,7 +521,7 @@ void structure_chunk::use_pml(direction d, double dx, double bloc,
sig[d] = NULL;
siginv[d] = NULL;
}
LOOP_OVER_DIRECTIONS(D3,dd) {
LOOP_OVER_FIELD_DIRECTIONS(v.dim, dd) {
if (!sig[dd]) {
int spml = (dd==d)?(2*v.num_direction(d)+2):1;
sigsize[dd] = spml;
Expand Down

0 comments on commit c12ff75

Please sign in to comment.