def diffusion(fce): if self.useLaplace: return nu * inner(grad(fce), grad(v1)) * dx else: form = inner(nu * 2 * sym(grad(fce)), sym(grad(v1))) * dx if self.bcv == 'CDN': return form if self.bcv == 'LAP': return form - inner(nu * dot(grad(fce).T, n), v1) * problem.get_outflow_measure_form() if self.bcv == 'DDN': return form # additional term must be added to non-constant part
def diffusion(fce): if self.useLaplace: return nu*inner(grad(fce), grad(v1)) * dx else: form = inner(nu * 2 * sym(grad(fce)), sym(grad(v1))) * dx if self.bcv == 'CDN': # IMP will work only if p=0 on output, or we must add term # inner(p0*n, v)*problem.get_outflow_measure_form() to avoid boundary layer return form if self.bcv == 'LAP': return form - inner(nu*dot(grad(fce).T, n), v1) * problem.get_outflow_measure_form() if self.bcv == 'DDN': # IMP will work only if p=0 on output, or we must add term # inner(p0*n, v)*problem.get_outflow_measure_form() to avoid boundary layer return form # additional term must be added to non-constant part
def nonlinearity(function): if self.use_ema: return 2*inner(dot(sym(grad(function)), u_ext), v1) * dx + inner(div(function)*u_ext, v1) * dx # return 2*inner(dot(sym(grad(function)), u_ext), v) * dx + inner(div(u_ext)*function, v) * dx # QQ implement this way? else: return inner(dot(grad(function), u_ext), v1) * dx
def compute_functionals(self, velocity, pressure, t): if self.args.wss: info('Computing stress tensor') I = Identity(velocity.geometric_dimension()) T = TensorFunctionSpace(self.mesh, 'Lagrange', 1) stress = project(-pressure*I + 2*sym(grad(velocity)), T) info('Generating boundary mesh') wall_mesh = BoundaryMesh(self.mesh, 'exterior') # wall_mesh = SubMesh(self.mesh, self.facet_function, 1) # QQ why does not work? # plot(wall_mesh, interactive=True) info(' Boundary mesh geometric dim: %d' % wall_mesh.geometry().dim()) info(' Boundary mesh topologic dim: %d' % wall_mesh.topology().dim()) info('Projecting stress to boundary mesh') Tb = TensorFunctionSpace(wall_mesh, 'Lagrange', 1) stress_b = interpolate(stress, Tb) self.fileDict['wss']['file'] << stress_b if False: # does not work info('Computing WSS') n = FacetNormal(wall_mesh) info(stress_b, True) # wss = stress_b*n - inner(stress_b*n, n)*n wss = dot(stress_b, n) - inner(dot(stress_b, n), n)*n # equivalent Vb = VectorFunctionSpace(wall_mesh, 'Lagrange', 1) Sb = FunctionSpace(wall_mesh, 'Lagrange', 1) # wss_func = project(wss, Vb) wss_norm = project(sqrt(inner(wss, wss)), Sb) plot(wss_norm, interactive=True)
def compute_functionals(self, velocity, pressure, t, step): if self.args.wss == 'all' or \ (step >= self.stepsInCycle and self.args.wss == 'peak' and (self.distance_from_chosen_steps < 0.5 * self.metadata['dt'])): # TODO check if choosing time steps works properly # QQ might skip step? change 0.5 to 0.51? self.tc.start('WSS') begin('WSS (%dth step)' % step) if self.args.wss_method == 'expression': stress = project(self.nu*2*sym(grad(velocity)), self.T) # pressure is not used as it contributes only to the normal component stress.set_allow_extrapolation(True) # need because of some inaccuracies in BoundaryMesh coordinates stress_b = interpolate(stress, self.Tb) # restrict stress to boundary mesh # self.fileDict['stress']['file'].write(stress_b, self.actual_time) # info('Saved stress tensor') info('Computing WSS') wss = dot(stress_b, self.nb) - inner(dot(stress_b, self.nb), self.nb)*self.nb wss_func = project(wss, self.Vb) wss_norm = project(sqrt_ufl(inner(wss, wss)), self.Sb) info('Saving WSS') self.fileDict['wss']['file'].write(wss_func, self.actual_time) self.fileDict['wss_norm']['file'].write(wss_norm, self.actual_time) if self.args.wss_method == 'integral': wss_norm = Function(self.SDG) mS = TestFunction(self.SDG) scaling = 1/FacetArea(self.mesh) stress = self.nu*2*sym(grad(velocity)) wss = dot(stress, self.normal) - inner(dot(stress, self.normal), self.normal)*self.normal wss_norm_form = scaling*mS*sqrt_ufl(inner(wss, wss))*ds # ds is integral over exterior facets only assemble(wss_norm_form, tensor=wss_norm.vector()) self.fileDict['wss_norm']['file'].write(wss_norm, self.actual_time) # to get vector WSS values: # NT this works, but in ParaView for (DG,1)-vector space glyphs are displayed in cell centers # wss_vector = [] # for i in range(3): # wss_component = Function(self.SDG) # wss_vector_form = scaling*wss[i]*mS*ds # assemble(wss_vector_form, tensor=wss_component.vector()) # wss_vector.append(wss_component) # wss_func = project(as_vector(wss_vector), self.VDG) # self.fileDict['wss']['file'].write(wss_func, self.actual_time) self.tc.end('WSS') end()
def save_vel(self, is_tent, field, t): self.vFunction.assign(field) self.fileDict['u2' if is_tent else 'u']['file'] << self.vFunction if self.doSaveDiff: self.vFunction.assign((1.0 / self.vel_normalization_factor[0]) * (field - self.solution)) self.fileDict['u2D' if is_tent else 'uD']['file'] << self.vFunction if self.args.ldsg: # info(div(2.*sym(grad(field))-grad(field)).ufl_shape) form = div(2.*sym(grad(field))-grad(field)) self.pFunction.assign(project(sqrt_ufl(inner(form, form)), self.pSpace)) self.fileDict['ldsg2' if is_tent else 'ldsg']['file'] << self.pFunction
def eps(v): return sym(grad(v))
def sigma(w, gdim): return 2.0 * mu * ufl.sym(grad(w)) + lmbda * ufl.tr( grad(w)) * ufl.Identity(gdim)
def strain(u): return sym(grad(u))
def _e(u): return ufl.sym(ufl.grad(u))
def sigma(v): return (2.0 * mu * ufl.sym(ufl.grad(v)) + lmbda * ufl.tr(ufl.sym(ufl.grad(v))) * ufl.Identity(len(v)))
def nonlinearity(function): if self.args.ema: return 2 * inner(dot(sym(grad(function)), u_ext), v1 ) * dx + inner(div(function) * u_ext, v1) * dx else: return inner(dot(grad(function), u_ext), v1) * dx
def sym_grad(u: Expr): return sym(grad(u))
def T(u): return -p * I + 2.0 * nu * sym(grad(u))
def symgrad(v): return ufl.sym(ufl.nabla_grad(v))
def test_diff_then_integrate(): # Define 1D geometry n = 21 mesh = UnitIntervalMesh(MPI.COMM_WORLD, n) # Shift and scale mesh x0, x1 = 1.5, 3.14 mesh.coordinates()[:] *= (x1 - x0) mesh.coordinates()[:] += x0 x = SpatialCoordinate(mesh)[0] xs = 0.1 + 0.8 * x / x1 # scaled to be within [0.1,0.9] # Define list of expressions to test, and configure # accuracies these expressions are known to pass with. # The reason some functions are less accurately integrated is # likely that the default choice of quadrature rule is not perfect F_list = [] def reg(exprs, acc=10): for expr in exprs: F_list.append((expr, acc)) # FIXME: 0*dx and 1*dx fails in the ufl-ffcx-jit framework somewhere # reg([Constant(0.0, cell=cell)]) # reg([Constant(1.0, cell=cell)]) monomial_list = [x**q for q in range(2, 6)] reg(monomial_list) reg([2.3 * p + 4.5 * q for p in monomial_list for q in monomial_list]) reg([x**x]) reg([x**(x**2)], 8) reg([x**(x**3)], 6) reg([x**(x**4)], 2) # Special functions: reg([atan(xs)], 8) reg([sin(x), cos(x), exp(x)], 5) reg([ln(xs), pow(x, 2.7), pow(2.7, x)], 3) reg([asin(xs), acos(xs)], 1) reg([tan(xs)], 7) try: import scipy except ImportError: scipy = None if hasattr(math, 'erf') or scipy is not None: reg([erf(xs)]) else: print( "Warning: skipping test of erf, old python version and no scipy.") # if 0: # print("Warning: skipping tests of bessel functions, doesn't build on all platforms.") # elif scipy is None: # print("Warning: skipping tests of bessel functions, missing scipy.") # else: # for nu in (0, 1, 2): # # Many of these are possibly more accurately integrated, # # but 4 covers all and is sufficient for this test # reg([bessel_J(nu, xs), bessel_Y(nu, xs), bessel_I(nu, xs), bessel_K(nu, xs)], 4) # To handle tensor algebra, make an x dependent input tensor # xx and square all expressions def reg2(exprs, acc=10): for expr in exprs: F_list.append((inner(expr, expr), acc)) xx = as_matrix([[2 * x**2, 3 * x**3], [11 * x**5, 7 * x**4]]) x3v = as_vector([3 * x**2, 5 * x**3, 7 * x**4]) cc = as_matrix([[2, 3], [4, 5]]) reg2([xx]) reg2([x3v]) reg2([cross(3 * x3v, as_vector([-x3v[1], x3v[0], x3v[2]]))]) reg2([xx.T]) reg2([tr(xx)]) reg2([det(xx)]) reg2([dot(xx, 0.1 * xx)]) reg2([outer(xx, xx.T)]) reg2([dev(xx)]) reg2([sym(xx)]) reg2([skew(xx)]) reg2([elem_mult(7 * xx, cc)]) reg2([elem_div(7 * xx, xx + cc)]) reg2([elem_pow(1e-3 * xx, 1e-3 * cc)]) reg2([elem_pow(1e-3 * cc, 1e-3 * xx)]) reg2([elem_op(lambda z: sin(z) + 2, 0.03 * xx)], 2) # pretty inaccurate... # FIXME: Add tests for all UFL operators: # These cause discontinuities and may be harder to test in the # above fashion: # 'inv', 'cofac', # 'eq', 'ne', 'le', 'ge', 'lt', 'gt', 'And', 'Or', 'Not', # 'conditional', 'sign', # 'jump', 'avg', # 'LiftingFunction', 'LiftingOperator', # FIXME: Test other derivatives: (but algorithms for operator # derivatives are the same!): # 'variable', 'diff', # 'Dx', 'grad', 'div', 'curl', 'rot', 'Dn', 'exterior_derivative', # Run through all operators defined above and compare integrals debug = 0 for F, acc in F_list: # Apply UFL differentiation f = diff(F, SpatialCoordinate(mesh))[..., 0] if debug: print(F) print(x) print(f) # Apply integration with DOLFINX # (also passes through form compilation and jit) M = f * dx f_integral = assemble_scalar(M) # noqa f_integral = mesh.mpi_comm().allreduce(f_integral, op=MPI.SUM) # Compute integral of f manually from anti-derivative F # (passes through pybind11 interface and uses UFL evaluation) F_diff = F((x1, )) - F((x0, )) # Compare results. Using custom relative delta instead # of decimal digits here because some numbers are >> 1. delta = min(abs(f_integral), abs(F_diff)) * 10**-acc assert f_integral - F_diff <= delta
def test_div_grad_then_integrate_over_cells_and_boundary(): # Define 2D geometry n = 10 mesh = RectangleMesh( [numpy.array([0.0, 0.0, 0.0]), numpy.array([2.0, 3.0, 0.0])], 2 * n, 3 * n) x, y = SpatialCoordinate(mesh) xs = 0.1 + 0.8 * x / 2 # scaled to be within [0.1,0.9] # ys = 0.1 + 0.8 * y / 3 # scaled to be within [0.1,0.9] n = FacetNormal(mesh) # Define list of expressions to test, and configure accuracies # these expressions are known to pass with. The reason some # functions are less accurately integrated is likely that the # default choice of quadrature rule is not perfect F_list = [] def reg(exprs, acc=10): for expr in exprs: F_list.append((expr, acc)) # FIXME: 0*dx and 1*dx fails in the ufl-ffcx-jit framework somewhere # reg([Constant(0.0, cell=cell)]) # reg([Constant(1.0, cell=cell)]) monomial_list = [x**q for q in range(2, 6)] reg(monomial_list) reg([2.3 * p + 4.5 * q for p in monomial_list for q in monomial_list]) reg([xs**xs]) reg( [xs**(xs**2)], 8 ) # Note: Accuracies here are from 1D case, not checked against 2D results. reg([xs**(xs**3)], 6) reg([xs**(xs**4)], 2) # Special functions: reg([atan(xs)], 8) reg([sin(x), cos(x), exp(x)], 5) reg([ln(xs), pow(x, 2.7), pow(2.7, x)], 3) reg([asin(xs), acos(xs)], 1) reg([tan(xs)], 7) # To handle tensor algebra, make an x dependent input tensor # xx and square all expressions def reg2(exprs, acc=10): for expr in exprs: F_list.append((inner(expr, expr), acc)) xx = as_matrix([[2 * x**2, 3 * x**3], [11 * x**5, 7 * x**4]]) xxs = as_matrix([[2 * xs**2, 3 * xs**3], [11 * xs**5, 7 * xs**4]]) x3v = as_vector([3 * x**2, 5 * x**3, 7 * x**4]) cc = as_matrix([[2, 3], [4, 5]]) reg2( [xx] ) # TODO: Make unit test for UFL from this, results in listtensor with free indices reg2([x3v]) reg2([cross(3 * x3v, as_vector([-x3v[1], x3v[0], x3v[2]]))]) reg2([xx.T]) reg2([tr(xx)]) reg2([det(xx)]) reg2([dot(xx, 0.1 * xx)]) reg2([outer(xx, xx.T)]) reg2([dev(xx)]) reg2([sym(xx)]) reg2([skew(xx)]) reg2([elem_mult(7 * xx, cc)]) reg2([elem_div(7 * xx, xx + cc)]) reg2([elem_pow(1e-3 * xxs, 1e-3 * cc)]) reg2([elem_pow(1e-3 * cc, 1e-3 * xx)]) reg2([elem_op(lambda z: sin(z) + 2, 0.03 * xx)], 2) # pretty inaccurate... # FIXME: Add tests for all UFL operators: # These cause discontinuities and may be harder to test in the # above fashion: # 'inv', 'cofac', # 'eq', 'ne', 'le', 'ge', 'lt', 'gt', 'And', 'Or', 'Not', # 'conditional', 'sign', # 'jump', 'avg', # 'LiftingFunction', 'LiftingOperator', # FIXME: Test other derivatives: (but algorithms for operator # derivatives are the same!): # 'variable', 'diff', # 'Dx', 'grad', 'div', 'curl', 'rot', 'Dn', 'exterior_derivative', # Run through all operators defined above and compare integrals debug = 0 if debug: F_list = F_list[1:] for F, acc in F_list: if debug: print('\n', "F:", str(F)) # Integrate over domain and its boundary int_dx = assemble(div(grad(F)) * dx(mesh)) # noqa int_ds = assemble(dot(grad(F), n) * ds(mesh)) # noqa if debug: print(int_dx, int_ds) # Compare results. Using custom relative delta instead of # decimal digits here because some numbers are >> 1. delta = min(abs(int_dx), abs(int_ds)) * 10**-acc assert int_dx - int_ds <= delta
def epsilon(v): return sym(grad(v))
def strain(v): return ufl.sym(ufl.grad(v))
def sym_grad(u: Expr): return ufl.sym(ufl.grad(u))
def sigma(v): return 2.0 * mu * sym(grad(v)) + lmbda * tr(sym(grad(v))) * Identity( len(v))
def nonlinearity(function): if self.args.ema: return 2 * inner(dot(sym(grad(function)), u_ext), v1) * dx + inner(div(function) * u_ext, v1) * dx else: return inner(dot(grad(function), u_ext), v1) * dx
def σ(v): """Return an expression for the stress σ given a displacement field""" return 2.0 * μ * ufl.sym(grad(v)) + λ * ufl.tr(ufl.sym( grad(v))) * ufl.Identity(len(v))
init_from_file_parameter_scalar_to_tensor(k, "data/het_0.csv") T = 500.0 t = 0.0 dt = 20.0 bcd1 = DirichletBC(W.sub(0).sub(0), Constant(0.0), boundaries, 1) # No normal displacement for solid on left side bcd3 = DirichletBC(W.sub(0).sub(0), Constant(0.0), boundaries, 3) # No normal displacement for solid on right side bcd4 = DirichletBC(W.sub(0).sub(1), Constant(0.0), boundaries, 4) # No normal displacement for solid on bottom side bcs = BlockDirichletBC([[bcd1, bcd3, bcd4], []]) a = inner(2 * mu_l * strain(u) + lmbda_l * div(u) * I, sym(grad(v))) * dx b = inner(-alpha * p * I, sym(grad(v))) * dx c = rho * alpha * div(u) * q * dx d = (rho * ct * p * q * dx + dt * dot(rho * k / vis * grad(p), grad(q)) * dx - dt * dot(avg_w(rho * k / vis * grad(p), weight_e(k, n)), jump(q, n)) * dS - theta * dt * dot(avg_w(rho * k / vis * grad(q), weight_e(k, n)), jump(p, n)) * dS + dt * penalty1 / h_avg * avg(rho) * k_e(k, n) / avg(vis) * dot(jump(p, n), jump(q, n)) * dS - dt * dot(rho * k / vis * grad(p), q * n) * ds(2) - dt * dot(rho * k / vis * grad(q), p * n) * ds(2) + dt * (penalty2 / h * rho / vis * dot(dot(n, k), n) * dot(p * n, q * n)) *
def stress_rebar(E, displ): return E * D_rebar_map(ufl.sym(ufl.grad(displ)))
def T(p, v): return -p * I + 2.0 * self.nu * sym(grad(v))
def eps(self, u): """Strain tensor as a function of the displacement""" return sym(grad(u))