exaoutput.py 11.8 KB
Newer Older
1
2
3

import os
from pathlib import Path
4
from tempfile import gettempdir
5
import subprocess
6
7
8
9
10
from collections import OrderedDict
from pylatexenc.latexencode import utf8tolatex, utf82latex


def remove_ensuremaths():
11
    """remove ensuremath wrappers in utf82latex before translating back from unicode to latex"""
12
13
14
15
16
17
    for key, value in utf82latex.items():
        if value.startswith('\\ensuremath{'):
            utf82latex[key] = value.replace('\\ensuremath{', '', 1)[:-1]


class ExaOutput:
18
19
20
    """generates configuration files for exastencils,
        but only if simdata is given"""
    def __init__(self, simdata=None, username="user", probname=None):
21
        remove_ensuremaths()
22
        self.exastencils_path = Path.home().joinpath("./exastencils")
23

24
        self.username = username
25
        self.l1_string = ""
26
27
28

        if probname is None:
            self.probname = self.username
29
30
31
        else:
            self.probname = probname

32
33
        #output parameters which should also be made adaptable at some point
        self.platform = OrderedDict([
34
35
36
37
38
                            ("targetOS", "Linux"),
                           ("targetCompiler", "GCC"),
                           ("targetCompilerVersion", 5),
                           ("targetCompilerVersionMinor", 4),
                           ("simd_instructionSet", "AVX")
39
40
                           ])
        self.settings = OrderedDict([
41
42
43
44
45
46
47
48
            ("user", self.username),
            ("configName", self.probname),
            ("basePathPrefix", "./" + self.probname),
            ("l1file", "$configName$.exa1"),
            ("debugL1File", "../Debug/$configName$_debug.exa1"),
            ("debugL2File", "../Debug/$configName$_debug.exa2"),
            ("debugL3File", "../Debug/$configName$_debug.exa3"),
            ("debugL4File", "../Debug/$configName$_debug.exa4"),
49
50
            ("htmlLogFile", "../Debug/$configName$_log.html"),
            ("outputPath", "../generated/$configName$/"),
51
52
            ("produceHtmlLog", True),
            ("timeStrategies", True),
53
54
            ("buildfileGenerators", "{ \"MakefileGenerator\" }")
        ])
55
        self.tmppath = Path(gettempdir())
56
57
        self.dirpath = self.exastencils_path.joinpath(self.probname)
        self.filespath = self.dirpath.joinpath(self.probname)
58
59
60
61
62
63
64
65
66
67
        ff = [self.dirpath]  # , self.tmppath.joinpath("generated"), self.tmppath.joinpath("Debug")]
        for f in ff:
            if not os.path.exists(str(f)):
                try:
                    os.makedirs(str(f))
                except OSError as exc:# Guard against race condition
                    if exc.errno != errno.EEXIST:
                        raise
            # # and link it into the exastencils directory
            # os.symlink(str(f), str(self.exastencils_path.joinpath(os.path.basename(os.path.normpath(f)))))
68
69
70
71
72
73
74
75
76
        if simdata is not None:
            self.create_settings()
    #        self.create_platform()
            self.create_knowledge()
            self.create_l1(simdata)
            self.create_examples_list_file()
    #        self.create_l2(simdata)
    #        self.create_l3()
    #        self.create_l4()
77
78

    def create_l1(self, simdata):
79
        l1path = str(self.filespath.with_suffix('.exa1'))
80
        domain_name = utf8tolatex(simdata["domain"]["name"], non_ascii_only=True, brackets=False)
81
        op = utf8tolatex(self.replace_cdot(simdata["pdes"]["pdes"][-1]["op"]), non_ascii_only=True, brackets=False)
82
83
        bc_rhs = self.replace_cdot(self.replace_boundary_x(simdata["bcs"]["bcs"][-1]["rhsstring_expanded"])) #TODO expand
        pde_rhs = self.replace_x(self.replace_cdot(simdata["pdes"]["pdes"][-1]["rhsstring_expanded"]))
84
85
        unknowns = [*simdata["unknowns"]]
        first_unknown = unknowns[0]
Theresa Pollinger's avatar
Theresa Pollinger committed
86
        self.l1_string = str(
87
88
                "/// inline knowledge \n"
                "Knowledge { \n"
Theresa Pollinger's avatar
Theresa Pollinger committed
89
                "  dimensionality = " + str(simdata["num_dimensions"]) + " \n"
90
91
92
93
94
95
96
                " \n"
                "  minLevel       = 5 \n"
                "  maxLevel       = 15 \n"
                "} \n"
                " \n"
                "/// problem specification \n"
                " \n"
Theresa Pollinger's avatar
Theresa Pollinger committed
97
                "Domain \Omega = ( " + str(simdata["domain"]["from"]) + ", " + str(simdata["domain"]["to"]) + " ) \n"
98
                " \n"
Theresa Pollinger's avatar
Theresa Pollinger committed
99
100
                "Field f@finest \in \Omega = " + pde_rhs + " \n"
                "Field " + first_unknown + " \in \Omega = 0.0 \n"
101
                " \n"
102
103
                "Field " + first_unknown + "@finest \in \partial \Omega = " + bc_rhs + " \n" #"sin ( 0.5 * PI * vf_boundaryCoord_x ) \n" #TODO expand
                "Field " + first_unknown + "@(all but finest) \in \partial \Omega = 0.0 \n"
104
                " \n"
Theresa Pollinger's avatar
Theresa Pollinger committed
105
                "Operator op = " + op + " // alt: - \partial_{xx} \n"
106
                " \n"
107
108
                "Equation " + first_unknown + "Eq@finest           op * " + first_unknown + " == f \n" #insert pde
                "Equation " + first_unknown + "Eq@(all but finest) op * " + first_unknown + " == 0.0 \n"
109
110
111
112
113
                " \n"
                "/// configuration of inter-layer transformations \n"
                " \n"
                "DiscretizationHints { // alt: Discretize, L2Hint(s) \n"
                "  f on Node \n"
114
                "  " + first_unknown + " on Node \n"
115
116
117
                " \n"
                "  op on \Omega \n"
                " \n"
118
                "  " + first_unknown + "Eq \n"
119
120
121
122
123
124
                " \n"
                "  // paramters \n"
                "  discr_type = \"" + simdata["sim"]["type"] + "\" \n"
                "} \n"
                " \n"
                "SolverHints { // alt: Solve, L3Hint(s) \n"
125
                "  generate solver for " + first_unknown + " in " + first_unknown + "Eq \n"
126
127
128
129
130
131
132
133
                " \n"
                "  // parameters \n"
                "  solver_targetResReduction = 1e-6 \n"
                "} \n"
                " \n"
                "ApplicationHints { // alt L4Hint(s) \n"
                "  // parameters \n"
                "  l4_genDefaultApplication = true \n"
134
                "  l4_defAppl_FieldToPrint = \"" + first_unknown + "\" \n" #TODO
Theresa Pollinger's avatar
Theresa Pollinger committed
135
136
137
                "} \n")
        with open(l1path, 'w') as l1:
            l1.write(self.l1_string)
138
139

    def replace_x(self, string):
140
141
142
143
        return string.replace("x", "vf_nodePosition_x@current")

    def replace_cdot(self, string):
        return string.replace("⋅", "*")
144
145
146
147
148

    def replace_boundary_x(self, string):
        return string.replace("x", "vf_boundaryCoord_x")

    def create_l2(self, simdata):
149
        l2path = str(self.filespath.with_suffix('.exa2'))
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
        with open(l2path,'w') as l2:
            l2.write(
                "Domain global< " + simdata["domain"]["from"] + " to " + simdata["domain"]["to"] + " > \n" # TODO domain goes here
                "\n"
                "Field Solution with Real on Node of global = 0.0 \n" #TODO codomain goes here
                "Field Solution@finest on boundary = vf_boundaryCoord_x ** 2 \n" # TODO BCs go here
                "Field Solution@(all but finest) on boundary = 0.0 \n"
                "\n"
                "Field RHS with Real on Node of global = 0.0 \n" #TODO RHS goes here
                #"Operator Laplace from kron ( Laplace_1D, Laplace_1D ) \n"
                "Operator Laplace_1D from Stencil { \n"
                "   [ 0] => 2.0 / ( vf_gridWidth_x ** 2 ) \n"
                "   [-1] => -1.0 / ( vf_gridWidth_x ** 2 ) \n"
                "   [ 1] => -1.0 / ( vf_gridWidth_x ** 2 ) \n"
                "\n"
                "Equation solEq@finest { \n"
                "    Laplace_1D * Solution == RHS \n"
                "} \n"
                "\n"
                "Equation solEq@(all but finest) { \n"
                "    Laplace_1D * Solution == 0.0 \n"
                "} \n"
            )

    def create_l3(self):
175
176
        l3path = str(self.filespath.with_suffix('.exa3'))
        with open(l3path, 'w') as l3:
177
178
179
180
181
            l3.write(
                "generate solver for Solution in solEq \n"
            )

    def create_l4(self):
182
        l4path = str(self.filespath.with_suffix('.exa4'))
183
        with open(l4path, 'w') as l4:
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
            l4.write(
                "Function Application ( ) : Unit { \n"
                "   startTimer ( 'setup' ) \n"
                "\n"
                "   initGlobals ( ) \n"
                "   initDomain ( ) \n"
                "   initFieldsWithZero ( ) \n"
                "   initGeometry ( ) \n"
                "   InitFields ( ) \n"
                "\n"
                "   stopTimer ( 'setup' ) \n"
                "\n"
                "   startTimer ( 'solve' ) \n"
                "\n"
                "   Solve@finest ( ) \n"
                "\n"
                "   stopTimer ( 'solve' ) \n"
                "\n"
                "   printAllTimers ( ) \n"
                "\n"
                "   destroyGlobals ( ) \n"
                "} \n"
            )

    def key_val(self, key, val):
        return key.ljust(30) + ' = ' + val + '\n'

    def format_key_val(self, key, val):
212
213
214
215
        val_repr = repr(val).replace('\'', '\"')
        if isinstance(val, bool):
            val_repr = val_repr.lower()
        return self.key_val(key, val_repr)
216
217
218
219
220

    def format_key(self, key, dict):
        return self.format_key_val(key, dict[key])

    def create_settings(self):
221
222
        settingspath = str(self.filespath) + '.settings'
        with open(settingspath, 'w') as settingsfile:
223
            for key in self.settings:
224
225
226
227
                if key == "buildfileGenerators":
                    settingsfile.write(self.key_val(key, self.settings[key]))
                else:
                    settingsfile.write(self.format_key(key, self.settings))
228
229

    def create_platform(self):
230
        platformpath = str(self.filespath) + '.platform'
231
        with open(platformpath, 'w') as platformfile:
232
233
234
235
            for key in self.platform:
                platformfile.write(self.format_key(key, self.platform))

    def create_knowledge(self):
236
        knowledgepath = str(self.filespath) + '.knowledge'
237
        with open(knowledgepath, 'w') as knowledgefile:
238
239
240
241
242
243
244
#            for key in self.knowledge:
#                knowledgefile.write(self.format_key(key, self.knowledge))
            knowledgefile.write(
                "// omp parallelization on exactly one fragment in one block \n"
                "import '../lib/domain_onePatch.knowledge' \n"
                "import '../lib/parallelization_pureOmp.knowledge'"
            )
245
246
247
248
249
250
251
252
253

    def create_examples_list_file(self):
        examples_path = str(self.exastencils_path.joinpath("examples").with_suffix('.sh'))
        with open(examples_path, 'w') as shell_file:
            shell_file.write(
                "#!/usr/bin/env bash \n"\
                "\n"
                "\n"
                "configList=\"\" \n"\
254
                "configList+=\"{}/{} \" \n".format(self.probname, self.probname)) #(self.dirpath, self.probname))
255

256
257
258
class ExaRunner:
    """A class to run exastencils using the files generated by an Exaoutput class, and to get the results"""

259
260
261
262
263
    from functools import lru_cache

    def __init__(self, exaout):
        self.exaout = exaout

264
    def run_exastencils(self):
265
        # print(str(os.path.abspath(self.exaout.exastencils_path)))
266
267
268
269
270
271
        p = subprocess.run(["./generate_compile_and_run_list.sh"], cwd=str(self.exaout.exastencils_path),
                           stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
        out = p.stdout
        if p.returncode != 0:
            print(out)

272
    @lru_cache()
273
    def load_data(self, data_name="u"):  # TODO more dimensions
274
        import pandas as pd
275
276
        data_path = self.exaout.exastencils_path.joinpath("generated").joinpath(self.exaout.probname)\
                                                .joinpath(data_name).with_suffix(".dat")
277
278
        df = pd.read_csv(data_path, sep=' ', index_col=0)
        try:
279
            df.columns = [data_name]
280
        except ValueError:  # length mismatch because additional column of nans was read
281
            df.columns = [data_name, 'nan']
282
        return df