Skip to content

Commit

Permalink
Merge pull request #6 from jpsferreira/feat/compressible-neohooke
Browse files Browse the repository at this point in the history
Enhance Kinematics documentation and refactor SEF calculation
  • Loading branch information
jpsferreira authored Jan 3, 2025
2 parents a4699ad + ffea6c6 commit a036703
Show file tree
Hide file tree
Showing 19 changed files with 3,288 additions and 902 deletions.
4 changes: 1 addition & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@ Hyperelastic Surrogates

## Installation

```bash
pip install hyper-surrogate
```
- Read the [installation guide](https://jpsferreira.github.io/hyper-surrogate/installation.html) for more information.

## Usage

Expand Down
10 changes: 10 additions & 0 deletions docs/custom.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
document.addEventListener("DOMContentLoaded", function () {
renderMathInElement(document.body, {
delimiters: [
{ left: "$$", right: "$$", display: true },
{ left: "$", right: "$", display: false },
{ left: "\\[", right: "\\]", display: true },
{ left: "\\(", right: "\\)", display: false },
],
});
});
54 changes: 54 additions & 0 deletions docs/installation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Installation

## From source

- Clone the repository

```zsh
git clone https://github.com/jpsferreira/hyper-surrogate.git
cd hyper-surrogate
```

- Install dependencies

```zsh
poetry install
```

or

```zsh
uv install
```

- Load python environment

```zsh
poetry shell
```

or

```zsh
source .venv/bin/activate
```

- Run tests

```zsh
pytest
```

## From PyPI

```zsh
pip install hyper-surrogate
```

```zsh
poetry add hyper-surrogate
```

```zsh
uv add hyper-surrogate
```
338 changes: 338 additions & 0 deletions docs/tutorial1.ipynb

Large diffs are not rendered by default.

35 changes: 30 additions & 5 deletions hyper_surrogate/deformation_gradient.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ def generate(
stretch_max: float = 3.0,
shear_min: float = -1,
shear_max: float = 1,
mode: str | None = None,
) -> Any:
"""
Generates a random deformation gradient.
Expand All @@ -269,11 +270,39 @@ def generate(
stretch_max (float): Maximum value for stretch. Default is 3.0.
shear_min (float): Minimum value for shear. Default is -1.
shear_max (float): Maximum value for shear. Default is 1.
mode (str): Mode for deformation gradient generation.
Options are 'uniaxial', 'shear', 'biaxial', or None.
Default is None.
Returns:
Any: Generated random deformation gradient.
"""

def generate_uniaxial() -> Any:
u = self.generator.uniform(stretch_min, stretch_max)
return self.rotate(self.uniaxial(u), self.generate_rotation())

def generate_shear() -> Any:
s = self.generator.uniform(shear_min, shear_max)
return self.rotate(self.shear(s), self.generate_rotation())

def generate_biaxial() -> Any:
b1 = self.generator.uniform(stretch_min, stretch_max)
b2 = self.generator.uniform(stretch_min, stretch_max)
return self.rotate(self.biaxial(b1, b2), self.generate_rotation())

# Map modes to corresponding functions
mode_map = {
"uniaxial": generate_uniaxial,
"shear": generate_shear,
"biaxial": generate_biaxial,
}

# If mode is specified, use the corresponding function
if mode in mode_map:
return mode_map[mode]()

# Default: combine all modes
u, s, b1, b2 = (
self.generator.uniform(stretch_min, stretch_max),
self.generator.uniform(shear_min, shear_max),
Expand All @@ -290,11 +319,7 @@ def generate(
self.generate_rotation(),
self.generate_rotation(),
)

# rotate deformation gradients
fu = self.rotate(fu, r1)
fs = self.rotate(fs, r2)
fb = self.rotate(fb, r3)

# Compute deformation gradient
return np.matmul(np.matmul(fb, fu), fs)
101 changes: 68 additions & 33 deletions hyper_surrogate/kinematics.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,28 @@


class Kinematics:
"""A class that provides various kinematic methods."""
"""
A class that provides various kinematic methods.
Attributes:
None: This class does not have any attributes.
Methods:
jacobian: Compute the Jacobian of the deformation gradient.
invariant1: Calculate the first invariant of each tensor in the batch.
invariant2: Calculate the second invariant of the deformation gradient tensor.
invariant3: Calculate the third invariant of the deformation gradient tensor.
right_cauchy_green: Compute the right Cauchy-Green deformation tensor for a batch of deformation gradients.
left_cauchy_green: Compute the left Cauchy-Green deformation tensor for a batch of deformation gradients.
rotation_tensor: Compute the rotation tensors.
pushforward: Forward tensor configuration.
principal_stretches: Compute the principal stretches.
principal_directions: Compute the principal directions.
"""

def __init__(self) -> None:
"""
Initialize the Kinematics object.
Returns:
None
"""
pass

def jacobian(self, f: np.ndarray) -> Any:
@staticmethod
def jacobian(f: np.ndarray) -> Any:
"""
Compute the Jacobian of the deformation gradient.
Expand All @@ -28,45 +38,45 @@ def jacobian(self, f: np.ndarray) -> Any:
return np.linalg.det(f)

@staticmethod
def invariant1(F: np.ndarray) -> Any:
def invariant1(f: np.ndarray) -> Any:
"""
Calculate the first invariant of each tensor in the batch.
Args:
F: 4D tensor of shape (N, 3, 3, 3).
f: 4D tensor of shape (N, 3, 3, 3).
Returns:
The first invariant of each tensor in the batch.
"""
# einsum
return np.einsum("nii->n", F)
return np.einsum("nii->n", f)

@staticmethod
def invariant2(F: np.ndarray) -> Any:
def invariant2(f: np.ndarray) -> Any:
"""
Calculate the second invariant of the deformation gradient tensor.
Args:
F: 4D tensor of shape (N, 3, 3, 3).
f: 4D tensor of shape (N, 3, 3, 3).
Returns:
The second invariant.
"""
# use einsum to calculate the second invariant: 0.5 * (np.trace(F) ** 2 - np.trace(np.matmul(F, F)))
return 0.5 * (np.einsum("nii->n", F) ** 2 - np.einsum("nij,nji->n", F, F))
return 0.5 * (np.einsum("nii->n", f) ** 2 - np.einsum("nij,nji->n", f, f))

@staticmethod
def invariant3(F: np.ndarray) -> Any:
def invariant3(f: np.ndarray) -> Any:
"""
Calculate the third invariant of the deformation gradient tensor.
Args:
F: The deformation gradient tensor as a 3D array.
f: The deformation gradient tensor as a 3D array.
Returns:
The third invariant.
"""
return np.linalg.det(F)
return np.linalg.det(f)

@staticmethod
def right_cauchy_green(f: np.ndarray) -> Any:
Expand Down Expand Up @@ -110,19 +120,6 @@ def left_cauchy_green(f: np.ndarray) -> Any:
# and 'jk' are the indices for the second matrix (transposed to 'kj' for multiplication).
return np.einsum("nij,nkj->nik", f, f)

@staticmethod
def rotation_tensor(f: np.ndarray) -> Any:
"""
Compute the rotation tensors.
Args:
f (np.ndarray): The deformation gradients. batched with shape (N, 3, 3).
Returns:
np.ndarray: The rotation tensors. batched with shape (N, 3, 3).
"""
return np.einsum("nij,njk->nik", f, np.linalg.inv(f))

@staticmethod
def pushforward(f: np.ndarray, tensor2D: np.ndarray) -> Any:
"""
Expand Down Expand Up @@ -161,3 +158,41 @@ def principal_directions(self, f: np.ndarray) -> np.ndarray:
np.ndarray: The principal directions.
"""
return np.linalg.eig(self.right_cauchy_green(f))[1]

def right_stretch_tensor(self, f: np.ndarray) -> Any:
"""
Compute the right stretch tensor.
Args:
f (np.ndarray): The deformation gradient.
Returns:
np.ndarray: The right stretch tensor.
"""
v, vv = np.linalg.eig(self.right_cauchy_green(f))
return np.einsum("...ij,...j->...ij", vv, v)

def left_stretch_tensor(self, f: np.ndarray) -> Any:
"""
Compute the left stretch tensor.
Args:
f (np.ndarray): The deformation gradient.
Returns:
np.ndarray: The left stretch tensor.
"""
v, vv = np.linalg.eig(self.left_cauchy_green(f))
return np.einsum("...ij,...j->...ij", vv, v)

def rotation_tensor(self, f: np.ndarray) -> Any:
"""
Compute the rotation tensors.
Args:
f (np.ndarray): The deformation gradients. batched with shape (N, 3, 3).
Returns:
np.ndarray: The rotation tensors. batched with shape (N, 3, 3).
"""
return np.einsum("nij,njk->nik", f, np.linalg.inv(self.right_stretch_tensor(f)))
6 changes: 5 additions & 1 deletion hyper_surrogate/materials.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,4 +126,8 @@ def __init__(self) -> None:

@property
def sef(self) -> Expr:
return (self.invariant1 - 3) * Symbol("C10") + (self.invariant2 - 3) * Symbol("C01")
return (
(self.invariant1 - 3) * Symbol("C10")
+ (self.invariant2 - 3) * Symbol("C01")
+ 0.25 * Symbol("KBULK") * (self.invariant3 - 1 - 2 * log(self.invariant3**0.5))
)
10 changes: 4 additions & 6 deletions hyper_surrogate/reporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,8 @@ class Reporter:
"visualize_determinants",
]

def __init__(self, tensor: np.ndarray, save_dir: Path):
def __init__(self, tensor: np.ndarray):
self.tensor = tensor # tensor is a np.array (N,3,3)
self.save_dir = save_dir
# Path.mkdir(Path(self.save_dir), parents=True, exist_ok=True)
self.pdf_metadata = {
"Title": "Generation Session Report",
"Author": "João Ferreira",
Expand Down Expand Up @@ -87,21 +85,21 @@ def generate_figures(self) -> list[matplotlib.figure.Figure]:
fig_list.append(fig_item)
return fig_list

def create_report(self, layout: str = "combined") -> None:
def create_report(self, save_dir: Path, layout: str = "combined") -> None:
"""Create final pdf report."""
fig_list = self.generate_figures()
fig_list_pbar = tqdm(fig_list, total=len(fig_list), leave=False)
fig_list_pbar.set_description(f"Creating {layout} pdf report.")
if layout == "combined":
with PdfPages(Path(self.save_dir, "report.pdf"), metadata=self.pdf_metadata) as pp_combined:
with PdfPages(Path(save_dir, "report.pdf"), metadata=self.pdf_metadata) as pp_combined:
for fig in fig_list_pbar:
fig_list_pbar.update(1)
title = fig.axes[0].get_title()
fig.savefig(pp_combined, format="pdf", bbox_inches="tight")
else:
for fig in fig_list_pbar:
title = fig.axes[0].get_title()
file_name = Path(self.save_dir, f"{title}.pdf")
file_name = Path(save_dir, f"{title}.pdf")
with PdfPages(file_name, metadata=self.pdf_metadata) as pp_single:
fig.savefig(pp_single, format="pdf", bbox_inches="tight")
fig_list_pbar.update(1)
Expand Down
2 changes: 1 addition & 1 deletion hyper_surrogate/symbolic.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

class SymbolicHandler:
"""
A class that handles symbolic computations using SymPy.
A class that handles symbolic computations for Continuum Mechanics Hyperelastic Frameworks using SymPy.
Attributes:
c_tensor (Matrix): A 3x3 matrix of symbols.
Expand Down
1 change: 0 additions & 1 deletion hyper_surrogate/umat_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ def common_subexpressions(tensor: sym.Matrix, var_name: str) -> List[str]:
Perform common subexpression elimination on a vector or matrix and generate Fortran code.
Args:
vector (list): The symbolic vector or matrix to process.
var_name (str): The base name for the variables in the Fortran code.
Returns:
Expand Down
21 changes: 21 additions & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,16 @@ copyright: Maintained by <a href="https://jpsferreira.com">Florian</a>.

nav:
- Home: index.md
- Installation: installation.md
- Modules: modules.md
- Tutorial1: tutorial1.ipynb
plugins:
- search
- mkdocstrings:
handlers:
python:
collector: griffe
- mknotebooks
theme:
name: material
feature:
Expand Down Expand Up @@ -50,3 +53,21 @@ markdown_extensions:
permalink: true
- pymdownx.arithmatex:
generic: true
- pymdownx.superfences:
- pymdownx.inlinehilite
- pymdownx.highlight
- pymdownx.extra
- pymdownx.caret
- pymdownx.mark
- pymdownx.smartsymbols
- pymdownx.tasklist
- pymdownx.emoji
- pymdownx.magiclink

extra_javascript:
- https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.11.1/katex.min.js
- https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.11.1/contrib/auto-render.min.js
- custom.js

extra_css:
- https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.11.1/katex.min.css
Loading

0 comments on commit a036703

Please sign in to comment.