attributes should depend on view
hidden attributes contain the view-independent variables, getter for currently visible quantities
This commit is contained in:
parent
84af516cdb
commit
38f9c1977c
2
PRIVATE
2
PRIVATE
|
@ -1 +1 @@
|
||||||
Subproject commit 29ef436acca5417aebc945b688642c34697af911
|
Subproject commit 5a715996e6e8418a59fbcaf3715a2516ad05ed51
|
|
@ -119,29 +119,29 @@ class Result:
|
||||||
self.add_curl = self.add_divergence = self.add_gradient = None # type: ignore
|
self.add_curl = self.add_divergence = self.add_gradient = None # type: ignore
|
||||||
|
|
||||||
r = re.compile(rf'{prefix_inc}([0-9]+)')
|
r = re.compile(rf'{prefix_inc}([0-9]+)')
|
||||||
self.increments = sorted([i for i in f.keys() if r.match(i)],key=util.natural_sort)
|
self._increments = sorted([i for i in f.keys() if r.match(i)],key=util.natural_sort)
|
||||||
self.times = np.around([f[i].attrs['t/s'] for i in self.increments],12)
|
self._times = np.around([f[i].attrs['t/s'] for i in self._increments],12)
|
||||||
if len(self.increments) == 0:
|
if len(self._increments) == 0:
|
||||||
raise ValueError('incomplete DADF5 file')
|
raise ValueError('incomplete DADF5 file')
|
||||||
|
|
||||||
self.N_materialpoints, self.N_constituents = np.shape(f['cell_to/phase'])
|
self.N_materialpoints, self.N_constituents = np.shape(f['cell_to/phase'])
|
||||||
|
|
||||||
self.homogenization = f['cell_to/homogenization']['label'].astype('str')
|
self.homogenization = f['cell_to/homogenization']['label'].astype('str')
|
||||||
self.homogenizations = sorted(np.unique(self.homogenization),key=util.natural_sort)
|
self._homogenizations = sorted(np.unique(self.homogenization),key=util.natural_sort)
|
||||||
self.phase = f['cell_to/phase']['label'].astype('str')
|
self.phase = f['cell_to/phase']['label'].astype('str')
|
||||||
self.phases = sorted(np.unique(self.phase),key=util.natural_sort)
|
self._phases = sorted(np.unique(self.phase),key=util.natural_sort)
|
||||||
|
|
||||||
self.fields: List[str] = []
|
fields: List[str] = []
|
||||||
for c in self.phases:
|
for c in self._phases:
|
||||||
self.fields += f['/'.join([self.increments[0],'phase',c])].keys()
|
fields += f['/'.join([self._increments[0],'phase',c])].keys()
|
||||||
for m in self.homogenizations:
|
for m in self._homogenizations:
|
||||||
self.fields += f['/'.join([self.increments[0],'homogenization',m])].keys()
|
fields += f['/'.join([self._increments[0],'homogenization',m])].keys()
|
||||||
self.fields = sorted(set(self.fields),key=util.natural_sort) # make unique
|
self._fields = sorted(set(fields),key=util.natural_sort) # make unique
|
||||||
|
|
||||||
self.visible = {'increments': self.increments,
|
self.visible = {'increments': self._increments,
|
||||||
'phases': self.phases,
|
'phases': self._phases,
|
||||||
'homogenizations': self.homogenizations,
|
'homogenizations': self._homogenizations,
|
||||||
'fields': self.fields,
|
'fields': self._fields,
|
||||||
}
|
}
|
||||||
|
|
||||||
self.fname = Path(fname).expanduser().absolute()
|
self.fname = Path(fname).expanduser().absolute()
|
||||||
|
@ -223,24 +223,24 @@ class Result:
|
||||||
|
|
||||||
if what == 'increments':
|
if what == 'increments':
|
||||||
choice = [c if isinstance(c,str) and c.startswith(prefix_inc) else
|
choice = [c if isinstance(c,str) and c.startswith(prefix_inc) else
|
||||||
self.increments[c] if isinstance(c,int) and c<0 else
|
self._increments[c] if isinstance(c,int) and c<0 else
|
||||||
f'{prefix_inc}{c}' for c in choice]
|
f'{prefix_inc}{c}' for c in choice]
|
||||||
elif what == 'times':
|
elif what == 'times':
|
||||||
atol = 1e-2 * np.min(np.diff(self.times))
|
atol = 1e-2 * np.min(np.diff(self._times))
|
||||||
what = 'increments'
|
what = 'increments'
|
||||||
if choice == ['*']:
|
if choice == ['*']:
|
||||||
choice = self.increments
|
choice = self._increments
|
||||||
else:
|
else:
|
||||||
iterator = np.array(choice).astype(float)
|
iterator = np.array(choice).astype(float)
|
||||||
choice = []
|
choice = []
|
||||||
for c in iterator:
|
for c in iterator:
|
||||||
idx = np.searchsorted(self.times,c,side='left')
|
idx = np.searchsorted(self._times,c,side='left')
|
||||||
if idx<len(self.times) and np.isclose(c,self.times[idx],rtol=0,atol=atol):
|
if idx<len(self._times) and np.isclose(c,self._times[idx],rtol=0,atol=atol):
|
||||||
choice.append(self.increments[idx])
|
choice.append(self._increments[idx])
|
||||||
elif idx>0 and np.isclose(c,self.times[idx-1],rtol=0,atol=atol):
|
elif idx>0 and np.isclose(c,self._times[idx-1],rtol=0,atol=atol):
|
||||||
choice.append(self.increments[idx-1])
|
choice.append(self._increments[idx-1])
|
||||||
|
|
||||||
valid = _match(choice,getattr(self,what))
|
valid = _match(choice,getattr(self,'_'+what))
|
||||||
existing = set(self.visible[what])
|
existing = set(self.visible[what])
|
||||||
|
|
||||||
if action == 'set':
|
if action == 'set':
|
||||||
|
@ -273,9 +273,9 @@ class Result:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
s,e = map(lambda x: int(x.split(prefix_inc)[-1] if isinstance(x,str) and x.startswith(prefix_inc) else x),
|
s,e = map(lambda x: int(x.split(prefix_inc)[-1] if isinstance(x,str) and x.startswith(prefix_inc) else x),
|
||||||
(self.incs[ 0] if start is None else start,
|
(self._incs[ 0] if start is None else start,
|
||||||
self.incs[-1] if end is None else end))
|
self._incs[-1] if end is None else end))
|
||||||
return [i for i in self.incs if s <= i <= e]
|
return [i for i in self._incs if s <= i <= e]
|
||||||
|
|
||||||
def times_in_range(self,
|
def times_in_range(self,
|
||||||
start: Optional[float] = None,
|
start: Optional[float] = None,
|
||||||
|
@ -296,9 +296,9 @@ class Result:
|
||||||
Time of each increment within the given bounds.
|
Time of each increment within the given bounds.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
s,e = (self.times[ 0] if start is None else start,
|
s,e = (self._times[ 0] if start is None else start,
|
||||||
self.times[-1] if end is None else end)
|
self._times[-1] if end is None else end)
|
||||||
return [t for t in self.times if s <= t <= e]
|
return [t for t in self._times if s <= t <= e]
|
||||||
|
|
||||||
|
|
||||||
def view(self,*,
|
def view(self,*,
|
||||||
|
@ -533,7 +533,7 @@ class Result:
|
||||||
msg = []
|
msg = []
|
||||||
with h5py.File(self.fname,'r') as f:
|
with h5py.File(self.fname,'r') as f:
|
||||||
for inc in self.visible['increments']:
|
for inc in self.visible['increments']:
|
||||||
msg += [f'\n{inc} ({self.times[self.increments.index(inc)]} s)']
|
msg += [f'\n{inc} ({self._times[self._increments.index(inc)]} s)']
|
||||||
for ty in ['phase','homogenization']:
|
for ty in ['phase','homogenization']:
|
||||||
msg += [f' {ty}']
|
msg += [f' {ty}']
|
||||||
for label in self.visible[ty+'s']:
|
for label in self.visible[ty+'s']:
|
||||||
|
@ -566,8 +566,28 @@ class Result:
|
||||||
return files
|
return files
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def incs(self):
|
def _incs(self):
|
||||||
return [int(i.split(prefix_inc)[-1]) for i in self.increments]
|
return [int(i.split(prefix_inc)[-1]) for i in self._increments]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def increments(self):
|
||||||
|
return [int(i.split(prefix_inc)[-1]) for i in self.visible['increments']]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def times(self):
|
||||||
|
return NotImplementedError
|
||||||
|
|
||||||
|
@property
|
||||||
|
def phases(self):
|
||||||
|
return [copy.deepcopy(self.visible['phases'])]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def homogenizations(self):
|
||||||
|
return [copy.deepcopy(self.visible['homogenizations'])]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def fields(self):
|
||||||
|
return [copy.deepcopy(self.visible['fields'])]
|
||||||
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -1723,7 +1743,7 @@ class Result:
|
||||||
DADF5 file at a stable relative path.
|
DADF5 file at a stable relative path.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if self.N_constituents != 1 or len(self.phases) != 1 or not self.structured:
|
if self.N_constituents != 1 or len(self._phases) != 1 or not self.structured:
|
||||||
raise TypeError('XDMF output requires structured grid with single phase and single constituent.')
|
raise TypeError('XDMF output requires structured grid with single phase and single constituent.')
|
||||||
|
|
||||||
attribute_type_map = defaultdict(lambda:'Matrix', ( ((),'Scalar'), ((3,),'Vector'), ((3,3),'Tensor')) )
|
attribute_type_map = defaultdict(lambda:'Matrix', ( ((),'Scalar'), ((3,),'Vector'), ((3,3),'Tensor')) )
|
||||||
|
@ -1749,7 +1769,7 @@ class Result:
|
||||||
time.attrib = {'TimeType': 'List'}
|
time.attrib = {'TimeType': 'List'}
|
||||||
|
|
||||||
time_data = ET.SubElement(time, 'DataItem')
|
time_data = ET.SubElement(time, 'DataItem')
|
||||||
times = [self.times[self.increments.index(i)] for i in self.visible['increments']]
|
times = [self._times[self._increments.index(i)] for i in self.visible['increments']]
|
||||||
time_data.attrib = {'Format': 'XML',
|
time_data.attrib = {'Format': 'XML',
|
||||||
'NumberType': 'Float',
|
'NumberType': 'Float',
|
||||||
'Dimensions': f'{len(times)}'}
|
'Dimensions': f'{len(times)}'}
|
||||||
|
@ -1876,7 +1896,7 @@ class Result:
|
||||||
|
|
||||||
v.comments = [util.execution_stamp('Result','export_VTK')]
|
v.comments = [util.execution_stamp('Result','export_VTK')]
|
||||||
|
|
||||||
N_digits = int(np.floor(np.log10(max(1,self.incs[-1]))))+1
|
N_digits = int(np.floor(np.log10(max(1,self._incs[-1]))))+1
|
||||||
|
|
||||||
constituents_ = constituents if isinstance(constituents,Iterable) else \
|
constituents_ = constituents if isinstance(constituents,Iterable) else \
|
||||||
(range(self.N_constituents) if constituents is None else [constituents]) # type: ignore
|
(range(self.N_constituents) if constituents is None else [constituents]) # type: ignore
|
||||||
|
@ -1966,7 +1986,7 @@ class Result:
|
||||||
if self.N_constituents != 1 or not self.structured:
|
if self.N_constituents != 1 or not self.structured:
|
||||||
raise TypeError('DREAM3D output requires structured grid with single constituent.')
|
raise TypeError('DREAM3D output requires structured grid with single constituent.')
|
||||||
|
|
||||||
N_digits = int(np.floor(np.log10(max(1,self.incs[-1]))))+1
|
N_digits = int(np.floor(np.log10(max(1,self._incs[-1]))))+1
|
||||||
|
|
||||||
|
|
||||||
at_cell_ph,in_data_ph,_,_ = self._mappings()
|
at_cell_ph,in_data_ph,_,_ = self._mappings()
|
||||||
|
@ -2036,12 +2056,12 @@ class Result:
|
||||||
cell_ensemble.create_dataset(name='PhaseName',data = phase_name, dtype=h5py.Datatype(tid))
|
cell_ensemble.create_dataset(name='PhaseName',data = phase_name, dtype=h5py.Datatype(tid))
|
||||||
|
|
||||||
cell_ensemble.attrs['AttributeMatrixType'] = np.array([11],np.uint32)
|
cell_ensemble.attrs['AttributeMatrixType'] = np.array([11],np.uint32)
|
||||||
cell_ensemble.attrs['TupleDimensions'] = np.array([len(self.phases) + 1], np.uint64)
|
cell_ensemble.attrs['TupleDimensions'] = np.array([len(self._phases) + 1], np.uint64)
|
||||||
for group in ['CrystalStructures','PhaseTypes','PhaseName']:
|
for group in ['CrystalStructures','PhaseTypes','PhaseName']:
|
||||||
add_attribute(cell_ensemble[group], 'ComponentDimensions', np.array([1],np.uint64))
|
add_attribute(cell_ensemble[group], 'ComponentDimensions', np.array([1],np.uint64))
|
||||||
add_attribute(cell_ensemble[group], 'Tuple Axis Dimensions', f'x={len(self.phases)+1}')
|
add_attribute(cell_ensemble[group], 'Tuple Axis Dimensions', f'x={len(self._phases)+1}')
|
||||||
add_attribute(cell_ensemble[group], 'DataArrayVersion', np.array([2],np.int32))
|
add_attribute(cell_ensemble[group], 'DataArrayVersion', np.array([2],np.int32))
|
||||||
add_attribute(cell_ensemble[group], 'TupleDimensions', np.array([len(self.phases) + 1],np.uint64))
|
add_attribute(cell_ensemble[group], 'TupleDimensions', np.array([len(self._phases) + 1],np.uint64))
|
||||||
for group in ['CrystalStructures','PhaseTypes']:
|
for group in ['CrystalStructures','PhaseTypes']:
|
||||||
add_attribute(cell_ensemble[group], 'ObjectType', 'DataArray<uint32_t>')
|
add_attribute(cell_ensemble[group], 'ObjectType', 'DataArray<uint32_t>')
|
||||||
add_attribute(cell_ensemble['PhaseName'], 'ObjectType', 'StringDataArray')
|
add_attribute(cell_ensemble['PhaseName'], 'ObjectType', 'StringDataArray')
|
||||||
|
@ -2129,9 +2149,9 @@ class Result:
|
||||||
f_out[inc]['geometry'].create_dataset('u_n',data=u_n)
|
f_out[inc]['geometry'].create_dataset('u_n',data=u_n)
|
||||||
|
|
||||||
|
|
||||||
for label in self.homogenizations:
|
for label in self._homogenizations:
|
||||||
f_in[inc]['homogenization'].copy(label,f_out[inc]['homogenization'],shallow=True)
|
f_in[inc]['homogenization'].copy(label,f_out[inc]['homogenization'],shallow=True)
|
||||||
for label in self.phases:
|
for label in self._phases:
|
||||||
f_in[inc]['phase'].copy(label,f_out[inc]['phase'],shallow=True)
|
f_in[inc]['phase'].copy(label,f_out[inc]['phase'],shallow=True)
|
||||||
|
|
||||||
for ty in ['phase','homogenization']:
|
for ty in ['phase','homogenization']:
|
||||||
|
|
|
@ -126,7 +126,7 @@ class TestResult:
|
||||||
@pytest.mark.parametrize('sign',[+1,-1])
|
@pytest.mark.parametrize('sign',[+1,-1])
|
||||||
def test_view_approxtimes(self,default,inc,sign):
|
def test_view_approxtimes(self,default,inc,sign):
|
||||||
eps = sign*1e-3
|
eps = sign*1e-3
|
||||||
assert [default.increments[inc]] == default.view(times=default.times[inc]+eps).visible['increments']
|
assert [default._increments[inc]] == default.view(times=default._times[inc]+eps).visible['increments']
|
||||||
|
|
||||||
def test_add_invalid(self,default):
|
def test_add_invalid(self,default):
|
||||||
default.add_absolute('xxxx')
|
default.add_absolute('xxxx')
|
||||||
|
@ -470,7 +470,7 @@ class TestResult:
|
||||||
assert np.array_equal(dset,cur[path])
|
assert np.array_equal(dset,cur[path])
|
||||||
else:
|
else:
|
||||||
c = [_.decode() for _ in cur[path]]
|
c = [_.decode() for _ in cur[path]]
|
||||||
r = ['Unknown Phase Type'] + result.phases
|
r = ['Unknown Phase Type'] + result._phases
|
||||||
assert c == r
|
assert c == r
|
||||||
grp = os.path.split(path)[0]
|
grp = os.path.split(path)[0]
|
||||||
for attr in ref[grp].attrs:
|
for attr in ref[grp].attrs:
|
||||||
|
@ -650,8 +650,8 @@ class TestResult:
|
||||||
'check_compile_job1.hdf5',])
|
'check_compile_job1.hdf5',])
|
||||||
def test_export_DADF5(self,res_path,tmp_path,fname):
|
def test_export_DADF5(self,res_path,tmp_path,fname):
|
||||||
r = Result(res_path/fname)
|
r = Result(res_path/fname)
|
||||||
r = r.view(phases = random.sample(r.phases,1))
|
r = r.view(phases = random.sample(r._phases,1))
|
||||||
r = r.view(increments = random.sample(r.increments,np.random.randint(1,len(r.increments))))
|
r = r.view(increments = random.sample(r._increments,np.random.randint(1,len(r._increments))))
|
||||||
r.export_DADF5(tmp_path/fname)
|
r.export_DADF5(tmp_path/fname)
|
||||||
r_exp = Result(tmp_path/fname)
|
r_exp = Result(tmp_path/fname)
|
||||||
assert str(r.get()) == str(r_exp.get())
|
assert str(r.get()) == str(r_exp.get())
|
||||||
|
|
Loading…
Reference in New Issue