Add physical-plane FEM model slice diagnostics and plots
This commit is contained in:
103
experiments/test_plot_model_slices.py
Normal file
103
experiments/test_plot_model_slices.py
Normal file
@@ -0,0 +1,103 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Small schema/plot controls; these are not stellar-equilibrium validation."""
|
||||
import csv
|
||||
from pathlib import Path
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
|
||||
import plot_model_slices as slices
|
||||
|
||||
|
||||
def write_csv(path, header, rows):
|
||||
with path.open("w", newline="") as stream:
|
||||
writer = csv.writer(stream)
|
||||
writer.writerow(header)
|
||||
writer.writerows(rows)
|
||||
|
||||
|
||||
def fixture(directory):
|
||||
# Two disconnected material triangles leave a genuine empty gap. Their
|
||||
# enthalpy is independent of density and one density sample is negative.
|
||||
coordinates = [(-2, 0), (-1, 0), (-1.5, 1), (1, 0), (2, 0), (1.5, 1)]
|
||||
rho, h = [-.4, .2, 1, .5, 1, 2], [1, 2, 3, 4, 5, 6]
|
||||
vertices = [[i, i // 3, u, .2, v, rho[i], h[i], 0] for i, (u, v) in enumerate(coordinates)]
|
||||
write_csv(directory / "vertices.csv", ["vertex", "element", "x", "y", "z", "rho", "h", "plane_error"], vertices)
|
||||
write_csv(directory / "triangles.csv", ["triangle", "element", "v0", "v1", "v2"], [[0, 0, 0, 1, 2], [1, 1, 3, 4, 5]])
|
||||
segments = []
|
||||
for element in range(2):
|
||||
for i, j in ((0, 1), (1, 2), (2, 0)):
|
||||
a, b = coordinates[3 * element + i], coordinates[3 * element + j]
|
||||
segments.append([a[0], .2, a[1], b[0], .2, b[1], 0])
|
||||
for name in ("surface.csv", "reference_surface.csv"):
|
||||
write_csv(directory / name, ["x0", "y0", "z0", "x1", "y1", "z1", "maximum_plane_error"], segments)
|
||||
metadata = dict(plane="xz", horizontal_axis=0, vertical_axis=2, normal_axis=1, offset=.2,
|
||||
root_tolerance=1e-11, deformation_scale=1, vertex_count=6, triangle_count=2,
|
||||
surface_segments=6, reference_surface_segments=6, surface_coplanar_triangles=0,
|
||||
reference_surface_coplanar_triangles=0, subdivisions=6, u_min=-2, u_max=2, v_min=0, v_max=1)
|
||||
write_csv(directory / "metadata.csv", ["metric", "value"], metadata.items())
|
||||
|
||||
|
||||
class ModelSlicePlotTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.temporary = tempfile.TemporaryDirectory()
|
||||
self.directory = Path(self.temporary.name)
|
||||
fixture(self.directory)
|
||||
|
||||
def tearDown(self):
|
||||
plt.close("all")
|
||||
self.temporary.cleanup()
|
||||
|
||||
def test_signed_independent_fields_are_preserved(self):
|
||||
data = slices.load_slice(self.directory)
|
||||
self.assertEqual(data.vertices[0, 5], -.4)
|
||||
self.assertEqual(data.vertices[0, 6], 1.)
|
||||
norm, _, _ = slices.color_scale(data.vertices[:, 5])
|
||||
self.assertEqual(norm(0.), .5)
|
||||
self.assertEqual(norm(-.4), 0.)
|
||||
|
||||
def test_no_triangulation_across_vacuum(self):
|
||||
data = slices.load_slice(self.directory)
|
||||
np.testing.assert_array_equal(data.triangles, [[0, 1, 2], [3, 4, 5]])
|
||||
for triangle in data.triangles:
|
||||
horizontal = data.vertices[triangle, 2]
|
||||
self.assertTrue(np.all(horizontal < 0) or np.all(horizontal > 0))
|
||||
figure = slices.render(data, reference_outline=True, title="Analytic geometry/schema control")
|
||||
self.assertEqual(figure.axes[0].get_aspect(), 1.)
|
||||
self.assertEqual(figure.axes[1].get_aspect(), 1.)
|
||||
for suffix in ("png", "pdf"):
|
||||
path = self.directory / ("control." + suffix)
|
||||
figure.savefig(path)
|
||||
self.assertGreater(path.stat().st_size, 1000)
|
||||
|
||||
def test_cross_element_triangle_is_rejected(self):
|
||||
write_csv(self.directory / "triangles.csv", ["triangle", "element", "v0", "v1", "v2"], [[0, 0, 0, 1, 4], [1, 1, 3, 4, 5]])
|
||||
with self.assertRaisesRegex(ValueError, "different material elements"):
|
||||
slices.load_slice(self.directory)
|
||||
|
||||
def test_wrong_physical_plane_is_rejected(self):
|
||||
path = self.directory / "vertices.csv"
|
||||
text = path.read_text().replace("0,0,-2,0.2,0,", "0,0,-2,0.25,0,")
|
||||
path.write_text(text)
|
||||
with self.assertRaisesRegex(ValueError, "physical plane"):
|
||||
slices.load_slice(self.directory)
|
||||
|
||||
def test_wrong_reference_plane_is_rejected(self):
|
||||
path = self.directory / "reference_surface.csv"
|
||||
values = slices.table(path, ["x0", "y0", "z0", "x1", "y1", "z1", "maximum_plane_error"])
|
||||
values[0, 1] = 0.
|
||||
write_csv(path, ["x0", "y0", "z0", "x1", "y1", "z1", "maximum_plane_error"], values)
|
||||
with self.assertRaisesRegex(ValueError, "outline"):
|
||||
slices.load_slice(self.directory)
|
||||
|
||||
def test_shape_exaggeration_is_rejected(self):
|
||||
path = self.directory / "metadata.csv"
|
||||
path.write_text(path.read_text().replace("deformation_scale,1", "deformation_scale,10"))
|
||||
with self.assertRaisesRegex(ValueError, "scale exactly one"):
|
||||
slices.load_slice(self.directory)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user