fish_farm_env / tests /test_constants.py
rahul24raj's picture
Upload folder using huggingface_hub
a0b8672 verified
"""Tests for constants module — utility functions and parameter sanity."""
from agentic_rl.constants import (
TILAPIA, WATER, ECONOMICS, SYSTEM,
uia_fraction, do_saturation, photoperiod_hours,
temperature_factor, do_factor, uia_factor,
)
class TestTilapiaParams:
def test_temperature_range_valid(self):
assert TILAPIA.T_min < TILAPIA.T_opt < TILAPIA.T_max
assert TILAPIA.T_lethal_low < TILAPIA.T_min
assert TILAPIA.T_max < TILAPIA.T_lethal_high
def test_growth_exponents_valid(self):
assert 0 < TILAPIA.m < 1 # anabolism exponent
assert 0 < TILAPIA.n < 1 # catabolism exponent
assert TILAPIA.m < TILAPIA.n # catabolism scales faster (biological constraint)
def test_fcr_target_realistic(self):
assert 1.0 < TILAPIA.fcr_target < 3.0
def test_do_thresholds_ordered(self):
assert TILAPIA.DO_lethal < TILAPIA.DO_stress < TILAPIA.DO_optimal
class TestWaterParams:
def test_uia_thresholds_ordered(self):
assert WATER.UIA_safe < WATER.UIA_crit < WATER.UIA_lethal
def test_ph_range_valid(self):
assert WATER.pH_lethal_low < WATER.pH_min < WATER.pH_max < WATER.pH_lethal_high
def test_no2_thresholds_ordered(self):
assert WATER.NO2_safe < WATER.NO2_stress < WATER.NO2_lethal
class TestUIAFraction:
def test_uia_at_neutral_ph(self):
f = uia_fraction(7.0, 25.0)
assert 0.0 < f < 0.05 # small fraction at neutral pH
def test_uia_increases_with_ph(self):
f_low = uia_fraction(7.0, 25.0)
f_high = uia_fraction(9.0, 25.0)
assert f_high > f_low * 10 # exponential increase
def test_uia_increases_with_temperature(self):
f_cold = uia_fraction(8.0, 15.0)
f_warm = uia_fraction(8.0, 35.0)
assert f_warm > f_cold
def test_uia_bounded(self):
f = uia_fraction(14.0, 40.0) # extreme
assert 0 < f <= 1.0
class TestDOSaturation:
def test_decreases_with_temperature(self):
assert do_saturation(15.0) > do_saturation(30.0)
def test_realistic_values(self):
assert 7.0 < do_saturation(25.0) < 9.0
assert 6.5 < do_saturation(30.0) < 8.0
def test_always_positive(self):
assert do_saturation(40.0) > 0
class TestPhotoperiodHours:
def test_tropical_roughly_12h(self):
"""At 10° latitude, daylight is roughly 12 hours year-round."""
for day in [1, 90, 180, 270]:
p = photoperiod_hours(day, 10.0)
assert 11.0 < p < 13.0
def test_higher_latitude_more_variation(self):
"""At 45° latitude, summer should have more daylight than winter."""
summer = photoperiod_hours(172, 45.0) # June solstice
winter = photoperiod_hours(355, 45.0) # December solstice
assert summer > winter + 4.0
def test_equator_constant_12h(self):
p = photoperiod_hours(90, 0.0)
assert abs(p - 12.0) < 0.1
class TestTemperatureFactor:
def test_optimal_near_one(self):
tau = temperature_factor(TILAPIA.T_opt)
assert tau > 0.95
def test_zero_at_extremes(self):
assert temperature_factor(TILAPIA.T_min) == 0.0
assert temperature_factor(TILAPIA.T_max) == 0.0
def test_below_min_is_zero(self):
assert temperature_factor(10.0) == 0.0
def test_above_max_is_zero(self):
assert temperature_factor(45.0) == 0.0
def test_symmetric_decay(self):
"""Temperature response should be roughly symmetric around T_opt."""
t_below = temperature_factor(TILAPIA.T_opt - 3)
t_above = temperature_factor(TILAPIA.T_opt + 3)
# Not exactly symmetric (different T_min/T_max), but both should be high
assert t_below > 0.5
assert t_above > 0.5
class TestDOFactor:
def test_above_critical_is_one(self):
assert do_factor(8.0) == 1.0
def test_below_min_is_zero(self):
assert do_factor(2.0) == 0.0
def test_linear_interpolation(self):
mid = (WATER.DO_crit + WATER.DO_min) / 2
sigma = do_factor(mid)
assert 0.4 < sigma < 0.6
class TestUIAFactorFunction:
def test_below_critical_is_one(self):
assert uia_factor(0.01) == 1.0
def test_above_lethal_is_zero(self):
assert uia_factor(1.0) == 0.0
def test_intermediate_value(self):
mid_uia = (WATER.UIA_crit + WATER.UIA_lethal) / 2
v = uia_factor(mid_uia)
assert 0.3 < v < 0.7
class TestEconomicsParams:
def test_feed_cheaper_than_fish(self):
assert ECONOMICS.feed_price_per_kg < ECONOMICS.market_price_per_kg
def test_positive_costs(self):
assert ECONOMICS.fixed_cost_per_day > 0
assert ECONOMICS.electricity_cost_per_kwh > 0
assert ECONOMICS.fingerling_cost > 0
class TestSystemParams:
def test_tank_dimensions(self):
assert SYSTEM.tank_volume_m3 > 0
assert SYSTEM.tank_depth_m > 0
# Surface area should be reasonable
surface = SYSTEM.tank_volume_m3 / SYSTEM.tank_depth_m
assert 50 < surface < 200 # 50-200 m² is reasonable for 100m³ tank
def test_sub_steps_reasonable(self):
assert SYSTEM.sub_steps >= 4 # at least 4 sub-steps for stability