def main(viscosity=1.3e-3, density=1e3, pout=223e5, uw=-0.01, nelems=10): # viscosity = 1.3e-3 # density = 1e3 # pout = 223e5 # nelems = 10 # uw = -0.01 domain, geom = mesh.rectilinear([numpy.linspace(0, 1, nelems), numpy.linspace(1, 2, nelems), [0, 2 * numpy.pi]], periodic=[2]) domain = domain.withboundary(inner='bottom', outer='top') ns = function.Namespace() ns.y, ns.r, ns.θ = geom ns.x_i = '<r cos(θ), y, r sin(θ)>_i' ns.uybasis, ns.urbasis, ns.pbasis = function.chain([ domain.basis('std', degree=3, removedofs=((0,-1), None, None)), # remove normal component at y=0 and y=1 domain.basis('std', degree=3, removedofs=((0,-1), None, None)), # remove tangential component at y=0 (no slip) domain.basis('std', degree=2)]) ns.ubasis_ni = '<urbasis_n cos(θ), uybasis_n, urbasis_n sin(θ)>_i' ns.viscosity = viscosity ns.density = density ns.u_i = 'ubasis_ni ?lhs_n' ns.p = 'pbasis_n ?lhs_n' ns.sigma_ij = 'viscosity (u_i,j + u_j,i) - p δ_ij' ns.pout = pout ns.uw = uw ns.uw_i = 'uw <cos(phi), 0, sin(phi)>_i' ns.tout_i = '-pout n_i' ns.uw_i = 'uw n_i' # uniform outflow res = domain.integral('(viscosity ubasis_ni,j u_i,j - p ubasis_ni,i + pbasis_n u_k,k) d:x' @ ns, degree=6) # res -= domain[1].boundary['inner'].integral('ubasis_ni tout_i d:x' @ ns, degree=6) sqr = domain.boundary['inner'].integral('(u_i - uw_i) (u_i - uw_i) d:x' @ ns, degree=6) # sqr = domain.boundary['outer'].integral('(u_i - uin_i) (u_i - uin_i) d:x' @ ns, degree=6) sqr -= domain.boundary['outer'].integral('(p - pout) (p - pout) d:x' @ ns, degree=6) cons = solver.optimize('lhs', sqr, droptol=1e-15) lhs = solver.solve_linear('lhs', res, constrain=cons) plottopo = domain[:, :, 0:].boundary['back'] bezier = plottopo.sample('bezier', 10) r, y, p, u = bezier.eval([ns.r, ns.y, ns.p, function.norm2(ns.u)], lhs=lhs) with export.mplfigure('pressure.png', dpi=800) as fig: ax = fig.add_subplot(111, title='pressure', aspect=1) ax.autoscale(enable=True, axis='both', tight=True) im = ax.tripcolor(r, y, bezier.tri, p, shading='gouraud', cmap='jet') ax.add_collection( collections.LineCollection(numpy.array([y, r]).T[bezier.hull], colors='k', linewidths=0.2, alpha=0.2)) fig.colorbar(im) uniform = plottopo.sample('uniform', 1) r_, y_, uv = uniform.eval([ns.r, ns.y, ns.u], lhs=lhs) with export.mplfigure('velocity.png', dpi=800) as fig: ax = fig.add_subplot(111, title='Velocity', aspect=1) ax.autoscale(enable=True, axis='both', tight=True) im = ax.tripcolor(r, y, bezier.tri, u, shading='gouraud', cmap='jet') ax.quiver(r_, y_, uv[:, 0], uv[:, 1], angles='xy', scale_units='xy') fig.colorbar(im)
def _plot(suffix, name='solution', figsize=(10, 10), index=None, mesh=None, xlim=None, ylim=None, axes=True, show=False, segments=None, ndigits=4, **kwargs): if ndigits is None: ndigits = 0 if index is None else 4 filename = f'{name}-{suffix}' if index: filename += f'-{index:0{ndigits}}' filename += '.png' with export.mplfigure(filename, figsize=figsize) as fig: ax = fig.add_subplot(111) yield (fig, ax) if mesh is not None: collection = LineCollection(mesh, colors='black', linewidth=0.1, alpha=1.0) ax.add_collection(collection) ax.set_aspect('equal') ax.autoscale(enable=True, axis='both', tight=True) if xlim: ax.set_xlim(*xlim) if ylim: ax.set_ylim(*ylim) if not axes: ax.axis('off') if show: plt.show()
def postprocess(domain, ns, every=.05, spacing=.01, **arguments): div = domain.integral('d(u_k, x_k)^2 J(x)' @ ns, degree=1).eval(**arguments)**.5 treelog.info('velocity divergence: {:.2e}'.format(div)) # confirm that velocity is pointwise divergence-free ns = ns.copy_() # copy namespace so that we don't modify the calling argument ns.streambasis = domain.basis('std', degree=2)[1:] # remove first dof to obtain non-singular system ns.stream = 'streambasis_n ?streamdofs_n' # stream function ns.ε = function.levicivita(2) sqr = domain.integral('sum:i((u_i - ε_ij d(stream, x_j))^2) J(x)' @ ns, degree=4) arguments['streamdofs'] = solver.optimize('streamdofs', sqr, arguments=arguments) # compute streamlines bezier = domain.sample('bezier', 9) x, u, p, stream = bezier.eval(['x', 'norm2(u)', 'p', 'stream'] @ ns, **arguments) with export.mplfigure('flow.png') as fig: # plot velocity as field, pressure as contours, streamlines as dashed ax = fig.add_axes([.1,.1,.8,.8], yticks=[], aspect='equal') import matplotlib.collections ax.add_collection(matplotlib.collections.LineCollection(x[bezier.hull], colors='w', linewidths=.5, alpha=.2)) ax.tricontour(x[:,0], x[:,1], bezier.tri, stream, 16, colors='k', linestyles='dotted', linewidths=.5, zorder=9) caxu = fig.add_axes([.1,.1,.03,.8], title='velocity') imu = ax.tripcolor(x[:,0], x[:,1], bezier.tri, u, shading='gouraud', cmap='jet') fig.colorbar(imu, cax=caxu) caxu.yaxis.set_ticks_position('left') caxp = fig.add_axes([.87,.1,.03,.8], title='pressure') imp = ax.tricontour(x[:,0], x[:,1], bezier.tri, p, 16, cmap='gray', linestyles='solid') fig.colorbar(imp, cax=caxp)
def plotbuildup_1D(ns, bezier, x, p, TT, endtime, t2): """ Exports figures to public.html for the pressure and temperature 1D radial profile along the reservoir Arguments: ns (?): Namespace bezier (?): Parametric curve x (array): Radial position p (array): Fluid pressure T (array): System (Solid + Fluid) temperature endtime (float): Time that drawdown period ended t2 (float): Time of buildup period Returns: pressure1d (png): graph of 1D radial pressure temperature1d (png): graph of 1D radial temperature """ with export.mplfigure('pressure1d.png', dpi=800) as plt: ax = plt.subplots() ax.set(xlabel='Distance [m]', ylabel='Pressure [MPa]') ax.plot(nanjoin(x[:, 0], bezier.tri)[::100], nanjoin(p, bezier.tri)[::100] / 1e6, label="FEM") ax.plot(x[:, 0][::100], np.array(panalyticalbuildup(ns, endtime, t2, x[:, 0]))[0][0][0][::100] / 1e6, label="analytical") ax.legend(loc="center right") with export.mplfigure('temperature1d.png', dpi=800) as plt: ax = plt.subplots() ax.set(xlabel='Distance [m]', ylabel='Temperature [K]') # ax.set_ylim([362.85, 363.02]) ax.plot(nanjoin(x[:, 0], bezier.tri)[0:100000:10], nanjoin(TT, bezier.tri)[0:100000:10], label="FEM") ax.plot(nanjoin(x[:, 0], bezier.tri)[0:100000:10], np.array( Tanalyticalbuildup( ns, endtime, t2, nanjoin(x[:, 0], bezier.tri)[0:100000:10]))[0][0][0], label="analytical") ax.legend(loc="center right")
def postprocess(domain, ns, every=.05, spacing=.01, **arguments): ns = ns.copy_( ) # copy namespace so that we don't modify the calling argument ns.streambasis = domain.basis( 'std', degree=2)[1:] # remove first dof to obtain non-singular system ns.stream = 'streambasis_n ?streamdofs_n' # stream function sqr = domain.integral( '((u_0 - stream_,1)^2 + (u_1 + stream_,0)^2) d:x' @ ns, degree=4) arguments['streamdofs'] = solver.optimize( 'streamdofs', sqr, arguments=arguments) # compute streamlines bezier = domain.sample('bezier', 9) x, u, p, stream = bezier.eval(['x_i', 'sqrt(u_k u_k)', 'p', 'stream'] @ ns, **arguments) with export.mplfigure( 'flow.png' ) as fig: # plot velocity as field, pressure as contours, streamlines as dashed ax = fig.add_axes([.1, .1, .8, .8], yticks=[], aspect='equal') import matplotlib.collections ax.add_collection( matplotlib.collections.LineCollection(x[bezier.hull], colors='w', linewidths=.5, alpha=.2)) ax.tricontour(x[:, 0], x[:, 1], bezier.tri, stream, 16, colors='k', linestyles='dotted', linewidths=.5, zorder=9) caxu = fig.add_axes([.1, .1, .03, .8], title='velocity') imu = ax.tripcolor(x[:, 0], x[:, 1], bezier.tri, u, shading='gouraud', cmap='jet') fig.colorbar(imu, cax=caxu) caxu.yaxis.set_ticks_position('left') caxp = fig.add_axes([.87, .1, .03, .8], title='pressure') imp = ax.tricontour(x[:, 0], x[:, 1], bezier.tri, p, 16, cmap='gray', linestyles='solid') fig.colorbar(imp, cax=caxp)
def plotovertime(timeperiod, parraywell, parrayexact, Tarraywell, Tarrayexact, Qarray): with export.mplfigure('pressuretime.png', dpi=800) as plt: ax1 = plt.subplots() ax2 = ax1.twinx() ax1.set(xlabel='Time [s]') ax1.set_ylabel('Pressure [MPa]', color='b') ax2.set_ylabel('Volumetric flow rate [m^3/s]', color='k') ax1.plot(timeperiod, parraywell / 1e6, 'bo', label="FEM") ax1.plot(timeperiod, parrayexact / 1e6, label="analytical") # ax1.plot(timeperiod, parrayexp, label="NLOG") ax1.legend(loc="center right") ax2.plot(timeperiod, Qarray, 'k') # with export.mplfigure('pressuretimeerror.png', dpi=800) as plt: # ax1 = plt.subplots() # ax2 = ax1.twinx() # ax1.set(xlabel='Time [s]') # ax1.set(ylabel=r'$\left(\left|p_{w}-{p}_{w,exact}\right|/\left|p_{w,0}\right|\right)$', yscale="log") # ax2.set_ylabel('Volumetric flow rate [m^3/s]', color='k') # ax1.plot(timeperiod, parrayerror / 225e5, 'bo', label=r'$r_{dr} = 1000m$ refined mesh') # ax1.set_ylim(ymin=0.00005) # ax1.legend(loc="center right") # ax2.plot(timeperiod, Qarray, 'k') with export.mplfigure('temperaturetime.png', dpi=800) as plt: ax1 = plt.subplots() ax2 = ax1.twinx() # ax1.set_ylim([362.9, 363.1]) ax1.set(xlabel='Time [s]') ax1.set_ylabel('Temperature [K]', color='b') ax2.set_ylabel('Volumetric flow rate [m^3/s]', color='k') ax1.plot(timeperiod, Tarraywell, 'ro', label="FEM") ax1.plot(timeperiod, Tarrayexact, label="analytical") ax1.legend(loc="center right") ax2.plot(timeperiod, Qarray, 'k')
def test_autodetect_imagetype(self): for (imagetype, test) in ( ('jpg', lambda data: self.assertEqual(data[:3], b'\xFF\xD8\xFF')), ('png', lambda data: self.assertEqual( data[:8], b'\x89\x50\x4E\x47\x0D\x0A\x1A\x0A')), ('pdf', lambda data: self.assertEqual(data[:4], b'\x25\x50\x44\x46')), ('svg', lambda data: self.assertRegex(data, b'<svg[^<>]*>'))): with self.subTest(imagetype=imagetype): with export.mplfigure('test.{}'.format(imagetype)) as fig: ax = fig.add_subplot(111) ax.plot([1, 2, 3], [1, 2, 3]) with (self.outdir / 'test.{}'.format(imagetype)).open('rb') as f: test(f.read())
def main(nelems: int, degree: int, reynolds: float, rotation: float, timestep: float, maxradius: float, seed: int, endtime: float): ''' Flow around a cylinder. .. arguments:: nelems [24] Element size expressed in number of elements along the cylinder wall. All elements have similar shape with approximately unit aspect ratio, with elements away from the cylinder wall growing exponentially. degree [3] Polynomial degree for velocity space; the pressure space is one degree less. reynolds [1000] Reynolds number, taking the cylinder radius as characteristic length. rotation [0] Cylinder rotation speed. timestep [.04] Time step maxradius [25] Target exterior radius; the actual domain size is subject to integer multiples of the configured element size. seed [0] Random seed for small velocity noise in the intial condition. endtime [inf] Stopping time. ''' elemangle = 2 * numpy.pi / nelems melems = int(numpy.log(2 * maxradius) / elemangle + .5) treelog.info('creating {}x{} mesh, outer radius {:.2f}'.format( melems, nelems, .5 * numpy.exp(elemangle * melems))) domain, geom = mesh.rectilinear([melems, nelems], periodic=(1, )) domain = domain.withboundary(inner='left', outer='right') ns = function.Namespace() ns.uinf = 1, 0 ns.r = .5 * function.exp(elemangle * geom[0]) ns.Re = reynolds ns.phi = geom[1] * elemangle # add small angle to break element symmetry ns.x_i = 'r <cos(phi), sin(phi)>_i' ns.J = ns.x.grad(geom) ns.unbasis, ns.utbasis, ns.pbasis = function.chain([ # compatible spaces domain.basis( 'spline', degree=(degree, degree - 1), removedofs=((0, ), None)), domain.basis('spline', degree=(degree - 1, degree)), domain.basis('spline', degree=degree - 1), ]) / function.determinant(ns.J) ns.ubasis_ni = 'unbasis_n J_i0 + utbasis_n J_i1' # piola transformation ns.u_i = 'ubasis_ni ?lhs_n' ns.p = 'pbasis_n ?lhs_n' ns.sigma_ij = '(u_i,j + u_j,i) / Re - p δ_ij' ns.h = .5 * elemangle ns.N = 5 * degree / ns.h ns.rotation = rotation ns.uwall_i = '0.5 rotation <-sin(phi), cos(phi)>_i' inflow = domain.boundary['outer'].select( -ns.uinf.dotnorm(ns.x), ischeme='gauss1') # upstream half of the exterior boundary sqr = inflow.integral('(u_i - uinf_i) (u_i - uinf_i)' @ ns, degree=degree * 2) cons = solver.optimize( 'lhs', sqr, droptol=1e-15) # constrain inflow semicircle to uinf sqr = domain.integral('(u_i - uinf_i) (u_i - uinf_i) + p^2' @ ns, degree=degree * 2) lhs0 = solver.optimize('lhs', sqr) # set initial condition to u=uinf, p=0 numpy.random.seed(seed) lhs0 *= numpy.random.normal(1, .1, lhs0.shape) # add small velocity noise res = domain.integral( '(ubasis_ni u_i,j u_j + ubasis_ni,j sigma_ij + pbasis_n u_k,k) d:x' @ ns, degree=9) res += domain.boundary['inner'].integral( '(N ubasis_ni - (ubasis_ni,j + ubasis_nj,i) n_j) (u_i - uwall_i) d:x / Re' @ ns, degree=9) inertia = domain.integral('ubasis_ni u_i d:x' @ ns, degree=9) bbox = numpy.array( [[-2, 46 / 9], [-2, 2]]) # bounding box for figure based on 16x9 aspect ratio bezier0 = domain.sample('bezier', 5) bezier = bezier0.subset((bezier0.eval( (ns.x - bbox[:, 0]) * (bbox[:, 1] - ns.x)) > 0).all(axis=1)) interpolate = util.tri_interpolator( bezier.tri, bezier.eval(ns.x), mergetol=1e-5) # interpolator for quivers spacing = .05 # initial quiver spacing xgrd = util.regularize(bbox, spacing) with treelog.iter.plain( 'timestep', solver.impliciteuler('lhs', residual=res, inertia=inertia, lhs0=lhs0, timestep=timestep, constrain=cons, newtontol=1e-10)) as steps: for istep, lhs in enumerate(steps): t = istep * timestep x, u, normu, p = bezier.eval( ['x_i', 'u_i', 'sqrt(u_k u_k)', 'p'] @ ns, lhs=lhs) ugrd = interpolate[xgrd](u) with export.mplfigure('flow.png', figsize=(12.8, 7.2)) as fig: ax = fig.add_axes([0, 0, 1, 1], yticks=[], xticks=[], frame_on=False, xlim=bbox[0], ylim=bbox[1]) im = ax.tripcolor(x[:, 0], x[:, 1], bezier.tri, p, shading='gouraud', cmap='jet') import matplotlib.collections ax.add_collection( matplotlib.collections.LineCollection(x[bezier.hull], colors='k', linewidths=.1, alpha=.5)) ax.quiver(xgrd[:, 0], xgrd[:, 1], ugrd[:, 0], ugrd[:, 1], angles='xy', width=1e-3, headwidth=3e3, headlength=5e3, headaxislength=2e3, zorder=9, alpha=.5) ax.plot(0, 0, 'k', marker=(3, 2, t * rotation * 180 / numpy.pi - 90), markersize=20) cax = fig.add_axes([0.9, 0.1, 0.01, 0.8]) cax.tick_params(labelsize='large') fig.colorbar(im, cax=cax) if t >= endtime: break xgrd = util.regularize(bbox, spacing, xgrd + ugrd * timestep) return lhs0, lhs
def main(fname: str, degree: int, Δuload: unit['mm'], nsteps: int, E: unit['GPa'], nu: float, σyield: unit['MPa'], hardening: unit['GPa'], referencedata: typing.Optional[str], testing: bool): ''' Plastic deformation of a perforated strip. .. arguments:: fname [strip.msh] Mesh file with units in [mm] degree [1] Finite element interpolation order Δuload [5μm] Load boundary displacement steps nsteps [11] Number of load steps E [70GPa] Young's modulus nu [0.2] Poisson ratio σyield [243MPa] Yield strength hardening [2.25GPa] Hardening parameter referencedata [zienkiewicz.csv] Reference data file name testing [False] Use a 1 element mesh for testing .. presets:: testing nsteps=30 referencedata= testing=True ''' # We commence with reading the mesh from the specified GMSH file, or, alternatively, # we continue with a single-element mesh for testing purposes. domain, geom = mesh.gmsh(pathlib.Path(__file__).parent/fname) Wdomain, Hdomain = domain.boundary['load'].integrate([function.J(geom),geom[1]*function.J(geom)], degree=1) Hdomain /= Wdomain if testing: domain, geom = mesh.rectilinear([numpy.linspace(0,Wdomain/2,2),numpy.linspace(0,Hdomain,2)]) domain = domain.withboundary(hsymmetry='left', vsymmetry='bottom', load='top') # We next initiate the point set in which the constitutive bahvior will be evaluated. # Note that this is also the point set in which the history variable will be stored. gauss = domain.sample('gauss', 2) # Elasto-plastic formulation # ========================== # The weak formulation is constructed using a `Namespace`, which is initialized and # populated with the necessary problem parameters and coordinate system. Note that the # coefficients `mu` and `λ` have been defined such that 'C_{ijkl}' is the fourth-order # **plane stress** elasticity tensor. ns = function.Namespace(fallback_length=domain.ndims) ns.x = geom ns.Δuload = Δuload ns.mu = E/(1-nu**2)*((1-nu)/2) ns.λ = E/(1-nu**2)*nu ns.delta = function.eye(domain.ndims) ns.C_ijkl = 'mu ( delta_ik delta_jl + delta_il delta_jk ) + λ delta_ij delta_kl' # We make use of a Lagrange finite element basis of arbitrary `degree`. Since we # approximate the displacement field, the basis functions are vector-valued. Both # the displacement field at the current load step `u` and displacement field of the # previous load step `u0` are approximated using this basis: ns.basis = domain.basis('std',degree=degree).vector(domain.ndims) ns.u0_i = 'basis_ni ?lhs0_n' ns.u_i = 'basis_ni ?lhs_n' # This simulation is based on a standard elasto-plasticity model. In this # model the *total strain*, ε_kl = ½ (∂u_k/∂x_l + ∂u_l/∂x_k)', is comprised of an # elastic and a plastic part: # # ε_kl = εe_kl + εp_kl # # The stress is related to the *elastic strain*, εe_kl, through Hooke's law: # # σ_ij = C_ijkl εe_kl = C_ijkl (ε_kl - εp_kl) ns.ε_kl = '(u_k,l + u_l,k) / 2' ns.ε0_kl = '(u0_k,l + u0_l,k) / 2' ns.gbasis = gauss.basis() ns.εp0_ij = 'gbasis_n ?εp0_nij' ns.κ0 = 'gbasis_n ?κ0_n' ns.εp = PlasticStrain(ns.ε, ns.ε0, ns.εp0, ns.κ0, E, nu, σyield, hardening) ns.εe_ij = 'ε_ij - εp_ij' ns.σ_ij = 'C_ijkl εe_kl' # Note that the plasticity model is implemented through the user-defined function `PlasticStrain`, # which implements the actual yielding model including a standard return mapping algorithm. This # function is discussed in detail below. # # The components of the residual vector are then defined as: # # r_n = ∫_Ω (∂N_ni/∂x_j) σ_ij dΩ res = domain.integral('basis_ni,j σ_ij d:x' @ ns, degree=2) # The problem formulation is completed by supplementing prescribed displacement boundary conditions # (for a load step), which are computed in the standard manner: sqr = domain.boundary['hsymmetry,vsymmetry'].integral('(u_k n_k)^2 d:x' @ ns, degree=2) sqr += domain.boundary['load'].integral('(u_k n_k - Δuload)^2 d:x' @ ns, degree=2) cons = solver.optimize('lhs', sqr, droptol=1e-15) # Incremental-iterative solution procedure # ======================================== # We initialize the solution vector for the first load step `lhs` and solution vector # of the previous load step `lhs0`. Note that, in order to construct a predictor step # for the first load step, we define the previous load step state as the solution # vector corresponding to a negative elastic loading step. lhs0 = -solver.solve_linear('lhs', domain.integral('basis_ni,j C_ijkl ε_kl d:x' @ ns, degree=2), constrain=cons) lhs = numpy.zeros_like(lhs0) εp0 = numpy.zeros((gauss.npoints,)+ns.εp0.shape) κ0 = numpy.zeros((gauss.npoints,)+ns.κ0.shape) # To store the force-dispalcement data we initialize an empty data array with the # inital state solution substituted in the first row. fddata = numpy.empty(shape=(nsteps+1,2)) fddata[:] = numpy.nan fddata[0,:] = 0 # Load step incrementation # ------------------------ with treelog.iter.fraction('step', range(nsteps)) as counter: for step in counter: # The solution of the previous load step is set to `lhs0`, and the Newton solution # procedure is initialized by extrapolation of the state vector: lhs_init = lhs + (lhs-lhs0) lhs0 = lhs # The non-linear system of equations is solved for `lhs` using Newton iterations, # where the `step` variable is used to scale the incremental constraints. lhs = solver.newton(target='lhs', residual=res, constrain=cons*step, lhs0=lhs_init, arguments={'lhs0':lhs0,'εp0':εp0,'κ0':κ0}).solve(tol=1e-6) # The computed solution is post-processed in the form of a loading curve - which # plots the normalized mean stress versus the maximum 'ε_{yy}' strain # component - and a contour plot showing the 'σ_{yy}' stress component on a # deformed mesh. Note that since the stresses are defined in the integration points # only, a post-processing step is involved that transfers the stress information to # the nodal points. εyymax = gauss.eval(ns.ε[1,1], arguments=dict(lhs=lhs)).max() basis = domain.basis('std', degree=1) bw, b = domain.integrate([basis * ns.σ[1,1] * function.J(geom), basis * function.J(geom)], degree=2, arguments=dict(lhs=lhs,lhs0=lhs0,εp0=εp0,κ0=κ0)) σyy = basis.dot(bw / b) uyload, σyyload = domain.boundary['load'].integrate(['u_1 d:x'@ns,σyy * function.J(geom)], degree=2, arguments=dict(lhs=lhs,εp0=εp0,κ0=κ0)) uyload /= Wdomain σyyload /= Wdomain fddata[step,0] = (E*εyymax)/σyield fddata[step,1] = (σyyload*2)/σyield with export.mplfigure('forcedisp.png') as fig: ax = fig.add_subplot(111, xlabel=r'${E \cdot {\rm max}(\varepsilon_{yy})}/{\sigma_{\rm yield}}$', ylabel=r'${\sigma_{\rm mean}}/{\sigma_{\rm yield}}$') if referencedata: data = numpy.genfromtxt(pathlib.Path(__file__).parent/referencedata, delimiter=',', skip_header=1) ax.plot(data[:,0], data[:,1], 'r:', label='Reference') ax.legend() ax.plot(fddata[:,0], fddata[:,1], 'o-', label='Nutils') ax.grid() bezier = domain.sample('bezier', 3) points, uvals, σyyvals = bezier.eval(['(x_i + 25 u_i)' @ ns, ns.u, σyy], arguments=dict(lhs=lhs)) with export.mplfigure('stress.png') as fig: ax = fig.add_subplot(111, aspect='equal', xlabel=r'$x$ [mm]', ylabel=r'$y$ [mm]') im = ax.tripcolor(points[:,0]/unit('mm'), points[:,1]/unit('mm'), bezier.tri, σyyvals/unit('MPa'), shading='gouraud', cmap='jet') ax.add_collection(collections.LineCollection(points.take(bezier.hull, axis=0), colors='k', linewidths=.1)) ax.autoscale(enable=True, axis='both', tight=True) cb = fig.colorbar(im) im.set_clim(0, 1.2*σyield) cb.set_label(r'$σ_{yy}$ [MPa]') # Load step convergence # --------------------- # At the end of the loading step, the plastic strain state and history parameter are updated, # where use if made of the strain hardening relation for the history variable: # # Δκ = √(Δεp_ij Δεp_ij) Δεp = ns.εp-ns.εp0 Δκ = function.sqrt((Δεp*Δεp).sum((0,1))) κ0 = gauss.eval(ns.κ0+Δκ, arguments=dict(lhs0=lhs0,lhs=lhs,εp0=εp0,κ0=κ0)) εp0 = gauss.eval(ns.εp, arguments=dict(lhs0=lhs0,lhs=lhs,εp0=εp0,κ0=κ0))
def main(): # length = 1000 # selems = [length/25, # length/50, # length/100, # length/200, # length/400, # length/1000] # nelems = [2.5, # 5, # 10, # 20, # 40, # 100, # 200] #elements per 100m # print(selems) # # #t=600, L=1000 # pFEA = [22086111.42748884, # 21902014.957589053, # 21726777.721221756, # 21562538.447041728, #dz = 5m # 21411662.357217178, # 21243415.78431648] # pEX = [20700173.2868534, # 20700173.2868534, # 20700173.2868534, # 20700173.2868534, #dz = 5m # 20700173.2868534, # 20700173.2868534] # print(pFEA, pEX) # # # t=600, L=250 # pFEA2 = [22145699.217542585, # (21912576.577329777+21891746.037332077)/2, # 21726704.23802078, #dz = 10m # 21562470.026213087, #dz = 5m # 21411600.745572496, #dz = 2.5m # 21243475.78431648] #dz = 1m # # pEX2 = [20700173.2868534, # 20700173.2868534, # 20700173.2868534, # 20700173.2868534, #dz = 5m # 20700173.2868534, #dz = 2.5m # 20700173.2868534] #dz = 1m # # # # pFEA2refined = [21135143.533079684, # 21103572.526394643, #20m (5/100), (12.5 element op 250) # 21068682.36205357, #10m (10/100), (25 elements) # 21055465.52883131] #1m (100/100m), (250elements op L=250) # nelemsrefined = [2.5, # 5, # 10, # 100] # pEX2refined = [20700173.2868534, # 20700173.2868534, # 20700173.2868534, # 20700173.2868534] # # pFEA3refined = [21135143.533079684, # 21103572.526394643, # 20m (5/100), (12.5 element op 250) # 21068682.36205357, # 10m (10/100), (25 elements) # 21055465.52883131] # 1m (100/100m), (250elements op L=250) # nelemsrefined = [2.5, # 5, # 10, # 100] # pEX3refined = [20700173.2868534, # 20700173.2868534, # 20700173.2868534, # 20700173.2868534] # # # t=600 L=250 # dpFEA = [-1305968.4288678593, #dz = 20m # -2921755.772435982, # -5885792.714165609, # -11436990.774427539, #dz = 2.5m # -25816941.087984808, # -44298204.62592584] #dz = 0.5m # dpEX = [-35996534.26293199, #dz = 20m # -35996534.26293199, # -35996534.26293199, # -35996534.26293199, # -35996534.26293199, # -35996534.26293199] #R=1000m refined nelems = [20, 40, 60, 80, 100, 120] pFEA = [ 20741097.145456452, 20715231.891588964, 20710359.28744662, 20708647.638260685, 20721549.490607046, 20707423.04132063 ] pEX = [ 20700173.2868534, 20700173.2868534, 20700173.2868534, 20700173.2868534, 20713168.98464002, 20700173.2868534 ] dpFEA = [ -119927562.10910182, -137233382.50286353, -143126609.38124058, -146087319.8746748, -147867023.71421945, -149054570.09563407 ] dpEX = [ -35996534.26293199, -35996534.26293199, -35996534.26293199, -35996534.26293199, -35996534.26293199, -35996534.26293199 ] #calculate L2 and H1 error, ns.du_i = 'u_i - uexact_i' def calculate_L2(FEA, EX): dp = np.subtract(FEA, EX) l2error = (dp * np.transpose(dp))**0.5 return l2error def calculate_H1(FEA, EX, gradFEA, gradEX): dp = np.subtract(FEA, EX) dpdp = np.subtract(gradFEA, gradEX) H1error = (dp * np.transpose(dp) + dpdp * np.transpose(dpdp))**0.5 return H1error # with export.mplfigure('elemspressure.png', dpi=800) as plt: # ax1 = plt.subplots() # ax1.set(xlabel='dz [m]') # ax1.invert_xaxis() # ax1.set_ylabel('Pressure [Pa]') # ax1.plot(selems, pFEA, 'b--', label="FEA R=1000m") # ax1.plot(selems, pEX2, label="analytical") # ax1.plot(selems, pFEA2, '--', label="FEA R=250m") # ax1.legend(loc="center right") # # with export.mplfigure('error.png', dpi=800) as plt: # ax1 = plt.subplots() # ax1.set(xlabel='dz [m]') # ax1.invert_xaxis() # ax1.set_ylabel('Difference [-]') # ax1.plot(selems, dp/225e5, label="error") # ax1.legend(loc="center right") #number of elements per 100m #log plot # with export.mplfigure('relativeerrorL2.png', dpi=800) as plt: # # plt.add_axes([0.6, 0.3, 0.3, 0.3]) # ax1 = plt.subplots() # ax1.set(xlabel=r'$N_{e}$ per 100m', xscale="log") #'r'' # ax1.set(ylabel=r'$\left(\left|p_{w}-{p}_{w,exact}\right|/\left|p_{w,0}\right|\right)$', yscale="log") # ax1.plot(nelems, dp2/225e5, 'o--', color='orange', label=r'$r_{dr} = 250m$ uniform mesh') # ax1.plot(nelems, dp/225e5, 'ob--', label=r'$r_{dr} = 1000m$ uniform mesh') # ax1.plot(nelemsrefined, dp3/ 225e5, 'o--', label=r'$r_{dr} = 250m$ refined mesh') # ax1.legend(loc="upper right") # plt.tight_layout() # with export.mplfigure('errorL2.png', dpi=800) as plt: # plt.add_axes([0.6, 0.3, 0.3, 0.3]) ax1 = plt.subplots() ax1.set(xlabel=r'$N_{e}$') ax1.set(ylabel=r'$\left|p_{w}-{p}_{w,exact}\right|_{L^{2}-norm}$', yscale="log") ax1.plot(nelems, calculate_L2(pFEA, pEX), 'o--', color='red', label=r'$r_{dr} = 1000m$, refined mesh') ax1.legend(loc="upper right") plt.tight_layout() with export.mplfigure('errorH1.png', dpi=800) as plt: # plt.add_axes([0.6, 0.3, 0.3, 0.3]) ax1 = plt.subplots() ax1.set(xlabel=r'$N_{e}$') # 'r'' ax1.set( ylabel= r'$\sqrt{\left|(p_{w}-{p}_{w,exact})^2+(p_{w}^{\prime}-{p}_{w,exact}^{\prime})2\right|}{H^{1}-norm}$', yscale="log") ax1.plot(nelems, calculate_H1(pFEA, pEX, dpFEA, dpEX), 'o--', color='red', label=r'$r_{dr} = 1000m$, refined mesh') ax1.legend(loc="upper right") plt.tight_layout()