Coverage for pybeepop/beepop/mite.py: 56%
84 statements
« prev ^ index » next coverage.py v7.11.0, created at 2025-10-30 13:34 +0000
« prev ^ index » next coverage.py v7.11.0, created at 2025-10-30 13:34 +0000
1"""
2Mite Population Module for BeePop+ Varroa Mite Simulation
4This module models Varroa destructor mite populations with resistance genetics
5for BeePop+ honey bee colony simulation. It tracks resistant and non-resistant
6mite subpopulations, supporting treatment efficacy modeling and resistance
7evolution studies.
9Classes:
10 Mite: Varroa mite population with resistance genetics tracking
11"""
14class Mite:
15 """
16 Varroa destructor mite population model with resistance genetics for BeePop+ simulation.
18 Attributes:
19 resistant (float): Number of treatment-resistant mites in population
20 non_resistant (float): Number of treatment-susceptible mites in population
22 Note:
23 Arithmetic operations include C++ compatibility features like integer
24 truncation in addition operations to maintain exact simulation reproducibility.
25 """
27 def __init__(self, resistant=0.0, non_resistant=0.0):
28 self.resistant = resistant
29 self.non_resistant = non_resistant
31 def zero(self):
32 self.resistant = 0.0
33 self.non_resistant = 0.0
35 def get_resistant(self):
36 return self.resistant
38 def get_non_resistant(self):
39 return self.non_resistant
41 def set_resistant(self, num):
42 self.resistant = num
44 def set_non_resistant(self, num):
45 self.non_resistant = num
47 def get_total(self):
48 return self.resistant + self.non_resistant
50 def get_pct_resistant(self):
51 total = self.get_total()
52 return (100.0 * self.resistant / total) if total > 0 else 0.0
54 def set_pct_resistant(self, pct):
55 total = self.get_total()
56 self.resistant = total * pct / 100.0
57 self.non_resistant = total - self.resistant
59 def __iadd__(self, other):
60 if isinstance(other, Mite):
61 self.resistant += other.resistant
62 self.non_resistant += other.non_resistant
63 elif isinstance(other, (int, float)):
64 total = self.get_total()
65 pctres = self.resistant / total if total > 0 else 0.0
66 addtores = other * pctres
67 self.resistant += addtores
68 self.non_resistant += other - addtores
69 return self
71 def __isub__(self, other):
72 if isinstance(other, Mite):
73 self.resistant -= other.resistant
74 self.non_resistant -= other.non_resistant
75 elif isinstance(other, (int, float)):
76 total = self.get_total()
77 pctres = self.resistant * 100 / total if total > 0 else 0.0
78 subfromres = other * pctres / 100.0
79 self.resistant -= subfromres
80 self.non_resistant -= other - subfromres
81 self.resistant = max(0.0, self.resistant)
82 self.non_resistant = max(0.0, self.non_resistant)
83 return self
85 def __add__(self, other):
86 if isinstance(other, Mite):
87 # Match C++ behavior: truncate to int like CMite::operator+(CMite theMite)
88 res = self.resistant + other.resistant
89 nres = self.non_resistant + other.non_resistant
90 return Mite(int(res), int(nres))
91 elif isinstance(other, (int, float)):
92 return Mite(self.resistant, self.non_resistant + other)
93 return NotImplemented
95 def __radd__(self, other):
96 # Handle cases like 0 + Mite or int + Mite
97 if isinstance(other, (int, float)):
98 return Mite(self.resistant, self.non_resistant + other)
99 return NotImplemented
101 def __sub__(self, other):
102 if isinstance(other, Mite):
103 res = self.resistant - other.resistant
104 nres = self.non_resistant - other.non_resistant
105 return Mite(max(0.0, res), max(0.0, nres))
106 elif isinstance(other, (int, float)):
107 return Mite(self.resistant, max(0.0, self.non_resistant - other))
108 return NotImplemented
110 def __mul__(self, value):
111 if isinstance(value, (int, float)):
112 return Mite(self.resistant * value, self.non_resistant * value)
113 return NotImplemented
115 def __int__(self):
116 return int(self.get_total())
118 def __eq__(self, other):
119 if not isinstance(other, Mite):
120 return False
121 return (
122 self.resistant == other.resistant
123 and self.non_resistant == other.non_resistant
124 )
126 def assign_value(self, value):
127 """
128 Matches C++ CMite::operator=(double value) behavior.
129 Sets resistant = 0 and non_resistant = value.
130 """
131 self.resistant = 0.0
132 self.non_resistant = float(value)
133 return self
135 def __str__(self):
136 return f"Mite(resistant={self.resistant}, non_resistant={self.non_resistant})"