Skip to content

Commit

Permalink
Rename linking current objective and expand docstring
Browse files Browse the repository at this point in the history
  • Loading branch information
f0uriest committed Dec 11, 2024
1 parent 39fec41 commit a63f2ae
Show file tree
Hide file tree
Showing 7 changed files with 27 additions and 18 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Changelog
New Feature

- Adds a new profile class ``PowerProfile`` for raising profiles to a power.
- Add ``desc.objectives.LinkingCurrent`` for ensuring that coils in a stage 2 or single stage optimization provide the required linking current for a given equilibrium.
- Add ``desc.objectives.LinkingCurrentConsistency`` for ensuring that coils in a stage 2 or single stage optimization provide the required linking current for a given equilibrium.


Bug Fixes
Expand Down
2 changes: 1 addition & 1 deletion desc/objectives/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
CoilSetLinkingNumber,
CoilSetMinDistance,
CoilTorsion,
LinkingCurrent,
LinkingCurrentConsistency,
PlasmaCoilSetMinDistance,
QuadraticFlux,
SurfaceCurrentRegularization,
Expand Down
13 changes: 10 additions & 3 deletions desc/objectives/_coils.py
Original file line number Diff line number Diff line change
Expand Up @@ -1763,9 +1763,15 @@ def compute(self, params_1, params_2=None, constants=None):
return Psi


class LinkingCurrent(_Objective):
class LinkingCurrentConsistency(_Objective):
"""Target the self-consistent poloidal linking current between the plasma and coils.
A self-consistent coil + plasma configuration must have the sum of the signed
currents in the coils that poloidally link the plasma equal to the total poloidal
current in the plasma G. This objective computes the difference between these two
quantities, such that a value of zero means the coils create the correct net
poloidal current.
Assumes the coil topology does not change (ie the linking number with the plasma
is fixed).
Expand Down Expand Up @@ -1796,15 +1802,16 @@ def __init__(
self,
eq,
coil,
*,
grid=None,
eq_fixed=False,
target=None,
bounds=None,
weight=1,
normalize=True,
normalize_target=True,
loss_function=None,
deriv_mode="auto",
grid=None,
eq_fixed=False,
jac_chunk_size=None,
name="linking current",
):
Expand Down
1 change: 1 addition & 0 deletions docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ Objective Functions
desc.objectives.HelicalForceBalance
desc.objectives.Isodynamicity
desc.objectives.LinearObjectiveFromUser
desc.objectives.LinkingCurrentConsistency
desc.objectives.MagneticWell
desc.objectives.MeanCurvature
desc.objectives.MercierStability
Expand Down
1 change: 1 addition & 0 deletions docs/api_objectives.rst
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ Coil Optimization
desc.objectives.CoilArclengthVariance
desc.objectives.ToroidalFlux
desc.objectives.SurfaceCurrentRegularization
desc.objectives.LinkingCurrentConsistency


Profiles
Expand Down
22 changes: 11 additions & 11 deletions tests/test_objective_funs.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
HeatingPowerISS04,
Isodynamicity,
LinearObjectiveFromUser,
LinkingCurrent,
LinkingCurrentConsistency,
MagneticWell,
MeanCurvature,
MercierStability,
Expand Down Expand Up @@ -1445,15 +1445,15 @@ def test_linking_current(self):
-c * 1.5,
]
np.testing.assert_allclose(coilset1._all_currents(), expected_currents)
obj = LinkingCurrent(eq, coilset1)
obj = LinkingCurrentConsistency(eq, coilset1)
obj.build()
f = obj.compute(coilset1.params_dict, eq.params_dict)
np.testing.assert_allclose(f, 0)

# same with virtual coils
coilset2 = CoilSet(coil1, coil2, NFP=2, sym=True)
np.testing.assert_allclose(coilset2._all_currents(), expected_currents)
obj = LinkingCurrent(eq, coilset2)
obj = LinkingCurrentConsistency(eq, coilset2)
obj.build()
f = obj.compute(coilset2.params_dict, eq.params_dict)
np.testing.assert_allclose(f, 0)
Expand All @@ -1464,7 +1464,7 @@ def test_linking_current(self):
np.testing.assert_allclose(
coilset3._all_currents(), expected_currents + expected_currents
)
obj = LinkingCurrent(eq, coilset3)
obj = LinkingCurrentConsistency(eq, coilset3)
obj.build()
f = obj.compute(coilset3.params_dict, eq.params_dict)
np.testing.assert_allclose(f, -G) # coils provide 2G so error is -G
Expand All @@ -1474,7 +1474,7 @@ def test_linking_current(self):
np.testing.assert_allclose(
coilset4._all_currents(), expected_currents + [0.5 * G / 8]
)
obj = LinkingCurrent(eq, coilset4)
obj = LinkingCurrentConsistency(eq, coilset4)
obj.build()
f = obj.compute(coilset4.params_dict, eq.params_dict)
np.testing.assert_allclose(f, -0.5 * G / 8)
Expand Down Expand Up @@ -2515,7 +2515,7 @@ class TestComputeScalarResolution:
FusionPower,
GenericObjective,
HeatingPowerISS04,
LinkingCurrent,
LinkingCurrentConsistency,
Omnigenity,
PlasmaCoilSetMinDistance,
PlasmaVesselDistance,
Expand Down Expand Up @@ -2949,14 +2949,14 @@ def test_compute_scalar_resolution_coils(self, objective):

@pytest.mark.unit
def test_compute_scalar_resolution_linking_current(self):
"""LinkingCurrent."""
"""LinkingCurrentConsistency."""
coil = FourierPlanarCoil(center=[10, 1, 0])
eq = Equilibrium()
coilset = CoilSet.from_symmetry(coil, NFP=4, sym=True)
f = np.zeros_like(self.res_array, dtype=float)
for i, res in enumerate(self.res_array):
obj = ObjectiveFunction(
LinkingCurrent(
LinkingCurrentConsistency(
eq,
coilset,
grid=LinearGrid(M=int(eq.M_grid * res), N=int(eq.N_grid * res)),
Expand Down Expand Up @@ -2996,7 +2996,7 @@ class TestObjectiveNaNGrad:
ForceBalanceAnisotropic,
FusionPower,
HeatingPowerISS04,
LinkingCurrent,
LinkingCurrentConsistency,
Omnigenity,
PlasmaCoilSetMinDistance,
PlasmaVesselDistance,
Expand Down Expand Up @@ -3283,11 +3283,11 @@ def test_objective_no_nangrad_ballooning(self):

@pytest.mark.unit
def test_objective_no_nangrad_linking_current(self):
"""LinkingCurrent."""
"""LinkingCurrentConsistency."""
coil = FourierPlanarCoil(center=[10, 1, 0])
coilset = CoilSet.from_symmetry(coil, NFP=4, sym=True)
eq = Equilibrium()
obj = ObjectiveFunction(LinkingCurrent(eq, coilset))
obj = ObjectiveFunction(LinkingCurrentConsistency(eq, coilset))
obj.build()
g = obj.grad(obj.x())
assert not np.any(np.isnan(g))
Expand Down
4 changes: 2 additions & 2 deletions tests/test_optimizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
FixPsi,
ForceBalance,
GenericObjective,
LinkingCurrent,
LinkingCurrentConsistency,
MagneticWell,
MeanCurvature,
ObjectiveFunction,
Expand Down Expand Up @@ -1405,7 +1405,7 @@ def test_optimize_coil_currents(DummyCoilSet):
coil.current = current / coils.num_coils

objective = ObjectiveFunction(QuadraticFlux(eq=eq, field=coils, vacuum=True))
constraints = LinkingCurrent(eq, coils, eq_fixed=True)
constraints = LinkingCurrentConsistency(eq, coils, eq_fixed=True)
optimizer = Optimizer("lsq-exact")
[coils_opt], _ = optimizer.optimize(
things=coils,
Expand Down

0 comments on commit a63f2ae

Please sign in to comment.