diff --git a/gprMax/cython/geometry_primitives.pyx b/gprMax/cython/geometry_primitives.pyx index a93da21c..89d3a92d 100644 --- a/gprMax/cython/geometry_primitives.pyx +++ b/gprMax/cython/geometry_primitives.pyx @@ -445,6 +445,12 @@ cpdef void build_triangle( j2 = round_value(np.amax([z1, z2, z3]) / dz) + 1 levelcells = round_value(x1 / dx) thicknesscells = round_value(thickness / dx) + + # Bound to the size of the grid + if i2 > solid.shape[1]: + i2 = solid.shape[1] + if j2 > solid.shape[2]: + j2 = solid.shape[2] elif normal == 'y': area = 0.5 * (-z2 * x3 + z1 * (-x2 + x3) + x1 * (z2 - z3) + x2 * z3) i1 = round_value(np.amin([x1, x2, x3]) / dx) - 1 @@ -453,6 +459,12 @@ cpdef void build_triangle( j2 = round_value(np.amax([z1, z2, z3]) / dz) + 1 levelcells = round_value(y1 /dy) thicknesscells = round_value(thickness / dy) + + # Bound to the size of the grid + if i2 > solid.shape[0]: + i2 = solid.shape[0] + if j2 > solid.shape[2]: + j2 = solid.shape[2] elif normal == 'z': area = 0.5 * (-y2 * x3 + y1 * (-x2 + x3) + x1 * (y2 - y3) + x2 * y3) i1 = round_value(np.amin([x1, x2, x3]) / dx) - 1 @@ -462,6 +474,18 @@ cpdef void build_triangle( levelcells = round_value(z1 / dz) thicknesscells = round_value(thickness / dz) + # Bound to the size of the grid + if i2 > solid.shape[0]: + i2 = solid.shape[0] + if j2 > solid.shape[1]: + j2 = solid.shape[1] + + # Bound to the start of the grid + if i1 < 0: + i1 = 0 + if j1 < 0: + j1 = 0 + sign = np.sign(area) for i in range(i1, i2): diff --git a/gprMax/user_objects/cmds_geometry/triangle.py b/gprMax/user_objects/cmds_geometry/triangle.py index 4a752d74..c2d28abe 100644 --- a/gprMax/user_objects/cmds_geometry/triangle.py +++ b/gprMax/user_objects/cmds_geometry/triangle.py @@ -96,36 +96,60 @@ class Triangle(RotatableMixin, GeometryUserObject): logger.exception(f"{self.__str__()} no materials have been specified") raise + if thickness < 0: + logger.exception(f"{self.__str__()} requires a positive value for thickness") + raise ValueError + uip = self._create_uip(grid) - p4 = uip.round_to_grid_static_point(up1) - p5 = uip.round_to_grid_static_point(up2) - p6 = uip.round_to_grid_static_point(up3) # Check whether points are valid against grid - uip.check_tri_points(up1, up2, up3, object) + uip.check_tri_points(up1, up2, up3, self.__str__()) # Convert points to metres x1, y1, z1 = uip.round_to_grid(up1) x2, y2, z2 = uip.round_to_grid(up2) x3, y3, z3 = uip.round_to_grid(up3) - if thickness < 0: - logger.exception(f"{self.__str__()} requires a positive value for thickness") - raise ValueError - # Check for valid orientations # yz-plane triangle if x1 == x2 == x3: normal = "x" + start = x1 # xz-plane triangle elif y1 == y2 == y3: normal = "y" + start = y1 # xy-plane triangle elif z1 == z2 == z3: normal = "z" + start = z1 else: logger.exception(f"{self.__str__()} the triangle is not specified correctly") raise ValueError + triangle_within_grid, start, thickness = uip.check_thickness(normal, start, thickness) + + # Exit early if none of the triangle is in this grid as there is + # nothing else to do. + if not triangle_within_grid: + return + + # Update start bound of the triangle + # yz-plane triangle + if normal == "x": + x1 = start + x2 = start + x3 = start + # xz-plane triangle + elif normal == "y": + y1 = start + y2 = start + y3 = start + # xy-plane triangle + elif normal == "z": + z1 = start + z2 = start + z3 = start + # Look up requested materials in existing list of material instances materials = [y for x in materialsrequested for y in grid.materials if y.ID == x] @@ -202,6 +226,10 @@ class Triangle(RotatableMixin, GeometryUserObject): grid.ID, ) + p4 = uip.round_to_grid_static_point(up1) + p5 = uip.round_to_grid_static_point(up2) + p6 = uip.round_to_grid_static_point(up3) + if thickness > 0: dielectricsmoothing = "on" if averaging else "off" logger.info( diff --git a/reframe_tests/regression_checks/TestTriangleGeometry_973a0082/triangle_y_small.h5 b/reframe_tests/regression_checks/TestTriangleGeometry_973a0082/triangle_y_small.h5 new file mode 100644 index 00000000..09f61a8c Binary files /dev/null and b/reframe_tests/regression_checks/TestTriangleGeometry_973a0082/triangle_y_small.h5 differ diff --git a/reframe_tests/regression_checks/TestTriangleGeometry_c0901cac/triangle_z_rigid.h5 b/reframe_tests/regression_checks/TestTriangleGeometry_c0901cac/triangle_z_rigid.h5 new file mode 100644 index 00000000..53780e71 Binary files /dev/null and b/reframe_tests/regression_checks/TestTriangleGeometry_c0901cac/triangle_z_rigid.h5 differ diff --git a/reframe_tests/regression_checks/TestTriangleGeometry_f2514f81/triangle_x_full.h5 b/reframe_tests/regression_checks/TestTriangleGeometry_f2514f81/triangle_x_full.h5 new file mode 100644 index 00000000..bc566a45 Binary files /dev/null and b/reframe_tests/regression_checks/TestTriangleGeometry_f2514f81/triangle_x_full.h5 differ diff --git a/reframe_tests/tests/src/geometry_tests/triangle_geometry/triangle_x_full.in b/reframe_tests/tests/src/geometry_tests/triangle_geometry/triangle_x_full.in new file mode 100644 index 00000000..4886179c --- /dev/null +++ b/reframe_tests/tests/src/geometry_tests/triangle_geometry/triangle_x_full.in @@ -0,0 +1,13 @@ +#title: Hertzian dipole over a half-space +#domain: 0.100 0.100 0.100 +#dx_dy_dz: 0.001 0.001 0.001 +#time_window: 3e-9 + +#waveform: gaussiandot 1 1e9 myWave +#hertzian_dipole: z 0.020 0.020 0.020 myWave +#rx: 0.080 0.080 0.080 + +#material: 8 0 1 0 half_space +#triangle: 0 0 0 0 0.1 0.05 0 0 0.1 0.1 half_space + +#geometry_objects_write: 0 0 0 0.1 0.1 0.1 full_volume diff --git a/reframe_tests/tests/src/geometry_tests/triangle_geometry/triangle_y_small.in b/reframe_tests/tests/src/geometry_tests/triangle_geometry/triangle_y_small.in new file mode 100644 index 00000000..6291052b --- /dev/null +++ b/reframe_tests/tests/src/geometry_tests/triangle_geometry/triangle_y_small.in @@ -0,0 +1,13 @@ +#title: Hertzian dipole over a half-space +#domain: 0.100 0.100 0.100 +#dx_dy_dz: 0.001 0.001 0.001 +#time_window: 3e-9 + +#waveform: gaussiandot 1 1e9 myWave +#hertzian_dipole: z 0.020 0.020 0.020 myWave +#rx: 0.080 0.080 0.080 + +#material: 8 0 1 0 half_space +#triangle: 0.06 0.06 0.06 0.08 0.06 0.075 0.072 0.06 0.06 0.03 half_space + +#geometry_objects_write: 0 0 0 0.1 0.1 0.1 full_volume diff --git a/reframe_tests/tests/src/geometry_tests/triangle_geometry/triangle_z_rigid.in b/reframe_tests/tests/src/geometry_tests/triangle_geometry/triangle_z_rigid.in new file mode 100644 index 00000000..f152d36b --- /dev/null +++ b/reframe_tests/tests/src/geometry_tests/triangle_geometry/triangle_z_rigid.in @@ -0,0 +1,13 @@ +#title: Hertzian dipole over a half-space +#domain: 0.100 0.100 0.100 +#dx_dy_dz: 0.001 0.001 0.001 +#time_window: 3e-9 + +#waveform: gaussiandot 1 1e9 myWave +#hertzian_dipole: z 0.020 0.020 0.020 myWave +#rx: 0.080 0.080 0.080 + +#material: 8 0 1 0 half_space +#triangle: 0.05 0 0.01 0.1 0.07 0.01 0 0.05 0.01 0.08 half_space n + +#geometry_objects_write: 0 0 0 0.1 0.1 0.1 full_volume diff --git a/reframe_tests/tests/test_geometry.py b/reframe_tests/tests/test_geometry.py index 885571e0..1051fc24 100644 --- a/reframe_tests/tests/test_geometry.py +++ b/reframe_tests/tests/test_geometry.py @@ -72,6 +72,13 @@ class TestCylindricalSectorGeometry(GprMaxRegressionTest): ) +@rfm.simple_test +class TestEdgeGeometry(AntennaModelMixin, GprMaxRegressionTest): + tags = {"test", "serial", "geometry", "edge", "transmission_line", "waveform", "antenna"} + sourcesdir = "src/geometry_tests/edge_geometry" + model = parameter(["antenna_wire_dipole_fs"]) + + @rfm.simple_test class TestEllipsoidGeometry(GprMaxRegressionTest): tags = {"test", "serial", "geometery", "ellipsoid"} @@ -97,10 +104,10 @@ class TestSphereGeometry(GprMaxRegressionTest): @rfm.simple_test -class TestEdgeGeometry(AntennaModelMixin, GprMaxRegressionTest): - tags = {"test", "serial", "geometry", "edge", "transmission_line", "waveform", "antenna"} - sourcesdir = "src/geometry_tests/edge_geometry" - model = parameter(["antenna_wire_dipole_fs"]) +class TestTriangleGeometry(GprMaxRegressionTest): + tags = {"test", "serial", "geometery", "triangle"} + sourcesdir = "src/geometry_tests/triangle_geometry" + model = parameter(["triangle_x_full", "triangle_y_small", "triangle_z_rigid"]) """Test MPI Functionality @@ -128,6 +135,13 @@ class TestConeGeometryMpi(MpiMixin, TestConeGeometry): test_dependency = TestConeGeometry +@rfm.simple_test +class TestCylinderGeometryMpi(MpiMixin, TestCylinderGeometry): + tags = {"test", "mpi", "geometery", "cylindrical", "sector", "cylindrical_sector"} + mpi_layout = parameter([[2, 2, 2], [3, 3, 3], [4, 4, 4]]) + test_dependency = TestCylinderGeometry + + @rfm.simple_test class TestCylindricalSectorGeometryMpi(MpiMixin, TestCylindricalSectorGeometry): tags = {"test", "mpi", "geometery", "cylinder"} @@ -136,10 +150,10 @@ class TestCylindricalSectorGeometryMpi(MpiMixin, TestCylindricalSectorGeometry): @rfm.simple_test -class TestCylinderGeometryMpi(MpiMixin, TestCylinderGeometry): - tags = {"test", "mpi", "geometery", "cylindrical", "sector", "cylindrical_sector"} +class TestEdgeGeometryMpi(MpiMixin, TestEdgeGeometry): + tags = {"test", "mpi", "geometry", "edge", "transmission_line", "waveform", "antenna"} mpi_layout = parameter([[2, 2, 2], [3, 3, 3], [4, 4, 4]]) - test_dependency = TestCylinderGeometry + test_dependency = TestEdgeGeometry @rfm.simple_test @@ -164,7 +178,7 @@ class TestSphereGeometryMpi(MpiMixin, TestSphereGeometry): @rfm.simple_test -class TestEdgeGeometryMpi(MpiMixin, TestEdgeGeometry): - tags = {"test", "mpi", "geometry", "edge", "transmission_line", "waveform", "antenna"} - mpi_layout = parameter([[3, 3, 3]]) - test_dependency = TestEdgeGeometry +class TestTriangleGeometryMpi(MpiMixin, TestTriangleGeometry): + tags = {"test", "mpi", "geometery", "triangle"} + mpi_layout = parameter([[2, 2, 2], [3, 3, 3], [4, 4, 4]]) + test_dependency = TestTriangleGeometry