feectools 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. feectools/__init__.py +0 -0
  2. feectools/accelerate/__init__.py +0 -0
  3. feectools/accelerate/accelerate.py +220 -0
  4. feectools/accelerate/compile_psydac.mk +52 -0
  5. feectools/api/__init__.py +0 -0
  6. feectools/api/essential_bc.py +122 -0
  7. feectools/api/fem_bilinear_form.py +2226 -0
  8. feectools/api/fem_common.py +286 -0
  9. feectools/api/fem_sum_form.py +123 -0
  10. feectools/api/settings.py +82 -0
  11. feectools/core/__init__.py +11 -0
  12. feectools/core/bsplines.py +1107 -0
  13. feectools/core/bsplines_kernels.py +1349 -0
  14. feectools/core/field_evaluation_kernels.py +5015 -0
  15. feectools/core/tests/__init__.py +0 -0
  16. feectools/core/tests/test_bsplines.py +263 -0
  17. feectools/core/tests/test_bsplines_kernel.py +40 -0
  18. feectools/core/tests/test_bsplines_pyccel.py +752 -0
  19. feectools/ddm/__init__.py +3 -0
  20. feectools/ddm/basic.py +78 -0
  21. feectools/ddm/blocking_data_exchanger.py +348 -0
  22. feectools/ddm/cart.py +1835 -0
  23. feectools/ddm/interface_data_exchanger.py +122 -0
  24. feectools/ddm/mpi.py +109 -0
  25. feectools/ddm/nonblocking_data_exchanger.py +331 -0
  26. feectools/ddm/partition.py +207 -0
  27. feectools/ddm/petsc.py +112 -0
  28. feectools/ddm/tests/__init__.py +0 -0
  29. feectools/ddm/tests/test_cart_1d.py +138 -0
  30. feectools/ddm/tests/test_cart_2d.py +164 -0
  31. feectools/ddm/tests/test_cart_3d.py +158 -0
  32. feectools/ddm/tests/test_multicart_2d.py +173 -0
  33. feectools/ddm/tests/test_partition.py +124 -0
  34. feectools/ddm/utilities.py +24 -0
  35. feectools/feec/__init__.py +0 -0
  36. feectools/feec/derivatives.py +780 -0
  37. feectools/feec/dof_kernels.py +210 -0
  38. feectools/feec/global_geometric_projectors.py +1073 -0
  39. feectools/feec/hodge.py +148 -0
  40. feectools/fem/__init__.py +0 -0
  41. feectools/fem/basic.py +465 -0
  42. feectools/fem/grid.py +181 -0
  43. feectools/fem/partitioning.py +344 -0
  44. feectools/fem/projectors.py +160 -0
  45. feectools/fem/splines.py +559 -0
  46. feectools/fem/tensor.py +1393 -0
  47. feectools/fem/tests/__init__.py +0 -0
  48. feectools/fem/tests/analytical_profiles_1d.py +100 -0
  49. feectools/fem/tests/analytical_profiles_base.py +34 -0
  50. feectools/fem/tests/splines_error_bounds.py +155 -0
  51. feectools/fem/tests/test_spline_histopolation.py +120 -0
  52. feectools/fem/tests/test_spline_interpolation.py +182 -0
  53. feectools/fem/tests/test_splines.py +184 -0
  54. feectools/fem/tests/test_splines_par.py +46 -0
  55. feectools/fem/tests/test_vector_spaces.py +150 -0
  56. feectools/fem/tests/utilities.py +47 -0
  57. feectools/fem/vector.py +729 -0
  58. feectools/linalg/__init__.py +0 -0
  59. feectools/linalg/basic.py +1386 -0
  60. feectools/linalg/block.py +1451 -0
  61. feectools/linalg/direct_solvers.py +201 -0
  62. feectools/linalg/fft.py +258 -0
  63. feectools/linalg/kernels/__init__.py +0 -0
  64. feectools/linalg/kernels/axpy_kernels.py +57 -0
  65. feectools/linalg/kernels/inner_kernels.py +100 -0
  66. feectools/linalg/kernels/matvec_kernels.py +206 -0
  67. feectools/linalg/kernels/stencil2IJV_kernels.py +227 -0
  68. feectools/linalg/kernels/stencil2coo_kernels.py +179 -0
  69. feectools/linalg/kernels/transpose_kernels.py +263 -0
  70. feectools/linalg/kron.py +911 -0
  71. feectools/linalg/solvers.py +1914 -0
  72. feectools/linalg/sparse.py +114 -0
  73. feectools/linalg/stencil.py +2923 -0
  74. feectools/linalg/stencil_dot_kernels.py +317 -0
  75. feectools/linalg/stencil_transpose_kernels.py +372 -0
  76. feectools/linalg/tests/__init__.py +0 -0
  77. feectools/linalg/tests/test_block.py +1588 -0
  78. feectools/linalg/tests/test_fft.py +106 -0
  79. feectools/linalg/tests/test_kron_stencil_matrix.py +114 -0
  80. feectools/linalg/tests/test_linalg.py +1065 -0
  81. feectools/linalg/tests/test_matrix_free.py +128 -0
  82. feectools/linalg/tests/test_solvers.py +213 -0
  83. feectools/linalg/tests/test_stencil_interface_matrix.py +379 -0
  84. feectools/linalg/tests/test_stencil_vector.py +1036 -0
  85. feectools/linalg/tests/test_stencil_vector_space.py +440 -0
  86. feectools/linalg/topetsc.py +522 -0
  87. feectools/linalg/utilities.py +200 -0
  88. feectools/utilities/__init__.py +0 -0
  89. feectools/utilities/quadratures.py +113 -0
  90. feectools/utilities/utils.py +166 -0
  91. feectools/version.py +1 -0
  92. feectools-0.1.0.dist-info/METADATA +66 -0
  93. feectools-0.1.0.dist-info/RECORD +98 -0
  94. feectools-0.1.0.dist-info/WHEEL +5 -0
  95. feectools-0.1.0.dist-info/entry_points.txt +3 -0
  96. feectools-0.1.0.dist-info/licenses/AUTHORS +22 -0
  97. feectools-0.1.0.dist-info/licenses/LICENSE +21 -0
  98. feectools-0.1.0.dist-info/top_level.txt +1 -0
feectools/__init__.py ADDED
File without changes
File without changes
@@ -0,0 +1,220 @@
1
+ # Based on https://gitlab.mpcdf.mpg.de/struphy/struphy/-/blob/devel/src/struphy/console/compile.py
2
+ import argparse
3
+ import os
4
+ import sys
5
+ from shutil import which, rmtree
6
+ from subprocess import run as sub_run, PIPE, STDOUT # nosec B404
7
+ import subprocess
8
+ import sysconfig
9
+
10
+ import feectools
11
+
12
+ # Get the absolute path to the psydac directory
13
+ psydac_path = os.path.abspath(feectools.__path__[0])
14
+ libdir = sysconfig.get_config_var("LIBDIR")
15
+ psydac_makefile_dir = os.path.join(psydac_path, "accelerate")
16
+
17
+ def subp_run(cmd, cwd=None, check=True):
18
+ """Call subprocess.run and print run command."""
19
+
20
+ if cwd is None:
21
+ cwd = psydac_path
22
+
23
+ print(f"\nRunning the following command as a subprocess:\n{' '.join(cmd)}")
24
+ print(f"Running in directory: {cwd}")
25
+ subprocess.run(cmd, cwd=cwd, check=check)
26
+
27
+
28
+ def psydac_compile(language, compiler_family, compiler_config, omp, delete, status, verbose, dependencies, yes):
29
+ """
30
+ Compile Psydac kernels. All files that contain "kernels" are detected automatically and saved to state.yml.
31
+
32
+ Parameters
33
+ ----------
34
+ language : str
35
+ Either "c" (default) or "fortran".
36
+
37
+ compiler_family : str
38
+ Either "GNU" (default), "intel", "PGI", "nvidia", "LLVM"
39
+
40
+ compiler_config: str
41
+ Path to a JSON compiler file.
42
+
43
+ omp_pic : bool
44
+ Whether to compile PIC kernels with OpenMP (default=False).
45
+
46
+ omp_feec : bool
47
+ WHether to compile FEEC kernels with OpenMP (default=False).
48
+
49
+ delete : bool
50
+ If True, deletes generated Fortran/C files and .so files (default=False).
51
+
52
+ status : bool
53
+ If true, prints the current Psydac compilation status on screen.
54
+
55
+ verbose : bool
56
+ Call pyccel in verbose mode (default=False).
57
+
58
+ dependencies : bool
59
+ Whether to print Psydac kernels (to be compiled) and their dependencies on screen.
60
+
61
+ yes : bool
62
+ Whether to say yes to prompt when changing the language.
63
+ """
64
+ if delete:
65
+ cleanup_files(psydac_path)
66
+ return
67
+
68
+ pyccel_path = which("pyccel")
69
+ if pyccel_path is None:
70
+ print(
71
+ "`pyccel` not found in PATH. Please ensure it is installed and accessible."
72
+ )
73
+ return
74
+
75
+ sources = []
76
+ # Cleanup if any files of the opposite language exist
77
+ cleanup = False
78
+ for root, _, files in os.walk(psydac_path):
79
+ for name in files:
80
+ if name.endswith("_kernels.py"):
81
+ file_path = os.path.join(root, name)
82
+ sources.append(file_path)
83
+ # Check if the corresponding pyccelized file already exists
84
+ subdir = "__pyccel__"
85
+ generated_file_fortran = os.path.join(root, subdir, name[:-3] + ".f90")
86
+ generated_file_c = os.path.join(root, subdir, name[:-3] + ".c")
87
+ if language == "fortran" and os.path.isfile(generated_file_c):
88
+ cleanup = True
89
+ elif language == "c" and os.path.isfile(generated_file_fortran):
90
+ cleanup = True
91
+ if cleanup:
92
+ if yes:
93
+ yesno = "Y"
94
+ else:
95
+ if language == "fortran":
96
+ compiled_in = "C"
97
+ else:
98
+ compiled_in = "fortran"
99
+ yesno = input(
100
+ f"Kernels compiled in language {compiled_in} exist, will be deleted, continue (Y/n)?"
101
+ )
102
+ if yesno in ("", "Y", "y", "yes"):
103
+ cleanup_files(psydac_path)
104
+ else:
105
+ return
106
+
107
+ # pyccel flags
108
+ # TODO: Compile psydac with OpenMP
109
+ flag_omp = ""
110
+ if omp:
111
+ flag_omp = "--openmp"
112
+ sources = " ".join(sources)
113
+ flags = "--language=" + language
114
+
115
+ if compiler_config:
116
+ flags += " --compiler-config=" + compiler_config
117
+ else:
118
+ flags += " --compiler-family=" + compiler_family
119
+
120
+ cmd = [
121
+ "make",
122
+ "-f",
123
+ "compile_psydac.mk",
124
+ "sources=" + sources,
125
+ "flags=" + flags,
126
+ "flags_openmp=" + flag_omp,
127
+ ]
128
+ print(os.path.join(libdir, "accelerate"))
129
+ subp_run(cmd, cwd=psydac_makefile_dir),
130
+
131
+
132
+ def cleanup_files(root_path: str):
133
+ """
134
+ Remove unnecessary build artifacts, such as `__pyccel__` directories and `.lock_acquisition.lock` files.
135
+ """
136
+ sources = []
137
+ for root, _, files in os.walk(root_path):
138
+ for filename in files:
139
+ if filename.endswith("_kernels.py"):
140
+ file_path = os.path.join(root, filename)
141
+ sources.append(file_path)
142
+ sources = " ".join(sources)
143
+ # Delete using the makefile
144
+ cmd = [
145
+ "make",
146
+ "clean",
147
+ "-f",
148
+ "compile_psydac.mk",
149
+ "sources=" + sources,
150
+ ]
151
+ subp_run(cmd, cwd=psydac_makefile_dir)
152
+
153
+
154
+ def main():
155
+ parser = argparse.ArgumentParser(
156
+ description="Pyccelize Psydac kernel files and optionally clean up build artifacts.",
157
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter,
158
+ )
159
+ parser.add_argument(
160
+ "--language",
161
+ type=str,
162
+ default="c",
163
+ choices=["fortran", "c"],
164
+ help="Language used to pyccelize kernel files.",
165
+ )
166
+ parser.add_argument(
167
+ "--openmp",
168
+ action="store_true",
169
+ help="Use OpenMP multithreading in generated code.",
170
+ )
171
+ parser.add_argument(
172
+ "--cleanup",
173
+ action="store_true",
174
+ help="If True, deletes generated Fortran/C files and .so files (default=False).",
175
+ )
176
+ parser.add_argument(
177
+ "--compiler-family",
178
+ type=str,
179
+ default="GNU",
180
+ help='either "GNU" (default), "intel", "PGI", "nvidia" or the path to a JSON compiler file.',
181
+ )
182
+
183
+ parser.add_argument(
184
+ "--compiler-config",
185
+ type=str,
186
+ default=None,
187
+ help='Path to a JSON compiler file.',
188
+ )
189
+
190
+ parser.add_argument(
191
+ "--status", action="store_true", help="Show the status of pyccelization."
192
+ )
193
+ parser.add_argument("--verbose", action="store_true", help="Enable verbose output.")
194
+ parser.add_argument(
195
+ "--dependencies",
196
+ action="store_true",
197
+ help="Print Psydac kernels to be compiled (.py) and their dependencies (.so) on screen.",
198
+ )
199
+ parser.add_argument(
200
+ "--yes", action="store_true", help="Automatically answer 'yes' to prompts."
201
+ )
202
+
203
+ args = parser.parse_args()
204
+
205
+ # Assuming psydac_compile is a function defined elsewhere
206
+ psydac_compile(
207
+ language=args.language,
208
+ compiler_family=args.compiler_family,
209
+ compiler_config=args.compiler_config,
210
+ omp=args.openmp,
211
+ delete=args.cleanup,
212
+ status=args.status,
213
+ verbose=args.verbose,
214
+ dependencies=args.dependencies,
215
+ yes=args.yes,
216
+ )
217
+
218
+
219
+ if __name__ == "__main__":
220
+ main()
@@ -0,0 +1,52 @@
1
+ # Based on https://gitlab.mpcdf.mpg.de/struphy/struphy/-/blob/devel/src/struphy/compile_struphy.mk
2
+ #--------------------------------------
3
+ # CONFIGURATION
4
+ #--------------------------------------
5
+
6
+ PYTHON := python3
7
+ SO_EXT := $(shell $(PYTHON) -c "import sysconfig; print(sysconfig.get_config_var('EXT_SUFFIX'))")
8
+ LIBDIR := $(shell $(PYTHON) -c "import sysconfig; print(sysconfig.get_config_var('LIBDIR'))")
9
+ psydac_path := $(shell $(PYTHON) -c "import feectools as _; print(_.__path__[0])")
10
+
11
+ # Arguments to this script are:
12
+ PSYDAC_SOURCES := $(sources)
13
+ FLAGS := --libdir $(LIBDIR) $(flags)
14
+ FLAGS_openmp := $(flags_openmp)
15
+
16
+ #--------------------------------------
17
+ # SOURCE FILES
18
+ #--------------------------------------
19
+
20
+ SOURCES := $(PSYDAC_SOURCES)
21
+
22
+ OUTPUTS := $(SOURCES:.py=$(SO_EXT))
23
+
24
+ #--------------------------------------
25
+ # PYCCELIZE
26
+ #--------------------------------------
27
+
28
+ .PHONY: all
29
+ all: $(OUTPUTS)
30
+
31
+ # %$(SO_EXT) : %.py $$(shell $$(PYTHON)) $$(psydac_path)/dependencies.py $$@)
32
+ .SECONDEXPANSION:
33
+ %$(SO_EXT): %.py
34
+
35
+ @echo "Building $@"
36
+ @echo "from dependencies:"
37
+ @for dep in $^ ; do \
38
+ echo $$dep ; \
39
+ done
40
+ pyccel $(FLAGS)$(FLAGS_openmp) $<
41
+ @echo ""
42
+
43
+ #--------------------------------------
44
+ # CLEAN UP
45
+ #--------------------------------------
46
+
47
+ .PHONY: clean
48
+ clean:
49
+ rm -rf $(OUTPUTS)
50
+ find $(psydac_path)/ -type d -name '__pyccel__' -prune -exec rm -rf {} \;
51
+ find $(psydac_path)/ -type d -name '__pycache__' -prune -exec rm -rf {} \;
52
+ find $(psydac_path)/ -type f -name '*.lock' -delete
File without changes
@@ -0,0 +1,122 @@
1
+ # coding: utf-8
2
+ from feectools.linalg.basic import ComposedLinearOperator
3
+ from feectools.linalg.stencil import StencilVector, StencilMatrix
4
+ from feectools.linalg.stencil import StencilInterfaceMatrix
5
+ from feectools.linalg.kron import KroneckerDenseMatrix
6
+ from feectools.linalg.block import BlockVector, BlockLinearOperator
7
+
8
+
9
+ #==============================================================================
10
+ def apply_essential_bc_kronecker_dense_matrix(a, *, axis, ext, order, identity=False):
11
+ """ This function applies the homogeneous boundary condition to the Kronecker product matrix objects,
12
+ If the identity keyword argument is set to True, the boundary diagonal terms are set to 1.
13
+
14
+ Parameters
15
+ ----------
16
+ a : KroneckerDenseMatrix
17
+ The matrix to be modified.
18
+
19
+ axis : int
20
+ Axis of the boundary, i.e. the index of the coordinate which remains constant.
21
+
22
+ ext : int
23
+ Extremity of the boundary, it takes the value of -1 or 1.
24
+
25
+ order : int
26
+ All function derivatives up to `order` are set to zero
27
+ on the specified boundary. `order >= 0` is required.
28
+
29
+ identity : bool
30
+ If true, the diagonal terms corresponding to boundary coefficients are set to 1.
31
+ """
32
+
33
+ mats = a.mats
34
+ p = a.codomain.pads[axis]
35
+
36
+ if ext == 1:
37
+ mats[axis][-p-1] = 0.
38
+ elif ext == -1:
39
+ mats[axis][p] = 0.
40
+
41
+ if identity and ext == 1:
42
+ mats[axis][-p-1,mats[axis].shape[0]-2*p-1] = 1
43
+ elif identity and ext == -1:
44
+ mats[axis][p][0] = 1
45
+
46
+ #==============================================================================
47
+ def apply_essential_bc_stencil(a, *, axis, ext, order, identity=False):
48
+ """ This function applies the homogeneous boundary condition to the Stencil objects,
49
+ by setting the boundary degrees of freedom to zero in the StencilVector,
50
+ and the corresponding rows in the StencilMatrix/StencilInterfaceMatrix to zeros.
51
+ If the identity keyword argument is set to True, the boundary diagonal terms are set to 1.
52
+
53
+ Parameters
54
+ ----------
55
+ a : StencilVector, StencilMatrix or StencilInterfaceMatrix
56
+ The matrix or the Vector to be modified.
57
+
58
+ axis : int
59
+ Axis of the boundary, i.e. the index of the coordinate which remains constant.
60
+
61
+ ext : int
62
+ Extremity of the boundary, it takes the value of -1 or 1.
63
+
64
+ order : int
65
+ All function derivatives up to `order` are set to zero
66
+ on the specified boundary. `order >= 0` is required.
67
+
68
+ identity : bool
69
+ If True, the diagonal terms corresponding to boundary coefficients are set to 1.
70
+ """
71
+
72
+ if isinstance(a, StencilVector):
73
+ V = a.space
74
+ n = V.ndim
75
+ elif isinstance(a, StencilMatrix):
76
+ V = a.codomain
77
+ n = V.ndim * 2
78
+ elif isinstance(a, StencilInterfaceMatrix):
79
+ V = a.codomain
80
+ n = V.ndim * 2
81
+
82
+ if axis == a.codomain_axis:
83
+ return
84
+ else:
85
+ raise TypeError('Cannot apply essential BC to object {} of type {}'\
86
+ .format(a, type(a)))
87
+
88
+ if V.parallel and V.cart.is_comm_null:
89
+ return
90
+
91
+ if axis not in range(V.ndim):
92
+ raise ValueError('Cannot apply essential BC along axis x{} in {}D'\
93
+ .format(axis + 1, V.ndim))
94
+
95
+ if ext not in (-1, 1):
96
+ raise ValueError("Argument 'ext' can only be -1 or 1, got {} instead"\
97
+ .format(ext))
98
+
99
+ if not isinstance(order, int) or order < 0:
100
+ raise ValueError("Argument 'order' must be a non-negative integer, got "
101
+ "{} instead".format(order))
102
+
103
+ if V.periods[axis]:
104
+ raise ValueError('Cannot apply essential BC along periodic direction '\
105
+ 'x{}'.format(axis + 1))
106
+
107
+ if ext == -1 and V.starts[axis] == 0:
108
+ s = V.starts[axis]
109
+ index = [(s + order if j == axis else slice(None)) for j in range(n)]
110
+ a[tuple(index)] = 0.0
111
+ if isinstance(a, StencilMatrix) and identity:
112
+ a[tuple(index[:n//2])+(0,)*(n//2)] = 1.
113
+
114
+ elif ext == 1 and V.ends[axis] == V.npts[axis] - 1:
115
+ e = V.ends[axis]
116
+ index = [(e - order if j == axis else slice(None)) for j in range(n)]
117
+ a[tuple(index)] = 0.0
118
+ if isinstance(a, StencilMatrix) and identity:
119
+ a[tuple(index[:n//2])+(0,)*(n//2)] = 1.
120
+ else:
121
+ pass
122
+