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 +431 -0
- d0fus-1.0.2/D0FUS_BIB/D0FUS_import.py +77 -0
- d0fus-1.0.2/D0FUS_BIB/D0FUS_parameterization.py +130 -0
- d0fus-1.0.2/D0FUS_BIB/D0FUS_physical_functions.py +2964 -0
- d0fus-1.0.2/D0FUS_BIB/D0FUS_radial_build_functions.py +3356 -0
- d0fus-1.0.2/D0FUS_EXE/D0FUS_genetic.py +750 -0
- d0fus-1.0.2/D0FUS_EXE/D0FUS_run.py +756 -0
- d0fus-1.0.2/D0FUS_EXE/D0FUS_scan.py +1380 -0
- d0fus-1.0.2/LICENSE +516 -0
- d0fus-1.0.2/PKG-INFO +282 -0
- d0fus-1.0.2/README.md +244 -0
- d0fus-1.0.2/d0fus.egg-info/PKG-INFO +282 -0
- d0fus-1.0.2/d0fus.egg-info/SOURCES.txt +17 -0
- d0fus-1.0.2/d0fus.egg-info/dependency_links.txt +1 -0
- d0fus-1.0.2/d0fus.egg-info/entry_points.txt +2 -0
- d0fus-1.0.2/d0fus.egg-info/requires.txt +10 -0
- d0fus-1.0.2/d0fus.egg-info/top_level.txt +3 -0
- d0fus-1.0.2/pyproject.toml +85 -0
- d0fus-1.0.2/setup.cfg +4 -0
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")
|