Bernoulli Console with Random Geometry

[122]:
seed = 0  # integer or None
summary = {}  # we will this up during execution
[123]:
import numpy as np

rs = np.random.RandomState()
if isinstance(seed, int):
    rs.seed(seed)


def brownian1d(T=1, N=100, mu=0.1, sigma=0.01, S0=20):
    dt = float(T)/N
    t = np.linspace(0, T, N)
    W = rs.standard_normal(size=N)
    W = np.cumsum(W)*np.sqrt(dt)  # standard brownian motion
    X = (mu-0.5*sigma**2)*t + sigma*W
    S = S0*np.exp(X)  # geometric brownian motion
    return S


params = dict(T=0.1, N=100, mu=0.5, sigma=0.1)

x = brownian1d(**params)
y = brownian1d(**params)
z = brownian1d(**params)

[124]:
from polymesh import PolyData, CartesianFrame, LineData
import numpy as np

frame = CartesianFrame(dim=3)

coords = np.stack([x, y, z], axis=1)
topo = np.zeros((coords.shape[0]-1, 2)).astype(int)
topo[:, 0] = np.arange(topo.shape[0])
topo[:, 1] = topo[:, 0] + 1

mesh = PolyData(coords=coords, frame=frame)
mesh['lines'] = LineData(topo=topo, frame=frame)

mesh.plot(notebook=False)

Index and coordinate of the last node. Later, when the 2-noded mesh is transformed into a mesh of 3-noded elements, this information is going to be necessary to identify the free end.

[125]:
i_last = len(coords) - 1
i_last, coords[i_last]
[125]:
(99, array([21.41614825, 21.56705787, 20.62494753]))

The parameters of the following cell are up for manipulation. They define a simple rectangular cross section and an isotropic Hooke model governed by Young’s modulus and Poisson’s ratio.

[126]:
# INPUT DATA
w, h = 10., 10.  # width and height of the rectangular cross section
F = -100.  # value of the vertical load at the free end
E = 210000.0  # Young's modulus
nu = 0.3  # Poisson's ratio

The model stiffness matrix is calculated automatically here:

[127]:
import numpy as np
from numpy import pi as PI

# cross section
A = w * h  # area
Iy = w * h**3 / 12  # second moment of inertia around the y axis
Iz = w * h**3 / 12  # second moment of inertia around the z axis
Ix = Iy + Iz  # torsional inertia

# model stiffness matrix
G = E / (2 * (1 + nu))
Hooke = np.array([
    [E*A, 0, 0, 0],
    [0, G*Ix, 0, 0],
    [0, 0, E*Iy, 0],
    [0, 0, 0, E*Iz]
])

The B2 element

Run a linear analysis and do some postprocessing using 2-Noded Bernoulli members.

[128]:
from sigmaepsilon.solid import Structure, LineMesh, PointData
from neumann.linalg import linspace, Vector
from polymesh.space import StandardFrame, PointCloud, frames_of_lines
from sigmaepsilon.solid.fem.cells import B2 as Beam

# space
GlobalFrame = StandardFrame(dim=3)

# support at the first, load at the last node
loads = np.zeros((coords.shape[0], 6))
fixity = np.zeros((coords.shape[0], 6)).astype(bool)
global_load_vector = Vector([0., 0, F], frame=GlobalFrame).show()
loads[-1, :3] = global_load_vector
fixity[0, :] = True

# pointdata
pd = PointData(coords=coords, frame=GlobalFrame,
               loads=loads, fixity=fixity)

# celldata
frames = frames_of_lines(coords, topo)
cd = Beam(topo=topo, frames=frames)

# set up mesh and structure
mesh = LineMesh(pd, cd, model=Hooke, frame=GlobalFrame)
structure = Structure(mesh=mesh)
structure.linsolve()

# postproc
# 1) displace the mesh
dofsol = structure.nodal_dof_solution(store='dofsol')
forces = structure.nodal_forces()
reactions = structure.reaction_forces()

Vertical displacement of the free end, external load at the free end and Vertical reaction force at the support:

[129]:
dofsol[-1, 2], forces[-1, 2], reactions[0, 2]
[129]:
(-1.985415419091222e-05, -100.0, 99.99999993859637)

Work of the external forces at the free end:

[130]:
dofsol[-1] @ forces[-1]
[130]:
0.0019854154190912217
[131]:
internal_forces = structure.internal_forces()
internal_forces[0, 0, 2]
[131]:
-99.81153149633388

The B3 element

We transform the mesh using the appropriate transformation function from PolyMesh.

[132]:
from polymesh.topo.tr import L2_to_L3
coords, topo = L2_to_L3(coords, topo)

Rebuild and calculate the mesh using 3-Node elements.

[133]:
from sigmaepsilon.solid.fem.cells import B3 as Beam

# support at the first, load at the last node
loads = np.zeros((coords.shape[0], 6))
fixity = np.zeros((coords.shape[0], 6)).astype(bool)
global_load_vector = Vector([0., 0, F], frame=GlobalFrame).show()
loads[i_last, :3] = global_load_vector
fixity[0, :] = True

# pointdata
pd = PointData(coords=coords, frame=GlobalFrame,
               loads=loads, fixity=fixity)

# celldata
frames = frames_of_lines(coords, topo)
cd = Beam(topo=topo, frames=frames)

# set up mesh and structure
mesh = LineMesh(pd, cd, model=Hooke, frame=GlobalFrame)
structure = Structure(mesh=mesh)
structure.linsolve()

# postproc
# 1) displace the mesh
dofsol = structure.nodal_dof_solution(store='dofsol')
forces = structure.nodal_forces()
reactions = structure.reaction_forces()
[134]:
dofsol[i_last, 2], forces[i_last, 2], reactions[0, 2]
[134]:
(-1.9854154472816174e-05, -100.0, 100.00000173423086)
[135]:
dofsol[i_last] @ forces[i_last]
[135]:
0.0019854154472816175
[136]:
internal_forces = structure.internal_forces()
internal_forces[0, 0, 2]
[136]:
-99.81153322028695