0
# Runtime Support
1
2
Runtime classes and utilities that provide the foundation for generated wrapper code, handling derived type management, Fortran-Python interoperability, and memory management for f90wrap-generated Python extensions.
3
4
## Capabilities
5
6
### Fortran Type Base Classes
7
8
Core base classes that generated wrapper code inherits from to provide Fortran derived type functionality in Python.
9
10
```python { .api }
11
class FortranDerivedType(object):
12
"""
13
Base class for all Fortran derived types in Python.
14
15
Provides memory management, copying, and handle-based access
16
to Fortran derived type instances.
17
"""
18
19
@classmethod
20
def from_handle(cls, handle, alloc=False):
21
"""
22
Create Python object from Fortran type handle.
23
24
Parameters:
25
- handle: int, opaque handle to Fortran type instance
26
- alloc: bool, whether to allocate new memory
27
28
Returns:
29
New instance of the derived type class
30
"""
31
32
def __copy__(self):
33
"""Create shallow copy of derived type instance."""
34
35
def copy(self):
36
"""Create deep copy of derived type instance."""
37
```
38
39
```python { .api }
40
class FortranDerivedTypeArray(object):
41
"""
42
Array container for Fortran derived types.
43
44
Provides Python sequence interface for arrays of Fortran derived types
45
with proper memory management and element access.
46
"""
47
48
def __init__(self, parent, getfunc, setfunc, lenfunc, doc, arraytype):
49
"""
50
Initialize derived type array.
51
52
Parameters:
53
- parent: parent object containing the array
54
- getfunc: function to get array element by index
55
- setfunc: function to set array element by index
56
- lenfunc: function to get array length
57
- doc: documentation string
58
- arraytype: type of array elements
59
"""
60
61
def iterindices(self):
62
"""Iterate over valid array indices."""
63
64
def items(self):
65
"""Iterate over (index, value) pairs."""
66
67
def __iter__(self):
68
"""Iterator protocol for array elements."""
69
70
def __len__(self):
71
"""Get array length."""
72
73
def __getitem__(self, i):
74
"""Get array element by index."""
75
76
def __setitem__(self, i, value):
77
"""Set array element by index."""
78
79
def __copy__(self):
80
"""Create shallow copy of array."""
81
82
def copy(self):
83
"""Create deep copy of array."""
84
```
85
86
```python { .api }
87
class FortranModule(object):
88
"""
89
Base class for Fortran modules in Python.
90
91
Provides namespace and organization for module-level procedures,
92
types, and parameters.
93
"""
94
```
95
96
### Type Registration and Lookup
97
98
System for registering and looking up Fortran type classes at runtime.
99
100
```python { .api }
101
class register_class(object):
102
"""
103
Decorator for registering Fortran type classes.
104
105
Parameters:
106
- cls_name: str, name of the class to register
107
108
Returns:
109
The registered class (for use as decorator)
110
"""
111
112
def __init__(self, cls_name):
113
"""Initialize the decorator with class name."""
114
115
def __call__(self, cls):
116
"""Register the class and return it."""
117
118
def lookup_class(cls_name):
119
"""
120
Look up registered Fortran type class by name.
121
122
Parameters:
123
- cls_name: str, name of the class to look up
124
125
Returns:
126
The registered class
127
128
Raises:
129
KeyError if class name not found
130
"""
131
```
132
133
### Memory Management Constants
134
135
Runtime constants for Fortran type handle management.
136
137
```python { .api }
138
sizeof_fortran_t = ... # Size in bytes of Fortran type handles
139
empty_handle = ... # Empty/null type handle value
140
empty_type = ... # Empty type instance for initialization
141
```
142
143
### Singleton Metaclass
144
145
Metaclass for implementing singleton pattern in Fortran module classes.
146
147
```python { .api }
148
class Singleton(type):
149
"""Metaclass for creating singleton classes."""
150
```
151
152
## Usage Examples
153
154
### Using Generated Wrapper Classes
155
156
```python
157
# Generated wrapper classes inherit from runtime base classes
158
from myfortrancode import MyType, MyModule
159
160
# Create instance using constructor
161
obj = MyType()
162
163
# Create from existing handle (advanced usage)
164
obj2 = MyType.from_handle(existing_handle)
165
166
# Copy instances
167
obj_copy = obj.copy()
168
obj_shallow = obj.__copy__()
169
170
# Access module-level functionality
171
result = MyModule.some_function(args)
172
```
173
174
### Working with Derived Type Arrays
175
176
```python
177
# Generated code creates arrays using FortranDerivedTypeArray
178
from myfortrancode import ContainerType
179
180
container = ContainerType()
181
182
# Access array elements (array property automatically created)
183
first_item = container.items[0]
184
container.items[1] = new_item
185
186
# Iterate over array
187
for item in container.items:
188
process(item)
189
190
# Get array length
191
count = len(container.items)
192
193
# Iterate with indices
194
for i, item in container.items.items():
195
print(f"Item {i}: {item}")
196
```
197
198
### Type Registration (Advanced)
199
200
```python
201
from f90wrap.runtime import register_class, lookup_class
202
203
# Register custom type class
204
@register_class
205
class MyCustomType(FortranDerivedType):
206
# Custom implementation
207
pass
208
209
# Look up registered class
210
cls = lookup_class('MyCustomType')
211
if cls:
212
instance = cls()
213
```
214
215
### Custom Derived Type Implementation
216
217
```python
218
from f90wrap.runtime import FortranDerivedType
219
220
class CustomFortranType(FortranDerivedType):
221
def __init__(self, handle=None):
222
if handle is None:
223
# Call Fortran constructor
224
self._handle = _mymodule.create_custom_type()
225
else:
226
self._handle = handle
227
228
def __del__(self):
229
# Ensure cleanup
230
if hasattr(self, '_handle'):
231
_mymodule.destroy_custom_type(self._handle)
232
233
@property
234
def value(self):
235
"""Access Fortran component through getter."""
236
return _mymodule.get_custom_type_value(self._handle)
237
238
@value.setter
239
def value(self, val):
240
"""Set Fortran component through setter."""
241
_mymodule.set_custom_type_value(self._handle, val)
242
```
243
244
## Memory Management
245
246
### Automatic Memory Management
247
248
The runtime classes provide automatic memory management for Fortran derived types:
249
250
- **Construction**: Automatic allocation when Python objects are created
251
- **Destruction**: Automatic cleanup when Python objects are garbage collected
252
- **Copying**: Deep and shallow copy support with proper memory handling
253
- **Reference Counting**: Integration with Python's reference counting system
254
255
### Handle-Based Access
256
257
Fortran derived types are accessed through opaque handles:
258
259
- **Type Safety**: Handles prevent direct memory access, ensuring type safety
260
- **Efficiency**: Minimal overhead for Fortran-Python data transfer
261
- **Portability**: Handle system works across different Fortran compilers
262
- **Debugging**: Handle validation helps catch memory errors
263
264
### Array Memory Management
265
266
Special handling for arrays of derived types:
267
268
- **Lazy Loading**: Array elements loaded on demand to minimize memory usage
269
- **Copy Semantics**: Proper deep/shallow copying for array elements
270
- **Index Validation**: Bounds checking prevents buffer overflows
271
- **Memory Sharing**: Efficient sharing of data between Python and Fortran
272
273
## Error Handling
274
275
### Exception Integration
276
277
Runtime classes integrate with Python's exception system:
278
279
```python
280
try:
281
obj = MyType()
282
obj.risky_operation()
283
except RuntimeError as e:
284
# Fortran runtime errors propagated as RuntimeError
285
print(f"Fortran error: {e}")
286
```
287
288
### Memory Error Detection
289
290
- **Handle Validation**: Invalid handles detected and reported
291
- **Double-Free Protection**: Prevention of multiple deallocations
292
- **Leak Detection**: Warning for objects not properly cleaned up
293
- **Corruption Detection**: Basic detection of memory corruption
294
295
## Thread Safety
296
297
### Thread-Safe Operations
298
299
The runtime system provides thread safety for:
300
301
- **Type Registration**: Thread-safe class registration and lookup
302
- **Handle Management**: Atomic handle operations where possible
303
- **Reference Counting**: Thread-safe reference counting integration
304
305
### Limitations
306
307
- **Fortran Thread Safety**: Depends on underlying Fortran code thread safety
308
- **Global State**: Some global state may require external synchronization
309
- **Compiler Specific**: Thread safety varies by Fortran compiler
310
311
## Performance Considerations
312
313
### Optimization Features
314
315
- **Minimal Overhead**: Thin wrapper layer with minimal Python overhead
316
- **Efficient Data Transfer**: Direct memory access where possible
317
- **Lazy Evaluation**: Deferred operations to minimize unnecessary computation
318
- **Memory Pooling**: Reuse of frequently allocated objects
319
320
### Performance Tips
321
322
- **Batch Operations**: Group related operations to minimize call overhead
323
- **Memory Reuse**: Reuse objects instead of frequent allocation/deallocation
324
- **Array Access**: Use efficient iteration patterns for array processing
325
- **Profile Guided**: Use profiling to identify performance bottlenecks
326
327
## Integration with NumPy
328
329
### Array Integration
330
331
The runtime classes integrate closely with NumPy:
332
333
- **Array Views**: Efficient views of Fortran arrays as NumPy arrays
334
- **Type Mapping**: Automatic mapping between Fortran and NumPy types
335
- **Memory Sharing**: Zero-copy sharing where memory layouts are compatible
336
- **Broadcasting**: Support for NumPy broadcasting where applicable
337
338
### Usage with NumPy
339
340
```python
341
import numpy as np
342
from myfortrancode import MyType
343
344
obj = MyType()
345
346
# Get NumPy view of Fortran array (if supported)
347
arr = obj.get_array_view()
348
print(f"Array shape: {arr.shape}, dtype: {arr.dtype}")
349
350
# Modify through NumPy (changes reflected in Fortran)
351
arr[0] = 42
352
353
# Create from NumPy array
354
obj.set_data_from_numpy(np.array([1, 2, 3, 4]))
355
```