From 443d79664325874559a6241a5e41fcfede1638f2 Mon Sep 17 00:00:00 2001 From: Sharan Roongta Date: Wed, 9 Nov 2022 22:58:51 +0100 Subject: [PATCH 01/60] phase and homogenization dict to be updated when new material added --- python/damask/_configmaterial.py | 22 ++++++++++++---------- python/tests/test_ConfigMaterial.py | 7 +++++++ 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/python/damask/_configmaterial.py b/python/damask/_configmaterial.py index 7a06a2c69..c02a1e056 100644 --- a/python/damask/_configmaterial.py +++ b/python/damask/_configmaterial.py @@ -209,8 +209,8 @@ class ConfigMaterial(Config): v: 1.0 phase: Steel homogenization: SX - homogenization: {} - phase: {} + homogenization: {SX: {t.b.d}} + phase: {Aluminum: {t.b.d}, Steel: {t.b.d}} >>> cm.from_table(t,O='qu',phase='phase',homogenization='single_crystal') material: @@ -224,8 +224,8 @@ class ConfigMaterial(Config): v: 1.0 phase: Steel homogenization: single_crystal - homogenization: {} - phase: {} + homogenization: {single_crystal: {t.b.d}} + phase: {Aluminum: {t.b.d}, Steel: {t.b.d}} """ kwargs_ = {k:table.get(v) if v in table.labels else np.atleast_2d([v]*len(table)).T for k,v in kwargs.items()} @@ -428,7 +428,6 @@ class ConfigMaterial(Config): -------- Create a dual-phase steel microstructure for micromechanical simulations: - >>> import numpy as np >>> import damask >>> m = damask.ConfigMaterial() >>> m = m.material_add(phase = ['Ferrite','Martensite'], @@ -446,12 +445,11 @@ class ConfigMaterial(Config): v: 1.0 phase: Martensite homogenization: SX - homogenization: {} - phase: {} + homogenization: {SX: {t.b.d}} + phase: {Ferrite: {t.b.d}, Martensite: {t.b.d}} Create a duplex stainless steel microstructure for forming simulations: - >>> import numpy as np >>> import damask >>> m = damask.ConfigMaterial() >>> m = m.material_add(phase = np.array(['Austenite','Ferrite']).reshape(1,2), @@ -476,8 +474,8 @@ class ConfigMaterial(Config): O: [0.6545817158479885, -0.08004812803625233, -0.6226561293931374, 0.4212059104577611] v: 0.8 homogenization: Taylor - homogenization: {} - phase: {} + homogenization: {Taylor: {t.b.d}} + phase: {Austenite: {t.b.d}, Ferrite: {t.b.d}} """ N,n,shaped = 1,1,{} @@ -507,5 +505,9 @@ class ConfigMaterial(Config): dup = self.copy() dup['material'] = dup['material'] + mat if 'material' in dup else mat + for k in np.unique(shaped['phase']): + if k not in dup['phase']: dup['phase'][str(k)] = {'t.b.d'} + for k in np.unique(shaped['homogenization']): + if k not in dup['homogenization']: dup['homogenization'][str(k)] = {'t.b.d'} return dup diff --git a/python/tests/test_ConfigMaterial.py b/python/tests/test_ConfigMaterial.py index f003e254e..60d0bcd50 100644 --- a/python/tests/test_ConfigMaterial.py +++ b/python/tests/test_ConfigMaterial.py @@ -98,6 +98,13 @@ class TestConfigMaterial: for i,m in enumerate(c['material']): assert m['homogenization'] == 1 and (m['constituents'][0]['O'] == [1,0,1,1]).all() + def test_updated_dicts(self,ref_path): + m1 = ConfigMaterial().material_add(phase=['Aluminum'],O=[1.0,0.0,0.0,0.0],homogenization='SX') + m2 = ConfigMaterial.load(ref_path/'material.yaml').material_add(phase=['Aluminum'],O=[1.0,0.0,0.0,0.0],homogenization='SX') + assert m1['phase'] == {'Aluminum': {'t.b.d'}} + assert m1['homogenization'] == {'SX': {'t.b.d'}} + assert not m2['phase']['Aluminum'] == {} + def test_from_table_with_constant(self): N = np.random.randint(3,10) a = np.vstack((np.hstack((np.arange(N),np.arange(N)[::-1])), From 13df12be1bc18e12d817cd743f1c1edbe05a5191 Mon Sep 17 00:00:00 2001 From: Sharan Date: Fri, 11 Nov 2022 01:14:16 +0100 Subject: [PATCH 02/60] initialising dummy arguments with None, making few changes on what is_complete should do --- python/damask/_configmaterial.py | 52 +++++++++---------- .../ConfigMaterial/measured.material.yaml | 2 +- python/tests/test_ConfigMaterial.py | 31 +++++------ 3 files changed, 43 insertions(+), 42 deletions(-) diff --git a/python/damask/_configmaterial.py b/python/damask/_configmaterial.py index c02a1e056..1e77c0b18 100644 --- a/python/damask/_configmaterial.py +++ b/python/damask/_configmaterial.py @@ -160,7 +160,7 @@ class ConfigMaterial(Config): pass - base_config = ConfigMaterial({'phase':{k if isinstance(k,int) else str(k):'t.b.d.' for k in np.unique(phase)}, + base_config = ConfigMaterial({'phase':{k if isinstance(k,int) else str(k): None for k in np.unique(phase)}, 'homogenization':{'direct':{'N_constituents':1}}}) constituent = {k:np.atleast_1d(v[idx].squeeze()) for k,v in zip(['O','phase'],[O,phase])} @@ -209,8 +209,8 @@ class ConfigMaterial(Config): v: 1.0 phase: Steel homogenization: SX - homogenization: {SX: {t.b.d}} - phase: {Aluminum: {t.b.d}, Steel: {t.b.d}} + homogenization: {SX: null} + phase: {Aluminum: null, Steel: null} >>> cm.from_table(t,O='qu',phase='phase',homogenization='single_crystal') material: @@ -224,8 +224,8 @@ class ConfigMaterial(Config): v: 1.0 phase: Steel homogenization: single_crystal - homogenization: {single_crystal: {t.b.d}} - phase: {Aluminum: {t.b.d}, Steel: {t.b.d}} + homogenization: {single_crystal: null} + phase: {Aluminum: null, Steel: null} """ kwargs_ = {k:table.get(v) if v in table.labels else np.atleast_2d([v]*len(table)).T for k,v in kwargs.items()} @@ -282,22 +282,22 @@ class ConfigMaterial(Config): 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}') + if self['phase'] is None: + print('Description of phase dictionary is missing') + ok = False + else: + if phase - set(self['phase']): + print(f'Phase(s) {phase-set(self["phase"])} missing') 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}') + if self['homogenization'] is None: + print('Description of homogenization dictionary is missing') + ok = False + else: + if homogenization - set(self['homogenization']): + print(f'Homogenization(s) {homogenization-set(self["homogenization"])} missing') 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 @@ -320,7 +320,7 @@ class ConfigMaterial(Config): if 'phase' in self: for k,v in self['phase'].items(): - if 'lattice' in v: + if v is not None and 'lattice' in v: try: Orientation(lattice=v['lattice']) except KeyError: @@ -445,8 +445,8 @@ class ConfigMaterial(Config): v: 1.0 phase: Martensite homogenization: SX - homogenization: {SX: {t.b.d}} - phase: {Ferrite: {t.b.d}, Martensite: {t.b.d}} + homogenization: {SX: null} + phase: {Ferrite: null, Martensite: null} Create a duplex stainless steel microstructure for forming simulations: @@ -474,8 +474,8 @@ class ConfigMaterial(Config): O: [0.6545817158479885, -0.08004812803625233, -0.6226561293931374, 0.4212059104577611] v: 0.8 homogenization: Taylor - homogenization: {Taylor: {t.b.d}} - phase: {Austenite: {t.b.d}, Ferrite: {t.b.d}} + homogenization: {Taylor: null} + phase: {Austenite: null, Ferrite: null} """ N,n,shaped = 1,1,{} @@ -505,9 +505,9 @@ class ConfigMaterial(Config): dup = self.copy() dup['material'] = dup['material'] + mat if 'material' in dup else mat - for k in np.unique(shaped['phase']): - if k not in dup['phase']: dup['phase'][str(k)] = {'t.b.d'} - for k in np.unique(shaped['homogenization']): - if k not in dup['homogenization']: dup['homogenization'][str(k)] = {'t.b.d'} + + for what in ['phase','homogenization']: + for k in np.unique(shaped[what]): + if k not in dup[what]: dup[what][str(k)] = None return dup diff --git a/python/tests/reference/ConfigMaterial/measured.material.yaml b/python/tests/reference/ConfigMaterial/measured.material.yaml index bc7e73968..508d03039 100644 --- a/python/tests/reference/ConfigMaterial/measured.material.yaml +++ b/python/tests/reference/ConfigMaterial/measured.material.yaml @@ -1,4 +1,4 @@ -phase: {'1': t.b.d., '2': t.b.d.} +phase: {'1': null, '2': null} homogenization: direct: {N_constituents: 1} diff --git a/python/tests/test_ConfigMaterial.py b/python/tests/test_ConfigMaterial.py index 60d0bcd50..a9cf9089d 100644 --- a/python/tests/test_ConfigMaterial.py +++ b/python/tests/test_ConfigMaterial.py @@ -65,17 +65,6 @@ class TestConfigMaterial: del material_config['material'][0]['homogenization'] assert not material_config.is_complete - def test_incomplete_homogenization_N_constituents(self,ref_path): - material_config = ConfigMaterial.load(ref_path/'material.yaml') - for h in material_config['homogenization'].keys(): - del material_config['homogenization'][h]['N_constituents'] - assert not material_config.is_complete - - def test_incomplete_phase_lattice(self,ref_path): - material_config = ConfigMaterial.load(ref_path/'material.yaml') - del material_config['phase']['Aluminum']['lattice'] - assert not material_config.is_complete - def test_incomplete_wrong_phase(self,ref_path): material_config = ConfigMaterial.load(ref_path/'material.yaml') new = material_config.material_rename_phase({'Steel':'FeNbC'}) @@ -86,6 +75,16 @@ class TestConfigMaterial: new = material_config.material_rename_homogenization({'Taylor':'isostrain'}) assert not new.is_complete + def test_empty_phase(self,ref_path): + material_config = ConfigMaterial.load(ref_path/'material.yaml') + material_config['phase'] = None + assert not material_config.is_complete + + def test_empty_homogenization(self,ref_path): + material_config = ConfigMaterial.load(ref_path/'material.yaml') + material_config['homogenization'] = None + assert not material_config.is_complete + def test_from_table(self): N = np.random.randint(3,10) a = np.vstack((np.hstack((np.arange(N),np.arange(N)[::-1])), @@ -100,10 +99,12 @@ class TestConfigMaterial: def test_updated_dicts(self,ref_path): m1 = ConfigMaterial().material_add(phase=['Aluminum'],O=[1.0,0.0,0.0,0.0],homogenization='SX') - m2 = ConfigMaterial.load(ref_path/'material.yaml').material_add(phase=['Aluminum'],O=[1.0,0.0,0.0,0.0],homogenization='SX') - assert m1['phase'] == {'Aluminum': {'t.b.d'}} - assert m1['homogenization'] == {'SX': {'t.b.d'}} - assert not m2['phase']['Aluminum'] == {} + m2 = ConfigMaterial.load(ref_path/'material.yaml') + for k in m2['phase']: + m2 = m2.material_add(phase=[k],O=[1.0,0.0,0.0,0.0],homogenization='SX') + assert not m2['phase'].get(k) is None + assert m1['phase'].get('Aluminum') is None + assert m1['homogenization'].get('SX') is None def test_from_table_with_constant(self): N = np.random.randint(3,10) From 4fc5ba54df7aea899521c02309291f93f592c7a9 Mon Sep 17 00:00:00 2001 From: Sharan Roongta Date: Fri, 11 Nov 2022 17:38:02 +0100 Subject: [PATCH 03/60] dummy phase dict need to be added for any new material added (similar to dream3D) --- python/damask/_configmaterial.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/python/damask/_configmaterial.py b/python/damask/_configmaterial.py index 1e77c0b18..87fb8be79 100644 --- a/python/damask/_configmaterial.py +++ b/python/damask/_configmaterial.py @@ -193,10 +193,10 @@ class ConfigMaterial(Config): >>> 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 - 1 1 1 0 0.8 0.19 0.24 -0.51 Steel SX + 3:pos pos pos 4: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 + 2 1 1 0 0.8 0.19 0.24 -0.51 Steel SX >>> cm.from_table(t,O='qu',phase='phase',homogenization='homog') material: - constituents: @@ -233,6 +233,8 @@ class ConfigMaterial(Config): _,idx = np.unique(np.hstack(list(kwargs_.values())),return_index=True,axis=0) idx = np.sort(idx) kwargs_ = {k:np.atleast_1d(v[idx].squeeze()) for k,v in kwargs_.items()} + for what in ['phase','homogenization']: + if what not in kwargs_: kwargs_[what]= what+'_label' return ConfigMaterial().material_add(**kwargs_) From 2e7d59ab435b4ac892605fcccb9faf9fbf347cba Mon Sep 17 00:00:00 2001 From: Philip Eisenlohr Date: Fri, 11 Nov 2022 18:07:48 -0500 Subject: [PATCH 04/60] brief but comprehensive "is_complete" reporting --- python/damask/_configmaterial.py | 50 +++++++++++++++++--------------- python/damask/util.py | 14 +++++---- 2 files changed, 35 insertions(+), 29 deletions(-) diff --git a/python/damask/_configmaterial.py b/python/damask/_configmaterial.py index 87fb8be79..4d0df7768 100644 --- a/python/damask/_configmaterial.py +++ b/python/damask/_configmaterial.py @@ -245,7 +245,7 @@ class ConfigMaterial(Config): Check for completeness. Only the general file layout is considered. - This check does not consider whether parameters for + This check does not consider whether specific parameters for a particular phase/homogenization model are missing. Returns @@ -255,51 +255,53 @@ class ConfigMaterial(Config): """ ok = True - for top_level in ['homogenization','phase','material']: - ok &= top_level in self - if top_level not in self: print(f'{top_level} entry missing') + msg = [] + all = set(['homogenization','phase','material']) + miss = set([item for item in all if item not in self]) + empty = set([item for item in all-miss if self[item] is None]) + + if miss: + msg.append(f'Top-level{"s" if len(miss)>1 else ""} {util.srepr(miss,",",quote=True)} missing') + ok = False + if empty: + msg.append(f'Top-level{"s" if len(empty)>1 else ""} {util.srepr(empty,",",quote=True)} empty') if ok: - ok &= len(self['material']) > 0 - if len(self['material']) < 1: print('Incomplete material definition') + ok &= len(self['material']) > 0 + if len(self['material']) < 1: msg.append('No materials defined') - 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}') + msg.append(f'No homogenization specified for 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}') + msg.append(f'No orientation specified for 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}') + msg.append(f'No phase specified for constituent {ii} of material {i}') ok = False - if self['phase'] is None: - print('Description of phase dictionary is missing') - ok = False - else: - if phase - set(self['phase']): - print(f'Phase(s) {phase-set(self["phase"])} missing') - ok = False - - if self['homogenization'] is None: - print('Description of homogenization dictionary is missing') - ok = False - else: - if homogenization - set(self['homogenization']): - print(f'Homogenization(s) {homogenization-set(self["homogenization"])} missing') + for v,other in {'phase':phase, + 'homogenization':homogenization}.items(): + me = set([] if v in empty else self[v]) + if _miss := other - me: + msg.append(f'{v.capitalize()}{"s" if len(_miss)>1 else ""} {util.srepr(_miss,",",quote=True)} missing') + ok = False + _empty = [item for item in me if self[v][item] is None] + if len(_empty) > 0: + msg.append(f'{v.capitalize()}{"s" if len(_empty)>1 else ""} {util.srepr(_empty,",",quote=True)} undefined') ok = False + print(util.srepr(msg)) return ok diff --git a/python/damask/util.py b/python/damask/util.py index ec42dede0..16f0c4c95 100644 --- a/python/damask/util.py +++ b/python/damask/util.py @@ -40,9 +40,10 @@ _colors = { # Functions #################################################################################################### def srepr(msg, - glue: str = '\n') -> str: + glue: str = '\n', + quote: bool = False) -> str: r""" - Join items with glue string. + Join (quoted) items with glue string. Parameters ---------- @@ -50,19 +51,22 @@ def srepr(msg, Items to join. glue : str, optional Glue used for joining operation. Defaults to '\n'. + quote : bool, optional + Quote items. Defaults to False. Returns ------- joined : str - String representation of the joined items. + String representation of the joined and quoted items. """ + q = '"' if quote else '' if (not hasattr(msg, 'strip') and (hasattr(msg, '__getitem__') or hasattr(msg, '__iter__'))): - return glue.join(str(x) for x in msg) + return glue.join(q+str(x)+q for x in msg) else: - return msg if isinstance(msg,str) else repr(msg) + return q+(msg if isinstance(msg,str) else repr(msg))+q def emph(msg) -> str: From ba4ac5c108e841edc4855bafa35bb52a2928d1a3 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Mon, 14 Nov 2022 12:42:13 +0100 Subject: [PATCH 05/60] less repetition --- python/damask/_grid.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/python/damask/_grid.py b/python/damask/_grid.py index feff001f3..db884873b 100644 --- a/python/damask/_grid.py +++ b/python/damask/_grid.py @@ -972,15 +972,16 @@ class Grid: # materials: 1 """ - options = ('nearest',False,None) orig = tuple(map(np.linspace,self.origin + self.size/self.cells*.5, self.origin + self.size - self.size/self.cells*.5,self.cells)) + interpolator = partial(interpolate.RegularGridInterpolator, + points=orig,method='nearest',bounds_error=False,fill_value=None) new = grid_filters.coordinates0_point(cells,self.size,self.origin) - return Grid(material = interpolate.RegularGridInterpolator(orig,self.material,*options)(new).astype(int), + return Grid(material = interpolator(values=self.material)(new).astype(int), size = self.size, origin = self.origin, - initial_conditions = {k: interpolate.RegularGridInterpolator(orig,v,*options)(new) + initial_conditions = {k: interpolator(values=v)(new) for k,v in self.initial_conditions.items()}, comments = self.comments+[util.execution_stamp('Grid','scale')], ) From fa69a1876be364b5a5d5563b9eae46b9c37ba56d Mon Sep 17 00:00:00 2001 From: Philip Eisenlohr Date: Mon, 14 Nov 2022 09:09:45 -0500 Subject: [PATCH 06/60] unify X or list/seq/collection of X --> (A/B/C of) X in docstrings --- python/damask/_colormap.py | 2 +- python/damask/_grid.py | 14 +++++++------- python/damask/_rotation.py | 12 ++++++------ python/damask/_table.py | 6 +++--- python/damask/_vtk.py | 2 +- python/damask/seeds.py | 2 +- python/damask/util.py | 14 +++++++------- 7 files changed, 26 insertions(+), 26 deletions(-) diff --git a/python/damask/_colormap.py b/python/damask/_colormap.py index 688070529..cdcbd8939 100644 --- a/python/damask/_colormap.py +++ b/python/damask/_colormap.py @@ -248,7 +248,7 @@ class Colormap(mpl.colors.ListedColormap): Parameters ---------- - fraction : float or sequence of float + fraction : (sequence of) float Fractional coordinate(s) to evaluate Colormap at. Returns diff --git a/python/damask/_grid.py b/python/damask/_grid.py index feff001f3..ae12ed91a 100644 --- a/python/damask/_grid.py +++ b/python/damask/_grid.py @@ -50,7 +50,7 @@ class Grid: Coordinates of grid origin in meter. Defaults to [0.0,0.0,0.0]. initial_conditions : dictionary, optional Labels and values of the inital conditions at each material point. - comments : str or sequence of str, optional + comments : (sequence of) str, optional Additional, human-readable information, e.g. history of operations. """ @@ -427,7 +427,7 @@ class Grid: coordinates : str Label of the vector column containing the spatial coordinates. Need to be ordered (1./x fast, 3./z slow). - labels : str or sequence of str + labels : (sequence of) str Label(s) of the columns containing the material definition. Each unique combination of values results in one material ID. @@ -1043,9 +1043,9 @@ class Grid: Parameters ---------- - from_material : int or sequence of int + from_material : (sequence of) int Material indices to be substituted. - to_material : int or sequence of int + to_material : (sequence of) int New material indices. Returns @@ -1104,7 +1104,7 @@ class Grid: distance : float, optional Voxel distance checked for presence of other materials. Defaults to sqrt(3). - selection : int or collection of int, optional + selection : (collection of) int, optional Material IDs to consider. Defaults to all. invert_selection : bool, optional Consider all material IDs except those in selection. Defaults to False. @@ -1179,7 +1179,7 @@ class Grid: Center of the primitive. If given as integers, cell centers are addressed. If given as floats, physical coordinates are addressed. - exponent : float or sequence of float, len (3) + exponent : (sequence of) float, len (3) Exponents for the three axes. 0 gives octahedron (ǀxǀ^(2^0) + ǀyǀ^(2^0) + ǀzǀ^(2^0) < 1) 1 gives sphere (ǀxǀ^(2^1) + ǀyǀ^(2^1) + ǀzǀ^(2^1) < 1) @@ -1271,7 +1271,7 @@ class Grid: offset : int, optional Offset (positive or negative) to tag material IDs. Defaults to material.max()+1. - selection : int or collection of int, optional + selection : (collection of) int, optional Material IDs that trigger an offset. Defaults to any other than own material ID. invert_selection : bool, optional diff --git a/python/damask/_rotation.py b/python/damask/_rotation.py index b72cec402..38b9a75f8 100644 --- a/python/damask/_rotation.py +++ b/python/damask/_rotation.py @@ -468,7 +468,7 @@ class Rotation: Parameters ---------- - shape : int or sequence of ints + shape : (sequence of) int New shape, number of elements needs to match the original shape. If an integer is supplied, then the result will be a 1-D array of that length. order : {'C', 'F', 'A'}, optional @@ -496,7 +496,7 @@ class Rotation: Parameters ---------- - shape : int or sequence of ints + shape : (sequence of) int Shape of broadcasted array, needs to be compatible with the original shape. mode : str, optional Where to preferentially locate missing dimensions. @@ -1023,7 +1023,7 @@ class Rotation: Parameters ---------- - shape : int or sequence of ints, optional + shape : (sequence of) int, optional Shape of the returned array. Defaults to None, which gives a scalar. rng_seed : {None, int, array_like[ints], SeedSequence, BitGenerator, Generator}, optional A seed to initialize the BitGenerator. @@ -1059,7 +1059,7 @@ class Rotation: Texture intensity values (probability density or volume fraction) at Euler space grid points. phi : numpy.ndarray, shape (n,3) Grid coordinates in Euler space at which weights are defined. - shape : int or sequence of ints, optional + shape : (sequence of) int, optional Shape of the returned array. Defaults to None, which gives a scalar. degrees : bool, optional Euler space grid coordinates are in degrees. Defaults to True. @@ -1111,7 +1111,7 @@ class Rotation: Central rotation. sigma : float Standard deviation of (Gaussian) misorientation distribution. - shape : int or sequence of ints, optional + shape : (sequence of) int, optional Shape of the returned array. Defaults to None, which gives a scalar. degrees : bool, optional sigma is given in degrees. Defaults to False. @@ -1169,7 +1169,7 @@ class Rotation: sigma : float, optional Standard deviation of (Gaussian) misorientation distribution. Defaults to 0. - shape : int or sequence of ints, optional + shape : (sequence of) int, optional Shape of the returned array. Defaults to None, which gives a scalar. degrees : bool, optional sigma and polar coordinates are given in degrees. Defaults to False. diff --git a/python/damask/_table.py b/python/damask/_table.py index 356e73730..990568364 100644 --- a/python/damask/_table.py +++ b/python/damask/_table.py @@ -25,7 +25,7 @@ class Table: For instance, 'F':(3,3) for a deformation gradient, or 'r':(1,) for a scalar. data : numpy.ndarray or pandas.DataFrame, optional Data. Existing column labels of a pandas.DataFrame will be replaced. - comments : str or iterable of str, optional + comments : (iterable of) str, optional Additional, human-readable information. """ @@ -464,9 +464,9 @@ class Table: Parameters ---------- - label_old : str or iterable of str + label_old : (iterable of) str Old column label(s). - label_new : str or iterable of str + label_new : (iterable of) str New column label(s). Returns diff --git a/python/damask/_vtk.py b/python/damask/_vtk.py index 46d779023..dede9f374 100644 --- a/python/damask/_vtk.py +++ b/python/damask/_vtk.py @@ -110,7 +110,7 @@ class VTK: Parameters ---------- - comments : str or sequence of str + comments : (sequence of) str Comments. """ diff --git a/python/damask/seeds.py b/python/damask/seeds.py index 11be5cc93..89d9bf935 100644 --- a/python/damask/seeds.py +++ b/python/damask/seeds.py @@ -118,7 +118,7 @@ def from_grid(grid, ---------- grid : damask.Grid Grid from which the material IDs are used as seeds. - selection : int or collection of int, optional + selection : (collection of) int, optional Material IDs to consider. invert_selection : bool, optional Consider all material IDs except those in selection. Defaults to False. diff --git a/python/damask/util.py b/python/damask/util.py index ec42dede0..04e448422 100644 --- a/python/damask/util.py +++ b/python/damask/util.py @@ -46,7 +46,7 @@ def srepr(msg, Parameters ---------- - msg : object with __repr__ or sequence of objects with __repr__ + msg : (sequence of) object with __repr__ Items to join. glue : str, optional Glue used for joining operation. Defaults to '\n'. @@ -71,7 +71,7 @@ def emph(msg) -> str: Parameters ---------- - msg : object with __repr__ or sequence of objects with __repr__ + msg : (sequence of) object with __repr__ Message to format. Returns @@ -88,7 +88,7 @@ def deemph(msg) -> str: Parameters ---------- - msg : object with __repr__ or sequence of objects with __repr__ + msg : (sequence of) object with __repr__ Message to format. Returns @@ -105,7 +105,7 @@ def warn(msg) -> str: Parameters ---------- - msg : object with __repr__ or sequence of objects with __repr__ + msg : (sequence of) object with __repr__ Message to format. Returns @@ -122,7 +122,7 @@ def strikeout(msg) -> str: Parameters ---------- - msg : object with __repr__ or iterable of objects with __repr__ + msg : (iterable of) object with __repr__ Message to format. Returns @@ -738,7 +738,7 @@ def tail_repack(extended: _Union[str, _Sequence[str]], Parameters ---------- - extended : str or list of str + extended : (list of) str Extended string list with potentially autosplitted tailing string relative to `existing`. existing : list of str Base string list. @@ -767,7 +767,7 @@ def aslist(arg: _Union[_IntCollection, int, None]) -> _List: Parameters ---------- - arg : int or collection of int or None + arg : (collection of) int or None Entity to transform into list. Returns From 045f1d39a1150b47f0b4fb23f549fc11837862e2 Mon Sep 17 00:00:00 2001 From: Philip Eisenlohr Date: Mon, 14 Nov 2022 14:52:07 -0500 Subject: [PATCH 07/60] add shorthand function for formatting --- python/damask/_configmaterial.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/python/damask/_configmaterial.py b/python/damask/_configmaterial.py index 4d0df7768..6fd671de1 100644 --- a/python/damask/_configmaterial.py +++ b/python/damask/_configmaterial.py @@ -254,6 +254,9 @@ class ConfigMaterial(Config): Whether the material.yaml definition is complete. """ + def LabeledList(label,items): + return f'{label.capitalize()}{"s" if len(items)>1 else ""} {util.srepr(items,",",quote=True)}' + ok = True msg = [] all = set(['homogenization','phase','material']) @@ -261,10 +264,10 @@ class ConfigMaterial(Config): empty = set([item for item in all-miss if self[item] is None]) if miss: - msg.append(f'Top-level{"s" if len(miss)>1 else ""} {util.srepr(miss,",",quote=True)} missing') + msg.append(f'{LabeledList("top-level",miss)} missing') ok = False if empty: - msg.append(f'Top-level{"s" if len(empty)>1 else ""} {util.srepr(empty,",",quote=True)} empty') + msg.append(f'{LabeledList("top-level",empty)} empty') if ok: ok &= len(self['material']) > 0 @@ -294,11 +297,10 @@ class ConfigMaterial(Config): 'homogenization':homogenization}.items(): me = set([] if v in empty else self[v]) if _miss := other - me: - msg.append(f'{v.capitalize()}{"s" if len(_miss)>1 else ""} {util.srepr(_miss,",",quote=True)} missing') + msg.append(f'{LabeledList(v,_miss)} missing') ok = False - _empty = [item for item in me if self[v][item] is None] - if len(_empty) > 0: - msg.append(f'{v.capitalize()}{"s" if len(_empty)>1 else ""} {util.srepr(_empty,",",quote=True)} undefined') + if len(_empty := [item for item in me if self[v][item] is None]) > 0: + msg.append(f'{LabeledList(v,_empty)} undefined') ok = False print(util.srepr(msg)) From 1dbf9ae9bc1a9240d9e83b5854e67a7504be5560 Mon Sep 17 00:00:00 2001 From: Philip Eisenlohr Date: Tue, 15 Nov 2022 11:43:58 -0500 Subject: [PATCH 08/60] increase test coverage to 100% --- python/damask/_rotation.py | 8 ++++---- python/tests/test_Rotation.py | 29 +++++++++++++++++++++++++++-- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/python/damask/_rotation.py b/python/damask/_rotation.py index b72cec402..3ce47d50b 100644 --- a/python/damask/_rotation.py +++ b/python/damask/_rotation.py @@ -773,12 +773,12 @@ class Rotation: raise ValueError('P ∉ {-1,1}') qu[...,1:4] *= -P + if accept_homomorph: qu[qu[...,0] < 0.0] *= -1 - else: - if np.any(qu[...,0] < 0.0): - raise ValueError('quaternion with negative first (real) component') - if not np.all(np.isclose(np.linalg.norm(qu,axis=-1), 1.0,rtol=0.0)): + elif np.any(qu[...,0] < 0.0): + raise ValueError('quaternion with negative first (real) component') + if not np.all(np.isclose(np.linalg.norm(qu,axis=-1), 1.0,rtol=1e-8)): raise ValueError('quaternion is not of unit length') return Rotation(qu) diff --git a/python/tests/test_Rotation.py b/python/tests/test_Rotation.py index 8b1bd0de8..1423e8ce9 100644 --- a/python/tests/test_Rotation.py +++ b/python/tests/test_Rotation.py @@ -708,6 +708,7 @@ class TestRotation: @pytest.mark.parametrize('degrees',[True,False]) def test_axis_angle(self,set_of_rotations,degrees,normalize,P): c = np.array([P*-1,P*-1,P*-1,1.]) + c[:3] *= 0.9 if normalize else 1.0 for rot in set_of_rotations: m = rot.as_Euler_angles() o = Rotation.from_axis_angle(rot.as_axis_angle(degrees)*c,degrees,normalize,P).as_Euler_angles() @@ -730,16 +731,30 @@ class TestRotation: assert ok and np.isclose(np.linalg.norm(o[:3]),1.0) \ and o[3]<=np.pi+1.e-9, f'{m},{o},{rot.as_quaternion()}' + def test_parallel(self,set_of_rotations): + a = np.array([[1.0,0.0,0.0], + [0.0,1.0,0.0]]) + for rot in set_of_rotations: + assert rot.allclose(Rotation.from_parallel(a,rot.broadcast_to((2,))@a)) + @pytest.mark.parametrize('P',[1,-1]) @pytest.mark.parametrize('normalize',[True,False]) def test_Rodrigues(self,set_of_rotations,normalize,P): c = np.array([P*-1,P*-1,P*-1,1.]) + c[:3] *= 0.9 if normalize else 1.0 for rot in set_of_rotations: m = rot.as_matrix() o = Rotation.from_Rodrigues_vector(rot.as_Rodrigues_vector()*c,normalize,P).as_matrix() ok = np.allclose(m,o,atol=atol) assert ok and np.isclose(np.linalg.det(o),1.0), f'{m},{o}' + def test_Rodrigues_compact(self,set_of_rotations): + for rot in set_of_rotations: + c = rot.as_Rodrigues_vector(compact=True) + r = rot.as_Rodrigues_vector(compact=False) + assert np.allclose(r[:3]*r[3], c, equal_nan=True) + + @pytest.mark.parametrize('P',[1,-1]) def test_homochoric(self,set_of_rotations,P): cutoff = np.tan(np.pi*.5*(1.-1e-4)) @@ -760,8 +775,9 @@ class TestRotation: @pytest.mark.parametrize('P',[1,-1]) @pytest.mark.parametrize('accept_homomorph',[True,False]) + # @pytest.mark.parametrize('normalize',[True,False]) def test_quaternion(self,set_of_rotations,P,accept_homomorph): - c = np.array([1,P*-1,P*-1,P*-1]) * (-1 if accept_homomorph else 1) + c = np.array([1,P*-1,P*-1,P*-1]) * (-1 if accept_homomorph else 1) #* (0.9 if normalize else 1.0) for rot in set_of_rotations: m = rot.as_cubochoric() o = Rotation.from_quaternion(rot.as_quaternion()*c,accept_homomorph,P).as_cubochoric() @@ -889,6 +905,15 @@ class TestRotation: with pytest.raises(ValueError): fr(eval(f'R.{to}()'),P=-30) + + def test_invalid_multiplication(self): + rot = Rotation.from_random() + with pytest.raises(TypeError): + rot@Rotation.from_random() + with pytest.raises(TypeError): + rot@[1,2,3,4] + + @pytest.mark.parametrize('shape',[None,(3,),(4,2)]) def test_broadcast(self,shape): rot = Rotation.from_random(shape) @@ -899,7 +924,7 @@ class TestRotation: assert np.allclose(rot_broadcast.quaternion[...,i,:], rot.quaternion) - @pytest.mark.parametrize('function,invalid',[(Rotation.from_quaternion, np.array([-1,0,0,0])), + @pytest.mark.parametrize('function,invalid',[(Rotation.from_quaternion, np.array([-1,0,0,0])), (Rotation.from_quaternion, np.array([1,1,1,0])), (Rotation.from_Euler_angles, np.array([1,4,0])), (Rotation.from_axis_angle, np.array([1,0,0,4])), From 23d2337fb29bc0df81c5dced473135c36e780cec Mon Sep 17 00:00:00 2001 From: Philip Eisenlohr Date: Tue, 15 Nov 2022 16:11:29 -0500 Subject: [PATCH 09/60] add option to normalize quaternions --- python/damask/_rotation.py | 13 +++++++++---- python/tests/test_Rotation.py | 7 ++++--- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/python/damask/_rotation.py b/python/damask/_rotation.py index b72cec402..e87bcf936 100644 --- a/python/damask/_rotation.py +++ b/python/damask/_rotation.py @@ -751,6 +751,7 @@ class Rotation: @staticmethod def from_quaternion(q: Union[Sequence[FloatSequence], np.ndarray], accept_homomorph: bool = False, + normalize: bool = False, P: Literal[1, -1] = -1) -> 'Rotation': """ Initialize from quaternion. @@ -762,6 +763,8 @@ class Rotation: accept_homomorph : bool, optional Allow homomorphic variants, i.e. q_0 < 0 (negative real hemisphere). Defaults to False. + normalize: bool, optional + Allow ǀqǀ ≠ 1. Defaults to False. P : int ∈ {-1,1}, optional Sign convention. Defaults to -1. @@ -773,12 +776,14 @@ class Rotation: raise ValueError('P ∉ {-1,1}') qu[...,1:4] *= -P + if accept_homomorph: qu[qu[...,0] < 0.0] *= -1 - else: - if np.any(qu[...,0] < 0.0): - raise ValueError('quaternion with negative first (real) component') - if not np.all(np.isclose(np.linalg.norm(qu,axis=-1), 1.0,rtol=0.0)): + elif np.any(qu[...,0] < 0.0): + raise ValueError('quaternion with negative first (real) component') + if normalize: + qu /= np.linalg.norm(qu,axis=-1,keepdims=True) + elif not np.all(np.isclose(np.linalg.norm(qu,axis=-1), 1.0,rtol=1e-8)): raise ValueError('quaternion is not of unit length') return Rotation(qu) diff --git a/python/tests/test_Rotation.py b/python/tests/test_Rotation.py index 8b1bd0de8..d39e20f93 100644 --- a/python/tests/test_Rotation.py +++ b/python/tests/test_Rotation.py @@ -760,11 +760,12 @@ class TestRotation: @pytest.mark.parametrize('P',[1,-1]) @pytest.mark.parametrize('accept_homomorph',[True,False]) - def test_quaternion(self,set_of_rotations,P,accept_homomorph): - c = np.array([1,P*-1,P*-1,P*-1]) * (-1 if accept_homomorph else 1) + @pytest.mark.parametrize('normalize',[True,False]) + def test_quaternion(self,set_of_rotations,P,accept_homomorph,normalize): + c = np.array([1,P*-1,P*-1,P*-1]) * (-1 if accept_homomorph else 1) * (0.9 if normalize else 1.0) for rot in set_of_rotations: m = rot.as_cubochoric() - o = Rotation.from_quaternion(rot.as_quaternion()*c,accept_homomorph,P).as_cubochoric() + o = Rotation.from_quaternion(rot.as_quaternion()*c,accept_homomorph,normalize,P).as_cubochoric() ok = np.allclose(m,o,atol=atol) if np.count_nonzero(np.isclose(np.abs(o),np.pi**(2./3.)*.5)): ok |= np.allclose(m*-1.,o,atol=atol) From 740965df7cace85422886bef783fd8774b9e5590 Mon Sep 17 00:00:00 2001 From: Philip Eisenlohr Date: Tue, 15 Nov 2022 17:03:57 -0500 Subject: [PATCH 10/60] cleaner and more efficient determination of ValueErrors --- python/damask/_rotation.py | 23 +++++++++++------------ python/tests/test_Rotation.py | 6 ++++-- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/python/damask/_rotation.py b/python/damask/_rotation.py index b72cec402..fee44736e 100644 --- a/python/damask/_rotation.py +++ b/python/damask/_rotation.py @@ -778,7 +778,7 @@ class Rotation: else: if np.any(qu[...,0] < 0.0): raise ValueError('quaternion with negative first (real) component') - if not np.all(np.isclose(np.linalg.norm(qu,axis=-1), 1.0,rtol=0.0)): + if not np.allclose(np.linalg.norm(qu,axis=-1), 1.0,rtol=0.0): raise ValueError('quaternion is not of unit length') return Rotation(qu) @@ -807,7 +807,7 @@ class Rotation: raise ValueError('invalid shape') eu = np.radians(eu) if degrees else eu - if np.any(eu < 0.0) or np.any(eu > 2.0*np.pi) or np.any(eu[...,1] > np.pi): # ToDo: No separate check for PHI + if np.any(eu < 0.0) or np.any(eu > np.pi*np.array([2,1,2])): raise ValueError('Euler angles outside of [0..2π],[0..π],[0..2π]') return Rotation(Rotation._eu2qu(eu)) @@ -841,11 +841,10 @@ class Rotation: ax[...,0:3] *= -P if degrees: ax[..., 3] = np.radians(ax[...,3]) - if normalize: ax[...,0:3] /= np.linalg.norm(ax[...,0:3],axis=-1,keepdims=True) if np.any(ax[...,3] < 0.0) or np.any(ax[...,3] > np.pi): raise ValueError('axis–angle rotation angle outside of [0..π]') - if not np.all(np.isclose(np.linalg.norm(ax[...,0:3],axis=-1), 1.0)): - print(np.linalg.norm(ax[...,0:3],axis=-1)) + if normalize: ax[...,0:3] /= np.linalg.norm(ax[...,0:3],axis=-1,keepdims=True) + elif not np.allclose(np.linalg.norm(ax[...,0:3],axis=-1), 1.0): raise ValueError('axis–angle rotation axis is not of unit length') return Rotation(Rotation._ax2qu(ax)) @@ -877,12 +876,12 @@ class Rotation: if not orthonormal: (U,S,Vh) = np.linalg.svd(om) # singular value decomposition om = np.einsum('...ij,...jl',U,Vh) - if not np.all(np.isclose(np.linalg.det(om),1.0)): - raise ValueError('orientation matrix has determinant ≠ 1') - if not np.all(np.isclose(np.einsum('...i,...i',om[...,0],om[...,1]), 0.0)) \ - or not np.all(np.isclose(np.einsum('...i,...i',om[...,1],om[...,2]), 0.0)) \ - or not np.all(np.isclose(np.einsum('...i,...i',om[...,2],om[...,0]), 0.0)): + elif not np.allclose(np.einsum('...i,...i',om[...,0],om[...,1]), 0.0) \ + or not np.allclose(np.einsum('...i,...i',om[...,1],om[...,2]), 0.0) \ + or not np.allclose(np.einsum('...i,...i',om[...,2],om[...,0]), 0.0): raise ValueError('orientation matrix is not orthogonal') + if not np.allclose(np.linalg.det(om),1.0): + raise ValueError('orientation matrix has determinant ≠ 1') return Rotation(Rotation._om2qu(om)) @@ -952,10 +951,10 @@ class Rotation: raise ValueError('P ∉ {-1,1}') ro[...,0:3] *= -P - if normalize: ro[...,0:3] /= np.linalg.norm(ro[...,0:3],axis=-1,keepdims=True) if np.any(ro[...,3] < 0.0): raise ValueError('Rodrigues vector rotation angle is negative') - if not np.all(np.isclose(np.linalg.norm(ro[...,0:3],axis=-1), 1.0)): + if normalize: ro[...,0:3] /= np.linalg.norm(ro[...,0:3],axis=-1,keepdims=True) + elif not np.allclose(np.linalg.norm(ro[...,0:3],axis=-1), 1.0): raise ValueError('Rodrigues vector rotation axis is not of unit length') return Rotation(Rotation._ro2qu(ro)) diff --git a/python/tests/test_Rotation.py b/python/tests/test_Rotation.py index 8b1bd0de8..680d4f7c8 100644 --- a/python/tests/test_Rotation.py +++ b/python/tests/test_Rotation.py @@ -899,9 +899,10 @@ class TestRotation: assert np.allclose(rot_broadcast.quaternion[...,i,:], rot.quaternion) - @pytest.mark.parametrize('function,invalid',[(Rotation.from_quaternion, np.array([-1,0,0,0])), + @pytest.mark.parametrize('function,invalid',[(Rotation.from_quaternion, np.array([-1,0,0,0])), (Rotation.from_quaternion, np.array([1,1,1,0])), (Rotation.from_Euler_angles, np.array([1,4,0])), + (Rotation.from_Euler_angles, np.array([-1,0,0])), (Rotation.from_axis_angle, np.array([1,0,0,4])), (Rotation.from_axis_angle, np.array([1,1,0,1])), (Rotation.from_matrix, np.random.rand(3,3)), @@ -909,7 +910,8 @@ class TestRotation: (Rotation.from_Rodrigues_vector, np.array([1,0,0,-1])), (Rotation.from_Rodrigues_vector, np.array([1,1,0,1])), (Rotation.from_homochoric, np.array([2,2,2])), - (Rotation.from_cubochoric, np.array([1.1,0,0])) ]) + (Rotation.from_cubochoric, np.array([1.1,0,0])), + ]) def test_invalid_value(self,function,invalid): with pytest.raises(ValueError): function(invalid) From aedeab7ef8482a57afde5a68c8505465f4e2d525 Mon Sep 17 00:00:00 2001 From: Test User Date: Wed, 16 Nov 2022 11:56:45 +0100 Subject: [PATCH 11/60] [skip ci] updated version information after successful test of v3.0.0-alpha7-91-g584d5b421 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index f72217dce..4f9d37c9e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.0.0-alpha7-86-g72408f389 +3.0.0-alpha7-91-g584d5b421 From 3c76eb3069fe8b16ecf8d1149430b8a41ab46f06 Mon Sep 17 00:00:00 2001 From: Test User Date: Wed, 16 Nov 2022 20:34:42 +0100 Subject: [PATCH 12/60] [skip ci] updated version information after successful test of v3.0.0-alpha7-94-g5d656d9c7 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 4f9d37c9e..ba869259d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.0.0-alpha7-91-g584d5b421 +3.0.0-alpha7-94-g5d656d9c7 From d887f0a9d8b9ad00e244d8bbb163d159891414d5 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 16 Nov 2022 21:13:13 +0100 Subject: [PATCH 13/60] better group if/if-elif cases one line if only when no elif follows to avoid confusion --- python/damask/_rotation.py | 53 +++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 30 deletions(-) diff --git a/python/damask/_rotation.py b/python/damask/_rotation.py index 73d9b0367..3304370fb 100644 --- a/python/damask/_rotation.py +++ b/python/damask/_rotation.py @@ -767,10 +767,8 @@ class Rotation: """ qu = np.array(q,dtype=float) - if qu.shape[:-2:-1] != (4,): - raise ValueError('invalid shape') - if abs(P) != 1: - raise ValueError('P ∉ {-1,1}') + if qu.shape[:-2:-1] != (4,): raise ValueError('invalid shape') + if abs(P) != 1: raise ValueError('P ∉ {-1,1}') qu[...,1:4] *= -P @@ -778,6 +776,7 @@ class Rotation: qu[qu[...,0] < 0.0] *= -1 elif np.any(qu[...,0] < 0.0): raise ValueError('quaternion with negative first (real) component') + if not np.allclose(np.linalg.norm(qu,axis=-1), 1.0,rtol=1e-8): raise ValueError('quaternion is not of unit length') @@ -803,11 +802,10 @@ class Rotation: """ eu = np.array(phi,dtype=float) - if eu.shape[:-2:-1] != (3,): - raise ValueError('invalid shape') + if eu.shape[:-2:-1] != (3,): raise ValueError('invalid shape') eu = np.radians(eu) if degrees else eu - if np.any(eu < 0.0) or np.any(eu > np.pi*np.array([2,1,2])): + if np.any(eu < 0.0) or np.any(eu > np.pi*np.array([2.0,1.0,2.0])): raise ValueError('Euler angles outside of [0..2π],[0..π],[0..2π]') return Rotation(Rotation._eu2qu(eu)) @@ -834,16 +832,16 @@ class Rotation: """ ax = np.array(axis_angle,dtype=float) - if ax.shape[:-2:-1] != (4,): - raise ValueError('invalid shape') - if abs(P) != 1: - raise ValueError('P ∉ {-1,1}') + if ax.shape[:-2:-1] != (4,): raise ValueError('invalid shape') + if abs(P) != 1: raise ValueError('P ∉ {-1,1}') ax[...,0:3] *= -P if degrees: ax[..., 3] = np.radians(ax[...,3]) if np.any(ax[...,3] < 0.0) or np.any(ax[...,3] > np.pi): raise ValueError('axis–angle rotation angle outside of [0..π]') - if normalize: ax[...,0:3] /= np.linalg.norm(ax[...,0:3],axis=-1,keepdims=True) + + if normalize: + ax[...,0:3] /= np.linalg.norm(ax[...,0:3],axis=-1,keepdims=True) elif not np.allclose(np.linalg.norm(ax[...,0:3],axis=-1), 1.0): raise ValueError('axis–angle rotation axis is not of unit length') @@ -867,12 +865,12 @@ class Rotation: """ om = np.array(basis,dtype=float) - if om.shape[-2:] != (3,3): - raise ValueError('invalid shape') + if om.shape[-2:] != (3,3): raise ValueError('invalid shape') if reciprocal: om = np.linalg.inv(tensor.transpose(om)/np.pi) # transform reciprocal basis set orthonormal = False # contains stretch + if not orthonormal: (U,S,Vh) = np.linalg.svd(om) # singular value decomposition om = np.einsum('...ij,...jl',U,Vh) @@ -880,6 +878,7 @@ class Rotation: or not np.allclose(np.einsum('...i,...i',om[...,1],om[...,2]), 0.0) \ or not np.allclose(np.einsum('...i,...i',om[...,2],om[...,0]), 0.0): raise ValueError('orientation matrix is not orthogonal') + if not np.allclose(np.linalg.det(om),1.0): raise ValueError('orientation matrix has determinant ≠ 1') @@ -945,15 +944,14 @@ class Rotation: """ ro = np.array(rho,dtype=float) - if ro.shape[:-2:-1] != (4,): - raise ValueError('invalid shape') - if abs(P) != 1: - raise ValueError('P ∉ {-1,1}') + if ro.shape[:-2:-1] != (4,): raise ValueError('invalid shape') + if abs(P) != 1: raise ValueError('P ∉ {-1,1}') ro[...,0:3] *= -P - if np.any(ro[...,3] < 0.0): - raise ValueError('Rodrigues vector rotation angle is negative') - if normalize: ro[...,0:3] /= np.linalg.norm(ro[...,0:3],axis=-1,keepdims=True) + if np.any(ro[...,3] < 0.0): raise ValueError('Rodrigues vector rotation angle is negative') + + if normalize: + ro[...,0:3] /= np.linalg.norm(ro[...,0:3],axis=-1,keepdims=True) elif not np.allclose(np.linalg.norm(ro[...,0:3],axis=-1), 1.0): raise ValueError('Rodrigues vector rotation axis is not of unit length') @@ -974,10 +972,8 @@ class Rotation: """ ho = np.array(h,dtype=float) - if ho.shape[:-2:-1] != (3,): - raise ValueError('invalid shape') - if abs(P) != 1: - raise ValueError('P ∉ {-1,1}') + if ho.shape[:-2:-1] != (3,): raise ValueError('invalid shape') + if abs(P) != 1: raise ValueError('P ∉ {-1,1}') ho *= -P @@ -1001,11 +997,8 @@ class Rotation: """ cu = np.array(x,dtype=float) - if cu.shape[:-2:-1] != (3,): - raise ValueError('invalid shape') - if abs(P) != 1: - raise ValueError('P ∉ {-1,1}') - + if cu.shape[:-2:-1] != (3,): raise ValueError('invalid shape') + if abs(P) != 1: raise ValueError('P ∉ {-1,1}') if np.abs(np.max(cu)) > np.pi**(2./3.) * 0.5+1e-9: raise ValueError('cubochoric coordinate outside of the cube') From bdd85a414cb29a3c71927c37161e7ceea912b328 Mon Sep 17 00:00:00 2001 From: Franz Roters Date: Thu, 17 Nov 2022 07:12:27 +0000 Subject: [PATCH 14/60] support for MSC.Marc 2022.2 --- .gitlab-ci.yml | 4 +- .../2020/Marc_tools/include_linux64.patch | 2 +- .../2020/Marc_tools/run_damask_hmp.patch | 2 +- .../2020/Marc_tools/run_damask_lmp.patch | 2 +- .../2020/Marc_tools/run_damask_mp.patch | 2 +- .../2020/Mentat_menus/job_run.ms.patch | 2 +- .../2021.2/Marc_tools/include_linux64.patch | 2 +- .../2021.2/Marc_tools/run_damask_hmp.patch | 2 +- .../2021.2/Marc_tools/run_damask_lmp.patch | 2 +- .../2021.2/Marc_tools/run_damask_mp.patch | 2 +- .../2021.2/Mentat_menus/job_run.ms.patch | 2 +- .../2021.3.1/Marc_tools/include_linux64.patch | 2 +- .../2021.3.1/Marc_tools/run_damask_hmp.patch | 2 +- .../2021.3.1/Marc_tools/run_damask_lmp.patch | 2 +- .../2021.3.1/Marc_tools/run_damask_mp.patch | 2 +- .../2021.3.1/Mentat_menus/job_run.ms.patch | 2 +- .../2022.1/Marc_tools/include_linux64.patch | 2 +- .../2022.1/Marc_tools/run_damask_hmp.patch | 2 +- .../2022.1/Marc_tools/run_damask_lmp.patch | 2 +- .../2022.1/Marc_tools/run_damask_mp.patch | 2 +- .../2022.1/Mentat_menus/job_run.ms.patch | 2 +- .../2022.2/Marc_tools/comp_damask_hmp.patch | 49 ++ .../2022.2/Marc_tools/comp_damask_lmp.patch | 49 ++ .../2022.2/Marc_tools/comp_damask_mp.patch | 49 ++ .../2022.2/Marc_tools/include_linux64.patch | 75 +++ .../2022.2/Marc_tools/run_damask_hmp.patch | 517 ++++++++++++++++++ .../2022.2/Marc_tools/run_damask_lmp.patch | 517 ++++++++++++++++++ .../2022.2/Marc_tools/run_damask_mp.patch | 517 ++++++++++++++++++ .../2022.2/Mentat_bin/edit_window.patch | 24 + .../MarcMentat/2022.2/Mentat_bin/kill4.patch | 0 .../MarcMentat/2022.2/Mentat_bin/kill5.patch | 0 .../MarcMentat/2022.2/Mentat_bin/kill6.patch | 0 .../2022.2/Mentat_bin/submit4.patch | 38 ++ .../2022.2/Mentat_bin/submit5.patch | 38 ++ .../2022.2/Mentat_bin/submit6.patch | 38 ++ .../2022.2/Mentat_menus/job_run.ms.patch | 158 ++++++ ..._modifications.py => MSC_modifications.py} | 61 ++- install/MarcMentat/installation.txt | 15 +- python/damask/solver/_marc.py | 2 +- src/Marc/DAMASK_Marc.f90 | 2 + src/Marc/include/concom2022.2 | 466 ++++++++++++++++ src/Marc/include/creeps2022.2 | 73 +++ 42 files changed, 2686 insertions(+), 46 deletions(-) create mode 100644 install/MarcMentat/2022.2/Marc_tools/comp_damask_hmp.patch create mode 100644 install/MarcMentat/2022.2/Marc_tools/comp_damask_lmp.patch create mode 100644 install/MarcMentat/2022.2/Marc_tools/comp_damask_mp.patch create mode 100644 install/MarcMentat/2022.2/Marc_tools/include_linux64.patch create mode 100644 install/MarcMentat/2022.2/Marc_tools/run_damask_hmp.patch create mode 100644 install/MarcMentat/2022.2/Marc_tools/run_damask_lmp.patch create mode 100644 install/MarcMentat/2022.2/Marc_tools/run_damask_mp.patch create mode 100644 install/MarcMentat/2022.2/Mentat_bin/edit_window.patch create mode 100644 install/MarcMentat/2022.2/Mentat_bin/kill4.patch create mode 100644 install/MarcMentat/2022.2/Mentat_bin/kill5.patch create mode 100644 install/MarcMentat/2022.2/Mentat_bin/kill6.patch create mode 100644 install/MarcMentat/2022.2/Mentat_bin/submit4.patch create mode 100644 install/MarcMentat/2022.2/Mentat_bin/submit5.patch create mode 100644 install/MarcMentat/2022.2/Mentat_bin/submit6.patch create mode 100644 install/MarcMentat/2022.2/Mentat_menus/job_run.ms.patch rename install/MarcMentat/{apply_DAMASK_modifications.py => MSC_modifications.py} (50%) create mode 100644 src/Marc/include/concom2022.2 create mode 100644 src/Marc/include/creeps2022.2 diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2fa92038f..2dd33b072 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -47,9 +47,9 @@ variables: PETSC_INTELLLVM: "Libraries/PETSc/3.16.3/oneAPI-2022.0.1-IntelMPI-2021.5.0" PETSC_INTEL: "Libraries/PETSc/3.16.5/Intel-2022.0.1-IntelMPI-2021.5.0" # ++++++++++++ MSC Marc +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - MSC: "FEM/MSC/2022.1" + MSC: "FEM/MSC/2022.2" IntelMarc: "Compiler/Intel/19.1.2 Libraries/IMKL/2020" - HDF5Marc: "HDF5/1.12.1/Intel-19.1.2" + HDF5Marc: "HDF5/1.12.2/Intel-19.1.2" ################################################################################################### diff --git a/install/MarcMentat/2020/Marc_tools/include_linux64.patch b/install/MarcMentat/2020/Marc_tools/include_linux64.patch index 043b887f0..193a308f2 100644 --- a/install/MarcMentat/2020/Marc_tools/include_linux64.patch +++ b/install/MarcMentat/2020/Marc_tools/include_linux64.patch @@ -46,7 +46,7 @@ + +# determine DAMASK version +if test -n "$DAMASK_USER"; then -+ DAMASKROOT=`dirname $DAMASK_USER`/.. ++ DAMASKROOT=`dirname $DAMASK_USER`/../.. + read DAMASKVERSION < $DAMASKROOT/VERSION + DAMASKVERSION="'"$DAMASKVERSION"'" +else diff --git a/install/MarcMentat/2020/Marc_tools/run_damask_hmp.patch b/install/MarcMentat/2020/Marc_tools/run_damask_hmp.patch index 0d1be0c8a..f5224265f 100644 --- a/install/MarcMentat/2020/Marc_tools/run_damask_hmp.patch +++ b/install/MarcMentat/2020/Marc_tools/run_damask_hmp.patch @@ -251,7 +251,7 @@ - usersub=$usersubname - fi - -+ userobj=$usermoext.o ++ userobj=$usernoext.o fi cat > $jid.runmarcscript << END4 if test "$user" diff --git a/install/MarcMentat/2020/Marc_tools/run_damask_lmp.patch b/install/MarcMentat/2020/Marc_tools/run_damask_lmp.patch index 0960673de..6e1aa8f01 100644 --- a/install/MarcMentat/2020/Marc_tools/run_damask_lmp.patch +++ b/install/MarcMentat/2020/Marc_tools/run_damask_lmp.patch @@ -251,7 +251,7 @@ - usersub=$usersubname - fi - -+ userobj=$usermoext.o ++ userobj=$usernoext.o fi cat > $jid.runmarcscript << END4 if test "$user" diff --git a/install/MarcMentat/2020/Marc_tools/run_damask_mp.patch b/install/MarcMentat/2020/Marc_tools/run_damask_mp.patch index f8ef8bfb0..12eb57510 100644 --- a/install/MarcMentat/2020/Marc_tools/run_damask_mp.patch +++ b/install/MarcMentat/2020/Marc_tools/run_damask_mp.patch @@ -251,7 +251,7 @@ - usersub=$usersubname - fi - -+ userobj=$usermoext.o ++ userobj=$usernoext.o fi cat > $jid.runmarcscript << END4 if test "$user" diff --git a/install/MarcMentat/2020/Mentat_menus/job_run.ms.patch b/install/MarcMentat/2020/Mentat_menus/job_run.ms.patch index e011e93e3..7c0942335 100644 --- a/install/MarcMentat/2020/Mentat_menus/job_run.ms.patch +++ b/install/MarcMentat/2020/Mentat_menus/job_run.ms.patch @@ -66,7 +66,7 @@ + label { + position -32 +6 + size 12 6 -+ text "O2 / OpenMP" ++ text "O3 / OpenMP" + border_width 1 + border_color black + } diff --git a/install/MarcMentat/2021.2/Marc_tools/include_linux64.patch b/install/MarcMentat/2021.2/Marc_tools/include_linux64.patch index e8dede2ea..a8cb9248a 100644 --- a/install/MarcMentat/2021.2/Marc_tools/include_linux64.patch +++ b/install/MarcMentat/2021.2/Marc_tools/include_linux64.patch @@ -46,7 +46,7 @@ + +# determine DAMASK version +if test -n "$DAMASK_USER"; then -+ DAMASKROOT=`dirname $DAMASK_USER`/.. ++ DAMASKROOT=`dirname $DAMASK_USER`/../.. + read DAMASKVERSION < $DAMASKROOT/VERSION + DAMASKVERSION="'"$DAMASKVERSION"'" +else diff --git a/install/MarcMentat/2021.2/Marc_tools/run_damask_hmp.patch b/install/MarcMentat/2021.2/Marc_tools/run_damask_hmp.patch index 8842a1fda..cd1d7547c 100644 --- a/install/MarcMentat/2021.2/Marc_tools/run_damask_hmp.patch +++ b/install/MarcMentat/2021.2/Marc_tools/run_damask_hmp.patch @@ -284,7 +284,7 @@ - usersub=$usersubname - fi - -+ userobj=$usermoext.o ++ userobj=$usernoext.o fi cat > $jid.runmarcscript << END4 if test "$user" diff --git a/install/MarcMentat/2021.2/Marc_tools/run_damask_lmp.patch b/install/MarcMentat/2021.2/Marc_tools/run_damask_lmp.patch index 02642e7b4..84839e7be 100644 --- a/install/MarcMentat/2021.2/Marc_tools/run_damask_lmp.patch +++ b/install/MarcMentat/2021.2/Marc_tools/run_damask_lmp.patch @@ -284,7 +284,7 @@ - usersub=$usersubname - fi - -+ userobj=$usermoext.o ++ userobj=$usernoext.o fi cat > $jid.runmarcscript << END4 if test "$user" diff --git a/install/MarcMentat/2021.2/Marc_tools/run_damask_mp.patch b/install/MarcMentat/2021.2/Marc_tools/run_damask_mp.patch index c22bcb5c7..e1c40b632 100644 --- a/install/MarcMentat/2021.2/Marc_tools/run_damask_mp.patch +++ b/install/MarcMentat/2021.2/Marc_tools/run_damask_mp.patch @@ -284,7 +284,7 @@ - usersub=$usersubname - fi - -+ userobj=$usermoext.o ++ userobj=$usernoext.o fi cat > $jid.runmarcscript << END4 if test "$user" diff --git a/install/MarcMentat/2021.2/Mentat_menus/job_run.ms.patch b/install/MarcMentat/2021.2/Mentat_menus/job_run.ms.patch index 55f64ecf5..b2bcc08ec 100644 --- a/install/MarcMentat/2021.2/Mentat_menus/job_run.ms.patch +++ b/install/MarcMentat/2021.2/Mentat_menus/job_run.ms.patch @@ -65,7 +65,7 @@ + label { + position -32 +6 + size 12 6 -+ text "O2 / OpenMP" ++ text "O3 / OpenMP" + border_width 1 + border_color black + } diff --git a/install/MarcMentat/2021.3.1/Marc_tools/include_linux64.patch b/install/MarcMentat/2021.3.1/Marc_tools/include_linux64.patch index a90c60aa6..9087d75a3 100644 --- a/install/MarcMentat/2021.3.1/Marc_tools/include_linux64.patch +++ b/install/MarcMentat/2021.3.1/Marc_tools/include_linux64.patch @@ -50,7 +50,7 @@ +# determine DAMASK version +if test -n "$DAMASK_USER"; then -+ DAMASKROOT=`dirname $DAMASK_USER`/.. ++ DAMASKROOT=`dirname $DAMASK_USER`/../.. + read DAMASKVERSION < $DAMASKROOT/VERSION + DAMASKVERSION="'"$DAMASKVERSION"'" +else diff --git a/install/MarcMentat/2021.3.1/Marc_tools/run_damask_hmp.patch b/install/MarcMentat/2021.3.1/Marc_tools/run_damask_hmp.patch index bdec42401..f670c1b71 100644 --- a/install/MarcMentat/2021.3.1/Marc_tools/run_damask_hmp.patch +++ b/install/MarcMentat/2021.3.1/Marc_tools/run_damask_hmp.patch @@ -283,7 +283,7 @@ - usersub=$usersubname - fi - -+ userobj=$usermoext.o ++ userobj=$usernoext.o fi cat > $jid.runmarcscript << END4 if test "$user" diff --git a/install/MarcMentat/2021.3.1/Marc_tools/run_damask_lmp.patch b/install/MarcMentat/2021.3.1/Marc_tools/run_damask_lmp.patch index 3872981dd..3f71a6f87 100644 --- a/install/MarcMentat/2021.3.1/Marc_tools/run_damask_lmp.patch +++ b/install/MarcMentat/2021.3.1/Marc_tools/run_damask_lmp.patch @@ -283,7 +283,7 @@ - usersub=$usersubname - fi - -+ userobj=$usermoext.o ++ userobj=$usernoext.o fi cat > $jid.runmarcscript << END4 if test "$user" diff --git a/install/MarcMentat/2021.3.1/Marc_tools/run_damask_mp.patch b/install/MarcMentat/2021.3.1/Marc_tools/run_damask_mp.patch index 00f8d6e8c..bdece2b7e 100644 --- a/install/MarcMentat/2021.3.1/Marc_tools/run_damask_mp.patch +++ b/install/MarcMentat/2021.3.1/Marc_tools/run_damask_mp.patch @@ -301,7 +301,7 @@ - usersub=$usersubname - fi - -+ userobj=$usermoext.o ++ userobj=$usernoext.o fi cat > $jid.runmarcscript << END4 if test "$user" diff --git a/install/MarcMentat/2021.3.1/Mentat_menus/job_run.ms.patch b/install/MarcMentat/2021.3.1/Mentat_menus/job_run.ms.patch index 6299ca83b..fa25218ca 100644 --- a/install/MarcMentat/2021.3.1/Mentat_menus/job_run.ms.patch +++ b/install/MarcMentat/2021.3.1/Mentat_menus/job_run.ms.patch @@ -67,7 +67,7 @@ + label { + position -32 +6 + size 12 6 -+ text "O2 / OpenMP" ++ text "O3 / OpenMP" + border_width 1 + border_color black + } diff --git a/install/MarcMentat/2022.1/Marc_tools/include_linux64.patch b/install/MarcMentat/2022.1/Marc_tools/include_linux64.patch index 18c92edd5..c0d5aa10e 100644 --- a/install/MarcMentat/2022.1/Marc_tools/include_linux64.patch +++ b/install/MarcMentat/2022.1/Marc_tools/include_linux64.patch @@ -40,7 +40,7 @@ +# determine DAMASK version +if test -n "$DAMASK_USER"; then -+ DAMASKROOT=`dirname $DAMASK_USER`/.. ++ DAMASKROOT=`dirname $DAMASK_USER`/../.. + read DAMASKVERSION < $DAMASKROOT/VERSION + DAMASKVERSION="'"$DAMASKVERSION"'" +else diff --git a/install/MarcMentat/2022.1/Marc_tools/run_damask_hmp.patch b/install/MarcMentat/2022.1/Marc_tools/run_damask_hmp.patch index cdeeecf4b..4a1356876 100644 --- a/install/MarcMentat/2022.1/Marc_tools/run_damask_hmp.patch +++ b/install/MarcMentat/2022.1/Marc_tools/run_damask_hmp.patch @@ -228,7 +228,7 @@ - usersub=$usersubname - fi - -+ userobj=$usermoext.o ++ userobj=$usernoext.o fi cat > $jid.runmarcscript << END4 if test "$user" diff --git a/install/MarcMentat/2022.1/Marc_tools/run_damask_lmp.patch b/install/MarcMentat/2022.1/Marc_tools/run_damask_lmp.patch index 21ed967f6..86265457b 100644 --- a/install/MarcMentat/2022.1/Marc_tools/run_damask_lmp.patch +++ b/install/MarcMentat/2022.1/Marc_tools/run_damask_lmp.patch @@ -228,7 +228,7 @@ - usersub=$usersubname - fi - -+ userobj=$usermoext.o ++ userobj=$usernoext.o fi cat > $jid.runmarcscript << END4 if test "$user" diff --git a/install/MarcMentat/2022.1/Marc_tools/run_damask_mp.patch b/install/MarcMentat/2022.1/Marc_tools/run_damask_mp.patch index cdeeecf4b..4a1356876 100644 --- a/install/MarcMentat/2022.1/Marc_tools/run_damask_mp.patch +++ b/install/MarcMentat/2022.1/Marc_tools/run_damask_mp.patch @@ -228,7 +228,7 @@ - usersub=$usersubname - fi - -+ userobj=$usermoext.o ++ userobj=$usernoext.o fi cat > $jid.runmarcscript << END4 if test "$user" diff --git a/install/MarcMentat/2022.1/Mentat_menus/job_run.ms.patch b/install/MarcMentat/2022.1/Mentat_menus/job_run.ms.patch index 9ff6b8ae0..979f8856a 100644 --- a/install/MarcMentat/2022.1/Mentat_menus/job_run.ms.patch +++ b/install/MarcMentat/2022.1/Mentat_menus/job_run.ms.patch @@ -67,7 +67,7 @@ + label { + position -32 +6 + size 12 6 -+ text "O2 / OpenMP" ++ text "O3 / OpenMP" + border_width 1 + border_color black + } diff --git a/install/MarcMentat/2022.2/Marc_tools/comp_damask_hmp.patch b/install/MarcMentat/2022.2/Marc_tools/comp_damask_hmp.patch new file mode 100644 index 000000000..886ebf008 --- /dev/null +++ b/install/MarcMentat/2022.2/Marc_tools/comp_damask_hmp.patch @@ -0,0 +1,49 @@ +--- ++++ +@@ -6,18 +6,27 @@ + DIR=$1 + user=$3 + program=$4 ++usernoext=$user ++usernoext=`dirname $usernoext`/`$BASENAME $usernoext .f` ++usernoext=`dirname $usernoext`/`$BASENAME $usernoext .F` ++usernoext=`dirname $usernoext`/`$BASENAME $usernoext .for` ++usernoext=`dirname $usernoext`/`$BASENAME $usernoext .f90` ++ ++# add BLAS options for linking ++ BLAS="%BLAS%" ++ + . $DIR/tools/include + DIRJOB=$2 + cd $DIRJOB +-echo "Compiling and linking user subroutine $user.f on host `hostname`" ++echo "Compiling and linking user subroutine $user on host `hostname`" + echo "program: $program" +- $FORTRAN $user.f || \ ++ $DFORTHIGHMP $user || \ + { +- echo "$0: compile failed for $user.f" ++ echo "$0: compile failed for $user" + exit 1 + } + /bin/rm $program 2>/dev/null +- userobj=$user.o ++ userobj=$usernoext.o + + + $LOAD ${program} $DIR/lib/main.o\ +@@ -33,9 +42,13 @@ + $TKLIBS \ + $MRCLIBS \ + $METISLIBS \ ++ $BLAS \ + $SYSLIBS || \ + { +- echo "$0: link failed for $user.o on host `hostname`" ++ echo "$0: link failed for $usernoext.o on host `hostname`" + exit 1 + } + /bin/rm $userobj ++ /bin/rm $DIRJOB/*.mod ++ /bin/rm $DIRJOB/*.smod ++ /bin/rm $DIRJOB/*_genmod.f90 diff --git a/install/MarcMentat/2022.2/Marc_tools/comp_damask_lmp.patch b/install/MarcMentat/2022.2/Marc_tools/comp_damask_lmp.patch new file mode 100644 index 000000000..191cb1a53 --- /dev/null +++ b/install/MarcMentat/2022.2/Marc_tools/comp_damask_lmp.patch @@ -0,0 +1,49 @@ +--- ++++ +@@ -6,18 +6,27 @@ + DIR=$1 + user=$3 + program=$4 ++usernoext=$user ++usernoext=`dirname $usernoext`/`$BASENAME $usernoext .f` ++usernoext=`dirname $usernoext`/`$BASENAME $usernoext .F` ++usernoext=`dirname $usernoext`/`$BASENAME $usernoext .for` ++usernoext=`dirname $usernoext`/`$BASENAME $usernoext .f90` ++ ++# add BLAS options for linking ++ BLAS="%BLAS%" ++ + . $DIR/tools/include + DIRJOB=$2 + cd $DIRJOB +-echo "Compiling and linking user subroutine $user.f on host `hostname`" ++echo "Compiling and linking user subroutine $user on host `hostname`" + echo "program: $program" +- $FORTRAN $user.f || \ ++ $DFORTRANLOWMP $user || \ + { +- echo "$0: compile failed for $user.f" ++ echo "$0: compile failed for $user" + exit 1 + } + /bin/rm $program 2>/dev/null +- userobj=$user.o ++ userobj=$usernoext.o + + + $LOAD ${program} $DIR/lib/main.o\ +@@ -33,9 +42,13 @@ + $TKLIBS \ + $MRCLIBS \ + $METISLIBS \ ++ $BLAS \ + $SYSLIBS || \ + { +- echo "$0: link failed for $user.o on host `hostname`" ++ echo "$0: link failed for $usernoext.o on host `hostname`" + exit 1 + } + /bin/rm $userobj ++ /bin/rm $DIRJOB/*.mod ++ /bin/rm $DIRJOB/*.smod ++ /bin/rm $DIRJOB/*_genmod.f90 diff --git a/install/MarcMentat/2022.2/Marc_tools/comp_damask_mp.patch b/install/MarcMentat/2022.2/Marc_tools/comp_damask_mp.patch new file mode 100644 index 000000000..7c9cf7ba7 --- /dev/null +++ b/install/MarcMentat/2022.2/Marc_tools/comp_damask_mp.patch @@ -0,0 +1,49 @@ +--- ++++ +@@ -6,18 +6,27 @@ + DIR=$1 + user=$3 + program=$4 ++usernoext=$user ++usernoext=`dirname $usernoext`/`$BASENAME $usernoext .f` ++usernoext=`dirname $usernoext`/`$BASENAME $usernoext .F` ++usernoext=`dirname $usernoext`/`$BASENAME $usernoext .for` ++usernoext=`dirname $usernoext`/`$BASENAME $usernoext .f90` ++ ++# add BLAS options for linking ++ BLAS="%BLAS%" ++ + . $DIR/tools/include + DIRJOB=$2 + cd $DIRJOB +-echo "Compiling and linking user subroutine $user.f on host `hostname`" ++echo "Compiling and linking user subroutine $user on host `hostname`" + echo "program: $program" +- $FORTRAN $user.f || \ ++ $DFORTRANMP $user || \ + { +- echo "$0: compile failed for $user.f" ++ echo "$0: compile failed for $user" + exit 1 + } + /bin/rm $program 2>/dev/null +- userobj=$user.o ++ userobj=$usernoext.o + + + $LOAD ${program} $DIR/lib/main.o\ +@@ -33,9 +42,13 @@ + $TKLIBS \ + $MRCLIBS \ + $METISLIBS \ ++ $BLAS \ + $SYSLIBS || \ + { +- echo "$0: link failed for $user.o on host `hostname`" ++ echo "$0: link failed for $usernoext.o on host `hostname`" + exit 1 + } + /bin/rm $userobj ++ /bin/rm $DIRJOB/*.mod ++ /bin/rm $DIRJOB/*.smod ++ /bin/rm $DIRJOB/*_genmod.f90 diff --git a/install/MarcMentat/2022.2/Marc_tools/include_linux64.patch b/install/MarcMentat/2022.2/Marc_tools/include_linux64.patch new file mode 100644 index 000000000..8a758c795 --- /dev/null +++ b/install/MarcMentat/2022.2/Marc_tools/include_linux64.patch @@ -0,0 +1,75 @@ +--- ++++ +@@ -166,6 +166,15 @@ + MARC_COSIM_LIB="$MSCCOSIM_HOME/CoSim$MSCCOSIM_VERSION/Dcosim$MSCCOSIM_VERSION/lib" + fi + ++# DAMASK uses the HDF5 compiler wrapper around the Intel compiler ++H5FC=$(h5fc -shlib -show) ++if [[ "$H5FC" == *"$dir is"* ]]; then ++ H5FC=$(echo $(echo "$H5FC" | tail -n1) | sed -e "s/\-shlib/-fPIC -qopenmp/g") ++ H5FC=${H5FC%-lmpifort*} ++fi ++HDF5_LIB=${H5FC//*ifort/} ++FCOMP="$H5FC" ++ + # AEM + if test "$MARCDLLOUTDIR" = ""; then + DLLOUTDIR="$MARC_LIB" +@@ -594,7 +603,7 @@ + PROFILE=" $PROFILE -pg" + fi + +-FORT_OPT="-c -assume byterecl -safe_cray_ptr -mp1 -WB -fp-model source" ++FORT_OPT="-c -implicitnone -stand f18 -standard-semantics -assume nostd_mod_proc_name -safe_cray_ptr -mp1 -WB -fp-model source" + if test "$MTHREAD" = "OPENMP" + then + FORT_OPT=" $FORT_OPT -qopenmp" +@@ -607,7 +616,7 @@ + FORT_OPT=" $FORT_OPT -save -zero" + fi + if test "$MARCHDF_HDF" = "HDF"; then +- FORT_OPT="$FORT_OPT -DMARCHDF_HDF=$MARCHDF_HDF $HDF_INCLUDE" ++ FORT_OPT="$FORT_OPT -DMARCHDF=$MARCHDF_HDF" + fi + + FORTLOW="$FCOMP $FORT_OPT $PROFILE -O0 $I8FFLAGS -I$MARC_SOURCE/common \ +@@ -621,6 +630,29 @@ + # for compiling free form f90 files. high opt, integer(4) + FORTF90="$FCOMP -c -O3" + ++# determine DAMASK version ++if test -n "$DAMASK_USER"; then ++ DAMASKROOT=`dirname $DAMASK_USER`/../.. ++ read DAMASKVERSION < $DAMASKROOT/VERSION ++ DAMASKVERSION="'"$DAMASKVERSION"'" ++else ++ DAMASKVERSION="'N/A'" ++fi ++ ++# DAMASK compiler calls ++DFORTLOWMP="$FCOMP -c -O0 -qno-offload -implicitnone -stand f18 -standard-semantics -assume nostd_mod_proc_name -safe_cray_ptr $PROFILE -zero -mp1 -WB $I8FFLAGS -I$MARC_SOURCE/common \ ++ -fpp -ftz -diag-disable 5268 -warn declarations -warn general -warn usage -warn interfaces -warn ignore_loc -warn alignments -DMARC4DAMASK=2022.1 -DDAMASKVERSION=$DAMASKVERSION \ ++ -qopenmp -qopenmp-threadprivate=compat\ ++ $MUMPS_INCLUDE $I8DEFINES -DLinux -DLINUX -DLinux_intel $FDEFINES $DDM $SOLVERFLAGS -I$KDTREE2_MOD -I$MARC_MOD" ++DFORTRANMP="$FCOMP -c -O1 -qno-offload -implicitnone -stand f18 -standard-semantics -assume nostd_mod_proc_name -safe_cray_ptr $PROFILE -zero -mp1 -WB $I8FFLAGS -I$MARC_SOURCE/common \ ++ -fpp -ftz -diag-disable 5268 -warn declarations -warn general -warn usage -warn interfaces -warn ignore_loc -warn alignments -DMARC4DAMASK=2022.1 -DDAMASKVERSION=$DAMASKVERSION \ ++ -qopenmp -qopenmp-threadprivate=compat\ ++ $MUMPS_INCLUDE $I8DEFINES -DLinux -DLINUX -DLinux_intel $FDEFINES $DDM $SOLVERFLAGS -I$KDTREE2_MOD -I$MARC_MOD" ++DFORTHIGHMP="$FCOMP -c -O3 -qno-offload -implicitnone -stand f18 -standard-semantics -assume nostd_mod_proc_name -safe_cray_ptr $PROFILE -zero -mp1 -WB $I8FFLAGS -I$MARC_SOURCE/common \ ++ -fpp -ftz -diag-disable 5268 -warn declarations -warn general -warn usage -warn interfaces -warn ignore_loc -warn alignments -DMARC4DAMASK=2022.1 -DDAMASKVERSION=$DAMASKVERSION \ ++ -qopenmp -qopenmp-threadprivate=compat\ ++ $MUMPS_INCLUDE $I8DEFINES -DLinux -DLINUX -DLinux_intel $FDEFINES $DDM $SOLVERFLAGS -I$KDTREE2_MOD -I$MARC_MOD" ++ + if test "$MARCDEBUG" = "ON" + then + FORTLOW="$FCOMP $FORT_OPT $PROFILE $I8FFLAGS -I$MARC_SOURCE/common \ +@@ -778,7 +810,7 @@ + + SOLVERLIBS="${BCSSOLVERLIBS} ${VKISOLVERLIBS} ${CASISOLVERLIBS} ${MF2SOLVERLIBS} \ + -L$MARC_MKL \ +- $MARC_LIB/blas_src.a ${ACSI_LIB}/ACSI_MarcLib.a $KDTREE2_LIB/libkdtree2.a $MARC_LIB/libtetmeshinterface.a $MARC_LIB/libcaefatigueinterface.a -L$MARC_LIB -lmkl_blacs_intelmpi_ilp64 -lmkl_scalapack_ilp64 -lmkl_intel_ilp64 -lmkl_intel_thread -lmkl_core -liomp5 -ltetmesh -lmeshgems -lmg-tetra -lmeshgems_stubs $HDF_LIBS $SOLVER2LIBS" ++ $MARC_LIB/blas_src.a ${ACSI_LIB}/ACSI_MarcLib.a $KDTREE2_LIB/libkdtree2.a $MARC_LIB/libtetmeshinterface.a $MARC_LIB/libcaefatigueinterface.a -L$MARC_LIB -lmkl_blacs_intelmpi_ilp64 -lmkl_scalapack_ilp64 -lmkl_intel_ilp64 -lmkl_intel_thread -lmkl_core -liomp5 -ltetmesh -lmeshgems -lmg-tetra -lmeshgems_stubs $HDF5_LIB $SOLVER2LIBS" + + SOLVERLIBS_DLL=${SOLVERLIBS} + if test "$AEM_DLL" -eq 1 diff --git a/install/MarcMentat/2022.2/Marc_tools/run_damask_hmp.patch b/install/MarcMentat/2022.2/Marc_tools/run_damask_hmp.patch new file mode 100644 index 000000000..a63591c4b --- /dev/null +++ b/install/MarcMentat/2022.2/Marc_tools/run_damask_hmp.patch @@ -0,0 +1,517 @@ +--- ++++ +@@ -136,6 +136,11 @@ + # is created. For job running in the background, the log # + # file is always created. Default is "yes" # + ############################################################################## ++# remove all Mentat paths from LD_LIBRARY_PATH ++LD_LIBRARY_PATH=:$LD_LIBRARY_PATH: ++LD_LIBRARY_PATH=${LD_LIBRARY_PATH//+([!(:)])mentat2022.2+([!(:)])/:} ++LD_LIBRARY_PATH=${LD_LIBRARY_PATH//+([(:)])/:} ++LD_LIBRARY_PATH=${LD_LIBRARY_PATH#:}; LD_LIBRARY_PATH=${LD_LIBRARY_PATH%:} + # set DIR to the directory in which this script is + REALCOM="`/bin/ls -l $0 |awk '{ print $NF; }'`" + DIR=`dirname $REALCOM` +@@ -302,7 +307,23 @@ + + . "$DIR/getarch" + ++ ++# getting user subroutine file name ++found=0 ++for i in "$@"; do ++ if test $found = 1; then ++ DAMASK_USER=$i ++ found=0 ++ fi ++ case $i in ++ -u* | -U*) ++ found=1 ++ ;; ++ esac ++done ++# sourcing include_linux64 (needs DAMASK_USER to be set) + . $MARC_INCLUDE ++ + # + + # +@@ -405,7 +426,7 @@ + did= + vid= + user= +-usersubname= ++usernoext= + objs= + qid=background + cpu= +@@ -676,50 +697,19 @@ + esac + ;; + -u* | -U*) +- user=`dirname $value`/`$BASENAME $value .f` +- usersubname=$user +- basefile=`$BASENAME $value` +- if test ${basefile##*.} = f +- then +- user=`dirname $value`/`$BASENAME $value .f` +- usersubname=$user.f +- elif test ${basefile##*.} = F +- then +- user=`dirname $value`/`$BASENAME $value .F` +- usersubname=$user.F +- elif test ${basefile##*.} = f90 +- then +- user=`dirname $value`/`$BASENAME $value .f90` +- usersubname=$user.f90 +- elif test ${basefile##*.} = F90 +- then +- user=`dirname $value`/`$BASENAME $value .F90` +- usersubname=$user.F90 +- fi ++ user=$value + case $user in + \/*) + ;; + *) + user=`pwd`/$user +- usersubname=`pwd`/$usersubname + ;; + esac +- if test ! -f $usersubname +- then +- if test -f $usersubname.f +- then +- usersubname=$usersubname.f +- elif test -f $usersubname.F +- then +- usersubname=$usersubname.F +- elif test -f $usersubname.f90 +- then +- usersubname=$usersubname.f90 +- elif test -f $usersubname.F90 +- then +- usersubname=$usersubname.F90 +- fi +- fi ++ usernoext=$user ++ usernoext=`dirname $usernoext`/`$BASENAME $usernoext .f` ++ usernoext=`dirname $usernoext`/`$BASENAME $usernoext .F` ++ usernoext=`dirname $usernoext`/`$BASENAME $usernoext .for` ++ usernoext=`dirname $usernoext`/`$BASENAME $usernoext .f90` + ;; + -obj | -OBJ) + objs="$value" +@@ -1207,12 +1197,12 @@ + fi + fi + fi +- if test "$usersubname" ++ if test "$user" + then +- if test ! -f $usersubname ++ if test ! -f $user + then + error="$error +-user subroutine file $usersubname not accessible" ++user subroutine file $user not accessible" + fi + fi + if test "$objs" +@@ -1531,7 +1521,7 @@ + Marc shared lib : $progdll + Version type : $mode + Job ID : $DIRJID/$jid$extra_job_info +-User subroutine name : $usersubname ++User subroutine name : $user + User objects/libs : $objs + Restart file job ID : $rid + Substructure file ID : $sid +@@ -1564,7 +1554,7 @@ + Marc shared lib : $progdll + Version type : $mode + Job ID : $DIRJID/$jid$extra_job_info +-User subroutine name : $usersubname ++User subroutine name : $user + User objects/libs : $objs + Restart file job ID : $rid + Substructure file ID : $sid +@@ -1687,7 +1677,7 @@ + ;; + esac + fi +- $ECHO "User subroutine name ($usersubname)? $ECHOTXT" ++ $ECHO "User subroutine name ($user)? $ECHOTXT" + read value + if test "$value" + then +@@ -1696,50 +1686,19 @@ + user= + ;; + *) +- user=`dirname $value`/`$BASENAME $value .f` +- usersubname=$user +- basefile=`$BASENAME $value` +- if test ${basefile##*.} = f +- then +- user=`dirname $value`/`$BASENAME $value .f` +- usersubname=$user.f +- elif test ${basefile##*.} = F +- then +- user=`dirname $value`/`$BASENAME $value .F` +- usersubname=$user.F +- elif test ${basefile##*.} = f90 +- then +- user=`dirname $value`/`$BASENAME $value .f90` +- usersubname=$user.f90 +- elif test ${basefile##*.} = F90 +- then +- user=`dirname $value`/`$BASENAME $value .F90` +- usersubname=$user.F90 +- fi ++ user=$value + case $user in + \/*) + ;; + *) + user=`pwd`/$user +- usersubname=`pwd`/$usersubname + ;; + esac +- if test ! -f $usersubname +- then +- if test -f $usersubname.f +- then +- usersubname=$usersubname.f +- elif test -f $usersubname.F +- then +- usersubname=$usersubname.F +- elif test -f $usersubname.f90 +- then +- usersubname=$usersubname.f90 +- elif test -f $usersubname.F90 +- then +- usersubname=$usersubname.F90 +- fi +- fi ++ usernoext=$user ++ usernoext=`dirname $usernoext`/`$BASENAME $usernoext .f` ++ usernoext=`dirname $usernoext`/`$BASENAME $usernoext .F` ++ usernoext=`dirname $usernoext`/`$BASENAME $usernoext .for` ++ usernoext=`dirname $usernoext`/`$BASENAME $usernoext .f90` + ;; + esac + fi +@@ -2274,11 +2233,12 @@ + # + # user subroutine used + # ++# add DAMASK options for linking ++ DAMASK="-lstdc++" + + if test "$user" + then +-# program=$user.marc +- program=$DIRJOB/`$BASENAME $user .f`.marc ++ program=$usernoext.marc + case $program in + \/* | \.\/*) + bd= +@@ -2391,7 +2351,7 @@ + fi + if test "$user" + then +- execpath=$DIRJOB/`$BASENAME $user .f`.marc ++ execpath=$usernoext.marc + usersub=1 + fi + export execpath +@@ -3274,44 +3234,27 @@ + echo + if test "$user" + then +- userobj=$DIRJOB/`$BASENAME $user .f`.o +- basefile=`$BASENAME $usersubname` +- if test ${basefile##*.} = f +- then +- usersub=$DIRJOB/`$BASENAME $user .f`.F +- ln -sf "$user.f" "$usersub" +- else +- usersub=$usersubname +- fi +- ++ userobj=$usernoext.o + fi + cat > $jid.runmarcscript << END4 + if test "$user" + then +- if test ${basefile##*.} = f +- then +- ln -sf "$user.f" "$usersub" +- fi + if test $MACHINENAME = "CRAY" + then +- $FORTRAN $usersub || \ ++ $DFORTHIGHMP $user || \ + { +- echo "$0: compile failed for $user.f" ++ echo "$0: compile failed for $user" + exit 1 + } + /bin/rm $program 2>/dev/null + else +- $FORTRAN $usersub -o $userobj || \ ++ $DFORTHIGHMP $user -o $userobj || \ + { +- echo "$0: compile failed for $user.f" ++ echo "$0: compile failed for $user" + exit 1 + } + /bin/rm $program 2>/dev/null + fi +- if test ${basefile##*.} = f +- then +- /bin/rm -f "$usersub" +- fi + fi + + +@@ -3331,6 +3274,7 @@ + $TKLIBS \ + $MRCLIBS \ + $METISLIBS \ ++ $DAMASK \ + $SFLIB \ + $OPENSSL_LIB \ + $SYSLIBS \ +@@ -3344,6 +3288,9 @@ + prgsav=yes + fi + /bin/rm $userobj 2>/dev/null ++/bin/rm $DIRJOB/*.mod 2>/dev/null ++/bin/rm $DIRJOB/*.smod 2>/dev/null ++/bin/rm $DIRJOB/*_genmod.f90 2>/dev/null + + # + # run marc +@@ -3390,7 +3337,7 @@ + fi + else + if test $cpdll = yes; then +- filename=`basename $usersubname .f` ++ filename=$usernoext + /bin/cp $DIRJOB/$marcdll $DIRJOB/${filename}_$marcdll 2>/dev/null + fi + if test $rmdll = yes +@@ -3556,7 +3503,7 @@ + # first copy over the user sub if local directories + if test ${dirstatus[$counter]} = "local" + then +- $RCP $user.f $i:$DIR1/ ++ $RCP $user $i:$DIR1/ + fi + # do the compilation on the other machine + if test ${dirstatus[$counter]} = "shared" +@@ -3569,21 +3516,21 @@ + remoteuser=$DIR1/`$BASENAME $user` + $RSH $i /bin/rm $remoteprog 2> /dev/null + echo +- $RSH $i $DIR2/tools/comp_user $DIR2 $DIR1 $remoteuser $remoteprog ++ $RSH $i $DIR2/tools/comp_damask_hmp $DIR2 $DIR1 $remoteuser $remoteprog + # check if successful, the new executable should be there + line=`$RSH $i /bin/ls $remoteprog 2> /dev/null` + if test "$line" + then + echo compilation and linking successful on host $i + else +- echo "$0: compile failed for $user.f on host $i" ++ echo "$0: compile failed for $user on host $i" + echo " $PRODUCT Exit number 3" + exit 1 + fi + # remove the user subroutine on remote machine + if test ${dirstatus[$counter]} = "local" + then +- $RSH $i /bin/rm $remoteuser.f 2> /dev/null ++ $RSH $i /bin/rm $remoteuser 2> /dev/null + fi + fi + fi +@@ -3593,39 +3540,27 @@ + if test "$userhost" + then + echo +- echo "Compiling and linking user subroutine $user.f on host `hostname`" +- fi +- userobj=$DIRJOB/`$BASENAME $user .f`.o +- basefile=`$BASENAME $usersubname` +- if test ${basefile##*.} = f +- then +- usersub=$DIRJOB/`$BASENAME $user .f`.F +- ln -sf "$user.f" "$usersub" +- else +- usersub=$usersubname ++ echo "Compiling and linking user subroutine $user on host `hostname`" + fi ++ userobj=$usernoext.o + if test $MACHINENAME = "CRAY" + then +- $FORTRAN $usersub || \ ++ $DFORTHIGHMP $user || \ + { +- echo "$0: compile failed for $user.f" ++ echo "$0: compile failed for $user" + echo " $PRODUCT Exit number 3" + exit 1 + } + /bin/rm $program 2>/dev/null + else +- $FORTRAN $usersub -o $userobj || \ ++ $DFORTHIGHMP $user -o $userobj || \ + { +- echo "$0: compile failed for $user.f" ++ echo "$0: compile failed for $user" + echo " $PRODUCT Exit number 3" + exit 1 + } + /bin/rm $program 2>/dev/null + fi +- if test ${basefile##*.} = f +- then +- /bin/rm -f "$usersub" +- fi + fi # if test $user + + +@@ -3645,6 +3580,7 @@ + $TKLIBS \ + $MRCLIBS \ + $METISLIBS \ ++ $DAMASK \ + $SFLIB \ + $OPENSSL_LIB \ + $SYSLIBS \ +@@ -3686,6 +3622,9 @@ + prgsav=yes + fi # if test $link + /bin/rm $userobj 2>/dev/null ++/bin/rm $DIRJOB/*.mod 2>/dev/null ++/bin/rm $DIRJOB/*.smod 2>/dev/null ++/bin/rm $DIRJOB/*_genmod.f90 2>/dev/null + + # + # run marc +@@ -3779,7 +3718,7 @@ + else + #dllrun >0 + if test $cpdll = yes; then +- filename=`basename $usersubname .f` ++ filename=$usernoext + /bin/cp $DIRJOB/$marcdll $DIRJOB/${filename}_$marcdll 2>/dev/null + fi + if test $rmdll = yes;then +@@ -3904,7 +3843,7 @@ + # first copy over the user sub if local directories + if test ${dirstatus[$counter]} = "local" + then +- $RCP $user.f $i:$DIR1/ ++ $RCP $user $i:$DIR1/ + fi + # do the compilation on the other machine + if test ${dirstatus[$counter]} = "shared" +@@ -3917,20 +3856,20 @@ + remoteuser=$DIR1/`$BASENAME $user` + $RSH $i /bin/rm $remoteprog 2> /dev/null + echo +- $RSH $i $DIR2/tools/comp_user $DIR2 $DIR1 $remoteuser $remoteprog ++ $RSH $i $DIR2/tools/comp_damask_hmp $DIR2 $DIR1 $remoteuser $remoteprog + # check if successful, the new executable should be there + line=`$RSH $i /bin/ls $remoteprog 2> /dev/null` + if test "$line" + then + echo compilation and linking successful on host $i + else +- echo "$0: compile failed for $user.f on host $i" ++ echo "$0: compile failed for $user on host $i" + exit 1 + fi + # remove the user subroutine on remote machine + if test ${dirstatus[$counter]} = "local" + then +- $RSH $i /bin/rm $remoteuser.f 2> /dev/null ++ $RSH $i /bin/rm $remoteuser 2> /dev/null + fi + fi + fi +@@ -3940,37 +3879,25 @@ + if test "$userhost" + then + echo +- echo "Compiling and linking user subroutine $user.f on host `hostname`" +- fi +- userobj=$DIRJOB/`$BASENAME $user .f`.o +- basefile=`$BASENAME $usersubname` +- if test ${basefile##*.} = f +- then +- usersub=$DIRJOB/`$BASENAME $user .f`.F +- ln -sf "$user.f" "$usersub" +- else +- usersub=$usersubname ++ echo "Compiling and linking user subroutine $user on host `hostname`" + fi ++ userobj=$usernoext.o + if test $MACHINENAME = "CRAY" + then +- $FORTRAN $usersub || \ ++ $DFORTHIGHMP $user || \ + { +- echo "$0: compile failed for $user.f" ++ echo "$0: compile failed for $user" + exit 1 + } + /bin/rm $program 2>/dev/null + else +- $FORTRAN $usersub -o $userobj || \ ++ $DFORTHIGHMP $user -o $userobj || \ + { +- echo "$0: compile failed for $user.f" ++ echo "$0: compile failed for $user" + exit 1 + } + /bin/rm $program 2>/dev/null + fi +- if test ${basefile##*.} = f +- then +- /bin/rm -f "$usersub" +- fi + fi # if test $user + + +@@ -3990,6 +3917,7 @@ + $TKLIBS \ + $MRCLIBS \ + $METISLIBS \ ++ $DAMASK \ + $SFLIB \ + $OPENSSL_LIB \ + $SYSLIBS \ +@@ -4030,7 +3958,9 @@ + prgsav=yes + fi # if test $link + /bin/rm $userobj 2>/dev/null +- ++/bin/rm $DIRJOB/*.mod 2>/dev/null ++/bin/rm $DIRJOB/*.smod 2>/dev/null ++/bin/rm $DIRJOB/*_genmod.f90 2>/dev/null + # done if no job id given + if test -z "$jid" + then +@@ -4149,7 +4079,7 @@ + else + #dllrun >0 + if test $cpdll = yes; then +- filename=`basename $usersubname .f` ++ filename=$usernoext + /bin/cp $DIRJOB/$marcdll $DIRJOB/${filename}_$marcdll 2>/dev/null + fi + if test $rmdll = yes;then diff --git a/install/MarcMentat/2022.2/Marc_tools/run_damask_lmp.patch b/install/MarcMentat/2022.2/Marc_tools/run_damask_lmp.patch new file mode 100644 index 000000000..4371ece0c --- /dev/null +++ b/install/MarcMentat/2022.2/Marc_tools/run_damask_lmp.patch @@ -0,0 +1,517 @@ +--- ++++ +@@ -136,6 +136,11 @@ + # is created. For job running in the background, the log # + # file is always created. Default is "yes" # + ############################################################################## ++# remove all Mentat paths from LD_LIBRARY_PATH ++LD_LIBRARY_PATH=:$LD_LIBRARY_PATH: ++LD_LIBRARY_PATH=${LD_LIBRARY_PATH//+([!(:)])mentat2022.2+([!(:)])/:} ++LD_LIBRARY_PATH=${LD_LIBRARY_PATH//+([(:)])/:} ++LD_LIBRARY_PATH=${LD_LIBRARY_PATH#:}; LD_LIBRARY_PATH=${LD_LIBRARY_PATH%:} + # set DIR to the directory in which this script is + REALCOM="`/bin/ls -l $0 |awk '{ print $NF; }'`" + DIR=`dirname $REALCOM` +@@ -302,7 +307,23 @@ + + . "$DIR/getarch" + ++ ++# getting user subroutine file name ++found=0 ++for i in "$@"; do ++ if test $found = 1; then ++ DAMASK_USER=$i ++ found=0 ++ fi ++ case $i in ++ -u* | -U*) ++ found=1 ++ ;; ++ esac ++done ++# sourcing include_linux64 (needs DAMASK_USER to be set) + . $MARC_INCLUDE ++ + # + + # +@@ -405,7 +426,7 @@ + did= + vid= + user= +-usersubname= ++usernoext= + objs= + qid=background + cpu= +@@ -676,50 +697,19 @@ + esac + ;; + -u* | -U*) +- user=`dirname $value`/`$BASENAME $value .f` +- usersubname=$user +- basefile=`$BASENAME $value` +- if test ${basefile##*.} = f +- then +- user=`dirname $value`/`$BASENAME $value .f` +- usersubname=$user.f +- elif test ${basefile##*.} = F +- then +- user=`dirname $value`/`$BASENAME $value .F` +- usersubname=$user.F +- elif test ${basefile##*.} = f90 +- then +- user=`dirname $value`/`$BASENAME $value .f90` +- usersubname=$user.f90 +- elif test ${basefile##*.} = F90 +- then +- user=`dirname $value`/`$BASENAME $value .F90` +- usersubname=$user.F90 +- fi ++ user=$value + case $user in + \/*) + ;; + *) + user=`pwd`/$user +- usersubname=`pwd`/$usersubname + ;; + esac +- if test ! -f $usersubname +- then +- if test -f $usersubname.f +- then +- usersubname=$usersubname.f +- elif test -f $usersubname.F +- then +- usersubname=$usersubname.F +- elif test -f $usersubname.f90 +- then +- usersubname=$usersubname.f90 +- elif test -f $usersubname.F90 +- then +- usersubname=$usersubname.F90 +- fi +- fi ++ usernoext=$user ++ usernoext=`dirname $usernoext`/`$BASENAME $usernoext .f` ++ usernoext=`dirname $usernoext`/`$BASENAME $usernoext .F` ++ usernoext=`dirname $usernoext`/`$BASENAME $usernoext .for` ++ usernoext=`dirname $usernoext`/`$BASENAME $usernoext .f90` + ;; + -obj | -OBJ) + objs="$value" +@@ -1207,12 +1197,12 @@ + fi + fi + fi +- if test "$usersubname" ++ if test "$user" + then +- if test ! -f $usersubname ++ if test ! -f $user + then + error="$error +-user subroutine file $usersubname not accessible" ++user subroutine file $user not accessible" + fi + fi + if test "$objs" +@@ -1531,7 +1521,7 @@ + Marc shared lib : $progdll + Version type : $mode + Job ID : $DIRJID/$jid$extra_job_info +-User subroutine name : $usersubname ++User subroutine name : $user + User objects/libs : $objs + Restart file job ID : $rid + Substructure file ID : $sid +@@ -1564,7 +1554,7 @@ + Marc shared lib : $progdll + Version type : $mode + Job ID : $DIRJID/$jid$extra_job_info +-User subroutine name : $usersubname ++User subroutine name : $user + User objects/libs : $objs + Restart file job ID : $rid + Substructure file ID : $sid +@@ -1687,7 +1677,7 @@ + ;; + esac + fi +- $ECHO "User subroutine name ($usersubname)? $ECHOTXT" ++ $ECHO "User subroutine name ($user)? $ECHOTXT" + read value + if test "$value" + then +@@ -1696,50 +1686,19 @@ + user= + ;; + *) +- user=`dirname $value`/`$BASENAME $value .f` +- usersubname=$user +- basefile=`$BASENAME $value` +- if test ${basefile##*.} = f +- then +- user=`dirname $value`/`$BASENAME $value .f` +- usersubname=$user.f +- elif test ${basefile##*.} = F +- then +- user=`dirname $value`/`$BASENAME $value .F` +- usersubname=$user.F +- elif test ${basefile##*.} = f90 +- then +- user=`dirname $value`/`$BASENAME $value .f90` +- usersubname=$user.f90 +- elif test ${basefile##*.} = F90 +- then +- user=`dirname $value`/`$BASENAME $value .F90` +- usersubname=$user.F90 +- fi ++ user=$value + case $user in + \/*) + ;; + *) + user=`pwd`/$user +- usersubname=`pwd`/$usersubname + ;; + esac +- if test ! -f $usersubname +- then +- if test -f $usersubname.f +- then +- usersubname=$usersubname.f +- elif test -f $usersubname.F +- then +- usersubname=$usersubname.F +- elif test -f $usersubname.f90 +- then +- usersubname=$usersubname.f90 +- elif test -f $usersubname.F90 +- then +- usersubname=$usersubname.F90 +- fi +- fi ++ usernoext=$user ++ usernoext=`dirname $usernoext`/`$BASENAME $usernoext .f` ++ usernoext=`dirname $usernoext`/`$BASENAME $usernoext .F` ++ usernoext=`dirname $usernoext`/`$BASENAME $usernoext .for` ++ usernoext=`dirname $usernoext`/`$BASENAME $usernoext .f90` + ;; + esac + fi +@@ -2274,11 +2233,12 @@ + # + # user subroutine used + # ++# add DAMASK options for linking ++ DAMASK="-lstdc++" + + if test "$user" + then +-# program=$user.marc +- program=$DIRJOB/`$BASENAME $user .f`.marc ++ program=$usernoext.marc + case $program in + \/* | \.\/*) + bd= +@@ -2391,7 +2351,7 @@ + fi + if test "$user" + then +- execpath=$DIRJOB/`$BASENAME $user .f`.marc ++ execpath=$usernoext.marc + usersub=1 + fi + export execpath +@@ -3274,44 +3234,27 @@ + echo + if test "$user" + then +- userobj=$DIRJOB/`$BASENAME $user .f`.o +- basefile=`$BASENAME $usersubname` +- if test ${basefile##*.} = f +- then +- usersub=$DIRJOB/`$BASENAME $user .f`.F +- ln -sf "$user.f" "$usersub" +- else +- usersub=$usersubname +- fi +- ++ userobj=$usernoext.o + fi + cat > $jid.runmarcscript << END4 + if test "$user" + then +- if test ${basefile##*.} = f +- then +- ln -sf "$user.f" "$usersub" +- fi + if test $MACHINENAME = "CRAY" + then +- $FORTRAN $usersub || \ ++ $DFORTLOWMP $user || \ + { +- echo "$0: compile failed for $user.f" ++ echo "$0: compile failed for $user" + exit 1 + } + /bin/rm $program 2>/dev/null + else +- $FORTRAN $usersub -o $userobj || \ ++ $DFORTLOWMP $user -o $userobj || \ + { +- echo "$0: compile failed for $user.f" ++ echo "$0: compile failed for $user" + exit 1 + } + /bin/rm $program 2>/dev/null + fi +- if test ${basefile##*.} = f +- then +- /bin/rm -f "$usersub" +- fi + fi + + +@@ -3331,6 +3274,7 @@ + $TKLIBS \ + $MRCLIBS \ + $METISLIBS \ ++ $DAMASK \ + $SFLIB \ + $OPENSSL_LIB \ + $SYSLIBS \ +@@ -3344,6 +3288,9 @@ + prgsav=yes + fi + /bin/rm $userobj 2>/dev/null ++/bin/rm $DIRJOB/*.mod 2>/dev/null ++/bin/rm $DIRJOB/*.smod 2>/dev/null ++/bin/rm $DIRJOB/*_genmod.f90 2>/dev/null + + # + # run marc +@@ -3390,7 +3337,7 @@ + fi + else + if test $cpdll = yes; then +- filename=`basename $usersubname .f` ++ filename=$usernoext + /bin/cp $DIRJOB/$marcdll $DIRJOB/${filename}_$marcdll 2>/dev/null + fi + if test $rmdll = yes +@@ -3556,7 +3503,7 @@ + # first copy over the user sub if local directories + if test ${dirstatus[$counter]} = "local" + then +- $RCP $user.f $i:$DIR1/ ++ $RCP $user $i:$DIR1/ + fi + # do the compilation on the other machine + if test ${dirstatus[$counter]} = "shared" +@@ -3569,21 +3516,21 @@ + remoteuser=$DIR1/`$BASENAME $user` + $RSH $i /bin/rm $remoteprog 2> /dev/null + echo +- $RSH $i $DIR2/tools/comp_user $DIR2 $DIR1 $remoteuser $remoteprog ++ $RSH $i $DIR2/tools/comp_damask_lmp $DIR2 $DIR1 $remoteuser $remoteprog + # check if successful, the new executable should be there + line=`$RSH $i /bin/ls $remoteprog 2> /dev/null` + if test "$line" + then + echo compilation and linking successful on host $i + else +- echo "$0: compile failed for $user.f on host $i" ++ echo "$0: compile failed for $user on host $i" + echo " $PRODUCT Exit number 3" + exit 1 + fi + # remove the user subroutine on remote machine + if test ${dirstatus[$counter]} = "local" + then +- $RSH $i /bin/rm $remoteuser.f 2> /dev/null ++ $RSH $i /bin/rm $remoteuser 2> /dev/null + fi + fi + fi +@@ -3593,39 +3540,27 @@ + if test "$userhost" + then + echo +- echo "Compiling and linking user subroutine $user.f on host `hostname`" +- fi +- userobj=$DIRJOB/`$BASENAME $user .f`.o +- basefile=`$BASENAME $usersubname` +- if test ${basefile##*.} = f +- then +- usersub=$DIRJOB/`$BASENAME $user .f`.F +- ln -sf "$user.f" "$usersub" +- else +- usersub=$usersubname ++ echo "Compiling and linking user subroutine $user on host `hostname`" + fi ++ userobj=$usernoext.o + if test $MACHINENAME = "CRAY" + then +- $FORTRAN $usersub || \ ++ $DFORTLOWMP $user || \ + { +- echo "$0: compile failed for $user.f" ++ echo "$0: compile failed for $user" + echo " $PRODUCT Exit number 3" + exit 1 + } + /bin/rm $program 2>/dev/null + else +- $FORTRAN $usersub -o $userobj || \ ++ $DFORTLOWMP $user -o $userobj || \ + { +- echo "$0: compile failed for $user.f" ++ echo "$0: compile failed for $user" + echo " $PRODUCT Exit number 3" + exit 1 + } + /bin/rm $program 2>/dev/null + fi +- if test ${basefile##*.} = f +- then +- /bin/rm -f "$usersub" +- fi + fi # if test $user + + +@@ -3645,6 +3580,7 @@ + $TKLIBS \ + $MRCLIBS \ + $METISLIBS \ ++ $DAMASK \ + $SFLIB \ + $OPENSSL_LIB \ + $SYSLIBS \ +@@ -3686,6 +3622,9 @@ + prgsav=yes + fi # if test $link + /bin/rm $userobj 2>/dev/null ++/bin/rm $DIRJOB/*.mod 2>/dev/null ++/bin/rm $DIRJOB/*.smod 2>/dev/null ++/bin/rm $DIRJOB/*_genmod.f90 2>/dev/null + + # + # run marc +@@ -3779,7 +3718,7 @@ + else + #dllrun >0 + if test $cpdll = yes; then +- filename=`basename $usersubname .f` ++ filename=$usernoext + /bin/cp $DIRJOB/$marcdll $DIRJOB/${filename}_$marcdll 2>/dev/null + fi + if test $rmdll = yes;then +@@ -3904,7 +3843,7 @@ + # first copy over the user sub if local directories + if test ${dirstatus[$counter]} = "local" + then +- $RCP $user.f $i:$DIR1/ ++ $RCP $user $i:$DIR1/ + fi + # do the compilation on the other machine + if test ${dirstatus[$counter]} = "shared" +@@ -3917,20 +3856,20 @@ + remoteuser=$DIR1/`$BASENAME $user` + $RSH $i /bin/rm $remoteprog 2> /dev/null + echo +- $RSH $i $DIR2/tools/comp_user $DIR2 $DIR1 $remoteuser $remoteprog ++ $RSH $i $DIR2/tools/comp_damask_lmp $DIR2 $DIR1 $remoteuser $remoteprog + # check if successful, the new executable should be there + line=`$RSH $i /bin/ls $remoteprog 2> /dev/null` + if test "$line" + then + echo compilation and linking successful on host $i + else +- echo "$0: compile failed for $user.f on host $i" ++ echo "$0: compile failed for $user on host $i" + exit 1 + fi + # remove the user subroutine on remote machine + if test ${dirstatus[$counter]} = "local" + then +- $RSH $i /bin/rm $remoteuser.f 2> /dev/null ++ $RSH $i /bin/rm $remoteuser 2> /dev/null + fi + fi + fi +@@ -3940,37 +3879,25 @@ + if test "$userhost" + then + echo +- echo "Compiling and linking user subroutine $user.f on host `hostname`" +- fi +- userobj=$DIRJOB/`$BASENAME $user .f`.o +- basefile=`$BASENAME $usersubname` +- if test ${basefile##*.} = f +- then +- usersub=$DIRJOB/`$BASENAME $user .f`.F +- ln -sf "$user.f" "$usersub" +- else +- usersub=$usersubname ++ echo "Compiling and linking user subroutine $user on host `hostname`" + fi ++ userobj=$usernoext.o + if test $MACHINENAME = "CRAY" + then +- $FORTRAN $usersub || \ ++ $DFORTLOWMP $user || \ + { +- echo "$0: compile failed for $user.f" ++ echo "$0: compile failed for $user" + exit 1 + } + /bin/rm $program 2>/dev/null + else +- $FORTRAN $usersub -o $userobj || \ ++ $DFORTLOWMP $user -o $userobj || \ + { +- echo "$0: compile failed for $user.f" ++ echo "$0: compile failed for $user" + exit 1 + } + /bin/rm $program 2>/dev/null + fi +- if test ${basefile##*.} = f +- then +- /bin/rm -f "$usersub" +- fi + fi # if test $user + + +@@ -3990,6 +3917,7 @@ + $TKLIBS \ + $MRCLIBS \ + $METISLIBS \ ++ $DAMASK \ + $SFLIB \ + $OPENSSL_LIB \ + $SYSLIBS \ +@@ -4030,7 +3958,9 @@ + prgsav=yes + fi # if test $link + /bin/rm $userobj 2>/dev/null +- ++/bin/rm $DIRJOB/*.mod 2>/dev/null ++/bin/rm $DIRJOB/*.smod 2>/dev/null ++/bin/rm $DIRJOB/*_genmod.f90 2>/dev/null + # done if no job id given + if test -z "$jid" + then +@@ -4149,7 +4079,7 @@ + else + #dllrun >0 + if test $cpdll = yes; then +- filename=`basename $usersubname .f` ++ filename=$usernoext + /bin/cp $DIRJOB/$marcdll $DIRJOB/${filename}_$marcdll 2>/dev/null + fi + if test $rmdll = yes;then diff --git a/install/MarcMentat/2022.2/Marc_tools/run_damask_mp.patch b/install/MarcMentat/2022.2/Marc_tools/run_damask_mp.patch new file mode 100644 index 000000000..11f9f00f4 --- /dev/null +++ b/install/MarcMentat/2022.2/Marc_tools/run_damask_mp.patch @@ -0,0 +1,517 @@ +--- ++++ +@@ -136,6 +136,11 @@ + # is created. For job running in the background, the log # + # file is always created. Default is "yes" # + ############################################################################## ++# remove all Mentat paths from LD_LIBRARY_PATH ++LD_LIBRARY_PATH=:$LD_LIBRARY_PATH: ++LD_LIBRARY_PATH=${LD_LIBRARY_PATH//+([!(:)])mentat2022.2+([!(:)])/:} ++LD_LIBRARY_PATH=${LD_LIBRARY_PATH//+([(:)])/:} ++LD_LIBRARY_PATH=${LD_LIBRARY_PATH#:}; LD_LIBRARY_PATH=${LD_LIBRARY_PATH%:} + # set DIR to the directory in which this script is + REALCOM="`/bin/ls -l $0 |awk '{ print $NF; }'`" + DIR=`dirname $REALCOM` +@@ -302,7 +307,23 @@ + + . "$DIR/getarch" + ++ ++# getting user subroutine file name ++found=0 ++for i in "$@"; do ++ if test $found = 1; then ++ DAMASK_USER=$i ++ found=0 ++ fi ++ case $i in ++ -u* | -U*) ++ found=1 ++ ;; ++ esac ++done ++# sourcing include_linux64 (needs DAMASK_USER to be set) + . $MARC_INCLUDE ++ + # + + # +@@ -405,7 +426,7 @@ + did= + vid= + user= +-usersubname= ++usernoext= + objs= + qid=background + cpu= +@@ -676,50 +697,19 @@ + esac + ;; + -u* | -U*) +- user=`dirname $value`/`$BASENAME $value .f` +- usersubname=$user +- basefile=`$BASENAME $value` +- if test ${basefile##*.} = f +- then +- user=`dirname $value`/`$BASENAME $value .f` +- usersubname=$user.f +- elif test ${basefile##*.} = F +- then +- user=`dirname $value`/`$BASENAME $value .F` +- usersubname=$user.F +- elif test ${basefile##*.} = f90 +- then +- user=`dirname $value`/`$BASENAME $value .f90` +- usersubname=$user.f90 +- elif test ${basefile##*.} = F90 +- then +- user=`dirname $value`/`$BASENAME $value .F90` +- usersubname=$user.F90 +- fi ++ user=$value + case $user in + \/*) + ;; + *) + user=`pwd`/$user +- usersubname=`pwd`/$usersubname + ;; + esac +- if test ! -f $usersubname +- then +- if test -f $usersubname.f +- then +- usersubname=$usersubname.f +- elif test -f $usersubname.F +- then +- usersubname=$usersubname.F +- elif test -f $usersubname.f90 +- then +- usersubname=$usersubname.f90 +- elif test -f $usersubname.F90 +- then +- usersubname=$usersubname.F90 +- fi +- fi ++ usernoext=$user ++ usernoext=`dirname $usernoext`/`$BASENAME $usernoext .f` ++ usernoext=`dirname $usernoext`/`$BASENAME $usernoext .F` ++ usernoext=`dirname $usernoext`/`$BASENAME $usernoext .for` ++ usernoext=`dirname $usernoext`/`$BASENAME $usernoext .f90` + ;; + -obj | -OBJ) + objs="$value" +@@ -1207,12 +1197,12 @@ + fi + fi + fi +- if test "$usersubname" ++ if test "$user" + then +- if test ! -f $usersubname ++ if test ! -f $user + then + error="$error +-user subroutine file $usersubname not accessible" ++user subroutine file $user not accessible" + fi + fi + if test "$objs" +@@ -1531,7 +1521,7 @@ + Marc shared lib : $progdll + Version type : $mode + Job ID : $DIRJID/$jid$extra_job_info +-User subroutine name : $usersubname ++User subroutine name : $user + User objects/libs : $objs + Restart file job ID : $rid + Substructure file ID : $sid +@@ -1564,7 +1554,7 @@ + Marc shared lib : $progdll + Version type : $mode + Job ID : $DIRJID/$jid$extra_job_info +-User subroutine name : $usersubname ++User subroutine name : $user + User objects/libs : $objs + Restart file job ID : $rid + Substructure file ID : $sid +@@ -1687,7 +1677,7 @@ + ;; + esac + fi +- $ECHO "User subroutine name ($usersubname)? $ECHOTXT" ++ $ECHO "User subroutine name ($user)? $ECHOTXT" + read value + if test "$value" + then +@@ -1696,50 +1686,19 @@ + user= + ;; + *) +- user=`dirname $value`/`$BASENAME $value .f` +- usersubname=$user +- basefile=`$BASENAME $value` +- if test ${basefile##*.} = f +- then +- user=`dirname $value`/`$BASENAME $value .f` +- usersubname=$user.f +- elif test ${basefile##*.} = F +- then +- user=`dirname $value`/`$BASENAME $value .F` +- usersubname=$user.F +- elif test ${basefile##*.} = f90 +- then +- user=`dirname $value`/`$BASENAME $value .f90` +- usersubname=$user.f90 +- elif test ${basefile##*.} = F90 +- then +- user=`dirname $value`/`$BASENAME $value .F90` +- usersubname=$user.F90 +- fi ++ user=$value + case $user in + \/*) + ;; + *) + user=`pwd`/$user +- usersubname=`pwd`/$usersubname + ;; + esac +- if test ! -f $usersubname +- then +- if test -f $usersubname.f +- then +- usersubname=$usersubname.f +- elif test -f $usersubname.F +- then +- usersubname=$usersubname.F +- elif test -f $usersubname.f90 +- then +- usersubname=$usersubname.f90 +- elif test -f $usersubname.F90 +- then +- usersubname=$usersubname.F90 +- fi +- fi ++ usernoext=$user ++ usernoext=`dirname $usernoext`/`$BASENAME $usernoext .f` ++ usernoext=`dirname $usernoext`/`$BASENAME $usernoext .F` ++ usernoext=`dirname $usernoext`/`$BASENAME $usernoext .for` ++ usernoext=`dirname $usernoext`/`$BASENAME $usernoext .f90` + ;; + esac + fi +@@ -2274,11 +2233,12 @@ + # + # user subroutine used + # ++# add DAMASK options for linking ++ DAMASK="-lstdc++" + + if test "$user" + then +-# program=$user.marc +- program=$DIRJOB/`$BASENAME $user .f`.marc ++ program=$usernoext.marc + case $program in + \/* | \.\/*) + bd= +@@ -2391,7 +2351,7 @@ + fi + if test "$user" + then +- execpath=$DIRJOB/`$BASENAME $user .f`.marc ++ execpath=$usernoext.marc + usersub=1 + fi + export execpath +@@ -3274,44 +3234,27 @@ + echo + if test "$user" + then +- userobj=$DIRJOB/`$BASENAME $user .f`.o +- basefile=`$BASENAME $usersubname` +- if test ${basefile##*.} = f +- then +- usersub=$DIRJOB/`$BASENAME $user .f`.F +- ln -sf "$user.f" "$usersub" +- else +- usersub=$usersubname +- fi +- ++ userobj=$usernoext.o + fi + cat > $jid.runmarcscript << END4 + if test "$user" + then +- if test ${basefile##*.} = f +- then +- ln -sf "$user.f" "$usersub" +- fi + if test $MACHINENAME = "CRAY" + then +- $FORTRAN $usersub || \ ++ $DFORTRANMP $user || \ + { +- echo "$0: compile failed for $user.f" ++ echo "$0: compile failed for $user" + exit 1 + } + /bin/rm $program 2>/dev/null + else +- $FORTRAN $usersub -o $userobj || \ ++ $DFORTRANMP $user -o $userobj || \ + { +- echo "$0: compile failed for $user.f" ++ echo "$0: compile failed for $user" + exit 1 + } + /bin/rm $program 2>/dev/null + fi +- if test ${basefile##*.} = f +- then +- /bin/rm -f "$usersub" +- fi + fi + + +@@ -3331,6 +3274,7 @@ + $TKLIBS \ + $MRCLIBS \ + $METISLIBS \ ++ $DAMASK \ + $SFLIB \ + $OPENSSL_LIB \ + $SYSLIBS \ +@@ -3344,6 +3288,9 @@ + prgsav=yes + fi + /bin/rm $userobj 2>/dev/null ++/bin/rm $DIRJOB/*.mod 2>/dev/null ++/bin/rm $DIRJOB/*.smod 2>/dev/null ++/bin/rm $DIRJOB/*_genmod.f90 2>/dev/null + + # + # run marc +@@ -3390,7 +3337,7 @@ + fi + else + if test $cpdll = yes; then +- filename=`basename $usersubname .f` ++ filename=$usernoext + /bin/cp $DIRJOB/$marcdll $DIRJOB/${filename}_$marcdll 2>/dev/null + fi + if test $rmdll = yes +@@ -3556,7 +3503,7 @@ + # first copy over the user sub if local directories + if test ${dirstatus[$counter]} = "local" + then +- $RCP $user.f $i:$DIR1/ ++ $RCP $user $i:$DIR1/ + fi + # do the compilation on the other machine + if test ${dirstatus[$counter]} = "shared" +@@ -3569,21 +3516,21 @@ + remoteuser=$DIR1/`$BASENAME $user` + $RSH $i /bin/rm $remoteprog 2> /dev/null + echo +- $RSH $i $DIR2/tools/comp_user $DIR2 $DIR1 $remoteuser $remoteprog ++ $RSH $i $DIR2/tools/comp_damask_mp $DIR2 $DIR1 $remoteuser $remoteprog + # check if successful, the new executable should be there + line=`$RSH $i /bin/ls $remoteprog 2> /dev/null` + if test "$line" + then + echo compilation and linking successful on host $i + else +- echo "$0: compile failed for $user.f on host $i" ++ echo "$0: compile failed for $user on host $i" + echo " $PRODUCT Exit number 3" + exit 1 + fi + # remove the user subroutine on remote machine + if test ${dirstatus[$counter]} = "local" + then +- $RSH $i /bin/rm $remoteuser.f 2> /dev/null ++ $RSH $i /bin/rm $remoteuser 2> /dev/null + fi + fi + fi +@@ -3593,39 +3540,27 @@ + if test "$userhost" + then + echo +- echo "Compiling and linking user subroutine $user.f on host `hostname`" +- fi +- userobj=$DIRJOB/`$BASENAME $user .f`.o +- basefile=`$BASENAME $usersubname` +- if test ${basefile##*.} = f +- then +- usersub=$DIRJOB/`$BASENAME $user .f`.F +- ln -sf "$user.f" "$usersub" +- else +- usersub=$usersubname ++ echo "Compiling and linking user subroutine $user on host `hostname`" + fi ++ userobj=$usernoext.o + if test $MACHINENAME = "CRAY" + then +- $FORTRAN $usersub || \ ++ $DFORTRANMP $user || \ + { +- echo "$0: compile failed for $user.f" ++ echo "$0: compile failed for $user" + echo " $PRODUCT Exit number 3" + exit 1 + } + /bin/rm $program 2>/dev/null + else +- $FORTRAN $usersub -o $userobj || \ ++ $DFORTRANMP $user -o $userobj || \ + { +- echo "$0: compile failed for $user.f" ++ echo "$0: compile failed for $user" + echo " $PRODUCT Exit number 3" + exit 1 + } + /bin/rm $program 2>/dev/null + fi +- if test ${basefile##*.} = f +- then +- /bin/rm -f "$usersub" +- fi + fi # if test $user + + +@@ -3645,6 +3580,7 @@ + $TKLIBS \ + $MRCLIBS \ + $METISLIBS \ ++ $DAMASK \ + $SFLIB \ + $OPENSSL_LIB \ + $SYSLIBS \ +@@ -3686,6 +3622,9 @@ + prgsav=yes + fi # if test $link + /bin/rm $userobj 2>/dev/null ++/bin/rm $DIRJOB/*.mod 2>/dev/null ++/bin/rm $DIRJOB/*.smod 2>/dev/null ++/bin/rm $DIRJOB/*_genmod.f90 2>/dev/null + + # + # run marc +@@ -3779,7 +3718,7 @@ + else + #dllrun >0 + if test $cpdll = yes; then +- filename=`basename $usersubname .f` ++ filename=$usernoext + /bin/cp $DIRJOB/$marcdll $DIRJOB/${filename}_$marcdll 2>/dev/null + fi + if test $rmdll = yes;then +@@ -3904,7 +3843,7 @@ + # first copy over the user sub if local directories + if test ${dirstatus[$counter]} = "local" + then +- $RCP $user.f $i:$DIR1/ ++ $RCP $user $i:$DIR1/ + fi + # do the compilation on the other machine + if test ${dirstatus[$counter]} = "shared" +@@ -3917,20 +3856,20 @@ + remoteuser=$DIR1/`$BASENAME $user` + $RSH $i /bin/rm $remoteprog 2> /dev/null + echo +- $RSH $i $DIR2/tools/comp_user $DIR2 $DIR1 $remoteuser $remoteprog ++ $RSH $i $DIR2/tools/comp_damask_mp $DIR2 $DIR1 $remoteuser $remoteprog + # check if successful, the new executable should be there + line=`$RSH $i /bin/ls $remoteprog 2> /dev/null` + if test "$line" + then + echo compilation and linking successful on host $i + else +- echo "$0: compile failed for $user.f on host $i" ++ echo "$0: compile failed for $user on host $i" + exit 1 + fi + # remove the user subroutine on remote machine + if test ${dirstatus[$counter]} = "local" + then +- $RSH $i /bin/rm $remoteuser.f 2> /dev/null ++ $RSH $i /bin/rm $remoteuser 2> /dev/null + fi + fi + fi +@@ -3940,37 +3879,25 @@ + if test "$userhost" + then + echo +- echo "Compiling and linking user subroutine $user.f on host `hostname`" +- fi +- userobj=$DIRJOB/`$BASENAME $user .f`.o +- basefile=`$BASENAME $usersubname` +- if test ${basefile##*.} = f +- then +- usersub=$DIRJOB/`$BASENAME $user .f`.F +- ln -sf "$user.f" "$usersub" +- else +- usersub=$usersubname ++ echo "Compiling and linking user subroutine $user on host `hostname`" + fi ++ userobj=$usernoext.o + if test $MACHINENAME = "CRAY" + then +- $FORTRAN $usersub || \ ++ $DFORTRANMP $user || \ + { +- echo "$0: compile failed for $user.f" ++ echo "$0: compile failed for $user" + exit 1 + } + /bin/rm $program 2>/dev/null + else +- $FORTRAN $usersub -o $userobj || \ ++ $DFORTRANMP $user -o $userobj || \ + { +- echo "$0: compile failed for $user.f" ++ echo "$0: compile failed for $user" + exit 1 + } + /bin/rm $program 2>/dev/null + fi +- if test ${basefile##*.} = f +- then +- /bin/rm -f "$usersub" +- fi + fi # if test $user + + +@@ -3990,6 +3917,7 @@ + $TKLIBS \ + $MRCLIBS \ + $METISLIBS \ ++ $DAMASK \ + $SFLIB \ + $OPENSSL_LIB \ + $SYSLIBS \ +@@ -4030,7 +3958,9 @@ + prgsav=yes + fi # if test $link + /bin/rm $userobj 2>/dev/null +- ++/bin/rm $DIRJOB/*.mod 2>/dev/null ++/bin/rm $DIRJOB/*.smod 2>/dev/null ++/bin/rm $DIRJOB/*_genmod.f90 2>/dev/null + # done if no job id given + if test -z "$jid" + then +@@ -4149,7 +4079,7 @@ + else + #dllrun >0 + if test $cpdll = yes; then +- filename=`basename $usersubname .f` ++ filename=$usernoext + /bin/cp $DIRJOB/$marcdll $DIRJOB/${filename}_$marcdll 2>/dev/null + fi + if test $rmdll = yes;then diff --git a/install/MarcMentat/2022.2/Mentat_bin/edit_window.patch b/install/MarcMentat/2022.2/Mentat_bin/edit_window.patch new file mode 100644 index 000000000..915af9bf6 --- /dev/null +++ b/install/MarcMentat/2022.2/Mentat_bin/edit_window.patch @@ -0,0 +1,24 @@ +--- ++++ +@@ -1,18 +1,5 @@ + #!/bin/sh +-# This script opens a window running an editor. The default window is an +-# xterm, and the default editor is vi. These may be customized. ++# This script opens a window running an editor. ++# The command to invoke the editor is specified during DAMASK installation + +-dir= +-for d in /usr/bin /usr/bin/X11; do +- if test -x "$d/xterm"; then +- dir="$d" +- break +- fi +-done +- +-if test -z "$dir"; then +- echo "$0: Could not find xterm" +- exit 1 +-fi +- +-"$dir/xterm" -T "vi $*" -n "vi $*" -e vi $* ++%EDITOR% $* diff --git a/install/MarcMentat/2022.2/Mentat_bin/kill4.patch b/install/MarcMentat/2022.2/Mentat_bin/kill4.patch new file mode 100644 index 000000000..e69de29bb diff --git a/install/MarcMentat/2022.2/Mentat_bin/kill5.patch b/install/MarcMentat/2022.2/Mentat_bin/kill5.patch new file mode 100644 index 000000000..e69de29bb diff --git a/install/MarcMentat/2022.2/Mentat_bin/kill6.patch b/install/MarcMentat/2022.2/Mentat_bin/kill6.patch new file mode 100644 index 000000000..e69de29bb diff --git a/install/MarcMentat/2022.2/Mentat_bin/submit4.patch b/install/MarcMentat/2022.2/Mentat_bin/submit4.patch new file mode 100644 index 000000000..98c51e76d --- /dev/null +++ b/install/MarcMentat/2022.2/Mentat_bin/submit4.patch @@ -0,0 +1,38 @@ +--- ++++ +@@ -63,10 +63,10 @@ + if [ "$slv" != "" -a "$slv" != "marc" -a "$slv" != "datfit" ]; then + slv="-iam sfm" + fi +-if [ "$slv" == "marc" ]; then ++if [ "$slv" = "marc" ]; then + slv="" + fi +-if [ "$slv" == "datfit" ]; then ++if [ "$slv" = "datfit" ]; then + slv="-iam datfit" + fi + +@@ -91,6 +91,7 @@ + srcfile="-u $srcfile -save y" + ;; + runsaved) ++ srcfile=${srcfile%.*}".marc" + srcfile="-prog $srcfile" + ;; + esac +@@ -189,12 +190,12 @@ + unset PYTHONPATH + + if [ "$doe_first" = "-" ]; then # submit of regular Marc job +- "${DIR}/tools/run_marc" $slv -j $job -v n -b y $nprocds $nprocd \ ++ "${DIR}/tools/run_damask_hmp" $slv -j $job -v n -b y $nprocds $nprocd \ + $srcfile $restart $postfile $viewfactorsfile $hostfile \ + $compat $copy_datfile $copy_postfile $scr_dir $dcoup \ + $assem_recov_nthread $nthread $nsolver $mode $gpu > /dev/null 2>&1 + else # submit of a DoE Marc job +- "${DIR}/tools/run_marc" $slv -j $job -v n -b n $nprocds $nprocd \ ++ "${DIR}/tools/run_damask_hmp" $slv -j $job -v n -b n $nprocds $nprocd \ + $srcfile $restart $postfile $viewfactorsfile $hostfile \ + $compat $copy_datfile $copy_postfile $scr_dir $dcoup \ + $assem_recov_nthread $nthread $nsolver $mode $gpu diff --git a/install/MarcMentat/2022.2/Mentat_bin/submit5.patch b/install/MarcMentat/2022.2/Mentat_bin/submit5.patch new file mode 100644 index 000000000..ab32b1058 --- /dev/null +++ b/install/MarcMentat/2022.2/Mentat_bin/submit5.patch @@ -0,0 +1,38 @@ +--- ++++ +@@ -63,10 +63,10 @@ + if [ "$slv" != "" -a "$slv" != "marc" -a "$slv" != "datfit" ]; then + slv="-iam sfm" + fi +-if [ "$slv" == "marc" ]; then ++if [ "$slv" = "marc" ]; then + slv="" + fi +-if [ "$slv" == "datfit" ]; then ++if [ "$slv" = "datfit" ]; then + slv="-iam datfit" + fi + +@@ -91,6 +91,7 @@ + srcfile="-u $srcfile -save y" + ;; + runsaved) ++ srcfile=${srcfile%.*}".marc" + srcfile="-prog $srcfile" + ;; + esac +@@ -189,12 +190,12 @@ + unset PYTHONPATH + + if [ "$doe_first" = "-" ]; then # submit of regular Marc job +- "${DIR}/tools/run_marc" $slv -j $job -v n -b y $nprocds $nprocd \ ++ "${DIR}/tools/run_damask_mp" $slv -j $job -v n -b y $nprocds $nprocd \ + $srcfile $restart $postfile $viewfactorsfile $hostfile \ + $compat $copy_datfile $copy_postfile $scr_dir $dcoup \ + $assem_recov_nthread $nthread $nsolver $mode $gpu > /dev/null 2>&1 + else # submit of a DoE Marc job +- "${DIR}/tools/run_marc" $slv -j $job -v n -b n $nprocds $nprocd \ ++ "${DIR}/tools/run_damask_mp" $slv -j $job -v n -b n $nprocds $nprocd \ + $srcfile $restart $postfile $viewfactorsfile $hostfile \ + $compat $copy_datfile $copy_postfile $scr_dir $dcoup \ + $assem_recov_nthread $nthread $nsolver $mode $gpu diff --git a/install/MarcMentat/2022.2/Mentat_bin/submit6.patch b/install/MarcMentat/2022.2/Mentat_bin/submit6.patch new file mode 100644 index 000000000..d5ea3cfde --- /dev/null +++ b/install/MarcMentat/2022.2/Mentat_bin/submit6.patch @@ -0,0 +1,38 @@ +--- ++++ +@@ -63,10 +63,10 @@ + if [ "$slv" != "" -a "$slv" != "marc" -a "$slv" != "datfit" ]; then + slv="-iam sfm" + fi +-if [ "$slv" == "marc" ]; then ++if [ "$slv" = "marc" ]; then + slv="" + fi +-if [ "$slv" == "datfit" ]; then ++if [ "$slv" = "datfit" ]; then + slv="-iam datfit" + fi + +@@ -91,6 +91,7 @@ + srcfile="-u $srcfile -save y" + ;; + runsaved) ++ srcfile=${srcfile%.*}".marc" + srcfile="-prog $srcfile" + ;; + esac +@@ -189,12 +190,12 @@ + unset PYTHONPATH + + if [ "$doe_first" = "-" ]; then # submit of regular Marc job +- "${DIR}/tools/run_marc" $slv -j $job -v n -b y $nprocds $nprocd \ ++ "${DIR}/tools/run_damask_lmp" $slv -j $job -v n -b y $nprocds $nprocd \ + $srcfile $restart $postfile $viewfactorsfile $hostfile \ + $compat $copy_datfile $copy_postfile $scr_dir $dcoup \ + $assem_recov_nthread $nthread $nsolver $mode $gpu > /dev/null 2>&1 + else # submit of a DoE Marc job +- "${DIR}/tools/run_marc" $slv -j $job -v n -b n $nprocds $nprocd \ ++ "${DIR}/tools/run_damask_lmp" $slv -j $job -v n -b n $nprocds $nprocd \ + $srcfile $restart $postfile $viewfactorsfile $hostfile \ + $compat $copy_datfile $copy_postfile $scr_dir $dcoup \ + $assem_recov_nthread $nthread $nsolver $mode $gpu diff --git a/install/MarcMentat/2022.2/Mentat_menus/job_run.ms.patch b/install/MarcMentat/2022.2/Mentat_menus/job_run.ms.patch new file mode 100644 index 000000000..3368a6360 --- /dev/null +++ b/install/MarcMentat/2022.2/Mentat_menus/job_run.ms.patch @@ -0,0 +1,158 @@ +--- ++++ +@@ -261,11 +261,18 @@ + } + button { + position +25 = +- size 25 4 ++ size 18 4 + text "ADVANCED JOB SUBMISSION" + help "job_run#Job Submission And Control" + popmenu job_submit_adv_pm + } ++ button { ++ position +18 = ++ size 7 4 ++ text "DAMASK" ++ help "damask_run#Job Submission And Control" ++ popmenu damask ++ } + button { + position 0 +4 + size 16 4 +@@ -1202,6 +1209,135 @@ + } + + ++#-------------------------------------------------------------------------------------------------- ++popmenu damask { ++ ++#ifdef QT_MENTAT ++ text "DAMASK.MPIE.DE" ++#endif ++ ++ group { ++#ifndef QT_MENTAT ++ label { ++ position 0 0 ++ size 50 4 ++ text "DAMASK.MPIE.DE" ++ } ++#endif ++ ++ label { ++ position 1 6 ++ size 13 6 ++ text "Optimzation" ++ border_width 1 ++ border_color black ++ } ++ ++ label { ++ position +13 = ++ size 20 6 ++ text "write Input" ++ border_width 1 ++ border_color black ++ } ++ ++ label { ++ position +18 = ++ size 30 6 ++ text "do not write Inp." ++ border_width 1 ++ border_color black ++ } ++ ++ label { ++ position -32 +6 ++ size 12 6 ++ text "O3 / OpenMP" ++ border_width 1 ++ border_color black ++ } ++ ++ popdown { ++ position +12 = ++ size 20 6 ++ text "Submit" ++ command "*submit_job 4 *monitor_job" ++ } ++ ++ popdown { ++ position +20 = ++ size 20 6 ++ text "Execute" ++ command "*execute_job 4 *monitor_job" ++ } ++ ++ label { ++ position -32 +6 ++ size 12 6 ++ text "O1 / OpenMP" ++ border_width 1 ++ border_color black ++ } ++ ++ popdown { ++ position +12 = ++ size 20 6 ++ text "Submit" ++ command "*submit_job 5 *monitor_job" ++ } ++ ++ popdown { ++ position +20 = ++ size 20 6 ++ text "Execute" ++ command "*execute_job 5 *monitor_job" ++ } ++ ++ label { ++ position -32 +6 ++ size 12 6 ++ text "O0 / OpenMP" ++ border_width 1 ++ border_color black ++ } ++ ++ popdown { ++ position +12 = ++ size 20 6 ++ text "Submit" ++ command "*submit_job 6 *monitor_job" ++ } ++ ++ popdown { ++ position +20 = ++ size 20 6 ++ text "Execute" ++ command "*execute_job 6 *monitor_job" ++ } ++ ++ popdown { ++ position 19 +8 ++ size 12 8 ++ text "CANCEL" ++ } ++} ++ ++ window { ++ parent mentat ++ origin 38 8 ++#ifdef DCOM ++ size 50 100 ++#else ++ size 50 94 ++#endif ++ background_color body ++ border_width 1 ++ border_color border ++ buffering single ++ } ++ mode permanent ++} ++ + #-------------------------------------------------------------------------------------------------- + popmenu job_exit_msg_pm { + diff --git a/install/MarcMentat/apply_DAMASK_modifications.py b/install/MarcMentat/MSC_modifications.py similarity index 50% rename from install/MarcMentat/apply_DAMASK_modifications.py rename to install/MarcMentat/MSC_modifications.py index 353df955e..689d49b2a 100755 --- a/install/MarcMentat/apply_DAMASK_modifications.py +++ b/install/MarcMentat/MSC_modifications.py @@ -9,9 +9,12 @@ from pathlib import Path import subprocess import shlex -sys.path.append(str(Path(__file__).parents[2]/'python/damask')) +sys.path.append(str(Path(__file__).resolve().parents[2]/'python/damask')) import solver +APPLY = 'install' +RESTORE = 'uninstall' + def copy_and_patch(patch,orig,editor): try: shutil.copyfile(orig,orig.parent/patch.stem) @@ -25,9 +28,11 @@ def copy_and_patch(patch,orig,editor): parser = argparse.ArgumentParser( - description='Apply DAMASK modification to MSC Marc/Mentat', + description=f'{APPLY.capitalize()} or {RESTORE} DAMASK modifications to MSC Marc/Mentat', formatter_class=argparse.ArgumentDefaultsHelpFormatter) +parser.add_argument('command', metavar='command', nargs='?', default=APPLY, choices=[APPLY,RESTORE], + help=f'Mode of operation {[APPLY,RESTORE]}') parser.add_argument('--editor', dest='editor', metavar='string', default='vi', help='Name of the editor (executable) used by Marc Mentat') parser.add_argument('--marc-root', dest='marc_root', metavar='string', @@ -40,10 +45,10 @@ parser.add_argument('--damask-root', dest='damask_root', metavar = 'string', default=solver._marc._damask_root, help='DAMASK root directory') - args = parser.parse_args() -marc_root = Path(args.marc_root).expanduser() -damask_root = Path(args.damask_root).expanduser() + +damask_root = Path(args.damask_root).expanduser() +marc_root = Path(args.marc_root).expanduser() marc_version = args.marc_version matches = {'Marc_tools': [['comp_user','comp_damask_*mp'], @@ -54,22 +59,40 @@ matches = {'Marc_tools': [['comp_user','comp_damask_*mp'], ['kill1','kill?']], 'Mentat_menus':[['job_run.ms','job_run.ms']]} -for cmd in ['patch','xvfb-run']: +for cmd in ['xvfb-run','patch'] if args.command == APPLY else ['xvfb-run'] if args.command == RESTORE else []: try: - subprocess.run(shlex.split(f'{cmd} --help')) + subprocess.run([cmd,'--help'], capture_output=True) except FileNotFoundError: print(f'"{cmd}" not found, please install') sys.exit() +if args.command == APPLY: + print('patching files...') -print('patching files...') + for directory in glob.glob(str(damask_root/'install/MarcMentat'/marc_version/'*')): + for orig, mods in matches[Path(directory).name]: + product,subfolder = (marc_root/directory).name.split('_') + orig = marc_root/f'{product.lower()}{marc_version}/{subfolder}/{orig}' + for patch in glob.glob(f'{directory}/{mods}.patch'): + copy_and_patch(Path(patch),orig,args.editor) -for directory in glob.glob(str(damask_root/'install/MarcMentat'/marc_version/'*')): - for orig, mods in matches[Path(directory).name]: - product,subfolder = (marc_root/Path(directory)).name.split('_') - orig = marc_root/f'{product.lower()}{marc_version}/{subfolder}/{orig}' - for patch in glob.glob(f'{directory}/{mods}.patch'): - copy_and_patch(Path(patch),orig,args.editor) +elif args.command == RESTORE: + print('deleting modified files...') + + for file in (glob.glob(str(marc_root/f'marc{marc_version}/tools/*_damask*')) + + glob.glob(str(marc_root/f'mentat{marc_version}/bin/kill[4-6]')) + + glob.glob(str(marc_root/f'mentat{marc_version}/bin/submit[4-6]*'))): + os.remove(file) + + print('restoring original files...') + + for file in (glob.glob(str(marc_root/f'marc{marc_version}/tools/include_linux64.orig')) + + glob.glob(str(marc_root/f'mentat{marc_version}/bin/edit_window.orig')) + + glob.glob(str(marc_root/f'mentat{marc_version}/menus/job_run.ms.orig'))): + shutil.copyfile(file,Path(file).with_suffix('')) + os.remove(file) +else: + print('skipping file modifications...') print('compiling Mentat menu binaries...') @@ -79,8 +102,10 @@ subprocess.run(shlex.split(f'xvfb-run -a {executable} -compile {menu_file}')) print('setting file access rights...') -for file in (glob.glob(str(marc_root/f'marc{marc_version}/tools/*_damask*')) + - glob.glob(str(marc_root/f'mentat{marc_version}/bin/edit_window')) + - glob.glob(str(marc_root/f'mentat{marc_version}/bin/kill[4-6]')) + - glob.glob(str(marc_root/f'mentat{marc_version}/bin/submit[4-6]'))): +for file in ( + (glob.glob(str(marc_root/f'marc{marc_version}/tools/*_damask*')) + + glob.glob(str(marc_root/f'mentat{marc_version}/bin/kill[4-6]')) + + glob.glob(str(marc_root/f'mentat{marc_version}/bin/submit[4-6]')) if args.command == APPLY else []) + + glob.glob(str(marc_root/f'mentat{marc_version}/bin/edit_window')) + ): os.chmod(file , 0o755) diff --git a/install/MarcMentat/installation.txt b/install/MarcMentat/installation.txt index 2ef682d65..e51af8932 100644 --- a/install/MarcMentat/installation.txt +++ b/install/MarcMentat/installation.txt @@ -1,7 +1,12 @@ -Install DAMASK modifications to use DAMASK_marc -This is for the Linux64 version of Marc/Mentat +Install or uninstall DAMASK modifications to MSC Marc/Mentat. +This is for the Linux64 version of Marc/Mentat. -Refer to http://damask.mpie.de for complete installation instructions. +usage: MSC_modifications.py [-h] [--editor string] [--marc-root string] [--marc-version string] [--damask-root string] + [command] + +where command is either 'install' or 'uninstall' + +Refer to https://damask.mpie.de/installation/source_code.html#msc-marc for complete installation instructions. Usually you will need to be root for this to work! @@ -9,6 +14,6 @@ See Marc and Mentat Release Guide for List of Build and Supported Platforms. The Intel Fortran compiler needs to be installed. -1) Install Marc, Mentat and Documentation as usual +1) Install Marc, Mentat, and Documentation as usual. Run the test example including subroutines to confirm that the installation of both Marc/Mentat and the Intel Fortran Compiler is ok. -2) Run the apply_DAMASK_modifications.py script from this directory. +2) Run the MSC_modifications.py script from this directory. diff --git a/python/damask/solver/_marc.py b/python/damask/solver/_marc.py index 51c65a695..76054d597 100644 --- a/python/damask/solver/_marc.py +++ b/python/damask/solver/_marc.py @@ -3,7 +3,7 @@ import shlex import re from pathlib import Path -_marc_version = '2022.1' +_marc_version = '2022.2' _marc_root = '/opt/msc' _damask_root = str(Path(__file__).parents[3]) diff --git a/src/Marc/DAMASK_Marc.f90 b/src/Marc/DAMASK_Marc.f90 index 91a30ba6f..8f93d93dc 100644 --- a/src/Marc/DAMASK_Marc.f90 +++ b/src/Marc/DAMASK_Marc.f90 @@ -413,6 +413,8 @@ subroutine uedinc(inc,incsub) use discretization_Marc implicit none(type,external) + + external :: nodvar integer(pI64), intent(in) :: inc, incsub integer :: n, nqncomp, nqdatatype diff --git a/src/Marc/include/concom2022.2 b/src/Marc/include/concom2022.2 new file mode 100644 index 000000000..2d4deaa34 --- /dev/null +++ b/src/Marc/include/concom2022.2 @@ -0,0 +1,466 @@ +! common block definition file taken from respective MSC.Marc release and reformated to free format +!*********************************************************************** +! +! File: concom.cmn +! +! MSC.Marc include file +! +integer & + iacous, iasmbl, iautth, ibear, icompl, iconj, icreep, ideva, idyn, idynt,& + ielas, ielcma, ielect, iform, ifour, iharm, ihcps, iheat, iheatt, ihresp,& + ijoule, ilem, ilnmom, iloren, inc, incext, incsub, ipass, iplres, ipois,& + ipoist, irpflo, ismall, ismalt, isoil, ispect, ispnow, istore, iswep, ithcrp,& + itherm, iupblg, iupdat, jacflg, jel, jparks, largst, lfond, loadup, loaduq,& + lodcor, lovl, lsub, magnet, ncycle, newtnt, newton, noshr, linear, ivscpl,& + icrpim, iradrt, ipshft, itshr, iangin, iupmdr, iconjf, jincfl, jpermg, jhour,& + isolvr, jritz, jtable, jshell, jdoubl, jform, jcentr, imini, kautth, iautof,& + ibukty, iassum, icnstd, icnstt, kmakmas, imethvp, iradrte, iradrtp, iupdate, iupdatp,& + ncycnt, marmen , idynme, ihavca, ispf, kmini, imixex, largtt, kdoela, iautofg,& + ipshftp, idntrc, ipore, jtablm, jtablc, isnecma, itrnspo, imsdif, jtrnspo, mcnear,& + imech, imecht, ielcmat, ielectt, magnett, imsdift, noplas, jtabls, jactch, jtablth,& + kgmsto , jpzo, ifricsh, iremkin, iremfor, ishearp, jspf, machining, jlshell, icompsol,& + iupblgfo, jcondir, nstcrp, nactive, ipassref, nstspnt, ibeart, icheckmpc, noline, icuring,& + ishrink, ioffsflg, isetoff, ioffsetm,iharmt, inc_incdat, iautspc, ibrake, icbush, istream_input,& + iprsinp, ivlsinp, ifirst_time,ipin_m, jgnstr_glb, imarc_return,iqvcinp, nqvceid, istpnx, imicro1,& + iaxisymm, jbreakglue,iglstif, jfastasm,iwear, iwearcf, imixmeth, ielcmadyn, idinout, igena_meth,& + magf_meth, non_assumed, iredoboudry, ioffsz0,icomplt, mesh_dual, iactrp, mgnewton, iusedens,igsigd0,& + iaem, icosim, inodels, nlharm, iampini, iphasetr, inonlcl, inonlct, iforminp,ispecerror,& + icsprg, imol, imolt, idatafit,iharmpar, inclcase, imultifreq,init_elas, ifatig, iftgmat,& + nchybrid, ibuckle, iexpande +dimension :: ideva(60) +integer num_concom +parameter(num_concom=263) +common/marc_concom/& + iacous, iasmbl, iautth, ibear, icompl, iconj, icreep, ideva, idyn, idynt,& + ielas, ielcma, ielect, iform, ifour, iharm, ihcps, iheat, iheatt, ihresp,& + ijoule, ilem, ilnmom, iloren, inc, incext, incsub, ipass, iplres, ipois,& + ipoist, irpflo, ismall, ismalt, isoil, ispect, ispnow, istore, iswep, ithcrp,& + itherm, iupblg, iupdat, jacflg, jel, jparks, largst, lfond, loadup, loaduq,& + lodcor, lovl, lsub, magnet, ncycle, newtnt, newton, noshr, linear, ivscpl,& + icrpim, iradrt, ipshft, itshr, iangin, iupmdr, iconjf, jincfl, jpermg, jhour,& + isolvr, jritz, jtable, jshell, jdoubl, jform, jcentr, imini, kautth, iautof,& + ibukty, iassum, icnstd, icnstt, kmakmas, imethvp, iradrte, iradrtp, iupdate, iupdatp,& + ncycnt, marmen, idynme, ihavca, ispf, kmini, imixex, largtt, kdoela, iautofg,& + ipshftp, idntrc, ipore, jtablm, jtablc, isnecma, itrnspo, imsdif, jtrnspo, mcnear,& + imech, imecht, ielcmat, ielectt, magnett, imsdift, noplas, jtabls, jactch, jtablth,& + kgmsto , jpzo, ifricsh, iremkin, iremfor, ishearp, jspf, machining, jlshell, icompsol,& + iupblgfo, jcondir, nstcrp, nactive, ipassref, nstspnt, ibeart, icheckmpc, noline, icuring,& + ishrink, ioffsflg, isetoff, ioffsetm,iharmt, inc_incdat, iautspc, ibrake, icbush, istream_input,& + iprsinp, ivlsinp, ifirst_time,ipin_m, jgnstr_glb, imarc_return,iqvcinp, nqvceid, istpnx, imicro1,& + iaxisymm, jbreakglue,iglstif, jfastasm,iwear, iwearcf, imixmeth, ielcmadyn, idinout, igena_meth,& + magf_meth, non_assumed, iredoboudry, ioffsz0,icomplt, mesh_dual, iactrp, mgnewton, iusedens,igsigd0,& + iaem, icosim, inodels, nlharm, iampini, iphasetr, inonlcl, inonlct, iforminp,ispecerror,& + icsprg, imol, imolt, idatafit,iharmpar, inclcase, imultifreq,init_elas, ifatig, iftgmat,& + nchybrid, ibuckle, iexpande +! +! comments of variables: +! +! iacous Control flag for acoustic analysis. Input data. +! iacous=1 modal acoustic analysis. +! iacous=2 harmonic acoustic-structural analysis. +! iasmbl Control flag to indicate that operator matrix should be +! recalculated. +! iautth Control flag for AUTO THERM option. +! ibear Control flag for bearing analysis. Input data. +! icompl Control variable to indicate that a complex analysis is +! being performed. Either a Harmonic analysis with damping, +! or a harmonic electro-magnetic analysis. Input data. +! iconj Flag for EBE conjugate gradient solver (=solver 1, retired) +! Also used for VKI iterative solver. +! icreep Control flag for creep analysis. Input data. +! ideva(60) - debug print out flag +! 1 print element stiffness matrices, mass matrix +! 2 output matrices used in tying +! 3 force the solution of a nonpositive definite matrix +! 4 print info of connections to each node +! 5 info of gap convergence, internal heat generated, contact +! touching and separation +! 6 nodal value array during rezoning +! 7 tying info in CONRAD GAP option, fluid element numbers in +! CHANNEL option +! 8 output incremental displacements in local coord. system +! 9 latent heat output +! 10 stress-strain in local coord. system +! 11 additional info on interlaminar stress +! 12 output right hand side and solution vector +! 13 info of CPU resources used and memory available on NT +! 14 info of mesh adaption process, 2D outline information +! info of penetration checking for remeshing +! save .fem files after afmesh3d meshing +! print local adaptivity info +! 15 surface energy balance flag +! 16 print info regarding pyrolysis +! 17 print info of "streamline topology" +! 18 print mesh data changes after remeshing +! 19 print material flow stress data read in from *.mat file +! if unit flag is on, print out flow stress after conversion +! 20 print information on table input +! 21 print out information regarding kinematic boundary conditions +! 22 print out information regarding dist loads, point loads, film +! and foundations +! 23 print out information about automatic domain decomposition +! 24 print out iteration information in SuperForm status report file +! 25 print out information for ablation +! 26 print out information for films - Table input +! 27 print out the tying forces +! 28 print out for CASI solver, convection, +! 29 DDM single file debug printout +! 30 print out cavity debug info +! 31 print out welding related info +! 32 prints categorized DDM memory usage +! 33 print out the cutting info regarding machining feature +! 34 print out the list of quantities which can be defined via a table +! and for each quantity the supported independent variables +! 35 print out detailed coupling region info +! 36 print out solver debug info level 1 (Least Detailed) +! 37 print out solver debug info level 1 (Medium Detailed) +! 38 print out solver debug info level 1 (Very Detailed) +! 39 print detailed memory allocation info +! 40 print out marc-adams debug info +! 41 output rezone mapping post file for debugging +! 42 output post file after calling oprofos() for debugging +! 43 debug printout for vcct +! 44 debug printout for progressive failure +! 45 print out automatically generated midside node coordinates (arecrd) +! 46 print out message about routine and location, where the ibort is raised (ibort_inc) +! 47 print out summary message of element variables on a +! group-basis after all the automatic changes have been +! made (em_ellibp) +! 48 Automatically generate check results based on max and min vals. +! These vals are stored in the checkr file, which is inserted +! into the *dat file by the generate_check_results script from /marc/tools +! 49 Automatically generate check results based on the real calculated values +! at the sppecified check result locations. +! These vals are stored in the checkr file, which is inserted +! into the *dat file by the update_check_results script from /marc/tools +! 50 generate a file containing the resistance or capacity matrix; +! this file can be used to compare results with a reference file +! 51 print out detailed information for segment-to-segment contact +! 52 print out detailed relative displacement information +! for uniaxial sliding contact +! 53 print out detailed sliding direction information for +! uniaxial sliding contact +! 54 print out detailed information for edges attached to a curve +! 55 print information related to viscoelasticity calculations +! 56 print out detailed information for element coloring for multithreading +! 57 print out extra overheads due to multi-threading. +! These overhead includes (i) time and (ii) memory. +! The memory report will be summed over all the children. +! 58 debug output for ELSTO usage +! 59 print out contact body forces and nodes in contact +! +! idyn Control flag for dynamics. Input data. +! 1 = eigenvalue extraction and / or modal superposition +! 2 = Newmark Beta and Single Step Houbolt (ssh with idynme=1) +! 3 = Houbolt +! 4 = Central difference +! 5 = Newer central difference +! idynt Copy of idyn at begining of increment +! ielas Control flag for ELASTIC analysis. Input data. +! Set by user or automatically turned on by Fourier option. +! Implies that each load case is treated separately. +! In Adaptive meshing analysis , forces re-analysis until +! convergence obtained. +! Also seriously misused to indicate no convergence. +! = 1 elastic option with fourier analysis +! = 2 elastic option without fourier analysis +! =-1 no convergence in recycles or max # increments reached +! Set to 1 if ELASTIC or SUBSTRUC parameter cards are used, +! or if fourier option is used. +! Then set to 2 if not fourier analysis. +! ielcma Control flag for electromagnetic analysis. Input data. +! ielcma = 1 Harmonic formulation +! ielcma = 2 Transient formulation +! ielect Control flag for electrostatic option. Input data. +! iform Control flag indicating that contact will be performed. +! ifour Control flag for Fourier analysis. +! 0 = Odd and even terms. +! 1 = symmetric (cosine) terms +! 2 = antisymmetric (sine) terms. +! iharm Control flag to indicate that a harmonic analysis will +! be performed. May change between passes. +! ihcps Control flag for coupled thermal - stress analysis. +! iheat Control flag for heat transfer analysis. Input data. +! iheatt Permanent control flag for heat transfer analysis. +! Note in coupled analysis iheatt will remain as one, +! but iheat will be zero in stress pass. +! ihresp Control flag to indicate to perform a harmonic subincrement. +! ijoule Control flag for Joule heating. +! ilem Control flag to determin which vector is to be transformed. +! Control flag to see where one is: +! ilem = 1 - elem.f +! ilem = 2 - initst.f +! ilem = 3 - pressr.f +! ilem = 3 - fstif.f +! ilem = 4 - jflux.f +! ilem = 4 - strass.f +! ilem = 5 - mass.f +! ilem = 5 - osolty.f +! ilnmom Control flag for soil - pore pressure calculation. Input data. +! ilnmom = 0 - perform only pore pressure calculation. +! = 1 - couples pore pressure - displacement analysis +! iloren Control flag for DeLorenzi J-Integral evaluation. Input data. +! inc Increment number. +! incext Control flag indicating that currently working on a +! subincrement. +! Could be due to harmonics , damping component (bearing), +! stiffness component (bearing), auto therm creep or +! old viscoplaticity +! incsub Sub-increment number. +! inonlcl control flag for nonlocal pass +! inonlct permanent control flag for nonlocal pass +! ipass Control flag for which part of coupled analysis. +! ipass = -1 - reset to base values +! ipass = 0 - do nothing +! ipass = 1 - stress part +! ipass = 2 - heat transfer part +! 3 - fluid pass +! 4 - joule heating pass +! 5 - pore pressure pass +! 6 - electrostatic pass +! 7 - magnetostatic pass +! 8 - electromagnetic pass +! 9 - diffusion pass +! ipass = 10 - nonlocal part +! iplres Flag indicating that either second matrix is stored. +! dynamic analysis - mass matrix +! heat transfer - specific heat matrix +! buckle - initial stress stiffness +! ipois Control flag indicating Poisson type analysis +! ipois = 1 for heat transfer +! = 1 for heat transfer part of coupled +! = 1 for bearing +! = 1 for electrostatic +! = 1 for magnetostatic +! = 1 for nonlocal part +! ipoist Permanent copy of ipois. In coupled analysis , ipois = 0 +! in stress portion, yet ipoist will still =1. +! irpflo global flag for rigid plastic flow analysis +! = 1 eularian formulation +! = 2 regular formulation; rigid material present in the analysis +! ismall control flag to indicate small displacement analysis. input data. +! ismall = 0 - large disp included. +! ismall = 1 - small displacement. +! the flag is changing between passes. +! ismalt permanent copy of ismall . in heat transfer portion of +! coupled analysis ismall =0 , but ismalt remains the same. +! isoil control flag indicating that soil / pore pressure +! calculation . input data. +! ispect control flag for response spectrum calculation. input data. +! ispnow control flag to indicate to perform a spectrum response +! calculation now. +! istore store stresses flag. +! istore = 0 in elem.f and if first pass of creep +! convergence checking in ogetst.f +! or harmonic analysis or thruc.f if not +! converged. +! iswep control flag for eigenvalue analysis. +! iswep=1 - go do extraction process +! ithcrp control flag for auto therm creep option. input data. +! itherm control flag for either temperature dependent material +! properties and/or thermal loads. +! iupblg control flag for follower force option. input data. +! iupdat control flag for update lagrange option for current element. +! jacflg control flag for lanczos iteration method. input data. +! jel control flag indicating that total load applied in +! increment, ignore previous solution. +! jel = 1 in increment 0 +! = 1 if elastic or fourier +! = 1 in subincrements with elastic and adaptive +! jparks control flag for j integral by parks method. input data. +! largst control flag for finite strain plasticity. input data. +! lfond control variable that indicates if doing elastic +! foundation or film calculation. influences whether +! this is volumetric or surface integration. +! loadup control flag that indicates that nonlinearity occurred +! during previous increment. +! loaduq control flag that indicates that nonlinearity occurred. +! lodcor control flag for switching on the residual load correction. +! notice in input stage lodcor=0 means no loadcor, +! after omarc lodcor=1 means no loadcor +! lovl control flag for determining which "overlay" is to +! be called from ellib. +! lovl = 1 omarc +! = 2 oaread +! = 3 opress +! = 4 oasemb +! = 5 osolty +! = 6 ogetst +! = 7 oscinc +! = 8 odynam +! = 9 opmesh +! = 10 omesh2 +! = 11 osetz +! = 12 oass +! = 13 oincdt +! = 14 oasmas +! = 15 ofluas +! = 16 ofluso +! = 17 oshtra +! = 18 ocass +! = 19 osoltc +! = 20 orezon +! = 21 otest +! = 22 oeigen +! lsub control variable to determine which part of element +! assembly function is being done. +! lsub = 1 - no longer used +! = 2 - beta* +! = 3 - cons* +! = 4 - ldef* +! = 5 - posw* +! = 6 - theta* +! = 7 - tmarx* +! = 8 - geom* +! magnet control flag for magnetostatic analysis. input data. +! ncycle cycle number. accumulated in osolty.f +! note first time through oasemb.f , ncycle = 0. +! newtnt control flag for permanent copy of newton. +! newton iteration type. input data. +! newton : = 1 full newton raphson +! 2 modified newton raphson +! 3 newton raphson with strain correct. +! 4 direct substitution +! 5 direct substitution followed by n.r. +! 6 direct substitution with line search +! 7 full newton raphson with secant initial stress +! 8 secant method +! 9 full newton raphson with line search +! noshr control flag for calculation interlaminar shears for +! elements 22,45, and 75. input data. +!ees +! +! jactch = 1 or 2 if elements are activated or deactivated +! = 3 if elements are adaptively remeshed or rezoned +! = 0 normally / reset to 0 when assembly is done +! ifricsh = 0 call to fricsh in otest not needed +! = 1 call to fricsh (nodal friction) in otest needed +! iremkin = 0 remove deactivated kinematic boundary conditions +! immediately - only in new input format (this is default) +! = 1 remove deactivated kinematic boundary conditions +! gradually - only in new input format +! iremfor = 0 remove force boundary conditions immediately - +! only in new input format (this is default) +! = 1 remove force boundary conditions gradually - +! only in new input format (this is default) +! ishearp set to 1 if shear panel elements are present in the model +! +! jspf = 0 not in spf loadcase +! > 0 in spf loadcase (jspf=1 during first increment) +! machining = 1 if the metal cutting feature is used, for memory allocation purpose +! = 0 (default) if no metal cutting feature required +! +! jlshell = 1 if there is a shell element in the mesh +! icompsol = 1 if there is a composite solid element in the mesh +! iupblgfo = 1 if follower force for point loads +! jcondir = 1 if contact priority option is used +! nstcrp = 0 (default) steady state creep flag (undocumented feature. +! if not 0, turns off special ncycle = 0 code in radial.f) +! nactive = number of active passes, if =1 then it's not a coupled analysis +! ipassref = reference ipass, if not in a multiphysics pass ipass=ipassref +! icheckmpc = value of mpc-check parameter option +! noline = set to 1 in osolty if no line seacrh should be done in ogetst +! icuring = set to 1 if the curing is included for the heat transfer analysis. +! ishrink = set to 1 if shrinkage strain is included for mechancial analysis. +! ioffsflg = 1 for small displacement beam/shell offsets +! = 2 for large displacement beam/shell offsets +! isetoff = 0 - do not apply beam/shell offsets +! = 1 - apply beam/shell offsets +! ioffsetm = min. value of offset flag +! iharmt = 1 global flag if a coupled analysis contains an harmonic pass +! inc_incdat = flag to record increment number of a new loadcase in incdat.f +! iautspc = flag for AutoSPC option +! ibrake = brake squeal in this increment +! icbush = set to 1 if cbush elements present in model +! istream_input = set to 1 for streaming input calling Marc as library +! iprsinp = set to 1 if pressure input, introduced so other variables +! such as h could be a function of pressure +! ivlsinp = set to 1 if velocity input, introduced so other variables +! such as h could be a function of velocity +! ipin_m = # of beam element with PIN flag +! jgnstr_glb = global control over pre or fast integrated composite shells +! imarc_return = Marc return flag for streaming input control +! iqvcimp = if non-zero, then the number of QVECT boundary conditions +! nqvceid = number of QVECT boundary conditions, where emisivity/absorbtion id entered +! istpnx = 1 if to stop at end of increment +! imicro1 = 1 if micro1 interface is used +! iaxisymm = set to 1 if axisymmetric analysis +! jbreakglue = set to 1 if breaking glued option is used +! iglstif = 1 if ddm and global stiffness matrix formed (sgi solver 6 or solver9) +! jfastasm = 1 do fast assembly using SuperForm code +! iwear = set to 1 if wear model, set to 2 if wear model and coordinates updated +! iwearcf = set to 1 to store nodal coefficient of friction for wear calculation +! imixmeth = set=1 then use nonlinear mixture material - allocate memory +! ielcmadyn = flag for magnetodynamics +! 0 - electromagnetics using newmark beta +! 1 - transient magnetics using backward euler +! idinout = flag to control if inside out elements should be deactivated +! igena_meth = 0 - generalized alpha parameters depend on whether or not contact +! is flagged (dynamic,7) +! 10 - generalized alpha parameters are optimized for a contact +! analysis (dynamic,8) +! 11 - generalized alpha parameters are optimized for an analysis +! without contact (dynamic,8) +! magf_meth = - Method to compute force in magnetostatic - structural +! = 1 - Virtual work method based on finite difference for the force computation +! = 2 - Maxwell stress tensor +! = 3 - Virtual work method based on local derivative for the force computation +! non_assumed = 1 no assumed strain formulation (forced) +! iredoboudry set to 1 if contact boundary needs to be recalculated +! ioffsz0 = 1 if composite are used with reference position.ne.0 +! icomplt = 1 global flag if a coupled analysis contains an complex pass +! mesh_dual = 1 two independent meshes are used in magnetodynamic/thermal/structural +! one for magnetodynamic and the other for the remaining passes +! iactrp = 1 in an analysis with global remeshing, include inactive +! rigid bodies on post file +! mgnewton = 1 Use full Newton Raphson iteration for magnetostatic pass +! +! iusedens > 0 if mass density is used in the analysis (dynamics, mass dependent loading) +! igsigd0 = 1 set varselem(igsigd) to zero in next oasemb +! iaem = 1 if marc is called from aem (0 - off - default) +! icosim = 1 if marc is used in co-simulation analysis with ADAMS using the CosimEngine +! = 2 if marc is used in co-simulation analysis with ADAMS using the ACSI interface +! = 3 if marc is used in co-simulation analysis with scFLOW using the CosimEngine +! = 4 if marc is used in co-simulation analysis with scFLOW and ADAMS using the CosimEngine +! inodels = 1 nodal integration elements 239/240/241 present +! nlharm = 0 harmonic subincrements are linear +! = 1 harmonic subincrements are nonlinear +! iampini = 0 amplitude of previous harmonic subinc is initial estimate (default) +! = 1 zero amplitude is initial estimate +! iphasetr = 1 phase transformation material model is used +! iforminp flag indicating that contact is switched on via the CONTACT +! option in the input file (as opposed to the case that contact +! is switched on internally due to cyclic symmetry or model +! section creation) +! ispecerror = a+10*b (only for spectrum response analysis with missing mass option) +! a=0 or a=1 (modal shape with non-zero shift) +! b=0 or b=1 (recover with new assembly of stiffness matrix) +! icsprg = set to 1 if spring elements present in model +! imol Control flag for molecualr diffusion pass +! imolt Permanent control flag for molecualr diffusion pass +! Note in coupled analysis imolt will remain as one, +! but imol will be zero in stress pass or thermal pass. +! idatafit = run Marc to fit parameters +! iharmpar = 1 if harmonic parameter option is used +! inclcase load case increment use for cyclic plasticity data fitting +! imultifreq flag to indicate how many harmonic magnetodynamic passes are computed in coupled +! magnetodynamic/thermal(/structural) analyses. +! 0 or 1 one pass 2 two passes 3 or more is not supported +! init_elas use elastic stress-strain law as the material tangent for +! the first cycle of an increment +! ifatig packed integer telling which fatigue mode is active +! 1 = elastomer +! 10 = stress-life +! 100 = strain-life +! = 2 strain-life fatigue +! iftgmat = 0 no fatigue material properties in the dat file +! = 1 fatigue material properties in the dat file +! nchybrid cycle count used for hybrid contact; meant to force an extra iteration +! if the overlap for a node in hybrid contact is too large +! ibuckle buckle parameter option is active +! iexpande set to 1 if expanded elements (248, 249, 250 or 251) are +! present, 0 otherwise +! +!*********************************************************************** +!$omp threadprivate(/marc_concom/) +!! diff --git a/src/Marc/include/creeps2022.2 b/src/Marc/include/creeps2022.2 new file mode 100644 index 000000000..b35d2b6bf --- /dev/null +++ b/src/Marc/include/creeps2022.2 @@ -0,0 +1,73 @@ +! common block definition file taken from respective MSC.Marc release and reformated to free format +!*********************************************************************** +! +! File: creeps.cmn +! +! MSC.Marc include file +! +real(pReal) cptim,timinc,timinc_p,timinc_s,timincm,timinc_a,timinc_b +integer icfte,icfst,icfeq,icftm,icetem,mcreep,jcreep,icpa,icftmp,icfstr,& + icfqcp,icfcpm,icrppr,icrcha,icpb,iicpmt,iicpa +real(pReal) time_beg_lcase,time_beg_inc,fractol,time_beg_pst +real(pReal) fraction_donn,timinc_ol2 +! +integer num_creepsr,num_creepsi,num_creeps2r,ncrp_arry +parameter(num_creepsr=7) +parameter(num_creepsi=17) +parameter(num_creeps2r=6) +parameter(ncrp_arry=7) +common/marc_creeps/cptim,timinc,timinc_p,timinc_s,timincm,timinc_a,timinc_b,icfte,icfst,& + icfeq,icftm,icetem,mcreep,jcreep,icpa,icftmp,icfstr,icfqcp,icfcpm,icrppr,icrcha,icpb,iicpmt,iicpa +common/marc_creeps2/time_beg_lcase,time_beg_inc,fractol,time_beg_pst,fraction_donn,timinc_ol2 +! +! cptim Total time at begining of increment. +! timinc Incremental time for this step. +! icfte Local copy number of slopes of creep strain rate function +! versus temperature. Is -1 if exponent law used. +! icfst Local copy number of slopes of creep strain rate function +! versus equivalent stress. Is -1 if exponent law used. +! icfeq Local copy number of slopes of creep strain rate function +! versus equivalent strain. Is -1 if exponent law used. +! icftm Local copy number of slopes of creep strain rate function +! versus time. Is -1 if exponent law used. +! icetem Element number that needs to be checked for creep convergence +! or, if negative, the number of elements that need to +! be checked. In the latter case the elements to check +! are stored in ielcp. +! mcreep Maximum nuber of iterations for explicit creep. +! jcreep Counter of number of iterations for explicit creep +! procedure. jcreep must be .le. mcreep +! icpa(1-6) Pointer to constants in creep strain rate expression. +! icftmp Pointer to temperature dependent creep strain rate data. +! icfstr Pointer to equivalent stress dependent creep strain rate data. +! icfqcp Pointer to equivalent creep strain dependent creep strain +! rate data. +! icfcpm Pointer to equivalent creep strain rate dependent +! creep strain rate data. +! icrppr Permanent copy of icreep +! icrcha Control flag for creep convergence checking , if set to +! 1 then testing on absolute change in stress and creep +! strain, not relative testing. Input data. +! icpb(1-4) Pointer to storage of material id cross reference numbers. +! iicpmt creep law type ID +! =1 - power law +! =2 - solder +! =3 - steady-creep +! =4 - hyperbolic steady-creep +! iicpa Pointer to table IDs for constants in creep strain rate +! expression +! +! +! time_beg_lcase time at the beginning of the current load case +! time_beg_inc time at the beginning of the current increment +! fractol fraction of loadcase or increment time when we +! consider it to be finished +! time_beg_pst time corresponding to first increment to be +! read in from thermal post file for auto step +! +! timinc_old Time step of the previous increment +! +!*********************************************************************** +!!$omp threadprivate(/marc_creeps/) +!!$omp threadprivate(/marc_creeps2/) +!! From 70248c44cb607045f314fa26219ff1fdf84c23c5 Mon Sep 17 00:00:00 2001 From: Test User Date: Thu, 17 Nov 2022 15:39:53 +0100 Subject: [PATCH 15/60] [skip ci] updated version information after successful test of v3.0.0-alpha7-97-g41226b195 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index ba869259d..7051e1ee6 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.0.0-alpha7-94-g5d656d9c7 +3.0.0-alpha7-97-g41226b195 From 87579dff11bdf79ee7b0da6d821d8fdbf54bcccd Mon Sep 17 00:00:00 2001 From: Philip Eisenlohr Date: Thu, 17 Nov 2022 18:39:32 -0500 Subject: [PATCH 16/60] extensive style polish; no functional changes --- python/damask/_rotation.py | 405 ++++++++++++++++++------------------- 1 file changed, 193 insertions(+), 212 deletions(-) diff --git a/python/damask/_rotation.py b/python/damask/_rotation.py index 2f9677c89..204a735ad 100644 --- a/python/damask/_rotation.py +++ b/python/damask/_rotation.py @@ -66,7 +66,7 @@ class Rotation: __slots__ = ['quaternion'] def __init__(self, - rotation: Union[FloatSequence, 'Rotation'] = np.array([1.0,0.0,0.0,0.0])): + rotation: Union[FloatSequence, 'Rotation'] = np.array([1.,0.,0.,0.])): """ New rotation. @@ -82,7 +82,7 @@ class Rotation: if isinstance(rotation,Rotation): self.quaternion = rotation.quaternion.copy() elif np.array(rotation).shape[-1] == 4: - self.quaternion = np.array(rotation) + self.quaternion = np.array(rotation,dtype=float) else: raise TypeError('"rotation" is neither a Rotation nor a quaternion') @@ -140,8 +140,8 @@ class Rotation: """ return NotImplemented if not isinstance(other, Rotation) else \ - np.logical_or(np.all(self.quaternion == other.quaternion,axis=-1), - np.all(self.quaternion == -1.0*other.quaternion,axis=-1)) + np.logical_or(np.all(self.quaternion == other.quaternion,axis=-1), + np.all(self.quaternion == -1.*other.quaternion,axis=-1)) def __ne__(self, @@ -161,8 +161,8 @@ class Rotation: def isclose(self: MyType, other: MyType, - rtol: float = 1e-5, - atol: float = 1e-8, + rtol: float = 1.e-5, + atol: float = 1.e-8, equal_nan: bool = True) -> bool: """ Report where values are approximately equal to corresponding ones of other Rotation. @@ -186,14 +186,14 @@ class Rotation: """ s = self.quaternion o = other.quaternion - return np.logical_or(np.all(np.isclose(s, o,rtol,atol,equal_nan),axis=-1), - np.all(np.isclose(s,-1.0*o,rtol,atol,equal_nan),axis=-1)) + return np.logical_or(np.all(np.isclose(s, o,rtol,atol,equal_nan),axis=-1), + np.all(np.isclose(s,-1.*o,rtol,atol,equal_nan),axis=-1)) def allclose(self: MyType, other: MyType, - rtol: float = 1e-5, - atol: float = 1e-8, + rtol: float = 1.e-5, + atol: float = 1.e-8, equal_nan: bool = True) -> Union[np.bool_, bool]: """ Test whether all values are approximately equal to corresponding ones of other Rotation. @@ -250,7 +250,7 @@ class Rotation: """ dup = self.copy() - dup.quaternion[...,1:] *= -1 + dup.quaternion[...,1:] *= -1. return dup @@ -393,9 +393,9 @@ class Rotation: if self.shape + (3,) == other.shape: q_m = self.quaternion[...,0] p_m = self.quaternion[...,1:] - A = q_m**2.0 - np.einsum('...i,...i',p_m,p_m) - B = 2.0 * np.einsum('...i,...i',p_m,other) - C = 2.0 * _P * q_m + A = q_m**2 - np.einsum('...i,...i',p_m,p_m) + B = 2. * np.einsum('...i,...i',p_m,other) + C = 2. * _P * q_m return np.block([(A * other[...,i]).reshape(self.shape+(1,)) + (B * p_m[...,i]).reshape(self.shape+(1,)) + (C * ( p_m[...,(i+1)%3]*other[...,(i+2)%3]\ @@ -419,7 +419,7 @@ class Rotation: def _standardize(self: MyType) -> MyType: """Standardize quaternion (ensure positive real hemisphere).""" - self.quaternion[self.quaternion[...,0] < 0.0] *= -1 + self.quaternion[self.quaternion[...,0] < 0.] *= -1. return self @@ -510,7 +510,7 @@ class Rotation: """ shape_ = (shape,) if isinstance(shape,(int,np.integer)) else tuple(shape) return self.copy(np.broadcast_to(self.quaternion.reshape(util.shapeshifter(self.shape,shape_,mode)+(4,)), - shape_+(4,))) + shape_+(4,))) def average(self: MyType, @@ -540,7 +540,7 @@ class Rotation: weights_ = np.ones(self.shape,dtype=float) if weights is None else np.array(weights,float) - eig, vec = np.linalg.eig(np.sum(_M(self.quaternion) * weights_[...,np.newaxis,np.newaxis],axis=-3) \ + eig, vec = np.linalg.eig(np.sum(_M(self.quaternion) * weights_[...,np.newaxis,np.newaxis],axis=-3) /np.sum( weights_[...,np.newaxis,np.newaxis],axis=-3)) return self.copy(Rotation.from_quaternion(np.real( @@ -770,20 +770,18 @@ class Rotation: """ qu = np.array(q,dtype=float) - if qu.shape[:-2:-1] != (4,): - raise ValueError('invalid shape') - if abs(P) != 1: - raise ValueError('P ∉ {-1,1}') + if qu.shape[:-2:-1] != (4,): raise ValueError('invalid shape') + if abs(P) != 1: raise ValueError('P ∉ {-1,1}') qu[...,1:4] *= -P if accept_homomorph: - qu[qu[...,0] < 0.0] *= -1 - elif np.any(qu[...,0] < 0.0): + qu[qu[...,0]<0.] *= -1. + elif np.any(qu[...,0] < 0.): raise ValueError('quaternion with negative first (real) component') if normalize: qu /= np.linalg.norm(qu,axis=-1,keepdims=True) - elif not np.all(np.isclose(np.linalg.norm(qu,axis=-1), 1.0,rtol=1e-8)): + elif not np.allclose(np.linalg.norm(qu,axis=-1),1.,rtol=1.e-8): raise ValueError('quaternion is not of unit length') return Rotation(qu) @@ -808,11 +806,10 @@ class Rotation: """ eu = np.array(phi,dtype=float) - if eu.shape[:-2:-1] != (3,): - raise ValueError('invalid shape') + if eu.shape[:-2:-1] != (3,): raise ValueError('invalid shape') eu = np.radians(eu) if degrees else eu - if np.any(eu < 0.0) or np.any(eu > 2.0*np.pi) or np.any(eu[...,1] > np.pi): # ToDo: No separate check for PHI + if np.any(eu < 0.) or np.any(eu > np.pi*np.array([2.,1.,2.])): raise ValueError('Euler angles outside of [0..2π],[0..π],[0..2π]') return Rotation(Rotation._eu2qu(eu)) @@ -839,18 +836,17 @@ class Rotation: """ ax = np.array(axis_angle,dtype=float) - if ax.shape[:-2:-1] != (4,): - raise ValueError('invalid shape') - if abs(P) != 1: - raise ValueError('P ∉ {-1,1}') + if ax.shape[:-2:-1] != (4,): raise ValueError('invalid shape') + if abs(P) != 1: raise ValueError('P ∉ {-1,1}') ax[...,0:3] *= -P - if degrees: ax[..., 3] = np.radians(ax[...,3]) - if normalize: ax[...,0:3] /= np.linalg.norm(ax[...,0:3],axis=-1,keepdims=True) - if np.any(ax[...,3] < 0.0) or np.any(ax[...,3] > np.pi): + if degrees: ax[..., 3] = np.radians(ax[...,3]) + if np.any(ax[...,3] < 0.) or np.any(ax[...,3] > np.pi): raise ValueError('axis–angle rotation angle outside of [0..π]') - if not np.all(np.isclose(np.linalg.norm(ax[...,0:3],axis=-1), 1.0)): - print(np.linalg.norm(ax[...,0:3],axis=-1)) + + if normalize: + ax[...,0:3] /= np.linalg.norm(ax[...,0:3],axis=-1,keepdims=True) + elif not np.allclose(np.linalg.norm(ax[...,0:3],axis=-1),1.): raise ValueError('axis–angle rotation axis is not of unit length') return Rotation(Rotation._ax2qu(ax)) @@ -873,22 +869,23 @@ class Rotation: """ om = np.array(basis,dtype=float) - if om.shape[-2:] != (3,3): - raise ValueError('invalid shape') + if om.shape[-2:] != (3,3): raise ValueError('invalid shape') if reciprocal: om = np.linalg.inv(tensor.transpose(om)/np.pi) # transform reciprocal basis set orthonormal = False # contains stretch + if not orthonormal: (U,S,Vh) = np.linalg.svd(om) # singular value decomposition om = np.einsum('...ij,...jl',U,Vh) - if not np.all(np.isclose(np.linalg.det(om),1.0)): - raise ValueError('orientation matrix has determinant ≠ 1') - if not np.all(np.isclose(np.einsum('...i,...i',om[...,0],om[...,1]), 0.0)) \ - or not np.all(np.isclose(np.einsum('...i,...i',om[...,1],om[...,2]), 0.0)) \ - or not np.all(np.isclose(np.einsum('...i,...i',om[...,2],om[...,0]), 0.0)): + elif not np.allclose(np.einsum('...i,...i',om[...,0],om[...,1]),0.) \ + or not np.allclose(np.einsum('...i,...i',om[...,1],om[...,2]),0.) \ + or not np.allclose(np.einsum('...i,...i',om[...,2],om[...,0]),0.): raise ValueError('orientation matrix is not orthogonal') + if not np.allclose(np.linalg.det(om),1.): + raise ValueError('orientation matrix has determinant ≠ 1') + return Rotation(Rotation._om2qu(om)) @staticmethod @@ -918,8 +915,8 @@ class Rotation: Corresponding three-dimensional vectors of second basis. """ - a_ = np.array(a) - b_ = np.array(b) + a_ = np.array(a,dtype=float) + b_ = np.array(b,dtype=float) if a_.shape[-2:] != (2,3) or b_.shape[-2:] != (2,3) or a_.shape != b_.shape: raise ValueError('invalid shape') am = np.stack([ a_[...,0,:], @@ -951,16 +948,15 @@ class Rotation: """ ro = np.array(rho,dtype=float) - if ro.shape[:-2:-1] != (4,): - raise ValueError('invalid shape') - if abs(P) != 1: - raise ValueError('P ∉ {-1,1}') + if ro.shape[:-2:-1] != (4,): raise ValueError('invalid shape') + if abs(P) != 1: raise ValueError('P ∉ {-1,1}') ro[...,0:3] *= -P - if normalize: ro[...,0:3] /= np.linalg.norm(ro[...,0:3],axis=-1,keepdims=True) - if np.any(ro[...,3] < 0.0): - raise ValueError('Rodrigues vector rotation angle is negative') - if not np.all(np.isclose(np.linalg.norm(ro[...,0:3],axis=-1), 1.0)): + if np.any(ro[...,3] < 0.): raise ValueError('Rodrigues vector rotation angle is negative') + + if normalize: + ro[...,0:3] /= np.linalg.norm(ro[...,0:3],axis=-1,keepdims=True) + elif not np.allclose(np.linalg.norm(ro[...,0:3],axis=-1),1.): raise ValueError('Rodrigues vector rotation axis is not of unit length') return Rotation(Rotation._ro2qu(ro)) @@ -980,14 +976,12 @@ class Rotation: """ ho = np.array(h,dtype=float) - if ho.shape[:-2:-1] != (3,): - raise ValueError('invalid shape') - if abs(P) != 1: - raise ValueError('P ∉ {-1,1}') + if ho.shape[:-2:-1] != (3,): raise ValueError('invalid shape') + if abs(P) != 1: raise ValueError('P ∉ {-1,1}') ho *= -P - if np.any(np.linalg.norm(ho,axis=-1) >_R1+1e-9): + if np.any(np.linalg.norm(ho,axis=-1) > _R1+1.e-9): raise ValueError('homochoric coordinate outside of the sphere') return Rotation(Rotation._ho2qu(ho)) @@ -1007,12 +1001,9 @@ class Rotation: """ cu = np.array(x,dtype=float) - if cu.shape[:-2:-1] != (3,): - raise ValueError('invalid shape') - if abs(P) != 1: - raise ValueError('P ∉ {-1,1}') - - if np.abs(np.max(cu)) > np.pi**(2./3.) * 0.5+1e-9: + if cu.shape[:-2:-1] != (3,): raise ValueError('invalid shape') + if abs(P) != 1: raise ValueError('P ∉ {-1,1}') + if np.abs(np.max(cu)) > np.pi**(2./3.) * 0.5+1.e-9: raise ValueError('cubochoric coordinate outside of the cube') ho = -P * Rotation._cu2ho(cu) @@ -1039,11 +1030,11 @@ class Rotation: r = rng.random(3 if shape is None else tuple(shape)+(3,) if hasattr(shape, '__iter__') else (shape,3)) # type: ignore A = np.sqrt(r[...,2]) - B = np.sqrt(1.0-r[...,2]) - q = np.stack([np.cos(2.0*np.pi*r[...,0])*A, - np.sin(2.0*np.pi*r[...,1])*B, - np.cos(2.0*np.pi*r[...,1])*B, - np.sin(2.0*np.pi*r[...,0])*A],axis=-1) + B = np.sqrt(1.-r[...,2]) + q = np.stack([np.cos(2.*np.pi*r[...,0])*A, + np.sin(2.*np.pi*r[...,1])*B, + np.cos(2.*np.pi*r[...,1])*B, + np.sin(2.*np.pi*r[...,0])*A],axis=-1) return Rotation(q if shape is None else q.reshape(r.shape[:-1]+(4,)))._standardize() @@ -1092,10 +1083,10 @@ class Rotation: phi_sorted = eu[np.lexsort((eu[:,0],eu[:,1],eu[:,2]))] steps,size,_ = grid_filters.cellsSizeOrigin_coordinates0_point(phi_sorted) delta = np.radians(size/steps) if deg else size/steps - return delta[0]*2.0*np.sin(delta[1]/2.0)*delta[2] / 8.0 / np.pi**2 * np.sin(np.radians(eu[:,1]) if deg else eu[:,1]) + return delta[0]*2.*np.sin(delta[1]/2.)*delta[2] / 8. / np.pi**2 * np.sin(np.radians(eu[:,1]) if deg else eu[:,1]) - dg = 1.0 if fractions else _dg(phi,degrees) - dV_V = dg * np.maximum(0.0,weights.squeeze()) + dg = 1. if fractions else _dg(phi,degrees) + dV_V = dg * np.maximum(0.,weights.squeeze()) N = 1 if shape is None else np.prod(shape) return Rotation.from_Euler_angles(phi[util.hybrid_IA(dV_V,N,rng_seed)],degrees).reshape(() if shape is None else shape) @@ -1130,24 +1121,24 @@ class Rotation: 200 orientations: >>> import damask - >>> center = damask.Rotation.from_Euler_angles([35.0,45.0,0.0],degrees=True) - >>> brass = damask.Rotation.from_spherical_component(center=center,sigma=3.0,shape=200,degrees=True) + >>> center = damask.Rotation.from_Euler_angles([35.,45.,0.],degrees=True) + >>> brass = damask.Rotation.from_spherical_component(center=center,sigma=3.,shape=200,degrees=True) Create a Goss texture consisting of 100 orientations: >>> import damask - >>> center = damask.Rotation.from_Euler_angles([0.0,45.0,0.0],degrees=True) - >>> goss = damask.Rotation.from_spherical_component(center=center,sigma=3.0,shape=100,degrees=True) + >>> center = damask.Rotation.from_Euler_angles([0.,45.,0.],degrees=True) + >>> goss = damask.Rotation.from_spherical_component(center=center,sigma=3.,shape=100,degrees=True) """ rng = np.random.default_rng(rng_seed) sigma = np.radians(sigma) if degrees else sigma N = 1 if shape is None else np.prod(shape) - u,Theta = (rng.random((N,2)) * 2.0 * np.array([1,np.pi]) - np.array([1.0, 0])).T + u,Theta = (rng.random((N,2)) * 2. * np.array([1.,np.pi]) - np.array([1.,0.])).T omega = abs(rng.normal(scale=sigma,size=N)) - p = np.column_stack([np.sqrt(1-u**2)*np.cos(Theta), - np.sqrt(1-u**2)*np.sin(Theta), + p = np.column_stack([np.sqrt(1.-u**2)*np.cos(Theta), + np.sqrt(1.-u**2)*np.sin(Theta), u, omega]) return Rotation.from_axis_angle(p).reshape(() if shape is None else shape) * center @@ -1156,7 +1147,7 @@ class Rotation: @staticmethod def from_fiber_component(crystal: IntSequence, sample: IntSequence, - sigma: float = 0.0, + sigma: float = 0., shape: Union[int, IntSequence] = None, degrees: bool = False, rng_seed: NumpyRngSeed = None): @@ -1206,7 +1197,7 @@ class Rotation: 100 orientations: >>> import damask - >>> gamma = damask.Rotation.from_fiber_component([54.7,45.0],[0.,0.],shape=100,degrees=True) + >>> gamma = damask.Rotation.from_fiber_component([54.7,45.],[0.,0.],shape=100,degrees=True) """ rng = np.random.default_rng(rng_seed) @@ -1216,18 +1207,18 @@ class Rotation: d_cr = np.array([np.sin(alpha[0])*np.cos(alpha[1]), np.sin(alpha[0])*np.sin(alpha[1]), np.cos(alpha[0])]) d_lab = np.array([np.sin( beta[0])*np.cos( beta[1]), np.sin( beta[0])*np.sin( beta[1]), np.cos( beta[0])]) ax_align = np.append(np.cross(d_lab,d_cr), np.arccos(np.dot(d_lab,d_cr))) - if np.isclose(ax_align[3],0.0): ax_align[:3] = np.array([1,0,0]) - R_align = Rotation.from_axis_angle(ax_align if ax_align[3] > 0.0 else -ax_align,normalize=True) # rotate fiber axis from sample to crystal frame + if np.isclose(ax_align[3],0.): ax_align[:3] = np.array([1.,0.,0.]) + R_align = Rotation.from_axis_angle(ax_align if ax_align[3] > 0. else -ax_align,normalize=True) # rotate fiber axis from sample to crystal frame N = 1 if shape is None else np.prod(shape) - u,Theta = (rng.random((N,2)) * 2.0 * np.array([1,np.pi]) - np.array([1.0, 0])).T + u,Theta = (rng.random((N,2)) * 2. * np.array([1.,np.pi]) - np.array([1.,0.])).T omega = abs(rng.normal(scale=sigma_,size=N)) p = np.column_stack([np.sqrt(1-u**2)*np.cos(Theta), np.sqrt(1-u**2)*np.sin(Theta), u, omega]) p[:,:3] = np.einsum('ij,...j',np.eye(3)-np.outer(d_lab,d_lab),p[:,:3]) # remove component along fiber axis f = np.column_stack((np.broadcast_to(d_lab,(N,3)),rng.random(N)*np.pi)) - f[::2,:3] *= -1 # flip half the rotation axes to negative sense + f[::2,:3] *= -1. # flip half the rotation axes to negative sense return (R_align.broadcast_to(N) * Rotation.from_axis_angle(p,normalize=True) @@ -1268,15 +1259,15 @@ class Rotation: @staticmethod def _qu2om(qu: np.ndarray) -> np.ndarray: qq = qu[...,0:1]**2-(qu[...,1:2]**2 + qu[...,2:3]**2 + qu[...,3:4]**2) - om = np.block([qq + 2.0*qu[...,1:2]**2, - 2.0*(qu[...,2:3]*qu[...,1:2]-_P*qu[...,0:1]*qu[...,3:4]), - 2.0*(qu[...,3:4]*qu[...,1:2]+_P*qu[...,0:1]*qu[...,2:3]), - 2.0*(qu[...,1:2]*qu[...,2:3]+_P*qu[...,0:1]*qu[...,3:4]), - qq + 2.0*qu[...,2:3]**2, - 2.0*(qu[...,3:4]*qu[...,2:3]-_P*qu[...,0:1]*qu[...,1:2]), - 2.0*(qu[...,1:2]*qu[...,3:4]-_P*qu[...,0:1]*qu[...,2:3]), - 2.0*(qu[...,2:3]*qu[...,3:4]+_P*qu[...,0:1]*qu[...,1:2]), - qq + 2.0*qu[...,3:4]**2, + om = np.block([qq + 2.*qu[...,1:2]**2, + 2.*(qu[...,2:3]*qu[...,1:2]-_P*qu[...,0:1]*qu[...,3:4]), + 2.*(qu[...,3:4]*qu[...,1:2]+_P*qu[...,0:1]*qu[...,2:3]), + 2.*(qu[...,1:2]*qu[...,2:3]+_P*qu[...,0:1]*qu[...,3:4]), + qq + 2.*qu[...,2:3]**2, + 2.*(qu[...,3:4]*qu[...,2:3]-_P*qu[...,0:1]*qu[...,1:2]), + 2.*(qu[...,1:2]*qu[...,3:4]-_P*qu[...,0:1]*qu[...,2:3]), + 2.*(qu[...,2:3]*qu[...,3:4]+_P*qu[...,0:1]*qu[...,1:2]), + qq + 2.*qu[...,3:4]**2, ]).reshape(qu.shape[:-1]+(3,3)) return om @@ -1291,22 +1282,20 @@ class Rotation: q12_s = qu[...,1:2]**2+qu[...,2:3]**2 chi = np.sqrt(q03_s*q12_s) - eu = np.where(np.abs(q12_s) < 1.0e-8, - np.block([np.arctan2(-_P*2.0*qu[...,0:1]*qu[...,3:4],qu[...,0:1]**2-qu[...,3:4]**2), + eu = np.where(np.abs(q12_s) < 1.e-8, + np.block([np.arctan2(-_P*2.*qu[...,0:1]*qu[...,3:4],qu[...,0:1]**2-qu[...,3:4]**2), np.zeros(qu.shape[:-1]+(2,))]), - np.where(np.abs(q03_s) < 1.0e-8, - np.block([np.arctan2( 2.0*qu[...,1:2]*qu[...,2:3],qu[...,1:2]**2-qu[...,2:3]**2), + np.where(np.abs(q03_s) < 1.e-8, + np.block([np.arctan2( 2.*qu[...,1:2]*qu[...,2:3],qu[...,1:2]**2-qu[...,2:3]**2), np.broadcast_to(np.pi,qu[...,0:1].shape), np.zeros(qu.shape[:-1]+(1,))]), np.block([np.arctan2((-_P*q02+q13)*chi, (-_P*q01-q23)*chi), - np.arctan2( 2.0*chi, q03_s-q12_s ), + np.arctan2( 2.*chi, q03_s-q12_s ), np.arctan2(( _P*q02+q13)*chi, (-_P*q01+q23)*chi)]) ) ) - # reduce Euler angles to definition range - eu[np.abs(eu)<1.e-6] = 0.0 - eu = np.where(eu<0, (eu+2.0*np.pi)%np.array([2.0*np.pi,np.pi,2.0*np.pi]),eu) # needed? - return eu + eu[np.abs(eu) < 1.e-6] = 0. + return np.where(eu < 0., eu%(np.pi*np.array([2.,1.,2.])),eu) @staticmethod def _qu2ax(qu: np.ndarray) -> np.ndarray: @@ -1317,11 +1306,11 @@ class Rotation: """ with np.errstate(invalid='ignore',divide='ignore'): s = np.sign(qu[...,0:1])/np.sqrt(qu[...,1:2]**2+qu[...,2:3]**2+qu[...,3:4]**2) - omega = 2.0 * np.arccos(np.clip(qu[...,0:1],-1.0,1.0)) - ax = np.where(np.broadcast_to(qu[...,0:1] < 1.0e-8,qu.shape), + omega = 2. * np.arccos(np.clip(qu[...,0:1],-1.,1.)) + ax = np.where(np.broadcast_to(qu[...,0:1] < 1.e-8,qu.shape), np.block([qu[...,1:4],np.broadcast_to(np.pi,qu[...,0:1].shape)]), np.block([qu[...,1:4]*s,omega])) - ax[np.isclose(qu[...,0],1.,rtol=0.0)] = [0.0, 0.0, 1.0, 0.0] + ax[np.isclose(qu[...,0],1.,rtol=0.)] = np.array([0.,0.,1.,0.]) return ax @staticmethod @@ -1329,23 +1318,23 @@ class Rotation: """Quaternion to Rodrigues–Frank vector.""" with np.errstate(invalid='ignore',divide='ignore'): s = np.linalg.norm(qu[...,1:4],axis=-1,keepdims=True) - ro = np.where(np.broadcast_to(np.abs(qu[...,0:1]) < 1.0e-12,qu.shape), + ro = np.where(np.broadcast_to(np.abs(qu[...,0:1]) < 1.e-12,qu.shape), np.block([qu[...,1:2], qu[...,2:3], qu[...,3:4], np.broadcast_to(np.inf,qu[...,0:1].shape)]), np.block([qu[...,1:2]/s,qu[...,2:3]/s,qu[...,3:4]/s, - np.tan(np.arccos(np.clip(qu[...,0:1],-1.0,1.0))) + np.tan(np.arccos(np.clip(qu[...,0:1],-1.,1.))) ]) ) - ro[np.abs(s).squeeze(-1) < 1.0e-12] = [0.0,0.0,_P,0.0] + ro[np.abs(s).squeeze(-1) < 1.e-12] = np.array([0.,0.,_P,0.]) return ro @staticmethod def _qu2ho(qu: np.ndarray) -> np.ndarray: """Quaternion to homochoric vector.""" with np.errstate(invalid='ignore'): - omega = 2.0 * np.arccos(np.clip(qu[...,0:1],-1.0,1.0)) - ho = np.where(np.abs(omega) < 1.0e-12, + omega = 2. * np.arccos(np.clip(qu[...,0:1],-1.,1.)) + ho = np.where(np.abs(omega) < 1.e-12, np.zeros(3), - qu[...,1:4]/np.linalg.norm(qu[...,1:4],axis=-1,keepdims=True) \ + qu[...,1:4]/np.linalg.norm(qu[...,1:4],axis=-1,keepdims=True) * (0.75*(omega - np.sin(omega)))**(1./3.)) return ho @@ -1364,46 +1353,46 @@ class Rotation: This formulation is from www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion. The original formulation had issues. """ - trace = om[...,0,0:1]+om[...,1,1:2]+om[...,2,2:3] + trace = om[...,0,0:1] + om[...,1,1:2] + om[...,2,2:3] with np.errstate(invalid='ignore',divide='ignore'): - s = [ - 0.5 / np.sqrt( 1.0 + trace), - 2.0 * np.sqrt( 1.0 + om[...,0,0:1] - om[...,1,1:2] - om[...,2,2:3]), - 2.0 * np.sqrt( 1.0 + om[...,1,1:2] - om[...,2,2:3] - om[...,0,0:1]), - 2.0 * np.sqrt( 1.0 + om[...,2,2:3] - om[...,0,0:1] - om[...,1,1:2] ) - ] - qu= np.where(trace>0, - np.block([0.25 / s[0], - (om[...,2,1:2] - om[...,1,2:3] ) * s[0], - (om[...,0,2:3] - om[...,2,0:1] ) * s[0], - (om[...,1,0:1] - om[...,0,1:2] ) * s[0]]), - np.where(om[...,0,0:1] > np.maximum(om[...,1,1:2],om[...,2,2:3]), - np.block([(om[...,2,1:2] - om[...,1,2:3]) / s[1], - 0.25 * s[1], - (om[...,0,1:2] + om[...,1,0:1]) / s[1], - (om[...,0,2:3] + om[...,2,0:1]) / s[1]]), - np.where(om[...,1,1:2] > om[...,2,2:3], - np.block([(om[...,0,2:3] - om[...,2,0:1]) / s[2], - (om[...,0,1:2] + om[...,1,0:1]) / s[2], - 0.25 * s[2], - (om[...,1,2:3] + om[...,2,1:2]) / s[2]]), - np.block([(om[...,1,0:1] - om[...,0,1:2]) / s[3], - (om[...,0,2:3] + om[...,2,0:1]) / s[3], - (om[...,1,2:3] + om[...,2,1:2]) / s[3], - 0.25 * s[3]]), - ) - ) - )*np.array([1,_P,_P,_P]) - qu[qu[...,0]<0] *=-1 + s = np.array([ + 0.5 / np.sqrt( 1. + trace), + 2. * np.sqrt( 1. + om[...,0,0:1] - om[...,1,1:2] - om[...,2,2:3]), + 2. * np.sqrt( 1. + om[...,1,1:2] - om[...,2,2:3] - om[...,0,0:1]), + 2. * np.sqrt( 1. + om[...,2,2:3] - om[...,0,0:1] - om[...,1,1:2] ) + ]) + qu = np.where(trace>0, + np.block([0.25 / s[0], + (om[...,2,1:2] - om[...,1,2:3] ) * s[0], + (om[...,0,2:3] - om[...,2,0:1] ) * s[0], + (om[...,1,0:1] - om[...,0,1:2] ) * s[0]]), + np.where(om[...,0,0:1] > np.maximum(om[...,1,1:2],om[...,2,2:3]), + np.block([(om[...,2,1:2] - om[...,1,2:3]) / s[1], + 0.25 * s[1], + (om[...,0,1:2] + om[...,1,0:1]) / s[1], + (om[...,0,2:3] + om[...,2,0:1]) / s[1]]), + np.where(om[...,1,1:2] > om[...,2,2:3], + np.block([(om[...,0,2:3] - om[...,2,0:1]) / s[2], + (om[...,0,1:2] + om[...,1,0:1]) / s[2], + 0.25 * s[2], + (om[...,1,2:3] + om[...,2,1:2]) / s[2]]), + np.block([(om[...,1,0:1] - om[...,0,1:2]) / s[3], + (om[...,0,2:3] + om[...,2,0:1]) / s[3], + (om[...,1,2:3] + om[...,2,1:2]) / s[3], + 0.25 * s[3]]), + ) + ) + )*np.array([1.,_P,_P,_P]) + qu[qu[...,0] < 0.] *= -1. return qu @staticmethod def _om2eu(om: np.ndarray) -> np.ndarray: """Rotation matrix to Bunge Euler angles.""" with np.errstate(invalid='ignore',divide='ignore'): - zeta = 1.0/np.sqrt(1.0-om[...,2,2:3]**2) - eu = np.where(np.isclose(np.abs(om[...,2,2:3]),1.0,0.0), + zeta = 1./np.sqrt(1.-om[...,2,2:3]**2) + eu = np.where(np.isclose(np.abs(om[...,2,2:3]),1.,0.), np.block([np.arctan2(om[...,0,1:2],om[...,0,0:1]), np.pi*0.5*(1-om[...,2,2:3]), np.zeros(om.shape[:-2]+(1,)), @@ -1413,9 +1402,8 @@ class Rotation: np.arctan2(om[...,0,2:3]*zeta,+om[...,1,2:3]*zeta) ]) ) - eu[np.abs(eu)<1.e-8] = 0.0 - eu = np.where(eu<0, (eu+2.0*np.pi)%np.array([2.0*np.pi,np.pi,2.0*np.pi]),eu) - return eu + eu[np.abs(eu) < 1.e-8] = 0.0 + return np.where(eu < 0., eu%(np.pi*np.array([2.,1.,2.])),eu) @staticmethod def _om2ax(om: np.ndarray) -> np.ndarray: @@ -1424,18 +1412,18 @@ class Rotation: om[...,2,0:1]-om[...,0,2:3], om[...,0,1:2]-om[...,1,0:1] ]) - t = 0.5*(om.trace(axis2=-2,axis1=-1) -1.0).reshape(om.shape[:-2]+(1,)) + t = 0.5*(om.trace(axis2=-2,axis1=-1) -1.).reshape(om.shape[:-2]+(1,)) w,vr = np.linalg.eig(om) # mask duplicated real eigenvalues - w[np.isclose(w[...,0],1.0+0.0j),1:] = 0. - w[np.isclose(w[...,1],1.0+0.0j),2:] = 0. + w[np.isclose(w[...,0],1.+0.j),1:] = 0. + w[np.isclose(w[...,1],1.+0.j),2:] = 0. vr = np.swapaxes(vr,-1,-2) - ax = np.where(np.abs(diag_delta)<1e-13, - np.real(vr[np.isclose(w,1.0+0.0j)]).reshape(om.shape[:-2]+(3,)), - np.abs(np.real(vr[np.isclose(w,1.0+0.0j)]).reshape(om.shape[:-2]+(3,))) \ + ax = np.where(np.abs(diag_delta)<1.e-13, + np.real(vr[np.isclose(w,1.+0.j)]).reshape(om.shape[:-2]+(3,)), + np.abs(np.real(vr[np.isclose(w,1.+0.j)]).reshape(om.shape[:-2]+(3,))) *np.sign(diag_delta)) - ax = np.block([ax,np.arccos(np.clip(t,-1.0,1.0))]) - ax[np.abs(ax[...,3])<1.e-8] = [ 0.0, 0.0, 1.0, 0.0] + ax = np.block([ax,np.arccos(np.clip(t,-1.,1.))]) + ax[np.abs(ax[...,3]) < 1.e-8] = np.array([0.,0.,1.,0.]) return ax @staticmethod @@ -1465,7 +1453,7 @@ class Rotation: -_P*sPhi*np.cos(ee[...,0:1]-ee[...,2:3]), -_P*sPhi*np.sin(ee[...,0:1]-ee[...,2:3]), -_P*cPhi*np.sin(ee[...,0:1]+ee[...,2:3])]) - qu[qu[...,0]<0.0]*=-1 + qu[qu[...,0] < 0.] *= -1. return qu @staticmethod @@ -1483,7 +1471,7 @@ class Rotation: -c[...,0:1]*s[...,1:2], +c[...,1:2] ]).reshape(eu.shape[:-1]+(3,3)) - om[np.abs(om)<1.e-12] = 0.0 + om[np.abs(om) < 1.e-12] = 0. return om @staticmethod @@ -1493,16 +1481,16 @@ class Rotation: sigma = 0.5*(eu[...,0:1]+eu[...,2:3]) delta = 0.5*(eu[...,0:1]-eu[...,2:3]) tau = np.linalg.norm(np.block([t,np.sin(sigma)]),axis=-1,keepdims=True) - alpha = np.where(np.abs(np.cos(sigma))<1.e-12,np.pi,2.0*np.arctan(tau/np.cos(sigma))) + alpha = np.where(np.abs(np.cos(sigma))<1.e-12,np.pi,2.*np.arctan(tau/np.cos(sigma))) with np.errstate(invalid='ignore',divide='ignore'): - ax = np.where(np.broadcast_to(np.abs(alpha)<1.0e-12,eu.shape[:-1]+(4,)), - [0.0,0.0,1.0,0.0], + ax = np.where(np.broadcast_to(np.abs(alpha)<1.e-12,eu.shape[:-1]+(4,)), + [0.,0.,1.,0.], np.block([-_P/tau*t*np.cos(delta), -_P/tau*t*np.sin(delta), -_P/tau* np.sin(sigma), alpha ])) - ax[(alpha<0.0).squeeze()] *=-1 + ax[(alpha<0.).squeeze()] *= -1. return ax @staticmethod @@ -1510,8 +1498,8 @@ class Rotation: """Bunge Euler angles to Rodrigues–Frank vector.""" ax = Rotation._eu2ax(eu) ro = np.block([ax[...,:3],np.tan(ax[...,3:4]*.5)]) - ro[ax[...,3]>=np.pi,3] = np.inf - ro[np.abs(ax[...,3])<1.e-16] = [ 0.0, 0.0, _P, 0.0 ] + ro[ax[...,3] >= np.pi,3] = np.inf + ro[np.abs(ax[...,3])<1.e-16] = np.array([0.,0.,_P,0.]) return ro @staticmethod @@ -1531,7 +1519,7 @@ class Rotation: """Axis–angle pair to quaternion.""" c = np.cos(ax[...,3:4]*.5) s = np.sin(ax[...,3:4]*.5) - qu = np.where(np.abs(ax[...,3:4])<1.e-6,[1.0, 0.0, 0.0, 0.0],np.block([c, ax[...,:3]*s])) + qu = np.where(np.abs(ax[...,3:4]) < 1.e-6,[1.,0.,0.,0.],np.block([c,ax[...,:3]*s])) return qu @staticmethod @@ -1539,17 +1527,17 @@ class Rotation: """Axis-angle pair to rotation matrix.""" c = np.cos(ax[...,3:4]) s = np.sin(ax[...,3:4]) - omc = 1. -c + omc = 1.-c om = np.block([c+omc*ax[...,0:1]**2, - omc*ax[...,0:1]*ax[...,1:2] + s*ax[...,2:3], - omc*ax[...,0:1]*ax[...,2:3] - s*ax[...,1:2], - omc*ax[...,0:1]*ax[...,1:2] - s*ax[...,2:3], + omc*ax[...,0:1]*ax[...,1:2] + s*ax[...,2:3], + omc*ax[...,0:1]*ax[...,2:3] - s*ax[...,1:2], + omc*ax[...,0:1]*ax[...,1:2] - s*ax[...,2:3], c+omc*ax[...,1:2]**2, - omc*ax[...,1:2]*ax[...,2:3] + s*ax[...,0:1], - omc*ax[...,0:1]*ax[...,2:3] + s*ax[...,1:2], - omc*ax[...,1:2]*ax[...,2:3] - s*ax[...,0:1], + omc*ax[...,1:2]*ax[...,2:3] + s*ax[...,0:1], + omc*ax[...,0:1]*ax[...,2:3] + s*ax[...,1:2], + omc*ax[...,1:2]*ax[...,2:3] - s*ax[...,0:1], c+omc*ax[...,2:3]**2]).reshape(ax.shape[:-1]+(3,3)) - return om if _P < 0.0 else np.swapaxes(om,-1,-2) + return om if _P < 0. else np.swapaxes(om,-1,-2) @staticmethod def _ax2eu(ax: np.ndarray) -> np.ndarray: @@ -1564,15 +1552,14 @@ class Rotation: np.inf, np.tan(ax[...,3:4]*0.5)) ]) - ro[np.abs(ax[...,3])<1.e-6] = [.0,.0,_P,.0] + ro[np.abs(ax[...,3]) < 1.e-6] = np.array([.0,.0,_P,.0]) return ro @staticmethod def _ax2ho(ax: np.ndarray) -> np.ndarray: """Axis–angle pair to homochoric vector.""" - f = (0.75 * ( ax[...,3:4] - np.sin(ax[...,3:4]) ))**(1.0/3.0) - ho = ax[...,:3] * f - return ho + f = (0.75 * ( ax[...,3:4] - np.sin(ax[...,3:4]) ))**(1./3.) + return ax[...,:3] * f @staticmethod def _ax2cu(ax: np.ndarray) -> np.ndarray: @@ -1603,16 +1590,15 @@ class Rotation: ax = np.where(np.isfinite(ro[...,3:4]), np.block([ro[...,0:3]*np.linalg.norm(ro[...,0:3],axis=-1,keepdims=True),2.*np.arctan(ro[...,3:4])]), np.block([ro[...,0:3],np.broadcast_to(np.pi,ro[...,3:4].shape)])) - ax[np.abs(ro[...,3]) < 1.e-8] = np.array([ 0.0, 0.0, 1.0, 0.0 ]) + ax[np.abs(ro[...,3]) < 1.e-8] = np.array([0.,0.,1.,0.]) return ax @staticmethod def _ro2ho(ro: np.ndarray) -> np.ndarray: """Rodrigues–Frank vector to homochoric vector.""" - f = np.where(np.isfinite(ro[...,3:4]),2.0*np.arctan(ro[...,3:4]) -np.sin(2.0*np.arctan(ro[...,3:4])),np.pi) - ho = np.where(np.broadcast_to(np.sum(ro[...,0:3]**2.0,axis=-1,keepdims=True) < 1.e-8,ro[...,0:3].shape), - np.zeros(3), ro[...,0:3]* (0.75*f)**(1.0/3.0)) - return ho + f = np.where(np.isfinite(ro[...,3:4]),2.*np.arctan(ro[...,3:4]) -np.sin(2.*np.arctan(ro[...,3:4])),np.pi) + return np.where(np.broadcast_to(np.sum(ro[...,0:3]**2,axis=-1,keepdims=True) < 1.e-8,ro[...,0:3].shape), + np.zeros(3), ro[...,0:3]* (0.75*f)**(1./3.)) @staticmethod def _ro2cu(ro: np.ndarray) -> np.ndarray: @@ -1646,13 +1632,12 @@ class Rotation: +9.528014229335313e-6, -5.660288876265125e-6, +1.2844901692764126e-6, +1.1255185726258763e-6, -1.3834391419956455e-6, +7.513691751164847e-7, -2.401996891720091e-7, +4.386887017466388e-8, -3.5917775353564864e-9]) - hmag_squared = np.sum(ho**2.,axis=-1,keepdims=True) + hmag_squared = np.sum(ho**2,axis=-1,keepdims=True) s = np.sum(tfit*hmag_squared**np.arange(len(tfit)),axis=-1,keepdims=True) with np.errstate(invalid='ignore'): - ax = np.where(np.broadcast_to(np.abs(hmag_squared)<1.e-8,ho.shape[:-1]+(4,)), - [ 0.0, 0.0, 1.0, 0.0 ], - np.block([ho/np.sqrt(hmag_squared),2.0*np.arccos(np.clip(s,-1.0,1.0))])) - return ax + return np.where(np.broadcast_to(np.abs(hmag_squared)<1.e-8,ho.shape[:-1]+(4,)), + [0.,0.,1.,0.], + np.block([ho/np.sqrt(hmag_squared),2.*np.arccos(np.clip(s,-1.,1.))])) @staticmethod def _ho2ro(ho: np.ndarray) -> np.ndarray: @@ -1676,27 +1661,25 @@ class Rotation: with np.errstate(invalid='ignore',divide='ignore'): # inverse M_3 - xyz2 = xyz3[...,0:2] * np.sqrt( 2.0*rs/(rs+np.abs(xyz3[...,2:3])) ) + xyz2 = xyz3[...,0:2] * np.sqrt( 2.*rs/(rs+np.abs(xyz3[...,2:3])) ) qxy = np.sum(xyz2**2,axis=-1,keepdims=True) q2 = qxy + np.max(np.abs(xyz2),axis=-1,keepdims=True)**2 sq2 = np.sqrt(q2) - q = (_beta/np.sqrt(2.0)/_R1) * np.sqrt(q2*qxy/(q2-np.max(np.abs(xyz2),axis=-1,keepdims=True)*sq2)) + q = (_beta/np.sqrt(2.)/_R1) * np.sqrt(q2*qxy/(q2-np.max(np.abs(xyz2),axis=-1,keepdims=True)*sq2)) tt = np.clip((np.min(np.abs(xyz2),axis=-1,keepdims=True)**2\ - +np.max(np.abs(xyz2),axis=-1,keepdims=True)*sq2)/np.sqrt(2.0)/qxy,-1.0,1.0) + +np.max(np.abs(xyz2),axis=-1,keepdims=True)*sq2)/np.sqrt(2.)/qxy,-1.,1.) T_inv = np.where(np.abs(xyz2[...,1:2]) <= np.abs(xyz2[...,0:1]), - np.block([np.ones_like(tt),np.arccos(tt)/np.pi*12.0]), - np.block([np.arccos(tt)/np.pi*12.0,np.ones_like(tt)]))*q - T_inv[xyz2<0.0] *= -1.0 - T_inv[np.broadcast_to(np.isclose(qxy,0.0,rtol=0.0,atol=1.0e-12),T_inv.shape)] = 0.0 - cu = np.block([T_inv, np.where(xyz3[...,2:3]<0.0,-np.ones_like(xyz3[...,2:3]),np.ones_like(xyz3[...,2:3])) \ - * rs/np.sqrt(6.0/np.pi), + np.block([np.ones_like(tt),np.arccos(tt)/np.pi*12.]), + np.block([np.arccos(tt)/np.pi*12.,np.ones_like(tt)]))*q + T_inv[xyz2<0.] *= -1. + T_inv[np.broadcast_to(np.isclose(qxy,0.,rtol=0.,atol=1.e-12),T_inv.shape)] = 0. + cu = np.block([T_inv, np.where(xyz3[...,2:3]<0.,-np.ones_like(xyz3[...,2:3]),np.ones_like(xyz3[...,2:3])) \ + * rs/np.sqrt(6./np.pi), ])/ _sc - cu[np.isclose(np.sum(np.abs(ho),axis=-1),0.0,rtol=0.0,atol=1.0e-16)] = 0.0 - cu = np.take_along_axis(cu,Rotation._get_pyramid_order(ho,'backward'),-1) - - return cu + cu[np.isclose(np.sum(np.abs(ho),axis=-1),0.,rtol=0.,atol=1.e-16)] = 0. + return np.take_along_axis(cu,Rotation._get_pyramid_order(ho,'backward'),-1) #---------- Cubochoric ---------- @staticmethod @@ -1739,32 +1722,30 @@ class Rotation: # get pyramid and scale by grid parameter ratio XYZ = np.take_along_axis(cu,Rotation._get_pyramid_order(cu,'forward'),-1) * _sc order = np.abs(XYZ[...,1:2]) <= np.abs(XYZ[...,0:1]) - q = np.pi/12.0 * np.where(order,XYZ[...,1:2],XYZ[...,0:1]) \ + q = np.pi/12. * np.where(order,XYZ[...,1:2],XYZ[...,0:1]) \ / np.where(order,XYZ[...,0:1],XYZ[...,1:2]) c = np.cos(q) s = np.sin(q) - q = _R1*2.0**0.25/_beta/ np.sqrt(np.sqrt(2.0)-c) \ + q = _R1*2.**0.25/_beta/ np.sqrt(np.sqrt(2.)-c) \ * np.where(order,XYZ[...,0:1],XYZ[...,1:2]) - T = np.block([ (np.sqrt(2.0)*c - 1.0), np.sqrt(2.0) * s]) * q + T = np.block([(np.sqrt(2.)*c - 1.), np.sqrt(2.) * s]) * q # transform to sphere grid (inverse Lambert) c = np.sum(T**2,axis=-1,keepdims=True) - s = c * np.pi/24.0 /XYZ[...,2:3]**2 - c = c * np.sqrt(np.pi/24.0)/XYZ[...,2:3] - q = np.sqrt( 1.0 - s) + s = c * np.pi/24. /XYZ[...,2:3]**2 + c = c * np.sqrt(np.pi/24.)/XYZ[...,2:3] + q = np.sqrt( 1. - s) - ho = np.where(np.isclose(np.sum(np.abs(XYZ[...,0:2]),axis=-1,keepdims=True),0.0,rtol=0.0,atol=1.0e-16), - np.block([np.zeros_like(XYZ[...,0:2]),np.sqrt(6.0/np.pi) *XYZ[...,2:3]]), + ho = np.where(np.isclose(np.sum(np.abs(XYZ[...,0:2]),axis=-1,keepdims=True),0.,rtol=0.,atol=1.e-16), + np.block([np.zeros_like(XYZ[...,0:2]),np.sqrt(6./np.pi)*XYZ[...,2:3]]), np.block([np.where(order,T[...,0:1],T[...,1:2])*q, np.where(order,T[...,1:2],T[...,0:1])*q, - np.sqrt(6.0/np.pi) * XYZ[...,2:3] - c]) + np.sqrt(6./np.pi) * XYZ[...,2:3] - c]) ) - ho[np.isclose(np.sum(np.abs(cu),axis=-1),0.0,rtol=0.0,atol=1.0e-16)] = 0.0 - ho = np.take_along_axis(ho,Rotation._get_pyramid_order(cu,'backward'),-1) - - return ho + ho[np.isclose(np.sum(np.abs(cu),axis=-1),0.,rtol=0.,atol=1.e-16)] = 0. + return np.take_along_axis(ho,Rotation._get_pyramid_order(cu,'backward'),-1) @staticmethod From 4e13a28ecfcec0c78320d455111a586924673fd4 Mon Sep 17 00:00:00 2001 From: Test User Date: Fri, 18 Nov 2022 05:17:34 +0100 Subject: [PATCH 17/60] [skip ci] updated version information after successful test of v3.0.0-alpha7-102-g05974fb30 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 7051e1ee6..0c791f6d8 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.0.0-alpha7-97-g41226b195 +3.0.0-alpha7-102-g05974fb30 From 822a09865935091868a0befe343f4c2abfe3ab16 Mon Sep 17 00:00:00 2001 From: Philip Eisenlohr Date: Fri, 18 Nov 2022 10:06:15 -0500 Subject: [PATCH 18/60] cleaner way to specify default dict entries --- python/damask/_configmaterial.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/python/damask/_configmaterial.py b/python/damask/_configmaterial.py index 6fd671de1..e678dab03 100644 --- a/python/damask/_configmaterial.py +++ b/python/damask/_configmaterial.py @@ -232,9 +232,9 @@ class ConfigMaterial(Config): _,idx = np.unique(np.hstack(list(kwargs_.values())),return_index=True,axis=0) idx = np.sort(idx) - kwargs_ = {k:np.atleast_1d(v[idx].squeeze()) for k,v in kwargs_.items()} - for what in ['phase','homogenization']: - if what not in kwargs_: kwargs_[what]= what+'_label' + kwargs_ = {'phase':'phase_label', + 'homogenization': 'homogenization_label'} \ + | {k:np.atleast_1d(v[idx].squeeze()) for k,v in kwargs_.items()} return ConfigMaterial().material_add(**kwargs_) From d374f6a02c3e434c652ce57e4a38a1840b157534 Mon Sep 17 00:00:00 2001 From: Philip Eisenlohr Date: Fri, 18 Nov 2022 11:01:01 -0500 Subject: [PATCH 19/60] revert, since not working in python3.8... --- python/damask/_configmaterial.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/python/damask/_configmaterial.py b/python/damask/_configmaterial.py index e678dab03..dbf6edf1f 100644 --- a/python/damask/_configmaterial.py +++ b/python/damask/_configmaterial.py @@ -232,9 +232,9 @@ class ConfigMaterial(Config): _,idx = np.unique(np.hstack(list(kwargs_.values())),return_index=True,axis=0) idx = np.sort(idx) - kwargs_ = {'phase':'phase_label', - 'homogenization': 'homogenization_label'} \ - | {k:np.atleast_1d(v[idx].squeeze()) for k,v in kwargs_.items()} + kwargs_ = {k:np.atleast_1d(v[idx].squeeze()) for k,v in kwargs_.items()} + for what in ['phase','homogenization']: + if what not in kwargs_: kwargs_[what] = what+'_label' return ConfigMaterial().material_add(**kwargs_) From dff8a5a7f9ef31f8f3bea2977342866f8b789f17 Mon Sep 17 00:00:00 2001 From: Test User Date: Fri, 18 Nov 2022 17:34:11 +0100 Subject: [PATCH 20/60] [skip ci] updated version information after successful test of v3.0.0-alpha7-108-gd596de7a3 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 0c791f6d8..25f2fc3ba 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.0.0-alpha7-102-g05974fb30 +3.0.0-alpha7-108-gd596de7a3 From 7e5a3a12abdfd6a03427b20f7bde249907f666ce Mon Sep 17 00:00:00 2001 From: Philip Eisenlohr Date: Fri, 18 Nov 2022 16:30:26 -0500 Subject: [PATCH 21/60] proper dealing with default/mandatory items in material_add --- python/damask/_configmaterial.py | 92 +++++++++++++++++++++----------- 1 file changed, 62 insertions(+), 30 deletions(-) diff --git a/python/damask/_configmaterial.py b/python/damask/_configmaterial.py index dbf6edf1f..873577771 100644 --- a/python/damask/_configmaterial.py +++ b/python/damask/_configmaterial.py @@ -424,6 +424,8 @@ class ConfigMaterial(Config): ---------- **kwargs Key-value pairs. + First index of array-like values runs over materials, + whereas second index runs over constituents. Returns ------- @@ -432,12 +434,12 @@ class ConfigMaterial(Config): Examples -------- - Create a dual-phase steel microstructure for micromechanical simulations: + Create two grains of ferrite and one grain of martensite, each with random orientation: >>> import damask >>> m = damask.ConfigMaterial() - >>> m = m.material_add(phase = ['Ferrite','Martensite'], - ... O = damask.Rotation.from_random(2), + >>> m = m.material_add(phase = ['Ferrite','Martensite','Ferrite'], + ... O = damask.Rotation.from_random(3), ... homogenization = 'SX') >>> m material: @@ -451,59 +453,89 @@ class ConfigMaterial(Config): v: 1.0 phase: Martensite homogenization: SX + - constituents: + - O: [0.47925185, -0.04294454, 0.78760173, -0.3849116 ] + v: 1.0 + phase: Ferrite + homogenization: SX homogenization: {SX: null} phase: {Ferrite: null, Martensite: null} - Create a duplex stainless steel microstructure for forming simulations: + Create hundred materials that each approximate a duplex stainless steel microstructure + with three austenite and one relatively bigger ferrite grain of random orientation each: >>> import damask >>> m = damask.ConfigMaterial() - >>> m = m.material_add(phase = np.array(['Austenite','Ferrite']).reshape(1,2), - ... O = damask.Rotation.from_random((2,2)), - ... v = np.array([0.2,0.8]).reshape(1,2), + >>> m = m.material_add(phase = np.array(['Austenite']*3+['Ferrite']), + ... O = damask.Rotation.from_random((100,4)), + ... v = np.array([0.2]*3+[0.4]), ... homogenization = 'Taylor') >>> m material: - constituents: - - phase: Austenite - O: [0.659802978293224, 0.6953785848195171, 0.22426295326327111, -0.17554139512785227] - v: 0.2 - - phase: Ferrite - O: [0.49356745891301596, 0.2841806579193434, -0.7487679215072818, -0.339085707289975] - v: 0.8 + - v: 0.2 + phase: Austenite + O: [0.46183665006602664, 0.2215160420973196, -0.5594313187331139, 0.6516702781083836] + - v: 0.2 + phase: Austenite + O: [0.11321658382410027, 0.6354079414360444, 0.00562701344273936, 0.7638108992590535] + - v: 0.2 + phase: Austenite + O: [0.050991978809077604, 0.8069522034362003, -0.11352928955610851, -0.5773552285027659] + - v: 0.4 + phase: Ferrite + O: [0.9460076150721788, 0.15880754622367604, -0.0069841062241482385, -0.28249066842661014] homogenization: Taylor + . + . + . - constituents: - - phase: Austenite - O: [0.26542221365204055, 0.7268854930702071, 0.4474726435701472, -0.44828201137283735] - v: 0.2 - - phase: Ferrite - O: [0.6545817158479885, -0.08004812803625233, -0.6226561293931374, 0.4212059104577611] - v: 0.8 + - v: 0.2 + phase: Austenite + O: [0.12531400788494199, -0.18637769037997565, 0.31737548053338394, -0.9213210951197429] + - v: 0.2 + phase: Austenite + O: [0.37453930577161404, -0.33529507696450805, -0.3266564259130028, -0.800370601162502] + - v: 0.2 + phase: Austenite + O: [0.035776891752713764, -0.720706371010592, -0.4540438656728926, -0.5226342017569017] + - v: 0.4 + phase: Ferrite + O: [0.6782596727966124, -0.20800082041703685, -0.138636083554039, 0.6909989227925536] homogenization: Taylor + homogenization: {Taylor: null} + phase: {Austenite: null, Ferrite: null} """ - N,n,shaped = 1,1,{} + _constituent_properties = ['phase','O','v','V_e'] + _dim = {'O':(4,),'V_e':(3,3,)} + _ex = dict((k, -len(v)) for k, v in _dim.items()) + + N,n,shaped = 1,1,{'v': None, + 'phase': None, + 'homogenization': None, + } - map_dim = {'O':-1,'V_e':-2} for k,v in kwargs.items(): shaped[k] = np.array(v) - s = shaped[k].shape[:map_dim.get(k,None)] + s = shaped[k].shape[:_ex.get(k,None)] N = max(N,s[0]) if len(s)>0 else N n = max(n,s[1]) if len(s)>1 else n + shaped['v'] = np.array(1./n) if shaped['v'] is None else shaped['v'] + mat: Sequence[dict] = [{'constituents':[{} for _ in range(n)]} for _ in range(N)] - if 'v' not in kwargs: - shaped['v'] = np.broadcast_to(1/n,(N,n)) - - map_shape = {'O':(N,n,4),'V_e':(N,n,3,3)} for k,v in shaped.items(): - target = map_shape.get(k,(N,n)) - obj = np.broadcast_to(v.reshape(util.shapeshifter(v.shape, target, mode = 'right')), target) + target = (N,n) + _dim.get(k,()) + obj = np.broadcast_to(np.array(v).reshape(util.shapeshifter(() if v is None else v.shape, + target, + mode = 'right')), + target) for i in range(N): - if k in ['phase','O','v','V_e']: + if k in _constituent_properties: for j in range(n): mat[i]['constituents'][j][k] = obj[i,j].item() if isinstance(obj[i,j],np.generic) else obj[i,j] else: @@ -514,6 +546,6 @@ class ConfigMaterial(Config): for what in ['phase','homogenization']: for k in np.unique(shaped[what]): - if k not in dup[what]: dup[what][str(k)] = None + if not (k is None or k in dup[what]): dup[what][str(k)] = None return dup From ce98cfdd5eb6d384405480d8988d5a5f757fdf47 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sat, 19 Nov 2022 07:55:22 +0100 Subject: [PATCH 22/60] padding is handled centrally in the FFT forward routines --- src/grid/grid_damage_spectral.f90 | 1 - src/grid/grid_mech_spectral_basic.f90 | 1 - src/grid/grid_mech_spectral_polarisation.f90 | 3 --- src/grid/grid_thermal_spectral.f90 | 1 - 4 files changed, 6 deletions(-) diff --git a/src/grid/grid_damage_spectral.f90 b/src/grid/grid_damage_spectral.f90 index 816cdd4b1..51804d52b 100644 --- a/src/grid/grid_damage_spectral.f90 +++ b/src/grid/grid_damage_spectral.f90 @@ -304,7 +304,6 @@ subroutine formResidual(in,x_scal,r,dummy,err_PETSc) phi_current = x_scal !-------------------------------------------------------------------------------------------------- ! evaluate polarization field - scalarField_real = 0.0_pReal scalarField_real(1:cells(1),1:cells(2),1:cells3) = phi_current call utilities_FFTscalarForward call utilities_fourierScalarGradient !< calculate gradient of damage field diff --git a/src/grid/grid_mech_spectral_basic.f90 b/src/grid/grid_mech_spectral_basic.f90 index bead280a7..ef958d718 100644 --- a/src/grid/grid_mech_spectral_basic.f90 +++ b/src/grid/grid_mech_spectral_basic.f90 @@ -545,7 +545,6 @@ subroutine formResidual(in, F, & !-------------------------------------------------------------------------------------------------- ! updated deformation gradient using fix point algorithm of basic scheme - tensorField_real = 0.0_pReal tensorField_real(1:3,1:3,1:cells(1),1:cells(2),1:cells3) = r ! store fPK field for subsequent FFT forward transform call utilities_FFTtensorForward ! FFT forward of global "tensorField_real" err_div = utilities_divergenceRMS() ! divRMS of tensorField_fourier for later use diff --git a/src/grid/grid_mech_spectral_polarisation.f90 b/src/grid/grid_mech_spectral_polarisation.f90 index 2b4ea364a..c82048d77 100644 --- a/src/grid/grid_mech_spectral_polarisation.f90 +++ b/src/grid/grid_mech_spectral_polarisation.f90 @@ -611,7 +611,6 @@ subroutine formResidual(in, FandF_tau, & !-------------------------------------------------------------------------------------------------- ! - tensorField_real = 0.0_pReal do k = 1, cells3; do j = 1, cells(2); do i = 1, cells(1) tensorField_real(1:3,1:3,i,j,k) = & num%beta*math_mul3333xx33(C_scale,F(1:3,1:3,i,j,k) - math_I3) -& @@ -643,7 +642,6 @@ subroutine formResidual(in, FandF_tau, & P_av-P_aim, & params%stress_mask))) ! calculate divergence - tensorField_real = 0.0_pReal tensorField_real(1:3,1:3,1:cells(1),1:cells(2),1:cells3) = r_F !< stress field in disguise call utilities_FFTtensorForward err_div = utilities_divergenceRMS() !< root mean squared error in divergence of stress @@ -662,7 +660,6 @@ subroutine formResidual(in, FandF_tau, & !-------------------------------------------------------------------------------------------------- ! calculating curl - tensorField_real = 0.0_pReal tensorField_real(1:3,1:3,1:cells(1),1:cells(2),1:cells3) = F call utilities_FFTtensorForward err_curl = utilities_curlRMS() diff --git a/src/grid/grid_thermal_spectral.f90 b/src/grid/grid_thermal_spectral.f90 index 29ae07769..b34717027 100644 --- a/src/grid/grid_thermal_spectral.f90 +++ b/src/grid/grid_thermal_spectral.f90 @@ -326,7 +326,6 @@ subroutine formResidual(in,x_scal,r,dummy,err_PETSc) T_current = x_scal !-------------------------------------------------------------------------------------------------- ! evaluate polarization field - scalarField_real = 0.0_pReal scalarField_real(1:cells(1),1:cells(2),1:cells3) = T_current call utilities_FFTscalarForward call utilities_fourierScalarGradient !< calculate gradient of temperature field From 20da5663c0b233d839c31b34f30a325faeadb955 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sat, 19 Nov 2022 08:14:38 +0100 Subject: [PATCH 23/60] simplified, avoid intermediate writes --- src/grid/grid_damage_spectral.f90 | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/grid/grid_damage_spectral.f90 b/src/grid/grid_damage_spectral.f90 index 51804d52b..fc1defac3 100644 --- a/src/grid/grid_damage_spectral.f90 +++ b/src/grid/grid_damage_spectral.f90 @@ -330,14 +330,10 @@ subroutine formResidual(in,x_scal,r,dummy,err_PETSc) call utilities_fourierGreenConvolution(K_ref, mu_ref, params%Delta_t) call utilities_FFTscalarBackward - where(scalarField_real(1:cells(1),1:cells(2),1:cells3) > phi_lastInc) & - scalarField_real(1:cells(1),1:cells(2),1:cells3) = phi_lastInc - where(scalarField_real(1:cells(1),1:cells(2),1:cells3) < num%residualStiffness) & - scalarField_real(1:cells(1),1:cells(2),1:cells3) = num%residualStiffness - !-------------------------------------------------------------------------------------------------- ! constructing residual - r = scalarField_real(1:cells(1),1:cells(2),1:cells3) - phi_current + r = max(min(scalarField_real(1:cells(1),1:cells(2),1:cells3),phi_lastInc),num%residualStiffness) & + - phi_current err_PETSc = 0 end subroutine formResidual From cd2a21509a3294548d069eb64647a8163a801517 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sat, 19 Nov 2022 08:55:15 +0100 Subject: [PATCH 24/60] avoid depenencies on global state requires on extra forward FFT pre iteration for basic scheme --- src/grid/grid_mech_spectral_basic.f90 | 2 +- src/grid/grid_mech_spectral_polarisation.f90 | 12 ++---------- src/grid/spectral_utilities.f90 | 18 ++++++++++++++---- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/grid/grid_mech_spectral_basic.f90 b/src/grid/grid_mech_spectral_basic.f90 index ef958d718..4dca95e80 100644 --- a/src/grid/grid_mech_spectral_basic.f90 +++ b/src/grid/grid_mech_spectral_basic.f90 @@ -536,6 +536,7 @@ subroutine formResidual(in, F, & F,params%Delta_t,params%rotation_BC) call MPI_Allreduce(MPI_IN_PLACE,terminallyIll,1_MPI_INTEGER_KIND,MPI_LOGICAL,MPI_LOR,MPI_COMM_WORLD,err_MPI) if (err_MPI /= 0_MPI_INTEGER_KIND) error stop 'MPI error' + err_div = utilities_divergenceRMS(r) !-------------------------------------------------------------------------------------------------- ! stress BC handling @@ -547,7 +548,6 @@ subroutine formResidual(in, F, & ! updated deformation gradient using fix point algorithm of basic scheme tensorField_real(1:3,1:3,1:cells(1),1:cells(2),1:cells3) = r ! store fPK field for subsequent FFT forward transform call utilities_FFTtensorForward ! FFT forward of global "tensorField_real" - err_div = utilities_divergenceRMS() ! divRMS of tensorField_fourier for later use call utilities_fourierGammaConvolution(params%rotation_BC%rotate(deltaF_aim,active=.true.)) ! convolution of Gamma and tensorField_fourier call utilities_FFTtensorBackward ! FFT backward of global tensorField_fourier diff --git a/src/grid/grid_mech_spectral_polarisation.f90 b/src/grid/grid_mech_spectral_polarisation.f90 index c82048d77..9c9a83766 100644 --- a/src/grid/grid_mech_spectral_polarisation.f90 +++ b/src/grid/grid_mech_spectral_polarisation.f90 @@ -634,6 +634,8 @@ subroutine formResidual(in, FandF_tau, & P_av,C_volAvg,C_minMaxAvg, & F - r_F_tau/num%beta,params%Delta_t,params%rotation_BC) call MPI_Allreduce(MPI_IN_PLACE,terminallyIll,1_MPI_INTEGER_KIND,MPI_LOGICAL,MPI_LOR,MPI_COMM_WORLD,err_MPI) + err_div = utilities_divergenceRMS(r_F) + err_curl = utilities_curlRMS(F) !-------------------------------------------------------------------------------------------------- ! stress BC handling @@ -641,10 +643,6 @@ subroutine formResidual(in, FandF_tau, & err_BC = maxval(abs(merge(math_mul3333xx33(C_scale,F_aim-params%rotation_BC%rotate(F_av)), & P_av-P_aim, & params%stress_mask))) -! calculate divergence - tensorField_real(1:3,1:3,1:cells(1),1:cells(2),1:cells3) = r_F !< stress field in disguise - call utilities_FFTtensorForward - err_div = utilities_divergenceRMS() !< root mean squared error in divergence of stress !-------------------------------------------------------------------------------------------------- ! constructing residual @@ -658,12 +656,6 @@ subroutine formResidual(in, FandF_tau, & + r_F_tau(1:3,1:3,i,j,k) end do; end do; end do -!-------------------------------------------------------------------------------------------------- -! calculating curl - tensorField_real(1:3,1:3,1:cells(1),1:cells(2),1:cells3) = F - call utilities_FFTtensorForward - err_curl = utilities_curlRMS() - end subroutine formResidual end module grid_mechanical_spectral_polarisation diff --git a/src/grid/spectral_utilities.f90 b/src/grid/spectral_utilities.f90 index 6cb7edd30..db2efbfec 100644 --- a/src/grid/spectral_utilities.f90 +++ b/src/grid/spectral_utilities.f90 @@ -616,9 +616,11 @@ end subroutine utilities_fourierGreenConvolution !-------------------------------------------------------------------------------------------------- -!> @brief calculate root mean square of divergence of field_fourier +!> @brief Calculate root mean square of divergence. !-------------------------------------------------------------------------------------------------- -real(pReal) function utilities_divergenceRMS() +real(pReal) function utilities_divergenceRMS(tensorField) + + real(pReal), dimension(3,3,cells(1),cells(2),cells3), intent(in) :: tensorField integer :: i, j, k integer(MPI_INTEGER_KIND) :: err_MPI @@ -628,6 +630,9 @@ real(pReal) function utilities_divergenceRMS() print'(/,1x,a)', '... calculating divergence ................................................' flush(IO_STDOUT) + tensorField_real(1:3,1:3,1:cells(1),1:cells(2),1:cells3) = tensorField + call utilities_FFTtensorforward() + rescaledGeom = cmplx(geomSize/scaledGeomSize,0.0_pReal,pReal) !-------------------------------------------------------------------------------------------------- @@ -660,9 +665,11 @@ end function utilities_divergenceRMS !-------------------------------------------------------------------------------------------------- -!> @brief calculate max of curl of field_fourier +!> @brief Calculate root mean square of curl. !-------------------------------------------------------------------------------------------------- -real(pReal) function utilities_curlRMS() +real(pReal) function utilities_curlRMS(tensorField) + + real(pReal), dimension(3,3,cells(1),cells(2),cells3), intent(in) :: tensorField integer :: i, j, k, l integer(MPI_INTEGER_KIND) :: err_MPI @@ -673,6 +680,9 @@ real(pReal) function utilities_curlRMS() print'(/,1x,a)', '... calculating curl ......................................................' flush(IO_STDOUT) + tensorField_real(1:3,1:3,1:cells(1),1:cells(2),1:cells3) = tensorField + call utilities_FFTtensorforward() + rescaledGeom = cmplx(geomSize/scaledGeomSize,0.0_pReal,pReal) !-------------------------------------------------------------------------------------------------- From 5017aabceaf32982dcf9d2e15387c1dca42adb85 Mon Sep 17 00:00:00 2001 From: Daniel Otto de Mentock Date: Sat, 19 Nov 2022 08:10:00 +0000 Subject: [PATCH 25/60] util.extend_docstring: proper layout for extended class (incl. current return type) --- python/damask/_orientation.py | 46 +++++++++---- python/damask/_rotation.py | 48 ++++++++++++- python/damask/seeds.py | 1 - python/damask/util.py | 104 ++++++++++++++++++++-------- python/tests/test_util.py | 126 +++++++++++++++++++++++++++++++++- 5 files changed, 276 insertions(+), 49 deletions(-) diff --git a/python/damask/_orientation.py b/python/damask/_orientation.py index 8bbcb7957..95bcc6795 100644 --- a/python/damask/_orientation.py +++ b/python/damask/_orientation.py @@ -94,7 +94,7 @@ class Orientation(Rotation,Crystal): """ - @util.extend_docstring(_parameter_doc) + @util.extend_docstring(extra_parameters=_parameter_doc) def __init__(self, rotation: Union[FloatSequence, Rotation] = np.array([1.,0.,0.,0.]), *, @@ -300,84 +300,95 @@ class Orientation(Rotation,Crystal): @classmethod - @util.extended_docstring(Rotation.from_random, _parameter_doc) + @util.extend_docstring(Rotation.from_random, + extra_parameters=_parameter_doc) def from_random(cls, **kwargs) -> 'Orientation': kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_random) return cls(rotation=Rotation.from_random(**kwargs_rot),**kwargs_ori) @classmethod - @util.extended_docstring(Rotation.from_quaternion,_parameter_doc) + @util.extend_docstring(Rotation.from_quaternion, + extra_parameters=_parameter_doc) def from_quaternion(cls, **kwargs) -> 'Orientation': kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_quaternion) return cls(rotation=Rotation.from_quaternion(**kwargs_rot),**kwargs_ori) @classmethod - @util.extended_docstring(Rotation.from_Euler_angles,_parameter_doc) + @util.extend_docstring(Rotation.from_Euler_angles, + extra_parameters=_parameter_doc) def from_Euler_angles(cls, **kwargs) -> 'Orientation': kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_Euler_angles) return cls(rotation=Rotation.from_Euler_angles(**kwargs_rot),**kwargs_ori) @classmethod - @util.extended_docstring(Rotation.from_axis_angle,_parameter_doc) + @util.extend_docstring(Rotation.from_axis_angle, + extra_parameters=_parameter_doc) def from_axis_angle(cls, **kwargs) -> 'Orientation': kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_axis_angle) return cls(rotation=Rotation.from_axis_angle(**kwargs_rot),**kwargs_ori) @classmethod - @util.extended_docstring(Rotation.from_basis,_parameter_doc) + @util.extend_docstring(Rotation.from_basis, + extra_parameters=_parameter_doc) def from_basis(cls, **kwargs) -> 'Orientation': kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_basis) return cls(rotation=Rotation.from_basis(**kwargs_rot),**kwargs_ori) @classmethod - @util.extended_docstring(Rotation.from_matrix,_parameter_doc) + @util.extend_docstring(Rotation.from_matrix, + extra_parameters=_parameter_doc) def from_matrix(cls, **kwargs) -> 'Orientation': kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_matrix) return cls(rotation=Rotation.from_matrix(**kwargs_rot),**kwargs_ori) @classmethod - @util.extended_docstring(Rotation.from_Rodrigues_vector,_parameter_doc) + @util.extend_docstring(Rotation.from_Rodrigues_vector, + extra_parameters=_parameter_doc) def from_Rodrigues_vector(cls, **kwargs) -> 'Orientation': kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_Rodrigues_vector) return cls(rotation=Rotation.from_Rodrigues_vector(**kwargs_rot),**kwargs_ori) @classmethod - @util.extended_docstring(Rotation.from_homochoric,_parameter_doc) + @util.extend_docstring(Rotation.from_homochoric, + extra_parameters=_parameter_doc) def from_homochoric(cls, **kwargs) -> 'Orientation': kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_homochoric) return cls(rotation=Rotation.from_homochoric(**kwargs_rot),**kwargs_ori) @classmethod - @util.extended_docstring(Rotation.from_cubochoric,_parameter_doc) + @util.extend_docstring(Rotation.from_cubochoric, + extra_parameters=_parameter_doc) def from_cubochoric(cls, **kwargs) -> 'Orientation': kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_cubochoric) return cls(rotation=Rotation.from_cubochoric(**kwargs_rot),**kwargs_ori) @classmethod - @util.extended_docstring(Rotation.from_spherical_component,_parameter_doc) + @util.extend_docstring(Rotation.from_spherical_component, + extra_parameters=_parameter_doc) def from_spherical_component(cls, **kwargs) -> 'Orientation': kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_spherical_component) return cls(rotation=Rotation.from_spherical_component(**kwargs_rot),**kwargs_ori) @classmethod - @util.extended_docstring(Rotation.from_fiber_component,_parameter_doc) + @util.extend_docstring(Rotation.from_fiber_component, + extra_parameters=_parameter_doc) def from_fiber_component(cls, **kwargs) -> 'Orientation': kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_fiber_component) return cls(rotation=Rotation.from_fiber_component(**kwargs_rot),**kwargs_ori) @classmethod - @util.extend_docstring(_parameter_doc) + @util.extend_docstring(extra_parameters=_parameter_doc) def from_directions(cls, uvw: FloatSequence, hkl: FloatSequence, @@ -392,6 +403,10 @@ class Orientation(Rotation,Crystal): hkl : numpy.ndarray, shape (...,3) Lattice plane normal aligned with lab frame z-direction. + Returns + ------- + new : damask.Orientation + """ o = cls(**kwargs) x = o.to_frame(uvw=uvw) @@ -538,8 +553,7 @@ class Orientation(Rotation,Crystal): Notes ----- - Currently requires same crystal family for both orientations. - For extension to cases with differing symmetry see A. Heinz and P. Neumann 1991 and 10.1107/S0021889808016373. + Requires same crystal family for both orientations. Examples -------- @@ -569,6 +583,8 @@ class Orientation(Rotation,Crystal): >>> plt.show() """ + # For extension to cases with differing symmetry see + # https://doi.org/10.1107/S0021889808016373 and https://doi.org/10.1107/S0108767391006864 if self.family != other.family: raise NotImplementedError('disorientation between different crystal families') diff --git a/python/damask/_rotation.py b/python/damask/_rotation.py index 204a735ad..c5c344765 100644 --- a/python/damask/_rotation.py +++ b/python/damask/_rotation.py @@ -732,7 +732,7 @@ class Rotation: Returns ------- x : numpy.ndarray, shape (...,3) - Cubochoric vector (x_1, x_2, x_3) with max(x_i) < 1/2*π^(2/3). + Cubochoric vector (x_1, x_2, x_3) with max(x_i) < 1/2*π^(2/3). Examples -------- @@ -768,6 +768,10 @@ class Rotation: P : int ∈ {-1,1}, optional Sign convention. Defaults to -1. + Returns + ------- + new : damask.Rotation + """ qu = np.array(q,dtype=float) if qu.shape[:-2:-1] != (4,): raise ValueError('invalid shape') @@ -800,6 +804,10 @@ class Rotation: degrees : bool, optional Euler angles are given in degrees. Defaults to False. + Returns + ------- + new : damask.Rotation + Notes ----- Bunge Euler angles correspond to a rotation axis sequence of z–x'–z''. @@ -834,6 +842,10 @@ class Rotation: P : int ∈ {-1,1}, optional Sign convention. Defaults to -1. + Returns + ------- + new : damask.Rotation + """ ax = np.array(axis_angle,dtype=float) if ax.shape[:-2:-1] != (4,): raise ValueError('invalid shape') @@ -898,6 +910,10 @@ class Rotation: R : numpy.ndarray, shape (...,3,3) Rotation matrix with det(R) = 1 and R.T ∙ R = I. + Returns + ------- + new : damask.Rotation + """ return Rotation.from_basis(R) @@ -914,6 +930,10 @@ class Rotation: b : numpy.ndarray, shape (...,2,3) Corresponding three-dimensional vectors of second basis. + Returns + ------- + new : damask.Rotation + """ a_ = np.array(a,dtype=float) b_ = np.array(b,dtype=float) @@ -946,6 +966,10 @@ class Rotation: P : int ∈ {-1,1}, optional Sign convention. Defaults to -1. + Returns + ------- + new : damask.Rotation + """ ro = np.array(rho,dtype=float) if ro.shape[:-2:-1] != (4,): raise ValueError('invalid shape') @@ -974,6 +998,10 @@ class Rotation: P : int ∈ {-1,1}, optional Sign convention. Defaults to -1. + Returns + ------- + new : damask.Rotation + """ ho = np.array(h,dtype=float) if ho.shape[:-2:-1] != (3,): raise ValueError('invalid shape') @@ -999,6 +1027,10 @@ class Rotation: P : int ∈ {-1,1}, optional Sign convention. Defaults to -1. + Returns + ------- + new : damask.Rotation + """ cu = np.array(x,dtype=float) if cu.shape[:-2:-1] != (3,): raise ValueError('invalid shape') @@ -1025,6 +1057,10 @@ class Rotation: A seed to initialize the BitGenerator. Defaults to None, i.e. unpredictable entropy will be pulled from the OS. + Returns + ------- + new : damask.Rotation + """ rng = np.random.default_rng(rng_seed) r = rng.random(3 if shape is None else tuple(shape)+(3,) if hasattr(shape, '__iter__') else (shape,3)) # type: ignore @@ -1066,6 +1102,10 @@ class Rotation: A seed to initialize the BitGenerator. Defaults to None, i.e. unpredictable entropy will be pulled from the OS. + Returns + ------- + new : damask.Rotation + Notes ----- Due to the distortion of Euler space in the vicinity of ϕ = 0, probability densities, p, defined on @@ -1150,7 +1190,7 @@ class Rotation: sigma: float = 0., shape: Union[int, IntSequence] = None, degrees: bool = False, - rng_seed: NumpyRngSeed = None): + rng_seed: NumpyRngSeed = None) -> 'Rotation': """ Initialize with samples from a Gaussian distribution around a given direction. @@ -1173,6 +1213,10 @@ class Rotation: A seed to initialize the BitGenerator. Defaults to None, i.e. unpredictable entropy will be pulled from the OS. + Returns + ------- + new : damask.Rotation + Notes ----- The crystal direction for (θ=0,φ=0) is [0 0 1], diff --git a/python/damask/seeds.py b/python/damask/seeds.py index 89d9bf935..7cea9d51c 100644 --- a/python/damask/seeds.py +++ b/python/damask/seeds.py @@ -1,4 +1,3 @@ - """Functionality for generation of seed points for Voronoi or Laguerre tessellation.""" from typing import Tuple as _Tuple diff --git a/python/damask/util.py b/python/damask/util.py index 04e448422..d8ed340f8 100644 --- a/python/damask/util.py +++ b/python/damask/util.py @@ -210,6 +210,14 @@ def open_text(fname: _FileHandle, open(_Path(fname).expanduser(),mode,newline=('\n' if mode == 'w' else None)) +def execution_stamp(class_name: str, + function_name: str = None) -> str: + """Timestamp the execution of a (function within a) class.""" + now = _datetime.datetime.now().astimezone().strftime('%Y-%m-%d %H:%M:%S%z') + _function_name = '' if function_name is None else f'.{function_name}' + return f'damask.{class_name}{_function_name} v{_version} ({now})' + + def natural_sort(key: str) -> _List[_Union[int, str]]: """ Natural sort. @@ -403,13 +411,6 @@ def project_equal_area(vector: _np.ndarray, return _np.roll(_np.block([v[...,:2]/_np.sqrt(1.0+_np.abs(v[...,2:3])),_np.zeros_like(v[...,2:3])]), -shift if keepdims else 0,axis=-1)[...,:3 if keepdims else 2] -def execution_stamp(class_name: str, - function_name: str = None) -> str: - """Timestamp the execution of a (function within a) class.""" - now = _datetime.datetime.now().astimezone().strftime('%Y-%m-%d %H:%M:%S%z') - _function_name = '' if function_name is None else f'.{function_name}' - return f'damask.{class_name}{_function_name} v{_version} ({now})' - def hybrid_IA(dist: _np.ndarray, N: int, @@ -486,18 +487,18 @@ def shapeshifter(fro: _Tuple[int, ...], final_shape: _List[int] = [] index = 0 for i,item in enumerate(_to): - if item==_fro[index]: + if item == _fro[index]: final_shape.append(item) index+=1 else: final_shape.append(1) - if _fro[index]==1 and not keep_ones: + if _fro[index] == 1 and not keep_ones: index+=1 - if index==len(_fro): + if index == len(_fro): final_shape = final_shape+[1]*(len(_to)-i-1) break - if index!=len(_fro): raise ValueError(f'shapes cannot be shifted {fro} --> {to}') - return tuple(final_shape[::-1] if mode=='left' else final_shape) + if index != len(_fro): raise ValueError(f'shapes cannot be shifted {fro} --> {to}') + return tuple(final_shape[::-1] if mode == 'left' else final_shape) def shapeblender(a: _Tuple[int, ...], b: _Tuple[int, ...]) -> _Tuple[int, ...]: @@ -528,37 +529,82 @@ def shapeblender(a: _Tuple[int, ...], return a + b[i:] -def extend_docstring(extra_docstring: str) -> _Callable: +def _docstringer(docstring: _Union[str, _Callable], + extra_parameters: str = None, + # extra_examples: str = None, + # extra_notes: str = None, + return_type: _Union[str, _Callable] = None) -> str: """ - Decorator: Append to function's docstring. + Extend a docstring. Parameters ---------- - extra_docstring : str - Docstring to append. + docstring : str or callable, optional + Docstring (of callable) to extend. + extra_parameters : str, optional + Additional information to append to Parameters section. + return_type : str or callable, optional + Type of return variable. """ - def _decorator(func): - func.__doc__ += extra_docstring - return func - return _decorator + docstring_ = str( docstring if isinstance(docstring,str) + else docstring.__doc__ if hasattr(docstring,'__doc__') + else '') + d = dict(Parameters=extra_parameters, + # Examples=extra_examples, + # Notes=extra_notes, + ) + for key,extra in [(k,v) for (k,v) in d.items() if v is not None]: + if not (heading := _re.search(fr'^([ ]*){key}\s*\n\1{"-"*len(key)}', + docstring_,flags=_re.MULTILINE)): + raise RuntimeError(f"Docstring {docstring_} lacks a correctly formatted {key} section to insert values into") + content = [line for line in extra.split('\n') if line.strip()] + indent = len(heading.group(1)) + shift = min([len(line)-len(line.lstrip(' '))-indent for line in content]) + extra = '\n'.join([(line[shift:] if shift > 0 else + f'{" "*-shift}{line}') for line in content]) + docstring_ = _re.sub(fr'(^([ ]*){key}\s*\n\2{"-"*len(key)}[\n ]*[A-Za-z0-9 ]*: ([^\n]+\n)*)', + fr'\1{extra}\n', + docstring_,flags=_re.MULTILINE) + if return_type is None: + return docstring_ + else: + if isinstance(return_type,str): + return_type_ = return_type + else: + return_class = return_type.__annotations__.get('return','') + return_type_ = (_sys.modules[return_type.__module__].__name__.split('.')[0] + +'.' + +(return_class.__name__ if not isinstance(return_class,str) else return_class) + ) -def extended_docstring(f: _Callable, - extra_docstring: str) -> _Callable: + return _re.sub(r'(^([ ]*)Returns\s*\n\2-------\s*\n[ ]*[A-Za-z0-9 ]*: )(.*)\n', + fr'\1{return_type_}\n', + docstring_,flags=_re.MULTILINE) + +def extend_docstring(docstring: _Union[str, _Callable] = None, + extra_parameters: str = None) -> _Callable: """ - Decorator: Combine another function's docstring with a given docstring. + Decorator: Extend the function's docstring. Parameters ---------- - f : function - Function of which the docstring is taken. - extra_docstring : str - Docstring to append. + docstring : str or callable, optional + Docstring to extend. Defaults to that of decorated function. + extra_parameters : str, optional + Additional information to append to Parameters section. + + Notes + ----- + Return type will become own type if docstring is callable. """ def _decorator(func): - func.__doc__ = f.__doc__ + extra_docstring + func.__doc__ = _docstringer(func.__doc__ if docstring is None else docstring, + extra_parameters, + func if isinstance(docstring,_Callable) else None, + ) return func return _decorator @@ -649,7 +695,6 @@ def Bravais_to_Miller(*, [0,0,0,1]])) return _np.einsum('il,...l',basis,axis) - def Miller_to_Bravais(*, uvw: _np.ndarray = None, hkl: _np.ndarray = None) -> _np.ndarray: @@ -706,7 +751,6 @@ def dict_prune(d: _Dict) -> _Dict: return new - def dict_flatten(d: _Dict) -> _Dict: """ Recursively remove keys of single-entry dictionaries. diff --git a/python/tests/test_util.py b/python/tests/test_util.py index 80786249a..b2e689471 100644 --- a/python/tests/test_util.py +++ b/python/tests/test_util.py @@ -8,7 +8,6 @@ import h5py from damask import util - class TestUtil: @pytest.mark.xfail(sys.platform == 'win32', reason='echo is not a Windows command') @@ -208,3 +207,128 @@ class TestUtil: @pytest.mark.parametrize('kw_Miller,kw_Bravais',[('uvw','uvtw'),('hkl','hkil')]) def test_Bravais_Miller_Bravais(self,vector,kw_Miller,kw_Bravais): assert np.all(vector == util.Miller_to_Bravais(**{kw_Miller:util.Bravais_to_Miller(**{kw_Bravais:vector})})) + + + @pytest.mark.parametrize('extra_parameters',[""" + p2 : str, optional + p2 description 1 + p2 description 2 + """, + """ + + p2 : str, optional + p2 description 1 + p2 description 2 + + """, + """ +p2 : str, optional + p2 description 1 + p2 description 2 + """]) + @pytest.mark.parametrize('invalid_docstring',[""" + Function description + + Parameters ---------- + p0 : numpy.ndarray, shape (...,4) + p0 description 1 + p0 description 2 + p1 : int, optional + p1 description + + Remaining description + """, + """ + Function description + + Parameters + ---------- + p0 : numpy.ndarray, shape (...,4) + p0 description 1 + p0 description 2 + p1 : int, optional + p1 description + + Remaining description + """,]) + def test_extend_docstring_parameters(self,extra_parameters,invalid_docstring): + test_docstring = """ + Function description + + Parameters + ---------- + p0 : numpy.ndarray, shape (...,4) + p0 description 1 + p0 description 2 + p1 : int, optional + p1 description + + Remaining description + """ + invalid_docstring = """ + Function description + + Parameters ---------- + p0 : numpy.ndarray, shape (...,4) + p0 description 1 + p0 description 2 + p1 : int, optional + p1 description + + Remaining description + """ + expected = """ + Function description + + Parameters + ---------- + p0 : numpy.ndarray, shape (...,4) + p0 description 1 + p0 description 2 + p1 : int, optional + p1 description + p2 : str, optional + p2 description 1 + p2 description 2 + + Remaining description + """.split("\n") + assert expected == util._docstringer(test_docstring,extra_parameters).split('\n') + with pytest.raises(RuntimeError): + util._docstringer(invalid_docstring,extra_parameters) + + def test_replace_docstring_return_type(self): + class TestClassOriginal: + pass + + def original_func() -> TestClassOriginal: + pass + + class TestClassDecorated: + def decorated_func_bound(self) -> 'TestClassDecorated': + pass + + def decorated_func() -> TestClassDecorated: + pass + + original_func.__doc__ = """ + Function description/Parameters + + Returns + ------- + Return value : test_util.TestClassOriginal + + Remaining description + """ + + expected = """ + Function description/Parameters + + Returns + ------- + Return value : test_util.TestClassDecorated + + Remaining description + """ + assert expected == util._docstringer(original_func,return_type=decorated_func) + assert expected == util._docstringer(original_func,return_type=TestClassDecorated.decorated_func_bound) From 18b89239291d62ff2239107108854d0570772632 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sat, 19 Nov 2022 09:25:06 +0100 Subject: [PATCH 26/60] centralize FFTs --- src/grid/grid_damage_spectral.f90 | 19 ++++++---------- src/grid/grid_mech_spectral_basic.f90 | 4 ---- src/grid/grid_mech_spectral_polarisation.f90 | 4 ---- src/grid/grid_thermal_spectral.f90 | 23 +++++++++----------- src/grid/spectral_utilities.f90 | 14 +++++++----- 5 files changed, 25 insertions(+), 39 deletions(-) diff --git a/src/grid/grid_damage_spectral.f90 b/src/grid/grid_damage_spectral.f90 index fc1defac3..f09992f55 100644 --- a/src/grid/grid_damage_spectral.f90 +++ b/src/grid/grid_damage_spectral.f90 @@ -253,11 +253,13 @@ end function grid_damage_spectral_solution subroutine grid_damage_spectral_forward(cutBack) logical, intent(in) :: cutBack + integer :: i, j, k, ce DM :: dm_local PetscScalar, dimension(:,:,:), pointer :: phi_PETSc PetscErrorCode :: err_PETSc + if (cutBack) then phi_current = phi_lastInc phi_stagInc = phi_lastInc @@ -284,7 +286,7 @@ end subroutine grid_damage_spectral_forward !-------------------------------------------------------------------------------------------------- -!> @brief forms the spectral damage residual vector +!> @brief Construct the residual vector. !-------------------------------------------------------------------------------------------------- subroutine formResidual(in,x_scal,r,dummy,err_PETSc) @@ -297,7 +299,8 @@ subroutine formResidual(in,x_scal,r,dummy,err_PETSc) X_RANGE,Y_RANGE,Z_RANGE), intent(out) :: & r PetscObject :: dummy - PetscErrorCode :: err_PETSc + PetscErrorCode, intent(out) :: err_PETSc + integer :: i, j, k, ce @@ -305,17 +308,13 @@ subroutine formResidual(in,x_scal,r,dummy,err_PETSc) !-------------------------------------------------------------------------------------------------- ! evaluate polarization field scalarField_real(1:cells(1),1:cells(2),1:cells3) = phi_current - call utilities_FFTscalarForward - call utilities_fourierScalarGradient !< calculate gradient of damage field - call utilities_FFTvectorBackward + call utilities_fourierScalarGradient() ce = 0 do k = 1, cells3; do j = 1, cells(2); do i = 1,cells(1) ce = ce + 1 vectorField_real(1:3,i,j,k) = matmul(homogenization_K_phi(ce) - K_ref, vectorField_real(1:3,i,j,k)) end do; end do; end do - call utilities_FFTvectorForward - call utilities_fourierVectorDivergence !< calculate damage divergence in fourier field - call utilities_FFTscalarBackward + call utilities_fourierVectorDivergence() ce = 0 do k = 1, cells3; do j = 1, cells(2); do i = 1,cells(1) ce = ce + 1 @@ -324,11 +323,7 @@ subroutine formResidual(in,x_scal,r,dummy,err_PETSc) + mu_ref*phi_current(i,j,k) end do; end do; end do -!-------------------------------------------------------------------------------------------------- -! convolution of damage field with green operator - call utilities_FFTscalarForward call utilities_fourierGreenConvolution(K_ref, mu_ref, params%Delta_t) - call utilities_FFTscalarBackward !-------------------------------------------------------------------------------------------------- ! constructing residual diff --git a/src/grid/grid_mech_spectral_basic.f90 b/src/grid/grid_mech_spectral_basic.f90 index 4dca95e80..a065633de 100644 --- a/src/grid/grid_mech_spectral_basic.f90 +++ b/src/grid/grid_mech_spectral_basic.f90 @@ -544,12 +544,8 @@ subroutine formResidual(in, F, & F_aim = F_aim - deltaF_aim err_BC = maxval(abs(merge(.0_pReal,P_av - P_aim,params%stress_mask))) -!-------------------------------------------------------------------------------------------------- -! updated deformation gradient using fix point algorithm of basic scheme tensorField_real(1:3,1:3,1:cells(1),1:cells(2),1:cells3) = r ! store fPK field for subsequent FFT forward transform - call utilities_FFTtensorForward ! FFT forward of global "tensorField_real" call utilities_fourierGammaConvolution(params%rotation_BC%rotate(deltaF_aim,active=.true.)) ! convolution of Gamma and tensorField_fourier - call utilities_FFTtensorBackward ! FFT backward of global tensorField_fourier !-------------------------------------------------------------------------------------------------- ! constructing residual diff --git a/src/grid/grid_mech_spectral_polarisation.f90 b/src/grid/grid_mech_spectral_polarisation.f90 index 9c9a83766..fea34d7d0 100644 --- a/src/grid/grid_mech_spectral_polarisation.f90 +++ b/src/grid/grid_mech_spectral_polarisation.f90 @@ -618,11 +618,7 @@ subroutine formResidual(in, FandF_tau, & math_mul3333xx33(C_scale,F_tau(1:3,1:3,i,j,k) - F(1:3,1:3,i,j,k) - math_I3)) end do; end do; end do -!-------------------------------------------------------------------------------------------------- -! doing convolution in Fourier space - call utilities_FFTtensorForward call utilities_fourierGammaConvolution(params%rotation_BC%rotate(num%beta*F_aim,active=.true.)) - call utilities_FFTtensorBackward !-------------------------------------------------------------------------------------------------- ! constructing residual diff --git a/src/grid/grid_thermal_spectral.f90 b/src/grid/grid_thermal_spectral.f90 index b34717027..c6b190254 100644 --- a/src/grid/grid_thermal_spectral.f90 +++ b/src/grid/grid_thermal_spectral.f90 @@ -242,11 +242,13 @@ end function grid_thermal_spectral_solution subroutine grid_thermal_spectral_forward(cutBack) logical, intent(in) :: cutBack + integer :: i, j, k, ce DM :: dm_local PetscScalar, dimension(:,:,:), pointer :: T_PETSc PetscErrorCode :: err_PETSc + if (cutBack) then T_current = T_lastInc T_stagInc = T_lastInc @@ -307,7 +309,7 @@ end subroutine grid_thermal_spectral_restartWrite !-------------------------------------------------------------------------------------------------- -!> @brief forms the spectral thermal residual vector +!> @brief Construct the residual vector. !-------------------------------------------------------------------------------------------------- subroutine formResidual(in,x_scal,r,dummy,err_PETSc) @@ -320,24 +322,22 @@ subroutine formResidual(in,x_scal,r,dummy,err_PETSc) X_RANGE,Y_RANGE,Z_RANGE), intent(out) :: & r PetscObject :: dummy - PetscErrorCode :: err_PETSc + PetscErrorCode, intent(out) :: err_PETSc + integer :: i, j, k, ce + T_current = x_scal !-------------------------------------------------------------------------------------------------- ! evaluate polarization field scalarField_real(1:cells(1),1:cells(2),1:cells3) = T_current - call utilities_FFTscalarForward - call utilities_fourierScalarGradient !< calculate gradient of temperature field - call utilities_FFTvectorBackward + call utilities_fourierScalarGradient() ce = 0 do k = 1, cells3; do j = 1, cells(2); do i = 1,cells(1) ce = ce + 1 vectorField_real(1:3,i,j,k) = matmul(homogenization_K_T(ce) - K_ref, vectorField_real(1:3,i,j,k)) end do; end do; end do - call utilities_FFTvectorForward - call utilities_fourierVectorDivergence !< calculate temperature divergence in fourier field - call utilities_FFTscalarBackward + call utilities_fourierVectorDivergence() ce = 0 do k = 1, cells3; do j = 1, cells(2); do i = 1,cells(1) ce = ce + 1 @@ -346,15 +346,12 @@ subroutine formResidual(in,x_scal,r,dummy,err_PETSc) + mu_ref*T_current(i,j,k) end do; end do; end do -!-------------------------------------------------------------------------------------------------- -! convolution of temperature field with green operator - call utilities_FFTscalarForward call utilities_fourierGreenConvolution(K_ref, mu_ref, params%Delta_t) - call utilities_FFTscalarBackward !-------------------------------------------------------------------------------------------------- ! constructing residual - r = T_current - scalarField_real(1:cells(1),1:cells(2),1:cells3) + r = T_current & + - scalarField_real(1:cells(1),1:cells(2),1:cells3) err_PETSc = 0 end subroutine formResidual diff --git a/src/grid/spectral_utilities.f90 b/src/grid/spectral_utilities.f90 index db2efbfec..858fc20db 100644 --- a/src/grid/spectral_utilities.f90 +++ b/src/grid/spectral_utilities.f90 @@ -116,12 +116,6 @@ module spectral_utilities public :: & spectral_utilities_init, & utilities_updateGamma, & - utilities_FFTtensorForward, & - utilities_FFTtensorBackward, & - utilities_FFTvectorForward, & - utilities_FFTvectorBackward, & - utilities_FFTscalarForward, & - utilities_FFTscalarBackward, & utilities_fourierGammaConvolution, & utilities_fourierGreenConvolution, & utilities_divergenceRMS, & @@ -526,6 +520,7 @@ subroutine utilities_fourierGammaConvolution(fieldAim) print'(/,1x,a)', '... doing gamma convolution ...............................................' flush(IO_STDOUT) + call utilities_FFTtensorForward() !-------------------------------------------------------------------------------------------------- ! do the actual spectral method calculation (mechanical equilibrium) memoryEfficient: if (num%memory_efficient) then @@ -587,6 +582,7 @@ subroutine utilities_fourierGammaConvolution(fieldAim) end if memoryEfficient if (cells3Offset == 0) tensorField_fourier(1:3,1:3,1,1,1) = cmplx(fieldAim/wgt,0.0_pReal,pReal) + call utilities_FFTtensorBackward() end subroutine utilities_fourierGammaConvolution @@ -603,6 +599,7 @@ subroutine utilities_fourierGreenConvolution(D_ref, mu_ref, Delta_t) !-------------------------------------------------------------------------------------------------- ! do the actual spectral method calculation + call utilities_FFTscalarForward() !$OMP PARALLEL DO PRIVATE(GreenOp_hat) do j = 1, cells2; do k = 1, cells(3); do i = 1, cells1Red GreenOp_hat = cmplx(1.0_pReal,0.0_pReal,pReal) & @@ -611,6 +608,7 @@ subroutine utilities_fourierGreenConvolution(D_ref, mu_ref, Delta_t) scalarField_fourier(i,k,j) = scalarField_fourier(i,k,j)*GreenOp_hat end do; end do; end do !$OMP END PARALLEL DO + call utilities_FFTscalarBackward() end subroutine utilities_fourierGreenConvolution @@ -810,9 +808,11 @@ subroutine utilities_fourierScalarGradient() integer :: i, j, k + call utilities_FFTscalarForward() do j = 1, cells2; do k = 1, cells(3); do i = 1,cells1Red vectorField_fourier(1:3,i,k,j) = scalarField_fourier(i,k,j)*xi1st(1:3,i,k,j) ! ToDo: no -conjg? end do; end do; end do + call utilities_FFTvectorBackward() end subroutine utilities_fourierScalarGradient @@ -822,8 +822,10 @@ end subroutine utilities_fourierScalarGradient !-------------------------------------------------------------------------------------------------- subroutine utilities_fourierVectorDivergence() + call utilities_FFTvectorForward() scalarField_fourier(1:cells1Red,1:cells(3),1:cells2) = sum(vectorField_fourier(1:3,1:cells1Red,1:cells(3),1:cells2) & *conjg(-xi1st),1) + call utilities_FFTscalarBackward() end subroutine utilities_fourierVectorDivergence From 9160c63adf8804a3047e30617a09d90d48774df4 Mon Sep 17 00:00:00 2001 From: Test User Date: Sat, 19 Nov 2022 11:31:43 +0100 Subject: [PATCH 27/60] [skip ci] updated version information after successful test of v3.0.0-alpha7-111-g30b23df2d --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 25f2fc3ba..68807f157 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.0.0-alpha7-108-gd596de7a3 +3.0.0-alpha7-111-g30b23df2d From cb6df618feca7068d2933c116e9a53b36d736cfd Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sat, 19 Nov 2022 10:50:15 +0100 Subject: [PATCH 28/60] avoid global variables --- src/grid/grid_mech_spectral_basic.f90 | 15 ++++++------- src/grid/grid_mech_spectral_polarisation.f90 | 15 +++++++------ src/grid/spectral_utilities.f90 | 22 +++++++++++++------- 3 files changed, 27 insertions(+), 25 deletions(-) diff --git a/src/grid/grid_mech_spectral_basic.f90 b/src/grid/grid_mech_spectral_basic.f90 index a065633de..1ec6d334c 100644 --- a/src/grid/grid_mech_spectral_basic.f90 +++ b/src/grid/grid_mech_spectral_basic.f90 @@ -491,7 +491,7 @@ end subroutine converged !-------------------------------------------------------------------------------------------------- -!> @brief forms the residual vector +!> @brief Construct the residual vector. !-------------------------------------------------------------------------------------------------- subroutine formResidual(in, F, & r, dummy, err_PETSc) @@ -501,15 +501,17 @@ subroutine formResidual(in, F, & intent(in) :: F !< deformation gradient field PetscScalar, dimension(3,3,X_RANGE,Y_RANGE,Z_RANGE), & intent(out) :: r !< residuum field + PetscObject :: dummy + PetscErrorCode :: err_PETSc + real(pReal), dimension(3,3) :: & deltaF_aim PetscInt :: & PETScIter, & nfuncs - PetscObject :: dummy - PetscErrorCode :: err_PETSc integer(MPI_INTEGER_KIND) :: err_MPI + call SNESGetNumberFunctionEvals(SNES_mechanical,nfuncs,err_PETSc) CHKERRQ(err_PETSc) call SNESGetIterationNumber(SNES_mechanical,PETScIter,err_PETSc) @@ -544,12 +546,7 @@ subroutine formResidual(in, F, & F_aim = F_aim - deltaF_aim err_BC = maxval(abs(merge(.0_pReal,P_av - P_aim,params%stress_mask))) - tensorField_real(1:3,1:3,1:cells(1),1:cells(2),1:cells3) = r ! store fPK field for subsequent FFT forward transform - call utilities_fourierGammaConvolution(params%rotation_BC%rotate(deltaF_aim,active=.true.)) ! convolution of Gamma and tensorField_fourier - -!-------------------------------------------------------------------------------------------------- -! constructing residual - r = tensorField_real(1:3,1:3,1:cells(1),1:cells(2),1:cells3) ! Gamma*P gives correction towards div(P) = 0, so needs to be zero, too + r = utilities_fourierGammaConvolution(r,params%rotation_BC%rotate(deltaF_aim,active=.true.)) ! convolution of Gamma and tensorField_fourier end subroutine formResidual diff --git a/src/grid/grid_mech_spectral_polarisation.f90 b/src/grid/grid_mech_spectral_polarisation.f90 index fea34d7d0..235bb873e 100644 --- a/src/grid/grid_mech_spectral_polarisation.f90 +++ b/src/grid/grid_mech_spectral_polarisation.f90 @@ -551,7 +551,7 @@ end subroutine converged !-------------------------------------------------------------------------------------------------- -!> @brief forms the residual vector +!> @brief Construct the residual vector. !-------------------------------------------------------------------------------------------------- subroutine formResidual(in, FandF_tau, & r, dummy,err_PETSc) @@ -561,6 +561,9 @@ subroutine formResidual(in, FandF_tau, & target, intent(in) :: FandF_tau PetscScalar, dimension(3,3,2,X_RANGE,Y_RANGE,Z_RANGE),& target, intent(out) :: r !< residuum field + PetscObject :: dummy + PetscErrorCode :: err_PETSc + PetscScalar, pointer, dimension(:,:,:,:,:) :: & F, & F_tau, & @@ -569,13 +572,10 @@ subroutine formResidual(in, FandF_tau, & PetscInt :: & PETScIter, & nfuncs - PetscObject :: dummy - PetscErrorCode :: err_PETSc integer(MPI_INTEGER_KIND) :: err_MPI integer :: & i, j, k, e -!--------------------------------------------------------------------------------------------------- F => FandF_tau(1:3,1:3,1,& XG_RANGE,YG_RANGE,ZG_RANGE) @@ -612,17 +612,16 @@ subroutine formResidual(in, FandF_tau, & !-------------------------------------------------------------------------------------------------- ! do k = 1, cells3; do j = 1, cells(2); do i = 1, cells(1) - tensorField_real(1:3,1:3,i,j,k) = & + r_F_tau(1:3,1:3,i,j,k) = & num%beta*math_mul3333xx33(C_scale,F(1:3,1:3,i,j,k) - math_I3) -& num%alpha*matmul(F(1:3,1:3,i,j,k), & math_mul3333xx33(C_scale,F_tau(1:3,1:3,i,j,k) - F(1:3,1:3,i,j,k) - math_I3)) end do; end do; end do - call utilities_fourierGammaConvolution(params%rotation_BC%rotate(num%beta*F_aim,active=.true.)) - !-------------------------------------------------------------------------------------------------- ! constructing residual - r_F_tau = num%beta*F - tensorField_real(1:3,1:3,1:cells(1),1:cells(2),1:cells3) + r_F_tau = num%beta*F & + - utilities_fourierGammaConvolution(r_F_tau,params%rotation_BC%rotate(num%beta*F_aim,active=.true.)) !-------------------------------------------------------------------------------------------------- ! evaluate constitutive response diff --git a/src/grid/spectral_utilities.f90 b/src/grid/spectral_utilities.f90 index 858fc20db..9e5282de0 100644 --- a/src/grid/spectral_utilities.f90 +++ b/src/grid/spectral_utilities.f90 @@ -42,7 +42,7 @@ module spectral_utilities !-------------------------------------------------------------------------------------------------- ! variables storing information for spectral method and FFTW - real(C_DOUBLE), public, dimension(:,:,:,:,:), pointer :: tensorField_real !< tensor field in real space + real(C_DOUBLE), dimension(:,:,:,:,:), pointer :: tensorField_real !< tensor field in real space real(C_DOUBLE), public, dimension(:,:,:,:), pointer :: vectorField_real !< vector field in real space real(C_DOUBLE), public, dimension(:,:,:), pointer :: scalarField_real !< scalar field in real space complex(C_DOUBLE_COMPLEX), dimension(:,:,:,:,:), pointer :: tensorField_fourier !< tensor field in Fourier space @@ -505,12 +505,14 @@ end subroutine utilities_FFTvectorBackward !-------------------------------------------------------------------------------------------------- !> @brief doing convolution gamma_hat * field_real, ensuring that average value = fieldAim !-------------------------------------------------------------------------------------------------- -subroutine utilities_fourierGammaConvolution(fieldAim) +function utilities_fourierGammaConvolution(field, fieldAim) result(gammaField) + real(pReal), intent(in), dimension(3,3,cells(1),cells(2),cells3) :: field real(pReal), intent(in), dimension(3,3) :: fieldAim !< desired average value of the field after convolution - complex(pReal), dimension(3,3) :: temp33_cmplx, xiDyad_cmplx - real(pReal), dimension(6,6) :: A, A_inv + real(pReal), dimension(3,3,cells(1),cells(2),cells3) :: gammaField + complex(pReal), dimension(3,3) :: temp33_cmplx, xiDyad_cmplx + real(pReal), dimension(6,6) :: A, A_inv integer :: & i, j, k, & l, m, n, o @@ -520,8 +522,11 @@ subroutine utilities_fourierGammaConvolution(fieldAim) print'(/,1x,a)', '... doing gamma convolution ...............................................' flush(IO_STDOUT) - call utilities_FFTtensorForward() -!-------------------------------------------------------------------------------------------------- + tensorField_real(1:3,1:3,cells(1)+1:cells1Red*2,1:cells(2),1:cells3) = 0.0_pReal + tensorField_real(1:3,1:3,1:cells(1), 1:cells(2),1:cells3) = field + call fftw_mpi_execute_dft_r2c(planTensorForth,tensorField_real,tensorField_fourier) + + !-------------------------------------------------------------------------------------------------- ! do the actual spectral method calculation (mechanical equilibrium) memoryEfficient: if (num%memory_efficient) then !$OMP PARALLEL DO PRIVATE(l,m,n,o,temp33_cmplx,xiDyad_cmplx,A,A_inv,err,gamma_hat) @@ -582,9 +587,10 @@ subroutine utilities_fourierGammaConvolution(fieldAim) end if memoryEfficient if (cells3Offset == 0) tensorField_fourier(1:3,1:3,1,1,1) = cmplx(fieldAim/wgt,0.0_pReal,pReal) - call utilities_FFTtensorBackward() + call fftw_mpi_execute_dft_c2r(planTensorBack,tensorField_fourier,tensorField_real) + gammaField = tensorField_real(1:3,1:3,1:cells(1),1:cells(2),1:cells3)*wgt -end subroutine utilities_fourierGammaConvolution +end function utilities_fourierGammaConvolution !-------------------------------------------------------------------------------------------------- From 7de3da50e7329a1bd961a3f3ea40c2a1adb6ecfb Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sat, 19 Nov 2022 11:48:21 +0100 Subject: [PATCH 29/60] include weighting operation into Gamma operator avoids point-wise multiplication. --- src/grid/spectral_utilities.f90 | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/grid/spectral_utilities.f90 b/src/grid/spectral_utilities.f90 index 9e5282de0..30ea11d26 100644 --- a/src/grid/spectral_utilities.f90 +++ b/src/grid/spectral_utilities.f90 @@ -379,6 +379,7 @@ end subroutine spectral_utilities_init subroutine utilities_updateGamma(C) real(pReal), intent(in), dimension(3,3,3,3) :: C !< input stiffness to store as reference stiffness + complex(pReal), dimension(3,3) :: temp33_cmplx, xiDyad_cmplx real(pReal), dimension(6,6) :: A, A_inv integer :: & @@ -386,7 +387,8 @@ subroutine utilities_updateGamma(C) l, m, n, o logical :: err - C_ref = C + + C_ref = C/wgt if (.not. num%memory_efficient) then gamma_hat = cmplx(0.0_pReal,0.0_pReal,pReal) ! for the singular point and any non invertible A @@ -586,9 +588,9 @@ function utilities_fourierGammaConvolution(field, fieldAim) result(gammaField) !$OMP END PARALLEL DO end if memoryEfficient - if (cells3Offset == 0) tensorField_fourier(1:3,1:3,1,1,1) = cmplx(fieldAim/wgt,0.0_pReal,pReal) + if (cells3Offset == 0) tensorField_fourier(1:3,1:3,1,1,1) = cmplx(fieldAim,0.0_pReal,pReal) call fftw_mpi_execute_dft_c2r(planTensorBack,tensorField_fourier,tensorField_real) - gammaField = tensorField_real(1:3,1:3,1:cells(1),1:cells(2),1:cells3)*wgt + gammaField = tensorField_real(1:3,1:3,1:cells(1),1:cells(2),1:cells3) end function utilities_fourierGammaConvolution @@ -634,8 +636,9 @@ real(pReal) function utilities_divergenceRMS(tensorField) print'(/,1x,a)', '... calculating divergence ................................................' flush(IO_STDOUT) - tensorField_real(1:3,1:3,1:cells(1),1:cells(2),1:cells3) = tensorField - call utilities_FFTtensorforward() + tensorField_real(1:3,1:3,cells(1)+1:cells1Red*2,1:cells(2),1:cells3) = 0.0_pReal + tensorField_real(1:3,1:3,1:cells(1), 1:cells(2),1:cells3) = tensorField + call fftw_mpi_execute_dft_r2c(planTensorForth,tensorField_real,tensorField_fourier) rescaledGeom = cmplx(geomSize/scaledGeomSize,0.0_pReal,pReal) @@ -684,8 +687,9 @@ real(pReal) function utilities_curlRMS(tensorField) print'(/,1x,a)', '... calculating curl ......................................................' flush(IO_STDOUT) - tensorField_real(1:3,1:3,1:cells(1),1:cells(2),1:cells3) = tensorField - call utilities_FFTtensorforward() + tensorField_real(1:3,1:3,cells(1)+1:cells1Red*2,1:cells(2),1:cells3) = 0.0_pReal + tensorField_real(1:3,1:3,1:cells(1), 1:cells(2),1:cells3) = tensorField + call fftw_mpi_execute_dft_r2c(planTensorForth,tensorField_real,tensorField_fourier) rescaledGeom = cmplx(geomSize/scaledGeomSize,0.0_pReal,pReal) @@ -737,7 +741,7 @@ end function utilities_curlRMS !-------------------------------------------------------------------------------------------------- -!> @brief calculates mask compliance tensor used to adjust F to fullfill stress BC +!> @brief Calculate masked compliance tensor used to adjust F to fullfill stress BC. !-------------------------------------------------------------------------------------------------- function utilities_maskedCompliance(rot_BC,mask_stress,C) From ad3c18b29b25b19d5fc5ed50eb87b6e18cfc6179 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sat, 19 Nov 2022 12:24:16 +0100 Subject: [PATCH 30/60] avoid use of global variables --- src/grid/grid_damage_spectral.f90 | 10 +++---- src/grid/grid_mech_spectral_basic.f90 | 2 +- src/grid/grid_mech_spectral_polarisation.f90 | 2 +- src/grid/grid_thermal_spectral.f90 | 10 +++---- src/grid/spectral_utilities.f90 | 29 ++++++++++++-------- 5 files changed, 27 insertions(+), 26 deletions(-) diff --git a/src/grid/grid_damage_spectral.f90 b/src/grid/grid_damage_spectral.f90 index f09992f55..6e88ea55a 100644 --- a/src/grid/grid_damage_spectral.f90 +++ b/src/grid/grid_damage_spectral.f90 @@ -318,16 +318,14 @@ subroutine formResidual(in,x_scal,r,dummy,err_PETSc) ce = 0 do k = 1, cells3; do j = 1, cells(2); do i = 1,cells(1) ce = ce + 1 - scalarField_real(i,j,k) = params%Delta_t*(scalarField_real(i,j,k) + homogenization_f_phi(phi_current(i,j,k),ce)) & - + homogenization_mu_phi(ce)*(phi_lastInc(i,j,k) - phi_current(i,j,k)) & - + mu_ref*phi_current(i,j,k) + r(i,j,k) = params%Delta_t*(scalarField_real(i,j,k) + homogenization_f_phi(phi_current(i,j,k),ce)) & + + homogenization_mu_phi(ce)*(phi_lastInc(i,j,k) - phi_current(i,j,k)) & + + mu_ref*phi_current(i,j,k) end do; end do; end do - call utilities_fourierGreenConvolution(K_ref, mu_ref, params%Delta_t) - !-------------------------------------------------------------------------------------------------- ! constructing residual - r = max(min(scalarField_real(1:cells(1),1:cells(2),1:cells3),phi_lastInc),num%residualStiffness) & + r = max(min(utilities_GreenConvolution(r, K_ref, mu_ref, params%Delta_t),phi_lastInc),num%residualStiffness) & - phi_current err_PETSc = 0 diff --git a/src/grid/grid_mech_spectral_basic.f90 b/src/grid/grid_mech_spectral_basic.f90 index 1ec6d334c..cab3d4c7b 100644 --- a/src/grid/grid_mech_spectral_basic.f90 +++ b/src/grid/grid_mech_spectral_basic.f90 @@ -546,7 +546,7 @@ subroutine formResidual(in, F, & F_aim = F_aim - deltaF_aim err_BC = maxval(abs(merge(.0_pReal,P_av - P_aim,params%stress_mask))) - r = utilities_fourierGammaConvolution(r,params%rotation_BC%rotate(deltaF_aim,active=.true.)) ! convolution of Gamma and tensorField_fourier + r = utilities_GammaConvolution(r,params%rotation_BC%rotate(deltaF_aim,active=.true.)) end subroutine formResidual diff --git a/src/grid/grid_mech_spectral_polarisation.f90 b/src/grid/grid_mech_spectral_polarisation.f90 index 235bb873e..90e6d346f 100644 --- a/src/grid/grid_mech_spectral_polarisation.f90 +++ b/src/grid/grid_mech_spectral_polarisation.f90 @@ -621,7 +621,7 @@ subroutine formResidual(in, FandF_tau, & !-------------------------------------------------------------------------------------------------- ! constructing residual r_F_tau = num%beta*F & - - utilities_fourierGammaConvolution(r_F_tau,params%rotation_BC%rotate(num%beta*F_aim,active=.true.)) + - utilities_GammaConvolution(r_F_tau,params%rotation_BC%rotate(num%beta*F_aim,active=.true.)) !-------------------------------------------------------------------------------------------------- ! evaluate constitutive response diff --git a/src/grid/grid_thermal_spectral.f90 b/src/grid/grid_thermal_spectral.f90 index c6b190254..0f970c8da 100644 --- a/src/grid/grid_thermal_spectral.f90 +++ b/src/grid/grid_thermal_spectral.f90 @@ -341,17 +341,15 @@ subroutine formResidual(in,x_scal,r,dummy,err_PETSc) ce = 0 do k = 1, cells3; do j = 1, cells(2); do i = 1,cells(1) ce = ce + 1 - scalarField_real(i,j,k) = params%Delta_t*(scalarField_real(i,j,k) + homogenization_f_T(ce)) & - + homogenization_mu_T(ce) * (T_lastInc(i,j,k) - T_current(i,j,k)) & - + mu_ref*T_current(i,j,k) + r(i,j,k) = params%Delta_t*(scalarField_real(i,j,k) + homogenization_f_T(ce)) & + + homogenization_mu_T(ce) * (T_lastInc(i,j,k) - T_current(i,j,k)) & + + mu_ref*T_current(i,j,k) end do; end do; end do - call utilities_fourierGreenConvolution(K_ref, mu_ref, params%Delta_t) - !-------------------------------------------------------------------------------------------------- ! constructing residual r = T_current & - - scalarField_real(1:cells(1),1:cells(2),1:cells3) + - utilities_GreenConvolution(r, K_ref, mu_ref, params%Delta_t) err_PETSc = 0 end subroutine formResidual diff --git a/src/grid/spectral_utilities.f90 b/src/grid/spectral_utilities.f90 index 30ea11d26..7bccfc0b0 100644 --- a/src/grid/spectral_utilities.f90 +++ b/src/grid/spectral_utilities.f90 @@ -116,8 +116,8 @@ module spectral_utilities public :: & spectral_utilities_init, & utilities_updateGamma, & - utilities_fourierGammaConvolution, & - utilities_fourierGreenConvolution, & + utilities_GammaConvolution, & + utilities_GreenConvolution, & utilities_divergenceRMS, & utilities_curlRMS, & utilities_fourierScalarGradient, & @@ -507,7 +507,7 @@ end subroutine utilities_FFTvectorBackward !-------------------------------------------------------------------------------------------------- !> @brief doing convolution gamma_hat * field_real, ensuring that average value = fieldAim !-------------------------------------------------------------------------------------------------- -function utilities_fourierGammaConvolution(field, fieldAim) result(gammaField) +function utilities_GammaConvolution(field, fieldAim) result(gammaField) real(pReal), intent(in), dimension(3,3,cells(1),cells(2),cells3) :: field real(pReal), intent(in), dimension(3,3) :: fieldAim !< desired average value of the field after convolution @@ -528,8 +528,6 @@ function utilities_fourierGammaConvolution(field, fieldAim) result(gammaField) tensorField_real(1:3,1:3,1:cells(1), 1:cells(2),1:cells3) = field call fftw_mpi_execute_dft_r2c(planTensorForth,tensorField_real,tensorField_fourier) - !-------------------------------------------------------------------------------------------------- -! do the actual spectral method calculation (mechanical equilibrium) memoryEfficient: if (num%memory_efficient) then !$OMP PARALLEL DO PRIVATE(l,m,n,o,temp33_cmplx,xiDyad_cmplx,A,A_inv,err,gamma_hat) do j = 1, cells2; do k = 1, cells(3); do i = 1, cells1Red @@ -592,22 +590,27 @@ function utilities_fourierGammaConvolution(field, fieldAim) result(gammaField) call fftw_mpi_execute_dft_c2r(planTensorBack,tensorField_fourier,tensorField_real) gammaField = tensorField_real(1:3,1:3,1:cells(1),1:cells(2),1:cells3) -end function utilities_fourierGammaConvolution +end function utilities_GammaConvolution !-------------------------------------------------------------------------------------------------- -!> @brief doing convolution DamageGreenOp_hat * field_real +!> @brief Convolution of Greens' operator for damage/thermal. !-------------------------------------------------------------------------------------------------- -subroutine utilities_fourierGreenConvolution(D_ref, mu_ref, Delta_t) +function utilities_GreenConvolution(field, D_ref, mu_ref, Delta_t) result(greenField) + real(pReal), intent(in), dimension(cells(1),cells(2),cells3) :: field real(pReal), dimension(3,3), intent(in) :: D_ref real(pReal), intent(in) :: mu_ref, Delta_t + real(pReal), dimension(cells(1),cells(2),cells3) :: greenField + complex(pReal) :: GreenOp_hat integer :: i, j, k -!-------------------------------------------------------------------------------------------------- -! do the actual spectral method calculation - call utilities_FFTscalarForward() + + scalarField_real(cells(1)+1:cells1Red*2,1:cells(2),1:cells3) = 0.0_pReal + scalarField_real(1:cells(1), 1:cells(2),1:cells3) = field + call fftw_mpi_execute_dft_r2c(planScalarForth,scalarField_real,scalarField_fourier) + !$OMP PARALLEL DO PRIVATE(GreenOp_hat) do j = 1, cells2; do k = 1, cells(3); do i = 1, cells1Red GreenOp_hat = cmplx(1.0_pReal,0.0_pReal,pReal) & @@ -618,7 +621,9 @@ subroutine utilities_fourierGreenConvolution(D_ref, mu_ref, Delta_t) !$OMP END PARALLEL DO call utilities_FFTscalarBackward() -end subroutine utilities_fourierGreenConvolution + greenField = scalarField_real(1:cells(1),1:cells(2),1:cells3) + +end function utilities_GreenConvolution !-------------------------------------------------------------------------------------------------- From f22ff8fa257866cc181bc2a6210309fca4e397b5 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sat, 19 Nov 2022 12:36:56 +0100 Subject: [PATCH 31/60] avoid state-changing functions requires explicit padding, i.e. a little bit of code duplication --- src/grid/spectral_utilities.f90 | 103 ++++++++------------------------ 1 file changed, 24 insertions(+), 79 deletions(-) diff --git a/src/grid/spectral_utilities.f90 b/src/grid/spectral_utilities.f90 index 7bccfc0b0..e353b7fb6 100644 --- a/src/grid/spectral_utilities.f90 +++ b/src/grid/spectral_utilities.f90 @@ -430,68 +430,6 @@ subroutine utilities_updateGamma(C) end subroutine utilities_updateGamma -!-------------------------------------------------------------------------------------------------- -!> @brief forward FFT of data in field_real to field_fourier -!> @details Does an unweighted FFT transform from real to complex. Extra padding entries are set -! to 0.0 -!-------------------------------------------------------------------------------------------------- -subroutine utilities_FFTtensorForward() - - tensorField_real(1:3,1:3,cells(1)+1:cells1Red*2,:,:) = 0.0_pReal - call fftw_mpi_execute_dft_r2c(planTensorForth,tensorField_real,tensorField_fourier) - -end subroutine utilities_FFTtensorForward - - -!-------------------------------------------------------------------------------------------------- -!> @brief backward FFT of data in field_fourier to field_real -!> @details Does an weighted inverse FFT transform from complex to real -!-------------------------------------------------------------------------------------------------- -subroutine utilities_FFTtensorBackward() - - call fftw_mpi_execute_dft_c2r(planTensorBack,tensorField_fourier,tensorField_real) - tensorField_real = tensorField_real * wgt ! normalize the result by number of elements - -end subroutine utilities_FFTtensorBackward - -!-------------------------------------------------------------------------------------------------- -!> @brief forward FFT of data in scalarField_real to scalarField_fourier -!> @details Does an unweighted FFT transform from real to complex. Extra padding entries are set -! to 0.0 -!-------------------------------------------------------------------------------------------------- -subroutine utilities_FFTscalarForward() - - scalarField_real(cells(1)+1:cells1Red*2,:,:) = 0.0_pReal - call fftw_mpi_execute_dft_r2c(planScalarForth,scalarField_real,scalarField_fourier) - -end subroutine utilities_FFTscalarForward - - -!-------------------------------------------------------------------------------------------------- -!> @brief backward FFT of data in scalarField_fourier to scalarField_real -!> @details Does an weighted inverse FFT transform from complex to real -!-------------------------------------------------------------------------------------------------- -subroutine utilities_FFTscalarBackward() - - call fftw_mpi_execute_dft_c2r(planScalarBack,scalarField_fourier,scalarField_real) - scalarField_real = scalarField_real * wgt ! normalize the result by number of elements - -end subroutine utilities_FFTscalarBackward - - -!-------------------------------------------------------------------------------------------------- -!> @brief forward FFT of data in field_real to field_fourier with highest freqs. removed -!> @details Does an unweighted FFT transform from real to complex. Extra padding entries are set -! to 0.0 -!-------------------------------------------------------------------------------------------------- -subroutine utilities_FFTvectorForward() - - vectorField_real(1:3,cells(1)+1:cells1Red*2,:,:) = 0.0_pReal - call fftw_mpi_execute_dft_r2c(planVectorForth,vectorField_real,vectorField_fourier) - -end subroutine utilities_FFTvectorForward - - !-------------------------------------------------------------------------------------------------- !> @brief backward FFT of data in field_fourier to field_real !> @details Does an weighted inverse FFT transform from complex to real @@ -619,7 +557,8 @@ function utilities_GreenConvolution(field, D_ref, mu_ref, Delta_t) result(greenF scalarField_fourier(i,k,j) = scalarField_fourier(i,k,j)*GreenOp_hat end do; end do; end do !$OMP END PARALLEL DO - call utilities_FFTscalarBackward() + call fftw_mpi_execute_dft_c2r(planScalarBack,scalarField_fourier,scalarField_real) + scalarField_real = scalarField_real * wgt ! normalize the result by number of elements greenField = scalarField_real(1:cells(1),1:cells(2),1:cells3) @@ -823,11 +762,13 @@ subroutine utilities_fourierScalarGradient() integer :: i, j, k - call utilities_FFTscalarForward() + scalarField_real(cells(1)+1:cells1Red*2,:,:) = 0.0_pReal + call fftw_mpi_execute_dft_r2c(planScalarForth,scalarField_real,scalarField_fourier) do j = 1, cells2; do k = 1, cells(3); do i = 1,cells1Red vectorField_fourier(1:3,i,k,j) = scalarField_fourier(i,k,j)*xi1st(1:3,i,k,j) ! ToDo: no -conjg? end do; end do; end do - call utilities_FFTvectorBackward() + call fftw_mpi_execute_dft_c2r(planVectorBack,vectorField_fourier,vectorField_real) + vectorField_real = vectorField_real * wgt ! normalize the result by number of elements end subroutine utilities_fourierScalarGradient @@ -837,10 +778,12 @@ end subroutine utilities_fourierScalarGradient !-------------------------------------------------------------------------------------------------- subroutine utilities_fourierVectorDivergence() - call utilities_FFTvectorForward() + vectorField_real(1:3,cells(1)+1:cells1Red*2,:,:) = 0.0_pReal + call fftw_mpi_execute_dft_r2c(planVectorForth,vectorField_real,vectorField_fourier) scalarField_fourier(1:cells1Red,1:cells(3),1:cells2) = sum(vectorField_fourier(1:3,1:cells1Red,1:cells(3),1:cells2) & *conjg(-xi1st),1) - call utilities_FFTscalarBackward() + call fftw_mpi_execute_dft_c2r(planScalarBack,scalarField_fourier,scalarField_real) + scalarField_real = scalarField_real * wgt ! normalize the result by number of elements end subroutine utilities_fourierVectorDivergence @@ -1075,8 +1018,9 @@ subroutine utilities_updateCoords(F) step = geomSize/real(cells, pReal) !-------------------------------------------------------------------------------------------------- ! integration in Fourier space to get fluctuations of cell center discplacements - tensorField_real(1:3,1:3,1:cells(1),1:cells(2),1:cells3) = F - call utilities_FFTtensorForward() + tensorField_real(1:3,1:3,1:cells(1), 1:cells(2),1:cells3) = F + tensorField_real(1:3,1:3,cells(1)+1:cells1Red*2,1:cells(2),1:cells3) = 0.0_pReal + call fftw_mpi_execute_dft_r2c(planTensorForth,tensorField_real,tensorField_fourier) !$OMP PARALLEL DO do j = 1, cells2; do k = 1, cells(3); do i = 1, cells1Red @@ -1089,7 +1033,8 @@ subroutine utilities_updateCoords(F) end do; end do; end do !$OMP END PARALLEL DO - call utilities_FFTvectorBackward() + call fftw_mpi_execute_dft_c2r(planVectorBack,vectorField_fourier,vectorField_real) + vectorField_real = vectorField_real * wgt ! normalize the result by number of elements !-------------------------------------------------------------------------------------------------- ! average F @@ -1183,38 +1128,38 @@ subroutine selfTest() call random_number(tensorField_real) tensorField_real(1:3,1:3,cells(1)+1:cells1Red*2,:,:) = 0.0_pReal tensorField_real_ = tensorField_real - call utilities_FFTtensorForward() + call fftw_mpi_execute_dft_r2c(planTensorForth,tensorField_real,tensorField_fourier) if (worldsize==1) then if (any(dNeq(sum(sum(sum(tensorField_real_,dim=5),dim=4),dim=3)/tensorField_fourier(:,:,1,1,1)%re,1.0_pReal,1.0e-12_pReal))) & error stop 'tensorField avg' endif - call utilities_FFTtensorBackward() + call fftw_mpi_execute_dft_c2r(planTensorBack,tensorField_fourier,tensorField_real) tensorField_real(1:3,1:3,cells(1)+1:cells1Red*2,:,:) = 0.0_pReal - if (maxval(abs(tensorField_real_ - tensorField_real))>5.0e-15_pReal) error stop 'tensorField' + if (maxval(abs(tensorField_real_ - tensorField_real*wgt))>5.0e-15_pReal) error stop 'tensorField' call random_number(vectorField_real) vectorField_real(1:3,cells(1)+1:cells1Red*2,:,:) = 0.0_pReal vectorField_real_ = vectorField_real - call utilities_FFTvectorForward() + call fftw_mpi_execute_dft_r2c(planVectorForth,vectorField_real,vectorField_fourier) if (worldsize==1) then if (any(dNeq(sum(sum(sum(vectorField_real_,dim=4),dim=3),dim=2)/vectorField_fourier(:,1,1,1)%re,1.0_pReal,1.0e-12_pReal))) & error stop 'vector avg' endif - call utilities_FFTvectorBackward() + call fftw_mpi_execute_dft_c2r(planVectorBack,vectorField_fourier,vectorField_real) vectorField_real(1:3,cells(1)+1:cells1Red*2,:,:) = 0.0_pReal - if (maxval(abs(vectorField_real_ - vectorField_real))>5.0e-15_pReal) error stop 'vectorField' + if (maxval(abs(vectorField_real_ - vectorField_real*wgt))>5.0e-15_pReal) error stop 'vectorField' call random_number(scalarField_real) scalarField_real(cells(1)+1:cells1Red*2,:,:) = 0.0_pReal scalarField_real_ = scalarField_real - call utilities_FFTscalarForward() + call fftw_mpi_execute_dft_r2c(planScalarForth,scalarField_real,scalarField_fourier) if (worldsize==1) then if (dNeq(sum(sum(sum(scalarField_real_,dim=3),dim=2),dim=1)/scalarField_fourier(1,1,1)%re,1.0_pReal,1.0e-12_pReal)) & error stop 'scalar avg' endif - call utilities_FFTscalarBackward() + call fftw_mpi_execute_dft_c2r(planScalarBack,scalarField_fourier,scalarField_real) scalarField_real(cells(1)+1:cells1Red*2,:,:) = 0.0_pReal - if (maxval(abs(scalarField_real_ - scalarField_real))>5.0e-15_pReal) error stop 'scalarField' + if (maxval(abs(scalarField_real_ - scalarField_real*wgt))>5.0e-15_pReal) error stop 'scalarField' end subroutine selfTest From 6db3b72c89c3affd859599eccb5d0349da62e8a4 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sat, 19 Nov 2022 13:05:12 +0100 Subject: [PATCH 32/60] avoid global variables extra memory (one vector field) required --- src/grid/grid_damage_spectral.f90 | 10 +++--- src/grid/grid_thermal_spectral.f90 | 10 +++--- src/grid/spectral_utilities.f90 | 53 +++++++++++++++++------------- 3 files changed, 41 insertions(+), 32 deletions(-) diff --git a/src/grid/grid_damage_spectral.f90 b/src/grid/grid_damage_spectral.f90 index 6e88ea55a..3e514b960 100644 --- a/src/grid/grid_damage_spectral.f90 +++ b/src/grid/grid_damage_spectral.f90 @@ -302,23 +302,23 @@ subroutine formResidual(in,x_scal,r,dummy,err_PETSc) PetscErrorCode, intent(out) :: err_PETSc integer :: i, j, k, ce + real(pReal), dimension(3,cells(1),cells(2),cells3) :: vectorField phi_current = x_scal !-------------------------------------------------------------------------------------------------- ! evaluate polarization field - scalarField_real(1:cells(1),1:cells(2),1:cells3) = phi_current - call utilities_fourierScalarGradient() + vectorField = utilities_ScalarGradient(phi_current) ce = 0 do k = 1, cells3; do j = 1, cells(2); do i = 1,cells(1) ce = ce + 1 - vectorField_real(1:3,i,j,k) = matmul(homogenization_K_phi(ce) - K_ref, vectorField_real(1:3,i,j,k)) + vectorField(1:3,i,j,k) = matmul(homogenization_K_phi(ce) - K_ref, vectorField(1:3,i,j,k)) end do; end do; end do - call utilities_fourierVectorDivergence() + r = utilities_VectorDivergence(vectorField) ce = 0 do k = 1, cells3; do j = 1, cells(2); do i = 1,cells(1) ce = ce + 1 - r(i,j,k) = params%Delta_t*(scalarField_real(i,j,k) + homogenization_f_phi(phi_current(i,j,k),ce)) & + r(i,j,k) = params%Delta_t*(r(i,j,k) + homogenization_f_phi(phi_current(i,j,k),ce)) & + homogenization_mu_phi(ce)*(phi_lastInc(i,j,k) - phi_current(i,j,k)) & + mu_ref*phi_current(i,j,k) end do; end do; end do diff --git a/src/grid/grid_thermal_spectral.f90 b/src/grid/grid_thermal_spectral.f90 index 0f970c8da..b1dde568f 100644 --- a/src/grid/grid_thermal_spectral.f90 +++ b/src/grid/grid_thermal_spectral.f90 @@ -325,23 +325,23 @@ subroutine formResidual(in,x_scal,r,dummy,err_PETSc) PetscErrorCode, intent(out) :: err_PETSc integer :: i, j, k, ce + real(pReal), dimension(3,cells(1),cells(2),cells3) :: vectorField T_current = x_scal !-------------------------------------------------------------------------------------------------- ! evaluate polarization field - scalarField_real(1:cells(1),1:cells(2),1:cells3) = T_current - call utilities_fourierScalarGradient() + vectorField = utilities_ScalarGradient(T_current) ce = 0 do k = 1, cells3; do j = 1, cells(2); do i = 1,cells(1) ce = ce + 1 - vectorField_real(1:3,i,j,k) = matmul(homogenization_K_T(ce) - K_ref, vectorField_real(1:3,i,j,k)) + vectorField(1:3,i,j,k) = matmul(homogenization_K_T(ce) - K_ref, vectorField(1:3,i,j,k)) end do; end do; end do - call utilities_fourierVectorDivergence() + r = utilities_VectorDivergence(vectorField) ce = 0 do k = 1, cells3; do j = 1, cells(2); do i = 1,cells(1) ce = ce + 1 - r(i,j,k) = params%Delta_t*(scalarField_real(i,j,k) + homogenization_f_T(ce)) & + r(i,j,k) = params%Delta_t*(r(i,j,k) + homogenization_f_T(ce)) & + homogenization_mu_T(ce) * (T_lastInc(i,j,k) - T_current(i,j,k)) & + mu_ref*T_current(i,j,k) end do; end do; end do diff --git a/src/grid/spectral_utilities.f90 b/src/grid/spectral_utilities.f90 index e353b7fb6..aebb7fa15 100644 --- a/src/grid/spectral_utilities.f90 +++ b/src/grid/spectral_utilities.f90 @@ -42,16 +42,16 @@ module spectral_utilities !-------------------------------------------------------------------------------------------------- ! variables storing information for spectral method and FFTW - real(C_DOUBLE), dimension(:,:,:,:,:), pointer :: tensorField_real !< tensor field in real space - real(C_DOUBLE), public, dimension(:,:,:,:), pointer :: vectorField_real !< vector field in real space - real(C_DOUBLE), public, dimension(:,:,:), pointer :: scalarField_real !< scalar field in real space - complex(C_DOUBLE_COMPLEX), dimension(:,:,:,:,:), pointer :: tensorField_fourier !< tensor field in Fourier space - complex(C_DOUBLE_COMPLEX), dimension(:,:,:,:), pointer :: vectorField_fourier !< vector field in Fourier space - complex(C_DOUBLE_COMPLEX), dimension(:,:,:), pointer :: scalarField_fourier !< scalar field in Fourier space - complex(pReal), dimension(:,:,:,:,:,:,:), allocatable :: gamma_hat !< gamma operator (field) for spectral method - complex(pReal), dimension(:,:,:,:), allocatable :: xi1st !< wave vector field for first derivatives - complex(pReal), dimension(:,:,:,:), allocatable :: xi2nd !< wave vector field for second derivatives - real(pReal), dimension(3,3,3,3) :: C_ref !< mechanic reference stiffness + real(C_DOUBLE), dimension(:,:,:,:,:), pointer :: tensorField_real !< tensor field in real space + real(C_DOUBLE), dimension(:,:,:,:), pointer :: vectorField_real !< vector field in real space + real(C_DOUBLE), dimension(:,:,:), pointer :: scalarField_real !< scalar field in real space + complex(C_DOUBLE_COMPLEX), dimension(:,:,:,:,:), pointer :: tensorField_fourier !< tensor field in Fourier space + complex(C_DOUBLE_COMPLEX), dimension(:,:,:,:), pointer :: vectorField_fourier !< vector field in Fourier space + complex(C_DOUBLE_COMPLEX), dimension(:,:,:), pointer :: scalarField_fourier !< scalar field in Fourier space + complex(pReal), dimension(:,:,:,:,:,:,:), allocatable :: gamma_hat !< gamma operator (field) for spectral method + complex(pReal), dimension(:,:,:,:), allocatable :: xi1st !< wave vector field for first derivatives + complex(pReal), dimension(:,:,:,:), allocatable :: xi2nd !< wave vector field for second derivatives + real(pReal), dimension(3,3,3,3) :: C_ref !< mechanic reference stiffness !-------------------------------------------------------------------------------------------------- @@ -120,8 +120,8 @@ module spectral_utilities utilities_GreenConvolution, & utilities_divergenceRMS, & utilities_curlRMS, & - utilities_fourierScalarGradient, & - utilities_fourierVectorDivergence, & + utilities_ScalarGradient, & + utilities_VectorDivergence, & utilities_maskedCompliance, & utilities_constitutiveResponse, & utilities_calculateRate, & @@ -755,37 +755,46 @@ end function utilities_maskedCompliance !-------------------------------------------------------------------------------------------------- -!> @brief calculate scalar gradient in fourier field +!> @brief Calculate gradient of scalar field. !-------------------------------------------------------------------------------------------------- -subroutine utilities_fourierScalarGradient() +function utilities_ScalarGradient(field) result(grad) + + real(pReal), intent(in), dimension( cells(1),cells(2),cells3) :: field + real(pReal), dimension(3,cells(1),cells(2),cells3) :: grad integer :: i, j, k - scalarField_real(cells(1)+1:cells1Red*2,:,:) = 0.0_pReal + scalarField_real(cells(1)+1:cells1Red*2,1:cells(2),1:cells3) = 0.0_pReal + scalarField_real(1:cells(1), 1:cells(2),1:cells3) = field call fftw_mpi_execute_dft_r2c(planScalarForth,scalarField_real,scalarField_fourier) do j = 1, cells2; do k = 1, cells(3); do i = 1,cells1Red vectorField_fourier(1:3,i,k,j) = scalarField_fourier(i,k,j)*xi1st(1:3,i,k,j) ! ToDo: no -conjg? end do; end do; end do call fftw_mpi_execute_dft_c2r(planVectorBack,vectorField_fourier,vectorField_real) - vectorField_real = vectorField_real * wgt ! normalize the result by number of elements + grad = vectorField_real(1:3,1:cells(1),1:cells(2),1:cells3)*wgt -end subroutine utilities_fourierScalarGradient +end function utilities_ScalarGradient !-------------------------------------------------------------------------------------------------- -!> @brief calculate vector divergence in fourier field +!> @brief Calculate divergence of vector field. !-------------------------------------------------------------------------------------------------- -subroutine utilities_fourierVectorDivergence() +function utilities_VectorDivergence(field) result(div) - vectorField_real(1:3,cells(1)+1:cells1Red*2,:,:) = 0.0_pReal + real(pReal), intent(in), dimension(3,cells(1),cells(2),cells3) :: field + real(pReal), dimension( cells(1),cells(2),cells3) :: div + + + vectorField_real(1:3,cells(1)+1:cells1Red*2,1:cells(2),1:cells3) = 0.0_pReal + vectorField_real(1:3,1:cells(1), 1:cells(2),1:cells3) = field call fftw_mpi_execute_dft_r2c(planVectorForth,vectorField_real,vectorField_fourier) scalarField_fourier(1:cells1Red,1:cells(3),1:cells2) = sum(vectorField_fourier(1:3,1:cells1Red,1:cells(3),1:cells2) & *conjg(-xi1st),1) call fftw_mpi_execute_dft_c2r(planScalarBack,scalarField_fourier,scalarField_real) - scalarField_real = scalarField_real * wgt ! normalize the result by number of elements + div = scalarField_real(1:cells(1),1:cells(2),1:cells3)*wgt -end subroutine utilities_fourierVectorDivergence +end function utilities_VectorDivergence !-------------------------------------------------------------------------------------------------- From eb226d237f2070858aaec46b7da24c605e9057e0 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sat, 19 Nov 2022 13:25:21 +0100 Subject: [PATCH 33/60] better readable --- src/grid/spectral_utilities.f90 | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/grid/spectral_utilities.f90 b/src/grid/spectral_utilities.f90 index aebb7fa15..3a3582f7d 100644 --- a/src/grid/spectral_utilities.f90 +++ b/src/grid/spectral_utilities.f90 @@ -300,8 +300,8 @@ subroutine spectral_utilities_init() !-------------------------------------------------------------------------------------------------- ! allocation - allocate (xi1st (3,cells1Red,cells(3),cells2),source = cmplx(0.0_pReal,0.0_pReal,pReal)) ! frequencies for first derivatives, only half the size for first dimension - allocate (xi2nd (3,cells1Red,cells(3),cells2),source = cmplx(0.0_pReal,0.0_pReal,pReal)) ! frequencies for second derivatives, only half the size for first dimension + allocate (xi1st (3,cells1Red,cells(3),cells2),source = cmplx(0.0_pReal,0.0_pReal,pReal)) ! frequencies for first derivatives, only half the size for first dimension + allocate (xi2nd (3,cells1Red,cells(3),cells2),source = cmplx(0.0_pReal,0.0_pReal,pReal)) ! frequencies for second derivatives, only half the size for first dimension !-------------------------------------------------------------------------------------------------- ! tensor MPI fftw plans @@ -525,6 +525,7 @@ function utilities_GammaConvolution(field, fieldAim) result(gammaField) end if memoryEfficient if (cells3Offset == 0) tensorField_fourier(1:3,1:3,1,1,1) = cmplx(fieldAim,0.0_pReal,pReal) + call fftw_mpi_execute_dft_c2r(planTensorBack,tensorField_fourier,tensorField_real) gammaField = tensorField_real(1:3,1:3,1:cells(1),1:cells(2),1:cells3) @@ -557,10 +558,9 @@ function utilities_GreenConvolution(field, D_ref, mu_ref, Delta_t) result(greenF scalarField_fourier(i,k,j) = scalarField_fourier(i,k,j)*GreenOp_hat end do; end do; end do !$OMP END PARALLEL DO - call fftw_mpi_execute_dft_c2r(planScalarBack,scalarField_fourier,scalarField_real) - scalarField_real = scalarField_real * wgt ! normalize the result by number of elements - greenField = scalarField_real(1:cells(1),1:cells(2),1:cells3) + call fftw_mpi_execute_dft_c2r(planScalarBack,scalarField_fourier,scalarField_real) + greenField = scalarField_real(1:cells(1),1:cells(2),1:cells3) * wgt end function utilities_GreenConvolution @@ -1025,12 +1025,19 @@ subroutine utilities_updateCoords(F) step = geomSize/real(cells, pReal) - !-------------------------------------------------------------------------------------------------- - ! integration in Fourier space to get fluctuations of cell center discplacements + tensorField_real(1:3,1:3,1:cells(1), 1:cells(2),1:cells3) = F tensorField_real(1:3,1:3,cells(1)+1:cells1Red*2,1:cells(2),1:cells3) = 0.0_pReal call fftw_mpi_execute_dft_r2c(planTensorForth,tensorField_real,tensorField_fourier) + !-------------------------------------------------------------------------------------------------- + ! average F + if (cells3Offset == 0) Favg = tensorField_fourier(1:3,1:3,1,1,1)%re*wgt + call MPI_Bcast(Favg,9_MPI_INTEGER_KIND,MPI_DOUBLE,0_MPI_INTEGER_KIND,MPI_COMM_WORLD,err_MPI) + if (err_MPI /= 0_MPI_INTEGER_KIND) error stop 'MPI error' + + !-------------------------------------------------------------------------------------------------- + ! integration in Fourier space to get fluctuations of cell center discplacements !$OMP PARALLEL DO do j = 1, cells2; do k = 1, cells(3); do i = 1, cells1Red if (any([i,j+cells2Offset,k] /= 1)) then @@ -1045,12 +1052,6 @@ subroutine utilities_updateCoords(F) call fftw_mpi_execute_dft_c2r(planVectorBack,vectorField_fourier,vectorField_real) vectorField_real = vectorField_real * wgt ! normalize the result by number of elements - !-------------------------------------------------------------------------------------------------- - ! average F - if (cells3Offset == 0) Favg = tensorField_fourier(1:3,1:3,1,1,1)%re*wgt - call MPI_Bcast(Favg,9_MPI_INTEGER_KIND,MPI_DOUBLE,0_MPI_INTEGER_KIND,MPI_COMM_WORLD,err_MPI) - if (err_MPI /= 0_MPI_INTEGER_KIND) error stop 'MPI error' - !-------------------------------------------------------------------------------------------------- ! pad cell center fluctuations along z-direction (needed when running MPI simulation) IPfluct_padded(1:3,1:cells(1),1:cells(2),2:cells3+1) = vectorField_real(1:3,1:cells(1),1:cells(2),1:cells3) From 9b80ff623b687a3be84b2876982ede91bd20004c Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sat, 19 Nov 2022 13:35:55 +0100 Subject: [PATCH 34/60] faster operation explicit weighting not needed --- src/grid/spectral_utilities.f90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/grid/spectral_utilities.f90 b/src/grid/spectral_utilities.f90 index 3a3582f7d..d5ec36702 100644 --- a/src/grid/spectral_utilities.f90 +++ b/src/grid/spectral_utilities.f90 @@ -552,7 +552,7 @@ function utilities_GreenConvolution(field, D_ref, mu_ref, Delta_t) result(greenF !$OMP PARALLEL DO PRIVATE(GreenOp_hat) do j = 1, cells2; do k = 1, cells(3); do i = 1, cells1Red - GreenOp_hat = cmplx(1.0_pReal,0.0_pReal,pReal) & + GreenOp_hat = cmplx(wgt,0.0_pReal,pReal) & / (cmplx(mu_ref,0.0_pReal,pReal) + cmplx(Delta_t,0.0_pReal,pReal) & * sum(conjg(xi1st(1:3,i,k,j))* matmul(cmplx(D_ref,0.0_pReal,pReal),xi1st(1:3,i,k,j)))) scalarField_fourier(i,k,j) = scalarField_fourier(i,k,j)*GreenOp_hat @@ -560,7 +560,7 @@ function utilities_GreenConvolution(field, D_ref, mu_ref, Delta_t) result(greenF !$OMP END PARALLEL DO call fftw_mpi_execute_dft_c2r(planScalarBack,scalarField_fourier,scalarField_real) - greenField = scalarField_real(1:cells(1),1:cells(2),1:cells3) * wgt + greenField = scalarField_real(1:cells(1),1:cells(2),1:cells3) end function utilities_GreenConvolution From 6907ca60b3268d0262bb611f9765b9faa453af06 Mon Sep 17 00:00:00 2001 From: Philip Eisenlohr Date: Sat, 19 Nov 2022 20:55:23 -0500 Subject: [PATCH 35/60] adjustments to make mypy happy --- python/damask/_configmaterial.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/python/damask/_configmaterial.py b/python/damask/_configmaterial.py index 873577771..d98f277fe 100644 --- a/python/damask/_configmaterial.py +++ b/python/damask/_configmaterial.py @@ -1,6 +1,6 @@ import numpy as np import h5py -from typing import Sequence, Dict, Any, Collection +from typing import Union, Sequence, Dict, Any, Collection from ._typehints import FileHandle from . import Config @@ -513,14 +513,16 @@ class ConfigMaterial(Config): _dim = {'O':(4,),'V_e':(3,3,)} _ex = dict((k, -len(v)) for k, v in _dim.items()) - N,n,shaped = 1,1,{'v': None, - 'phase': None, - 'homogenization': None, - } + N,n = 1,1 + shaped : Dict[str, Union[None,np.ndarray]] = \ + {'v': None, + 'phase': None, + 'homogenization': None, + } for k,v in kwargs.items(): shaped[k] = np.array(v) - s = shaped[k].shape[:_ex.get(k,None)] + s = shaped[k].shape[:_ex.get(k,None)] # type: ignore N = max(N,s[0]) if len(s)>0 else N n = max(n,s[1]) if len(s)>1 else n @@ -544,8 +546,8 @@ class ConfigMaterial(Config): dup = self.copy() dup['material'] = dup['material'] + mat if 'material' in dup else mat - for what in ['phase','homogenization']: - for k in np.unique(shaped[what]): - if not (k is None or k in dup[what]): dup[what][str(k)] = None + for what in [item for item in ['phase','homogenization'] if shaped[item] is not None]: + for k in np.unique(shaped[what]): # type: ignore + if k not in dup[what]: dup[what][str(k)] = None return dup From ef435ee7d1b1d53a5154cb8cc3cea37e55a1a9ec Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Fri, 18 Nov 2022 07:14:05 +0100 Subject: [PATCH 36/60] commonly used variable name --- PRIVATE | 2 +- .../eigen/thermalexpansion_AISI304.yaml | 6 +++--- .../mechanical/eigen/thermalexpansion_Al.yaml | 2 +- .../mechanical/eigen/thermalexpansion_Au.yaml | 2 +- .../eigen/thermalexpansion_C35E.yaml | 6 +++--- .../mechanical/eigen/thermalexpansion_Cu.yaml | 2 +- .../mechanical/eigen/thermalexpansion_Fe.yaml | 2 +- .../eigen/thermalexpansion_Sn-beta.yaml | 12 +++++------ .../mechanical/eigen/thermalexpansion_W.yaml | 2 +- .../eigen/thermalexpansion_X20Cr13.yaml | 4 ++-- ...hase_mechanical_eigen_thermalexpansion.f90 | 20 +++++++++---------- 11 files changed, 30 insertions(+), 30 deletions(-) diff --git a/PRIVATE b/PRIVATE index 7b1ad7672..81f5f24d0 160000 --- a/PRIVATE +++ b/PRIVATE @@ -1 +1 @@ -Subproject commit 7b1ad767256f796f56514d8888027499fe777132 +Subproject commit 81f5f24d076a623e6052c234825c591267915285 diff --git a/examples/config/phase/mechanical/eigen/thermalexpansion_AISI304.yaml b/examples/config/phase/mechanical/eigen/thermalexpansion_AISI304.yaml index bc0db5c5e..d96c253b9 100644 --- a/examples/config/phase/mechanical/eigen/thermalexpansion_AISI304.yaml +++ b/examples/config/phase/mechanical/eigen/thermalexpansion_AISI304.yaml @@ -6,8 +6,8 @@ references: https://doi.org/10.1016/0040-6031(93)80437-F, fit to Fig. 6 (T_min=100K, T_max=1400K) -A_11: 2.068e-08 -A_11,T: 1.579e-09 -A_11,T^2: 3.449e-13 +Alpha_11: 2.068e-08 +Alpha_11,T: 1.579e-09 +Alpha_11,T^2: 3.449e-13 T_ref: 293.15 diff --git a/examples/config/phase/mechanical/eigen/thermalexpansion_Al.yaml b/examples/config/phase/mechanical/eigen/thermalexpansion_Al.yaml index 495680b4e..7f323f710 100644 --- a/examples/config/phase/mechanical/eigen/thermalexpansion_Al.yaml +++ b/examples/config/phase/mechanical/eigen/thermalexpansion_Al.yaml @@ -4,4 +4,4 @@ references: - https://en.wikipedia.org/wiki/Thermal_expansion, 293.15K -A_11: 23.1e-6 +Alpha_11: 23.1e-6 diff --git a/examples/config/phase/mechanical/eigen/thermalexpansion_Au.yaml b/examples/config/phase/mechanical/eigen/thermalexpansion_Au.yaml index a14ac6b0f..b0ff0360d 100644 --- a/examples/config/phase/mechanical/eigen/thermalexpansion_Au.yaml +++ b/examples/config/phase/mechanical/eigen/thermalexpansion_Au.yaml @@ -4,4 +4,4 @@ references: - https://en.wikipedia.org/wiki/Thermal_expansion, 293.15K -A_11: 14.e-6 +Alpha_11: 14.e-6 diff --git a/examples/config/phase/mechanical/eigen/thermalexpansion_C35E.yaml b/examples/config/phase/mechanical/eigen/thermalexpansion_C35E.yaml index 08e9d6894..98937cea8 100644 --- a/examples/config/phase/mechanical/eigen/thermalexpansion_C35E.yaml +++ b/examples/config/phase/mechanical/eigen/thermalexpansion_C35E.yaml @@ -4,8 +4,8 @@ references: - https://commons.wikimedia.org/wiki/File:Coefficient_dilatation_lineique_aciers.svg, fit to image description (Scilab code) -A_11: 12.70371e-6 -A_11,T: 7.54e-9 -A_11,T^2: -1.0e-11 +Alpha_11: 12.70371e-6 +Alpha_11,T: 7.54e-9 +Alpha_11,T^2: -1.0e-11 T_ref: 273.0 diff --git a/examples/config/phase/mechanical/eigen/thermalexpansion_Cu.yaml b/examples/config/phase/mechanical/eigen/thermalexpansion_Cu.yaml index a0a35c955..74418c55c 100644 --- a/examples/config/phase/mechanical/eigen/thermalexpansion_Cu.yaml +++ b/examples/config/phase/mechanical/eigen/thermalexpansion_Cu.yaml @@ -4,4 +4,4 @@ references: - https://en.wikipedia.org/wiki/Thermal_expansion, 293.15K -A_11: 17.e-6 +Alpha_11: 17.e-6 diff --git a/examples/config/phase/mechanical/eigen/thermalexpansion_Fe.yaml b/examples/config/phase/mechanical/eigen/thermalexpansion_Fe.yaml index da8ead4c1..6b64ca1a2 100644 --- a/examples/config/phase/mechanical/eigen/thermalexpansion_Fe.yaml +++ b/examples/config/phase/mechanical/eigen/thermalexpansion_Fe.yaml @@ -4,4 +4,4 @@ references: - https://en.wikipedia.org/wiki/Thermal_expansion, 293.15K -A_11: 11.8e-6 +Alpha_11: 11.8e-6 diff --git a/examples/config/phase/mechanical/eigen/thermalexpansion_Sn-beta.yaml b/examples/config/phase/mechanical/eigen/thermalexpansion_Sn-beta.yaml index f77f79bba..1bbd4c012 100644 --- a/examples/config/phase/mechanical/eigen/thermalexpansion_Sn-beta.yaml +++ b/examples/config/phase/mechanical/eigen/thermalexpansion_Sn-beta.yaml @@ -6,12 +6,12 @@ references: https://doi.org/10.1107/S0365110X62000742, fit to Tab. 2 (T_min=30ºC, T_max=210ºC) -A_11: 1.639e-05 -A_11,T: 1.799e-08 -A_11,T^2: 1.734e-10 +Alpha_11: 1.639e-05 +Alpha_11,T: 1.799e-08 +Alpha_11,T^2: 1.734e-10 -A_33: 3.263e-05 -A_33,T: 1.387e-08 -A_33,T^2: 5.794e-10 +Alpha_33: 3.263e-05 +Alpha_33,T: 1.387e-08 +Alpha_33,T^2: 5.794e-10 T_ref: 293.15 diff --git a/examples/config/phase/mechanical/eigen/thermalexpansion_W.yaml b/examples/config/phase/mechanical/eigen/thermalexpansion_W.yaml index cb29ab270..ca4d2566b 100644 --- a/examples/config/phase/mechanical/eigen/thermalexpansion_W.yaml +++ b/examples/config/phase/mechanical/eigen/thermalexpansion_W.yaml @@ -4,4 +4,4 @@ references: - https://en.wikipedia.org/wiki/Thermal_expansion, 293.15K -A_11: 4.5e-6 +Alpha_11: 4.5e-6 diff --git a/examples/config/phase/mechanical/eigen/thermalexpansion_X20Cr13.yaml b/examples/config/phase/mechanical/eigen/thermalexpansion_X20Cr13.yaml index 1b8f1545b..d4b5d1df9 100644 --- a/examples/config/phase/mechanical/eigen/thermalexpansion_X20Cr13.yaml +++ b/examples/config/phase/mechanical/eigen/thermalexpansion_X20Cr13.yaml @@ -4,7 +4,7 @@ references: - https://commons.wikimedia.org/wiki/File:Coefficient_dilatation_lineique_aciers.svg, fit to image description (Scilab code) -A_11: 11.365e-6 -A_11,T: 5.0e-9 +Alpha_11: 11.365e-6 +Alpha_11,T: 5.0e-9 T_ref: 273.0 diff --git a/src/phase_mechanical_eigen_thermalexpansion.f90 b/src/phase_mechanical_eigen_thermalexpansion.f90 index 7713650ea..ddd495687 100644 --- a/src/phase_mechanical_eigen_thermalexpansion.f90 +++ b/src/phase_mechanical_eigen_thermalexpansion.f90 @@ -9,8 +9,8 @@ submodule(phase:eigen) thermalexpansion type :: tParameters type(tPolynomial) :: & - A_11, & - A_33 + Alpha_11, & + Alpha_33 end type tParameters type(tParameters), dimension(:), allocatable :: param @@ -57,9 +57,9 @@ module function thermalexpansion_init(kinematics_length) result(myKinematics) if (myKinematics(k,p)) then associate(prm => param(kinematics_thermal_expansion_instance(p))) - prm%A_11 = polynomial(kinematics%get_dict(k),'A_11','T') + prm%Alpha_11 = polynomial(kinematics%get_dict(k),'Alpha_11','T') if (any(phase_lattice(p) == ['hP','tI'])) & - prm%A_33 = polynomial(kinematics%get_dict(k),'A_33','T') + prm%Alpha_33 = polynomial(kinematics%get_dict(k),'Alpha_33','T') end associate end if end do @@ -80,7 +80,7 @@ module subroutine thermalexpansion_LiAndItsTangent(Li, dLi_dTstar, ph,me) dLi_dTstar !< derivative of Li with respect to Tstar (4th-order tensor defined to be zero) real(pReal) :: T, dot_T - real(pReal), dimension(3,3) :: A + real(pReal), dimension(3,3) :: Alpha T = thermal_T(ph,me) @@ -88,11 +88,11 @@ module subroutine thermalexpansion_LiAndItsTangent(Li, dLi_dTstar, ph,me) associate(prm => param(kinematics_thermal_expansion_instance(ph))) - A = 0.0_pReal - A(1,1) = prm%A_11%at(T) - if (any(phase_lattice(ph) == ['hP','tI'])) A(3,3) = prm%A_33%at(T) - A = lattice_symmetrize_33(A,phase_lattice(ph)) - Li = dot_T * A + Alpha = 0.0_pReal + Alpha(1,1) = prm%Alpha_11%at(T) + if (any(phase_lattice(ph) == ['hP','tI'])) Alpha(3,3) = prm%Alpha_33%at(T) + Alpha = lattice_symmetrize_33(Alpha,phase_lattice(ph)) + Li = dot_T * Alpha end associate dLi_dTstar = 0.0_pReal From 34fb7e921a4754fa0eb8b5d1953e7c1adaff7504 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sun, 20 Nov 2022 12:58:50 +0100 Subject: [PATCH 37/60] use self-documenting code the comments did not anything that was not clear from the variable/function names --- src/grid/grid_mech_spectral_basic.f90 | 20 ++++++--------- src/grid/grid_mech_spectral_polarisation.f90 | 27 ++++++-------------- 2 files changed, 16 insertions(+), 31 deletions(-) diff --git a/src/grid/grid_mech_spectral_basic.f90 b/src/grid/grid_mech_spectral_basic.f90 index cab3d4c7b..c570e94e7 100644 --- a/src/grid/grid_mech_spectral_basic.f90 +++ b/src/grid/grid_mech_spectral_basic.f90 @@ -519,8 +519,6 @@ subroutine formResidual(in, F, & if (nfuncs == 0 .and. PETScIter == 0) totalIter = -1 ! new increment -!-------------------------------------------------------------------------------------------------- -! begin of new iteration newIteration: if (totalIter <= PETScIter) then totalIter = totalIter + 1 print'(1x,a,3(a,i0))', trim(incInfo), ' @ Iteration ', num%itmin, '≤',totalIter, '≤', num%itmax @@ -531,17 +529,15 @@ subroutine formResidual(in, F, & flush(IO_STDOUT) end if newIteration -!-------------------------------------------------------------------------------------------------- -! evaluate constitutive response - call utilities_constitutiveResponse(r, & ! residuum gets field of first PK stress (to save memory) - P_av,C_volAvg,C_minMaxAvg, & - F,params%Delta_t,params%rotation_BC) - call MPI_Allreduce(MPI_IN_PLACE,terminallyIll,1_MPI_INTEGER_KIND,MPI_LOGICAL,MPI_LOR,MPI_COMM_WORLD,err_MPI) - if (err_MPI /= 0_MPI_INTEGER_KIND) error stop 'MPI error' - err_div = utilities_divergenceRMS(r) + associate (P => r) + call utilities_constitutiveResponse(P, & + P_av,C_volAvg,C_minMaxAvg, & + F,params%Delta_t,params%rotation_BC) + call MPI_Allreduce(MPI_IN_PLACE,terminallyIll,1_MPI_INTEGER_KIND,MPI_LOGICAL,MPI_LOR,MPI_COMM_WORLD,err_MPI) + if (err_MPI /= 0_MPI_INTEGER_KIND) error stop 'MPI error' + err_div = utilities_divergenceRMS(P) + end associate -!-------------------------------------------------------------------------------------------------- -! stress BC handling deltaF_aim = math_mul3333xx33(S, P_av - P_aim) ! S = 0.0 for no bc F_aim = F_aim - deltaF_aim err_BC = maxval(abs(merge(.0_pReal,P_av - P_aim,params%stress_mask))) diff --git a/src/grid/grid_mech_spectral_polarisation.f90 b/src/grid/grid_mech_spectral_polarisation.f90 index 90e6d346f..e2ec8488c 100644 --- a/src/grid/grid_mech_spectral_polarisation.f90 +++ b/src/grid/grid_mech_spectral_polarisation.f90 @@ -597,8 +597,6 @@ subroutine formResidual(in, FandF_tau, & if (nfuncs == 0 .and. PETScIter == 0) totalIter = -1 ! new increment -!-------------------------------------------------------------------------------------------------- -! begin of new iteration newIteration: if (totalIter <= PETScIter) then totalIter = totalIter + 1 print'(1x,a,3(a,i0))', trim(incInfo), ' @ Iteration ', num%itmin, '≤',totalIter, '≤', num%itmax @@ -609,38 +607,29 @@ subroutine formResidual(in, FandF_tau, & flush(IO_STDOUT) end if newIteration -!-------------------------------------------------------------------------------------------------- -! do k = 1, cells3; do j = 1, cells(2); do i = 1, cells(1) r_F_tau(1:3,1:3,i,j,k) = & num%beta*math_mul3333xx33(C_scale,F(1:3,1:3,i,j,k) - math_I3) -& num%alpha*matmul(F(1:3,1:3,i,j,k), & math_mul3333xx33(C_scale,F_tau(1:3,1:3,i,j,k) - F(1:3,1:3,i,j,k) - math_I3)) end do; end do; end do - -!-------------------------------------------------------------------------------------------------- -! constructing residual r_F_tau = num%beta*F & - utilities_GammaConvolution(r_F_tau,params%rotation_BC%rotate(num%beta*F_aim,active=.true.)) -!-------------------------------------------------------------------------------------------------- -! evaluate constitutive response - call utilities_constitutiveResponse(r_F, & ! "residuum" gets field of first PK stress (to save memory) - P_av,C_volAvg,C_minMaxAvg, & - F - r_F_tau/num%beta,params%Delta_t,params%rotation_BC) - call MPI_Allreduce(MPI_IN_PLACE,terminallyIll,1_MPI_INTEGER_KIND,MPI_LOGICAL,MPI_LOR,MPI_COMM_WORLD,err_MPI) - err_div = utilities_divergenceRMS(r_F) - err_curl = utilities_curlRMS(F) + associate (P => r_F) + call utilities_constitutiveResponse(P, & + P_av,C_volAvg,C_minMaxAvg, & + F - r_F_tau/num%beta,params%Delta_t,params%rotation_BC) + call MPI_Allreduce(MPI_IN_PLACE,terminallyIll,1_MPI_INTEGER_KIND,MPI_LOGICAL,MPI_LOR,MPI_COMM_WORLD,err_MPI) + err_div = utilities_divergenceRMS(P) + err_curl = utilities_curlRMS(F) + end associate -!-------------------------------------------------------------------------------------------------- -! stress BC handling F_aim = F_aim - math_mul3333xx33(S, P_av - P_aim) ! S = 0.0 for no bc err_BC = maxval(abs(merge(math_mul3333xx33(C_scale,F_aim-params%rotation_BC%rotate(F_av)), & P_av-P_aim, & params%stress_mask))) -!-------------------------------------------------------------------------------------------------- -! constructing residual e = 0 do k = 1, cells3; do j = 1, cells(2); do i = 1, cells(1) e = e + 1 From 2173c9e4992c88ecc2999d077086e2ef506b022b Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sun, 20 Nov 2022 13:36:03 +0100 Subject: [PATCH 38/60] undo weighting needed for restart --- src/grid/spectral_utilities.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/grid/spectral_utilities.f90 b/src/grid/spectral_utilities.f90 index d5ec36702..54dbf8c43 100644 --- a/src/grid/spectral_utilities.f90 +++ b/src/grid/spectral_utilities.f90 @@ -1118,7 +1118,7 @@ subroutine utilities_saveReferenceStiffness() open(newunit=fileUnit, file=getSolverJobName()//'.C_ref',& status='replace',access='stream',action='write',iostat=ierr) if (ierr /=0) call IO_error(100,ext_msg='could not open file '//getSolverJobName()//'.C_ref') - write(fileUnit) C_ref + write(fileUnit) C_ref*wgt close(fileUnit) end if From c73f777b5cb9aff7b7871b32342b5f2d02012633 Mon Sep 17 00:00:00 2001 From: Test User Date: Sun, 20 Nov 2022 17:10:14 +0100 Subject: [PATCH 39/60] [skip ci] updated version information after successful test of v3.0.0-alpha7-122-g815d825fa --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 68807f157..ddc6c7da1 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.0.0-alpha7-111-g30b23df2d +3.0.0-alpha7-122-g815d825fa From cad4cbc5d24ba749749f47339f9ae2e5867d7c62 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Sun, 20 Nov 2022 21:04:42 +0100 Subject: [PATCH 40/60] circument bug in gfortran associate to strided pointer seems to cause trouble --- src/grid/DAMASK_grid.f90 | 2 -- src/grid/grid_mech_spectral_polarisation.f90 | 35 ++++++++++++++------ 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/src/grid/DAMASK_grid.f90 b/src/grid/DAMASK_grid.f90 index 1b785ca3d..c9dea0166 100644 --- a/src/grid/DAMASK_grid.f90 +++ b/src/grid/DAMASK_grid.f90 @@ -106,8 +106,6 @@ program DAMASK_grid external :: & quit - class(tNode), pointer :: & - tmp type(tDict), pointer :: & config_load, & num_grid, & diff --git a/src/grid/grid_mech_spectral_polarisation.f90 b/src/grid/grid_mech_spectral_polarisation.f90 index e2ec8488c..46ff04adb 100644 --- a/src/grid/grid_mech_spectral_polarisation.f90 +++ b/src/grid/grid_mech_spectral_polarisation.f90 @@ -616,29 +616,44 @@ subroutine formResidual(in, FandF_tau, & r_F_tau = num%beta*F & - utilities_GammaConvolution(r_F_tau,params%rotation_BC%rotate(num%beta*F_aim,active=.true.)) + err_curl = utilities_curlRMS(F) + +#ifdef __GFORTRAN__ + call utilities_constitutiveResponse(r_F, & +#else associate (P => r_F) call utilities_constitutiveResponse(P, & +#endif P_av,C_volAvg,C_minMaxAvg, & F - r_F_tau/num%beta,params%Delta_t,params%rotation_BC) call MPI_Allreduce(MPI_IN_PLACE,terminallyIll,1_MPI_INTEGER_KIND,MPI_LOGICAL,MPI_LOR,MPI_COMM_WORLD,err_MPI) +#ifdef __GFORTRAN__ + err_div = utilities_divergenceRMS(r_F) +#else err_div = utilities_divergenceRMS(P) - err_curl = utilities_curlRMS(F) +#endif + e = 0 + do k = 1, cells3; do j = 1, cells(2); do i = 1, cells(1) + e = e + 1 + r_F(1:3,1:3,i,j,k) = & + math_mul3333xx33(math_invSym3333(homogenization_dPdF(1:3,1:3,1:3,1:3,e) + C_scale), & +#ifdef __GFORTRAN__ + r_F(1:3,1:3,i,j,k) - matmul(F(1:3,1:3,i,j,k), & +#else + P(1:3,1:3,i,j,k) - matmul(F(1:3,1:3,i,j,k), & +#endif + math_mul3333xx33(C_scale,F_tau(1:3,1:3,i,j,k) - F(1:3,1:3,i,j,k) - math_I3))) & + + r_F_tau(1:3,1:3,i,j,k) + end do; end do; end do +#ifndef __GFORTRAN__ end associate +#endif F_aim = F_aim - math_mul3333xx33(S, P_av - P_aim) ! S = 0.0 for no bc err_BC = maxval(abs(merge(math_mul3333xx33(C_scale,F_aim-params%rotation_BC%rotate(F_av)), & P_av-P_aim, & params%stress_mask))) - e = 0 - do k = 1, cells3; do j = 1, cells(2); do i = 1, cells(1) - e = e + 1 - r_F(1:3,1:3,i,j,k) = & - math_mul3333xx33(math_invSym3333(homogenization_dPdF(1:3,1:3,1:3,1:3,e) + C_scale), & - r_F(1:3,1:3,i,j,k) - matmul(F(1:3,1:3,i,j,k), & - math_mul3333xx33(C_scale,F_tau(1:3,1:3,i,j,k) - F(1:3,1:3,i,j,k) - math_I3))) & - + r_F_tau(1:3,1:3,i,j,k) - end do; end do; end do end subroutine formResidual From 6f6e143f5f9a28fd52d32597f7e3b0e1303cc1a4 Mon Sep 17 00:00:00 2001 From: Test User Date: Mon, 21 Nov 2022 05:14:06 +0100 Subject: [PATCH 41/60] [skip ci] updated version information after successful test of v3.0.0-alpha7-125-g762a5de6c --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index ddc6c7da1..746394ec1 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.0.0-alpha7-122-g815d825fa +3.0.0-alpha7-125-g762a5de6c From 3fb0b5d0999f0424f16a633d31b6561898e8c5f3 Mon Sep 17 00:00:00 2001 From: Daniel Otto de Mentock Date: Tue, 22 Nov 2022 14:20:19 +0100 Subject: [PATCH 42/60] removed superfluous asDict specification for polynomials arguments --- src/phase_mechanical_elastic.f90 | 12 ++++++------ src/phase_mechanical_plastic_dislotwin.f90 | 4 ++-- src/polynomials.f90 | 10 +++++----- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/phase_mechanical_elastic.f90 b/src/phase_mechanical_elastic.f90 index 2dae61f34..cbe8c439a 100644 --- a/src/phase_mechanical_elastic.f90 +++ b/src/phase_mechanical_elastic.f90 @@ -45,17 +45,17 @@ module subroutine elastic_init(phases) associate(prm => param(ph)) - prm%C_11 = polynomial(elastic%asDict(),'C_11','T') - prm%C_12 = polynomial(elastic%asDict(),'C_12','T') - prm%C_44 = polynomial(elastic%asDict(),'C_44','T') + prm%C_11 = polynomial(elastic,'C_11','T') + prm%C_12 = polynomial(elastic,'C_12','T') + prm%C_44 = polynomial(elastic,'C_44','T') if (any(phase_lattice(ph) == ['hP','tI'])) then - prm%C_13 = polynomial(elastic%asDict(),'C_13','T') - prm%C_33 = polynomial(elastic%asDict(),'C_33','T') + prm%C_13 = polynomial(elastic,'C_13','T') + prm%C_33 = polynomial(elastic,'C_33','T') end if if (phase_lattice(ph) == 'tI') & - prm%C_66 = polynomial(elastic%asDict(),'C_66','T') + prm%C_66 = polynomial(elastic,'C_66','T') end associate end do diff --git a/src/phase_mechanical_plastic_dislotwin.f90 b/src/phase_mechanical_plastic_dislotwin.f90 index 77f162fef..1e02e7644 100644 --- a/src/phase_mechanical_plastic_dislotwin.f90 +++ b/src/phase_mechanical_plastic_dislotwin.f90 @@ -299,7 +299,7 @@ module function plastic_dislotwin_init() result(myPlasticity) prm%b_tr = math_expand(prm%b_tr,prm%N_tr) prm%i_tr = pl%get_asFloat('i_tr') - prm%Delta_G = polynomial(pl%asDict(),'Delta_G','T') + prm%Delta_G = polynomial(pl,'Delta_G','T') prm%L_tr = pl%get_asFloat('L_tr') a_cF = prm%b_tr(1)*sqrt(6.0_pReal) ! b_tr is Shockley partial prm%h = 5.0_pReal * a_cF/sqrt(3.0_pReal) @@ -357,7 +357,7 @@ module function plastic_dislotwin_init() result(myPlasticity) end if if (prm%sum_N_tw + prm%sum_N_tr > 0 .or. prm%extendedDislocations) & - prm%Gamma_sf = polynomial(pl%asDict(),'Gamma_sf','T') + prm%Gamma_sf = polynomial(pl,'Gamma_sf','T') slipAndTwinActive: if (prm%sum_N_sl * prm%sum_N_tw > 0) then prm%h_sl_tw = lattice_interaction_SlipByTwin(N_sl,prm%N_tw,pl%get_as1dFloat('h_sl-tw'), & diff --git a/src/polynomials.f90 b/src/polynomials.f90 index 385905b38..38e31eb55 100644 --- a/src/polynomials.f90 +++ b/src/polynomials.f90 @@ -157,7 +157,7 @@ subroutine selfTest() 'C,T^4: '//trim(adjustl(coef_s(5)))//IO_EOL//& 'T_ref: '//trim(adjustl(x_ref_s))//IO_EOL dict => YAML_parse_str_asDict(trim(YAML_s)) - p2 = polynomial(dict%asDict(),'C','T') + p2 = polynomial(dict,'C','T') if (dNeq(p1%at(x),p2%at(x),1.0e-6_pReal)) error stop 'polynomials: init' y = coef(1)+coef(2)*(x-x_ref)+coef(3)*(x-x_ref)**2+coef(4)*(x-x_ref)**3+coef(5)*(x-x_ref)**4 if (dNeq(p1%at(x),y,1.0e-6_pReal)) error stop 'polynomials: eval(full)' @@ -166,28 +166,28 @@ subroutine selfTest() 'C,T: '//trim(adjustl(coef_s(2)))//IO_EOL//& 'T_ref: '//trim(adjustl(x_ref_s))//IO_EOL dict => YAML_parse_str_asDict(trim(YAML_s)) - p1 = polynomial(dict%asDict(),'C','T') + p1 = polynomial(dict,'C','T') if (dNeq(p1%at(x_ref+x),-p1%at(x_ref-x),1.0e-10_pReal)) error stop 'polynomials: eval(linear)' YAML_s = 'C: 0.0'//IO_EOL//& 'C,T^2: '//trim(adjustl(coef_s(3)))//IO_EOL//& 'T_ref: '//trim(adjustl(x_ref_s))//IO_EOL dict => YAML_parse_str_asDict(trim(YAML_s)) - p1 = polynomial(dict%asDict(),'C','T') + p1 = polynomial(dict,'C','T') if (dNeq(p1%at(x_ref+x),p1%at(x_ref-x),1e-10_pReal)) error stop 'polynomials: eval(quadratic)' YAML_s = 'Y: '//trim(adjustl(coef_s(1)))//IO_EOL//& 'Y,X^3: '//trim(adjustl(coef_s(2)))//IO_EOL//& 'X_ref: '//trim(adjustl(x_ref_s))//IO_EOL dict => YAML_parse_str_asDict(trim(YAML_s)) - p1 = polynomial(dict%asDict(),'Y','X') + p1 = polynomial(dict,'Y','X') if (dNeq(p1%at(x_ref+x)-coef(1),-(p1%at(x_ref-x)-coef(1)),1.0e-8_pReal)) error stop 'polynomials: eval(cubic)' YAML_s = 'Y: '//trim(adjustl(coef_s(1)))//IO_EOL//& 'Y,X^4: '//trim(adjustl(coef_s(2)))//IO_EOL//& 'X_ref: '//trim(adjustl(x_ref_s))//IO_EOL dict => YAML_parse_str_asDict(trim(YAML_s)) - p1 = polynomial(dict%asDict(),'Y','X') + p1 = polynomial(dict,'Y','X') if (dNeq(p1%at(x_ref+x),p1%at(x_ref-x),1.0e-6_pReal)) error stop 'polynomials: eval(quartic)' From cbe2e74cdde5c8ce5e5c7934c8878c94decc9a53 Mon Sep 17 00:00:00 2001 From: Philip Eisenlohr Date: Tue, 22 Nov 2022 14:39:51 +0000 Subject: [PATCH 43/60] Collection of small polishing steps --- python/damask/_colormap.py | 7 ++----- python/damask/_rotation.py | 12 ++++++------ 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/python/damask/_colormap.py b/python/damask/_colormap.py index cdcbd8939..1f6e61b23 100644 --- a/python/damask/_colormap.py +++ b/python/damask/_colormap.py @@ -3,6 +3,7 @@ import json import functools import colorsys from typing import Union, TextIO +from itertools import chain import numpy as np import scipy.interpolate as interp @@ -373,16 +374,12 @@ class Colormap(mpl.colors.ListedColormap): File to store results. Defaults to colormap name + '.json'. """ - colors = [] - for i,c in enumerate(np.round(self.colors,6).tolist()): - colors+=[i]+c - out = [{ 'Creator':util.execution_stamp('Colormap'), 'ColorSpace':'RGB', 'Name':self.name, 'DefaultMap':True, - 'RGBPoints':colors + 'RGBPoints':list(chain.from_iterable([(i,*c) for i,c in enumerate(self.colors.round(6))])) }] fhandle = self._get_file_handle(fname,'.json') diff --git a/python/damask/_rotation.py b/python/damask/_rotation.py index 204a735ad..b39b38bef 100644 --- a/python/damask/_rotation.py +++ b/python/damask/_rotation.py @@ -1088,7 +1088,7 @@ class Rotation: dg = 1. if fractions else _dg(phi,degrees) dV_V = dg * np.maximum(0.,weights.squeeze()) - N = 1 if shape is None else np.prod(shape) + N = 1 if shape is None else np.prod(shape).astype(int) return Rotation.from_Euler_angles(phi[util.hybrid_IA(dV_V,N,rng_seed)],degrees).reshape(() if shape is None else shape) @@ -1210,11 +1210,11 @@ class Rotation: if np.isclose(ax_align[3],0.): ax_align[:3] = np.array([1.,0.,0.]) R_align = Rotation.from_axis_angle(ax_align if ax_align[3] > 0. else -ax_align,normalize=True) # rotate fiber axis from sample to crystal frame - N = 1 if shape is None else np.prod(shape) + N = 1 if shape is None else np.prod(shape).astype(int) u,Theta = (rng.random((N,2)) * 2. * np.array([1.,np.pi]) - np.array([1.,0.])).T omega = abs(rng.normal(scale=sigma_,size=N)) - p = np.column_stack([np.sqrt(1-u**2)*np.cos(Theta), - np.sqrt(1-u**2)*np.sin(Theta), + p = np.column_stack([np.sqrt(1.-u**2)*np.cos(Theta), + np.sqrt(1.-u**2)*np.sin(Theta), u, omega]) p[:,:3] = np.einsum('ij,...j',np.eye(3)-np.outer(d_lab,d_lab),p[:,:3]) # remove component along fiber axis f = np.column_stack((np.broadcast_to(d_lab,(N,3)),rng.random(N)*np.pi)) @@ -1290,7 +1290,7 @@ class Rotation: np.broadcast_to(np.pi,qu[...,0:1].shape), np.zeros(qu.shape[:-1]+(1,))]), np.block([np.arctan2((-_P*q02+q13)*chi, (-_P*q01-q23)*chi), - np.arctan2( 2.*chi, q03_s-q12_s ), + np.arctan2( 2.*chi, q03_s-q12_s ), np.arctan2(( _P*q02+q13)*chi, (-_P*q01+q23)*chi)]) ) ) @@ -1394,7 +1394,7 @@ class Rotation: zeta = 1./np.sqrt(1.-om[...,2,2:3]**2) eu = np.where(np.isclose(np.abs(om[...,2,2:3]),1.,0.), np.block([np.arctan2(om[...,0,1:2],om[...,0,0:1]), - np.pi*0.5*(1-om[...,2,2:3]), + np.pi*0.5*(1.-om[...,2,2:3]), np.zeros(om.shape[:-2]+(1,)), ]), np.block([np.arctan2(om[...,2,0:1]*zeta,-om[...,2,1:2]*zeta), From 6315f97f4af381838d4182b372b982fef7e5e4a9 Mon Sep 17 00:00:00 2001 From: Philip Eisenlohr Date: Tue, 22 Nov 2022 16:26:15 -0500 Subject: [PATCH 44/60] added explicit Optional type hint --- python/damask/_colormap.py | 16 +++---- python/damask/_config.py | 6 +-- python/damask/_configmaterial.py | 16 +++---- python/damask/_crystal.py | 18 ++++---- python/damask/_grid.py | 36 ++++++++-------- python/damask/_orientation.py | 22 +++++----- python/damask/_result.py | 72 ++++++++++++++++---------------- python/damask/_rotation.py | 22 +++++----- python/damask/_table.py | 12 +++--- python/damask/_vtk.py | 14 +++---- python/damask/seeds.py | 10 ++--- python/damask/util.py | 35 ++++++++-------- 12 files changed, 141 insertions(+), 138 deletions(-) diff --git a/python/damask/_colormap.py b/python/damask/_colormap.py index 1f6e61b23..da59aaaad 100644 --- a/python/damask/_colormap.py +++ b/python/damask/_colormap.py @@ -2,7 +2,7 @@ import os import json import functools import colorsys -from typing import Union, TextIO +from typing import Optional, Union, TextIO from itertools import chain import numpy as np @@ -275,8 +275,8 @@ class Colormap(mpl.colors.ListedColormap): def shade(self, field: np.ndarray, - bounds: FloatSequence = None, - gap: float = None) -> Image: + bounds: Optional[FloatSequence] = None, + gap: Optional[float] = None) -> Image: """ Generate PIL image of 2D field using colormap. @@ -315,7 +315,7 @@ class Colormap(mpl.colors.ListedColormap): def reversed(self, - name: str = None) -> 'Colormap': + name: Optional[str] = None) -> 'Colormap': """ Reverse. @@ -364,7 +364,7 @@ class Colormap(mpl.colors.ListedColormap): def save_paraview(self, - fname: FileHandle = None): + fname: Optional[FileHandle] = None): """ Save as JSON file for use in Paraview. @@ -388,7 +388,7 @@ class Colormap(mpl.colors.ListedColormap): def save_ASCII(self, - fname: FileHandle = None): + fname: Optional[FileHandle] = None): """ Save as ASCII file. @@ -403,7 +403,7 @@ class Colormap(mpl.colors.ListedColormap): t.save(self._get_file_handle(fname,'.txt')) - def save_GOM(self, fname: FileHandle = None): + def save_GOM(self, fname: Optional[FileHandle] = None): """ Save as ASCII file for use in GOM Aramis. @@ -424,7 +424,7 @@ class Colormap(mpl.colors.ListedColormap): def save_gmsh(self, - fname: FileHandle = None): + fname: Optional[FileHandle] = None): """ Save as ASCII file for use in gmsh. diff --git a/python/damask/_config.py b/python/damask/_config.py index 5423699db..f6714cd81 100644 --- a/python/damask/_config.py +++ b/python/damask/_config.py @@ -2,7 +2,7 @@ import copy from io import StringIO from collections.abc import Iterable import abc -from typing import Union, Dict, Any, Type, TypeVar +from typing import Optional, Union, Dict, Any, Type, TypeVar import numpy as np import yaml @@ -21,7 +21,7 @@ class NiceDumper(yaml.SafeDumper): """Make YAML readable for humans.""" def write_line_break(self, - data: str = None): + data: Optional[str] = None): super().write_line_break(data) if len(self.indents) == 1: @@ -53,7 +53,7 @@ class Config(dict): """YAML-based configuration.""" def __init__(self, - yml: Union[str, Dict[str, Any]] = None, + yml: Union[None, str, Dict[str, Any]] = None, **kwargs): """Initialize from YAML, dict, or key=value pairs.""" if isinstance(yml,str): diff --git a/python/damask/_configmaterial.py b/python/damask/_configmaterial.py index d98f277fe..2c6ac4daa 100644 --- a/python/damask/_configmaterial.py +++ b/python/damask/_configmaterial.py @@ -1,6 +1,6 @@ import numpy as np import h5py -from typing import Union, Sequence, Dict, Any, Collection +from typing import Optional, Union, Sequence, Dict, Any, Collection from ._typehints import FileHandle from . import Config @@ -22,7 +22,7 @@ class ConfigMaterial(Config): """ def __init__(self, - d: Dict[str, Any] = None, + d: Optional[Dict[str, Any]] = None, **kwargs): """ New material configuration. @@ -83,13 +83,13 @@ class ConfigMaterial(Config): @staticmethod def load_DREAM3D(fname: str, - grain_data: str = None, - cell_data: str = None, + grain_data: Optional[str] = None, + cell_data: Optional[str] = None, cell_ensemble_data: str = 'CellEnsembleData', phases: str = 'Phases', Euler_angles: str = 'EulerAngles', phase_names: str = 'PhaseName', - base_group: str = None) -> 'ConfigMaterial': + base_group: Optional[str] = None) -> 'ConfigMaterial': """ Load DREAM.3D (HDF5) file. @@ -354,8 +354,8 @@ class ConfigMaterial(Config): def material_rename_phase(self, mapping: Dict[str, str], - ID: Sequence[int] = None, - constituent: Sequence[int] = None) -> 'ConfigMaterial': + ID: Optional[Sequence[int]] = None, + constituent: Optional[Sequence[int]] = None) -> 'ConfigMaterial': """ Change phase name in material. @@ -388,7 +388,7 @@ class ConfigMaterial(Config): def material_rename_homogenization(self, mapping: Dict[str, str], - ID: Sequence[int] = None) -> 'ConfigMaterial': + ID: Optional[Sequence[int]] = None) -> 'ConfigMaterial': """ Change homogenization name in material. diff --git a/python/damask/_crystal.py b/python/damask/_crystal.py index fb2dc3438..ed694fb12 100644 --- a/python/damask/_crystal.py +++ b/python/damask/_crystal.py @@ -1,4 +1,4 @@ -from typing import Union, Dict, List, Tuple +from typing import Optional, Union, Dict, List, Tuple import numpy as np @@ -324,10 +324,10 @@ class Crystal(): """ def __init__(self, *, - family: CrystalFamily = None, - lattice: CrystalLattice = None, - a: float = None, b: float = None, c: float = None, - alpha: float = None, beta: float = None, gamma: float = None, + family: Optional[CrystalFamily] = None, + lattice: Optional[CrystalLattice] = None, + a: Optional[float] = None, b: Optional[float] = None, c: Optional[float] = None, + alpha: Optional[float] = None, beta: Optional[float] = None, gamma: Optional[float] = None, degrees: bool = False): """ New representation of a crystal. @@ -690,8 +690,8 @@ class Crystal(): self.lattice[-1],None),dtype=float) def to_lattice(self, *, - direction: FloatSequence = None, - plane: FloatSequence = None) -> np.ndarray: + direction: Optional[FloatSequence] = None, + plane: Optional[FloatSequence] = None) -> np.ndarray: """ Calculate lattice vector corresponding to crystal frame direction or plane normal. @@ -717,8 +717,8 @@ class Crystal(): def to_frame(self, *, - uvw: FloatSequence = None, - hkl: FloatSequence = None) -> np.ndarray: + uvw: Optional[FloatSequence] = None, + hkl: Optional[FloatSequence] = None) -> np.ndarray: """ Calculate crystal frame vector corresponding to lattice direction [uvw] or plane normal (hkl). diff --git a/python/damask/_grid.py b/python/damask/_grid.py index 9197c1c5f..c73311482 100644 --- a/python/damask/_grid.py +++ b/python/damask/_grid.py @@ -4,7 +4,7 @@ import warnings import multiprocessing as mp from functools import partial import typing -from typing import Union, Optional, TextIO, List, Sequence, Dict +from typing import Optional, Union, TextIO, List, Sequence, Dict from pathlib import Path import numpy as np @@ -34,8 +34,8 @@ class Grid: material: np.ndarray, size: FloatSequence, origin: FloatSequence = np.zeros(3), - initial_conditions: Dict[str,np.ndarray] = None, - comments: Union[str, Sequence[str]] = None): + initial_conditions: Optional[Dict[str,np.ndarray]] = None, + comments: Union[None, str, Sequence[str]] = None): """ New geometry definition for grid solvers. @@ -348,9 +348,11 @@ class Grid: @staticmethod def load_DREAM3D(fname: Union[str, Path], - feature_IDs: str = None, cell_data: str = None, - phases: str = 'Phases', Euler_angles: str = 'EulerAngles', - base_group: str = None) -> 'Grid': + feature_IDs: Optional[str] = None, + cell_data: Optional[str] = None, + phases: str = 'Phases', + Euler_angles: str = 'EulerAngles', + base_group: Optional[str] = None) -> 'Grid': """ Load DREAM.3D (HDF5) file. @@ -463,7 +465,7 @@ class Grid: size: FloatSequence, seeds: np.ndarray, weights: FloatSequence, - material: IntSequence = None, + material: Optional[IntSequence] = None, periodic: bool = True): """ Create grid from Laguerre tessellation. @@ -520,7 +522,7 @@ class Grid: def from_Voronoi_tessellation(cells: IntSequence, size: FloatSequence, seeds: np.ndarray, - material: IntSequence = None, + material: Optional[IntSequence] = None, periodic: bool = True) -> 'Grid': """ Create grid from Voronoi tessellation. @@ -763,9 +765,9 @@ class Grid: def canvas(self, - cells: IntSequence = None, - offset: IntSequence = None, - fill: int = None) -> 'Grid': + cells: Optional[IntSequence] = None, + offset: Optional[IntSequence] = None, + fill: Optional[int] = None) -> 'Grid': """ Crop or enlarge/pad grid. @@ -901,7 +903,7 @@ class Grid: def rotate(self, R: Rotation, - fill: int = None) -> 'Grid': + fill: Optional[int] = None) -> 'Grid': """ Rotate grid (and pad if required). @@ -1093,10 +1095,10 @@ class Grid: def clean(self, distance: float = np.sqrt(3), - selection: IntCollection = None, + selection: Optional[IntCollection] = None, invert_selection: bool = False, periodic: bool = True, - rng_seed: NumpyRngSeed = None) -> 'Grid': + rng_seed: Optional[NumpyRngSeed] = None) -> 'Grid': """ Smooth grid by selecting most frequent material ID within given stencil at each location. @@ -1163,7 +1165,7 @@ class Grid: dimension: Union[FloatSequence, IntSequence], center: Union[FloatSequence, IntSequence], exponent: Union[FloatSequence, float], - fill: int = None, + fill: Optional[int] = None, R: Rotation = Rotation(), inverse: bool = False, periodic: bool = True) -> 'Grid': @@ -1254,8 +1256,8 @@ class Grid: def vicinity_offset(self, distance: float = np.sqrt(3), - offset: int = None, - selection: IntCollection = None, + offset: Optional[int] = None, + selection: Optional[IntCollection] = None, invert_selection: bool = False, periodic: bool = True) -> 'Grid': """ diff --git a/python/damask/_orientation.py b/python/damask/_orientation.py index 95bcc6795..06eb6f3fc 100644 --- a/python/damask/_orientation.py +++ b/python/damask/_orientation.py @@ -1,6 +1,6 @@ import inspect import copy -from typing import Union, Callable, Dict, Any, Tuple, TypeVar +from typing import Optional, Union, Callable, Dict, Any, Tuple, TypeVar import numpy as np @@ -98,10 +98,10 @@ class Orientation(Rotation,Crystal): def __init__(self, rotation: Union[FloatSequence, Rotation] = np.array([1.,0.,0.,0.]), *, - family: CrystalFamily = None, - lattice: CrystalLattice = None, - a: float = None, b: float = None, c: float = None, - alpha: float = None, beta: float = None, gamma: float = None, + family: Optional[CrystalFamily] = None, + lattice: Optional[CrystalLattice] = None, + a: Optional[float] = None, b: Optional[float] = None, c: Optional[float] = None, + alpha: Optional[float] = None, beta: Optional[float] = None, gamma: Optional[float] = None, degrees: bool = False): """ New orientation. @@ -131,7 +131,7 @@ class Orientation(Rotation,Crystal): def __copy__(self: MyType, - rotation: Union[FloatSequence, Rotation] = None) -> MyType: + rotation: Union[None, FloatSequence, Rotation] = None) -> MyType: """ Return deepcopy(self). @@ -617,7 +617,7 @@ class Orientation(Rotation,Crystal): def average(self, - weights: FloatSequence = None, + weights: Optional[FloatSequence] = None, return_cloud: bool = False): """ Return orientation average over last dimension. @@ -819,8 +819,8 @@ class Orientation(Rotation,Crystal): # functions that require lattice, not just family def to_pole(self, *, - uvw: FloatSequence = None, - hkl: FloatSequence = None, + uvw: Optional[FloatSequence] = None, + hkl: Optional[FloatSequence] = None, with_symmetry: bool = False, normalize: bool = True) -> np.ndarray: """ @@ -861,8 +861,8 @@ class Orientation(Rotation,Crystal): def Schmid(self, *, - N_slip: IntSequence = None, - N_twin: IntSequence = None) -> np.ndarray: + N_slip: Optional[IntSequence] = None, + N_twin: Optional[IntSequence] = None) -> np.ndarray: u""" Calculate Schmid matrix P = d ⨂ n in the lab frame for selected deformation systems. diff --git a/python/damask/_result.py b/python/damask/_result.py index 7e19c66f7..2fa353f7d 100644 --- a/python/damask/_result.py +++ b/python/damask/_result.py @@ -11,7 +11,7 @@ from pathlib import Path from functools import partial from collections import defaultdict from collections.abc import Iterable -from typing import Union, Callable, Any, Sequence, Literal, Dict, List, Tuple, Optional +from typing import Optional, Union, Callable, Any, Sequence, Literal, Dict, List, Tuple import h5py import numpy as np @@ -189,11 +189,11 @@ class Result: def _manage_view(self, action: Literal['set', 'add', 'del'], - increments: Union[int, Sequence[int], str, Sequence[str], bool] = None, - times: Union[float, Sequence[float], str, Sequence[str], bool] = None, - phases: Union[str, Sequence[str], bool] = None, - homogenizations: Union[str, Sequence[str], bool] = None, - fields: Union[str, Sequence[str], bool] = None) -> "Result": + increments: Union[None, int, Sequence[int], str, Sequence[str], bool] = None, + times: Union[None, float, Sequence[float], str, Sequence[str], bool] = None, + phases: Union[None, str, Sequence[str], bool] = None, + homogenizations: Union[None, str, Sequence[str], bool] = None, + fields: Union[None, str, Sequence[str], bool] = None) -> "Result": """ Manages the visibility of the groups. @@ -256,8 +256,8 @@ class Result: def increments_in_range(self, - start: Union[str, int] = None, - end: Union[str, int] = None) -> Sequence[int]: + start: Union[None, str, int] = None, + end: Union[None, str, int] = None) -> Sequence[int]: """ Get all increments within a given range. @@ -280,8 +280,8 @@ class Result: return [i for i in self.incs if s <= i <= e] def times_in_range(self, - start: float = None, - end: float = None) -> Sequence[float]: + start: Optional[float] = None, + end: Optional[float] = None) -> Sequence[float]: """ Get times of all increments within a given time range. @@ -304,12 +304,12 @@ class Result: def view(self,*, - increments: Union[int, Sequence[int], str, Sequence[str], bool] = None, - times: Union[float, Sequence[float], str, Sequence[str], bool] = None, - phases: Union[str, Sequence[str], bool] = None, - homogenizations: Union[str, Sequence[str], bool] = None, - fields: Union[str, Sequence[str], bool] = None, - protected: bool = None) -> "Result": + increments: Union[None, int, Sequence[int], str, Sequence[str], bool] = None, + times: Union[None, float, Sequence[float], str, Sequence[str], bool] = None, + phases: Union[None, str, Sequence[str], bool] = None, + homogenizations: Union[None, str, Sequence[str], bool] = None, + fields: Union[None, str, Sequence[str], bool] = None, + protected: Optional[bool] = None) -> "Result": """ Set view. @@ -361,11 +361,11 @@ class Result: def view_more(self,*, - increments: Union[int, Sequence[int], str, Sequence[str], bool] = None, - times: Union[float, Sequence[float], str, Sequence[str], bool] = None, - phases: Union[str, Sequence[str], bool] = None, - homogenizations: Union[str, Sequence[str], bool] = None, - fields: Union[str, Sequence[str], bool] = None) -> "Result": + increments: Union[None, int, Sequence[int], str, Sequence[str], bool] = None, + times: Union[None, float, Sequence[float], str, Sequence[str], bool] = None, + phases: Union[None, str, Sequence[str], bool] = None, + homogenizations: Union[None, str, Sequence[str], bool] = None, + fields: Union[None, str, Sequence[str], bool] = None) -> "Result": """ Add to view. @@ -404,11 +404,11 @@ class Result: def view_less(self,*, - increments: Union[int, Sequence[int], str, Sequence[str], bool] = None, - times: Union[float, Sequence[float], str, Sequence[str], bool] = None, - phases: Union[str, Sequence[str], bool] = None, - homogenizations: Union[str, Sequence[str], bool] = None, - fields: Union[str, Sequence[str], bool] = None) -> "Result": + increments: Union[None, int, Sequence[int], str, Sequence[str], bool] = None, + times: Union[None, float, Sequence[float], str, Sequence[str], bool] = None, + phases: Union[None, str, Sequence[str], bool] = None, + homogenizations: Union[None, str, Sequence[str], bool] = None, + fields: Union[None, str, Sequence[str], bool] = None) -> "Result": """ Remove from view. @@ -650,7 +650,7 @@ class Result: formula: str, name: str, unit: str = 'n/a', - description: str = None): + description: Optional[str] = None): """ Add result of a general formula. @@ -966,7 +966,7 @@ class Result: } def add_equivalent_Mises(self, T_sym: str, - kind: str = None): + kind: Optional[str] = None): """ Add the equivalent Mises stress or strain of a symmetric tensor. @@ -1021,7 +1021,7 @@ class Result: } def add_norm(self, x: str, - ord: Union[int, float, Literal['fro', 'nuc']] = None): + ord: Union[None, int, float, Literal['fro', 'nuc']] = None): """ Add the norm of vector or tensor. @@ -1101,8 +1101,8 @@ class Result: def add_pole(self, q: str = 'O', *, - uvw: FloatSequence = None, - hkl: FloatSequence = None, + uvw: Optional[FloatSequence] = None, + hkl: Optional[FloatSequence] = None, with_symmetry: bool = False, normalize: bool = True): """ @@ -1593,7 +1593,7 @@ class Result: output: Union[str, List[str]] = '*', flatten: bool = True, prune: bool = True, - constituents: IntSequence = None, + constituents: Optional[IntSequence] = None, fill_float: float = np.nan, fill_int: int = 0) -> Optional[Dict[str,Any]]: """ @@ -1683,7 +1683,7 @@ class Result: def export_XDMF(self, output: Union[str, List[str]] = '*', - target_dir: Union[str, Path] = None, + target_dir: Union[None, str, Path] = None, absolute_path: bool = False): """ Write XDMF file to directly visualize data from DADF5 file. @@ -1811,8 +1811,8 @@ class Result: def export_VTK(self, output: Union[str,List[str]] = '*', mode: str = 'cell', - constituents: IntSequence = None, - target_dir: Union[str, Path] = None, + constituents: Optional[IntSequence] = None, + target_dir: Union[None, str, Path] = None, fill_float: float = np.nan, fill_int: int = 0, parallel: bool = True): @@ -1958,7 +1958,7 @@ class Result: def export_simulation_setup(self, output: Union[str, List[str]] = '*', - target_dir: Union[str, Path] = None, + target_dir: Union[None, str, Path] = None, overwrite: bool = False, ): """ diff --git a/python/damask/_rotation.py b/python/damask/_rotation.py index 07eb25803..567c91d37 100644 --- a/python/damask/_rotation.py +++ b/python/damask/_rotation.py @@ -1,5 +1,5 @@ import copy -from typing import Union, Sequence, Tuple, Literal, List, TypeVar +from typing import Optional, Union, Sequence, Tuple, Literal, List, TypeVar import numpy as np @@ -99,7 +99,7 @@ class Rotation: def __copy__(self: MyType, - rotation: Union[FloatSequence, 'Rotation'] = None) -> MyType: + rotation: Union[None, FloatSequence, 'Rotation'] = None) -> MyType: """ Return deepcopy(self). @@ -514,7 +514,7 @@ class Rotation: def average(self: MyType, - weights: FloatSequence = None) -> MyType: + weights: Optional[FloatSequence] = None) -> MyType: """ Average along last array dimension. @@ -1044,8 +1044,8 @@ class Rotation: @staticmethod - def from_random(shape: Union[int, IntSequence] = None, - rng_seed: NumpyRngSeed = None) -> 'Rotation': + def from_random(shape: Union[None, int, IntSequence] = None, + rng_seed: Optional[NumpyRngSeed] = None) -> 'Rotation': """ Initialize with samples from a uniform distribution. @@ -1078,10 +1078,10 @@ class Rotation: @staticmethod def from_ODF(weights: np.ndarray, phi: np.ndarray, - shape: Union[int, IntSequence] = None, + shape: Union[None, int, IntSequence] = None, degrees: bool = False, fractions: bool = True, - rng_seed: NumpyRngSeed = None) -> 'Rotation': + rng_seed: Optional[NumpyRngSeed] = None) -> 'Rotation': """ Initialize with samples from a binned orientation distribution function (ODF). @@ -1135,9 +1135,9 @@ class Rotation: @staticmethod def from_spherical_component(center: 'Rotation', sigma: float, - shape: Union[int, IntSequence] = None, + shape: Union[None, int, IntSequence] = None, degrees: bool = False, - rng_seed: NumpyRngSeed = None) -> 'Rotation': + rng_seed: Optional[NumpyRngSeed] = None) -> 'Rotation': """ Initialize with samples from a Gaussian distribution around a given center. @@ -1188,9 +1188,9 @@ class Rotation: def from_fiber_component(crystal: IntSequence, sample: IntSequence, sigma: float = 0., - shape: Union[int, IntSequence] = None, + shape: Union[None, int, IntSequence] = None, degrees: bool = False, - rng_seed: NumpyRngSeed = None) -> 'Rotation': + rng_seed: Optional[NumpyRngSeed] = None) -> 'Rotation': """ Initialize with samples from a Gaussian distribution around a given direction. diff --git a/python/damask/_table.py b/python/damask/_table.py index 990568364..9aa0a8ce5 100644 --- a/python/damask/_table.py +++ b/python/damask/_table.py @@ -1,6 +1,6 @@ import re import copy -from typing import Union, Tuple, List, Iterable +from typing import Optional, Union, Tuple, List, Iterable import pandas as pd import numpy as np @@ -13,8 +13,8 @@ class Table: def __init__(self, shapes: dict = {}, - data: np.ndarray = None, - comments: Union[str, Iterable[str]] = None): + data: Optional[np.ndarray] = None, + comments: Union[None, str, Iterable[str]] = None): """ New spreadsheet. @@ -188,7 +188,7 @@ class Table: def _add_comment(self, label: str, shape: Tuple[int, ...], - info: str = None): + info: Optional[str] = None): if info is not None: specific = f'{label}{" "+str(shape) if np.prod(shape,dtype=np.int64) > 1 else ""}: {info}' general = util.execution_stamp('Table') @@ -383,7 +383,7 @@ class Table: def set(self, label: str, data: np.ndarray, - info: str = None) -> 'Table': + info: Optional[str] = None) -> 'Table': """ Add new or replace existing column data. @@ -458,7 +458,7 @@ class Table: def rename(self, old: Union[str, Iterable[str]], new: Union[str, Iterable[str]], - info: str = None) -> 'Table': + info: Optional[str] = None) -> 'Table': """ Rename column data. diff --git a/python/damask/_vtk.py b/python/damask/_vtk.py index dede9f374..e398c0d53 100644 --- a/python/damask/_vtk.py +++ b/python/damask/_vtk.py @@ -1,7 +1,7 @@ import os import multiprocessing as mp from pathlib import Path -from typing import Union, Literal, List, Sequence +from typing import Optional, Union, Literal, List, Sequence import numpy as np import vtk @@ -286,7 +286,7 @@ class VTK: @staticmethod def load(fname: Union[str, Path], - dataset_type: Literal['ImageData', 'UnstructuredGrid', 'PolyData', 'RectilinearGrid'] = None) -> 'VTK': + dataset_type: Literal[None, 'ImageData', 'UnstructuredGrid', 'PolyData', 'RectilinearGrid'] = None) -> 'VTK': """ Load from VTK file. @@ -409,11 +409,11 @@ class VTK: # Check https://blog.kitware.com/ghost-and-blanking-visibility-changes/ for missing data def set(self, - label: str = None, - data: Union[np.ndarray, np.ma.MaskedArray] = None, - info: str = None, + label: Optional[str] = None, + data: Union[None, np.ndarray, np.ma.MaskedArray] = None, + info: Optional[str] = None, *, - table: 'Table' = None): + table: Optional['Table'] = None): """ Add new or replace existing point or cell data. @@ -533,7 +533,7 @@ class VTK: def show(self, - label: str = None, + label: Optional[str] = None, colormap: Union[Colormap, str] = 'cividis'): """ Render. diff --git a/python/damask/seeds.py b/python/damask/seeds.py index 7cea9d51c..4ea4afaad 100644 --- a/python/damask/seeds.py +++ b/python/damask/seeds.py @@ -1,6 +1,6 @@ """Functionality for generation of seed points for Voronoi or Laguerre tessellation.""" -from typing import Tuple as _Tuple +from typing import Optional as _Optional, Tuple as _Tuple from scipy import spatial as _spatial import numpy as _np @@ -13,8 +13,8 @@ from . import grid_filters as _grid_filters def from_random(size: _FloatSequence, N_seeds: int, - cells: _IntSequence = None, - rng_seed: _NumpyRngSeed = None) -> _np.ndarray: + cells: _Optional[_IntSequence] = None, + rng_seed: _Optional[_NumpyRngSeed] = None) -> _np.ndarray: """ Place seeds randomly in space. @@ -54,7 +54,7 @@ def from_Poisson_disc(size: _FloatSequence, N_candidates: int, distance: float, periodic: bool = True, - rng_seed: _NumpyRngSeed = None) -> _np.ndarray: + rng_seed: _Optional[_NumpyRngSeed] = None) -> _np.ndarray: """ Place seeds according to a Poisson disc distribution. @@ -106,7 +106,7 @@ def from_Poisson_disc(size: _FloatSequence, def from_grid(grid, - selection: _IntCollection = None, + selection: _Optional[_IntCollection] = None, invert_selection: bool = False, average: bool = False, periodic: bool = True) -> _Tuple[_np.ndarray, _np.ndarray]: diff --git a/python/damask/util.py b/python/damask/util.py index bda92b732..0eb36d957 100644 --- a/python/damask/util.py +++ b/python/damask/util.py @@ -10,8 +10,9 @@ import signal as _signal import fractions as _fractions from collections import abc as _abc from functools import reduce as _reduce, partial as _partial -from typing import Callable as _Callable, Union as _Union, Iterable as _Iterable, Sequence as _Sequence, Dict as _Dict, \ - List as _List, Tuple as _Tuple, Literal as _Literal, Any as _Any, Collection as _Collection, TextIO as _TextIO +from typing import Optional as _Optional, Callable as _Callable, Union as _Union, Iterable as _Iterable, \ + Sequence as _Sequence, Dict as _Dict, List as _List, Tuple as _Tuple, Literal as _Literal, \ + Any as _Any, Collection as _Collection, TextIO as _TextIO from pathlib import Path as _Path import numpy as _np @@ -140,8 +141,8 @@ def strikeout(msg) -> str: def run(cmd: str, wd: str = './', - env: _Dict[str, str] = None, - timeout: int = None) -> _Tuple[str, str]: + env: _Optional[_Dict[str, str]] = None, + timeout: _Optional[int] = None) -> _Tuple[str, str]: """ Run a command. @@ -215,7 +216,7 @@ def open_text(fname: _FileHandle, def execution_stamp(class_name: str, - function_name: str = None) -> str: + function_name: _Optional[str] = None) -> str: """Timestamp the execution of a (function within a) class.""" now = _datetime.datetime.now().astimezone().strftime('%Y-%m-%d %H:%M:%S%z') _function_name = '' if function_name is None else f'.{function_name}' @@ -238,7 +239,7 @@ def natural_sort(key: str) -> _List[_Union[int, str]]: def show_progress(iterable: _Iterable, - N_iter: int = None, + N_iter: _Optional[int] = None, prefix: str = '', bar_length: int = 50) -> _Any: """ @@ -418,7 +419,7 @@ def project_equal_area(vector: _np.ndarray, def hybrid_IA(dist: _np.ndarray, N: int, - rng_seed: _NumpyRngSeed = None) -> _np.ndarray: + rng_seed: _Optional[_NumpyRngSeed] = None) -> _np.ndarray: """ Hybrid integer approximation. @@ -534,10 +535,10 @@ def shapeblender(a: _Tuple[int, ...], def _docstringer(docstring: _Union[str, _Callable], - extra_parameters: str = None, - # extra_examples: str = None, - # extra_notes: str = None, - return_type: _Union[str, _Callable] = None) -> str: + extra_parameters: _Optional[str] = None, + # extra_examples: _Optional[str] = None, + # extra_notes: _Optional[str] = None, + return_type: _Union[None, str, _Callable] = None) -> str: """ Extend a docstring. @@ -587,8 +588,8 @@ def _docstringer(docstring: _Union[str, _Callable], fr'\1{return_type_}\n', docstring_,flags=_re.MULTILINE) -def extend_docstring(docstring: _Union[str, _Callable] = None, - extra_parameters: str = None) -> _Callable: +def extend_docstring(docstring: _Union[None, str, _Callable] = None, + extra_parameters: _Optional[str] = None) -> _Callable: """ Decorator: Extend the function's docstring. @@ -672,8 +673,8 @@ def DREAM3D_cell_data_group(fname: _Union[str, _Path]) -> str: def Bravais_to_Miller(*, - uvtw: _np.ndarray = None, - hkil: _np.ndarray = None) -> _np.ndarray: + uvtw: _Optional[_np.ndarray] = None, + hkil: _Optional[_np.ndarray] = None) -> _np.ndarray: """ Transform 4 Miller–Bravais indices to 3 Miller indices of crystal direction [uvw] or plane normal (hkl). @@ -700,8 +701,8 @@ def Bravais_to_Miller(*, return _np.einsum('il,...l',basis,axis) def Miller_to_Bravais(*, - uvw: _np.ndarray = None, - hkl: _np.ndarray = None) -> _np.ndarray: + uvw: _Optional[_np.ndarray] = None, + hkl: _Optional[_np.ndarray] = None) -> _np.ndarray: """ Transform 3 Miller indices to 4 Miller–Bravais indices of crystal direction [uvtw] or plane normal (hkil). From 3334d0845c3a7d897f9b0c700b6ec0aed9819974 Mon Sep 17 00:00:00 2001 From: Test User Date: Wed, 23 Nov 2022 09:23:04 +0100 Subject: [PATCH 45/60] [skip ci] updated version information after successful test of v3.0.0-alpha7-143-gb2fcd1ec1 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 746394ec1..d76e8bcc0 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.0.0-alpha7-125-g762a5de6c +3.0.0-alpha7-143-gb2fcd1ec1 From deb8ebeb5b4ee111e132b0006ce5a9e2856f0dae Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Tue, 22 Nov 2022 14:24:33 +0100 Subject: [PATCH 46/60] avoid confusion during reporting polarization needs to ensure BC for F and P --- src/grid/grid_mech_spectral_polarisation.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/grid/grid_mech_spectral_polarisation.f90 b/src/grid/grid_mech_spectral_polarisation.f90 index 2b4ea364a..2bf3f3a5e 100644 --- a/src/grid/grid_mech_spectral_polarisation.f90 +++ b/src/grid/grid_mech_spectral_polarisation.f90 @@ -541,7 +541,7 @@ subroutine converged(snes_local,PETScIter,devNull1,devNull2,devNull3,reason,dumm err_div/divTol, ' (',err_div, ' / m, tol = ',divTol,')' print '(1x,a,f12.2,a,es8.2,a,es9.2,a)', 'error curl = ', & err_curl/curlTol,' (',err_curl,' -, tol = ',curlTol,')' - print '(1x,a,f12.2,a,es8.2,a,es9.2,a)', 'error stress BC = ', & + print '(1x,a,f12.2,a,es8.2,a,es9.2,a)', 'error mech BC = ', & err_BC/BCTol, ' (',err_BC, ' Pa, tol = ',BCTol,')' print'(/,1x,a)', '===========================================================================' flush(IO_STDOUT) From eea0c4c44cecb0cbdb49ffb01c2c41f99c386843 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Thu, 24 Nov 2022 10:15:23 +0100 Subject: [PATCH 47/60] return was missing --- python/damask/_rotation.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/python/damask/_rotation.py b/python/damask/_rotation.py index 07eb25803..d9d6fbbcb 100644 --- a/python/damask/_rotation.py +++ b/python/damask/_rotation.py @@ -879,6 +879,10 @@ class Rotation: reciprocal : bool, optional Basis vectors are given in reciprocal (instead of real) space. Defaults to False. + Returns + ------- + new : damask.Rotation + """ om = np.array(basis,dtype=float) if om.shape[-2:] != (3,3): raise ValueError('invalid shape') From 9d71ffa3eee182ca1d28232b2975f11daa8c2084 Mon Sep 17 00:00:00 2001 From: Sharan Roongta Date: Thu, 24 Nov 2022 11:23:10 +0100 Subject: [PATCH 48/60] better naming --- examples/config/numerics.yaml | 2 +- src/grid/grid_damage_spectral.f90 | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/config/numerics.yaml b/examples/config/numerics.yaml index 4363b97cc..e2759ab92 100644 --- a/examples/config/numerics.yaml +++ b/examples/config/numerics.yaml @@ -80,4 +80,4 @@ commercialFEM: generic: random_seed: 0 # fixed seeding for pseudo-random number generator, Default 0: use random seed. - residualStiffness: 1.0e-6 # non-zero residual damage. + phi_min: 1.0e-6 # non-zero residual damage. diff --git a/src/grid/grid_damage_spectral.f90 b/src/grid/grid_damage_spectral.f90 index 3e514b960..cd7c20ef8 100644 --- a/src/grid/grid_damage_spectral.f90 +++ b/src/grid/grid_damage_spectral.f90 @@ -33,7 +33,7 @@ module grid_damage_spectral integer :: & itmax !< maximum number of iterations real(pReal) :: & - residualStiffness, & !< non-zero residual damage + phi_min, & !< non-zero residual damage eps_damage_atol, & !< absolute tolerance for damage evolution eps_damage_rtol !< relative tolerance for damage evolution end type tNumerics @@ -95,9 +95,9 @@ subroutine grid_damage_spectral_init() num%eps_damage_rtol = num_grid%get_asFloat ('eps_damage_rtol',defaultVal=1.0e-6_pReal) num_generic => config_numerics%get_dict('generic',defaultVal=emptyDict) - num%residualStiffness = num_generic%get_asFloat('residualStiffness', defaultVal=1.0e-6_pReal) + num%phi_min = num_generic%get_asFloat('phi_min', defaultVal=1.0e-6_pReal) - if (num%residualStiffness < 0.0_pReal) call IO_error(301,ext_msg='residualStiffness') + if (num%phi_min < 0.0_pReal) call IO_error(301,ext_msg='phi_min') if (num%itmax <= 1) call IO_error(301,ext_msg='itmax') if (num%eps_damage_atol <= 0.0_pReal) call IO_error(301,ext_msg='eps_damage_atol') if (num%eps_damage_rtol <= 0.0_pReal) call IO_error(301,ext_msg='eps_damage_rtol') @@ -325,7 +325,7 @@ subroutine formResidual(in,x_scal,r,dummy,err_PETSc) !-------------------------------------------------------------------------------------------------- ! constructing residual - r = max(min(utilities_GreenConvolution(r, K_ref, mu_ref, params%Delta_t),phi_lastInc),num%residualStiffness) & + r = max(min(utilities_GreenConvolution(r, K_ref, mu_ref, params%Delta_t),phi_lastInc),num%phi_min) & - phi_current err_PETSc = 0 From 2884c3c2c9b4d653491429d66c1655071fece362 Mon Sep 17 00:00:00 2001 From: Test User Date: Thu, 24 Nov 2022 13:08:58 +0100 Subject: [PATCH 49/60] [skip ci] updated version information after successful test of v3.0.0-alpha7-146-g19fbfb096 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index d76e8bcc0..c5a763660 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.0.0-alpha7-143-gb2fcd1ec1 +3.0.0-alpha7-146-g19fbfb096 From df4c0fbc33b6f9b60db0d129cf19a2b886777d51 Mon Sep 17 00:00:00 2001 From: Test User Date: Fri, 25 Nov 2022 00:56:42 +0100 Subject: [PATCH 50/60] [skip ci] updated version information after successful test of v3.0.0-alpha7-149-g99673bb86 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index c5a763660..72d594fee 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.0.0-alpha7-146-g19fbfb096 +3.0.0-alpha7-149-g99673bb86 From f8844285d77aa80ac6567a9056b4259f14eca55a Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Thu, 24 Nov 2022 11:38:16 +0100 Subject: [PATCH 51/60] putting understanding of hybridIA into code --- python/tests/test_util.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/python/tests/test_util.py b/python/tests/test_util.py index b2e689471..eff6a1bd4 100644 --- a/python/tests/test_util.py +++ b/python/tests/test_util.py @@ -43,7 +43,7 @@ class TestUtil: @pytest.mark.parametrize('rv',[stats.rayleigh(),stats.weibull_min(1.2),stats.halfnorm(),stats.pareto(2.62)]) - def test_hybridIA(self,rv): + def test_hybridIA_distribution(self,rv): bins = np.linspace(0,10,100000) centers = (bins[1:]+bins[:-1])/2 N_samples = bins.shape[0]-1000 @@ -52,6 +52,21 @@ class TestUtil: dist_sampled = np.histogram(centers[selected],bins)[0]/N_samples*np.sum(dist) assert np.sqrt(((dist - dist_sampled) ** 2).mean()) < .025 and selected.shape[0]==N_samples + def test_hybridIA_constant(self): + N_bins = np.random.randint(20,400) + m = np.random.randint(1,20) + N_samples = m * N_bins + dist = np.ones(N_bins)*np.random.rand() + assert np.all(np.sort(util.hybrid_IA(dist,N_samples))==np.arange(N_samples).astype(int)//m) + + def test_hybridIA_linear(self): + N_points = np.random.randint(10,200) + m = np.random.randint(1,20) + dist = np.arange(N_points) + N_samples = m * np.sum(dist) + assert np.all(np.bincount(util.hybrid_IA(dist*np.random.rand(),N_samples)) == dist*m) + + @pytest.mark.parametrize('point,direction,normalize,keepdims,answer', [ ([1,0,0],'z',False,True, [1,0,0]), From e10f9fa299df508192f7d7d66d3c05ddc22d90e0 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Fri, 25 Nov 2022 01:25:36 +0100 Subject: [PATCH 52/60] not useful here not a general convention, is documented for the affected from_/as_ methods --- python/damask/_rotation.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/python/damask/_rotation.py b/python/damask/_rotation.py index d9d6fbbcb..6566fb880 100644 --- a/python/damask/_rotation.py +++ b/python/damask/_rotation.py @@ -27,10 +27,6 @@ class Rotation: - A rotation angle ω is taken to be positive for a counterclockwise rotation when viewing from the end point of the rotation axis towards the origin. - Rotations will be interpreted in the passive sense. - - Euler angle triplets are implemented using the Bunge convention, - with angular ranges of [0,2π], [0,π], [0,2π]. - - The rotation angle ω is limited to the interval [0,π]. - - The real part of a quaternion is positive, Re(q) ≥ 0 - P = -1 (as default). Examples From 77be2c0d4cbf03703b8c206cf5cecbfef01a5065 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Fri, 25 Nov 2022 07:00:15 +0100 Subject: [PATCH 53/60] standard way to report --- python/damask/util.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/python/damask/util.py b/python/damask/util.py index bda92b732..c23d3c802 100644 --- a/python/damask/util.py +++ b/python/damask/util.py @@ -416,7 +416,7 @@ def project_equal_area(vector: _np.ndarray, -shift if keepdims else 0,axis=-1)[...,:3 if keepdims else 2] -def hybrid_IA(dist: _np.ndarray, +def hybrid_IA(dist: _FloatSequence, N: int, rng_seed: _NumpyRngSeed = None) -> _np.ndarray: """ @@ -425,19 +425,25 @@ def hybrid_IA(dist: _np.ndarray, Parameters ---------- dist : numpy.ndarray - Distribution to be approximated + Distribution to be approximated. N : int Number of samples to draw. rng_seed : {None, int, array_like[ints], SeedSequence, BitGenerator, Generator}, optional A seed to initialize the BitGenerator. Defaults to None. If None, then fresh, unpredictable entropy will be pulled from the OS. + Returns + ------- + hist : numpy.ndarray, shape (N) + Integer approximation of the distribution. + """ - N_opt_samples,N_inv_samples = (max(_np.count_nonzero(dist),N),0) # random subsampling if too little samples requested + N_opt_samples = max(_np.count_nonzero(dist),N) # random subsampling if too little samples requested + N_inv_samples = 0 scale_,scale,inc_factor = (0.0,float(N_opt_samples),1.0) while (not _np.isclose(scale, scale_)) and (N_inv_samples != N_opt_samples): - repeats = _np.rint(scale*dist).astype(_np.int64) + repeats = _np.rint(scale*_np.array(dist)).astype(_np.int64) N_inv_samples = _np.sum(repeats) scale_,scale,inc_factor = (scale,scale+inc_factor*0.5*(scale - scale_), inc_factor*2.0) \ if N_inv_samples < N_opt_samples else \ From af24d47b9ae05e4788cb864f53d6a63190542cfe Mon Sep 17 00:00:00 2001 From: Philip Eisenlohr Date: Fri, 25 Nov 2022 07:55:31 +0000 Subject: [PATCH 54/60] Shorter YAML code --- src/YAML_types.f90 | 73 +++++++++++++++++++++++++--------------------- 1 file changed, 39 insertions(+), 34 deletions(-) diff --git a/src/YAML_types.f90 b/src/YAML_types.f90 index 65dffa8b4..35227845a 100644 --- a/src/YAML_types.f90 +++ b/src/YAML_types.f90 @@ -196,6 +196,7 @@ subroutine selfTest s1 = '1' s2 = '2' allocate(l) + if (l%contains('1')) error stop 'empty tList_contains' call l%append(s1) call l%append(s2) if (any(l%as1dInt() /= [1,2])) error stop 'tList_as1dInt' @@ -204,7 +205,9 @@ subroutine selfTest s2 = 'false' if (any(l%as1dBool() .neqv. [.true.,.false.])) error stop 'tList_as1dBool' if (any(l%as1dString() /= ['true ','false'])) error stop 'tList_as1dString' - if (l%asFormattedString() /= '[true, false]') error stop 'tScalar_asFormattedString' + if (l%asFormattedString() /= '[true, false]') error stop 'tList_asFormattedString' + if ( .not. l%contains('true') & + .or. .not. l%contains('false')) error stop 'tList_contains' end block list @@ -226,6 +229,8 @@ subroutine selfTest s3 = '3' s4 = '4' allocate(d) + if (d%contains('one-two')) error stop 'empty tDict_contains' + if (d%get_asInt('one-two',defaultVal=-1) /= -1) error stop 'empty tDict_get' call d%set('one-two',l) call d%set('three',s3) call d%set('four',s4) @@ -233,6 +238,13 @@ subroutine selfTest error stop 'tDict_asFormattedString' if (d%get_asInt('three') /= 3) error stop 'tDict_get_asInt' if (any(d%get_as1dInt('one-two') /= [1,2])) error stop 'tDict_get_as1dInt' + call d%set('one-two',s4) + if (d%asFormattedString() /= '{one-two: 4, three: 3, four: 4}') & + error stop 'tDict_set overwrite' + if ( .not. d%contains('one-two') & + .or. .not. d%contains('three') & + .or. .not. d%contains('four') & + ) error stop 'tDict_contains' end block dict @@ -407,7 +419,7 @@ recursive function tList_asFormattedString(self) result(str) str = '[' item => self%first - do i = 1, self%length -1 + do i = 2, self%length str = str//item%node%asFormattedString()//', ' item => item%next end do @@ -482,7 +494,7 @@ function tList_as2dFloat(self) row_data => self%get_list(1) allocate(tList_as2dFloat(self%length,row_data%length)) - do i=1,self%length + do i = 1, self%length row_data => self%get_list(i) if (row_data%length /= size(tList_as2dFloat,2)) call IO_error(709,ext_msg='inconsistent column count in tList_as2dFloat') tList_as2dFloat(i,:) = self%get_as1dFloat(i) @@ -593,15 +605,14 @@ function tList_contains(self,k) result(exists) type(tScalar), pointer :: scalar - exists = .false. item => self%first - do j = 1, self%length + exists = .false. + j = 1 + do while (j <= self%length .and. .not. exists) scalar => item%node%asScalar() - if (scalar%value == k) then - exists = .true. - exit - endif + exists = scalar%value == k item => item%next + j = j + 1 end do end function tList_contains @@ -620,9 +631,10 @@ function tList_get(self,i) result(node) integer :: j - if (i < 1 .or. i > self%length) call IO_error(150,ext_msg='tList_get @ '//IO_intAsString(i)) + if (i < 1 .or. i > self%length) call IO_error(150,ext_msg='tList_get @ '//IO_intAsString(i) & + //' of '//IO_intAsString(self%length) ) item => self%first - do j = 2,i + do j = 2, i item => item%next end do node => item%node @@ -854,7 +866,7 @@ recursive function tDict_asFormattedString(self) result(str) str = '{' item => self%first - do i = 1, self%length -1 + do i = 2, self%length str = str//trim(item%key)//': '//item%node%asFormattedString()//', ' item => item%next end do @@ -881,8 +893,7 @@ subroutine tDict_set(self,key,node) self%length = 1 else item => self%first - searchExisting: do while (associated(item%next)) - if (item%key == key) exit + searchExisting: do while (associated(item%next) .and. item%key /= key) item => item%next end do searchExisting if (item%key /= key) then @@ -935,9 +946,10 @@ function tDict_key(self,i) result(key) type(tItem), pointer :: item - if (i < 1 .or. i > self%length) call IO_error(150,ext_msg='tDict_key @ '//IO_intAsString(i)) + if (i < 1 .or. i > self%length) call IO_error(150,ext_msg='tDict_key @ '//IO_intAsString(i) & + //' of '//IO_intAsString(self%length) ) item => self%first - do j = 1, i-1 + do j = 2, i item => item%next end do @@ -986,11 +998,10 @@ function tDict_contains(self,k) result(exists) exists = .false. - do j=1, self%length - if (self%key(j) == k) then - exists = .true. - return - end if + j = 1 + do while(j <= self%length .and. .not. exists) + exists = self%key(j) == k + j = j + 1 end do end function tDict_contains @@ -1008,27 +1019,21 @@ function tDict_get(self,k,defaultVal) result(node) type(tItem), pointer :: item integer :: j - logical :: found - - found = present(defaultVal) - if (found) node => defaultVal - - j = 1 item => self%first - do while(j <= self%length) + + do j=1, self%length if (item%key == k) then - found = .true. - exit + node => item%node + return end if item => item%next - j = j + 1 end do - if (.not. found) then - call IO_error(143,ext_msg=k) + if (present(defaultVal)) then + node => defaultVal else - if (associated(item)) node => item%node + call IO_error(143,ext_msg=k) end if end function tDict_get From aca6ae928dc2f319b70c3f12c05cfde0973ba521 Mon Sep 17 00:00:00 2001 From: Test User Date: Fri, 25 Nov 2022 13:16:48 +0100 Subject: [PATCH 55/60] [skip ci] updated version information after successful test of v3.0.0-alpha7-152-g36f050a08 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 72d594fee..5f41b5f96 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.0.0-alpha7-149-g99673bb86 +3.0.0-alpha7-152-g36f050a08 From bfdd072d06a79c9bb4321daaccf908c7f917ccae Mon Sep 17 00:00:00 2001 From: Test User Date: Sat, 26 Nov 2022 02:15:10 +0100 Subject: [PATCH 56/60] [skip ci] updated version information after successful test of v3.0.0-alpha7-160-g92ae86b63 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 5f41b5f96..b03081020 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.0.0-alpha7-152-g36f050a08 +3.0.0-alpha7-160-g92ae86b63 From 8112f87d395e7a4a142f5134c31f6c83407404cd Mon Sep 17 00:00:00 2001 From: Daniel Otto de Mentock Date: Mon, 28 Nov 2022 10:33:07 +0100 Subject: [PATCH 57/60] parameter names can contain underscores --- python/damask/util.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/damask/util.py b/python/damask/util.py index bda92b732..f1fd08392 100644 --- a/python/damask/util.py +++ b/python/damask/util.py @@ -567,7 +567,7 @@ def _docstringer(docstring: _Union[str, _Callable], shift = min([len(line)-len(line.lstrip(' '))-indent for line in content]) extra = '\n'.join([(line[shift:] if shift > 0 else f'{" "*-shift}{line}') for line in content]) - docstring_ = _re.sub(fr'(^([ ]*){key}\s*\n\2{"-"*len(key)}[\n ]*[A-Za-z0-9 ]*: ([^\n]+\n)*)', + docstring_ = _re.sub(fr'(^([ ]*){key}\s*\n\2{"-"*len(key)}[\n ]*[A-Za-z0-9_ ]*: ([^\n]+\n)*)', fr'\1{extra}\n', docstring_,flags=_re.MULTILINE) @@ -583,7 +583,7 @@ def _docstringer(docstring: _Union[str, _Callable], +(return_class.__name__ if not isinstance(return_class,str) else return_class) ) - return _re.sub(r'(^([ ]*)Returns\s*\n\2-------\s*\n[ ]*[A-Za-z0-9 ]*: )(.*)\n', + return _re.sub(r'(^([ ]*)Returns\s*\n\2-------\s*\n[ ]*[A-Za-z0-9_ ]*: )(.*)\n', fr'\1{return_type_}\n', docstring_,flags=_re.MULTILINE) From d668f8a56db0bb765357ae42779eb701c79f7366 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Mon, 28 Nov 2022 20:05:39 +0000 Subject: [PATCH 58/60] don't add empty strings --- python/damask/_vtk.py | 9 +++++++-- python/damask/util.py | 8 ++++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/python/damask/_vtk.py b/python/damask/_vtk.py index e398c0d53..a6f3b2047 100644 --- a/python/damask/_vtk.py +++ b/python/damask/_vtk.py @@ -116,7 +116,10 @@ class VTK: """ s = vtk.vtkStringArray() s.SetName('comments') - for c in util.tail_repack(comments,self.comments): + comments_ = util.tail_repack(comments,self.comments) if comments[:len(self.comments)] == self.comments else \ + [comments] if isinstance(comments,str) else \ + comments + for c in comments_: s.InsertNextValue(c) self.vtk_data.GetFieldData().AddArray(s) @@ -547,9 +550,11 @@ class VTK: Notes ----- - See http://compilatrix.com/article/vtk-1 for further ideas. + The first component is shown when visualizing vector datasets + (this includes tensor datasets because they are flattened). """ + # See http://compilatrix.com/article/vtk-1 for possible improvements. try: import wx _ = wx.App(False) # noqa diff --git a/python/damask/util.py b/python/damask/util.py index 16054b6cb..dc19287f1 100644 --- a/python/damask/util.py +++ b/python/damask/util.py @@ -793,7 +793,7 @@ def tail_repack(extended: _Union[str, _Sequence[str]], Parameters ---------- - extended : (list of) str + extended : (sequence of) str Extended string list with potentially autosplitted tailing string relative to `existing`. existing : list of str Base string list. @@ -811,9 +811,9 @@ def tail_repack(extended: _Union[str, _Sequence[str]], ['a','new','shiny','e','n','t','r','y'] """ - return [extended] if isinstance(extended,str) else existing + \ - ([''.join(extended[len(existing):])] if _np.prod([len(i) for i in extended[len(existing):]]) == 1 else - list(extended[len(existing):])) + new = extended[len(existing):] + return [extended] if isinstance(extended,str) else \ + existing + list([''.join(new)] if _np.prod([len(i) for i in new]) == 1 else new) def aslist(arg: _Union[_IntCollection, int, None]) -> _List: From 88878c50c66c30e58b390cd32c494feb6d1bc58e Mon Sep 17 00:00:00 2001 From: Test User Date: Tue, 29 Nov 2022 00:45:34 +0100 Subject: [PATCH 59/60] [skip ci] updated version information after successful test of v3.0.0-alpha7-163-g3505fdee9 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index b03081020..fc19cbd0b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.0.0-alpha7-160-g92ae86b63 +3.0.0-alpha7-163-g3505fdee9 From afa0a644ed0a1a1aa4942f232cc2505ae4a0fe74 Mon Sep 17 00:00:00 2001 From: Test User Date: Tue, 29 Nov 2022 08:43:36 +0100 Subject: [PATCH 60/60] [skip ci] updated version information after successful test of v3.0.0-alpha7-168-g741aeab1d --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index fc19cbd0b..825f32e31 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.0.0-alpha7-163-g3505fdee9 +3.0.0-alpha7-168-g741aeab1d