specnn4pde 0.0.2__tar.gz
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.
- specnn4pde-0.0.2/LICENSE +21 -0
- specnn4pde-0.0.2/PKG-INFO +53 -0
- specnn4pde-0.0.2/README.md +24 -0
- specnn4pde-0.0.2/mxwpy/__init__.py +0 -0
- specnn4pde-0.0.2/mxwpy/linalg.py +57 -0
- specnn4pde-0.0.2/mxwpy/npde.py +338 -0
- specnn4pde-0.0.2/mxwpy/spectral.py +464 -0
- specnn4pde-0.0.2/mxwpy/tools.py +201 -0
- specnn4pde-0.0.2/setup.cfg +4 -0
- specnn4pde-0.0.2/setup.py +36 -0
- specnn4pde-0.0.2/specnn4pde.egg-info/PKG-INFO +53 -0
- specnn4pde-0.0.2/specnn4pde.egg-info/SOURCES.txt +13 -0
- specnn4pde-0.0.2/specnn4pde.egg-info/dependency_links.txt +1 -0
- specnn4pde-0.0.2/specnn4pde.egg-info/requires.txt +7 -0
- specnn4pde-0.0.2/specnn4pde.egg-info/top_level.txt +1 -0
specnn4pde-0.0.2/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Mingxing Weng
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: specnn4pde
|
|
3
|
+
Version: 0.0.2
|
|
4
|
+
Summary: Solving partial differential equations using spectral methods and neural networks.
|
|
5
|
+
Home-page: https://github.com/mxweng/specnn4pde
|
|
6
|
+
Author: MXWeng
|
|
7
|
+
Author-email: 2431141461@qq.com
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Intended Audience :: Science/Research
|
|
18
|
+
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
19
|
+
Requires-Python: >=3.6
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Requires-Dist: GPUtil
|
|
23
|
+
Requires-Dist: IPython
|
|
24
|
+
Requires-Dist: numpy
|
|
25
|
+
Requires-Dist: pandas
|
|
26
|
+
Requires-Dist: psutil
|
|
27
|
+
Requires-Dist: scipy
|
|
28
|
+
Requires-Dist: sympy
|
|
29
|
+
|
|
30
|
+
# SpecNN4PDE
|
|
31
|
+
SpecNN4PDE is an under development Python library for solving partial differential equations using spectral methods and neural networks. It consists of the following modules:
|
|
32
|
+
|
|
33
|
+
- `spectral`: Provides functions for working with spectral methods as described in the book [Spectral Methods: Algorithms, Analysis and Applications](https://link.springer.com/book/10.1007/978-3-540-71041-7) by Shen, Tang, and Wang.
|
|
34
|
+
- `linalg`: This module primarily focuses on numerical algebra methods.
|
|
35
|
+
- `tools`: A collection of utility functions for system and package information retrieval, time measurement, etc.
|
|
36
|
+
- `npde`: Functions for solving partial differential equations, e.g., calculating the multivariate derivatives.
|
|
37
|
+
|
|
38
|
+
This project is still in the early stages of development, and the API is subject to change. The library is designed to be used in research and educational settings.
|
|
39
|
+
|
|
40
|
+
## Dependencies
|
|
41
|
+
|
|
42
|
+
When you install this library using pip, most dependencies will be automatically handled. However, please note that the `npde` module requires PyTorch, which needs to be installed separately.
|
|
43
|
+
|
|
44
|
+
You can install PyTorch by following the instructions on the [official PyTorch website](https://pytorch.org/get-started/locally/). Please ensure that you select the correct installation command based on your operating system, package manager, Python version, and the specifications of your CUDA toolkit if you are planning to use PyTorch with GPU support.
|
|
45
|
+
|
|
46
|
+
If you are not planning to use the `npde` module, you do not need to install PyTorch.
|
|
47
|
+
|
|
48
|
+
## Installation
|
|
49
|
+
|
|
50
|
+
To install this library, you can use pip:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
pip install specnn4pde
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# SpecNN4PDE
|
|
2
|
+
SpecNN4PDE is an under development Python library for solving partial differential equations using spectral methods and neural networks. It consists of the following modules:
|
|
3
|
+
|
|
4
|
+
- `spectral`: Provides functions for working with spectral methods as described in the book [Spectral Methods: Algorithms, Analysis and Applications](https://link.springer.com/book/10.1007/978-3-540-71041-7) by Shen, Tang, and Wang.
|
|
5
|
+
- `linalg`: This module primarily focuses on numerical algebra methods.
|
|
6
|
+
- `tools`: A collection of utility functions for system and package information retrieval, time measurement, etc.
|
|
7
|
+
- `npde`: Functions for solving partial differential equations, e.g., calculating the multivariate derivatives.
|
|
8
|
+
|
|
9
|
+
This project is still in the early stages of development, and the API is subject to change. The library is designed to be used in research and educational settings.
|
|
10
|
+
|
|
11
|
+
## Dependencies
|
|
12
|
+
|
|
13
|
+
When you install this library using pip, most dependencies will be automatically handled. However, please note that the `npde` module requires PyTorch, which needs to be installed separately.
|
|
14
|
+
|
|
15
|
+
You can install PyTorch by following the instructions on the [official PyTorch website](https://pytorch.org/get-started/locally/). Please ensure that you select the correct installation command based on your operating system, package manager, Python version, and the specifications of your CUDA toolkit if you are planning to use PyTorch with GPU support.
|
|
16
|
+
|
|
17
|
+
If you are not planning to use the `npde` module, you do not need to install PyTorch.
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
To install this library, you can use pip:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
pip install specnn4pde
|
|
File without changes
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
__all__ = ['ROU_cholesky',
|
|
2
|
+
]
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
def ROU_cholesky(L, v, alpha=1, beta=1):
|
|
7
|
+
"""
|
|
8
|
+
Perform a rank-one update of the Cholesky decomposition of a matrix.
|
|
9
|
+
|
|
10
|
+
Parameters
|
|
11
|
+
----------
|
|
12
|
+
L : ndarray
|
|
13
|
+
The lower triangular Cholesky factor of the matrix A.
|
|
14
|
+
alpha : float
|
|
15
|
+
The scalar multiplier for the matrix. Must be non-negative.
|
|
16
|
+
beta : float
|
|
17
|
+
The scalar multiplier for the outer product of v. Must be non-negative.
|
|
18
|
+
v : ndarray
|
|
19
|
+
The vector used for the rank-one update.
|
|
20
|
+
|
|
21
|
+
Returns
|
|
22
|
+
----------
|
|
23
|
+
L_prime : ndarray
|
|
24
|
+
The updated lower triangular Cholesky factor of the matrix
|
|
25
|
+
\tilde{A} = alpha * A + beta * v * v^T.
|
|
26
|
+
|
|
27
|
+
References
|
|
28
|
+
----------
|
|
29
|
+
1. https://en.wikipedia.org/wiki/Cholesky_decomposition#Rank-one_update
|
|
30
|
+
2. Krause Oswin, Igel ChristianA, 2015,
|
|
31
|
+
More Efficient Rank-one Covariance Matrix Update for Evolution Strategies,
|
|
32
|
+
https://christian-igel.github.io/paper/AMERCMAUfES.pdf
|
|
33
|
+
|
|
34
|
+
Example
|
|
35
|
+
----------
|
|
36
|
+
>>> L = np.array([[1, 0, 0], [2, 1, 0], [3, 2, 1]])
|
|
37
|
+
>>> alpha = 2
|
|
38
|
+
>>> beta = 3
|
|
39
|
+
>>> v = np.array([1, 2, 3])
|
|
40
|
+
>>> L_prime = ROU_cholesky(L, v, alpha, beta)
|
|
41
|
+
>>> print(L_prime)
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
if alpha < 0 or beta < 0:
|
|
45
|
+
raise ValueError("alpha and beta must be non-negative")
|
|
46
|
+
|
|
47
|
+
n = L.shape[0]
|
|
48
|
+
L, x = np.sqrt(alpha) * L, np.sqrt(beta) * v
|
|
49
|
+
for k in range(n):
|
|
50
|
+
r = np.sqrt(L[k, k]**2 + x[k]**2)
|
|
51
|
+
c = r / L[k, k]
|
|
52
|
+
s = x[k] / L[k, k]
|
|
53
|
+
L[k, k] = r
|
|
54
|
+
if k < n - 1:
|
|
55
|
+
L[(k+1):n, k] = (L[(k+1):n, k] + s * x[(k+1):n]) / c
|
|
56
|
+
x[(k+1):n] = c * x[(k+1):n] - s * L[(k+1):n, k]
|
|
57
|
+
return L
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
__all__ = ['gradients', 'Jacobian', 'partial_derivative', 'partial_derivative_vector',
|
|
2
|
+
'meshgrid_to_matrix', 'gen_collo',
|
|
3
|
+
]
|
|
4
|
+
|
|
5
|
+
import torch
|
|
6
|
+
from torch.autograd.functional import jacobian
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def gradients(u, x, order=1, retain_graph=False):
|
|
10
|
+
"""
|
|
11
|
+
Compute the gradients for d dimensional function. It only supports two kinds of functions:
|
|
12
|
+
|
|
13
|
+
1. scalar function f(x1, x2, ..., xd)
|
|
14
|
+
The first order gradients are [df/dx1, df/dx2, ..., df/dxd]
|
|
15
|
+
2. vector function like F(x1,x2,...,xd) = [f1(x1), f2(x2), ..., fd(xd)]
|
|
16
|
+
The first order gradients are [df1/dx1, df2/dx2, ..., dfn/dxd]
|
|
17
|
+
|
|
18
|
+
Higher order gradients are also supported.
|
|
19
|
+
|
|
20
|
+
!!! For functions like F(x1, ..., xd) = [f1(x1, ..., xd), ..., fd(x1, ..., xd)],
|
|
21
|
+
use `partial_derivative_vector` instead.
|
|
22
|
+
|
|
23
|
+
Parameters
|
|
24
|
+
----------
|
|
25
|
+
u : tensor
|
|
26
|
+
The values of the function at the point x.
|
|
27
|
+
x : Tensor, shape (n, d)
|
|
28
|
+
The point at which to compute the gradients, where n is the number of points and d is the dimension.
|
|
29
|
+
order : int, optional
|
|
30
|
+
The order of the gradients. The default is 1.
|
|
31
|
+
retain_graph : bool, optional
|
|
32
|
+
Whether to retain the computational graph for further computation. Defaults to False.
|
|
33
|
+
|
|
34
|
+
Returns
|
|
35
|
+
----------
|
|
36
|
+
grads: list of tensors of shape like x
|
|
37
|
+
The gradients up to the order. grads[i] is the (i+1)-th order gradients.
|
|
38
|
+
|
|
39
|
+
Example
|
|
40
|
+
----------
|
|
41
|
+
>>> def f(x):
|
|
42
|
+
... return x**2
|
|
43
|
+
>>> x = torch.tensor([[1.0, 2], [3, 4], [5, 6]], requires_grad=True)
|
|
44
|
+
>>> u = f(x)
|
|
45
|
+
>>> gradients(u, x, 2)
|
|
46
|
+
[tensor([[ 2., 4.],
|
|
47
|
+
[ 6., 8.],
|
|
48
|
+
[10., 12.]]),
|
|
49
|
+
tensor([[2., 2.],
|
|
50
|
+
[2., 2.],
|
|
51
|
+
[2., 2.]])]
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
grads = [torch.autograd.grad(u, x, grad_outputs=torch.ones_like(u), create_graph=True)[0]]
|
|
55
|
+
for _ in range(1, order):
|
|
56
|
+
grads.append(torch.autograd.grad(grads[-1], x, grad_outputs=torch.ones_like(grads[-1]), create_graph=True)[0])
|
|
57
|
+
# clean the computational graph of the gradients to save memory
|
|
58
|
+
if not retain_graph:
|
|
59
|
+
grads = [g.detach() for g in grads]
|
|
60
|
+
return grads
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def Jacobian(f, x, order=1, create_graph=False):
|
|
64
|
+
"""
|
|
65
|
+
Compute the Jacobian of a vector function.
|
|
66
|
+
But only support univariate function. For multivariate vector function,
|
|
67
|
+
use `partial_derivative_vector` instead.
|
|
68
|
+
|
|
69
|
+
!!! Not suitale for high order derivatives, because
|
|
70
|
+
creating computational graphs will consume a lot of time and memory.
|
|
71
|
+
|
|
72
|
+
Parameters
|
|
73
|
+
----------
|
|
74
|
+
f : function
|
|
75
|
+
The function to compute the Jacobian for.
|
|
76
|
+
x : Tensor
|
|
77
|
+
The point at which to compute the Jacobian.
|
|
78
|
+
order : int, optional
|
|
79
|
+
The order of the derivative. Defaults to 1.
|
|
80
|
+
create_graph : bool, optional
|
|
81
|
+
Whether to create a computational graph. Defaults to False.
|
|
82
|
+
|
|
83
|
+
Returns
|
|
84
|
+
----------
|
|
85
|
+
Tensor
|
|
86
|
+
The Jacobian of the function at the given point.
|
|
87
|
+
|
|
88
|
+
Example
|
|
89
|
+
----------
|
|
90
|
+
>>> def f(x):
|
|
91
|
+
... return torch.cat([x, x**2], dim=1)
|
|
92
|
+
>>> x = torch.tensor([[1.0], [2], [3]])
|
|
93
|
+
>>> Jacobian(f, x)
|
|
94
|
+
tensor([[1., 2.],
|
|
95
|
+
[1., 4.],
|
|
96
|
+
[1., 6.]])
|
|
97
|
+
"""
|
|
98
|
+
|
|
99
|
+
def _f(*args, **kwargs):
|
|
100
|
+
return f(*args, **kwargs).sum(dim=0)
|
|
101
|
+
if order == 0:
|
|
102
|
+
return f(x) if create_graph else f(x).detach()
|
|
103
|
+
elif order == 1:
|
|
104
|
+
return jacobian(_f, x, create_graph).squeeze(2).T
|
|
105
|
+
else:
|
|
106
|
+
def _jacobian(x):
|
|
107
|
+
return jacobian(_f, x, True).squeeze(2).T
|
|
108
|
+
return Jacobian(_jacobian, x, order-1, create_graph)
|
|
109
|
+
|
|
110
|
+
def partial_derivative(F, X, Alpha, create_graph=False):
|
|
111
|
+
"""
|
|
112
|
+
Compute the partial derivative for vector-valued function but inefficient,
|
|
113
|
+
use `partial_derivative_vector` instead.
|
|
114
|
+
|
|
115
|
+
!!! Not suitale for high order derivatives, because
|
|
116
|
+
creating computational graphs will consume a lot of time and memory.
|
|
117
|
+
|
|
118
|
+
Parameters
|
|
119
|
+
----------
|
|
120
|
+
F : function
|
|
121
|
+
The function to compute the partial derivative for.
|
|
122
|
+
X : Tensor
|
|
123
|
+
The points at which to compute the partial derivative.
|
|
124
|
+
Alpha : list
|
|
125
|
+
The order of the derivative for each dimension.
|
|
126
|
+
create_graph : bool, optional
|
|
127
|
+
Whether to create a computational graph. Defaults to False.
|
|
128
|
+
|
|
129
|
+
Returns
|
|
130
|
+
----------
|
|
131
|
+
Tensor
|
|
132
|
+
The partial derivative of the function at the given points.
|
|
133
|
+
"""
|
|
134
|
+
|
|
135
|
+
if len(Alpha) == 1:
|
|
136
|
+
return Jacobian(F, X, Alpha[0], create_graph)
|
|
137
|
+
else:
|
|
138
|
+
X_perfix, x_last = X[:, :-1], X[:, -1:]
|
|
139
|
+
def _f(x):
|
|
140
|
+
def _F(X):
|
|
141
|
+
return F(torch.cat([X, x], dim=1))
|
|
142
|
+
return partial_derivative(_F, X_perfix, Alpha[:-1], True)
|
|
143
|
+
return Jacobian(_f, x_last, Alpha[-1], create_graph)
|
|
144
|
+
|
|
145
|
+
def partial_derivative_vector(F, X, Alpha, create_graph=False, batch_size=[15000,1]):
|
|
146
|
+
"""
|
|
147
|
+
Compute the partial derivatives for vector-valued function
|
|
148
|
+
F(x1, x2, ..., xn) = [f1(x1, x2, ..., xn), f2(x1, x2, ..., xn), ..., fk(x1, x2, ..., xn)],
|
|
149
|
+
return [\partial^\alpha f1, \partial^\alpha f2, ..., \partial^\alpha fn].
|
|
150
|
+
|
|
151
|
+
!!! Not suitale for high order derivatives, because
|
|
152
|
+
creating computational graphs will consume a lot of time and memory.
|
|
153
|
+
|
|
154
|
+
Parameters
|
|
155
|
+
----------
|
|
156
|
+
F : function
|
|
157
|
+
The function to compute the partial derivatives for.
|
|
158
|
+
X : tensor, shape (N, d)
|
|
159
|
+
The points at which to compute the partial derivatives, where N is the number of points and d is the dimension.
|
|
160
|
+
Alpha : list
|
|
161
|
+
The order of the derivative for each dimension.
|
|
162
|
+
create_graph : bool, optional
|
|
163
|
+
Whether to create a computational graph. Defaults to False.
|
|
164
|
+
batch_size : list, optional
|
|
165
|
+
The batch size for computing the partial derivatives.
|
|
166
|
+
batch_size[0] is the number of points in each batch,
|
|
167
|
+
and batch_size[1] is the number of functions in each batch.
|
|
168
|
+
Defaults to [15000, 1].
|
|
169
|
+
|
|
170
|
+
Returns
|
|
171
|
+
----------
|
|
172
|
+
Tensor, shape (k, N, d)
|
|
173
|
+
The partial derivatives of the function at the given points.
|
|
174
|
+
|
|
175
|
+
Example
|
|
176
|
+
----------
|
|
177
|
+
>>> def F(X):
|
|
178
|
+
... return X.prod(dim=1).unsqueeze(dim=1).repeat(1, 2)
|
|
179
|
+
>>> X = torch.tensor([[1.0, 2], [3, 4]])
|
|
180
|
+
>>> partial_derivative_vector(F, X, Alpha = [1, 1])
|
|
181
|
+
tensor([[1., 1.],
|
|
182
|
+
[1., 1.]])
|
|
183
|
+
"""
|
|
184
|
+
|
|
185
|
+
out_dim = F(X[:1]).shape[1]
|
|
186
|
+
res = []
|
|
187
|
+
for i in range(0, X.shape[0], batch_size[0]):
|
|
188
|
+
res_sub = []
|
|
189
|
+
for j in range(0, out_dim, batch_size[1]):
|
|
190
|
+
def _F(X): return F(X)[:, j:j+batch_size[1]]
|
|
191
|
+
res_sub.append(partial_derivative(_F, X[i:i+batch_size[0]], Alpha, create_graph))
|
|
192
|
+
res.append(torch.cat(res_sub, dim=1))
|
|
193
|
+
return torch.cat(res, dim=0)
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def meshgrid_to_matrix(inputs, indexing='xy'):
|
|
197
|
+
"""
|
|
198
|
+
Convert the meshgrid to matrix.
|
|
199
|
+
|
|
200
|
+
Parameters
|
|
201
|
+
----------
|
|
202
|
+
inputs : list of iterables, length d
|
|
203
|
+
The grid points in each dimension.
|
|
204
|
+
indexing : str, optional
|
|
205
|
+
The indexing of the meshgrid. The default is 'xy'.
|
|
206
|
+
The options are 'xy' and 'ij', the same as numpy.meshgrid and torch.meshgrid.
|
|
207
|
+
|
|
208
|
+
Returns
|
|
209
|
+
----------
|
|
210
|
+
tensor, shape ( n1*n2*...*nd, d)
|
|
211
|
+
The matrix of the grid points, ni is the number of grid points in the i-th dimension.
|
|
212
|
+
|
|
213
|
+
Example
|
|
214
|
+
----------
|
|
215
|
+
>>> x = torch.linspace(1, 2, 3)
|
|
216
|
+
>>> y = torch.linspace(4, 5, 3)
|
|
217
|
+
>>> meshgrid_to_matrix([x, y], indexing='xy')
|
|
218
|
+
tensor([[1.0000, 4.0000],
|
|
219
|
+
[1.5000, 4.0000],
|
|
220
|
+
[2.0000, 4.0000],
|
|
221
|
+
[1.0000, 4.5000],
|
|
222
|
+
[1.5000, 4.5000],
|
|
223
|
+
[2.0000, 4.5000],
|
|
224
|
+
[1.0000, 5.0000],
|
|
225
|
+
[1.5000, 5.0000],
|
|
226
|
+
[2.0000, 5.0000]])
|
|
227
|
+
>>> meshgrid_to_matrix([x, y], indexing='ij')
|
|
228
|
+
tensor([[1.0000, 4.0000],
|
|
229
|
+
[1.0000, 4.5000],
|
|
230
|
+
[1.0000, 5.0000],
|
|
231
|
+
[1.5000, 4.0000],
|
|
232
|
+
[1.5000, 4.5000],
|
|
233
|
+
[1.5000, 5.0000],
|
|
234
|
+
[2.0000, 4.0000],
|
|
235
|
+
[2.0000, 4.5000],
|
|
236
|
+
[2.0000, 5.0000]])
|
|
237
|
+
"""
|
|
238
|
+
|
|
239
|
+
Co = torch.meshgrid(*inputs, indexing=indexing)
|
|
240
|
+
return torch.cat([c.reshape(-1,1) for c in Co], dim=1)
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
def gen_collo(Domain, grids, temporal = False, corner = True):
|
|
244
|
+
"""
|
|
245
|
+
Generate the collocation points for the PDE problem on regular domain.
|
|
246
|
+
If Domain and grids are provided, the uniform grids will be generated automatically as G.
|
|
247
|
+
If Domain and grids are not provided, G should be provided.
|
|
248
|
+
|
|
249
|
+
Parameters
|
|
250
|
+
----------
|
|
251
|
+
Domain : list of list, optional
|
|
252
|
+
The domain of the problem. eg. [[t_min, x1_min, x2_min, ...], [t_max, x1_max, x2_max, ...]]
|
|
253
|
+
grids : list, optional
|
|
254
|
+
The number of collocations in each dimension. eg. [N_t, N_x1, N_x2, ...]
|
|
255
|
+
temporal : bool, optional
|
|
256
|
+
If the problem is temporal. The default is False.
|
|
257
|
+
corner : bool, optional
|
|
258
|
+
If the collocation points include the corner points. The default is True.
|
|
259
|
+
G : list of tensor, optional
|
|
260
|
+
The tensors in the list are the collocation points in each dimension.
|
|
261
|
+
If Domain and grids are not provided, G should be provided.
|
|
262
|
+
|
|
263
|
+
Returns
|
|
264
|
+
-------
|
|
265
|
+
collo_rs : tensor
|
|
266
|
+
The collocation points in the interior of the domain.
|
|
267
|
+
collo_ic : tensor, optional
|
|
268
|
+
If temporal is set as True. The collocation points on the initial condition.
|
|
269
|
+
collo_bc : tensor
|
|
270
|
+
The collocation points on the boundary condition.
|
|
271
|
+
|
|
272
|
+
Example
|
|
273
|
+
----------
|
|
274
|
+
>>> domian = [[0, 0, 1], [2, 3, 4]]
|
|
275
|
+
>>> grids = [3, 4, 5]
|
|
276
|
+
>>> gen_collo(domian, grids)
|
|
277
|
+
(tensor([[1.0000, 1.0000, 1.7500],
|
|
278
|
+
[1.0000, 1.0000, 2.5000],
|
|
279
|
+
[1.0000, 1.0000, 3.2500],
|
|
280
|
+
[1.0000, 2.0000, 1.7500],
|
|
281
|
+
[1.0000, 2.0000, 2.5000],
|
|
282
|
+
[1.0000, 2.0000, 3.2500]]),
|
|
283
|
+
tensor([[0.0000, 0.0000, 1.0000],
|
|
284
|
+
[0.0000, 0.0000, 1.7500],
|
|
285
|
+
[0.0000, 0.0000, 2.5000],
|
|
286
|
+
[0.0000, 0.0000, 3.2500],
|
|
287
|
+
[0.0000, 0.0000, 4.0000],
|
|
288
|
+
[2.0000, 0.0000, 1.0000],
|
|
289
|
+
......
|
|
290
|
+
[1.0000, 1.0000, 4.0000],
|
|
291
|
+
[1.0000, 2.0000, 1.0000],
|
|
292
|
+
[1.0000, 2.0000, 4.0000]]))
|
|
293
|
+
"""
|
|
294
|
+
|
|
295
|
+
if G is None:
|
|
296
|
+
dim = len(Domain[0])
|
|
297
|
+
if len(grids) != dim:
|
|
298
|
+
if len(grids) == 1:
|
|
299
|
+
Warning("The number of grids is set as the same for all dimensions.")
|
|
300
|
+
grids = grids * dim
|
|
301
|
+
else:
|
|
302
|
+
raise ValueError("The length of grids should be equal to the dimension of the domain.")
|
|
303
|
+
G = [torch.linspace(l, r, n) for l, r, n in zip(*(Domain + [grids]))]
|
|
304
|
+
dim = len(G)
|
|
305
|
+
if temporal:
|
|
306
|
+
G_rs = [G[0][1:]] + [G[i][1:-1] for i in range(1, dim)]
|
|
307
|
+
G_ic = [G[0][0]] + G[1:]
|
|
308
|
+
collo_rs = meshgrid_to_matrix(G_rs)
|
|
309
|
+
collo_ic = meshgrid_to_matrix(G_ic)
|
|
310
|
+
collo_bc = []
|
|
311
|
+
for i in range(1, dim):
|
|
312
|
+
G_bc = [G[0]]
|
|
313
|
+
for j in range(1, dim):
|
|
314
|
+
if j < i:
|
|
315
|
+
G_bc.append(G[j][1:-1])
|
|
316
|
+
elif j == i:
|
|
317
|
+
G_bc.append(G[j][[0,-1]])
|
|
318
|
+
else:
|
|
319
|
+
G_bc.append(G[j] if corner else G[j][1:-1])
|
|
320
|
+
collo_bc.append(meshgrid_to_matrix(G_bc))
|
|
321
|
+
collo_bc = torch.cat(collo_bc, dim=0)
|
|
322
|
+
return collo_rs, collo_ic, collo_bc
|
|
323
|
+
else:
|
|
324
|
+
G_rs = [G[i][1:-1] for i in range(dim)]
|
|
325
|
+
collo_rs = meshgrid_to_matrix(G_rs)
|
|
326
|
+
collo_bc = []
|
|
327
|
+
for i in range(dim):
|
|
328
|
+
G_bc = []
|
|
329
|
+
for j in range(dim):
|
|
330
|
+
if j < i:
|
|
331
|
+
G_bc.append(G[j][1:-1])
|
|
332
|
+
elif j == i:
|
|
333
|
+
G_bc.append(G[j][[0,-1]])
|
|
334
|
+
else:
|
|
335
|
+
G_bc.append(G[j] if corner else G[j][1:-1])
|
|
336
|
+
collo_bc.append(meshgrid_to_matrix(G_bc))
|
|
337
|
+
collo_bc = torch.cat(collo_bc, dim=0)
|
|
338
|
+
return collo_rs, collo_bc
|
|
@@ -0,0 +1,464 @@
|
|
|
1
|
+
__all__ = ['JacobiP', 'Jacobi_Gauss', 'Jacobi_Gauss_Lobatto',
|
|
2
|
+
'HermiteP', 'HermiteF', 'Hermite_Gauss', 'mapped_Jacobi_Gauss',
|
|
3
|
+
'glue1D', 'glue_pts_1D',
|
|
4
|
+
]
|
|
5
|
+
|
|
6
|
+
"""
|
|
7
|
+
spectral.py
|
|
8
|
+
|
|
9
|
+
This module provides functions for working with spectral methods.
|
|
10
|
+
The implementation is mainly based on the book:
|
|
11
|
+
Shen, J., Tang, T. & Wang, L.-L. Spectral Methods: Algorithms,
|
|
12
|
+
Analysis and Applications. vol. 41 (Springer Science & Business
|
|
13
|
+
Media, 2011).
|
|
14
|
+
https://link.springer.com/book/10.1007/978-3-540-71041-7
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
import numpy as np
|
|
18
|
+
from scipy.special import roots_hermite, gamma
|
|
19
|
+
from scipy.sparse import diags, eye, lil_matrix, csr_matrix
|
|
20
|
+
from scipy.linalg import eigh, block_diag
|
|
21
|
+
from sympy import symbols, sqrt, atanh, tanh, sinh, log, lambdify, diff
|
|
22
|
+
|
|
23
|
+
def JacobiP(x, alpha, beta, N):
|
|
24
|
+
"""
|
|
25
|
+
This function evaluates the orthonormal Jacobi polynomial of order
|
|
26
|
+
up to N with parameters alpha and beta at points x.
|
|
27
|
+
|
|
28
|
+
Parameters
|
|
29
|
+
----------
|
|
30
|
+
x : array
|
|
31
|
+
Points at which the Jacobi polynomial is to be computed.
|
|
32
|
+
alpha : float
|
|
33
|
+
The alpha parameter of the Jacobi polynomial. Must be greater than -1.
|
|
34
|
+
beta : float
|
|
35
|
+
The beta parameter of the Jacobi polynomial. Must be greater than -1.
|
|
36
|
+
N : int
|
|
37
|
+
The order of the Jacobi polynomial.
|
|
38
|
+
|
|
39
|
+
Returns
|
|
40
|
+
----------
|
|
41
|
+
PL: ndarray, shape (N + 1, len(x))
|
|
42
|
+
The N-th row of PL is the values of orthonormal Jacobi
|
|
43
|
+
polynomial J_{N}^{alpha, beta}(x) / sqrt(gamma_{N}^{alpha, beta}).
|
|
44
|
+
|
|
45
|
+
References:
|
|
46
|
+
----------
|
|
47
|
+
1. Spectral Method P74
|
|
48
|
+
2. Code-reproduction/Poisson-GPU.ipynb
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
xp = x.copy()
|
|
52
|
+
if len(xp.shape) == 2 and xp.shape[1] == 1:
|
|
53
|
+
xp = xp.T
|
|
54
|
+
PL = np.zeros((N + 1, max(xp.shape)))
|
|
55
|
+
gamma0 = np.power(2, alpha + beta + 1) * gamma(alpha + 1) * gamma(beta + 1) / gamma(alpha + beta + 2)
|
|
56
|
+
PL[0] = 1.0 / np.sqrt(gamma0)
|
|
57
|
+
if N == 0:
|
|
58
|
+
return PL.T
|
|
59
|
+
gamma1 = (alpha + 1) * (beta + 1) / (alpha + beta + 3) * gamma0
|
|
60
|
+
PL[1] = ((alpha + beta + 2) * xp / 2 + (alpha - beta) / 2) / np.sqrt(gamma1)
|
|
61
|
+
aold = 2 / (2 + alpha + beta) * np.sqrt((alpha + 1) * (beta + 1) / (alpha + beta + 3))
|
|
62
|
+
for i in range(1, N):
|
|
63
|
+
h1 = 2 * i + alpha + beta
|
|
64
|
+
anew = 2 / (h1 + 2) * np.sqrt((i + 1) * (i + 1 + alpha + beta) * (i + 1 + alpha) * (i + 1 + beta) / (h1 + 1) / (h1 + 3))
|
|
65
|
+
bnew = -(alpha * alpha - beta * beta) / h1 / (h1 + 2)
|
|
66
|
+
PL[i + 1] = 1 / anew * (-aold * PL[i - 1] + (xp - bnew) * PL[i])
|
|
67
|
+
aold = anew
|
|
68
|
+
return PL
|
|
69
|
+
|
|
70
|
+
def Jacobi_Gauss(alpha, beta, N):
|
|
71
|
+
"""
|
|
72
|
+
This function computes the Gauss Jacobi quadrature first order
|
|
73
|
+
derivative matrix, nodes and weights of Jacobi polynomial J_{N}^{alpha, beta}.
|
|
74
|
+
|
|
75
|
+
Parameters
|
|
76
|
+
----------
|
|
77
|
+
alpha : float
|
|
78
|
+
The alpha parameter of the Gauss Jacobi quadrature. alpha > -1.
|
|
79
|
+
beta : float
|
|
80
|
+
The beta parameter of the Gauss Jacobi quadrature. beta > -1.
|
|
81
|
+
If alpha = beta = 0, the Jacobi polynomial is Legendre polynomial.
|
|
82
|
+
N : int
|
|
83
|
+
The order of the Gauss Jacobi quadrature.
|
|
84
|
+
|
|
85
|
+
Returns
|
|
86
|
+
----------
|
|
87
|
+
D: ndarray, shape (N, N)
|
|
88
|
+
The first order derivative matrix of the Gauss Jacobi quadrature.
|
|
89
|
+
r: ndarray, shape (N,)
|
|
90
|
+
The Gauss Jacobi quadrature nodes.
|
|
91
|
+
w: ndarray, shape (N,)
|
|
92
|
+
The Gauss Jacobi quadrature weights.
|
|
93
|
+
|
|
94
|
+
References
|
|
95
|
+
----------
|
|
96
|
+
1. Spectral Method P84
|
|
97
|
+
"""
|
|
98
|
+
|
|
99
|
+
if N == 1:
|
|
100
|
+
D = np.zeros((1,1))
|
|
101
|
+
r = np.array([-(alpha - beta) / (alpha + beta + 2)])
|
|
102
|
+
w = np.array([2])
|
|
103
|
+
return D, r, w
|
|
104
|
+
|
|
105
|
+
h1 = 2.0 * np.arange(N) + alpha + beta
|
|
106
|
+
h11, h12, h13 = h1 + 1, h1 + 2, h1 + 3
|
|
107
|
+
h2 = 1.0 * np.arange(1, N)
|
|
108
|
+
# Adjust h1, h11, h12 values based on alpha and beta
|
|
109
|
+
# to avoid division by zero
|
|
110
|
+
if abs(alpha + beta) < 10 * np.finfo(float).eps:
|
|
111
|
+
h1[0] = 1.0
|
|
112
|
+
elif abs(alpha + beta + 1) < 10 * np.finfo(float).eps:
|
|
113
|
+
h11[0] = 1.0
|
|
114
|
+
elif abs(alpha + beta + 2) < 10 * np.finfo(float).eps:
|
|
115
|
+
h1[1], h12[0] = 1.0, 1.0
|
|
116
|
+
|
|
117
|
+
# equation (3.142) symmetric tridiagonal matrix A_{N+1}
|
|
118
|
+
A = diags(0.5 * (beta**2 - alpha**2) / h12 / h1).toarray() + \
|
|
119
|
+
diags(2 / h12[:-1] * np.sqrt(h2 * (h2 + alpha + beta) * \
|
|
120
|
+
(h2 + alpha) * (h2 + beta) / h11[:-1] / h13[:-1]), 1).toarray()
|
|
121
|
+
|
|
122
|
+
r, V = eigh(A + A.T)
|
|
123
|
+
# equation (3.144)
|
|
124
|
+
w = np.power(V[0, :], 2) * np.power(2, alpha + beta + 1) * \
|
|
125
|
+
gamma(alpha + 1) * gamma(beta + 1) / gamma(alpha + beta + 2)
|
|
126
|
+
|
|
127
|
+
l = JacobiP(r, alpha + 1, alpha + 1, N - 1)[-1]
|
|
128
|
+
# construct first order JG derivative matrix D by equation (3.164)
|
|
129
|
+
Distance = r[:, None] - r[None, :] + np.eye(N)
|
|
130
|
+
D = l[:, None] / l[None, :] / Distance
|
|
131
|
+
np.fill_diagonal(D, 0)
|
|
132
|
+
|
|
133
|
+
# for program stability, we force row sum of D to be 0
|
|
134
|
+
# which ensure the derivative of constants to be zero matrix
|
|
135
|
+
np.fill_diagonal(D, -np.sum(D, axis=1))
|
|
136
|
+
return D, r, w
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def Jacobi_Gauss_Lobatto(alpha, beta, N):
|
|
140
|
+
"""
|
|
141
|
+
This function computes the Gauss-Lobatto quadrature first order
|
|
142
|
+
derivative matrix, nodes and weights of Jacobi polynomial J_{N}^{alpha, beta}.
|
|
143
|
+
The nodes are {-1, 1, zeros of dx(J_N^{alpha, beta}(x))}
|
|
144
|
+
|
|
145
|
+
Parameters
|
|
146
|
+
----------
|
|
147
|
+
alpha : float
|
|
148
|
+
The alpha parameter of the Gauss-Lobatto quadrature. alpha > -1.
|
|
149
|
+
beta : float
|
|
150
|
+
The beta parameter of the Gauss-Lobatto quadrature. beta > -1.
|
|
151
|
+
If alpha = beta = 0, the Jacobi polynomial is Legendre polynomial.
|
|
152
|
+
N : int
|
|
153
|
+
The order of the Gauss-Lobatto quadrature.
|
|
154
|
+
|
|
155
|
+
Returns
|
|
156
|
+
----------
|
|
157
|
+
D: ndarray, shape (N + 1, N + 1)
|
|
158
|
+
The first order derivative matrix of the Gauss-Lobatto quadrature.
|
|
159
|
+
r: ndarray, shape (N + 1,)
|
|
160
|
+
The Gauss-Lobatto quadrature nodes.
|
|
161
|
+
w: ndarray, shape (N + 1,)
|
|
162
|
+
The Gauss-Lobatto quadrature weights.
|
|
163
|
+
|
|
164
|
+
References
|
|
165
|
+
----------
|
|
166
|
+
1. Spectral Method P83
|
|
167
|
+
2. Code-reproduction/Poisson-GPU.ipynb
|
|
168
|
+
"""
|
|
169
|
+
|
|
170
|
+
r = np.zeros((N + 1,))
|
|
171
|
+
r[0], r[-1] = -1.0, 1.0
|
|
172
|
+
w = np.zeros((N + 1,))
|
|
173
|
+
w[0] = (beta + 1) * gamma(beta + 1)**2
|
|
174
|
+
w[-1] = (alpha + 1) * gamma(alpha + 1)**2
|
|
175
|
+
|
|
176
|
+
if N > 1:
|
|
177
|
+
# dx(J_N^{alpha, beta}(x)) = C(alpha, beta, N) * J_{N-1}^{alpha+1, beta+1}(x)
|
|
178
|
+
# thus have same zeros
|
|
179
|
+
r[1:-1] = Jacobi_Gauss(alpha + 1, beta + 1, N - 1)[1]
|
|
180
|
+
# equ(3.139)
|
|
181
|
+
cd = 2**(alpha + beta + 1) * gamma(N) / gamma(N + alpha + beta + 2)
|
|
182
|
+
md = gamma(N + alpha + 1) / gamma(N + beta + 1)
|
|
183
|
+
w[0] *= cd * md
|
|
184
|
+
w[-1] *= cd / md
|
|
185
|
+
w[1:-1] = (2 * N + alpha + beta + 1) / (1 - r[1:-1]**2)**2 / (N-1) / (N + alpha + beta + 2) / JacobiP(r[1:-1], alpha + 2, beta + 2, N - 2)[-1]**2
|
|
186
|
+
|
|
187
|
+
# construct first order LGL derivative matrix D
|
|
188
|
+
Distance = r[:, None] - r[None, :] + np.eye(N + 1)
|
|
189
|
+
omega = np.prod(Distance, axis=1)
|
|
190
|
+
# equation (3.75)
|
|
191
|
+
D = diags(omega) @ (1 / Distance) @ diags(1 / omega)
|
|
192
|
+
# for program stability, we force row sum of D to be 0
|
|
193
|
+
# which ensure the derivative of constants to be zero matrix
|
|
194
|
+
np.fill_diagonal(D, 0)
|
|
195
|
+
np.fill_diagonal(D, -np.sum(D, axis=1))
|
|
196
|
+
return D, r, w
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def HermiteP(x, N, normalized=False, return_full=True):
|
|
200
|
+
"""
|
|
201
|
+
Evaluate orthognormal Hermite polynomial of degree N at x by recurrence relation.
|
|
202
|
+
|
|
203
|
+
Parameters
|
|
204
|
+
----------
|
|
205
|
+
x : ndarray
|
|
206
|
+
The input array.
|
|
207
|
+
N : int
|
|
208
|
+
The degree of Hermite polynomial.
|
|
209
|
+
normalized : bool, optional
|
|
210
|
+
Whether to normalize PL[N] to have L2 norm 1. Default is False.
|
|
211
|
+
return_full : bool, optional
|
|
212
|
+
Whether to return the full PL array. Default is True.
|
|
213
|
+
|
|
214
|
+
Returns
|
|
215
|
+
----------
|
|
216
|
+
PL[N] or PL : ndarray, shape (N + 1, len(x))
|
|
217
|
+
The value of Hermite polynomial of degree N at x, or the full PL array if return_full is True.
|
|
218
|
+
|
|
219
|
+
References
|
|
220
|
+
----------
|
|
221
|
+
Spectral Method P254
|
|
222
|
+
"""
|
|
223
|
+
|
|
224
|
+
xp = x.copy()
|
|
225
|
+
if len(xp.shape) == 2 and xp.shape[1] == 1:
|
|
226
|
+
xp = xp.T
|
|
227
|
+
PL = np.ones((N + 1, max(xp.shape)))
|
|
228
|
+
if normalized:
|
|
229
|
+
Norm = np.zeros(N + 1)
|
|
230
|
+
Norm[0] = np.linalg.norm(PL[0])
|
|
231
|
+
if N == 0:
|
|
232
|
+
return PL[0] / Norm[0] if normalized else PL[0]
|
|
233
|
+
PL[1] = 2 * xp
|
|
234
|
+
if normalized:
|
|
235
|
+
Norm[1] = np.linalg.norm(PL[1])
|
|
236
|
+
if N == 1 and normalized:
|
|
237
|
+
PL[0] /= Norm[0]
|
|
238
|
+
for i in range(1, N):
|
|
239
|
+
PL[i + 1] = 2 * xp * PL[i] - 2 * i * PL[i - 1]
|
|
240
|
+
if normalized:
|
|
241
|
+
if i == 1:
|
|
242
|
+
PL[0] /= Norm[0]
|
|
243
|
+
PL[i] /= Norm[i]
|
|
244
|
+
PL[i + 1] /= Norm[i]
|
|
245
|
+
Norm[i + 1] = np.linalg.norm(PL[i + 1])
|
|
246
|
+
if normalized:
|
|
247
|
+
PL[N] /= Norm[N]
|
|
248
|
+
return PL if return_full else PL[N]
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
def HermiteF(x, N, return_full=True):
|
|
252
|
+
"""
|
|
253
|
+
Evaluate modified Hermite Function of degree N at x by recurrence relation.
|
|
254
|
+
|
|
255
|
+
Parameters
|
|
256
|
+
----------
|
|
257
|
+
x : ndarray
|
|
258
|
+
The input array.
|
|
259
|
+
N : int
|
|
260
|
+
The degree of Hermite polynomial.
|
|
261
|
+
return_full : bool, optional
|
|
262
|
+
Whether to return the full PL array. Default is True.
|
|
263
|
+
|
|
264
|
+
Returns
|
|
265
|
+
----------
|
|
266
|
+
PL[N] or PL : ndarray, shape (N + 1, len(x))
|
|
267
|
+
The value of modified Hermite polynomial of degree N at x, or the full PL array if return_full is True.
|
|
268
|
+
|
|
269
|
+
References
|
|
270
|
+
----------
|
|
271
|
+
Spectral Method P256
|
|
272
|
+
"""
|
|
273
|
+
|
|
274
|
+
xp = x.copy()
|
|
275
|
+
if len(xp.shape) == 2 and xp.shape[1] == 1:
|
|
276
|
+
xp = xp.T
|
|
277
|
+
PL = np.ones((N + 1, max(xp.shape)))
|
|
278
|
+
PL[0] = np.exp(-xp ** 2 / 2) / np.pi ** 0.25 # underflow may occur for large r
|
|
279
|
+
if N == 0:
|
|
280
|
+
return PL[0]
|
|
281
|
+
PL[1] = np.sqrt(2) * xp * PL[0]
|
|
282
|
+
for i in range(1, N):
|
|
283
|
+
PL[i + 1] = np.sqrt(2 / (i + 1)) * xp * PL[i] - np.sqrt(i / (i + 1)) * PL[i - 1]
|
|
284
|
+
return PL if return_full else PL[N]
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
def Hermite_Gauss(N, c=1 / np.sqrt(2)):
|
|
288
|
+
"""
|
|
289
|
+
Generate the Hermite-Gauss(HG) quadrature points r and weights w w.r.t Hermite function.
|
|
290
|
+
|
|
291
|
+
Parameters
|
|
292
|
+
----------
|
|
293
|
+
N : int
|
|
294
|
+
Number of points, underflow will occur for N > 740 with default c.
|
|
295
|
+
c : float, optional
|
|
296
|
+
The decay factor for v = exp(-(cx)^2) * u(x). Default is 1 / sqrt(2).
|
|
297
|
+
If c = 0, it degenerates to Hermite-ploynomial case.
|
|
298
|
+
|
|
299
|
+
Returns
|
|
300
|
+
----------
|
|
301
|
+
D : ndarray, shape (N, N)
|
|
302
|
+
The first order derivative matrix of Hermite-Gauss quadrature points.
|
|
303
|
+
r : ndarray, shape (N,)
|
|
304
|
+
The Hermite-Gauss quadrature points.
|
|
305
|
+
w : ndarray, shape (N,)
|
|
306
|
+
The weights of Hermite-Gauss quadrature points.
|
|
307
|
+
|
|
308
|
+
References
|
|
309
|
+
----------
|
|
310
|
+
Spectral Method P261
|
|
311
|
+
"""
|
|
312
|
+
|
|
313
|
+
r, w = roots_hermite(N)
|
|
314
|
+
if c != 0:
|
|
315
|
+
w = 1 / (HermiteF(r, N - 1, False)**2 * N) # equ(7.81), modified weights for Hermite function
|
|
316
|
+
H = HermiteP(r, N - 1, True, False) * np.exp(-(c * r) ** 2) # equ(7.93), underflow may occur for large r
|
|
317
|
+
dis = r[:, np.newaxis] - r[np.newaxis, :]
|
|
318
|
+
np.fill_diagonal(dis, 1)
|
|
319
|
+
D = H[:, np.newaxis] / H[np.newaxis, :] / dis
|
|
320
|
+
np.fill_diagonal(D, r * (1 - 2 * c**2))
|
|
321
|
+
return D, r, w
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
def mapped_Jacobi_Gauss(alpha, beta, N, sf = 1, mapping = 'alg'):
|
|
326
|
+
"""
|
|
327
|
+
Mapped Jacobi-Gauss quadrature points, weights and first order derivative matrix.
|
|
328
|
+
The mapping is defined by the function y = map(r, s), where r is the original Jacobi-Gauss quadrature points,
|
|
329
|
+
and s is the scaling factor of the mapping.
|
|
330
|
+
|
|
331
|
+
Parameters
|
|
332
|
+
----------
|
|
333
|
+
alpha : float
|
|
334
|
+
The alpha parameter of the Jacobi polynomial. alpha > -1.
|
|
335
|
+
beta : float
|
|
336
|
+
The beta parameter of the Jacobi polynomial. beta > -1.
|
|
337
|
+
If alpha = beta = 0, the Jacobi polynomial is Legendre polynomial.
|
|
338
|
+
N : int
|
|
339
|
+
The order of the Jacobi polynomial.
|
|
340
|
+
sf : float, optional
|
|
341
|
+
The scaling factor of the mapping. Default is 1.
|
|
342
|
+
mapping : str, optional
|
|
343
|
+
The mapping function. Default is 'alg', which means using the algebraic mapping (cf. equ(7.159)).
|
|
344
|
+
Other options are 'log' and 'exp'.
|
|
345
|
+
|
|
346
|
+
Returns
|
|
347
|
+
----------
|
|
348
|
+
D : ndarray, shape (N, N)
|
|
349
|
+
The first order derivative matrix of the mapped Jacobi-Gauss quadrature.
|
|
350
|
+
r : ndarray, shape (N,)
|
|
351
|
+
The mapped Jacobi-Gauss quadrature nodes.
|
|
352
|
+
w : ndarray, shape (N,)
|
|
353
|
+
The modified mapped Jacobi-Gauss quadrature weights.
|
|
354
|
+
|
|
355
|
+
References
|
|
356
|
+
----------
|
|
357
|
+
1. Spectral Method P280, P286
|
|
358
|
+
"""
|
|
359
|
+
|
|
360
|
+
y, s = symbols('y s')
|
|
361
|
+
|
|
362
|
+
if mapping == 'alg':
|
|
363
|
+
map_expr = s * y / sqrt(1 - y**2)
|
|
364
|
+
diff_map_expr = diff(map_expr, y)
|
|
365
|
+
elif mapping == 'log':
|
|
366
|
+
map_expr = s * atanh(y)
|
|
367
|
+
diff_map_expr = diff(map_expr, y)
|
|
368
|
+
elif mapping == 'exp':
|
|
369
|
+
map_expr = sinh(s * y)
|
|
370
|
+
diff_map_expr = diff(map_expr, y)
|
|
371
|
+
else:
|
|
372
|
+
raise ValueError("Invalid mapping function. Please choose from 'alg', 'log' and 'exp'.")
|
|
373
|
+
|
|
374
|
+
map = lambdify((y, s), map_expr, "numpy")
|
|
375
|
+
diff_map = lambdify((y, s), diff_map_expr, "numpy")
|
|
376
|
+
|
|
377
|
+
D, r, w = Jacobi_Gauss(alpha, beta, N)
|
|
378
|
+
omega = (1 - r)**alpha * (1 + r)**beta
|
|
379
|
+
diff_g = diff_map(r, sf)
|
|
380
|
+
D, r, w = D / diff_g[:, None], map(r, sf), w / omega * diff_g
|
|
381
|
+
return D, r, w
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
def glue1D(interval, Ncell, D, r, w, end_pts = False):
|
|
387
|
+
"""
|
|
388
|
+
Glue the differential matrix D, Gauss points r, and quadrature weights w on each cell together.
|
|
389
|
+
|
|
390
|
+
Parameters
|
|
391
|
+
----------
|
|
392
|
+
interval : list or tuple, length 2
|
|
393
|
+
The left and right edge of the domain.
|
|
394
|
+
Ncell : int
|
|
395
|
+
The number of cells.
|
|
396
|
+
D, r, w : ndarray
|
|
397
|
+
The differential matrix, Gauss points, and quadrature weights on the reference cell [-1, 1],
|
|
398
|
+
which can be generated by `spectral.Jacobi_Gauss`, `spectral.Jacobi_Gauss_Lobatto`.
|
|
399
|
+
end_pts : bool, optional
|
|
400
|
+
Whether the end points -1, 1 are included in r or not. The default is False.
|
|
401
|
+
E.g., if `spectral.Jacobi_Gauss_Lobatto` is used, the end points are included in r.
|
|
402
|
+
|
|
403
|
+
Returns
|
|
404
|
+
----------
|
|
405
|
+
D, r, w : ndarray
|
|
406
|
+
The differential matrix D, Gauss points r, and quadrature weights w on the interval.
|
|
407
|
+
if end_pts is False, shape (Ncell * Np, Ncell * Np), (Ncell * Np,), (Ncell * Np,)
|
|
408
|
+
if end_pts is True, shape (Ncell * (Np - 1) + 1, Ncell * (Np - 1) + 1), (Ncell * (Np - 1) + 1,), (Ncell * (Np - 1) + 1,)
|
|
409
|
+
"""
|
|
410
|
+
|
|
411
|
+
Np = len(r)
|
|
412
|
+
D, r, w = D.copy(), r.copy(), w.copy()
|
|
413
|
+
left, right = interval
|
|
414
|
+
Len = (right - left) / Ncell / 2
|
|
415
|
+
r = (r + 1) * Len + left
|
|
416
|
+
r = r[None, :].repeat(Ncell, axis=0)
|
|
417
|
+
r = r + np.arange(Ncell)[:, None] * Len * 2
|
|
418
|
+
D_blocks = [D / Len] * Ncell
|
|
419
|
+
D, r, w = block_diag(*D_blocks), r.reshape(-1), np.tile(w, Ncell) * Len
|
|
420
|
+
if end_pts:
|
|
421
|
+
Glue = lil_matrix(np.zeros((Ncell * (Np - 1) + 1, Ncell * Np)))
|
|
422
|
+
for j in range(Ncell):
|
|
423
|
+
rowStart, colStart = j * (Np - 1), j * Np
|
|
424
|
+
Glue[rowStart:rowStart+Np, colStart:colStart+Np] = eye(Np)
|
|
425
|
+
D, Glue = csr_matrix(D), Glue.tocsr()
|
|
426
|
+
D = (Glue @ D @ Glue.T).toarray()
|
|
427
|
+
r = np.delete(r, np.arange(Np-1, len(r)-1, Np))
|
|
428
|
+
w = Glue @ w
|
|
429
|
+
return D, r, w
|
|
430
|
+
|
|
431
|
+
def glue_pts_1D(interval, Ncell, r, end_pts = False):
|
|
432
|
+
"""
|
|
433
|
+
Glue the points r on each cell together.
|
|
434
|
+
|
|
435
|
+
Parameters
|
|
436
|
+
----------
|
|
437
|
+
interval : list or tuple, length 2
|
|
438
|
+
The left and right edge of the domain.
|
|
439
|
+
Ncell : int
|
|
440
|
+
The number of cells.
|
|
441
|
+
r : ndarray
|
|
442
|
+
The collocation points on the reference cell [-1, 1],
|
|
443
|
+
end_pts : bool, optional
|
|
444
|
+
Whether the end points -1, 1 are included in r or not. The default is False.
|
|
445
|
+
|
|
446
|
+
Returns
|
|
447
|
+
----------
|
|
448
|
+
r : ndarray
|
|
449
|
+
The collocation points r on the interval.
|
|
450
|
+
if end_pts is False, shape (Ncell * Np,)
|
|
451
|
+
if end_pts is True, shape (Ncell * (Np - 1) + 1,)
|
|
452
|
+
"""
|
|
453
|
+
|
|
454
|
+
Np = len(r)
|
|
455
|
+
r = r.copy()
|
|
456
|
+
left, right = interval
|
|
457
|
+
Len = (right - left) / Ncell / 2
|
|
458
|
+
r = (r + 1) * Len + left
|
|
459
|
+
r = r[None, :].repeat(Ncell, axis=0)
|
|
460
|
+
r = r + np.arange(Ncell)[:, None] * Len * 2
|
|
461
|
+
r = r.reshape(-1)
|
|
462
|
+
if end_pts:
|
|
463
|
+
r = np.delete(r, np.arange(Np-1, len(r)-1, Np))
|
|
464
|
+
return r
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
__all__ = ['pkg_system_info', 'func_timer', 'timer',
|
|
2
|
+
]
|
|
3
|
+
|
|
4
|
+
import platform
|
|
5
|
+
import psutil
|
|
6
|
+
import pandas as pd
|
|
7
|
+
from datetime import datetime
|
|
8
|
+
from IPython.display import display, HTML
|
|
9
|
+
import GPUtil
|
|
10
|
+
import importlib
|
|
11
|
+
import subprocess
|
|
12
|
+
|
|
13
|
+
import time
|
|
14
|
+
from functools import wraps
|
|
15
|
+
|
|
16
|
+
def pkg_system_info(packages, show_pkg=True, show_gpu=True, show_system=True):
|
|
17
|
+
"""
|
|
18
|
+
This function takes a list of package names as input, imports each package dynamically,
|
|
19
|
+
and displays the version information of each package and the system information.
|
|
20
|
+
|
|
21
|
+
Parameters
|
|
22
|
+
----------
|
|
23
|
+
packages : list of str
|
|
24
|
+
A list of package names to import and get version information.
|
|
25
|
+
show_pkg : bool
|
|
26
|
+
Whether to show package version information. Default is True.
|
|
27
|
+
show_system : bool
|
|
28
|
+
Whether to show system information. Default is True.
|
|
29
|
+
show_gpu : bool
|
|
30
|
+
Whether to show GPU information. Default is True.
|
|
31
|
+
|
|
32
|
+
Returns
|
|
33
|
+
----------
|
|
34
|
+
None
|
|
35
|
+
|
|
36
|
+
Example
|
|
37
|
+
----------
|
|
38
|
+
>>> pkg_system_info(['numpy', 'pandas', 'scipy', 'qiskit'], show_pkg=True, show_gpu=True, show_system=False)
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
def get_cpu_info():
|
|
42
|
+
# Get CPU information on Linux
|
|
43
|
+
cpu_info = subprocess.check_output("lscpu", shell=True).decode()
|
|
44
|
+
architecture = subprocess.check_output("uname -m", shell=True).decode().strip()
|
|
45
|
+
lines = cpu_info.split('\n')
|
|
46
|
+
info_dict = {}
|
|
47
|
+
for line in lines:
|
|
48
|
+
if "Vendor ID:" in line:
|
|
49
|
+
info_dict['Vendor ID'] = line.split(':')[1].strip()
|
|
50
|
+
if "CPU family:" in line:
|
|
51
|
+
info_dict['CPU family'] = line.split(':')[1].strip()
|
|
52
|
+
if "Model:" in line:
|
|
53
|
+
info_dict['Model'] = line.split(':')[1].strip()
|
|
54
|
+
if "Stepping:" in line:
|
|
55
|
+
info_dict['Stepping'] = line.split(':')[1].strip()
|
|
56
|
+
return architecture, info_dict
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
if show_pkg:
|
|
60
|
+
# Get packages version information
|
|
61
|
+
pkg_versions = []
|
|
62
|
+
for pkg_name in packages:
|
|
63
|
+
try:
|
|
64
|
+
pkg = importlib.import_module(pkg_name)
|
|
65
|
+
version = pkg.__version__
|
|
66
|
+
except AttributeError:
|
|
67
|
+
version = "Version not available"
|
|
68
|
+
pkg_versions.append((pkg.__name__, version))
|
|
69
|
+
|
|
70
|
+
pkg_versions_df = pd.DataFrame(pkg_versions, columns=['Package', 'Version'])
|
|
71
|
+
display(HTML(pkg_versions_df.to_html(index=False)))
|
|
72
|
+
|
|
73
|
+
if show_gpu:
|
|
74
|
+
# Get GPU information
|
|
75
|
+
gpus = GPUtil.getGPUs()
|
|
76
|
+
gpu_info_list = []
|
|
77
|
+
if gpus:
|
|
78
|
+
for gpu in gpus:
|
|
79
|
+
gpu_info = [gpu.name, f"{round(gpu.memoryTotal / 1024, 1)} Gb", 1]
|
|
80
|
+
for existing_gpu_info in gpu_info_list:
|
|
81
|
+
if existing_gpu_info[0] == gpu_info[0] and existing_gpu_info[1] == gpu_info[1]:
|
|
82
|
+
existing_gpu_info[2] += 1
|
|
83
|
+
break
|
|
84
|
+
else:
|
|
85
|
+
gpu_info_list.append(gpu_info)
|
|
86
|
+
else:
|
|
87
|
+
gpu_info_list = [['No GPU detected', 'N/A', 'N/A']]
|
|
88
|
+
|
|
89
|
+
gpu_info_df = pd.DataFrame(gpu_info_list, columns=['GPU Version', 'GPU Memory', 'Count'])
|
|
90
|
+
display(HTML(gpu_info_df.to_html(index=False)))
|
|
91
|
+
|
|
92
|
+
if show_system:
|
|
93
|
+
# Get system information
|
|
94
|
+
system_info = {
|
|
95
|
+
'Python version': platform.python_version(),
|
|
96
|
+
'Python compiler': platform.python_compiler(),
|
|
97
|
+
'Python build': platform.python_build(),
|
|
98
|
+
'OS': platform.system(),
|
|
99
|
+
'CPU Version': platform.processor(),
|
|
100
|
+
'CPU Number': psutil.cpu_count(),
|
|
101
|
+
'CPU Memory': f"{round(psutil.virtual_memory().total / (1024.0 **3), 1)} Gb",
|
|
102
|
+
'Time': datetime.now().strftime("%a %b %d %H:%M:%S %Y %Z")
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if system_info['OS'] == 'Linux':
|
|
106
|
+
architecture, cpu_info = get_cpu_info()
|
|
107
|
+
system_info['CPU Version'] = f"{architecture} Family {cpu_info['CPU family']} Model {cpu_info['Model']} Stepping {cpu_info['Stepping']}, {cpu_info['Vendor ID']}"
|
|
108
|
+
|
|
109
|
+
system_info_df = pd.DataFrame(list(system_info.items()), columns=['System Information', 'Details'])
|
|
110
|
+
display(HTML(system_info_df.to_html(index=False)))
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def func_timer(function):
|
|
116
|
+
"""
|
|
117
|
+
This is a timer decorator. It calculates the execution time of the function.
|
|
118
|
+
|
|
119
|
+
Args
|
|
120
|
+
----------
|
|
121
|
+
function : callable
|
|
122
|
+
The function to be timed.
|
|
123
|
+
|
|
124
|
+
Returns
|
|
125
|
+
----------
|
|
126
|
+
function : callable
|
|
127
|
+
The decorated function which will print its execution time when called.
|
|
128
|
+
|
|
129
|
+
Example
|
|
130
|
+
----------
|
|
131
|
+
>>> @func_timer
|
|
132
|
+
>>> def my_function(n):
|
|
133
|
+
>>> return sum(range(n))
|
|
134
|
+
>>> my_function(1000000)
|
|
135
|
+
"""
|
|
136
|
+
|
|
137
|
+
@wraps(function)
|
|
138
|
+
def function_timer(*args, **kwargs):
|
|
139
|
+
t0 = time.time()
|
|
140
|
+
result = function(*args, **kwargs)
|
|
141
|
+
t1 = time.time()
|
|
142
|
+
print ("Running time of %s: %.3e seconds" % (function.__name__, t1-t0))
|
|
143
|
+
return result
|
|
144
|
+
return function_timer
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
class timer:
|
|
148
|
+
"""
|
|
149
|
+
A simple timer class.
|
|
150
|
+
|
|
151
|
+
Attributes
|
|
152
|
+
----------
|
|
153
|
+
start_time : float
|
|
154
|
+
The time when the timer was started.
|
|
155
|
+
last_lap_time : float
|
|
156
|
+
The time when the last lap was recorded.
|
|
157
|
+
|
|
158
|
+
Methods
|
|
159
|
+
-------
|
|
160
|
+
__init__():
|
|
161
|
+
Initializes the timer.
|
|
162
|
+
__str__():
|
|
163
|
+
Returns a string representation of the timer.
|
|
164
|
+
__repr__():
|
|
165
|
+
Returns a formal string representation of the timer.
|
|
166
|
+
reset():
|
|
167
|
+
Resets the timer.
|
|
168
|
+
update():
|
|
169
|
+
Updates the last lap time without printing anything.
|
|
170
|
+
lap():
|
|
171
|
+
Records a lap time and prints the time difference since the last lap.
|
|
172
|
+
stop():
|
|
173
|
+
Prints the total time.
|
|
174
|
+
"""
|
|
175
|
+
|
|
176
|
+
def __init__(self):
|
|
177
|
+
self.start_time = time.time()
|
|
178
|
+
self.last_lap_time = self.start_time
|
|
179
|
+
|
|
180
|
+
def __str__(self):
|
|
181
|
+
return 'Timer(start_time=%.3e, last_lap_time=%.3e)' % (self.start_time, self.last_lap_time)
|
|
182
|
+
|
|
183
|
+
def __repr__(self):
|
|
184
|
+
return self.__str__()
|
|
185
|
+
|
|
186
|
+
def reset(self):
|
|
187
|
+
self.start_time = time.time()
|
|
188
|
+
self.last_lap_time = self.start_time
|
|
189
|
+
|
|
190
|
+
def update(self):
|
|
191
|
+
self.last_lap_time = time.time()
|
|
192
|
+
|
|
193
|
+
def lap(self):
|
|
194
|
+
current_time = time.time()
|
|
195
|
+
lap_time = current_time - self.last_lap_time
|
|
196
|
+
self.last_lap_time = current_time
|
|
197
|
+
print('Lap time: %.3e s' % lap_time)
|
|
198
|
+
|
|
199
|
+
def stop(self):
|
|
200
|
+
total_time = time.time() - self.start_time
|
|
201
|
+
return print('Total time: %.3e s' % total_time)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
from distutils.command import install_data
|
|
2
|
+
from setuptools import setup, find_packages
|
|
3
|
+
|
|
4
|
+
setup(
|
|
5
|
+
name='specnn4pde', # package name
|
|
6
|
+
version='0.0.2', # version
|
|
7
|
+
author='MXWeng', # author name
|
|
8
|
+
author_email='2431141461@qq.com', # author email
|
|
9
|
+
description='Solving partial differential equations using spectral methods and neural networks.', # short description
|
|
10
|
+
long_description=open('README.md').read(), # long description, usually your README
|
|
11
|
+
long_description_content_type='text/markdown', # format of the long description, 'text/markdown' if it's Markdown
|
|
12
|
+
url='https://github.com/mxweng/specnn4pde', # project homepage
|
|
13
|
+
packages=find_packages(), # automatically discover all packages
|
|
14
|
+
classifiers=[
|
|
15
|
+
'Development Status :: 3 - Alpha',
|
|
16
|
+
'License :: OSI Approved :: MIT License',
|
|
17
|
+
'Operating System :: OS Independent',
|
|
18
|
+
'Programming Language :: Python :: 3',
|
|
19
|
+
'Programming Language :: Python :: 3.8',
|
|
20
|
+
'Programming Language :: Python :: 3.9',
|
|
21
|
+
'Programming Language :: Python :: 3.10',
|
|
22
|
+
'Programming Language :: Python :: 3.11',
|
|
23
|
+
'Programming Language :: Python :: 3.12',
|
|
24
|
+
'Intended Audience :: Science/Research',
|
|
25
|
+
'Topic :: Scientific/Engineering :: Mathematics',
|
|
26
|
+
], # list of classifiers
|
|
27
|
+
python_requires='>=3.6', # Python version requirement
|
|
28
|
+
install_requires=['GPUtil',
|
|
29
|
+
'IPython',
|
|
30
|
+
'numpy',
|
|
31
|
+
'pandas',
|
|
32
|
+
'psutil',
|
|
33
|
+
'scipy',
|
|
34
|
+
'sympy',
|
|
35
|
+
], # dependencies
|
|
36
|
+
)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: specnn4pde
|
|
3
|
+
Version: 0.0.2
|
|
4
|
+
Summary: Solving partial differential equations using spectral methods and neural networks.
|
|
5
|
+
Home-page: https://github.com/mxweng/specnn4pde
|
|
6
|
+
Author: MXWeng
|
|
7
|
+
Author-email: 2431141461@qq.com
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Intended Audience :: Science/Research
|
|
18
|
+
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
19
|
+
Requires-Python: >=3.6
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Requires-Dist: GPUtil
|
|
23
|
+
Requires-Dist: IPython
|
|
24
|
+
Requires-Dist: numpy
|
|
25
|
+
Requires-Dist: pandas
|
|
26
|
+
Requires-Dist: psutil
|
|
27
|
+
Requires-Dist: scipy
|
|
28
|
+
Requires-Dist: sympy
|
|
29
|
+
|
|
30
|
+
# SpecNN4PDE
|
|
31
|
+
SpecNN4PDE is an under development Python library for solving partial differential equations using spectral methods and neural networks. It consists of the following modules:
|
|
32
|
+
|
|
33
|
+
- `spectral`: Provides functions for working with spectral methods as described in the book [Spectral Methods: Algorithms, Analysis and Applications](https://link.springer.com/book/10.1007/978-3-540-71041-7) by Shen, Tang, and Wang.
|
|
34
|
+
- `linalg`: This module primarily focuses on numerical algebra methods.
|
|
35
|
+
- `tools`: A collection of utility functions for system and package information retrieval, time measurement, etc.
|
|
36
|
+
- `npde`: Functions for solving partial differential equations, e.g., calculating the multivariate derivatives.
|
|
37
|
+
|
|
38
|
+
This project is still in the early stages of development, and the API is subject to change. The library is designed to be used in research and educational settings.
|
|
39
|
+
|
|
40
|
+
## Dependencies
|
|
41
|
+
|
|
42
|
+
When you install this library using pip, most dependencies will be automatically handled. However, please note that the `npde` module requires PyTorch, which needs to be installed separately.
|
|
43
|
+
|
|
44
|
+
You can install PyTorch by following the instructions on the [official PyTorch website](https://pytorch.org/get-started/locally/). Please ensure that you select the correct installation command based on your operating system, package manager, Python version, and the specifications of your CUDA toolkit if you are planning to use PyTorch with GPU support.
|
|
45
|
+
|
|
46
|
+
If you are not planning to use the `npde` module, you do not need to install PyTorch.
|
|
47
|
+
|
|
48
|
+
## Installation
|
|
49
|
+
|
|
50
|
+
To install this library, you can use pip:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
pip install specnn4pde
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
setup.py
|
|
4
|
+
mxwpy/__init__.py
|
|
5
|
+
mxwpy/linalg.py
|
|
6
|
+
mxwpy/npde.py
|
|
7
|
+
mxwpy/spectral.py
|
|
8
|
+
mxwpy/tools.py
|
|
9
|
+
specnn4pde.egg-info/PKG-INFO
|
|
10
|
+
specnn4pde.egg-info/SOURCES.txt
|
|
11
|
+
specnn4pde.egg-info/dependency_links.txt
|
|
12
|
+
specnn4pde.egg-info/requires.txt
|
|
13
|
+
specnn4pde.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
mxwpy
|