@@ -330,8 +330,10 @@ def buildGrid(self, aspectRatio, meshRatio, sComm, mpiBlocks):
330330 baseSize = 32
331331
332332 Lx , Ly , Lz = int (aspectRatio ), int (aspectRatio ), 1
333- Nx = Ny = int (baseSize * aspectRatio * meshRatio * self .resFactor )
334- Nz = int (baseSize * self .resFactor )
333+ unitSize = baseSize * self .resFactor
334+
335+ Nx = Ny = int (aspectRatio * meshRatio * unitSize )
336+ Nz = int (unitSize )
335337 dealias = 3 / 2
336338 dtype = np .float64
337339
@@ -383,6 +385,8 @@ class OutputFiles():
383385 Utility class used to load and post-process solution
384386 writen with Dedalus HDF5 IO.
385387 """
388+ VERBOSE = False
389+
386390 def __init__ (self , folder ):
387391 self .folder = folder
388392 fileNames = glob .glob (f"{ self .folder } /*.h5" )
@@ -515,8 +519,8 @@ def __iter__(self):
515519 yield range (i , min (i + self .maxSize * self .step , self .stop ), self .step )
516520
517521
518- def readFields (self , name , start = 0 , stop = None , step = 1 , verbose = False ):
519- if verbose : print (f"Reading { name } from hdf5 file { self .fileName } " )
522+ def readFields (self , name , start = 0 , stop = None , step = 1 ):
523+ if self . VERBOSE : print (f"Reading { name } from hdf5 file { self .fileName } " )
520524 if name == "velocity" :
521525 fData = self .vData
522526 elif name == "buoyancy" :
@@ -527,29 +531,35 @@ def readFields(self, name, start=0, stop=None, step=1, verbose=False):
527531 raise ValueError (f"cannot read { name } from file" )
528532 if stop is None :
529533 stop = self .nFields
530- if verbose : print (f" -- field[{ start } :{ stop } :{ step } ]" )
534+ if self . VERBOSE : print (f" -- field[{ start } :{ stop } :{ step } ]" )
531535 data = fData [start :stop :step ]
532- if verbose : print (" -- done !" )
536+ if self . VERBOSE : print (" -- done !" )
533537 return data
534538
535539
536540 def getProfiles (self , which = ["uRMS" , "bRMS" ],
537- start = 0 , stop = None , step = 1 , batchSize = None ,
538- verbose = False ):
541+ start = 0 , stop = None , step = 1 , batchSize = None ):
542+ if stop is None :
543+ stop = self .nFields
539544 avgAxes = (0 , 1 ) if self .dim == 2 else (0 , 1 , 2 )
540545 formula = {
541546 "u" : "u.sum(axis=1)" ,
542547 "uv" : "u[:, -1]" ,
543548 "uh" : "u[:, :-1].sum(axis=1)" ,
544549 "b" : "b" ,
545- "p" : "p"
550+ "p" : "p" ,
546551 }
552+
547553 if which == "all" :
548554 which = [var + "Mean" for var in formula .keys ()] \
549555 + [var + "RMS" for var in formula .keys ()]
556+ else :
557+ which = list (which )
558+ if "bRMS" in which and "bMean" not in which :
559+ which .append ("bMean" )
560+ if "pRMS" in which and "pMean" not in which :
561+ which .append ("pMean" )
550562 profiles = {name : np .zeros (self .nZ ) for name in which }
551- if stop is None :
552- stop = self .nFields
553563
554564 nSamples = 0
555565 def addSamples (current , new , nNew ):
@@ -558,93 +568,111 @@ def addSamples(current, new, nNew):
558568 current += new
559569 current /= (nSamples + nNew )
560570
571+ # Mean profiles
561572 for r in self .BatchRanges (start , stop , step , batchSize ):
562573
563574 bSize = len (r )
564575
565576 # Read required data
566- if set (["uRMS " , "uvRMS " , "uhRMS " ,
567- "uMean " , "uvMean " , "uhMean " ]).intersection (which ):
568- u = self .readFields ("velocity" , r .start , r .stop , r .step , verbose )
569- if set (["bRMS" , " bMean" ]).intersection (which ):
570- b = self .readFields ("buoyancy" , r .start , r .stop , r .step , verbose )
571- if set (["pRMS" , " pMean" ]).intersection (which ):
572- p = self .readFields ("pressure" , r .start , r .stop , r .step , verbose )
577+ if set (["uMean " , "uvMean " , "uhMean " ,
578+ "uRMS " , "uvRMS " , "uhRMS " ]).intersection (which ):
579+ u = self .readFields ("velocity" , r .start , r .stop , r .step )
580+ if set (["bMean" ]).intersection (which ):
581+ b = self .readFields ("buoyancy" , r .start , r .stop , r .step )
582+ if set (["pMean" ]).intersection (which ):
583+ p = self .readFields ("pressure" , r .start , r .stop , r .step )
573584
574585 # Mean profiles
575- if "uMean" in which :
576- uMean = u .sum (axis = 1 ).mean (axis = avgAxes )
577- addSamples (profiles ["uMean" ], uMean , bSize )
578- if "uvMean" in which :
579- uvMean = u [:, - 1 ].mean (axis = avgAxes )
580- addSamples (profiles ["uvMean" ], uvMean , bSize )
581- if "uhMean" in which :
582- uhMean = u [:, :- 1 ].sum (axis = 1 ).mean (axis = avgAxes )
583- addSamples (profiles ["uhMean" ], uhMean , bSize )
584- if "bMean" in which :
585- bMean = b .mean (axis = avgAxes )
586- addSamples (profiles ["bMean" ], bMean , bSize )
587- if "pMean" in which :
588- pMean = p .mean (axis = avgAxes )
589- addSamples (profiles ["pMean" ], pMean , bSize )
586+ for name in which :
587+ if "Mean" in name :
588+ var = eval (formula [name [:- 4 ]]).mean (axis = avgAxes )
589+ addSamples (profiles [name ], var , bSize )
590590
591- # RMS profiles
592- # -- inplace power 2 first
593591 try : u **= 2
594592 except : pass
595- try : b **= 2
596- except : pass
597- try : p **= 2
598- except : pass
599593
600- if "uRMS" in which :
601- uRMS = u .sum (axis = 1 ).mean (axis = avgAxes )
602- addSamples (profiles ["uRMS" ], uRMS , bSize )
603- if "uvRMS" in which :
604- uvRMS = u [:, - 1 ].mean (axis = avgAxes )
605- addSamples (profiles ["uvRMS" ], uvRMS , bSize )
606- if "uhRMS" in which :
607- uhRMS = u [:, :- 1 ].sum (axis = 1 ).mean (axis = avgAxes )
608- addSamples (profiles ["uhRMS" ], uhRMS , bSize )
594+ # RMS profiles
595+ for name in which :
596+ if "RMS" in name and name not in ["bRMS" , "pRMS" ]:
597+ var = eval (formula [name [:- 3 ]]).mean (axis = avgAxes )
598+ addSamples (profiles [name ], var , bSize )
599+
600+ nSamples += bSize
601+
602+ # bRMS and pRMS require precomputed mean
603+ nSamples = 0
604+ for r in self .BatchRanges (start , stop , step , batchSize ):
605+
606+ bSize = len (r )
607+
609608 if "bRMS" in which :
609+ b = self .readFields ("buoyancy" , r .start , r .stop , r .step )
610+ b -= profiles ["bMean" ]
611+ b **= 2
610612 bRMS = b .mean (axis = avgAxes )
611613 addSamples (profiles ["bRMS" ], bRMS , bSize )
614+
612615 if "pRMS" in which :
616+ p = self .readFields ("pressure" , r .start , r .stop , r .step )
617+ p -= profiles ["pMean" ]
618+ p **= 2
613619 pRMS = p .mean (axis = avgAxes )
614620 addSamples (profiles ["pRMS" ], pRMS , bSize )
615621
616622 nSamples += bSize
617623
624+ # Square root after time averaging for RMS
618625 for name , val in profiles .items ():
619626 if "RMS" in name :
620627 val **= 0.5
628+
621629 profiles ["nSamples" ] = nSamples
622630 return profiles
623631
632+ def getTimeSeries (self , which = ["ke" ], batchSize = None ):
633+
634+ series = {name : [] for name in which }
635+ avgAxes = 1 if self .dim == 2 else (1 , 2 )
636+
637+ Iz = LagrangeApproximation (self .z ).getIntegrationMatrix ([(0 , 1 )])
638+
639+ for r in self .BatchRanges (self .nFields , maxSize = batchSize ):
640+
641+ if "ke" in which :
642+ u = self .readFields ("velocity" , r .start , r .stop , r .step )
643+ u **= 2
644+ ke = Iz @ u .sum (axis = 1 ).mean (axis = avgAxes )[..., None ]
645+ series ["ke" ].append (ke .ravel ())
646+
647+ for key , val in series .items ():
648+ series [key ] = np .array (val ).ravel ()
624649
625- def getLayersQuantities (self , iBeg = 0 , iEnd = None , step = 1 , verbose = False ):
626- uMean , _ , bRMS = self .getMeanProfiles (
627- bRMS = True , iBeg = iBeg , iEnd = iEnd , step = step , verbose = verbose )
628- uMean = uMean .mean (axis = 0 )
629- bRMS = bRMS .mean (axis = 0 )
650+ return series
630651
631- z = self .z
632- nFine = int (1e4 )
633- zFine = np .linspace (0 , 1 , num = nFine )
634- P = LagrangeApproximation (z ).getInterpolationMatrix (zFine )
635652
636- uMeanFine = P @ uMean
637- bRMSFine = P @ bRMS
653+ def getBoundaryLayers (self ,
654+ which = ["uRMS" , "bRMS" ], profiles = None ,
655+ start = 0 , stop = None , step = 1 , batchSize = None ):
638656
639- approx = LagrangeApproximation (z )
657+ if which == "all" :
658+ which = ["uRMS" , "bRMS" , "uhRMS" ]
659+ else :
660+ which = list (which )
661+ deltas = {name : None for name in which }
662+
663+ if profiles is None :
664+ profiles = {}
665+ missing = set (which ).difference (profiles .keys ())
666+ profiles .update (self .getProfiles (missing , start , stop , step , batchSize ))
640667
641- xOptU = sco .minimize_scalar (lambda z : - approx (z , fValues = uMeanFine ), bounds = [0 , 0.5 ])
642- xOptB = sco .minimize_scalar (lambda z : - approx (z , fValues = bRMS ), bounds = [0 , 0.5 ])
668+ approx = LagrangeApproximation (self .z )
643669
644- deltaU = xOptU .x
645- deltaT = xOptB .x
670+ for name in which :
671+ values = profiles [name ]
672+ opt = sco .minimize_scalar (lambda z : - approx (z , fValues = values ), bounds = [0 , 0.5 ])
673+ deltas [name ] = opt .x
646674
647- return zFine , uMeanFine , bRMSFine , deltaU , deltaT
675+ return deltas
648676
649677
650678 @staticmethod
@@ -832,36 +860,54 @@ def toVTR(self, idxFormat="{:06d}"):
832860 template = f"{ baseName } _{ idxFormat } "
833861 coords = [self .x , self .y , self .z ]
834862 varNames = ["velocity_x" , "velocity_y" , "velocity_z" , "buoyancy" , "pressure" ]
835- for i in range (np . cumsum ( self .nFields )[ 0 ] ):
836- u = self .fields (i )
863+ for i in range (self .nFields ):
864+ u = self .readFieldAt (i )
837865 writeToVTR (template .format (i ), u , coords , varNames )
838866
839867
840868if __name__ == "__main__" :
841869 import matplotlib .pyplot as plt
842870
843- dirName = "run_3D_A4_R1_M1"
871+ aspectRatio = 4 # Lx = Ly = A*Lz
872+ meshRatio = 0.5 # Nx/Lx = Ny/Ly = M*Nz/Lz
873+ resFactor = 1 # Nz = R*32
874+
875+ dirName = f"run_3D_A{ aspectRatio } _M{ meshRatio } _R{ resFactor } "
844876
845877 problem = RBCProblem3D .runSimulation (
846878 dirName , 100 , 1e-2 / 4 , logEvery = 20 , dtWrite = 1.0 ,
847- aspectRatio = 4 , resFactor = 1 , meshRatio = 1 )
848-
849- output = OutputFiles (dirName )
850- profiles = output .getProfiles (which = "all" , verbose = True , batchSize = 25 )
851-
852- for name , p in profiles .items ():
853- if "Mean" in name :
854- plt .figure ("Mean profiles" )
855- plt .plot (p , output .z , label = name )
856- if "RMS" in name :
857- plt .figure ("RMS profiles" )
858- plt .plot (p , output .z , label = name )
859-
860- for pType in ["Mean" , "RMS" ]:
861- plt .figure (f"{ pType } profiles" )
862- plt .legend ()
863- plt .xlabel ("profile" )
864- plt .ylabel ("z coord" )
879+ aspectRatio = 4 , meshRatio = 1 , resFactor = 1 )
880+
881+ # OutputFiles.VERBOSE = True
882+ # output = OutputFiles(dirName)
883+
884+ # series = output.getTimeSeries()
885+
886+ # plt.figure("series")
887+ # plt.plot(output.times, series["ke"], label="ke")
888+ # plt.legend()
889+
890+ # profiles = output.getProfiles(which="all", batchSize=None, start=40)
891+
892+ # deltas = output.getBoundaryLayers(which="all", profiles=profiles)
893+
894+ # for name, p in profiles.items():
895+ # if "Mean" in name:
896+ # plt.figure("Mean profiles")
897+ # plt.plot(p, output.z, label=name)
898+ # if name in deltas:
899+ # plt.hlines(deltas[name], p.min(), p.max(), linestyles="--", colors="black")
900+ # if "RMS" in name:
901+ # plt.figure("RMS profiles")
902+ # plt.plot(p, output.z, label=name)
903+ # if name in deltas:
904+ # plt.hlines(deltas[name], p.min(), p.max(), linestyles="--", colors="black")
905+
906+ # for pType in ["Mean", "RMS"]:
907+ # plt.figure(f"{pType} profiles")
908+ # plt.legend()
909+ # plt.xlabel("profile")
910+ # plt.ylabel("z coord")
865911
866912
867913 # approx = LagrangeApproximation(output.z)
0 commit comments