9from .Helper
import write_file
11from .CompileMode
import CompileMode
15 """Represents the created Makefile of a Peano 4 project"""
17 default_overwrite =
True
24 result_template = jinja2.Template(
28~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
30CXXFLAGS = {{CXXFLAGS}}
36CONFIGUREPATH = {{CONFIGUREPATH}}
37EXECUTABLENAME = {{EXECUTABLENAME}}
38FORTRAN_MODULES = {{FORTRAN_MODULES}}
40~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
44~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
46~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
51 version_string = subprocess.run(
52 [self.
d[
"CXX"],
"--version"], stdout=subprocess.PIPE
55 version_string = subprocess.run(
56 [
"echo",
"Unknown"], shell=
True, stdout=subprocess.PIPE
58 self.
d[
"VERSION"] = version_string.stdout.decode(
"utf-8")
63 return jinja2.Template(
67### MPI parallelisation
69Peano's distributed memory parallelisation is based upon plain space-filling
70curves which are used first to split the cells among the ranks, and, after
71that, to split the cells into chunks and deploy them onto cores (if shared
72memory is used). There is no particularly novel contribution/paper on this
73aspect of the code. The paper that is (algorithmically) most interesting is
74an old EuroPar publication:
76 @InProceedings{Bungartz:2006:Parallelisation,
77 author={Bungartz, Hans-Joachim and Mehl, Miriam and Weinzierl, Tobias},
78 editor={Nagel, Wolfgang E. and Walter, Wolfgang V. and Lehner, Wolfgang},
79 title={A Parallel Adaptive Cartesian PDE Solver Using Space--Filling Curves},
80 booktitle={Euro-Par 2006 Parallel Processing},
82 publisher={Springer Berlin Heidelberg},
83 address={Berlin, Heidelberg},
85 abstract={In this paper, we present a parallel multigrid PDE solver working on adaptive hierarchical cartesian grids. The presentation is restricted to the linear elliptic operator of second order, but extensions are possible and have already been realised as prototypes. Within the solver the handling of the vertices and the degrees of freedom associated to them is implemented solely using stacks and iterates of a Peano space--filling curve. Thus, due to the structuredness of the grid, two administrative bits per vertex are sufficient to store both geometry and grid refinement information. The implementation and parallel extension, using a space--filling curve to obtain a load balanced domain decomposition, will be formalised. In view of the fact that we are using a multigrid solver of linear complexity {\\$}{\\backslash}mathcal{\\{}O{\\}}(n){\\$}, it has to be ensured that communication cost and, hence, the parallel algorithm's overall complexity do not exceed this linear behaviour.},
86 isbn={978-3-540-37784-9}
92### OpenMP parallelisation
94Peano 4 run uses a wrapper around OpenMP to obtain a high task efficiency.
95The wrapper can be read as user-level threading implemented on top of OpenMP's
96tasking mechanism. It is described in
98 @article{Schulz:2021:Tasking,
99 title = {Task inefficiency patterns for a wave equation solver},
102 author = {Holger Schulz and Gonzalo Brito Gadeschi and Oleksandr Rudyy and Tobias Weinzierl},
109Peano relies on a mixture of classic domain decomposition and task-based
110parallelism. The domain decomposition provides the baseline performance,
111and the tasking adds the big flexibility and scalability gain on top. The
112key publication discussing the overall idea and algorithmic ingredients is
115 @article{Charrier:2020:Enclave,
116 author = {Charrier, Dominic Etienne and Hazelwood, Benjamin and Weinzierl, Tobias},
117 title = {Enclave Tasking for DG Methods on Dynamically Adaptive Meshes},
118 journal = {SIAM Journal on Scientific Computing},
123 doi = {10.1137/19M1276194},
124 URL = {https://doi.org/10.1137/19M1276194},
125 eprint = {https://doi.org/10.1137/19M1276194}
134 return self.
d[
"EXECUTABLENAME"]
140 self.
d[
"CXXFLAGS"] =
""
142 self.
d[
"FCFLAGS"] =
""
143 self.
d[
"LDFLAGS"] =
""
144 self.
d[
"LIBS"] =
"-lomp"
146 self.
d[
"CONFIGUREPATH"] =
"."
147 self.
d[
"EXECUTABLENAME"] =
""
148 self.
d[
"CMAKE_BUILD_DIR"] =
""
149 self.
d[
"FORTRAN_MODULES"] = []
150 self.
d[
"APP_SUBDIRECTORIES"] = []
155 self.
d[
"EXECUTABLENAME"] = fname
166 self.
d[
"DIM"] = str(dimension)
170 Returns the directory where the ./configure script is located
172 return self.
d[
"CONFIGUREPATH"]
176 Returns the directory where the ./configure script is located
182 Add the header search path to both the C++ and the Fortran
185 self.
d[
"CXXFLAGS"] +=
" -I" + path
186 self.
d[
"FCFLAGS"] +=
" -I" + path
190 If you want to link against a library from Peano, feel free to use
191 get_Peano4_source_directory() and hand in a concatenation of this
192 path plus a subpath. Otherwise, specify the absolute path where to
193 search for. By default, Peano's src directory is in the search
196 A popular invocation including one of Peano's toolboxes is
198 project.output.makefile.add_library("ToolboxFiniteElements2d_trace", project.output.makefile.get_source_path() + "/toolbox/finiteelements")
200 if library_path !=
"":
201 self.
d[
"LIBS"] =
"-L" + library_path +
" " + self.
d[
"LIBS"]
202 self.
d[
"LIBS"] += library_name +
" "
206 mode should be of type CompileMode. Pass in
208 peano4.api.output.CompileMode.DEBUG
210 for example. Debug is the default.
212 if mode == CompileMode.DEBUG:
213 self.
d[
"MODE"] =
"DEBUG"
214 elif mode == CompileMode.ASSERTS:
215 self.
d[
"MODE"] =
"ASSERTS"
216 elif mode == CompileMode.STATS:
217 self.
d[
"MODE"] =
"STATS"
218 elif mode == CompileMode.TRACE:
219 self.
d[
"MODE"] =
"TRACE"
220 elif mode == CompileMode.RELEASE:
221 self.
d[
"MODE"] =
"RELEASE"
226 self.
d[
"CXX"] = value
229 self.
d[
"CXXFLAGS"] = value
232 if value
in self.
d[
"CXXFLAGS"]
and not force:
236 +
" is already in list of flags. Ignored as force attribute is not set"
239 self.
d[
"CXXFLAGS"] +=
" " + value
245 self.
d[
"FCFLAGS"] = value
248 if value
in self.
d[
"FCFLAGS"]
and not force:
252 +
" is already in list of flags. Ignored as force attribute is not set"
255 self.
d[
"FCFLAGS"] +=
" " + value
258 self.
d[
"LDFLAGS"] +=
" " + value
261 self.
d[
"LDFLAGS"] = value +
" "
265 directory should point to the directory which holds the ./configure script.
266 It furthermore has to be invoked after configure has passed successfully.
267 This script does not accept relative paths. We then search for the subdirectory
268 src and parse the Makefile there.
270 if 'PEANO_SRC_ROOT_DIR' in os.environ:
271 directory = os.environ[
'PEANO_SRC_ROOT_DIR']
273 self.
d[
"CONFIGUREPATH"] = directory
275 if 'PEANO_CMAKE_BUILD_DIR' in os.environ:
276 self.
d[
"CMAKE_BUILD_DIR"] = os.environ[
'PEANO_CMAKE_BUILD_DIR']
279 input_file = directory +
"/config.log"
280 input = open(input_file,
"r")
282 print(
"parse configure outcome " + input_file +
" to extract configure settings")
292 print(
"found the configure call info " + line)
294 for define
in MakefileDefined:
295 if re.search(
"#define " + define, line):
298 input_file = directory +
"/src/Makefile"
299 input = open(input_file,
"r")
300 print(
"parse configure outcome " + input_file +
" to extract compile settings")
301 MakefileConstants = [
302 "CXXFLAGS_PEANO_2D_RELEASE",
303 "CXXFLAGS_PEANO_2D_STATS",
304 "CXXFLAGS_PEANO_2D_ASSERTS",
305 "CXXFLAGS_PEANO_2D_TRACE",
306 "CXXFLAGS_PEANO_2D_DEBUG",
307 "CXXFLAGS_PEANO_3D_RELEASE",
308 "CXXFLAGS_PEANO_3D_STATS",
309 "CXXFLAGS_PEANO_3D_ASSERTS",
310 "CXXFLAGS_PEANO_3D_TRACE",
311 "CXXFLAGS_PEANO_3D_DEBUG",
312 "LDFLAGS_PEANO_RELEASE",
313 "LDFLAGS_PEANO_STATS",
314 "LDFLAGS_PEANO_ASSERTS",
315 "LDFLAGS_PEANO_TRACE",
316 "LDFLAGS_PEANO_DEBUG",
317 "LDADD_PEANO_2D_RELEASE",
318 "LDADD_PEANO_2D_STATS",
319 "LDADD_PEANO_2D_ASSERTS",
320 "LDADD_PEANO_2D_TRACE",
321 "LDADD_PEANO_2D_DEBUG",
322 "LDADD_PEANO_3D_RELEASE",
323 "LDADD_PEANO_3D_STATS",
324 "LDADD_PEANO_3D_ASSERTS",
325 "LDADD_PEANO_3D_TRACE",
326 "LDADD_PEANO_3D_DEBUG",
337 for constant
in MakefileConstants:
338 if re.search(constant +
" *=", line)
and line.startswith(constant):
340 flags = line.split(
"=", 1)[1].strip()
342 self.
d[constant] = flags
344 print(
"Error in " + line +
" for token " + constant)
347 self.
d[
"CMAKE_BUILD_DIR"] = next((path
for path
in (os.path.join(directory, subdir)
for subdir
in os.listdir(directory))
if os.path.isfile(os.path.join(path,
"PeanoTargets.cmake"))),
"")
350 if self.
d[
"CMAKE_BUILD_DIR"] !=
"":
351 cmake_cache_file = self.
d[
"CMAKE_BUILD_DIR"] +
"/CMakeCache.txt"
352 if os.path.isfile(cmake_cache_file):
353 with open(cmake_cache_file,
'r')
as input:
355 key_value = line.split(
"=", 1)
356 if len(key_value) == 2:
357 key, value = key_value
358 key = key.split(
":")[0].strip()
359 if key ==
"CMAKE_CXX_COMPILER":
360 self.
d[
"CXX"] = value.strip()
361 if key ==
"CMAKE_Fortran_COMPILER":
362 self.
d[
"FC"] = value.strip()
365 Error: if you call parse_configure_script_outcome(), please hand over directory where
366 ./configure had been called. You passed """ + directory
371 Add a new header filename.
372 This is actually not needed for compilation,
373 but is useful to have for IDEs where the header files can be displayed
377 Filename of a C/C++ header file. They usually should have the .h/.hpp extension.
379 Use this flag for generated files which can be tracked
380 by the cleaning routines 'distclean' or 'maintainer-clean' of the Makefile.
385 and self.
hfiles.count(filename) == 0
389 if self.
hfiles.count(filename) == 0:
390 self.
hfiles.append(filename)
397 if filename
in self.
hfiles:
398 self.
hfiles.remove(filename)
402 Add a new cpp filename. This is basically a set implementation, i.e., you can
403 add files multiple times, but they are not inserted multiple times. This
404 is important, as the steps add the cpp files. Multiple steps can hold the
405 same action, so this action would be created multiple times.
407 All the standard Peano 4 routines rely on this function to add their
408 generated files to the build environment. Nothing stops you however to
409 add more files yourself.
412 Filename of a C++ file. They usually should have the .cpp/.cxx extension.
414 Use this flag for generated files which can be tracked
415 by the cleaning routines 'distclean' or 'maintainer-clean' of the Makefile.
422 and self.
cppfiles.count(filename) == 0
427 if self.
cppfiles.count(filename) == 0:
443 Add a new Fortran file.
445 All the standard Peano 4 routines rely on this function to add their
446 generated files to the build environment. Nothing stops you however to
447 add more files yourself. Don't add a file multiple times. This might
450 Fortran is really picky about the translation order. So you have to add
451 the stuff in the right order. Otherwise, Fortran might complain. This is
454 If your file defines a module, please do not use this routine, but use
455 add_Fortran_module() instead.
458 Filename of a Fortran file. They usually should have the .f90 extension.
460 Use this flag for generated files which can be tracked
461 by the cleaning routines 'distclean' or 'maintainer-clean' of the Makefile.
486 Filename of a Fortran source code file which hosts a module. It should
487 have the extension .f90 or similar.
490 Enforce that Fortran module is added even though it might already be in
493 if not module_file.endswith(
".f90"):
495 "Warning: Fortran module file does not have extension .f90 ("
497 +
") and translation thus might fail"
499 if module_file
in self.
d[
"FORTRAN_MODULES"]
and not force:
501 """Fortran module file
505is already in module file list. Did not add it once more. You can overwrite
506this default behaviour via the force attribute in add_Fortran_module(). If
507you create multiple Peano 4 makefiles in a row (as you change parameters, e.g.)
508then this message can typically be ignored.
511 elif module_file
in self.
d[
"FORTRAN_MODULES"]
and force:
513 "Fortran module file "
515 +
" is already in module file list but force flag is set. Add it"
517 self.
d[
"FORTRAN_MODULES"].append(module_file)
519 self.
d[
"FORTRAN_MODULES"].append(module_file)
522 for i
in module_files:
525 def generate(self, overwrite, directory, subdirectories=[]):
527 Generates build files and other project-related files based on templates.
529 :param overwrite: Specifies whether existing files should be overwritten.
530 :type overwrite: bool
531 :param directory: The directory where the generated files will be placed.
534 self.
d[
"H_HEADERS"] = self.
hfiles
541 for subdirectory
in subdirectories:
542 self.
d[
"APP_SUBDIRECTORIES"].append(subdirectory)
545 def generate_output_file(input_file_path, output_file_path):
547 print(
"write " + output_file_path)
548 template_loader = jinja2.FileSystemLoader(searchpath=os.path.split(input_file_path)[0])
549 templateEnv = jinja2.Environment(loader=template_loader)
550 template = templateEnv.get_template(os.path.split(input_file_path)[1])
551 with open(output_file_path,
"w")
as output:
552 output.write(template.render(self.
d))
554 file_dir = os.path.dirname(os.path.realpath(__file__))
556 generate_output_file(os.path.join(file_dir,
"Gitignore.template"), os.path.join(directory,
".gitignore"))
558 if self.
d[
"CMAKE_BUILD_DIR"] !=
"":
559 generate_output_file(os.path.join(file_dir,
"CMakeLists.txt.template"), os.path.join(directory,
"CMakeLists.txt"))
561 generate_output_file(os.path.join(file_dir,
"Makefile.cmake.template"), os.path.join(directory,
"Makefile"))
563 generate_output_file(os.path.join(file_dir,
"Makefile.template"), os.path.join(directory,
"Makefile"))
Represents the created Makefile of a Peano 4 project.
get_configure_path(self)
Returns the directory where the .
add_CXX_flag(self, value, force=False)
add_linker_flag(self, value)
add_Fortran_module(self, module_file, force=False)
Add a Fortran module.
set_CXX_flags(self, value)
add_Fortran_file(self, filename, generated=False)
Add a new Fortran file.
add_Fortran_modules(self, module_files)
set_dimension(self, dimension)
set_Fortran_flags(self, value)
get_source_path(self)
Returns the directory where the .
add_Fortran_flag(self, value, force=False)
remove_Fortran_file(self, filename)
set_Fortran_compiler(self, value)
set_CXX_compiler(self, value)
remove_h_file(self, filename)
parse_configure_script_outcome(self, directory)
directory should point to the directory which holds the .
add_library(self, library_name, library_path="")
If you want to link against a library from Peano, feel free to use get_Peano4_source_directory() and ...
add_cpp_file(self, filename, generated=False)
Add a new cpp filename.
add_header_search_path(self, path)
Add the header search path to both the C++ and the Fortran call command.
set_linker_flags(self, value)
generate(self, overwrite, directory, subdirectories=[])
Generates build files and other project-related files based on templates.
readme_package_descriptor(self)
set_executable_name(self, fname)
remove_cpp_file(self, filename)
add_h_file(self, filename, generated=False)
Add a new header filename.
set_mode(self, mode)
mode should be of type CompileMode.