Skip to content

Commit 4b4ff88

Browse files
committed
Merge branch '461-use-namedtuple-in-return-2' into 'development'
Resolve "use NamedTuple in return" Closes #461 See merge request damask/DAMASK!1025
2 parents b657b19 + ccb1dbe commit 4b4ff88

File tree

5 files changed

+70
-36
lines changed

5 files changed

+70
-36
lines changed

python/damask/_orientation.py

+40-24
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import copy
2-
from typing import Tuple, Optional, Union, TypeVar, Literal # mypy 1.11, overload
2+
from typing import Optional, Union, TypeVar, Literal, NamedTuple # mypy 1.11, overload
33

44
import numpy as np
55

@@ -12,6 +12,21 @@
1212

1313
MyType = TypeVar('MyType', bound='Orientation')
1414

15+
class DisorientationTuple(NamedTuple):
16+
disorientation: 'Orientation'
17+
operators: np.ndarray
18+
19+
20+
class AverageTuple(NamedTuple):
21+
average: 'Orientation'
22+
cloud: 'Orientation'
23+
24+
25+
class ToSSTTuple(NamedTuple):
26+
vector_sst: np.ndarray
27+
operator: np.ndarray
28+
29+
1530
class Orientation(Rotation,Crystal):
1631
"""
1732
Representation of crystallographic orientation as combination of rotation and either crystal family or Bravais lattice.
@@ -466,7 +481,7 @@ def larger_or_equal(v,c):
466481

467482
def disorientation(self: MyType,
468483
other: MyType,
469-
return_operators: bool = False) -> Union[Tuple[MyType, np.ndarray], MyType]:
484+
return_operators: bool = False) -> Union[MyType, DisorientationTuple]:
470485
"""
471486
Calculate disorientation between self and given other orientation.
472487
@@ -477,15 +492,16 @@ def disorientation(self: MyType,
477492
Compatible innermost dimensions will blend.
478493
return_operators : bool, optional
479494
Return index pair of symmetrically equivalent orientations
480-
that result in disorientation axis falling into FZ.
495+
that result in misorientation falling into disorientation FZ.
481496
Defaults to False.
482497
483498
Returns
484499
-------
485500
disorientation : Orientation
486501
Disorientation between self and other.
487502
operators : numpy.ndarray of int, shape (...,2), conditional
488-
Index of symmetrically equivalent orientation that rotated vector to the SST.
503+
Index pair of symmetrically equivalent orientations
504+
that result in misorientation falling into disorientation FZ.
489505
490506
Notes
491507
-----
@@ -543,11 +559,11 @@ def disorientation(self: MyType,
543559

544560
quat = r[ok][sort].reshape((*shp,4))
545561

546-
return (
547-
(self.copy(rotation=quat), (np.vstack(loc[:2]).T)[sort].reshape((*shp,2)))
548-
if return_operators else
549-
self.copy(rotation=quat)
550-
)
562+
if return_operators:
563+
operators = (np.vstack(loc[:2]).T)[sort].reshape((*shp, 2))
564+
return DisorientationTuple(self.copy(rotation=quat), operators)
565+
else:
566+
return self.copy(rotation=quat)
551567

552568

553569
def disorientation_angle(self: MyType,
@@ -637,7 +653,7 @@ def disorientation_angle(self: MyType,
637653

638654
def average(self: MyType, # type: ignore[override]
639655
weights: Optional[FloatSequence] = None,
640-
return_cloud: bool = False) -> Union[Tuple[MyType, MyType], MyType]:
656+
return_cloud: bool = False) -> Union[MyType, AverageTuple]:
641657
"""
642658
Return orientation average over last dimension.
643659
@@ -671,9 +687,10 @@ def average(self: MyType,
671687
axis=0),
672688
axis=0))
673689

674-
return ((self.copy(Rotation(r).average(weights)),self.copy(Rotation(r))) if return_cloud else
675-
self.copy(Rotation(r).average(weights))
676-
)
690+
if return_cloud:
691+
return AverageTuple(self.copy(Rotation(r).average(weights)),self.copy(Rotation(r)))
692+
else:
693+
return self.copy(Rotation(r).average(weights))
677694

678695
# mypy 1.11
679696
#@overload
@@ -686,7 +703,7 @@ def to_SST(self,
686703
vector: FloatSequence,
687704
proper: bool = False,
688705
# return_operators: bool = False) -> Union[np.ndarray,Tuple[np.ndarray,np.ndarray]]:
689-
return_operators: bool = False) -> np.ndarray:
706+
return_operator: bool = False) -> Union[np.ndarray, ToSSTTuple]:
690707
"""
691708
Rotate lab frame vector to ensure it falls into (improper or proper) standard stereographic triangle of crystal symmetry.
692709
@@ -699,16 +716,16 @@ def to_SST(self,
699716
proper : bool, optional
700717
Consider only vectors with z >= 0, hence combine two neighboring SSTs.
701718
Defaults to False.
702-
return_operators : bool, optional
703-
Return the symmetrically equivalent orientation that rotated vector to SST.
719+
return_operator : bool, optional
720+
Return the index of the symmetrically equivalent orientation that rotated vector to SST.
704721
Defaults to False.
705722
706723
Returns
707724
-------
708725
vector_SST : numpy.ndarray, shape (...,3)
709726
Rotated vector falling into SST.
710727
operator : numpy.ndarray of int, shape (...), conditional
711-
Index of symmetrically equivalent orientation that rotated vector to SST.
728+
Index of the symmetrically equivalent orientation that rotated vector to SST.
712729
713730
"""
714731
vector_ = np.array(vector,float)
@@ -723,11 +740,10 @@ def to_SST(self,
723740
loc = np.where(ok)
724741
sort = 0 if len(loc) == 1 else np.lexsort(loc[:0:-1])
725742

726-
return (
727-
(poles[ok][sort].reshape(blend+(3,)), (np.vstack(loc[:1]).T)[sort].reshape(blend))
728-
if return_operators else
729-
poles[ok][sort].reshape(blend+(3,))
730-
)
743+
if return_operator:
744+
return ToSSTTuple(poles[ok][sort].reshape(blend+(3,)), (np.vstack(loc[:1]).T)[sort].reshape(blend))
745+
else:
746+
return poles[ok][sort].reshape(blend+(3,))
731747

732748

733749
def in_SST(self,
@@ -827,8 +843,8 @@ def IPF_color(self,
827843
if np.array(vector).shape[-1] != 3:
828844
raise ValueError('input is not a field of three-dimensional vectors')
829845

830-
vector_ = self.to_SST(vector,proper) if in_SST else \
831-
self @ np.broadcast_to(vector,self.shape+(3,))
846+
vector_:np.ndarray = self.to_SST(vector,proper) if in_SST else \
847+
self @ np.broadcast_to(vector,self.shape+(3,)) #type: ignore
832848

833849
if self.standard_triangle is None: # direct exit for no symmetry
834850
return np.zeros_like(vector_)

python/damask/_result.py

+11-5
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from pathlib import Path
99
from collections import defaultdict
1010
from collections.abc import Iterable
11-
from typing import Optional, Union, Callable, Any, Sequence, Literal, Dict, List, Tuple
11+
from typing import Optional, Union, Callable, Any, Sequence, Literal, Dict, List, Tuple, NamedTuple
1212

1313
import h5py
1414
import numpy as np
@@ -30,6 +30,12 @@
3030

3131
prefix_inc = 'increment_'
3232

33+
class MappingsTuple(NamedTuple):
34+
at_cell_ph: List[Dict[str, np.ndarray]]
35+
in_data_ph: List[Dict[str, np.ndarray]]
36+
at_cell_ho: Dict[str, np.ndarray]
37+
in_data_ho: Dict[str, np.ndarray]
38+
3339

3440
def _read(dataset: h5py._hl.dataset.Dataset) -> np.ndarray:
3541
"""Read a dataset and its metadata into a numpy.ndarray."""
@@ -1577,7 +1583,7 @@ def job_pointwise(group: str,
15771583
print(f'Could not add dataset: {err}.')
15781584

15791585

1580-
def _mappings(self):
1586+
def _mappings(self) -> MappingsTuple:
15811587
"""Mappings to place data spatially."""
15821588
with h5py.File(self.fname,'r') as f:
15831589

@@ -1594,7 +1600,7 @@ def _mappings(self):
15941600
in_data_ho = {label: f['/'.join(['cell_to','homogenization'])]['entry'][at_cell_ho[label]] \
15951601
for label in self._visible['homogenizations']}
15961602

1597-
return at_cell_ph,in_data_ph,at_cell_ho,in_data_ho
1603+
return MappingsTuple(at_cell_ph, in_data_ph, at_cell_ho, in_data_ho)
15981604

15991605

16001606
def get(self,
@@ -1694,7 +1700,7 @@ def place(self,
16941700
(range(self.N_constituents) if constituents is None else [constituents]) # type: ignore
16951701

16961702
suffixes = [''] if self.N_constituents == 1 or isinstance(constituents,int) else \
1697-
[f'#{c}' for c in constituents_]
1703+
[f'#{c}' for c in constituents_] # type: ignore
16981704

16991705
at_cell_ph,in_data_ph,at_cell_ho,in_data_ho = self._mappings()
17001706

@@ -1722,7 +1728,7 @@ def place(self,
17221728
_empty_like(data,self.N_materialpoints,fill_float,fill_int)
17231729

17241730
for c,suffix in zip(constituents_,suffixes):
1725-
r[inc][ty][field][out+suffix][at_cell_ph[c][label]] = data[in_data_ph[c][label]]
1731+
r[inc][ty][field][out+suffix][at_cell_ph[c][label]] = data[in_data_ph[c][label]] # type: ignore
17261732

17271733
if ty == 'homogenization':
17281734
if out not in r[inc][ty][field].keys():

python/damask/_rotation.py

+11-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import copy
33
import re
44
import builtins
5-
from typing import Optional, Union, Sequence, Tuple, Literal, List, TypeVar
5+
from typing import Optional, Union, Sequence, Tuple, Literal, List, TypeVar, NamedTuple
66

77
import numpy as np
88

@@ -12,6 +12,11 @@
1212
from . import grid_filters
1313

1414

15+
class AxisAngleTuple(NamedTuple):
16+
axis: np.ndarray
17+
angle: np.ndarray
18+
19+
1520
_P = -1
1621

1722
# parameters for conversion from/to cubochoric
@@ -720,7 +725,7 @@ def as_Euler_angles(self,
720725

721726
def as_axis_angle(self,
722727
degrees: bool = False,
723-
pair: bool = False) -> Union[Tuple[np.ndarray, np.ndarray], np.ndarray]:
728+
pair: bool = False) -> Union[AxisAngleTuple, np.ndarray]:
724729
"""
725730
Represent as axis–angle pair.
726731
@@ -748,7 +753,10 @@ def as_axis_angle(self,
748753
"""
749754
ax: np.ndarray = Rotation._qu2ax(self.quaternion)
750755
if degrees: ax[...,3] = np.degrees(ax[...,3])
751-
return (ax[...,:3],ax[...,3]) if pair else ax
756+
if pair:
757+
return AxisAngleTuple(ax[...,:3],ax[...,3])
758+
else:
759+
return ax
752760

753761
def as_matrix(self) -> np.ndarray:
754762
"""

python/damask/_vtk.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -652,7 +652,7 @@ def show(self,
652652
colormap
653653
lut.SetNumberOfTableValues(len(colormap_.colors))
654654
for i,c in enumerate(colormap_.colors):
655-
lut.SetTableValue(i,c if len(c)==4 else np.append(c,1.0))
655+
lut.SetTableValue(i,c if len(c)==4 else np.append(c,1.0)) # type: ignore
656656
lut.Build()
657657
if label is not None:
658658
self.vtk_data.GetCellData().SetActiveScalars(label)

python/damask/util.py

+7-3
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from functools import reduce as _reduce, partial as _partial, wraps as _wraps
1414
import inspect
1515
from typing import Optional as _Optional, Callable as _Callable, Union as _Union, Iterable as _Iterable, \
16-
Dict as _Dict, List as _List, Tuple as _Tuple, Literal as _Literal, \
16+
Dict as _Dict, List as _List, Tuple as _Tuple, Literal as _Literal, NamedTuple as _NamedTuple,\
1717
Any as _Any, TextIO as _TextIO, Generator as _Generator
1818
from pathlib import Path as _Path
1919

@@ -24,6 +24,10 @@
2424
from ._typehints import FloatSequence as _FloatSequence, IntSequence as _IntSequence, \
2525
NumpyRngSeed as _NumpyRngSeed, FileHandle as _FileHandle
2626

27+
class stdioTuple(_NamedTuple):
28+
stdin: str
29+
stdout: str
30+
2731

2832
# https://svn.blender.org/svnroot/bf-blender/trunk/blender/build_files/scons/tools/bcolors.py
2933
# https://stackoverflow.com/questions/287871
@@ -145,7 +149,7 @@ def strikeout(msg) -> str:
145149
def run(cmd: str,
146150
wd: str = './',
147151
env: _Optional[_Dict[str, str]] = None,
148-
timeout: _Optional[int] = None) -> _Tuple[str, str]:
152+
timeout: _Optional[int] = None) -> stdioTuple:
149153
"""
150154
Run a command.
151155
@@ -194,7 +198,7 @@ def pass_signal(sig,_,proc,default):
194198
print(stderr)
195199
raise RuntimeError(f"'{cmd}' failed with returncode {process.returncode}")
196200

197-
return stdout, stderr
201+
return stdioTuple(stdout, stderr)
198202

199203
@_contextlib.contextmanager
200204
def open_text(fname: _FileHandle,

0 commit comments

Comments
 (0)