1 | import string |
---|
2 | import utils_c4 as utils |
---|
3 | import os |
---|
4 | import os.path as op |
---|
5 | import shutil, collections |
---|
6 | from versionConfig import version, versionComment |
---|
7 | |
---|
8 | NT_project = collections.namedtuple( 'project', ['id','v'] ) |
---|
9 | NT_fnParts = collections.namedtuple( 'fnParts', ['len','fxLen','unfLen','checkTLen','ixDomain','ixFreq'] ) |
---|
10 | |
---|
11 | ############################################################################## |
---|
12 | # Configure config-file paths |
---|
13 | # |
---|
14 | # All configuration directories, e.g. cmip5_vocabs, are looked for in a single |
---|
15 | # parent directory. This is the "config" directory within the package unless |
---|
16 | # the environment variable CC_CONFIG_DIR is set. |
---|
17 | |
---|
18 | HERE = op.dirname(__file__) |
---|
19 | CC_CONFIG_DEFAULT_DIR = op.join(HERE, 'config') |
---|
20 | CC_CONFIG_DIR = os.environ.get('CC_CONFIG_DIR', CC_CONFIG_DEFAULT_DIR) |
---|
21 | |
---|
22 | ############################################################################## |
---|
23 | |
---|
24 | validCmip5Experiments = ['1pctCO2', 'abrupt4xCO2', 'amip', 'amip4K', 'amip4xCO2', 'amipFuture', 'aqua4K', 'aqua4xCO2', 'aquaControl', 'decadal1959', 'decadal1960', 'decadal1961', 'decadal1962', 'decadal1963', 'decadal1964', 'decadal1965', 'decadal1966', 'decadal1967', 'decadal1968', 'decadal1969', 'decadal1970', 'decadal1971', 'decadal1972', 'decadal1973', 'decadal1974', 'decadal1975', 'decadal1976', 'decadal1977', 'decadal1978', 'decadal1979', 'decadal1980', 'decadal1981', 'decadal1982', 'decadal1983', 'decadal1984', 'decadal1985', 'decadal1986', 'decadal1987', 'decadal1988', 'decadal1989', 'decadal1990', 'decadal1991', 'decadal1992', 'decadal1993', 'decadal1994', 'decadal1995', 'decadal1996', 'decadal1997', 'decadal1998', 'decadal1999', 'decadal2000', 'decadal2001', 'decadal2002', 'decadal2003', 'decadal2004', 'decadal2005', 'decadal2006', 'decadal2007', 'decadal2008', 'decadal2009', 'decadal2010', 'decadal2011', 'decadal2012', 'esmControl', 'esmFdbk1', 'esmFdbk2', 'esmFixClim1', 'esmFixClim2', 'esmHistorical', 'esmrcp85', 'historical', 'historicalExt', 'historicalGHG', 'historicalMisc', 'historicalNat', 'lgm', 'midHolocene', 'noVolc1960', 'noVolc1965', 'noVolc1970', 'noVolc1975', 'noVolc1980', 'noVolc1985', 'noVolc1990', 'noVolc1995', 'noVolc2000', 'noVolc2005', 'past1000', 'piControl', 'rcp26', 'rcp45', 'rcp60', 'rcp85', 'sst2020', 'sst2030', 'sst2090', 'sst2090rcp45', 'sstClim', 'sstClim4xCO2', 'sstClimAerosol', 'sstClimSulfate', 'volcIn2010'] |
---|
25 | |
---|
26 | validCordexExperiment = validCmip5Experiments + ['evaluation'] |
---|
27 | |
---|
28 | |
---|
29 | validCmip5Frequencies = ['fx','yr','monClim','mon','day','6hr','3hr','subhr'] |
---|
30 | validCordexFrequencies = ['fx','sem','mon','day','6hr','3hr'] |
---|
31 | validSpecsFrequencies = ['fx','mon','day','6hr'] |
---|
32 | validCcmiFrequencies = ['fx','yr','mon','day','hr','subhr'] |
---|
33 | validSpecsExptFamilies = map( lambda x: string.strip( x ), |
---|
34 | open( op.join(CC_CONFIG_DIR, 'specs_vocabs/exptFamily.txt' )).readlines() ) |
---|
35 | |
---|
36 | validCordexDomainsL = [ 'SAM-44', 'CAM-44', 'NAM-44', 'EUR-44', 'AFR-44', 'WAS-44', 'EAS-44', 'CAS-44', 'AUS-44', 'ANT-44', 'ARC-44', 'MED-44'] |
---|
37 | validCordexDomainsLi = map( lambda x: x + 'i', validCordexDomainsL ) |
---|
38 | validCordexDomainsH = ['EUR-11'] |
---|
39 | validCordexDomains = validCordexDomainsL + validCordexDomainsLi + validCordexDomainsH |
---|
40 | |
---|
41 | plevRequired = ['clh', 'clm', 'cll', 'ua850', 'va850', 'ta850', 'hus850', 'ua500', 'va500', 'ta500', 'zg500', 'ua200', 'va200', 'ta200', 'zg200'] |
---|
42 | plevBndsRequired = ['clh', 'clm', 'cll'] |
---|
43 | heightRequired = ['tas','tasmax','tasmin','huss','sfcWind','sfcWindmax','wsgsmax','uas','vas'] |
---|
44 | |
---|
45 | |
---|
46 | ii = open( op.join(CC_CONFIG_DIR, 'cordex_vocabs/GCMModelName.txt' )).readlines() |
---|
47 | validGcmNames = [] |
---|
48 | for l in ii: |
---|
49 | if l[0] != '#' and len( string.strip(l) ) > 0: |
---|
50 | validGcmNames.append( string.split(l)[0] ) |
---|
51 | |
---|
52 | ii = open( op.join(CC_CONFIG_DIR, 'cordex_vocabs/RCMModelName.txt' )).readlines() |
---|
53 | validRcmNames = [] |
---|
54 | validInstNames = [] |
---|
55 | for l in ii: |
---|
56 | if l[0] != '#' and len( string.strip(l) ) > 0: |
---|
57 | bits = string.split(l) |
---|
58 | validRcmNames.append( bits[0] ) |
---|
59 | validInstNames.append( bits[1] ) |
---|
60 | |
---|
61 | plevValues = {'clh':22000, 'clm':56000, 'cll':84000} |
---|
62 | for i in [200,500,850]: |
---|
63 | for v in ['zg','ua', 'va', 'ta', 'hus']: |
---|
64 | k = '%s%s' % (v,i) |
---|
65 | plevValues[k] = i*100 |
---|
66 | |
---|
67 | heightRequired = ['tas', 'tasmax', 'tasmin', 'huss', 'sfcWind', 'sfcWindmax', 'wsgsmax', 'uas', 'vas'] |
---|
68 | heightValues = {} |
---|
69 | heightRange = {} |
---|
70 | for v in heightRequired: |
---|
71 | if v in ['tas', 'tasmax', 'tasmin', 'huss']: |
---|
72 | heightValues[v] = 2 |
---|
73 | else: |
---|
74 | heightValues[v] = 10 |
---|
75 | heightRange[v] = (1.5,10.) |
---|
76 | |
---|
77 | ii = open( op.join(CC_CONFIG_DIR, 'cordex_vocabs/cordex_domains.csv' )).readlines() |
---|
78 | keys = ['name','tag','res','grid_np_lon','grid_np_lat','nlon','nlat','w','e','s','n'] |
---|
79 | rotatedPoleGrids = {} |
---|
80 | for l in ii[2:16]: |
---|
81 | bits = string.split(string.strip(l),',') |
---|
82 | ee = {} |
---|
83 | i = 0 |
---|
84 | for k in keys: |
---|
85 | if k in ['nlon','nlat']: |
---|
86 | ee[k] = int(bits[i]) |
---|
87 | elif k in ['grid_np_lon','grid_np_lat','w','e','s','n','res']: |
---|
88 | if bits[i] != 'N/A': |
---|
89 | ee[k] = float(bits[i]) |
---|
90 | else: |
---|
91 | ee[k] = bits[i] |
---|
92 | else: |
---|
93 | ee[k] = bits[i] |
---|
94 | i += 1 |
---|
95 | rotatedPoleGrids[bits[1]] = ee |
---|
96 | |
---|
97 | ##Area,Name, deg,Nlon,Nlat,West8,East8,South8,North8, |
---|
98 | keys = ['name','tag','res','nlon','nlat','w','e','s','n'] |
---|
99 | interpolatedGrids = {} |
---|
100 | for l in ii[18:33]: |
---|
101 | bits = string.split(string.strip(l),',') |
---|
102 | ee = {} |
---|
103 | i = 0 |
---|
104 | for k in keys: |
---|
105 | if k in ['nlon','nlat']: |
---|
106 | ee[k] = int(bits[i]) |
---|
107 | elif k in ['w','e','s','n','res']: |
---|
108 | ee[k] = float(bits[i]) |
---|
109 | else: |
---|
110 | ee[k] = bits[i] |
---|
111 | i += 1 |
---|
112 | interpolatedGrids[bits[1]] = ee |
---|
113 | |
---|
114 | class readVocab(object): |
---|
115 | |
---|
116 | def __init__(self,dir): |
---|
117 | self.dir = dir |
---|
118 | |
---|
119 | def driver(self,tt): |
---|
120 | if tt[0] == "simpleList": |
---|
121 | tx = tt + (None,None,None,None) |
---|
122 | return self.getSimpleList( tx[1],bit=tx[2],omt=tx[3],options=tx[4] ) |
---|
123 | else: |
---|
124 | print 'readVocab.driver: option %s not recgnised' % tt[0] |
---|
125 | |
---|
126 | def getEvalAssign(self, file ): |
---|
127 | ii = open('%s/%s/%s' % (CC_CONFIG_DIR, self.dir,file) ) |
---|
128 | ll = [] |
---|
129 | for l in ii.readlines(): |
---|
130 | if l[0] != '#': |
---|
131 | ll.append( l ) |
---|
132 | assert len(ll) == 1, 'Too many lines in %s' % file |
---|
133 | try: |
---|
134 | return eval( ll[0] ) |
---|
135 | except: |
---|
136 | print 'Failed to evaluate configuration line from %s:\n%s' % (file,l[0]) |
---|
137 | raise |
---|
138 | |
---|
139 | def getSimpleList(self,file,bit=None,omt=None,options=None): |
---|
140 | ii = open('%s/%s/%s' % (CC_CONFIG_DIR, self.dir,file) ) |
---|
141 | oo = [] |
---|
142 | if options == None: |
---|
143 | olist = [] |
---|
144 | else: |
---|
145 | olist = string.split(options,',') |
---|
146 | |
---|
147 | if 'returnMappings' in olist: |
---|
148 | assert bit in [0, -1], 'only support returnMappings for bit = -1 or 0' |
---|
149 | ee = {} |
---|
150 | |
---|
151 | for l in ii.readlines(): |
---|
152 | if l[0] != '#': |
---|
153 | ll = string.strip(l) |
---|
154 | if omt == 'last': |
---|
155 | oo.append(string.join(string.split(ll)[:-1])) |
---|
156 | elif bit == None: |
---|
157 | oo.append(ll) |
---|
158 | else: |
---|
159 | if 'returnMappings' in olist: |
---|
160 | bb = string.split(ll) |
---|
161 | if bit == -1: |
---|
162 | ee[bb[-1]] = string.join( bb[:-1] ) |
---|
163 | else: |
---|
164 | ee[bb[0]] = string.join( bb[1:] ) |
---|
165 | oo.append( bb[bit] ) |
---|
166 | else: |
---|
167 | oo.append(string.split(ll)[bit]) |
---|
168 | |
---|
169 | if 'noneMap' in olist: |
---|
170 | oo = map( lambda x: {'None':None}.get(x,x), oo ) |
---|
171 | |
---|
172 | if 'returnMappings' in olist: |
---|
173 | return oo, ee |
---|
174 | else: |
---|
175 | return oo |
---|
176 | |
---|
177 | validSpecsInstitutions = ['IC3', 'MPI-M', 'KNMI', 'UOXF', 'CNRM-CERFACS', 'ENEA', 'MOHC', 'SMHI', 'IPSL', 'UREAD', 'ECWMF'] |
---|
178 | |
---|
179 | class projectConfig(object): |
---|
180 | |
---|
181 | def __init__(self, project, version=-1): |
---|
182 | knownProjects = ['CMIP5','CCMI','CORDEX','SPECS','ESA-CCI', '__dummy'] |
---|
183 | assert project in knownProjects, 'Project %s not in knownProjects %s' % (project, str(knownProjects)) |
---|
184 | |
---|
185 | self.project = project |
---|
186 | self.fNameSep = '_' |
---|
187 | self.varIndex = 0 |
---|
188 | self.fnvdict = None |
---|
189 | self.varTables='CMIP' |
---|
190 | self.checkVarType = True |
---|
191 | self.projectV = NT_project(project,version) |
---|
192 | self.gridSpecTol = 0.01 |
---|
193 | ## default encoding of time range in file names: YYYY[MM[DD[HH]]]-YYYY[MM[DD[HH]]] |
---|
194 | self.trangeType = 'CMIP' |
---|
195 | self.controlledFnParts = [] |
---|
196 | if project == 'CORDEX': |
---|
197 | self.requiredGlobalAttributes = [ 'institute_id', 'contact', 'rcm_version_id', 'product', 'CORDEX_domain', 'creation_date', \ |
---|
198 | 'frequency', 'model_id', 'driving_model_id', 'driving_experiment', 'driving_model_ensemble_member', 'experiment_id'] |
---|
199 | self.controlledGlobalAttributes = ['frequency', 'driving_experiment_name', 'project_id', 'CORDEX_domain', 'driving_model_id', 'model_id', 'institute_id','driving_model_ensemble_member','rcm_version_id'] |
---|
200 | self.globalAttributesInFn = [None,'CORDEX_domain','driving_model_id','experiment_id','driving_model_ensemble_member','model_id','rcm_version_id'] |
---|
201 | self.requiredVarAttributes = ['long_name', 'standard_name', 'units'] |
---|
202 | self.drsMappings = {'variable':'@var','institute':'institute_id', 'product':'product', 'experiment':'experiment_id', \ |
---|
203 | 'ensemble':'driving_model_ensemble_member', 'model':'model_id', 'driving_model':'driving_model_id', \ |
---|
204 | 'frequency':'frequency', \ |
---|
205 | 'project':'project_id', 'domain':'CORDEX_domain', 'model_version':'rcm_version_id' } |
---|
206 | |
---|
207 | elif project == 'SPECS': |
---|
208 | lrdr = readVocab( 'specs_vocabs/') |
---|
209 | self.requiredGlobalAttributes = lrdr.driver( ('simpleList', 'globalAts.txt' ) ) |
---|
210 | self.exptFamilies = lrdr.driver( ('simpleList', 'exptFamily.txt', 0 ) ) |
---|
211 | self.validInstitutions = lrdr.driver( ('simpleList', 'validInstitutions_sv0101.txt' ) ) |
---|
212 | self.realm = lrdr.driver( ('simpleList', 'realm_sv0101.txt' ) ) |
---|
213 | self.controlledGlobalAttributes = lrdr.driver( ('simpleList', 'controlledGlobalAttributes_sv0101.txt' ) ) |
---|
214 | ##'initialization_method','physics_version','realization'] |
---|
215 | self.globalAttributesInFn = lrdr.driver( ('simpleList', 'globalAttributesInFn_sv0101.txt',None,None,'noneMap' ) ) |
---|
216 | self.requiredVarAttributes = ['long_name', 'standard_name', 'units'] |
---|
217 | oo, self.drsMappings = lrdr.driver( ('simpleList', 'drsMappings_sv0101.txt',0,None,'returnMappings' ) ) |
---|
218 | |
---|
219 | ##self.drsMappings = {'variable':'@var', 'institute':'institute_id', 'product':'product', 'experiment':'experiment_id', \ |
---|
220 | ##'ensemble':'@ensemble', 'model':'model_id', 'realm':'modeling_realm', \ |
---|
221 | ##'frequency':'frequency', 'start_date':'@forecast_reference_time', \ |
---|
222 | ##'table':'@mip_id', |
---|
223 | ##'project':'project_id'} |
---|
224 | |
---|
225 | elif project == 'CMIP5': |
---|
226 | lrdr = readVocab( 'cmip5_vocabs/') |
---|
227 | self.requiredGlobalAttributes = [ 'contact', 'product', 'creation_date', 'tracking_id', \ |
---|
228 | 'experiment_id'] |
---|
229 | ##self.requiredGlobalAttributes = lrdr.getSimpleList( 'globalAts.txt' ) |
---|
230 | self.controlledGlobalAttributes = [ 'project_id','experiment_id', 'frequency','Conventions','modeling_realm', \ |
---|
231 | 'initialization_method','physics_version','realization'] |
---|
232 | self.globalAttributesInFn = [None,'@mip_id','model_id','experiment_id','@ensemble'] |
---|
233 | #sic_Oimon_EC-Earth2_seaIceBestInit_S19910501_series1_r1i1p1_199501-199502.nc |
---|
234 | ## mip_id derived from global attribute Table_id (CMOR convention); experiment family derived from experiment_id, ensemble derived from rip attributes. |
---|
235 | self.requiredVarAttributes = ['long_name', 'standard_name', 'units'] |
---|
236 | ## key: DRS element name, value: global attribute name or tag for mapping from file information ("@...."). |
---|
237 | self.drsMappings = {'variable':'@var', 'institute':'institute_id', 'product':'product', 'experiment':'experiment_id', \ |
---|
238 | 'ensemble':'@ensemble', 'model':'model_id', 'realm':'modeling_realm', \ |
---|
239 | 'frequency':'frequency', 'table':'@mip_id', |
---|
240 | 'project':'project_id'} |
---|
241 | |
---|
242 | elif project == 'CCMI': |
---|
243 | lrdr = readVocab( 'ccmi_vocabs/') |
---|
244 | self.requiredGlobalAttributes = [ 'creation_date', 'tracking_id', 'forcing', 'model_id', 'parent_experiment_id', 'parent_experiment_rip', 'branch_time', 'contact', 'institute_id' ] |
---|
245 | self.requiredGlobalAttributes = lrdr.getSimpleList( 'globalAts.txt', bit=0 ) |
---|
246 | self.controlledGlobalAttributes = [ 'experiment_id', 'project', 'frequency' ] |
---|
247 | self.globalAttributesInFn = [None,'@mip_id','model_id','experiment_id','@ensemble'] |
---|
248 | self.requiredVarAttributes = ['long_name', 'units'] |
---|
249 | self.drsMappings = {'variable':'@var', 'institute':'institute_id', 'product':'product', 'experiment':'experiment_id', \ |
---|
250 | 'ensemble':'@ensemble', 'model':'model_id', 'realm':'modeling_realm', \ |
---|
251 | 'frequency':'frequency', 'table':'@mip_id', |
---|
252 | 'project':'project_id'} |
---|
253 | |
---|
254 | elif project == 'ESA-CCI': |
---|
255 | lrdr = readVocab( 'esacci_vocabs/') |
---|
256 | self.varTables='FLAT' |
---|
257 | self.fNameSep = '-' |
---|
258 | self.checkVarType = False |
---|
259 | self.requiredGlobalAttributes = lrdr.getSimpleList( 'requiredGlobalAts.txt', bit=0 ) |
---|
260 | self.controlledGlobalAttributes = ['platform','sensor','project','Conventions','institution','cdm_data_type','time_coverage_duration','spatial_resolution' ] |
---|
261 | self.controlledFnParts = ['level','cciProject','var','version'] |
---|
262 | self.requiredVarAttributes = ['long_name', 'standard_name', 'units'] |
---|
263 | self.drsMappings = {'variable':'#var','platform':'platform','sensor':'sensor','level':'#level', \ |
---|
264 | 'standard_name':'*standard_name', \ |
---|
265 | 'activity':'=CLIPC', \ |
---|
266 | 'algorithm':'$algorithm:unset', 'frequency':'$frequency', \ |
---|
267 | 'spatial_resolution':'spatial_resolution', 'ecv':'@ecv','version':'#version','convention_version':'#gdsv'} |
---|
268 | self.globalAttributesInFn = [None,] |
---|
269 | elif project == '__dummy': |
---|
270 | self.requiredGlobalAttributes = map( lambda x: 'ga%s' % x, range(10) ) |
---|
271 | self.controlledGlobalAttributes = [ ] |
---|
272 | self.globalAttributesInFn = [None,'ga2', 'ga3', 'ga4' ] |
---|
273 | self.requiredVarAttributes = ['long_name', 'standard_name', 'units'] |
---|
274 | self.drsMappings = {'variable':'@var'} |
---|
275 | |
---|
276 | ####### used in checkStandardDims |
---|
277 | |
---|
278 | self.plevRequired = plevRequired |
---|
279 | self.plevValues = plevValues |
---|
280 | self.heightRequired = heightRequired |
---|
281 | self.heightValues = heightValues |
---|
282 | self.heightRange = heightRange |
---|
283 | |
---|
284 | ####### used in checkGrids |
---|
285 | self.rotatedPoleGrids = rotatedPoleGrids |
---|
286 | self.interpolatedGrids = interpolatedGrids |
---|
287 | self.doCheckGrids = self.projectV.id in ['CORDEX',] |
---|
288 | |
---|
289 | ####### used in checkFileName (freqIndex also used in checkByVar) |
---|
290 | |
---|
291 | if self.projectV.id == 'CORDEX': |
---|
292 | self.fnParts = NT_fnParts( len=[8,9], fxLen=[8,], unfLen=[9,], checkTLen=True, ixDomain=1, ixFreq=7 ) |
---|
293 | elif self.projectV.id == 'CMIP5': |
---|
294 | self.fnParts = NT_fnParts( len=[5,6], fxLen=[5,], unfLen=[6,], checkTLen=False, ixDomain=None, ixFreq=None ) |
---|
295 | elif self.projectV.id == 'SPECS': |
---|
296 | self.fnParts = lrdr.getEvalAssign( 'fnParts_sv0101.txt' ) |
---|
297 | elif self.projectV.id == 'CCMI': |
---|
298 | self.fnParts = NT_fnParts( len=[5,6], fxLen=[5,], unfLen=[6,], checkTLen=False, ixDomain=None, ixFreq=None ) |
---|
299 | elif self.projectV.id == 'ESA-CCI': |
---|
300 | self.fnParts = NT_fnParts( len=[7,8,9], fxLen=[0,], unfLen=[7,8,9,], checkTLen=False, ixDomain=None, ixFreq=None ) |
---|
301 | self.trangeType = 'ESA-CCI' |
---|
302 | elif self.projectV.id == '__dummy': |
---|
303 | self.fnParts = NT_fnParts( len=[4,5], fxLen=[4,], unfLen=[5,], checkTLen=False, ixDomain=None, ixFreq=1 ) |
---|
304 | |
---|
305 | self.fnPartsOkLen = self.fnParts.len |
---|
306 | self.fnPartsOkFixedLen = self.fnParts.fxLen |
---|
307 | self.fnPartsOkUnfixedLen = self.fnParts.unfLen |
---|
308 | self.checkTrangeLen = self.fnParts.checkTLen |
---|
309 | self.domainIndex = self.fnParts.ixDomain |
---|
310 | self.freqIndex = self.fnParts.ixFreq |
---|
311 | |
---|
312 | |
---|
313 | self.defaults = { 'variableDataType':'float' } |
---|
314 | ######## used in mipVocabs |
---|
315 | if self.projectV.id == 'CORDEX': |
---|
316 | self.mipVocabDir = op.join(CC_CONFIG_DIR, 'cordex_vocabs/mip/') |
---|
317 | self.mipVocabTl = ['fx','sem','mon','day','6h','3h'] |
---|
318 | self.mipVocabVgmap = {'6h':'6hr','3h':'3hr'} |
---|
319 | self.mipVocabFnpat = 'CORDEX_%s' |
---|
320 | elif self.projectV.id == 'CMIP5': |
---|
321 | self.mipVocabDir = op.join(CC_CONFIG_DIR, 'cmip5_vocabs/mip/') |
---|
322 | self.mipVocabTl = ['fx','Oyr','Oclim','Omon','Amon','Lmon','LImon','OImon','cfMon','aero','cfDay','day','cfOff','cfSites','6hrLev','6hrPlev','3hr','cf3hr'] |
---|
323 | self.mipVocabVgmap = {} |
---|
324 | self.mipVocabFnpat = 'CMIP5_%s' |
---|
325 | self.defaults['variableDataType'] = None |
---|
326 | elif self.projectV.id == 'SPECS': |
---|
327 | self.mipVocabDir = op.join(CC_CONFIG_DIR, 'specs_vocabs/mip/') |
---|
328 | self.mipVocabTl = ['fx','Omon','Amon','Lmon','OImon','day','6hr'] |
---|
329 | self.mipVocabVgmap = {} |
---|
330 | self.mipVocabFnpat = 'SPECS_%s' |
---|
331 | elif self.projectV.id == 'CCMI': |
---|
332 | self.mipVocabDir = op.join(CC_CONFIG_DIR, 'ccmi_vocabs/mip/') |
---|
333 | self.mipVocabTl = ['fixed','annual','monthly','daily','hourly'] |
---|
334 | self.mipVocabVgmap = {'fixed':'fx','annual':'yr','monthly':'mon','daily':'day','hourly':'hr'} |
---|
335 | self.mipVocabFnpat = 'CCMI1_%s' |
---|
336 | elif self.projectV.id == 'ESA-CCI': |
---|
337 | self.mipVocabDir = op.join(CC_CONFIG_DIR, 'esacci_vocabs/') |
---|
338 | self.mipVocabTl = [] |
---|
339 | self.mipVocabVgmap = { 'ESACCI':'ESACCI' } |
---|
340 | self.mipVocabFnpat = 'variableInFile.txt' |
---|
341 | else: |
---|
342 | self.mipVocabDir = None |
---|
343 | self.mipVocabTl = ['day', 't2'] |
---|
344 | self.mipVocabVgmap = {} |
---|
345 | self.mipVocabFnpat = None |
---|
346 | self.mipVocabPars = [self.mipVocabDir, self.mipVocabTl, self.mipVocabVgmap, self.mipVocabFnpat] |
---|
347 | |
---|
348 | ######## used in checkByVar |
---|
349 | if self.project == 'CORDEX': |
---|
350 | self.groupIndex = 7 |
---|
351 | elif self.project in ['CMIP5','CCMI','SPECS','__dummy']: |
---|
352 | self.groupIndex = 1 |
---|
353 | elif self.project in ['ESA-CCI']: |
---|
354 | self.fnvdict = { 'SSTskin':{'v':'sea_surface_temperature', 'sn':'sea_surface_skin_temperature'} } |
---|
355 | self.fnoptions = {'groupIndex':[1,0], 'trangeIndex':[0,-2] } |
---|
356 | self.fnoptions['inFn'] = [[None,'*activity','*level','*project','*var','*product','*additional','*gdsv','*version'], |
---|
357 | ['*activity','*project','*level','*var','*additional',None,'*version']] |
---|
358 | self.fnoptions['varIndex'] = [4,3] |
---|
359 | ##Indicative Date>[<Indicative Time>]-ESACCI-<Processing Level>_<CCI Project>-<Data Type>-<Product String>[- <Additional Segregator>][-v<GDS version>]-fv<File version>.nc |
---|
360 | ##ESACCI-<CCI Project>-<Processing Level>-<Data Type>-<Product String>[-<Additional Segregator>]-<IndicativeDate>[<Indicative Time>]-fv<File version>.nc |
---|
361 | |
---|
362 | self.trangeIndex = -1 |
---|
363 | |
---|
364 | self.getVocabs() |
---|
365 | test = False |
---|
366 | if test: |
---|
367 | for k in self.vocabs['variable'].varcons.keys(): |
---|
368 | for k2 in self.vocabs['variable'].varcons[k].keys(): |
---|
369 | if "height2m" in self.vocabs['variable'].varcons[k][k2].get( '_dimension',[]): |
---|
370 | print 'config_c4: %s , %s: %s' % (k,k2,str(self.vocabs['variable'].varcons[k][k2]['_dimension'] ) ) |
---|
371 | |
---|
372 | ##assert self.project != 'CCMI', 'Not completely set up for CCMI yet' |
---|
373 | |
---|
374 | def getExtraAtts(self): |
---|
375 | |
---|
376 | eafile = self.mipVocabDir + 'extraAtts.txt' |
---|
377 | self.extraAtts = {} |
---|
378 | if os.path.isfile( eafile ): |
---|
379 | for l in open( eafile ).readlines(): |
---|
380 | if l[0] != '#': |
---|
381 | bits = map( string.strip, string.split(l,',') ) |
---|
382 | id = '%s.%s' % (bits[0],bits[1]) |
---|
383 | ee = {} |
---|
384 | for b in bits[2:]: |
---|
385 | bb = string.split(b,'=') |
---|
386 | ee[bb[0]] = bb[1] |
---|
387 | self.extraAtts[id] = ee |
---|
388 | |
---|
389 | def getVocabs(self): |
---|
390 | ## "Returns a dictionary of vocabulary details for the project provided." |
---|
391 | if self.projectV.id == 'SPECS': |
---|
392 | ##'experiment_id':utils.patternControl( 'experiment_id', "(?P<val>.*)[0-9]{4}", list=validSpecsExptFamilies ), \ |
---|
393 | vocabs = { 'variable':utils.mipVocab(self), \ |
---|
394 | 'Conventions':utils.listControl( 'Conventions', ['CF-1.6'] ), \ |
---|
395 | 'frequency':utils.listControl( 'frequency', validSpecsFrequencies ), \ |
---|
396 | 'experiment_id':utils.listControl( 'experiment_id', validSpecsExptFamilies ), \ |
---|
397 | 'initialization_method':utils.patternControl( 'initialization_method', "[0-9]+" ), \ |
---|
398 | 'physics_version':utils.patternControl( 'physics_version', "[0-9]+" ), \ |
---|
399 | 'realization':utils.patternControl( 'realization', "[0-9]+" ), \ |
---|
400 | 'startdate':utils.patternControl( 'startdate', "S[0-9]{8}" ), \ |
---|
401 | ## 'associated_experiment':utils.patternControl( 'associated_experment', "(?P<val>(N/A|(decadal|seasonal): r\*i[0-9]{1,4}p[0-9]{1,4}))" ), \ |
---|
402 | 'project_id':utils.listControl( 'project_id', ['SPECS', 'NMME-SPECS'] ), \ |
---|
403 | ## 'institution':utils.listControl( 'institution', validSpecsInstitutions ), \ |
---|
404 | 'modeling_realm':utils.listControl( 'realm', self.realm, split=True ), \ |
---|
405 | } |
---|
406 | elif self.projectV.id == 'CMIP5': |
---|
407 | ##'experiment_id':utils.patternControl( 'experiment_id', "(?P<val>.*)[0-9]{4}", list=validSpecsExptFamilies ), \ |
---|
408 | lrdr = readVocab( 'cmip5_vocabs/') |
---|
409 | vocabs = { 'variable':utils.mipVocab(self), \ |
---|
410 | 'Conventions':utils.listControl( 'Conventions', ['CF-1.4','CF-1.5'] ), \ |
---|
411 | 'experiment_id':utils.listControl( 'experiment_id', lrdr.getSimpleList( 'experiments.txt' ) ), \ |
---|
412 | 'frequency':utils.listControl( 'frequency', validCmip5Frequencies ), \ |
---|
413 | 'initialization_method':utils.patternControl( 'initialization_method', "[0-9]+" ), \ |
---|
414 | 'physics_version':utils.patternControl( 'physics_version', "[0-9]+" ), \ |
---|
415 | 'realization':utils.patternControl( 'realization', "[0-9]+" ), \ |
---|
416 | 'project_id':utils.listControl( 'project_id', ['CMIP5'] ), \ |
---|
417 | ## 'institution':utils.listControl( 'institution', validSpecsInstitutions ), \ |
---|
418 | 'modeling_realm':utils.listControl( 'realm', ['atmos', 'ocean', 'land', 'landIce', 'seaIce', 'aerosol', 'atmosChem', 'ocnBgchem'], split=True ), \ |
---|
419 | } |
---|
420 | elif self.projectV.id == 'CCMI': |
---|
421 | |
---|
422 | lrdr = readVocab( 'ccmi_vocabs/') |
---|
423 | vocabs = { 'variable':utils.mipVocab(self), \ |
---|
424 | 'frequency':utils.listControl( 'frequency', validCcmiFrequencies ), \ |
---|
425 | 'experiment_id':utils.listControl( 'experiment_id', lrdr.getSimpleList( 'ccmi_experiments.txt', bit=-1 ) ), \ |
---|
426 | ## do not preserve or check relation between model and institution. |
---|
427 | 'institution':utils.listControl( 'institution', lrdr.getSimpleList( 'models_insts.txt', bit=1 ) ), \ |
---|
428 | 'model_id':utils.listControl( 'model_id', lrdr.getSimpleList( 'models_insts.txt', bit=0 ) ), \ |
---|
429 | 'modeling_realm':utils.listControl( 'realm', ['atmos', 'ocean', 'land', 'landIce', 'seaIce', 'aerosol', 'atmosChem', 'ocnBgchem'] ), \ |
---|
430 | 'project_id':utils.listControl( 'project_id', ['CCMI'] ) } |
---|
431 | |
---|
432 | elif self.projectV.id == 'ESA-CCI': |
---|
433 | lrdr = readVocab( 'esacci_vocabs/') |
---|
434 | cciProjectList, self.ecvMappings = lrdr.getSimpleList( 'cciProject.txt', bit=-1, options='returnMappings' ) |
---|
435 | vocabs = { 'variable':utils.mipVocab(self), \ |
---|
436 | 'version':utils.patternControl( 'version', '^(fv[0-9]+(\.[0-9]+){0,1})$', examples=['fv1.1'] ), \ |
---|
437 | 'level':utils.listControl( 'level', lrdr.getSimpleList( 'procLevel01.txt', bit=0 ) ), \ |
---|
438 | 'platform':utils.listControl( 'platforms', lrdr.getSimpleList( 'platforms.txt', bit=0), enumeration=True, split=True, splitVal=',' ), \ |
---|
439 | 'institution':utils.listControl( 'institution', lrdr.getSimpleList( 'institutions.txt', omt='last' ) ), \ |
---|
440 | 'Conventions':utils.patternControl( 'Conventions', '^CF-1.[56789](,.*){0,1}$', examples=['CF-1.6'] ), \ |
---|
441 | 'sensor':utils.listControl( 'sensors', lrdr.getSimpleList( 'sensors.txt', bit=0 ), enumeration=True, split=True, splitVal=',' ), \ |
---|
442 | 'cdm_data_type':utils.listControl( 'cdm_data_type', lrdr.getSimpleList( 'threddsDataType.txt', bit=0 ) ), \ |
---|
443 | 'time_coverage_duration':utils.patternControl( 'time_coverage_duration', 'ISO8601 duration', cls='ISO',examples=['P1Y'] ), \ |
---|
444 | 'spatial_resolution':utils.patternControl( 'spatial_resolution', '([0-9]+(.[0-9]+){0,1})[\s]*(km|m|degree).*', examples=['20km','1 km at nadir'] ), \ |
---|
445 | 'project':utils.listControl( 'project', ['Climate Change Initiative - European Space Agency','CLIPC'] ), \ |
---|
446 | 'cciProject':utils.listControl( 'cciproject', cciProjectList ), \ |
---|
447 | 'var':utils.listControl( 'var', lrdr.getSimpleList( 'variables.txt', bit=-1 ) ) \ |
---|
448 | } |
---|
449 | elif self.projectV.id == '__dummy': |
---|
450 | vocabs = { 'variable':utils.mipVocab(self,dummy=True) } |
---|
451 | else: |
---|
452 | vocabs = { 'variable':utils.mipVocab(self), \ |
---|
453 | 'driving_experiment_name':utils.listControl( 'driving_experiment_name', validCordexExperiment ), \ |
---|
454 | 'project_id':utils.listControl( 'project_id', ['CORDEX'] ), \ |
---|
455 | 'CORDEX_domain':utils.listControl( 'CORDEX_domain', validCordexDomains ), \ |
---|
456 | 'driving_model_id':utils.listControl( 'driving_model_id', validGcmNames ), \ |
---|
457 | 'driving_model_ensemble_member':utils.patternControl( 'driving_model_ensemble_member', 'r[0-9]+i[0-9]+p[0-9]+' ), \ |
---|
458 | 'rcm_version_id':utils.patternControl( 'rcm_version_id', '[a-zA-Z0-9-]+' ), \ |
---|
459 | 'model_id':utils.listControl( 'model_id', validRcmNames ), \ |
---|
460 | 'institute_id':utils.listControl( 'institute_id', validInstNames ), \ |
---|
461 | 'frequency':utils.listControl( 'frequency', validCordexFrequencies ) } |
---|
462 | |
---|
463 | self.vocabs = vocabs |
---|
464 | |
---|
465 | |
---|
466 | def setEsaCciFNType(self,id): |
---|
467 | if id in [1,2]: |
---|
468 | id1 = 1 |
---|
469 | else: |
---|
470 | id1 = id |
---|
471 | self.groupIndex = self.fnoptions['groupIndex'][id1] |
---|
472 | self.trangeIndex = self.fnoptions['trangeIndex'][id1] |
---|
473 | self.globalAttributesInFn = self.fnoptions['inFn'][id1] |
---|
474 | self.varIndex = self.fnoptions['varIndex'][id1] |
---|
475 | |
---|
476 | |
---|
477 | def copy_config(dest_dir): |
---|
478 | """ |
---|
479 | Copy the current default configuration directory into a separate directory. |
---|
480 | |
---|
481 | The directory <ceda_cc-package-dir>/config is copied to `dest_dir`. |
---|
482 | This is useful when ceda-cc is installed as a Python package and the user may |
---|
483 | not know where the config directory is stored. |
---|
484 | |
---|
485 | :param dest_dir: should be a path to a directory which does not yet exist. |
---|
486 | The configuration directory will be copied to this path. |
---|
487 | |
---|
488 | """ |
---|
489 | shutil.copytree(CC_CONFIG_DEFAULT_DIR, dest_dir) |
---|