Skip to content

Commit

Permalink
add sensor example (#723)
Browse files Browse the repository at this point in the history
* add sensor example
  • Loading branch information
roosre authored Nov 29, 2024
1 parent ec6d153 commit 7d2e00a
Show file tree
Hide file tree
Showing 4 changed files with 190 additions and 1 deletion.
1 change: 1 addition & 0 deletions doc/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -100,3 +100,4 @@ Limitations
* Section cuts cannot be visualized.
* Sampling point analysis data is not available.
* Imported solid model mapping statistics are not available.
* Sensor by solid model is not yet supported.
173 changes: 173 additions & 0 deletions examples/modeling_features/007-sensor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
# Copyright (C) 2022 - 2024 ANSYS, Inc. and/or its affiliates.
# SPDX-License-Identifier: MIT
#
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

"""
.. _sensor_example:
Sensor
======
The :class:`.Sensor` capabilities to analyze the composite structure
is demonstrated in this example. A sensor is used to compute the weight,
area, cost, etc. of the model or specific entities such as ply material,
modeling ply, etc.
"""

# %%
# Import modules
# --------------
#
# Import the standard library and third-party dependencies.
import pathlib
import tempfile

import pyvista

# %%
# Import the PyACP dependencies.
from ansys.acp.core import SensorType, UnitSystemType, launch_acp
from ansys.acp.core.extras import RACE_CARE_NOSE_CAMERA_METER, ExampleKeys, get_example_file

# sphinx_gallery_thumbnail_number = 2


# %%
# Start ACP and load the model
# ----------------------------

# %%
# Get the example file from the server.
tempdir = tempfile.TemporaryDirectory()
WORKING_DIR = pathlib.Path(tempdir.name)
acph5_input_file = get_example_file(ExampleKeys.RACE_CAR_NOSE_ACPH5, WORKING_DIR)

# %%
# Launch the PyACP server and connect to it.
acp = launch_acp()

# %%
# Load the model from the input file which contains
# a formula 1 front wing with layup. The plot shows the total
# laminate thickness per element.
model = acp.import_model(acph5_input_file)
model.unit_system = UnitSystemType.SI
print(model.unit_system)
model.update()

thickness_data = model.elemental_data.thickness
if thickness_data is not None:
plotter = pyvista.Plotter()
plotter.add_mesh(thickness_data.get_pyvista_mesh(model.mesh), show_edges=False)
plotter.camera_position = RACE_CARE_NOSE_CAMERA_METER
plotter.show()

# %%
# Set price per area for all fabrics.
model.fabrics["UD"].area_price = 15 # $/m^2
model.fabrics["woven"].area_price = 23 # $/m^2
model.fabrics["core_4mm"].area_price = 7 # $/m^2

# %%
# Sensor by area
# --------------

# %%
# Entire Model
# ~~~~~~~~~~~~
# The first sensor is applied to the entire model to compute for example
# the total weight, area of production material, and material cost.
sensor_by_area = model.create_sensor(
name="By Area",
sensor_type=SensorType.SENSOR_BY_AREA,
entities=[model.element_sets["All_Elements"]],
)
# %%
# Update the model to compute the sensor values.
model.update()


def print_measures(my_sensor):
print(f"Price: {my_sensor.price:.2f} $")
print(f"Weight: {my_sensor.weight:.2f} kg")
print(f"Covered area: {my_sensor.covered_area:.2f} m²")
print(f"Production ply area: {my_sensor.production_ply_area:.2f} m²")
cog = my_sensor.center_of_gravity
print(f"Center of gravity: ({cog[0]:.2f}, {cog[1]:.2f}, {cog[2]:.2f}) m")


# %%
# Print the values. The ``production ply area`` is the area of production material.
print_measures(sensor_by_area)

# %%
# Scope to a specific component
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# Compute the measures for the nose only. Note that :class:`.OrientedSelectionSet`
# can also be used to scope the sensor.
eset_nose = model.element_sets["els_nose"]
sensor_by_area.entities = [eset_nose]
model.update()
print_measures(sensor_by_area)
plotter = pyvista.Plotter()
plotter.add_mesh(eset_nose.mesh.to_pyvista(), show_edges=False, opacity=1, color="turquoise")
plotter.add_mesh(model.mesh.to_pyvista(), show_edges=False, opacity=0.2)
plotter.camera_position = RACE_CARE_NOSE_CAMERA_METER
plotter.show()

# %%
# Sensor by material
# ------------------
#
# A sensor can also be used to compute the amount of a certain ply material
# (:class:`.Fabric`, :class:`.Stackup`, :class:`.SubLaminate`).
sensor_by_material = model.create_sensor(
name="By Material",
sensor_type=SensorType.SENSOR_BY_MATERIAL,
entities=[model.fabrics["UD"]],
)
print_measures(sensor_by_area)

# %%
# Sensor by ply
# -------------
#
# A sensor can also be scoped to a specific ply or a list of plies. In this example,
# a ply of the suction side and a ply of the pressure side of wing 3 are selected.
mg = model.modeling_groups["wing_3"]
modeling_plies = [
mg.modeling_plies["mp.wing_3.1_suction"],
mg.modeling_plies["mp.wing_3.1_pressure.2"],
]
sensor_by_ply = model.create_sensor(
name="By Ply",
sensor_type=SensorType.SENSOR_BY_PLIES,
entities=modeling_plies,
)
model.update()
print_measures(sensor_by_ply)
plotter = pyvista.Plotter()
for ply in modeling_plies:
plotter.add_mesh(ply.mesh.to_pyvista(), show_edges=False, opacity=1, color="turquoise")
plotter.add_mesh(model.mesh.to_pyvista(), show_edges=False, opacity=0.2)
plotter.camera_position = RACE_CARE_NOSE_CAMERA_METER
plotter.show()
2 changes: 2 additions & 0 deletions src/ansys/acp/core/extras/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from ansys.acp.core.extras.example_helpers import (
FLAT_PLATE_SHELL_CAMERA,
FLAT_PLATE_SOLID_CAMERA,
RACE_CARE_NOSE_CAMERA_METER,
ExampleKeys,
get_example_file,
)
Expand All @@ -33,4 +34,5 @@
"get_example_file",
"FLAT_PLATE_SHELL_CAMERA",
"FLAT_PLATE_SOLID_CAMERA",
"RACE_CARE_NOSE_CAMERA_METER",
]
15 changes: 14 additions & 1 deletion src/ansys/acp/core/extras/example_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,13 @@
import urllib.parse
import urllib.request

__all__ = ["ExampleKeys", "get_example_file"]
__all__ = [
"ExampleKeys",
"get_example_file",
"FLAT_PLATE_SHELL_CAMERA",
"FLAT_PLATE_SOLID_CAMERA",
"RACE_CARE_NOSE_CAMERA_METER",
]

from typing import TYPE_CHECKING

Expand All @@ -58,6 +64,13 @@
(-0.2895, 0.9160, -0.2776),
]

# Order of inputs: position, rotation point, orientation
RACE_CARE_NOSE_CAMERA_METER = [
(1.614, 1.154, 2.243),
(0.450, 0.238, -0.181),
(-0.1094, 0.9460, -0.3050),
]


@dataclasses.dataclass
class _ExampleLocation:
Expand Down

0 comments on commit 7d2e00a

Please sign in to comment.