d0fus 1.0.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
d0fus-1.0.2/D0FUS.py ADDED
@@ -0,0 +1,431 @@
1
+ """
2
+
3
+ D0FUS - Design 0-dimensional for FUsion Systems
4
+ Author: Auclair Timothe
5
+
6
+ This software is governed by the CeCILL-C license under French law.
7
+ See LICENSE file or https://cecill.info/licences/Licence_CeCILL-C_V1-en.html
8
+ Copyright holders : Commissariat à l’Energie Atomique et aux Energies Alternatives (CEA), France
9
+ The terms and conditions of the CeCILL-C license are deemed to be accepted
10
+ upon downloading the software and/or exercising any of the rights granted under the CeCILL-C license.
11
+
12
+ """
13
+ #%% Imports
14
+ import sys
15
+ import os
16
+
17
+ # Add the path
18
+ project_root = os.path.dirname(__file__)
19
+ sys.path.insert(0, project_root)
20
+
21
+ # Import all necessary modules
22
+ from D0FUS_BIB.D0FUS_parameterization import *
23
+ from D0FUS_EXE import D0FUS_scan, D0FUS_run, D0FUS_genetic
24
+
25
+ #%% Mode detection
26
+
27
+ def detect_mode_from_input(input_file):
28
+ """
29
+ Detect if input file is for RUN, SCAN, or OPTIMIZATION mode
30
+
31
+ Returns:
32
+ tuple: ('run', 'scan', or 'optimization', additional parameters)
33
+
34
+ Raises:
35
+ ValueError: if invalid configuration
36
+ FileNotFoundError: if input file doesn't exist
37
+ """
38
+ if not os.path.exists(input_file):
39
+ raise FileNotFoundError(f"Input file not found: {input_file}")
40
+
41
+ with open(input_file, 'r', encoding='utf-8') as f:
42
+ content = f.read()
43
+
44
+ # Extract genetic algorithm parameters if present
45
+ genetic_params = {}
46
+ genetic_keywords = {
47
+ 'population_size': ('population_size', int),
48
+ 'generations': ('generations', int),
49
+ 'crossover_rate': ('crossover_rate', float),
50
+ 'mutation_rate': ('mutation_rate', float)
51
+ }
52
+
53
+ for keyword, (param_name, param_type) in genetic_keywords.items():
54
+ pattern = rf'^\s*{keyword}\s*[:=]\s*([0-9.]+)'
55
+ match = re.search(pattern, content, re.MULTILINE | re.IGNORECASE)
56
+ if match:
57
+ try:
58
+ genetic_params[param_name] = param_type(match.group(1))
59
+ except ValueError:
60
+ raise ValueError(f"Invalid value for {keyword}: {match.group(1)}")
61
+
62
+ # Find all bracket patterns: parameter = [values]
63
+ bracket_pattern = r'^\s*(\w+)\s*[:=]\s*\[([^\]]+)\]'
64
+ matches = re.findall(bracket_pattern, content, re.MULTILINE)
65
+
66
+ if not matches:
67
+ # No brackets → RUN mode
68
+ return 'run', []
69
+
70
+ # Classify each bracket parameter
71
+ scan_params = [] # [min, max, n_points]
72
+ opt_params = {} # [min, max]
73
+
74
+ for param_name, values_str in matches:
75
+ values = re.split(r'[,;]', values_str)
76
+ values = [v.strip() for v in values if v.strip()]
77
+
78
+ if len(values) == 2:
79
+ # 2 values → OPTIMIZATION parameter
80
+ try:
81
+ min_val = float(values[0])
82
+ max_val = float(values[1])
83
+ opt_params[param_name] = (min_val, max_val)
84
+ except ValueError as e:
85
+ raise ValueError(
86
+ f"\n Invalid values for parameter {param_name}: {values_str}\n"
87
+ f"Values must be numeric: [min, max]\n"
88
+ f"Error: {str(e)}"
89
+ )
90
+ elif len(values) == 3:
91
+ # 3 values → SCAN parameter
92
+ try:
93
+ min_val = float(values[0])
94
+ max_val = float(values[1])
95
+ n_points = int(float(values[2]))
96
+ scan_params.append((param_name, min_val, max_val, n_points))
97
+ except ValueError as e:
98
+ raise ValueError(
99
+ f"\n Invalid values for scan parameter {param_name}: {values_str}\n"
100
+ f"Values must be numeric: [min, max, n_points]\n"
101
+ f"Error: {str(e)}"
102
+ )
103
+ else:
104
+ raise ValueError(
105
+ f"\n Invalid bracket format for {param_name}: {values_str}\n"
106
+ f"Expected:\n"
107
+ f" - [min, max] for optimization\n"
108
+ f" - [min, max, n_points] for scan\n"
109
+ )
110
+
111
+ # Determine mode based on what we found
112
+ n_scan = len(scan_params)
113
+ n_opt = len(opt_params)
114
+
115
+ if n_opt > 0 and n_scan == 0:
116
+ # Only optimization parameters → OPTIMIZATION mode
117
+ if n_opt < 2:
118
+ param_name = list(opt_params.keys())[0]
119
+ raise ValueError(
120
+ f"\n Invalid optimization: Found only 1 parameter ({param_name}).\n"
121
+ f"\n"
122
+ f"OPTIMIZATION mode requires at least 2 parameters with [min, max].\n"
123
+ f"\n"
124
+ f"Example:\n"
125
+ f" R0 = [3, 9]\n"
126
+ f" a = [1, 3]\n"
127
+ f" Bmax = [10, 16]\n"
128
+ )
129
+ return 'optimization', (opt_params, genetic_params)
130
+
131
+ elif n_scan > 0 and n_opt == 0:
132
+ # Only scan parameters → SCAN mode
133
+ if n_scan == 1:
134
+ param_name = scan_params[0][0]
135
+ raise ValueError(
136
+ f"\n Invalid scan: Found only 1 parameter ({param_name}).\n"
137
+ f"\n"
138
+ f"SCAN mode requires exactly 2 parameters with [min, max, n_points].\n"
139
+ f"\n"
140
+ f"Example:\n"
141
+ f" R0 = [3, 9, 25]\n"
142
+ f" a = [1, 3, 25]\n"
143
+ )
144
+ elif n_scan == 2:
145
+ return 'scan', scan_params
146
+ else:
147
+ param_names = [p[0] for p in scan_params]
148
+ raise ValueError(
149
+ f"\n Invalid scan: Found {n_scan} parameters: {', '.join(param_names)}.\n"
150
+ f"\n"
151
+ f"SCAN mode requires exactly 2 parameters.\n"
152
+ )
153
+
154
+ elif n_opt > 0 and n_scan > 0:
155
+ # Mixed parameters → ERROR
156
+ raise ValueError(
157
+ f"\n Invalid input file: Mixed parameter formats detected.\n"
158
+ f" - {n_opt} optimization parameter(s) with [min, max]\n"
159
+ f" - {n_scan} scan parameter(s) with [min, max, n_points]\n"
160
+ f"\n"
161
+ f"Please choose ONE mode:\n"
162
+ f" - OPTIMIZATION: Use [min, max] for all variable parameters\n"
163
+ f" - SCAN: Use [min, max, n_points] for exactly 2 parameters\n"
164
+ f" - RUN: Remove all brackets for fixed values\n"
165
+ )
166
+
167
+ # Should not reach here
168
+ return 'run', []
169
+
170
+ #%% Main functions
171
+
172
+ def print_banner():
173
+ """Display D0FUS banner"""
174
+ banner = """
175
+ ╔═══════════════════════════════════════════════════╗
176
+ ║ ║
177
+ ║ D0FUS ║
178
+ ║ Design 0-dimensional for Fusion Systems ║
179
+ ║ ║
180
+ ╚═══════════════════════════════════════════════════╝
181
+ """
182
+ print(banner)
183
+
184
+ def print_usage():
185
+ """Print usage information"""
186
+ usage = """
187
+ Usage:
188
+ python D0FUS.py [input_file]
189
+
190
+ If no input file is provided, interactive mode will start.
191
+
192
+ Modes (detected automatically from input file format):
193
+
194
+ RUN mode: Single point calculation
195
+ No brackets in input file
196
+ Example: R0 = 9
197
+
198
+ SCAN mode: 2D parameter space exploration
199
+ Exactly 2 parameters with [min, max, n_points]
200
+ Example: R0 = [3, 9, 25]
201
+ a = [1, 3, 25]
202
+
203
+ OPTIMIZATION mode: Genetic algorithm optimization
204
+ 2+ parameters with [min, max] (no n_points)
205
+ Example: R0 = [3, 9]
206
+ a = [1, 3]
207
+ Bmax = [10, 16]
208
+
209
+ Optional genetic algorithm parameters:
210
+ population_size = 50 (default: 50)
211
+ generations = 100 (default: 100)
212
+ crossover_rate = 0.7 (default: 0.7)
213
+ mutation_rate = 0.2 (default: 0.2)
214
+
215
+ Detection rules:
216
+ • [min, max] format (2 values) → OPTIMIZATION (need 2+ parameters)
217
+ • [min, max, n] format (3 values) → SCAN (need exactly 2 parameters)
218
+ • No brackets → RUN
219
+ • Cannot mix formats in same file
220
+
221
+ For help:
222
+ python D0FUS.py --help
223
+ """
224
+ print(usage)
225
+
226
+ def list_input_files():
227
+ """List available input files in D0FUS_INPUTS directory"""
228
+ input_dir = Path(__file__).parent / 'D0FUS_INPUTS'
229
+ if not input_dir.exists():
230
+ print(f"Warning: Input directory '{input_dir}' not found.")
231
+ return []
232
+
233
+ input_files = list(input_dir.glob('*.txt'))
234
+ return sorted(input_files)
235
+
236
+ def select_input_file():
237
+ """Interactive input file selection"""
238
+ input_files = list_input_files()
239
+
240
+ if not input_files:
241
+ print("\n No input files found in D0FUS_INPUTS directory.")
242
+ print("Using default parameters for RUN mode.")
243
+ return None
244
+
245
+ print("\n" + "="*60)
246
+ print("Available input files:")
247
+ print("="*60)
248
+ for i, file in enumerate(input_files, 1):
249
+ # Try to detect mode for each file
250
+ try:
251
+ mode, params = detect_mode_from_input(str(file))
252
+ if mode == 'scan':
253
+ param_names = [p[0] for p in params]
254
+ mode_str = f"SCAN ({param_names[0]} × {param_names[1]})"
255
+ elif mode == 'optimization':
256
+ opt_params, genetic_params = params
257
+ param_names = list(opt_params.keys())
258
+ mode_str = f"GENETIC ({len(param_names)} params)"
259
+ else:
260
+ mode_str = "RUN"
261
+ print(f" {i}. {file.name:<30} [{mode_str}]")
262
+ except:
263
+ print(f" {i}. {file.name:<30} [Unknown]")
264
+ print(f" 0. Use default parameters (RUN mode)")
265
+ print("="*60)
266
+
267
+ while True:
268
+ try:
269
+ choice = input("\nSelect input file (number): ").strip()
270
+ choice = int(choice)
271
+
272
+ if choice == 0:
273
+ return None
274
+ elif 1 <= choice <= len(input_files):
275
+ return str(input_files[choice - 1])
276
+ else:
277
+ print(f"Invalid choice. Please enter a number between 0 and {len(input_files)}.")
278
+ except ValueError:
279
+ print("Invalid input. Please enter a number.")
280
+ except KeyboardInterrupt:
281
+ print("\n\nOperation cancelled by user.")
282
+ sys.exit(0)
283
+
284
+ def execute_with_mode_detection(input_file):
285
+ """
286
+ Execute D0FUS with automatic mode detection
287
+
288
+ Args:
289
+ input_file: Path to input file (or None for defaults)
290
+ """
291
+ if input_file is None:
292
+ # No input file → use defaults for RUN mode
293
+ print("\n" + "="*60)
294
+ print("Mode: RUN (default parameters)")
295
+ print("="*60 + "\n")
296
+ D0FUS_run.main(None)
297
+ return
298
+
299
+ # Detect mode from input file
300
+ try:
301
+ mode, params = detect_mode_from_input(input_file)
302
+
303
+ if mode == 'run':
304
+ # RUN mode detected
305
+ print("\n" + "="*60)
306
+ print("Mode: RUN (single point calculation)")
307
+ print(f"Input: {os.path.basename(input_file)}")
308
+ print("="*60 + "\n")
309
+ D0FUS_run.main(input_file)
310
+
311
+ elif mode == 'scan':
312
+ # SCAN mode detected
313
+ param_names = [p[0] for p in params]
314
+ print("\n" + "="*60)
315
+ print(f"Mode: SCAN (2D parameter space)")
316
+ print(f"Scan parameters: {param_names[0]} × {param_names[1]}")
317
+ print(f"Input: {os.path.basename(input_file)}")
318
+
319
+ # Display scan ranges
320
+ for param_name, min_val, max_val, n_points in params:
321
+ print(f" {param_name}: [{min_val}, {max_val}] with {n_points} points")
322
+ print("="*60 + "\n")
323
+
324
+ D0FUS_scan.main(input_file)
325
+
326
+ elif mode == 'optimization':
327
+ # OPTIMIZATION mode detected
328
+ opt_params, genetic_params = params
329
+ param_names = list(opt_params.keys())
330
+ print("\n" + "="*60)
331
+ print(f"Mode: OPTIMIZATION (genetic algorithm)")
332
+ print(f"Optimization parameters: {', '.join(param_names)}")
333
+ print(f"Input: {os.path.basename(input_file)}")
334
+
335
+ # Display optimization ranges
336
+ for param_name, (min_val, max_val) in opt_params.items():
337
+ print(f" {param_name}: [{min_val}, {max_val}]")
338
+
339
+ # Display genetic algorithm parameters
340
+ print("\nGenetic algorithm parameters:")
341
+ default_params = {
342
+ 'population_size': 50,
343
+ 'generations': 100,
344
+ 'crossover_rate': 0.7,
345
+ 'mutation_rate': 0.2
346
+ }
347
+ for param_name, default_value in default_params.items():
348
+ actual_value = genetic_params.get(param_name, default_value)
349
+ status = "" if param_name in genetic_params else " (default)"
350
+ print(f" {param_name}: {actual_value}{status}")
351
+
352
+ print("="*60 + "\n")
353
+
354
+ # Prepare parameters for genetic optimization
355
+ ga_params = {
356
+ 'population_size': genetic_params.get('population_size', 50),
357
+ 'generations': genetic_params.get('generations', 100),
358
+ 'crossover_rate': genetic_params.get('crossover_rate', 0.7),
359
+ 'mutation_rate': genetic_params.get('mutation_rate', 0.2),
360
+ 'verbose': True
361
+ }
362
+
363
+ # Run genetic optimization with specified or default parameters
364
+ D0FUS_genetic.run_genetic_optimization(input_file, **ga_params)
365
+
366
+ except ValueError as e:
367
+ # Invalid number of brackets or parsing error
368
+ print(str(e))
369
+ sys.exit(1)
370
+ except FileNotFoundError as e:
371
+ print(f"\n {str(e)}")
372
+ sys.exit(1)
373
+ except Exception as e:
374
+ print(f"\n Unexpected error: {str(e)}")
375
+ import traceback
376
+ traceback.print_exc()
377
+ sys.exit(1)
378
+
379
+ def interactive_mode():
380
+ """Interactive mode: select file, auto-detect mode, execute"""
381
+ print_banner()
382
+
383
+ # Select input file
384
+ input_file = select_input_file()
385
+
386
+ # Execute with automatic mode detection
387
+ execute_with_mode_detection(input_file)
388
+
389
+ def command_line_mode(input_file):
390
+ """Command line mode: auto-detect mode from input file"""
391
+ print_banner()
392
+
393
+ # Check if file exists
394
+ if not os.path.exists(input_file):
395
+ print(f"\n Error: Input file not found: {input_file}")
396
+ print("\nAvailable files in D0FUS_INPUTS:")
397
+ for f in list_input_files():
398
+ print(f" - {f.name}")
399
+ sys.exit(1)
400
+
401
+ # Execute with automatic mode detection
402
+ execute_with_mode_detection(input_file)
403
+
404
+ def main():
405
+ """Main entry point"""
406
+ # Check for help flag
407
+ if len(sys.argv) > 1 and sys.argv[1] in ['--help', '-h', 'help']:
408
+ print_banner()
409
+ print_usage()
410
+ sys.exit(0)
411
+
412
+ # Run in appropriate mode
413
+ try:
414
+ if len(sys.argv) == 1:
415
+ # No arguments → interactive mode
416
+ interactive_mode()
417
+ elif len(sys.argv) == 2:
418
+ # One argument → command line mode with input file
419
+ input_file = sys.argv[1]
420
+ command_line_mode(input_file)
421
+ else:
422
+ print("Error: Too many arguments.")
423
+ print_usage()
424
+ sys.exit(1)
425
+
426
+ except KeyboardInterrupt:
427
+ print("\n\n Operation cancelled by user")
428
+ sys.exit(0)
429
+
430
+ if __name__ == "__main__":
431
+ main()
@@ -0,0 +1,77 @@
1
+ from __future__ import annotations
2
+
3
+ """
4
+ D0FUS Import Module
5
+ ===================
6
+ Central import module for the D0FUS (Design 0-dimensional for FUsion Systems) project.
7
+
8
+ Created: December 2023
9
+ Author: Auclair Timothé
10
+ """
11
+
12
+ #%% Environment Configuration
13
+
14
+ import os
15
+ os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE"
16
+
17
+ #%% Standard Library Imports
18
+
19
+ import json
20
+ import math
21
+ import random
22
+ import re
23
+ import shutil
24
+ import sys
25
+ import time
26
+ import warnings
27
+ import importlib
28
+ from datetime import datetime
29
+ from pathlib import Path
30
+
31
+ #%% Scientific Computing Libraries
32
+
33
+ import numpy as np
34
+ import pandas as pd
35
+ import sympy as sp
36
+
37
+ #%% Scipy - Optimization and Numerical Methods
38
+
39
+ from scipy.integrate import quad
40
+ from scipy.interpolate import interp1d, griddata
41
+ from scipy.optimize import (
42
+ basinhopping,
43
+ bisect,
44
+ brentq,
45
+ differential_evolution,
46
+ fsolve,
47
+ least_squares,
48
+ minimize,
49
+ minimize_scalar,
50
+ root,
51
+ root_scalar,
52
+ shgo
53
+ )
54
+ from scipy.signal import find_peaks
55
+
56
+ #%% Visualization Libraries
57
+
58
+ import matplotlib.pyplot as plt
59
+ import matplotlib.colors as mcolors
60
+ import matplotlib.lines as mlines
61
+ import matplotlib.patches as mpatches
62
+ from matplotlib.colors import Normalize
63
+ from matplotlib.gridspec import GridSpec
64
+ from matplotlib.ticker import MultipleLocator
65
+ from mpl_toolkits.axes_grid1 import make_axes_locatable
66
+ from pandas.plotting import table
67
+ from tqdm import tqdm
68
+ from dataclasses import dataclass
69
+ from typing import Optional, Dict, List, Tuple
70
+
71
+ #%% Genetic Algorithm Libraries
72
+
73
+ from deap import algorithms, base, creator, tools
74
+
75
+ #%%
76
+
77
+ # print("D0FUS_import loaded")
@@ -0,0 +1,130 @@
1
+ """
2
+ D0FUS Parameterization Module
3
+ ==============================
4
+ Physical constants, material properties, and default parameters for tokamak design.
5
+
6
+ Created: December 2023
7
+ Author: Auclair Timothé
8
+ """
9
+
10
+ #%% Imports
11
+
12
+ # When imported as a module (normal usage in production)
13
+ if __name__ != "__main__":
14
+ from .D0FUS_import import *
15
+
16
+ # When executed directly (for testing and development)
17
+ else:
18
+ import sys
19
+ import os
20
+
21
+ # Add parent directory to path to allow absolute imports
22
+ sys.path.insert(0, os.path.dirname(os.path.dirname(__file__)))
23
+
24
+ # Import using absolute paths for standalone execution
25
+ from D0FUS_BIB.D0FUS_import import *
26
+
27
+ #%% Physical Constants
28
+
29
+ # Fundamental constants
30
+ E_ELEM = 1.6e-19 # Elementary charge [C]
31
+ M_E = 9.1094e-31 # Electron mass [kg]
32
+ M_I = 2 * 1.6726e-27 # Ion mass (deuterium) [kg]
33
+ μ0 = 4.0 * np.pi * 1.0e-7 # Vacuum permeability [H/m]
34
+ EPS_0 = 8.8542e-12 # Vacuum permittivity [F/m]
35
+
36
+ #%% Fusion Reaction Parameters
37
+
38
+ # Energy release per reaction
39
+ E_ALPHA = 3.5 * 1.0e6 * E_ELEM # Alpha particle energy [J]
40
+ E_N = 14.1 * 1.0e6 * E_ELEM # Neutron energy [J]
41
+ E_F = 22.4 * 1.0e6 * E_ELEM # Total fusion energy (assuming all neutrons react with Li) [J]
42
+
43
+ # Plasma composition
44
+ Atomic_mass = 2.5 # Average atomic mass [AMU]
45
+ Zeff = 1 # Effective charge (default: 1)
46
+ r_synch = 0.5 # Synchrotron radiation reflection coefficient
47
+
48
+ #%% Plasma Stability Limits
49
+
50
+ betaN_limit = 2.8 # Troyon beta limit [% m T/MA]
51
+ q_limit = 2.5 # Minimum safety factor (q95 or q*)
52
+ ms = 0.3 # Vertical stability margin parameter
53
+
54
+ #%% Material Properties
55
+
56
+ # Structural steel
57
+ σ_manual = 1500 # Manual stress limit [MPa]
58
+ nu_Steel = 0.29 # Poisson's ratio (CIRCEE model)
59
+ Young_modul_Steel = 200e9 # Young's modulus [Pa] (CIRCEE model)
60
+ Young_modul_Glass_Fiber = 90e9 # Young's modulus for S-glass fiber [Pa]
61
+ # Reference: https://www.engineeringtoolbox.com/polymer-composite-fibers-d_1226.html
62
+
63
+ #%% Plasma Performance Parameters
64
+
65
+ C_Alpha = 5 # Helium ash dilution tuning parameter
66
+
67
+ #%% Magnetic Flux Parameters
68
+
69
+ Ce = 0.45 # Ejima constant (flux consumption)
70
+ ITERPI = 20 # ITER plasma induction flux [Wb]
71
+
72
+ #%% Toroidal Field (TF) Coil Parameters
73
+
74
+ coef_inboard_tension = 1/2 # Stress distribution ratio (inboard/outboard leg)
75
+ F_CClamp = 0e6 # C-Clamp structural limit [N]
76
+ # Typical range: 30e6 N (DDD) to 60e6 N (Bachmann 2023, FED)
77
+ n_TF = 1 # Conductor asymmetry parameter
78
+ c_BP = 0.07 # Backplate thickness [m]
79
+
80
+ #%% Central Solenoid (CS) Parameters
81
+
82
+ Gap = 0.1 # Clearance between CS wedging/bucking and TF [m]
83
+ n_CS = 1 # CS conductor parameter
84
+
85
+ #%% Superconductor Operating Conditions
86
+
87
+ # If manual option: current density fixed
88
+ Jc_Manual = 100e6 # MA/m²
89
+
90
+ # Helium cooling
91
+ T_helium = 4.2 # Liquid helium temperature [K]
92
+ Marge_T_Helium = 0.3 # Temperature margin linked to 10 bar operation [K]
93
+
94
+ # Area fractions
95
+ f_Cu_Non_Cu = 1 - 0.5 # Copper fraction in the strand
96
+ f_Cu_Strand = 1 - 0.3 # Copper stabilizer fraction (n_Cu/(n_Cu+n_Su))
97
+ f_Cool = 1 - 0.3 # Cooling channel fraction
98
+ f_In = 1 - 0.2 # Insulation fraction
99
+
100
+ # Temperature margins [K]
101
+ # Added to T_He to obtain T_operating (conservative design approach)
102
+ Marge_T_Nb3Sn = 2.0 # Safety margin for Nb3Sn
103
+ Marge_T_NbTi = 1.7 # Safety margin for NbTi
104
+ Marge_T_Rebco = 5.0 # Safety margin for REBCO
105
+
106
+ # Default operating parameters
107
+ Eps = -0.6/100 # Effective strain for Nb3Sn [-] (EU-DEMO TF: -0.35%)
108
+ Tet = 0.0 # REBCO tape angle [rad] (0 = B⊥, π/2 = B//ab)
109
+
110
+ #%% Power Conversion Efficiencies
111
+
112
+ eta_T = 0.4 # Thermal-to-electric conversion efficiency
113
+ eta_RF = 0.8 * 0.5 # RF heating efficiency (klystron efficiency × plasma absorption)
114
+
115
+ #%% Plasma-Facing Components (PFU)
116
+
117
+ theta_deg = 2.7 # Grazing angle at divertor strike point [deg]
118
+ # References:
119
+ # - T. R. Reiter, "Basic Fusion Boundary Plasma Physics," ITER School Lecture Notes (2019)
120
+ # - "SOLPS-ITER simulations of the ITER divertor with improved plasma conditions,"
121
+ # Journal of Nuclear Materials (2024)
122
+
123
+ #%% Numerical Configuration
124
+
125
+ # Suppress runtime warnings for cleaner output
126
+ warnings.filterwarnings("ignore", category=RuntimeWarning)
127
+
128
+ #%%
129
+
130
+ # print("D0FUS_parameterization loaded")