/* * Copyright (c) 2019 by Alfonso Crisci, Marco Morabito e Alessandro Messeri
   * * @authors Alfonso Crisci, Marco Morabito e Alessandro Messeri
  * * Corresponet Email: a.crisci@ibe.cnr.it
  * * This program 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 2 
  * * of the License, or (at your option) any later version, 
  * * provided that any use properly credits the author. 
  * * This program 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 at http://www.gnu.org * * */


/*
 * Define global constants for functions.
 */


var    Patm = 101325.0; // pascal
var    CpAir= 1004.0;
var    CpWat= 4186.0;
var    CpVap= 1805.0;
var    Hfg= 2501000.0;
var    RAir= 287.055;
var    TKelConv= 273.15;
var    PI   = Math.PI,
       pi = Math.PI,
       twopi = 2 * pi,
       rad  = PI / 180,
       radians = PI / 180,
       degrees = 180 / PI,
       J1970 = 2440588,
       J2000 = 2451545;

/*
 * Format  functions.
 */

function OneDec(c) 
{
    return Math.round(10 * c) / 10;
}

function TwoDec(c) 
{
    return Math.round(100 * c) / 100;
}
function ThreeDec(c) 
{
    return Math.round(1000 * c) / 1000;
}

function FourDec(c) 
{
    return Math.round(10000 * c) / 10000;
}

function scientificNotation(c,e)
 {
    return c.toPrecision(e);
}

/** * @(#)pnorm.js and qnorm.js 
  * * Copyright (c) 2000 by Sundar Dorai-Raj
  * * @author Sundar Dorai-Raj
  * * Email: sdoraira@vt.edu
  * * This program 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 2 
  * * of the License, or (at your option) any later version, 
  * * provided that any use properly credits the author. 
  * * This program 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 at http://www.gnu.org * * */

  // "Applied Statistics Algorithms" (1985)
  //  P. Griffiths and I. D. Hill, editor

function pnorm(z,tail) {
    
    // Algorithm AS66 Applied Statistics (1973) vol 22 no.3
    // Computes P(Z<z)
    
    if( tail === undefined ) { tail = false;};
    
    z=parseFloat(z);
    var ltone= 7.0;
    var utzero= 18.66;
    con= 1.28;
    a1 = 0.398942280444;
    a2 = 0.399903438504;
    a3 = 5.75885480458;
    a4 = 29.8213557808;
    a5 = 2.62433121679;
    a6 = 48.6959930692;
    a7 = 5.92885724438;
    b1 = 0.398942280385;
    b2 = 3.8052e-8;
    b3 = 1.00000615302;
    b4 = 3.98064794e-4;
    b5 = 1.986153813664;
    b6 = 0.151679116635;
    b7 = 5.29330324926;
    b8 = 4.8385912808;
    b9 = 15.1508972451;
    b10= 0.742380924027;
    b11= 30.789933034;
    b12= 3.99019417011;

    
   if(z<0) {
      tail=!tail;
      z=-z;
    }
    if(z<=ltone || tail && z<=utzero) {
      y=0.5*z*z;
      if(z>con) {
        alnorm=b1*Math.exp(-y)/(z-b2+b3/(z+b4+b5/(z-b6+b7/(z+b8-b9/(z+b10+b11/(z+b12))))));
      }
      else {
        alnorm=0.5-z*(a1-a2*y/(y+a3-a4/(y+a5+a6/(y+a7))));
      }
    }
    else {
      alnorm=0;
    }
    if(!tail) alnorm=1-alnorm;
      return(alnorm);
  }

function qnorm(p) {
    
    // ALGORITHM AS 111, APPL.STATIST., VOL.26, 118-121, 1977.
    // Computes z=invNorm(p)
    
    p=parseFloat(p);
    split=0.42;
    a0=  2.50662823884;
    a1=-18.61500062529;
    a2= 41.39119773534;
    a3=-25.44106049637;
    b1= -8.47351093090;
    b2= 23.08336743743;
    b3=-21.06224101826;
    b4=  3.13082909833;
    c0= -2.78718931138;
    c1= -2.29796479134;
    c2=  4.85014127135;
    c3=  2.32121276858;
    d1=  3.54388924762;
    d2=  1.63706781897;
    q=p-0.5;
    
    if(Math.abs(q)<=split) {
      r=q*q;
      ppnd=q*(((a3*r+a2)*r+a1)*r+a0)/((((b4*r+b3)*r+b2)*r+b1)*r+1);
    }
    else {
      r=p;
      if(q>0) r=1-p;
      if(r>0) {
        r=Math.sqrt(-Math.log(r));
        ppnd=(((c3*r+c2)*r+c1)*r+c0)/((d2*r+d1)*r+1);
        if(q<0) ppnd=-ppnd;
      }
      else {
        ppnd=0;
      }
    } 
    return(ppnd);
  }


/**
 * Air Pressure a elevation  
 *
 * @param {number} press,topo
 * @return {number}
 * 
 */

function pheight(press,topo)
{
  var pressalt= press * Math.pow((1-(2.25577*(0.00001)*topo)),5.25588);
  return(pressalt)
}

/**
 * Error function
 *
 * @param {number} x
 * @return {number}
 * 
 */

function erf(x) {x=parseFloat(x); 
                 return(2 * pnorm(x * Math.sqrt(2)) - 1);}




/**
 * Wind reduction in boundary layer. 
 * @param {number} x,ref,fin
 * @return {number}
 * 
 */

function reducewind(x,ref,fin) {  
                                        if( ref === undefined ) { tresh = 10;};
                                        if( fin === undefined ) { fin = 2;};
                                        return(x*1/(Math.log(ref/0.01)/Math.log(fin/0.01)));
                                    
                               }



///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Math & Trigonometric functions.

function radToDeg(angleRad) 
{
  return (180.0 * angleRad / Math.PI);
}

function degToRad(angleDeg) 
{
  return (Math.PI * angleDeg / 180.0);
}

function compass_16(direction) 
 {
  var dir = ["N", "NNE", "NE", "ENE", "E", "ESE", "SE",
             "SSE", "S", "SSW", "SW", "WSW", "W", "WNW",
            "NW", "NNW"];
  var dirint=(((direction+11.25)/22.5));							   
  return(dir[parseInt(dirint % 16)]);
}



function compass_8(direction) 
{ var dir = ["N",  "NE", "E",  "SE",
             "S",  "SW", "W", "NW"];
  var dirint=(((direction+22.5)/45));							   
  return(dir[parseInt(dirint % 8)]);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Math & Trigonometric functions.


String.prototype.toDate = function(format)
{
  var normalized      = this.replace(/[^a-zA-Z0-9]/g, '-');
  var normalizedFormat= format.toLowerCase().replace(/[^a-zA-Z0-9]/g, '-');
  var formatItems     = normalizedFormat.split('-');
  var dateItems       = normalized.split('-');

  var monthIndex  = formatItems.indexOf("mm");
  var dayIndex    = formatItems.indexOf("dd");
  var yearIndex   = formatItems.indexOf("yyyy");
  var hourIndex     = formatItems.indexOf("hh");
  var minutesIndex  = formatItems.indexOf("ii");
  var secondsIndex  = formatItems.indexOf("ss");

  var today = new Date();

  var year  = yearIndex>-1  ? dateItems[yearIndex]    : today.getFullYear();
  var month = monthIndex>-1 ? dateItems[monthIndex]-1 : today.getMonth()-1;
  var day   = dayIndex>-1   ? dateItems[dayIndex]     : today.getDate();

  var hour    = hourIndex>-1      ? dateItems[hourIndex]    : today.getHours();
  var minute  = minutesIndex>-1   ? dateItems[minutesIndex] : today.getMinutes();
  var second  = secondsIndex>-1   ? dateItems[secondsIndex] : today.getSeconds();

  return new Date(year,month,day,hour,minute,second);
};

function sun_data(strtime,lat,lon,parameter) 
   {
    var datetime=new Date(strtime); 
    var udtTimedHours=datetime.getHours() - 0;
    var udtTimedMinutes =datetime.getMinutes() - 0;
    var udtTimedSeconds = datetime.getSeconds() - 0;
    var udtLocationdLongitude = lon - 0;
    var udtLocationdLatitude = lat - 0;
    var dEarthMeanRadius = 6371.01;
    var dAstronomicalUnit = 149597890;
    var dDecimalHours = udtTimedHours + (udtTimedMinutes + udtTimedSeconds / 60) / 60;
    var dJulianDate = datetime.valueOf() / (1000.0 *60.0*60.0 * 24.0) - 0.5  + J1970;
    var dElapsedJulianDays = dJulianDate - 2451545;
    var dOmega = 2.1429 - 0.0010394594 * dElapsedJulianDays;
    var dMeanLongitude = 4.895063 + 0.017202791698 * dElapsedJulianDays;
    var dMeanAnomaly = 6.24006 + 0.0172019699 * dElapsedJulianDays;
    var dEclipticLongitude = dMeanLongitude + 0.03341607 * Math.sin(dMeanAnomaly) + 3.4894E-4 * Math.sin(2 * dMeanAnomaly) - 1.134E-4 - 2.03E-5 * Math.sin(dOmega);
    var dEclipticObliquity = 0.4090928 - 6.214E-9 * dElapsedJulianDays + 3.96E-5 * Math.cos(dOmega);
    var dSin_EclipticLongitude = Math.sin(dEclipticLongitude);
    var dY = Math.cos(dEclipticObliquity) * dSin_EclipticLongitude;
    var dX = Math.cos(dEclipticLongitude);
    var dRightAscension = Math.atan2(dY, dX);
    0 > dRightAscension && (dRightAscension += twopi);
    var dDeclination = Math.asin(Math.sin(dEclipticObliquity) * dSin_EclipticLongitude);
    var dGreenwichMeanSiderealTime = 6.6974243242 + 0.0657098283 * dElapsedJulianDays + dDecimalHours;
    var dLocalMeanSiderealTime = (15 * dGreenwichMeanSiderealTime +udtLocationdLongitude) * rad;
    var dHourAngle = dLocalMeanSiderealTime - dRightAscension;
    var dLatitudeInRadians = udtLocationdLatitude * rad;
    var dCos_Latitude = Math.cos(dLatitudeInRadians);
    var dSin_Latitude = Math.sin(dLatitudeInRadians);
    var dCos_HourAngle = Math.cos(dHourAngle);
    var udtSunCoordinatesdZenithAngle = Math.acos(dCos_Latitude * dCos_HourAngle * Math.cos(dDeclination) + Math.sin(dDeclination) * dSin_Latitude);
    dY = -Math.sin(dHourAngle);
    dX = Math.tan(dDeclination) * dCos_Latitude - dSin_Latitude * dCos_HourAngle;
    var udtSunCoordinatesdAzimuth = Math.atan2(dY,dX);
    0 > udtSunCoordinatesdAzimuth && (udtSunCoordinatesdAzimuth += twopi);
    udtSunCoordinatesdAzimuth /= rad;
    var dParallax = dEarthMeanRadius / dAstronomicalUnit * Math.sin(udtSunCoordinatesdZenithAngle);
    udtSunCoordinatesdZenithAngle = (udtSunCoordinatesdZenithAngle + dParallax) / rad;
    var azimuth = udtSunCoordinatesdAzimuth;
    var zenith = udtSunCoordinatesdZenithAngle;
    var elevation = 90 - udtSunCoordinatesdZenithAngle;
    if (elevation > 85.0) {var refractionCorrection = 0.0;} 
        else {
        var te = Math.tan (degToRad(elevation));
        if (elevation > 5.0) 
            {var refractionCorrection = 58.1 / te - 0.07 / (te*te*te) + 0.000086 / (te*te*te*te*te);} 
        else if (elevation > -0.575) 
               {var refractionCorrection = 1735.0 + elevation * (-518.2 + elevation * (103.4 + elevation * (-12.79 + elevation * 0.711) ) );}  
        else {var refractionCorrection = -20.774 / te;}
        refractionCorrection = refractionCorrection / 3600.0;
    }

    var solarZen = zenith - refractionCorrection;
     
    if ( parameter == "azimuth") {return(azimuth)}
    else if ( parameter == "zenith") {return(zenith)}
    else if ( parameter == "solarZenith") {return(solarZen)}
    else if ( parameter == "altitude") {return(elevation)}
    else if ( parameter == "declination") {return(dDeclination*(180/PI))}
    else if ( parameter == "JD") {return(dJulianDate)}
    else { return("Parameter not indicated!")};
     
}



    

/**
 * Given t air temperature (Celsius degrees), rh relative humidity (%) , wind speed in m per second, global solar radiation in  Watt on square meter
 * tg globometric temperature gives, solar zenith in radians,  pair Air Pressure in millibar (hPa), 
 * alb_sfc mean albedo surface, ratio diffuse and  directed solar radiation and irad if radiation is computed in 
 * in heat globe realease the function computes
 * Wet-bulb globe temperature (WBGT) index following Liljegren scheme . 
 * @param {number}t,rh,wind,solar,zenith,pair,alb_sfc,fdir,irad.
 * @return {number}
 * @customfunction
 */

function wbgt_liljegren(t,rh,wind,solar,zenith,tg,pair,alb_sfc,fdir,irad,diam_globe) 
         {
          var wbgt;
          if( pair === undefined ) {pair = 1013.25;};
          if( alb_sfc === undefined ) {alb_sfc = 0.4;};
          if( fdir === undefined ) { fdir = 0.8;}; 
          if( irad === undefined ) {irad = 1;};
          if( diam_globe === undefined ) {diam_globe=0.0508;};
                
          if( tg === undefined ) { tg =Tglob_sphere(t,rh,wind,solar,zenith,pair,alb_sfc,fdir,diam_globe)};
                     
          var tw = natural_wetbulb(t,rh,wind,solar,zenith,pair,alb_sfc,fdir,irad);
           
          wbgt = 0.7*tw+0.2*tg+0.1*t;
          return wbgt;
}

/**
 * Given t air temperature (Celsius), rh relative humidity (%) and Tg globometric temperature gives  Wet-bulb globe temperature (WBGT) index indoor. 
 * @param {number} t,rh,tg,pa 
 * @return {number}
 * @customfunction
 */

function wbgt_stull(t,rh,tg) 
              {
              var wbgt;
              var tw = wetbulb_stull(t,rh)
              wbgt = 0.7*tw+0.2*tg+0.1*t;
              return wbgt;
           }


/**
 * Given  tg globometric of sphere . 
 * @param {number} t,rh,speed,solar,zenith,pair,alb_sfc,fdir,diam
 * @return {number}
 * @customfunction
 */

function Tglob_sphere(t,rh,speed,solar,zenith,pair,alb_sfc,fdir,diam)
                        {
                        if( solar < 5 ) { return(t)};   
                        if(zenith === undefined )   {zenith = 0.0001;};
                        if(pair === undefined )     { pair =1013.25;};
                        if(alb_sfc === undefined ) {alb_sfc = 0.4;};
                        if(fdir === undefined )     { fdir = 0.8;}; 
                        if(zenith <= 0 ){ zenith = 0.0000000001;};
                        if(zenith > 1.57 ){ zenith = 1.57;};
                        
                        var converge,cza,dT,Tref,h,Tglobe,tmp_globe;
                           zenith=zenith/(180/Math.PI);
                           converge = 0.05;
                           cza = Math.cos(zenith);

                        var emis_air=emis_atm(t,rh);
                        var speedmin = 0.1;  
                        var alb_globe = 0.05;
                        var emis_globe = 0.95;
                        var emis_sfc = 0.999;
                        var stefanb = 0.0000000567;
                        var Tair = t + 273.15;
                        var Tsfc = t + 273.15;
                        var Tglobe_prev = t + 273.15;
                          
                        var iter=1;
                          
                        do {
                           Tref = 0.5 * (Tglobe_prev + Tair);
                           h = h_sphere_in_air(Tref, speed, pair,speedmin, diam);
                           tmp_globe= 0.5 * (emis_air * Math.pow( Tair,4) + Math.pow(Tsfc,4)) -
                                      h / (emis_globe * stefanb) * (Tglobe_prev - Tair) +
                                      solar / ((2 * emis_globe * stefanb) * (1 - alb_globe) * (fdir * (1 / (2 * cza) - 1) + 1 + alb_sfc)); 
                          
                           Tglobe =Math.pow(tmp_globe ,0.25);
                          
                           dT = Tglobe - Tglobe_prev;
                           
                           if(Math.abs(dT) < converge) { Tglobe = Tglobe - 273.15;break;} else {Tglobe_prev =Tglobe_prev+0.01;}
                                                        iter=iter+1;
                           } while ( iter < 1000);
                          
                           if ( iter===1000) {Tglobe=-999};
                          
                          return(Tglobe);
                         }
  
/**
 * Given air temperature (Celsius), relative humidity (%)  gives natural wetbulb in celsius degrees.
 * Formulation from Stull 2011, Journal of Applied Meteorology and Climatology.
 * @param {number} t,rh
 * @return {number}
 * @customfunction 
 */

function wetbulb_stull(t,rh) 
{
     c = new Array(6);
     c[0] =0.151977;
     c[1] =8.313659;
     c[2] =1.676331;
     c[3] =0.00391838;
     c[4] =0.023101;
     c[5] =4.686035;

  
  
    var wetbulb = t * Math.atan(c[0] * Math.sqrt(rh + c[1])) 
                     + Math.atan(t + rh) - Math.atan(rh - c[2]) 
                     + c[3] * (Math.pow(rh,3/2)) * Math.atan(c[4] * rh) - c[5];
    return(wetbulb)
}

/**
 * Given air temperature (Celsius), relative humidity (%) and pressure ( pa) gives natural wetbulb in Ceslius degrees.
 * Brice and HALL vapor pressure https://www.weather.gov/epz/wxcalc_rh
 * @param {number} t, rh, pair
 * @return {number}
 * @customfunction
 */

function wetbulb_brice_hall(t,rh,pair)
			{  
              if (pair == undefined) {pair = 1013.25};
              var Ewguess,Eguess,wetbulb,cursign;
              var Twguess = 0;
			  var incr = 1;
			  var previoussign = 1;
			  var Edifference = 1;
	          var E2 = pvap(t,rh);

			  outerloop:
               
				while (Math.abs(Edifference) > 0.005) 
				{
					Ewguess = 6.112 * Math.exp((17.67 * Twguess) / (Twguess + 243.5));
					Eguess = Ewguess - (pair) * (t - Twguess) * 0.00066 * (1 + (0.00115 * Twguess));
					Edifference = E2 - Eguess;
					
					if (Edifference == 0)
					{
						break outerloop;

					} else {
						if (Edifference < 0)
						{
							cursign = -1;
							if (cursign != previoussign)
							{
								previoussign = cursign;
								incr = incr/10;
							} else {
								incr = incr;
							}
						} else {
							cursign = 1;
							if (cursign != previoussign)
							{
								previoussign = cursign;
								incr = incr/10;
							} else {
								incr = incr;
							}
						}
					}
					
					Twguess = Twguess + incr * previoussign;
					
				}
				wetbulb = Twguess;
				return wetbulb;
			}	


/**
 * Given t air temperature (Celsius degrees), rh relative humidity (%) , wind speed in m per second,
 * global solar radiation in watt on square meters, solar zenith in radians, pair Air Pressure in millibar (hPa), 
 * alb_sfc mean albedo surface, ratio diffuse and  directed solar radiation and irad if radiation is computed in 
 * in heat globe realease the function computes
 * natural wet-bulb temperature index following Liljegren scheme . 
 * @param {number} t,rh,wind,solar,zenith,pair,alb_sfc,fdir,irad
 * @return {number}
 * @customfunction
 */


function natural_wetbulb(t,rh,wind,solar,zenith,pair,alb_sfc,fdir,irad)
                        {
                        if( solar < 10 ) { solar == 0};  
                        if( zenith === undefined ) {zenith = 0.00001;};
                        if( pair === undefined ) {pair = 1013.25;};
                        if( alb_sfc === undefined ) {alb_sfc = 0.4;};
                        if( fdir === undefined ) { fdir = 0.8;}; 
                        if( irad === undefined ) {irad = 1;};
                           zenith=zenith/(180/Math.PI);
                          
                        var converge,cza,dT,Tref,h,Twb,Fatm,density,eair;
                       
                        converge = 0.05;
                          
                        if(zenith <= 0 ){ zenith = 0.0000000001;};
                        if(zenith > 1.57 ){ zenith = 1.57;};
                          
                        var speedmin = 0.1;  
                        var emis_sfc = 0.999;
                        var stefanb=0.000000056696;
                           
                        /* heat capaticy of dry air at constant pressure */
                        
                        var cp=1003.5 ;
                        var m_air=28.97;
                        var m_h2o=18.015;
                        var r_gas=8314.34;
                        var r_air=r_gas / m_air;
                        var ratio=cp * m_air/ m_h2o;
                        var Pr=cp / (cp + (1.25 * r_air));
  
                        // Wick constants
                        
                        var emis_wick=0.95 // emissivity
                        var alb_wick=0.4 // albedo
                        var diam_wick=0.007 // diameter (in m)
                        var len_wick=0.0254 // length (in m)
  
                        // Globe constants
                        
                    
                        var Tair = t + 273.15;
                        var Tsfc = t + 273.15;
                        var Twb_prev = dewpoint(t,rh) + 273.15;
                        var emis_air= emis_atm(t,rh);
                            eair = (rh/100) * esat(Tair);   
                             density = (pair * 100) / (Tair * r_air);
                       
                        var iter=1;
                          
                        do {
                           
                            Tref = 0.5 * (Twb_prev + Tair);
                          
                            // Radiative heating term	
                          
                           Fatm = stefanb * emis_wick * (0.5 * (emis_air * Math.pow(Tair, 4) 
                                   + emis_sfc * Math.pow(Tsfc, 4)  - Math.pow(Twb_prev, 4)) 
                                   + (1 - alb_wick) * solar * ((1 - fdir) * (1 + 0.25 * diam_wick / len_wick) 
                                   + (Math.tan(zenith) / 3.1416) + 0.25 * diam_wick / len_wick) * fdir + alb_sfc);
    
                           // Schmidt number
                          
                           var Sc = viscosity(Tair) / (density * diffusivity(Tref, pair));
    
                           // Calculate the convective heat transfer coefficient for a long cylinder in cross flow
                          
                            h = h_cylinder_in_air(Twb_prev,  wind, pair,speedmin, diam_wick);    
                          
                           // Calculate the saturation vapor pressure (hPa) over liquid water
                            
                           var ewick = esat(Twb_prev);
    
                           // Calculate the heat of evaporation, J/(kg K)
                            
                           var evap = h_evap(Twb_prev); 
                           
                           Twb = Tair - (evap/ratio) * ((ewick - eair) / (pair - ewick)) * Math.pow((Pr / Sc),0.56) + Fatm / h * irad;
                          
                           dT = Twb - Twb_prev;
                           
                           if (Math.abs(dT) < converge) { Twb = Twb - 273.15; break;} else {Twb_prev=Twb_prev+0.01;}
                                                          iter=iter+1;
                           } while ( iter < 1000);
                          
                           if ( iter===1000) {Twb=-999}
                          
                          return(Twb);
                         }



/**
 * lost_productivity is a function to estimate population heat exposure and impacts on working people
 * @param {number} wbgt,tresh
 * @return {number}
 * Estimating population heat exposure and impacts on working people in conjunction with climate change
 * Tord Kjellstrom  & Chris Freyberg & Bruno Lemke & Matthias Otto & David Briggs
 * Int J Biometeorol (2018) 62:291-306 DOI 10.1007/s00484-017-1407-0
*/

function lost_productivity(wbgt,tresh) {  
                                        if( tresh === undefined ) { tresh = 33.5;};
                                        return(0.5*(1+ erf((wbgt-tresh)/(3.75*Math.sqrt(2))))*100)
}

function BMW(h,w) 
         {return(w/(Math.pow((h/100),2)));} 

/**
 * Given body surface area by using antropometric features. 
 * @param {number} h,w
 * @return {number}
 * @customfunction
 */


function BSA (h,w) 
         { return( Math.pow(h/100,0.725)*(0.20247*(Math.pow(w,0.425)))); }    

  
/**
 * Given met rate level. 
 * @param {number} BSA, isolevel
 * @return {number}
 * @customfunction
 */


function met_rate(BSA, isolevel) {
  
   if ( isolevel === undefined) {isolevel = 1 };
  
  return(BSA*(isolevel*50));
}



/**
 * Given met and clo level gives acclimated tresholds of wbgt. 
 * @param {number} met,clolevel
 * @return {number}
 * @customfunction
 */

function rel_acclimatized(met,clolevel) {
  
     if ( clolevel === undefined) {isolevel = 1 };
  
     return(56.7-(11.5*Math.LN10(met))-clolevel);
}


/**
 * Given met and clo level gives unacclimated tresholds of wbgt. 
 * @param {number} met,clolevel
 * @return {number}
 * @customfunction
 */

function ral_unacclimatized(met,clolevel) {
  
     if ( clolevel === undefined) {isolevel = 1 };
  
     return(59.9-(14.1*Math.LN10(met))-clolevel);
}



/*           https://www.rapidtables.com/convert/color/hex-to-rgb.html
             RISCHIO = 80% NESSUN RISCHIO (GREEN) rgb(0,255,0)
             80% < RISCHIO = 100% ATTENZIONE (YELLOW) rgb(255,255,0)
             100% < RISCHIO = 120% ALLARME (ORANGE) rgb(255,165,0)
             RISCHIO > 120% EMERGENZA (RED) rgb(255,0,0)
*/            
            
          
/**
 * Given t air temperature (Celsius), rh relative humidity (%) and tg globometric temperature gives  heat risk level by using WBGT index. 
 * @param {number} t,rh,tg,tresh
 * @return {number}
 * @customfunction
 */

function heat_risk_text_level(t,rh,tg,tresh) { 
                                               if ( tresh === undefined) {tresh = 28.5 };
                                               var risk =wbgt(t,rh,tg)/tresh;
                                               var level_list=["NESSUN RISCHIO","ATTENZIONE","ALLARME","EMERGENZA"];  
                                               var class;
                                               if    ( risk <= 0.8)        {  class = 1;} 
                                                     else if (risk <= 1)   {  class = 2;} 
                                                     else if (risk <= 1.2) {  class = 3;} 
                                                     else                  {  class = 4};
                                              
                                               return(level_list[class]);           
                                              }


/**
 * Given t air temperature (Celsius), rh relative humidity (%) and tg globometric temperature gives  heat risk color level by using WBGT index. 
 * @param {number} t,rh,tg,tresh
 * @return {number}
 * @customfunction
 */

function heat_risk_color_level(wbgt,tresh)  { 
                                               if ( tresh === undefined) {tresh = 28.5 };
                                               var risk =wbgt/tresh;
                                               var colorcode_list=["green","yellow","orange","red"]; 
                                                  var class;
                                               if    ( risk <= 0.8)        {  class = 1;} 
                                                     else if (risk <= 1)   {  class = 2;} 
                                                     else if (risk <= 1.2) {  class = 3;} 
                                                     else                  {  class = 4};
                                               return(colorcode_list[class]);           
                                              }

/**
 * Gives heat color risk level in hex format by using WBGT index. 
 * @param {number} t,rh,tg,tresh
 * @return {number}
 * @customfunction
 */

function heat_risk_hexrgb_level(wbgt,tresh) { 
                                               if ( tresh === undefined) {tresh = 28.5 };
                                               var risk= wbgt/tresh;
                                               var colorcode_hex=["#00ff00","#ffff00","#ffa500","#ff0000"];
                                               var class;
                                   
                                               if    ( risk <= 0.8)        {  class = 1;} 
                                                     else if (risk <= 1)   {  class = 2;} 
                                                     else if (risk <= 1.2) {  class = 3;} 
                                                     else                  {  class = 4};


                                               return(colorcode_hex[class]);           
                                              }

/**
 * Given t air temperature (Celsius), rh relative humidity (%) and tg globometric temperature gives  heat risk value by using WBGT index. 
 * @param {number} t,rh,tg,tresh
 * @return {number}
 * @customfunction
 */

function heat_risk_index_level(wbgt,tresh)    { 
                                               if ( tresh === undefined) {tresh = 28.5 };
                                               var risk =(wbgt/tresh)*100;
                                               return(risk);        
                                              }




/**
 * Given a air temperature t (Celsius degree), globe temperature (Celsius degree), wind speed in m per second and diam of glbe in meters compute the mean radiant temperature (Celsius degree) ;
 * Reference; BSL, page 23.;
 *
 * @param {number} t, tg, wind, diam_glob
 * @return {number}
 * @customfunction
 */

function mrt_globe(t, tg, wind, diam_globe,emis_globe)

{        if ( diam_globe === undefined) {diam_globe = 0.05;} ; // in meters.
 
         if ( emis_globe === undefined) {emis_globe = 0.97;} ; 
 
         var stefanb = 0.0000000567;
 
         return Math.pow((Math.pow(tg + 273.15, 4) + ((1.1 * Math.pow(10,8) * Math.pow(wind,0.6)) /(emis_globe*Math.pow(diam_globe,0.4))) * (tg - t)), 0.25)- 273.15;
}

/**
 * Given air temperature t (Celsius degrees) and relative humidity (%) gives  deficit of saturarion in hPa.
 *
 * @param {number} t,rh
 * @return {number}
 * @customfunction
 */

function deficitsat(t,rh) 
{
  var pws = PVS(t);
  var pae=rh/100*pws;
  return (pws-pae);
}


/**
 * Given air temperature t (Celsius degrees) and relative humidity (%) gives  saturation  vapor pressure in hPa.
 *
 * @param {number} t,rh
 * @return {number}
 * @customfunction
 */

function es(t)
{
  var es_air, tk,i;
  g = new Array(8);
  g[0] =-2.8365744E3;
  g[1] =-6.028076559E3;
  g[2] =1.954263612E1;
  g[3] =-2.737830188E-2;
  g[4] =1.6261698E-5;
  g[5] =7.0229056E-10;
  g[6] =-1.8680009E-13;
  g[7] = 2.7150305;
  

  tk = t+273.15; 
  
  es_air = g[7]*Math.log(tk);
  
  for ( var i = 0; i < 7; i ++ )
         {es_air = es_air+g[i]*Math.pow(tk,i-2)};
  
  var es = Math.exp(es_air)*0.01;
  
  return es;
}


/**
 * Given air temperature (Celsius), relative humidity (%) and pressure ( pa) gives saturation vapor pressure in hPa.
 *
 * @param {number} t,rh
 * @return {number}
 * @customfunction
 */

function pvap(t,rh)
			{
				var E;
				E = es(t) * (rh/100);
				return E;
			}





/**
 * Given air temperature t (Celsius)  function gives Saturation Vapor Pressure  in hectoPascal (hPa)
 *
 * @param {number} t
 * @return {number}
 * @customfunction
 */

function PVS(t)
{
  t=t+273.16;
  var minT = 173; // -100 Deg. C.
  var maxT = 678;
  var noresp = -9999;
  var pvsresp;
  
  if (t < minT || t> maxT) 
     {return noresp;}
  
  else if (t<273.15)
       {pvsresp=pvsIce(t)/100;}
  else
       {pvsresp=pvsWater(t)/100;}
  
  return(TwoDec(pvsresp));
}

/*
 * Saturation Vapor Pressure formula for range -100..0 Deg. C.
 * Hardy B, 1998,"ITS-90 Formulations for Vapor Pressure, Frostpoint Temperature,Dewpoint Temperature, and Enhancement Factors in the Range 100 to +100 C".
 * Proceedings of the Third International Symposium on Humidity & Moisture",Teddington, London, England, April 1998
*/

function pvsIce(T) 
{
			       var k0 = -5.8666426e3;
			       var k1 = 2.232870244e1;
			       var k2 = 1.39387003e-2;
			       var k3 = -3.4262402e-5;
			       var k4 = 2.7040955e-8;
			       var k5 = 6.7063522e-1;
                   var lnP = k0/T + k1 + (k2 + (k3 + (k4*T))*T)*T + k5*Math.log(T);
                   return Math.exp(lnP);
}


/**
 * Given air temperature T (Celsius)  function gives Saturation Vapor Pressure. Dimension of outcomes in kPascal (kPa)
 * Saturation Vapor Pressure formula for range 273..678 Deg. K. 
 * Equation (30) in Section 8.1 "The Saturation-Pressure Equation (Basic Equation),Erlangen, Germany, September 1997.
 * @param {number} T
 * @return {number}
 * @customfunction
 */

function pvsWater(T) 
{
  
                   var n1 = 0.11670521452767e4;
                   var n6 = 0.14915108613530e2;
                   var n2 = -0.72421316703206e6;
                   var n7 = -0.48232657361591e4;
                   var n3 = -0.17073846940092e2;
                   var n8 = 0.40511340542057e6;
                   var n4 = 0.12020824702470e5;
                   var n9 = -0.23855557567849;
                   var n5 = -0.32325550322333e7;
                   var n10 = 0.65017534844798e3;

                   var th = T+n9/(T-n10);
                   var A = (th+n1)*th+n2;
                   var B = (n3*th+n4)*th+n5;
                   var C = (n6*th+n7)*th+n8;

                   var p = 2*C/(-B+Math.sqrt(B*B-4*A*C));
                   p *= p;
                   p *= p;
                   return p*1e6;
}


/**
 * Given a air temperature t (Celsius) and air relative humidity  (RH)  and formula gives the Dew Point in Celsius degrees.
 *
 * @param {number} t,RH
 * @return {number}
 * @customfunction
 */


function dewpoint(t,rh,formula) {
         if (formula == undefined) {formula == "NOAA"}
         var RHD = rh / 100;
         if (formula == "Paroscientific") 
             {return 237.3 * (Math.log(RHD) / 17.27 + t / (237.3 + t)) / (1 - Math.log(RHD) / 17.27 - t / (237.3 + t));}
         else if  (formula == "Sonntag") 
             {return 243.12 * (Math.log(RHD) / 17.62 + t / (243.12 + t)) / (1 - Math.log(RHD) / 17.62 - t / (243.12 + t));}
         else 
             {return 243.5 * (Math.log(RHD) / 17.67 + t / (243.5 + t)) / (1 - Math.log(RHD) / 17.67 - t / (243.5 + t));}
   

}

function h_evap(tk){
   var evap = (313.15 - tk) / 30 * (-71100) + 2407300;
  return(evap);
}


function emis_atm(t,rh)
{
                  //  Reference; Oke (2nd edition), page 373.;
                  var e = (rh*0.01) * esat(t+273.15);
                  return 0.575 * Math.pow(e,0.143);
}                             
 
 /**
 * Calculate the saturation vapor pressure (mb) over liquid water given the temperature (K).;
 * Reference Buck's (1981) approximation (eqn 3) of Wexler's (1976) formulae.;
 *
 * @param {number} t
 * @return {number}
 * @customfunction
 */  

function esat (tk) 
{
                  var esat= 6.1121 * Math.exp(17.502 * (tk - 273.15) / (tk - 32.18));
                  return 1.004 * esat;  
}

/**
 * Given a air temperature t (Celsius) compute the viscosity of air, kg/(m s) given temperature, K;
 * Reference; BSL, page 23.;
 *
 * @param {number} t
 * @return {number}
 * @customfunction
 */

              
function viscosity(t)
{

                       var omega = ((t+273.15) / 97 - 2.9) / 0.4 * (-0.034) + 1.048;
                       return 0.0000026693 * Math.pow((28.97 * t),0.5) / (Math.pow(3.617,2) * omega);
}



/**
 * Given a air temperature tk (Kelvin) and air pressure in millibar(hPA) compute the heat diffusivity in air;
 * Reference; BSL, page 23.;
 *
 * @param {number} t
 * @return {number}
 * @customfunction
 */

function diffusivity(tk, pair) {
  
   if( pair === undefined ) {pair=1013.25;};
  
  var pcrit13 = Math.pow(36.4 * 218, 1 / 3);
  var tcrit512 = Math.pow(132 * 647.3,(5 / 12));
  var Tcrit12 = Math.pow((132 * 647.3), 0.5);
  var Mmix = Math.pow((1 / 28.97 + 1 / 18.015),0.5);
  var diffusivity = 0.000364 * Math.pow((tk / Tcrit12),2.334) * pcrit13 * tcrit512 * Mmix / (pair / 1013.25) * 0.0001;
 return(diffusivity);
}





//  Purpose: to calculate the convective h the heat tranfer coefficient for flow around a sphere.; t in Kelvin degrees;
//  Reference : Bird, Stewart, && Lightfoot (BSL), page 409.;

                             
function h_sphere_in_air(tk,speed,pair,speedmin,diam_globe)
    {
                                    if( diam_globe === undefined ) {diam_globe=0.0508;};
                                    if( speedmin === undefined ) {speedmin=0.1;};
                                    if( pair === undefined ) {pair=1013.25;};
           
                                    var Rair = 8314.34 / 28.97;
                                    var Pr = 1003.5 / (1003.5 + 1.25 * Rair);
                                    var thermal_con = (1003.5 + 1.25 * 8314.34 / 28.97) * viscosity(tk-273.15);
                                    var density = (pair * 100) / (Rair * tk);  // kg/m3;
                                    if(speed < speedmin ){speed = speedmin};
                                    var Re = (speed * density * diam_globe)/ viscosity(tk-273.15);
                                    var Nu = 2 + 0.6 * Math.pow(Re,0.5) * Math.pow(Pr, 0.3333);
                                    return (Nu * thermal_con) / diam_globe; // W/(m2 K);
   }

//  Purpose: to calculate the convective heat tranfer coefficient for heat flow around a cylinder; t in K
//  Reference : Bird, Stewart, && Lightfoot (BSL), page 409.;

function h_cylinder_in_air(tk,speed,pair,speedmin,diam_wick){
  
   if( diam_wick === undefined ) { diam_wick=0.007;};
   if( speedmin === undefined )  { speedmin=0.1;};
   if( pair === undefined )      { pair=1013.25;};
           
   var m_air = 28.97;
   var r_gas = 8314.34;
   var r_air = r_gas / m_air;
   var cp = 1003.5; // heat capaticy at constant pressure of dry air
   var Pr = cp / (cp + (1.25 * r_air));
  
  // Calculate the thermal conductivity of air, W/(m K)
  
  var thermal_con = (cp + 1.25 * r_gas / m_air) * viscosity(tk-273.15);
                                   
  // Density of the air
  
  var density = pair * 100 / (r_air * tk);
  
  if (speed < speedmin) {speed = speedmin};
  
  // Reynolds number
  
  var Re = speed * density * diam_wick / viscosity(tk);
  
  //  Nusselt number
  
  var Nu = 0.281 * Math.pow(Re,0.6) * Math.pow(Pr, 0.44);
  
  // Convective heat transfer coefficient in W/(m2 K) for a long cylinder in cross flow
  var h_cylinder_in_air = Nu * thermal_con / diam_wick ; 
  
  return(h_cylinder_in_air);
}



/**
 * Given t, air temperature (Celsius degree)
 * rh, relative humidity (%) Used only this way to input humidity level
 * wind, relative air velocity (m/s)
 * trad, mean radiant temperature (Celsius degree)
 * M, metabolic rate (met)
 * W, external work, normally around 0 (met)
 * clo, clothing (clo) compute the Predicted Mean Vote for indoor moderate thermal environments.
 * Reference; ISO7730
 *
 * @param {number} t,rh,wind,trad,M,W,clo
 * @return {number}
 * @customfunction
 */

function PMV_ISO7730(t,rh,wind,trad,M,W,clo) 
    {
     

    var pa, icl, mw, fcl, hcf, taa, tra, tcla, p1, p2, p3, p4,
    p5, xn, xf, eps, hcn, hc, tcl, hl1, hl2, hl3, hl4, hl5, hl6,
    ts, pmv, ppd, n;

    pa = rh * 10 * Math.exp(16.6536 - 4030.183 / (t + 235));

    icl = 0.155 * clo; //thermal insulation of the clothing in M2K/W
      
    mw = M - W; //internal heat production in the human body
    
    if (icl <= 0.078) {fcl = 1 + (1.29 * icl)} else {fcl = 1.05 + (0.645 * icl)};

    // heat transf. coeff. by forced convection
  
    hcf = 12.1 * Math.sqrt(wind);
    taa = t + 273;
    tra = trad + 273;
    tcla = taa + (35.5 - t) / (3.5 * icl + 0.1);

    p1 = icl * fcl;
    p2 = p1 * 3.96;
    p3 = p1 * 100;
    p4 = p1 * taa;
    p5 = 308.7 - 0.028 * mw + p2 * Math.pow(tra / 100, 4);
    xn = tcla / 100;
    xf = tcla / 50;
    eps = 0.00015;

    n = 0;
  
    while (Math.abs(xn - xf) > eps) {
        xf = (xf + xn) / 2;
        hcn = 2.38 * Math.pow(Math.abs(100.0 * xf - taa), 0.25);
        if (hcf > hcn) hc = hcf;
        else hc = hcn;
        xn = (p5 + p4 * hc - p2 * Math.pow(xf, 4)) / (100 + p3 * hc);
        ++n;
        if (n > 150) {
              return('Max iterations exceeded');
        }
    }

    tcl = 100 * xn - 273;

    // heat loss diff. through skin 
      
    hl1 = 3.05 * 0.001 * (5733 - (6.99 * mw) - pa);
      
    // heat loss by sweating
    
    if (mw > 58.15) {hl2 = 0.42 * (mw - 58.15)} else  {hl2 = 0};
    
    // latent respiration heat loss 
      
    hl3 = 1.7 * 0.00001 * M * (5867 - pa);
      
    // dry respiration heat loss
      
    hl4 = 0.0014 * M * (34 - t);
      
    // heat loss by radiation  R
      
    hl5 = 3.96 * fcl * (Math.pow(xn, 4) - Math.pow(tra / 100, 4));
      
    // heat loss by convection C
      
    hl6 = fcl * hc * (tcl - t);

    ts = 0.303 * Math.exp(-0.036 * M) + 0.028;
  
    pmv = ts * (mw - hl1 - hl2 - hl3 - hl4 - hl5 - hl6);
  
   
    return(TwoDec(pmv));
}
/**
 * Given air temperature (Celsius), relative humidity (%), wind velocity (m/sec), direct beam short-wavelength radiation (W/mq) 
 * and sunelev sun elevation angle (degrees) gives Steadman outdoor index.
 *
 * @param {number} t, rh, wind, rshort, sunelev
 * @return {number}
 * @customfunction 
 */

function steadman_outdoor(t,rh,wind,rad,sunelev)
{    
  var steadman_outdoor_sun=9999;
  if (rh > 100.1 || rh < 0.0) {return 9999};
  if (t > 100.0 || t < -100.0) {return 9999};
  if (rad < 50) { return(steadman_outdoor_shade(t,rh,wind))}
  else {
    var ee = (rh/1000.0)*(6.105*Math.exp((t*17.27)/(237.7+t)));
    var q_glob = 0.56*(0.386-(0.0032*sunelev))*rad + 0.224*(0.1*rad)+ 0.028*rad- 150.0*(0.38-0.16*(Math.pow(ee,0.5))); 
    if (q_glob > 0.0) {steadman_outdoor_sun = t+3.48*(ee)-0.7*wind +0.7*q_glob/(wind+10.0)-4.25};
    };  
  return TwoDec(steadman_outdoor_sun);
}

/**
 * Given air temperature (Celsius), rh relative humidity (%), wind velocity (m/sec) gives Steadman outdoor shade index.
 *
 * @param {number} t,rh,wind
 * @return {number}
 * @customfunction
 */

function steadman_outdoor_shade(t,rh,wind)
{
    var steadman_outdoor_shade,e;
    
    steadman_outdoor_shade = 9999;
    
    if (rh > 100.1 || rh < 0.0)
        {return 9999}
    else if (wind > 130.0 || wind < 0.0)
        {return 9999}
    else if (t > 100.0 || t < -100.0)
         {return 9999}
    else
    {
       e = (rh/100.0)*(6.105*Math.exp((t*17.27)/(237.7+t)));
       steadman_outdoor_shade = t+(0.33*e)-(0.7*wind)-4.0;
    };

  
  return TwoDec(steadman_outdoor_shade);
}

/**
 * Given air temperature (Celsius), relative humidity (%)  gives Steadman indoor index.
 *
 * @param {number} t,rh 
 * @return {number}
 * @customfunction
 */

function steadman_indoor(t,rh)
{ 
    var steadman_indoor,e;

    steadman_indoor = -9999;
  
    if (rh > 100.1 || rh < 0.0) {return -9999}
    else if (t > 100.0 || t < -100.0) {return -9999}
    else
    {
      e = (rh/100.0)*(6.105*Math.exp((t*17.27)/(237.7+t)));
      steadman_indoor = -2.56+(0.89*t)+(0.382*e);  
    };

  return TwoDec(steadman_indoor);
}

/**
 * Given air temperature (Celsius Degrees), air relative humidity (%), wind velocity ( mpersec) and mean radiant temperature (trad) in Celsius Degrees    
 * gives 10 UTCI class.
 * @param {number} t,rh,wind,trad
 * @return {number}
 * @customfunction
 */

function utci_class10(t,rh,wind,trad) 
  {
	
  var  utci_v,utci_c;
 
  utci_v=UTCI(t,rh,wind,trad);
  
  if ( utci_v > 46.0)
   {utci_c=10.0;}
  else if (utci_v > 38.0 && utci_v <= 46.0)
    {utci_c=9.0;}
  else if (utci_v > 32.0 && utci_v <= 38.0)
  {utci_c=8.0;}
  else if (utci_v > 26.0 && utci_v <= 32.0)
    {utci_c=7.0;}
  else if (utci_v > 9.0 && utci_v <= 26.0)
    {utci_c=6.0;}
  else if (utci_v > 0.0 && utci_v <= 9.0)
    {utci_c=5.0;}
  else if (utci_v > -13.0 && utci_v <= 0)
  {utci_c=4.0;}
  else if (utci_v > -27.0 && utci_v <= -13.0)
    {utci_c=3.0;}	
  else if (utci_v > -40.0 && utci_v <= -27.0)
    {utci_c=2.0;}
  else if (utci_v <= -40.0)
    {utci_c=1.0;}
  else if (utci_v == 9999)
  {utci_c=9999};

  return utci_c;
}

/**
 * Given air temperature (Celsius Degrees), air relative humidity (%), wind velocity ( mpersec) and mean radiant temperature (trad) in Celsius Degrees   
 * gives 7 UTCI class.
 * @param {number} t,rh,wind,trad
 * @return {number}
 * @customfunction
 */

function utci_class7(t,rh, wind,trad) 
{
	
  var  utci_v,utci_c;
 
  utci_v=UTCI(t,rh,wind,trad);
  
  if ( utci_v > 46.0)
   {utci_c=7.0;}
  else if (utci_v > 38.0 && utci_v <= 46.0)
    {utci_c=7.0;}
  else if (utci_v > 32.0 && utci_v <= 38.0)
  {utci_c=7.0;}
  else if (utci_v > 26.0 && utci_v <= 32.0)
    {utci_c=6.0;}
  else if (utci_v > 16.0 && utci_v <= 26.0)
    {utci_c=6.0;}
  else if (utci_v > 0.0 && utci_v <= 16.0)
    {utci_c=5.0;}
  else if (utci_v > -13.0 && utci_v <= 0)
  {utci_c=4.0;}
  else if (utci_v > -27.0 && utci_v <= -13.0)
    {utci_c=3.0;}	
  else if (utci_v > -40.0 && utci_v <= -27.0)
    {utci_c=2.0;}
  else if (utci_v <= -40.0)
    {utci_c=1.0;}
  else if (utci_v == 9999)
  {utci_c=9999};

  return utci_c;
}

/**
 * Given air temperature (t Celsius degrees), relative humidity (%), wind velocity (m/sec) 
 * and mean radiant temperature (tmrt in Celsius degree) 
 * gives the Universal Thermal Climate Index (Celsius degree).
 *
 * @param {number} t, rh, wind, tmrt
 * @return {number}
 * @customfunction
 */

function UTCI(ta,rh,wind,tmrt)  
                 {    
                  
                  var ta,pa,va, e, dtm,i;
                  e = es(ta)/10; // use vapour pressure in kPa 
                  pa = (e*rh/100.0); 
                  va = wind;
	              if (  va < 0.51) {va=0.5;};
	              if (  va > 17) {va=17;};
				 
                  dtm = tmrt - ta;
    
                  utci = new Array(210);
                  
                  utci[0]=ta;
                  utci[1]=6.07562052E-01;
                  utci[2]=-2.27712343E-02*ta;
                  utci[3]=8.06470249E-04*ta*ta;
                  utci[4]=-1.54271372E-04*ta*ta*ta;
                  utci[5]=-3.24651735E-06*ta*ta*ta*ta;
                  utci[6]=7.32602852E-08*ta*ta*ta*ta*ta;
                  utci[7]=1.35959073E-09*ta*ta*ta*ta*ta*ta;
                  utci[8]=-2.25836520E-00*va;
                  utci[9]=8.80326035E-02*ta*va;
                  utci[10]=2.16844454E-03*ta*ta*va;
                  utci[11]=-1.53347087E-05*ta*ta*ta*va;
                  utci[12]=-5.72983704E-07*ta*ta*ta*ta*va;
                  utci[13]=-2.55090145E-09*ta*ta*ta*ta*ta*va;
                  utci[14]=-7.51269505E-01*va*va;
                  utci[15]=-4.08350271E-03*ta*va*va;
                  utci[16]=-5.21670675E-05*ta*ta*va*va;
                  utci[17]=1.94544667E-06*ta*ta*ta*va*va;
                  utci[18]=1.14099531E-08*ta*ta*ta*ta*va*va;
                  utci[19]=1.58137256E-01*va*va*va;
                  utci[20]=-6.57263143E-05*ta*va*va*va;
                  utci[21]=2.22697524E-07*ta*ta*va*va*va;
                  utci[22]=-4.16117031E-08*ta*ta*ta*va*va*va;
                  utci[23]=-1.27762753E-02*va*va*va*va;
                  utci[24]=9.66891875E-06*ta*va*va*va*va;
                  utci[25]=2.52785852E-09*ta*ta*va*va*va*va;
                  utci[26]=4.56306672E-04*va*va*va*va*va;
                  utci[27]=-1.74202546E-07*ta*va*va*va*va*va;
                  utci[28]=-5.91491269E-06*va*va*va*va*va*va;
                  utci[29]=3.98374029E-01*dtm;
                  utci[30]=1.83945314E-04*ta*dtm;
                  utci[31]=-1.73754510E-04*ta*ta*dtm;
                  utci[32]=-7.60781159E-07*ta*ta*ta*dtm;
                  utci[33]=3.77830287E-08*ta*ta*ta*ta*dtm;
                  utci[34]=5.43079673E-10*ta*ta*ta*ta*ta*dtm;
                  utci[35]=-2.00518269E-02*va*dtm;
                  utci[36]=8.92859837E-04*ta*va*dtm;
                  utci[37]=3.45433048E-06*ta*ta*va*dtm;
                  utci[38]=-3.77925774E-07*ta*ta*ta*va*dtm;
                  utci[39]=-1.69699377E-09*ta*ta*ta*ta*va*dtm;
                  utci[40]=1.69992415E-04*va*va*dtm;
                  utci[41]=-4.99204314E-05*ta*va*va*dtm;
                  utci[42]=2.47417178E-07*ta*ta*va*va*dtm;
                  utci[43]=1.07596466E-08*ta*ta*ta*va*va*dtm;
                  utci[44]=8.49242932E-05*va*va*va*dtm;
                  utci[45]=1.35191328E-06*ta*va*va*va*dtm;
                  utci[46]=-6.21531254E-09*ta*ta*va*va*va*dtm;
                  utci[47]=-4.99410301E-06*va*va*va*va*dtm;
                  utci[48]=-1.89489258E-08*ta*va*va*va*va*dtm;
                  utci[49]=8.15300114E-08*va*va*va*va*va*dtm;
                  utci[50]=7.55043090E-04*dtm*dtm;
                  utci[51]=-5.65095215E-05*ta*dtm*dtm;
                  utci[52]=-4.52166564E-07*ta*ta*dtm*dtm;
                  utci[53]=2.46688878E-08*ta*ta*ta*dtm*dtm;
                  utci[54]=2.42674348E-10*ta*ta*ta*ta*dtm*dtm;
                  utci[55]=1.54547250E-04*va*dtm*dtm;
                  utci[56]=5.24110970E-06*ta*va*dtm*dtm;
                  utci[57]=-8.75874982E-08*ta*ta*va*dtm*dtm;
                  utci[58]=-1.50743064E-09*ta*ta*ta*va*dtm*dtm;
                  utci[59]=-1.56236307E-05*va*va*dtm*dtm;
                  utci[60]=-1.33895614E-07*ta*va*va*dtm*dtm;
                  utci[61]=2.49709824E-09*ta*ta*va*va*dtm*dtm;
                  utci[62]=6.51711721E-07*va*va*va*dtm*dtm;
                  utci[63]=1.94960053E-09*ta*va*va*va*dtm*dtm;
                  utci[64]=-1.00361113E-08*va*va*va*va*dtm*dtm;
                  utci[65]=-1.21206673E-05*dtm*dtm*dtm;
                  utci[66]=-2.18203660E-07*ta*dtm*dtm*dtm;
                  utci[67]=7.51269482E-09*ta*ta*dtm*dtm*dtm;
                  utci[68]=9.79063848E-11*ta*ta*ta*dtm*dtm*dtm;
                  utci[69]=1.25006734E-06*va*dtm*dtm*dtm;
                  utci[70]=-1.81584736E-09*ta*va*dtm*dtm*dtm;
                  utci[71]=-3.52197671E-10*ta*ta*va*dtm*dtm*dtm;
                  utci[72]=-3.36514630E-08*va*va*dtm*dtm*dtm;
                  utci[73]=1.35908359E-10*ta*va*va*dtm*dtm*dtm;
                  utci[74]=4.17032620E-10*va*va*va*dtm*dtm*dtm;
                  utci[75]=-1.30369025E-09*dtm*dtm*dtm*dtm;
                  utci[76]=4.13908461E-10*ta*dtm*dtm*dtm*dtm;
                  utci[77]=9.22652254E-12*ta*ta*dtm*dtm*dtm*dtm;
                  utci[78]=-5.08220384E-09*va*dtm*dtm*dtm*dtm;
                  utci[79]=-2.24730961E-11*ta*va*dtm*dtm*dtm*dtm;
                  utci[80]=1.17139133E-10*va*va*dtm*dtm*dtm*dtm;
                  utci[81]=6.62154879E-10*dtm*dtm*dtm*dtm*dtm;
                  utci[82]=4.03863260E-13*ta*dtm*dtm*dtm*dtm*dtm;
                  utci[83]=1.95087203E-12*va*dtm*dtm*dtm*dtm*dtm;
                  utci[84]=-4.73602469E-12*dtm*dtm*dtm*dtm*dtm*dtm;
                  utci[85]=5.12733497E-00*pa;
                  utci[86]=-3.12788561E-01*ta*pa;
                  utci[87]=-1.96701861E-02*ta*ta*pa;
                  utci[88]=9.99690870E-04*ta*ta*ta*pa;
                  utci[89]=9.51738512E-06*ta*ta*ta*ta*pa;
                  utci[90]=-4.66426341E-07*ta*ta*ta*ta*ta*pa;
                  utci[91]=5.48050612E-01*va*pa;
                  utci[92]=-3.30552823E-03*ta*va*pa;
                  utci[93]=-1.64119440E-03*ta*ta*va*pa;
                  utci[94]=-5.16670694E-06*ta*ta*ta*va*pa;
                  utci[95]=9.52692432E-07*ta*ta*ta*ta*va*pa;
                  utci[96]=-4.29223622E-02*va*va*pa;
                  utci[97]=5.00845667E-03*ta*va*va*pa;
                  utci[98]=1.00601257E-06*ta*ta*va*va*pa;
                  utci[99]=-1.81748644E-06*ta*ta*ta*va*va*pa;
                  utci[100]=-1.25813502E-03*va*va*va*pa;
                  utci[101]=-1.79330391E-04*ta*va*va*va*pa;
                  utci[102]=2.34994441E-06*ta*ta*va*va*va*pa;
                  utci[103]=1.29735808E-04*va*va*va*va*pa;
                  utci[104]=1.29064870E-06*ta*va*va*va*va*pa;
                  utci[105]=-2.28558686E-06*va*va*va*va*va*pa;
                  utci[106]=-3.69476348E-02*dtm*pa;
                  utci[107]=1.62325322E-03*ta*dtm*pa;
                  utci[108]=-3.14279680E-05*ta*ta*dtm*pa;
                  utci[109]=2.59835559E-06*ta*ta*ta*dtm*pa;
                  utci[110]=-4.77136523E-08*ta*ta*ta*ta*dtm*pa;
                  utci[111]=8.64203390E-03*va*dtm*pa;
                  utci[112]=-6.87405181E-04*ta*va*dtm*pa;
                  utci[113]=-9.13863872E-06*ta*ta*va*dtm*pa;
                  utci[114]=5.15916806E-07*ta*ta*ta*va*dtm*pa;
                  utci[115]=-3.59217476E-05*va*va*dtm*pa;
                  utci[116]=3.28696511E-05*ta*va*va*dtm*pa;
                  utci[117]=-7.10542454E-07*ta*ta*va*va*dtm*pa;
                  utci[118]=-1.24382300E-05*va*va*va*dtm*pa;
                  utci[119]=-7.38584400E-09*ta*va*va*va*dtm*pa;
                  utci[120]=2.20609296E-07*va*va*va*va*dtm*pa;
                  utci[121]=-7.32469180E-04*dtm*dtm*pa;
                  utci[122]=-1.87381964E-05*ta*dtm*dtm*pa;
                  utci[123]=4.80925239E-06*ta*ta*dtm*dtm*pa;
                  utci[124]=-8.75492040E-08*ta*ta*ta*dtm*dtm*pa;
                  utci[125]=2.77862930E-05*va*dtm*dtm*pa;
                  utci[126]=-5.06004592E-06*ta*va*dtm*dtm*pa;
                  utci[127]=1.14325367E-07*ta*ta*va*dtm*dtm*pa;
                  utci[128]=2.53016723E-06*va*va*dtm*dtm*pa;
                  utci[129]=-1.72857035E-08*ta*va*va*dtm*dtm*pa;
                  utci[130]=-3.95079398E-08*va*va*va*dtm*dtm*pa;
                  utci[131]=-3.59413173E-07*dtm*dtm*dtm*pa;
                  utci[132]=7.04388046E-07*ta*dtm*dtm*dtm*pa;
                  utci[133]=-1.89309167E-08*ta*ta*dtm*dtm*dtm*pa;
                  utci[134]=-4.79768731E-07*va*dtm*dtm*dtm*pa;
                  utci[135]=7.96079978E-09*ta*va*dtm*dtm*dtm*pa;
                  utci[136]=1.62897058E-09*va*va*dtm*dtm*dtm*pa;
                  utci[137]=3.94367674E-08*dtm*dtm*dtm*dtm*pa;
                  utci[138]=-1.18566247E-09*ta*dtm*dtm*dtm*dtm*pa;
                  utci[139]=3.34678041E-10*va*dtm*dtm*dtm*dtm*pa;
                  utci[140]=-1.15606447E-10*dtm*dtm*dtm*dtm*dtm*pa;
                  utci[141]=-2.80626406E-00*pa*pa;
                  utci[142]=5.48712484E-01*ta*pa*pa;
                  utci[143]=-3.99428410E-03*ta*ta*pa*pa;
                  utci[144]=-9.54009191E-04*ta*ta*ta*pa*pa;
                  utci[145]=1.93090978E-05*ta*ta*ta*ta*pa*pa;
                  utci[146]=-3.08806365E-01*va*pa*pa;
                  utci[147]=1.16952364E-02*ta*va*pa*pa;
                  utci[148]=4.95271903E-04*ta*ta*va*pa*pa;
                  utci[149]=-1.90710882E-05*ta*ta*ta*va*pa*pa;
                  utci[150]=2.10787756E-03*va*va*pa*pa;
                  utci[151]=-6.98445738E-04*ta*va*va*pa*pa;
                  utci[152]=2.30109073E-05*ta*ta*va*va*pa*pa;
                  utci[153]=4.17856590E-04*va*va*va*pa*pa;
                  utci[154]=-1.27043871E-05*ta*va*va*va*pa*pa;
                  utci[155]=-3.04620472E-06*va*va*va*va*pa*pa;
                  utci[156]=5.14507424E-02*dtm*pa*pa;
                  utci[157]=-4.32510997E-03*ta*dtm*pa*pa;
                  utci[158]=8.99281156E-05*ta*ta*dtm*pa*pa;
                  utci[159]=-7.14663943E-07*ta*ta*ta*dtm*pa*pa;
                  utci[160]=-2.66016305E-04*va*dtm*pa*pa;
                  utci[161]=2.63789586E-04*ta*va*dtm*pa*pa;
                  utci[162]=-7.01199003E-06*ta*ta*va*dtm*pa*pa;
                  utci[163]=-1.06823306E-04*va*va*dtm*pa*pa;
                  utci[164]=3.61341136E-06*ta*va*va*dtm*pa*pa;
                  utci[165]=2.29748967E-07*va*va*va*dtm*pa*pa;
                  utci[166]=3.04788893E-04*dtm*dtm*pa*pa;
                  utci[167]=-6.42070836E-05*ta*dtm*dtm*pa*pa;
                  utci[168]=1.16257971E-06*ta*ta*dtm*dtm*pa*pa;
                  utci[169]=7.68023384E-06*va*dtm*dtm*pa*pa;
                  utci[170]=-5.47446896E-07*ta*va*dtm*dtm*pa*pa;
                  utci[171]=-3.59937910E-08*va*va*dtm*dtm*pa*pa;
                  utci[172]=-4.36497725E-06*dtm*dtm*dtm*pa*pa;
                  utci[173]=1.68737969E-07*ta*dtm*dtm*dtm*pa*pa;
                  utci[174]=2.67489271E-08*va*dtm*dtm*dtm*pa*pa;
                  utci[175]=3.23926897E-09*dtm*dtm*dtm*dtm*pa*pa;
                  utci[176]=-3.53874123E-02*pa*pa*pa;
                  utci[177]=-2.21201190E-01*ta*pa*pa*pa;
                  utci[178]=1.55126038E-02*ta*ta*pa*pa*pa;
                  utci[179]=-2.63917279E-04*ta*ta*ta*pa*pa*pa;
                  utci[180]=4.53433455E-02*va*pa*pa*pa;
                  utci[181]=-4.32943862E-03*ta*va*pa*pa*pa;
                  utci[182]=1.45389826E-04*ta*ta*va*pa*pa*pa;
                  utci[183]=2.17508610E-04*va*va*pa*pa*pa;
                  utci[184]=-6.66724702E-05*ta*va*va*pa*pa*pa;
                  utci[185]=3.33217140E-05*va*va*va*pa*pa*pa;
                  utci[186]=-2.26921615E-03*dtm*pa*pa*pa;
                  utci[187]=3.80261982E-04*ta*dtm*pa*pa*pa;
                  utci[188]=-5.45314314E-09*ta*ta*dtm*pa*pa*pa;
                  utci[189]=-7.96355448E-04*va*dtm*pa*pa*pa;
                  utci[190]=2.53458034E-05*ta*va*dtm*pa*pa*pa;
                  utci[191]=-6.31223658E-06*va*va*dtm*pa*pa*pa;
                  utci[192]=3.02122035E-04*dtm*dtm*pa*pa*pa;
                  utci[193]=-4.77403547E-06*ta*dtm*dtm*pa*pa*pa;
                  utci[194]=1.73825715E-06*va*dtm*dtm*pa*pa*pa;
                  utci[195]=-4.09087898E-07*dtm*dtm*dtm*pa*pa*pa;
                  utci[196]=6.14155345E-01*pa*pa*pa*pa;
                  utci[197]=-6.16755931E-02*ta*pa*pa*pa*pa;
                  utci[198]=1.33374846E-03*ta*ta*pa*pa*pa*pa;
                  utci[199]=3.55375387E-03*va*pa*pa*pa*pa;
                  utci[200]=-5.13027851E-04*ta*va*pa*pa*pa*pa;
                  utci[201]=1.02449757E-04*va*va*pa*pa*pa*pa;
                  utci[202]=-1.48526421E-03*dtm*pa*pa*pa*pa;
                  utci[203]=-4.11469183E-05*ta*dtm*pa*pa*pa*pa;
                  utci[204]=-6.80434415E-06*va*dtm*pa*pa*pa*pa;
                  utci[205]=-9.77675906E-06*dtm*dtm*pa*pa*pa*pa;
                  utci[206]=8.82773108E-02*pa*pa*pa*pa*pa;
                  utci[207]=-3.01859306E-03*ta*pa*pa*pa*pa*pa;
                  utci[208]=1.04452989E-03*va*pa*pa*pa*pa*pa;
                  utci[209]=2.47090539E-04*dtm*pa*pa*pa*pa*pa;
                  utci[210]=1.48348065E-03*pa*pa*pa*pa*pa*pa;            
                  
                  var total = 0;

                  for (i = 0, n = utci.length; i < n; ++i)
                      {
                           total = total+utci[i];
                      };

                  if (  ta < -50.0 || ta > 60.0 ) {total=9999};
                  if ( (tmrt < ta-30.0) || (tmrt > ta+70.0 )) {total=9999};
                  if (  rh <= 0.0 || rh >= 100.0 ) {total=9999};
                  return TwoDec(total);
}

/**
 * Given air temperature (Celsius), relative humidity (%) give a heat index in Celsius degree. 
 * References: http://www.wpc.ncep.noaa.gov/html/heatindex.shtml [2] https://en.wikipedia.org/wiki/Heat_index [3] http://www.srh.noaa.gov/images/ffc/pdf/ta_htindx.PDF
 * 
 * @param {number} t,rh
 * @return {number}
 * @customfunction
 */

function heatindex(t,rh)
{
  var tf, tf2, ur2, hif;
  tf = C2F(t);
  tf2 = Math.pow(tf, 2.0);
  ur2 = Math.pow(rh, 2.0);
  hif = -42.379 + 2.04901523 * tf + 10.1433127 * rh - 0.22475541 *tf * rh
        - 6.83783 * 0.001* tf2 - 5.481717 * 0.01* ur2 +1.22874 * 0.001* tf2* rh
        + 8.5282 * 0.0001* tf * ur2 -1.99 * 0.000001* tf2* ur2;  
  
  if (t < 44 & t > 27 & rh < 13 )
           {
        return (TwoDec(F2C(hif-((13-rh)/4)*Math.sqrt((17-Mat.abs(tf-95.))/17))));
      }
  
  else if (t < 31 & t > 27 & rh > 85 ) {
        return (TwoDec(F2C(hif-((rh-85)/10) * ((87-tf)/5))));
      }
  

  if (t > 27)
      {
        return (TwoDec(F2C(hif)));
      }
     
  else
      
      {return(TwoDec(F2C(0.5 * (tf + 61.0 + ((tf-68.0) *1.2) + (rh*0.094) ))))};
  
}


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////