diff --git a/notebooks/symbolic/stress.ipynb b/notebooks/symbolic/stress.ipynb index 3b3e239..8c6d195 100644 --- a/notebooks/symbolic/stress.ipynb +++ b/notebooks/symbolic/stress.ipynb @@ -43,19 +43,10 @@ { "data": { "text/latex": [ - "$\\displaystyle \\left[\\begin{matrix}σ_{11} & σ_{22} & σ_{33} & σ_{23} & σ_{13} & σ_{12}\\end{matrix}\\right]$" + "$\\displaystyle \\left[\\begin{matrix}\\sigma_{11} & \\sigma_{22} & \\sigma_{33} & \\sigma_{23} & \\sigma_{13} & \\sigma_{12}\\end{matrix}\\right]$" ], "text/plain": [ - "[σ_11, σ_22, σ_33, σ_23, σ_13, σ_12]" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "mechpy.core.symbolic.stress.SymbolicStressTensor" + "[\\sigma_11, \\sigma_22, \\sigma_33, \\sigma_23, \\sigma_13, \\sigma_12]" ] }, "metadata": {}, @@ -63,11 +54,12 @@ } ], "source": [ - "s_11, s_22, s_33, s_23, s_13, s_12 = sp.symbols('σ_11 σ_22 σ_33 σ_23 σ_13 σ_12')\n", - "data = sp.ImmutableDenseNDimArray([s_11, s_22, s_33, s_23, s_13, s_12])\n", - "display(data)\n", + "s_11, s_22, s_33, s_23, s_13, s_12 = sp.symbols(\n", + " \"\\\\sigma_11 \\\\sigma_22 \\\\sigma_33 \\\\sigma_23 \\\\sigma_13 \\\\sigma_12\"\n", + ")\n", + "data = sp.NDimArray([s_11, s_22, s_33, s_23, s_13, s_12])\n", "sigma = SymbolicStressTensor(data)\n", - "display(sigma.__class__)" + "display(sigma.data)" ] }, { @@ -91,8 +83,11 @@ "outputs": [ { "data": { + "text/latex": [ + "$\\displaystyle \\left[\\begin{matrix}\\sigma_{1} & \\sigma_{2} & \\sigma_{3} & \\sigma_{4} & \\sigma_{5} & \\sigma_{6}\\end{matrix}\\right]$" + ], "text/plain": [ - "mechpy.core.symbolic.stress.SymbolicStressTensor" + "[\\sigma_1, \\sigma_2, \\sigma_3, \\sigma_4, \\sigma_5, \\sigma_6]" ] }, "metadata": {}, @@ -100,11 +95,8 @@ }, { "data": { - "text/latex": [ - "$\\displaystyle \\left[\\begin{matrix}\\sigma_{1} & \\sigma_{2} & \\sigma_{3} & \\sigma_{4} & \\sigma_{5} & \\sigma_{6}\\end{matrix}\\right]$" - ], "text/plain": [ - "[\\sigma_1, \\sigma_2, \\sigma_3, \\sigma_4, \\sigma_5, \\sigma_6]" + "'standard'" ] }, "metadata": {}, @@ -125,10 +117,8 @@ ], "source": [ "stress_tensor = SymbolicStressTensor.create()\n", - "display(stress_tensor.__class__)\n", "display(stress_tensor.data)\n", - "# display(stress_tensor.notation)\n", - "# display(stress_tensor.name)\n", + "display(stress_tensor.notation)\n", "display(stress_tensor.to_general().data)" ] }, @@ -159,19 +149,7 @@ { "data": { "text/plain": [ - "2" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/latex": [ - "$\\displaystyle \\sigma$" - ], - "text/plain": [ - "\\sigma" + "'voigt'" ] }, "metadata": {}, @@ -191,12 +169,9 @@ } ], "source": [ - "stress_tensor = SymbolicStressTensor.create(notation=2)\n", - "# display(stress_tensor)\n", + "stress_tensor = SymbolicStressTensor.create(notation=\"voigt\")\n", "display(stress_tensor.data)\n", "display(stress_tensor.notation)\n", - "# display(stress_tensor.name)\n", - "display(sp.symbols(stress_tensor.name))\n", "display(stress_tensor.to_general().data)" ] }, @@ -238,12 +213,9 @@ } ], "source": [ - "stress_tensor = SymbolicStressTensor.create(name=\"\\sigma^1\", notation=2)\n", - "# display(stress_tensor)\n", - "# display(stress_tensor.data)\n", - "# display(stress_tensor.notation)\n", - "# display(stress_tensor.name)\n", - "display(sp.symbols(stress_tensor.name))\n", + "name = sp.symbols(\"\\sigma^1\")\n", + "display(name)\n", + "stress_tensor = SymbolicStressTensor.create(name=name, notation=\"voigt\")\n", "display(stress_tensor.to_general().data)" ] }, @@ -321,7 +293,7 @@ } ], "source": [ - "stress_tensor = SymbolicStressTensor.create(notation=2)\n", + "stress_tensor = SymbolicStressTensor.create(notation=\"voigt\")\n", "display(stress_tensor.data)\n", "\n", "\n" @@ -354,13 +326,13 @@ ], "source": [ "s_11 = stress_tensor[0]\n", - "subs_dict = {\n", + "subs = {\n", " 1: s_11,\n", " 2: s_11,\n", " 3: 0,\n", " 4: 1,\n", "}\n", - "stress_tensor.subs(subs_dict, keys=True)\n", + "stress_tensor.subs_tensor_components(subs)\n", "display(stress_tensor.data)" ] }, @@ -390,10 +362,10 @@ } ], "source": [ - "subs_dict = {\n", + "subs = {\n", " s_11: 0,\n", "}\n", - "stress_tensor.subs(subs_dict)\n", + "stress_tensor.subs(subs)\n", "display(stress_tensor.data)" ] }, diff --git a/src/mechpy/core/symbolic/stress.py b/src/mechpy/core/symbolic/stress.py index 68678b1..ce01520 100644 --- a/src/mechpy/core/symbolic/stress.py +++ b/src/mechpy/core/symbolic/stress.py @@ -4,15 +4,22 @@ class SymbolicStressTensor(SS3X3T): - STRESS_VOIGT_MAPPING = {0: 1, 1: 1, 2: 1, 3: 1, 4: 1, 5: 1} + STRESS_VOIGT_MAPPING = { + 0: 1, + 1: 1, + 2: 1, + 3: 1, + 4: 1, + 5: 1, + } - def __init__(self, data, name=None, notation=1): + def __init__(self, data, name=None, notation=None): super().__init__(data, name=name, notation=notation) @classmethod - def create(cls, name="\sigma", notation=1): + def create(cls, name="\\sigma", notation=None): stress_tensor = super().create(name, notation) - if notation == 2: + if notation == "voigt": data = stress_tensor.data mapping = cls.STRESS_VOIGT_MAPPING new_components = [data[key] * value for key, value in mapping.items()] @@ -20,13 +27,14 @@ def create(cls, name="\sigma", notation=1): return stress_tensor def to_general(self): - if self.notation == 1: + if self.notation == "standard": if self.name: return SymbolicStressTensor.create( - name=self.name, notation=2 + name=self.name, + notation="voigt", ).to_general() raise ValueError("Should have a name") - elif self.notation == 2: + elif self.notation == "voigt": data = self.data mapping = self.STRESS_VOIGT_MAPPING new_components = [data[key] / value for key, value in mapping.items()] @@ -38,7 +46,7 @@ def normal_components(self): def shear_components(self): return self.data[3:] - + def principal_components(self): return self.eigenvalues().keys() diff --git a/src/mechpy/core/symbolic/tensor.py b/src/mechpy/core/symbolic/tensor.py index ed7219d..b6631e4 100644 --- a/src/mechpy/core/symbolic/tensor.py +++ b/src/mechpy/core/symbolic/tensor.py @@ -102,7 +102,9 @@ def to_3x3(self): ) raise ValueError("The tensor is not a 3x3 Array.") - def to_sym_3x3(self, notation="standard"): + def to_sym_3x3(self, notation=None): + if notation is None: + notation = "standard" if self.data.shape == (3, 3) and self.is_symmetric(): return self.to_3x3().to_symmetric(notation) raise ValueError("The tensor is not a symmetric 3x3 Array.") @@ -137,19 +139,28 @@ def create(cls, shape, name): return cls(data, name=name) def subs_tensor_params(self, param_values): - pass - - def subs(self, subs_dict, keys=False): - raise DeprecationWarning - # try: - # if keys: - # for k, v in subs_dict.items(): - # component = self.data[k] - # self.data = self.data.subs({component: v}) - # else: - # self.data = self.data.subs(subs_dict) - # except Exception as e: - # raise RuntimeError(f"An error occurred during substitution: {e}") + if not isinstance(param_values, dict): + raise TypeError("param_values must be a dictionary") + + # Perform the substitution for provided parameters + for param, value in param_values.items(): + if not param in self.tensor_params: + raise ValueError(f"Parameter {param} not found in tensor parameters") + + self.data = self.data.subs(param, value) + self.tensor_params.pop(param) + + def subs_tensor_components(self, components_values): + data = sp.MutableDenseNDimArray(self.data) + for key, value in components_values.items(): + data[key] = value + self.data = sp.NDimArray(data) + + def subs(self, subs_dict): + try: + self.data = self.data.subs(subs_dict) + except Exception as e: + raise RuntimeError(f"An error occurred during substitution: {e}") def __matmul__(self, other): if not isinstance(other, SymbolicTensor): @@ -195,7 +206,9 @@ def from_list(cls, components): def create(cls, name): return super().create(cls.shape, name) - def to_symmetric(self, notation="standard"): + def to_symmetric(self, notation=None): + if notation is None: + notation = "standard" if not self.is_symmetric(): raise ValueError("The tensor is not symmetric.") NOTATIONS = SymbolicSymmetricThreeByThreeTensor.NOTATIONS @@ -296,11 +309,13 @@ def __init__( self, data, name=None, - notation="standard", + notation=None, tensor_params=None, ): if not isinstance(data, sp.NDimArray) or data.shape != self.shape: raise ValueError("Data must be a 6x1 SymPy Array.") + if notation is None: + notation = "standard" if notation not in self.NOTATIONS.keys(): raise NotImplementedError(f"Notation {notation} not implemented.") @@ -318,10 +333,12 @@ def from_list( cls, components, name=None, - notation="standard", + notation=None, ): if not isinstance(components, list): raise ValueError("Input must be a list") + if notation is None: + notation = "standard" if notation not in cls.NOTATIONS.keys(): raise NotImplementedError(f"Notation {notation} not implemented") @@ -338,8 +355,10 @@ def from_list( def create( cls, name, - notation="standard", + notation=None, ): + if notation is None: + notation = "standard" if notation == "voigt": mapping = cls.INVERSE_VOIGT_MAPPING components = [sp.symbols(f"{name}_{i+1}{j+1}") for i, j in mapping.values()] diff --git a/tests/test_core.py b/tests/test_core.py index 50e9c9b..6d6de38 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -22,6 +22,10 @@ SymbolicSymmetricThreeByThreeTensor, ) +from mechpy.core.symbolic.stress import ( + SymbolicStressTensor, +) + class TestSymbolicCoordSystem(unittest.TestCase): def test_init(self): @@ -502,7 +506,6 @@ def test_to_3x3(self): new_tensor = tensor.to_3x3() self.assertIsInstance(new_tensor, SymbolicThreeByThreeTensor) self.assertEqual(new_tensor.data, data) - def test_to_sym_3x3(self): data = sp.NDimArray([[1, 2, 3], [2, 4, 5], [3, 5, 6]]) @@ -512,20 +515,20 @@ def test_to_sym_3x3(self): self.assertEqual(new_tensor.data, sp.NDimArray([1, 2, 3, 4, 5, 6])) def test_to_6x6(self): - data = sp.NDimArray([ - [11, 21, 31, 41, 51, 61], - [12, 22, 32, 42, 52, 62], - [13, 23, 33, 43, 53, 63], - [14, 24, 34, 44, 54, 64], - [15, 25, 35, 45, 55, 65], - [16, 26, 36, 46, 56, 66], - ]) + data = sp.NDimArray( + [ + [11, 21, 31, 41, 51, 61], + [12, 22, 32, 42, 52, 62], + [13, 23, 33, 43, 53, 63], + [14, 24, 34, 44, 54, 64], + [15, 25, 35, 45, 55, 65], + [16, 26, 36, 46, 56, 66], + ] + ) tensor = SymbolicTensor(data) new_tensor = tensor.to_6x6() self.assertIsInstance(new_tensor, SymbolicSixBySixTensor) self.assertEqual(new_tensor.data, data) - - def test_from_list(self): components = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] @@ -984,5 +987,65 @@ def test_diagonalize(self): pass +class TestSymbolicStressTensor(unittest.TestCase): + def test_init(self): + s_1, s_2, s_3, s_4, s_5, s_6 = sp.symbols( + "\\sigma_1 \\sigma_2 \\sigma_3 \\sigma_4 \\sigma_5 \\sigma_6" + ) + data = sp.NDimArray([s_1, s_2, s_3, s_4, s_5, s_6]) + stress_tensor = SymbolicStressTensor(data) + self.assertEqual(stress_tensor.data, data) + self.assertEqual(stress_tensor.name, None) + self.assertEqual(stress_tensor.notation, "standard") + self.assertEqual(stress_tensor.tensor_params, {}) + + def test_create(self): + s_1, s_2, s_3, s_4, s_5, s_6 = sp.symbols( + "\\sigma_1 \\sigma_2 \\sigma_3 \\sigma_4 \\sigma_5 \\sigma_6" + ) + data = sp.NDimArray([s_1, s_2, s_3, s_4, s_5, s_6]) + + stress_tensor = SymbolicStressTensor.create() + self.assertIsInstance(stress_tensor, SymbolicStressTensor) + stress_tensor = SymbolicStressTensor(data) + + def test_to_general(self): + pass + + def test_normal_components(self): + s_1, s_2, s_3, s_4, s_5, s_6 = sp.symbols( + "\\sigma_1 \\sigma_2 \\sigma_3 \\sigma_4 \\sigma_5 \\sigma_6" + ) + data = sp.NDimArray([s_1, s_2, s_3, s_4, s_5, s_6]) + stress_tensor = SymbolicStressTensor(data) + self.assertEqual( + stress_tensor.normal_components(), + sp.NDimArray([s_1, s_2, s_3]), + ) + + def test_shear_components(self): + s_1, s_2, s_3, s_4, s_5, s_6 = sp.symbols( + "\\sigma_1 \\sigma_2 \\sigma_3 \\sigma_4 \\sigma_5 \\sigma_6" + ) + data = sp.NDimArray([s_1, s_2, s_3, s_4, s_5, s_6]) + stress_tensor = SymbolicStressTensor(data) + self.assertEqual( + stress_tensor.shear_components(), + sp.NDimArray([s_4, s_5, s_6]), + ) + + def test_principal_components(self): + pass + + def test_pressure(self): + pass + + def test_tresca(self): + pass + + def test_von_mises(self): + pass + + if __name__ == "__main__": unittest.main()