ras-commander 0.1.6__py2.py3-none-any.whl → 0.20.dev0__py2.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.
@@ -1,315 +0,0 @@
1
- """
2
- Execution operations for runningHEC-RAS simulations using subprocess.
3
- Based on the HEC-Commander project's "Command Line is All You Need" approach, leveraging the -c compute flag to run HEC-RAS and orchestrating changes directly in the RAS input files to achieve automation outcomes.
4
- """
5
-
6
- import os
7
- import subprocess
8
- import shutil
9
- from pathlib import Path
10
- from concurrent.futures import ThreadPoolExecutor, as_completed
11
- from .file_operations import FileOperations
12
- from .plan_operations import PlanOperations
13
- import subprocess
14
- import os
15
- import logging
16
- import time
17
- from .project_config import ProjectConfig
18
- import pandas as pd
19
-
20
- class RasExecutor:
21
-
22
- @staticmethod
23
- def compute_hecras_plan(compute_plan_file):
24
- """
25
- Compute a HEC-RAS plan using the provided plan file.
26
-
27
- This method executes a HEC-RAS plan by running the HEC-RAS executable
28
- with the specified plan file. It uses the plan file's path to determine
29
- the corresponding project file path.
30
-
31
- Args:
32
- compute_plan_file (str): The full path to the HEC-RAS plan file (.p**)
33
-
34
- Returns:
35
- bool: True if the plan computation was successful, False otherwise.
36
-
37
- Raises:
38
- subprocess.CalledProcessError: If the HEC-RAS execution fails.
39
-
40
- Note:
41
- This method assumes that the project file (.prj) is in the same
42
- directory as the plan file and has the same name (different extension).
43
- """
44
- config = ProjectConfig()
45
- config.check_initialized()
46
-
47
- # Derive the project file path from the plan file path
48
- compute_project_file = Path(compute_plan_file).with_suffix('.prj')
49
-
50
- cmd = f'"{config.hecras_exe_path}" -c "{compute_project_file}" "{compute_plan_file}"'
51
- print(f"Running command: {cmd}")
52
- try:
53
- subprocess.run(cmd, check=True, shell=True, capture_output=True, text=True)
54
- logging.info(f"HEC-RAS execution completed for plan: {Path(compute_plan_file).name}")
55
- return True
56
- except subprocess.CalledProcessError as e:
57
- logging.error(f"Error running plan: {Path(compute_plan_file).name}")
58
- logging.error(f"Error message: {e.output}")
59
- return False
60
-
61
-
62
- @staticmethod
63
- def compute_hecras_plan_from_folder(plan_for_compute, folder_for_compute):
64
- """
65
- Compute a HEC-RAS plan from a specified folder.
66
-
67
- This function allows running a plan directly from a different folder than the project folder,
68
- which is useful for the -test function and parallel runs. It uses the HEC-RAS executable path
69
- from the ProjectConfig, but derives other paths from the provided arguments.
70
-
71
- Args:
72
- plan_for_compute (str): The full path to the HEC-RAS plan file (.p**) to be computed.
73
- folder_for_compute (str): The folder containing the HEC-RAS project files.
74
-
75
- Returns:
76
- bool: True if the plan computation was successful, False otherwise.
77
-
78
- Raises:
79
- subprocess.CalledProcessError: If the HEC-RAS execution fails.
80
-
81
- Note:
82
- This function uses the ProjectConfig only to get the hecras_exe_path.
83
- Other paths are derived from plan_for_compute and folder_for_compute.
84
- """
85
- config = ProjectConfig()
86
- config.check_initialized()
87
- compute_project_file = FileOperations.find_hecras_project_file(folder_for_compute)
88
- cmd = f'"{config.hecras_exe_path}" -c "{compute_project_file}" "{plan_for_compute}"'
89
- print(f"Running command: {cmd}")
90
- try:
91
- subprocess.run(cmd, check=True, shell=True, capture_output=True, text=True)
92
- logging.info(f"HEC-RAS execution completed for plan: {Path(plan_for_compute).name}")
93
- return True
94
- except subprocess.CalledProcessError as e:
95
- logging.error(f"Error running plan: {Path(plan_for_compute).name}")
96
- logging.error(f"Error message: {e.output}")
97
- return False
98
-
99
-
100
- @staticmethod
101
- def recreate_test_function(project_folder):
102
- """
103
- Recreate the -test function of HEC-RAS command line.
104
-
105
- Parameters:
106
- project_folder (str): Path to the HEC-RAS project folder
107
-
108
- Returns:
109
- None
110
-
111
-
112
- This function executes all ras plans in a separate folder defined by compute_folder='[Test]', so we need to call the individual functions and use distinct variable names
113
- For this function, we are using "compute" in the varable names as these are the values used for the compute operations in a separate copy of the ras project folder
114
-
115
- """
116
- print("Starting the recreate_test_function...")
117
-
118
- # Create the test folder path
119
- compute_folder='[Test]'
120
- folder_for_compute = Path(project_folder).parent / f"{Path(project_folder).name} {compute_folder}"
121
- print(f"Creating the test folder: {folder_for_compute}...")
122
-
123
- # Copy the project folder to the test folder
124
- print("Copying project folder to the test folder...")
125
- shutil.copytree(project_folder, folder_for_compute, dirs_exist_ok=True)
126
- print(f"Test folder created at: {folder_for_compute}")
127
-
128
- # Find the project file
129
- print("Finding the project file...")
130
- compute_project_file = FileOperations.find_hecras_project_file(folder_for_compute)
131
-
132
- if not compute_project_file:
133
- print("Project file not found.")
134
- return
135
- print(f"Project file found: {compute_project_file}")
136
-
137
- # Parse the project file to get plan entries
138
- print("Parsing the project file to get plan entries...")
139
- ras_compute_plan_entries = FileOperations.get_plan_entries(compute_project_file)
140
- print("Parsed project file successfully.")
141
-
142
- # Enforce recomputing of geometry preprocessor and IB tables
143
- print("Enforcing recomputing of geometry preprocessor and IB tables...")
144
- for plan_file in ras_compute_plan_entries['full_path']:
145
- PlanOperations.update_geompre_flags(plan_file, run_htab_value=-1, use_ib_tables_value=-1)
146
- print("Recomputing enforced successfully.")
147
-
148
- # Change max cores to 1
149
- print("Changing max cores to 2 for all plan files...")
150
- for plan_file in ras_compute_plan_entries['full_path']:
151
- PlanOperations.set_num_cores(plan_file, num_cores=2)
152
- print("Max cores updated successfully.")
153
-
154
- # Run all plans sequentially
155
- print("Running all plans sequentially...")
156
- for _, plan in ras_compute_plan_entries.iterrows():
157
- plan_for_compute = plan["full_path"]
158
- RasExecutor.compute_hecras_plan_from_folder(plan_for_compute, folder_for_compute)
159
-
160
- print("All plans have been executed.")
161
- print("recreate_test_function completed.")
162
-
163
- @staticmethod
164
- def run_plans_parallel(config, max_workers, cores_per_run):
165
- """
166
- Run HEC-RAS plans in parallel using ThreadPoolExecutor.
167
-
168
- Parameters:
169
- config (ProjectConfig): Configuration object containing project information
170
- max_workers (int): Maximum number of parallel runs
171
- cores_per_run (int): Number of cores to use per run
172
-
173
- Returns:
174
- dict: Dictionary with plan numbers as keys and execution success as values
175
-
176
- This function executes all ras plans in separate folders defined by the max_workers and the numbering of the test folders [Test 1], [Test 2], etc.
177
- Each worker operates sequentially on its assigned folder while all workers operate in parallel.
178
-
179
- Revisions:
180
- 1. Created a pandas DataFrame to map each folder to a plan for execution.
181
- 2. Implemented logic to assign worker numbers and compute folders.
182
- 3. Used find_hecras_project_file function to get the full path of project files.
183
- 4. Updated plan file paths to use compute folders.
184
- 5. Revised the parallel execution to use separate threads for each worker.
185
- 6. Implemented a queue system for each worker to handle plans sequentially.
186
- 7. Updated the cleanup process to use the new folder structure.
187
- """
188
- import queue
189
- from threading import Thread
190
-
191
- project_folder = Path(config.project_file).parent
192
- test_folders = []
193
-
194
- # Create multiple copies of the project folder
195
- for i in range(1, max_workers + 1):
196
- folder_for_compute = project_folder.parent / f"{project_folder.name} [Test {i}]"
197
- shutil.copytree(project_folder, folder_for_compute, dirs_exist_ok=True)
198
- test_folders.append(folder_for_compute)
199
- print(f"Created test folder: {folder_for_compute}")
200
-
201
- compute_parallel_entries = []
202
- for i, (_, plan_row) in enumerate(config.ras_plan_entries.iterrows()):
203
- worker_number = i % max_workers
204
- compute_folder = test_folders[worker_number]
205
- compute_project_file = FileOperations.find_hecras_project_file(compute_folder)
206
- compute_plan_file = compute_folder / Path(plan_row['full_path']).name
207
- compute_parallel_entries.append({
208
- 'worker_number': worker_number,
209
- 'compute_folder': compute_folder,
210
- 'compute_project_file': compute_project_file,
211
- 'compute_plan_file': compute_plan_file,
212
- 'plan_number': plan_row['plan_number']
213
- })
214
-
215
- compute_parallel_df = pd.DataFrame(compute_parallel_entries)
216
- print("compute_parallel_entries dataframe:")
217
- display(compute_parallel_df)
218
-
219
- results = {}
220
- worker_queues = [queue.Queue() for _ in range(max_workers)]
221
-
222
- def worker_thread(worker_id):
223
- """
224
- Execute HEC-RAS plans assigned to a specific worker thread.
225
-
226
- This function continuously processes plans from the worker's queue until it's empty.
227
- It sets the number of cores for each plan, computes the plan, and records the result.
228
-
229
- Parameters:
230
- worker_id (int): The ID of the worker thread.
231
-
232
- Notes:
233
- - Uses PlanOperations.set_num_cores to set the number of cores for each plan.
234
- - Uses RasExecutor.compute_hecras_plan to execute each plan.
235
- - Records success or failure in the 'results' dictionary.
236
- - Prints status messages for completed or failed plans.
237
- """
238
- while True:
239
- try:
240
- row = worker_queues[worker_id].get(block=False)
241
- PlanOperations.set_num_cores(str(row['compute_plan_file']), cores_per_run)
242
- success = RasExecutor.compute_hecras_plan(row['compute_plan_file'])
243
- results[row['plan_number']] = success
244
- print(f"Completed: Plan {row['plan_number']} in worker {worker_id}")
245
- except queue.Empty:
246
- break
247
- except Exception as e:
248
- results[row['plan_number']] = False
249
- print(f"Failed: Plan {row['plan_number']} in worker {worker_id}. Error: {str(e)}")
250
-
251
- # Distribute plans to worker queues
252
- for _, row in compute_parallel_df.iterrows():
253
- worker_queues[row['worker_number']].put(row)
254
-
255
- # Start worker threads
256
- threads = []
257
- for i in range(max_workers):
258
- thread = Thread(target=worker_thread, args=(i,))
259
- thread.start()
260
- threads.append(thread)
261
-
262
- # Wait for all threads to complete
263
- for thread in threads:
264
- thread.join()
265
-
266
- # Clean up and consolidate results
267
- time.sleep(3) # Allow files to close
268
- final_test_folder = project_folder.parent / f"{project_folder.name} [Test]"
269
- final_test_folder.mkdir(exist_ok=True)
270
-
271
- for test_folder in test_folders:
272
- for item in test_folder.iterdir():
273
- dest_path = final_test_folder / item.name
274
- if dest_path.exists():
275
- if dest_path.is_dir():
276
- shutil.rmtree(dest_path)
277
- else:
278
- dest_path.unlink()
279
- shutil.move(str(item), final_test_folder)
280
- shutil.rmtree(test_folder)
281
- print(f"Moved and removed test folder: {test_folder}")
282
-
283
- return results
284
-
285
- @staticmethod
286
- def run_all_plans_parallel(project_folder, hecras_exe_path):
287
- """
288
- Run all plans in a project folder in parallel.
289
-
290
- Parameters:
291
- project_folder (str): The path to the project folder.
292
- hecras_exe_path (str): The path to the HEC-RAS executable.
293
-
294
- Returns:
295
- dict: A dictionary with plan numbers as keys and execution success status as values.
296
- """
297
- config = ProjectConfig.init_ras_project(project_folder, hecras_exe_path)
298
-
299
- if config:
300
- print("ras_plan_entries dataframe:")
301
- display(config.ras_plan_entries)
302
-
303
- max_workers = 2 # Number of parallel runs
304
- cores_per_run = 2 # Number of cores per run
305
-
306
- results = RasExecutor.run_plans_parallel(config, max_workers, cores_per_run)
307
-
308
- print("\nExecution Results:")
309
- for plan_number, success in results.items():
310
- print(f"Plan {plan_number}: {'Successful' if success else 'Failed'}")
311
-
312
- return results
313
- else:
314
- print("Failed to initialize project configuration.")
315
- return None
@@ -1,173 +0,0 @@
1
- """
2
- File operations for HEC-RAS project files.
3
- """
4
- import re
5
- from pathlib import Path
6
- import pandas as pd
7
-
8
- class FileOperations:
9
- """
10
- A class for HEC-RAS file operations.
11
-
12
-
13
- Revision Notes: All functions from class ProjectManager should be moved here
14
-
15
-
16
- """
17
- @staticmethod
18
- def find_hecras_project_file(folder_path):
19
- """
20
- Find the appropriate HEC-RAS project file (.prj) in the given folder.
21
-
22
- Parameters:
23
- folder_path (str or Path): Path to the folder containing HEC-RAS files.
24
-
25
- Returns:
26
- Path: The full path of the selected .prj file or None if no suitable file is found.
27
- """
28
- print(f"running find_hecras_project_file with folder_path: {folder_path}")
29
- folder_path = Path(folder_path)
30
- print("Searching for .prj files...")
31
- prj_files = list(folder_path.glob("*.prj"))
32
- # print(f"Found {len(prj_files)} .prj files")
33
- # print("Searching for .rasmap files...")
34
- rasmap_files = list(folder_path.glob("*.rasmap"))
35
- #print(f"Found {len(rasmap_files)} .rasmap files")
36
- if len(prj_files) == 1:
37
- project_file = prj_files[0]
38
- # print(f"Only one .prj file found. Selecting: {project_file}")
39
- # print(f"Full path: {project_file.resolve()}")
40
- return project_file.resolve()
41
- if len(prj_files) > 1:
42
- print("Multiple .prj files found.")
43
- if len(rasmap_files) == 1:
44
- base_filename = rasmap_files[0].stem
45
- project_file = folder_path / f"{base_filename}.prj"
46
- # print(f"Found single .rasmap file. Using its base name: {base_filename}")
47
- # print(f"Full path: {project_file.resolve()}")
48
- return project_file.resolve()
49
- print("Multiple .prj files and no single .rasmap file. Searching for 'Proj Title=' in .prj files...")
50
- for prj_file in prj_files:
51
- # print(f"Checking file: {prj_file.name}")
52
- with open(prj_file, 'r') as file:
53
- if "Proj Title=" in file.read():
54
- # print(f"Found 'Proj Title=' in file: {prj_file.name}")
55
- # print(f"Full path: {prj_file.resolve()}")
56
- return prj_file.resolve()
57
- print("No suitable .prj file found after all checks.")
58
- return project_file
59
-
60
- @staticmethod
61
- def get_project_name(project_path):
62
- """
63
- Extract the project name from the given project path.
64
-
65
- Parameters:
66
- project_path (Path): Path object representing the project file path
67
-
68
- Returns:
69
- str: The project name derived from the file name without extension
70
- """
71
- project_name = project_path.stem
72
- return project_name
73
-
74
- @staticmethod
75
- def get_plan_entries(project_file):
76
- """
77
- Parse HEC-RAS project file and create dataframe for plan entries.
78
-
79
- Parameters:
80
- project_file (str): Full path to HEC-RAS project file (.prj)
81
-
82
- Returns:
83
- pandas DataFrame: DataFrame containing plan entries
84
- """
85
- project_path = Path(project_file)
86
- project_name = FileOperations.get_project_name(project_path)
87
- project_dir = project_path.parent
88
-
89
- with open(project_file, 'r') as f:
90
- content = f.read()
91
-
92
- plan_entries = re.findall(r'Plan File=(.*?)(?:\n|$)', content)
93
-
94
- ras_plan_entries = pd.DataFrame({
95
- 'plan_number': [re.findall(r'\d+', entry)[0] for entry in plan_entries],
96
- 'file_name': [f"{project_name}.{entry.strip().zfill(2)}" for entry in plan_entries],
97
- 'full_path': [str(project_dir / f"{project_name}.{entry.strip().zfill(2)}") for entry in plan_entries],
98
- 'results_path': [str(project_dir / f"{project_name}.{entry.strip().zfill(2)}.hdf") for entry in plan_entries]
99
- })
100
-
101
- return ras_plan_entries
102
-
103
- @staticmethod
104
- def get_flow_entries(project_file):
105
- """
106
- Parse HEC-RAS project file and create dataframe for flow entries.
107
-
108
- Parameters:
109
- project_file (str): Full path to HEC-RAS project file (.prj)
110
-
111
- Returns:
112
- pandas DataFrame: DataFrame containing flow entries
113
- """
114
- project_path = Path(project_file)
115
- project_name = FileOperations.get_project_name(project_path)
116
- project_dir = project_path.parent
117
- with open(project_file, 'r') as f:
118
- content = f.read()
119
- flow_entries = re.findall(r'Flow File=(.*?)(?:\n|$)', content)
120
- ras_flow_entries = pd.DataFrame({
121
- 'flow_number': [re.findall(r'\d+', entry)[0] for entry in flow_entries],
122
- 'file_name': [f"{project_name}.{entry.strip().zfill(2)}" for entry in flow_entries],
123
- 'full_path': [str(project_dir / f"{project_name}.{entry.strip().zfill(2)}") for entry in flow_entries]
124
- })
125
- return ras_flow_entries
126
-
127
- @staticmethod
128
- def get_unsteady_entries(project_file):
129
- """
130
- Parse HEC-RAS project file and create dataframe for unsteady entries.
131
-
132
- Parameters:
133
- project_file (str): Full path to HEC-RAS project file (.prj)
134
-
135
- Returns:
136
- pandas DataFrame: DataFrame containing unsteady entries
137
- """
138
- project_path = Path(project_file)
139
- project_name = FileOperations.get_project_name(project_path)
140
- project_dir = project_path.parent
141
- with open(project_file, 'r') as f:
142
- content = f.read()
143
- unsteady_entries = re.findall(r'Unsteady File=(.*?)(?:\n|$)', content)
144
- ras_unsteady_entries = pd.DataFrame({
145
- 'unsteady_number': [re.findall(r'\d+', entry)[0] for entry in unsteady_entries],
146
- 'file_name': [f"{project_name}.{entry.strip().zfill(2)}" for entry in unsteady_entries],
147
- 'full_path': [str(project_dir / f"{project_name}.{entry.strip().zfill(2)}") for entry in unsteady_entries]
148
- })
149
- return ras_unsteady_entries
150
-
151
- @staticmethod
152
- def get_geom_entries(project_file):
153
- """
154
- Parse HEC-RAS project file and create dataframe for geometry entries.
155
-
156
- Parameters:
157
- project_file (str): Full path to HEC-RAS project file (.prj)
158
-
159
- Returns:
160
- pandas DataFrame: DataFrame containing geometry entries
161
- """
162
- project_path = Path(project_file)
163
- project_name = FileOperations.get_project_name(project_path)
164
- project_dir = project_path.parent
165
- with open(project_file, 'r') as f:
166
- content = f.read()
167
- geom_entries = re.findall(r'Geom File=(.*?)(?:\n|$)', content)
168
- ras_geom_entries = pd.DataFrame({
169
- 'geom_number': [re.findall(r'\d+', entry)[0] for entry in geom_entries],
170
- 'file_name': [f"{project_name}.{entry.strip().zfill(2)}" for entry in geom_entries],
171
- 'full_path': [str(project_dir / f"{project_name}.{entry.strip().zfill(2)}") for entry in geom_entries]
172
- })
173
- return ras_geom_entries
@@ -1,184 +0,0 @@
1
- """
2
- Operations for handling geometry files in HEC-RAS projects.
3
- """
4
- from pathlib import Path
5
- from .plan_operations import PlanOperations
6
- from .file_operations import FileOperations
7
- from .project_config import ProjectConfig
8
- import re
9
-
10
- class GeometryOperations:
11
- """
12
- A class for operations on HEC-RAS geometry files.
13
- """
14
- @staticmethod
15
- def clear_geometry_preprocessor_files(plan_file):
16
- """
17
- Clear HEC-RAS geometry preprocessor files for a given plan file.
18
-
19
- Parameters:
20
- plan_file (str): Full path to the HEC-RAS plan file (.p*)
21
-
22
- Returns:
23
- None
24
- """
25
- config = ProjectConfig()
26
- config.check_initialized()
27
-
28
- plan_path = Path(plan_file)
29
- geom_preprocessor_file = plan_path.with_suffix('.c' + plan_path.suffix[2:])
30
- if geom_preprocessor_file.exists():
31
- print(f"Deleting geometry preprocessor file: {geom_preprocessor_file}")
32
- geom_preprocessor_file.unlink()
33
- print("File deletion completed successfully.")
34
- else:
35
- print(f"No geometry preprocessor file found for: {plan_file}")
36
-
37
- @staticmethod
38
- def clear_geometry_preprocessor_files_for_all_plans():
39
- """
40
- Clear HEC-RAS geometry preprocessor files for all plan files in the project directory.
41
-
42
- Returns:
43
- None
44
- """
45
- config = ProjectConfig()
46
- config.check_initialized()
47
-
48
- for plan_file in config.project_folder.glob("*.p[0-9][0-9]"):
49
- GeometryOperations.clear_geometry_preprocessor_files(plan_file)
50
-
51
- @staticmethod
52
- def copy_geometry_files(dst_folder, template_geom):
53
- """
54
- Copy geometry files from a template to the next available geometry number
55
- and update the destination folder accordingly.
56
-
57
- Parameters:
58
- dst_folder (str): Destination folder path
59
- template_geom (str): Template geometry number (e.g., 'g01')
60
-
61
- Returns:
62
- str: New geometry number (e.g., 'g03')
63
- """
64
- config = ProjectConfig()
65
- config.check_initialized()
66
-
67
- src_folder = config.project_folder
68
- dst_folder = Path(dst_folder)
69
- dst_folder.mkdir(parents=True, exist_ok=True)
70
-
71
- # Determine the next available geometry number
72
- existing_numbers = []
73
- geom_file_pattern = re.compile(r'^Geom File=g(\d+)', re.IGNORECASE)
74
-
75
- for plan_file in src_folder.glob("*.p[0-9][0-9]"):
76
- with open(plan_file, 'r') as file:
77
- lines = file.readlines()
78
- for line in lines:
79
- match = geom_file_pattern.match(line.strip())
80
- if match:
81
- existing_numbers.append(int(match.group(1)))
82
-
83
- if existing_numbers:
84
- existing_numbers.sort()
85
- next_number = 1
86
- for num in existing_numbers:
87
- if num == next_number:
88
- next_number += 1
89
- else:
90
- break
91
- else:
92
- next_number = 1
93
-
94
- next_geom_number = f"{next_number:02d}"
95
-
96
- # Copy the template geometry file to the new geometry file
97
- template_geom_filename = f"{config.project_name}.g{template_geom}"
98
- src_g_file = src_folder / template_geom_filename
99
- if src_g_file.exists():
100
- new_geom_filename = f"{config.project_name}.g{next_geom_number}"
101
- dst_g_file = dst_folder / new_geom_filename
102
- dst_g_file.write_bytes(src_g_file.read_bytes())
103
- print(f"Copied {src_g_file} to {dst_g_file}")
104
- else:
105
- raise FileNotFoundError(f"Template geometry file '{src_g_file}' does not exist.")
106
-
107
- # Copy the corresponding .hdf file
108
- src_hdf_file = src_folder / f"{template_geom_filename}.hdf"
109
- if src_hdf_file.exists():
110
- new_hdf_filename = f"{new_geom_filename}.hdf"
111
- dst_hdf_file = dst_folder / new_hdf_filename
112
- dst_hdf_file.write_bytes(src_hdf_file.read_bytes())
113
- print(f"Copied {src_hdf_file} to {dst_hdf_file}")
114
- else:
115
- raise FileNotFoundError(f"Template geometry .hdf file '{src_hdf_file}' does not exist.")
116
- config = ProjectConfig()
117
- return f"g{next_geom_number}"
118
-
119
- @staticmethod
120
- def rename_geometry_files(old_number, new_number):
121
- """
122
- Rename geometry files in the project folder.
123
-
124
- Parameters:
125
- old_number (str): Old geometry number (e.g., 'g01')
126
- new_number (str): New geometry number (e.g., 'g02')
127
-
128
- Returns:
129
- None
130
- """
131
- config = ProjectConfig()
132
- config.check_initialized()
133
-
134
- folder = config.project_folder
135
- old_g_file = next(folder.glob(f"*.{old_number}"), None)
136
- if old_g_file:
137
- new_g_file = folder / old_g_file.name.replace(old_number, new_number)
138
- old_g_file.rename(new_g_file)
139
- print(f"Renamed {old_g_file} to {new_g_file}")
140
- else:
141
- print(f"No .{old_number} file found in {folder}")
142
-
143
- old_hdf_file = next(folder.glob(f"*.{old_number}.hdf"), None)
144
- if old_hdf_file:
145
- new_hdf_file = folder / old_hdf_file.name.replace(old_number, new_number)
146
- old_hdf_file.rename(new_hdf_file)
147
- print(f"Renamed {old_hdf_file} to {new_hdf_file}")
148
- else:
149
- print(f"No .{old_number}.hdf file found in {folder}")
150
-
151
- @staticmethod
152
- def update_geometry_reference_in_plan(plan_file, new_geometry_number):
153
- """
154
- Update the geometry reference in a plan file.
155
-
156
- Parameters:
157
- plan_file (str): Full path to the plan file
158
- new_geometry_number (str): New geometry number (e.g., 'g02')
159
-
160
- Returns:
161
- None
162
- """
163
- config = ProjectConfig()
164
- config.check_initialized()
165
-
166
- geometry_full_path = next(config.project_folder.glob(f"*.g{new_geometry_number}"), None)
167
- if not geometry_full_path:
168
- raise FileNotFoundError(f"Geometry file '*.g{new_geometry_number}' not found in the project folder.")
169
-
170
- plan_path = Path(plan_file)
171
- with open(plan_path, 'r') as file:
172
- lines = file.readlines()
173
- updated = False
174
- for index, line in enumerate(lines):
175
- if line.startswith("Geom File="):
176
- lines[index] = f"Geom File=g{new_geometry_number}\n"
177
- updated = True
178
- break
179
- if updated:
180
- with open(plan_path, 'w') as file:
181
- file.writelines(lines)
182
- print(f"Updated geometry reference in {plan_file} to {new_geometry_number}")
183
- else:
184
- print(f"No geometry reference found in {plan_file}")