Skip to content

Commit 5d761f0

Browse files
github-actions[bot]feilin-flexcomputebenflexcomputeyifan-flex
authored
Scheduled sync: main → develop (#1373)
* allow n_edge=0 (#1371) * [FXC-2300] Improved error message when using legacy output field names (#1366) (#1367) Co-authored-by: Ben <106089368+benflexcompute@users.noreply.github.com> * [FXC-2301] Fixed the translator not recursively finding solver variable names (#1365) (#1368) Co-authored-by: Ben <106089368+benflexcompute@users.noreply.github.com> * [FXC-1749] make isentropic compressible solve on by default for liquid (#1369) * [FXC-1749] make isentropic compressible solve on by default for liquidOperatingCondition * Fix unit test * Change implementation * [FXC-342] [FXC-343] Add output classes for imported surfaces (#1352) * Add output for imported surfaces * Add docstrings * Address PR comments * Add TimeAverageImportedSurfaceOutput to time-average types --------- Co-authored-by: Feilin <52168719+feilin-flexcompute@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Ben <106089368+benflexcompute@users.noreply.github.com> Co-authored-by: yifan-flex <124317394+yifan-flex@users.noreply.github.com>
1 parent daf7c95 commit 5d761f0

16 files changed

+665
-75
lines changed

flow360/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,8 @@
112112
)
113113
from flow360.component.simulation.outputs.outputs import (
114114
AeroAcousticOutput,
115+
ImportedSurfaceIntegralOutput,
116+
ImportedSurfaceOutput,
115117
IsosurfaceOutput,
116118
Observer,
117119
ProbeOutput,
@@ -121,6 +123,7 @@
121123
SurfaceOutput,
122124
SurfaceProbeOutput,
123125
SurfaceSliceOutput,
126+
TimeAverageImportedSurfaceOutput,
124127
TimeAverageIsosurfaceOutput,
125128
TimeAverageProbeOutput,
126129
TimeAverageSliceOutput,
@@ -231,6 +234,9 @@
231234
"ProbeOutput",
232235
"SurfaceProbeOutput",
233236
"AeroAcousticOutput",
237+
"ImportedSurfaceOutput",
238+
"TimeAverageImportedSurfaceOutput",
239+
"ImportedSurfaceIntegralOutput",
234240
"Observer",
235241
"HeatEquationSolver",
236242
"NavierStokesSolver",

flow360/component/simulation/entity_info.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -370,15 +370,16 @@ def get_registry(self, internal_registry, **_) -> EntityRegistry:
370370
"face", face_group_tag, registry=internal_registry
371371
)
372372

373-
if self.edge_group_tag is None:
374-
edge_group_tag = self._get_default_grouping_tag("edge")
375-
log.info(f"Using `{edge_group_tag}` as default grouping for edges.")
376-
else:
377-
edge_group_tag = self.edge_group_tag
373+
if len(self.edge_ids) > 0:
374+
if self.edge_group_tag is None:
375+
edge_group_tag = self._get_default_grouping_tag("edge")
376+
log.info(f"Using `{edge_group_tag}` as default grouping for edges.")
377+
else:
378+
edge_group_tag = self.edge_group_tag
378379

379-
internal_registry = self._group_entity_by_tag(
380-
"edge", edge_group_tag, registry=internal_registry
381-
)
380+
internal_registry = self._group_entity_by_tag(
381+
"edge", edge_group_tag, registry=internal_registry
382+
)
382383

383384
if self.body_attribute_names:
384385
# Post-25.5 geometry asset. For Pre 25.5 we just skip body grouping.

flow360/component/simulation/outputs/outputs.py

Lines changed: 114 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
GhostCircularPlane,
3939
GhostSphere,
4040
GhostSurface,
41+
ImportedSurface,
4142
Surface,
4243
)
4344
from flow360.component.simulation.unit_system import LengthType
@@ -134,7 +135,7 @@ def _validate_improper_surface_field_usage(cls, value: UniqueItemList):
134135
):
135136
continue
136137
surface_solver_variable_names = output_item.value.solver_variable_names(
137-
variable_type="Surface"
138+
recursive=True, variable_type="Surface"
138139
)
139140
if len(surface_solver_variable_names) > 0:
140141
raise ValueError(
@@ -1101,6 +1102,114 @@ class StreamlineOutput(Flow360BaseModel):
11011102
output_type: Literal["StreamlineOutput"] = pd.Field("StreamlineOutput", frozen=True)
11021103

11031104

1105+
class ImportedSurfaceOutput(_AnimationAndFileFormatSettings):
1106+
"""
1107+
:class:`ImportedSurfaceOutput` class for generating interpolated output on imported surfaces.
1108+
1109+
Example
1110+
-------
1111+
>>> fl.ImportedSurfaceOutput(
1112+
... name="Jet_cross_sections_output",
1113+
... entities=[
1114+
... geometry.imported_surfaces["*"],
1115+
... ],
1116+
... output_fields=[
1117+
... fl.solution.Cp,
1118+
... ]
1119+
... )
1120+
1121+
====
1122+
"""
1123+
1124+
name: Optional[str] = pd.Field(
1125+
"Imported surface output", description="Name of the `ImportedSurfaceOutput`."
1126+
)
1127+
entities: EntityList[ImportedSurface] = pd.Field(
1128+
alias="surfaces",
1129+
description="List of imported surfaces where output is generated.",
1130+
)
1131+
output_fields: UniqueItemList[UserVariable] = pd.Field(description="List of output variables.")
1132+
output_type: Literal["ImportedSurfaceOutput"] = pd.Field("ImportedSurfaceOutput", frozen=True)
1133+
1134+
1135+
class TimeAverageImportedSurfaceOutput(ImportedSurfaceOutput):
1136+
"""
1137+
:class:`TimeAverageImportedSurfaceOutput` class for generating **time-averaged**
1138+
output on imported surfaces.
1139+
1140+
Similar to :class:`ImportedSurfaceOutput`, this output type records user-specified
1141+
variables on imported geometry surfaces, but instead of instantaneous values,
1142+
it computes averages over a specified range of physical time steps.
1143+
1144+
Example
1145+
-------
1146+
>>> fl.TimeAverageImportedSurfaceOutput(
1147+
... name="Jet_cross_sections_output",
1148+
... entities=[
1149+
... geometry.imported_surfaces["*"],
1150+
... ],
1151+
... output_fields=[
1152+
... fl.solution.Cp,
1153+
... ],
1154+
... start_step=2000
1155+
... )
1156+
1157+
====
1158+
"""
1159+
1160+
name: Optional[str] = pd.Field(
1161+
"Time average imported surface output",
1162+
description="Name of the `TimeAverageImportedSurfaceOutput`.",
1163+
)
1164+
start_step: Union[pd.NonNegativeInt, Literal[-1]] = pd.Field(
1165+
default=-1, description="Physical time step to start calculating averaging"
1166+
)
1167+
output_type: Literal["TimeAverageImportedSurfaceOutput"] = pd.Field(
1168+
"TimeAverageImportedSurfaceOutput", frozen=True
1169+
)
1170+
1171+
1172+
class ImportedSurfaceIntegralOutput(_OutputBase):
1173+
"""
1174+
:class:`ImportedSurfaceIntegralOutput` class for computing integrals of
1175+
user-specified variables over imported surfaces.
1176+
Integrals are computed for each of the individual surfaces.
1177+
1178+
Example
1179+
-------
1180+
Define a :class:`ImportedSurfaceIntegralOutput` to compute the integrated
1181+
mass flow rate across an imported cross-section plane
1182+
placed downstream of a nozzle. These planes are provided only for
1183+
post-processing and are not part of the simulated mesh boundaries.
1184+
1185+
>>> fl.ImportedSurfaceIntegralOutput(
1186+
... name="Nozzle_exit_planes_integrals",
1187+
... entities=[
1188+
... geometry.imported_surfaces["*"],
1189+
... ],
1190+
... output_fields=[
1191+
... fl.UserVariable(
1192+
... name="MassFlowRate",
1193+
... value=fl.solution.density
1194+
... * fl.math.dot(fl.solution.velocity, fl.solution.node_unit_normal)
1195+
... ),
1196+
... ]
1197+
... )
1198+
1199+
====
1200+
"""
1201+
1202+
name: str = pd.Field("Imported surface integral output", description="Name of integral.")
1203+
entities: EntityList[ImportedSurface] = pd.Field(
1204+
alias="surfaces",
1205+
description="List of boundaries where the surface integral will be calculated.",
1206+
)
1207+
output_fields: UniqueItemList[UserVariable] = pd.Field(description="List of output variables.")
1208+
output_type: Literal["ImportedSurfaceIntegralOutput"] = pd.Field(
1209+
"ImportedSurfaceIntegralOutput", frozen=True
1210+
)
1211+
1212+
11041213
OutputTypes = Annotated[
11051214
Union[
11061215
SurfaceOutput,
@@ -1119,6 +1228,9 @@ class StreamlineOutput(Flow360BaseModel):
11191228
TimeAverageSurfaceProbeOutput,
11201229
AeroAcousticOutput,
11211230
StreamlineOutput,
1231+
ImportedSurfaceOutput,
1232+
TimeAverageImportedSurfaceOutput,
1233+
ImportedSurfaceIntegralOutput,
11221234
],
11231235
pd.Field(discriminator="output_type"),
11241236
]
@@ -1130,4 +1242,5 @@ class StreamlineOutput(Flow360BaseModel):
11301242
TimeAverageIsosurfaceOutput,
11311243
TimeAverageProbeOutput,
11321244
TimeAverageSurfaceProbeOutput,
1245+
TimeAverageImportedSurfaceOutput,
11331246
)

flow360/component/simulation/primitives.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -574,6 +574,17 @@ def _will_be_deleted_by_mesher(self, farfield_method: Literal["auto", "quasi-3d"
574574
raise ValueError(f"Unknown auto farfield generation method: {farfield_method}.")
575575

576576

577+
@final
578+
class ImportedSurface(EntityBase):
579+
"""ImportedSurface for post-processing"""
580+
581+
private_attribute_registry_bucket_name: Literal["SurfaceEntityType"] = "SurfaceEntityType"
582+
private_attribute_entity_type_name: Literal["ImportedSurface"] = pd.Field(
583+
"ImportedSurface", frozen=True
584+
)
585+
file_name: str
586+
587+
577588
class GhostSurface(_SurfaceEntityBase):
578589
"""
579590
Represents a boundary surface that may or may not be generated therefore may or may not exist.

0 commit comments

Comments
 (0)