Skip to content

Commit

Permalink
update displacement
Browse files Browse the repository at this point in the history
  • Loading branch information
obouchaara committed Jun 13, 2024
1 parent 5686c51 commit ac74852
Show file tree
Hide file tree
Showing 4 changed files with 143 additions and 58 deletions.
118 changes: 82 additions & 36 deletions notebooks/symbolic/displacement.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
],
"source": [
"data = sp.Array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])\n",
"displacement_field = SymbolicDisplacement.create_linear(data)\n",
"displacement_field = SymbolicDisplacement.create_linear(data=data)\n",
"display(displacement_field.data)"
]
},
Expand Down Expand Up @@ -104,10 +104,34 @@
{
"data": {
"text/latex": [
"$\\displaystyle \\left[\\begin{matrix}\\sqrt{x^{2} + y^{2}} & \\operatorname{atan}_{2}{\\left(y,x \\right)} & z\\end{matrix}\\right]$"
"$\\displaystyle \\sqrt{x^{2} + y^{2}}$"
],
"text/plain": [
"[sqrt(x**2 + y**2), atan2(y, x), z]"
"sqrt(x**2 + y**2)"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/latex": [
"$\\displaystyle \\operatorname{atan}_{2}{\\left(y,x \\right)}$"
],
"text/plain": [
"atan2(y, x)"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/latex": [
"$\\displaystyle z$"
],
"text/plain": [
"z"
]
},
"metadata": {},
Expand All @@ -117,7 +141,7 @@
"source": [
"cartesian_system = SymbolicCartesianCoordSystem()\n",
"coord_system = cartesian_system.to_cylindrical()\n",
"display(coord_system.basis_symbols)"
"display(*coord_system.basis)"
]
},
{
Expand All @@ -139,9 +163,9 @@
}
],
"source": [
"x1, x2, x3 = coord_system.basis_symbols\n",
"data = [x1*x1+x3, x2, x1+x3]\n",
"displacement_field = SymbolicDisplacement.create(data, cartesian_system)\n",
"x1, x2, x3 = coord_system.basis\n",
"data = sp.NDimArray([x1*x1+x3, x2, x1+x3])\n",
"displacement_field = SymbolicDisplacement(coord_system=cartesian_system, data=data)\n",
"display(displacement_field.data)"
]
},
Expand Down Expand Up @@ -194,7 +218,7 @@
{
"data": {
"text/plain": [
"(r(x, y), theta(x), z)"
"(x(x, y), theta(x), z)"
]
},
"metadata": {},
Expand All @@ -203,14 +227,13 @@
],
"source": [
"cartesian_system = SymbolicCartesianCoordSystem()\n",
"display(cartesian_system.basis_symbols)\n",
"x1_1, x2_1, x3_1 = cartesian_system.basis_symbols\n",
"display(cartesian_system.basis)\n",
"x1, x2, x3 = cartesian_system.basis\n",
"cylindrical_system = SymbolicCylindricalCoordSystem()\n",
"display(cylindrical_system.basis_symbols)\n",
"x1_2, x2_2, x3_2 = cylindrical_system.basis_symbols\n",
"custom_basis_symbols = sp.Function(x1_2)(x1_1, x2_1), sp.Function(x2_2)(x1_1), x3_2\n",
"display(custom_basis_symbols)\n",
"custom_cylindrical_system = SymbolicCylindricalCoordSystem(custom_basis_symbols)"
"display(cylindrical_system.basis)\n",
"y1, y2, y3 = cylindrical_system.basis\n",
"custom_basis = sp.Function(x1)(x1, x2), sp.Function(y2)(x1), y3\n",
"display(custom_basis)"
]
},
{
Expand All @@ -219,42 +242,64 @@
"metadata": {},
"outputs": [
{
"ename": "ValueError",
"evalue": "The field data contains symbols not in the basis or field parameters: y, x",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)",
"Cell \u001b[0;32mIn[8], line 3\u001b[0m\n\u001b[1;32m 1\u001b[0m x1, x2, x3 \u001b[38;5;241m=\u001b[39m custom_cylindrical_system\u001b[38;5;241m.\u001b[39mbasis_symbols\n\u001b[1;32m 2\u001b[0m data \u001b[38;5;241m=\u001b[39m [x1\u001b[38;5;241m*\u001b[39mx1, x1\u001b[38;5;241m+\u001b[39mx2, x3\u001b[38;5;241m*\u001b[39mx3]\n\u001b[0;32m----> 3\u001b[0m displacement_field \u001b[38;5;241m=\u001b[39m \u001b[43mSymbolicDisplacement\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcreate\u001b[49m\u001b[43m(\u001b[49m\u001b[43mdata\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcustom_cylindrical_system\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 4\u001b[0m display(displacement_field\u001b[38;5;241m.\u001b[39mdata)\n",
"File \u001b[0;32m~/mechpy/src/mechpy/core/symbolic/field.py:265\u001b[0m, in \u001b[0;36mSymbolicVectorField.create\u001b[0;34m(cls, data, coord_system, field_params)\u001b[0m\n\u001b[1;32m 261\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mConversion error\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 263\u001b[0m data \u001b[38;5;241m=\u001b[39m sp\u001b[38;5;241m.\u001b[39mImmutableDenseNDimArray(data)\n\u001b[0;32m--> 265\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mcls\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mdata\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcoord_system\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mfield_params\u001b[49m\u001b[43m)\u001b[49m\n",
"File \u001b[0;32m~/mechpy/src/mechpy/core/symbolic/displacement.py:10\u001b[0m, in \u001b[0;36mSymbolicDisplacement.__init__\u001b[0;34m(self, data, coord_system, field_params)\u001b[0m\n\u001b[1;32m 9\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m__init__\u001b[39m(\u001b[38;5;28mself\u001b[39m, data, coord_system\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m, field_params\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m):\n\u001b[0;32m---> 10\u001b[0m \u001b[38;5;28;43msuper\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[38;5;21;43m__init__\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mdata\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcoord_system\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mfield_params\u001b[49m\u001b[43m)\u001b[49m\n",
"File \u001b[0;32m~/mechpy/src/mechpy/core/symbolic/field.py:176\u001b[0m, in \u001b[0;36mSymbolicSpatialField.__init__\u001b[0;34m(self, data, coord_system, field_params)\u001b[0m\n\u001b[1;32m 173\u001b[0m data \u001b[38;5;241m=\u001b[39m sp\u001b[38;5;241m.\u001b[39mImmutableDenseNDimArray(data)\n\u001b[1;32m 175\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(data, (sp\u001b[38;5;241m.\u001b[39mExpr, sp\u001b[38;5;241m.\u001b[39mImmutableDenseNDimArray)):\n\u001b[0;32m--> 176\u001b[0m \u001b[38;5;28;43msuper\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[38;5;21;43m__init__\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mdata\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcoord_system\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mfield_params\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 177\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m 178\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mInput data must be a SymPy Expr or SymPy Array\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n",
"File \u001b[0;32m~/mechpy/src/mechpy/core/symbolic/field.py:21\u001b[0m, in \u001b[0;36mSymbolicField.__init__\u001b[0;34m(self, data, coord_system, field_params)\u001b[0m\n\u001b[1;32m 19\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mcoord_system \u001b[38;5;241m=\u001b[39m coord_system\n\u001b[1;32m 20\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mfield_params \u001b[38;5;241m=\u001b[39m field_params \u001b[38;5;129;01mor\u001b[39;00m {}\n\u001b[0;32m---> 21\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mvalidate_field\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 22\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m 23\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mcoord system must be a SymbolicCoordSystem\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n",
"File \u001b[0;32m~/mechpy/src/mechpy/core/symbolic/field.py:30\u001b[0m, in \u001b[0;36mSymbolicField.validate_field\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 28\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mvalidate_field\u001b[39m(\u001b[38;5;28mself\u001b[39m):\n\u001b[1;32m 29\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mvalidate_field_params()\n\u001b[0;32m---> 30\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mvalidate_basis_symbols\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n",
"File \u001b[0;32m~/mechpy/src/mechpy/core/symbolic/field.py:83\u001b[0m, in \u001b[0;36mSymbolicField.validate_basis_symbols\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 81\u001b[0m invalid_symbols \u001b[38;5;241m=\u001b[39m free_symbols \u001b[38;5;241m-\u001b[39m valid_symbols\n\u001b[1;32m 82\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m invalid_symbols:\n\u001b[0;32m---> 83\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[1;32m 84\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mThe field data contains symbols not in the basis or field parameters: \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 85\u001b[0m \u001b[38;5;241m+\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m, \u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;241m.\u001b[39mjoin(\u001b[38;5;28mstr\u001b[39m(symbol) \u001b[38;5;28;01mfor\u001b[39;00m symbol \u001b[38;5;129;01min\u001b[39;00m invalid_symbols)\n\u001b[1;32m 86\u001b[0m )\n",
"\u001b[0;31mValueError\u001b[0m: The field data contains symbols not in the basis or field parameters: y, x"
]
"data": {
"text/plain": [
"SymbolicCylindricalCoordSystem(origin=(0, 0, 0), basis=(x(x, y), theta(x), z))"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/latex": [
"$\\displaystyle \\left[\\begin{matrix}x^{2}{\\left(x,y \\right)} & \\theta{\\left(x \\right)} + x{\\left(x,y \\right)} & z^{2}\\end{matrix}\\right]$"
],
"text/plain": [
"[x(x, y)**2, theta(x) + x(x, y), z**2]"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"x1, x2, x3 = custom_cylindrical_system.basis_symbols\n",
"data = [x1*x1, x1+x2, x3*x3]\n",
"displacement_field = SymbolicDisplacement.create(data, custom_cylindrical_system)\n",
"custom_cylindrical_system = SymbolicCylindricalCoordSystem(basis=custom_basis)\n",
"display(custom_cylindrical_system)\n",
"x1, x2, x3 = custom_cylindrical_system.basis\n",
"data = sp.NDimArray([x1 * x1, x1 + x2, x3 * x3])\n",
"displacement_field = SymbolicDisplacement.create(\n",
" coord_system=custom_cylindrical_system,\n",
" data=data,\n",
" symbols_validation=False,\n",
")\n",
"display(displacement_field.data)"
]
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 9,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
"$\\displaystyle \\left[\\begin{matrix}2 r{\\left(x,y \\right)} \\frac{\\partial}{\\partial x} r{\\left(x,y \\right)} & \\frac{\\partial}{\\partial y} r{\\left(x,y \\right)} & 2 z\\\\\\frac{\\partial}{\\partial y} r{\\left(x,y \\right)} & r{\\left(x,y \\right)} \\frac{\\partial}{\\partial y} r{\\left(x,y \\right)} + \\frac{\\frac{\\partial}{\\partial x} r{\\left(x,y \\right)}}{2} + \\frac{\\frac{d}{d x} \\theta{\\left(x \\right)}}{2} & 0\\\\2 z & 0 & 0\\end{matrix}\\right]$"
"$\\displaystyle \\left[\\begin{matrix}2 x{\\left(x,y \\right)} \\frac{\\partial}{\\partial x} x{\\left(x,y \\right)} & \\frac{\\partial}{\\partial y} x{\\left(x,y \\right)} & 2 z & 2 x{\\left(x,y \\right)} \\frac{\\partial}{\\partial y} x{\\left(x,y \\right)} + \\frac{d}{d x} \\theta{\\left(x \\right)} + \\frac{\\partial}{\\partial x} x{\\left(x,y \\right)} & 0 & 0\\end{matrix}\\right]$"
],
"text/plain": [
"[2*x(x, y)*Derivative(x(x, y), x), Derivative(x(x, y), y), 2*z, 2*x(x, y)*Derivative(x(x, y), y) + Derivative(theta(x), x) + Derivative(x(x, y), x), 0, 0]"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/latex": [
"$\\displaystyle \\left[\\begin{matrix}2 x{\\left(x,y \\right)} \\frac{\\partial}{\\partial x} x{\\left(x,y \\right)} & \\frac{\\partial}{\\partial y} x{\\left(x,y \\right)} & 2 z\\\\\\frac{\\partial}{\\partial y} x{\\left(x,y \\right)} & x{\\left(x,y \\right)} \\frac{\\partial}{\\partial y} x{\\left(x,y \\right)} + \\frac{\\frac{d}{d x} \\theta{\\left(x \\right)}}{2} + \\frac{\\frac{\\partial}{\\partial x} x{\\left(x,y \\right)}}{2} & 0\\\\2 z & 0 & 0\\end{matrix}\\right]$"
],
"text/plain": [
"[[2*r(x, y)*Derivative(r(x, y), x), Derivative(r(x, y), y), 2*z], [Derivative(r(x, y), y), r(x, y)*Derivative(r(x, y), y) + Derivative(r(x, y), x)/2 + Derivative(theta(x), x)/2, 0], [2*z, 0, 0]]"
"[[2*x(x, y)*Derivative(x(x, y), x), Derivative(x(x, y), y), 2*z], [Derivative(x(x, y), y), x(x, y)*Derivative(x(x, y), y) + Derivative(theta(x), x)/2 + Derivative(x(x, y), x)/2, 0], [2*z, 0, 0]]"
]
},
"metadata": {},
Expand All @@ -263,6 +308,7 @@
],
"source": [
"strain_tensor = displacement_field.strain_tensor(cartesian_system)\n",
"display(strain_tensor.data)\n",
"display(strain_tensor.to_general().data)"
]
}
Expand Down
14 changes: 7 additions & 7 deletions src/mechpy/core/symbolic/displacement.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
import sympy as sp

from .strain import SymbolicStrainTensor
from .coord import SymbolicCartesianCoordSystem
from .field import SymbolicVectorField
from .strain import SymbolicStrainTensor


class SymbolicDisplacement(SymbolicVectorField):
def __init__(self, data, coord_system=None, field_params=None):
super().__init__(data, coord_system, field_params)
def __init__(self, coord_system, data, field_params=None, symbols_validation=True):
super().__init__(coord_system, data, field_params, symbols_validation)

def __repr__(self):
return f"SymbolicDisplacement(\n{self.data}\n)"

def strain_tensor(self, coord_system=None) -> SymbolicStrainTensor:
if not coord_system:
coord_system = SymbolicCartesianCoordSystem()
if coord_system is None:
coord_system = self.coord_system

x1, x2, x3 = coord_system.basis_symbols
x1, x2, x3 = coord_system.basis
u, v, w = self.data
e_11 = sp.diff(u, x1)
e_22 = sp.diff(v, x2)
Expand All @@ -25,5 +25,5 @@ def strain_tensor(self, coord_system=None) -> SymbolicStrainTensor:
e_23 = sp.diff(v, x3) + sp.diff(w, x2)
e_31 = sp.diff(w, x1) + sp.diff(u, x3)
components = [e_11, e_22, e_33, e_12, e_23, e_31]
strain_tensor = SymbolicStrainTensor.from_list(components, notation=2)
strain_tensor = SymbolicStrainTensor.from_list(components, notation="voigt")
return strain_tensor
39 changes: 24 additions & 15 deletions src/mechpy/core/symbolic/field.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@


class SymbolicField:
def __init__(self, coord_system, data, field_params=None):
def __init__(self, coord_system, data, field_params=None, symbols_validation=True):
"""
Initialize a SymbolicField instance.
Expand Down Expand Up @@ -47,23 +47,30 @@ def __init__(self, coord_system, data, field_params=None):
"Field parameters must not overlap with coordinate system basis symbols."
)

invalid_symbols = self.get_invalid_symbols()
if len(invalid_symbols):
raise ValueError(
"The field data contains symbols not in the basis or field parameters: "
+ ", ".join(str(s) for s in invalid_symbols)
)
if symbols_validation:
invalid_symbols = self.get_invalid_symbols()
if len(invalid_symbols):
raise ValueError(
"The field data contains symbols not in the basis or field parameters: "
+ ", ".join(str(s) for s in invalid_symbols)
)

def __repr__(self):
return f"{self.__class__.__name__}(\n{self.coord_system.basis},\n{self.data},\n{self.field_params})"

def get_invalid_symbols(self):
def get_ignored_symbols(data):
symbols_set = set()
# to implement
return symbols_set

basis = set(self.coord_system.basis)
field_param = set(self.field_params)
valid_symbols = basis.union(field_param)
free_symbols = self.data.free_symbols
free_symbols = {s for s in free_symbols if not isinstance(s, sp.Number)}
invalid_symbols = free_symbols - valid_symbols
ignored_symbols = get_ignored_symbols(self.data)
invalid_symbols = free_symbols - valid_symbols - ignored_symbols
return invalid_symbols

def subs_field_params(self, param_values):
Expand Down Expand Up @@ -135,8 +142,8 @@ def subs(self, subs_dict, keys=False):


class SymbolicSpatialField(SymbolicField):
def __init__(self, coord_system, data, field_params=None):
super().__init__(coord_system, data, field_params)
def __init__(self, coord_system, data, field_params=None, symbols_validation=True):
super().__init__(coord_system, data, field_params, symbols_validation)

def lambdify(self):
"""
Expand Down Expand Up @@ -276,7 +283,7 @@ class SymbolicVectorField(SymbolicSpatialField):
shape = (3,)

@classmethod
def create(cls, coord_system=None, data=None, field_params=None):
def create(cls, coord_system=None, data=None, field_params=None, symbols_validation=True):
if data is None:
if coord_system is None:
coord_system = SymbolicCartesianCoordSystem()
Expand All @@ -290,16 +297,18 @@ def create(cls, coord_system=None, data=None, field_params=None):
if coord_system is None:
coord_system = SymbolicCartesianCoordSystem()
try:
components = sp.NDimArray(data, shape=(3, 3))
is_symbolic = lambda _: isinstance(_, (sp.Number, sp.Symbol, sp.Expr)) # to validation module
components = sp.NDimArray(data, shape=(3,))
is_symbolic = lambda _: isinstance(
_, (sp.Number, sp.Symbol, sp.Expr)
) # to validation module
if not all(is_symbolic(_) for _ in components):
raise ValueError("data type error")
except:
raise ValueError("Conversion error")

data = sp.NDimArray(data)
data = sp.NDimArray(data, shape=(3,))

return cls(data, coord_system, field_params)
return cls(coord_system, data, field_params, symbols_validation)

@classmethod
def create_linear(cls, coord_system=None, data=None, field_params=None):
Expand Down
Loading

0 comments on commit ac74852

Please sign in to comment.