| | """
|
| | Unit tests for RectangularBeam calculator
|
| | Tests based on ACI 318 Example 4-1 (Imperial) and 4-1M (SI)
|
| | """
|
| |
|
| | import unittest
|
| | import math
|
| | from calculator import RectangularBeam
|
| |
|
| |
|
| | class TestRectangularBeamImperial(unittest.TestCase):
|
| | """Tests for Imperial unit calculations (Example 4-1)."""
|
| |
|
| | def setUp(self):
|
| | """Set up beam with Example 4-1 values."""
|
| | self.beam = RectangularBeam(
|
| | b=12.0,
|
| | h=20.0,
|
| | d=17.5,
|
| | fc=4000.0,
|
| | fy=60000.0,
|
| | n_bars=4,
|
| | bar_area=0.79,
|
| | unit_system="imperial"
|
| | )
|
| | self.results = self.beam.calculate_mn()
|
| |
|
| | def test_steel_area(self):
|
| | """Test As = n_bars * bar_area."""
|
| | expected_As = 4 * 0.79
|
| | self.assertAlmostEqual(self.results["As"], expected_As, places=2)
|
| |
|
| | def test_stress_block_depth_a(self):
|
| | """Test a = (As * fy) / (0.85 * fc * b)."""
|
| |
|
| | self.assertAlmostEqual(self.results["a"], 4.647, delta=0.01)
|
| |
|
| | def test_neutral_axis_depth_c(self):
|
| | """Test c = a / beta1."""
|
| |
|
| | expected_c = self.results["a"] / 0.85
|
| | self.assertAlmostEqual(self.results["c"], expected_c, delta=0.01)
|
| |
|
| | def test_nominal_moment(self):
|
| | """Test Mn calculation."""
|
| |
|
| |
|
| | self.assertAlmostEqual(self.results["Mn_display"], 239.79, delta=0.5)
|
| |
|
| | def test_tension_controlled(self):
|
| | """Test that beam is tension controlled (epsilon_t >= 0.005)."""
|
| | self.assertGreaterEqual(self.results["epsilon_t"], 0.005)
|
| | self.assertEqual(self.results["phi"], 0.9)
|
| |
|
| | def test_yield_check(self):
|
| | """Test that steel yields."""
|
| | self.assertTrue(self.results["yield_check"])
|
| |
|
| | def test_minimum_steel_check(self):
|
| | """Test minimum steel area calculation."""
|
| |
|
| | As_min = self.results["As_min"]
|
| | self.assertGreater(As_min, 0)
|
| | self.assertTrue(self.results["as_check"])
|
| |
|
| |
|
| | class TestRectangularBeamSI(unittest.TestCase):
|
| | """Tests for SI unit calculations (Example 4-1M)."""
|
| |
|
| | def setUp(self):
|
| | """Set up beam with Example 4-1M values."""
|
| | self.beam = RectangularBeam(
|
| | b=250.0,
|
| | h=565.0,
|
| | d=500.0,
|
| | fc=20.0,
|
| | fy=420.0,
|
| | n_bars=3,
|
| | bar_area=510.0,
|
| | unit_system="si"
|
| | )
|
| | self.results = self.beam.calculate_mn()
|
| |
|
| | def test_steel_area(self):
|
| | """Test As = n_bars * bar_area."""
|
| | expected_As = 3 * 510
|
| | self.assertAlmostEqual(self.results["As"], expected_As, places=0)
|
| |
|
| | def test_stress_block_depth_a(self):
|
| | """Test a = (As * fy) / (0.85 * fc * b)."""
|
| |
|
| | self.assertAlmostEqual(self.results["a"], 151.76, delta=1.0)
|
| |
|
| | def test_yield_check(self):
|
| | """Test that steel yields."""
|
| | self.assertTrue(self.results["yield_check"])
|
| |
|
| | def test_minimum_steel_check(self):
|
| | """Test minimum steel area calculation for SI."""
|
| | As_min = self.results["As_min"]
|
| | self.assertGreater(As_min, 0)
|
| |
|
| |
|
| | class TestBeta1Calculation(unittest.TestCase):
|
| | """Tests for beta1 calculation based on fc."""
|
| |
|
| | def test_beta1_low_fc_imperial(self):
|
| | """Beta1 = 0.85 for fc <= 4000 psi."""
|
| | beam = RectangularBeam(
|
| | b=12, h=20, d=17.5, fc=4000, fy=60000,
|
| | n_bars=4, bar_area=0.79, unit_system="imperial"
|
| | )
|
| | self.assertEqual(beam.beta1, 0.85)
|
| |
|
| | def test_beta1_high_fc_imperial(self):
|
| | """Beta1 = 0.65 for fc >= 8000 psi."""
|
| | beam = RectangularBeam(
|
| | b=12, h=20, d=17.5, fc=8000, fy=60000,
|
| | n_bars=4, bar_area=0.79, unit_system="imperial"
|
| | )
|
| | self.assertEqual(beam.beta1, 0.65)
|
| |
|
| | def test_beta1_mid_fc_imperial(self):
|
| | """Beta1 interpolated for 4000 < fc < 8000 psi."""
|
| | beam = RectangularBeam(
|
| | b=12, h=20, d=17.5, fc=6000, fy=60000,
|
| | n_bars=4, bar_area=0.79, unit_system="imperial"
|
| | )
|
| |
|
| | self.assertAlmostEqual(beam.beta1, 0.75, places=2)
|
| |
|
| | def test_beta1_override(self):
|
| | """Test that beta1 can be overridden."""
|
| | beam = RectangularBeam(
|
| | b=12, h=20, d=17.5, fc=4000, fy=60000,
|
| | n_bars=4, bar_area=0.79, beta1=0.70, unit_system="imperial"
|
| | )
|
| | self.assertEqual(beam.beta1, 0.70)
|
| |
|
| |
|
| | class TestEdgeCases(unittest.TestCase):
|
| | """Tests for edge cases."""
|
| |
|
| | def test_single_bar(self):
|
| | """Test with single bar."""
|
| | beam = RectangularBeam(
|
| | b=12, h=20, d=17.5, fc=4000, fy=60000,
|
| | n_bars=1, bar_area=0.79, unit_system="imperial"
|
| | )
|
| | results = beam.calculate_mn()
|
| | self.assertEqual(results["As"], 0.79)
|
| |
|
| | def test_custom_epsilon_cu(self):
|
| | """Test with custom ultimate concrete strain."""
|
| | beam = RectangularBeam(
|
| | b=12, h=20, d=17.5, fc=4000, fy=60000,
|
| | n_bars=4, bar_area=0.79, epsilon_cu=0.0035, unit_system="imperial"
|
| | )
|
| | self.assertEqual(beam.epsilon_cu, 0.0035)
|
| |
|
| |
|
| | if __name__ == '__main__':
|
| | unittest.main()
|
| |
|