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

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

Converted all global_atts to lists of key,value pairs so order can be maintained.

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