def arc_length_parameterize(x, y, tol=1e-14, filter_fraction=0.9, return_t=False): """ Reparametrize the periodic curve defined by (x, y) Note that although this will solve the Newton problem to tol, the actual parameterization will not be arclength to that value unless the speed of the parameterization is resolved to that tolerance! Resolving the speed may take significantly more resolution than the coordinates (x, y) """ n = x.shape[0] dt, tv, ik, ikr = _setup(n) xh, yh, sd = _get_speed(x, y, ik) # total arc-length al = np.sum(sd)*dt # rescaled speed asd = sd*2*np.pi/al # fourier transform for speed and periodized arc-length pal_hat = np.fft.fft(asd)/ikr sd_hat = np.fft.fft(asd) # functions for newton solve to get arc-length coordinates def al_func(s): f = nufft_interpolation1d(s, pal_hat) return f + s - tv def J_func(s): return nufft_interpolation1d(s, sd_hat) # run Newton solver solver = VectorNewton(al_func, J_func) snew = solver.solve(tv, tol=tol, verbose=False) if False: x = nufft_interpolation1d(snew, xh) y = nufft_interpolation1d(snew, yh) filt = lambda x: fractional_fourier_filter(x, filter_fraction) if return_t: return filt(x), filt(y), snew else: return filt(x), filt(y) else: snew = tv+fractional_fourier_filter(snew-tv, filter_fraction) x = nufft_interpolation1d(snew, xh) y = nufft_interpolation1d(snew, yh) if return_t: return x, y, snew else: return x, y
def old_arc_length_parameterize(x, y, tol=1e-14, filter_function=None, return_t=False): """ Reparametrize the periodic curve defined by (x, y) Note that although this will solve the Newton problem to tol, the actual parameterization will not be arclength to that value unless the speed of the parameterization is resolved to that tolerance! Resolving the speed may take significantly more resolution than the coordinates (x, y) Because smooth functions may have high-frequency fourier noise added by the reparametrization, one may consider adding a filter_function, to control high-frequency noise in the reparametrized (x, y) """ if filter_function is None: filter_function = _null_filter_function if type(filter_function) is float: filter_function = SimpleFourierFilter() n = x.shape[0] dt, tv, ik, ikr = _setup(n) xh, yh, sd = _get_speed(x, y, ik) # total arc-length al = np.sum(sd)*dt # rescaled speed asd = sd*2*np.pi/al # fourier transform for speed and periodized arc-length pal_hat = np.fft.fft(asd)/ikr sd_hat = np.fft.fft(asd) # functions for newton solve to get arc-length coordinates def al_func(s): f = nufft_interpolation1d(s, pal_hat) return f + s - tv def J_func(s): return nufft_interpolation1d(s, sd_hat) # run Newton solver solver = VectorNewton(al_func, J_func) snew = solver.solve(tv, tol=tol, verbose=False) # get the new x and y coordinates x = nufft_interpolation1d(snew, xh) y = nufft_interpolation1d(snew, yh) if return_t: return filter_function(x), filter_function(y), snew else: return filter_function(x), filter_function(y)
def generate(self, dt, fixed_grid=False): ebdyc = self.ebdyc ebdyc_old = self.ebdyc_old u, v = self.u, self.v uo, vo = self.uo, self.vo ux, uy, vx, vy = self.ux, self.uy, self.vx, self.vy uxo, uyo, vxo, vyo = self.uxo, self.uyo, self.vxo, self.vyo # interpolate the velocity ubs = ebdyc.interpolate_radial_to_boundary(u) vbs = ebdyc.interpolate_radial_to_boundary(v) # move all boundarys; generate new embedded boundaries new_ebdys = [] self.reparmed_ubs = [] self.reparmed_vbs = [] for ind, ebdy in enumerate(self.ebdyc): if False: # this is the ABF way # interpolate the velocity ub = ubs.bdy_value_list[ind] vb = vbs.bdy_value_list[ind] ubo_new_parm = self.ubos[ind] vbo_new_parm = self.vbos[ind] # move the boundary with Forward Euler bx = ebdy.bdy.x + 0.5 * dt * (3 * ub - ubo_new_parm) by = ebdy.bdy.y + 0.5 * dt * (3 * vb - vbo_new_parm) # repararmetrize the boundary bx, by, new_t = arc_length_parameterize( bx, by, filter_fraction=self.filter_fraction, return_t=True) # move these boundary values for velocity to the new parametrization self.reparmed_ubs.append( nufft_interpolation1d(new_t, np.fft.fft(ub))) self.reparmed_vbs.append( nufft_interpolation1d(new_t, np.fft.fft(vb))) # generate the new embedded boundary new_ebdy = ebdy.regenerate(bx, by) new_ebdys.append(new_ebdy) else: # this is the BDF way # interpolate the velocity ub = ubs.bdy_value_list[ind] vb = vbs.bdy_value_list[ind] ubo_new_parm = self.ubos[ind] vbo_new_parm = self.vbos[ind] # move the boundary with Forward Euler bx = ebdy.bdy.x + 0.5 * dt * (3 * ub - ubo_new_parm) by = ebdy.bdy.y + 0.5 * dt * (3 * vb - vbo_new_parm) # repararmetrize the boundary bx, by, new_t = arc_length_parameterize( bx, by, filter_fraction=self.filter_fraction, return_t=True) # move these boundary values for velocity to the new parametrization self.reparmed_ubs.append( nufft_interpolation1d(new_t, np.fft.fft(ub))) self.reparmed_vbs.append( nufft_interpolation1d(new_t, np.fft.fft(vb))) # generate the new embedded boundary new_ebdy = ebdy.regenerate(bx, by) new_ebdys.append(new_ebdy) new_ebdyc = EmbeddedBoundaryCollection(new_ebdys) # get dnager zone distance umax = np.sqrt(u * u + v * v).max() ddd = 2 * umax * dt # raise an exception if danger zone thicker than radial width if ddd > new_ebdyc[0].radial_width: raise Exception( 'Velocity is so fast that one timestep oversteps safety zones; reduce timestep.' ) # register the grid... if fixed_grid: new_ebdyc.register_grid(ebdyc.grid, danger_zone_distance=ddd) else: new_ebdyc.generate_grid(danger_zone_distance=ddd) # let's get the points that need to be interpolated to aap = new_ebdyc.pnar AP_key = ebdyc.register_points(aap.x, aap.y, dzl=new_ebdyc.danger_zone_list, gil=new_ebdyc.guess_ind_list) OAP_key = ebdyc_old.register_points(aap.x, aap.y, dzl=new_ebdyc.danger_zone_list, gil=new_ebdyc.guess_ind_list) # now we need to interpolate onto things AEP = ebdyc.registered_partitions[AP_key] OAEP = ebdyc_old.registered_partitions[OAP_key] # get departure points xd_all = np.zeros(aap.N) yd_all = np.zeros(aap.N) xD_all = np.zeros(aap.N) yD_all = np.zeros(aap.N) # advect those in the annulus c1n, c2n, c3n = AEP.get_Ns() oc1n, oc2n, oc3n = OAEP.get_Ns() # category 1 and 2 c1_2 = AEP.zone1_or_2 oc1_2 = OAEP.zone1_or_2 fc12 = np.logical_and(c1_2, oc1_2) fc12n = np.sum(fc12) # category 1 and 2 # NOTE: THESE INTERPOLATIONS CAN BE MADE FASTER BY EXPLOITING SHARED # GRIDPOINTS IF THAT IS ENFORCED IN GRID GENERATION # THIS IS NOT EXPLOITED, FOR THE TIME BEING uxh = ebdyc.interpolate_to_points(ux, aap.x, aap.y) uyh = ebdyc.interpolate_to_points(uy, aap.x, aap.y) vxh = ebdyc.interpolate_to_points(vx, aap.x, aap.y) vyh = ebdyc.interpolate_to_points(vy, aap.x, aap.y) uh = ebdyc.interpolate_to_points(u, aap.x, aap.y) vh = ebdyc.interpolate_to_points(v, aap.x, aap.y) uxoh = ebdyc_old.interpolate_to_points(uxo, aap.x, aap.y) uyoh = ebdyc_old.interpolate_to_points(uyo, aap.x, aap.y) vxoh = ebdyc_old.interpolate_to_points(vxo, aap.x, aap.y) vyoh = ebdyc_old.interpolate_to_points(vyo, aap.x, aap.y) uoh = ebdyc_old.interpolate_to_points(uo, aap.x, aap.y) voh = ebdyc_old.interpolate_to_points(vo, aap.x, aap.y) SLM = np.zeros([ fc12n, ] + [4, 4], dtype=float) SLR = np.zeros([ fc12n, ] + [ 4, ], dtype=float) # solve for departure points SLM[:, 0, 0] = uxh[fc12] SLM[:, 0, 1] = uyh[fc12] SLM[:, 0, 2] = 0.5 / dt SLM[:, 0, 3] = 0.0 SLM[:, 1, 0] = vxh[fc12] SLM[:, 1, 1] = vyh[fc12] SLM[:, 1, 2] = 0.0 SLM[:, 1, 3] = 0.5 / dt SLM[:, 2, 0] = 2.0 / dt + 3 * uxh[fc12] SLM[:, 2, 1] = 3 * uyh[fc12] SLM[:, 2, 2] = -uxoh[fc12] SLM[:, 2, 3] = -uyoh[fc12] SLM[:, 3, 0] = 3 * vxh[fc12] SLM[:, 3, 1] = 2.0 / dt + 3 * vyh[fc12] SLM[:, 3, 2] = -vxoh[fc12] SLM[:, 3, 3] = -vyoh[fc12] SLR[:, 0] = uh[fc12] SLR[:, 1] = vh[fc12] SLR[:, 2] = 3 * uh[fc12] - uoh[fc12] SLR[:, 3] = 3 * vh[fc12] - voh[fc12] OUT = np.linalg.solve(SLM, SLR) dx, dy, Dx, Dy = OUT[:, 0], OUT[:, 1], OUT[:, 2], OUT[:, 3] xd, yd = aap.x[fc12] - dx, aap.y[fc12] - dy xD, yD = aap.x[fc12] - Dx, aap.y[fc12] - Dy xd_all[fc12] = xd yd_all[fc12] = yd xD_all[fc12] = xD yD_all[fc12] = yD # categroy 3... this is the tricky one fc3n = aap.N - fc12n # print('Number of points in category 3 is:', fc3n) if fc3n > 0: for ind, (ebdy, ebdy_old) in enumerate(zip(ebdyc, ebdyc_old)): ub = ubs.bdy_value_list[ind] vb = vbs.bdy_value_list[ind] c3l = AEP.zone3l[ind] oc3l = OAEP.zone3l[ind] fc3l = np.unique(np.concatenate([c3l, oc3l])) th = ebdy.bdy.dt tk = ebdy.bdy.k def d1_der(f): return np.fft.ifft(np.fft.fft(f) * tk * 1j).real interp = lambda f: interp1d(0, 2 * np.pi, th, f, k=3, p=True) bx_interp = interp(ebdy.bdy.x) by_interp = interp(ebdy.bdy.y) bxs_interp = interp(d1_der(ebdy.bdy.x)) bys_interp = interp(d1_der(ebdy.bdy.y)) nx_interp = interp(ebdy.bdy.normal_x) ny_interp = interp(ebdy.bdy.normal_y) nxs_interp = interp(d1_der(ebdy.bdy.normal_x)) nys_interp = interp(d1_der(ebdy.bdy.normal_y)) urb = ebdy.interpolate_radial_to_boundary_normal_derivative( u[0]) vrb = ebdy.interpolate_radial_to_boundary_normal_derivative( v[0]) urrb = ebdy.interpolate_radial_to_boundary_normal_derivative2( u[0]) vrrb = ebdy.interpolate_radial_to_boundary_normal_derivative2( v[0]) ub_interp = interp(ub) vb_interp = interp(vb) urb_interp = interp(urb) vrb_interp = interp(vrb) urrb_interp = interp(urrb) vrrb_interp = interp(vrrb) ubs_interp = interp(d1_der(ub)) vbs_interp = interp(d1_der(vb)) urbs_interp = interp(d1_der(urb)) vrbs_interp = interp(d1_der(vrb)) urrbs_interp = interp(d1_der(urrb)) vrrbs_interp = interp(d1_der(vrrb)) old_bx_interp = interp(ebdy_old.bdy.x) old_by_interp = interp(ebdy_old.bdy.y) old_bxs_interp = interp(d1_der(ebdy_old.bdy.x)) old_bys_interp = interp(d1_der(ebdy_old.bdy.y)) old_nx_interp = interp(ebdy_old.bdy.normal_x) old_ny_interp = interp(ebdy_old.bdy.normal_y) old_nxs_interp = interp(d1_der(ebdy_old.bdy.normal_x)) old_nys_interp = interp(d1_der(ebdy_old.bdy.normal_y)) old_ub = ebdy_old.interpolate_radial_to_boundary(uo[0]) old_vb = ebdy_old.interpolate_radial_to_boundary(vo[0]) old_urb = ebdy_old.interpolate_radial_to_boundary_normal_derivative( uo[0]) old_vrb = ebdy_old.interpolate_radial_to_boundary_normal_derivative( vo[0]) old_urrb = ebdy_old.interpolate_radial_to_boundary_normal_derivative2( uo[0]) old_vrrb = ebdy_old.interpolate_radial_to_boundary_normal_derivative2( vo[0]) # i think the old parm is right, but should think about old_ub_interp = interp(old_ub) old_vb_interp = interp(old_vb) old_urb_interp = interp(old_urb) old_vrb_interp = interp(old_vrb) old_urrb_interp = interp(old_urrb) old_vrrb_interp = interp(old_vrrb) old_ubs_interp = interp(d1_der(old_ub)) old_vbs_interp = interp(d1_der(old_vb)) old_urbs_interp = interp(d1_der(old_urb)) old_vrbs_interp = interp(d1_der(old_vrb)) old_urrbs_interp = interp(d1_der(old_urrb)) old_vrrbs_interp = interp(d1_der(old_vrrb)) xx = aap.x[fc3l] yy = aap.y[fc3l] def objective(s, r, so, ro): f = np.empty([s.size, 4]) f[:, 0] = old_bx_interp(so) + ro * old_nx_interp( so) + 2 * dt * ub_interp(s) + 2 * dt * r * urb_interp( s) + dt * r**2 * urrb_interp(s) - xx f[:, 1] = old_by_interp(so) + ro * old_ny_interp( so) + 2 * dt * vb_interp(s) + 2 * dt * r * vrb_interp( s) + dt * r**2 * vrrb_interp(s) - yy f[:, 2] = bx_interp(s) + r * nx_interp( s ) + 1.5 * dt * ub_interp(s) + 1.5 * dt * r * urb_interp( s) + 0.75 * dt * r**2 * urrb_interp( s) - 0.5 * dt * old_ub_interp( so) - 0.5 * dt * ro * old_urb_interp( so) - 0.25 * dt * ro**2 * old_urrb_interp( so) - xx f[:, 3] = by_interp(s) + r * ny_interp( s ) + 1.5 * dt * vb_interp(s) + 1.5 * dt * r * vrb_interp( s) + 0.75 * dt * r**2 * vrrb_interp( s) - 0.5 * dt * old_vb_interp( so) - 0.5 * dt * ro * old_vrb_interp( so) - 0.25 * dt * ro**2 * old_vrrb_interp( so) - yy return f def Jac(s, r, so, ro): J = np.empty([s.size, 4, 4]) # derivative with respect to s J[:, 0, 0] = 2 * dt * ubs_interp(s) + 2 * dt * r * urbs_interp( s) + dt * r**2 * urrbs_interp(s) J[:, 1, 0] = 2 * dt * vbs_interp(s) + 2 * dt * r * vrbs_interp( s) + dt * r**2 * vrrbs_interp(s) J[:, 2, 0] = bxs_interp( s) + r * nxs_interp(s) + 1.5 * dt * ubs_interp( s) + 1.5 * dt * r * urbs_interp( s) + 0.75 * dt * r**2 * urrbs_interp(s) J[:, 3, 0] = bys_interp( s) + r * nys_interp(s) + 1.5 * dt * vbs_interp( s) + 1.5 * dt * r * vrbs_interp( s) + 0.75 * dt * r**2 * vrrbs_interp(s) # derivative with respect to r J[:, 0, 1] = 2 * dt * urb_interp(s) + 2 * dt * r * urrb_interp(s) J[:, 1, 1] = 2 * dt * vrb_interp(s) + 2 * dt * r * vrrb_interp(s) J[:, 2, 1] = nx_interp(s) + 1.5 * dt * urb_interp( s) + 1.5 * dt * r * urrb_interp(s) J[:, 3, 1] = ny_interp(s) + 1.5 * dt * vrb_interp( s) + 1.5 * dt * r * vrrb_interp(s) # derivative with respect to so J[:, 0, 2] = old_bxs_interp(so) + ro * old_nxs_interp(so) J[:, 1, 2] = old_bys_interp(so) + ro * old_nys_interp(so) J[:, 2, 2] = -0.5 * dt * old_ubs_interp( so) - 0.5 * dt * ro * old_urbs_interp( so) - 0.25 * dt * ro**2 * old_urrbs_interp(so) J[:, 3, 2] = -0.5 * dt * old_vbs_interp( so) - 0.5 * dt * ro * old_vrbs_interp( so) - 0.25 * dt * ro**2 * old_vrrbs_interp(so) # derivative with respect to ro J[:, 0, 3] = old_nx_interp(so) J[:, 1, 3] = old_ny_interp(so) J[:, 2, 3] = -0.5 * dt * old_urb_interp( so) - 0.5 * dt * ro * old_urrb_interp(so) J[:, 3, 3] = -0.5 * dt * old_vrb_interp( so) - 0.5 * dt * ro * old_vrrb_interp(so) return J # take as guess inds our s, r s = AEP.full_t[fc3l] r = AEP.full_r[fc3l] so = OAEP.full_t[fc3l] ro = OAEP.full_r[fc3l] # now solve for sd, rd res = objective(s, r, so, ro) mres1 = np.hypot(res[:, 0], res[:, 1]).max() mres2 = np.hypot(res[:, 2], res[:, 3]).max() mres = max(mres1, mres2) tol = 1e-12 while mres > tol: J = Jac(s, r, so, ro) d = np.linalg.solve(J, res) s -= d[:, 0] r -= d[:, 1] so -= d[:, 2] ro -= d[:, 3] res = objective(s, r, so, ro) mres1 = np.hypot(res[:, 0], res[:, 1]).max() mres2 = np.hypot(res[:, 2], res[:, 3]).max() mres = max(mres1, mres2) r_fail_1 = r.max() > 0.0 r_fail_2 = r.min() < -ebdy.radial_width ro_fail_1 = ro.max() > 0.0 ro_fail_2 = ro.min() < -ebdy_old.radial_width r_fail = r_fail_1 or r_fail_2 ro_fail = ro_fail_1 or ro_fail_2 fail = r_fail or ro_fail fail_amount = 0.0 if fail: if r_fail_1: fail_amount = max(fail_amount, r.max()) r[r > 0.0] = 0.0 if r_fail_2: fail_amount = max(fail_amount, (-r - ebdy.radial_width).max()) r[r < -ebdy.radial_width] = -ebdy.radial_width if ro_fail_1: fail_amount = max(fail_amount, ro.max()) ro[ro > 0.0] = 0.0 if ro_fail_2: fail_amount = max(fail_amount, (-ro - ebdy_old.radial_width).max()) ro[ro < -ebdy_old.radial_width] = -ebdy_old.radial_width # get the departure points xd = bx_interp(s) + nx_interp(s) * r yd = by_interp(s) + ny_interp(s) * r xD = old_bx_interp(so) + old_nx_interp(so) * ro yD = old_by_interp(so) + old_ny_interp(so) * ro xd_all[fc3l] = xd yd_all[fc3l] = yd xD_all[fc3l] = xD yD_all[fc3l] = yD self.new_ebdyc = new_ebdyc self.xd_all = xd_all self.yd_all = yd_all self.xD_all = xD_all self.yD_all = yD_all return self.new_ebdyc
def generate(self, dt, fixed_grid=False): """ If fixed_grid = True, reuse same grid Otherwise, generate new grid """ ebdyc = self.ebdyc u, v = self.u, self.v ux, uy, vx, vy = self.ux, self.uy, self.vx, self.vy # interpolate the velocity ubs = ebdyc.interpolate_radial_to_boundary(u) vbs = ebdyc.interpolate_radial_to_boundary(v) # move all boundarys; generate new embedded boundaries new_ebdys = [] self.reparmed_ubs = [] self.reparmed_vbs = [] for ind, ebdy in enumerate(ebdyc): # interpolate the velocity ub = ubs[ind] vb = vbs[ind] # move the boundary with Forward Euler bx = ebdy.bdy.x + dt*ub by = ebdy.bdy.y + dt*vb # repararmetrize the boundary bx, by, new_t = arc_length_parameterize(bx, by, filter_fraction=self.filter_fraction, return_t=True) # bx, by, new_t = bx, by, np.linspace(0, 2*np.pi, bx.size, endpoint=False) # bx, by, new_t = arc_length_parameterize(bx, by, return_t=True, filter_function=self.filter_function) # move these boundary values to the new parametrization # This is not necessary for this timestepper, but is used by other # timesteppers which use this as a startup! # SHOULD I SWITCH THIS TO NUFFT WHEN THAT IS BEING USED? self.reparmed_ubs.append(nufft_interpolation1d(new_t, np.fft.fft(ub))) self.reparmed_vbs.append(nufft_interpolation1d(new_t, np.fft.fft(vb))) # bu_interp = interp1d(0, 2*np.pi, ebdy.bdy.dt, ub, p=True) # bv_interp = interp1d(0, 2*np.pi, ebdy.bdy.dt, vb, p=True) # self.reparmed_ubs.append(bu_interp(new_t)) # self.reparmed_vbs.append(bv_interp(new_t)) # generate the new embedded boundary new_ebdy = ebdy.regenerate(bx, by) new_ebdys.append(new_ebdy) new_ebdyc = EmbeddedBoundaryCollection(new_ebdys) # get dnager zone distance umax = np.sqrt(u*u + v*v).max() ddd = 2*umax*dt # raise an exception if danger zone thicker than radial width if ddd > new_ebdyc[0].radial_width: raise Exception('Velocity is so fast that one timestep oversteps safety zones; reduce timestep.') # register the grid... if fixed_grid: new_ebdyc.register_grid(ebdyc.grid, danger_zone_distance=ddd) else: new_ebdyc.generate_grid(danger_zone_distance=ddd) # let's get the points that need to be interpolated to aap = new_ebdyc.pnar AP_key = ebdyc.register_points(aap.x, aap.y, dzl=new_ebdyc.danger_zone_list, gil=new_ebdyc.guess_ind_list) # now we need to interpolate onto things AEP = ebdyc.registered_partitions[AP_key] # get departure points xd_all = np.zeros(aap.N) yd_all = np.zeros(aap.N) c1n, c2n, c3n = AEP.get_Ns() # category 1 and 2 c1_2n = c1n + c2n c1_2 = AEP.zone1_or_2 uxh = ebdyc.interpolate_to_points(ux, aap.x, aap.y) uyh = ebdyc.interpolate_to_points(uy, aap.x, aap.y) vxh = ebdyc.interpolate_to_points(vx, aap.x, aap.y) vyh = ebdyc.interpolate_to_points(vy, aap.x, aap.y) uh = ebdyc.interpolate_to_points(u, aap.x, aap.y) vh = ebdyc.interpolate_to_points(v, aap.x, aap.y) SLM = np.zeros([c1_2n,] + [2,2], dtype=float) SLR = np.zeros([c1_2n,] + [2,], dtype=float) SLM[:,0,0] = 1 + dt*uxh[c1_2] SLM[:,0,1] = dt*uyh[c1_2] SLM[:,1,0] = dt*vxh[c1_2] SLM[:,1,1] = 1 + dt*vyh[c1_2] SLR[:,0] = dt*uh[c1_2] SLR[:,1] = dt*vh[c1_2] OUT = np.linalg.solve(SLM, SLR) xdt, ydt = OUT[:,0], OUT[:,1] xd, yd = aap.x[c1_2] - xdt, aap.y[c1_2] - ydt xd_all[c1_2] = xd yd_all[c1_2] = yd # categroy 3... this is the tricky one if c3n > 0: for ind, ebdy in enumerate(ebdyc): ub = ubs[ind] vb = vbs[ind] c3l = AEP.zone3l[ind] th = ebdy.bdy.dt # th = 2*np.pi/nb # tk = np.fft.fftfreq(nb, th/(2*np.pi)) tk = ebdy.bdy.k def d1_der(f): return np.fft.ifft(np.fft.fft(f)*tk*1j).real interp = lambda f: interp1d(0, 2*np.pi, th, f, k=3, p=True) bx_interp = interp(ebdy.bdy.x) by_interp = interp(ebdy.bdy.y) bxs_interp = interp(d1_der(ebdy.bdy.x)) bys_interp = interp(d1_der(ebdy.bdy.y)) nx_interp = interp(ebdy.bdy.normal_x) ny_interp = interp(ebdy.bdy.normal_y) nxs_interp = interp(d1_der(ebdy.bdy.normal_x)) nys_interp = interp(d1_der(ebdy.bdy.normal_y)) urb = ebdy.interpolate_radial_to_boundary_normal_derivative(u[ind]) vrb = ebdy.interpolate_radial_to_boundary_normal_derivative(v[ind]) ub_interp = interp(ub) vb_interp = interp(vb) urb_interp = interp(urb) vrb_interp = interp(vrb) ubs_interp = interp(d1_der(ub)) vbs_interp = interp(d1_der(vb)) urbs_interp = interp(d1_der(urb)) vrbs_interp = interp(d1_der(vrb)) xo = aap.x[c3l] yo = aap.y[c3l] def objective(s, r): f = np.empty([s.size, 2]) f[:,0] = bx_interp(s) + r*nx_interp(s) + dt*ub_interp(s) + dt*r*urb_interp(s) - xo f[:,1] = by_interp(s) + r*ny_interp(s) + dt*vb_interp(s) + dt*r*vrb_interp(s) - yo return f def Jac(s, r): J = np.empty([s.size, 2, 2]) J[:,0,0] = bxs_interp(s) + r*nxs_interp(s) + dt*ubs_interp(s) + dt*r*urbs_interp(s) J[:,1,0] = bys_interp(s) + r*nys_interp(s) + dt*vbs_interp(s) + dt*r*vrbs_interp(s) J[:,0,1] = nx_interp(s) + dt*urb_interp(s) J[:,1,1] = ny_interp(s) + dt*vrb_interp(s) return J # take as guess inds our s, r s = AEP.zone3t[ind] r = AEP.zone3r[ind] # now solve for sd, rd res = objective(s, r) mres = np.hypot(res[:,0], res[:,1]).max() tol = 1e-12 while mres > tol: J = Jac(s, r) d = np.linalg.solve(J, res) s -= d[:,0] r -= d[:,1] res = objective(s, r) mres = np.hypot(res[:,0], res[:,1]).max() # get the departure points xd = bx_interp(s) + nx_interp(s)*r yd = by_interp(s) + ny_interp(s)*r xd_all[c3l] = xd yd_all[c3l] = yd self.new_ebdyc = new_ebdyc self.xd_all = xd_all self.yd_all = yd_all return self.new_ebdyc
def J_func(s): return nufft_interpolation1d(s, sd_hat)
def al_func(s): f = nufft_interpolation1d(s, pal_hat) return f + s - tv