[Econ] Preprocess Seed Costs#3112
Conversation
|
Hey Allister Looking at the inputs/outputs I have one question on the field size. The biophysical aggregate output is 400,000 m2 are planted with corn. However, in the inputs I only see corn_silage being planted twice in 2013/2017 and the field size is 10. I assume this field size is in hectares (please verify) which would mean a size of 100,000 m2 so the corn planted size should be 200,000 m2 Similar but different issues with alfalfa hay vs silage. Both are reported as 172,706 m2 by the code, but I only see alfafa_silage between planted twice so should have the same area as corn and alfalfa_hay should be zero. I might be misfollowing the input json so please correct me if this is the case |
I believe this is because there are two fields in this simulation. Both have a field size of 10 hectares. Regarding alfalfa silage and hay: both are expected to be planted (silage in field 1 and hay in field 2). I'll look into the values for their field size! |
Hey Allister You are correct. I missed that there were two fields. Corn grain is correct at 400,000 m2. As far as I can tell, alfalfa is also planted twice on each field so it should have the same total area - 200,000 m2 for each hay and silage. |
Thanks Braden, I have just updated the PR to fix this. Now the total area for both alfalfa (hay and silage) should be 200,000 m2. What went wrong:
Fix:
|
bradenlimb
left a comment
There was a problem hiding this comment.
Looks like it is working correctly to me! Thanks for fixing this!
ew3361zh
left a comment
There was a problem hiding this comment.
Need to spend some more time with the larger functions but thought this feedback would be a good start. Nice work, just multiple complex mappings and loops and exceptions all happening and want to make sure we're defensively guarding properly.
| ) | ||
| return values | ||
|
|
||
| def _scenario_names(self) -> list[str]: |
There was a problem hiding this comment.
| def _scenario_names(self) -> list[str]: | |
| def _get_scenario_names(self) -> list[str]: |
or _fetch_scenario_names()
| "cereal_rye_hay": "commodity_prices_wheat_seed_dollar_per_square_meter", | ||
| } | ||
|
|
||
| _HA_TO_M2: float = 10_000.0 |
There was a problem hiding this comment.
I believe this already exists in general_constants.py and if not, it should be added there.
| _HA_TO_M2: float = 10_000.0 | ||
|
|
||
| # Harvest operations that terminate a crop's life in the field. | ||
| _FINAL_HARVEST_OPS: frozenset[str] = frozenset({"harvest_kill", "kill_only"}) |
There was a problem hiding this comment.
This already exists in harvest_operations.py
| """Return (planting_date, kill_date) pairs for one crop schedule entry. | ||
|
|
||
| Pairs each planting event with its corresponding final harvest | ||
| (``harvest_kill`` or ``kill_only``). Intermediate ``harvest_only`` | ||
| operations are ignored. Pattern expansion (``pattern_repeat``, | ||
| ``planting_skip``, ``harvesting_skip``) is applied before pairing. |
There was a problem hiding this comment.
I think a clearer docstring function overview here would be helpful. Also update to numpy style with Returns section, Parameters, etc
| # Harvest operations that terminate a crop's life in the field. | ||
| _FINAL_HARVEST_OPS: frozenset[str] = frozenset({"harvest_kill", "kill_only"}) | ||
|
|
||
| def _growing_periods( |
There was a problem hiding this comment.
Add action verb to function name. gather e.g.
| raw_p_years: list[int] = list(schedule.get("planting_years") or []) | ||
| raw_p_days: list[int] = list(schedule.get("planting_days") or []) | ||
| raw_h_years: list[int] = list(schedule.get("harvest_years") or []) | ||
| raw_h_days: list[int] = list(schedule.get("harvest_days") or []) | ||
| raw_h_ops: list[str] = list(schedule.get("harvest_operations") or []) |
There was a problem hiding this comment.
I would use full words here for the p and h.
| p_years = Schedule.repeat_pattern(raw_p_years, planting_skip, pattern_repeat) | ||
| p_days = Utility.elongate_list(raw_p_days * (pattern_repeat + 1), len(p_years)) | ||
| h_years = Schedule.repeat_pattern(raw_h_years, harvesting_skip, pattern_repeat) | ||
| h_days = Utility.elongate_list(raw_h_days * (pattern_repeat + 1), len(h_years)) | ||
| h_ops = Utility.elongate_list(raw_h_ops * (pattern_repeat + 1), len(h_years)) |
| For each field, each crop's planting-to-kill periods are located within | ||
| the simulation window. The field's area in m² is spread evenly over | ||
| each growing period (``field_size_m² / period_duration``), then | ||
| accumulated into a per-simulation-day array keyed by seed commodity. |
| return periods | ||
|
|
||
| def _preprocess_seed_costs(self) -> dict[str, list[float]]: | ||
| """Build a daily time-series of responsible field area (m²) per seed key. |
There was a problem hiding this comment.
What is responsible field area?
| plant_date = None | ||
| return periods | ||
|
|
||
| def _preprocess_seed_costs(self) -> dict[str, list[float]]: |
There was a problem hiding this comment.
This function is a bit large and doing multiple things - what do you think about extracting some small helper functions?
Adds seed cost preprocessing to the Economics module, computing per-field seed costs by mapping crop specifications to commodity prices and converting field sizes to m².
Context
Issue(s) closed by this pull request: closes #3080.
What
preprocessing.pythat readsfield.crop_specificationandfield.field_sizefrom the simulation data, converts field size to m² (to match economics inputs), and maps crops grown to the corresponding commodity prices to compute seed costs per field."seed_cost": [0.0]to the fallback values dictionary infallback_values.py.printstatement inEEE_manager.pyfor the metadata load failure case (debugging aid).test_economics_preprocessing.pyfor the new seed cost preprocessing logic.test_economics.pyto account for the new seed cost data flow.Why
The Economics module needed to process seed costs as part of the farm economic analysis, but there was no preprocessing step to extract crop specification and field size data from the biophysical simulation outputs, convert units, and map crops to their seed cost commodity prices. Without this preprocessing, seed costs could not be included in the economic analysis.
How
The preprocessing step reads
field.crop_specification(which crops are grown on each field) andfield.field_size(the area of each field) from the simulation data. Field sizes are converted to m² to match the units expected by the economics inputs. Crops are mapped many-to-one to commodity price categories using the existing crop-to-commodity mapping. The resulting seed cost per field is computed and made available to the economic framework. When biophysical data is unavailable, the fallback value of0.0is used for seed cost.Test plan
test_economics_preprocessing.pycovering seed cost preprocessing with valid crop/field data, missing data fallback, and crop-to-commodity mapping.test_economics.pyto include seed cost in the economics data flow.Input Changes
field.crop_specificationandfield.field_sizedata from the biophysical simulation)Output Changes
Filter