Skip to content

Indoor humidity and air-conditioning dehumidification - #4164

Open
cathyxinchangli wants to merge 64 commits into
ESCOMP:masterfrom
cathyxinchangli:dehumidification_pr
Open

Indoor humidity and air-conditioning dehumidification#4164
cathyxinchangli wants to merge 64 commits into
ESCOMP:masterfrom
cathyxinchangli:dehumidification_pr

Conversation

@cathyxinchangli

Copy link
Copy Markdown
Contributor

Description of changes

The code changes add indoor humidity and air-conditioning dehumidification to the CLMU BEM. It prognoses indoor specific humidity, calculates sensible cooling and latent dehumidification loads, and diagnoses condensate production and routes the condensate into urban runoff. The behavior is controlled by an integer CLM namelist variable, building_humidity_mode:

  • 0: use the existing CLMU formulation without indoor humidity or AC dehumidification;
  • 1: enable indoor humidity and latent heat exchange, but no AC dehumidification (requires prognostic building temperature, building_temp_method=1); and
  • 2: enable indoor humidity, latent heat exchange, dehumidification load, and condensate production (requires prognostic building temperature, urban_hac to be ON or ON_WASTEHEAT and urban_explicit_ac=.true.).

The default is set to 0 to ensure bit-for-bit reproducibility with the original scheme.

Specific notes

Contributors other than yourself, if any:
Lei Zhao (@Face2sea), Zhiwen Luo, Keith Oleson (@olyson), Yifan Cheng (@yifanc17), Xiaoxiong Xie, Alvin C. G. Varquez, Mitsuna Sekiya

CTSM issues resolved or otherwise addressed, if any:
Resolves #4162

If answers are expected to change, describe (delete this line otherwise):
Results remain bit-for-bit under building_humidity_mode=0. Comparing building_humidity_mode=1 with 0, two new variables are added (QBUILD, RHBUILD), and VENTILATION and EFLXBUILD changes because they now include latent heat exchanges between indoors and outdoors, and URBAN_AC and URBAN_HEAT changes slightly because of the changes in ventilation and higher heat capacity of moist air. Comparing building_humidity_mode=2 with 1, three more new variables (URBAN_AC_SEN, QCOND_FROM_AC, QCOND_FROM_AC_LUN) are added, and URBAN_AC increases because it now includes sensible (for cooling) and latent (for dehumidification) heat components of urban AC demand. URBAN_HEAT, VENTILATION, EFLXBUILD, WASTEHEAT changes slightly as an indirect results of the changes in AC.

Any user interface changes (namelist or namelist defaults changes)?
Yes, building_humidity_mode is added as a namelist variable.

Testing planned or performed, if any:
Results of the tests are under /glade/work/xinchang/03b_Dehumidification/05_pull_request/.

  • The physics of the scheme is validated in the accompanying publication;
  • Land-only simulations under DEBUG mode show Mode 0 is bit-for-bit as original CLMU, and Mode 2 is bit-for-bit as the validated version of the scheme (building_humidity_regression_diagnostics.ipynb);
  • Key variables for Mode 0, 1, and 2 are compared (building_humidity_mode_diagnostics.ipynb);
  • Restart behavior is tested for all three modes. All history fields except QAF were bit-for-bit after a continues 2-month run and a 1-month, 1-resubmit run in all three modes (building_humidity_restart_diagnostics.ipynb). The fact that the QAF discrepancy exists under Mode 0 (which is bit-for-bit as the original CLMU) seems to suggest this is not a problem of the new scheme. The reason might be because QAF history field is computed from the patch-level variable, whereas the QAF restart field is saved from the land-unit-level variable.

Requirements before merge:

  • The code in this PR branch builds with no errors.
  • The code in this PR branch runs with no errors. Briefly describe tested configuration(s): land-only, 1-degree simulations run for 1 year under DEBUG mode ran without errors. The scripts used to run the simulations are in /glade/u/home/xinchang/cases_dehumidification/.
  • This either (a) does not change answers, (b) it only changes answers at roundoff level, or (c) I have performed a scientific evaluation of the answer changes. Which?: (c)
  • I have reviewed relevant parts of the CLM documentation Tech Note or User's Guide to determine if anything needs to be changed or added. If it does, describe:
  • This PR either (a) does not create a need to update the documentation or (b) includes required documentation updates (see guidelines for contributing documentation). Which?: (b)

cathyxinchangli and others added 30 commits April 30, 2024 17:27
Define, initialize, create history field, and create restart variable for `q_building`, internal building air specific humidity.

Add argument "is_prog_buildtemp" to various subroutines to only initialize/create restart file for `q_building` if using prognostic temperature method.
1. define `q_building_max` as a constant in clm_varcon.F90
2. add latent heat component to `eflx_ventilation` and `eflx_building`
1. update `q_building` for the current time step assuming perfect mixing;
2. implement dehumidification process under explicit-AC-adoption scheme: introduce local variable `eflx_urban_ac_sat_lat` to represent latent heat load being removed. Dehumidification under original scheme is not implemented. Humidification for heating is also not implemented.
3. reset `q_building` based on `eflx_urban_ac_sat_lat`.
add one line to account for when there is no sensible heat load and only latent heat load.
Revoke some changes from before b/c they may not be necessary.
Change all waterdiagnostic_type into waterdiagnosticbulk_type to try to fix the error of no "water_inst%waterdiagnostic_inst" defined when trying to call it in clm_driver.F90.
1. Define RH_building, add hist field
2. Convert RH_building_max (RH setpoint) to q_building_max (spec hum setpoint)
3. Calculate RH_building from q_building
Change density and specific heat capacity from dry air to humid air.

NOT DONE IN THIS COMMIT but may need to change pressure from forc_pbot to pstd in some QSat() calls to maintain consistency with original code.
change all pressure in QSat() calls to pstd for consistency with original code (i.e., in calculation of rho_dair).
This reverts commit 5f39e20.

Changing back to using bottom layer of atmos. pressure to calculate rh_building, based on email discussion with Keith. Need another commit to update the use of pressure in density of humid air calculation.
Change all pressure from pstd (standard pressure) to forc_pbot (bottom layer atmos. forcing pressure).
1. Add variable 'eflx_urban_ac_sen_lun` and hist field `URBAN_AC_SEN`
2. Output `URBAN_AC_SEN` before latent heat is calculated
1. Calculate total condensed water, and convert it to water flux per impervious surface area in UrbBuildTempOlesonMod.F90 (incl. a write statement);
2. Add new variable `qflx_condensate_from_ac_col`  in WaterFluxType.F90;
3. Update BuildingTemperature() calls
1. calculate condensate flux w.r.t. urban land unit area in BuildingTemperature subroutine;
2. add condensate flux to surface runoff in TotalSurfaceRunoff subroutine.
`qflx_condensate_from_ac_col` is added to column-level water balance check, and `qflx_condensate_from_ac_grc` is calculated & added to grid-cell-level water balance check.
Note these two terms have not been added to the error messages.
@cathyxinchangli

Copy link
Copy Markdown
Contributor Author

Hi @olyson, sorry for the delay! I completed the tests after a couple more failed attempts. The comparisons between Modes 0, 1, and 2 are in the following notebooks:

  • After merging up to the latest tag (Notebook 1): /glade/work/xinchang/03b_Dehumidification/05_pull_request/building_humidity_mode_diagnostics_260813.ipynb
  • Before merging (Notebook 2): /glade/work/xinchang/03b_Dehumidification/05_pull_request/building_humidity_mode_diagnostics.ipynb

Results in general look reasonable to me in terms of spatial patterns and magnitude. The spatial patterns are mostly consistent before and after merging. It seems after merging, the difference between variables are larger between Mode 1 and 2 (i.e., dehumidification is run more). This seems to agree with the fact that QBUILD is higher after merging for regions with high dehumidification needs (see end of Notebook 1 for plots; also note below). In contrast, the difference between variables are smaller between Mode 0 and 1 after merging, which made sense to me, since before merging, Mode 0 and 1 also used different indoor pressures, which would have contributed to some of the differences.

Note: I should point out I used different surface data for running the simulations before and after merging, since the old surface data I used (a version of U-Surf) was no longer compatible with ctsm5.4, so I let the model use the default surface data. Apart from higher QBUILD, the code produced lower (up to 6 K over India) monthly mean TBUILD after merging. Was this to be expected because of surface data? Does the default surface data for urban properties use U-Surf in ctsm5.4?

@olyson

olyson commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Thanks @cathyxinchangli . U-Surf isn't in ctsm5.4, it uses the Oleson and Feddema data, so yes that's probably why you are seeing those differences. I guess you could try running your older setup (before the merge) with whatever default surface dataset comes with that code (which should include the Oleson and Feddema data), and then compare to your after the merge setup. There will still be differences but they should be much smaller. But if you think the dehumidification parameterization is working fine in the after the merge code, then maybe it's not necessary to do that.

@cathyxinchangli

Copy link
Copy Markdown
Contributor Author

Thanks @olyson! For my peace of mind, I reran Modes 0, 1, and 2 tests with before-merging code base using the default surface datasets, and compared TSA_U, RH2M_U, QBUILD, and TBUILD between Mode 1 simulations done with before- and after-merging code bases. All four variables show smaller differences now, and the spatial patterns of the differences are also more random, which is more aligned with what I would expect from a code base change. I summarize the spatiotemporal maximum absolute differences for the four variables below, and the plots can be seen in the last section of this notebook if you are interested: /glade/work/xinchang/03b_Dehumidification/05_pull_request/building_humidity_mode_diagnostics_3bdd812_260818.ipynb.

Simulation pairs: ctsm5.4+default surfdata vs ctsm5.2+U-Surf ctsm5.4+default surfdata vs ctsm5.2+default surfdata
Max diff. TSA_U 4 K 2.5 K
Max diff. RH2M_U 25% 22%
Max diff. TBUILD 7 K 3.5 K
Max diff. QBUILD 0.005 kg/kg 0.003 kg/kg

I also compared the two default surface datasets, and the differences are not that small -- it seems both the urban extent (changing from Gao and O'Neill to CIMP7) and the urban surface properties (such as CV_ROOF/WALL/IMPROAD) changed. See /glade/u/home/xinchang/work/03b_Dehumidification/05_pull_request/surfdata_ctsm52_vs_ctsm54_comparison.md for more details. Because of these differences in the two versions of the default surfdata, I am comfortable with the remaining differences we see between before- and after-merging code base.

Given this, do you think we are now ready for a code review @olyson?

@olyson

olyson commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

You are right, the urban extent did change, from GaoOneill to CMIP7. However, the basic urban properties that are input to mksurfdata_esmf should be the same. For ecample, the ctsm5.4 version uses:

/glade/campaign/cesm/cesmdata/cseg/inputdata/lnd/clm2/rawdata/CTSM54RawData/urban_properties/urban_properties_CMIP7_ThreeClass_2000_c250423.nc

and the ctsm5.2 version uses:

/glade/campaign/cesm/cesmdata/cseg/inputdata/lnd/clm2/rawdata/gao_oneill_urban/historical/urban_properties_GaoOneil_05deg_ThreeClass_2000_cdf5_c20220910.nc

and the CANYON_HWR is identical between the two. I haven't check all of the variables but I would expect them to be the same.

I think it is just that there is a difference in the land mask or mksurfdata_esmf algorithms used to generate the two surface datasets. Here's a screen shot of the differences in URBAN_REGION_ID between ctsm5.4 and ctsm5.2. You can see that the differences are all positive and primarily occur along the coasts and in areas with islands. There are just a few changes in continental interiors which presumably are due to some kind of change in the mksurfdata_esmf algorithms. However, I think the basic urban properties data are the same.

Screenshot 2026-08-19 085512

It sounds like the parameterization is working fine in the new code.
I need to get some guidance from the software engineers regarding the failing fortran unit tests. I expect we'll have to make some changes to the namelist variables and how they are implemented in the code. I'll make that part of my review.

@samsrabin samsrabin removed the next this should get some attention in the next week or two. Normally each Thursday SE meeting. label Aug 20, 2026

@olyson olyson left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @cathyxinchangli , I'm submitting my review, thanks. I'll be meeting with @ekluzek soon to discuss code changes required for the fortran unit tests, but I don't think that will interfere with resolving these comments when you have time.

Comment thread bld/namelist_files/namelist_definition_ctsm.xml Outdated
Comment thread bld/namelist_files/namelist_definition_ctsm.xml Outdated
Comment thread bld/CLMBuildNamelist.pm
Comment thread src/biogeophys/BalanceCheckMod.F90 Outdated
Comment thread src/biogeophys/BalanceCheckMod.F90
Comment thread src/biogeophys/WaterDiagnosticBulkType.F90 Outdated
Comment thread src/biogeophys/WaterFluxType.F90
Comment thread src/biogeophys/WaterFluxType.F90 Outdated
Comment thread src/main/clm_varcon.F90 Outdated
Comment thread bld/namelist_files/namelist_definition_ctsm.xml
@cathyxinchangli

Copy link
Copy Markdown
Contributor Author

Hi @olyson, sorry about the delay as I stepped away for other projects! I have now addressed all review comments with new commits and replies when needed. I verified that the results are bit-for-bit for all three modes compared to before I addressed the comments, except for floating point differences for ERRH2O under Mode 2 (see my reply to the specific comment for more details).

Comment thread src/biogeophys/UrbBuildTempOleson2015Mod.F90 Outdated
Comment thread src/biogeophys/UrbBuildTempOleson2015Mod.F90 Outdated
Comment thread src/biogeophys/UrbBuildTempOleson2015Mod.F90 Outdated
@olyson

olyson commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Thanks @cathyxinchangli , this looks good, I've resolved all comments. There are three new comments for minor spelling errors.
I got some help from @ekluzek with the fortran unit tests and am working on that now.

@cathyxinchangli

Copy link
Copy Markdown
Contributor Author

Thank you so much @olyson for reviewing the changes and catching my new mistakes! I've fixed them (plus one more Codex caught) in the new commit. Also thank you and @ekluzek for resolving the issues of the unit tests! I really appreciate your help and support.

@olyson olyson added the next this should get some attention in the next week or two. Normally each Thursday SE meeting. label Aug 27, 2026
@olyson

olyson commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Hi @cathyxinchangli , with guidance from @ekluzek I've resolved the five fortran unit test failures with this commit:

6143a6d

The failures were due to the fact that the namelist is not read in for these unit tests and that triggered the errors in these blocks of code:

    if ( .not. ReadNamelist )then
       write(iulog,*)'Testing on building_humidity_mode before urban namelist was read in'
       call endrun(msg=errMsg(sourcefile, __LINE__))
    end if
    if ( .not. ReadNamelist )then
       write(iulog,*)'Testing on building_humidity_mode before urban namelist was read in'
       call endrun(msg=errMsg(sourcefile, __LINE__))
    end if

The solution was to add a InitForTesting subroutine to src/biogeophys/UrbanParamsType.F90 where ReadNamelist is set to .false. and building_humidity_mode is set to its default value, currently 0. The five unit tests then call this subroutine at the appropriate place so that the namelist functions IsBuildingHumidityEnabled and IsACDehumidificationEnabled can be used.
I learned all of this the last few days, so I'm not an expert, but all the tests pass now.

Next step is for you to convert the PR from a draft. I've marked this PR with "next" so that we can discuss next steps with the software engineers.

@wwieder wwieder removed the next this should get some attention in the next week or two. Normally each Thursday SE meeting. label Aug 27, 2026
@wwieder
wwieder marked this pull request as ready for review August 27, 2026 16:32
@wwieder
wwieder requested a review from slevis-lmwg August 27, 2026 16:33
@wwieder wwieder added this to the cesm3.0.0 release branch tag milestone Aug 27, 2026
@cathyxinchangli

Copy link
Copy Markdown
Contributor Author

Thank you so much, @olyson! That's great to know for future reference. Seems like @wwieder beat me to it and converted it from draft to ready (thanks Will!). Let me know if there's anything else I could do in the meantime!

@olyson

olyson commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Next step would be a paired review with @slevis-lmwg , you, and myself, to go over the code one more time. You could just email Sam and myself about your availability for meeting via zoom next week if possible.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement new capability or improved behavior of existing capability science Enhancement to or bug impacting science

Projects

Status: Todo

Development

Successfully merging this pull request may close these issues.

Representing indoor humidity and air-conditioning dehumidification in CLMU BEM

5 participants