Data model

The unit of data in torchcell is the experiment record: one genotype, grown in one environment, observed to have one phenotype, paired with the reference it is measured against and the publication it came from. The models live in torchcell/datamodels/schema.py. They are pydantic models built on ModelStrict (torchcell/datamodels/pydant.py), which forbids extra fields and freezes instances, so a record either validates completely or is rejected.

An interactive view of the class hierarchy, generated from the live models at build time, is the ontology explorer.

The experiment record

Experiment
  experiment_type   str          key into EXPERIMENT_TYPE_MAP ("fitness", "gene interaction", ...)
  dataset_name      str          the loader class that produced it, e.g. "SmfCostanzo2016Dataset"
  genotype          Genotype     what was changed in the strain
  environment       Environment  what the strain was grown in
  phenotype         Phenotype    what was measured

ExperimentReference
  experiment_reference_type  str
  dataset_name               str
  genome_reference           ReferenceGenome   species, strain, ploidy
  environment_reference      Environment
  phenotype_reference        Phenotype         the reference value (e.g. wild-type fitness 1.0)

Publication
  pubmed_id, pubmed_url, doi, doi_url           at least one id and one URL are required

Each experiment type pairs a subclass of Experiment with a subclass of ExperimentReference that narrows phenotype to one phenotype class, for example FitnessExperiment and FitnessExperimentReference with FitnessPhenotype. Two dictionaries at the end of schema.py, EXPERIMENT_TYPE_MAP and EXPERIMENT_REFERENCE_TYPE_MAP, map the experiment_type string to the class; every reader that deserializes a record (the dataset loaders, Neo4jQueryRaw, the converters) dispatches through them.

Genotype

Genotype.perturbations is a list of gene perturbations, sorted on validation by (systematic_gene_name, perturbation_type, perturbed_gene_name) so that equal genotypes serialize identically. Every perturbation extends GenePerturbation:

  • systematic_gene_name: validated against the S288C naming patterns (coding genes such as YAL001C, mitochondrial Q0010-style names, noncoding YNC... genes).

  • perturbed_gene_name: the allele or common name, such as tfc3_damp.

  • provenance: "engineered" (made in the lab) or "natural" (found in an isolate).

The concrete perturbation classes are organized by what they change relative to the reference genome: presence or absence of a gene (deletions, marker deletions, gene additions, natural gene absence and presence), sequence-level alleles (DAmP, temperature-sensitive, suppressor and sequence-variant alleles), copy number (natural CNVs and engineered copy number), and expression modulation (CRISPRa and CRISPRi). Each names its mechanism with a Sequence Ontology term (mechanism_so_id, mechanism_so_name).

Environment

Environment holds a media (a Media resolved into typed components, with name, state and is_synthetic), an optional temperature, a list of environment perturbations (added small molecules, physical factors, biologic agents), an aerobicity, and optional duration_hours and duration_generations.

Phenotype

Phenotype is the base class of every measured label. It carries three fields that describe the label rather than its value:

  • graph_level: where the label sits on a gene graph. Validated against edge, node, hyperedge, subgraph, global, metabolism and gene ontology.

  • label_name: the name of the field that holds the value. A validator checks that the concrete class declares that field.

  • label_statistic_name: the name of the field holding its uncertainty or confidence statistic, or None.

Numeric phenotypes record their uncertainty with its kind: FitnessPhenotype, for example, stores the source-reported number in fitness_uncertainty, names it with fitness_uncertainty_type (an UncertaintyType: sample_sd, standard_error, bootstrap_se, variance, ci95), records the replicate design in n_samples and sample_unit, and derives the standard error fitness_se from those when it is not supplied (a bootstrap SE is used as is; a sample SD is divided by the square root of n_samples). A value the source does not report is declared as a typed ProvenanceGap in provenance_gaps, and the field itself must then be None.

Phenotype classes

The defaults below were read from each class’s model_fields in schema.py. graph_level is a default, and a loader may set another value (the digenic-interaction datasets store GeneInteractionPhenotype records at edge, the trigenic ones at hyperedge).

Phenotype class

Value field (label_name)

Value type

graph_level

label_statistic_name

CalMorphPhenotype

calmorph

dict[str, float]

global

calmorph_coefficient_of_variation

EnvironmentResponsePhenotype

environment_response

float | None

global

environment_response_se

FitnessPhenotype

fitness

float

global

fitness_se

GeneEssentialityPhenotype

is_essential

bool

node

None

GeneInteractionPhenotype

gene_interaction

float

hyperedge

gene_interaction_p_value

MetabolitePhenotype

metabolite_level

dict[str, float]

metabolism

metabolite_level_se

MicroarrayExpressionPhenotype

expression_log2_ratio

dict[str, float]

node

expression_log2_ratio_se

ProteinAbundancePhenotype

protein_abundance

dict[str, float]

node

protein_abundance_se

PseudobulkExpressionPhenotype

expression_log2_ratio

dict[str, float]

node

dispersion

RNASeqExpressionPhenotype

expression_tpm

dict[str, float]

node

None

SyntheticLethalityPhenotype

is_synthetic_lethal

bool

edge

synthetic_lethality_statistic_score

VisualScorePhenotype

visual_score

float

global

None

schema.py also defines SyntheticRescuePhenotype (is_synthetic_rescue, edge), and EXPERIMENT_TYPE_MAP has a fourteenth entry, segregant_growth, whose experiment pairs a SegregantGenotype (a haplotype mosaic of two parent assemblies) with an EnvironmentResponsePhenotype.

Verification levels

Built datasets are checked record by record against five ordered levels, defined as Level in torchcell/verification/report.py and implemented as reusable checks in torchcell/verification/levels.py:

Level

Name

Checks

L0

structural

every record instantiates its schema model

L1

completeness

record counts, known keys and contiguity against an oracle

L2

value fidelity

cross-method agreement, types, ranges, no NaN

L3

semantic

units and conventions (fitness as mutant over wild type; log2 of sample over reference)

L4

cross-source consistency

entities that two sources share agree

Each check returns a LevelResult; a per-dataset verifier (for example torchcell/verification/morphology.py) assembles them into a VerificationReport together with a Provenance record of the source.

Provenance of hand-entered values

A constant that a loader cannot read from a data column (a replicate count, the kind of an uncertainty, a strain background) is stored as a SourcedValue (torchcell/verification/sourced.py): the value, a Provenance naming the source file by citation key and sha256, and a verbatim quote from that file that justifies it.