Model - Snailz Docs

Skip to content

# Model

Key randomization functions in model.

## `assay_performed(params)`

Number of days between collection and assay being performed.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`params` | `AssayParams` | assay parameters | required

Returns:

Type | Description
--- | ---
`timedelta` | Number of days.

Source code in `src/snailz/model.py`

    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    def assay_performed(params: AssayParams) -> timedelta:
        """Number of days between collection and assay being performed.

        Parameters:
            params: assay parameters

        Returns:
            Number of days.
        """
        return timedelta(days=random.randint(0, params.delay))

## `assay_reading(params, specimen, treatment, performed)`

Calculate individual assay reading.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`params` | `AssayParams` | assay parameters | required
`specimen` | `object` | specimen being assayed | required
`treatment` | `str` | "C" for control or "S" for sample | required
`performed` | `date` | date assay performed | required

Returns:

Type | Description
--- | ---
`float` | Reading value.

Source code in `src/snailz/model.py`

    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    def assay_reading(
        params: AssayParams, specimen: object, treatment: str, performed: date
    ) -> float:
        """
        Calculate individual assay reading.

        Parameters:
            params: assay parameters
            specimen: specimen being assayed
            treatment: "C" for control or "S" for sample
            performed: date assay performed

        Returns:
            Reading value.
        """
        degradation = max(
            0.0, 1.0 - (params.degrade * (performed - specimen.collected).days)
        )
        if treatment == "C":
            base_value = 0.0
            stdev = params.rel_stdev
        elif specimen.is_mutant:
            base_value = params.mutant * degradation
            stdev = base_value * params.rel_stdev
        else:
            base_value = params.baseline * degradation
            stdev = base_value * params.rel_stdev

        return abs(random.gauss(base_value, stdev))

## `assay_specimens(params, specimens)`

Generate list of specimens to be assayed.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`params` | `AssayParams` | assay parameters | required
`specimens` | `BaseModel` | all available specimens | required

Returns:

Type | Description
--- | ---
`list` | List of specimens (possibly containing duplicates).

Source code in `src/snailz/model.py`

    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    def assay_specimens(params: AssayParams, specimens: BaseModel) -> list:
        """Generate list of specimens to be assayed.

        Parameters:
            params: assay parameters
            specimens: all available specimens

        Returns:
            List of specimens (possibly containing duplicates).
        """
        extra = random.choices(
            specimens.items,
            k=math.floor(params.p_duplicate_assay * len(specimens.items)),
        )
        subjects = specimens.items + extra
        random.shuffle(subjects)
        return subjects

## `days_to_next_survey(params)`

Choose the number of days between surveys.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`params` | `SurveyParams` | specimen generation parameters | required

Returns:

Type | Description
--- | ---
`timedelta` | Days to the next survey.

Source code in `src/snailz/model.py`

    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    def days_to_next_survey(params: SurveyParams) -> timedelta:
        """Choose the number of days between surveys.

        Parameters:
            params: specimen generation parameters

        Returns:
            Days to the next survey.
        """
        return timedelta(days=random.randint(1, params.max_interval))

## `image_noise(params, img, img_size)`

Add noise effects to image.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`img` | `Image` | pristine image | required

Returns:

Type | Description
--- | ---
`Image` | Distorted image.

Source code in `src/snailz/model.py`

    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    def image_noise(params: AssayParams, img: PilImage, img_size: int) -> PilImage:
        """Add noise effects to image.

        Parameters:
            img: pristine image

        Returns:
            Distorted image.
        """
        # Add uniform noise (not provided by pillow).
        for x in range(img_size):
            for y in range(img_size):
                noise = random.randint(-params.image_noise, params.image_noise)
                old_val = img.getpixel((x, y))
                assert isinstance(old_val, int)  # for type checking
                val = max(utils.BLACK, min(utils.WHITE, old_val + noise))
                img.putpixel((x, y), val)

        # Blur.
        img = img.filter(ImageFilter.GaussianBlur(BLUR_RADIUS))

        return img

## `machine_brightness(params)`

Choose relative brightness of this machine's camera.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`params` | `MachineParams` | machine parameters | required

Returns:

Type | Description
--- | ---
`float` | Brightness level in that range.

Source code in `src/snailz/model.py`

    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    def machine_brightness(params: MachineParams) -> float:
        """Choose relative brightness of this machine's camera.

        Parameters:
            params: machine parameters

        Returns:
            Brightness level in that range.
        """

        return random.uniform(1.0 - params.variation, 1.0 + params.variation)

## `mutation_loci(params)`

Make a list of mutable loci positions.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`params` | `SpecimenParams` | specimen generation parameters | required

Returns:

Type | Description
--- | ---
`list[int]` | Randomly selected positions that can be mutated.

Source code in `src/snailz/model.py`

    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    def mutation_loci(params: SpecimenParams) -> list[int]:
        """Make a list of mutable loci positions.

        Parameters:
            params: specimen generation parameters

        Returns:
            Randomly selected positions that can be mutated.
        """
        return list(
            sorted(random.sample(list(range(params.genome_length)), params.max_mutations))
        )

## `specimen_adjust_mass(survey, max_pollution, specimen)`

Adjust mass of specimen depending on pollution levels.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`survey` | `Survey` | survey that specimen is taken from | required
`max_pollution` | `float` | maximum pollution level seen across all surveys | required
`specimen` | `Specimen` | specimen to adjust | required

Source code in `src/snailz/model.py`

    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    def specimen_adjust_mass(
        survey: Survey, max_pollution: float, specimen: Specimen
    ) -> float:
        """Adjust mass of specimen depending on pollution levels.

        Parameters:
            survey: survey that specimen is taken from
            max_pollution: maximum pollution level seen across all surveys
            specimen: specimen to adjust
        """
        pollution = survey.cells[specimen.location.x, specimen.location.y]
        if (pollution is None) or (pollution == 0.0):
            return specimen.mass
        scaling = 1.0 + 2.0 * utils.sigmoid(pollution / max_pollution)
        return specimen.mass * scaling

## `specimen_collection_date(survey)`

Choose a collection date for a specimen.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`survey` | `BaseModel` | survey that specimen belongs to | required

Returns:

Type | Description
--- | ---
`date` | Date specimen was collected.

Source code in `src/snailz/model.py`

    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    def specimen_collection_date(survey: BaseModel) -> date:
        """Choose a collection date for a specimen.

        Parameters:
            survey: survey that specimen belongs to

        Returns:
            Date specimen was collected.
        """
        return date.fromordinal(
            random.randint(survey.start_date.toordinal(), survey.end_date.toordinal())
        )

## `specimen_genome(params, specimens)`

Generate genome for a particular specimen.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`specimens` | `BaseModel` | all specimens | required

Returns:

Type | Description
--- | ---
`tuple[int, str]` | Random genome produced by mutating reference genome.

Source code in `src/snailz/model.py`

    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    def specimen_genome(params: SpecimenParams, specimens: BaseModel) -> tuple[int, str]:
        """Generate genome for a particular specimen.

        Parameters:
            specimens: all specimens

        Returns:
            Random genome produced by mutating reference genome.
        """
        num_species = len(specimens.references)
        species = utils.choose_one(list(range(num_species)), weights=params.prob_species)
        genome = list(specimens.references[species])
        max_mutations = random.randint(1, len(specimens.loci[species]))
        locations = random.sample(specimens.loci[species], max_mutations)
        for loc in locations:
            genome[loc] = utils.choose_one(utils.BASES)
        result = "".join(genome)
        return species, result

## `specimen_initial_mass(params, species, collected, is_mutant)`

Generate mass of a specimen.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`params` | `SpecimenParams` | specimen generation parameters | required
`collected` | `date` | specimen collection date | required
`is_mutant` | `bool` | whether this specimen is a mutant | required

Returns:

Type | Description
--- | ---
`float` | Random mass.

Source code in `src/snailz/model.py`

    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    def specimen_initial_mass(
        params: SpecimenParams,
        species: int,
        collected: date,
        is_mutant: bool,
    ) -> float:
        """Generate mass of a specimen.

        Parameters:
            params: specimen generation parameters
            collected: specimen collection date
            is_mutant: whether this specimen is a mutant

        Returns:
            Random mass.
        """

        # Initial mass
        mass_scale = params.mut_mass_scale if is_mutant else 1.0
        mean_mass = mass_scale * params.mean_masses[species]
        mass = abs(random.gauss(mean_mass, mean_mass * params.mass_rel_stdev))

        # Growth effects
        days_passed = (collected - params.start_date).days
        mass += params.daily_growth * days_passed * mass

        return mass

## `specimens_num_per_survey(params, survey)`

Number of specimens per survey.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`params` | `SpecimenParams` | specimen generation parameters | required
`survey` | `Survey` | particular survey | required

Returns:

Type | Description
--- | ---
`int` | Number of specimens.

Source code in `src/snailz/model.py`

    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    def specimens_num_per_survey(params: SpecimenParams, survey: Survey) -> int:
        """Number of specimens per survey.

        Parameters:
            params: specimen generation parameters
            survey: particular survey

        Returns:
            Number of specimens.
        """
        return random.randint(survey.size // 2, (3 * survey.size) // 2)

## `specimens_place(survey, specimens)`

Place specimens in grid.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`survey` | `Survey` | survey from which specimens taken | required
`specimens` | `list[Specimen]` | to place | required

Source code in `src/snailz/model.py`

    246
    247
    248
    249
    250
    251
    252
    253
    def specimens_place(survey: Survey, specimens: list[Specimen]) -> None:
        """Place specimens in grid.

        Parameters:
            survey: survey from which specimens taken
            specimens: to place
        """
        anneal(survey.size, specimens)

## `specimen_reference_genome(params)`

Make a random reference genome.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`params` | `SpecimenParams` | SpecimenParams with length attribute | required

Returns:

Type | Description
--- | ---
`str` | A randomly generated genome string of the specified length

Source code in `src/snailz/model.py`

    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    def specimen_reference_genome(params: SpecimenParams) -> str:
        """Make a random reference genome.

        Parameters:
            params: SpecimenParams with length attribute

        Returns:
            A randomly generated genome string of the specified length
        """
        return "".join(random.choices(utils.BASES, k=params.genome_length))

## `survey_initialize_grid(size)`

Initialize values in survey grid.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`size` | `int` | size of survey grid | required

Returns:

Type | Description
--- | ---
`Grid[int]` | Initialized grid.

Source code in `src/snailz/model.py`

    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    def survey_initialize_grid(size: int) -> Grid[int]:
        """Initialize values in survey grid.

        Parameters:
            size: size of survey grid

        Returns:
            Initialized grid.
        """
        cells = Grid(width=size, height=size, default=0)
        size_1 = size - 1
        center = size // 2
        moves = [[-1, 0], [1, 0], [0, -1], [0, 1]]
        x, y = center, center
        cells[x, y] = 1
        while (x != 0) and (x != size_1) and (y != 0) and (y != size_1):
            cells[x, y] += 1
            m = random.choice(moves)
            x += m[0]
            y += m[1]
        return cells