You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I use FEniCS installed in WSL of Windows 10.
The version is 2019.01.
Then I update demo files in the tutorial.
I delete the plot code because WSL cannot use it.
"""Class for a scalar (or vector) field over a BoxGrid or UniformBoxGrid grid."""fromnumpyimportzeros, array, transpose, ndarray, linspace, meshgridimportdolfin__all__= ['BoxField', 'BoxGrid', 'UniformBoxGrid', 'X', 'Y', 'Z',
'FEniCSBoxField', 'update_from_fenics_array']
# constants for indexing the space directions:X=X1=0Y=X2=1Z=X3=2classUniformBoxGrid(object):
""" Simple uniform grid on an interval, rectangle, box, or hypercube. ============= ==================================================== Attributes Description ============= ==================================================== nsd no of spatial dimensions in the grid min_coor array of minimum coordinates max_coor array of maximum coordinates division array of cell divisions in the delta array of grid spacings dirnames names of the space directions ('x', 'y', etc.) shape (nx+1, ny+1, ...); dimension of array over grid coor list of coordinates; self.coor[Y][j] is the the j-th coordinate in direction Y (=1) X, Y, Z are predefined constants 0, 1, 2 coorv expanded version of coor for vectorized expressions (in 2D, self.coorv[0] = self.coor[0][:,newaxis]) tolerance small geometric tolerance based on grid coordinates npoints total number of grid points ============= ==================================================== """def__init__(self,
min=(0,0), # minimum coordinatesmax=(1,1), # maximum coordinatesdivision=(4,4), # cell divisionsdirnames=('x', 'y', 'z')): # names of the directions""" Initialize a BoxGrid by giving domain range (minimum and maximum coordinates: min and max tuples/lists/arrays) and number of cells in each space direction (division tuple/list/array). The dirnames tuple/list holds the names of the coordinates in the various spatial directions. >>> g = UniformBoxGrid(min=0, max=1, division=10) >>> g = UniformBoxGrid(min=(0,-1), max=(1,1), division=(10,4)) >>> g = UniformBoxGrid(min=(0,0,-1), max=(2,1,1), division=(2,3,5)) """# Allow int/float specifications in one-dimensional grids# (just turn to lists for later multi-dimensional processing)ifisinstance(min, (int,float)):
min= [min]
ifisinstance(max, (int,float)):
max= [max]
ifisinstance(division, (int,float)):
division= [division]
ifisinstance(dirnames, str):
dirnames= [dirnames]
self.nsd=len(min)
# strip dirnames down to right space dim (in case the default# with three components were unchanged by the user):dirnames=dirnames[:self.nsd]
# check consistent lengths:forainmax, division:
iflen(a) !=self.nsd:
raiseValueError(
'Incompatible lengths of arguments to constructor'\
' (%d != %d)'% (len(a), self.nsd))
self.min_coor=array(min, float)
self.max_coor=array(max, float)
self.dirnames=dirnamesself.division=divisionself.coor= [None]*self.nsdself.shape= [0]*self.nsdself.delta=zeros(self.nsd)
foriinrange(self.nsd):
self.delta[i] = \
(self.max_coor[i] -self.min_coor[i])/float(self.division[i])
self.shape[i] =self.division[i] +1# no of grid pointsself.coor[i] = \
linspace(self.min_coor[i], self.max_coor[i], self.shape[i])
self._more_init()
def_more_init(self):
self.shape=tuple(self.shape)
self.coorv=meshgrid(*self.coor, indexing='ij')
ifnotisinstance(self.coorv, (list,tuple)):
# 1D grid, wrap self.coorv as list:self.coorv= [self.coorv]
self.npoints=1foriinrange(len(self.shape)):
self.npoints*=self.shape[i]
self.tolerance= (max(self.max_coor) -min(self.min_coor))*1E-14# nicknames: xcoor, ycoor, xcoorv, ycoorv, etcforiinrange(self.nsd):
self.__dict__[self.dirnames[i]+'coor'] =self.coor[i]
self.__dict__[self.dirnames[i]+'coorv'] =self.coorv[i]
ifself.nsd==3:
# make boundary coordinates for vectorization:xdummy, \
self.ycoorv_xfixed_boundary, \
self.zcoorv_xfixed_boundary=meshgrid(0, self.ycoor, self.zcoor,
indexing='ij')
self.xcoorv_yfixed_boundary, \
ydummy, \
self.zcoorv_yfixed_boundary=meshgrid(self.xcoor, 0, self.zcoor,
indexing='ij')
self.xcoorv_yfixed_boundary, \
self.zcoorv_yfixed_boundary, \
zdummy=meshgrid(self.xcoor, self.ycoor, 0, indexing='ij')
# could have _ in all variable names and define read-only# access via propertiesdefstring2griddata(s):
""" Turn a text specification of a grid into a dictionary with the grid data. For example, >>> s = "domain=[0,10] indices=[0:11]" >>> data = BoxGrid.string2griddata(s) >>> data {'dirnames': ('x', 'y'), 'division': [10], 'max': [10], 'min': [0]} >>> s = "domain=[0.2,0.5]x[0,2E+00] indices=[0:20]x[0:100]" >>> data = BoxGrid.string2griddata(s) >>> data {'dirnames': ('x', 'y', 'z'), 'division': [19, 99], 'max': [0.5, 2], 'min': [0.2, 0]} >>> s = "[0,1]x[0,2]x[-1,1.5] [0:25]x[0:10]x[0:16]" >>> data = BoxGrid.string2griddata(s) >>> data {'dirnames': ('x', 'y', 'z'), 'division': [24, 9, 15], 'max': [1.0, 2.0, 1.5], 'min': [0.0, 0.0, -1.0]} The data dictionary can be used as keyword arguments to the class UniformBoxGrid constructor. """domain=r'\[([^,]*),([^\]]*)\]'indices=r'\[([^:,]*):([^\]]*)\]'importred=re.findall(domain, s)
i=re.findall(indices, s)
nsd=len(d)
ifnsd!=len(i):
raiseValueError('could not parse "%s"'%s)
kwargs= {}
dirnames= ('x', 'y', 'z')
fordirinrange(nsd):
ifnotisinstance(d[dir], (list,tuple)) orlen(d[dir]) !=2or \
notisinstance(i[dir], (list,tuple)) orlen(i[dir]) !=2:
raiseValueError('syntax error in "%s"'%s)
# old syntax (nx, xmin, xmax, ny, ymin, etc.):#kwargs[dirnames[dir]] = (float(d[dir][0]), float(d[dir][1]))#kwargs['n'+dirnames[dir]] = int(i[dir][1]) - int(i[dir][0]) # no of cells!kwargs['min'] = [float(d[dir][0]) fordirinrange(nsd)]
kwargs['max'] = [float(d[dir][1]) fordirinrange(nsd)]
kwargs['division'] = [int(i[dir][1]) -int(i[dir][0]) \
fordirinrange(nsd)]
kwargs['dirnames'] =dirnames[:nsd]
returnkwargsstring2griddata=staticmethod(string2griddata)
def__getitem__(self, i):
""" Return access to coordinate array in direction no i, or direction name i, or return the coordinate of a point if i is an nsd-tuple. >>> g = UniformBoxGrid(x=(0,1), y=(-1,1), nx=2, ny=4) # xy grid >>> g[0][0] == g.min[0] # min coor in direction 0 True >>> g['x'][0] == g.min[0] # min coor in direction 'x' True >>> g[0,4] (0.0, 1.0) >>> g = UniformBoxGrid(min=(0,-1), max=(1,1), division=(2,4), dirnames=('y', 'z')) >>> g[1][0] == g.min[1] True >>> g['z'][0] == g.min[1] # min coor in direction 'z' True """ifisinstance(i, str):
returnself.coor[self.name2dirindex(i)]
elifisinstance(i, int):
ifself.nsd>1:
returnself.coor[i] # coordinate arrayelse:
returnself.coor[0][i] # coordinate itself in 1Delifisinstance(i, (list,tuple)):
returntuple([self.coor[k][i[k]] forkinrange(len(i))])
else:
raiseTypeError('i must be str, int, tuple')
def__setitem__(self, i, value):
raiseAttributeError('subscript assignment is not valid for '\
'%s instances'%self.__class__.__name__)
defncells(self, i):
"""Return no of cells in direction i."""# i has the meaning as in __getitem__. May be removed if not much usedreturnlen(self.coor[i])-1defname2dirindex(self, name):
""" Return direction index corresponding to direction name. In an xyz-grid, 'x' is 0, 'y' is 1, and 'z' is 2. In an yz-grid, 'x' is not defined, 'y' is 0, and 'z' is 1. """try:
returnself.dirnames.index(name)
exceptValueError:
# print name, 'is not defined'print(name, 'is not defined')
returnNonedefdirindex2name(self, i):
"""Inverse of name2dirindex."""try:
returnself.dirnames[i]
exceptIndexError:
# print i, 'is not a valid index'print(i, 'is not a valid index')
returnNonedefok(self):
returnTrue# constructor init only => always okdef__len__(self):
"""Total number of grid points."""n=1fordirinself.coor:
n*=len(dir)
returnndef__repr__(self):
s=self.__class__.__name__+ \
'(min=%s, max=%s, division=%s, dirnames=%s)'% \
(self.min_coor.tolist(),
self.max_coor.tolist(),
self.division, self.dirnames)
returnsdef__str__(self):
"""Pretty print, using the syntax of init_fromstring."""domain='x'.join(['[%g,%g]'% (min_, max_) \
formin_, max_inzip(self.min_coor, self.max_coor)])
indices='x'.join(['[0:%d]'%divfordivinself.division])
return'domain=%s indices=%s'% (domain, indices)
definterpolator(self, point_values):
""" Given a self.nsd dimension array point_values with values at each grid point, this method returns a function for interpolating the scalar field defined by point_values at an arbitrary point. 2D Example: given a filled array point_values[i,j], compute interpolator = grid.interpolator(point_values) v = interpolator(0.1243, 9.231) # interpolate point_values >>> g=UniformBoxGrid(x=(0,2), nx=2, y=(-1,1), ny=2) >>> g UniformBoxGrid(x=(0,2), nx=2, y=(-1,1), ny=2) >>> def f(x,y): return 2+2*x-y >>> f=g.vectorized_eval(f) >>> f array([[ 3., 2., 1.], [ 5., 4., 3.], [ 7., 6., 5.]]) >>> i=g.interpolator(f) >>> i(0.1,0.234) # interpolate (not a grid point) 1.9660000000000002 >>> f(0.1,0.234) # exact answer 1.9660000000000002 """args=self.coorargs.append(point_values)
# make use of wrap2callable, which applies ScientificPythonreturnwrap2callable(args)
defvectorized_eval(self, f):
""" Evaluate a function f (of the space directions) over a grid. f is supposed to be vectorized. >>> g = BoxGrid(x=(0,1), y=(0,1), nx=3, ny=3) >>> # f(x,y) = sin(x)*exp(x-y): >>> a = g.vectorized_eval(lambda x,y: sin(x)*exp(y-x)) >>> print a [[ 0. 0. 0. 0. ] [ 0.23444524 0.3271947 0.45663698 0.63728825] [ 0.31748164 0.44308133 0.6183698 0.86300458] [ 0.30955988 0.43202561 0.60294031 0.84147098]] >>> # f(x,y) = 2: (requires special consideration) >>> a = g.vectorized_eval(lambda x,y: zeros(g.shape)+2) >>> print a [[ 2. 2. 2. 2.] [ 2. 2. 2. 2.] [ 2. 2. 2. 2.] [ 2. 2. 2. 2.]] """a=f(*self.coorv)
# check if f is really vectorized:try:
msg='calling %s, which is supposed to be vectorized'%f.__name__exceptAttributeError: # if __name__ is missingmsg='calling a function, which is supposed to be vectorized'try:
self.compatible(a)
except (IndexError,TypeError) ase:
# print 'e=',e, type(e), e.__class__.__name__print('e=',e, type(e), e.__class__.__name__)
raisee.__class__('BoxGrid.vectorized_eval(f):\n%s, BUT:\n%s'% \
(msg, e))
returnadefinit_fromstring(s):
data=UniformBoxGrid.string2griddata(s)
returnUniformBoxGrid(**data)
init_fromstring=staticmethod(init_fromstring)
defcompatible(self, data_array, name_of_data_array=''):
""" Check that data_array is a NumPy array with dimensions compatible with the grid. """ifnotisinstance(data_array, ndarray):
raiseTypeError('data %s is %s, not NumPy array'% \
(name_of_data_array, type(data_array)))
else:
ifdata_array.shape!=self.shape:
raiseIndexError("data %s of shape %s is not "\
"compatible with the grid's shape %s"% \
(name_of_data_array, data_array.shape,
self.shape))
returnTrue# if we haven't raised any exceptionsdefiter(self, domain_part='all', vectorized_version=True):
""" Return iterator over grid points. domain_part = 'all': all grid points domain_part = 'interior': interior grid points domain_part = 'all_boundary': all boundary points domain_part = 'interior_boundary': interior boundary points domain_part = 'corners': all corner points domain_part = 'all_edges': all points along edges in 3D grids domain_part = 'interior_edges': interior points along edges vectorized_version is true if the iterator returns slice objects for the index slice in each direction. vectorized_version is false if the iterator visits each point at a time (scalar version). """self.iterator_domain=domain_partself.vectorized_iter=vectorized_versionreturnselfdef__iter__(self):
# Idea: set up slices for the various self.iterator_domain# values. In scalar mode, make a loop over the slices and# yield the scalar value. In vectorized mode, return the# appropriate slices.self._slices= [] # elements meant to be slice objectsifself.iterator_domain=='all':
self._slices.append([])
foriinrange(self.nsd):
self._slices[-1].append((i, slice(0, len(self.coor[i]), 1)))
elifself.iterator_domain=='interior':
self._slices.append([])
foriinrange(self.nsd):
self._slices[-1].append((i, slice(1, len(self.coor[i])-1, 1)))
elifself.iterator_domain=='all_boundary':
foriinrange(self.nsd):
self._slices.append([])
# boundary i fixed at 0:forjinrange(self.nsd):
ifj!=i:
self._slices[-1].\
append((j, slice(0, len(self.coor[j]), 1)))
else:
self._slices[-1].append((i, slice(0, 1, 1)))
# boundary i fixed at its max value:forjinrange(self.nsd):
ifj!=i:
self._slices[-1].\
append((j, slice(0, len(self.coor[j]), 1)))
else:
n=len(self.coor[i])
self._slices[-1].append((i, slice(n-1, n, 1)))
elifself.iterator_domain=='interior_boundary':
foriinrange(self.nsd):
self._slices.append([])
# boundary i fixed at 0:forjinrange(self.nsd):
ifj!=i:
self._slices[-1].\
append((j, slice(1, len(self.coor[j])-1, 1)))
else:
self._slices[-1].append((i, slice(0, 1, 1)))
# boundary i fixed at its max value:forjinrange(self.nsd):
ifj!=i:
self._slices[-1].\
append((j, slice(1, len(self.coor[j])-1, 1)))
else:
n=len(self.coor[i])
self._slices[-1].append((i, slice(n-1, n, 1)))
elifself.iterator_domain=='corners':
ifself.nsd==1:
fori0in (0, len(self.coor[0])-1):
self._slices.append([])
self._slices[-1].append((0, slice(i0, i0+1, 1)))
elifself.nsd==2:
fori0in (0, len(self.coor[0])-1):
fori1in (0, len(self.coor[1])-1):
self._slices.append([])
self._slices[-1].append((0, slice(i0, i0+1, 1)))
self._slices[-1].append((0, slice(i1, i1+1, 1)))
elifself.nsd==3:
fori0in (0, len(self.coor[0])-1):
fori1in (0, len(self.coor[1])-1):
fori2in (0, len(self.coor[2])-1):
self._slices.append([])
self._slices[-1].append((0, slice(i0, i0+1, 1)))
self._slices[-1].append((0, slice(i1, i1+1, 1)))
self._slices[-1].append((0, slice(i2, i2+1, 1)))
elifself.iterator_domain=='all_edges':
# print 'iterator over "all_edges" is not implemented'print('iterator over "all_edges" is not implemented')
elifself.iterator_domain=='interior_edges':
# print 'iterator over "interior_edges" is not implemented'print('iterator over "interior_edges" is not implemented')
else:
raiseValueError('iterator over "%s" is not impl.'% \
self.iterator_domain)
# "def __next__(self):"""" If vectorized mode: Return list of slice instances, where the i-th element in the list represents the slice for the index in the i-th space direction (0,...,nsd-1). If scalar mode: Return list of indices (in multi-D) or the index (in 1D). """ifself.vectorized_iter:
forsinself._slices:
yield [slice_in_dirfordir, slice_in_dirins]
else:
# scalar versionforsinself._slices:
slices= [slice_in_dirfordir, slice_in_dirins]
iflen(slices) ==1:
foriinxrange(slices[0].start, slices[0].stop):
yieldieliflen(slices) ==2:
foriinxrange(slices[0].start, slices[0].stop):
forjinxrange(slices[1].start, slices[1].stop):
yield [i, j]
eliflen(slices) ==3:
foriinxrange(slices[0].start, slices[0].stop):
forjinxrange(slices[1].start, slices[1].stop):
forkinxrange(slices[2].start, slices[2].stop):
yield [i, j, k]
deflocate_cell(self, point):
""" Given a point (x, (x,y), (x,y,z)), locate the cell in which the point is located, and return 1) the (i,j,k) vertex index of the "lower-left" grid point in this cell, 2) the distances (dx, (dx,dy), or (dx,dy,dz)) from this point to the given point, 3) a boolean list if point matches the coordinates of any grid lines. If a point matches the last grid point in a direction, the cell index is set to the max index such that the (i,j,k) index can be used directly for look up in an array of values. The corresponding element in the distance array is then set 0. 4) the indices of the nearest grid point. The method only works for uniform grid spacing. Used for interpolation. >>> g1 = UniformBoxGrid(min=0, max=1, division=4) >>> cell_index, distance, match, nearest = g1.locate_cell(0.7) >>> print cell_index [2] >>> print distance [ 0.2] >>> print match [False] >>> print nearest [3] >>> >>> g1.locate_cell(0.5) ([2], array([ 0.]), [True], [2]) >>> >>> g2 = UniformBoxGrid.init_fromstring('[-1,1]x[-1,2] [0:3]x[0:4]') >>> print g2.coor [array([-1. , -0.33333333, 0.33333333, 1. ]), array([-1. , -0.25, 0.5 , 1.25, 2. ])] >>> g2.locate_cell((0.2,0.2)) ([1, 1], array([ 0.53333333, 0.45 ]), [False, False], [2, 2]) >>> g2.locate_cell((1,2)) ([3, 4], array([ 0., 0.]), [True, True], [3, 4]) >>> >>> >>> """ifisinstance(point, (int,float)):
point= [point]
nsd=len(point)
ifnsd!=self.nsd:
raiseValueError('point=%s has wrong dimension (this is a %dD grid!)'% \
(point, self.nsd))
#index = zeros(nsd, int)index= [0]*nsddistance=zeros(nsd)
grid_point= [False]*nsdnearest_point= [0]*nsdfori, coorinenumerate(point):
# is point inside the domain?ifcoor<self.min_coor[i] orcoor>self.max_coor[i]:
raiseValueError(
'locate_cell: point=%s is outside the domain [%s,%s]'% \
point, self.min_coor[i], self.max_coor[i])
index[i] =int((coor-self.min_coor[i])//self.delta[i]) # (need integer division)distance[i] =coor- (self.min_coor[i] +index[i]*self.delta[i])
ifdistance[i] >self.delta[i]/2:
nearest_point[i] =index[i] +1else:
nearest_point[i] =index[i]
ifabs(distance[i]) <self.tolerance:
grid_point[i] =Truenearest_point[i] =index[i]
if (abs(distance[i] -self.delta[i])) <self.tolerance:
# last cell, update index such that it coincides with the pointgrid_point[i] =Trueindex[i] +=1nearest_point[i] =index[i]
distance[i] =0.0returnindex, distance, grid_point, nearest_pointdefinterpolate(v0, v1, x0, x1, x):
returnv0+ (v1-v0)/float(x1-x0)*(x-x0)
defgridline_slice(self, start_coor, direction=0, end_coor=None):
""" Compute start and end indices of a line through the grid, and return a tuple that can be used as slice for the grid points along the line. The line must be in x, y or z direction (direction=0,1 or 2). If end_coor=None, the line ends where the grid ends. start_coor holds the coordinates of the start of the line. If start_coor does not coincide with one of the grid points, the line is snapped onto the grid (i.e., the line coincides with a grid line). Return: tuple with indices and slice describing the grid point indices that make up the line, plus a boolean "snapped" which is True if the original line did not coincide with any grid line, meaning that the returned line was snapped onto to the grid. >>> g2 = UniformBoxGrid.init_fromstring('[-1,1]x[-1,2] [0:3]x[0:4]') >>> print g2.coor [array([-1. , -0.33333333, 0.33333333, 1. ]), array([-1. , -0.25, 0.5 , 1.25, 2. ])] >>> g2.gridline_slice((-1, 0.5), 0) ((slice(0, 4, 1), 2), False) >>> g2.gridline_slice((-0.9, 0.4), 0) ((slice(0, 4, 1), 2), True) >>> g2.gridline_slice((-0.2, -1), 1) ((1, slice(0, 5, 1)), True) """start_cell, start_distance, start_match, start_nearest= \
self.locate_cell(start_coor)
# If snapping the line onto to the grid is not desired, the# start_cell and start_match lists must be used for interpolation# (i.e., interpolation is needed in the directions i where# start_match[i] is False).start_snapped=start_nearest[:]
ifend_coorisNone:
end_snapped=start_snapped[:]
end_snapped[direction] =self.division[direction] # highest legal indexelse:
end_cell, end_distance, end_match, end_nearest= \
self.locate_cell(end_coor)
end_snapped=end_nearest[:]
# recall that upper index limit must be +1 in a slice:line_slice=start_snapped[:]
line_slice[direction] = \
slice(start_snapped[direction], end_snapped[direction]+1, 1)
# note that if all start_match are true, then the plane# was not snappedreturntuple(line_slice), notarray(start_match).all()
defgridplane_slice(self, value, constant_coor=0):
""" Compute a slice for a plane through the grid, defined by coor[constant_coor]=value. Return a tuple that can be used as slice, plus a boolean parameter "snapped" reflecting if the plane was snapped onto a grid plane (i.e., value did not correspond to an existing grid plane). """start_coor=self.min_coor.copy()
start_coor[constant_coor] =valuestart_cell, start_distance, start_match, start_nearest= \
self.locate_cell(start_coor)
start_snapped= [0]*self.nsdstart_snapped[constant_coor] =start_nearest[constant_coor]
# recall that upper index limit must be +1 in a slice:end_snapped= [self.division[i] foriinrange(self.nsd)]
end_snapped[constant_coor] =start_snapped[constant_coor]
plane_slice= [slice(start_snapped[i], end_snapped[i]+1, 1) \
foriinrange(self.nsd)]
plane_slice[constant_coor] =start_nearest[constant_coor]
returntuple(plane_slice), notstart_match[constant_coor]
classBoxGrid(UniformBoxGrid):
""" Extension of class UniformBoxGrid to non-uniform box grids. The coordinate vectors (in each space direction) can have arbitrarily spaced coordinate values. The coor argument must be a list of nsd (number of space dimension) components, each component contains the grid coordinates in that space direction (stored as an array). """def__init__(self, coor, dirnames=('x', 'y', 'z')):
UniformBoxGrid.__init__(self,
min=[a[0] foraincoor],
max=[a[-1] foraincoor],
division=[len(a)-1foraincoor],
dirnames=dirnames)
# override:self.coor=coordef__repr__(self):
s=self.__class__.__name__+'(coor=%s)'%self.coorreturnsdeflocate_cell(self, point):
raiseNotImplementedError('Cannot locate point in cells in non-uniform grids')
def_test(g, points=None):
result='g=%s'%str(g)
deffv(*args):
# vectorized evaluation functionreturnzeros(g.shape)+2deffs(*args):
# scalar versionreturn2fv_arr=g.vectorized_eval(fv)
fs_arr=zeros(g.shape)
coor= [0.0]*g.nsditparts= ['all', 'interior', 'all_boundary', 'interior_boundary',
'corners']
ifg.nsd==3:
itparts+= ['all_edges', 'interior_edges']
fordomain_partinitparts:
result+='\niterator over "%s"\n'%domain_partforiing.iter(domain_part, vectorized_version=False):
ifisinstance(i, int): i= [i] # wrap index as list (if 1D)forkinrange(g.nsd):
coor[k] =g.coor[k][i[k]]
result+='%s %s\n'% (i, coor)
ifdomain_part=='all': # fs_arr shape corresponds to all pointsfs_arr[i] =fs(*coor)
result+='vectorized iterator over "%s":\n'%domain_partforslicesing.iter(domain_part, vectorized_version=True):
ifdomain_part=='all':
fs_arr[slices] =fv(*g.coor)
# else: more complicatedforslice_inslices:
result+='slice: %s values: %s\n'% (slice_, fs_arr[slice_])
# boundary slices...returnresultclassField(object):
""" General base class for all grids. Holds a connection to a grid, a name of the field, and optionally a list of the independent variables and a string with a description of the field. """def__init__(self, grid, name,
independent_variables=None,
description=None,
**kwargs):
self.grid=gridself.name=nameself.independent_variables=independent_variablesifself.independent_variablesisNone:
# copy grid.dirnames as independent variables:self.independent_variables=self.grid.dirnames# metainformation:self.meta= {'description': description,}
self.meta.update(kwargs) # user can add more meta informationclassBoxField(Field):
""" Field over a BoxGrid or UniformBoxGrid grid. ============= ============================================= Attributes Description ============= ============================================= grid reference to the underlying grid instance values array holding field values at the grid points ============= ============================================= """def__init__(self, grid, name, vector=0, **kwargs):
""" Initialize scalar or vector field over a BoxGrid/UniformBoxGrid. ============= =============================================== Arguments Description ============= =============================================== *grid* grid instance *name* name of the field *vector* scalar field if 0, otherwise the no of vector components (spatial dimensions of vector field) *values* (*kwargs*) optional array with field values ============= =============================================== Here is an example:: >>> g = UniformBoxGrid(min=[0,0], max=[1.,1.], division=[3, 4]) >>> print g domain=[0,1]x[0,1] indices=[0:3]x[0:4] >>> u = BoxField(g, 'u') >>> u.values = u.grid.vectorized_eval(lambda x,y: x + y) >>> i = 1; j = 2 >>> print 'u(%g, %g)=%g' % (g.coor[X][i], g.coor[Y][j], u.values[i,j]) u(0.333333, 0.5)=0.833333 >>> # visualize: >>> from scitools.std import surf >>> surf(u.grid.coorv[X], u.grid.coorv[Y], u.values) ``u.grid.coorv`` is a list of coordinate arrays that are suitable for Matlab-style visualization of 2D scalar fields. Also note how one can access the coordinates and u value at a point (i,j) in the grid. """Field.__init__(self, grid, name, **kwargs)
ifvector>0:
# for a vector field we add a "dimension" in values for# the various vector components (first index):self.required_shape= [vector]
self.required_shape+=list(self.grid.shape)
else:
self.required_shape=self.grid.shapeif'values'inkwargs:
values=kwargs['values']
self.set_values(values)
else:
# create array of scalar field grid point values:self.values=zeros(self.required_shape)
# doesn't work: self.__getitem__ = self.values.__getitem__#self.__setitem__ = self.values.__setitem__defcopy_values(self, values):
"""Take a copy of the values array and reshape it if necessary."""self.set_values(values.copy())
defset_values(self, values):
"""Attach the values array to this BoxField object."""ifvalues.shape==self.required_shape:
self.values=values# field data are providedelse:
try:
values.shape=self.required_shapeself.values=valuesexceptValueError:
raiseValueError(
'values array is incompatible with grid size; '\
'shape is %s while required shape is %s'% \
(values.shape, self.required_shape))
defupdate(self):
"""Update the self.values array (if grid has been changed)."""ifself.grid.shape!=self.values.shape:
self.values=zeros(self.grid.shape)
# these are slower than u_ = u.values; u_[i] since an additional# function call is required compared to NumPy array indexing:def__getitem__(self, i): returnself.values[i]
def__setitem__(self, i, v): self.values[i] =vdef__str__(self):
iflen(self.values.shape) >self.grid.nsd:
s='Vector field with %d components'%self.values.shape[-1]
else:
s='Scalar field's+=', over '+str(self.grid)
returnsdefgridline(self, start_coor, direction=0, end_coor=None,
snap=True):
""" Return a coordinate array and corresponding field values along a line starting with start_coor, in the given direction, and ending in end_coor (default: grid boundary). Two more boolean values are also returned: fixed_coor (the value of the fixed coordinates, which may be different from those in start_coor if snap=True) and snapped (True if the line really had to be snapped onto the grid, i.e., fixed_coor differs from coordinates in start_coor. If snap is True, the line is snapped onto the grid, otherwise values along the line must be interpolated (not yet implemented). >>> g2 = UniformBoxGrid.init_fromstring('[-1,1]x[-1,2] [0:3]x[0:4]') >>> print g2 UniformBoxGrid(min=[-1. -1.], max=[ 1. 2.], division=[3, 4], dirnames=('x', 'y')) >>> print g2.coor [array([-1. , -0.33333333, 0.33333333, 1. ]), array([-1. , -0.25, 0.5 , 1.25, 2. ])] >>> u = BoxField(g2, 'u') >>> u.values = u.grid.vectorized_eval(lambda x,y: x + y) >>> xc, uc, fixed_coor, snapped = u.gridline((-1,0.5), 0) >>> print xc [-1. -0.33333333 0.33333333 1. ] >>> print uc [-0.5 0.16666667 0.83333333 1.5 ] >>> print fixed_coor, snapped [0.5] False >>> #plot(xc, uc, title='u(x, y=%g)' % fixed_coor) """ifnotsnap:
raiseNotImplementedError('Use snap=True, no interpolation impl.')
slice_index, snapped= \
self.grid.gridline_slice(start_coor, direction, end_coor)
fixed_coor= [self.grid[s][i] fors,iinenumerate(slice_index) \
ifnotisinstance(i, slice)]
iflen(fixed_coor) ==1:
fixed_coor=fixed_coor[0] # avoid returning list of length 1returnself.grid.coor[direction][slice_index[direction].start:\
slice_index[direction].stop], \
self.values[slice_index], fixed_coor, snappeddefgridplane(self, value, constant_coor=0, snap=True):
""" Return two one-dimensional coordinate arrays and corresponding field values over a plane where one coordinate, constant_coor, is fixed at a value. If snap is True, the plane is snapped onto a grid plane such that the points in the plane coincide with the grid points. Otherwise, the returned values must be interpolated (not yet impl.). """ifnotsnap:
raiseNotImplementedError('Use snap=True, no interpolation impl.')
slice_index, snapped=self.grid.gridplane_slice(value, constant_coor)
ifconstant_coor==0:
x=self.grid.coor[1]
y=self.grid.coor[2]
elifconstant_coor==1:
x=self.grid.coor[0]
y=self.grid.coor[2]
elifconstant_coor==2:
x=self.grid.coor[0]
y=self.grid.coor[1]
fixed_coor=self.grid.coor[constant_coor][slice_index[constant_coor]]
returnx, y, self.values[slice_index], fixed_coor, snappeddef_rank12rankd_mesh(a, shape):
""" Given rank 1 array a with values in a mesh with the no of points described by shape, transform the array to the right "mesh array" with the same shape. """shape=list(shape)
shape.reverse()
iflen(a.shape) ==1:
returna.reshape(shape).transpose()
else:
raiseValueError('array a cannot be multi-dimensional (not %s), ' \
'break it up into one-dimensional components' \
%a.shape)
deffenics_mesh2UniformBoxGrid(fenics_mesh, division=None):
""" Turn a regular, structured DOLFIN finite element mesh into a UniformBoxGrid object. (Application: plotting with scitools.) Standard DOLFIN numbering numbers the nodes along the x[0] axis, then x[1] axis, and so on. """ifhasattr(fenics_mesh, 'structured_data'):
coor=fenics_mesh.structured_datamin_coor= [c[0] forcincoor]
max_coor= [c[-1] forcincoor]
division= [len(c)-1forcincoor]
else:
ifdivisionisNone:
raiseValueError('division must be given when fenics_mesh does not have a strutured_data attribute')
else:
coor=fenics_mesh.coordinates() # numpy arraymin_coor=coor[0]
max_coor=coor[-1]
returnUniformBoxGrid(min=min_coor, max=max_coor,
division=division)
deffenics_mesh2BoxGrid(fenics_mesh, division=None):
""" Turn a structured DOLFIN finite element mesh into a BoxGrid object. Standard DOLFIN numbering numbers the nodes along the x[0] axis, then x[1] axis, and so on. """ifhasattr(fenics_mesh, 'structured_data'):
coor=fenics_mesh.structured_datareturnBoxGrid(coor)
else:
ifdivisionisNone:
raiseValueError('division must be given when fenics_mesh does not have a strutured_data attribute')
else:
c=fenics_mesh.coordinates() # numpy arrayshape= [n+1fornindivision] # shape for points in each dir.c2= [c[:,i] foriinrange(c.shape[1])] # split x,y,z componentsforiinrange(c.shape[1]):
c2[i] =_rank12rankd_mesh(c2[i], shape)
# extract coordinates in the different directionscoor= []
iflen(c2) ==1:
coor= [c2[0][:]]
eliflen(c2) ==2:
coor= [c2[0][:,0], c2[1][0,:]]
eliflen(c2) ==3:
coor= [c2[0][:,0,0], c2[1][0,:,0], c2[2][0,0,:]]
returnBoxGrid(coor)
defFEniCSBoxField(fenics_function, division=None, uniform_mesh=True):
""" Turn a DOLFIN P1 finite element field over a structured mesh into a BoxField object. Standard DOLFIN numbering numbers the nodes along the x[0] axis, then x[1] axis, and so on. If the DOLFIN function employs elements of degree > 1, the function is automatically interpolated to elements of degree 1. """# Get meshfenics_mesh=fenics_function.function_space().mesh()
# Interpolate if necessaryelement=fenics_function.ufl_element()
ifelement.degree() !=1:
ifelement.value_size() ==1:
fenics_function \
=interpolate(u, FunctionSpace(fenics_mesh, 'P', 1))
else:
fenics_function \
=interpolate(u, VectorFunctionSpace(fenics_mesh, 'P', 1,
element.value_size()))
importdolfinifdolfin.__version__[:3] =="1.0":
nodal_values=fenics_function.vector().get_local().copy()
else:
d2v=fenics.dof_to_vertex_map(fenics_function.function_space())
nodal_values=fenics_function.vector().get_local().copy()
nodal_values[d2v] =fenics_function.vector().get_local().copy()
ifuniform_mesh:
grid=fenics_mesh2UniformBoxGrid(fenics_mesh, division)
else:
grid=fenics_mesh2BoxGrid(fenics_mesh, division)
ifnodal_values.size>grid.npoints:
# vector field, treat each component separatelyncomponents=int(nodal_values.size/grid.npoints)
try:
nodal_values.shape= (ncomponents, grid.npoints)
exceptValueErrorase:
raiseValueError('Vector field (nodal_values) has length %d, there are %d grid points, and this does not match with %d components'% (nodal_values.size, grid.npoints, ncomponents))
vector_field= [_rank12rankd_mesh(nodal_values[i,:].copy(),
grid.shape) \
foriinrange(ncomponents)]
nodal_values=array(vector_field)
bf=BoxField(grid, name=fenics_function.name(),
vector=ncomponents, values=nodal_values)
else:
try:
nodal_values=_rank12rankd_mesh(nodal_values, grid.shape)
exceptValueErrorase:
raiseValueError('DOLFIN function has vector of size %s while the provided mesh has %d points and shape %s'% (nodal_values.size, grid.npoints, grid.shape))
bf=BoxField(grid, name=fenics_function.name(),
vector=0, values=nodal_values)
returnbfdefupdate_from_fenics_array(fenics_array, box_field):
""" Update the values in a BoxField object box_field with a new DOLFIN array (fenics_array). The array must be reshaped and transposed in the right way (therefore box_field.copy_values(fenics_array) will not work). """nodal_values=fenics_array.copy()
iflen(nodal_values.shape) >1:
raiseNotImplementedError# no support for vector valued functions yet# the problem is in _rank12rankd_meshtry:
nodal_values=_rank12rankd_mesh(nodal_values, box_field.grid.shape)
exceptValueErrorase:
raiseValueError(
'DOLFIN function has vector of size %s while ''the provided mesh demands %s'%
(nodal_values.size, grid.shape))
box_field.set_values(nodal_values)
returnbox_fielddef_str_equal(a, b):
"""Return '' if a==b, else string with indication of differences."""ifa==b:
return''else:
r= [] # resulting string with indication of differencesfori, charsinenumerate(zip(a, b)):
a_, b_=charsifa_==b_:
r.append(a_)
else:
r.append('[')
r.append(a_)
r.append('|')
r.append(b_)
r.append(']')
return''.join(r)
deftest_2Dmesh():
g1=UniformBoxGrid(min=0, max=1, division=4)
expected="""\g=domain=[0,1] indices=[0:4]iterator over "all"[0] [0.0][1] [0.25][2] [0.5][3] [0.75][4] [1.0]vectorized iterator over "all":slice: slice(0, 5, 1) values: [ 2. 2. 2. 2. 2.]iterator over "interior"[1] [0.25][2] [0.5][3] [0.75]vectorized iterator over "interior":slice: slice(1, 4, 1) values: [ 2. 2. 2.]iterator over "all_boundary"[0, 4] [0.0]vectorized iterator over "all_boundary":slice: slice(0, 1, 1) values: [ 2.]slice: slice(4, 5, 1) values: [ 2.]iterator over "interior_boundary"[0, 4] [0.0]vectorized iterator over "interior_boundary":slice: slice(0, 1, 1) values: [ 2.]slice: slice(4, 5, 1) values: [ 2.]iterator over "corners"[0] [0.0][4] [1.0]vectorized iterator over "corners":slice: slice(0, 1, 1) values: [ 2.]slice: slice(4, 5, 1) values: [ 2.]iterator over "all_edges" is not implementediterator over "all_edges" is not implementediterator over "interior_edges" is not implementediterator over "interior_edges" is not implemented"""computed=_test(g1, [0.7, 0.5])
msg=_str_equal(expected, computed)
# print 'msg: [%s]' % msgprint('msg: [%s]'%msg)
success=notmsgassertsuccess, msg# Demonstrate functionality with structured mesh classspec='[0,1]x[-1,2] with indices [0:3]x[0:2]'g2=UniformBoxGrid.init_fromstring(spec)
_test(g2, [(0.2,0.2), (1,2)])
g3=UniformBoxGrid(min=(0,0,-1), max=(1,1,1), division=(4,1,2))
_test(g3)
# print 'g3=\n%s' % str(g3)print('g3=\n%s'%str(g3))
# print 'g3[Z]=', g3[Z]print('g3[Z]=', g3[Z])
# print 'g3[Z][1] =', g3[Z][1]print('g3[Z][1] =', g3[Z][1])
# print 'dx, dy, dz spacings:', g3.deltaprint('dx, dy, dz spacings:', g3.delta)
g4=UniformBoxGrid(min=(0,-1), max=(1,1),
division=(4,2), dirnames=('y','z'))
_test(g4)
# print 'g4["y"][-1]:', g4["y"][-1]print('g4["y"][-1]:', g4["y"][-1])
def_test3():
fromnumpyimportsin, zeros, exp# check vectorization evaluation:g=UniformBoxGrid(min=(0,0), max=(1,1), division=(3,3))
try:
g.vectorized_eval(lambdax,y: 2)
exceptTypeErrorasmsg:
# fine, expect to arrive here# print '*** Expected error in this test:', msgprint('*** Expected error in this test:', msg)
try:
g.vectorized_eval(lambdax,y: zeros((2,2))+2)
exceptIndexErrorasmsg:
# fine, expect to arrive here# print '*** Expected error in this test:', msgprint('*** Expected error in this test:', msg)
a=g.vectorized_eval(lambdax,y: sin(x)*exp(y-x))
# print aprint(a)
a=g.vectorized_eval(lambdax,y: zeros(g.shape)+2)
# print aprint(a)
def_test_field(g):
# print 'grid: %s' % gprint('grid: %s'%g)
# function: 1 + x + y + zdeff(*args):
sum=1.0forxinargs:
sum=sum+xreturnsumu=BoxField(g, 'u')
v=BoxField(g, 'v', vector=g.nsd)
u.values=u.grid.vectorized_eval(f) # fill field valuesifg.nsd==1:
v[:,X] =u.values+1# 1st componentelifg.nsd==2:
v[:,:,X] =u.values+1# 1st componentv[:,:,Y] =u.values+2# 2nd componentelifg.nsd==3:
v[:,:,:,X] =u.values+1# 1st componentv[:,:,:,Y] =u.values+2# 2nd componentv[:,:,:,Z] =u.values+3# 3rd component# write out field values at the mid point of the grid# (convert g.shape to NumPy array and divide by 2 to find# approximately the mid point)midptindex=tuple(array(g.shape,int)/2)
ptcoor=g[midptindex]
# tuples with just one item does not work as indices# print 'mid point %s has indices %s' % (ptcoor, midptindex)print('mid point %s has indices %s'% (ptcoor, midptindex))
# print 'f%s=%g' % (ptcoor, f(*ptcoor))print('f%s=%g'% (ptcoor, f(*ptcoor)))
# print 'u at %s: %g' % (midptindex, u[midptindex])print('u at %s: %g'% (midptindex, u[midptindex]))
v_index=list(midptindex); v_index.append(slice(g.nsd))
# print 'v at %s: %s' % (midptindex, v[v_index])print('v at %s: %s'% (midptindex, v[v_index]))
# test extraction of lines:ifu.grid.nsd>=2:
direction=u.grid.nsd-1coor, u_coor, fixed_coor, snapped= \
u.gridline(u.grid.min_coor, direction)
# if snapped: print 'Error: snapped line'ifsnapped: print('Error: snapped line')
# print 'line in x[%d]-direction, starting at %s' % \# (direction, u.grid.min_coor)print('line in x[%d]-direction, starting at %s'% \
(direction, u.grid.min_coor))
# print coorprint(coor)
# print u_coorprint(u_coor)
direction=0point=u.grid.min_coor.copy()
point[direction+1] =u.grid.max_coor[direction+1]
coor, u_coor, fixed_coor, snapped= \
u.gridline(u.grid.min_coor, direction)
# if snapped: print 'Error: snapped line'ifsnapped: print('Error: snapped line')
# print 'line in x[%d]-direction, starting at %s' % \# (direction, point)print('line in x[%d]-direction, starting at %s'% \
(direction, point))
# print coorprint(coor)
# print u_coorprint(u_coor)
ifu.grid.nsd==3:
y_center= (u.grid.max_coor[1] +u.grid.min_coor[1])/2.0xc, yc, uc, fixed_coor, snapped= \
u.gridplane(value=y_center, constant_coor=1)
# print 'Plane y=%g:' % fixed_coor,print('Plane y=%g:'%fixed_coor,)
# if snapped: print ' (snapped from y=%g)' % y_centerifsnapped: print(' (snapped from y=%g)'%y_center)
else: print()
print(xc)
print(yc)
print(uc)
def_test4():
g1=UniformBoxGrid(min=0, max=1, division=4)
_testbox(g1)
spec='[0,1]x[-1,2] with indices [0:4]x[0:3]'g2=UniformBoxGrid.init_fromstring(spec)
_testbox(g2)
g3=UniformBoxGrid(min=(0,0,-1), max=(1,1,1), division=(4,3,2))
_testbox(g3)
if__name__=='__main__':
test_2Dmesh()
The text was updated successfully, but these errors were encountered:
MaxCan-Code
added a commit
to MaxCan-Code/fenics-tutorial
that referenced
this issue
Jan 25, 2021
I use FEniCS installed in WSL of Windows 10.
The version is 2019.01.
Then I update demo files in the tutorial.
I delete the plot code because WSL cannot use it.
The text was updated successfully, but these errors were encountered: