diff --git a/.gitattributes b/.gitattributes index b096658f8..c2785cf15 100644 --- a/.gitattributes +++ b/.gitattributes @@ -8,6 +8,7 @@ *.jpg binary *.hdf5 binary *.pdf binary +*.dream3d binary # ignore files from MSC.Marc in language statistics installation/mods_MarcMentat/20*/* linguist-vendored diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 33e0e91a5..f1e67a115 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -193,6 +193,8 @@ grid_mech_compile_Intel: - module load $IntelCompiler $MPICH_Intel $PETSc_MPICH_Intel - cp -r grid_mech_compile grid_mech_compile_Intel - grid_mech_compile_Intel/test.py + - cd pytest + - pytest -k 'compile and grid' except: - master - release @@ -203,6 +205,8 @@ Compile_FEM_Intel: - module load $IntelCompiler $MPICH_Intel $PETSc_MPICH_Intel - cp -r FEM_compile FEM_compile_Intel - FEM_compile_Intel/test.py + - cd pytest + - pytest -k 'compile and mesh' except: - master - release @@ -213,6 +217,8 @@ grid_mech_compile_GNU: - module load $GNUCompiler $MPICH_GNU $PETSc_MPICH_GNU - cp -r grid_mech_compile grid_mech_compile_GNU - grid_mech_compile_GNU/test.py + - cd pytest + - pytest -k 'compile and grid' except: - master - release @@ -223,6 +229,8 @@ Compile_FEM_GNU: - module load $GNUCompiler $MPICH_GNU $PETSc_MPICH_GNU - cp -r FEM_compile FEM_compile_GNU - FEM_compile_GNU/test.py + - cd pytest + - pytest -k 'compile and mesh' except: - master - release @@ -244,7 +252,7 @@ Pytest_grid: script: - module load $IntelCompiler $MPICH_Intel $PETSc_MPICH_Intel - cd pytest - - pytest + - pytest -m 'not compile' except: - master - release @@ -306,6 +314,8 @@ Marc_compileIfort: script: - module load $IntelMarc $HDF5Marc $MSC - Marc_compileIfort/test.py + - cd pytest + - pytest -k 'compile and Marc' except: - master - release diff --git a/VERSION b/VERSION index 260159fc8..41d9ce4ba 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v3.0.0-alpha-452-gd3f068cd7 +v3.0.0-alpha-502-g8ab405e5d diff --git a/examples/ConfigFiles/Phase_Phenopowerlaw_BCC-Ferrite.config b/examples/ConfigFiles/Phase_Phenopowerlaw_BCC-Ferrite.config deleted file mode 100644 index 5af1eee11..000000000 --- a/examples/ConfigFiles/Phase_Phenopowerlaw_BCC-Ferrite.config +++ /dev/null @@ -1,21 +0,0 @@ -# Tasan et.al. 2015 Acta Materalia -# Tasan et.al. 2015 International Journal of Plasticity -# Diehl et.al. 2015 Meccanica -[BCC-Ferrite] - -elasticity hooke -plasticity phenopowerlaw - -lattice_structure bcc -Nslip 12 12 # per family -Ntwin 0 # per family -c11 233.3e9 -c12 135.5e9 -c44 118.0e9 -gdot0_slip 0.001 -n_slip 20 -tau0_slip 95.e6 97.e6 # per family, optimization long simplex 109 -tausat_slip 222.e6 412.7e6 # per family, optimization long simplex 109 -h0_slipslip 1000.0e6 -interaction_slipslip 1 1 1.4 1.4 1.4 1.4 -a_slip 2.0 diff --git a/examples/ConfigFiles/Phase_Phenopowerlaw_BCC-Ferrite.yaml b/examples/ConfigFiles/Phase_Phenopowerlaw_BCC-Ferrite.yaml new file mode 100644 index 000000000..4940ca8bd --- /dev/null +++ b/examples/ConfigFiles/Phase_Phenopowerlaw_BCC-Ferrite.yaml @@ -0,0 +1,16 @@ +# Tasan et.al. 2015 Acta Materalia +# Tasan et.al. 2015 International Journal of Plasticity +# Diehl et.al. 2015 Meccanica +Ferrite: + elasticity: {C_11: 233.3e9, C_12: 135.5e9, C_44: 118.0e9, type: hooke} + lattice: bcc + plasticity: + N_sl: [12, 12] + a_sl: 2.0 + dot_gamma_0_sl: 0.001 + h_0_sl_sl: 1000.0e6 + h_sl_sl: [1, 1, 1.4, 1.4, 1.4, 1.4] + n_sl: 20 + type: phenopowerlaw + xi_0_sl: [95.e6, 96.e6] + xi_inf_sl: [222.e6, 412.7e6] diff --git a/examples/ConfigFiles/Phase_Phenopowerlaw_BCC-Martensite.config b/examples/ConfigFiles/Phase_Phenopowerlaw_BCC-Martensite.config deleted file mode 100644 index a04f27e7f..000000000 --- a/examples/ConfigFiles/Phase_Phenopowerlaw_BCC-Martensite.config +++ /dev/null @@ -1,21 +0,0 @@ -# Tasan et.al. 2015 Acta Materalia -# Tasan et.al. 2015 International Journal of Plasticity -# Diehl et.al. 2015 Meccanica -[BCC-Martensite] - -elasticity hooke -plasticity phenopowerlaw - -lattice_structure bcc -Nslip 12 12 # per family -Ntwin 0 # per family -c11 417.4e9 -c12 242.4e9 -c44 211.1e9 -gdot0_slip 0.001 -n_slip 20 -tau0_slip 405.8e6 456.7e6 # per family -tausat_slip 872.9e6 971.2e6 # per family -h0_slipslip 563.0e9 -interaction_slipslip 1 1 1.4 1.4 1.4 1.4 -a_slip 2.0 diff --git a/examples/ConfigFiles/Phase_Phenopowerlaw_BCC-Martensite.yaml b/examples/ConfigFiles/Phase_Phenopowerlaw_BCC-Martensite.yaml new file mode 100644 index 000000000..b207d7b34 --- /dev/null +++ b/examples/ConfigFiles/Phase_Phenopowerlaw_BCC-Martensite.yaml @@ -0,0 +1,16 @@ +# Tasan et.al. 2015 Acta Materalia +# Tasan et.al. 2015 International Journal of Plasticity +# Diehl et.al. 2015 Meccanica +Martensite: + elasticity: {C_11: 417.4e9, C_12: 242.4e9, C_44: 211.1e9, type: hooke} + lattice: bcc + plasticity: + N_sl: [12, 12] + a_sl: 2.0 + dot_gamma_0_sl: 0.001 + h_0_sl_sl: 563.0e9 + h_sl_sl: [1, 1, 1.4, 1.4, 1.4, 1.4] + n_sl: 20 + type: phenopowerlaw + xi_0_sl: [405.8e6, 456.7e6] + xi_inf_sl: [872.9e6, 971.2e6] diff --git a/examples/SpectralMethod/Polycrystal/material.yaml b/examples/SpectralMethod/Polycrystal/material.yaml index cdc210152..671136d40 100644 --- a/examples/SpectralMethod/Polycrystal/material.yaml +++ b/examples/SpectralMethod/Polycrystal/material.yaml @@ -1,3 +1,4 @@ +--- homogenization: SX: N_constituents: 1 diff --git a/processing/post/addGaussian.py b/processing/post/addGaussian.py deleted file mode 100755 index f00122c63..000000000 --- a/processing/post/addGaussian.py +++ /dev/null @@ -1,76 +0,0 @@ -#!/usr/bin/env python3 - -import os -import sys -from io import StringIO -from optparse import OptionParser - -from scipy import ndimage - -import damask - - -scriptName = os.path.splitext(os.path.basename(__file__))[0] -scriptID = ' '.join([scriptName,damask.version]) - - -# -------------------------------------------------------------------- -# MAIN -# -------------------------------------------------------------------- - -parser = OptionParser(option_class=damask.extendableOption, usage='%prog option [ASCIItable(s)]', description = """ -Add column(s) containing Gaussian filtered values of requested column(s). -Operates on periodic and non-periodic ordered three-dimensional data sets. -For details see scipy.ndimage documentation. - -""", version = scriptID) - -parser.add_option('-p','--pos','--periodiccellcenter', - dest = 'pos', - type = 'string', metavar = 'string', - help = 'label of coordinates [%default]') -parser.add_option('-s','--scalar', - dest = 'labels', - action = 'extend', metavar = '', - help = 'label(s) of scalar field values') -parser.add_option('-o','--order', - dest = 'order', - type = int, - metavar = 'int', - help = 'order of the filter [%default]') -parser.add_option('--sigma', - dest = 'sigma', - type = float, - metavar = 'float', - help = 'standard deviation [%default]') -parser.add_option('--periodic', - dest = 'periodic', - action = 'store_true', - help = 'assume periodic grain structure') - - - -parser.set_defaults(pos = 'pos', - order = 0, - sigma = 1, - ) - -(options,filenames) = parser.parse_args() -if filenames == []: filenames = [None] - -if options.labels is None: parser.error('no data column specified.') - -for name in filenames: - damask.util.report(scriptName,name) - - table = damask.Table.load(StringIO(''.join(sys.stdin.read())) if name is None else name) - damask.grid_filters.coord0_check(table.get(options.pos)) - - for label in options.labels: - table = table.add('Gauss{}({})'.format(options.sigma,label), - ndimage.filters.gaussian_filter(table.get(label).reshape(-1), - options.sigma,options.order, - mode = 'wrap' if options.periodic else 'nearest'), - scriptID+' '+' '.join(sys.argv[1:])) - - table.save((sys.stdout if name is None else name), legacy=True) diff --git a/processing/pre/geom_fromDREAM3D.py b/processing/pre/geom_fromDREAM3D.py index 639c1d894..eca837455 100755 --- a/processing/pre/geom_fromDREAM3D.py +++ b/processing/pre/geom_fromDREAM3D.py @@ -1,12 +1,8 @@ #!/usr/bin/env python3 import os -import sys from optparse import OptionParser -import h5py -import numpy as np - import damask @@ -64,88 +60,12 @@ parser.set_defaults(pointwise = 'CellData', if options.basegroup is None: parser.error('No base group selected') -rootDir ='DataContainers' - - if filenames == []: parser.error('no input file specified.') for name in filenames: - damask.util.report(scriptName,name) + damask.util.report(scriptName,name) - errors = [] + geom = damask.Geom.load_DREAM3D(name,options.basegroup,options.pointwise) + damask.util.croak(geom) - inFile = h5py.File(name, 'r') - group_geom = os.path.join(rootDir,options.basegroup,'_SIMPL_GEOMETRY') - try: - size = inFile[os.path.join(group_geom,'DIMENSIONS')][...] \ - * inFile[os.path.join(group_geom,'SPACING')][...] - grid = inFile[os.path.join(group_geom,'DIMENSIONS')][...] - origin = inFile[os.path.join(group_geom,'ORIGIN')][...] - except KeyError: - errors.append('Geometry data ({}) not found'.format(group_geom)) - - - group_pointwise = os.path.join(rootDir,options.basegroup,options.pointwise) - if options.average is None: - label = 'Point' - - dataset = os.path.join(group_pointwise,options.quaternion) - try: - quats = np.reshape(inFile[dataset][...],(np.product(grid),4)) - rot = [damask.Rotation.from_quaternion(q,True,P=+1) for q in quats] - except KeyError: - errors.append('Pointwise orientation (quaternion) data ({}) not readable'.format(dataset)) - - dataset = os.path.join(group_pointwise,options.phase) - try: - phase = np.reshape(inFile[dataset][...],(np.product(grid))) - except KeyError: - errors.append('Pointwise phase data ({}) not readable'.format(dataset)) - - microstructure = np.arange(1,np.product(grid)+1,dtype=int).reshape(grid,order='F') - - - else: - label = 'Grain' - - dataset = os.path.join(group_pointwise,options.microstructure) - try: - microstructure = np.transpose(inFile[dataset][...].reshape(grid[::-1]),(2,1,0)) # convert from C ordering - except KeyError: - errors.append('Link between pointwise and grain average data ({}) not readable'.format(dataset)) - - group_average = os.path.join(rootDir,options.basegroup,options.average) - - dataset = os.path.join(group_average,options.quaternion) - try: - rot = [damask.Rotation.from_quaternion(q,True,P=+1) for q in inFile[dataset][...][1:]] # skip first entry (unindexed) - except KeyError: - errors.append('Average orientation data ({}) not readable'.format(dataset)) - - dataset = os.path.join(group_average,options.phase) - try: - phase = [i[0] for i in inFile[dataset][...]][1:] # skip first entry (unindexed) - except KeyError: - errors.append('Average phase data ({}) not readable'.format(dataset)) - - if errors != []: - damask.util.croak(errors) - continue - - config_header = [''] - for i in range(np.nanmax(microstructure)): - config_header += ['[{}{}]'.format(label,i+1), - '(gauss)\tphi1 {:.2f}\tPhi {:.2f}\tphi2 {:.2f}'.format(*rot[i].as_Eulers(degrees = True)), - ] - config_header += [''] - for i in range(np.nanmax(microstructure)): - config_header += ['[{}{}]'.format(label,i+1), - '(constituent)\tphase {}\ttexture {}\tfraction 1.0'.format(phase[i],i+1), - ] - - header = [scriptID + ' ' + ' '.join(sys.argv[1:])]\ - + config_header - geom = damask.Geom(microstructure,size,origin,comments=header) - damask.util.croak(geom) - - geom.save_ASCII(os.path.splitext(name)[0]+'.geom') + geom.save_ASCII(os.path.splitext(name)[0]+'.geom') diff --git a/processing/pre/geom_fromTable.py b/processing/pre/geom_fromTable.py index ed172b9fa..9ff4ffdc2 100755 --- a/processing/pre/geom_fromTable.py +++ b/processing/pre/geom_fromTable.py @@ -2,11 +2,8 @@ import os import sys -from io import StringIO from optparse import OptionParser -import numpy as np - import damask @@ -40,64 +37,21 @@ parser.add_option('-q', '--quaternion', dest = 'quaternion', type = 'string', metavar='string', help = 'quaternion label') -parser.add_option('--axes', - dest = 'axes', - type = 'string', nargs = 3, metavar = ' '.join(['string']*3), - help = 'orientation coordinate frame in terms of position coordinate frame [+x +y +z]') - -parser.set_defaults(pos = 'pos', - ) +parser.set_defaults(pos= 'pos') (options,filenames) = parser.parse_args() if filenames == []: filenames = [None] -if np.sum([options.quaternion is not None, - options.microstructure is not None]) != 1: - parser.error('need either microstructure or quaternion (and optionally phase) as input.') -if options.microstructure is not None and options.phase is not None: - parser.error('need either microstructure or phase (and mandatory quaternion) as input.') -if options.axes is not None and not set(options.axes).issubset(set(['x','+x','-x','y','+y','-y','z','+z','-z'])): - parser.error('invalid axes {} {} {}.'.format(*options.axes)) - for name in filenames: damask.util.report(scriptName,name) - table = damask.Table.load(StringIO(''.join(sys.stdin.read())) if name is None else name) - table.sort_by(['{}_{}'.format(i,options.pos) for i in range(3,0,-1)]) # x fast, y slow - grid,size,origin = damask.grid_filters.cell_coord0_gridSizeOrigin(table.get(options.pos)) + labels = [] + for l in [options.quaternion,options.phase,options.microstructure]: + if l is not None: labels.append(l) - config_header = table.comments - - if options.microstructure: - microstructure = table.get(options.microstructure).reshape(grid,order='F') - - elif options.quaternion: - q = table.get(options.quaternion) - phase = table.get(options.phase).astype(int) if options.phase else \ - np.ones((table.data.shape[0],1),dtype=int) - - unique,unique_inverse = np.unique(np.hstack((q,phase)),return_inverse=True,axis=0) - microstructure = unique_inverse.reshape(grid,order='F') + 1 - - config_header = [''] - for i,data in enumerate(unique): - ori = damask.Rotation(data[0:4]) - config_header += ['[Grain{}]'.format(i+1), - '(gauss)\tphi1 {:.2f}\tPhi {:.2f}\tphi2 {:.2f}'.format(*ori.as_Eulers(degrees = True)), - ] - if options.axes is not None: config_header += ['axes\t{} {} {}'.format(*options.axes)] - - config_header += [''] - for i,data in enumerate(unique): - config_header += ['[Grain{}]'.format(i+1), - '(constituent)\tphase {}\ttexture {}\tfraction 1.0'.format(int(data[4]),i+1), - ] - - header = [scriptID + ' ' + ' '.join(sys.argv[1:])]\ - + config_header - geom = damask.Geom(microstructure,size,origin, - comments=header) + t = damask.Table.load(name) + geom = damask.Geom.from_table(t,options.pos,labels) damask.util.croak(geom) geom.save_ASCII(sys.stdout if name is None else os.path.splitext(name)[0]+'.geom') diff --git a/python/damask/__init__.py b/python/damask/__init__.py index e21ebd03d..600f64138 100644 --- a/python/damask/__init__.py +++ b/python/damask/__init__.py @@ -10,20 +10,21 @@ with open(_Path(__file__).parent/_Path('VERSION')) as _f: # make classes directly accessible as damask.Class from ._environment import Environment as _ # noqa environment = _() -from ._table import Table # noqa -from ._vtk import VTK # noqa -from ._colormap import Colormap # noqa -from ._rotation import Rotation # noqa -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 -from . import util # noqa -from . import seeds # noqa -from . import grid_filters # noqa -from . import mechanics # noqa +from . import util # noqa +from . import seeds # noqa +from . import mechanics # noqa +from . import solver # noqa +from . import grid_filters # noqa +from ._lattice import Symmetry, Lattice# noqa +from ._table import Table # noqa +from ._rotation import Rotation # noqa +from ._vtk import VTK # noqa +from ._colormap import Colormap # noqa +from ._orientation import Orientation # noqa +from ._config import Config # noqa +from ._configmaterial import ConfigMaterial # noqa +from ._geom import Geom # noqa +from ._result import Result # noqa diff --git a/python/damask/_config.py b/python/damask/_config.py new file mode 100644 index 000000000..c9130d7aa --- /dev/null +++ b/python/damask/_config.py @@ -0,0 +1,80 @@ +from io import StringIO +import abc + +import yaml + +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 Config(dict): + """YAML-based configuration.""" + + def __repr__(self): + """Show as in file.""" + output = StringIO() + self.save(output) + output.seek(0) + return ''.join(output.readlines()) + + @classmethod + def load(cls,fname): + """ + Load from yaml file. + + Parameters + ---------- + fname : file, str, or pathlib.Path + Filename or file for writing. + + """ + try: + fhandle = open(fname) + except TypeError: + fhandle = fname + return cls(yaml.safe_load(fhandle)) + + def save(self,fname,**kwargs): + """ + Save to yaml file. + + Parameters + ---------- + fname : file, str, or pathlib.Path + Filename or file for writing. + **kwargs : dict + Keyword arguments parsed to yaml.dump. + + """ + try: + fhandle = open(fname,'w') + except TypeError: + fhandle = fname + + if 'width' not in kwargs: + kwargs['width'] = 256 + if 'default_flow_style' not in kwargs: + kwargs['default_flow_style'] = None + fhandle.write(yaml.dump(dict(self),Dumper=NiceDumper,**kwargs)) + + + @property + @abc.abstractmethod + def is_complete(self): + """Check for completeness.""" + pass + + @property + @abc.abstractmethod + def is_valid(self): + """Check for valid file layout.""" + pass diff --git a/python/damask/_configmaterial.py b/python/damask/_configmaterial.py new file mode 100644 index 000000000..a7ecec108 --- /dev/null +++ b/python/damask/_configmaterial.py @@ -0,0 +1,299 @@ +import copy + +import numpy as np + +from . import grid_filters +from . import Config +from . import Lattice +from . import Rotation + +class ConfigMaterial(Config): + """Material configuration.""" + + def save(self,fname='material.yaml',**kwargs): + """ + Save to yaml file. + + Parameters + ---------- + fname : file, str, or pathlib.Path, optional + Filename or file for writing. Defaults to 'material.yaml'. + **kwargs + Keyword arguments parsed to yaml.dump. + + """ + super().save(fname,**kwargs) + + + @staticmethod + def from_table(table,coordinates=None,constituents={},**kwargs): + """ + Load from an ASCII table. + + Parameters + ---------- + table : damask.Table + Table that contains material information. + coordinates : str, optional + Label of spatial coordiates. Used for sorting and performing a + sanity check. Default to None, in which case no sorting or checking is + peformed. + constituents : dict, optional + Entries for 'constituents'. The key is the name and the value specifies + the label of the data column in the table + **kwargs + Keyword arguments where the key is the name and the value specifies + the label of the data column in the table + + Examples + -------- + >>> import damask + >>> import damask.ConfigMaterial as cm + >>> t = damask.Table.load('small.txt') + >>> t + pos pos pos qu qu qu qu phase homog + 0 0 0 0 0.19 0.8 0.24 -0.51 Aluminum SX + 1 1 0 0 0.8 0.19 0.24 -0.51 Steel SX + >>> cm.from_table(t,'pos',{'O':'qu','phase':'phase'},homogenization='homog') + material: + - constituents: + - O: [0.19, 0.8, 0.24, -0.51] + fraction: 1.0 + phase: Aluminum + homogenization: SX + - constituents: + - O: [0.8, 0.19, 0.24, -0.51] + fraction: 1.0 + phase: Steel + homogenization: SX + + """ + if coordinates is not None: + t = table.sort_by([f'{i}_{coordinates}' for i in range(3,0,-1)]) + grid_filters.coord0_check(t.get(coordinates)) + else: + t = table + + constituents_ = {k:t.get(v) for k,v in constituents.items()} + kwargs_ = {k:t.get(v) for k,v in kwargs.items()} + + _,idx = np.unique(np.hstack(list({**constituents_,**kwargs_}.values())),return_index=True,axis=0) + + constituents_ = {k:v[idx].squeeze() for k,v in constituents_.items()} + kwargs_ = {k:v[idx].squeeze() for k,v in kwargs_.items()} + + return ConfigMaterial().material_add(constituents_,**kwargs_) + + + @property + def is_complete(self): + """Check for completeness.""" + ok = True + for top_level in ['homogenization','phase','material']: + # 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['material']) > 0 + if len(self['material']) < 1: print('Incomplete material definition') + + if ok: + homogenization = set() + phase = set() + for i,v in enumerate(self['material']): + if 'homogenization' in v: + homogenization.add(v['homogenization']) + else: + print(f'No homogenization specified in material {i}') + ok = False + + if 'constituents' in v: + for ii,vv in enumerate(v['constituents']): + if 'O' not in vv: + print('No orientation specified in constituent {ii} of material {i}') + ok = False + if 'phase' in vv: + phase.add(vv['phase']) + else: + print(f'No phase specified in constituent {ii} of material {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 'material' in self: + for i,v in enumerate(self['material']): + if 'constituents' in v: + f = 0.0 + for c in v['constituents']: + f+= float(c['fraction']) + if 'O' in c: + try: + Rotation.from_quaternion(c['O']) + except ValueError: + o = c['O'] + print(f"Invalid orientation: '{o}' in material '{i}'") + ok = False + if not np.isclose(f,1.0): + print(f"Invalid total fraction '{f}' in material '{i}'") + ok = False + + return ok + + + def material_rename_phase(self,mapping,ID=None,constituent=None): + """ + Change phase name in material. + + Parameters + ---------- + mapping: dictionary + Mapping from old name to new name + ID: list of ints, optional + Limit renaming to selected material IDs. + constituent: list of ints, optional + Limit renaming to selected constituents. + + """ + dup = copy.deepcopy(self) + for i,m in enumerate(dup['material']): + 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 material_rename_homogenization(self,mapping,ID=None): + """ + Change homogenization name in material. + + 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['material']): + if ID and i not in ID: continue + try: + m['homogenization'] = mapping[m['homogenization']] + except KeyError: + continue + return dup + + + def material_add(self,constituents,**kwargs): + """ + Add material entries. + + Parameters + ---------- + constituents : dict + Entries for 'constituents'. The key is the name and the value specifies + the label of the data column in the table + **kwargs + Keyword arguments where the key is the name and the value specifies + the label of the data column in the table + + Examples + -------- + >>> import damask + >>> m = damask.ConfigMaterial() + >>> O = damask.Rotation.from_random(3).as_quaternion() + >>> phase = ['Aluminum','Steel','Aluminum'] + >>> m.material_add(constituents={'phase':phase,'O':O},homogenization='SX') + material: + - constituents: + - O: [0.577764, -0.146299, -0.617669, 0.513010] + fraction: 1.0 + phase: Aluminum + homogenization: SX + - constituents: + - O: [0.184176, 0.340305, 0.737247, 0.553840] + fraction: 1.0 + phase: Steel + homogenization: SX + - constituents: + - O: [0.0886257, -0.144848, 0.615674, -0.769487] + fraction: 1.0 + phase: Aluminum + homogenization: SX + + """ + c = [{'constituents':u} for u in ConfigMaterial._constituents(**constituents)] + for k,v in kwargs.items(): + if hasattr(v,'__len__') and not isinstance(v,str): + if len(v) != len(c): + raise ValueError('len mismatch 1') + for i,vv in enumerate(v): + c[i][k] = [w.item() for w in vv] if isinstance(vv,np.ndarray) else vv.item() + else: + for i in range(len(c)): + c[i][k] = v + dup = copy.deepcopy(self) + if 'material' not in dup: dup['material'] = [] + dup['material'] +=c + + return dup + + + @staticmethod + def _constituents(N=1,**kwargs): + """Construct list of constituents.""" + for v in kwargs.values(): + if hasattr(v,'__len__') and not isinstance(v,str): N_material = len(v) + + if N == 1: + m = [[{'fraction':1.0}] for _ in range(N_material)] + for k,v in kwargs.items(): + if hasattr(v,'__len__') and not isinstance(v,str): + if len(v) != N_material: + raise ValueError('len mismatch 2') + for i,vv in enumerate(np.array(v)): + m[i][0][k] = [w.item() for w in vv] if isinstance(vv,np.ndarray) else vv.item() + else: + for i in range(N_material): + m[i][0][k] = v + return m + else: + raise NotImplementedError diff --git a/python/damask/_geom.py b/python/damask/_geom.py index cfcdf5539..6366f06ab 100644 --- a/python/damask/_geom.py +++ b/python/damask/_geom.py @@ -1,15 +1,17 @@ import copy import multiprocessing as mp from functools import partial +from os import path import numpy as np +import h5py from scipy import ndimage,spatial from . import environment -from . import Rotation from . import VTK from . import util from . import grid_filters +from . import Rotation class Geom: @@ -207,6 +209,68 @@ class Geom: return Geom(material.reshape(grid,order='F'),size,origin,comments) + + @staticmethod + def load_DREAM3D(fname,base_group,point_data=None,material='FeatureIds'): + """ + Load a DREAM.3D file. + + Parameters + ---------- + fname : str + Filename of the DREAM.3D file + base_group : str + Name of the group (folder) below 'DataContainers'. For example + 'SyntheticVolumeDataContainer'. + point_data : str, optional + Name of the group (folder) containing the point wise material data, + for example 'CellData'. Defaults to None, in which case points consecutively numbered. + material : str, optional + Name of the dataset containing the material ID. Defaults to + 'FeatureIds'. + + """ + root_dir ='DataContainers' + f = h5py.File(fname, 'r') + g = path.join(root_dir,base_group,'_SIMPL_GEOMETRY') + size = f[path.join(g,'DIMENSIONS')][()] * f[path.join(g,'SPACING')][()] + grid = f[path.join(g,'DIMENSIONS')][()] + origin = f[path.join(g,'ORIGIN')][()] + group_pointwise = path.join(root_dir,base_group,point_data) + + ma = np.arange(1,np.product(grid)+1,dtype=int) if point_data is None else \ + np.reshape(f[path.join(group_pointwise,material)],grid.prod()) + + return Geom(ma.reshape(grid,order='F'),size,origin,util.execution_stamp('Geom','load_DREAM3D')) + + + @staticmethod + def from_table(table,coordinates,labels): + """ + Load an ASCII table. + + Parameters + ---------- + table : damask.Table + Table that contains material information. + coordinates : str + Label of the column containing the spatial coordinates. + labels : str or list of str + Label(s) of the columns containing the material definition. + Each unique combintation of values results in a material. + + """ + t = table.sort_by([f'{i}_{coordinates}' for i in range(3,0,-1)]) + + grid,size,origin = grid_filters.cell_coord0_gridSizeOrigin(t.get(coordinates)) + + labels_ = [labels] if isinstance(labels,str) else labels + _,unique_inverse = np.unique(np.hstack([t.get(l) for l in labels_]),return_inverse=True,axis=0) + ma = unique_inverse.reshape(grid,order='F') + 1 + + return Geom(ma,size,origin,util.execution_stamp('Geom','from_table')) + + @staticmethod def _find_closest_seed(seeds, weights, point): return np.argmin(np.sum((np.broadcast_to(point,(len(seeds),3))-seeds)**2,axis=1) - weights) @@ -399,7 +463,7 @@ class Geom: def save(self,fname,compress=True): """ - Generate vtk rectilinear grid. + Store as vtk rectilinear grid. Parameters ---------- @@ -489,7 +553,7 @@ class Geom: coords_rot = R.broadcast_to(tuple(self.grid))@coords with np.errstate(all='ignore'): - mask = np.where(np.sum(np.power(coords_rot/r,2.0**exponent),axis=-1) > 1.0,True,False) + mask = np.sum(np.power(coords_rot/r,2.0**np.array(exponent)),axis=-1) > 1.0 if periodic: # translate back to center mask = np.roll(mask,((c-np.ones(3)*.5)*self.grid).astype(int),(0,1,2)) diff --git a/python/damask/_material.py b/python/damask/_material.py deleted file mode 100644 index 106d1582e..000000000 --- a/python/damask/_material.py +++ /dev/null @@ -1,193 +0,0 @@ -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 diff --git a/python/damask/_table.py b/python/damask/_table.py index 431cf1886..dd8df97b0 100644 --- a/python/damask/_table.py +++ b/python/damask/_table.py @@ -33,6 +33,10 @@ class Table: """Brief overview.""" return util.srepr(self.comments)+'\n'+self.data.__repr__() + def __len__(self): + """Number of rows.""" + return len(self.data) + def __copy__(self): """Copy Table.""" return copy.deepcopy(self) diff --git a/python/tests/reference/Material/material.yaml b/python/tests/reference/ConfigMaterial/material.yaml similarity index 52% rename from python/tests/reference/Material/material.yaml rename to python/tests/reference/ConfigMaterial/material.yaml index 1d3cf08a8..97c6504bb 100644 --- a/python/tests/reference/Material/material.yaml +++ b/python/tests/reference/ConfigMaterial/material.yaml @@ -1,33 +1,35 @@ homogenization: SX: + N_constituents: 2 mech: {type: none} Taylor: - mech: {type: isostrain, N_constituents: 2} + N_constituents: 2 + mech: {type: isostrain} -microstructure: +material: - constituents: - fraction: 1.0 - orientation: [1.0, 0.0, 0.0, 0.0] + O: [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] + O: [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] + O: [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] + - constituents: + - fraction: 0.5 + O: [0.28645844315788244, -0.022571491243423537, -0.467933059311115, -0.8357456192708106] phase: Aluminum - - fraction: .5 - orientation: [0.3986143167493579, -0.7014883552495493, 0.2154871765709027, 0.5500781677772945] + - fraction: 0.5 + O: [0.3986143167493579, -0.7014883552495493, 0.2154871765709027, 0.5500781677772945] phase: Steel + homogenization: Taylor phase: Aluminum: diff --git a/python/tests/test_Config.py b/python/tests/test_Config.py new file mode 100644 index 000000000..e715ad763 --- /dev/null +++ b/python/tests/test_Config.py @@ -0,0 +1,37 @@ +import pytest + +from damask import Config + +class TestConfig: + + @pytest.mark.parametrize('flow_style',[None,True,False]) + def test_load_save_str(self,tmp_path,flow_style): + config = Config() + config['A'] = 1 + config['B'] = [2,3] + config.save(tmp_path/'config.yaml',default_flow_style=flow_style) + assert Config.load(tmp_path/'config.yaml') == config + + def test_load_save_file(self,tmp_path): + config = Config() + config['A'] = 1 + config['B'] = [2,3] + with open(tmp_path/'config.yaml','w') as f: + config.save(f) + with open(tmp_path/'config.yaml') as f: + assert Config.load(f) == config + + def test_repr(self,tmp_path): + config = Config() + config['A'] = 1 + config['B'] = [2,3] + with open(tmp_path/'config.yaml','w') as f: + f.write(config.__repr__()) + assert Config.load(tmp_path/'config.yaml') == config + + + def test_abstract_is_valid(self): + assert Config().is_valid is None + + def test_abstract_is_complete(self): + assert Config().is_complete is None diff --git a/python/tests/test_ConfigMaterial.py b/python/tests/test_ConfigMaterial.py new file mode 100644 index 000000000..4863a8ac4 --- /dev/null +++ b/python/tests/test_ConfigMaterial.py @@ -0,0 +1,76 @@ +import os + +import pytest + +from damask import ConfigMaterial + +@pytest.fixture +def reference_dir(reference_dir_base): + """Directory containing reference results.""" + return reference_dir_base/'ConfigMaterial' + + +class TestConfigMaterial: + + @pytest.mark.parametrize('fname',[None,'test.yaml']) + def test_load_save(self,reference_dir,tmp_path,fname): + reference = ConfigMaterial.load(reference_dir/'material.yaml') + os.chdir(tmp_path) + if fname is None: + reference.save() + new = ConfigMaterial.load('material.yaml') + else: + reference.save(fname) + new = ConfigMaterial.load(fname) + assert reference == new + + def test_valid_complete(self,reference_dir): + material_config = ConfigMaterial.load(reference_dir/'material.yaml') + assert material_config.is_valid and material_config.is_complete + + def test_invalid_lattice(self,reference_dir): + material_config = ConfigMaterial.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 = ConfigMaterial.load(reference_dir/'material.yaml') + material_config['material'][0]['constituents'][0]['O']=[0,0,0,0] + assert not material_config.is_valid + + def test_invalid_fraction(self,reference_dir): + material_config = ConfigMaterial.load(reference_dir/'material.yaml') + material_config['material'][0]['constituents'][0]['fraction']=.9 + assert not material_config.is_valid + + @pytest.mark.parametrize('item',['homogenization','phase','material']) + def test_incomplete_missing(self,reference_dir,item): + material_config = ConfigMaterial.load(reference_dir/'material.yaml') + del material_config[item] + assert not material_config.is_complete + + @pytest.mark.parametrize('item',['O','phase']) + def test_incomplete_material_constituent(self,reference_dir,item): + material_config = ConfigMaterial.load(reference_dir/'material.yaml') + del material_config['material'][0]['constituents'][0][item] + assert not material_config.is_complete + + def test_incomplete_material_homogenization(self,reference_dir): + material_config = ConfigMaterial.load(reference_dir/'material.yaml') + del material_config['material'][0]['homogenization'] + assert not material_config.is_complete + + def test_incomplete_phase_lattice(self,reference_dir): + material_config = ConfigMaterial.load(reference_dir/'material.yaml') + del material_config['phase']['Aluminum']['lattice'] + assert not material_config.is_complete + + def test_incomplete_wrong_phase(self,reference_dir): + material_config = ConfigMaterial.load(reference_dir/'material.yaml') + new = material_config.material_rename_phase({'Steel':'FeNbC'}) + assert not new.is_complete + + def test_incomplete_wrong_homogenization(self,reference_dir): + material_config = ConfigMaterial.load(reference_dir/'material.yaml') + new = material_config.material_rename_homogenization({'Taylor':'isostrain'}) + assert not new.is_complete diff --git a/python/tests/test_Material.py b/python/tests/test_Material.py deleted file mode 100644 index 567dfe646..000000000 --- a/python/tests/test_Material.py +++ /dev/null @@ -1,61 +0,0 @@ -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 diff --git a/src/YAML_parse.f90 b/src/YAML_parse.f90 index cb5b726dc..8e20e0c29 100644 --- a/src/YAML_parse.f90 +++ b/src/YAML_parse.f90 @@ -220,13 +220,26 @@ logical function isKey(line) if(len(IO_rmComment(line)) == 0) then isKey = .false. else - isKey = IO_rmComment(line(len(IO_rmComment(line)):len(IO_rmComment(line)))) == ':' & - .and. .not. isFlow(line) + isKey = index(IO_rmComment(line),':',back=.false.) == len(IO_rmComment(line)) .and. & + index(IO_rmComment(line),':',back=.true.) == len(IO_rmComment(line)) .and. & + .not. isFlow(line) endif end function isKey +!-------------------------------------------------------------------------------------------------- +! @brief check whether a string is a list in flow style +!-------------------------------------------------------------------------------------------------- +logical function isFlowList(line) + + character(len=*), intent(in) :: line + + isFlowList = index(adjustl(line),'[') == 1 + +end function isFlowList + + !-------------------------------------------------------------------------------------------------- ! @brief skip empty lines ! @details update start position in the block by skipping empty lines if present. @@ -244,7 +257,6 @@ subroutine skip_empty_lines(blck,s_blck) if(empty) s_blck = s_blck + index(blck(s_blck:),IO_EOL) enddo - end subroutine skip_empty_lines @@ -273,6 +285,58 @@ subroutine skip_file_header(blck,s_blck) end subroutine skip_file_header +!-------------------------------------------------------------------------------------------------- +!> @brief check if a line in flow YAML starts and ends in the same line +!-------------------------------------------------------------------------------------------------- +logical function flow_is_closed(str,e_char) + + character(len=*), intent(in) :: str + character, intent(in) :: e_char !< end of list/dict ( '}' or ']') + integer :: N_sq, & !< number of open square brackets + N_cu, & !< number of open curly brackets + i + character(len=:), allocatable:: line + + flow_is_closed = .false. + N_sq = 0 + N_cu = 0 + if(e_char == ']') line = str(index(str(:),'[')+1:) + if(e_char == '}') line = str(index(str(:),'{')+1:) + + do i = 1, len_trim(line) + flow_is_closed = (N_sq==0 .and. N_cu==0 .and. scan(line(i:i),e_char) == 1) + N_sq = N_sq + merge(1,0,line(i:i) == '[') + N_cu = N_cu + merge(1,0,line(i:i) == '{') + N_sq = N_sq - merge(1,0,line(i:i) == ']') + N_cu = N_cu - merge(1,0,line(i:i) == '}') + enddo + +end function flow_is_closed + + +!-------------------------------------------------------------------------------------------------- +!> @brief return the flow YAML line without line break +!-------------------------------------------------------------------------------------------------- +subroutine remove_line_break(blck,s_blck,e_char,flow_line) + + character(len=*), intent(in) :: blck !< YAML in mixed style + integer, intent(inout) :: s_blck + character, intent(in) :: e_char !< end of list/dict ( '}' or ']') + character(len=:), allocatable, intent(out) :: flow_line + logical :: line_end + + line_end =.false. + flow_line = '' + + do while(.not.line_end) + flow_line = flow_line//IO_rmComment(blck(s_blck:s_blck + index(blck(s_blck:),IO_EOL) - 2))//' ' + line_end = flow_is_closed(flow_line,e_char) + s_blck = s_blck + index(blck(s_blck:),IO_EOL) + enddo + +end subroutine remove_line_break + + !-------------------------------------------------------------------------------------------------- ! @brief reads a line of YAML block which is already in flow style ! @details Dicts should be enlcosed within '{}' for it to be consistent with DAMASK YAML parser @@ -402,7 +466,7 @@ recursive subroutine lst(blck,flow,s_blck,s_flow,offset) integer, intent(inout) :: s_blck, & !< start position in blck s_flow, & !< start position in flow offset !< stores leading '- ' in nested lists - character(len=:), allocatable :: line + character(len=:), allocatable :: line,flow_line integer :: e_blck,indent indent = indentDepth(blck(s_blck:),offset) @@ -437,8 +501,12 @@ recursive subroutine lst(blck,flow,s_blck,s_flow,offset) s_blck = e_blck +2 offset = 0 elseif(isFlow(line)) then - call line_isFlow(flow,s_flow,line) - s_blck = e_blck +2 + if(isFlowList(line)) then + call remove_line_break(blck,s_blck,']',flow_line) + else + call remove_line_break(blck,s_blck,'}',flow_line) + endif + call line_isFlow(flow,s_flow,flow_line) offset = 0 endif else ! list item in the same line @@ -448,8 +516,13 @@ recursive subroutine lst(blck,flow,s_blck,s_flow,offset) s_blck = e_blck +2 offset = 0 elseif(isFlow(line)) then - call line_isFlow(flow,s_flow,line) - s_blck = e_blck +2 + s_blck = s_blck + index(blck(s_blck:),'-') + if(isFlowList(line)) then + call remove_line_break(blck,s_blck,']',flow_line) + else + call remove_line_break(blck,s_blck,'}',flow_line) + endif + call line_isFlow(flow,s_flow,flow_line) offset = 0 else ! non scalar list item offset = offset + indentDepth(blck(s_blck:))+1 ! offset in spaces to be ignored @@ -486,8 +559,8 @@ recursive subroutine dct(blck,flow,s_blck,s_flow,offset) s_flow, & !< start position in flow offset - character(len=:), allocatable :: line - integer :: e_blck,indent + character(len=:), allocatable :: line,flow_line + integer :: e_blck,indent,col_pos logical :: previous_isKey previous_isKey = .false. @@ -521,12 +594,22 @@ recursive subroutine dct(blck,flow,s_blck,s_flow,offset) endif if(isKeyValue(line)) then - call keyValue_toFlow(flow,s_flow,line) + col_pos = index(line,':') + if(isFlow(line(col_pos+1:))) then + if(isFlowList(line(col_pos+1:))) then + call remove_line_break(blck,s_blck,']',flow_line) + else + call remove_line_break(blck,s_blck,'}',flow_line) + endif + call keyValue_toFlow(flow,s_flow,flow_line) + else + call keyValue_toFlow(flow,s_flow,line) + s_blck = e_blck + 2 + endif else call line_toFlow(flow,s_flow,line) + s_blck = e_blck + 2 endif - - s_blck = e_blck +2 end if if(isScalar(line) .or. isKeyValue(line)) then @@ -559,7 +642,7 @@ recursive subroutine decide(blck,flow,s_blck,s_flow,offset) s_flow, & !< start position in flow offset integer :: e_blck - character(len=:), allocatable :: line + character(len=:), allocatable :: line,flow_line if(s_blck <= len(blck)) then call skip_empty_lines(blck,s_blck) @@ -583,8 +666,12 @@ recursive subroutine decide(blck,flow,s_blck,s_flow,offset) flow(s_flow:s_flow) = '}' s_flow = s_flow + 1 elseif(isFlow(line)) then + if(isFlowList(line)) then + call remove_line_break(blck,s_blck,']',flow_line) + else + call remove_line_break(blck,s_blck,'}',flow_line) + endif call line_isFlow(flow,s_flow,line) - s_blck = e_blck +2 else line = line(indentDepth(line)+1:) call line_toFlow(flow,s_flow,line) @@ -723,6 +810,36 @@ subroutine selfTest if (.not. to_flow(flow_mixed_braces) == flow) error stop 'to_flow' end block basic_flow + multi_line_flow1: block + character(len=*), parameter :: flow_multi = & + "%YAML 1.1"//IO_EOL//& + "---"//IO_EOL//& + "a: [b,"//IO_EOL//& + "c: "//IO_EOL//& + "d, e]"//IO_EOL + + character(len=*), parameter :: flow = & + "{a: [b, {c: d}, e]}" + + if( .not. to_flow(flow_multi) == flow) error stop 'to_flow' + end block multi_line_flow1 + + multi_line_flow2: block + character(len=*), parameter :: flow_multi = & + "%YAML 1.1"//IO_EOL//& + "---"//IO_EOL//& + "-"//IO_EOL//& + " a: {b:"//IO_EOL//& + "[c,"//IO_EOL//& + "d"//IO_EOL//& + "e, f]}"//IO_EOL + + character(len=*), parameter :: flow = & + "[{a: {b: [c, d e, f]}}]" + + if( .not. to_flow(flow_multi) == flow) error stop 'to_flow' + end block multi_line_flow2 + basic_mixed: block character(len=*), parameter :: block_flow = & "%YAML 1.1"//IO_EOL//& diff --git a/src/YAML_types.f90 b/src/YAML_types.f90 index cc1c85efd..09a2d0592 100644 --- a/src/YAML_types.f90 +++ b/src/YAML_types.f90 @@ -952,6 +952,9 @@ function tNode_get_byKey_asIndex(self,key) result(keyIndex) endif enddo + if(keyIndex == -1) call IO_error(140,ext_msg=key) + + end function tNode_get_byKey_asIndex diff --git a/src/constitutive.f90 b/src/constitutive.f90 index 62846359d..64d3f2d31 100644 --- a/src/constitutive.f90 +++ b/src/constitutive.f90 @@ -452,11 +452,11 @@ subroutine constitutive_init PhaseLoop2:do p = 1,phases%length !-------------------------------------------------------------------------------------------------- ! partition and initialize state - plasticState(p)%partionedState0 = plasticState(p)%state0 - plasticState(p)%state = plasticState(p)%partionedState0 + plasticState(p)%partitionedState0 = plasticState(p)%state0 + plasticState(p)%state = plasticState(p)%partitionedState0 forall(s = 1:phase_Nsources(p)) - sourceState(p)%p(s)%partionedState0 = sourceState(p)%p(s)%state0 - sourceState(p)%p(s)%state = sourceState(p)%p(s)%partionedState0 + sourceState(p)%p(s)%partitionedState0 = sourceState(p)%p(s)%state0 + sourceState(p)%p(s)%state = sourceState(p)%p(s)%partitionedState0 end forall constitutive_source_maxSizeDotState = max(constitutive_source_maxSizeDotState, & @@ -922,7 +922,7 @@ subroutine constitutive_allocateState(state, & allocate(state%atol (sizeState), source=0.0_pReal) allocate(state%state0 (sizeState,NipcMyPhase), source=0.0_pReal) - allocate(state%partionedState0(sizeState,NipcMyPhase), source=0.0_pReal) + allocate(state%partitionedState0(sizeState,NipcMyPhase), source=0.0_pReal) allocate(state%subState0 (sizeState,NipcMyPhase), source=0.0_pReal) allocate(state%state (sizeState,NipcMyPhase), source=0.0_pReal) diff --git a/src/crystallite.f90 b/src/crystallite.f90 index 0b19afac1..dc6b9f7da 100644 --- a/src/crystallite.f90 +++ b/src/crystallite.f90 @@ -44,30 +44,30 @@ module crystallite ! crystallite_Fp, & !< current plastic def grad (end of converged time step) crystallite_Fp0, & !< plastic def grad at start of FE inc - crystallite_partionedFp0,& !< plastic def grad at start of homog inc + crystallite_partitionedFp0,& !< plastic def grad at start of homog inc crystallite_subFp0,& !< plastic def grad at start of crystallite inc ! crystallite_Fi, & !< current intermediate def grad (end of converged time step) crystallite_Fi0, & !< intermediate def grad at start of FE inc - crystallite_partionedFi0,& !< intermediate def grad at start of homog inc + crystallite_partitionedFi0,& !< intermediate def grad at start of homog inc crystallite_subFi0,& !< intermediate def grad at start of crystallite inc ! crystallite_Lp0, & !< plastic velocitiy grad at start of FE inc - crystallite_partionedLp0, & !< plastic velocity grad at start of homog inc + crystallite_partitionedLp0, & !< plastic velocity grad at start of homog inc ! crystallite_Li, & !< current intermediate velocitiy grad (end of converged time step) crystallite_Li0, & !< intermediate velocitiy grad at start of FE inc - crystallite_partionedLi0, & !< intermediate velocity grad at start of homog inc + crystallite_partitionedLi0, & !< intermediate velocity grad at start of homog inc ! crystallite_S0, & !< 2nd Piola-Kirchhoff stress vector at start of FE inc - crystallite_partionedS0 !< 2nd Piola-Kirchhoff stress vector at start of homog inc + crystallite_partitionedS0 !< 2nd Piola-Kirchhoff stress vector at start of homog inc real(pReal), dimension(:,:,:,:,:), allocatable, public, protected :: & crystallite_P, & !< 1st Piola-Kirchhoff stress per grain crystallite_Lp, & !< current plastic velocitiy grad (end of converged time step) crystallite_S, & !< current 2nd Piola-Kirchhoff stress vector (end of converged time step) - crystallite_partionedF0 !< def grad at start of homog inc + crystallite_partitionedF0 !< def grad at start of homog inc real(pReal), dimension(:,:,:,:,:), allocatable, public :: & - crystallite_partionedF !< def grad to be reached at end of homog inc + crystallite_partitionedF !< def grad to be reached at end of homog inc logical, dimension(:,:,:), allocatable, public :: & crystallite_requested !< used by upper level (homogenization) to request crystallite calculation @@ -166,20 +166,20 @@ subroutine crystallite_init iMax = discretization_nIP eMax = discretization_nElem - allocate(crystallite_partionedF(3,3,cMax,iMax,eMax),source=0.0_pReal) + allocate(crystallite_partitionedF(3,3,cMax,iMax,eMax),source=0.0_pReal) allocate(crystallite_S0, & crystallite_F0, crystallite_Fi0,crystallite_Fp0, & crystallite_Li0,crystallite_Lp0, & - crystallite_partionedS0, & - crystallite_partionedF0,crystallite_partionedFp0,crystallite_partionedFi0, & - crystallite_partionedLp0,crystallite_partionedLi0, & + crystallite_partitionedS0, & + crystallite_partitionedF0,crystallite_partitionedFp0,crystallite_partitionedFi0, & + crystallite_partitionedLp0,crystallite_partitionedLi0, & crystallite_S,crystallite_P, & crystallite_Fe,crystallite_Fi,crystallite_Fp, & crystallite_Li,crystallite_Lp, & crystallite_subF,crystallite_subF0, & crystallite_subFp0,crystallite_subFi0, & - source = crystallite_partionedF) + source = crystallite_partitionedF) allocate(crystallite_dt(cMax,iMax,eMax),source=0.0_pReal) allocate(crystallite_subdt,crystallite_subFrac,crystallite_subStep, & @@ -269,10 +269,10 @@ subroutine crystallite_init !$OMP END PARALLEL DO - crystallite_partionedFp0 = crystallite_Fp0 - crystallite_partionedFi0 = crystallite_Fi0 - crystallite_partionedF0 = crystallite_F0 - crystallite_partionedF = crystallite_F0 + crystallite_partitionedFp0 = crystallite_Fp0 + crystallite_partitionedFi0 = crystallite_Fi0 + crystallite_partitionedF0 = crystallite_F0 + crystallite_partitionedF = crystallite_F0 call crystallite_orientations() @@ -280,8 +280,8 @@ subroutine crystallite_init do e = FEsolving_execElem(1),FEsolving_execElem(2) do i = FEsolving_execIP(1),FEsolving_execIP(2) do c = 1,homogenization_Ngrains(material_homogenizationAt(e)) - call constitutive_dependentState(crystallite_partionedF0(1:3,1:3,c,i,e), & - crystallite_partionedFp0(1:3,1:3,c,i,e), & + call constitutive_dependentState(crystallite_partitionedF0(1:3,1:3,c,i,e), & + crystallite_partitionedFp0(1:3,1:3,c,i,e), & c,i,e) ! update dependent state variables to be consistent with basic states enddo enddo @@ -325,8 +325,8 @@ function crystallite_stress() todo = .false. - subLp0 = crystallite_partionedLp0 - subLi0 = crystallite_partionedLi0 + subLp0 = crystallite_partitionedLp0 + subLi0 = crystallite_partitionedLi0 @@ -338,15 +338,15 @@ function crystallite_stress() do i = FEsolving_execIP(1),FEsolving_execIP(2); do c = 1,homogenization_Ngrains(material_homogenizationAt(e)) homogenizationRequestsCalculation: if (crystallite_requested(c,i,e)) then plasticState (material_phaseAt(c,e))%subState0( :,material_phaseMemberAt(c,i,e)) = & - plasticState (material_phaseAt(c,e))%partionedState0(:,material_phaseMemberAt(c,i,e)) + plasticState (material_phaseAt(c,e))%partitionedState0(:,material_phaseMemberAt(c,i,e)) do s = 1, phase_Nsources(material_phaseAt(c,e)) sourceState(material_phaseAt(c,e))%p(s)%subState0( :,material_phaseMemberAt(c,i,e)) = & - sourceState(material_phaseAt(c,e))%p(s)%partionedState0(:,material_phaseMemberAt(c,i,e)) + sourceState(material_phaseAt(c,e))%p(s)%partitionedState0(:,material_phaseMemberAt(c,i,e)) enddo - crystallite_subFp0(1:3,1:3,c,i,e) = crystallite_partionedFp0(1:3,1:3,c,i,e) - crystallite_subFi0(1:3,1:3,c,i,e) = crystallite_partionedFi0(1:3,1:3,c,i,e) - crystallite_subF0(1:3,1:3,c,i,e) = crystallite_partionedF0(1:3,1:3,c,i,e) + crystallite_subFp0(1:3,1:3,c,i,e) = crystallite_partitionedFp0(1:3,1:3,c,i,e) + crystallite_subFi0(1:3,1:3,c,i,e) = crystallite_partitionedFi0(1:3,1:3,c,i,e) + crystallite_subF0(1:3,1:3,c,i,e) = crystallite_partitionedF0(1:3,1:3,c,i,e) crystallite_subFrac(c,i,e) = 0.0_pReal crystallite_subStep(c,i,e) = 1.0_pReal/num%subStepSizeCryst todo(c,i,e) = .true. @@ -426,8 +426,8 @@ function crystallite_stress() ! prepare for integration if (todo(c,i,e)) then crystallite_subF(1:3,1:3,c,i,e) = crystallite_subF0(1:3,1:3,c,i,e) & - + crystallite_subStep(c,i,e) *( crystallite_partionedF (1:3,1:3,c,i,e) & - -crystallite_partionedF0(1:3,1:3,c,i,e)) + + crystallite_subStep(c,i,e) *( crystallite_partitionedF (1:3,1:3,c,i,e) & + -crystallite_partitionedF0(1:3,1:3,c,i,e)) crystallite_Fe(1:3,1:3,c,i,e) = matmul(matmul(crystallite_subF(1:3,1:3,c,i,e), & math_inv33(crystallite_Fp(1:3,1:3,c,i,e))), & math_inv33(crystallite_Fi(1:3,1:3,c,i,e))) @@ -441,8 +441,6 @@ function crystallite_stress() enddo elementLooping3 !$OMP END PARALLEL DO - call nonlocalConvergenceCheck - !-------------------------------------------------------------------------------------------------- ! integrate --- requires fully defined state array (basic + dependent state) where(.not. crystallite_converged .and. crystallite_subStep > num%subStepMinCryst) & ! do not try non-converged but fully cutbacked any further @@ -475,17 +473,17 @@ subroutine crystallite_initializeRestorationPoints(i,e) s do c = 1,homogenization_Ngrains(material_homogenizationAt(e)) - crystallite_partionedFp0(1:3,1:3,c,i,e) = crystallite_Fp0(1:3,1:3,c,i,e) - crystallite_partionedLp0(1:3,1:3,c,i,e) = crystallite_Lp0(1:3,1:3,c,i,e) - crystallite_partionedFi0(1:3,1:3,c,i,e) = crystallite_Fi0(1:3,1:3,c,i,e) - crystallite_partionedLi0(1:3,1:3,c,i,e) = crystallite_Li0(1:3,1:3,c,i,e) - crystallite_partionedF0(1:3,1:3,c,i,e) = crystallite_F0(1:3,1:3,c,i,e) - crystallite_partionedS0(1:3,1:3,c,i,e) = crystallite_S0(1:3,1:3,c,i,e) + crystallite_partitionedFp0(1:3,1:3,c,i,e) = crystallite_Fp0(1:3,1:3,c,i,e) + crystallite_partitionedLp0(1:3,1:3,c,i,e) = crystallite_Lp0(1:3,1:3,c,i,e) + crystallite_partitionedFi0(1:3,1:3,c,i,e) = crystallite_Fi0(1:3,1:3,c,i,e) + crystallite_partitionedLi0(1:3,1:3,c,i,e) = crystallite_Li0(1:3,1:3,c,i,e) + crystallite_partitionedF0(1:3,1:3,c,i,e) = crystallite_F0(1:3,1:3,c,i,e) + crystallite_partitionedS0(1:3,1:3,c,i,e) = crystallite_S0(1:3,1:3,c,i,e) - plasticState(material_phaseAt(c,e))%partionedState0(:,material_phasememberAt(c,i,e)) = & + plasticState(material_phaseAt(c,e))%partitionedState0(:,material_phasememberAt(c,i,e)) = & plasticState(material_phaseAt(c,e))%state0( :,material_phasememberAt(c,i,e)) do s = 1, phase_Nsources(material_phaseAt(c,e)) - sourceState(material_phaseAt(c,e))%p(s)%partionedState0(:,material_phasememberAt(c,i,e)) = & + sourceState(material_phaseAt(c,e))%p(s)%partitionedState0(:,material_phasememberAt(c,i,e)) = & sourceState(material_phaseAt(c,e))%p(s)%state0( :,material_phasememberAt(c,i,e)) enddo enddo @@ -506,17 +504,17 @@ subroutine crystallite_windForward(i,e) s do c = 1,homogenization_Ngrains(material_homogenizationAt(e)) - crystallite_partionedF0 (1:3,1:3,c,i,e) = crystallite_partionedF(1:3,1:3,c,i,e) - crystallite_partionedFp0(1:3,1:3,c,i,e) = crystallite_Fp (1:3,1:3,c,i,e) - crystallite_partionedLp0(1:3,1:3,c,i,e) = crystallite_Lp (1:3,1:3,c,i,e) - crystallite_partionedFi0(1:3,1:3,c,i,e) = crystallite_Fi (1:3,1:3,c,i,e) - crystallite_partionedLi0(1:3,1:3,c,i,e) = crystallite_Li (1:3,1:3,c,i,e) - crystallite_partionedS0 (1:3,1:3,c,i,e) = crystallite_S (1:3,1:3,c,i,e) + crystallite_partitionedF0 (1:3,1:3,c,i,e) = crystallite_partitionedF(1:3,1:3,c,i,e) + crystallite_partitionedFp0(1:3,1:3,c,i,e) = crystallite_Fp (1:3,1:3,c,i,e) + crystallite_partitionedLp0(1:3,1:3,c,i,e) = crystallite_Lp (1:3,1:3,c,i,e) + crystallite_partitionedFi0(1:3,1:3,c,i,e) = crystallite_Fi (1:3,1:3,c,i,e) + crystallite_partitionedLi0(1:3,1:3,c,i,e) = crystallite_Li (1:3,1:3,c,i,e) + crystallite_partitionedS0 (1:3,1:3,c,i,e) = crystallite_S (1:3,1:3,c,i,e) - plasticState (material_phaseAt(c,e))%partionedState0(:,material_phasememberAt(c,i,e)) = & + plasticState (material_phaseAt(c,e))%partitionedState0(:,material_phasememberAt(c,i,e)) = & plasticState (material_phaseAt(c,e))%state (:,material_phasememberAt(c,i,e)) do s = 1, phase_Nsources(material_phaseAt(c,e)) - sourceState(material_phaseAt(c,e))%p(s)%partionedState0(:,material_phasememberAt(c,i,e)) = & + sourceState(material_phaseAt(c,e))%p(s)%partitionedState0(:,material_phasememberAt(c,i,e)) = & sourceState(material_phaseAt(c,e))%p(s)%state (:,material_phasememberAt(c,i,e)) enddo enddo @@ -540,18 +538,18 @@ subroutine crystallite_restore(i,e,includeL) do c = 1,homogenization_Ngrains(material_homogenizationAt(e)) if (includeL) then - crystallite_Lp(1:3,1:3,c,i,e) = crystallite_partionedLp0(1:3,1:3,c,i,e) - crystallite_Li(1:3,1:3,c,i,e) = crystallite_partionedLi0(1:3,1:3,c,i,e) + crystallite_Lp(1:3,1:3,c,i,e) = crystallite_partitionedLp0(1:3,1:3,c,i,e) + crystallite_Li(1:3,1:3,c,i,e) = crystallite_partitionedLi0(1:3,1:3,c,i,e) endif ! maybe protecting everything from overwriting makes more sense - crystallite_Fp(1:3,1:3,c,i,e) = crystallite_partionedFp0(1:3,1:3,c,i,e) - crystallite_Fi(1:3,1:3,c,i,e) = crystallite_partionedFi0(1:3,1:3,c,i,e) - crystallite_S (1:3,1:3,c,i,e) = crystallite_partionedS0 (1:3,1:3,c,i,e) + crystallite_Fp(1:3,1:3,c,i,e) = crystallite_partitionedFp0(1:3,1:3,c,i,e) + crystallite_Fi(1:3,1:3,c,i,e) = crystallite_partitionedFi0(1:3,1:3,c,i,e) + crystallite_S (1:3,1:3,c,i,e) = crystallite_partitionedS0 (1:3,1:3,c,i,e) plasticState (material_phaseAt(c,e))%state( :,material_phasememberAt(c,i,e)) = & - plasticState (material_phaseAt(c,e))%partionedState0(:,material_phasememberAt(c,i,e)) + plasticState (material_phaseAt(c,e))%partitionedState0(:,material_phasememberAt(c,i,e)) do s = 1, phase_Nsources(material_phaseAt(c,e)) sourceState(material_phaseAt(c,e))%p(s)%state( :,material_phasememberAt(c,i,e)) = & - sourceState(material_phaseAt(c,e))%p(s)%partionedState0(:,material_phasememberAt(c,i,e)) + sourceState(material_phaseAt(c,e))%p(s)%partitionedState0(:,material_phasememberAt(c,i,e)) enddo enddo @@ -758,7 +756,7 @@ subroutine crystallite_results do o = 1, size(output_constituent(p)%label) select case (output_constituent(p)%label(o)) case('F') - selected_tensors = select_tensors(crystallite_partionedF,p) + selected_tensors = select_tensors(crystallite_partitionedF,p) call results_writeDataset(group,selected_tensors,output_constituent(p)%label(o),& 'deformation gradient','1') case('Fe') @@ -943,7 +941,7 @@ function integrateStress(ipc,ip,el,timeFraction) result(broken) F = crystallite_subF(1:3,1:3,ipc,ip,el) endif - call constitutive_dependentState(crystallite_partionedF(1:3,1:3,ipc,ip,el), & + call constitutive_dependentState(crystallite_partitionedF(1:3,1:3,ipc,ip,el), & crystallite_Fp(1:3,1:3,ipc,ip,el),ipc,ip,el) Lpguess = crystallite_Lp(1:3,1:3,ipc,ip,el) ! take as first guess @@ -1120,9 +1118,9 @@ subroutine integrateStateFPI(g,i,e) c = material_phaseMemberAt(g,i,e) broken = constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & - crystallite_partionedF0, & + crystallite_partitionedF0, & crystallite_Fi(1:3,1:3,g,i,e), & - crystallite_partionedFp0, & + crystallite_partitionedFp0, & crystallite_subdt(g,i,e), g,i,e,p,c) if(broken) return @@ -1152,9 +1150,9 @@ subroutine integrateStateFPI(g,i,e) if(broken) exit iteration broken = constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & - crystallite_partionedF0, & + crystallite_partitionedF0, & crystallite_Fi(1:3,1:3,g,i,e), & - crystallite_partionedFp0, & + crystallite_partitionedFp0, & crystallite_subdt(g,i,e), g,i,e,p,c) if(broken) exit iteration @@ -1243,9 +1241,9 @@ subroutine integrateStateEuler(g,i,e) c = material_phaseMemberAt(g,i,e) broken = constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & - crystallite_partionedF0, & + crystallite_partitionedF0, & crystallite_Fi(1:3,1:3,g,i,e), & - crystallite_partionedFp0, & + crystallite_partitionedFp0, & crystallite_subdt(g,i,e), g,i,e,p,c) if(broken) return @@ -1296,9 +1294,9 @@ subroutine integrateStateAdaptiveEuler(g,i,e) c = material_phaseMemberAt(g,i,e) broken = constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & - crystallite_partionedF0, & + crystallite_partitionedF0, & crystallite_Fi(1:3,1:3,g,i,e), & - crystallite_partionedFp0, & + crystallite_partitionedFp0, & crystallite_subdt(g,i,e), g,i,e,p,c) if(broken) return @@ -1325,9 +1323,9 @@ subroutine integrateStateAdaptiveEuler(g,i,e) if(broken) return broken = constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & - crystallite_partionedF0, & + crystallite_partitionedF0, & crystallite_Fi(1:3,1:3,g,i,e), & - crystallite_partionedFp0, & + crystallite_partitionedFp0, & crystallite_subdt(g,i,e), g,i,e,p,c) if(broken) return @@ -1434,9 +1432,9 @@ subroutine integrateStateRK(g,i,e,A,B,CC,DB) c = material_phaseMemberAt(g,i,e) broken = constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & - crystallite_partionedF0, & + crystallite_partitionedF0, & crystallite_Fi(1:3,1:3,g,i,e), & - crystallite_partionedFp0, & + crystallite_partitionedFp0, & crystallite_subdt(g,i,e), g,i,e,p,c) if(broken) return @@ -1476,9 +1474,9 @@ subroutine integrateStateRK(g,i,e,A,B,CC,DB) if(broken) exit broken = constitutive_collectDotState(crystallite_S(1:3,1:3,g,i,e), & - crystallite_partionedF0, & + crystallite_partitionedF0, & crystallite_Fi(1:3,1:3,g,i,e), & - crystallite_partionedFp0, & + crystallite_partitionedFp0, & crystallite_subdt(g,i,e)*CC(stage), g,i,e,p,c) if(broken) exit @@ -1526,38 +1524,6 @@ subroutine integrateStateRK(g,i,e,A,B,CC,DB) end subroutine integrateStateRK -!-------------------------------------------------------------------------------------------------- -!> @brief sets convergence flag for nonlocal calculations -!> @details one non-converged nonlocal sets all other nonlocals to non-converged to trigger cut back -!-------------------------------------------------------------------------------------------------- -subroutine nonlocalConvergenceCheck - - integer :: e,i,p - logical :: nonlocal_broken - - nonlocal_broken = .false. - !$OMP PARALLEL DO PRIVATE(p) - do e = FEsolving_execElem(1),FEsolving_execElem(2) - p = material_phaseAt(1,e) - do i = FEsolving_execIP(1),FEsolving_execIP(2) - if(plasticState(p)%nonlocal .and. .not. crystallite_converged(1,i,e)) nonlocal_broken = .true. - enddo - enddo - !$OMP END PARALLEL DO - - if(.not. nonlocal_broken) return - !$OMP PARALLEL DO PRIVATE(p) - do e = FEsolving_execElem(1),FEsolving_execElem(2) - p = material_phaseAt(1,e) - do i = FEsolving_execIP(1),FEsolving_execIP(2) - if(plasticState(p)%nonlocal) crystallite_converged(1,i,e) = .false. - enddo - enddo - !$OMP END PARALLEL DO - -end subroutine nonlocalConvergenceCheck - - !-------------------------------------------------------------------------------------------------- !> @brief determines whether a point is converged !-------------------------------------------------------------------------------------------------- @@ -1590,7 +1556,7 @@ subroutine crystallite_restartWrite write(fileName,'(a,i0,a)') trim(getSolverJobName())//'_',worldrank,'.hdf5' fileHandle = HDF5_openFile(fileName,'a') - call HDF5_write(fileHandle,crystallite_partionedF,'F') + call HDF5_write(fileHandle,crystallite_partitionedF,'F') call HDF5_write(fileHandle,crystallite_Fp, 'Fp') call HDF5_write(fileHandle,crystallite_Fi, 'Fi') call HDF5_write(fileHandle,crystallite_Lp, 'Lp') @@ -1665,7 +1631,7 @@ subroutine crystallite_forward integer :: i, j - crystallite_F0 = crystallite_partionedF + crystallite_F0 = crystallite_partitionedF crystallite_Fp0 = crystallite_Fp crystallite_Lp0 = crystallite_Lp crystallite_Fi0 = crystallite_Fi diff --git a/src/homogenization.f90 b/src/homogenization.f90 index de003fbc3..5aa10fcf3 100644 --- a/src/homogenization.f90 +++ b/src/homogenization.f90 @@ -404,16 +404,16 @@ subroutine partitionDeformation(subF,ip,el) chosenHomogenization: select case(homogenization_type(material_homogenizationAt(el))) case (HOMOGENIZATION_NONE_ID) chosenHomogenization - crystallite_partionedF(1:3,1:3,1,ip,el) = subF + crystallite_partitionedF(1:3,1:3,1,ip,el) = subF case (HOMOGENIZATION_ISOSTRAIN_ID) chosenHomogenization call mech_isostrain_partitionDeformation(& - crystallite_partionedF(1:3,1:3,1:homogenization_Ngrains(material_homogenizationAt(el)),ip,el), & + crystallite_partitionedF(1:3,1:3,1:homogenization_Ngrains(material_homogenizationAt(el)),ip,el), & subF) case (HOMOGENIZATION_RGC_ID) chosenHomogenization call mech_RGC_partitionDeformation(& - crystallite_partionedF(1:3,1:3,1:homogenization_Ngrains(material_homogenizationAt(el)),ip,el), & + crystallite_partitionedF(1:3,1:3,1:homogenization_Ngrains(material_homogenizationAt(el)),ip,el), & subF,& ip, & el) @@ -448,8 +448,8 @@ function updateState(subdt,subF,ip,el) updateState = & updateState .and. & mech_RGC_updateState(crystallite_P(1:3,1:3,1:homogenization_Ngrains(material_homogenizationAt(el)),ip,el), & - crystallite_partionedF(1:3,1:3,1:homogenization_Ngrains(material_homogenizationAt(el)),ip,el), & - crystallite_partionedF0(1:3,1:3,1:homogenization_Ngrains(material_homogenizationAt(el)),ip,el),& + crystallite_partitionedF(1:3,1:3,1:homogenization_Ngrains(material_homogenizationAt(el)),ip,el), & + crystallite_partitionedF0(1:3,1:3,1:homogenization_Ngrains(material_homogenizationAt(el)),ip,el),& subF,& subdt, & dPdFs, & diff --git a/src/homogenization_mech_RGC.f90 b/src/homogenization_mech_RGC.f90 index b429e949f..ea5bffd28 100644 --- a/src/homogenization_mech_RGC.f90 +++ b/src/homogenization_mech_RGC.f90 @@ -212,7 +212,7 @@ end subroutine mech_RGC_init !-------------------------------------------------------------------------------------------------- module subroutine mech_RGC_partitionDeformation(F,avgF,instance,of) - real(pReal), dimension (:,:,:), intent(out) :: F !< partioned F per grain + real(pReal), dimension (:,:,:), intent(out) :: F !< partitioned F per grain real(pReal), dimension (3,3), intent(in) :: avgF !< averaged F integer, intent(in) :: & @@ -867,7 +867,7 @@ module procedure mech_RGC_updateState !-------------------------------------------------------------------------------------------------- subroutine grainDeformation(F, avgF, instance, of) - real(pReal), dimension(:,:,:), intent(out) :: F !< partioned F per grain + real(pReal), dimension(:,:,:), intent(out) :: F !< partitioned F per grain real(pReal), dimension(:,:), intent(in) :: avgF !< averaged F integer, intent(in) :: & diff --git a/src/prec.f90 b/src/prec.f90 index cec4928ba..b2866a4f4 100644 --- a/src/prec.f90 +++ b/src/prec.f90 @@ -47,7 +47,7 @@ module prec dotState, & !< rate of state change deltaState !< increment of state change real(pReal), allocatable, dimension(:,:) :: & - partionedState0, & + partitionedState0, & subState0 end type diff --git a/src/rotations.f90 b/src/rotations.f90 index 0b72c1dd5..ea4a8a9d8 100644 --- a/src/rotations.f90 +++ b/src/rotations.f90 @@ -737,13 +737,13 @@ pure function eu2om(eu) result(om) s = sin(eu) om(1,1) = c(1)*c(3)-s(1)*s(3)*c(2) - om(1,2) = s(1)*c(3)+c(1)*s(3)*c(2) - om(1,3) = s(3)*s(2) om(2,1) = -c(1)*s(3)-s(1)*c(3)*c(2) - om(2,2) = -s(1)*s(3)+c(1)*c(3)*c(2) - om(2,3) = c(3)*s(2) om(3,1) = s(1)*s(2) + om(1,2) = s(1)*c(3)+c(1)*s(3)*c(2) + om(2,2) = -s(1)*s(3)+c(1)*c(3)*c(2) om(3,2) = -c(1)*s(2) + om(1,3) = s(3)*s(2) + om(2,3) = c(3)*s(2) om(3,3) = c(2) where(abs(om)<1.0e-12_pReal) om = 0.0_pReal