Skip to content

Instantly share code, notes, and snippets.

@bbarenblat
Created September 10, 2018 20:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bbarenblat/ecfd2321f61e8e2b60d99091d8a49093 to your computer and use it in GitHub Desktop.
Save bbarenblat/ecfd2321f61e8e2b60d99091d8a49093 to your computer and use it in GitHub Desktop.
-- Copyright 2018 Google LLC
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
import Control.Monad (unless)
import System.Console.GetOpt (getOpt)
import qualified System.Console.GetOpt as GetOpt
import System.Environment (getArgs)
import System.Exit (exitFailure)
import System.IO (hPutStr, stderr)
import Text.Printf (printf)
data Flag = Verbose
deriving Eq
main :: IO ()
main = do
let optDescr = [GetOpt.Option ['v'] [] (GetOpt.NoArg Verbose) ""]
(opts, args, errs) <- getOpt GetOpt.Permute optDescr <$> getArgs
unless (null errs && length args == 3) $ usage >> exitFailure
let [tF1, rh1, tF2] = map read args :: [Double]
rh2 = humidity tF1 rh1 tF2
putStrLn $
if Verbose `elem` opts
then printf "Moving air from %.0f°F to %.0f°F will change relative humidity from %.0f%% to %.0f%%." tF1 tF2 rh1 rh2
else printf "%.0f" rh2
usage :: IO ()
usage = hPutStr stderr $ unlines
[ "usage: humidity [-v] temp1 humidity1% temp2"
, ""
, "Assuming a relative humidity of humidity1% at temp1, computes relative"
, "humidity% at temp2. All temperatures are assumed Fahrenheit."
, ""
, "With -v, prints an English description of the activity performed (useful for"
, "sanity-checking your inputs)." ]
humidity :: Double -> Double -> Double -> Double
humidity tF1 rh1 tF2 =
let tK1 = fahrenheitToKelvins tF1
tK2 = fahrenheitToKelvins tF2 in
saturationPressureMillibars tK1 / saturationPressureMillibars tK2
* tK2 / tK1 * rh1
fahrenheitToKelvins :: Double -> Double
fahrenheitToKelvins f = (f + 459.67) * 5 / 9
-- Approximates the equilibrium vapor pressure of water over a flat surface of
-- pure water. This follows the World Meteorological Organization's
-- recommendations for use in computing relative humidity.
--
-- The approximation used here is equation 15 of Arnold Wexler (1976), "Vapor
-- Pressure Formulation for Water in Range 0 to 100 °C. A Revision", Journal of
-- Research at the National Bureau of Standards - A. Physics and Chemistry,
-- 80A(5-6): 775-785. The approximation has excellent accuracy (errors of less
-- than 16 ppm over the range 0°C < t < 100°C), and Buck indicates that it's
-- also suitable for supercooled regimes below freezing (Arden L. Buck (1981),
-- "New Equations for Computing Vapor Pressure and Enhancement Factor", Journal
-- of Applied Meteorology, 20(12): 1527-1532).
saturationPressureMillibars :: Double -> Double
saturationPressureMillibars tK =
let g :: [Double]
g = [ -0.29912729e4, -0.60170128e4, 0.1887643854e2, -0.28354721e-1
, 0.17838301e-4, -0.84150417e-9, 0.44412543e-12, 0.2858487e1 ]
lnP = sum [g !! i * tK ** (fromIntegral (i - 2)) | i <- [0..6]]
+ g !! 7 * log tK in
0.01 * exp lnP
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment