Функция на сетке

Важная особенность np.array — возможность обходиться при вычислении значения функции без циклов.

import numpy as np

def f(x,y):
    return x**2+2*x+6*y

s = np.linspace(1,7,3)
p = np.linspace(5,9,3)

v = f (s,p) # Функция f была применена поэлементно 
# v == array([  33.,   66.,  117.])

S, P = np.meshgrid(s,p,indexing='ij')
v = f (S,P) # Функция f была применена для каждой пары из s и p
# array([[ 33.,  45.,  57.],
#       [ 54.,  66.,  78.],
#       [ 93., 105., 117.]])

В случае простой подстановки f (s,p) будет массивы будут подставлены поэлементно. В случае подстановки с использованием meshgrid из массивов будет построена сетка, в узлах которой будут пары элементов и функция будет рассчитана для каждого элемента сетки.

Дифференциальные операторы на сетке

Для расчетов производных на сетке будем использовать модуль findiffpip (документация).

import numpy as np
from findiff import FinDiff

x = np.linspace(0, 10, 100)
dx = x[1] - x[0]
f = np.sin(x)

d_dx = FinDiff(0, dx, 1)
df_dx = d_dx(f)

Объект FinDiff реализует дифференциальный оператор, аргументы: 0 — по первой оси, dx — размер шага, 1 — первая производная.

df_dx — массив np.array со значениями производной f в узлах сетки. Модуль findiff не изменяет размер массива т.к. на краях применяется схема дифференциирование вперед или назад соответственно, а по остальному объему массива используется центральная схема.

Дифференциальные операторы модуля findiff

Название Значение Запись Вход Выход
FinDiff дифференциал d/dx скалярное поле скалярное поле
Gradient градиент ∇f скалярное поле векторное поле
Laplacian оператор Лапласа 2 f скалярное поле векторное поле
Divergence дивергенция ∇· f векторное поле скалярное поле
Curl ротор ∇×f векторное поле векторное поле

В 2D задаче

import numpy as np
from findiff import Gradient, Divergence, Laplacian
import matplotlib.pyplot as plt

#%%

borders = [-2*np.pi, 2*np.pi, -2*np.pi, 2*np.pi]

x = np.linspace(-2*np.pi, 2*np.pi, 30)
dx = x[1]-x[0]
y = np.linspace(-2*np.pi, 2*np.pi, 30)
dy = y[1]-y[0]

X, Y = np.meshgrid(x, y, indexing='ij')
f = Y*np.sin(X) + np.cos(Y)

#%%

plt.imshow(f.T,  origin='lower', extent=borders)
contours = plt.contour(X, Y, f,  origin='lower', colors = 'r')
plt.clabel(contours, colors = 'r')
plt.show()

#%%
grad = Gradient(h=[dx, dy])
grad_f = grad(f)

plt.imshow(f.T ,  origin='lower', extent=borders)
plt.colorbar()
plt.quiver(X,Y,grad_f[0],grad_f[1])
plt.show()

#%%

u = np.array((X**2-Y**2, Y**2-X))

div = Divergence(h=[dx, dy])
div_u = div(u)

plt.imshow(div_u.T,origin='lower', extent=borders)
plt.colorbar()
plt.quiver(X,Y,u[0],u[1])
plt.show()

Скалярная функция f и ее изолинии

Скалярная функция f и ее изолинии

Скалярная функция f и ее градиент

Скалярная функция f и ее градиент

Векторная функция u и ее дивергенция

Векторная функция u и ее дивергенция

В 3D задаче

import numpy as np
from findiff import Gradient, Divergence, Laplacian, Curl

x = np.linspace(0, 10, 100)
dx = x[1]-x[0]
y = np.linspace(0, 10, 100)
dy = y[1]-y[0]
z = np.linspace(0, 10, 100)
dz = z[1]-z[0]

X, Y, Z = np.meshgrid(x, y, z, indexing='ij')
f = np.sin(X) * np.cos(Y) * np.sin(Z)

grad = Gradient(h=[dx, dy, dz])
grad_f = grad(f)

laplace = Laplacian(h=[dx, dy, dz])
laplace_f = laplace(f)

g = np.array([f, 2*f, 3*f])

div = Divergence(h=[dx, dy, dz])
div_g = div(g)

curl = Curl(h=[dx, dy, dz])
curl_g = curl(g)