Skip to content

Commit 843b676

Browse files
committed
Add tool to upgrade collisions/closure in Hermes-3
1 parent 7164a89 commit 843b676

File tree

4 files changed

+75
-8
lines changed

4 files changed

+75
-8
lines changed

src/boutupgrader/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from .bout_v5_xzinterpolation_upgrader import add_parser as add_xzinterp_parser
1212
from .bout_v6_coordinates_upgrader import add_parser as add_v6_coordinates_parser
1313
from .bout_v6_input_file_upgrader import add_parser as add_v6_input_parser
14+
from .hermes_collisions_input_file_upgrader import add_parser as add_hermes_input_parser
1415

1516
try:
1617
# This gives the version if the boututils package was installed
@@ -63,6 +64,10 @@ def main():
6364
"v6", help="BOUT++ v6 upgrades"
6465
).add_subparsers(title="v6 subcommands", required=True)
6566

67+
hermes_subcommand = subcommand.add_parser(
68+
"hermes", help="Hermes-3 subcommands"
69+
).add_subparsers(title="hermes subcommands", required=True)
70+
6671
add_3to4_parser(v4_subcommand, common_args, files_args)
6772
add_factory_parser(v5_subcommand, common_args, files_args)
6873
add_format_parser(v5_subcommand, common_args, files_args)
@@ -73,6 +78,7 @@ def main():
7378
add_xzinterp_parser(v5_subcommand, common_args, files_args)
7479
add_v6_coordinates_parser(v6_subcommand, common_args, files_args)
7580
add_v6_input_parser(v6_subcommand, common_args, files_args)
81+
add_hermes_input_parser(hermes_subcommand, common_args, files_args)
7682

7783
args = parser.parse_args()
7884
args.func(args)

src/boutupgrader/bout_v5_input_file_upgrader.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ def remove_deleted(deleted, options_file):
203203
del options_file[key]
204204

205205

206-
def apply_fixes(replacements, deleted, options_file):
206+
def apply_fixes(replacements, deleted, options_file, additional_modifications):
207207
"""Apply all fixes in this module"""
208208

209209
modified = copy.deepcopy(options_file)
@@ -212,6 +212,8 @@ def apply_fixes(replacements, deleted, options_file):
212212

213213
remove_deleted(deleted, modified)
214214

215+
additional_modifications(modified)
216+
215217
return modified
216218

217219

@@ -236,14 +238,14 @@ def possibly_apply_patch(patch, options_file, quiet=False, force=False):
236238
return make_change
237239

238240

239-
def add_parser_general(subcommand, default_args, files_args, run):
241+
def add_parser_general(subcommand, default_args, files_args, run, name):
240242
parser = subcommand.add_parser(
241243
"input",
242244
formatter_class=argparse.RawDescriptionHelpFormatter,
243245
help="Fix input files",
244246
description=textwrap.dedent(
245-
"""\
246-
Fix input files for BOUT++ v5+
247+
f"""\
248+
Fix input files for {name}
247249
248250
Please note that this will only fix input options in sections with
249251
standard or default names. You may also need to fix options in custom
@@ -290,7 +292,7 @@ def add_parser_general(subcommand, default_args, files_args, run):
290292
parser.set_defaults(func=run)
291293

292294

293-
def run_general(REPLACEMENTS, DELETED, args):
295+
def run_general(REPLACEMENTS, DELETED, args, *, additional_modifications=None):
294296
from boutdata.data import BoutOptions, BoutOptionsFile
295297

296298
# Monkey-patch BoutOptions to make sure it's case sensitive
@@ -324,7 +326,7 @@ def run_general(REPLACEMENTS, DELETED, args):
324326
continue
325327

326328
try:
327-
modified = apply_fixes(REPLACEMENTS, DELETED, original)
329+
modified = apply_fixes(REPLACEMENTS, DELETED, original, additional_modifications)
328330
except RuntimeError as e:
329331
print(e)
330332
continue
@@ -347,4 +349,4 @@ def run(args):
347349

348350

349351
def add_parser(subcommand, default_args, files_args):
350-
return add_parser_general(subcommand, default_args, files_args, run)
352+
return add_parser_general(subcommand, default_args, files_args, run, "BOUT++ v5+")

src/boutupgrader/bout_v6_input_file_upgrader.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,4 @@ def run(args):
1919

2020

2121
def add_parser(subcommand, default_args, files_args):
22-
return add_parser_general(subcommand, default_args, files_args, run)
22+
return add_parser_general(subcommand, default_args, files_args, run, "BOUT++ v6+")
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
from itertools import chain
2+
from typing import TypedDict
3+
import re
4+
5+
from .bout_v5_input_file_upgrader import add_parser_general, run_general
6+
from boutdata.data import BoutOptionsFile
7+
8+
class Replacement(TypedDict):
9+
old: str
10+
new: str
11+
12+
REPLACEMENTS = []
13+
DELETED = []
14+
15+
NEW_NAMES = {
16+
"collisions": ["braginskii_collisions", "braginskii_friction", "braginskii_heat_exchange"],
17+
"electron_viscosity": ["braginskii_electron_viscosity"],
18+
"ion_viscosity": ["braginskii_ion_viscosity"],
19+
"thermal_force": ["braginskii_thermal_force"]
20+
}
21+
22+
COMPONENT_RE = re.compile(r"[+\-\w]+")
23+
24+
25+
def update_component_names(options_file: BoutOptionsFile) -> None:
26+
"""Change the names of closure-related components to reflect the refactor"""
27+
has_collisions = False
28+
recycling_component = ""
29+
components = re.findall(COMPONENT_RE, options_file["hermes:components"])
30+
for section_name in components:
31+
section = options_file.getSection(section_name)
32+
explicit_types = "type" in section
33+
types = [tname.strip() for tname in section["type"].split(",")] if explicit_types else [section_name]
34+
open_paren = types[0][0] == "("
35+
close_paren = types[-1][-1] == ")"
36+
if open_paren:
37+
types[0] = types[0][1:]
38+
if close_paren:
39+
types[-1] = types[-1][:-1]
40+
new_types = list(chain.from_iterable(NEW_NAMES.get(t, [t]) for t in types))
41+
has_collisions = has_collisions or "collisions" in types
42+
if "recycling" in new_types:
43+
recycling_component = section_name
44+
if new_types != types:
45+
section["type"] = ("(" if open_paren else "") + ", ".join(new_types) + (")" if close_paren else "")
46+
# Add braginskii_conduction to the end of the list of components
47+
if has_collisions:
48+
components.append("braginskii_conduction")
49+
# Make sure recycling is evaluated after conduction
50+
if recycling_component != "":
51+
components.remove(recycling_component)
52+
components.append(recycling_component)
53+
options_file["hermes:components"] = "(" + ", ".join(components) + ")"
54+
55+
def run(args) -> None:
56+
run_general(REPLACEMENTS, DELETED, args, additional_modifications=update_component_names)
57+
58+
def add_parser(subcommand, default_args, files_args):
59+
return add_parser_general(subcommand, default_args, files_args, run, "Hermes-3")

0 commit comments

Comments
 (0)