Skip to content

[FXC-5449] allow varying refinements on axisymmetric body faces#1882

Open
alexxu-flex wants to merge 14 commits intomainfrom
alexxu/varying-refinement-faces
Open

[FXC-5449] allow varying refinements on axisymmetric body faces#1882
alexxu-flex wants to merge 14 commits intomainfrom
alexxu/varying-refinement-faces

Conversation

@alexxu-flex
Copy link
Copy Markdown
Collaborator

@alexxu-flex alexxu-flex commented Mar 9, 2026

Note

Medium Risk
Medium risk because it changes meshing parameter validation and translation output for UniformRefinement, which could alter generated volume-meshing JSON for axisymmetric cases. Scope is localized and covered by new unit/translator tests.

Overview
Enables per-face uniform refinement spacing overrides on AxisymmetricBody via UniformRefinement.face_spacing, keyed by body.face(i) and validated against the refinement’s entities and profile-curve face count.

Introduces a new immutable Face reference type and AxisymmetricBody.face() helper, updates preprocessing to recursively unit-convert values inside nested dicts as well as lists, and extends the volume-meshing translator to emit dense faceSpacings arrays for axisymmetric refinements (with round-trip serialization tests).

Written by Cursor Bugbot for commit 200f6b4. This will update automatically on new commits. Configure here.

@alexxu-flex alexxu-flex marked this pull request as ready for review March 11, 2026 20:01
... entities=[cylinder, box, axisymmetric_body, sphere],
... spacing=1*fl.u.cm
... spacing=1*fl.u.cm,
... face_spacing={
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is too nested and confusing. We need to redesign the interface.

Copy link
Copy Markdown
Collaborator Author

@alexxu-flex alexxu-flex Mar 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

//User interface
face_spacing={
axisymmetric_body.segments[1] : 0.2*fl.u.cm
}
// Storage side
"face_spacing":{
("entioty_id":"$axisymmetric_body.private_attribute_id", "segment_index": 1) : {"value": 0.2, "units":"cm"}
}

Copy link
Copy Markdown
Collaborator Author

@alexxu-flex alexxu-flex Mar 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then you need a Pydantic model for the "segment" class.

It will be similar relationship between Windtunnel farfield and the windtunnel ghost surfaces.

class Segment(BaseModel):
    type_name:Literal["Segment"]
    entity_id:str
    segment_index: int =pd.Field(min=..., )

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 3 potential issues.

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

for key, val in value.items():
if isinstance(key, Face):
result.setdefault(key.entity_name, {})[key.index] = val
elif isinstance(key, str) and isinstance(val, dict):
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Face overrides lose entity identity

Medium Severity

face_spacing converts Face keys using only entity_name, dropping Face.entity_id. This makes overrides ambiguous when multiple AxisymmetricBody objects share a name, and stale Face references from a different entity with the same name are silently accepted. Translation then applies spacing by name, so overrides can target the wrong body.

Additional Locations (2)
Fix in Cursor Fix in Web

for entity in self.entities.stored_entities:
if isinstance(entity, AxisymmetricBody):
entity_map[entity.name] = entity

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Selector entities rejected in face spacing validation

Medium Severity

check_face_spacing builds entity_map from self.entities.stored_entities only. When UniformRefinement.entities is provided via selectors, stored_entities can be empty before expansion, so valid face_spacing entries are rejected as “not an AxisymmetricBody in this refinement’s entities list.”

Fix in Cursor Fix in Web

elif isinstance(key, str) and isinstance(val, dict):
# Already in {name: {idx: spacing}} format (e.g., from JSON deserialization)
result[key] = {int(k): v for k, v in val.items()}
else:
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mixed key formats drop face overrides

Low Severity

_convert_face_spacing silently overwrites entries when face_spacing mixes Face keys and serialized string keys for the same entity. The str branch assigns result[key] = ..., replacing previously accumulated per-face values from Face keys, so some overrides are lost without validation errors.

Additional Locations (1)
Fix in Cursor Fix in Web



@final
class Face(pd.BaseModel):
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Face will be reserved for geometry concepts. It is a reserved word.

"profile_curve[i] and profile_curve[i+1]. Faces without overrides use the default `spacing`.",
)

@pd.field_validator("face_spacing", mode="before")
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's not use before validators unless really necessary.

Why don't we do this instead?

    face_spacing: Optional[Dict[AxisSymmetricSegment, LengthType.Positive]] = pd.Field(

And then we have:

class AxisSymmetricSegment(Flow360BaseModel):
    entity_id: str
    segment_index: pd.PositiveInt

so the axisymmetric_body.face(2) returns an AxisSymmetricSegment instance?

Then we do not need this complicate and fragile before validator?


return self

@pd.model_validator(mode="after")
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make this a contextual validator. You can then retrieve the axisymmetric body instance by querying the entity registry.

Take a look at param_info.get_entity_registry() and registry.find_by_type_name_and_id()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants