195 lines
6.4 KiB
Python
195 lines
6.4 KiB
Python
|
|
import optparse
|
||
|
|
import shutil, distutils.dir_util, os, sys, glob
|
||
|
|
|
||
|
|
import numpy
|
||
|
|
import math
|
||
|
|
import matplotlib.pyplot as plt
|
||
|
|
from pylagrit import PyLaGriT
|
||
|
|
|
||
|
|
#
|
||
|
|
# Create parser and options
|
||
|
|
#
|
||
|
|
p = optparse.OptionParser()
|
||
|
|
p.add_option('--dem-file', help='DEM data file name including path', type='string', dest='dem_filename' )
|
||
|
|
p.add_option('--exo-file', help='Exodus II mesh output including path', type='string', dest='exo_filename')
|
||
|
|
p.add_option('--dry-run', help='Show commands and diagnostics but no execution', default=False, dest='dry_run', action='store_true')
|
||
|
|
p.add_option('--plot', help='Show commands and diagnostics but no execution', default=False, dest='plot', action='store_true')
|
||
|
|
#
|
||
|
|
(opts,args) = p.parse_args()
|
||
|
|
|
||
|
|
print(opts.dem_filename)
|
||
|
|
print(opts.dry_run)
|
||
|
|
|
||
|
|
# Input: DEM data
|
||
|
|
dem_file_fullname=opts.dem_filename
|
||
|
|
dem_file_noext, dem_file_ext=os.path.splitext(opts.dem_filename)
|
||
|
|
dem_file_base=os.path.basename(opts.dem_filename).rstrip(dem_file_ext)
|
||
|
|
dem_file_path=os.path.dirname(opts.dem_filename)
|
||
|
|
|
||
|
|
# Output: Exodus II mesh
|
||
|
|
exo_file_fullname=opts.exo_filename
|
||
|
|
exo_file_noext, exo_file_ext=os.path.splitext(opts.exo_filename)
|
||
|
|
exo_file_base=os.path.basename(opts.exo_filename).rstrip(exo_file_ext)
|
||
|
|
exo_file_path=os.path.dirname(opts.exo_filename)
|
||
|
|
|
||
|
|
# Output: XML region specifications for the new mesh
|
||
|
|
xml_file_fullname=exo_file_path+exo_file_base+'.xml'
|
||
|
|
|
||
|
|
# DEM parsing
|
||
|
|
#
|
||
|
|
with open(dem_file_fullname) as dem_header:
|
||
|
|
for line in dem_header:
|
||
|
|
if ("ncols" in line):
|
||
|
|
nx=int(line.split()[1])
|
||
|
|
elif ("nrows" in line):
|
||
|
|
ny=int(line.split()[1])
|
||
|
|
elif ("xllcorner" in line):
|
||
|
|
xll_corner=float(line.split()[1])
|
||
|
|
elif ("yllcorner" in line):
|
||
|
|
yll_corner=float(line.split()[1])
|
||
|
|
elif ("cellsize" in line):
|
||
|
|
dx=float(line.split()[1])
|
||
|
|
dy=dx
|
||
|
|
elif ("NODATA_value" in line):
|
||
|
|
no_data_value=int(line.split()[1])
|
||
|
|
break
|
||
|
|
|
||
|
|
print(nx, ny, xll_corner, yll_corner, dx, dy, no_data_value)
|
||
|
|
dem_header.close()
|
||
|
|
|
||
|
|
d = numpy.flipud(numpy.genfromtxt(dem_file_fullname,skip_header=6))
|
||
|
|
#plt.matshow(d)
|
||
|
|
|
||
|
|
# Create mesh based on ncols and nrows in file, could automatically read
|
||
|
|
x = numpy.linspace(xll_corner,dx*(nx-1),nx)
|
||
|
|
y = numpy.linspace(yll_corner,dy*(ny-1),ny)
|
||
|
|
|
||
|
|
x=numpy.arange(xll_corner,dx*nx,dx)
|
||
|
|
y=numpy.arange(yll_corner,dy*ny,dy)
|
||
|
|
|
||
|
|
xx, yy = numpy.meshgrid(x,y)
|
||
|
|
|
||
|
|
# Write avs file
|
||
|
|
fh = open(dem_file_base+'.avs','w')
|
||
|
|
# Find number of data values and write avs header
|
||
|
|
N = numpy.where(numpy.isnan(d)==False)[0].shape[0]
|
||
|
|
fh.write(str(N)+' 0 0 0 0\n')
|
||
|
|
# Collect data into avs format
|
||
|
|
# JDM: Not sure if this should be nx*ny?
|
||
|
|
davs = numpy.zeros([nx*ny,4])
|
||
|
|
ind = 0
|
||
|
|
for i,row in enumerate(d):
|
||
|
|
for j,v in enumerate(row):
|
||
|
|
davs[ind,:] = [ind + 1, xx[i,j], yy[i,j], v]
|
||
|
|
ind += 1
|
||
|
|
# Write data to avs file
|
||
|
|
numpy.savetxt(fh,davs,fmt=['%4d','%.1lf','%.1lf','%.8lf'])
|
||
|
|
fh.close()
|
||
|
|
|
||
|
|
# Crank up pylagrit
|
||
|
|
lg = PyLaGriT()
|
||
|
|
# Read in elevations in avs fromat
|
||
|
|
m = lg.read(dem_file_base+'.avs')
|
||
|
|
# Take a look, change paraview exe
|
||
|
|
# Will need to use glyph filter to view points
|
||
|
|
#m.paraview(exe='paraview')
|
||
|
|
|
||
|
|
# Copy z values over to attribute
|
||
|
|
m.addatt('z_save',vtype='vdouble',rank='scalar')
|
||
|
|
m.copyatt('zic','z_save')
|
||
|
|
# Not sure why this has to be done, but not data elements don't get removed otherwise
|
||
|
|
m.setatt('zic',0.)
|
||
|
|
|
||
|
|
# Create connected quad mesh surface
|
||
|
|
m2 = lg.create()
|
||
|
|
#m2.createpts_xyz((nx,ny,1),[xx.min(),yy.min(),0.],[xx.max(),yy.max(),0],rz_switch=[1,1,1],connect=True)
|
||
|
|
m2.createpts_xyz((nx,ny,1),[xx.min(),yy.min(),0.],[xx.max(),yy.max(),0],rz_switch=[1,1,1])
|
||
|
|
# Create temporary z value attribute
|
||
|
|
m2.addatt('z_save',vtype='vdouble',rank='scalar')
|
||
|
|
# Interpolate elevations to z_save
|
||
|
|
m2.interpolate_voronoi('z_save',m,'z_save')
|
||
|
|
# Find nodes associated with nodata
|
||
|
|
pdel = m2.pset_attribute('z_save',-9999)
|
||
|
|
# Create element set from these nodes and remove elements
|
||
|
|
edel = pdel.eltset()
|
||
|
|
m2.rmpoint_eltset(edel)
|
||
|
|
# Copy temp z values over to actual a values
|
||
|
|
#m2.copyatt('z_save','zic')
|
||
|
|
# Take a look to make sure everything is ok
|
||
|
|
#m2.paraview(exe='paraview')
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
m3 = m2.copypts(elem_type='triplane')
|
||
|
|
m3.connect()
|
||
|
|
# To lazy to add to pylagrit now, and don't know how to make it intuitive
|
||
|
|
# Creates edge_max element attribute containing max edge length
|
||
|
|
m3.sendline('quality/edge_max/y')
|
||
|
|
# Query created attribute
|
||
|
|
#m3.printatt('edgemax')
|
||
|
|
m3.minmax('edgemax')
|
||
|
|
# Figure out max desired edge length
|
||
|
|
max_edge = numpy.sqrt(dx**2+dy**2)
|
||
|
|
# Identify elements with longer edges
|
||
|
|
edel = m3.eltset_attribute('edgemax',max_edge*2.05,'gt')
|
||
|
|
m3.rmpoint_eltset(edel)
|
||
|
|
|
||
|
|
#m3 = m2.grid2grid_quadtotri2()
|
||
|
|
#m3=m2
|
||
|
|
# Create temporary z value attribute
|
||
|
|
m3.addatt('z_save',vtype='vdouble',rank='scalar')
|
||
|
|
# Interpolate elevations to z_save
|
||
|
|
m3.interpolate_voronoi('z_save',m,'z_save')
|
||
|
|
|
||
|
|
# Find nodes associated with nodata
|
||
|
|
pdel = m3.pset_attribute('z_save',-9999)
|
||
|
|
# Create element set from these nodes and remove elements
|
||
|
|
edel = pdel.eltset()
|
||
|
|
m3.rmpoint_eltset(edel)
|
||
|
|
# Copy temp z values over to actual a values
|
||
|
|
m3.copyatt('z_save','zic')
|
||
|
|
# Take a look to make sure everything is ok
|
||
|
|
#m2.paraview(exe='paraview')
|
||
|
|
|
||
|
|
# Create top surface avs
|
||
|
|
m3.dump('top.inp')
|
||
|
|
## Subtract 1 from z values of top and dump into bottom surface avs
|
||
|
|
m3.math('sub',1,'zic',cmosrc=m3)
|
||
|
|
m3.dump('mid.inp')
|
||
|
|
m3.setatt('zic',0.0)
|
||
|
|
m3.dump('bot.inp')
|
||
|
|
|
||
|
|
# Stack the layers in a new mesh object
|
||
|
|
stack = lg.create()
|
||
|
|
stack.stack_layers('avs',['bot.inp 1','mid.inp 1,3','top.inp 1,0'],flip_opt=True)
|
||
|
|
stack_hex = stack.stack_fill()
|
||
|
|
# Automatically create face sets based on normal vectors and layer id
|
||
|
|
#fs = stack_hex.create_boundary_facesets(base_name='faceset_bounds',stacked_layers=True)
|
||
|
|
#fs = stack_hex.create_boundary_facesets(base_name='faceset_bounds',stacked_layers=False)
|
||
|
|
# Diagnostic
|
||
|
|
#stack_hex.sendline('quality volume itetclr')
|
||
|
|
|
||
|
|
# Write exo file with boundary facesets
|
||
|
|
#stack_hex.dump_exo(exo_file_fullname,facesets=fs.values())
|
||
|
|
stack_hex.dump_exo(exo_file_fullname)
|
||
|
|
|
||
|
|
# Write region and faceset identifier file for ats_xml
|
||
|
|
matnames = {10000:'computational domain peat'}
|
||
|
|
facenames = {1:'bottom face',
|
||
|
|
2:'surface',
|
||
|
|
3:'front',
|
||
|
|
4:'right',
|
||
|
|
5:'back',
|
||
|
|
6:'left'}
|
||
|
|
|
||
|
|
# Dump ats style xml for mesh, can provide options for other schemas easily also
|
||
|
|
#stack_hex.dump_ats_xml(xml_file_fullname,exo_file_fullname,matnames=matnames,facenames=facenames)
|
||
|
|
stack_hex.dump_ats_xml(xml_file_fullname,exo_file_fullname,matnames=matnames,facenames=facenames)
|
||
|
|
|
||
|
|
# Take a look
|
||
|
|
if opts.plot:
|
||
|
|
stack_hex.paraview(exe='/Applications/paraview.app/Contents/MacOS/paraview')
|
||
|
|
|
||
|
|
|
||
|
|
|