Skip to content

Commit d71ca77

Browse files
committed
Refactor Enclosure to Class, improve other D3D functions, WIP: Class that reads D3D model folder and displays it in a human readable way
1 parent 97ae955 commit d71ca77

16 files changed

+976
-297
lines changed

JulesD3D/D3DModel.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import matplotlib.pyplot as plt
2+
import matplotlib.patheffects as PathEffects
3+
from mpl_toolkits.mplot3d import Axes3D
4+
import pandas as pd
5+
import numpy as np
6+
from JulesD3D.dep import Depth
7+
from JulesD3D.grid import Grid
8+
from JulesD3D.enc import Enclosure
9+
from JulesD3D.bnd import Boundaries
10+
from os import path, walk
11+
from cmocean.cm import deep
12+
13+
colormap = deep
14+
15+
# Make this class containing objects of grid, bnd, enc, depth, mdf, sed files, bcc, bct
16+
17+
class D3DModel(object):
18+
'''
19+
Read a folder containing Delft3D4-FLOW files
20+
'''
21+
def __init__(self, *args, **kwargs):
22+
print("Ayyyyeyeyeye")
23+
24+
def __repr__(self):
25+
return "Reads all Delft3D files in a folder"
26+
27+
@staticmethod
28+
def readFolder(folderpath):
29+
if not path.exists(folderpath):
30+
raise Exception('Looks like read folder does not exist, aborting')
31+
32+
basename = path.basename(folderpath)
33+
plot_title, _ = path.splitext(basename)
34+
title = basename
35+
36+
all_filenames = []
37+
38+
# Find filenames in template/read folder
39+
for root, dirs, files in walk(folderpath):
40+
for file in files:
41+
if file.endswith('bnd'):
42+
bnd_filename = path.join(folderpath, file)
43+
all_filenames.append({"type": "Boundary", "filename": path.split(bnd_filename)[1]})
44+
elif file.endswith('dep'):
45+
dep_filename = path.join(folderpath, file)
46+
all_filenames.append({"type": "Depth", "filename": path.split(dep_filename)[1]})
47+
elif file.endswith('enc'):
48+
enc_filename = path.join(folderpath, file)
49+
all_filenames.append({"type": "Enclosure", "filename":path.split(enc_filename)[1]})
50+
elif file.endswith('grd'):
51+
grid_filename = path.join(folderpath, file)
52+
all_filenames.append({"type": "Grid", "filename":path.split(grid_filename)[1]})
53+
54+
files_df = pd.DataFrame(data=all_filenames)
55+
display(files_df)
56+
57+
self.filenames = all_filenames
58+
59+
# def readGrid(self):
60+
61+
# grid = Grid.read(grid_filename)
62+
# grid.shape
63+
64+
# dep = Depth.read(dep_filename, grid.shape)
65+
# depth = dep.values[0:-1,0:-1]
66+
67+
# boundary_coords = bnd.readBnd(fname=bnd_filename)
68+
69+
# enclosure_x, enclosure_y = readEnc(enc_filename)
70+

JulesD3D/DepthModel.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
# TODO
2+
# * Not sure if this is how to Class in Python ¯\_(ツ)_/¯
23
# * Fix bank_index (center) mess!
34
# * Make nice n clear repr string
45
# * Smoothen slope break direction independent
56

67
from JulesD3D.dep import Dep
78
from JulesD3D.grid import Grid
89
from JulesD3D.enc import writeEncFileWithChannel, writeSimpleEncFile
9-
from JulesD3D.bnd import bnd
10+
# from JulesD3D.bnd import Boundaries
1011
import bezier
1112
import numpy as np
1213
import math, os
@@ -43,7 +44,6 @@ def makeNewGrid(self):
4344
print("width", self.grid['width'])
4445
print("length", self.grid['length'])
4546

46-
4747
if self.grid['width'] % self.grid['x_gridstep']:
4848
raise Exception("Width is not a multiple of x_gridstep")
4949
if self.grid['length'] % self.grid['y_gridstep']:
@@ -251,13 +251,14 @@ def generateBathymetrySlopeBreak(self):
251251

252252
return depth_matrix_with_channel.T
253253

254+
@staticmethod
254255
def makeModelAtOnce(self):
255256
'''
256257
Performs all the generation steps and writing files at once in the right order
257258
'''
258259
self.makeNewGrid()
259260
self.writeGridFile()
260-
self.generateBathymetrySlopeBreak()
261+
self.generateBathymetrySlopeBreak()
261262
self.writeDepFile()
262263

263264
def plotCrossSection(self):

JulesD3D/bnd.py

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,34 @@
11
import pandas as pd
22

3-
class bnd():
4-
'''Delft3d boundary definition file'''
5-
# def __init__(self, fname=None):
6-
# self.readBnd(fname)
7-
# # self.read_bnd(fname)
3+
class Boundaries():
4+
'''
5+
Delft3D boundary definition file .bnd
6+
'''
7+
def __init__(self, fname=None):
8+
self.readBnd(self, fname)
89

910
def readBnd(fname=None): # self?
1011
'''Read a Delft3d boundary definition file, return list of coordinated for plotting'''
1112
if not fname:
12-
print("No file name supplied!")
13-
return
13+
raise Exception("No boundary filename given!")
1414

1515
column_names = ['name','type','forcing','m1','n1','m2','n2',
1616
'reflection coefficient','vertical profile',
1717
'label1','label2']
1818

19-
data = pd.read_csv(fname, delim_whitespace=True,
19+
bnd_data = pd.read_csv(fname, delim_whitespace=True,
2020
header=None, names=column_names)
2121

22-
display(data)
22+
display(bnd_data)
2323

2424
boundary_coords = []
25-
nr_of_bounds = data.shape[0]
25+
nr_of_bounds = bnd_data.shape[0]
2626
for i in range(nr_of_bounds):
27-
boundary_coords.append(([data.m1[i], data.n1[i]], [data.m2[i], data.n2[i]]))
27+
boundary_coords.append(([bnd_data.m1[i], bnd_data.n1[i]], [bnd_data.m2[i], bnd_data.n2[i]]))
2828

2929
return boundary_coords
3030

31+
# for plotting boundary locations
3132
def getXY(coords):
3233
bc_x_coords, bc_y_coords = [[], []]
3334
for bnd in coords:

JulesD3D/bndDemo.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,7 @@ def __init__(self, fname=None):
1111
def read_bnd(self, fname=None):
1212
'''Read a Delft3d boundary definition file'''
1313
if not fname:
14-
print("No boundary filename given!")
15-
return
16-
else:
17-
fname = fname
14+
raise Exception("No boundary filename given!")
1815

1916
column_names = ['name','type','forcing','m1','n1','m2','n2',
2017
'reflection coefficient','vertical profile',

JulesD3D/dep.py

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -43,31 +43,33 @@ def formatSci(floatNr):
4343

4444
import numpy as np
4545

46-
class Dep(object):
46+
class Depth(object):
4747
"""Create a Delft3D dep file
48-
# Create an dep grid
49-
dep = dep()
50-
# Load a dep from file
51-
grid = Grid.fromfile('filename.grd')
52-
dep = Dep.read('filename.dep',grid.shape)
53-
# Write dep to file
54-
Dep.write(dep,'filename.dep')"""
48+
Create an dep grid
49+
dep = Depth()
50+
51+
Load a dep from file (grid has to be loaded first)
52+
grid = Grid.read('filename.grd')
53+
dep = Depth.read('filename.dep',grid.shape)
54+
55+
Write dep to file
56+
Depth.write(dep,'filename.dep')"""
5557

5658
def __init__(self, *args, **kwargs):
5759
self.properties = {}
5860
self.shape = None
5961
self.dep = None
6062

6163
def copy(self):
62-
copy = Dep()
64+
copy = Depth()
6365
copy.shape = self.shape
6466
copy.values = self.values.copy()
6567

6668
return copy
6769

6870
@staticmethod
6971
def read(filename, gridshape, **kwargs):
70-
dep = Dep()
72+
dep = Depth()
7173
with open(filename, 'r') as f:
7274
strings = f.read()
7375
# f.close

JulesD3D/enc.py

Lines changed: 111 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,120 @@
11
import pandas as pd
2+
# check yDim, xDim are off by one or not
23

3-
# TODO turn into class with these functions as its methods
4-
def readEnc(filename=None):
5-
'''Read a Delft3d enclosure file. Return list of x coordinates and list of y coordinates for easy plotting of enclosure'''
6-
if not filename:
7-
print("No file name supplied!")
8-
return
9-
enclosure_x = []
10-
enclosure_y = []
11-
with open(filename,'r') as f:
12-
for i, line in enumerate(f):
13-
# boy this is hacky change to list comprehension?
14-
enclosure_x.append(int(line.split(" ")[1]))
15-
enclosure_y.append(int(line.split(" ")[2]))
16-
17-
enc_coords = {'x': enclosure_x, 'y': enclosure_y}
18-
coords_df = pd.DataFrame(data=enc_coords)
19-
20-
display(coords_df)
21-
22-
return enclosure_x, enclosure_y
4+
# demo enc function
5+
# writeEncFileWithChannel(xDim, yDim, new_filename=self.filenames['enc'],
6+
# bank_left=bank_left, bank_right=bank_right+2,
7+
# channel_length_index=channel_length_index-1)
238

24-
# Remember: Enclosure needs to be larger than boundary locations!
9+
# demo make new grid
10+
# newGrid = Grid()
11+
# newGrid.x = self.grid['x_grid'] # matrix
12+
# newGrid.y = self.grid['y_grid'] # matrix
13+
# newGrid.shape = self.grid['shape'] # list
14+
# newGrid.properties = {'Coordinate System': 'Cartesian', 'xori': 0.0, 'yori': 0.0, 'alfori': 0.0}
15+
# Grid.write(newGrid, self.filenames['grid'])
2516

26-
27-
# SIMPLE ENCLOSURE FILE spanning complete domain
28-
def writeSimpleEncFile(xDim, yDim, new_enc_filename=None):
29-
''' Write rectangular enclosure'''
30-
if not new_enc_filename:
31-
print("No .enc filename specified aborting!")
17+
class Enclosure():
18+
'''
19+
Create a Delft3D enclosure file
20+
Enclosure excludes gridcells from computation
21+
22+
Create a new enclosure
23+
enc = Enclosure()
3224
33-
enclosureX = [1, xDim + 1, xDim + 1, 1, 1]
34-
enclosureY = [1, 1, yDim + 1, yDim + 1, 1]
25+
Load a enclosure from .enc file
26+
enc = Enclosure.read('channelonly.enc')
3527
36-
print(" ----- Writing simple rectangular enclosure -----")
37-
with open(new_enc_filename, 'w') as enclosureOutfile:
38-
zipped = list(zip(enclosureX, enclosureY)) # merge x and y lists
39-
enclosureLines = [('{:>6}{:>6}\n'.format(line[0], line[1])) for line in zipped] # would line for line in work as well?
40-
enclosureOutfile.writelines(enclosureLines)
41-
42-
def writeEncFileWithChannel(xDim, yDim, new_enc_filename=None, bank_left=None, bank_right=None, channel_length_index=None): # Add channel_width argument
43-
''' Write enclosure file, ignoring 'banks' around channel'''
44-
if not new_enc_filename:
45-
raise Exception("No enclosure file name supplied!")
28+
Write enclosure to .enc file
29+
Enclosure.writeSimpleEnc(enc, 'complete.enc')
4630
47-
print(" ----- Writing enclosure file with channel -----")
48-
enclosureX = [1, bank_left, bank_left, bank_right, bank_right, xDim+1, xDim+1, 1, 1]
49-
enclosureY = [channel_length_index, channel_length_index, 1, 1, channel_length_index, channel_length_index, yDim+1, yDim+1, channel_length_index]
31+
Remember: Enclosure needs to be larger than boundary locations!
32+
'''
33+
def __init__(self, *args, **kwargs):
34+
self.dims = kwargs.get('dims')
35+
if not self.dims:
36+
raise Exception("No tuple of dimenstinos provided?")
37+
self.filename = kwargs.get('filename')
38+
xDim, yDim = self.dims
39+
40+
if kwargs.get("channel_length_index"):
41+
self.channel_length_index = kwargs.get("channel_length_index")
42+
self.bank_left = kwargs.get('bank_left')
43+
self.bank_right = kwargs.get('bank_right')
44+
self.x = [1, self.bank_left, self.bank_left, self.bank_right, self.bank_right, xDim+1, xDim+1, 1, 1]
45+
self.y = [self.channel_length_index, self.channel_length_index, 1, 1, self.channel_length_index, self.channel_length_index, yDim+1, yDim+1, self.channel_length_index]
46+
elif kwargs.get('read_filename'):
47+
self.x = kwargs.get('x') # list of x coords
48+
self.y = kwargs.get('y') # list of y coords
49+
else:
50+
self.x = [1, xDim + 1, xDim + 1, 1, 1]
51+
self.y = [1, 1, yDim + 1, yDim + 1, 1]
52+
53+
54+
def __repr__(self):
55+
repr_string = f"New Enclosure with xDim {self.dims[0]} and yDim {self.dims[1]}"
56+
57+
# if self.channel_length_index and self.bank_left and self.bank_right: # can't acces these properties if they are not arguments to Enclosure
58+
# repr_string += f" with channel at y = {self.channel_length_index} from {self.bank_left} to {self.bank_right}"
59+
60+
return repr_string
5061

51-
with open(new_enc_filename, 'w') as enclosureOutfile:
52-
zipped = list(zip(enclosureX, enclosureY))
53-
enclosureLines = [('{:>6}{:>6}\n'.format(line[0], line[1])) for line in zipped] # print both padded to 6 characters wide
54-
# [print(enclosureLine) for enclosureLine in enclosureLines]
55-
enclosureOutfile.writelines(enclosureLines)
62+
def display(self):
63+
enc_coords = {'x': self.x, 'y': self.y}
64+
enc_coords_df = pd.DataFrame(data=enc_coords)
65+
66+
return display(enc_coords_df)
67+
68+
@staticmethod
69+
def read(filename=None):
70+
'''Read a Delft3d enclosure file. Return list of x coordinates and list of y coordinates for easy plotting of enclosure'''
71+
if not filename:
72+
raise Exception("No file name supplied!")
73+
74+
with open(filename, 'r') as f:
75+
enc_coords = [(int(line.split(" ")[1]), int(line.split(" ")[2])) for line in f]
76+
77+
enc_x, enc_y = zip(*enc_coords) # unzip
78+
79+
xDim = max(enc_x)
80+
yDim = max(enc_y)
81+
dims = (xDim, yDim)
82+
83+
# how do i know from read file wether is has channel
84+
85+
enc = Enclosure(dims=dims, read_filename=True, x=enc_x, y=enc_y)
86+
87+
Enclosure.x = enc_x
88+
Enclosure.y = enc_y
89+
90+
enc_coords = {'x': enc_x, 'y': enc_y}
91+
enc_coords_df = pd.DataFrame(data=enc_coords)
92+
93+
display(enc_coords_df)
94+
95+
Enclosure.filename = filename
96+
97+
return enc
98+
99+
def write(self): # Add channel_width argument
100+
'''
101+
Write enclosure file,
102+
* with_channel: option to ignore 'banks' around channel
103+
'''
104+
if not self.filename:
105+
raise Exception("No enclosure filename supplied!")
106+
107+
if not self.channel_length_index or not self.bank_left or not self.bank_right:
108+
raise Exception("bank_left, bank_right, and channel_length_index keyword arguments have to be provided when excluding areas from enclosure!")
109+
print(" ----- Writing enclosure file excluding channel -----")
110+
else:
111+
print(" ----- Writing simple (rectangular) enclosure -----")
112+
113+
with open(self.filename, 'w') as enclosureOutfile:
114+
zipped = list(zip(self.x, self.y))
115+
enclosureLines = [('{:>6}{:>6}\n'.format(line[0], line[1])) for line in zipped] # pad both to 6 characters wide
116+
enclosureOutfile.writelines(enclosureLines)
117+
118+
print(" ----- Wrote new .enc file to", self.filename)
56119

57-
return [enclosureX, enclosureY]
120+
return [self.x, self.y]

0 commit comments

Comments
 (0)