def _build_process_type_list(self): '''Generate lists of processes organized by process type Currently, this can be 'diagnostic', 'explicit', 'implicit', or 'adjustment'.''' self.process_types = {'diagnostic': [], 'explicit': [], 'implicit': [], 'adjustment': []} for name, proc, level in walk_processes(self, topdown=self.topdown): self.process_types[proc.time_type].append(proc) self.has_process_type_list = True
def step_forward(self): '''new oop climlab... just loop through processes and add up the tendencies''' if not self.has_process_type_list: self._build_process_type_list() # First compute all strictly diagnostic processes for proc in self.process_types['diagnostic']: proc.compute() # Compute tendencies and diagnostics for all explicit processes for proc in self.process_types['explicit']: proc.compute() # Update state variables using all explicit tendencies # Tendencies are d/dt(state) -- so just multiply by timestep for forward time for proc in self.process_types['explicit']: for varname in proc.state.keys(): try: proc.state[varname] += (proc.tendencies[varname] * self.param['timestep']) except: pass # Now compute all implicit processes -- matrix inversions for proc in self.process_types['implicit']: proc.compute() for varname in proc.state.keys(): try: proc.state[varname] += proc.adjustment[varname] except: pass # Adjustment processes change the state instantaneously for proc in self.process_types['adjustment']: proc.compute() for varname, value in proc.state.iteritems(): #proc.set_state(varname, proc.adjusted_state[varname]) try: proc.state[varname] += proc.adjustment[varname] except: pass # Gather all diagnostics for name, proc, level in walk_processes(self): self.diagnostics.update(proc.diagnostics) proc._update_time()
def _build_process_type_list(self): """Generates lists of processes organized by process type. Following object attributes are generated or updated: :ivar dict process_types: a dictionary with entries: ``'diagnostic'``, ``'explicit'``, ``'implicit'`` and ``'adjustment'`` which point to a list of processes according to the process types. The ``process_types`` dictionary is created while walking through the processes with :func:`~climlab.utils.walk.walk_processes` """ self.process_types = { 'diagnostic': [], 'explicit': [], 'implicit': [], 'adjustment': [] } for name, proc, level in walk.walk_processes(self, topdown=self.topdown): self.process_types[proc.time_type].append(proc) self.has_process_type_list = True
def step_forward(self): '''Call the compute() method to get current tendencies, then apply them to update state variables.''' self.compute() # Total tendency is applied as an explicit forward timestep # (already accounting properly for order of operations in compute() ) for name, var in self.state.iteritems(): var += self.tendencies[name] * self.param['timestep'] # Update all time counters for this and all subprocesses in the tree for name, proc, level in walk_processes(self): proc._update_time()
def compute_diagnostics(self, num_iter=3): """Compute all tendencies and diagnostics, but don't update model state. By default it will call compute() 3 times to make sure all subprocess coupling is accounted for. The number of iterations can be changed with the input argument. """ for n in range(num_iter): self.compute() # Pass diagnostics up the process tree for name, proc, level in walk_processes(self, ignoreFlag=True): for diagname, value in proc.diagnostics.items(): self.__setattr__(diagname, value)
def compute_diagnostics(self, num_iter=3): """Compute all tendencies and diagnostics, but don't update model state. By default it will call compute() 3 times to make sure all subprocess coupling is accounted for. The number of iterations can be changed with the input argument. """ for n in range(num_iter): self.compute() # Pass diagnostics up the process tree for name, proc, level in walk_processes(self, ignoreFlag=True): for diagname, value in proc.diagnostics.iteritems(): self.__setattr__(diagname, value)
def _build_process_type_list(self): """Generates lists of processes organized by process type. Following object attributes are generated or updated: :ivar dict process_types: a dictionary with entries: ``'diagnostic'``, ``'explicit'``, ``'implicit'`` and ``'adjustment'`` which point to a list of processes according to the process types. The ``process_types`` dictionary is created while walking through the processes with :func:`~climlab.utils.walk.walk_processes` """ self.process_types = {'diagnostic': [], 'explicit': [], 'implicit': [], 'adjustment': []} for name, proc, level in walk_processes(self, topdown=self.topdown): self.process_types[proc.time_type].append(proc) self.has_process_type_list = True
def step_forward(self): """Updates state variables with computed tendencies. Calls the :func:`compute` method to get current tendencies for all process states. Multiplied with the timestep and added up to the state variables is updating all model states. :Example: :: >>> import climlab >>> model = climlab.EBM() >>> # checking time step counter >>> model.time['steps'] 0 >>> # stepping the model forward >>> model.step_forward() >>> # step counter increased >>> model.time['steps'] 1 """ self.compute() # Total tendency is applied as an explicit forward timestep # (already accounting properly for order of operations in compute() ) for name, var in self.state.items(): var += self.tendencies[name] * self.timestep # Update all time counters for this and all subprocesses in the tree # Also pass diagnostics up the process tree for name, proc, level in walk.walk_processes(self, ignoreFlag=True): if proc.time['active_now']: proc._update_time() for diagname, value in proc.diagnostics.items(): self.__setattr__(diagname, value)
def step_forward(self): """Updates state variables with computed tendencies. Calls the :func:`compute` method to get current tendencies for all process states. Multiplied with the timestep and added up to the state variables is updating all model states. :Example: :: >>> import climlab >>> model = climlab.EBM() >>> # checking time step counter >>> model.time['steps'] 0 >>> # stepping the model forward >>> model.step_forward() >>> # step counter increased >>> model.time['steps'] 1 """ self.compute() # Total tendency is applied as an explicit forward timestep # (already accounting properly for order of operations in compute() ) for name, var in self.state.iteritems(): var += self.tendencies[name] * self.timestep # Update all time counters for this and all subprocesses in the tree # Also pass diagnostics up the process tree for name, proc, level in walk_processes(self, ignoreFlag=True): proc._update_time() for diagname, value in proc.diagnostics.iteritems(): self.__setattr__(diagname, value)
def compute(self): """Computes the tendencies for all state variables given current state and specified input. The function first computes all diagnostic processes. They don't produce any tendencies directly but they may affect the other processes (such as change in solar distribution). Subsequently, all tendencies and diagnostics for all explicit processes are computed. Tendencies due to implicit and adjustment processes need to be calculated from a state that is already adjusted after explicit alteration. For that reason the explicit tendencies are applied to the states temporarily. Now all tendencies from implicit processes are calculated by matrix inversions and similar to the explicit tendencies, the implicit ones are applied to the states temporarily. Subsequently, all instantaneous adjustments are computed. Then the changes that were made to the states from explicit and implicit processes are removed again as this :class:`~climlab.process.time_dependent_process.TimeDependentProcess.compute()` function is supposed to calculate only tendencies and not apply them to the states. Finally, all calculated tendencies from all processes are collected for each state, summed up and stored in the dictionary ``self.tendencies``, which is an attribute of the time-dependent-process object, for which the :class:`~climlab.process.time_dependent_process.TimeDependentProcess.compute()` method has been called. **Object attributes** \n During method execution following object attributes are modified: :ivar dict tendencies: dictionary that holds tendencies for all states is calculated for current timestep through adding up tendencies from explicit, implicit and adjustment processes. :ivar dict diagnostics: process diagnostic dictionary is updated by diagnostic dictionaries of subprocesses after computation of tendencies. """ if not self.has_process_type_list: self._build_process_type_list() # First compute all strictly diagnostic processes ignored = self._compute_type('diagnostic') # Compute tendencies and diagnostics for all explicit processes tendencies_explicit = self._compute_type('explicit') # Tendencies due to implicit and adjustment processes need to be # calculated from a state that is already adjusted after explicit stuff # So apply the tendencies temporarily and then remove them again for name, var in self.state.items(): var += tendencies_explicit[name] * self.timestep # Now compute all implicit processes -- matrix inversions tendencies_implicit = self._compute_type('implicit') for name, var in self.state.items(): var += tendencies_implicit[name] * self.timestep # Finally compute all instantaneous adjustments adjustments = self._compute_type('adjustment') # The adjustment is actually ignored here because it is stored # in proc.tendencies and applied later as if it were an explicit forward step # Now remove the changes from the model state for name, var in self.state.items(): var -= ((tendencies_implicit[name] + tendencies_explicit[name]) * self.timestep) # Walk the subprocess tree and sum up all tendencies from subprocesses # By walking with topdown=False we ensure that we don't miss anything for (name, proc, level) in walk_processes(self, topdown=False): for subname, subproc in proc.subprocess.items(): for varname in subproc.tendencies: proc.tendencies[varname] += subproc.tendencies[varname]