Compute a projected reference area#
This example previews the projected silhouette area of selected Geometry
surfaces and records an automatic projected-area recipe in
SimulationParams.
import flow360 as fl
project = fl.Project.from_cloud("PROJECT_ID_HERE")
geometry = project.geometry
with fl.create_draft(
new_run_from=geometry,
face_grouping="face_grouping_tag",
) as draft:
wing_surfaces = draft.surfaces["wing_*"]
# Compute a concrete preview immediately.
preview_area = fl.measure.projected_area(
draft,
surfaces=wing_surfaces,
direction="Z",
)
print("projected area:", preview_area)
# Store an automatic recipe in the simulation parameters. Submission from
# this active draft recomputes the value before validation and upload.
with fl.SI_unit_system:
params = fl.SimulationParams(
reference_geometry=fl.ReferenceGeometry(
area=fl.ProjectedArea(
surfaces=wing_surfaces,
direction="Z",
)
)
)
# Configure the remaining simulation parameters and submit within this
# draft context so the selected geometry and tessellation remain available.
Behavior#
fl.measure.projected_area(...)computes immediately and returns a concrete project-length-unit-squared value. It does not modifySimulationParams.Assigning
fl.ProjectedArea(...)toReferenceGeometry.arearecords the automatic recipe. Python and the Web user interface recompute its output-onlycomputedvalue before submission.Submission must occur while the Geometry-root draft context that owns the selected surfaces is active. Surface-mesh and volume-mesh drafts do not carry the required tessellation data.
The uploaded simulation JSON retains both the recipe and the latest
computedvalue, allowing automatic behavior to survive Web user interface and Python round trips.Coordinate-system rotation and scale are applied before projection.
Approximation#
The calculation rasterizes the union of projected triangle coverage. Overlapping front and back surfaces are counted once. Projected bounds define the raster frame; their bounding-box area is not used as the result.
Because whole pixels are counted, the result carries a discretization error proportional to pixel size, with an essentially random sign rather than a consistent bias. It is largest for small features measured inside a large bounding box, and for straight edges that happen to fall between pixel centres; curved silhouettes average out considerably better. At the default settings expect on the order of 0.1%, so treat a difference of that size between two measurements of the same geometry as expected rather than as a defect.
New Python code should use ProjectedArea for automatic behavior and must not
write the legacy Web user interface field private_attribute_area_settings.
Half-body domains#
With domain_type="half_body_positive_y" or "half_body_negative_y", the
recipe measures only the half that is actually meshed, trimming the tessellation
at Y=0. Do not apply a 0.5 factor of your own: the trim is derived from
the finalized meshing settings, so it is already correct whether the uploaded
geometry is a full model or a single half. Projection along Y is unaffected.
fl.measure.projected_area has no such awareness – it measures the surfaces as
given – which is the main reason to prefer the recipe for a reference area.
Confirming the selection#
Selectors that match nothing raise no error, so a missed surface shows up only as
a reference area that is quietly too small. draft.preview_unselected(...)
lists every surface the selection does not cover, which makes the omission
visible before submission:
missed = draft.preview_unselected(projected_area_surfaces)
if missed:
raise ValueError(f"No selector covers: {missed}")
Surfaces intentionally excluded – wind tunnel walls, for example – appear in that list and are expected there.