2020-06-26 15:15:06 +05:30
|
|
|
|
import multiprocessing as mp
|
2019-04-13 14:41:32 +05:30
|
|
|
|
import re
|
2019-09-14 21:22:07 +05:30
|
|
|
|
import glob
|
2019-12-13 16:45:45 +05:30
|
|
|
|
import os
|
2020-05-25 22:20:31 +05:30
|
|
|
|
import datetime
|
2020-05-05 13:27:22 +05:30
|
|
|
|
import xml.etree.ElementTree as ET
|
|
|
|
|
import xml.dom.minidom
|
2020-06-03 14:13:07 +05:30
|
|
|
|
from pathlib import Path
|
2020-02-21 23:54:26 +05:30
|
|
|
|
from functools import partial
|
2020-11-28 02:15:23 +05:30
|
|
|
|
from collections import defaultdict
|
2019-09-12 06:33:19 +05:30
|
|
|
|
|
|
|
|
|
import h5py
|
2019-04-17 23:27:16 +05:30
|
|
|
|
import numpy as np
|
2020-06-20 20:45:13 +05:30
|
|
|
|
from numpy.lib import recfunctions as rfn
|
2019-09-12 06:33:19 +05:30
|
|
|
|
|
2020-06-28 15:10:19 +05:30
|
|
|
|
import damask
|
2020-03-11 11:20:13 +05:30
|
|
|
|
from . import VTK
|
2020-03-13 00:22:33 +05:30
|
|
|
|
from . import Table
|
2020-02-16 00:39:24 +05:30
|
|
|
|
from . import Orientation
|
2020-02-21 22:17:47 +05:30
|
|
|
|
from . import grid_filters
|
2020-03-13 00:22:33 +05:30
|
|
|
|
from . import mechanics
|
2020-11-16 03:44:46 +05:30
|
|
|
|
from . import tensor
|
2020-03-13 00:22:33 +05:30
|
|
|
|
from . import util
|
|
|
|
|
|
2020-11-05 20:43:29 +05:30
|
|
|
|
h5py3 = h5py.__version__[0] == '3'
|
2019-04-13 14:41:32 +05:30
|
|
|
|
|
2020-03-09 18:09:20 +05:30
|
|
|
|
class Result:
|
2019-09-20 01:02:15 +05:30
|
|
|
|
"""
|
2020-02-21 12:15:05 +05:30
|
|
|
|
Read and write to DADF5 files.
|
2019-09-16 08:49:14 +05:30
|
|
|
|
|
2020-03-19 12:15:31 +05:30
|
|
|
|
DADF5 (DAMASK HDF5) files contain DAMASK results.
|
2020-02-21 12:15:05 +05:30
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
def __init__(self,fname):
|
|
|
|
|
"""
|
2020-03-12 11:21:52 +05:30
|
|
|
|
Open an existing DADF5 file.
|
2019-09-16 08:49:14 +05:30
|
|
|
|
|
2020-02-21 12:15:05 +05:30
|
|
|
|
Parameters
|
|
|
|
|
----------
|
2020-11-19 18:15:40 +05:30
|
|
|
|
fname : str or pathlib.Path
|
|
|
|
|
Name of the DADF5 file to be opened.
|
2019-09-20 01:02:15 +05:30
|
|
|
|
|
2020-02-21 12:15:05 +05:30
|
|
|
|
"""
|
|
|
|
|
with h5py.File(fname,'r') as f:
|
|
|
|
|
|
2020-11-18 19:22:16 +05:30
|
|
|
|
self.version_major = f.attrs['DADF5_version_major']
|
|
|
|
|
self.version_minor = f.attrs['DADF5_version_minor']
|
|
|
|
|
|
2021-03-25 23:52:59 +05:30
|
|
|
|
if self.version_major != 0 or not 7 <= self.version_minor <= 12:
|
2020-06-25 01:04:51 +05:30
|
|
|
|
raise TypeError(f'Unsupported DADF5 version {self.version_major}.{self.version_minor}')
|
2020-03-22 20:43:35 +05:30
|
|
|
|
|
2020-12-04 02:28:24 +05:30
|
|
|
|
self.structured = 'grid' in f['geometry'].attrs.keys() or \
|
|
|
|
|
'cells' in f['geometry'].attrs.keys()
|
2020-03-22 20:43:35 +05:30
|
|
|
|
|
|
|
|
|
if self.structured:
|
2020-12-04 02:28:24 +05:30
|
|
|
|
try:
|
|
|
|
|
self.cells = f['geometry'].attrs['cells']
|
|
|
|
|
except KeyError:
|
|
|
|
|
self.cells = f['geometry'].attrs['grid']
|
2020-03-22 20:43:35 +05:30
|
|
|
|
self.size = f['geometry'].attrs['size']
|
2020-11-18 19:22:16 +05:30
|
|
|
|
self.origin = f['geometry'].attrs['origin']
|
2020-03-22 20:43:35 +05:30
|
|
|
|
|
2021-03-25 23:52:59 +05:30
|
|
|
|
r=re.compile('inc[0-9]+' if self.version_minor < 12 else 'increment_[0-9]+')
|
|
|
|
|
increments_unsorted = {int(i[10:]):i for i in f.keys() if r.match(i)}
|
2020-03-22 20:43:35 +05:30
|
|
|
|
self.increments = [increments_unsorted[i] for i in sorted(increments_unsorted)]
|
2021-03-25 23:52:59 +05:30
|
|
|
|
self.times = [round(f[i].attrs['time/s'],12) for i in self.increments] if self.version_minor < 12 else \
|
|
|
|
|
[round(f[i].attrs['t/s'],12) for i in self.increments]
|
2020-03-22 20:43:35 +05:30
|
|
|
|
|
2021-03-25 23:52:59 +05:30
|
|
|
|
grp = 'mapping' if self.version_minor < 12 else 'cell_to'
|
2020-05-07 22:42:05 +05:30
|
|
|
|
|
2021-03-25 23:52:59 +05:30
|
|
|
|
self.N_materialpoints, self.N_constituents = np.shape(f[f'{grp}/phase'])
|
|
|
|
|
|
|
|
|
|
self.homogenizations = [m.decode() for m in np.unique(f[f'{grp}/homogenization']
|
|
|
|
|
['Name' if self.version_minor < 12 else 'label'])]
|
|
|
|
|
self.phases = [c.decode() for c in np.unique(f[f'{grp}/phase']
|
|
|
|
|
['Name' if self.version_minor < 12 else 'label'])]
|
2020-03-22 20:43:35 +05:30
|
|
|
|
|
2020-11-18 19:22:16 +05:30
|
|
|
|
self.out_type_ph = []
|
|
|
|
|
for c in self.phases:
|
|
|
|
|
self.out_type_ph += f['/'.join([self.increments[0],'phase',c])].keys()
|
|
|
|
|
self.out_type_ph = list(set(self.out_type_ph)) # make unique
|
2020-03-22 20:43:35 +05:30
|
|
|
|
|
2020-11-18 19:22:16 +05:30
|
|
|
|
self.out_type_ho = []
|
|
|
|
|
for m in self.homogenizations:
|
|
|
|
|
self.out_type_ho += f['/'.join([self.increments[0],'homogenization',m])].keys()
|
|
|
|
|
self.out_type_ho = list(set(self.out_type_ho)) # make unique
|
2019-10-20 14:30:10 +05:30
|
|
|
|
|
2021-01-13 19:27:58 +05:30
|
|
|
|
self.visible = {'increments': self.increments,
|
|
|
|
|
'phases': self.phases,
|
|
|
|
|
'homogenizations': self.homogenizations,
|
|
|
|
|
'out_type_ph': self.out_type_ph,
|
|
|
|
|
'out_type_ho': self.out_type_ho
|
|
|
|
|
}
|
2019-10-20 14:30:10 +05:30
|
|
|
|
|
2020-06-03 14:13:07 +05:30
|
|
|
|
self.fname = Path(fname).absolute()
|
2019-10-20 14:30:10 +05:30
|
|
|
|
|
2020-05-30 16:17:36 +05:30
|
|
|
|
self._allow_modification = False
|
2020-05-25 22:42:31 +05:30
|
|
|
|
|
2019-10-20 14:30:10 +05:30
|
|
|
|
|
2020-03-11 10:58:13 +05:30
|
|
|
|
def __repr__(self):
|
2020-11-05 11:45:59 +05:30
|
|
|
|
"""Show summary of file content."""
|
2021-01-13 19:27:58 +05:30
|
|
|
|
visible_increments = self.visible['increments']
|
2020-04-21 14:47:15 +05:30
|
|
|
|
|
2021-01-13 19:27:58 +05:30
|
|
|
|
self.view('increments',visible_increments[0:1])
|
2020-03-19 16:00:36 +05:30
|
|
|
|
first = self.list_data()
|
2020-04-21 14:47:15 +05:30
|
|
|
|
|
2021-01-13 19:27:58 +05:30
|
|
|
|
self.view('increments',visible_increments[-1:])
|
|
|
|
|
last = '' if len(visible_increments) < 2 else self.list_data()
|
2020-04-21 14:47:15 +05:30
|
|
|
|
|
2021-01-13 19:27:58 +05:30
|
|
|
|
self.view('increments',visible_increments)
|
2020-04-21 14:47:15 +05:30
|
|
|
|
|
2021-01-13 19:27:58 +05:30
|
|
|
|
in_between = '' if len(visible_increments) < 3 else \
|
2021-02-26 07:50:28 +05:30
|
|
|
|
''.join([f'\n{inc}\n ...\n' for inc in visible_increments[1:-1]])
|
2020-04-21 14:47:15 +05:30
|
|
|
|
|
|
|
|
|
return util.srepr(first + in_between + last)
|
2020-03-11 10:58:13 +05:30
|
|
|
|
|
|
|
|
|
|
2021-01-13 19:27:58 +05:30
|
|
|
|
def _manage_view(self,action,what,datasets):
|
2020-02-21 12:15:05 +05:30
|
|
|
|
"""
|
|
|
|
|
Manages the visibility of the groups.
|
2019-10-20 14:30:10 +05:30
|
|
|
|
|
2020-02-21 12:15:05 +05:30
|
|
|
|
Parameters
|
|
|
|
|
----------
|
2020-03-03 04:17:29 +05:30
|
|
|
|
action : str
|
2020-11-23 23:52:48 +05:30
|
|
|
|
Select from 'set', 'add', and 'del'.
|
2020-03-03 04:17:29 +05:30
|
|
|
|
what : str
|
2021-02-26 07:50:28 +05:30
|
|
|
|
Attribute to change (must be from self.visible).
|
2020-04-21 02:21:51 +05:30
|
|
|
|
datasets : list of str or bool
|
2021-02-26 07:50:28 +05:30
|
|
|
|
Name of datasets as list; supports ? and * wildcards.
|
|
|
|
|
True is equivalent to [*], False is equivalent to [].
|
2020-03-03 04:17:29 +05:30
|
|
|
|
|
2020-02-21 12:15:05 +05:30
|
|
|
|
"""
|
2020-11-29 13:28:48 +05:30
|
|
|
|
def natural_sort(key):
|
|
|
|
|
convert = lambda text: int(text) if text.isdigit() else text
|
|
|
|
|
return [ convert(c) for c in re.split('([0-9]+)', key) ]
|
|
|
|
|
|
2020-02-21 12:15:05 +05:30
|
|
|
|
# allow True/False and string arguments
|
2020-05-21 14:15:52 +05:30
|
|
|
|
if datasets is True:
|
2020-03-03 04:17:29 +05:30
|
|
|
|
datasets = ['*']
|
2020-02-21 12:15:05 +05:30
|
|
|
|
elif datasets is False:
|
2020-03-03 04:17:29 +05:30
|
|
|
|
datasets = []
|
2020-03-03 18:37:02 +05:30
|
|
|
|
choice = datasets if hasattr(datasets,'__iter__') and not isinstance(datasets,str) else \
|
|
|
|
|
[datasets]
|
|
|
|
|
|
2021-03-25 23:52:59 +05:30
|
|
|
|
inc = 'inc' if self.version_minor < 12 else 'increment_' # compatibility hack
|
2020-03-03 18:37:02 +05:30
|
|
|
|
if what == 'increments':
|
2021-03-25 23:52:59 +05:30
|
|
|
|
choice = [c if isinstance(c,str) and c.startswith(inc) else
|
|
|
|
|
f'{inc}{c}' for c in choice]
|
2020-03-03 18:37:02 +05:30
|
|
|
|
elif what == 'times':
|
|
|
|
|
what = 'increments'
|
|
|
|
|
if choice == ['*']:
|
|
|
|
|
choice = self.increments
|
|
|
|
|
else:
|
|
|
|
|
iterator = map(float,choice)
|
|
|
|
|
choice = []
|
|
|
|
|
for c in iterator:
|
2020-03-22 21:33:28 +05:30
|
|
|
|
idx = np.searchsorted(self.times,c)
|
2020-05-26 03:24:06 +05:30
|
|
|
|
if idx >= len(self.times): continue
|
2020-03-03 18:37:02 +05:30
|
|
|
|
if np.isclose(c,self.times[idx]):
|
|
|
|
|
choice.append(self.increments[idx])
|
|
|
|
|
elif np.isclose(c,self.times[idx+1]):
|
|
|
|
|
choice.append(self.increments[idx+1])
|
2019-10-20 14:30:10 +05:30
|
|
|
|
|
2020-02-21 12:15:05 +05:30
|
|
|
|
valid = [e for e_ in [glob.fnmatch.filter(getattr(self,what),s) for s in choice] for e in e_]
|
2021-01-13 19:27:58 +05:30
|
|
|
|
existing = set(self.visible[what])
|
2020-02-21 12:15:05 +05:30
|
|
|
|
|
|
|
|
|
if action == 'set':
|
2021-01-13 19:27:58 +05:30
|
|
|
|
self.visible[what] = valid
|
2020-02-21 12:15:05 +05:30
|
|
|
|
elif action == 'add':
|
2020-03-22 21:33:28 +05:30
|
|
|
|
add = existing.union(valid)
|
2020-11-29 13:28:48 +05:30
|
|
|
|
add_sorted = sorted(add, key=natural_sort)
|
2021-01-13 19:27:58 +05:30
|
|
|
|
self.visible[what] = add_sorted
|
2020-02-21 12:15:05 +05:30
|
|
|
|
elif action == 'del':
|
2020-03-22 21:33:28 +05:30
|
|
|
|
diff = existing.difference(valid)
|
2020-11-29 13:28:48 +05:30
|
|
|
|
diff_sorted = sorted(diff, key=natural_sort)
|
2021-01-13 19:27:58 +05:30
|
|
|
|
self.visible[what] = diff_sorted
|
2020-02-21 12:15:05 +05:30
|
|
|
|
|
2020-03-03 17:13:14 +05:30
|
|
|
|
|
2020-11-19 18:15:40 +05:30
|
|
|
|
def _get_attribute(self,path,attr):
|
|
|
|
|
"""
|
|
|
|
|
Get the attribute of a dataset.
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
|
|
|
|
Path : str
|
|
|
|
|
Path to the dataset.
|
|
|
|
|
attr : str
|
2020-11-23 23:52:48 +05:30
|
|
|
|
Name of the attribute to get.
|
2020-11-19 18:15:40 +05:30
|
|
|
|
|
2020-11-23 23:52:48 +05:30
|
|
|
|
Returns
|
|
|
|
|
-------
|
|
|
|
|
attr at path, str or None.
|
|
|
|
|
The requested attribute, None if not found.
|
2020-11-19 18:15:40 +05:30
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
with h5py.File(self.fname,'r') as f:
|
|
|
|
|
try:
|
2020-11-24 00:47:04 +05:30
|
|
|
|
return f[path].attrs[attr] if h5py3 else f[path].attrs[attr].decode()
|
2020-11-19 18:15:40 +05:30
|
|
|
|
except KeyError:
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
2020-05-30 16:17:36 +05:30
|
|
|
|
def allow_modification(self):
|
2020-11-19 18:15:40 +05:30
|
|
|
|
"""Allow to overwrite existing data."""
|
2020-11-15 15:23:23 +05:30
|
|
|
|
print(util.warn('Warning: Modification of existing datasets allowed!'))
|
2020-05-30 16:17:36 +05:30
|
|
|
|
self._allow_modification = True
|
2020-05-25 22:42:31 +05:30
|
|
|
|
|
2020-06-01 15:03:22 +05:30
|
|
|
|
def disallow_modification(self):
|
2021-02-26 07:50:28 +05:30
|
|
|
|
"""Disallow to overwrite existing data (default case)."""
|
2020-05-30 16:17:36 +05:30
|
|
|
|
self._allow_modification = False
|
2020-05-25 22:42:31 +05:30
|
|
|
|
|
|
|
|
|
|
2021-03-25 23:52:59 +05:30
|
|
|
|
def increments_in_range(self,start,end):
|
2020-11-19 18:15:40 +05:30
|
|
|
|
"""
|
|
|
|
|
Select all increments within a given range.
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
|
|
|
|
start : int or str
|
|
|
|
|
Start increment.
|
|
|
|
|
end : int or str
|
|
|
|
|
End increment.
|
|
|
|
|
|
|
|
|
|
"""
|
2021-03-25 23:52:59 +05:30
|
|
|
|
# compatibility hack
|
|
|
|
|
ln = 3 if self.version_minor < 12 else 10
|
2020-03-03 17:13:14 +05:30
|
|
|
|
selected = []
|
2021-03-25 23:52:59 +05:30
|
|
|
|
for i,inc in enumerate([int(i[ln:]) for i in self.increments]):
|
|
|
|
|
s,e = map(lambda x: int(x[ln:] if isinstance(x,str) and x.startswith('inc') else x), (start,end))
|
2020-03-03 17:13:14 +05:30
|
|
|
|
if s <= inc <= e:
|
|
|
|
|
selected.append(self.increments[i])
|
|
|
|
|
return selected
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def times_in_range(self,start,end):
|
2020-11-19 18:15:40 +05:30
|
|
|
|
"""
|
|
|
|
|
Select all increments within a given time range.
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
|
|
|
|
start : float
|
|
|
|
|
Time of start increment.
|
|
|
|
|
end : float
|
|
|
|
|
Time of end increment.
|
|
|
|
|
|
|
|
|
|
"""
|
2020-03-03 17:13:14 +05:30
|
|
|
|
selected = []
|
|
|
|
|
for i,time in enumerate(self.times):
|
|
|
|
|
if start <= time <= end:
|
2020-03-10 03:58:25 +05:30
|
|
|
|
selected.append(self.times[i])
|
2020-03-03 17:13:14 +05:30
|
|
|
|
return selected
|
|
|
|
|
|
|
|
|
|
|
2020-03-10 03:58:25 +05:30
|
|
|
|
def iterate(self,what):
|
2020-02-21 12:15:05 +05:30
|
|
|
|
"""
|
2021-01-13 19:27:58 +05:30
|
|
|
|
Iterate over visible items and view them independently.
|
2020-02-21 12:15:05 +05:30
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
|
|
|
|
what : str
|
2021-01-13 19:27:58 +05:30
|
|
|
|
Attribute to change (must be from self.visible).
|
2020-02-21 12:15:05 +05:30
|
|
|
|
|
|
|
|
|
"""
|
2021-01-13 19:27:58 +05:30
|
|
|
|
datasets = self.visible[what]
|
|
|
|
|
last_view = datasets.copy()
|
2020-02-21 12:15:05 +05:30
|
|
|
|
for dataset in datasets:
|
2021-01-13 19:27:58 +05:30
|
|
|
|
if last_view != self.visible[what]:
|
|
|
|
|
self._manage_view('set',what,datasets)
|
2020-03-03 11:19:46 +05:30
|
|
|
|
raise Exception
|
2021-01-13 19:27:58 +05:30
|
|
|
|
self._manage_view('set',what,dataset)
|
|
|
|
|
last_view = self.visible[what]
|
2020-03-03 11:19:46 +05:30
|
|
|
|
yield dataset
|
2021-01-13 19:27:58 +05:30
|
|
|
|
self._manage_view('set',what,datasets)
|
2020-02-15 19:43:56 +05:30
|
|
|
|
|
|
|
|
|
|
2021-01-13 19:27:58 +05:30
|
|
|
|
def view(self,what,datasets):
|
2020-02-21 12:15:05 +05:30
|
|
|
|
"""
|
2021-01-13 19:27:58 +05:30
|
|
|
|
Set view.
|
2020-02-15 19:43:56 +05:30
|
|
|
|
|
2020-02-21 12:15:05 +05:30
|
|
|
|
Parameters
|
|
|
|
|
----------
|
2020-03-03 04:17:29 +05:30
|
|
|
|
what : str
|
2021-02-26 07:50:28 +05:30
|
|
|
|
Attribute to change (must be from self.visible).
|
2020-04-21 02:21:51 +05:30
|
|
|
|
datasets : list of str or bool
|
2021-02-26 07:50:28 +05:30
|
|
|
|
Name of datasets as list; supports ? and * wildcards.
|
|
|
|
|
True is equivalent to [*], False is equivalent to [].
|
2020-02-15 19:43:56 +05:30
|
|
|
|
|
2020-02-21 12:15:05 +05:30
|
|
|
|
"""
|
2021-01-13 19:27:58 +05:30
|
|
|
|
self._manage_view('set',what,datasets)
|
2020-02-15 22:26:20 +05:30
|
|
|
|
|
|
|
|
|
|
2021-01-13 19:27:58 +05:30
|
|
|
|
def view_more(self,what,datasets):
|
2020-02-21 12:15:05 +05:30
|
|
|
|
"""
|
2021-01-13 19:27:58 +05:30
|
|
|
|
Add to view.
|
2020-02-15 22:26:20 +05:30
|
|
|
|
|
2020-02-21 12:15:05 +05:30
|
|
|
|
Parameters
|
|
|
|
|
----------
|
2020-03-03 04:17:29 +05:30
|
|
|
|
what : str
|
2021-02-26 07:50:28 +05:30
|
|
|
|
Attribute to change (must be from self.visible).
|
2020-04-21 02:21:51 +05:30
|
|
|
|
datasets : list of str or bool
|
2021-02-26 07:50:28 +05:30
|
|
|
|
Name of datasets as list; supports ? and * wildcards.
|
|
|
|
|
True is equivalent to [*], False is equivalent to [].
|
2020-02-15 22:26:20 +05:30
|
|
|
|
|
2020-02-21 12:15:05 +05:30
|
|
|
|
"""
|
2021-01-13 19:27:58 +05:30
|
|
|
|
self._manage_view('add',what,datasets)
|
2020-02-15 22:26:20 +05:30
|
|
|
|
|
|
|
|
|
|
2021-01-13 19:27:58 +05:30
|
|
|
|
def view_less(self,what,datasets):
|
2020-02-21 12:15:05 +05:30
|
|
|
|
"""
|
2021-01-13 19:27:58 +05:30
|
|
|
|
Delete from view.
|
2020-02-15 19:43:56 +05:30
|
|
|
|
|
2020-02-21 12:15:05 +05:30
|
|
|
|
Parameters
|
|
|
|
|
----------
|
2020-03-03 04:17:29 +05:30
|
|
|
|
what : str
|
2021-02-26 07:50:28 +05:30
|
|
|
|
Attribute to change (must be from self.visible).
|
2020-04-21 02:21:51 +05:30
|
|
|
|
datasets : list of str or bool
|
2021-02-26 07:50:28 +05:30
|
|
|
|
Name of datasets as list; supports ? and * wildcards.
|
|
|
|
|
True is equivalent to [*], False is equivalent to [].
|
2019-10-19 16:40:46 +05:30
|
|
|
|
|
2020-02-21 12:15:05 +05:30
|
|
|
|
"""
|
2021-01-13 19:27:58 +05:30
|
|
|
|
self._manage_view('del',what,datasets)
|
2020-02-15 19:43:56 +05:30
|
|
|
|
|
2020-05-30 16:17:36 +05:30
|
|
|
|
|
|
|
|
|
def rename(self,name_old,name_new):
|
|
|
|
|
"""
|
2021-02-26 07:50:28 +05:30
|
|
|
|
Rename dataset.
|
2020-06-25 01:04:51 +05:30
|
|
|
|
|
2020-06-02 01:43:01 +05:30
|
|
|
|
Parameters
|
|
|
|
|
----------
|
|
|
|
|
name_old : str
|
2021-02-26 07:50:28 +05:30
|
|
|
|
Name of the dataset to be renamed.
|
2020-06-02 01:43:01 +05:30
|
|
|
|
name_new : str
|
2021-02-26 07:50:28 +05:30
|
|
|
|
New name of the dataset.
|
2020-05-30 16:17:36 +05:30
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
if self._allow_modification:
|
|
|
|
|
with h5py.File(self.fname,'a') as f:
|
|
|
|
|
for path_old in self.get_dataset_location(name_old):
|
|
|
|
|
path_new = os.path.join(os.path.dirname(path_old),name_new)
|
|
|
|
|
f[path_new] = f[path_old]
|
2020-11-05 20:43:29 +05:30
|
|
|
|
f[path_new].attrs['Renamed'] = f'Original name: {name_old}' if h5py3 else \
|
2020-11-06 01:49:49 +05:30
|
|
|
|
f'Original name: {name_old}'.encode()
|
2020-05-30 16:17:36 +05:30
|
|
|
|
del f[path_old]
|
|
|
|
|
else:
|
2020-06-01 15:03:22 +05:30
|
|
|
|
raise PermissionError('Rename operation not permitted')
|
2020-05-30 16:17:36 +05:30
|
|
|
|
|
|
|
|
|
|
2020-11-19 02:21:37 +05:30
|
|
|
|
def place(self,datasets,constituent=0,tagged=False,split=True):
|
2020-03-10 03:58:25 +05:30
|
|
|
|
"""
|
|
|
|
|
Distribute datasets onto geometry and return Table or (split) dictionary of Tables.
|
2020-03-11 11:20:13 +05:30
|
|
|
|
|
2020-03-10 03:58:25 +05:30
|
|
|
|
Must not mix nodal end cell data.
|
2020-03-11 11:20:13 +05:30
|
|
|
|
|
2020-03-10 03:58:25 +05:30
|
|
|
|
Only data within
|
2020-11-18 19:22:16 +05:30
|
|
|
|
- inc*/phase/*/*
|
|
|
|
|
- inc*/homogenization/*/*
|
|
|
|
|
- inc*/geometry/*
|
2020-03-10 03:58:25 +05:30
|
|
|
|
are considered.
|
2020-03-11 11:20:13 +05:30
|
|
|
|
|
2020-03-10 03:58:25 +05:30
|
|
|
|
Parameters
|
|
|
|
|
----------
|
|
|
|
|
datasets : iterable or str
|
2020-11-19 02:21:37 +05:30
|
|
|
|
constituent : int
|
2021-02-26 07:50:28 +05:30
|
|
|
|
Constituent to consider for phase data.
|
2020-04-21 02:21:51 +05:30
|
|
|
|
tagged : bool
|
2021-02-26 07:50:28 +05:30
|
|
|
|
Tag Table.column name with '#constituent'.
|
|
|
|
|
Defaults to False.
|
2020-04-21 02:21:51 +05:30
|
|
|
|
split : bool
|
2021-02-26 07:50:28 +05:30
|
|
|
|
Split Table by increment and return dictionary of Tables.
|
|
|
|
|
Defaults to True.
|
2020-03-10 03:58:25 +05:30
|
|
|
|
|
|
|
|
|
"""
|
2020-11-18 19:22:16 +05:30
|
|
|
|
sets = datasets if hasattr(datasets,'__iter__') and not isinstance(datasets,str) else \
|
|
|
|
|
[datasets]
|
2020-11-19 04:00:39 +05:30
|
|
|
|
tag = f'#{constituent}' if tagged else ''
|
2020-03-10 03:58:25 +05:30
|
|
|
|
tbl = {} if split else None
|
|
|
|
|
inGeom = {}
|
|
|
|
|
inData = {}
|
2021-03-25 23:52:59 +05:30
|
|
|
|
# compatibility hack
|
|
|
|
|
name = 'Name' if self.version_minor < 12 else 'label'
|
|
|
|
|
member = 'Position' if self.version_minor < 12 else 'entry'
|
|
|
|
|
grp = 'mapping' if self.version_minor < 12 else 'cell_to'
|
2020-03-10 03:58:25 +05:30
|
|
|
|
with h5py.File(self.fname,'r') as f:
|
|
|
|
|
for dataset in sets:
|
|
|
|
|
for group in self.groups_with_datasets(dataset):
|
2021-03-10 08:32:49 +05:30
|
|
|
|
path = '/'.join([group,dataset])
|
2020-03-10 03:58:25 +05:30
|
|
|
|
inc,prop,name,cat,item = (path.split('/') + ['']*5)[:5]
|
|
|
|
|
key = '/'.join([prop,name+tag])
|
|
|
|
|
if key not in inGeom:
|
|
|
|
|
if prop == 'geometry':
|
2020-11-18 19:22:16 +05:30
|
|
|
|
inGeom[key] = inData[key] = np.arange(self.N_materialpoints)
|
|
|
|
|
elif prop == 'phase':
|
2021-03-25 23:52:59 +05:30
|
|
|
|
inGeom[key] = np.where(f[f'{grp}/phase'][:,constituent][name] == str.encode(name))[0]
|
|
|
|
|
inData[key] = f[f'{grp}/phase'][inGeom[key],constituent][member]
|
2020-11-18 19:22:16 +05:30
|
|
|
|
elif prop == 'homogenization':
|
2021-03-25 23:52:59 +05:30
|
|
|
|
inGeom[key] = np.where(f[f'{grp}/homogenization'][name] == str.encode(name))[0]
|
|
|
|
|
inData[key] = f[f'{grp}/homogenization'][inGeom[key].tolist()][member]
|
2020-03-10 03:58:25 +05:30
|
|
|
|
shape = np.shape(f[path])
|
2020-11-18 19:22:16 +05:30
|
|
|
|
data = np.full((self.N_materialpoints,) + (shape[1:] if len(shape)>1 else (1,)),
|
2020-03-22 21:33:28 +05:30
|
|
|
|
np.nan,
|
|
|
|
|
dtype=np.dtype(f[path]))
|
2020-03-10 03:58:25 +05:30
|
|
|
|
data[inGeom[key]] = (f[path] if len(shape)>1 else np.expand_dims(f[path],1))[inData[key]]
|
2021-03-10 08:32:49 +05:30
|
|
|
|
path = ('/'.join([prop,name]+([cat] if cat else [])+([item] if item else [])) if split else path)+tag
|
2020-03-10 03:58:25 +05:30
|
|
|
|
if split:
|
|
|
|
|
try:
|
2021-03-08 21:33:18 +05:30
|
|
|
|
tbl[inc] = tbl[inc].add(path,data)
|
2020-03-10 03:58:25 +05:30
|
|
|
|
except KeyError:
|
2020-11-18 19:22:16 +05:30
|
|
|
|
tbl[inc] = Table(data.reshape(self.N_materialpoints,-1),{path:data.shape[1:]})
|
2020-03-10 03:58:25 +05:30
|
|
|
|
else:
|
|
|
|
|
try:
|
2021-03-08 21:33:18 +05:30
|
|
|
|
tbl = tbl.add(path,data)
|
2020-03-10 03:58:25 +05:30
|
|
|
|
except AttributeError:
|
2020-11-18 19:22:16 +05:30
|
|
|
|
tbl = Table(data.reshape(self.N_materialpoints,-1),{path:data.shape[1:]})
|
2020-03-10 03:58:25 +05:30
|
|
|
|
|
|
|
|
|
return tbl
|
|
|
|
|
|
|
|
|
|
|
2020-02-21 12:15:05 +05:30
|
|
|
|
def groups_with_datasets(self,datasets):
|
|
|
|
|
"""
|
2020-03-03 17:13:14 +05:30
|
|
|
|
Return groups that contain all requested datasets.
|
2020-02-15 19:43:56 +05:30
|
|
|
|
|
2020-03-03 17:13:14 +05:30
|
|
|
|
Only groups within
|
2020-11-18 19:22:16 +05:30
|
|
|
|
- inc*/phase/*/*
|
|
|
|
|
- inc*/homogenization/*/*
|
2020-05-13 14:39:37 +05:30
|
|
|
|
- inc*/geometry/*
|
|
|
|
|
|
2020-03-03 17:13:14 +05:30
|
|
|
|
are considered as they contain user-relevant data.
|
2020-02-21 12:15:05 +05:30
|
|
|
|
Single strings will be treated as list with one entry.
|
2019-09-13 18:32:42 +05:30
|
|
|
|
|
2021-02-26 07:50:28 +05:30
|
|
|
|
Wild card matching is allowed, but the number of arguments needs to fit.
|
2020-02-15 19:43:56 +05:30
|
|
|
|
|
2020-02-21 12:15:05 +05:30
|
|
|
|
Parameters
|
|
|
|
|
----------
|
2020-04-21 02:21:51 +05:30
|
|
|
|
datasets : iterable or str or bool
|
2019-09-13 18:32:42 +05:30
|
|
|
|
|
2020-02-21 12:15:05 +05:30
|
|
|
|
Examples
|
|
|
|
|
--------
|
2020-03-19 12:15:31 +05:30
|
|
|
|
datasets = False matches no group
|
|
|
|
|
datasets = True matches all groups
|
|
|
|
|
datasets = ['F','P'] matches a group with ['F','P','sigma']
|
|
|
|
|
datasets = ['*','P'] matches a group with ['F','P']
|
|
|
|
|
datasets = ['*'] does not match a group with ['F','P','sigma']
|
|
|
|
|
datasets = ['*','*'] does not match a group with ['F','P','sigma']
|
|
|
|
|
datasets = ['*','*','*'] matches a group with ['F','P','sigma']
|
2020-02-15 19:43:56 +05:30
|
|
|
|
|
2020-02-21 12:15:05 +05:30
|
|
|
|
"""
|
|
|
|
|
if datasets is False: return []
|
2020-03-03 17:13:14 +05:30
|
|
|
|
|
2020-03-03 18:37:02 +05:30
|
|
|
|
sets = datasets if isinstance(datasets,bool) or (hasattr(datasets,'__iter__') and not isinstance(datasets,str)) else \
|
|
|
|
|
[datasets]
|
2019-09-12 06:27:24 +05:30
|
|
|
|
|
2020-02-21 12:15:05 +05:30
|
|
|
|
groups = []
|
2019-12-13 16:45:45 +05:30
|
|
|
|
|
2020-02-21 12:15:05 +05:30
|
|
|
|
with h5py.File(self.fname,'r') as f:
|
2020-03-10 03:58:25 +05:30
|
|
|
|
for i in self.iterate('increments'):
|
2020-11-18 19:22:16 +05:30
|
|
|
|
for o,p in zip(['phases','homogenizations'],['out_type_ph','out_type_ho']):
|
2020-03-22 20:43:35 +05:30
|
|
|
|
for oo in self.iterate(o):
|
|
|
|
|
for pp in self.iterate(p):
|
|
|
|
|
group = '/'.join([i,o[:-1],oo,pp]) # o[:-1]: plural/singular issue
|
|
|
|
|
if sets is True:
|
|
|
|
|
groups.append(group)
|
|
|
|
|
else:
|
2020-08-28 16:15:41 +05:30
|
|
|
|
if group in f.keys():
|
|
|
|
|
match = [e for e_ in [glob.fnmatch.filter(f[group].keys(),s) for s in sets] for e in e_]
|
|
|
|
|
if len(set(match)) == len(sets): groups.append(group)
|
2020-02-21 12:15:05 +05:30
|
|
|
|
return groups
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def list_data(self):
|
|
|
|
|
"""Return information on all active datasets in the file."""
|
2021-03-25 23:52:59 +05:30
|
|
|
|
# compatibility hack
|
|
|
|
|
de = 'Description' if self.version_minor < 12 else 'description'
|
|
|
|
|
un = 'Unit' if self.version_minor < 12 else 'unit'
|
2020-02-21 12:15:05 +05:30
|
|
|
|
message = ''
|
|
|
|
|
with h5py.File(self.fname,'r') as f:
|
2020-03-10 03:58:25 +05:30
|
|
|
|
for i in self.iterate('increments'):
|
2020-06-25 01:04:51 +05:30
|
|
|
|
message += f'\n{i} ({self.times[self.increments.index(i)]}s)\n'
|
2020-11-18 19:22:16 +05:30
|
|
|
|
for o,p in zip(['phases','homogenizations'],['out_type_ph','out_type_ho']):
|
2020-06-26 15:15:06 +05:30
|
|
|
|
message += f' {o[:-1]}\n'
|
2020-03-22 20:43:35 +05:30
|
|
|
|
for oo in self.iterate(o):
|
2020-06-26 15:15:06 +05:30
|
|
|
|
message += f' {oo}\n'
|
2020-03-22 20:43:35 +05:30
|
|
|
|
for pp in self.iterate(p):
|
2020-06-26 15:15:06 +05:30
|
|
|
|
message += f' {pp}\n'
|
2020-03-22 20:43:35 +05:30
|
|
|
|
group = '/'.join([i,o[:-1],oo,pp]) # o[:-1]: plural/singular issue
|
|
|
|
|
for d in f[group].keys():
|
|
|
|
|
try:
|
|
|
|
|
dataset = f['/'.join([group,d])]
|
2021-03-25 23:52:59 +05:30
|
|
|
|
if un in dataset.attrs:
|
|
|
|
|
unit = f" / {dataset.attrs[un]}" if h5py3 else \
|
|
|
|
|
f" / {dataset.attrs[un].decode()}"
|
2020-11-05 20:43:29 +05:30
|
|
|
|
else:
|
|
|
|
|
unit = ''
|
2021-03-25 23:52:59 +05:30
|
|
|
|
description = dataset.attrs[de] if h5py3 else \
|
|
|
|
|
dataset.attrs[de].decode()
|
2020-06-26 15:15:06 +05:30
|
|
|
|
message += f' {d}{unit}: {description}\n'
|
2020-03-22 20:43:35 +05:30
|
|
|
|
except KeyError:
|
|
|
|
|
pass
|
2020-02-21 12:15:05 +05:30
|
|
|
|
return message
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_dataset_location(self,label):
|
|
|
|
|
"""Return the location of all active datasets with given label."""
|
|
|
|
|
path = []
|
|
|
|
|
with h5py.File(self.fname,'r') as f:
|
2020-03-10 03:58:25 +05:30
|
|
|
|
for i in self.iterate('increments'):
|
2020-03-03 18:54:27 +05:30
|
|
|
|
k = '/'.join([i,'geometry',label])
|
|
|
|
|
try:
|
2020-02-21 12:15:05 +05:30
|
|
|
|
f[k]
|
|
|
|
|
path.append(k)
|
2020-03-22 20:43:35 +05:30
|
|
|
|
except KeyError:
|
2020-02-21 12:15:05 +05:30
|
|
|
|
pass
|
2020-11-18 19:22:16 +05:30
|
|
|
|
for o,p in zip(['phases','homogenizations'],['out_type_ph','out_type_ho']):
|
2020-03-10 03:58:25 +05:30
|
|
|
|
for oo in self.iterate(o):
|
|
|
|
|
for pp in self.iterate(p):
|
2020-03-03 18:54:27 +05:30
|
|
|
|
k = '/'.join([i,o[:-1],oo,pp,label])
|
|
|
|
|
try:
|
|
|
|
|
f[k]
|
|
|
|
|
path.append(k)
|
2020-03-22 20:43:35 +05:30
|
|
|
|
except KeyError:
|
2020-03-03 18:54:27 +05:30
|
|
|
|
pass
|
2020-02-21 12:15:05 +05:30
|
|
|
|
return path
|
|
|
|
|
|
|
|
|
|
|
2020-07-03 10:59:31 +05:30
|
|
|
|
def enable_user_function(self,func):
|
|
|
|
|
globals()[func.__name__]=func
|
|
|
|
|
print(f'Function {func.__name__} enabled in add_calculation.')
|
|
|
|
|
|
|
|
|
|
|
2020-02-21 12:15:05 +05:30
|
|
|
|
def read_dataset(self,path,c=0,plain=False):
|
|
|
|
|
"""
|
|
|
|
|
Dataset for all points/cells.
|
2020-02-15 19:43:56 +05:30
|
|
|
|
|
2020-02-21 12:15:05 +05:30
|
|
|
|
If more than one path is given, the dataset is composed of the individual contributions.
|
2020-11-19 18:15:40 +05:30
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
|
|
|
|
path : list of strings
|
|
|
|
|
The name of the datasets to consider.
|
|
|
|
|
c : int, optional
|
|
|
|
|
The constituent to consider. Defaults to 0.
|
|
|
|
|
plain: boolean, optional
|
|
|
|
|
Convert into plain numpy datatype.
|
|
|
|
|
Only relevant for compound datatype, e.g. the orientation.
|
|
|
|
|
Defaults to False.
|
|
|
|
|
|
2020-02-21 12:15:05 +05:30
|
|
|
|
"""
|
2021-03-25 23:52:59 +05:30
|
|
|
|
# compatibility hack
|
|
|
|
|
name = 'Name' if self.version_minor < 12 else 'label'
|
|
|
|
|
member = 'Position' if self.version_minor < 12 else 'entry'
|
|
|
|
|
grp = 'mapping' if self.version_minor < 12 else 'cell_to'
|
2020-02-21 12:15:05 +05:30
|
|
|
|
with h5py.File(self.fname,'r') as f:
|
2020-11-18 19:22:16 +05:30
|
|
|
|
shape = (self.N_materialpoints,) + np.shape(f[path[0]])[1:]
|
2020-03-22 20:43:35 +05:30
|
|
|
|
if len(shape) == 1: shape = shape +(1,)
|
|
|
|
|
dataset = np.full(shape,np.nan,dtype=np.dtype(f[path[0]]))
|
|
|
|
|
for pa in path:
|
|
|
|
|
label = pa.split('/')[2]
|
|
|
|
|
|
2020-03-22 21:33:28 +05:30
|
|
|
|
if pa.split('/')[1] == 'geometry':
|
2020-03-22 20:43:35 +05:30
|
|
|
|
dataset = np.array(f[pa])
|
|
|
|
|
continue
|
|
|
|
|
|
2021-03-25 23:52:59 +05:30
|
|
|
|
p = np.where(f[f'{grp}/phase'][:,c][name] == str.encode(label))[0]
|
2020-03-22 20:43:35 +05:30
|
|
|
|
if len(p)>0:
|
2021-03-25 23:52:59 +05:30
|
|
|
|
u = (f[f'{grp}/phase'][member][p,c])
|
2020-03-22 20:43:35 +05:30
|
|
|
|
a = np.array(f[pa])
|
|
|
|
|
if len(a.shape) == 1:
|
|
|
|
|
a=a.reshape([a.shape[0],1])
|
|
|
|
|
dataset[p,:] = a[u,:]
|
|
|
|
|
|
2021-03-25 23:52:59 +05:30
|
|
|
|
p = np.where(f[f'{grp}/homogenization'][name] == str.encode(label))[0]
|
2020-03-22 20:43:35 +05:30
|
|
|
|
if len(p)>0:
|
2021-03-25 23:52:59 +05:30
|
|
|
|
u = (f[f'{grp}/homogenization'][member][p.tolist()])
|
2020-03-22 20:43:35 +05:30
|
|
|
|
a = np.array(f[pa])
|
|
|
|
|
if len(a.shape) == 1:
|
|
|
|
|
a=a.reshape([a.shape[0],1])
|
|
|
|
|
dataset[p,:] = a[u,:]
|
2020-02-21 12:15:05 +05:30
|
|
|
|
|
|
|
|
|
if plain and dataset.dtype.names is not None:
|
2020-03-03 18:54:27 +05:30
|
|
|
|
return dataset.view(('float64',len(dataset.dtype.names)))
|
2020-02-21 12:15:05 +05:30
|
|
|
|
else:
|
2020-03-03 18:54:27 +05:30
|
|
|
|
return dataset
|
2020-02-21 12:15:05 +05:30
|
|
|
|
|
2020-07-31 20:20:01 +05:30
|
|
|
|
@property
|
2020-12-04 03:30:49 +05:30
|
|
|
|
def coordinates0_point(self):
|
2020-02-21 12:15:05 +05:30
|
|
|
|
"""Return initial coordinates of the cell centers."""
|
|
|
|
|
if self.structured:
|
2020-12-04 03:30:49 +05:30
|
|
|
|
return grid_filters.coordinates0_point(self.cells,self.size,self.origin).reshape(-1,3,order='F')
|
2020-02-21 12:15:05 +05:30
|
|
|
|
else:
|
2020-02-21 22:17:47 +05:30
|
|
|
|
with h5py.File(self.fname,'r') as f:
|
|
|
|
|
return f['geometry/x_c'][()]
|
2020-02-21 12:15:05 +05:30
|
|
|
|
|
2020-07-31 20:20:01 +05:30
|
|
|
|
@property
|
2020-12-04 03:30:49 +05:30
|
|
|
|
def coordinates0_node(self):
|
2020-04-22 11:10:02 +05:30
|
|
|
|
"""Return initial coordinates of the cell centers."""
|
|
|
|
|
if self.structured:
|
2020-12-04 03:30:49 +05:30
|
|
|
|
return grid_filters.coordinates0_node(self.cells,self.size,self.origin).reshape(-1,3,order='F')
|
2020-04-22 11:10:02 +05:30
|
|
|
|
else:
|
|
|
|
|
with h5py.File(self.fname,'r') as f:
|
|
|
|
|
return f['geometry/x_n'][()]
|
|
|
|
|
|
2020-02-21 12:15:05 +05:30
|
|
|
|
|
2020-02-21 23:54:26 +05:30
|
|
|
|
@staticmethod
|
|
|
|
|
def _add_absolute(x):
|
|
|
|
|
return {
|
|
|
|
|
'data': np.abs(x['data']),
|
2020-06-25 01:04:51 +05:30
|
|
|
|
'label': f'|{x["label"]}|',
|
2020-02-21 23:54:26 +05:30
|
|
|
|
'meta': {
|
2021-03-25 23:52:59 +05:30
|
|
|
|
'unit': x['meta']['unit'],
|
|
|
|
|
'description': f"absolute value of {x['label']} ({x['meta']['description']})",
|
|
|
|
|
'creator': 'add_absolute'
|
2020-02-21 23:54:26 +05:30
|
|
|
|
}
|
|
|
|
|
}
|
2020-02-21 12:15:05 +05:30
|
|
|
|
def add_absolute(self,x):
|
|
|
|
|
"""
|
|
|
|
|
Add absolute value.
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
|
|
|
|
x : str
|
2020-03-19 12:15:31 +05:30
|
|
|
|
Label of scalar, vector, or tensor dataset to take absolute value of.
|
2020-02-21 12:15:05 +05:30
|
|
|
|
|
|
|
|
|
"""
|
2020-02-22 02:07:02 +05:30
|
|
|
|
self._add_generic_pointwise(self._add_absolute,{'x':x})
|
2020-02-21 12:15:05 +05:30
|
|
|
|
|
|
|
|
|
|
2020-02-21 23:54:26 +05:30
|
|
|
|
@staticmethod
|
|
|
|
|
def _add_calculation(**kwargs):
|
|
|
|
|
formula = kwargs['formula']
|
|
|
|
|
for d in re.findall(r'#(.*?)#',formula):
|
2020-06-25 01:04:51 +05:30
|
|
|
|
formula = formula.replace(f'#{d}#',f"kwargs['{d}']['data']")
|
2020-02-21 12:15:05 +05:30
|
|
|
|
|
2020-02-21 23:54:26 +05:30
|
|
|
|
return {
|
|
|
|
|
'data': eval(formula),
|
|
|
|
|
'label': kwargs['label'],
|
|
|
|
|
'meta': {
|
2021-03-25 23:52:59 +05:30
|
|
|
|
'unit': kwargs['unit'],
|
|
|
|
|
'description': f"{kwargs['description']} (formula: {kwargs['formula']})",
|
|
|
|
|
'creator': 'add_calculation'
|
2020-02-21 23:54:26 +05:30
|
|
|
|
}
|
|
|
|
|
}
|
2020-07-31 20:34:14 +05:30
|
|
|
|
def add_calculation(self,label,formula,unit='n/a',description=None):
|
2020-02-21 12:15:05 +05:30
|
|
|
|
"""
|
|
|
|
|
Add result of a general formula.
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
|
|
|
|
label : str
|
2020-02-21 17:33:50 +05:30
|
|
|
|
Label of resulting dataset.
|
|
|
|
|
formula : str
|
2020-03-19 12:15:31 +05:30
|
|
|
|
Formula to calculate resulting dataset. Existing datasets are referenced by ‘#TheirLabel#‘.
|
2020-02-21 12:15:05 +05:30
|
|
|
|
unit : str, optional
|
2020-03-19 12:15:31 +05:30
|
|
|
|
Physical unit of the result.
|
2020-02-21 12:15:05 +05:30
|
|
|
|
description : str, optional
|
2020-03-19 12:15:31 +05:30
|
|
|
|
Human-readable description of the result.
|
2020-02-21 12:15:05 +05:30
|
|
|
|
|
|
|
|
|
"""
|
2020-02-21 23:54:26 +05:30
|
|
|
|
dataset_mapping = {d:d for d in set(re.findall(r'#(.*?)#',formula))} # datasets used in the formula
|
2020-02-21 12:15:05 +05:30
|
|
|
|
args = {'formula':formula,'label':label,'unit':unit,'description':description}
|
2020-02-22 02:07:02 +05:30
|
|
|
|
self._add_generic_pointwise(self._add_calculation,dataset_mapping,args)
|
2020-02-21 23:54:26 +05:30
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
2020-11-18 03:26:22 +05:30
|
|
|
|
def _add_stress_Cauchy(P,F):
|
2020-02-21 23:54:26 +05:30
|
|
|
|
return {
|
2020-11-18 03:26:22 +05:30
|
|
|
|
'data': mechanics.stress_Cauchy(P['data'],F['data']),
|
2020-02-21 23:54:26 +05:30
|
|
|
|
'label': 'sigma',
|
|
|
|
|
'meta': {
|
2021-03-25 23:52:59 +05:30
|
|
|
|
'unit': P['meta']['unit'],
|
|
|
|
|
'description': "Cauchy stress calculated "
|
|
|
|
|
f"from {P['label']} ({P['meta']['description']})"
|
|
|
|
|
f" and {F['label']} ({F['meta']['description']})",
|
|
|
|
|
'creator': 'add_stress_Cauchy'
|
2020-02-21 23:54:26 +05:30
|
|
|
|
}
|
|
|
|
|
}
|
2020-11-18 03:26:22 +05:30
|
|
|
|
def add_stress_Cauchy(self,P='P',F='F'):
|
2020-02-21 12:15:05 +05:30
|
|
|
|
"""
|
2020-02-21 17:33:50 +05:30
|
|
|
|
Add Cauchy stress calculated from first Piola-Kirchhoff stress and deformation gradient.
|
2020-02-21 12:15:05 +05:30
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
|
|
|
|
P : str, optional
|
2020-03-19 12:15:31 +05:30
|
|
|
|
Label of the dataset containing the first Piola-Kirchhoff stress. Defaults to ‘P’.
|
2020-02-21 12:15:05 +05:30
|
|
|
|
F : str, optional
|
2020-03-19 12:15:31 +05:30
|
|
|
|
Label of the dataset containing the deformation gradient. Defaults to ‘F’.
|
2020-02-21 12:15:05 +05:30
|
|
|
|
|
|
|
|
|
"""
|
2020-11-18 03:26:22 +05:30
|
|
|
|
self._add_generic_pointwise(self._add_stress_Cauchy,{'P':P,'F':F})
|
2020-02-21 12:15:05 +05:30
|
|
|
|
|
|
|
|
|
|
2020-02-21 23:54:26 +05:30
|
|
|
|
@staticmethod
|
|
|
|
|
def _add_determinant(T):
|
|
|
|
|
return {
|
|
|
|
|
'data': np.linalg.det(T['data']),
|
2020-06-25 01:04:51 +05:30
|
|
|
|
'label': f"det({T['label']})",
|
2020-02-21 23:54:26 +05:30
|
|
|
|
'meta': {
|
2021-03-25 23:52:59 +05:30
|
|
|
|
'unit': T['meta']['unit'],
|
|
|
|
|
'description': f"determinant of tensor {T['label']} ({T['meta']['description']})",
|
|
|
|
|
'creator': 'add_determinant'
|
2020-02-21 23:54:26 +05:30
|
|
|
|
}
|
|
|
|
|
}
|
2020-02-21 17:33:50 +05:30
|
|
|
|
def add_determinant(self,T):
|
2020-02-21 12:15:05 +05:30
|
|
|
|
"""
|
|
|
|
|
Add the determinant of a tensor.
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
2020-02-21 17:33:50 +05:30
|
|
|
|
T : str
|
2020-03-19 12:15:31 +05:30
|
|
|
|
Label of tensor dataset.
|
2020-02-21 12:15:05 +05:30
|
|
|
|
|
|
|
|
|
"""
|
2020-02-22 02:07:02 +05:30
|
|
|
|
self._add_generic_pointwise(self._add_determinant,{'T':T})
|
2020-02-21 12:15:05 +05:30
|
|
|
|
|
|
|
|
|
|
2020-02-21 23:54:26 +05:30
|
|
|
|
@staticmethod
|
|
|
|
|
def _add_deviator(T):
|
|
|
|
|
return {
|
2020-11-19 19:08:54 +05:30
|
|
|
|
'data': tensor.deviatoric(T['data']),
|
2020-06-25 01:04:51 +05:30
|
|
|
|
'label': f"s_{T['label']}",
|
2020-02-21 23:54:26 +05:30
|
|
|
|
'meta': {
|
2021-03-25 23:52:59 +05:30
|
|
|
|
'unit': T['meta']['unit'],
|
|
|
|
|
'description': f"deviator of tensor {T['label']} ({T['meta']['description']})",
|
|
|
|
|
'creator': 'add_deviator'
|
2020-02-21 23:54:26 +05:30
|
|
|
|
}
|
|
|
|
|
}
|
2020-02-21 17:33:50 +05:30
|
|
|
|
def add_deviator(self,T):
|
2020-02-21 12:15:05 +05:30
|
|
|
|
"""
|
|
|
|
|
Add the deviatoric part of a tensor.
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
2020-02-21 17:33:50 +05:30
|
|
|
|
T : str
|
2020-03-19 12:15:31 +05:30
|
|
|
|
Label of tensor dataset.
|
2020-02-21 12:15:05 +05:30
|
|
|
|
|
|
|
|
|
"""
|
2020-02-22 02:07:02 +05:30
|
|
|
|
self._add_generic_pointwise(self._add_deviator,{'T':T})
|
2020-02-21 12:15:05 +05:30
|
|
|
|
|
|
|
|
|
|
2020-02-21 23:54:26 +05:30
|
|
|
|
@staticmethod
|
2020-05-27 21:06:30 +05:30
|
|
|
|
def _add_eigenvalue(T_sym,eigenvalue):
|
|
|
|
|
if eigenvalue == 'max':
|
2021-03-25 23:52:59 +05:30
|
|
|
|
label,p = 'maximum',2
|
2020-05-27 21:06:30 +05:30
|
|
|
|
elif eigenvalue == 'mid':
|
2021-03-25 23:52:59 +05:30
|
|
|
|
label,p = 'intermediate',1
|
2020-05-27 21:06:30 +05:30
|
|
|
|
elif eigenvalue == 'min':
|
2021-03-25 23:52:59 +05:30
|
|
|
|
label,p = 'minimum',0
|
2020-05-27 21:06:30 +05:30
|
|
|
|
|
2020-02-21 23:54:26 +05:30
|
|
|
|
return {
|
2020-11-16 03:44:46 +05:30
|
|
|
|
'data': tensor.eigenvalues(T_sym['data'])[:,p],
|
2020-06-25 01:04:51 +05:30
|
|
|
|
'label': f"lambda_{eigenvalue}({T_sym['label']})",
|
2020-02-21 23:54:26 +05:30
|
|
|
|
'meta' : {
|
2021-03-25 23:52:59 +05:30
|
|
|
|
'unit': T_sym['meta']['unit'],
|
|
|
|
|
'description': f"{label} eigenvalue of {T_sym['label']} ({T_sym['meta']['description']})",
|
|
|
|
|
'creator': 'add_eigenvalue'
|
2020-02-21 23:54:26 +05:30
|
|
|
|
}
|
|
|
|
|
}
|
2020-05-27 21:06:30 +05:30
|
|
|
|
def add_eigenvalue(self,T_sym,eigenvalue='max'):
|
2020-02-21 12:15:05 +05:30
|
|
|
|
"""
|
|
|
|
|
Add eigenvalues of symmetric tensor.
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
2020-03-03 03:44:59 +05:30
|
|
|
|
T_sym : str
|
2020-03-19 12:15:31 +05:30
|
|
|
|
Label of symmetric tensor dataset.
|
2020-05-27 21:06:30 +05:30
|
|
|
|
eigenvalue : str, optional
|
|
|
|
|
Eigenvalue. Select from ‘max’, ‘mid’, ‘min’. Defaults to ‘max’.
|
2020-02-21 12:15:05 +05:30
|
|
|
|
|
|
|
|
|
"""
|
2020-05-27 21:06:30 +05:30
|
|
|
|
self._add_generic_pointwise(self._add_eigenvalue,{'T_sym':T_sym},{'eigenvalue':eigenvalue})
|
2020-02-21 12:15:05 +05:30
|
|
|
|
|
|
|
|
|
|
2020-02-21 23:54:26 +05:30
|
|
|
|
@staticmethod
|
2020-05-27 21:06:30 +05:30
|
|
|
|
def _add_eigenvector(T_sym,eigenvalue):
|
|
|
|
|
if eigenvalue == 'max':
|
|
|
|
|
label,p = 'maximum',2
|
|
|
|
|
elif eigenvalue == 'mid':
|
|
|
|
|
label,p = 'intermediate',1
|
|
|
|
|
elif eigenvalue == 'min':
|
|
|
|
|
label,p = 'minimum',0
|
2020-02-21 23:54:26 +05:30
|
|
|
|
return {
|
2020-11-16 03:44:46 +05:30
|
|
|
|
'data': tensor.eigenvectors(T_sym['data'])[:,p],
|
2020-06-25 01:04:51 +05:30
|
|
|
|
'label': f"v_{eigenvalue}({T_sym['label']})",
|
2020-02-21 23:54:26 +05:30
|
|
|
|
'meta' : {
|
2021-03-25 23:52:59 +05:30
|
|
|
|
'unit': '1',
|
|
|
|
|
'description': f"eigenvector corresponding to {label} eigenvalue"
|
|
|
|
|
f" of {T_sym['label']} ({T_sym['meta']['description']})",
|
|
|
|
|
'creator': 'add_eigenvector'
|
2020-02-21 23:54:26 +05:30
|
|
|
|
}
|
2020-06-25 01:04:51 +05:30
|
|
|
|
}
|
2020-05-27 21:06:30 +05:30
|
|
|
|
def add_eigenvector(self,T_sym,eigenvalue='max'):
|
2020-02-21 12:15:05 +05:30
|
|
|
|
"""
|
2020-05-27 21:06:30 +05:30
|
|
|
|
Add eigenvector of symmetric tensor.
|
2020-02-21 12:15:05 +05:30
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
2020-03-03 03:44:59 +05:30
|
|
|
|
T_sym : str
|
2020-03-19 12:15:31 +05:30
|
|
|
|
Label of symmetric tensor dataset.
|
2020-05-27 21:06:30 +05:30
|
|
|
|
eigenvalue : str, optional
|
|
|
|
|
Eigenvalue to which the eigenvector corresponds. Select from
|
|
|
|
|
‘max’, ‘mid’, ‘min’. Defaults to ‘max’.
|
2020-02-21 12:15:05 +05:30
|
|
|
|
|
|
|
|
|
"""
|
2020-05-27 21:06:30 +05:30
|
|
|
|
self._add_generic_pointwise(self._add_eigenvector,{'T_sym':T_sym},{'eigenvalue':eigenvalue})
|
2020-02-21 12:15:05 +05:30
|
|
|
|
|
|
|
|
|
|
2020-02-21 23:54:26 +05:30
|
|
|
|
@staticmethod
|
2020-12-02 19:15:47 +05:30
|
|
|
|
def _add_IPF_color(l,q):
|
2020-06-20 20:45:13 +05:30
|
|
|
|
m = util.scale_to_coprime(np.array(l))
|
2020-11-29 03:07:03 +05:30
|
|
|
|
try:
|
2021-03-25 23:52:59 +05:30
|
|
|
|
lattice = {'fcc':'cF','bcc':'cI','hex':'hP'}[q['meta']['lattice']]
|
2020-11-29 03:07:03 +05:30
|
|
|
|
except KeyError:
|
2021-03-25 23:52:59 +05:30
|
|
|
|
lattice = q['meta']['lattice']
|
2020-12-06 13:02:45 +05:30
|
|
|
|
try:
|
|
|
|
|
o = Orientation(rotation = (rfn.structured_to_unstructured(q['data'])),lattice=lattice)
|
|
|
|
|
except ValueError:
|
|
|
|
|
o = Orientation(rotation = q['data'],lattice=lattice)
|
2020-02-21 23:54:26 +05:30
|
|
|
|
|
|
|
|
|
return {
|
2020-11-18 21:15:53 +05:30
|
|
|
|
'data': np.uint8(o.IPF_color(l)*255),
|
2020-02-21 23:54:26 +05:30
|
|
|
|
'label': 'IPFcolor_[{} {} {}]'.format(*m),
|
|
|
|
|
'meta' : {
|
2021-03-25 23:52:59 +05:30
|
|
|
|
'unit': '8-bit RGB',
|
|
|
|
|
'lattice': q['meta']['lattice'],
|
|
|
|
|
'description': 'Inverse Pole Figure (IPF) colors along sample direction [{} {} {}]'.format(*m),
|
|
|
|
|
'creator': 'add_IPF_color'
|
2020-02-21 23:54:26 +05:30
|
|
|
|
}
|
|
|
|
|
}
|
2020-12-02 19:15:47 +05:30
|
|
|
|
def add_IPF_color(self,l,q='O'):
|
2020-02-21 12:15:05 +05:30
|
|
|
|
"""
|
|
|
|
|
Add RGB color tuple of inverse pole figure (IPF) color.
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
2020-02-21 22:12:01 +05:30
|
|
|
|
l : numpy.array of shape (3)
|
2020-03-19 12:15:31 +05:30
|
|
|
|
Lab frame direction for inverse pole figure.
|
2020-12-02 19:15:47 +05:30
|
|
|
|
q : str
|
|
|
|
|
Label of the dataset containing the crystallographic orientation as quaternions.
|
|
|
|
|
Defaults to 'O'.
|
2020-02-21 12:15:05 +05:30
|
|
|
|
|
|
|
|
|
"""
|
2020-07-01 01:13:57 +05:30
|
|
|
|
self._add_generic_pointwise(self._add_IPF_color,{'q':q},{'l':l})
|
2020-02-21 12:15:05 +05:30
|
|
|
|
|
|
|
|
|
|
2020-02-21 23:54:26 +05:30
|
|
|
|
@staticmethod
|
2020-03-03 03:44:59 +05:30
|
|
|
|
def _add_maximum_shear(T_sym):
|
2020-02-21 23:54:26 +05:30
|
|
|
|
return {
|
2020-03-03 03:44:59 +05:30
|
|
|
|
'data': mechanics.maximum_shear(T_sym['data']),
|
2020-06-25 01:04:51 +05:30
|
|
|
|
'label': f"max_shear({T_sym['label']})",
|
2020-02-21 23:54:26 +05:30
|
|
|
|
'meta': {
|
2021-03-25 23:52:59 +05:30
|
|
|
|
'unit': T_sym['meta']['unit'],
|
|
|
|
|
'description': f"maximum shear component of {T_sym['label']} ({T_sym['meta']['description']})",
|
|
|
|
|
'creator': 'add_maximum_shear'
|
2020-02-21 23:54:26 +05:30
|
|
|
|
}
|
2020-02-21 12:15:05 +05:30
|
|
|
|
}
|
2020-03-03 03:44:59 +05:30
|
|
|
|
def add_maximum_shear(self,T_sym):
|
2020-02-21 12:15:05 +05:30
|
|
|
|
"""
|
|
|
|
|
Add maximum shear components of symmetric tensor.
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
2020-03-03 03:44:59 +05:30
|
|
|
|
T_sym : str
|
2020-03-19 12:15:31 +05:30
|
|
|
|
Label of symmetric tensor dataset.
|
2020-02-21 12:15:05 +05:30
|
|
|
|
|
|
|
|
|
"""
|
2020-03-03 03:44:59 +05:30
|
|
|
|
self._add_generic_pointwise(self._add_maximum_shear,{'T_sym':T_sym})
|
2020-02-21 12:15:05 +05:30
|
|
|
|
|
|
|
|
|
|
2020-02-21 23:54:26 +05:30
|
|
|
|
@staticmethod
|
2020-11-18 03:26:22 +05:30
|
|
|
|
def _add_equivalent_Mises(T_sym,kind):
|
2020-11-06 04:17:37 +05:30
|
|
|
|
k = kind
|
|
|
|
|
if k is None:
|
2021-03-25 23:52:59 +05:30
|
|
|
|
if T_sym['meta']['unit'] == '1':
|
2020-11-05 10:18:12 +05:30
|
|
|
|
k = 'strain'
|
2021-03-25 23:52:59 +05:30
|
|
|
|
elif T_sym['meta']['unit'] == 'Pa':
|
2020-11-05 10:18:12 +05:30
|
|
|
|
k = 'stress'
|
|
|
|
|
if k not in ['stress', 'strain']:
|
|
|
|
|
raise ValueError('invalid von Mises kind {kind}')
|
2020-02-21 12:15:05 +05:30
|
|
|
|
|
2020-02-21 23:54:26 +05:30
|
|
|
|
return {
|
2020-11-18 03:26:22 +05:30
|
|
|
|
'data': (mechanics.equivalent_strain_Mises if k=='strain' else \
|
|
|
|
|
mechanics.equivalent_stress_Mises)(T_sym['data']),
|
2020-06-25 01:04:51 +05:30
|
|
|
|
'label': f"{T_sym['label']}_vM",
|
2020-02-21 23:54:26 +05:30
|
|
|
|
'meta': {
|
2021-03-25 23:52:59 +05:30
|
|
|
|
'unit': T_sym['meta']['unit'],
|
|
|
|
|
'description': f"Mises equivalent {k} of {T_sym['label']} ({T_sym['meta']['description']})",
|
|
|
|
|
'creator': 'add_Mises'
|
2020-02-21 23:54:26 +05:30
|
|
|
|
}
|
|
|
|
|
}
|
2020-11-18 03:26:22 +05:30
|
|
|
|
def add_equivalent_Mises(self,T_sym,kind=None):
|
2020-02-21 12:15:05 +05:30
|
|
|
|
"""
|
|
|
|
|
Add the equivalent Mises stress or strain of a symmetric tensor.
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
2020-03-03 03:44:59 +05:30
|
|
|
|
T_sym : str
|
2020-03-19 12:15:31 +05:30
|
|
|
|
Label of symmetric tensorial stress or strain dataset.
|
2020-11-05 10:18:12 +05:30
|
|
|
|
kind : {'stress', 'strain', None}, optional
|
|
|
|
|
Kind of the von Mises equivalent. Defaults to None, in which case
|
|
|
|
|
it is selected based on the unit of the dataset ('1' -> strain, 'Pa' -> stress').
|
2020-02-21 12:15:05 +05:30
|
|
|
|
|
|
|
|
|
"""
|
2020-11-18 03:26:22 +05:30
|
|
|
|
self._add_generic_pointwise(self._add_equivalent_Mises,{'T_sym':T_sym},{'kind':kind})
|
2020-02-21 12:15:05 +05:30
|
|
|
|
|
|
|
|
|
|
2020-02-21 23:54:26 +05:30
|
|
|
|
@staticmethod
|
|
|
|
|
def _add_norm(x,ord):
|
|
|
|
|
o = ord
|
|
|
|
|
if len(x['data'].shape) == 2:
|
|
|
|
|
axis = 1
|
|
|
|
|
t = 'vector'
|
|
|
|
|
if o is None: o = 2
|
|
|
|
|
elif len(x['data'].shape) == 3:
|
|
|
|
|
axis = (1,2)
|
|
|
|
|
t = 'tensor'
|
|
|
|
|
if o is None: o = 'fro'
|
|
|
|
|
else:
|
|
|
|
|
raise ValueError
|
2020-02-21 12:15:05 +05:30
|
|
|
|
|
2020-02-21 23:54:26 +05:30
|
|
|
|
return {
|
|
|
|
|
'data': np.linalg.norm(x['data'],ord=o,axis=axis,keepdims=True),
|
2020-06-25 01:04:51 +05:30
|
|
|
|
'label': f"|{x['label']}|_{o}",
|
2020-02-21 23:54:26 +05:30
|
|
|
|
'meta': {
|
2021-03-25 23:52:59 +05:30
|
|
|
|
'unit': x['meta']['unit'],
|
|
|
|
|
'description': f"{o}-norm of {t} {x['label']} ({x['meta']['description']})",
|
|
|
|
|
'creator': 'add_norm'
|
2020-02-21 23:54:26 +05:30
|
|
|
|
}
|
|
|
|
|
}
|
2020-02-21 12:15:05 +05:30
|
|
|
|
def add_norm(self,x,ord=None):
|
|
|
|
|
"""
|
|
|
|
|
Add the norm of vector or tensor.
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
|
|
|
|
x : str
|
2020-03-19 12:15:31 +05:30
|
|
|
|
Label of vector or tensor dataset.
|
2020-02-21 12:15:05 +05:30
|
|
|
|
ord : {non-zero int, inf, -inf, ‘fro’, ‘nuc’}, optional
|
2020-03-19 12:15:31 +05:30
|
|
|
|
Order of the norm. inf means NumPy’s inf object. For details refer to numpy.linalg.norm.
|
2020-02-21 12:15:05 +05:30
|
|
|
|
|
|
|
|
|
"""
|
2020-02-22 02:07:02 +05:30
|
|
|
|
self._add_generic_pointwise(self._add_norm,{'x':x},{'ord':ord})
|
2020-02-21 12:15:05 +05:30
|
|
|
|
|
|
|
|
|
|
2020-02-21 23:54:26 +05:30
|
|
|
|
@staticmethod
|
2020-11-18 03:26:22 +05:30
|
|
|
|
def _add_stress_second_Piola_Kirchhoff(P,F):
|
2020-02-21 23:54:26 +05:30
|
|
|
|
return {
|
2020-11-18 03:26:22 +05:30
|
|
|
|
'data': mechanics.stress_second_Piola_Kirchhoff(P['data'],F['data']),
|
2020-02-21 23:54:26 +05:30
|
|
|
|
'label': 'S',
|
|
|
|
|
'meta': {
|
2021-03-25 23:52:59 +05:30
|
|
|
|
'unit': P['meta']['unit'],
|
|
|
|
|
'description': "second Piola-Kirchhoff stress calculated "
|
|
|
|
|
f"from {P['label']} ({P['meta']['description']})"
|
|
|
|
|
f" and {F['label']} ({F['meta']['description']})",
|
|
|
|
|
'creator': 'add_stress_second_Piola_Kirchhoff'
|
2020-02-21 23:54:26 +05:30
|
|
|
|
}
|
|
|
|
|
}
|
2020-11-18 03:26:22 +05:30
|
|
|
|
def add_stress_second_Piola_Kirchhoff(self,P='P',F='F'):
|
2020-02-21 12:15:05 +05:30
|
|
|
|
"""
|
2020-06-25 01:04:51 +05:30
|
|
|
|
Add second Piola-Kirchhoff stress calculated from first Piola-Kirchhoff stress and deformation gradient.
|
2020-02-21 12:15:05 +05:30
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
|
|
|
|
P : str, optional
|
2020-06-25 01:04:51 +05:30
|
|
|
|
Label of first Piola-Kirchhoff stress dataset. Defaults to ‘P’.
|
2020-02-21 12:15:05 +05:30
|
|
|
|
F : str, optional
|
2020-03-19 12:15:31 +05:30
|
|
|
|
Label of deformation gradient dataset. Defaults to ‘F’.
|
2020-02-21 12:15:05 +05:30
|
|
|
|
|
|
|
|
|
"""
|
2020-11-18 03:26:22 +05:30
|
|
|
|
self._add_generic_pointwise(self._add_stress_second_Piola_Kirchhoff,{'P':P,'F':F})
|
2020-02-21 12:15:05 +05:30
|
|
|
|
|
|
|
|
|
|
2020-11-10 01:50:56 +05:30
|
|
|
|
# The add_pole functionality needs discussion.
|
|
|
|
|
# The new Crystal object can perform such a calculation but the outcome depends on the lattice parameters
|
|
|
|
|
# as well as on whether a direction or plane is concerned (see the DAMASK_examples/pole_figure notebook).
|
|
|
|
|
# Below code appears to be too simplistic.
|
|
|
|
|
|
|
|
|
|
# @staticmethod
|
|
|
|
|
# def _add_pole(q,p,polar):
|
|
|
|
|
# pole = np.array(p)
|
|
|
|
|
# unit_pole = pole/np.linalg.norm(pole)
|
|
|
|
|
# m = util.scale_to_coprime(pole)
|
|
|
|
|
# rot = Rotation(q['data'].view(np.double).reshape(-1,4))
|
|
|
|
|
#
|
|
|
|
|
# rotatedPole = rot @ np.broadcast_to(unit_pole,rot.shape+(3,)) # rotate pole according to crystal orientation
|
|
|
|
|
# xy = rotatedPole[:,0:2]/(1.+abs(unit_pole[2])) # stereographic projection
|
|
|
|
|
# coords = xy if not polar else \
|
|
|
|
|
# np.block([np.sqrt(xy[:,0:1]*xy[:,0:1]+xy[:,1:2]*xy[:,1:2]),np.arctan2(xy[:,1:2],xy[:,0:1])])
|
|
|
|
|
# return {
|
|
|
|
|
# 'data': coords,
|
|
|
|
|
# 'label': 'p^{}_[{} {} {})'.format(u'rφ' if polar else 'xy',*m),
|
|
|
|
|
# 'meta' : {
|
2021-03-25 23:52:59 +05:30
|
|
|
|
# 'unit': '1',
|
|
|
|
|
# 'description': '{} coordinates of stereographic projection of pole (direction/plane) in crystal frame'\
|
2020-11-10 01:50:56 +05:30
|
|
|
|
# .format('Polar' if polar else 'Cartesian'),
|
2021-03-25 23:52:59 +05:30
|
|
|
|
# 'creator': 'add_pole'
|
2020-11-10 01:50:56 +05:30
|
|
|
|
# }
|
|
|
|
|
# }
|
|
|
|
|
# def add_pole(self,q,p,polar=False):
|
|
|
|
|
# """
|
|
|
|
|
# Add coordinates of stereographic projection of given pole in crystal frame.
|
|
|
|
|
#
|
|
|
|
|
# Parameters
|
|
|
|
|
# ----------
|
|
|
|
|
# q : str
|
|
|
|
|
# Label of the dataset containing the crystallographic orientation as quaternions.
|
|
|
|
|
# p : numpy.array of shape (3)
|
|
|
|
|
# Crystallographic direction or plane.
|
|
|
|
|
# polar : bool, optional
|
|
|
|
|
# Give pole in polar coordinates. Defaults to False.
|
|
|
|
|
#
|
|
|
|
|
# """
|
|
|
|
|
# self._add_generic_pointwise(self._add_pole,{'q':q},{'p':p,'polar':polar})
|
2020-02-21 12:15:05 +05:30
|
|
|
|
|
|
|
|
|
|
2020-02-21 23:54:26 +05:30
|
|
|
|
@staticmethod
|
2020-11-20 03:16:52 +05:30
|
|
|
|
def _add_rotation(F):
|
2020-02-21 23:54:26 +05:30
|
|
|
|
return {
|
2020-11-20 03:16:52 +05:30
|
|
|
|
'data': mechanics.rotation(F['data']).as_matrix(),
|
2020-06-25 01:04:51 +05:30
|
|
|
|
'label': f"R({F['label']})",
|
2020-02-21 23:54:26 +05:30
|
|
|
|
'meta': {
|
2021-03-25 23:52:59 +05:30
|
|
|
|
'unit': F['meta']['unit'],
|
|
|
|
|
'description': f"rotational part of {F['label']} ({F['meta']['description']})",
|
|
|
|
|
'creator': 'add_rotation'
|
2020-02-21 23:54:26 +05:30
|
|
|
|
}
|
2020-02-21 12:15:05 +05:30
|
|
|
|
}
|
2020-11-20 03:16:52 +05:30
|
|
|
|
def add_rotation(self,F):
|
2020-02-21 12:15:05 +05:30
|
|
|
|
"""
|
|
|
|
|
Add rotational part of a deformation gradient.
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
2020-02-21 17:33:50 +05:30
|
|
|
|
F : str, optional
|
2020-03-19 12:15:31 +05:30
|
|
|
|
Label of deformation gradient dataset.
|
2020-02-21 12:15:05 +05:30
|
|
|
|
|
|
|
|
|
"""
|
2020-11-20 03:16:52 +05:30
|
|
|
|
self._add_generic_pointwise(self._add_rotation,{'F':F})
|
2020-02-21 12:15:05 +05:30
|
|
|
|
|
|
|
|
|
|
2020-02-21 23:54:26 +05:30
|
|
|
|
@staticmethod
|
|
|
|
|
def _add_spherical(T):
|
|
|
|
|
return {
|
2020-11-19 19:08:54 +05:30
|
|
|
|
'data': tensor.spherical(T['data'],False),
|
2020-06-25 01:04:51 +05:30
|
|
|
|
'label': f"p_{T['label']}",
|
2020-02-21 23:54:26 +05:30
|
|
|
|
'meta': {
|
2021-03-25 23:52:59 +05:30
|
|
|
|
'unit': T['meta']['unit'],
|
|
|
|
|
'description': f"spherical component of tensor {T['label']} ({T['meta']['description']})",
|
|
|
|
|
'creator': 'add_spherical'
|
2020-02-21 23:54:26 +05:30
|
|
|
|
}
|
|
|
|
|
}
|
2020-02-21 17:33:50 +05:30
|
|
|
|
def add_spherical(self,T):
|
2020-02-21 12:15:05 +05:30
|
|
|
|
"""
|
|
|
|
|
Add the spherical (hydrostatic) part of a tensor.
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
2020-02-21 17:33:50 +05:30
|
|
|
|
T : str
|
2020-03-19 12:15:31 +05:30
|
|
|
|
Label of tensor dataset.
|
2020-02-21 12:15:05 +05:30
|
|
|
|
|
|
|
|
|
"""
|
2020-02-22 02:07:02 +05:30
|
|
|
|
self._add_generic_pointwise(self._add_spherical,{'T':T})
|
2020-02-21 12:15:05 +05:30
|
|
|
|
|
|
|
|
|
|
2020-02-21 23:54:26 +05:30
|
|
|
|
@staticmethod
|
2020-11-16 05:42:23 +05:30
|
|
|
|
def _add_strain(F,t,m):
|
2020-02-21 23:54:26 +05:30
|
|
|
|
return {
|
2020-11-16 05:42:23 +05:30
|
|
|
|
'data': mechanics.strain(F['data'],t,m),
|
2020-06-25 01:04:51 +05:30
|
|
|
|
'label': f"epsilon_{t}^{m}({F['label']})",
|
2020-02-21 23:54:26 +05:30
|
|
|
|
'meta': {
|
2021-03-25 23:52:59 +05:30
|
|
|
|
'unit': F['meta']['unit'],
|
|
|
|
|
'description': f"strain tensor of {F['label']} ({F['meta']['description']})",
|
|
|
|
|
'creator': 'add_strain'
|
2020-02-21 23:54:26 +05:30
|
|
|
|
}
|
|
|
|
|
}
|
2020-11-16 05:42:23 +05:30
|
|
|
|
def add_strain(self,F='F',t='V',m=0.0):
|
2020-02-21 12:15:05 +05:30
|
|
|
|
"""
|
2020-02-21 17:33:50 +05:30
|
|
|
|
Add strain tensor of a deformation gradient.
|
2020-02-21 12:15:05 +05:30
|
|
|
|
|
2020-11-16 05:42:23 +05:30
|
|
|
|
For details refer to damask.mechanics.strain
|
2020-02-21 12:15:05 +05:30
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
|
|
|
|
F : str, optional
|
2020-03-19 12:15:31 +05:30
|
|
|
|
Label of deformation gradient dataset. Defaults to ‘F’.
|
2020-02-21 12:15:05 +05:30
|
|
|
|
t : {‘V’, ‘U’}, optional
|
2020-03-19 12:15:31 +05:30
|
|
|
|
Type of the polar decomposition, ‘V’ for left stretch tensor and ‘U’ for right stretch tensor.
|
|
|
|
|
Defaults to ‘V’.
|
2020-02-21 12:15:05 +05:30
|
|
|
|
m : float, optional
|
2020-03-19 12:15:31 +05:30
|
|
|
|
Order of the strain calculation. Defaults to ‘0.0’.
|
2020-02-21 12:15:05 +05:30
|
|
|
|
|
|
|
|
|
"""
|
2020-11-16 05:42:23 +05:30
|
|
|
|
self._add_generic_pointwise(self._add_strain,{'F':F},{'t':t,'m':m})
|
2020-02-21 12:15:05 +05:30
|
|
|
|
|
|
|
|
|
|
2020-02-21 23:54:26 +05:30
|
|
|
|
@staticmethod
|
|
|
|
|
def _add_stretch_tensor(F,t):
|
|
|
|
|
return {
|
2020-11-16 05:31:32 +05:30
|
|
|
|
'data': (mechanics.stretch_left if t.upper() == 'V' else mechanics.stretch_right)(F['data']),
|
2020-06-25 01:04:51 +05:30
|
|
|
|
'label': f"{t}({F['label']})",
|
2020-02-21 23:54:26 +05:30
|
|
|
|
'meta': {
|
2021-03-25 23:52:59 +05:30
|
|
|
|
'unit': F['meta']['unit'],
|
|
|
|
|
'description': '{} stretch tensor of {} ({})'.format('left' if t.upper() == 'V' else 'right',
|
|
|
|
|
F['label'],F['meta']['description']),
|
|
|
|
|
'creator': 'add_stretch_tensor'
|
2020-02-21 23:54:26 +05:30
|
|
|
|
}
|
|
|
|
|
}
|
2020-02-21 17:33:50 +05:30
|
|
|
|
def add_stretch_tensor(self,F='F',t='V'):
|
2020-02-21 12:15:05 +05:30
|
|
|
|
"""
|
2020-02-21 17:33:50 +05:30
|
|
|
|
Add stretch tensor of a deformation gradient.
|
2020-02-21 12:15:05 +05:30
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
|
|
|
|
F : str, optional
|
2020-03-19 12:15:31 +05:30
|
|
|
|
Label of deformation gradient dataset. Defaults to ‘F’.
|
2020-02-21 12:15:05 +05:30
|
|
|
|
t : {‘V’, ‘U’}, optional
|
2020-03-19 12:15:31 +05:30
|
|
|
|
Type of the polar decomposition, ‘V’ for left stretch tensor and ‘U’ for right stretch tensor.
|
|
|
|
|
Defaults to ‘V’.
|
2020-02-21 12:15:05 +05:30
|
|
|
|
|
|
|
|
|
"""
|
2020-02-22 02:07:02 +05:30
|
|
|
|
self._add_generic_pointwise(self._add_stretch_tensor,{'F':F},{'t':t})
|
2020-02-21 23:54:26 +05:30
|
|
|
|
|
|
|
|
|
|
2020-02-22 02:07:02 +05:30
|
|
|
|
def _job(self,group,func,datasets,args,lock):
|
2020-02-22 04:29:33 +05:30
|
|
|
|
"""Execute job for _add_generic_pointwise."""
|
2020-02-21 23:54:26 +05:30
|
|
|
|
try:
|
2020-02-22 03:46:25 +05:30
|
|
|
|
datasets_in = {}
|
|
|
|
|
lock.acquire()
|
|
|
|
|
with h5py.File(self.fname,'r') as f:
|
2020-03-12 03:05:58 +05:30
|
|
|
|
for arg,label in datasets.items():
|
|
|
|
|
loc = f[group+'/'+label]
|
|
|
|
|
datasets_in[arg]={'data' :loc[()],
|
|
|
|
|
'label':label,
|
2020-11-05 20:43:29 +05:30
|
|
|
|
'meta': {k:(v if h5py3 else v.decode()) for k,v in loc.attrs.items()}}
|
2020-02-22 03:46:25 +05:30
|
|
|
|
lock.release()
|
|
|
|
|
r = func(**datasets_in,**args)
|
2020-02-21 23:54:26 +05:30
|
|
|
|
return [group,r]
|
|
|
|
|
except Exception as err:
|
2020-06-25 01:04:51 +05:30
|
|
|
|
print(f'Error during calculation: {err}.')
|
2020-02-21 23:54:26 +05:30
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
2020-02-22 02:07:02 +05:30
|
|
|
|
def _add_generic_pointwise(self,func,datasets,args={}):
|
2020-02-22 03:46:25 +05:30
|
|
|
|
"""
|
|
|
|
|
General function to add pointwise data.
|
2020-02-21 23:54:26 +05:30
|
|
|
|
|
2020-02-22 03:46:25 +05:30
|
|
|
|
Parameters
|
|
|
|
|
----------
|
|
|
|
|
func : function
|
2020-06-03 23:54:18 +05:30
|
|
|
|
Callback function that calculates a new dataset from one or
|
|
|
|
|
more datasets per HDF5 group.
|
2020-02-22 03:46:25 +05:30
|
|
|
|
datasets : dictionary
|
2020-06-03 23:54:18 +05:30
|
|
|
|
Details of the datasets to be used: label (in HDF5 file) and
|
|
|
|
|
arg (argument to which the data is parsed in func).
|
2020-02-22 03:46:25 +05:30
|
|
|
|
args : dictionary, optional
|
2020-03-19 12:15:31 +05:30
|
|
|
|
Arguments parsed to func.
|
2020-02-22 04:29:33 +05:30
|
|
|
|
|
2020-02-22 03:46:25 +05:30
|
|
|
|
"""
|
2020-12-06 14:50:32 +05:30
|
|
|
|
chunk_size = 1024**2//8
|
2021-01-13 17:18:20 +05:30
|
|
|
|
pool = mp.Pool(int(os.environ.get('OMP_NUM_THREADS',1)))
|
2020-06-26 15:15:06 +05:30
|
|
|
|
lock = mp.Manager().Lock()
|
2020-02-22 03:46:25 +05:30
|
|
|
|
|
|
|
|
|
groups = self.groups_with_datasets(datasets.values())
|
2020-08-27 03:44:37 +05:30
|
|
|
|
if len(groups) == 0:
|
|
|
|
|
print('No matching dataset found, no data was added.')
|
|
|
|
|
return
|
|
|
|
|
|
2020-02-22 03:46:25 +05:30
|
|
|
|
default_arg = partial(self._job,func=func,datasets=datasets,args=args,lock=lock)
|
|
|
|
|
|
2020-03-09 18:09:20 +05:30
|
|
|
|
for result in util.show_progress(pool.imap_unordered(default_arg,groups),len(groups)):
|
|
|
|
|
if not result:
|
|
|
|
|
continue
|
2020-02-22 03:46:25 +05:30
|
|
|
|
lock.acquire()
|
|
|
|
|
with h5py.File(self.fname, 'a') as f:
|
2020-05-25 22:42:31 +05:30
|
|
|
|
try:
|
2020-05-30 16:17:36 +05:30
|
|
|
|
if self._allow_modification and result[0]+'/'+result[1]['label'] in f:
|
2020-05-25 22:42:31 +05:30
|
|
|
|
dataset = f[result[0]+'/'+result[1]['label']]
|
2020-05-26 03:24:06 +05:30
|
|
|
|
dataset[...] = result[1]['data']
|
2021-03-25 23:52:59 +05:30
|
|
|
|
dataset.attrs['overwritten'] = True
|
2020-05-25 22:42:31 +05:30
|
|
|
|
else:
|
2020-12-06 14:50:32 +05:30
|
|
|
|
if result[1]['data'].size >= chunk_size*2:
|
|
|
|
|
shape = result[1]['data'].shape
|
|
|
|
|
chunks = (chunk_size//np.prod(shape[1:]),)+shape[1:]
|
|
|
|
|
dataset = f[result[0]].create_dataset(result[1]['label'],data=result[1]['data'],
|
2020-12-07 00:27:00 +05:30
|
|
|
|
maxshape=shape, chunks=chunks,
|
|
|
|
|
compression='gzip', compression_opts=6,
|
|
|
|
|
shuffle=True,fletcher32=True)
|
2020-12-06 14:50:32 +05:30
|
|
|
|
else:
|
2020-12-07 00:27:00 +05:30
|
|
|
|
dataset = f[result[0]].create_dataset(result[1]['label'],data=result[1]['data'])
|
2020-05-25 23:27:32 +05:30
|
|
|
|
|
2020-05-25 22:20:31 +05:30
|
|
|
|
now = datetime.datetime.now().astimezone()
|
2021-03-25 23:52:59 +05:30
|
|
|
|
dataset.attrs['created'] = now.strftime('%Y-%m-%d %H:%M:%S%z') if h5py3 else \
|
2020-11-05 20:43:29 +05:30
|
|
|
|
now.strftime('%Y-%m-%d %H:%M:%S%z').encode()
|
2020-05-25 23:27:32 +05:30
|
|
|
|
|
2020-02-22 03:46:25 +05:30
|
|
|
|
for l,v in result[1]['meta'].items():
|
2021-03-25 23:52:59 +05:30
|
|
|
|
dataset.attrs[l.lower()]=v if h5py3 else v.encode()
|
|
|
|
|
creator = dataset.attrs['creator'] if h5py3 else \
|
|
|
|
|
dataset.attrs['creator'].decode()
|
|
|
|
|
dataset.attrs['creator'] = f"damask.Result.{creator} v{damask.version}" if h5py3 else \
|
2020-11-05 20:43:29 +05:30
|
|
|
|
f"damask.Result.{creator} v{damask.version}".encode()
|
2020-05-25 23:27:32 +05:30
|
|
|
|
|
2020-05-26 10:09:11 +05:30
|
|
|
|
except (OSError,RuntimeError) as err:
|
2020-06-25 01:04:51 +05:30
|
|
|
|
print(f'Could not add dataset: {err}.')
|
2020-02-22 03:46:25 +05:30
|
|
|
|
lock.release()
|
|
|
|
|
|
|
|
|
|
pool.close()
|
|
|
|
|
pool.join()
|
2020-02-21 12:15:05 +05:30
|
|
|
|
|
|
|
|
|
|
2020-09-21 01:34:28 +05:30
|
|
|
|
def save_XDMF(self):
|
2020-05-05 13:27:22 +05:30
|
|
|
|
"""
|
|
|
|
|
Write XDMF file to directly visualize data in DADF5 file.
|
|
|
|
|
|
2021-01-13 19:27:58 +05:30
|
|
|
|
The view is not taken into account, i.e. the content of the
|
|
|
|
|
whole file will be included.
|
2020-05-05 13:27:22 +05:30
|
|
|
|
"""
|
2021-03-25 23:52:59 +05:30
|
|
|
|
# compatibility hack
|
|
|
|
|
u = 'Unit' if self.version_minor < 12 else 'unit'
|
2020-11-30 15:10:46 +05:30
|
|
|
|
if self.N_constituents != 1 or len(self.phases) != 1 or not self.structured:
|
|
|
|
|
raise TypeError('XDMF output requires homogeneous grid')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
attribute_type_map = defaultdict(lambda:'Matrix', ( ((),'Scalar'), ((3,),'Vector'), ((3,3),'Tensor')) )
|
|
|
|
|
|
|
|
|
|
def number_type_map(dtype):
|
|
|
|
|
if dtype in np.sctypes['int']: return 'Int'
|
|
|
|
|
if dtype in np.sctypes['uint']: return 'UInt'
|
|
|
|
|
if dtype in np.sctypes['float']: return 'Float'
|
|
|
|
|
|
2020-05-05 13:27:22 +05:30
|
|
|
|
|
|
|
|
|
xdmf=ET.Element('Xdmf')
|
2020-05-07 22:42:05 +05:30
|
|
|
|
xdmf.attrib={'Version': '2.0',
|
2020-05-05 13:27:22 +05:30
|
|
|
|
'xmlns:xi': 'http://www.w3.org/2001/XInclude'}
|
|
|
|
|
|
|
|
|
|
domain=ET.SubElement(xdmf, 'Domain')
|
|
|
|
|
|
|
|
|
|
collection = ET.SubElement(domain, 'Grid')
|
|
|
|
|
collection.attrib={'GridType': 'Collection',
|
|
|
|
|
'CollectionType': 'Temporal'}
|
|
|
|
|
|
|
|
|
|
time = ET.SubElement(collection, 'Time')
|
|
|
|
|
time.attrib={'TimeType': 'List'}
|
|
|
|
|
|
|
|
|
|
time_data = ET.SubElement(time, 'DataItem')
|
2020-05-07 22:42:05 +05:30
|
|
|
|
time_data.attrib={'Format': 'XML',
|
|
|
|
|
'NumberType': 'Float',
|
2020-06-25 01:04:51 +05:30
|
|
|
|
'Dimensions': f'{len(self.times)}'}
|
2020-05-05 13:27:22 +05:30
|
|
|
|
time_data.text = ' '.join(map(str,self.times))
|
|
|
|
|
|
|
|
|
|
attributes = []
|
|
|
|
|
data_items = []
|
|
|
|
|
|
|
|
|
|
for inc in self.increments:
|
|
|
|
|
|
|
|
|
|
grid=ET.SubElement(collection,'Grid')
|
|
|
|
|
grid.attrib = {'GridType': 'Uniform',
|
|
|
|
|
'Name': inc}
|
|
|
|
|
|
|
|
|
|
topology=ET.SubElement(grid, 'Topology')
|
2020-05-07 22:42:05 +05:30
|
|
|
|
topology.attrib={'TopologyType': '3DCoRectMesh',
|
2020-12-04 02:28:24 +05:30
|
|
|
|
'Dimensions': '{} {} {}'.format(*self.cells+1)}
|
2020-05-05 13:27:22 +05:30
|
|
|
|
|
|
|
|
|
geometry=ET.SubElement(grid, 'Geometry')
|
|
|
|
|
geometry.attrib={'GeometryType':'Origin_DxDyDz'}
|
|
|
|
|
|
|
|
|
|
origin=ET.SubElement(geometry, 'DataItem')
|
|
|
|
|
origin.attrib={'Format': 'XML',
|
|
|
|
|
'NumberType': 'Float',
|
|
|
|
|
'Dimensions': '3'}
|
|
|
|
|
origin.text="{} {} {}".format(*self.origin)
|
|
|
|
|
|
|
|
|
|
delta=ET.SubElement(geometry, 'DataItem')
|
|
|
|
|
delta.attrib={'Format': 'XML',
|
|
|
|
|
'NumberType': 'Float',
|
|
|
|
|
'Dimensions': '3'}
|
2020-12-04 02:28:24 +05:30
|
|
|
|
delta.text="{} {} {}".format(*(self.size/self.cells))
|
2020-05-05 13:27:22 +05:30
|
|
|
|
|
|
|
|
|
|
|
|
|
|
with h5py.File(self.fname,'r') as f:
|
|
|
|
|
attributes.append(ET.SubElement(grid, 'Attribute'))
|
2020-11-19 18:15:40 +05:30
|
|
|
|
attributes[-1].attrib={'Name': 'u / m',
|
2020-05-05 13:27:22 +05:30
|
|
|
|
'Center': 'Node',
|
|
|
|
|
'AttributeType': 'Vector'}
|
|
|
|
|
data_items.append(ET.SubElement(attributes[-1], 'DataItem'))
|
|
|
|
|
data_items[-1].attrib={'Format': 'HDF',
|
|
|
|
|
'Precision': '8',
|
2020-12-04 02:28:24 +05:30
|
|
|
|
'Dimensions': '{} {} {} 3'.format(*(self.cells+1))}
|
2020-06-25 01:04:51 +05:30
|
|
|
|
data_items[-1].text=f'{os.path.split(self.fname)[1]}:/{inc}/geometry/u_n'
|
2020-05-05 13:27:22 +05:30
|
|
|
|
|
2020-11-18 19:22:16 +05:30
|
|
|
|
for o,p in zip(['phases','homogenizations'],['out_type_ph','out_type_ho']):
|
2020-05-05 13:27:22 +05:30
|
|
|
|
for oo in getattr(self,o):
|
|
|
|
|
for pp in getattr(self,p):
|
|
|
|
|
g = '/'.join([inc,o[:-1],oo,pp])
|
|
|
|
|
for l in f[g]:
|
|
|
|
|
name = '/'.join([g,l])
|
|
|
|
|
shape = f[name].shape[1:]
|
|
|
|
|
dtype = f[name].dtype
|
|
|
|
|
|
2020-11-30 15:10:46 +05:30
|
|
|
|
if dtype not in np.sctypes['int']+np.sctypes['uint']+np.sctypes['float']: continue
|
2021-03-25 23:52:59 +05:30
|
|
|
|
unit = f[name].attrs[u] if h5py3 else f[name].attrs[u].decode()
|
2020-05-05 13:27:22 +05:30
|
|
|
|
|
|
|
|
|
attributes.append(ET.SubElement(grid, 'Attribute'))
|
2020-11-19 18:15:40 +05:30
|
|
|
|
attributes[-1].attrib={'Name': name.split('/',2)[2]+f' / {unit}',
|
2020-11-28 02:15:23 +05:30
|
|
|
|
'Center': 'Cell',
|
2020-11-30 15:10:46 +05:30
|
|
|
|
'AttributeType': attribute_type_map[shape]}
|
2020-05-05 13:27:22 +05:30
|
|
|
|
data_items.append(ET.SubElement(attributes[-1], 'DataItem'))
|
|
|
|
|
data_items[-1].attrib={'Format': 'HDF',
|
2020-11-30 15:10:46 +05:30
|
|
|
|
'NumberType': number_type_map(dtype),
|
|
|
|
|
'Precision': f'{dtype.itemsize}',
|
2020-12-04 02:28:24 +05:30
|
|
|
|
'Dimensions': '{} {} {} {}'.format(*self.cells,1 if shape == () else
|
|
|
|
|
np.prod(shape))}
|
2020-06-25 01:04:51 +05:30
|
|
|
|
data_items[-1].text=f'{os.path.split(self.fname)[1]}:{name}'
|
2020-05-05 13:27:22 +05:30
|
|
|
|
|
2021-02-10 14:33:35 +05:30
|
|
|
|
with open(self.fname.with_suffix('.xdmf').name,'w',newline='\n') as f:
|
2020-05-05 13:27:22 +05:30
|
|
|
|
f.write(xml.dom.minidom.parseString(ET.tostring(xdmf).decode()).toprettyxml())
|
|
|
|
|
|
|
|
|
|
|
2020-11-30 13:58:46 +05:30
|
|
|
|
def save_VTK(self,labels=[],mode='cell'):
|
2020-02-21 12:15:05 +05:30
|
|
|
|
"""
|
|
|
|
|
Export to vtk cell/point data.
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
2020-03-19 16:00:36 +05:30
|
|
|
|
labels : str or list of, optional
|
2020-03-19 12:15:31 +05:30
|
|
|
|
Labels of the datasets to be exported.
|
2020-02-21 17:33:50 +05:30
|
|
|
|
mode : str, either 'cell' or 'point'
|
2020-03-19 12:15:31 +05:30
|
|
|
|
Export in cell format or point format.
|
|
|
|
|
Defaults to 'cell'.
|
2020-02-21 12:15:05 +05:30
|
|
|
|
|
|
|
|
|
"""
|
2020-02-21 17:33:50 +05:30
|
|
|
|
if mode.lower()=='cell':
|
2020-02-21 12:15:05 +05:30
|
|
|
|
|
2020-03-22 20:43:35 +05:30
|
|
|
|
if self.structured:
|
2020-12-04 02:28:24 +05:30
|
|
|
|
v = VTK.from_rectilinear_grid(self.cells,self.size,self.origin)
|
2020-03-22 20:43:35 +05:30
|
|
|
|
else:
|
|
|
|
|
with h5py.File(self.fname,'r') as f:
|
2020-10-27 18:12:49 +05:30
|
|
|
|
v = VTK.from_unstructured_grid(f['/geometry/x_n'][()],
|
|
|
|
|
f['/geometry/T_c'][()]-1,
|
2020-11-19 04:00:39 +05:30
|
|
|
|
f['/geometry/T_c'].attrs['VTK_TYPE'] if h5py3 else \
|
2020-10-27 18:12:49 +05:30
|
|
|
|
f['/geometry/T_c'].attrs['VTK_TYPE'].decode())
|
2020-02-21 23:22:58 +05:30
|
|
|
|
elif mode.lower()=='point':
|
2020-12-04 03:30:49 +05:30
|
|
|
|
v = VTK.from_poly_data(self.coordinates0_point)
|
2020-03-12 03:05:58 +05:30
|
|
|
|
|
2021-03-25 23:52:59 +05:30
|
|
|
|
# compatibility hack
|
|
|
|
|
ln = 3 if self.version_minor < 12 else 10
|
|
|
|
|
|
|
|
|
|
N_digits = int(np.floor(np.log10(max(1,int(self.increments[-1][ln:])))))+1
|
2020-02-21 12:15:05 +05:30
|
|
|
|
|
2021-01-13 19:27:58 +05:30
|
|
|
|
for inc in util.show_progress(self.iterate('increments'),len(self.visible['increments'])):
|
2020-03-22 20:43:35 +05:30
|
|
|
|
|
2021-01-13 19:27:58 +05:30
|
|
|
|
viewed_backup_ho = self.visible['homogenizations'].copy()
|
|
|
|
|
self.view('homogenizations',False)
|
2020-03-22 20:43:35 +05:30
|
|
|
|
for label in (labels if isinstance(labels,list) else [labels]):
|
2020-11-19 03:42:29 +05:30
|
|
|
|
for o in self.iterate('out_type_ph'):
|
2020-11-19 04:00:39 +05:30
|
|
|
|
for c in range(self.N_constituents):
|
|
|
|
|
prefix = '' if self.N_constituents == 1 else f'constituent{c}/'
|
2021-03-25 23:52:59 +05:30
|
|
|
|
if o not in ['mechanics', 'mechanical']: # compatibility hack
|
2020-11-19 04:00:39 +05:30
|
|
|
|
for _ in self.iterate('phases'):
|
|
|
|
|
path = self.get_dataset_location(label)
|
|
|
|
|
if len(path) == 0:
|
|
|
|
|
continue
|
|
|
|
|
array = self.read_dataset(path,c)
|
2021-03-25 23:52:59 +05:30
|
|
|
|
v.add(array,prefix+path[0].split('/',1)[1]+f' / {self._get_attribute(path[0],"unit")}')
|
2020-11-19 04:00:39 +05:30
|
|
|
|
else:
|
|
|
|
|
paths = self.get_dataset_location(label)
|
|
|
|
|
if len(paths) == 0:
|
2020-03-22 20:43:35 +05:30
|
|
|
|
continue
|
2020-11-19 04:00:39 +05:30
|
|
|
|
array = self.read_dataset(paths,c)
|
2021-03-25 23:52:59 +05:30
|
|
|
|
if self.version_minor < 12:
|
|
|
|
|
ph_name = re.compile(r'(?<=(phase\/))(.*?)(?=(mechanics))') # identify phase name
|
|
|
|
|
else:
|
|
|
|
|
ph_name = re.compile(r'(?<=(phase\/))(.*?)(?=(mechanical))') # identify phase name
|
|
|
|
|
dset_name = prefix+re.sub(ph_name,r'',paths[0].split('/',1)[1]) # remove phase name
|
|
|
|
|
v.add(array,dset_name+f' / {self._get_attribute(paths[0],"unit")}')
|
2021-01-13 19:27:58 +05:30
|
|
|
|
self.view('homogenizations',viewed_backup_ho)
|
2020-03-22 20:43:35 +05:30
|
|
|
|
|
2021-01-13 19:27:58 +05:30
|
|
|
|
viewed_backup_ph = self.visible['phases'].copy()
|
|
|
|
|
self.view('phases',False)
|
2020-03-22 20:43:35 +05:30
|
|
|
|
for label in (labels if isinstance(labels,list) else [labels]):
|
2020-11-19 04:00:39 +05:30
|
|
|
|
for _ in self.iterate('out_type_ho'):
|
2020-11-19 03:42:29 +05:30
|
|
|
|
paths = self.get_dataset_location(label)
|
|
|
|
|
if len(paths) == 0:
|
|
|
|
|
continue
|
|
|
|
|
array = self.read_dataset(paths)
|
2021-03-25 23:52:59 +05:30
|
|
|
|
v.add(array,paths[0].split('/',1)[1]+f' / {self._get_attribute(paths[0],"unit")}')
|
2021-01-13 19:27:58 +05:30
|
|
|
|
self.view('phases',viewed_backup_ph)
|
2020-03-22 20:43:35 +05:30
|
|
|
|
|
|
|
|
|
u = self.read_dataset(self.get_dataset_location('u_n' if mode.lower() == 'cell' else 'u_p'))
|
|
|
|
|
v.add(u,'u')
|
|
|
|
|
|
2021-03-25 23:52:59 +05:30
|
|
|
|
v.save(f'{self.fname.stem}_inc{inc[ln:].zfill(N_digits)}')
|