TidalPy 0.7.5__cp314-cp314-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- TidalPy/Extending/__init__.py +9 -0
- TidalPy/Extending/burnman/__init__.py +10 -0
- TidalPy/Extending/burnman/build.py +196 -0
- TidalPy/Extending/burnman/burnman_defaultc.py +21 -0
- TidalPy/Extending/burnman/burnman_layer.py +408 -0
- TidalPy/Extending/burnman/burnman_world.py +119 -0
- TidalPy/Extending/burnman/conversion.py +13 -0
- TidalPy/Extending/burnman/defaults.py +8 -0
- TidalPy/Extending/burnman/material/__init__.py +0 -0
- TidalPy/Extending/burnman/material/custom/__init__.py +10 -0
- TidalPy/Extending/burnman/material/custom/constant.py +96 -0
- TidalPy/Extending/burnman/material/custom/ice.py +182 -0
- TidalPy/Extending/burnman/material/custom/pyrite.py +29 -0
- TidalPy/Extending/burnman/material/helper.py +115 -0
- TidalPy/Extending/burnman/package.py +47 -0
- TidalPy/Material/__init__.py +0 -0
- TidalPy/Material/eos/__init__.pxd +8 -0
- TidalPy/Material/eos/__init__.py +0 -0
- TidalPy/Material/eos/eos_solution.cp314-win_amd64.pyd +0 -0
- TidalPy/Material/eos/eos_solution.pxd +93 -0
- TidalPy/Material/eos/eos_solution.pyx +2 -0
- TidalPy/Material/eos/eos_solution_.cpp +402 -0
- TidalPy/Material/eos/eos_solution_.hpp +123 -0
- TidalPy/Material/eos/methods/__init__.pxd +1 -0
- TidalPy/Material/eos/methods/__init__.py +0 -0
- TidalPy/Material/eos/methods/interpolate.cp314-win_amd64.pyd +0 -0
- TidalPy/Material/eos/methods/interpolate.pxd +21 -0
- TidalPy/Material/eos/methods/interpolate.pyx +70 -0
- TidalPy/Material/eos/ode.cp314-win_amd64.pyd +0 -0
- TidalPy/Material/eos/ode.pxd +24 -0
- TidalPy/Material/eos/ode.pyx +69 -0
- TidalPy/Material/eos/solver.cp314-win_amd64.pyd +0 -0
- TidalPy/Material/eos/solver.pxd +23 -0
- TidalPy/Material/eos/solver.pyx +279 -0
- TidalPy/RadialSolver/__init__.pxd +2 -0
- TidalPy/RadialSolver/__init__.py +4 -0
- TidalPy/RadialSolver/boundaries/__init__.py +0 -0
- TidalPy/RadialSolver/boundaries/boundaries.cp314-win_amd64.pyd +0 -0
- TidalPy/RadialSolver/boundaries/boundaries.pxd +17 -0
- TidalPy/RadialSolver/boundaries/boundaries.pyx +186 -0
- TidalPy/RadialSolver/boundaries/surface_bc.cp314-win_amd64.pyd +0 -0
- TidalPy/RadialSolver/boundaries/surface_bc.pxd +8 -0
- TidalPy/RadialSolver/boundaries/surface_bc.pyx +163 -0
- TidalPy/RadialSolver/collapse/__init__.py +0 -0
- TidalPy/RadialSolver/collapse/collapse.cp314-win_amd64.pyd +0 -0
- TidalPy/RadialSolver/collapse/collapse.pxd +22 -0
- TidalPy/RadialSolver/collapse/collapse.pyx +175 -0
- TidalPy/RadialSolver/constants.cp314-win_amd64.pyd +0 -0
- TidalPy/RadialSolver/constants.pxd +3 -0
- TidalPy/RadialSolver/constants.pyx +7 -0
- TidalPy/RadialSolver/derivatives/__init__.py +0 -0
- TidalPy/RadialSolver/derivatives/odes.cp314-win_amd64.pyd +0 -0
- TidalPy/RadialSolver/derivatives/odes.pxd +71 -0
- TidalPy/RadialSolver/derivatives/odes.pyx +788 -0
- TidalPy/RadialSolver/helpers.cp314-win_amd64.pyd +0 -0
- TidalPy/RadialSolver/helpers.pyx +570 -0
- TidalPy/RadialSolver/interfaces/__init__.py +0 -0
- TidalPy/RadialSolver/interfaces/interfaces.cp314-win_amd64.pyd +0 -0
- TidalPy/RadialSolver/interfaces/interfaces.pxd +18 -0
- TidalPy/RadialSolver/interfaces/interfaces.pyx +316 -0
- TidalPy/RadialSolver/interfaces/reversed.cp314-win_amd64.pyd +0 -0
- TidalPy/RadialSolver/interfaces/reversed.pxd +21 -0
- TidalPy/RadialSolver/interfaces/reversed.pyx +197 -0
- TidalPy/RadialSolver/love.cp314-win_amd64.pyd +0 -0
- TidalPy/RadialSolver/love.pxd +6 -0
- TidalPy/RadialSolver/love.pyx +30 -0
- TidalPy/RadialSolver/love_.cpp +33 -0
- TidalPy/RadialSolver/love_.hpp +7 -0
- TidalPy/RadialSolver/matrix.cp314-win_amd64.pyd +0 -0
- TidalPy/RadialSolver/matrix.pxd +25 -0
- TidalPy/RadialSolver/matrix.pyx +522 -0
- TidalPy/RadialSolver/matrix_types/__init__.py +1 -0
- TidalPy/RadialSolver/matrix_types/solid_matrix.cp314-win_amd64.pyd +0 -0
- TidalPy/RadialSolver/matrix_types/solid_matrix.pxd +13 -0
- TidalPy/RadialSolver/matrix_types/solid_matrix.pyx +372 -0
- TidalPy/RadialSolver/rs_solution.cp314-win_amd64.pyd +0 -0
- TidalPy/RadialSolver/rs_solution.pxd +105 -0
- TidalPy/RadialSolver/rs_solution.pyx +597 -0
- TidalPy/RadialSolver/rs_solution_.cpp +193 -0
- TidalPy/RadialSolver/rs_solution_.hpp +78 -0
- TidalPy/RadialSolver/shooting.cp314-win_amd64.pyd +0 -0
- TidalPy/RadialSolver/shooting.pxd +42 -0
- TidalPy/RadialSolver/shooting.pyx +976 -0
- TidalPy/RadialSolver/solver.cp314-win_amd64.pyd +0 -0
- TidalPy/RadialSolver/solver.pxd +48 -0
- TidalPy/RadialSolver/solver.pyx +836 -0
- TidalPy/RadialSolver/starting/__init__.py +0 -0
- TidalPy/RadialSolver/starting/common.cp314-win_amd64.pyd +0 -0
- TidalPy/RadialSolver/starting/common.pxd +12 -0
- TidalPy/RadialSolver/starting/common.pyx +159 -0
- TidalPy/RadialSolver/starting/driver.cp314-win_amd64.pyd +0 -0
- TidalPy/RadialSolver/starting/driver.pxd +22 -0
- TidalPy/RadialSolver/starting/driver.pyx +229 -0
- TidalPy/RadialSolver/starting/kamata.cp314-win_amd64.pyd +0 -0
- TidalPy/RadialSolver/starting/kamata.pxd +58 -0
- TidalPy/RadialSolver/starting/kamata.pyx +577 -0
- TidalPy/RadialSolver/starting/saito.cp314-win_amd64.pyd +0 -0
- TidalPy/RadialSolver/starting/saito.pxd +6 -0
- TidalPy/RadialSolver/starting/saito.pyx +47 -0
- TidalPy/RadialSolver/starting/takeuchi.cp314-win_amd64.pyd +0 -0
- TidalPy/RadialSolver/starting/takeuchi.pxd +37 -0
- TidalPy/RadialSolver/starting/takeuchi.pyx +430 -0
- TidalPy/WorldPack/WorldPack.zip +0 -0
- TidalPy/__init__.py +73 -0
- TidalPy/cache.py +71 -0
- TidalPy/configurations.py +251 -0
- TidalPy/constants.cp314-win_amd64.pyd +0 -0
- TidalPy/constants.pxd +74 -0
- TidalPy/constants.pyx +151 -0
- TidalPy/cooling/__init__.py +19 -0
- TidalPy/cooling/cooling.py +288 -0
- TidalPy/cooling/cooling_models.py +185 -0
- TidalPy/defaultc.py +467 -0
- TidalPy/dynamics/__init__.py +15 -0
- TidalPy/dynamics/dual_dissipation.py +165 -0
- TidalPy/dynamics/single_dissipation.py +174 -0
- TidalPy/exceptions.py +230 -0
- TidalPy/initialize.py +105 -0
- TidalPy/logger.py +179 -0
- TidalPy/numba_scipy/__init__.py +7 -0
- TidalPy/numba_scipy/special/__init__.py +3 -0
- TidalPy/numba_scipy/special/overloads.py +25 -0
- TidalPy/numba_scipy/special/signatures.py +96 -0
- TidalPy/orbit/__init__.py +4 -0
- TidalPy/orbit/averaging.py +318 -0
- TidalPy/output.py +38 -0
- TidalPy/paths.py +171 -0
- TidalPy/radiogenics/__init__.py +11 -0
- TidalPy/radiogenics/radiogenic_models.py +123 -0
- TidalPy/radiogenics/radiogenics.py +320 -0
- TidalPy/rheology/__init__.py +14 -0
- TidalPy/rheology/base.cp314-win_amd64.pyd +0 -0
- TidalPy/rheology/base.pxd +33 -0
- TidalPy/rheology/base.pyx +138 -0
- TidalPy/rheology/complex_compliance/__init__.py +17 -0
- TidalPy/rheology/complex_compliance/complex_compliance.py +231 -0
- TidalPy/rheology/complex_compliance/compliance_models.py +655 -0
- TidalPy/rheology/models.cp314-win_amd64.pyd +0 -0
- TidalPy/rheology/models.pxd +36 -0
- TidalPy/rheology/models.pyx +282 -0
- TidalPy/rheology/partial_melt/__init__.py +19 -0
- TidalPy/rheology/partial_melt/melting_models.py +204 -0
- TidalPy/rheology/partial_melt/partialmelt.py +371 -0
- TidalPy/rheology/rheology.py +396 -0
- TidalPy/rheology/viscosity/__init__.py +22 -0
- TidalPy/rheology/viscosity/viscosity.py +169 -0
- TidalPy/rheology/viscosity/viscosity_models.py +162 -0
- TidalPy/stellar/__init__.py +15 -0
- TidalPy/stellar/insolation.py +170 -0
- TidalPy/stellar/stellar.py +53 -0
- TidalPy/structures/__init__.py +5 -0
- TidalPy/structures/helpers/__init__.py +0 -0
- TidalPy/structures/helpers/orbit_config.py +96 -0
- TidalPy/structures/layers/__init__.py +18 -0
- TidalPy/structures/layers/basic.py +501 -0
- TidalPy/structures/layers/gas.py +46 -0
- TidalPy/structures/layers/helper.py +106 -0
- TidalPy/structures/layers/physics.py +660 -0
- TidalPy/structures/orbit/__init__.py +5 -0
- TidalPy/structures/orbit/base.py +1619 -0
- TidalPy/structures/orbit/physics.py +586 -0
- TidalPy/structures/physical.py +967 -0
- TidalPy/structures/world_builder/__init__.py +3 -0
- TidalPy/structures/world_builder/config_handler.py +104 -0
- TidalPy/structures/world_builder/iterative_builder.py +156 -0
- TidalPy/structures/world_builder/world_builder.py +268 -0
- TidalPy/structures/world_types/__init__.py +28 -0
- TidalPy/structures/world_types/basic.py +928 -0
- TidalPy/structures/world_types/gas.py +40 -0
- TidalPy/structures/world_types/layered.py +517 -0
- TidalPy/structures/world_types/stellar.py +95 -0
- TidalPy/structures/world_types/tidal.py +466 -0
- TidalPy/tides/__init__.py +23 -0
- TidalPy/tides/ctl_funcs/__init__.py +11 -0
- TidalPy/tides/ctl_funcs/ctl_funcs.py +53 -0
- TidalPy/tides/dissipation.py +56 -0
- TidalPy/tides/eccentricity_funcs/__init__.py +177 -0
- TidalPy/tides/eccentricity_funcs/orderl2.py +848 -0
- TidalPy/tides/eccentricity_funcs/orderl3.py +879 -0
- TidalPy/tides/eccentricity_funcs/orderl4.py +1023 -0
- TidalPy/tides/eccentricity_funcs/orderl5.py +1161 -0
- TidalPy/tides/eccentricity_funcs/orderl6.py +1309 -0
- TidalPy/tides/eccentricity_funcs/orderl7.py +1451 -0
- TidalPy/tides/heating.py +52 -0
- TidalPy/tides/inclination_funcs/__init__.py +73 -0
- TidalPy/tides/inclination_funcs/orderl2.py +56 -0
- TidalPy/tides/inclination_funcs/orderl3.py +62 -0
- TidalPy/tides/inclination_funcs/orderl4.py +74 -0
- TidalPy/tides/inclination_funcs/orderl5.py +88 -0
- TidalPy/tides/inclination_funcs/orderl6.py +102 -0
- TidalPy/tides/inclination_funcs/orderl7.py +116 -0
- TidalPy/tides/love1d.py +159 -0
- TidalPy/tides/methods/__init__.py +3 -0
- TidalPy/tides/methods/base.py +867 -0
- TidalPy/tides/methods/global_approx.py +464 -0
- TidalPy/tides/methods/layered.py +331 -0
- TidalPy/tides/modes/__init__.py +2 -0
- TidalPy/tides/modes/collapse_modes.py +107 -0
- TidalPy/tides/modes/mode_calc_helper/__init__.py +110 -0
- TidalPy/tides/modes/mode_calc_helper/eccen_calc_orderl2.py +274 -0
- TidalPy/tides/modes/mode_calc_helper/eccen_calc_orderl3.py +260 -0
- TidalPy/tides/modes/mode_calc_helper/eccen_calc_orderl4.py +270 -0
- TidalPy/tides/modes/mode_calc_helper/eccen_calc_orderl5.py +280 -0
- TidalPy/tides/modes/mode_calc_helper/eccen_calc_orderl6.py +290 -0
- TidalPy/tides/modes/mode_calc_helper/eccen_calc_orderl7.py +300 -0
- TidalPy/tides/modes/mode_calc_helper/inclin_calc_orderl2.py +60 -0
- TidalPy/tides/modes/mode_calc_helper/inclin_calc_orderl3.py +62 -0
- TidalPy/tides/modes/mode_calc_helper/inclin_calc_orderl4.py +64 -0
- TidalPy/tides/modes/mode_calc_helper/inclin_calc_orderl5.py +66 -0
- TidalPy/tides/modes/mode_calc_helper/inclin_calc_orderl6.py +68 -0
- TidalPy/tides/modes/mode_calc_helper/inclin_calc_orderl7.py +70 -0
- TidalPy/tides/modes/mode_manipulation.py +465 -0
- TidalPy/tides/modes/modes.py +147 -0
- TidalPy/tides/modes/multilayer_modes.py +535 -0
- TidalPy/tides/multilayer/__init__.py +7 -0
- TidalPy/tides/multilayer/displacements.py +76 -0
- TidalPy/tides/multilayer/heating.cp314-win_amd64.pyd +0 -0
- TidalPy/tides/multilayer/heating.pxd +16 -0
- TidalPy/tides/multilayer/heating.pyx +237 -0
- TidalPy/tides/multilayer/sensitivity.cp314-win_amd64.pyd +0 -0
- TidalPy/tides/multilayer/sensitivity.pxd +21 -0
- TidalPy/tides/multilayer/sensitivity.pyx +335 -0
- TidalPy/tides/multilayer/stress_strain.py +209 -0
- TidalPy/tides/potential/__init__.py +18 -0
- TidalPy/tides/potential/nsr_med_eccen_gen_obliquity.py +476 -0
- TidalPy/tides/potential/nsr_med_eccen_med_obliquity.py +391 -0
- TidalPy/tides/potential/nsr_med_eccen_no_obliquity.py +311 -0
- TidalPy/tides/potential/nsr_modes_low_eccen_gen_obliquity.py +425 -0
- TidalPy/tides/potential/nsr_modes_med_eccen_gen_obliquity.py +507 -0
- TidalPy/tides/potential/nsr_modes_med_eccen_med_obliquity.py +414 -0
- TidalPy/tides/potential/nsr_modes_med_eccen_no_obliquity.py +324 -0
- TidalPy/tides/potential/synchronous_low_e.py +128 -0
- TidalPy/tides/universal_coeffs.py +74 -0
- TidalPy/toolbox/__init__.py +2 -0
- TidalPy/toolbox/quick_tides.py +725 -0
- TidalPy/utilities/__init__.py +0 -0
- TidalPy/utilities/arrays/__init__.py +0 -0
- TidalPy/utilities/arrays/interp.pxd +25 -0
- TidalPy/utilities/arrays/interp.pyx +2 -0
- TidalPy/utilities/arrays/interp_.cpp +321 -0
- TidalPy/utilities/arrays/interp_.hpp +30 -0
- TidalPy/utilities/classes/__init__.py +8 -0
- TidalPy/utilities/classes/base.py +14 -0
- TidalPy/utilities/classes/base_x.cp314-win_amd64.pyd +0 -0
- TidalPy/utilities/classes/base_x.pxd +5 -0
- TidalPy/utilities/classes/base_x.pyx +29 -0
- TidalPy/utilities/classes/config/__init__.py +3 -0
- TidalPy/utilities/classes/config/config.py +426 -0
- TidalPy/utilities/classes/model/__init__.py +2 -0
- TidalPy/utilities/classes/model/functional_utils.py +98 -0
- TidalPy/utilities/classes/model/model.py +450 -0
- TidalPy/utilities/classes/model/model_utils.py +119 -0
- TidalPy/utilities/conversions/__init__.py +10 -0
- TidalPy/utilities/conversions/conversions.py +182 -0
- TidalPy/utilities/conversions/conversions_x.cp314-win_amd64.pyd +0 -0
- TidalPy/utilities/conversions/conversions_x.pxd +37 -0
- TidalPy/utilities/conversions/conversions_x.pyx +214 -0
- TidalPy/utilities/conversions/timing.py +34 -0
- TidalPy/utilities/dictionary_utils.py +191 -0
- TidalPy/utilities/dimensions/__init__.py +0 -0
- TidalPy/utilities/dimensions/nondimensional.cp314-win_amd64.pyd +0 -0
- TidalPy/utilities/dimensions/nondimensional.pxd +18 -0
- TidalPy/utilities/dimensions/nondimensional.pyx +94 -0
- TidalPy/utilities/dimensions/nondimensional_.hpp +13 -0
- TidalPy/utilities/exoplanets/__init__.py +1 -0
- TidalPy/utilities/exoplanets/data_download.py +135 -0
- TidalPy/utilities/graphics/__init__.py +10 -0
- TidalPy/utilities/graphics/global_map.py +329 -0
- TidalPy/utilities/graphics/grid_plot.py +763 -0
- TidalPy/utilities/graphics/multilayer/RN08-Data.csv +52 -0
- TidalPy/utilities/graphics/multilayer/T05-Data.csv +1 -0
- TidalPy/utilities/graphics/multilayer/__init__.py +1 -0
- TidalPy/utilities/graphics/multilayer/yplot.py +249 -0
- TidalPy/utilities/graphics/phasespace_plot.py +158 -0
- TidalPy/utilities/graphics/planet_plot.py +308 -0
- TidalPy/utilities/integration/__init__.py +170 -0
- TidalPy/utilities/integration/cyrk_helper.py +41 -0
- TidalPy/utilities/integration/julia_helper.py +134 -0
- TidalPy/utilities/integration/numbalsoda_helper.py +38 -0
- TidalPy/utilities/integration/scipy_helper.py +28 -0
- TidalPy/utilities/io/__init__.py +0 -0
- TidalPy/utilities/io/pathing.py +38 -0
- TidalPy/utilities/io/progress.py +57 -0
- TidalPy/utilities/math/__init__.pxd +5 -0
- TidalPy/utilities/math/__init__.py +0 -0
- TidalPy/utilities/math/complex.cp314-win_amd64.pyd +0 -0
- TidalPy/utilities/math/complex.pxd +43 -0
- TidalPy/utilities/math/complex.pyx +496 -0
- TidalPy/utilities/math/numba_special.py +64 -0
- TidalPy/utilities/math/numerics.cp314-win_amd64.pyd +0 -0
- TidalPy/utilities/math/numerics.pxd +8 -0
- TidalPy/utilities/math/numerics.pyx +37 -0
- TidalPy/utilities/math/special.cp314-win_amd64.pyd +0 -0
- TidalPy/utilities/math/special.pxd +1 -0
- TidalPy/utilities/math/special.pyx +81 -0
- TidalPy/utilities/multiprocessing/__init__.py +24 -0
- TidalPy/utilities/multiprocessing/multiprocessing.py +473 -0
- TidalPy/utilities/numpy_helper/__init__.py +3 -0
- TidalPy/utilities/numpy_helper/array_other.py +129 -0
- TidalPy/utilities/numpy_helper/array_shape.py +92 -0
- TidalPy/utilities/performance/__init__.py +19 -0
- TidalPy/utilities/performance/memory.py +53 -0
- TidalPy/utilities/performance/numba.py +75 -0
- TidalPy/utilities/performance/special/__init__.py +1 -0
- TidalPy/utilities/performance/special/factorial.py +28 -0
- TidalPy/utilities/spherical_helper/__init__.py +4 -0
- TidalPy/utilities/spherical_helper/mass.py +62 -0
- TidalPy/utilities/spherical_helper/volume.py +126 -0
- TidalPy/utilities/string_helper/__init__.py +2 -0
- TidalPy/utilities/string_helper/string_helper.py +120 -0
- TidalPy/utilities/types.py +30 -0
- TidalPy/utilities/types_x.cp314-win_amd64.pyd +0 -0
- TidalPy/utilities/types_x.pxd +3 -0
- TidalPy/utilities/types_x.pyx +2 -0
- tidalpy-0.7.5.dist-info/DELVEWHEEL +2 -0
- tidalpy-0.7.5.dist-info/METADATA +339 -0
- tidalpy-0.7.5.dist-info/RECORD +322 -0
- tidalpy-0.7.5.dist-info/WHEEL +5 -0
- tidalpy-0.7.5.dist-info/entry_points.txt +2 -0
- tidalpy-0.7.5.dist-info/licenses/LICENSE.md +179 -0
- tidalpy-0.7.5.dist-info/top_level.txt +1 -0
- tidalpy.libs/msvcp140-a4c2229bdc2a2a630acdc095b4d86008.dll +0 -0
|
@@ -0,0 +1,9 @@
|
|
|
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)
|
|
@@ -0,0 +1,10 @@
|
|
|
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
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
from typing import Tuple
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
from TidalPy.exceptions import BadValueError, ParameterMissingError, ParameterValueError
|
|
6
|
+
from TidalPy.utilities.types import float_eps
|
|
7
|
+
from TidalPy.Extending.burnman.package import burnman, burnman_installed
|
|
8
|
+
from TidalPy.Extending.burnman.defaults import default_burnman_layer_params
|
|
9
|
+
from TidalPy.Extending.burnman.material.helper import find_material
|
|
10
|
+
|
|
11
|
+
from TidalPy.logger import get_logger
|
|
12
|
+
log = get_logger("TidalPy")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def build_layer(layer_name: str, layer_config: dict, burnman_verbose: str = False) -> burnman.Layer:
|
|
16
|
+
""" Build a Burnman layer
|
|
17
|
+
|
|
18
|
+
Parameters
|
|
19
|
+
----------
|
|
20
|
+
layer_name : str
|
|
21
|
+
Name of the layer
|
|
22
|
+
layer_config : dict
|
|
23
|
+
Dictionary of layer configurations used to initialize the layer
|
|
24
|
+
burnman_verbose : bool, default = False
|
|
25
|
+
Determines the verboseness of the BurnMan package.
|
|
26
|
+
|
|
27
|
+
Returns
|
|
28
|
+
-------
|
|
29
|
+
layer : burnman.Layer
|
|
30
|
+
An initialized burnman layer
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
# Record information
|
|
34
|
+
log.debug(f'Burnman layer {layer_name} being built.')
|
|
35
|
+
if not burnman_installed:
|
|
36
|
+
log.debug("Burnman install not found.")
|
|
37
|
+
raise ImportError('Burnman package not found.')
|
|
38
|
+
|
|
39
|
+
# Load in defaults
|
|
40
|
+
layer_config = {**default_burnman_layer_params, **layer_config}
|
|
41
|
+
|
|
42
|
+
# Check for missing parameters
|
|
43
|
+
for param_name in ['radii', 'material', 'material_source', 'temperature_mode']:
|
|
44
|
+
if param_name not in layer_config:
|
|
45
|
+
raise ParameterMissingError(f'BurnMan Layer requires parameter: {param_name}')
|
|
46
|
+
|
|
47
|
+
material = layer_config['material']
|
|
48
|
+
material_source = layer_config['material_source']
|
|
49
|
+
|
|
50
|
+
# Determine if the material is a composite or not
|
|
51
|
+
composite = False
|
|
52
|
+
if type(layer_config['material']) in [list, tuple]:
|
|
53
|
+
log.debug(f'Composite material encountered for layer: {layer_name}.')
|
|
54
|
+
composite = True
|
|
55
|
+
|
|
56
|
+
if composite:
|
|
57
|
+
try:
|
|
58
|
+
material_fractions = layer_config['material_fractions']
|
|
59
|
+
except KeyError:
|
|
60
|
+
raise ParameterMissingError("Multiple materials provided but no material_fraction's were given.")
|
|
61
|
+
if type(material_fractions) not in [list, tuple]:
|
|
62
|
+
raise ParameterValueError('Material fractions must be provided as a list or tuple.')
|
|
63
|
+
if type(material_source) not in [list, tuple]:
|
|
64
|
+
raise ParameterValueError('Multiple materials provided with only one source.')
|
|
65
|
+
if len(material) != len(material_source):
|
|
66
|
+
raise ParameterValueError('Number of composite materials is not the same as number of material sources.')
|
|
67
|
+
if len(material) != len(material_fractions):
|
|
68
|
+
raise ParameterValueError('Number of composite materials is not the same as number of material fractions.')
|
|
69
|
+
|
|
70
|
+
if type(material_fractions) is tuple:
|
|
71
|
+
# Burnman only supports lists for this
|
|
72
|
+
material_fractions = list(material_fractions)
|
|
73
|
+
|
|
74
|
+
material_instances = list()
|
|
75
|
+
for mat_name, mat_source in zip(material, material_source):
|
|
76
|
+
# Find BurnMan material based on material and source name
|
|
77
|
+
material_class = find_material(mat_name, mat_source)
|
|
78
|
+
material_instances.append(material_class())
|
|
79
|
+
|
|
80
|
+
# Build composite material
|
|
81
|
+
init_material = burnman.Composite(material_instances, material_fractions)
|
|
82
|
+
|
|
83
|
+
else:
|
|
84
|
+
# Find BurnMan material based on material and source name
|
|
85
|
+
material_class = find_material(layer_config['material'], layer_config['material_source'])
|
|
86
|
+
|
|
87
|
+
# Initialize material
|
|
88
|
+
init_material = material_class()
|
|
89
|
+
|
|
90
|
+
# Make layer and load in material
|
|
91
|
+
radii = layer_config['radii']
|
|
92
|
+
layer = burnman.Layer(name=layer_name, radii=radii, verbose=burnman_verbose)
|
|
93
|
+
layer.set_material(init_material)
|
|
94
|
+
|
|
95
|
+
# Don't keep radii in the config, otherwise it will save to the json file as a large list
|
|
96
|
+
del layer_config['radii']
|
|
97
|
+
|
|
98
|
+
# Load in temperature model
|
|
99
|
+
if layer_config['temperature_mode'] == 'adiabatic':
|
|
100
|
+
if layer_config.get('temperature_top', None) is None:
|
|
101
|
+
layer.set_temperature_mode('adiabatic')
|
|
102
|
+
else:
|
|
103
|
+
layer.set_temperature_mode('adiabatic', temperature_top=layer_config['temperature_top'])
|
|
104
|
+
elif layer_config['temperature_mode'] == 'user-defined':
|
|
105
|
+
layer.set_temperature_mode('user-defined', layer_config['temperature_fixed'] * np.ones_like(radii))
|
|
106
|
+
else:
|
|
107
|
+
layer.set_temperature_mode(layer_config['temperature_mode'])
|
|
108
|
+
|
|
109
|
+
return layer
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def build_burnman_world(planet_config: dict, verbose: bool = False) -> Tuple[burnman.Planet, Tuple[burnman.Layer, ...]]:
|
|
113
|
+
""" Builds a BurnMan planet from a provided configuration dictionary.
|
|
114
|
+
|
|
115
|
+
Parameters
|
|
116
|
+
----------
|
|
117
|
+
planet_config : dict
|
|
118
|
+
Dictionary of planet configurations used to initialize layers and the planet.
|
|
119
|
+
verbose : bool = False
|
|
120
|
+
If True, BurnMan will print more information to console.
|
|
121
|
+
|
|
122
|
+
Returns
|
|
123
|
+
-------
|
|
124
|
+
burnman_world : burnman.Planet
|
|
125
|
+
An initialized and built burnman planet class
|
|
126
|
+
burnman_layers : Tuple[burnman.Layer, ...]
|
|
127
|
+
An ordered list of initialized burnman layers
|
|
128
|
+
"""
|
|
129
|
+
|
|
130
|
+
log.debug(f"Building BurnMan world: {planet_config['name']}")
|
|
131
|
+
|
|
132
|
+
if not burnman_installed:
|
|
133
|
+
log.debug("Burnman install not found.")
|
|
134
|
+
raise ImportError('Burnman package not found.')
|
|
135
|
+
|
|
136
|
+
# Store Layer information
|
|
137
|
+
try:
|
|
138
|
+
layers = planet_config['layers']
|
|
139
|
+
except KeyError:
|
|
140
|
+
raise ParameterMissingError('BurnMan Planet must have at least one layer.')
|
|
141
|
+
|
|
142
|
+
# Set defaults if none are provided
|
|
143
|
+
last_layer_radius = 0.
|
|
144
|
+
for layer_i, (layer_name, layer_config_user) in enumerate(layers.items()):
|
|
145
|
+
|
|
146
|
+
log.debug(f"Initializing layer: {layer_name}")
|
|
147
|
+
|
|
148
|
+
# Check if layer has must-have parameters
|
|
149
|
+
for param_name in ['type', 'material', 'radius']:
|
|
150
|
+
if param_name not in layer_config_user:
|
|
151
|
+
raise ParameterMissingError(f'BurnMan Layer requires parameter: {param_name}')
|
|
152
|
+
|
|
153
|
+
# Load in defaults for non-required parameters if not present
|
|
154
|
+
layer_config = {**default_burnman_layer_params, **layer_config_user}
|
|
155
|
+
|
|
156
|
+
# Load in calculated parameters
|
|
157
|
+
if 'thickness' not in layer_config:
|
|
158
|
+
if layer_i == 0:
|
|
159
|
+
layer_config['thickness'] = layer_config['radius']
|
|
160
|
+
else:
|
|
161
|
+
layer_config['thickness'] = layer_config['radius'] - last_layer_radius
|
|
162
|
+
layer_config['radius_upper'] = layer_config['radius']
|
|
163
|
+
layer_config['radius_lower'] = layer_config['radius_upper'] - layer_config['thickness']
|
|
164
|
+
layer_config['radii'] = np.linspace(
|
|
165
|
+
layer_config['radius_lower'], layer_config['radius_upper'],
|
|
166
|
+
layer_config['slices'], endpoint=True
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
# Check for physical consistency
|
|
170
|
+
if layer_config['thickness'] <= float_eps:
|
|
171
|
+
raise BadValueError('Layer thickness must be non-zero')
|
|
172
|
+
if layer_i > 0:
|
|
173
|
+
if layer_config['radius_lower'] != last_layer_radius:
|
|
174
|
+
raise BadValueError('Layers must stack on top of one another')
|
|
175
|
+
|
|
176
|
+
last_layer_radius = layer_config['radius']
|
|
177
|
+
# Put the new config back into the layers storage
|
|
178
|
+
layers[layer_name] = layer_config
|
|
179
|
+
|
|
180
|
+
# Build BurnMan layers
|
|
181
|
+
log.debug("Building BurnMan Layers")
|
|
182
|
+
burnman_layers_byname = {layer_name: build_layer(layer_name, layer_data) for layer_name, layer_data in
|
|
183
|
+
layers.items()}
|
|
184
|
+
burnman_layers = [burnman_layers_byname[layer_name] for layer_name in layers]
|
|
185
|
+
|
|
186
|
+
# Build BurnMan Planet
|
|
187
|
+
log.debug(f"Initializing BurnMan Planet for {planet_config['name']}")
|
|
188
|
+
burnman_world = burnman.Planet(planet_config['name'], burnman_layers, verbose=verbose)
|
|
189
|
+
# Note: This section can be slow!
|
|
190
|
+
burnman_world.make()
|
|
191
|
+
log.debug('BurnMan world construction completed')
|
|
192
|
+
|
|
193
|
+
# Change layer list to tuple to emphasize that these should not change or mutate
|
|
194
|
+
burnman_layers = tuple(burnman_layers)
|
|
195
|
+
|
|
196
|
+
return burnman_world, burnman_layers
|
|
@@ -0,0 +1,21 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
from typing import TYPE_CHECKING
|
|
2
|
+
|
|
3
|
+
burnman_installed = True
|
|
4
|
+
try:
|
|
5
|
+
import burnman
|
|
6
|
+
except ImportError:
|
|
7
|
+
burnman_installed = False
|
|
8
|
+
# Build fake class so type checking passes.
|
|
9
|
+
class burnman:
|
|
10
|
+
Planet = None
|
|
11
|
+
Layer = None
|
|
12
|
+
Material = None
|
|
13
|
+
|
|
14
|
+
import numpy as np
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
import TidalPy
|
|
18
|
+
from TidalPy.exceptions import (AttributeNotSetError, ImproperPropertyHandling, UnknownTidalPyConfigValue)
|
|
19
|
+
from TidalPy.utilities.numpy_helper.array_other import find_nearest
|
|
20
|
+
from TidalPy.utilities.types import FloatArray
|
|
21
|
+
from TidalPy.structures.layers.physics import PhysicsLayer
|
|
22
|
+
from TidalPy.Extending.burnman.conversion import burnman_property_name_conversion, burnman_property_value_conversion
|
|
23
|
+
|
|
24
|
+
from TidalPy.logger import get_logger
|
|
25
|
+
log = get_logger("TidalPy")
|
|
26
|
+
|
|
27
|
+
if TYPE_CHECKING:
|
|
28
|
+
from .burnman_world import BurnManWorld
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class BurnmanLayer(PhysicsLayer):
|
|
32
|
+
""" BurnmanLayer
|
|
33
|
+
Layer object to store parameters calculated by the Burnman software. Additionally it contains properties and
|
|
34
|
+
functionality that matches the TidalPy `PhysicsLayer`.
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
See Also
|
|
38
|
+
--------
|
|
39
|
+
TidalPy.structures.layers.PhysicsLayer
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
layer_class = 'burnman'
|
|
43
|
+
|
|
44
|
+
def __init__(
|
|
45
|
+
self, layer_name: str, layer_index: int, world: 'BurnManWorld', layer_config: dict,
|
|
46
|
+
is_top_layer: bool, initialize: bool = True
|
|
47
|
+
):
|
|
48
|
+
""" Burnman layer constructor
|
|
49
|
+
|
|
50
|
+
Parameters
|
|
51
|
+
----------
|
|
52
|
+
layer_name : str
|
|
53
|
+
User-friendly name of layer.
|
|
54
|
+
layer_index : int
|
|
55
|
+
Location of layer within a world (0 indicates center-most).
|
|
56
|
+
world : LayeredWorldType
|
|
57
|
+
World instance where layer was initialized in.
|
|
58
|
+
layer_config : dict
|
|
59
|
+
Layer's user-provided configurations.
|
|
60
|
+
is_top_layer : bool
|
|
61
|
+
If `True`, this layer is the top-most layer.
|
|
62
|
+
initialize : bool = True
|
|
63
|
+
If `True`, then the Layer's reinit is called at the end of the constructor.
|
|
64
|
+
"""
|
|
65
|
+
|
|
66
|
+
if not burnman_installed:
|
|
67
|
+
log.warning('Burnman package not found. BurnmanLayer will have limited functionality.')
|
|
68
|
+
|
|
69
|
+
super().__init__(layer_name, layer_index, world, layer_config, is_top_layer, initialize=False)
|
|
70
|
+
|
|
71
|
+
# BurnmanLayer is built on the BurnMan API and layer system.
|
|
72
|
+
# Pull out BurnMan parameters
|
|
73
|
+
burnman_layer = self.world.bm_layers[layer_index]
|
|
74
|
+
self._bm_layer = burnman_layer
|
|
75
|
+
self._bm_material = burnman_layer.material
|
|
76
|
+
|
|
77
|
+
# Other state variables that will be initialized later
|
|
78
|
+
self._bm_mid_index = None
|
|
79
|
+
self._persistent_pressure = None
|
|
80
|
+
self.interp_func = None
|
|
81
|
+
|
|
82
|
+
# Material Properties set by BurnMan
|
|
83
|
+
self.interp_temperature_range = np.linspace(
|
|
84
|
+
*tuple(self.config['interp_temperature_range']),
|
|
85
|
+
self.world.config['bm_interpolation_n']
|
|
86
|
+
)
|
|
87
|
+
self._interp_prop_data_lookup = dict()
|
|
88
|
+
|
|
89
|
+
if initialize:
|
|
90
|
+
self.reinit(initial_init=initialize)
|
|
91
|
+
|
|
92
|
+
def reinit(self, initial_init: bool = False, initialize_geometry: bool = False):
|
|
93
|
+
""" Reinitialize the physical object by pulling in any potentially new configurations
|
|
94
|
+
|
|
95
|
+
Parameters
|
|
96
|
+
----------
|
|
97
|
+
initial_init : bool = False
|
|
98
|
+
Set to `True` for the first time an instance is created.
|
|
99
|
+
set_by_burnman : bool = False
|
|
100
|
+
Set to `True` if a Burnman layer/world constructor is calling reinit
|
|
101
|
+
initialize_geometry : bool = False
|
|
102
|
+
Set to `True` if the set_geometry method should be called from within reinit
|
|
103
|
+
"""
|
|
104
|
+
|
|
105
|
+
if initial_init or initialize_geometry:
|
|
106
|
+
# Find how many slices
|
|
107
|
+
self._num_slices = len(self.bm_layer.radii)
|
|
108
|
+
|
|
109
|
+
# Find which slice index is nearest to the middle of the layer (as determined by the radius/thickness)
|
|
110
|
+
thickness = self.bm_layer.thickness
|
|
111
|
+
self._bm_mid_index = find_nearest(self.bm_layer.radii, self.bm_layer.radii - (thickness / 2.))
|
|
112
|
+
|
|
113
|
+
# Setup geometry
|
|
114
|
+
self.set_geometry(radius=self.bm_layer.outer_radius, mass=self.bm_layer.mass, thickness=thickness)
|
|
115
|
+
|
|
116
|
+
# Call the standard reinit for the physics layer
|
|
117
|
+
super().reinit(initial_init, initialize_geometry=False)
|
|
118
|
+
|
|
119
|
+
# Build lookup tables
|
|
120
|
+
self._build_material_property_interpolation()
|
|
121
|
+
|
|
122
|
+
def set_state(
|
|
123
|
+
self, temperature: FloatArray = None, pressure: FloatArray = None, viscosity: FloatArray = None,
|
|
124
|
+
shear_modulus: FloatArray = None
|
|
125
|
+
):
|
|
126
|
+
""" Set the layer's state properties
|
|
127
|
+
|
|
128
|
+
Parameters
|
|
129
|
+
----------
|
|
130
|
+
temperature : FloatArray = None
|
|
131
|
+
New dynamic temperature for the layer [K].
|
|
132
|
+
pressure : FloatArray = None
|
|
133
|
+
New dynamic pressure for the layer [Pa].
|
|
134
|
+
viscosity : FloatArray = None
|
|
135
|
+
The new viscosity of the layer in [Pa s]
|
|
136
|
+
shear_modulus : FloatArray = None
|
|
137
|
+
The new shear modulus of the layer in [Pa]
|
|
138
|
+
|
|
139
|
+
"""
|
|
140
|
+
|
|
141
|
+
# Check if the pressure or temperature of the layer has changed.
|
|
142
|
+
temperature_change = temperature is not None
|
|
143
|
+
|
|
144
|
+
# TODO: pressure_change is currently unused (see TODO below).
|
|
145
|
+
# pressure_change = pressure is not None
|
|
146
|
+
|
|
147
|
+
if temperature_change:
|
|
148
|
+
# Update material properties interpolated by burnman.
|
|
149
|
+
|
|
150
|
+
# TODO: Current limitations:
|
|
151
|
+
# - No material properties change when the pressure changes.
|
|
152
|
+
# - Future: Build another look up table for pressure?
|
|
153
|
+
# - Does not make calls to Burnman's EOS calculator for temperature changes, instead a lookup table is
|
|
154
|
+
# used to find pre-calculated values for the material properties.
|
|
155
|
+
# - Generally this should be okay for small temperature changes, but the larger the delta-temp the
|
|
156
|
+
# larger the error will be.
|
|
157
|
+
# - Recalculating the EOS can be computationally expensive, especially once it is wrapped within a bunch
|
|
158
|
+
# of TidalPy methods. This may be a major limitation to TidalPy's future development.
|
|
159
|
+
# - Workaround: the user can access the burnman layer and planet to manually update the EOS, but changes
|
|
160
|
+
# won't propagate into the TidalPy methods (as of writing).
|
|
161
|
+
|
|
162
|
+
# Set new material properties based on BurnMan Interpolation
|
|
163
|
+
for prop_name, prop_data in self._interp_prop_data_lookup.items():
|
|
164
|
+
setattr(self, prop_name, np.interp(temperature, self.interp_temperature_range, prop_data))
|
|
165
|
+
self.thermal_diffusivity = self.thermal_conductivity / (self.density * self.specific_heat)
|
|
166
|
+
|
|
167
|
+
# Set the new state properties in the layer.
|
|
168
|
+
super().set_state(temperature=temperature, pressure=pressure, viscosity=viscosity, shear_modulus=shear_modulus)
|
|
169
|
+
|
|
170
|
+
def set_geometry(
|
|
171
|
+
self, radius: float = None, mass: float = None, thickness: float = None,
|
|
172
|
+
mass_below: float = 0., update_state_geometry: bool = True, build_slices: bool = True
|
|
173
|
+
):
|
|
174
|
+
""" Calculates and sets the layer's physical parameters based on user provided input.
|
|
175
|
+
|
|
176
|
+
For a BurnmanLayer almost all of the geometry is set by the results of the burnman evaluation.
|
|
177
|
+
|
|
178
|
+
Assumptions
|
|
179
|
+
-----------
|
|
180
|
+
Spherical Geometry
|
|
181
|
+
|
|
182
|
+
Parameters
|
|
183
|
+
----------
|
|
184
|
+
radius : float = None
|
|
185
|
+
Outer radius of object [m]
|
|
186
|
+
mass : float = None
|
|
187
|
+
Mass of object [kg]
|
|
188
|
+
thickness : float = None
|
|
189
|
+
Thickness of the object [m]
|
|
190
|
+
mass_below : float = 0.
|
|
191
|
+
Mass below this object (only applicable for shell-like structures)
|
|
192
|
+
Used in gravity and pressure calculations
|
|
193
|
+
update_state_geometry : bool = True
|
|
194
|
+
Update the class' state geometry
|
|
195
|
+
build_slices : bool = True
|
|
196
|
+
If True, method will attempt to calculate gravities, densities, etc. for each slice.
|
|
197
|
+
|
|
198
|
+
"""
|
|
199
|
+
|
|
200
|
+
# Set the physical properties
|
|
201
|
+
self._radius = self.bm_layer.outer_radius
|
|
202
|
+
self._thickness = self.bm_layer.thickness
|
|
203
|
+
self._radius_middle = self.radius - (self.thickness / 2.)
|
|
204
|
+
self._radius_inner = self.radius - self.thickness
|
|
205
|
+
self._volume = (4. / 3.) * np.pi * (self.radius**3 - self.radius_inner**3)
|
|
206
|
+
self._surface_area_outer = 4. * np.pi * self.radius**2
|
|
207
|
+
self._surface_area_middle = 4. * np.pi * self.radius_middle**2
|
|
208
|
+
self._surface_area_inner = 4. * np.pi * self.radius_inner**2
|
|
209
|
+
|
|
210
|
+
# Set the mass properties
|
|
211
|
+
self._mass = self.bm_layer.mass
|
|
212
|
+
self._density_bulk = self.mass / self.volume
|
|
213
|
+
if self.layer_below is None:
|
|
214
|
+
layer_below_mass = 0.
|
|
215
|
+
else:
|
|
216
|
+
layer_below_mass = self.layer_below.mass
|
|
217
|
+
self._mass_below = layer_below_mass
|
|
218
|
+
|
|
219
|
+
# Set slice physical properties
|
|
220
|
+
# For Burnman layers we want to skip the first step, we will do this for all items pulled from BM.
|
|
221
|
+
# But we want to keep the same number of shells. So we will perform an interpolation to expand from the
|
|
222
|
+
# Burnman values
|
|
223
|
+
bm_radii = self.bm_layer.radii
|
|
224
|
+
self._radii = np.linspace(bm_radii[1], bm_radii[-1], self.num_slices)
|
|
225
|
+
self._depths = self.radius - self._radii
|
|
226
|
+
self._sa_slices = 4. * np.pi * self.radii**2
|
|
227
|
+
self._volume_slices = np.zeros_like(self._radii)
|
|
228
|
+
self._volume_slices[0] = (4. / 3.) * np.pi * (self.radii[0]**3 - self.radius_inner**3)
|
|
229
|
+
self._volume_slices[1:] = (4. / 3.) * np.pi * (self.radii[1:]**3 - self.radii[:-1]**3)
|
|
230
|
+
|
|
231
|
+
# Set slice mass properties
|
|
232
|
+
self._density_slices = np.interp(self.radii, bm_radii, self.bm_layer.density)
|
|
233
|
+
self._gravity_slices = np.interp(self.radii, bm_radii, self.bm_layer.gravity)
|
|
234
|
+
self._pressure_slices = np.interp(self.radii, bm_radii, self.bm_layer.pressures)
|
|
235
|
+
self._mass_slices = self.density_slices * self.volume_slices
|
|
236
|
+
|
|
237
|
+
# Mass below each slice is equal to slice masses + and mass below this physical object
|
|
238
|
+
self._mass_below_slices = np.asarray(
|
|
239
|
+
[self.mass_below + sum(self.mass_slices[:i + 1]) for i in range(self.num_slices)]
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
# For BurnmanLayer, assume everything is calculated by BurnMan.
|
|
243
|
+
# Override some of the items set by the set_geometry method.
|
|
244
|
+
if self.world.config['bm_interpolation_method'] == 'mid':
|
|
245
|
+
self._pressure_middle = self.bm_layer.pressures[self._bm_mid_index]
|
|
246
|
+
self._density_middle = self.bm_layer.density[self._bm_mid_index]
|
|
247
|
+
self._gravity_middle = self.bm_layer.gravity[self._bm_mid_index]
|
|
248
|
+
self.interp_func = lambda array: array[self._bm_mid_index]
|
|
249
|
+
elif self.world.config['bm_interpolation_method'] == 'avg':
|
|
250
|
+
self._pressure_middle = np.average(self.bm_layer.pressures)
|
|
251
|
+
self._density_middle = np.average(self.bm_layer.density)
|
|
252
|
+
self._gravity_middle = np.average(self.bm_layer.gravity)
|
|
253
|
+
self.interp_func = np.average
|
|
254
|
+
elif self.world.config['bm_interpolation_method'] == 'median':
|
|
255
|
+
self._pressure_middle = np.median(self.bm_layer.pressures)
|
|
256
|
+
self._density_middle = np.median(self.bm_layer.density)
|
|
257
|
+
self._gravity_middle = np.median(self.bm_layer.gravity)
|
|
258
|
+
self.interp_func = np.median
|
|
259
|
+
else:
|
|
260
|
+
raise UnknownTidalPyConfigValue
|
|
261
|
+
|
|
262
|
+
# Set up a pressure that will persist if the layer's state is cleared
|
|
263
|
+
self._persistent_pressure = np.copy(self.pressure)
|
|
264
|
+
|
|
265
|
+
# Update state properties
|
|
266
|
+
# Note: these are not actually accessible without using the protected getter.
|
|
267
|
+
# Instead, the regular getter method pulls from the BurnMan layer directly (they have been inner-scoped)
|
|
268
|
+
# These definitions below are set just so that the protected properties still hold a value.
|
|
269
|
+
self._temperature_outer = self.bm_layer.temperatures[-1]
|
|
270
|
+
self._temperature_inner = self.bm_layer.temperatures[0]
|
|
271
|
+
self._density_outer = self.bm_layer.density[-1]
|
|
272
|
+
self._density_inner = self.bm_layer.density[0]
|
|
273
|
+
self._gravity_outer = self.bm_layer.gravity[-1]
|
|
274
|
+
self._gravity_inner = self.bm_layer.gravity[0]
|
|
275
|
+
self._pressure_outer = self.bm_layer.pressures[-1]
|
|
276
|
+
self._pressure_inner = self.bm_layer.pressures[0]
|
|
277
|
+
|
|
278
|
+
# Make a call to the parent methods set_geometry method, but update_state_geometry=False will prevent them from
|
|
279
|
+
# changing the geometry that was set above.
|
|
280
|
+
super().set_geometry(
|
|
281
|
+
self.radius, self.mass, self.thickness, mass_below=layer_below_mass,
|
|
282
|
+
update_state_geometry=False, build_slices=False
|
|
283
|
+
)
|
|
284
|
+
|
|
285
|
+
def set_static_pressure(
|
|
286
|
+
self, pressure_above: float = None, build_slices: bool = True,
|
|
287
|
+
called_from_burnman: bool = True
|
|
288
|
+
):
|
|
289
|
+
""" Sets the static pressure for the physical structure.
|
|
290
|
+
|
|
291
|
+
`Static` here indicates that this is not a dynamic pressure used in many calculations. The static pressure can
|
|
292
|
+
be used in place of the dynamic pressure, but that is not always the case.
|
|
293
|
+
|
|
294
|
+
Parameters
|
|
295
|
+
----------
|
|
296
|
+
pressure_above : float = None
|
|
297
|
+
Pressure above this structure. If this is a layer, then it is the pressure at the base of the overlying
|
|
298
|
+
layer. If it is the upper-most layer or a world, then it may be the surface pressure.
|
|
299
|
+
build_slices : bool = True
|
|
300
|
+
If `True`, method will find the pressure at each slice of the physical object.
|
|
301
|
+
called_from_burnman : bool = False
|
|
302
|
+
Set to `True` if called from a burnman layer/world.
|
|
303
|
+
"""
|
|
304
|
+
log.debug('Static pressure method called from burnman layer - skipping update.')
|
|
305
|
+
# super().set_static_pressure(pressure_above, build_slices)
|
|
306
|
+
|
|
307
|
+
def geotherm(self, avg_temperature: float = None):
|
|
308
|
+
""" Calculates layer's geotherm based on an average temperature (or layer's current temperature)
|
|
309
|
+
|
|
310
|
+
Returns
|
|
311
|
+
-------
|
|
312
|
+
temperature_profile : np.ndarray
|
|
313
|
+
numpy array of the adiabatic temperature profile
|
|
314
|
+
"""
|
|
315
|
+
|
|
316
|
+
if avg_temperature is None:
|
|
317
|
+
avg_temperature = self.temperature
|
|
318
|
+
|
|
319
|
+
temperature_profile = \
|
|
320
|
+
burnman.geotherm.adiabatic(self.bm_layer.pressures, avg_temperature, self.bm_layer.material)
|
|
321
|
+
|
|
322
|
+
# We again want to shrink the temperature domain to match the radii which only take [1:] of the Burnman version.
|
|
323
|
+
bm_radii = self.bm_layer.radii
|
|
324
|
+
temperature_profile = np.interp(self.radii, bm_radii, temperature_profile)
|
|
325
|
+
|
|
326
|
+
return temperature_profile
|
|
327
|
+
|
|
328
|
+
def _build_material_property_interpolation(self):
|
|
329
|
+
""" Interpolates material properties based on a fixed pressure and a suggested temperature range.
|
|
330
|
+
|
|
331
|
+
Using the BurnMan package's equation of states, this function will build interpolated lookup tables for several
|
|
332
|
+
material properties. These lookup tables are functions of only temperature; pressure is assumed to not
|
|
333
|
+
change significantly in a TidalPy simulation. However, the machinery to change properties based on
|
|
334
|
+
pressure is built into BurnMan and can be accessed via the layer's reference to the Burnman layer:
|
|
335
|
+
self.bm_material.evaluate
|
|
336
|
+
|
|
337
|
+
The specific constant pressure used in building the lookup table is set by the layer configuration. See the
|
|
338
|
+
variable 'bm_interpolation_method' in TidalPy's main configurations.py
|
|
339
|
+
|
|
340
|
+
Conversions between BurnMan and TidalPy property names are also performed here. Some conversions require a
|
|
341
|
+
transition from molar to specific.
|
|
342
|
+
|
|
343
|
+
The final interpolated lookup table is stored in the self._interp_prop_data_lookup which is used in the
|
|
344
|
+
temperature.setter
|
|
345
|
+
"""
|
|
346
|
+
|
|
347
|
+
log.debug(f'Building Burnman material property lookup tables for {self}.')
|
|
348
|
+
|
|
349
|
+
if self.pressure is None:
|
|
350
|
+
raise AttributeNotSetError
|
|
351
|
+
|
|
352
|
+
self._interp_prop_data_lookup = dict()
|
|
353
|
+
interp_properties = ['bulk_modulus', 'thermal_expansion', 'specific_heat']
|
|
354
|
+
bm_properties = [burnman_property_name_conversion[interp_prop] for interp_prop in interp_properties]
|
|
355
|
+
|
|
356
|
+
# We will use the fixed pressure to calculate the various parameters at all the temperature ranges
|
|
357
|
+
# These results will then be used in an interpolation for whenever self.temperature changes
|
|
358
|
+
pressures = self.pressure * np.ones_like(self.interp_temperature_range)
|
|
359
|
+
property_results = self.bm_material.evaluate(bm_properties, pressures, self.interp_temperature_range)
|
|
360
|
+
|
|
361
|
+
for interp_prop, prop_result in zip(interp_properties, property_results):
|
|
362
|
+
|
|
363
|
+
# Perform any unit or other conversions needed to interface BurnMan to TidalPy
|
|
364
|
+
conversion_type = burnman_property_value_conversion.get(interp_prop, None)
|
|
365
|
+
if conversion_type is not None:
|
|
366
|
+
if conversion_type == 'molar':
|
|
367
|
+
# Convert the parameter from a molar value to a specific value
|
|
368
|
+
prop_result = prop_result / self.bm_material.molar_mass
|
|
369
|
+
else:
|
|
370
|
+
raise KeyError
|
|
371
|
+
|
|
372
|
+
self._interp_prop_data_lookup[interp_prop] = np.asarray(prop_result)
|
|
373
|
+
|
|
374
|
+
# State properties
|
|
375
|
+
@property
|
|
376
|
+
def bm_layer(self) -> burnman.Layer:
|
|
377
|
+
return self._bm_layer
|
|
378
|
+
|
|
379
|
+
@bm_layer.setter
|
|
380
|
+
def bm_layer(self, value):
|
|
381
|
+
raise ImproperPropertyHandling('Can not change burnman layer information after layer has been initialized.')
|
|
382
|
+
|
|
383
|
+
@property
|
|
384
|
+
def bm_material(self) -> burnman.Material:
|
|
385
|
+
return self._bm_material
|
|
386
|
+
|
|
387
|
+
@bm_material.setter
|
|
388
|
+
def bm_material(self, value):
|
|
389
|
+
raise ImproperPropertyHandling('Can not change burnman layer information after layer has been initialized.')
|
|
390
|
+
|
|
391
|
+
@property
|
|
392
|
+
def pressure(self):
|
|
393
|
+
""" Layer's dynamic pressure used in calculations """
|
|
394
|
+
# If there is no user provided pressure, use the one set by burnman
|
|
395
|
+
if self._pressure is None:
|
|
396
|
+
return self.pressure_middle
|
|
397
|
+
else:
|
|
398
|
+
return self._pressure
|
|
399
|
+
|
|
400
|
+
@pressure.setter
|
|
401
|
+
def pressure(self, new_pressure: FloatArray):
|
|
402
|
+
self.set_pressure(new_pressure)
|
|
403
|
+
|
|
404
|
+
# Add burnman layer type to known layer types
|
|
405
|
+
log.debug('Adding BurnmanLayer to known layer classes.')
|
|
406
|
+
TidalPy.structures.layers.known_layer_classes['burnman'] = BurnmanLayer
|
|
407
|
+
log.debug('Adding BurnmanLayer to known layer classes (by world type).')
|
|
408
|
+
TidalPy.structures.layers.layers_class_by_world_class['burnman'] = BurnmanLayer
|