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)
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)
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
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
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!")
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)
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
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!")