def test_residual(self): """ This test loads a SurfaceXYZFourier that interpolates the xyz coordinates of a surface in the NCSX configuration that was computed on a previous branch of pyplasmaopt. Here, we verify that the Boozer residual at these interpolation points is small. """ s = get_exact_surface() coils, currents, ma = get_ncsx_data() stellarator = CoilCollection(coils, currents, 3, True) bs = BiotSavart(stellarator.coils, stellarator.currents) bs_tf = BiotSavart(stellarator.coils, stellarator.currents) weight = 1. tf = ToroidalFlux(s, bs_tf) # these data are obtained from `boozer` branch of pyplamsaopt tf_target = 0.41431152 iota = -0.44856192 boozer_surface = BoozerSurface(bs, s, tf, tf_target) x = np.concatenate((s.get_dofs(), [iota])) r0 = boozer_surface.boozer_penalty_constraints( x, derivatives=0, constraint_weight=weight, optimize_G=False, scalarize=False) # the residual should be close to zero for all entries apart from the y # and z coordinate at phi=0 and theta=0 (and the corresponding rotations) ignores_idxs = np.zeros_like(r0) ignores_idxs[[1, 2, 693, 694, 695, 1386, 1387, 1388, -2, -1]] = 1 assert np.max(np.abs(r0[ignores_idxs < 0.5])) < 1e-8 assert np.max(np.abs(r0[-2:])) < 1e-6
def test_residual(self): """ This test loads a SurfaceXYZFourier that interpolates the xyz coordinates of a surface in the NCSX configuration that was computed on a previous branch of pyplasmaopt. Here, we verify that the QFM residual at these interpolation points is small. This test has been copied from test_boozersurface.py since Boozer coordinates are well defined when a magnetic surface exists, and thus the QFM residual should be small. """ s = get_exact_surface() coils, currents, ma = get_ncsx_data() stellarator = CoilCollection(coils, currents, 3, True) bs = BiotSavart(stellarator.coils, stellarator.currents) bs_tf = BiotSavart(stellarator.coils, stellarator.currents) weight = 1. tf = ToroidalFlux(s, bs_tf) # these data are obtained from `boozer` branch of pyplamsaopt tf_target = 0.41431152 qfm_surface = QfmSurface(bs, s, tf, tf_target) x = s.get_dofs() r0 = qfm_surface.qfm_penalty_constraints(x, derivatives=0, constraint_weight=weight) assert (r0 < 1e-10)
def subtest_boozer_penalty_constraints_gradient(self, surfacetype, stellsym, optimize_G=False): np.random.seed(1) coils, currents, ma = get_ncsx_data() stellarator = CoilCollection(coils, currents, 3, True) bs = BiotSavart(stellarator.coils, stellarator.currents) bs_tf = BiotSavart(stellarator.coils, stellarator.currents) s = get_surface(surfacetype, stellsym) s.fit_to_curve(ma, 0.1) weight = 11.1232 tf = ToroidalFlux(s, bs_tf) tf_target = 0.1 boozer_surface = BoozerSurface(bs, s, tf, tf_target) iota = -0.3 x = np.concatenate((s.get_dofs(), [iota])) if optimize_G: x = np.concatenate((x, [ 2. * np.pi * np.sum(np.abs(bs.coil_currents)) * (4 * np.pi * 10**(-7) / (2 * np.pi)) ])) f0, J0 = boozer_surface.boozer_penalty_constraints( x, derivatives=1, constraint_weight=weight, optimize_G=optimize_G) h = np.random.uniform(size=x.shape) - 0.5 Jex = J0 @ h err_old = 1e9 epsilons = np.power(2., -np.asarray(range(7, 20))) print( "################################################################################" ) for eps in epsilons: f1 = boozer_surface.boozer_penalty_constraints( x + eps * h, derivatives=0, constraint_weight=weight, optimize_G=optimize_G) Jfd = (f1 - f0) / eps err = np.linalg.norm(Jfd - Jex) / np.linalg.norm(Jex) print(err / err_old, f0, f1) assert err < err_old * 0.55 err_old = err print( "################################################################################" )
def test_toroidal_flux_is_constant(self): """ this test ensures that the toroidal flux does not change, regardless of the cross section (varphi = constant) across which it is computed """ s = get_exact_surface() coils, currents, ma = get_ncsx_data() stellarator = CoilCollection(coils, currents, 3, True) bs_tf = BiotSavart(stellarator.coils, stellarator.currents) gamma = s.gamma() num_phi = gamma.shape[0] tf_list = np.zeros((num_phi, )) for idx in range(num_phi): tf = ToroidalFlux(s, bs_tf, idx=idx) tf_list[idx] = tf.J() mean_tf = np.mean(tf_list) max_err = np.max(np.abs(mean_tf - tf_list)) / mean_tf assert max_err < 1e-2
def subtest_boozer_constrained_jacobian(self, surfacetype, stellsym, optimize_G=False): np.random.seed(1) coils, currents, ma = get_ncsx_data() stellarator = CoilCollection(coils, currents, 3, True) bs = BiotSavart(stellarator.coils, stellarator.currents) bs_tf = BiotSavart(stellarator.coils, stellarator.currents) s = get_surface(surfacetype, stellsym) s.fit_to_curve(ma, 0.1) tf = ToroidalFlux(s, bs_tf) tf_target = 0.1 boozer_surface = BoozerSurface(bs, s, tf, tf_target) iota = -0.3 lm = [0., 0.] x = np.concatenate((s.get_dofs(), [iota])) if optimize_G: x = np.concatenate((x, [ 2. * np.pi * np.sum(np.abs(bs.coil_currents)) * (4 * np.pi * 10**(-7) / (2 * np.pi)) ])) xl = np.concatenate((x, lm)) res0, dres0 = boozer_surface.boozer_exact_constraints( xl, derivatives=1, optimize_G=optimize_G) h = np.random.uniform(size=xl.shape) - 0.5 dres_exact = dres0 @ h err_old = 1e9 epsilons = np.power(2., -np.asarray(range(7, 20))) print( "################################################################################" ) for eps in epsilons: res1 = boozer_surface.boozer_exact_constraints( xl + eps * h, derivatives=0, optimize_G=optimize_G) dres_fd = (res1 - res0) / eps err = np.linalg.norm(dres_fd - dres_exact) print(err / err_old) assert err < err_old * 0.55 err_old = err print( "################################################################################" )
def subtest_boozer_penalty_constraints_hessian(self, surfacetype, stellsym, optimize_G=False): np.random.seed(1) coils, currents, ma = get_ncsx_data() stellarator = CoilCollection(coils, currents, 3, True) bs = BiotSavart(stellarator.coils, stellarator.currents) bs_tf = BiotSavart(stellarator.coils, stellarator.currents) s = get_surface(surfacetype, stellsym) s.fit_to_curve(ma, 0.1) tf = ToroidalFlux(s, bs_tf) tf_target = 0.1 boozer_surface = BoozerSurface(bs, s, tf, tf_target) iota = -0.3 x = np.concatenate((s.get_dofs(), [iota])) if optimize_G: x = np.concatenate((x, [ 2. * np.pi * np.sum(np.abs(bs.coil_currents)) * (4 * np.pi * 10**(-7) / (2 * np.pi)) ])) f0, J0, H0 = boozer_surface.boozer_penalty_constraints( x, derivatives=2, optimize_G=optimize_G) h1 = np.random.uniform(size=x.shape) - 0.5 h2 = np.random.uniform(size=x.shape) - 0.5 d2f = h1 @ H0 @ h2 err_old = 1e9 epsilons = np.power(2., -np.asarray(range(10, 20))) print( "################################################################################" ) for eps in epsilons: fp, Jp = boozer_surface.boozer_penalty_constraints( x + eps * h1, derivatives=1, optimize_G=optimize_G) d2f_fd = (Jp @ h2 - J0 @ h2) / eps err = np.abs(d2f_fd - d2f) / np.abs(d2f) print(err / err_old) assert err < err_old * 0.55 err_old = err
def subtest_toroidal_flux1(self, surfacetype, stellsym): coils, currents, ma = get_ncsx_data() stellarator = CoilCollection(coils, currents, 3, True) bs_tf = BiotSavart(stellarator.coils, stellarator.currents) s = get_surface(surfacetype, stellsym) tf = ToroidalFlux(s, bs_tf) coeffs = s.get_dofs() def f(dofs): s.set_dofs(dofs) return tf.J() def df(dofs): s.set_dofs(dofs) return tf.dJ_by_dsurfacecoefficients() taylor_test1(f, df, coeffs)
def subtest_qfm_penalty_constraints_gradient(self, surfacetype, stellsym): np.random.seed(1) coils, currents, ma = get_ncsx_data() stellarator = CoilCollection(coils, currents, 3, True) bs = BiotSavart(stellarator.coils, stellarator.currents) bs_tf = BiotSavart(stellarator.coils, stellarator.currents) s = get_surface(surfacetype, stellsym) s.fit_to_curve(ma, 0.1) weight = 11.1232 tf = ToroidalFlux(s, bs_tf) tf_target = 0.1 qfm_surface = QfmSurface(bs, s, tf, tf_target) x = s.get_dofs() f0, J0 = qfm_surface.qfm_penalty_constraints(x, derivatives=1, constraint_weight=weight) h = np.random.uniform(size=x.shape) - 0.5 Jex = J0 @ h err_old = 1e9 epsilons = np.power(2., -np.asarray(range(9, 17))) print( "################################################################################" ) for eps in epsilons: f1 = qfm_surface.qfm_penalty_constraints(x + eps * h, derivatives=0, constraint_weight=weight) Jfd = (f1 - f0) / eps err = np.linalg.norm(Jfd - Jex) / np.linalg.norm(Jex) print(err / err_old) assert err < err_old * 0.6 err_old = err print( "################################################################################" )
def subtest_qfm_penalty_constraints_hessian(self, surfacetype, stellsym): np.random.seed(1) coils, currents, ma = get_ncsx_data() stellarator = CoilCollection(coils, currents, 3, True) bs = BiotSavart(stellarator.coils, stellarator.currents) bs_tf = BiotSavart(stellarator.coils, stellarator.currents) s = get_surface(surfacetype, stellsym) s.fit_to_curve(ma, 0.1) tf = ToroidalFlux(s, bs_tf) tf_target = 0.5 qfm_surface = QfmSurface(bs, s, tf, tf_target) x = s.get_dofs() f0, J0, H0 = qfm_surface.qfm_penalty_constraints(x, derivatives=2) h1 = np.random.uniform(size=x.shape) - 0.5 h2 = np.random.uniform(size=x.shape) - 0.5 d2f = h1 @ H0 @ h2 err_old = 1e9 epsilons = np.power(2., -np.asarray(range(11, 18))) print( "################################################################################" ) for eps in epsilons: fp, Jp = qfm_surface.qfm_penalty_constraints(x + eps * h1, derivatives=1) d2f_fd = (Jp @ h2 - J0 @ h2) / eps err = np.abs(d2f_fd - d2f) / np.abs(d2f) print(err / err_old) # assert err < err_old * 0.6 err_old = err
bs_tf = BiotSavart(coils, currents) G0 = 2. * np.pi * np.sum(np.abs(bs.coil_currents)) * (4 * np.pi * 10**(-7) / (2 * np.pi)) mpol = 5 # try increasing this to 8 or 10 for smoother surfaces ntor = 5 # try increasing this to 8 or 10 for smoother surfaces stellsym = True nfp = 3 phis = np.linspace(0, 1/nfp, 2*ntor+1, endpoint=False) thetas = np.linspace(0, 1, 2*mpol+1, endpoint=False) s = SurfaceXYZTensorFourier( mpol=mpol, ntor=ntor, stellsym=stellsym, nfp=nfp, quadpoints_phi=phis, quadpoints_theta=thetas) s.fit_to_curve(ma, 0.10, flip_theta=True) iota = -0.4 tf = ToroidalFlux(s, bs_tf) ar = Area(s) ar_target = ar.J() boozer_surface = BoozerSurface(bs, s, ar, ar_target) # compute surface first using LBFGS, this will just be a rough initial guess res = boozer_surface.minimize_boozer_penalty_constraints_LBFGS(tol=1e-10, maxiter=300, constraint_weight=100., iota=iota, G=G0) print(f"After LBFGS: iota={res['iota']:.3f}, tf={tf.J():.3f}, area={s.area():.3f}, ||residual||={np.linalg.norm(boozer_surface_residual(s, res['iota'], res['G'], bs, derivatives=0)):.3e}") if "DISPLAY" in os.environ: s.plot() # now drive the residual down using a specialised least squares algorithm res = boozer_surface.minimize_boozer_penalty_constraints_ls(tol=1e-10, maxiter=100, constraint_weight=100., iota=res['iota'], G=res['G'], method='manual') print(f"After Lev-Mar: iota={res['iota']:.3f}, tf={tf.J():.3f}, area={s.area():.3f}, ||residual||={np.linalg.norm(boozer_surface_residual(s, res['iota'], res['G'], bs, derivatives=0)):.3e}") if "DISPLAY" in os.environ: s.plot()