def test_solve_quadratic_fixed_supplying_objects(self):
     """
     Same as test_solve_quadratic_fixed, except supplying objects
     rather than functions as targets.
     """
     for solver in solvers:
         iden1 = Identity()
         iden2 = Identity()
         iden3 = Identity()
         iden1.x = 4
         iden2.x = 5
         iden3.x = 6
         iden1.names = ['x1']
         iden2.names = ['x2']
         iden3.names = ['x3']
         iden1.fixed = [True]
         iden3.fixed = [True]
         term1 = [iden1, 1, 1]
         term2 = [iden2, 2, 1 / 4.]
         term3 = [iden3, 3, 1 / 9.]
         prob = LeastSquaresProblem([term1, term2, term3])
         solver(prob)
         self.assertAlmostEqual(prob.objective(), 10)
         self.assertAlmostEqual(iden1.x, 4)
         self.assertAlmostEqual(iden2.x, 2)
         self.assertAlmostEqual(iden3.x, 6)
 def test_solve_quadratic_fixed_supplying_attributes(self):
     """
     Same as test_solve_quadratic_fixed, except supplying attributes
     rather than functions as targets.
     """
     for solver in solvers:
         iden1 = Identity()
         iden2 = Identity()
         iden3 = Identity()
         iden1.x = 4
         iden2.x = 5
         iden3.x = 6
         iden1.names = ['x1']
         iden2.names = ['x2']
         iden3.names = ['x3']
         iden1.fixed = [True]
         iden3.fixed = [True]
         # Try a mix of explicit LeastSquaresTerms and tuples
         term1 = LeastSquaresTerm(Target(iden1, 'x'), 1, 1)
         term2 = (iden2, 'x', 2, 1 / 4.)
         term3 = (iden3, 'x', 3, 1 / 9.)
         prob = LeastSquaresProblem([term1, term2, term3])
         solver(prob)
         self.assertAlmostEqual(prob.objective(), 10)
         self.assertAlmostEqual(iden1.x, 4)
         self.assertAlmostEqual(iden2.x, 2)
         self.assertAlmostEqual(iden3.x, 6)
 def test_solve_quadratic_fixed(self):
     """
     Same as test_solve_quadratic, except with different weights and x
     and z are fixed, so only y is optimized.
     """
     for solver in solvers:
         iden1 = Identity()
         iden2 = Identity()
         iden3 = Identity()
         iden1.x = 4
         iden2.x = 5
         iden3.x = 6
         iden1.names = ['x1']
         iden2.names = ['x2']
         iden3.names = ['x3']
         iden1.fixed = [True]
         iden3.fixed = [True]
         term1 = (iden1.J, 1, 1)
         term2 = (iden2.J, 2, 1 / 4.)
         term3 = (iden3.J, 3, 1 / 9.)
         prob = LeastSquaresProblem([term1, term2, term3])
         solver(prob)
         self.assertAlmostEqual(prob.objective(), 10)
         self.assertAlmostEqual(iden1.x, 4)
         self.assertAlmostEqual(iden2.x, 2)
         self.assertAlmostEqual(iden3.x, 6)
 def test_solve_quadratic_fixed_supplying_properties(self):
     """
     Same as test_solve_quadratic_fixed, except supplying @properties
     rather than functions as targets.
     """
     for solver in solvers:
         iden1 = Identity()
         iden2 = Identity()
         iden3 = Identity()
         iden1.x = 4
         iden2.x = 5
         iden3.x = 6
         iden1.names = ['x1']
         iden2.names = ['x2']
         iden3.names = ['x3']
         iden1.fixed = [True]
         iden3.fixed = [True]
         # Try a mix of explicit LeastSquaresTerms and lists
         term1 = [iden1, 'f', 1, 1]
         term2 = [iden2, 'f', 2, 1 / 4.]
         term3 = LeastSquaresTerm.from_sigma(Target(iden3, 'f'), 3, sigma=3)
         prob = LeastSquaresProblem([term1, term2, term3])
         solver(prob)
         self.assertAlmostEqual(prob.objective(), 10)
         self.assertAlmostEqual(iden1.x, 4)
         self.assertAlmostEqual(iden2.x, 2)
         self.assertAlmostEqual(iden3.x, 6)
Example #5
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)
    def subtest_curve_length_optimisation(self, rotated):
        nquadrature = 100
        nfourier = 4
        nfp = 5
        curve = CurveRZFourier(nquadrature, nfourier, nfp, True)
        if rotated:
            curve = RotatedCurve(curve, 0.5, flip=False)

        # Initialize the Fourier amplitudes to some random values
        x0 = np.random.rand(curve.num_dofs()) - 0.5
        x0[0] = 3.0
        curve.set_dofs(x0)
        print('Initial curve dofs: ', curve.get_dofs())

        # Tell the curve object that the first Fourier mode is fixed, whereas
        # all the other dofs are not.
        curve.all_fixed(False)
        curve.fixed[0] = True

        # Presently in simsgeo, the length objective is a separate object
        # rather than a function of Curve itself.
        obj = make_optimizable(CurveLength(curve))

        # For now, we need to add this attribute to CurveLength. Eventually
        # this would hopefully be done in simsgeo, but for now I'll put it here.
        obj.depends_on = ['curve']

        print('Initial curve length: ', obj.J())

        # Each target function 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.
        prob = LeastSquaresProblem([(obj, 0.0, 1.0)])

        # At the initial condition, get the Jacobian two ways: analytic
        # derivatives and finite differencing. The difference should be small.
        fd_jac = prob.dofs.fd_jac()
        jac = prob.dofs.jac()
        print('finite difference Jacobian:')
        print(fd_jac)
        print('Analytic Jacobian:')
        print(jac)
        print('Difference:')
        print(fd_jac - jac)
        assert np.allclose(fd_jac, jac, rtol=1e-4, atol=1e-4)

        # Solve the minimization problem:
        least_squares_serial_solve(prob, ftol=1e-10, xtol=1e-10, gtol=1e-10)

        print('At the optimum, x: ', prob.x)
        print(' Final curve dofs: ', curve.get_dofs())
        print(' Final curve length:    ', obj.J())
        print(' Expected final length: ', 2 * np.pi * x0[0])
        print(' objective function: ', prob.objective())
        assert abs(obj.J() - 2 * np.pi * x0[0]) < 1e-8
Example #7
0
    def test_supply_tuples(self):
        """
        Test basic usage
        """
        # Objective function f(x) = ((x - 3) / 2) ** 2
        iden1 = Identity()
        term1 = (iden1.J, 3, 0.25)
        prob = LeastSquaresProblem([term1])
        self.assertAlmostEqual(prob.objective(), 2.25)
        self.assertAlmostEqual(prob.objective(), sum(t.f_out() for t in prob.terms))
        self.assertEqual(len(prob.dofs.f()), 1)
        self.assertAlmostEqual(prob.dofs.f()[0], 0)
        self.assertEqual(len(prob.f()), 1)
        self.assertAlmostEqual(prob.f()[0], -1.5)
        self.assertAlmostEqual(prob.objective_from_shifted_f(prob.f()), 2.25)
        self.assertAlmostEqual(prob.objective_from_unshifted_f(prob.dofs.f()), 2.25)
        iden1.set_dofs([10])
        self.assertAlmostEqual(prob.objective(), 12.25)
        self.assertAlmostEqual(prob.objective(), sum(t.f_out() for t in prob.terms))
        self.assertAlmostEqual(prob.objective_from_shifted_f(prob.f()), 12.25)
        self.assertAlmostEqual(prob.objective_from_unshifted_f(prob.dofs.f()), 12.25)
        self.assertAlmostEqual(prob.objective([0]), 2.25)
        self.assertAlmostEqual(prob.objective([10]), 12.25)
        self.assertEqual(prob.dofs.all_owners, [iden1])
        self.assertEqual(prob.dofs.dof_owners, [iden1])

        # Objective function
        # f(x,y) = ((x - 3) / 2) ** 2 + ((y + 4) / 5) ** 2
        iden2 = Identity()
        term2 = (iden2.J, -4, 0.04)
        prob = LeastSquaresProblem([term1, term2])
        self.assertAlmostEqual(prob.objective(), 12.89)
        self.assertAlmostEqual(prob.objective(), sum(t.f_out() for t in prob.terms))
        self.assertEqual(len(prob.f()), 2)
        self.assertAlmostEqual(prob.objective_from_shifted_f(prob.f()), 12.89)
        self.assertAlmostEqual(prob.objective_from_unshifted_f(prob.dofs.f()), 12.89)
        iden1.set_dofs([5])
        iden2.set_dofs([-7])
        self.assertAlmostEqual(prob.objective(), 1.36)
        self.assertAlmostEqual(prob.objective(), sum(t.f_out() for t in prob.terms))
        self.assertEqual(len(prob.f()), 2)
        self.assertAlmostEqual(prob.objective_from_shifted_f(prob.f()), 1.36)
        self.assertAlmostEqual(prob.objective_from_unshifted_f(prob.dofs.f()), 1.36)
        self.assertAlmostEqual(prob.objective([10, 0]), 12.89)
        self.assertAlmostEqual(prob.objective([5, -7]), 1.36)
        self.assertEqual(prob.dofs.dof_owners, [iden1, iden2])
        self.assertEqual(prob.dofs.all_owners, [iden1, iden2])
 def test_solve_rosenbrock_using_vector(self):
     """
     Minimize the Rosenbrock function using a single vector-valued
     least-squares term.
     """
     for solver in solvers:
         for grad in [True, False]:
             r = Rosenbrock()
             prob = LeastSquaresProblem([(r.terms, 0, 1)])
             if solver == serial_solve:
                 if grad == True:
                     continue
                 else:
                     solver(prob, tol=1e-12)
             else:
                 solver(prob, grad=grad)
             self.assertAlmostEqual(prob.objective(), 0)
             v = r.get_dofs()
             self.assertAlmostEqual(v[0], 1)
             self.assertAlmostEqual(v[1], 1)
 def test_solve_quadratic(self):
     """
     Minimize f(x,y,z) = 1 * (x - 1) ^ 2 + 2 * (y - 2) ^ 2 + 3 * (z - 3) ^ 2.
     The optimum is at (x,y,z)=(1,2,3), and f=0 at this point.
     """
     for solver in solvers:
         iden1 = Identity()
         iden2 = Identity()
         iden3 = Identity()
         term1 = (iden1.J, 1, 1)
         term2 = (iden2.J, 2, 2)
         term3 = (iden3.J, 3, 3)
         prob = LeastSquaresProblem([term1, term2, term3])
         if solver == serial_solve:
             solver(prob, tol=1e-12)
         else:
             solver(prob)
         self.assertAlmostEqual(prob.objective(), 0)
         self.assertAlmostEqual(iden1.x, 1)
         self.assertAlmostEqual(iden2.x, 2)
         self.assertAlmostEqual(iden3.x, 3)
 def test_solve_rosenbrock_using_scalars(self):
     """
     Minimize the Rosenbrock function using two separate least-squares
     terms.
     """
     for solver in solvers:
         for grad in [True, False]:
             r = Rosenbrock()
             term1 = (r.term1, 0, 1)
             term2 = (r.term2, 0, 1)
             prob = LeastSquaresProblem((term1, term2))
             if solver == serial_solve:
                 if grad == True:
                     continue
                 else:
                     solver(prob, tol=1e-12)
             else:
                 solver(prob, grad=grad)
             self.assertAlmostEqual(prob.objective(), 0)
             v = r.get_dofs()
             self.assertAlmostEqual(v[0], 1)
             self.assertAlmostEqual(v[1], 1)
residue2 = Residue(spec, p, q, theta=np.pi)

if mpi.group == 0:
    r1 = residue1.J()
    r2 = residue2.J()
if mpi.proc0_world:
    print("Initial residues:", r1, r2)
#exit(0)

# Define objective function
prob = LeastSquaresProblem([(vmec.aspect, 6, 1), (vmec.iota_axis, 0.385, 1),
                            (vmec.iota_edge, 0.415, 1), (qs, 0, 1),
                            (residue1, 0, 2), (residue2, 0, 2)])

# Check whether we're in the CI. If so, just do a single function
# evaluation rather than a real optimization.
ci = "CI" in os.environ and os.environ['CI'].lower() in ['1', 'true']
if ci:
    obj = prob.objective()
else:
    # Remove the max_nfev=1 in the next line to do a serious optimization:
    least_squares_mpi_solve(prob, mpi=mpi, grad=True, max_nfev=1)

if mpi.group == 0:
    r1 = residue1.J()
    r2 = residue2.J()
if mpi.proc0_world:
    print("Final residues:", r1, r2)

print("Good bye")
    def test_stellopt_scenarios_1DOF_circularCrossSection_varyR0_targetVolume(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
        VMEC 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 VMEC.

        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
        """

        # logging.basicConfig(level=logging.DEBUG)
        # logger = logging.getLogger('[{}]'.format(MPI.COMM_WORLD.Get_rank()) + __name__)
        logger = logging.getLogger(__name__)

        for ngroups in range(1, 1 + MPI.COMM_WORLD.Get_size()):
            for grad in [False, True]:
                # In the next line, we can adjust how many groups the pool of MPI
                # processes is split into.
                mpi = MpiPartition(ngroups=ngroups)
                mpi.write()

                # Start with a default surface, which is axisymmetric with major
                # radius 1 and minor radius 0.1.
                equil = Vmec(mpi=mpi)
                surf = equil.boundary

                # Set the initial boundary shape. Here is one syntax:
                surf.set('rc(0,0)', 1.0)
                # Here is another syntax:
                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)

                # 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(0,0)', False)

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

                # Solve the minimization problem. We can choose whether to use a
                # derivative-free or derivative-based algorithm.
                least_squares_mpi_solve(prob, mpi=mpi, grad=grad)

                # Make sure all procs call VMEC:
                objective = prob.objective()
                if mpi.proc0_world:
                    print("At the optimum,")
                    print(" rc(m=0,n=0) = ", surf.get_rc(0, 0))
                    print(" volume, according to VMEC    = ", equil.volume())
                    print(" volume, according to Surface = ", surf.volume())
                    print(" objective function = ", objective)

                assert np.abs(surf.get_rc(0, 0) - 0.7599088773175) < 1.0e-5
                assert np.abs(equil.volume() - 0.15) < 1.0e-6
                assert np.abs(surf.volume() - 0.15) < 1.0e-6
                assert prob.objective() < 1.0e-15
Example #13
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)
Example #14
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)
Example #15
0
# Define some Target objects that depend on Parameter objects. In the
# future these functions would involve codes like VMEC, but for now we
# just use the functions f(x) = x.
iden1 = Identity()
iden2 = Identity()
iden3 = Identity()

# Parameters are all not fixed by default, meaning they will not be
# optimized.  You can choose to exclude any subset of the parameters
# from the space of independent variables by setting their 'fixed'
# property to True.
#iden1.fixed[0] = True
#iden2.fixed[0] = True
#iden3.fixed[0] = True

# Each Target is then equipped with a shift and weight, to become a
# term in a least-squares objective function
term1 = (iden1, 1, 1)
term2 = (iden2, 2, 2)
term3 = (iden3, 3, 3)

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

# Solve the minimization problem:
least_squares_serial_solve(prob)

print("An optimum was found at x=", iden1.x, ", y=", iden2.x, \
      ", z=", iden3.x)
print("The minimum value of the objective function is ", prob.objective())