-
Notifications
You must be signed in to change notification settings - Fork 9
Support multi-point SeedpointVolume across volume/surface translators and GAI seed points #1982
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -164,6 +164,25 @@ def _collect_all_custom_volumes(zones): | |
| return custom_volumes | ||
|
|
||
|
|
||
| def _collect_all_seedpoint_volumes(zones): | ||
| """Collect all SeedpointVolume instances from CustomZones.""" | ||
| seedpoint_volumes: list[SeedpointVolume] = [] | ||
| for zone in zones: | ||
| if isinstance(zone, CustomZones): | ||
| for volume in zone.entities.stored_entities: | ||
| if isinstance(volume, SeedpointVolume): | ||
| seedpoint_volumes.append(volume) | ||
| return seedpoint_volumes | ||
|
|
||
|
|
||
| def _validate_seedpoint_volume_usage(seedpoint_volumes, param_info: ParamsValidationInfo): | ||
| """Validate SeedpointVolume usage against mesher capabilities.""" | ||
| if seedpoint_volumes and not (param_info.use_snappy or param_info.is_beta_mesher): | ||
| raise ValueError( | ||
| "`SeedpointVolume` is supported only when using snappyHexMeshing or the beta mesher." | ||
| ) | ||
|
|
||
|
|
||
| def _validate_custom_volume_rotation_association(custom_volumes, rotation_entity_names, param_info): | ||
| """Validate that Cylinder/AxisymmetricBody/Sphere in CustomVolume.bounding_entities | ||
| are associated with a RotationVolume or RotationSphere.""" | ||
|
|
@@ -369,6 +388,16 @@ def _check_volume_zones_have_unique_names(cls, v): | |
|
|
||
| return v | ||
|
|
||
| @contextual_model_validator(mode="after") | ||
| def _check_seedpoint_volume_usage(self, param_info: ParamsValidationInfo): | ||
| """Validate SeedpointVolume usage in legacy meshing schema.""" | ||
| if self.volume_zones is None: | ||
| return self | ||
| _validate_seedpoint_volume_usage( | ||
| _collect_all_seedpoint_volumes(self.volume_zones), param_info | ||
| ) | ||
| return self | ||
|
|
||
| @contextual_model_validator(mode="after") | ||
| def _check_no_reused_volume_entities(self) -> Self: | ||
| """ | ||
|
|
@@ -725,10 +754,12 @@ def _check_snappy_zones(self) -> Self: | |
| "snappyHexMeshing requires at least one `SeedpointVolume` when not using `AutomatedFarfield`." | ||
| ) | ||
|
|
||
| else: | ||
| if total_seedpoint_volumes: | ||
| raise ValueError("`SeedpointVolume` is applicable only with snappyHexMeshing.") | ||
| return self | ||
|
|
||
| @contextual_model_validator(mode="after") | ||
| def _check_seedpoint_volume_usage(self, param_info: ParamsValidationInfo): | ||
| """Validate SeedpointVolume usage in modular meshing schema.""" | ||
| _validate_seedpoint_volume_usage(_collect_all_seedpoint_volumes(self.zones), param_info) | ||
| return self | ||
|
Comment on lines
+759
to
763
|
||
|
|
||
| @contextual_model_validator(mode="after") | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -1041,7 +1041,7 @@ def __getitem__(self, key: str): | |||||
| @final | ||||||
| class SeedpointVolume(_VolumeEntityBase): | ||||||
| """ | ||||||
| Represents a separate zone in the mesh, defined by a point inside it. | ||||||
| Represents a separate zone in the mesh, defined by one or more interior seed points. | ||||||
| To be used only with snappyHexMesh. | ||||||
|
||||||
| To be used only with snappyHexMesh. | |
| To be used with snappyHexMeshing or the beta mesher. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -572,10 +572,18 @@ def snappy_mesher_json(input_params: SimulationParams): | |
|
|
||
| # points in mesh | ||
| if all_seedpoint_zones and translated["cadIsFluid"]: | ||
| translated["locationInMesh"] = { | ||
| zone.name: [point.value.item() for point in zone.point_in_mesh] | ||
| for zone in all_seedpoint_zones | ||
| } | ||
| location_in_mesh = {} | ||
| for zone in all_seedpoint_zones: | ||
| if len(zone.point_in_mesh) != 1: | ||
| raise Flow360TranslationError( | ||
| f"SeedpointVolume '{zone.name}' must provide exactly one point for " | ||
| + "snappyHexMeshing locationInMesh.", | ||
| zone.point_in_mesh, | ||
| ["meshing", "zones"], | ||
| ) | ||
| location_in_mesh[zone.name] = [point.value.item() for point in zone.point_in_mesh[0]] | ||
|
|
||
| translated["locationInMesh"] = location_in_mesh | ||
|
|
||
| return translated | ||
|
|
||
|
|
@@ -692,6 +700,27 @@ def _get_volume_zones(volume_zones_list: list[dict]): | |
| return volume_zones_translated | ||
|
|
||
|
|
||
| def _get_gai_seed_points(input_params: SimulationParams) -> list[list[float]]: | ||
| """Collect all SeedpointVolume points for GAI defaults.seed_points.""" | ||
| volume_zones = getattr(input_params.meshing, "volume_zones", None) | ||
| if volume_zones is None: | ||
| volume_zones = getattr(input_params.meshing, "zones", None) | ||
| if volume_zones is None: | ||
| return [] | ||
|
|
||
| seed_points: list[list[float]] = [] | ||
| for zone in volume_zones: | ||
| if not isinstance(zone, CustomZones): | ||
| continue | ||
| for entity in zone.entities.stored_entities: | ||
| if not isinstance(entity, SeedpointVolume): | ||
| continue | ||
| seed_points.extend( | ||
| [[coord.value.item() for coord in point] for point in entity.point_in_mesh] | ||
| ) | ||
| return seed_points | ||
|
|
||
|
|
||
| def _filter_mirror_status(data): | ||
| """Process mirror_status to ensure idempotency while preserving mirroring relationships. | ||
|
|
||
|
|
@@ -803,6 +832,7 @@ def _get_gai_setting_whitelist(input_params: SimulationParams) -> dict: | |
| "remove_hidden_geometry": None, | ||
| "min_passage_size": None, | ||
| "planar_face_tolerance": None, | ||
| "seed_points": None, | ||
| } | ||
|
Comment on lines
832
to
836
|
||
|
|
||
| # Conditionally add sliding_interface_tolerance only when rotation zones are present | ||
|
|
@@ -967,6 +997,10 @@ def filter_simulation_json(input_params: SimulationParams, mesh_units): | |
| json_data=json_data, input_params=input_params, mesh_unit=mesh_units | ||
| ) | ||
|
|
||
| seed_points = _get_gai_seed_points(input_params) | ||
| if seed_points: | ||
| json_data.setdefault("meshing", {}).setdefault("defaults", {})["seed_points"] = seed_points | ||
|
|
||
| # Generate whitelist based on simulation context | ||
| whitelist = _get_gai_setting_whitelist(input_params) | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Validation regression: unconditional check replaced with context-dependent one
Medium Severity
The old
_check_snappy_zoneselsebranch unconditionally rejectedSeedpointVolumewith non-snappy meshers (plain@pd.model_validator). The replacement_check_seedpoint_volume_usageis a@contextual_model_validatorthat only runs when aParamsValidationInfocontext is provided. When aModularMeshingWorkflowis constructed without a validation context (e.g., in notebooks or scripts),SeedpointVolumeentries paired with a non-snappy, non-beta mesher will silently pass validation instead of raising an error.Additional Locations (1)
flow360/component/simulation/meshing_param/params.py#L733-L757Reviewed by Cursor Bugbot for commit 3413d3c. Configure here.