3838
3939# package modules
4040from aeolis .utils import *
41-
41+ from aeolis . separation import compute_separation
4242
4343# initialize logger
4444logger = logging .getLogger (__name__ )
@@ -142,10 +142,8 @@ def __init__(self, x, y, z, dx, dy, L, l, z0,
142142 self .z0 = z0
143143
144144
145- def __call__ (self , x , y , z , taux , tauy , u0 , udir ,
146- process_separation , c , mu_b ,
147- taus0 , taun0 , sep_filter_iterations , zsep_y_filter ,
148- plot = False ):
145+ def __call__ (self , p , x , y , z , u0 , udir ,
146+ taux , tauy , taus0 , taun0 , plot = False ):
149147
150148 '''Compute wind shear for given wind speed and direction
151149
@@ -222,10 +220,9 @@ def __call__(self, x, y, z, taux, tauy, u0, udir,
222220 # rotate to horizontal computational grid and add to tau0
223221 # =====================================================================
224222
225- # Compute separation bubble
226- if process_separation :
227- zsep = self .separation (c , mu_b , sep_filter_iterations , zsep_y_filter )
228- z_origin = gc ['z' ].copy ()
223+ if p ['process_separation' ]:
224+ z_origin = gc ['z' ][:].copy ()
225+ zsep = compute_separation (p , gc ['z' ], gc ['dx' ])
229226 gc ['z' ] = np .maximum (gc ['z' ], zsep )
230227
231228 # Compute wind shear stresses on computational grid
@@ -238,7 +235,7 @@ def __call__(self, x, y, z, taux, tauy, u0, udir,
238235 gc ['taux' ] = np .maximum (gc ['taux' ], 0. )
239236
240237 # Compute the influence of the separation on the shear stress
241- if process_separation :
238+ if p [ ' process_separation' ] :
242239 gc ['hsep' ] = gc ['z' ] - z_origin
243240 self .separation_shear (gc ['hsep' ])
244241
@@ -264,7 +261,7 @@ def __call__(self, x, y, z, taux, tauy, u0, udir,
264261 gi ['taux' ] = self .interpolate (gc ['x' ], gc ['y' ], gc ['taux' ], gi ['x' ], gi ['y' ], taus0 )
265262 gi ['tauy' ] = self .interpolate (gc ['x' ], gc ['y' ], gc ['tauy' ], gi ['x' ], gi ['y' ], taun0 )
266263
267- if process_separation :
264+ if p [ ' process_separation' ] :
268265 gi ['hsep' ] = self .interpolate (gc ['x' ], gc ['y' ], gc ['hsep' ], gi ['x' ], gi ['y' ], 0. )
269266
270267 # Final plots and lay-out
@@ -368,158 +365,6 @@ def set_computational_grid(self, udir):
368365
369366 return self
370367
371-
372-
373- def separation (self , c , mu_b , sep_filter_iterations , zsep_y_filter ):
374-
375- # Initialize grid and bed dimensions
376- gc = self .cgrid
377-
378- x = gc ['x' ]
379- y = gc ['y' ]
380- z = gc ['z' ]
381-
382- nx = len (gc ['z' ][1 ])
383- ny = len (gc ['z' ][0 ])
384- dx = gc ['dx' ]
385- dy = gc ['dy' ]
386-
387- # Initialize arrays
388-
389- dzx = np .zeros (gc ['z' ].shape )
390-
391- dzdx0 = np .zeros (gc ['z' ].shape )
392- dzdx1 = np .zeros (gc ['z' ].shape )
393-
394- stall = np .zeros (gc ['z' ].shape )
395- bubble = np .zeros (gc ['z' ].shape )
396-
397- k = np .array (range (0 , nx ))
398-
399- zsep = np .zeros (z .shape ) # total separation bubble
400- zsep_new = np .zeros (z .shape ) # first-oder separation bubble surface
401-
402- zfft = np .zeros ((ny ,nx ), dtype = complex )
403-
404- # Compute bed slope angle in x-dir
405- dzx [:,:- 2 ] = np .rad2deg (np .arctan ((z [:,2 :]- z [:,:- 2 ])/ (2. * dx )))
406- dzx [:,- 2 ] = dzx [:,- 3 ]
407- dzx [:,- 1 ] = dzx [:,- 2 ]
408-
409- # Determine location of separation bubbles
410- '''Separation bubble exist if bed slope angle (lee side)
411- is larger than max angle that wind stream lines can
412- follow behind an obstacle (mu_b = ..)'''
413-
414- stall += np .logical_and (abs (dzx ) > mu_b , dzx < 0. )
415-
416- stall [:,1 :- 1 ] += np .logical_and (stall [:,1 :- 1 ]== 0 , stall [:,:- 2 ]> 0. , stall [:,2 :]> 0. )
417-
418- # Define separation bubble
419- bubble [:,:- 1 ] = (stall [:,:- 1 ] == 0. ) * (stall [:,1 :] > 0. )
420-
421- # Better solution for cleaner separation bubble, but no working Barchan dune (yet)
422- p = 1
423- bubble [:,p :] = bubble [:,:- p ]
424- bubble [:,- p :] = 0
425-
426- bubble = bubble .astype (int )
427-
428- # Count separation bubbles
429- n = np .sum (bubble )
430- bubble_n = np .asarray (np .where (bubble == True )).T
431-
432-
433- # Walk through all separation bubbles and determine polynoms
434- j = 9999
435- for k in range (0 , n ):
436-
437- i = bubble_n [k ,1 ]
438- j = bubble_n [k ,0 ]
439-
440- #Bart: check for negative wind direction
441- if np .sum (gc ['taux' ]) >= 0 :
442- idir = 1
443- else :
444- idir = - 1
445-
446- ix_neg = (dzx [j , i + idir * 5 :] >= 0 ) # i + 5??
447-
448- if np .sum (ix_neg ) == 0 :
449- zbrink = z [j ,i ] # z level of brink at z(x0)
450- else :
451- zbrink = z [j ,i ] - z [j ,i + idir * 5 + idir * np .where (ix_neg )[0 ][0 ]]
452-
453- # Better solution and cleaner separation bubble, but no working Barchan dune (yet)
454- dzdx0 = (z [j ,i ] - z [j ,i - 3 ]) / (3. * dx )
455-
456- a = dzdx0 / c
457- ls = np .minimum (np .maximum ((3. * zbrink / (2. * c ) * (1. + a / 4. + a ** 2 / 8. )), 0.1 ), 200. )
458-
459- a2 = - 3 * zbrink / ls ** 2 - 2 * dzdx0 / ls
460- a3 = 2 * zbrink / ls ** 3 + dzdx0 / ls ** 2
461-
462- i_max = min (i + int (ls / dx )+ 1 ,int (nx - 1 ))
463-
464- if idir == 1 :
465- xs = x [j ,i :i_max ] - x [j ,i ]
466- else :
467- xs = - (x [j ,i :i_max ] - x [j ,i ])
468-
469- zsep_new [j ,i :i_max ] = (a3 * xs ** 3 + a2 * xs ** 2 + dzdx0 * xs + z [j ,i ])
470-
471- # Choose maximum of bedlevel, previous zseps and new zseps
472- zsep [j ,:] = np .maximum .reduce ([z [j ,:], zsep [j ,:], zsep_new [j ,:]])
473-
474- for filter_iter in range (sep_filter_iterations ):
475-
476- zsep_new = np .zeros (zsep .shape )
477-
478- Cut = 1.5
479- dk = 2.0 * np .pi / (np .max (x ))
480- zfft [j ,:] = np .fft .fft (zsep [j ,:])
481- zfft [j ,:] *= np .exp (- (dk * k * dx )** 2 / (2. * Cut ** 2 ))
482- zsep_fft = np .real (np .fft .ifft (zfft [j ,:]))
483-
484- if np .sum (ix_neg ) == 0 :
485- zbrink = zsep_fft [i ]
486- else :
487- zbrink = zsep_fft [i ] - zsep_fft [i + idir * 5 + idir * np .where (ix_neg )[0 ][0 ]]
488-
489- # First order polynom
490- dzdx1 = (zsep_fft [i ] - zsep_fft [i - 3 ])/ (3. * dx )
491-
492- a = dzdx1 / c
493-
494- ls = np .minimum (np .maximum ((3. * zbrink / (2. * c ) * (1. + a / 4. + a ** 2 / 8. )), 0.1 ), 200. )
495-
496-
497- a2 = - 3 * zbrink / ls ** 2 - 2 * dzdx1 / ls
498- a3 = 2 * zbrink / ls ** 3 + dzdx1 / ls ** 2
499-
500- i_max1 = min (i + idir * int (ls / dx ),int (nx - 1 ))
501-
502- if idir == 1 :
503- xs1 = x [j ,i :i_max1 ] - x [j ,i ]
504- else :
505- xs1 = - (x [j ,i :i_max1 ] - x [j ,i ])
506-
507- zsep_new [j , i :i_max1 ] = (a3 * xs1 ** 3 + a2 * xs1 ** 2 + dzdx1 * xs1 + zbrink )
508-
509- # Pick the maximum seperation bubble hieght at all locations
510- zsep [j ,:] = np .maximum .reduce ([z [j ,:], zsep [j ,:], zsep_new [j ,:]])
511-
512-
513- # Smooth surface of separation bubbles over y direction
514- if zsep_y_filter :
515- zsep = ndimage .gaussian_filter1d (zsep , sigma = 0.2 , axis = 0 )
516-
517- #Correct for any seperation bubbles that are below the bed surface following smoothing
518- ilow = zsep < z
519- zsep [ilow ] = z [ilow ]
520-
521- return zsep
522-
523368
524369 def compute_shear (self , u0 , nfilter = (1. , 2. )):
525370 '''Compute wind shear perturbation for given free-flow wind
0 commit comments