presets Module
Built-in genetic presets and preset application helpers.
Overview
The presets subpackage provides reusable preset abstractions and concrete
implementations (for example, gene drives) that can inject gamete modifiers,
zygote modifiers, and fitness patches into populations.
Complete Module Reference
natal.presets
Genetic presets subpackage.
Provides genetic modification presets including gene drives (HomingDrive, ToxinAntidoteDrive), cytoplasmic inheritance (Wolbachia), allele conversion systems, and the GeneticPreset base class.
GameteAlleleConversionRule
GameteAlleleConversionRule(from_allele: Union[str, Gene], to_allele: Union[str, Gene], rate: float, name: Optional[str] = None, sex_filter: Optional[Union[str, int, Sex]] = 'both', genotype_filter: _GenotypeFilter = None, source_glab: Optional[Union[str, int]] = None, target_glab: Optional[Union[str, int]] = None)
Defines a single allele conversion rule: from_allele -> to_allele with probability.
Examples:
rule = GameteAlleleConversionRule(from_allele="A", to_allele="B", rate=0.5)
In heterozygotes carrying A, 50% of gametes convert A -> B
Initialize an allele conversion rule.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
from_allele
|
Union[str, Gene]
|
Source allele (string identifier or Gene object). |
required |
to_allele
|
Union[str, Gene]
|
Target allele (string identifier or Gene object). |
required |
rate
|
float
|
Conversion probability, must be in [0, 1]. |
required |
name
|
Optional[str]
|
Optional human-readable name. |
None
|
sex_filter
|
Optional[Union[str, int, Sex]]
|
Apply only to specific sex ("female", "male", or "both"). |
'both'
|
genotype_filter
|
_GenotypeFilter
|
Optional filter for applicable genotypes. Accepts callable or genotype pattern string. |
None
|
source_glab
|
Optional[Union[str, int]]
|
Optional gamete label filter. If specified, this rule only applies to gametes carrying this label (str name or int index). If None, applies to all glab variants. |
None
|
target_glab
|
Optional[Union[str, int]]
|
Optional gamete label for converted gametes. If specified, the converted gamete will be tagged with this label. If None, the converted gamete retains the source's glab. |
None
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If rate is not in [0, 1]. |
TypeError
|
If from_allele and to_allele types don't match. |
Source code in src/natal/modifiers/gamete_conversion.py
applies_to_sex
Check if rule applies to a given sex.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sex_idx
|
_SexSpecifier
|
Integer sex index (0 for first sex, 1 for second, etc.). |
required |
sex_name
|
Optional[str]
|
Optional sex name for clarity ("female", "male"). |
None
|
Returns:
| Type | Description |
|---|---|
bool
|
True if rule applies to this sex. |
Source code in src/natal/modifiers/gamete_conversion.py
applies_to_genotype
Check if rule applies to a given genotype.
If no filter is set, rule applies to all genotypes.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
genotype
|
Genotype
|
The Genotype to check. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True if rule should apply to this genotype. |
Source code in src/natal/modifiers/gamete_conversion.py
GameteConversionRuleSet
Manages a collection of gamete conversion rules.
Accepts both :class:GameteAlleleConversionRule (allele-level) and
:class:GameteHaploidGenomeConversionRule (whole-HaploidGenotype-level).
Rules are evaluated in insertion order; the first matching rule wins for
each (hg, glab) entry.
Example usage::
ruleset = GameteConversionRuleSet()
# allele-level
ruleset.add_allele_convert("A", "B", rate=0.5)
# haploid-genome-level
ruleset.add_hg_convert(hg_AB, hg_CD, rate=0.8)
gamete_mod = ruleset.to_gamete_modifier(population)
population.add_gamete_modifier(gamete_mod, name="conversions")
Initialize an empty ruleset.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Human-readable name for this ruleset. |
'GameteConversionRuleSet'
|
Source code in src/natal/modifiers/gamete_conversion.py
add_rule
Append a rule (allele-level or HaploidGenotype-level). Returns self.
Source code in src/natal/modifiers/gamete_conversion.py
add_allele_convert
add_allele_convert(from_allele: Union[str, Gene], to_allele: Union[str, Gene], rate: float, sex_filter: Optional[Union[str, int]] = None, genotype_filter: _GenotypeFilter = None, source_glab: Optional[Union[str, int]] = None, target_glab: Optional[Union[str, int]] = None) -> GameteConversionRuleSet
Add an allele-level conversion rule.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
from_allele
|
Union[str, Gene]
|
Source allele identifier or Gene. |
required |
to_allele
|
Union[str, Gene]
|
Target allele identifier or Gene. |
required |
rate
|
float
|
Conversion probability. |
required |
sex_filter
|
Optional[Union[str, int]]
|
Rule applies only to this sex ("male"/"female" or index). |
None
|
genotype_filter
|
_GenotypeFilter
|
Rule applies only if diploid parent passes this filter. |
None
|
source_glab
|
Optional[Union[str, int]]
|
Rule applies only to gametes currently holding this label. |
None
|
target_glab
|
Optional[Union[str, int]]
|
Gametes that successfully convert get reassigned to this label. |
None
|
Returns:
| Type | Description |
|---|---|
GameteConversionRuleSet
|
self for chaining. |
Source code in src/natal/modifiers/gamete_conversion.py
add_hg_convert
add_hg_convert(hg_match: Union[Callable[[HaploidGenotype], bool], HaploidGenotype], to_haploid_genotype: Union[HaploidGenotype, Callable[[HaploidGenotype], HaploidGenotype]], rate: float, sex_filter: Optional[Union[str, int]] = None, genotype_filter: _GenotypeFilter = None, source_glab: Optional[Union[str, int]] = None, target_glab: Optional[Union[str, int]] = None) -> GameteConversionRuleSet
Add a HaploidGenotype-level conversion rule.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
hg_match
|
Union[Callable[[HaploidGenotype], bool], HaploidGenotype]
|
Match predicate / HaploidGenotype. |
required |
to_haploid_genotype
|
Union[HaploidGenotype, Callable[[HaploidGenotype], HaploidGenotype]]
|
Replacement HaploidGenotype or callable. |
required |
rate
|
float
|
Conversion probability. |
required |
sex_filter
|
Optional[Union[str, int]]
|
Rule applies only to this sex ("male"/"female" or index). |
None
|
genotype_filter
|
_GenotypeFilter
|
Rule applies only if diploid parent passes this filter. |
None
|
source_glab
|
Optional[Union[str, int]]
|
Rule applies only to gametes currently holding this label. |
None
|
target_glab
|
Optional[Union[str, int]]
|
Gametes that successfully convert get reassigned to this label. |
None
|
Returns:
| Type | Description |
|---|---|
GameteConversionRuleSet
|
self for chaining. |
Source code in src/natal/modifiers/gamete_conversion.py
to_gamete_modifier
Convert the ruleset to a GameteModifier for population integration.
The returned modifier will
- Iterate over all genotypes in the population
- For each genotype, extract glab-aware gamete frequencies
- Apply conversion rules respecting source_glab/target_glab constraints
- Return compressed-index frequency mappings
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
population
|
BasePopulation[Any]
|
The BasePopulation that will use this modifier. |
required |
Returns:
| Type | Description |
|---|---|
GameteModifier
|
A callable that implements GameteModifier protocol. |
Source code in src/natal/modifiers/gamete_conversion.py
388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 | |
GameteHaploidGenomeConversionRule
GameteHaploidGenomeConversionRule(hg_match: Union[Callable[[HaploidGenotype], bool], HaploidGenotype], to_haploid_genotype: Union[HaploidGenotype, Callable[[HaploidGenotype], HaploidGenotype]], rate: float, name: Optional[str] = None, sex_filter: Optional[Union[str, int, Sex]] = 'both', genotype_filter: _GenotypeFilter = None, source_glab: Optional[Union[str, int]] = None, target_glab: Optional[Union[str, int]] = None)
Defines a whole-HaploidGenotype replacement rule at the gamete level.
Unlike :class:GameteAlleleConversionRule which swaps a single allele,
this rule matches an entire HaploidGenotype and replaces it with
another HaploidGenotype (or a dynamically computed one).
Examples:
# Replace haploid genome hg_AB with hg_CD at 80 % probability
rule = GameteHaploidGenomeConversionRule(
hg_match=hg_AB,
to_haploid_genotype=hg_CD,
rate=0.8,
)
Initialise a haploid-genome-level gamete conversion rule.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
hg_match
|
Union[Callable[[HaploidGenotype], bool], HaploidGenotype]
|
Either a specific |
required |
to_haploid_genotype
|
Union[HaploidGenotype, Callable[[HaploidGenotype], HaploidGenotype]]
|
The replacement |
required |
rate
|
float
|
Probability of conversion, in [0, 1]. |
required |
name
|
Optional[str]
|
Human-readable label. |
None
|
sex_filter
|
Optional[Union[str, int, Sex]]
|
Apply only to specific sex. |
'both'
|
genotype_filter
|
_GenotypeFilter
|
Optional filter on the diploid Genotype of the gamete producer. Accepts callable or genotype pattern string. |
None
|
source_glab
|
Optional[Union[str, int]]
|
Optional glab filter on the input gamete. |
None
|
target_glab
|
Optional[Union[str, int]]
|
Optional glab to assign to the converted gamete. |
None
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If rate is not in [0, 1]. |
Source code in src/natal/modifiers/gamete_conversion.py
matches
replacement
applies_to_sex
Check if rule applies to a given sex.
Source code in src/natal/modifiers/gamete_conversion.py
applies_to_genotype
Check if rule applies to a given diploid genotype.
Source code in src/natal/modifiers/gamete_conversion.py
ZygoteAlleleConversionRule
ZygoteAlleleConversionRule(from_allele: Union[str, Gene], to_allele: Union[str, Gene], rate: float, name: Optional[str] = None, side: Literal['maternal', 'paternal', 'both'] = 'both', genotype_filter: _GenotypeFilter = None, maternal_glab: Optional[Union[str, int]] = None, paternal_glab: Optional[Union[str, int]] = None)
Defines an allele-level zygote conversion rule: from_allele -> to_allele.
Unlike :class:ZygoteGenotypeConversionRule which matches and replaces whole
diploid genotypes, this rule operates at the single-allele level — if
the zygote's genotype contains from_allele, it is replaced by
to_allele on the specified side(s) of the diploid.
The side parameter controls which parental copy is subject to
conversion:
"maternal"— only the maternal haploid genome."paternal"— only the paternal haploid genome."both"— both sides independently (can produce up to 4 outcome genotypes for a double-heterozygote).
Examples:
# In the zygote, convert allele W→D on both sides with 95% each
rule = ZygoteAlleleConversionRule("W", "D", rate=0.95, side="both")
Initialise an allele-level zygote conversion rule.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
from_allele
|
Union[str, Gene]
|
Source allele (string name or |
required |
to_allele
|
Union[str, Gene]
|
Target allele (string name or |
required |
rate
|
float
|
Per-copy conversion probability, in [0, 1]. |
required |
name
|
Optional[str]
|
Human-readable label. |
None
|
side
|
Literal['maternal', 'paternal', 'both']
|
Which parental copy to attempt conversion on. |
'both'
|
genotype_filter
|
_GenotypeFilter
|
Optional genotype filter. Accepts predicate
|
None
|
maternal_glab
|
Optional[Union[str, int]]
|
Optional glab filter on maternal gamete (c1). |
None
|
paternal_glab
|
Optional[Union[str, int]]
|
Optional glab filter on paternal gamete (c2). |
None
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If rate is not in [0, 1]. |
Source code in src/natal/modifiers/zygote_conversion.py
applies_to_genotype
Check whether this rule should be evaluated for genotype.
Source code in src/natal/modifiers/zygote_conversion.py
ZygoteConversionRuleSet
Manages a collection of zygote conversion rules.
Accepts both :class:ZygoteGenotypeConversionRule (genotype-level) and
:class:ZygoteAlleleConversionRule (allele-level). Rules are
evaluated in insertion order; the first matching rule wins for each
(c1, c2) pair.
Examples:
ruleset = ZygoteConversionRuleSet()
# genotype-level
ruleset.add_convert(gt_AA, gt_Aa, rate=0.8)
# allele-level
ruleset.add_allele_convert("W", "D", rate=0.95, side="both")
zygote_mod = ruleset.to_zygote_modifier(population)
population.add_zygote_modifier(zygote_mod, name="zygote_conversions")
Initialize an empty zygote conversion rule set.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
A human-readable name for this rule set. |
'ZygoteConversionRuleSet'
|
Source code in src/natal/modifiers/zygote_conversion.py
add_rule
Append a rule (genotype-level or allele-level). Returns self.
Source code in src/natal/modifiers/zygote_conversion.py
add_convert
add_convert(genotype_match: Union[Callable[[Genotype], bool], Genotype], to_genotype: Union[Genotype, Callable[[Genotype], Genotype]], rate: float, name: Optional[str] = None, maternal_glab: Optional[Union[str, int]] = None, paternal_glab: Optional[Union[str, int]] = None) -> ZygoteConversionRuleSet
Add a genotype-level conversion rule.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
genotype_match
|
Union[Callable[[Genotype], bool], Genotype]
|
Match predicate / Genotype. |
required |
to_genotype
|
Union[Genotype, Callable[[Genotype], Genotype]]
|
Replacement Genotype or callable. |
required |
rate
|
float
|
Conversion probability. |
required |
name
|
Optional[str]
|
Human-readable label. |
None
|
maternal_glab
|
Optional[Union[str, int]]
|
Optional gamete-label filter on the maternal gamete. |
None
|
paternal_glab
|
Optional[Union[str, int]]
|
Optional gamete-label filter on the paternal gamete. |
None
|
Returns:
| Type | Description |
|---|---|
ZygoteConversionRuleSet
|
self for chaining. |
Source code in src/natal/modifiers/zygote_conversion.py
add_allele_convert
add_allele_convert(from_allele: Union[str, Gene], to_allele: Union[str, Gene], rate: float, name: Optional[str] = None, side: Literal['maternal', 'paternal', 'both'] = 'both', genotype_filter: _GenotypeFilter = None, maternal_glab: Optional[Union[str, int]] = None, paternal_glab: Optional[Union[str, int]] = None) -> ZygoteConversionRuleSet
Add an allele-level conversion rule.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
from_allele
|
Union[str, Gene]
|
Source allele identifier or Gene. |
required |
to_allele
|
Union[str, Gene]
|
Target allele identifier or Gene. |
required |
rate
|
float
|
Per-copy conversion probability. |
required |
name
|
Optional[str]
|
Human-readable label. |
None
|
side
|
Literal['maternal', 'paternal', 'both']
|
Which parental copy to attempt conversion on ("maternal", "paternal", "both"). |
'both'
|
genotype_filter
|
_GenotypeFilter
|
Optional genotype filter (predicate or pattern string). |
None
|
maternal_glab
|
Optional[Union[str, int]]
|
Optional glab filter on maternal gamete. |
None
|
paternal_glab
|
Optional[Union[str, int]]
|
Optional glab filter on paternal gamete. |
None
|
Returns:
| Type | Description |
|---|---|
ZygoteConversionRuleSet
|
self for chaining. |
Source code in src/natal/modifiers/zygote_conversion.py
to_zygote_modifier
Convert the rule-set into a ZygoteModifier.
The returned callable produces a dict understood by the existing
wrap_zygote_modifier infrastructure::
{ (c1, c2): { genotype_idx: prob, ... }, ... }
Both genotype-level and allele-level rules are evaluated in
insertion order. The first matching rule wins for each
(c1, c2) pair.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
population
|
BasePopulation[Any]
|
The population that will consume the modifier. |
required |
Returns:
| Type | Description |
|---|---|
ZygoteModifier
|
A zero-argument callable implementing |
Source code in src/natal/modifiers/zygote_conversion.py
355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 | |
ZygoteGenotypeConversionRule
ZygoteGenotypeConversionRule(genotype_match: Union[Callable[[Genotype], bool], Genotype], to_genotype: Union[Genotype, Callable[[Genotype], Genotype]], rate: float, name: Optional[str] = None, maternal_glab: Optional[Union[str, int]] = None, paternal_glab: Optional[Union[str, int]] = None)
Defines a single zygote-level genotype conversion rule.
A rule specifies that when a zygote's resulting diploid genotype
satisfies genotype_match, it may be converted to to_genotype
with the given rate.
The genotype_match predicate operates on the Genotype that would
normally result from fertilization before the modifier is applied.
Examples:
# Whenever the zygote would be AA, convert to Aa with 80% probability
rule = ZygoteGenotypeConversionRule(
genotype_match=lambda g: g.is_homozygous_at(locus_A),
to_genotype=Aa_genotype,
rate=0.8,
)
Initialise a zygote conversion rule.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
genotype_match
|
Union[Callable[[Genotype], bool], Genotype]
|
Either a specific |
required |
to_genotype
|
Union[Genotype, Callable[[Genotype], Genotype]]
|
The replacement genotype. May be a concrete
|
required |
rate
|
float
|
Probability of conversion, in [0, 1]. |
required |
name
|
Optional[str]
|
Human-readable label. |
None
|
maternal_glab
|
Optional[Union[str, int]]
|
Optional gamete-label filter on the maternal
gamete (c1). If specified, the rule only fires when the
maternal gamete carries this glab (str name or int index).
|
None
|
paternal_glab
|
Optional[Union[str, int]]
|
Optional gamete-label filter on the paternal gamete (c2). Same semantics as maternal_glab but for the paternal contribution. |
None
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If rate is not in [0, 1]. |
Source code in src/natal/modifiers/zygote_conversion.py
matches
replacement
GeneticPreset
Bases: ABC
Abstract base for genetic modification presets including gene drives, mutations, and allele conversions.
A preset bundles gamete modifiers, zygote modifiers, and fitness effects that form a cohesive genetic system. This can include: - Gene drives (e.g., CRISPR/Cas9 homing drives) - General mutations (point mutations, insertions, deletions) - Complex allele conversion systems
Presets should implement
- gamete_modifier(): returns GameteModifier callable or None
- zygote_modifier(): returns ZygoteModifier callable or None
- fitness_patch(): returns declarative fitness configuration dict or None
All methods are optional (can return None). At least one method should be implemented for the preset to have any effect.
Examples:
Attributes:
| Name | Type | Description |
|---|---|---|
name |
str
|
Human-readable preset name. |
hook_id |
Optional[int]
|
Optional identifier used when registering modifiers. |
Initialize the preset.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Optional human-readable name for the preset. |
''
|
species
|
Optional[Species]
|
Optional species bound at construction time. |
None
|
priority
|
int
|
Execution order — lower values apply first. Same priority uses registration order (stable sort). |
0
|
Source code in src/natal/presets/_base.py
bind_species
Bind this preset instance to a concrete species.
This enables delayed species injection: users can construct presets without passing species, and binding happens automatically when the preset is applied to a population.
Source code in src/natal/presets/_base.py
gamete_modifier
abstractmethod
Return a gamete modifier or None.
The modifier should return:
Dict[(sex_idx, ztype_idx) -> Dict[compressed_hg_glab_idx -> freq]]
where compressed_hg_glab_idx is an integer index into the compressed haploid genotype space.
Source code in src/natal/presets/_base.py
zygote_modifier
abstractmethod
Return a zygote modifier or None.
The modifier should return:
Dict[(c1, c2) -> (idx_modified | Genotype | Dict[idx -> prob])]
where c1, c2 are compressed coordinate pairs representing the parental diploid genotypes.
Source code in src/natal/presets/_base.py
fitness_patch
Return declarative fitness patch.
Returns:
| Type | Description |
|---|---|
Optional[PresetFitnessPatch]
|
Fitness patch from custom function if set, otherwise None. |
Optional[PresetFitnessPatch]
|
Subclasses should override this method for built-in behavior. |
Source code in src/natal/presets/_base.py
with_fitness_patch
Set a custom fitness patch function and return self for chaining.
This allows dynamic modification of fitness effects at runtime without subclassing, using a fluent interface.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
patch_func
|
Callable[[], Optional[PresetFitnessPatch]]
|
Callable that returns a PresetFitnessPatch or None. |
required |
Returns:
| Type | Description |
|---|---|
Self
|
Self for method chaining. |
Example
preset = (HomingDrive(...) ... .with_fitness_patch(lambda: { ... 'viability_allele': {'Drive': (0.8, 'dominant')} ... })) population.apply_preset(preset)
Also works with complex custom logic
def conditional_patch(): ... if some_condition: ... return {'fecundity_allele': {'Mut': (0.5, 'recessive')}} ... return None
preset = HomingDrive(...).with_fitness_patch(conditional_patch)
Note
This overrides any fitness patch defined in subclasses. To preserve subclass behavior while adding modifications, subclass and call super().fitness_patch() instead.
Source code in src/natal/presets/_base.py
clear_fitness_patch
Remove any custom fitness patch, restoring default behavior.
Returns:
| Type | Description |
|---|---|
GeneticPreset
|
Self for method chaining. |
apply
Register this preset onto a population (DEPRECATED).
.. deprecated:: Use population.apply_preset(preset) instead. This method is kept for backwards compatibility and may be removed in future versions.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
population
|
BasePopulation[Any]
|
The BasePopulation instance to modify. |
required |
See Also
:meth:natal.population.base.BasePopulation.apply_preset - Preferred modern API
Source code in src/natal/presets/_base.py
CytoplasmicPreset
Bases: GeneticPreset
Base class for maternally-inherited cytoplasmic elements.
Child slab = mother slab regardless of father. The mechanism:
1. Gamete tagging happens externally during slab expansion
(via build_population_config) — the
non-default glab/slab pairs are auto-detected by convention.
gamete_modifier returns None (no per-modifier tagging).
2. apply_zygote_redirect (called during zygote map expansion)
redirects tagged gamete pairs from slab-0 to the correct child slab.
Subclasses must provide _maternal_map — a dict mapping
{maternal_slab_name: glab_name}. Each maternal slab that
should be heritable gets a unique glab for tagging.
Example (Wolbachia): _maternal_map = {"infected": "wolbachia"}
Source code in src/natal/presets/_base.py
gamete_modifier
zygote_modifier
Return no zygote-level modifier — redirection is done post-expansion.
apply_zygote_redirect
staticmethod
apply_zygote_redirect(z2g_expanded: NDArray[float64], glab_name: str, slab_name: str, gamete_labels: List[str], somatic_labels: List[str], n_slabs: int, n_genotypes_raw: int, n_hg: int, n_glabs: int) -> None
Redirect zygote columns: glab-tagged maternal gametes → target slab.
Looks up glab_name and slab_name in the label lists (not the registry — this runs in build_population_config which has no registry access). No-op if either label is missing.
Source code in src/natal/presets/cytoplasmic.py
tag_maternal_gametes
staticmethod
tag_maternal_gametes(z2g_expanded: NDArray[float64], gamete_labels: List[str], somatic_labels: List[str], n_genotypes: int, n_gtypes: int, n_glabs: int, n_slabs: int) -> None
Tag maternal gametes so non-default glabs are inherited maternally.
Operates on the slab-expanded z2g map (post-expansion, shape
(2, G×S, HL)). For each matching glab/slab index pair
(glab[i] ↔ slab[i] for i >= 1), copies the default-glab female
gamete probabilities to the non-default glab column — and zeros
out the original — so that only mothers carrying the matching
slab produce gametes with the non-default glab.
This method should be called after slab expansion and before redirect_zygotes.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
z2g_expanded
|
NDArray[float64]
|
Slab-expanded genotype-to-gamete map, shape
|
required |
gamete_labels
|
List[str]
|
Ordered gamete label names. |
required |
somatic_labels
|
List[str]
|
Ordered somatic label names. |
required |
n_genotypes
|
int
|
Pre-expansion genotype count |
required |
n_gtypes
|
int
|
Number of haploid genotype types (HL / n_glabs). |
required |
n_glabs
|
int
|
Number of gamete label types. |
required |
n_slabs
|
int
|
Number of somatic label types. |
required |
Source code in src/natal/presets/cytoplasmic.py
redirect_zygotes
staticmethod
redirect_zygotes(g2z_expanded: NDArray[float64], gamete_labels: List[str], somatic_labels: List[str], n_genotypes: int, n_gtypes: int, n_glabs: int, n_slabs: int) -> None
Redirect zygote columns: glab-tagged gamete pairs → matching child slab.
Iterates matching glab/slab index pairs (glab[i] ↔ slab[i] for
i >= 1) and calls :meth:apply_zygote_redirect for each pair.
That method moves zygote probabilities from the default slab-0
column to the matching child slab column when the maternal gamete
carries the glab tag — enforcing strict maternal inheritance.
This method should be called after slab expansion and
tag_maternal_gametes.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
g2z_expanded
|
NDArray[float64]
|
Slab-expanded gametes-to-zygote map, shape
|
required |
gamete_labels
|
List[str]
|
Ordered gamete label names. |
required |
somatic_labels
|
List[str]
|
Ordered somatic label names. |
required |
n_genotypes
|
int
|
Pre-expansion genotype count |
required |
n_gtypes
|
int
|
Number of haploid genotype types (HL / n_glabs). |
required |
n_glabs
|
int
|
Number of gamete label types. |
required |
n_slabs
|
int
|
Number of somatic label types. |
required |
Source code in src/natal/presets/cytoplasmic.py
TransgenicBackground
TransgenicBackground(name: str, tg_slab: str, wt_slab: str = 'WT_bg', fecundity_scaling: float = 1.0, viability_scaling: Optional[float] = None, species: Optional[Species] = None, priority: int = 0)
Bases: GeneticPreset
Fitness scaling for a transgenic background slab.
Applies fecundity and/or viability scaling to individuals carrying the tg_slab somatic label. Does NOT implement outcrossing clearance — that requires a separate inheritance mechanism.
Initialize a TransgenicBackground preset.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Preset name. |
required |
tg_slab
|
str
|
Somatic slab label for transgenic individuals. |
required |
wt_slab
|
str
|
Somatic slab label for wild-type background. |
'WT_bg'
|
fecundity_scaling
|
float
|
Fecundity multiplier for transgenic carriers. |
1.0
|
viability_scaling
|
Optional[float]
|
Optional viability multiplier for transgenic
carriers. |
None
|
species
|
Optional[Species]
|
Optional species for validation. |
None
|
priority
|
int
|
Modifier and fitness application priority. |
0
|
Source code in src/natal/presets/cytoplasmic.py
gamete_modifier
zygote_modifier
fitness_patch
Build fitness patch applying fecundity and optional viability scaling.
Returns:
| Type | Description |
|---|---|
PresetFitnessPatch
|
A fitness patch dict with |
PresetFitnessPatch
|
|
Source code in src/natal/presets/cytoplasmic.py
Wolbachia
Wolbachia(name: str, infected_slab: str = 'infected', normal_slab: str = 'normal', viability_scaling: float = 1.0, fecundity_scaling: Optional[float] = None, species: Optional[Species] = None, priority: int = 0)
Bases: CytoplasmicPreset
Maternally-inherited endosymbiont. Infected mothers pass the infection to all offspring regardless of the father.
Requires Species with
- gamete_labels including
"wolbachia" - somatic_labels including
"normal","infected"
Initialize a Wolbachia cytoplasmic preset.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Preset name. |
required |
infected_slab
|
str
|
Somatic slab label for infected individuals. |
'infected'
|
normal_slab
|
str
|
Somatic slab label for uninfected individuals. |
'normal'
|
viability_scaling
|
float
|
Viability multiplier for infected carriers. |
1.0
|
fecundity_scaling
|
Optional[float]
|
Fecundity multiplier for infected carriers.
|
None
|
species
|
Optional[Species]
|
Optional species for validation. |
None
|
priority
|
int
|
Modifier and fitness application priority. |
0
|
Source code in src/natal/presets/cytoplasmic.py
fitness_patch
Build fitness patch applying viability and fecundity scaling.
Returns:
| Type | Description |
|---|---|
PresetFitnessPatch
|
A fitness patch dict with optional |
PresetFitnessPatch
|
|
Source code in src/natal/presets/cytoplasmic.py
HomingDrive
HomingDrive(name: str, drive_allele: AlleleSpecifier, target_allele: AlleleSpecifier, resistance_allele: Optional[AlleleSpecifier] = None, functional_resistance_allele: Optional[AlleleSpecifier] = None, cas9_allele: Optional[AlleleSpecifier] = None, drive_conversion_rate: SexSpecificRates = 0.5, late_germline_resistance_formation_rate: SexSpecificRates = 0.0, embryo_resistance_formation_rate: SexSpecificRates = 0.0, functional_resistance_ratio: float = 0.0, fecundity_scaling: FecundityScalingConfig = 1.0, viability_scaling: ViabilityScalingConfig = 1.0, sexual_selection_scaling: SexualSelectionScalingConfig = 1.0, zygote_viability_scaling: ZygoteViabilityScalingConfig = 1.0, viability_mode: AlleleScalingMode = 'multiplicative', fecundity_mode: AlleleScalingMode = 'multiplicative', sexual_selection_mode: AlleleScalingMode = 'multiplicative', zygote_viability_mode: AlleleScalingMode = 'multiplicative', cas9_deposition_glab: Optional[str] = None, species: Optional[Any] = None, priority: int = 0, use_paternal_deposition: bool = False)
Bases: GeneticPreset
Homing-based gene drive (e.g., CRISPR/Cas9 homing drives).
This preset implements a homing gene drive that spreads through homology-directed repair (HDR) converting wild-type alleles into drive alleles in heterozygotes. It can also generate resistance alleles through non-homologous end joining (NHEJ).
Key features include drive conversion in heterozygotes, germline/embryo resistance formation, optional parental Cas9 deposition, and sex-specific rate control.
The drive operates through a sequential cascade: 1. Homing conversion (WT -> Drive) 2. Resistance formation in remaining WT alleles 3. Optional functional resistance split
Attributes:
| Name | Type | Description |
|---|---|---|
drive_conversion_rate |
Tuple[float, float]
|
Female/male homing rates. |
late_germline_resistance_formation_rate |
Tuple[float, float]
|
Female/male late germline resistance rates. |
embryo_resistance_formation_rate |
Tuple[float, float]
|
Female/male embryo resistance rates. |
Examples:
drive = HomingDrive( name="MyDrive", drive_allele="Drive", target_allele="WT", resistance_allele="Resistance", drive_conversion_rate=0.95, late_germline_resistance_formation_rate=0.03 ) population.apply_preset(drive)
Initialize a homing-based gene drive (e.g., CRISPR/Cas9 homing drives).
This drive spreads via homology-directed repair (HDR) converting wild-type alleles into drive alleles in heterozygotes. It can also generate resistance alleles through non-homologous end joining (NHEJ).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Name of the gene drive. |
required |
drive_allele
|
str or Gene
|
The allele carrying the drive cassette. |
required |
target_allele
|
str or Gene
|
The wild-type allele targeted by the drive. |
required |
resistance_allele
|
str or Gene
|
The non-functional resistance allele formed by NHEJ. |
None
|
functional_resistance_allele
|
str or Gene
|
The functional resistance allele formed by in-frame NHEJ. If not provided, assume no functional resistance. |
None
|
cas9_allele
|
str or Gene
|
The allele carrying Cas9 for cleavage, used when modeling a split drive where Cas9 is separate from the drive locus. |
None
|
drive_conversion_rate
|
float or dict
|
Probability of drive conversion caused by Cas9 cleavage and homology-directed repair in heterozygotes. Can be a single float (applies to both sexes), a dict with sex keys, or a tuple (female_rate, male_rate) for sex-specific rates. |
0.5
|
late_germline_resistance_formation_rate
|
float or dict
|
Probability of resistance formation after drive conversion in the germline. Can be a single float (applies to both sexes), a dict with sex keys, or a tuple (female_rate, male_rate) for sex-specific rates. |
0.0
|
embryo_resistance_formation_rate
|
float or dict
|
Probability of resistance formation in embryos due to maternal/paternal Cas9 deposition. Can be a single float, dict, or tuple. |
0.0
|
functional_resistance_ratio
|
float
|
Proportion of resistance alleles that are functional (in-frame mutations). Range: 0.0 (all non-functional) to 1.0 (all functional). |
0.0
|
fecundity_scaling
|
float or dict
|
Fitness multiplier for drive carriers affecting fecundity. Applied multiplicatively based on allele copy number. |
1.0
|
viability_scaling
|
float or dict
|
Fitness multiplier for drive carriers affecting viability. Applied multiplicatively based on allele copy number. |
1.0
|
sexual_selection_scaling
|
float or tuple
|
Fitness multiplier affecting sexual selection. Can be a single float or tuple (default_selection, carrier_selection). |
1.0
|
zygote_viability_scaling
|
float or dict
|
Fitness multiplier affecting survival of zygotes before competition takes place. Applied multiplicatively based on allele copy number. |
1.0
|
viability_mode
|
str
|
Scaling mode: "multiplicative", "dominant", "recessive", or "custom". If "custom", scaling values must be tuples (het_val, hom_val). |
'multiplicative'
|
fecundity_mode
|
str
|
Scaling mode: "multiplicative", "dominant", "recessive", or "custom". If "custom", scaling values must be tuples (het_val, hom_val). |
'multiplicative'
|
sexual_selection_mode
|
str
|
Scaling mode for scalar sexual_selection_scaling. Note: if sexual_selection_scaling is a tuple, mode is ignored. |
'multiplicative'
|
zygote_viability_mode
|
str
|
Scaling mode: "multiplicative", "dominant", "recessive", or "custom". If "custom", scaling values must be tuples (het_val, hom_val). |
'multiplicative'
|
cas9_deposition_glab
|
str
|
Gamete label for Cas9 deposition tracking. Used for maternal/paternal effect modeling. |
None
|
species
|
Species
|
Species to bind at construction time. If None, will be bound when applied to population. |
None
|
use_paternal_deposition
|
bool
|
Whether to enable paternal Cas9 deposition. If True, fathers can deposit Cas9 in embryos. |
False
|
Examples:
>>> drive = HomingDrive(
... name="MyDrive",
... drive_allele="Drive",
... target_allele="WT",
... resistance_allele="R2",
... drive_conversion_rate=0.95,
... late_germline_resistance_formation_rate=0.03
... )
>>> population.apply_preset(drive)
Source code in src/natal/presets/homing.py
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 | |
resistance_genotype
property
Gene: The resistance allele formed by NHEJ repair.
Raises:
| Type | Description |
|---|---|
ValueError
|
If no resistance allele was configured. |
functional_resistance_allele
property
Gene or None: The functional resistance allele, if configured.
cas9_allele
property
Gene or None: The Cas9 source allele, if different from drive_allele.
fitness_patch
Return declarative fitness patch for homing drive scaling configs.
Source code in src/natal/presets/homing.py
gamete_modifier
Implement homing in heterozygous parents, germline resistance, and Cas9 deposition.
In heterozygotes (drive/wild-type), gametes are biased towards drive.
Source code in src/natal/presets/homing.py
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 | |
zygote_modifier
Implement embryo resistance.
Cleavage in the embryo (due to deposited Cas9 or zygotic expression) converts wild-type alleles into resistance alleles.
Source code in src/natal/presets/homing.py
336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 | |
ToxinAntidoteDrive
ToxinAntidoteDrive(name: str, drive_allele: AlleleSpecifier, target_allele: AlleleSpecifier, disrupted_allele: AlleleSpecifier, conversion_rate: SexSpecificRates = 0.8, embryo_disruption_rate: SexSpecificRates = 0.0, viability_scaling: ViabilityScalingConfig = 1.0, fecundity_scaling: FecundityScalingConfig = 1.0, sexual_selection_scaling: Optional[SexualSelectionScalingConfig] = None, zygote_viability_scaling: ZygoteViabilityScalingConfig = 0.0, viability_mode: AlleleScalingMode = 'recessive', fecundity_mode: AlleleScalingMode = 'recessive', sexual_selection_mode: AlleleScalingMode = 'recessive', zygote_viability_mode: AlleleScalingMode = 'recessive', cas9_deposition_glab: Optional[str] = None, species: Optional[Any] = None, priority: int = 0, use_paternal_deposition: bool = False)
Bases: GeneticPreset
Toxin-Antidote gene drive (e.g., TARE, TADE).
This preset implements a toxin-antidote gene drive system where a "drive" allele disrupts a "target" allele into a "disrupted" version. The "disrupted" allele typically carries a high fitness cost (the toxin effect), while the "drive" allele itself often provides a functional rescue (the antidote).
Key features include germline disruption, embryo disruption, and configurable fitness costs for the disrupted allele.
In a typical TARE (Toxin-Antidote Recessive Embryo lethality) configuration, the disrupted allele is set to be recessive lethal (viability_scaling=0.0, viability_mode="recessive").
Attributes:
| Name | Type | Description |
|---|---|---|
conversion_rate |
Tuple[float, float]
|
Female/male germline disruption rates. |
embryo_disruption_rate |
Tuple[float, float]
|
Female/male embryo disruption rates. |
viability_mode |
AlleleScalingMode
|
Scaling mode for viability effects. |
fecundity_mode |
AlleleScalingMode
|
Scaling mode for fecundity effects. |
Initialize a toxin-antidote gene drive.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Name of the gene drive. |
required |
drive_allele
|
AlleleSpecifier
|
The allele carrying the antidote and disruption machinery. |
required |
target_allele
|
AlleleSpecifier
|
The wild-type allele targeted for disruption. |
required |
disrupted_allele
|
AlleleSpecifier
|
The resulting non-functional/disrupted allele. |
required |
conversion_rate
|
SexSpecificRates
|
Probability of target disruption in the germline. |
0.8
|
embryo_disruption_rate
|
SexSpecificRates
|
Probability of target disruption in embryos. |
0.0
|
viability_scaling
|
ViabilityScalingConfig
|
Fitness multiplier for the disrupted allele. |
1.0
|
fecundity_scaling
|
FecundityScalingConfig
|
Fecundity multiplier for the disrupted allele. |
1.0
|
sexual_selection_scaling
|
Optional[SexualSelectionScalingConfig]
|
Optional sexual-selection multiplier for the disrupted allele.
Supports a scalar copy-number effect or a tuple
|
None
|
zygote_viability_scaling
|
ZygoteViabilityScalingConfig
|
Zygote viability scaling configuration for the disrupted allele. Applied during reproduction stage before survival; represents probability that a zygote survives to become an individual. |
0.0
|
viability_mode
|
AlleleScalingMode
|
Scaling mode for viability (default "recessive"). |
'recessive'
|
fecundity_mode
|
AlleleScalingMode
|
Scaling mode for fecundity (default "recessive"). |
'recessive'
|
sexual_selection_mode
|
AlleleScalingMode
|
Scaling mode for scalar sexual-selection values.
Ignored when |
'recessive'
|
zygote_viability_mode
|
AlleleScalingMode
|
Scaling mode for zygote viability (default "multiplicative"). |
'recessive'
|
cas9_deposition_glab
|
Optional[str]
|
Gamete label for Cas9 deposition tracking. |
None
|
species
|
Optional[Any]
|
Optional species to bind at construction. |
None
|
use_paternal_deposition
|
bool
|
Whether to enable paternal Cas9 deposition. |
False
|
Source code in src/natal/presets/toxin_antidote.py
drive_allele
property
Gene: The drive allele carrying the toxin-antidote construct.
disrupted_allele
property
Gene: The disrupted (cleaved) allele produced by target disruption.
fitness_patch
Return declarative fitness patch for the disrupted allele.
Source code in src/natal/presets/toxin_antidote.py
gamete_modifier
Implement target disruption in the germline of drive carriers.
Source code in src/natal/presets/toxin_antidote.py
zygote_modifier
Implement target disruption in embryos.
Source code in src/natal/presets/toxin_antidote.py
apply_preset_to_population
Apply a genetic preset to a population by registering its modifiers and fitness effects.
This function handles the mechanical application of a preset to a population, including: 1. Species binding and validation 2. Registration of gamete modifiers 3. Registration of zygote modifiers 4. Application of fitness patches
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
population
|
BasePopulation[Any]
|
The BasePopulation instance to modify. |
required |
preset
|
GeneticPreset
|
The GeneticPreset instance to apply. |
required |
Note
This is typically called through the modern API:
population.apply_preset(preset)
The legacy API preset.apply(population) is deprecated but still supported.
Raises:
| Type | Description |
|---|---|
ValueError
|
If preset is bound to a different species than the population |
RuntimeError
|
If preset has no bound species |
Source code in src/natal/presets/_base.py
apply_preset_fitness_patch
Apply a declarative preset fitness patch to population config tensors.
Patch schema (all keys optional): - viability: Dict[genotype_selector, _ViabilityScalingConfig] - fecundity: Dict[genotype_selector, _FecundityScalingConfig] - sexual_selection: Dict[female_selector, Union[float, Dict[male_selector, float]]]
Source code in src/natal/fitness/_patch.py
358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 | |