Ignore:
Timestamp:
10/21/22 11:51:59 (3 years ago)
Author:
vverjans
Message:

NEW piecewise polynomials implemented in ARMA model schemes

File:
1 edited

Legend:

Unmodified
Added
Removed
  • issm/trunk-jpl/src/m/classes/SMBarma.py

    r27260 r27318  
    1616    def __init__(self, *args):  # {{{
    1717        self.num_basins = 0
    18         self.const = np.nan
    19         self.trend = np.nan
     18        self.num_params = 0
     19        self.num_breaks = 0
     20        self.polynomialparams = np.nan
    2021        self.ar_order = 0
    21         self.arma_initialtime = 0
    22         self.arma_timestep = 0
    2322        self.arlag_coefs = np.nan
    2423        self.malag_coefs = np.nan
     
    4241        s += '{}\n'.format(fielddisplay(self, 'num_basins', 'number of different basins [unitless]'))
    4342        s += '{}\n'.format(fielddisplay(self, 'basin_id', 'basin number assigned to each element [unitless]'))
    44         s += '{}\n'.format(fielddisplay(self, 'const', 'basin-specific constant values [m ice eq./yr]'))
    45         s += '{}\n'.format(fielddisplay(self, 'trend', 'basin-specific trend values [m ice eq. yr^(-2)]'))
     43        s += '{}\n'.format(fielddisplay(self, 'num_breaks', 'number of different breakpoints in the piecewise-polynomial (separating num_breaks+1 periods)'))
     44        s += '{}\n'.format(fielddisplay(self, 'num_params', 'number of different parameters in the piecewise-polynomial (1:intercept only, 2:with linear trend, 3:with quadratic trend, etc.)'))
     45        s += '{}\n'.format(fielddisplay(self, 'polynomialparams', 'coefficients for the polynomial (const,trend,quadratic,etc.),dim1 for basins,dim2 for periods,dim3 for orders, ex: polyparams=cat(num_params,intercepts,trendlinearcoefs,trendquadraticcoefs)'))
     46        s += '{}\n'.format(fielddisplay(self, 'datebreaks', 'dates at which the breakpoints in the piecewise polynomial occur (1 row per basin) [yr]'))
    4647        s += '{}\n'.format(fielddisplay(self, 'ar_order', 'order of the autoregressive model [unitless]'))
    4748        s += '{}\n'.format(fielddisplay(self, 'ma_order', 'order of the moving-average model [unitless]'))
    48         s += '{}\n'.format(fielddisplay(self, 'arma_initialtime', 'initial time assumed in the autoregressive model parameterization [yr]'))
    4949        s += '{}\n'.format(fielddisplay(self, 'arma_timestep', 'time resolution of the ARMA model [yr]'))
    5050        s += '{}\n'.format(fielddisplay(self, 'arlag_coefs', 'basin-specific vectors of AR lag coefficients [unitless]'))
     
    8383            self.arlag_coefs = np.zeros((self.num_basins, self.ar_order)) # Autoregression coefficients all set to 0
    8484            print('      smb.ar_order (order of autoregressive model) not specified: order of autoregressive model set to 0')
    85         if self.arma_initialtime == 0:
    86             self.arma_initialtime = md.timestepping.start_time # ARMA model has no prescribed initial time
    87             print('      smb.arma_initialtime (initial time in the ARMA model parameterization) not specified: set to md.timestepping.start_time')
    8885        if self.arma_timestep == 0:
    8986            self.arma_timestep = md.timestepping.time_step # ARMA model has no prescribed time step
     
    10097    def checkconsistency(self, md, solution, analyses):  # {{{
    10198        if 'MasstransportAnalysis' in analyses:
     99            nbas = md.smb.num_basins;
     100            nprm = md.smb.num_params;
     101            nbrk = md.smb.num_breaks;
    102102            md = checkfield(md, 'fieldname', 'smb.num_basins', 'numel', 1, 'NaN', 1, 'Inf', 1, '>', 0)
     103            md = checkfield(md, 'fieldname', 'smb.num_params', 'numel', 1, 'NaN', 1, 'Inf', 1, '>', 0)
     104            md = checkfield(md, 'fieldname', 'smb.num_breaks', 'numel', 1, 'NaN', 1, 'Inf', 1, '>=', 0)
    103105            md = checkfield(md, 'fieldname', 'smb.basin_id', 'Inf', 1, '>=', 0, '<=', md.smb.num_basins, 'size', [md.mesh.numberofelements])
    104             if len(np.shape(self.const)) == 1:
    105                 self.const = np.array([self.const])
    106                 self.trend = np.array([self.trend])
    107             md = checkfield(md, 'fieldname', 'smb.const', 'NaN', 1, 'Inf', 1, 'size', [1, md.smb.num_basins], 'numel', md.smb.num_basins) # Scheme fails if passed as column vector
    108             md = checkfield(md, 'fieldname', 'smb.trend', 'NaN', 1, 'Inf', 1, 'size', [1, md.smb.num_basins], 'numel', md.smb.num_basins) # Scheme fails if passed as column vector; NOTE: As opposed to MATLAB implementation, pass list
     106            if len(np.shape(self.polynomialparams)) == 1:
     107                self.polynomialparams = np.array([[self.polynomialparams]])
     108            if(nbas>1 and nbrk>=1 and nprm>1):
     109                md = checkfield(md,'fieldname','smb.polynomialparams','NaN',1,'Inf',1,'size',[nbas,nbrk+1,nprm],'numel',nbas*(nbrk+1)*nprm)
     110            elif(nbas==1):
     111                md = checkfield(md,'fieldname','smb.polynomialparams','NaN',1,'Inf',1,'size',[nprm,nbrk+1],'numel',nbas*(nbrk+1)*nprm)
     112            elif(nbrk==0):
     113                md = checkfield(md,'fieldname','smb.polynomialparams','NaN',1,'Inf',1,'size',[nbas,nprm],'numel',nbas*(nbrk+1)*nprm)
     114            elif(nprm==1):
     115                md = checkfield(md,'fieldname','smb.polynomialparams','NaN',1,'Inf',1,'size',[nbas,nbrk],'numel',nbas*(nbrk+1)*nprm)
    109116            md = checkfield(md, 'fieldname', 'smb.ar_order', 'numel', 1, 'NaN', 1, 'Inf', 1, '>=', 0)
    110             md = checkfield(md, 'fieldname', 'smb.arma_initialtime', 'numel', 1, 'NaN', 1, 'Inf', 1)
    111117            md = checkfield(md, 'fieldname', 'smb.arma_timestep', 'numel', 1, 'NaN', 1, 'Inf', 1, '>=', md.timestepping.time_step) # Autoregression time step cannot be finer than ISSM timestep
    112118            md = checkfield(md, 'fieldname', 'smb.arlag_coefs', 'NaN', 1, 'Inf', 1, 'size', [md.smb.num_basins, md.smb.ar_order])
    113119            md = checkfield(md, 'fieldname', 'smb.malag_coefs', 'NaN', 1, 'Inf', 1, 'size', [md.smb.num_basins, md.smb.ma_order])
    114            
     120            if(nbrk>0):
     121                md = checkfield(md, 'fieldname', 'smb.datebreaks', 'NaN', 1, 'Inf', 1, 'size', [nbas,nbrk])
     122            elif(np.size(md.smb.datebreaks)==0 or np.all(np.isnan(md.smb.datebreaks))):
     123                pass
     124            else:
     125                raise RuntimeError('md.smb.num_breaks is 0 but md.smb.datebreaks is not empty')
     126
    115127            if(np.any(np.isnan(self.refelevation) is False) or np.size(self.refelevation) > 1):
    116128                if len(np.shape(self.refelevation)) == 1:
     
    149161    def marshall(self, prefix, md, fid):  # {{{
    150162        yts = md.constants.yts
    151 
     163        nbas = md.smb.num_basins;
     164        nprm = md.smb.num_params;
     165        nper = md.smb.num_breaks+1;
    152166        templapserates    = np.copy(md.smb.lapserates)
    153167        tempelevationbins = np.copy(md.smb.elevationbins)
    154168        temprefelevation  = np.copy(md.smb.refelevation)
     169        # Scale the parameters #
     170        polyparamsScaled   = np.copy(md.smb.polynomialparams)
     171        polyparams2dScaled = np.zeros((nbas,nper*nprm))
     172        if(nprm>1):
     173            # Case 3D #
     174            if(nbas>1 and nper>1):
     175                for ii in range(nprm):
     176                    polyparamsScaled[:,:,ii] = polyparamsScaled[:,:,ii]*(1/yts)**(ii+1)
     177                # Fit in 2D array #
     178                for ii in range(nprm):
     179                    polyparams2dScaled[:,ii*nper:(ii+1)*nper] = 1*polyparamsScaled[:,:,ii]
     180            # Case 2D and higher-order params at increasing row index #
     181            elif(nbas==1):
     182                for ii in range(nprm):
     183                    polyparamsScaled[ii,:] = polyparamsScaled[ii,:]*(1/yts)**(ii+1)
     184                # Fit in row array #
     185                for ii in range(nprm):
     186                    polyparams2dScaled[0,ii*nper:(ii+1)*nper] = 1*polyparamsScaled[ii,:]
     187            # Case 2D and higher-order params at incrasing column index #
     188            elif(nper==1):
     189                for ii in range(nprm):
     190                    polyparamsScaled[:,ii] = polyparamsScaled[:,ii]*(1/yts)**(ii+1)
     191                # 2D array is already in correct format #
     192                polyparams2dScaled = np.copy(polyparamsScaled)
     193        else:
     194            polyparamsScaled   = polyparamsScaled*(1/yts)
     195            # 2D array is already in correct format #
     196            polyparams2dScaled = np.copy(polyparamsScaled)
     197       
     198        if(nper==1):
     199            dbreaks = np.zeros((nbas,1))
     200        else:
     201            dbreaks = np.copy(md.smb.datebreaks)
     202
    155203        if(np.any(np.isnan(md.smb.lapserates))):
    156204            templapserates = np.zeros((md.smb.num_basins,2))
     
    172220        WriteData(fid, prefix, 'name', 'md.smb.model', 'data', 13, 'format', 'Integer')
    173221        WriteData(fid, prefix, 'object', self, 'class', 'smb', 'fieldname', 'num_basins', 'format', 'Integer')
     222        WriteData(fid, prefix, 'object', self, 'class', 'smb', 'fieldname', 'num_breaks', 'format', 'Integer')
     223        WriteData(fid, prefix, 'object', self, 'class', 'smb', 'fieldname', 'num_params', 'format', 'Integer')
    174224        WriteData(fid, prefix, 'object', self, 'class', 'smb', 'fieldname', 'ar_order', 'format', 'Integer')
    175225        WriteData(fid, prefix, 'object', self, 'class', 'smb', 'fieldname', 'ma_order', 'format', 'Integer')
    176         WriteData(fid, prefix, 'object', self, 'class', 'smb', 'fieldname', 'arma_initialtime', 'format', 'Double', 'scale', yts)
    177226        WriteData(fid, prefix, 'object', self, 'class', 'smb', 'fieldname', 'arma_timestep', 'format', 'Double', 'scale', yts)
    178227        WriteData(fid, prefix, 'object', self, 'class', 'smb', 'fieldname', 'basin_id', 'data', self.basin_id - 1, 'name', 'md.smb.basin_id', 'format', 'IntMat', 'mattype', 2)  # 0-indexed
    179         WriteData(fid, prefix, 'object', self, 'class', 'smb', 'fieldname', 'const', 'format', 'DoubleMat', 'name', 'md.smb.const', 'scale', 1 / yts, 'yts', yts)
    180         WriteData(fid, prefix, 'object', self, 'class', 'smb', 'fieldname', 'trend', 'format', 'DoubleMat', 'name', 'md.smb.trend', 'scale', 1 / (yts ** 2), 'yts', yts)
     228        WriteData(fid, prefix, 'data', polyparams2dScaled, 'name', 'md.smb.polynomialparams', 'format', 'DoubleMat')
    181229        WriteData(fid, prefix, 'object', self, 'class', 'smb', 'fieldname', 'arlag_coefs', 'format', 'DoubleMat', 'name', 'md.smb.arlag_coefs', 'yts', yts)
    182230        WriteData(fid, prefix, 'object', self, 'class', 'smb', 'fieldname', 'malag_coefs', 'format', 'DoubleMat', 'name', 'md.smb.malag_coefs', 'yts', yts)
     231        WriteData(fid, prefix, 'data', dbreaks, 'name', 'md.smb.datebreaks', 'format', 'DoubleMat','scale',yts)
    183232        WriteData(fid, prefix, 'data', templapserates, 'name', 'md.smb.lapserates', 'format', 'DoubleMat', 'scale', 1 / yts, 'yts', yts)
    184233        WriteData(fid, prefix, 'data', tempelevationbins, 'name', 'md.smb.elevationbins', 'format', 'DoubleMat')
Note: See TracChangeset for help on using the changeset viewer.