Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 99 additions & 1 deletion process/core/caller.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@
from tabulate import tabulate

from process.core import constants
from process.core.final import finalise
from process.core import process_output as po
from process.core.io.mfile import MFile
from process.core.process_output import OutputFileManager, ovarre
from process.core.solver import constraints
from process.core.solver.iteration_variables import set_scaled_iteration_variable
from process.core.solver.objectives import objective_function
from process.data_structure.blanket_variables import BlktModelTypes
from process.data_structure.numerics import PROCESSRunMode
from process.models.tfcoil.base import TFConductorModel
from process.models.tfcoil.superconducting import SuperconductingTFTurnType

Expand Down Expand Up @@ -396,6 +397,103 @@ def _call_models_once(self, xc: np.ndarray):
# FISPACT and LOCA model (not used)- removed


def finalise(models, data, ifail: int, non_idempotent_msg: str | None = None):
"""Routine to print out the final point in the scan.

Writes to OUT.DAT and MFILE.DAT.

Parameters
----------
models : process.main.Models
physics and engineering model objects
data: DataStructure
data structure object to provide data to evaluate the constraints
ifail : int
error flag
non_idempotent_msg : None | str, optional
warning about non-idempotent variables, defaults to None
"""
if ifail == 1:
po.oheadr(constants.NOUT, "Final Feasible Point")
else:
po.oheadr(constants.NOUT, "Final UNFEASIBLE Point")

# Output relevant to no optimisation
if data.numerics.ioptimz == PROCESSRunMode.EVALUATION:
output_evaluation(data)

# Print non-idempotence warning to OUT.DAT only
if non_idempotent_msg:
po.oheadr(constants.NOUT, "NON-IDEMPOTENT VARIABLES")
po.ocmmnt(constants.NOUT, non_idempotent_msg)

# Write output to OUT.DAT and MFILE.DAT
models.write(data, constants.NOUT)


def output_evaluation(data):
"""Write output for an evaluation run of PROCESS

Parameters
----------
data: DataStructure
data structure object to provide data to evaluate the constraints
"""
po.oheadr(constants.NOUT, "Numerics")
po.ocmmnt(constants.NOUT, "PROCESS has performed an evaluation run.")
po.oblnkl(constants.NOUT)

# Evaluate objective function
norm_objf = objective_function(data.numerics.minmax, data)
po.ovarre(constants.MFILE, "Normalised objective function", "(norm_objf)", norm_objf)

# Print the residuals of the constraint equations

residual_error, value, residual, symbols, units = constraints.constraint_eqns(
data.numerics.neqns + data.numerics.nineqns, -1, data
)

labels = [
data.numerics.lablcc[j - 1]
for j in data.numerics.icc[: data.numerics.neqns + data.numerics.nineqns]
]

def _fmt(a, units):
return [f"{c} {u}" for c, u in zip(a, units, strict=False)]

po.write(
constants.NOUT,
tabulate(
{
"Constraint Name": labels,
"Constraint Type": symbols,
"Physical constraint": _fmt(value, units),
"Constraint residual": _fmt(residual, units),
"Normalised residual": residual_error,
},
headers="keys",
),
)

for i in range(data.numerics.neqns):
constraint_id = data.numerics.icc[i]
po.ovarre(
constants.MFILE,
f"{labels[i]} normalised residue",
f"(eq_con{constraint_id:03d})",
residual_error[i],
)

for i in range(data.numerics.nineqns):
constraint_id = data.numerics.icc[data.numerics.neqns + i]
po.ovarre(
constants.MFILE,
f"{labels[data.numerics.neqns + i]}",
f"(ineq_con{constraint_id:03d})",
residual_error[data.numerics.neqns + i],
)


def write_output_files(
models: Models, data: DataStructure, ifail: int, *, runtime: float | None = None
):
Expand Down
105 changes: 0 additions & 105 deletions process/core/final.py
Original file line number Diff line number Diff line change
@@ -1,105 +0,0 @@
"""Final output at the end of a scan."""

from tabulate import tabulate

from process.core import constants
from process.core import output as op
from process.core import process_output as po
from process.core.solver import constraints
from process.core.solver.objectives import objective_function
from process.data_structure.numerics import PROCESSRunMode


def finalise(models, data, ifail: int, non_idempotent_msg: str | None = None):
"""Routine to print out the final point in the scan.

Writes to OUT.DAT and MFILE.DAT.

Parameters
----------
models : process.main.Models
physics and engineering model objects
data: DataStructure
data structure object to provide data to evaluate the constraints
ifail : int
error flag
non_idempotent_msg : None | str, optional
warning about non-idempotent variables, defaults to None
"""
if ifail == 1:
po.oheadr(constants.NOUT, "Final Feasible Point")
else:
po.oheadr(constants.NOUT, "Final UNFEASIBLE Point")

# Output relevant to no optimisation
if data.numerics.ioptimz == PROCESSRunMode.EVALUATION:
output_evaluation(data)

# Print non-idempotence warning to OUT.DAT only
if non_idempotent_msg:
po.oheadr(constants.NOUT, "NON-IDEMPOTENT VARIABLES")
po.ocmmnt(constants.NOUT, non_idempotent_msg)

# Write output to OUT.DAT and MFILE.DAT
op.write(models, data, constants.NOUT)


def output_evaluation(data):
"""Write output for an evaluation run of PROCESS

Parameters
----------
data: DataStructure
data structure object to provide data to evaluate the constraints
"""
po.oheadr(constants.NOUT, "Numerics")
po.ocmmnt(constants.NOUT, "PROCESS has performed an evaluation run.")
po.oblnkl(constants.NOUT)

# Evaluate objective function
norm_objf = objective_function(data.numerics.minmax, data)
po.ovarre(constants.MFILE, "Normalised objective function", "(norm_objf)", norm_objf)

# Print the residuals of the constraint equations

residual_error, value, residual, symbols, units = constraints.constraint_eqns(
data.numerics.neqns + data.numerics.nineqns, -1, data
)

labels = [
data.numerics.lablcc[j]
for j in [
i - 1
for i in data.numerics.icc[: data.numerics.neqns + data.numerics.nineqns]
]
]
physical_constraint = [f"{c} {u}" for c, u in zip(value, units, strict=False)]
physical_residual = [f"{c} {u}" for c, u in zip(residual, units, strict=False)]

table_data = {
"Constraint Name": labels,
"Constraint Type": symbols,
"Physical constraint": physical_constraint,
"Constraint residual": physical_residual,
"Normalised residual": residual_error,
}

po.write(constants.NOUT, tabulate(table_data, headers="keys"))

for i in range(data.numerics.neqns):
constraint_id = data.numerics.icc[i]
po.ovarre(
constants.MFILE,
f"{labels[i]} normalised residue",
f"(eq_con{constraint_id:03d})",
residual_error[i],
)

for i in range(data.numerics.nineqns):
constraint_id = data.numerics.icc[data.numerics.neqns + i]
po.ovarre(
constants.MFILE,
f"{labels[data.numerics.neqns + i]}",
f"(ineq_con{constraint_id:03d})",
residual_error[data.numerics.neqns + i],
)
13 changes: 2 additions & 11 deletions process/core/input.py
Original file line number Diff line number Diff line change
Expand Up @@ -1138,24 +1138,15 @@ def bounds(self) -> tuple[NumberType | None, NumberType | None]:
"scan",
int,
choices=range(IPNSCNS + 1),
array=True,
),
"nsweep": InputVariable(
"scan",
int,
choices=range(1, IPNSCNV + 1),
),
"isweep_2": InputVariable(
"scan",
int,
choices=range(IPNSCNS + 1),
),
"nsweep_2": InputVariable(
"scan",
int,
choices=range(1, IPNSCNV + 1),
array=True,
),
"sweep": InputVariable("scan", float, array=True),
"sweep_2": InputVariable("scan", float, array=True),
"impvardiv": InputVariable(
"reinke",
int,
Expand Down
5 changes: 3 additions & 2 deletions process/core/io/plot/scans.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
from matplotlib.ticker import MultipleLocator, PercentFormatter

from process.core.io.mfile import MFile
from process.core.io.mfile.cli import mfile
from process.core.io.variable_metadata import var_dicts as meta
from process.core.scan import ScanVariables

Expand Down Expand Up @@ -532,9 +533,9 @@ def plot_1d_scan(
# This uses exclusively the last output_name2 defined in an earlier loop ignoring
# all other output_name2s...
if output_name == "plasma_current_MA":
extra_str = f"plasma_current{f'_vs_{output_name2}' if len(output_names2) > 0 else ''}" # ruff:ignore[line-too-long]
extra_str = f"plasma_current{f'_vs_{output_name2}' if len(output_names2) > 0 else ''}" # noqa: E501
elif stack_plots and output_names[-1] == output_name:
extra_str = f"{output_name}{f'_vs_{output_name2}' if len(output_names2) > 0 else '_vs_'.join(output_names)}" # ruff:ignore[line-too-long]
extra_str = f"{output_name}{f'_vs_{output_name2}' if len(output_names2) > 0 else '_vs_'.join(output_names)}" # noqa: E501
else:
extra_str = (
f"{output_name}{f'_vs_{output_name2}' if len(output_names2) > 0 else ''}"
Expand Down
Loading
Loading