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

ORG78 Finish event wiring in SIPNET #25

Merged
merged 12 commits into from
Feb 6, 2025
121 changes: 89 additions & 32 deletions sipnet.c
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,7 @@ static double *outputPtrs[MAX_DATA_TYPES]; // pointers to different possible out

#if EVENT_HANDLER
static EventNode **events;
static EventNode *locEvent; // current location event list
#endif

/* Read climate file into linked lists,
Expand Down Expand Up @@ -2275,54 +2276,103 @@ void updateTrackers(double oldSoilWater) {
// mean of soil wetness at start of time step at soil wetness at end of time step - assume linear
}

// This should be in events.h/c, but with all the global state defined in this file,
// let's leave it here for now. Maybe someday we will factor that out.
//
// Process events for current location/year/day
void processEvents() {
#if EVENT_HANDLER
// If locEvent starts off NULL, this function will just fall through, as it should.
const int year = climate->year;
const int day = climate->day;

// The events file has been tested on read, so we know this event list should be in chrono
// order. However, we need to check to make sure the current event is not in the past, as
// that would indicate an event that did not have a corresponding climate file record.
while (locEvent != NULL && locEvent->year <= year && locEvent->day <= day) {
if (locEvent->year < year || locEvent->day < day) {
printf("Agronomic event found for loc: %d year: %d day: %d that does not have a corresponding record in the climate file\n", locEvent->year, locEvent->year, locEvent->day);
exit(1);
}
switch (locEvent->type) {
// Implementation TBD, as we enable the various event types
case IRRIGATION:
// TBD
printf("Irrigation events not yet implemented\n");
break;
case PLANTING:
// TBD
printf("Planting events not yet implemented\n");
break;
case HARVEST:
// TBD
printf("Harvest events not yet implemented\n");
break;
case TILLAGE:
// TBD
printf("Tillage events not yet implemented\n");
break;
case FERTILIZATION:
// TBD
printf("Fertilization events not yet implemented\n");
break;
default:
printf("Unknown event type (%d) in processEvents()\n", locEvent->type);
exit(1);
Copy link
Member

Choose a reason for hiding this comment

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

do we really want to exit and not just print error message, and continue?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's a great question, I was going with what seems to be the standard for SIPNET - that is, exit on errors that look like mistakes in inputs. Any thoughts on this @dlebauer @infotroph ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Decided via discussion: using different error codes, starting here

}

// !!! main runner function !!!
locEvent = locEvent->nextEvent;
}
#endif
}


// !!! main runner function !!!

// calculate all fluxes and update state for this time step
// we calculate all fluxes before updating state in case flux calculations depend on the old state
void updateState() {
double npp; // net primary productivity, g C * m^-2 ground area * day^-1
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Everything in this function above the #if EVENT_HANDLER is just indent formatting changes

double oldSoilWater; // how much soil water was there before we updated it? Used in trackers
int err;
oldSoilWater = envi.soilWater;

calculateFluxes();

// update the stocks, with fluxes adjusted for length of time step:
envi.plantWoodC += (fluxes.photosynthesis + fluxes.woodCreation - fluxes.leafCreation - fluxes.woodLitter
- fluxes.rVeg-fluxes.coarseRootCreation-fluxes.fineRootCreation)* climate->length;
envi.plantLeafC += (fluxes.leafCreation - fluxes.leafLitter) * climate->length;

double npp; // net primary productivity, g C * m^-2 ground area * day^-1
double oldSoilWater; // how much soil water was there before we updated it? Used in trackers
int err;
oldSoilWater = envi.soilWater;

calculateFluxes();

// update the stocks, with fluxes adjusted for length of time step:
envi.plantWoodC += (fluxes.photosynthesis + fluxes.woodCreation - fluxes.leafCreation - fluxes.woodLitter
- fluxes.rVeg-fluxes.coarseRootCreation-fluxes.fineRootCreation)* climate->length;
envi.plantLeafC += (fluxes.leafCreation - fluxes.leafLitter) * climate->length;

soilDegradation(); // This updates all the soil functions
soilDegradation(); // This updates all the soil functions

#if MODEL_WATER // water pool updating happens here:

#if LITTER_WATER // (2 soil water layers; litter water will only be on if complex water is also on)
envi.litterWater += (fluxes.rain + fluxes.snowMelt - fluxes.immedEvap - fluxes.fastFlow
- fluxes.evaporation - fluxes.topDrainage) * climate->length;
envi.soilWater += (fluxes.topDrainage - fluxes.transpiration - fluxes.bottomDrainage)
* climate->length;

#if MODEL_WATER // water pool updating happens here:
#else // LITTER_WATER = 0 (only one soil water layer)
// note: some of these fluxes will always be 0 if complex water is off
envi.soilWater += (fluxes.rain + fluxes.snowMelt - fluxes.immedEvap - fluxes.fastFlow
- fluxes.evaporation - fluxes.transpiration - fluxes.bottomDrainage) * climate->length;
#endif // LITTER_WATER

#if LITTER_WATER // (2 soil water layers; litter water will only be on if complex water is also on)
envi.litterWater += (fluxes.rain + fluxes.snowMelt - fluxes.immedEvap - fluxes.fastFlow
- fluxes.evaporation - fluxes.topDrainage) * climate->length;
envi.soilWater += (fluxes.topDrainage - fluxes.transpiration - fluxes.bottomDrainage)
* climate->length;
// if COMPLEX_WATER = 0 or SNOW = 0, some or all of these fluxes will always be 0
envi.snow += (fluxes.snowFall - fluxes.snowMelt - fluxes.sublimation) * climate->length;

#else // LITTER_WATER = 0 (only one soil water layer)
// note: some of these fluxes will always be 0 if complex water is off
envi.soilWater += (fluxes.rain + fluxes.snowMelt - fluxes.immedEvap - fluxes.fastFlow
- fluxes.evaporation - fluxes.transpiration - fluxes.bottomDrainage) * climate->length;
#endif // LITTER_WATER

// if COMPLEX_WATER = 0 or SNOW = 0, some or all of these fluxes will always be 0
envi.snow += (fluxes.snowFall - fluxes.snowMelt - fluxes.sublimation) * climate->length;

#endif // MODEL_WATER
#endif // MODEL_WATER

ensureNonNegativeStocks();

#if EVENT_HANDLER
// Process events for this location/year/day, AFTER updates are made to fluxes and state
// variables above. Events are (currently, Jan 25) handled as instantaneous deltas to
// relevant state (envi and fluxes fields),
processEvents();
#endif

npp = fluxes.photosynthesis - fluxes.rVeg-fluxes.rCoarseRoot-fluxes.rFineRoot;

Expand All @@ -2343,7 +2393,6 @@ void updateState() {
}

updateTrackers(oldSoilWater);

}


Expand Down Expand Up @@ -2485,7 +2534,9 @@ void setupModel(SpatialParams *spatialParams, int loc) {

// Setup events at given location
void setupEvents(int currLoc) {
// Implementation TBD
#if EVENT_HANDLER
Copy link
Member

Choose a reason for hiding this comment

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

probably should be consistent and have the EVENT_HANDLER around the function as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch!

locEvent = events[currLoc];
Copy link
Member

Choose a reason for hiding this comment

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

indenting looks off here

Copy link
Member

Choose a reason for hiding this comment

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

Formatting looks inconsistent throughout - what about applying a formatter in a separate PR?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I cannot get CLion on Mac to listen to its own format settings, thus some wonky things sneak in. I def. vote for adding a formatter on checkin/push/merge or some such, but I'll fix this one here for now. Thanks for pointing that out!

#endif
}


Expand Down Expand Up @@ -2554,6 +2605,12 @@ void runModelNoOut(double **outArray, int numDataTypes, int dataTypeIndices[], S

setupModel(spatialParams, loc);

#if EVENT_HANDLER
// Implementation TBD
Copy link
Member

Choose a reason for hiding this comment

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

indenting looks off here

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ditto

printf("Event handler not yet implemented for running model with no output\n");
exit(1);
#endif

// loop through every step of the model:
while (climate != NULL) {
updateState();
Expand Down