@@ -376,6 +376,8 @@ def printSpaceDistr(self):
376376 MPI .COMM_WORLD .Barrier ()
377377
378378
379+
380+
379381class OutputFiles ():
380382 """
381383 Utility class used to load and post-process solution
@@ -389,7 +391,7 @@ def __init__(self, folder):
389391 assert len (fileNames ) == 1 , "cannot read fields splitted in several files"
390392 self .fileName = fileNames [0 ]
391393
392- self ._file = None # temporary buffer to store the HDF5 file
394+ self .file = h5py . File ( self . fileName , mode = 'r' )
393395
394396 vData0 = self .file ['tasks' ]['velocity' ]
395397 self .x = np .array (vData0 .dims [2 ]["x" ])
@@ -403,15 +405,9 @@ def __init__(self, folder):
403405 else :
404406 raise NotImplementedError (f"{ dim = } " )
405407
406- @property
407- def file (self ):
408- if self .file is None :
409- self ._file = h5py .File (self .fileName , mode = 'r' )
410- return self ._file
411-
412408 def __del__ (self ):
413409 try :
414- self ._file .close ()
410+ self .file .close ()
415411 except :
416412 pass
417413
@@ -459,15 +455,7 @@ def bData(self):
459455 def pData (self ):
460456 return self .file ['tasks' ]['pressure' ]
461457
462- @property
463- def times (self ):
464- return np .array (self .vData .dims [0 ]["sim_time" ])
465-
466- @property
467- def nFields (self ):
468- return len (self .times )
469-
470- def readFields (self , iField ):
458+ def readFieldAt (self , iField ):
471459 data = self .file ["tasks" ]
472460 fields = [
473461 data ["velocity" ][iField , 0 ],
@@ -481,7 +469,53 @@ def readFields(self, iField):
481469 ]
482470 return np .array (fields )
483471
484- def readField (self , name , iBeg = 0 , iEnd = None , step = 1 , verbose = False ):
472+ @property
473+ def times (self ):
474+ return np .array (self .vData .dims [0 ]["sim_time" ])
475+
476+ @property
477+ def nFields (self ):
478+ return len (self .times )
479+
480+
481+ class BatchRanges ():
482+
483+ def __init__ (self , * args , maxSize = None , start = 0 , step = 1 ):
484+ assert len (args ) < 5
485+ try :
486+ start , stop , step , maxSize = args
487+ except :
488+ try :
489+ start , stop , step = args
490+ except :
491+ try :
492+ start , stop = args
493+ except :
494+ stop , = args
495+ self .range = range (start , stop , step )
496+ self .maxSize = stop if not maxSize else maxSize
497+
498+ @property
499+ def start (self ):
500+ return self .range .start
501+
502+ @property
503+ def stop (self ):
504+ return self .range .stop
505+
506+ @property
507+ def step (self ):
508+ return self .range .step
509+
510+ def __len__ (self ):
511+ return len (self .range )
512+
513+ def __iter__ (self ):
514+ for i in range (self .start , self .stop , self .step * self .maxSize ):
515+ yield range (i , min (i + self .maxSize * self .step , self .stop ), self .step )
516+
517+
518+ def readFields (self , name , start = 0 , stop = None , step = 1 , verbose = False ):
485519 if verbose : print (f"Reading { name } from hdf5 file { self .fileName } " )
486520 if name == "velocity" :
487521 fData = self .vData
@@ -491,60 +525,101 @@ def readField(self, name, iBeg=0, iEnd=None, step=1, verbose=False):
491525 fData = self .pData
492526 else :
493527 raise ValueError (f"cannot read { name } from file" )
494- shape = fData .shape
495- if iEnd is None :
496- iEnd = shape [0 ]
497- rData = range (iBeg , iEnd , step )
498- data = np .empty ((len (rData ), * shape [1 :]), dtype = float )
499- for i , iData in enumerate (rData ):
500- if verbose : print (f" -- field { i + 1 } /{ len (rData )} , idx={ iData } " )
501- data [i ] = fData [iData ]
528+ if stop is None :
529+ stop = self .nFields
530+ if verbose : print (f" -- field[{ start } :{ stop } :{ step } ]" )
531+ data = fData [start :stop :step ]
502532 if verbose : print (" -- done !" )
503533 return data
504534
505535
506- def getMeanProfiles (self , buoyancy = False , bRMS = False , pressure = False ,
507- iBeg = 0 , iEnd = None , step = 1 , verbose = False ):
508- """
509- Args:
510- iFile (int): file index
511- buoyancy (bool, optional): return buoyancy profile. Defaults to False.
512- pressure (bool, optional): return pressure profile. Defaults to False.
513-
514- Returns:
515- profilr (list): mean profiles of velocity, buoyancy and pressure
516- """
517- profile = []
518- axes = 1 if self .dim == 2 else (1 , 2 )
519- velocity = self .readField ("velocity" , iBeg , iEnd , step , verbose )
520-
521- # Horizontal mean velocity amplitude
522- uH = velocity [:, :self .dim - 1 ]
523- meanH = ((uH ** 2 ).sum (axis = 1 )** 0.5 ).mean (axis = axes )
524- profile .append (meanH )
525-
526- # Vertical mean velocity
527- uV = velocity [:, - 1 ]
528- meanV = np .mean (abs (uV ), axis = axes )
529- profile .append (meanV )
530-
531-
532-
533- # uRMS = (ux**2 + uz**2).mean(axis=(0, 1))**0.5
534- # bRMS = ((b - b.mean(axis=(0, 1)))**2).mean(axis=(0, 1))**0.5
535-
536- if bRMS or buoyancy :
537- b = self .readField ("buoyancy" , iBeg , iEnd , step , verbose )
538- if buoyancy :
539- profile .append (np .mean (b , axis = axes ))
540- if bRMS :
541- diff = b - b .mean (axis = axes )[(slice (None ), * [None ]* (self .dim - 1 ), slice (None ))]
542- rms = (diff ** 2 ).mean (axis = axes )** 0.5
543- profile .append (rms )
544- if pressure :
545- p = self .readField ("pressure" , iBeg , iEnd , step , verbose )
546- profile .append (np .mean (p , axis = axes )) # (time_index, Nz)
547- return profile
536+ def getProfiles (self , which = ["uRMS" , "bRMS" ],
537+ start = 0 , stop = None , step = 1 , batchSize = None ,
538+ verbose = False ):
539+ avgAxes = (0 , 1 ) if self .dim == 2 else (0 , 1 , 2 )
540+ formula = {
541+ "u" : "u.sum(axis=1)" ,
542+ "uv" : "u[:, -1]" ,
543+ "uh" : "u[:, :-1].sum(axis=1)" ,
544+ "b" : "b" ,
545+ "p" : "p"
546+ }
547+ if which == "all" :
548+ which = [var + "Mean" for var in formula .keys ()] \
549+ + [var + "RMS" for var in formula .keys ()]
550+ profiles = {name : np .zeros (self .nZ ) for name in which }
551+ if stop is None :
552+ stop = self .nFields
553+
554+ nSamples = 0
555+ def addSamples (current , new , nNew ):
556+ current *= nSamples
557+ new *= nNew
558+ current += new
559+ current /= (nSamples + nNew )
560+
561+ for r in self .BatchRanges (start , stop , step , batchSize ):
562+
563+ bSize = len (r )
564+
565+ # 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 )
573+
574+ # 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 )
590+
591+ # RMS profiles
592+ # -- inplace power 2 first
593+ try : u **= 2
594+ except : pass
595+ try : b **= 2
596+ except : pass
597+ try : p **= 2
598+ except : pass
599+
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 )
609+ if "bRMS" in which :
610+ bRMS = b .mean (axis = avgAxes )
611+ addSamples (profiles ["bRMS" ], bRMS , bSize )
612+ if "pRMS" in which :
613+ pRMS = p .mean (axis = avgAxes )
614+ addSamples (profiles ["pRMS" ], pRMS , bSize )
615+
616+ nSamples += bSize
617+
618+ for name , val in profiles .items ():
619+ if "RMS" in name :
620+ val **= 0.5
621+ profiles ["nSamples" ] = nSamples
622+ return profiles
548623
549624
550625 def getLayersQuantities (self , iBeg = 0 , iEnd = None , step = 1 , verbose = False ):
@@ -668,7 +743,7 @@ def computeMeanSpectrum(uValues, xGrid=None, zGrid=None, verbose=False):
668743 return energy_spectrum
669744
670745
671- def getMeanSpectrum (self , iFile :int , iBeg = 0 , iEnd = None , step = 1 , verbose = False , batchSize = 5 ):
746+ def getMeanSpectrum (self , iFile :int , iBeg = 0 , iEnd = None , step = 1 , batchSize = 5 , verbose = False ):
672747 """
673748 Mean spectrum from a given output file
674749
@@ -700,7 +775,7 @@ def getMeanSpectrum(self, iFile:int, iBeg=0, iEnd=None, step=1, verbose=False, b
700775 if verbose :
701776 print (f" -- computing for fields in range ({ iBegSub } ,{ iEndSub } ,{ stepSub } )" )
702777 velocity = self .readField (iFile , "velocity" , iBegSub , iEndSub , stepSub , verbose )
703- spectra += computeMeanSpectrum (velocity , verbose = verbose , xGrid = self .x , zGrid = self .z )
778+ spectra += self . computeMeanSpectrum (velocity , verbose = verbose , xGrid = self .x , zGrid = self .z )
704779 return np .concatenate (spectra )
705780
706781
@@ -763,19 +838,32 @@ def toVTR(self, idxFormat="{:06d}"):
763838
764839
765840if __name__ == "__main__" :
766- import scipy .optimize as sco
767-
768- from pySDC .playgrounds .dedalus .problems .utils import OutputFiles
769- # from qmat.lagrange import LagrangeApproximation
770841 import matplotlib .pyplot as plt
771842
772843 dirName = "run_3D_A4_R1_M1"
773844
774845 problem = RBCProblem3D .runSimulation (
775- dirName , 100 , 1e-2 / 2 , logEvery = 20 , dtWrite = 1.0 ,
846+ dirName , 100 , 1e-2 / 4 , logEvery = 20 , dtWrite = 1.0 ,
776847 aspectRatio = 4 , resFactor = 1 , meshRatio = 1 )
777848
778- # output = OutputFiles(dirName)
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" )
865+
866+
779867 # approx = LagrangeApproximation(output.z)
780868
781869 # nThrow = 20
0 commit comments