diff --git a/Coverage report.pdf b/Coverage report.pdf
new file mode 100644
index 00000000..2d65db3d
Binary files /dev/null and b/Coverage report.pdf differ
diff --git a/README.md b/README.md
index da66993c..a54227ff 100644
--- a/README.md
+++ b/README.md
@@ -3,11 +3,36 @@
Please follow the instructions in [python_testing_exercise.md](https://github.com/Simulation-Software-Engineering/Lecture-Material/blob/main/05_testing_and_ci/python_testing_exercise.md).
## Test logs (for submission)
+For all the tests, the following changes were made :
+
+**Changing `self.nx = int(w / dx)` to `self.nx = int(h / dx)` in initialize_domain**
+
+**Changing to `dx2, dy2 = self.dx * self.dy, self.dy * self.dy` in initialize_physical_parameters**
+
+**Changing to `u = self.T_hot * np.ones((self.nx, self.ny))` in set_initial_condition**
+
### pytest log
+#### unit
+
+
+
+
+
+
+
+#### integration
+
+
+
+
+
+
### unittest log
+
+
## Citing
The code used in this exercise is based on [Chapter 7 of the book "Learning Scientific Programming with Python"](https://scipython.com/book/chapter-7-matplotlib/examples/the-two-dimensional-diffusion-equation/).
diff --git a/diffusion2d.py b/diffusion2d.py
index 51a07f2d..45233db5 100644
--- a/diffusion2d.py
+++ b/diffusion2d.py
@@ -38,6 +38,10 @@ def __init__(self):
self.dt = None
def initialize_domain(self, w=10., h=10., dx=0.1, dy=0.1):
+ assert isinstance(w, float), "Width (w) must be a float"
+ assert isinstance(h, float), "Height (h) must be a float"
+ assert isinstance(dx, float), "dx must be a float"
+ assert isinstance(dy, float), "dy must be a float"
self.w = w
self.h = h
self.dx = dx
@@ -45,7 +49,10 @@ def initialize_domain(self, w=10., h=10., dx=0.1, dy=0.1):
self.nx = int(w / dx)
self.ny = int(h / dy)
- def initialize_physical_parameters(self, d=4., T_cold=300, T_hot=700):
+ def initialize_physical_parameters(self, d=4., T_cold=300., T_hot=700.):
+ assert isinstance(d, float), "Thermal diffusivity (d) must be a float"
+ assert isinstance(T_cold, float), "T_cold must be a float"
+ assert isinstance(T_hot, float), "T_hot must be a float"
self.D = d
self.T_cold = T_cold
self.T_hot = T_hot
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 00000000..070be7e6
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,2 @@
+numpy>=1.26.1
+matplotlib>=3.8.4
\ No newline at end of file
diff --git a/tests/integration/__init__.py b/tests/integration/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/integration/test_diffusion2d.py b/tests/integration/test_diffusion2d.py
index fd026b40..ed8a4f4c 100644
--- a/tests/integration/test_diffusion2d.py
+++ b/tests/integration/test_diffusion2d.py
@@ -10,6 +10,9 @@ def test_initialize_physical_parameters():
Checks function SolveDiffusion2D.initialize_domain
"""
solver = SolveDiffusion2D()
+ solver.initialize_domain(w = 20., h = 30., dx = 0.2, dy = 0.4)
+ solver.initialize_physical_parameters(d=2., T_cold=200., T_hot=500.)
+ assert round(solver.dt, 3) == 0.008
def test_set_initial_condition():
@@ -17,3 +20,34 @@ def test_set_initial_condition():
Checks function SolveDiffusion2D.get_initial_function
"""
solver = SolveDiffusion2D()
+
+ # Set domain and physical parameters
+ w, h = 10.0, 11.0 # Width and height of the domain
+ dx, dy = 0.1, 0.2 # Grid spacing in x and y directions
+ T_cold, T_hot = 301.0, 701.0 # Cold and hot temperatures
+
+ # Initialize the domain and physical parameters
+ solver.initialize_domain(w=w, h=h, dx=dx, dy=dy)
+ solver.initialize_physical_parameters(T_cold=T_cold, T_hot=T_hot)
+
+ # Set the initial condition
+ res = solver.set_initial_condition()
+
+ # Test each grid point
+ radius_squared = 2**2 # Radius of the circle squared
+ center_x, center_y = 5.0, 5.0 # Center of the hot circle
+ nx, ny = solver.nx, solver.ny # Number of grid points in x and y directions
+
+ for i in range(nx):
+ for j in range(ny):
+ # Calculate the squared distance from the center of the circle
+ x, y = i * dx, j * dy
+ distance_squared = (x - center_x) ** 2 + (y - center_y) ** 2
+
+ # Check if the point is inside or outside the circle
+ if distance_squared < radius_squared:
+ # Inside the circle, temperature should be T_hot
+ assert res[i, j] == T_hot, f"Expected T_hot={T_hot} at ({i},{j}), got {res[i, j]}"
+ else:
+ # Outside the circle, temperature should be T_cold
+ assert res[i, j] == T_cold, f"Expected T_cold={T_cold} at ({i},{j}), got {res[i, j]}"
diff --git a/tests/unit/__init__.py b/tests/unit/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/unit/test_diffusion2d_functions.py b/tests/unit/test_diffusion2d_functions.py
index c4277ffd..8d5fc28d 100644
--- a/tests/unit/test_diffusion2d_functions.py
+++ b/tests/unit/test_diffusion2d_functions.py
@@ -10,6 +10,10 @@ def test_initialize_domain():
Check function SolveDiffusion2D.initialize_domain
"""
solver = SolveDiffusion2D()
+ solver.initialize_domain(w=20.,h=30.,dx=0.2,dy=0.4)
+
+ assert solver.nx == 100, f"Expected nx=100, but got {solver.nx}"
+ assert solver.ny == 75, f"Expected ny=75, but got {solver.ny}"
def test_initialize_physical_parameters():
@@ -17,6 +21,15 @@ def test_initialize_physical_parameters():
Checks function SolveDiffusion2D.initialize_domain
"""
solver = SolveDiffusion2D()
+ solver.w = 20.
+ solver.h = 30.
+ solver.dx = 0.2
+ solver.dy = 0.4
+ solver.initialize_physical_parameters(d=2., T_cold=200., T_hot=500.)
+
+ # Check the calculated dt value (assert with some tolerance)
+ expected_dt = 0.008
+ assert abs(solver.dt - expected_dt) < 1e-4, f"Expected dt={expected_dt}, but got {solver.dt}"
def test_set_initial_condition():
@@ -24,3 +37,23 @@ def test_set_initial_condition():
Checks function SolveDiffusion2D.get_initial_function
"""
solver = SolveDiffusion2D()
+ solver = SolveDiffusion2D()
+ solver.nx = 100
+ solver.ny = 150
+ solver.dx = 0.2
+ solver.dy = 0.4
+ solver.T_cold = 100.
+ solver.T_hot = 400.
+
+ u = solver.set_initial_condition()
+
+ # Check the shape of the output matrix u (it should match nx, ny)
+ assert u.shape == (solver.nx, solver.ny), f"Expected u.shape = ({solver.nx}, {solver.ny}), but got {u.shape}"
+
+ # Check that corners are cold (boundary conditions)
+ assert u[0, 0] == solver.T_cold, "Top-left corner should be cold."
+ assert u[0, -1] == solver.T_cold, "Top-right corner should be cold."
+ assert u[-1, 0] == solver.T_cold, "Bottom-left corner should be cold."
+ assert u[-1, -1] == solver.T_cold, "Bottom-right corner should be cold."
+
+
diff --git a/tests/unit/test_diffusion2d_functions_unit.py b/tests/unit/test_diffusion2d_functions_unit.py
new file mode 100644
index 00000000..8f451050
--- /dev/null
+++ b/tests/unit/test_diffusion2d_functions_unit.py
@@ -0,0 +1,82 @@
+"""
+Tests for functions in class SolveDiffusion2D
+"""
+
+from diffusion2d import SolveDiffusion2D
+import unittest
+
+class TestDiffusion2D(unittest.TestCase):
+ def setUp(self):
+ """Initialize the solver with default values for tests."""
+ self.solver = SolveDiffusion2D()
+
+ # Set up the domain and physical parameters for the tests
+ self.solver.w = 20. # Width of the domain
+ self.solver.h = 30. # Height of the domain
+ self.solver.dx = 0.2 # Grid step size in x direction
+ self.solver.dy = 0.4 # Grid step size in y direction
+ self.solver.T_cold = 100. # Initial cold temperature
+ self.solver.T_hot = 400. # Initial hot temperature
+ self.solver.initialize_domain(self.solver.w, self.solver.h, self.solver.dx, self.solver.dy)
+
+ def test_initialize_domain(self):
+ """
+ Check function SolveDiffusion2D.initialize_domain
+ """
+ self.solver.initialize_domain(w=20., h=30., dx=0.2, dy=0.4)
+
+ # nx and ny should be based on w/dx and h/dy
+ self.assertEqual(self.solver.nx, 100, f"Expected nx=100, but got {self.solver.nx}")
+ self.assertEqual(self.solver.ny, 75, f"Expected ny=75, but got {self.solver.ny}")
+
+
+
+
+ def test_initialize_physical_parameters(self):
+ """
+ Checks function SolveDiffusion2D.initialize_domain
+ """
+ self.solver.initialize_physical_parameters(d=2., T_cold=200., T_hot=500.)
+
+ # Check the calculated dt value (assert with some tolerance)
+ expected_dt = 0.008
+ self.assertAlmostEqual(self.solver.dt, expected_dt, places=4, msg=f"Expected dt={expected_dt}, but got {self.solver.dt}")
+
+
+
+ def test_set_initial_condition(self):
+ """
+ Checks function SolveDiffusion2D.get_initial_function
+ """
+ # Initialize physical parameters for this test
+ self.solver.nx = 100
+ self.solver.ny = 150
+ self.solver.T_cold = 100.
+ self.solver.T_hot = 400.
+ u = self.solver.set_initial_condition()
+
+ # Check the shape of the output matrix u (it should match nx, ny)
+ self.assertEqual(u.shape, (self.solver.nx, self.solver.ny),f"Expected u.shape = ({self.solver.nx}, {self.solver.ny}), but got {u.shape}")
+
+ # Check that corners are cold (boundary conditions)
+ self.assertEqual(u[0, 0], self.solver.T_cold, "Top-left corner should be cold.")
+ self.assertEqual(u[0, -1], self.solver.T_cold, "Top-right corner should be cold.")
+ self.assertEqual(u[-1, 0], self.solver.T_cold, "Bottom-left corner should be cold.")
+ self.assertEqual(u[-1, -1], self.solver.T_cold, "Bottom-right corner should be cold.")
+
+ # Check if some of the center values are hot (inside the circle, should be equal to T_hot)
+ # Based on the implementation, we know that the center will have T_hot values.
+ r, cx, cy = 2, 5, 5 # Circle parameters used in set_initial_condition
+ for i in range(self.solver.nx):
+ for j in range(self.solver.ny):
+ # Calculate distance from the center (cx, cy)
+ dist = (i * self.solver.dx - cx) ** 2 + (j * self.solver.dy - cy) ** 2
+ if dist < r**2:
+ # The points within the radius of the circle should have T_hot
+ self.assertEqual(u[i, j], self.solver.T_hot,f"Expected T_hot={self.solver.T_hot} inside the circle, but got {u[i,j]} at ({i},{j})")
+ else:
+ # Points outside the circle should remain at T_cold
+ self.assertEqual(u[i, j], self.solver.T_cold, f"Expected T_cold={self.solver.T_cold} outside the circle, but got {u[i,j]} at ({i},{j})")
+
+
+
diff --git a/tox.toml b/tox.toml
new file mode 100644
index 00000000..fa300c42
--- /dev/null
+++ b/tox.toml
@@ -0,0 +1,11 @@
+env_list = ["pytest", "unittest"]
+
+[env.pytest]
+description = "pytest"
+deps = ["pytest", "-r requirements.txt"]
+commands = [["python", "-m", "pytest", "tests/integration/test_diffusion2d.py"]]
+
+[env.unittest]
+description = "unittest"
+deps = ["-r requirements.txt"]
+commands = [["python", "-m", "unittest", "tests/unit/test_diffusion2d_functions_unit.py"]]
\ No newline at end of file
diff --git a/tox_result.png b/tox_result.png
new file mode 100644
index 00000000..d3872675
Binary files /dev/null and b/tox_result.png differ