├── CNAME ├── TidalPy ├── Material │ ├── __init__.py │ └── eos │ │ ├── __init__.py │ │ ├── methods │ │ ├── __init__.py │ │ ├── __init__.pxd │ │ └── interpolate.pxd │ │ ├── eos_solution.pyx │ │ ├── __init__.pxd │ │ ├── ode.pxd │ │ └── solver.pxd ├── utilities │ ├── __init__.py │ ├── io │ │ ├── __init__.py │ │ └── pathing.py │ ├── arrays │ │ ├── __init__.py │ │ ├── interp.pyx │ │ ├── interp.pxd │ │ └── interp_.hpp │ ├── math │ │ ├── __init__.py │ │ ├── special.pxd │ │ ├── numerics.pxd │ │ ├── __init__.pxd │ │ ├── numerics.pyx │ │ ├── complex.pxd │ │ └── numba_special.py │ ├── dimensions │ │ ├── __init__.py │ │ ├── nondimensional_.hpp │ │ └── nondimensional.pxd │ ├── graphics │ │ ├── multilayer │ │ │ └── __init__.py │ │ └── __init__.py │ ├── types_x.pxd │ ├── performance │ │ ├── special │ │ │ ├── __init__.py │ │ │ └── factorial.py │ │ ├── __init__.py │ │ ├── memory.py │ │ └── numba.py │ ├── exoplanets │ │ └── __init__.py │ ├── classes │ │ ├── model │ │ │ └── __init__.py │ │ ├── base_x.pxd │ │ ├── config │ │ │ └── __init__.py │ │ ├── __init__.py │ │ ├── base.py │ │ └── base_x.pyx │ ├── types_x.pyx │ ├── string_helper │ │ └── __init__.py │ ├── numpy_helper │ │ └── __init__.py │ ├── spherical_helper │ │ └── __init__.py │ ├── conversions │ │ ├── __init__.py │ │ ├── conversions_x.pxd │ │ └── timing.py │ ├── multiprocessing │ │ └── __init__.py │ ├── integration │ │ ├── scipy_helper.py │ │ ├── numbalsoda_helper.py │ │ └── cyrk_helper.py │ └── types.py ├── structures │ ├── helpers │ │ └── __init__.py │ ├── world_builder │ │ └── __init__.py │ ├── __init__.py │ ├── orbit │ │ └── __init__.py │ ├── layers │ │ ├── __init__.py │ │ └── gas.py │ └── world_types │ │ ├── __init__.py │ │ └── gas.py ├── RadialSolver │ ├── boundaries │ │ ├── __init__.py │ │ ├── surface_bc.pxd │ │ └── boundaries.pxd │ ├── collapse │ │ ├── __init__.py │ │ └── collapse.pxd │ ├── interfaces │ │ ├── __init__.py │ │ ├── interfaces.pxd │ │ └── reversed.pxd │ ├── starting │ │ ├── __init__.py │ │ ├── saito.pxd │ │ ├── common.pxd │ │ ├── driver.pxd │ │ ├── takeuchi.pxd │ │ ├── kamata.pxd │ │ └── saito.pyx │ ├── derivatives │ │ ├── __init__.py │ │ └── odes.pxd │ ├── constants.pxd │ ├── matrix_types │ │ ├── __init__.py │ │ └── solid_matrix.pxd │ ├── __init__.pxd │ ├── love.pxd │ ├── love_.hpp │ ├── __init__.py │ ├── constants.pyx │ ├── matrix.pxd │ ├── shooting.pxd │ ├── love.pyx │ ├── solver.pxd │ ├── love_.cpp │ └── rs_solution_.hpp ├── Extending │ ├── burnman │ │ ├── material │ │ │ ├── __init__.py │ │ │ └── custom │ │ │ │ ├── __init__.py │ │ │ │ └── pyrite.py │ │ ├── defaults.py │ │ ├── __init__.py │ │ ├── conversion.py │ │ ├── burnman_defaultc.py │ │ └── package.py │ └── __init__.py ├── WorldPack │ ├── WorldPack.zip │ ├── 55cnc.toml │ ├── sol.toml │ ├── neptune.toml │ ├── jupiter.toml │ ├── trappist1.toml │ ├── triton_simple.toml │ ├── io_simple.toml │ ├── nereid_dev.toml │ ├── 55cnce_simple.toml │ ├── charon.toml │ ├── pluto.toml │ ├── earth_simple.toml │ ├── io.toml │ ├── triton.toml │ ├── luna.toml │ ├── trappist1e.toml │ ├── trappist1g.toml │ ├── trappist1c.toml │ ├── trappist1d.toml │ ├── trappist1f.toml │ ├── trappist1h.toml │ ├── 55cnce.toml │ ├── trappist1b.toml │ ├── europa.toml │ ├── earth.toml │ └── mercury.toml ├── numba_scipy │ ├── special │ │ ├── __init__.py │ │ └── overloads.py │ ├── __init__.py │ └── TODO_DeletePackage.md ├── tides │ ├── modes │ │ ├── __init__.py │ │ └── mode_calc_helper │ │ │ ├── inclin_calc_orderl2.py │ │ │ ├── inclin_calc_orderl3.py │ │ │ ├── inclin_calc_orderl4.py │ │ │ ├── inclin_calc_orderl5.py │ │ │ ├── inclin_calc_orderl6.py │ │ │ └── inclin_calc_orderl7.py │ ├── methods │ │ └── __init__.py │ ├── ctl_funcs │ │ ├── __init__.py │ │ └── ctl_funcs.py │ ├── multilayer │ │ ├── heating.pxd │ │ ├── __init__.py │ │ └── sensitivity.pxd │ ├── __init__.py │ ├── potential │ │ └── __init__.py │ ├── dissipation.py │ ├── inclination_funcs │ │ ├── orderl2.py │ │ └── orderl3.py │ ├── universal_coeffs.py │ └── heating.py ├── toolbox │ └── __init__.py ├── orbit │ └── __init__.py ├── radiogenics │ └── __init__.py ├── rheology │ ├── __init__.py │ ├── complex_compliance │ │ └── __init__.py │ ├── viscosity │ │ └── __init__.py │ ├── base.pxd │ ├── partial_melt │ │ └── __init__.py │ └── models.pxd ├── cooling │ └── __init__.py ├── stellar │ ├── __init__.py │ └── stellar.py ├── dynamics │ └── __init__.py ├── output.py ├── constants.pxd ├── __init__.py └── cache.py ├── Documentation ├── Overview │ ├── 0_Readme.md │ └── index.md ├── _static │ ├── images │ │ └── 2025-11-28_Logo_2-4.png │ └── custom.css ├── RadialSolver │ ├── Starting Radius Table.xlsx │ ├── 4_RadialSolver_Cython_API.md │ └── index.md ├── API │ └── index.md ├── Dynamics │ ├── 1_Dynamics.md │ └── index.md ├── Style Templates │ ├── docstring - module.txt │ ├── docstring - class.txt │ └── docstring - function or method.txt ├── Rheology │ └── index.md └── index.md ├── Papers └── 2025-JOSS │ ├── paper.pdf │ └── figures │ ├── bbg │ ├── io_rheology_comparison.png │ ├── stacked_images_set_0.png │ ├── dynamic_vs_static_tides.png │ ├── spin_orbit_resonance_ledges.png │ ├── compressibility_effects_venus.png │ ├── trappist1e_2d_heating_15deg_obliquity.png │ ├── trappist1e_2d_heating_tidally_locked.png │ ├── trappist1e_2d_heating_2-1_sor_15deg_obliquity.png │ ├── trappist1e_2d_heating_2-1_spin-orbit_resonance.png │ ├── trappist1e_2d_heating_3-2_sor_15deg_obliquity.png │ └── trappist1e_2d_heating_3-2_spin-orbit_resonance.png │ ├── wbg │ ├── io_rheology_comparison.png │ ├── stacked_images_set_0.png │ ├── dynamic_vs_static_tides.png │ ├── spin_orbit_resonance_ledges.png │ ├── compressibility_effects_venus.png │ ├── trappist1e_2d_heating_15deg_obliquity.png │ ├── trappist1e_2d_heating_tidally_locked.png │ ├── trappist1e_2d_heating_2-1_sor_15deg_obliquity.png │ ├── trappist1e_2d_heating_2-1_spin-orbit_resonance.png │ ├── trappist1e_2d_heating_3-2_sor_15deg_obliquity.png │ └── trappist1e_2d_heating_3-2_spin-orbit_resonance.png │ └── trappist1e-bm.toml ├── Benchmarks ├── RadialSolver │ ├── Guo+2004.npy │ └── Farrell1972.npy └── Performance │ ├── tides │ └── Previous Runs │ │ ├── RunTimePlot_0.2.1dev.pdf │ │ ├── RunTimePlot_0.2.1.dev7.pdf │ │ ├── CompileTimePlot_0.2.1dev.pdf │ │ └── CompileTimePlot_0.2.1.dev7.pdf │ └── performance suite │ ├── performance_build_world.py │ ├── run_suite.py │ └── performance_complex_compliance_func.py ├── Tests ├── Test_Old │ ├── Test_SetA_Package │ │ ├── test_a_version.py │ │ ├── test_tidalpy_config.py │ │ └── test_io.py │ ├── Test_SetS_Tides │ │ └── Test_Heating │ │ │ └── test_heating.py │ ├── Test_SetB_Package │ │ ├── test_c_tools_timing.py │ │ ├── test_i_spherical_mass.py │ │ ├── test_b_utilities_numpy.py │ │ └── test_g_math_special_funcs.py │ ├── Test_SetE_Functional │ │ └── test_a_performance_funcs.py │ └── Test_SetO_OOP_Calcs │ │ └── test_oop_rheology.py ├── Test_RadialSolver │ ├── Test_PropMatrix │ │ ├── solid_derivative_matrix.npy │ │ ├── solid_derivative_matrix_l3.npy │ │ ├── solid_fundamental_matrix.npy │ │ ├── solid_fundamental_matrix_l3.npy │ │ ├── solid_inverse_fundamental_matrix.npy │ │ └── solid_inverse_fundamental_matrix_l3.npy │ └── test_a_boundary_conditions.py ├── Test_Math │ ├── test_utilities_special.py │ └── test_utilities_numerics.py ├── Test_Utilities │ ├── Test_Exoplanets │ │ └── test_exoplanet_download.py │ └── Test_Dimensions │ │ └── test_nondimensional.py └── Test_Package │ └── test_configs.py ├── index.html ├── readthedocs.yml ├── NOTICE ├── .github ├── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md └── workflows │ ├── make_joss_pdf.yml │ ├── push_tests_win.yml │ └── push_tests_ubun.yml ├── .vscode └── tasks.json ├── MANIFEST.in ├── citation.cff ├── meta.yaml └── setup.py /CNAME: -------------------------------------------------------------------------------- 1 | tidalpy.info -------------------------------------------------------------------------------- /TidalPy/Material/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /TidalPy/Material/eos/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /TidalPy/utilities/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /TidalPy/utilities/io/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /TidalPy/structures/helpers/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /TidalPy/utilities/arrays/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /TidalPy/utilities/math/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /TidalPy/Material/eos/methods/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /TidalPy/RadialSolver/boundaries/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /TidalPy/RadialSolver/collapse/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /TidalPy/RadialSolver/interfaces/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /TidalPy/RadialSolver/starting/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /TidalPy/utilities/dimensions/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /TidalPy/Extending/burnman/material/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /TidalPy/RadialSolver/derivatives/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /TidalPy/utilities/graphics/multilayer/__init__.py: -------------------------------------------------------------------------------- 1 | from .yplot import yplot as yplot 2 | -------------------------------------------------------------------------------- /TidalPy/utilities/math/special.pxd: -------------------------------------------------------------------------------- 1 | cdef double cf_double_factorial(int n) noexcept nogil 2 | -------------------------------------------------------------------------------- /Documentation/Overview/0_Readme.md: -------------------------------------------------------------------------------- 1 | 2 | ```{include} Readme.md 3 | :start-after: Overview 4 | ``` -------------------------------------------------------------------------------- /TidalPy/utilities/types_x.pxd: -------------------------------------------------------------------------------- 1 | ctypedef fused double_numeric: 2 | double 3 | double complex -------------------------------------------------------------------------------- /Papers/2025-JOSS/paper.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jrenaud90/TidalPy/HEAD/Papers/2025-JOSS/paper.pdf -------------------------------------------------------------------------------- /TidalPy/utilities/performance/special/__init__.py: -------------------------------------------------------------------------------- 1 | from .factorial import find_factorial as find_factorial -------------------------------------------------------------------------------- /TidalPy/utilities/exoplanets/__init__.py: -------------------------------------------------------------------------------- 1 | from .data_download import get_exoplanet_data as get_exoplanet_data 2 | -------------------------------------------------------------------------------- /TidalPy/RadialSolver/constants.pxd: -------------------------------------------------------------------------------- 1 | cdef size_t MAX_NUM_Y 2 | cdef size_t MAX_NUM_Y_REAL 3 | cdef size_t MAX_NUM_SOL -------------------------------------------------------------------------------- /TidalPy/WorldPack/WorldPack.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jrenaud90/TidalPy/HEAD/TidalPy/WorldPack/WorldPack.zip -------------------------------------------------------------------------------- /TidalPy/numba_scipy/special/__init__.py: -------------------------------------------------------------------------------- 1 | from . import overloads as _overloads 2 | 3 | _overloads.add_overloads() 4 | -------------------------------------------------------------------------------- /Benchmarks/RadialSolver/Guo+2004.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jrenaud90/TidalPy/HEAD/Benchmarks/RadialSolver/Guo+2004.npy -------------------------------------------------------------------------------- /Benchmarks/RadialSolver/Farrell1972.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jrenaud90/TidalPy/HEAD/Benchmarks/RadialSolver/Farrell1972.npy -------------------------------------------------------------------------------- /TidalPy/RadialSolver/matrix_types/__init__.py: -------------------------------------------------------------------------------- 1 | from TidalPy.RadialSolver.matrix_types.solid_matrix import fundamental_matrix as fundamental_matrix -------------------------------------------------------------------------------- /TidalPy/utilities/classes/model/__init__.py: -------------------------------------------------------------------------------- 1 | from .model import LayerModelHolder as LayerModelHolder 2 | from .model import ModelHolder as ModelHolder 3 | -------------------------------------------------------------------------------- /Documentation/_static/images/2025-11-28_Logo_2-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jrenaud90/TidalPy/HEAD/Documentation/_static/images/2025-11-28_Logo_2-4.png -------------------------------------------------------------------------------- /Documentation/RadialSolver/Starting Radius Table.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jrenaud90/TidalPy/HEAD/Documentation/RadialSolver/Starting Radius Table.xlsx -------------------------------------------------------------------------------- /Papers/2025-JOSS/figures/bbg/io_rheology_comparison.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jrenaud90/TidalPy/HEAD/Papers/2025-JOSS/figures/bbg/io_rheology_comparison.png -------------------------------------------------------------------------------- /Papers/2025-JOSS/figures/bbg/stacked_images_set_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jrenaud90/TidalPy/HEAD/Papers/2025-JOSS/figures/bbg/stacked_images_set_0.png -------------------------------------------------------------------------------- /Papers/2025-JOSS/figures/wbg/io_rheology_comparison.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jrenaud90/TidalPy/HEAD/Papers/2025-JOSS/figures/wbg/io_rheology_comparison.png -------------------------------------------------------------------------------- /Papers/2025-JOSS/figures/wbg/stacked_images_set_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jrenaud90/TidalPy/HEAD/Papers/2025-JOSS/figures/wbg/stacked_images_set_0.png -------------------------------------------------------------------------------- /TidalPy/Material/eos/methods/__init__.pxd: -------------------------------------------------------------------------------- 1 | from TidalPy.Material.eos.methods.interpolate cimport EOS_INTERPOLATE_METHOD_INT, preeval_interpolate, InterpolateEOSInput -------------------------------------------------------------------------------- /TidalPy/utilities/types_x.pyx: -------------------------------------------------------------------------------- 1 | # distutils: language = c++ 2 | # cython: boundscheck=False, wraparound=False, nonecheck=False, cdivision=True, initializedcheck=False -------------------------------------------------------------------------------- /Papers/2025-JOSS/figures/bbg/dynamic_vs_static_tides.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jrenaud90/TidalPy/HEAD/Papers/2025-JOSS/figures/bbg/dynamic_vs_static_tides.png -------------------------------------------------------------------------------- /Papers/2025-JOSS/figures/wbg/dynamic_vs_static_tides.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jrenaud90/TidalPy/HEAD/Papers/2025-JOSS/figures/wbg/dynamic_vs_static_tides.png -------------------------------------------------------------------------------- /TidalPy/RadialSolver/__init__.pxd: -------------------------------------------------------------------------------- 1 | from TidalPy.RadialSolver.rs_solution cimport RadialSolverSolution 2 | from TidalPy.RadialSolver.solver cimport cf_radial_solver 3 | -------------------------------------------------------------------------------- /Papers/2025-JOSS/figures/bbg/spin_orbit_resonance_ledges.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jrenaud90/TidalPy/HEAD/Papers/2025-JOSS/figures/bbg/spin_orbit_resonance_ledges.png -------------------------------------------------------------------------------- /Papers/2025-JOSS/figures/wbg/spin_orbit_resonance_ledges.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jrenaud90/TidalPy/HEAD/Papers/2025-JOSS/figures/wbg/spin_orbit_resonance_ledges.png -------------------------------------------------------------------------------- /Tests/Test_Old/Test_SetA_Package/test_a_version.py: -------------------------------------------------------------------------------- 1 | def test_version(): 2 | # Test Load 3 | from TidalPy import version 4 | 5 | assert version is not None 6 | -------------------------------------------------------------------------------- /Papers/2025-JOSS/figures/bbg/compressibility_effects_venus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jrenaud90/TidalPy/HEAD/Papers/2025-JOSS/figures/bbg/compressibility_effects_venus.png -------------------------------------------------------------------------------- /Papers/2025-JOSS/figures/wbg/compressibility_effects_venus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jrenaud90/TidalPy/HEAD/Papers/2025-JOSS/figures/wbg/compressibility_effects_venus.png -------------------------------------------------------------------------------- /TidalPy/Material/eos/eos_solution.pyx: -------------------------------------------------------------------------------- 1 | # distutils: language = c++ 2 | # cython: boundscheck=False, wraparound=False, nonecheck=False, cdivision=True, initializedcheck=False 3 | -------------------------------------------------------------------------------- /TidalPy/utilities/arrays/interp.pyx: -------------------------------------------------------------------------------- 1 | # distutils: language = c++ 2 | # cython: boundscheck=False, wraparound=False, nonecheck=False, cdivision=True, initializedcheck=False 3 | -------------------------------------------------------------------------------- /TidalPy/utilities/classes/base_x.pxd: -------------------------------------------------------------------------------- 1 | cdef class TidalPyBaseExtensionClass: 2 | 3 | cdef str name_prefix 4 | cdef public str class_name 5 | cdef bint debug_mode 6 | -------------------------------------------------------------------------------- /Documentation/RadialSolver/4_RadialSolver_Cython_API.md: -------------------------------------------------------------------------------- 1 | # RadialSolver Cython API 2 | TBD: The cython hooks to the radial solver are present and ready for use but not yet documented! -------------------------------------------------------------------------------- /Benchmarks/Performance/tides/Previous Runs/RunTimePlot_0.2.1dev.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jrenaud90/TidalPy/HEAD/Benchmarks/Performance/tides/Previous Runs/RunTimePlot_0.2.1dev.pdf -------------------------------------------------------------------------------- /Tests/Test_RadialSolver/Test_PropMatrix/solid_derivative_matrix.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jrenaud90/TidalPy/HEAD/Tests/Test_RadialSolver/Test_PropMatrix/solid_derivative_matrix.npy -------------------------------------------------------------------------------- /TidalPy/utilities/string_helper/__init__.py: -------------------------------------------------------------------------------- 1 | from .string_helper import convert_time_to_hhmmss as convert_time_to_hhmmss 2 | from .string_helper import timestamped_str as timestamped_str -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Benchmarks/Performance/tides/Previous Runs/RunTimePlot_0.2.1.dev7.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jrenaud90/TidalPy/HEAD/Benchmarks/Performance/tides/Previous Runs/RunTimePlot_0.2.1.dev7.pdf -------------------------------------------------------------------------------- /Papers/2025-JOSS/figures/bbg/trappist1e_2d_heating_15deg_obliquity.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jrenaud90/TidalPy/HEAD/Papers/2025-JOSS/figures/bbg/trappist1e_2d_heating_15deg_obliquity.png -------------------------------------------------------------------------------- /Papers/2025-JOSS/figures/bbg/trappist1e_2d_heating_tidally_locked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jrenaud90/TidalPy/HEAD/Papers/2025-JOSS/figures/bbg/trappist1e_2d_heating_tidally_locked.png -------------------------------------------------------------------------------- /Papers/2025-JOSS/figures/wbg/trappist1e_2d_heating_15deg_obliquity.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jrenaud90/TidalPy/HEAD/Papers/2025-JOSS/figures/wbg/trappist1e_2d_heating_15deg_obliquity.png -------------------------------------------------------------------------------- /Papers/2025-JOSS/figures/wbg/trappist1e_2d_heating_tidally_locked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jrenaud90/TidalPy/HEAD/Papers/2025-JOSS/figures/wbg/trappist1e_2d_heating_tidally_locked.png -------------------------------------------------------------------------------- /Tests/Test_RadialSolver/Test_PropMatrix/solid_derivative_matrix_l3.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jrenaud90/TidalPy/HEAD/Tests/Test_RadialSolver/Test_PropMatrix/solid_derivative_matrix_l3.npy -------------------------------------------------------------------------------- /Tests/Test_RadialSolver/Test_PropMatrix/solid_fundamental_matrix.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jrenaud90/TidalPy/HEAD/Tests/Test_RadialSolver/Test_PropMatrix/solid_fundamental_matrix.npy -------------------------------------------------------------------------------- /TidalPy/tides/modes/__init__.py: -------------------------------------------------------------------------------- 1 | from .modes import find_unique_frequency_list as find_unique_frequency_list 2 | from .modes import find_unique_frequency_dict as find_unique_frequency_dict 3 | -------------------------------------------------------------------------------- /Benchmarks/Performance/tides/Previous Runs/CompileTimePlot_0.2.1dev.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jrenaud90/TidalPy/HEAD/Benchmarks/Performance/tides/Previous Runs/CompileTimePlot_0.2.1dev.pdf -------------------------------------------------------------------------------- /Tests/Test_RadialSolver/Test_PropMatrix/solid_fundamental_matrix_l3.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jrenaud90/TidalPy/HEAD/Tests/Test_RadialSolver/Test_PropMatrix/solid_fundamental_matrix_l3.npy -------------------------------------------------------------------------------- /Benchmarks/Performance/tides/Previous Runs/CompileTimePlot_0.2.1.dev7.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jrenaud90/TidalPy/HEAD/Benchmarks/Performance/tides/Previous Runs/CompileTimePlot_0.2.1.dev7.pdf -------------------------------------------------------------------------------- /TidalPy/tides/methods/__init__.py: -------------------------------------------------------------------------------- 1 | from .base import TidesBase as TidesBase 2 | from .global_approx import GlobalApproxTides as GlobalApproxTides 3 | from .layered import LayeredTides as LayeredTides 4 | -------------------------------------------------------------------------------- /Tests/Test_RadialSolver/Test_PropMatrix/solid_inverse_fundamental_matrix.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jrenaud90/TidalPy/HEAD/Tests/Test_RadialSolver/Test_PropMatrix/solid_inverse_fundamental_matrix.npy -------------------------------------------------------------------------------- /TidalPy/toolbox/__init__.py: -------------------------------------------------------------------------------- 1 | from .quick_tides import quick_dual_body_tidal_dissipation as quick_dual_body_tidal_dissipation 2 | from .quick_tides import quick_tidal_dissipation as quick_tidal_dissipation 3 | -------------------------------------------------------------------------------- /Papers/2025-JOSS/figures/bbg/trappist1e_2d_heating_2-1_sor_15deg_obliquity.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jrenaud90/TidalPy/HEAD/Papers/2025-JOSS/figures/bbg/trappist1e_2d_heating_2-1_sor_15deg_obliquity.png -------------------------------------------------------------------------------- /Papers/2025-JOSS/figures/bbg/trappist1e_2d_heating_2-1_spin-orbit_resonance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jrenaud90/TidalPy/HEAD/Papers/2025-JOSS/figures/bbg/trappist1e_2d_heating_2-1_spin-orbit_resonance.png -------------------------------------------------------------------------------- /Papers/2025-JOSS/figures/bbg/trappist1e_2d_heating_3-2_sor_15deg_obliquity.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jrenaud90/TidalPy/HEAD/Papers/2025-JOSS/figures/bbg/trappist1e_2d_heating_3-2_sor_15deg_obliquity.png -------------------------------------------------------------------------------- /Papers/2025-JOSS/figures/bbg/trappist1e_2d_heating_3-2_spin-orbit_resonance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jrenaud90/TidalPy/HEAD/Papers/2025-JOSS/figures/bbg/trappist1e_2d_heating_3-2_spin-orbit_resonance.png -------------------------------------------------------------------------------- /Papers/2025-JOSS/figures/wbg/trappist1e_2d_heating_2-1_sor_15deg_obliquity.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jrenaud90/TidalPy/HEAD/Papers/2025-JOSS/figures/wbg/trappist1e_2d_heating_2-1_sor_15deg_obliquity.png -------------------------------------------------------------------------------- /Papers/2025-JOSS/figures/wbg/trappist1e_2d_heating_2-1_spin-orbit_resonance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jrenaud90/TidalPy/HEAD/Papers/2025-JOSS/figures/wbg/trappist1e_2d_heating_2-1_spin-orbit_resonance.png -------------------------------------------------------------------------------- /Papers/2025-JOSS/figures/wbg/trappist1e_2d_heating_3-2_sor_15deg_obliquity.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jrenaud90/TidalPy/HEAD/Papers/2025-JOSS/figures/wbg/trappist1e_2d_heating_3-2_sor_15deg_obliquity.png -------------------------------------------------------------------------------- /Papers/2025-JOSS/figures/wbg/trappist1e_2d_heating_3-2_spin-orbit_resonance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jrenaud90/TidalPy/HEAD/Papers/2025-JOSS/figures/wbg/trappist1e_2d_heating_3-2_spin-orbit_resonance.png -------------------------------------------------------------------------------- /Tests/Test_RadialSolver/Test_PropMatrix/solid_inverse_fundamental_matrix_l3.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jrenaud90/TidalPy/HEAD/Tests/Test_RadialSolver/Test_PropMatrix/solid_inverse_fundamental_matrix_l3.npy -------------------------------------------------------------------------------- /TidalPy/utilities/math/numerics.pxd: -------------------------------------------------------------------------------- 1 | from libcpp cimport bool as cpp_bool 2 | 3 | cdef cpp_bool cf_isclose( 4 | double a, 5 | double b, 6 | double rtol = *, 7 | double atol = * 8 | ) noexcept nogil -------------------------------------------------------------------------------- /TidalPy/utilities/classes/config/__init__.py: -------------------------------------------------------------------------------- 1 | from .config import ConfigHolder as ConfigHolder 2 | from .config import WorldConfigHolder as WorldConfigHolder 3 | from .config import LayerConfigHolder as LayerConfigHolder 4 | -------------------------------------------------------------------------------- /TidalPy/RadialSolver/love.pxd: -------------------------------------------------------------------------------- 1 | cdef extern from "love_.cpp" nogil: 2 | 3 | void find_love_cf( 4 | double* complex_love_numbers_ptr, 5 | double* surface_solutions_ptr, 6 | double surface_gravity) 7 | -------------------------------------------------------------------------------- /TidalPy/WorldPack/55cnc.toml: -------------------------------------------------------------------------------- 1 | name = "55-Cancri" 2 | type = "star" 3 | radius = 667900000.0 4 | mass = 1.91e+30 5 | luminosity = 2.266e+26 6 | tides_on = false 7 | 8 | [tides] 9 | model = "global_approx" 10 | fixed_q = 100.0 11 | -------------------------------------------------------------------------------- /TidalPy/WorldPack/sol.toml: -------------------------------------------------------------------------------- 1 | name = "Sol" 2 | type = "star" 3 | radius = 695700000.0 4 | mass = 1.988435e+30 5 | luminosity = 3.848e+26 6 | tides_on = false 7 | 8 | [tides] 9 | model = "global_approx" 10 | fixed_q = 100.0 11 | -------------------------------------------------------------------------------- /TidalPy/numba_scipy/__init__.py: -------------------------------------------------------------------------------- 1 | def _init_extension(): 2 | '''Register SciPy functions with Numba. 3 | 4 | This entry_point is called by Numba when it initializes. 5 | ''' 6 | 7 | from . import special as special 8 | -------------------------------------------------------------------------------- /TidalPy/structures/world_builder/__init__.py: -------------------------------------------------------------------------------- 1 | from .world_builder import build_from_world as build_from_world 2 | from .world_builder import build_world as build_world 3 | from .world_builder import scale_from_world as scale_from_world 4 | -------------------------------------------------------------------------------- /TidalPy/utilities/numpy_helper/__init__.py: -------------------------------------------------------------------------------- 1 | from .array_other import find_nearest as find_nearest 2 | from .array_other import neg_array_for_log_plot as neg_array_for_log_plot 3 | from .array_shape import reshape_help as reshape_help 4 | -------------------------------------------------------------------------------- /Documentation/API/index.md: -------------------------------------------------------------------------------- 1 | # TidalPy API Reference 2 | 3 | This API reference manual is autogenerated from docstrings in the code. 4 | 5 | ```{autosummary} 6 | :toctree: generated 7 | :recursive: 8 | 9 | TidalPy 10 | ``` -------------------------------------------------------------------------------- /TidalPy/RadialSolver/starting/saito.pxd: -------------------------------------------------------------------------------- 1 | cdef void cf_saito_liquid_static_incompressible( 2 | double radius, 3 | int degree_l, 4 | size_t num_ys, 5 | double complex* starting_conditions_ptr 6 | ) noexcept nogil 7 | -------------------------------------------------------------------------------- /TidalPy/structures/__init__.py: -------------------------------------------------------------------------------- 1 | from .physical import PhysicalObjSpherical 2 | 3 | # Physical must be imported before the following are imported. 4 | from .orbit import PhysicsOrbit as Orbit 5 | from .world_builder import build_from_world, build_world, scale_from_world 6 | -------------------------------------------------------------------------------- /TidalPy/structures/orbit/__init__.py: -------------------------------------------------------------------------------- 1 | from .base import OrbitBase as OrbitBase 2 | from .physics import PhysicsOrbit as PhysicsOrbit 3 | 4 | # User will almost always want the Physics version of the orbit, so it is aliased as just `Orbit` here 5 | Orbit = PhysicsOrbit 6 | -------------------------------------------------------------------------------- /TidalPy/WorldPack/neptune.toml: -------------------------------------------------------------------------------- 1 | name = "Neptune" 2 | type = "gas_giant" 3 | radius = 24622000.0 4 | mass = 1.02413e+26 5 | semi_major_axis = 30.07 6 | semi_major_axis_in_au = true 7 | eccentricity = 0.008678 8 | tides_on = true 9 | 10 | [tides] 11 | fixed_q = 9000.0 12 | -------------------------------------------------------------------------------- /TidalPy/numba_scipy/TODO_DeletePackage.md: -------------------------------------------------------------------------------- 1 | # TODO: Right now numba-scipy is limiting the scipy version (<1.7.0) allowed. Once that has been updated then remove 2 | # these files in favor of using the third party package. 3 | # See: https://github.com/numba/numba-scipy/pull/90 4 | -------------------------------------------------------------------------------- /TidalPy/RadialSolver/love_.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | void find_love_cf( 5 | double* complex_love_numbers_ptr, // These are double pointers that pointer to a double complex array. 6 | double* surface_solutions_ptr, // Same as above 7 | double surface_gravity); 8 | -------------------------------------------------------------------------------- /TidalPy/WorldPack/jupiter.toml: -------------------------------------------------------------------------------- 1 | name = "Jupiter" 2 | type = "gas_giant" 3 | radius = 69911000.0 4 | mass = 1.898e+27 5 | semi_major_axis = 5.20336301 6 | semi_major_axis_in_au = true 7 | eccentricity = 0.04839266 8 | tides_on = false 9 | 10 | [tides] 11 | fixed_q = 8000.0 12 | -------------------------------------------------------------------------------- /TidalPy/RadialSolver/boundaries/surface_bc.pxd: -------------------------------------------------------------------------------- 1 | cdef int cf_get_surface_bc( 2 | double* boundary_conditions_ptr, 3 | int* bc_model_ptr, 4 | size_t num_bcs, 5 | double radius_to_use, 6 | double bulk_density_to_use, 7 | double degree_l_dbl, 8 | ) noexcept nogil 9 | -------------------------------------------------------------------------------- /TidalPy/utilities/spherical_helper/__init__.py: -------------------------------------------------------------------------------- 1 | from .volume import calculate_voxel_volumes as calculate_voxel_volumes 2 | from .volume import calculate_voxel_volumes_npy as calculate_voxel_volumes_npy 3 | 4 | from .mass import calculate_mass_gravity_arrays as calculate_mass_gravity_arrays -------------------------------------------------------------------------------- /TidalPy/Extending/burnman/defaults.py: -------------------------------------------------------------------------------- 1 | default_burnman_layer_params = { 2 | 'material_source' : None, 3 | 'temperature_mode' : 'adiabatic', 4 | 'fixed_temperature' : None, 5 | 'top_temperature' : None, 6 | 'interp_lookup_method': 'mid', 7 | 'slices' : 50 8 | } 9 | -------------------------------------------------------------------------------- /TidalPy/orbit/__init__.py: -------------------------------------------------------------------------------- 1 | from .averaging import orbit_average as orbit_average 2 | from .averaging import orbit_average_3d as orbit_average_3d 3 | from .averaging import orbit_average_3d_multiarray as orbit_average_3d_multiarray 4 | from .averaging import orbit_average_4d_multiarray as orbit_average_4d_multiarray 5 | -------------------------------------------------------------------------------- /TidalPy/RadialSolver/__init__.py: -------------------------------------------------------------------------------- 1 | from TidalPy.RadialSolver.solver import radial_solver as radial_solver 2 | 3 | from TidalPy.RadialSolver.helpers import build_rs_input_homogeneous_layers as build_rs_input_homogeneous_layers 4 | from TidalPy.RadialSolver.helpers import build_rs_input_from_data as build_rs_input_from_data 5 | -------------------------------------------------------------------------------- /TidalPy/RadialSolver/constants.pyx: -------------------------------------------------------------------------------- 1 | # distutils: language = c++ 2 | # cython: boundscheck=False, wraparound=False, nonecheck=False, cdivision=True, initializedcheck=False 3 | 4 | # Maximum size for array building 5 | cdef size_t MAX_NUM_Y = 6 6 | cdef size_t MAX_NUM_Y_REAL = 2 * MAX_NUM_Y 7 | cdef size_t MAX_NUM_SOL = 3 8 | -------------------------------------------------------------------------------- /readthedocs.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | build: 4 | os: "ubuntu-lts-latest" 5 | tools: 6 | python: "3.12" 7 | 8 | jobs: 9 | pre_build: 10 | - doxygen DoxyFile 11 | 12 | sphinx: 13 | configuration: Documentation/conf.py 14 | 15 | python: 16 | install: 17 | - method: pip 18 | path: .[docs] -------------------------------------------------------------------------------- /TidalPy/WorldPack/trappist1.toml: -------------------------------------------------------------------------------- 1 | # From Delrez+2018 and Kane2018 2 | # Updated using Agol+2020, Mass from Mann+2019, Luminosity from Ducrot+2020 3 | 4 | name = "TRAPPIST-1" 5 | type = "star" 6 | radius = 82927000.0 7 | mass = 1.786e+29 8 | luminosity = 2.11799e+23 9 | tides_on = false 10 | 11 | [tides] 12 | model = "global_approx" 13 | fixed_q = 5000.0 14 | -------------------------------------------------------------------------------- /TidalPy/RadialSolver/starting/common.pxd: -------------------------------------------------------------------------------- 1 | cdef double complex cf_z_calc( 2 | double complex x_squared, 3 | int degree_l 4 | ) noexcept nogil 5 | 6 | cdef void cf_takeuchi_phi_psi( 7 | double complex z, 8 | int degree_l, 9 | double complex* phi_ptr, 10 | double complex* phi_lplus1_ptr, 11 | double complex* psi_ptr, 12 | ) noexcept nogil -------------------------------------------------------------------------------- /TidalPy/utilities/dimensions/nondimensional_.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class NonDimensionalScalesCC 4 | { 5 | public: 6 | double second2_conversion; 7 | double second_conversion; 8 | double length_conversion; 9 | double length3_conversion; 10 | double density_conversion; 11 | double mass_conversion; 12 | double pascal_conversion; 13 | }; 14 | -------------------------------------------------------------------------------- /TidalPy/utilities/classes/__init__.py: -------------------------------------------------------------------------------- 1 | from .base import TidalPyClass as TidalPyClass 2 | 3 | from .config import ConfigHolder as ConfigHolder 4 | from .config import LayerConfigHolder as LayerConfigHolder 5 | from .config import WorldConfigHolder as WorldConfigHolder 6 | 7 | from .model import LayerModelHolder as LayerModelHolder 8 | from .model import ModelHolder as ModelHolder 9 | -------------------------------------------------------------------------------- /Documentation/Overview/index.md: -------------------------------------------------------------------------------- 1 | # Overview 2 | 3 | ```{toctree} 4 | :maxdepth: 2 5 | :caption: Contents 6 | 7 | General <0_Readme.md> 8 | Getting Started <1_Getting_Started.md> 9 | Configurations <2_TidalPy_Configurations.md> 10 | Contributing 11 | Code of Conduct 12 | License 13 | Additional License Notice 14 | ``` -------------------------------------------------------------------------------- /TidalPy/utilities/classes/base.py: -------------------------------------------------------------------------------- 1 | from TidalPy import version 2 | 3 | 4 | class TidalPyClass: 5 | """ All functional methods used in TidalPy inherit from this base class. 6 | 7 | Class Attributes 8 | ---------------- 9 | tidalpy_version : str 10 | Stores the TidalPy version text at the time of import 11 | 12 | """ 13 | 14 | tidalpy_version = version 15 | -------------------------------------------------------------------------------- /TidalPy/tides/ctl_funcs/__init__.py: -------------------------------------------------------------------------------- 1 | from .ctl_funcs import linear_dt, linear_dt_with_q 2 | 3 | known_ctl_methods = { 4 | 'linear_simple' : linear_dt, 5 | 'linear_simple_with_q': linear_dt_with_q 6 | } 7 | 8 | ctl_method_input_getters = { 9 | 'linear_simple' : (('tides', 'fixed_dt'),), 10 | 'linear_simple_with_q': (('tides', 'fixed_dt'), ('tides', 'fixed_q')) 11 | } 12 | -------------------------------------------------------------------------------- /TidalPy/Material/eos/__init__.pxd: -------------------------------------------------------------------------------- 1 | # Common functions and structures 2 | from TidalPy.Material.eos.eos_solution cimport EOSSolutionCC 3 | from TidalPy.Material.eos.ode cimport EOS_ODEInput, eos_diffeq 4 | from TidalPy.Material.eos.solver cimport solve_eos 5 | 6 | # Specific EOS functions and structures 7 | # Interpolate 8 | from TidalPy.Material.eos.methods.interpolate cimport InterpolateEOSInput, preeval_interpolate 9 | -------------------------------------------------------------------------------- /Tests/Test_Math/test_utilities_special.py: -------------------------------------------------------------------------------- 1 | from math import isclose 2 | from scipy.special import factorial2 3 | 4 | import pytest 5 | 6 | from TidalPy.utilities.math.special import double_factorial 7 | 8 | @pytest.mark.parametrize('l', (0, 2, 3, 4, 5, 10, 20, 100)) 9 | def test_double_factorial(l): 10 | 11 | tpy_value = double_factorial(l) 12 | ref_value = factorial2(l) 13 | 14 | assert isclose(tpy_value, ref_value) 15 | -------------------------------------------------------------------------------- /TidalPy/WorldPack/triton_simple.toml: -------------------------------------------------------------------------------- 1 | name = "Triton_Simple" 2 | type = "simple_tidal" 3 | radius = 1353000.0 4 | mass = 2.139e+22 5 | semi_major_axis = 354760000.0 6 | semi_major_axis_in_au = false 7 | eccentricity = 1.6e-5 8 | spin_period = -5.876854 9 | albedo = 0.55 10 | force_spin_sync = false 11 | 12 | [tides] 13 | use_ctl = false 14 | ctl_calc_method = "linear_simple_with_q" 15 | fixed_q = 100.0 16 | static_k2 = 0.1 17 | fixed_dt = 507800.0 18 | -------------------------------------------------------------------------------- /TidalPy/utilities/math/__init__.pxd: -------------------------------------------------------------------------------- 1 | from TidalPy.utilities.math.complex cimport ( 2 | cmplx_NAN, cmplx_zero, SQRT2, LOGE2, SQRT2_INV, THRESH, DBL_MAX_4, 3 | SCALED_CEXP_K_F, SCALED_CEXP_K_D, SCALED_CEXP_K_LD, SCALED_K_LOGE2_D, SCALED_CEXP_LOWERF, SCALED_CEXP_UPPERF, 4 | SCALED_CEXP_LOWER, SCALED_CEXP_UPPER, SCALED_CEXP_LOWERL, SCALED_CEXP_UPPERL, 5 | cf_build_dblcmplx, cf_cinv, cf_hypot, cf_csqrt, cf_scaled_cexp, cf_cexp, cf_clog, cf_cpow, cf_cipow) 6 | -------------------------------------------------------------------------------- /Documentation/Dynamics/1_Dynamics.md: -------------------------------------------------------------------------------- 1 | # TidalPy Dynamics 2 | 3 | TidalPy's dynamics API is currently undergoing changes, this documentation will be updated once it is complete. For the 4 | time being please take a look at the autogenerated API documentation. 5 | 6 | As of TidalPy v0.7.0, the dynamics functionality is spread between `TidalPy.dynamics` and `TidalPy.tides` modules. This 7 | will be refactored into a new `TidalPy.Dynamics` module (with a capital). 8 | -------------------------------------------------------------------------------- /TidalPy/Extending/__init__.py: -------------------------------------------------------------------------------- 1 | extended_configs = dict() 2 | 3 | from TidalPy.utilities.dictionary_utils import nested_merge 4 | from TidalPy.Extending.burnman import burnman_installed 5 | 6 | # Add any extension configs to the extended config dict which will be added to the tidalpy configs 7 | if burnman_installed: 8 | from TidalPy.Extending.burnman.burnman_defaultc import default_burnman_configs 9 | extended_configs = nested_merge(extended_configs, default_burnman_configs) -------------------------------------------------------------------------------- /TidalPy/WorldPack/io_simple.toml: -------------------------------------------------------------------------------- 1 | name = "Io_Simple" 2 | type = "layered" 3 | radius = 1821490.0 4 | orbital_period = 1.769 5 | eccentricity = 0.0041 6 | spin_period = 1.769 7 | albedo = 0.63 8 | force_spin_sync = true 9 | 10 | [layers.Core] 11 | type = "iron" 12 | is_tidal = false 13 | radius = 810000.0 14 | density = 5200.0 15 | 16 | [layers.Mantle] 17 | type = "rock" 18 | is_tidal = true 19 | radius = 1821490.0 20 | surface_temperature = 100.0 21 | density = 3200.0 22 | -------------------------------------------------------------------------------- /TidalPy/WorldPack/nereid_dev.toml: -------------------------------------------------------------------------------- 1 | name = "Nereid" 2 | type = "layered" 3 | radius = 180000.0 4 | mass = 3.1e+19 5 | semi_major_axis = 5513940000.0 6 | semi_major_axis_in_au = false 7 | eccentricity = 0.7417482 8 | spin_period = 0.48308333333 9 | albedo = 0.24 10 | force_spin_sync = false 11 | 12 | [layers.Core] 13 | type = "rock" 14 | is_tidal = true 15 | density_bulk = 1500.0 16 | radius = 180000.0 17 | 18 | [layers.Core.rheology.complex_compliance] 19 | model = "sundberg" 20 | -------------------------------------------------------------------------------- /TidalPy/structures/layers/__init__.py: -------------------------------------------------------------------------------- 1 | from typing import Union 2 | 3 | from .basic import LayerBase 4 | from .gas import GasLayer 5 | from .physics import PhysicsLayer 6 | 7 | LayerType = Union[PhysicsLayer, LayerBase, GasLayer] 8 | PhysicalLayerType = PhysicsLayer 9 | 10 | known_layer_classes = { 11 | 'gas' : GasLayer, 12 | 'physics': PhysicsLayer 13 | } 14 | 15 | layers_class_by_world_class = { 16 | 'layered' : PhysicsLayer, 17 | 'gas_giant_layered': GasLayer, 18 | } 19 | -------------------------------------------------------------------------------- /TidalPy/Extending/burnman/material/custom/__init__.py: -------------------------------------------------------------------------------- 1 | from .ice import LowPressureIceConst as LowPressureIceConst 2 | from .ice import HighPressureIceConst as HighPressureIceConst 3 | from .ice import UnterbornIce as UnterbornIce 4 | from .ice import Water as Water 5 | from .ice import HighPressureIce as HighPressureIce 6 | from .ice import IceX_Fu2010 as IceX_Fu2010 7 | from .ice import IceVII_Fu2010 as IceVII_Fu2010 8 | from .ice import IceIh_Fu2010 as IceIh_Fu2010 9 | 10 | from .pyrite import Pyrite as Pyrite 11 | -------------------------------------------------------------------------------- /Tests/Test_Old/Test_SetA_Package/test_tidalpy_config.py: -------------------------------------------------------------------------------- 1 | from TidalPy import config 2 | 3 | 4 | def test_load_configs(): 5 | # Load configurations and make sure they have all the needed parameters 6 | assert type(config) == dict 7 | 8 | config_headers = [ 9 | 'pathing', 10 | 'debug', 11 | 'logging', 12 | 'configs', 13 | 'numba', 14 | 'worlds', 15 | 'tides' 16 | ] 17 | 18 | for header in config_headers: 19 | assert header in config 20 | -------------------------------------------------------------------------------- /TidalPy/radiogenics/__init__.py: -------------------------------------------------------------------------------- 1 | from TidalPy.utilities.classes.model.model_utils import build_model_default_inputs, find_all_models 2 | 3 | from . import radiogenic_models 4 | 5 | known_models, known_model_const_args, known_model_live_args = find_all_models(radiogenic_models) 6 | 7 | 8 | def get_radiogenic_model_default_inputs(layer_type: str): 9 | return build_model_default_inputs(known_model_const_args, radiogenic_models, inner_keys=layer_type) 10 | 11 | from .radiogenics import Radiogenics as Radiogenics 12 | -------------------------------------------------------------------------------- /Documentation/Style Templates/docstring - module.txt: -------------------------------------------------------------------------------- 1 | """Docstring for the example.py module. 2 | 3 | Modules names should have short, all-lowercase names. The module name may 4 | have underscores if this improves readability. 5 | 6 | Every module should have a docstring at the very top of the file. The 7 | module's docstring may extend over multiple lines. If your docstring does 8 | extend over multiple lines, the closing three quotation marks must be on 9 | a line by itself, preferably preceded by a blank line. 10 | 11 | """ -------------------------------------------------------------------------------- /TidalPy/utilities/conversions/__init__.py: -------------------------------------------------------------------------------- 1 | from .conversions import days2rads as days2rads 2 | from .conversions import rads2days as rads2days 3 | from .conversions import Au2m as Au2m 4 | from .conversions import m2Au as m2Au 5 | from .conversions import orbital_motion2semi_a as orbital_motion2semi_a 6 | from .conversions import semi_a2orbital_motion as semi_a2orbital_motion 7 | from .conversions import myr2sec as myr2sec 8 | from .conversions import sec2myr as sec2myr 9 | 10 | from .timing import convert_to_hms as convert_to_hms -------------------------------------------------------------------------------- /TidalPy/RadialSolver/matrix_types/solid_matrix.pxd: -------------------------------------------------------------------------------- 1 | cdef void cf_fundamental_matrix( 2 | Py_ssize_t first_slice_index, 3 | Py_ssize_t num_radial_slices, 4 | double* radius_array_ptr, 5 | double* density_array_ptr, 6 | double* gravity_array_ptr, 7 | double complex* complex_shear_array_ptr, 8 | double complex* fundamental_mtx_ptr, 9 | double complex* inverse_fundamental_mtx_ptr, 10 | double complex* derivative_mtx_ptr, 11 | int degree_l = *, 12 | double G_to_use = * 13 | ) noexcept nogil 14 | -------------------------------------------------------------------------------- /TidalPy/RadialSolver/boundaries/boundaries.pxd: -------------------------------------------------------------------------------- 1 | from libcpp cimport bool as cpp_bool 2 | 3 | 4 | cdef void cf_apply_surface_bc( 5 | double complex* constant_vector_ptr, 6 | int* bc_solution_info, 7 | double* bc_pointer, 8 | double complex* uppermost_y_per_solution_ptr, 9 | double surface_gravity, 10 | double G_to_use, 11 | size_t num_sols, 12 | size_t max_num_y, 13 | size_t ytype_i, 14 | int layer_type, 15 | cpp_bool layer_is_static, 16 | cpp_bool layer_is_incomp 17 | ) noexcept nogil 18 | -------------------------------------------------------------------------------- /TidalPy/Extending/burnman/__init__.py: -------------------------------------------------------------------------------- 1 | from .package import burnman as burnman 2 | from .package import Material as Material 3 | from .package import Mineral as Mineral 4 | from .package import material_property as material_property 5 | from .package import dictionarize_formula as dictionarize_formula 6 | from .package import formula_mass as formula_mass 7 | from .package import burnman_installed as burnman_installed 8 | 9 | from .build import build_burnman_world as build_burnman_world 10 | from .burnman_world import BurnManWorld as BurnManWorld 11 | -------------------------------------------------------------------------------- /Documentation/Rheology/index.md: -------------------------------------------------------------------------------- 1 | # TidalPy.Rheology Documentation 2 | 3 | **TidalPy's Rheology Module** 4 | 5 | [Auto Generated API](https://tidalpy.readthedocs.io/en/latest/API/generated/TidalPy.rheology.html) 6 | 7 | TidalPy's Rheology Module handles converting from static viscosities and moduli to a complex moduli based on a 8 | the requested rheology. These complex moduli can then be used to find Love numbers. 9 | found below. 10 | 11 | ```{toctree} 12 | :maxdepth: 2 13 | :caption: Contents 14 | 15 | Rheology <1_Rheology.md> 16 | ``` -------------------------------------------------------------------------------- /Documentation/Dynamics/index.md: -------------------------------------------------------------------------------- 1 | # TidalPy.Dynamics Documentation 2 | 3 | **TidalPy's Dynamics Module** 4 | 5 | [Auto Generated API](https://tidalpy.readthedocs.io/en/latest/API/generated/TidalPy.dynamics.html) 6 | 7 | TidalPy's Dynamics Module contains functionality to determine dominate tidal forcing modes (determined from the world's 8 | orbit and rotation) and how these modes translate to dissipation within both the target world and host. 9 | 10 | ```{toctree} 11 | :maxdepth: 2 12 | :caption: Contents 13 | 14 | Dynamics <1_Dynamics.md> 15 | ``` -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | # TidalPy - Additional License Notice 2 | _Copyright 2025 Joe P. Renaud_ 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0) 9 | 10 | This product includes software developed as part of the TidalPy project. 11 | 12 | **If used in published research, please cite the project as described in the citation.cff file.** 13 | -------------------------------------------------------------------------------- /TidalPy/utilities/graphics/__init__.py: -------------------------------------------------------------------------------- 1 | # Cartopy is usually not installed during testing which is fine. But this module will throw an error when tests are run 2 | # and Cartopy is not installed. So check if it is installed before bringing these packages up. 3 | import importlib.util 4 | 5 | from .grid_plot import GridPlot as GridPlot 6 | from .planet_plot import planet_plot as planet_plot 7 | 8 | if importlib.util.find_spec('cartopy') is not None: 9 | spec = importlib.util.find_spec('cartopy') 10 | from .global_map import projection_map as projection_map 11 | -------------------------------------------------------------------------------- /TidalPy/Extending/burnman/conversion.py: -------------------------------------------------------------------------------- 1 | """ Common conversions between TidalPy and BurnMan """ 2 | 3 | burnman_property_name_conversion = { 4 | 'thermal_expansion': 'thermal_expansivity', 5 | # 'grueneisen': 'grueneisen_parameter', # FIXME: remove the comment here once ice EOS in place. 6 | 'bulk_modulus' : 'isothermal_bulk_modulus_reuss', 7 | 'specific_heat' : 'molar_heat_capacity_p', 8 | } 9 | 10 | burnman_property_value_conversion = { 11 | # Need to change BurnMan's molar heat capacity to specific 12 | 'specific_heat': 'molar' 13 | } 14 | -------------------------------------------------------------------------------- /TidalPy/tides/multilayer/heating.pxd: -------------------------------------------------------------------------------- 1 | 2 | cdef void cf_calc_radial_volumetric_tidal_heating( 3 | double* volumetric_tidal_heating_arr_ptr, 4 | size_t total_slices, 5 | double eccentricity, 6 | double orbital_frequency, 7 | double semi_major_axis, 8 | double host_mass, 9 | double* radius_arr_ptr, 10 | double* radial_sensitivity_to_shear_arr_ptr, 11 | double complex* complex_shear_modulus_arr_ptr, 12 | double* radial_sensitivity_to_bulk_arr_ptr, 13 | double complex* complex_bulk_modulus_arr_ptr, 14 | int degree_l, 15 | double G_to_use 16 | ) noexcept nogil 17 | -------------------------------------------------------------------------------- /TidalPy/utilities/dimensions/nondimensional.pxd: -------------------------------------------------------------------------------- 1 | 2 | cdef extern from "nondimensional_.hpp" nogil: 3 | cdef cppclass NonDimensionalScalesCC: 4 | double second2_conversion 5 | double second_conversion 6 | double length_conversion 7 | double length3_conversion 8 | double density_conversion 9 | double mass_conversion 10 | double pascal_conversion 11 | 12 | 13 | cdef void cf_build_nondimensional_scales( 14 | NonDimensionalScalesCC* non_dim_scales_ptr, 15 | double frequency, 16 | double mean_radius, 17 | double bulk_density 18 | ) noexcept nogil 19 | -------------------------------------------------------------------------------- /TidalPy/Material/eos/ode.pxd: -------------------------------------------------------------------------------- 1 | from libcpp cimport bool as cpp_bool 2 | 3 | from CyRK cimport PreEvalFunc 4 | 5 | cdef struct EOSOutput: 6 | double density 7 | double complex bulk_modulus 8 | double complex shear_modulus 9 | 10 | cdef struct EOS_ODEInput: 11 | double G_to_use 12 | double planet_radius 13 | char* eos_input_ptr 14 | cpp_bool final_solve 15 | cpp_bool update_bulk 16 | cpp_bool update_shear 17 | 18 | cdef void eos_diffeq( 19 | double* dy_ptr, 20 | double radius, 21 | double* y_ptr, 22 | char* input_args, 23 | PreEvalFunc eos_function) noexcept nogil 24 | 25 | -------------------------------------------------------------------------------- /TidalPy/rheology/__init__.py: -------------------------------------------------------------------------------- 1 | # Rheology Imports 2 | from .rheology import Rheology as Rheology 3 | 4 | from TidalPy.rheology.models import find_rheology as find_rheology 5 | from TidalPy.rheology.models import Elastic as Elastic 6 | from TidalPy.rheology.models import Newton as Newton 7 | from TidalPy.rheology.models import Maxwell as Maxwell 8 | from TidalPy.rheology.models import Voigt as Voigt 9 | from TidalPy.rheology.models import Burgers as Burgers 10 | from TidalPy.rheology.models import Andrade as Andrade 11 | from TidalPy.rheology.models import SundbergCooper as SundbergCooper 12 | 13 | # Alias rheologies 14 | Sundberg = SundbergCooper 15 | -------------------------------------------------------------------------------- /TidalPy/WorldPack/55cnce_simple.toml: -------------------------------------------------------------------------------- 1 | # Very roughly pulled from some analysis by Dorn+ (A&A 2017) 2 | 3 | name = "55-Cancri-e" 4 | type = "layered" 5 | radius = 11950000.0 6 | semi_major_axis = 0.01544 7 | semi_major_axis_in_au = true 8 | eccentricity = 0.02 9 | spin_period = 1.0 10 | force_spin_sync = true 11 | 12 | [layers.Core] 13 | type = "iron" 14 | is_tidal = false 15 | radius = 4000000.0 16 | density = 14000.0 17 | 18 | [layers.Lower_Mantle] 19 | type = "rock" 20 | is_tidal = false 21 | radius = 8959000.0 22 | density = 5000.0 23 | 24 | [layers.Upper_Mantle] 25 | type = "rock" 26 | is_tidal = true 27 | radius = 11950000.0 28 | density = 3300.0 29 | -------------------------------------------------------------------------------- /Documentation/RadialSolver/index.md: -------------------------------------------------------------------------------- 1 | # TidalPy.RadialSolver Documentation 2 | 3 | **Welcome to the RadialSolver's documentation!** 4 | 5 | [Auto Generated API](https://tidalpy.readthedocs.io/en/latest/API/generated/TidalPy.RadialSolver.html) 6 | 7 | TidalPy's RadialSolver Module handles calculating Love numbers for planets. Details about how to use it can be 8 | found below. 9 | 10 | ```{toctree} 11 | :maxdepth: 2 12 | :caption: Contents 13 | 14 | Calculating Love Numbers <1_Calculating_Love_Numbers.md> 15 | Solution Class <2_RadialSolver_Solution_Class.md> 16 | Helper Functions <3_RadialSolver_Helpers.md> 17 | Cython API <4_RadialSolver_Cython_API.md> 18 | ``` -------------------------------------------------------------------------------- /Tests/Test_Old/Test_SetS_Tides/Test_Heating/test_heating.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | import numpy as np 4 | 5 | 6 | def test_volumetric_heating(): 7 | """ Test the volumetric heating function. """ 8 | 9 | # Ensure imports work 10 | from TidalPy.tides import calculate_volumetric_heating 11 | 12 | stress = (10. + 0.1j) * np.ones((6, 10, 12), dtype=np.complex128) 13 | strain = (5. - 0.1j) * np.ones((6, 10, 12), dtype=np.complex128) 14 | 15 | volumetric_heating = calculate_volumetric_heating(stress, strain) 16 | 17 | assert volumetric_heating.shape == (10, 12) 18 | assert volumetric_heating.dtype == np.float64 19 | assert np.all(volumetric_heating >= 0.) 20 | -------------------------------------------------------------------------------- /TidalPy/tides/multilayer/__init__.py: -------------------------------------------------------------------------------- 1 | from .displacements import calculate_displacements as calculate_displacements 2 | from TidalPy.tides.multilayer.heating import calc_radial_volumetric_tidal_heating_from_rs_solution as calc_radial_volumetric_tidal_heating_from_rs_solution 3 | from TidalPy.tides.multilayer.heating import calc_radial_volumetric_tidal_heating as calc_radial_volumetric_tidal_heating 4 | 5 | from .stress_strain import calculate_strain_stress as calculate_strain_stress 6 | from TidalPy.tides.multilayer.sensitivity import calc_sensitivity_to_bulk as calc_sensitivity_to_bulk 7 | from TidalPy.tides.multilayer.sensitivity import calc_sensitivity_to_shear as calc_sensitivity_to_shear -------------------------------------------------------------------------------- /TidalPy/RadialSolver/starting/driver.pxd: -------------------------------------------------------------------------------- 1 | from libcpp cimport bool as cpp_bool 2 | from libcpp.string cimport string as cpp_string 3 | 4 | 5 | cdef void cf_find_starting_conditions( 6 | cpp_bool* success_ptr, 7 | cpp_string& message, 8 | int layer_type, 9 | bint is_static, 10 | bint is_incompressible, 11 | cpp_bool use_kamata, 12 | double frequency, 13 | double radius, 14 | double density, 15 | double complex bulk_modulus, 16 | double complex shear_modulus, 17 | int degree_l, 18 | double G_to_use, 19 | size_t num_ys, 20 | double complex* starting_conditions_ptr, 21 | cpp_bool run_y_checks = * 22 | ) noexcept nogil 23 | -------------------------------------------------------------------------------- /TidalPy/WorldPack/charon.toml: -------------------------------------------------------------------------------- 1 | name = "Charon" 2 | type = "burnman" 3 | radius = 606016.07 4 | orbital_period = 6.3872304 5 | eccentricity = 0.0002 6 | spin_period = 6.3872304 7 | albedo = 0.3 8 | force_spin_sync = false 9 | 10 | [layers.Core] 11 | type = "rock" 12 | is_tidal = true 13 | radius = 437374.8067 14 | material = "forsterite" 15 | material_source = "SLB_2011" 16 | temperature_mode = "adiabatic" 17 | temperature_top = 300.0 18 | 19 | [layers.Crust] 20 | type = "ice" 21 | is_tidal = false 22 | radius = 606000.0 23 | material = "IceIh_Fu2010" 24 | material_source = "TidalPy" 25 | temperature_mode = "user-defined" 26 | surface_temperature = 40.0 27 | temperature_fixed = 40.0 28 | -------------------------------------------------------------------------------- /TidalPy/RadialSolver/interfaces/interfaces.pxd: -------------------------------------------------------------------------------- 1 | from libcpp cimport bool as cpp_bool 2 | 3 | cdef void cf_solve_upper_y_at_interface( 4 | double complex* lower_layer_y_ptr, 5 | double complex* upper_layer_y_ptr, 6 | size_t num_sols_lower, 7 | size_t num_sols_upper, 8 | size_t max_num_y, 9 | int lower_layer_type, 10 | cpp_bool lower_is_static, 11 | cpp_bool lower_is_incompressible, 12 | int upper_layer_type, 13 | cpp_bool upper_is_static, 14 | cpp_bool upper_is_incompressible, 15 | double interface_gravity, 16 | double liquid_density, 17 | double G_to_use 18 | ) noexcept nogil 19 | -------------------------------------------------------------------------------- /Documentation/Style Templates/docstring - class.txt: -------------------------------------------------------------------------------- 1 | 2 | The class docstring need only include descriptions of attributes and methods that are most likely to be used or ones 3 | that may lead to confusion with the user. Other methods and attributes that are well described elsewhere 4 | (and/or self-explanatory) can be left out of the class docstring. 5 | 6 | """ 7 | Array with associated photographic information. 8 | 9 | ... 10 | 11 | Attributes 12 | ---------- 13 | exposure : float 14 | Exposure in seconds. 15 | 16 | Methods 17 | ------- 18 | colorspace(c='rgb') 19 | Represent the photo in the given colorspace. 20 | gamma(n=1.0) 21 | Change the photo's gamma exposure. 22 | 23 | """ -------------------------------------------------------------------------------- /TidalPy/WorldPack/pluto.toml: -------------------------------------------------------------------------------- 1 | name = "Pluto" 2 | type = "burnman" 3 | radius = 1189900.0 4 | semi_major_axis = 39.48 5 | semi_major_axis_in_au = true 6 | eccentricity = 0.2488 7 | spin_period = 6.3872304 8 | albedo = 0.55 9 | force_spin_sync = false 10 | 11 | [layers.Core] 12 | type = "rock" 13 | is_tidal = true 14 | radius = 910903.0 15 | material = "forsterite" 16 | material_source = "SLB_2011" 17 | temperature_mode = "adiabatic" 18 | temperature_top = 300.0 19 | 20 | [layers.Crust] 21 | type = "ice" 22 | is_tidal = false 23 | radius = 1189900.0 24 | material = "IceIh_Fu2010" 25 | material_source = "TidalPy" 26 | temperature_mode = "user-defined" 27 | surface_temperature = 40.0 28 | temperature_fixed = 40.0 29 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for TidalPy 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Example: I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /TidalPy/RadialSolver/collapse/collapse.pxd: -------------------------------------------------------------------------------- 1 | from libcpp cimport bool as cpp_bool 2 | 3 | 4 | cdef void cf_collapse_layer_solution( 5 | double complex* solution_ptr, 6 | double complex* constant_vector_ptr, 7 | double complex** storage_by_solution, 8 | double* layer_radius_ptr, 9 | double* layer_density_ptr, 10 | double* layer_gravity_ptr, 11 | double frequency_to_use, 12 | size_t layer_start_index, 13 | size_t num_layer_slices, 14 | size_t num_sols, 15 | size_t max_num_y, 16 | size_t num_ys, 17 | size_t num_output_ys, 18 | size_t ytype_i, 19 | int layer_type, 20 | cpp_bool layer_is_static, 21 | cpp_bool layer_is_incomp 22 | ) noexcept nogil 23 | -------------------------------------------------------------------------------- /TidalPy/Material/eos/methods/interpolate.pxd: -------------------------------------------------------------------------------- 1 | from libcpp cimport bool as cpp_bool 2 | 3 | from TidalPy.Material.eos.ode cimport EOS_ODEInput 4 | 5 | cdef int EOS_INTERPOLATE_METHOD_INT = 0 6 | 7 | cdef struct InterpolateEOSInput: 8 | size_t num_slices 9 | double* radius_array_ptr 10 | double* density_array_ptr 11 | double complex* bulk_modulus_array_ptr 12 | double complex* shear_modulus_array_ptr 13 | 14 | cdef void preeval_interpolate( 15 | # Values that will be updated by the function 16 | char* preeval_output, 17 | # Input that is used by the pre-eval 18 | double radius, 19 | double* radial_solutions, 20 | char* preeval_input 21 | ) noexcept nogil 22 | -------------------------------------------------------------------------------- /TidalPy/utilities/arrays/interp.pxd: -------------------------------------------------------------------------------- 1 | cdef extern from "interp_.cpp" nogil: 2 | size_t cf_binary_search_with_guess( 3 | double key, 4 | double* array, 5 | size_t length, 6 | size_t guess 7 | ) 8 | 9 | void cf_interp( 10 | double* desired_x_ptr, 11 | double* x_domain_ptr, 12 | double* dependent_values_ptr, 13 | size_t len_x, 14 | size_t* provided_j_ptr, 15 | double* result_ptr 16 | ) 17 | 18 | void cf_interp_complex( 19 | double desired_x, 20 | double* x_domain_ptr, 21 | double* dependent_values_ptr, 22 | size_t len_x, 23 | size_t* provided_j_ptr, 24 | double* result_ptr 25 | ) 26 | -------------------------------------------------------------------------------- /TidalPy/utilities/arrays/interp_.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | static const double EPS = std::numeric_limits::epsilon(); 6 | 7 | size_t cf_binary_search_with_guess( 8 | double key, 9 | double* array, 10 | size_t length, 11 | size_t guess 12 | ); 13 | 14 | void cf_interp( 15 | double* desired_x_ptr, 16 | double* x_domain_ptr, 17 | double* dependent_values_ptr, 18 | size_t len_x, 19 | size_t* provided_j_ptr, 20 | double* result_ptr 21 | ); 22 | 23 | void cf_interp_complex( 24 | double desired_x, 25 | double* x_domain_ptr, 26 | double* dependent_values_ptr, 27 | size_t len_x, 28 | size_t* provided_j_ptr, 29 | double* result_ptr 30 | ); 31 | -------------------------------------------------------------------------------- /TidalPy/cooling/__init__.py: -------------------------------------------------------------------------------- 1 | from TidalPy.utilities.classes.model.model_utils import build_model_default_inputs, find_all_models 2 | 3 | import TidalPy 4 | from . import cooling_models 5 | 6 | 7 | parameter_info_loc = ('cooling',) 8 | 9 | known_models, known_model_const_args, known_model_live_args = find_all_models(cooling_models) 10 | 11 | 12 | def get_cooling_model_default_inputs(layer_type: str): 13 | return build_model_default_inputs(known_model_const_args, 14 | TidalPy.config['layers'], 15 | inner_keys=(layer_type, 'cooling')) 16 | 17 | 18 | from .cooling import CoolingModel as CoolingModel 19 | from .cooling_models import CoolingOutputType as CoolingOutputType 20 | -------------------------------------------------------------------------------- /TidalPy/WorldPack/earth_simple.toml: -------------------------------------------------------------------------------- 1 | name = "Earth_Simple" 2 | type = "layered" 3 | radius = 6371000.0 4 | semi_major_axis = 1.0 5 | semi_major_axis_in_au = true 6 | eccentricity = 0.01671022 7 | spin_period = 1.0 8 | tides_on = true 9 | 10 | [tides] 11 | model = "global_approx" 12 | fixed_q = 100.0 13 | 14 | [layers.Inner_Core] 15 | type = "iron" 16 | is_tidal = false 17 | radius = 1220000.0 18 | density = 17000.0 19 | 20 | [layers.Outer_Core] 21 | type = "iron" 22 | is_tidal = false 23 | radius = 3480000.0 24 | density = 12000.0 25 | 26 | [layers.Lower_Mantle] 27 | type = "rock" 28 | is_tidal = false 29 | radius = 5711000.0 30 | density = 5000.0 31 | 32 | [layers.Upper_Mantle] 33 | type = "rock" 34 | is_tidal = true 35 | radius = 6371000.0 36 | density = 3300.0 37 | -------------------------------------------------------------------------------- /TidalPy/RadialSolver/interfaces/reversed.pxd: -------------------------------------------------------------------------------- 1 | from libcpp cimport bool as cpp_bool 2 | from libcpp.complex cimport complex as cpp_complex 3 | 4 | 5 | cdef void cf_top_to_bottom_interface_bc( 6 | double complex* constant_vector_ptr, 7 | double complex* layer_above_constant_vector_ptr, 8 | double complex* uppermost_y_per_solution_ptr, 9 | double gravity_upper, 10 | double layer_above_lower_gravity, 11 | double density_upper, 12 | double layer_above_lower_density, 13 | int layer_type, 14 | int layer_above_type, 15 | cpp_bool layer_is_static, 16 | cpp_bool layer_above_is_static, 17 | cpp_bool layer_is_incomp, 18 | cpp_bool layer_above_is_incomp, 19 | size_t num_sols, 20 | size_t max_num_y 21 | ) noexcept nogil 22 | -------------------------------------------------------------------------------- /TidalPy/utilities/performance/__init__.py: -------------------------------------------------------------------------------- 1 | from .numba import njit as njit 2 | from .numba import use_numba as use_numba 3 | from .numba import bool_ as bool_ 4 | from .numba import float64 as float64 5 | from .numba import int64 as int64 6 | from .numba import int32 as int32 7 | from .numba import int16 as int16 8 | from .numba import int8 as int8 9 | from .numba import uint64 as uint64 10 | from .numba import uint32 as uint32 11 | from .numba import uint16 as uint16 12 | from .numba import uint8 as uint8 13 | from .numba import complex128 as complex128 14 | from .numba import nbDict as nbDict 15 | from .numba import nbList as nbList 16 | from .numba import nbUnicode as nbUnicode 17 | from .numba import prange as prange 18 | 19 | from .special import find_factorial as find_factorial -------------------------------------------------------------------------------- /TidalPy/utilities/performance/special/factorial.py: -------------------------------------------------------------------------------- 1 | """ Special math functions are defined here. 2 | """ 3 | 4 | from scipy import special 5 | from numba import njit 6 | 7 | 8 | @njit(cache=False) 9 | def find_factorial(number: float) -> float: 10 | """ Find's the factorial of a number based on SciPy's Gamma function. 11 | 12 | Notes 13 | ----- 14 | This uses the numba-scipy package to register overloads for scipy's special functions. This allows Numba to njit 15 | these functions, including gamma. 16 | 17 | Parameters 18 | ---------- 19 | number : float 20 | Number to be factorialized. 21 | 22 | Returns 23 | ------- 24 | factorial : float 25 | Factorial of 'number' 26 | """ 27 | 28 | return special.gamma(number + 1.) 29 | -------------------------------------------------------------------------------- /TidalPy/WorldPack/io.toml: -------------------------------------------------------------------------------- 1 | name = "Io" 2 | type = "burnman" 3 | radius = 1821490.0 4 | orbital_period = 1.769 5 | eccentricity = 0.0041 6 | spin_period = 1.769 7 | albedo = 0.63 8 | force_spin_sync = true 9 | 10 | [layers.Core] 11 | type = "iron" 12 | is_tidal = false 13 | radius = 810000.0 14 | material = [ "Pyrite", "Fe_Dewaele",] 15 | material_source = [ "TidalPy", "other",] 16 | material_fractions = [ 0.5, 0.5,] 17 | temperature_mode = "user-defined" 18 | temperature_fixed = 1800.0 19 | 20 | [layers.Mantle] 21 | type = "rock" 22 | is_tidal = true 23 | radius = 1821490.0 24 | material = [ "forsterite", "mg_perovskite",] 25 | material_source = [ "SLB_2011", "SLB_2011",] 26 | material_fractions = [ 0.65, 0.35,] 27 | temperature_mode = "adiabatic" 28 | temperature_top = 1800.0 29 | surface_temperature = 100.0 30 | -------------------------------------------------------------------------------- /TidalPy/rheology/complex_compliance/__init__.py: -------------------------------------------------------------------------------- 1 | from TidalPy.utilities.classes.model.model_utils import build_model_default_inputs, find_all_models 2 | 3 | import TidalPy 4 | from . import compliance_models as complex_compliances 5 | from .compliance_models import find_factorial 6 | 7 | known_models, known_model_const_args, known_model_live_args = \ 8 | find_all_models(complex_compliances, ignore_functional_types=(find_factorial,)) 9 | 10 | 11 | def get_complex_comp_model_default_inputs(layer_type: str): 12 | return build_model_default_inputs(known_model_const_args, 13 | TidalPy.config['layers'], 14 | inner_keys=(layer_type, 'rheology')) 15 | 16 | 17 | from .complex_compliance import ComplexCompliance as ComplexCompliance 18 | -------------------------------------------------------------------------------- /TidalPy/tides/multilayer/sensitivity.pxd: -------------------------------------------------------------------------------- 1 | cdef void cf_calc_sensitivity_to_shear( 2 | double* radial_sensitivity_to_shear_ptr, 3 | double complex* radial_solutions_ptr, 4 | double* radius_array_ptr, 5 | double complex* shear_modulus_array_ptr, 6 | double complex* bulk_modulus_array_ptr, 7 | size_t total_slices, 8 | size_t num_ytypes, 9 | int degree_l 10 | ) noexcept nogil 11 | 12 | cdef void cf_calc_sensitivity_to_bulk( 13 | double* radial_sensitivity_to_bulk_ptr, 14 | double complex* radial_solutions_ptr, 15 | double* radius_array_ptr, 16 | double complex* shear_modulus_array_ptr, 17 | double complex* bulk_modulus_array_ptr, 18 | size_t total_slices, 19 | size_t num_ytypes, 20 | int degree_l 21 | ) noexcept nogil 22 | -------------------------------------------------------------------------------- /Benchmarks/Performance/performance suite/performance_build_world.py: -------------------------------------------------------------------------------- 1 | import TidalPy 2 | 3 | TidalPy.config['stream_level'] = 'WARNING' 4 | TidalPy.reinit() 5 | 6 | from TidalPy.structures import build_world 7 | 8 | 9 | from performance_base import PerformanceTrackBase 10 | 11 | class BuildWorldPerformance(PerformanceTrackBase): 12 | 13 | def run_perform_build_star(self): 14 | self.record_performance('Build World - Star', build_world, 15 | inputs=('55cnc',), repeats=3, number=10) 16 | 17 | def run_perform_build_simple_layered(self): 18 | self.record_performance('Build World - Layered', build_world, 19 | inputs=('io_simple',), repeats=3, number=10) 20 | 21 | 22 | if __name__ == '__main__': 23 | performance_tracker = BuildWorldPerformance() -------------------------------------------------------------------------------- /TidalPy/numba_scipy/special/overloads.py: -------------------------------------------------------------------------------- 1 | import numba 2 | import scipy.special as sc 3 | 4 | from . import signatures 5 | 6 | 7 | def choose_kernel(name, all_signatures): 8 | 9 | def choice_function(*args): 10 | for signature in all_signatures: 11 | if args == signature: 12 | f = signatures.name_and_types_to_pointer[(name, *signature)] 13 | return lambda *args: f(*args) 14 | 15 | return choice_function 16 | 17 | 18 | def add_overloads(): 19 | # print('!!TPY: Adding Numba-Scipy Overloads...') 20 | for name, all_signatures in signatures.name_to_numba_signatures.items(): 21 | sc_function = getattr(sc, name) 22 | numba.extending.overload(sc_function)( 23 | choose_kernel(name, all_signatures) 24 | ) 25 | # print('!!TPY: Done.') 26 | -------------------------------------------------------------------------------- /Benchmarks/Performance/performance suite/run_suite.py: -------------------------------------------------------------------------------- 1 | from performance_build_world import BuildWorldPerformance 2 | from performance_complex_compliance_func import ComplexCompliancePerformance 3 | from performance_eccentricity_func import EccentricityFuncPerformance 4 | from performance_tides import TideCalcPerformance 5 | from performance_quick_calcs import QuickCalcPerformance 6 | from multilayer_radial_solver import TidalYPerformance 7 | from multimode_solver import MultilayerModeNumbaPerformance, MultilayerModePerformance 8 | 9 | if __name__ == '__main__': 10 | BuildWorldPerformance() 11 | ComplexCompliancePerformance() 12 | EccentricityFuncPerformance() 13 | TideCalcPerformance() 14 | QuickCalcPerformance() 15 | TidalYPerformance() 16 | MultilayerModeNumbaPerformance() 17 | MultilayerModePerformance() 18 | -------------------------------------------------------------------------------- /TidalPy/utilities/multiprocessing/__init__.py: -------------------------------------------------------------------------------- 1 | psutil_installed = False 2 | try: 3 | import psutil as psutil 4 | psutil_installed = True 5 | except ImportError: 6 | 7 | # Build fake class for type checking 8 | class psutil: 9 | def virtual_memory(self): 10 | pass 11 | def cpu_count(self): 12 | pass 13 | 14 | pathos_installed = False 15 | try: 16 | from pathos import multiprocessing as pathos_mp 17 | pathos_installed = True 18 | except ImportError: 19 | # Pathos is not installed. Use Python's multiprocessing instead. 20 | pathos_mp = None 21 | 22 | from .multiprocessing import multiprocessing_run as multiprocessing_run 23 | from .multiprocessing import MultiprocessingInput as MultiprocessingInput 24 | from .multiprocessing import MultiprocessingOutput as MultiprocessingOutput -------------------------------------------------------------------------------- /TidalPy/Material/eos/solver.pxd: -------------------------------------------------------------------------------- 1 | from libcpp.vector cimport vector 2 | from libcpp.memory cimport unique_ptr 3 | from libcpp cimport bool as cpp_bool 4 | 5 | from CyRK cimport PreEvalFunc, CySolveOutput, ODEMethod 6 | 7 | from TidalPy.Material.eos.ode cimport EOS_ODEInput 8 | from TidalPy.Material.eos.eos_solution cimport EOSSolutionCC, EOS_DY_VALUES 9 | 10 | cdef void solve_eos( 11 | EOSSolutionCC* eos_solution_ptr, 12 | vector[PreEvalFunc] eos_function_bylayer_ptr_vec, 13 | vector[EOS_ODEInput] eos_input_bylayer_vec, 14 | double planet_bulk_density, 15 | double surface_pressure = *, 16 | double G_to_use = *, 17 | ODEMethod integration_method = *, 18 | double rtol = *, 19 | double atol = *, 20 | double pressure_tol = *, 21 | size_t max_iters = *, 22 | cpp_bool verbose = * 23 | ) noexcept nogil 24 | -------------------------------------------------------------------------------- /TidalPy/stellar/__init__.py: -------------------------------------------------------------------------------- 1 | from typing import Union 2 | 3 | from .insolation import calc_equilibrium_temperature as calc_equilibrium_temperature 4 | from .insolation import equilibrium_insolation_mendez as equilibrium_insolation_mendez 5 | from .insolation import equilibrium_insolation_no_eccentricity as equilibrium_insolation_no_eccentricity 6 | from .insolation import equilibrium_insolation_williams as equilibrium_insolation_williams 7 | 8 | EquilibFuncType = Union[type(equilibrium_insolation_mendez), type(equilibrium_insolation_no_eccentricity), 9 | type(equilibrium_insolation_williams)] 10 | 11 | equilibrium_insolation_functions = { 12 | 'no_eccentricity': equilibrium_insolation_no_eccentricity, 13 | 'williams' : equilibrium_insolation_williams, 14 | 'mendez' : equilibrium_insolation_mendez 15 | } 16 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve TidalPy 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Versions (please complete the following information, where applicable):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - TidalPy Version [e.g. 22] 30 | 31 | **Additional context** 32 | Add any other context about the problem here. 33 | -------------------------------------------------------------------------------- /TidalPy/WorldPack/triton.toml: -------------------------------------------------------------------------------- 1 | name = "Triton" 2 | type = "burnman" 3 | radius = 1353000.0 4 | semi_major_axis = 354760000.0 5 | semi_major_axis_in_au = false 6 | eccentricity = 1.6e-5 7 | spin_period = 5.876854 8 | albedo = 0.55 9 | force_spin_sync = false 10 | 11 | [layers.Core] 12 | type = "rock" 13 | is_tidal = true 14 | radius = 1064000.0 15 | material = "forsterite" 16 | material_source = "SLB_2011" 17 | temperature_mode = "adiabatic" 18 | temperature_top = 273.15 19 | 20 | [layers.Crust] 21 | type = "ice" 22 | is_tidal = true 23 | radius = 1353000.0 24 | material = "IceIh_Fu2010" 25 | material_source = "TidalPy" 26 | temperature_mode = "user-defined" 27 | surface_temperature = 35.0 28 | temperature_fixed = 35.0 29 | 30 | [layers.Core.rheology.complex_compliance] 31 | model = "sundberg" 32 | 33 | [layers.Crust.rheology.complex_compliance] 34 | model = "sundberg" 35 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "tasks": [ 3 | { 4 | "type": "cppbuild", 5 | "label": "C/C++: gcc.exe build active file", 6 | "command": "C:\\Software\\mingw64\\bin\\gcc.exe", 7 | "args": [ 8 | "-fdiagnostics-color=always", 9 | "-g", 10 | "${file}", 11 | "-o", 12 | "${fileDirname}\\${fileBasenameNoExtension}.exe" 13 | ], 14 | "options": { 15 | "cwd": "${fileDirname}" 16 | }, 17 | "problemMatcher": [ 18 | "$gcc" 19 | ], 20 | "group": { 21 | "kind": "build", 22 | "isDefault": true 23 | }, 24 | "detail": "Task generated by Debugger." 25 | } 26 | ], 27 | "version": "2.0.0" 28 | } -------------------------------------------------------------------------------- /TidalPy/WorldPack/luna.toml: -------------------------------------------------------------------------------- 1 | name = "Luna" 2 | type = "burnman" 3 | radius = 1737400.0 4 | orbital_period = 27.322 5 | eccentricity = 0.0554 6 | spin_period = 27.322 7 | albedo = 0.12 8 | force_spin_sync = true 9 | 10 | [layers.Inner_Core] 11 | type = "iron" 12 | is_tidal = false 13 | radius = 160000.0 14 | material = "Fe_Dewaele" 15 | material_source = "other" 16 | temperature_mode = "user-defined" 17 | temperature_fixed = 300.0 18 | 19 | [layers.Outer_Core] 20 | type = "iron" 21 | is_tidal = false 22 | radius = 350000.0 23 | material = "Liquid_Fe_Anderson" 24 | material_source = "other" 25 | temperature_mode = "user-defined" 26 | temperature_fixed = 300.0 27 | 28 | [layers.Mantle] 29 | type = "rock" 30 | is_tidal = false 31 | radius = 1737400.0 32 | material = "forsterite" 33 | material_source = "SLB_2011" 34 | temperature_mode = "adiabatic" 35 | temperature_top = 350.0 36 | surface_temperature = 300.0 37 | -------------------------------------------------------------------------------- /TidalPy/utilities/conversions/conversions_x.pxd: -------------------------------------------------------------------------------- 1 | cdef double cf_m2Au( 2 | double meters 3 | ) noexcept nogil 4 | 5 | cdef double cf_Au2m( 6 | double astronomical_units 7 | ) noexcept nogil 8 | 9 | cdef double cf_rads2days( 10 | double radians_per_second 11 | ) noexcept nogil 12 | 13 | cdef double cf_days2rads( 14 | double days 15 | ) noexcept nogil 16 | 17 | cdef double cf_sec2myr( 18 | double seconds 19 | ) noexcept nogil 20 | 21 | cdef double cf_myr2sec( 22 | double myrs 23 | ) noexcept nogil 24 | 25 | cdef double cf_orbital_motion2semi_a( 26 | double orbital_motion, 27 | double host_mass, 28 | double target_mass = *, 29 | double G_to_use = * 30 | ) noexcept nogil 31 | 32 | cdef double cf_semi_a2orbital_motion( 33 | double semi_major_axis, 34 | double host_mass, 35 | double target_mass = *, 36 | double G_to_use = * 37 | ) noexcept nogil 38 | -------------------------------------------------------------------------------- /TidalPy/utilities/conversions/timing.py: -------------------------------------------------------------------------------- 1 | from typing import Tuple 2 | 3 | from TidalPy.utilities.performance.numba import njit 4 | 5 | 6 | @njit(cacheable=True) 7 | def convert_to_hms(seconds: float) -> Tuple[int, int, int, float]: 8 | """ Convert seconds to a tuple of days, hours, minutes, seconds 9 | 10 | Parameters 11 | ---------- 12 | seconds : float 13 | Time in seconds 14 | 15 | Returns 16 | ------- 17 | days : int 18 | Days 19 | hours : int 20 | Hours 21 | minutes : int 22 | Minutes 23 | seconds : float 24 | Remaining seconds after conversion 25 | """ 26 | 27 | days = int(seconds / (24. * 3600.)) 28 | seconds = seconds % (24. * 3600.) 29 | hours = int(seconds / 3600.) 30 | seconds = seconds % 3600. 31 | minutes = int(seconds / 60.) 32 | seconds = seconds % 60. 33 | 34 | return days, hours, minutes, seconds 35 | -------------------------------------------------------------------------------- /TidalPy/WorldPack/trappist1e.toml: -------------------------------------------------------------------------------- 1 | # Radius: Delrez et al., (2018) corrected by Kane et al., (2018) 2 | # Masses: Grimm et al., (2018) 3 | # Gravity: g*mass/(R2) 4 | # Flux: Delrez et al., (2018) corrected by Kane et al., (2018) 5 | # Density (Jontof-Hutter et al., 2014): radii: Delrez et al., (2018) + masses: Grimm e al (2018) corrected by Kane et al., (2018) 6 | # Updated using the analysis done by Agol+2020 and references therein. 7 | 8 | name = "TRAPPIST-1e" 9 | type = "simple_tidal" 10 | radius = 5868000.0 11 | radius_error_pos = 82000.0 12 | radius_error_neg = 75000.0 13 | mass = 2.316e+24 14 | mass_error_pos = 1.3e+23 15 | mass_error_neg = 1.3e+23 16 | semi_major_axis = 4376000000.0 17 | semi_major_axis_error_pos = 37000000.0 18 | semi_major_axis_error_neg = 37000000.0 19 | semi_major_axis_in_au = false 20 | eccentricity = 0.00447 21 | eccentricity_error_pos = 0.00014 22 | eccentricity_error_neg = 0.00014 23 | force_spin_sync = true 24 | -------------------------------------------------------------------------------- /TidalPy/WorldPack/trappist1g.toml: -------------------------------------------------------------------------------- 1 | # Radius: Delrez et al., (2018) corrected by Kane et al., (2018) 2 | # Masses: Grimm et al., (2018) 3 | # Gravity: g*mass/(R2) 4 | # Flux: Delrez et al., (2018) corrected by Kane et al., (2018) 5 | # Density (Jontof-Hutter et al., 2014): radii: Delrez et al., (2018) + masses: Grimm e al (2018) corrected by Kane et al., (2018) 6 | # Updated using the analysis done by Agol+2020 and references therein. 7 | 8 | name = "TRAPPIST-1g" 9 | type = "simple_tidal" 10 | radius = 7204000.0 11 | radius_error_pos = 94000.0 12 | radius_error_neg = 85000.0 13 | mass = 7.89e+24 14 | mass_error_pos = 2.26e+23 15 | mass_error_neg = 2.26e+23 16 | semi_major_axis = 7006000000.0 17 | semi_major_axis_error_pos = 60000000.0 18 | semi_major_axis_error_neg = 60000000.0 19 | semi_major_axis_in_au = false 20 | eccentricity = 0.00254 21 | eccentricity_error_pos = 0.00126 22 | eccentricity_error_neg = 0.00126 23 | force_spin_sync = true 24 | -------------------------------------------------------------------------------- /Tests/Test_Math/test_utilities_numerics.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from math import isclose as py_isclose 4 | from math import nan 5 | 6 | from TidalPy.utilities.math.numerics import isclose 7 | 8 | 9 | @pytest.mark.parametrize('a', (0.0, -55.222226, 10., 1.0e200, -1.0e200, 1.0e-9, 1.0e-5, -1.0e-9, -1.0e-5, 1.4562221e34, 1.0e-14, 0.98e-14)) 10 | @pytest.mark.parametrize('b', (0.0, -55.222222, 10., 1.0e200, -1.0e200, 1.0e-9, 1.0e-5, -1.0e-9, -1.0e-5, 1.4582221e34, 1.0e-14, 0.98e-14)) 11 | @pytest.mark.parametrize('rtol', (3.0, 1.0e-9, 1.0e-3)) 12 | @pytest.mark.parametrize('atol', (3.0, 1.0e-3, 0.0)) 13 | def test_math_isclose(a, b, rtol, atol): 14 | 15 | pyresult = py_isclose(a, b, rel_tol=rtol, abs_tol=atol) 16 | tpyresult = isclose(a, b, rtol, atol) 17 | 18 | assert pyresult == tpyresult 19 | 20 | def test_math_isclose_nans(): 21 | 22 | assert isclose(nan, 10.0) == False 23 | assert isclose(10.0, nan) == False 24 | 25 | -------------------------------------------------------------------------------- /TidalPy/WorldPack/trappist1c.toml: -------------------------------------------------------------------------------- 1 | # Radius: Delrez et al., (2018) corrected by Kane et al., (2018) 2 | # Masses: Grimm et al., (2018) 3 | # Gravity: g*mass/(R2) 4 | # Flux: Delrez et al., (2018) corrected by Kane et al., (2018) 5 | # Density (Jontof-Hutter et al., 2014): radii: Delrez et al., (2018) + masses: Grimm e al (2018) corrected by Kane et al., (2018) 6 | # Updated using the analysis done by Agol+2020 and references therein. 7 | 8 | name = "TRAPPIST-1c" 9 | type = "simple_tidal" 10 | radius = 6995000.0 11 | radius_error_pos = 86000.0 12 | radius_error_neg = 77000.0 13 | mass = 7.814e+24 14 | mass_error_pos = 3.35e+23 15 | mass_error_neg = 3.35e+23 16 | semi_major_axis = 2364000000.0 17 | semi_major_axis_error_pos = 20000000.0 18 | semi_major_axis_error_neg = 20000000.0 19 | semi_major_axis_in_au = false 20 | eccentricity = 0.00028 21 | eccentricity_error_pos = 0.00027 22 | eccentricity_error_neg = 0.00027 23 | force_spin_sync = true 24 | -------------------------------------------------------------------------------- /TidalPy/WorldPack/trappist1d.toml: -------------------------------------------------------------------------------- 1 | # Radius: Delrez et al., (2018) corrected by Kane et al., (2018) 2 | # Masses: Grimm et al., (2018) 3 | # Gravity: g*mass/(R2) 4 | # Flux: Delrez et al., (2018) corrected by Kane et al., (2018) 5 | # Density (Jontof-Hutter et al., 2014): radii: Delrez et al., (2018) + masses: Grimm e al (2018) corrected by Kane et al., (2018) 6 | # Updated using the analysis done by Agol+2020 and references therein. 7 | 8 | name = "TRAPPIST-1d" 9 | type = "simple_tidal" 10 | radius = 5026000.0 11 | radius_error_pos = 71000.0 12 | radius_error_neg = 66000.0 13 | mass = 2.316e+24 14 | mass_error_pos = 7.4e+22 15 | mass_error_neg = 7.4e+22 16 | semi_major_axis = 3331000000.0 17 | semi_major_axis_error_pos = 28000000.0 18 | semi_major_axis_error_neg = 28000000.0 19 | semi_major_axis_in_au = false 20 | eccentricity = 0.003815 21 | eccentricity_error_pos = 0.001145 22 | eccentricity_error_neg = 0.001145 23 | force_spin_sync = true 24 | -------------------------------------------------------------------------------- /TidalPy/WorldPack/trappist1f.toml: -------------------------------------------------------------------------------- 1 | # Radius: Delrez et al., (2018) corrected by Kane et al., (2018) 2 | # Masses: Grimm et al., (2018) 3 | # Gravity: g*mass/(R2) 4 | # Flux: Delrez et al., (2018) corrected by Kane et al., (2018) 5 | # Density (Jontof-Hutter et al., 2014): radii: Delrez et al., (2018) + masses: Grimm e al (2018) corrected by Kane et al., (2018) 6 | # Updated using the analysis done by Agol+2020 and references therein. 7 | 8 | name = "TRAPPIST-1f" 9 | type = "simple_tidal" 10 | radius = 6664000.0 11 | radius_error_pos = 85000.0 12 | radius_error_neg = 77000.0 13 | mass = 6.205e+24 14 | mass_error_pos = 1.84e+23 15 | mass_error_neg = 1.84e+23 16 | semi_major_axis = 5758000000.0 17 | semi_major_axis_error_pos = 49000000.0 18 | semi_major_axis_error_neg = 49000000.0 19 | semi_major_axis_in_au = false 20 | eccentricity = 0.004455 21 | eccentricity_error_pos = 0.003945 22 | eccentricity_error_neg = 0.003945 23 | force_spin_sync = true 24 | -------------------------------------------------------------------------------- /TidalPy/WorldPack/trappist1h.toml: -------------------------------------------------------------------------------- 1 | # Radius: Delrez et al., (2018) corrected by Kane et al., (2018) 2 | # Masses: Grimm et al., (2018) 3 | # Gravity: g*mass/(R2) 4 | # Flux: Delrez et al., (2018) corrected by Kane et al., (2018) 5 | # Density (Jontof-Hutter et al., 2014): radii: Delrez et al., (2018) + masses: Grimm e al (2018) corrected by Kane et al., (2018) 6 | # Updated using the analysis done by Agol+2020 and references therein. 7 | 8 | name = "TRAPPIST-1h" 9 | type = "simple_tidal" 10 | radius = 4817000.0 11 | radius_error_pos = 91000.0 12 | radius_error_neg = 88000.0 13 | mass = 1.945e+24 14 | mass_error_pos = 1.22e+23 15 | mass_error_neg = 1.22e+23 16 | semi_major_axis = 9259000000.0 17 | semi_major_axis_error_pos = 79000000.0 18 | semi_major_axis_error_neg = 79000000.0 19 | semi_major_axis_in_au = false 20 | eccentricity = 0.001835 21 | eccentricity_error_pos = 0.001815 22 | eccentricity_error_neg = 0.001815 23 | force_spin_sync = true 24 | -------------------------------------------------------------------------------- /TidalPy/utilities/math/numerics.pyx: -------------------------------------------------------------------------------- 1 | # distutils: language = c++ 2 | # cython: boundscheck=False, wraparound=False, nonecheck=False, cdivision=True, initializedcheck=False 3 | 4 | from libc.math cimport fabs, fmax, isnan 5 | 6 | 7 | cdef cpp_bool cf_isclose( 8 | double a, 9 | double b, 10 | double rtol = 1.0e-9, 11 | double atol = 0.0 12 | ) noexcept nogil: 13 | 14 | if isnan(a): 15 | return False 16 | 17 | if isnan(b): 18 | return False 19 | 20 | # Check for pure equivalence 21 | if a == b: 22 | return True 23 | 24 | # Check for closeness 25 | cdef double lhs = fabs(a - b) 26 | cdef double rhs = fmax(rtol * fmax(fabs(a), fabs(b)), atol) 27 | 28 | return lhs <= rhs 29 | 30 | 31 | def isclose( 32 | double a, 33 | double b, 34 | double rtol = 1.0e-9, 35 | double atol = 0.0): 36 | 37 | return cf_isclose(a, b, rtol, atol) 38 | -------------------------------------------------------------------------------- /TidalPy/RadialSolver/matrix.pxd: -------------------------------------------------------------------------------- 1 | from libcpp cimport bool as cpp_bool 2 | from libcpp.memory cimport shared_ptr 3 | from libcpp.vector cimport vector 4 | 5 | from TidalPy.RadialSolver.rs_solution cimport RadialSolutionStorageCC 6 | 7 | cdef int cf_matrix_propagate( 8 | RadialSolutionStorageCC* solution_storage_ptr, 9 | double frequency, 10 | double planet_bulk_density, 11 | # TODO: In the future the propagation matrix should take in layer types and multiple layers 12 | # int* layer_types_ptr, 13 | # int* is_static_by_layer_ptr, 14 | # int* is_incompressible_by_layer_ptr, 15 | vector[size_t] first_slice_index_by_layer_vec, 16 | vector[size_t] num_slices_by_layer_vec, 17 | size_t num_bc_models, 18 | int* bc_models_ptr, 19 | double G_to_use, 20 | int degree_l, 21 | double starting_radius, 22 | double start_radius_tolerance, 23 | int core_model, 24 | cpp_bool verbose 25 | ) noexcept nogil 26 | -------------------------------------------------------------------------------- /TidalPy/WorldPack/55cnce.toml: -------------------------------------------------------------------------------- 1 | # Very roughly pulled from some analysis by Dorn+ (A&A 2017) 2 | 3 | name = "55-Cancri-e" 4 | type = "burnman" 5 | radius = 11950000.0 6 | semi_major_axis = 0.01544 7 | semi_major_axis_in_au = true 8 | eccentricity = 0.02 9 | spin_period = 1.0 10 | force_spin_sync = true 11 | 12 | [layers.Core] 13 | type = "iron" 14 | is_tidal = false 15 | radius = 4000000.0 16 | material = "Fe_Dewaele" 17 | material_source = "other" 18 | temperature_mode = "user-defined" 19 | temperature_fixed = 300.0 20 | 21 | [layers.Lower_Mantle] 22 | type = "rock" 23 | is_tidal = false 24 | radius = 8959000.0 25 | material = "mg_bridgmanite" 26 | material_source = "SLB_2011" 27 | temperature_mode = "adiabatic" 28 | 29 | [layers.Upper_Mantle] 30 | type = "rock" 31 | is_tidal = true 32 | radius = 11950000.0 33 | material = "forsterite" 34 | material_source = "SLB_2011" 35 | temperature_mode = "adiabatic" 36 | temperature_top = 1200.0 37 | surface_temperature = 300.0 38 | -------------------------------------------------------------------------------- /TidalPy/WorldPack/trappist1b.toml: -------------------------------------------------------------------------------- 1 | # Radius: Delrez et al., (2018) corrected by Kane et al., (2018) 2 | # Masses: Grimm et al., (2018) 3 | # Gravity: g*mass/(R2) 4 | # Flux: Delrez et al., (2018) corrected by Kane et al., (2018) 5 | # Density (Jontof-Hutter et al., 2014): radii: Delrez et al., (2018) + masses: Grimm e al (2018) corrected by Kane et al., (2018) 6 | # Updated using the analysis done by Agol+2020 and references therein. Eccentricities are from Grimm+2018 7 | 8 | name = "TRAPPIST-1b" 9 | type = "simple_tidal" 10 | radius = 7119000.0 11 | radius_error_pos = 87000.0 12 | radius_error_neg = 77000.0 13 | mass = 8.311e+24 14 | mass_error_pos = 4.12e+23 15 | mass_error_neg = 4.12e+23 16 | semi_major_axis = 1726000000.0 17 | semi_major_axis_error_pos = 15000000.0 18 | semi_major_axis_error_neg = 15000000.0 19 | semi_major_axis_in_au = false 20 | eccentricity = 0.00216 21 | eccentricity_error_pos = 1e-5 22 | eccentricity_error_neg = 1e-5 23 | force_spin_sync = true 24 | -------------------------------------------------------------------------------- /TidalPy/utilities/classes/base_x.pyx: -------------------------------------------------------------------------------- 1 | # distutils: language = c++ 2 | # cython: boundscheck=False, wraparound=False, nonecheck=False, cdivision=True, initializedcheck=False 3 | 4 | from TidalPy import config 5 | 6 | cdef bint DEBUG_MODE 7 | DEBUG_MODE = config['debug']['extensive_checks'] 8 | 9 | cdef class TidalPyBaseExtensionClass: 10 | """ 11 | TidalPy's base extension class used as a basis for most other cython extension types used throughout TidalPy. 12 | """ 13 | 14 | 15 | def __init__( 16 | self, 17 | str class_name = 'TidalPyBaseExtensionClass', 18 | str name_prefix = '', 19 | bint debug_mode = DEBUG_MODE 20 | ): 21 | 22 | # Store base class properties 23 | self.class_name = class_name 24 | self.name_prefix = name_prefix 25 | self.debug_mode = debug_mode 26 | 27 | 28 | def __str__(self): 29 | return f'{self.name_prefix}::[!{self.class_name}].' -------------------------------------------------------------------------------- /Tests/Test_Old/Test_SetB_Package/test_c_tools_timing.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | 4 | 5 | from TidalPy.utilities.conversions.timing import convert_to_hms 6 | 7 | def test_convert_hms(): 8 | """ Test the convert_to_hms function """ 9 | 10 | result = convert_to_hms(60.) 11 | assert type(result) == tuple 12 | 13 | day, hour, minute, second = result 14 | assert type(day) in [int, np.int32] 15 | assert type(hour) in [int, np.int32] 16 | assert type(minute) in [int, np.int32] 17 | assert type(second) in [float, np.float64] 18 | 19 | assert day == 0 20 | assert hour == 0 21 | assert minute == 1 22 | assert second == 0. 23 | 24 | day, hour, minute, second = convert_to_hms(198000.) 25 | assert day == 2 26 | assert hour == 7 27 | assert minute == 0 28 | assert second == 0. 29 | 30 | day, hour, minute, second = convert_to_hms(198025.5) 31 | assert day == 2 32 | assert hour == 7 33 | assert minute == 0 34 | assert second == 25.5 35 | -------------------------------------------------------------------------------- /TidalPy/rheology/viscosity/__init__.py: -------------------------------------------------------------------------------- 1 | from TidalPy.utilities.classes.model.model_utils import build_model_default_inputs, find_all_models 2 | 3 | import TidalPy 4 | from . import viscosity_models 5 | 6 | known_models, known_model_const_args, known_model_live_args = find_all_models(viscosity_models) 7 | 8 | 9 | def get_solid_viscosity_model_default_inputs(layer_type: str): 10 | return build_model_default_inputs(known_model_const_args, 11 | TidalPy.config['layers'], 12 | inner_keys=(layer_type, 'solid_viscosity')) 13 | 14 | 15 | def get_liquid_viscosity_model_default_inputs(layer_type: str): 16 | return build_model_default_inputs(known_model_const_args, 17 | TidalPy.config['layers'], 18 | inner_keys=(layer_type, 'liquid_viscosity')) 19 | 20 | 21 | from .viscosity import LiquidViscosity as LiquidViscosity 22 | from .viscosity import SolidViscosity as SolidViscosity 23 | -------------------------------------------------------------------------------- /TidalPy/utilities/integration/scipy_helper.py: -------------------------------------------------------------------------------- 1 | """ Helper functions to interface with SciPy's integration suite """ 2 | 3 | from typing import Tuple 4 | 5 | import numpy as np 6 | 7 | from . import _solve_ivp 8 | 9 | 10 | def solve_ivp( 11 | diffeq, time_span: Tuple[float, float], initial_condition: np.ndarray, args: Tuple = None, 12 | rtol: float = 1.0e-6, atol: float = 1.0e-8, max_step: float = np.inf, 13 | first_step: float = None, method: str = 'RK45', t_eval: np.ndarray = np.empty((0,), dtype=np.float64) 14 | ): 15 | 16 | # Solve the ode 17 | solution = _solve_ivp( 18 | diffeq, time_span, initial_condition, method=method, t_eval=t_eval, args=args, 19 | first_step=first_step, max_step=max_step, rtol=rtol, atol=atol 20 | ) 21 | 22 | # Pull out information from SciPy's solution class 23 | time_domain = solution.t 24 | y_results = solution.y 25 | success = solution.success 26 | message = solution.message 27 | 28 | return time_domain, y_results, success, message 29 | -------------------------------------------------------------------------------- /TidalPy/rheology/base.pxd: -------------------------------------------------------------------------------- 1 | from TidalPy.utilities.classes.base_x cimport TidalPyBaseExtensionClass 2 | 3 | 4 | cdef class RheologyModelBase(TidalPyBaseExtensionClass): 5 | 6 | # Class attributes 7 | cdef size_t expected_num_args 8 | 9 | # Class methods 10 | cdef double complex _implementation( 11 | self, 12 | double frequency, 13 | double modulus, 14 | double viscosity 15 | ) noexcept nogil 16 | 17 | cdef void _vectorize_frequency( 18 | self, 19 | double* frequency_ptr, 20 | double modulus, 21 | double viscosity, 22 | double complex* output_ptr, 23 | Py_ssize_t n, 24 | ) noexcept nogil 25 | 26 | cdef void _vectorize_modulus_viscosity( 27 | self, 28 | double frequency, 29 | double* modulus_ptr, 30 | double* viscosity_ptr, 31 | double complex* output_ptr, 32 | Py_ssize_t n, 33 | ) noexcept nogil 34 | -------------------------------------------------------------------------------- /TidalPy/dynamics/__init__.py: -------------------------------------------------------------------------------- 1 | from .dual_dissipation import eccentricity_derivative as eccentricity_derivative_dual_ 2 | from .dual_dissipation import semi_major_axis_derivative as semi_major_axis_derivative_dual_ 3 | from .dual_dissipation import semia_eccen_derivatives as semia_eccen_derivatives_dual_ 4 | 5 | from .single_dissipation import eccentricity_derivative as eccentricity_derivative_ 6 | from .single_dissipation import semi_major_axis_derivative as semi_major_axis_derivative_ 7 | from .single_dissipation import semia_eccen_derivatives as semia_eccen_derivatives_ 8 | from .single_dissipation import spin_rate_derivative as spin_rate_derivative 9 | 10 | eccentricity_derivative_dual = eccentricity_derivative_dual_ 11 | semi_major_axis_derivative_dual = semi_major_axis_derivative_dual_ 12 | semia_eccen_derivatives_dual = semia_eccen_derivatives_dual_ 13 | eccentricity_derivative = eccentricity_derivative_ 14 | semi_major_axis_derivative = semi_major_axis_derivative_ 15 | semia_eccen_derivatives = semia_eccen_derivatives_ 16 | -------------------------------------------------------------------------------- /TidalPy/output.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | 3 | import TidalPy 4 | from TidalPy.logger import get_logger 5 | 6 | log = get_logger("TidalPy") 7 | 8 | def set_output_dir(new_output_dir: str) -> str: 9 | """Sets new output directory for TidalPy data and logs. 10 | 11 | Parameters 12 | ---------- 13 | new_output_dir : str 14 | New output directory. TidalPy will create a new directory if it does not exist. 15 | 16 | Returns 17 | ------- 18 | str 19 | New output directory. 20 | """ 21 | 22 | assert type(new_output_dir) is str 23 | log.debug(f'TidalPy output directory changing to {new_output_dir}.') 24 | TidalPy._output_path = new_output_dir 25 | return new_output_dir 26 | 27 | def create_output_dir() -> str: 28 | """Creates an output directory for TidalPy data. 29 | 30 | Returns 31 | ------- 32 | str 33 | Path to output directory. 34 | """ 35 | 36 | Path(TidalPy._output_path).mkdir(parents=True, exist_ok=True) 37 | return TidalPy._output_path 38 | 39 | -------------------------------------------------------------------------------- /TidalPy/rheology/partial_melt/__init__.py: -------------------------------------------------------------------------------- 1 | from TidalPy.utilities.classes.model.model_utils import build_model_default_inputs, find_all_models 2 | 3 | import TidalPy 4 | from . import melting_models as partial_melting_models 5 | 6 | known_models, known_model_const_args, known_model_live_args = find_all_models(partial_melting_models) 7 | 8 | 9 | def get_partial_melt_model_default_inputs(layer_type: str): 10 | return build_model_default_inputs(known_model_const_args, 11 | TidalPy.config['layers'], 12 | inner_keys=(layer_type, 'partial_melting')) 13 | 14 | 15 | from .partialmelt import PartialMelt as PartialMelt 16 | from .partialmelt import calculate_melt_fraction as calculate_melt_fraction 17 | from .partialmelt import calculate_temperature_frommelt as calculate_temperature_frommelt 18 | from .partialmelt import calculate_temperature_frommelt_array as calculate_temperature_frommelt_array 19 | from .partialmelt import calculate_melt_fraction_array as calculate_melt_fraction_array 20 | -------------------------------------------------------------------------------- /TidalPy/tides/__init__.py: -------------------------------------------------------------------------------- 1 | from .love1d import complex_love 2 | from .love1d import complex_love_general 3 | from .love1d import effective_rigidity 4 | from .love1d import effective_rigidity_general 5 | from .love1d import static_love 6 | from .love1d import static_love_general 7 | 8 | from .methods import TidesBase as TidesBase 9 | from .methods import GlobalApproxTides as GlobalApproxTides 10 | from .methods import LayeredTides as LayeredTides 11 | 12 | from .dissipation import calc_tidal_susceptibility as calc_tidal_susceptibility 13 | from .dissipation import calc_tidal_susceptibility_reduced as calc_tidal_susceptibility_reduced 14 | 15 | from .heating import calculate_volumetric_heating as calculate_volumetric_heating 16 | # Alias functions 17 | 18 | calc_complex_love = complex_love 19 | calc_complex_love_general = complex_love_general 20 | calc_effective_rigidity = effective_rigidity 21 | calc_static_love = static_love 22 | calc_static_love_general = static_love_general 23 | calc_effective_rigidity_general = effective_rigidity_general 24 | -------------------------------------------------------------------------------- /TidalPy/utilities/types.py: -------------------------------------------------------------------------------- 1 | from typing import Union 2 | 3 | import numpy as np 4 | 5 | # General helpers 6 | NoneType = type(None) 7 | 8 | # Numpy and Array type lists 9 | float_like = [float, np.float64] 10 | floatarray_like = [float, np.float64, np.ndarray] 11 | int_like = [int, np.int32, np.int64] 12 | 13 | numpy_float_info = np.finfo(dtype=np.float64) 14 | float_eps = numpy_float_info.eps 15 | float_max = numpy_float_info.max 16 | float_min = numpy_float_info.min 17 | float_log10_max = np.log10(float_max) 18 | float_lognat_max = np.log(float_max) 19 | 20 | # Other type lists 21 | list_like = [list, tuple, set] 22 | 23 | # Type-annotation helpers 24 | NumericalType = Union[float, int, complex, np.float64, np.int64] 25 | FloatArray = Union[float, np.float64, np.ndarray] 26 | ComplexArray = Union[complex, np.complex128, np.ndarray] 27 | NumArray = Union[FloatArray, ComplexArray] 28 | TupleNone = Union[tuple, NoneType] 29 | ArrayNone = Union[np.ndarray, NoneType] 30 | FloatNone = Union[NoneType, float] 31 | -------------------------------------------------------------------------------- /TidalPy/WorldPack/europa.toml: -------------------------------------------------------------------------------- 1 | name = "Europa" 2 | type = "burnman" 3 | radius = 1561000.0 4 | orbital_period = 3.551181 5 | eccentricity = 0.01 6 | spin_period = 3.551181 7 | albedo = 0.67 8 | force_spin_sync = true 9 | 10 | [layers.Core] 11 | type = "iron" 12 | is_tidal = false 13 | radius = 599000.0 14 | material = [ "Pyrite", "Fe_Dewaele",] 15 | material_source = [ "TidalPy", "other",] 16 | material_fractions = [ 0.5, 0.5,] 17 | temperature_mode = "user-defined" 18 | temperature_fixed = 1800.0 19 | 20 | [layers.Mantle] 21 | type = "rock" 22 | is_tidal = false 23 | radius = 1421000.0 24 | material = [ "forsterite", "mg_perovskite",] 25 | material_source = [ "SLB_2011", "SLB_2011",] 26 | material_fractions = [ 0.65, 0.35,] 27 | temperature_mode = "adiabatic" 28 | temperature_top = 1800.0 29 | surface_temperature = 273.15 30 | 31 | [layers.Crust] 32 | type = "ice" 33 | is_tidal = true 34 | radius = 1561000.0 35 | material = "LowPressureIceConst" 36 | material_source = "TidalPy" 37 | temperature_mode = "user-defined" 38 | surface_temperature = 100.0 39 | temperature_fixed = 100.0 40 | -------------------------------------------------------------------------------- /Tests/Test_Old/Test_SetA_Package/test_io.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | 3 | from TidalPy.paths import timestamped_str, unique_path 4 | 5 | 6 | def test_timestamp(): 7 | """ Test the timestamp to string function """ 8 | 9 | time_str = timestamped_str() 10 | assert type(time_str) == str 11 | 12 | time_str = timestamped_str(string_to_stamp='', date=False, time=False, second=False) 13 | assert time_str == '' 14 | 15 | time_str = timestamped_str(string_to_stamp='Hello', date=True, time=True, second=True) 16 | assert type(time_str) == str 17 | 18 | now = datetime.now() 19 | time_str = timestamped_str(string_to_stamp='Hello', date=True, time=True, second=True, provided_datetime=now) 20 | assert type(time_str) == str 21 | 22 | 23 | def test_uniquepath(): 24 | """ Test the unique path function """ 25 | 26 | new_path = unique_path(attempt_path='Test', is_dir=False, make_dir=False) 27 | assert type(new_path) == str 28 | 29 | new_path = unique_path(attempt_path='Test', is_dir=True, make_dir=False) 30 | assert type(new_path) == str 31 | -------------------------------------------------------------------------------- /TidalPy/Extending/burnman/burnman_defaultc.py: -------------------------------------------------------------------------------- 1 | default_burnman_configs = { 2 | 'worlds': { 3 | 'types': { 4 | 'burnman': { 5 | 'name' : 'unknown_world_burnman_type', 6 | 'store_tides_config_in_world' : True, 7 | 'force_spin_sync' : True, 8 | 'equilibrium_insolation_model' : 'williams', 9 | 'fraction_internal_heating_to_surface': 1.0, 10 | 'emissivity' : 0.9, 11 | 'albedo' : 0.3, 12 | 'use_real_moi' : True, 13 | 'tides_on' : True, 14 | 'surface_pressure' : 0., 15 | 'slices' : None, 16 | 'bm_interpolation_method' : 'mid', # Options: mid, avg, median 17 | 'bm_interpolation_n' : 100 18 | } 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /TidalPy/WorldPack/earth.toml: -------------------------------------------------------------------------------- 1 | name = "Earth" 2 | type = "burnman" 3 | radius = 6371000.0 4 | semi_major_axis = 1.0 5 | semi_major_axis_in_au = true 6 | eccentricity = 0.01671022 7 | spin_period = 1.0 8 | 9 | [layers.Inner_Core] 10 | type = "iron" 11 | is_tidal = false 12 | radius = 1220000.0 13 | material = "Fe_Dewaele" 14 | material_source = "other" 15 | temperature_mode = "user-defined" 16 | temperature_fixed = 300.0 17 | 18 | [layers.Outer_Core] 19 | type = "iron" 20 | is_tidal = false 21 | radius = 3480000.0 22 | material = "Liquid_Fe_Anderson" 23 | material_source = "other" 24 | temperature_mode = "user-defined" 25 | temperature_fixed = 300.0 26 | 27 | [layers.Lower_Mantle] 28 | type = "rock" 29 | is_tidal = false 30 | radius = 5711000.0 31 | material = "mg_bridgmanite" 32 | material_source = "SLB_2011" 33 | temperature_mode = "adiabatic" 34 | 35 | [layers.Upper_Mantle] 36 | type = "rock" 37 | is_tidal = true 38 | radius = 6371000.0 39 | material = "forsterite" 40 | material_source = "SLB_2011" 41 | temperature_mode = "adiabatic" 42 | temperature_top = 1200.0 43 | surface_temperature = 300.0 44 | -------------------------------------------------------------------------------- /TidalPy/WorldPack/mercury.toml: -------------------------------------------------------------------------------- 1 | # Pulled from central results of Goossens+2021 2 | 3 | name = "Mercury" 4 | type = "burnman" 5 | radius = 2440000.0 6 | semi_major_axis = 0.38709893 7 | semi_major_axis_in_au = true 8 | eccentricity = 0.20563069 9 | spin_period = 58.6462 10 | force_spin_sync = false 11 | 12 | [layers.Inner_Core] 13 | type = "iron" 14 | is_tidal = false 15 | radius = 1277250.0 16 | material = [ "Pyrite", "Fe_Dewaele",] 17 | material_source = [ "TidalPy", "other",] 18 | material_fractions = [ 0.8, 0.2,] 19 | temperature_mode = "user-defined" 20 | temperature_fixed = 2100.0 21 | 22 | [layers.Outer_Core] 23 | type = "iron" 24 | is_tidal = false 25 | radius = 1965000.0 26 | material = [ "Pyrite", "Fe_Dewaele",] 27 | material_source = [ "TidalPy", "other",] 28 | material_fractions = [ 0.8, 0.2,] 29 | temperature_mode = "adiabatic" 30 | temperature_fixed = 2100.0 31 | 32 | [layers.Mantle] 33 | type = "rock" 34 | is_tidal = true 35 | radius = 2440000.0 36 | material = "forsterite" 37 | material_source = "SLB_2011" 38 | temperature_mode = "adiabatic" 39 | temperature_top = 1200.0 40 | surface_temperature = 452.0 41 | -------------------------------------------------------------------------------- /Tests/Test_Old/Test_SetE_Functional/test_a_performance_funcs.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from scipy.special import gamma 3 | 4 | 5 | 6 | 7 | def test_find_factorial(): 8 | # Test Load 9 | from TidalPy.utilities.performance import find_factorial 10 | assert type(find_factorial(1.)) in [float, np.float64] 11 | 12 | # Test Floats 13 | assert find_factorial(0.) == 1. 14 | np.testing.assert_approx_equal(find_factorial(0.1), gamma(0.1 + 1)) 15 | np.testing.assert_approx_equal(find_factorial(0.2), gamma(0.2 + 1)) 16 | np.testing.assert_approx_equal(find_factorial(0.3), gamma(0.3 + 1)) 17 | np.testing.assert_approx_equal(find_factorial(0.45), gamma(0.45 + 1)) 18 | np.testing.assert_approx_equal(find_factorial(0.5), gamma(0.5 + 1)) 19 | np.testing.assert_approx_equal(find_factorial(0.75), gamma(0.75 + 1)) 20 | np.testing.assert_approx_equal(find_factorial(0.9), gamma(0.9 + 1)) 21 | np.testing.assert_approx_equal(find_factorial(3.0), gamma(3.0 + 1)) 22 | np.testing.assert_approx_equal(find_factorial(-1.0), gamma(-1.0 + 1)) 23 | np.testing.assert_approx_equal(find_factorial(-2.0), gamma(-2.0 + 1)) 24 | assert find_factorial(1.) == 1. 25 | -------------------------------------------------------------------------------- /TidalPy/utilities/integration/numbalsoda_helper.py: -------------------------------------------------------------------------------- 1 | from typing import Tuple 2 | 3 | import numpy as np 4 | 5 | from numba import cfunc 6 | import numba as nb 7 | 8 | from . import lsoda_sig, lsoda 9 | 10 | 11 | def numbalsoda_solver( 12 | diffeq, time_span: Tuple[float, float], initial_condition: np.ndarray, args: Tuple = None, 13 | rtol: float = 1.0e-6, atol: float = 1.0e-8, max_step: float = np.inf, 14 | first_step: float = None, method: int = 1, t_eval: np.ndarray = None 15 | ): 16 | 17 | if t_eval is None: 18 | raise ValueError('t_eval required for NumbaLSOSA') 19 | 20 | shape = initial_condition.shape 21 | 22 | @cfunc(lsoda_sig) 23 | def new_diffeq(t, u, du, p): 24 | u_ = nb.carray(u, shape) 25 | out = diffeq(t, u_, *args) 26 | for i in range(u_.size): 27 | du[i] = out[i] 28 | 29 | new_diffeq_pointer = new_diffeq.address 30 | 31 | solution, success = lsoda(new_diffeq_pointer, initial_condition, t_eval, rtol=rtol, atol=atol) 32 | 33 | message = 'None' 34 | 35 | # Convert solution to transpose 36 | solution = solution.T 37 | 38 | return t_eval, solution, success, message 39 | -------------------------------------------------------------------------------- /Papers/2025-JOSS/figures/trappist1e-bm.toml: -------------------------------------------------------------------------------- 1 | # Radius: Delrez et al., (2018) corrected by Kane et al., (2018) 2 | # Masses: Grimm et al., (2018) 3 | # Gravity: g*mass/(R2) 4 | # Flux: Delrez et al., (2018) corrected by Kane et al., (2018) 5 | # Density (Jontof-Hutter et al., 2014): radii: Delrez et al., (2018) + masses: Grimm e al (2018) corrected by Kane et al., (2018) 6 | # Updated using the analysis done by Agol+2020 and references therein. 7 | 8 | name = "TRAPPIST-1e-bm" 9 | type = "layered" 10 | radius = 5868000.0 11 | radius_error_pos = 82000.0 12 | radius_error_neg = 75000.0 13 | mass = 2.316e+24 14 | mass_error_pos = 1.3e+23 15 | mass_error_neg = 1.3e+23 16 | semi_major_axis = 4376000000.0 17 | semi_major_axis_error_pos = 37000000.0 18 | semi_major_axis_error_neg = 37000000.0 19 | semi_major_axis_in_au = false 20 | eccentricity = 0.00447 21 | eccentricity_error_pos = 0.00014 22 | eccentricity_error_neg = 0.00014 23 | force_spin_sync = true 24 | 25 | [tides] 26 | model = "global_approx" 27 | fixed_q = 100.0 28 | 29 | [layers.Core] 30 | type = "iron" 31 | is_tidal = false 32 | radius = 1760400.0 33 | density = 12000.0 34 | 35 | [layers.Mantle] 36 | type = "rock" 37 | is_tidal = true 38 | radius = 5868000.0 39 | density = 3300.0 40 | -------------------------------------------------------------------------------- /TidalPy/structures/world_types/__init__.py: -------------------------------------------------------------------------------- 1 | from typing import Union 2 | 3 | from .basic import BaseWorld 4 | from .gas import GasGiantLayeredWorld, GasGiantWorld 5 | from .layered import LayeredWorld 6 | from .stellar import StarWorld 7 | from .tidal import TidalWorld 8 | 9 | AllWorldType = Union[BaseWorld, TidalWorld, GasGiantWorld, StarWorld, LayeredWorld, GasGiantLayeredWorld] 10 | GasStarWorldType = Union[GasGiantWorld, StarWorld] 11 | LayeredWorldType = Union[LayeredWorld, GasGiantLayeredWorld] 12 | TidalWorldType = Union[GasStarWorldType, TidalWorld, LayeredWorld] 13 | 14 | all_world_types = (BaseWorld, TidalWorld, GasGiantWorld, StarWorld, LayeredWorld, GasGiantLayeredWorld) 15 | all_tidal_world_types = (GasGiantWorld, StarWorld, TidalWorld, LayeredWorld, GasGiantLayeredWorld) 16 | 17 | world_types = { 18 | 'star' : StarWorld, 19 | 'gas' : GasGiantWorld, 20 | 'gas_giant' : GasGiantWorld, 21 | 'gas_layered' : GasGiantLayeredWorld, 22 | 'layered_gas_giant': GasGiantLayeredWorld, 23 | 'layered_ice_giant': GasGiantLayeredWorld, 24 | 'ice_giant' : GasGiantWorld, 25 | 'simple_tide' : TidalWorld, 26 | 'simple_tidal' : TidalWorld, 27 | 'layered' : LayeredWorld 28 | } 29 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | # MANIFEST.in 2 | 3 | # Exclude all c++ and c files; we will manually add back in some custom ones. 4 | # This avoids shipping already cythonized c files that need to be cythonized locally. 5 | exclude **/*.c 6 | exclude **/*.cpp 7 | exclude **/*.h 8 | exclude **/*.hpp 9 | 10 | # Include data files used for plotting and benchmarking 11 | include TidalPy/utilities/graphics/multilayer/*.csv 12 | 13 | # Include World Configuration Files 14 | include TidalPy/WorldPack/*.zip 15 | 16 | # Include Cython pyx and pxd files 17 | global-include *.pxd 18 | global-include *.pyx 19 | include cython_extensions.json 20 | 21 | # Include required hpp and cpp files 22 | include TidalPy/utilities/arrays/interp_.cpp 23 | include TidalPy/utilities/arrays/interp_.hpp 24 | include TidalPy/RadialSolver/love_.cpp 25 | include TidalPy/RadialSolver/love_.hpp 26 | include TidalPy/RadialSolver/rs_solution_.cpp 27 | include TidalPy/RadialSolver/rs_solution_.hpp 28 | include TidalPy/Material/eos/eos_solution_.cpp 29 | include TidalPy/Material/eos/eos_solution_.hpp 30 | include TidalPy/utilities/dimensions/nondimensional_.hpp 31 | 32 | # Exclude the whole Tests folder 33 | prune .vscode 34 | prune .idea 35 | prune .github 36 | prune Tests 37 | prune Papers 38 | prune Demos 39 | prune Documentation 40 | prune Benchmarks -------------------------------------------------------------------------------- /TidalPy/RadialSolver/starting/takeuchi.pxd: -------------------------------------------------------------------------------- 1 | cdef void cf_takeuchi_solid_dynamic_compressible( 2 | double frequency, 3 | double radius, 4 | double density, 5 | double complex bulk_modulus, 6 | double complex shear_modulus, 7 | int degree_l, 8 | double G_to_use, 9 | size_t num_ys, 10 | double complex* starting_conditions_ptr 11 | ) noexcept nogil 12 | 13 | cdef void cf_takeuchi_solid_static_compressible( 14 | double radius, 15 | double density, 16 | double complex bulk_modulus, 17 | double complex shear_modulus, 18 | int degree_l, 19 | double G_to_use, 20 | size_t num_ys, 21 | double complex* starting_conditions_ptr 22 | ) noexcept nogil 23 | 24 | ######################################################################################################################## 25 | #### Liquid Layers 26 | ######################################################################################################################## 27 | 28 | cdef void cf_takeuchi_liquid_dynamic_compressible( 29 | double frequency, 30 | double radius, 31 | double density, 32 | double complex bulk_modulus, 33 | int degree_l, 34 | double G_to_use, 35 | size_t num_ys, 36 | double complex* starting_conditions_ptr 37 | ) noexcept nogil -------------------------------------------------------------------------------- /TidalPy/structures/world_types/gas.py: -------------------------------------------------------------------------------- 1 | from TidalPy.exceptions import NotYetImplementedError 2 | 3 | from .layered import LayeredWorld 4 | from .tidal import TidalWorld 5 | 6 | 7 | class GasGiantWorld(TidalWorld): 8 | """ GasGiantWorld 9 | Worlds that are simple gas giants and dissipate tidal energy through the CPL/CTL method (or not at all). 10 | 11 | 12 | See Also 13 | -------- 14 | Parent Class: 15 | TidalPy.structures.world_types.TidalWorld 16 | """ 17 | 18 | world_class = 'gas_giant' 19 | 20 | 21 | class GasGiantLayeredWorld(LayeredWorld): 22 | """ GasGiantLayeredWorld 23 | Worlds that are gas or ice giants and dissipate tidal energy through either the CPL/CTL method or a more complex 24 | rheology. 25 | 26 | These world types are not implemented as of at lease v0.2.1 27 | 28 | 29 | See Also 30 | -------- 31 | Parent Class: 32 | TidalPy.structures.world_types.LayeredWorld 33 | """ 34 | 35 | world_class = 'gas_giant_layered' 36 | 37 | def __init__(self, world_config: dict, name: str = None, initialize: bool = True): 38 | raise NotYetImplementedError( 39 | 'Layered Gas Giant world_types are not yet implemented. You could try to hack a regular LayeredWorld instead.' 40 | ) 41 | -------------------------------------------------------------------------------- /TidalPy/tides/potential/__init__.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, Tuple, TYPE_CHECKING 2 | 3 | 4 | from .synchronous_low_e import tidal_potential as tidal_potential_simple 5 | from .nsr_modes_med_eccen_no_obliquity import tidal_potential as tidal_potential_nsr_modes 6 | from .nsr_med_eccen_no_obliquity import tidal_potential as tidal_potential_nsr 7 | from .nsr_med_eccen_med_obliquity import tidal_potential as tidal_potential_obliquity_nsr 8 | from .nsr_med_eccen_gen_obliquity import tidal_potential as tidal_potential_gen_obliquity_nsr 9 | from .nsr_modes_med_eccen_med_obliquity import tidal_potential as tidal_potential_obliquity_nsr_modes 10 | from .nsr_modes_med_eccen_gen_obliquity import tidal_potential as tidal_potential_gen_obliquity_nsr_modes 11 | from .nsr_modes_low_eccen_gen_obliquity import tidal_potential as tidal_potential_gen_obliquity_low_e_nsr_modes 12 | 13 | if TYPE_CHECKING: 14 | from TidalPy.utilities.types import FloatArray 15 | 16 | TidalPotentialOutput = Tuple['FloatArray', 'FloatArray', 'FloatArray', 'FloatArray', 'FloatArray', 'FloatArray'] 17 | PotentialTupleModeOutput = Dict[str, Tuple['FloatArray', 'FloatArray', 'FloatArray', 'FloatArray', 'FloatArray', 'FloatArray']] 18 | TidalPotentialModeOutput = Tuple[Dict[str, 'FloatArray'], Dict[str, 'FloatArray'], PotentialTupleModeOutput] 19 | -------------------------------------------------------------------------------- /Tests/Test_Old/Test_SetB_Package/test_i_spherical_mass.py: -------------------------------------------------------------------------------- 1 | """ Tests for spherical helper function to calculate the volume of spherical voxels. """ 2 | 3 | import numpy as np 4 | 5 | 6 | 7 | from TidalPy.constants import G 8 | from TidalPy.utilities.spherical_helper.mass import calculate_mass_gravity_arrays 9 | 10 | radius = np.linspace(0.01e3, 6378.1e3, 50) 11 | layer_0 = radius < 3483.e3 12 | layer_1 = radius >= 3483.e3 13 | l1_n = len(radius[layer_1]) 14 | density = np.zeros_like(radius) 15 | density[layer_0] = 10000. 16 | density[layer_1] = 4500. 17 | 18 | 19 | def test_calculate_mass_gravity_arrays(): 20 | """ Test the calculation of volume, mass, and gravity from radius and density arrays. """ 21 | 22 | volumes, masses, gravities = calculate_mass_gravity_arrays(radius, density) 23 | 24 | # Check array sizes 25 | assert len(volumes) == len(radius) 26 | assert len(masses) == len(radius) 27 | assert len(gravities) == len(radius) 28 | 29 | # Check values 30 | real_volume = (4. / 3.) * np.pi * radius[-1]**3 31 | np.testing.assert_almost_equal(np.abs(np.sum(volumes) - real_volume)/real_volume, 0.) 32 | mass = np.sum(masses) 33 | real_gravity_surf = G * mass / radius[-1]**2 34 | np.testing.assert_almost_equal(np.abs(gravities[-1] - real_gravity_surf)/real_gravity_surf, 0.) -------------------------------------------------------------------------------- /TidalPy/RadialSolver/shooting.pxd: -------------------------------------------------------------------------------- 1 | from libcpp cimport bool as cpp_bool 2 | from libcpp.memory cimport shared_ptr 3 | from libcpp.vector cimport vector 4 | 5 | from CyRK cimport ODEMethod 6 | 7 | from TidalPy.RadialSolver.rs_solution cimport RadialSolutionStorageCC 8 | 9 | 10 | cdef size_t cf_find_num_shooting_solutions( 11 | int layer_type, 12 | bint is_static, 13 | bint is_incompressible 14 | ) noexcept nogil 15 | 16 | 17 | cdef int cf_shooting_solver( 18 | RadialSolutionStorageCC* solution_storage_ptr, 19 | double frequency, 20 | double planet_bulk_density, 21 | int* layer_types_ptr, 22 | bint* is_static_by_layer_ptr, 23 | bint* is_incompressible_by_layer_ptr, 24 | vector[size_t] first_slice_index_by_layer_vec, 25 | vector[size_t] num_slices_by_layer_vec, 26 | size_t num_bc_models, 27 | int* bc_models_ptr, 28 | double G_to_use, 29 | int degree_l, 30 | cpp_bool use_kamata, 31 | double starting_radius, 32 | double start_radius_tolerance, 33 | ODEMethod integration_method, 34 | double integration_rtol, 35 | double integration_atol, 36 | cpp_bool scale_rtols_by_layer_type, 37 | size_t max_num_steps, 38 | size_t expected_size, 39 | size_t max_ram_MB, 40 | double max_step, 41 | cpp_bool verbose 42 | ) noexcept nogil 43 | -------------------------------------------------------------------------------- /TidalPy/Extending/burnman/material/custom/pyrite.py: -------------------------------------------------------------------------------- 1 | from TidalPy.Extending.burnman import burnman_installed, Mineral 2 | 3 | 4 | class Pyrite(Mineral): 5 | 6 | def __init__(self): 7 | 8 | if not burnman_installed: 9 | raise ImportError('Burnman package not found.') 10 | 11 | """ Parameters from Thompson et al, 2016 in American Mineralogist Vol 101, Page 1046""" 12 | self.params = { 13 | 'formula' : {'Fe': 1., 'Si': 2.}, 14 | 'equation_of_state': 'bm3', 15 | 'K_0' : 140.2e9, 16 | 'Kprime_0' : 5.52, 17 | 'grueneisen_0' : 1.4, 18 | 'Debye_0' : 624., 19 | 'V_0' : 2.393e-5, 20 | 'q_0' : 2.06, 21 | 'molar_mass' : 119.9750 / 1000., 22 | 'n' : 3, 23 | # Shear information is from Whitaker & Wang 2010 Journal of Earth Science Vol 21 No 5 p. 792 24 | 'G_0' : 112.3e9, # From Whitaker & Wang 2010 Journal of Earth Science Vol 21 No 5 p. 792 25 | 'Gprime_0' : 3.0, 26 | # Merkel et al (2002) in Physics and Chemistry of Minerals Vol 29 page 1) had slightly higher value (126e9) 27 | } 28 | 29 | Mineral.__init__(self) 30 | -------------------------------------------------------------------------------- /TidalPy/rheology/models.pxd: -------------------------------------------------------------------------------- 1 | from TidalPy.rheology.base cimport RheologyModelBase 2 | 3 | ######################################################################################################################## 4 | ######################################## New Rheological Models Go Below Here! ######################################### 5 | ######################################################################################################################## 6 | 7 | cdef class Elastic(RheologyModelBase): 8 | pass 9 | 10 | cdef class Newton(RheologyModelBase): 11 | pass 12 | 13 | cdef class Maxwell(RheologyModelBase): 14 | pass 15 | 16 | cdef class Voigt(RheologyModelBase): 17 | cdef double voigt_modulus_scale 18 | cdef double voigt_viscosity_scale 19 | 20 | cdef class Burgers(RheologyModelBase): 21 | cdef double voigt_modulus_scale 22 | cdef double voigt_viscosity_scale 23 | 24 | cdef class Andrade(RheologyModelBase): 25 | cdef double alpha 26 | cdef double alpha_factorial 27 | cdef double zeta 28 | cdef double complex sine_term 29 | 30 | cdef class SundbergCooper(RheologyModelBase): 31 | cdef double voigt_modulus_scale 32 | cdef double voigt_viscosity_scale 33 | cdef double alpha 34 | cdef double alpha_factorial 35 | cdef double zeta 36 | cdef double complex sine_term 37 | -------------------------------------------------------------------------------- /Documentation/_static/custom.css: -------------------------------------------------------------------------------- 1 | /* Change background behind logo/search area */ 2 | .wy-side-nav-search { 3 | background-color: #1f2a44; 4 | /* Other good ones: #655A7C; #1f2a44 */ 5 | } 6 | 7 | .version-switch select { 8 | color: white !important; 9 | } 10 | 11 | .wy-menu .caption-text { 12 | color: #8ee2f2; 13 | } 14 | 15 | .document .caption-text { 16 | color: #1f2a44; 17 | } 18 | 19 | /* Fix spacing in directory listing on main page body. */ 20 | /* Remove space after headers */ 21 | .rst-content h1, 22 | .rst-content h2, 23 | .rst-content h3, 24 | .rst-content h4, 25 | .rst-content h5, 26 | .rst-content h6 { 27 | margin-bottom: 0 !important; 28 | margin-bottom: 10px !important; 29 | } 30 | 31 | .rst-content .toctree-wrapper > p.caption { 32 | margin-top: 0 !important; 33 | margin-bottom: 0 !important; 34 | } 35 | 36 | /* Remove space before/after ul lists */ 37 | .rst-content ul { 38 | margin-top: 0 !important; 39 | margin-bottom: 0 !important; 40 | } 41 | 42 | /* If you also want to adjust ol lists */ 43 | .rst-content ol { 44 | margin-top: 0 !important; 45 | margin-bottom: 0 !important; 46 | } 47 | 48 | /* Adjust list item spacing if needed */ 49 | .rst-content ul li, 50 | .rst-content ol li { 51 | margin-bottom: 0 !important; 52 | } -------------------------------------------------------------------------------- /TidalPy/RadialSolver/love.pyx: -------------------------------------------------------------------------------- 1 | # distutils: language = c++ 2 | # cython: boundscheck=False, wraparound=False, nonecheck=False, cdivision=True, initializedcheck=False 3 | 4 | def find_love( 5 | double complex[::1] complex_love_numbers_view, 6 | double complex[::1] surface_solutions_view, 7 | double surface_gravity 8 | ): 9 | """ 10 | Find the complex Love and Shida numbers given the surface radial solutions for a planet. 11 | 12 | Parameters 13 | ---------- 14 | complex_love_numbers_view : double complex[::1], array, output 15 | Array to store complex Love numbers. There must be space for 3 double complex numbers. 16 | surface_solutions_view : double complex[::1], array, input 17 | Array of radial solutions (y_i) values at the surface of a planet. 18 | surface_gravity : double, input 19 | Acceleration due to gravity at the planet's surface [m s-2]. 20 | """ 21 | 22 | # Create pointers; the c++ functions only work with doubles so we need to cast them to double 23 | cdef double* complex_love_numbers_ptr = &complex_love_numbers_view[0] 24 | cdef double* surface_solutions_ptr = &surface_solutions_view[0] 25 | 26 | return find_love_cf( 27 | complex_love_numbers_ptr, 28 | surface_solutions_ptr, 29 | surface_gravity 30 | ) 31 | -------------------------------------------------------------------------------- /TidalPy/utilities/io/pathing.py: -------------------------------------------------------------------------------- 1 | import os 2 | from typing import Dict, List, Union 3 | 4 | 5 | def get_all_files_of_type(directory_to_search: str, file_extensions: Union[List[str], str]) -> Dict[str, str]: 6 | """ Returns all files with a specified extension(s) in a given directory 7 | 8 | Parameters 9 | ---------- 10 | directory_to_search : str 11 | The directory to search for files in. 12 | file_extensions : Union[List[str], str] 13 | Extension, or list of extensions, to search for. 14 | 15 | Returns 16 | ------- 17 | files : Dict[str, str] 18 | Dictionary of files stored as file_name: file_path 19 | """ 20 | 21 | if type(file_extensions) is str: 22 | file_extensions = list(file_extensions) 23 | # splitext retains the first period, the user may not have expected that 24 | for e_i, extension in enumerate(file_extensions): 25 | if extension[0] != '.': 26 | file_extensions[e_i] = f'.{extension}' 27 | 28 | files = dict() 29 | # Only pull out files, not sub-directories 30 | only_files = [f for f in os.listdir(directory_to_search) 31 | if os.path.isfile(os.path.join(directory_to_search, f))] 32 | 33 | for file_with_extension in only_files: 34 | filename, extension = os.path.splitext(file_with_extension) 35 | if extension in file_extensions: 36 | files[filename] = os.path.join(directory_to_search, file_with_extension) 37 | 38 | return files 39 | -------------------------------------------------------------------------------- /Tests/Test_Old/Test_SetB_Package/test_b_utilities_numpy.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | from TidalPy.utilities.numpy_helper.array_other import neg_array_for_log_plot, normalize_dict 4 | 5 | 6 | def test_normalize_dict(): 7 | """ Tests the normalize_dict function """ 8 | 9 | # Test with floats 10 | test_dict = { 11 | 'a': 102.0, 12 | 'b': 121.2, 13 | 'c': -12.0 14 | } 15 | 16 | result = normalize_dict(test_dict, pass_negatives=False, new_max=1.0, new_min=0.0) 17 | 18 | assert type(result) == dict 19 | assert type(result['a']) in [float, np.float64] 20 | assert type(result['b']) in [float, np.float64] 21 | assert type(result['c']) in [float, np.float64] 22 | 23 | np.testing.assert_allclose(result['b'], 1.0) 24 | np.testing.assert_allclose(result['c'] + 1.0, 1.0) 25 | assert result['b'] > result['a'] > result['c'] 26 | 27 | result = normalize_dict(test_dict, pass_negatives=False, new_max=3.2, new_min=-10.0) 28 | 29 | np.testing.assert_allclose(result['b'], 3.2) 30 | np.testing.assert_allclose(result['c'], -10.0) 31 | assert result['b'] > result['a'] > result['c'] 32 | 33 | 34 | def test_neg_array_for_plot(): 35 | """ Test function neg_array_for_log_plot """ 36 | 37 | x = np.linspace(-10, 10, 10) 38 | y_p, y_n = neg_array_for_log_plot(x) 39 | 40 | assert np.all(y_p[~np.isnan(y_p)] >= 0.0) 41 | assert np.all(y_n[~np.isnan(y_n)] >= 0.0) 42 | assert np.all(np.isnan(y_p[x < 0.0])) 43 | assert np.all(np.isnan(y_n[x >= 0.0])) -------------------------------------------------------------------------------- /TidalPy/RadialSolver/solver.pxd: -------------------------------------------------------------------------------- 1 | 2 | from libcpp cimport bool as cpp_bool 3 | 4 | from CyRK cimport ODEMethod 5 | 6 | from TidalPy.RadialSolver.rs_solution cimport RadialSolutionStorageCC 7 | 8 | 9 | cdef int cf_radial_solver( 10 | RadialSolutionStorageCC* solution_storage_ptr, 11 | size_t total_slices, 12 | double* radius_array_in_ptr, 13 | double* density_array_in_ptr, 14 | double complex* complex_bulk_modulus_in_ptr, 15 | double complex* complex_shear_modulus_in_ptr, 16 | double frequency, 17 | double planet_bulk_density, 18 | size_t num_layers, 19 | int* layer_types_ptr, 20 | bint* is_static_bylayer_ptr, 21 | bint* is_incompressible_bylayer_ptr, 22 | double surface_pressure, 23 | int degree_l, 24 | size_t num_bc_models, 25 | int* bc_models_ptr, 26 | int core_model, 27 | cpp_bool use_kamata, 28 | double starting_radius, 29 | double start_radius_tolerance, 30 | ODEMethod integration_method_int, 31 | double integration_rtol, 32 | double integration_atol, 33 | cpp_bool scale_rtols_bylayer_type, 34 | size_t max_num_steps, 35 | size_t expected_size, 36 | size_t max_ram_MB, 37 | double max_step, 38 | cpp_bool nondimensionalize, 39 | cpp_bool use_prop_matrix, 40 | int* eos_integration_method_int_bylayer_ptr, 41 | ODEMethod eos_integration_method, 42 | double eos_rtol, 43 | double eos_atol, 44 | double eos_pressure_tol, 45 | int eos_max_iters, 46 | cpp_bool verbose, 47 | cpp_bool warnings 48 | ) noexcept nogil 49 | -------------------------------------------------------------------------------- /TidalPy/RadialSolver/love_.cpp: -------------------------------------------------------------------------------- 1 | #include "love_.hpp" 2 | 3 | void find_love_cf( 4 | double* complex_love_numbers_ptr, // These are double pointers that pointer to a double complex array. 5 | double* surface_solutions_ptr, // Same as above 6 | double surface_gravity) 7 | { 8 | const double y1_real = surface_solutions_ptr[0]; 9 | const double y1_imag = surface_solutions_ptr[1]; 10 | const double y3_real = surface_solutions_ptr[4]; 11 | const double y3_imag = surface_solutions_ptr[5]; 12 | const double y5_real = surface_solutions_ptr[8]; 13 | const double y5_imag = surface_solutions_ptr[9]; 14 | 15 | // Calculate Love and Shida numbers 16 | // Note Im(k2) = -Im(y5) (Henning & Hurford 2014 eq. A9), opposite convention of Tobie et al. (2005, eqs. 9 & 36) 17 | // And k2 = |-y5-1| (Roberts & Nimmo 2008 equation A8), not 1-y5 as in Henning & Hurford (2014) equation A9. 18 | 19 | // Okay, some clarification on this. It looks like VS04 that HH14 is based on used a different convention for y5, 20 | // Tobie05's y5 = -y5 of SV; we follow that format here. 21 | 22 | // Love k 23 | complex_love_numbers_ptr[0] = y5_real - 1.0; 24 | complex_love_numbers_ptr[1] = y5_imag; 25 | 26 | // Love h 27 | complex_love_numbers_ptr[2] = y1_real * surface_gravity; 28 | complex_love_numbers_ptr[3] = y1_imag * surface_gravity; 29 | 30 | // Shida l 31 | complex_love_numbers_ptr[4] = y3_real * surface_gravity; 32 | complex_love_numbers_ptr[5] = y3_imag * surface_gravity; 33 | } 34 | -------------------------------------------------------------------------------- /TidalPy/utilities/math/complex.pxd: -------------------------------------------------------------------------------- 1 | from TidalPy.constants cimport d_DBL_MAX, d_DBL_MIN, d_DBL_MANT_DIG, d_NAN_DBL, d_INF_DBL 2 | 3 | cdef double complex cmplx_NAN 4 | cdef double complex cmplx_zero 5 | cdef double complex cmplx_one 6 | cdef double SQRT2 7 | cdef double LOGE2 8 | cdef double SQRT2_INV 9 | cdef double THRESH 10 | cdef double DBL_MAX_4 11 | cdef int SCALED_CEXP_K_F 12 | cdef int SCALED_CEXP_K_D 13 | cdef int SCALED_CEXP_K_LD 14 | cdef double SCALED_K_LOGE2_D 15 | cdef float SCALED_CEXP_LOWERF 16 | cdef float SCALED_CEXP_UPPERF 17 | cdef double SCALED_CEXP_LOWER 18 | cdef double SCALED_CEXP_UPPER 19 | cdef long double SCALED_CEXP_LOWERL 20 | cdef long double SCALED_CEXP_UPPERL 21 | 22 | 23 | cdef double complex cf_build_dblcmplx(double a, double b) noexcept nogil 24 | 25 | cdef double cf_cabs(double complex z) noexcept nogil 26 | 27 | cdef double cf_cabs2(double complex z) noexcept nogil 28 | 29 | cdef double complex cf_cinv(double complex z) noexcept nogil 30 | 31 | cdef double cf_hypot(const double x, const double y) noexcept nogil 32 | 33 | cdef double complex cf_csqrt(const double complex z) noexcept nogil 34 | 35 | cdef double complex cf_scaled_cexp(const double x, const double y, const int expt) noexcept nogil 36 | 37 | cdef double complex cf_cexp(const double complex z) noexcept nogil 38 | 39 | cdef double complex cf_clog(const double complex z) noexcept nogil 40 | 41 | cdef double complex cf_cpow(const double complex a, const double complex b) noexcept nogil 42 | 43 | cdef double complex cf_cipow(const double complex a, const int b) noexcept nogil 44 | -------------------------------------------------------------------------------- /TidalPy/utilities/integration/cyrk_helper.py: -------------------------------------------------------------------------------- 1 | """ Helper functions to interface with CyRK's integration suite """ 2 | 3 | from typing import Tuple 4 | 5 | import numpy as np 6 | 7 | from TidalPy.utilities.performance import njit 8 | 9 | from . import _cyrk_ode, _nbrk_ode, _nb2cy 10 | 11 | 12 | def cyrk_solver( 13 | diffeq, time_span: Tuple[float, float], initial_condition: np.ndarray, args: Tuple = tuple(), 14 | rtol: float = 1.0e-6, atol: float = 1.0e-8, max_step: float = np.inf, 15 | first_step: float = 0., method: int = 1, t_eval: np.ndarray = np.empty((0,), dtype=np.float64), 16 | convert_func_to_cy: bool = False 17 | ): 18 | 19 | # Change the diffeq to match the desired format 20 | if convert_func_to_cy: 21 | diffeq = _nb2cy(diffeq, use_njit=True, cache_njit=True) 22 | 23 | return _cyrk_ode( 24 | diffeq, time_span, initial_condition, args=args, 25 | rtol=rtol, atol=atol, max_step=max_step, first_step=first_step, 26 | rk_method=method, t_eval=t_eval 27 | ) 28 | 29 | 30 | @njit(cacheable=True) 31 | def nbrk_solver( 32 | diffeq, time_span: Tuple[float, float], initial_condition: np.ndarray, args: Tuple = None, 33 | rtol: float = 1.0e-6, atol: float = 1.0e-8, max_step: float = np.inf, 34 | first_step: float = None, method: int = 1, t_eval: np.ndarray = np.empty((0,), dtype=np.float64) 35 | ): 36 | 37 | return _nbrk_ode( 38 | diffeq, time_span, initial_condition, args, 39 | rtol=rtol, atol=atol, max_step=max_step, first_step=first_step, 40 | rk_method=method, t_eval=t_eval 41 | ) 42 | -------------------------------------------------------------------------------- /.github/workflows/make_joss_pdf.yml: -------------------------------------------------------------------------------- 1 | name: Draft PDF 2 | 3 | on: 4 | pull_request: 5 | types: [opened, synchronize, reopened] 6 | workflow_dispatch: 7 | push: 8 | paths: 9 | - Papers/2025-JOSS/** 10 | - .github/workflows/make_joss_pdf.yml 11 | 12 | 13 | jobs: 14 | paper: 15 | runs-on: ubuntu-latest 16 | name: Paper Draft 17 | steps: 18 | - name: Checkout 19 | uses: actions/checkout@v4 20 | with: 21 | ref: ${{ github.head_ref }} # ensures a proper branch instead of detached HEAD 22 | 23 | - name: Build draft PDF 24 | uses: openjournals/openjournals-draft-action@master 25 | with: 26 | journal: joss 27 | # This should be the path to the paper within your repo. 28 | paper-path: 'Papers/2025-JOSS/paper.md' 29 | 30 | - name: Upload 31 | uses: actions/upload-artifact@v4 32 | with: 33 | name: paper 34 | # This is the output path where Pandoc will write the compiled 35 | # PDF. Note, this should be the same directory as the input 36 | # paper.md 37 | path: 'Papers/2025-JOSS/paper.pdf' 38 | 39 | - name: Commit PDF to repository 40 | uses: EndBug/add-and-commit@v9 41 | with: 42 | message: '(auto) Paper PDF Draft' 43 | # This should be the path to the paper within your repo. 44 | add: 'Papers/2025-JOSS/*.pdf' # 'paper/*.pdf' to commit all PDFs in the paper directory 45 | push: true -------------------------------------------------------------------------------- /Documentation/index.md: -------------------------------------------------------------------------------- 1 | # TidalPy Documentation 2 | 3 | ```{include} Overview/Readme.md 4 | :start-after: TidalPy 5 | :end-before: Overview 6 | ``` 7 | 8 | Please click on a page below to learn more about the package. 9 | 10 | Also check out the GitHub page to see the code. 11 | [GitHub](https://github.com/jrenaud90/TidalPy) 12 | 13 | ```{toctree} 14 | :maxdepth: 2 15 | :caption: TidalPy 16 | 17 | Overview 18 | ``` 19 | 20 | ```{toctree} 21 | :maxdepth: 2 22 | :caption: Modules 23 | 24 | Rheology 25 | RadialSolver (Love Number Calculator) 26 | Exoplanets 27 | Dynamics 28 | ``` 29 | 30 | ```{toctree} 31 | :maxdepth: 2 32 | :caption: Demos 33 | 34 | Demos/1 - Build Planets 35 | Demos/2 - Thermal Exploration 36 | Demos/3 - Calculating Love Numbers 37 | Demos/4 - Eccentricity Truncations 38 | Demos/5 - Rheology Exploration 39 | Demos/6 - Multilayer Heating 40 | Demos/7 - Comparison of Tidal Modes 41 | Demos/8 - Love Number Sensitivity 42 | ``` 43 | 44 | ```{toctree} 45 | :maxdepth: 2 46 | :caption: Auto Generated API 47 | 48 | TidalPy API 49 | ``` 50 | 51 | ```{toctree} 52 | :maxdepth: 2 53 | :caption: Additional Info 54 | :hidden: 55 | 56 | Change Log 57 | ``` -------------------------------------------------------------------------------- /TidalPy/tides/ctl_funcs/ctl_funcs.py: -------------------------------------------------------------------------------- 1 | from typing import TYPE_CHECKING 2 | 3 | from ...utilities.performance import njit 4 | 5 | if TYPE_CHECKING: 6 | from ...utilities.types import FloatArray 7 | 8 | 9 | @njit(cacheable=True) 10 | def linear_dt(frequency: 'FloatArray', fixed_dt: float): 11 | """ Estimates dissipative term of the Love number assuming a function that is inversely linear with frequency. 12 | 13 | Parameters 14 | ---------- 15 | frequency : FloatArray 16 | Frequency (the absolute value of the tidal modes) 17 | fixed_dt : float 18 | Inverse proportionality coefficient [s] 19 | 20 | Returns 21 | ------- 22 | effective_q : FloatArray 23 | The effective Q for the world 24 | """ 25 | 26 | effective_q = frequency * fixed_dt 27 | 28 | return effective_q 29 | 30 | 31 | @njit(cacheable=True) 32 | def linear_dt_with_q(frequency: 'FloatArray', fixed_dt: float, fixed_q: float): 33 | """ Estimates dissipative term of the Love number assuming a function that is linear with frequency. The fixed Q 34 | acts as an additional inverse proportionality constant. 35 | 36 | Parameters 37 | ---------- 38 | frequency : FloatArray 39 | Frequency (the absolute value of the tidal modes) 40 | fixed_dt : float 41 | Inverse proportionality coefficient [s] 42 | fixed_q : float 43 | Additional inverse proportionality coefficient 44 | 45 | Returns 46 | ------- 47 | effective_q : FloatArray 48 | The effective Q for the world 49 | """ 50 | 51 | effective_q = frequency * fixed_dt / fixed_q 52 | 53 | return effective_q 54 | -------------------------------------------------------------------------------- /TidalPy/constants.pxd: -------------------------------------------------------------------------------- 1 | # Extremes 2 | # Forcing Frequency Extremes 3 | cdef double d_MIN_FREQUENCY 4 | cdef double d_MAX_FREQUENCY 5 | 6 | # Minimum difference between spin and orbital frequency before it is treated as zero. 7 | cdef double d_MIN_SPIN_ORBITAL_DIFF 8 | 9 | # Shear/Bulk Modulus Extremes 10 | cdef double d_MIN_VISCOSITY 11 | cdef double d_MIN_MODULUS 12 | 13 | # Thickness 14 | cdef double d_MIN_THICKNESS 15 | 16 | # Mathematics 17 | cdef double d_ppm 18 | cdef double d_ppb 19 | 20 | cdef double d_PI_DBL 21 | cdef double d_DBL_MAX 22 | cdef double d_DBL_MIN 23 | cdef double d_DBL_MANT_DIG 24 | cdef double d_INF_DBL 25 | cdef double d_EPS_DBL_10 26 | cdef double d_EPS_DBL_100 27 | cdef double d_EPS_DBL 28 | cdef double d_NAN_DBL 29 | 30 | # Sun 31 | cdef double d_mass_solar 32 | cdef double d_radius_solar 33 | cdef double d_luminosity_solar 34 | 35 | # TRAPPIST-1 36 | cdef double d_mass_trap1 37 | cdef double d_radius_trap1 38 | cdef double d_luminosity_trap1 39 | 40 | # Earth 41 | cdef double d_mass_earth 42 | cdef double d_radius_earth 43 | 44 | # Jupiter 45 | cdef double d_mass_jupiter 46 | cdef double d_radius_jupiter 47 | 48 | # Pluto 49 | cdef double d_mass_pluto 50 | cdef double d_radius_pluto 51 | 52 | # Io 53 | cdef double d_mass_io 54 | cdef double d_radius_io 55 | 56 | # Alias Names 57 | cdef double d_G 58 | cdef double d_R 59 | cdef double d_Au 60 | cdef double d_sbc 61 | cdef double d_SBC 62 | cdef double d_newtons_constant 63 | 64 | cdef double d_M_sol 65 | cdef double d_M_earth 66 | cdef double d_M_jup 67 | cdef double d_M_pluto 68 | 69 | cdef double d_R_sol 70 | cdef double d_R_earth 71 | cdef double d_R_jup 72 | cdef double d_R_pluto 73 | 74 | cdef double d_L_sol 75 | -------------------------------------------------------------------------------- /TidalPy/structures/layers/gas.py: -------------------------------------------------------------------------------- 1 | from typing import TYPE_CHECKING 2 | 3 | from .basic import LayerBase 4 | 5 | if TYPE_CHECKING: 6 | from ..world_types import GasGiantLayeredWorld 7 | 8 | 9 | class GasLayer(LayerBase): 10 | """" GasLayer 11 | Layer object used to construct gas giant or ice giant planets that contain a significant gas layer. Currently, 12 | these layers do not do anything over the base layer class but allow for future functionality. 13 | 14 | Notes: 15 | .. Does not provide any functionality to perform tidal calculations (see PhysicsLayer instead) 16 | 17 | See Also 18 | -------- 19 | TidalPy.structures.layers.LayerBase 20 | """ 21 | 22 | layer_class = 'gas' 23 | 24 | def __init__( 25 | self, layer_name: str, layer_index: int, world: 'GasGiantLayeredWorld', layer_config: dict, 26 | is_top_layer: bool, initialize: bool = True 27 | ): 28 | """ Gas layer constructor 29 | 30 | Parameters 31 | ---------- 32 | layer_name : str 33 | User-friendly name of layer. 34 | layer_index : int 35 | Location of layer within a world (0 indicates center-most). 36 | world : LayeredWorldType 37 | World instance where layer was initialized in. 38 | layer_config : dict 39 | Layer's user-provided configurations. 40 | is_top_layer : bool 41 | If `True`, this layer is the top-most layer. 42 | initialize : bool = True 43 | If `True`, then the Layer's reinit is called at the end of the constructor. 44 | """ 45 | 46 | super().__init__(layer_name, layer_index, world, layer_config, is_top_layer, initialize) 47 | -------------------------------------------------------------------------------- /TidalPy/__init__.py: -------------------------------------------------------------------------------- 1 | # Find Version Number 2 | import importlib.metadata 3 | __version__ = importlib.metadata.version("TidalPy") 4 | version = __version__ 5 | 6 | # Set test_mode to False (used to turn off logging during testing) 7 | _test_mode = False 8 | 9 | import os 10 | if 'TIDALPY_TEST_MODE' in os.environ: 11 | if os.environ['TIDALPY_TEST_MODE']: 12 | _test_mode = True 13 | 14 | import time 15 | 16 | # Initial Runtime 17 | init_time = time.time() 18 | 19 | # Various properties to be set by the configuration file and initializer (these should not be changed by user) 20 | _tidalpy_init = False 21 | _in_jupyter = False 22 | _output_dir = None 23 | _config_path = None 24 | 25 | # TidalPy configurations 26 | config = None 27 | 28 | # World configuration directory 29 | world_config_dir = None 30 | 31 | # Public properties that can be changed by user 32 | extensive_logging = False 33 | extensive_checks = False 34 | 35 | # Load the TidalPy initializer and run it (user can run it later so load it with the handle `reinitialize`) 36 | from TidalPy.initialize import initialize as reinit 37 | 38 | # Call reinit for the first initialization 39 | reinit() 40 | 41 | # Import module functions 42 | from .cache import clear_cache as clear_cache 43 | from .cache import clear_data as clear_data 44 | 45 | def test_mode(): 46 | """ Turn on test mode and reinitialize TidalPy """ 47 | global _test_mode 48 | 49 | if _test_mode: 50 | # Don't need to do anything. 51 | pass 52 | else: 53 | _test_mode = True 54 | reinit() 55 | 56 | def log_to_file(): 57 | """ Quick switch to turn on saving logs to file """ 58 | if not config['logging']['write_log_to_disk']: 59 | config['logging']['write_log_to_disk'] = True 60 | reinit() 61 | -------------------------------------------------------------------------------- /TidalPy/tides/dissipation.py: -------------------------------------------------------------------------------- 1 | from typing import TYPE_CHECKING 2 | 3 | 4 | from TidalPy.constants import G 5 | from TidalPy.utilities.performance import njit 6 | 7 | if TYPE_CHECKING: 8 | from TidalPy.utilities.types import FloatArray 9 | 10 | 11 | @njit(cacheable=True) 12 | def calc_tidal_susceptibility(host_mass: float, target_radius: float, semi_major_axis: 'FloatArray') -> 'FloatArray': 13 | """ Calculate the tidal susceptibility for a given target radius, host mass, and their separation. 14 | 15 | Parameters 16 | ---------- 17 | host_mass : float 18 | Mass of central host [kg] 19 | target_radius : float 20 | Radius of target body [m] 21 | semi_major_axis : FloatArray 22 | Semi-major axis [m] 23 | 24 | Returns 25 | ------- 26 | tidal_susceptibility : FloatArray 27 | Tidal Susceptibility [N m] 28 | """ 29 | 30 | tidal_susceptibility = (3. / 2.) * G * host_mass**2 * target_radius**5 / semi_major_axis**6 31 | 32 | return tidal_susceptibility 33 | 34 | 35 | @njit(cacheable=True) 36 | def calc_tidal_susceptibility_reduced(host_mass: float, target_radius: float) -> float: 37 | """ Calculate the tidal susceptibility (reduced) for a given target radius and host mass. 38 | 39 | The reduced tidal susceptibility excludes the semi-major axis. 40 | 41 | Parameters 42 | ---------- 43 | host_mass : float 44 | Mass of central host [kg] 45 | target_radius : float 46 | Radius of target body [m] 47 | 48 | Returns 49 | ------- 50 | tidal_susceptibility_reduced : np.ndarray 51 | Tidal Susceptibility [N m] 52 | """ 53 | 54 | tidal_susceptibility_reduced = (3. / 2.) * G * host_mass**2 * target_radius**5 55 | 56 | return tidal_susceptibility_reduced 57 | -------------------------------------------------------------------------------- /TidalPy/tides/inclination_funcs/orderl2.py: -------------------------------------------------------------------------------- 1 | """ Inclination functions (squared) for tidal order-l = 2. These are exact (no truncation on I) 2 | """ 3 | 4 | from typing import TYPE_CHECKING 5 | 6 | import numpy as np 7 | 8 | from ...utilities.performance.numba import njit 9 | 10 | if TYPE_CHECKING: 11 | from . import InclinOutput 12 | from ...utilities.types import FloatArray 13 | 14 | 15 | @njit(cacheable=True) 16 | def calc_inclination_off(inclination: 'FloatArray') -> 'InclinOutput': 17 | """Calculate F^2_lmp (assuming I=0) for l = 2""" 18 | 19 | # Inclination Functions Calculated for l = 2, Inclination == off. 20 | ones_ = np.ones_like(inclination) 21 | 22 | inclination_results = { 23 | (0, 1): 0.25 * ones_, 24 | (2, 0): 9. * ones_, 25 | } 26 | 27 | return inclination_results 28 | 29 | 30 | @njit(cacheable=True) 31 | def calc_inclination(inclination: 'FloatArray') -> 'InclinOutput': 32 | """Calculate F^2_lmp for l = 2""" 33 | 34 | # Inclination Functions Calculated for l = 2. 35 | # Optimizations 36 | i = inclination 37 | i_half = i / 2. 38 | i_double = 2. * i 39 | sin_i = np.sin(i) 40 | sin_i_half = np.sin(i_half) 41 | cos_i_half = np.cos(i_half) 42 | sin_i_double = np.sin(i_double) 43 | 44 | inclination_results = { 45 | (0, 0) : 0.140625*sin_i**4, 46 | (0, 1) : (-sin_i_half**4 + sin_i_half**2 + 0.5*sin_i**2 - 0.5)**2, 47 | (0, 2) : 0.140625*sin_i**4, 48 | (1, 0) : 9.0*sin_i_half**2*cos_i_half**6, 49 | (1, 1) : 0.5625*sin_i_double**2, 50 | (1, 2) : 9.0*sin_i_half**6*cos_i_half**2, 51 | (2, 0) : 9.0*cos_i_half**8, 52 | (2, 1) : 2.25*sin_i**4, 53 | (2, 2) : 9.0*sin_i_half**8 54 | } 55 | 56 | return inclination_results 57 | -------------------------------------------------------------------------------- /TidalPy/utilities/performance/memory.py: -------------------------------------------------------------------------------- 1 | from collections import deque 2 | from itertools import chain 3 | from sys import getsizeof, stderr 4 | 5 | try: 6 | from reprlib import repr 7 | except ImportError: 8 | pass 9 | 10 | 11 | def total_size(o, handlers={}, verbose=False): 12 | """ Returns the approximate memory footprint an object and all of its contents. 13 | 14 | Automatically finds the contents of the following builtin containers and 15 | their subclasses: tuple, list, deque, dict, set and frozenset. 16 | To search other containers, add handlers to iterate over their contents: 17 | 18 | handlers = {SomeContainerClass: iter, 19 | OtherContainerClass: OtherContainerClass.get_elements} 20 | 21 | """ 22 | 23 | def dict_handler(d): 24 | return chain.from_iterable(d.items()) 25 | 26 | all_handlers = { 27 | tuple : iter, 28 | list : iter, 29 | deque : iter, 30 | dict : dict_handler, 31 | set : iter, 32 | frozenset: iter, 33 | } 34 | all_handlers.update(handlers) # user handlers take precedence 35 | seen = set() # track which object id's have already been seen 36 | default_size = getsizeof(0) # estimate sizeof object without __sizeof__ 37 | 38 | def sizeof(o): 39 | if id(o) in seen: # do not double count the same object 40 | return 0 41 | seen.add(id(o)) 42 | s = getsizeof(o, default_size) 43 | 44 | if verbose: 45 | print(s, type(o), repr(o), file=stderr) 46 | 47 | for typ, handler in all_handlers.items(): 48 | if isinstance(o, typ): 49 | s += sum(map(sizeof, handler(o))) 50 | break 51 | return s 52 | 53 | return sizeof(o) * 1e-6 54 | -------------------------------------------------------------------------------- /TidalPy/Extending/burnman/package.py: -------------------------------------------------------------------------------- 1 | import TidalPy 2 | from TidalPy.utilities.dictionary_utils import nested_merge 3 | from TidalPy.logger import get_logger 4 | log = get_logger("TidalPy") 5 | 6 | burnman_installed = True 7 | try: 8 | log.debug('Attempting to import the BurnMan package.') 9 | import burnman 10 | except ImportError: 11 | log.warning("BurnMan installation can not be found. TidalPy's BurnMan extension functions can not be used.") 12 | burnman_installed = False 13 | # Build fake class so type checking passes. 14 | class burnman: 15 | Planet = None 16 | Layer = None 17 | Material = None 18 | 19 | class Mineral: 20 | pass 21 | 22 | class Material: 23 | pass 24 | 25 | def dictionarize_formula(x): 26 | return None 27 | def formula_mass(x): 28 | return None 29 | def material_property(x): 30 | return None 31 | 32 | else: 33 | log.debug(f'BurnMan version {burnman.__version__} was found!') 34 | from burnman.classes.material import Material as Material 35 | from burnman.classes.material import material_property as material_property 36 | from burnman.classes.mineral import Mineral as Mineral 37 | from burnman.tools.chemistry import dictionarize_formula as dictionarize_formula 38 | from burnman.tools.chemistry import formula_mass as formula_mass 39 | 40 | log.debug('Appending TidalPy config with BurnMan specific configurations.') 41 | from .burnman_defaultc import default_burnman_configs 42 | 43 | TidalPy.config = nested_merge(TidalPy.config, default_burnman_configs, make_copies=False) 44 | log.debug('BurnMan extensions initialized.') 45 | 46 | from .burnman_layer import BurnmanLayer as BurnmanLayer 47 | from .burnman_world import BurnManWorld as BurnManWorld -------------------------------------------------------------------------------- /TidalPy/tides/modes/mode_calc_helper/inclin_calc_orderl2.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, TYPE_CHECKING 2 | 3 | from TidalPy.utilities.performance import njit 4 | 5 | from ...inclination_funcs import orderl2 6 | 7 | if TYPE_CHECKING: 8 | from TidalPy.utilities.types import FloatArray 9 | 10 | from ...inclination_funcs import InclinOutput 11 | 12 | 13 | @njit(cacheable=True) 14 | def inclination_off_maxl_2(obliquity: 'FloatArray') -> Dict[int, 'InclinOutput']: 15 | """ Calculates inclination functions (squared) for a given maximum tidal order (going through each l) - Off Mode 16 | 17 | Obliquity is assumed to be zero. 18 | 19 | Max Supported l = 2 20 | 21 | Parameters 22 | ---------- 23 | obliquity : FloatArray 24 | Planet's obliquity [radians] 25 | Returns 26 | ------- 27 | result_by_orderl : Dict[int, InclinOutput] 28 | Inclination function L^2_lmp truncated. Stored by order-l. 29 | """ 30 | 31 | result_by_orderl = { 32 | 2: orderl2.calc_inclination_off(obliquity) 33 | } 34 | 35 | return result_by_orderl 36 | 37 | 38 | @njit(cacheable=True) 39 | def inclination_on_maxl_2(obliquity: 'FloatArray') -> Dict[int, 'InclinOutput']: 40 | """ Calculates inclination functions (squared) for a given maximum tidal order (going through each l) - On Mode 41 | 42 | Obliquity can be arbitrary. 43 | 44 | Max Supported l = 2 45 | 46 | Parameters 47 | ---------- 48 | obliquity : FloatArray 49 | Planet's obliquity [radians] 50 | Returns 51 | ------- 52 | result_by_orderl : Dict[int, InclinOutput] 53 | Inclination function L^2_lmp truncated. Stored by order-l. 54 | """ 55 | 56 | result_by_orderl = { 57 | 2: orderl2.calc_inclination(obliquity) 58 | } 59 | 60 | return result_by_orderl 61 | -------------------------------------------------------------------------------- /Tests/Test_Utilities/Test_Exoplanets/test_exoplanet_download.py: -------------------------------------------------------------------------------- 1 | def test_exoplanet_download(): 2 | """Tests the exoplanet archive download utility.""" 3 | 4 | from TidalPy.utilities.exoplanets import get_exoplanet_data 5 | 6 | exoplanet_data = get_exoplanet_data( 7 | ensure_radius=True, 8 | radius_cutoff=1.5, 9 | ensure_mass=True, 10 | mass_cutoff=None, 11 | ensure_orbital_period=True, 12 | orbital_period_cutoff=50, 13 | ensure_eccentricity=True, 14 | eccentricity_threshold=None, 15 | star_type=None, 16 | only_defaults=True) 17 | 18 | assert len(exoplanet_data) > 0 19 | 20 | def test_exoplanet_download_stellar_type(): 21 | """Tests the exoplanet archive download utility using the different kinds of stellar types.""" 22 | 23 | from TidalPy.utilities.exoplanets import get_exoplanet_data 24 | 25 | # Try just a single stellar type 26 | exoplanet_data = get_exoplanet_data( 27 | ensure_radius=True, 28 | radius_cutoff=1.5, 29 | ensure_mass=True, 30 | mass_cutoff=None, 31 | ensure_orbital_period=True, 32 | orbital_period_cutoff=50, 33 | ensure_eccentricity=True, 34 | eccentricity_threshold=None, 35 | star_type='M', 36 | only_defaults=True) 37 | 38 | assert len(exoplanet_data) > 0 39 | 40 | # Try just a list of stellar types 41 | exoplanet_data = get_exoplanet_data( 42 | ensure_radius=True, 43 | radius_cutoff=1.5, 44 | ensure_mass=True, 45 | mass_cutoff=None, 46 | ensure_orbital_period=True, 47 | orbital_period_cutoff=50, 48 | ensure_eccentricity=True, 49 | eccentricity_threshold=None, 50 | star_type=['F', 'G', 'K'], 51 | only_defaults=True) 52 | 53 | assert len(exoplanet_data) > 0 54 | -------------------------------------------------------------------------------- /TidalPy/RadialSolver/starting/kamata.pxd: -------------------------------------------------------------------------------- 1 | cdef void cf_kamata_solid_dynamic_compressible( 2 | double frequency, 3 | double radius, 4 | double density, 5 | double complex bulk_modulus, 6 | double complex shear_modulus, 7 | int degree_l, 8 | double G_to_use, 9 | size_t num_ys, 10 | double complex* starting_conditions_ptr 11 | ) noexcept nogil 12 | 13 | cdef void cf_kamata_solid_static_compressible( 14 | double radius, 15 | double density, 16 | double complex bulk_modulus, 17 | double complex shear_modulus, 18 | int degree_l, 19 | double G_to_use, 20 | size_t num_ys, 21 | double complex* starting_conditions_ptr 22 | ) noexcept nogil 23 | 24 | cdef void cf_kamata_solid_dynamic_incompressible( 25 | double frequency, 26 | double radius, 27 | double density, 28 | double complex shear_modulus, 29 | int degree_l, 30 | double G_to_use, 31 | size_t num_ys, 32 | double complex* starting_conditions_ptr 33 | ) noexcept nogil 34 | 35 | ######################################################################################################################## 36 | #### Liquid Layers 37 | ######################################################################################################################## 38 | 39 | cdef void cf_kamata_liquid_dynamic_compressible( 40 | double frequency, 41 | double radius, 42 | double density, 43 | double complex bulk_modulus, 44 | int degree_l, 45 | double G_to_use, 46 | size_t num_ys, 47 | double complex* starting_conditions_ptr 48 | ) noexcept nogil 49 | 50 | cdef void cf_kamata_liquid_dynamic_incompressible( 51 | double frequency, 52 | double radius, 53 | double density, 54 | int degree_l, 55 | double G_to_use, 56 | size_t num_ys, 57 | double complex* starting_conditions_ptr 58 | ) noexcept nogil -------------------------------------------------------------------------------- /TidalPy/RadialSolver/starting/saito.pyx: -------------------------------------------------------------------------------- 1 | # distutils: language = c++ 2 | # cython: boundscheck=False, wraparound=False, nonecheck=False, cdivision=True, initializedcheck=False 3 | 4 | ######################################################################################################################## 5 | #### Liquid Layers 6 | ######################################################################################################################## 7 | 8 | 9 | cdef void cf_saito_liquid_static_incompressible( 10 | double radius, 11 | int degree_l, 12 | size_t num_ys, 13 | double complex* starting_conditions_ptr 14 | ) noexcept nogil: 15 | """ Calculate the initial guess at the bottom of a liquid layer using the static assumption. 16 | 17 | This function uses the Saito 1974 equations (Eq. 19). 18 | 19 | Using the static assumption in a liquid layer results in one independent solutions for the radial derivative. 20 | 21 | These independent solution allow for a general tidal harmonic l, for static tides (w = 0). 22 | However, compressibility and all dissipation dependence is lost due to no dependence on bulk or shear moduli. 23 | 24 | 25 | References 26 | ---------- 27 | S74 28 | 29 | Parameters 30 | ---------- 31 | radius : double 32 | Radius where the radial functions are calculated. [m] 33 | degree_l : unsigned char 34 | Tidal harmonic order. 35 | num_ys : ssize_t 36 | Number of radial solutions for this layer type. 37 | starting_conditions_ptr : double complex*, 38 | Desired starting conditions for this layer. 39 | One independent liquid guess (sn1) 40 | """ 41 | 42 | # See Eq. 19 in Saito 1974 43 | # # y5 solution 0 44 | starting_conditions_ptr[0] = radius**degree_l 45 | 46 | # # y7 solution 0 47 | starting_conditions_ptr[1] = 2. * (degree_l - 1.) * radius**(degree_l - 1.) 48 | -------------------------------------------------------------------------------- /TidalPy/tides/modes/mode_calc_helper/inclin_calc_orderl3.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, TYPE_CHECKING 2 | 3 | from TidalPy.utilities.performance import njit 4 | 5 | from ...inclination_funcs import orderl2, orderl3 6 | 7 | if TYPE_CHECKING: 8 | from TidalPy.utilities.types import FloatArray 9 | 10 | from ...inclination_funcs import InclinOutput 11 | 12 | 13 | @njit(cacheable=True) 14 | def inclination_off_maxl_3(obliquity: 'FloatArray') -> Dict[int, 'InclinOutput']: 15 | """ Calculates inclination functions (squared) for a given maximum tidal order (going through each l) - Off Mode 16 | 17 | Obliquity is assumed to be zero. 18 | 19 | Max Supported l = 3 20 | 21 | Parameters 22 | ---------- 23 | obliquity : FloatArray 24 | Planet's obliquity [radians] 25 | Returns 26 | ------- 27 | result_by_orderl : Dict[int, InclinOutput] 28 | Inclination function L^2_lmp truncated. Stored by order-l. 29 | """ 30 | 31 | result_by_orderl = { 32 | 2: orderl2.calc_inclination_off(obliquity), 33 | 3: orderl3.calc_inclination_off(obliquity) 34 | } 35 | 36 | return result_by_orderl 37 | 38 | 39 | @njit(cacheable=True) 40 | def inclination_on_maxl_3(obliquity: 'FloatArray') -> Dict[int, 'InclinOutput']: 41 | """ Calculates inclination functions (squared) for a given maximum tidal order (going through each l) - On Mode 42 | 43 | Obliquity can be arbitrary. 44 | 45 | Max Supported l = 3 46 | 47 | Parameters 48 | ---------- 49 | obliquity : FloatArray 50 | Planet's obliquity [radians] 51 | Returns 52 | ------- 53 | result_by_orderl : Dict[int, InclinOutput] 54 | Inclination function L^2_lmp truncated. Stored by order-l. 55 | """ 56 | 57 | result_by_orderl = { 58 | 2: orderl2.calc_inclination(obliquity), 59 | 3: orderl3.calc_inclination(obliquity) 60 | } 61 | 62 | return result_by_orderl 63 | -------------------------------------------------------------------------------- /.github/workflows/push_tests_win.yml: -------------------------------------------------------------------------------- 1 | # This workflow will install Python dependencies, run tests and lint with a variety of Python versions 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions 3 | 4 | name: Windows Tests 5 | 6 | on: 7 | pull_request: 8 | types: [opened, synchronize, reopened] 9 | workflow_dispatch: 10 | push: 11 | paths: 12 | - TidalPy/** 13 | 14 | env: 15 | TIDALPY_TEST_MODE: 1 16 | 17 | jobs: 18 | test-win: 19 | if: | 20 | github.event_name == 'pull_request' || 21 | github.event_name == 'workflow_dispatch' || 22 | contains(github.event.head_commit.message, 'run tests') 23 | 24 | name: Test TidalPy on Windows 25 | runs-on: windows-latest 26 | strategy: 27 | fail-fast: false 28 | matrix: 29 | python-version: 30 | - "3.9" 31 | - "3.10" 32 | - "3.11" 33 | - "3.12" 34 | - "3.13" 35 | steps: 36 | - uses: actions/checkout@v4 37 | 38 | - name: Set up Python ${{ matrix.python-version }} 39 | uses: actions/setup-python@v5 40 | with: 41 | python-version: ${{ matrix.python-version }} 42 | - name: Upgrade pip 43 | run: python -m pip install --upgrade pip 44 | 45 | - name: Install Dependencies 46 | run: | 47 | python -m pip install pytest pytest-xdist 48 | 49 | - name: Install Package with Burnman 50 | if: ${{ fromJSON(matrix.python-version) < 3.13 }} 51 | shell: bash -el {0} 52 | run: | 53 | python -m pip install -v .[burnman] 54 | 55 | - name: Install Package (No Burnman) 56 | if: ${{ fromJSON(matrix.python-version) >= 3.13 }} 57 | shell: bash -el {0} 58 | run: | 59 | python -m pip install -v . 60 | 61 | - name: Run pytest 62 | run: pytest -n auto --capture=sys -v .\Tests\ 63 | -------------------------------------------------------------------------------- /TidalPy/tides/modes/mode_calc_helper/inclin_calc_orderl4.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, TYPE_CHECKING 2 | 3 | from TidalPy.utilities.performance import njit 4 | 5 | from ...inclination_funcs import orderl2, orderl3, orderl4 6 | 7 | if TYPE_CHECKING: 8 | from TidalPy.utilities.types import FloatArray 9 | 10 | from ...inclination_funcs import InclinOutput 11 | 12 | 13 | @njit(cacheable=True) 14 | def inclination_off_maxl_4(obliquity: 'FloatArray') -> Dict[int, 'InclinOutput']: 15 | """ Calculates inclination functions (squared) for a given maximum tidal order (going through each l) - Off Mode 16 | 17 | Obliquity is assumed to be zero. 18 | 19 | Max Supported l = 4 20 | 21 | Parameters 22 | ---------- 23 | obliquity : FloatArray 24 | Planet's obliquity [radians] 25 | Returns 26 | ------- 27 | result_by_orderl : Dict[int, InclinOutput] 28 | Inclination function L^2_lmp truncated. Stored by order-l. 29 | """ 30 | 31 | result_by_orderl = { 32 | 2: orderl2.calc_inclination_off(obliquity), 33 | 3: orderl3.calc_inclination_off(obliquity), 34 | 4: orderl4.calc_inclination_off(obliquity) 35 | } 36 | 37 | return result_by_orderl 38 | 39 | 40 | @njit(cacheable=True) 41 | def inclination_on_maxl_4(obliquity: 'FloatArray') -> Dict[int, 'InclinOutput']: 42 | """ Calculates inclination functions (squared) for a given maximum tidal order (going through each l) - On Mode 43 | 44 | Obliquity can be arbitrary. 45 | 46 | Max Supported l = 4 47 | 48 | Parameters 49 | ---------- 50 | obliquity : FloatArray 51 | Planet's obliquity [radians] 52 | Returns 53 | ------- 54 | result_by_orderl : Dict[int, InclinOutput] 55 | Inclination function L^2_lmp truncated. Stored by order-l. 56 | """ 57 | 58 | result_by_orderl = { 59 | 2: orderl2.calc_inclination(obliquity), 60 | 3: orderl3.calc_inclination(obliquity), 61 | 4: orderl4.calc_inclination(obliquity) 62 | } 63 | 64 | return result_by_orderl 65 | -------------------------------------------------------------------------------- /TidalPy/RadialSolver/derivatives/odes.pxd: -------------------------------------------------------------------------------- 1 | from libcpp.memory cimport shared_ptr 2 | 3 | from CyRK cimport DiffeqFuncType, PreEvalFunc 4 | 5 | from TidalPy.Material.eos.eos_solution cimport EOSSolutionCC 6 | 7 | 8 | cdef struct RadialSolverDiffeqArgStruct: 9 | double degree_l 10 | double lp1 11 | double lm1 12 | double llp1 13 | double G 14 | double grav_coeff 15 | double frequency 16 | size_t layer_index 17 | EOSSolutionCC* eos_solution_ptr 18 | 19 | cdef void cf_solid_dynamic_compressible( 20 | double* dy_ptr, 21 | double radius, 22 | double* y_ptr, 23 | char* args_ptr, 24 | PreEvalFunc unused) noexcept nogil 25 | 26 | cdef void cf_solid_dynamic_incompressible( 27 | double* dy_ptr, 28 | double radius, 29 | double* y_ptr, 30 | char* args_ptr, 31 | PreEvalFunc unused) noexcept nogil 32 | 33 | cdef void cf_solid_static_compressible( 34 | double* dy_ptr, 35 | double radius, 36 | double* y_ptr, 37 | char* args_ptr, 38 | PreEvalFunc unused) noexcept nogil 39 | 40 | cdef void cf_solid_static_incompressible( 41 | double* dy_ptr, 42 | double radius, 43 | double* y_ptr, 44 | char* args_ptr, 45 | PreEvalFunc unused) noexcept nogil 46 | 47 | cdef void cf_liquid_dynamic_compressible( 48 | double* dy_ptr, 49 | double radius, 50 | double* y_ptr, 51 | char* args_ptr, 52 | PreEvalFunc unused) noexcept nogil 53 | 54 | cdef void cf_liquid_dynamic_incompressible( 55 | double* dy_ptr, 56 | double radius, 57 | double* y_ptr, 58 | char* args_ptr, 59 | PreEvalFunc unused) noexcept nogil 60 | 61 | cdef void cf_liquid_static_incompressible( 62 | double* dy_ptr, 63 | double radius, 64 | double* y_ptr, 65 | char* args_ptr, 66 | PreEvalFunc unused) noexcept nogil 67 | 68 | cdef DiffeqFuncType cf_find_layer_diffeq( 69 | int layer_type, 70 | int layer_is_static, 71 | int layer_is_incomp) noexcept nogil -------------------------------------------------------------------------------- /Tests/Test_Old/Test_SetB_Package/test_g_math_special_funcs.py: -------------------------------------------------------------------------------- 1 | """ Tests for TidalPy's special math functions """ 2 | 3 | import numpy as np 4 | 5 | 6 | 7 | from TidalPy.utilities.math.numba_special import sqrt_neg 8 | 9 | 10 | def test_sqrt_neg(): 11 | """ Tests the special square root function that works with numba. """ 12 | 13 | # Real inputs 14 | z_float_pos = 22. 15 | z_float_neg = -22. 16 | z_array_pos = np.linspace(1., 10., 5) 17 | z_array_neg = -np.linspace(1., 10., 5) 18 | 19 | # Test that the positive function works 20 | assert sqrt_neg(z_float_pos, is_real=True) == np.sqrt(z_float_pos) 21 | assert sqrt_neg(z_float_pos, is_real=False) == np.sqrt(z_float_pos) 22 | np.testing.assert_allclose(sqrt_neg(z_array_pos, is_real=True), np.sqrt(z_array_pos)) 23 | np.testing.assert_allclose(sqrt_neg(z_array_pos, is_real=False), np.sqrt(z_array_pos)) 24 | 25 | # Test that the expanded functionality works as expected 26 | assert sqrt_neg(z_float_neg, is_real=True) == np.lib.scimath.sqrt(z_float_neg) 27 | assert sqrt_neg(z_float_neg, is_real=False) == np.lib.scimath.sqrt(z_float_neg) 28 | np.testing.assert_allclose(sqrt_neg(z_array_neg, is_real=True), np.lib.scimath.sqrt(z_array_neg)) 29 | np.testing.assert_allclose(sqrt_neg(z_array_neg, is_real=False), np.lib.scimath.sqrt(z_array_neg)) 30 | 31 | # Now test how imaginary inputs work. 32 | z_float_pos = 22. + 2.j 33 | z_float_neg = -22. - 2.j 34 | z_array_pos = np.linspace(1., 10., 5) + 1.0j * np.linspace(1., 10., 5) 35 | z_array_neg = -np.linspace(1., 10., 5) - 1.0j * np.linspace(1., 10., 5) 36 | 37 | # Test that the positive function works 38 | np.testing.assert_allclose(sqrt_neg(z_float_pos, is_real=False), np.sqrt(z_float_pos)) 39 | np.testing.assert_allclose(sqrt_neg(z_array_pos, is_real=False), np.sqrt(z_array_pos)) 40 | 41 | # Test that the expanded functionality works as expected 42 | np.testing.assert_allclose(sqrt_neg(z_float_neg, is_real=False), np.lib.scimath.sqrt(z_float_neg)) 43 | np.testing.assert_allclose(sqrt_neg(z_array_neg, is_real=False), np.lib.scimath.sqrt(z_array_neg)) 44 | -------------------------------------------------------------------------------- /Tests/Test_Old/Test_SetO_OOP_Calcs/test_oop_rheology.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from TidalPy.structures import build_world 4 | 5 | # Build basic layered io 6 | io_base = build_world('io_simple') 7 | 8 | 9 | def test_basic_set_temperature(): 10 | # Set the temperature of the Mantle to something where there would be no partial melt 11 | io_base.Mantle.set_state(temperature=1500.) 12 | 13 | assert io_base.Mantle.temperature == 1500. 14 | assert io_base.Mantle.rheology.partial_melting_model.melt_fraction == 0. 15 | assert io_base.Mantle.rheology.melt_fraction is io_base.Mantle.rheology.partial_melting_model.melt_fraction 16 | assert io_base.Mantle.melt_fraction is io_base.Mantle.rheology.partial_melting_model.melt_fraction 17 | 18 | # Make sure the layer below the mantle is picking up on the changes 19 | assert io_base.Core.surface_temperature is io_base.Mantle.temperature 20 | 21 | # Make sure the strength information is passing around where it should be 22 | assert io_base.Mantle.rheology.postmelt_viscosity is \ 23 | io_base.Mantle.rheology.partial_melting_model.postmelt_viscosity 24 | assert io_base.Mantle.viscosity is io_base.Mantle.rheology.partial_melting_model.postmelt_viscosity 25 | assert io_base.Mantle.rheology.postmelt_shear_modulus is \ 26 | io_base.Mantle.rheology.partial_melting_model.postmelt_shear_modulus 27 | assert io_base.Mantle.shear_modulus is io_base.Mantle.rheology.partial_melting_model.postmelt_shear_modulus 28 | assert io_base.Mantle.rheology.postmelt_compliance is \ 29 | io_base.Mantle.rheology.partial_melting_model.postmelt_compliance 30 | assert io_base.Mantle.compliance is io_base.Mantle.rheology.partial_melting_model.postmelt_compliance 31 | 32 | premelt_shear = io_base.Mantle.shear_modulus 33 | premelt_visco = io_base.Mantle.viscosity 34 | 35 | # Try with some melt now 36 | io_base.Mantle.set_state(temperature=1800.) 37 | 38 | assert io_base.Mantle.melt_fraction > 0. 39 | assert io_base.Mantle.melt_fraction < 1. 40 | assert io_base.Mantle.shear_modulus < premelt_shear 41 | assert io_base.Mantle.viscosity < premelt_visco 42 | -------------------------------------------------------------------------------- /TidalPy/tides/modes/mode_calc_helper/inclin_calc_orderl5.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, TYPE_CHECKING 2 | 3 | from TidalPy.utilities.performance import njit 4 | 5 | from ...inclination_funcs import orderl2, orderl3, orderl4, orderl5 6 | 7 | if TYPE_CHECKING: 8 | from TidalPy.utilities.types import FloatArray 9 | 10 | from ...inclination_funcs import InclinOutput 11 | 12 | 13 | @njit(cacheable=True) 14 | def inclination_off_maxl_5(obliquity: 'FloatArray') -> Dict[int, 'InclinOutput']: 15 | """ Calculates inclination functions (squared) for a given maximum tidal order (going through each l) - Off Mode 16 | 17 | Obliquity is assumed to be zero. 18 | 19 | Max Supported l = 5 20 | 21 | Parameters 22 | ---------- 23 | obliquity : FloatArray 24 | Planet's obliquity [radians] 25 | Returns 26 | ------- 27 | result_by_orderl : Dict[int, InclinOutput] 28 | Inclination function L^2_lmp truncated. Stored by order-l. 29 | """ 30 | 31 | result_by_orderl = { 32 | 2: orderl2.calc_inclination_off(obliquity), 33 | 3: orderl3.calc_inclination_off(obliquity), 34 | 4: orderl4.calc_inclination_off(obliquity), 35 | 5: orderl5.calc_inclination_off(obliquity) 36 | } 37 | 38 | return result_by_orderl 39 | 40 | 41 | @njit(cacheable=True) 42 | def inclination_on_maxl_5(obliquity: 'FloatArray') -> Dict[int, 'InclinOutput']: 43 | """ Calculates inclination functions (squared) for a given maximum tidal order (going through each l) - On Mode 44 | 45 | Obliquity can be arbitrary. 46 | 47 | Max Supported l = 5 48 | 49 | Parameters 50 | ---------- 51 | obliquity : FloatArray 52 | Planet's obliquity [radians] 53 | Returns 54 | ------- 55 | result_by_orderl : Dict[int, InclinOutput] 56 | Inclination function L^2_lmp truncated. Stored by order-l. 57 | """ 58 | 59 | result_by_orderl = { 60 | 2: orderl2.calc_inclination(obliquity), 61 | 3: orderl3.calc_inclination(obliquity), 62 | 4: orderl4.calc_inclination(obliquity), 63 | 5: orderl5.calc_inclination(obliquity) 64 | } 65 | 66 | return result_by_orderl 67 | -------------------------------------------------------------------------------- /TidalPy/utilities/performance/numba.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | import numpy as np 4 | 5 | from TidalPy import config 6 | 7 | use_numba_cfg = config['numba']['use_numba'] 8 | use_numba_env = True 9 | if 'NUMBA_DISABLE_JIT' in os.environ: 10 | use_numba_env = (os.environ['NUMBA_DISABLE_JIT'] == 0) 11 | use_numba = use_numba_cfg and use_numba_env 12 | cache_numba = config['numba']['cache_numba'] 13 | 14 | if use_numba: 15 | import numba 16 | from numba.typed import Dict, List 17 | 18 | 19 | def njit(*args, **kwargs): 20 | if 'cacheable' in kwargs: 21 | if kwargs['cacheable'] and cache_numba: 22 | kwargs['cache'] = True 23 | else: 24 | kwargs['cache'] = False 25 | del kwargs['cacheable'] 26 | return numba.njit(*args, **kwargs) 27 | return numba.njit(*args, **kwargs) 28 | 29 | 30 | vectorize = numba.vectorize 31 | complex128 = numba.complex128 32 | float64 = numba.float64 33 | int64 = numba.int64 34 | int32 = numba.int32 35 | int16 = numba.int16 36 | int8 = numba.int8 37 | uint64 = numba.uint64 38 | uint32 = numba.uint32 39 | uint16 = numba.uint16 40 | uint8 = numba.uint8 41 | bool_ = numba.bool_ 42 | prange = numba.prange 43 | nbUnicode = numba.types.unicode_type 44 | nbDict = Dict 45 | nbList = List 46 | 47 | else: 48 | vectorize = np.vectorize 49 | complex128 = np.complex128 50 | float64 = np.float64 51 | int64 = np.int64 52 | int32 = np.int32 53 | int16 = np.int16 54 | int8 = np.int8 55 | uint64 = np.uint64 56 | uint32 = np.uint32 57 | uint16 = np.uint16 58 | uint8 = np.uint8 59 | bool_ = np.bool_ 60 | nbList = list 61 | prange = range 62 | nbUnicode = str 63 | 64 | def njit(*args, **kwargs): 65 | def njit_inner(func): 66 | return func 67 | 68 | return njit_inner 69 | 70 | # Create fake function to allow for nbDict.empty() to still work 71 | def nbDict(*args, **kwargs): 72 | return dict(*args, **kwargs) 73 | def nbDictEmpty(*args, **kwargs): 74 | return dict() 75 | nbDict.empty = nbDictEmpty 76 | -------------------------------------------------------------------------------- /TidalPy/stellar/stellar.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | from TidalPy.constants import luminosity_solar, mass_solar, sbc 4 | from TidalPy.utilities.performance.numba import njit 5 | 6 | 7 | @njit(cacheable=True) 8 | def efftemp_from_luminosity(luminosity: float, radius: float): 9 | """ Calculates a star's effective surface temperature provided a luminosity 10 | 11 | :param luminosity: StarWorld's luminosity [Watts] 12 | :param radius: StarWorld's Surface Radius [m] 13 | :return: StarWorld's Effective Surface temperature [K] 14 | """ 15 | 16 | return (luminosity / (4. * np.pi * sbc * radius**2))**(1 / 4) 17 | 18 | 19 | @njit(cacheable=True) 20 | def luminosity_from_efftemp(effective_temperature: float, radius: float): 21 | """ Calculates a star's luminosity provided an effective surface temperature 22 | 23 | :param effective_temperature: StarWorld's Effective Surface temperature [K] 24 | :param radius: StarWorld's Surface Radius [m] 25 | :return: StarWorld's luminosity [Watt] 26 | """ 27 | 28 | return 4. * np.pi * sbc * radius**2 * effective_temperature**4 29 | 30 | 31 | # Stellar Relationships and Scaling 32 | @njit(cacheable=True) 33 | def luminosity_from_mass(stellar_mass: float): 34 | """ Estimates stellar luminosity from a star's mass 35 | 36 | Partially based on Cuntz & Wang 2018 (doi:10.3847/2515-5172/aaaa67) and wikipedia.org/wiki/Mass–luminosity_relation 37 | 38 | :param stellar_mass: StarWorld's mass [kg] 39 | :return: StarWorld's luminosity [Watts] 40 | """ 41 | 42 | mass_ratio = stellar_mass / mass_solar 43 | 44 | if mass_ratio < .2: 45 | return luminosity_solar * 0.23 * mass_ratio**2.3 46 | if mass_ratio < 0.85: 47 | a = -141.7 * stellar_mass**4 + 232.4 * stellar_mass**3 - 129.1 * stellar_mass**2 + 33.29 * stellar_mass + 0.215 48 | return luminosity_solar * mass_ratio**a 49 | if mass_ratio < 2.: 50 | return luminosity_solar * mass_ratio**4 51 | if mass_ratio < 20.: 52 | return luminosity_solar * 1.4 * mass_ratio**3.5 53 | return luminosity_solar * 3.2e4 * mass_ratio 54 | -------------------------------------------------------------------------------- /citation.cff: -------------------------------------------------------------------------------- 1 | cff-version: 1.2.0 2 | title: TidalPy 3 | message: If you use this software, please cite it using the metadata from this file. 4 | type: software 5 | abstract: TidalPy is an open-source Python package for modeling tidal deformation, 6 | internal dissipation, and rotational-orbital evolution in planetary systems. The 7 | software combines a user-friendly Python interface with performance-critical routines 8 | implemented in C++ and Cython. Key capabilities include dynamic Love number computation, 9 | advanced rheological models, and coupled spin-orbit evolution. TidalPy addresses 10 | a gap in existing tools by providing these capabilities within a single accessible 11 | framework that easily interfaces with other popular Python packages used in the 12 | field. It has been extensively tested in a variety of studies examining tidal dissipation 13 | in Solar System planets and moons, as well as exoplanets. 14 | authors: 15 | - given-names: Joe 16 | family-names: Renaud 17 | email: joe.p.renaud@gmail.com 18 | affiliation: University of Maryland College Park; NASA Goddard 19 | orcid: https://orcid.org/0000-0002-8619-8542 20 | identifiers: 21 | - type: doi 22 | value: 10.5281/zenodo.7017475 23 | description: Zenodo Record 24 | - type: url 25 | value: https://pypi.org/project/TidalPy/ 26 | description: PyPI Repository 27 | - type: url 28 | value: https://anaconda.org/conda-forge/tidalpy 29 | description: Conda-Forge Repository 30 | repository-code: https://github.com/jrenaud90/TidalPy 31 | url: https://TidalPy.info 32 | keywords: 33 | - Tides 34 | - Tidal Dynamics 35 | - Planetary Science 36 | - Thermal-Orbital Evolution 37 | - Tidal Heating 38 | - Exoplanets 39 | - Moons 40 | - Solar System 41 | - Mercury 42 | - Venus 43 | - Earth 44 | - Moon 45 | - Mars 46 | - Europa 47 | - Io 48 | - Triton 49 | - Pluto 50 | - Rheology 51 | license: Apache-2.0 52 | commit: 1676d51 53 | version: 0.7.0 54 | date-released: '2025-12-03' 55 | preferred-citation: 56 | type: article 57 | authors: 58 | - family-names: Renaud 59 | given-names: Joe P. 60 | title: 'TidalPy: Software Suite for Solving Problems in Tidal Dynamics' 61 | journal: Zenodo 62 | year: 2022 63 | doi: 10.5281/zenodo.7017475 64 | -------------------------------------------------------------------------------- /TidalPy/tides/modes/mode_calc_helper/inclin_calc_orderl6.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, TYPE_CHECKING 2 | 3 | from TidalPy.utilities.performance import njit 4 | 5 | from ...inclination_funcs import orderl2, orderl3, orderl4, orderl5, orderl6 6 | 7 | if TYPE_CHECKING: 8 | from TidalPy.utilities.types import FloatArray 9 | 10 | from ...inclination_funcs import InclinOutput 11 | 12 | 13 | @njit(cacheable=True) 14 | def inclination_off_maxl_6(obliquity: 'FloatArray') -> Dict[int, 'InclinOutput']: 15 | """ Calculates inclination functions (squared) for a given maximum tidal order (going through each l) - Off Mode 16 | 17 | Obliquity is assumed to be zero. 18 | 19 | Max Supported l = 6 20 | 21 | Parameters 22 | ---------- 23 | obliquity : FloatArray 24 | Planet's obliquity [radians] 25 | Returns 26 | ------- 27 | result_by_orderl : Dict[int, InclinOutput] 28 | Inclination function L^2_lmp truncated. Stored by order-l. 29 | """ 30 | 31 | result_by_orderl = { 32 | 2: orderl2.calc_inclination_off(obliquity), 33 | 3: orderl3.calc_inclination_off(obliquity), 34 | 4: orderl4.calc_inclination_off(obliquity), 35 | 5: orderl5.calc_inclination_off(obliquity), 36 | 6: orderl6.calc_inclination_off(obliquity) 37 | } 38 | 39 | return result_by_orderl 40 | 41 | 42 | @njit(cacheable=True) 43 | def inclination_on_maxl_6(obliquity: 'FloatArray') -> Dict[int, 'InclinOutput']: 44 | """ Calculates inclination functions (squared) for a given maximum tidal order (going through each l) - On Mode 45 | 46 | Obliquity can be arbitrary. 47 | 48 | Max Supported l = 6 49 | 50 | Parameters 51 | ---------- 52 | obliquity : FloatArray 53 | Planet's obliquity [radians] 54 | Returns 55 | ------- 56 | result_by_orderl : Dict[int, InclinOutput] 57 | Inclination function L^2_lmp truncated. Stored by order-l. 58 | """ 59 | 60 | result_by_orderl = { 61 | 2: orderl2.calc_inclination(obliquity), 62 | 3: orderl3.calc_inclination(obliquity), 63 | 4: orderl4.calc_inclination(obliquity), 64 | 5: orderl5.calc_inclination(obliquity), 65 | 6: orderl6.calc_inclination(obliquity) 66 | } 67 | 68 | return result_by_orderl 69 | -------------------------------------------------------------------------------- /meta.yaml: -------------------------------------------------------------------------------- 1 | {% set name = "TidalPy" %} 2 | {% set version = "0.7.0" %} 3 | 4 | package: 5 | name: {{ name|lower }} 6 | version: {{ version }} 7 | 8 | source: 9 | url: https://pypi.org/packages/source/{{ name[0] }}/{{ name }}/tidalpy-{{ version }}.tar.gz 10 | sha256: ce1075272c0d8737c1247b6c98537b87dcbe9fea6a8de3e02438bd97ad3791a7 11 | 12 | build: 13 | skip: true # [py>=313] 14 | script: {{ PYTHON }} -m pip install . -vv --no-deps --no-build-isolation 15 | number: 0 16 | 17 | requirements: 18 | build: 19 | - {{ compiler('c') }} 20 | - {{ compiler('cxx') }} 21 | - {{ stdlib('c') }} 22 | host: 23 | - python 24 | - setuptools >=64.0.0 25 | - numpy # empty version spec will pick up channel pinnings 26 | # - numpy >=1.26,<1.27 # tidalpy specific pinnings also enforced 27 | - scipy >=1.9.3,<1.14 28 | - cython >=3.0.0 29 | - wheel >=0.38 30 | - cyrk >=0.12.2,<0.13 31 | - pip 32 | run: 33 | - python 34 | - numba >=0.54.1 35 | - scipy >=1.9.3,<1.14 36 | - platformdirs >=3.11.0,<4 37 | - toml >=0.10.2 38 | - dill >=0.3.2 39 | - psutil >=5.8.0 40 | - pathos >=0.2.0 41 | - cyrk >=0.12.2,<0.13 42 | - astropy-base 43 | - astroquery 44 | - matplotlib-base >=3.4.2 45 | - ipympl >=0.9.6,<0.10.0 46 | - cmcrameri 47 | 48 | test: 49 | imports: 50 | - TidalPy 51 | commands: 52 | - python -c "import TidalPy; print(TidalPy.__version__)" 53 | - pip check 54 | requires: 55 | - pip 56 | 57 | about: 58 | home: www.tidalpy.info/ 59 | summary: Tidal Dynamics and Thermal-Orbital Evolution Software Suite Implemented in Cython and Python 60 | description: | 61 | TidalPy provides efficient tools to estimate tidal dissipation within rocky and icy worlds. 62 | The RaidalSolver package includes tools to calculate a planet or moon's "Love" numbers. 63 | The Tides package includes tools to estimate tidal heating and spin-orbit evolution including the effects from 64 | higher-order eccentricity and obliquity terms which are often left out of other models. 65 | license: Apache-2.0 66 | license_file: LICENSE.md 67 | doc_url: https://github.com/jrenaud90/TidalPy/tree/main/Documentation 68 | dev_url: https://github.com/jrenaud90/TidalPy 69 | 70 | extra: 71 | recipe-maintainers: 72 | - jrenaud90 -------------------------------------------------------------------------------- /Tests/Test_Package/test_configs.py: -------------------------------------------------------------------------------- 1 | import pathlib 2 | 3 | 4 | def test_override_config_from_file(): 5 | """ Tests that we can override TidalPy's configurations by providing a new config file. """ 6 | import TidalPy 7 | 8 | # Reset to default in case it was already overridden this session 9 | TidalPy.reinit('default') 10 | 11 | original_file_level = TidalPy.config['logging']['file_level'] 12 | original_console_level = TidalPy.config['logging']['console_level'] 13 | 14 | # Make a new config file that changes one of the above. 15 | config_path = "new_config.toml" 16 | with open("new_config.toml", "w") as config_file: 17 | config_file.write("[logging]\n") 18 | config_file.write('file_level = "INFO"\n') 19 | 20 | # Tell TidalPy to override the configs 21 | TidalPy.reinit(config_path) 22 | 23 | # Check that the config was updated 24 | assert TidalPy.config['logging']['file_level'] != original_file_level 25 | assert TidalPy.config['logging']['file_level'] == "INFO" 26 | 27 | # Check that the other config was unaffected. 28 | assert TidalPy.config['logging']['console_level'] == original_console_level 29 | 30 | # Delete the temp file 31 | fp = pathlib.Path(config_path) 32 | fp.unlink() 33 | 34 | 35 | def test_override_config_from_dict(): 36 | """ Tests that we can override TidalPy's configurations by providing a new config dict. """ 37 | import TidalPy 38 | 39 | # Reset to default in case it was already overridden this session 40 | TidalPy.reinit('default') 41 | 42 | original_file_level = TidalPy.config['logging']['file_level'] 43 | original_console_level = TidalPy.config['logging']['console_level'] 44 | 45 | # Make a new config file that changes one of the above. 46 | new_config = dict( 47 | logging = dict( 48 | file_level = "INFO" 49 | ) 50 | ) 51 | 52 | # Tell TidalPy to override the configs 53 | TidalPy.reinit(new_config) 54 | 55 | # Check that the config was updated 56 | assert TidalPy.config['logging']['file_level'] != original_file_level 57 | assert TidalPy.config['logging']['file_level'] == "INFO" 58 | 59 | # Check that the other config was unaffected. 60 | assert TidalPy.config['logging']['console_level'] == original_console_level 61 | -------------------------------------------------------------------------------- /Tests/Test_Utilities/Test_Dimensions/test_nondimensional.py: -------------------------------------------------------------------------------- 1 | 2 | import numpy as np 3 | 4 | from math import isnan, isclose 5 | 6 | from TidalPy.constants import G, PI_DBL 7 | from TidalPy.utilities.dimensions.nondimensional import NonDimensionalScalesClass, build_nondimensional_scales 8 | 9 | 10 | frequency = 1.0e-3 11 | mean_radius = 1.0e6 12 | bulk_density = 5500. 13 | 14 | def test_non_dimensionalize_structure(): 15 | """ Test that the non-dimensionalize structure initializes correctly. """ 16 | 17 | test_struct = NonDimensionalScalesClass() 18 | 19 | # All conversions should initialize as nans 20 | assert isnan(test_struct.second2_conversion) 21 | assert isnan(test_struct.second_conversion) 22 | assert isnan(test_struct.length_conversion) 23 | assert isnan(test_struct.length3_conversion) 24 | assert isnan(test_struct.density_conversion) 25 | assert isnan(test_struct.mass_conversion) 26 | assert isnan(test_struct.pascal_conversion) 27 | 28 | 29 | def test_build_nondimensional_scales(): 30 | """ Test building a non-dimensionalize structure with real inputs. """ 31 | 32 | # Build 33 | test_struct = build_nondimensional_scales(frequency, mean_radius, bulk_density) 34 | 35 | # Check values were set correctly 36 | assert not isnan(test_struct.second2_conversion) 37 | assert not isnan(test_struct.second_conversion) 38 | assert not isnan(test_struct.length_conversion) 39 | assert not isnan(test_struct.length3_conversion) 40 | assert not isnan(test_struct.density_conversion) 41 | assert not isnan(test_struct.mass_conversion) 42 | assert not isnan(test_struct.pascal_conversion) 43 | 44 | # Check that they are the correct values. 45 | second2_conv = 1. / (PI_DBL * G * bulk_density) 46 | assert isclose(test_struct.second2_conversion, second2_conv) 47 | assert isclose(test_struct.second_conversion, np.sqrt(second2_conv)) 48 | assert isclose(test_struct.length_conversion, mean_radius) 49 | assert isclose(test_struct.length3_conversion, mean_radius**3) 50 | assert isclose(test_struct.density_conversion, bulk_density) 51 | assert isclose(test_struct.mass_conversion, bulk_density * mean_radius**3) 52 | assert isclose(test_struct.pascal_conversion, (bulk_density * mean_radius**3) / (mean_radius * second2_conv)) 53 | -------------------------------------------------------------------------------- /TidalPy/tides/universal_coeffs.py: -------------------------------------------------------------------------------- 1 | """ Universal coefficients used to calculate tidal heating and tidal potential derivatives 2 | Precomputed here to avoid calls to gamma functions in expensive loops. 3 | Defined as: 4 | [(l - m)! / (l + m)!] * (2 - delta_0m) 5 | Stored as: 6 | [order_l] [m] 7 | Starting with order_l = 2 and m = 0 8 | """ 9 | 10 | from TidalPy.exceptions import TidalPyValueException 11 | from TidalPy.utilities.performance.numba import njit 12 | 13 | 14 | @njit(cacheable=True) 15 | def get_universal_coeffs(order_l: int): 16 | # TODO: Right now this is defined inside the function to ensure that it is compiled correctly by njit - if we make a typed dict it may be possible to pull it outside the function for better optimization 17 | universal_coeffs_by_orderl_minus2 = ( 18 | # l = 2 19 | { 20 | 0: 1., 21 | 1: 1. / 3., 22 | 2: 1. / 12. 23 | }, 24 | # l = 3 25 | { 26 | 0: 1., 27 | 1: 1. / 6., 28 | 2: 1. / 60., 29 | 3: 1. / 360. 30 | }, 31 | # l = 4 32 | { 33 | 0: 1., 34 | 1: 1. / 10., 35 | 2: 1. / 180., 36 | 3: 1. / 2520., 37 | 4: 1. / 20160. 38 | }, 39 | # l = 5 40 | { 41 | 0: 1., 42 | 1: 1. / 15., 43 | 2: 1. / 420., 44 | 3: 1. / 10080., 45 | 4: 1. / 181440., 46 | 5: 1. / 1814400. 47 | }, 48 | # l = 6 49 | { 50 | 0: 1., 51 | 1: 1. / 21., 52 | 2: 1. / 840., 53 | 3: 1. / 30240., 54 | 4: 1. / 907200., 55 | 5: 1. / 19958400., 56 | 6: 1. / 239500800. 57 | }, 58 | # l = 7 59 | { 60 | 0: 1., 61 | 1: 1. / 28., 62 | 2: 1. / 1512., 63 | 3: 1. / 75600, 64 | 4: 1. / 3326400., 65 | 5: 1. / 119750400., 66 | 6: 1. / 3113510400., 67 | 7: 1. / 43589145600. 68 | } 69 | ) 70 | 71 | if order_l < 2: 72 | raise TidalPyValueException('Tidal order l must be an integer >= 2.') 73 | 74 | return universal_coeffs_by_orderl_minus2[order_l - 2] 75 | -------------------------------------------------------------------------------- /TidalPy/cache.py: -------------------------------------------------------------------------------- 1 | import os 2 | import shutil 3 | 4 | from TidalPy.paths import get_config_dir, get_log_dir, get_worlds_dir 5 | 6 | def clear_cache(verbose: bool = True): 7 | """ Clears TidalPy's cached functions (python cache and cached numba functions). 8 | 9 | Parameters 10 | ---------- 11 | verbose : bool = True 12 | Prints the name of pycache directories as they are cleared. 13 | 14 | Returns 15 | ------- 16 | success: bool 17 | """ 18 | 19 | # Get install directory for TidalPy 20 | tidalpy_loc = os.path.join(os.path.dirname(os.path.realpath(__file__)), os.pardir) 21 | 22 | if verbose: 23 | print('TidalPy Directory:', tidalpy_loc) 24 | print('Clearing TidalPy Cache...') 25 | 26 | for subdir, dirs, files in os.walk(tidalpy_loc): 27 | 28 | # Python and Numba caches save to the __pycache__ dir 29 | if '__pycache__' in dirs: 30 | cache_dir = os.path.join(subdir, '__pycache__') 31 | if verbose: 32 | print('Deleting: ', cache_dir) 33 | shutil.rmtree(cache_dir) 34 | 35 | return True 36 | 37 | def clear_data(verbose: bool = True): 38 | """ Clears TidalPy's data files. 39 | 40 | Parameters 41 | ---------- 42 | verbose : bool = True 43 | Prints the name of directories as they are cleared. 44 | 45 | Returns 46 | ------- 47 | success: bool 48 | """ 49 | 50 | dirs_to_del = list() 51 | dirs_to_del.append(get_config_dir()) 52 | dirs_to_del.append(get_log_dir()) 53 | dirs_to_del.append(get_worlds_dir()) 54 | dir_str = '\n\t'.join(dirs_to_del) 55 | 56 | confirmation = input("Confirm that you would like to delete TidalPy's data directories? " + \ 57 | "Any edits made to TidalPy configurations and world configs will be lost. " + \ 58 | "Advise making backups first. " + \ 59 | f"The following directories will be removed: {dir_str}" + \ 60 | "\nProceed? (Y/N): ") 61 | 62 | if confirmation.lower() == 'y': 63 | # Delete files. 64 | for dir in dirs_to_del: 65 | if verbose: 66 | print('Deleting: ', dir) 67 | shutil.rmtree(dir) 68 | 69 | return True 70 | else: 71 | return False 72 | -------------------------------------------------------------------------------- /TidalPy/utilities/math/numba_special.py: -------------------------------------------------------------------------------- 1 | """ This module provides several special functions that are specifically designed to work with TidalPy and its 2 | dependencies (looking at you, Numba). 3 | 4 | """ 5 | 6 | from typing import TYPE_CHECKING 7 | 8 | import numpy as np 9 | 10 | from TidalPy.utilities.performance import njit, use_numba 11 | 12 | if TYPE_CHECKING: 13 | from TidalPy.utilities.types import NumArray 14 | 15 | 16 | def _sqrt_neg_python(z: 'NumArray', is_real: bool = False) -> 'NumArray': 17 | """ Square root - Allows for negative values 18 | 19 | Parameters 20 | ---------- 21 | z : FloatArray 22 | Input value (domain is all positive and negative numbers) 23 | 24 | Returns 25 | ------- 26 | z_sqrt : FloatArray 27 | Output value (range is all positive values and complex numbers) 28 | 29 | """ 30 | 31 | if is_real: 32 | # First solve the square root assuming z is positive. 33 | z_sqrt_abs = np.sqrt(np.abs(z)) 34 | 35 | # Now correct the negatives (this will either be a Boolean or an array of Booleans, depending upon input type) 36 | z_sqrt = (np.real(z) > 0.) * z_sqrt_abs + \ 37 | (np.real(z) < 0.) * z_sqrt_abs * 1.0j 38 | 39 | else: 40 | # This is a more "complex" process because the input could already be both negative AND complex. 41 | z_r = np.real(z) 42 | z_i = np.imag(z) 43 | quad = np.sqrt(z_r * z_r + z_i * z_i) 44 | 45 | real_part = np.sqrt((quad + z_r) / 2.) 46 | imag_part = np.sqrt((quad - z_r) / 2.) 47 | 48 | z_sqrt = real_part + \ 49 | (z_i != 0.) * imag_part * np.sign(z_i) * 1.0j + \ 50 | (z_i == 0.) * imag_part * 1.0j 51 | 52 | return z_sqrt 53 | 54 | 55 | # Imaginary square roots 56 | if use_numba: 57 | # TODO: Numba currently does not support wrapping np.lib.scimath.sqrt, so we have to define our own function. 58 | # However, numba.njit of np.sqrt is about 10x faster than np.sqrt with floats and about 2x fast with arrays. 59 | # So the above method is actually pretty efficient. 60 | sqrt_neg = njit(cacheable=True)(_sqrt_neg_python) 61 | else: 62 | # Numpy already has a built in function to handle this. Use it instead 63 | def sqrt_neg(z, is_real: bool = False): 64 | return np.lib.scimath.sqrt(z) 65 | -------------------------------------------------------------------------------- /TidalPy/tides/inclination_funcs/orderl3.py: -------------------------------------------------------------------------------- 1 | """ Inclination functions (squared) for tidal order-l = 3. These are exact (no truncation on I) 2 | """ 3 | 4 | from typing import TYPE_CHECKING 5 | 6 | import numpy as np 7 | 8 | from ...utilities.performance.numba import njit 9 | 10 | if TYPE_CHECKING: 11 | from . import InclinOutput 12 | from ...utilities.types import FloatArray 13 | 14 | 15 | @njit(cacheable=True) 16 | def calc_inclination_off(inclination: 'FloatArray') -> 'InclinOutput': 17 | """Calculate F^2_lmp (assuming I=0) for l = 3""" 18 | 19 | # Inclination Functions Calculated for l = 3, Inclination == off. 20 | ones_ = np.ones_like(inclination) 21 | 22 | inclination_results = { 23 | (1, 1): 2.25 * ones_, 24 | (3, 0): 225. * ones_, 25 | } 26 | 27 | return inclination_results 28 | 29 | 30 | @njit(cacheable=True) 31 | def calc_inclination(inclination: 'FloatArray') -> 'InclinOutput': 32 | """Calculate F^2_lmp for l = 3""" 33 | 34 | # Inclination Functions Calculated for l = 3. 35 | # Optimizations 36 | i = inclination 37 | i_half = i / 2. 38 | sin_i = np.sin(i) 39 | cos_i = np.cos(i) 40 | sin_i_half = np.sin(i_half) 41 | cos_i_half = np.cos(i_half) 42 | 43 | inclination_results = { 44 | (0, 0) : 0.09765625*sin_i**6, 45 | (0, 1) : 0.87890625*(sin_i**2 - 0.8)**2*sin_i**2, 46 | (0, 2) : 0.87890625*(0.8 - sin_i**2)**2*sin_i**2, 47 | (0, 3) : 0.09765625*sin_i**6, 48 | (1, 0) : 56.25*sin_i_half**4*cos_i_half**8, 49 | (1, 1) : 31.640625*(-cos_i**2 + 0.6666666666666666666666667*cos_i + 0.06666666666666666666666667)**2*cos_i_half**4, 50 | (1, 2) : 31.640625*(sin_i**2 - 0.6666666666666666666666667*cos_i - 0.9333333333333333333333333)**2*sin_i_half**4, 51 | (1, 3) : 56.25*sin_i_half**8*cos_i_half**4, 52 | (2, 0) : 3.515625*(cos_i + 1.0)**4*sin_i**2, 53 | (2, 1) : 31.640625*(sin_i**2 - 0.6666666666666666666666667*cos_i - 0.6666666666666666666666667)**2*sin_i**2, 54 | (2, 2) : 225.0*(sin_i_half**5*cos_i_half - 0.25*sin_i**3)**2, 55 | (2, 3) : 225.0*sin_i_half**10*cos_i_half**2, 56 | (3, 0) : 225.0*cos_i_half**12, 57 | (3, 1) : 2025.0*sin_i_half**4*cos_i_half**8, 58 | (3, 2) : 2025.0*sin_i_half**8*cos_i_half**4, 59 | (3, 3) : 225.0*sin_i_half**12 60 | } 61 | 62 | return inclination_results -------------------------------------------------------------------------------- /TidalPy/tides/modes/mode_calc_helper/inclin_calc_orderl7.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, TYPE_CHECKING 2 | 3 | from TidalPy.utilities.performance import njit 4 | 5 | from ...inclination_funcs import orderl2, orderl3, orderl4, orderl5, orderl6, orderl7 6 | 7 | if TYPE_CHECKING: 8 | from TidalPy.utilities.types import FloatArray 9 | 10 | from ...inclination_funcs import InclinOutput 11 | 12 | 13 | @njit(cacheable=True) 14 | def inclination_off_maxl_7(obliquity: 'FloatArray') -> Dict[int, 'InclinOutput']: 15 | """ Calculates inclination functions (squared) for a given maximum tidal order (going through each l) - Off Mode 16 | 17 | Obliquity is assumed to be zero. 18 | 19 | Max Supported l = 7 20 | 21 | Parameters 22 | ---------- 23 | obliquity : FloatArray 24 | Planet's obliquity [radians] 25 | Returns 26 | ------- 27 | result_by_orderl : Dict[int, InclinOutput] 28 | Inclination function L^2_lmp truncated. Stored by order-l. 29 | """ 30 | 31 | result_by_orderl = { 32 | 2: orderl2.calc_inclination_off(obliquity), 33 | 3: orderl3.calc_inclination_off(obliquity), 34 | 4: orderl4.calc_inclination_off(obliquity), 35 | 5: orderl5.calc_inclination_off(obliquity), 36 | 6: orderl6.calc_inclination_off(obliquity), 37 | 7: orderl7.calc_inclination_off(obliquity) 38 | } 39 | 40 | return result_by_orderl 41 | 42 | 43 | @njit(cacheable=True) 44 | def inclination_on_maxl_7(obliquity: 'FloatArray') -> Dict[int, 'InclinOutput']: 45 | """ Calculates inclination functions (squared) for a given maximum tidal order (going through each l) - On Mode 46 | 47 | Obliquity can be arbitrary. 48 | 49 | Max Supported l = 7 50 | 51 | Parameters 52 | ---------- 53 | obliquity : FloatArray 54 | Planet's obliquity [radians] 55 | Returns 56 | ------- 57 | result_by_orderl : Dict[int, InclinOutput] 58 | Inclination function L^2_lmp truncated. Stored by order-l. 59 | """ 60 | 61 | result_by_orderl = { 62 | 2: orderl2.calc_inclination(obliquity), 63 | 3: orderl3.calc_inclination(obliquity), 64 | 4: orderl4.calc_inclination(obliquity), 65 | 5: orderl5.calc_inclination(obliquity), 66 | 6: orderl6.calc_inclination(obliquity), 67 | 7: orderl7.calc_inclination(obliquity) 68 | } 69 | 70 | return result_by_orderl 71 | -------------------------------------------------------------------------------- /TidalPy/tides/heating.py: -------------------------------------------------------------------------------- 1 | """ Functions used to estimate tidal heating within a solid planet or layer. """ 2 | 3 | import numpy as np 4 | 5 | from ..utilities.performance import njit 6 | 7 | @njit(cacheable=True) 8 | def calculate_volumetric_heating(stress: np.ndarray, strain: np.ndarray) -> np.ndarray: 9 | """ Calculates the tidal heating rate per unit volume based on the tidal stresses and strains. 10 | 11 | Parameters 12 | ---------- 13 | stress : np.ndarray 14 | Tidal stress tensor (complex np.ndarray) [Pa] 15 | strain : np.ndarray 16 | Tidal strain tensor (complex np.ndarray) [unitless] 17 | 18 | Returns 19 | ------- 20 | volumetric_heating : np.ndarray 21 | Tidal heating rate per unit volume [W m-3] 22 | """ 23 | 24 | # Find real and imaginary components of the stress and strain tensor. 25 | stress_real = np.real(stress) 26 | stress_imag = np.imag(stress) 27 | strain_real = np.real(strain) 28 | strain_imag = np.imag(strain) 29 | 30 | # Find heating rate per unit volume. 31 | # Heating is equal to imag[o] * real[s] - real[o] * imag[s] but we need to multiply by two for the cross terms 32 | # since it is part of a symmetric matrix but only one side of the matrix is calculated. 33 | volumetric_heating = ( 34 | # Im[s_rr] Re[e_rr] - Re[s_rr] Im[e_rr] 35 | stress_imag[0] * strain_real[0] - stress_real[0] * strain_imag[0] + 36 | # Im[s_thth] Re[e_thth] - Re[s_thth] Im[e_thth] 37 | stress_imag[1] * strain_real[1] - stress_real[1] * strain_imag[1] + 38 | # Im[s_phiphi] Re[e_phiphi] - Re[s_phiphi] Im[e_phiphi] 39 | stress_imag[2] * strain_real[2] - stress_real[2] * strain_imag[2] + 40 | # 2 Im[s_rth] Re[e_rth] - Re[s_rth] Im[e_rth] 41 | 2. * (stress_imag[3] * strain_real[3] - stress_real[3] * strain_imag[3]) + 42 | # 2 Im[s_rphi] Re[e_rphi] - Re[s_rphi] Im[e_rphi] 43 | 2. * (stress_imag[4] * strain_real[4] - stress_real[4] * strain_imag[4]) + 44 | # 2 Im[s_thphi] Re[e_thphi] - Re[s_thphi] Im[e_thphi] 45 | 2. * (stress_imag[5] * strain_real[5] - stress_real[5] * strain_imag[5]) 46 | ) 47 | 48 | # TODO: Without this abs term the resulting heating maps are very blotchy around 49 | # Europa book does have an abs at Equation 42, Page 102 50 | volumetric_heating = np.abs(volumetric_heating) 51 | 52 | return volumetric_heating 53 | -------------------------------------------------------------------------------- /Benchmarks/Performance/performance suite/performance_complex_compliance_func.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | from performance_base import PerformanceTrackBase 4 | 5 | import TidalPy 6 | TidalPy.config['stream_level'] = 'WARNING' 7 | TidalPy.reinit() 8 | 9 | class ComplexCompliancePerformance(PerformanceTrackBase): 10 | 11 | def run_perform_complex_comp_maxwell_float(self): 12 | from TidalPy.rheology.complex_compliance.compliance_models import maxwell 13 | self.record_performance('Complex Compliance - Maxwell - Float', maxwell, 14 | inputs=(1.1e-4, 2.1e-11, 3.3e9)) 15 | 16 | def run_perform_complex_comp_andrade_float(self): 17 | from TidalPy.rheology.complex_compliance.compliance_models import andrade 18 | self.record_performance('Complex Compliance - Andrade - Float', andrade, 19 | inputs=(1.1e-4, 2.1e-11, 3.3e9)) 20 | 21 | def run_perform_complex_comp_sundberg_float(self): 22 | from TidalPy.rheology.complex_compliance.compliance_models import sundberg 23 | self.record_performance('Complex Compliance - Sundberg - Float', sundberg, 24 | inputs=(1.1e-4, 2.1e-11, 3.3e9)) 25 | 26 | def run_perform_complex_comp_maxwell_array(self): 27 | from TidalPy.rheology.complex_compliance.compliance_models import maxwell 28 | freq = np.linspace(1.1e-4, 5.1e-4, 10000) 29 | self.record_performance('Complex Compliance - Maxwell - Array', maxwell, 30 | inputs=(freq, 2.1e-11, 3.3e9), array_N=len(freq)) 31 | 32 | def run_perform_complex_comp_andrade_array(self): 33 | from TidalPy.rheology.complex_compliance.compliance_models import andrade 34 | freq = np.linspace(1.1e-4, 5.1e-4, 10000) 35 | self.record_performance('Complex Compliance - Andrade - Array', andrade, 36 | inputs=(freq, 2.1e-11, 3.3e9), array_N=len(freq)) 37 | 38 | def run_perform_complex_comp_sundberg_array(self): 39 | from TidalPy.rheology.complex_compliance.compliance_models import sundberg 40 | freq = np.linspace(1.1e-4, 5.1e-4, 10000) 41 | self.record_performance('Complex Compliance - Sundberg - Array', sundberg, 42 | inputs=(freq, 2.1e-11, 3.3e9), array_N=len(freq)) 43 | 44 | 45 | if __name__ == '__main__': 46 | performance_tracker = ComplexCompliancePerformance() -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | import platform 3 | import json 4 | from setuptools import Extension, setup 5 | 6 | import numpy as np 7 | import CyRK 8 | 9 | DEBUG_MODE = False 10 | 11 | install_platform = platform.system() 12 | 13 | if install_platform.lower() == 'windows': 14 | extra_compile_args = ['/openmp'] 15 | extra_link_args = [] 16 | if DEBUG_MODE: 17 | extra_compile_args.append('/Ox') 18 | extra_compile_args.append('/Zi') 19 | extra_link_args.append("/debug:full") 20 | elif install_platform.lower() == 'darwin': 21 | extra_compile_args = ['-O3', '-Wno-error=incompatible-function-pointer-types', '-fopenmp'] 22 | extra_link_args = ['-lomp'] 23 | else: 24 | extra_compile_args = ['-fopenmp', '-O3'] 25 | extra_link_args = ['-fopenmp', '-O3'] 26 | macro_list = [("NPY_NO_DEPRECATED_API", "NPY_1_9_API_VERSION")] 27 | 28 | # Load TidalPy's cython extensions 29 | absolute_path = os.path.dirname(__file__) 30 | cython_ext_path = os.path.join(absolute_path, 'cython_extensions.json') 31 | with open(cython_ext_path, 'r') as cython_ext_file: 32 | cython_ext_dict = json.load(cython_ext_file) 33 | 34 | tidalpy_cython_extensions = list() 35 | for cython_ext, ext_data in cython_ext_dict.items(): 36 | 37 | if ext_data['is_cpp']: 38 | if install_platform.lower() == 'windows': 39 | specific_compile_args = extra_compile_args + ext_data['compile_args'] + ["/std:c++20"] 40 | else: 41 | specific_compile_args = extra_compile_args + ext_data['compile_args'] + ["-std=c++20"] 42 | else: 43 | specific_compile_args = extra_compile_args + ext_data['compile_args'] 44 | 45 | tidalpy_cython_extensions.append( 46 | Extension( 47 | name=ext_data['name'], 48 | sources=[os.path.join(*tuple(source_path)) for source_path in ext_data['sources']], 49 | # Always add numpy to any includes 50 | include_dirs=[os.path.join(*tuple(dir_path)) for dir_path in ext_data['include_dirs']] + [np.get_include()] + CyRK.get_include(), 51 | extra_compile_args=specific_compile_args, 52 | define_macros=macro_list, 53 | extra_link_args=ext_data['link_args'] + extra_link_args, 54 | ) 55 | ) 56 | 57 | # Cython extensions require a setup.py in addition to pyproject.toml in order to create platform-specific wheels. 58 | setup( 59 | ext_modules=tidalpy_cython_extensions 60 | ) 61 | -------------------------------------------------------------------------------- /Tests/Test_RadialSolver/test_a_boundary_conditions.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from math import isnan 3 | 4 | import numpy as np 5 | 6 | from TidalPy.RadialSolver.boundaries.surface_bc import get_surface_bc 7 | 8 | 9 | @pytest.mark.parametrize('degree_l', (2, 3)) 10 | def test_get_surface_bc(degree_l): 11 | """ Test boundary condition finder function. """ 12 | 13 | radius = 1000. 14 | density = 2000. 15 | 16 | def check_val(array, model_type): 17 | if model_type == 0: 18 | for i in range(3): 19 | assert array[i] == 0. 20 | elif model_type == 1: 21 | for i in range(2): 22 | assert array[i] == 0. 23 | assert array[2] == (2. * degree_l + 1.) / radius 24 | elif model_type == 2: 25 | assert array[0] == (-1. / 3.) * (2. * degree_l + 1.) * density 26 | assert array[1] == 0. 27 | assert array[2] == (2. * degree_l + 1.) / radius 28 | else: 29 | raise NotImplementedError 30 | 31 | return True 32 | 33 | # Test with 1 model 34 | for model_type in (0, 1, 2): 35 | bc_models = np.asarray((model_type,), dtype=np.intc) 36 | boundary_condition_array = get_surface_bc( 37 | bc_models, 38 | radius, 39 | density, 40 | degree_l, 41 | ) 42 | assert check_val(boundary_condition_array[:3], model_type=model_type) 43 | for value in boundary_condition_array[3:]: 44 | assert isnan(value) 45 | 46 | # Test with 2 models 47 | for model_pair in ((0, 0), (0, 1), (1, 0), (1, 1,), (1, 2), (2, 1), (2, 2)): 48 | bc_models = np.asarray(model_pair, dtype=np.intc) 49 | boundary_condition_array = get_surface_bc( 50 | bc_models, 51 | radius, 52 | density, 53 | degree_l, 54 | ) 55 | for i, model_type in enumerate(model_pair): 56 | assert check_val(boundary_condition_array[3*i:(3*i)+3], model_type=model_type) 57 | 58 | # Test with 3 models 59 | for model_pair in ((0, 0, 0), (0, 1, 2), (1, 1, 1), (2, 2, 2), (2, 1, 0)): 60 | bc_models = np.asarray(model_pair, dtype=np.intc) 61 | boundary_condition_array = get_surface_bc( 62 | bc_models, 63 | radius, 64 | density, 65 | degree_l, 66 | ) 67 | for i, model_type in enumerate(model_pair): 68 | assert check_val(boundary_condition_array[3*i:(3*i)+3], model_type=model_type) 69 | -------------------------------------------------------------------------------- /.github/workflows/push_tests_ubun.yml: -------------------------------------------------------------------------------- 1 | name: Ubuntu Tests 2 | 3 | on: 4 | pull_request: 5 | types: [opened, synchronize, reopened] 6 | workflow_dispatch: 7 | push: 8 | paths: 9 | - TidalPy/** 10 | 11 | env: 12 | TIDALPY_TEST_MODE: 1 13 | 14 | jobs: 15 | lint-with-ruff: 16 | if: | 17 | github.event_name == 'pull_request' || 18 | github.event_name == 'workflow_dispatch' || 19 | contains(github.event.head_commit.message, 'run tests') 20 | 21 | name: Lint TidalPy with ruff 22 | runs-on: ubuntu-latest 23 | steps: 24 | - uses: actions/checkout@v4 25 | 26 | - name: Set up Python 27 | uses: actions/setup-python@v5 28 | with: 29 | python-version: '3.x' 30 | 31 | - name: Upgrade pip 32 | run: python -m pip install --upgrade pip 33 | 34 | - name: Install ruff 35 | run: pip install ruff 36 | 37 | - name: Run ruff linting 38 | run: ruff check TidalPy/ --ignore F401,E402,E501 --select E,F 39 | test-ubuntu: 40 | if: | 41 | github.event_name == 'pull_request' || 42 | github.event_name == 'workflow_dispatch' || 43 | contains(github.event.head_commit.message, 'run tests') 44 | 45 | name: Test TidalPy on Ubuntu 46 | runs-on: ubuntu-latest 47 | strategy: 48 | fail-fast: false 49 | matrix: 50 | python-version: 51 | - "3.9" 52 | - "3.10" 53 | - "3.11" 54 | - "3.12" 55 | - "3.13" 56 | steps: 57 | - uses: actions/checkout@v4 58 | 59 | - name: Set up Python ${{ matrix.python-version }} 60 | uses: actions/setup-python@v5 61 | with: 62 | python-version: ${{ matrix.python-version }} 63 | 64 | - name: Upgrade pip 65 | run: python -m pip install --upgrade pip 66 | 67 | - name: Install Other Dependencies 68 | # For burnman, need GitHub version to enable python 3.12 support. 69 | run: | 70 | python -m pip install pytest pytest-xdist 71 | 72 | - name: Install Package with Burnman 73 | if: ${{ fromJSON(matrix.python-version) < 3.13 }} 74 | shell: bash -el {0} 75 | run: | 76 | python -m pip install -v .[burnman] 77 | 78 | - name: Install Package (No Burnman) 79 | if: ${{ fromJSON(matrix.python-version) >= 3.13 }} 80 | shell: bash -el {0} 81 | run: | 82 | python -m pip install -v . 83 | 84 | - name: Run pytest 85 | run: pytest -n auto -v Tests/ 86 | -------------------------------------------------------------------------------- /Documentation/Style Templates/docstring - function or method.txt: -------------------------------------------------------------------------------- 1 | """Summarize the function in one line. 2 | 3 | Several sentences providing an extended description. Refer to 4 | variables using back-ticks, e.g. `var`. 5 | 6 | Parameters 7 | ---------- 8 | var1 : array_like 9 | Array_like means all those objects -- lists, nested lists, etc. -- 10 | that can be converted to an array. We can also refer to 11 | variables like `var1`. 12 | var2 : int 13 | The type above can either refer to an actual Python type 14 | (e.g. ``int``), or describe the type of the variable in more 15 | detail, e.g. ``(N,) ndarray`` or ``array_like``. 16 | *args : iterable 17 | Other arguments. 18 | long_var_name : {'hi', 'ho'}, optional 19 | Choices in brackets, default first when optional. 20 | **kwargs : dict 21 | Keyword arguments. 22 | 23 | Returns 24 | ------- 25 | type 26 | Explanation of anonymous return value of type ``type``. 27 | describe : type 28 | Explanation of return value named `describe`. 29 | out : type 30 | Explanation of `out`. 31 | type_without_description 32 | 33 | Other Parameters 34 | ---------------- 35 | only_seldom_used_keywords : type 36 | Explanation. 37 | common_parameters_listed_above : type 38 | Explanation. 39 | 40 | Raises 41 | ------ 42 | BadException 43 | Because you shouldn't have done that. 44 | 45 | See Also 46 | -------- 47 | numpy.array : Relationship (optional). 48 | numpy.ndarray : Relationship (optional), which could be fairly long, in 49 | which case the line wraps here. 50 | numpy.dot, numpy.linalg.norm, numpy.eye 51 | 52 | Notes 53 | ----- 54 | Notes about the implementation algorithm (if needed). 55 | 56 | This can have multiple paragraphs. 57 | 58 | You may include some math: 59 | 60 | .. math:: X(e^{j\omega } ) = x(n)e^{ - j\omega n} 61 | 62 | And even use a Greek symbol like :math:`\omega` inline. 63 | 64 | References 65 | ---------- 66 | Cite the relevant literature, e.g. [1]_. You may also cite these 67 | references in the notes section above. 68 | 69 | .. [1] O. McNoleg, "The integration of GIS, remote sensing, 70 | expert systems and adaptive co-kriging for environmental habitat 71 | modelling of the Highland Haggis using object-oriented, fuzzy-logic 72 | and neural-network techniques," Computers & Geosciences, vol. 22, 73 | pp. 585-588, 1996. 74 | 75 | Examples 76 | -------- 77 | These are written in doctest format, and should illustrate how to 78 | use the function. 79 | 80 | >>> a = [1, 2, 3] 81 | >>> print([x + 3 for x in a]) 82 | [4, 5, 6] 83 | >>> print("a\nb") 84 | a 85 | b 86 | """ -------------------------------------------------------------------------------- /TidalPy/RadialSolver/rs_solution_.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "eos_solution_.hpp" 10 | #include "love_.hpp" 11 | #include "nondimensional_.hpp" 12 | 13 | const size_t MAX_NUM_Y = 6; 14 | const size_t MAX_NUM_Y_REAL = 12; // Maximum number of y values counting both the real and imaginary portions. 15 | 16 | 17 | // Error Codes: 18 | // -1 : Equation of State storage (EOSSolutionCC) could not be initialized. 19 | // -2 : (set by python wrapper) Unknown / Unsupported boundary condition provided. 20 | // -5 : There was a problem with the inputs to radial solver 21 | 22 | // -1X : Error in shooting method 23 | // -10 : Error in finding starting conditions 24 | // -11 : Numerical integration failed 25 | // -12 : Error using ZGESV solver with boundary condition 26 | // 27 | // -2X : Error in propagation matrix method 28 | // -20 : Unknown core starting conditions 29 | // -21 : Error using ZGESV solver with boundary condition 30 | 31 | class RadialSolutionStorageCC 32 | { 33 | // Attributes 34 | protected: 35 | 36 | public: 37 | bool success = false; 38 | int error_code = -100; 39 | int degree_l = 0; 40 | std::string message = "No Message Set."; 41 | size_t num_ytypes = 0; 42 | size_t num_slices = 0; 43 | size_t num_layers = 0; 44 | size_t total_size = 0; 45 | 46 | // Equation of state solution 47 | std::unique_ptr eos_solution_uptr = nullptr; 48 | 49 | // Radial solution results 50 | std::vector full_solution_vec = std::vector(); 51 | 52 | // Love number attributes 53 | std::vector complex_love_vec = std::vector(); 54 | 55 | // Diagnostic data 56 | std::vector shooting_method_steps_taken_vec = std::vector(); 57 | 58 | // Constructors and methods 59 | virtual ~RadialSolutionStorageCC(); 60 | RadialSolutionStorageCC(); 61 | RadialSolutionStorageCC( 62 | size_t num_ytypes, 63 | double* upper_radius_bylayer_ptr, 64 | size_t num_layers, 65 | double* radius_array_ptr, 66 | size_t size_radius_array, 67 | int degree_l); 68 | 69 | EOSSolutionCC* get_eos_solution_ptr(); 70 | void change_radius_array( 71 | double* new_radius_array_ptr, 72 | size_t new_size_radius_array, 73 | bool array_changed); 74 | void find_love(); 75 | void dimensionalize_data( 76 | NonDimensionalScalesCC* nondim_scales, 77 | bool redimensionalize); 78 | }; 79 | --------------------------------------------------------------------------------