Это типичный прецедент для систем уравнений FEM/FVM, поэтому, возможно, это более широкий интерес. С треугольной сеткой порционногоЭффективно построить матрицу FEM/FVM
Я хотел бы создать scipy.sparse.csr_matrix
. Матричные строки/столбцы представляют значения в узлах сетки. Матрица имеет записи на главной диагонали и где два узла соединены ребром.
Вот MWE, что первый строит node-> edge-> клетки отношения с, а затем строит матрицу:
import numpy
import meshzoo
from scipy import sparse
nx = 1600
ny = 1000
verts, cells = meshzoo.rectangle(0.0, 1.61, 0.0, 1.0, nx, ny)
n = len(verts)
nds = cells.T
nodes_edge_cells = numpy.stack([nds[[1, 2]], nds[[2, 0]],nds[[0, 1]]], axis=1)
# assign values to each edge (per cell)
alpha = numpy.random.rand(3, len(cells))
vals = numpy.array([
[alpha**2, -alpha],
[-alpha, alpha**2],
])
# Build I, J, V entries for COO matrix
I = []
J = []
V = []
#
V.append(vals[0][0])
V.append(vals[0][1])
V.append(vals[1][0])
V.append(vals[1][1])
#
I.append(nodes_edge_cells[0])
I.append(nodes_edge_cells[0])
I.append(nodes_edge_cells[1])
I.append(nodes_edge_cells[1])
#
J.append(nodes_edge_cells[0])
J.append(nodes_edge_cells[1])
J.append(nodes_edge_cells[0])
J.append(nodes_edge_cells[1])
# Create suitable data for coo_matrix
I = numpy.concatenate(I).flat
J = numpy.concatenate(J).flat
V = numpy.concatenate(V).flat
matrix = sparse.coo_matrix((V, (I, J)), shape=(n, n))
matrix = matrix.tocsr()
С
python -m cProfile -o profile.prof main.py
snakeviz profile.prof
можно создать и просмотреть профиль выше:
Метод tocsr()
принимает львиную долю от времени выполнения, но это также верно, когда здание alpha
является более сложным. Следовательно, я ищу способы ускорить это.
Что я уже нашел:
Благодаря структуре данных, значения по диагонали матрицы можно суммировать заранее, то есть,
V.append(vals[0, 0, 0] + vals[1, 1, 2]) I.append(nodes_edge_cells[0, 0]) # == nodes_edge_cells[1, 2] J.append(nodes_edge_cells[0, 0]) # == nodes_edge_cells[1, 2]
Это делает
I
,J
,V
короче и, следовательно, ускоряетtocsr
.Прямо сейчас, края «на ячейку». Я мог идентифицировать равные края друг с другом, используя
numpy.unique
, эффективно экономя около половиныI
,J
,V
. Однако я обнаружил, что это тоже занимает некоторое время. (Не удивительно.)
Еще одна мысль, что у меня было, что я мог бы заменить диагональ V
, I
, J
простым numpy.add.at
если была структура csr_matrix
-как данных, где хранится главная диагональ в отдельности. Я знаю, что это существует в некоторых других пакетах программного обеспечения, но не может найти его в scipy. Верный?
Возможно, существует разумный способ построения CSR напрямую?
Я хотел бы посмотреть некоторые тайминги для разных шагов. 'Tocsr' использует скомпилированный код. Я бы подумал, что любое массирование «coo» входов перед рукой займет столько же времени, если не больше. – hpaulj
Вы уверены, что 'tocsr' занимает много времени? Я сделал что-то очень похожее на матрицу размером 10k на 10k, где I, J, V имеет длину в миллионы, и это не так долго. Может быть, 5-10 секунд. – BallpointBen
Спасибо за комментарии. Я добавил профиль к исходному сообщению. –