Skip to content

Add a feature tree #821

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 0 additions & 11 deletions doc/source/api/example_helpers.rst

This file was deleted.

26 changes: 26 additions & 0 deletions doc/source/api/extras.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
Extras
------

Example helpers
~~~~~~~~~~~~~~~

.. currentmodule:: ansys.acp.core.extras.example_helpers

.. autosummary::
:toctree: _autosummary

ExampleKeys
get_example_file
set_plot_theme


Feature tree
~~~~~~~~~~~~

.. currentmodule:: ansys.acp.core.extras.feature_tree

.. autosummary::
:toctree: _autosummary

get_feature_tree
print_feature_tree
2 changes: 1 addition & 1 deletion doc/source/api/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ API reference
other_utils
dpf_integration_helpers
mechanical_integration_helpers
example_helpers
extras
internal
{% else %}
The API reference is not available in this documentation build.
Expand Down
110 changes: 110 additions & 0 deletions doc/source/user_guide/concepts/feature_tree.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
.. _feature_tree:

Feature tree
------------

.. testsetup::

import ansys.acp.core as pyacp

acp = pyacp.launch_acp()
model = acp.import_model("../tests/data/minimal_complete_model_no_matml_link.acph5")

The following tree shows the hierarchy of PyACP objects:

.. doctest::

>>> pyacp.extras.feature_tree.print_feature_tree()
Model
├── Material
├── Fabric
├── Stackup
├── SubLaminate
├── ElementSet
├── EdgeSet
├── CADGeometry
│ └── CADComponent (read-only)
├── VirtualGeometry
├── Rosette
├── LookUpTable1D
│ └── LookUpTable1DColumn
├── LookUpTable3D
│ └── LookUpTable3DColumn
├── ParallelSelectionRule
├── CylindricalSelectionRule
├── SphericalSelectionRule
├── TubeSelectionRule
├── CutOffSelectionRule
├── GeometricalSelectionRule
├── VariableOffsetSelectionRule
├── BooleanSelectionRule
├── OrientedSelectionSet
├── ModelingGroup
│ ├── ModelingPly
│ │ └── ProductionPly (read-only)
│ │ └── AnalysisPly (read-only)
│ ├── InterfaceLayer
│ └── ButtJointSequence
├── ImportedModelingGroup
│ └── ImportedModelingPly
│ └── ImportedProductionPly (read-only)
│ └── ImportedAnalysisPly (read-only)
├── SamplingPoint
├── SectionCut
├── SolidModel
│ ├── ExtrusionGuide
│ ├── SnapToGeometry
│ ├── SolidElementSet (read-only)
│ ├── CutOffGeometry
│ ├── AnalysisPly (read-only)
│ └── InterfaceLayer (read-only)
├── ImportedSolidModel
│ ├── SolidElementSet (read-only)
│ ├── CutOffGeometry
│ ├── LayupMappingObject
│ │ ├── AnalysisPly (read-only)
│ │ └── ImportedAnalysisPly (read-only)
│ ├── AnalysisPly (read-only)
│ └── ImportedAnalysisPly (read-only)
├── Sensor
└── FieldDefinition
<BLANKLINE>


This structure determines how objects can be created, accessed, and stored in the model.


For example, :class:`.ModelingPly` is a child of :class:`.ModelingGroup`, which is a child of :class:`.Model`. To access a specific modeling ply, you can traverse this tree hierarchy:

.. doctest::

>>> model
<Model with name 'ACP Model'>
>>> model.modeling_groups
<MutableMapping[ModelingGroup] with keys ['ModelingGroup.1']>
>>> modeling_group = model.modeling_groups["ModelingGroup.1"]
>>> modeling_group.modeling_plies
<MutableMapping[ModelingPly] with keys ['ModelingPly.1']>
>>> modeling_ply = modeling_group.modeling_plies["ModelingPly.1"]
>>> modeling_ply
<ModelingPly with id 'ModelingPly.1'>

To create a new modeling ply, you can use the :meth:`.ModelingGroup.create_modeling_ply` method:

.. doctest::

>>> new_ply = modeling_group.create_modeling_ply(name="New Ply")
>>> new_ply
<ModelingPly with id 'New Ply'>

When cloning and storing a modeling ply, the ``parent`` argument must be a :class:`.ModelingGroup` object:

.. doctest::

>>> other_modeling_group = model.create_modeling_group()
>>> cloned_ply = modeling_ply.clone()
>>> cloned_ply
<ModelingPly with id ''>
>>> cloned_ply.store(parent=other_modeling_group)
>>> cloned_ply
<ModelingPly with id 'ModelingPly.2'>
1 change: 1 addition & 0 deletions doc/source/user_guide/concepts/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ These guides explain the PyACP concepts.
.. toctree::
:maxdepth: 2

feature_tree
material_property_sets
store
2 changes: 1 addition & 1 deletion doc/source/user_guide/concepts/store.rst
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ You can make changes to the unstored material, but they are lost when the Python

>>> material.density.rho = 8000

To store a material in an ACP model, call its :meth:`store <.Material.store>` method. The ``parent`` parameter determines where in the model the material is stored. In this case, the parent is the model itself.
To store a material in an ACP model, call its :meth:`store <.Material.store>` method. The ``parent`` parameter determines where in the model the material is stored. In this case, the parent is the model itself. See :ref:`feature_tree` for more information on how to determine the ``parent`` object.

.. doctest::

Expand Down
126 changes: 63 additions & 63 deletions doc/source/user_guide/howto/print_model.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,26 +22,26 @@ You can print the tree structure using the :func:`.print_model` function:

>>> pyacp.print_model(model)
'ACP Model'
Materials
'Structural Steel'
Fabrics
'Fabric.1'
Element Sets
'All_Elements'
Edge Sets
'ns_edge'
Rosettes
'Global Coordinate System'
Oriented Selection Sets
'OrientedSelectionSet.1'
Modeling Groups
'ModelingGroup.1'
Modeling Plies
'ModelingPly.1'
Production Plies
'P1__ModelingPly.1'
Analysis Plies
'P1L1__ModelingPly.1'
├── Materials
└── 'Structural Steel'
├── Fabrics
└── 'Fabric.1'
├── Element Sets
└── 'All_Elements'
├── Edge Sets
└── 'ns_edge'
├── Rosettes
└── 'Global Coordinate System'
├── Oriented Selection Sets
└── 'OrientedSelectionSet.1'
└── Modeling Groups
└── 'ModelingGroup.1'
└── Modeling Plies
└── 'ModelingPly.1'
└── Production Plies
└── 'P1__ModelingPly.1'
└── Analysis Plies
└── 'P1L1__ModelingPly.1'
<BLANKLINE>


Expand Down Expand Up @@ -70,47 +70,47 @@ The ``hide_empty`` label can be set to ``False`` to also show empty groups:

>>> pyacp.print_model(model, hide_empty=False)
'ACP Model'
Materials
'Structural Steel'
Fabrics
'Fabric.1'
Stackups
Sublaminates
Element Sets
'All_Elements'
Edge Sets
'ns_edge'
Cad Geometries
Virtual Geometries
Rosettes
'Global Coordinate System'
Lookup Tables 1d
Lookup Tables 3d
Parallel Selection Rules
Cylindrical Selection Rules
Spherical Selection Rules
Tube Selection Rules
Cut Off Selection Rules
Geometrical Selection Rules
Variable Offset Selection Rules
Boolean Selection Rules
Oriented Selection Sets
'OrientedSelectionSet.1'
Modeling Groups
'ModelingGroup.1'
Modeling Plies
'ModelingPly.1'
Production Plies
'P1__ModelingPly.1'
Analysis Plies
'P1L1__ModelingPly.1'
Interface Layers
Butt Joint Sequences
Imported Modeling Groups
Sampling Points
Section Cuts
Solid Models
Imported Solid Models
Sensors
Field Definitions
├── Materials
└── 'Structural Steel'
├── Fabrics
└── 'Fabric.1'
├── Stackups
├── Sublaminates
├── Element Sets
└── 'All_Elements'
├── Edge Sets
└── 'ns_edge'
├── Cad Geometries
├── Virtual Geometries
├── Rosettes
└── 'Global Coordinate System'
├── Lookup Tables 1d
├── Lookup Tables 3d
├── Parallel Selection Rules
├── Cylindrical Selection Rules
├── Spherical Selection Rules
├── Tube Selection Rules
├── Cut Off Selection Rules
├── Geometrical Selection Rules
├── Variable Offset Selection Rules
├── Boolean Selection Rules
├── Oriented Selection Sets
└── 'OrientedSelectionSet.1'
├── Modeling Groups
└── 'ModelingGroup.1'
├── Modeling Plies
└── 'ModelingPly.1'
└── Production Plies
└── 'P1__ModelingPly.1'
└── Analysis Plies
└── 'P1L1__ModelingPly.1'
├── Interface Layers
└── Butt Joint Sequences
├── Imported Modeling Groups
├── Sampling Points
├── Section Cuts
├── Solid Models
├── Imported Solid Models
├── Sensors
└── Field Definitions
<BLANKLINE>
53 changes: 42 additions & 11 deletions src/ansys/acp/core/_model_printer.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,16 +45,45 @@
self.label = label
self.children: list["Node"] = children if children else []

def __str__(self, level: int | None = 0) -> str:
assert level is not None
four_spaces = " "
ret = four_spaces * level + self.label + os.linesep
for child in self.children:
ret += child.__str__(level + 1)
return ret


def print_model(model: Model, *, hide_empty: bool = True) -> None:
def __str__(self) -> str:
return self._to_string(_prefix="", show_lines=True)

def _to_string(
self,
*,
show_lines: bool,
_prefix: str = "",
_is_last_child: bool = True,
_is_root: bool = True,
) -> str:
if show_lines:
elbow = "└── "
line = "│ "
tee = "├── "
empty = " "
else:
elbow = line = tee = empty = " " * 4
if _is_root:
res = _prefix + self.label + os.linesep
else:
res = _prefix + (elbow if _is_last_child else tee) + self.label + os.linesep
for i, child in enumerate(self.children):
if _is_root:
new_prefix = _prefix
elif _is_last_child:
new_prefix = _prefix + empty
else:
new_prefix = _prefix + line
res += child._to_string(
_prefix=new_prefix,
show_lines=show_lines,
_is_last_child=(i == len(self.children) - 1),
_is_root=False,
)
return res


def print_model(model: Model, *, hide_empty: bool = True, show_lines: bool = True) -> None:
"""Print a tree representation of the model.

Parameters
Expand All @@ -63,9 +92,11 @@
pyACP model
hide_empty :
Whether to hide empty collections.
show_lines :
Whether to show lines connecting the nodes.

"""
return print(get_model_tree(model, hide_empty=hide_empty))
return print(get_model_tree(model, hide_empty=hide_empty)._to_string(show_lines=show_lines))

Check warning on line 99 in src/ansys/acp/core/_model_printer.py

View check run for this annotation

Codecov / codecov/patch

src/ansys/acp/core/_model_printer.py#L99

Added line #L99 was not covered by tests


def get_model_tree(model: Model, *, hide_empty: bool = True) -> Node:
Expand Down
Loading