diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 67807b319..aa027cdc8 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -2,6 +2,22 @@ ## Summary +<<<<<<< HEAD +- **Motivation**: (Why are you making this change?) +- **What**: (Short description of the change) + +## How to test + +Steps to reproduce and verify the change locally (commands, expected output): + +make +cd tests/smoke/ +../../sipnet -i sipnet.in + +## Related issues + +- Fixes or relates to: # +======= - **Motivation**: Why is this change needed? - **What**: Short description of the functional or documentation changes @@ -17,11 +33,21 @@ cd tests/smoke/ ../../sipnet -i sipnet.in ## Related issues - Fixes # (or "Relates to #N" if this is not a resolution of that ticket) +>>>>>>> ffdf0421f622091e702eadf686263ab7465ac6b9 ## Checklist - [ ] Tests added for new features - [ ] Documentation updated (if applicable) +<<<<<<< HEAD +- [ ] Update CHANGELOG.md +- [ ] Requested review from at least one other developer + + +## Additional notes + +If this PR is large or non-trivial, please summarize the design decisions and any alternatives considered. If you've already discussed this on Slack or an issue, link those conversations. +======= - [ ] `docs/CHANGELOG.md` updated with noteworthy changes - [ ] Code formatted with `clang-format` (run `git clang-format` if needed) - [ ] Requested review from at least one CODEOWNER @@ -32,3 +58,4 @@ cd tests/smoke/ ../../sipnet -i sipnet.in --- **Note**: See [CONTRIBUTING.md](../docs/CONTRIBUTING.md) for additional guidance. This repository uses automated formatting checks; if the pre-commit hook blocks your commit, run `git clang-format` to format staged changes. +>>>>>>> ffdf0421f622091e702eadf686263ab7465ac6b9 diff --git a/src/sipnet/events.c b/src/sipnet/events.c index 0595a4fd6..6ff6b2a93 100644 --- a/src/sipnet/events.c +++ b/src/sipnet/events.c @@ -292,7 +292,7 @@ void writeEventOut(EventNode *oneEvent, int numParams, ...) { va_end(args); } -void closeEventOutFile() { +void closeEventOutFile(void) { if (eventOutFile) { fclose(eventOutFile); } @@ -305,7 +305,7 @@ void initEvents(char *eventFile, int printHeader) { } } -void setupEvents() { gEvent = gEvents; } +void setupEvents(void) { gEvent = gEvents; } void resetEventFluxes(void) { fluxes.eventLeafC = 0.0; @@ -346,8 +346,11 @@ void processEvents(void) { // 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 (gEvent != NULL && gEvent->year <= climYear && gEvent->day <= climDay) { - if (gEvent->year < climYear || gEvent->day < climDay) { + while (gEvent != NULL && + (gEvent->year < climYear || + (gEvent->year == climYear && gEvent->day <= climDay))) { + if (gEvent->year < climYear || + (gEvent->year == climYear && gEvent->day < climDay)) { logError("Agronomic event found for year: %d day: %d that does not " "have a corresponding record in the climate file\n", gEvent->year, gEvent->day); diff --git a/src/sipnet/sipnet.c b/src/sipnet/sipnet.c index 490cfdba5..1c0c3c8c8 100644 --- a/src/sipnet/sipnet.c +++ b/src/sipnet/sipnet.c @@ -9,20 +9,20 @@ largely based on PnET */ +#include #include -#include #include -#include +#include #include "common/context.h" #include "common/exitCodes.h" #include "common/logging.h" #include "common/util.h" -#include "sipnet.h" #include "events.h" #include "outputItems.h" #include "runmean.h" +#include "sipnet.h" #include "state.h" #define C_WEIGHT 12.0 // molecular weight of carbon @@ -473,7 +473,7 @@ void outputState(FILE *out, int year, int day, double time) { } // de-allocate space used for climate linked list -void freeClimateList() { +void freeClimateList(void) { ClimateNode *curr, *prev; curr = firstClimate; @@ -1158,17 +1158,13 @@ double calcCNEffect(double kCN, double poolC, double poolN) { */ void calcSoilMaintRespiration(double tsoil, double water, double whc) { - // TBD We seem to be conflating maintResp and rSoil in the non-microbe - // case, need to dig in. With that said... + double moistEffect = calcMoistEffect(water, whc); - if (!ctx.microbes) { - double moistEffect = calcMoistEffect(water, whc); + // :: from [1], remainder of eq (A20) + // See calcMoistEffect() for first part of eq (A20) calculation + double tempEffect = calcTempEffect(tsoil); - // :: from [1], remainder of eq (A20) - // See calcMoistEffect() for first part of eq (A20) calculation - double tempEffect = calcTempEffect(tsoil); - - // Effects of tillage, if any + // Effects of tillage, if any double tillageEffect = calcTillageEffect(); // Effects of current CN @@ -1178,10 +1174,8 @@ void calcSoilMaintRespiration(double tsoil, double water, double whc) { fluxes.maintRespiration = envi.soilC * params.baseSoilResp * moistEffect * tempEffect * tillageEffect * cnEffect; - // With no microbes, rSoil flux is just the maintenance respiration - fluxes.rSoil = fluxes.maintRespiration; - } - // else fluxes.rSoil = 0.0? + // With no microbes, rSoil flux is just the maintenance respiration + fluxes.rSoil = fluxes.soilMaintRespiration; } /*! @@ -1214,17 +1208,24 @@ void calcMicrobeFluxes(double tsoil, double water, double whc, // respiration is determined by microbe biomass // :: from [4], eq (5.12) with addition of moisture effect // [TAG:UNKNOWN_PROVENANCE] moistEffect - tempEffect = params.baseMicrobeResp * pow(params.microbeQ10, tsoil / 10); - fluxes.maintRespiration = envi.microbeC * moistEffect * tempEffect; + tempEffect = pow(params.microbeQ10, tsoil / 10); + fluxes.microbeMaintRespiration = + envi.microbeC * params.baseMicrobeResp * moistEffect * tempEffect; + + // rSoil is maintenance respiration + growth (microbe) respiration + // :: from [4], eq (5.10) for microbe term + fluxes.rSoil = fluxes.microbeMaintRespiration + + (1 - params.efficiency) * fluxes.microbeIngestion; } else { fluxes.microbeIngestion = 0.0; fluxes.soilPulse = 0.0; + fluxes.microbeMaintRespiration = 0.0; // fluxes.maintRespiration is otherwise set, do not set to zero here } } -void calcLitterFluxes() { +void calcLitterFluxes(void) { if (ctx.litterPool) { double tempEffect = calcTempEffect(climate->tsoil); double moistEffect = calcMoistEffect(envi.soilWater, params.soilWHC); @@ -1300,7 +1301,7 @@ double calcRootAndWoodFluxes(void) { /*! * Calculate mineral N volatilization flux */ -void calcNVolatilizationFlux() { +void calcNVolatilizationFlux(void) { // flux = k_vol * nMin * Dtemp * Dwater // Note k_vol is in units of day^-1, so we do not need to divide // by climate length to make this a flux @@ -1314,7 +1315,7 @@ void calcNVolatilizationFlux() { /*! * Calculate mineral N leaching flux */ -void calcNLeachingFlux() { +void calcNLeachingFlux(void) { double phi; // phi is (drainage / soilWHC) between 0 and 1 if ((fluxes.drainage / params.soilWHC) < 1) { @@ -1610,13 +1611,13 @@ void updateMeanTrackers(void) { /*! * Update the main pools, leafC, woodC, soil and snow */ -void updateMainPools() { +void updateMainPools(void) { // Update the stocks, with fluxes adjusted for length of time step. // Notes: // - GPP shows up twice (direct + via NPP --> woodCreation), but // the math works out to: // envi.plantWoodC += NPP_allocation_to_wood − woodLitter. - // - The soil C pool(s) (envi.soil, envi.fineRootC, envi.CoarseRootC) + // - The soil C pool(s) (envi.soilC, envi.fineRootC, envi.CoarseRootC) // are updated in updatePoolsForSoil(). // :: from [1], eq (A1), where: @@ -1684,13 +1685,8 @@ void updatePoolsForSoil(void) { // :: eq (5.11) used for soilPulse, and // :: eq (5.12) used for maintRespiration envi.microbeC += (microbeEff * fluxes.microbeIngestion + fluxes.soilPulse - - fluxes.maintRespiration) * + fluxes.microbeMaintRespiration) * climate->length; - - // rSoil is maintenance resp + growth (microbe) resp - // :: from [4], eq (5.10) for microbe term - fluxes.rSoil = - fluxes.maintRespiration + (1 - microbeEff) * fluxes.microbeIngestion; } else { if (ctx.litterPool) { // :: from [2], litter model description @@ -1963,7 +1959,7 @@ void initModel(ModelParams **modelParams, const char *paramFile, } // See sipnet.h -void cleanupModel() { +void cleanupModel(void) { freeClimateList(); deallocateMeanTracker(meanNPP); diff --git a/src/sipnet/state.h b/src/sipnet/state.h index 31c236719..0b4f1e08f 100644 --- a/src/sipnet/state.h +++ b/src/sipnet/state.h @@ -525,13 +525,15 @@ typedef struct FluxVars { // Microbes [3] // microbes on: microbial maintenance respiration rate - // microbes off: equivalent to rSoil, calc'd as described in [1], eq (A20) // (g C m-2 ground area day^-1) - double maintRespiration; + double microbeMaintRespiration; // Flux that microbes remove from soil (mg C g soil day) // TBD I highly doubt those units; this is calc'd as // (g C * m-2) * (day-1) * (unitless terms) double microbeIngestion; + // microbes off: soil respiration equivalent to rSoil, calc'd as described in + // [1], eq (A20) (g C m-2 ground area day^-1) + double soilMaintRespiration; // Exudates into the soil double soilPulse;