More progress... but more things I need to calculate that I don't yet know how.
This commit is contained in:
parent
ccfc47eb79
commit
d679bcf781
11 changed files with 137 additions and 26 deletions
36
README.md
36
README.md
|
|
@ -2,4 +2,38 @@
|
||||||
|
|
||||||
Functions to compute relative humidity, absolute humidity, wet bulb
|
Functions to compute relative humidity, absolute humidity, wet bulb
|
||||||
temperature, and other values related to humidity of air, given
|
temperature, and other values related to humidity of air, given
|
||||||
partial data
|
partial data.
|
||||||
|
|
||||||
|
## General architecture
|
||||||
|
|
||||||
|
### The packet
|
||||||
|
|
||||||
|
The 'packet', in the terminology of this library, is a map which has bindings
|
||||||
|
for some of the following keywords:
|
||||||
|
|
||||||
|
1. `:actual-humidity`
|
||||||
|
2. `:actual-vapour-pressure
|
||||||
|
1. `:dew-point`
|
||||||
|
2. `:pressure-pascals`
|
||||||
|
3. `:pressure-millibars`
|
||||||
|
4. `:saturation-pressure`
|
||||||
|
5. `:relative-humidity`
|
||||||
|
6. `:temperature`
|
||||||
|
7. `:temperature-celsius`
|
||||||
|
8. `:temperature-kelvin`
|
||||||
|
|
||||||
|
These keywords represent variables in the pressure equations, and they are all
|
||||||
|
to a degree inter-related; so if you have (or can assume) some of them, you can
|
||||||
|
compute others.
|
||||||
|
|
||||||
|
Rather than having a mess of functions all of which call one another, which
|
||||||
|
seemed likely to result in horrible messes and potential infinite recursion,
|
||||||
|
there is one central function, `humidity.core/resolution`, which takes a
|
||||||
|
partial package and repeatedly tries to compute the values for more variables
|
||||||
|
until it can compute no more, and then returns the enhanced packet.
|
||||||
|
|
||||||
|
At present there are no checks to ensure that the packet makes sense.
|
||||||
|
|
||||||
|
Associated with each variable there is a namespace which takes a packet, and,
|
||||||
|
if that packet contains enough information to compute that variable, returns
|
||||||
|
a numeric value, else `nil`.
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,6 @@
|
||||||
|
|
||||||
(defn abs-humidity [& {:keys [relative-humidity saturation-pressure temperature-kelvin]}]
|
(defn abs-humidity [& {:keys [relative-humidity saturation-pressure temperature-kelvin]}]
|
||||||
(when (and relative-humidity saturation-pressure temperature-kelvin)
|
(when (and relative-humidity saturation-pressure temperature-kelvin)
|
||||||
(/ (* relative-humidity saturation-pressure) (* Rw temperature-kelvin 100)))
|
;; I don't know why I'm having to multiply by a thousand here...
|
||||||
|
(* (/ (* relative-humidity saturation-pressure) Rw temperature-kelvin) 1000))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,9 +9,15 @@
|
||||||
"Base of natural logarithms"
|
"Base of natural logarithms"
|
||||||
2.71828)
|
2.71828)
|
||||||
|
|
||||||
|
(def ^:const Pa
|
||||||
|
"Standard atmospheric pressure, in Pascals. I don't know why this isn't
|
||||||
|
100,000, but it isn't.
|
||||||
|
See https://en.wikipedia.org/wiki/Standard_atmosphere_(unit)"
|
||||||
|
101325)
|
||||||
|
|
||||||
(def ^:const Pc
|
(def ^:const Pc
|
||||||
"Critical pressure for water, in MPa (Megapascal)"
|
"Critical pressure for water, in Pascals"
|
||||||
22.064)
|
22064)
|
||||||
|
|
||||||
(def ^:const Rw
|
(def ^:const Rw
|
||||||
"Specific gas constant for water vapour (J/(kg⋅K))"
|
"Specific gas constant for water vapour (J/(kg⋅K))"
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
(ns humidity.core
|
(ns humidity.core
|
||||||
(:require [humidity.absolute :refer [abs-humidity]]
|
(:require [humidity.absolute :refer [abs-humidity]]
|
||||||
[humidity.constants :refer [celsius-offset]]
|
[humidity.constants :refer [celsius-offset Pa]]
|
||||||
[humidity.saturation-vp :as saturation-vp]
|
[humidity.saturation-vp :as saturation-vp]
|
||||||
[humidity.utils :refer [?assoc]]
|
[humidity.utils :refer [?assoc]]
|
||||||
[humidity.wet-bulb :refer [wet-bulb-temperature]]))
|
[humidity.wet-bulb :refer [wet-bulb-temperature]]))
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
(defn resolve-humidity
|
(defn resolve-humidity
|
||||||
"Resolve humidity equations given the data in this packet."
|
"Resolve humidity equations given the data in this packet."
|
||||||
[& {:keys [temperature temperature-celsius temperature-kelvin relative-humidity
|
[& {:keys [temperature temperature-celsius temperature-kelvin relative-humidity
|
||||||
pressure-kilopascals pressure-millibars saturation-pressure] :as packet}]
|
pressure-pascals pressure-millibars saturation-vapour-pressure] :as packet}]
|
||||||
(println packet)
|
(println packet)
|
||||||
(if temperature (resolve-humidity (assoc (dissoc packet :temperature) :temperature-celsius temperature))
|
(if temperature (resolve-humidity (assoc (dissoc packet :temperature) :temperature-celsius temperature))
|
||||||
(?assoc packet
|
(?assoc packet
|
||||||
|
|
@ -22,13 +22,13 @@
|
||||||
(and temperature-celsius relative-humidity)
|
(and temperature-celsius relative-humidity)
|
||||||
(wet-bulb-temperature temperature-celsius relative-humidity))
|
(wet-bulb-temperature temperature-celsius relative-humidity))
|
||||||
:absolute-humidity (abs-humidity :relative-humidity relative-humidity
|
:absolute-humidity (abs-humidity :relative-humidity relative-humidity
|
||||||
:saturation-pressure saturation-pressure
|
:saturation-vapour-pressure saturation-vapour-pressure
|
||||||
:temperature-kelvin temperature-kelvin)
|
:temperature-kelvin temperature-kelvin)
|
||||||
:pressure-kilopascals (when-not pressure-kilopascals
|
:pressure-pascals (when-not pressure-pascals
|
||||||
(if pressure-millibars (/ pressure-millibars 10) 100))
|
(if pressure-millibars (* pressure-millibars 100) Pa))
|
||||||
:pressure-millibars (when-not pressure-millibars
|
:pressure-millibars (when-not pressure-millibars
|
||||||
(if pressure-kilopascals (* pressure-kilopascals 10) 1000))
|
(if pressure-pascals (/ pressure-pascals 100) (/ Pa 100)))
|
||||||
:saturation-pressure (saturation-vp/saturation-vp packet))))
|
:saturation-vapour-pressure (saturation-vp/saturation-vp packet))))
|
||||||
|
|
||||||
|
|
||||||
(defn resolution
|
(defn resolution
|
||||||
|
|
|
||||||
|
|
@ -1 +1,34 @@
|
||||||
(ns humidity.relative)
|
(ns ^{:authority "https://journals.ametsoc.org/view/journals/apme/35/4/1520-0450_1996_035_0601_imfaos_2_0_co_2.xml/"
|
||||||
|
:author "simon"
|
||||||
|
:doc "Function to return relative humidity."} humidity.relative
|
||||||
|
(:require [humidity.constants :refer [celsius-offset e]]
|
||||||
|
[humidity.utils :refer [expt]]))
|
||||||
|
|
||||||
|
(def ^:const magic-numbers
|
||||||
|
"The magic numbers (empirical constants) from the derived expression. It
|
||||||
|
bothers me that all these formulae depend on 'empirical constants', *and*
|
||||||
|
that there is no commonality between the empirical constants of different
|
||||||
|
formulae."
|
||||||
|
[0 17.625 243.04])
|
||||||
|
|
||||||
|
(def C magic-numbers)
|
||||||
|
|
||||||
|
(defn rel-humidity
|
||||||
|
"Returns relative humidity (as a percentage, 0...100) given values for dew
|
||||||
|
point and temperature in either Celsius or Kelvin."
|
||||||
|
[& {:keys [dew-point temperature-celsius temperature-kelvin]}]
|
||||||
|
(cond (and dew-point (or temperature-celsius temperature-kelvin))
|
||||||
|
(let [Tc (if temperature-celsius
|
||||||
|
temperature-celsius
|
||||||
|
(- temperature-kelvin celsius-offset))]
|
||||||
|
(* 100 (/ (expt e (/ (* (C 1) dew-point)
|
||||||
|
(+ (C 2) dew-point)))
|
||||||
|
(expt e (/ (* (C 1) Tc)
|
||||||
|
(+ (C 2) Tc))))))))
|
||||||
|
|
||||||
|
;; Absolute Humidity (grams/m3) = 6.112 × e^[(17.67 × T)/(T+243.5)] × rh × 2.1674
|
||||||
|
;; -----------------------------------------------
|
||||||
|
;; (273.15+T)
|
||||||
|
;;
|
||||||
|
;; => /
|
||||||
|
;;
|
||||||
|
|
|
||||||
|
|
@ -5,14 +5,16 @@
|
||||||
(:require [clojure.math :refer [pow]]
|
(:require [clojure.math :refer [pow]]
|
||||||
[humidity.constants :refer [celsius-offset e]]))
|
[humidity.constants :refer [celsius-offset e]]))
|
||||||
|
|
||||||
|
|
||||||
(defn saturation-vp-tetens
|
(defn saturation-vp-tetens
|
||||||
"Calculate and return saturation vapour pressure in hPa using Tetens'
|
"Calculate and return saturation vapour pressure in Pa using Tetens'
|
||||||
formula, given temerature in ° Celsius."
|
formula, given temerature in ° Celsius."
|
||||||
[temperature-celsius]
|
[temperature-celsius]
|
||||||
(let [a 6.1078 ;; yet more magic numbers...
|
(let [a 610.78 ;; yet more magic numbers...
|
||||||
|
;; NOTE: 610.78 rather than 0.61078 in source because
|
||||||
|
;; we want answer in Pascals.
|
||||||
b 17.27
|
b 17.27
|
||||||
c 237.3]
|
c 237.3]
|
||||||
|
;; constant 100 to convert to Pascals
|
||||||
(* a (pow e (/ (* b temperature-celsius) (+ c temperature-celsius))))))
|
(* a (pow e (/ (* b temperature-celsius) (+ c temperature-celsius))))))
|
||||||
|
|
||||||
(defn saturation-vp
|
(defn saturation-vp
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
(ns ^{:doc "Function to calculate wet bulb temperature (in ° C) given temperature in
|
(ns ^{:doc "Function to calculate wet bulb temperature (in ° C) given temperature in
|
||||||
° C and relative-humidity percentage (0...100)"}
|
° C and relative-humidity percentage (0...100)"
|
||||||
|
:author "simon"}
|
||||||
humidity.wet-bulb
|
humidity.wet-bulb
|
||||||
(:require [clojure.math :refer [atan]]
|
(:require [clojure.math :refer [atan]]
|
||||||
[humidity.utils :refer [expt]]))
|
[humidity.utils :refer [expt]]))
|
||||||
|
|
|
||||||
13
test/humidity/absolute_test.clj
Normal file
13
test/humidity/absolute_test.clj
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
(ns humidity.absolute-test
|
||||||
|
(:require [clojure.test :refer [deftest is testing]]
|
||||||
|
[humidity.constants :refer [celsius-offset]]
|
||||||
|
[humidity.absolute :refer [abs-humidity]]))
|
||||||
|
|
||||||
|
(deftest absolute-humidity-test
|
||||||
|
(testing "definitional"
|
||||||
|
(let [min-expected 39.58
|
||||||
|
max-expected 39.59
|
||||||
|
actual (abs-humidity :relative-humidity 100
|
||||||
|
:saturation-pressure 56.29
|
||||||
|
:temperature-kelvin (+ 35 celsius-offset))]
|
||||||
|
(is (< min-expected actual max-expected)))))
|
||||||
1
test/humidity/dew_point_test.clj
Normal file
1
test/humidity/dew_point_test.clj
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
(ns humidity.dew-point-test)
|
||||||
11
test/humidity/relative_test.clj
Normal file
11
test/humidity/relative_test.clj
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
(ns humidity.relative-test
|
||||||
|
(:require [clojure.test :refer [deftest is testing]]
|
||||||
|
[humidity.constants :refer [celsius-offset]]
|
||||||
|
[humidity.relative :refer [rel-humidity]]))
|
||||||
|
|
||||||
|
(deftest relative-humidity-test
|
||||||
|
(testing "Online examples"
|
||||||
|
(let [min-expected 99
|
||||||
|
max-expected 101
|
||||||
|
actual (rel-humidity :dew-point 35 :temperature-celsius 35)]
|
||||||
|
(is (< min-expected actual max-expected)))))
|
||||||
10
test/humidity/saturation_vp_test.clj
Normal file
10
test/humidity/saturation_vp_test.clj
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
(ns humidity.saturation-vp-test(:require [clojure.test :refer [deftest is testing]]
|
||||||
|
[humidity.constants :refer [celsius-offset]]
|
||||||
|
[humidity.saturation-vp :refer [saturation-vp saturation-vp-tetens]]))
|
||||||
|
|
||||||
|
(deftest saturation-vp-test
|
||||||
|
(testing "from online sources"
|
||||||
|
(let [min-expected 5622
|
||||||
|
max-expected 5629
|
||||||
|
actual (saturation-vp {:temperature-celsius 35})]
|
||||||
|
(is (< min-expected actual max-expected)))))
|
||||||
Loading…
Add table
Add a link
Reference in a new issue