<commit_before>""" Make a glacier class which uses fortran's code

The main difference with pyglacier.wrapper's Glacier class is that the latter
does not store state information (instead, all is in fortran), whereas
the Glacier class of this module is a true class, which can be duplicated and
so on, and all necessary state information and parameters are passed to the 
fortran code every time a function (e.g. update_velocity, update_mass...) 
is called.
"""
from __future__ import division, print_function
import os, tempfile, datetime, shutil, copy
import warnings

import numpy as np
import dimarray as da

# useful for some in-memory operations
import pyglacier
try:
    from . import wrapper
except Exception as error:
    warnings.warn("Could not import wrapper. Please set the paths correctly or check the code version.")
    wrapper = None

# from .settings import OUTDIR, NML
from . import settings
from .namelist import Namelist, Param
# from .namelist import Namelist, read_namelist_file
from .plotting import plot_glacier
from .run import run_model
# from .wrapper import fortran, get_var, set_var, set_nml, get_nml
from .plotting import plot_glacier, plot_stress

def load_default_nml(params_nml):
    nml = Namelist.read(params_nml) # default
    # make sure geometry is always taken from file 
    # and not from some default profile
    i = nml.index(Param('mode', group='geometry'))
    nml[i].value = 'from_file'  
    globals()['DEFAULT_PARAMS'] = nml # make it module-wide
    return nml

try:
    load_default_nml(settings.NML)
except Exception as error:
    warnings.warn("Could not load default namelist")
    warnings.warn("Please setup project before loading pyglacier.setup(codedir...) or import from code dir")
    raise

def _get_param(params, name, group=None):
    " get one Param instance from the list of params"
    if group is not None:
        i = params.index(Param(name, group=group))
        param = params[i]
    else:
        matches = [p for p in params if p.name == name]
        assert len(matches) == 1, 'no or multiple params found, please provide group: \n'+repr(matches)
        param = matches[0]
    return param

class Glacier(object):

    params = DEFAULT_PARAMS
    _class_directories = []  # history of output directories for simulation for all instances

    def __init__(self, x, zb, w, h, u, params=None, id=None):
        self.x = np.asarray(x)
        self.zb = np.asarray(zb)
        self.w = np.asarray(w)
        self.h = np.asarray(h)
        self.u = np.asarray(u)
        assert self.x.shape == self.zb.shape == self.w.shape == self.h.shape == self.u.shape, 'inconsistent shapes !'

        # load parameters
        if params is not None:
            self.update_params(params)

        self.outdir = None
        self._instance_directories = [] # keep track of what was created by this instance
        self.id = id # for in-memory calculations

    @property
    def size(self):
        return self.x.size

    # Convenience methods to set / get param values 
    # and to common read / write / update operations
    # =============================================
    def set_param(self, name, value, group=None):
        " set param values "
        param = _get_param(self.params, name, group)
        param.value = value

    def get_param(self, name, group=None):
        param = _get_param(self.params, name, group)
        return param.value

    # Here I/O of whole bunch of params
    def update_params(self, params):
        for p in Namelist(params):
            i = self.params.index(p)
            self.params[i] = p

    def read_params(self, nml):
        params = Namelist.read(nml)
        self.update_params(params)

    def write_params(self, nml):
        self.params.write(nml)

    # Convert to / from dataset
    # =============================================
    _names = 'zb', 'W', 'H', 'U'  # model output: small and big letters...
    def to_dataset(self, compute_elevation=False):
        ds = da.Dataset()
        for v in self._names:
            ds[v] = getattr(self, v.lower())
            # ds[v] = da.DimArray(getattr(self, v.lower()), axes=[self.x], dims=['x'])
        # also add glacier elevation gl, xgl
        if compute_elevation:
            hb, hs, gl, xgl = self.compute_elevation()
            ds['hb'] = hb
            ds['hs'] = hs
            ds['gl'] = gl
            ds['xgl'] = xgl
        
        ds.set_axis(self.x, name='x', inplace=True)
        return ds

    @classmethod
    def from_dataset(cls, ds):
        return cls(ds.x, ds['zb'], ds['W'], ds['H'], ds['U'])

    # Convenience methods
    # =========================================
    @classmethod
    def read(cls, fname):
        " read from restart file "
        ds = da.read_nc(fname)
        return cls.from_dataset(ds)

    @classmethod
    def read_output(cls, fname, t=-1):
        ds = da.read_nc(fname, cls._names, indices={'time':t}, indexing='position')
        return cls.from_dataset(ds)


    # Run the model on disk
    # =============================================
    def _get_out_dir(self, create=False):
        """Generate a directory under default output directory
        """
        outdir = os.path.join(settings.OUTDIR, str(datetime.datetime.now())).replace(" ","_")
        if not os.path.exists(outdir) and create:
            os.makedirs(outdir)
        return outdir

    def _get_in_file(self):
        """ reference geometry, forcing and so on
        """
        return os.path.join(self.out_dir, "glacier_input.nc")

    def integrate(self, years, out_dir=None, **kwargs):
        """Run the model as it were from command-line

        years : float
            years of simulation
        out_dir : str, optional
            provide an output directory for the simulation
            (otherwise a new directory will be created)
        **kwargs : passed to run_model
            This includes 'dt' (time step etc...)
        """
        if out_dir:
            self.out_dir = out_dir
        else:
            self.out_dir = self._get_out_dir(create=True) # new out directory<commit_msg>tmp dir w/o special characters<commit_after>""" Make a glacier class which uses fortran's code

The main difference with pyglacier.wrapper's Glacier class is that the latter
does not store state information (instead, all is in fortran), whereas
the Glacier class of this module is a true class, which can be duplicated and
so on, and all necessary state information and parameters are passed to the 
fortran code every time a function (e.g. update_velocity, update_mass...) 
is called.
"""
from __future__ import division, print_function
import os, tempfile, datetime, shutil, copy
import warnings

import numpy as np
import dimarray as da

# useful for some in-memory operations
import pyglacier
try:
    from . import wrapper
except Exception as error:
    warnings.warn("Could not import wrapper. Please set the paths correctly or check the code version.")
    wrapper = None

# from .settings import OUTDIR, NML
from . import settings
from .namelist import Namelist, Param
# from .namelist import Namelist, read_namelist_file
from .plotting import plot_glacier
from .run import run_model
# from .wrapper import fortran, get_var, set_var, set_nml, get_nml
from .plotting import plot_glacier, plot_stress

def load_default_nml(params_nml):
    nml = Namelist.read(params_nml) # default
    # make sure geometry is always taken from file 
    # and not from some default profile
    i = nml.index(Param('mode', group='geometry'))
    nml[i].value = 'from_file'  
    globals()['DEFAULT_PARAMS'] = nml # make it module-wide
    return nml

try:
    load_default_nml(settings.NML)
except Exception as error:
    warnings.warn("Could not load default namelist")
    warnings.warn("Please setup project before loading pyglacier.setup(codedir...) or import from code dir")
    raise

def _get_param(params, name, group=None):
    " get one Param instance from the list of params"
    if group is not None:
        i = params.index(Param(name, group=group))
        param = params[i]
    else:
        matches = [p for p in params if p.name == name]
        assert len(matches) == 1, 'no or multiple params found, please provide group: \n'+repr(matches)
        param = matches[0]
    return param

class Glacier(object):

    params = DEFAULT_PARAMS
    _class_directories = []  # history of output directories for simulation for all instances

    def __init__(self, x, zb, w, h, u, params=None, id=None):
        self.x = np.asarray(x)
        self.zb = np.asarray(zb)
        self.w = np.asarray(w)
        self.h = np.asarray(h)
        self.u = np.asarray(u)
        assert self.x.shape == self.zb.shape == self.w.shape == self.h.shape == self.u.shape, 'inconsistent shapes !'

        # load parameters
        if params is not None:
            self.update_params(params)

        self.outdir = None
        self._instance_directories = [] # keep track of what was created by this instance
        self.id = id # for in-memory calculations

    @property
    def size(self):
        return self.x.size

    # Convenience methods to set / get param values 
    # and to common read / write / update operations
    # =============================================
    def set_param(self, name, value, group=None):
        " set param values "
        param = _get_param(self.params, name, group)
        param.value = value

    def get_param(self, name, group=None):
        param = _get_param(self.params, name, group)
        return param.value

    # Here I/O of whole bunch of params
    def update_params(self, params):
        for p in Namelist(params):
            i = self.params.index(p)
            self.params[i] = p

    def read_params(self, nml):
        params = Namelist.read(nml)
        self.update_params(params)

    def write_params(self, nml):
        self.params.write(nml)

    # Convert to / from dataset
    # =============================================
    _names = 'zb', 'W', 'H', 'U'  # model output: small and big letters...
    def to_dataset(self, compute_elevation=False):
        ds = da.Dataset()
        for v in self._names:
            ds[v] = getattr(self, v.lower())
            # ds[v] = da.DimArray(getattr(self, v.lower()), axes=[self.x], dims=['x'])
        # also add glacier elevation gl, xgl
        if compute_elevation:
            hb, hs, gl, xgl = self.compute_elevation()
            ds['hb'] = hb
            ds['hs'] = hs
            ds['gl'] = gl
            ds['xgl'] = xgl
        
        ds.set_axis(self.x, name='x', inplace=True)
        return ds

    @classmethod
    def from_dataset(cls, ds):
        return cls(ds.x, ds['zb'], ds['W'], ds['H'], ds['U'])

    # Convenience methods
    # =========================================
    @classmethod
    def read(cls, fname):
        " read from restart file "
        ds = da.read_nc(fname)
        return cls.from_dataset(ds)

    @classmethod
    def read_output(cls, fname, t=-1):
        ds = da.read_nc(fname, cls._names, indices={'time':t}, indexing='position')
        return cls.from_dataset(ds)


    # Run the model on disk
    # =============================================
    def _get_out_dir(self, create=False):
        """Generate a directory under default output directory
        """
        outdir = os.path.join(settings.OUTDIR, str(datetime.datetime.now())).replace(" ",".").replace(":","")
        if not os.path.exists(outdir) and create:
            os.makedirs(outdir)
        return outdir

    def _get_in_file(self):
        """ reference geometry, forcing and so on
        """
        return os.path.join(self.out_dir, "glacier_input.nc")

    def integrate(self, years, out_dir=None, **kwargs):
        """Run the model as it were from command-line

        years : float
            years of simulation
        out_dir : str, optional
            provide an output directory for the simulation
            (otherwise a new directory will be created)
        **kwargs : passed to run_model
            This includes 'dt' (time step etc...)
        """
        if out_dir:
            self.out_dir = out_dir
        else:
            self.out_dir = self._get_out_dir(create=True) # new out directory
{'fraction_non_alphanumeric': 0.128477037278734, 'fraction_numerical': 0.0004894363324904152, 'mean_word_length': 2.666267942583732, 'pattern_counts': {'":': 1, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3780217', 'n_tokens_mistral': 3688, 'n_tokens_neox': 3594, 'n_words': 1178}