integrate_module 0.99.1__py3-none-any.whl

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.
integrate/__init__.py ADDED
@@ -0,0 +1,144 @@
1
+ import multiprocessing
2
+ multiprocessing.freeze_support()
3
+
4
+ # Import rejection sampling functions from new module
5
+ from integrate.integrate_rejection import integrate_rejection
6
+ from integrate.integrate_rejection import integrate_rejection_range
7
+ from integrate.integrate_rejection import integrate_posterior_chunk
8
+ from integrate.integrate_rejection import integrate_posterior_main
9
+ from integrate.integrate_rejection import likelihood_gaussian_diagonal
10
+ from integrate.integrate_rejection import likelihood_gaussian_diagonal_old
11
+ from integrate.integrate_rejection import likelihood_gaussian_full
12
+ from integrate.integrate_rejection import likelihood_multinomial
13
+ from integrate.integrate_rejection import likelihood_multinomial_old
14
+ from integrate.integrate_rejection import select_subset_for_inversion
15
+ from integrate.integrate_rejection import cleanup_shared_memory
16
+ from integrate.integrate_rejection import reconstruct_shared_arrays
17
+ from integrate.integrate_rejection import create_shared_memory
18
+ from integrate.integrate_rejection import compute_hypothesis_probability
19
+
20
+ # Import other functions from main module
21
+ from integrate.integrate import integrate_update_prior_attributes
22
+ from integrate.integrate import integrate_posterior_stats
23
+ from integrate.integrate import logl_T_est
24
+ from integrate.integrate import lu_post_sample_logl
25
+ from integrate.integrate import prior_data
26
+ from integrate.integrate import prior_data_gaaem
27
+ from integrate.integrate import prior_data_identity
28
+ from integrate.integrate import forward_gaaem
29
+ from integrate.integrate import synthetic_case
30
+ from integrate.integrate import prior_model_layered
31
+ from integrate.integrate import prior_model_workbench
32
+ from integrate.integrate import prior_model_workbench_direct
33
+ from integrate.integrate import posterior_cumulative_thickness
34
+ #from integrate.integrate import integrate_rejection_multi
35
+ from integrate.integrate import use_parallel
36
+ from integrate.integrate import kl_divergence
37
+ from integrate.integrate import entropy
38
+ from integrate.integrate import class_id_to_idx
39
+ from integrate.integrate import is_notebook
40
+ from integrate.integrate import get_hypothesis_probability
41
+ from integrate.integrate import sample_posterior_multiple_hypotheses
42
+ from integrate.integrate import timing_compute
43
+ from integrate.integrate import timing_plot
44
+ #from integrate.integrate import compute_P_obs_from_log
45
+ #from integrate.integrate import rescale_P_obs_temperature
46
+ #from integrate.integrate import Pobs_to_datagrid
47
+
48
+ # Import matplotlib backend setup
49
+ from integrate.integrate_plot import setup_matplotlib_backend
50
+
51
+ from integrate.integrate_io import copy_prior
52
+ from integrate.integrate_io import load_prior
53
+ from integrate.integrate_io import load_prior_data
54
+ from integrate.integrate_io import save_prior_data
55
+ from integrate.integrate_io import load_prior_model
56
+ from integrate.integrate_io import save_prior_model
57
+ from integrate.integrate_io import load_data
58
+ from integrate.integrate_io import get_geometry
59
+ from integrate.integrate_io import extract_feature_at_elevation
60
+ from integrate.integrate_io import get_discrete_classes
61
+ from integrate.integrate_io import get_number_of_datasets
62
+ from integrate.integrate_io import get_number_of_data
63
+ from integrate.integrate_io import read_gex
64
+ from integrate.integrate_io import read_gex_workbench
65
+ from integrate.integrate_io import gex_to_stm
66
+ from integrate.integrate_io import get_gex_file_from_data
67
+ from integrate.integrate_io import write_stm_files
68
+ from integrate.integrate_io import post_to_csv
69
+ from integrate.integrate_io import copy_hdf5_file
70
+ from integrate.integrate_io import hdf5_scan
71
+ from integrate.integrate_io import get_case_data
72
+ from integrate.integrate_io import save_data_gaussian
73
+ from integrate.integrate_io import xyz_to_h5
74
+ from integrate.integrate_io import save_data_multinomial
75
+ from integrate.integrate_io import write_data_gaussian # Deprecated - use save_data_gaussian
76
+ from integrate.integrate_io import write_data_multinomial # Deprecated - use save_data_multinomial
77
+ from integrate.integrate_io import check_data
78
+ from integrate.integrate_io import merge_prior
79
+ from integrate.integrate_io import merge_data
80
+ from integrate.integrate_io import merge_posterior
81
+ from integrate.integrate_io import filter_prior
82
+ from integrate.integrate_io import read_usf
83
+ from integrate.integrate_io import read_usf_mul
84
+ from integrate.integrate_io import test_read_usf
85
+ from integrate.integrate_io import hdf5_info
86
+ from integrate.integrate_io import read_borehole
87
+ from integrate.integrate_io import write_borehole
88
+
89
+ from integrate.integrate_plot import plot_geometry
90
+ from integrate.integrate_plot import plot_profile
91
+ from integrate.integrate_plot import plot_profile_continuous
92
+ from integrate.integrate_plot import plot_profile_discrete
93
+ from integrate.integrate_plot import plot_cumulative_probability_profile
94
+ from integrate.integrate_plot import plot_T_EV
95
+ from integrate.integrate_plot import plot_data_xy
96
+ from integrate.integrate_plot import plot_data
97
+ from integrate.integrate_plot import plot_data_prior_post
98
+ from integrate.integrate_plot import plot_data_prior
99
+ from integrate.integrate_plot import plot_prior_stats
100
+ from integrate.integrate_plot import plot_post_stats
101
+ from integrate.integrate_plot import plot_feature_2d
102
+ from integrate.integrate_plot import plot_posterior_cumulative_thickness
103
+ from integrate.integrate_plot import h5_get_clim_cmap
104
+ from integrate.integrate_plot import get_colormap_and_limits
105
+ from integrate.integrate_plot import plot_xy
106
+ from integrate.integrate_plot import find_points_along_line_segments
107
+ from integrate.integrate_plot import plot_boreholes
108
+
109
+ # Import from borehole module
110
+ from integrate.integrate_borehole import compute_P_obs_discrete
111
+ from integrate.integrate_borehole import compute_P_obs_discrete as Pobs_discrete_compute
112
+ from integrate.integrate_borehole import welllog_compute_P_obs_class_mode
113
+ from integrate.integrate_borehole import rescale_P_obs_temperature
114
+ from integrate.integrate_borehole import rescale_P_obs_temperature as Pobs_rescale_temperature
115
+ from integrate.integrate_borehole import Pobs_to_datagrid
116
+ from integrate.integrate_borehole import get_weight_from_position
117
+ from integrate.integrate_borehole import prior_data_borehole
118
+ from integrate.integrate_borehole import prior_data_borehole_class_mode
119
+ from integrate.integrate_borehole import prior_data_borehole_class_layer
120
+ from integrate.integrate_borehole import save_borehole_data
121
+
122
+ # Import query functions
123
+ from integrate.integrate_query import query
124
+ from integrate.integrate_query import query_probability
125
+ from integrate.integrate_query import query_percentile
126
+ from integrate.integrate_query import query_plot
127
+ from integrate.integrate_query import query_percentile_plot
128
+ from integrate.integrate_query import save_query
129
+ from integrate.integrate_query import load_query
130
+ from integrate.integrate_query import get_prior_model_info
131
+ from integrate.integrate_query import prior_describe
132
+ from integrate.integrate_query import query_from_text
133
+ from integrate.integrate_query import title_from_json
134
+ from integrate.integrate_query import query_test_llm
135
+
136
+ # Import gex module functions
137
+ from integrate.gex import read_gex as read_gex2
138
+ from integrate.gex import describe_gex as describe_gex2
139
+
140
+
141
+ # REMOVE CLI IMPORTS - These cause circular dependencies
142
+ # from . import integrate_cli
143
+ # from . import integrate_timing
144
+
integrate/gex.py ADDED
@@ -0,0 +1,402 @@
1
+ import numpy as np
2
+ import re
3
+ from typing import Dict, List, Tuple, Union, Any
4
+
5
+
6
+ def read_gex(file_gex: str) -> Tuple[Dict[str, Any], List[Dict[str, Any]]]:
7
+ """
8
+ Read GEX file and return GENERAL section and CHANNELS list.
9
+
10
+ Parameters:
11
+ -----------
12
+ file_gex : str
13
+ Path to the GEX file
14
+
15
+ Returns:
16
+ --------
17
+ GENERAL : dict
18
+ Dictionary containing all key-value pairs from [General] section
19
+ CHANNELS : list
20
+ List of dictionaries, one per channel section
21
+ """
22
+
23
+ def parse_value(value_str: str) -> Union[str, int, float, np.ndarray]:
24
+ """Parse a value string into appropriate data type."""
25
+ value_str = value_str.strip()
26
+
27
+ # Try to split into multiple values (space-separated)
28
+ parts = value_str.split()
29
+
30
+ if len(parts) == 1:
31
+ # Single value
32
+ try:
33
+ # Try integer first
34
+ if '.' not in value_str and 'E' not in value_str.upper() and 'e' not in value_str:
35
+ return int(value_str)
36
+ else:
37
+ # Try float
38
+ return float(value_str)
39
+ except ValueError:
40
+ # Return as string
41
+ return value_str
42
+ else:
43
+ # Multiple values - try to convert to numpy array of floats
44
+ try:
45
+ return np.array([float(p) for p in parts])
46
+ except ValueError:
47
+ # If conversion fails, return as string
48
+ return value_str
49
+
50
+ def group_numbered_keys(section_dict: Dict[str, Any]) -> Dict[str, Any]:
51
+ """Group numbered keys into 2D numpy arrays."""
52
+ grouped = {}
53
+ numbered_groups = {}
54
+
55
+ for key, value in section_dict.items():
56
+ # Check if key ends with a number
57
+ match = re.match(r'^(.+?)(\d+)$', key)
58
+ if match:
59
+ base_name = match.group(1)
60
+ number = int(match.group(2))
61
+
62
+ if base_name not in numbered_groups:
63
+ numbered_groups[base_name] = {}
64
+ numbered_groups[base_name][number] = value
65
+ else:
66
+ grouped[key] = value
67
+
68
+ # Convert numbered groups to 2D arrays
69
+ for base_name, numbered_dict in numbered_groups.items():
70
+ # Sort by number and collect values
71
+ sorted_items = sorted(numbered_dict.items())
72
+ values = [item[1] for item in sorted_items]
73
+
74
+ # If all values are numpy arrays of the same length, stack them
75
+ if all(isinstance(v, np.ndarray) for v in values):
76
+ try:
77
+ grouped[base_name] = np.array(values)
78
+ except:
79
+ # If stacking fails, keep as list
80
+ grouped[base_name] = values
81
+ else:
82
+ # Keep as list if not all numpy arrays
83
+ grouped[base_name] = values
84
+
85
+ return grouped
86
+
87
+ # Read the file
88
+ with open(file_gex, 'r') as f:
89
+ lines = f.readlines()
90
+
91
+ GENERAL = {}
92
+ CHANNELS = []
93
+ current_section = None
94
+ current_dict = None
95
+
96
+ for line in lines:
97
+ line = line.strip()
98
+
99
+ # Skip empty lines and comments
100
+ if not line or line.startswith('/'):
101
+ continue
102
+
103
+ # Check for section headers
104
+ if line.startswith('[') and line.endswith(']'):
105
+ # Save previous section if it exists
106
+ if current_section is not None and current_dict is not None:
107
+ if current_section.lower() == 'general':
108
+ GENERAL = group_numbered_keys(current_dict)
109
+ elif current_section.lower().startswith('channel'):
110
+ CHANNELS.append(group_numbered_keys(current_dict))
111
+
112
+ # Start new section
113
+ current_section = line[1:-1] # Remove brackets
114
+ current_dict = {}
115
+ continue
116
+
117
+ # Parse key-value pairs
118
+ if '=' in line and current_dict is not None:
119
+ key, value = line.split('=', 1)
120
+ key = key.strip()
121
+ value = value.strip()
122
+
123
+ if value: # Only process non-empty values
124
+ current_dict[key] = parse_value(value)
125
+
126
+ # Handle the last section
127
+ if current_section is not None and current_dict is not None:
128
+ if current_section.lower() == 'general':
129
+ GENERAL = group_numbered_keys(current_dict)
130
+ elif current_section.lower().startswith('channel'):
131
+ CHANNELS.append(group_numbered_keys(current_dict))
132
+
133
+ return GENERAL, CHANNELS
134
+
135
+
136
+ def describe_gex(input_data, channels_data=None):
137
+ """
138
+ Describe a GEX system configuration in a human-readable format.
139
+
140
+ Parameters:
141
+ -----------
142
+ input_data : str or dict
143
+ Either a GEX filename (str) or a GENERAL dictionary
144
+ channels_data : list of dict, optional
145
+ List of channel dictionaries. Required if input_data is a dict.
146
+
147
+ Returns:
148
+ --------
149
+ None
150
+ Prints description to screen
151
+ """
152
+
153
+ # Handle input - either filename or dictionaries
154
+ if isinstance(input_data, str):
155
+ # It's a filename
156
+ filename = input_data
157
+ general, channels = read_gex(filename)
158
+ print(f"GEX System Description: {filename}")
159
+ else:
160
+ # It's a dictionary
161
+ general = input_data
162
+ channels = channels_data or []
163
+ print("GEX System Description")
164
+
165
+ print("=" * 60)
166
+
167
+ # System identification
168
+ description = general.get('Description', 'Unknown')
169
+ data_type = general.get('DataType', 'Unknown')
170
+ print(f"System: {description}")
171
+ if data_type != 'Unknown':
172
+ print(f"Data Type: {data_type}")
173
+
174
+ print()
175
+
176
+ # Transmitter loop information
177
+ loop_type = general.get('LoopType', 'Unknown')
178
+ tx_area = general.get('TxLoopArea', 'Unknown')
179
+ turns_lm = general.get('NumberOfTurnsLM', 'Unknown')
180
+ turns_hm = general.get('NumberOfTurnsHM', 'Unknown')
181
+
182
+ print("TRANSMITTER CONFIGURATION:")
183
+ print(f" Loop Type: {loop_type}")
184
+ print(f" Loop Area: {tx_area} m²")
185
+ print(f" Turns (Low Moment): {turns_lm}")
186
+ print(f" Turns (High Moment): {turns_hm}")
187
+
188
+ # Transmitter loop geometry
189
+ if 'TxLoopPoint' in general:
190
+ tx_points = general['TxLoopPoint']
191
+ if isinstance(tx_points, np.ndarray):
192
+ n_points = len(tx_points)
193
+ if n_points == 4:
194
+ loop_shape = "Rectangular"
195
+ elif n_points == 8:
196
+ loop_shape = "Octagonal"
197
+ else:
198
+ loop_shape = f"{n_points}-sided polygon"
199
+
200
+ print(f" Loop Shape: {loop_shape} ({n_points} points)")
201
+
202
+ # Calculate approximate dimensions
203
+ x_coords = tx_points[:, 0]
204
+ y_coords = tx_points[:, 1]
205
+ x_range = np.max(x_coords) - np.min(x_coords)
206
+ y_range = np.max(y_coords) - np.min(y_coords)
207
+ print(f" Dimensions: {x_range:.2f} x {y_range:.2f} m")
208
+
209
+ print()
210
+
211
+ # Receiver configuration
212
+ print("RECEIVER CONFIGURATION:")
213
+ if 'RxCoilPosition' in general:
214
+ rx_pos = general['RxCoilPosition']
215
+ if isinstance(rx_pos, np.ndarray) and len(rx_pos) > 0:
216
+ if len(rx_pos) == 1:
217
+ x, y, z = rx_pos[0]
218
+ print(f" Receiver Position: ({x:.2f}, {y:.2f}, {z:.2f}) m")
219
+ # Calculate offset from transmitter
220
+ if 'TxCoilPosition' in general:
221
+ tx_pos = general['TxCoilPosition'][0]
222
+ offset = np.sqrt((x - tx_pos[0])**2 + (y - tx_pos[1])**2)
223
+ print(f" Tx-Rx Offset: {offset:.2f} m")
224
+ else:
225
+ print(f" Multiple Receivers: {len(rx_pos)} positions")
226
+
227
+ print()
228
+
229
+ # Timing configuration
230
+ print("TIMING CONFIGURATION:")
231
+ front_gate_delay = general.get('FrontGateDelay', 'Unknown')
232
+ print(f" Front Gate Delay: {front_gate_delay}")
233
+
234
+ if 'GateTime' in general:
235
+ gate_times = general['GateTime']
236
+ if isinstance(gate_times, np.ndarray):
237
+ n_gates = len(gate_times)
238
+ if gate_times.shape[1] >= 3:
239
+ # Assume format: [center, start, end]
240
+ earliest = np.min(gate_times[:, 1]) # earliest start time
241
+ latest = np.max(gate_times[:, 2]) # latest end time
242
+ print(f" Number of Gates: {n_gates}")
243
+ print(f" Time Window: {earliest:.2e} to {latest:.2e} seconds")
244
+
245
+ # Show early and late time examples
246
+ print(f" Early Gates: {gate_times[0, 0]:.2e}, {gate_times[1, 0]:.2e}, {gate_times[2, 0]:.2e} s")
247
+ if n_gates > 3:
248
+ print(f" Late Gates: {gate_times[-3, 0]:.2e}, {gate_times[-2, 0]:.2e}, {gate_times[-1, 0]:.2e} s")
249
+
250
+ print()
251
+
252
+ # Waveform information
253
+ print("WAVEFORM CONFIGURATION:")
254
+ waveform_types = []
255
+ if 'WaveformLMPoint' in general:
256
+ wf_lm = general['WaveformLMPoint']
257
+ if isinstance(wf_lm, np.ndarray):
258
+ n_points_lm = len(wf_lm)
259
+ waveform_types.append(f"Low Moment ({n_points_lm} points)")
260
+
261
+ if 'WaveformHMPoint' in general:
262
+ wf_hm = general['WaveformHMPoint']
263
+ if isinstance(wf_hm, np.ndarray):
264
+ n_points_hm = len(wf_hm)
265
+ waveform_types.append(f"High Moment ({n_points_hm} points)")
266
+
267
+ if waveform_types:
268
+ print(f" Available Waveforms: {', '.join(waveform_types)}")
269
+ else:
270
+ print(" Waveform Data: Not available")
271
+
272
+ print()
273
+
274
+ # Channel information
275
+ print("CHANNEL CONFIGURATION:")
276
+ n_channels = len(channels)
277
+ print(f" Number of Channels: {n_channels}")
278
+
279
+ if n_channels > 0:
280
+ for i, channel in enumerate(channels):
281
+ print(f"\n Channel {i+1}:")
282
+
283
+ # Channel-specific parameters
284
+ rx_coil_num = channel.get('RxCoilNumber', 'Unknown')
285
+ print(f" Receiver Coil: {rx_coil_num}")
286
+
287
+ no_gates = channel.get('NoGates', 'Unknown')
288
+ if no_gates != 'Unknown':
289
+ print(f" Number of Gates: {no_gates}")
290
+
291
+ rep_freq = channel.get('RepFreq', 'Unknown')
292
+ if rep_freq != 'Unknown':
293
+ print(f" Repetition Frequency: {rep_freq} Hz")
294
+
295
+ front_gate_time = channel.get('FrontGateTime', 'Unknown')
296
+ if front_gate_time != 'Unknown':
297
+ print(f" Front Gate Time: {front_gate_time} s")
298
+
299
+ # Data processing parameters
300
+ uniform_std = channel.get('UniformDataSTD', 'Unknown')
301
+ if uniform_std != 'Unknown':
302
+ print(f" Uniform Data STD: {uniform_std}")
303
+
304
+ remove_gates = channel.get('RemoveInitialGates', 'Unknown')
305
+ if remove_gates != 'Unknown':
306
+ print(f" Remove Initial Gates: {remove_gates}")
307
+
308
+ print()
309
+
310
+ # Position information
311
+ if any(key in general for key in ['GPSPosition', 'TxCoilPosition', 'AltimeterPosition']):
312
+ print("POSITION INFORMATION:")
313
+
314
+ if 'GPSPosition' in general:
315
+ gps_pos = general['GPSPosition']
316
+ if isinstance(gps_pos, np.ndarray) and len(gps_pos) > 0:
317
+ if len(gps_pos) == 1:
318
+ x, y, z = gps_pos[0]
319
+ print(f" GPS Position: ({x:.2f}, {y:.2f}, {z:.2f})")
320
+ else:
321
+ print(f" GPS Positions: {len(gps_pos)} locations")
322
+
323
+ if 'TxCoilPosition' in general:
324
+ tx_pos = general['TxCoilPosition']
325
+ if isinstance(tx_pos, np.ndarray) and len(tx_pos) > 0:
326
+ x, y, z = tx_pos[0]
327
+ print(f" Transmitter Position: ({x:.2f}, {y:.2f}, {z:.2f}) m")
328
+
329
+ if 'AltimeterPosition' in general:
330
+ alt_pos = general['AltimeterPosition']
331
+ if isinstance(alt_pos, np.ndarray) and len(alt_pos) > 0:
332
+ if not np.allclose(alt_pos, 0): # Only show if not all zeros
333
+ x, y, z = alt_pos[0]
334
+ print(f" Altimeter Position: ({x:.2f}, {y:.2f}, {z:.2f}) m")
335
+
336
+ print()
337
+
338
+ # Summary
339
+ print("SYSTEM SUMMARY:")
340
+ summary_points = []
341
+
342
+ if data_type != 'Unknown':
343
+ summary_points.append(f"{data_type} system")
344
+
345
+ if 'TxLoopPoint' in general:
346
+ tx_points = general['TxLoopPoint']
347
+ if isinstance(tx_points, np.ndarray):
348
+ n_points = len(tx_points)
349
+ if n_points == 4:
350
+ summary_points.append("rectangular transmitter loop")
351
+ elif n_points == 8:
352
+ summary_points.append("octagonal transmitter loop")
353
+ else:
354
+ summary_points.append(f"{n_points}-sided transmitter loop")
355
+
356
+ if tx_area != 'Unknown':
357
+ summary_points.append(f"{tx_area} m² loop area")
358
+
359
+ summary_points.append(f"{n_channels} channel{'s' if n_channels != 1 else ''}")
360
+
361
+ if 'GateTime' in general:
362
+ gate_times = general['GateTime']
363
+ if isinstance(gate_times, np.ndarray):
364
+ n_gates = len(gate_times)
365
+ summary_points.append(f"{n_gates} time gates")
366
+
367
+ print(f" • {', '.join(summary_points).capitalize()}")
368
+
369
+ print("=" * 60)
370
+
371
+
372
+ if __name__ == "__main__":
373
+ # Test the functions
374
+ print("Testing read_gex() and describe_gex() functions...")
375
+
376
+ # Test files
377
+ test_files = [
378
+ '202500404_DEN_Diamond_Soeballe_mergedGates_SR.gex',
379
+ 'TX07_20230731_2x4_RC20-33.gex'
380
+ ]
381
+
382
+ for filename in test_files:
383
+ print(f"\n{'='*80}")
384
+ print(f"Testing describe_gex() with filename: {filename}")
385
+ print(f"{'='*80}")
386
+
387
+ try:
388
+ # Test with filename
389
+ describe_gex(filename)
390
+
391
+ print(f"\n{'='*80}")
392
+ print(f"Testing describe_gex() with dictionaries from: {filename}")
393
+ print(f"{'='*80}")
394
+
395
+ # Test with dictionaries
396
+ general, channels = read_gex(filename)
397
+ describe_gex(general, channels)
398
+
399
+ except Exception as e:
400
+ print(f"Error testing {filename}: {e}")
401
+ import traceback
402
+ traceback.print_exc()