Source code for EasyFEA.fem._forms
# Copyright (C) 2021-2025 Université Gustave Eiffel.
# This file is part of the EasyFEA project.
# EasyFEA is distributed under the terms of the GNU General Public License v3, see LICENSE.txt and CREDITS.md for more information.
"""Module containing the BiLinearForm and LinearForm classes used to construct arbitrary fem matrices."""
from abc import ABC, abstractmethod
from typing import Callable, TYPE_CHECKING
import numpy as np
# from fem
from ._linalg import FeArray
if TYPE_CHECKING:
from ._field import Field
class _Form(ABC):
"""Form class from which BilinearForm and LinearForm are derived."""
def __init__(self, form: Callable[..., FeArray.FeArrayALike]):
self._form = form
def __call__(self, *args, **kwds):
return self._form(*args, **kwds)
@abstractmethod
def _assemble(self, field: "Field") -> np.ndarray:
"""Assemble de form with the field.
Parameters
----------
field : Field
field
Returns
-------
np.ndarray
the integrated numpy array
"""
pass
[docs]
class BiLinearForm(_Form):
def _assemble(self, field):
# get field data
dof_n = field.dof_n
groupElem = field.groupElem
nPe = groupElem.nPe
# init data array
data = np.zeros((groupElem.Ne, nPe * dof_n, nPe * dof_n), dtype=float)
# get form function
form = self._form
# set u and v field
u = field
v = field.copy()
# get dofs and nodes
dofs = np.arange(nPe * dof_n)
nodes = np.arange(nPe).reshape(nPe, 1).repeat(dof_n, axis=1).ravel()
# get dX to integrate
dX_e_pg = groupElem.Get_weightedJacobian_e_pg(field.matrixType)
# loop over u dofs
for i in dofs:
# activate node and dof for u
u._Set_node(nodes[i])
u._Set_dof(i % dof_n)
# loop over v dofs
for j in dofs:
# activate node and dof for v
v._Set_node(nodes[j])
v._Set_dof(j % dof_n)
# get (Ne, nPg) array
values_e_pg = form(u, v)
# sum on gauss points
values_e = (values_e_pg * dX_e_pg).sum(axis=1)
# add data
data[:, i, j] = values_e
return data
[docs]
class LinearForm(_Form):
def _assemble(self, field):
# get field data
dof_n = field.dof_n
groupElem = field.groupElem
nPe = groupElem.nPe
# init data array
data = np.zeros((groupElem.Ne, nPe * dof_n, 1), dtype=float)
# get form function
form = self._form
# get v field
v = field
# get dofs and nodes
dofs = np.arange(nPe * dof_n)
nodes = np.arange(nPe).reshape(nPe, 1).repeat(dof_n, axis=1).ravel()
# get dX to integrate
dX_e_pg = groupElem.Get_weightedJacobian_e_pg(field.matrixType)
# loop over u dofs
for i in dofs:
# activate node and dof for v
v._Set_node(nodes[i])
v._Set_dof(i % dof_n)
# get (Ne, nPg) array
values_e_pg = form(v)
# sum on gauss points
values_e = (values_e_pg * dX_e_pg).sum(axis=1)
# add data
data[:, i] = values_e
return data