diff --git a/build/includes/gru_actor/gru_actor.hpp b/build/includes/gru_actor/gru_actor.hpp new file mode 100644 index 0000000000000000000000000000000000000000..00afc6905645dbd6a88406d3351833283824800d --- /dev/null +++ b/build/includes/gru_actor/gru_actor.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include "caf/all.hpp" +#include "fortran_data_types.hpp" +#include "timing_info.hpp" + +#include <chrono> +#include <string> + +namespace caf{ +struct gru_state { + caf::actor file_access_actor; + caf::actor parent; + + int indxGRU; // index for gru part of derived types in FORTRAN + int refGRU; // The actual ID of the GRU we are + int numHRUs; +}; +} \ No newline at end of file diff --git a/build/includes/gru_actor/gru_actor_subroutine_wrapper.hpp b/build/includes/gru_actor/gru_actor_subroutine_wrapper.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8ac785596a086f427ff2eebbf995f096ecd25e71 --- /dev/null +++ b/build/includes/gru_actor/gru_actor_subroutine_wrapper.hpp @@ -0,0 +1,4 @@ +#pragma once + +extern "C" { +} \ No newline at end of file diff --git a/build/source/actors/gru_actor/gru_actor.cpp b/build/source/actors/gru_actor/gru_actor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..84610cc8c5b8f9a323535eed9a0829b4dbf9afcc --- /dev/null +++ b/build/source/actors/gru_actor/gru_actor.cpp @@ -0,0 +1,14 @@ +#include "caf/all.hpp" +#include "gru_actor.hpp" +#include "global.hpp" +#include "message_atoms.hpp" +#include "gru_actor_subroutine_wrappers.hpp" + +namespace caf { + +behavior gru_actor(stateful_actor<gru_state>* self, int refGRU, int indxGRU, + std::string configPath, int outputStrucSize, caf::actor parent) + + + +} \ No newline at end of file diff --git a/build/source/actors/gru_actor/gru_actor.f90 b/build/source/actors/gru_actor/gru_actor.f90 new file mode 100644 index 0000000000000000000000000000000000000000..6b371417206238cb95d211d43c445a2e23d2597c --- /dev/null +++ b/build/source/actors/gru_actor/gru_actor.f90 @@ -0,0 +1,105 @@ +!!! Lets try and build this for only the lateral flows case. +!!! If lateral flows exits use the code +module gru_actor +implicit none + +! public::run_gru +public::init_basin_for_timestep + +contains +subroutine init_basin_for_timestep() + implicit none + + ! initialize runoff variables + bvarStruct%var(iLookBVAR%basin__SurfaceRunoff)%dat(1) = 0._dp ! surface runoff (m s-1) + bvarStruct%var(iLookBVAR%basin__SoilDrainage)%dat(1) = 0._dp + bvarStruct%var(iLookBVAR%basin__ColumnOutflow)%dat(1) = 0._dp ! outflow from all "outlet" HRUs (those with no downstream HRU) + bvarStruct%var(iLookBVAR%basin__TotalRunoff)%dat(1) = 0._dp + + ! initialize baseflow variables + bvarStruct%var(iLookBVAR%basin__AquiferRecharge)%dat(1) = 0._dp ! recharge to the aquifer (m s-1) + bvarStruct%var(iLookBVAR%basin__AquiferBaseflow)%dat(1) = 0._dp ! baseflow from the aquifer (m s-1) + bvarStruct%var(iLookBVAR%basin__AquiferTranspire)%dat(1) = 0._dp ! transpiration loss from the aquifer (m s-1) + +end subroutine + +subroutine run_hru_for_timestep() + implicit none + + ! initialize runoff variables + bvarStruct%var(iLookBVAR%basin__SurfaceRunoff)%dat(1) = 0._dp ! surface runoff (m s-1) + bvarStruct%var(iLookBVAR%basin__SoilDrainage)%dat(1) = 0._dp + bvarStruct%var(iLookBVAR%basin__ColumnOutflow)%dat(1) = 0._dp ! outflow from all "outlet" HRUs (those with no downstream HRU) + bvarStruct%var(iLookBVAR%basin__TotalRunoff)%dat(1) = 0._dp + + ! initialize baseflow variables + bvarStruct%var(iLookBVAR%basin__AquiferRecharge)%dat(1) = 0._dp ! recharge to the aquifer (m s-1) + bvarStruct%var(iLookBVAR%basin__AquiferBaseflow)%dat(1) = 0._dp ! baseflow from the aquifer (m s-1) + bvarStruct%var(iLookBVAR%basin__AquiferTranspire)%dat(1) = 0._dp ! transpiration loss from the aquifer (m s-1) + + ! ----- calculate weighted basin (GRU) fluxes -------------------------------------------------------------------------------------- + + ! increment basin surface runoff (m s-1) + bvarStruct%var(iLookBVAR%basin__SurfaceRunoff)%dat(1) = bvarStruct%var(iLookBVAR%basin__SurfaceRunoff)%dat(1) + fluxStruct%var(iLookFLUX%scalarSurfaceRunoff)%dat(1) * fracHRU + + !increment basin soil drainage (m s-1) + bvarStruct%var(iLookBVAR%basin__SoilDrainage)%dat(1) = bvarStruct%var(iLookBVAR%basin__SoilDrainage)%dat(1) + fluxStruct%var(iLookFLUX%scalarSoilDrainage)%dat(1) * fracHRU + + ! increment aquifer variables -- ONLY if aquifer baseflow is computed individually for each HRU and aquifer is run + ! NOTE: groundwater computed later for singleBasin + if(model_decisions(iLookDECISIONS%spatial_gw)%iDecision == localColumn .and. model_decisions(iLookDECISIONS%groundwatr)%iDecision == bigBucket) then + + bvarStruct%var(iLookBVAR%basin__AquiferRecharge)%dat(1) = bvarStruct%var(iLookBVAR%basin__AquiferRecharge)%dat(1) + fluxStruct%var(iLookFLUX%scalarSoilDrainage)%dat(1) * fracHRU + bvarStruct%var(iLookBVAR%basin__AquiferTranspire)%dat(1) = bvarStruct%var(iLookBVAR%basin__AquiferTranspire)%dat(1) + fluxStruct%var(iLookFLUX%scalarAquiferTranspire)%dat(1) * fracHRU + bvarStruct%var(iLookBVAR%basin__AquiferBaseflow)%dat(1) = bvarStruct%var(iLookBVAR%basin__AquiferBaseflow)%dat(1) & + + fluxStruct%var(iLookFLUX%scalarAquiferBaseflow)%dat(1) * fracHRU + end if + + ! perform the routing + associate(totalArea => bvarStruct%var(iLookBVAR%basin__totalArea)%dat(1) ) + + ! compute water balance for the basin aquifer + if(model_decisions(iLookDECISIONS%spatial_gw)%iDecision == singleBasin)then + message=trim(message)//'multi_driver/bigBucket groundwater code not transferred from old code base yet' + err=20; return + end if + + ! calculate total runoff depending on whether aquifer is connected + if(model_decisions(iLookDECISIONS%groundwatr)%iDecision == bigBucket) then + ! aquifer + bvarStruct%var(iLookBVAR%basin__TotalRunoff)%dat(1) = bvarStruct%var(iLookBVAR%basin__SurfaceRunoff)%dat(1) + bvarStruct%var(iLookBVAR%basin__ColumnOutflow)%dat(1)/totalArea + bvarStruct%var(iLookBVAR%basin__AquiferBaseflow)%dat(1) + else + ! no aquifer + bvarStruct%var(iLookBVAR%basin__TotalRunoff)%dat(1) = bvarStruct%var(iLookBVAR%basin__SurfaceRunoff)%dat(1) + bvarStruct%var(iLookBVAR%basin__ColumnOutflow)%dat(1)/totalArea + bvarStruct%var(iLookBVAR%basin__SoilDrainage)%dat(1) + endif + + call qOverland(& + ! input + model_decisions(iLookDECISIONS%subRouting)%iDecision, & ! intent(in): index for routing method + bvarStruct%var(iLookBVAR%basin__TotalRunoff)%dat(1), & ! intent(in): total runoff to the channel from all active components (m s-1) + bvarStruct%var(iLookBVAR%routingFractionFuture)%dat, & ! intent(in): fraction of runoff in future time steps (m s-1) + bvarStruct%var(iLookBVAR%routingRunoffFuture)%dat, & ! intent(in): runoff in future time steps (m s-1) + ! output + bvarStruct%var(iLookBVAR%averageInstantRunoff)%dat(1), & ! intent(out): instantaneous runoff (m s-1) + bvarStruct%var(iLookBVAR%averageRoutedRunoff)%dat(1), & ! intent(out): routed runoff (m s-1) + err,message) ! intent(out): error control + if(err/=0)then; err=20; message=trim(message)//trim(cmessage); return; endif + end associate + + + +end subroutine + + + + +end module gru_actor + +! the way the lateral flow interface should work seems to be at the level of the hru. +! The HRU would have an interface where it has a donwslope compontent. It would then ask +! for this downslope component. This all does have to be setup before hand so the gru needs to +! set these up because the hrus all need to comptue +! a grus timestep depends on all the hrus + +! So the Gru needs to be controlling the hrus. It needs to know which ones have lateral flows and which ones do not. +! This is so the other hrus know they do not need to contact another actor. Otherwise they will have to. \ No newline at end of file diff --git a/build/source/actors/hru_actor/hru_actor.f90 b/build/source/actors/hru_actor/hru_actor.f90 new file mode 100644 index 0000000000000000000000000000000000000000..2ae7bab059d99f8c4f479b7e0202578c2456e613 --- /dev/null +++ b/build/source/actors/hru_actor/hru_actor.f90 @@ -0,0 +1,151 @@ +module hru_actor + implicit none + + + public::run_hru_for_timestep() + + contains + subroutine run_hru_for_timestep() + + + ! local variables: + integer(i4b) :: nSnow + integer(i4b) :: nSoil + integer(i4b) :: nLayers + + ! ******************************************************************************************* + ! *** initialize computeVegFlux (flag to indicate if we are computing fluxes over vegetation) + ! ******************************************************************************************* + + ! if computeVegFlux changes, then the number of state variables changes, and we need to reoranize the data structures + if(modelTimeStep==1)then + ! get vegetation phenology + ! (compute the exposed LAI and SAI and whether veg is buried by snow) + call vegPhenlgy(& + ! input/output: data structures + model_decisions, & ! intent(in): model decisions + typeStruct, & ! intent(in): type of vegetation and soil + attrStruct, & ! intent(in): spatial attributes + mparStruct, & ! intent(in): model parameters + progStruct, & ! intent(in): model prognostic variables for a local HRU + diagStruct, & ! intent(inout): model diagnostic variables for a local HRU + ! output + computeVegFluxFlag, & ! intent(out): flag to indicate if we are computing fluxes over vegetation (.false. means veg is buried with snow) + notUsed_canopyDepth, & ! intent(out): NOT USED: canopy depth (m) + notUsed_exposedVAI, & ! intent(out): NOT USED: exposed vegetation area index (m2 m-2) + fracJulDay, & + yearLength, & + err,cmessage) ! intent(out): error control + if(err/=0)then; message=trim(message)//trim(cmessage); return; endif + + ! save the flag for computing the vegetation fluxes + if(computeVegFluxFlag) computeVegFlux = yes + if(.not.computeVegFluxFlag) computeVegFlux = no + ! define the green vegetation fraction of the grid box (used to compute LAI) + diagStruct%var(iLookDIAG%scalarGreenVegFraction)%dat(1) = greenVegFrac_monthly(timeStruct%var(iLookTIME%im)) + end if ! if first timestep + + ! initialize total inflow for each layer in a soil column + fluxStruct%var(iLookFLUX%mLayerColumnInflow)%dat(:) = 0._dp + + ! convienence variables + nSnow = indxStruct%var(iLookINDEX%nSnow)%dat(1) ! number of snow layers + nSoil = indxStruct%var(iLookINDEX%nSoil)%dat(1) ! number of soil layers + nLayers = indxStruct%var(iLookINDEX%nLayers)%dat(1) ! total number of layers + + computeVegFluxFlag = (ComputeVegFlux == yes) + + ! water pixel: do nothing + if (typeStruct%var(iLookTYPE%vegTypeIndex) == isWater) return + + ! get height at bottom of each soil layer, negative downwards (used in Noah MP) + allocate(zSoilReverseSign(nSoil),stat=err) + if(err/=0)then + message=trim(message)//'problem allocating space for zSoilReverseSign' + err=20; return + endif + zSoilReverseSign(:) = -progStruct%var(iLookPROG%iLayerHeight)%dat(nSnow+1:nLayers) + + ! populate parameters in Noah-MP modules + ! Passing a maxSoilLayer in order to pass the check for NROOT, that is done to avoid making any changes to Noah-MP code. + ! --> NROOT from Noah-MP veg tables (as read here) is not used in SUMMA + call REDPRM(typeStruct%var(iLookTYPE%vegTypeIndex), & ! vegetation type index + typeStruct%var(iLookTYPE%soilTypeIndex), & ! soil type + typeStruct%var(iLookTYPE%slopeTypeIndex), & ! slope type index + zSoilReverseSign, & ! * not used: height at bottom of each layer [NOTE: negative] (m) + maxSoilLayers, & ! number of soil layers + urbanVegCategory) ! vegetation category for urban areas + + ! deallocate height at bottom of each soil layer(used in Noah MP) + deallocate(zSoilReverseSign,stat=err) + if(err/=0)then + message=trim(message)//'problem deallocating space for zSoilReverseSign' + err=20; return + endif + + ! overwrite the minimum resistance + if(overwriteRSMIN) RSMIN = mparStruct%var(iLookPARAM%minStomatalResistance)%dat(1) + + ! overwrite the vegetation height + HVT(typeStruct%var(iLookTYPE%vegTypeIndex)) = mparStruct%var(iLookPARAM%heightCanopyTop)%dat(1) + HVB(typeStruct%var(iLookTYPE%vegTypeIndex)) = mparStruct%var(iLookPARAM%heightCanopyBottom)%dat(1) + + ! overwrite the tables for LAI and SAI + if(model_decisions(iLookDECISIONS%LAI_method)%iDecision == specified)then + SAIM(typeStruct%var(iLookTYPE%vegTypeIndex),:) = mparStruct%var(iLookPARAM%winterSAI)%dat(1) + LAIM(typeStruct%var(iLookTYPE%vegTypeIndex),:) = mparStruct%var(iLookPARAM%summerLAI)%dat(1)*greenVegFrac_monthly + end if + + ! compute derived forcing variables + call derivforce(& + timeStruct%var, & ! vector of time information + forcStruct%var, & ! vector of model forcing data + attrStruct%var, & ! vector of model attributes + mparStruct, & ! data structure of model parameters + progStruct, & ! data structure of model prognostic variables + diagStruct, & ! data structure of model diagnostic variables + fluxStruct, & ! data structure of model fluxes + tmZoneOffsetFracDay,& + err,cmessage) ! error control + if(err/=0)then; err=20; message=trim(message)//trim(cmessage); return; endif + + ! initialize the number of flux calls + diagStruct%var(iLookDIAG%numFluxCalls)%dat(1) = 0._dp + + ! run the model for a single HRU + call coupled_em(& + ! model control + indxHRU, & ! intent(in): hruID + dt_init, & ! intent(inout): initial time step + dt_init_factor, & ! Used to adjust the length of the timestep in the event of a failure + computeVegFluxFlag, & ! intent(inout): flag to indicate if we are computing fluxes over vegetation + ! data structures (input) + typeStruct, & ! intent(in): local classification of soil veg etc. for each HRU + attrStruct, & ! intent(in): local attributes for each HRU + forcStruct, & ! intent(in): model forcing data + mparStruct, & ! intent(in): model parameters + bvarStruct, & ! intent(in): basin-average model variables + ! data structures (input-output) + indxStruct, & ! intent(inout): model indices + progStruct, & ! intent(inout): model prognostic variables for a local HRU + diagStruct, & ! intent(inout): model diagnostic variables for a local HRU + fluxStruct, & ! intent(inout): model fluxes for a local HRU + fracJulDay, & + yearLength, & + ! error control + err,cmessage) ! intent(out): error control + if(err/=0)then; err=20; message=trim(message)//trim(cmessage); return; endif + + ! save the flag for computing the vegetation fluxes + if(computeVegFluxFlag) ComputeVegFlux = yes + if(.not.computeVegFluxFlag) ComputeVegFlux = no + + ! The gru_actor will need the following information + fracHRU = attrStruct%var(iLookATTR%HRUarea) / bvarStruct%var(iLookBVAR%basin__totalArea)%dat(1) + fluxStruct%var(iLookFLUX%scalarSurfaceRunoff)%dat(1) + fluxStruct%var(iLookFLUX%scalarSoilDrainage)%dat(1) + fluxStruct%var(iLookFLUX%scalarAquiferTranspire)%dat(1) + fluxStruct%var(iLookFLUX%scalarAquiferBaseflow)%dat(1) + end subroutine + +end module hru_actor \ No newline at end of file diff --git a/build/source/actors/job_actor/job_actor.f90 b/build/source/actors/job_actor/job_actor.f90 new file mode 100644 index 0000000000000000000000000000000000000000..6f30c1a257b675574a58c1eb969ba65cedd69e83 --- /dev/null +++ b/build/source/actors/job_actor/job_actor.f90 @@ -0,0 +1,3 @@ +module job_actor +implicit none +public::init_veg_ \ No newline at end of file