# Metview Macro

# **************************** LICENSE START ***********************************
#
# Copyright 2012 ECMWF. This software is distributed under the terms
# of the Apache License version 2.0. In applying this license, ECMWF does not
# waive the privileges and immunities granted to it by virtue of its status as
# an Intergovernmental Organization or submit itself to any jurisdiction.
#
# ***************************** LICENSE END ************************************


#**************************************************************************
# Function      : mvl_flextra_etadot
#
# Syntax        : fieldset mvl_flextra_etdot(spf:fieldset,
#                                       etadot:fieldset)
#
# Author (date) : Sandor Kertesz, ECMWF (29/12/2011)
#
# Category      : INTERPOLATION
#
# OneLineDesc   : Computes the time derivate of eta fields needed by FLEXTRA
#
# Description   : This function multiplies the time derivative of eta (a.k.a. etadot)
#		  		  fields by a factor to generate the fields needed by FLEXTRA.
# 		          The formula applied in this function is as follows ("delta" stands
#                 for the partial derivative in the formula):   
# 
#		          etadot_flextra = etadot_IFS * delta(pressure)/delta(eta)					
#	
#		          To achieve the highest possible precision vectors are used for carrying out
#			      the computations.
#
#				  The function selects the first "sp" field from fieldset "spf" 
#                 and reads the "date", "time", "step", "gridType" and "numberOfValues" 
#                 parameters out of it. Then only those etadot fields from fieldset 
#                 "etadot" that are matching these reference parameters are transformed.
#
#                 Fieldset "etadot" is sorted according to "shorName" and "level"
#                 before the transformation takes place. This means that the resulting
#                 fieldset might contain the fields in a different order than the input
#                 "etadot" fieldset.
#
#                 Please note that this function works only for regular lat-long grids!
#
# Parameters    : spf  - fieldset containing the surface pressure field
#                 etadot - fieldset on model levels containing the etadot fields 
# 
# Return Value  : fieldset containing the etadot fields needed by FLEXTRA
#
# Dependencies  : none
#
# Example Usage : 
#
# **************************************************************************


function mvl_flextra_etadot(spf:fieldset,etadot:fieldset)

#Initialise the output fieldset
etadot_out=nil

#Get sp field
sp=nil
loop f in spf
	if sp = nil and grib_get_string(f,"shortName") = "sp" then
		sp=f
	end if	
end loop
		
#Get some reference parameters from sp. These parameters 
#must have the same value for all the etadot fields!

rDate=grib_get_string(sp,"date")
rTime=grib_get_string(sp,"time")
rStep=grib_get_long(sp,"step")
rType=grib_get_string(sp,"gridType")
rNum=grib_get_long(sp,"numberOfValues")

if rType <> "regular_ll" then
	print("Grid type: ", rType)
	fail("Non-supported grid type:  must be regular_ll!")
end if	

#Read surface pressure into a vector
spVec=values(sp)

#Reference pressure
p00=101325.
               
#Initialise some parameterssetgribprecision(16)
abIsRead=0
lastCnt=0

#Sort according to shortname and level
etadot=sort(etadot,["shortName","level"],">")

loop f in etadot
	sName=grib_get_string(f,"shortName")			

	#Read A and B coefficients
	if sName = "etadot" and abIsRead = 0 then
	
		pv=grib_get_double_array(f,"pv")
		nLev=count(pv)/2-1
		ac=vector(nLev+1)
		bc=vector(nLev+1)

		for i=1 to nLev+1 do
			ac[i]=pv[i]
			bc[i]=pv[nLev+1+i]
		end for

		abIsRead=1

	end if

	#Read and process etadot fields
	if sName = "etadot" then
	
		#If parameters do not match values from the sp field
		# simply concatenates the field to the output fieldset
		if rDate <> grib_get_string(f,"date") or
	       rTime <> grib_get_string(f,"time") or
           rStep <> grib_get_long(f,"step") or
		   rType <> grib_get_string(f,"gridType") or
           rNum  <> grib_get_long(f,"numberOfValues") then
		 	
		   etadot_out = etadot_out &f 
		   
		#Otherwise it does the etadot computation   	
		else 	  		
		   lev=grib_get_long(f,"level")
		   delta_ac=ac[lev+1]-ac[lev]
		   delta_bc=bc[lev+1]-bc[lev]
		
		   #print("lev=",lev," a=",ac[lev]," b=",bc[lev]," delta_a=",delta_ac," delta_bc=",delta_bc) 		
		   
		   #Get values
           fVec=values(f)
           
           #Compute new values          
       	   fVec=2.*fVec*spVec*(delta_ac/spVec+delta_bc)/(delta_ac/p00+delta_bc)
         
		   if lastCnt > 0 then
		     lastLev=grib_get_long(etadot_out[lastCnt],"level")
		     if lastLev <> lev-1 then
		   	    fail("Missing level: ", lev-1," !")
		     end if	 			  
		     #Subtract the values of the previous level
		     fVec=fVec-fVecPrev
		  end if
  
          #Add the results to the output grib
		  etadot_out = etadot_out & set_values(f,fVec)
		
		  #Save values of the previous level
		  fVecPrev=fVec
		
		  lastCnt=count(etadot_out)
	   end if

	#Other fields
	else
		etadot_out = etadot_out &f 
	end if		   

end loop	

return etadot_out

end flextraEtaDot
