def test_dBdX_by_dcoilcoeff_reverse_taylortest(self): np.random.seed(1) coil = get_coil() bs = BiotSavart([coil], [1e4]) points = np.asarray( 17 * [[-1.41513202e-03, 8.99999382e-01, -3.14473221e-04]]) points += 0.001 * (np.random.rand(*points.shape) - 0.5) bs.set_points(points) coil_dofs = np.asarray(coil.get_dofs()) B = bs.B() dBdX = bs.dB_by_dX() J0 = np.sum(dBdX**2) dJ = bs.B_and_dB_vjp(B, dBdX) h = 1e-2 * np.random.rand(len(coil_dofs)).reshape(coil_dofs.shape) dJ_dh = 2 * np.sum(dJ[1][0] * h) err = 1e6 for i in range(5, 10): eps = 0.5**i coil.set_dofs(coil_dofs + eps * h) bs.clear_cached_properties() dBdXh = bs.dB_by_dX() Jh = np.sum(dBdXh**2) deriv_est = (Jh - J0) / eps err_new = np.linalg.norm(deriv_est - dJ_dh) assert err_new < 0.55 * err err = err_new
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 stdBonAxis(self): bs = BiotSavart(self.coils, self.currents) bs.set_points(self.axis.gamma()) Bfield = bs.B() devBstrength = [ sqrt(dot(Bfieldi, Bfieldi)) - self.stel.B0 for Bfieldi in Bfield ] return std(devBstrength)
def subtest_biotsavart_gradient_symmetric_and_divergence_free(self, idx): coil = get_coil() bs = BiotSavart([coil], [1e4]) points = np.asarray( 17 * [[-1.41513202e-03, 8.99999382e-01, -3.14473221e-04]]) points += 0.001 * (np.random.rand(*points.shape) - 0.5) bs.set_points(points) dB = bs.dB_by_dX() assert abs(dB[idx][0, 0] + dB[idx][1, 1] + dB[idx][2, 2]) < 1e-14 assert np.allclose(dB[idx], dB[idx].T)
def subtest_biotsavart_dAdX_taylortest(self, idx): coil = get_coil() bs = BiotSavart([coil], [1e4]) points = np.asarray( 17 * [[-1.41513202e-03, 8.99999382e-01, -3.14473221e-04]]) points += 0.001 * (np.random.rand(*points.shape) - 0.5) bs.set_points(points) A0 = bs.A()[idx] dA = bs.dA_by_dX()[idx] for direction in [ np.asarray((1., 0, 0)), np.asarray((0, 1., 0)), np.asarray((0, 0, 1.)) ]: deriv = dA.T.dot(direction) err = 1e6 for i in range(5, 10): eps = 0.5**i bs.set_points(points + eps * direction) Aeps = bs.A()[idx] deriv_est = (Aeps - A0) / (eps) new_err = np.linalg.norm(deriv - deriv_est) assert new_err < 0.55 * err err = new_err
def subtest_d2B_by_dXdX_is_symmetric(self, idx): coil = get_coil() bs = BiotSavart([coil], [1e4]) points = np.asarray( 17 * [[-1.41513202e-03, 8.99999382e-01, -3.14473221e-04]]) points += 0.001 * (np.random.rand(*points.shape) - 0.5) bs.set_points(points) d2B_by_dXdX = bs.d2B_by_dXdX() for i in range(3): assert np.allclose(d2B_by_dXdX[idx, :, :, i], d2B_by_dXdX[idx, :, :, i].T)
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 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 pyoculusPoincare(stel, qvfilename, Rbegin=1.55, Rend=1.62, nPpts=50, nPtrj=5): from axisOptFuncs import importCoils, getFourierCurve from pyoculus.solvers import PoincarePlot import matplotlib.pyplot as plt _, current = importCoils("coils." + qvfilename) outputFile = qvfilename + "_coil_coeffs.dat" coils, currents = getFourierCurve(outputFile, current) bs = BiotSavart(coils, currents) sbsp = SimsgeoBiotSavart(bs, R0=sum(stel.rc), Z0=0, Nfp=stel.nfp) params = dict() Rbegin = 1.01 * sum(stel.rc) params["Rbegin"] = Rbegin params["Rend"] = Rend params["nPpts"] = nPpts params["nPtrj"] = nPtrj p = PoincarePlot(sbsp, params) poincare_output = p.compute() p.plot(s=1) plt.savefig("poincarePyoculus_" + qvfilename + '.pdf', bbox_inches='tight', pad_inches=0) iota = p.compute_iota() p.plot_iota() plt.savefig("iotaPyoculus_" + qvfilename + '.pdf', bbox_inches='tight', pad_inches=0) plt.show()
def test_interpolated_field_convergence_rate(self): R0test = 1.5 B0test = 0.8 B0 = ToroidalField(R0test, B0test) coils, currents, _ = get_ncsx_data(Nt_coils=5, Nt_ma=10, ppp=5) stellarator = CoilCollection(coils, currents, 3, True) bs = BiotSavart(stellarator.coils, stellarator.currents) old_err_1 = 1e6 old_err_2 = 1e6 btotal = bs + B0 for n in [4, 8, 16]: rmin = 1.3 rmax = 1.7 rsteps = n phimin = 0 phimax = 2 * np.pi phisteps = n * 32 zmin = -0.1 zmax = 0.1 zsteps = n bsh = InterpolatedField(btotal, 2, [rmin, rmax, rsteps], [phimin, phimax, phisteps], [zmin, zmax, zsteps], True) err_1 = np.mean(bsh.estimate_error_B(1000)) err_2 = np.mean(bsh.estimate_error_GradAbsB(1000)) print(err_1, err_2) assert err_1 < 0.6**3 * old_err_1 assert err_2 < 0.6**3 * old_err_2 old_err_1 = err_1 old_err_2 = err_2
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 test_biotsavart_both_interfaces_give_same_result(self): coils = [get_coil()] currents = [1e4] points = np.asarray( 10 * [[-1.41513202e-03, 8.99999382e-01, -3.14473221e-04]]) B1 = BiotSavart(coils, currents).set_points(points).B() from simsoptpp import biot_savart_B B2 = biot_savart_B(points, [c.gamma() for c in coils], [c.gammadash() for c in coils], currents) assert np.linalg.norm(B1) > 1e-5 assert np.allclose(B1, B2)
def test_get_set_points_cyl_cart(self): coils, currents, _ = get_ncsx_data(Nt_coils=5, Nt_ma=10, ppp=5) stellarator = CoilCollection(coils, currents, 3, True) bs = BiotSavart(stellarator.coils, stellarator.currents) points_xyz = np.asarray([[0.5, 0.6, 0.7]]) points_rphiz = np.zeros_like(points_xyz) points_rphiz[:, 0] = np.linalg.norm(points_xyz[:, 0:2], axis=1) points_rphiz[:, 1] = np.mod( np.arctan2(points_xyz[:, 1], points_xyz[:, 0]), 2 * np.pi) points_rphiz[:, 2] = points_xyz[:, 2] bs.set_points_cyl(points_rphiz) # import IPython; IPython.embed() # import sys; sys.exit() assert np.allclose(bs.get_points_cyl(), points_rphiz) assert np.allclose(bs.get_points_cart(), points_xyz) bs.set_points_cart(points_xyz) assert np.allclose(bs.get_points_cyl(), points_rphiz) assert np.allclose(bs.get_points_cart(), points_xyz)
def CoilsBonAxis(axis, qvfilename, NFP): from axisOptFuncs import importCoils, getFourierCurve, plot_stellarator from simsopt.geo.biotsavart import BiotSavart from numpy import sqrt, dot import matplotlib.pyplot as plt _, current = importCoils("coils." + qvfilename) outputFile = qvfilename + "_coil_coeffs.dat" coils, currents = getFourierCurve(outputFile, current) print("Look at resulting coils") plot_stellarator("coils_FOURIER_", qvfilename, coils, NFP, axis, "quasisymmetry_out." + qvfilename + ".nc") print("Plot on-axis B from these coils") bs = BiotSavart(coils, currents) bs.set_points(axis.gamma()) Bfield = bs.B() Bstrength = [sqrt(dot(Bfieldi, Bfieldi)) for Bfieldi in Bfield] plt.figure() plt.plot(Bstrength) plt.xlabel('phi') plt.ylabel('B') plt.savefig("Bonaxis" + qvfilename + '.pdf', bbox_inches='tight', pad_inches=0)
def residue(self, guess=1.6, pp=3, qq=8, sbegin=1.58, send=1.62): bs = BiotSavart(self.coils, self.currents) sbsp = SimsgeoBiotSavart(bs, R0=sum(self.stel.rc), Z0=0, Nfp=self.nfp) fp = FixedPoint(sbsp, {"Z": 0.0}) output = fp.compute(guess=guess, pp=pp, qq=qq, sbegin=sbegin, send=send) try: residue = output.GreenesResidue except: residue = 0 return residue
def test_biotsavart_exponential_convergence(self): coil = get_coil() from time import time # points = np.asarray(17 * [[-1.41513202e-03, 8.99999382e-01, -3.14473221e-04 ]]) points = np.asarray( 10 * [[-1.41513202e-03, 8.99999382e-01, -3.14473221e-04]]) tic = time() btrue = BiotSavart([get_coil(1000)], [1e4]).set_points(points).B() # print(btrue) bcoarse = BiotSavart([get_coil(10)], [1e4]).set_points(points).B() bfine = BiotSavart([get_coil(20)], [1e4]).set_points(points).B() assert np.linalg.norm(btrue - bfine) < 1e-4 * np.linalg.norm(bcoarse - bfine) # print(time()-tic) tic = time() dbtrue = BiotSavart([get_coil(1000)], [1e4]).set_points(points).dB_by_dX() # print(dbtrue) dbcoarse = BiotSavart([get_coil(10)], [1e4]).set_points(points).dB_by_dX() dbfine = BiotSavart([get_coil(20)], [1e4]).set_points(points).dB_by_dX() assert np.linalg.norm(btrue - bfine) < 1e-4 * np.linalg.norm(bcoarse - bfine) # print(time()-tic) tic = time() dbtrue = BiotSavart([get_coil(1000)], [1e4]).set_points(points).d2B_by_dXdX() # print("dbtrue", dbtrue) dbcoarse = BiotSavart([get_coil(10)], [1e4]).set_points(points).d2B_by_dXdX() dbfine = BiotSavart([get_coil(20)], [1e4]).set_points(points).d2B_by_dXdX() assert np.linalg.norm(btrue - bfine) < 1e-4 * np.linalg.norm(bcoarse - bfine)
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 test_helicalcoil_Bfield(self): point = [[-1.41513202e-03, 8.99999382e-01, -3.14473221e-04]] field = [[-0.00101961, 0.20767292, -0.00224908]] derivative = [[[0.47545098, 0.01847397, 1.10223595], [0.01847426, -2.66700072, 0.01849548], [1.10237535, 0.01847085, 2.19154973]]] coils = [CurveHelical(100, 2, 5, 2, 1., 0.3) for i in range(2)] coils[0].set_dofs(np.concatenate(([0, 0], [0, 0]))) coils[1].set_dofs(np.concatenate(([np.pi / 2, 0], [0, 0]))) currents = [-3.07e5, 3.07e5] Bhelical = BiotSavart(coils, currents) Bhelical.set_points(point) assert np.allclose(Bhelical.B(), field) assert np.allclose(Bhelical.dB_by_dX(), derivative)
def test_biotsavart_B_is_curlA(self): coil = get_coil() bs = BiotSavart([coil], [1e4]) points = np.asarray( 17 * [[-1.41513202e-03, 8.99999382e-01, -3.14473221e-04]]) bs.set_points(points) B, dA_by_dX = bs.B(), bs.dA_by_dX() curlA1 = dA_by_dX[:, 1, 2] - dA_by_dX[:, 2, 1] curlA2 = dA_by_dX[:, 2, 0] - dA_by_dX[:, 0, 2] curlA3 = dA_by_dX[:, 0, 1] - dA_by_dX[:, 1, 0] curlA = np.concatenate( (curlA1[:, None], curlA2[:, None], curlA3[:, None]), axis=1) err = np.max(np.abs(curlA - B)) assert err < 1e-14
def getResidue(stel, axis, qvfilename, guess=1.6, pp=3, qq=8, sbegin=1.58, send=1.62): from axisOptFuncs import importCoils, getFourierCurve from pyoculus.solvers import FixedPoint _, current = importCoils("coils." + qvfilename) outputFile = qvfilename + "_coil_coeffs.dat" coils, currents = getFourierCurve(outputFile, current) bs = BiotSavart(coils, currents) sbsp = SimsgeoBiotSavart(bs, R0=sum(stel.rc), Z0=0, Nfp=stel.nfp) fp = FixedPoint(sbsp, {"Z": 0.0}) #sbegin=1.01*sum(stel.rc) output = fp.compute(guess=guess, pp=pp, qq=qq, sbegin=sbegin, send=send) residue = output.GreenesResidue print(residue)
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 test_interpolated_field_close(self): R0test = 1.5 B0test = 0.8 B0 = ToroidalField(R0test, B0test) coils, currents, _ = get_ncsx_data(Nt_coils=5, Nt_ma=10, ppp=5) stellarator = CoilCollection(coils, currents, 3, True) bs = BiotSavart(stellarator.coils, stellarator.currents) btotal = bs + B0 n = 10 rmin = 1.5 rmax = 1.7 rsteps = n phimin = 0 phimax = 2 * np.pi phisteps = n * 32 zmin = -0.1 zmax = 0.1 zsteps = n bsh = InterpolatedField(btotal, 4, [rmin, rmax, rsteps], [phimin, phimax, phisteps], [zmin, zmax, zsteps], True) N = 10 points = np.random.uniform(size=(N, 3)) points[:, 0] = points[:, 0] * (rmax - rmin) + rmin points[:, 1] = points[:, 1] * (phimax - phimin) + phimin points[:, 2] = points[:, 2] * (zmax - zmin) + zmin bsh.set_points_cyl(points) btotal.set_points_cyl(points) B = btotal.B() Bh = bsh.B() dB = btotal.GradAbsB() dBh = bsh.GradAbsB() print("btotal.B()", B) print("bsh.B()", Bh) print("btotal.GradAbsB(()", dB) print("bsh.GradAbsB()", dBh) assert np.allclose(B, Bh, rtol=1e-3) assert np.allclose(dB, dBh, rtol=1e-3)
def test_sum_Bfields(self): pointVar = 1e-1 npoints = 20 points = np.asarray( npoints * [[-1.41513202e-03, 8.99999382e-01, -3.14473221e-04]]) points += pointVar * (np.random.rand(*points.shape) - 0.5) # Set up helical field coils = [CurveHelical(101, 2, 5, 2, 1., 0.3) for i in range(2)] coils[0].set_dofs(np.concatenate(([np.pi / 2, 0], [0, 0]))) coils[1].set_dofs(np.concatenate(([0, 0], [0, 0]))) currents = [-2.1e5, 2.1e5] Bhelical = BiotSavart(coils, currents) # Set up toroidal fields Btoroidal1 = ToroidalField(1., 1.) Btoroidal2 = ToroidalField(1.2, 0.1) # Set up sum of the three in two different ways Btotal1 = MagneticFieldSum([Bhelical, Btoroidal1, Btoroidal2]) Btotal2 = Bhelical + Btoroidal1 + Btoroidal2 Btotal3 = Btoroidal1 + Btoroidal2 # Evaluate at a given point Bhelical.set_points(points) Btoroidal1.set_points(points) Btoroidal2.set_points(points) Btotal1.set_points(points) Btotal2.set_points(points) Btotal3.set_points(points) # Verify assert np.allclose(Btotal1.B(), Btotal2.B()) assert np.allclose(Bhelical.B() + Btoroidal1.B() + Btoroidal2.B(), Btotal1.B()) assert np.allclose(Btotal1.dB_by_dX(), Btotal2.dB_by_dX()) assert np.allclose( Bhelical.dB_by_dX() + Btoroidal1.dB_by_dX() + Btoroidal2.dB_by_dX(), Btotal1.dB_by_dX()) assert np.allclose(Btoroidal1.d2B_by_dXdX() + Btoroidal2.d2B_by_dXdX(), Btotal3.d2B_by_dXdX()) assert np.allclose(Btoroidal1.A() + Btoroidal2.A(), Btotal3.A()) assert np.allclose(Btoroidal1.dA_by_dX() + Btoroidal2.dA_by_dX(), Btotal3.dA_by_dX()) assert np.allclose(Btoroidal1.d2A_by_dXdX() + Btoroidal2.d2A_by_dXdX(), Btotal3.d2A_by_dXdX())
def BonAxis(self): bs = BiotSavart(self.coils, self.currents) bs.set_points(self.axis.gamma()) Bfield = bs.B() Bstrength = [sqrt(dot(Bfieldi, Bfieldi)) for Bfieldi in Bfield] return Bstrength
def test_circularcoil_Bfield(self): current = 1.2e7 radius = 1.12345 center = [0.12345, 0.6789, 1.23456] pointVar = 1e-1 npoints = 1 ## verify the field at the center of a coil in the xy plane Bfield = CircularCoil(I=current, r0=radius) points = np.array([[1e-10, 0, 0.]]) Bfield.set_points(points) assert np.allclose(Bfield.B(), [[0, 0, current / 1e7 * 2 * np.pi / radius]]) # Verify that divergence is zero dB1_by_dX = Bfield.dB_by_dX() assert np.allclose( dB1_by_dX[:, 0, 0] + dB1_by_dX[:, 1, 1] + dB1_by_dX[:, 2, 2], np.zeros((npoints))) # Verify that, as a vacuum field, grad B=grad grad phi so that grad_i B_j = grad_j B_i transpGradB1 = [dBdx.T for dBdx in dB1_by_dX] assert np.allclose(dB1_by_dX, transpGradB1) ### compare to biosavart(circular_coil) ## at these points points = np.asarray( npoints * [[-1.41513202e-03, 8.99999382e-01, -3.14473221e-04]]) points += pointVar * (np.random.rand(*points.shape) - 0.5) ## verify with a x^2+z^2=radius^2 circular coil normal = [np.pi / 2, 0] coils = [CurveXYZFourier(300, 1)] coils[0].set_dofs( [center[0], radius, 0., center[1], 0., 0., center[2], 0., radius]) Bcircular = BiotSavart(coils, [current]) Bfield = CircularCoil(I=current, r0=radius, normal=normal, center=center) Bfield.set_points(points) Bcircular.set_points(points) dB1_by_dX = Bfield.dB_by_dX() transpGradB1 = [dBdx.T for dBdx in dB1_by_dX] assert np.allclose(Bfield.B(), Bcircular.B()) assert np.allclose(Bfield.dB_by_dX(), Bcircular.dB_by_dX()) assert np.allclose( dB1_by_dX[:, 0, 0] + dB1_by_dX[:, 1, 1] + dB1_by_dX[:, 2, 2], np.zeros((npoints))) assert np.allclose(dB1_by_dX, transpGradB1) # use normal = [0, 1, 0] normal = [0, 1, 0] coils = [CurveXYZFourier(300, 1)] coils[0].set_dofs( [center[0], radius, 0., center[1], 0., 0., center[2], 0., radius]) Bcircular = BiotSavart(coils, [current]) Bfield = CircularCoil(I=current, r0=radius, normal=normal, center=center) Bfield.set_points(points) Bcircular.set_points(points) dB1_by_dX = Bfield.dB_by_dX() transpGradB1 = [dBdx.T for dBdx in dB1_by_dX] assert np.allclose(Bfield.B(), Bcircular.B()) assert np.allclose(Bfield.dB_by_dX(), Bcircular.dB_by_dX()) assert np.allclose( dB1_by_dX[:, 0, 0] + dB1_by_dX[:, 1, 1] + dB1_by_dX[:, 2, 2], np.zeros((npoints))) assert np.allclose(dB1_by_dX, transpGradB1) ## verify with a y^2+z^2=radius^2 circular coil normal = [np.pi / 2, np.pi / 2] coils = [CurveXYZFourier(300, 1)] coils[0].set_dofs( [center[0], 0, 0., center[1], radius, 0., center[2], 0., radius]) Bcircular = BiotSavart(coils, [current]) Bfield = CircularCoil(I=current, r0=radius, normal=normal, center=center) Bfield.set_points(points) Bcircular.set_points(points) dB1_by_dX = Bfield.dB_by_dX() transpGradB1 = [dBdx.T for dBdx in dB1_by_dX] assert np.allclose(Bfield.B(), Bcircular.B()) assert np.allclose(Bfield.dB_by_dX(), Bcircular.dB_by_dX()) assert np.allclose(dB1_by_dX[:, 0, 0] + dB1_by_dX[:, 1, 1] + dB1_by_dX[:, 2, 2], np.zeros((npoints))) # divergence assert np.allclose(dB1_by_dX, transpGradB1) # symmetry of the gradient Bfield.set_points([[0.1, 0.2, 0.3]]) Afield = Bfield.A() assert np.allclose(Afield, [[0, 5.15786, -2.643056]]) # use normal=[1,0,0] normal = [1, 0, 0] coils = [CurveXYZFourier(300, 1)] coils[0].set_dofs( [center[0], 0, 0., center[1], radius, 0., center[2], 0., radius]) Bcircular = BiotSavart(coils, [current]) Bfield = CircularCoil(I=current, r0=radius, normal=normal, center=center) Bfield.set_points(points) Bcircular.set_points(points) dB1_by_dX = Bfield.dB_by_dX() transpGradB1 = [dBdx.T for dBdx in dB1_by_dX] assert np.allclose(Bfield.B(), Bcircular.B()) assert np.allclose(Bfield.dB_by_dX(), Bcircular.dB_by_dX()) assert np.allclose(dB1_by_dX[:, 0, 0] + dB1_by_dX[:, 1, 1] + dB1_by_dX[:, 2, 2], np.zeros((npoints))) # divergence assert np.allclose(dB1_by_dX, transpGradB1) # symmetry of the gradient ## verify with a x^2+y^2=radius^2 circular coil center = [0, 0, 0] normal = [0, 0] coils = [CurveXYZFourier(300, 1)] coils[0].set_dofs( [center[0], 0, radius, center[1], radius, 0., center[2], 0., 0.]) Bcircular = BiotSavart(coils, [current]) coils2 = [CurveRZFourier(300, 1, 1, True)] coils2[0].set_dofs([radius, 0, 0]) Bcircular2 = BiotSavart(coils, [current]) Bfield = CircularCoil(I=current, r0=radius, normal=normal, center=center) Bfield.set_points(points) Bcircular.set_points(points) Bcircular2.set_points(points) dB1_by_dX = Bfield.dB_by_dX() transpGradB1 = [dBdx.T for dBdx in dB1_by_dX] assert np.allclose(Bfield.B(), Bcircular.B()) assert np.allclose(Bfield.B(), Bcircular2.B()) assert np.allclose(Bfield.dB_by_dX(), Bcircular.dB_by_dX()) assert np.allclose(Bfield.dB_by_dX(), Bcircular2.dB_by_dX()) assert np.allclose(dB1_by_dX[:, 0, 0] + dB1_by_dX[:, 1, 1] + dB1_by_dX[:, 2, 2], np.zeros((npoints))) # divergence assert np.allclose(dB1_by_dX, transpGradB1) # symmetry of the gradient # use normal = [0, 0, 1] center = [0, 0, 0] normal = [0, 0, 1] coils = [CurveXYZFourier(300, 1)] coils[0].set_dofs( [center[0], 0, radius, center[1], radius, 0., center[2], 0., 0.]) Bcircular = BiotSavart(coils, [current]) coils2 = [CurveRZFourier(300, 1, 1, True)] coils2[0].set_dofs([radius, 0, 0]) Bcircular2 = BiotSavart(coils, [current]) Bfield = CircularCoil(I=current, r0=radius, normal=normal, center=center) Bfield.set_points(points) Bcircular.set_points(points) Bcircular2.set_points(points) dB1_by_dX = Bfield.dB_by_dX() transpGradB1 = [dBdx.T for dBdx in dB1_by_dX] assert np.allclose(Bfield.B(), Bcircular.B()) assert np.allclose(Bfield.B(), Bcircular2.B()) assert np.allclose(Bfield.dB_by_dX(), Bcircular.dB_by_dX()) assert np.allclose(Bfield.dB_by_dX(), Bcircular2.dB_by_dX()) assert np.allclose(dB1_by_dX[:, 0, 0] + dB1_by_dX[:, 1, 1] + dB1_by_dX[:, 2, 2], np.zeros((npoints))) # divergence assert np.allclose(dB1_by_dX, transpGradB1) # symmetry of the gradient
def subtest_boozer_surface_optimisation_convergence( self, surfacetype, stellsym, optimize_G, second_stage): coils, currents, ma = get_ncsx_data() if stellsym: stellarator = CoilCollection(coils, currents, 3, True) else: # Create a stellarator that still has rotational symmetry but # doesn't have stellarator symmetry. We do this by first applying # stellarator symmetry, then breaking this slightly, and then # applying rotational symmetry from simsopt.geo.curve import RotatedCurve coils_flipped = [RotatedCurve(c, 0, True) for c in coils] currents_flipped = [-cur for cur in currents] for c in coils_flipped: c.rotmat += 0.001 * np.random.uniform( low=-1., high=1., size=c.rotmat.shape) c.rotmatT = c.rotmat.T stellarator = CoilCollection(coils + coils_flipped, currents + currents_flipped, 3, False) bs = BiotSavart(stellarator.coils, stellarator.currents) s = get_surface(surfacetype, stellsym) s.fit_to_curve(ma, 0.1) iota = -0.3 ar = Area(s) ar_target = ar.J() boozer_surface = BoozerSurface(bs, s, ar, ar_target) if optimize_G: G = 2. * np.pi * np.sum(np.abs( bs.coil_currents)) * (4 * np.pi * 10**(-7) / (2 * np.pi)) else: G = None # compute surface first using LBFGS exact and an area constraint res = boozer_surface.minimize_boozer_penalty_constraints_LBFGS( tol=1e-9, maxiter=500, constraint_weight=100., iota=iota, G=G) print('Squared residual after LBFGS', res['fun']) if second_stage == 'ls': res = boozer_surface.minimize_boozer_penalty_constraints_ls( tol=1e-9, maxiter=100, constraint_weight=100., iota=res['iota'], G=res['G']) elif second_stage == 'newton': res = boozer_surface.minimize_boozer_penalty_constraints_newton( tol=1e-9, maxiter=10, constraint_weight=100., iota=res['iota'], G=res['G'], stab=1e-4) elif second_stage == 'newton_exact': res = boozer_surface.minimize_boozer_exact_constraints_newton( tol=1e-9, maxiter=10, iota=res['iota'], G=res['G']) print('Residual after second stage', np.linalg.norm(res['residual'])) assert res['success'] # For the stellsym case we have z(0, 0) = y(0, 0) = 0. For the not # stellsym case, we enforce z(0, 0) = 0, but expect y(0, 0) \neq 0 gammazero = s.gamma()[0, 0, :] assert np.abs(gammazero[2]) < 1e-10 if stellsym: assert np.abs(gammazero[1]) < 1e-10 else: assert np.abs(gammazero[1]) > 1e-6 if surfacetype == 'SurfaceXYZTensorFourier': assert np.linalg.norm(res['residual']) < 1e-9 if second_stage == 'newton_exact' or surfacetype == 'SurfaceXYZTensorFourier': assert np.abs(ar_target - ar.J()) < 1e-9
def test_to_vtk(self): coils, currents, _ = get_ncsx_data(Nt_coils=5, Nt_ma=10, ppp=5) stellarator = CoilCollection(coils, currents, 3, True) bs = BiotSavart(stellarator.coils, stellarator.currents) bs.to_vtk('/tmp/bfield')
def subtest_biotsavart_d2A_by_dXdX_taylortest(self, idx): coil = get_coil() bs = BiotSavart([coil], [1e4]) points = np.asarray( 17 * [[-1.41513202e-03, 8.99999382e-01, -3.14473221e-04]]) bs.set_points(points) dA_by_dX, d2A_by_dXdX = bs.dA_by_dX(), bs.d2A_by_dXdX() for d1 in range(3): for d2 in range(3): second_deriv = d2A_by_dXdX[idx, d1, d2] err = 1e6 for i in range(5, 10): eps = 0.5**i ed2 = np.zeros((1, 3)) ed2[0, d2] = 1. bs.set_points(points + eps * ed2) dA_dXp = bs.dA_by_dX()[idx, d1] bs.set_points(points - eps * ed2) dA_dXm = bs.dA_by_dX()[idx, d1] second_deriv_est = (dA_dXp - dA_dXm) / (2. * eps) new_err = np.linalg.norm(second_deriv - second_deriv_est) print("new_err", new_err) assert new_err < 0.30 * err err = new_err
""" This example demonstrate how to compute surfaces in Boozer coordinates for a magnetic field induced by coils. We start with an initial guess that is just a tube around the magnetic axis, then we reduce the Boozer residual with BFGS first, then drive it to machine zero with a Levenberg-Marquardt algorithm. All of this is done while keeping the surface area constant. We then switch the label to the Toroidal Flux, and aim for a Boozer surface with three times larger flux. """ coils, currents, ma = get_ncsx_data() stellarator = CoilCollection(coils, currents, 3, True) coils = stellarator.coils currents = stellarator.currents bs = BiotSavart(coils, currents) 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
def test_biotsavart_coil_current_taylortest(self): coil0 = get_coil() current0 = 1e4 coil1 = get_coil(perturb=True) current1 = 1e3 bs = BiotSavart([coil0, coil1], [current0, current1]) points = np.asarray( 17 * [[-1.41513202e-03, 8.99999382e-01, -3.14473221e-04]]) bs.set_points(points) B = bs.B() J = bs.dB_by_dX() H = bs.d2B_by_dXdX() dB = bs.dB_by_dcoilcurrents() dJ = bs.d2B_by_dXdcoilcurrents() dH = bs.d3B_by_dXdXdcoilcurrents() h = 1. bs.currents_optim[0].set_dofs(1e4 + h) bs.invalidate_cache() Bp = bs.B() Jp = bs.dB_by_dX() Hp = bs.d2B_by_dXdX() bs.currents_optim[0].set_dofs(1e4 - h) bs.invalidate_cache() Bm = bs.B() Jm = bs.dB_by_dX() Hm = bs.d2B_by_dXdX() dB_approx = (Bp - Bm) / (2 * h) dJ_approx = (Jp - Jm) / (2 * h) dH_approx = (Hp - Hm) / (2 * h) assert np.linalg.norm(dB[0] - dB_approx) < 1e-15 assert np.linalg.norm(dJ[0] - dJ_approx) < 1e-15 assert np.linalg.norm(dH[0] - dH_approx) < 1e-13