Files
MeanField/experiments/test_plot_model_slices.py

120 lines
5.5 KiB
Python

#!/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))
raster = slices.rasterize_fields(data, (-2, 2, 0, 1), 64)
self.assertTrue(raster.mask[:, :, 24:40].all())
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_raster_overlap_uses_first_triangle_without_trace_averaging(self):
data = slices.load_slice(self.directory)
original = slices.rasterize_fields(data, (-2, 2, 0, 1), 64)
extra = data.vertices[:3].copy()
extra[:, 0] += len(data.vertices)
extra[:, 1] = 2
extra[:, 5] = 100
extra[:, 6] = -100
data.vertices = np.concatenate((data.vertices, extra))
data.triangles = np.concatenate((data.triangles, [[6, 7, 8]]))
overlapped = slices.rasterize_fields(data, (-2, 2, 0, 1), 64)
np.testing.assert_array_equal(original.mask, overlapped.mask)
np.testing.assert_array_equal(original.data, overlapped.data)
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()