cloudnetpy 1.65.7__py3-none-any.whl → 1.66.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. cloudnetpy/categorize/__init__.py +0 -1
  2. cloudnetpy/categorize/atmos_utils.py +278 -59
  3. cloudnetpy/categorize/attenuation.py +31 -0
  4. cloudnetpy/categorize/attenuations/__init__.py +37 -0
  5. cloudnetpy/categorize/attenuations/gas_attenuation.py +30 -0
  6. cloudnetpy/categorize/attenuations/liquid_attenuation.py +80 -0
  7. cloudnetpy/categorize/attenuations/melting_attenuation.py +75 -0
  8. cloudnetpy/categorize/attenuations/rain_attenuation.py +84 -0
  9. cloudnetpy/categorize/categorize.py +140 -81
  10. cloudnetpy/categorize/classify.py +92 -128
  11. cloudnetpy/categorize/containers.py +45 -31
  12. cloudnetpy/categorize/droplet.py +2 -2
  13. cloudnetpy/categorize/falling.py +3 -3
  14. cloudnetpy/categorize/freezing.py +2 -2
  15. cloudnetpy/categorize/itu.py +243 -0
  16. cloudnetpy/categorize/melting.py +0 -3
  17. cloudnetpy/categorize/model.py +31 -14
  18. cloudnetpy/categorize/radar.py +28 -12
  19. cloudnetpy/constants.py +3 -6
  20. cloudnetpy/model_evaluation/file_handler.py +2 -2
  21. cloudnetpy/model_evaluation/products/observation_products.py +8 -8
  22. cloudnetpy/model_evaluation/tests/unit/test_grid_methods.py +5 -2
  23. cloudnetpy/model_evaluation/tests/unit/test_observation_products.py +11 -11
  24. cloudnetpy/output.py +46 -26
  25. cloudnetpy/plotting/plot_meta.py +8 -2
  26. cloudnetpy/plotting/plotting.py +31 -8
  27. cloudnetpy/products/classification.py +39 -34
  28. cloudnetpy/products/der.py +15 -13
  29. cloudnetpy/products/drizzle_tools.py +22 -21
  30. cloudnetpy/products/ier.py +8 -45
  31. cloudnetpy/products/iwc.py +7 -22
  32. cloudnetpy/products/lwc.py +14 -15
  33. cloudnetpy/products/mwr_tools.py +15 -2
  34. cloudnetpy/products/product_tools.py +121 -119
  35. cloudnetpy/utils.py +4 -0
  36. cloudnetpy/version.py +2 -2
  37. {cloudnetpy-1.65.7.dist-info → cloudnetpy-1.66.0.dist-info}/METADATA +1 -1
  38. {cloudnetpy-1.65.7.dist-info → cloudnetpy-1.66.0.dist-info}/RECORD +41 -35
  39. {cloudnetpy-1.65.7.dist-info → cloudnetpy-1.66.0.dist-info}/WHEEL +1 -1
  40. cloudnetpy/categorize/atmos.py +0 -376
  41. {cloudnetpy-1.65.7.dist-info → cloudnetpy-1.66.0.dist-info}/LICENSE +0 -0
  42. {cloudnetpy-1.65.7.dist-info → cloudnetpy-1.66.0.dist-info}/top_level.txt +0 -0
@@ -1,30 +1,36 @@
1
1
  cloudnetpy/__init__.py,sha256=X_FqY-4yg5GUj5Edo14SToLEos6JIsC3fN-v1FUgQoA,43
2
2
  cloudnetpy/cloudnetarray.py,sha256=Ol1ha4RPAmFZANL__U5CaMKX4oYMXYR6OnjoCZ9w3eo,7077
3
3
  cloudnetpy/concat_lib.py,sha256=8Ek059RMLAfbbXCkX90cgnhw_8ZpcDrxw1yPvwtuitU,9846
4
- cloudnetpy/constants.py,sha256=Kn95HXVMsKFo9Bu-UOYSBJuPEOjBR4JLaEXH0-MBpwk,830
4
+ cloudnetpy/constants.py,sha256=RDB9aqpBRztk3QVCFgsmi9fwhtLuit_0WJrt0D6sDcc,736
5
5
  cloudnetpy/datasource.py,sha256=j7N4g59HPvOBWle-W9bOUF0BfRLgvR4zwOi_B50cI7Q,7921
6
6
  cloudnetpy/exceptions.py,sha256=ns48useL9RN3mPh7CqIiLA19VI9OmVbyRsKTkwbThF8,1760
7
7
  cloudnetpy/metadata.py,sha256=v_VDo2vbdTxB0zIsfP69IcrwSKiRlLpsGdq6JPI4CoA,5306
8
- cloudnetpy/output.py,sha256=YkCaxVkG_Mt2hng_IVnhygHteV4UMKzKALkeFZwFJL8,14822
8
+ cloudnetpy/output.py,sha256=YrWRBEZg0QNZRVnd9ziAziH-eJSh7O5JuWiH4ZxM0_s,15584
9
9
  cloudnetpy/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
- cloudnetpy/utils.py,sha256=JV0Fawnme1HoZgoiidV3eIzsn6vx0AEjBNmI1CcrBsA,28517
11
- cloudnetpy/version.py,sha256=B0fKgZkDpneBNddUtrKe13FSc_Y17mGFfki5_swqhMU,72
12
- cloudnetpy/categorize/__init__.py,sha256=gP5q3Vis1y9u9OWgA_idlbjfWXYN_S0IBSWdwBhL_uU,69
13
- cloudnetpy/categorize/atmos.py,sha256=vavMC_WQQyGH14eL4vAzKLKDDZt8tBrMYimztYHOjH8,12639
14
- cloudnetpy/categorize/atmos_utils.py,sha256=ns5ydiEN34Ng6mJiOBpxKBVDU2NXj6W3Q5IUynmNRYI,3586
15
- cloudnetpy/categorize/categorize.py,sha256=VcxSs22icYDG3R5x9jTX7uuSjPU8tyc5bIz0Zj5F9z0,18303
16
- cloudnetpy/categorize/classify.py,sha256=a-0bVCtynGfORnDGTsPuzqkuDeOOR_OMz5ai9NsMuic,9870
17
- cloudnetpy/categorize/containers.py,sha256=g3SQHoqlY1uJ8b-MG-BbW3oWz5IyacA8kJBeIPy_4EA,4859
10
+ cloudnetpy/utils.py,sha256=1gne8Qqa-e4CNNJMynWr4LVirGK0Be-KcskVZMD72ac,28621
11
+ cloudnetpy/version.py,sha256=M2-atDdtYzbMUo8WvBwyYGrpfWspuimBvKUAoMUh9xk,72
12
+ cloudnetpy/categorize/__init__.py,sha256=s-SJaysvVpVVo5kidiruWQO6p3gv2TXwY1wEHYO5D6I,44
13
+ cloudnetpy/categorize/atmos_utils.py,sha256=9-ymI6i1xASf-XAFyO87FaTfvq6bF89N1i_27OkUp-M,10104
14
+ cloudnetpy/categorize/attenuation.py,sha256=Y_-fzmQTltWTqIZTulJhovC7a6ifpMcaAazDJcnMIOc,990
15
+ cloudnetpy/categorize/categorize.py,sha256=UQdgLHTNc-J4-CRK3P1mrGNUMal2cKE6nwE5JYlFMcc,20644
16
+ cloudnetpy/categorize/classify.py,sha256=qovHgHsMku5kpl3cJxKteNBsG8GAkfI3Zo8QhJwZSFQ,8512
17
+ cloudnetpy/categorize/containers.py,sha256=4AUx95Br-aczyUB1dCmTfLn0MRKsk2GLkdCTdnqIfAs,5186
18
18
  cloudnetpy/categorize/disdrometer.py,sha256=keU3pFvKtk840A0oLwAyNDuqOCswBPJEKf2bV0YWyA8,2004
19
- cloudnetpy/categorize/droplet.py,sha256=s-q1nCZ40rw5-fabfj61mH2lmdcNRT-TASvwWGZeptY,8688
20
- cloudnetpy/categorize/falling.py,sha256=Wz49mbw0pubnbhoekYTqGT0S9UNaE88jWOjSPEsCIaI,4386
21
- cloudnetpy/categorize/freezing.py,sha256=c4k5AIgfBpvw64EaVVVYPi2Fx4SpHk1cyfceE1ydD28,3755
19
+ cloudnetpy/categorize/droplet.py,sha256=t49KEsH5ZM68JQ4NvAf9kGgQ-evic1T4de2-jgJ2f4M,8683
20
+ cloudnetpy/categorize/falling.py,sha256=lok0HMi1ewf9pS70mq62nRKL6wJzMyWbYmv1cdwrwnA,4404
21
+ cloudnetpy/categorize/freezing.py,sha256=eSFD37R7vBrg7mgfSanrwhBjnFyWNBpjw2AtvRmSh48,3753
22
22
  cloudnetpy/categorize/insects.py,sha256=9J5agmktit8Or66GGNue-bThiaG9rB2SuPNZBXI7FCE,5243
23
+ cloudnetpy/categorize/itu.py,sha256=fnyPE4FreZhwXHJbOPTlHKeG9hTXuJZIKt_VBUQqiJo,10234
23
24
  cloudnetpy/categorize/lidar.py,sha256=YQrM_LOz8NQrrD9l9HyujV1GSGwkQ8LMqXN13bEJRW4,2605
24
- cloudnetpy/categorize/melting.py,sha256=mYdOKxfTC2InB8NdOPwr_7NpbouQMm-9f2Q1kfTqIJE,6262
25
- cloudnetpy/categorize/model.py,sha256=rLyx9SKz56BmQ809PwwhCnbusshUuYPoqhLJbnZvrt8,5842
25
+ cloudnetpy/categorize/melting.py,sha256=Oi80SrB4pNBhZlFhb6ayXkT2KMtXXV2rYu6jzEGn7tg,6211
26
+ cloudnetpy/categorize/model.py,sha256=stNfirRtMLPPH-9hydgS33aXeXeE50Cv_ki3BTjFApo,6630
26
27
  cloudnetpy/categorize/mwr.py,sha256=F7cquERWL6mBkgboqeaCIPf9gOlKI-NWUQIBdQXGT_I,1635
27
- cloudnetpy/categorize/radar.py,sha256=NCBjyC-OvkcprDnaDD0ql3WoKtSWMHcMhspTh5Zlmi8,13730
28
+ cloudnetpy/categorize/radar.py,sha256=0Wg5u2aLXRVhHiFiXb4fSqY_iGgSwcCMMVshM3wBoo0,14149
29
+ cloudnetpy/categorize/attenuations/__init__.py,sha256=CWFHVWeTIe2hrZtgkJaX2HGftbuffsFc39Mzv5B0Lw0,1037
30
+ cloudnetpy/categorize/attenuations/gas_attenuation.py,sha256=emr-RCxQT0i2N8k6eBNhRsmsCBPHJzQsWJfjC4fVSTo,975
31
+ cloudnetpy/categorize/attenuations/liquid_attenuation.py,sha256=0p0G79BPkw1itCXHMwbvkNHtJGBocJzow3gNHAirChI,3036
32
+ cloudnetpy/categorize/attenuations/melting_attenuation.py,sha256=-NDv8YZygqEsRHBs6RTkJ85Lu52o1Xo5ZUMI4cBoDbA,2334
33
+ cloudnetpy/categorize/attenuations/rain_attenuation.py,sha256=qazJzRyXf9vbjJhh4yiFmABI4L57j5W_6YZ-6qjRiBI,2839
28
34
  cloudnetpy/instruments/__init__.py,sha256=_jejVwi_viSZehmAOkEqTNI-0-exGgAJ_bHW1IRRwTI,398
29
35
  cloudnetpy/instruments/basta.py,sha256=_OTnySd36ktvxk_swWBzbv_H4AVGlkF_Ce3KtPGD1rE,3758
30
36
  cloudnetpy/instruments/campbell_scientific.py,sha256=2WHfBKQjtRSl0AqvtPeX7G8Hdi3Dn0WbvoAppFOMbA8,5270
@@ -53,7 +59,7 @@ cloudnetpy/instruments/disdrometer/common.py,sha256=g52iK2aNp3Z88kovUmGVpC54NZom
53
59
  cloudnetpy/instruments/disdrometer/parsivel.py,sha256=HJZrEysQkx9MiIVPDV25CYHpXi_SjgZlgO-otoaKK34,25640
54
60
  cloudnetpy/instruments/disdrometer/thies.py,sha256=JYFREICrf6nas3bJeEnJUtWzDc_4mEmt3TxhqO--bfQ,10632
55
61
  cloudnetpy/model_evaluation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
56
- cloudnetpy/model_evaluation/file_handler.py,sha256=0Pg7V6eo1G6KYeE10B6lR8hIKIJoseO-pBaorcW42rY,6446
62
+ cloudnetpy/model_evaluation/file_handler.py,sha256=jnpTxwxLSZdt08By0cjFDmq1KWC4fhJaN_MfjgA8ijQ,6440
57
63
  cloudnetpy/model_evaluation/metadata.py,sha256=PAsnOqcUoV3CJwplgWiVCF9Zt4io8tqj7CIgS4fEL-8,8412
58
64
  cloudnetpy/model_evaluation/model_metadata.py,sha256=CxpY6RPm7GOTBBmPhcNVVpm9ateUmHSUwGtFXTLq3To,1436
59
65
  cloudnetpy/model_evaluation/utils.py,sha256=Z9VqYVdtY9yTr2JeVfBn4nccIVWCN5Fd-BCyB_qYI-A,154
@@ -65,7 +71,7 @@ cloudnetpy/model_evaluation/products/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeu
65
71
  cloudnetpy/model_evaluation/products/advance_methods.py,sha256=rng3ZLR1Arv1AGUzq0Ehu-65628PC5LZVKpHSUpCIW8,8526
66
72
  cloudnetpy/model_evaluation/products/grid_methods.py,sha256=4no7mbKc9HlEXSNKPioqLmFZxUefuI-yqX0-Ej2jMzU,9067
67
73
  cloudnetpy/model_evaluation/products/model_products.py,sha256=uWi7zXQI7kR_ju0SL_BC1wozcq5DhaCcT-XZq33Q-bA,6861
68
- cloudnetpy/model_evaluation/products/observation_products.py,sha256=vrbHT008T4RFXM2pKm7dWPLKb1smD4rUNOM6IhUcU_w,5500
74
+ cloudnetpy/model_evaluation/products/observation_products.py,sha256=UJTb6-1Z-HOB9ltW8E7QHNEoByXeDQQUNi3GyS5lG_0,5500
69
75
  cloudnetpy/model_evaluation/products/product_resampling.py,sha256=IuWvtwpya76URh1WmTTgtLxAo4HZxkz6GmftpZkMCGo,3640
70
76
  cloudnetpy/model_evaluation/products/tools.py,sha256=lXnQ9XIEf5zqk_haY3mSrekPyGbAwNWvd6ZOol1Ip1Q,2918
71
77
  cloudnetpy/model_evaluation/statistics/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -85,31 +91,31 @@ cloudnetpy/model_evaluation/tests/e2e/process_lwc/tests.py,sha256=ANBA0LVao3Xrm-
85
91
  cloudnetpy/model_evaluation/tests/unit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
86
92
  cloudnetpy/model_evaluation/tests/unit/conftest.py,sha256=WL_FgrDeoUYGp4PKjb37HLu79D9uu33PGQL40_ctqS0,7446
87
93
  cloudnetpy/model_evaluation/tests/unit/test_advance_methods.py,sha256=IkoAVtsWVFrPpFqQOLAPHKb9qgV-KjGGVEtWMudeiSo,10079
88
- cloudnetpy/model_evaluation/tests/unit/test_grid_methods.py,sha256=qkNPfHI25EE0-BXk73TijpeM7YwswX7e41-764o5lqE,26254
94
+ cloudnetpy/model_evaluation/tests/unit/test_grid_methods.py,sha256=AEUXN5HBhKliPsSNGDCUtWOtIx6Y8iqkywb_-RfXYU0,26277
89
95
  cloudnetpy/model_evaluation/tests/unit/test_model_products.py,sha256=FRbYLshSHH2E527uJPwvUIyZKTsPFSZrwDsPsNrFSSU,3475
90
- cloudnetpy/model_evaluation/tests/unit/test_observation_products.py,sha256=P-W5QwRHMtem6p5SyyH7p9TvHGro3XW1baQcIwh6nFg,4892
96
+ cloudnetpy/model_evaluation/tests/unit/test_observation_products.py,sha256=DN3yVqq8vFYca_9POjcrJ8XViMrJks_jM-aQznfN8QQ,4936
91
97
  cloudnetpy/model_evaluation/tests/unit/test_plot_tools.py,sha256=POdypGWjV2NA4DCU7w8Unk_IdPfOpUb1qBDhfA3x1Bw,9222
92
98
  cloudnetpy/model_evaluation/tests/unit/test_plotting.py,sha256=h9V8JKmrO4v9bOvv-UjRa06sZJQPhDNVHGBSImDdtkI,3277
93
99
  cloudnetpy/model_evaluation/tests/unit/test_statistical_methods.py,sha256=Ra3r4V0qbqkpDuaTYvEIbaasl0nZ5gmTLR4eGC0glBQ,9724
94
100
  cloudnetpy/model_evaluation/tests/unit/test_tools.py,sha256=Ia_VrLdV2NstX5gbx_3AZTOAlrgLAy_xFZ8fHYVX0xI,3817
95
101
  cloudnetpy/plotting/__init__.py,sha256=lg9Smn4BI0dVBgnDLC3JVJ4GmwoSnO-qoSd4ApvwV6Y,107
96
- cloudnetpy/plotting/plot_meta.py,sha256=JHrr-4A9fhqdi_tQFe6mR4Fdry3hkI-lmmVu5Ny2vco,15979
97
- cloudnetpy/plotting/plotting.py,sha256=JIgia-Hujsa2ot4JMoBLzEdH7YWzmlGuKSLvvQ9tl0U,34253
102
+ cloudnetpy/plotting/plot_meta.py,sha256=ZvaKU3eXy1KFxQomnsEu3mCYpwwBYKAYk7oAwOzAGSg,16143
103
+ cloudnetpy/plotting/plotting.py,sha256=ML7v5iUlIBfeXX-F55Cf0GiHfDErblUWhfAXOCZZb3k,35141
98
104
  cloudnetpy/products/__init__.py,sha256=2hRb5HG9hNrxH1if5laJkLeFeaZCd5W1q3hh4ewsX0E,273
99
- cloudnetpy/products/classification.py,sha256=bNG8W1CMgGoUBpXopQjYAW3F-uEJGyojXb4A5jmErHo,7921
100
- cloudnetpy/products/der.py,sha256=1LDBbnbUg8feMUTGWJq3bObBhEcZ_Ee17MB1x0GwRdo,12669
105
+ cloudnetpy/products/classification.py,sha256=AKb9GCatvhS5KR0c9LfN96nUvzi02175ZCQlvMH1Dws,8077
106
+ cloudnetpy/products/der.py,sha256=soypE7uSEP4uHUCCQVEhyXsKY6e9mzV9B_2S5GUizqk,12729
101
107
  cloudnetpy/products/drizzle.py,sha256=58C9Mo6oRXR8KpbVPghbJvHvFX9GfS3xUp058pbf0qw,10804
102
108
  cloudnetpy/products/drizzle_error.py,sha256=4GwlHRtNbk9ks7bGtXCco-wXbcDOKeAQwKmbhzut6Qk,6132
103
- cloudnetpy/products/drizzle_tools.py,sha256=LR2AtbFQRGFrJ2LGyiLxOfbnlznVLydXvb8RFDR0_4E,10848
104
- cloudnetpy/products/ier.py,sha256=ge1f_aYick20Nlznq8zbBl5umWlTP-UwMivy4Y05Sck,7839
105
- cloudnetpy/products/iwc.py,sha256=Q8dXV3JF3JUQgwkmQFOKakm21Tnf8oCWsH0CSqIEKl4,10209
106
- cloudnetpy/products/lwc.py,sha256=wSd3GDqELz4yyWBMiKDR-QhRK8scPheqsBcS1qzxYOI,18997
109
+ cloudnetpy/products/drizzle_tools.py,sha256=SXD3GProk30NgRFIhvwLyeTEQ4PQPXFZ2RKgBR9WjbY,10870
110
+ cloudnetpy/products/ier.py,sha256=yv5bTBtA1tOB-dAt71Gnou1ywvrnhZRhmWk84p3oJRA,6006
111
+ cloudnetpy/products/iwc.py,sha256=_focccRSkgrS7wgKUY5ASfQ_PcmEZNQkvuvu3q9QA4o,9475
112
+ cloudnetpy/products/lwc.py,sha256=sl6Al2tuH3KkCBrPbWTmuz3jlD5UQJ4D6qBsn1tt2CQ,18962
107
113
  cloudnetpy/products/mie_lu_tables.nc,sha256=It4fYpqJXlqOgL8jeZ-PxGzP08PMrELIDVe55y9ob58,16637951
108
- cloudnetpy/products/mwr_tools.py,sha256=tN_sPDS3BdpFJfa5a2mnc3eCMoi7syjVJMaTt962hmo,5004
109
- cloudnetpy/products/product_tools.py,sha256=VNw2diJj30POz68-3qNVkJP7r9AUspT_d1Fp0BbeIx8,10414
114
+ cloudnetpy/products/mwr_tools.py,sha256=rd7UC67O4fsIE5SaHVZ4qWvUJTj41ZGwgQWPwZzOM14,5377
115
+ cloudnetpy/products/product_tools.py,sha256=01Zc6xV8CSuYcIcLpchFf5POL3_c629-YMNDZJ51udA,10853
110
116
  docs/source/conf.py,sha256=IKiFWw6xhUd8NrCg0q7l596Ck1d61XWeVjIFHVSG9Og,1490
111
- cloudnetpy-1.65.7.dist-info/LICENSE,sha256=wcZF72bdaoG9XugpyE95Juo7lBQOwLuTKBOhhtANZMM,1094
112
- cloudnetpy-1.65.7.dist-info/METADATA,sha256=KHoz5LFKsFR3kBEdosbY1L_jC15RvnJCjnotAaTQF0w,5784
113
- cloudnetpy-1.65.7.dist-info/WHEEL,sha256=cVxcB9AmuTcXqmwrtPhNK88dr7IR_b6qagTj0UvIEbY,91
114
- cloudnetpy-1.65.7.dist-info/top_level.txt,sha256=ibSPWRr6ojS1i11rtBFz2_gkIe68mggj7aeswYfaOo0,16
115
- cloudnetpy-1.65.7.dist-info/RECORD,,
117
+ cloudnetpy-1.66.0.dist-info/LICENSE,sha256=wcZF72bdaoG9XugpyE95Juo7lBQOwLuTKBOhhtANZMM,1094
118
+ cloudnetpy-1.66.0.dist-info/METADATA,sha256=EwNyFbZwEjCO1ykTbgOgruQsjgKlbJNAPU7O9Myg8-w,5784
119
+ cloudnetpy-1.66.0.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
120
+ cloudnetpy-1.66.0.dist-info/top_level.txt,sha256=ibSPWRr6ojS1i11rtBFz2_gkIe68mggj7aeswYfaOo0,16
121
+ cloudnetpy-1.66.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (74.1.2)
2
+ Generator: setuptools (75.1.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,376 +0,0 @@
1
- """This module contains functions to calculate
2
- various atmospheric parameters.
3
- """
4
-
5
- from typing import Final
6
-
7
- import numpy as np
8
- import scipy.constants
9
- from numpy import ma
10
-
11
- from cloudnetpy import constants as con
12
- from cloudnetpy import utils
13
- from cloudnetpy.categorize.atmos_utils import (
14
- calc_psychrometric_constant,
15
- calc_saturation_vapor_pressure,
16
- )
17
- from cloudnetpy.categorize.containers import ClassificationResult
18
- from cloudnetpy.categorize.model import Model
19
-
20
- M_TO_KM: Final = 0.001
21
- TWO_WAY: Final = 2
22
-
23
-
24
- def calc_lwc_change_rate(temperature: np.ndarray, pressure: np.ndarray) -> np.ndarray:
25
- """Returns rate of change of condensable water (LWC).
26
-
27
- Calculates the theoretical adiabatic rate of increase of LWC
28
- with height, given the cloud base temperature and pressure.
29
-
30
- Args:
31
- temperature: Temperature of cloud base (K).
32
- pressure: Pressure of cloud base (Pa).
33
-
34
- Returns:
35
- dlwc/dz (kg m-3 m-1)
36
-
37
- References:
38
- Brenguier, 1991, https://bit.ly/2QCSJtb
39
-
40
- """
41
- svp = calc_saturation_vapor_pressure(temperature)
42
- svp_mixing_ratio = calc_mixing_ratio(svp, pressure)
43
- air_density = calc_air_density(pressure, temperature, svp_mixing_ratio)
44
- kelvin_per_kg = calc_psychrometric_constant(temperature)
45
- pressure_difference = pressure - svp
46
- f1 = kelvin_per_kg - 1
47
- f2 = 1 / (
48
- kelvin_per_kg
49
- + (con.LATENT_HEAT * svp_mixing_ratio * air_density / pressure_difference)
50
- )
51
- f3 = con.MW_RATIO * svp * pressure_difference**-2
52
- dqs_dp = f1 * f2 * f3
53
- return dqs_dp * air_density**2 * -scipy.constants.g
54
-
55
-
56
- def calc_mixing_ratio(svp: np.ndarray, pressure: np.ndarray) -> np.ndarray:
57
- """Calculates mixing ratio from saturation vapor pressure and pressure.
58
-
59
- Args:
60
- svp: Saturation vapor pressure (Pa).
61
- pressure: Atmospheric pressure (Pa).
62
-
63
- Returns:
64
- Mixing ratio (kg kg-1).
65
-
66
- """
67
- return con.MW_RATIO * svp / (pressure - svp)
68
-
69
-
70
- def calc_air_density(
71
- pressure: np.ndarray,
72
- temperature: np.ndarray,
73
- svp_mixing_ratio: np.ndarray,
74
- ) -> np.ndarray:
75
- """Calculates air density (kg m-3).
76
-
77
- Args:
78
- pressure: Pressure (Pa).
79
- temperature: Temperature (K).
80
- svp_mixing_ratio: Saturation vapor pressure mixing ratio (kg/kg).
81
-
82
- Returns:
83
- Air density (kg m-3).
84
-
85
- """
86
- return pressure / (con.RS * temperature * (0.6 * svp_mixing_ratio + 1))
87
-
88
-
89
- def get_attenuations(data: dict, classification: ClassificationResult) -> dict:
90
- """Calculates attenuations due to atmospheric gases and liquid water.
91
-
92
- Args:
93
- data: Containing :class:`Model` and :class:`Mwr` instances.
94
- classification: A :class:`ClassificationResult` instance.
95
-
96
- Returns:
97
- Dictionary containing `radar_gas_atten`, `radar_liquid_atten`,
98
- `liquid_atten_err`, `liquid_corrected` and `liquid_uncorrected` fields.
99
-
100
- """
101
- gas = GasAttenuation(data, classification)
102
- liquid = LiquidAttenuation(data, classification)
103
- return {
104
- "radar_gas_atten": gas.atten,
105
- "radar_liquid_atten": liquid.atten,
106
- "liquid_atten_err": liquid.atten_err,
107
- "liquid_corrected": liquid.corrected,
108
- "liquid_uncorrected": liquid.uncorrected,
109
- }
110
-
111
-
112
- class Attenuation:
113
- """Base class for gas and liquid attenuations.
114
-
115
- Args:
116
- model: The :class:`Model` instance.
117
- classification: The :class:`ClassificationResult` instance.
118
-
119
- Attributes:
120
- classification (ClassificationResult): The :class:`ClassificationResult`
121
- instance.
122
-
123
- """
124
-
125
- def __init__(self, model: Model, classification: ClassificationResult):
126
- self._dheight = utils.mdiff(model.height)
127
- self._model = model.data_dense
128
- self._liquid_in_pixel = utils.isbit(classification.category_bits, 0)
129
- self.classification = classification
130
-
131
-
132
- class GasAttenuation(Attenuation):
133
- """Radar gas attenuation class. Child of Attenuation.
134
-
135
- Args:
136
- data: Containing :class:`Model` instance.
137
- classification: The :class:`ClassificationResult` instance.
138
-
139
- Attributes:
140
- atten (ndarray): Gas attenuation (dB).
141
-
142
- """
143
-
144
- def __init__(self, data: dict, classification: ClassificationResult):
145
- super().__init__(data["model"], classification)
146
- self.atten = self._calc_gas_atten()
147
-
148
- def _calc_gas_atten(self) -> np.ndarray:
149
- specific_atten = ma.copy(self._model["specific_gas_atten"])
150
- specific_atten_corrected = self._fix_atten_in_liquid(specific_atten)
151
- return self._specific_to_gas_atten(specific_atten_corrected)
152
-
153
- def _fix_atten_in_liquid(self, atten: np.ndarray) -> np.ndarray:
154
- saturated_atten = self._model["specific_saturated_gas_atten"]
155
- atten[self._liquid_in_pixel] = saturated_atten[self._liquid_in_pixel]
156
- return atten
157
-
158
- def _specific_to_gas_atten(self, specific_atten: np.ndarray) -> np.ndarray:
159
- layer1_atten = self._model["gas_atten"][:, 0]
160
- atten_cumsum = ma.cumsum(specific_atten, axis=1)
161
- atten = TWO_WAY * atten_cumsum * self._dheight * M_TO_KM
162
- atten += utils.transpose(layer1_atten)
163
- atten = np.insert(atten, 0, layer1_atten, axis=1)[:, :-1]
164
- return ma.array(atten, mask=atten_cumsum.mask)
165
-
166
-
167
- class LiquidAttenuation(Attenuation):
168
- """Radar liquid attenuation class. Child of Attenuation.
169
-
170
- Args:
171
- data: Containing :class:`Model` and :class:`Mwr` instances.
172
- classification: The :class:`ClassificationResult` instance.
173
-
174
- Attributes:
175
- atten (ndarray): Radar liquid attenuation (dB).
176
- atten_err (ndarray): Error of radar liquid attenuation (dB).
177
- uncorrected (ndarray): Boolean array denoting uncorrected pixels.
178
- corrected (ndarray): Boolean array denoting corrected pixels.
179
-
180
- """
181
-
182
- def __init__(self, data: dict, classification: ClassificationResult):
183
- super().__init__(data["model"], classification)
184
- if data["mwr"] is not None:
185
- self._mwr = data["mwr"].data
186
- else:
187
- n_time = data["radar"].data["Z"][:].shape[0]
188
- self._mwr = {
189
- "lwp": ma.masked_all(n_time),
190
- "lwp_error": ma.masked_all(n_time),
191
- }
192
- self._lwc_dz_err = self._get_lwc_change_rate_error()
193
- self.atten = self._get_liquid_atten()
194
- self.atten_err = self._get_liquid_atten_err()
195
- self.uncorrected = self._find_pixels_hard_to_correct()
196
- self.corrected = self._find_corrected_pixels()
197
- self._mask_uncorrected_attenuation()
198
-
199
- def _get_lwc_change_rate_error(self) -> np.ndarray:
200
- atmosphere = (self._model["temperature"], self._model["pressure"])
201
- return fill_clouds_with_lwc_dz(atmosphere, self._liquid_in_pixel)
202
-
203
- def _get_liquid_atten(self) -> ma.MaskedArray:
204
- """Finds radar liquid attenuation."""
205
- lwp = ma.copy(self._mwr["lwp"][:])
206
- lwp[lwp < 0] = 0
207
- lwc = calc_adiabatic_lwc(self._lwc_dz_err, self._dheight)
208
- lwc_scaled = distribute_lwp_to_liquid_clouds(lwc, lwp)
209
- return self._calc_attenuation(lwc_scaled)
210
-
211
- def _get_liquid_atten_err(self) -> ma.MaskedArray:
212
- """Finds radar liquid attenuation error."""
213
- lwc_err_scaled = distribute_lwp_to_liquid_clouds(
214
- self._lwc_dz_err,
215
- self._mwr["lwp_error"][:],
216
- )
217
- return self._calc_attenuation(lwc_err_scaled)
218
-
219
- def _calc_attenuation(self, lwc_scaled: np.ndarray) -> ma.MaskedArray:
220
- """Calculates liquid attenuation (dB)."""
221
- liquid_attenuation = ma.zeros(lwc_scaled.shape)
222
- spec_liq = self._model["specific_liquid_atten"]
223
- lwp_cumsum = ma.cumsum(lwc_scaled[:, :-1] * spec_liq[:, :-1], axis=1)
224
- liquid_attenuation[:, 1:] = TWO_WAY * lwp_cumsum * M_TO_KM
225
- return liquid_attenuation
226
-
227
- def _find_pixels_hard_to_correct(self) -> np.ndarray:
228
- melting_layer = utils.isbit(self.classification.category_bits, 3)
229
- hard_to_correct = np.cumsum(melting_layer, axis=1) >= 1
230
- hard_to_correct[self.classification.is_rain == 1, :] = True
231
- attenuated = self._find_attenuated_part_of_atmosphere()
232
- hard_to_correct[attenuated & self.atten.mask] = True
233
- return hard_to_correct
234
-
235
- def _find_corrected_pixels(self) -> np.ndarray:
236
- proper_values = ma.array(self.atten > 0)
237
- filled = False
238
- return proper_values.filled(filled) & ~self.uncorrected
239
-
240
- def _mask_uncorrected_attenuation(self) -> None:
241
- self.atten[self.uncorrected] = ma.masked
242
-
243
- def _find_attenuated_part_of_atmosphere(self) -> np.ndarray:
244
- return np.cumsum(self._lwc_dz_err, axis=1) > 0
245
-
246
-
247
- def fill_clouds_with_lwc_dz(atmosphere: tuple, is_liquid: np.ndarray) -> np.ndarray:
248
- """Fills liquid clouds with lwc change rate at the cloud bases.
249
-
250
- Args:
251
- atmosphere: 2-element tuple containing temperature (K) and pressure (Pa).
252
- is_liquid: Boolean array indicating presence of liquid clouds.
253
-
254
- Returns:
255
- Liquid water content change rate (kg/m3/m), so that for each cloud the base
256
- value is filled for the whole cloud.
257
-
258
- """
259
- lwc_dz = get_lwc_change_rate_at_bases(atmosphere, is_liquid)
260
- lwc_dz_filled = ma.zeros(lwc_dz.shape)
261
- lwc_dz_filled[is_liquid] = utils.ffill(lwc_dz[is_liquid])
262
- return lwc_dz_filled
263
-
264
-
265
- def get_lwc_change_rate_at_bases(
266
- atmosphere: tuple,
267
- is_liquid: np.ndarray,
268
- ) -> np.ndarray:
269
- """Finds LWC change rate in liquid cloud bases.
270
-
271
- Args:
272
- atmosphere: 2-element tuple containing temperature (K) and pressure (Pa).
273
- is_liquid: Boolean array indicating presence of liquid clouds.
274
-
275
- Returns:
276
- Liquid water content change rate at cloud bases (kg/m3/m).
277
-
278
- """
279
- liquid_bases = find_cloud_bases(is_liquid)
280
- lwc_dz = ma.zeros(liquid_bases.shape)
281
- lwc_dz[liquid_bases] = calc_lwc_change_rate(
282
- atmosphere[0][liquid_bases],
283
- atmosphere[1][liquid_bases],
284
- )
285
- return lwc_dz
286
-
287
-
288
- def find_cloud_bases(array: np.ndarray) -> np.ndarray:
289
- """Finds bases of clouds.
290
-
291
- Args:
292
- array: 2D boolean array denoting clouds or some other similar field.
293
-
294
- Returns:
295
- Boolean array indicating bases of the individual clouds.
296
-
297
- """
298
- zeros = np.zeros(array.shape[0])
299
- array_padded = np.insert(array, 0, zeros, axis=1).astype(int)
300
- return np.diff(array_padded, axis=1) == 1
301
-
302
-
303
- def find_cloud_tops(array: np.ndarray) -> np.ndarray:
304
- """Finds tops of clouds.
305
-
306
- Args:
307
- array: 2D boolean array denoting clouds or some other similar field.
308
-
309
- Returns:
310
- Boolean array indicating tops of the individual clouds.
311
-
312
- """
313
- array_flipped = np.fliplr(array)
314
- bases_of_flipped = find_cloud_bases(array_flipped)
315
- return np.fliplr(bases_of_flipped)
316
-
317
-
318
- def find_lowest_cloud_bases(
319
- cloud_mask: np.ndarray,
320
- height: np.ndarray,
321
- ) -> ma.MaskedArray:
322
- """Finds altitudes of cloud bases."""
323
- cloud_heights = cloud_mask * height
324
- return _find_lowest_heights(cloud_heights)
325
-
326
-
327
- def find_highest_cloud_tops(
328
- cloud_mask: np.ndarray,
329
- height: np.ndarray,
330
- ) -> ma.MaskedArray:
331
- """Finds altitudes of cloud tops."""
332
- cloud_heights = cloud_mask * height
333
- cloud_heights_flipped = np.fliplr(cloud_heights)
334
- return _find_lowest_heights(cloud_heights_flipped)
335
-
336
-
337
- def _find_lowest_heights(cloud_heights: np.ndarray) -> ma.MaskedArray:
338
- inds = (cloud_heights != 0).argmax(axis=1)
339
- heights = np.array([cloud_heights[i, ind] for i, ind in enumerate(inds)])
340
- return ma.masked_equal(heights, 0.0)
341
-
342
-
343
- def calc_adiabatic_lwc(lwc_change_rate: np.ndarray, dheight: float) -> np.ndarray:
344
- """Calculates adiabatic liquid water content (kg/m3).
345
-
346
- Args:
347
- lwc_change_rate: Liquid water content change rate (kg/m3/m) calculated at the
348
- base of each cloud and filled to that cloud.
349
- dheight: Median difference of the height vector (m).
350
-
351
- Returns:
352
- Liquid water content (kg/m3).
353
-
354
- """
355
- is_liquid = lwc_change_rate != 0
356
- ind_from_base = utils.cumsumr(is_liquid, axis=1)
357
- return ind_from_base * dheight * lwc_change_rate
358
-
359
-
360
- def distribute_lwp_to_liquid_clouds(lwc: np.ndarray, lwp: np.ndarray) -> np.ndarray:
361
- """Finds LWC that would produce measured LWP.
362
-
363
- Calculates LWP-weighted, normalized LWC. This is the measured
364
- LWP distributed to liquid cloud pixels according to their
365
- theoretical proportion, i.e., sum(scaled LWC) = measured LWP.
366
-
367
- Args:
368
- lwc: 2D liquid water content (kg/m3).
369
- lwp: 1D liquid water path (kg/m2).
370
-
371
- Returns:
372
- 2D LWP-weighted, normalized LWC (kg/m2).
373
-
374
- """
375
- lwc_sum = ma.sum(lwc, axis=1)
376
- return (lwc.T / lwc_sum * lwp).T