!###############################################################################
!# #
!# aed_zooplankton.F90 #
!# #
!# Developed by : #
!# AquaticEcoDynamics (AED) Group #
!# School of Agriculture and Environment #
!# The University of Western Australia #
!# #
!# http://aquatic.science.uwa.edu.au/ #
!# #
!# Copyright 2013 - 2024 - The University of Western Australia #
!# #
!# AED is free software: you can redistribute it and/or modify #
!# it under the terms of the GNU General Public License as published by #
!# the Free Software Foundation, either version 3 of the License, or #
!# (at your option) any later version. #
!# #
!# AED is distributed in the hope that it will be useful, #
!# but WITHOUT ANY WARRANTY; without even the implied warranty of #
!# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
!# GNU General Public License for more details. #
!# #
!# You should have received a copy of the GNU General Public License #
!# along with this program. If not, see . #
!# #
!# ----------------------------------------------------------------------- #
!# #
!# Created October 2011 #
!# #
!###############################################################################
! !
! .----------------. .----------------. .----------------. !
! | .--------------. || .--------------. || .--------------. | !
! | | ________ | || | ____ | || | ____ | | !
! | | | __ _| | || | .' `. | || | .' `. | | !
! | | |_/ / / | || | / .--. \ | || | / .--. \ | | !
! | | .'.' _ | || | | | | | | || | | | | | | | !
! | | _/ /__/ | | || | \ `--' / | || | \ `--' / | | !
! | | |________| | || | `.____.' | || | `.____.' | | !
! | | | || | | || | | | !
! | '--------------' || '--------------' || '--------------' | !
! '----------------' '----------------' '----------------' !
! !
!###############################################################################
#include "aed.h"
#define _PHYLEN_ 3
#define _PHYMOD_ 'PHY'
#define _OGMPOC_ 'OGM'
MODULE aed_zooplankton
!-------------------------------------------------------------------------------
! aed_zooplankton --- multi zooplankton biogeochemical model
!-------------------------------------------------------------------------------
USE aed_core
USE aed_util
USE aed_zoop_utils
IMPLICIT NONE
PRIVATE ! By default make everything private
!
PUBLIC aed_zooplankton_data_t
!
TYPE,extends(aed_model_data_t) :: aed_zooplankton_data_t
!# Variable identifiers
INTEGER :: id_zoo(MAX_ZOOP_TYPES)
INTEGER :: id_Nexctarget,id_Nmorttarget
INTEGER :: id_Pexctarget,id_Pmorttarget
INTEGER :: id_Cexctarget,id_Cmorttarget
INTEGER :: id_DOupttarget
INTEGER :: id_tem, id_sal, id_oxy
INTEGER :: id_grz,id_resp,id_mort
!# Model parameters
INTEGER :: num_zoops
TYPE(zoop_data_t),DIMENSION(:),ALLOCATABLE :: zoops
LOGICAL :: simDNexcr, simDPexcr, simDCexcr
LOGICAL :: simPNexcr, simPPexcr, simPCexcr
LOGICAL :: simZoopFeedback
CONTAINS
PROCEDURE :: define => aed_define_zooplankton
PROCEDURE :: calculate => aed_calculate_zooplankton
! PROCEDURE :: mobility => aed_mobility_zooplankton
! PROCEDURE :: light_extinction => aed_light_extinction_zooplankton
! PROCEDURE :: delete => aed_delete_zooplankton
END TYPE
! MODULE GLOBALS
INTEGER :: diag_level = 10 ! 0 = no diagnostic outputs
! 1 = basic diagnostic outputs
! 2 = flux rates, and supporitng
! 3 = other metrics
!10 = all debug & checking outputs
!===============================================================================
CONTAINS
!###############################################################################
INTEGER FUNCTION load_csv(dbase, zoop_param, dbsize)
!-------------------------------------------------------------------------------
USE aed_csv_reader
!-------------------------------------------------------------------------------
!ARGUMENTS
CHARACTER(len=*),INTENT(in) :: dbase
TYPE(zoop_param_t),INTENT(out) :: zoop_param(MAX_ZOOP_TYPES)
INTEGER,INTENT(out) :: dbsize
!
!LOCALS
INTEGER :: unit, nccols, ccol, dcol
CHARACTER(len=32),POINTER,DIMENSION(:) :: csvnames
CHARACTER(len=32) :: name
TYPE(AED_SYMBOL),DIMENSION(:),ALLOCATABLE :: values
INTEGER :: idx_col = 0, idx_pry = 0
LOGICAL :: meh
INTEGER :: ret = 0
!
!BEGIN
!-------------------------------------------------------------------------------
dbsize = 0
unit = aed_csv_read_header(dbase, csvnames, nccols)
IF (unit <= 0) THEN
load_csv = -1
RETURN !# No file found
ENDIF
ALLOCATE(values(nccols))
DO WHILE ( aed_csv_read_row(unit, values) )
DO ccol=2,nccols
dcol = ccol - 1
zoop_param(dcol)%zoop_name = csvnames(ccol)
CALL copy_name(values(1), name)
SELECT CASE (name)
CASE ('zoop_initial') ; zoop_param(dcol)%zoop_initial = extract_double(values(ccol))
CASE ('min_zoo') ; zoop_param(dcol)%min_zoo = extract_double(values(ccol))
CASE ('Rgrz_zoo') ; zoop_param(dcol)%Rgrz_zoo = extract_double(values(ccol))
CASE ('fassim_zoo') ; zoop_param(dcol)%fassim_zoo = extract_double(values(ccol))
CASE ('Kgrz_zoo') ; zoop_param(dcol)%Kgrz_zoo = extract_double(values(ccol))
CASE ('theta_grz_zoo') ; zoop_param(dcol)%theta_grz_zoo = extract_double(values(ccol))
CASE ('Rresp_zoo') ; zoop_param(dcol)%Rresp_zoo = extract_double(values(ccol))
CASE ('Rmort_zoo') ; zoop_param(dcol)%Rmort_zoo = extract_double(values(ccol))
CASE ('ffecal_zoo') ; zoop_param(dcol)%ffecal_zoo = extract_double(values(ccol))
CASE ('fexcr_zoo') ; zoop_param(dcol)%fexcr_zoo = extract_double(values(ccol))
CASE ('ffecal_sed') ; zoop_param(dcol)%ffecal_sed = extract_double(values(ccol))
CASE ('theta_resp_zoo') ; zoop_param(dcol)%theta_resp_zoo = extract_double(values(ccol))
CASE ('Tstd_zoo') ; zoop_param(dcol)%Tstd_zoo = extract_double(values(ccol))
CASE ('Topt_zoo') ; zoop_param(dcol)%Topt_zoo = extract_double(values(ccol))
CASE ('Tmax_zoo') ; zoop_param(dcol)%Tmax_zoo = extract_double(values(ccol))
CASE ('saltfunc_zoo') ; zoop_param(dcol)%saltfunc_zoo = extract_integer(values(ccol))
CASE ('Smin_zoo') ; zoop_param(dcol)%Smin_zoo = extract_double(values(ccol))
CASE ('Smax_zoo') ; zoop_param(dcol)%Smax_zoo = extract_double(values(ccol))
CASE ('Sint_zoo') ; zoop_param(dcol)%Sint_zoo = extract_double(values(ccol))
CASE ('INC_zoo') ; zoop_param(dcol)%INC_zoo = extract_double(values(ccol))
CASE ('IPC_zoo') ; zoop_param(dcol)%IPC_zoo = extract_double(values(ccol))
CASE ('DOmin_zoo') ; zoop_param(dcol)%DOmin_zoo = extract_double(values(ccol))
CASE ('Cmin_grz_zoo') ; zoop_param(dcol)%Cmin_grz_zoo = extract_double(values(ccol))
CASE ('num_prey') ; zoop_param(dcol)%num_prey = extract_integer(values(ccol))
CASE DEFAULT
idx_pry = indexed_field('prey(', ')%zoop_prey', MAX_ZOOP_PREY, name)
IF ( idx_pry > 0 ) THEN
CALL copy_name(values(ccol), zoop_param(dcol)%prey(idx_pry)%zoop_prey)
ELSE
idx_pry = indexed_field('prey(', ')%Pzoo_prey', MAX_ZOOP_PREY, name)
IF ( idx_pry > 0 ) THEN
zoop_param(dcol)%prey(idx_pry)%Pzoo_prey = extract_double(values(ccol))
ELSE
print *, 'Unknown row "', TRIM(name), '"'
ENDIF
ENDIF
END SELECT
ENDDO
ENDDO
meh = aed_csv_close(unit)
!# don't care if close fails
IF (ASSOCIATED(csvnames)) DEALLOCATE(csvnames)
IF (ALLOCATED(values)) DEALLOCATE(values)
dbsize = nccols-1
load_csv = ret
END FUNCTION load_csv
!+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
!###############################################################################
SUBROUTINE aed_zooplankton_load_params(data, dbase, count, list)
!-------------------------------------------------------------------------------
!ARGUMENTS
CLASS (aed_zooplankton_data_t),INTENT(inout) :: data
CHARACTER(len=*),INTENT(in) :: dbase
INTEGER,INTENT(inout) :: count !Number of zooplankton groups
INTEGER,INTENT(in) :: list(*) !List of zooplankton groups to simulate
!
!LOCALS
INTEGER :: status, dbsize
INTEGER :: i,j,tfil,sort_i(MAX_ZOOP_PREY)
AED_REAL :: Pzoo_prey(MAX_ZOOP_PREY)
TYPE(zoop_param_t),ALLOCATABLE :: zoop_param(:)
NAMELIST /zoop_params/ zoop_param ! %% zoop_param_t - see aed_zoop_utils
!-------------------------------------------------------------------------------
!BEGIN
ALLOCATE(zoop_param(MAX_ZOOP_TYPES))
SELECT CASE (param_file_type(dbase))
CASE (CSV_TYPE)
status = load_csv(dbase, zoop_param, dbsize)
CASE (NML_TYPE)
print*,"nml format parameter file is deprecated. Please update to CSV format"
open(NEWUNIT=tfil,file=dbase, status='OLD',iostat=status)
IF (status /= 0) STOP 'Error opening zoop_params namelist file'
read(tfil,nml=zoop_params,iostat=status)
close(tfil)
dbsize = 0
DO i=1,MAX_ZOOP_TYPES
IF (zoop_param(i)%zoop_name == '') EXIT
dbsize = dbsize + 1
ENDDO
CASE DEFAULT
print *,'Unknown file type "',TRIM(dbase),'"'; status=1
END SELECT
IF (status /= 0) STOP 'Error reading namelist zoop_params'
data%num_zoops = 0
allocate(data%zoops(count))
DO i=1,count
IF ( list(i) < 1 .OR. list(i) > dbsize ) EXIT !# bad index, exit the loop
data%num_zoops = data%num_zoops + 1
! Assign parameters from database to simulated groups
data%zoops(i)%zoop_name = zoop_param(list(i))%zoop_name
data%zoops(i)%zoop_initial = zoop_param(list(i))%zoop_initial
data%zoops(i)%min_zoo = zoop_param(list(i))%min_zoo
data%zoops(i)%Rgrz_zoo = zoop_param(list(i))%Rgrz_zoo/secs_per_day
data%zoops(i)%fassim_zoo = zoop_param(list(i))%fassim_zoo
data%zoops(i)%Kgrz_zoo = zoop_param(list(i))%Kgrz_zoo
data%zoops(i)%theta_grz_zoo = zoop_param(list(i))%theta_grz_zoo
data%zoops(i)%Rresp_zoo = zoop_param(list(i))%Rresp_zoo/secs_per_day
data%zoops(i)%Rmort_zoo = zoop_param(list(i))%Rmort_zoo/secs_per_day
data%zoops(i)%ffecal_zoo = zoop_param(list(i))%ffecal_zoo
data%zoops(i)%fexcr_zoo = zoop_param(list(i))%fexcr_zoo
data%zoops(i)%ffecal_sed = zoop_param(list(i))%ffecal_sed
data%zoops(i)%theta_resp_zoo = zoop_param(list(i))%theta_resp_zoo
data%zoops(i)%Tstd_zoo = zoop_param(list(i))%Tstd_zoo
data%zoops(i)%Topt_zoo = zoop_param(list(i))%Topt_zoo
data%zoops(i)%Tmax_zoo = zoop_param(list(i))%Tmax_zoo
data%zoops(i)%saltfunc_zoo = zoop_param(list(i))%saltfunc_zoo
data%zoops(i)%Smin_zoo = zoop_param(list(i))%Smin_zoo
data%zoops(i)%Smax_zoo = zoop_param(list(i))%Smax_zoo
data%zoops(i)%Sint_zoo = zoop_param(list(i))%Sint_zoo
data%zoops(i)%INC_zoo = zoop_param(list(i))%INC_zoo
data%zoops(i)%IPC_zoo = zoop_param(list(i))%IPC_zoo
data%zoops(i)%simDOlim = zoop_param(list(i))%simDOlim
data%zoops(i)%DOmin_zoo = zoop_param(list(i))%DOmin_zoo
data%zoops(i)%Cmin_grz_zoo = zoop_param(list(i))%Cmin_grz_zoo
data%zoops(i)%num_prey = zoop_param(list(i))%num_prey
!Loop through prey variables assigning a target variable and preference factor
!First sort in decending order of food preferences
DO j=1,data%zoops(i)%num_prey
sort_i(j) = j
Pzoo_prey(j) = zoop_param(list(i))%prey(j)%Pzoo_prey
ENDDO
CALL qsort(Pzoo_prey,sort_i,1,data%zoops(i)%num_prey)
DO j=1,data%zoops(i)%num_prey
data%zoops(i)%prey(j)%zoop_prey = zoop_param(list(i))%prey(sort_i(data%zoops(i)%num_prey-j+1))%zoop_prey
data%zoops(i)%prey(j)%Pzoo_prey = zoop_param(list(i))%prey(sort_i(data%zoops(i)%num_prey-j+1))%Pzoo_prey
ENDDO
! Register group as a state variable
data%id_zoo(i) = aed_define_variable( &
zoop_param(list(i))%zoop_name, &
'mmolC/m**3', 'zooplankton', &
zoop_param(list(i))%zoop_initial, &
minimum=zoop_param(list(i))%min_zoo)
ENDDO
!
DEALLOCATE(zoop_param)
END SUBROUTINE aed_zooplankton_load_params
!+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
!###############################################################################
SUBROUTINE aed_define_zooplankton(data, namlst)
!-------------------------------------------------------------------------------
! Initialise the zooplankton biogeochemical model
!
! Here, the aed_zooplankton namelist is read and te variables exported
! by the model are registered with AED.
!-------------------------------------------------------------------------------
!ARGUMENTS
CLASS (aed_zooplankton_data_t),INTENT(inout) :: data
INTEGER,INTENT(in) :: namlst
!
!LOCALS
INTEGER :: status
INTEGER :: zoop_i, prey_i, phy_i
! %% NAMELIST %% /aed_zooplankton/
! %% Last Checked 20/08/2021
INTEGER :: num_zoops
INTEGER :: the_zoops(MAX_ZOOP_TYPES)
CHARACTER(len=64) :: dn_target_variable='' !dissolved nitrogen target variable
CHARACTER(len=64) :: pn_target_variable='' !particulate nitrogen target variable
CHARACTER(len=64) :: dp_target_variable='' !dissolved phosphorus target variable
CHARACTER(len=64) :: pp_target_variable='' !particulate phosphorus target variable
CHARACTER(len=64) :: dc_target_variable='' !dissolved carbon target variable
CHARACTER(len=64) :: pc_target_variable='' !particulate carbon target variable
CHARACTER(len=128) :: dbase='aed_zoop_pars.nml'
LOGICAL :: simZoopFeedback = .TRUE.
! %% From Module Globals
! INTEGER :: diag_level = 10 ! 0 = no diagnostic outputs
! ! 1 = basic diagnostic outputs
! ! 2 = flux rates, and supporitng
! ! 3 = other metrics
! !10 = all debug & checking outputs
! %% END NAMELIST %% /aed_zooplankton/
NAMELIST /aed_zooplankton/ num_zoops, the_zoops, &
dn_target_variable, pn_target_variable, dp_target_variable, &
pp_target_variable, dc_target_variable, pc_target_variable, &
dbase, simZoopFeedback, diag_level
!-----------------------------------------------------------------------
!BEGIN
print *," aed_zooplankton configuration"
! Read the namelist
read(namlst,nml=aed_zooplankton,iostat=status)
IF (status /= 0) STOP 'Error reading namelist aed_zooplankton'
data%num_zoops = 0
data%simZoopFeedback = simZoopFeedback
! Store parameter values in our own derived type
! NB: all rates must be provided in values per day,
! and are converted in aed_zooplankton_load_params to values per second.
CALL aed_zooplankton_load_params(data, dbase, num_zoops, the_zoops)
CALL aed_bio_temp_function(data%num_zoops, &
data%zoops%theta_resp_zoo, &
data%zoops%Tstd_zoo, &
data%zoops%Topt_zoo, &
data%zoops%Tmax_zoo, &
data%zoops%aTn, &
data%zoops%bTn, &
data%zoops%kTn, &
data%zoops%zoop_name)
! Register link to prey state variables
DO zoop_i = 1,num_zoops
phy_i = 0
DO prey_i = 1,data%zoops(zoop_i)%num_prey
data%zoops(zoop_i)%id_prey(prey_i) = aed_locate_variable( &
data%zoops(zoop_i)%prey(prey_i)%zoop_prey)
!If the zooplankton prey is phytoplankton then also register state dependency on
!internal nitrogen and phosphorus
IF (data%zoops(zoop_i)%prey(prey_i)%zoop_prey(1:_PHYLEN_).EQ. _PHYMOD_) THEN
phy_i = phy_i + 1
data%zoops(zoop_i)%id_phyIN(phy_i) = aed_locate_variable( &
TRIM(data%zoops(zoop_i)%prey(prey_i)%zoop_prey)//'_IN')
data%zoops(zoop_i)%id_phyIP(phy_i) = aed_locate_variable( &
TRIM(data%zoops(zoop_i)%prey(prey_i)%zoop_prey)//'_IP')
ENDIF
ENDDO
ENDDO
! Register link to nutrient pools, if variable names are provided in namelist.
data%simDNexcr = dn_target_variable .NE. ''
IF (data%simDNexcr) THEN
data%id_Nexctarget = aed_locate_variable(dn_target_variable)
ENDIF
data%simDPexcr = dp_target_variable .NE. ''
IF (data%simDPexcr) THEN
data%id_Pexctarget = aed_locate_variable(dp_target_variable)
ENDIF
data%simDCexcr = dc_target_variable .NE. ''
IF (data%simDCexcr) THEN
data%id_Cexctarget = aed_locate_variable(dc_target_variable)
ENDIF
data%simPNexcr = pn_target_variable .NE. ''
IF (data%simPNexcr) THEN
data%id_Nmorttarget = aed_locate_variable(pn_target_variable)
ENDIF
data%simPPexcr = pp_target_variable .NE. ''
IF (data%simPPexcr) THEN
data%id_Pmorttarget = aed_locate_variable(pp_target_variable)
ENDIF
data%simPCexcr = pc_target_variable .NE. ''
IF (data%simPCexcr) THEN
data%id_Cmorttarget = aed_locate_variable(pc_target_variable)
ENDIF
! Register diagnostic variables
data%id_grz = aed_define_diag_variable('grz','mmolC/m**3/d', 'net zooplankton grazing')
data%id_resp = aed_define_diag_variable('resp','mmolC/m**3/d', 'net zooplankton respiration')
data%id_mort = aed_define_diag_variable('mort','mmolC/m**3/d','net zooplankton mortality')
! Register environmental dependencies
data%id_tem = aed_locate_global('temperature')
data%id_sal = aed_locate_global('salinity')
data%id_oxy = aed_locate_variable('OXY_oxy')
END SUBROUTINE aed_define_zooplankton
!+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
!###############################################################################
SUBROUTINE aed_calculate_zooplankton(data,column,layer_idx)
!-------------------------------------------------------------------------------
! Right hand sides of zooplankton biogeochemical model
!-------------------------------------------------------------------------------
!ARGUMENTS
CLASS (aed_zooplankton_data_t),INTENT(in) :: data
TYPE (aed_column_t),INTENT(inout) :: column(:)
INTEGER,INTENT(in) :: layer_idx
!
!LOCALS
INTEGER :: zoop_i,prey_i,prey_j,phy_i
AED_REAL :: zoo,temp,salinity,oxy !State variables
AED_REAL :: prey(MAX_ZOOP_PREY), grazing_prey(MAX_ZOOP_PREY) !Prey state variables
AED_REAL :: phy_INcon(MAX_ZOOP_PREY), phy_IPcon(MAX_ZOOP_PREY) !Internal nutrients for phytoplankton
AED_REAL :: dn_excr, dp_excr, dc_excr !Excretion state variables
AED_REAL :: pon, pop, poc !Mortaility and fecal pellet state variables
AED_REAL :: FGrazing_Limitation, f_T, f_Salinity, f_DO
AED_REAL :: pref_factor, Ctotal_prey !total concentration of available prey
AED_REAL :: food, grazing, respiration, mortality !Growth & decay functions
AED_REAL :: grazing_n, grazing_p !Grazing on nutrients
AED_REAL :: pon_excr, pop_excr, poc_excr !POM excretion rates
AED_REAL :: don_excr, dop_excr, doc_excr, delta_C !DOM excretion rates
!
!-------------------------------------------------------------------------------
!BEGIN
pon = 0.0 ; poc = 0.0 ; pop = 0.0 !## CAB [-Wmaybe-uninitialized]
! Retrieve current environmental conditions.
temp = _STATE_VAR_(data%id_tem) ! local temperature
salinity = _STATE_VAR_(data%id_sal) ! local salinity
oxy = _STATE_VAR_(data%id_oxy) ! local oxygen
! Retrieve current (local) state variable values.
IF (data%simDNexcr) dn_excr = _STATE_VAR_(data%id_Nexctarget)
IF (data%simDPexcr) dp_excr = _STATE_VAR_(data%id_Pexctarget)
IF (data%simDCexcr) dc_excr = _STATE_VAR_(data%id_Cexctarget)
IF (data%simPNexcr) pon = _STATE_VAR_(data%id_Nmorttarget)
IF (data%simPPexcr) pop = _STATE_VAR_(data%id_Pmorttarget)
IF (data%simPCexcr) poc = _STATE_VAR_(data%id_Cmorttarget)
DO zoop_i=1,data%num_zoops
! Retrieve this zooplankton group
zoo = _STATE_VAR_(data%id_zoo(zoop_i))
!Retrieve prey groups
Ctotal_prey = zero_
DO prey_i=1,data%zoops(zoop_i)%num_prey
prey(prey_i) = _STATE_VAR_(data%zoops(zoop_i)%id_prey(prey_i))
Ctotal_prey = Ctotal_prey + prey(prey_i)
ENDDO
grazing = zero_
respiration = zero_
mortality = zero_
! Get the grazing limitation function
fGrazing_Limitation = fPrey_Limitation(data%zoops,zoop_i,Ctotal_prey)
! Get the temperature function
f_T = fTemp_function(1, data%zoops(zoop_i)%Tmax_zoo, &
data%zoops(zoop_i)%Tstd_zoo, &
data%zoops(zoop_i)%theta_grz_zoo, &
data%zoops(zoop_i)%aTn, &
data%zoops(zoop_i)%bTn, &
data%zoops(zoop_i)%kTn, temp)
! Get the growth rate (/ s)
! grazing is in units of mass consumed/mass zoops/unit time
grazing = data%zoops(zoop_i)%Rgrz_zoo * fGrazing_Limitation * f_T
! Now determine available prey and limit grazing amount to
! availability of prey
! food is total amount of food in units of mass/unit volume/unit time
food = grazing * zoo
IF (Ctotal_prey < data%zoops(zoop_i)%num_prey * data%zoops(zoop_i)%Cmin_grz_zoo ) THEN
food = zero_
grazing = food / zoo
ELSEIF (food > Ctotal_prey - data%zoops(zoop_i)%num_prey * data%zoops(zoop_i)%Cmin_grz_zoo ) THEN
food = Ctotal_prey - data%zoops(zoop_i)%num_prey * data%zoops(zoop_i)%Cmin_grz_zoo
grazing = food / zoo
ENDIF
! Now determine prey composition based on preference factors and
! availability of prey
! Prey has been ordered in grazing preference
! So take food in order of preference up to availability minus
!value of minimum residual
! grazing_prey is in units of mass consumed/unit volumne/unit time
DO prey_i = 1,data%zoops(zoop_i)%num_prey
!Add up preferences for remaining prey
pref_factor = zero_
DO prey_j = prey_i,data%zoops(zoop_i)%num_prey
pref_factor = pref_factor + data%zoops(zoop_i)%prey(prey_j)%Pzoo_prey
ENDDO
IF (food * data%zoops(zoop_i)%prey(prey_i)%Pzoo_prey / pref_factor <= &
prey(prey_i) - data%zoops(zoop_i)%Cmin_grz_zoo) THEN
!Take fraction of left over food based on preference factor
grazing_prey(prey_i) = food * data%zoops(zoop_i)%prey(prey_i)%Pzoo_prey / pref_factor
ELSEIF (prey(prey_i) > data%zoops(zoop_i)%Cmin_grz_zoo) THEN
grazing_prey(prey_i) = prey(prey_i) - data%zoops(zoop_i)%Cmin_grz_zoo
ELSE
grazing_prey(prey_i) = zero_
ENDIF
!Food remaining after grazing from current prey
food = food - grazing_prey(prey_i)
ENDDO
! Now determine nutrient composition of food based on prey type
! At this stage only the AED model state variables have multiple
! nutrients (C,N&P) so assume all others have a single nutrient
! and thus not need to calculate nutrient excretion as is taken
! care of in the respiration term. 22/12/2011
! grazing_n is in units of mass N consumed/unit volume/unit time
! grazing_p is in units of mass P consumed/unit volume/unit time
grazing_n = zero_
grazing_p = zero_
phy_i = 0
DO prey_i = 1,data%zoops(zoop_i)%num_prey
IF (data%zoops(zoop_i)%prey(prey_i)%zoop_prey .EQ. _OGMPOC_) THEN
IF (poc > zero_) THEN
grazing_n = grazing_n + grazing_prey(prey_i) * pon/poc
grazing_p = grazing_p + grazing_prey(prey_i) * pop/poc
ELSE
grazing_n = zero_
grazing_p = zero_
ENDIF
ELSEIF (data%zoops(zoop_i)%prey(prey_i)%zoop_prey(1:_PHYLEN_).EQ. _PHYMOD_) THEN
phy_i = phy_i + 1
phy_INcon(phy_i) = _STATE_VAR_(data%zoops(zoop_i)%id_phyIN(phy_i))
phy_IPcon(phy_i) = _STATE_VAR_(data%zoops(zoop_i)%id_phyIP(phy_i))
grazing_n = grazing_n + grazing_prey(prey_i) / prey(prey_i) * phy_INcon(phy_i) /14.0
grazing_p = grazing_p + grazing_prey(prey_i) / prey(prey_i) * phy_IPcon(phy_i) /31.0
ELSEIF (data%zoops(zoop_i)%prey(prey_i)%zoop_prey(1:15).EQ.'aed_zooplankton') THEN
grazing_n = grazing_n + grazing_prey(prey_i) * data%zoops(zoop_i)%INC_zoo
grazing_p = grazing_p + grazing_prey(prey_i) * data%zoops(zoop_i)%IPC_zoo
ENDIF
ENDDO
! Get the salinity limitation.
f_Salinity = fSalinity_Limitation(data%zoops,zoop_i,salinity)
f_DO = 1.
IF (oxy zero_) THEN
_FLUX_VAR_(data%id_Nmorttarget) = &
_FLUX_VAR_(data%id_Nmorttarget) + ( -1.0 * grazing_prey(prey_i) * pon/poc)
_FLUX_VAR_(data%id_Pmorttarget) = &
_FLUX_VAR_(data%id_Pmorttarget) + ( -1.0 * grazing_prey(prey_i) * pop/poc)
ENDIF
ELSEIF (data%zoops(zoop_i)%prey(prey_i)%zoop_prey(1:_PHYLEN_).EQ. _PHYMOD_) THEN
phy_i = phy_i + 1
_FLUX_VAR_(data%zoops(zoop_i)%id_phyIN(phy_i)) = &
_FLUX_VAR_(data%zoops(zoop_i)%id_phyIN(phy_i)) + &
( -1.0 * grazing_prey(prey_i) / prey(prey_i) * phy_INcon(phy_i))
_FLUX_VAR_(data%zoops(zoop_i)%id_phyIP(phy_i)) = &
_FLUX_VAR_(data%zoops(zoop_i)%id_phyIP(phy_i)) + &
( -1.0 * grazing_prey(prey_i) / prey(prey_i) * phy_IPcon(phy_i))
ENDIF
ENDDO
! Now manage excretion contributions to DOM
IF (data%simDCexcr) THEN
_FLUX_VAR_(data%id_Cexctarget) = _FLUX_VAR_(data%id_Cexctarget) + &
(data%zoops(zoop_i)%fexcr_zoo * respiration * zoo + doc_excr)
ENDIF
IF (data%simDNexcr) THEN
_FLUX_VAR_(data%id_Nexctarget) = _FLUX_VAR_(data%id_Nexctarget) + (don_excr)
ENDIF
IF (data%simDPexcr) THEN
_FLUX_VAR_(data%id_Pexctarget) = _FLUX_VAR_(data%id_Pexctarget) + (dop_excr)
ENDIF
! Now manage messy feeding, fecal pellets and mortality contributions to POM
IF (data%simPCexcr) THEN
_FLUX_VAR_(data%id_Cmorttarget) = _FLUX_VAR_(data%id_Cmorttarget) + ( poc_excr)
ENDIF
IF (data%simPNexcr) THEN
_FLUX_VAR_(data%id_Nmorttarget) = _FLUX_VAR_(data%id_Nmorttarget) + ( pon_excr)
ENDIF
IF (data%simPPexcr) THEN
_FLUX_VAR_(data%id_Pmorttarget) = _FLUX_VAR_(data%id_Pmorttarget) + ( pop_excr)
ENDIF
ENDIF
! Export diagnostic variables
_DIAG_VAR_(data%id_grz ) = zoo*grazing*secs_per_day
_DIAG_VAR_(data%id_resp ) = zoo*respiration*secs_per_day
_DIAG_VAR_(data%id_mort ) = zoo*mortality*secs_per_day
ENDDO
END SUBROUTINE aed_calculate_zooplankton
!+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
END MODULE aed_zooplankton