aegis_sim.submodels.genetics.ploider
1import numpy as np 2from numba import njit, prange 3 4 5@njit(parallel=True) 6def _diploid_to_haploid_numba(c0, c1, dominance_factor): 7 """Parallel numba kernel for diploid-to-haploid conversion. 8 9 Operates on uint8 views of bool arrays to avoid numba's bool limitations. 10 Returns float32 output: 1.0 for homozygous true, 0.0 for homozygous false, 11 dominance_factor for heterozygous. 12 """ 13 out = np.empty(c0.shape, dtype=np.float32) 14 n0, n1, n2 = c0.shape 15 for i in prange(n0): 16 for j in range(n1): 17 for k in range(n2): 18 a = c0[i, j, k] 19 b = c1[i, j, k] 20 if a == b: 21 out[i, j, k] = np.float32(a) 22 else: 23 out[i, j, k] = dominance_factor 24 return out 25 26 27class Ploider: 28 """ """ 29 30 def init(self, REPRODUCTION_MODE, DOMINANCE_FACTOR, PLOIDY): 31 self.REPRODUCTION_MODE = REPRODUCTION_MODE 32 self.DOMINANCE_FACTOR = DOMINANCE_FACTOR 33 self.y = PLOIDY 34 35 if REPRODUCTION_MODE == "sexual": 36 assert PLOIDY == 2, f"If reproduction is sexual, ploidy can only be 2, not {PLOIDY}." 37 38 def diploid_to_haploid(self, loci): 39 """Merge two arrays encoding two chromatids into one array. 40 41 Arguments: 42 loci: A bool numpy array with shape (population size, ploidy, genome length, BITS_PER_LOCUS) 43 44 Returns: 45 A float numpy array with shape (population size, genome length, BITS_PER_LOCUS) 46 """ 47 48 assert len(loci.shape) == 4, len(loci.shape) # e.g. (45, 2, 250, 8) 49 assert loci.shape[1] == 2, loci.shape[1] # ploidy 50 51 arr = _diploid_to_haploid_numba( 52 loci[:, 0].view(np.uint8), 53 loci[:, 1].view(np.uint8), 54 np.float32(self.DOMINANCE_FACTOR), 55 ) 56 57 assert len(arr.shape) == 3, len(arr.shape) 58 59 return arr 60 61 62ploider = Ploider()
class
Ploider:
28class Ploider: 29 """ """ 30 31 def init(self, REPRODUCTION_MODE, DOMINANCE_FACTOR, PLOIDY): 32 self.REPRODUCTION_MODE = REPRODUCTION_MODE 33 self.DOMINANCE_FACTOR = DOMINANCE_FACTOR 34 self.y = PLOIDY 35 36 if REPRODUCTION_MODE == "sexual": 37 assert PLOIDY == 2, f"If reproduction is sexual, ploidy can only be 2, not {PLOIDY}." 38 39 def diploid_to_haploid(self, loci): 40 """Merge two arrays encoding two chromatids into one array. 41 42 Arguments: 43 loci: A bool numpy array with shape (population size, ploidy, genome length, BITS_PER_LOCUS) 44 45 Returns: 46 A float numpy array with shape (population size, genome length, BITS_PER_LOCUS) 47 """ 48 49 assert len(loci.shape) == 4, len(loci.shape) # e.g. (45, 2, 250, 8) 50 assert loci.shape[1] == 2, loci.shape[1] # ploidy 51 52 arr = _diploid_to_haploid_numba( 53 loci[:, 0].view(np.uint8), 54 loci[:, 1].view(np.uint8), 55 np.float32(self.DOMINANCE_FACTOR), 56 ) 57 58 assert len(arr.shape) == 3, len(arr.shape) 59 60 return arr
def
init(self, REPRODUCTION_MODE, DOMINANCE_FACTOR, PLOIDY):
31 def init(self, REPRODUCTION_MODE, DOMINANCE_FACTOR, PLOIDY): 32 self.REPRODUCTION_MODE = REPRODUCTION_MODE 33 self.DOMINANCE_FACTOR = DOMINANCE_FACTOR 34 self.y = PLOIDY 35 36 if REPRODUCTION_MODE == "sexual": 37 assert PLOIDY == 2, f"If reproduction is sexual, ploidy can only be 2, not {PLOIDY}."
def
diploid_to_haploid(self, loci):
39 def diploid_to_haploid(self, loci): 40 """Merge two arrays encoding two chromatids into one array. 41 42 Arguments: 43 loci: A bool numpy array with shape (population size, ploidy, genome length, BITS_PER_LOCUS) 44 45 Returns: 46 A float numpy array with shape (population size, genome length, BITS_PER_LOCUS) 47 """ 48 49 assert len(loci.shape) == 4, len(loci.shape) # e.g. (45, 2, 250, 8) 50 assert loci.shape[1] == 2, loci.shape[1] # ploidy 51 52 arr = _diploid_to_haploid_numba( 53 loci[:, 0].view(np.uint8), 54 loci[:, 1].view(np.uint8), 55 np.float32(self.DOMINANCE_FACTOR), 56 ) 57 58 assert len(arr.shape) == 3, len(arr.shape) 59 60 return arr
Merge two arrays encoding two chromatids into one array.
Arguments: loci: A bool numpy array with shape (population size, ploidy, genome length, BITS_PER_LOCUS)
Returns: A float numpy array with shape (population size, genome length, BITS_PER_LOCUS)
ploider =
<Ploider object>