Merge branch 'development' into Fortran-simplifications

This commit is contained in:
Martin Diehl 2020-09-22 12:15:42 +02:00
commit f26c3ca1ea
6 changed files with 301 additions and 4 deletions

View File

@ -1 +1 @@
v3.0.0-alpha-233-g190f8a82
v3.0.0-alpha-245-g5ef761fb9

View File

@ -18,6 +18,7 @@ from ._lattice import Symmetry, Lattice# noqa
from ._orientation import Orientation # noqa
from ._result import Result # noqa
from ._geom import Geom # noqa
from ._material import Material # noqa
from . import solver # noqa
# deprecated

193
python/damask/_material.py Normal file
View File

@ -0,0 +1,193 @@
from io import StringIO
import copy
import yaml
import numpy as np
from . import Lattice
from . import Rotation
class NiceDumper(yaml.SafeDumper):
"""Make YAML readable for humans."""
def write_line_break(self, data=None):
super().write_line_break(data)
if len(self.indents) == 1:
super().write_line_break()
def increase_indent(self, flow=False, indentless=False):
return super().increase_indent(flow, False)
class Material(dict):
"""Material configuration."""
def __repr__(self):
"""Show as in file."""
output = StringIO()
self.save(output)
output.seek(0)
return ''.join(output.readlines())
@staticmethod
def load(fname):
"""Load from yaml file."""
try:
fhandle = open(fname)
except TypeError:
fhandle = fname
return Material(yaml.safe_load(fhandle))
def save(self,fname='material.yaml'):
"""
Save to yaml file.
Parameters
----------
fname : file, str, or pathlib.Path
Filename or file for reading.
"""
try:
fhandle = open(fname,'w')
except TypeError:
fhandle = fname
fhandle.write(yaml.dump(dict(self),width=256,default_flow_style=None,Dumper=NiceDumper))
@property
def is_complete(self):
"""Check for completeness."""
ok = True
for top_level in ['homogenization','phase','microstructure']:
# ToDo: With python 3.8 as prerequisite we can shorten with :=
ok &= top_level in self
if top_level not in self: print(f'{top_level} entry missing')
if ok:
ok &= len(self['microstructure']) > 0
if len(self['microstructure']) < 1: print('Incomplete microstructure definition')
if ok:
homogenization = set()
phase = set()
for i,v in enumerate(self['microstructure']):
if 'homogenization' in v:
homogenization.add(v['homogenization'])
else:
print(f'No homogenization specified in microstructure {i}')
ok = False
if 'constituents' in v:
for ii,vv in enumerate(v['constituents']):
if 'orientation' not in vv:
print('No orientation specified in constituent {ii} of microstructure {i}')
ok = False
if 'phase' in vv:
phase.add(vv['phase'])
else:
print(f'No phase specified in constituent {ii} of microstructure {i}')
ok = False
for k,v in self['phase'].items():
if 'lattice' not in v:
print(f'No lattice specified in phase {k}')
ok = False
#for k,v in self['homogenization'].items():
# if 'N_constituents' not in v:
# print(f'No. of constituents not specified in homogenization {k}'}
# ok = False
if phase - set(self['phase']):
print(f'Phase(s) {phase-set(self["phase"])} missing')
ok = False
if homogenization - set(self['homogenization']):
print(f'Homogenization(s) {homogenization-set(self["homogenization"])} missing')
ok = False
return ok
@property
def is_valid(self):
"""Check for valid file layout."""
ok = True
if 'phase' in self:
for k,v in self['phase'].items():
if 'lattice' in v:
try:
Lattice(v['lattice'])
except KeyError:
s = v['lattice']
print(f"Invalid lattice: '{s}' in phase '{k}'")
ok = False
if 'microstructure' in self:
for i,v in enumerate(self['microstructure']):
if 'constituents' in v:
f = 0.0
for c in v['constituents']:
f+= float(c['fraction'])
if 'orientation' in c:
try:
Rotation.from_quaternion(c['orientation'])
except ValueError:
o = c['orientation']
print(f"Invalid orientation: '{o}' in microstructure '{i}'")
ok = False
if not np.isclose(f,1.0):
print(f"Invalid total fraction '{f}' in microstructure '{i}'")
ok = False
return ok
def microstructure_rename_phase(self,mapping,ID=None,constituent=None):
"""
Change phase name in microstructure.
Parameters
----------
mapping: dictionary
Mapping from old name to new name
ID: list of ints, optional
Limit renaming to selected microstructure IDs.
constituent: list of ints, optional
Limit renaming to selected constituents.
"""
dup = copy.deepcopy(self)
for i,m in enumerate(dup['microstructure']):
if ID and i not in ID: continue
for c in m['constituents']:
if constituent is not None and c not in constituent: continue
try:
c['phase'] = mapping[c['phase']]
except KeyError:
continue
return dup
def microstructure_rename_homogenization(self,mapping,ID=None):
"""
Change homogenization name in microstructure.
Parameters
----------
mapping: dictionary
Mapping from old name to new name
ID: list of ints, optional
Limit renaming to selected homogenization IDs.
"""
dup = copy.deepcopy(self)
for i,m in enumerate(dup['microstructure']):
if ID and i not in ID: continue
try:
m['homogenization'] = mapping[m['homogenization']]
except KeyError:
continue
return dup

View File

@ -0,0 +1,42 @@
homogenization:
SX:
mech: {type: none}
Taylor:
mech: {type: isostrain, N_constituents: 2}
microstructure:
- constituents:
- fraction: 1.0
orientation: [1.0, 0.0, 0.0, 0.0]
phase: Aluminum
homogenization: SX
- constituents:
- fraction: 1.0
orientation: [0.7936696712125002, -0.28765777461664166, -0.3436487135089419, 0.4113964260949434]
phase: Aluminum
homogenization: SX
- constituents:
- fraction: 1.0
orientation: [0.3986143167493579, -0.7014883552495493, 0.2154871765709027, 0.5500781677772945]
phase: Aluminum
homogenization: SX
- homogenization: Taylor
constituents:
- fraction: .5
orientation: [0.28645844315788244, -0.022571491243423537, -0.467933059311115, -0.8357456192708106]
phase: Aluminum
- fraction: .5
orientation: [0.3986143167493579, -0.7014883552495493, 0.2154871765709027, 0.5500781677772945]
phase: Steel
phase:
Aluminum:
elasticity: {C_11: 106.75e9, C_12: 60.41e9, C_44: 28.34e9, type: hooke}
generic:
output: [F, P, Fe, Fp, Lp]
lattice: fcc
Steel:
elasticity: {C_11: 233.3e9, C_12: 135.5e9, C_44: 118.0e9, type: hooke}
generic:
output: [F, P, Fe, Fp, Lp]
lattice: bcc

View File

@ -0,0 +1,61 @@
import os
import pytest
from damask import Material
@pytest.fixture
def reference_dir(reference_dir_base):
"""Directory containing reference results."""
return reference_dir_base/'Material'
class TestMaterial:
@pytest.mark.parametrize('fname',[None,'test.yaml'])
def test_load_save(self,reference_dir,tmp_path,fname):
reference = Material.load(reference_dir/'material.yaml')
os.chdir(tmp_path)
if fname is None:
reference.save()
new = Material.load('material.yaml')
else:
reference.save(fname)
new = Material.load(fname)
assert reference == new
def test_valid_complete(self,reference_dir):
material_config = Material.load(reference_dir/'material.yaml')
assert material_config.is_valid and material_config.is_complete
def test_invalid_lattice(self,reference_dir):
material_config = Material.load(reference_dir/'material.yaml')
material_config['phase']['Aluminum']['lattice']='fxc'
assert not material_config.is_valid
def test_invalid_orientation(self,reference_dir):
material_config = Material.load(reference_dir/'material.yaml')
material_config['microstructure'][0]['constituents'][0]['orientation']=[0,0,0,0]
assert not material_config.is_valid
def test_invalid_fraction(self,reference_dir):
material_config = Material.load(reference_dir/'material.yaml')
material_config['microstructure'][0]['constituents'][0]['fraction']=.9
assert not material_config.is_valid
@pytest.mark.parametrize('item',['homogenization','phase','microstructure'])
def test_incomplete_missing(self,reference_dir,item):
material_config = Material.load(reference_dir/'material.yaml')
del material_config[item]
assert not material_config.is_complete
def test_incomplete_wrong_phase(self,reference_dir):
material_config = Material.load(reference_dir/'material.yaml')
new = material_config.microstructure_rename_phase({'Steel':'FeNbC'})
assert not new.is_complete
def test_incomplete_wrong_homogenization(self,reference_dir):
material_config = Material.load(reference_dir/'material.yaml')
new = material_config.microstructure_rename_homogenization({'Taylor':'isostrain'})
assert not new.is_complete

View File

@ -265,9 +265,9 @@ subroutine hypela2(d,g,e,de,s,t,dt,ngens,m,nn,kcus,matus,ndi,nshear,disp, &
print'(a,i2)', ' Coordinates: ', ncrd
print'(a,i12)', ' Nodes: ', nnode
print'(a,i1)', ' Deformation gradient: ', itel
write(OUTPUT_UNIT,'(/,a,/,3(3(f12.7,1x)/))',advance='no') ' Deformation gradient at t=n:', &
write(6,'(/,a,/,3(3(f12.7,1x)/))',advance='no') ' Deformation gradient at t=n:', &
transpose(ffn)
write(OUTPUT_UNIT,'(/,a,/,3(3(f12.7,1x)/))',advance='no') ' Deformation gradient at t=n+1:', &
write(6,'(/,a,/,3(3(f12.7,1x)/))',advance='no') ' Deformation gradient at t=n+1:', &
transpose(ffn1)
endif
@ -312,7 +312,7 @@ subroutine hypela2(d,g,e,de,s,t,dt,ngens,m,nn,kcus,matus,ndi,nshear,disp, &
cycleCounter = -1 ! first calc step increments this to cycle = 0
print'(a,i6,1x,i2)', '<< HYPELA2 >> cutback detected..! ',m(1),nn
endif ! convergence treatment end
flush(OUTPUT_UNIT)
flush(6)
if (lastLovl /= lovl) then
cycleCounter = cycleCounter + 1