From 214f1a8921dad525772c9d955bc50b8440fbae0e Mon Sep 17 00:00:00 2001 From: Ardavan Oskooi Date: Mon, 10 May 2021 23:53:03 -0700 Subject: [PATCH 01/15] compute material volume averages of a MaterialGrid using analytic formulation --- src/meepgeom.cpp | 166 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 139 insertions(+), 27 deletions(-) diff --git a/src/meepgeom.cpp b/src/meepgeom.cpp index b6f4a9cf5..83d483708 100644 --- a/src/meepgeom.cpp +++ b/src/meepgeom.cpp @@ -1144,6 +1144,78 @@ void geom_epsilon::eff_chi1inv_matrix(meep::component c, symmetric_matrix *chi1i static int eps_ever_negative = 0; static meep::field_type func_ft = meep::E_stuff; +static double voxel_rad = 0; +static vector3 voxel_cen; + +#ifdef CTL_HAS_COMPLEX_INTEGRATION +static cnumber matgrid_ceps_func(int n, number *x, void *geomeps_) { + geom_epsilon *geomeps = (geom_epsilon *)geomeps_; + vector3 p = {0, 0, 0}; + p.x = x[0]; + p.y = n > 1 ? x[1] : 0; + p.z = n > 2 ? x[2] : 0; + double s = 1; + if (dim == meep::Dcyl) { + double py = p.y; + p.y = p.z; + p.z = py; + s = p.x; + } + cnumber ret; + double r2 = voxel_rad*voxel_rad; + double z2 = sqr(p.x-voxel_cen.x) + sqr(p.y-voxel_cen.y); + double w = 2*sqrt(r2 - z2)/(meep::pi*r2); + double ep = geomeps->chi1p1(func_ft, vector3_to_vec(p)); + if (ep < 0) eps_ever_negative = 1; + ret.re = ep * s; + ret.im = s / ep; + master_printf("matgrid_ceps_func:, (%0.5f,%0.5f), %0.5f, %0.5f\n",p.x,p.y,ret.re,ret.im); + return ret * w; +} +#else +static number matgrid_eps_func(int n, number *x, void *geomeps_) { + geom_epsilon *geomeps = (geom_epsilon *)geomeps_; + vector3 p = {0, 0, 0}; + double s = 1; + p.x = x[0]; + p.y = n > 1 ? x[1] : 0; + p.z = n > 2 ? x[2] : 0; + if (dim == meep::Dcyl) { + double py = p.y; + p.y = p.z; + p.z = py; + s = p.x; + } + double r2 = voxel_rad*voxel_rad; + double z2 = (p.x-voxel_cen.x)*(p.x-voxel_cen.x) + (p.y-voxel_cen.y)*(p.y-voxel_cen.y); + double w = 2*sqrt(r2 - z2)/(meep::pi*r2); + double ep = geomeps->chi1p1(func_ft, vector3_to_vec(p)); + if (ep < 0) eps_ever_negative = 1; + master_printf("matgrid_eps_func:, (%0.5f,%0.5f), (%0.5f,%0.5f), %0.6f, %0.6f, %d\n",p.x,p.y,voxel_cen.x,voxel_cen.y,r2,z2,r2 < z2 ? 1 : 0); + return (ep * s) * w; +} +static number matgrid_inveps_func(int n, number *x, void *geomeps_) { + geom_epsilon *geomeps = (geom_epsilon *)geomeps_; + vector3 p = {0, 0, 0}; + double s = 1; + p.x = x[0]; + p.y = n > 1 ? x[1] : 0; + p.z = n > 2 ? x[2] : 0; + if (dim == meep::Dcyl) { + double py = p.y; + p.y = p.z; + p.z = py; + s = p.x; + } + double r2 = voxel_rad*voxel_rad; + double z2 = (p.x-voxel_cen.x)*(p.x-voxel_cen.x) + (p.y-voxel_cen.y)*(p.y-voxel_cen.y); + double w = 2*sqrt(r2 - z2)/(meep::pi*r2); + double ep = geomeps->chi1p1(func_ft, vector3_to_vec(p)); + if (ep < 0) eps_ever_negative = 1; + master_printf("matgrid_inveps_func:, (%0.5f,%0.5f), (%0.5f,%0.5f), %0.6f, %0.6f, %d\n",p.x,p.y,voxel_cen.x,voxel_cen.y,r2,z2,r2 < z2 ? 1 : 0); + return (s / ep) * w; +} +#endif #ifdef CTL_HAS_COMPLEX_INTEGRATION static cnumber ceps_func(int n, number *x, void *geomeps_) { @@ -1253,47 +1325,87 @@ void geom_epsilon::fallback_chi1inv_row(meep::component c, double chi1inv_row[3] number esterr; integer errflag, n; number xmin[3], xmax[3]; - vector3 gvmin, gvmax; - gvmin = vec_to_vector3(v.get_min_corner()); - gvmax = vec_to_vector3(v.get_max_corner()); - xmin[0] = gvmin.x; - xmax[0] = gvmax.x; - if (dim == meep::Dcyl) { - xmin[1] = gvmin.z; - xmin[2] = gvmin.y; - xmax[1] = gvmax.z; - xmax[2] = gvmax.y; + double vol = 1; + if (md->which_subclass == material_data::MATERIAL_GRID) { + // integrate along a line in the direction of the normal vector through the center of a circular voxel + // for a normal vector at an oblique angle, start with a horizontal line through (-D/2,0) and (+D/2,0) + // and apply counter clockwise rotation through the z-axis using the direction angle of the normal vector + double theta = atan(gradient.y()/gradient.x()); + voxel_rad = v.diameter()/2; + voxel_cen = p; + if (theta == 0) { + xmin[0] = -voxel_rad; + xmin[1] = 0; + xmin[2] = 0; + xmax[0] = voxel_rad; + xmax[1] = 0; + xmax[2] = 0; + } + else if (fabs(theta) == meep::pi/2) { + xmin[0] = 0; + xmin[1] = -voxel_rad; + xmin[2] = 0; + xmax[0] = 0; + xmax[1] = voxel_rad; + xmax[2] = 0; + } + else { + xmin[0] = -cos(theta)*voxel_rad + p.x; + xmin[1] = -sin(theta)*voxel_rad + p.y; + xmin[2] = 0; + xmax[0] = cos(theta)*voxel_rad + p.x; + xmax[1] = sin(theta)*voxel_rad + p.y; + xmax[2] = 0; + } + n = 2; + vol = 2*voxel_rad; } else { - xmin[1] = gvmin.y; - xmin[2] = gvmin.z; - xmax[1] = gvmax.y; - xmax[2] = gvmax.z; + // quadrature over entire voxel from one corner of cube to the other + vector3 gvmin, gvmax; + gvmin = vec_to_vector3(v.get_min_corner()); + gvmax = vec_to_vector3(v.get_max_corner()); + xmin[0] = gvmin.x; + xmax[0] = gvmax.x; + if (dim == meep::Dcyl) { + xmin[1] = gvmin.z; + xmin[2] = gvmin.y; + xmax[1] = gvmax.z; + xmax[2] = gvmax.y; + } + else { + xmin[1] = gvmin.y; + xmin[2] = gvmin.z; + xmax[1] = gvmax.y; + xmax[2] = gvmax.z; + } + if (xmin[2] == xmax[2]) + n = xmin[1] == xmax[1] ? 1 : 2; + else + n = 3; + for (int i = 0; i < n; ++i) + vol *= xmax[i] - xmin[i]; + if (dim == meep::Dcyl) vol *= (xmin[0] + xmax[0]) * 0.5; } - if (xmin[2] == xmax[2]) - n = xmin[1] == xmax[1] ? 1 : 2; - else - n = 3; - double vol = 1; - for (int i = 0; i < n; ++i) - vol *= xmax[i] - xmin[i]; - if (dim == meep::Dcyl) vol *= (xmin[0] + xmax[0]) * 0.5; + eps_ever_negative = 0; func_ft = meep::type(c); double meps, minveps; #ifdef CTL_HAS_COMPLEX_INTEGRATION - cnumber ret = cadaptive_integration(ceps_func, xmin, xmax, n, (void *)this, 0, tol, maxeval, + cnumber ret = cadaptive_integration((md->which_subclass == material_data::MATERIAL_GRID) ? matgrid_ceps_func: ceps_func, + xmin, xmax, n, (void *)this, 0, tol, maxeval, &esterr, &errflag); meps = ret.re / vol; minveps = ret.im / vol; #else - meps = adaptive_integration(eps_func, xmin, xmax, n, (void *)this, 0, tol, maxeval, &esterr, + meps = adaptive_integration((md->which_subclass == material_data::MATERIAL_GRID) ? matgrid_eps_func : eps_func, xmin, xmax, n, (void *)this, 0, tol, maxeval, &esterr, &errflag) / - vol; - minveps = adaptive_integration(inveps_func, xmin, xmax, n, (void *)this, 0, tol, maxeval, &esterr, + vol; + minveps = adaptive_integration((md->which_subclass == material_data::MATERIAL_GRID) ? matgrid_inveps_func : inveps_func, xmin, xmax, n, (void *)this, 0, tol, maxeval, &esterr, &errflag) / - vol; + vol; #endif + if (eps_ever_negative) // averaging negative eps causes instability minveps = 1.0 / (meps = eps(v.center())); From 5b204100b059df536ba8362a1d8e41f603180a17 Mon Sep 17 00:00:00 2001 From: Ardavan Oskooi Date: Tue, 11 May 2021 17:30:56 -0700 Subject: [PATCH 02/15] fixes --- src/meepgeom.cpp | 35 +++++++---------------------------- 1 file changed, 7 insertions(+), 28 deletions(-) diff --git a/src/meepgeom.cpp b/src/meepgeom.cpp index 83d483708..6eb018538 100644 --- a/src/meepgeom.cpp +++ b/src/meepgeom.cpp @@ -1163,13 +1163,12 @@ static cnumber matgrid_ceps_func(int n, number *x, void *geomeps_) { } cnumber ret; double r2 = voxel_rad*voxel_rad; - double z2 = sqr(p.x-voxel_cen.x) + sqr(p.y-voxel_cen.y); + double z2 = (p.x-voxel_cen.x)*(p.x-voxel_cen.x) + (p.y-voxel_cen.y)*(p.y-voxel_cen.y); double w = 2*sqrt(r2 - z2)/(meep::pi*r2); double ep = geomeps->chi1p1(func_ft, vector3_to_vec(p)); if (ep < 0) eps_ever_negative = 1; ret.re = ep * s; ret.im = s / ep; - master_printf("matgrid_ceps_func:, (%0.5f,%0.5f), %0.5f, %0.5f\n",p.x,p.y,ret.re,ret.im); return ret * w; } #else @@ -1191,7 +1190,6 @@ static number matgrid_eps_func(int n, number *x, void *geomeps_) { double w = 2*sqrt(r2 - z2)/(meep::pi*r2); double ep = geomeps->chi1p1(func_ft, vector3_to_vec(p)); if (ep < 0) eps_ever_negative = 1; - master_printf("matgrid_eps_func:, (%0.5f,%0.5f), (%0.5f,%0.5f), %0.6f, %0.6f, %d\n",p.x,p.y,voxel_cen.x,voxel_cen.y,r2,z2,r2 < z2 ? 1 : 0); return (ep * s) * w; } static number matgrid_inveps_func(int n, number *x, void *geomeps_) { @@ -1212,7 +1210,6 @@ static number matgrid_inveps_func(int n, number *x, void *geomeps_) { double w = 2*sqrt(r2 - z2)/(meep::pi*r2); double ep = geomeps->chi1p1(func_ft, vector3_to_vec(p)); if (ep < 0) eps_ever_negative = 1; - master_printf("matgrid_inveps_func:, (%0.5f,%0.5f), (%0.5f,%0.5f), %0.6f, %0.6f, %d\n",p.x,p.y,voxel_cen.x,voxel_cen.y,r2,z2,r2 < z2 ? 1 : 0); return (s / ep) * w; } #endif @@ -1333,30 +1330,12 @@ void geom_epsilon::fallback_chi1inv_row(meep::component c, double chi1inv_row[3] double theta = atan(gradient.y()/gradient.x()); voxel_rad = v.diameter()/2; voxel_cen = p; - if (theta == 0) { - xmin[0] = -voxel_rad; - xmin[1] = 0; - xmin[2] = 0; - xmax[0] = voxel_rad; - xmax[1] = 0; - xmax[2] = 0; - } - else if (fabs(theta) == meep::pi/2) { - xmin[0] = 0; - xmin[1] = -voxel_rad; - xmin[2] = 0; - xmax[0] = 0; - xmax[1] = voxel_rad; - xmax[2] = 0; - } - else { - xmin[0] = -cos(theta)*voxel_rad + p.x; - xmin[1] = -sin(theta)*voxel_rad + p.y; - xmin[2] = 0; - xmax[0] = cos(theta)*voxel_rad + p.x; - xmax[1] = sin(theta)*voxel_rad + p.y; - xmax[2] = 0; - } + xmin[0] = -cos(theta)*voxel_rad + p.x; + xmin[1] = -sin(theta)*voxel_rad + p.y; + xmin[2] = 0; + xmax[0] = cos(theta)*voxel_rad + p.x; + xmax[1] = sin(theta)*voxel_rad + p.y; + xmax[2] = 0; n = 2; vol = 2*voxel_rad; } From 263f92b6985440414a182c58f4659741919e2c86 Mon Sep 17 00:00:00 2001 From: Ardavan Oskooi Date: Sun, 16 May 2021 18:50:35 -0700 Subject: [PATCH 03/15] evaluate weight of matgrid once at the voxel center --- src/meepgeom.cpp | 213 +++++++++++++++++++++++++---------------------- 1 file changed, 114 insertions(+), 99 deletions(-) diff --git a/src/meepgeom.cpp b/src/meepgeom.cpp index 6eb018538..fb6004811 100644 --- a/src/meepgeom.cpp +++ b/src/meepgeom.cpp @@ -368,7 +368,7 @@ meep::vec material_grid_grad(vector3 p, material_data *md) { gradient.set_direction(meep::Y, du_dy); gradient.set_direction(meep::Z, du_dz); - return (abs(gradient) < 1e-8) ? zero_vec(dim) : gradient/abs(gradient); + return (abs(gradient) < 1e-8) ? zero_vec(dim) : gradient; } void map_lattice_coordinates(double &px, double &py, double &pz) { @@ -1144,78 +1144,89 @@ void geom_epsilon::eff_chi1inv_matrix(meep::component c, symmetric_matrix *chi1i static int eps_ever_negative = 0; static meep::field_type func_ft = meep::E_stuff; -static double voxel_rad = 0; -static vector3 voxel_cen; + +struct matgrid_volavg { + meep::ndim dim; // dimensionality of voxel + double rad; // (spherical) voxel radius + double uval; // bilinearly-interpolated weight at voxel center + double ugrad_abs; // magnitude of gradient of uval + double beta; // thresholding bias + double eta; // thresholding erosion/dilation + vector3 med1_eps_diag; // diagonal of epsilon tensor from medium 1 + vector3 med2_eps_diag; // diagonal of epsilon tensor from medium 2 +}; #ifdef CTL_HAS_COMPLEX_INTEGRATION -static cnumber matgrid_ceps_func(int n, number *x, void *geomeps_) { - geom_epsilon *geomeps = (geom_epsilon *)geomeps_; - vector3 p = {0, 0, 0}; - p.x = x[0]; - p.y = n > 1 ? x[1] : 0; - p.z = n > 2 ? x[2] : 0; - double s = 1; - if (dim == meep::Dcyl) { - double py = p.y; - p.y = p.z; - p.z = py; - s = p.x; - } +static cnumber matgrid_ceps_func(int n, number *x, void *mgva_) { + matgrid_volavg *mgva = (matgrid_volavg *)mgva_; + double z = x[0]; + double u = mgva->uval + mgva->ugrad_abs*z; + double tanh_beta_eta = tanh(mgva->beta*mgva->eta); + double u_proj = (tanh_beta_eta + tanh(mgva->beta*(u-mgva->eta))) / + (tanh_beta_eta + tanh(mgva->beta*(1-mgva->eta))); + vector3 med1_eps_diag = mgva->med1_eps_diag; + vector3 med2_eps_diag = mgva->med2_eps_diag; + double eps1 = (med1_eps_diag.x + med1_eps_diag.y + med1_eps_diag.z)/3; + double eps2 = (med2_eps_diag.x + med2_eps_diag.y + med2_eps_diag.z)/3; cnumber ret; - double r2 = voxel_rad*voxel_rad; - double z2 = (p.x-voxel_cen.x)*(p.x-voxel_cen.x) + (p.y-voxel_cen.y)*(p.y-voxel_cen.y); - double w = 2*sqrt(r2 - z2)/(meep::pi*r2); - double ep = geomeps->chi1p1(func_ft, vector3_to_vec(p)); - if (ep < 0) eps_ever_negative = 1; - ret.re = ep * s; - ret.im = s / ep; + ret.re = u_proj*eps1 + (1-u_proj)*eps2; + ret.im = u_proj/eps1 + (1-u_proj)/eps2; + double w = 0; + if (mgva->dim == meep::D1) + w = 1/(2*mgva->rad); + else if (mgva->dim == meep::D2) + w = 2*sqrt(mgva->rad*mgva->rad - z*z)/(meep::pi * mgva->rad*mgva->rad); + else if (mgva->dim == meep::D3) + w = meep::pi*(mgva->rad*mgva->rad - z*z)/(4/3 * meep::pi * mgva->rad*mgva->rad*mgva->rad); return ret * w; } #else -static number matgrid_eps_func(int n, number *x, void *geomeps_) { - geom_epsilon *geomeps = (geom_epsilon *)geomeps_; - vector3 p = {0, 0, 0}; - double s = 1; - p.x = x[0]; - p.y = n > 1 ? x[1] : 0; - p.z = n > 2 ? x[2] : 0; - if (dim == meep::Dcyl) { - double py = p.y; - p.y = p.z; - p.z = py; - s = p.x; - } - double r2 = voxel_rad*voxel_rad; - double z2 = (p.x-voxel_cen.x)*(p.x-voxel_cen.x) + (p.y-voxel_cen.y)*(p.y-voxel_cen.y); - double w = 2*sqrt(r2 - z2)/(meep::pi*r2); - double ep = geomeps->chi1p1(func_ft, vector3_to_vec(p)); - if (ep < 0) eps_ever_negative = 1; - return (ep * s) * w; -} -static number matgrid_inveps_func(int n, number *x, void *geomeps_) { - geom_epsilon *geomeps = (geom_epsilon *)geomeps_; - vector3 p = {0, 0, 0}; - double s = 1; - p.x = x[0]; - p.y = n > 1 ? x[1] : 0; - p.z = n > 2 ? x[2] : 0; - if (dim == meep::Dcyl) { - double py = p.y; - p.y = p.z; - p.z = py; - s = p.x; - } - double r2 = voxel_rad*voxel_rad; - double z2 = (p.x-voxel_cen.x)*(p.x-voxel_cen.x) + (p.y-voxel_cen.y)*(p.y-voxel_cen.y); - double w = 2*sqrt(r2 - z2)/(meep::pi*r2); - double ep = geomeps->chi1p1(func_ft, vector3_to_vec(p)); - if (ep < 0) eps_ever_negative = 1; - return (s / ep) * w; +static number matgrid_eps_func(int n, number *x, void *mgva_) { + matgrid_volavg *mgva = (matgrid_volavg *)mgva_; + double z = x[0]; + double u = mgva->uval + mgva->ugrad_abs*z; + double tanh_beta_eta = tanh(mgva->beta*mgva->eta); + double u_proj = (tanh_beta_eta + tanh(mgva->beta*(u-mgva->eta))) / + (tanh_beta_eta + tanh(mgva->beta*(1-mgva->eta))); + vector3 med1_eps_diag = mgva->med1_eps_diag; + vector3 med2_eps_diag = mgva->med2_eps_diag; + double eps1 = (med1_eps_diag.x + med1_eps_diag.y + med1_eps_diag.z)/3; + double eps2 = (med2_eps_diag.x + med2_eps_diag.y + med2_eps_diag.z)/3; + double eps_interp = u_proj*eps1 + (1-u_proj)*eps2; + double w = 0; + if (mgva->dim == meep::D1) + w = 1/(2*mgva->rad); + else if (mgva->dim == meep::D2) + w = 2*sqrt(mgva->rad*mgva->rad - z*z)/(meep::pi * mgva->rad*mgva->rad); + else if (mgva->dim == meep::D3) + w = meep::pi*(mgva->rad*mgva->rad - z*z)/(4/3 * meep::pi * mgva->rad*mgva->rad*mgva->rad); + return eps_interp * w; +} +static number matgrid_inveps_func(int n, number *x, void *mgva_) { + matgrid_volavg *mgva = (matgrid_volavg *)mgva_; + double z = x[0]; + double u = mgva->uval + mgva->ugrad_abs*z; + double tanh_beta_eta = tanh(mgva->beta*mgva->eta); + double u_proj = (tanh_beta_eta + tanh(mgva->beta*(u-mgva->eta))) / + (tanh_beta_eta + tanh(mgva->beta*(1-mgva->eta))); + vector3 med1_eps_diag = mgva->med1_eps_diag; + vector3 med2_eps_diag = mgva->med2_eps_diag; + double eps1 = (med1_eps_diag.x + med1_eps_diag.y + med1_eps_diag.z)/3; + double eps2 = (med2_eps_diag.x + med2_eps_diag.y + med2_eps_diag.z)/3; + double epsinv_interp = u_proj/eps1 + (1-u_proj)/eps2; + double w = 0; + if (mgva->dim == meep::D1) + w = 1/(2*mgva->rad); + else if (mgva->dim == meep::D2) + w = 2*sqrt(mgva->rad*mgva->rad - z*z)/(meep::pi * mgva->rad*mgva->rad); + else if (mgva->dim == meep::D3) + w = meep::pi*(mgva->rad*mgva->rad - z*z)/(4/3 * meep::pi * mgva->rad*mgva->rad*mgva->rad); + return epsinv_interp * w; } #endif #ifdef CTL_HAS_COMPLEX_INTEGRATION -static cnumber ceps_func(int n, number *x, void *geomeps_) { +static cnumber ceps_func(int n, number *x, void *mgva_) { geom_epsilon *geomeps = (geom_epsilon *)geomeps_; vector3 p = {0, 0, 0}; p.x = x[0]; @@ -1320,27 +1331,36 @@ void geom_epsilon::fallback_chi1inv_row(meep::component c, double chi1inv_row[3] } number esterr; - integer errflag, n; + integer errflag; number xmin[3], xmax[3]; - double vol = 1; + double meps, minveps; + if (md->which_subclass == material_data::MATERIAL_GRID) { - // integrate along a line in the direction of the normal vector through the center of a circular voxel - // for a normal vector at an oblique angle, start with a horizontal line through (-D/2,0) and (+D/2,0) - // and apply counter clockwise rotation through the z-axis using the direction angle of the normal vector - double theta = atan(gradient.y()/gradient.x()); - voxel_rad = v.diameter()/2; - voxel_cen = p; - xmin[0] = -cos(theta)*voxel_rad + p.x; - xmin[1] = -sin(theta)*voxel_rad + p.y; - xmin[2] = 0; - xmax[0] = cos(theta)*voxel_rad + p.x; - xmax[1] = sin(theta)*voxel_rad + p.y; - xmax[2] = 0; - n = 2; - vol = 2*voxel_rad; + matgrid_volavg *mgva; + mgva->dim = v.dim; + mgva->ugrad_abs = meep::abs(gradient); + mgva->uval = material_grid_val(p, md); + mgva->rad = v.diameter()/2; + mgva->beta = md->beta; + mgva->eta = md->eta; + mgva->med1_eps_diag = md->medium_1.epsilon_diag; + mgva->med2_eps_diag = md->medium_2.epsilon_diag; + xmin[0] = -v.diameter()/2; xmin[1] = 0; xmin[2] = 0; + xmax[0] = v.diameter()/2; xmax[1] = 0; xmax[2] = 0; +#ifdef CTL_HAS_COMPLEX_INTEGRATION + cnumber ret = cadaptive_integration(matgrid_ceps_func, xmin, xmax, 1, (void *)mgva, 0, tol, maxeval, + &esterr, &errflag); + meps = ret.re; + minveps = ret.im; +#else + meps = adaptive_integration(matgrid_eps_func, xmin, xmax, 1, (void *)mgva, 0, tol, maxeval, &esterr, + &errflag); + minveps = adaptive_integration(matgrid_inveps_func, xmin, xmax, 1, (void *)mgva, 0, tol, maxeval, &esterr, + &errflag); +#endif } else { - // quadrature over entire voxel from one corner of cube to the other + integer n; vector3 gvmin, gvmax; gvmin = vec_to_vector3(v.get_min_corner()); gvmax = vec_to_vector3(v.get_max_corner()); @@ -1362,31 +1382,26 @@ void geom_epsilon::fallback_chi1inv_row(meep::component c, double chi1inv_row[3] n = xmin[1] == xmax[1] ? 1 : 2; else n = 3; + double vol = 1; for (int i = 0; i < n; ++i) vol *= xmax[i] - xmin[i]; if (dim == meep::Dcyl) vol *= (xmin[0] + xmax[0]) * 0.5; - } - - eps_ever_negative = 0; - func_ft = meep::type(c); - double meps, minveps; + eps_ever_negative = 0; + func_ft = meep::type(c); #ifdef CTL_HAS_COMPLEX_INTEGRATION - cnumber ret = cadaptive_integration((md->which_subclass == material_data::MATERIAL_GRID) ? matgrid_ceps_func: ceps_func, - xmin, xmax, n, (void *)this, 0, tol, maxeval, - &esterr, &errflag); - meps = ret.re / vol; - minveps = ret.im / vol; + cnumber ret = cadaptive_integration(ceps_func, xmin, xmax, n, (void *)this, 0, tol, maxeval, + &esterr, &errflag); + meps = ret.re / vol; + minveps = ret.im / vol; #else - meps = adaptive_integration((md->which_subclass == material_data::MATERIAL_GRID) ? matgrid_eps_func : eps_func, xmin, xmax, n, (void *)this, 0, tol, maxeval, &esterr, - &errflag) / - vol; - minveps = adaptive_integration((md->which_subclass == material_data::MATERIAL_GRID) ? matgrid_inveps_func : inveps_func, xmin, xmax, n, (void *)this, 0, tol, maxeval, &esterr, - &errflag) / - vol; + meps = adaptive_integration(eps_func, xmin, xmax, n, (void *)this, 0, tol, maxeval, &esterr, + &errflag) / vol; + minveps = adaptive_integration(inveps_func, xmin, xmax, n, (void *)this, 0, tol, maxeval, &esterr, + &errflag) / vol; #endif - - if (eps_ever_negative) // averaging negative eps causes instability - minveps = 1.0 / (meps = eps(v.center())); + if (eps_ever_negative) // averaging negative eps causes instability + minveps = 1.0 / (meps = eps(v.center())); + } { double n[3] = {0, 0, 0}; From 829ca01744db58e5e7207436fc860b1ba2e68850 Mon Sep 17 00:00:00 2001 From: Ardavan Oskooi Date: Sun, 23 May 2021 22:32:58 -0700 Subject: [PATCH 04/15] compute weights array at voxel center using geom_box coordinates --- src/meepgeom.cpp | 77 +++++++++++++++++++++++------------------------- 1 file changed, 37 insertions(+), 40 deletions(-) diff --git a/src/meepgeom.cpp b/src/meepgeom.cpp index fb6004811..6a95e03d9 100644 --- a/src/meepgeom.cpp +++ b/src/meepgeom.cpp @@ -381,13 +381,13 @@ void map_lattice_coordinates(double &px, double &py, double &pz) { } meep::vec matgrid_grad(vector3 p, geom_box_tree tp, int oi, material_data *md) { - meep::vec gradient(zero_vec(dim)); - int matgrid_val_count = 0; - if (md->material_grid_kinds == material_data::U_MIN || md->material_grid_kinds == material_data::U_PROD) meep::abort("%s:%i:matgrid_grad does not support overlapping grids with U_MIN or U_PROD\n",__FILE__,__LINE__); + meep::vec gradient(zero_vec(dim)); + int matgrid_val_count = 0; + // iterate through object tree at current point if (tp) { do { @@ -417,7 +417,6 @@ double material_grid_val(vector3 p, material_data *md) { if (!is_material_grid(md)) { meep::abort("Invalid material grid detected.\n"); } return meep::linear_interpolate(p.x, p.y, p.z, md->weights, md->grid_size.x, md->grid_size.y, md->grid_size.z, 1); - } static double tanh_projection(double u, double beta, double eta) { @@ -1159,11 +1158,8 @@ struct matgrid_volavg { #ifdef CTL_HAS_COMPLEX_INTEGRATION static cnumber matgrid_ceps_func(int n, number *x, void *mgva_) { matgrid_volavg *mgva = (matgrid_volavg *)mgva_; - double z = x[0]; - double u = mgva->uval + mgva->ugrad_abs*z; - double tanh_beta_eta = tanh(mgva->beta*mgva->eta); - double u_proj = (tanh_beta_eta + tanh(mgva->beta*(u-mgva->eta))) / - (tanh_beta_eta + tanh(mgva->beta*(1-mgva->eta))); + double u_proj = tanh_projection(mgva->uval + mgva->ugrad_abs*x[0], + mgva->beta, mgva->eta); vector3 med1_eps_diag = mgva->med1_eps_diag; vector3 med2_eps_diag = mgva->med2_eps_diag; double eps1 = (med1_eps_diag.x + med1_eps_diag.y + med1_eps_diag.z)/3; @@ -1175,19 +1171,16 @@ static cnumber matgrid_ceps_func(int n, number *x, void *mgva_) { if (mgva->dim == meep::D1) w = 1/(2*mgva->rad); else if (mgva->dim == meep::D2) - w = 2*sqrt(mgva->rad*mgva->rad - z*z)/(meep::pi * mgva->rad*mgva->rad); + w = 2*sqrt(mgva->rad*mgva->rad - x[0]*x[0])/(meep::pi * mgva->rad*mgva->rad); else if (mgva->dim == meep::D3) - w = meep::pi*(mgva->rad*mgva->rad - z*z)/(4/3 * meep::pi * mgva->rad*mgva->rad*mgva->rad); + w = meep::pi*(mgva->rad*mgva->rad - x[0]*x[0])/(4/3 * meep::pi * mgva->rad*mgva->rad*mgva->rad); return ret * w; } #else static number matgrid_eps_func(int n, number *x, void *mgva_) { matgrid_volavg *mgva = (matgrid_volavg *)mgva_; - double z = x[0]; - double u = mgva->uval + mgva->ugrad_abs*z; - double tanh_beta_eta = tanh(mgva->beta*mgva->eta); - double u_proj = (tanh_beta_eta + tanh(mgva->beta*(u-mgva->eta))) / - (tanh_beta_eta + tanh(mgva->beta*(1-mgva->eta))); + double u_proj = tanh_projection(mgva->uval + mgva->ugrad_abs*x[0], + mgva->beta, mgva->eta); vector3 med1_eps_diag = mgva->med1_eps_diag; vector3 med2_eps_diag = mgva->med2_eps_diag; double eps1 = (med1_eps_diag.x + med1_eps_diag.y + med1_eps_diag.z)/3; @@ -1197,18 +1190,15 @@ static number matgrid_eps_func(int n, number *x, void *mgva_) { if (mgva->dim == meep::D1) w = 1/(2*mgva->rad); else if (mgva->dim == meep::D2) - w = 2*sqrt(mgva->rad*mgva->rad - z*z)/(meep::pi * mgva->rad*mgva->rad); + w = 2*sqrt(mgva->rad*mgva->rad - x[0]*x[0])/(meep::pi * mgva->rad*mgva->rad); else if (mgva->dim == meep::D3) - w = meep::pi*(mgva->rad*mgva->rad - z*z)/(4/3 * meep::pi * mgva->rad*mgva->rad*mgva->rad); + w = meep::pi*(mgva->rad*mgva->rad - x[0]*x[0])/(4/3 * meep::pi * mgva->rad*mgva->rad*mgva->rad); return eps_interp * w; } static number matgrid_inveps_func(int n, number *x, void *mgva_) { matgrid_volavg *mgva = (matgrid_volavg *)mgva_; - double z = x[0]; - double u = mgva->uval + mgva->ugrad_abs*z; - double tanh_beta_eta = tanh(mgva->beta*mgva->eta); - double u_proj = (tanh_beta_eta + tanh(mgva->beta*(u-mgva->eta))) / - (tanh_beta_eta + tanh(mgva->beta*(1-mgva->eta))); + double u_proj = tanh_projection(mgva->uval + mgva->ugrad_abs*x[0], + mgva->beta, mgva->eta); vector3 med1_eps_diag = mgva->med1_eps_diag; vector3 med2_eps_diag = mgva->med2_eps_diag; double eps1 = (med1_eps_diag.x + med1_eps_diag.y + med1_eps_diag.z)/3; @@ -1218,15 +1208,15 @@ static number matgrid_inveps_func(int n, number *x, void *mgva_) { if (mgva->dim == meep::D1) w = 1/(2*mgva->rad); else if (mgva->dim == meep::D2) - w = 2*sqrt(mgva->rad*mgva->rad - z*z)/(meep::pi * mgva->rad*mgva->rad); + w = 2*sqrt(mgva->rad*mgva->rad - x[0]*x[0])/(meep::pi * mgva->rad*mgva->rad); else if (mgva->dim == meep::D3) - w = meep::pi*(mgva->rad*mgva->rad - z*z)/(4/3 * meep::pi * mgva->rad*mgva->rad*mgva->rad); + w = meep::pi*(mgva->rad*mgva->rad - x[0]*x[0])/(4/3 * meep::pi * mgva->rad*mgva->rad*mgva->rad); return epsinv_interp * w; } #endif #ifdef CTL_HAS_COMPLEX_INTEGRATION -static cnumber ceps_func(int n, number *x, void *mgva_) { +static cnumber ceps_func(int n, number *x, void *geomeps_) { geom_epsilon *geomeps = (geom_epsilon *)geomeps_; vector3 p = {0, 0, 0}; p.x = x[0]; @@ -1295,12 +1285,15 @@ void geom_epsilon::fallback_chi1inv_row(meep::component c, double chi1inv_row[3] (material_type)material_of_unshifted_point_in_tree_inobject(p, restricted_tree, &inobject); material_data *md = material; meep::vec gradient(zero_vec(v.dim)); + double uval = 0; if (md->which_subclass == material_data::MATERIAL_GRID) { geom_box_tree tp; int oi; tp = geom_tree_search(p, restricted_tree, &oi); gradient = matgrid_grad(p, tp, oi, md); + uval = material_grid_val(to_geom_box_coords(p, &tp->objects[oi]), + (material_data *)tp->objects[oi].o->material); } else { gradient = normal_vector(meep::type(c), v); @@ -1336,26 +1329,30 @@ void geom_epsilon::fallback_chi1inv_row(meep::component c, double chi1inv_row[3] double meps, minveps; if (md->which_subclass == material_data::MATERIAL_GRID) { - matgrid_volavg *mgva; - mgva->dim = v.dim; - mgva->ugrad_abs = meep::abs(gradient); - mgva->uval = material_grid_val(p, md); - mgva->rad = v.diameter()/2; - mgva->beta = md->beta; - mgva->eta = md->eta; - mgva->med1_eps_diag = md->medium_1.epsilon_diag; - mgva->med2_eps_diag = md->medium_2.epsilon_diag; - xmin[0] = -v.diameter()/2; xmin[1] = 0; xmin[2] = 0; - xmax[0] = v.diameter()/2; xmax[1] = 0; xmax[2] = 0; + matgrid_volavg mgva; + mgva.dim = v.dim; + mgva.ugrad_abs = meep::abs(gradient); + mgva.uval = uval; + mgva.rad = v.diameter()/2; + mgva.beta = md->beta; + mgva.eta = md->eta; + mgva.med1_eps_diag = md->medium_1.epsilon_diag; + mgva.med2_eps_diag = md->medium_2.epsilon_diag; + xmin[0] = -v.diameter()/2; + xmin[1] = 0; + xmin[2] = 0; + xmax[0] = v.diameter()/2; + xmax[1] = 0; + xmax[2] = 0; #ifdef CTL_HAS_COMPLEX_INTEGRATION - cnumber ret = cadaptive_integration(matgrid_ceps_func, xmin, xmax, 1, (void *)mgva, 0, tol, maxeval, + cnumber ret = cadaptive_integration(matgrid_ceps_func, xmin, xmax, 1, (void *)&mgva, 0, tol, maxeval, &esterr, &errflag); meps = ret.re; minveps = ret.im; #else - meps = adaptive_integration(matgrid_eps_func, xmin, xmax, 1, (void *)mgva, 0, tol, maxeval, &esterr, + meps = adaptive_integration(matgrid_eps_func, xmin, xmax, 1, (void *)&mgva, 0, tol, maxeval, &esterr, &errflag); - minveps = adaptive_integration(matgrid_inveps_func, xmin, xmax, 1, (void *)mgva, 0, tol, maxeval, &esterr, + minveps = adaptive_integration(matgrid_inveps_func, xmin, xmax, 1, (void *)&mgva, 0, tol, maxeval, &esterr, &errflag); #endif } From 28f7b306d44d3efc02df16e32b945ca7204b7146 Mon Sep 17 00:00:00 2001 From: Ardavan Oskooi Date: Thu, 27 May 2021 10:29:44 -0700 Subject: [PATCH 05/15] flip weights for two materials when computing averaged quantities --- src/meepgeom.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/meepgeom.cpp b/src/meepgeom.cpp index 6a95e03d9..ca788530c 100644 --- a/src/meepgeom.cpp +++ b/src/meepgeom.cpp @@ -1185,7 +1185,7 @@ static number matgrid_eps_func(int n, number *x, void *mgva_) { vector3 med2_eps_diag = mgva->med2_eps_diag; double eps1 = (med1_eps_diag.x + med1_eps_diag.y + med1_eps_diag.z)/3; double eps2 = (med2_eps_diag.x + med2_eps_diag.y + med2_eps_diag.z)/3; - double eps_interp = u_proj*eps1 + (1-u_proj)*eps2; + double eps_interp = (1-u_proj)*eps1 + u_proj*eps2; double w = 0; if (mgva->dim == meep::D1) w = 1/(2*mgva->rad); @@ -1203,7 +1203,7 @@ static number matgrid_inveps_func(int n, number *x, void *mgva_) { vector3 med2_eps_diag = mgva->med2_eps_diag; double eps1 = (med1_eps_diag.x + med1_eps_diag.y + med1_eps_diag.z)/3; double eps2 = (med2_eps_diag.x + med2_eps_diag.y + med2_eps_diag.z)/3; - double epsinv_interp = u_proj/eps1 + (1-u_proj)/eps2; + double epsinv_interp = (1-u_proj)/eps1 + u_proj/eps2; double w = 0; if (mgva->dim == meep::D1) w = 1/(2*mgva->rad); @@ -1322,7 +1322,6 @@ void geom_epsilon::fallback_chi1inv_row(meep::component c, double chi1inv_row[3] } return; } - number esterr; integer errflag; number xmin[3], xmax[3]; @@ -1399,7 +1398,6 @@ void geom_epsilon::fallback_chi1inv_row(meep::component c, double chi1inv_row[3] if (eps_ever_negative) // averaging negative eps causes instability minveps = 1.0 / (meps = eps(v.center())); } - { double n[3] = {0, 0, 0}; double nabsinv = 1.0 / meep::abs(gradient); From f111705f45dc21ae11a6552b3d9d81a1c84c3250 Mon Sep 17 00:00:00 2001 From: Ardavan Oskooi Date: Thu, 27 May 2021 17:39:29 -0700 Subject: [PATCH 06/15] add support for overlapping grids --- src/meepgeom.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/meepgeom.cpp b/src/meepgeom.cpp index ca788530c..90c0b447d 100644 --- a/src/meepgeom.cpp +++ b/src/meepgeom.cpp @@ -417,6 +417,7 @@ double material_grid_val(vector3 p, material_data *md) { if (!is_material_grid(md)) { meep::abort("Invalid material grid detected.\n"); } return meep::linear_interpolate(p.x, p.y, p.z, md->weights, md->grid_size.x, md->grid_size.y, md->grid_size.z, 1); + } static double tanh_projection(double u, double beta, double eta) { @@ -458,14 +459,12 @@ double matgrid_val(vector3 p, geom_box_tree tp, int oi, material_data *md) { ++matgrid_val_count; } - double u_interp = (md->material_grid_kinds == material_data::U_MIN - ? umin - : (md->material_grid_kinds == material_data::U_PROD - ? uprod - : (md->material_grid_kinds == material_data::U_MEAN ? usum / matgrid_val_count - : udefault))); - - return (md->beta != 0) ? tanh_projection(u_interp, md->beta, md->eta) : u_interp; + return (md->material_grid_kinds == material_data::U_MIN + ? umin + : (md->material_grid_kinds == material_data::U_PROD + ? uprod + : (md->material_grid_kinds == material_data::U_MEAN ? usum / matgrid_val_count + : udefault))); } static void cinterp_tensors(vector3 diag_in_1, cvector3 offdiag_in_1, vector3 diag_in_2, cvector3 offdiag_in_2, vector3 *diag_out, cvector3 *offdiag_out, @@ -808,6 +807,7 @@ void geom_epsilon::get_material_pt(material_type &material, const meep::vec &r) tp = geom_tree_search(p, restricted_tree, &oi); // interpolate and (possibly) project onto material grid u = matgrid_val(p, tp, oi, md); + if (md->beta != 0) u = tanh_projection(u, md->beta, md->eta); // interpolate material from material grid point epsilon_material_grid(md, u); @@ -1165,8 +1165,8 @@ static cnumber matgrid_ceps_func(int n, number *x, void *mgva_) { double eps1 = (med1_eps_diag.x + med1_eps_diag.y + med1_eps_diag.z)/3; double eps2 = (med2_eps_diag.x + med2_eps_diag.y + med2_eps_diag.z)/3; cnumber ret; - ret.re = u_proj*eps1 + (1-u_proj)*eps2; - ret.im = u_proj/eps1 + (1-u_proj)/eps2; + ret.re = (1-u_proj)*eps1 + u_proj*eps2; + ret.im = (1-u_proj)/eps1 + u_proj/eps2; double w = 0; if (mgva->dim == meep::D1) w = 1/(2*mgva->rad); @@ -1292,8 +1292,7 @@ void geom_epsilon::fallback_chi1inv_row(meep::component c, double chi1inv_row[3] int oi; tp = geom_tree_search(p, restricted_tree, &oi); gradient = matgrid_grad(p, tp, oi, md); - uval = material_grid_val(to_geom_box_coords(p, &tp->objects[oi]), - (material_data *)tp->objects[oi].o->material); + uval = matgrid_val(p, tp, oi, md); } else { gradient = normal_vector(meep::type(c), v); @@ -1633,6 +1632,7 @@ void geom_epsilon::sigma_row(meep::component c, double sigrow[3], const meep::ve tp = geom_tree_search(p, restricted_tree, &oi); u = matgrid_val(p, tp, oi, mat); // interpolate onto material grid + if (mat->beta != 0) tanh_projection(u, mat->beta, mat->eta); epsilon_material_grid(mat, u); // interpolate material from material grid point check_offdiag(&mat->medium); } From e85f272127fbcad494982acc219c4b56bfd34037 Mon Sep 17 00:00:00 2001 From: Ardavan Oskooi Date: Sat, 5 Jun 2021 15:44:55 -0700 Subject: [PATCH 07/15] compute gradients with respect to x,y,z coordinates rather than dx,dy,dz using chain rule --- src/meepgeom.cpp | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/src/meepgeom.cpp b/src/meepgeom.cpp index 90c0b447d..501c215e7 100644 --- a/src/meepgeom.cpp +++ b/src/meepgeom.cpp @@ -364,11 +364,15 @@ meep::vec material_grid_grad(vector3 p, material_data *md) { #undef D - gradient.set_direction(meep::X, du_dx); - gradient.set_direction(meep::Y, du_dy); - gradient.set_direction(meep::Z, du_dz); + // to obtain the gradient with respect to the rx,ry,rz + // coordinates rather than dx,dy,dz we use the chain + // rule which therefore ends up multiplying each + // component by nx,ny,nz respectively (see map_coordinates) + gradient.set_direction(meep::X, du_dx * nx); + gradient.set_direction(meep::Y, du_dy * ny); + gradient.set_direction(meep::Z, du_dz * ny); - return (abs(gradient) < 1e-8) ? zero_vec(dim) : gradient; + return gradient; } void map_lattice_coordinates(double &px, double &py, double &pz) { @@ -1158,8 +1162,8 @@ struct matgrid_volavg { #ifdef CTL_HAS_COMPLEX_INTEGRATION static cnumber matgrid_ceps_func(int n, number *x, void *mgva_) { matgrid_volavg *mgva = (matgrid_volavg *)mgva_; - double u_proj = tanh_projection(mgva->uval + mgva->ugrad_abs*x[0], - mgva->beta, mgva->eta); + double u_proj = mgva->uval + mgva->ugrad_abs*x[0]; + if (mgva->beta != 0) u_proj = tanh_projection(u_proj, mgva->beta, mgva->eta); vector3 med1_eps_diag = mgva->med1_eps_diag; vector3 med2_eps_diag = mgva->med2_eps_diag; double eps1 = (med1_eps_diag.x + med1_eps_diag.y + med1_eps_diag.z)/3; @@ -1179,8 +1183,8 @@ static cnumber matgrid_ceps_func(int n, number *x, void *mgva_) { #else static number matgrid_eps_func(int n, number *x, void *mgva_) { matgrid_volavg *mgva = (matgrid_volavg *)mgva_; - double u_proj = tanh_projection(mgva->uval + mgva->ugrad_abs*x[0], - mgva->beta, mgva->eta); + double u_proj = mgva->uval + mgva->ugrad_abs*x[0]; + if (mgva->beta != 0) u_proj = tanh_projection(u_proj, mgva->beta, mgva->eta); vector3 med1_eps_diag = mgva->med1_eps_diag; vector3 med2_eps_diag = mgva->med2_eps_diag; double eps1 = (med1_eps_diag.x + med1_eps_diag.y + med1_eps_diag.z)/3; @@ -1197,8 +1201,8 @@ static number matgrid_eps_func(int n, number *x, void *mgva_) { } static number matgrid_inveps_func(int n, number *x, void *mgva_) { matgrid_volavg *mgva = (matgrid_volavg *)mgva_; - double u_proj = tanh_projection(mgva->uval + mgva->ugrad_abs*x[0], - mgva->beta, mgva->eta); + double u_proj = mgva->uval + mgva->ugrad_abs*x[0]; + if (mgva->beta != 0) u_proj = tanh_projection(u_proj, mgva->beta, mgva->eta); vector3 med1_eps_diag = mgva->med1_eps_diag; vector3 med2_eps_diag = mgva->med2_eps_diag; double eps1 = (med1_eps_diag.x + med1_eps_diag.y + med1_eps_diag.z)/3; @@ -1323,10 +1327,10 @@ void geom_epsilon::fallback_chi1inv_row(meep::component c, double chi1inv_row[3] } number esterr; integer errflag; - number xmin[3], xmax[3]; double meps, minveps; if (md->which_subclass == material_data::MATERIAL_GRID) { + number xmin[1], xmax[1]; matgrid_volavg mgva; mgva.dim = v.dim; mgva.ugrad_abs = meep::abs(gradient); @@ -1337,11 +1341,7 @@ void geom_epsilon::fallback_chi1inv_row(meep::component c, double chi1inv_row[3] mgva.med1_eps_diag = md->medium_1.epsilon_diag; mgva.med2_eps_diag = md->medium_2.epsilon_diag; xmin[0] = -v.diameter()/2; - xmin[1] = 0; - xmin[2] = 0; xmax[0] = v.diameter()/2; - xmax[1] = 0; - xmax[2] = 0; #ifdef CTL_HAS_COMPLEX_INTEGRATION cnumber ret = cadaptive_integration(matgrid_ceps_func, xmin, xmax, 1, (void *)&mgva, 0, tol, maxeval, &esterr, &errflag); @@ -1356,6 +1356,7 @@ void geom_epsilon::fallback_chi1inv_row(meep::component c, double chi1inv_row[3] } else { integer n; + number xmin[3], xmax[3]; vector3 gvmin, gvmax; gvmin = vec_to_vector3(v.get_min_corner()); gvmax = vec_to_vector3(v.get_max_corner()); From 691e3b1cb472bc03f1f6402a94defb0325becb44 Mon Sep 17 00:00:00 2001 From: Ardavan Oskooi Date: Sat, 5 Jun 2021 17:49:03 -0700 Subject: [PATCH 08/15] fix bug in scaling of gradient in z direction --- src/meepgeom.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/meepgeom.cpp b/src/meepgeom.cpp index 501c215e7..cbe9a4cf1 100644 --- a/src/meepgeom.cpp +++ b/src/meepgeom.cpp @@ -370,7 +370,7 @@ meep::vec material_grid_grad(vector3 p, material_data *md) { // component by nx,ny,nz respectively (see map_coordinates) gradient.set_direction(meep::X, du_dx * nx); gradient.set_direction(meep::Y, du_dy * ny); - gradient.set_direction(meep::Z, du_dz * ny); + gradient.set_direction(meep::Z, du_dz * nz); return gradient; } @@ -1395,9 +1395,9 @@ void geom_epsilon::fallback_chi1inv_row(meep::component c, double chi1inv_row[3] minveps = adaptive_integration(inveps_func, xmin, xmax, n, (void *)this, 0, tol, maxeval, &esterr, &errflag) / vol; #endif - if (eps_ever_negative) // averaging negative eps causes instability - minveps = 1.0 / (meps = eps(v.center())); } + if (eps_ever_negative) // averaging negative eps causes instability + minveps = 1.0 / (meps = eps(v.center())); { double n[3] = {0, 0, 0}; double nabsinv = 1.0 / meep::abs(gradient); From aa1bedd70eb0a4e8cb73fa45ff88eef135ae817b Mon Sep 17 00:00:00 2001 From: Ardavan Oskooi Date: Sat, 5 Jun 2021 22:02:09 -0700 Subject: [PATCH 09/15] a few simplifications --- src/meepgeom.cpp | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/src/meepgeom.cpp b/src/meepgeom.cpp index cbe9a4cf1..b287c0553 100644 --- a/src/meepgeom.cpp +++ b/src/meepgeom.cpp @@ -425,11 +425,10 @@ double material_grid_val(vector3 p, material_data *md) { } static double tanh_projection(double u, double beta, double eta) { - double u_proj = 0; + if (beta == 0) return u; double tanh_beta_eta = tanh(beta*eta); - u_proj = (tanh_beta_eta + tanh(beta*(u-eta))) / + return (tanh_beta_eta + tanh(beta*(u-eta))) / (tanh_beta_eta + tanh(beta*(1-eta))); - return u_proj; } double matgrid_val(vector3 p, geom_box_tree tp, int oi, material_data *md) { @@ -809,9 +808,8 @@ void geom_epsilon::get_material_pt(material_type &material, const meep::vec &r) geom_box_tree tp; tp = geom_tree_search(p, restricted_tree, &oi); - // interpolate and (possibly) project onto material grid - u = matgrid_val(p, tp, oi, md); - if (md->beta != 0) u = tanh_projection(u, md->beta, md->eta); + // interpolate and project onto material grid + u = tanh_projection(matgrid_val(p, tp, oi, md), md->beta, md->eta); // interpolate material from material grid point epsilon_material_grid(md, u); @@ -1162,8 +1160,8 @@ struct matgrid_volavg { #ifdef CTL_HAS_COMPLEX_INTEGRATION static cnumber matgrid_ceps_func(int n, number *x, void *mgva_) { matgrid_volavg *mgva = (matgrid_volavg *)mgva_; - double u_proj = mgva->uval + mgva->ugrad_abs*x[0]; - if (mgva->beta != 0) u_proj = tanh_projection(u_proj, mgva->beta, mgva->eta); + // use a linear approximation for the material grid weights around the Yee grid point + double u_proj = tanh_projection(mgva->uval + mgva->ugrad_abs*x[0], mgva->beta, mgva->eta); vector3 med1_eps_diag = mgva->med1_eps_diag; vector3 med2_eps_diag = mgva->med2_eps_diag; double eps1 = (med1_eps_diag.x + med1_eps_diag.y + med1_eps_diag.z)/3; @@ -1183,8 +1181,8 @@ static cnumber matgrid_ceps_func(int n, number *x, void *mgva_) { #else static number matgrid_eps_func(int n, number *x, void *mgva_) { matgrid_volavg *mgva = (matgrid_volavg *)mgva_; - double u_proj = mgva->uval + mgva->ugrad_abs*x[0]; - if (mgva->beta != 0) u_proj = tanh_projection(u_proj, mgva->beta, mgva->eta); + // use a linear approximation for the material grid weights around the Yee grid point + double u_proj = tanh_projection(mgva->uval + mgva->ugrad_abs*x[0], mgva->beta, mgva->eta); vector3 med1_eps_diag = mgva->med1_eps_diag; vector3 med2_eps_diag = mgva->med2_eps_diag; double eps1 = (med1_eps_diag.x + med1_eps_diag.y + med1_eps_diag.z)/3; @@ -1201,8 +1199,8 @@ static number matgrid_eps_func(int n, number *x, void *mgva_) { } static number matgrid_inveps_func(int n, number *x, void *mgva_) { matgrid_volavg *mgva = (matgrid_volavg *)mgva_; - double u_proj = mgva->uval + mgva->ugrad_abs*x[0]; - if (mgva->beta != 0) u_proj = tanh_projection(u_proj, mgva->beta, mgva->eta); + // use a linear approximation for the material grid weights around the Yee grid point + double u_proj = tanh_projection(mgva->uval + mgva->ugrad_abs*x[0], mgva->beta, mgva->eta); vector3 med1_eps_diag = mgva->med1_eps_diag; vector3 med2_eps_diag = mgva->med2_eps_diag; double eps1 = (med1_eps_diag.x + med1_eps_diag.y + med1_eps_diag.z)/3; @@ -1632,8 +1630,8 @@ void geom_epsilon::sigma_row(meep::component c, double sigrow[3], const meep::ve geom_box_tree tp; tp = geom_tree_search(p, restricted_tree, &oi); - u = matgrid_val(p, tp, oi, mat); // interpolate onto material grid - if (mat->beta != 0) tanh_projection(u, mat->beta, mat->eta); + // interpolate and project onto material grid + u = tanh_projection(matgrid_val(p, tp, oi, mat), mat->beta, mat->eta); epsilon_material_grid(mat, u); // interpolate material from material grid point check_offdiag(&mat->medium); } @@ -2705,8 +2703,7 @@ void material_grids_addgradient_point(double *v, std::complex fields_a, vector3 sz = mg->grid_size; double *vcur = v; double *ucur = mg->weights; - uval = material_grid_val(p, mg); - if (mg->beta != 0) uval = tanh_projection(uval, mg->beta, mg->eta); + uval = tanh_projection(material_grid_val(p, mg), mg->beta, mg->eta); add_interpolate_weights(p.x, p.y, p.z, vcur, sz.x, sz.y, sz.z, 1, get_material_gradient(uval, fields_a, fields_f, freq, mg, field_dir) * scalegrad, From 84162fcead3f38880a1a5a9a53240c39ac3fa255 Mon Sep 17 00:00:00 2001 From: Ardavan Oskooi Date: Thu, 17 Jun 2021 23:56:24 -0700 Subject: [PATCH 10/15] compute gradient of the weights array with respect to the coordinates of the geometric object using vector-Jacobian product --- src/meepgeom.cpp | 60 ++++++++++++++++++++++++++++++++++++++++-------- src/meepgeom.hpp | 2 +- 2 files changed, 51 insertions(+), 11 deletions(-) diff --git a/src/meepgeom.cpp b/src/meepgeom.cpp index b287c0553..deedd2d5c 100644 --- a/src/meepgeom.cpp +++ b/src/meepgeom.cpp @@ -308,7 +308,33 @@ bool is_metal(meep::field_type ft, const material_type *material) { } } -meep::vec material_grid_grad(vector3 p, material_data *md) { +// computes the vector-Jacobian product of the gradient of the matgrid_val function v +// with the Jacobian of the to_geom_box_coords function for geometric_object o +vector3 to_geom_object_coords_VJP(vector3 v, const geometric_object *o) { + switch (o->which_subclass) { + default: { + vector3 po = {0, 0, 0}; + return po; + } + case geometric_object::SPHERE: { + number radius = o->subclass.sphere_data->radius; + return vector3_scale(0.5 / radius, v); + } + /* case geometric_object::CYLINDER: + NOT YET IMPLEMENTED */ + case geometric_object::BLOCK: { + vector3 size = o->subclass.block_data->size; + if (size.x != 0.0) v.x /= size.x; + if (size.y != 0.0) v.y /= size.y; + if (size.z != 0.0) v.z /= size.z; + return matrix3x3_transpose_vector3_mult(o->subclass.block_data->projection_matrix, v); + } + /* case geometric_object::PRISM: + NOT YET IMPLEMENTED */ + } +} + +meep::vec material_grid_grad(vector3 p, material_data *md, const geometric_object *o) { if (!is_material_grid(md)) { meep::abort("Invalid material grid detected.\n"); } meep::vec gradient(zero_vec(dim)); @@ -364,13 +390,26 @@ meep::vec material_grid_grad(vector3 p, material_data *md) { #undef D - // to obtain the gradient with respect to the rx,ry,rz - // coordinates rather than dx,dy,dz we use the chain - // rule which therefore ends up multiplying each - // component by nx,ny,nz respectively (see map_coordinates) - gradient.set_direction(meep::X, du_dx * nx); - gradient.set_direction(meep::Y, du_dy * ny); - gradient.set_direction(meep::Z, du_dz * nz); + // [du_dx,du_dy,du_dz] is the gradient ∇u with respect to the transformed coordinate + // r1 of the matgrid_val function but what we want is the gradient of u(g(r2)) with + // respect to r2 where g(r2) is the to_geom_object_coords function. computing this + // quantity involves using the chain rule and the vector-Jacobian product ∇u J + // where J is the Jacobian matrix of g. + vector3 grad_u; + grad_u.x = du_dx * nx; + grad_u.y = du_dy * ny; + grad_u.z = du_dz * nz; + if (o != NULL) { + vector3 grad_u_J = to_geom_object_coords_VJP(grad_u, o); + gradient.set_direction(meep::X, grad_u_J.x); + gradient.set_direction(meep::Y, grad_u_J.y); + gradient.set_direction(meep::Z, grad_u_J.z); + } + else { + gradient.set_direction(meep::X, grad_u.x); + gradient.set_direction(meep::Y, grad_u.y); + gradient.set_direction(meep::Z, grad_u.z); + } return gradient; } @@ -396,7 +435,8 @@ meep::vec matgrid_grad(vector3 p, geom_box_tree tp, int oi, material_data *md) { if (tp) { do { gradient += material_grid_grad(to_geom_box_coords(p, &tp->objects[oi]), - (material_data *)tp->objects[oi].o->material); + (material_data *)tp->objects[oi].o->material, + tp->objects[oi].o); if (md->material_grid_kinds == material_data::U_DEFAULT) break; ++matgrid_val_count; tp = geom_tree_search_next(p, tp, &oi); @@ -405,7 +445,7 @@ meep::vec matgrid_grad(vector3 p, geom_box_tree tp, int oi, material_data *md) { // perhaps there is no object tree and the default material is a material grid if (!tp && is_material_grid(default_material)) { map_lattice_coordinates(p.x,p.y,p.z); - gradient = material_grid_grad(p, (material_data *)default_material); + gradient = material_grid_grad(p, (material_data *)default_material, NULL /* geometric_object *o */); ++matgrid_val_count; } diff --git a/src/meepgeom.hpp b/src/meepgeom.hpp index 5805e39d7..949fe8ad0 100644 --- a/src/meepgeom.hpp +++ b/src/meepgeom.hpp @@ -210,7 +210,7 @@ void init_libctl(material_type default_mat, bool ensure_per, /***************************************************************/ void update_weights(material_type matgrid, double *weights); meep::vec matgrid_grad(vector3 p, geom_box_tree tp, int oi, material_data *md); -meep::vec material_grid_grad(vector3 p, material_data *md); +meep::vec material_grid_grad(vector3 p, material_data *md, const geometric_object *o); double matgrid_val(vector3 p, geom_box_tree tp, int oi, material_data *md); double material_grid_val(vector3 p, material_data *md); geom_box_tree calculate_tree(const meep::volume &v, geometric_object_list g); From 6d2f446fcac4135fb52cb3e8490950e497e5a03e Mon Sep 17 00:00:00 2001 From: Ardavan Oskooi Date: Sun, 20 Jun 2021 08:24:38 -0700 Subject: [PATCH 11/15] check if geometric_object is not NULL in to_geom_object_coords_VJP --- src/meepgeom.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/meepgeom.cpp b/src/meepgeom.cpp index deedd2d5c..5420c1e07 100644 --- a/src/meepgeom.cpp +++ b/src/meepgeom.cpp @@ -311,6 +311,8 @@ bool is_metal(meep::field_type ft, const material_type *material) { // computes the vector-Jacobian product of the gradient of the matgrid_val function v // with the Jacobian of the to_geom_box_coords function for geometric_object o vector3 to_geom_object_coords_VJP(vector3 v, const geometric_object *o) { + if (!o) { meep::abort("must pass a geometric_object to to_geom_object_coords_VJP.\n"); } + switch (o->which_subclass) { default: { vector3 po = {0, 0, 0}; @@ -392,9 +394,9 @@ meep::vec material_grid_grad(vector3 p, material_data *md, const geometric_objec // [du_dx,du_dy,du_dz] is the gradient ∇u with respect to the transformed coordinate // r1 of the matgrid_val function but what we want is the gradient of u(g(r2)) with - // respect to r2 where g(r2) is the to_geom_object_coords function. computing this - // quantity involves using the chain rule and the vector-Jacobian product ∇u J - // where J is the Jacobian matrix of g. + // respect to r2 where g(r2) is the to_geom_object_coords function (in libctl/utils/geom.c). + // computing this quantity involves using the chain rule and thus the vector-Jacobian product + // ∇u J where J is the Jacobian matrix of g. vector3 grad_u; grad_u.x = du_dx * nx; grad_u.y = du_dy * ny; From 5f04aae4fedbd0f57e691159dfd1db2c657411fd Mon Sep 17 00:00:00 2001 From: Ardavan Oskooi Date: Tue, 22 Jun 2021 19:11:17 -0700 Subject: [PATCH 12/15] add chain rule for the map_lattice_coordinates function for default material --- src/meepgeom.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/meepgeom.cpp b/src/meepgeom.cpp index 5420c1e07..371c80437 100644 --- a/src/meepgeom.cpp +++ b/src/meepgeom.cpp @@ -408,9 +408,9 @@ meep::vec material_grid_grad(vector3 p, material_data *md, const geometric_objec gradient.set_direction(meep::Z, grad_u_J.z); } else { - gradient.set_direction(meep::X, grad_u.x); - gradient.set_direction(meep::Y, grad_u.y); - gradient.set_direction(meep::Z, grad_u.z); + gradient.set_direction(meep::X, geometry_lattice.size.x == 0 ? 0 : grad_u.x / geometry_lattice.size.x); + gradient.set_direction(meep::Y, geometry_lattice.size.y == 0 ? 0 : grad_u.y / geometry_lattice.size.y); + gradient.set_direction(meep::Z, geometry_lattice.size.z == 0 ? 0 : grad_u.z / geometry_lattice.size.z); } return gradient; From d72cd977c81a0c34e59ab19e1d0b0518b9137014 Mon Sep 17 00:00:00 2001 From: Ardavan Oskooi Date: Tue, 22 Jun 2021 21:57:19 -0700 Subject: [PATCH 13/15] refactor to minimize copy-pasted lines --- src/meepgeom.cpp | 72 +++++++++++++++++++----------------------------- 1 file changed, 28 insertions(+), 44 deletions(-) diff --git a/src/meepgeom.cpp b/src/meepgeom.cpp index 371c80437..bfa331a60 100644 --- a/src/meepgeom.cpp +++ b/src/meepgeom.cpp @@ -1195,66 +1195,50 @@ struct matgrid_volavg { double ugrad_abs; // magnitude of gradient of uval double beta; // thresholding bias double eta; // thresholding erosion/dilation - vector3 med1_eps_diag; // diagonal of epsilon tensor from medium 1 - vector3 med2_eps_diag; // diagonal of epsilon tensor from medium 2 + double eps1; // trace of epsilon tensor from medium 1 + double eps2; // trace of epsilon tensor from medium 2 }; -#ifdef CTL_HAS_COMPLEX_INTEGRATION -static cnumber matgrid_ceps_func(int n, number *x, void *mgva_) { +static void get_uproj_w(const void *mgva_, double x0, double &uproj_, double &w_) { matgrid_volavg *mgva = (matgrid_volavg *)mgva_; // use a linear approximation for the material grid weights around the Yee grid point - double u_proj = tanh_projection(mgva->uval + mgva->ugrad_abs*x[0], mgva->beta, mgva->eta); - vector3 med1_eps_diag = mgva->med1_eps_diag; - vector3 med2_eps_diag = mgva->med2_eps_diag; - double eps1 = (med1_eps_diag.x + med1_eps_diag.y + med1_eps_diag.z)/3; - double eps2 = (med2_eps_diag.x + med2_eps_diag.y + med2_eps_diag.z)/3; - cnumber ret; - ret.re = (1-u_proj)*eps1 + u_proj*eps2; - ret.im = (1-u_proj)/eps1 + u_proj/eps2; - double w = 0; + uproj_ = tanh_projection(mgva->uval + mgva->ugrad_abs*x0, mgva->beta, mgva->eta); if (mgva->dim == meep::D1) - w = 1/(2*mgva->rad); + w_ = 1/(2*mgva->rad); else if (mgva->dim == meep::D2) - w = 2*sqrt(mgva->rad*mgva->rad - x[0]*x[0])/(meep::pi * mgva->rad*mgva->rad); + w_ = 2*sqrt(mgva->rad*mgva->rad - x0*x0)/(meep::pi * mgva->rad*mgva->rad); else if (mgva->dim == meep::D3) - w = meep::pi*(mgva->rad*mgva->rad - x[0]*x[0])/(4/3 * meep::pi * mgva->rad*mgva->rad*mgva->rad); + w_ = meep::pi*(mgva->rad*mgva->rad - x0*x0)/(4/3 * meep::pi * mgva->rad*mgva->rad*mgva->rad); +} + +#ifdef CTL_HAS_COMPLEX_INTEGRATION +static cnumber matgrid_ceps_func(int n, number *x, void *mgva_) { + double u_proj = 0, w = 0; + get_uproj_w(mgva_, x[0], u_proj, w); + double eps1 = mgva->eps1; + double eps2 = mgva->eps2; + cnumber ret; + ret.re = (1-u_proj)*eps1 + u_proj*eps2; + ret.im = (1-u_proj)/eps1 + u_proj/eps2; return ret * w; } #else static number matgrid_eps_func(int n, number *x, void *mgva_) { + double u_proj = 0, w = 0; + get_uproj_w(mgva_, x[0], u_proj, w); matgrid_volavg *mgva = (matgrid_volavg *)mgva_; - // use a linear approximation for the material grid weights around the Yee grid point - double u_proj = tanh_projection(mgva->uval + mgva->ugrad_abs*x[0], mgva->beta, mgva->eta); - vector3 med1_eps_diag = mgva->med1_eps_diag; - vector3 med2_eps_diag = mgva->med2_eps_diag; - double eps1 = (med1_eps_diag.x + med1_eps_diag.y + med1_eps_diag.z)/3; - double eps2 = (med2_eps_diag.x + med2_eps_diag.y + med2_eps_diag.z)/3; + double eps1 = mgva->eps1; + double eps2 = mgva->eps2; double eps_interp = (1-u_proj)*eps1 + u_proj*eps2; - double w = 0; - if (mgva->dim == meep::D1) - w = 1/(2*mgva->rad); - else if (mgva->dim == meep::D2) - w = 2*sqrt(mgva->rad*mgva->rad - x[0]*x[0])/(meep::pi * mgva->rad*mgva->rad); - else if (mgva->dim == meep::D3) - w = meep::pi*(mgva->rad*mgva->rad - x[0]*x[0])/(4/3 * meep::pi * mgva->rad*mgva->rad*mgva->rad); return eps_interp * w; } static number matgrid_inveps_func(int n, number *x, void *mgva_) { + double u_proj = 0, w = 0; + get_uproj_w(mgva_, x[0], u_proj, w); matgrid_volavg *mgva = (matgrid_volavg *)mgva_; - // use a linear approximation for the material grid weights around the Yee grid point - double u_proj = tanh_projection(mgva->uval + mgva->ugrad_abs*x[0], mgva->beta, mgva->eta); - vector3 med1_eps_diag = mgva->med1_eps_diag; - vector3 med2_eps_diag = mgva->med2_eps_diag; - double eps1 = (med1_eps_diag.x + med1_eps_diag.y + med1_eps_diag.z)/3; - double eps2 = (med2_eps_diag.x + med2_eps_diag.y + med2_eps_diag.z)/3; + double eps1 = mgva->eps1; + double eps2 = mgva->eps2; double epsinv_interp = (1-u_proj)/eps1 + u_proj/eps2; - double w = 0; - if (mgva->dim == meep::D1) - w = 1/(2*mgva->rad); - else if (mgva->dim == meep::D2) - w = 2*sqrt(mgva->rad*mgva->rad - x[0]*x[0])/(meep::pi * mgva->rad*mgva->rad); - else if (mgva->dim == meep::D3) - w = meep::pi*(mgva->rad*mgva->rad - x[0]*x[0])/(4/3 * meep::pi * mgva->rad*mgva->rad*mgva->rad); return epsinv_interp * w; } #endif @@ -1378,8 +1362,8 @@ void geom_epsilon::fallback_chi1inv_row(meep::component c, double chi1inv_row[3] mgva.rad = v.diameter()/2; mgva.beta = md->beta; mgva.eta = md->eta; - mgva.med1_eps_diag = md->medium_1.epsilon_diag; - mgva.med2_eps_diag = md->medium_2.epsilon_diag; + mgva.eps1 = (md->medium_1.epsilon_diag.x+md->medium_1.epsilon_diag.y+md->medium_1.epsilon_diag.z)/3; + mgva.eps2 = (md->medium_2.epsilon_diag.x+md->medium_2.epsilon_diag.y+md->medium_2.epsilon_diag.z)/3; xmin[0] = -v.diameter()/2; xmax[0] = v.diameter()/2; #ifdef CTL_HAS_COMPLEX_INTEGRATION From e882ba924c608eaa6233b86fd7929464ea408681 Mon Sep 17 00:00:00 2001 From: Ardavan Oskooi Date: Tue, 22 Jun 2021 22:06:45 -0700 Subject: [PATCH 14/15] fix bug in matgrid_ceps_func --- src/meepgeom.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/meepgeom.cpp b/src/meepgeom.cpp index bfa331a60..8d053028f 100644 --- a/src/meepgeom.cpp +++ b/src/meepgeom.cpp @@ -1215,6 +1215,7 @@ static void get_uproj_w(const void *mgva_, double x0, double &uproj_, double &w_ static cnumber matgrid_ceps_func(int n, number *x, void *mgva_) { double u_proj = 0, w = 0; get_uproj_w(mgva_, x[0], u_proj, w); + matgrid_volavg *mgva = (matgrid_volavg *)mgva_; double eps1 = mgva->eps1; double eps2 = mgva->eps2; cnumber ret; From 3b356bc8b685058dbfaaaf992c5cb3eb58dcd41a Mon Sep 17 00:00:00 2001 From: Ardavan Oskooi Date: Wed, 23 Jun 2021 07:31:31 -0700 Subject: [PATCH 15/15] fixes and tweaks --- src/meepgeom.cpp | 35 +++++++++++++---------------------- 1 file changed, 13 insertions(+), 22 deletions(-) diff --git a/src/meepgeom.cpp b/src/meepgeom.cpp index 8d053028f..304a2943a 100644 --- a/src/meepgeom.cpp +++ b/src/meepgeom.cpp @@ -1199,48 +1199,39 @@ struct matgrid_volavg { double eps2; // trace of epsilon tensor from medium 2 }; -static void get_uproj_w(const void *mgva_, double x0, double &uproj_, double &w_) { - matgrid_volavg *mgva = (matgrid_volavg *)mgva_; +static void get_uproj_w(const matgrid_volavg *mgva, double x0, double &u_proj, double &w) { // use a linear approximation for the material grid weights around the Yee grid point - uproj_ = tanh_projection(mgva->uval + mgva->ugrad_abs*x0, mgva->beta, mgva->eta); + u_proj = tanh_projection(mgva->uval + mgva->ugrad_abs*x0, mgva->beta, mgva->eta); if (mgva->dim == meep::D1) - w_ = 1/(2*mgva->rad); - else if (mgva->dim == meep::D2) - w_ = 2*sqrt(mgva->rad*mgva->rad - x0*x0)/(meep::pi * mgva->rad*mgva->rad); + w = 1/(2*mgva->rad); + else if (mgva->dim == meep::D2 || mgva->dim == meep::Dcyl) + w = 2*sqrt(mgva->rad*mgva->rad - x0*x0)/(meep::pi * mgva->rad*mgva->rad); else if (mgva->dim == meep::D3) - w_ = meep::pi*(mgva->rad*mgva->rad - x0*x0)/(4/3 * meep::pi * mgva->rad*mgva->rad*mgva->rad); + w = meep::pi*(mgva->rad*mgva->rad - x0*x0)/(4/3 * meep::pi * mgva->rad*mgva->rad*mgva->rad); } #ifdef CTL_HAS_COMPLEX_INTEGRATION static cnumber matgrid_ceps_func(int n, number *x, void *mgva_) { double u_proj = 0, w = 0; - get_uproj_w(mgva_, x[0], u_proj, w); matgrid_volavg *mgva = (matgrid_volavg *)mgva_; - double eps1 = mgva->eps1; - double eps2 = mgva->eps2; + get_uproj_w(mgva, x[0], u_proj, w); cnumber ret; - ret.re = (1-u_proj)*eps1 + u_proj*eps2; - ret.im = (1-u_proj)/eps1 + u_proj/eps2; + ret.re = (1-u_proj)*mgva->eps1 + u_proj*mgva->eps2; + ret.im = (1-u_proj)/mgva->eps1 + u_proj/mgva->eps2; return ret * w; } #else static number matgrid_eps_func(int n, number *x, void *mgva_) { double u_proj = 0, w = 0; - get_uproj_w(mgva_, x[0], u_proj, w); matgrid_volavg *mgva = (matgrid_volavg *)mgva_; - double eps1 = mgva->eps1; - double eps2 = mgva->eps2; - double eps_interp = (1-u_proj)*eps1 + u_proj*eps2; - return eps_interp * w; + get_uproj_w(mgva, x[0], u_proj, w); + return w * ((1-u_proj)*mgva->eps1 + u_proj*mgva->eps2); } static number matgrid_inveps_func(int n, number *x, void *mgva_) { double u_proj = 0, w = 0; - get_uproj_w(mgva_, x[0], u_proj, w); matgrid_volavg *mgva = (matgrid_volavg *)mgva_; - double eps1 = mgva->eps1; - double eps2 = mgva->eps2; - double epsinv_interp = (1-u_proj)/eps1 + u_proj/eps2; - return epsinv_interp * w; + get_uproj_w(mgva, x[0], u_proj, w); + return w * ((1-u_proj)/mgva->eps1 + u_proj/mgva->eps2); } #endif