@@ -137,6 +137,49 @@ def rbc3dInterpolation(coarseFields):
137137
138138 return fineFields
139139
140+
141+ def rbc2dInterpolation (coarseFields ):
142+ """
143+ Interpolate a RBC2D field to twice its space resolution
144+
145+ Parameters
146+ ----------
147+ coarseFields : np.3darray
148+ The fields values on the coarse grid, with shape [nV,nX,nZ].
149+ The last dimension (z) uses a chebychev grid,
150+ while x is uniform periodic.
151+
152+ Returns
153+ -------
154+ fineFields : np.4darray
155+ The interpolated fields, with shape [nV,2*nX,2*nZ]
156+ """
157+ coarseFields = np .asarray (coarseFields )
158+ assert coarseFields .ndim == 3 , "requires 3D array"
159+
160+ nV , nX , nZ = coarseFields .shape
161+
162+ # Chebychev grids and interpolation matrix for z
163+ zC = NodesGenerator ("CHEBY-1" , "GAUSS" ).getNodes (nZ )
164+ zF = NodesGenerator ("CHEBY-1" , "GAUSS" ).getNodes (2 * nZ )
165+ Pz = LagrangeApproximation (zC , weightComputation = "STABLE" ).getInterpolationMatrix (zF )
166+
167+ # Fourier interpolation in x
168+ print (" -- computing 1D FFT ..." )
169+ uFFT = np .fft .fftshift (np .fft .fft (coarseFields , axis = 1 ), axes = 1 )
170+ print (" -- padding in Fourier space ..." )
171+ uPadded = np .zeros_like (uFFT , shape = (nV , 2 * nX , nZ ))
172+ uPadded [:, nX // 2 :- nX // 2 ] = uFFT
173+ print (" -- computing 1D IFFT ..." )
174+ uXY = np .fft .ifft (np .fft .ifftshift (uPadded , axes = 1 ), axis = 1 ).real * 2
175+
176+ # Polynomial interpolation in z
177+ print (" -- interpolating in z direction ..." )
178+ fineFields = (Pz @ uXY .reshape (- 1 , nZ ).T ).T .reshape (nV , 2 * nX , 2 * nZ )
179+
180+ return fineFields
181+
182+
140183def decomposeRange (iBeg , iEnd , step , maxSize ):
141184 if iEnd is None :
142185 raise ValueError ("need to provide iEnd for range decomposition" )
@@ -218,7 +261,7 @@ def shape(self):
218261 if self .dim == 2 :
219262 return (4 , self .nX , self .nZ )
220263 elif self .dim == 3 :
221- return (4 , self .nX , self .nY , self .nZ )
264+ return (5 , self .nX , self .nY , self .nZ )
222265
223266 @property
224267 def k (self ):
@@ -442,27 +485,66 @@ def toVTR(self, idxFormat="{:06d}"):
442485 writeToVTR (template .format (i ), u , coords , varNames )
443486
444487
445- def interpolate (self , iFile :int , fileName :str , iField :int = - 1 ):
446- assert self .dim == 3 , "interpolation only possible for 3D RBC fields"
488+ def toPySDC (self , iFile :int , fileName :str , iField :int = - 1 , interpolate = False ):
447489
448490 fields = self .file (iFile )["tasks" ]
449491
450492 velocity = fields ["velocity" ][iField ]
451493 buoyancy = fields ["buoyancy" ][iField ]
452494 pressure = fields ["pressure" ][iField ]
453495
454- uCoarse = np .concat ([velocity , buoyancy [None , ...], pressure [None , ...]])
455- uFine = rbc3dInterpolation (uCoarse )
496+ uAll = np .concat ([velocity , buoyancy [None , ...], pressure [None , ...]])
497+
498+ if self .dim == 3 :
499+ if interpolate :
500+ uAll = rbc3dInterpolation (uAll )
501+ nX , nY , nZ = uAll .shape [1 :]
502+ xCoord = np .linspace (0 , 1 , nX , endpoint = False )
503+ yCoord = np .linspace (0 , 1 , nY , endpoint = False )
504+ zCoord = NodesGenerator ("CHEBY-1" , "GAUSS" ).getNodes (nZ )
505+ header = (5 , [xCoord , yCoord , zCoord ])
506+
507+ elif self .dim == 2 :
508+ if interpolate :
509+ uAll = rbc2dInterpolation (uAll )
510+ nX , nZ = uAll .shape [1 :]
511+ xCoord = np .linspace (0 , 1 , nX , endpoint = False )
512+ zCoord = NodesGenerator ("CHEBY-1" , "GAUSS" ).getNodes (nZ )
513+ header = (4 , [xCoord , zCoord ])
514+ else :
515+ raise NotImplementedError (f"dim={ self .dim } " )
516+
517+ output = Rectilinear (np .float64 , fileName )
518+ output .setHeader (* header )
519+ output .initialize ()
520+ output .addField (0 , uAll )
521+
522+
523+ def interpolateRBCFile (fileName , outputFile , idxField = - 1 ):
524+
525+ inpt :Rectilinear = Rectilinear .fromFile (fileName )
526+ _ , uC = inpt .readField (idxField )
456527
457- nX , nY , nZ = uFine .shape [1 :]
528+ if inpt .dim == 2 :
529+ uF = rbc2dInterpolation (uC )
530+ nX , nZ = uF .shape [1 :]
531+ xCoord = np .linspace (0 , 1 , nX , endpoint = False )
532+ zCoord = NodesGenerator ("CHEBY-1" , "GAUSS" ).getNodes (nZ )
533+ header = (4 , [xCoord , zCoord ])
534+ elif inpt .dim == 3 :
535+ uF = rbc3dInterpolation (uC )
536+ nX , nY , nZ = uF .shape [1 :]
458537 xCoord = np .linspace (0 , 1 , nX , endpoint = False )
459538 yCoord = np .linspace (0 , 1 , nY , endpoint = False )
460539 zCoord = NodesGenerator ("CHEBY-1" , "GAUSS" ).getNodes (nZ )
540+ header = (5 , [xCoord , yCoord , zCoord ])
541+ else :
542+ raise NotImplementedError (f"dim={ inpt .dim } " )
461543
462- output = Rectilinear (np .float64 , fileName )
463- output .setHeader (5 , [ xCoord , yCoord , zCoord ] )
464- output .initialize ()
465- output .addField (0 , uFine )
544+ output = Rectilinear (np .float64 , outputFile )
545+ output .setHeader (* header )
546+ output .initialize ()
547+ output .addField (0 , uF )
466548
467549
468550def checkDNS (sMean :np .ndarray , k :np .ndarray , vRatio :int = 4 , nThrow :int = 1 ):
@@ -495,60 +577,6 @@ def fun(coeffs):
495577
496578 return status , [a , b , c ], x , y , nValues
497579
498- def generateChunkPairs (folder :str , N :int , M :int ,
499- tStep :int = 1 , xStep :int = 1 , zStep :int = 1 ,
500- shuffleSeed = None
501- ):
502- """
503- Function to generate chunk pairs
504-
505- Args:
506- folder (str): path to dedalus hdf5 data
507- N (int): timesteps of dt
508- M (int): size of chunk
509- tStep (int, optional): time slicing. Defaults to 1.
510- xStep (int, optional): x-grid slicing. Defaults to 1.
511- zStep (int, optional): z-grid slicing. Defaults to 1.
512- shuffleSeed (int, optional): seed for random shuffle. Defaults to None.
513-
514- Returns:
515- pairs (list): chunk pairs
516- """
517- out = OutputFiles (folder )
518-
519- pairs = []
520- vxData , vzData , bData , pData = [], [], [], []
521- for iFile in range (0 , out .nFiles ):
522- vxData .append (out .vData (iFile )[:, 0 , ::xStep , ::zStep ])
523- vzData .append (out .vData (iFile )[:, 1 , ::xStep , ::zStep ])
524- bData .append (out .bData (iFile )[:, ::xStep , ::zStep ])
525- pData .append (out .pData (iFile )[:, ::xStep , ::zStep ])
526- # stack all arrays
527- vxData = np .concatenate (vxData )
528- vzData = np .concatenate (vzData )
529- bData = np .concatenate (bData )
530- pData = np .concatenate (pData )
531-
532- assert vxData .shape [0 ] == vzData .shape [0 ]
533- assert vzData .shape [0 ] == pData .shape [0 ]
534- assert vzData .shape [0 ] == bData .shape [0 ]
535- nTimes = vxData .shape [0 ]
536-
537- for i in range (0 , nTimes - M - N + 1 , tStep ):
538- chunk1 = np .stack ((vxData [i :i + M ],vzData [i :i + M ],bData [i :i + M ],pData [i :i + M ]), axis = 1 )
539- chunk2 = np .stack ((vxData [i + N :i + N + M ],vzData [i + N :i + N + M ], bData [i + N :i + N + M ],
540- pData [i + N :i + N + M ]), axis = 1 )
541- # chunks are shape (M, 4, Nx//xStep, Nz//zStep)
542- assert chunk1 .shape == chunk2 .shape
543- pairs .append ((chunk1 , chunk2 ))
544-
545- # shuffle if a seed is given
546- if shuffleSeed is not None :
547- random .seed (shuffleSeed )
548- random .shuffle (pairs )
549-
550- return pairs
551-
552580
553581def contourPlot (field , x , y , time = None ,
554582 title = None , refField = None , refTitle = None , saveFig = False ,
0 commit comments