Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add bout-upgrader tool #111

Merged
merged 82 commits into from
Sep 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
82 commits
Select commit Hold shift + click to select a range
d871cc1
Add tool for updating v4 factory uses to v5 style
ZedThree Nov 8, 2019
ef2eae8
Add LaplaceXZ to factory-upgrader helper script
ZedThree Nov 14, 2019
1a3ef9b
Add InvertPar to factory-upgrader helper script
ZedThree Nov 14, 2019
43ecd30
Catch static variables with zero initialisation in factory upgrader
ZedThree Nov 14, 2019
b50ca68
Add Mesh to factory updater
ZedThree Nov 14, 2019
5d3e07b
Add InterpolationFactory to factory upgrader
ZedThree Nov 15, 2019
0db1788
Add format-upgrader to replace printf formats with fmt formats
ZedThree Nov 19, 2019
b652493
Make format upgrader fix uses of {:s} with std::string::c_str
ZedThree Nov 19, 2019
4dd3a7d
Add formats with width specifier to v5 format fixer
ZedThree Nov 20, 2019
d1f83bc
Fix all BoutException calls in library
ZedThree Nov 20, 2019
59727bb
Fix uses of toString().c_str() with formatting
ZedThree Nov 20, 2019
9da6d86
Add updater for Interpolation -> XZInterpolation types
ZedThree Feb 20, 2020
d9a2548
Add input file upgrader for v4 -> v5
ZedThree Feb 24, 2020
b8836a6
Add input replacements for paralleltransform changes
ZedThree Feb 24, 2020
8dc28dd
Fix typo in input file upgrader
ZedThree Feb 26, 2020
e4efa55
Add 4to5 macro updater script
ZedThree Feb 26, 2020
af193d5
Move bout::version::revision into standalone file
ZedThree Feb 26, 2020
720ac0d
Write comments using '#' in BoutOptions
ZedThree Feb 28, 2020
cec0075
Fix uncompiled parts of #ifdef blocks in macro upgrader
ZedThree Mar 2, 2020
435e885
Add renamed feature macros to bout-v5-macro-upgrader
ZedThree May 4, 2020
b0f6e50
Fix a couple of uses of renamed macros
ZedThree May 5, 2020
2ee94f8
Consider underscores as word boundaries when updating macros
ZedThree Jul 23, 2020
e5764ed
Fix bug with default file format when using legacy netcdf
ZedThree Jul 23, 2020
dd0b505
Add fixer for change of factory create method name
ZedThree Sep 4, 2020
a58540d
Add warning in upgrader if factory arguments have changed
ZedThree Sep 7, 2020
5f322fd
Option to update values in bout-v5-input-file-upgrader.py
johnomotani Nov 2, 2020
d24b391
Deprecate fft_measure option
johnomotani Nov 2, 2020
4bf3484
Handle bool-like expressions in the same way as BOUT++
johnomotani Nov 3, 2020
363e1c3
Add tool to upgrade legacy models
ZedThree Jun 8, 2020
8c8851b
Catch (some) invalid names in physics model upgrader
ZedThree Jun 9, 2020
12c7d96
Fix deprecated bout_solve/bout_constrain calls
ZedThree Jun 9, 2020
137ba7c
Allows physics model upgrader to fix split operator models
ZedThree Jun 11, 2020
d8ecd76
Attempt a better fix of bout_constrain
ZedThree Jun 11, 2020
9c2b49d
Support macros being removed in bout-v5-macro-upgrader.py
johnomotani Jan 12, 2021
97b99f5
Print error for HDF5 macros when running bout-v5-macro-upgrader.py
johnomotani Jan 12, 2021
f50e14c
Use lowercase options for setting derivative methods
ZedThree Feb 5, 2021
d1f0daa
User lowercase for nout, timestep inputs
ZedThree Feb 5, 2021
19e977e
Use lowercase for mesh:staggergrids
ZedThree Feb 5, 2021
2af5151
Consistently use lowercase for "All" section
ZedThree Feb 5, 2021
a801666
Replace entire "All" section in input upgrader
ZedThree Feb 8, 2021
b46035a
Add argument to input upgrader to just apply canonicalisation
ZedThree Feb 8, 2021
e91a145
Monkey-patch BoutOptions to make it case-sensitive
ZedThree Feb 9, 2021
3e94de1
Tweak replacement key names in input upgrader
ZedThree Feb 9, 2021
0eb786a
Add helper function to work out if an option needs upgrading
ZedThree Feb 9, 2021
25bab63
Lowercase 'twistshift' option
ZedThree Feb 9, 2021
c6c43a2
Fix some more common spellings of input options
ZedThree Feb 9, 2021
6617529
Fix some example input files with wrong derivatives sections
ZedThree Feb 9, 2021
b800570
Fix examples using old `laplace_nonuniform` option
ZedThree Feb 10, 2021
58d31d0
Fix example with wrong capitalisation of output:shiftOutput
ZedThree Feb 10, 2021
be00a67
Fix bad capitalisation of zShift option in input files
ZedThree Feb 11, 2021
c641e8a
Use consistent case for Solver atol/rtol options
ZedThree Feb 11, 2021
520de5e
Fix for some tests with dump_format in wrong section
ZedThree Feb 11, 2021
a6b76f6
Convert output camelCase options to lowercase
ZedThree Mar 2, 2021
65c3c8f
Rename 'restart' section to 'restart_files'
ZedThree Apr 9, 2021
dbfd348
Update physics model upgrader for additional Solver::add argument
ZedThree Apr 14, 2021
61adb7e
Add ability to upgrade physics model preconditioners/Jacobians
ZedThree Apr 15, 2021
299f0a4
Add some comments to physics model upgrader
ZedThree Apr 16, 2021
8c9fe1b
Remove some now obsolete input options for DataFile
ZedThree Jun 9, 2021
6f1585c
Add tool to move headers under `include/bout` and fix `#include`s
ZedThree Jul 26, 2022
f83cadb
Update bin/bout-v5-header-upgrader.py
bendudson Feb 2, 2023
050131a
Pull out duplicated code from upgrader scripts
ZedThree Jul 3, 2024
b3547d7
Move upgrader scripts from BOUT-dev repo to boututils
ZedThree Jul 17, 2024
7fe4f04
Add upgrader scripts as subcommands of top-level `bout-upgrader`
ZedThree Jul 23, 2024
cf58eca
Move import of `boutdata` into function to avoid circular dependency
ZedThree Jul 23, 2024
050437e
Apply black
ZedThree Jul 23, 2024
1ac8499
Move upgrader script to own package
ZedThree Sep 12, 2024
960b69b
Remove execute permissions from individual upgrader modules
ZedThree Sep 12, 2024
2f8df50
Remove unneeded function
ZedThree Sep 12, 2024
5ac848b
Sort headers
ZedThree Sep 12, 2024
1e38d87
Replace `.format` with f-strings
ZedThree Sep 12, 2024
c835b75
Remove default `open` flags
ZedThree Sep 12, 2024
b728c86
Use generator in place of tuple
ZedThree Sep 12, 2024
24a1386
Group v5 upgrade subcommands
ZedThree Sep 12, 2024
f948fc2
Add version argument to bout-upgrader
ZedThree Sep 12, 2024
14c7dc3
Add tool to help with updating files from v3 to v4
ZedThree Sep 28, 2016
5f3d19e
Use mesh->coordinates() instead of coords in 3to4
ZedThree Sep 29, 2016
5bbe434
Enable bout_3to4 to check 2D subscripts
ZedThree Nov 21, 2016
3f35847
Added ng@ -> LocalN@ replacement
loeiten Apr 18, 2017
4969437
Changed ngz to warning, added more warnings
loeiten Apr 18, 2017
b66b192
Move bout_3to4 into boutupgrader structure
ZedThree Sep 12, 2024
8c0669d
Apply black and ruff fixes
ZedThree Sep 12, 2024
cbe7da9
Fix some more ruff/flake8 warnings
ZedThree Sep 26, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ docs = [

[project.scripts]
bout-squashoutput = "boutdata.scripts.bout_squashoutput:main"
bout-upgrader = "boutupgrader:main"

[tool.setuptools.dynamic]
version = { attr = "setuptools_scm.get_version" }
Expand Down
70 changes: 70 additions & 0 deletions src/boutupgrader/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import argparse
from importlib.metadata import PackageNotFoundError, version

from .bout_3to4 import add_parser as add_3to4_parser
from .bout_v5_factory_upgrader import add_parser as add_factory_parser
from .bout_v5_format_upgrader import add_parser as add_format_parser
from .bout_v5_header_upgrader import add_parser as add_header_parser
from .bout_v5_input_file_upgrader import add_parser as add_input_parser
from .bout_v5_macro_upgrader import add_parser as add_macro_parser
from .bout_v5_physics_model_upgrader import add_parser as add_model_parser
from .bout_v5_xzinterpolation_upgrader import add_parser as add_xzinterp_parser

try:
# This gives the version if the boututils package was installed
__version__ = version("boutdata")
except PackageNotFoundError:
# This branch handles the case when boututils is used from the git repo
try:
from setuptools_scm import get_version

__version__ = get_version(root="..", relative_to=__file__)
except (ModuleNotFoundError, LookupError):
__version__ = "dev"


def main():
# Parent parser that has arguments common to all subcommands
common_args = argparse.ArgumentParser(add_help=False)
common_args.add_argument(
"--quiet", "-q", action="store_true", help="Don't print patches"
)
force_or_patch_group = common_args.add_mutually_exclusive_group()
force_or_patch_group.add_argument(
"--force", "-f", action="store_true", help="Make changes without asking"
)
force_or_patch_group.add_argument(
"--patch-only", "-p", action="store_true", help="Print the patches and exit"
)

# Parent parser for commands that always take a list of files
files_args = argparse.ArgumentParser(add_help=False)
files_args.add_argument("files", action="store", nargs="+", help="Input files")

parser = argparse.ArgumentParser(
description="Upgrade BOUT++ source and input files to newer versions"
)
parser.add_argument(
"--version", action="version", version=f"%(prog)s {__version__}"
)
subcommand = parser.add_subparsers(title="subcommands", required=True)

v4_subcommand = subcommand.add_parser(
"v4", help="BOUT++ v4 upgrades"
).add_subparsers(title="v4 subcommands", required=True)
add_3to4_parser(v4_subcommand, common_args, files_args)

v5_subcommand = subcommand.add_parser(
"v5", help="BOUT++ v5 upgrades"
).add_subparsers(title="v5 subcommands", required=True)

add_factory_parser(v5_subcommand, common_args, files_args)
add_format_parser(v5_subcommand, common_args, files_args)
add_header_parser(v5_subcommand, common_args)
add_input_parser(v5_subcommand, common_args, files_args)
add_macro_parser(v5_subcommand, common_args, files_args)
add_model_parser(v5_subcommand, common_args, files_args)
add_xzinterp_parser(v5_subcommand, common_args, files_args)

args = parser.parse_args()
args.func(args)
230 changes: 230 additions & 0 deletions src/boutupgrader/bout_3to4.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
#!/usr/bin/env python3

import fileinput
import re
import sys

nonmembers = {
"DC": ["DC", 1],
"slice": ["sliceXZ", 2],
}

coordinates = [
"outputVars",
"dx",
"dy",
"dz",
"non_uniform",
"d1_dx",
"d1_dy",
"J",
"Bxy",
"g11",
"g22",
"g33",
"g12",
"g13",
"g23",
"g_11",
"g_22",
"g_33",
"g_12",
"g_13",
"g_23",
"G1_11",
"G1_22",
"G1_33",
"G1_12",
"G1_13",
"G2_11",
"G2_22",
"G2_33",
"G2_12",
"G2_23",
"G3_11",
"G3_22",
"G3_33",
"G3_13",
"G3_23",
"G1",
"G2",
"G3",
"ShiftTorsion",
"IntShiftTorsion",
"geometry",
"calcCovariant",
"calcContravariant",
"jacobian",
]

local_mesh = [
("ngx", "LocalNx"),
("ngy", "LocalNy"),
]

warnings = [
(r"\^", "Use pow(a,b) instead of a^b"),
(r"\.max\(", "Use max(a) instead of a.max()"),
(
"ngz",
(
"ngz is changed to LocalNz in v4."
" The extra point in z has been removed."
" Change ngz -> LocalNz, and ensure that"
" the number of points are correct"
),
),
]


def fix_nonmembers(line_text, filename, line_num, replace=False):
"""Replace member functions with nonmembers"""

old_line_text = line_text

for old, (new, num_args) in nonmembers.items():
pattern = re.compile(rf"(\w*)\.{old}\(")
matches = re.findall(pattern, line_text)
for match in matches:
replacement = f"{new}({match}"
if num_args > 1:
replacement += ", "
line_text = re.sub(pattern, replacement, line_text)
if not replace:
name_num = f"{filename}:{line_num}:"
print(f"{name_num}{old_line_text}", end="")
print(" " * len(name_num) + line_text)
if replace:
return line_text


def fix_subscripts(line_text, filename, line_num, replace=False):
"""Replace triple square brackets with round brackets

Should also check that the variable is a Field3D/Field2D - but doesn't
"""

old_line_text = line_text
# Catch both 2D and 3D arrays
pattern = re.compile(r"\[([^[]*)\]\[([^[]*)\](?:\[([^[]*)\])?")
matches = re.findall(pattern, line_text)
for match in matches:
# If the last group is non-empty, then it was a 3D array
if len(match[2]):
replacement = r"(\1, \2, \3)"
else:
replacement = r"(\1, \2)"
line_text = re.sub(pattern, replacement, line_text)
if not replace:
name_num = f"{filename}:{line_num}:"
print(f"{name_num}{old_line_text}", end="")
print(" " * len(name_num) + line_text)
if replace:
return line_text


def fix_coordinates(line_text, filename, line_num, replace=False):
"""Fix variables that have moved from mesh to coordinates"""

old_line_text = line_text

for var in coordinates:
pattern = re.compile(f"mesh->{var}")
matches = re.findall(pattern, line_text)
for match in matches:
line_text = re.sub(pattern, f"mesh->coordinates()->{var}", line_text)
if not replace:
name_num = f"{filename}:{line_num}:"
print(
f"{name_num}{old_line_text}",
end="",
)
print(" " * len(name_num) + line_text)
if replace:
return line_text


def fix_local_mesh_size(line_text, filename, line_num, replace=False):
"""Replaces ng@ with LocalNg@, where @ is in {x,y,z}"""

old_line_text = line_text

for lm in local_mesh:
pattern = re.compile(lm[0])
matches = re.findall(pattern, line_text)
for match in matches:
line_text = re.sub(pattern, lm[1], line_text)
if not replace:
name_num = f"{filename}:{line_num}:"
print(
f"{name_num}{old_line_text}",
end="",
)
print(" " * len(name_num) + line_text)
if replace:
return line_text


def throw_warnings(line_text, filename, line_num):
"""Throws a warning for ^, .max() and ngz"""

for warn in warnings:
pattern = re.compile(warn[0])
matches = re.findall(pattern, line_text)
for match in matches:
name_num = f"{filename}:{line_num}:"
# stdout is redirected to the file if --replace is given,
# therefore use stderr
sys.stderr.write(f"{name_num}{line_text}")
# Coloring with \033[91m, end coloring with \033[0m\n
sys.stderr.write(
" " * len(name_num) + f"\033[91m!!!WARNING: {warn[1]}\033[0m\n\n"
)


def add_parser(subcommand, default_args, files_args):
epilog = """
Currently bout_3to4 can detect the following transformations are needed:
- Triple square brackets instead of round brackets for subscripts
- Field member functions that are now non-members
- Variables/functions that have moved from Mesh to Coordinates

Note that in the latter case of transformations, you will still need to manually add
Coordinates *coords = mesh->coordinates();
to the correct scopes
"""

parser = subcommand.add_parser(
"3to4",
help="A little helper for upgrading from BOUT++ version 3 to version 4",
description="A little helper for upgrading from BOUT++ version 3 to version 4",
parents=[default_args, files_args],
epilog=epilog,
)
parser.set_defaults(func=run)


def run(args):
# Loops over all lines across all files
for line in fileinput.input(files=args.files, inplace=args.replace):
filename = fileinput.filename()
line_num = fileinput.filelineno()

# Apply the transformations and then update the line if we're doing a replacement
new_line = fix_nonmembers(line, filename, line_num, args.replace)
line = new_line if args.replace else line

new_line = fix_subscripts(line, filename, line_num, args.replace)
line = new_line if args.replace else line

new_line = fix_coordinates(line, filename, line_num, args.replace)
line = new_line if args.replace else line

new_line = fix_local_mesh_size(line, filename, line_num, args.replace)
line = new_line if args.replace else line

new_line = throw_warnings(line, filename, line_num)

# If we're doing a replacement, then we need to print all lines, without a newline
if args.replace:
print(line, end="")
Loading
Loading