Skip to content

Commit 42ed3e1

Browse files
committed
test(fortran): move fortran apps tests to separate file
1 parent ecfb381 commit 42ed3e1

File tree

3 files changed

+181
-162
lines changed

3 files changed

+181
-162
lines changed

test/fortran/__init__.py

Whitespace-only changes.

test/fortran/test_apps.py

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
"""Integration tests based on various scientific applications written in Fortran."""
2+
3+
import logging
4+
import os
5+
import pathlib
6+
import unittest
7+
8+
from transpyle.general import Language, CodeReader, Parser, AstGeneralizer, Unparser, CodeWriter
9+
10+
from ..common import \
11+
basic_check_fortran_code, basic_check_fortran_ast, \
12+
basic_check_python_code, basic_check_python_ast, \
13+
APPS_ROOT, execute_on_examples
14+
from ..test_apps import _prepare_roundtrip, AppTests
15+
16+
_LOG = logging.getLogger(__name__)
17+
18+
19+
def _roundtrip_fortran(case, path, results_path, parser, ast_generalizer, unparser):
20+
with path.open() as original_file:
21+
basic_check_fortran_code(case, path, original_file.read(), results=results_path,
22+
suffix=None)
23+
fortran_ast = parser.parse('', path)
24+
basic_check_fortran_ast(case, path, fortran_ast, results=results_path)
25+
tree = ast_generalizer.generalize(fortran_ast)
26+
basic_check_python_ast(case, path, tree, results=results_path)
27+
# python_code = python_unparser.unparse(tree)
28+
# basic_check_python_code(self, path, python_code, results=results_path)
29+
# tree = python_parser.parse(python_code)
30+
# basic_check_python_ast(self, path, tree, results=results_path)
31+
fortran_code = unparser.unparse(tree)
32+
basic_check_fortran_code(case, path, fortran_code, results=results_path)
33+
34+
35+
def _migrate_fortran(case, path, results_path, parser, ast_generalizer, unparser):
36+
with path.open() as original_file:
37+
basic_check_fortran_code(case, path, original_file.read(), results=results_path,
38+
suffix=None)
39+
fortran_ast = parser.parse('', path)
40+
basic_check_fortran_ast(case, path, fortran_ast, results=results_path)
41+
tree = ast_generalizer.generalize(fortran_ast)
42+
basic_check_python_ast(case, path, tree, results=results_path)
43+
python_code = unparser.unparse(tree)
44+
basic_check_python_code(case, path, python_code, results=results_path)
45+
46+
47+
@unittest.skipIf(
48+
Language.find('Fortran') is None, 'skipping due to missing Fortran language support')
49+
class FFBMiniTests(AppTests):
50+
51+
app_name = 'FFB-MINI'
52+
53+
app_source_folder = APPS_ROOT.joinpath('ffb-mini', 'src')
54+
55+
paths = [
56+
pathlib.Path(root, name) for root, _, files in os.walk(str(app_source_folder))
57+
for name in files if pathlib.Path(name).suffix in ('.f', '.F', '.f90', '.F90')
58+
and name not in {
59+
'ddcom4.F', # SyntaxError - just not implemented yet
60+
'ffb_mini_main.F90', # NotImplementedError
61+
'f_test.F90', # NotImplementedError
62+
'mod_maprof.F90', # NotImplementedError
63+
# OFP fails for the following files
64+
# issues need to be resolved upstream or files need to be modified
65+
'bcgs3x.F', 'bcgsxe.F', 'calax3.F', 'callap.F', 'dd_mpi.F', 'e2plst.F', 'extrfn.F',
66+
'gfutil.f', 'grad3x.F', 'les3x.F', 'lesrop.F', 'lesrpx.F', 'lessfx.F', 'lrfnms.F',
67+
'makemesh.F90', 'miniapp_util.F', 'mfname.F', 'neibr2.F', 'nodlex.F', 'pres3e.F',
68+
'rcmelm.F', 'rfname.F', 'srfexx.F', 'vel3d1.F', 'vel3d2.F'}]
69+
70+
@unittest.skipUnless(os.environ.get('TEST_LONG'), 'skipping long test')
71+
def test_roundtrip(self):
72+
self._test_app(_prepare_roundtrip(self, Language.find('Fortran')), _roundtrip_fortran)
73+
74+
75+
@unittest.skipIf(
76+
Language.find('Fortran') is None, 'skipping due to missing Fortran language support')
77+
class Flash5Tests(unittest.TestCase):
78+
79+
app_name = 'FLASH5'
80+
81+
app_source_folder = APPS_ROOT.joinpath('flash5', 'source')
82+
83+
paths = path_selection_tree(app_source_folder, {
84+
# pathlib.Path('physics', 'Eos', 'EosMain', 'Helmholtz_starkiller',
85+
# 'SpeciesBased'): 'actual_eos.F90', # access specifiers (i.e public/private)
86+
pathlib.Path('physics', 'Hydro', 'HydroMain', 'unsplit'): [
87+
'hy_getFaceFlux.F90',
88+
# 'hy_getRiemannState.F90', # need to preprocess 1 macro
89+
'hy_TVDslope.F90',
90+
'hy_upwindTransverseFlux.F90', pathlib.Path('MHD', 'hy_eigenVector.F90')],
91+
pathlib.Path('physics', 'sourceTerms', 'Burn'): {
92+
'BurnMain': {
93+
'nuclearBurn': [
94+
'Burn.F90', 'bn_burner.F90', 'bn_azbar.F90', 'bn_screen4.F90', 'bn_sneutx.F90',
95+
'bn_mcord.F90'],
96+
pathlib.Path('nuclearBurn', 'Aprox13'): [
97+
'bn_mapNetworkToSpecies.F90', 'bn_networkTable.F90', 'bn_networkRates.F90',
98+
'bn_networkScreen.F90', 'bn_network.F90', 'bn_networkSparseJakob.F90',
99+
'bn_networkSparsePointers.F90', 'bn_networkDenseJakob.F90', 'bn_gift.F90']},
100+
'BurnIntegrate': ['bn_netIntegrate.F90', 'bn_baderMa28.F90', 'bn_rosenMa28.F90']},
101+
pathlib.Path('Simulation'): 'Simulation_init.F90'
102+
})
103+
paths.append(app_source_folder.parent.joinpath('lib', 'ma28', 'source', 'Ma28.F90'))
104+
105+
@unittest.skipUnless(os.environ.get('TEST_LONG'), 'skipping long test')
106+
@execute_on_examples(paths)
107+
def test_roundtrip(self, input_path):
108+
reader = CodeReader()
109+
fortran_code = reader.read_file(input_path)
110+
results_path = pathlib.Path(APPS_RESULTS_ROOT, 'flash5')
111+
results_path.mkdir(exist_ok=True)
112+
basic_check_fortran_code(self, input_path, fortran_code, results=results_path, suffix=None)
113+
parser = Parser.find(Language.find('Fortran'))()
114+
fortran_ast = parser.parse(fortran_code, input_path)
115+
basic_check_fortran_ast(self, input_path, fortran_ast, results=results_path)
116+
ast_generalizer = AstGeneralizer.find(Language.find('Fortran'))()
117+
syntax = ast_generalizer.generalize(fortran_ast)
118+
basic_check_python_ast(self, input_path, syntax, results=results_path)
119+
unparser = Unparser.find(Language.find('Fortran'))()
120+
code = unparser.unparse(syntax)
121+
basic_check_fortran_code(self, input_path, code, results=results_path)
122+
123+
def test_partial_inline_burn(self):
124+
_ = self.app_source_folder.joinpath(
125+
'physics', 'sourceTerms', 'Burn', 'BurnMain', 'nuclearBurn')
126+
inlined_path = _.joinpath('Aprox13', 'bn_mapNetworkToSpecies.F90')
127+
target_path = _.joinpath('Burn.F90')
128+
129+
reader = CodeReader()
130+
inlined_code = reader.read_file(inlined_path)
131+
target_code = reader.read_file(target_path)
132+
133+
parser = Parser.find(Language.find('Fortran'))()
134+
inlined_fortran_ast = parser.parse(inlined_code, inlined_path)
135+
# inlined_fortran_ast = inlined_fortran_ast.find('.//subroutine')
136+
target_fortran_ast = parser.parse(target_code, target_path)
137+
138+
ast_generalizer = AstGeneralizer.find(Language.find('Fortran'))()
139+
inlined_syntax = ast_generalizer.generalize(inlined_fortran_ast)
140+
inlined_function = inlined_syntax.body[-1]
141+
# TODO: implement object finding to find function
142+
target_syntax = ast_generalizer.generalize(target_fortran_ast)
143+
target_function = target_syntax.body[-1]
144+
# TODO: implement object finding to find function
145+
146+
# import horast
147+
# print(horast.unparse(inlined_function))
148+
# print(horast.unparse(target_function))
149+
# import ipdb; ipdb.set_trace()
150+
151+
# import static_typing
152+
inlined_syntax = inline_syntax(
153+
target_function, inlined_function,
154+
# globals_={'NSPECIES': 13, 'st': static_typing, **globals()},
155+
verbose=True)
156+
annotation = horast_nodes.OpenAccPragma('parallel loop')
157+
annotate_loop_syntax(inlined_syntax, annotation)
158+
159+
unparser = Unparser.find(Language.find('Fortran'))()
160+
transformed_code = unparser.unparse(inlined_syntax)
161+
162+
results_path = pathlib.Path(APPS_RESULTS_ROOT, 'flash5-inlined')
163+
results_path.mkdir(exist_ok=True)
164+
CodeWriter().write_file(transformed_code, results_path.joinpath('Burn.inlined_some.F90'))
165+
166+
167+
@unittest.skipIf(
168+
Language.find('Fortran') is None, 'skipping due to missing Fortran language support')
169+
@unittest.skipUnless(os.environ.get('TEST_MIRANDA'), 'skipping tests on MIRANDA code')
170+
class MirandaIOTests(AppTests):
171+
172+
app_name = 'miranda_io'
173+
174+
app_source_folder = APPS_ROOT.joinpath('miranda_io')
175+
176+
paths = [app_source_folder.joinpath('miranda_io.f90')]
177+
178+
def test_roundtrip_miranda_io(self):
179+
self._test_app(_prepare_roundtrip(self, Language.find('Fortran')), _roundtrip_fortran)

test/test_apps.py

Lines changed: 2 additions & 162 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
"""Integration tests based on various scientific applications."""
22

33
import logging
4-
import os
54
import pathlib
65
import typing as t
76
import unittest
@@ -10,13 +9,11 @@
109
import typed_ast.ast3 as typed_ast3
1110
import horast.nodes as horast_nodes
1211

13-
from transpyle.general import Language, CodeReader, Parser, AstGeneralizer, Unparser, CodeWriter
12+
from transpyle.general import Language, Parser, AstGeneralizer, Unparser
1413
from transpyle.pair import inline_syntax, annotate_loop_syntax
1514

1615
from .common import \
17-
basic_check_fortran_code, basic_check_fortran_ast, \
18-
basic_check_python_code, basic_check_python_ast, \
19-
APPS_ROOT, APPS_RESULTS_ROOT, execute_on_examples
16+
APPS_RESULTS_ROOT
2017

2118
_LOG = logging.getLogger(__name__)
2219

@@ -95,34 +92,6 @@ def _prepare_roundtrip(case, language: Language):
9592
return parser, ast_generalizer, unparser
9693

9794

98-
def _roundtrip_fortran(case, path, results_path, parser, ast_generalizer, unparser):
99-
with path.open() as original_file:
100-
basic_check_fortran_code(case, path, original_file.read(), results=results_path,
101-
suffix=None)
102-
fortran_ast = parser.parse('', path)
103-
basic_check_fortran_ast(case, path, fortran_ast, results=results_path)
104-
tree = ast_generalizer.generalize(fortran_ast)
105-
basic_check_python_ast(case, path, tree, results=results_path)
106-
# python_code = python_unparser.unparse(tree)
107-
# basic_check_python_code(self, path, python_code, results=results_path)
108-
# tree = python_parser.parse(python_code)
109-
# basic_check_python_ast(self, path, tree, results=results_path)
110-
fortran_code = unparser.unparse(tree)
111-
basic_check_fortran_code(case, path, fortran_code, results=results_path)
112-
113-
114-
def _migrate_fortran(case, path, results_path, parser, ast_generalizer, unparser):
115-
with path.open() as original_file:
116-
basic_check_fortran_code(case, path, original_file.read(), results=results_path,
117-
suffix=None)
118-
fortran_ast = parser.parse('', path)
119-
basic_check_fortran_ast(case, path, fortran_ast, results=results_path)
120-
tree = ast_generalizer.generalize(fortran_ast)
121-
basic_check_python_ast(case, path, tree, results=results_path)
122-
python_code = unparser.unparse(tree)
123-
basic_check_python_code(case, path, python_code, results=results_path)
124-
125-
12695
class AppTests(unittest.TestCase):
12796

12897
app_name = None
@@ -140,132 +109,3 @@ def _test_app(self, tools, test, dir_name=None):
140109
for path in self.paths:
141110
with self.subTest(path=path):
142111
test(self, path, results_path, *tools)
143-
144-
145-
class FFBMiniTests(AppTests):
146-
147-
app_name = 'FFB-MINI'
148-
149-
app_source_folder = APPS_ROOT.joinpath('ffb-mini', 'src')
150-
151-
paths = [
152-
pathlib.Path(root, name) for root, _, files in os.walk(str(app_source_folder))
153-
for name in files if pathlib.Path(name).suffix in ('.f', '.F', '.f90', '.F90')
154-
and name not in {
155-
'ddcom4.F', # SyntaxError - just not implemented yet
156-
'ffb_mini_main.F90', # NotImplementedError
157-
'f_test.F90', # NotImplementedError
158-
'mod_maprof.F90', # NotImplementedError
159-
# OFP fails for the following files
160-
# issues need to be resolved upstream or files need to be modified
161-
'bcgs3x.F', 'bcgsxe.F', 'calax3.F', 'callap.F', 'dd_mpi.F', 'e2plst.F', 'extrfn.F',
162-
'gfutil.f', 'grad3x.F', 'les3x.F', 'lesrop.F', 'lesrpx.F', 'lessfx.F', 'lrfnms.F',
163-
'makemesh.F90', 'miniapp_util.F', 'mfname.F', 'neibr2.F', 'nodlex.F', 'pres3e.F',
164-
'rcmelm.F', 'rfname.F', 'srfexx.F', 'vel3d1.F', 'vel3d2.F'}]
165-
166-
@unittest.skipUnless(os.environ.get('TEST_LONG'), 'skipping long test')
167-
def test_roundtrip(self):
168-
self._test_app(_prepare_roundtrip(self, Language.find('Fortran')), _roundtrip_fortran)
169-
170-
171-
class Flash5Tests(unittest.TestCase):
172-
173-
app_name = 'FLASH5'
174-
175-
app_source_folder = APPS_ROOT.joinpath('flash5', 'source')
176-
177-
paths = path_selection_tree(app_source_folder, {
178-
# pathlib.Path('physics', 'Eos', 'EosMain', 'Helmholtz_starkiller',
179-
# 'SpeciesBased'): 'actual_eos.F90', # access specifiers (i.e public/private)
180-
pathlib.Path('physics', 'Hydro', 'HydroMain', 'unsplit'): [
181-
'hy_getFaceFlux.F90',
182-
# 'hy_getRiemannState.F90', # need to preprocess 1 macro
183-
'hy_TVDslope.F90',
184-
'hy_upwindTransverseFlux.F90', pathlib.Path('MHD', 'hy_eigenVector.F90')],
185-
pathlib.Path('physics', 'sourceTerms', 'Burn'): {
186-
'BurnMain': {
187-
'nuclearBurn': [
188-
'Burn.F90', 'bn_burner.F90', 'bn_azbar.F90', 'bn_screen4.F90', 'bn_sneutx.F90',
189-
'bn_mcord.F90'],
190-
pathlib.Path('nuclearBurn', 'Aprox13'): [
191-
'bn_mapNetworkToSpecies.F90', 'bn_networkTable.F90', 'bn_networkRates.F90',
192-
'bn_networkScreen.F90', 'bn_network.F90', 'bn_networkSparseJakob.F90',
193-
'bn_networkSparsePointers.F90', 'bn_networkDenseJakob.F90', 'bn_gift.F90']},
194-
'BurnIntegrate': ['bn_netIntegrate.F90', 'bn_baderMa28.F90', 'bn_rosenMa28.F90']},
195-
pathlib.Path('Simulation'): 'Simulation_init.F90'
196-
})
197-
paths.append(app_source_folder.parent.joinpath('lib', 'ma28', 'source', 'Ma28.F90'))
198-
199-
@unittest.skipUnless(os.environ.get('TEST_LONG'), 'skipping long test')
200-
@execute_on_examples(paths)
201-
def test_roundtrip(self, input_path):
202-
reader = CodeReader()
203-
fortran_code = reader.read_file(input_path)
204-
results_path = pathlib.Path(APPS_RESULTS_ROOT, 'flash5')
205-
results_path.mkdir(exist_ok=True)
206-
basic_check_fortran_code(self, input_path, fortran_code, results=results_path, suffix=None)
207-
parser = Parser.find(Language.find('Fortran'))()
208-
fortran_ast = parser.parse(fortran_code, input_path)
209-
basic_check_fortran_ast(self, input_path, fortran_ast, results=results_path)
210-
ast_generalizer = AstGeneralizer.find(Language.find('Fortran'))()
211-
syntax = ast_generalizer.generalize(fortran_ast)
212-
basic_check_python_ast(self, input_path, syntax, results=results_path)
213-
unparser = Unparser.find(Language.find('Fortran'))()
214-
code = unparser.unparse(syntax)
215-
basic_check_fortran_code(self, input_path, code, results=results_path)
216-
217-
def test_partial_inline_burn(self):
218-
_ = self.app_source_folder.joinpath(
219-
'physics', 'sourceTerms', 'Burn', 'BurnMain', 'nuclearBurn')
220-
inlined_path = _.joinpath('Aprox13', 'bn_mapNetworkToSpecies.F90')
221-
target_path = _.joinpath('Burn.F90')
222-
223-
reader = CodeReader()
224-
inlined_code = reader.read_file(inlined_path)
225-
target_code = reader.read_file(target_path)
226-
227-
parser = Parser.find(Language.find('Fortran'))()
228-
inlined_fortran_ast = parser.parse(inlined_code, inlined_path)
229-
# inlined_fortran_ast = inlined_fortran_ast.find('.//subroutine')
230-
target_fortran_ast = parser.parse(target_code, target_path)
231-
232-
ast_generalizer = AstGeneralizer.find(Language.find('Fortran'))()
233-
inlined_syntax = ast_generalizer.generalize(inlined_fortran_ast)
234-
inlined_function = inlined_syntax.body[-1]
235-
# TODO: implement object finding to find function
236-
target_syntax = ast_generalizer.generalize(target_fortran_ast)
237-
target_function = target_syntax.body[-1]
238-
# TODO: implement object finding to find function
239-
240-
# import horast
241-
# print(horast.unparse(inlined_function))
242-
# print(horast.unparse(target_function))
243-
# import ipdb; ipdb.set_trace()
244-
245-
# import static_typing
246-
inlined_syntax = inline_syntax(
247-
target_function, inlined_function,
248-
# globals_={'NSPECIES': 13, 'st': static_typing, **globals()},
249-
verbose=True)
250-
annotation = horast_nodes.OpenAccPragma('parallel loop')
251-
annotate_loop_syntax(inlined_syntax, annotation)
252-
253-
unparser = Unparser.find(Language.find('Fortran'))()
254-
transformed_code = unparser.unparse(inlined_syntax)
255-
256-
results_path = pathlib.Path(APPS_RESULTS_ROOT, 'flash5-inlined')
257-
results_path.mkdir(exist_ok=True)
258-
CodeWriter().write_file(transformed_code, results_path.joinpath('Burn.inlined_some.F90'))
259-
260-
261-
@unittest.skipUnless(os.environ.get('TEST_MIRANDA'), 'skipping tests on MIRANDA code')
262-
class MirandaIOTests(AppTests):
263-
264-
app_name = 'miranda_io'
265-
266-
app_source_folder = APPS_ROOT.joinpath('miranda_io')
267-
268-
paths = [app_source_folder.joinpath('miranda_io.f90')]
269-
270-
def test_roundtrip_miranda_io(self):
271-
self._test_app(_prepare_roundtrip(self, Language.find('Fortran')), _roundtrip_fortran)

0 commit comments

Comments
 (0)