/***************************** LICENSE START ***********************************

 Copyright 2012 ECMWF and INPE. 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 *************************************/

#include "MvMiscelaneous.h"
#include "MvPath.hpp"

#if defined(METVIEW_AIX_XLC)
inline double exp10(const double r) { return exp(r*2.302585093);} // exp(r*ln(10))
#endif

namespace metview {

const double cTMELT = 273.16;
const double cR3LES =  17.502;
const double cR3IES =  22.587;
const double cR4LES =  32.19;
const double cR4IES =  -0.7;
const double cRD    =  287.05;
const double cRV    =  461.51;
const double cRESTT =  611.21;
const double cR2ES  = cRESTT*cRD/cRV;
const double cVTMPC1= cRV/cRD-1.;
const double RAD    = 180./3.14159;

// Call a shell command
// Returns the result and an error message
void shellCommand(string &command, stringstream& out,stringstream& err)
{
	FILE *in;
	char cbuf[512];

	// Create a temporary file
	string ftmp = MakeTmpPath("temp");
	string cmd = command + " 2>" + ftmp;

	if (!(in = popen(cmd.c_str() ,"r")) )
		return;

	while(fgets(cbuf, sizeof(cbuf), in) != NULL)
		out << cbuf;

	pclose(in);

	if (!(in = fopen(ftmp.c_str() ,"r")) )
		return;

	while(fgets(cbuf, sizeof(cbuf), in) != NULL)
		err << cbuf;

	fclose(in);

	// Remove temporary file
	string com = "rm -f " + ftmp;
	system(com.c_str());
}

bool createWorkDir(string prefix,string& tmpPath,string& errTxt)
{
 	string tmpRoot;
	
	char *mvtmp=getenv("METVIEW_TMPDIR");
	if (mvtmp == 0)  
	{	
		errTxt="No env variable METVIEW_TMPDIR is not defined!";
		return false;
	}
	else
	{
		tmpRoot=string(mvtmp);
	}

	time_t sec=time(NULL);
    pid_t pid = getpid();

 	std::stringstream out;
  	out << tmpRoot << "/" + prefix + "_" << sec << "_" << pid; 
	tmpPath=out.str();
	
	if(mkdir(tmpPath.c_str(),0777) != 0)
	{
		errTxt="Could not genarate work directory: " + tmpPath;
		return false;
	}
	
	return true;
}  

/*! 
  \brief computes the saturation  mixing ratio

  This method computes the saturation mixing ratio.

  \param t  temperature in K 
  \param p  pressure in Pa
  \return   saturation mixing ratio in kg/kg 
*/

double saturationMixingRatio(double t, double p)
{
	double e=saturationVapourPressure(t); 
  	return 0.621981*e/(p-e); 
}

/*! 
  \brief computes the relative himidity

  This method computes the relative humidity.

  \param t  temperature in K 
  \param p  pressure in Pa
  \param q  specific humidity in kg/kg
  \return   relative humidity (0-1) 
*/

double relativeHumidity(double t, double p,double q)
{
	double es=saturationVapourPressure(t);
	double e=vapourPressure(p,q);
	
  	return e/es; 
}

/*! 
  \brief computes the relative himidity from dewpoint temperature

  This method computes the relative humidity from dewpoint temperature.

  \param t  temperature in K 
  \param td dewpoint temperature in K 
  \return   relative humidity (0-1) 
*/

double relativeHumidityFromTd(double t, double td)
{
	double es=saturationVapourPressure(td)/saturationVapourPressure(t);	
  	return es; 
}

/*! 
  \brief computes the specific humidity from relative humidity

  This method computes specific humidity from relative humidity

  \param t  temperature in K 
  \param p  pressure in Pa
  \param r  relative humidity (0-1) 
  \return   specific humidity in kg/kg 
*/

double specificHumidity(double t, double p,double r)
{
  	double ws=saturationMixingRatio(t,p);
	double w=r*ws;
	
	return w/(1.+w);
}

/*! 
  \brief computes the specific humidity from dewpoint temperature

  This method computes specific humidity from dewpoint temperature

  \param t  temperature in K 
  \param p  pressure in Pa
  \param td  dewpoint temperature in K 
  \return   specific humidity in kg/kg 
*/

double specificHumidityFromTd(double t, double p,double td)
{
  	double r=relativeHumidityFromTd(t,td);
  	return specificHumidity(t,p,r);

}

/*! 
  \brief computes the saturation vapour pressure over water from temperature
 
  This method computes the saturation vapour pressure
  over water and ice from temperature.

  \param t temperature in K 
  \return pressure in Pa   
*/   

double saturationVapourPressure(double t)
{
	double c1    = 611.21;
	double c3l   = 17.502;
	double c4l   = 32.19;
	double c3i   = 22.587;
	double c4i   = -0.7;
	double t0      = 273.16;
	double ti= 250.16;
	
	//Saturation vapour pressure over water
	double es_water = c1*exp(c3l*(t-t0)/(t-c4l)); 
	
	//Saturation vapour pressure over ice
	double es_ice  = c1*exp( c3i*(t-t0)/(t-c4i)); 

	//fraction of liquid water	
	double alpha;
	if(t <= ti)
	  	alpha=0.;
	else if (t > ti && t <t0)
	  	alpha=(t-ti)/(t0-ti);
	else
	  	alpha=1.;
		
	return alpha*es_water+(1.-alpha)*es_ice;
}	

/*! 
  \brief computes the vapour pressure over from pressure and spec humidity
 
  This method computes the vapour pressure
  from pressure and specific humidity.

  \param p pressure in Pa 
  \param q specific humidity in kg/kg
  \return vapour pressure in Pa   
*/   
double vapourPressure(double p,double q)
{
	double w=q/(1-q);
	return p*w/(0.621981+w);
}  
  
/*! 
  \brief computes the water vapour ppmv from pressure and specific humidity
 
  This method computes the water vapour ppmv
  from pressure and specific humidity.

  \param p pressure in Pa 
  \param q specific humidity in kg/kg
  \return humidity in ppm   
*/     
  
double vapourPPMV(double p,double q)
{
	double pw=vapourPressure(p,q);
	return pw/(p-pw)*1000000;
}  
  
/*! 
  \brief computes the ozone ppmv from mixing ratio
 
  This method computes the ozone ppmv
  from from mixing ratio.

  \param r ozone mixing ratio in kg/kg 
  \return ozone in ppmv  
*/     
  
double ozonePPMV(double r)
{
	double mmr2vmr = 28.97/48.0;
	return 1000000*r*mmr2vmr;
}

double dewPointFromQ(double p, double t, double q, const string& formula)
{
   const string cMixedFormula( "MIXED_PHASE_0_TO_-23" );
   const string cSaturationIce( "SATURATION_OVER_ICE" );
   double ZCVM3, ZCVM4;

   if( formula == cMixedFormula )
   {
      double rtwat   = cTMELT;
      double rtice   = cTMELT - 23.0;
      double foealfa = min(1.,pow(((max(rtice,min(rtwat,t))-rtice)/(rtwat-rtice)),2.0) );

      ZCVM3 = foealfa*cR3LES + (1.-foealfa)*cR3IES;
      ZCVM4 = foealfa*cR4LES + (1.-foealfa)*cR4IES;
   }
   else if ( formula == cSaturationIce )
   {
      if( t > cTMELT )
      {
         ZCVM3=cR3LES;
         ZCVM4=cR4LES;
      }
      else
      {
         ZCVM3=cR3IES;
         ZCVM4=cR4IES;
      }
   }
   else  // SATURATION OVER WATER
   {
      ZCVM3=cR3LES;
      ZCVM4=cR4LES;
   }

   double ZFRAC = log(p*q/(cR2ES*(1.+cVTMPC1*q)))/ZCVM3;

   return (cTMELT-ZFRAC*ZCVM4)/(1.-ZFRAC);
}

double speed( double u, double v )
{
   return sqrt(pow(u,2) + pow(v,2));
}

double direction( double u, double v )
{
   return (-90.0 - atan2(v,u)*RAD);
}

} //namespace metview




