pycphy 0.1.0__py3-none-any.whl → 0.2.0__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.
- pycphy/__init__.py +11 -0
- pycphy/cli.py +145 -0
- pycphy/config_manager.py +373 -0
- pycphy/foamCaseDeveloper/__init__.py +60 -41
- pycphy/foamCaseDeveloper/config/__init__.py +69 -26
- pycphy/foamCaseDeveloper/config/cad_mesh_config.py +62 -0
- pycphy/foamCaseDeveloper/config/config_hfdibdem.py +193 -0
- pycphy/foamCaseDeveloper/config/constant/__init__.py +23 -0
- pycphy/foamCaseDeveloper/config/constant/dynamic_mesh_config.py +208 -0
- pycphy/foamCaseDeveloper/config/constant/gravity_field_config.py +379 -0
- pycphy/foamCaseDeveloper/config/constant/transport_properties_config.py +225 -0
- pycphy/foamCaseDeveloper/config/constant/turbulence_config.py +617 -0
- pycphy/foamCaseDeveloper/config/csv_boundary_reader.py +219 -0
- pycphy/foamCaseDeveloper/config/system/__init__.py +31 -0
- pycphy/foamCaseDeveloper/config/system/block_mesh_config.py +184 -0
- pycphy/foamCaseDeveloper/config/{control_config.py → system/control_config.py} +113 -1
- pycphy/foamCaseDeveloper/config/system/decompose_par_config.py +525 -0
- pycphy/foamCaseDeveloper/config/system/fv_options_config.py +575 -0
- pycphy/foamCaseDeveloper/config/system/fv_schemes_config.py +363 -0
- pycphy/foamCaseDeveloper/config/system/set_fields_config.py +640 -0
- pycphy/foamCaseDeveloper/config/system/snappy_hex_mesh_config.py +241 -0
- pycphy/foamCaseDeveloper/config/zero/U_config.py +135 -0
- pycphy/foamCaseDeveloper/config/zero/__init__.py +22 -0
- pycphy/foamCaseDeveloper/config/zero/f_config.py +140 -0
- pycphy/foamCaseDeveloper/config/zero/lambda_config.py +157 -0
- pycphy/foamCaseDeveloper/config/zero/p_config.py +97 -0
- pycphy/foamCaseDeveloper/core/__init__.py +30 -18
- pycphy/foamCaseDeveloper/core/block_mesh_developer.py +1 -1
- pycphy/foamCaseDeveloper/core/cad_block_mesh_developer.py +463 -0
- pycphy/foamCaseDeveloper/core/case_builder.py +1217 -0
- pycphy/foamCaseDeveloper/core/foam_case_manager.py +370 -111
- pycphy/foamCaseDeveloper/develop_case.py +640 -0
- pycphy/foamCaseDeveloper/main.py +260 -260
- pycphy/foamCaseDeveloper/utils/myAutoCAD.py +418 -0
- pycphy/foamCaseDeveloper/writers/__init__.py +37 -4
- pycphy/foamCaseDeveloper/writers/constant/__init__.py +25 -0
- pycphy/foamCaseDeveloper/writers/constant/dynamic_mesh_dict_writer.py +75 -0
- pycphy/foamCaseDeveloper/writers/constant/gravity_field_writer.py +88 -0
- pycphy/foamCaseDeveloper/writers/constant/hfdibdem_dict_writer.py +81 -0
- pycphy/foamCaseDeveloper/writers/constant/transport_properties_writer.py +202 -0
- pycphy/foamCaseDeveloper/writers/{turbulence_properties_writer.py → constant/turbulence_properties_writer.py} +49 -1
- pycphy/foamCaseDeveloper/writers/system/__init__.py +31 -0
- pycphy/foamCaseDeveloper/writers/{block_mesh_writer.py → system/block_mesh_writer.py} +1 -1
- pycphy/foamCaseDeveloper/writers/{control_dict_writer.py → system/control_dict_writer.py} +37 -1
- pycphy/foamCaseDeveloper/writers/system/decompose_par_writer.py +228 -0
- pycphy/foamCaseDeveloper/writers/system/fv_options_writer.py +188 -0
- pycphy/foamCaseDeveloper/writers/system/fv_schemes_writer.py +155 -0
- pycphy/foamCaseDeveloper/writers/system/set_fields_writer.py +191 -0
- pycphy/foamCaseDeveloper/writers/system/snappy_hex_mesh_writer.py +123 -0
- pycphy/foamCaseDeveloper/writers/zero/__init__.py +24 -0
- pycphy/foamCaseDeveloper/writers/zero/f_field_writer.py +89 -0
- pycphy/foamCaseDeveloper/writers/zero/lambda_field_writer.py +84 -0
- pycphy/foamCaseDeveloper/writers/zero/p_field_writer.py +89 -0
- pycphy/foamCaseDeveloper/writers/zero/u_field_writer.py +96 -0
- pycphy/foamCaseDeveloper/writers/zero/zero_field_factory.py +388 -0
- {pycphy-0.1.0.dist-info → pycphy-0.2.0.dist-info}/METADATA +154 -6
- pycphy-0.2.0.dist-info/RECORD +63 -0
- pycphy-0.2.0.dist-info/entry_points.txt +3 -0
- pycphy/foamCaseDeveloper/config/block_mesh_config.py +0 -90
- pycphy/foamCaseDeveloper/config/turbulence_config.py +0 -187
- pycphy/foamCaseDeveloper/core/control_dict_writer.py +0 -55
- pycphy/foamCaseDeveloper/core/turbulence_properties_writer.py +0 -68
- pycphy-0.1.0.dist-info/RECORD +0 -24
- pycphy-0.1.0.dist-info/entry_points.txt +0 -2
- {pycphy-0.1.0.dist-info → pycphy-0.2.0.dist-info}/WHEEL +0 -0
- {pycphy-0.1.0.dist-info → pycphy-0.2.0.dist-info}/licenses/LICENSE +0 -0
- {pycphy-0.1.0.dist-info → pycphy-0.2.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,463 @@
|
|
1
|
+
"""
|
2
|
+
CAD-based Block Mesh Developer
|
3
|
+
|
4
|
+
This module provides functionality to generate blockMeshDict files from AutoCAD CAD files
|
5
|
+
by reading 3DSOLID and REGION entities with XData containing mesh configuration information.
|
6
|
+
"""
|
7
|
+
|
8
|
+
import os
|
9
|
+
import csv
|
10
|
+
import numpy as np
|
11
|
+
from typing import Dict, List, Tuple, Optional, Any
|
12
|
+
|
13
|
+
from ..writers.system.block_mesh_writer import BlockMeshWriter
|
14
|
+
from ..utils.myAutoCAD import myAutoCAD
|
15
|
+
|
16
|
+
|
17
|
+
class CADBlockMeshDeveloper:
|
18
|
+
"""
|
19
|
+
A class to generate blockMeshDict files from AutoCAD CAD files.
|
20
|
+
|
21
|
+
This class reads 3DSOLID entities for block definitions and REGION entities for
|
22
|
+
patch definitions, using XData to identify and configure the mesh parameters.
|
23
|
+
"""
|
24
|
+
|
25
|
+
def __init__(self,
|
26
|
+
blocks_csv_file: str = "Inputs/blocks.csv",
|
27
|
+
patches_csv_file: str = "Inputs/patches.csv",
|
28
|
+
tolerance: float = 1e-6,
|
29
|
+
block_xdata_app_name: str = "BLOCKDATA",
|
30
|
+
region_xdata_app_name: str = "REGIONDATA"):
|
31
|
+
"""
|
32
|
+
Initialize the CAD Block Mesh Developer.
|
33
|
+
|
34
|
+
Args:
|
35
|
+
blocks_csv_file: Path to CSV file containing block parameters
|
36
|
+
patches_csv_file: Path to CSV file containing patch definitions
|
37
|
+
tolerance: Tolerance for face coincidence checking
|
38
|
+
block_xdata_app_name: XData application name for 3DSOLID entities
|
39
|
+
region_xdata_app_name: XData application name for REGION entities
|
40
|
+
"""
|
41
|
+
self.blocks_csv_file = blocks_csv_file
|
42
|
+
self.patches_csv_file = patches_csv_file
|
43
|
+
self.tolerance = tolerance
|
44
|
+
self.block_xdata_app_name = block_xdata_app_name
|
45
|
+
self.region_xdata_app_name = region_xdata_app_name
|
46
|
+
|
47
|
+
# Data structures for mesh generation
|
48
|
+
self.all_vertices = []
|
49
|
+
self.block_definitions = []
|
50
|
+
self.patch_definitions = {}
|
51
|
+
self.solid_data = {}
|
52
|
+
|
53
|
+
# Configuration data
|
54
|
+
self.block_parameters = {}
|
55
|
+
self.patch_info = {}
|
56
|
+
|
57
|
+
# CAD connection
|
58
|
+
self.cad_app = None
|
59
|
+
self.modelspace = None
|
60
|
+
|
61
|
+
def _load_csv_data(self, filepath: str, required_columns: List[str], key_column: str) -> Optional[Dict]:
|
62
|
+
"""
|
63
|
+
Load data from a CSV file into a dictionary.
|
64
|
+
|
65
|
+
Args:
|
66
|
+
filepath: Path to the CSV file
|
67
|
+
required_columns: List of required column names
|
68
|
+
key_column: Column to use as dictionary key
|
69
|
+
|
70
|
+
Returns:
|
71
|
+
Dictionary with loaded data or None if error
|
72
|
+
"""
|
73
|
+
data = {}
|
74
|
+
try:
|
75
|
+
with open(filepath, mode='r', newline='') as infile:
|
76
|
+
reader = csv.DictReader(infile)
|
77
|
+
if not all(col in reader.fieldnames for col in required_columns):
|
78
|
+
missing = set(required_columns) - set(reader.fieldnames)
|
79
|
+
raise KeyError(f"CSV file '{filepath}' is missing required columns: {missing}")
|
80
|
+
for row in reader:
|
81
|
+
key = row[key_column]
|
82
|
+
data[key] = row
|
83
|
+
print(f"Successfully loaded {len(data)} definitions from '{filepath}'.")
|
84
|
+
return data
|
85
|
+
except FileNotFoundError:
|
86
|
+
print(f"Error: The file '{filepath}' was not found.")
|
87
|
+
return None
|
88
|
+
except KeyError as e:
|
89
|
+
print(f"Error: {e}")
|
90
|
+
return None
|
91
|
+
|
92
|
+
def _generate_solid_faces(self, vertex_indices: List[int]) -> List[List[int]]:
|
93
|
+
"""
|
94
|
+
Generate face definitions for a hex block from vertex indices.
|
95
|
+
|
96
|
+
Args:
|
97
|
+
vertex_indices: List of 8 vertex indices in OpenFOAM ordering
|
98
|
+
|
99
|
+
Returns:
|
100
|
+
List of face definitions as lists of vertex indices
|
101
|
+
"""
|
102
|
+
return [
|
103
|
+
# Bottom face (z=0)
|
104
|
+
[vertex_indices[0], vertex_indices[1], vertex_indices[2], vertex_indices[3]],
|
105
|
+
# Top face (z=1)
|
106
|
+
[vertex_indices[4], vertex_indices[5], vertex_indices[6], vertex_indices[7]],
|
107
|
+
# Side faces
|
108
|
+
[vertex_indices[0], vertex_indices[4], vertex_indices[7], vertex_indices[3]], # x=0
|
109
|
+
[vertex_indices[1], vertex_indices[2], vertex_indices[6], vertex_indices[5]], # x=1
|
110
|
+
[vertex_indices[0], vertex_indices[1], vertex_indices[5], vertex_indices[4]], # y=0
|
111
|
+
[vertex_indices[3], vertex_indices[7], vertex_indices[6], vertex_indices[2]] # y=1
|
112
|
+
]
|
113
|
+
|
114
|
+
def connect_to_cad(self) -> bool:
|
115
|
+
"""
|
116
|
+
Connect to AutoCAD and initialize the modelspace.
|
117
|
+
|
118
|
+
Returns:
|
119
|
+
True if connection successful, False otherwise
|
120
|
+
"""
|
121
|
+
try:
|
122
|
+
self.cad_app = myAutoCAD(create_if_not_exists=False)
|
123
|
+
self.modelspace = self.cad_app.model
|
124
|
+
return True
|
125
|
+
except Exception as e:
|
126
|
+
print(f"Error: Failed to connect to AutoCAD. Details: {e}")
|
127
|
+
return False
|
128
|
+
|
129
|
+
def load_configuration(self) -> bool:
|
130
|
+
"""
|
131
|
+
Load block and patch configuration from CSV files.
|
132
|
+
|
133
|
+
Returns:
|
134
|
+
True if configuration loaded successfully, False otherwise
|
135
|
+
"""
|
136
|
+
# Load block parameters
|
137
|
+
self.block_parameters = self._load_csv_data(
|
138
|
+
self.blocks_csv_file,
|
139
|
+
['BlockID', 'CellsX', 'CellsY', 'CellsZ', 'Grading'],
|
140
|
+
'BlockID'
|
141
|
+
)
|
142
|
+
|
143
|
+
# Load patch information
|
144
|
+
self.patch_info = self._load_csv_data(
|
145
|
+
self.patches_csv_file,
|
146
|
+
['RegionName', 'PatchName', 'PatchType'],
|
147
|
+
'RegionName'
|
148
|
+
)
|
149
|
+
|
150
|
+
if not self.block_parameters or not self.patch_info:
|
151
|
+
print("Aborting due to missing or invalid configuration files.")
|
152
|
+
return False
|
153
|
+
|
154
|
+
return True
|
155
|
+
|
156
|
+
def debug_entities(self) -> None:
|
157
|
+
"""Debug method to list all entities and their XData."""
|
158
|
+
print("\n=== DEBUG: Listing all entities ===")
|
159
|
+
|
160
|
+
entity_types = {}
|
161
|
+
for entity in self.modelspace:
|
162
|
+
entity_type = entity.ObjectName
|
163
|
+
if entity_type not in entity_types:
|
164
|
+
entity_types[entity_type] = []
|
165
|
+
|
166
|
+
# Try to get XData applications
|
167
|
+
xdata_apps = self.cad_app.list_entity_xdata(entity)
|
168
|
+
entity_info = {
|
169
|
+
'handle': entity.Handle,
|
170
|
+
'xdata_apps': xdata_apps
|
171
|
+
}
|
172
|
+
entity_types[entity_type].append(entity_info)
|
173
|
+
|
174
|
+
for entity_type, entities in entity_types.items():
|
175
|
+
print(f"\n{entity_type} entities ({len(entities)}):")
|
176
|
+
for entity_info in entities:
|
177
|
+
print(f" Handle: {entity_info['handle']}")
|
178
|
+
if entity_info['xdata_apps']:
|
179
|
+
print(f" XData apps: {entity_info['xdata_apps']}")
|
180
|
+
# Show detailed XData for debugging
|
181
|
+
try:
|
182
|
+
entity = self.modelspace.HandleToObject(entity_info['handle'])
|
183
|
+
all_xdata = self.cad_app.get_xdata(entity, "")
|
184
|
+
if all_xdata:
|
185
|
+
self.cad_app.print_xdata(all_xdata)
|
186
|
+
except AttributeError:
|
187
|
+
# HandleToObject might not be available, skip detailed XData display
|
188
|
+
print(f" (Detailed XData display not available)")
|
189
|
+
else:
|
190
|
+
print(f" No XData found")
|
191
|
+
|
192
|
+
def process_solids(self) -> None:
|
193
|
+
"""Process 3DSOLID entities and extract block definitions."""
|
194
|
+
print("\nProcessing 3D Solids based on XData...")
|
195
|
+
|
196
|
+
for entity in self.modelspace:
|
197
|
+
if entity.ObjectName == 'AcDb3dSolid':
|
198
|
+
print(f" Found 3DSOLID entity: {entity.Handle}")
|
199
|
+
xdata = self.cad_app.get_xdata(entity, self.block_xdata_app_name)
|
200
|
+
if xdata is None:
|
201
|
+
print(f" No XData found for app '{self.block_xdata_app_name}'")
|
202
|
+
continue
|
203
|
+
else:
|
204
|
+
print(f" Found XData: {xdata}")
|
205
|
+
|
206
|
+
try:
|
207
|
+
# Use the new parsing method
|
208
|
+
block_data = self.cad_app.get_blockdata_from_3dsolid(entity)
|
209
|
+
if not block_data:
|
210
|
+
print(f" Could not parse block data from XData")
|
211
|
+
continue
|
212
|
+
|
213
|
+
block_id = block_data.get('block_id')
|
214
|
+
description = block_data.get('description', "")
|
215
|
+
|
216
|
+
if block_id in self.block_parameters:
|
217
|
+
props = self.block_parameters[block_id]
|
218
|
+
verts = self.cad_app.get_solid_vertices(entity)
|
219
|
+
if verts is None:
|
220
|
+
print(f" Could not extract vertices from 3DSOLID entity")
|
221
|
+
continue
|
222
|
+
vert_indices = [len(self.all_vertices) + i for i in range(len(verts))]
|
223
|
+
self.all_vertices.extend(verts)
|
224
|
+
|
225
|
+
# Create block definition
|
226
|
+
block_def = {
|
227
|
+
"id": block_id,
|
228
|
+
"vertices": tuple(vert_indices),
|
229
|
+
"cells": (int(props['CellsX']), int(props['CellsY']), int(props['CellsZ'])),
|
230
|
+
"grading": props['Grading']
|
231
|
+
}
|
232
|
+
self.block_definitions.append(block_def)
|
233
|
+
|
234
|
+
# Generate faces for patch matching
|
235
|
+
faces = self._generate_solid_faces(vert_indices)
|
236
|
+
face_coords = [np.array([self.all_vertices[i] for i in face]) for face in faces]
|
237
|
+
|
238
|
+
self.solid_data[entity.Handle] = {
|
239
|
+
"block_id": block_id,
|
240
|
+
"vertex_indices": vert_indices,
|
241
|
+
"faces_v_indices": faces,
|
242
|
+
"faces_v_coords": face_coords
|
243
|
+
}
|
244
|
+
|
245
|
+
print(f" Found and processed block with ID: '{block_id}'.")
|
246
|
+
else:
|
247
|
+
print(f" Found block ID '{block_id}' but it's not defined in '{self.blocks_csv_file}'. Skipping.")
|
248
|
+
|
249
|
+
except (IndexError, KeyError, ValueError) as e:
|
250
|
+
print(f" Error processing solid entity: {e}")
|
251
|
+
continue
|
252
|
+
|
253
|
+
def process_regions(self) -> None:
|
254
|
+
"""Process REGION entities and match them to solid faces for patches."""
|
255
|
+
print("\nProcessing Regions for patches based on XData...")
|
256
|
+
|
257
|
+
for entity in self.modelspace:
|
258
|
+
if entity.ObjectName == 'AcDbRegion':
|
259
|
+
print(f" Found REGION entity: {entity.Handle}")
|
260
|
+
xdata = self.cad_app.get_xdata(entity, self.region_xdata_app_name)
|
261
|
+
if xdata is None:
|
262
|
+
print(f" No XData found for app '{self.region_xdata_app_name}'")
|
263
|
+
continue
|
264
|
+
else:
|
265
|
+
print(f" Found XData: {xdata}")
|
266
|
+
|
267
|
+
try:
|
268
|
+
# Use the new parsing method
|
269
|
+
region_data = self.cad_app.get_regionname_from_region(entity)
|
270
|
+
if not region_data:
|
271
|
+
print(f" Could not parse region data from XData")
|
272
|
+
continue
|
273
|
+
|
274
|
+
region_name = region_data.get('region_name')
|
275
|
+
|
276
|
+
if region_name in self.patch_info:
|
277
|
+
patch_config = self.patch_info[region_name]
|
278
|
+
patch_name = patch_config['PatchName']
|
279
|
+
|
280
|
+
region_verts = self.cad_app.get_region_vertices(entity)
|
281
|
+
if region_verts is None:
|
282
|
+
print(f" Could not extract vertices from REGION entity")
|
283
|
+
continue
|
284
|
+
match_found = False
|
285
|
+
|
286
|
+
# Try to match region to a solid face
|
287
|
+
for handle, data in self.solid_data.items():
|
288
|
+
for i, solid_face_coords in enumerate(data['faces_v_coords']):
|
289
|
+
if self.cad_app.are_faces_coincident(region_verts, solid_face_coords, self.tolerance):
|
290
|
+
if patch_name not in self.patch_definitions:
|
291
|
+
self.patch_definitions[patch_name] = {
|
292
|
+
'type': patch_config['PatchType'],
|
293
|
+
'faces': []
|
294
|
+
}
|
295
|
+
self.patch_definitions[patch_name]['faces'].append(data['faces_v_indices'][i])
|
296
|
+
print(f" Matched region '{region_name}' to a face on block '{data['block_id']}' -> Patch: '{patch_name}'")
|
297
|
+
match_found = True
|
298
|
+
break
|
299
|
+
if match_found:
|
300
|
+
break
|
301
|
+
|
302
|
+
if not match_found:
|
303
|
+
print(f" WARNING: Region '{region_name}' was found but could not be matched to any solid face.")
|
304
|
+
else:
|
305
|
+
print(f" Found region '{region_name}' but it's not defined in '{self.patches_csv_file}'. Skipping.")
|
306
|
+
|
307
|
+
except (IndexError, KeyError, ValueError) as e:
|
308
|
+
print(f" Error processing region entity: {e}")
|
309
|
+
continue
|
310
|
+
|
311
|
+
def _convert_to_blockmesh_format(self) -> Tuple[List, List, List]:
|
312
|
+
"""
|
313
|
+
Convert internal data structures to BlockMeshWriter format.
|
314
|
+
|
315
|
+
Returns:
|
316
|
+
Tuple of (vertices, blocks, boundary) in BlockMeshWriter format
|
317
|
+
"""
|
318
|
+
# Convert vertices to tuple format
|
319
|
+
vertices = [tuple(v) for v in self.all_vertices]
|
320
|
+
|
321
|
+
# Convert blocks to BlockMeshWriter format
|
322
|
+
blocks = []
|
323
|
+
for block in self.block_definitions:
|
324
|
+
block_tuple = (
|
325
|
+
'hex',
|
326
|
+
list(block["vertices"]),
|
327
|
+
list(block["cells"]),
|
328
|
+
'simpleGrading', # Default grading type
|
329
|
+
[1, 1, 1] # Default grading values
|
330
|
+
)
|
331
|
+
blocks.append(block_tuple)
|
332
|
+
|
333
|
+
# Convert patches to boundary format
|
334
|
+
boundary = []
|
335
|
+
for name, data in sorted(self.patch_definitions.items()):
|
336
|
+
patch_dict = {
|
337
|
+
'name': name,
|
338
|
+
'type': data['type'],
|
339
|
+
'faces': data['faces']
|
340
|
+
}
|
341
|
+
boundary.append(patch_dict)
|
342
|
+
|
343
|
+
return vertices, blocks, boundary
|
344
|
+
|
345
|
+
def generate_blockmesh_dict(self, output_path: str = "system/blockMeshDict") -> bool:
|
346
|
+
"""
|
347
|
+
Generate the complete blockMeshDict file from CAD data.
|
348
|
+
|
349
|
+
Args:
|
350
|
+
output_path: Path where to save the blockMeshDict file
|
351
|
+
|
352
|
+
Returns:
|
353
|
+
True if generation successful, False otherwise
|
354
|
+
"""
|
355
|
+
# Ensure output directory exists
|
356
|
+
os.makedirs(os.path.dirname(output_path), exist_ok=True)
|
357
|
+
|
358
|
+
# Convert data to BlockMeshWriter format
|
359
|
+
vertices, blocks, boundary = self._convert_to_blockmesh_format()
|
360
|
+
|
361
|
+
# Create and use the BlockMeshWriter
|
362
|
+
writer = BlockMeshWriter(
|
363
|
+
file_path=output_path,
|
364
|
+
scale=1.0,
|
365
|
+
vertices=vertices,
|
366
|
+
blocks=blocks,
|
367
|
+
edges=[], # No edges for this implementation
|
368
|
+
boundary=boundary,
|
369
|
+
merge_patch_pairs=[] # No merge pairs for this implementation
|
370
|
+
)
|
371
|
+
|
372
|
+
try:
|
373
|
+
writer.write()
|
374
|
+
print(f"Successfully generated blockMeshDict at: {output_path}")
|
375
|
+
return True
|
376
|
+
except Exception as e:
|
377
|
+
print(f"Error writing blockMeshDict: {e}")
|
378
|
+
return False
|
379
|
+
|
380
|
+
def generate_zero_fields(self, output_dir: str = "0"):
|
381
|
+
"""
|
382
|
+
Generate all zero field files using config files and CSV boundary conditions.
|
383
|
+
|
384
|
+
Args:
|
385
|
+
output_dir: Directory where to write the zero field files
|
386
|
+
"""
|
387
|
+
from ..writers.zero.zero_field_factory import ZeroFieldFactory
|
388
|
+
|
389
|
+
print("\nGenerating zero field files using config + CSV boundary conditions...")
|
390
|
+
print("=" * 60)
|
391
|
+
|
392
|
+
# Create zero field factory
|
393
|
+
factory = ZeroFieldFactory(output_dir=output_dir)
|
394
|
+
|
395
|
+
# Show available fields
|
396
|
+
available_fields = factory.get_available_fields()
|
397
|
+
print("Field availability:")
|
398
|
+
for field_name, info in available_fields.items():
|
399
|
+
print(f" {field_name}: CSV={info['csv_available']}, BCs={len(info['boundary_conditions']) if info['boundary_conditions'] else 0} patches")
|
400
|
+
|
401
|
+
# Write all zero field files
|
402
|
+
written_fields = factory.write_all_fields(use_csv_boundaries=True)
|
403
|
+
|
404
|
+
print(f"Zero field files written to: {output_dir}/")
|
405
|
+
return written_fields
|
406
|
+
|
407
|
+
def process_cad_file(self, output_path: str = "system/blockMeshDict", debug: bool = False) -> bool:
|
408
|
+
"""
|
409
|
+
Complete workflow to process CAD file and generate blockMeshDict.
|
410
|
+
|
411
|
+
Args:
|
412
|
+
output_path: Path where to save the blockMeshDict file
|
413
|
+
debug: If True, show debug information about entities and XData
|
414
|
+
|
415
|
+
Returns:
|
416
|
+
True if processing successful, False otherwise
|
417
|
+
"""
|
418
|
+
# Step 1: Connect to CAD
|
419
|
+
if not self.connect_to_cad():
|
420
|
+
return False
|
421
|
+
|
422
|
+
# Step 2: Load configuration
|
423
|
+
if not self.load_configuration():
|
424
|
+
return False
|
425
|
+
|
426
|
+
# Step 2.5: Debug entities if requested
|
427
|
+
if debug:
|
428
|
+
self.debug_entities()
|
429
|
+
|
430
|
+
# Step 3: Process solids
|
431
|
+
self.process_solids()
|
432
|
+
|
433
|
+
# Step 4: Process regions
|
434
|
+
self.process_regions()
|
435
|
+
|
436
|
+
# Step 5: Generate blockMeshDict
|
437
|
+
success = self.generate_blockmesh_dict(output_path)
|
438
|
+
|
439
|
+
if success:
|
440
|
+
# Step 6: Generate zero field files
|
441
|
+
self.generate_zero_fields()
|
442
|
+
|
443
|
+
print("\n" + "="*60)
|
444
|
+
print("CAD Processing Summary:")
|
445
|
+
print("="*60)
|
446
|
+
self.get_summary()
|
447
|
+
|
448
|
+
return success
|
449
|
+
|
450
|
+
def get_summary(self) -> Dict[str, Any]:
|
451
|
+
"""
|
452
|
+
Get a summary of the processed data.
|
453
|
+
|
454
|
+
Returns:
|
455
|
+
Dictionary with processing summary
|
456
|
+
"""
|
457
|
+
return {
|
458
|
+
"total_vertices": len(self.all_vertices),
|
459
|
+
"total_blocks": len(self.block_definitions),
|
460
|
+
"total_patches": len(self.patch_definitions),
|
461
|
+
"blocks": [block["id"] for block in self.block_definitions],
|
462
|
+
"patches": list(self.patch_definitions.keys())
|
463
|
+
}
|