def test_replaceNaNTagged(self):
     dom=self.domain
     sigma = es.Scalar(0,es.FunctionOnBoundary(dom))
     dat=(sigma*0)/0
     sigma.setTaggedValue(1 , es.Lsup(dat))
     sigma.replaceNaN(10)
     self.assertEqual(es.Lsup(sigma), 10)
     sigma = es.Scalar(0,es.FunctionOnBoundary(dom))
     sigma.promote()
     dat=(sigma*0)/0
     sigma.setTaggedValue(1 , es.Lsup(dat))
     sigma.replaceNaN(3+4j)
     self.assertEqual(es.Lsup(sigma), 5)
 def test_replaceNaNConstant(self):
     dom=self.domain
     dat = es.Data(10,es.ContinuousFunction(dom))
     dat=(dat*0)/0
     self.assertTrue(dat.hasNaN(),"dat should contain NaN but its doesn't")
     dat.replaceNaN(10)
     self.assertEqual(es.Lsup(dat), 10)
     dat = es.Data(10,es.ContinuousFunction(dom))
     dat.promote()
     dat=(dat*0)/0
     self.assertTrue(dat.hasNaN(),"dat should contain NaN but its doesn't")
     dat.replaceNaN(4+3j)
     self.assertEqual(es.Lsup(dat), 5)
Ejemplo n.º 3
0
    def doStep(self, dt):
        """

          performs an iteration step of the penalty method.
          IterationDivergenceError is raised if pressure error cannot be reduced or max_iter is reached.

          """
        penalty = self.viscosity / self.relaxation
        self.__pde.setValue(lame_mu=self.viscosity, \
                            lame_lambda=penalty, \
                            F=self.internal_force, \
                            sigma=self.pressure*es.kronecker(self.__pde.getDomain()), \
                            r=self.prescribed_velocity, \
                            q=self.location_prescribed_velocity)
        self.__pde.getSolverOptions().setTolerance(self.rel_tol / 10.)
        self.velocity = self.__pde.getSolution()
        update = penalty * es.div(self.velocity)
        self.pressure = self.pressure - update
        self.__diff, diff_old = es.Lsup(update), self.__diff
        self.__iter += 1
        self.trace("velocity range %e:%e" %
                   (es.inf(self.velocity), es.sup(self.velocity)))
        self.trace("pressure range %e:%e" %
                   (es.inf(self.pressure), es.sup(self.pressure)))
        self.trace("pressure correction: %e" % self.__diff)
        if self.__iter > 2 and diff_old < self.__diff:
            self.trace("Pressure iteration failed!")
            raise esmf.IterationDivergenceError(
                "no improvement in pressure iteration")
        if self.__iter > self.max_iter:
            raise esmf.IterationDivergenceError(
                "Maximum number of iterations steps reached")
 def test_replaceNaNExpanded(self):
     dom=self.domain
     scl=es.Scalar(0,es.ContinuousFunction(dom))
     scl.expand()
     sclNaN=scl/0
     self.assertTrue(sclNaN.hasNaN(),"sclNaN should contain NaN but its doesn't")
     sclNaN.replaceNaN(15.0)
     self.assertEqual(es.Lsup(sclNaN), 15.0)
     scl=es.Scalar(0,es.ContinuousFunction(dom))
     scl.expand()
     scl.promote()
     if not es.getEscriptParamInt('AUTOLAZY')==1:            
         sclNaN=scl/0
         self.assertTrue(sclNaN.hasNaN(),"sclNaN should contain NaN but its doesn't")
         sclNaN.replaceNaN(3+4j)
         self.assertEqual(es.Lsup(sclNaN), 5.0)
 def test_replaceInfExpanded(self):
     dom=self.domain
     scl=es.Scalar(1,es.ContinuousFunction(dom))
     scl.expand()
     sclNaN=scl/0
     self.assertTrue(sclNaN.hasInf(),"sclNaN should contain Inf but its doesn't")
     sclNaN.replaceNaN(17.0) # Make sure it is distinguishing between NaN and Inf
     sclNaN.replaceInf(15.0)
     self.assertEqual(es.Lsup(sclNaN), 15.0)
     scl=es.Scalar(10,es.ContinuousFunction(dom))
     scl.expand()
     scl.promote()
     if not es.getEscriptParamInt('AUTOLAZY')==1:            
         sclNaN=scl/0
         self.assertTrue(sclNaN.hasInf(),"sclNaN should contain Inf but its doesn't")
         sclNaN.replaceInf(3+4j)
         sclNaN.replaceNaN(3+19j)    # Make sure it is distinguishing between NaN and Inf
         self.assertEqual(es.Lsup(sclNaN), 5.0)
Ejemplo n.º 6
0
def calculate_CFL_number(flux, dt):
    """
    Calculate the CFL (Courant, Friedrich, Lewy) stability criterion.
    """

    CFL_number = flux * dt / flux.getDomain().getSize()

    max_CFL_number = es.Lsup(CFL_number)

    return max_CFL_number
Ejemplo n.º 7
0
 def terminateIteration(self):
     """iteration is terminateIterationd if relative pressure change is less than rel_tol"""
     return self.__diff <= self.rel_tol * es.Lsup(
         self.pressure) + self.abs_tol
Ejemplo n.º 8
0
    def test_comm1(self):
        # ---
        # Initialisations
        # ---

        # Get timing:
        startTime = datetime.datetime.now()

        # Mode (TE includes air-layer, whereas TM does not):
        mode = 'TE'

        # Read the mesh file and define the 'finley' domain:
        #mesh_file = "mesh/commemi-1/commemi1_te.fly"
        #domain = finley.ReadMesh(mesh_file)
        #mesh_file = "mesh/commemi-1/commemi1_te.msh"
        #domain = finley.ReadGmsh(mesh_file, numDim=2)
        domain = generateCommemi1Mesh()

        # Sounding frequencies (in Hz):
        freq_def = {"high": 1.0e+1, "low": 1.0e+1, "step": 1}
        # Frequencies will be mapped on a log-scale from
        # 'high' to 'low' with 'step' points per decade.
        # (also only one frequency must be passed via dict)

        # Step sizes for sampling along vertical and horizontal axis (in m):
        xstep = 100
        zstep = 250

        # ---
        # Resistivity model
        # ---

        # Resistivity values assigned to tagged regions (in Ohm.m):
        rho = [
            1.0e+14,  # 0: air
            100.0,  # 1: host
            0.5  # 2: anomaly
        ]

        # Tags must match those in the file:
        tags = ["domain_air", "domain_host", "domain_anomaly"]

        # ---
        # Layer definitions for 1D response at boundaries.
        # ---

        # List with resistivity values for left and right boundary.
        rho_1d_left = [rho[0], rho[1]]
        rho_1d_rght = [rho[0], rho[1]]

        # Associated interfaces for 1D response left and right (must match the mesh file).
        ifc_1d_left = [20000, 0, -20000]
        ifc_1d_rght = [20000, 0, -20000]

        # Save in dictionary with layer interfaces and resistivities left and right:
        ifc_1d = {"left": ifc_1d_left, "right": ifc_1d_rght}
        rho_1d = {"left": rho_1d_left, "right": rho_1d_rght}

        # ---
        # Adjust parameters here for TM mode
        # ---

        # Simply delete first element from lists:
        if mode.upper() == 'TM':
            tags.pop(0)
            rho.pop(0)
            rho_1d['left'].pop(0)
            rho_1d['right'].pop(0)
            ifc_1d['left'].pop(0)
            ifc_1d['right'].pop(0)

        # ---
        # Run MT_2D
        # ---

        # Class options:
        mt2d.MT_2D._solver = "DIRECT"  #"ITERATIVE" #"CHOLEVSKY" #"CGLS " #"BICGSTAB" #"DIRECT" "ITERATIVE"
        mt2d.MT_2D._debug = False

        # Instantiate an MT_2D object with required & optional parameters:
        obj_mt2d = mt2d.MT_2D(domain,
                              mode,
                              freq_def,
                              tags,
                              rho,
                              rho_1d,
                              ifc_1d,
                              xstep=xstep,
                              zstep=zstep,
                              maps=None,
                              plot=False)

        # Solve for fields, apparent resistivity and phase:
        mt2d_fields, arho_2d, aphi_2d = obj_mt2d.pdeSolve()

        #import random

        #mt2d_fields[0]['real']+=random.random()
        #mt2d_fields[0]['imag']+=50*random.random()

        #print(arho_2d[0][0])
        #for i in range(len(aphi_2d[0])):
        #aphi_2d[0][i]+=(50*random.random())

        #for i in range(len(arho_2d[0])):
        #arho_2d[0][i]-=17.8*(random.random())

        # ---
        # User defined plots
        # ---

        from scipy.interpolate import InterpolatedUnivariateSpline

        # Setup abscissas/Ordinates for escript data:
        x = numpy.array(obj_mt2d.loc.getX())[:, 0]
        y0 = numpy.array(obj_mt2d.loc.getValue(arho_2d[0]))
        y1 = numpy.array(obj_mt2d.loc.getValue(aphi_2d[0]))

        # Values from Weaver -- Model 2D-1 (EP, T=0.1, z=0), see Zhdanov et al, 1997,
        # "Methods for modelling electromagnetic fields. Results from COMMEMI -- the
        # international project on the comparison of modelling results for electromag-
        # netic induction", Journal of Applied Geophysics, 133-271
        rte = [8.07, 14.10, 51.50, 95.71, 104.00, 100.00,
               100.00]  # TE rho_a (3 Canada)
        rtm = [9.86, 46.40, 94.80, 98.30, 99.70, 100.00,
               100.00]  # TM rho_a (3 Canada)
        if mode.lower() == 'te':
            ra = rte
        else:
            ra = rtm
        # Associated stations shifted to match escript coordinates:
        xs = numpy.array([0, 500, 1000, 2000, 4000, 8000, 16000
                          ]) + x.max() / 2.0

        # Setup interpolation to get values at specified stations (for comparison):
        fi = InterpolatedUnivariateSpline(x, y0)
        # Save escript values at comparison points in text file:
        # re-enable to allow comparisons
        #numpy.savetxt("commemi1_"+mode.lower()+".dat", numpy.column_stack((xs,fi(xs))), fmt='%g')

        # X plot-limits:
        x0lim = [2000, 38000]
        y1lim = [0, 120]
        y2lim = [40, 85]

        # Plot labels:
        title = '    escript COMMEMI-1 MT-2D ' + '(' + mode.upper(
        ) + ')' + ' freq: ' + str(obj_mt2d.frequencies[0]) + ' Hz'
        ylbl0 = r'resistivity $(\Omega m)$'
        ylbl1 = r'phase $(\circ)$'
        xlbl1 = 'X (m)'
        # Setup the plot window with app. res. on top and phase on bottom:
        if HAVE_MPL:
            f, ax = pyplot.subplots(2,
                                    figsize=(3.33, 3.33),
                                    dpi=1200,
                                    facecolor='w',
                                    edgecolor='k',
                                    sharex=True)  # Mind shared axis
            f.subplots_adjust(hspace=0.1,
                              top=0.95,
                              left=0.135,
                              bottom=0.125,
                              right=0.975)
            f.suptitle(title, y=0.99, fontsize=8)  #

            # Top: apparent resistivity and points from Weaver for comparison:
            ax[0].plot(x, y0, color='red', label='escript')
            ax[0].plot(xs,
                       ra,
                       linestyle='',
                       markersize=3,
                       marker='o',
                       color='blue',
                       label='Weaver')
            ax[0].grid(b=True, which='both', color='grey', linestyle=':')
            ax[0].set_ylabel(ylbl0)
            ax[0].yaxis.set_label_coords(-0.082, 0.5)
            # Plot limits:
            ax[0].set_xlim(x0lim)
            ax[0].set_ylim(y1lim)

            # Bottom: phase on linear plot
            ax[1].plot(x, y1, color='blue')
            ax[1].grid(b=True, which='both', color='grey', linestyle=':')
            ax[1].set_xlabel(xlbl1)
            ax[1].set_ylabel(ylbl1)
            # Plot limits:
            ax[1].set_xlim(x0lim)
            ax[1].set_ylim(y2lim)

            # ask matplotlib for the plotted objects and their labels
            lna, la = ax[0].get_legend_handles_labels()
            ax[0].legend(lna,
                         la,
                         bbox_to_anchor=(0.675, 0.325),
                         loc=2,
                         borderaxespad=0.,
                         prop={'size': 8},
                         frameon=False)

            pyplot.ticklabel_format(style='sci',
                                    axis='x',
                                    scilimits=(0, 0),
                                    useMathText=True)
            ax[0].xaxis.major.formatter._useMathText = True
            pyplot.rc('font', **{'size': 8, 'family': 'sans-serif'})
            # Uncomment to inspect visually
            #f.savefig("commemi1_"+mode.lower()+".png", dpi=1200)

        # Now let's see if the points match
        # First, we need to find correspondance between xs and x
        indices = []
        for i in range(len(xs)):
            mindiff = 40000
            mindex = 0
            for j in range(len(x)):
                if abs(xs[i] - x[j]) < mindiff:
                    mindiff = abs(xs[i] - x[j])
                    mindex = j
            indices.append(mindex)

        # The following are very simple checks based on the visual shape of the correct result
        maxdiff = 0
        for i in range(len(indices)):
            if abs(y0[indices[i]] - ra[i]) > maxdiff:
                maxdiff = abs(y0[indices[i]] - ra[i])

        # Threshold is pretty arbitrary
        self.assertLess(maxdiff, 5)  # "Mismatch with reference data"

        c = 0
        for y in y1:
            if y < 46:
                c += 1

        self.assertLess(74, escript.Lsup(y1))  # "Peak of bottom plot is off."
        self.assertLess(escript.Lsup(y1), 81)  # "Peak of bottom plot is off."

        self.assertLess(0.78,
                        c / len(y1))  # "Bottom plot has too many high points"
        self.assertLess(c / len(y1),
                        0.8)  # "Bottom plot has too many high points"

        #
        print(datetime.datetime.now() - startTime)
        print("Done!")
Ejemplo n.º 9
0
def iterate_coupled_flow_eqs(mesh,
                             topo_gradient,
                             pressure_pde,
                             solute_pde,
                             pressure_convergence_criterion,
                             concentration_convergence_criterion,
                             min_iterations,
                             max_iterations,
                             dt,
                             g_vector,
                             pressure,
                             concentration,
                             rho_f,
                             phi,
                             diffusivity,
                             l_disp,
                             t_disp,
                             solute_source,
                             specific_storage,
                             k_tensor,
                             k_vector,
                             dispersion_tensor,
                             viscosity,
                             gamma,
                             alpha,
                             fluid_source,
                             rho_f_0,
                             specified_pressure_bnd,
                             specified_pressure,
                             specified_concentration_bnd,
                             specified_concentration,
                             specified_concentration_rho_f,
                             rch_bnd_loc,
                             recharge_mass_flux,
                             coupled_iterations=True,
                             solute_transport=True,
                             heat_transport=False,
                             steady_state=False,
                             proj=None,
                             drain_loc=None,
                             seepage_bnd=False,
                             recalculate_seepage_bnd=True,
                             active_seepage_bnd=None,
                             concentration_bnd_inflow_only=False,
                             concentration_bnd_inflow_direction='up',
                             max_allowed_CFL_number=None,
                             force_CFL_timestep=False,
                             dt_max=None,
                             calculate_viscosity=False,
                             verbose=False,
                             iterate_seepage_in_one_timestep=False,
                             max_seepage_iterations=50,
                             ignore_convergence_failure=False):
    """
    Iterative solve groundwater flow, solute transport and heat flow equations.
    
    solves either steady state or 1 timestep in implicit or explicit mode
    
    iterative coupling scheme of solute transport, pressure & flow eqs. and
    eqs of state follows Ackerer (2004), Geophysical Research Letters 31(12)
    
    Parameters
    ---------
    mesh : 
        escript mesh object
    pressure_pde : 
        groundwater flow PDE
    solute_pde
        solute transport PDE
    pressure_convergence_criterion : float
        convergence criterion groundwater flow eq. (Pa)
    concentration_convergence_criterion : float
        convergence criterion solute transport eq. (kg/kg)
    max_iterations : int
        max number of iterations
    dt : int
        timestep
    g_vector : 
        gravity vector (0,g)
    pressure : 
        pressure (Pa)
    concentration : 
        solute concentration (kg/kg)
    rho_f : 
        fluid density (kg / m3)
    phi :
        porosity
    D :
        solute diffusivity (...)
    l_disp :
        longitudinal dispersivity (...)
    t_disp :
        transverse dispersivity (...)
    solute_source :
        solute source (units...)
    specific_storage :
        specific storativity (...)
    k :
        permeability (m2)
    anisotropy :
        permeability anisotropy = horizontal/vertical permeability
        (dimensionless)
    viscosity : 
        viscosity (...)
    gamma :
        ?
    alpha :
        ?
    fluid_source :
        fluid source term (...)
    rho_f_0
        fluid density at solute concentration C=0 (kg/m3)
    specified_pressure_bnd
        location of specified pressure boundary
    specified_pressure
        specified pressure (Pa)
    specified_concentration_bnd
        location of specified concentration boundary
    specified_concentration
        specified concentration (kg/kg)
    rch_bnd_loc :

    recharge_mass_flux : float

    coupled_iterations : bool, optional
        couple groundwater and solute transport equations iteratively
        by adjusting density term
    solute_transport : bool, optional
        if True, simulate solute transport
    heat_transport : bool, optional
        if True, simulate heat transport
    steady_state : bool, optional
        True for steady state groundwater flow, False for transient
    verbose : bool, optional
        verbose text output
    drain_loc :
        location of drain boundary nodes
    debug : bool, optional
        debugging
    dt_max : float?
        =None                 ...
    proj : 
        escript PDE for projecting element data to nodes
    seepage_optimization_automated : boolean
        
    
    
    Returns 
    -------
    pressure_t2_i2 :
        pressure at next timestep (t2) and last iteration (i2)
    concentration_t2_i2 :
        solute concentration (kg/kg)
    rho_f_t2_i2 :
        fluid density
    iteration : int
        number of iterations
    dt_max :
        max timestep size
        
    """

    # calculate transverse dispersivity
    #t_disp = l_disp * disp_ratio

    year = 365.25 * 24 * 60 * 60.

    if verbose is True:
        print('running iterative solver for pressure and concentration PDEs')
        if coupled_iterations is False:
            print('pressure and concentration are not coupled')

    #pressure_new = pressure
    pressure_old_ts = pressure
    concentration_old_ts = concentration
    fluid_density_new = fluid_density_old = rho_f
    #pressure_t1 = pressure.copy()
    #concentration_t1 = concentration.copy()

    # added 22 jun 2016, not sure if this is ok:
    active_rch_bnd = rch_bnd_loc

    if coupled_iterations is True and calculate_viscosity is True:
        viscosity_new = calculate_viscosity_simple(concentration)
    else:
        viscosity_new = viscosity

    active_specified_concentration_bnd = specified_concentration_bnd

    iteration = 0
    converged = False
    non_convergence = False
    ele_size = None
    q = None
    v = None

    while converged is False and non_convergence is False:

        if verbose is True:
            print('iteration ', iteration)
            if iteration > 0:
                print('pressure convergence ', es.Lsup(pressure_conv))

        if solute_transport is True:

            # get flux
            q = calculate_q(k_vector, viscosity_new, pressure_old_ts,
                            fluid_density_new, g_vector)

            v = q / phi

            # calculate new solute concentration
            concentration_old_iteration = concentration

            # finite element solute transport
            if concentration_bnd_inflow_only is True and iteration == 0:
                # only apply concentration bnd for inflow into model domain
                # assumes a horizontal model bnd
                # TODO: calculate flux normal to model boundary to account
                # for non-horizontal upper boundaries

                proj.setValue(D=es.kronecker(mesh), Y=q)
                try:
                    nodal_q = proj.getSolution()
                except RuntimeError(msg):
                    print('error, non-convergence')
                    print(msg)
                    non_convergence = True

                nodal_q_norm = rotate_vector_escript(nodal_q, topo_gradient)

                nodal_v = nodal_q / phi

                if concentration_bnd_inflow_direction == 'up':
                    inflow_bnd = (es.whereNegative(nodal_q_norm[1]) *
                                  specified_concentration_bnd)
                elif concentration_bnd_inflow_direction == 'down':
                    inflow_bnd = (es.wherePositive(nodal_q_norm[1]) *
                                  specified_concentration_bnd)
                elif concentration_bnd_inflow_direction == 'left':
                    inflow_bnd = (es.wherePositive(nodal_q[0]) *
                                  specified_concentration_bnd)
                elif concentration_bnd_inflow_direction == 'right':
                    inflow_bnd = (es.whereNegative(nodal_q[0]) *
                                  specified_concentration_bnd)

                if es.sup(inflow_bnd) > 0:
                    active_specified_concentration_bnd = inflow_bnd
                else:
                    min_x = es.inf(
                        specified_concentration_bnd *
                        specified_concentration_bnd.getDomain().getX()[0])

                    active_specified_concentration_bnd = \
                        (specified_concentration_bnd *
                         es.whereZero(
                             specified_concentration_bnd.getDomain().getX()[0]
                             - min_x))

                    if verbose is True:
                        print('warning, outflow for all specified ' \
                              'concentration boundary nodes')
                        #print 'using entire bnd instead'
                        #active_specified_concentration_bnd = \
                        #    specified_concentration_bnd
                        print('using first node as fixed conc bnd instead')
                        print('number of active conc bnd nodes:')
                        print(
                            np.sum(
                                np.array(active_specified_concentration_bnd.
                                         toListOfTuples())))

                if verbose is True:
                    import grompy_lib

                    xyi, ia = grompy_lib.convert_to_array(
                        active_specified_concentration_bnd)
                    xyc, ca = grompy_lib.convert_to_array(
                        specified_concentration_bnd)
                    print('inflow conc bnd nodes = %0.0f / %0.0f' \
                          % (ia.sum(), ca.sum()))
                    print('x = %0.3f - %0.3f' %
                          (xyi[ia == 1, 0].min(), xyi[ia == 1, 0].max()))
                    print('qv conc bnd: ',
                          (nodal_q[1] * specified_concentration_bnd))

            #solute_pde.setValue(D=1,
            #                    r=specified_concentration_rho_f,
            #                    q=active_specified_concentration_bnd)
            solute_pde.setValue(D=1,
                                r=specified_concentration,
                                q=active_specified_concentration_bnd)

            solute_pde = update_solute_transport_pde(mesh, solute_pde,
                                                     concentration_old_ts, v,
                                                     dt, solute_source,
                                                     dispersion_tensor,
                                                     diffusivity, l_disp,
                                                     t_disp, fluid_density_old)

            try:
                #solute_mass = solute_pde.getSolution()
                concentration = solute_pde.getSolution()
            except RuntimeError(error_msg):
                print('!! runtime error ', error_msg)
                print('solver options: ')
                print(solute_pde.getSolverOptions().getSummary())

                non_convergence = True

                #raise RuntimeError(error_msg)

            # calculate concentration, using new solute mass and eq of state
            #concentration_new = calculate_concentration(
            #    solute_mass, rho_f_0, gamma)

            #concentration_new = solve_solute_transport_v2(
            #        solute_pde, mesh,
            #        steady_state,
            #        concentration_t1, v, dt, solute_source,
            #        diffusivity, l_disp, t_disp, fluid_density_old,
            #        rho_f_0, gamma)

            concentration_change_rate = \
                (concentration - concentration_old_ts) / dt

        else:
            # no solute transport:
            concentration_change_rate = 0

        if heat_transport is True:
            # no temperature in models yet:
            temperature_change_rate = 0
        else:
            # no heat transport:
            temperature_change_rate = 0

        if coupled_iterations is True:
            if verbose is True:
                print('recalculating fluid density and viscosity')
            # recalculate fluid density
            fluid_density_old = fluid_density_new
            fluid_density_new = \
                calculate_fluid_density(concentration, gamma, rho_f_0)

            if calculate_viscosity is True:
                viscosity_new = \
                    calculate_viscosity_simple(concentration)

        else:
            # leave fluid density unchanged
            concentration_change_rate = 0
            temperature_change_rate = 0

        # store old pressure
        pressure_old_iteration = pressure

        if drain_loc is None or es.sup(drain_loc) == 0:

            # calculate pressure, no drain or seepage bnd
            pressure_pde = \
                update_pressure_pde(pressure_pde,
                                    pressure_old_ts,
                                    phi, specific_storage,
                                    k_tensor, k_vector,
                                    fluid_density_new,
                                    viscosity_new, dt,
                                    rch_bnd_loc,
                                    recharge_mass_flux,
                                    fluid_source, g_vector,
                                    gamma, concentration_change_rate,
                                    alpha, temperature_change_rate)
            try:
                pressure = pressure_pde.getSolution()
            except RuntimeError(msg):
                print('error, non-convergence')
                print(msg)
                non_convergence = True
            #print 'no seepage bnd'
        else:
            # implement drain or seepage boundary
            if seepage_bnd is True:

                ## use seepage boundary:
                if active_seepage_bnd is None:
                    # calculate pressure without any drain boundary
                    pressure_pde.setValue(r=specified_pressure,
                                          q=specified_pressure_bnd)
                    active_rch_bnd = rch_bnd_loc
                else:
                    # incorporate active drain bnd of previous timestep
                    specified_pressure_bnd_mod = \
                        es.wherePositive(
                            specified_pressure_bnd + active_seepage_bnd)
                    pressure_pde.setValue(r=specified_pressure,
                                          q=specified_pressure_bnd_mod)

                    # do not change active rch bnd
                    active_rch_bnd = rch_bnd_loc

                    #active_rch_bnd = rch_bnd_loc * \
                    #                 es.whereZero(specified_pressure_bnd)
                    #specified_flux = rch_bnd_loc * dt * recharge_mass_flux

                # calculate pressure with existing seepage bnd
                pressure_pde = \
                    update_pressure_pde(pressure_pde,
                                        pressure_old_ts,
                                        phi, specific_storage,
                                        k_tensor, k_vector,
                                        fluid_density_new,
                                        viscosity_new, dt,
                                        active_rch_bnd, recharge_mass_flux,
                                        fluid_source, g_vector,
                                        gamma, concentration_change_rate,
                                        alpha, temperature_change_rate)
                try:
                    pressure = pressure_pde.getSolution()
                except RuntimeError:
                    print("error, pressure PDE solver failed")
                    converged = True
                    non_convergence = True
                    #if pressure_new not in locals():
                    #    pressure_new = pressure_t1

                # assign drain bnd nodes
                if active_seepage_bnd is None:
                    active_seepage_bnd = \
                        es.wherePositive(drain_loc * pressure)

                if iteration < max_seepage_iterations and recalculate_seepage_bnd is True:
                    # adjust seepage boundary, but only for first x iterations
                    # to avoid instability

                    if verbose is True:
                        seepage_xy = active_seepage_bnd.getDomain().getX()
                        seepage_nodes_xy = \
                            np.array(seepage_xy.toListOfTuples())
                        seepage_array = np.array(
                            active_seepage_bnd.toListOfTuples())
                        ind = seepage_array > 0
                        print('\tbefore adjustment:')
                        print('\tactive seepage bnd from x=%0.0f to %0.0f m' \
                              % (seepage_nodes_xy[ind, 0].min(),
                                 seepage_nodes_xy[ind, 0].max()))

                    # remove seepage nodes that have become source of water
                    q = calculate_q(k_vector, viscosity_new, pressure,
                                    fluid_density_new, g_vector)
                    proj.setValue(D=es.kronecker(mesh), Y=q)
                    try:
                        nodal_q = proj.getSolution()
                    except RuntimeError(msg):
                        print('error, non-convergence')
                        print(msg)
                        non_convergence = True

                    # calculate max vertical flux into the model domain at
                    # drain bnd nodes
                    # -> not possible, cannot mix face elements and normal elements
                    # later on to adjust seepage...
                    #nodal_q_norm = nodal_q * nodal_q.getDomain().getNormal()

                    #
                    nodal_q_norm = rotate_vector_escript(
                        nodal_q, topo_gradient)

                    #flux_seepage_bnd = active_seepage_bnd * nodal_q[1]
                    flux_seepage_bnd = active_seepage_bnd * nodal_q_norm[1]

                    #flux_seepage_bnd_corr = flux_seepage_bnd +

                    seepage_change_buffer = 1e-3 / year

                    seepage_inflow_nodes = \
                        es.whereNegative(flux_seepage_bnd
                                         + recharge_mass_flux
                                         / fluid_density_new)

                    if verbose is True:

                        print('\tflux seepage bnd (m/yr): ',
                              flux_seepage_bnd * year)
                        print('recharge ')
                        print('\tseepage inflow nodes: ', seepage_inflow_nodes)

                    #seepage_inflow_nodes = \
                    #    es.whereNegative(flux_seepage_bnd)

                    removed_seepage_inflow_nodes = seepage_inflow_nodes

                    # add boundary nodes with P>0 to seepage bnd
                    new_seepage_nodes = \
                        es.wherePositive(drain_loc
                                         * (1 - active_seepage_bnd)
                                         * pressure)

                    # update the seepage bnd
                    active_seepage_bnd = (active_seepage_bnd +
                                          new_seepage_nodes -
                                          removed_seepage_inflow_nodes)

                    if verbose is True:
                        seepage_xy = active_seepage_bnd.getDomain().getX()
                        seepage_nodes_xy = \
                            np.array(seepage_xy.toListOfTuples())
                        seepage_array = np.array(
                            active_seepage_bnd.toListOfTuples())
                        ind = np.array(seepage_array > 0)
                        print('\tafter adjustment:')
                        print('\tN=%i active seepage bnd x=%0.0f to %0.0f m' \
                              % (np.sum(ind.astype(int)),
                                 seepage_nodes_xy[ind, 0].min(),
                                 seepage_nodes_xy[ind, 0].max()))

                    if iterate_seepage_in_one_timestep is True:
                        # update the specified pressure boundary to include
                        # new seepage nodes
                        specified_pressure_bnd_mod = \
                            es.wherePositive(
                                specified_pressure_bnd + active_seepage_bnd)
                        #active_rch_bnd = rch_bnd_loc * es.whereZero(specified_pressure_bnd_mod)
                        # changed to have steady recharge bnd regardless of seepage bnd,
                        # 11 apr 2016, Elco
                        active_rch_bnd = rch_bnd_loc

                        # experiment, adjust recharge to have 0 rehcarge at seepage nodes
                        # not sure if this makes sense...
                        #specified_flux_adj = active_rch_bnd * dt * recharge_mass_flux
                        #
                        #pressure_pde.setValue(r=specified_pressure,
                        #                      q=specified_pressure_bnd_mod,
                        #                      y=specified_flux_adj)
                        pressure_pde.setValue(r=specified_pressure,
                                              q=specified_pressure_bnd_mod)

                        # recalculate pressure
                        #pressure_pde = \
                        #    update_pressure_pde(pressure_pde,
                        #                        pressure_t1,
                        #                        phi, specific_storage,
                        #                        k_tensor, k_vector,
                        #                        fluid_density_new,
                        #                        viscosity_new, dt,
                        #                        rch_bnd_loc, recharge_mass_flux,
                        #                        fluid_source, g_vector,
                        #                        gamma, concentration_change_rate,
                        #                        alpha, temperature_change_rate)

                        # recalculate pressure
                        try:
                            pressure = pressure_pde.getSolution()
                        except RuntimeError(msg):
                            print('error, non-convergence')
                            print(msg)
                            non_convergence = True

                        # remove inflow nodes again
                        #q = (k_vector / viscosity_new *
                        #     -(es.grad(pressure_new)
                        #       - fluid_density_new * g_vector)
                        #     / phi)
                        q = calculate_q(k_vector, viscosity_new, pressure,
                                        fluid_density_new, g_vector)
                        proj.setValue(D=es.kronecker(mesh), Y=q)
                        nodal_q = proj.getSolution()

                        # calculate max vertical flux into the model domain at
                        # drain bnd nodes
                        #nodal_q_norm = nodal_q * nodal_q.getDomain().getNormal()
                        nodal_q_norm = rotate_vector_escript(
                            nodal_q, topo_gradient)
                        flux_seepage_bnd = active_seepage_bnd * nodal_q_norm[1]

                        #removed_seepage_inflow_nodes = \
                        #    es.whereNegative(flux_seepage_bnd -
                        #                     seepage_inflow_threshold)
                        #removed_seepage_inflow_nodes = \
                        #    es.whereNegative(flux_seepage_bnd
                        #                     + recharge_mass_flux
                        #                     / fluid_density_new)

                        removed_seepage_inflow_nodes = \
                            es.whereNegative(flux_seepage_bnd)

                        active_seepage_bnd = (active_seepage_bnd -
                                              removed_seepage_inflow_nodes)

                        if verbose is True:
                            seepage_xy = active_seepage_bnd.getDomain().getX()
                            seepage_nodes_xy = \
                                np.array(seepage_xy.toListOfTuples())
                            seepage_array = np.array(
                                active_seepage_bnd.toListOfTuples())
                            ind = seepage_array > 0
                            print(
                                '\tafter 2nd adjustment (removing inflow nodes):'
                            )
                            print('\tN=%i active seepage bnd from ' \
                                  'x=%0.0f to %0.0f m' \
                                  % (np.sum(ind.astype(int)),
                                     seepage_nodes_xy[ind, 0].min(),
                                     seepage_nodes_xy[ind, 0].max()))

                if iterate_seepage_in_one_timestep is True:
                    # assign updated seepage nodes:
                    specified_pressure_bnd_mod = \
                        es.wherePositive(
                            specified_pressure_bnd + active_seepage_bnd)

                    #active_rch_bnd = rch_bnd_loc * es.whereZero(specified_pressure_bnd_mod)
                    active_rch_bnd = rch_bnd_loc

                    # experiment, adjust recharge to have 0 rehcarge at seepage nodes
                    # not sure if this makes sense...
                    # ! probably the source of long timescale instability of seepage/rch bnd

                    #specified_flux_adj = active_rch_bnd * dt * recharge_mass_flux

                    #pressure_pde.setValue(r=specified_pressure,
                    #                      q=specified_pressure_bnd_mod,
                    #                      y=specified_flux_adj)
                    pressure_pde.setValue(r=specified_pressure,
                                          q=specified_pressure_bnd_mod)

                    # recalculate final pressure
                    #pressure_pde = \
                    #    update_pressure_pde(pressure_pde,
                    #                        pressure_t1,
                    #                        phi, specific_storage,
                    #                        k_tensor, k_vector,
                    #                        fluid_density_new,
                    #                        viscosity_new, dt,
                    #                        rch_bnd_loc, recharge_mass_flux,
                    #                        fluid_source, g_vector,
                    #                        gamma, concentration_change_rate,
                    #                        alpha, temperature_change_rate)

                    try:
                        pressure = pressure_pde.getSolution()
                    except RuntimeError(msg):
                        print('error, non-convergence')
                        print(msg)
                        non_convergence = True

        # calculate convergence criteria
        pressure_conv = pressure - pressure_old_iteration

        if solute_transport is True:
            conc_conv = concentration - concentration_old_iteration
        else:
            conc_conv = 0.0

        # check whether iterations have converged or not:
        if (es.Lsup(pressure_conv) < pressure_convergence_criterion) and \
                (es.Lsup(conc_conv) < concentration_convergence_criterion)\
                and iteration + 1 >= min_iterations:
            if iteration > 0 and verbose is True:
                print('iterations converged after %i iterations' % iteration)
            converged = True
        else:
            if verbose is True:
                print('iteration %i, max. pressure change %0.3e ' \
                      % (iteration, es.Lsup(pressure_conv)))
                print('              max. C change %0.3e ' \
                      % (es.Lsup(conc_conv)))

        if iteration + 1 >= max_iterations:
            print('warning, reached maximum number of %i iterations' \
                  % (iteration + 1))
            print('iteration %i, max. pressure change %0.3e Pa, ' \
                  'convergence at %0.2e Pa' \
                  % (iteration, es.Lsup(pressure_conv),
                     pressure_convergence_criterion))
            print('              max. C change %0.3e kg/kg, ' \
                  'convergence at %0.2e kg/kg' \
                  % (es.Lsup(conc_conv), concentration_convergence_criterion))
            converged = True
            non_convergence = True

        # check CFL number
        #max_CFL_number = calculate_CFL_number(q, dt)
        if ele_size is None:
            ele_size = q.getDomain().getSize()
        #print ele_size - q.getDomain().getSize()

        CFL_number = q * dt / ele_size
        max_CFL_number = es.Lsup(CFL_number)

        if max_CFL_number > 0.5 and verbose is True:
            print('warning, max CFL number = %0.2f, exceeds 0.5' \
                  % max_CFL_number)

        # recaclulcate timestep if max timestep exceeds CFL number
        if (max_allowed_CFL_number is not None
                and max_CFL_number > max_allowed_CFL_number
                and iteration == 0) \
                or (force_CFL_timestep is True and iteration <= 1):

            # make sure iteration is repeated
            converged = False

            #CFL_number / flux * flux.getDomain().getSize() = dtc /

            dtc = max_allowed_CFL_number / q * ele_size
            new_timestep = es.inf((dtc**2)**0.5)
            if dt_max is not None and new_timestep > dt_max:
                new_timestep = dt_max

            dt = new_timestep

            if verbose is True:
                print('max CFL number = ', max_CFL_number)
                print('changing timestep from %0.2e sec to %0.2e sec' \
                      % (dt, new_timestep))

        if coupled_iterations is False:
            converged = True

        iteration += 1

    return (pressure, concentration, fluid_density_new, viscosity_new, q, v,
            active_specified_concentration_bnd, active_seepage_bnd,
            active_rch_bnd, iteration, es.Lsup(pressure_conv),
            es.Lsup(conc_conv), max_CFL_number, non_convergence, dt)
Ejemplo n.º 10
0
def run_model_scenario_and_analyze_results(Parameters,
                                           ModelOptions,
                                           mesh_function,
                                           run,
                                           model_scenario_name,
                                           scenario_parameters,
                                           scenario_param_names,
                                           df,
                                           model_output_folder,
                                           scriptdir,
                                           scenario_name,
                                           nscenarios,
                                           dfo=None):

    year = 365.25 * 24 * 60 * 60

    model_file_adj = ''

    run_id = 'S%i' % run
    #scenario_name = run_id

    print '-' * 30
    print 'model scenario id %s, run %i of %i' % (run_id, run + 1, nscenarios)
    print '-' * 30

    model_file_adj += 'run%s' % run_id

    # update default parameters in Parameter class
    for scenario_param_name, scenario_parameter in \
            zip(scenario_param_names, scenario_parameters):

        if scenario_parameter is not None:
            # find model parameter name to adjust
            model_param_name = scenario_param_name[:-2]

            print 'updating parameter %s from %s to %s' \
                  % (model_param_name,
                     str(getattr(Parameters, model_param_name)),
                     str(scenario_parameter))

            # update model parameter
            setattr(Parameters, model_param_name, scenario_parameter)

            # and add model param name to filename
            model_file_adj += '_%s_%s' % (model_param_name,
                                          str(scenario_parameter))

    # set filename for mesh

    mesh_fn = os.path.join(
        scriptdir, 'model_output',
        '_%i_%s.msh' % (random.randint(0, 100), '%s.msh' % scenario_name))

    # get names and values of input parameters
    attributes = inspect.getmembers(
        Parameters, lambda attribute: not (inspect.isroutine(attribute)))
    attribute_dict = [
        attribute for attribute in attributes
        if not (attribute[0].startswith('__') and attribute[0].endswith('__'))
    ]

    if df is None:
        # get attributes
        attribute_names = [
            attribute[0] for attribute in attributes if not (
                attribute[0].startswith('__') and attribute[0].endswith('__'))
        ]

        # set up pandas dataframe to store model input params
        ind = [0]
        columns = attribute_names
        df = pd.DataFrame(index=ind, columns=columns)

    # store input parameters in dataframe
    for a in attribute_dict:
        if a[0] in df.columns:
            if type(a[1]) is list:
                df.ix[run, a[0]] = str(a[1])
            else:
                df.ix[run, a[0]] = a[1]

    #
    start_time = datetime.datetime.now()
    start_date_str = '%i-%i-%i' % (start_time.day, start_time.month,
                                   start_time.year)
    start_time_str = '%i:%i:%i' % (start_time.hour, start_time.minute,
                                   start_time.second)
    df.ix[run, 'start_date'] = start_date_str
    df.ix[run, 'start_time'] = start_time_str

    # run a single model scenario
    model_results = grompy_salt_lib.run_model_scenario(
        scenario_name, model_output_folder, model_file_adj, ModelOptions,
        Parameters, mesh_function, mesh_fn)

    end_time = datetime.datetime.now()
    runtime = end_time - start_time
    df.ix[run, 'computing_runtime_sec'] = runtime.total_seconds()

    print 'processing model results'
    # get model results
    (mesh, surface, sea_surface, k_vector, P, Conc, rho_f, viscosity, h, q,
     q_abs, nodal_flux, Pdiff, Cdiff, pressure_differences_max,
     concentration_differences_max, pressure_differences_mean,
     concentration_differences_mean, dts, runtimes, nsteps, output_step,
     boundary_conditions, boundary_fluxes, boundary_flux_stats,
     reached_steady_state) = model_results

    dt = dts[-1]
    runtime = runtimes[-1]

    flux = q

    [
        specified_pressure_bnd, specified_pressure,
        specified_concentration_bnd, active_concentration_bnd,
        specified_concentration, specified_concentration_rho_f, rch_bnd_loc,
        active_seepage_bnd
    ] = boundary_conditions

    [
        flux_surface_norm, land_flux_in, land_flux_out, submarine_flux,
        submarine_flux_in, submarine_flux_out
    ] = boundary_fluxes

    [
        total_flux_over_surface_norm, total_rch_flux, total_seepage_flux,
        total_land_flux_in, total_land_flux_out, total_submarine_flux,
        total_submarine_flux_in, total_submarine_flux_out, ext_rch,
        ext_seepage, ext_inflow, ext_outflow, ext_inflow_land,
        ext_outflow_land, ext_inflow_sea, ext_outflow_sea,
        ext_outflow_land_threshold, ext_outflow_sea_threshold, min_land_flux,
        max_land_flux, min_seepage_flux, max_seepage_flux, min_submarine_flux,
        max_submarine_flux
    ] = boundary_flux_stats

    newcols = [
        'model_scenario_id', 'P_min', 'P_max', 'C_min', 'C_max', 'h_min',
        'h_max', 'vx_min', 'vx_max', 'vy_min', 'vy_max', 'max_pressure_change',
        'max_concentration_change', 'runtime', 'nsteps', 'dt_final',
        'total_flux_over_surface', 'total_rch_flux', 'total_seepage_flux',
        'total_land_flux_in', 'total_land_flux_out', 'total_submarine_flux',
        'total_submarine_flux_in', 'total_submarine_flux_out',
        'ext_inflow_land', 'ext_outflow_land', 'ext_inflow_sea',
        'ext_outflow_sea', 'ext_outflow_land_exc_threshold',
        'ext_outflow_sea_exc_threshold', 'min_land_flux', 'max_land_flux',
        'min_seepage_flux', 'max_seepage_flux', 'min_submarine_flux',
        'max_submarine_flux'
    ]

    if run == 0:
        df = grompy_salt_lib.add_cols_to_df(df, newcols)
        df['model_scenario_id'] = ''

    # store model results in dataframe
    df.ix[run, 'model_scenario_id'] = run_id
    if model_scenario_name is not None:
        df.ix[run, 'model_scenario_name'] = model_scenario_name
    df.ix[run, 'P_min'] = es.inf(P)
    df.ix[run, 'P_max'] = es.sup(P)
    df.ix[run, 'C_min'] = es.inf(Conc)
    df.ix[run, 'C_max'] = es.sup(Conc)
    df.ix[run, 'h_min'] = es.inf(h)
    df.ix[run, 'h_max'] = es.sup(h)
    df.ix[run, 'vx_min'] = es.inf(flux[0])
    df.ix[run, 'vx_max'] = es.sup(flux[0])
    df.ix[run, 'vy_min'] = es.inf(flux[1])
    df.ix[run, 'vy_max'] = es.sup(flux[1])
    df.ix[run, 'max_pressure_change'] = es.Lsup(Pdiff)
    df.ix[run, 'max_concentration_change'] = es.Lsup(Cdiff)
    df.ix[run, 'runtime'] = runtime
    df.ix[run, 'nsteps'] = nsteps
    df.ix[run, 'dt_final'] = dt
    df.ix[run, 'total_flux_over_surface'] = total_flux_over_surface_norm[1]
    df.ix[run, 'total_rch_flux'] = total_rch_flux[1]
    df.ix[run, 'total_seepage_flux'] = total_seepage_flux[1]
    df.ix[run, 'total_land_flux_in'] = total_land_flux_in[1]
    df.ix[run, 'total_land_flux_out'] = total_land_flux_out[1]
    df.ix[run, 'total_submarine_flux'] = total_submarine_flux[1]
    df.ix[run, 'total_submarine_flux_in'] = total_submarine_flux_in[1]
    df.ix[run, 'total_submarine_flux_out'] = total_submarine_flux_out[1]
    df.ix[run, 'ext_inflow_land'] = ext_inflow_land[1]
    df.ix[run, 'ext_outflow_land'] = ext_outflow_land[1]
    df.ix[run, 'ext_inflow_sea'] = ext_inflow_sea[1]
    df.ix[run, 'ext_outflow_sea'] = ext_outflow_sea[1]
    df.ix[run,
          'ext_outflow_land_exc_threshold'] = ext_outflow_land_threshold[1]
    df.ix[run, 'ext_outflow_sea_exc_threshold'] = ext_outflow_sea_threshold[1]
    df.ix[run, 'min_land_flux'] = min_land_flux
    df.ix[run, 'max_land_flux'] = max_land_flux
    df.ix[run, 'min_seepage_flux'] = min_seepage_flux
    df.ix[run, 'max_seepage_flux'] = max_seepage_flux
    df.ix[run, 'min_submarine_flux'] = min_submarine_flux
    df.ix[run, 'max_submarine_flux'] = max_submarine_flux

    # check if model output folder exists and create if not
    if not os.path.exists(model_output_folder):
        os.makedirs(model_output_folder)

    # save model output to vtk file
    if ModelOptions.save_vtk_files is True:
        vtk_folder = os.path.join(model_output_folder, 'vtk_files')

        if not os.path.exists(vtk_folder):
            os.makedirs(vtk_folder)

        fn_VTK = os.path.join(vtk_folder,
                              '%s_final_output.vtu' % model_file_adj)
        print 'saving vtk file of model results: %s' % fn_VTK

        nodata = -99999
        flux_surface_plot = nodal_flux * surface + \
            nodata * es.whereZero(surface)
        if sea_surface is None:
            sea_surface_save = surface
        else:
            sea_surface_save = sea_surface

        esys.weipa.saveVTK(fn_VTK,
                           pressure=P,
                           concentration=Conc,
                           h=h,
                           flux=flux,
                           qx=flux[0],
                           qy=flux[1],
                           kx=k_vector[0],
                           ky=k_vector[1],
                           nodal_flux=nodal_flux,
                           surface=surface,
                           sea_surface=sea_surface_save,
                           nodal_flux_surface=flux_surface_plot,
                           specified_pressure_bnd=specified_pressure_bnd,
                           active_seepage_bnd=active_seepage_bnd,
                           recharge_bnd=rch_bnd_loc,
                           active_concentration_bnd=active_concentration_bnd,
                           flux_surface_norm=flux_surface_norm,
                           land_flux_in=land_flux_in,
                           land_flux_out=land_flux_out,
                           submarine_flux=submarine_flux,
                           submarine_flux_in=submarine_flux_in,
                           submarine_flux_out=submarine_flux_out)

        df.ix[run, 'vtk_filename'] = fn_VTK

    if ModelOptions.save_variables_to_csv is True:

        var_folder = os.path.join(model_output_folder, 'variables')

        if not os.path.exists(var_folder):
            os.makedirs(var_folder)

        q_abs = (flux[0]**2 + flux[1]**2)**0.5

        model_vars = [P, Conc, h, q_abs * year, flux[0] * year, flux[1] * year]
        varlabels = ['P', 'conc', 'h', 'v', 'vx', 'vy']

        for var, varlabel in zip(model_vars, varlabels):
            xya, va = grompy_salt_lib.convert_to_array(var)

            filename = os.path.join(
                var_folder, '%s_%s_final.csv' % (varlabel, model_file_adj))
            csv_str = 'x,y,%s\n' % varlabel
            for x, y, vai in zip(xya[:, 0], xya[:, 1], va):
                csv_str += '%0.3f,%0.3f,%0.3e\n' % (x, y, vai)

            print 'writing final variable %s to file %s' % (varlabel, filename)

            fout = open(filename, 'w')
            fout.write(csv_str)
            fout.close()

        # write node and element locations and connectivity to separate file
        mesh_fn = os.path.join(var_folder, 'mesh_%s.fly' % model_file_adj)
        mesh.write(mesh_fn)

    # write pressure and concentration differences
    diff_folder = os.path.join(model_output_folder, 'P_and_C_change')
    if not os.path.exists(diff_folder):
        os.makedirs(diff_folder)

    df_diff = pd.DataFrame(columns=[
        'timestep', 'dt', 'runtime', 'pressure_change_mean',
        'pressure_change_max', 'concentration_change_mean',
        'concentration_change_max'
    ],
                           index=np.arange(nsteps))

    #df_diff['timestep'] = np.arange(nsteps)
    df_diff['pressure_change_mean'] = pressure_differences_mean
    df_diff['pressure_change_max'] = pressure_differences_max
    df_diff['concentration_change_mean'] = concentration_differences_mean
    df_diff['concentration_change_max'] = concentration_differences_max
    df_diff['dt'] = dts
    df_diff['runtime'] = runtimes

    filename = os.path.join(diff_folder,
                            'P_and_C_changes_%s_final.csv' % model_file_adj)

    print 'saving P and C changes to %s' % filename
    df_diff.to_csv(filename, index_label='timestep')

    # merge new model results dataframe with existing model output, if any
    dfm = df
    if dfo is not None:
        dfm = pd.concat([dfo, df])

        # keep columnn order
        dfm = dfm[list(dfo.columns)]

    # save model runs input params and results to .csv file
    today = datetime.datetime.now()
    today_str = '%i-%i-%i' % (today.day, today.month, today.year)
    filename = os.path.join(
        model_output_folder, 'final_model_results_%s_%s_%i_runs.csv' %
        (scenario_name, today_str, nscenarios))

    # check if file exists already
    if os.path.exists(filename):
        backup_filename = filename + '_backup'
        os.rename(filename, backup_filename)
        print 'moved previous input & output data to %s' % backup_filename

    print 'saving model run input & output data to %s' % filename
    dfm.to_csv(filename, index_label='model_run')

    return df
Ejemplo n.º 11
0
    def test_comm4(self):
        # ---
        # Initialisations
        # ---

        # Get timing:
        startTime = datetime.datetime.now()

        # Mode (TE includes air-layer, whereas TM does not):
        mode = 'TE'

        # Read the mesh file and define the 'finley' domain: 
        #mesh_file = "mesh/commemi-4/commemi4_tm.msh"
        #domain = finley.ReadGmsh(mesh_file, numDim=2)
        domain = generateCommemi4Mesh()

        #mesh_file = "mesh/commemi-4/commemi4_tm.fly"
        #domain = finley.ReadMesh(mesh_file)

        # Sounding frequencies (in Hz):
        freq_def = {"high":1.0e+0,"low":1.0e-0,"step":1}
        # Frequencies will be mapped on a log-scale from
        # 'high' to 'low' with 'step' points per decade.
        # (also only one frequency must be passed via dict)

        # Step sizes for sampling along vertical and horizontal axis (in m):
        xstep=100
        zstep=100



        # ---
        # Resistivity model
        # ---

        # Resistivity values assigned to tagged regions (in Ohm.m):
        rho  = [
                1.0e+14, # 0: air     1.0e-30
                25.0   , # 1: lyr1    0.04
                10.0   , # 2: slab    0.1
                2.5    , # 3: basin   0.4
                1000.0 , # 4: lyr2    0.001
                5.0      # 5: lyr3    0.2
            ]

        # Tags must match those in the file:
        tags = ["air", "lyr1", "slab", "basin", "lyr2", "lyr3"]

        # Optional user defined map of resistivity:
        def f4(x,z,r): return escript.sqrt(escript.sqrt(x*x+z*z))/r
        maps = [None, None, None, None, f4, None]



        # ---
        # Layer definitions for 1D response at boundaries.
        # ---

        # List with resistivity values for left and right boundary.
        rho_1d_left  = [ rho[0], rho[1], rho[2], rho[4], rho[5] ]
        rho_1d_rght  = [ rho[0], rho[1], rho[3], rho[4], rho[5] ]

        # Associated interfaces for 1D response left and right (must match the mesh file).
        ifc_1d_left = [ 50000, 0, -500, -2000, -25000, -50000]
        ifc_1d_rght = [ 50000, 0, -500, -1000, -25000, -50000]

        # Save in dictionary with layer interfaces and resistivities left and right:
        ifc_1d = {"left":ifc_1d_left , "right":ifc_1d_rght}
        rho_1d = {"left":rho_1d_left , "right":rho_1d_rght}



        # ---
        # Adjust parameters here for TM mode
        # ---

        # Simply delete first element from lists:
        if mode.upper() == 'TM':
            tags.pop(0)
            rho.pop(0)
            rho_1d['left'].pop(0)
            rho_1d['right'].pop(0)
            ifc_1d['left'].pop(0)
            ifc_1d['right'].pop(0)
            if maps is not None:
                maps.pop(0)



        # ---
        # Run MT_2D
        # ---

        # Class options:
        mt2d.MT_2D._solver = "DIRECT" #"ITERATIVE" #"CHOLEVSKY" #"CGLS " #"BICGSTAB" #"DIRECT" "ITERATIVE"
        mt2d.MT_2D._debug   = False

        # Instantiate an MT_2D object with required & optional parameters:
        obj_mt2d = mt2d.MT_2D(domain, mode, freq_def, tags, rho, rho_1d, ifc_1d,
                xstep=xstep ,zstep=zstep, maps=None, plot=False)

        # Solve for fields, apparent resistivity and phase:
        mt2d_fields, arho_2d, aphi_2d = obj_mt2d.pdeSolve()
        
        
        #import random

        #mt2d_fields[0]['real']+=random.random()
        #mt2d_fields[0]['imag']+=50*random.random()

        #print(arho_2d[0][0])
        #for i in range(len(aphi_2d[0])):
            #aphi_2d[0][i]+=(50*random.random())

        #for i in range(len(arho_2d[0])):
            #arho_2d[0][i]-=7*(random.random())    
        

        # ---
        # User defined plots
        # ---

        # Setup abscissas/Ordinates for escript data:
        x  = numpy.array( obj_mt2d.loc.getX() )[:,0]
        y0 = numpy.array( obj_mt2d.loc.getValue(arho_2d[0]) )
        y1 = numpy.array( obj_mt2d.loc.getValue(aphi_2d[0]) )

        # Sort these arrays and delete any duplicates to prevent the call to 
        # InterpolatedUnivariateSpline below from returning an error
        indices = numpy.argsort(x,kind='quicksort')
        x = x[indices]
        y0 = y0[indices]
        y1 = y1[indices]
        indices = numpy.unique(x,return_index=True)
        x = x[indices[1]]
        y0 = y0[indices[1]]
        y1 = y1[indices[1]]

        # Zhdanov et al, 1997, -- Model 2D-1 Table B.33. Model2D-4 (T=1.0, z=0), see 
        # "Methods for modelling electromagnetic fields. Results from COMMEMI -- the
        # international project on the comparison of modelling results for electromag-
        # netic induction", Journal of Applied Geophysics, 133-271
        rte = [12.70, 12.00, 8.80, 6.84, 6.67, 6.25] # TE rho_a (3 Canada)   
        rtm = [11.40, 11.50, 9.03, 6.78, 6.80, 5.71] # TM rho_a (3 Canada) 
        if mode.lower() == 'te':
            ra = rte
        else:
            ra = rtm  
        # Associated stations shifted to match escript coordinates:
        xs = numpy.array( [-10, -7, -6, -5, 2, 5] )*1000 + x.max()/2.0

        # Setup interpolation to get values at specified stations (for comparison):
        fi = InterpolatedUnivariateSpline(x, y0)
        # Save esscript values at comparison points in text file:
        # uncomment to investigate
        #numpy.savetxt("mesh/commemi-4/commemi4_"+mode.lower()+".dat", numpy.column_stack((xs,fi(xs))), fmt='%g')

        # X plot-limits:
        x0lim = [2000,38000]
        #y1lim = [0,120]
        #y2lim = [40,85]
        
        # Plot labels:
        title = '    escript COMMEMI-4 MT-2D ' + '(' + mode.upper() + ')' + ' freq: ' + str(obj_mt2d.frequencies[0]) + ' Hz'
        ylbl0 = r'resistivity $(\Omega m)$'
        ylbl1 = r'phase $(\circ)$'
        xlbl1 = 'X (m)'
        if HAVE_MPL:
            # Setup the plot window with app. res. on top and phase on bottom:
            f, ax = pyplot.subplots(2, figsize=(3.33,3.33), dpi=1200,
                    facecolor='w', edgecolor='k', sharex=True) # Mind shared axis
            f.subplots_adjust(hspace=0.1, top=0.95, left=0.135, bottom=0.125, right=0.975)  
            f.suptitle(title, y=0.99,fontsize=8) # 
                
            # Top: apparent resistivity and points from Weaver for comparison:
            ax[0].plot(x, y0, color='red',  label = 'escript')
            ax[0].plot(xs,ra, linestyle='', markersize=3, marker='o',
                    color='blue', label = 'Weaver') 
            ax[0].grid(b=True, which='both', color='grey',linestyle=':')
            ax[0].set_ylabel( ylbl0)
            ax[0].yaxis.set_label_coords(-0.082, 0.5)
            # Plot limits:
            ax[0].set_xlim(x0lim)      
            #ax[0].set_ylim(y1lim)    

            # Bottom: phase on linear plot
            ax[1].plot(x,y1, color='blue')
            ax[1].grid(b=True, which='both', color='grey',linestyle=':')
            ax[1].set_xlabel( xlbl1 )
            ax[1].set_ylabel( ylbl1 )
            # Plot limits:
            ax[1].set_xlim(x0lim)      
            #ax[1].set_ylim(y2lim)     

            # ask matplotlib for the plotted objects and their labels
            lna, la = ax[0].get_legend_handles_labels()
            ax[0].legend(lna, la, bbox_to_anchor=(0.02, 0.325), loc=2,
                    borderaxespad=0.,prop={'size':8}, frameon=False)

            pyplot.ticklabel_format(style='sci', axis='x', scilimits=(0,0),
                    useMathText=True)
            ax[0].xaxis.major.formatter._useMathText = True
            pyplot.rc('font', **{'size': 8,'family':'sans-serif'})
        #uncomment to allow visual inspection
        #f.savefig("mesh/commemi-4/commemi4_"+mode.lower()+".png", dpi=1200)

        # Now let's see if the points match
        # First, we need to find correspondance between xs and x
        indices=[]
        for i in range(len(xs)):
            mindiff=40000
            mindex=0
            for j in range(len(x)):
                if abs(xs[i]-x[j]) < mindiff: 
                    mindiff=abs(xs[i]-x[j])
                    mindex=j
            indices.append(mindex)
            
        # The following are very simple checks based on the visual shape of the correct result        
        maxdiff=0
        for i in range(len(indices)):
            if abs(y0[indices[i]]-ra[i])>maxdiff:
                maxdiff=abs(y0[indices[i]]-ra[i])
            
        if maxdiff>5:           #Threshold is pretty arbitrary
            raise RuntimeError("Mismatch with reference data")

        c=0
        for y in y1:
            if y<46:
                c+=1

        if not (62 < escript.Lsup(y1) < 64):
            raise RuntimeError("Peak of bottom plot is off.")
            
        if not (0.61 < c/len(y1) < 0.65):
            print(c/len(y1))
            raise RuntimeError("Bottom plot has too many high points")

        #
        print("Runtime:", datetime.datetime.now()-startTime)
        print("Done!")