Beispiel #1
0
class Component:
    """
    Abstract class defining methods inherited by all CliMT components.
    """
    def __init__(self, **kwargs):

        # Initialize self.Fixed (subset of self.Prognostic which will NOT be time-marched)
        if 'Fixed' in kwargs: self.Fixed = kwargs.pop('Fixed')
        else: self.Fixed = []

        # Initialize I/O
        self.Io = IO(self, **kwargs)

        # Get values from restart file, if available
        if 'RestartFile' in kwargs:
            ParamNames = Parameters().value.keys()
            FieldNames = self.Required
            kwargs = self.Io.readRestart(FieldNames, ParamNames, kwargs)

        # Initialize scalar parameters
        self.Params  = Parameters(**kwargs)

        # Frequency with which compute() will be executed
        if 'UpdateFreq' in kwargs:
            self.UpdateFreq = kwargs.pop('UpdateFreq')
        else:
            self.UpdateFreq = self.Params['dt']

        # Initialize State
        self.State = State(self, **kwargs)
        self.Grid = self.State.Grid

        # Dictionary to hold increments on prognos fields
        self.Inc = {}

        # Initialize diagnostics
        self.compute(ForcedCompute=True)

        # Create output file
        self.Io.createOutputFile(self.State, self.Params.value)

        # Write out initial state
        if not self.Io.Appending: self.write()

        # Initialize plotting facilities
        self.Plot = Plot()

        # Initialize runtime monitor
        self.Monitor = Monitor(self,**kwargs)

        # Notify user of unused input quantities
        self._checkUnused(kwargs)

        # Set some redundant attributes (mainly for backward compatibility)
        self.nlon = self.Grid['nlon']
        self.nlat = self.Grid['nlat']
        self.nlev = self.Grid['nlev']
        try: self.o3 = self.State['o3']
        except: pass

    def compute(self, ForcedCompute=False):
        """
        Updates component's diagnostics and increments
        """
        # See if it's time for an update; if not, skip rest
        if not ForcedCompute:
            freq = self.UpdateFreq
            time = self.State.ElapsedTime
            if int(time/freq) == int((time-self['dt'])/freq): return

        # Set up union of State, Grid and Params
        Input = {}
        for dic in [self.State.Now, self.Grid.value, self.Params.value]: Input.update(dic)
        Input['UpdateFreq'] = self.UpdateFreq

        # For implicit time stepping, replace current time level with previous (old) time level
        if self.SteppingScheme == 'implicit': Input.update(self.State.Old)

        # For semimplicit time stepping, append previous (old) time level to Input dict
        if self.SteppingScheme == 'semi-implicit':
            for key in self.Prognostic: Input[key+'old'] = self.State.Old[key]

        # List of arguments to be passed to extension
        args = [ Input[key] for key in self.ToExtension ]

        # Call extension and build dictionary of ouputs
        OutputValues = self.driver(*args)
        if len(self.FromExtension) == 1: Output = {self.FromExtension[0]: OutputValues}
        else:                            Output = dict( zip(self.FromExtension, OutputValues ) )

        # Extract increments from Output
        for key in self.Prognostic:
            self.Inc[key] = Output.pop(key+'inc')

        # Remove increments of Fixed variables
        for key in self.Fixed:
            if key in self.Inc: self.Inc.pop(key)
            if key in Output: Output.pop(key)

        # Update State
        self.State.update(Output)
        for key in Output: exec('self.'+key+'=Output[key]')

        # No further need for input dictionary
        del(Input)

    def step(self, RunLength=1, Inc={}):
        """
        Advances component one timestep and writes to output file if necessary.
        Inc is an externally-specified set of increments added to the internally-computed
        increments at each time step.
        """

        # If RunLength is integer, interpret as number of time steps
        if type(RunLength) is type(1):
            NSteps = RunLength

        # If RunLength is float, interpret as length of run in seconds
        if type(RunLength) is type(1.):
            NSteps = int(RunLength/self['dt'])

        for i in range(NSteps):
            # Add external increments
            for key in Inc.keys():
                if key in self.Inc.keys():
                    self.Inc[key] += Inc[key]
                else:
                    self.Inc[key] = Inc[key]

            # Avance prognostics 1 time step
            self.State.advance(self)

            # Bring diagnostics and increments up to date
            self.compute()

            # Bring calendar up to date
            self['calday'] += self['dt']/self['lod']
            if self['calday'] > self['daysperyear']:
                self['calday'] -= self['daysperyear']

            # Write to file, if it's time to
            dt   = self.Params['dt']
            time = self.State.ElapsedTime
            freq = self.Io.OutputFreq
            if int(time/freq) != int((time-dt)/freq): self.write()

            # Refresh monitor, if it's time to
            if self.Monitor.Monitoring:
                freq = self.Monitor.MonitorFreq
                if int(time/freq) != int((time-dt)/freq): self.Monitor.refresh(self)

    def __call__(self,**kwargs):
        """
        # Provides a simple interface to extension, useful e.g. for diagnostics.
        """
        # Re-initialize parameters, grid and state
        self.Params  = Parameters(**kwargs)
        self.State = State(self, **kwargs)
        self.Grid = self.State.Grid
        # Bring diagnostics up to date
        self.compute()

    def write(self):
        """
        Invokes write method of IO instance to write out current State
        """
        self.Io.writeOutput(self.Params, self.State)

    def open(self, OutputFileName='CliMT.nc'):
        """
        """
        if self.Io.OutputFileName == OutputFileName:
            print '\n +++ ClimT.Io: File %s is currently open for output'% OutputFileName
            return
        else:
            print 'Opening %s for output'% OutputFileName
            self.Io.OutputFileName = OutputFileName
            self.Io.DoingOutput = True
            self.Io.Appending = False
            self.Io.OutputTimeIndex = 0
            self.Io.createOutputFile(self.State, self.Params)

    def plot(self, *FieldKeys):
        self.Plot(self, *FieldKeys)

    def setFigure(self, FigureNumber=None):
        self.Plot.setFigure(FigureNumber)

    def closeFigure(self, FigureNumber=None):
        self.Plot.closeFigure(FigureNumber)

    def usage(self):
        print self.__doc__

    def report(self):
        print 'CliMT component:\n    %s' % self.Name
        keys = self.State.keys()
        keys1 = []
        for i in range(len(keys)):
            if   keys[i] in self.Prognostic: keys1.append('%12s   %s' % (keys[i],'(prognostic)'))
        for i in range(len(keys)):
            if keys[i] in self.Diagnostic: keys1.append('%12s   %s' % (keys[i],'(diagnostic)'))
        for i in range(len(keys)):
            if keys[i] not in self.Prognostic and keys[i] not in self.Diagnostic:
                                           keys1.append('%12s   %s' % (keys[i],'(Fixed)'))
        print 'State variables:\n %s' % '\n '.join( keys1 )

    def _checkUnused(self,kwargs):
        '''
        Notify of unused input quantities.
        '''
        unused = []
        io_keys = ['RestartFile','OutputFile','OutputFreq','OutputFields','ElapsedTime']
        monitor_keys = ['MonitorFields','MonitorFreq']
        for key in kwargs:
            if key not in self.Params  \
            and key not in self.Grid   \
            and key not in KnownFields \
            and key not in io_keys \
            and key not in monitor_keys:
                unused.append(key)

        if len(unused) > 0:
           if len(unused) == 1: suffix = 'y'
           else              : suffix = 'ies'
           print '\n ++++ CliMT.'+self.Name+'.initialize: WARNING: Input quantit%s %s not used.\n' \
                  % (suffix,str(list(unused)))

    def _getShape3D(self, **kwargs):
        '''
        Returns shape of 3D arrays to be passed to extension.
        '''
        return (self._getAxisLength('lev', **kwargs),
                self._getAxisLength('lat', **kwargs),
                self._getAxisLength('lon', **kwargs))


    def _getAxisLength(self, AxisName, **kwargs):
        '''
        Returns length of axis.
        '''
        # Check input
        assert AxisName in ['lev','lat','lon'], \
               '\n\n ++++ CliMT.%s: Axis name must be one of "lon", "lat", "lev"' % self.Name

        # See if axis was supplied in input
        n = None
        if AxisName in kwargs:
            if ndim(array(kwargs[AxisName])) == 0:
                n = 1
            else:
                assert ndim(array(kwargs[AxisName])) == 1, \
                    '\n\n ++++ CliMT.%s.init: input %s must be rank 1' % (self.Name,AxisName)
                n = len(array(kwargs[AxisName]))

        # If not, see if some field was supplied
        else:
            for key in kwargs:
                if key in KnownFields:
                    if KnownFields[key][2] == '2D' and AxisName != 'lev':
                        i = ['lat','lon'].index(AxisName)
                        try:    n = array(kwargs[key]).shape[i]
                        except: n = 1
                    elif KnownFields[key][2] == '3D':
                        i = ['lev','lat','lon'].index(AxisName)
                        try:    n = array(kwargs[key]).shape[i]
                        except: n = 1

        # Last resort: get dimensions set in Makefile
        if n is None: exec('n = get_n%s()' % AxisName)

        # Check if extension enforces axis dimension, ensure consistency
        try:
            exec('n_ext = self.Extension.get_n%s()' % AxisName)
        except:
            n_ext = n
        assert n_ext == n, \
            '\n\n ++++ CliMT.%s.init: input %s has dimension %i but extension requires %i'% \
            (self.Name, AxisName, n, n_ext)

        return n

    # Returns requested quantity from Params, Grid or State
    def __getitem__(self, key):
        for obj in [self.Params, self.Grid, self.State]:
            if key in obj:
                if type(obj[key]) is type('string'): return obj[key]
                else: return squeeze(obj[key])
        raise IndexError,'\n\n CliMT.State: %s not in Params, Grid or State' % str(key)

    # Sets requested quantity in Params, Grid or State
    def __setitem__(self, key, value):
        if key in self.Params:
            self.Params[key] = value
            return
        if key in self.Grid:
            self.Grid[key] = value
            return
        elif key in self.State and KnownFields[key][2] == '2D':
            self.State[key]=reshape(value,self.Grid.Shape3D[1:3])
            return
        elif key in self.State and KnownFields[key][2] == '3D':
            self.State[key]=reshape(value,self.Grid.Shape3D)
            return
        else: raise IndexError,'\n\n CliMT.State: %s not in Params, Grid or State' % str(key)
Beispiel #2
0
class federation(Component):
    """
    Combine components to create time-dependent model.

    * Instantiation:
    
      x = climt.federation(C1, C2, ..., Cn, <args> )

      where C1, ..., Cn are instances of CliMT components 
      and <args> are any keywork arguments relevant to the
      components included.

      The parameters and state of constituent components is re-initialized.

    * Running the federation:

      x.step()     will evolve the federation 1 timestep
      x.step(100)  will evolve the federation 100 timesteps
      x.step(100.) will evolve the federation 100 seconds
    """

    def __init__(self, *components, **kwargs):
        """
        """
        # Check input components
        if len(components) < 2:
            raise "\n\n +++ CliMT.federation: you must give me more than 1 component to federate!\n\n"
        else:
            for component in components:
                assert (
                    type(component) is InstanceType
                ), "\n\n +++CliMT.federation: Input item %s is not an instance.\n\n" % str(c)

        # Re-order components: diagnostic, semi-implicit, explicit, implicit
        components = list(components)
        """
        for i in range(len(components)):
            if len(components[i].Prognostic) > 0:
                components.append(components.pop(i))
        for scheme in ['semi-implicit', 'explicit', 'implicit']:
            for i in range(len(components)):
                if components[i].SteppingScheme == scheme:
                    components.append(components.pop(i))
        """
        self.components = components

        # Federation's Required is union of all components' Required;
        # same for Prognostic and Diagnostic
        self.Required = []
        self.Prognostic = []
        self.Diagnostic = []
        for component in components:
            self.Required = list(set(self.Required).union(component.Required))
            self.Prognostic = list(set(self.Prognostic).union(component.Prognostic))
            self.Diagnostic = list(set(self.Diagnostic).union(component.Diagnostic))

        # Other attributes
        self.Name = "federation"
        self.Extension = None

        # Set LevType to None if all components are None, else p
        self.LevType = None
        for component in components:
            if component.LevType == "p":
                self.LevType = "p"

        # Initialize self.Fixed (subset of self.Prognostic which will NOT be time-marched)
        if "Fixed" in kwargs:
            self.Fixed = kwargs.pop("Fixed")
        else:
            self.Fixed = []

        # Instantiate I/O
        self.Io = IO(self, **kwargs)

        # Get values from restart file, if available
        if "RestartFile" in kwargs:
            ParamNames = Parameters().value.keys()
            FieldNames = self.Required
            kwargs = self.Io.readRestart(FieldNames, ParamNames, kwargs)

        # Initialize scalar parameters
        self.Params = Parameters(**kwargs)

        # Initialize State
        self.State = State(self, **kwargs)
        self.Grid = self.State.Grid

        # Set some redundant attributes (mainly for backward compatibility)
        self.nlon = self.Grid["nlon"]
        self.nlat = self.Grid["nlat"]
        self.nlev = self.Grid["nlev"]
        try:
            self.o3 = self.State["o3"]
        except:
            pass

        # Check if components enforce axis dimensions, ensure consistency
        for component in self.components:
            for AxisName in ["lev", "lat", "lon"]:
                exec("n_fed = self.n%s" % AxisName)
                try:
                    exec("n_com = component.Extension.get_n%s()" % AxisName)
                except:
                    n_com = n_fed
                assert (
                    n_com == n_fed
                ), "\n\n ++++ CliMT.federation.init: recompile with %i %ss to run this federation\n" % (n_fed, AxisName)

        # Dictionary to hold increments on prognos fields
        self.Inc = {}

        # Adjust components' attributes
        for component in self.components:
            component.Monitoring = False
            component.Io.OutputFreq = self.Io.OutputFreq
            component.Fixed.extend(self.Fixed)
            if component.UpdateFreq == component["dt"]:
                component.UpdateFreq = self["dt"]
            component.Params = self.Params
            component.Grid = self.State.Grid
            component.State = self.State
            component.Inc = {}
            # insolation component gets special treatment because
            # of need to set orb params in common block (yes, this is ugly)
            try:
                component.setOrbParams(**kwargs)
            except:
                pass
        self.compute(ForcedCompute=True)

        # Create output file
        self.Io.createOutputFile(self.State, self.Params.value)

        # Write out initial state
        if not self.Io.Appending:
            self.write()

        # Initialize plotting facilities
        self.Plot = Plot()

        # Initialize runtime monitor
        self.Monitor = Monitor(self, **kwargs)

        # Notify user of unused input quantities
        self._checkUnused(kwargs)

        # Print out report
        # self.report()

    def compute(self, ForcedCompute=False):
        """
        Update federation's diagnostics and increments.
        """
        ## New = self.State.Old.copy()
        ## for component in self.components:
        ##     # enforce time-splitting of implicit and semi-implicit components
        ##     self.State.Old.update(New)
        ##     # bring component's diagnostics and increments up to date
        ##     component.compute(ForcedCompute=ForcedCompute)
        ##     # accumulate increments
        ##     for key in component.Inc:
        ##         New[key] += component.Inc[key]
        ## for key in self.State.Old:
        ##     self.Inc[key] = New[key]  - self.State.Old[key]

        self.Inc = self.State.Old.copy()
        for key in self.Inc:
            self.Inc[key] = self.Inc[key] * 0.0
        for component in self.components:
            # bring component's diagnostics and increments up to date
            component.compute(ForcedCompute=ForcedCompute)
            # accumulate increments
            for key in component.Inc:
                self.Inc[key] += component.Inc[key]
Beispiel #3
0
class federation(Component):
    """
    Combine components to create time-dependent model.

    * Instantiation:
    
      x = climt.federation(C1, C2, ..., Cn, <args> )

      where C1, ..., Cn are instances of CliMT components 
      and <args> are any keywork arguments relevant to the
      components included.

      The parameters and state of constituent components is re-initialized.

    * Running the federation:

      x.step()     will evolve the federation 1 timestep
      x.step(100)  will evolve the federation 100 timesteps
      x.step(100.) will evolve the federation 100 seconds
    """
    def __init__(self, *components, **kwargs):
        """
        """
        # Check input components
        if len(components) < 2:
            raise \
        '\n\n +++ CliMT.federation: you must give me more than 1 component to federate!\n\n'
        else:
            for component in components:
                assert type(component) is InstanceType, \
                '\n\n +++CliMT.federation: Input item %s is not an instance.\n\n' % str(c)

        # Re-order components: diagnostic, semi-implicit, explicit, implicit
        components = list(components)
        """
        for i in range(len(components)):
            if len(components[i].Prognostic) > 0:
                components.append(components.pop(i))
        for scheme in ['semi-implicit', 'explicit', 'implicit']:
            for i in range(len(components)):
                if components[i].SteppingScheme == scheme:
                    components.append(components.pop(i))
        """
        self.components = components

        # Federation's Required is union of all components' Required;
        # same for Prognostic and Diagnostic
        self.Required = []
        self.Prognostic = []
        self.Diagnostic = []
        for component in components:
            self.Required = list(set(self.Required).union(component.Required))
            self.Prognostic = list(
                set(self.Prognostic).union(component.Prognostic))
            self.Diagnostic = list(
                set(self.Diagnostic).union(component.Diagnostic))

        # Other attributes
        self.Name = 'federation'
        self.Extension = None

        # Set LevType to None if all components are None, else p
        self.LevType = None
        for component in components:
            if component.LevType == 'p': self.LevType = 'p'

        # Initialize self.Fixed (subset of self.Prognostic which will NOT be time-marched)
        if 'Fixed' in kwargs: self.Fixed = kwargs.pop('Fixed')
        else: self.Fixed = []

        # Instantiate I/O
        self.Io = IO(self, **kwargs)

        # Get values from restart file, if available
        if 'RestartFile' in kwargs:
            ParamNames = Parameters().value.keys()
            FieldNames = self.Required
            kwargs = self.Io.readRestart(FieldNames, ParamNames, kwargs)

        # Initialize scalar parameters
        self.Params = Parameters(**kwargs)

        # Initialize State
        self.State = State(self, **kwargs)
        self.Grid = self.State.Grid

        # Set some redundant attributes (mainly for backward compatibility)
        self.nlon = self.Grid['nlon']
        self.nlat = self.Grid['nlat']
        self.nlev = self.Grid['nlev']
        try:
            self.o3 = self.State['o3']
        except:
            pass

        # Check if components enforce axis dimensions, ensure consistency
        for component in self.components:
            for AxisName in ['lev', 'lat', 'lon']:
                exec('n_fed = self.n%s' % AxisName)
                try:
                    exec('n_com = component.Extension.get_n%s()' % AxisName)
                except:
                    n_com = n_fed
                assert n_com == n_fed, \
                '\n\n ++++ CliMT.federation.init: recompile with %i %ss to run this federation\n'\
                % (n_fed,AxisName)

        # Dictionary to hold increments on prognos fields
        self.Inc = {}

        # Adjust components' attributes
        for component in self.components:
            component.Monitoring = False
            component.Io.OutputFreq = self.Io.OutputFreq
            component.Fixed.extend(self.Fixed)
            if component.UpdateFreq == component['dt']:
                component.UpdateFreq = self['dt']
            component.Params = self.Params
            component.Grid = self.State.Grid
            component.State = self.State
            component.Inc = {}
            # insolation component gets special treatment because
            # of need to set orb params in common block (yes, this is ugly)
            try:
                component.setOrbParams(**kwargs)
            except:
                pass
        self.compute(ForcedCompute=True)

        # Create output file
        self.Io.createOutputFile(self.State, self.Params.value)

        # Write out initial state
        if not self.Io.Appending: self.write()

        # Initialize plotting facilities
        self.Plot = Plot()

        # Initialize runtime monitor
        self.Monitor = Monitor(self, **kwargs)

        # Notify user of unused input quantities
        self._checkUnused(kwargs)

        # Print out report
        #self.report()

    def compute(self, ForcedCompute=False):
        """
        Update federation's diagnostics and increments.
        """
        ## New = self.State.Old.copy()
        ## for component in self.components:
        ##     # enforce time-splitting of implicit and semi-implicit components
        ##     self.State.Old.update(New)
        ##     # bring component's diagnostics and increments up to date
        ##     component.compute(ForcedCompute=ForcedCompute)
        ##     # accumulate increments
        ##     for key in component.Inc:
        ##         New[key] += component.Inc[key]
        ## for key in self.State.Old:
        ##     self.Inc[key] = New[key]  - self.State.Old[key]

        self.Inc = self.State.Old.copy()
        for key in self.Inc:
            self.Inc[key] = self.Inc[key] * 0.
        for component in self.components:
            # bring component's diagnostics and increments up to date
            component.compute(ForcedCompute=ForcedCompute)
            # accumulate increments
            for key in component.Inc:
                self.Inc[key] += component.Inc[key]
Beispiel #4
0
class Component:
    """
    Abstract class defining methods inherited by all CliMT components.
    """
    def __init__(self, **kwargs):

        # Initialize self.Fixed (subset of self.Prognostic which will NOT be time-marched)
        if 'Fixed' in kwargs: self.Fixed = kwargs.pop('Fixed')
        else: self.Fixed = []

        # Initialize I/O
        self.Io = IO(self, **kwargs)

        # Get values from restart file, if available
        if 'RestartFile' in kwargs:
            ParamNames = Parameters().value.keys()
            FieldNames = self.Required
            kwargs = self.Io.readRestart(FieldNames, ParamNames, kwargs)

        # Initialize scalar parameters
        self.Params = Parameters(**kwargs)

        # Frequency with which compute() will be executed
        if 'UpdateFreq' in kwargs:
            self.UpdateFreq = kwargs.pop('UpdateFreq')
        else:
            self.UpdateFreq = self.Params['dt']

        # Initialize State
        self.State = State(self, **kwargs)
        self.Grid = self.State.Grid

        # Dictionary to hold increments on prognos fields
        self.Inc = {}

        # Initialize diagnostics
        self.compute(ForcedCompute=True)

        # Create output file
        self.Io.createOutputFile(self.State, self.Params.value)

        # Write out initial state
        if not self.Io.Appending: self.write()

        # Initialize plotting facilities
        self.Plot = Plot()

        # Initialize runtime monitor
        self.Monitor = Monitor(self, **kwargs)

        # Notify user of unused input quantities
        self._checkUnused(kwargs)

        # Set some redundant attributes (mainly for backward compatibility)
        self.nlon = self.Grid['nlon']
        self.nlat = self.Grid['nlat']
        self.nlev = self.Grid['nlev']
        try:
            self.o3 = self.State['o3']
        except:
            pass

    def compute(self, ForcedCompute=False):
        """
        Updates component's diagnostics and increments
        """
        # See if it's time for an update; if not, skip rest
        if not ForcedCompute:
            freq = self.UpdateFreq
            time = self.State.ElapsedTime
            if int(time / freq) == int((time - self['dt']) / freq): return

        # Set up union of State, Grid and Params
        Input = {}
        for dic in [self.State.Now, self.Grid.value, self.Params.value]:
            Input.update(dic)
        Input['UpdateFreq'] = self.UpdateFreq

        # For implicit time stepping, replace current time level with previous (old) time level
        if self.SteppingScheme == 'implicit': Input.update(self.State.Old)

        # For semimplicit time stepping, append previous (old) time level to Input dict
        if self.SteppingScheme == 'semi-implicit':
            for key in self.Prognostic:
                Input[key + 'old'] = self.State.Old[key]

        # List of arguments to be passed to extension
        args = [Input[key] for key in self.ToExtension]

        # Call extension and build dictionary of ouputs
        OutputValues = self.driver(*args)
        if len(self.FromExtension) == 1:
            Output = {self.FromExtension[0]: OutputValues}
        else:
            Output = dict(zip(self.FromExtension, OutputValues))

        # Extract increments from Output
        for key in self.Prognostic:
            self.Inc[key] = Output.pop(key + 'inc')

        # Remove increments of Fixed variables
        for key in self.Fixed:
            if key in self.Inc: self.Inc.pop(key)
            if key in Output: Output.pop(key)

        # Update State
        self.State.update(Output)
        for key in Output:
            exec('self.' + key + '=Output[key]')

        # No further need for input dictionary
        del (Input)

    def step(self, RunLength=1, Inc={}):
        """
        Advances component one timestep and writes to output file if necessary.
        Inc is an externally-specified set of increments added to the internally-computed
        increments at each time step. 
        """

        # If RunLength is integer, interpret as number of time steps
        if type(RunLength) is type(1):
            NSteps = RunLength

        # If RunLength is float, interpret as length of run in seconds
        if type(RunLength) is type(1.):
            NSteps = int(RunLength / self['dt'])

        for i in range(NSteps):
            # Add external increments
            for key in Inc.keys():
                if key in self.Inc.keys():
                    self.Inc[key] += Inc[key]
                else:
                    self.Inc[key] = Inc[key]

            # Avance prognostics 1 time step
            self.State.advance(self)

            # Bring diagnostics and increments up to date
            self.compute()

            # Bring calendar up to date
            self['calday'] += self['dt'] / self['lod']
            if self['calday'] > self['daysperyear']:
                self['calday'] -= self['daysperyear']

            # Write to file, if it's time to
            dt = self.Params['dt']
            time = self.State.ElapsedTime
            freq = self.Io.OutputFreq
            if int(time / freq) != int((time - dt) / freq): self.write()

            # Refresh monitor, if it's time to
            if self.Monitor.Monitoring:
                freq = self.Monitor.MonitorFreq
                if int(time / freq) != int((time - dt) / freq):
                    self.Monitor.refresh(self)

    def __call__(self, **kwargs):
        """
        # Provides a simple interface to extension, useful e.g. for diagnostics. 
        """
        # Re-initialize parameters, grid and state
        self.Params = Parameters(**kwargs)
        self.State = State(self, **kwargs)
        self.Grid = self.State.Grid
        # Bring diagnostics up to date
        self.compute()

    def write(self):
        """
        Invokes write method of IO instance to write out current State
        """
        self.Io.writeOutput(self.Params, self.State)

    def open(self, OutputFileName='CliMT.nc'):
        """
        """
        if self.Io.OutputFileName == OutputFileName:
            print '\n +++ ClimT.Io: File %s is currently open for output' % OutputFileName
            return
        else:
            print 'Opening %s for output' % OutputFileName
            self.Io.OutputFileName = OutputFileName
            self.Io.DoingOutput = True
            self.Io.Appending = False
            self.Io.OutputTimeIndex = 0
            self.Io.createOutputFile(self.State, self.Params)

    def plot(self, *FieldKeys):
        self.Plot(self, *FieldKeys)

    def setFigure(self, FigureNumber=None):
        self.Plot.setFigure(FigureNumber)

    def closeFigure(self, FigureNumber=None):
        self.Plot.closeFigure(FigureNumber)

    def usage(self):
        print self.__doc__

    def report(self):
        print 'CliMT component:\n    %s' % self.Name
        keys = self.State.keys()
        keys1 = []
        for i in range(len(keys)):
            if keys[i] in self.Prognostic:
                keys1.append('%12s   %s' % (keys[i], '(prognostic)'))
        for i in range(len(keys)):
            if keys[i] in self.Diagnostic:
                keys1.append('%12s   %s' % (keys[i], '(diagnostic)'))
        for i in range(len(keys)):
            if keys[i] not in self.Prognostic and keys[
                    i] not in self.Diagnostic:
                keys1.append('%12s   %s' % (keys[i], '(Fixed)'))
        print 'State variables:\n %s' % '\n '.join(keys1)

    def _checkUnused(self, kwargs):
        '''
        Notify of unused input quantities.
        '''
        unused = []
        io_keys = [
            'RestartFile', 'OutputFile', 'OutputFreq', 'OutputFields',
            'ElapsedTime'
        ]
        monitor_keys = ['MonitorFields', 'MonitorFreq']
        for key in kwargs:
            if key not in self.Params  \
            and key not in self.Grid   \
            and key not in KnownFields \
            and key not in io_keys \
            and key not in monitor_keys:
                unused.append(key)

        if len(unused) > 0:
            if len(unused) == 1: suffix = 'y'
            else: suffix = 'ies'
            print '\n ++++ CliMT.'+self.Name+'.initialize: WARNING: Input quantit%s %s not used.\n' \
                   % (suffix,str(list(unused)))

    def _getShape3D(self, **kwargs):
        '''
        Returns shape of 3D arrays to be passed to extension.
        '''
        return (self._getAxisLength('lev', **kwargs),
                self._getAxisLength('lat', **kwargs),
                self._getAxisLength('lon', **kwargs))

    def _getAxisLength(self, AxisName, **kwargs):
        '''
        Returns length of axis.
        '''
        # Check input
        assert AxisName in ['lev','lat','lon'], \
               '\n\n ++++ CliMT.%s: Axis name must be one of "lon", "lat", "lev"' % self.Name

        # See if axis was supplied in input
        n = None
        if AxisName in kwargs:
            if rank(array(kwargs[AxisName])) == 0:
                n = 1
            else:
                assert rank(array(kwargs[AxisName])) == 1, \
                    '\n\n ++++ CliMT.%s.init: input %s must be rank 1' % (self.Name,AxisName)
                n = len(array(kwargs[AxisName]))

        # If not, see if some field was supplied
        else:
            for key in kwargs:
                if key in KnownFields:
                    if KnownFields[key][2] == '2D' and AxisName != 'lev':
                        i = ['lat', 'lon'].index(AxisName)
                        try:
                            n = array(kwargs[key]).shape[i]
                        except:
                            n = 1
                    elif KnownFields[key][2] == '3D':
                        i = ['lev', 'lat', 'lon'].index(AxisName)
                        try:
                            n = array(kwargs[key]).shape[i]
                        except:
                            n = 1

        # Last resort: get dimensions set in Makefile
        if n is None: exec('n = get_n%s()' % AxisName)

        # Check if extension enforces axis dimension, ensure consistency
        try:
            exec('n_ext = self.Extension.get_n%s()' % AxisName)
        except:
            n_ext = n
        assert n_ext == n, \
            '\n\n ++++ CliMT.%s.init: input %s has dimension %i but extension requires %i'% \
            (self.Name, AxisName, n, n_ext)

        return n

    # Returns requested quantity from Params, Grid or State
    def __getitem__(self, key):
        for obj in [self.Params, self.Grid, self.State]:
            if key in obj:
                if type(obj[key]) is type('string'): return obj[key]
                else: return squeeze(obj[key])
        raise IndexError, '\n\n CliMT.State: %s not in Params, Grid or State' % str(
            key)

    # Sets requested quantity in Params, Grid or State
    def __setitem__(self, key, value):
        if key in self.Params:
            self.Params[key] = value
            return
        if key in self.Grid:
            self.Grid[key] = value
            return
        elif key in self.State and KnownFields[key][2] == '2D':
            self.State[key] = reshape(value, self.Grid.Shape3D[1:3])
            return
        elif key in self.State and KnownFields[key][2] == '3D':
            self.State[key] = reshape(value, self.Grid.Shape3D)
            return
        else:
            raise IndexError, '\n\n CliMT.State: %s not in Params, Grid or State' % str(
                key)