-
Notifications
You must be signed in to change notification settings - Fork 2
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
Conversation
… mass spent on the event.
…sholding to trophic flow of mass to reproductive mass.
@TaranRallings Is this ready for review now? |
There was a problem hiding this 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!
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 |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
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 |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this 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 | ||
) |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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] | ||
) |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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:
and cohort != consumer_cohort | |
and cohort is not consumer_cohort |
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), | ||
}, |
There was a problem hiding this comment.
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:
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.
There was a problem hiding this comment.
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.
"basal": (4.19 * 10**10, 0.69), | ||
"field": (9.08 * 10**11, 0.7), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"basal": (4.19 * 10**10, 0.69), | |
"field": (9.08 * 10**11, 0.7), | |
"basal": (4.19e10, 0.69), | |
"field": (9.08e11, 0.7), |
"basal": (4.19 * 10**10, 0.69), | ||
"field": (1.49 * 10**11, 0.88), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"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. |
There was a problem hiding this comment.
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).
DISPERSAL_MASS_THRESHOLD: float = 0.75 # Toy value for thesholding dispersal. | |
DISPERSAL_MASS_THRESHOLD: float = 0.75 | |
"""Toy value for thesholding dispersal.""" |
There was a problem hiding this comment.
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.
…dling in cohort foraging
Codecov ReportAttention:
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. |
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
Key checklist
pre-commit
checks:$ pre-commit run -a
$ poetry run pytest
Further checks