nautilus-astrochem-code 2.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. nautilus_astrochem_code-2.1.0/.codespell.toml +3 -0
  2. nautilus_astrochem_code-2.1.0/.fortitude.toml +24 -0
  3. nautilus_astrochem_code-2.1.0/.fprettify.yaml +17 -0
  4. nautilus_astrochem_code-2.1.0/.pre-commit-config.yaml +25 -0
  5. nautilus_astrochem_code-2.1.0/LICENSE +28 -0
  6. nautilus_astrochem_code-2.1.0/PKG-INFO +74 -0
  7. nautilus_astrochem_code-2.1.0/Readme.md +52 -0
  8. nautilus_astrochem_code-2.1.0/meson.build +71 -0
  9. nautilus_astrochem_code-2.1.0/meson.options +27 -0
  10. nautilus_astrochem_code-2.1.0/nautilus_astrochem_code/__init__.py +11 -0
  11. nautilus_astrochem_code-2.1.0/nautilus_astrochem_code/binaries/__init__.py +0 -0
  12. nautilus_astrochem_code-2.1.0/nautilus_astrochem_code/binaries/binary.py +135 -0
  13. nautilus_astrochem_code-2.1.0/nautilus_astrochem_code/binaries/nautilus_ascii.py +9 -0
  14. nautilus_astrochem_code-2.1.0/nautilus_astrochem_code/binaries/nautilus_code.py +113 -0
  15. nautilus_astrochem_code-2.1.0/nautilus_astrochem_code/binaries/nautilus_rates.py +75 -0
  16. nautilus_astrochem_code-2.1.0/nautilus_astrochem_code/binaries/utils.py +59 -0
  17. nautilus_astrochem_code-2.1.0/nautilus_astrochem_code/cli.py +96 -0
  18. nautilus_astrochem_code-2.1.0/nautilus_astrochem_code/meson.build +39 -0
  19. nautilus_astrochem_code-2.1.0/nautilus_astrochem_code/py.typed +0 -0
  20. nautilus_astrochem_code-2.1.0/pyproject.toml +133 -0
  21. nautilus_astrochem_code-2.1.0/src/git_infos/git_infos.f90 +16 -0
  22. nautilus_astrochem_code-2.1.0/src/git_infos/meson.build +39 -0
  23. nautilus_astrochem_code-2.1.0/src/meson.build +65 -0
  24. nautilus_astrochem_code-2.1.0/src/nautilus.f90 +480 -0
  25. nautilus_astrochem_code-2.1.0/src/nautilus_core/dust_temperature_module.f90 +675 -0
  26. nautilus_astrochem_code-2.1.0/src/nautilus_core/input_output.f90 +1022 -0
  27. nautilus_astrochem_code-2.1.0/src/nautilus_core/meson.build +22 -0
  28. nautilus_astrochem_code-2.1.0/src/nautilus_core/nautilus_main.f90 +1707 -0
  29. nautilus_astrochem_code-2.1.0/src/nautilus_core/ode_solver.f90 +2473 -0
  30. nautilus_astrochem_code-2.1.0/src/nautilus_core/shielding.f90 +841 -0
  31. nautilus_astrochem_code-2.1.0/src/nautilus_core/structure.f90 +741 -0
  32. nautilus_astrochem_code-2.1.0/src/nautilus_global/configuration.f90 +138 -0
  33. nautilus_astrochem_code-2.1.0/src/nautilus_global/global_variables.f90 +680 -0
  34. nautilus_astrochem_code-2.1.0/src/nautilus_global/meson.build +16 -0
  35. nautilus_astrochem_code-2.1.0/src/nautilus_global/numerical_types.f90 +18 -0
  36. nautilus_astrochem_code-2.1.0/src/nautilus_global/utilities.f90 +163 -0
  37. nautilus_astrochem_code-2.1.0/src/nautilus_io/impl_default_io.f90 +225 -0
  38. nautilus_astrochem_code-2.1.0/src/nautilus_io/impl_netcdf_io.f90 +544 -0
  39. nautilus_astrochem_code-2.1.0/src/nautilus_io/meson.build +28 -0
  40. nautilus_astrochem_code-2.1.0/src/nautilus_io/nautilus_io.f90 +122 -0
  41. nautilus_astrochem_code-2.1.0/src/nautilus_major_reactions.f90 +551 -0
  42. nautilus_astrochem_code-2.1.0/src/nautilus_outputs.f90 +169 -0
  43. nautilus_astrochem_code-2.1.0/src/nautilus_rates.f90 +189 -0
  44. nautilus_astrochem_code-2.1.0/src/nautilus_rates_netcdf.f90 +518 -0
  45. nautilus_astrochem_code-2.1.0/src/nautilus_select_outputs.f90 +235 -0
  46. nautilus_astrochem_code-2.1.0/src/nautilus_trace_major.f90 +585 -0
  47. nautilus_astrochem_code-2.1.0/src/tests/CMakeLists.txt +3 -0
  48. nautilus_astrochem_code-2.1.0/src/tests/io/CMakeLists.txt +3 -0
  49. nautilus_astrochem_code-2.1.0/src/tests/io/test_io_netcdf.f90 +24 -0
  50. nautilus_astrochem_code-2.1.0/src/tests/migration/CMakeLists.txt +2 -0
  51. nautilus_astrochem_code-2.1.0/src/tests/migration/test_iso_fortran_env.f90 +37 -0
  52. nautilus_astrochem_code-2.1.0/src/tests/parameters/CMakeLists.txt +3 -0
  53. nautilus_astrochem_code-2.1.0/src/tests/parameters/test_compounds.f90 +17 -0
  54. nautilus_astrochem_code-2.1.0/subprojects/.wraplock +0 -0
  55. nautilus_astrochem_code-2.1.0/subprojects/opkd/Readme.md +16 -0
  56. nautilus_astrochem_code-2.1.0/subprojects/opkd/meson.build +121 -0
  57. nautilus_astrochem_code-2.1.0/subprojects/opkd/meson.options +16 -0
  58. nautilus_astrochem_code-2.1.0/subprojects/opkd/opkda1.f90 +9794 -0
  59. nautilus_astrochem_code-2.1.0/subprojects/opkd/opkda2-blas.f90 +593 -0
  60. nautilus_astrochem_code-2.1.0/subprojects/opkd/opkda2-linpack.f90 +579 -0
  61. nautilus_astrochem_code-2.1.0/subprojects/opkd/opkda2.f90 +268 -0
  62. nautilus_astrochem_code-2.1.0/subprojects/opkd/opkdmain.f90 +16442 -0
  63. nautilus_astrochem_code-2.1.0/tests/__init__.py +0 -0
  64. nautilus_astrochem_code-2.1.0/tests/conftest.py +0 -0
  65. nautilus_astrochem_code-2.1.0/tests/test_binaries.py +10 -0
  66. nautilus_astrochem_code-2.1.0/version.sh +20 -0
@@ -0,0 +1,3 @@
1
+ [tool.codespell]
2
+ ignore-words-list = 'blanck,inout,INOUT,indext,DELT,fillin,YHE,activ,ACTIV,fonction,ans,oint,te,composant'
3
+ skip = 'subprojects/**'
@@ -0,0 +1,24 @@
1
+ [check]
2
+ line-length = 300
3
+ preview = true
4
+ extend-exclude = [
5
+ 'tests',
6
+ 'subprojects',
7
+ 'src/nautilus_major_reactions.f90',
8
+ 'src/nautilus_rates.f90',
9
+ 'src/nautilus_outputs.f90',
10
+ 'src/nautilus_select_outputs.f90',
11
+ 'src/nautilus_trace_major.f90',
12
+ ]
13
+ # uvx --from fortitude-lint@latest fortitude explain S241
14
+ ignore = [
15
+ 'S241', # [quotes]()
16
+ 'C051', # [trailing backslash]()
17
+ 'C091', # [external procedure](https://fortitude.readthedocs.io/en/stable/rules/external-procedure/#external-procedure-c091)
18
+ 'C121', # [use stmt](https://fortitude.readthedocs.io/en/stable/rules/use-all/#use-all-c121)
19
+ 'C131', # [accessibility statement](https://fortitude.readthedocs.io/en/stable/rules/missing-accessibility-statement/)
20
+ 'C181', # [unchecked-stat](https://fortitude.readthedocs.io/en/stable/rules/unchecked-stat/#unchecked-stat-c181)
21
+ ]
22
+
23
+ [check.strings]
24
+ quotes = 'single'
@@ -0,0 +1,17 @@
1
+ ---
2
+ whitespace-comma: true
3
+ whitespace-plusminus: 1
4
+ whitespace-multdiv: 0
5
+
6
+ strip-comments: true
7
+ enable-decl: true
8
+ enable-replacements: true
9
+ c-relations: true
10
+
11
+ # keywords, procedures/modules, operators and constants
12
+ case: [1, 1, 1, 0] # 0: do nothing | 1:lowercase | 2: uppercase
13
+
14
+ indent: 3
15
+ line-length: 300
16
+
17
+ exclude: subprojects/*
@@ -0,0 +1,25 @@
1
+ repos:
2
+ - repo: https://github.com/codespell-project/codespell
3
+ rev: v2.4.3
4
+ hooks:
5
+ - id: codespell
6
+ args: [ --toml, .codespell.toml ]
7
+
8
+ # Fortran
9
+ - repo: https://github.com/PlasmaFAIR/fortitude-pre-commit
10
+ rev: v0.9.2
11
+ hooks:
12
+ - id: fortitude
13
+ args: [ '--config-file=.fortitude.toml', '--fix' ]
14
+ - repo: https://github.com/fortran-lang/fprettify
15
+ rev: v0.3.7
16
+ hooks:
17
+ - id: fprettify
18
+ args: [ '-c', '.fprettify.yaml', '-r', 'nautilus-astrochem-code/src' ]
19
+ - repo: https://github.com/trim21/pre-commit-mirror-meson
20
+ rev: v1.12.0
21
+ hooks:
22
+ - id: meson-fmt
23
+ args: [ '--inplace', '--recursive' ]
24
+ - id: meson-fmt
25
+ args: [ '--check-only', '--recursive' ]
@@ -0,0 +1,28 @@
1
+ The nautilus gas-grain code has been developed at the ''Laboratoire d'astrophysique de Bordeaux''
2
+ by a group of researchers led by Valentine Wakelam from the original code of Eric Herbst (Hasegawa et al. 1992).
3
+
4
+ Copyright is protected by the following license:
5
+
6
+ '''MIT License
7
+ Copyright (c) 2016 Valentine Wakelam
8
+ Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ of this software and associated documentation files (the "Software"), to deal
10
+ in the Software without restriction, including without limitation the rights
11
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ copies of the Software, and to permit persons to whom the Software is
13
+ furnished to do so, subject to the following conditions:
14
+ The above copyright notice and this permission notice shall be included in all
15
+ copies or substantial portions of the Software.
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.'''
23
+
24
+ When publishing results obtained with nautilus (and any modified version of it), the authors should include the reference:
25
+ ''Ruaud et al.~Monthly Notices of the Royal Astronomical Society, Volume 459, Issue 4, p.3756-3767.''
26
+
27
+ '''If we provide the code for external users of the group, we do not provide any user support.
28
+ If users want help, then they can contact us, but this will be done in the context of a collaboration.'''
@@ -0,0 +1,74 @@
1
+ Metadata-Version: 2.4
2
+ Name: nautilus-astrochem-code
3
+ Version: 2.1.0
4
+ Summary: Fortran simulation binaries for the NAUTILUS gas-grain chemistry code
5
+ Author-Email: Valentine Wakelam <valentine.wakelam@u-bordeaux.fr>, Alexandre Mechineau <alexandre.mechineau@u-bordeaux.fr>
6
+ License-Expression: MIT
7
+ License-File: LICENSE
8
+ Classifier: Intended Audience :: Science/Research
9
+ Classifier: Programming Language :: Fortran
10
+ Classifier: Programming Language :: Python :: 3 :: Only
11
+ Classifier: Programming Language :: Python :: 3.11
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Programming Language :: Python :: 3.13
14
+ Classifier: Programming Language :: Python :: 3.14
15
+ Classifier: Topic :: Scientific/Engineering :: Astronomy
16
+ Classifier: Topic :: Scientific/Engineering :: Chemistry
17
+ Classifier: Typing :: Typed
18
+ Requires-Python: >=3.11
19
+ Requires-Dist: loguru>=0.7.3
20
+ Requires-Dist: tyro>=1.0.15
21
+ Description-Content-Type: text/markdown
22
+
23
+ # Nautilus gas-grain code for astrochemistry
24
+
25
+ ![Stable Version](https://img.shields.io/pypi/v/nautilus_astrochem_code?style=for-the-badge&label=Stable)
26
+ ![Python Versions](https://img.shields.io/pypi/pyversions/nautilus_astrochem_code?style=for-the-badge&label=Python)
27
+
28
+ > Python CLI for the Nautilus gas-grain astrochemistry code.
29
+
30
+ [![](https://img.shields.io/badge/doc-Users-green?style=for-the-badge)](https://lab.pages.in2p3.fr/astrochem-tools/nautilus-doc/ "Science & Examples")
31
+ [![](https://img.shields.io/badge/doc-IN2P3-green?style=for-the-badge)](https://lab.pages.in2p3.fr/astrochem-tools/pnautilus "Public documentation")
32
+ [![](https://img.shields.io/badge/doc-Framagit-grey?style=for-the-badge)](https://wakelam.frama.io/nautilus "Private documentation")
33
+
34
+ This package is part of the [Nautilus](https://gitlab.in2p3.fr/LAB/astrochem-tools/pnautilus) project.
35
+
36
+ It provides the compiled Fortran binaries of
37
+ the [Nautilus gas-grain code](https://gitlab.in2p3.fr/LAB/astrochem-tools/pnautilus/-/tree/main/nautilus-astrochem-code)
38
+ for astrochemistry: `nautilus_code` and `nautilus_rates_netcdf`.
39
+
40
+ > [!important]
41
+ > You are not meant to call these binaries directly.
42
+ > Install the [nautilus-astrochem](https://pypi.org/project/nautilus-astrochem) package instead:
43
+ > it drives these binaries and adds plotting and post-processing.
44
+
45
+ ## Getting started
46
+
47
+ To get started with `nautilus-astrochem-code`, we offer a repository
48
+ [nautilus-doc](https://gitlab.in2p3.fr/LAB/astrochem-tools/nautilus-doc),
49
+ with scientific documentation and examples of use cases ready to run.
50
+ This repository is used to provide the [documentation website](https://lab.pages.in2p3.fr/astrochem-tools/nautilus-doc/),
51
+ where the content of the documentation is available.
52
+
53
+ ## Installation
54
+
55
+ This package is a dependency of `nautilus-astrochem`; you normally install it through that
56
+ package rather than on its own.
57
+
58
+ ### Common issues
59
+
60
+ We provide pre-built wheels for the most common platforms.
61
+ When no wheel matches your platform, or if you force a build from the source,
62
+ the binaries are compiled during installation, so you must provide:
63
+
64
+ - a Fortran compiler, and
65
+ - the netcdf library for Fortran.
66
+
67
+ Only `gfortran` with `netcdf-fortran` is tested for now.
68
+
69
+ - on macOS: `sudo port install gcc14 netcdf-fortran` or `brew install gcc netcdf-fortran`
70
+ - on Ubuntu: `apt install gfortran libnetcdff-dev`
71
+
72
+ ## Contact
73
+
74
+ Requests or questions can be sent to valentine.wakelam@u-bordeaux.fr.
@@ -0,0 +1,52 @@
1
+ # Nautilus gas-grain code for astrochemistry
2
+
3
+ ![Stable Version](https://img.shields.io/pypi/v/nautilus_astrochem_code?style=for-the-badge&label=Stable)
4
+ ![Python Versions](https://img.shields.io/pypi/pyversions/nautilus_astrochem_code?style=for-the-badge&label=Python)
5
+
6
+ > Python CLI for the Nautilus gas-grain astrochemistry code.
7
+
8
+ [![](https://img.shields.io/badge/doc-Users-green?style=for-the-badge)](https://lab.pages.in2p3.fr/astrochem-tools/nautilus-doc/ "Science & Examples")
9
+ [![](https://img.shields.io/badge/doc-IN2P3-green?style=for-the-badge)](https://lab.pages.in2p3.fr/astrochem-tools/pnautilus "Public documentation")
10
+ [![](https://img.shields.io/badge/doc-Framagit-grey?style=for-the-badge)](https://wakelam.frama.io/nautilus "Private documentation")
11
+
12
+ This package is part of the [Nautilus](https://gitlab.in2p3.fr/LAB/astrochem-tools/pnautilus) project.
13
+
14
+ It provides the compiled Fortran binaries of
15
+ the [Nautilus gas-grain code](https://gitlab.in2p3.fr/LAB/astrochem-tools/pnautilus/-/tree/main/nautilus-astrochem-code)
16
+ for astrochemistry: `nautilus_code` and `nautilus_rates_netcdf`.
17
+
18
+ > [!important]
19
+ > You are not meant to call these binaries directly.
20
+ > Install the [nautilus-astrochem](https://pypi.org/project/nautilus-astrochem) package instead:
21
+ > it drives these binaries and adds plotting and post-processing.
22
+
23
+ ## Getting started
24
+
25
+ To get started with `nautilus-astrochem-code`, we offer a repository
26
+ [nautilus-doc](https://gitlab.in2p3.fr/LAB/astrochem-tools/nautilus-doc),
27
+ with scientific documentation and examples of use cases ready to run.
28
+ This repository is used to provide the [documentation website](https://lab.pages.in2p3.fr/astrochem-tools/nautilus-doc/),
29
+ where the content of the documentation is available.
30
+
31
+ ## Installation
32
+
33
+ This package is a dependency of `nautilus-astrochem`; you normally install it through that
34
+ package rather than on its own.
35
+
36
+ ### Common issues
37
+
38
+ We provide pre-built wheels for the most common platforms.
39
+ When no wheel matches your platform, or if you force a build from the source,
40
+ the binaries are compiled during installation, so you must provide:
41
+
42
+ - a Fortran compiler, and
43
+ - the netcdf library for Fortran.
44
+
45
+ Only `gfortran` with `netcdf-fortran` is tested for now.
46
+
47
+ - on macOS: `sudo port install gcc14 netcdf-fortran` or `brew install gcc netcdf-fortran`
48
+ - on Ubuntu: `apt install gfortran libnetcdff-dev`
49
+
50
+ ## Contact
51
+
52
+ Requests or questions can be sent to valentine.wakelam@u-bordeaux.fr.
@@ -0,0 +1,71 @@
1
+ project(
2
+ 'Nautilus',
3
+ ['fortran', 'c'],
4
+ version : '2.1.0',
5
+ default_options : ['b_pie=true', 'b_lto=true', 'b_lto_mode=thin', 'warning_level=3', 'default_library=static'],
6
+ meson_version : '>=1.9'
7
+ )
8
+ meson.add_dist_script('version.sh', 'set-dist', meson.project_version())
9
+
10
+
11
+ # Common flags to optimize used by both, `nautilus` and `opkd`
12
+ # -ffast-math -finit-real=nan
13
+ ## Flags recommended by maqao
14
+ # -funroll-loops -march=native
15
+
16
+ fc = meson.get_compiler('fortran')
17
+ if fc.get_id() == 'gcc'
18
+ arg = '-ffree-line-length-0'
19
+ if fc.has_argument(arg)
20
+ add_project_arguments(arg, language: 'fortran')
21
+ endif
22
+
23
+ add_project_arguments('-fimplicit-none', language: 'fortran')
24
+ endif
25
+
26
+ if fc.get_id() == 'intel'
27
+ args = []
28
+ args += ['-diag-disable=10448']
29
+ args += ['-Qparallel']
30
+
31
+ add_project_arguments(args, language: 'fortran')
32
+ add_project_link_arguments(args, language: 'fortran')
33
+ endif
34
+
35
+ # Use vendored package.
36
+ opkd_sp = subproject('opkd')
37
+ opkd_dep = opkd_sp.get_variable('opkd_dep')
38
+
39
+ if get_option('verify')
40
+ warning('Check memory and float operations')
41
+ add_project_arguments(
42
+ [
43
+ '-fcheck=all',
44
+ '-fbounds-check',
45
+ '-fstack-protector-all',
46
+ '-fno-omit-frame-pointer',
47
+ '-fbacktrace',
48
+ ],
49
+ language: 'fortran',
50
+ )
51
+ add_project_arguments(
52
+ [
53
+ '-finit-real=snan',
54
+ '-ffpe-trap=invalid,zero,overflow',
55
+ ],
56
+ language: 'fortran',
57
+ )
58
+ endif
59
+
60
+ # add python package
61
+ subdir('nautilus_astrochem_code')
62
+ # add fortran source
63
+ subdir('src')
64
+
65
+
66
+ # add doxygen doc
67
+ fs = import('fs')
68
+
69
+ if fs.exists('doc/meson.build')
70
+ subdir('doc')
71
+ endif
@@ -0,0 +1,27 @@
1
+ option(
2
+ 'verify',
3
+ type: 'boolean',
4
+ value: false,
5
+ description: 'Enable extra Fortran runtime/debug checks',
6
+ )
7
+
8
+ option(
9
+ 'enable_python',
10
+ type: 'boolean',
11
+ value: false,
12
+ description: 'Build the python package',
13
+ )
14
+
15
+ option(
16
+ 'enable_doxygen',
17
+ type: 'boolean',
18
+ value: false,
19
+ description: 'Build the doxygen documentation',
20
+ )
21
+
22
+ option(
23
+ 'enable_ascii_binaries',
24
+ type: 'boolean',
25
+ value: true,
26
+ description: 'Build the binary for the original ASCII format',
27
+ )
@@ -0,0 +1,11 @@
1
+ """
2
+ Provides access to the `nautilus_code` and `nautilus_rates` command.
3
+ Also expose their input class.
4
+
5
+ User should not need to import anything from this module or its submodules.
6
+ """
7
+
8
+ from .binaries.nautilus_code import NautilusCode, nautilus_code
9
+ from .binaries.nautilus_rates import NautilusRates, nautilus_rates
10
+
11
+ __all__ = ('NautilusCode', 'NautilusRates', 'nautilus_code', 'nautilus_rates')
@@ -0,0 +1,135 @@
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ from contextlib import contextmanager
5
+ from typing import TYPE_CHECKING, Literal, NoReturn, assert_never, overload
6
+
7
+ from loguru import logger
8
+
9
+ if TYPE_CHECKING:
10
+ from collections.abc import Generator
11
+ from pathlib import Path
12
+ from subprocess import CompletedProcess
13
+
14
+ __all__ = ('NautilusBinary', 'get_nautilus_binary', 'invoke_binary')
15
+
16
+ NautilusBinary = Literal['nautilus_code', 'nautilus_rates', 'nautilus_rates_netcdf']
17
+ """Available binaries from the nautilus astrochemistry code."""
18
+
19
+ NautilusAsciiBinary = Literal[
20
+ 'nautilus_outputs', 'nautilus_select_outputs', 'nautilus_major_reactions', 'nautilus_trace_major'
21
+ ]
22
+
23
+
24
+ def get_version() -> str:
25
+ """Get the version of the package."""
26
+ import importlib.metadata
27
+
28
+ return importlib.metadata.version('nautilus-astrochem-code')
29
+
30
+
31
+ def get_sideloaded_nautilus_binary(binary_name: NautilusBinary | NautilusAsciiBinary, build_dir: Path) -> Path:
32
+ logger.warning(f'Sideloading `{binary_name}` -> {build_dir} [from NAUTILUS_ASTROCHEM_BUILD_DIR]')
33
+
34
+ bin_path = build_dir / 'src' / binary_name
35
+
36
+ if not bin_path.is_file():
37
+ msg = f'`NAUTILUS_ASTROCHEM_BUILD_DIR` set to `{build_dir}`, but `{bin_path}` was not found.'
38
+ raise FileNotFoundError(msg)
39
+
40
+ if not os.access(bin_path, os.X_OK):
41
+ bin_path.chmod(0o755)
42
+
43
+ return bin_path
44
+
45
+
46
+ @contextmanager
47
+ def get_nautilus_binary(
48
+ binary_name: NautilusBinary | NautilusAsciiBinary, *, allow_sideload: bool = False
49
+ ) -> Generator[Path]:
50
+ """Get the path to a nautilus binary.
51
+
52
+ If `allow_sideload` is set and `NAUTILUS_ASTROCHEM_BUILD_DIR` is set, sideload the binary
53
+ from that user-managed meson build directory, instead of the one bundled in the package.
54
+ Useful during development to pick up a Fortran rebuild without reinstalling the python package.
55
+
56
+ `allow_sideload` is only ever set by `nautilus_astrochem_code`'s own CLI entrypoints: downstream
57
+ consumers are unable to enable it, so their users cannot sideload binaries regardless
58
+ of environment variables set on their machine.
59
+
60
+ Otherwise, fall back to the binary bundled with the package.
61
+ Log the path and version of the binary.
62
+ """
63
+ from pathlib import Path
64
+
65
+ # Fast path: if sideload is allowed and build dir is set, use that
66
+ if allow_sideload is True and (build_dir := os.getenv('NAUTILUS_ASTROCHEM_BUILD_DIR')) is not None:
67
+ yield get_sideloaded_nautilus_binary(binary_name, Path(build_dir))
68
+ return
69
+
70
+ from importlib import resources
71
+
72
+ binary = resources.files(__package__).joinpath(binary_name)
73
+ with resources.as_file(binary) as bin_path:
74
+ if not os.access(bin_path, os.X_OK):
75
+ bin_path.chmod(0o755)
76
+
77
+ logger.debug(f'Using `{binary_name}` -> {bin_path} [{get_version()}]')
78
+ yield bin_path
79
+
80
+
81
+ @overload
82
+ def invoke_binary(
83
+ binary_name: NautilusBinary | NautilusAsciiBinary,
84
+ args: list[str],
85
+ *,
86
+ dry: bool,
87
+ use_subprocess: Literal[True],
88
+ allow_sideload: bool,
89
+ ) -> CompletedProcess[str]: ...
90
+
91
+
92
+ @overload
93
+ def invoke_binary(
94
+ binary_name: NautilusBinary | NautilusAsciiBinary,
95
+ args: list[str],
96
+ *,
97
+ dry: bool,
98
+ use_subprocess: Literal[False],
99
+ allow_sideload: bool,
100
+ ) -> NoReturn: ...
101
+
102
+
103
+ def invoke_binary(
104
+ binary_name: NautilusBinary | NautilusAsciiBinary,
105
+ args: list[str],
106
+ *,
107
+ dry: bool,
108
+ use_subprocess: bool,
109
+ allow_sideload: bool = False,
110
+ ) -> CompletedProcess[str]:
111
+ """Allow invoking a binary matching `NautilusBinary | NautilusAsciiBinary` with its arguments.
112
+
113
+ The other flags allow controlling the invocations.
114
+ """
115
+ import subprocess # ruff: ignore[suspicious-subprocess-import]
116
+ import sys
117
+
118
+ with get_nautilus_binary(binary_name, allow_sideload=allow_sideload) as bin_path:
119
+ logger.debug(f'With: {args}')
120
+ bin_str = str(bin_path)
121
+
122
+ match use_subprocess:
123
+ case True:
124
+ if dry is True:
125
+ return subprocess.CompletedProcess(args=[bin_str, *args], returncode=0)
126
+
127
+ return subprocess.run([bin_str, *args], capture_output=False, text=True, check=True) # ruff: ignore[subprocess-without-shell-equals-true]
128
+ case False:
129
+ if dry is True:
130
+ return sys.exit(0)
131
+ # replace this process rather than spawning a child:
132
+ # correct exit code, correct signal forwarding (Ctrl+C, SIGTERM), no double process
133
+ return os.execv(bin_str, [bin_str, *args]) # ruff: ignore[start-process-with-no-shell]
134
+ case _:
135
+ assert_never(use_subprocess)
@@ -0,0 +1,9 @@
1
+ from __future__ import annotations
2
+
3
+ import sys
4
+
5
+ from .binary import NautilusAsciiBinary, invoke_binary
6
+
7
+
8
+ def nautilus_ascii_binary(binary: NautilusAsciiBinary, *, allow_sideload: bool = False):
9
+ invoke_binary(binary, sys.argv[1:], dry=False, use_subprocess=False, allow_sideload=allow_sideload)
@@ -0,0 +1,113 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from pathlib import Path
5
+ from typing import Annotated
6
+
7
+ import tyro
8
+
9
+
10
+ def nautilus_code(
11
+ p: Annotated[NautilusCode, tyro.conf.arg(name='')],
12
+ ) -> None:
13
+ """Call `nautilus_code`."""
14
+ from loguru import logger
15
+
16
+ from .binary import invoke_binary
17
+ from .utils import check_network_present, check_output_file_not_locked
18
+
19
+ p.load_env()
20
+ logger.debug(p)
21
+
22
+ if not (parameters := p.parameters).is_file():
23
+ msg = f'Parameters file not found: `{parameters}`'
24
+ raise FileNotFoundError(msg)
25
+
26
+ if not (abundances := p.abundances).is_file():
27
+ msg = f'Abundances file not found: `{abundances}`'
28
+ raise FileNotFoundError(msg)
29
+
30
+ # Ensure directory exists and files present.
31
+ check_network_present(p.network)
32
+
33
+ logger.info(f'Using abundances file at: `{abundances}`.')
34
+ logger.info(f'Using parameters file at: `{parameters}`.')
35
+ logger.info(f'Using network directory at: `{p.network}`.')
36
+
37
+ if (structure_evolution := p.structure_evolution) is not None:
38
+ if not structure_evolution.is_file():
39
+ msg = f'Structure evolution file not found: `{structure_evolution}`.'
40
+ raise FileNotFoundError(msg)
41
+
42
+ logger.info(f'Using structure evolution file at: `{structure_evolution}`.')
43
+
44
+ if p.ascii is False:
45
+ # check that there is no lock on the output file
46
+ check_output_file_not_locked(p.output)
47
+
48
+ logger.info(f'Using output file at: `{p.output}`.')
49
+
50
+ invoke_binary(
51
+ 'nautilus_code',
52
+ p.as_cmd_list(),
53
+ dry=p.dry,
54
+ use_subprocess=p.subprocess,
55
+ allow_sideload=p._allow_sideload, # pyright: ignore[reportPrivateUsage] # ruff: ignore[private-member-access]
56
+ )
57
+
58
+
59
+ OutputMode = tyro.conf.create_mutex_group(required=False, title='output mode')
60
+ SpatialMode = tyro.conf.create_mutex_group(required=False, title='`0D+T` or `1D`')
61
+
62
+
63
+ @dataclass
64
+ class NautilusCode:
65
+ """Invoke `nautilus_code`."""
66
+
67
+ abundances: Path = Path('abundances.in')
68
+ """Path to an abundances file"""
69
+ parameters: Path = Path('parameters.in')
70
+ """Path to a parameters file"""
71
+
72
+ network: Path = Path()
73
+ """Optional path to a network directory"""
74
+
75
+ structure_evolution: Annotated[Path | None, SpatialMode, tyro.conf.DisallowNone] = None
76
+ """Optional path to a structure evolution file"""
77
+ oneD_static: Annotated[Path | None, SpatialMode, tyro.conf.arg(name='1D-static'), tyro.conf.DisallowNone] = None # ruff: ignore[mixed-case-variable-in-class-scope]
78
+ """Optional path to a 1D static file"""
79
+
80
+ output: Annotated[Path, OutputMode, tyro.conf.arg(aliases=['-o'])] = Path('output.nc')
81
+ """Path of the netCDF output file (ignored in ascii mode) [env: NAUTILUS_ASTROCHEM_OUTPUT]"""
82
+
83
+ ascii: Annotated[bool, OutputMode, tyro.conf.FlagCreatePairsOff] = False
84
+ """Force the output to use ASCII [env: NAUTILUS_ASTROCHEM_ASCII]"""
85
+
86
+ dry: Annotated[bool, tyro.conf.FlagCreatePairsOff] = False
87
+ subprocess: tyro.conf.Suppress[bool] = True
88
+ _allow_sideload: tyro.conf.Suppress[bool] = False
89
+ """Internal attributes to allow sideloading the binary."""
90
+
91
+ def load_env(self):
92
+ """Load environment variables."""
93
+ import os
94
+
95
+ if (output := os.getenv('NAUTILUS_ASTROCHEM_OUTPUT')) is not None:
96
+ self.output = Path(output)
97
+
98
+ if (ascii := os.getenv('NAUTILUS_ASTROCHEM_ASCII')) is not None: # ruff: ignore[builtin-variable-shadowing]
99
+ self.ascii = bool(ascii)
100
+
101
+ if (dry := os.getenv('NAUTILUS_ASTROCHEM_DRY')) is not None:
102
+ self.dry = bool(dry)
103
+
104
+ def as_cmd_list(self) -> list[str]:
105
+ args = (
106
+ f'--parameters={self.parameters}',
107
+ f'--abundances={self.abundances}',
108
+ f'--network={self.network}',
109
+ f'--structure-evolution={struct_evol}' if (struct_evol := self.structure_evolution) else None,
110
+ f'--1D-static={one_d_static} ' if (one_d_static := self.oneD_static) else None,
111
+ f'--output={self.output}' if self.ascii is False else None,
112
+ )
113
+ return list(filter(None, args))
@@ -0,0 +1,75 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from pathlib import Path
5
+ from typing import Annotated
6
+
7
+ import tyro
8
+ from loguru import logger
9
+
10
+
11
+ def nautilus_rates(p: Annotated[NautilusRates, tyro.conf.arg(name='')]):
12
+ """Call `nautilus_rates`."""
13
+ from .binary import invoke_binary
14
+ from .utils import check_output_file_exists, check_output_file_not_locked
15
+
16
+ p.load_env()
17
+ logger.debug(p)
18
+
19
+ match p.ascii:
20
+ case True:
21
+ invoke_binary(
22
+ 'nautilus_rates',
23
+ p.as_cmd_list(),
24
+ dry=p.dry,
25
+ use_subprocess=p.subprocess,
26
+ allow_sideload=p._allow_sideload, # ruff: ignore[private-member-access] # pyright: ignore[reportPrivateUsage]
27
+ )
28
+ case False:
29
+ check_output_file_exists(p.output)
30
+ # check that there is no lock on the output file
31
+ check_output_file_not_locked(p.output)
32
+
33
+ logger.info(f'Using output file at: `{p.output}`.')
34
+
35
+ invoke_binary(
36
+ 'nautilus_rates_netcdf',
37
+ p.as_cmd_list(),
38
+ dry=p.dry,
39
+ use_subprocess=p.subprocess,
40
+ allow_sideload=p._allow_sideload, # ruff: ignore[private-member-access] # pyright: ignore[reportPrivateUsage]
41
+ )
42
+
43
+
44
+ OutputMode = tyro.conf.create_mutex_group(required=False, title='output mode')
45
+
46
+
47
+ @dataclass
48
+ class NautilusRates:
49
+ output: Annotated[Path, OutputMode, tyro.conf.arg(aliases=['-o'])] = Path('output.nc')
50
+ """Path of the netCDF file, used as input and output (ignored in ascii mode) [env: NAUTILUS_ASTROCHEM_OUTPUT]"""
51
+
52
+ ascii: Annotated[bool, OutputMode, tyro.conf.FlagCreatePairsOff] = False
53
+ """Force the output to use ASCII [env: NAUTILUS_ASTROCHEM_ASCII]"""
54
+
55
+ dry: Annotated[bool, tyro.conf.FlagCreatePairsOff] = False
56
+ subprocess: tyro.conf.Suppress[bool] = True
57
+ _allow_sideload: tyro.conf.Suppress[bool] = False
58
+ """Internal attributes to allow sideloading the binary."""
59
+
60
+ def load_env(self):
61
+ """Load environment variables."""
62
+ import os
63
+
64
+ if (output := os.getenv('NAUTILUS_ASTROCHEM_OUTPUT')) is not None:
65
+ self.output = Path(output)
66
+
67
+ if (ascii := os.getenv('NAUTILUS_ASTROCHEM_ASCII')) is not None: # ruff: ignore[builtin-variable-shadowing]
68
+ self.ascii = bool(ascii)
69
+
70
+ if (dry := os.getenv('NAUTILUS_ASTROCHEM_DRY')) is not None:
71
+ self.dry = bool(dry)
72
+
73
+ def as_cmd_list(self) -> list[str]:
74
+ args = (f'{self.output.as_posix()}' if self.ascii is False else None,)
75
+ return list(filter(None, args))