source: nappy/trunk/nappy/nc_interface/cdms_to_na.py @ 3492

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/nappy/trunk/nappy/nc_interface/cdms_to_na.py@3492
Revision 3492, 6.7 KB checked in by astephen, 12 years ago (diff)

Removed bug from legacy code.

RevLine 
[3321]1#   Copyright (C) 2004 CCLRC & NERC( Natural Environment Research Council ).
2#   This software may be distributed under the terms of the
3#   Q Public License, version 1.0 or later. http://ndg.nerc.ac.uk/public_docs/QPublic_license.txt
4
[3329]5"""
6cdms_to_na.py
7=============
[3321]8
[3329]9Holds the class CDMSToNA that converts a set of CDMS variables and global attributes.
[3321]10
11"""
12
13# Imports from python standard library
[3329]14import sys
[3321]15
[3329]16# Import from nappy package
[3390]17import nappy
[3329]18from nappy.na_error import na_error
19import nappy.utils
20import nappy.utils.common_utils
[3347]21import nappy.cdms_utils.var_utils
[3329]22import nappy.na_file.na_core
[3390]23import nappy.nc_interface.na_content_collector
[3321]24
[3329]25# Import external packages (if available)
26if sys.platform.find("win") > -1:
27    raise na_error.NAPlatformError("Windows does not support CDMS. CDMS is required to convert to CDMS objects and NetCDF.")
28try:
29    import cdms, Numeric
30except:
31    raise Exception("Could not import third-party software. Nappy requires the CDMS and Numeric packages to be installed to convert to CDMS and NetCDF.")
[3321]32
[3329]33cdms.setAutoBounds("off") 
[3321]34
[3390]35# Define global variables
36permitted_overwrite_metadata = ("DATE",  "RDATE", "ANAME", "MNAME",
37           "ONAME", "ORG", "SNAME", "VNAME")
38items_as_lists = ["DATE", "RDATE", "ANAME", "VNAME"]
39var_limit = 5000 # surely never going to get this many vars in a file!
[3345]40
[3405]41DEBUG = nappy.utils.getDebug() 
42
43class CDMSToNA:
[3351]44    """
[3405]45    Converts CDMS objects to NASA Ames file dictionaries.
[3351]46    """
[3347]47
[3390]48    def __init__(self, cdms_variables, global_atts={}, na_items_to_override={}, 
[3469]49                 only_return_file_names=False, requested_ffi=None):
[3351]50        """
[3390]51        Sets up instance variables.     
[3351]52        """
[3390]53        self.cdms_variables = cdms_variables
54        self.global_atts = global_atts
55        self.na_items_to_override = na_items_to_override
56        self.only_return_file_names = only_return_file_names
[3469]57        self.requested_ffi = requested_ffi
58
[3390]59        self.converted = False
60        self.output_message = []
61   
62    def convert(self):
63        """
64        Reads the CDMS objects and convert to a set of dictionaries that
65        provide the structure for a NA File object.
66        Returns [(na_dict, var_ids), (na_dict, var_ids), ....]
67        All these na_dict dictionaries can be readily written to a NA File object.
[3351]68
[3390]69        Note that NASA Ames is not as flexible as NetCDF so you cannot just send any
70        set of variables to write to a NASA Ames file. Essentially there is one
71        multi-dimensional structure and all variables must be defined against it.
[3351]72
[3390]73        Otherwise variables must be auxiliary variables within that structure (i.e. only
74        defined once per the least changing dimension.
75        """
76        if self.converted == True:
77            print "Already converted to NA dictionary objects."
78            return self.na_dict_list
79       
80        # Convert any singleton variables to CDMS variables
81        variables = self._convertSingletonVars(self.cdms_variables)
[3351]82
[3390]83        # Re-order variables if they have the attribute "nasa_ames_var_number" which means they came from a NASA Ames file originally
84        variables = self._reorderVars(variables)
[3351]85
[3390]86        # Make first call to collector class that creates NA dict from CDMS variables and global atts dicts
[3469]87        collector = nappy.nc_interface.na_content_collector.NAContentCollector(variables, 
88                                        self.global_atts, requested_ffi=self.requested_ffi)
[3441]89        collector.collectNAContent()
[3351]90
[3390]91        # Return if no files returned
[3441]92        if collector.found_na == False:
[3390]93            msg = "\nNo files created after variables parsed."
94            if DEBUG: print msg
95            self.output_message.append(msg)
[3441]96            return
[3351]97
[3441]98        # NOTE: collector has attributes: na_dict, var_ids, unused_vars
99
[3390]100        # Set up a list to collect multiple calls to content collector
101        na_dict_list = []
[3441]102        na_dict_list.append((collector.na_dict, collector.var_ids))
[3351]103
[3390]104        # If there are variables that were not captured (i.e. unused) by NAContentCollector then loop through these
105        # in attempt to convert all to a set of na_dicts
106        while len(collector.unused_vars) > 0:
[3469]107            collector = nappy.nc_interface.na_content_collector.NAContentCollector(collector.unused_vars, 
108                                       self.global_atts, requested_ffi=self.requested_ffi)
[3441]109            collector.collectNAContent()           
[3390]110            self.output_message += collector.output_message
[3441]111
[3390]112            # Append to list if more variables were captured
[3441]113            if collector.found_na == True: 
114                na_dict_list.append((collector.na_dict, collector.var_ids))
[3351]115
[3390]116        self.na_dict_list = na_dict_list
117        self.converted = True
118        return self.na_dict_list
[3351]119
[3390]120    def _convertSingletonVars(self, variables):
[3351]121        """
[3390]122        Loops through variables to convert singleton variables (i.e. Masked Arrays/Numeric Arrays)
123        to proper CDMS variables. Then code won't break when asking for rank attribute later.
124        Returns a list of CDMS variable objects
125        """
126        vars = []
[3348]127
[3390]128        for variable in variables:
129            var_obj = variable
[3348]130
[3390]131            # If singleton variable then convert into proper CDMS variables so code doesn't break later
132            if not hasattr(var_obj, "rank"):
133                var_metadata = var_obj.attributes       
134                var_value = var_obj
[3405]135                var_obj = cdms.createVariable(Numeric.array(var_obj), 
136                id=nappy.cdms_utils.var_utils.getBestName(var_metadata).replace(" ", "_"), 
137                                   attributes=var_metadata)
138                var_obj.value = var_obj._data[0]                 
[3321]139               
[3390]140            vars.append(var_obj)
[3321]141
[3416]142        return vars
143
[3390]144    def _reorderVars(self, variables):
145        """
146        Returns a reordered list of variables. Any that have the attribute
147        "nasa_ames_var_number" get ordered first in the list (according to numbering).
148        """
149        # Set up a long list (longer than number of vars)
150        if len(variables) > var_limit:
151            raise Exception("Can only handle converting less than " + `var_limit` + " variables in any batch.")
[3321]152
[3390]153        # Collect up those that are ordered and unordered
154        ordered_vars = [None] * var_limit
155        unordered_vars = []
156        for var in variables:
157            var_metadata = var.attributes
158            if hasattr(var_metadata, "nasa_ames_var_number"):
159                num = var_metadata.nasa_ames_var_number
160                ordered_vars[num] = var
161            else:
162                unordered_vars.append(var)
163   
164        vars = []
165        # Clear any None values in ordered_vars and place in final vars list
166        for var in ordered_vars + unordered_vars:
167            if var != None: vars.append(var)
[3321]168           
[3390]169        return vars
[3321]170
Note: See TracBrowser for help on using the repository browser.