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
3133This assumption makes ownership and memory management clear.
3234We 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.
3436Instead, we simply pass data back and forth,
3537and 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.
46481 . 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
5356This 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 `
61621 . find an index, ` idx ` , in ` available_array ` such that ` available_array(idx) ` is ` .true. `
62631 . set ` instance_array(idx) ` equal to ` derived_type_original `
63641 . 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
92921 . 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
94941 . on the Fortran side, retrieve the instantiated index from the manager module
9595 and use this to call the Fortran function/subroutine of interest
96961 . 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
1011001 . we end up with the result of the Fortran callable back in Python
@@ -175,9 +174,7 @@ and normal Python rules apply in Python
175174Note: this section was never properly finished.
176175Once we started trying to write it,
177176we 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
182179To pass derived types back and forth across the Python-Fortran interface,
183180we introduce a 'manager' module for all derived types.
0 commit comments