Skip to content

Commit f57d6c8

Browse files
authored
Plot fixes, operators helpers updated (#11)
1 parent 4d019b7 commit f57d6c8

22 files changed

+445
-427
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
#ansys/dpf/core
1313
/ansys/dpf/core/__pycache__
1414

15+
#operators
16+
/ansys/dpf/core/operators/__pycache__
17+
1518
#other
1619
/perso
1720
/examples/.ipynb_checkpoints

ansys/dpf/core/__init__.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,10 @@
2323
_global_channel, connect_to_server)
2424
from ansys.dpf.core.data_sources import DataSources
2525
from ansys.dpf.core.scoping import Scoping
26-
from ansys.dpf.core.common import types, natures, field_from_array, locations
26+
from ansys.dpf.core.common import types, natures, field_from_array, locations, ShellLayers
2727
from ansys.dpf.core.core import BaseService
2828
from ansys.dpf.core.time_freq_support import TimeFreqSupport
29-
from ansys.dpf.core.operators import sum, to_nodal, norm, eqv
29+
from ansys.dpf.core.operators_helper import sum, to_nodal, norm, eqv
3030
from ansys.dpf.core.meshed_region import MeshedRegion
3131
from ansys.dpf.core.result_info import ResultInfo
3232
from ansys.dpf.core.collection import Collection

ansys/dpf/core/common.py

+11-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,17 @@ class locations:
5858

5959
#applies everywhere
6060
overall = "overall"
61-
61+
62+
63+
class ShellLayers(Enum):
64+
"""Contains shell layers types."""
65+
TOP = 0
66+
BOTTOM = 1
67+
TOPBOTTOM = 2
68+
MID = 3
69+
TOPBOTTOMMID = 4
70+
NONELAYER = 5
71+
INDEPENDANTLAYER = 6
6272

6373

6474
def field_from_array(arr):

ansys/dpf/core/dpf_operator.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from ansys.grpc.dpf import operator_pb2, operator_pb2_grpc, base_pb2
77
from ansys.dpf.core import (fields_container, field, scoping,
88
meshed_region, result_info, time_freq_support,
9-
operators, collection, data_sources, server)
9+
operators_helper, collection, data_sources, server)
1010
from ansys.dpf.core.common import types, camel_to_snake_case
1111
from ansys.dpf.core.inputs import Inputs
1212
from ansys.dpf.core.outputs import Outputs

ansys/dpf/core/field.py

+49-35
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44

55
from ansys import dpf
66
from ansys.grpc.dpf import field_pb2, field_pb2_grpc, base_pb2, field_definition_pb2, field_definition_pb2_grpc
7-
from ansys.dpf.core.common import natures, types, locations
8-
from ansys.dpf.core import operators, plotting, scoping, meshed_region, time_freq_support
9-
7+
from ansys.dpf.core.common import natures, types, locations, ShellLayers
8+
from ansys.dpf.core import operators_helper, scoping, meshed_region, time_freq_support
9+
from ansys.dpf.core.plotter import Plotter
1010

1111
class Field:
1212
"""Class representing evaluated data from a ``ansys.dpf.core.Operator``.
@@ -74,9 +74,10 @@ def __init__(self, nentities=0,
7474
raise TypeError(f'Cannot create a field from a "{type(field)}" object')
7575

7676
self._field_definition = self._load_field_definition()
77-
77+
7878
# add dynamic methods
7979
self._update_dynamic_methods()
80+
8081

8182
@property
8283
def size(self):
@@ -98,38 +99,12 @@ def elementary_data_shape(self):
9899
return (1, self.component_count)
99100
else :
100101
return self.component_count
101-
102+
102103
def _update_dynamic_methods(self):
103104
"""Add or remove dynamic methods to this instance based on the
104105
field type"""
105106
if self.location in [locations.elemental_nodal, locations.elemental]:
106107
self.to_nodal = self.__to_nodal
107-
108-
# specify plot method based on field type
109-
if self.location == locations.elemental:
110-
self.plot = self.__plot_elemental
111-
elif self.location in [locations.nodal, locations.elemental_nodal]:
112-
self.plot = self.__plot_nodal
113-
self.plot = self.__plot_lines
114-
115-
116-
@wraps(plotting.plot_lines)
117-
def __plot_lines(self, *args, **kwargs):
118-
"""Wraps plotting.plot_lines"""
119-
return plotting.plot_lines(self, *args, **kwargs)
120-
121-
@wraps(plotting.plot_nodal)
122-
def __plot_nodal(self, comp=None, **kwargs):
123-
"""wraps plotting.plot_nodal"""
124-
return plotting.plot_nodal(self, comp, **kwargs)
125-
126-
@wraps(plotting.plot_elemental)
127-
def __plot_elemental(self, comp=None, **kwargs):
128-
"""wraps plotting.plot_elemental
129-
130-
Should be only available when type == locations.elemental
131-
"""
132-
return plotting.plot_elemental(self, comp, **kwargs)
133108

134109
@property
135110
def location(self):
@@ -142,12 +117,46 @@ def location(self):
142117
if self._field_definition:
143118
return self._field_definition.location
144119

120+
@property
121+
def shell_layers(self):
122+
"""Return the field shell layers.
123+
124+
Returns
125+
-------
126+
Enum
127+
dpf.core.common.ShellLayers enum value
128+
"""
129+
if self._field_definition:
130+
return self._field_definition.shell_layers
131+
145132
def __to_nodal(self):
146133
"""create a to_nodal operator and evaluates it"""
147134
op = dpf.core.Operator("to_nodal")
148135
op.inputs.connect(self)
149136
return op.outputs.field()
150137

138+
def plot(self, notebook = None, shell_layers = None):
139+
"""Plot the field/fields container on mesh support if exists.
140+
141+
Warning
142+
-------
143+
Regarding the interactions with the GRPc server, this can be slower than:
144+
>>> mesh = model.metadata.meshed_region
145+
>>> mesh.plot(field)
146+
Better use the previous lines.
147+
148+
Parameters
149+
----------
150+
notebook (default: True)
151+
bool, that specifies if the plotting is in the notebook (2D) or not (3D)
152+
153+
shell_layers : core.ShellLayers, optional
154+
Enum used to set the shell layers if the model to plot
155+
contains shell elements.
156+
"""
157+
pl = Plotter(self.meshed_region)
158+
pl.plot_contour(self, notebook, shell_layers)
159+
151160
def resize(self, nentities, datasize):
152161
"""allocate memory
153162
@@ -392,12 +401,12 @@ def component_count(self):
392401

393402
def __add__(self, field_b):
394403
"""Adds two fields together"""
395-
return dpf.core.operators.add(self, field_b)
404+
return dpf.core.operators_helper.add(self, field_b)
396405

397406
def __pow__(self, value):
398407
if value != 2:
399408
raise ValueError('DPF only the value is "2" suppported')
400-
return dpf.core.operators.sqr(self)
409+
return dpf.core.operators_helper.sqr(self)
401410

402411
def _del_data(self):
403412
pass
@@ -442,9 +451,9 @@ def __len__(self):
442451
return self.size
443452

444453

445-
@wraps(operators.min_max)
454+
@wraps(operators_helper.min_max)
446455
def _min_max(self):
447-
return operators.min_max(self)
456+
return operators_helper.min_max(self)
448457

449458
def min(self):
450459
"""Component-wise minimum over this field
@@ -487,6 +496,11 @@ def location(self):
487496
@property
488497
def unit(self):
489498
return self._stub.List(self._messageDefinition).unit.symbol
499+
500+
@property
501+
def shell_layers(self):
502+
enum_val = self._stub.List(self._messageDefinition).shell_layers
503+
return ShellLayers(enum_val)
490504

491505
def __del__(self):
492506
try:

ansys/dpf/core/meshed_region.py

+47-18
Original file line numberDiff line numberDiff line change
@@ -172,30 +172,26 @@ def grid(self):
172172
self._full_grid = self._as_vtk()
173173
return self._full_grid
174174

175-
def plot(self, field_or_fields_container=None, is3dplotting=False):
175+
def plot(self, field_or_fields_container=None, notebook=None, shell_layers=None):
176176
"""Plot the field/fields container on mesh.
177177
178178
Parameters
179179
----------
180180
field_or_fields_container
181181
dpf.core.Field or dpf.core.FieldsContainer
182182
183-
is3dplotting (default: False)
184-
bool, that specifies if the plotting is 3D or not
183+
notebook (default: None)
184+
bool, that specifies if the plotting is in the notebook (2D) or not (3D)
185+
186+
shell_layers : core.ShellLayers, optional
187+
Enum used to set the shell layers if the model to plot
188+
contains shell elements.
185189
"""
186190
pl = _DpfPlotter(self)
187-
if isinstance(field_or_fields_container, dpf.core.Field) or isinstance(field_or_fields_container, dpf.core.FieldsContainer):
188-
fields_container = None
189-
if isinstance(field_or_fields_container, dpf.core.Field):
190-
fields_container = dpf.core.FieldsContainer()
191-
fields_container.add_label('time')
192-
fields_container.add_field({'time':1}, field_or_fields_container)
193-
elif isinstance(field_or_fields_container, dpf.core.FieldsContainer):
194-
fields_container = field_or_fields_container
195-
pl.plot_contour(fields_container, not is3dplotting)
196-
elif(field_or_fields_container is None):
197-
pl.plot_mesh(not is3dplotting)
198-
191+
if field_or_fields_container is not None:
192+
pl.plot_contour(field_or_fields_container, notebook, shell_layers)
193+
else:
194+
pl.plot_mesh(notebook)
199195

200196

201197
class Node:
@@ -303,9 +299,9 @@ def _get_element_shape(self):
303299

304300
class Nodes():
305301
"""Class to encapsulate mesh nodes"""
306-
307302
def __init__(self, mesh):
308303
self._mesh = mesh
304+
self._mapping_id_to_index = None
309305

310306
def __str__(self):
311307
return 'DPF Nodes object with %d nodes\n' % len(self)
@@ -389,13 +385,31 @@ def _get_coordinates_field(self):
389385
request.nodal_property = meshed_region_pb2.COORDINATES
390386
fieldOut = self._mesh._stub.ListProperty(request)
391387
return field.Field(self._mesh._channel, field=fieldOut)
388+
389+
390+
def _build_mapping_id_to_index(self):
391+
"""Return a mapping between ids and indeces of the entity."""
392+
dic_out = {}
393+
ids = self._mesh.nodes.scoping.ids
394+
i = 0
395+
for node_id in ids:
396+
dic_out[node_id] = i
397+
i += 1
398+
return dic_out
399+
400+
@property
401+
def mapping_id_to_index(self):
402+
if self._mapping_id_to_index is None:
403+
self._mapping_id_to_index = self._build_mapping_id_to_index()
404+
return self._mapping_id_to_index
392405

393406

394407
class Elements():
395408
"""Class to encapsulate mesh elements"""
396-
409+
397410
def __init__(self, mesh):
398411
self._mesh = mesh
412+
self._mapping_id_to_index = None
399413

400414
def __str__(self):
401415
return 'DPF Elements object with %d elements' % len(self)
@@ -523,10 +537,25 @@ def _get_connectivities_field(self):
523537
request.elemental_property = meshed_region_pb2.CONNECTIVITY
524538
fieldOut = self._mesh._stub.ListProperty(request)
525539
return field.Field(self._mesh._channel, field=fieldOut)
526-
527540

528541
@property
529542
def n_elements(self):
530543
"""Number of elements"""
531544
return self.scoping.size
545+
546+
def _build_mapping_id_to_index(self):
547+
"""Return a mapping between ids and indeces of the entity."""
548+
dic_out = {}
549+
ids = self._mesh.elements.scoping.ids
550+
i = 0
551+
for element_id in ids:
552+
dic_out[element_id] = i
553+
i += 1
554+
return dic_out
555+
556+
@property
557+
def mapping_id_to_index(self):
558+
if self._mapping_id_to_index is None:
559+
self._mapping_id_to_index = self._build_mapping_id_to_index()
560+
return self._mapping_id_to_index
532561

File renamed without changes.

0 commit comments

Comments
 (0)