Write a netCDF file using a data structure.
        
        :parameter data: data structure
        :parameter outfile: output file
        :keyword clobber: erase file if it already exists
        :keyword format: NetCDF file format.
        
        .. note :: the data structure requires a "_dimensions" field (dimension structure)

def write(self, data, outfile, clobber=False,format='NETCDF4'):
        '''
        Write a netCDF file using a data structure.
        
        :parameter data: data structure
        :parameter outfile: output file
        :keyword clobber: erase file if it already exists
        :keyword format: NetCDF file format.
        
        .. note :: the data structure requires a "_dimensions" field (dimension structure)
        '''
        
        #Open file
        if self.verbose == 1 : self.message(1, 'Writing data file {}'.format(os.path.basename(outfile)))
        elif self.verbose > 1 : self.message(2, 'Writing data file {}'.format(outfile))
        root_grp=ncfile(outfile, 'w', format=format, clobber=clobber)
#        root_grp.description = 'nctools.write() file'
        
        #Get attributes
        if data.has_key('_attributes'):
            self.message(2, 'Adding attributes data')
            attrStr=data.pop('_attributes')
            self.message(4, 'Attribute list (N={0}) :[{1}]'.format(len(attrStr.keys()), ','.join(attrStr.keys())) )
            root_grp.setncatts(attrStr)
        
        #Get dimensions
        dimDict=data.pop('_dimensions')
        ndims=dimDict.pop('_ndims')
        dimlist = dimDict.keys()
        dimVal = dimDict.values()
        
        #Get variables
        parlist = data.keys()
        
        
        # Set up dimensions
        
        #Put dimensions
        for d in dimlist :
            self.message(2, 'Adding D {0}={1}'.format(d,dimDict[d]))
            root_grp.createDimension(d, dimDict[d])
        
#        if data.has_key('p')  : self.Error('Variable name \'p\' is not available for use as NetCDF variable name')
        
        #Loop over variables
        for p in parlist :
            
            self.message(4,'Looping parameter list : %s' %p)
            
            #Get dimensions for current variable
            if not data[p].has_key('_dimensions') : warn('_dimension attribute is not set for variable'+p)
            pardim=data[p].pop('_dimensions') if data[p].has_key('_dimensions') else dimStr()
            if isinstance(pardim,dimStr) : pardim=tuple(pardim.keys())
            elif isinstance(pardim,dict) :pardim=tuple(pardim.keys()[1:]) if pardim.has_key("_ndims") else tuple(pardim.keys())
            elif isinstance(pardim,list) : pardim = tuple(pardim)
            elif isinstance(pardim,tuple) : pass
            else : self.Error('_dimensions must be dict, list or tuple - not {0}'.type(pardim))
            
            #Convert to numpy array if scalar or non numpy
            if not hasattr(data[p]['data'],'__iter__') or not hasattr(data[p]['data'], 'dtype'):  data[p]['data']=np.array(data[p]['data'])

            #Get _FillValue if possible
#            if hasattr(data[p]['data'],'fill_value') : data[p]['_FillValue']=data[p]['data'].fill_value 

#            if not (data[p]['data'].dtype == '|S6') and not (data[p]['data'].dtype == '|S2') :
            self.message(2, 'Adding V {0} (dims={{{1}}},attr={{{2}}})'.
                         format(p,
                                ', '.join(['\'{0}\':{1}'.format(d,dimDict[d]) for d in pardim]),
                                ', '.join(['\'{0}\':{1}'.format(d,data[p][d]) for d in data[p].keys() if (d != '_dimensions') and (d != 'data')]) )
                         )
            
            if locals().has_key(p) : self.Error('Variable name \'{0}\' is already declared - change variable name'.format(p))
            
            #Scale it back
            ##############
            
            #look at scaler factors and offsets in both attributes and data structure keys
            scale_factor=scale_factor=data[p].get('scale_factor',None)
            if scale_factor is None : scale_factor=data[p].get('scale',None)
            if scale_factor is None and hasattr(data[p]['data'],'__dict__') : scale_factor=data[p]['data'].__dict__.get('scale_factor',None)  
            if scale_factor is None and hasattr(data[p]['data'],'__dict__') : scale_factor=data[p]['data'].__dict__.get('scale',None) 
            
            
            offset=data[p].get('add_offset',None) 
            if offset is None and hasattr(data[p]['data'],'__dict__') : offset=data[p]['data'].__dict__.get('add_offset',None)
            
            #Apply scaling and prepare message
            scale_msg='Apply scaling : {}'.format(p)
            if scale_factor is not None :
                data[p]['data'] = data[p]['data'] / scale_factor
                scale_msg+=' / {0}'.format(scale_factor)
            if offset is not None :
                data[p]['data'] = data[p]['data'] - offset
                scale_msg+=' - {0}'.format(offset)
            
            #show message
            if scale_factor is not None or offset is not None :
                self.message(2,scale_msg)
            
            #Apply fill_value as argument to createVariable function
            if hasattr(data[p]['data'],'fill_value') :
                locals()[p] = root_grp.createVariable(p,
                                               data[p]['data'].dtype if not str(data[p]['data'].dtype).startswith('|S') else 'S1',
                                               pardim,
                                               fill_value=data[p]['data'].fill_value)
            else :
                locals()[p] = root_grp.createVariable(p,
                                               data[p]['data'].dtype if not str(data[p]['data'].dtype).startswith('|S') else 'S1',
                                               pardim)
            
            #Get data and compare to current dimensions
            dumVar=data[p].pop('data')
            ncsh=tuple([long(dimVal[dimlist.index(d)]) for d in pardim if d in dimlist])
            ncdimname=tuple([d for d in pardim if d in dimlist])
            
            #Transposition is done if provided dimensions is not in phase with data dimensions (and if provided dimensions has no unlimited dimensions)
            if not ncsh == dumVar.shape and ncsh.count(0) == 0:
                dimOrder=tuple([ncsh.index(dsh) for dsh in dumVar.shape if dsh in ncsh])
                self.message(2, 'Transposing data axes {0}{1}'.format(ncdimname,dimOrder)) #Make it a bit more explicit...
                if len(dimOrder) > 0:
                    dumVar=dumVar.transpose(dimOrder)
            
            #Transpose data before writing it into file
            locals()[p][:]=dumVar
            #.transpose(tuple(range(len(pardim))[::-1])) #old stuff
                
            #Update with attribute list
            attrDict=locals()[p].__dict__
            attrDict.update(data[p])
            [attrDict.pop(k) for k in  locals()[p].__dict__.keys()]
            
            
            #Get common attributes first
            attrDict.pop('_FillValue',None)
            locals()[p].setncatts(attrDict)
#            for a in attrDict :
#                if not hasattr(locals()[p],a) :
#                    locals()[p].setncattr(a,data[p][a])
        
        self.message(2, 'Closing file')
        root_grp.close()

        return True