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

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

Fixed ambiguous test.

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