예제 #1
0
    def test_integrated_stellopt_scenarios_1dof_Garabedian(self):
        """
        This script implements the "1DOF_circularCrossSection_varyAxis_targetIota"
        example from
        https://github.com/landreman/stellopt_scenarios

        This example demonstrates optimizing a surface shape using the
        Garabedian representation instead of VMEC's RBC/ZBS representation.
        This optimization problem has one independent variable, the Garabedian
        Delta_{m=1, n=-1} coefficient, representing the helical excursion of
        the magnetic axis. The objective function is (iota - iota_target)^2,
        where iota is measured on the magnetic axis.

        Details of the optimum and a plot of the objective function landscape
        can be found here:
        https://github.com/landreman/stellopt_scenarios/tree/master/1DOF_circularCrossSection_varyAxis_targetIota
        """
        filename = os.path.join(TEST_DIR, '1DOF_Garabedian.sp')

        for mpol_ntor in [2, 4]:
            # Start with a default surface.
            equil = Spec(filename)
            equil.inputlist.mpol = mpol_ntor
            equil.inputlist.ntor = mpol_ntor

            # We will optimize in the space of Garabedian coefficients
            # rather than RBC/ZBS coefficients. To do this, we convert the
            # boundary to the Garabedian representation:
            surf = equil.boundary.to_Garabedian()
            equil.boundary = surf

            # SPEC parameters are all fixed by default, while surface
            # parameters are all non-fixed by default. You can choose
            # which parameters are optimized by setting their 'fixed'
            # attributes.
            surf.all_fixed()
            surf.set_fixed('Delta(1,-1)', False)

            # Use low resolution, for speed:
            equil.inputlist.lrad[0] = 4
            equil.inputlist.nppts = 100

            # Each Target is then equipped with a shift and weight, to become a
            # term in a least-squares objective function
            desired_iota = 0.41  # Sign was + for VMEC
            prob = LeastSquaresProblem([(equil.iota, desired_iota, 1)])

            # Check that the problem was set up correctly:
            self.assertEqual(len(prob.dofs.names), 1)
            self.assertEqual(prob.dofs.names[0][:11], 'Delta(1,-1)')
            np.testing.assert_allclose(prob.x, [0.1])
            self.assertEqual(prob.dofs.all_owners, [equil, surf])
            self.assertEqual(prob.dofs.dof_owners, [surf])

            # Solve the minimization problem:
            least_squares_serial_solve(prob)

            self.assertAlmostEqual(surf.get_Delta(1, -1), 0.08575, places=4)
            self.assertAlmostEqual(equil.iota(), desired_iota, places=5)
            self.assertLess(np.abs(prob.objective()), 1.0e-15)
예제 #2
0
    def test_init_from_file(self):
        """
        Try creating a Spec instance from a specified input file.
        """

        filename = os.path.join(TEST_DIR, '1DOF_Garabedian.sp')

        s = Spec(filename)
        self.assertEqual(s.inputlist.nfp, 5)
        self.assertEqual(s.inputlist.nvol, 1)
        self.assertTrue(s.need_to_run_code)

        places = 5

        # n = 0, m = 0:
        self.assertAlmostEqual(s.boundary.get_rc(0, 0), 1.0, places=places)
        self.assertAlmostEqual(s.boundary.get_zs(0, 0), 0.0, places=places)

        # n = 0, m = 1:
        self.assertAlmostEqual(s.boundary.get_rc(1, 0), 0.01, places=places)
        self.assertAlmostEqual(s.boundary.get_zs(1, 0), 0.01, places=places)

        # n = 1, m = 0:
        self.assertAlmostEqual(s.boundary.get_rc(0, 1), 0.1, places=places)
        self.assertAlmostEqual(s.boundary.get_zs(0, 1), 0.1, places=places)
예제 #3
0
 def test_init_defaults(self):
     """
     Just create a Spec instance using the standard constructor,
     and make sure we can read some of the attributes.
     """
     spec = Spec()
     self.assertEqual(spec.inputlist.nfp, 5)
     self.assertEqual(spec.inputlist.nvol, 1)
     self.assertTrue(spec.need_to_run_code)
예제 #4
0
def runSPEC(qvfilename,
            findResidue=0,
            p=2,
            q=5,
            s_guess=0.5,
            RunSPEC=1,
            nmodes=25):
    from axisOptFuncs import output2spec
    from simsopt.mhd.spec import Spec
    from simsopt.mhd.spec import Residue
    print("Output to SPEC")
    qscfile = "quasisymmetry_out." + qvfilename + ".nc"
    output2spec(qvfilename, qscfile, nmodes, findResidue)
    if RunSPEC == 1:
        print("Run SPEC")
        spec = Spec(qvfilename + ".sp")
        spec.run()
    if findResidue == 1:
        residue1 = Residue(spec, p, q, s_guess=s_guess)
        r1 = residue1.J()
        print("Residue = ", r1)
    print("Plot SPEC result")
    import specPlot
    specPlot.main('spec00000.sp.h5', qvfilename)
예제 #5
0
    def test_residue(self):
        """
        Check that we can compute residues from a Spec equilibrium.
        """

        filename = os.path.join(TEST_DIR, 'QH-residues.sp')

        # Initialize SPEC from an input file
        spec = Spec(filename)
        # The main resonant surface is iota = p / q:
        p = -8
        q = 7
        # Guess for radial location of the island chain:
        s_guess = 0.9

        residue1 = Residue(spec, p, q, s_guess=s_guess)
        residue2 = Residue(spec, p, q, s_guess=s_guess, theta=np.pi)

        res1 = residue1.J()
        res2 = residue2.J()
        print(f'Residues: {res1}, {res2}')
        self.assertAlmostEqual(res1, 0.02331532869145614, places=4)
        self.assertAlmostEqual(res2, -0.022876376815881616, places=4)
예제 #6
0
    def test_run(self):
        """
        Try running SPEC and reading in the output.
        """
        filename = os.path.join(TEST_DIR, '1DOF_Garabedian.sp')

        for new_mpol in [2, 3]:
            for new_ntor in [2, 3]:
                s = Spec(filename)
                print('new_mpol: {}, new_ntor: {}'.format(new_mpol, new_ntor))
                s.inputlist.mpol = new_mpol
                s.inputlist.ntor = new_ntor
                s.run()

                self.assertAlmostEqual(s.volume(), 0.001973920880217874, places=4)

                self.assertAlmostEqual(s.results.output.helicity, 0.435225, places=3)

                self.assertAlmostEqual(s.iota(), 0.544176, places=3)
surface can be adjusted to eliminate magnetic islands inside it,
considering a vacuum field. For this example we will use the SPEC code
with a single radial domain. The geometry comes from a quasi-helically
symmetric configuration developed at the University of Wisconsin. We
will eliminate the islands by minimizing an objective function
involving Greene's residue for several O-points and X-points, similar
to the approach of Hanson and Cary (1984).
"""

log()

mpi = MpiPartition()
mpi.write()

# Initialze a Spec object from a standard SPEC input file:
s = Spec(os.path.join(os.path.dirname(__file__), 'inputs', 'QH-residues.sp'),
         mpi=mpi)

# Expand number of Fourier modes to include larger poloidal mode numbers:
s.boundary.change_resolution(6, s.boundary.ntor)
# To make this example run relatively quickly, we will optimize in a
# small parameter space. Here we pick out just 2 Fourier modes to vary
# in the optimization:
s.boundary.all_fixed()
s.boundary.set_fixed('zs(6,1)', False)
s.boundary.set_fixed('zs(6,2)', False)

# The main resonant surface is iota = p / q:
p = -8
q = 7
# Guess for radial location of the island chain:
s_guess = 0.9
예제 #8
0
    def test_integrated_stellopt_scenarios_1dof(self):
        """
        This script implements the "1DOF_circularCrossSection_varyR0_targetVolume"
        example from
        https://github.com/landreman/stellopt_scenarios

        This optimization problem has one independent variable, representing
        the mean major radius. The problem also has one objective: the plasma
        volume. There is not actually any need to run an equilibrium code like
        SPEC since the objective function can be computed directly from the
        boundary shape. But this problem is a fast way to test the
        optimization infrastructure with SPEC.

        Details of the optimum and a plot of the objective function landscape
        can be found here:
        https://github.com/landreman/stellopt_scenarios/tree/master/1DOF_circularCrossSection_varyR0_targetVolume
        """
        for grad in [True, False]:
            # Start with a default surface.
            equil = Spec()
            surf = equil.boundary

            # Set the initial boundary shape. Here is one way to do it:
            surf.set('rc(0,0)', 1.0)
            # Here is another syntax that works:
            surf.set_rc(0, 1, 0.1)
            surf.set_zs(0, 1, 0.1)

            surf.set_rc(1, 0, 0.1)
            surf.set_zs(1, 0, 0.1)

            surf.set_rc(1, 1, 0)
            surf.set_zs(1, 1, 0)

            # SPEC parameters are all fixed by default, while surface
            # parameters are all non-fixed by default. You can choose
            # which parameters are optimized by setting their 'fixed'
            # attributes.
            surf.all_fixed()
            surf.set_fixed('rc(0,0)', False)

            # Turn off Poincare plots and use low resolution, for speed:
            equil.inputlist.nptrj[0] = 0
            equil.inputlist.lrad[0] = 2

            # Each Target is then equipped with a shift and weight, to become a
            # term in a least-squares objective function
            desired_volume = 0.15
            term1 = (equil.volume, desired_volume, 1)

            # A list of terms are combined to form a nonlinear-least-squares
            # problem.
            prob = LeastSquaresProblem([term1])

            # Check that the problem was set up correctly:
            self.assertEqual(len(prob.dofs.names), 1)
            self.assertEqual(prob.dofs.names[0][:7], 'rc(0,0)')
            np.testing.assert_allclose(prob.x, [1.0])
            self.assertEqual(prob.dofs.all_owners, [equil, surf])
            self.assertEqual(prob.dofs.dof_owners, [surf])

            # Solve the minimization problem:
            least_squares_serial_solve(prob, grad=grad)

            self.assertAlmostEqual(surf.get_rc(0, 0), 0.7599088773175, places=5)
            self.assertAlmostEqual(equil.volume(), 0.15, places=6)
            self.assertAlmostEqual(surf.volume(), 0.15, places=6)
            self.assertLess(np.abs(prob.objective()), 1.0e-15)
예제 #9
0
    def test_integrated_stellopt_scenarios_2dof(self):
        """
        This script implements the "2DOF_vmecOnly_targetIotaAndVolume" example from
        https://github.com/landreman/stellopt_scenarios

        This optimization problem has two independent variables, representing
        the helical shape of the magnetic axis. The problem also has two
        objectives: the plasma volume and the rotational transform on the
        magnetic axis.

        The resolution in this example (i.e. ns, mpol, and ntor) is somewhat
        lower than in the stellopt_scenarios version of the example, just so
        this example runs fast.

        Details of the optimum and a plot of the objective function landscape
        can be found here:
        https://github.com/landreman/stellopt_scenarios/tree/master/2DOF_vmecOnly_targetIotaAndVolume
        """
        filename = os.path.join(TEST_DIR, '2DOF_targetIotaAndVolume.sp')

        # Initialize SPEC from an input file
        equil = Spec(filename)
        surf = equil.boundary

        # VMEC parameters are all fixed by default, while surface parameters are all non-fixed by default.
        # You can choose which parameters are optimized by setting their 'fixed' attributes.
        surf.all_fixed()
        surf.set_fixed('rc(1,1)', False)
        surf.set_fixed('zs(1,1)', False)

        # Each Target is then equipped with a shift and weight, to become a
        # term in a least-squares objective function.  A list of terms are
        # combined to form a nonlinear-least-squares problem.
        desired_volume = 0.15
        volume_weight = 1
        term1 = (equil.volume, desired_volume, volume_weight)

        desired_iota = -0.41
        iota_weight = 1
        term2 = (equil.iota, desired_iota, iota_weight)

        prob = LeastSquaresProblem([term1, term2])

        # Solve the minimization problem:
        least_squares_serial_solve(prob)

        # The tests here are based on values from the VMEC version in
        # https://github.com/landreman/stellopt_scenarios/tree/master/2DOF_vmecOnly_targetIotaAndVolume
        # Due to this and the fact that we don't yet have iota on axis from SPEC, the tolerances are wide.
        """
        assert np.abs(surf.get_rc(1, 1) - 0.0313066948) < 0.001
        assert np.abs(surf.get_zs(1, 1) - (-0.031232391)) < 0.001
        assert np.abs(equil.volume() - 0.178091) < 0.001
        assert np.abs(surf.volume()  - 0.178091) < 0.001
        assert np.abs(equil.iota() - (-0.4114567)) < 0.001
        assert (prob.objective() - 7.912501330E-04) < 0.2e-4
        """
        self.assertAlmostEqual(surf.get_rc(1, 1), 0.0313066948, places=3)
        self.assertAlmostEqual(surf.get_zs(1, 1), -0.031232391, places=3)
        self.assertAlmostEqual(equil.volume(), 0.178091, places=3)
        self.assertAlmostEqual(surf.volume(), 0.178091, places=3)
        self.assertAlmostEqual(equil.iota(), -0.4114567, places=3)
        self.assertAlmostEqual(prob.objective(), 7.912501330E-04, places=3)