the elimination of magnetic islands, with both VMEC and SPEC called in the objective function. Below, the argument max_nfev=1 in least_squares_mpi_solve causes the optimization to stop after only a single iteration, so this example does not take too long to run. For a real optimization, that argument should be removed. """ log() mpi = MpiPartition() mpi.write() vmec_filename = os.path.join(os.path.dirname(__file__), 'inputs', 'input.nfp2_QA_iota0.4_withIslands') vmec = Vmec(vmec_filename, mpi=mpi) surf = vmec.boundary spec_filename = os.path.join(os.path.dirname(__file__), 'inputs', 'nfp2_QA_iota0.4_withIslands.sp') spec = Spec(spec_filename, mpi=mpi) # This next line is where the boundary surface objects of VMEC and # SPEC are linked: spec.boundary = surf # Define parameter space: surf.all_fixed() surf.fixed_range(mmin=0, mmax=3, nmin=-3, nmax=3, fixed=False) surf.set_fixed("rc(0,0)") # Major radius
from simsopt.util.mpi import MpiPartition from simsopt.mhd import Vmec, Boozer, Quasisymmetry from simsopt.objectives.least_squares import LeastSquaresProblem from simsopt.solve.mpi import least_squares_mpi_solve import os """ Optimize for quasi-helical symmetry (M=1, N=1) at a given radius. """ # This problem has 24 degrees of freedom, so we can use 24 + 1 = 25 # concurrent function evaluations for 1-sided finite difference # gradients. mpi = MpiPartition(25) vmec = Vmec(os.path.join(os.path.dirname(__file__), 'inputs', 'input.nfp4_QH_warm_start'), mpi=mpi) # Define parameter space: surf = vmec.boundary surf.all_fixed() max_mode = 2 surf.fixed_range(mmin=0, mmax=max_mode, nmin=-max_mode, nmax=max_mode, fixed=False) surf.set_fixed("rc(0,0)") # Major radius # Configure quasisymmetry objective: qs = Quasisymmetry(
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 """ # This next line turns on detailed logging. It can be commented out if # you do not want such verbose output. log(logging.INFO) mpi = MpiPartition() # Initialize VMEC from an input file: vmec = Vmec(os.path.join(os.path.dirname(__file__), 'inputs', 'input.2DOF_vmecOnly_targetIotaAndVolume'), mpi=mpi) surf = vmec.boundary # Initialize SPEC from an input file: spec = Spec(os.path.join(os.path.dirname(__file__), 'inputs', '2DOF_targetIotaAndVolume.sp'), mpi=mpi) # Set the SPEC boundary to be the same object as the VMEC boundary! spec.boundary = surf # 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)
#!/usr/bin/env python from simsopt.mhd import Vmec, Boozer, Quasisymmetry from simsopt import LeastSquaresProblem from simsopt import least_squares_serial_solve import os """ This script solve the problem in https://github.com/landreman/stellopt_scenarios/tree/master/2DOF_circularCrossSection_varyAxis_targetIotaAndQuasisymmetry See that website for a detailed description of the problem and plots of the objective function landscape. """ vmec = Vmec(os.path.join(os.path.dirname(__file__), 'inputs', 'input.2DOF_circularCrossSection_varyAxis_targetIotaAndQuasisymmetry')) # Define parameter space: vmec.boundary.all_fixed() vmec.boundary.set_fixed("rc(0,1)", False) vmec.boundary.set_fixed("zs(0,1)", False) # Define objective function: boozer = Boozer(vmec, mpol=32, ntor=16) qs = Quasisymmetry(boozer, 1.0, # Radius to target 1, 0, # (M, N) you want in |B| normalization="symmetric", weight="stellopt_ornl") # Objective function is 100 * (iota - (-0.41))^2 + 1 * (qs - 0)^2 prob = LeastSquaresProblem([(vmec.iota_axis, -0.41, 100),
The objective function for this example targets quasi-axisymmetry and the iota profile. First we optimize in a small parameter space, with m and |n| values up through 1. Then the parameter space is widened to include m and |n| values up through 2, with the resolution of VMEC and booz_xform increased at the same time. Then the parameter space is widened again to include m and |n| values up through 3, and again the resolution for VMEC and booz_xform is increased. """ #log() mpi = MpiPartition() mpi.write() vmec = Vmec(os.path.join(os.path.dirname(__file__), 'inputs', 'input.nfp2_QA'), mpi=mpi) vmec.verbose = mpi.proc0_world surf = vmec.boundary # Configure quasisymmetry objective: boozer = Boozer(vmec) boozer.bx.verbose = mpi.proc0_world qs = Quasisymmetry( boozer, 0.5, # Radius to target 1, 0) # (M, N) you want in |B| # Define objective function prob = LeastSquaresProblem([(vmec.aspect, 6, 1), (vmec.iota_axis, 0.465, 1), (vmec.iota_edge, 0.495, 1), (qs, 0, 1)])
can be found here: https://github.com/landreman/stellopt_scenarios/tree/master/2DOF_vmecOnly_targetIotaAndVolume """ # This next line turns on detailed logging. It can be commented out if # you do not want such verbose output. log() # In the next line, we can adjust how many groups the pool of MPI # processes is split into. mpi = MpiPartition(ngroups=3) mpi.write() # Initialize VMEC from an input file: equil = Vmec( os.path.join(os.path.dirname(__file__), 'inputs', 'input.2DOF_vmecOnly_targetIotaAndVolume'), mpi) 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
from simsopt import LeastSquaresProblem from simsopt.solve.mpi import least_squares_mpi_solve import os """ This script solve the problem in https://github.com/landreman/stellopt_scenarios/tree/master/7DOF_varyAxisAndElongation_targetIotaAndQuasisymmetry See that website for a detailed description of the problem. """ # This next line turns on detailed logging. It can be commented out if # you do not want such verbose output. log() mpi = MpiPartition() vmec = Vmec( os.path.join(os.path.dirname(__file__), 'inputs', 'input.stellopt_scenarios_7dof'), mpi) # We will optimize in the space of Garabedian coefficients: surf = vmec.boundary.to_Garabedian() vmec.boundary = surf # Define parameter space: surf.all_fixed() surf.fixed_range(mmin=0, mmax=2, nmin=-1, nmax=1, fixed=False) surf.set_fixed("Delta(1,0)") # toroidally-averaged major radius surf.set_fixed("Delta(0,0)") # toroidally-averaged minor radius # Define objective function: boozer = Boozer(vmec, mpol=32, ntor=16) qs = Quasisymmetry(
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 """ # Print detailed logging info. This could be commented out if desired. log() # In the next line, we can adjust how many groups the pool of MPI # processes is split into. mpi = MpiPartition(ngroups=2) 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()
from simsopt.mhd import Vmec, Spec, Boozer, Quasisymmetry from simsopt.mhd.spec import Residue from simsopt.objectives.least_squares import LeastSquaresProblem from simsopt.solve.mpi import least_squares_mpi_solve """ In this example, we simultaneously optimize for quasisymmetry and the elimination of magnetic islands, with both VMEC and SPEC called in the objective function. """ log() mpi = MpiPartition() mpi.write() vmec = Vmec(os.path.join(os.path.dirname(__file__), 'inputs', 'input.nfp2_QA_iota0.4_withIslands'), mpi=mpi) surf = vmec.boundary spec = Spec(os.path.join(os.path.dirname(__file__), 'inputs', 'nfp2_QA_iota0.4_withIslands.sp'), mpi=mpi) # This next line is where the boundary surface objects of VMEC and # SPEC are linked: spec.boundary = surf # Define parameter space: surf.all_fixed() surf.fixed_range(mmin=0, mmax=3, nmin=-3, nmax=3, fixed=False) surf.set_fixed("rc(0,0)") # Major radius # Configure quasisymmetry objective:
can be found here: https://github.com/landreman/stellopt_scenarios/tree/master/1DOF_circularCrossSection_varyAxis_targetIota """ # Print detailed logging info. This line could be commented out if desired. log() # In the next line, we can adjust how many groups the pool of MPI # processes is split into. mpi = MpiPartition(ngroups=1) mpi.write() # Start with a default surface, which is axisymmetric with major # radius 1 and minor radius 0.1. equil = Vmec(os.path.join(os.path.dirname(__file__), 'inputs', 'input.1DOF_Garabedian'), mpi=mpi) # 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 # 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('Delta(1,-1)', False) # Each function we want in the objective function is then equipped