diff --git a/README.md b/README.md index 62720af..01b8bd5 100644 --- a/README.md +++ b/README.md @@ -13,10 +13,8 @@ I'm using this code to explore human survivability given global warming. The fol 3. [Extreme Heat](https://www.journeyman.cc/blog/posts-output/2026-07-31-Extreme-Heat/) 4. [Analysis of 2026 heatwaves UK](https://www.journeyman.cc/blog/posts-output/2026-08-04-Analysis-of-2026-heatwaves-UK/) - ## Status - Alpha-quality code. It more or less works but it isn't at all polished. ## General architecture @@ -26,16 +24,18 @@ Alpha-quality code. It more or less works but it isn't at all polished. The 'packet', in the terminology of this library, is a map which has bindings for some of the following keywords: -1. `:absolute-humidity` +1. `:absolute-humidity` *grammes per metre3.* 2. `:actual-vapour-pressure` *not yet implemented* 1. `:dew-point` *not yet implemented* 2. `:pressure-pascals` 3. `:pressure-millibars` -4. `:saturation-vapour-pressure` -5. `:relative-humidity` -6. `:temperature` *assumed to be celsius* +4. `:saturation-vapour-pressure` *Pascals* +5. `:relative-humidity` *percentage, 0...100.* +6. `:temperature` *assumed to be ° Celsius* 7. `:temperature-celsius` 8. `:temperature-kelvin` +9. `:volume` *in metres3, relative to 1 at standard temperature and pressure.* +10. `:wet-bulb-temperature` *in ° Celsius.* 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 diff --git a/src/humidity/actual_vp.clj b/src/humidity/actual_vp.clj index 2776a94..0c2ff87 100644 --- a/src/humidity/actual_vp.clj +++ b/src/humidity/actual_vp.clj @@ -1,4 +1,6 @@ -(ns humidity.actual-vp) +(ns ^{:author "simon" + :authority "https://www.weather.gov/media/epz/wxcalc/vaporPressure.pdf" + :doc "Compute actual vapour pressure."} humidity.actual-vp) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/src/humidity/core.clj b/src/humidity/core.clj index ed9700e..aaaa6d3 100644 --- a/src/humidity/core.clj +++ b/src/humidity/core.clj @@ -6,6 +6,7 @@ [humidity.relative :refer [rel-humidity]] [humidity.saturation-vp :refer [saturation-vp]] [humidity.utils :refer [?assoc]] + [humidity.volume :refer [volume-fn]] [humidity.wet-bulb :as wb])) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -33,7 +34,8 @@ "Resolve humidity equations given the data in this packet." [& {:keys [absolute-humidity pressure-pascals pressure-millibars relative-humidity saturation-vapour-pressure temperature - temperature-celsius temperature-kelvin wet-bulb-temperature] :as packet}] + temperature-celsius temperature-kelvin volume + wet-bulb-temperature] :as packet}] (println packet) (if temperature (resolve-humidity (assoc (dissoc packet :temperature) @@ -46,7 +48,8 @@ (* pressure-millibars 100) Pa)) :pressure-millibars (when-not pressure-millibars (if pressure-pascals - (/ pressure-pascals 100) (/ Pa 100))) + (float (/ pressure-pascals 100)) + (float (/ Pa 100)))) :relative-humidity (when-not relative-humidity (rel-humidity packet)) :saturation-vapour-pressure (when-not saturation-vapour-pressure @@ -59,6 +62,7 @@ (and temperature-celsius (not temperature-kelvin)) (+ temperature-celsius celsius-offset)) + :volume (when-not volume (volume-fn packet)) :wet-bulb-temperature (when-not wet-bulb-temperature (wb/wet-bulb-temperature packet))))) diff --git a/src/humidity/volume.clj b/src/humidity/volume.clj new file mode 100644 index 0000000..185365b --- /dev/null +++ b/src/humidity/volume.clj @@ -0,0 +1,22 @@ +(ns ^{:author "simon" + :authority "https://en.wikipedia.org/wiki/Gas_laws" + :doc "In computing the relative humidity of air after it has warmed, I need + to account for the change in volume. By Charles' Law, given stable + pressure, volume is proportinal to absolute temperature (i.e. V=Tk, where K + is a constant). However, the sources I have read do not give that constant, + for air. But seeing what I'm interested in is that amount of air which is + contained in a cubic metre at standard temperature and pressure, then *I + think* I can just take (temperature-kelvin/celsius-offset) as the temperature + component. + + Gay-Lussac's law says pretty much the same for pressure, so again *I think* I + can take (pressure-pascals/Pa) as the pressure component."} humidity.volume + (:require [humidity.constants :refer [celsius-offset Pa]])) + +(defn volume-fn + "Compute the volume, in m3 of a quantity of air which would be + 1m3 at standard temperature and pressure, given temperature in + ° Kelvin and pressure in Pascals." + [& {:keys [temperature-kelvin pressure-pascals]}] + (when (and temperature-kelvin pressure-pascals) + (* (/ temperature-kelvin celsius-offset) (/ pressure-pascals Pa)))) diff --git a/test/humidity/core_test.clj b/test/humidity/core_test.clj index ef48072..e029375 100644 --- a/test/humidity/core_test.clj +++ b/test/humidity/core_test.clj @@ -1,7 +1,7 @@ (ns humidity.core-test (:require - [clojure.test :refer [deftest is testing]] - [humidity.core :refer [resolution]])) + [clojure.test :refer [deftest is testing]] + [humidity.core :refer [resolution]])) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; @@ -27,12 +27,13 @@ (deftest resolution-test (testing "resolution") (let [expected {:relative-humidity 100, - :temperature-celsius 35, - :pressure-pascals 101325, - :pressure-millibars 4053/4, - :saturation-vapour-pressure 5622.488734516426, - :temperature-kelvin 308.15, - :absolute-humidity 3953.618101887827} - packet {:relative-humidity 100 :temperature-celsius 35} - actual (resolution packet)] - (is (= actual expected)))) + :temperature-celsius 35, + :pressure-pascals 101325, + :pressure-millibars 1013.25, + :saturation-vapour-pressure 5622.488734516426, + :temperature-kelvin 308.15, + :absolute-humidity 3953.618101887827, + :volume 1.1281347245103424} + packet {:relative-humidity 100 :temperature-celsius 35} + actual (resolution packet)] + (is (= actual expected)))) diff --git a/test/humidity/volume_test.clj b/test/humidity/volume_test.clj new file mode 100644 index 0000000..1ef5071 --- /dev/null +++ b/test/humidity/volume_test.clj @@ -0,0 +1,41 @@ +(ns humidity.volume-test + (:require [clojure.test :refer [deftest is testing]] + [humidity.constants :refer [celsius-offset Pa]] + [humidity.volume :refer [volume-fn]])) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; +;;; Copyright (C) 2026 Simon Brooke +;;; +;;; 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. +;;; +;;; 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. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with this program; if not, write to the Free Software +;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +;;; USA. +;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(deftest relative-humidity-test + (testing "definitional" + (let [min-expected 0.99 + max-expected 1.01 + actual (volume-fn :pressure-pascals Pa :temperature-kelvin celsius-offset)] + (is (< min-expected actual max-expected)))) + (testing "Example from metoffice 26th May data." + (let [min-expected 1.14 + max-expected 1.15 + actual (volume-fn :pressure-pascals 102600 :temperature-kelvin (+ 35.1 celsius-offset))] + (is (< min-expected actual max-expected))) + (testing "Missing data returns nil" + (let [expected nil + actual (volume-fn :pressure-pascals 102600 :temperature-celsius 35.1)] + (is (= actual expected))))))