# 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 ************************************

#-----------------------------------------------------------------------------
# Classes implementing mars requests and calculation of derived fields,
# e.g. total precipitation, wind speed + standard stuff.
# To load the classes within a macro, call load_param_classes.
#
# load_param_classes calls the function check_mars_order which checks that
# the order in which the fields are sorted in a mars retrieve is identical to
# the order when this was programmed. To do so it gets the ACTUAL array used
# for sorting fields in the mars module.
# This is important because in order to improve performance, one unique
# retrieve is done, then the fieldset is accessed using the sorting order.
# If the order changes, this does not work anymore.
#-----------------------------------------------------------------------------
function load_param_classes()
	load_list_tools()
	print("param classes loaded")
	check_mars_order()
	print("mars field order checked")
end load_param_classes

object generic_param(request:definition,params)

	global model
	model = -1

	global field
	field = nil
	function field
		return field
	end field

	function request()
		return request
	end request

	function member_count()
		if (request["members"] <> nil) then
			return request["members"]
		else
			return 1
		end if
	end member_count

	function save_model(f:fieldset)
		if (count(f) > 1) then
			rr = f[1]
		else
			rr = f
		end if
	    codes = grib_codes()
		model = getksec1(rr,codes.model.indx)
		return model
	end save_model

	function change_grib(field:fieldset,param)
		 return change_grib(field,param,[])
	end change_grib

	function change_grib(field:fieldset,param,l:list)
		values = l
	    codes = grib_codes()
		if (model <> -1) then
			values = values & [codes.model.indx,model]
		end if
		values = values & [codes.param.indx,param]
		return putksec1(field,values)
	end change_grib

	global mars
	mars = (
				type    : "fc",
				class   : "od",
				expver  : 0001,
				stream  : "oper",
				date    : date(-1),
				time    : 12,
				step    : [24,48,72,96,120,144,168,192,216,240],
				param   : params,
				levtype : "sfc"
		   )
	function mars
		return mars
	end mars

	function fieldset()
		if (field = nil) then
		   field = get_fieldset()
		end if
		return field
	end fieldset

	function get_fieldset()
		return retrieve(mars(),request())
	end get_fieldset
	
end generic_param

object ff10_param(request) : generic_param(request,["10u","10v"])
   
	function get_fieldset()
		req = (mars(),request())
		res = retrieve(req)

		codes = grib_codes()
		save_model(res)
		#-------- calculate the wind speed ----------
		nmembers = member_count()
		u = nil
		v = nil
		indx = 1
		for i = 1 to count(res) / (2 * nmembers) do
			u = u & res[indx,indx+nmembers*2-2,2]
			v = v & res[indx+1,indx+nmembers*2-1,2]
			indx = indx + nmembers*2
		end for
		ff = sqrt(u*u+v*v)
		field = change_grib(ff,codes.param.ff10)
		return field
	end fieldset

end ff10_param

function ff10_param(request,val)
	return ff10_param(request)
end ff10_param


object tp_param(request:definition,cumulation:number) : generic_param(request,["lsp","cp"])
   
	function get_fieldset()
		#-------- build the MARS request ----------
		req = (mars(), request())
		steplist = req.step
		step1 = req.step[1]
		step0 = step1 - cumulation
		limit=1
		if (step0 > 0) then
			if (count(steplist) > 1) then
				req.step = [step0] & req.step
			else
				req.step = [step0] & [req.step]
			end if
			limit=0
		end if
		res = retrieve(req)
		save_model(res)

		count = count(res)
		tp = res[1,count-1,2] + res[2,count,2]
		nmembers = member_count()
		count = count(tp)
		field = tp[1+nmembers,count] - tp[1,count-nmembers]
		if (limit) then
			field = tp[1,nmembers] & field
		end if

		codes = grib_codes()
		rain = nil
		for i = 1 to count(field) / nmembers do
			indx = (i-1) * nmembers
			rain = rain & change_grib(field[indx+1,indx+nmembers],codes.param.tp,[codes.step1.indx,steplist[i]-cumulation,codes.step2.indx,steplist[i],codes.timerange.indx,5])
		end for
		return rain
	end fieldset

end tp_param
