Package hedge :: Package models :: Module pml
[hide private]
[frames] | no frames]

Source Code for Module hedge.models.pml

  1  # -*- coding: utf8 -*- 
  2  """Models describing absorbing boundary layers.""" 
  3   
  4  from __future__ import division 
  5   
  6  __copyright__ = "Copyright (C) 2007 Andreas Kloeckner" 
  7   
  8  __license__ = """ 
  9  This program is free software: you can redistribute it and/or modify 
 10  it under the terms of the GNU General Public License as published by 
 11  the Free Software Foundation, either version 3 of the License, or 
 12  (at your option) any later version. 
 13   
 14  This program is distributed in the hope that it will be useful, 
 15  but WITHOUT ANY WARRANTY; without even the implied warranty of 
 16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 17  GNU General Public License for more details. 
 18   
 19  You should have received a copy of the GNU General Public License 
 20  along with this program.  If not, see U{http://www.gnu.org/licenses/}. 
 21  """ 
 22   
 23   
 24   
 25   
 26  import numpy 
 27  import numpy.linalg as la 
 28   
 29  from pytools import memoize_method, Record 
 30  from hedge.models.em import \ 
 31          MaxwellOperator, \ 
 32          TMMaxwellOperator, \ 
 33          TEMaxwellOperator 
34 35 36 37 38 -class AbarbanelGottliebPMLMaxwellOperator(MaxwellOperator):
39 """Implements a PML as in 40 41 [1] S. Abarbanel and D. Gottlieb, "On the construction and analysis of absorbing 42 layers in CEM," Applied Numerical Mathematics, vol. 27, 1998, S. 331-340. 43 (eq 3.7-3.11) 44 45 [2] E. Turkel and A. Yefet, "Absorbing PML 46 boundary layers for wave-like equations," 47 Applied Numerical Mathematics, vol. 27, 48 1998, S. 533-557. 49 (eq. 4.10) 50 51 [3] Abarbanel, D. Gottlieb, and J.S. Hesthaven, "Long Time Behavior of the 52 Perfectly Matched Layer Equations in Computational Electromagnetics," 53 Journal of Scientific Computing, vol. 17, Dez. 2002, S. 405-422. 54 55 Generalized to 3D in doc/maxima/abarbanel-pml.mac. 56 """ 57
58 - class PMLCoefficients(Record):
59 __slots__ = ["sigma", "sigma_prime", "tau"] 60 # (tau=mu in [3] , to avoid confusion with permeability) 61
62 - def map(self, f):
63 return self.__class__( 64 **dict((name, f(getattr(self, name))) 65 for name in self.fields))
66
67 - def __init__(self, *args, **kwargs):
68 self.add_decay = kwargs.pop("add_decay", True) 69 MaxwellOperator.__init__(self, *args, **kwargs)
70
71 - def pml_local_op(self, w):
72 sub_e, sub_h, sub_p, sub_q = self.split_ehpq(w) 73 74 e_subset = self.get_eh_subset()[0:3] 75 h_subset = self.get_eh_subset()[3:6] 76 dim_subset = (True,) * self.dimensions + (False,) * (3-self.dimensions) 77 78 def pad_vec(v, subset): 79 result = numpy.zeros((3,), dtype=object) 80 result[numpy.array(subset, dtype=bool)] = v 81 return result
82 83 from hedge.optemplate import make_vector_field 84 sig = pad_vec( 85 make_vector_field("sigma", self.dimensions), 86 dim_subset) 87 sig_prime = pad_vec( 88 make_vector_field("sigma_prime", self.dimensions), 89 dim_subset) 90 if self.add_decay: 91 tau = pad_vec( 92 make_vector_field("tau", self.dimensions), 93 dim_subset) 94 else: 95 tau = numpy.zeros((3,)) 96 97 e = pad_vec(sub_e, e_subset) 98 h = pad_vec(sub_h, h_subset) 99 p = pad_vec(sub_p, dim_subset) 100 q = pad_vec(sub_q, dim_subset) 101 102 rhs = numpy.zeros(12, dtype=object) 103 104 for mx in range(3): 105 my = (mx+1) % 3 106 mz = (mx+2) % 3 107 108 from hedge.tools import levi_civita 109 assert levi_civita((mx,my,mz)) == 1 110 111 rhs[mx] += -sig[my]/self.epsilon*(2*e[mx]+p[mx]) - 2*tau[my]/self.epsilon*e[mx] 112 rhs[my] += -sig[mx]/self.epsilon*(2*e[my]+p[my]) - 2*tau[mx]/self.epsilon*e[my] 113 rhs[3+mz] += 1/(self.epsilon*self.mu) * ( 114 sig_prime[mx] * q[mx] - sig_prime[my] * q[my]) 115 116 rhs[6+mx] += sig[my]/self.epsilon*e[mx] 117 rhs[6+my] += sig[mx]/self.epsilon*e[my] 118 rhs[9+mx] += -sig[mx]/self.epsilon*q[mx] - (e[my] + e[mz]) 119 120 from hedge.tools import full_to_subset_indices 121 sub_idx = full_to_subset_indices(e_subset+h_subset+dim_subset+dim_subset) 122 123 return rhs[sub_idx]
124
125 - def op_template(self, w=None):
126 from hedge.tools import count_subset 127 fld_cnt = count_subset(self.get_eh_subset()) 128 if w is None: 129 from hedge.optemplate import make_vector_field 130 w = make_vector_field("w", fld_cnt+2*self.dimensions) 131 132 from hedge.tools import join_fields 133 return join_fields( 134 MaxwellOperator.op_template(self, w[:fld_cnt]), 135 numpy.zeros((2*self.dimensions,), dtype=object) 136 ) + self.pml_local_op(w)
137
138 - def bind(self, discr, coefficients):
139 return MaxwellOperator.bind(self, discr, 140 sigma=coefficients.sigma, 141 sigma_prime=coefficients.sigma_prime, 142 tau=coefficients.tau)
143
144 - def assemble_ehpq(self, e=None, h=None, p=None, q=None, discr=None):
145 if discr is None: 146 def zero(): return 0 147 else: 148 def zero(): return discr.volume_zeros() 149 150 from hedge.tools import count_subset 151 e_components = count_subset(self.get_eh_subset()[0:3]) 152 h_components = count_subset(self.get_eh_subset()[3:6]) 153 154 def default_fld(fld, comp): 155 if fld is None: 156 return [zero() for i in xrange(comp)] 157 else: 158 return fld
159 160 e = default_fld(e, e_components) 161 h = default_fld(h, h_components) 162 p = default_fld(p, self.dimensions) 163 q = default_fld(q, self.dimensions) 164 165 from hedge.tools import join_fields 166 return join_fields(e, h, p, q) 167 168 @memoize_method
169 - def partial_to_ehpq_subsets(self):
170 e_subset = self.get_eh_subset()[0:3] 171 h_subset = self.get_eh_subset()[3:6] 172 173 dim_subset = [True] * self.dimensions + [False] * (3-self.dimensions) 174 175 from hedge.tools import partial_to_all_subset_indices 176 return tuple(partial_to_all_subset_indices( 177 [e_subset, h_subset, dim_subset, dim_subset]))
178
179 - def split_ehpq(self, w):
180 e_idx, h_idx, p_idx, q_idx = self.partial_to_ehpq_subsets() 181 e, h, p, q = w[e_idx], w[h_idx], w[p_idx], w[q_idx] 182 183 from hedge.flux import FluxVectorPlaceholder as FVP 184 if isinstance(w, FVP): 185 return FVP(scalars=e), FVP(scalars=h) 186 else: 187 from hedge.tools import make_obj_array as moa 188 return moa(e), moa(h), moa(p), moa(q)
189 190 # sigma business ----------------------------------------------------------
191 - def _construct_scalar_coefficients(self, discr, node_coord, 192 i_min, i_max, o_min, o_max, exponent):
193 assert o_min < i_min <= i_max < o_max 194 195 if o_min != i_min: 196 l_dist = (i_min - node_coord) / (i_min-o_min) 197 l_dist_prime = discr.volume_zeros(kind="numpy", dtype=node_coord.dtype) 198 l_dist_prime[l_dist >= 0] = -1 / (i_min-o_min) 199 l_dist[l_dist < 0] = 0 200 else: 201 l_dist = l_dist_prime = numpy.zeros_like(node_coord) 202 203 if i_max != o_max: 204 r_dist = (node_coord - i_max) / (o_max-i_max) 205 r_dist_prime = discr.volume_zeros(kind="numpy", dtype=node_coord.dtype) 206 r_dist_prime[r_dist >= 0] = 1 / (o_max-i_max) 207 r_dist[r_dist < 0] = 0 208 else: 209 r_dist = r_dist_prime = numpy.zeros_like(node_coord) 210 211 l_plus_r = l_dist+r_dist 212 return l_plus_r**exponent, \ 213 (l_dist_prime+r_dist_prime)*exponent*l_plus_r**(exponent-1), \ 214 l_plus_r
215
216 - def coefficients_from_boxes(self, discr, 217 inner_bbox, outer_bbox=None, 218 magnitude=None, tau_magnitude=None, 219 exponent=None, dtype=None):
220 if outer_bbox is None: 221 outer_bbox = discr.mesh.bounding_box() 222 223 if exponent is None: 224 exponent = 2 225 226 if magnitude is None: 227 magnitude = 20 228 229 if tau_magnitude is None: 230 tau_magnitude = 0.4 231 232 # scale by free space conductivity 233 from math import sqrt 234 magnitude = magnitude*sqrt(self.epsilon/self.mu) 235 tau_magnitude = tau_magnitude*sqrt(self.epsilon/self.mu) 236 237 i_min, i_max = inner_bbox 238 o_min, o_max = outer_bbox 239 240 from hedge.tools import make_obj_array 241 242 nodes = discr.nodes 243 if dtype is not None: 244 nodes = nodes.astype(dtype) 245 246 sigma, sigma_prime, tau = zip(*[self._construct_scalar_coefficients( 247 discr, nodes[:,i], 248 i_min[i], i_max[i], o_min[i], o_max[i], 249 exponent) 250 for i in range(discr.dimensions)]) 251 252 return self.PMLCoefficients( 253 sigma=magnitude*make_obj_array(sigma), 254 sigma_prime=magnitude*make_obj_array(sigma_prime), 255 tau=tau_magnitude*make_obj_array(tau))
256
257 - def coefficients_from_width(self, discr, width, 258 magnitude=None, tau_magnitude=None, exponent=None, 259 dtype=None):
260 o_min, o_max = discr.mesh.bounding_box() 261 return self.coefficients_from_boxes(discr, 262 (o_min+width, o_max-width), 263 (o_min, o_max), 264 magnitude, tau_magnitude, exponent, dtype)
265
266 267 268 269 -class AbarbanelGottliebPMLTEMaxwellOperator( 270 TEMaxwellOperator, AbarbanelGottliebPMLMaxwellOperator):
271 # not unimplemented--this IS the implementation. 272 pass
273
274 -class AbarbanelGottliebPMLTMMaxwellOperator( 275 TMMaxwellOperator, AbarbanelGottliebPMLMaxwellOperator):
276 # not unimplemented--this IS the implementation. 277 pass
278