From eb790908315e8757e74112591e477dd848d03ac0 Mon Sep 17 00:00:00 2001
From: Kyle Klenk <kyle.c.klenk@gmail.com>
Date: Thu, 25 Aug 2022 18:36:40 +0000
Subject: [PATCH] file_access_actor can read in all attribute data for HRU

---
 .../file_access_actor_subroutine_wrappers.hpp |   2 +
 build/makefile                                |   5 +-
 .../file_access_actor/file_access_actor.cpp   |  10 +
 .../file_access_actor/initOutputStruc.f90     | 263 ++++++++--------
 .../read_attribute_all_hru.f90                | 291 ++++++++++++++++++
 build/source/driver/SummaActors_setup.f90     |   2 +-
 .../source/driver/summaActors_globalData.f90  |  30 +-
 build/source/dshare/data_types.f90            |   3 +-
 build/source/engine/alloc_file_access.f90     | 188 +++++------
 .../celia1990/verification_data/runinfo.txt   |   2 +-
 10 files changed, 567 insertions(+), 229 deletions(-)
 create mode 100644 build/source/actors/file_access_actor/read_attribute_all_hru.f90

diff --git a/build/includes/file_access_actor/file_access_actor_subroutine_wrappers.hpp b/build/includes/file_access_actor/file_access_actor_subroutine_wrappers.hpp
index 9df2799..ade26ec 100644
--- a/build/includes/file_access_actor/file_access_actor_subroutine_wrappers.hpp
+++ b/build/includes/file_access_actor/file_access_actor_subroutine_wrappers.hpp
@@ -31,4 +31,6 @@ extern "C" {
   void def_output(void* handle_ncid, int* startGRU, int* numGRU, int* numHRU, int* err);
 
   void Write_HRU_Param(void* handle_ncid, int* indxGRU, int* indxHRU, int* err);
+
+  void readAttributeFileAccessActor(int* num_gru, int* err);
 }
diff --git a/build/makefile b/build/makefile
index 94a5a62..3d6283a 100644
--- a/build/makefile
+++ b/build/makefile
@@ -143,7 +143,8 @@ INTERFACE = $(patsubst %, $(ACTORS_DIR)/global/%, $(SUMMA_INTERFACE))
 SUMMA_FILEACCESS_INTERFACE = \
 		initOutputStruc.f90 \
 		deallocateOutputStruc.f90 \
-		cppwrap_fileAccess.f90
+		cppwrap_fileAccess.f90 \
+		read_attribute_all_hru.f90
 
 FILEACCESS_INTERFACE = $(patsubst %, $(FILE_ACCESS_DIR)/%, $(SUMMA_FILEACCESS_INTERFACE))
 
@@ -158,7 +159,7 @@ SUMMA_HRU_INTERFACE = \
 HRU_INTERFACE = $(patsubst %, $(HRU_ACTOR_DIR)/%, $(SUMMA_HRU_INTERFACE))
 
 SUMMA_GRU_INTERFACE = \
-		gru_actor.f90
+		gru_actor.f90 \
 
 GRU_INTERFACE = $(patsubst %, $(GRU_ACTOR_DIR)/%, $(SUMMA_GRU_INTERFACE))
 		
diff --git a/build/source/actors/file_access_actor/file_access_actor.cpp b/build/source/actors/file_access_actor/file_access_actor.cpp
index dad7a63..560dfdf 100644
--- a/build/source/actors/file_access_actor/file_access_actor.cpp
+++ b/build/source/actors/file_access_actor/file_access_actor.cpp
@@ -240,6 +240,16 @@ void initalizeFileAccessActor(stateful_actor<file_access_state>* self) {
     Init_OutputStruct(self->state.handle_forcing_file_info, &self->state.outputStrucSize, 
         &self->state.numGRU, &self->state.err);
 
+        // Read In all of the attribres for the number of GRUs in the run Domian
+    readAttributeFileAccessActor(&self->state.numGRU, &err);
+    if (err != 0) {
+        aout(self) << "ERROR: FILE_ACCESS_ACTOR readAttributeFilAccessActor() \n";
+        std::string function = "readAttributeFileAccessActor";
+        self->send(self->state.parent, file_access_actor_err_v, function);
+        self->quit();
+        return;
+    }
+
     // Initalize the output manager  
     self->state.output_manager = new OutputManager(self->state.num_vectors_in_output_manager, self->state.numGRU);
     
diff --git a/build/source/actors/file_access_actor/initOutputStruc.f90 b/build/source/actors/file_access_actor/initOutputStruc.f90
index 111ad6a..cc2090a 100644
--- a/build/source/actors/file_access_actor/initOutputStruc.f90
+++ b/build/source/actors/file_access_actor/initOutputStruc.f90
@@ -32,6 +32,7 @@ subroutine initalizeOutput(forcFileInfo, maxSteps, nGRU, err)
   ! local variables
   integer(i4b)                          :: nVars
   integer(i4b)                          :: iGRU
+  integer(i4b)                          :: iHRU
   integer(i4b)                          :: iStep
   integer(i4b)                          :: nSnow
   integer(i4b)                          :: nSoil
@@ -42,39 +43,33 @@ subroutine initalizeOutput(forcFileInfo, maxSteps, nGRU, err)
   if (.not.allocated(outputStructure))then
     allocate(outputStructure(1))
   end if
+
   ! Statistics Structures
   allocate(outputStructure(1)%forcStat(1))
-  allocate(outputStructure(1)%forcStat(1)%gru(nGRU))
-
   allocate(outputStructure(1)%progStat(1))
-  allocate(outputStructure(1)%progStat(1)%gru(nGRU))
-
   allocate(outputStructure(1)%diagStat(1))
-  allocate(outputStructure(1)%diagStat(1)%gru(nGRU))
-
   allocate(outputStructure(1)%fluxStat(1))
-  allocate(outputStructure(1)%fluxStat(1)%gru(nGRU))
-
   allocate(outputStructure(1)%indxStat(1))
-  allocate(outputStructure(1)%indxStat(1)%gru(nGRU))
-
   allocate(outputStructure(1)%bvarStat(1))
+  allocate(outputStructure(1)%forcStat(1)%gru(nGRU))
+  allocate(outputStructure(1)%progStat(1)%gru(nGRU))
+  allocate(outputStructure(1)%diagStat(1)%gru(nGRU))
+  allocate(outputStructure(1)%fluxStat(1)%gru(nGRU))
+  allocate(outputStructure(1)%indxStat(1)%gru(nGRU))
   allocate(outputStructure(1)%bvarStat(1)%gru(nGRU))
+
   ! Primary Data Structures (scalars)
   allocate(outputStructure(1)%timeStruct(1))
-  allocate(outputStructure(1)%timeStruct(1)%gru(nGRU))
-
   allocate(outputStructure(1)%forcStruct(1))
-  allocate(outputStructure(1)%forcStruct(1)%gru(nGRU))
-
   allocate(outputStructure(1)%attrStruct(1))
-  allocate(outputStructure(1)%attrStruct(1)%gru(nGRU))
-
   allocate(outputStructure(1)%typeStruct(1))
-  allocate(outputStructure(1)%typeStruct(1)%gru(nGRU))
-
   allocate(outputStructure(1)%idStruct(1))
+  allocate(outputStructure(1)%timeStruct(1)%gru(nGRU))
+  allocate(outputStructure(1)%forcStruct(1)%gru(nGRU))
+  allocate(outputStructure(1)%attrStruct(1)%gru(nGRU))
+  allocate(outputStructure(1)%typeStruct(1)%gru(nGRU))
   allocate(outputStructure(1)%idStruct(1)%gru(nGRU))
+  
   ! Primary Data Structures (variable length vectors)
   allocate(outputStructure(1)%indxStruct(1))
   allocate(outputStructure(1)%mparStruct(1))
@@ -86,132 +81,140 @@ subroutine initalizeOutput(forcFileInfo, maxSteps, nGRU, err)
   allocate(outputStructure(1)%progStruct(1)%gru(nGRU))
   allocate(outputStructure(1)%diagStruct(1)%gru(nGRU))
   allocate(outputStructure(1)%fluxStruct(1)%gru(nGRU))
+
   ! Basin-Average structures
   allocate(outputStructure(1)%bparStruct(1))
   allocate(outputStructure(1)%bvarStruct(1))
   allocate(outputStructure(1)%bparStruct(1)%gru(nGRU))
   allocate(outputStructure(1)%bvarStruct(1)%gru(nGRU))
+
   ! Finalize Stats for writing
   allocate(outputStructure(1)%finalizeStats(1))
   allocate(outputStructure(1)%finalizeStats(1)%gru(nGRU))
-  !
-  ! Allocate space for HRUs
-  !
+  
+  
   do iGRU = 1, nGRU
+    ! Statistics Structures
+    allocate(outputStructure(1)%forcStat(1)%gru(iGRU)%hru(gru_struc(iGRU)%hruCount))
+    allocate(outputStructure(1)%progStat(1)%gru(iGRU)%hru(gru_struc(iGRU)%hruCount))
+    allocate(outputStructure(1)%diagStat(1)%gru(iGRU)%hru(gru_struc(iGRU)%hruCount))
+    allocate(outputStructure(1)%fluxStat(1)%gru(iGRU)%hru(gru_struc(iGRU)%hruCount))
+    allocate(outputStructure(1)%indxStat(1)%gru(iGRU)%hru(gru_struc(iGRU)%hruCount))
+    allocate(outputStructure(1)%bvarStat(1)%gru(iGRU)%hru(gru_struc(iGRU)%hruCount))
+
+    ! Primary Data Structures (scalars)
+    allocate(outputStructure(1)%timeStruct(1)%gru(iGRU)%hru(gru_struc(iGRU)%hruCount))
+    allocate(outputStructure(1)%forcStruct(1)%gru(iGRU)%hru(gru_struc(iGRU)%hruCount))
+    allocate(outputStructure(1)%attrStruct(1)%gru(iGRU)%hru(gru_struc(iGRU)%hruCount))
+    allocate(outputStructure(1)%typeStruct(1)%gru(iGRU)%hru(gru_struc(iGRU)%hruCount))
+    allocate(outputStructure(1)%idStruct(1)%gru(iGRU)%hru(gru_struc(iGRU)%hruCount))
+  
+    ! Primary Data Structures (variable length vectors)
+    allocate(outputStructure(1)%indxStruct(1)%gru(iGRU)%hru(gru_struc(iGRU)%hruCount))
+    allocate(outputStructure(1)%mparStruct(1)%gru(iGRU)%hru(gru_struc(iGRU)%hruCount))
+    allocate(outputStructure(1)%progStruct(1)%gru(iGRU)%hru(gru_struc(iGRU)%hruCount))
+    allocate(outputStructure(1)%diagStruct(1)%gru(iGRU)%hru(gru_struc(iGRU)%hruCount))
+    allocate(outputStructure(1)%fluxStruct(1)%gru(iGRU)%hru(gru_struc(iGRU)%hruCount))
+  
+    ! Basin-Average structures
+    allocate(outputStructure(1)%bvarStruct(1)%gru(iGRU)%hru(gru_struc(iGRU)%hruCount))
+
+    ! Finalize Stats for writing
+    allocate(outputStructure(1)%finalizeStats(1)%gru(iGRU)%hru(gru_struc(iGRU)%hruCount))
 
-    ! Get the maximum number of steps needed to initalize the output structure
-    nVars = maxval(forcFileInfo%ffile_list(:)%nVars)
-    nSnow = gru_struc(iGRU)%hruInfo(1)%nSnow
-    nSoil = gru_struc(iGRU)%hruInfo(1)%nSoil
-
-    do iStruct=1,size(structInfo)
-      ! allocate space structures
-      select case(trim(structInfo(iStruct)%structName))    
-        case('time')
-          allocate(outputStructure(1)%timeStruct(1)%gru(iGRU)%hru(1)) 
-          call alloc_outputStruc(time_meta,outputStructure(1)%timeStruct(1)%gru(iGRU)%hru(1), &
+  end do
+
+  do iGRU=1,nGRU
+    do iHRU=1,gru_struc(iGRU)%hruCount
+
+      ! Get the maximum number of steps needed to initalize the output structure
+      nVars = maxval(forcFileInfo%ffile_list(:)%nVars)
+      nSnow = gru_struc(iGRU)%hruInfo(iHRU)%nSnow
+      nSoil = gru_struc(iGRU)%hruInfo(iHRU)%nSoil
+
+      do iStruct=1,size(structInfo)
+        ! allocate space structures
+          select case(trim(structInfo(iStruct)%structName))    
+            case('time')
+              call alloc_outputStruc(time_meta,outputStructure(1)%timeStruct(1)%gru(iGRU)%hru(iHRU), &
                         maxSteps,err=err,message=message)     ! model forcing data
-        case('forc')
-          allocate(outputStructure(1)%forcStruct(1)%gru(iGRU)%hru(1))
-          call alloc_outputStruc(forc_meta,outputStructure(1)%forcStruct(1)%gru(iGRU)%hru(1), &
-                        maxSteps,nSnow,nSoil,err,message);    ! model forcing data
-        case('attr')
-          allocate(outputStructure(1)%attrStruct(1)%gru(iGRU)%hru(1))
-          call alloc_outputStruc(attr_meta,outputStructure(1)%attrStruct(1)%gru(iGRU)%hru(1), &
-                        maxSteps,nSnow,nSoil,err,message);    ! local attributes for each HRU
-        case('type')
-          allocate(outputStructure(1)%typeStruct(1)%gru(iGRU)%hru(1))
-          call alloc_outputStruc(type_meta,outputStructure(1)%typeStruct(1)%gru(iGRU)%hru(1), &
-                        maxSteps,nSnow,nSoil,err,message);    ! classification of soil veg etc.
-        case('id'  )
-          allocate(outputStructure(1)%idStruct(1)%gru(iGRU)%hru(1))
-          call alloc_outputStruc(id_meta,outputStructure(1)%idStruct(1)%gru(iGRU)%hru(1), &
-                        maxSteps,nSnow,nSoil,err,message);        ! local values of hru and gru IDs
-        case('mpar')
-          allocate(outputStructure(1)%mparStruct(1)%gru(iGRU)%hru(1))
-          call alloc_outputStruc(mpar_meta,outputStructure(1)%mparStruct(1)%gru(iGRU)%hru(1), &
-                        maxSteps,nSnow,nSoil,err,message);    ! model parameters
-        case('indx')
-          allocate(outputStructure(1)%indxStruct(1)%gru(iGRU)%hru(1))
-          call alloc_outputStruc(indx_meta,outputStructure(1)%indxStruct(1)%gru(iGRU)%hru(1), &
-                        maxSteps,nSnow,nSoil,err,message);    ! model variables
-        case('prog')
-          allocate(outputStructure(1)%progStruct(1)%gru(iGRU)%hru(1))
-          call alloc_outputStruc(prog_meta,outputStructure(1)%progStruct(1)%gru(iGRU)%hru(1), &
-                        maxSteps,nSnow,nSoil,err,message);    ! model prognostic (state) variables
-        case('diag')
-          allocate(outputStructure(1)%diagStruct(1)%gru(iGRU)%hru(1))
-          call alloc_outputStruc(diag_meta,outputStructure(1)%diagStruct(1)%gru(iGRU)%hru(1), &
-                        maxSteps,nSnow,nSoil,err,message);    ! model diagnostic variables
-        case('flux')
-          allocate(outputStructure(1)%fluxStruct(1)%gru(iGRU)%hru(1))
-          call alloc_outputStruc(flux_meta,outputStructure(1)%fluxStruct(1)%gru(iGRU)%hru(1), &
-                        maxSteps,nSnow,nSoil,err,message);    ! model fluxes
-        case('bpar')
-          call alloc_outputStruc(bpar_meta,outputStructure(1)%bparStruct(1)%gru(iGRU), &
-                        maxSteps,nSnow=0,nSoil=0,err=err,message=message);  ! basin-average params 
-        case('bvar')
-          allocate(outputStructure(1)%bvarStruct(1)%gru(iGRU)%hru(1))
-          call alloc_outputStruc(bvar_meta,outputStructure(1)%bvarStruct(1)%gru(iGRU)%hru(1), &
-                        maxSteps,nSnow=0,nSoil=0,err=err,message=message);  ! basin-average variables
-        case('deriv'); cycle
-        case default; err=20; message='unable to find structure name: '//trim(structInfo(iStruct)%structName)
-      end select
-      ! check errors
-      if(err/=0)then
-        message=trim(message)//'[structure =  '//trim(structInfo(iStruct)%structName)//']'
-        return
-      endif
-    end do  ! looping through data structures
-
-    do iStruct=1,size(structInfo)
-
-      ! allocate space for statistics structures
-      select case(trim(structInfo(iStruct)%structName))
-        case('forc')
-          allocate(outputStructure(1)%forcStat(1)%gru(iGRU)%hru(1))
-          call alloc_outputStruc(statForc_meta(:)%var_info,outputStructure(1)%forcStat(1)%gru(iGRU)%hru(1), &
-                                maxSteps,nSnow,nSoil,err,message);    ! model forcing data
-        case('prog')
-          allocate(outputStructure(1)%progStat(1)%gru(iGRU)%hru(1))
-          call alloc_outputStruc(statProg_meta(:)%var_info,outputStructure(1)%progStat(1)%gru(iGRU)%hru(1), &
-                                maxSteps,nSnow,nSoil,err,message);    ! model prognostic 
-        case('diag')
-          allocate(outputStructure(1)%diagStat(1)%gru(iGRU)%hru(1))
-          call alloc_outputStruc(statDiag_meta(:)%var_info,outputStructure(1)%diagStat(1)%gru(iGRU)%hru(1), &
-                                maxSteps,nSnow,nSoil,err,message);    ! model diagnostic
-        case('flux')
-          allocate(outputStructure(1)%fluxStat(1)%gru(iGRU)%hru(1))
-          call alloc_outputStruc(statFlux_meta(:)%var_info,outputStructure(1)%fluxStat(1)%gru(iGRU)%hru(1), &
-                                maxSteps,nSnow,nSoil,err,message);    ! model fluxes
-        case('indx')
-          allocate(outputStructure(1)%indxStat(1)%gru(iGRU)%hru(1))
-          call alloc_outputStruc(statIndx_meta(:)%var_info,outputStructure(1)%indxStat(1)%gru(iGRU)%hru(1), &
-                                maxSteps,nSnow,nSoil,err,message);    ! index vars
-        case('bvar')
-          allocate(outputStructure(1)%bvarStat(1)%gru(iGRU)%hru(1))
-          call alloc_outputStruc(statBvar_meta(:)%var_info,outputStructure(1)%bvarStat(1)%gru(iGRU)%hru(1), &
-                                maxSteps,nSnow=0,nSoil=0,err=err,message=message);  ! basin-average variables
-        case default; cycle
-      end select
+            case('forc')
+              ! Structure
+              call alloc_outputStruc(forc_meta,outputStructure(1)%forcStruct(1)%gru(iGRU)%hru(iHRU), &
+                          maxSteps,nSnow,nSoil,err,message);    ! model forcing data
+              ! Statistics
+              call alloc_outputStruc(statForc_meta(:)%var_info,outputStructure(1)%forcStat(1)%gru(iGRU)%hru(iHRU), &
+                          maxSteps,nSnow,nSoil,err,message);    ! model forcing data
+            case('attr')
+              call alloc_outputStruc(attr_meta,outputStructure(1)%attrStruct(1)%gru(iGRU)%hru(iHRU), &
+                          maxSteps,nSnow,nSoil,err,message);    ! local attributes for each HRU
+            case('type')
+              call alloc_outputStruc(type_meta,outputStructure(1)%typeStruct(1)%gru(iGRU)%hru(iHRU), &
+                            maxSteps,nSnow,nSoil,err,message);    ! classification of soil veg etc.
+            case('id'  )
+              call alloc_outputStruc(id_meta,outputStructure(1)%idStruct(1)%gru(iGRU)%hru(iHRU), &
+                            maxSteps,nSnow,nSoil,err,message);        ! local values of hru gru IDs
+            case('mpar')
+              call alloc_outputStruc(mpar_meta,outputStructure(1)%mparStruct(1)%gru(iGRU)%hru(iHRU), &
+                            maxSteps,nSnow,nSoil,err,message);    ! model parameters
+            case('indx')
+              ! Structure
+              call alloc_outputStruc(indx_meta,outputStructure(1)%indxStruct(1)%gru(iGRU)%hru(iHRU), &
+                            maxSteps,nSnow,nSoil,err,message);    ! model variables
+              ! Statistics
+              call alloc_outputStruc(statIndx_meta(:)%var_info,outputStructure(1)%indxStat(1)%gru(iGRU)%hru(1), &
+                            maxSteps,nSnow,nSoil,err,message);    ! index vars
+            case('prog')
+              ! Structure
+              call alloc_outputStruc(prog_meta,outputStructure(1)%progStruct(1)%gru(iGRU)%hru(iHRU), &
+                            maxSteps,nSnow,nSoil,err,message);    ! model prognostic (state) variables
+              ! Statistics
+              call alloc_outputStruc(statProg_meta(:)%var_info,outputStructure(1)%progStat(1)%gru(iGRU)%hru(iHRU), &
+                            maxSteps,nSnow,nSoil,err,message);    ! model prognostic 
+            case('diag')
+              ! Structure
+              call alloc_outputStruc(diag_meta,outputStructure(1)%diagStruct(1)%gru(iGRU)%hru(iHRU), &
+                            maxSteps,nSnow,nSoil,err,message);    ! model diagnostic variables
+              ! Statistics
+              call alloc_outputStruc(statDiag_meta(:)%var_info,outputStructure(1)%diagStat(1)%gru(iGRU)%hru(iHRU), &
+                            maxSteps,nSnow,nSoil,err,message);    ! model diagnostic
+            case('flux')
+              ! Structure
+              call alloc_outputStruc(flux_meta,outputStructure(1)%fluxStruct(1)%gru(iGRU)%hru(iHRU), &
+                            maxSteps,nSnow,nSoil,err,message);    ! model fluxes
+              ! Statistics
+              call alloc_outputStruc(statFlux_meta(:)%var_info,outputStructure(1)%fluxStat(1)%gru(iGRU)%hru(iHRU), &
+                            maxSteps,nSnow,nSoil,err,message);    ! model fluxes
+            case('bpar')
+              call alloc_outputStruc(bpar_meta,outputStructure(1)%bparStruct(1)%gru(iGRU), &
+                            maxSteps,nSnow=0,nSoil=0,err=err,message=message);  ! basin-average params 
+            case('bvar')
+              ! Structure
+              call alloc_outputStruc(bvar_meta,outputStructure(1)%bvarStruct(1)%gru(iGRU)%hru(iHRU), &
+                          maxSteps,nSnow=0,nSoil=0,err=err,message=message);  ! basin-average variables
+              ! Statistics
+              call alloc_outputStruc(statBvar_meta(:)%var_info,outputStructure(1)%bvarStat(1)%gru(iGRU)%hru(iHRU), &
+                          maxSteps,nSnow=0,nSoil=0,err=err,message=message);  ! basin-average variables
+            case('deriv'); cycle
+            case default; err=20; message='unable to find structure name: '//trim(structInfo(iStruct)%structName)
+        end select
+
+        ! check errors
+        if(err/=0)then
+          message=trim(message)//'initOutputStruc.f90 - [structure =  '//trim(structInfo(iStruct)%structName)//']'
+          return
+        endif
+      end do  ! looping through data structures
     
-      ! check errors
-      if(err/=0)then
-        message=trim(message)//'[statistics for =  '//trim(structInfo(iStruct)%structName)//']'
-        return
-      endif
-    
-    end do ! iStruct
-    ! Finalize stats structure for writing to output file
-    allocate(outputStructure(1)%finalizeStats(1)%gru(iGRU)%hru(1))
-    allocate(outputStructure(1)%finalizeStats(1)%gru(iGRU)%hru(1)%tim(maxSteps))
-    do iStep = 1, maxSteps
-      allocate(outputStructure(1)%finalizeStats(1)%gru(iGRU)%hru(1)%tim(iStep)%dat(1:maxVarFreq))
-    end do ! timeSteps
-  end do ! Looping through GRUs
+      ! Finalize stats structure for writing to output file
+      allocate(outputStructure(1)%finalizeStats(1)%gru(iGRU)%hru(iHRU)%tim(maxSteps))
+      do iStep = 1, maxSteps
+        allocate(outputStructure(1)%finalizeStats(1)%gru(iGRU)%hru(iHRU)%tim(iStep)%dat(1:maxVarFreq))
+      end do ! timeSteps
+    end do ! Looping through GRUs
+  end do
 
 
 end subroutine initalizeOutput
 
-
 end module
\ No newline at end of file
diff --git a/build/source/actors/file_access_actor/read_attribute_all_hru.f90 b/build/source/actors/file_access_actor/read_attribute_all_hru.f90
new file mode 100644
index 0000000..f0912a6
--- /dev/null
+++ b/build/source/actors/file_access_actor/read_attribute_all_hru.f90
@@ -0,0 +1,291 @@
+module read_attribute_all_hru
+    USE, intrinsic :: iso_c_binding
+    USE nrtype
+    implicit none
+    private
+    public::read_attribute_file_access_actor
+contains
+subroutine read_attribute_file_access_actor(num_gru,err) bind(C, name="readAttributeFileAccessActor")
+    USE globalData,only:outputStructure                     ! Using the output structure as global input for the attribute data. This is so we can hrus can setup params in parallel.
+    USE netcdf
+    USE netcdf_util_module,only:nc_file_open                   ! open netcdf file
+    USE netcdf_util_module,only:nc_file_close                  ! close netcdf file
+    USE netcdf_util_module,only:netcdf_err                     ! netcdf error handling function
+    ! provide access to derived data types
+    USE data_types,only:var_d                            ! x%var(:)     (i4b)
+    USE data_types,only:var_i                            ! x%var(:)     integer(8)
+    USE data_types,only:var_i8                           ! x%var(:)     (dp)
+    ! provide access to global data
+    USE globalData,only:gru_struc                              ! gru-hru mapping structure
+    USE globalData,only:attr_meta,type_meta,id_meta            ! metadata structures
+    USE get_ixname_module,only:get_ixAttr,get_ixType,get_ixId  ! access function to find index of elements in structure
+    ! Attribute File
+    USE summaActors_FileManager,only:SETTINGS_PATH                     ! define path to settings files (e.g., parameters, soil and veg. tables)
+    USE summaActors_FileManager,only:LOCAL_ATTRIBUTES                  ! name of model initial attributes file
+
+    
+    implicit none
+   
+    integer(c_int),intent(in)            :: num_gru            ! id of the HRU
+    integer(c_int),intent(out)           :: err                ! error code
+
+    ! Local Variables
+    character(len=256)                      :: message            ! error message
+    character(len=256)                   :: cmessage           ! error message for downwind routine
+    integer(i4b)                         :: iVar               ! loop through varibles in the netcdf file
+    integer(i4b)                         :: varType            ! type of variable (categorica, numerical, idrelated)
+    integer(i4b)                         :: varIndx            ! index of variable within its data structure
+   
+    ! check structures
+    integer(i4b)                         :: iCheck             ! index of an attribute name
+    logical(lgt),allocatable             :: checkType(:)       ! vector to check if we have all desired categorical values
+    logical(lgt),allocatable             :: checkId(:)         ! vector to check if we have all desired IDs
+    logical(lgt),allocatable             :: checkAttr(:)       ! vector to check if we have all desired local attributes
+   
+    ! netcdf variables
+    integer(i4b)                         :: ncID               ! netcdf file id
+    character(LEN=nf90_max_name)         :: varName            ! character array of netcdf variable name
+    integer(i4b)                         :: nVar               ! number of variables in netcdf local attribute file
+    integer(i4b),parameter               :: categorical=101    ! named variable to denote categorical data
+    integer(i4b),parameter               :: numerical=102      ! named variable to denote numerical data
+    integer(i4b),parameter               :: idrelated=103      ! named variable to denote ID related data
+    integer(i4b)                         :: categorical_var(1) ! temporary categorical variable from local attributes netcdf file
+    real(dp)                             :: numeric_var(1)     ! temporary numeric variable from local attributes netcdf file
+    integer(8)                           :: idrelated_var(1)   ! temporary ID related variable from local attributes netcdf file
+    
+    integer(i4b)                         :: iGRU
+    integer(i4b)                         :: iHRU
+    ! attribute file
+    character(len=256)                    :: attrFile           ! attributes file name
+
+
+    ! define mapping variables
+   
+    ! Start procedure here
+    err=0; message="read_attriute_all_hru "
+
+    attrFile = trim(SETTINGS_PATH)//trim(LOCAL_ATTRIBUTES)
+
+   
+    ! **********************************************************************************************
+    ! (1) prepare check vectors
+    ! **********************************************************************************************
+    allocate(checkType(size(type_meta)),checkAttr(size(attr_meta)),checkId(size(id_meta)),stat=err)
+    if(err/=0)then
+        err=20
+        message=trim(message)//'problem allocating space for variable check vectors'
+        print*, message
+        return
+    endif
+    checkType(:) = .false.
+    checkAttr(:) = .false.
+    checkId(:)   = .false.
+   
+    ! **********************************************************************************************
+    ! (2) open netcdf file
+    ! **********************************************************************************************
+    ! open file
+    call nc_file_open(trim(attrFile),nf90_noWrite,ncID,err,cmessage)
+    if(err/=0)then
+        message=trim(message)//trim(cmessage)
+        print*, message
+        return
+    endif
+   
+    ! get number of variables total in netcdf file
+    err = nf90_inquire(ncID,nvariables=nVar)
+    call netcdf_err(err,message)
+    if (err/=0) then
+        message=trim(message)//'problem with nf90_inquire'
+        return
+    endif
+    ! **********************************************************************************************
+    ! (3) read local attributes
+    ! **********************************************************************************************
+    ! loop through variables in netcdf file and pull out local attributes
+    iCheck = 1
+    do iVar = 1,nVar
+   
+        ! inqure about current variable name, type, number of dimensions
+        err = nf90_inquire_variable(ncID,iVar,name=varName)
+        if(err/=nf90_noerr)then; 
+            message=trim(message)//'problem inquiring variable: '//trim(varName)//'/'//trim(nf90_strerror(err)); 
+            print*, message
+            return 
+        endif
+   
+        ! find attribute name
+        select case(trim(varName))
+   
+            ! ** categorical data
+            case('vegTypeIndex','soilTypeIndex','slopeTypeIndex','downHRUindex')
+   
+                ! get the index of the variable
+                varType = categorical
+                varIndx = get_ixType(varName)
+                checkType(varIndx) = .true.
+   
+                ! check that the variable could be identified in the data structure
+                if(varIndx < 1)then
+                    err=20; 
+                    message=trim(message)//'unable to find variable ['//trim(varName)//'] in data structure'; 
+                    print*, message
+                    return; 
+                endif
+        
+
+                do iGRU=1,num_gru
+                    do iHRU = 1,gru_struc(iGRU)%hruCount
+                        err = nf90_get_var(ncID,iVar,categorical_var,start=(/gru_struc(iGRU)%hruInfo(iHRU)%hru_nc/),count=(/1/))
+                        if(err/=nf90_noerr)then
+                            message=trim(message)//'problem reading: '//trim(varName)
+                            print*, message
+                            return
+                        end if
+                        outputStructure(1)%typeStruct(1)%gru(iGRU)%hru(iHRU)%var(varIndx) = categorical_var(1)
+                    end do
+                end do
+   
+                ! ** ID related data
+            case('hruId')
+                ! get the index of the variable
+                varType = idrelated
+                varIndx = get_ixId(varName)
+                checkId(varIndx) = .true.
+        
+                ! check that the variable could be identified in the data structure
+                if(varIndx < 1)then
+                    err=20
+                    message=trim(message)//'unable to find variable ['//trim(varName)//'] in data structure'
+                    print*, message
+                    return
+                endif
+        
+                ! get data from netcdf file and store in vector
+                do iGRU=1,num_gru
+                    do iHRU = 1,gru_struc(iGRU)%hruCount
+                        err = nf90_get_var(ncID,iVar,idrelated_var,start=(/gru_struc(iGRU)%hruInfo(iHRU)%hru_nc/),count=(/1/))
+                        if(err/=nf90_noerr)then
+                            message=trim(message)//'problem reading: '//trim(varName)
+                            print*, message
+                            return
+                        end if
+                        outputStructure(1)%idStruct(1)%gru(iGRU)%hru(iHRU)%var(varIndx) = idrelated_var(1)
+                    end do
+                end do
+    
+            ! ** numerical data
+            case('latitude','longitude','elevation','tan_slope','contourLength','HRUarea','mHeight')
+   
+                ! get the index of the variable
+                varType = numerical
+                varIndx = get_ixAttr(varName)
+                checkAttr(varIndx) = .true.
+        
+                ! check that the variable could be identified in the data structure
+                if(varIndx < 1)then
+                    err=20; message=trim(message)//'unable to find variable ['//trim(varName)//'] in data structure'
+                    print*, message
+                    return 
+                endif
+                ! get data from netcdf file and store in vector
+                
+                do iGRU=1,num_gru
+                    do iHRU = 1,gru_struc(iGRU)%hruCount        
+                        err = nf90_get_var(ncID,iVar,numeric_var,start=(/gru_struc(iGRU)%hruInfo(iHRU)%hru_nc/),count=(/1/))
+                        if(err/=nf90_noerr)then
+                            message=trim(message)//'problem reading: '//trim(varName)
+                            print*, message
+                            return
+                        end if
+                        outputStructure(1)%attrStruct(1)%gru(iGRU)%hru(iHRU)%var(varIndx) = numeric_var(1)
+                    end do
+                end do
+            
+            ! for mapping varibles, do nothing (information read above)
+            case('hru2gruId','gruId'); cycle
+        
+                ! check that variables are what we expect
+                case default
+                    message=trim(message)//'unknown variable ['//trim(varName)//'] in local attributes file'
+                    print*,message
+                    err=20
+                    return
+   
+        end select ! select variable
+   
+    end do ! (looping through netcdf local attribute file)
+    
+    ! ** now handle the optional aspect variable if it's missing
+    varIndx = get_ixAttr('aspect')
+    ! check that the variable was not found in the attribute file
+    if(.not. checkAttr(varIndx)) then
+        write(*,*) NEW_LINE('A')//'INFO: aspect not found in the input attribute file, continuing ...'//NEW_LINE('A')
+        do iGRU=1,num_gru
+            do iHRU = 1, gru_struc(iGRU)%hruCount
+                outputStructure(1)%attrStruct(1)%gru(iGRU)%hru(iHRU)%var(varIndx) = nr_realMissing      ! populate variable with out-of-range value, used later
+            end do
+        end do
+        checkAttr(varIndx) = .true.
+    endif
+   
+    ! TODO: find out why this is here, probably for the lateral flows
+    varIndx = get_ixTYPE('downkHRU')
+    checkType(varIndx) = .true.
+    ! outputStructure(1)%typeStruct(1)%gru(iGRU)%hru(iHRU)%var(varIndx) = 0
+   
+    ! **********************************************************************************************
+    ! (4) check that we have all the desired varaibles
+    ! **********************************************************************************************
+    ! check that we have all desired categorical variables
+    if(any(.not.checkType))then
+        do iCheck = 1,size(type_meta)
+            if(.not.checkType(iCheck))then 
+                err=20
+                message=trim(message)//'missing variable ['//trim(type_meta(iCheck)%varname)//'] in local attributes file'
+                print*, message
+                return
+            endif
+     end do
+    endif
+   
+    ! check that we have all desired ID variables
+    if(any(.not.checkId))then
+        do iCheck = 1,size(id_meta)
+            if(.not.checkId(iCheck))then
+                err=20
+                message=trim(message)//'missing variable ['//trim(id_meta(iCheck)%varname)//'] in local attributes file'
+                print*, message
+                return 
+            endif
+        end do
+    endif
+   
+    ! check that we have all desired local attributes
+    if(any(.not.checkAttr))then
+        do iCheck = 1,size(attr_meta)
+            if(.not.checkAttr(iCheck))then; 
+                err=20
+                message=trim(message)//'missing variable ['//trim(attr_meta(iCheck)%varname)//'] in local attributes file'
+                print*, message
+                return 
+            endif
+        end do
+    endif
+   
+    ! **********************************************************************************************
+    ! (5) close netcdf file
+    ! **********************************************************************************************
+   
+    call nc_file_close(ncID,err,cmessage)
+    if (err/=0)then; message=trim(message)//trim(cmessage); return; end if
+   
+    ! free memory
+    deallocate(checkType)
+    deallocate(checkId)
+    deallocate(checkAttr)
+   
+end subroutine
+
+
+end module
\ No newline at end of file
diff --git a/build/source/driver/SummaActors_setup.f90 b/build/source/driver/SummaActors_setup.f90
index 801be8f..3917cf0 100755
--- a/build/source/driver/SummaActors_setup.f90
+++ b/build/source/driver/SummaActors_setup.f90
@@ -146,7 +146,7 @@ contains
  integer(i4b)                             :: iVar               ! looping variables
  ! ---------------------------------------------------------------------------------------
  ! initialize error control
- err=0; message='summa4chm_paramSetup/'
+ err=0; message='hru_paramSetup/'
  ! initialize the start of the initialization
  call date_and_time(values=startSetup)
  
diff --git a/build/source/driver/summaActors_globalData.f90 b/build/source/driver/summaActors_globalData.f90
index 509cb9a..efd6b18 100755
--- a/build/source/driver/summaActors_globalData.f90
+++ b/build/source/driver/summaActors_globalData.f90
@@ -114,22 +114,38 @@ subroutine summa_defineGlobalData(start_gru_index, err) bind(C, name="defineGlob
 
   ! populate metadata for all model variables
   call popMetadat(err,cmessage)
-  if(err/=0)then; message=trim(message)//trim(cmessage); return; endif
+  if(err/=0)then
+    message=trim(message)//trim(cmessage)
+    print*, message
+    return 
+  endif
 
   ! define mapping between fluxes and states
   call flxMapping(err,cmessage)
-  if(err/=0)then; message=trim(message)//trim(cmessage); return; endif
+  if(err/=0)then
+    message=trim(message)//trim(cmessage)
+    print*, message
+    return 
+  endif
 
   ! check data structures
   call checkStruc(err,cmessage)
-  if(err/=0)then; message=trim(message)//trim(cmessage); return; endif
+  if(err/=0)then 
+    message=trim(message)//trim(cmessage) 
+    print*, message
+    return 
+  endif
 
   ! define the mask to identify the subset of variables in the "child" data structure (just scalar variables)
   flux_mask = (flux_meta(:)%vartype==iLookVarType%scalarv)
 
   ! create the averageFlux metadata structure
   call childStruc(flux_meta, flux_mask, averageFlux_meta, childFLUX_MEAN, err, cmessage)
-  if(err/=0)then; message=trim(message)//trim(cmessage); return; endif
+  if(err/=0)then 
+    message=trim(message)//trim(cmessage)
+    print*, message
+    return
+  endif
 
   ! child metadata structures - so that we do not carry full stats structures around everywhere
   ! only carry stats for variables with output frequency > model time step
@@ -151,7 +167,11 @@ subroutine summa_defineGlobalData(start_gru_index, err) bind(C, name="defineGlob
       case('bvar'); call childStruc(bvar_meta,statBvar_mask,statBvar_meta,bvarChild_map,err,cmessage)
     end select
     ! check errors
-    if(err/=0)then; message=trim(message)//trim(cmessage)//'[statistics for =  '//trim(structInfo(iStruct)%structName)//']'; return; endif
+    if(err/=0)then
+      message=trim(message)//trim(cmessage)//'[statistics for =  '//trim(structInfo(iStruct)%structName)//']' 
+      print*, message 
+      return 
+    endif
   end do ! iStruct
 
   ! set all stats metadata to correct var types
diff --git a/build/source/dshare/data_types.f90 b/build/source/dshare/data_types.f90
index c2551e0..0cf403a 100755
--- a/build/source/dshare/data_types.f90
+++ b/build/source/dshare/data_types.f90
@@ -427,7 +427,8 @@ type(gru_hru_time_int),allocatable                :: timeStruct(:)
 type(gru_hru_time_double),allocatable             :: forcStruct(:)                 ! x%gru(:)%hru(:)%var(:)%tim(:)     -- model forcing data
 type(gru_hru_double),allocatable                  :: attrStruct(:)                 ! x%gru(:)%hru(:)%var(:)            -- local attributes for each HRU, DOES NOT CHANGE OVER TIMESTEPS
 type(gru_hru_int),allocatable                     :: typeStruct(:)                 ! x%gru(:)%hru(:)%var(:)%tim(:)     -- local classification of soil veg etc. for each HRU, DOES NOT CHANGE OVER TIMESTEPS
-type(gru_hru_time_int8),allocatable               :: idStruct(:)                   ! x%gru(:)%hru(:)%var(:)%tim(:)     --
+! type(gru_hru_time_int8),allocatable               :: idStruct(:)                   ! x%gru(:)%hru(:)%var(:)%tim(:)     --
+type(gru_hru_int8),allocatable                    :: idStruct(:)                   ! x%gru(:)%hru(:)%var(:)
 
 ! define the primary data structures (variable length vectors)
 type(gru_hru_time_intVec),allocatable             :: indxStruct(:)                 ! x%gru(:)%hru(:)%var(:)%tim(:)%dat -- model indices
diff --git a/build/source/engine/alloc_file_access.f90 b/build/source/engine/alloc_file_access.f90
index 5a83a89..139982f 100644
--- a/build/source/engine/alloc_file_access.f90
+++ b/build/source/engine/alloc_file_access.f90
@@ -5,6 +5,7 @@ USE data_types,only:var_time_ilength
 USE data_types,only:var_time_i
 USE data_types,only:var_time_d
 USE data_types,only:var_time_i8
+USE data_types,only:var_i8
 USE data_types,only:var_d
 USE data_types,only:var_i
 USE data_types,only:var_dlength
@@ -41,105 +42,114 @@ subroutine alloc_outputStruc(metaStruct,dataStruct,nSteps,nSnow,nSoil,err,messag
   integer(i4b)                     :: iVar
   character(len=256)               :: cmessage       ! error message of the downwind routine
   ! initalize error control
-  err=0; message='alloc_outputStruc'
+  message='alloc_outputStruc'
 
   nVars = size(metaStruct)
-  if(present(nSnow) .or. present(nSoil))then
-      ! check both are present
-      if(.not.present(nSoil))then; err=20; message=trim(message)//'expect nSoil to be present when nSnow is present'; return; end if
-      if(.not.present(nSnow))then; err=20; message=trim(message)//'expect nSnow to be present when nSoil is present'; return; end if
-      nLayers = nSnow+nSoil
+    if(present(nSnow) .or. present(nSoil))then
+        ! check both are present
+        if(.not.present(nSoil))then; err=20; message=trim(message)//'expect nSoil to be present when nSnow is present'; return; end if
+        if(.not.present(nSnow))then; err=20; message=trim(message)//'expect nSnow to be present when nSoil is present'; return; end if
+        nLayers = nSnow+nSoil
     
-      ! It is possible that nSnow and nSoil are actually needed here, so we return an error if the optional arguments are missing when needed
-  else
-      select type(dataStruct)
-          ! class is (var_flagVec); err=20
-          class is (var_time_ilength); err=20
-          class is (var_time_dlength); err=20
-      end select
-      if(err/=0)then; message=trim(message)//'expect nSnow and nSoil to be present for variable-length data structures'; return; end if
-  end if
+        ! It is possible that nSnow and nSoil are actually needed here, so we return an error if the optional arguments are missing when needed
+    else
+        select type(dataStruct)
+            ! class is (var_flagVec); err=20
+            class is (var_time_ilength); err=20
+            class is (var_time_dlength); err=20
+        end select
+        if(err/=0)then; message=trim(message)//'expect nSnow and nSoil to be present for variable-length data structures'; return; end if
+    end if
 
-  check=.false.
+    check=.false.
     ! allocate the dimension for model variables
-  select type(dataStruct)
+    select type(dataStruct)
 
-      class is (var_time_i)
-          if(allocated(dataStruct%var))then
-              check=.true.
-          else 
-              allocate(dataStruct%var(nVars),stat=err)
-          end if
-          do iVar=1, nVars
-              allocate(dataStruct%var(iVar)%tim(nSteps))
-          end do
-          return
+        class is (var_time_i)
+            if(allocated(dataStruct%var))then
+                check=.true.
+            else 
+                allocate(dataStruct%var(nVars),stat=err)
+            end if
+            
+            do iVar=1, nVars
+                allocate(dataStruct%var(iVar)%tim(nSteps))
+            end do
+            return
 
-      class is (var_time_i8)
-          if(allocated(dataStruct%var))then 
-              check=.true.
-          else 
-              allocate(dataStruct%var(nVars),stat=err) 
-          end if 
-          do iVar=1, nVars
-              allocate(dataStruct%var(iVar)%tim(nSteps))
-          end do
-          return
+        class is (var_time_i8)
+            if(allocated(dataStruct%var))then 
+                check=.true.
+            else 
+                allocate(dataStruct%var(nVars),stat=err) 
+            end if 
+            do iVar=1, nVars
+                allocate(dataStruct%var(iVar)%tim(nSteps))
+            end do
+            return
 
-      class is (var_time_d)
-          if(allocated(dataStruct%var))then
-              check=.true.
-          else
-              allocate(dataStruct%var(nVars),stat=err)
-          end if
-          do iVar=1, nVars
-              allocate(dataStruct%var(iVar)%tim(nSteps))
-          end do
-          return
-      
-      class is (var_d)
-          if(allocated(dataStruct%var))then
-              check=.true.
-          else
-              allocate(dataStruct%var(nVars),stat=err)
-          end if
-          return
-      
-      class is (var_i)
-          if(allocated(dataStruct%var))then
-              check=.true.
-          else
-              allocate(dataStruct%var(nVars),stat=err)
-          end if
-          return
-      
-      class is (var_dlength)
-          if(allocated(dataStruct%var))then
-              check=.true.
-          else
-              allocate(dataStruct%var(nVars),stat=err)
-          end if
-      ! class is (var_flagVec);      if(allocated(dataStruct%var))then; check=.true.; else; allocate(dataStruct%var(nVars),stat=err); end if
+        class is (var_time_d)
+            if(allocated(dataStruct%var))then
+                check=.true.
+            else
+                allocate(dataStruct%var(nVars),stat=err)
+            end if
+            do iVar=1, nVars
+                allocate(dataStruct%var(iVar)%tim(nSteps))
+            end do
+            return
+        
+        class is (var_d)
+            if(allocated(dataStruct%var))then
+                check=.true.
+            else
+                allocate(dataStruct%var(nVars),stat=err)
+            end if
+            return
+        
+        class is (var_i)
+            if(allocated(dataStruct%var))then
+                check=.true.
+            else
+                allocate(dataStruct%var(nVars),stat=err)
+            end if
+            return
+        
+        class is (var_i8)
+            if(allocated(dataStruct%var))then
+                check=.true.
+            else
+                allocate(dataStruct%var(nVars), stat=err)
+            end if
+            return
+        
+        class is (var_dlength)
+            if(allocated(dataStruct%var))then
+                check=.true.
+            else
+                allocate(dataStruct%var(nVars),stat=err)
+            end if
+        ! class is (var_flagVec);      if(allocated(dataStruct%var))then; check=.true.; else; allocate(dataStruct%var(nVars),stat=err); end if
 
-      class is (var_time_ilength)
-          if(allocated(dataStruct%var))then
-              check=.true. 
-          else 
-              allocate(dataStruct%var(nVars),stat=err) 
-          end if
-          do iVar=1, nVars
-              allocate(dataStruct%var(iVar)%tim(nSteps))
-          end do
+        class is (var_time_ilength)
+            if(allocated(dataStruct%var))then
+                check=.true. 
+            else 
+                allocate(dataStruct%var(nVars),stat=err) 
+            end if
+            do iVar=1, nVars
+                allocate(dataStruct%var(iVar)%tim(nSteps))
+            end do
 
-      class is (var_time_dlength)
-          if(allocated(dataStruct%var))then
-              check=.true.
-          else 
-              allocate(dataStruct%var(nVars),stat=err)
-          end if
-          do iVar=1, nVars
-              allocate(dataStruct%var(iVar)%tim(nSteps))
-          end do
+        class is (var_time_dlength)
+            if(allocated(dataStruct%var))then
+                check=.true.
+            else 
+                allocate(dataStruct%var(nVars),stat=err)
+            end if
+            do iVar=1, nVars
+                allocate(dataStruct%var(iVar)%tim(nSteps))
+            end do
       
       class default; err=20; message=trim(message)//'unable to identify derived data type for the variable dimension'; return
   end select
diff --git a/utils/laugh_tests/celia1990/verification_data/runinfo.txt b/utils/laugh_tests/celia1990/verification_data/runinfo.txt
index a4397e2..35a4527 100644
--- a/utils/laugh_tests/celia1990/verification_data/runinfo.txt
+++ b/utils/laugh_tests/celia1990/verification_data/runinfo.txt
@@ -1 +1 @@
- Run start time on system:  ccyy=2022 - mm=08 - dd=15 - hh=02 - mi=49 - ss=51.739
+ Run start time on system:  ccyy=2022 - mm=08 - dd=24 - hh=02 - mi=58 - ss=32.515
-- 
GitLab