From fc9206f10dbb374b8ac004c8906f814499d4359b Mon Sep 17 00:00:00 2001 From: Dion Ho Jia Xu Date: Tue, 4 Jun 2024 13:41:21 -0400 Subject: [PATCH 1/5] Completed changes to address JOSS reviewer feedback. Fixed error in paper.bib and changed .gitignore. Finally re-added PyTests as history re-write is complete. Update README.md Added Matplotlib to dependencies and corrected minor error in Jupyter Notebook documentation. --- PythonicDISORT_optional_dependencies.txt | 1 + README.md | 44 +- all_optional_dependencies.txt | 4 +- docs/JOSS_Paper/paper.bib | 122 ++ docs/JOSS_Paper/paper.md | 100 +- docs/Pythonic-DISORT.ipynb | 532 +++-- docs/index.rst | 4 +- docs/section6_testresults.npz | Bin 0 -> 330294 bytes pydisotest/11_test.py | 73 + pydisotest/1_test.ipynb | 1890 +++++++++++++++++ pydisotest/1_test.py | 449 ++++ pydisotest/2_test.ipynb | 1303 ++++++++++++ pydisotest/2_test.py | 306 +++ pydisotest/3_test.ipynb | 746 +++++++ pydisotest/3_test.py | 157 ++ pydisotest/4_test.ipynb | 1025 +++++++++ pydisotest/4_test.py | 251 +++ pydisotest/5_test.ipynb | 1046 +++++++++ pydisotest/5_test.py | 274 +++ pydisotest/8_test.ipynb | 1000 +++++++++ pydisotest/8_test.py | 235 ++ pydisotest/9_test.ipynb | 718 +++++++ pydisotest/9_test.py | 167 ++ pydisotest/Stamnes_results/1a_test.npz | Bin 0 -> 1250 bytes pydisotest/Stamnes_results/1b_test.npz | Bin 0 -> 1251 bytes pydisotest/Stamnes_results/1c_test.npz | Bin 0 -> 1253 bytes pydisotest/Stamnes_results/1d_test.npz | Bin 0 -> 1252 bytes pydisotest/Stamnes_results/1e_test.npz | Bin 0 -> 1250 bytes pydisotest/Stamnes_results/1f_test.npz | Bin 0 -> 1250 bytes pydisotest/Stamnes_results/2a_test.npz | Bin 0 -> 1319 bytes pydisotest/Stamnes_results/2b_test.npz | Bin 0 -> 1322 bytes pydisotest/Stamnes_results/2c_test.npz | Bin 0 -> 1317 bytes pydisotest/Stamnes_results/2d_test.npz | Bin 0 -> 1318 bytes pydisotest/Stamnes_results/3a_test.npz | Bin 0 -> 1251 bytes pydisotest/Stamnes_results/3b_test.npz | Bin 0 -> 1252 bytes pydisotest/Stamnes_results/4a_test.npz | Bin 0 -> 1471 bytes pydisotest/Stamnes_results/4b_test.npz | Bin 0 -> 1473 bytes pydisotest/Stamnes_results/4c_test.npz | Bin 0 -> 1725 bytes pydisotest/Stamnes_results/5BDRF_test.npz | Bin 0 -> 1477 bytes pydisotest/Stamnes_results/5a_test.npz | Bin 0 -> 1602 bytes pydisotest/Stamnes_results/5b_test.npz | Bin 0 -> 1803 bytes pydisotest/Stamnes_results/8a_test.npz | Bin 0 -> 1262 bytes pydisotest/Stamnes_results/8b_test.npz | Bin 0 -> 1263 bytes pydisotest/Stamnes_results/8c_test.npz | Bin 0 -> 1277 bytes pydisotest/Stamnes_results/9a_test.npz | Bin 0 -> 1355 bytes pydisotest/Stamnes_results/9b_test.npz | Bin 0 -> 1355 bytes .../_assemble_intensity_and_fluxes.py | 37 +- src/PythonicDISORT/_solve_for_coeffs.py | 6 +- .../_solve_for_gen_and_part_sols.py | 30 +- src/PythonicDISORT/pydisort.py | 19 +- src/PythonicDISORT/subroutines.py | 2 + 51 files changed, 10218 insertions(+), 323 deletions(-) create mode 100644 docs/section6_testresults.npz create mode 100644 pydisotest/11_test.py create mode 100644 pydisotest/1_test.ipynb create mode 100644 pydisotest/1_test.py create mode 100644 pydisotest/2_test.ipynb create mode 100644 pydisotest/2_test.py create mode 100644 pydisotest/3_test.ipynb create mode 100644 pydisotest/3_test.py create mode 100644 pydisotest/4_test.ipynb create mode 100644 pydisotest/4_test.py create mode 100644 pydisotest/5_test.ipynb create mode 100644 pydisotest/5_test.py create mode 100644 pydisotest/8_test.ipynb create mode 100644 pydisotest/8_test.py create mode 100644 pydisotest/9_test.ipynb create mode 100644 pydisotest/9_test.py create mode 100644 pydisotest/Stamnes_results/1a_test.npz create mode 100644 pydisotest/Stamnes_results/1b_test.npz create mode 100644 pydisotest/Stamnes_results/1c_test.npz create mode 100644 pydisotest/Stamnes_results/1d_test.npz create mode 100644 pydisotest/Stamnes_results/1e_test.npz create mode 100644 pydisotest/Stamnes_results/1f_test.npz create mode 100644 pydisotest/Stamnes_results/2a_test.npz create mode 100644 pydisotest/Stamnes_results/2b_test.npz create mode 100644 pydisotest/Stamnes_results/2c_test.npz create mode 100644 pydisotest/Stamnes_results/2d_test.npz create mode 100644 pydisotest/Stamnes_results/3a_test.npz create mode 100644 pydisotest/Stamnes_results/3b_test.npz create mode 100644 pydisotest/Stamnes_results/4a_test.npz create mode 100644 pydisotest/Stamnes_results/4b_test.npz create mode 100644 pydisotest/Stamnes_results/4c_test.npz create mode 100644 pydisotest/Stamnes_results/5BDRF_test.npz create mode 100644 pydisotest/Stamnes_results/5a_test.npz create mode 100644 pydisotest/Stamnes_results/5b_test.npz create mode 100644 pydisotest/Stamnes_results/8a_test.npz create mode 100644 pydisotest/Stamnes_results/8b_test.npz create mode 100644 pydisotest/Stamnes_results/8c_test.npz create mode 100644 pydisotest/Stamnes_results/9a_test.npz create mode 100644 pydisotest/Stamnes_results/9b_test.npz diff --git a/PythonicDISORT_optional_dependencies.txt b/PythonicDISORT_optional_dependencies.txt index fda8def..be052de 100644 --- a/PythonicDISORT_optional_dependencies.txt +++ b/PythonicDISORT_optional_dependencies.txt @@ -1,4 +1,5 @@ # Optional dependencies for the PythonicDISORT package # Install through "pip install -r PythonicDISORT_optional_dependencies.txt" +PythonicDISORT pytest \ No newline at end of file diff --git a/README.md b/README.md index 45d209f..fa849ec 100644 --- a/README.md +++ b/README.md @@ -1,40 +1,41 @@ # Introduction -The PythonicDISORT package is a Discrete Ordinates Solver for the (1D) Radiative Transfer Equation in a single or multi-layer plane-parallel atmosphere. +The PythonicDISORT package is a Discrete Ordinates Solver for the (1D) Radiative Transfer Equation +in a plane-parallel, horizontally homogeneous atmosphere. It is coded entirely in Python 3 and is a reimplementation instead of a wrapper. While PythonicDISORT has been optimized for speed, it will naturally be slower than similar FORTRAN algorithms. On the other hand, PythonicDISORT should be easier to install, use, and modify than FORTRAN-based Discrete Ordinates Solvers. -PythonicDISORT is based on Stamnes' FORTRAN DISORT (see References, in particular [2, 3, 8]) and has its main features: -delta-M scaling, Nakajima-Tanaka (NT) corrections, only flux option, isotropic internal sources (thermal sources), +PythonicDISORT is based on Stamnes' FORTRAN DISORT (see References, in particular [2, 3, 8]) and has its main features: multi-layer solver, +delta-M scaling, Nakajima-Tanaka (NT) corrections, only flux option, direct beam source, isotropic internal source (blackbody emission), Dirichlet boundary conditions (diffuse flux boundary sources), Bi-Directional Reflectance Function (BDRF) for surface reflection, and more. -In addition, upon the request of a user, we added a subroutine to calculate actinic fluxes and we are open to further feature requests as well as feedback. +In addition, subroutine to calculate actinic fluxes was added to satisfy a user request and further feature requests as well as feedback are welcome. You may contact me, Dion, through dh3065@columbia.edu. -Our **GitHub repository:** https://github.com/LDEO-CREW/Pythonic-DISORT also includes our F2PY-wrapped Stamnes DISORT (version 4.0.99) in the `disort4.0.99_f2py` directory. -The original was downloaded from http://www.rtatmocn.com/disort/. The wrapper is inspired by https://github.com/kconnour/pyRT_DISORT. +The **GitHub repository** is https://github.com/LDEO-CREW/Pythonic-DISORT. # Documentation https://pythonic-disort.readthedocs.io/en/latest/ Also see the accompanying Jupyter Notebook `Pythonic-DISORT.ipynb` in the `docs` directory of our GitHub repository. -The Jupyter Notebook provides comprehensive documentation, suggested inputs, explanations, +This Jupyter Notebook provides comprehensive documentation, suggested inputs, explanations, mathematical derivations and verification tests. -We highly recommend reading the non-optional parts of sections 1 and 2 before use. +It is highly recommended that new users read the non-optional parts of sections 1 and 2. ## PyTest and examples of how to use PythonicDISORT -Not only do we have verification tests in the Jupyter Notebook, we have also recreated most of the test problems in Stamnes' `disotest.f90`; -`disotest.f90` is included in the `disort4.0.99_f2py` directory of our GitHub repository. In these tests, the solutions from PythonicDISORT are compared -against solutions from our F2PY-wrapped Stamnes' DISORT (version 4.0.99). With PyTest installed, execute the console command `pytest` -in the `pydisotest` directory to run these tests. The `pydisotest` directory also contains Jupyter Notebooks, one for each test, -to show how the tests were implemented. These notebooks double up as examples of how to use PythonicDISORT. +Not only are there verification tests in `Pythonic-DISORT.ipynb`, +most of the test problems in Stamnes' `disotest.f90` (download DISORT 4.0.99 from http://www.rtatmocn.com/disort/) have also been recreated. +In these tests, the solutions from PythonicDISORT are compared against solutions +from a F2PY-wrapped Stamnes' DISORT (version 4.0.99; wrapper inspired by https://github.com/kconnour/pyRT_DISORT). With PyTest installed, execute the console command `pytest` +in the `pydisotest` directory to run these tests. The `pydisotest` directory also contains Jupyter Notebooks that correspond to each test +to show how it was implemented. These notebooks double up as examples of how to use PythonicDISORT. # Installation * From PyPI: `pip install PythonicDISORT` -* From Conda-forge: (TODO: we need to first publish on Conda-forge) +* From Conda-forge: (TODO: need to first publish on Conda-forge) * By cloning repository: `pip install .` in the `Pythonic-DISORT` directory; `pip install -r all_optional_dependencies.txt` to install all optional dependencies (see *Requirements to run PythonicDISORT*) ## Requirements to run PythonicDISORT @@ -43,21 +44,18 @@ to show how the tests were implemented. These notebooks double up as examples of * `scipy >= 1.8.0` * (OPTIONAL) `pytest >= 6.2.5` (Required to use the command `pytest`, see *PyTest and examples of how to use PythonicDISORT*) -## Additional requirements to run the Jupyter Notebook +## (OPTIONAL) Additional requirements to run the Jupyter Notebook * `autograd >= 1.5` * `jupyter > 1.0.0` * `notebook > 6.5.2` +* `matplotlib >= 3.6.0` -In addition, our F2PY-wrapped Stamnes' DISORT (in the `disort4.0.99_f2py` directory), or equivalent, -must be set up to run the last section (section 6). +In addition, a F2PY-wrapped Stamnes' DISORT, or equivalent, is required to properly run the last section (section 6). ## Compatibility -The PythonicDISORT package *should* be system agnostic given its minimal dependencies and pure Python code. -We do not guarantee that our Jupyter Notebook and F2PY-wrapped Stamnes' DISORT will work on other systems though. -The latter will almost certainly need user edits to work and in any case it requires FORTRAN compilers which -are not included in our GitHub repository. Everything in the repository was built and tested on Windows 11 but -not yet tested on other systems. +The PythonicDISORT package should be system agnostic given its minimal dependencies and pure Python code. +Everything in the repository was built and tested on Windows 11. # Acknowledgements @@ -87,4 +85,4 @@ Science and Technology Center (STC) (Award #2019625) under which this package wa 11) T. Nakajima and M. Tanaka. 1988. *Algorithms for radiative intensity calculations in moderately thick atmospheres using a truncation approximation.* https://www.sciencedirect.com/science/article/pii/0022407388900313. -12) K. Connour and A. Stcherbinine. 2022. *pyRT_DISORT.* https://github.com/kconnour/pyRT_DISORT. +12) Connour, Kyle and Wolff, Michael. 2020. *pyRT_DISORT: A pre-processing front-end to help make DISORT simulations easier in Python.* https://github.com/kconnour/pyRT_DISORT. diff --git a/all_optional_dependencies.txt b/all_optional_dependencies.txt index 84d577c..a56546e 100644 --- a/all_optional_dependencies.txt +++ b/all_optional_dependencies.txt @@ -1,7 +1,9 @@ # All optional dependencies for the Pythonic DISORT project # Install through "pip install -r all_optional_dependencies.txt" +PythonicDISORT pytest autograd jupyter -notebook \ No newline at end of file +notebook +matplotlib \ No newline at end of file diff --git a/docs/JOSS_Paper/paper.bib b/docs/JOSS_Paper/paper.bib index a66357f..6ab10ab 100644 --- a/docs/JOSS_Paper/paper.bib +++ b/docs/JOSS_Paper/paper.bib @@ -1,3 +1,125 @@ +@article{TLZWSY2020, +author = {Teng, Shiwen and Liu, Chao and Zhang, Zhibo and Wang, Yuan and Sohn, Byung-Ju and Yung, Yuk L.}, +title = {Retrieval of Ice-Over-Water Cloud Microphysical and Optical Properties Using Passive Radiometers}, +journal = {Geophysical Research Letters}, +volume = {47}, +number = {16}, +pages = {e2020GL088941}, +keywords = {cloud properties, satellite radiometer, vertical distribution}, +doi = {10.1029/2020GL088941}, +url = {https://agupubs.onlinelibrary.wiley.com/doi/abs/10.1029/2020GL088941}, +eprint = {https://agupubs.onlinelibrary.wiley.com/doi/pdf/10.1029/2020GL088941}, +note = {e2020GL088941 2020GL088941}, +abstract = {Abstract Current satellite cloud products from passive radiometers provide effective single-layer cloud properties by assuming a homogeneous cloud in a pixel, resulting in inevitable biases when multiple-layer clouds are present in a vertical column. We devise a novel method to retrieve cloud vertical properties for ice-over-water clouds using passive radiometers. Based on the absorptivity differences of liquid water and ice clouds at four shortwave-infrared channels (centered at 0.87, 1.61, 2.13, and 2.25 μm), cloud optical thicknesses (COT) and effective radii of both upper-layer ice and lower-layer liquid water clouds are inferred simultaneously. The algorithm works most effectively for clouds with ice COT < 7 and liquid water COT > 5. The simulated spectral reflectances based on our retrieved ice-over-water clouds become more consistent with observations than those with a single-layer assumption. This new algorithm will improve our understanding of clouds, and we suggest that these four cloud channels should be all included in future satellite sensors.}, +year = {2020} +} + +@article{TCCGL1999, +author = {Torricella, Francesca and Cattani, Elsa and Cervino, Marco and Guzzi, Rodolfo and Levoni, Chiara}, +title = {Retrieval of aerosol properties over the ocean using Global Ozone Monitoring Experiment measurements: Method and applications to test cases}, +journal = {Journal of Geophysical Research: Atmospheres}, +volume = {104}, +number = {D10}, +pages = {12085-12098}, +doi = {10.1029/1999JD900040}, +url = {https://agupubs.onlinelibrary.wiley.com/doi/abs/10.1029/1999JD900040}, +eprint = {https://agupubs.onlinelibrary.wiley.com/doi/pdf/10.1029/1999JD900040}, +abstract = {Satellite monitoring of aerosol properties using passive techniques is widely considered a crucial tool for the study of climatic effects of atmospheric particulate [Kaufman et al., 1997]. Only space-based observations can provide the required global coverage information on spatial distribution and temporal variation of the aerosol field. This paper describes a method for deriving aerosol optical thickness at 500 nm and aerosol type from Global Ozone Monitoring Experiment (GOME) data over the ocean under cloud-free conditions. GOME, flying on board the second European Remote Sensing satellite (ERS 2) since April 1995, is a spectrometer that measures radiation reflected from Earth in the spectral range 240–793 nm. The features of the instrument relevant to the aerosol retrieval task are its high relative radiometric accuracy (better than 1\%), its spectral coverage, and its spectral resolution, which allows wavelengths in spectral regions free of molecular absorption (atmospheric windows) to be selected. The method presented is based on a pseudo-inversion approach in which measured reflectance spectra are fitted to simulated equivalents computed using a suitable radiative transfer model. The crucial aspects of this method are the high accuracy and the nonapproximate nature of the radiative transfer model, which simulates the spectra during the fitting procedure, and careful selection of candidate aerosol classes. A test application of the proposed method to a Saharan dust outbreak which occurred in June 1997 is presented, showing that in spite of the instrument's low spatial resolution, information on both optical thickness and spectral characterization of the aerosol can be retrieved from GOME data. Preliminary comparisons of the results with independent estimates of the aerosol content show that a good correlation exists, encouraging planning of a systematic application of the method.}, +year = {1999} +} + +@ARTICLE{MRO/CRISM2008, + author={McGuire, Patrick C. and Wolff, Michael J. and Smith, Michael D. and Arvidson, Raymond E. and Murchie, Scott L. and Clancy, R. Todd and Roush, Ted L. and Cull, Selby C. and Lichtenberg, Kim A. and Wiseman, Sandra M. and Green, Robert O. and Martin, Terry Z. and Milliken, Ralph E. and Cavender, Peter J. and Humm, David C. and Seelos, Frank P. and Seelos, Kim D. and Taylor, Howard W. and Ehlmann, Bethany L. and Mustard, John F. and Pelkey, Shannon M. and Titus, Timothy N. and Hash, Christopher D. and Malaret, Erick R.}, + journal={IEEE Transactions on Geoscience and Remote Sensing}, + title={MRO/CRISM Retrieval of Surface Lambert Albedos for Multispectral Mapping of Mars With DISORT-Based Radiative Transfer Modeling: Phase 1—Using Historical Climatology for Temperatures, Aerosol Optical Depths, and Atmospheric Pressures}, + year={2008}, + volume={46}, + number={12}, + pages={4020-4040}, + keywords={Mars;Temperature;Aerosols;Optical surface waves;Optical variables control;Atmospheric waves;Surface reconstruction;Ice;Information retrieval;Atmospheric modeling;Atmospheric propagation;infrared spectroscopy;remote sensing;software verification and validation}, + doi={10.1109/TGRS.2008.2000631}} + +@conference{JupyterNotebook, +Title = {Jupyter Notebooks -- a publishing format for reproducible computational workflows}, +Author = {Thomas Kluyver and Benjamin Ragan-Kelley and Fernando P{\'e}rez and Brian Granger and Matthias Bussonnier and Jonathan Frederic and Kyle Kelley and Jessica Hamrick and Jason Grout and Sylvain Corlay and Paul Ivanov and Dami{\'a}n Avila and Safia Abdalla and Carol Willing}, +Booktitle = {Positioning and Power in Academic Publishing: Players, Agents and Agendas}, +Editor = {F. Loizides and B. Schmidt}, +Organization = {IOS Press}, +Pages = {87 - 90}, +Year = {2016} +} + +@ARTICLE{SciPy, + author = {Virtanen, Pauli and Gommers, Ralf and Oliphant, Travis E. and + Haberland, Matt and Reddy, Tyler and Cournapeau, David and + Burovski, Evgeni and Peterson, Pearu and Weckesser, Warren and + Bright, Jonathan and {van der Walt}, St{\'e}fan J. and + Brett, Matthew and Wilson, Joshua and Millman, K. Jarrod and + Mayorov, Nikolay and Nelson, Andrew R. J. and Jones, Eric and + Kern, Robert and Larson, Eric and Carey, C J and + Polat, {\.I}lhan and Feng, Yu and Moore, Eric W. and + {VanderPlas}, Jake and Laxalde, Denis and Perktold, Josef and + Cimrman, Robert and Henriksen, Ian and Quintero, E. A. and + Harris, Charles R. and Archibald, Anne M. and + Ribeiro, Ant{\^o}nio H. and Pedregosa, Fabian and + {van Mulbregt}, Paul and {SciPy 1.0 Contributors}}, + title = {{{SciPy} 1.0: Fundamental Algorithms for Scientific + Computing in Python}}, + journal = {Nature Methods}, + year = {2020}, + volume = {17}, + pages = {261--272}, + adsurl = {https://rdcu.be/b08Wh}, + doi = {10.1038/s41592-019-0686-2}, +} + +@Article{NumPy, + title = {Array programming with {NumPy}}, + author = {Charles R. Harris and K. Jarrod Millman and St{\'{e}}fan J. + van der Walt and Ralf Gommers and Pauli Virtanen and David + Cournapeau and Eric Wieser and Julian Taylor and Sebastian + Berg and Nathaniel J. Smith and Robert Kern and Matti Picus + and Stephan Hoyer and Marten H. van Kerkwijk and Matthew + Brett and Allan Haldane and Jaime Fern{\'{a}}ndez del + R{\'{i}}o and Mark Wiebe and Pearu Peterson and Pierre + G{\'{e}}rard-Marchant and Kevin Sheppard and Tyler Reddy and + Warren Weckesser and Hameer Abbasi and Christoph Gohlke and + Travis E. Oliphant}, + year = {2020}, + month = sep, + journal = {Nature}, + volume = {585}, + number = {7825}, + pages = {357--362}, + doi = {10.1038/s41586-020-2649-2}, + publisher = {Springer Science and Business Media {LLC}}, + url = {https://doi.org/10.1038/s41586-020-2649-2} +} + +@book{Cha1960, + author = "S. Chandrasekhar", + title = "Radiative Transfer", + year = "1960", + publisher = "Dover", +} + +@software{CM2020, +author = {Connour, Kyle and Wolff, Michael}, +license = {BSD-3-Clause}, +title = {{pyRT_DISORT: A pre-processing front-end to help make DISORT simulations easier in Python}}, +url = {https://github.com/kconnour/pyRT_DISORT}, +version = {1.0.0}, +year={2020} +} + +@software{Hu2017, + author={Zoey Hu}, + title={pyDISORT}, + url={https://github.com/chanGimeno/pyDISORT}, + version = {0.8}, + year={2017} +} + @article{STWJ1988, author = {Knut Stamnes and S-Chee Tsay and Warren Wiscombe and Kolf Jayaweera}, journal = {Appl. Opt.}, diff --git a/docs/JOSS_Paper/paper.md b/docs/JOSS_Paper/paper.md index c0b8534..e656a69 100644 --- a/docs/JOSS_Paper/paper.md +++ b/docs/JOSS_Paper/paper.md @@ -58,13 +58,28 @@ aas-journal: Astrophysical Journal <- The name of the AAS journal. ---> # Summary + + +The Radiative Transfer Equation (RTE) models the processes of absorption, scattering and emission +as electromagnetic radiation propagates through a medium. +Consider a plane-parallel, horizontally homogeneous atmosphere with vertical coordinate +$\tau$ (optical depth) increasing from top to bottom and directional coordinates $\phi$ for the azimuthal angle (positive is counterclockwise) +and $\mu=\cos\theta$ for the polar direction ($\theta$ is the polar angle measured from the surface normal), +with $\mu > 0$ pointing up following the convention of [@STWJ1988]. +Given three possible sources: +blackbody emission from the atmosphere $s(\tau)$, +scattering from a direct beam (of sunlight) with intensity $I_0$ and incident cosine polar and azimuthal angles $\mu_0, \phi_0$, +and/or radiation from other atmospheric layers or the Earth's surface which is modeled by Dirichlet boundary conditions, +the diffuse intensity $u(\tau, \mu, \phi)$ propagating in direction $(\mu, \phi)$ +is described by the 1D RTE [@Cha1960; @STWJ1988]: \begin{align} \begin{split} @@ -73,46 +88,65 @@ Dirichlet boundary conditions. \end{split} \label{RTE} \end{align} -The RTE is important in many fields of science and engineering. +Here $\omega$ is the single-scattering albedo and $p$ the scattering phase function. +These are assumed to be independent of $\tau$, i.e. homogeneous in the atmospheric layer. +An atmosphere with $\tau$-dependent $\omega$ and $p$ can be modelled by +a multi-layer atmosphere with different $\omega$ and $p$ for each layer. + +The RTE is important in many fields of science and engineering, +for example, in the retrieval of optical properties from measurements [@TCCGL1999; @MRO/CRISM2008; @TLZWSY2020]. The gold standard for numerically solving the 1D RTE is the Discrete Ordinate Radiative Transfer -package `DISORT` which was coded in FORTRAN 77 and first released in 1988 [@STWJ1988]. +package `DISORT` which was coded in FORTRAN 77 and first released in 1988 [@STWJ1988; @Sta1999]. It has been widely used, for example by `MODTRAN` [@Ber2014], `Streamer` [@Key1998], and `SBDART` [@Ric1998], -all of which are comprehensive radiative transfer models that are themselves widely used in atmospheric science. +all of which are comprehensive radiative transfer models that are themselves widely used in atmospheric science, +and by the three retrieval papers @TCCGL1999; @MRO/CRISM2008; @TLZWSY2020. `DISORT` implements the Discrete Ordinates Method which has two key steps. -First, the diffuse intensity function $u$ is expanded as the Fourier cosine series: +First, the diffuse intensity function $u$ and phase function $p$ are expanded as the Fourier cosine series and Legendre series respectively: $$ -u\left(\tau, \mu, \phi\right) = \sum_{m=0} u^m\left(\tau, \mu\right)\cos\left(m\left(\phi_0 - \phi\right)\right) +\begin{aligned} +u\left(\tau, \mu, \phi\right) &\approx \sum_{m=0} u^m\left(\tau, \mu\right)\cos\left(m\left(\phi_0 - \phi\right)\right) \\ +p\left(\mu, \phi ; \mu', \phi'\right) = p\left(\cos\gamma\right) &\approx \sum_{\ell=0} (2\ell + 1) g_\ell P_\ell\left(\cos\gamma\right) +\end{aligned} $$ -This addresses the $\phi'$ integral in (\ref{RTE}) and decomposes the problem into solving +where $\gamma$ is the scattering angle. +These address the $\phi'$ integral in (\ref{RTE}) and decompose the problem into solving $$ \mu \frac{d u^m(\tau, \mu)}{d \tau}=u^m(\tau, \mu)-\int_{-1}^1 D^m\left(\mu, \mu'\right) u^m\left(\tau, \mu'\right) \mathrm{d} \mu' - Q^m(\tau, \mu) - \delta_{0m}s(\tau) $$ -for each Fourier mode of $u$. The second key step is to discretize the $\mu'$ integral using -some quadrature scheme; `DISORT` uses the double-Gauss quadrature scheme from @Syk1951. -This results in a system of ODEs that can be solved using standard methods. +for each Fourier mode of $u$. The terms $D^m$ are derived from $p$ +and are thus also independent of $\tau$. The second key step is to discretize the +$\mu'$ integral using some quadrature scheme; `DISORT` +uses the double-Gauss quadrature scheme from @Syk1951. +This results in a system of ordinary differential equations that can be solved using standard methods. Our package `PythonicDISORT` is a Python 3 reimplementation of `DISORT` that replicates most of its functionality while being easier to install, use, and modify, though at the cost of computational speed. It has `DISORT`'s main features: -multi-layer solving, delta-M scaling, Nakajima-Tanaka (NT) corrections, only flux option, -isotropic internal sources (thermal sources), Dirichlet boundary conditions -(diffuse flux boundary sources), Bi-Directional Reflectance Function (BDRF) +multi-layer solver, delta-M scaling, Nakajima-Tanaka (NT) corrections, only flux option, +direct beam source, isotropic internal source (blackbody emission), Dirichlet boundary conditions +(diffuse flux boundary sources), Bi-Directional Reflectance Function (BDRF) for surface reflection, and more. In addition, `PythonicDISORT` has been -tested against `DISORT` on `DISORT`'s own test problems. As far as we know, all -prior attempts at creating Python interfaces for `DISORT` have focused -on creating wrappers and `PythonicDISORT` is the first true Python reimplementation. +tested against `DISORT` on `DISORT`'s own test problems. While packages +that wrap `DISORT` in Python already exist [@CM2020; @Hu2017], +`PythonicDISORT` is the first time `DISORT` +has been reimplemented from scratch in Python. # Statement of need -We clarify that `PythonicDISORT` is not meant to replace `DISORT`. Due to fundamental +`PythonicDISORT` is not meant to replace `DISORT`. Due to fundamental differences between Python and FORTRAN, `PythonicDISORT`, though optimized, -remains about an order of magnitude slower than `DISORT`. Thus, projects which -prioritize computational speed should still use `DISORT`. Moreover, `PythonicDISORT` -lacks `DISORT`'s latest features, most notably its pseudo-spherical correction. +remains about an order of magnitude slower than `DISORT`. Thus, projects that +prioritize computational speed should still use `DISORT`. I will continue to optimize +`PythonicDISORT`; there remain avenues for code vectorization among other optimizations. +It is unlikely that `PythonicDISORT` can be optimized to achieve the speed of `DISORT` though. +In addition, `PythonicDISORT` currently lacks `DISORT`'s latest features, +most notably its pseudo-spherical correction, though +I am open to adding new features and I added a subroutine +to compute actinic fluxes to satisfy a user request. `PythonicDISORT` is instead designed with three goals in mind. First, it is meant to be a pedagogical and exploratory tool. @@ -121,32 +155,34 @@ introduction to Radiative Transfer and Discrete Ordinates Solvers. Even researchers who are experienced in the field may find it useful to experiment with `PythonicDISORT` before deciding whether and how to upscale with `DISORT`. Installation of `PythonicDISORT` through `pip` should be system agnostic -as `PythonicDISORT`'s core dependencies are only `NumPy` and `SciPy`. -We also intend to implement `conda` installation. In addition, using +as `PythonicDISORT`'s core dependencies are only `NumPy` [@NumPy] and `SciPy` [@SciPy]. +I also intend to implement `conda` installation. In addition, using `PythonicDISORT` is as simple as calling the Python function `pydisort`. In contrast, `DISORT` requires FORTRAN compilers, has a lengthy and system dependent -installation process, and each call requires shell script for compilation and execution. +installation, and each call requires shell script for compilation and execution. Second, `PythonicDISORT` is designed to be modified by users to suit their needs. -Given that Python is a widely used high-level language, `PythonicDISORT`'s +Given that Python is a widely-used high-level language, `PythonicDISORT`'s code should be understandable, at least more so than `DISORT`'s FORTRAN code. -Moreover, `PythonicDISORT` comes with a Jupyter Notebook -(our *Comprehensive Documentation*) that breaks down both the mathematics +Moreover, `PythonicDISORT` comes with a Jupyter Notebook [@JupyterNotebook] -- +our [*Comprehensive Documentation*](https://pythonic-disort.readthedocs.io/en/latest/Pythonic-DISORT.html) -- +that breaks down both the mathematics and code behind the solver. Users can in theory follow the Notebook to recode `PythonicDISORT` from scratch; it should at least help them make modifications. -Third, we intend for `PythonicDISORT` to be a testbed. -For the same reasons given above, we expect that it is easier +Third, `PythonicDISORT` is intended to be a testbed. +For the same reasons given above, it should be easier to implement and test experimental features in `PythonicDISORT` than in `DISORT`. This should expedite research and development for `DISORT` and similar algorithms. -`PythonicDISORT` was first released on PyPI and GitHub on May 30, 2023. -We know of its use in at least three ongoing projects: +`PythonicDISORT` was first released on [PyPI](https://pypi.org/project/PythonicDISORT/) +and [GitHub](https://github.com/LDEO-CREW/Pythonic-DISORT) on May 30, 2023. +I know of its use in at least three ongoing projects: on the Two-Stream Approximations, on atmospheric photolysis, and on the topographic mapping of Mars through photoclinometry. -We will continue to maintain and upgrade `PythonicDISORT`. Our latest version: -`PythonicDISORT v0.4.2` was released on Nov 28, 2023. +I will continue to maintain and upgrade `PythonicDISORT`. Our latest version: +`PythonicDISORT v0.7.0` was released on April 26, 2024. # Acknowledgements diff --git a/docs/Pythonic-DISORT.ipynb b/docs/Pythonic-DISORT.ipynb index dba139b..3e484c5 100644 --- a/docs/Pythonic-DISORT.ipynb +++ b/docs/Pythonic-DISORT.ipynb @@ -39,64 +39,16 @@ "from scipy import constants" ] }, - { - "cell_type": "markdown", - "id": "3a033cf9", - "metadata": {}, - "source": [ - "# Table of Contents\n", - "* [1. USER INPUT REQUIRED: Choose parameters](#1.-USER-INPUT-REQUIRED:-Choose-parameters)\n", - "\t* [1.1 Choose optical properties](#1.1-Choose-optical-properties)\n", - "\t* [1.2 Choose computational parameters](#1.2-Choose-computational-parameters)\n", - "\t* [1.3 Choose phase function](#1.3-Choose-phase-function)\n", - "\t\t* [1.3.1 OPTIONAL: Choose delta-M scaling](#1.3.1-OPTIONAL:-Choose-delta-M-scaling)\n", - "\t* [1.4 Choose direct beam source](#1.4-Choose-direct-beam-source)\n", - "\t* [1.5 OPTIONAL: Choose Dirichlet BCs](#1.5-OPTIONAL:-Choose-Dirichlet-BCs)\n", - "\t* [1.6 OPTIONAL: Choose BDRF](#1.6-OPTIONAL:-Choose-BDRF)\n", - "\t* [1.7 OPTIONAL: Choose isotropic internal sources](#1.7-OPTIONAL:-Choose-isotropic-internal-sources)\n", - "* [2. PythonicDISORT modules and outputs](#2.-PythonicDISORT-modules-and-outputs)\n", - "* [3. Breakdown of single layer solver](#3.-Breakdown-of-single-layer-solver)\n", - "\t* [3.1 Quadrature](#3.1-Quadrature)\n", - "\t* [3.2 Fourier expansion of solution](#3.2-Fourier-expansion-of-solution)\n", - "\t\t* [3.2.1 Surface reflection](#3.2.1-Surface-reflection)\n", - "\t\t* [3.2.2 Important terms](#3.2.2-Important-terms)\n", - "\t* [3.3 Delta-M scaling](#3.3-Delta-M-scaling)\n", - "\t\t* [3.3.1 Scaling a multi-layer atmosphere](#3.3.1-Scaling-a-multi-layer-atmosphere)\n", - "\t* [3.4 System of ODEs](#3.4-System-of-ODEs)\n", - "\t\t* [3.4.1 How to choose NQuad and NLeg?](#3.4.1-How-to-choose-NQuad-and-NLeg?)\n", - "\t\t* [3.4.2 Assembly of system](#3.4.2-Assembly-of-system)\n", - "\t* [3.5 Diagonalization of coefficient matrix](#3.5-Diagonalization-of-coefficient-matrix)\n", - "\t* [3.6 General solution for each mode and layer](#3.6-General-solution-for-each-mode-and-layer)\n", - "\t\t* [3.6.1 The particular solutions](#3.6.1-The-particular-solutions)\n", - "\t\t* [3.6.2 The homogeneous solution](#3.6.2-The-homogeneous-solution)\n", - "\t\t* [3.6.3 Verification of the general solution](#3.6.3-Verification-of-the-general-solution)\n", - "\t* [3.7 The full solution](#3.7-The-full-solution)\n", - "\t\t* [3.7.1 Verification and visualization: uncorrected](#3.7.1-Verification-and-visualization:-uncorrected)\n", - "\t\t* [3.7.2 NT corrections](#3.7.2-NT-corrections)\n", - "\t\t* [3.7.3 Verification and visualization: NT corrected](#3.7.3-Verification-and-visualization:-NT-corrected)\n", - "\t* [3.8 Computation of flux](#3.8-Computation-of-flux)\n", - "\t\t* [3.8.1 Impact of delta-M scaling on flux calculations](#3.8.1-Impact-of-delta-M-scaling-on-flux-calculations)\n", - "\t\t* [3.8.2 Verification of flux](#3.8.2-Verification-of-flux)\n", - "\t\t* [3.8.3 Reflectance and transmittance](#3.8.3-Reflectance-and-transmittance)\n", - "* [4. Solve for multiple layers](#4.-Solve-for-multiple-layers)\n", - "\t* [4.1 Memory inefficiencies](#4.1-Memory-inefficiencies)\n", - "\t* [4.2 Verification of multi-layer solver](#4.2-Verification-of-multi-layer-solver)\n", - "* [5. Timing PythonicDISORT](#5.-Timing-PythonicDISORT)\n", - "* [6. Comparisons against Stamnes' DISORT](#6.-Comparisons-against-Stamnes'-DISORT)\n", - "\t* [6.1 PyTest](#6.1-PyTest)\n", - "\t* [6.2 Timing Stamnes' DISORT](#6.2-Timing-Stamnes'-DISORT)\n" - ] - }, { "cell_type": "markdown", "id": "fd874e5a", "metadata": {}, "source": [ - "**Installation**\n", + "**Installation and more examples of use**\n", "\n", "`pip install PythonicDISORT`\n", "\n", - "See https://github.com/LDEO-CREW/Pythonic-DISORT for other options." + "See https://github.com/LDEO-CREW/Pythonic-DISORT for other installation options. See the Jupyter Notebooks in the `pydisotest` directory for more examples of use." ] }, { @@ -104,7 +56,7 @@ "id": "5373074c", "metadata": {}, "source": [ - "**Mathematical setup and overview**\n", + "**Setup and overview**\n", "\n", "Denote the optical depth as $\\tau$, the cosine of the polar angle as $\\mu$ (positive is upward), and the azimuthal angle as $\\phi$ (positive is counterclockwise when looking down on the atmospheric layer). The goal is to solve the (time-independent and 1D) Radiative Transfer Equation for a plane-parallel atmosphere:\n", "\n", @@ -115,7 +67,7 @@ "\\end{aligned}\n", "$$\n", "\n", - "for the **diffuse** (specific) intensity, $u = u_\\text{diffuse}$. This will be done numerically using the Discrete Ordinates Method. Our Discrete Ordinates Method package is called PythonicDISORT. The total intensity is given by\n", + "for the **diffuse** intensity, $u = u_\\text{diffuse}$ using the Discrete Ordinates Method. Our setup is equivalent to that of Stamnes et. al. [[1]](#cite-STWJ1988). The total intensity is given by\n", "\n", "$$u_\\text{total} = u_\\text{diffuse} + u_\\text{direct}$$\n", "\n", @@ -134,7 +86,7 @@ "id": "1cf1dadf", "metadata": {}, "source": [ - "The fundamental idea behind the Discrete Ordinates Method, from Chandrasekhar [[1]](#cite-Cha1960), is to perform the following series expansions\n", + "The fundamental idea behind the Discrete Ordinates Method, from Chandrasekhar [[2]](#cite-Cha1960), is to perform the following series expansions\n", "\n", "$$\n", "\\begin{aligned}\n", @@ -163,7 +115,60 @@ "id": "1fc5f6c5", "metadata": {}, "source": [ - "It is mathematically straightforward to generalize to multiple atmospheric layers, each demarcated by $\\tau_l$ for index $l = 0, 1, \\dots, L$, and each with its own single-scattering albedo $\\omega$ and phase function $p$. Each layer is modeled by its own radiative transfer equation, and until section [3.6](#3.6-General-solution-for-each-mode-and-layer) the method is the same for each layer. The only complication from moving to a multi-layered atmosphere is that the boundary conditions for each layer are coupled. Consequently, one would need to implement section [4](#4.-Solve-for-multiple-layers) instead of section [3.6](#3.6-General-solution-for-each-mode-and-layer)." + "The single-scattering albedo $\\omega$ and scattering phase function $p$ \n", + "are assumed to be independent of $\\tau$, i.e. homogeneous in the atmospheric layer.\n", + "An atmosphere with $\\tau$-dependent $\\omega$ and $p$ can be modelled by \n", + "a multi-layer atmosphere with different $\\omega$ and $p$ for each layer.\n", + "\n", + "It is mathematically straightforward to generalize the Discrete Ordinates Method to multiple atmospheric layers, each demarcated by $\\tau_l$ for index $l = 0, 1, \\dots, L$. Each layer is modeled by its own radiative transfer equation, and until section [3.6](#3.6-General-solution-for-each-mode-and-layer) the method is the same for each layer. The only complication from moving to a multi-layered atmosphere is that the boundary conditions for each layer are coupled. Consequently, one would need to implement section [4](#4.-Solve-for-multiple-layers) instead of section [3.6](#3.6-General-solution-for-each-mode-and-layer)." + ] + }, + { + "cell_type": "markdown", + "id": "3a033cf9", + "metadata": {}, + "source": [ + "# Table of Contents\n", + "* [1. USER INPUT REQUIRED: Choose parameters](#1.-USER-INPUT-REQUIRED:-Choose-parameters)\n", + "\t* [1.1 Choose optical properties](#1.1-Choose-optical-properties)\n", + "\t* [1.2 Choose computational parameters](#1.2-Choose-computational-parameters)\n", + "\t* [1.3 Choose phase function](#1.3-Choose-phase-function)\n", + "\t\t* [1.3.1 OPTIONAL: Choose delta-M scaling](#1.3.1-OPTIONAL:-Choose-delta-M-scaling)\n", + "\t* [1.4 Choose direct beam source](#1.4-Choose-direct-beam-source)\n", + "\t* [1.5 OPTIONAL: Choose Dirichlet BCs](#1.5-OPTIONAL:-Choose-Dirichlet-BCs)\n", + "\t* [1.6 OPTIONAL: Choose BDRF](#1.6-OPTIONAL:-Choose-BDRF)\n", + "\t* [1.7 OPTIONAL: Choose isotropic internal source](#1.7-OPTIONAL:-Choose-isotropic-internal-source)\n", + "* [2. PythonicDISORT modules and outputs](#2.-PythonicDISORT-modules-and-outputs)\n", + "* [3. Breakdown of single layer solver](#3.-Breakdown-of-single-layer-solver)\n", + "\t* [3.1 Quadrature](#3.1-Quadrature)\n", + "\t* [3.2 Fourier expansion of solution](#3.2-Fourier-expansion-of-solution)\n", + "\t\t* [3.2.1 Surface reflection](#3.2.1-Surface-reflection)\n", + "\t\t* [3.2.2 Important terms](#3.2.2-Important-terms)\n", + "\t* [3.3 Delta-M scaling](#3.3-Delta-M-scaling)\n", + "\t\t* [3.3.1 Scaling a multi-layer atmosphere](#3.3.1-Scaling-a-multi-layer-atmosphere)\n", + "\t* [3.4 System of ODEs](#3.4-System-of-ODEs)\n", + "\t\t* [3.4.1 How to choose NQuad and NLeg?](#3.4.1-How-to-choose-NQuad-and-NLeg?)\n", + "\t\t* [3.4.2 Assembly of system](#3.4.2-Assembly-of-system)\n", + "\t* [3.5 Diagonalization of coefficient matrix](#3.5-Diagonalization-of-coefficient-matrix)\n", + "\t* [3.6 General solution for each mode and layer](#3.6-General-solution-for-each-mode-and-layer)\n", + "\t\t* [3.6.1 The particular solutions](#3.6.1-The-particular-solutions)\n", + "\t\t* [3.6.2 The homogeneous solution](#3.6.2-The-homogeneous-solution)\n", + "\t\t* [3.6.3 Verification of the general solution](#3.6.3-Verification-of-the-general-solution)\n", + "\t* [3.7 The full solution](#3.7-The-full-solution)\n", + "\t\t* [3.7.1 Verification and visualization: uncorrected](#3.7.1-Verification-and-visualization:-uncorrected)\n", + "\t\t* [3.7.2 NT corrections](#3.7.2-NT-corrections)\n", + "\t\t* [3.7.3 Verification and visualization: NT corrected](#3.7.3-Verification-and-visualization:-NT-corrected)\n", + "\t* [3.8 Computation of flux](#3.8-Computation-of-flux)\n", + "\t\t* [3.8.1 Impact of delta-M scaling on flux calculations](#3.8.1-Impact-of-delta-M-scaling-on-flux-calculations)\n", + "\t\t* [3.8.2 Verification of flux](#3.8.2-Verification-of-flux)\n", + "\t\t* [3.8.3 Reflectance and transmittance](#3.8.3-Reflectance-and-transmittance)\n", + "* [4. Solve for multiple layers](#4.-Solve-for-multiple-layers)\n", + "\t* [4.1 Memory inefficiencies](#4.1-Memory-inefficiencies)\n", + "\t* [4.2 Verification of multi-layer solver](#4.2-Verification-of-multi-layer-solver)\n", + "* [5. Timing PythonicDISORT](#5.-Timing-PythonicDISORT)\n", + "* [6. Comparisons against Stamnes' DISORT](#6.-Comparisons-against-Stamnes'-DISORT)\n", + "\t* [6.1 PyTest](#6.1-PyTest)\n", + "\t* [6.2 Timing Stamnes' DISORT](#6.2-Timing-Stamnes'-DISORT)\n" ] }, { @@ -179,9 +184,9 @@ "id": "27764183", "metadata": {}, "source": [ - "Our notations somewhat follow those in Stamnes et. al.'s 1988 paper [[2]](#cite-STWJ1988), **with the equivalent variable, if available, in their FORTRAN DISORT code [[3]](#cite-Sta1999) in brackets**. The default values provided correspond to *Test Problem 3b: Henyey-Greenstein Scattering* of Stamnes' DISORT but with $(\\mu_0, \\phi_0)$ changed from $\\left(1, 0\\right)$ to $(0.6, 0.9 \\pi)$ for better plots.\n", + "Our notations somewhat follow those of Stamnes et. al.'s 1988 paper [[1]](#cite-STWJ1988) **with the equivalent variable in their FORTRAN DISORT code** [[3]](#cite-Sta1999)**, if available, in brackets**. The default values provided here correspond to *Test Problem 3b: Henyey-Greenstein Scattering* of Stamnes' DISORT but with $(\\mu_0, \\phi_0)$ changed from $\\left(1, 0\\right)$ to $(0.6, 0.9 \\pi)$ for better plots.\n", "\n", - "*These inputs are for the solver function `pydisort`. Input checks are performed in `pydisort.py`.*" + "These inputs are for the solver function `pydisort`. Input checks are performed in `pydisort.py`. Refer to the `*_test.ipynb` Jupyter Notebooks in the `pydisotest` directory for examples of other inputs." ] }, { @@ -207,7 +212,7 @@ "source": [ "* **Optical depth (DTAUC denotes the optical thickness of each layer)**\n", "\n", - "Take the top of the atmosphere to have $\\tau = 0$. Consequently, the first (zeroth index) atmospheric layer from the top has optical thickness $\\tau_0$ and each subsequent layer $l$ has optical thickness $\\tau_l - \\tau_{l-1}$. The number of layers $\\text{NLayers}$ (denoted $\\text{NLYR}$ in Stamnes' DISORT [[3]](#cite-Sta1999)) is taken to be `len(tau_arr)`. One can accomodate large thickness using Stamnes-Conklin's substitutions [[4]](#cite-SC1984), though there will still be inaccuracies. We require each $\\tau_l$ and the optical thickness of each layer to be positive." + "Take the top of the atmosphere to have $\\tau = 0$. Consequently, the first (zeroth index) atmospheric layer from the top has optical thickness $\\tau_0$ and each subsequent layer $l$ has optical thickness $\\tau_l - \\tau_{l-1}$. The number of layers $\\text{NLayers}$ (denoted $\\text{NLYR}$ in Stamnes' DISORT [[3]](#cite-Sta1999)) is taken to be `len(tau_arr)`. Stamnes-Conklin substitutions [[4]](#cite-SC1984) allow large thickness to be accomodated, though there will still be inaccuracies. We require each $\\tau_l$ and the optical thickness of each layer to be positive." ] }, { @@ -245,7 +250,7 @@ "source": [ "* **Single-scattering albedo (SSALB)**\n", "\n", - "As before, **the zeroth index corresponds to the layer at the top of the atmosphere**. Within each layer assume $\\omega$ to be independent from $\\tau$. We require each $\\omega \\in [0,1)$, and values too close to $1$ will cause instability. Nonetheless, one may use $\\omega$ close to $1$ to approximate conservative scattering. **We suggest using $\\omega \\leq 1 - 10^{-6}$.** See section [3.5](#3.5-Diagonalization-of-coefficient-matrix) for more details." + "As before, **the zeroth index corresponds to the layer at the top of the atmosphere**. Within each layer assume $\\omega$ to be independent from $\\tau$. We require each $\\omega \\in [0,1)$, and values too close to $1$ will cause instability. Nonetheless, one may use $\\omega$ close to $1$ to approximate conservative scattering. **We suggest using** $\\omega \\leq 1 - 10^{-6}$. See section [3.5](#3.5-Diagonalization-of-coefficient-matrix) for more details." ] }, { @@ -421,7 +426,7 @@ "id": "59d5c631", "metadata": {}, "source": [ - "Assume that the phase function is directly dependent on only the scattering angle $\\gamma$, i.e. the scattering medium has spherical symmetry. Then, one can follow the method in [[2]](#cite-STWJ1988), but with slightly different notations and definitions, and expand the phase function in a Legendre series with respect to $\\cos\\gamma$:\n", + "Assume that the phase function is directly dependent on only the scattering angle $\\gamma$, i.e. the scattering medium has spherical symmetry. Then, follow the method in [[1]](#cite-STWJ1988), but with slightly different notations and definitions, and expand the phase function in a Legendre series with respect to $\\cos\\gamma$:\n", "\n", "$$\n", "p(\\cos\\gamma) \\approx \\sum_{\\ell=0}^\\text{NLeg} (2\\ell + 1)g_\\ell P_\\ell(\\cos\\gamma), \\quad g_\\ell = \\frac{1}{2}\\int_{-1}^{1} p(\\cos\\gamma) P_\\ell(\\cos\\gamma) \\mathrm{d}\\cos\\gamma\n", @@ -617,7 +622,7 @@ "source": [ "Standard Legendre series approximation of highly anisotropic phase functions require a large number of terms to accurately capture the strong directional scattering. This is due to the slow decay of their Legendre coefficients. Using the HG phase function as an illustrative example, its Legendre coefficients are given by $\\mathscr{g}_\\ell = g^\\ell$ where $g$ is the asymmetry factor. It is clear therefore that the closer $|g|$ is to $1$, i.e. the more anisotropic the HG phase function is, the slower its Legendre coefficients will decay.\n", "\n", - "One can use fewer Legendre terms if one re-expresses the phase function as a linear combination of a Dirac $\\delta$-function and a more isotropic remainder. We follow the method in [[5]](#cite-Wis1977) for scaling the first $2M$ Legendre coefficients of a phase function such that they become the coefficients of the remainder." + "Fewer Legendre terms are required if one re-expresses the phase function as a linear combination of a Dirac $\\delta$-function and a more isotropic remainder. We follow the method in [[5]](#cite-Wis1977) for scaling the first $2M$ Legendre coefficients of a phase function such that they become the coefficients of the remainder." ] }, { @@ -648,7 +653,7 @@ "id": "4e172a8e", "metadata": {}, "source": [ - "* **(OPTIONAL) Fractional scattering into peak parameter (Automatically chosen in Stamnes' DISORT [[3]](#cite-Sta1999))**\n", + "* **(OPTIONAL) Fractional scattering into peak parameter (Automatically chosen in Stamnes' DISORT** [[3]](#cite-Sta1999)**)**\n", "\n", "We require $f \\in [0, 1)$. Values close to $1$ will cause instability. The zeroth entry of the array corresponds to the zeroth (topmost) atmospheric layer." ] @@ -672,7 +677,7 @@ "id": "2ef87ed2", "metadata": {}, "source": [ - "* **(OPTIONAL) Whether to perform Nakajima-Tanaka intensity corrections, see section [3.7.2](#3.7.2-NT-corrections) (Always true in Stamnes' DISORT [[3]](#cite-Sta1999))**" + "* **(OPTIONAL) Whether to perform Nakajima-Tanaka intensity corrections, see section** [3.7.2](#3.7.2-NT-corrections) **(Always true in Stamnes' DISORT** [[3]](#cite-Sta1999)**)**" ] }, { @@ -704,7 +709,7 @@ "source": [ "* **Parameters for the (incident) direct collimated (sun) beam**\n", "\n", - "We do not allow $\\mu_0$ to coincide with a quadrature angle to prevent singularities. If that happens either $\\text{NQuad}$ or $\\mu_0$ should be tweaked. In the future this can be implemented as a special case. In addition, we do not allow $\\mu_0 \\leq 0$. Small $\\mu_0$ values will cause instability. We require both angles to be principal and $I_0 \\geq 0$. Choosing $I_0 = 0$ will disable this source and isotropic internal sources can be chosen in section [1.7](#1.7-OPTIONAL:-Choose-isotropic-internal-sources). The flux contribution of this source is $I_0 \\mu_0$.\n", + "We do not allow $\\mu_0$ to coincide with a quadrature angle to prevent singularities. If that happens either $\\text{NQuad}$ or $\\mu_0$ should be tweaked. In the future this can be implemented as a special case. In addition, we do not allow $\\mu_0 \\leq 0$. Small $\\mu_0$ values will cause instability. We require both angles to be principal and $I_0 \\geq 0$. Choosing $I_0 = 0$ will disable this source and the isotropic internal source can be chosen in section [1.7](#1.7-OPTIONAL:-Choose-isotropic-internal-source). The flux contribution of this source is $I_0 \\mu_0$.\n", "\n", "If the direct beam is the only source, then $I_0$ is a simple scale factor for the outputs, i.e. for all $\\tau, \\phi, I$,\n", "\n", @@ -874,7 +879,7 @@ "id": "6b33ce2f", "metadata": {}, "source": [ - " * **(OPTIONAL) BDRF Fourier modes (No direct equivalent in Stamnes' DISORT [[3]](#cite-Sta1999), but see variables *BDREF* and *LAMBER*)**\n", + " * **(OPTIONAL) BDRF Fourier modes (No direct equivalent in Stamnes' DISORT** [[3]](#cite-Sta1999)**, but see variables *BDREF* and *LAMBER*)**\n", " \n", " We require the number of BDRF Fourier modes to be non-negative and $\\leq \\text{NLeg}$. The default is a black surface, i.e. $q\\left(\\mu, \\phi; -\\mu', \\phi'\\right) = 0$." ] @@ -901,7 +906,7 @@ "id": "5d6aaa05", "metadata": {}, "source": [ - "## 1.7 OPTIONAL: Choose isotropic internal sources" + "## 1.7 OPTIONAL: Choose isotropic internal source" ] }, { @@ -937,15 +942,15 @@ "id": "67fbe54d", "metadata": {}, "source": [ - "Let $B$ denote the Planck function with SI units $W sr^{−1} m^{−2} m^{−1}$. One can use\n", + "Let $B$ denote the Planck function with SI units $W sr^{−1} m^{−2} m^{−1}$. Let the isotropic internal source be blackbody emission:\n", "\n", "$$s_l(\\tau) = \\epsilon_l B_\\lambda(T(\\tau))$$\n", "\n", - "where the wavelength $\\lambda$ is fixed across the entire atmosphere, and $\\epsilon_l = 1 - \\omega_l$ by Kirchoff's law. Following [[4, section 2.5]](#cite-STL2000), one can make the assumption that\n", + "for some fixed wavelength $\\lambda$, and $\\epsilon_l = 1 - \\omega_l$ by Kirchoff's law. Following [[4, section 2.5]](#cite-STL2000), a possible model for the blackbody emission is\n", "\n", "$$B_\\lambda(T(\\tau)) = a_0 + a_1 \\tau$$\n", "\n", - "where $a_0, a_1$ are fixed across the entire atmosphere. Interpolate the points $\\big(0, B(T(0))\\big)$ and $\\big(\\tau_{\\text{BoA}}, B(T(\\tau_{\\text{BoA}}))\\big)$ to get\n", + "for constants $a_0, a_1$ to be specified. Interpolate the points $\\big(0, B(T(0))\\big)$ and $\\big(\\tau_{\\text{BoA}}, B(T(\\tau_{\\text{BoA}}))\\big)$ to get\n", " \n", "$$\n", "\\begin{aligned}\n", @@ -1039,9 +1044,9 @@ "id": "17a83658", "metadata": {}, "source": [ - "The solver function `pydisort` will always return `mu_arr` (type: array), `flux_up` (type: function), `flux_down` (type: function) and `u0` (type: function). The first output `mu_arr` is the array of $\\mu_i$ values, i.e. $\\mu$ quadrature nodes. Both `flux_up` $F^+$ and `flux_down` $F^-$ accept only one argument, `tau` $\\tau$, and return the diffuse fluxes at the specified optical depths. The latter also returns the direct flux as its second output. More details on the flux functions can be found in section [3.8](#3.8-Computation-of-flux). The distinction between \"direct\" and \"diffuse\" is explained in the preamble, above section [1](#1.-USER-INPUT-REQUIRED:-Choose-parameters). \n", + "The solver function `pydisort` will always return `mu_arr` (type: array), `flux_up` (type: function), `flux_down` (type: function) and `u0` (type: function). The first output `mu_arr` is the array of $\\mu_i$ values, i.e. $\\mu$ quadrature nodes. Both `flux_up` $F^+$ and `flux_down` $F^-$ accept only one argument, `tau` $\\tau$, and return the diffuse fluxes at the specified optical depths. The latter also returns the direct flux as its second output. More details on the flux functions can be found in section [3.8](#3.8-Computation-of-flux). The distinction between \"direct\" and \"diffuse\" is explained in the initial setup.\n", "\n", - "Finally, the function `u0` $u^0$ is the zeroth Fourier moment of the (diffuse specific) intensity and it is continuous and variable in $\\tau$, which is its sole argument, but discrete in $\\mu$ and fixed to the quadrature points $\\mu_i$. The function output is 2D and its $0, 1$ axes capture variation with $\\mu$ and $\\tau$ respectively. The first half of the $\\mu$ indices correspond to the upward direction and the second half to the downward direction in alignment with `mu_arr`. This function is useful for calculating actinic flux and other intensity moments, but reclassification of delta-scaled flux (see section [3.8.1](#3.8.1-Impact-of-delta-M-scaling-on-flux-calculations)) and other corrections must be done manually (one can calculate actinic flux by inputing `u0` into `PythonicDISORT.subroutines.generate_diff_act_flux_funcs` and it will automatically perform the reclassification).\n", + "Finally, the function `u0` $u^0$ is the zeroth Fourier moment of the (diffuse) intensity and it is continuous and variable in $\\tau$, which is its sole argument, but discrete in $\\mu$ and fixed to the quadrature points $\\mu_i$. The function output is 2D and its $0, 1$ axes capture variation with $\\mu$ and $\\tau$ respectively. The first half of the $\\mu$ indices correspond to the upward direction and the second half to the downward direction in alignment with `mu_arr`. This function is useful for calculating actinic flux and other intensity moments, but reclassification of delta-scaled flux (see section [3.8.1](#3.8.1-Impact-of-delta-M-scaling-on-flux-calculations)) and other corrections must be done manually (actinic flux can be calculated by inputing `u0` into `PythonicDISORT.subroutines.generate_diff_act_flux_funcs` and it will automatically perform the reclassification).\n", "\n", "When `only_flux = False` (default), `pydisort` will also output the intensity function `u` $u$ which is continuous and variable in $\\tau$ and $\\phi$, which are its arguments, but discrete in $\\mu$ and fixed to the quadrature points $\\mu_i$. The function output is 3D and its $0, 1, 2$ axes capture variation with $\\mu, \\tau, \\phi$ respectively. The function also has the optional flag `return_Fourier_error` which defaults to `False`, see section [3.7](#3.7-The-full-solution) for more details." ] @@ -1226,7 +1231,7 @@ "id": "be81279f", "metadata": {}, "source": [ - "*We will re-derive equations (6a) to (6d) of [[2]](#cite-STWJ1988) in this subsection.*" + "*We will re-derive equations (6a) to (6d) of* [[1]](#cite-STWJ1988) *in this subsection.*" ] }, { @@ -1285,7 +1290,7 @@ "P_\\ell\\left(\\nu\\right) = P_\\ell\\left(\\mu'\\right)P_\\ell\\left(\\mu\\right) + 2\\sum_{m=1}^\\ell \\frac{\\left(\\ell-m\\right)!}{\\left(\\ell+m\\right)!}P_\\ell^m\\left(\\mu'\\right)P_\\ell^m\\left(\\mu\\right)\\cos\\left(m\\left(\\phi'-\\phi\\right)\\right)\n", "$$\n", "\n", - "Consequently, one can expand the $\\mu, \\phi, \\mu', \\phi'$ form of the phase function as\n", + "Consequently, the $\\mu, \\phi, \\mu', \\phi'$ form of the phase function can be expanded as\n", "\n", "$$\n", "p\\left(\\mu, \\phi; \\mu', \\phi'\\right) \\approx \\sum_{\\ell=0}^\\text{NLeg} \\left[ \\mathscr{g}_\\ell P_\\ell\\left(\\mu'\\right)P_\\ell\\left(\\mu\\right) + 2\\sum_{m=1}^\\ell \\mathscr{g}_\\ell^m P_\\ell^m\\left(\\mu'\\right)P_\\ell^m\\left(\\mu\\right)\\cos\\left(m\\left(\\phi'-\\phi\\right)\\right) \\right]\n", @@ -1329,7 +1334,7 @@ "id": "0fdd37d3", "metadata": {}, "source": [ - "**Sunbeam source term**" + "**Direct beam source term**" ] }, { @@ -1337,7 +1342,7 @@ "id": "4332606f", "metadata": {}, "source": [ - "Next, focus on the sunbeam source term; the isotropic internal sources will contribute only to the $0$th Fourier mode as they have no $\\phi$ dependence. Substitute the expansion of $p\\left(\\mu, \\phi; \\mu', \\phi'\\right)$ once again to get\n", + "Next, focus on the direct beam source term -- the isotropic internal source will contribute only to the $0$th Fourier mode as they have no $\\phi$ dependence. Substitute the expansion of $p\\left(\\mu, \\phi; \\mu', \\phi'\\right)$ once again to get\n", "\n", "$$\n", "\\begin{aligned}\n", @@ -1525,7 +1530,7 @@ "id": "5e0ca2d8", "metadata": {}, "source": [ - "*This is implemented in `pydisort.py`.*\n", + "*This is implemented in* `pydisort.py`.\n", "\n", "When scaling a multi-layer atmosphere, do not directly scale `tau_arr` for that will lead to discontinuity between each layer that has a different scale parameter $1 - \\omega f$. Instead, **scale the optical thickness** of each layer. Therefore, while $\\tau_0^* = (1 - \\omega_0 f_0)\\tau_0$, in general $\\tau_l^* \\neq (1 - \\omega_l f_l)\\tau_l$." ] @@ -1550,7 +1555,7 @@ "# Example: Delta-M scaling of tau_arr\n", "thickness_arr = np.concatenate([[tau_arr[0]], np.diff(tau_arr)])\n", "scaled_thickness_arr = (1 - omega_arr * f_arr) * thickness_arr\n", - "# We include 0 in the array for computational reasons\n", + "# Include 0 in the array for computational reasons\n", "scaled_tau_arr_with_0 = np.array(\n", " list(map(lambda l: np.sum(scaled_thickness_arr[:l]), range(NLayers + 1)))\n", ")\n", @@ -1570,7 +1575,7 @@ "id": "f73b8abf", "metadata": {}, "source": [ - "*We will prove equations (7a) and (7b) of* [[2]](#cite-STWJ1988) *in this subsection.*" + "*We will prove equations (7a) and (7b) of* [[1]](#cite-STWJ1988) *in this subsection.*" ] }, { @@ -1592,7 +1597,7 @@ "id": "54087f37", "metadata": {}, "source": [ - "By double-Gauss quadrature, one can approximate the ODE as\n", + "By double-Gauss quadrature, the ODE can be approximated as\n", "\n", "\n", "$$\n", @@ -1704,7 +1709,7 @@ "id": "f009ab80", "metadata": {}, "source": [ - "The main consideration when choosing the number of streams is the finding that $\\text{NQuad} < \\text{NLeg}$ results in large errors, see [[1, Chapter VI]](#cite-Cha1960) and [[8, section 3.7]](#cite-STWLE2000). Increasing $\\text{NQuad}$ past the threshold generally results in better accuracy, though monotone convergence is not guaranteed when using the double-Gauss quadrature scheme, see [[7]](#cite-Syk1951) for a discussion on the convergence of different quadrature schemes. Given, however, that the computational complexity of `pydisort` scales linearly with $\\text{NLeg}$ and cubicly with $\\text{NQuad}$, it is recommended to choose $\\text{NQuad}$ based on the computational resources and time one can afford, then choose $\\text{NLeg} = \\text{NQuad}$. The only option in Stamnes' DISORT [[3]](#cite-Sta1999) is $\\text{NLeg} = \\text{NQuad}$." + "The main consideration when choosing the number of streams is the finding that $\\text{NQuad} < \\text{NLeg}$ results in large errors, see [[1, Chapter VI]](#cite-Cha1960) and [[8, section 3.7]](#cite-STWLE2000). Increasing $\\text{NQuad}$ past the threshold generally results in better accuracy, though monotone convergence is not guaranteed when using the double-Gauss quadrature scheme, see [[7]](#cite-Syk1951) for a discussion on the convergence of different quadrature schemes. Given, however, that the computational complexity of `pydisort` scales linearly with $\\text{NLeg}$ and cubicly with $\\text{NQuad}$, it is recommended to choose $\\text{NQuad}$ based on the computational resources and time available, then choose $\\text{NLeg} = \\text{NQuad}$. The only option in Stamnes' DISORT [[3]](#cite-Sta1999) is $\\text{NLeg} = \\text{NQuad}$." ] }, { @@ -1736,7 +1741,7 @@ "id": "924c8cc3", "metadata": {}, "source": [ - "One will need to loop everything until but excluding section [3.7](#3.7-The-full-solution) over Fourier mode indices $m = 0$ to $m = \\text{NFourier}$ (outer loop) and atmospheric layer indices $l = 0$ to $l = \\text{NLayers}$ (inner loop). PythonicDISORT is structured differently to maximize computational speed, but one can attain the same solutions through simple for-loops." + "One will need to loop everything until but excluding section [3.7](#3.7-The-full-solution) over Fourier mode indices $m = 0$ to $m = \\text{NFourier}$ (outer loop) and atmospheric layer indices $l = 0$ to $l = \\text{NLayers}$ (inner loop). PythonicDISORT is structured differently to maximize computational speed, but the same solutions are attainable through simple for-loops." ] }, { @@ -1746,7 +1751,7 @@ "metadata": {}, "outputs": [], "source": [ - "# We will demonstrate only one loop\n", + "# Only one loop will be demonstrated\n", "m = 0\n", "l = NLayers - 1" ] @@ -1826,7 +1831,7 @@ "metadata": {}, "outputs": [], "source": [ - "# We take precautions against overflow and underflow\n", + "# Take precautions against overflow and underflow\n", "if np.any(weighted_asso_Leg_coeffs_l > 0) and np.all(np.isfinite(asso_leg_term_pos)):\n", " D_temp = weighted_asso_Leg_coeffs_l[None, :] * asso_leg_term_pos.T\n", " D_pos = (omega_l / 2) * D_temp @ asso_leg_term_pos\n", @@ -1847,7 +1852,7 @@ "id": "9e92901b", "metadata": {}, "source": [ - "**Assemble the coefficient matrix and sunbeam source vector** in `_solve_for_gen_and_part_sols.py`" + "**Assemble the coefficient matrix and direct beam source vector** in `_solve_for_gen_and_part_sols.py`" ] }, { @@ -1877,7 +1882,7 @@ "id": "75bcb1df", "metadata": {}, "source": [ - "*This is implemented in `_solve_for_gen_and_part_sols.py`*.\n", + "*This is implemented in* `_solve_for_gen_and_part_sols.py`.\n", "\n", "We will for most part omit the Fourier mode index $m$ in this subsection and in section [3.6](#3.6-General-solution-for-each-mode-and-layer). Continuing from section [3.4](#3.4-System-of-ODEs), the system of ODEs for each Fourier mode is\n", "\n", @@ -1891,7 +1896,7 @@ "id": "12e9f00b", "metadata": {}, "source": [ - "The goal is to diagonalize the coefficient matrix, which we denote $A$, such that $A = G\\Sigma G^{-1}$. We will use the reduction of order method in [[2]](#cite-STWJ1988), but with minor sign differences, to solve for the eigenpairs of the coefficient matrix from the eigenequation\n", + "The goal is to diagonalize the coefficient matrix, which we denote $A$, such that $A = G\\Sigma G^{-1}$. We will use the reduction of order method in [[1]](#cite-STWJ1988), but with minor sign differences, to solve for the eigenpairs of the coefficient matrix from the eigenequation\n", "\n", "$$\n", "\\begin{bmatrix} -\\alpha & -\\beta \\\\ \\beta & \\alpha \\end{bmatrix} \\begin{bmatrix} G^+ \\\\ G^- \\end{bmatrix} = k \\begin{bmatrix} G^+ \\\\ G^- \\end{bmatrix}\n", @@ -1927,11 +1932,11 @@ "(\\alpha - \\beta) (\\alpha + \\beta) \\left(G^- + G^+\\right) = k^2 \\left(G^- + G^+\\right)\n", "$$\n", "\n", - "from which one can solve for the eigenvalues $k$ which are always real and, using the previous equations, for $G^+$ and $G^-$. Consequently, one can construct the eigenvector matrix\n", + "which can be solved for the eigenvalues $k$ which are always real. Subsequently, $G^+, G^-$, the eigenvector matrix\n", "\n", "$$G = \\begin{bmatrix} G^+ \\\\ G^- \\end{bmatrix}$$\n", "\n", - "and compute its inverse. Denote the vector of eigenvalues as $K$ and arrange its entries as negative then positive, from largest to smallest magnitude. This completes the diagonalization $A = G \\Sigma G^{-1}$ where the diagonal of $\\Sigma$ is $K$." + "and $G^{-1}$ can all be determined. Denote the vector of eigenvalues as $K$ and arrange its entries as negative then positive, from largest to smallest magnitude. This completes the diagonalization $A = G \\Sigma G^{-1}$ where the diagonal of $\\Sigma$ is $K$." ] }, { @@ -2051,7 +2056,7 @@ "id": "7277dd5a", "metadata": {}, "source": [ - "**Sunbeam source** in `_solve_for_gen_and_part_sols.py`" + "**Direct beam source** *(implemented in* `_solve_for_gen_and_part_sols.py`*)*" ] }, { @@ -2059,7 +2064,7 @@ "id": "09957a31", "metadata": {}, "source": [ - "Particular solutions $\\mathscr{v}_\\text{direct}$ for the sunbeam source satisfy\n", + "Particular solutions $\\mathscr{v}_\\text{direct}$ for the direct beam source satisfy\n", "\n", "$$\n", "\\frac{\\mathrm{d}\\mathscr{v}_\\text{direct}}{\\mathrm{d}\\tau} = A \\mathscr{v}_\\text{direct} + \\tilde{Q}(\\tau)\n", @@ -2109,15 +2114,7 @@ "id": "32db54cc", "metadata": {}, "source": [ - "**Verification of particular solution for sunbeam source**" - ] - }, - { - "cell_type": "markdown", - "id": "41a24990", - "metadata": {}, - "source": [ - "One can use the *autograd* package to perform the differentiation with respect to $\\tau$." + "**Verification of particular solution for direct beam source**" ] }, { @@ -2132,6 +2129,14 @@ "tau_test_arr = np.random.random(Ntau) * tau_arr[-1]" ] }, + { + "cell_type": "markdown", + "id": "41a24990", + "metadata": {}, + "source": [ + "The *autograd* package allows for fast and machine precise differentiation with respect to $\\tau$:" + ] + }, { "cell_type": "code", "execution_count": 42, @@ -2142,7 +2147,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Max pointwise error ratio = 1.7643698012714831e-07\n" + "Max pointwise error ratio = 1.764369823126468e-07\n" ] } ], @@ -2165,7 +2170,7 @@ "id": "f617f40d", "metadata": {}, "source": [ - "**Isotropic internal sources** as implemented in `subroutines.py` as the Python function `_mathscr_v`" + "**Isotropic internal source** *(implemented as the function* `_mathscr_v` *in* `subroutines.py`*)*" ] }, { @@ -2173,7 +2178,7 @@ "id": "67a88c08", "metadata": {}, "source": [ - "Particular solutions $\\mathscr{v}$ for the isotropic internal sources satisfy\n", + "Particular solutions $\\mathscr{v}$ for the isotropic internal source satisfy\n", "\n", "$$\n", "\\frac{\\mathrm{d}\\mathscr{v}}{\\mathrm{d}\\tau} = A\\mathscr{v} - \\begin{bmatrix} \\tilde{\\mathrm{S}}(\\tau) \\\\ -\\tilde{\\mathrm{S}}(\\tau) \\end{bmatrix}\n", @@ -2211,7 +2216,7 @@ "\\mathscr{v}(\\tau) = G\\left(\\mathscr{b}_0^\\Sigma + \\mathscr{b}_1^\\Sigma \\tau + \\dots + \\mathscr{b}_n^\\Sigma \\tau^n\\right)G^{-1} \\begin{bmatrix} M^{-1} \\\\ -M^{-1} \\end{bmatrix}\n", "$$\n", "\n", - "In theory one can accomodate internal sources which vary with $\\mu$ and $\\phi$ through Legendre expansion, but use cases in the context of atmospheric radiation seem limited and the extra flexibility does not seem worth the overhead." + "In theory internal sources which vary with $\\mu$ and $\\phi$ can be accomodated through Legendre expansion, but use cases in the context of atmospheric radiation seem limited and the extra flexibility does not seem worth the overhead." ] }, { @@ -2219,7 +2224,7 @@ "id": "fd7a2f4a", "metadata": {}, "source": [ - "**Verification of particular solution for isotropic internal sources in a pseudo multi-layer atmosphere**" + "**Verification of the particular solution for the isotropic internal source in a pseudo multi-layer atmosphere**" ] }, { @@ -2229,7 +2234,7 @@ "metadata": {}, "outputs": [], "source": [ - "Ntau = 20\n", + "Ntau = 100\n", "\n", "tau_test_arr = np.random.random(Ntau) * tau_arr[-1]\n", "l = np.argmax(tau_test_arr[:, None] <= tau_arr[None, :], axis=1)\n", @@ -2246,7 +2251,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Max pointwise error ratio = 3.0352876269313535e-07\n" + "Max pointwise error ratio = 3.035266647257085e-07\n" ] } ], @@ -2262,7 +2267,7 @@ " np.tile(K, (NLayers, 1)),\n", " np.tile(G_inv, (NLayers, 1, 1)),\n", " mu_arr,\n", - " _is_compatible_with_autograd=True,\n", + " _autograd_compatible=True,\n", ")\n", "LHS = np.sum(ag.jacobian(mathscr_v_tau)(tau_test_arr), axis=-1)\n", "RHS = A @ mathscr_v_tau(tau_test_arr) - s(tau_test_arr)[None, :] / mu_arr[:, None]\n", @@ -2283,7 +2288,7 @@ "id": "bd6071b2", "metadata": {}, "source": [ - "*This is implemented in `_solve_for_coeffs.py`.*\n", + "*This is implemented in* `_solve_for_coeffs.py`.\n", "\n", "The homogeneous solution $v$ can be split into\n", "\n", @@ -2357,7 +2362,7 @@ "\\begin{bmatrix} G^{--} & G^{-+} E^-(\\tau_0) \\\\ \\left(G^+ - RG^-\\right)^- E^-(\\tau_0) & \\left(G^+ - RG^-\\right)^+ \\end{bmatrix} \\begin{bmatrix} C^- \\\\ C^+ \\end{bmatrix} = \\text{RHS}\n", "$$\n", "\n", - "This reformulated system has no positive exponents so there is no risk of overflow. Furthermore, when $\\tau_0$ is large the matrix becomes approximately block diagonal and so it remains well-conditioned. We will solve for $C$ but do not construct $\\xi$ because we will use the factor of $E^-(\\tau_0)$ to avoid positive exponents when we construct the general solution. This method is generalizable to multiple atmospheric layers, see section [4](#4.-Solve-for-multiple-layers)." + "This reformulated system has no positive exponents so there is no risk of overflow. Furthermore, when $\\tau_0$ is large the matrix becomes approximately block diagonal and so it remains well-conditioned. Solve for $C$ but do not construct $\\xi$. Instead, use the factor of $E^-(\\tau_0)$ to avoid positive exponents when constructing the general solution. This method is generalizable to multiple atmospheric layers, see section [4](#4.-Solve-for-multiple-layers)." ] }, { @@ -2391,7 +2396,7 @@ "else:\n", " b_neg_m = b_neg[:, m]\n", "\n", - "# We exclude isotropic internal sources\n", + "# Note that the isotropic internal source is excluded\n", "if I0 > 0:\n", " if m < NBDRF:\n", " BDRF_RHS_contribution = mathscr_X_pos + R @ B_neg\n", @@ -2498,8 +2503,8 @@ "source": [ "# The general solution for one Fourier mode\n", "\n", - "# Note that we use the factor of E^-(\\tau_0) attached to the coefficients (see Section 3.6.2)\n", - "# to avoid positive exponents when we construct the general solution for one Fourier mode\n", + "# Use the factor of E^-(\\tau_0) attached to the coefficients (see Section 3.6.2)\n", + "# to avoid positive exponents when constructing the general solution for one Fourier mode\n", "if I0 > 0:\n", "\n", " def um(tau):\n", @@ -2632,7 +2637,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Max pointwise error ratio = 1.0304962395436337e-06\n" + "Max pointwise error ratio = 2.717262771011055e-07\n" ] } ], @@ -2670,7 +2675,7 @@ "id": "68a49a51", "metadata": {}, "source": [ - "*This is implemented in `_assemble_intensity_and_fluxes.py`*\n", + "*This is implemented in* `_assemble_intensity_and_fluxes.py`.\n", "\n", "The above must be repeated for $\\text{NFourier}$ Fourier modes. The full numerical solution given by PythonicDISORT is\n", "\n", @@ -2704,7 +2709,7 @@ "source": [ "If values of $u$ are desired at non-quadrature points, i.e. at $\\mu \\neq \\mu_i$, then interpolation is required. The simplest method is to use `numpy.polynomial.polynomial.Polynomial.fit` on the upward then downward $\\mu$ points to form two splines which together form the full interpolation. When performing the interpolation this way, using Legendre points, uniform convergence is guaranteed as $N \\rightarrow \\infty$, see [[10, chapter 8]](#cite-Tre1996). \n", "\n", - "There are, however, caveats. First, the true solution is in general discontinuous at $\\mu = 0$ so there is no accurate way to interpolate that point. Second, intensity values very near the sunbeam remain inaccurate despite NT corrections, so one should be concerned about including them in a global interpolation. Finally, using a high-order polynomial for interpolation is expensive, unstable and sensitive to errors in the interpolation points. Thus, even though Runge phenomenon is not a concern given uniform convergence, one may want to consider other methods of interpolation, splines for example, or to not interpolate at all and just use the values at $\\mu_i$ especially when $\\text{NQuad}$ is large." + "There are, however, caveats. First, the true solution is in general discontinuous at $\\mu = 0$ so there is no accurate way to interpolate that point. Second, intensity values very near the direct beam remain inaccurate despite NT corrections, so one should be concerned about including them in a global interpolation. Finally, using a high-order polynomial for interpolation is expensive, unstable and sensitive to errors in the interpolation points. Thus, even though Runge phenomenon is not a concern given uniform convergence, one may want to consider other methods of interpolation, splines for example, or to not interpolate at all and just use the values at $\\mu_i$ especially when $\\text{NQuad}$ is large." ] }, { @@ -2742,7 +2747,7 @@ "id": "87efd624", "metadata": {}, "source": [ - "We include the (Lambertian) BDRF and (isotropic) BCs but omit all other optional arguments and treat the atmosphere as single layered. These verifications require the *autograd* package and requires $u$ to be compatible with *autograd*. The latter is enabled by passing `_is_compatible_with_autograd=True` into `pydisort`, but this will slow it down." + "We include the (Lambertian) BDRF and (isotropic) BCs but omit all other optional arguments and treat the atmosphere as single layered. These verifications require the *autograd* package and requires $u$ to be compatible with *autograd*. The latter is enabled by passing `_autograd_compatible=True` into `pydisort`, but this will slow it down." ] }, { @@ -2761,7 +2766,7 @@ " BDRF_Fourier_modes=BDRF_Fourier_modes,\n", " b_pos=b_pos,\n", " b_neg=b_neg,\n", - " _is_compatible_with_autograd=True\n", + " _autograd_compatible=True\n", ")[-1]" ] }, @@ -2943,7 +2948,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 59, @@ -3003,7 +3008,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 60, @@ -3072,7 +3077,7 @@ "id": "f64918ae", "metadata": {}, "source": [ - "*This is implemented in `disort.py`.*\n", + "*This is implemented in* `disort.py`.\n", "\n", "This subsection summarizes the main points from [[11]](#cite-NT1988) and from *Appendix A* of [[8]](#cite-STWLE2000) but omits most of the mathematical explanation. Recall that $\\tau^*, \\omega^*, p^*$ denote $\\delta-M$ scaled parameters and $f$ is the scattering fraction into peak. Nakajima-Tanaka (NT) corrections are disabled by default, enable them with the flag `NT_cor = True`. Note that if $I_0 = 0$, $f = 0$ or only $\\text{NLeg}$ coefficients are supplied in `Leg_coeffs_all`, then NT corrections will remain disabled." ] @@ -3082,7 +3087,7 @@ "id": "c11b6904", "metadata": {}, "source": [ - "The $\\delta-M$ method allows for accurate flux computation, but intensity values remain inaccurate particularly at backscattering angles and around the direct beam. These inaccuracies are largely caused by truncation of the Legendre series of the phase function. Nakajima and Tanaka proposed intensity corrections to reduce these accuracies. This correction is applied to the intensity but not to the flux as the latter is already accurate. This unfortunately means that flux values calculated by integrating the corrected intensity will differ slightly from values given by the flux functions. Note that NT corrections ignore, or rather have not been derived for, the isotropic internal sources $s$, see [[8, section 3.6.3]](#cite-STWLE2000), and they ignore surface reflection, see section [3.7.3](#3.7.3-Verification-and-visualization:-NT-corrected)." + "The $\\delta-M$ method allows for accurate flux computation, but intensity values remain inaccurate particularly at backscattering angles and around the direct beam. These inaccuracies are largely caused by truncation of the Legendre series of the phase function. Nakajima and Tanaka proposed intensity corrections to reduce these accuracies. This correction is applied to the intensity but not to the flux as the latter is already accurate. This unfortunately means that flux values calculated by integrating the corrected intensity will differ slightly from values given by the flux functions. Note that NT corrections ignore, or rather have not been derived for, the isotropic internal source $s$, see [[8, section 3.6.3]](#cite-STWLE2000), and they ignore surface reflection, see section [3.7.3](#3.7.3-Verification-and-visualization:-NT-corrected)." ] }, { @@ -3107,7 +3112,7 @@ "\\end{aligned}\n", "$$\n", "\n", - "respectively. Note that by construction (section [1.3.1](#1.3.1-OPTIONAL:-Choose-delta-M-scaling)), $p^*$ has a finite number of (non-zero) Legendre coefficients. In contrast, $p$ is the original phase function and in general has infinite Legendre coefficients. Unlike the Henyey-Greenstein phase function, realistic phase functions derived from Mie equations generally only have series representations. This lack of a closed-form means that it is impossible to input the true $p$ into PythonicDISORT. Instead, one uses a large (`NLeg_all`) number of Legendre coefficients to very accurately approximate $p$." + "respectively. Note that by construction (section [1.3.1](#1.3.1-OPTIONAL:-Choose-delta-M-scaling)), $p^*$ has a finite number of (non-zero) Legendre coefficients. In contrast, $p$ is the original phase function and in general has infinite Legendre coefficients. Unlike the Henyey-Greenstein phase function, realistic phase functions derived from Mie equations generally only have series representations. This lack of a closed-form means that it is impossible to input the true $p$ into PythonicDISORT. Instead, use a large (`NLeg_all`) number of Legendre coefficients to very accurately approximate $p$." ] }, { @@ -3115,7 +3120,7 @@ "id": "4912b19f", "metadata": {}, "source": [ - "By superposition, every correction term, i.e. every term but $u^*$, must satisfy homogeneous BCs. This is not true when there is surface reflection but we will only discuss this complication in section [3.7.3](#3.7.3-Verification-and-visualization:-NT-corrected). One can solve for $\\left(\\tilde{u}_1^* - u_1^*\\right)$ analytically. The TMS correction to the solution is applied for each atmospheric layer. For $\\mu > 0$ and $\\tau \\in [\\tau_{l-1}, \\tau_{l}]$, one has\n", + "By superposition, every correction term, i.e. every term but $u^*$, must satisfy homogeneous BCs. This is not true when there is surface reflection but we will only discuss this complication in section [3.7.3](#3.7.3-Verification-and-visualization:-NT-corrected). The correction function $\\left(\\tilde{u}_1^* - u_1^*\\right)$ can be analytically determined. The TMS correction to the solution is applied for each atmospheric layer. For $\\mu > 0$ and $\\tau \\in [\\tau_{l-1}, \\tau_{l}]$, one has\n", "\n", "$$\n", "\\begin{aligned}\n", @@ -3155,7 +3160,7 @@ "id": "45f68b9a", "metadata": {}, "source": [ - "The TMS correction substantially reduces the truncation error everywhere except around the direct beam. A second NT correction named *IMS* is required to address the significant errors that remain. One incorporates the IMS through the approximation $u_\\text{true} \\approx u_\\text{TMS} + u_\\text{IMS}$. It is impractical to determine $u_\\text{IMS}$ exactly and both [[8]](#cite-STWLE2000) and [[11]](#cite-NT1988) make many approximations, albeit different ones, to determine $u_\\text{IMS}$. We follow [[8]](#cite-STWLE2000) and approximate the IMS correction as\n", + "The TMS correction substantially reduces the truncation error everywhere except around the direct beam. A second NT correction named *IMS* is required to address the significant errors that remain. One incorporates the IMS through the approximation $u_\\text{true} \\approx u_\\text{TMS} + u_\\text{IMS}$. It is impractical to determine $u_\\text{IMS}$ exactly and both [[8]](#cite-STWLE2000) and [[11]](#cite-NT1988) make many approximations, albeit different ones, to determine $u_\\text{IMS}$. Follow [[8]](#cite-STWLE2000) and approximate the IMS correction as\n", "\n", "$$\n", "\\begin{aligned}\n", @@ -3163,7 +3168,7 @@ "\\end{aligned}\n", "$$\n", "\n", - "for $\\mu > 0$, and take **$u_\\text{IMS}(\\tau, -\\mu, \\phi) \\approx 0$ for $\\mu \\leq 0$, i.e. the correction applies only to the downward intensities.** One has that $p_r = p - p^*$ is the residual phase function from the $\\delta-M$ approximation (section [1.3.1](#1.3.1-OPTIONAL:-Choose-delta-M-scaling)) and\n", + "for $\\mu > 0$, and take $u_\\text{IMS}(\\tau, -\\mu, \\phi) \\approx 0$ for $\\mu \\leq 0$, i.e. **the correction applies only to the downward intensities.** One has that $p_r = p - p^*$ is the residual phase function from the $\\delta-M$ approximation (section [1.3.1](#1.3.1-OPTIONAL:-Choose-delta-M-scaling)) and\n", "\n", "$$\n", "p_r^2\\left(-\\mu, \\phi ;-\\mu_0, \\phi_0\\right) = \\frac{1}{4 \\pi} \\int_0^{2 \\pi} \\int_{-1}^1 p_r\\left(-\\mu, \\phi ; \\mu', \\phi'\\right) p_r\\left(\\mu', \\phi' ;-\\mu_0, \\phi_0\\right) \\mathrm{d} \\phi' \\mathrm{d} \\mu'\n", @@ -3177,7 +3182,7 @@ "\\end{aligned}\n", "$$\n", "\n", - "As with $p$, one can truncate the series at `NLeg_all` and assume that the remaining Legendre terms are negligible.\n" + "As with $p$, truncate the series at `NLeg_all` and assume that the remaining Legendre terms are negligible.\n" ] }, { @@ -3185,7 +3190,7 @@ "id": "74eb9bc7", "metadata": {}, "source": [ - "One can derive the function\n", + "Derive the function\n", "\n", "$$\n", "\\begin{aligned}\n", @@ -3256,7 +3261,7 @@ " b_pos=b_pos,\n", " b_neg=b_neg,\n", " f_arr=f_arr[0],\n", - " _is_compatible_with_autograd=True,\n", + " _autograd_compatible=True,\n", ")[-1]\n", "\n", "# With both delta-M scaling and NT corrections\n", @@ -3270,7 +3275,7 @@ " b_neg=b_neg,\n", " f_arr=f_arr[0],\n", " NT_cor=True,\n", - " _is_compatible_with_autograd=True,\n", + " _autograd_compatible=True,\n", ")[-1]" ] }, @@ -3446,7 +3451,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 67, @@ -3502,7 +3507,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 68, @@ -3566,7 +3571,7 @@ "id": "0fe27fd8", "metadata": {}, "source": [ - "*This is implemented in `disort.py`.*\n", + "*This is implemented in* `disort.py`.\n", "\n", "PythonicDISORT also returns the positive (upward) and negative (downward) (energetic) flux functions. One has that\n", "\n", @@ -3621,7 +3626,7 @@ "\\end{aligned}\n", "$$\n", "\n", - "using the cosine expansion of $u$ from section [3.2](#3.2-Fourier-expansion-of-solution). In the last line, one can approximate the $\\mu$ integral by the Gauss-Legendre quadrature rule that was previously used. Only the $0$th moment matters for the flux. The upwelling and downwelling are respectively \n", + "using the cosine expansion of $u$ from section [3.2](#3.2-Fourier-expansion-of-solution). In the last line, the $\\mu$ integral can be approximated by Gauss-Legendre quadrature. Only the $0$th moment matters for the flux. The upwelling and downwelling are respectively \n", "\n", "$$F_\\text{total}^+(0), \\quad F_\\text{total}^-(\\tau_\\text{BoA})$$ " ] @@ -3681,7 +3686,7 @@ "metadata": {}, "outputs": [], "source": [ - "Ntau = 1000 # Number of tau test points\n", + "Ntau = 100 # Number of tau test points\n", "tau_test_arr = np.random.random(Ntau) * tau_arr[-1]\n", "\n", "# Number of phi grid points\n", @@ -3755,10 +3760,10 @@ "output_type": "stream", "text": [ "Flux up\n", - "Max pointwise error = 1.0482015255774968e-10\n", + "Max pointwise error = 1.0467893218901736e-10\n", "\n", "Flux down (diffuse only)\n", - "Max pointwise error = 3.907647538881065e-10\n" + "Max pointwise error = 3.907594248175883e-10\n" ] } ], @@ -3853,12 +3858,12 @@ "output_type": "stream", "text": [ "Without delta-scaling, i.e. f = 0\n", - "Flux up: Max pointwise error = 0.000887835471282683\n", - "Flux down: Max pointwise error = 0.000984622509934141\n", + "Flux up: Max pointwise error = 0.0008905161967485142\n", + "Flux down: Max pointwise error = 0.0009873031591491888\n", "\n", "With delta-scaling, f = 0.18530201888518416\n", - "Flux up: Max pointwise error = 0.00010464159282852492\n", - "Flux down: Max pointwise error = 9.899519048461869e-05\n" + "Flux up: Max pointwise error = 0.00010443756013378547\n", + "Flux down: Max pointwise error = 9.895489992306494e-05\n" ] } ], @@ -3938,7 +3943,7 @@ "id": "882a21c4", "metadata": {}, "source": [ - "**Computation and interpretation of reflectance and transmittance values**" + "**Computation and interpretation of reflectance, transmittance and absorption**" ] }, { @@ -3946,7 +3951,7 @@ "id": "720a5dd7", "metadata": {}, "source": [ - "Reflectance, $\\mathscr{R}$, and transmittance, $\\mathscr{T}$, can be computed only if the incident radiation comes entirely from one side of the atmosphere, usually downward onto the top layer. One generally calculates reflectance and transmittance, then absorptance $\\mathscr{A}$ can be calculated from the fact that the three ratios must sum to $1$ with respect to a specific source. As an example, we calculate the reflectance, transmittance and absorptance with respect to the direct beam:\n", + "Reflectance, $\\mathscr{R}$, and transmittance, $\\mathscr{T}$, can be computed only if the incident radiation comes entirely from one side of the atmosphere, usually downward onto the top layer. Generally, reflectance and transmittance are computed first, then absorptance $\\mathscr{A}$ is calculated from the fact that the three ratios must sum to $1$ with respect to a specific source. As an example, we will calculate the reflectance, transmittance and absorptance with respect to the direct beam:\n", "\n", "$$\n", "\\mathscr{R} = \\frac{F_\\text{Total}^+(0)}{I_0 \\mu_0}, \\quad \\mathscr{T} = \\frac{F_\\text{Total}^-(\\tau_0)}{I_0 \\mu_0}, \\quad \\mathscr{A} = 1 - \\mathscr{R} - \\mathscr{T}\n", @@ -4006,7 +4011,7 @@ "id": "1c8ef541", "metadata": {}, "source": [ - "*This is implemented in `_solve_for_coeffs.py`.*\n", + "*This is implemented in* `_solve_for_coeffs.py`.\n", "\n", "If the atmosphere has multiple layers, they will be coupled through their BCs as the solution must be continuous in $\\tau$. Notice that the BCs are only used to solve for the coefficients of the homogeneous solution. Hence, one first solves for the general solution of each layer up to unknown coefficients before solving for all the coefficients simultaneously through a generalization of section [3.6.2](#3.6.2-The-homogeneous-solution). One then constructs the \"full solution\" for each layer as per section [3.7](#3.7-The-full-solution). The full solution for the entire multi-layer atmosphere branches to the \"full solution\" of individual layers depending on the $\\tau$ input." ] @@ -4255,7 +4260,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 80, @@ -4292,7 +4297,7 @@ "id": "7df4dd6c", "metadata": {}, "source": [ - "PythonicDISORT has been optimized for speed over memory usage. The output functions store multiple tensors, the largest of which has dimensions $\\text{NFourier} \\times \\text{NLayers} \\times \\text{NQuad} \\times \\text{NQuad}$. When $u$ is called, a tensor of dimensions $\\text{NFourier} \\times \\text{Ntau} \\times \\text{NQuad} \\times \\text{NQuad}$ is constructed, where $\\text{Ntau}$ is the length of the $\\tau$ input and is in general large. A more memory efficient method would be to input the $\\tau$ and $\\phi$ values into `pydisort` and have the output be the solution evaluated at those values rather than a function. This is how Stamnes' DISORT works [[2]](#cite-STWJ1988). This way, the largest tensor that PythonicDISORT needs to construct will have dimensions $\\text{Ntau} \\times \\text{NQuad} \\times \\text{NQuad}$, but the tradeoff will be less speed and flexibility. Even within our current design paradigm there are avenues for memory optimization. Depending on the phase function of each atmospheric layer, the $\\text{NFourier} \\times \\text{NLayers} \\times \\text{NQuad} \\times \\text{NQuad}$ tensor may be sparse. Therefore, it may be beneficial to implement a sparse tensor framework or otherwise memory efficient variants of PythonicDISORT." + "PythonicDISORT has been optimized for speed over memory usage. The output functions store multiple tensors, the largest of which has dimensions $\\text{NFourier} \\times \\text{NLayers} \\times \\text{NQuad} \\times \\text{NQuad}$. When $u$ is called, a tensor of dimensions $\\text{NFourier} \\times \\text{Ntau} \\times \\text{NQuad} \\times \\text{NQuad}$ is constructed, where $\\text{Ntau}$ is the length of the $\\tau$ input and is in general large. A more memory efficient method would be to input the $\\tau$ and $\\phi$ values into `pydisort` and have the output be the solution evaluated at those values rather than a function. This is how Stamnes' DISORT works [[1]](#cite-STWJ1988). This way, the largest tensor that PythonicDISORT needs to construct will have dimensions $\\text{Ntau} \\times \\text{NQuad} \\times \\text{NQuad}$, but the tradeoff will be less speed and flexibility. Even within our current design paradigm there are avenues for memory optimization. Depending on the phase function of each atmospheric layer, the $\\text{NFourier} \\times \\text{NLayers} \\times \\text{NQuad} \\times \\text{NQuad}$ tensor may be sparse. Therefore, it may be beneficial to implement a sparse tensor framework or otherwise memory efficient variants of PythonicDISORT." ] }, { @@ -4318,7 +4323,7 @@ "metadata": {}, "outputs": [], "source": [ - "Ntau = 1000\n", + "Ntau = 100\n", "\n", "tau_test_arr = np.sort(np.random.random(Ntau) * tau_arr[-1])" ] @@ -4330,7 +4335,7 @@ "metadata": {}, "outputs": [], "source": [ - "# We turn everything on\n", + "# Turn everything on\n", "flux_up_1layer, flux_down_1layer, u0, u_1layer = PythonicDISORT.pydisort(\n", " tau_arr[-1], omega_arr[0],\n", " NQuad,\n", @@ -4408,7 +4413,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "NQuad, NLeg, NLoops, NLayers = 16 16 16 16\n" + "NQuad, NLeg, NFourier, NLayers = 16 16 16 16\n" ] } ], @@ -4441,19 +4446,19 @@ "output_type": "stream", "text": [ "Intensity\n", - "45.8 ms ± 2.99 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n", + "41.8 ms ± 369 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n", "\n", "Intensity with only one layer\n", - "3.35 ms ± 73 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n", + "3.07 ms ± 26.5 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n", "\n", "Intensity with blackbody emission and Lambertian BDRF\n", - "44.1 ms ± 271 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n", + "46.5 ms ± 748 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n", "\n", "Only fluxes\n", - "3.5 ms ± 138 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n", + "3.62 ms ± 28 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n", "\n", "Only fluxes with delta-M scaling\n", - "3.51 ms ± 24.5 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n" + "3.73 ms ± 31 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n" ] } ], @@ -4555,23 +4560,23 @@ "output_type": "stream", "text": [ "Intensity\n", - "180 µs ± 10.9 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)\n", + "179 µs ± 5.14 µs per loop (mean ± std. dev. of 7 runs, 10,000 loops each)\n", "\n", "Intensity with only one layer\n", - "189 µs ± 2.21 µs per loop (mean ± std. dev. of 7 runs, 10,000 loops each)\n", + "176 µs ± 1.03 µs per loop (mean ± std. dev. of 7 runs, 10,000 loops each)\n", "\n", "Intensity with NT corrections\n", - "7.68 ms ± 118 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n", + "7.32 ms ± 13.1 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n", "\n", "Intensity with NT corrections and only one layer\n", - "1.14 ms ± 16.7 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)\n", + "1.09 ms ± 22.8 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)\n", "\n", "Intensity with only blackbody emission\n", - "490 µs ± 21.5 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)\n", + "448 µs ± 1.95 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)\n", "\n", "Up and down fluxes respectively\n", - "60.8 µs ± 377 ns per loop (mean ± std. dev. of 7 runs, 10,000 loops each)\n", - "71.4 µs ± 2.63 µs per loop (mean ± std. dev. of 7 runs, 10,000 loops each)\n" + "59.8 µs ± 302 ns per loop (mean ± std. dev. of 7 runs, 10,000 loops each)\n", + "67.6 µs ± 1.77 µs per loop (mean ± std. dev. of 7 runs, 10,000 loops each)\n" ] } ], @@ -4622,23 +4627,23 @@ "Number of tau points = 1000 , Number of phi points = 100\n", "\n", "Intensity\n", - "36.2 ms ± 201 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n", + "36.1 ms ± 1.25 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n", "\n", "Intensity with only one layer\n", - "36.1 ms ± 264 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n", + "36.1 ms ± 97.9 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n", "\n", "Intensity with NT corrections\n", - "200 ms ± 2.92 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n", + "196 ms ± 11.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n", "\n", "Intensity with NT corrections and only one layer\n", - "61.7 ms ± 1.9 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n", + "55.8 ms ± 150 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n", "\n", "Intensity with only blackbody emission\n", - "37.1 ms ± 304 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n", + "36.1 ms ± 907 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n", "\n", "Up and down fluxes respectively\n", - "367 µs ± 34.4 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)\n", - "397 µs ± 15.6 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)\n" + "355 µs ± 946 ns per loop (mean ± std. dev. of 7 runs, 1,000 loops each)\n", + "376 µs ± 11 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)\n" ] } ], @@ -4692,7 +4697,7 @@ "id": "071bbadb", "metadata": {}, "source": [ - "Inspired by [[12]](#cite-KS2022), we created a Python wrapper around version 4.0.99 of Stamnes' FORTRAN DISORT [[3]](#cite-Sta1999) using F2PY with `O3` optimizations. Note that Stamnes' DISORT has 32-bit precision whereas PythonicDISORT has 64-bit precision. We will compare pointwise the solutions from PythonicDISORT against those from Stamnes' DISORT.\n", + "Inspired by [[12]](#cite-Con2020), we created a Python wrapper around version 4.0.99 of Stamnes' FORTRAN DISORT [[3]](#cite-Sta1999) using F2PY with `O3` optimizations. Note that Stamnes' DISORT has 32-bit precision whereas PythonicDISORT has 64-bit precision. We will compare pointwise the solutions from PythonicDISORT against those from Stamnes' DISORT.\n", "\n", "**For some tests, we do not compare intensities at polar angles that are within** $10^\\circ$ **of the direct beam.** This is because, even with NT corrections, there tends to be large inaccuracies at $\\mu$ points that are extremely close to the direct beam." ] @@ -4706,9 +4711,11 @@ ] }, { - "cell_type": "raw", - "id": "b51979a2", + "cell_type": "code", + "execution_count": 89, + "id": "71e1d202", "metadata": {}, + "outputs": [], "source": [ "# PythonicDISORT\n", "mu_arr, flux_up_NT, flux_down_NT, u0, u_NT = PythonicDISORT.pydisort(\n", @@ -4761,7 +4768,7 @@ "Nphi = int((NQuad * pi) // 2) * 2 + 1\n", "phi_arr, full_weights_phi = PythonicDISORT.subroutines.Clenshaw_Curtis_quad(Nphi)\n", "\n", - "Ntau = 1000 # Number of tau test points\n", + "Ntau = 100 # Number of tau test points\n", "tau_test_arr = np.random.random(Ntau) * tau_arr[-1]\n", "\n", "#tau_test_arr_small = np.random.choice(tau_test_arr, size=10, replace=False)\n", @@ -4783,22 +4790,26 @@ "id": "12a3734e", "metadata": {}, "source": [ - "Our F2PY-wrapped Stamnes DISORT (version 4.0.99) must be set up to run the following. We provide our `disort4.0.99_f2py` directory in our GitHub repository but it was designed for our personal use on a Windows 11 and we provide no guarantee that our setup will work for any other system." + "We generated reference solutions using our F2py-wrapped Stamnes' DISORT (version 4.0.99) and those results will be loaded, rather than re-generated, if DISORT is unavailable." ] }, { "cell_type": "code", - "execution_count": 92, - "id": "e672f708", + "execution_count": null, + "id": "633e643b", "metadata": {}, "outputs": [], "source": [ - "import disort" + "disort_is_installed = True\n", + "try:\n", + " import disort\n", + "except ImportError:\n", + " disort_is_installed = False" ] }, { "cell_type": "code", - "execution_count": 93, + "execution_count": 92, "id": "c61dda6e", "metadata": {}, "outputs": [], @@ -4857,16 +4868,45 @@ }, { "cell_type": "code", - "execution_count": 94, + "execution_count": 93, "id": "1a1ccbb9", "metadata": {}, "outputs": [], "source": [ - "# Run disort, putting DFDT, UAVG, and UU in a, b, and c, respectively\n", - "rfldir, rfldn, flup, dfdt, uavg, uu, albmed, trnmed = disort.disort(usrang, usrtau, ibcnd, onlyfl, prnt, plank, lamber, deltamplus, do_pseudo_sphere, dtauc, ssalb,\n", - " pmom, temper, wvnmlo, wvnmhi, utau, umu0, phi0 * 180/pi, umu, phi * 180/pi, fbeam, fisot, albedo, btemp, ttemp,\n", - " temis, earth_radius, h_lyr, rhoq, rhou, rho_accurate, bemst, emust, accur, header, rfldir,\n", - " rfldn, flup, dfdt, uavg, uu, albmed, trnmed)" + "if disort_is_installed:\n", + " # Run disort, putting DFDT, UAVG, and UU in a, b, and c, respectively\n", + " rfldir, rfldn, flup, dfdt, uavg, uu, albmed, trnmed = disort.disort(usrang, usrtau, ibcnd, onlyfl, prnt, plank, lamber, deltamplus, do_pseudo_sphere, dtauc, ssalb,\n", + " pmom, temper, wvnmlo, wvnmhi, utau, umu0, phi0 * 180/pi, umu, phi * 180/pi, fbeam, fisot, albedo, btemp, ttemp,\n", + " temis, earth_radius, h_lyr, rhoq, rhou, rho_accurate, bemst, emust, accur, header, rfldir,\n", + " rfldn, flup, dfdt, uavg, uu, albmed, trnmed)\n", + "else:\n", + " results = np.load(\"section6_testresults.npz\")\n", + " # Load saved results from Stamnes' DISORT\n", + " uu = results[\"uu\"]\n", + " flup = results[\"flup\"]\n", + " rfldn = results[\"rfldn\"]\n", + " rfldir = results[\"rfldir\"]\n", + " # Load comparison points\n", + " tau_test_arr = results[\"tau_test_arr\"]\n", + " phi_arr = results[\"phi_arr\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 94, + "id": "4b8b863d", + "metadata": {}, + "outputs": [], + "source": [ + "'''np.savez(\n", + " \"section6_testresults\",\n", + " phi_arr=phi_arr,\n", + " tau_test_arr=tau_test_arr,\n", + " uu=uu,\n", + " flup=flup,\n", + " rfldn=rfldn,\n", + " rfldir=rfldir,\n", + ")'''" ] }, { @@ -4890,16 +4930,16 @@ "Max pointwise differences\n", "\n", "Upward (diffuse) fluxes\n", - "Difference = 7.122510390455972e-05\n", - "Difference ratio = 0.001242476950475304\n", + "Difference = 6.71759360550972e-05\n", + "Difference ratio = 0.00020636065957854008\n", "\n", "Downward (diffuse) fluxes\n", - "Difference = 3.018062563686641e-05\n", - "Difference ratio = 0.00033429607872324335\n", + "Difference = 2.5611040443518363e-05\n", + "Difference ratio = 2.1529500099075758e-05\n", "\n", "Direct (downward) fluxes\n", - "Difference = 2.452002791919483e-07\n", - "Difference ratio = 1.8387572070496156e-06\n" + "Difference = 1.714574304756411e-07\n", + "Difference ratio = 1.6885422491020773e-06\n" ] } ], @@ -5001,8 +5041,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "At tau = 1.1961224297838768\n", - "Max pointwise difference = 0.008281490171013317\n" + "At tau = 1.1589799827860823\n", + "Max pointwise difference = 0.008266844581869215\n" ] } ], @@ -5020,7 +5060,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 99, @@ -5029,7 +5069,7 @@ }, { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAvAAAAImCAYAAAA1wb5IAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/H5lhTAAAACXBIWXMAAA9hAAAPYQGoP6dpAABkvElEQVR4nO3dfVxUZf7/8fcAMngDGBIIGyCZeRPeFJSCWtoNRWVZfsu2ImvVcq0tl2033Wo1t2LbNrOtdLOt3G5l27LaX6bRnVpqJYlplmlZmIIkKYjFjXB+fxizjtzNwMycOTOvZ4955Jw55zqfc5g55z3XXHPGZhiGIQAAAACWEGJ2AQAAAABcR4AHAAAALIQADwAAAFgIAR4AAACwEAI8AAAAYCEEeAAAAMBCCPAAAACAhRDgAQAAAAshwAMAAAAWQoAHAAAALIQAD3jQ4sWLZbPZHLeIiAj17t1bY8eOVX5+vsrLy1uc/5tvvnGaXlBQoJNOOkldu3aVzWZTcXFxm9ODUWv7zqw216xZozlz5mj//v0eq6czWtqW1mr0xr70FH/br205cOCA/vCHPyg7O1vHHnusbDab5syZ45XlP/roI5177rmKjIxUjx49NHbsWH3wwQettv3+++/r/PPP1zHHHKOuXbuqX79++vOf/+zmFgLwFwR4wAueeuoprV27VoWFhXr00Uc1bNgw3XfffRo4cKDeeustx3wXXHCB1q5dq4SEBMe077//Xrm5uerbt6+WL1+utWvX6sQTT2x1erBqad+Z2eaaNWt01113+U3QbGlbWqvRG/vSU/xtv7aloqJCixYtUm1trcaPH++15T/++GOdfvrp+umnn/TMM8/omWeeUU1Njc466yytXbu22fzPP/+8zjjjDEVHR+vpp5/WsmXLdNttt8kwDLdrBOAfwswuAAhEaWlpysjIcNyfMGGCfvvb32rUqFG69NJLtW3bNsXHx+vYY4/Vscce67Tsl19+qfr6el199dU644wzHNM3bNjQ4vTO+PHHH9WtWzePtOVrLe07f2zTLO5sSyBtt5lSUlK0b98+2Ww27d27V//85z+9svydd96pnj17avny5Y7X79lnn63jjz9et956q1NP/K5du3T99dfrhhtu0IIFCxzTx44d24EtBOAv6IEHfCQ5OVkPPPCADhw4oMcee0xS86EL1157rUaNGiVJmjhxomw2m8aMGdPq9Cbbtm3TlVdeqbi4ONntdg0cOFCPPvqo0/rnzJkjm82mTz75RP/3f/+nY445Rn379u1QG5999pl++ctfKjo6WvHx8frVr36lysrKZtv8xRdf6Je//KXi4+Nlt9uVnJysa665RrW1tW6ttyUtDftwt7722nS1vTlz5uj3v/+9JCk1NdUxhOq9997zyv79/vvvdf311yspKUl2u13HHnusRo4c6fTpTkvb0lqNrQ2hcaVmV2ppyfbt23XdddepX79+6tatm37xi19o3Lhx2rRpk1v79WiPPPKI0zC2o2/dunVTXV1dm7V1VNM6vL38Bx98oDFjxji9+Y6MjNTpp5+uNWvWqLS01DH9n//8pw4ePKjbbrutw3UB8D/0wAM+dP755ys0NFSrVq1q8fE777xTp512mm688Ubde++9Gjt2rKKiomS321ucLklbtmxRVlaW4w1C7969tWLFCt18883au3evZs+e7bSOSy+9VFdccYWmTZumgwcPdqiNCRMmaOLEiZo8ebI2bdqkWbNmSZKefPJJxzwbN27UqFGjFBsbq7lz56pfv34qLS3Va6+9prq6OtntdrfX6ypX6vNke1OmTNEPP/yghx9+WC+//LJjKMqgQYMkeX7/5ubm6pNPPtE999yjE088Ufv379cnn3yiioqKVrehrRpbGvvuas0dqUWSdu/erV69eukvf/mLjj32WP3www/617/+peHDh2vDhg3q379/u/u1JePGjXN8+rVhwwZNnz5d8+bNU2ZmpiSpW7duCg8Pd1rGMAw1NDS0WW+TsDDzT5tNr5+jNU3btGmTY1+tWrVKMTEx+uKLL3TxxRdr8+bNiomJ0aWXXqq//vWvjuMIAIsxAHjMU089ZUgyPv7441bniY+PNwYOHOg0/44dOxyPv/vuu4Yk48UXX3RarrXp5557rnHccccZlZWVTtNvuukmIyIiwvjhhx8MwzCM2bNnG5KMP/3pT81qcreNv/71r07zTZ8+3YiIiDAaGxsd084880yjZ8+eRnl5eav7wtX1tqSlfedOfa606U57999/f7N63N1OV9fXo0cPY8aMGW5tS1s1tjSvqzW7UosrDh06ZNTV1Rn9+vUzfvvb37ZbsyseffRRQ5JRUlLS5nxNry1Xbq7W8f333xuSjNmzZ7tdd3vLDxs2zDjxxBONhoYGx7T6+nrj+OOPNyQZzz//vGN6//79jYiICCMyMtK49957jXfffdf461//anTt2tUYOXJku68JAP6JITSAjxke/OJYTU2N3n77bV1yySXq1q2bDh065Lidf/75qqmp0bp165yWmTBhQqfbuOiii5zuDxkyRDU1NY6r7Pz4449auXKlLr/88lbHVndkva5qrz5ftueN/Xvaaadp8eLFuvvuu7Vu3TrV19d3aLs8UXNHazl06JDuvfdeDRo0SOHh4QoLC1N4eLi2bdumzz//3CPbUVxcrJiYGCUlJbU5X3p6uj7++GOXbomJiR6prTN+85vf6Msvv9RNN92kXbt2aefOnZo2bZq+/fZbSVJIyP9O7Y2NjaqpqdEf//hHzZo1S2PGjNHvf/975efn64MPPtDbb79t1mYA6AQCPOBDBw8eVEVFhcdCQEVFhQ4dOqSHH35YXbp0cbqdf/75kqS9e/c6LXP0lUY60kavXr2c7jd9dP/TTz9Jkvbt26eGhgYdd9xxHq3dVe3V58v2vLF/CwoKNGnSJP3zn/9UZmamYmJidM0116isrKxD29eZmjtaS15enu68806NHz9e//3vf/Xhhx/q448/1tChQzv8dzpacXGxhg0b1u58PXr00LBhw1y6HT38xgy/+tWv9Je//EXPPPOMjjvuOCUnJ2vLli269dZbJUm/+MUvHPM2PZfOPfdcpzZycnIkSZ988omPqgbgSeYP5gOCyOuvv66GhganL6B2xjHHHKPQ0FDl5ubqxhtvbHGe1NRUp/tHf0muI220JyYmRqGhofruu+88WrsVeWM7Y2NjNX/+fM2fP18lJSV67bXXNHPmTJWXl2v58uU+rbmjtTz77LO65pprdO+99zpN37t3r3r27NnpbTAMQ5s3b9avf/3rdudduXKly1dl2bFjh/r06dPJ6jrvtttu04wZM7Rt2zZFRkYqJSVFN9xwg7p376709HTHfEOGDGnxk6ymTwKP7K0HYB0EeMBHSkpKdOuttyo6Olo33HCDR9rs1q2bxo4dqw0bNmjIkCEd6h30RBtH69q1q8444wy9+OKLuueeexQbG+uT9ZqptV55b29ncnKybrrpJr399ttt/pBPWzUeraM1u1OLzWZr9kXM119/Xbt27dIJJ5zgds1H++GHH/TTTz+59OaoaQiNK/xhCE0Tu92utLQ0SYePLwUFBZo6daq6du3q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8AAAAECwI8ADAAAAFkKABwAAACyEAA8AAABYCAEeAAAAsBACPAAAAGAhBHgAAADAQgjwAAAAgIUQ4AEAAAALIcADAAAAFkKABwAAACyEAA8AAABYCAEeAAAAsBACPAAAAOBDYWFhGjZsmIYNG6YpU6a4v7wXagIAAADQip49e6q4uLjDy9MDDwAAAFgIAR4AAAD42apVqzRu3DglJibKZrPplVdeaTbPggULlJqaqoiICKWnp2v16tVuraOqqkrp6ekaNWqUVq5c6XaNDKEBAAAAfnbw4EENHTpU1113nSZMmNDs8YKCAs2YMUMLFizQyJEj9dhjjyknJ0dbtmxRcnKyJCk9PV21tbXNln3zzTeVmJiob775RomJidq8ebMuuOACbdq0SVFRUS7XSIAHAABAQKuqqnK6b7fbZbfbW5w3JydHOTk5rbY1b948TZ482fHl0/nz52vFihVauHCh8vPzJUlFRUVt1pOYmChJSktL06BBg/Tll18qIyPD5e0hwAMAAMB0B7+NUkhEhEfbbKypkSQlJSU5TZ89e7bmzJnjdnt1dXUqKirSzJkznaZnZ2drzZo1LrWxb98+devWTXa7Xd999522bNmi448/3q06CPAAAAAIaDt37nQaotJa73t79u7dq4aGBsXHxztNj4+PV1lZmUttfP7557rhhhsUEhIim82mhx56SDExMW7VQYAHAABAQIuKinJrjHl7bDab033DMJpNa01WVpY2bdrUqfVzFRoAAADABbGxsQoNDW3W215eXt6sV96bCPAAAACAC8LDw5Wenq7CwkKn6YWFhcrKyvJZHQyhAQAAAH5WXV2t7du3O+7v2LFDxcXFiomJUXJysvLy8pSbm6uMjAxlZmZq0aJFKikp0bRp03xWIwEeAAAA+Nn69es1duxYx/28vDxJ0qRJk7R48WJNnDhRFRUVmjt3rkpLS5WWlqZly5YpJSXFZzUS4L0o8qvWRygd6NvY4WXd0d56vL3+I7lbS2s1dHSb3F2Pq1qrxxv70NOOrN2b9Xr6b+YvPL3PrLafvP0cN3N/+PPrt6394s91+wNPnYc8pSPP8fZqOrrNI+e32jHGLGPGjJFhGG3OM336dE2fPt1HFTVHgPewHl+HKNTe/gveVwdZfzqYe6oWf9omyf/qcYe/PQ8P9G209P7srGDe9pawP1rGfuk4f9t33qin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", + "image/png": "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1NTovffe02WXXabQ0FAdOXLEfrvwwgtVU1PT7KoUV1xxRafbuOSSSxzuDx06VDU1Nfar7Pz0009au3atrrzyylbnVnfkeZ3VXn3ebM8T+/fMM8/U0qVLdd9992njxo2qr6/vUL/cUXNHazly5IgeeOABDR48WMHBweratauCg4O1c+dOffXVV27pR1FRkSIiIhQXF9fmeikpKfrss8+cusXGxrqlts4YPny4Fi5cqEmTJmncuHG64YYbVFBQoJiYGN1xxx329X7/+9/r66+/1q233qq9e/dqz549ysrK0nfffSdJ6tKFCACYFe9ewIsOHz6siooKt4WAiooKHTlyRE888YS6devmcLvwwgslSeXl5Q7bHP8n8460ceKJJzrcb/qT/M8//yxJOnDggBoaGnTyySe7tXZntVefN9vzxP7Ny8vTlClT9Pe//11paWmKiIjQddddp9LS0g71rzM1d7SW7Oxs3XPPPZo0aZL+9a9/6ZNPPtFnn32m5OTkDv87Ha+oqEjDhg1rd72ePXtq2LBhTt2On37jK3r37q2LL75Yn3/+uX3//e53v9Nf/vIXLVu2TCeffLLi4+O1fft2zZo1S5L0q1/9ysiSAXSC70zmAwLAW2+9pYaGBocvoHbGCSecoKCgIGVmZuqWW25pcZ3ExESH+8d/Sa4jbbQnIiJCQUFB+v77791auxl5op+RkZFauHChFi5cqOLiYq1cuVKzZ89WWVmZVq9e7dWaO1rLiy++qOuuu04PPPCAw/Ly8nL17t27032w2Wz64osvdPPNN7e77tq1azVhwgSn2t29e7f69u3byeo8o+mve8e+x++8807NnDlTO3fuVK9evZSQkKCbbrpJPXr0UEpKilGlAugkAjzgJcXFxZo1a5bCw8N10003uaXN0NBQTZgwQVu2bNHQoUM7NDrojjaO1717d/3617/Wq6++qvvvv1+RkZFeeV4jtTYq7+l+xsfH69Zbb9V7773X7mUBnf3LQUdrdqUWi8XS7AuWb731lvbu3avTTjvN5ZqP9+OPP+rnn3926sNR0xQaZ/jCFJqWHDhwQP/+9781bNgwhYSEODxmtVrt14cvLi5WXl6epk+fru7duxtRKgA3IMADHvDFF1/Y5wyXlZVp/fr1eu655xQUFKQVK1a49Zrbjz32mMaOHatx48bp5ptvVt++fXXo0CHt2rVL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pNFePhTA1WNsIB2TA6mvgDuZZgrNV199pdWrV2vjxo0aOXKkJOnpp59WWlqaduzYoQEDWg4Effr0cbj/5ptvasKECTrllFMcloeGhjZbty21tbWqra213z/+J3p9hSujPv4QJL11MnD3vmI6je8IxLnwgfKByohjXEff1/5wTA608w/gTaYJ8Bs2bFB4eLg9vEtHf8kqPDxcBQUFrQb4Y+3fv19vvfWWnn/++WaPvfTSS3rxxRcVHR2tjIwMzZ07V7169Wq1rZycHN17770d64wXdOSkYfaDKAEY3sKoOpzR2WOS2Y/JrmBePOAa0wT40tJSRUVFNVseFRXl9E/XPv/88+rVq5cuv/xyh+XXXHONEhMT1adPH33xxReaM2eOtm7d2uwan8eaM2eO/VvJ0tER+Li4OCd741mdOWmY9YThD+GdUXjfEUgBPVBG373NXe/lQDsmm7W/gLcZHuDnzZvX7kj2Z599Jqn5z9ZKrv107bPPPqtrrrlGISEhDsunT59u//+kpCT169dPqamp2rx5s0aMGNFiW1arVVar1ann9SZ3nDTMdgD1dug1074B4H3uPiaZ7ZjcWYHWX6AjDA/wt956a7tXfOnbt68+//xz7d+/v9ljP/zwg1M/Xbt+/Xrt2LFDeXl57a47YsQIdevWTTt37mw1wPsid540OIDC094pHqD0+B1Gl+Hz2hshZx/C1wTiQBLgbYYH+MjISEVGRra7XlpamiorK/Xpp5/qzDPPlCR98sknqqysdOqna5955hmlpKQoOTm53XW//PJL1dfXKyYmpv0O+BB3TsHgwAmYw7EB39UwH0jTZzimeY87zkX8ewFtM81lJAcNGqQLLrhA06dP18aNG7Vx40ZNnz5dF198scMXWAcOHKgVK1Y4bFtVVaVXX31V06ZNa9buN998o/nz52vTpk369ttvtWrVKv3mN7/R8OHDNWbMGI/3y92qd4e75QeGzMSb9Zpt38DcXA3YgRTIfZknrlJlNh2t2R3nMCAQmCbAS0evFDNkyBClp6crPT1dQ4cO1bJlyxzW2bFjhyorHT/5L1++XDabTb/97W+btRkcHKz33ntP559/vgYMGKDbbrtN6enpevfddxUUFOTR/nhSRw6CHDjhbQTO1nV03zi7Hfves9x1LA2UYzLnH8A1hk+hcUVERIRefPHFNtdp6advb7zxRt14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", "text/plain": [ "
" ] @@ -5061,8 +5101,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "At tau = 7.991591727003761\n", - "Max pointwise difference ratio = 0.008982786619195859\n" + "At tau = 1.8540976793185102\n", + "Max pointwise difference ratio = 0.0020281292072543114\n" ] } ], @@ -5080,7 +5120,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 101, @@ -5089,7 +5129,7 @@ }, { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAvAAAAImCAYAAAA1wb5IAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/H5lhTAAAACXBIWXMAAA9hAAAPYQGoP6dpAABUW0lEQVR4nO3dfVxUZf7/8fcIMijKGBIgikhl3iGY4A2oKZUYrpZbm3ZHWmqRua3L+t00K82tqG0zy8JftpbbrWyZN22m0Y03pVYieFOtaVl4AxKmoCagcH5/mLON3M0gw3Dw9Xw8zqPONde55nPOHOE9F2fOWAzDMAQAAADAFJp5ugAAAAAAziPAAwAAACZCgAcAAABMhAAPAAAAmAgBHgAAADARAjwAAABgIgR4AAAAwEQI8AAAAICJEOABAAAAEyHAAwAAACZCgEeTt2jRIlksFvvi6+urkJAQJSQkKC0tTQUFBVX2/+GHHxzaMzIy1KNHD7Vo0UIWi0U5OTk1tqNuNmzYoFmzZunIkSOVHqvutWksnD0XzmU/ajo+nlDVvlRXY2N//Rrbsa3OuHHjHH6mnb1s2rSp1jG++OILDRs2TK1bt1arVq2UkJCgzz77rM79Pv74Y91xxx3q2rWr/Pz81L59e1177bXKysqql30GcBYDaOJefvllQ5Lx8ssvGxs3bjTWrVtnvP3228aUKVMMm81mBAQEGJmZmfb+BQUFxsaNG42SkhKHtubNmxsjR4401qxZY2zcuNE4fvx4te2ouyeffNKQZOzZs6fSY1W9No2FK+fCuexHTcfHE6ral+pqbMyvn2E0vmNbnd27dxsbN26stAQGBhrt27c3Tp06VeP2X3zxhWG1Wo1BgwYZS5cuNd555x2jf//+htVqNTZs2OByP8MwjD/84Q9GQkKCkZ6ebqxZs8Z46623jP79+xve3t7GRx995JbjAJzPCPBo8s4E+C+//LLSYz/++KMRFhZmtG7d2sjPz692jE8//dSQZGRkZDjVfi6a2hsAV/fHLCHqbO44F6pihuNjhhqrYta6DcMw1qxZY0gyHnjggVr7Dhs2zAgODnb4t1lcXGwEBgYa8fHxLvczDMM4ePBgpec5evSoERwcbFx55ZV12SUANSDAo8mrKcAbhmH8+9//NiQZDz/8sEP/M7/Ex44da0hyWAYPHlxt+xnffvutcdNNNxkXXnih4ePjY3Tt2tV47rnnHJ575syZhiQjKyvLuP766402bdoYISEhdRpjx44dxo033mj4+/sbQUFBxu23324cOXKk0v5+8803xo033mgEBQUZPj4+RlhYmJGcnOwwK+rM81alpv3ZtWuXMW7cOOOSSy4xWrRoYYSGhhojRowwtm3bVmn7s5dPPvmkytfmjPXr1xtXXHGF0apVK6NFixZGXFyc8Z///MehT0FBgTFx4kSjQ4cOho+Pjz2E/PavL9WpbfzazoWzVbUfzryOtR0fw6j/c6a243b2vtRUY3WvnzM11/X1c+a8c/bY/ta8efOq7H9madGihVFaWlpjbfUpOTnZsFgsxvfff19r31atWhljxoyp1H7dddcZkowDBw641K8mCQkJxqWXXurEHgBwhfc5XoEDmN7w4cPl5eWldevWVfn4gw8+qL59++qee+7RY489poSEBPn7+8tqtVbZLklff/214uPj1bFjRz311FMKCQnR6tWrde+996qwsFAzZ850eI7rrrtON954o1JSUnT8+PE6jXH99ddrzJgxGj9+vLZv367p06dLkl566SV7n61bt2rgwIEKDAzU7Nmz1blzZ+Xl5WnFihUqKyuT1Wp1+XmrUtX+HDhwQG3bttXjjz+uCy+8UD///LP+9a9/qV+/fsrOzlaXLl00YcIE/fzzz5o3b57eeecdtWvXTpLUvXv3ap9r7dq1Gjp0qKKiorRw4UJZrValp6dr5MiRevPNNzVmzBhJUnJysrZs2aJHH31Ul156qY4cOaItW7bo0KFDNe6LM+NXd47URU2vY23Hxx3njKvHraYaq7r23dma6/r6OXPe1VZ3VUaOHKnY2FhJUnZ2tiZNmqQ5c+YoLi5OktSyZUv5+PhU2s4wDJWXl9dY8xne3s79ii4qKtLbb7+tK6+8UhEREbX2P/Nv/Wxn2rZv36527do53a+murZs2aIrrrjCqf0A4AJPv4MA3K22GXjDMIzg4GCjW7duDv1/O0v4ySefGJKMt956y2G76tqHDRtmdOjQwSgqKnJonzx5suHr62v8/PPPhmH8b9bvoYceqlSTq2P8/e9/d+g3adIkw9fX16ioqLC3XXHFFUabNm2MgoKCao+Fs89blZr252ynTp0yysrKjM6dOxt//vOf7e01XcZQ1WvTv39/IygoyDh69KjD2JGRkUaHDh3s+9+qVStjypQptdZ1NmfHr+5cqEpNM/C1vY41HR93nDO1Hbeq9qW6Gqvq62zNdX39zlbdeVdT3bV5/vnnDUlGbm5urX3PnCfOLM7WMX/+fEOS8eabbzrVv1evXsall15qlJeX29tOnjxpXHTRRYYk44033nCpX3VuueUWw9vb29i8ebNTdQFwHnehAXR6Vqy+lJSU6KOPPtLvf/97tWzZUqdOnbIvw4cPV0lJSaW7RFx//fXnPMY111zjsB4VFaWSkhL7XXZ++eUXrV27VqNHj9aFF15Yb7VX5ez9kaRTp07pscceU/fu3eXj4yNvb2/5+Pho165d+uabb2odsyrHjx/X559/rj/84Q9q1aqVvd3Ly0vJycnat2+fdu7cKUnq27evFi1apEceeUSbNm3SyZMn63X8+lLb61gdd5wzUt2Om7NcqbmudbjjvDtbTk6OAgICFBYWVmvfmJgYffnll04toaGhTj3/woUL1bZtW/3+9793qv8f//hHffvtt5o8ebL279+vvXv3KiUlRT/++KMkqVmzZi71q8qDDz6o119/XU8//bRiYmKcqguA8wjwOO8dP35chw4dcvqXZW0OHTqkU6dOad68eWrevLnDMnz4cElSYWGhwzZn/xm6LmO0bdvWYf3Mn7lPnDghSTp8+LDKy8vVoUOHeq29KlX9WT01NVUPPvigRo0apXfffVeff/65vvzyS0VHR9trdNXhw4dlGEaVz3fm9TxziUVGRobGjh2rf/7zn4qLi1NAQIBuu+025efn18v49aW217E67jhnpLodN2e5UnNd63DHeXe2nJwc9erVy6m+rVq1Uq9evZxaqroE52zbtm3T5s2bdeutt1Z5uUtV7rjjDj3++ON69dVX1aFDB3Xs2FFff/21pk6dKklq3769S/3O9vDDD+uRRx7Ro48+qsmTJztVEwDXcA08znvvvfeeysvLNWTIkHoZ74ILLrDP0N5zzz1V9jn7OlWLxXLOY9QmICBAXl5e2rdvX73WXpWz90eSXnvtNd1222167LHHHNoLCwvVpk2bWsesrt5mzZopLy+v0mMHDhyQJAUGBtr/O3fuXM2dO1e5ublasWKFpk2bpoKCAq1ateqcx/c0d5wzUt2Omztqrmsd7jjvfsswDO3YsUN33323U/3Xrl2rhIQEp/ru2bNHnTp1qrHPwoULJZ2+ht8V9913n6ZMmaJdu3apdevWCg8P11133SU/Pz+HGXNn+53x8MMPa9asWZo1a5buv/9+l2oC4DwCPM5rubm5mjp1qmw2m+666656GbNly5ZKSEhQdna2oqKinJpFc8cYZ2vRooUGDx6st956S48++miVwdMdz3uGxWKpNEP43nvvaf/+/brkkkvsbc7OOEuSn5+f+vXrp3feeUf/+Mc/1KJFC0lSRUWFXnvtNXXo0EGXXnpppe06duyoyZMn66OPPqryS2nOdXx3qu74uPO1O8PZ4+bsa1jXmp2tQ3L+vHOl7t/6+eefdeLECaffHJ25hMYZtf1VsLS0VK+99pr69u2ryMhIp8b8LavVat8uNzdXGRkZmjhxov08d7Xf3/72N82aNUsPPPCAUx92B1B3BHicN3bs2GG/vragoEDr16/Xyy+/LC8vLy1durTa68Lr4plnntHAgQM1aNAg3X333erUqZOOHj2q3bt3691339XHH3/cIGOcbc6cORo4cKD69eunadOm6ZJLLtHBgwe1YsUKvfDCC2rdurVbnleSRowYoUWLFqlr166KiopSVlaWnnzyyUqX9PTs2dO+/2PHjlXz5s3VpUsXtW7duspx09LSNHToUCUkJGjq1Kny8fFRenq6duzYoTfffFMWi0VFRUVKSEjQzTffrK5du6p169b68ssvtWrVKl133XU11u3M+A2ppuNT369dXY9bdTVWxZmaz+X1c/a8q6nu6s496XS4bd68uTIzMxUVFaXo6GjZbLZq+7du3dp+95pztWzZMv3888/Vzr6vXbtWV155pR566CE99NBD9vYdO3ZoyZIlio2NldVq1datW/X444+rc+fO+tvf/uZyP0l66qmn9NBDD+nqq6/W7373u0qft+jfv3+97DOAX3n2M7SA+52588WZxcfHxwgKCjIGDx5sPPbYY5XuyFIfd6ExDMPYs2ePcccddxjt27c3mjdvblx44YVGfHy88cgjj9j7nLkbyE8//VRl7ecyRnX33P7666+NG264wWjbtq3h4+NjdOzY0Rg3bpzDfeCded6q1LQ/hw8fNsaPH28EBQUZLVu2NAYOHGisX7/eGDx4cKV7pk+fPt0IDQ01mjVr5tJ94P38/IwWLVoY/fv3N95991374yUlJUZKSooRFRVl+Pv7Gy1atDC6dOlizJw506kvmqptfMOov7vQOPM6Vnd8DKN+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NkmlpaX65ptv1K5dO0+X0iQMGDCg0i18v/32W4WHh3uoIjRmXEJzjlJTU5WcnKzY2FjFxcVpwYIFys3NVUpKiqdLazKOHTum3bt329f37NmjnJwcBQQEqGPHjh6srGm455579MYbb2j58uVq3bq1/S9KNptNLVq08HB1TcP999+vpKQkhYWF6ejRo1q8eLHWrFmjVatWebq0JqF169aVPrPh5+entm3b8lmOejR16lSNHDlSHTt2VEFBgR555BEVFxdr7Nixni6tSfjzn/+s+Ph4PfbYYxo9erS++OILLViwQAsWLPB0aWiECPDnaMyYMTp06JBmz56tvLw8RUZGauXKlbxjrkebN29WQkKCff3MtZZjx47VokWLPFRV03HmFqhDhgxxaH/55Zc1bty4hi+oCTp48KCSk5OVl5cnm82mqKgorVq1SkOHDvV0aYDT9u3bp5tuukmFhYW68MIL1b9/f23atInfd/WkT58+Wrp0qaZPn67Zs2crIiJCc+fO1S233OLp0tAIcR94AAAAwES4Bh4AAAAwEQI8AAAAYCIEeAAAAMBECPAAAACAiRDgAQAAABMhwAMAAAAmQoAHAAAATIQADwAAAJgIAR4AAAAwEQI8AAAAYCIEeAAwga5du+qf//ynp8sAADQCBHgAaOROnDih3bt3Kzo62tOlAAAaAQI8ADRyO3bskGEYioyM9HQpAIBGgAAPAI1UTk6OrrjiCg0cOFAVFRXq2LGjnn76aU+XBQDwMG9PFwAAqOy7777T4MGD9X//939q27atKioq1KdPH6WmpmrQoEGKjY31dIkAAA9hBh4AGqGUlBRdd911euCBB5Sbm6u4uDj99a9/VZs2bbR+/XpPlwcA8CACPAA0Mvn5+fr444+VkpKi8vJybd++XZdddpmaNWsmb29v+fj4eLpEAIAHEeABoJHZtGmTKioq1KtXL/33v//ViRMn1KtXL+3du1eFhYUaMGCAp0sEAHgQAR4AGpmysjJJUklJiXJyctShQwe1bdtWL7zwgrp3765evXp5tkAAgEfxIVYAaGT69+8vb29vzZ49W8eOHdPFF1+s9PR0Pf300/rkk088XR4AwMMI8ADQyHTs2FEvvfSS7rvvPuXl5cnb21u//PKLVq5cqb59+3q6PACAh1kMwzA8XQQAoGoBAQF66aWXNGrUKE+XAgBoJLgGHgAaqX379unw4cPq2bOnp0sBADQiBHgAaKS2b98uPz8/XXTRRZ4uBQDQiHAJDQAAAGAizMADAAAAJkKABwAAAEyEAA8AAACYCAEeAAAAMBECPAAAAGAiBHgAAADARAjwAAAAgIkQ4AEAAAATIcADAAAAJkKABwAAAEzk/wPRQC0vts8w4wAAAABJRU5ErkJggg==", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAvAAAAImCAYAAAA1wb5IAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/H5lhTAAAACXBIWXMAAA9hAAAPYQGoP6dpAABj4klEQVR4nO3de3wU1f3/8fcSyIYgCYaQQEqCVLmHa4IQLgpeokERlCqojWgBS9Eq5osKtQpSJVUrxlv4gZdSxSpVxEtFMF64KKASiIIogsUmQEIkQgJoEgjz+wOzZcltN9nLzO7r+XjsA3YyM/uZ2d0z7zl7dtZmGIYhAAAAAJbQzN8FAAAAAHAdAR4AAACwEAI8AAAAYCEEeAAAAMBCCPAAAACAhRDgAQAAAAshwAMAAAAWQoAHAAAALIQADwAAAFgIAR4AAACwEAI8At7ixYtls9kct7CwMLVv314jR45UZmamiouLa53/+++/d5q+dOlS9erVSy1btpTNZlNeXl6909E469ev15w5c3To0KEaf6vruTELV18LTdmO+vaPP9S2LXXVaPbnz2z7ti6HDx/WXXfdpdTUVLVr1042m01z5sxxefktW7Zo7NixiouLU3h4uLp37665c+fqp59+cppv9erVTm3nqbeNGzfW+xjPPvusbDabzjjjjMZsIoAGEOARNP7+979rw4YNysnJ0dNPP61+/frpoYceUo8ePfT+++875rvsssu0YcMGdejQwTHthx9+UHp6us4++2ytXLlSGzZsUNeuXeucjsZbv3697r///lpDVG3PjVm481poynbUt3/8obZtqatGMz9/kvn2bV1KSkq0aNEiVVRUaOzYsW4tu337dg0ZMkTff/+9srKy9O9//1sTJkzQ3Llzde2119a6zLx587RhwwanW2JiYp2PsXfvXs2YMUNxcXFu1QbAdc39XQDgK4mJiUpOTnbcHzdunO644w4NGzZMV111lXbu3KnY2Fi1a9dO7dq1c1r222+/1bFjx/Tb3/5W559/vmP6li1bap3eFD/99JPCw8M9si4z8OT21PbcmEVdr5HamHk73OXOtgTSdvtTp06ddPDgQdlsNh04cEDPPvusy8v+85//VHl5uZYtW6azzz5bknTBBReosLBQixYt0sGDB3XmmWc6LdOlSxcNHjzY5ceYOnWqzjvvPEVFRem1115zeTkArqMHHkEtISFBjz76qA4fPqyFCxdKqvkx/4033qhhw4ZJksaPHy+bzaYRI0bUOb3azp07dd111ykmJkZ2u109evTQ008/7fT4c+bMkc1m0+bNm/Wb3/xGZ555puOg6u46vvrqK1177bWKjIxUbGysfve736m0tLTGNn/zzTe69tprFRsbK7vdroSEBN1www2qqKhw63FrU9/27Nq1SzfddJO6dOmi8PBw/epXv9Lo0aO1detWp+XvvPNOSVLnzp0dH9evXr261uem2scff6wLL7xQrVu3Vnh4uIYMGaJ33nnHaZ4ffvhBN998s+Lj42W329WuXTsNHTrU6dOXujS0/oZeC6erbTtceR4b2j+S518zDe2307elvhrrev5cqbmxz58rrztX9+2pnnrqqTqHl9hsNoWHh6uysrLe2hqr+jEao0WLFpKkyMhIp+lt2rRRs2bNFBoa2qTalixZojVr1ig7O7tJ6wFQP3rgEfRGjRqlkJAQrV27tta/33vvvTr33HN1yy23aN68eRo5cqQiIiJkt9trnS7972Pq6hOE9u3ba9WqVbrtttt04MABzZ492+kxrrrqKk2YMEFTp07V0aNHG7WOcePGafz48Zo0aZK2bt2qWbNmSZKef/55xzxffPGFhg0bpujoaM2dO1ddunRRYWGh3nrrLVVWVsput7v9uLWpbXv27duntm3b6q9//avatWunH3/8Uf/4xz80aNAgbdmyRd26ddPkyZP1448/6sknn9Trr7/uGGrRs2fPOh9rzZo1uvjii9WnTx8999xzstvtys7O1ujRo/Xyyy9r/PjxkqT09HRt3rxZDz74oLp27apDhw5p8+bNKikpqXdbXFl/Xa+RxqjveWxo/3jjNePufquvxtrGvrtac2OfP1dedw3VXZvRo0c7PtHbsmWLpk2bpvnz5yslJUWSFB4eXmsYNgxDVVVV9dZcrXlzzx+iJ06cqKysLP3hD3/QQw89pHbt2mnNmjVauHChbrnlFrVq1arGMrfccosmTJig8PBwpaSk6N5773WcsJ6quLhY06dP11//+ld17NjR47UDOIUBBLi///3vhiTj888/r3Oe2NhYo0ePHk7z79692/H3jz76yJBkvPrqq07L1TX9kksuMTp27GiUlpY6Tb/11luNsLAw48cffzQMwzBmz55tSDLuu+++GjW5u46HH37Yab5p06YZYWFhxokTJxzTLrjgAqNNmzZGcXFxnfvC1cetTX3bc7rjx48blZWVRpcuXYw77rjDMf2RRx6psf+r1fbcDB482IiJiTEOHz7stO7ExESjY8eOju0/44wzjOnTpzdY1+lcXX9dr4Xa1LYdrj6P9e0fb7xmGtpvtW1LXTXWNq+rNTf2+TtdXa+7+upuyNNPP21IMvLz8xuct/p14srNlTp++OEHQ5Ixe/Zsl+v9+uuvje7duzs91m233eb0vBuGYWzevNm4/fbbjeXLlxtr1641nn/+eaNHjx5GSEiIsXLlyhrrHTdunDFkyBDHeiZOnGi0atXK5boAuI4hNIBO9op5Snl5uT744ANdeeWVCg8P1/Hjxx23UaNGqby8vMYVHMaNG9fkdVxxxRVO9/v06aPy8nLHVXZ++uknrVmzRtdcc02d45Ab87i1OX17JOn48eOaN2+eevbsqdDQUDVv3lyhoaHauXOnvv766wbXWZujR4/q008/1W9+8xunq12EhIQoPT1de/bs0Y4dOyRJ5557rhYvXqwHHnhAGzdu1LFjxzy6fk9p6HmsizdeM1Lj9pur3Km5sXV443V3ury8PEVFRSk+Pr7BeZOSkvT555+7dPPGl0C///57jR49Wm3bttVrr72mNWvW6OGHH9bixYs1efJkp3n79++vrKwsjR07VsOHD9dNN92k9evXq0OHDrrrrruc5l22bJnefvttPfPMM40e3gPAdQR4BL2jR4+qpKTEYwfLkpISHT9+XE8++aRatGjhdBs1apQk6cCBA07LnH5Vjsaso23btk737Xa7JOnnn3+WJB08eFBVVVX1frTdmMetTW1XGcnIyNC9996rsWPH6u2339ann36qzz//XH379nXU6K6DBw/KMIxaH6/6+aweYrF06VJNnDhRzz77rFJSUhQVFaUbbrhBRUVFHlm/pzT0PNbFG68ZqXH7zVXu1NzYOrzxujtdXl6e+vXr59K8Z5xxhvr16+fSranj0Wszc+ZMlZWVadWqVRo3bpzOO+883XnnncrKytLzzz+vNWvW1Lt8mzZtdPnll+vLL7907L8jR47olltu0R//+EfFxcXp0KFDOnTokOM7AIcOHXIMpQPgGYyBR9B75513VFVVVe+XDt1x5plnOnpob7nlllrn6dy5s9P903usGrOOhkRFRSkkJER79uzxaO21qa0HbsmSJbrhhhs0b948p+kHDhxQmzZtGlxnXfU2a9ZMhYWFNf62b98+SVJ0dLTj36ysLGVlZSk/P19vvfWWZs6cqeLiYq1cubLJ6/c3b7xmpMbtN2/U3Ng6vPG6O5VhGNq2bZv+8Ic/uDT/mjVrNHLkSJfm3b17t84666wmVFdTXl6eevbsWWOs+8CBAyVJ27Zta/AqStWfWFa/zw8cOKD9+/fr0Ucf1aOPPlpj/jPPPFNjxozRG2+84YEtACAR4BHk8vPzNWPGDEVGRur3v/+9R9YZHh6ukSNHasuWLerTp0+jetE8sY7TtWzZUueff75effVVPfjgg7UGT288bjWbzebo4a32zjvvaO/evTrnnHMc01ztcZakVq1aadCgQXr99df1t7/9TS1btpQknThxQkuWLFHHjh1rvRZ7QkKCbr31Vn3wwQf65JNPPL5+b6pr/3jzuavm6n5z9TlsbM2u1iG5/rpzp+5T/fjjj/r5559dPjmqHkLjCm8MoYmLi9O2bdt05MgRp2FhGzZskKQGv3x68OBB/fvf/1a/fv0UFhYmSWrfvr0++uijGvP+9a9/1Zo1a/Tuu++a5kQXCBQEeASNbdu2OcbXFhcXa926dfr73/+ukJAQLV++3KPXp3788cc1bNgwDR8+XH/4wx901lln6fDhw9q1a5fefvttffjhhz5Zx+nmz5+vYcOGadCgQZo5c6bOOecc7d+/X2+99ZYWLlyo1q1be+VxJenyyy/X4sWL1b17d/Xp00e5ubl65JFHagSG3r17O7Z/4sSJatGihbp166bWrVvXut7MzExdfPHFGjlypGbMmKHQ0FBlZ2dr27Ztevnll2Wz2VRaWqqRI0fquuuuU/fu3dW6dWt9/vnnWrlypa666qp663Zl/b5U3/7x9HPX2P1WV421caXmpjx/rr7u6qu7rteedDL0t2jRQjk5OerTp4/69u1b4xKNp2rdurXT71E01rvvvqujR4/q8OHDkk5ezaf6muujRo1SeHi41qxZowsvvFD33Xef7rvvPknS9OnTNXbsWF188cW64447FB0drY0bNyozM1M9e/ZUWlqa4zGuu+46JSQkKDk5WdHR0dq5c6ceffRR7d+/X4sXL3bMFxYWVusnmIsXL1ZISIjHPt0EcAq/foUW8IHqK19U30JDQ42YmBjj/PPPN+bNm1fjiiyeuAqNYRjG7t27jd/97nfGr371K6NFixZGu3btjCFDhhgPPPCAY57qq4H88MMPtdbelHXUth2GYRjbt283rr76aqNt27ZGaGiokZCQYNx4441GeXm5W49bm/q25+DBg8akSZOMmJgYIzw83Bg2bJixbt064/zzzzfOP/98p3lnzZplxMXFGc2aNTMkGR999FG927Ru3TrjggsuMFq1amW0bNnSGDx4sPH22287/l5eXm5MnTrV6NOnjxEREWG0bNnS6NatmzF79mzj6NGj9W6TK+s3DM9dhcaV57Gu/WMYnn3NuLLf6npOaquxrnkbqrkpz587r7uG9m1d5s+fb8TFxRmSjB07djQ4vyd06tSpwavXVL8mT79CzYcffmikpqYa7du3N1q2bGl07drV+L//+z/jwIEDTvNlZmYa/fr1MyIjI42QkBCjXbt2xpVXXml89tlnLtXIVWgA77EZhgcvvwEAAADAq7gKDQAAAGAhBHgAAADARwoKCjRixAj17NlTffr00auvvur2OhhCAwAAAPhIYWGh9u/fr379+qm4uFgDBgzQjh07alzetT5chQYAAADwkQ4dOjh+IDAmJkZRUVH68ccf3QrwDKEBAAAAfrF27VqNHj1acXFxstlstf4IWXZ2tjp37qywsDAlJSVp3bp1jXqsTZs26cSJE4qPj3drOQI8AAAA8IujR4+qb9++euqpp2r9+9KlSzV9+nTdc8892rJli4YPH660tDTl5+c75klKSlJiYmKNW/WveEtSSUmJbrjhBi1atMjtGhkD7yEnTpzQvn371Lp1a5//sAsAAIA7DMPQ4cOHFRcXp2bN/N+fW15ersrKSq+s2zCMGtnMbrfX+JXm2thsNi1fvlxjx451TBs0aJAGDBigBQsWOKb16NFDY8eOVWZmpks1VVRU6OKLL9aUKVOUnp7u2oacgjHwHrJv3z63P/4AAADwp4KCglp/mdiXysvL1THhDJX8UOWV9Z9xxhk6cuSI07TZs2drzpw5bq+rsrJSubm5mjlzptP01NRUrV+/3qV1GIahG2+8URdccEGjwrtEgPeY6p/a7vj43WrWsuEzOgAAAH858XOF9tz+kCO/+FNlZaVKfqjSWxs6qtUZnv004OiRE7oiZY8KCgoUERHhmO5K73ttDhw4oKqqKsXGxjpNj42NVVFRkUvr+OSTT7R06VL16dPHMb7+xRdf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Z4gfqwHQFJbpgd+wYYMiIyMd4V2SBg8erMjISK1fv97l9ZSWlspms6lNmzZO01966SVFR0erV69emjFjhg4fPlzveioqKlRWVuZ087RAb1wDffsCCeEd7uD1AgDeZZkAX1RUpJiYmBrTY2JiVFRU5NI6ysvLNXPmTF133XWKiIhwTL/++uv18ssva/Xq1br33nu1bNkyXXXVVfWuKzMz0zEWPzIyUvHx8e5tUD2CIdgGwzYCgNkEcttbvW2BvI1ANb8H+Dlz5tT4Aunpt02bNkmSbDZbjeUNw6h1+umOHTumCRMm6MSJE8rOznb625QpU3TRRRcpMTFREyZM0Guvvab3339fmzdvrnN9s2bNUmlpqeNWUFDg5pYD1kBvKhqD1w0AeI/fx8DfeuutDV7x5ayzztKXX36p/fv31/jbDz/8oNjY2HqXP3bsmK655hrt3r1bH374oVPve20GDBigFi1aaOfOnRowYECt89jtdtnt9nrX0xT0IMAMCGFA4OH4Alif3wN8dHS0oqOjG5wvJSVFpaWl+uyzz3TuuedKkj799FOVlpZqyJAhdS5XHd537typjz76SG3btm3wsb766isdO3ZMHTp0cH1DgABDeEdTlXcvV9g3Yf4uA0GEkxMEC78PoXFVjx49dOmll2rKlCnauHGjNm7cqClTpujyyy93ugJN9+7dtXz5cknS8ePH9Zvf/EabNm3SSy+9pKqqKhUVFamoqEiVlZWSpO+++05z587Vpk2b9P3332vFihW6+uqr1b9/fw0dOtQv2wr4G+EdAADzskyAl05eKaZ3795KTU1Vamqq+vTpoxdffNFpnh07dqi0tFSStGfPHr311lvas2eP+vXrpw4dOjhu1VeuCQ0N1QcffKBLLrlE3bp102233abU1FS9//77CgnhTB4AAADm4vchNO6IiorSkiVL6p3HMAzH/8866yyn+7WJj4/XmjVrPFIfEAjofYcnMYwGADzPUj3wALyL8A4AgPkR4AFIIrzDe3htAYBnEeABAAAACyHAA6CHFF7HawwAPIcADwAAAFiIpa5CAwC+cF6XXR5b19qd53hsXQCAwLB792797ne/0/79+xUSEqKNGzeqVatWLi9PgAeCHEMb4CtcUhIATrrxxhv1wAMPaPjw4frxxx9lt9vdWp4hNADgRZ7szQcAWN9XX32lFi1aaPjw4ZJO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MAwlJib6uxQAgAkQ4AHApPLy8nTBBRdo2LBhOnHihBISEvTYY4/5uywAgJ8193cBAICavvvuO51//vm688471bZtW504cUIDBw5URkaGhg8fruTkZH+XCADwE3rgAcCEpk6dqquuukp//vOflZ+fr5SUFN11111q06aN1q1b5+/yAAB+RIAHAJMpKirShx9+qKlTp6qqqkpbt25V//791axZMzVv3lyhoaH+LhEA4EcEeAAwmY0bN+rEiRPq16+fvvnmG/3888/q16+fCgoKdODAAQ0dOtTfJQIA/IgADwAmU1lZKUkqLy9XXl6eOnbsqLZt22rhwoXq2bOn+vXr598CAQB+xZdYAcBkBg8erObNm2vu3Lk6cuSIzj77bGVnZ+uxxx7TRx995O/yAAB+RoAHAJNJSEjQ888/r7vvvluFhYVq3ry5fvrpJ61YsULnnnuuv8sDAPiZzTAMw99FAABqFxUVpeeff15jx471dykAAJNgDDwAmNSePXt08OBB9e7d29+lAABMhAAPACa1detWtWrVSr/+9a/9XQoAwEQYQgMAAABYCD3wAAAAgIUQ4AEAAAALIcADAAAAFkKABwAAACyEAA8AAABYCAEeAAAAsBACPAAAAGAhBHgAAADAQgjwAAAAgIUQ4AEAAAAL+f9S87JIXiLEMgAAAABJRU5ErkJggg==", "text/plain": [ "
" ] @@ -5128,9 +5168,7 @@ "source": [ "We use PyTest to implement test problems 1 to 9, 11, 14 and 15 *(TODO: 6, 7, 14, 15 have not yet been implemented)* of version 4.0.99 of Stamnes' FORTRAN DISORT [[3]](#cite-Sta1999). These test problems are coded, described and explained in `DISOTEST.txt` and `disotest.f90`. Test problem 11 is equivalent to our verification test in section [4.2](#4.2-Verification-of-multi-layer-solver) and we implemented the latter in PyTest. We added a subproblem to problem 5 to test the Lambertian BDRF. All test parameters are copied from `disotest.f90` and `DISOTESTAUX.f` unless stated otherwise. Except for test problem 11 which is an internal consistency test, we compare the solutions from PythonicDISORT against corresponding solutions from Stamnes' DISORT which are saved in `.npz` files.\n", "\n", - "We compare flux and intensity values at random $\\tau$ points and, for the intensity, at $\\mu$ and $\\phi$ quadrature points. For some tests, we do not compare intensities at polar angles that are within $10^\\circ$ of the direct beam. Our test criteria is that every point that has difference greater than $10^{-3}$ must have a difference ratio of less than $10^{-2}$ $(1\\%)$ for the intensity, or $10^{-3}$ $(0.1\\%)$ for the fluxes. **With PyTest installed, execute the console command** `pytest` **in the** `pydisotest` **directory to run these tests.** Add the flag `-s` to print the differences to console.\n", - "\n", - "The Stamnes DISORT solutions which we test PythonicDISORT against can be re-generated using the Jupyter Notebooks in the `pydisotest` directory but this requires setting up the F2PY-wrapped Stamnes DISORT (version 4.0.99) which we used. We provide our `disort4.0.99_f2py` directory in our GitHub repository but it was designed for our personal use on a Windows 11 and we provide no guarantee that our setup will work for any other system." + "We compare fluxes at the $\\tau$ points given in `disotest.f90`, and at $\\mu$ and $\\phi$ quadrature points for the intensity. For some tests, we do not compare intensity values at polar angles that are within $10^\\circ$ of the direct beam. Our test criteria is that every point that has difference greater than $10^{-3}$ must have a difference ratio of less than $10^{-2}$ $(1\\%)$ for the intensity, or $10^{-3}$ $(0.1\\%)$ for the fluxes. **With PyTest installed, execute the console command** `pytest` **in the** `pydisotest` **directory to run these tests.** Add the flag `-s` to print the differences to console." ] }, { @@ -5146,7 +5184,7 @@ "id": "b3425ef1", "metadata": {}, "source": [ - "We time our F2PY-wrapped Stamnes' DISORT rather than the original FORTRAN DISORT which is faster. Compare against PythonicDISORT's times in section [5](#5.-Timing-PythonicDISORT)." + "Note that we time our F2PY-wrapped Stamnes' DISORT rather than the original FORTRAN DISORT which is faster. Compare against PythonicDISORT's times in section [5](#5.-Timing-PythonicDISORT)." ] }, { @@ -5154,7 +5192,7 @@ "id": "fe4380fb", "metadata": {}, "source": [ - "**Time taken to evaluate the solution at just one point**" + "**Time taken to compute the solution at just one point**" ] }, { @@ -5190,20 +5228,29 @@ "output_type": "stream", "text": [ "Intensity\n", - "4.4 ms ± 132 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n", + "4.31 ms ± 89.6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n", "\n", "Only fluxes\n", - "477 µs ± 11.1 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)\n" + "437 µs ± 3.56 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)\n" ] } ], "source": [ - "print(\"Intensity\")\n", - "%timeit disort.disort(usrang, usrtau, ibcnd, False, prnt, plank, lamber, deltamplus, do_pseudo_sphere, dtauc, ssalb, pmom, temper, wvnmlo, wvnmhi, utau, umu0, phi0, umu, phi, fbeam, fisot, albedo, btemp, ttemp, temis, earth_radius, h_lyr, rhoq, rhou, rho_accurate, bemst, emust, accur, header, rfldir, rfldn, flup, dfdt, uavg, uu, albmed, trnmed)\n", - "print()\n", + "if disort_is_installed:\n", + " print(\"Intensity\")\n", + " %timeit disort.disort(usrang, usrtau, ibcnd, False, prnt, plank, lamber, deltamplus, do_pseudo_sphere, dtauc, ssalb, pmom, temper, wvnmlo, wvnmhi, utau, umu0, phi0, umu, phi, fbeam, fisot, albedo, btemp, ttemp, temis, earth_radius, h_lyr, rhoq, rhou, rho_accurate, bemst, emust, accur, header, rfldir, rfldn, flup, dfdt, uavg, uu, albmed, trnmed)\n", + " print()\n", "\n", - "print(\"Only fluxes\")\n", - "%timeit disort.disort(usrang, usrtau, ibcnd, True, prnt, plank, lamber, deltamplus, do_pseudo_sphere, dtauc, ssalb, pmom, temper, wvnmlo, wvnmhi, utau, umu0, phi0, umu, phi, fbeam, fisot, albedo, btemp, ttemp, temis, earth_radius, h_lyr, rhoq, rhou, rho_accurate, bemst, emust, accur, header, rfldir, rfldn, flup, dfdt, uavg, uu, albmed, trnmed)" + " print(\"Only fluxes\")\n", + " %timeit disort.disort(usrang, usrtau, ibcnd, True, prnt, plank, lamber, deltamplus, do_pseudo_sphere, dtauc, ssalb, pmom, temper, wvnmlo, wvnmhi, utau, umu0, phi0, umu, phi, fbeam, fisot, albedo, btemp, ttemp, temis, earth_radius, h_lyr, rhoq, rhou, rho_accurate, bemst, emust, accur, header, rfldir, rfldn, flup, dfdt, uavg, uu, albmed, trnmed)\n", + "else:\n", + " print(\"MOST RECENT TIMING TESTS\")\n", + " print()\n", + " print(\"Intensity\")\n", + " print(\"4.31 ms ± 89.6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\")\n", + " print()\n", + " print(\"Only fluxes\")\n", + " print(\"437 µs ± 3.56 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)\")" ] }, { @@ -5211,7 +5258,7 @@ "id": "7a36a9cf", "metadata": {}, "source": [ - "**Time taken to evaluate the solution at a large number of points**" + "**Time taken to compute the solution at a large number of points**" ] }, { @@ -5231,7 +5278,7 @@ } ], "source": [ - "# We evaluate the solution at only one point\n", + "# Evaluate the solution at only one point\n", "ntau = Ntau_time\n", "utau = tau_test_arr_time\n", "nphi = Nphi_time\n", @@ -5259,20 +5306,37 @@ "output_type": "stream", "text": [ "Intensity\n", - "2.05 s ± 92.1 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n", + "1.85 s ± 14.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n", "\n", "Only fluxes\n", - "11 ms ± 167 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n" + "10.9 ms ± 84 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n" ] } ], "source": [ - "print(\"Intensity\")\n", - "%timeit disort.disort(usrang, usrtau, ibcnd, False, prnt, plank, lamber, deltamplus, do_pseudo_sphere, dtauc, ssalb, pmom, temper, wvnmlo, wvnmhi, utau, umu0, phi0, umu, phi, fbeam, fisot, albedo, btemp, ttemp, temis, earth_radius, h_lyr, rhoq, rhou, rho_accurate, bemst, emust, accur, header, rfldir, rfldn, flup, dfdt, uavg, uu, albmed, trnmed)\n", - "print()\n", + "if disort_is_installed:\n", + " print(\"Intensity\")\n", + " %timeit disort.disort(usrang, usrtau, ibcnd, False, prnt, plank, lamber, deltamplus, do_pseudo_sphere, dtauc, ssalb, pmom, temper, wvnmlo, wvnmhi, utau, umu0, phi0, umu, phi, fbeam, fisot, albedo, btemp, ttemp, temis, earth_radius, h_lyr, rhoq, rhou, rho_accurate, bemst, emust, accur, header, rfldir, rfldn, flup, dfdt, uavg, uu, albmed, trnmed)\n", + " print()\n", "\n", - "print(\"Only fluxes\")\n", - "%timeit disort.disort(usrang, usrtau, ibcnd, True, prnt, plank, lamber, deltamplus, do_pseudo_sphere, dtauc, ssalb, pmom, temper, wvnmlo, wvnmhi, utau, umu0, phi0, umu, phi, fbeam, fisot, albedo, btemp, ttemp, temis, earth_radius, h_lyr, rhoq, rhou, rho_accurate, bemst, emust, accur, header, rfldir, rfldn, flup, dfdt, uavg, uu, albmed, trnmed)" + " print(\"Only fluxes\")\n", + " %timeit disort.disort(usrang, usrtau, ibcnd, True, prnt, plank, lamber, deltamplus, do_pseudo_sphere, dtauc, ssalb, pmom, temper, wvnmlo, wvnmhi, utau, umu0, phi0, umu, phi, fbeam, fisot, albedo, btemp, ttemp, temis, earth_radius, h_lyr, rhoq, rhou, rho_accurate, bemst, emust, accur, header, rfldir, rfldn, flup, dfdt, uavg, uu, albmed, trnmed)\n", + "else:\n", + " print(\"MOST RECENT TIMING TESTS\")\n", + " print()\n", + " print(\"Intensity\")\n", + " print(\"1.85 s ± 14.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\")\n", + " print()\n", + " print(\"Only fluxes\")\n", + " print(\"10.9 ms ± 84 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\")" + ] + }, + { + "cell_type": "markdown", + "id": "abeb9eae", + "metadata": {}, + "source": [ + "A surprisingly long time is taken by our F2PY-wrapped DISORT to compute the intensity at a large number of points." ] }, { @@ -5283,11 +5347,13 @@ "