From c991da3c52a03c1d3736e1377d54382fc06ff73e Mon Sep 17 00:00:00 2001
From: Wouter Peters <wouter.peters@wur.nl>
Date: Thu, 13 Jun 2013 13:09:04 +0000
Subject: [PATCH] sf6 code to be updated

---
 da/sf6/__init__.py    |   0
 da/sf6/statevector.py | 192 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 192 insertions(+)
 create mode 100644 da/sf6/__init__.py
 create mode 100755 da/sf6/statevector.py

diff --git a/da/sf6/__init__.py b/da/sf6/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/da/sf6/statevector.py b/da/sf6/statevector.py
new file mode 100755
index 00000000..ddebf759
--- /dev/null
+++ b/da/sf6/statevector.py
@@ -0,0 +1,192 @@
+#!/usr/bin/env python
+# ct_statevector_tools.py
+
+"""
+Author : peters 
+
+Revision History:
+File created on 28 Jul 2010.
+
+"""
+
+import os
+import sys
+sys.path.append(os.getcwd())
+
+import logging
+from da.baseclasses.statevector import StateVector
+import numpy as np
+import da.tools.io4 as io
+
+identifier = 'SF6 Statevector '
+version = '0.0'
+
+################### Begin Class SF6StateVector ###################
+
+class SF6StateVector(StateVector):
+    """ This is a StateVector object for CarbonTracker. It has a private method to make new ensemble members """
+
+    def get_covariance(self, date):
+        """ Make a new ensemble from specified matrices, the attribute lag refers to the position in the state vector. 
+            Note that lag=1 means an index of 0 in python, hence the notation lag-1 in the indexing below.
+            The argument is thus referring to the lagged state vector as [1,2,3,4,5,..., nlag]
+        """    
+
+        import da.tools.io4 as io
+        try:
+            import matplotlib.pyplot as plt
+        except:
+            pass
+
+        # Get the needed matrices from the specified covariance files
+
+        fullcov = np.zeros((self.nparams, self.nparams), float)
+
+        fullcov[:,:] = 0.2**2
+
+        return fullcov
+
+    def Initialize(self):
+        """
+        Initialize the object by specifying the dimensions. 
+        There are two major requirements for each statvector that you want to build:
+        
+            (1) is that the statevector can map itself onto a regular grid
+            (2) is that the statevector can map itself (mean+covariance) onto TransCom regions
+
+        An example is given below.
+        """
+
+        self.nlag = int(self.DaCycle['time.nlag'])
+        self.nmembers = int(self.DaCycle['da.optimizer.nmembers'])
+        self.nparams = int(self.DaCycle.DaSystem['nparameters'])
+        self.nobs = 0
+        
+        self.isOptimized = False
+        self.ObsToAssimmilate = ()  # empty containter to hold observations to assimilate later on
+
+        # These list objects hold the data for each time step of lag in the system. Note that the ensembles for each time step consist 
+        # of lists of EnsembleMember objects, we define member 0 as the mean of the distribution and n=1,...,nmembers as the spread.
+
+        self.EnsembleMembers = range(self.nlag)
+
+        for n in range(self.nlag):
+            self.EnsembleMembers[n] = []
+
+
+        # This specifies the file to read with the gridded mask at 1x1 degrees. Each gridbox holds a number that specifies the parametermember
+        #  that maps onto it. From this map, a dictionary is created that allows a reverse look-up so that we can map parameters to a grid.
+
+        mapfile = os.path.join(self.DaCycle.DaSystem['regionsfile'])
+        ncf = io.CT_Read(mapfile, 'read')
+        self.tcmap = ncf.GetVariable('transcom_regions')
+        ncf.close()
+
+        self.gridmap = np.ones((180,360),'float')
+
+        logging.debug("A TransCom  map on 1x1 degree was read from file %s" % self.DaCycle.DaSystem['regionsfile'])
+        logging.debug("A parameter map on 1x1 degree was created")
+
+        # Create a dictionary for state <-> gridded map conversions
+
+        nparams = self.gridmap.max()
+        self.griddict = {}
+        for r in range(1, nparams + 1):
+            sel = (self.gridmap.flat == r).nonzero()
+            if len(sel[0]) > 0: 
+                self.griddict[r] = sel
+
+        logging.debug("A dictionary to map grids to states and vice versa was created")
+
+        # Create a matrix for state <-> TransCom conversions
+
+        self.tcmatrix = np.zeros((self.nparams, 23), 'float') 
+
+        logging.debug("A matrix to map states to TransCom regions and vice versa was created")
+
+        # Create a mask for species/unknowns
+
+        self.make_species_mask()
+
+    def make_species_mask(self):
+
+        """
+
+        This method creates a dictionary with as key the name of a tracer, and as values an array of 0.0/1.0 values 
+        specifying which StateVector elements are constrained by this tracer. This mask can be used in 
+        the optimization to ensure that certain types of osbervations only update certain unknowns.
+
+        An example would be that the tracer '14CO2' can be allowed to only map onto fossil fuel emissions in the state
+
+        The form of the mask is:
+
+        {'co2': np.ones(self.nparams), 'co2c14', np.zeros(self.nparams)  }
+
+        so that 'co2' maps onto all parameters, and 'co2c14' on none at all. These arrays are used in the Class 
+        optimizer when state updates are actually performed
+
+        """
+        self.speciesdict = {'sf6': np.ones(self.nparams)}
+        logging.debug("A species mask was created, only the following species are recognized in this system:")
+        for k in self.speciesdict.keys(): 
+            logging.debug("   ->    %s" % k)
+
+    def propagate(self):
+        """ 
+        :rtype: None
+
+        Propagate the parameter values in the StateVector to the next cycle. This means a shift by one cycle 
+        step for all states that will
+        be optimized once more, and the creation of a new ensemble for the time step that just 
+        comes in for the first time (step=nlag). 
+        In the future, this routine can incorporate a formal propagation of the statevector.
+
+        """
+        from datetime import timedelta
+
+        ensemble_deviations = np.array([p.ParameterValues for p in self.EnsembleMembers[0] ])
+        if ensemble_deviations.std(axis=0) < 0.05 :
+            for m in self.EnsembleMembers[0]:
+                m  = 3.0 * m  # inflate deviations by a factor of 3.0
+
+            logging.info('The state vector covariance was inflated to 1-sigma of %5.2f ' % (ensemble_deviations.std(axis=0)*3.0))
+
+        logging.info('The state vector remains the same in the SF6 run')
+        logging.info('The state vector has been propagated by one cycle')
+
+
+################### End Class SF6StateVector ###################
+
+
+if __name__ == "__main__":
+    from da.tools.initexit import StartLogger 
+    from da.tools.pipeline import start_job
+
+    sys.path.append(os.getcwd())
+
+    opts = ['-v']
+    args = {'rc':'da.rc', 'logfile':'da_initexit.log', 'jobrcfilename':'test.rc'}
+
+    StartLogger()
+
+    DaCycle = start_job(opts, args)
+
+    DaCycle.Initialize()
+
+    StateVector = CtStateVector()
+
+    StateVector.Initialize()
+
+    for n in range(dims[0]):
+        cov = StateVector.get_covariance()
+        dummy = StateVector.make_new_ensemble(n + 1, cov)
+
+    StateVector.propagate()
+
+    savedir = DaCycle['dir.output']
+    filename = os.path.join(savedir, 'savestate.nc')
+
+    dummy = StateVector.WriteToFile()
+
+    StateVector.ReadFromFile(filename)
+
-- 
GitLab