Skip to content

Commit

Permalink
Add deformation generation notebook, update deformation script output…
Browse files Browse the repository at this point in the history
… path, and format materials module
  • Loading branch information
jpsferreira committed Apr 11, 2024
1 parent 65d81f1 commit a6b9219
Show file tree
Hide file tree
Showing 5 changed files with 251 additions and 35 deletions.
130 changes: 130 additions & 0 deletions hyper_surrogate/reporter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
from datetime import datetime
from pathlib import Path
from typing import ClassVar

import matplotlib
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

# import pandas as pd
import seaborn as sns
from matplotlib.backends.backend_pdf import PdfPages
from tqdm import tqdm

matplotlib.use("svg")
plt.set_loglevel("error")
plt.rcParams["figure.max_open_warning"] = -1


class Reporter:
"""
Generate a PDF report from batches of tensors.
It provides various methods to create different types of visualizations and tables based on the parsed data.
"""

LAYOUT: ClassVar[list[str]] = ["standalone", "combined"]

FIG_SIZE = (8.27, 11.69) # A4 paper size in inches

REPORT_FIGURES: ClassVar[list[str]] = [
"visualize_eigenvalues",
"visualize_determinants",
]

def __init__(self, tensor: np.ndarray, save_dir: Path):
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",
"Subject": "Tensor Batch Session Summary",
"CreationDate": datetime.today(),
}

def basic_statistics(self) -> tuple[float, float, float, float]:
# Calculate mean, median, standard deviation, and range for the entire tensor
mean = np.mean(self.tensor)
median = np.median(self.tensor)
std_dev = np.std(self.tensor)
value_range = np.ptp(self.tensor) # Peak-to-peak (max - min)
return (mean, median, std_dev, value_range)

def visualize_eigenvalues(self) -> list[matplotlib.figure.Figure]:
# Plot histograms of the eigenvalues
eigenvalues = np.linalg.eigvals(self.tensor)
fig, ax = plt.subplots(1, 1, figsize=self.FIG_SIZE)
sns.histplot(eigenvalues.flatten(), kde=True, ax=ax, alpha=0.75)
plt.title("Histogram of Eigenvalues")
plt.xlabel("Eigenvalue")
plt.ylabel("Frequency")
return [fig]

def visualize_determinants(self) -> list[matplotlib.figure.Figure]:
# Plot a histogram of the determinants of the 3x3 matrices
determinants = np.linalg.det(self.tensor)
print(determinants)
fig, ax = plt.subplots(1, 1, figsize=self.FIG_SIZE)
sns.histplot(determinants.flatten(), kde=True, ax=ax)
# plt.hist(determinants, alpha=0.75)
plt.title("Histogram of Determinants")
plt.xlabel("Determinant")
plt.ylabel("Frequency")
return [fig]

@staticmethod
def tablefig(
df: pd.DataFrame,
figsize: tuple = (8.27, 11.69),
location: str = "center left",
title: str = "Title",
) -> list[matplotlib.figure.Figure]:
"""Create a table figure using the provided DataFrame and displays it using Matplotlib."""
fig, ax = plt.subplots(figsize=figsize)
ax.table(
cellText=df.values,
colLabels=df.columns,
loc=location,
rowLabels=df.index,
)

ax.axis("off")
ax.set_title(title)
return [fig]

def generate_figures(self) -> list[matplotlib.figure.Figure]:
"""Generate figures for report."""
fig_list = []
report_figures_pbar = tqdm(self.REPORT_FIGURES, total=len(self.REPORT_FIGURES), leave=False)
for report_figure in report_figures_pbar:
report_figures_pbar.set_description(f"Generating {report_figure}")
func = getattr(self, report_figure)
for fig_item in func():
if isinstance(fig_item, list):
fig_list.extend(fig_item)
else:
fig_list.append(fig_item)
return fig_list

def create_report(self, 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:
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")
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)
plt.close("all")
87 changes: 87 additions & 0 deletions notebooks/generate_deformation.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"import sympy as sym\n",
"from hyper_surrogate.deformation_gradient import DeformationGradientGenerator\n",
"from hyper_surrogate.kinematics import Kinematics as K\n",
"from hyper_surrogate.materials import NeoHooke"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"SIZE = 10000\n",
"f = DeformationGradientGenerator(seed=42, size=SIZE).generate()\n",
"c = K.right_cauchy_green(f)"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [],
"source": [
"# NEOHOOKE\n",
"material = NeoHooke()\n",
"pk2_func_iterator = material.evaluate_iterator(material.pk2(), c, SIZE)\n",
"pk2 = np.array([next(pk2_func_iterator) for _ in range(SIZE)]) #np.array(list(pk2_func_iterator))\n",
"cmat_func_iterator = material.evaluate_iterator(material.cmat(), c, SIZE)\n",
"cmat = np.array([next(cmat_func_iterator) for _ in range(SIZE)]) #np.array(list(cmat_func_iterator))"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"f: (10000, 3, 3)\n",
"c: (10000, 3, 3)\n",
"pk2: (10000, 3, 3)\n",
"cmat: (10000, 3, 3, 3, 3)\n"
]
}
],
"source": [
"print(f\"f: {f.shape}\")\n",
"print(f\"c: {c.shape}\")\n",
"print(f\"pk2: {pk2.shape}\")\n",
"print(f\"cmat: {cmat.shape}\")\n",
"\n"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "hyper-surrogate-lMkffKrT-py3.11",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.2"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
65 changes: 31 additions & 34 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ sympy = "^1.12"
matplotlib = "^3.8.3"
seaborn = "^0.13.2"
tqdm = "^4.66.2"
pandas = "^2.2.2"

[tool.poetry.group.dev.dependencies]
pytest = "^7.2.0"
Expand Down
3 changes: 2 additions & 1 deletion scripts/generate_deformations.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@
logging.info(f"Generated {args.batch_size} deformation gradients.")
c = K.right_cauchy_green(f)

reporter = Reporter(c, Path("output.pdf"))
# report pdf to output_path name
reporter = Reporter(c, args.output_path.parent)
reporter.create_report()

if "pk2" in args.tensors:
Expand Down

0 comments on commit a6b9219

Please sign in to comment.