improve pml specification
This commit is contained in:
parent
c137da15b9
commit
d02cd18403
4
fdtd.py
4
fdtd.py
@ -126,7 +126,9 @@ def main():
|
|||||||
|
|
||||||
logger.info('grid shape: {}'.format(grid.shape))
|
logger.info('grid shape: {}'.format(grid.shape))
|
||||||
# #### Create the simulation grid ####
|
# #### Create the simulation grid ####
|
||||||
sim = Simulation(grid.grids, do_poynting=True, pml_thickness=8)
|
pmls = [{'axis': a, 'polarity': p, 'thickness': pml_thickness}
|
||||||
|
for a in 'xyz' for p in 'np']
|
||||||
|
sim = Simulation(grid.grids, do_poynting=True, pmls=pmls)
|
||||||
|
|
||||||
# Source parameters and function
|
# Source parameters and function
|
||||||
w = 2 * numpy.pi * dx / wl
|
w = 2 * numpy.pi * dx / wl
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
*
|
*
|
||||||
* Template parameters:
|
* Template parameters:
|
||||||
* common_header: Rendered contents of common.cl
|
* common_header: Rendered contents of common.cl
|
||||||
* pmls: [('x', 'n'), ('z', 'p'),...] list of pml axes and polarities
|
* pmls: [{'axis': 'x', 'polarity': 'n', 'thickness': 8}, ...] list of pml dicts containing
|
||||||
* pml_thickness: Number of cells (integer)
|
axes, polarities, and thicknesses.
|
||||||
*
|
*
|
||||||
* OpenCL args:
|
* OpenCL args:
|
||||||
* E, H, dt, eps, [p{01}e{np}, Psi_{xyz}{np}_E]
|
* E, H, dt, eps, [p{01}e{np}, Psi_{xyz}{np}_E]
|
||||||
@ -18,9 +18,6 @@ __global ftype *epsx = eps + XX;
|
|||||||
__global ftype *epsy = eps + YY;
|
__global ftype *epsy = eps + YY;
|
||||||
__global ftype *epsz = eps + ZZ;
|
__global ftype *epsz = eps + ZZ;
|
||||||
|
|
||||||
{% if pmls -%}
|
|
||||||
const int pml_thickness = {{pml_thickness}};
|
|
||||||
{%- endif %}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Precalclate derivatives
|
* Precalclate derivatives
|
||||||
@ -42,7 +39,9 @@ ftype pExi = 0;
|
|||||||
ftype pEyi = 0;
|
ftype pEyi = 0;
|
||||||
ftype pEzi = 0;
|
ftype pEzi = 0;
|
||||||
|
|
||||||
{% for r, p in pmls -%}
|
{% for pml in pmls -%}
|
||||||
|
{%- set r = pml['axis'] -%}
|
||||||
|
{%- set p = pml['polarity'] -%}
|
||||||
{%- set u, v = ['x', 'y', 'z'] | reject('equalto', r) -%}
|
{%- set u, v = ['x', 'y', 'z'] | reject('equalto', r) -%}
|
||||||
{%- set psi = 'Psi_' ~ r ~ p ~ '_E' -%}
|
{%- set psi = 'Psi_' ~ r ~ p ~ '_E' -%}
|
||||||
{%- if r != 'y' -%}
|
{%- if r != 'y' -%}
|
||||||
@ -51,14 +50,16 @@ ftype pEzi = 0;
|
|||||||
{%- set se, sh = '+', '-' -%}
|
{%- set se, sh = '+', '-' -%}
|
||||||
{%- endif -%}
|
{%- endif -%}
|
||||||
|
|
||||||
|
pml_{{r ~ p}}_thickness = {{pml['thickness']}};
|
||||||
|
|
||||||
{%- if p == 'n' %}
|
{%- if p == 'n' %}
|
||||||
|
|
||||||
if ( {{r}} < pml_thickness ) {
|
if ( {{r}} < pml_{{r ~ p}_thickness ) {
|
||||||
const size_t ir = {{r}}; // index into pml parameters
|
const size_t ir = {{r}}; // index into pml parameters
|
||||||
|
|
||||||
{%- elif p == 'p' %}
|
{%- elif p == 'p' %}
|
||||||
|
|
||||||
if ( s{{r}} > {{r}} && {{r}} >= s{{r}} - pml_thickness ) {
|
if ( s{{r}} > {{r}} && {{r}} >= s{{r}} - pml_{{r ~ p}_thickness ) {
|
||||||
const size_t ir = (s{{r}} - 1) - {{r}}; // index into pml parameters
|
const size_t ir = (s{{r}} - 1) - {{r}}; // index into pml parameters
|
||||||
|
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
@ -4,22 +4,18 @@
|
|||||||
*
|
*
|
||||||
* Template parameters:
|
* Template parameters:
|
||||||
* common_header: Rendered contents of common.cl
|
* common_header: Rendered contents of common.cl
|
||||||
* pmls: [('x', 'n'), ('z', 'p'),...] list of pml axes and polarities
|
* pmls: [{'axis': 'x', 'polarity': 'n', 'thickness': 8}, ...] list of pml dicts containing
|
||||||
* pml_thickness: Number of cells (integer)
|
axes, polarities, and thicknesses.
|
||||||
* do_poynting: Whether to precalculate poynting vector components (boolean)
|
* do_poynting: Whether to precalculate poynting vector components (boolean)
|
||||||
*
|
*
|
||||||
* OpenCL args:
|
* OpenCL args:
|
||||||
* E, H, dt, [p{01}h{np}, Psi_{xyz}{np}_H], [oS]
|
* E, H, dt, [p{xyz}{01}h{np}, Psi_{xyz}{np}_H], [oS]
|
||||||
*/
|
*/
|
||||||
|
|
||||||
{{common_header}}
|
{{common_header}}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
{% if pmls -%}
|
|
||||||
const int pml_thickness = {{pml_thickness}};
|
|
||||||
{%- endif %}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Precalculate derivatives
|
* Precalculate derivatives
|
||||||
*/
|
*/
|
||||||
@ -57,7 +53,9 @@ ftype pHxi = 0;
|
|||||||
ftype pHyi = 0;
|
ftype pHyi = 0;
|
||||||
ftype pHzi = 0;
|
ftype pHzi = 0;
|
||||||
|
|
||||||
{%- for r, p in pmls -%}
|
{% for pml in pmls -%}
|
||||||
|
{%- set r = pml['axis'] -%}
|
||||||
|
{%- set p = pml['polarity'] -%}
|
||||||
{%- set u, v = ['x', 'y', 'z'] | reject('equalto', r) -%}
|
{%- set u, v = ['x', 'y', 'z'] | reject('equalto', r) -%}
|
||||||
{%- set psi = 'Psi_' ~ r ~ p ~ '_H' -%}
|
{%- set psi = 'Psi_' ~ r ~ p ~ '_H' -%}
|
||||||
{%- if r != 'y' -%}
|
{%- if r != 'y' -%}
|
||||||
@ -66,14 +64,16 @@ ftype pHzi = 0;
|
|||||||
{%- set se, sh = '+', '-' -%}
|
{%- set se, sh = '+', '-' -%}
|
||||||
{%- endif -%}
|
{%- endif -%}
|
||||||
|
|
||||||
|
pml_{{r ~ p}}_thickness = {{pml['thickness']}};
|
||||||
|
|
||||||
{%- if p == 'n' %}
|
{%- if p == 'n' %}
|
||||||
|
|
||||||
if ( {{r}} < pml_thickness ) {
|
if ( {{r}} < pml_{{r ~ p}}_thickness ) {
|
||||||
const size_t ir = {{r}}; // index into pml parameters
|
const size_t ir = {{r}}; // index into pml parameters
|
||||||
|
|
||||||
{%- elif p == 'p' %}
|
{%- elif p == 'p' %}
|
||||||
|
|
||||||
if ( s{{r}} > {{r}} && {{r}} >= s{{r}} - pml_thickness ) {
|
if ( s{{r}} > {{r}} && {{r}} >= s{{r}} - pml_{{r ~ p}}_thickness ) {
|
||||||
const size_t ir = (s{{r}} - 1) - {{r}}; // index into pml parameters
|
const size_t ir = (s{{r}} - 1) - {{r}}; // index into pml parameters
|
||||||
|
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
@ -29,7 +29,8 @@ class Simulation(object):
|
|||||||
After constructing this object, call the (update_E, update_H, update_S) members
|
After constructing this object, call the (update_E, update_H, update_S) members
|
||||||
to perform FDTD updates on the stored (E, H, S) fields:
|
to perform FDTD updates on the stored (E, H, S) fields:
|
||||||
|
|
||||||
sim = Simulation(grid.grids, do_poynting=True, pml_thickness=8)
|
pmls = [{'axis': a, 'polarity': p} for a in 'xyz' for p in 'np']
|
||||||
|
sim = Simulation(grid.grids, do_poynting=True, pmls=pmls)
|
||||||
with open('sources.c', 'w') as f:
|
with open('sources.c', 'w') as f:
|
||||||
f.write('{}'.format(sim.sources))
|
f.write('{}'.format(sim.sources))
|
||||||
|
|
||||||
@ -73,31 +74,34 @@ class Simulation(object):
|
|||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
epsilon: List[numpy.ndarray],
|
epsilon: List[numpy.ndarray],
|
||||||
|
pmls: List[Dict[str, int or float]],
|
||||||
dt: float = .99/numpy.sqrt(3),
|
dt: float = .99/numpy.sqrt(3),
|
||||||
initial_E: List[numpy.ndarray] = None,
|
initial_E: List[numpy.ndarray] = None,
|
||||||
initial_H: List[numpy.ndarray] = None,
|
initial_H: List[numpy.ndarray] = None,
|
||||||
context: pyopencl.Context = None,
|
context: pyopencl.Context = None,
|
||||||
queue: pyopencl.CommandQueue = None,
|
queue: pyopencl.CommandQueue = None,
|
||||||
float_type: numpy.float32 or numpy.float64 = numpy.float32,
|
float_type: numpy.float32 or numpy.float64 = numpy.float32,
|
||||||
pmls: List[List[str]] = None,
|
|
||||||
pml_thickness: int = 10,
|
|
||||||
do_poynting: bool = True):
|
do_poynting: bool = True):
|
||||||
"""
|
"""
|
||||||
Initialize the simulation.
|
Initialize the simulation.
|
||||||
|
|
||||||
:param epsilon: List containing [eps_r,xx, eps_r,yy, eps_r,zz], where each element is a Yee-shifted ndarray
|
:param epsilon: List containing [eps_r,xx, eps_r,yy, eps_r,zz], where each element is a Yee-shifted ndarray
|
||||||
spanning the simulation domain. Relative epsilon is used.
|
spanning the simulation domain. Relative epsilon is used.
|
||||||
:param dt: Time step. Default is the Courant factor.
|
:param pmls: List of dicts with keys:
|
||||||
|
'axis': One of 'x', 'y', 'z'.
|
||||||
|
'direction': One of 'n', 'p'.
|
||||||
|
'thickness': Number of layers, default 8.
|
||||||
|
'epsilon_eff': Effective epsilon to match to. Default 1.0.
|
||||||
|
'mu_eff': Effective mu to match to. Default 1.0.
|
||||||
|
'ln_R_per_layer': Desired (ln(R) / thickness) value. Default -1.6.
|
||||||
|
'm': Polynomial grading exponent. Default 3.5.
|
||||||
|
'ma': Exponent for alpha. Default 1.
|
||||||
|
:param dt: Time step. Default is .99/sqrt(3).
|
||||||
:param initial_E: Initial E-field (default is 0 everywhere). Same format as epsilon.
|
:param initial_E: Initial E-field (default is 0 everywhere). Same format as epsilon.
|
||||||
:param initial_H: Initial H-field (default is 0 everywhere). Same format as epsilon.
|
:param initial_H: Initial H-field (default is 0 everywhere). Same format as epsilon.
|
||||||
:param context: pyOpenCL context. If not given, pyopencl.create_some_context(False) is called.
|
:param context: pyOpenCL context. If not given, pyopencl.create_some_context(False) is called.
|
||||||
:param queue: pyOpenCL command queue. If not given, pyopencl.CommandQueue(context) is called.
|
:param queue: pyOpenCL command queue. If not given, pyopencl.CommandQueue(context) is called.
|
||||||
:param float_type: numpy.float32 or numpy.float64. Default numpy.float32.
|
:param float_type: numpy.float32 or numpy.float64. Default numpy.float32.
|
||||||
:param pmls: List of [axis, direction] pairs which specify simluation boundaries to be
|
|
||||||
'coated' with a PML (absorbing layer). Axis should be one of 'x', 'y', 'z', and
|
|
||||||
direction should be one of 'n', 'p' (i.e., negative, positive).
|
|
||||||
Default is to apply PMLs to all six boundaries.
|
|
||||||
:param pml_thickness: Thickness of any PMLs, in number of grid cells. Default 10.
|
|
||||||
:param do_poynting: If true, enables calculation of the poynting vector, S.
|
:param do_poynting: If true, enables calculation of the poynting vector, S.
|
||||||
Poynting vector calculation adds the following computational burdens:
|
Poynting vector calculation adds the following computational burdens:
|
||||||
* During update_H, ~6 extra additions/cell are performed in order to spatially
|
* During update_H, ~6 extra additions/cell are performed in order to spatially
|
||||||
@ -154,8 +158,13 @@ class Simulation(object):
|
|||||||
Exception('Initial_H list elements must have same shape as epsilon elements')
|
Exception('Initial_H list elements must have same shape as epsilon elements')
|
||||||
self.H = pyopencl.array.to_device(self.queue, vec(H).astype(float_type))
|
self.H = pyopencl.array.to_device(self.queue, vec(H).astype(float_type))
|
||||||
|
|
||||||
if pmls is None:
|
for pml in pmls:
|
||||||
pmls = [[d, p] for d in 'xyz' for p in 'np']
|
pml.setdefault('thickness', 8)
|
||||||
|
pml.setdefault('epsilon_eff', 1.0)
|
||||||
|
pml.setdefault('mu_eff', 1.0)
|
||||||
|
pml.setdefault('ln_R_per_layer', -1.6)
|
||||||
|
pml.setdefault('m', 3.5)
|
||||||
|
pml.setdefault('ma', 1)
|
||||||
|
|
||||||
ctype = type_to_C(self.arg_type)
|
ctype = type_to_C(self.arg_type)
|
||||||
|
|
||||||
@ -176,7 +185,6 @@ class Simulation(object):
|
|||||||
)
|
)
|
||||||
jinja_args = {
|
jinja_args = {
|
||||||
'common_header': common_source,
|
'common_header': common_source,
|
||||||
'pml_thickness': pml_thickness,
|
|
||||||
'pmls': pmls,
|
'pmls': pmls,
|
||||||
'do_poynting': do_poynting,
|
'do_poynting': do_poynting,
|
||||||
}
|
}
|
||||||
@ -201,35 +209,39 @@ class Simulation(object):
|
|||||||
'''
|
'''
|
||||||
PML
|
PML
|
||||||
'''
|
'''
|
||||||
m = (3.5, 1)
|
|
||||||
sigma_max = 0.8 * (m[0] + 1) / numpy.sqrt(1.0) # TODO: epsilon_eff (not 1.0)
|
|
||||||
alpha_max = 0 # TODO: Decide what to do about non-zero alpha
|
|
||||||
|
|
||||||
def par(x):
|
|
||||||
sigma = ((x / pml_thickness) ** m[0]) * sigma_max
|
|
||||||
alpha = ((1 - x / pml_thickness) ** m[1]) * alpha_max
|
|
||||||
p0 = numpy.exp(-(sigma + alpha) * dt)
|
|
||||||
p1 = sigma / (sigma + alpha) * (p0 - 1)
|
|
||||||
return p0, p1
|
|
||||||
|
|
||||||
xen, xep, xhn, xhp = (numpy.arange(1, pml_thickness + 1, dtype=float_type)[::-1] for _ in range(4))
|
|
||||||
xep -= 0.5
|
|
||||||
xhn -= 0.5
|
|
||||||
|
|
||||||
pml_p_names = [['p' + a + eh + np for np in 'np' for a in '01'] for eh in 'eh']
|
|
||||||
pml_e_fields = OrderedDict()
|
pml_e_fields = OrderedDict()
|
||||||
pml_h_fields = OrderedDict()
|
pml_h_fields = OrderedDict()
|
||||||
for ne, nh, pe, ph in zip(*pml_p_names, par(xen) + par(xep), par(xhn) + par(xhp)):
|
|
||||||
pml_e_fields[ptr(ne)] = pyopencl.array.to_device(self.queue, pe)
|
|
||||||
pml_h_fields[ptr(nh)] = pyopencl.array.to_device(self.queue, ph)
|
|
||||||
|
|
||||||
for pml in pmls:
|
for pml in pmls:
|
||||||
uv = 'xyz'.replace(pml[0], '')
|
a = 'xyz'.find(pml['axis'])
|
||||||
psi_base = 'Psi_' + ''.join(pml) + '_'
|
|
||||||
|
sigma_max = -pml['ln_R_per_layer'] / 2 * (pml['m'] + 1) / \
|
||||||
|
numpy.sqrt(pml['epsilon_eff'] * pml['mu_eff'])
|
||||||
|
alpha_max = 0 # TODO: Nonzero alpha
|
||||||
|
|
||||||
|
def par(x):
|
||||||
|
sigma = ((x / pml['thickness']) ** pml['m']) * sigma_max
|
||||||
|
alpha = ((1 - x / pml['thickness']) ** pml['ma']) * alpha_max
|
||||||
|
p0 = numpy.exp(-(sigma + alpha) * dt)
|
||||||
|
p1 = sigma / (sigma + alpha) * (p0 - 1)
|
||||||
|
return p0, p1
|
||||||
|
|
||||||
|
xe, xh = (numpy.arange(1, pml['thickness'] + 1, dtype=float_type)[::-1] for _ in range(2))
|
||||||
|
if pml['polarity'] == 'p':
|
||||||
|
xe -= 0.5
|
||||||
|
elif pml['polarity'] == 'n':
|
||||||
|
xh -= 0.5
|
||||||
|
|
||||||
|
pml_p_names = [['p' + pml['axis'] + i + eh + pml['polarity'] for i in '01'] for eh in 'eh']
|
||||||
|
for name_e, name_h, pe, ph in zip(pml_p_names[0], pml_p_names[1], par(xe), par(xh)):
|
||||||
|
pml_e_fields[ptr(name_e)] = pyopencl.array.to_device(self.queue, pe)
|
||||||
|
pml_h_fields[ptr(name_h)] = pyopencl.array.to_device(self.queue, ph)
|
||||||
|
|
||||||
|
uv = 'xyz'.replace(pml['axis'], '')
|
||||||
|
psi_base = 'Psi_' + pml['axis'] + pml['polarity'] + '_'
|
||||||
psi_names = [[psi_base + eh + c for c in uv] for eh in 'EH']
|
psi_names = [[psi_base + eh + c for c in uv] for eh in 'EH']
|
||||||
|
|
||||||
psi_shape = list(epsilon[0].shape)
|
psi_shape = list(epsilon[0].shape)
|
||||||
psi_shape['xyz'.find(pml[0])] = pml_thickness
|
psi_shape[a] = pml['thickness']
|
||||||
|
|
||||||
for ne, nh in zip(*psi_names):
|
for ne, nh in zip(*psi_names):
|
||||||
pml_e_fields[ptr(ne)] = pyopencl.array.zeros(self.queue, tuple(psi_shape), dtype=self.arg_type)
|
pml_e_fields[ptr(ne)] = pyopencl.array.zeros(self.queue, tuple(psi_shape), dtype=self.arg_type)
|
||||||
|
Loading…
Reference in New Issue
Block a user