Skip to content

Commit a5fba54

Browse files
committed
Merge branch 'main' into result-type
2 parents f23cf17 + ca2a5f5 commit a5fba54

43 files changed

Lines changed: 232 additions & 247 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,12 @@ jobs:
113113
# TODO: figure out whether we need/want to use other compilers too
114114
compiler: "gcc"
115115
version: "13"
116+
- name: Set DLL directory environment variable
117+
# Used when running the tests, see `tests/conftest.py` for details
118+
if: ${{ startsWith(matrix.os, 'windows') }}
119+
run: |
120+
echo "PYTHON_ADD_DLL_DIRECTORY=C:\\mingw64\\bin" >> $GITHUB_ENV
121+
116122
- uses: ./.github/actions/setup
117123
with:
118124
python-version: ${{ matrix.python-version }}

.github/workflows/release.yaml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
name: Release
22

33
on:
4+
workflow_dispatch:
45
push:
56
tags: ['v*']
67

@@ -27,7 +28,6 @@ jobs:
2728
pip install -r {project}/requirements-only-tests-min-locked.txt
2829
CIBW_TEST_COMMAND: >-
2930
pytest {project}/tests
30-
MACOSX_DEPLOYMENT_TARGET: "13.0"
3131
strategy:
3232
fail-fast: false
3333
matrix:
@@ -56,6 +56,14 @@ jobs:
5656
# TODO: figure out whether we need/want to use other compilers too
5757
compiler: "gcc"
5858
version: "13"
59+
- name: Set deployment target - MacOS 13.0
60+
if: ${{ matrix.os == 'macos-13' }}
61+
run: |
62+
echo "MACOSX_DEPLOYMENT_TARGET=13.0" >> $GITHUB_ENV
63+
- name: Set deployment target - MacOS 14.0
64+
if: ${{ matrix.os == 'macos-14' }}
65+
run: |
66+
echo "MACOSX_DEPLOYMENT_TARGET=14.0" >> $GITHUB_ENV
5967
- name: Specify LLVM - windows-arm
6068
if: ${{ matrix.os == 'windows-11-arm' }}
6169
shell: pwsh

.pre-commit-config.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@ repos:
4444
- id: ruff
4545
args: [ --fix, --exit-non-zero-on-fix ]
4646
- id: ruff-format
47+
- repo: https://github.com/PlasmaFAIR/fortitude-pre-commit
48+
# Fortitude version.
49+
rev: v0.7.5
50+
hooks:
51+
- id: fortitude
52+
args: ["--fix", "--unsafe-fixes", "--preview"]
4753
- repo: https://github.com/astral-sh/uv-pre-commit
4854
rev: 0.5.21
4955
hooks:

TODO.md

Lines changed: 0 additions & 8 deletions
This file was deleted.

changelog/25.feature.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Added demonstration of wrapping Fortran derived types

changelog/28.trivial.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Added [fortitude](https://github.com/PlasmaFAIR/fortitude) for linting the Fortran

changelog/31.trivial.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Allow release workflow to run on command

docs/NAVIGATION.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ See https://oprypin.github.io/mkdocs-literate-nav/
66
- [Home](index.md)
77
- [Installation](installation.md)
88
- [How-to guides](how-to-guides/index.md)
9-
- [Do a basic calculation](how-to-guides/basic-calculation.md)
10-
- [Run code in a notebook](how-to-guides/run-code-in-a-notebook.py)
9+
- [Basic demo](how-to-guides/basic-demo.py)
1110
- [Tutorials](tutorials/index.md)
1211
- [Further background](further-background/index.md)
1312
- [Dependency pinning and testing](further-background/dependency-pinning-and-testing.md)
13+
- [Wrapping Fortran derived types](further-background/wrapping-fortran-derived-types.md)
1414
- [Development](development.md)
1515
- [API reference](api/example_fgen_basic/)
1616
- [Fortran API](fortran-api/home.html)

IMPLEMENTATION-NOTES.md renamed to docs/further-background/wrapping-fortran-derived-types.md

Lines changed: 27 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
@Marco please move these into `docs/further-background/wrapping-derived-types.md` (and do any other clean up and formatting fixes you'd like)
1+
# Wrapping derived types
2+
3+
Here we describe our approach to wrapping Fortran derived types.
24

35
## What is the goal?
46

@@ -30,7 +32,7 @@ the original Python object will remain unchanged
3032

3133
This assumption makes ownership and memory management clear.
3234
We do not need to keep instances around as views
33-
and worry about consistency across the Python-Fortran interface.
35+
and therefore do not need to worry about consistency across the Python-Fortran interface.
3436
Instead, we simply pass data back and forth,
3537
and the normal rules of data consistency within each programming language apply.
3638

@@ -45,57 +47,54 @@ The manager module has two key components:
4547
In practice, they are essentially temporary variables.
4648
1. an allocatable array of logical (boolean) values,
4749
call this `available_array`.
48-
The convention is that, if `available_array(i)`, where `i` is an integer,
49-
is `.true.` then the instance at `instance_array(i)` is available for the manager to use,
50-
otherwise the manager assumes that the instance is already being used for some purpose
50+
The convention is that, if `available_array(i)` is `.true.`,
51+
where `i` is an integer,
52+
then the instance at `instance_array(i)` is available for the manager to use.
53+
Otherwise, the manager assumes that the instance is already being used for some purpose
5154
and therefore cannot be used for whatever operation is currently being performed.
5255

5356
This setup allows us to effectively pass derived types back and forth between Python and Fortran.
5457

55-
Whenever we need to return a derived type to Python, we:
56-
57-
[TODO think about retrieving multiple derived types at once]
58+
Whenever we need to return a derived type (or derived types) to Python, we:
5859

59-
1. get the derived type from whatever Fortran function or subroutine created it,
60+
1. get the derived type(s) from whatever Fortran function or subroutine created it,
6061
call this `derived_type_original`
6162
1. find an index, `idx`, in `available_array` such that `available_array(idx)` is `.true.`
6263
1. set `instance_array(idx)` equal to `derived_type_original`
6364
1. we return `idx` to Python
64-
- `idx` is an integer, so we can return this easily to Python using `f2py`
65-
1. we then create a Python object with an API that mirrors `derived_type_original`
65+
- `idx` is an integer (or integers), so we can return this easily to Python using `f2py`
66+
1. we then create a Python object (or objects) with an API that mirrors `derived_type_original`
6667
using the class method `from_instance_index`.
67-
This class method is [TODO or will be] auto-generated via `pyfgen`
68+
This class method is auto-generated via `pyfgen`
69+
(TODO: implement auto-generation)
6870
and handles retrieval of all the attribute values of `derived_type_original`
6971
from Fortran and sets them on the Python object that is being instantiated
7072
- we can do this as, if you dig down deep enough, all attributes eventually
7173
become primitive types which can be passed back and forth using `f2py`,
7274
it can just be that multiple levels of recursion are needed
7375
if you have derived types that themselves have derived type attributes
74-
1. we then call the manager [TODO I think this will end up being wrapper, we can tighten the language later]
75-
module's `finalise_instance` function to free the (temporary) instance
76+
1. we then call the wrapper module's `finalise_instance` function to free the (temporary) instance(s)
7677
that was used by the manager
78+
(we cannot access the manager module directly as it cannot be wrapped by `f2py`)
7779
- this instance is no longer needed because all the data has been transferred to Python
78-
1. we end up with a Python instance that has the result
80+
1. we end up with a Python instance(s) that has the result
7981
and no extra/leftover memory footprint in Fortran
8082
(and leave Fortran to decide whether to clean up `derived_type_original` or not)
8183

82-
Whenever we need to pass a derived type to Fortran, we:
83-
84-
[TODO think about passing multiple derived types at once]
84+
Whenever we need to pass a derived type (or derived types) to Fortran, we:
8585

86-
1. call the manager [TODO I think this will end up being wrapper, we can tighten the language later]
87-
module's `get_free_instance_index` function to get an available index to use for the passing
88-
1. call the manager [TODO I think this will end up being wrapper, we can tighten the language later]
89-
module's `build_instance` function with the index we just received
90-
plus all of the Python object's attribute values
91-
- on the Fortran side, there is now an instantiated derived type, ready for use
86+
1. get an instance index we can use to communicate with Fortran
87+
1. call the Python object's `build_fortran_instance` method,
88+
which returns the instance index where the object was created on the Fortran side.
89+
Under the hood, this calls the wrapper module's
90+
`get_free_instance_index` and `build_instance` functions
91+
1. on the Fortran side, there is now an instantiated derived type, ready for use
9292
1. call the wrapped Fortran function of interest,
93-
except we pass the instance index instead of the derived type
93+
except we pass the instance index instead of the actual Python object itself
9494
1. on the Fortran side, retrieve the instantiated index from the manager module
9595
and use this to call the Fortran function/subroutine of interest
9696
1. return the result from Fortran back to Python
97-
1. call the manager [TODO I think this will end up being wrapper, we can tighten the language later]
98-
module's `finalise_instance` function to free the (temporary) instance
97+
1. call the wrapper module's `finalise_instance` function to free the (temporary) instance
9998
that was used to pass the instance in the first place
10099
- this instance is no longer needed because all the data has been transferred and used by Fortran
101100
1. we end up with the result of the Fortran callable back in Python
@@ -175,9 +174,7 @@ and normal Python rules apply in Python
175174
Note: this section was never properly finished.
176175
Once we started trying to write it,
177176
we realised how hard it would be to avoid weird edge cases
178-
so we stopped and changed to [our current solution][Our solution]
179-
(@Marco please check that this internal cross-reference works
180-
once the docs are built).
177+
so we stopped and changed to [our current solution][our-solution].
181178

182179
To pass derived types back and forth across the Python-Fortran interface,
183180
we introduce a 'manager' module for all derived types.

docs/how-to-guides/basic-calculation.md

Lines changed: 0 additions & 10 deletions
This file was deleted.

0 commit comments

Comments
 (0)