Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/animal module - Energy to Mass Conversion #338

Merged
merged 14 commits into from
Nov 16, 2023

Conversation

TaranRallings
Copy link
Collaborator

@TaranRallings TaranRallings commented Oct 23, 2023

Description

I am aiming to align the animal module with Madingley before the winter break. To that end, I have converted the animal module to run on wet biomass as they do and implemented some of their parametrizations.

This is a long PR but it is mostly small changes of language (replacing energy with mass), some flow re-routing, and updating the tests. One of the larger changes is to reproduction. The model now tracks core body mass and reproductive body mass as different pools and draws the material of reproductive events from the reproductive mass pool specifically. This reproductive system will be expanded when I implement semelparity.

Fixes # (issue)

Type of change

  • New feature (non-breaking change which adds functionality)
  • Optimization (back-end change that speeds up the code)
  • Bug fix (non-breaking change which fixes an issue)

Key checklist

  • Make sure you've run the pre-commit checks: $ pre-commit run -a
  • [x All tests pass: $ poetry run pytest

Further checks

  • Code is commented, particularly in hard-to-understand areas
  • Tests added that prove fix is effective or that feature works

@alexdewar
Copy link
Collaborator

@TaranRallings Is this ready for review now?

Copy link
Collaborator

@dalonsoa dalonsoa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've left a couple of comments worth to look at, but otherwise it looks good!

virtual_rainforest/models/animals/scaling_functions.py Outdated Show resolved Hide resolved
Comment on lines +92 to +94
Es = 3.7 * 10 ** (-2) # energy to mass conversion constant (g/kJ)
sig = 0.5 # proportion of time-step with temp in active range (toy)
Ea = 0.69 # aggregate activation energy of metabolic reactions
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this conform with the decided approach of including constants? If not, the standardised approach should be used.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does not! I am doing a full constants rework immediately after this PR to avoid the PR sprawling out into the whole animal module.

Comment on lines 280 to 297
try:
if self.functional_group.diet == DietType.HERBIVORE and plant_list:
food_choice = choice(plant_list)
mass_consumed = self.eat(food_choice, excrement_pool)
elif self.functional_group.diet == DietType.CARNIVORE and animal_list:
food_choice = choice(animal_list)
mass_consumed = self.eat(food_choice, carcass_pool)
else:
LOGGER.info("No food available.")
food_choice = None # No food available

except ValueError as e:
if str(e) == "Individuals cannot be 0.":
LOGGER.warning("Tried to eat with zero individuals in the cohort.")
mass_consumed = 0
food_choice = None # No food was actually consumed
else:
raise
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not convinced by this approach. Using the text of a exception to decide what to do seems a bit hacky to me.

My personal preference would be to check if individuals are zero in the appropriate function and then return the correct value for food_choice and mass_consumed. If that is deemed to complicated to implement, then create a custom exception, eg. EatingZeroIndividualsCohortError, catch that (and only that) to act accordingly, leaving any other exception unhandled.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I see what you mean! I'll get that worked out.

Copy link
Collaborator

@alexdewar alexdewar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I finally got round to finishing the review I started weeks ago 😆.

I've made some minor suggestions, but nothing that should be a blocker.

number_offspring = int(
(parent_cohort.reproductive_mass * parent_cohort.individuals)
/ parent_cohort.functional_group.birth_mass
)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess you're rounding down on purpose here?

Copy link
Collaborator Author

@TaranRallings TaranRallings Nov 15, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, there must be reproductive mass enough to create a full offspring.

self.mass: float = data["layer_leaf_mass"].sum(dim="layers").to_numpy()[cell_id]
self.mass_current: float = (
data["layer_leaf_mass"].sum(dim="layers").to_numpy()[cell_id]
)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like you're calculating multiple sums then only using one of them. Could you just calculate the sum you need?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I remember correctly, and I may not be remembering correctly, this is some of @davidorme 's work from the plant module implementation. If he has no objections to the change then I am happy with it.

if (
consumer_cohort.individuals == 0
): # temporary while finalizing die_cohort placements
continue
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose you could print a warning here for now, so you don't forget to remove it.

if (
min_size <= cohort.mass_current <= max_size
and cohort.individuals != 0
and cohort != consumer_cohort
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you want to compare the identity of these objects:

Suggested change
and cohort != consumer_cohort
and cohort is not consumer_cohort

Comment on lines 33 to 40
MetabolicType.ENDOTHERMIC: {
"basal": (4.19 * 10**10, 0.69),
"field": (9.08 * 10**11, 0.7),
},
MetabolicType.ECTOTHERMIC: {
"basal": (4.19 * 10**10, 0.69),
"field": (1.49 * 10**11, 0.88),
},
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can write scientific notation like this:

Suggested change
MetabolicType.ENDOTHERMIC: {
"basal": (4.19 * 10**10, 0.69),
"field": (9.08 * 10**11, 0.7),
},
MetabolicType.ECTOTHERMIC: {
"basal": (4.19 * 10**10, 0.69),
"field": (1.49 * 10**11, 0.88),
},
MetabolicType.ENDOTHERMIC: {
"basal": (4.19e10, 0.69),
"field": (9.08e11, 0.7),
},
MetabolicType.ECTOTHERMIC: {
"basal": (4.19e10, 0.69),
"field": (1.49e11, 0.88),
},

I am wondering whether these would be better as dataclasses rather than dicts.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am doing a constants rework immediately after this PR to avoid the PR sprawling out into the whole animal module.

Comment on lines 48 to 49
"basal": (4.19 * 10**10, 0.69),
"field": (9.08 * 10**11, 0.7),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"basal": (4.19 * 10**10, 0.69),
"field": (9.08 * 10**11, 0.7),
"basal": (4.19e10, 0.69),
"field": (9.08e11, 0.7),

Comment on lines 52 to 53
"basal": (4.19 * 10**10, 0.69),
"field": (1.49 * 10**11, 0.88),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"basal": (4.19 * 10**10, 0.69),
"field": (1.49 * 10**11, 0.88),
"basal": (4.19e10, 0.69),
"field": (1.49e11, 0.88),

1.0 # Toy value for threshold of trophic flow to reproductive mass.
)

DISPERSAL_MASS_THRESHOLD: float = 0.75 # Toy value for thesholding dispersal.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general it's better to describe constants with docstrings cf. comments. That way sphinx will be able to pick them up (as will your IDE).

Suggested change
DISPERSAL_MASS_THRESHOLD: float = 0.75 # Toy value for thesholding dispersal.
DISPERSAL_MASS_THRESHOLD: float = 0.75
"""Toy value for thesholding dispersal."""

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(repeating myself just so it's clear what I'm doing)
I'll be doing a full constants rework after this PR to bring everything in line, including docstrings.

@codecov-commenter
Copy link

Codecov Report

Attention: 10 lines in your changes are missing coverage. Please review.

Comparison is base (5b1a77d) 96.27% compared to head (f840129) 95.69%.

Files Patch % Lines
...irtual_rainforest/models/animals/animal_cohorts.py 81.39% 8 Missing ⚠️
...al_rainforest/models/animals/animal_communities.py 92.30% 1 Missing ⚠️
...ual_rainforest/models/animals/scaling_functions.py 94.44% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           develop     #338      +/-   ##
===========================================
- Coverage    96.27%   95.69%   -0.59%     
===========================================
  Files           51       51              
  Lines         2499     2534      +35     
===========================================
+ Hits          2406     2425      +19     
- Misses          93      109      +16     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@TaranRallings TaranRallings merged commit 8a586fe into develop Nov 16, 2023
22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants