further commenting, removing not used variables and code (marc2vtk)

This commit is contained in:
Martin Diehl 2016-03-04 18:50:13 +01:00
parent d1e8f69857
commit a4bbdd5ecb
8 changed files with 194 additions and 273 deletions

View File

@ -1,27 +1,27 @@
# -*- coding: UTF-8 no BOM -*-
# $Id$
"""Main aggregator"""
import sys, os
with open(os.path.join(os.path.dirname(__file__),'../../VERSION')) as f:
version = f.readline()[:-1]
from .environment import Environment # only one class
from .asciitable import ASCIItable # only one class
from .config import Material # will be extended to debug and numerics
from .colormaps import Colormap, Color
from .orientation import Quaternion, Rodrigues, Symmetry, Orientation
from .environment import Environment # noqa
from .asciitable import ASCIItable # noqa
from .config import Material # noqa
from .colormaps import Colormap, Color # noqa
from .orientation import Quaternion, Rodrigues, Symmetry, Orientation # noqa
# try:
# from .corientation import Quaternion, Rodrigues, Symmetry, Orientation
# print "Import Cython version of Orientation module"
# except:
# from .orientation import Quaternion, Rodrigues, Symmetry, Orientation
#from .block import Block # only one class
from .result import Result # only one class
from .geometry import Geometry # one class with subclasses
from .solver import Solver # one class with subclasses
from .test import Test
from .util import extendableOption
from .result import Result # noqa
from .geometry import Geometry # noqa
from .solver import Solver # noqa
from .test import Test # noqa
from .util import extendableOption # noqa
try:
from . import core

View File

@ -4,12 +4,9 @@
import os,sys
import numpy as np
import util
class ASCIItable():
'''
There should be a doc string here :)
'''
"""Read and write to ASCII tables"""
__slots__ = ['__IO__',
'info',
@ -58,8 +55,8 @@ class ASCIItable():
self.data = []
self.line = ''
if self.__IO__['in'] == None \
or self.__IO__['out'] == None: raise IOError # complain if any required file access not possible
if self.__IO__['in'] is None \
or self.__IO__['out'] is None: raise IOError # complain if any required file access not possible
# ------------------------------------------------------------------
def _transliterateToFloat(self,
@ -86,9 +83,7 @@ class ASCIItable():
# ------------------------------------------------------------------
def output_write(self,
what):
'''
aggregate a single row (string) or list of (possibly containing further lists of) rows into output
'''
"""aggregate a single row (string) or list of (possibly containing further lists of) rows into output"""
if not isinstance(what, (str, unicode)):
try:
for item in what: self.output_write(item)
@ -104,7 +99,7 @@ class ASCIItable():
clear = True):
try:
self.__IO__['output'] == [] or self.__IO__['out'].write('\n'.join(self.__IO__['output']) + '\n')
except IOError as e:
except IOError:
return False
if clear: self.output_clear()
return True
@ -127,11 +122,12 @@ class ASCIItable():
# ------------------------------------------------------------------
def head_read(self):
'''
get column labels by either reading
the first row or, if keyword "head[*]" is present,
the last line of the header
'''
"""
get column labels by either reading
the first row or, if keyword "head[*]" is present,
the last line of the header
"""
import re
try:
@ -180,10 +176,7 @@ class ASCIItable():
# ------------------------------------------------------------------
def head_write(self,
header = True):
'''
write current header information (info + labels)
'''
"""write current header information (info + labels)"""
head = ['{}\theader'.format(len(self.info)+self.__IO__['labeled'])] if header else []
head.append(self.info)
if self.__IO__['labeled']: head.append('\t'.join(self.labels))
@ -192,9 +185,7 @@ class ASCIItable():
# ------------------------------------------------------------------
def head_getGeom(self):
'''
interpret geom header
'''
"""interpret geom header"""
identifiers = {
'grid': ['a','b','c'],
'size': ['x','y','z'],
@ -234,9 +225,7 @@ class ASCIItable():
# ------------------------------------------------------------------
def head_putGeom(self,info):
'''
translate geometry description to header
'''
"""translate geometry description to header"""
self.info_append([
"grid\ta {}\tb {}\tc {}".format(*info['grid']),
"size\tx {}\ty {}\tz {}".format(*info['size']),
@ -249,9 +238,7 @@ class ASCIItable():
def labels_append(self,
what,
reset = False):
'''
add item or list to existing set of labels (and switch on labeling)
'''
"""add item or list to existing set of labels (and switch on labeling)"""
if not isinstance(what, (str, unicode)):
try:
for item in what: self.labels_append(item)
@ -265,26 +252,25 @@ class ASCIItable():
# ------------------------------------------------------------------
def labels_clear(self):
'''
delete existing labels and switch to no labeling
'''
"""delete existing labels and switch to no labeling"""
self.labels = []
self.__IO__['labeled'] = False
# ------------------------------------------------------------------
def label_index(self,
labels):
'''
tell index of column label(s).
return numpy array if asked for list of labels.
transparently deals with label positions implicitly given as numbers or their headings given as strings.
'''
"""
tell index of column label(s).
return numpy array if asked for list of labels.
transparently deals with label positions implicitly given as numbers or their headings given as strings.
"""
from collections import Iterable
if isinstance(labels, Iterable) and not isinstance(labels, str): # check whether list of labels is requested
idx = []
for label in labels:
if label != None:
if label is not None:
try:
idx.append(int(label)) # column given as integer number?
except ValueError:
@ -305,25 +291,25 @@ class ASCIItable():
try:
idx = self.labels.index('1_'+labels) # locate '1_'+string in label list
except ValueError:
idx = None if labels == None else -1
idx = None if labels is None else -1
return np.array(idx) if isinstance(idx,list) else idx
# ------------------------------------------------------------------
def label_dimension(self,
labels):
'''
tell dimension (length) of column label(s).
return numpy array if asked for list of labels.
transparently deals with label positions implicitly given as numbers or their headings given as strings.
'''
"""
tell dimension (length) of column label(s).
return numpy array if asked for list of labels.
transparently deals with label positions implicitly given as numbers or their headings given as strings.
"""
from collections import Iterable
if isinstance(labels, Iterable) and not isinstance(labels, str): # check whether list of labels is requested
dim = []
for label in labels:
if label != None:
if label is not None:
myDim = -1
try: # column given as number?
idx = int(label)
@ -364,12 +350,12 @@ class ASCIItable():
# ------------------------------------------------------------------
def label_indexrange(self,
labels):
'''
tell index range for given label(s).
return numpy array if asked for list of labels.
transparently deals with label positions implicitly given as numbers or their headings given as strings.
'''
"""
tell index range for given label(s).
return numpy array if asked for list of labels.
transparently deals with label positions implicitly given as numbers or their headings given as strings.
"""
from collections import Iterable
start = self.label_index(labels)
@ -381,9 +367,7 @@ class ASCIItable():
# ------------------------------------------------------------------
def info_append(self,
what):
'''
add item or list to existing set of infos
'''
"""add item or list to existing set of infos"""
if not isinstance(what, (str, unicode)):
try:
for item in what: self.info_append(item)
@ -394,9 +378,7 @@ class ASCIItable():
# ------------------------------------------------------------------
def info_clear(self):
'''
delete any info block
'''
"""delete any info block"""
self.info = []
# ------------------------------------------------------------------
@ -409,9 +391,7 @@ class ASCIItable():
# ------------------------------------------------------------------
def data_skipLines(self,
count):
'''
wind forward by count number of lines
'''
"""wind forward by count number of lines"""
for i in xrange(count):
alive = self.data_read()
@ -421,9 +401,7 @@ class ASCIItable():
def data_read(self,
advance = True,
respectLabels = True):
'''
read next line (possibly buffered) and parse it into data array
'''
"""read next line (possibly buffered) and parse it into data array"""
self.line = self.__IO__['readBuffer'].pop(0) if len(self.__IO__['readBuffer']) > 0 \
else self.__IO__['in'].readline().strip() # take buffered content or get next data row from file
@ -434,7 +412,7 @@ class ASCIItable():
if self.__IO__['labeled'] and respectLabels: # if table has labels
items = self.line.split()[:len(self.__IO__['labels'])] # use up to label count (from original file info)
self.data = items if len(items) == len(self.__IO__['labels']) else [] # take entries if correct number, i.e. not too few compared to label count
self.data = items if len(items) == len(self.__IO__['labels']) else [] # take entries if label count matches
else:
self.data = self.line.split() # otherwise take all
@ -443,9 +421,7 @@ class ASCIItable():
# ------------------------------------------------------------------
def data_readArray(self,
labels = []):
'''
read whole data of all (given) labels as numpy array
'''
"""read whole data of all (given) labels as numpy array"""
from collections import Iterable
try:
@ -453,7 +429,7 @@ class ASCIItable():
except:
pass # assume/hope we are at data start already...
if labels == None or labels == []:
if labels is None or labels == []:
use = None # use all columns (and keep labels intact)
labels_missing = []
else:
@ -467,9 +443,10 @@ class ASCIItable():
columns = []
for i,(c,d) in enumerate(zip(indices[present],dimensions[present])): # for all valid labels ...
# ... transparently add all components unless column referenced by number or with explicit dimension
columns += range(c,c + \
(d if str(c) != str(labels[present[i]]) else \
1)) # ... transparently add all components unless column referenced by number or with explicit dimension
1))
use = np.array(columns)
self.labels = list(np.array(self.labels)[use]) # update labels with valid subset
@ -481,9 +458,7 @@ class ASCIItable():
# ------------------------------------------------------------------
def data_write(self,
delimiter = '\t'):
'''
write current data array and report alive output back
'''
"""write current data array and report alive output back"""
if len(self.data) == 0: return True
if isinstance(self.data[0],list):
@ -495,9 +470,7 @@ class ASCIItable():
def data_writeArray(self,
fmt = None,
delimiter = '\t'):
'''
write whole numpy array data
'''
"""write whole numpy array data"""
for row in self.data:
try:
output = [fmt % value for value in row] if fmt else map(repr,row)
@ -520,9 +493,7 @@ class ASCIItable():
# ------------------------------------------------------------------
def data_set(self,
what, where):
'''
update data entry in column "where". grows data array if needed.
'''
"""update data entry in column "where". grows data array if needed."""
idx = -1
try:
idx = self.label_index(where)
@ -547,10 +518,7 @@ class ASCIItable():
# ------------------------------------------------------------------
def microstructure_read(self,
grid):
'''
read microstructure data (from .geom format)
'''
"""read microstructure data (from .geom format)"""
N = grid.prod() # expected number of microstructure indices in data
microstructure = np.zeros(N,'i') # initialize as flat array

View File

@ -2,4 +2,4 @@
"""Aggregator for configuration file handling"""
from .material import Material #noqa
from .material import Material # noqa

View File

@ -243,7 +243,8 @@ class Material():
except AttributeError:
pass
for (phase,texture,fraction,crystallite) in zip(components['phase'],components['texture'],components['fraction'],components['crystallite']):
for (phase,texture,fraction,crystallite) in zip(components['phase'],components['texture'],
components['fraction'],components['crystallite']):
microstructure.add_multiKey('constituent','phase %i\ttexture %i\tfraction %g\ncrystallite %i'%(
self.data['phase']['__order__'].index(phase)+1,
self.data['texture']['__order__'].index(texture)+1,

View File

@ -9,7 +9,6 @@ import numpy as np
# ******************************************************************************************
class Rodrigues:
# ******************************************************************************************
def __init__(self, vector = np.zeros(3)):
self.vector = vector
@ -28,20 +27,22 @@ class Rodrigues:
# ******************************************************************************************
class Quaternion:
# ******************************************************************************************
# All methods and naming conventions based off
# http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions
"""
Orientation represented as unit quaternion
All methods and naming conventions based on http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions
# w is the real part, (x, y, z) are the imaginary parts
# Representation of rotation is in ACTIVE form!
# (derived directly or through angleAxis, Euler angles, or active matrix)
# vector "a" (defined in coordinate system "A") is actively rotated to new coordinates "b"
# b = Q * a
# b = np.dot(Q.asMatrix(),a)
w is the real part, (x, y, z) are the imaginary parts
Representation of rotation is in ACTIVE form!
(derived directly or through angleAxis, Euler angles, or active matrix)
vector "a" (defined in coordinate system "A") is actively rotated to new coordinates "b"
b = Q * a
b = np.dot(Q.asMatrix(),a)
"""
def __init__(self,
quatArray = [1.0,0.0,0.0,0.0]):
"""initializes to identity if not given"""
self.w, \
self.x, \
self.y, \
@ -49,19 +50,23 @@ class Quaternion:
self.homomorph()
def __iter__(self):
"""components"""
return iter([self.w,self.x,self.y,self.z])
def __copy__(self):
"""create copy"""
Q = Quaternion([self.w,self.x,self.y,self.z])
return Q
copy = __copy__
def __repr__(self):
"""readbable string"""
return 'Quaternion(real=%+.6f, imag=<%+.6f, %+.6f, %+.6f>)' % \
(self.w, self.x, self.y, self.z)
def __pow__(self, exponent):
"""power"""
omega = math.acos(self.w)
vRescale = math.sin(exponent*omega)/math.sin(omega)
Q = Quaternion()
@ -72,6 +77,7 @@ class Quaternion:
return Q
def __ipow__(self, exponent):
"""in place power"""
omega = math.acos(self.w)
vRescale = math.sin(exponent*omega)/math.sin(omega)
self.w = np.cos(exponent*omega)
@ -81,6 +87,7 @@ class Quaternion:
return self
def __mul__(self, other):
"""multiplication"""
try: # quaternion
Aw = self.w
Ax = self.x
@ -128,6 +135,7 @@ class Quaternion:
return self.copy()
def __imul__(self, other):
"""in place multiplication"""
try: # Quaternion
Ax = self.x
Ay = self.y
@ -145,6 +153,7 @@ class Quaternion:
return self
def __div__(self, other):
"""division"""
if isinstance(other, (int,float,long)):
w = self.w / other
x = self.x / other
@ -155,6 +164,7 @@ class Quaternion:
return NotImplemented
def __idiv__(self, other):
"""in place division"""
if isinstance(other, (int,float,long)):
self.w /= other
self.x /= other
@ -163,6 +173,7 @@ class Quaternion:
return self
def __add__(self, other):
"""addition"""
if isinstance(other, Quaternion):
w = self.w + other.w
x = self.x + other.x
@ -173,6 +184,7 @@ class Quaternion:
return NotImplemented
def __iadd__(self, other):
"""in place division"""
if isinstance(other, Quaternion):
self.w += other.w
self.x += other.x
@ -181,6 +193,7 @@ class Quaternion:
return self
def __sub__(self, other):
"""subtraction"""
if isinstance(other, Quaternion):
Q = self.copy()
Q.w -= other.w
@ -192,6 +205,7 @@ class Quaternion:
return self.copy()
def __isub__(self, other):
"""in place subtraction"""
if isinstance(other, Quaternion):
self.w -= other.w
self.x -= other.x
@ -200,6 +214,7 @@ class Quaternion:
return self
def __neg__(self):
"""additive inverse"""
self.w = -self.w
self.x = -self.x
self.y = -self.y
@ -207,6 +222,7 @@ class Quaternion:
return self
def __abs__(self):
"""norm"""
return math.sqrt(self.w ** 2 + \
self.x ** 2 + \
self.y ** 2 + \
@ -215,6 +231,7 @@ class Quaternion:
magnitude = __abs__
def __eq__(self,other):
"""equal at e-8 precision"""
return (abs(self.w-other.w) < 1e-8 and \
abs(self.x-other.x) < 1e-8 and \
abs(self.y-other.y) < 1e-8 and \
@ -226,9 +243,11 @@ class Quaternion:
abs(-self.z-other.z) < 1e-8)
def __ne__(self,other):
"""not equal at e-8 precision"""
return not self.__eq__(self,other)
def __cmp__(self,other):
"""linear ordering"""
return cmp(self.Rodrigues(),other.Rodrigues())
def magnitude_squared(self):
@ -290,9 +309,10 @@ class Quaternion:
return np.outer([i for i in self],[i for i in self])
def asMatrix(self):
return np.array([[1.0-2.0*(self.y*self.y+self.z*self.z), 2.0*(self.x*self.y-self.z*self.w), 2.0*(self.x*self.z+self.y*self.w)],
[ 2.0*(self.x*self.y+self.z*self.w), 1.0-2.0*(self.x*self.x+self.z*self.z), 2.0*(self.y*self.z-self.x*self.w)],
[ 2.0*(self.x*self.z-self.y*self.w), 2.0*(self.x*self.w+self.y*self.z), 1.0-2.0*(self.x*self.x+self.y*self.y)]])
return np.array(
[[1.0-2.0*(self.y*self.y+self.z*self.z), 2.0*(self.x*self.y-self.z*self.w), 2.0*(self.x*self.z+self.y*self.w)],
[ 2.0*(self.x*self.y+self.z*self.w), 1.0-2.0*(self.x*self.x+self.z*self.z), 2.0*(self.y*self.z-self.x*self.w)],
[ 2.0*(self.x*self.z-self.y*self.w), 2.0*(self.x*self.w+self.y*self.z), 1.0-2.0*(self.x*self.x+self.y*self.y)]])
def asAngleAxis(self,
degrees = False):
@ -315,15 +335,17 @@ class Quaternion:
return np.inf*np.ones(3) if self.w == 0.0 else np.array([self.x, self.y, self.z])/self.w
def asEulers(self,
type = 'bunge',
type = "bunge",
degrees = False,
standardRange = False):
'''
u"""
Orientation as Bunge-Euler angles
conversion of ACTIVE rotation to Euler angles taken from:
Melcher, A.; Unser, A.; Reichhardt, M.; Nestler, B.; Pötschke, M.; Selzer, M.
Conversion of EBSD data by a quaternion based algorithm to be used for grain structure simulations
Technische Mechanik 30 (2010) pp 401--413
'''
"""
angles = [0.0,0.0,0.0]
if type.lower() == 'bunge' or type.lower() == 'zxz':
@ -369,7 +391,7 @@ class Quaternion:
@classmethod
def fromRandom(cls,randomSeed = None):
if randomSeed == None:
if randomSeed is None:
randomSeed = int(os.urandom(4).encode('hex'), 16)
np.random.seed(randomSeed)
r = np.random.random(3)
@ -420,7 +442,6 @@ class Quaternion:
y = - c1 * s2 * s3 + s1 * s2 * c3
z = c1 * c2 * s3 + s1 * c2 * c3
else:
# print 'unknown Euler convention'
w = c1 * c2 * c3 - s1 * s2 * s3
x = s1 * s2 * c3 + c1 * c2 * s3
y = s1 * c2 * c3 + c1 * s2 * s3
@ -428,7 +449,8 @@ class Quaternion:
return cls([w,x,y,z])
## Modified Method to calculate Quaternion from Orientation Matrix, Source: http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/
# Modified Method to calculate Quaternion from Orientation Matrix,
# Source: http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/
@classmethod
def fromMatrix(cls, m):
@ -482,8 +504,12 @@ class Quaternion:
@classmethod
def new_interpolate(cls, q1, q2, t):
# see http://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/20070017872_2007014421.pdf for (another?) way to interpolate quaternions
"""
interpolation
see http://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/20070017872_2007014421.pdf
for (another?) way to interpolate quaternions
"""
assert isinstance(q1, Quaternion) and isinstance(q2, Quaternion)
Q = cls()
@ -522,11 +548,11 @@ class Quaternion:
# ******************************************************************************************
class Symmetry:
# ******************************************************************************************
lattices = [None,'orthorhombic','tetragonal','hexagonal','cubic',]
def __init__(self, symmetry = None):
"""lattice with given symmetry, defaults to None"""
if isinstance(symmetry, basestring) and symmetry.lower() in Symmetry.lattices:
self.lattice = symmetry.lower()
else:
@ -534,29 +560,31 @@ class Symmetry:
def __copy__(self):
"""copy"""
return self.__class__(self.lattice)
copy = __copy__
def __repr__(self):
"""readbable string"""
return '%s' % (self.lattice)
def __eq__(self, other):
"""equal"""
return self.lattice == other.lattice
def __neq__(self, other):
"""not equal"""
return not self.__eq__(other)
def __cmp__(self,other):
"""linear ordering"""
return cmp(Symmetry.lattices.index(self.lattice),Symmetry.lattices.index(other.lattice))
def symmetryQuats(self,who = []):
'''
List of symmetry operations as quaternions.
'''
"""List of symmetry operations as quaternions."""
if self.lattice == 'cubic':
symQuats = [
[ 1.0, 0.0, 0.0, 0.0 ],
@ -629,18 +657,15 @@ class Symmetry:
def equivalentQuaternions(self,
quaternion,
who = []):
'''
List of symmetrically equivalent quaternions based on own symmetry.
'''
"""List of symmetrically equivalent quaternions based on own symmetry."""
return [quaternion*q for q in self.symmetryQuats(who)]
def inFZ(self,R):
'''
Check whether given Rodrigues vector falls into fundamental zone of own symmetry.
'''
"""Check whether given Rodrigues vector falls into fundamental zone of own symmetry."""
if isinstance(R, Quaternion): R = R.asRodrigues() # translate accidentially passed quaternion
R = abs(R) # fundamental zone in Rodrigues space is point symmetric around origin
# fundamental zone in Rodrigues space is point symmetric around origin
R = abs(R)
if self.lattice == 'cubic':
return math.sqrt(2.0)-1.0 >= R[0] \
and math.sqrt(2.0)-1.0 >= R[1] \
@ -662,12 +687,13 @@ class Symmetry:
def inDisorientationSST(self,R):
'''
"""
Check whether given Rodrigues vector (of misorientation) falls into standard stereographic triangle of own symmetry.
Determination of disorientations follow the work of A. Heinz and P. Neumann:
Representation of Orientation and Disorientation Data for Cubic, Hexagonal, Tetragonal and Orthorhombic Crystals
Acta Cryst. (1991). A47, 780-789
'''
"""
if isinstance(R, Quaternion): R = R.asRodrigues() # translate accidentially passed quaternion
epsilon = 0.0
@ -691,11 +717,12 @@ class Symmetry:
vector,
proper = False,
color = False):
'''
"""
Check whether given vector falls into standard stereographic triangle of own symmetry.
proper considers only vectors with z >= 0, hence uses two neighboring SSTs.
Return inverse pole figure color if requested.
'''
"""
# basis = {'cubic' : np.linalg.inv(np.array([[0.,0.,1.], # direction of red
# [1.,0.,1.]/np.sqrt(2.), # direction of green
# [1.,1.,1.]/np.sqrt(3.)]).transpose()), # direction of blue
@ -752,15 +779,15 @@ class Symmetry:
inSST = np.all(theComponents >= 0.0)
else:
v = np.array(vector,dtype = float)
if proper: # check both improper ...
if proper: # check both improper ...
theComponents = np.dot(basis['improper'],v)
inSST = np.all(theComponents >= 0.0)
if not inSST: # ... and proper SST
theComponents = np.dot(basis['proper'],v)
inSST = np.all(theComponents >= 0.0)
else:
v[2] = abs(v[2]) # z component projects identical for positive and negative values
theComponents = np.dot(basis['improper'],v)
v[2] = abs(v[2]) # z component projects identical
theComponents = np.dot(basis['improper'],v) # for positive and negative values
inSST = np.all(theComponents >= 0.0)
if color: # have to return color array
@ -781,7 +808,6 @@ class Symmetry:
# ******************************************************************************************
class Orientation:
# ******************************************************************************************
__slots__ = ['quaternion','symmetry']
@ -791,7 +817,7 @@ class Orientation:
angleAxis = None,
matrix = None,
Eulers = None,
random = False, # put any integer to have a fixed seed or True for real random
random = False, # integer to have a fixed seed or True for real random
symmetry = None,
):
if random: # produce random orientation
@ -815,12 +841,14 @@ class Orientation:
self.symmetry = Symmetry(symmetry)
def __copy__(self):
"""copy"""
return self.__class__(quaternion=self.quaternion,symmetry=self.symmetry.lattice)
copy = __copy__
def __repr__(self):
"""value as all implemented representations"""
return 'Symmetry: %s\n' % (self.symmetry) + \
'Quaternion: %s\n' % (self.quaternion) + \
'Matrix:\n%s\n' % ( '\n'.join(['\t'.join(map(str,self.asMatrix()[i,:])) for i in range(3)]) ) + \
@ -863,10 +891,7 @@ class Orientation:
self.equivalentQuaternions(who))
def reduced(self):
'''
Transform orientation to fall into fundamental zone according to symmetry
'''
"""Transform orientation to fall into fundamental zone according to symmetry"""
for me in self.symmetry.equivalentQuaternions(self.quaternion):
if self.symmetry.inFZ(me.asRodrigues()): break
@ -876,13 +901,13 @@ class Orientation:
def disorientation(self,
other,
SST = True):
'''
"""
Disorientation between myself and given other orientation.
Rotation axis falls into SST if SST == True.
(Currently requires same symmetry for both orientations.
Look into A. Heinz and P. Neumann 1991 for cases with differing sym.)
'''
"""
if self.symmetry != other.symmetry: raise TypeError('disorientation between different symmetry classes not supported yet.')
misQ = self.quaternion.conjugated()*other.quaternion
@ -900,32 +925,27 @@ class Orientation:
if breaker: break
if breaker: break
# disorientation, own sym, other sym, self-->other: True, self<--other: False
return (Orientation(quaternion = theQ,symmetry = self.symmetry.lattice),
i,j,k == 1) # disorientation, own sym, other sym, self-->other: True, self<--other: False
i,j,k == 1)
def inversePole(self,
axis,
proper = False,
SST = True):
'''
axis rotated according to orientation (using crystal symmetry to ensure location falls into SST)
'''
"""axis rotated according to orientation (using crystal symmetry to ensure location falls into SST)"""
if SST: # pole requested to be within SST
for i,q in enumerate(self.symmetry.equivalentQuaternions(self.quaternion)): # test all symmetric equivalent quaternions
pole = q.conjugated()*axis # align crystal direction to axis
if self.symmetry.inSST(pole,proper): break # found SST version
if self.symmetry.inSST(pole,proper): break # found SST version
else:
pole = self.quaternion.conjugated()*axis # align crystal direction to axis
return (pole,i if SST else 0)
def IPFcolor(self,axis):
'''
TSL color of inverse pole figure for given axis
'''
"""TSL color of inverse pole figure for given axis"""
color = np.zeros(3,'d')
for q in self.symmetry.equivalentQuaternions(self.quaternion):
@ -939,7 +959,9 @@ class Orientation:
def average(cls,
orientations,
multiplicity = []):
"""RETURN THE AVERAGE ORIENTATION
"""
average orientation
ref: F. Landis Markley, Yang Cheng, John Lucas Crassidis, and Yaakov Oshman.
Averaging Quaternions,
Journal of Guidance, Control, and Dynamics, Vol. 30, No. 4 (2007), pp. 1193-1197.
@ -949,7 +971,6 @@ class Orientation:
b = Orientation(Eulers=np.radians([20, 0, 0]), symmetry='hexagonal')
avg = Orientation.average([a,b])
"""
if not all(isinstance(item, Orientation) for item in orientations):
raise TypeError("Only instances of Orientation can be averaged.")
@ -960,8 +981,7 @@ class Orientation:
reference = orientations[0] # take first as reference
for i,(o,n) in enumerate(zip(orientations,multiplicity)):
closest = o.equivalentOrientations(reference.disorientation(o,SST = False)[2])[0] # select sym orientation with lowest misorientation
M = closest.quaternion.asM() * n if i == 0 else M + closest.quaternion.asM() * n # add (multiples) of this orientation to average
M = closest.quaternion.asM() * n if i == 0 else M + closest.quaternion.asM() * n # noqa add (multiples) of this orientation to average noqa
eig, vec = np.linalg.eig(M/N)
return Orientation(quaternion = Quaternion(quatArray = np.real(vec.T[eig.argmax()])),

View File

@ -11,10 +11,11 @@ except (ImportError) as e:
sys.stderr.write('\nREMARK: h5py module not available \n\n')
class Result():
'''
General class for result parsing.
Needs h5py to be installed
'''
"""
General class for result parsing.
Needs h5py to be installed
"""
def __init__(self,resultsFile):
self.data=h5py.File(resultsFile,"r")

View File

@ -1,6 +1,5 @@
# -*- coding: UTF-8 no BOM -*-
# $Id$
# This tool converts a msc.marc result file into the vtk format that
# can be viewed by Paraview software (Kitware), or MayaVi (needs xml-vtk, or ...
#
@ -8,13 +7,8 @@
# Some example vtk files: http://people.sc.fsu.edu/~jburkardt/data/vtk/vtk.html
# www.paraview.org
import os,sys,math,time,re
# python external
try:
import numpy as N
import numpy
except:
print('Could not import numpy.')
import os,sys,re
import numpy as np
import py_post # MSC closed source module to access marc result files
@ -27,7 +21,7 @@ class MARC_POST():
self.fpath=os.path.join(self.projdir,self.postname)
print('Trying to open ',self.fpath,' ...')
self.p=py_post.post_open(self.fpath)
if self.p==None:
if self.p is None:
print('Could not open %s.'%self.postname); #return 'err'#; sys.exit(1)
raise Exception('Could not open t16')
print('Postfile %s%s is open ...'%(self.projdir,self.postname))
@ -105,7 +99,6 @@ class MARC_POST():
def writeNodes2VTK(self, fobj):
self.points=[]
self.VTKcnt=200 # number of values per line in vtk file
ndCnt=1
fobj.write('POINTS %i'%self.p.nodes()+' float\n')
self.nodes_dict={} # store the node IDs in case of holes in the numbering
for iNd in self.nodes:
@ -126,8 +119,6 @@ class MARC_POST():
el=self.p.element(iEl)
cell_nodes=[] # for pyvtk
ndlist=el.items
#for k in [0, 1, 3, 2, 4, 5, 7, 6]: # FOR CELL TPYE VTK_VOXEL
#for k in [0, 4, 3, 1, 5, 7, 6, 2]:
for k in [0, 1, 2, 3, 4, 5, 6, 7]: # FOR CELL TYPE VTK_HEXAHEDRON
node=ndlist[k]-1
cell_nodes.append(self.nodes_dict[node])
@ -147,7 +138,6 @@ class MARC_POST():
fobj.write('\n');cnt=0
fobj.write('\n')
print('Elements written to VTK: %i'%self.p.elements())
#print('Nr of nodes: ',self.nodes)
def writeElScalars2NodesVTK(self,fobj):
fobj.write('\nPOINT_DATA %i\n'%self.p.nodes())
@ -157,7 +147,6 @@ class MARC_POST():
fobj.write('LOOKUP_TABLE default\n')
idxScal=self.nscal_list.index('Displacement Z')
for iNd in self.nodes:
#fobj.write('%f %f '%(self.p.node_scalar(iNd,idxScal), N.random.rand()))
fobj.write('%f '%(self.p.node_scalar(iNd,idxScal)))
for iEl in range(0,self.nel):
el=self.p.element(iEl)
@ -173,8 +162,6 @@ class MARC_POST():
def writeNodeScalars2VTK(self,fobj):
fobj.write('\nPOINT_DATA %i\n'%self.p.nodes())
nNdDat=self.nscals
nComponents=1+nNdDat
self.pointDataScalars=[]
for idxNdScal in range(-3,self.nscals): #now include node x,y,z
if idxNdScal>=0:
@ -209,8 +196,6 @@ class MARC_POST():
idx_sig_vMises=self.getLabelNr('Equivalent Von Mises Stress')
idx_sig33=self.getLabelNr('Comp 33 of Cauchy Stress')
fobj.write('\nCELL_DATA %i\n'%self.p.elements())
nElDat=self.elscals
nComponents=1+nElDat
for idxElScal in range(0,self.elscals):
datalabel=self.elscal_list[idxElScal]
datalabel=re.sub("\s",'_',datalabel)
@ -250,19 +235,16 @@ class MARC_POST():
result.append(avgScal)
return result
def writeUniaxiality2VTK(self,fobj):
#fobj.write('\nCELL_DATA %i\n'%self.p.elements())
def writeUniaxiality2VTK(self,fobj):
datalabel='uniaxiality_sig_vMises_durch_sig33'
fobj.write('SCALARS %s float %i\n'%(datalabel,1))
fobj.write('LOOKUP_TABLE default\n')
cnt=0
for iEl in range(0,self.nel):
cnt=cnt+1
#if abs(self.sig33[iEl])<1e-5:
if abs(self.sig_vMises[iEl])<1e-5:
datum=0.
else:
#datum=self.sig_vMises[iEl]/self.sig33[iEl]
datum=self.sig33[iEl]/self.sig_vMises[iEl]
fobj.write('%E '%(datum))
if cnt>self.VTKcnt:
@ -283,8 +265,8 @@ class MARC_POST():
self.mean_stress.append(self.meanStress(sig))
def triaxiality_per_element(self):
# classical triaxiality
# 1/3 : uniax tension
# classical triaxiality
# 1/3 : uniax tension
self.triaxiality=[]
for iEl in range(0,self.nel):
t=self.mean_stress[iEl]/self.sig_vMises[iEl]
@ -303,10 +285,6 @@ class MARC_POST():
fobj.write('\n')
def calc_lode_parameter(self):
# [-1 ... +1] see e.g. Wippler & Boehlke triaxiality measures doi:10.1002/pamm.201010061
# +1 : uniax tensile?
# 0 : shear
# -1 : uniax compr ?
self.lode=[]
try:
self.stress
@ -328,10 +306,11 @@ class MARC_POST():
def princStress(self, stress):
"""
Function to compute 3D principal stresses and sort them.
from: http://geodynamics.org/svn/cig/short/3D/PyLith/trunk/playpen/postproc/vtkcff.py
"""
stressMat=N.array(stress)
(princStress, princAxes) = numpy.linalg.eigh(stressMat)
stressMat=np.array(stress)
(princStress, princAxes) = np.linalg.eigh(stressMat)
idx = princStress.argsort()
princStressOrdered = princStress[idx]
princAxesOrdered = princAxes[:,idx]
@ -339,36 +318,28 @@ class MARC_POST():
def avg_elten(self,
idxElTen, mat=0, elID=None):
tensum=N.zeros((3,3));
T=N.zeros((3,3));
tensum=np.zeros((3,3));
T=np.zeros((3,3));
pts=0;
avg=N.zeros((3,3));
#print 'Element Scalars'
#print self.p.element_scalar_label(elscal2)
if elID==None:
avg=np.zeros((3,3));
if elID is None:
averaged_elements=range(0,self.nel)
else:
averaged_elements=[elID]
#for i in range (0,self.nel):
for i in averaged_elements:
if mat==0 or int(self.p.element_scalar(i,4)[0].value)==mat:
eldata=self.p.element(i)
T=self.p.element_tensor(i,idxElTen)
for k in range (0,8):
tensum[0][0] = tensum[0][0] + T[k].t11
tensum[0][1] = tensum[0][1] + T[k].t12
tensum[0][2] = tensum[0][2] + T[k].t13
#tensum1[1][0] = tensum1[1][0] + T1[k].t21
tensum[1][1] = tensum[1][1] + T[k].t22
tensum[1][2] = tensum[1][2] + T[k].t23
#tensum1[2][0] = tensum1[2][0] + T1[k].t31
#tensum1[2][1] = tensum1[2][1] + T1[k].t32
tensum[2][2] = tensum[2][2] + T[k].t33
pts=pts+1
avg=tensum/pts
#print avg
avg=self.fillComponents(avg)
#print avg
del [T]
return (avg,tensum,pts)
@ -384,7 +355,7 @@ class MARC_POST():
t=tensor33
s=(t[0,0]-t[1,1])**2+(t[1,1]-t[2,2])**2+(t[0,0]-t[2,2])**2+\
6*(t[0,1]**2+t[1,2]**2+t[2,0]**2)
vM=N.sqrt(s/2.)
vM=np.sqrt(s/2.)
return vM
def meanStress(self,tensor33):
@ -397,8 +368,7 @@ class MARC_POST():
t=tensor33
I1=t[0,0]+t[1,1]+t[2,2]
I2=t[0,0]*t[1,1]+t[1,1]*t[2,2]+t[0,0]*t[2,2]-\
t[0,1]**2-t[1,2]**2-t[0,2]**2
# I3 = det(t)
t[0,1]**2-t[1,2]**2-t[0,2]**2
I3=t[0,0]*t[1,1]*t[2,2]+\
2*t[0,1]*t[1,2]*t[2,0]-\
t[2,2]*t[0,1]**2-t[0,0]*t[1,2]**2-t[1,1]*t[0,2]**2
@ -406,17 +376,18 @@ class MARC_POST():
class VTK_WRITER():
'''
The resulting vtk-file can be imported in Paraview 3.12
Then use Filters: Cell Data to Point Data + Contour
to plot semi-transparent iso-surfaces.
'''
"""
The resulting vtk-file can be imported in Paraview 3.12
Then use Filters: Cell Data to Point Data + Contour
to plot semi-transparent iso-surfaces.
"""
import re
def __init__(self):
self.p=MARC_POST() # self.p
def openFile(self, filename='test.vtp'):
#if not self.f:#==None:
self.f=open(filename,'w+')
self.fname=filename
@ -427,7 +398,7 @@ class VTK_WRITER():
dformat='ASCII', # BINARY | [ASCII]
dtype='UNSTRUCTURED_GRID' # UNSTRUCTURED GRID
):
if vtkFile==None:
if vtkFile is None:
vtkFile=self.f
# First Line contains Data format version
self.versionVTK=version
@ -440,7 +411,6 @@ class VTK_WRITER():
def marc2vtkBatch(self):
for iori in range(1,63):
#self.p=msc_post.MSC_POST()
self.p.postname='indent_fric0.3_R2.70_cA146.0_h0.320_ori%03i_OST_h19d.t16'%(iori)
if os.path.exists(self.p.postname):
self.marc2vtk(mode='fast', batchMode=1)
@ -496,14 +466,14 @@ class VTK_WRITER():
def scaleBar(self, length=1.0, posXYZ=[0., 0., 0.]):
self.fsb=open('micronbar_l%.1f.vtp'%length,'w+')
self.writeFirstLines(self.fsb, comment='micronbar')
pts=N.array([])
pts=np.array([])
width=length*1.
height=length*1.
wVec=N.array([0., width, 0.])
lVec=N.array([length,0.,0.])
hVec=N.array([0.,0.,height])
wVec=np.array([0., width, 0.])
lVec=np.array([length,0.,0.])
hVec=np.array([0.,0.,height])
posXYZ=posXYZ-0.5*wVec-0.5*lVec#-0.5*hVec # CENTERING Y/N
posXYZ=N.array(posXYZ)
posXYZ=np.array(posXYZ)
pts=[posXYZ, posXYZ+lVec,
posXYZ+wVec,
posXYZ+wVec+lVec]
@ -514,34 +484,22 @@ class VTK_WRITER():
self.fsb.write('%f %f %f\n'%(pts[npts][0], pts[npts][1], pts[npts][2]))
if 1: #Triad
nCells=3
#nCells=1 #One Line
ptsPerCell=2 # Lines (Type=3)
#ptsPerCell=4 # Quads (Type=9)
#ptsPerCell=8 # Hexahedron (Type=12)
cellSize=(ptsPerCell+1)*nCells
self.fsb.write('CELLS %i %i\n'%(nCells,cellSize))
self.fsb.write('2 0 1\n') #X-Line
self.fsb.write('2 0 2\n') #Y-Line
self.fsb.write('2 0 4\n') #Z-Line
#self.fsb.write('4 0 1 3 2\n') #Quad
#self.fsb.write('%i 0 1 3 2 4 5 7 6\n'%ptsPerCell) #Hexahedron
self.fsb.write('CELL_TYPES %i\n'%(nCells))
self.fsb.write('3\n3\n3\n')#Line
#self.fsb.write('12\n')#Hexahedron
else: # Cube, change posXYZ
nCells=1
ptsPerCell=2 # Lines (Type=3)
#ptsPerCell=4 # Quads (Type=9)
#ptsPerCell=8 # Hexahedron (Type=12)
cellSize=(ptsPerCell+1)*nCells
self.fsb.write('CELLS %i %i\n'%(nCells,cellSize))
self.fsb.write('2 0 1\n') #Line
#self.fsb.write('4 0 1 3 2\n') #Quad
#self.fsb.write('%i 0 1 3 2 4 5 7 6\n'%ptsPerCell) #Hexahedron
self.fsb.write('CELL_TYPES %i\n'%(nCells))
self.fsb.write('3\n')#Line
#self.fsb.write('12\n')#Hexahedron
self.fsb.write('\n')
self.fsb.close()
@ -549,8 +507,7 @@ class VTK_WRITER():
def example_unstructured(self):
self.openFile(filename='example_unstructured_grid.vtk')
#self.writeFirstLines()
self.f.write('''
self.f.write("""
# vtk DataFile Version 2.0
example_unstruct_grid
ASCII
@ -590,61 +547,40 @@ LOOKUP_TABLE default
1.02
1.50
0.00
3 5 6 23423423423423423423.23423423''')
3 5 6 23423423423423423423.23423423""")
self.f.close()
def writeNodes2VTK(self, fobj):
self.VTKcnt=200 # how many numbers per line in vtk file
#self.VTKcnt=6
ndCnt=1
#self.nodes=range(0,10)
fobj.write('POINTS %i'%self.p.nodes()+' float\n')
for iNd in self.nodes:
nd=self.p.node(iNd)
disp=self.p.node_displacement(iNd)
#contact=self.p.node_scalar(iNd,contactNr)
#ndCnt=ndCnt+1
fobj.write('%f %f %f \n'%
#(nd.x, nd.y, nd.z))
(nd.x+disp[0], nd.y+disp[1], nd.z+disp[2]))
#if ndCnt>6:
# fobj.write('\n')
# ndCnt=1
fobj.write('\n')
print('Nodes written to VTK: %i'%self.p.nodes())
#print('Nr of nodes: ',self.nodes)
def writeElements2VTK(self, fobj):
fobj.write('\nCELLS %i %i'%(self.p.elements(),self.p.elements()*9)+'\n')
for iEl in range(0,self.nel):
el=self.p.element(iEl)
#disp=self.p.node_displacement(iNd)
#contact=self.p.node_scalar(iNd,contactNr)
#ndCnt=ndCnt+1
fobj.write('8 ')
ndlist=el.items
#for k in [0, 1, 3, 2, 4, 5, 7, 6]: # FOR CELL TPYE VTK_VOXEL
#for k in [0, 4, 3, 1, 5, 7, 6, 2]:
for k in [0, 1, 2, 3, 4, 5, 6, 7]: # FOR CELL TYPE VTK_HEXAHEDRON
fobj.write('%6i '%(ndlist[k]-1))
fobj.write('\n')
#if ndCnt>6:
# fobj.write('\n')
# ndCnt=1
fobj.write('\nCELL_TYPES %i'%self.p.elements()+'\n')
cnt=0
for iEl in range(0,self.nel):
cnt=cnt+1
#fobj.write('11\n') #VTK_VOXEL
fobj.write('12 ') #VTK_HEXAHEDRON
if cnt>self.VTKcnt:
fobj.write('\n');cnt=0
fobj.write('\n')
print('Elements written to VTK: %i'%self.p.elements())
#print('Nr of nodes: ',self.nodes)
def writeElScalars2NodesVTK(self,fobj):
fobj.write('\nPOINT_DATA %i\n'%self.p.nodes())
@ -668,10 +604,7 @@ LOOKUP_TABLE default
fobj.write('\n')
def writeNodeScalars2VTK(self,fobj):
#print('writeElementData2VTK')
fobj.write('\nPOINT_DATA %i\n'%self.p.nodes())
nNdDat=self.nscals
nComponents=1+nNdDat
for idxNdScal in range(-3,self.nscals): # include node x,y,z
if idxNdScal>=0:
datalabel=self.nscal_list[idxNdScal]
@ -700,10 +633,7 @@ LOOKUP_TABLE default
fobj.write('\n')
def writeElementData2VTK(self,fobj):
#print('writeElementData2VTK')
fobj.write('\nCELL_DATA %i\n'%self.p.elements())
nElDat=self.elscals
nComponents=1+nElDat
for idxElScal in range(0,self.elscals):
datalabel=self.elscal_list[idxElScal]
datalabel=re.sub("\s",'_',datalabel)
@ -730,7 +660,7 @@ LOOKUP_TABLE default
def example1(self):
self.openFile()
self.writeFirstLines()
self.f.write('''DATASET POLYDATA
self.f.write("""DATASET POLYDATA
POINTS 8 float
0.0 0.0 0.0
1.0 0.0 0.0
@ -789,18 +719,20 @@ LOOKUP_TABLE my_table 8
0.0 0.0 1.0 1.0
1.0 0.0 1.0 1.0
0.0 1.0 1.0 1.0
1.0 1.0 1.0 1.0''')
1.0 1.0 1.0 1.0""")
self.f.close()
import pyvtk
class marc_to_vtk():
'''
Anybody wants to implement it with pyvtk?
The advantage would be that pyvtk can also wirte the
<xml>-VTK format and binary.
These can be plotted with mayavi.
'''
"""
Anybody wants to implement it with pyvtk?
The advantage would be that pyvtk can also wirte the
<xml>-VTK format and binary.
These can be plotted with mayavi.
"""
def __init__(self):
self.p=[]#MARC_POST() # self.p
@ -810,5 +742,4 @@ class marc_to_vtk():
hexahedron=self.p.cells),
'm2v output')
vtk.tofile('m2v_file')
#vtk.tofile('example3b','binary')
#VtkData('example3')

View File

@ -2,4 +2,4 @@
"""Test functionality"""
from .test import Test "noqa
from .test import Test #noqa