datagenerator.fluvsim

  1########################################################################
  2# Code to create numpy 3D array with output from channel simulations
  3# - runs fortran program fluvsim.for for a single channel
  4# -- creates fluvsim parameter file (fluvsim.par)
  5# -- reads parameter file
  6# -- runs fluvsim simulation
  7# -- returns 3D array
  8#    --- Codes for facies output:
  9#    --- 0  is floodplain shale
 10#    --- 1  is channel fill (sand)
 11#    --- 2  is shale channel drape
 12#    --- 3  is levee (mid quality sand)
 13#    --- 4  is crevasse (low quality sand)
 14########################################################################
 15
 16import os
 17import numpy as np
 18from datetime import datetime
 19from datagenerator.util import import_matplotlib
 20
 21plt = import_matplotlib()
 22
 23
 24def create_fluvsim_params(
 25    nx=100,
 26    ny=100,
 27    maxthickness=50,
 28    work_folder="/scratch"
 29) -> None:
 30    """
 31    Create Fluvsim parameter file
 32    -----------------------------
 33
 34    Create fluvsim.par parameter file with 
 35    parameters for fluvsim simulation
 36
 37    Parameters
 38    ----------
 39    nx : int, optional
 40        _description_, by default 100
 41    ny : int, optional
 42        _description_, by default 100
 43    maxthickness : int, optional
 44        Maximum thickness, by default 50
 45    work_folder : str, optional
 46        Default work folder, by default "/scratch"
 47    
 48    Returns
 49    -------
 50    None
 51    """
 52
 53    # create fluvsim.par parameter file with randomly chosen values for some parameters
 54    seed = datetime.now().microsecond
 55
 56    # number of channels
 57    # - compute number of channels (needs 10 to work properly)
 58    num_chans = int(np.random.triangular(left=3, mode=5, right=25) + 0.5)
 59    print("...num_chans = ", num_chans)
 60
 61    # channel depth
 62    # - compute number that range from 1+ to 7+, centered at ~3
 63    # - re-scale for maxthickness/50.
 64    vert_scale_factor = maxthickness / 50.0
 65    # random_chan_thickness = np.random.gamma(shape=15.,scale=3.)/13.5       *  vert_scale_factor
 66    # random_chan_thickness = np.random.gamma(shape=5.,scale=7.)/13.5       *  vert_scale_factor
 67    random_chan_thickness = (
 68        np.random.gamma(shape=5.0, scale=5.65) / 13.5 * vert_scale_factor
 69    )
 70    random_chan_thickness = format(random_chan_thickness, "2.1f")
 71    print("...random_chan_thickness = ", random_chan_thickness)
 72
 73    # channel lateral departure (meander width)
 74    # - re-scale
 75    lateral_scale_factor = nx / 100.0
 76    avg_departure = 175.0 * lateral_scale_factor
 77    avg_departure = format(avg_departure, "5.0f")
 78
 79    # channel sinuosity (meander) wavelength
 80    # - re-scale for low/mid/high (L/M/H)
 81    wavelength_factor = nx / 100.0
 82    avg_length = 800.0 * wavelength_factor
 83    avg_length_l = format(avg_length * 0.7, "5.0f")
 84    avg_length_m = format(avg_length, "5.0f")
 85    avg_length_h = format(avg_length * 1.3, "5.0f")
 86
 87    # levee width
 88    levee_onoff = np.random.binomial(1, 0.6)
 89    # levee width
 90    # - re-scale for low/mid/high (L/M/H)
 91    avg_levee = 240.0 * lateral_scale_factor
 92    avg_levee_l = format(avg_levee * 0.67, "5.0f")
 93    avg_levee_m = format(avg_levee, "5.0f")
 94    avg_levee_h = format(avg_levee * 2.0, "5.0f")
 95    print("...levee widths = ", avg_levee_l, avg_levee_m, avg_levee_h)
 96
 97    param_file_text = (
 98        "                   Parameters for FLUVSIM"
 99        + "\n"
100        + "                   **********************"
101        + "\n"
102        + ""
103        + "\n"
104        + "START OF PARAMETERS:"
105        + "\n"
106        + "data/well01.dat                -file with well conditioning data"
107        + "\n"
108        + "1  2  3  4  5                  -  columns for X, Y, Z, well #, facies"
109        + "\n"
110        + "-1.0       1.0e21              -  trimming limits"
111        + "\n"
112        + "1                              -debugging level: 0,1,2,3"
113        + "\n"
114        + "output/fluvsim.dbg             -file for debugging output"
115        + "\n"
116        + "output/fluvsim.geo             -file for geometric specification"
117        + "\n"
118        + "output/fluvsim.out             -file for simulation output"
119        + "\n"
120        + "output/fluvsim.vp              -file for vertical prop curve output"
121        + "\n"
122        + "output/fluvsim.ap              -file for areal prop map output"
123        + "\n"
124        + "output/fluvsim.wd              -file for well data output"
125        + "\n"
126        + "1                              -number of realizations to generate"
127        + "\n"
128        + format(nx, "<3d")
129        + "   0.0    40.0             -nx,xmn,xsiz - geological coordinates"
130        + "\n"
131        + format(nx, "<3d")
132        + "   0.0    40.0             -ny,ymn,ysiz - geological coordinates"
133        + "\n"
134        + format(int(maxthickness), "<3d")
135        + "          50.0              -nz, average thickness in physical units"
136        + "\n"
137        + format(seed, "<6d")
138        + "                         -random number seed"
139        + "\n"
140        + "1   0   0   1                  -1=on,0=off: global, vert, areal, wells"
141        + "\n"
142        + "1.  1.  1.  1.                 -weighting : global, vert, areal, wells"
143        + "\n"
144        + "1     10   0.05                -maximum iter, max no change, min. obj."
145        + "\n"
146        + "0.0   0.10   3  1  8           -annealing schedule: t0,redfac,ka,k,num"
147        + "\n"
148        + "0.1 0.1 0.1 1.0                -Pert prob: 1on+1off, 1on, 1off, fix well"
149        + "\n"
150        + "   1    1    "
151        + format(levee_onoff, "1d")
152        + "                 -Facies(on): channel, levee, crevasse"
153        + "\n"
154        + "0.30 0.15 0.03                 -Proportion: channel, levee, crevasse"
155        + "\n"
156        + "pcurve.dat                     -  vertical proportion curves"
157        + "\n"
158        + "0                              -     0=net-to-gross, 1=all facies"
159        + "\n"
160        + "1  7  8                        -     column numbers"
161        + "\n"
162        + "arealprop.dat                  -  areal proportion map"
163        + "\n"
164        + "1                              -     0=net-to-gross, 1=all facies"
165        + "\n"
166        + "2  3  4                        -     column numbers"
167        + "\n"
168        + format(num_chans, "<3d")
169        + "                            -maximum number of channels"
170        + "\n"
171        + "-45.0    0.0    45.0           -channel:  orientation (degrees)"
172        + "\n"
173        + avg_departure
174        + "  "
175        + avg_departure
176        + "   "
177        + avg_departure
178        + "           -channel:  sinuosity: average departure"
179        + "\n"
180        + avg_length_l
181        + "  "
182        + avg_length_m
183        + "   "
184        + avg_length_h
185        + "           -channel:  sinuosity: length scale"
186        + "\n"
187        + "  "
188        + random_chan_thickness
189        + "    "
190        + random_chan_thickness
191        + "     "
192        + random_chan_thickness
193        + "           -channel:  thickness"
194        + "\n"
195        + "  1.0    1.0     1.0           -channel:  thickness undulation"
196        + "\n"
197        + "250.0  400.0   650.0           -channel:  thickness undul. length scale"
198        + "\n"
199        + " 50.0  150.0   300.0           -channel:  width/thickness ratio"
200        + "\n"
201        + "  1.0    1.0     1.0           -channel:  width: undulation"
202        + "\n"
203        + "250.0  400.0   550.0           -channel:  width: undulation length scale"
204        + "\n"
205        + "500.0 1500.0  3500.0           -levee:    average width"
206        + "\n"
207        + "  0.1    0.15    0.25          -levee:    average height"
208        + "\n"
209        + "  0.05   0.1     0.3           -levee:    depth below top"
210        + "\n"
211        + " 80.0  200.0   500.0           -crevasse: attachment length"
212        + "\n"
213        + "  0.25   0.5     0.75          -crevasse: relative thickness by channel"
214        + "\n"
215        + "200.0  500.0  4500.0           -crevasse: areal size (diameter)"
216        + "\n"
217    )
218
219    # avg_levee_l+'  '+avg_levee_m+'   '+avg_levee_h+'           -levee:    average width'+'\n'+\
220
221    # write param file to disk
222    params_file = os.path.abspath(os.path.join(work_folder, "fluvsim.par"))
223    with open(params_file, "w") as paramfile:
224        paramfile.write(param_file_text)
225    return
226
227
228def read_fluvsim_output(nx, ny, nz, work_folder="/scratch"):
229    # from scipy.ndimage.morphology import grey_closing
230
231    output_file = os.path.abspath(os.path.join(work_folder, "output", "fluvsim.out"))
232    f = open(output_file)
233    a = f.read().split("\n")
234
235    kk = 0
236    facies = np.zeros((nx, ny, nz), "int")
237    for k in range(nz):
238        for j in range(ny):
239            for i in range(nx):
240                facies[i, j, k] = int(a[kk])
241                kk = kk + 1
242
243    return facies
244
245
246def run_fluvsim(nx=100, ny=100, maxthickness=50, work_folder="/scratch", quiet=True):
247    # set up to work on scratch folder
248    current_dir = os.getcwd()
249    code_dir = os.path.join(os.path.abspath(os.path.dirname(__file__)))
250    code_file = os.path.join(code_dir, "fluvsim.f90")
251    workfolder_code_file = os.path.join(work_folder, "fluvsim.f90")
252    os.system("cp " + code_file + " " + workfolder_code_file)
253    try:
254        workfolder_output = os.path.abspath(os.path.join(work_folder, "output"))
255        os.system("mkdir -p " + workfolder_output + "&>/scratch/outputfile")
256    except OSError:
257        pass
258    os.chdir(work_folder)
259    fortran_code_file = os.path.abspath(os.path.join(work_folder, "fluvsim.f90"))
260    compiled_fortran_code_file = "./fluvsim.o"
261    return_code_2 = os.system(
262        "gfortran " + fortran_code_file + " -o " + compiled_fortran_code_file
263    )
264    if return_code_2 != 0:
265        print("...retrieving fluvsim.o from code repository....")
266        os.system(
267            "cp -p "
268            + os.path.join(code_dir, "fluvsim2.o")
269            + " "
270            + compiled_fortran_code_file
271        )
272
273    # create params file
274    create_fluvsim_params(
275        nx=nx, ny=ny, maxthickness=maxthickness, work_folder=work_folder
276    )
277
278    # run fluvsim
279    os.chdir(work_folder)
280    os.system(
281        compiled_fortran_code_file
282        + "&>"
283        + os.path.join(work_folder, "fluvsim_output.txt")
284    )
285
286    # read fluvsim.out ascii file into numpy array
287    facies = read_fluvsim_output(nx, ny, maxthickness, work_folder=work_folder)
288
289    if quiet:  # TODO save plots to output dir?
290        # plot
291        xsection = 10
292        ysection = 10
293        zsection = 30
294
295        # xsection
296        plt.figure(1, figsize=(15, 9))
297        plt.subplot(2, 1, 1)
298        temp = facies[xsection, :, :]
299        plt.imshow(np.rot90(temp))
300        plt.title("xsection = " + str(xsection))
301
302        # ysection
303        plt.subplot(2, 1, 2)
304        temp = facies[:, ysection, :]
305        plt.imshow(np.rot90(temp))
306        plt.title("ysection = " + str(ysection))
307
308        # zsection
309        plt.figure(2, figsize=(10, 10))
310        temp = facies[:, :, zsection]
311        plt.imshow(temp)
312        plt.title("zsection = " + str(zsection))
313
314        plt.show()
315
316    os.chdir(current_dir)
317
318    return facies
319
320
321if __name__ == "__main__":
322
323    # nx=300
324    # ny=300
325    # maxthickness=800
326    # quiet=False
327    model = run_fluvsim(nx=300, ny=300, maxthickness=800, quiet=False)
328    print("model shape = ", model.shape)
def create_fluvsim_params(nx=100, ny=100, maxthickness=50, work_folder='/scratch') -> None:
 25def create_fluvsim_params(
 26    nx=100,
 27    ny=100,
 28    maxthickness=50,
 29    work_folder="/scratch"
 30) -> None:
 31    """
 32    Create Fluvsim parameter file
 33    -----------------------------
 34
 35    Create fluvsim.par parameter file with 
 36    parameters for fluvsim simulation
 37
 38    Parameters
 39    ----------
 40    nx : int, optional
 41        _description_, by default 100
 42    ny : int, optional
 43        _description_, by default 100
 44    maxthickness : int, optional
 45        Maximum thickness, by default 50
 46    work_folder : str, optional
 47        Default work folder, by default "/scratch"
 48    
 49    Returns
 50    -------
 51    None
 52    """
 53
 54    # create fluvsim.par parameter file with randomly chosen values for some parameters
 55    seed = datetime.now().microsecond
 56
 57    # number of channels
 58    # - compute number of channels (needs 10 to work properly)
 59    num_chans = int(np.random.triangular(left=3, mode=5, right=25) + 0.5)
 60    print("...num_chans = ", num_chans)
 61
 62    # channel depth
 63    # - compute number that range from 1+ to 7+, centered at ~3
 64    # - re-scale for maxthickness/50.
 65    vert_scale_factor = maxthickness / 50.0
 66    # random_chan_thickness = np.random.gamma(shape=15.,scale=3.)/13.5       *  vert_scale_factor
 67    # random_chan_thickness = np.random.gamma(shape=5.,scale=7.)/13.5       *  vert_scale_factor
 68    random_chan_thickness = (
 69        np.random.gamma(shape=5.0, scale=5.65) / 13.5 * vert_scale_factor
 70    )
 71    random_chan_thickness = format(random_chan_thickness, "2.1f")
 72    print("...random_chan_thickness = ", random_chan_thickness)
 73
 74    # channel lateral departure (meander width)
 75    # - re-scale
 76    lateral_scale_factor = nx / 100.0
 77    avg_departure = 175.0 * lateral_scale_factor
 78    avg_departure = format(avg_departure, "5.0f")
 79
 80    # channel sinuosity (meander) wavelength
 81    # - re-scale for low/mid/high (L/M/H)
 82    wavelength_factor = nx / 100.0
 83    avg_length = 800.0 * wavelength_factor
 84    avg_length_l = format(avg_length * 0.7, "5.0f")
 85    avg_length_m = format(avg_length, "5.0f")
 86    avg_length_h = format(avg_length * 1.3, "5.0f")
 87
 88    # levee width
 89    levee_onoff = np.random.binomial(1, 0.6)
 90    # levee width
 91    # - re-scale for low/mid/high (L/M/H)
 92    avg_levee = 240.0 * lateral_scale_factor
 93    avg_levee_l = format(avg_levee * 0.67, "5.0f")
 94    avg_levee_m = format(avg_levee, "5.0f")
 95    avg_levee_h = format(avg_levee * 2.0, "5.0f")
 96    print("...levee widths = ", avg_levee_l, avg_levee_m, avg_levee_h)
 97
 98    param_file_text = (
 99        "                   Parameters for FLUVSIM"
100        + "\n"
101        + "                   **********************"
102        + "\n"
103        + ""
104        + "\n"
105        + "START OF PARAMETERS:"
106        + "\n"
107        + "data/well01.dat                -file with well conditioning data"
108        + "\n"
109        + "1  2  3  4  5                  -  columns for X, Y, Z, well #, facies"
110        + "\n"
111        + "-1.0       1.0e21              -  trimming limits"
112        + "\n"
113        + "1                              -debugging level: 0,1,2,3"
114        + "\n"
115        + "output/fluvsim.dbg             -file for debugging output"
116        + "\n"
117        + "output/fluvsim.geo             -file for geometric specification"
118        + "\n"
119        + "output/fluvsim.out             -file for simulation output"
120        + "\n"
121        + "output/fluvsim.vp              -file for vertical prop curve output"
122        + "\n"
123        + "output/fluvsim.ap              -file for areal prop map output"
124        + "\n"
125        + "output/fluvsim.wd              -file for well data output"
126        + "\n"
127        + "1                              -number of realizations to generate"
128        + "\n"
129        + format(nx, "<3d")
130        + "   0.0    40.0             -nx,xmn,xsiz - geological coordinates"
131        + "\n"
132        + format(nx, "<3d")
133        + "   0.0    40.0             -ny,ymn,ysiz - geological coordinates"
134        + "\n"
135        + format(int(maxthickness), "<3d")
136        + "          50.0              -nz, average thickness in physical units"
137        + "\n"
138        + format(seed, "<6d")
139        + "                         -random number seed"
140        + "\n"
141        + "1   0   0   1                  -1=on,0=off: global, vert, areal, wells"
142        + "\n"
143        + "1.  1.  1.  1.                 -weighting : global, vert, areal, wells"
144        + "\n"
145        + "1     10   0.05                -maximum iter, max no change, min. obj."
146        + "\n"
147        + "0.0   0.10   3  1  8           -annealing schedule: t0,redfac,ka,k,num"
148        + "\n"
149        + "0.1 0.1 0.1 1.0                -Pert prob: 1on+1off, 1on, 1off, fix well"
150        + "\n"
151        + "   1    1    "
152        + format(levee_onoff, "1d")
153        + "                 -Facies(on): channel, levee, crevasse"
154        + "\n"
155        + "0.30 0.15 0.03                 -Proportion: channel, levee, crevasse"
156        + "\n"
157        + "pcurve.dat                     -  vertical proportion curves"
158        + "\n"
159        + "0                              -     0=net-to-gross, 1=all facies"
160        + "\n"
161        + "1  7  8                        -     column numbers"
162        + "\n"
163        + "arealprop.dat                  -  areal proportion map"
164        + "\n"
165        + "1                              -     0=net-to-gross, 1=all facies"
166        + "\n"
167        + "2  3  4                        -     column numbers"
168        + "\n"
169        + format(num_chans, "<3d")
170        + "                            -maximum number of channels"
171        + "\n"
172        + "-45.0    0.0    45.0           -channel:  orientation (degrees)"
173        + "\n"
174        + avg_departure
175        + "  "
176        + avg_departure
177        + "   "
178        + avg_departure
179        + "           -channel:  sinuosity: average departure"
180        + "\n"
181        + avg_length_l
182        + "  "
183        + avg_length_m
184        + "   "
185        + avg_length_h
186        + "           -channel:  sinuosity: length scale"
187        + "\n"
188        + "  "
189        + random_chan_thickness
190        + "    "
191        + random_chan_thickness
192        + "     "
193        + random_chan_thickness
194        + "           -channel:  thickness"
195        + "\n"
196        + "  1.0    1.0     1.0           -channel:  thickness undulation"
197        + "\n"
198        + "250.0  400.0   650.0           -channel:  thickness undul. length scale"
199        + "\n"
200        + " 50.0  150.0   300.0           -channel:  width/thickness ratio"
201        + "\n"
202        + "  1.0    1.0     1.0           -channel:  width: undulation"
203        + "\n"
204        + "250.0  400.0   550.0           -channel:  width: undulation length scale"
205        + "\n"
206        + "500.0 1500.0  3500.0           -levee:    average width"
207        + "\n"
208        + "  0.1    0.15    0.25          -levee:    average height"
209        + "\n"
210        + "  0.05   0.1     0.3           -levee:    depth below top"
211        + "\n"
212        + " 80.0  200.0   500.0           -crevasse: attachment length"
213        + "\n"
214        + "  0.25   0.5     0.75          -crevasse: relative thickness by channel"
215        + "\n"
216        + "200.0  500.0  4500.0           -crevasse: areal size (diameter)"
217        + "\n"
218    )
219
220    # avg_levee_l+'  '+avg_levee_m+'   '+avg_levee_h+'           -levee:    average width'+'\n'+\
221
222    # write param file to disk
223    params_file = os.path.abspath(os.path.join(work_folder, "fluvsim.par"))
224    with open(params_file, "w") as paramfile:
225        paramfile.write(param_file_text)
226    return
Create Fluvsim parameter file

Create fluvsim.par parameter file with parameters for fluvsim simulation

Parameters
  • nx (int, optional): _description_, by default 100
  • ny (int, optional): _description_, by default 100
  • maxthickness (int, optional): Maximum thickness, by default 50
  • work_folder (str, optional): Default work folder, by default "/scratch"
Returns
  • None
def read_fluvsim_output(nx, ny, nz, work_folder='/scratch'):
229def read_fluvsim_output(nx, ny, nz, work_folder="/scratch"):
230    # from scipy.ndimage.morphology import grey_closing
231
232    output_file = os.path.abspath(os.path.join(work_folder, "output", "fluvsim.out"))
233    f = open(output_file)
234    a = f.read().split("\n")
235
236    kk = 0
237    facies = np.zeros((nx, ny, nz), "int")
238    for k in range(nz):
239        for j in range(ny):
240            for i in range(nx):
241                facies[i, j, k] = int(a[kk])
242                kk = kk + 1
243
244    return facies
def run_fluvsim(nx=100, ny=100, maxthickness=50, work_folder='/scratch', quiet=True):
247def run_fluvsim(nx=100, ny=100, maxthickness=50, work_folder="/scratch", quiet=True):
248    # set up to work on scratch folder
249    current_dir = os.getcwd()
250    code_dir = os.path.join(os.path.abspath(os.path.dirname(__file__)))
251    code_file = os.path.join(code_dir, "fluvsim.f90")
252    workfolder_code_file = os.path.join(work_folder, "fluvsim.f90")
253    os.system("cp " + code_file + " " + workfolder_code_file)
254    try:
255        workfolder_output = os.path.abspath(os.path.join(work_folder, "output"))
256        os.system("mkdir -p " + workfolder_output + "&>/scratch/outputfile")
257    except OSError:
258        pass
259    os.chdir(work_folder)
260    fortran_code_file = os.path.abspath(os.path.join(work_folder, "fluvsim.f90"))
261    compiled_fortran_code_file = "./fluvsim.o"
262    return_code_2 = os.system(
263        "gfortran " + fortran_code_file + " -o " + compiled_fortran_code_file
264    )
265    if return_code_2 != 0:
266        print("...retrieving fluvsim.o from code repository....")
267        os.system(
268            "cp -p "
269            + os.path.join(code_dir, "fluvsim2.o")
270            + " "
271            + compiled_fortran_code_file
272        )
273
274    # create params file
275    create_fluvsim_params(
276        nx=nx, ny=ny, maxthickness=maxthickness, work_folder=work_folder
277    )
278
279    # run fluvsim
280    os.chdir(work_folder)
281    os.system(
282        compiled_fortran_code_file
283        + "&>"
284        + os.path.join(work_folder, "fluvsim_output.txt")
285    )
286
287    # read fluvsim.out ascii file into numpy array
288    facies = read_fluvsim_output(nx, ny, maxthickness, work_folder=work_folder)
289
290    if quiet:  # TODO save plots to output dir?
291        # plot
292        xsection = 10
293        ysection = 10
294        zsection = 30
295
296        # xsection
297        plt.figure(1, figsize=(15, 9))
298        plt.subplot(2, 1, 1)
299        temp = facies[xsection, :, :]
300        plt.imshow(np.rot90(temp))
301        plt.title("xsection = " + str(xsection))
302
303        # ysection
304        plt.subplot(2, 1, 2)
305        temp = facies[:, ysection, :]
306        plt.imshow(np.rot90(temp))
307        plt.title("ysection = " + str(ysection))
308
309        # zsection
310        plt.figure(2, figsize=(10, 10))
311        temp = facies[:, :, zsection]
312        plt.imshow(temp)
313        plt.title("zsection = " + str(zsection))
314
315        plt.show()
316
317    os.chdir(current_dir)
318
319    return facies