<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Dry-Down Notes]]></title><description><![CDATA[Dry-Down Notes]]></description><link>https://drydown-notes.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Mon, 02 Nov 2026 13:59:06 GMT</lastBuildDate><atom:link href="https://drydown-notes.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Grains per pound in 20 lines of Python: the humidity math behind a drying log]]></title><description><![CDATA[After a water loss, a drying log is a set of numbers written down at every visit: temperature and relative humidity inside, the same two outside, and…]]></description><link>https://drydown-notes.hashnode.dev/grains-per-pound-in-20-lines-of-python-the-humidity-math-behind-a-drying-log</link><guid isPermaLink="true">https://drydown-notes.hashnode.dev/grains-per-pound-in-20-lines-of-python-the-humidity-math-behind-a-drying-log</guid><category><![CDATA[Python]]></category><dc:creator><![CDATA[Alex Alwood]]></dc:creator><pubDate>Fri, 30 Oct 2026 14:21:41 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6ae4a3eb7a8fca3c72818f32/94959763-cd39-4f89-9118-87e1dda7aa32.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>After a water loss, a drying log is a set of numbers written down at every visit: temperature and relative humidity inside, the same two outside, and readings on the wet material. Relative humidity is the number everyone writes down, and it is the worst one to compare between two readings. RH depends on temperature. Air at 50% RH and 70°F holds less water than air at 50% RH and 80°F.</p>
<p>Restoration crews convert the pair to grains per pound (GPP): grains of water vapor per pound of dry air. GPP does not change when the temperature changes, so a reading from the basement, the living room and the street can sit in one column and mean the same thing. I run a restoration crew at Blue Spruce Restoration in Denver, and the math below is the version I keep for our logs. It is about twenty lines of Python.</p>
<h2>Why Denver needs its own constant</h2>
<p>Psychrometric charts are usually drawn for sea level. Denver sits at about 5,280 ft, where the standard-atmosphere pressure is 83.4 kPa, roughly 82% of the sea-level value. Lower pressure means the same temperature and RH carry more water per pound of dry air. Air at 70°F and 50% RH is 54.4 GPP at sea level and 66.2 GPP in Denver. The Denver value is 22% higher, so a sea-level chart reads about 18% low here and elevation has to be an input.</p>
<h2>The conversion</h2>
<p>Four steps. Saturation vapor pressure from temperature (the Magnus formula), partial pressure from RH, the humidity ratio from partial and total pressure, then grains.</p>
<pre><code class="language-python">import math
def sat_vapor_pressure_kpa(temp_f):
    t_c = (temp_f - 32) * 5 / 9
    return 0.61094 * math.exp(17.625 * t_c / (t_c + 243.04))
def pressure_kpa(elevation_ft):
    h = elevation_ft * 0.3048
    return 101.325 * (1 - 2.25577e-5 * h) ** 5.25588
def gpp(temp_f, rh_percent, elevation_ft=0):
    p = pressure_kpa(elevation_ft)
    pw = sat_vapor_pressure_kpa(temp_f) * rh_percent / 100
    w = 0.62198 * pw / (p - pw)
    return w * 7000
</code></pre>
<p>The constant 0.62198 is the ratio of the molar masses of water and dry air. The 7,000 converts pounds to grains. <code>pressure_kpa</code> is the standard-atmosphere formula, so it ignores the weather. Real station pressure moves a few percent from day to day, which is small next to what elevation does.</p>
<pre><code class="language-python">print(round(gpp(70, 50, 0), 1))     # 54.4
print(round(gpp(70, 50, 5280), 1))  # 66.2
</code></pre>
<h2>A log that can answer a question</h2>
<p>One row per reading, one location per row, GPP computed when the row is written. The numbers below are made up for the example. They show a living room with a dehumidifier running and the outdoor air next to it.</p>
<pre><code class="language-csv">day,time,location,temp_f,rh_pct,gpp
0,08:00,outdoor,54,30,22.4
0,08:00,living room,78,62,108.4
1,08:00,living room,80,55,102.5
2,08:00,living room,80,44,81.6
3,08:00,living room,79,36,64.4
</code></pre>
<p>In RH terms the living room fell from 62% to 36%, and the temperature moved at the same time, so that column is hard to read. In GPP the room fell from 108.4 to 64.4 over three days. Outdoor air at 22.4 GPP gives a reference point for the same morning. An unaffected room in the same house gives a second one, and I read the log against both.</p>
<p>The most useful query is the boring one: did the number fall since the last visit?</p>
<pre><code class="language-python">def stalled(gpp_by_visit, min_drop=2.0):
    pairs = zip(gpp_by_visit, gpp_by_visit[1:])
    return [i + 1 for i, (a, b) in enumerate(pairs) if a - b &lt; min_drop]
print(stalled([108.4, 102.5, 81.6, 64.4]))   # []
print(stalled([108.4, 102.5, 101.9, 64.4]))  # [2]
</code></pre>
<p>The 2.0 GPP threshold is my own choice. Tune it to your meter and your rooms. A visit that shows up in the list means the air stopped drying, and the usual causes are a dehumidifier whose collection bin is full, a closed door that sealed the room off from the equipment, or a source that is still wet. The script finds the visit. A person goes back and finds the reason.</p>
<h2>What this number does not tell you</h2>
<p>GPP describes the air. It says nothing about moisture inside drywall, framing or a slab. Those need a material meter and a dry reference reading from the same type of material in an unaffected area. Air can reach a low GPP while a wall cavity stays wet, and that gap is why a drying job is not finished when the room feels dry.</p>
<p>Hygrometers also carry error. Check the accuracy in your meter's spec sheet, because a few percent of RH moves the GPP result by several grains at 80°F.</p>
<p>If you keep a log in a spreadsheet instead, the same four steps work as cell formulas. Put elevation in its own cell so the file survives a job in Boulder or Colorado Springs, and write down which hygrometer took the reading.</p>
]]></content:encoded></item></channel></rss>