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

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

Updated nappy so it can handle numpy and cdms2 - but only partially tested!

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