Skip to content

Commit

Permalink
Merge branch '461-use-namedtuple-in-return-2' into 'development'
Browse files Browse the repository at this point in the history
Resolve "use NamedTuple in return"

Closes #461

See merge request damask/DAMASK!1025
  • Loading branch information
MarDiehl committed Jan 25, 2025
2 parents b657b19 + ccb1dbe commit 4b4ff88
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 36 deletions.
64 changes: 40 additions & 24 deletions python/damask/_orientation.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import copy
from typing import Tuple, Optional, Union, TypeVar, Literal # mypy 1.11, overload
from typing import Optional, Union, TypeVar, Literal, NamedTuple # mypy 1.11, overload

import numpy as np

Expand All @@ -12,6 +12,21 @@

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

class DisorientationTuple(NamedTuple):
disorientation: 'Orientation'
operators: np.ndarray


class AverageTuple(NamedTuple):
average: 'Orientation'
cloud: 'Orientation'


class ToSSTTuple(NamedTuple):
vector_sst: np.ndarray
operator: np.ndarray


class Orientation(Rotation,Crystal):
"""
Representation of crystallographic orientation as combination of rotation and either crystal family or Bravais lattice.
Expand Down Expand Up @@ -466,7 +481,7 @@ def larger_or_equal(v,c):

def disorientation(self: MyType,
other: MyType,
return_operators: bool = False) -> Union[Tuple[MyType, np.ndarray], MyType]:
return_operators: bool = False) -> Union[MyType, DisorientationTuple]:
"""
Calculate disorientation between self and given other orientation.
Expand All @@ -477,15 +492,16 @@ def disorientation(self: MyType,
Compatible innermost dimensions will blend.
return_operators : bool, optional
Return index pair of symmetrically equivalent orientations
that result in disorientation axis falling into FZ.
that result in misorientation falling into disorientation FZ.
Defaults to False.
Returns
-------
disorientation : Orientation
Disorientation between self and other.
operators : numpy.ndarray of int, shape (...,2), conditional
Index of symmetrically equivalent orientation that rotated vector to the SST.
Index pair of symmetrically equivalent orientations
that result in misorientation falling into disorientation FZ.
Notes
-----
Expand Down Expand Up @@ -543,11 +559,11 @@ def disorientation(self: MyType,

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

return (
(self.copy(rotation=quat), (np.vstack(loc[:2]).T)[sort].reshape((*shp,2)))
if return_operators else
self.copy(rotation=quat)
)
if return_operators:
operators = (np.vstack(loc[:2]).T)[sort].reshape((*shp, 2))
return DisorientationTuple(self.copy(rotation=quat), operators)
else:
return self.copy(rotation=quat)


def disorientation_angle(self: MyType,
Expand Down Expand Up @@ -637,7 +653,7 @@ def disorientation_angle(self: MyType,

def average(self: MyType, # type: ignore[override]
weights: Optional[FloatSequence] = None,
return_cloud: bool = False) -> Union[Tuple[MyType, MyType], MyType]:
return_cloud: bool = False) -> Union[MyType, AverageTuple]:
"""
Return orientation average over last dimension.
Expand Down Expand Up @@ -671,9 +687,10 @@ def average(self: MyType,
axis=0),
axis=0))

return ((self.copy(Rotation(r).average(weights)),self.copy(Rotation(r))) if return_cloud else
self.copy(Rotation(r).average(weights))
)
if return_cloud:
return AverageTuple(self.copy(Rotation(r).average(weights)),self.copy(Rotation(r)))
else:
return self.copy(Rotation(r).average(weights))

# mypy 1.11
#@overload
Expand All @@ -686,7 +703,7 @@ def to_SST(self,
vector: FloatSequence,
proper: bool = False,
# return_operators: bool = False) -> Union[np.ndarray,Tuple[np.ndarray,np.ndarray]]:
return_operators: bool = False) -> np.ndarray:
return_operator: bool = False) -> Union[np.ndarray, ToSSTTuple]:
"""
Rotate lab frame vector to ensure it falls into (improper or proper) standard stereographic triangle of crystal symmetry.
Expand All @@ -699,16 +716,16 @@ def to_SST(self,
proper : bool, optional
Consider only vectors with z >= 0, hence combine two neighboring SSTs.
Defaults to False.
return_operators : bool, optional
Return the symmetrically equivalent orientation that rotated vector to SST.
return_operator : bool, optional
Return the index of the symmetrically equivalent orientation that rotated vector to SST.
Defaults to False.
Returns
-------
vector_SST : numpy.ndarray, shape (...,3)
Rotated vector falling into SST.
operator : numpy.ndarray of int, shape (...), conditional
Index of symmetrically equivalent orientation that rotated vector to SST.
Index of the symmetrically equivalent orientation that rotated vector to SST.
"""
vector_ = np.array(vector,float)
Expand All @@ -723,11 +740,10 @@ def to_SST(self,
loc = np.where(ok)
sort = 0 if len(loc) == 1 else np.lexsort(loc[:0:-1])

return (
(poles[ok][sort].reshape(blend+(3,)), (np.vstack(loc[:1]).T)[sort].reshape(blend))
if return_operators else
poles[ok][sort].reshape(blend+(3,))
)
if return_operator:
return ToSSTTuple(poles[ok][sort].reshape(blend+(3,)), (np.vstack(loc[:1]).T)[sort].reshape(blend))
else:
return poles[ok][sort].reshape(blend+(3,))


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

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

if self.standard_triangle is None: # direct exit for no symmetry
return np.zeros_like(vector_)
Expand Down
16 changes: 11 additions & 5 deletions python/damask/_result.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from pathlib import Path
from collections import defaultdict
from collections.abc import Iterable
from typing import Optional, Union, Callable, Any, Sequence, Literal, Dict, List, Tuple
from typing import Optional, Union, Callable, Any, Sequence, Literal, Dict, List, Tuple, NamedTuple

import h5py
import numpy as np
Expand All @@ -30,6 +30,12 @@

prefix_inc = 'increment_'

class MappingsTuple(NamedTuple):
at_cell_ph: List[Dict[str, np.ndarray]]
in_data_ph: List[Dict[str, np.ndarray]]
at_cell_ho: Dict[str, np.ndarray]
in_data_ho: Dict[str, np.ndarray]


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


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

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

return at_cell_ph,in_data_ph,at_cell_ho,in_data_ho
return MappingsTuple(at_cell_ph, in_data_ph, at_cell_ho, in_data_ho)


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

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

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

Expand Down Expand Up @@ -1722,7 +1728,7 @@ def place(self,
_empty_like(data,self.N_materialpoints,fill_float,fill_int)

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

if ty == 'homogenization':
if out not in r[inc][ty][field].keys():
Expand Down
14 changes: 11 additions & 3 deletions python/damask/_rotation.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import copy
import re
import builtins
from typing import Optional, Union, Sequence, Tuple, Literal, List, TypeVar
from typing import Optional, Union, Sequence, Tuple, Literal, List, TypeVar, NamedTuple

import numpy as np

Expand All @@ -12,6 +12,11 @@
from . import grid_filters


class AxisAngleTuple(NamedTuple):
axis: np.ndarray
angle: np.ndarray


_P = -1

# parameters for conversion from/to cubochoric
Expand Down Expand Up @@ -720,7 +725,7 @@ def as_Euler_angles(self,

def as_axis_angle(self,
degrees: bool = False,
pair: bool = False) -> Union[Tuple[np.ndarray, np.ndarray], np.ndarray]:
pair: bool = False) -> Union[AxisAngleTuple, np.ndarray]:
"""
Represent as axis–angle pair.
Expand Down Expand Up @@ -748,7 +753,10 @@ def as_axis_angle(self,
"""
ax: np.ndarray = Rotation._qu2ax(self.quaternion)
if degrees: ax[...,3] = np.degrees(ax[...,3])
return (ax[...,:3],ax[...,3]) if pair else ax
if pair:
return AxisAngleTuple(ax[...,:3],ax[...,3])
else:
return ax

def as_matrix(self) -> np.ndarray:
"""
Expand Down
2 changes: 1 addition & 1 deletion python/damask/_vtk.py
Original file line number Diff line number Diff line change
Expand Up @@ -652,7 +652,7 @@ def show(self,
colormap
lut.SetNumberOfTableValues(len(colormap_.colors))
for i,c in enumerate(colormap_.colors):
lut.SetTableValue(i,c if len(c)==4 else np.append(c,1.0))
lut.SetTableValue(i,c if len(c)==4 else np.append(c,1.0)) # type: ignore
lut.Build()
if label is not None:
self.vtk_data.GetCellData().SetActiveScalars(label)
Expand Down
10 changes: 7 additions & 3 deletions python/damask/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from functools import reduce as _reduce, partial as _partial, wraps as _wraps
import inspect
from typing import Optional as _Optional, Callable as _Callable, Union as _Union, Iterable as _Iterable, \
Dict as _Dict, List as _List, Tuple as _Tuple, Literal as _Literal, \
Dict as _Dict, List as _List, Tuple as _Tuple, Literal as _Literal, NamedTuple as _NamedTuple,\
Any as _Any, TextIO as _TextIO, Generator as _Generator
from pathlib import Path as _Path

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

class stdioTuple(_NamedTuple):
stdin: str
stdout: str


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

return stdout, stderr
return stdioTuple(stdout, stderr)

@_contextlib.contextmanager
def open_text(fname: _FileHandle,
Expand Down

0 comments on commit 4b4ff88

Please sign in to comment.