diff --git a/documentation/proc-pages/images/plot_proc_1.PNG b/documentation/proc-pages/images/plot_proc_1.PNG index 932f01290f..bd7997819d 100644 Binary files a/documentation/proc-pages/images/plot_proc_1.PNG and b/documentation/proc-pages/images/plot_proc_1.PNG differ diff --git a/documentation/proc-pages/images/plot_proc_2.PNG b/documentation/proc-pages/images/plot_proc_2.PNG index 7d56144766..ccc3842957 100644 Binary files a/documentation/proc-pages/images/plot_proc_2.PNG and b/documentation/proc-pages/images/plot_proc_2.PNG differ diff --git a/documentation/proc-pages/io/utilities.md b/documentation/proc-pages/io/utilities.md index 2398f09862..49e958c89d 100644 --- a/documentation/proc-pages/io/utilities.md +++ b/documentation/proc-pages/io/utilities.md @@ -74,7 +74,7 @@ A utility to produce a three-page PDF summary of the output from PROCESS, includ ### Usage ```bash -python process/io/plot_proc.py [-h] [-f path/to/MFILE.DAT] [-s] +python process/io/plot_proc.py [-h] [-f path/to/MFILE.DAT] [-s] [-n N] [-d] [-c COLOUR] ``` If no `-f` argument is provided it assumes a file named `MFILE.DAT` is in the current directory. @@ -82,9 +82,12 @@ If no `-f` argument is provided it assumes a file named `MFILE.DAT` is in the cu ### Options | Argument | Description | | ---------------------- | -------------------------------- | -| `-h --help` | show help message and exit | -| `-f path/to/MFILE.DAT` | specify input/output file prefix | -| `-s, --show` | show plot | +| `-h --help` | Show help message and exit | +| `-f FILENAME` | Specify input/output file path | +| `-s, --show` | Show plot | +| `-n, N` | Which scan number to plot | +| `-d, --DEMO_ranges` | Uses the DEMO dimensions as ranges for all graphics | +| `-c, COLOUR` | Which colour scheme to use for cross-section plots; 1: Original PROCESS (default), 2: BLUEMIRA | ### Output Produces a three-page PDF file in the same directory as the input MFILE. The PDF file name has the same prefix as the input MFILE but ending in `SUMMARY.pdf` @@ -105,71 +108,88 @@ Produces a three-page PDF file in the same directory as the input MFILE. The PDF `Plasma Composition` - Number densities of several ion species relative to the electron density. -`Coil Currents etc` - Peak coil currents of the PF coils in $MA$, flux swing of the central solenoid -used for startup and total available in $Wb$. Total burn time `tburn` in hrs. +`Coil Currents etc` - Peak coil currents of the PF coils in $\text{MA}$, flux swing of the central solenoid +used for startup and total available in $\text{Wb}$. Total burn time `tburn` in hrs. -`Cost of electricity` - This is the cost of electricity in $/MWh$. Check the respective cost model +`Cost of electricity` - This is the cost of electricity in $ $/ \text{MWh}$. Check the respective cost model for the reference year of the inflation used. | Geometry | | :--------------------------------------------------------- | -| major radius $R_0$ | -| minor radius $a$ | -| aspect ratio $A$ | -| elongation at the 95% flux surface $\kappa_{95}$ | -| plasma triangularity at the 95% flux surface $\delta_{95}$ | -| plasma surface area | -| plasma volume | -| number of TF coils | -| inboard/outboard blanket thickness | -| inboard/outboard shield thickness | -| total fusion power | +| Major radius, $R_0$ | +| Minor radius, $a$ | +| Aspect ratio, $A$ | +| Elongation at the 95% flux surface, $\kappa_{95}$ | +| Plasma triangularity at the 95% flux surface, $\delta_{95}$| +| Plasma surface area | +| Plasma volume | +| Number of TF coils | +| Inboard blanket + shield | +| Outboard blanket + shield | +| Total fusion power | +| Plasma gain factor, $Q_{\text{p}}$ | | Power flows | | :---------------------------------------------------------------------------------------------------------- | -| average neutron wall load $W_{all}=\frac{P_{neutrons}}{S_{plasma,surface}f_{user}}$[^2] | -| normalised radius of the 'core' region $\rho_{core}$ used in the radiation correction of the | -| confinement scaling[^3] [^4] | -| the electron density at the pedestal top $n_{e,ped}[m^{-3}]$ | -| the normalised radius $\rho=r/a$ at the pedestal top | -| the helium fraction relative to the electron density | -| the core radiation $P_{rad} (\rho<\rho_{core})$ subtracted from $P_{heat}$ in confinement scaling | -| $W_{th}$, the total radiation inside the separatrix | -| nuclear heating power to blanket $P_{nuc,blkt}= P_{neutr} (1-e^{-\frac{\Delta x_{blkt}}{\lambda_{decay}}})$ | -| nuclear heating power to the shield $P_{nuc,shld}=P_{neutr}-P_{nuc,blkt}$ | -| power crossing the separatrix into the SoL/Divertor $P_{sep}$ | -| L-H threshold power $P_{LH}$ | -| divertor lifetime in years | -| high grade heat for electricity production $P_{therm}$ | -| gross cycle efficiency $P_{e,gross}/P_{therm}$ | -| net cycle efficiency $\frac{P_{e,gross}-P_{heat,pump}}{P_{therm}-P_{heat,pump}}$ | -| net electric power $P_{e,net}=P_{e,gross}-P_{recirc}$ | -| plant efficiency $P_{e,net}/P_{fus}$ | +| Nominal neutron wall load[^2] | +| Normalised radius of the 'core' region $\rho_{core}$ used in the radiation correction of the onfinement scaling[^3] [^4] | +| The electron density at the pedestal top, $n_{\text{e,ped}}$ | +| The normalised radius $\rho=r/a$ at the pedestal top | +| The helium fraction relative to the electron density | +| The core radiation $P_{\text{rad}} (\rho<\rho_{\text{core}})$ subtracted from $P_{\text{heat}}$ in confinement scaling | +| The total radiation inside the separatrix (LCFS), $W_{\text{th}}$ | +| Nuclear heating power to blanket $P_{\text{nuc,blkt}}= P_{\text{neutr}} \left(1-e^{-\frac{\Delta x_{\text{blkt}}}{\lambda_{\text{decay}}}}\right)$ | +| Nuclear heating power to the shield $P_{\text{nuc,shld}}=P_{\text{neutr}}-P_{\text{nuc,blkt}}$ | +| TF cryogenic power | +| Power to the divertor | +| Divertor lifetime in years | +| Primary high grade heat for electricity production, $P_{\text{therm}}$ | +| Gross cycle efficiency, $P_{\text{e,gross}}/P_{\text{therm}}$ | +| Net cycle efficiency, $\frac{P_{\text{e,gross}}-P_{\text{heat,pump}}}{P_{\text{therm}}-P_{\text{heat,pump}}}$ | +| Net electric power, $P_{\text{e,net}}=P_{\text{e,gross}}-P_{\text{recirc}}$ | +| Fusion-to-electric efficiency, $P_{\text{e,net}}/P_{\text{fus}}$ | | Physics | | :-------------------------------------------------------------------------------------------------------------- | -| plasma current $I_P[MA]$ | -| vaccuum magnetic field at in the plasma centre $B_T(R_0)$ | -| safety factor at the 95\% flux surface $q_{95}$ | -| definitions of $\beta$ as given in [^1] | -| volume averaged electron temperature $\langle T_e\rangle$ and density $\langle n_e\rangle$ | -| fraction of the line averaged electron density over the Greenwald density $\langle n_{e,line}\rangle / n_{GW}$ | -| peaking of the electron temperature $T_{e,0}/\langle T_e\rangle$ and density $n_{e,0}/\langle n_{e,vol}\rangle$ | -| core and SoL effective charge $Z_{eff}=\sum_i f_iZ_i^2$ | -| impurity fraction $f_Z=n_Z/\langle n_e\rangle$ | -| H-factor and confinement time are calculated using a radiation corrected confinement scaling[^3] [^4]. | - -| Neutral Beam Current Drive | +| Plasma current, $I_{\text{P}}$ | +| Vaccuum magnetic field at in the plasma centre, $B_{\text{T}}(R_0)$ | +| Safety factor at the 95% flux surface, $q_{95}$ | +| Definitions of $\beta$ as given in [^1] | +| Volume averaged electron temperature $\langle T_e\rangle$ and density $\langle n_e\rangle$ | +| Fraction of the line averaged electron density over the Greenwald density, $\langle n_{\text{e,line}}\rangle / n_{\text{GW}}$ | +| Peaking of the electron temperature $T_{\text{e,0}}/\langle T_{\text{e}}\rangle$ and density $n_{\text{e,0}}/\langle n_{\text{e,vol}}\rangle$ | +| Plasma effective charge, $Z_{\text{eff}}=\sum_i f_iZ_i^2$ | +| Impurity fraction, $f_Z=n_Z/\langle n_e\rangle$ | +| H-factor and confinement time calculated from a radiation corrected confinement scaling[^3] [^4]. | +| L-H threshold power, $P_{\text{LH}}$ | +| The confinement time scaling law used | + +| Heating & Current Drive | | :------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| the steady state auxiliary power used for heating and current drive during the flat top phase (NOT to be confused with the start up or ramp down power requirements) | -| part of the auxiliary power that is used for heating only, but not current drive | -| current drive fractions for the inductive, auxiliary and bootstrap current | -| the neutral beam current drive efficiency $\gamma_{NB}$ | -| the neutral beam energy | -| the plasma heating used in the calculation of the confinement scaling/H-factor $P_{aux} + P_\alpha - P_{rad,core}$ | -| the divertor figure of merit $P_{sep}/R$, $P_{sep}/(\langle n_e\rangle R)$ | -| fraction of the power crossing the separatrix with respect to the LH-threshold power $P_{sep}/P_{LH}$ | -| non-radiation corrected H-factor (calculated for info only) | +| The steady state auxiliary power used for heating and current drive during the flat top phase (NOT to be confused with the start up or ramp down power requirements) | +| Part of the auxiliary power that is used for heating only, but not current drive | +| Current drive fractions for the bootstrap auxiliary and inductive current | +| The neutral beam current drive efficiency, $\gamma_{NB}$ (If NBI used) | +| The neutral beam energy (If NBI used) | +| The plasma heating used in the calculation of the confinement scaling / H-factor, $P_{\text{aux}} + P_\alpha - P_{\text{rad,core}}$ | +|The normalised current drive efficiency| +| The divertor figures of merit, $\frac{P_{\text{sep}}}{R}$ & $\frac{P_{\text{sep}}}{\langle n_e\rangle R}$ | +| Fraction of the power crossing the separatrix with respect to the LH-threshold power $P_{\text{sep}}/P_{\text{LH}}$ | +| Non-radiation corrected H-factor, $\text{H*}$ (Calculated for info only) | + +| TF and WP structure | +| :---------------------------------------------------------------------------------------------------------- | +|Inboard TF nose case thickness| +|Inboard TF minimum distance between side case and WP| +|Radial width of inboard TF leg| +|Thickness of insualtion surrounding WP| +|Number of turns in WP| +|WP current density| +|Radial width of WP| +|Inter-turn insulation thickness| +|Turn steel conduit thickness| +|Turn cable space width and surface area| +|Turn cooling pipe diameter| ## Sankey Diagram @@ -294,7 +314,7 @@ This utility plots the output of a PROCESS scan. PROCESS must be run on a scan-e ### Usage ``` -python process/io/plot_scans.py [-h] [-f path/to/MFILE(s)] [-yv 'output vars'] [-yv2 2nd axis output variable] +python process/io/plot_scans.py [-h] [-f path/to/MFILE(s)] [-yv output vars] [-yv2 2nd axis output variable] [-o [path/to/directory]] [-out] [-sf [SAVE_FORMAT]] [-as [AXIS_FONT_SIZE]] [-ln LABEL_NAME] [-2DC] [-stc] ``` ### Options @@ -302,13 +322,16 @@ python process/io/plot_scans.py [-h] [-f path/to/MFILE(s)] [-yv 'output vars'] [ | Argument | Description | | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------- | | `-h, --help` | show help message and exit | -| `-f` | file(s) to read as MFILE.DAT | -| `-yv` | select the output variables | -| `-yv2` | select the 2nd axis output variable | -| `-o` | Output directory for plots, defaults to current working directory. | -| `-sf` | output format (default='pdf') | -| `-as` | Axis label font size selection (default=18) | -| `-ln` | Label names for plot legend. If multiple input files used then list the same number of label names eg: -nl 'leg1 leg2', (default = MFile file name) | +| `-f, --input_files` | Specify input file(s) path(s) (default = MFILE.DAT).More than one input file can be used eg: -f 'A_MFILE.DAT B_MFILE.DAT'. You can only specify the folder containing the MFILE. The different files scan will be plotted on the same graph. The scans must use the same scan variation. | +| `-yv, --y_vars` | Select the output variables. More than one output can be plotted eg: -yv 'var1 var2'. A separate plot will be created for each inputs variables | +| `-yv2, --y_vars2` | Select the 2nd axis output variable eg: -yv2 'var'. 2nd variable will be plotted on shared figure inputsvariable. | +| `-o, --outputdir` | Output directory for plots, defaults to current working directory. | +| `-out, --term_output` | Option to show scans values on terminal directory. | +| `-sf, --save_format` | Output format (default='pdf') | +| `-as, --axis_font_size` | Axis label font size selection (default=18) | +| `-ln, --label_name` | Label names for plot legend. If multiple input files used then list the same number of label names eg: -nl 'leg1 leg2', (default = MFile file name) | +| `-2DC, --two_dimensional_contour` | Option to plot 2D scans as a coloured contour plot instead of a line plot. Note: Non convergent points will show up with a value of zero Note: The scan paramters must both be in increasing orderl | +| `-stc, --stack_plots` | Option to plot multiple 1D plots in a column of subplots. Variables will be plotted in order of input | diff --git a/process/build.py b/process/build.py index af54eeb3d2..76f4b29a14 100755 --- a/process/build.py +++ b/process/build.py @@ -1994,6 +1994,7 @@ def radialb(self, output: bool): vbuild, "(thshield_vb)", ) + po.ovarre( self.mfile, "Thermal shield, vertical (m)", @@ -2258,6 +2259,12 @@ def radialb(self, output: bool): vbuild, "(thshield_vb)", ) + po.ovarre( + self.mfile, + "Thermal shield, vertical (m)", + "(thshield_vb)", + build_variables.thshield_vb, + ) vbuild = vbuild - build_variables.thshield_vb po.obuild( @@ -2497,9 +2504,12 @@ def radialb(self, output: bool): "(ohhghf)", pfcoil_variables.ohhghf, ) - po.ovarre( - self.mfile, - "Width of neutral beam duct where it passes between the TF coils (m)", - "(beamwd)", - current_drive_variables.beamwd, - ) + if (current_drive_variables.iefrf in [5, 8]) or ( + current_drive_variables.iefrffix in [5, 8] + ): + po.ovarre( + self.mfile, + "Width of neutral beam duct where it passes between the TF coils (m)", + "(beamwd)", + current_drive_variables.beamwd, + ) diff --git a/process/io/plot_proc.py b/process/io/plot_proc.py index d239d719e4..092d7bcc0e 100755 --- a/process/io/plot_proc.py +++ b/process/io/plot_proc.py @@ -17,6 +17,7 @@ import os import sys import argparse +from argparse import RawTextHelpFormatter import matplotlib import matplotlib.pyplot as plt from matplotlib.patches import Rectangle @@ -64,18 +65,66 @@ import importlib_resources as resources -solenoid = "pink" -cscompression = "red" -tfc = "cyan" -thermal_shield = "gray" -vessel = "green" -shield = "green" -blanket = "magenta" -plasma = "khaki" -cryostat = "red" -firstwall = "darkblue" -winding = "blue" -nbshield_colour = "gray" +def parse_args(args): + """Parse supplied arguments. + + :param args: arguments to parse + :type args: list, None + :return: parsed arguments + :rtype: Namespace + """ + # Setup command line arguments + parser = argparse.ArgumentParser( + description="Produces a three page summary of the PROCESS MFILE output, using the MFILE. " + "For info please see https://github.com/ukaea/PROCESS?tab=readme-ov-file#contacts ", + formatter_class=RawTextHelpFormatter, + ) + + parser.add_argument( + "-f", + metavar="FILENAME", + type=str, + default="", + help="specify input/output file path", + ) + parser.add_argument("-s", "--show", help="show plot", action="store_true") + + parser.add_argument("-n", type=int, help="Which scan to plot?") + + parser.add_argument( + "-d", + "--DEMO_ranges", + help="Uses the DEMO dimensions as ranges for all graphics", + action="store_true", + ) + + parser.add_argument( + "-c", + "--colour", + type=int, + help=( + "Which colour scheme to use for cross-section plots\n" + "1: Original PROCESS (default)\n" + "2: BLUEMIRA" + ), + default=1, + ) + + return parser.parse_args(args) + + +# Colours are PROCESS defualt, BLUEMIRA +SOLENOID_COLOUR = ["pink", "#1764ab"] +CSCOMPRESSION_COLOUR = ["red", "#33CCCC"] +TFC_COLOUR = ["cyan", "#084a91"] +THERMAL_SHIELD_COLOUR = ["gray", "#e3eef9"] +VESSEL_COLOUR = ["green", "#b7d4ea"] +SHIELD_COLOUR = ["green", "#94c4df"] +BLANKET_COLOUR = ["magenta", "#4a98c9"] +PLASMA_COLOUR = ["khaki", "#cc8acc"] +CRYOSTAT_COLOUR = ["red", "#2e7ebc"] +FIRSTWALL_COLOUR = ["darkblue", "darkblue"] +NBSHIELD_COLOUR = ["black", "black"] thin = 0.0 @@ -108,20 +157,6 @@ "tfthko", ] -vertical_upper = [ - "rminor*kappa", - "vgaptop", - "fwtth", - "blnktth", - "vvblgap", - "shldtth", - "d_vv_top", - "vgap2", - "thshield_vb", - "tftsgap", - "tfcth", -] - vertical_lower = [ "rminor*kappa", "vgap", @@ -153,6 +188,8 @@ def plot_plasma(axis, mfile_data, scan): scan --> scan number to use """ + args = parse_args(None) + colour_scheme = int(args.colour) r_0 = mfile_data.data["rmajor"].get_scan(scan) a = mfile_data.data["rminor"].get_scan(scan) @@ -170,17 +207,20 @@ def plot_plasma(axis, mfile_data, scan): axis.plot(pg.rs[0], pg.zs[0], color="black") axis.plot(pg.rs[1], pg.zs[1], color="black") - axis.fill_betweenx( - pg.zs[0], - pg.rs[0], - pg.rs[1], - where=(pg.rs[1] < pg.rs[0]) - & (pg.zs[0] > (-a * pg.kappa)) - & (pg.zs[0] < (a * pg.kappa)), - color=plasma, + + # Colour in right side of plasma + axis.fill_between( + x=pg.rs[0], + y1=pg.zs[0], + where=(pg.rs[0] > r_0 - (triang_95 * a * 1.5)), + color=PLASMA_COLOUR[colour_scheme - 1], ) - axis.fill_betweenx( - pg.zs[0], pg.rs[0], pg.rs[1], where=(pg.rs[1] > pg.rs[0]), color="none" + # Colour in left side of plasma + axis.fill_between( + x=pg.rs[1], + y1=pg.zs[1], + where=(pg.rs[1] < r_0 - (triang_95 * a * 1.5)), + color=PLASMA_COLOUR[colour_scheme - 1], ) @@ -313,6 +353,9 @@ def poloidal_cross_section(axis, mfile_data, scan, demo_ranges): def plot_cryostat(axis, mfile_data, scan): """Function to plot cryostat in poloidal cross-section""" + args = parse_args(None) + colour_scheme = int(args.colour) + rects = cryostat_geometry(rdewex=rdewex, ddwex=ddwex, zdewex=zdewex) for rec in rects: @@ -321,61 +364,123 @@ def plot_cryostat(axis, mfile_data, scan): xy=(rec.anchor_x, rec.anchor_z), width=rec.width, height=rec.height, - facecolor=cryostat, + facecolor=CRYOSTAT_COLOUR[colour_scheme - 1], ) ) -def color_key(axis): +def color_key(axis, mfile_data, scan): + """Function to plot the colour key Arguments: axis --> object to add plot to """ + + args = parse_args(None) + colour_scheme = int(args.colour) + axis.set_ylim([0, 10]) axis.set_xlim([0, 10]) axis.set_axis_off() axis.set_autoscaley_on(False) axis.set_autoscalex_on(False) + axis.text( + -5, + 12, + "*The CS comp and thermal shield are not shown in the poloidal cross-section", + ha="left", + va="top", + size="medium", + ) + axis.text(-5, 10, "CS coil", ha="left", va="top", size="medium") - axis.add_patch(patches.Rectangle([0.2, 9.7], 1, 0.4, lw=0, facecolor=solenoid)) + axis.add_patch( + patches.Rectangle( + [0.7, 9.7], 1, 0.4, lw=0, facecolor=SOLENOID_COLOUR[colour_scheme - 1] + ) + ) axis.text(-5, 9, "CS comp", ha="left", va="top", size="medium") - axis.add_patch(patches.Rectangle([0.2, 8.7], 1, 0.4, lw=0, facecolor=cscompression)) + axis.add_patch( + patches.Rectangle( + [0.7, 8.7], 1, 0.4, lw=0, facecolor=CSCOMPRESSION_COLOUR[colour_scheme - 1] + ) + ) axis.text(-5, 8, "TF coil", ha="left", va="top", size="medium") - axis.add_patch(patches.Rectangle([0.2, 7.7], 1, 0.4, lw=0, facecolor=tfc)) + axis.add_patch( + patches.Rectangle( + [0.7, 7.7], 1, 0.4, lw=0, facecolor=TFC_COLOUR[colour_scheme - 1] + ) + ) - axis.text(-5, 7, "Th shield", ha="left", va="top", size="medium") + axis.text(-5, 7, "Thermal shield", ha="left", va="top", size="medium") axis.add_patch( - patches.Rectangle([0.2, 6.7], 1, 0.4, lw=0, facecolor=thermal_shield) + patches.Rectangle( + [0.7, 6.7], + 1, + 0.4, + lw=0, + facecolor=THERMAL_SHIELD_COLOUR[colour_scheme - 1], + ) ) axis.text(-5, 6, "VV & shield", ha="left", va="top", size="medium") - axis.add_patch(patches.Rectangle([0.2, 5.7], 1, 0.4, lw=0, facecolor=vessel)) + axis.add_patch( + patches.Rectangle( + [0.7, 5.7], 1, 0.4, lw=0, facecolor=VESSEL_COLOUR[colour_scheme - 1] + ) + ) axis.text(-5, 5, "Blanket", ha="left", va="top", size="medium") - axis.add_patch(patches.Rectangle([0.2, 4.7], 1, 0.4, lw=0, facecolor=blanket)) + axis.add_patch( + patches.Rectangle( + [0.7, 4.7], 1, 0.4, lw=0, facecolor=BLANKET_COLOUR[colour_scheme - 1] + ) + ) axis.text(-5, 4, "First wall", ha="left", va="top", size="medium") - axis.add_patch(patches.Rectangle([0.2, 3.7], 1, 0.4, lw=0, facecolor=firstwall)) + axis.add_patch( + patches.Rectangle( + [0.7, 3.7], 1, 0.4, lw=0, facecolor=FIRSTWALL_COLOUR[colour_scheme - 1] + ) + ) axis.text(-5, 3, "Plasma", ha="left", va="top", size="medium") - axis.add_patch(patches.Rectangle([0.2, 2.7], 1, 0.4, lw=0, facecolor=plasma)) + axis.add_patch( + patches.Rectangle( + [0.7, 2.7], 1, 0.4, lw=0, facecolor=PLASMA_COLOUR[colour_scheme - 1] + ) + ) axis.text(-5, 2, "PF coils", ha="left", va="top", size="medium") axis.add_patch( - patches.Rectangle([0.2, 1.7], 1, 0.4, lw=1, facecolor="none", edgecolor="black") + patches.Rectangle([0.7, 1.7], 1, 0.4, lw=1, facecolor="none", edgecolor="black") ) + if (mfile_data.data["iefrf"].get_scan(scan) in [5, 8]) or ( + mfile_data.data["iefrffix"].get_scan(scan) in [5, 8] + ): + axis.text(-5, 1, "NB duct shield", ha="left", va="top", size="medium") + axis.add_patch( + patches.Rectangle( + [0.7, 0.7], 1, 0.4, lw=0, facecolor=NBSHIELD_COLOUR[colour_scheme - 1] + ) + ) + axis.text(-5, 0.1, "Cryostat", ha="left", va="top", size="medium") + axis.add_patch( + patches.Rectangle( + [0.7, -0.3], 1, 0.4, lw=0, facecolor=CRYOSTAT_COLOUR[colour_scheme - 1] + ) + ) - axis.text(-5, 1, "NB duct shield", ha="left", va="top", size="medium") + axis.text(-5, 1, "Cryostat", ha="left", va="top", size="medium") axis.add_patch( - patches.Rectangle([0.2, 0.7], 1, 0.4, lw=0, facecolor=nbshield_colour) + patches.Rectangle( + [0.7, 0.7], 1, 0.1, lw=0, facecolor=CRYOSTAT_COLOUR[colour_scheme - 1] + ) ) - axis.text(-5, 0.1, "cryostat", ha="left", va="top", size="medium") - axis.add_patch(patches.Rectangle([0.2, -0.3], 1, 0.4, lw=0, facecolor=cryostat)) - def toroidal_cross_section(axis, mfile_data, scan, demo_ranges): """Function to plot toroidal cross-section @@ -384,17 +489,8 @@ def toroidal_cross_section(axis, mfile_data, scan, demo_ranges): mfile_data --> MFILE data object scan --> scan number to use """ - - # Check for Copper magnets - if "i_tf_sup" in mfile_data.data.keys(): - i_tf_sup = int(mfile_data.data["i_tf_sup"].get_scan(scan)) - else: - i_tf_sup = int(1) - - if "i_tf_turns_integer" in mfile_data.data.keys(): - i_tf_turns_integer = int(mfile_data.data["i_tf_turns_integer"].get_scan(scan)) - else: - i_tf_turns_integer = int(0) + args = parse_args(None) + colour_scheme = int(args.colour) axis.set_xlabel("x / m") axis.set_ylabel("y / m") @@ -405,47 +501,49 @@ def toroidal_cross_section(axis, mfile_data, scan, demo_ranges): # Colour in the main components r2, r1 = cumulative_radial_build2("ohcth", mfile_data, scan) - arc_fill(axis, r1, r2, color=solenoid) + arc_fill(axis, r1, r2, color=SOLENOID_COLOUR[colour_scheme - 1]) r2, r1 = cumulative_radial_build2("precomp", mfile_data, scan) - arc_fill(axis, r1, r2, color=cscompression) + arc_fill(axis, r1, r2, color=CSCOMPRESSION_COLOUR[colour_scheme - 1]) r2, r1 = cumulative_radial_build2("tfcth", mfile_data, scan) - arc_fill(axis, r1, r2, color=tfc) + arc_fill(axis, r1, r2, color=TFC_COLOUR[colour_scheme - 1]) r2, r1 = cumulative_radial_build2("thshield_ib", mfile_data, scan) - arc_fill(axis, r1, r2, color=thermal_shield) + arc_fill(axis, r1, r2, color=THERMAL_SHIELD_COLOUR[colour_scheme - 1]) r2, r1 = cumulative_radial_build2("d_vv_in", mfile_data, scan) - arc_fill(axis, r1, r2, color=vessel) + arc_fill(axis, r1, r2, color=VESSEL_COLOUR[colour_scheme - 1]) r2, r1 = cumulative_radial_build2("shldith", mfile_data, scan) - arc_fill(axis, r1, r2, color=vessel) + arc_fill(axis, r1, r2, color=VESSEL_COLOUR[colour_scheme - 1]) r2, r1 = cumulative_radial_build2("blnkith", mfile_data, scan) - arc_fill(axis, r1, r2, color=blanket) + arc_fill(axis, r1, r2, color=BLANKET_COLOUR[colour_scheme - 1]) r2, r1 = cumulative_radial_build2("fwith", mfile_data, scan) - arc_fill(axis, r1, r2, color=firstwall) + arc_fill(axis, r1, r2, color=FIRSTWALL_COLOUR[colour_scheme - 1]) - arc_fill(axis, rmajor - rminor, rmajor + rminor, color=plasma) + arc_fill( + axis, rmajor - rminor, rmajor + rminor, color=PLASMA_COLOUR[colour_scheme - 1] + ) r2, r1 = cumulative_radial_build2("fwoth", mfile_data, scan) - arc_fill(axis, r1, r2, color=firstwall) + arc_fill(axis, r1, r2, color=FIRSTWALL_COLOUR[colour_scheme - 1]) r2, r1 = cumulative_radial_build2("blnkoth", mfile_data, scan) - arc_fill(axis, r1, r2, color=blanket) + arc_fill(axis, r1, r2, color=BLANKET_COLOUR[colour_scheme - 1]) r2, r1 = cumulative_radial_build2("shldoth", mfile_data, scan) - arc_fill(axis, r1, r2, color=shield) + arc_fill(axis, r1, r2, color=SHIELD_COLOUR[colour_scheme - 1]) r2, r1 = cumulative_radial_build2("d_vv_out", mfile_data, scan) - arc_fill(axis, r1, r2, color=vessel) + arc_fill(axis, r1, r2, color=VESSEL_COLOUR[colour_scheme - 1]) r2, r1 = cumulative_radial_build2("thshield_ob", mfile_data, scan) - arc_fill(axis, r1, r2, color=thermal_shield) + arc_fill(axis, r1, r2, color=THERMAL_SHIELD_COLOUR[colour_scheme - 1]) - arc_fill(axis, rdewex, rdewex + ddwex, color=cryostat) + arc_fill(axis, rdewex, rdewex + ddwex, color=CRYOSTAT_COLOUR[colour_scheme - 1]) # Segment the TF coil inboard # Calculate centrelines @@ -472,23 +570,6 @@ def toroidal_cross_section(axis, mfile_data, scan, demo_ranges): xo = r2 * np.cos(angu) yo = r2 * np.sin(angu) axis.plot((xi, xo), (yi, yo), color="black") - # Annotate plot. - axis.text( - rmajor * np.cos(0.3), - rmajor * np.sin(0.3), - "plasma", - fontsize=(12), - ha="center", - va="center", - ) - axis.text( - (rdewex + ddwex) / 1.41, - (rdewex + ddwex) / 1.41, - "cryostat", - fontsize=(10), - ha="left", - va="bottom", - ) for item in i: # Neutral beam shielding @@ -499,61 +580,18 @@ def toroidal_cross_section(axis, mfile_data, scan, demo_ranges): r3=r3, r4=r4, w=w + nbshield, - facecolor=nbshield_colour, + facecolor=NBSHIELD_COLOUR[colour_scheme - 1], ) # Overlay TF coil segments - TF_outboard(axis, item, n_tf=n_tf, r3=r3, r4=r4, w=w, facecolor="cyan") - - # Winding pack : inboard (superconducor only) - if i_tf_sup == 1: - # Inboard - if i_tf_turns_integer == 1: - rect = patches.Rectangle( - [r1 + thkcas + tinstf, 0], dr_tf_wp, wwp1 / 2, lw=0, facecolor=winding - ) - axis.add_patch(rect) - else: - rect = patches.Rectangle( - [r1 + thkcas + tinstf, 0], - dr_tf_wp / 2, - wwp2 / 2, - lw=0, - facecolor=winding, - ) - axis.add_patch(rect) - - rect = patches.Rectangle( - [r1 + thkcas + tinstf + dr_tf_wp / 2, 0], - dr_tf_wp / 2, - wwp1 / 2, - lw=0, - facecolor=winding, - ) - axis.add_patch(rect) - - # Outboard - if i_tf_turns_integer == 1: - rect = patches.Rectangle( - [r3 + casthi + tinstf, 0], dr_tf_wp, wwp1 / 2, lw=0, facecolor=winding - ) - axis.add_patch(rect) - else: - rect = patches.Rectangle( - [r3 + casthi + tinstf, 0], - dr_tf_wp / 2, - wwp1 / 2, - lw=0, - facecolor=winding, - ) - axis.add_patch(rect) - rect = patches.Rectangle( - [r3 + casthi + tinstf + dr_tf_wp / 2, 0], - dr_tf_wp / 2, - wwp2 / 2, - lw=0, - facecolor=winding, - ) - axis.add_patch(rect) + TF_outboard( + axis, + item, + n_tf=n_tf, + r3=r3, + r4=r4, + w=w, + facecolor=TFC_COLOUR[colour_scheme - 1], + ) iefrf = mfile_data.data["iefrf"].get_scan(scan) if (iefrf == 5) or (iefrf == 8): @@ -1082,6 +1120,9 @@ def plot_vacuum_vessel(axis, mfile_data, scan): mfile_data --> MFILE data object scan --> scan number to use """ + args = parse_args(None) + colour_scheme = int(args.colour) + i_single_null = mfile_data.data["i_single_null"].get_scan(scan) triang_95 = mfile_data.data["triang95"].get_scan(scan) @@ -1128,7 +1169,7 @@ def plot_vacuum_vessel(axis, mfile_data, scan): axis.fill( vvg_single_null.rs, vvg_single_null.zs, - color=vessel, + color=VESSEL_COLOUR[colour_scheme - 1], ) if i_single_null == 0: @@ -1146,7 +1187,7 @@ def plot_vacuum_vessel(axis, mfile_data, scan): axis.fill( vvg_double_null.rs, vvg_double_null.zs, - color=vessel, + color=VESSEL_COLOUR[colour_scheme - 1], ) @@ -1158,6 +1199,9 @@ def plot_shield(axis, mfile_data, scan): mfile_data --> MFILE data object scan --> scan number to use """ + args = parse_args(None) + colour_scheme = int(args.colour) + i_single_null = mfile_data.data["i_single_null"].get_scan(scan) triang_95 = mfile_data.data["triang95"].get_scan(scan) @@ -1192,7 +1236,9 @@ def plot_shield(axis, mfile_data, scan): cumulative_lower=cumulative_lower, ) axis.plot(sg_single_null.rs, sg_single_null.zs, color="black", lw=thin) - axis.fill(sg_single_null.rs, sg_single_null.zs, color=shield) + axis.fill( + sg_single_null.rs, sg_single_null.zs, color=SHIELD_COLOUR[colour_scheme - 1] + ) if i_single_null == 0: sg_double_null = shield_geometry_double_null( @@ -1204,7 +1250,9 @@ def plot_shield(axis, mfile_data, scan): triang=triang_95, ) axis.plot(sg_double_null.rs, sg_double_null.zs, color="black", lw=thin) - axis.fill(sg_double_null.rs, sg_double_null.zs, color=shield) + axis.fill( + sg_double_null.rs, sg_double_null.zs, color=SHIELD_COLOUR[colour_scheme - 1] + ) def plot_blanket(axis, mfile_data, scan) -> None: @@ -1216,11 +1264,19 @@ def plot_blanket(axis, mfile_data, scan) -> None: scan --> scan number to use """ + + args = parse_args(None) + colour_scheme = int(args.colour) + # Single null: Draw top half from output # Double null: Reflect bottom half to top i_single_null = mfile_data.data["i_single_null"].get_scan(scan) triang_95 = mfile_data.data["triang95"].get_scan(scan) - blnktth = mfile_data.data["blnktth"].get_scan(scan) + if int(i_single_null) == 1: + blnktth = mfile_data.data["blnktth"].get_scan(scan) + else: + blnktth = 0.0 + c_shldith = cumulative_radial_build("shldith", mfile_data, scan) c_blnkoth = cumulative_radial_build("blnkoth", mfile_data, scan) @@ -1267,7 +1323,11 @@ def plot_blanket(axis, mfile_data, scan) -> None: lw=thin, ) - axis.fill(bg_single_null.rs, bg_single_null.zs, color=blanket) + axis.fill( + bg_single_null.rs, + bg_single_null.zs, + color=BLANKET_COLOUR[colour_scheme - 1], + ) if i_single_null == 0: bg_double_null = blanket_geometry_double_null( @@ -1282,8 +1342,16 @@ def plot_blanket(axis, mfile_data, scan) -> None: # Plot blanket axis.plot(bg_double_null.rs[0], bg_double_null.zs[0], color="black", lw=thin) axis.plot(bg_double_null.rs[1], bg_double_null.zs[1], color="black", lw=thin) - axis.fill(bg_double_null.rs[0], bg_double_null.zs[0], color=blanket) - axis.fill(bg_double_null.rs[1], bg_double_null.zs[1], color=blanket) + axis.fill( + bg_double_null.rs[0], + bg_double_null.zs[0], + color=BLANKET_COLOUR[colour_scheme - 1], + ) + axis.fill( + bg_double_null.rs[1], + bg_double_null.zs[1], + color=BLANKET_COLOUR[colour_scheme - 1], + ) def plot_firstwall(axis, mfile_data, scan): @@ -1295,10 +1363,17 @@ def plot_firstwall(axis, mfile_data, scan): scan --> scan number to use """ + args = parse_args(None) + colour_scheme = int(args.colour) + i_single_null = mfile_data.data["i_single_null"].get_scan(scan) triang_95 = mfile_data.data["triang95"].get_scan(scan) - blnktth = mfile_data.data["blnktth"].get_scan(scan) - tfwvt = mfile_data.data["fwtth"].get_scan(scan) + if int(i_single_null) == 1: + blnktth = mfile_data.data["blnktth"].get_scan(scan) + tfwvt = mfile_data.data["fwtth"].get_scan(scan) + else: + blnktth = tfwvt = 0.0 + c_blnkith = cumulative_radial_build("blnkith", mfile_data, scan) c_fwoth = cumulative_radial_build("fwoth", mfile_data, scan) @@ -1341,7 +1416,11 @@ def plot_firstwall(axis, mfile_data, scan): # Plot first wall axis.plot(fwg_single_null.rs, fwg_single_null.zs, color="black", lw=thin) - axis.fill(fwg_single_null.rs, fwg_single_null.zs, color=firstwall) + axis.fill( + fwg_single_null.rs, + fwg_single_null.zs, + color=FIRSTWALL_COLOUR[colour_scheme - 1], + ) if i_single_null == 0: fwg_double_null = first_wall_geometry_double_null( @@ -1357,8 +1436,16 @@ def plot_firstwall(axis, mfile_data, scan): # Plot blanket axis.plot(fwg_double_null.rs[0], fwg_double_null.zs[0], color="black", lw=thin) axis.plot(fwg_double_null.rs[1], fwg_double_null.zs[1], color="black", lw=thin) - axis.fill(fwg_double_null.rs[0], fwg_double_null.zs[0], color=blanket) - axis.fill(fwg_double_null.rs[1], fwg_double_null.zs[1], color=blanket) + axis.fill( + fwg_double_null.rs[0], + fwg_double_null.zs[0], + color=BLANKET_COLOUR[colour_scheme - 1], + ) + axis.fill( + fwg_double_null.rs[1], + fwg_double_null.zs[1], + color=BLANKET_COLOUR[colour_scheme - 1], + ) def angle_check(angle1, angle2): @@ -1383,6 +1470,9 @@ def plot_tf_coils(axis, mfile_data, scan): scan --> scan number to use """ + args = parse_args(None) + colour_scheme = int(args.colour) + # Arc points # MDK Only 4 points now required for elliptical arcs x1 = mfile_data.data["xarc(1)"].get_scan(scan) @@ -1423,7 +1513,7 @@ def plot_tf_coils(axis, mfile_data, scan): xy=(rec.anchor_x, rec.anchor_z), width=rec.width, height=rec.height, - facecolor=tfc, + facecolor=TFC_COLOUR[colour_scheme - 1], ) ) @@ -1445,7 +1535,9 @@ def plot_tf_coils(axis, mfile_data, scan): for vert in verts: path = Path(vert, closed=True) - patch = patches.PathPatch(path, facecolor=tfc, lw=0) + patch = patches.PathPatch( + path, facecolor=TFC_COLOUR[colour_scheme - 1], lw=0 + ) axis.add_patch(patch) for rec in rects: @@ -1454,7 +1546,7 @@ def plot_tf_coils(axis, mfile_data, scan): xy=(rec.anchor_x, rec.anchor_z), width=rec.width, height=rec.height, - facecolor=tfc, + facecolor=TFC_COLOUR[colour_scheme - 1], ) ) @@ -1496,8 +1588,10 @@ def plot_tf_wp(axis, mfile_data, scan: int) -> None: jwptf = round(mfile_data.data["jwptf"].get_scan(scan)) / 1e6 tf_thickness = mfile_data.data["tfcth"].get_scan(scan) integer_turns = mfile_data.data["i_tf_turns_integer"].get_scan(scan) - turn_layers = mfile_data.data["n_layer"].get_scan(scan) - turn_pancakes = mfile_data.data["n_pancake"].get_scan(scan) + + if integer_turns == 1: + turn_layers = mfile_data.data["n_layer"].get_scan(scan) + turn_pancakes = mfile_data.data["n_pancake"].get_scan(scan) # Superconducting coil check if cond_type == 1: @@ -1951,6 +2045,8 @@ def plot_pf_coils(axis, mfile_data, scan): mfile_data --> MFILE.DAT object scan --> scan number to use """ + args = parse_args(None) + colour_scheme = int(args.colour) coils_r = [] coils_z = [] @@ -1962,7 +2058,7 @@ def plot_pf_coils(axis, mfile_data, scan): ohcth = mfile_data.data["ohcth"].get_scan(scan) ohdz = mfile_data.data["ohdz"].get_scan(scan) - # Number of coils (1 is OH coil) + # Number of coils, both PF and CS number_of_coils = 0 for item in mfile_data.data.keys(): if "rpf[" in item: @@ -1977,9 +2073,9 @@ def plot_pf_coils(axis, mfile_data, scan): # If Central Solenoid present, ignore last entry in for loop # The last entry will be the OH coil in this case if iohcl == 0: - noc = number_of_coils + 1 - else: noc = number_of_coils + else: + noc = number_of_coils - 1 for coil in range(0, noc): coils_r.append(mfile_data.data["rpf[{:01}]".format(coil)].get_scan(scan)) @@ -2002,18 +2098,18 @@ def plot_pf_coils(axis, mfile_data, scan): axis.plot(r_points[i], z_points[i], color="black") axis.text( coils_r[i], - coils_z[i], + coils_z[i] - 0.1, coil_text[i], ha="center", va="center", - fontsize=5 * abs((coils_dr[i] * coils_dz[i])), + fontsize=4.85 * abs((coils_dr[i] * coils_dz[i])), ) axis.add_patch( patches.Rectangle( xy=(central_coil.anchor_x, central_coil.anchor_z), width=central_coil.width, height=central_coil.height, - facecolor="pink", + facecolor=SOLENOID_COLOUR[colour_scheme - 1], ) ) @@ -2028,7 +2124,7 @@ def plot_info(axis, data, mfile_data, scan): scan --> scan number to use """ - eqpos = 0.7 + eqpos = 0.75 for i in range(len(data)): colorflag = "black" if mfile_data.data[data[i][0]].exists: @@ -2137,6 +2233,12 @@ def plot_header(axis, mfile_data, scan): ), ] + axis.text(-0.05, 4.0, "Colour Legend:", ha="left", va="center") + axis.text( + 0.0, 3.0, "ITR --> Iteration variable", color="red", ha="left", va="center" + ) + axis.text(0.0, 2.0, "OP --> Output variable", color="blue", ha="left", va="center") + H = mfile_data.data["fimp(01)"].get_scan(scan) He = mfile_data.data["fimp(02)"].get_scan(scan) Be = mfile_data.data["fimp(03)"].get_scan(scan) @@ -2210,10 +2312,6 @@ def plot_header(axis, mfile_data, scan): ) data2 = data2 + data - axis.text(-0.05, -12.6, "Colour Legend:", ha="left", va="center") - axis.text(0.0, -13.4, "ITR", color="red", ha="left", va="center") - axis.text(0.0, -14.2, "OP", color="blue", ha="left", va="center") - plot_info(axis, data2, mfile_data, scan) @@ -2254,8 +2352,8 @@ def plot_geometry_info(axis, mfile_data, scan): ("sarea", "Surface area", "m$^2$"), ("vol", "Plasma volume", "m$^3$"), ("n_tf", "No. of TF coils", ""), - (in_blanket_thk, "inboard blanket+shield", "m"), - (out_blanket_thk, "ouboard blanket+shield", "m"), + (in_blanket_thk, "Inboard blanket+shield", "m"), + (out_blanket_thk, "Outboard blanket+shield", "m"), ("powfmw", "Fusion power", "MW"), ("bigq", "$Q$", ""), ("", "", ""), @@ -2415,7 +2513,6 @@ def plot_magnetics_info(axis, mfile_data, scan): sig_cond = 1.0e-6 * mfile_data.data[ "sig_tf_tresca_max({})".format(i_tf_bucking + 1) ].get_scan(scan) - alstrtf = 1.0e-6 * mfile_data.data["alstrtf"].get_scan(scan) if i_tf_sup == 1: data = [ @@ -2433,7 +2530,6 @@ def plot_magnetics_info(axis, mfile_data, scan): ("tmargoh", "CS Temperature margin", "K"), (sig_cond, "TF Cond max TRESCA stress", "MPa"), (sig_case, "TF Case max TRESCA stress", "MPa"), - (alstrtf, "Allowable stress", "Pa"), ("whttf/n_tf", "Mass per TF coil", "kg"), ] @@ -2459,7 +2555,6 @@ def plot_magnetics_info(axis, mfile_data, scan): ("#TF coil forces/stresses", "", ""), (sig_cond, "TF conductor max TRESCA stress", "MPa"), (sig_case, "TF bucking max TRESCA stress", "MPa"), - (alstrtf, "conductor Allowable stress", "Pa"), (fcoolcp, "CP cooling fraction", "%"), ("vcool", "Maximum coolant flow speed", "m.s$^{-1}$"), (prescp, "CP Resisitive heating", "MW"), @@ -2530,7 +2625,7 @@ def plot_power_info(axis, mfile_data, scan): ped_height, ped_pos, ("ralpne", "Helium fraction", ""), - ("pinnerzoneradmw", "inner zone radiation", "MW"), + ("pinnerzoneradmw", "Inner zone radiation", "MW"), ("pradmw", "Total radiation in LCFS", "MW"), ("pnucblkt", "Nuclear heating in blanket", "MW"), ("pnucshld", "Nuclear heating in shield", "MW"), @@ -2624,10 +2719,12 @@ def plot_current_drive_info(axis, mfile_data, scan): axis.set_autoscalex_on(False) pinjie = mfile_data.data["pinjmw"].get_scan(scan) - pinjmwfix = mfile_data.data["pinjmwfix"].get_scan(scan) pdivt = mfile_data.data["pdivt"].get_scan(scan) pdivr = pdivt / mfile_data.data["rmajor"].get_scan(scan) + if mfile_data.data["iefrffix"].get_scan(scan) != 0: + pinjmwfix = mfile_data.data["pinjmwfix"].get_scan(scan) + pdivnr = ( 1.0e20 * mfile_data.data["pdivt"].get_scan(scan) @@ -2658,7 +2755,7 @@ def plot_current_drive_info(axis, mfile_data, scan): ( "gamcd", "Normalised current drive efficiency", - "(10$^{19}$ A/(Wm$^{2}$))", + "(10$^{20}$ A/(Wm$^{2}$))", ), (pdivr, r"$\frac{P_{\mathrm{div}}}{R_{0}}$", "MW m$^{-1}$"), ( @@ -2669,7 +2766,8 @@ def plot_current_drive_info(axis, mfile_data, scan): (flh, r"$\frac{P_{\mathrm{div}}}{P_{\mathrm{LH}}}$", ""), (hstar, "H* (non-rad. corr.)", ""), ] - if "iefrffix" in mfile_data.data.keys(): + # iefrffix is now always in the MFILE with = 0 meaning no fixed heating + if mfile_data.data["iefrffix"].get_scan(scan) != 0: data.insert( 1, ("pinjmwfix", f"{secondary_heating} secondary auxiliary power", "MW") ) @@ -2713,7 +2811,7 @@ def plot_current_drive_info(axis, mfile_data, scan): ( "gamcd", "Normalised current drive efficiency", - "(10$^{19}$ A/(Wm$^{2}$))", + "(10$^{20}$ A/(Wm$^{2}$))", ), (pdivr, r"$\frac{P_{\mathrm{div}}}{R_{0}}$", "MW m$^{-1}$"), ( @@ -2742,7 +2840,7 @@ def plot_current_drive_info(axis, mfile_data, scan): ( "gamcd", "Normalised current drive efficiency", - "(10$^{19}$ A/(Wm$^{2}$))", + "(10$^{20}$ A/(Wm$^{2}$))", ), (pdivr, r"$\frac{P_{\mathrm{div}}}{R_{0}}$", "MW m$^{-1}$"), ( @@ -2771,7 +2869,7 @@ def plot_current_drive_info(axis, mfile_data, scan): ( "gamcd", "Normalised current drive efficiency", - "(10$^{19}$ A/(Wm$^{2}$))", + "(10$^{20}$ A/(Wm$^{2}$))", ), (pdivr, r"$\frac{P_{\mathrm{div}}}{R_{0}}$", "MW m$^{-1}$"), ( @@ -2847,7 +2945,7 @@ def main_plot( # Plot color key plot_3 = fig2.add_subplot(241) - color_key(plot_3) + color_key(plot_3, m_file_data, scan) # Plot density profiles plot_4 = fig2.add_subplot(234) # , aspect= 0.05) @@ -2941,288 +3039,38 @@ def save_plots(m_file_data, scan): fig.savefig("tprofile.svg", format="svg", dpi=1200) -def test(f): - """Test Function +def main(args=None): + # TODO The use of globals here isn't ideal, but is required to get main() + # working with minimal changes. Should be converted to class structure + args = parse_args(args) - :param f: filename to test - """ + # read MFILE + if args.f != "": + m_file = mf.MFile(args.f) + else: + m_file = mf.MFile("MFILE.DAT") - try: - # read MFILE - m_file = mf.MFile(filename=f) + if args.n: + scan = args.n + else: scan = -1 - # Check for Copper magnets - if "i_tf_sup" in m_file.data.keys(): - i_tf_sup = int(m_file.data["i_tf_sup"].get_scan(scan)) - else: - i_tf_sup = int(1) + if args.DEMO_ranges: + demo_ranges = True + else: + demo_ranges = False - # Check integer turns - if "i_tf_turns_integer" in m_file.data.keys(): - i_tf_turns_integer = int(m_file.data["i_tf_turns_integer"].get_scan(scan)) - else: - i_tf_turns_integer = int(0) + # Check for Copper magnets + if "i_tf_sup" in m_file.data.keys(): + i_tf_sup = int(m_file.data["i_tf_sup"].get_scan(scan)) + else: + i_tf_sup = int(1) - global bore - bore = m_file.data["bore"].get_scan(scan) - global ohcth - ohcth = m_file.data["ohcth"].get_scan(scan) - global gapoh - gapoh = m_file.data["gapoh"].get_scan(scan) - global tfcth - tfcth = m_file.data["tfcth"].get_scan(scan) - global gapds - gapds = m_file.data["gapds"].get_scan(scan) - global d_vv_in - d_vv_in = m_file.data["d_vv_in"].get_scan(scan) - global shldith - shldith = m_file.data["shldith"].get_scan(scan) - global blnkith - blnkith = m_file.data["blnkith"].get_scan(scan) - global fwith - fwith = m_file.data["fwith"].get_scan(scan) - global scrapli - scrapli = m_file.data["scrapli"].get_scan(scan) - global rmajor - rmajor = m_file.data["rmajor"].get_scan(scan) - global rminor - rminor = m_file.data["rminor"].get_scan(scan) - global scraplo - scraplo = m_file.data["scraplo"].get_scan(scan) - global fwoth - fwoth = m_file.data["fwoth"].get_scan(scan) - global blnkoth - blnkoth = m_file.data["blnkoth"].get_scan(scan) - global shldoth - shldoth = m_file.data["shldoth"].get_scan(scan) - global d_vv_out - d_vv_out = m_file.data["d_vv_out"].get_scan(scan) - global gapsto - gapsto = m_file.data["gapsto"].get_scan(scan) - global tfthko - tfthko = m_file.data["tfthko"].get_scan(scan) - global rdewex - rdewex = m_file.data["rdewex"].get_scan(scan) - global ddwex - ddwex = m_file.data["ddwex"].get_scan(scan) - global zdewex - zdewex = m_file.data["zdewex"].get_scan(scan) - global n_tf - n_tf = m_file.data["n_tf"].get_scan(scan) - - if i_tf_sup == 1: - global wwp1 - wwp1 = m_file.data["wwp1"].get_scan(scan) - if i_tf_turns_integer == 0: - global wwp2 - wwp2 = m_file.data["wwp2"].get_scan(scan) - global dr_tf_wp - dr_tf_wp = m_file.data["dr_tf_wp"].get_scan(scan) - global tinstf - tinstf = m_file.data["tinstf"].get_scan(scan) - global thkcas - thkcas = m_file.data["thkcas"].get_scan(scan) - - # To be re-inergrated to resistives when in-plane stresses is integrated - global casthi - casthi = m_file.data["casthi"].get_scan(scan) - - global nbshield - nbshield = m_file.data["nbshield"].get_scan(scan) - global rtanbeam - rtanbeam = m_file.data["rtanbeam"].get_scan(scan) - global rtanmax - rtanmax = m_file.data["rtanmax"].get_scan(scan) - global beamwd - beamwd = m_file.data["beamwd"].get_scan(scan) - # # Pedestal profile parameters - global ipedestal - ipedestal = m_file.data["ipedestal"].get_scan(scan) - global neped - neped = m_file.data["neped"].get_scan(scan) - global nesep - nesep = m_file.data["nesep"].get_scan(scan) - global rhopedn - rhopedn = m_file.data["rhopedn"].get_scan(scan) - global rhopedt - rhopedt = m_file.data["rhopedt"].get_scan(scan) - global tbeta - tbeta = m_file.data["tbeta"].get_scan(scan) - global teped - teped = m_file.data["teped"].get_scan(scan) - global tesep - tesep = m_file.data["tesep"].get_scan(scan) - global alphan - alphan = m_file.data["alphan"].get_scan(scan) - global alphat - alphat = m_file.data["alphat"].get_scan(scan) - global ne0 - ne0 = m_file.data["ne0"].get_scan(scan) - global te0 - te0 = m_file.data["te0"].get_scan(scan) - # # Plasma - global triang - triang = m_file.data["triang95"].get_scan(scan) - global alphaj - alphaj = m_file.data["alphaj"].get_scan(scan) - global q0 - q0 = m_file.data["q0"].get_scan(scan) - global q95 - q95 = m_file.data["q95"].get_scan(scan) - - # Build the dictionaries of radial and vertical build values and cumulative - # values - global radial - radial = dict() - global cumulative_radial - cumulative_radial = dict() - subtotal = 0 - for item in RADIAL_BUILD: - if item == "rminori" or item == "rminoro": - build = m_file.data["rminor"].get_scan(scan) - elif item == "vvblgapi" or item == "vvblgapo": - build = m_file.data["vvblgap"].get_scan(scan) - elif "d_vv_in" in item: - build = m_file.data["d_vv_in"].get_scan(scan) - elif "d_vv_out" in item: - build = m_file.data["d_vv_out"].get_scan(scan) - else: - build = m_file.data[item].get_scan(scan) - - radial[item] = build - subtotal += build - cumulative_radial[item] = subtotal - - global upper - upper = dict() - global cumulative_upper - cumulative_upper = dict() - subtotal = 0 - for item in vertical_upper: - upper[item] = m_file.data[item].get_scan(scan) - subtotal += upper[item] - cumulative_upper[item] = subtotal - - global lower - lower = dict() - global cumulative_lower - cumulative_lower = dict() - subtotal = 0 - for item in vertical_lower: - lower[item] = m_file.data[item].get_scan(scan) - subtotal -= lower[item] - cumulative_lower[item] = subtotal - - colour_dict = {} - colour_dict["ohcth"] = solenoid - colour_dict["tfcth"] = tfc - colour_dict["thshield_ib"] = thermal_shield - colour_dict["thshield_ob"] = thermal_shield - colour_dict["thshield_vb"] = thermal_shield - colour_dict["d_vv_in"] = vessel - colour_dict["d_vv_out"] = vessel - colour_dict["d_vv_top"] = vessel - colour_dict["d_vv_bot"] = vessel - colour_dict["shldith"] = shield - colour_dict["blnkith"] = blanket - colour_dict["rminor"] = plasma - colour_dict["fwith"] = firstwall - colour_dict["fwoth"] = firstwall - - # create main plot - page1 = plt.figure(figsize=(12, 9), dpi=80) - page2 = plt.figure(figsize=(12, 9), dpi=80) - page3 = plt.figure(figsize=(12, 9), dpi=80) - - # run main_plot - main_plot(page1, page2, page3, m_file, scan=scan) - - # with bpdf.PdfPages(args.o) as pdf: - # with bpdf.PdfPages("ref.SUMMARY.pdf") as pdf: - # pdf.savefig(page1) - # pdf.savefig(page2) - # plt.show() - - # # tidy up to avoid memory issues - # del page1 - # del page2 - plt.close(page1) - plt.close(page2) - - return True - except Exception: - print("FTest failure for file : {}".format(f)) - return False - - -def parse_args(args): - """Parse supplied arguments. - - :param args: arguments to parse - :type args: list, None - :return: parsed arguments - :rtype: Namespace - """ - # Setup command line arguments - parser = argparse.ArgumentParser( - description="Produces a two page summary of the PROCESS MFILE output, using the MFILE. " - "For info please see https://github.com/ukaea/PROCESS?tab=readme-ov-file#contacts " - ) - - parser.add_argument( - "-f", - metavar="FILENAME", - type=str, - default="", - help="specify input/output file path", - ) - parser.add_argument("-s", "--show", help="show plot", action="store_true") - - parser.add_argument("-n", type=int, help="Which scan to plot?") - - parser.add_argument( - "-d", - "--DEMO_ranges", - help="Uses the DEMO dimensions as ranges for all graphics", - action="store_true", - ) - - return parser.parse_args(args) - - -def main(args=None): - # TODO The use of globals here isn't ideal, but is required to get main() - # working with minimal changes. Should be converted to class structure - args = parse_args(args) - - # read MFILE - if args.f != "": - m_file = mf.MFile(args.f) - else: - m_file = mf.MFile("MFILE.DAT") - - if args.n: - scan = args.n - else: - scan = -1 - - if args.DEMO_ranges: - demo_ranges = True - else: - demo_ranges = False - - # Check for Copper magnets - if "i_tf_sup" in m_file.data.keys(): - i_tf_sup = int(m_file.data["i_tf_sup"].get_scan(scan)) - else: - i_tf_sup = int(1) - - # Check integer turns - if "i_tf_turns_integer" in m_file.data.keys(): - i_tf_turns_integer = int(m_file.data["i_tf_turns_integer"].get_scan(scan)) - else: - i_tf_turns_integer = int(0) + # Check WP configuration + if "i_tf_wp_geom" in m_file.data.keys(): + i_tf_wp_geom = int(m_file.data["i_tf_wp_geom"].get_scan(scan)) + else: + i_tf_wp_geom = int(0) global bore global ohcth @@ -3280,7 +3128,7 @@ def main(args=None): n_tf = m_file.data["n_tf"].get_scan(scan) if i_tf_sup == 1: # If superconducting magnets wwp1 = m_file.data["wwp1"].get_scan(scan) - if i_tf_turns_integer == 0: + if i_tf_wp_geom == 1: wwp2 = m_file.data["wwp2"].get_scan(scan) dr_tf_wp = m_file.data["dr_tf_wp"].get_scan(scan) tinstf = m_file.data["tinstf"].get_scan(scan) @@ -3294,10 +3142,17 @@ def main(args=None): global rtanmax global beamwd - nbshield = m_file.data["nbshield"].get_scan(scan) - rtanbeam = m_file.data["rtanbeam"].get_scan(scan) - rtanmax = m_file.data["rtanmax"].get_scan(scan) - beamwd = m_file.data["beamwd"].get_scan(scan) + iefrf = int(m_file.data["iefrf"].get_scan(scan)) + iefrffix = int(m_file.data["iefrffix"].get_scan(scan)) + + if (iefrf in [5, 8]) or (iefrffix in [5, 8]): + + nbshield = m_file.data["nbshield"].get_scan(scan) + rtanbeam = m_file.data["rtanbeam"].get_scan(scan) + rtanmax = m_file.data["rtanmax"].get_scan(scan) + beamwd = m_file.data["beamwd"].get_scan(scan) + else: + nbshield = rtanbeam = rtanmax = beamwd = 0.0 # Pedestal profile parameters global ipedestal @@ -3331,13 +3186,11 @@ def main(args=None): global alphaj global q0 global q95 - global kallenbach_switch triang = m_file.data["triang95"].get_scan(scan) alphaj = m_file.data["alphaj"].get_scan(scan) q0 = m_file.data["q0"].get_scan(scan) q95 = m_file.data["q95"].get_scan(scan) - kallenbach_switch = m_file.data["kallenbach_switch"].get_scan(scan) # Radial position -- 0 # Electron density -- 1 @@ -3365,6 +3218,34 @@ def main(args=None): vol = m_file.data["vol"].get_scan(scan) # Build the dictionaries of radial and vertical build values and cumulative values + global vertical_upper + if int(m_file.data["i_single_null"].get_scan(scan)) == 0: + vertical_upper = [ + "rminor*kappa", + "vgaptop", + "divfix", + "shldtth", + "d_vv_top", + "vgap2", + "thshield_vb", + "tftsgap", + "tfcth", + ] + else: + vertical_upper = [ + "rminor*kappa", + "vgaptop", + "fwtth", + "blnktth", + "vvblgap", + "shldtth", + "d_vv_top", + "vgap2", + "thshield_vb", + "tftsgap", + "tfcth", + ] + radial = {} cumulative_radial = {} subtotal = 0 @@ -3404,22 +3285,6 @@ def main(args=None): subtotal -= lower[item] cumulative_lower[item] = subtotal - colour_dict = {} - colour_dict["ohcth"] = solenoid - colour_dict["tfcth"] = tfc - colour_dict["thshield_ib"] = thermal_shield - colour_dict["thshield_ob"] = thermal_shield - colour_dict["thshield_vb"] = thermal_shield - colour_dict["d_vv_in"] = vessel - colour_dict["d_vv_out"] = vessel - colour_dict["d_vv_top"] = vessel - colour_dict["d_vv_bot"] = vessel - colour_dict["shldith"] = shield - colour_dict["blnkith"] = blanket - colour_dict["rminor"] = plasma - colour_dict["fwith"] = firstwall - colour_dict["fwoth"] = firstwall - # read MFILE # m_file = mf.MFile(args.f) # scan = scan @@ -3450,5 +3315,205 @@ def main(args=None): plt.close(page3) +def test(f): + """Test Function + + :param f: filename to test + """ + + try: + # read MFILE + m_file = mf.MFile(filename=f) + scan = -1 + + # Check for Copper magnets + if "i_tf_sup" in m_file.data.keys(): + i_tf_sup = int(m_file.data["i_tf_sup"].get_scan(scan)) + else: + i_tf_sup = int(1) + + # Check integer turns + if "i_tf_turns_integer" in m_file.data.keys(): + i_tf_turns_integer = int(m_file.data["i_tf_turns_integer"].get_scan(scan)) + else: + i_tf_turns_integer = int(0) + + global bore + bore = m_file.data["bore"].get_scan(scan) + global ohcth + ohcth = m_file.data["ohcth"].get_scan(scan) + global gapoh + gapoh = m_file.data["gapoh"].get_scan(scan) + global tfcth + tfcth = m_file.data["tfcth"].get_scan(scan) + global gapds + gapds = m_file.data["gapds"].get_scan(scan) + global d_vv_in + d_vv_in = m_file.data["d_vv_in"].get_scan(scan) + global shldith + shldith = m_file.data["shldith"].get_scan(scan) + global blnkith + blnkith = m_file.data["blnkith"].get_scan(scan) + global fwith + fwith = m_file.data["fwith"].get_scan(scan) + global scrapli + scrapli = m_file.data["scrapli"].get_scan(scan) + global rmajor + rmajor = m_file.data["rmajor"].get_scan(scan) + global rminor + rminor = m_file.data["rminor"].get_scan(scan) + global scraplo + scraplo = m_file.data["scraplo"].get_scan(scan) + global fwoth + fwoth = m_file.data["fwoth"].get_scan(scan) + global blnkoth + blnkoth = m_file.data["blnkoth"].get_scan(scan) + global shldoth + shldoth = m_file.data["shldoth"].get_scan(scan) + global d_vv_out + d_vv_out = m_file.data["d_vv_out"].get_scan(scan) + global gapsto + gapsto = m_file.data["gapsto"].get_scan(scan) + global tfthko + tfthko = m_file.data["tfthko"].get_scan(scan) + global rdewex + rdewex = m_file.data["rdewex"].get_scan(scan) + global ddwex + ddwex = m_file.data["ddwex"].get_scan(scan) + global zdewex + zdewex = m_file.data["zdewex"].get_scan(scan) + global n_tf + n_tf = m_file.data["n_tf"].get_scan(scan) + + if i_tf_sup == 1: + global wwp1 + wwp1 = m_file.data["wwp1"].get_scan(scan) + if i_tf_turns_integer == 0: + global wwp2 + wwp2 = m_file.data["wwp2"].get_scan(scan) + global dr_tf_wp + dr_tf_wp = m_file.data["dr_tf_wp"].get_scan(scan) + global tinstf + tinstf = m_file.data["tinstf"].get_scan(scan) + global thkcas + thkcas = m_file.data["thkcas"].get_scan(scan) + + # To be re-inergrated to resistives when in-plane stresses is integrated + global casthi + casthi = m_file.data["casthi"].get_scan(scan) + + global nbshield + nbshield = m_file.data["nbshield"].get_scan(scan) + global rtanbeam + rtanbeam = m_file.data["rtanbeam"].get_scan(scan) + global rtanmax + rtanmax = m_file.data["rtanmax"].get_scan(scan) + global beamwd + beamwd = m_file.data["beamwd"].get_scan(scan) + # # Pedestal profile parameters + global ipedestal + ipedestal = m_file.data["ipedestal"].get_scan(scan) + global neped + neped = m_file.data["neped"].get_scan(scan) + global nesep + nesep = m_file.data["nesep"].get_scan(scan) + global rhopedn + rhopedn = m_file.data["rhopedn"].get_scan(scan) + global rhopedt + rhopedt = m_file.data["rhopedt"].get_scan(scan) + global tbeta + tbeta = m_file.data["tbeta"].get_scan(scan) + global teped + teped = m_file.data["teped"].get_scan(scan) + global tesep + tesep = m_file.data["tesep"].get_scan(scan) + global alphan + alphan = m_file.data["alphan"].get_scan(scan) + global alphat + alphat = m_file.data["alphat"].get_scan(scan) + global ne0 + ne0 = m_file.data["ne0"].get_scan(scan) + global te0 + te0 = m_file.data["te0"].get_scan(scan) + # # Plasma + global triang + triang = m_file.data["triang95"].get_scan(scan) + global alphaj + alphaj = m_file.data["alphaj"].get_scan(scan) + global q0 + q0 = m_file.data["q0"].get_scan(scan) + global q95 + q95 = m_file.data["q95"].get_scan(scan) + + # Build the dictionaries of radial and vertical build values and cumulative + # values + + global radial + radial = dict() + global cumulative_radial + cumulative_radial = dict() + subtotal = 0 + for item in RADIAL_BUILD: + if item == "rminori" or item == "rminoro": + build = m_file.data["rminor"].get_scan(scan) + elif item == "vvblgapi" or item == "vvblgapo": + build = m_file.data["vvblgap"].get_scan(scan) + elif "d_vv_in" in item: + build = m_file.data["d_vv_in"].get_scan(scan) + elif "d_vv_out" in item: + build = m_file.data["d_vv_out"].get_scan(scan) + else: + build = m_file.data[item].get_scan(scan) + + radial[item] = build + subtotal += build + cumulative_radial[item] = subtotal + + global upper + upper = dict() + global cumulative_upper + cumulative_upper = dict() + subtotal = 0 + for item in vertical_upper: + upper[item] = m_file.data[item].get_scan(scan) + subtotal += upper[item] + cumulative_upper[item] = subtotal + + global lower + lower = dict() + global cumulative_lower + cumulative_lower = dict() + subtotal = 0 + for item in vertical_lower: + lower[item] = m_file.data[item].get_scan(scan) + subtotal -= lower[item] + cumulative_lower[item] = subtotal + + # create main plot + page1 = plt.figure(figsize=(12, 9), dpi=80) + page2 = plt.figure(figsize=(12, 9), dpi=80) + page3 = plt.figure(figsize=(12, 9), dpi=80) + + # run main_plot + main_plot(page1, page2, page3, m_file, scan=scan) + + # with bpdf.PdfPages(args.o) as pdf: + # with bpdf.PdfPages("ref.SUMMARY.pdf") as pdf: + # pdf.savefig(page1) + # pdf.savefig(page2) + # plt.show() + + # # tidy up to avoid memory issues + # del page1 + # del page2 + plt.close(page1) + plt.close(page2) + + return True + except Exception: + print("FTest failure for file : {}".format(f)) + return False + + if __name__ == "__main__": main() diff --git a/process/sctfcoil.py b/process/sctfcoil.py index f2099fed45..521291ab3e 100644 --- a/process/sctfcoil.py +++ b/process/sctfcoil.py @@ -4604,12 +4604,11 @@ def outtf(self, peaktfflag): build_variables.r_tf_inboard_out, "OP ", ) - po.ovarre( - constants.mfile, + po.ovarin( + self.outfile, "WP shape selection switch", "(i_tf_wp_geom)", tfcoil_variables.i_tf_wp_geom, - "OP ", ) po.ovarre( constants.mfile, @@ -4626,7 +4625,7 @@ def outtf(self, peaktfflag): build_variables.r_tf_outboard_mid, "OP ", ) - po.ovarre( + po.ovarin( self.outfile, "Outboard leg nose case type", "(i_tf_case_geom)",