Changeset 9018


Ignore:
Timestamp:
Nov 8, 2013, 8:45:50 PM (11 years ago)
Author:
steve
Message:

Added in the possibility to store centroid values into sww files

Location:
trunk/anuga_core/source/anuga
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/anuga_core/source/anuga/file/sww.py

    r8810 r9018  
    7171        self.recursion = recursion
    7272        self.mode = mode
     73       
    7374        if hasattr(domain, 'max_size'):
    7475            self.max_size = domain.max_size # File size max is 2Gig
    7576        else:
    7677            self.max_size = max_size
     78           
     79        if hasattr(domain, 'store_centroids'):
     80            self.store_centroids = domain.store_centroids
     81        else:
     82            self.store_centroids = False
     83           
    7784        if hasattr(domain, 'minimum_storable_height'):
    7885            self.minimum_storable_height = domain.minimum_storable_height
     
    105112                          'suitable for plotting'
    106113                         
    107             self.writer = Write_sww(static_quantities, dynamic_quantities)
     114            self.writer = Write_sww(static_quantities, dynamic_quantities, store_centroids=self.store_centroids)
    108115            self.writer.store_header(fid,
    109116                                     domain.starttime,
     
    194201        # Get names of static quantities
    195202        static_quantities = {}
     203        static_quantities_centroid = {}
    196204        for name in self.writer.static_quantities:
    197205            Q = domain.quantities[name]
     
    199207                                       precision=self.precision)
    200208            static_quantities[name] = A
     209           
     210            if self.store_centroids:
     211                static_quantities_centroid[name] = Q.centroid_values
    201212       
    202213        # Store static quantities       
    203214        self.writer.store_static_quantities(fid, **static_quantities)
    204                                            
     215       
     216        if  self.store_centroids:
     217            self.writer.store_static_quantities_centroid(fid, **static_quantities_centroid)
     218                                       
    205219        fid.close()
    206220
     
    319333            # Now store dynamic quantities
    320334            dynamic_quantities = {}
     335            dynamic_quantities_centroid = {}
     336           
    321337            for name in self.writer.dynamic_quantities:
    322338                #netcdf_array = fid.variables[name]
     
    341357                dynamic_quantities[name] = A
    342358               
     359                if self.store_centroids:
     360                    dynamic_quantities_centroid[name] = Q.centroid_values
     361               
    343362                                       
    344363            # Store dynamic quantities
    345             self.writer.store_quantities(fid,
     364            slice_index = self.writer.store_quantities(fid,
    346365                                         time=self.domain.time,
    347366                                         sww_precision=self.precision,
    348367                                         **dynamic_quantities)
     368           
     369            # Store dynamic quantities
     370            if self.store_centroids:
     371                self.writer.store_quantities_centroid(fid,
     372                                                      slice_index= slice_index,
     373                                                      sww_precision=self.precision,
     374                                                      **dynamic_quantities_centroid)           
    349375
    350376
     
    430456       
    431457        for q in filter(lambda n:n != 'x' and n != 'y' and n != 'time' and n != 'volumes' and \
    432                         '_range' not in n, \
     458                        '_range' not in n and '_c' not in n , \
    433459                        fin.variables.keys()):
     460            #print q
    434461            if len(fin.variables[q].shape) == 1: # Not a time-varying quantity
    435462                self.quantities[q] = num.ravel(num.array(fin.variables[q], num.float)).reshape(M,3)
     
    466493    """
    467494
    468     def __init__(self, static_quantities, dynamic_quantities):
     495    def __init__(self, static_quantities, dynamic_quantities, store_centroids=False):
    469496        """Initialise Write_sww with two list af quantity names:
    470497       
     
    479506        self.static_quantities = static_quantities   
    480507        self.dynamic_quantities = dynamic_quantities
     508        self.store_centroids = store_centroids
    481509
    482510
     
    577605            outfile.createVariable(q + Write_sww.RANGE, sww_precision,
    578606                                   ('numbers_in_range',))
     607           
     608            if self.store_centroids:
     609                outfile.createVariable(q + '_c', sww_precision,
     610                                   ('number_of_volumes',))
    579611                                   
    580612            # Initialise ranges with small and large sentinels.
     
    702734
    703735
     736    def write_dynamic_quantities(self, outfile, quantities,
     737                    times, precis = netcdf_float32, verbose = False):   
     738        """
     739            Write out given quantities to file.
     740        """
     741       
     742
     743        for q in quantities:
     744            outfile.createVariable(q, precis, ('number_of_timesteps',
     745                                                      'number_of_points'))
     746            outfile.createVariable(q + Write_sts.RANGE, precis,
     747                                   ('numbers_in_range',))
     748           
     749            if self.store_centroids:
     750                outfile.createVariable(q + '_c', precis,
     751                                   ('number_of_timesteps','number_of_volumes'))
     752
     753            # Initialise ranges with small and large sentinels.
     754            # If this was in pure Python we could have used None sensibly
     755            outfile.variables[q+Write_sts.RANGE][0] = max_float  # Min
     756            outfile.variables[q+Write_sts.RANGE][1] = -max_float # Max
     757
     758        # Doing sts_precision instead of Float gives cast errors.
     759        outfile.createVariable('time', netcdf_float, ('number_of_timesteps',))
     760
     761        if isinstance(times, (list, num.ndarray)):
     762            outfile.variables['time'][:] = times    # Store time relative
     763
     764        if verbose:
     765            log.critical('------------------------------------------------')
     766            log.critical('Statistics:')
     767            log.critical('    t in [%f, %f], len(t) == %d'
     768                         % (num.min(times), num.max(times), len(times.flat)))
    704769
    705770    def store_parallel_data(self,
     
    795860
    796861                   
    797        
     862
     863    def store_static_quantities_centroid(self,
     864                                            outfile,
     865                                            sww_precision=num.float32,
     866                                            verbose=False,
     867                                            **quant):
     868        """
     869        Write the static centroid quantity info.
     870
     871        **quant is extra keyword arguments passed in. These must be
     872          the numpy arrays to be stored in the sww file at each timestep.
     873
     874        The argument sww_precision allows for storing as either
     875        * single precision (default): num.float32
     876        * double precision: num.float64 or num.float
     877
     878        Precondition:
     879            store_triangulation and
     880            store_header have been called.
     881        """
     882
     883        # The dictionary quant must contain numpy arrays for each name.
     884        # These will typically be quantities from Domain such as friction
     885        #
     886        # Arrays not listed in static_quantitiues will be ignored, silently.
     887        #
     888        # This method will also write the ranges for each quantity,
     889        # e.g. stage_range, xmomentum_range and ymomentum_range
     890        for q in self.static_quantities:
     891            if not quant.has_key(q):
     892                msg = 'Values for quantity %s was not specified in ' % q
     893                msg += 'store_quantities so they cannot be stored.'
     894                raise NewQuantity, msg
     895            else:
     896                q_values = ensure_numeric(quant[q])
     897               
     898                x = q_values.astype(sww_precision)
     899                outfile.variables[q+'_c'][:] = x
     900       
     901
     902                   
     903       
    798904
    799905    def store_quantities(self,
     
    862968                if q_values_max > q_range[1]:
    863969                    outfile.variables[q + Write_sww.RANGE][1] = q_values_max
    864 
     970                   
     971        return slice_index
     972                   
     973                   
     974
     975    def store_quantities_centroid(self,
     976                                  outfile,
     977                                  sww_precision=num.float32,
     978                                  slice_index=None,
     979                                  verbose=False,
     980                                  **quant):
     981        """
     982        Write the quantity centroid info at each timestep.
     983
     984        **quant is extra keyword arguments passed in. These must be
     985          the numpy arrays to be stored in the sww file at each timestep.
     986
     987        if the time array is already been built, use the slice_index
     988        to specify the index.
     989
     990        Otherwise, use time to increase the time dimension
     991
     992        Maybe make this general, but the viewer assumes these quantities,
     993        so maybe we don't want it general - unless the viewer is general
     994       
     995        The argument sww_precision allows for storing as either
     996        * single precision (default): num.float32
     997        * double precision: num.float64 or num.float
     998
     999        Precondition:
     1000            store_triangulation and
     1001            store_header have been called.
     1002        """
     1003
     1004        assert slice_index is not None, 'slice_index should be set in store_quantities'
     1005         
     1006
     1007        # Write the named dynamic quantities
     1008        # The dictionary quant must contain numpy arrays for each name.
     1009        # These will typically be the conserved quantities from Domain
     1010        # (Typically stage,  xmomentum, ymomentum).
     1011        #
     1012        # Arrays not listed in dynamic_quantitiues will be ignored, silently.
     1013        #
     1014        # This method will also write the ranges for each quantity,
     1015        # e.g. stage_range, xmomentum_range and ymomentum_range
     1016        for q in self.dynamic_quantities:
     1017            if not quant.has_key(q):
     1018                msg = 'Values for quantity %s was not specified in ' % q
     1019                msg += 'store_quantities so they cannot be stored.'
     1020                raise NewQuantity, msg
     1021            else:
     1022                q_values = ensure_numeric(quant[q])
     1023               
     1024                q_retyped = q_values.astype(sww_precision)
     1025                outfile.variables[q+'_c'][slice_index] = q_retyped
    8651026
    8661027
     
    9471108    # or              concatenate((x[:,num.newaxis], x[:,num.newaxis]), axis=1)
    9481109
    949     conserved_quantities = []
     1110    dynamic_quantities = []
    9501111    interpolated_quantities = {}
    951     other_quantities = []
     1112    static_quantities = []
    9521113
    9531114    # get geo_reference
     
    9621123        dimensions = fid.variables[quantity].dimensions
    9631124        if 'number_of_timesteps' in dimensions:
    964             conserved_quantities.append(quantity)
     1125            dynamic_quantities.append(quantity)
    9651126            interpolated_quantities[quantity] = \
    9661127                  interpolated_quantity(fid.variables[quantity][:], time_interp)
    9671128        else:
    968             other_quantities.append(quantity)
    969 
    970     other_quantities.remove('x')
    971     other_quantities.remove('y')
    972     #other_quantities.remove('z')
    973     other_quantities.remove('volumes')
     1129            static_quantities.append(quantity)
     1130
     1131    #print static_quantities
     1132    #print dynamic_quantities
     1133   
    9741134    try:
    975         other_quantities.remove('stage_range')
    976         other_quantities.remove('xmomentum_range')
    977         other_quantities.remove('ymomentum_range')
    978         other_quantities.remove('elevation_range')
     1135        dynamic_quantities.remove('stage_c')
     1136        dynamic_quantities.remove('xmomentum_c')
     1137        dynamic_quantities.remove('ymomentum_c')
     1138        dynamic_quantities.remove('elevation_c')
    9791139    except:
    9801140        pass
    981 
    982     conserved_quantities.remove('time')
     1141   
     1142    try:
     1143        static_quantities.remove('elevation_c')
     1144    except:
     1145        pass
     1146       
     1147   
     1148    static_quantities.remove('x')
     1149    static_quantities.remove('y')
     1150    #other_quantities.remove('z')
     1151    static_quantities.remove('volumes')
     1152    try:
     1153        static_quantities.remove('stage_range')
     1154        static_quantities.remove('xmomentum_range')
     1155        static_quantities.remove('ymomentum_range')
     1156        static_quantities.remove('elevation_range')
     1157    except:
     1158        pass
     1159
     1160    dynamic_quantities.remove('time')
    9831161
    9841162    if verbose: log.critical('    building domain')
     
    9991177        unique = True
    10001178    if unique:
    1001         coordinates, volumes, boundary = weed(coordinates, volumes,boundary)
     1179        coordinates, volumes, boundary = weed(coordinates, volumes, boundary)
    10021180
    10031181     
     
    10161194    domain.geo_reference = geo_reference
    10171195
    1018     for quantity in other_quantities:
     1196    for quantity in static_quantities:
    10191197        try:
    10201198            NaN = fid.variables[quantity].missing_value
     
    10411219        domain.set_quantity(quantity, X)
    10421220    #
    1043     for quantity in conserved_quantities:
     1221    for quantity in dynamic_quantities:
    10441222        try:
    10451223            NaN = fid.variables[quantity].missing_value
  • trunk/anuga_core/source/anuga/file/test_read_sww.py

    r8405 r9018  
    112112        assert num.allclose(sww_file.y, domain.get_vertex_coordinates()[:,1])
    113113
    114 
     114       
    115115        assert num.allclose(sww_file.time, [0.0, 1.0, 2.0, 3.0, 4.0])
    116116       
     
    179179        os.remove(source)
    180180       
     181    def test_read_sww_with_centroids(self):
     182        """
     183        Save to an sww file and then read back the info.
     184        Here we store the info "uniquely"
     185        """
     186
     187        #---------------------------------------------------------------------
     188        # Import necessary modules
     189        #---------------------------------------------------------------------
     190        from anuga.abstract_2d_finite_volumes.mesh_factory import \
     191            rectangular_cross
     192        from anuga.shallow_water.shallow_water_domain import Domain
     193        from boundaries import Reflective_boundary
     194        from anuga.abstract_2d_finite_volumes.generic_boundary_conditions\
     195                            import Dirichlet_boundary, Time_boundary
     196
     197        #---------------------------------------------------------------------
     198        # Setup computational domain
     199        #---------------------------------------------------------------------
     200        length = 8.
     201        width = 4.
     202        dx = dy = 2   # Resolution: Length of subdivisions on both axes
     203       
     204        inc = 0.05 # Elevation increment
     205
     206        points, vertices, boundary = rectangular_cross(int(length/dx),
     207                                                       int(width/dy),
     208                                                       len1=length,
     209                                                       len2=width)
     210        domain = Domain(points, vertices, boundary)
     211        domain.set_name('read_sww_test_c'+str(domain.processor))  # Output name
     212        domain.set_quantities_to_be_stored({'elevation': 2,
     213                                            'stage': 2,
     214                                            'xmomentum': 2,
     215                                            'ymomentum': 2,
     216                                            'friction': 1})
     217
     218        domain.set_store_vertices_uniquely(True)
     219        domain.set_store_centroids(True)
     220       
     221        #---------------------------------------------------------------------
     222        # Setup initial conditions
     223        #---------------------------------------------------------------------
     224        domain.set_quantity('elevation', 0.0)    # Flat bed initially
     225        domain.set_quantity('friction', 0.01)    # Constant friction
     226        domain.set_quantity('stage', 0.0)        # Dry initial condition
     227
     228        #------------------------------------------------------------------
     229        # Setup boundary conditions
     230        #------------------------------------------------------------------
     231        Bi = Dirichlet_boundary([0.4, 0, 0])          # Inflow
     232        Br = Reflective_boundary(domain)              # Solid reflective wall
     233        Bo = Dirichlet_boundary([-5, 0, 0])           # Outflow
     234
     235        domain.set_boundary({'left': Bi, 'right': Bo, 'top': Br, 'bottom': Br})
     236
     237        #-------------------------------------------------------------------
     238        # Evolve system through time
     239        #-------------------------------------------------------------------
     240
     241        for t in domain.evolve(yieldstep=1, finaltime=4.0):
     242            pass
     243           
     244           
     245        # Check that quantities have been stored correctly   
     246        source = domain.get_name() + '.sww'
     247
     248
     249        #x = fid.variables['x'][:]
     250        #y = fid.variables['y'][:]
     251        #stage = fid.variables['stage'][:]
     252        #elevation = fid.variables['elevation'][:]
     253        #fid.close()
     254                   
     255        #assert len(stage.shape) == 2
     256        #assert len(elevation.shape) == 2       
     257       
     258        #M, N = stage.shape
     259               
     260        sww_file = sww.Read_sww(source)
     261
     262        #print 'last frame number',sww_file.get_last_frame_number()
     263
     264        assert num.allclose(sww_file.x, domain.get_vertex_coordinates()[:,0])
     265        assert num.allclose(sww_file.y, domain.get_vertex_coordinates()[:,1])
     266
     267       
     268        assert num.allclose(sww_file.time, [0.0, 1.0, 2.0, 3.0, 4.0])
     269       
     270        M = domain.get_number_of_triangles()
     271       
     272        assert num.allclose(num.reshape(num.arange(3*M), (M,3)), sww_file.vertices)
     273
     274        last_frame_number = sww_file.get_last_frame_number()
     275        assert last_frame_number == 4
     276
     277        assert num.allclose(sww_file.get_bounds(), [0.0, length, 0.0, width])
     278
     279        assert 'stage'     in sww_file.quantities.keys()
     280        assert 'friction'  in sww_file.quantities.keys()
     281        assert 'elevation' in sww_file.quantities.keys()
     282        assert 'xmomentum' in sww_file.quantities.keys()
     283        assert 'ymomentum' in sww_file.quantities.keys()
     284
     285
     286        for qname, q in sww_file.read_quantities(last_frame_number).items():
     287            assert num.allclose(domain.get_quantity(qname).get_values(), q)
     288
     289        #-----------------------------------------
     290        # Start the evolution off again at frame 3
     291        #-----------------------------------------
     292        sww_file.read_quantities(last_frame_number-1)
     293
     294        points, vertices, boundary = rectangular_cross(int(length/dx),
     295                                                       int(width/dy),
     296                                                       len1=length,
     297                                                       len2=width)
     298        new_domain = Domain(points, vertices, boundary)
     299        new_domain.set_quantities_to_be_stored(None)
     300
     301        new_domain.set_store_vertices_uniquely(True)
     302
     303        for qname, q in sww_file.read_quantities(last_frame_number-1).items():
     304            new_domain.set_quantity(qname, q)   
     305
     306        #------------------------------------------------------------------
     307        # Setup boundary conditions
     308        #------------------------------------------------------------------
     309        Bi = Dirichlet_boundary([0.4, 0, 0])          # Inflow
     310        Br = Reflective_boundary(new_domain)          # Solid reflective wall
     311        Bo = Dirichlet_boundary([-5, 0, 0])           # Outflow
     312
     313        new_domain.set_boundary({'left': Bi, 'right': Bo, 'top': Br, 'bottom': Br})
     314
     315        #-------------------------------------------------------------------
     316        # Evolve system through time
     317        #-------------------------------------------------------------------
     318
     319        for t in new_domain.evolve(yieldstep=1.0, finaltime=1.0):
     320             pass
     321
     322        # Compare  new_domain and domain quantities
     323        for quantity in domain.get_quantity_names():
     324            dv = domain.get_quantity(quantity).get_values()
     325            ndv = new_domain.get_quantity(quantity).get_values()
     326
     327            #print dv-ndv
     328
     329            assert num.allclose( dv, ndv, rtol=5.e-2, atol=5.e-2)
     330
     331        # Clean up
     332        #os.remove(source)
     333       
    181334
    182335if __name__ == "__main__":
  • trunk/anuga_core/source/anuga/file/test_sww.py

    r8780 r9018  
    460460if __name__ == "__main__":
    461461    suite = unittest.makeSuite(Test_sww, 'test')
    462     runner = unittest.TextTestRunner(verbosity=1)
     462    runner = unittest.TextTestRunner(verbosity=2)
    463463    runner.run(suite)
  • trunk/anuga_core/source/anuga/shallow_water/shallow_water_domain.py

    r9003 r9018  
    208208        #-------------------------------
    209209        self.set_store(True)
     210        self.set_store_centroids(False)
    210211        self.set_store_vertices_uniquely(False)
    211212        self.quantities_to_be_stored = {'elevation': 1,
     
    213214                                        'xmomentum': 2,
    214215                                        'ymomentum': 2}
    215 
    216        
    217 
    218216
    219217        #-------------------------------
     
    231229    def set_defaults(self):
    232230        """Set the default values in this routine. That way we can inherit class
    233         and just over redefine the defaults for the new class
     231        and just redefine the defaults for the new class
    234232        """
    235233
     
    451449        return self.store
    452450
     451
     452    def set_store_centroids(self, flag=True):
     453        """Set whether centroid data is saved to sww file.
     454        """
     455
     456        self.store_centroids = flag
     457       
     458    def get_store_centroids(self):
     459        """Get whether data saved to sww file.
     460        """
     461       
     462        return self.store_centroids   
     463   
     464       
    453465       
    454466    def set_sloped_mannings_function(self, flag=True):
Note: See TracChangeset for help on using the changeset viewer.