def divide_grid_and_radial2(self, v): gv, w = np.split(v, [self.grid_phys.N]) g = np.zeros(self.grid.shape, v.dtype) g[self.phys] = gv w = self.v2r(w) out = EmbeddedFunction(self) out.load_data(g, w) return out
def __call__(self, f, **kwargs): """ f must be of type EmbeddedFunction """ _, fc, fr_list = f.get_components() # get the grid-based solution uch, uc = self._grid_solve(fc) # get interpolate method if self.interpolation_order == np.Inf: # get derivatives in Fourier space ucxh, ucyh = self.ikx * uch, self.iky * uch uch_stack = np.stack([uch, ucxh, ucyh]) interpolater = periodic_interp2d(fh=uch_stack, eps=1e-14, upsampfac=1.25, spread_kerevalmeth=0) all_bvs = interpolater(self.ebdyc.interfaces_x_transf, self.ebdyc.interfaces_y_transf) bvs = all_bvs[0].real bxs = all_bvs[1].real bys = all_bvs[2].real else: # interpolate the solution to the interface bvs = self.ebdyc.interpolate_grid_to_interface( uc, order=self.interpolation_order, cutoff=False) # get the grid solution's derivatives and interpolate to interface ucx, ucy = self.dx(uc), self.dy(uc) bxs = self.ebdyc.interpolate_grid_to_interface( ucx, order=self.interpolation_order, cutoff=False) bys = self.ebdyc.interpolate_grid_to_interface( ucy, order=self.interpolation_order, cutoff=False) # convert these from lists to vectors bvl, bxl, byl = self.ebdyc.v2l(bvs), self.ebdyc.v2l( bxs), self.ebdyc.v2l(bys) # compute the needed layer potentials sigmag_list = [] for helper, fr, bv, bx, by in zip(self.helpers, fr_list, bvl, bxl, byl): sigmag_list.append(helper(fr, bv, bx, by, **kwargs)) self.iteration_counts = [ helper.iterations_last_call for helper in self.helpers ] # we now need to evaluate this onto the grid / interface points sigmag = np.concatenate(sigmag_list) out = self.evaluate_to_grid_pnai(sigmag) # need to divide this apart gu, bus = self.ebdyc.divide_pnai(out) # we can now add gu directly to uc uc[self.ebdyc.phys_not_in_annulus] += gu # we have to send the bslps back to the indivdual ebdys to deal with them urs = [helper.correct(bu) for helper, bu in zip(self.helpers, bus)] # interpolate urs onto uc _ = self.ebdyc.interpolate_radial_to_grid1(urs, uc) uc *= self.ebdyc.phys ue = EmbeddedFunction(self.ebdyc) ue.load_data(uc, urs) return ue
def gradient(self, ff, derivative_type='spectral'): """ Compute the gradient of a function defined on the embedded boundary collection Inputs: ff, EmbeddedFunction: function to take the gradient of derivative_type: 'spectral' or 'fourth' in both cases, spectral differentation is used in the radial regions. On the grid, if 'spectral', then the function is cutoff and fourier based estimation of the derivative is used; if 'fourth', then the function is NOT cutoff and fourth-order centered differences are used. This may provide better accuracy when the cutoff windows are thin. However, if the cutoff windows are not at least 2h, then this can give catastrophically bad values Outputs: fx, fy: EmbeddedFunctions giving each required derivative """ f, _, fr_list = ff.get_components() if derivative_type == 'spectral': fc = f * self.grid_step fc[self.ext] = 0.0 fch = np.fft.fft2(fc) fxh = fch * self.ikx fyh = fch * self.iky fx = np.fft.ifft2(fxh).real fy = np.fft.ifft2(fyh).real else: fx = fd_x_4(f, self.grid.xh) fy = fd_y_4(f, self.grid.yh) # compute on the radial grid fxrs, fyrs = [], [] for i in range(self.N): fxr, fyr = self[i].gradient(fx, fy, fr_list[i]) fxrs.append(fxr) fyrs.append(fyr) # set to 0 on regular grid in the exterior region fx *= self.phys fy *= self.phys # generate EmbeddedFunctions ffx = EmbeddedFunction(self) ffy = EmbeddedFunction(self) ffx.load_data(fx, fxrs) ffy.load_data(fy, fyrs) return ffx, ffy
def laplacian(self, ff, derivative_type='spectral'): """ Compute the laplacian of a function defined on the embedded boundary collection Inputs: ff, EmbeddedFunction: function to take the gradient of derivative_type: 'spectral' or 'fourth' in both cases, spectral differentation is used in the radial regions. On the grid, if 'spectral', then the function is cutoff and fourier based estimation of the derivative is used; if 'fourth', then the function is NOT cutoff and fourth-order centered differences are used. This may provide better accuracy when the cutoff windows are thin. However, if the cutoff windows are not at least 2h, then this can give catastrophically bad values Outputs: lapf: EmbeddedFunction giving the laplacian of f """ f, _, fr_list = ff.get_components() if derivative_type == 'spectral': fc = f * self.grid_step fc[self.ext] = 0.0 fch = np.fft.fft2(fc) lapfh = fch * self.lap lapf = np.fft.ifft2(lapfh).real else: fx = fd_x_4(f, self.grid.xh) fy = fd_y_4(f, self.grid.yh) fxx = fd_x_4(fx, self.grid.xh) fyy = fd_y_4(fy, self.grid.yh) # compute on the radial grid lapfrs = [] for i in range(self.N): lapfr = self.ebdys[i].laplacian(lapf, fr_list[i]) lapfrs.append(lapfr) # set to 0 on regular grid in the exterior region lapf *= self.phys # generate EmbeddedFunctions lapff = EmbeddedFunction(self) lapff.load_data(lapf, lapfrs) return lapff
def __call__(self, fu, fv, **kwargs): # separate the components fuc = fu.get_smoothed_grid_value() fvc = fv.get_smoothed_grid_value() fur_list = fu.get_radial_value_list() fvr_list = fv.get_radial_value_list() uc, vc, pc = self._grid_solve(fuc, fvc) # interpolate the solution to the interface bus = self.ebdyc.interpolate_grid_to_interface( uc, order=self.interpolation_order, cutoff=False) bvs = self.ebdyc.interpolate_grid_to_interface( vc, order=self.interpolation_order, cutoff=False) # get the grid solution's derivatives ucx, ucy = self.dx(uc), self.dy(uc) vcx, vcy = self.dx(vc), self.dy(vc) # compute the grid solutions stress tcxx = 2 * ucx - pc tcxy = ucy + vcx tcyy = 2 * vcy - pc # interpolate these to the interface btxxs = self.ebdyc.interpolate_grid_to_interface( tcxx, order=self.interpolation_order, cutoff=False) btxys = self.ebdyc.interpolate_grid_to_interface( tcxy, order=self.interpolation_order, cutoff=False) btyys = self.ebdyc.interpolate_grid_to_interface( tcyy, order=self.interpolation_order, cutoff=False) # convert these from lists to vectors bul, bvl = self.ebdyc.v2l(bus), self.ebdyc.v2l(bvs) btxxl, btxyl, btyyl = self.ebdyc.v2l(btxxs), self.ebdyc.v2l( btxys), self.ebdyc.v2l(btyys) # compute the needed layer potentials sigmag_list = [] for helper, fur, fvr, bu, bv, btxx, btxy, btyy in zip( self.helpers, fur_list, fvr_list, bul, bvl, btxxl, btxyl, btyyl): sigmag_list.append( helper(fur, fvr, bu, bv, btxx, btxy, btyy, **kwargs)) # we now need to evaluate this onto the grid / interface points sigmag = np.column_stack(sigmag_list) out = self.Layer_Apply(self.grid_sources, self.ebdyc.grid_pnai, sigmag) # need to divide this apart gu, bus = self.ebdyc.divide_pnai(out[0]) gv, bvs = self.ebdyc.divide_pnai(out[1]) gp, bps = self.ebdyc.divide_pnai(out[2]) # we can now add gu directly to uc uc[self.ebdyc.phys_not_in_annulus] += gu vc[self.ebdyc.phys_not_in_annulus] += gv pc[self.ebdyc.phys_not_in_annulus] += gp # we have to send the bslps back to the indivdual ebdys to deal with them single_ebdy = len(self.ebdyc) == 1 urs, vrs, prs = zip(*[ helper.correct(bu, bv, bp, single_ebdy) for helper, bu, bv, bp in zip(self.helpers, bus, bvs, bps) ]) # interpolate urs onto uc _ = self.ebdyc.interpolate_radial_to_grid1(urs, uc) _ = self.ebdyc.interpolate_radial_to_grid1(vrs, vc) _ = self.ebdyc.interpolate_radial_to_grid1(prs, pc) uc *= self.ebdyc.phys vc *= self.ebdyc.phys pc *= self.ebdyc.phys u = EmbeddedFunction(self.ebdyc) v = EmbeddedFunction(self.ebdyc) p = EmbeddedFunction(self.ebdyc) u.load_data(uc, urs) v.load_data(vc, vrs) p.load_data(pc, prs) return u, v, p
fv = fv_function(grid.xg, grid.yg) ua = u_function(grid.xg, grid.yg) va = v_function(grid.xg, grid.yg) fu_rs = [fu_function(ebdy.radial_x, ebdy.radial_y) for ebdy in ebdys] fv_rs = [fv_function(ebdy.radial_x, ebdy.radial_y) for ebdy in ebdys] ua_rs = [u_function(ebdy.radial_x, ebdy.radial_y) for ebdy in ebdys] va_rs = [v_function(ebdy.radial_x, ebdy.radial_y) for ebdy in ebdys] pa_rs = [p_function(ebdy.radial_x, ebdy.radial_y) for ebdy in ebdys] pa_rs = [pa_r - np.mean(pa_r) for pa_r in pa_rs] upper_u = np.concatenate( [u_function(ebdy.bdy.x, ebdy.bdy.y) for ebdy in ebdys]) upper_v = np.concatenate( [v_function(ebdy.bdy.x, ebdy.bdy.y) for ebdy in ebdys]) _fu = EmbeddedFunction(ebdyc) _fu.load_data(fu, fu_rs) fu = _fu _fv = EmbeddedFunction(ebdyc) _fv.load_data(fv, fv_rs) fv = _fv # setup the solver solver = StokesSolver(ebdyc, solver_type=solver_type) uc, vc, pc = solver(fu, fv, tol=1e-12, verbose=verbose) ur = urs[0] vr = vrs[0] if plot: mue = np.ma.array(uc, mask=ebdyc.ext) fig, ax = plt.subplots() ax.pcolormesh(grid.xg, grid.yg, mue)