From cec2f081243c6a3391dbdd8489d41422a01ca349 Mon Sep 17 00:00:00 2001
From: Kyle <kyle.c.klenk@gmail.com>
Date: Mon, 15 Aug 2022 15:08:58 -0600
Subject: [PATCH] trying to add a gru_actor

---
 build/includes/gru_actor/gru_actor.hpp        |  19 +++
 .../gru_actor_subroutine_wrapper.hpp          |   4 +
 build/source/actors/gru_actor/gru_actor.cpp   |  14 ++
 build/source/actors/gru_actor/gru_actor.f90   | 105 ++++++++++++
 build/source/actors/hru_actor/hru_actor.f90   | 151 ++++++++++++++++++
 build/source/actors/job_actor/job_actor.f90   |   3 +
 6 files changed, 296 insertions(+)
 create mode 100644 build/includes/gru_actor/gru_actor.hpp
 create mode 100644 build/includes/gru_actor/gru_actor_subroutine_wrapper.hpp
 create mode 100644 build/source/actors/gru_actor/gru_actor.cpp
 create mode 100644 build/source/actors/gru_actor/gru_actor.f90
 create mode 100644 build/source/actors/hru_actor/hru_actor.f90
 create mode 100644 build/source/actors/job_actor/job_actor.f90

diff --git a/build/includes/gru_actor/gru_actor.hpp b/build/includes/gru_actor/gru_actor.hpp
new file mode 100644
index 0000000..00afc69
--- /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 0000000..8ac7855
--- /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 0000000..84610cc
--- /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 0000000..6b37141
--- /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 0000000..2ae7bab
--- /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 0000000..6f30c1a
--- /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
-- 
GitLab