120 kc = np.where(G.solid, k2, k1)
121 idx = np.arange(n * n).reshape(n, n)
122 rows, cols, vals = [], [], []
123 rhs = np.zeros(n * n)
124 def add(r, c, v): rows.append(r); cols.append(c); vals.append(v)
129 P = (i, j); Q = (i + 1, j)
if axis == 0
else (i, j + 1)
130 if Q[axis] >= n:
continue
131 a_s = G.asx[i + 1, j]
if axis == 0
else G.asy[i, j + 1]
132 kP, kQ = kc[P], kc[Q]
133 cross = G.solid[P] != G.solid[Q]
136 kf = 2 * kP * kQ / (kP + kQ); stencil = [(P, -kf), (Q, kf)]
137 elif method
in (
"DIRq",
"DIRq-side"):
138 kf = (1 - a_s) * k1 + a_s * k2
if method ==
"DIRq" else kP
139 stencil = [(P, -kf), (Q, kf)]
142 sh = (1, 0)
if axis == 0
else (0, 1)
143 Pm = (P[0] - sh[0], P[1] - sh[1]); Qp = (Q[0] + sh[0], Q[1] + sh[1])
146 fP = a_s
if G.solid[P]
else 1 - a_s
147 w = kP * fP * gl + kQ * (1 - fP) * gr
149 w = kP * gl
if xi >= 0
else kQ * gr
150 stencil = [(Pm, w[0]), (P, w[1]), (Q, w[2]), (Qp, w[3])]
151 elif method ==
"DIRc":
152 kf = (1 - a_s) * k1 + a_s * k2
153 stencil = [(P, -kf), (Q, kf)]
156 sh = (1, 0)
if axis == 0
else (0, 1)
157 Pm = (P[0] - sh[0], P[1] - sh[1]); Qp = (Q[0] + sh[0], Q[1] + sh[1])
158 gl, gr = dir_face_both(xi)
159 fP = a_s
if G.solid[P]
else 1 - a_s
160 w = kP * fP * gl + kQ * (1 - fP) * gr
161 stencil = [(Pm, w[0]), (P, w[1]), (Q, w[2]), (Qp, w[3])]
162 elif method ==
"OF-a":
163 kf = (1 - a_s) * k1 + a_s * k2; stencil = [(P, -kf), (Q, kf)]
166 if method ==
"DIR-B" and 0 < a_s < 1:
168 kr, ko = kP, (k1
if kP == k2
else k2)
169 ao = a_s
if kP == k1
else 1 - a_s
171 fx = G.xe[i + 1]
if axis == 0
else G.xc[i]; fy = G.yc[j]
if axis == 0
else G.ye[j + 1]
172 nrm = np.array([fx, fy]) / np.hypot(fx, fy); nx2 = nrm[axis] ** 2
173 S = ao / ko + (1 - ao) / kr
174 kf = (1 / kr * nx2 + S * (1 - nx2)) / ((1 / kr) ** 2 * nx2 + S / (ao * ko + (1 - ao) * kr) * (1 - nx2))
175 stencil = [(P, -kf), (Q, kf)]
178 sh = (1, 0)
if axis == 0
else (0, 1)
179 Pm = (P[0] - sh[0], P[1] - sh[1]); Qp = (Q[0] + sh[0], Q[1] + sh[1])
180 ok = (method
in (
"DIR",
"DIR-B")
and min(Pm) >= 0
and max(Qp) < n
and
181 G.solid[Pm] == G.solid[P]
and G.solid[Qp] == G.solid[Q])
184 kf = kP
if xi >= 0
else kQ
185 stencil = [(Pm, kf * w[0]), (P, kf * w[1]), (Q, kf * w[2]), (Qp, kf * w[3])]
187 if method
in (
"DIR",
"DIR-B"): nfb += 1
188 kf = 1 / ((0.5 + xi) / kP + (0.5 - xi) / kQ); stencil = [(P, -kf), (Q, kf)]
192 add(idx[P], idx[c], -w / h**2 * -1)
193 add(idx[Q], idx[c], -w / h**2)
196 A = sp.csr_matrix((vals, (rows, cols)), shape=(n * n, n * n))
199 diag = np.zeros(n * n)
200 for (P, bx, by)
in ([((0, j), G.xe[0], G.yc[j])
for j
in range(n)] + [((n - 1, j), G.xe[n], G.yc[j])
for j
in range(n)] +
201 [((i, 0), G.xc[i], G.ye[0])
for i
in range(n)] + [((i, n - 1), G.xc[i], G.ye[n])
for i
in range(n)]):
203 diag[idx[P]] += c; rhs[idx[P]] += c *
exact(bx, by, k1, k2)
204 A = A + sp.diags(diag)
205 T = spla.spsolve(A.tocsc(), rhs)
206 return T.reshape(n, n), nfb
218 from conj
import bilin
220 gq, wq = np.polynomial.legendre.leggauss(24)
221 ks = G.solid.astype(float)
222 r = np.hypot(G.X, G.Y)
223 cut = np.abs(r - R) < 1.5 * h
224 for i, j
in zip(*np.nonzero(cut)):
225 XX, YY = np.meshgrid(G.xc[i] + 0.5 * h * gq, G.yc[j] + 0.5 * h * gq, indexing=
"ij")
226 ks[i, j] = (np.outer(wq, wq) * 0.25 * (np.hypot(XX, YY) < R)).sum()
228 vf, vs = kf > 1e-12, ks > 1e-12
229 idf = -np.ones((n, n), int); idf[vf] = np.arange(vf.sum())
230 ids = -np.ones((n, n), int); ids[vs] = vf.sum() + np.arange(vs.sum())
231 N = vf.sum() + vs.sum()
232 rows, cols, vals = [], [], []
234 def add(r_, c_, v): rows.append(r_); cols.append(c_); vals.append(v)
235 afx, afy = 1 - G.asx, 1 - G.asy
236 for (idx, D, ax_, ay_)
in ((idf, k1, afx, afy), (ids, k2, G.asx, G.asy)):
237 for (a, P, Q)
in ((ax_[1:-1, :], idx[:-1, :], idx[1:, :]), (ay_[:, 1:-1], idx[:, :-1], idx[:, 1:])):
238 m = (a > 0) & (P >= 0) & (Q >= 0)
239 for aa, p, q
in zip(a[m], P[m], Q[m]):
241 add(p, p, cf); add(p, q, -cf); add(q, q, cf); add(q, p, -cf)
242 Ax = -(G.asx[1:, :] - G.asx[:-1, :]) * h; Ay = -(G.asy[:, 1:] - G.asy[:, :-1]) * h
243 Aw = np.hypot(Ax, Ay)
245 for i, j
in zip(*np.nonzero(Aw > 1e-12 * h)):
246 if idf[i, j] < 0
or ids[i, j] < 0:
continue
247 xw = np.array([G.X[i, j], G.Y[i, j]]); xw = xw * R / np.hypot(*xw); nn = xw / R
248 for sf
in (s, 1.0 * h, 1.5 * h):
249 pf = bilin(G, idf, xw + sf * nn)
250 if pf
is not None:
break
251 for ss
in (s, 1.0 * h, 1.5 * h):
252 ps = bilin(G, ids, xw - ss * nn)
253 if ps
is not None:
break
254 gf, gs_ = k1 / sf, k2 / ss
257 g = gf * gs_ / (gf + gs_)
259 add(idf[i, j], col, +Aw[i, j] * g * wv / h**2); add(ids[i, j], col, -Aw[i, j] * g * wv / h**2)
261 add(idf[i, j], col, -Aw[i, j] * g * wv / h**2); add(ids[i, j], col, +Aw[i, j] * g * wv / h**2)
263 for (P, bx, by)
in ([((0, j), G.xe[0], G.yc[j])
for j
in range(n)] + [((n - 1, j), G.xe[n], G.yc[j])
for j
in range(n)] +
264 [((i, 0), G.xc[i], G.ye[0])
for i
in range(n)] + [((i, n - 1), G.xc[i], G.ye[n])
for i
in range(n)]):
266 add(idf[P], idf[P], cc); rhs[idf[P]] += cc *
exact(bx, by, k1, k2)
267 A = sp.csr_matrix((vals, (rows, cols)), shape=(N, N))
268 u = spla.spsolve(A.tocsc(), rhs)
269 T = np.where(G.solid, u[np.maximum(ids, 0)], u[np.maximum(idf, 0)])