0
# Namelist Objects and Formatting
1
2
Dictionary-like container objects that represent Fortran namelists in Python with extensive formatting controls for generating Fortran-compliant output. Namelist objects extend Python's OrderedDict with specialized methods and properties for scientific computing workflows.
3
4
## Capabilities
5
6
### Namelist Class
7
8
The primary container for namelist data, providing dictionary-like access with Fortran-specific functionality.
9
10
```python { .api }
11
class Namelist(OrderedDict):
12
"""
13
Representation of Fortran namelist in Python environment.
14
15
Extends OrderedDict with Fortran-specific methods and formatting controls.
16
Automatically converts nested dicts to Namelist objects and handles
17
complex Fortran features like derived types and multidimensional arrays.
18
"""
19
20
def __init__(self, *args, default_start_index=None, **kwds):
21
"""
22
Create Namelist object from dict-like data.
23
24
Args:
25
*args: Positional arguments passed to OrderedDict
26
default_start_index: int, optional - Default start index for arrays
27
**kwds: Keyword arguments passed to OrderedDict
28
"""
29
```
30
31
**Usage Examples:**
32
33
```python
34
# Create from dictionary
35
data = {'config': {'param': 10, 'values': [1, 2, 3]}}
36
nml = f90nml.Namelist(data)
37
38
# Create with default start index
39
nml = f90nml.Namelist(data, default_start_index=0)
40
41
# Dictionary-like access
42
nml['new_group'] = {'setting': 'value'}
43
print(nml['config']['param'])
44
45
# Automatic dict-to-Namelist conversion
46
nml['derived_type'] = {
47
'field1': 100,
48
'field2': 'text',
49
'nested': {'subfield': 42}
50
}
51
```
52
53
### Writing and File Operations
54
55
Save namelist data to files with extensive formatting control.
56
57
```python { .api }
58
def write(self, nml_path, force=False, sort=False):
59
"""
60
Write Namelist to a Fortran 90 namelist file.
61
62
Args:
63
nml_path: str or file-like object - Output path or file object
64
force: bool - Overwrite existing files (default: False)
65
sort: bool - Sort keys alphabetically (default: False)
66
67
Raises:
68
IOError: If file exists and force=False
69
"""
70
```
71
72
**Usage Examples:**
73
74
```python
75
nml = f90nml.read('input.nml')
76
77
# Write to file
78
nml.write('output.nml')
79
80
# Write with sorting
81
nml.write('sorted_output.nml', sort=True)
82
83
# Write to file object
84
with open('custom.nml', 'w') as f:
85
nml.write(f)
86
```
87
88
### Data Manipulation Methods
89
90
Specialized methods for working with namelist data structures.
91
92
```python { .api }
93
def patch(self, nml_patch):
94
"""
95
Update the namelist from another partial or full namelist.
96
97
Different from update() - merges values within sections rather
98
than replacing entire sections.
99
100
Args:
101
nml_patch: dict or Namelist - Data to merge into this namelist
102
"""
103
104
def todict(self, complex_tuple=False):
105
"""
106
Return a standard dict equivalent to the namelist.
107
108
Args:
109
complex_tuple: bool - Convert complex numbers to 2-tuples (default: False)
110
111
Returns:
112
dict: Standard Python dictionary with metadata preserved
113
"""
114
115
def groups(self):
116
"""
117
Return iterator spanning values with group and variable names.
118
119
Yields:
120
tuple: ((group_name, variable_name), value) pairs
121
"""
122
```
123
124
**Usage Examples:**
125
126
```python
127
# Patch existing namelist
128
base_nml = f90nml.read('base.nml')
129
updates = {'config': {'new_param': 50}}
130
base_nml.patch(updates)
131
132
# Convert to standard dict
133
nml_dict = nml.todict()
134
135
# Convert with complex number handling for JSON serialization
136
json_dict = nml.todict(complex_tuple=True)
137
138
# Iterate over all variables
139
for (group, var), value in nml.groups():
140
print(f"{group}.{var} = {value}")
141
```
142
143
### Formatting Properties
144
145
Extensive formatting controls for customizing Fortran output appearance.
146
147
```python { .api }
148
# Layout and spacing
149
column_width: int # Maximum characters per line (default: 72)
150
indent: str # Indentation string (default: ' ')
151
end_comma: bool # Append commas to entries (default: False)
152
assign_spacing: bool # Space around '=' (default: True)
153
index_spacing: bool # Space between array indices (default: False)
154
155
# Data representation
156
uppercase: bool # Uppercase names (default: False)
157
logical_repr: dict # Boolean string representations
158
true_repr: str # True value representation (default: '.true.')
159
false_repr: str # False value representation (default: '.false.')
160
float_format: str # Float formatting string (default: '')
161
162
# Array handling
163
default_start_index: int # Default array start index (default: None)
164
start_index: dict # Per-variable start indices
165
repeat_counter: bool # Use repeat syntax like '3*value' (default: False)
166
split_strings: bool # Split long strings (default: False)
167
```
168
169
**Usage Examples:**
170
171
```python
172
nml = f90nml.read('input.nml')
173
174
# Customize formatting
175
nml.column_width = 80
176
nml.indent = ' ' # 2 spaces instead of 4
177
nml.uppercase = True
178
nml.end_comma = True
179
180
# Customize logical representations
181
nml.true_repr = 'T'
182
nml.false_repr = 'F'
183
# or
184
nml.logical_repr = {True: 'T', False: 'F'}
185
186
# Float formatting
187
nml.float_format = '.3f' # 3 decimal places
188
189
# Array formatting
190
nml.repeat_counter = True # Use 3*1.0 instead of 1.0, 1.0, 1.0
191
nml.default_start_index = 0 # 0-based indexing
192
193
# Write with custom formatting
194
nml.write('formatted_output.nml')
195
```
196
197
### Cogroup Handling
198
199
Support for namelist files with duplicate group names (cogroups).
200
201
```python { .api }
202
def create_cogroup(self, group_name):
203
"""Convert an existing namelist group to a cogroup."""
204
205
def add_cogroup(self, key, val):
206
"""Append a duplicate group to the Namelist as a new group."""
207
208
class Cogroup(list):
209
"""List of Namelist groups which share a common key."""
210
211
def __init__(self, nml, key, *args, **kwds):
212
"""Generate list of cogroups linked to parent namelist."""
213
214
def update(self, args):
215
"""Update all cogroup elements with new values."""
216
217
keys: list # List of internal keys for this cogroup
218
```
219
220
**Usage Examples:**
221
222
```python
223
# Handle multiple groups with same name
224
nml_text = '''
225
&config
226
param1 = 10
227
/
228
&config
229
param2 = 20
230
/
231
'''
232
nml = f90nml.reads(nml_text)
233
234
# Access cogroup
235
config_groups = nml['config'] # Returns Cogroup object
236
print(len(config_groups)) # 2
237
238
# Access individual groups
239
first_config = config_groups[0]
240
second_config = config_groups[1]
241
242
# Update all groups in cogroup
243
config_groups.update({'shared_param': 100})
244
245
# Add new cogroup
246
nml.add_cogroup('config', {'param3': 30})
247
```
248
249
### Advanced Features
250
251
Specialized functionality for complex Fortran namelist features.
252
253
```python { .api }
254
class RepeatValue:
255
"""Container class for output using repeat counters."""
256
257
def __init__(self, n, value):
258
"""
259
Create RepeatValue for repeated data.
260
261
Args:
262
n: int - Number of repetitions
263
value: any - Value to repeat
264
"""
265
266
repeats: int # Number of repetitions
267
value: any # Value being repeated
268
269
class NmlKey(str):
270
"""String containing internal key for duplicate key handling."""
271
272
def __new__(cls, value='', *args, **kwargs):
273
"""Create NmlKey with internal key storage."""
274
```
275
276
**Usage Examples:**
277
278
```python
279
# Work with repeat values when repeat_counter is enabled
280
nml = f90nml.Namelist()
281
nml.repeat_counter = True
282
nml['data'] = {'array': [1, 1, 1, 2, 2]} # Will output as: 3*1, 2*2
283
284
# Handle special keys for duplicate groups
285
for key in nml.keys():
286
if isinstance(key, f90nml.NmlKey):
287
print(f"Internal key: {key._key}, Display key: {key}")
288
289
# Working with cogroups in complex scenarios
290
nml_complex = '''
291
&solver_config
292
method = 'CG'
293
tolerance = 1e-6
294
/
295
&solver_config
296
method = 'GMRES'
297
tolerance = 1e-8
298
max_iter = 100
299
/
300
&solver_config
301
method = 'BiCGSTAB'
302
tolerance = 1e-10
303
/
304
'''
305
nml = f90nml.reads(nml_complex)
306
307
# Iterate through all solver configurations
308
solver_configs = nml['solver_config']
309
for i, config in enumerate(solver_configs):
310
print(f"Solver {i+1}: {config['method']}, tol={config['tolerance']}")
311
312
# Update specific cogroup member
313
solver_configs[1]['preconditioner'] = 'ILU'
314
315
# Convert cogroup back to individual namelists
316
for i, config in enumerate(solver_configs):
317
config.write(f'solver_{i+1}.nml')
318
```
319
320
## Type Conversion and Validation
321
322
Automatic handling of Python to Fortran type conversion:
323
324
```python
325
# Automatic type promotion
326
nml = f90nml.Namelist()
327
nml['data'] = {
328
'integer': 42,
329
'float': 3.14159,
330
'boolean': True,
331
'string': 'hello world',
332
'array': [1, 2, 3, 4, 5],
333
'complex': complex(1.0, 2.0)
334
}
335
336
# Nested dict becomes nested Namelist
337
nml['derived'] = {
338
'field1': 10,
339
'nested': {
340
'subfield': 'value'
341
}
342
}
343
344
# Array of dicts becomes array of Namelists
345
nml['particles'] = [
346
{'x': 1.0, 'y': 2.0},
347
{'x': 3.0, 'y': 4.0}
348
]
349
```
350
351
## Error Handling
352
353
```python
354
# Invalid formatting parameters
355
try:
356
nml.column_width = -1 # Invalid
357
except ValueError as e:
358
print("Column width must be non-negative")
359
360
try:
361
nml.indent = "invalid" # Must be whitespace only
362
except ValueError as e:
363
print("Indent must contain only whitespace")
364
365
# File writing errors
366
try:
367
nml.write('/invalid/path/file.nml')
368
except IOError as e:
369
print(f"Cannot write file: {e}")
370
```