download
raw
5.37 kB
import sympy as sym
import numpy as np
sym.init_printing()
def basis(d,point_distribution='uniform',symbolic=False):
"""
Return all local basis functions phi as functions of the local point X
in a 1D element with d+1 nodes.
If symbolic=True, return expressions as sympy expressions, else return Python
functions of X.
point_distribution can be 'uniform' or 'Chebyshev'.
"""
X=sym.Symbol('X')
if d==0:
phi_sym=[1]
else:
if point_distribution=='uniform':
if symbolic:
# compute symbolic nodes
h=sym.Rational(2,d)
nodes=[-1 + i*h for i in range(d+1)]
else:
nodes=np.linspace(-1,1,d+1)
elif point_distribution=='Chebyshev':
# Just numeric nodes
nodes=Chebyshev_nodes(-1,1,d)
phi_sym=[Lagrange_polynomials(X,r,nodes) for r in range(d+1)]
# Transform to python functions
phi_num=[sym.lambdify([X],phi_sym[r], modules='numpy') for r in range(d+1)]
return phi_sym if symbolic else phi_num
def Lagrange_polynomials(x,i,points):
p=1
for k in range(len(points)):
if k!=i:
p*=(x-points[k])/(points[i]-points[k])
return p
def element_matrix(phi,Omega_e, symbolic=True):
n=len(phi)
if symbolic:
A_e=sym.zeros(n,n)
else:
A_e=np.zeros((n,n), dtype=object)
X=sym.Symbol('X')
if symbolic:
h=sym.Symbol('h')
else:
h=Omega_e[1]-Omega_e[0]
detJ=h/2
for r in range(n):
phi_r = phi[r](X) if callable(phi[r]) else phi[r]
for s in range(r,n):
phi_s = phi[s](X) if callable(phi[s]) else phi[s]
val = sym.integrate(phi_r*phi_s*detJ,(X,-1,1))
# if not symbolic:
# val = float(val) # Removed to allow symbolic expressions
A_e[r,s]=val
A_e[s,r]=A_e[r,s]
return A_e
def element_vector(f,phi,Omega_e, symbolic=True):
n=len(phi)
if symbolic:
b_e=sym.zeros(n,1)
else:
b_e=np.zeros(n, dtype=object)
X=sym.Symbol('X')
x=sym.Symbol('x') # Global coordinate
if symbolic:
h=sym.Symbol('h')
else:
h=Omega_e[1]-Omega_e[0]
detJ=h/2
# Coordinate mapping x -> X
# x = (Omega_e[0] + Omega_e[1])/2 + h/2 * X
# or x = Omega_e[0]*(1-X)/2 + Omega_e[1]*(1+X)/2
x_map = Omega_e[0]*(1-X)/2 + Omega_e[1]*(1+X)/2
if hasattr(f, 'subs'):
f_mapped = f.subs(x, x_map)
elif callable(f):
f_mapped = f(x_map)
else:
f_mapped = f
for r in range(n):
phi_r = phi[r](X) if callable(phi[r]) else phi[r]
integrand_expr = f_mapped * phi_r * detJ
I = sym.integrate(integrand_expr, (X, -1, 1))
# if not symbolic:
# I = float(I) # Removed
if symbolic:
b_e[r] = I
else:
b_e[r] = I
return b_e
def element_stiffness_matrix(phi, Omega_e, symbolic=True):
n = len(phi)
if symbolic:
K_e = sym.zeros(n, n)
else:
K_e = np.zeros((n, n), dtype=object)
X = sym.Symbol('X')
if symbolic:
h = sym.Symbol('h')
else:
h = Omega_e[1] - Omega_e[0]
# detJ = dx/dX = h/2
# d/dx = (d/dX) * (dX/dx) = (d/dX) * (2/h)
detJ = h / 2
inv_detJ = 2 / h
for r in range(n):
phi_r = phi[r](X) if callable(phi[r]) else phi[r]
dphi_r = sym.diff(phi_r, X)
for s in range(r, n):
phi_s = phi[s](X) if callable(phi[s]) else phi[s]
dphi_s = sym.diff(phi_s, X)
# Integral of (dphi_r/dx * dphi_s/dx) * detJ dX
# = (dphi_r/dX * inv_detJ) * (dphi_s/dX * inv_detJ) * detJ
# = dphi_r/dX * dphi_s/dX * inv_detJ
integrand = dphi_r * dphi_s * inv_detJ
val = sym.integrate(integrand, (X, -1, 1))
K_e[r, s] = val
K_e[s, r] = K_e[r, s]
return K_e
def assemble(nodes, elements, phi, f, symbolic=True, matrix_function=element_matrix):
N_n, N_e = len(nodes), len(elements)
if symbolic:
A = sym.zeros(N_n, N_n)
b = sym.zeros(N_n, 1)
else:
A = np.zeros((N_n, N_n), dtype=object)
b = np.zeros(N_n, dtype=object)
for e in range(N_e):
Omega_e = [nodes[elements[e][0]], nodes[elements[e][-1]]]
A_e = matrix_function(phi, Omega_e, symbolic=symbolic)
# Only compute load vector if f is provided (not None)
if f is not None:
b_e = element_vector(f, phi, Omega_e, symbolic=symbolic)
else:
b_e = sym.zeros(len(phi), 1) if symbolic else np.zeros(len(phi), dtype=object)
for r in range(len(elements[e])):
for s in range(len(elements[e])):
A[elements[e][r], elements[e][s]] += A_e[r, s]
if f is not None:
b[elements[e][r]] += b_e[r]
return A, b
def compute_solution(A,b,symbolic=True):
if symbolic:
c=A.LUsolve(b)
else:
if hasattr(A, 'dtype') and A.dtype == object:
A_sym = sym.Matrix(A)
b_sym = sym.Matrix(b)
c = A_sym.LUsolve(b_sym)
c = np.array(c).flatten()
else:
c=np.linalg.solve(A,b)
return c

Xet Storage Details

Size:
5.37 kB
·
Xet hash:
936a31c3c744525e6b3459007659ec10023dd14d68328d2a5a70ac7f3777a92f

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.