code wiki / (root) / nx_water_awg.nx

nx_water_awg.nx source

↩ module page · 168 lines · 6292 B

1// nx_water_awg.nx -- WATER SYSTEMS / ATMOSPHERIC WATER HARVESTING. Models 2// the whole "get water from the air" landscape, not one dehumidifier, and 3// recommends the best harvester for a climate (temperature + relative 4// humidity): 5// CONDENSATION -- refrigeration / dehumidifier (Watergen-class): cool 6// air below its dew point. Needs humid air (RH >~40%), 7// grid energy (~300 Wh/L). Psychrometric yield modeled. 8// SORBENT -- desiccant / MOF (Berkeley MOF-303, SOURCE hydropanels): 9// adsorb at low RH, release with solar heat. Works into 10// the desert (RH >~15%), low grid energy. 11// PASSIVE_CAP -- passive capillary-condensation material (UPenn 2025 12// amphiphilic nanoporous polymer, sciencedaily 250521): 13// condenses in nanopores with NO energy input, at lower 14// humidity than conventional cooling. 15// FOG -- mesh fog harvesting (needs near-saturation / fog). 16// RADIATIVE -- passive night-sky radiative cooling condenser. 17// 18// INTEGER-EXACT. Temp in C; RH in %; saturation vapor density g/m^3 x10; 19// yield in mL; energy in Wh/L. Psychrometric condensation yield from a 20// saturation-vapor-density table. 21// 22// THE exceed: given a climate it PICKS the right harvesting technology 23// (desert -> sorbent; moderate -> passive capillary; humid -> condensation) 24// and models the psychrometric yield + specific energy -- a real 25// research-to-design step, sovereign, no hardware yet (honest). 26// 27// grounded: psychrometric_saturation_vapor_density + atmospheric_water_generator 28// + upenn_amphiphilic_nanoporous_passive_harvesting_2025 29// + berkeley_mof_303_sorbent_awh 30// genealogy_id: atmospheric_water_harvesting + nishi_water_systems 31 32import "nx_syscalls.nx" 33 34// ===== Harvester technology classes =============================== 35 36const WA_CONDENSATION: i64 = 0 37const WA_SORBENT: i64 = 1 38const WA_PASSIVE_CAP: i64 = 2 39const WA_FOG: i64 = 3 40const WA_RADIATIVE: i64 = 4 41const WA_CLASS_N: i64 = 5 42const WA_NONE: i64 = 0 - 1 43 44// Power kind. 45const WA_POWER_PASSIVE: i64 = 0 46const WA_POWER_SOLAR: i64 = 1 47const WA_POWER_GRID: i64 = 2 48 49// Minimum relative humidity (%) each class works at. 50func wa_class_min_rh(cls: i64) -> i64 { 51 if cls == WA_CONDENSATION { return 40 } 52 if cls == WA_SORBENT { return 15 } 53 if cls == WA_PASSIVE_CAP { return 30 } 54 if cls == WA_FOG { return 95 } 55 if cls == WA_RADIATIVE { return 60 } 56 return 101 57} 58 59// Approximate specific energy (Wh per litre); 0 = passive. 60func wa_class_energy_whl(cls: i64) -> i64 { 61 if cls == WA_CONDENSATION { return 300 } 62 if cls == WA_SORBENT { return 50 } 63 if cls == WA_PASSIVE_CAP { return 0 } 64 if cls == WA_FOG { return 0 } 65 if cls == WA_RADIATIVE { return 0 } 66 return 0 67} 68 69// Relative yield score (0-100), throughput potential in favourable conditions. 70func wa_class_yield_score(cls: i64) -> i64 { 71 if cls == WA_CONDENSATION { return 90 } 72 if cls == WA_SORBENT { return 30 } 73 if cls == WA_PASSIVE_CAP { return 40 } 74 if cls == WA_FOG { return 50 } 75 if cls == WA_RADIATIVE { return 20 } 76 return 0 77} 78 79func wa_class_power_kind(cls: i64) -> i64 { 80 if cls == WA_CONDENSATION { return WA_POWER_GRID } 81 if cls == WA_SORBENT { return WA_POWER_SOLAR } 82 return WA_POWER_PASSIVE 83} 84 85// Does a class work at a given RH? 86func wa_class_works(cls: i64, rh_pct: i64) -> i64 { 87 if rh_pct >= wa_class_min_rh(cls) { return 1 } 88 return 0 89} 90 91// Fitness = yield minus an energy penalty (favour passive/low-energy), 92// or -1 if the class cannot work at this RH. 93func wa_class_fitness(cls: i64, rh_pct: i64) -> i64 { 94 if wa_class_works(cls, rh_pct) == 0 { return 0 - 1 } 95 return wa_class_yield_score(cls) - wa_class_energy_whl(cls) / 10 96} 97 98// Recommend the best harvester technology for a climate (RH-driven). 99func wa_recommend(temp_c: i64, rh_pct: i64) -> i64 { 100 var best: i64 = WA_NONE 101 var best_fit: i64 = 0 102 var c: i64 = 0 103 while c < WA_CLASS_N { 104 let f: i64 = wa_class_fitness(c, rh_pct) 105 if f >= 0 { 106 if f > best_fit { 107 best_fit = f 108 best = c 109 } 110 } 111 c = c + 1 112 } 113 return best 114} 115 116// ===== Psychrometrics (condensation yield) ======================== 117 118// Saturation vapor density (g/m^3, x10) at a temperature. 119func wa_sat_vapor_density_x10(temp_c: i64) -> i64 { 120 if temp_c == 0 { return 48 } 121 if temp_c == 5 { return 68 } 122 if temp_c == 10 { return 94 } 123 if temp_c == 15 { return 128 } 124 if temp_c == 20 { return 173 } 125 if temp_c == 25 { return 230 } 126 if temp_c == 30 { return 304 } 127 if temp_c == 35 { return 396 } 128 if temp_c == 40 { return 511 } 129 return 0 - 1 130} 131 132// Absolute humidity (g/m^3 x10) = saturation density * RH / 100. 133func wa_abs_humidity_x10(temp_c: i64, rh_pct: i64) -> i64 { 134 let sat: i64 = wa_sat_vapor_density_x10(temp_c) 135 if sat < 0 { return 0 - 1 } 136 return sat * rh_pct / 100 137} 138 139// Extractable water (g/m^3 x10) by condensation: intake absolute humidity 140// minus what the air still holds when leaving saturated at the coil temp. 141func wa_extractable_x10(temp_c: i64, rh_pct: i64, coil_temp_c: i64) -> i64 { 142 let intake: i64 = wa_abs_humidity_x10(temp_c, rh_pct) 143 let coil_sat: i64 = wa_sat_vapor_density_x10(coil_temp_c) 144 if intake < 0 { return 0 } 145 if coil_sat < 0 { return 0 } 146 if intake <= coil_sat { return 0 } 147 return intake - coil_sat 148} 149 150// Daily condensation yield (mL) for an airflow (m^3/h). extractable_x10 is 151// g/m^3 x10; 1 g water ~ 1 mL. 152func wa_daily_yield_ml(airflow_m3h: i64, extractable_x10: i64) -> i64 { 153 return airflow_m3h * 24 * extractable_x10 / 10 154} 155 156// First-order specific energy (Wh/L) for refrigeration condensation: the 157// drier the air, the more air (and energy) per litre. Anchored so ~10 g/m^3 158// extractable ~ 300 Wh/L. 159func wa_specific_energy_whl(extractable_x10: i64) -> i64 { 160 if extractable_x10 <= 0 { return 0 - 1 } 161 return 30000 / extractable_x10 162} 163 164// Fresh condensate is essentially distilled -> near-zero TDS (flat, and 165// unsafe until disinfected + remineralized). 166func wa_condensate_tds() -> i64 { 167 return 2 168}