def __init__(self, model, particle, variation, kernel, options, comm): self.model = model self.particle = particle # number of particles self.variation = variation self.kernel = kernel self.options = options self.comm = comm self.rank = comm.Get_rank() self.nproc = comm.Get_size() self.save_kernel = options["save_kernel"] self.type_Hessian = options["type_Hessian"] self.ncalls = 0 self.gls = GlobalLocalSwitch(self.model, self.particle, self.options, self.comm) if not self.options["is_projection"]: if self.particle.number_particles_all == 1: z_trial = dl.TrialFunction(self.gls.Vh_Local) z_test = dl.TestFunction(self.gls.Vh_Local) self.Hessian = dl.assemble(z_trial * z_test * dl.dx) else: z_vec = [None] * particle.number_particles_all c_vec = [None] * particle.number_particles_all for n in range(particle.number_particles_all): z_trial = dl.TrialFunction(self.gls.Vh_Global.sub(0)) z_test = dl.TestFunction(self.gls.Vh_Global.sub(0)) z_vec[n] = z_trial c_vec[n] = z_test z_vec = dl.as_vector(z_vec) c_vec = dl.as_vector(c_vec) self.Hessian = dl.assemble(dl.dot(c_vec, z_vec) * dl.dx)
def bulk_electrostriction(E, e_r, p, direction, q_b): """ calculate the bulk electrostriction force """ pp = as_matrix(p) # photoelestic tensor is stored as as numpy array if direction == 'backward': EE_6vec_r = as_vector([ E[0] * E[0], E[1] * E[1], -E[2] * E[2], 0.0, 0.0, 2.0 * E[0] * E[1] ]) EE_6vec_i = as_vector( [0.0, 0.0, 0.0, 2.0 * E[1] * E[2], 2.0 * E[0] * E[2], 0.0]) sigma_r = -0.5 * epsilon_0 * e_r**2 * pp * EE_6vec_r sigma_i = -0.5 * epsilon_0 * e_r**2 * pp * EE_6vec_i f_r = f_elst_r(sigma_r, sigma_i, q_b) f_i = f_elst_i(sigma_r, sigma_i, q_b) elif direction == 'forward': EE_6vec_r = as_vector([ E[0] * E[0], E[1] * E[1], E[2] * E[2], 0.0, 0.0, 2.0 * E[0] * E[1] ]) # EE_6vec_i, sigma_i, q_b is zero sigma_r = -0.5 * epsilon_0 * e_r**2 * pp * EE_6vec_r # no need to multiply zeros ... f_r = as_vector([ -Dx(sigma_r[0], 0) - Dx(sigma_r[5], 1), -Dx(sigma_r[5], 0) - Dx(sigma_r[1], 1), -Dx(sigma_r[4], 0) - Dx(sigma_r[3], 1) ]) f_i = Constant((0.0, 0.0, 0.0), cell=triangle) #f_i = as_vector([ - q_b*sigma_r[4],- q_b*sigma_r[3],- q_b*sigma_r[2]]) else: raise ValueError('Specify scattering direction as forward or backward') return (f_r, f_i)
def test_bdm_identity_transform(gdim): N = 5 k = 2 # Create mesh and define a divergence free field if gdim == 2: mesh = dolfin.UnitSquareMesh(N, N) field = ['-sin(pi*x[1])*cos(pi*x[0])', 'sin(pi*x[0])*cos(pi*x[1])'] elif gdim == 3: mesh = dolfin.UnitCubeMesh(N, N, N) field = [ '-sin(pi*x[0])*cos(pi*x[1])*sin(pi*x[2])', 'sin(pi*x[0])*cos(pi*x[1])*sin(pi*x[2])', '-cos(pi*x[2])*cos(pi*(x[0]-x[1]))', ] V = dolfin.FunctionSpace(mesh, 'DG', k) u = dolfin.as_vector([dolfin.Function(V) for _ in range(gdim)]) a = dolfin.as_vector([dolfin.Function(V) for _ in range(gdim)]) # Make a divergence free field for i, cpp in enumerate(field): ei = dolfin.Expression(cpp, degree=k) u[i].interpolate(ei) a[i].assign(u[i]) # Run the projection into BDM and then assign this to u bdm = VelocityBDMProjection(simulation=Simulation(), w=u, use_bcs=False) bdm.run() # Check the changes made for ui, ai in zip(u, a): error = dolfin.errornorm(ai, ui, degree_rise=0) assert error < 1e-15
def permeability_tensor(self, K): FS = self.geometry.f0.function_space() TS = TensorFunctionSpace(self.geometry.mesh, 'P', 1) d = self.geometry.dim() fibers = Function(FS) fibers.vector()[:] = self.geometry.f0.vector().get_local() fibers.vector()[:] /= df.norm(self.geometry.f0) if self.geometry.s0 is not None: # normalize vectors sheet = Function(FS) sheet.vector()[:] = self.geometry.s0.vector().get_local() sheet.vector()[:] /= df.norm(self.geometry.s0) if d == 3: csheet = Function(FS) csheet.vector()[:] = self.geometry.n0.vector().get_local() csheet.vector()[:] /= df.norm(self.geometry.n0) else: return Constant(1) from ufl import diag factor = 10 if d == 3: ftensor = df.as_matrix(((fibers[0], sheet[0], csheet[0]), (fibers[1], sheet[1], csheet[1]), (fibers[2], sheet[2], csheet[2]))) ktensor = diag(df.as_vector([K, K / factor, K / factor])) else: ftensor = df.as_matrix( ((fibers[0], sheet[0]), (fibers[1], sheet[1]))) ktensor = diag(df.as_vector([K, K / factor])) permeability = df.project( df.dot(df.dot(ftensor, ktensor), df.inv(ftensor)), TS) return permeability
def Displacement2Epsilon0(self, U): """Converti le localisateur en deplacement en champ de predeformation a appliquer au probleme auxiliaire suivant""" Epsilon0 = [] for i in range(len(U)): Epsilon0 = Epsilon0 + [ fe.as_vector(( U[i][0], fe.interpolate(fe.Constant(0.0), self.X), U[i][1] / fe.sqrt(2), )) ] # zero_ = fe.interpolate(fe.Constant(0.0), self.X) # # Possibilité de mettre directement fe.Constant(0.0) ? # prestrain_ = (U[i][0], zero_, U[i][1] / fe.sqrt(2)) # prestrain_ = fe.as_vector(prestrain_) # Epsilon0.append(prestrain_) for i in range(len(U)): Epsilon0 = Epsilon0 + [ fe.as_vector(( fe.interpolate(fe.Constant(0.0), self.X), U[i][1], U[i][0] / fe.sqrt(2), )) ] # zero_ = fe.interpolate(fe.Constant(0.0), self.X) # # Possibilité de mettre directement fe.Constant(0.0) ? # prestrain_ = (zero_, U[i][1], U[i][0] / fe.sqrt(2)) # prestrain_ = fe.as_vector(prestrain_) # Epsilon0.append(prestrain_) return Epsilon0
def test_is_zero_simple_vector_expressions(): mesh = UnitSquareMesh(4, 4) V = FunctionSpace(mesh, 'CG', 1) v = TestFunction(V) u = TrialFunction(V) check_is_zero(dot(as_vector([Zero(), u]), as_vector([Zero(), v])), 1) check_is_zero(dot(as_vector([Zero(), u]), as_vector([v, Zero()])), 0)
def test_I5y(F_dict, F_str): F = F_dict[F_str] if "2D" in F_str: y = df.as_vector([0, 1]) else: y = df.as_vector([0, 1, 0]) assert abs(df.assemble(kinematics.I5(F, y) * df.dx) - B**4) < 1e-12
def test_I5x(F_dict, F_str): F = F_dict[F_str] if "2D" in F_str: x = df.as_vector([1, 0]) else: x = df.as_vector([1, 0, 0]) assert abs(df.assemble(kinematics.I5(F, x) * df.dx) - A**4) < 1e-12
def create_functions(self): """ Create functions to hold solutions """ sim = self.simulation # Function spaces Vu = sim.data['Vu'] Vp = sim.data['Vp'] cd = sim.data['constrained_domain'] # Create coupled mixed function space and mixed function to hold results func_spaces = [Vu] * sim.ndim + [Vp] self.subspace_names = ['u%d' % d for d in range(sim.ndim)] + ['p'] # Create stress tensor space P = Vu.ufl_element().degree() Vs = dolfin.FunctionSpace(sim.data['mesh'], 'DG', P, constrained_domain=cd) for i in range(sim.ndim**2): stress_name = 'stress_%d' % i sim.data[stress_name] = dolfin.Function(Vs) func_spaces.append(Vs) self.subspace_names.append(stress_name) # Create mixed space e_mixed = dolfin.MixedElement([fs.ufl_element() for fs in func_spaces]) Vcoupled = dolfin.FunctionSpace(sim.data['mesh'], e_mixed) sim.data['Vcoupled'] = Vcoupled # Create function assigner Nspace = len(func_spaces) self.subspaces = [Vcoupled.sub(i) for i in range(Nspace)] sim.data['coupled'] = self.coupled_func = dolfin.Function(Vcoupled) self.assigner = dolfin.FunctionAssigner(func_spaces, Vcoupled) # Create segregated functions on component and vector form u_list, up_list, upp_list, u_conv = [], [], [], [] for d in range(sim.ndim): sim.data['u%d' % d] = u = dolfin.Function(Vu) sim.data['up%d' % d] = up = dolfin.Function(Vu) sim.data['upp%d' % d] = upp = dolfin.Function(Vu) sim.data['u_conv%d' % d] = uc = dolfin.Function(Vu) u_list.append(u) up_list.append(up) upp_list.append(upp) u_conv.append(uc) sim.data['u'] = dolfin.as_vector(u_list) sim.data['up'] = dolfin.as_vector(up_list) sim.data['upp'] = dolfin.as_vector(upp_list) sim.data['u_conv'] = dolfin.as_vector(u_conv) sim.data['p'] = dolfin.Function(Vp)
def test_form_splitter_matrices(shape): mesh = UnitSquareMesh(dolfin.MPI.comm_self, 3, 3) Vu = FunctionSpace(mesh, 'DG', 2) Vp = FunctionSpace(mesh, 'DG', 1) def define_eq(u, v, p, q): "A simple Stokes-like coupled weak form" eq = Constant(2) * dot(u, v) * dx eq += dot(grad(p), v) * dx eq -= dot(Constant([1, 1]), v) * dx eq += dot(grad(q), u) * dx eq -= dot(Constant(0.3), q) * dx return eq if shape == (2, 2): eu = MixedElement([Vu.ufl_element(), Vu.ufl_element()]) ew = MixedElement([eu, Vp.ufl_element()]) W = FunctionSpace(mesh, ew) u, p = TrialFunctions(W) v, q = TestFunctions(W) u = as_vector([u[0], u[1]]) v = as_vector([v[0], v[1]]) elif shape == (3, 3): ew = MixedElement( [Vu.ufl_element(), Vu.ufl_element(), Vp.ufl_element()]) W = FunctionSpace(mesh, ew) u0, u1, p = TrialFunctions(W) v0, v1, q = TestFunctions(W) u = as_vector([u0, u1]) v = as_vector([v0, v1]) eq = define_eq(u, v, p, q) # Define coupled problem eq = define_eq(u, v, p, q) # Split the weak form into a saddle point block matrix system mat, vec = split_form_into_matrix(eq, W, W) # Check shape and that appropriate elements are none assert mat.shape == shape assert mat[-1, -1] is None for i in range(shape[0] - 1): for j in range(shape[1] - 1): if i != j: assert mat[i, j] is None # Check that the split matrices are identical with the # coupled matrix when reassembled into a single matrix compare_split_matrices(eq, mat, vec, W, W)
def fit_primitives(vec, deepcopy=False, indexed=True): assert not (deepcopy and indexed) N = self.parameters["N"] # 'self' is visible from here if indexed: ws = split(vec[0]) pv = [as_vector(ws[:N - 1]), as_vector(ws[N - 1:])] pv += list(split(vec[1])) else: ws = vec[0].split(deepcopy) pv = [as_vector(ws[:N - 1]), as_vector(ws[N - 1:])] pv += list(vec[1].split(deepcopy)) return tuple(pv)
def total_flux(Mo, rho_mat, chi): """ :returns: total flux :rtype: :py:class:`ufl.core.expr.Expr` """ N = len(rho_mat) rho_mat = list(map(Constant, rho_mat)) rho_diff = as_vector(rho_mat[:-1]) - as_vector((N - 1) * [ rho_mat[-1], ]) J = -Mo * dot(grad(chi).T, rho_diff) return J
def test_I8xy(F_dict, F_str): F = F_dict[F_str] if "2D" in F_str: x = df.as_vector([1, 0]) y = df.as_vector([0, 1]) else: x = df.as_vector([1, 0, 0]) y = df.as_vector([0, 1, 0]) assert ( abs(df.assemble(kinematics.I8(F, x, y) * df.dx) - (A**2 * 0 + 0 * B)) < 1e-12)
def define_coupled_equation(self): """ Setup the coupled Navier-Stokes equation This implementation assembles the full LHS and RHS each time they are needed """ Vcoupled = self.simulation.data['Vcoupled'] # Unpack the coupled trial and test functions uc = dolfin.TrialFunction(Vcoupled) vc = dolfin.TestFunction(Vcoupled) ulist = [] vlist = [] ndim = self.simulation.ndim for d in range(ndim): ulist.append(uc[d]) vlist.append(vc[d]) u = dolfin.as_vector(ulist) v = dolfin.as_vector(vlist) p = uc[ndim] q = vc[ndim] lm_trial = lm_test = None if self.use_lagrange_multiplicator: lm_trial = uc[ndim + 1] lm_test = vc[ndim + 1] assert self.flux_type == UPWIND eq = define_dg_equations( u, v, p, q, lm_trial, lm_test, self.simulation, include_hydrostatic_pressure=self.include_hydrostatic_pressure, incompressibility_flux_type=self.incompressibility_flux_type, use_grad_q_form=self.use_grad_q_form, use_grad_p_form=self.use_grad_p_form, use_stress_divergence_form=self.use_stress_divergence_form, velocity_continuity_factor_D12=self.velocity_continuity_factor_D12, pressure_continuity_factor=self.pressure_continuity_factor, ) a, L = dolfin.system(eq) self.form_lhs = a self.form_rhs = L self.tensor_lhs = None self.tensor_rhs = None
def eps(self, u): e = df.sym(df.grad(u)) dim = self.mesh.geometric_dimension() if dim == 1: return df.as_vector([e[0, 0]]) if dim == 2: return df.as_vector([e[0, 0], e[1, 1], 2 * e[0, 1]]) if dim == 3: return df.as_vector([ e[0, 0], e[1, 1], e[2, 2], 2 * e[1, 2], 2 * e[0, 2], 2 * e[0, 1] ])
def fit_primitives(vec, deepcopy=False, indexed=True): assert not (deepcopy and indexed) N = self.parameters["N"] # 'self' is visible from here if indexed: ws = split(vec[0]) # FIXME: Remove the following hack #ws_ch = split(ws[0]) # Not working with older versions of DOLFIN ws_ch = tuple([ws[0][i] for i in range(len(ws[0]))]) else: ws = vec[0].split(deepcopy) ws_ch = ws[0].split(deepcopy) pv = [as_vector(ws_ch[:N - 1]), as_vector(ws_ch[N - 1:])] pv += ws[1:] return tuple(pv)
def set_function_space(self): """set_function_space.""" self.V = df.VectorFunctionSpace(self.mesh,'P',1,dim=self.number_of_moment) #Set test function(s) v_list = df.TestFunctions(self.V) #Convert to ufl form self.v = df.as_vector(v_list) #set trial function(s) if self.problem_type == 'nonlinear': u_list = df.Function(self.V) elif self.problem_type == 'linear': u_list = df.TrialFunctions(self.V) #Convert to ufl form self.u = df.as_vector(u_list)
def updateCoefficients(self): # Init coefficient matrix x = SpatialCoordinate(self.mesh)[0] self.a = as_matrix([[.5 * (x * self.gamma[0] * self.sigmax)**2]]) self.b = as_vector([x * (self.gamma[0] * (self.mu - self.r) + self.r)]) self.c = Constant(0.0) # Init right-hand side self.f = Constant(0.0) self.u_ = exp( ((self.mu - self.r)**2 / (2 * self.sigmax**2) * self.alpha / (1 - self.alpha) + self.r * self.alpha) * (self.T[1] - self.t)) * (x**self.alpha) / self.alpha self.u_T = (x**self.alpha) / self.alpha # Set boundary conditions # self.g_t = lambda t : [(Constant(0.0), "near(x[0],0)")] self.g = Constant(0.0) # self.g_t = lambda t : self.u_t(t) self.gamma_star = [ Constant((self.mu - self.r) / (self.sigmax**2 * (1 - self.alpha))) ] self.loc = conditional(x > 0.5, conditional(x < 1.5, 1, 0), 0)
def setup(self): """ Create mesh velocity and deformation functions """ sim = self.simulation assert self.active is False, 'Trying to setup mesh morphing twice in the same simulation' # Store previous cell volumes mesh = sim.data['mesh'] Vcvol = dolfin.FunctionSpace(mesh, 'DG', 0) sim.data['cvolp'] = dolfin.Function(Vcvol) # The function spaces for mesh velocities and displacements Vmesh = dolfin.FunctionSpace(mesh, 'CG', 1) Vmesh_vec = dolfin.VectorFunctionSpace(mesh, 'CG', 1) sim.data['Vmesh'] = Vmesh # Create mesh velocity functions u_mesh = [] for d in range(sim.ndim): umi = dolfin.Function(Vmesh) sim.data['u_mesh%d' % d] = umi u_mesh.append(umi) u_mesh = dolfin.as_vector(u_mesh) sim.data['u_mesh'] = u_mesh # Create mesh displacement vector function self.displacement = dolfin.Function(Vmesh_vec) self.assigners = [ dolfin.FunctionAssigner(Vmesh_vec.sub(d), Vmesh) for d in range(sim.ndim) ] self.active = True
def sigma(self, uu): eps = self.RR*self.epsilon(uu)*self.RR.T ss = self.DD*dolfin.as_vector([eps[0, 0], eps[1, 1], eps[2, 2]]) ss_01 = 2*self.G_01*eps[0, 1] ss_02 = 2*self.G_02*eps[0, 2] ss_12 = 2*self.G_12*eps[1, 2] return self.RR.T*dolfin.as_matrix([[ss[0], ss_01, ss_02], [ss_01, ss[1], ss_12], [ss_02, ss_12, ss[2]]])*self.RR
def main(): args = get_settings() interp = itp.Interpolation(args.mesh_file_in, args.u_file_in, p_filename_in=args.p_file_in) interp.update(args.step) u_1 = interp.u p_1 = interp.p mesh_2 = import_mesh(args.other_mesh_in) S_2 = df.FunctionSpace(mesh_2, "CG", 1) u_ = dict() for key, val in u_1.iteritems(): u_[key] = ft.interpolate_nonmatching_mesh(val, S_2) u__ = df.as_vector([u_[key] for key in u_.keys()]) u = AssignedVectorFunction(u__) u() p = ft.interpolate_nonmatching_mesh(p_1, S_2) xdmff_u = df.XDMFFile(mesh_2.mpi_comm(), args.initfile_out + "_u.xdmf") xdmff_u.parameters["rewrite_function_mesh"] = False xdmff_u.parameters["flush_output"] = True xdmff_u.write(u, 0.) xdmff_p = df.XDMFFile(mesh_2.mpi_comm(), args.initfile_out + "_p.xdmf") xdmff_p.parameters["rewrite_function_mesh"] = False xdmff_p.parameters["flush_output"] = True xdmff_p.write(p, 0.)
def steadystate(geo, phys, F, u0): F = dolfin.as_vector([F]) bc = dict(upperb=dolfin.Constant(c0), lowerb=dolfin.Constant(c0)) pde = ConvectionDiffusionSteady(geo, phys, F=F, u0=u0, bc=bc) pde.add_functionals([partial(current, F=F), selectivity]) pde.single_solve() return pde
def get_collected_velocity_bcs(simulation, name): """ When mixed Dirichlet/Neumann BCs on the same facet (for different velocity components) is not supported it can be convenient to get all BCs collected by boundary region. This function returns a dictionary for Dirichlet or Neumann BCs where the "ds" meassure is the key and a vector of boundary values for each velocity component is the value The "name" parameter must be 'dirichlet_bcs' or 'neumann_bcs' """ # Collect BCs bc_dict = {} for d in range(simulation.ndim): for bc in simulation.data[name].get('u%d' % d, []): if d == 0: bc_dict[bc.ds()] = [bc.func()] else: bc_dict[bc.ds()].append(bc.func()) # Verify that all components are present and convert to vector for ds, u_bc in bc_dict.items(): assert len(u_bc) == simulation.ndim bc_dict[ds] = dolfin.as_vector(u_bc) simulation.log.debug(' Found %d %s boundary regions' % (len(bc_dict), name)) return bc_dict
def force_diff(**params): # for random walk (with pointsize force field, no current) setup = Setup(create_geo=False, **params) # DEBUG #print "active params", setup.active_params #print "inactive params", setup.inactive_params F = force_pointsize(**params) if setup.phys.posDTarget: D = diffusivity_simple(**params) name = "diffusivity_div_simple" if not fields.exists(name, **params): V = D.function_space() divD = dolfin.project( dolfin.as_vector([dolfin.grad(D[0])[0], dolfin.grad(D[1])[1]]), V) fields.save_functions(name, setup.active_params, divD=divD) fields.update() divD, = fields.get_functions(name, "divD", **params) else: D0 = setup.phys.DTargetBulk D0a = np.array([D0, D0, D0]) divDa = np.array([0., 0., 0.]) D = lambda x: D0a divD = lambda x: divDa return F, D, divD
def df_wrap(val, description, degree, sim): """ Wrap numbers as dolfin.Constant and strings as dolfin.Expression C++ code. Lists must be ndim long and contain either numbers or strings """ if isinstance(val, (int, float)): # A real number return dolfin.Constant(val) elif isinstance(val, str): # A C++ code string return OcellarisCppExpression(sim, val, description, degree) elif isinstance(val, (list, tuple)): D = sim.ndim L = len(val) if L != D: raise OcellarisError( 'Invalid length of list', 'BC list in "%r" must be length %d, is %d.' % (description, D, L), ) if all(isinstance(v, str) for v in val): # A list of C++ code strings return OcellarisCppExpression(sim, val, description, degree) else: # A mix of constants and (possibly) C++ strings val = [ df_wrap(v, description + ' item %d' % i, degree, sim) for i, v in enumerate(val) ] return dolfin.as_vector(val)
def Wactive_orthotropic(Ta, C, f0, s0, n0): """Return active strain energy for an orthotropic active stress Arguments --------- Ta : dolfin.Function or dolfin.Constant A vector function representng the mangnitude of the active stress in the reference configuration (firt Pioala). Ta = (Ta_f0, Ta_s0, Ta_n0) C : ufl.Form The right Cauchy-Green deformation tensor f0 : dolfin.Function A vector function representng the direction of the first component s0 : dolfin.Function A vector function representng the direction of the second component n0 : dolfin.Function A vector function representng the direction of the third component """ I4f = dolfin.inner(C * f0, f0) I4s = dolfin.inner(C * s0, s0) I4n = dolfin.inner(C * n0, n0) I4 = dolfin.as_vector([I4f - 1, I4s - 1, I4n - 1]) return dolfin.Constant(0.5) * dolfin.inner(Ta, I4)
def source_term(self): if self.moment_order == 3: F_rhs = [0.0] * self.number_of_moments F_rhs[0] = df.Expression( "2.0 - 1.0 * pow(sqrt(pow(x[0],2)+pow(x[1],2)),2)", degree=2) elif self.moment_order == 'nono6': F_rhs = [0.0] * NoV elif self.moment_order == 'nono13': F_rhs = [0.0] * NoV R = Expression("sqrt(pow(x[0],2)+pow(x[1],2))", degree=2) F_rhs[0] = Expression( "1.0 * (1.0 - (5.0*pow(R,2))/(18.0*pow(kn,2))) * cos(phi)", R=R, kn=Kn, phi=phi, degree=2) F_rhs[3] = Expression( "1.0 * (1.0 - (5.0*pow(R,2))/(18.0*pow(kn,2))) * cos(phi)", R=R, kn=Kn, phi=phi, degree=2) F_rhs[0] = Expression( "2.0 - 1.0 * pow(sqrt(pow(x[0],2)+pow(x[1],2)),2)", degree=2) F_rhs[3] = Expression( "2.0 - 1.0 * pow(sqrt(pow(x[0],2)+pow(x[1],2)),2)", degree=2) if self.moment_order == 3: F_rhs = df.as_vector(F_rhs) # converting to ufl vector local_source_term = df.inner(self.v, F_rhs) * df.dx return local_source_term
def updateCoefficients(self): # Init coefficient matrix P, Inv = SpatialCoordinate(self.mesh) self.a = as_matrix([[+.5 * (P * self.sigma)**2, 0], [0, 0]]) # def K(t): return self.K0 + beta_SA * sin(4*pi*(t - t_SA)) def K(t): return self.K0 self.b = as_vector([ +self.alpha * (K(self.t) - P), -(self.gamma[0] + self.cost(self.gamma[0])) ]) self.c = Constant(-self.r) # Init right-hand side self.f = -(self.gamma[0] - self.cost(self.gamma[0])) * P self.u_T = -2 * P * ufl.Max(1000 - Inv, 0) # self.u_T = Constant(0.0) # Set boundary conditions # self.g_t = lambda t : [(Constant(0.0), "near(x[0],0)")] self.g = self.u_T
def get_variable(self, name): zero = dolfin.Constant(0.0) if name == 'u': # Assume that the waves are traveling in x-direction if self.simulation.ndim == 2: return dolfin.as_vector([self.get_variable('uhoriz'), zero]) else: return dolfin.as_vector( [self.get_variable('uhoriz'), zero, zero]) elif name == 'uvert': return zero if name not in self._functions: expr = self._get_expression(name) self._functions[name] = dolfin.interpolate(expr, self.V) return self._functions[name]
def __init__(self, simulation, u_conv): """ Given a velocity in DG, e.g DG2, produce a velocity in DGT0, i.e. a constant on each facet """ V = u_conv[0].function_space() V_dgt0 = dolfin.FunctionSpace(V.mesh(), 'DGT', 0) u = dolfin.TrialFunction(V_dgt0) v = dolfin.TestFunction(V_dgt0) ndim = simulation.ndim w = u_conv w_new = dolfin.as_vector( [dolfin.Function(V_dgt0) for _ in range(ndim)]) dot, avg, dS, ds = dolfin.dot, dolfin.avg, dolfin.dS, dolfin.ds a = dot(avg(u), avg(v)) * dS + dot(u, v) * ds L = [] for d in range(ndim): L.append(avg(w[d]) * avg(v) * dS + w[d] * v * ds) self.lhs = [dolfin.Form(Li) for Li in L] self.A = dolfin.assemble(a) self.solver = dolfin.PETScKrylovSolver('cg') self.velocity = simulation.data['u_conv_dgt0'] = w_new
def __init__( self, WPQ, kappa, rho, rho_const, mu, cp, g, extra_force, heat_source, u_bcs, p_bcs, theta_dirichlet_bcs=None, theta_neumann_bcs=None, theta_robin_bcs=None, my_dx=dx, my_ds=ds ): super(StokesHeat, self).__init__() theta_dirichlet_bcs = theta_dirichlet_bcs or {} theta_neumann_bcs = theta_neumann_bcs or {} theta_robin_bcs = theta_robin_bcs or {} # Translate the Dirichlet boundary conditions into the product space. self.dirichlet_bcs = helpers.dbcs_to_productspace( WPQ, [u_bcs, p_bcs, theta_dirichlet_bcs] ) self.uptheta = Function(WPQ) u, p, theta = split(self.uptheta) v, q, zeta = TestFunctions(WPQ) mesh = WPQ.mesh() r = SpatialCoordinate(mesh)[0] # Right-hand side for momentum equation. f = rho(theta) * g # coupling if extra_force is not None: f += as_vector((extra_force[0], extra_force[1], 0.0)) self.stokes_F = stokes.F( u, p, v, q, f, r, mu, my_dx ) self.heat_F = heat.F( theta, zeta, kappa=kappa, rho=rho_const, cp=cp, convection=u, # coupling source=heat_source, r=r, neumann_bcs=theta_neumann_bcs, robin_bcs=theta_robin_bcs, my_dx=my_dx, my_ds=my_ds ) self.F0 = self.stokes_F + self.heat_F self.jacobian = derivative(self.F0, self.uptheta) return
from src.model import Model from pylab import zeros, linspace, sqrt from dolfin import project, Function, File, as_vector nx = 40 ny = 40 nz = 7 model = Model() model.generate_uniform_mesh(nx,ny,nz,0,1,0,1,deform=False,generate_pbcs=True) Q = model.Q U_obs = project(dolfin.as_vector([Function(Q),Function(Q)])) b_obs = Function(Q) U_opt = project(as_vector([Function(Q),Function(Q),Function(Q)])) b_opt = Function(Q) rcParams['text.usetex']=True rcParams['font.size'] = 12 rcParams['font.family'] = 'serif' for L in [10000]: File('./results/U_obs.xml') >> U_obs File('./results/U_opt.xml') >> U_opt File('./results/beta2_obs.xml') >> b_obs File('./results/beta2_opt.xml') >> b_opt U_b = zeros(100) U_p = zeros(100)
def grad(f): g = dolfin.grad(f) if len(g.shape()) == 0: return dolfin.as_vector([g]) else: return g
def solve_fixed_point( mesh, W_element, P_element, Q_element, u0, p0, theta0, kappa, rho, mu, cp, g, extra_force, heat_source, u_bcs, p_bcs, theta_dirichlet_bcs, theta_neumann_bcs, my_dx, my_ds, max_iter, tol ): # Solve the coupled heat-Stokes equation approximately. Do this # iteratively by solving the heat equation, then solving Stokes with the # updated heat, the heat equation with the updated velocity and so forth # until the change is 'small'. WP = FunctionSpace(mesh, MixedElement([W_element, P_element])) Q = FunctionSpace(mesh, Q_element) # Initialize functions. up0 = Function(WP) u0, p0 = up0.split() theta1 = Function(Q) for _ in range(max_iter): heat_problem = heat.Heat( Q, kappa=kappa, rho=rho(theta0), cp=cp, convection=u0, source=heat_source, dirichlet_bcs=theta_dirichlet_bcs, neumann_bcs=theta_neumann_bcs, my_dx=my_dx, my_ds=my_ds ) theta1.assign(heat_problem.solve_stationary()) # Solve problem for velocity, pressure. f = rho(theta0) * g # coupling if extra_force: f += as_vector((extra_force[0], extra_force[1], 0.0)) # up1 = up0.copy() stokes.stokes_solve( up0, mu, u_bcs, p_bcs, f, my_dx=my_dx, tol=1.0e-10, verbose=False, maxiter=1000 ) # from dolfin import plot # plot(u0) # plot(theta0) theta_diff = errornorm(theta0, theta1) info('||theta - theta0|| = {:e}'.format(theta_diff)) # info('||u - u0|| = {:e}'.format(u_diff)) # info('||p - p0|| = {:e}'.format(p_diff)) # diff = theta_diff + u_diff + p_diff diff = theta_diff info('sum = {:e}'.format(diff)) # # Show the iterates. # plot(theta0, title='theta0') # plot(u0, title='u0') # interactive() # #exit() if diff < tol: break theta0.assign(theta1) # Create a *deep* copy of u0, p0, to be able to deal with them as # actually separate entities. u0, p0 = up0.split(deepcopy=True) return u0, p0, theta0
space_S3 = df.VectorFunctionSpace(mesh, 'CG', 1, dim=3) # Create two scalar functions and a vector function # from the previously defined spaces f1 = df.interpolate(df.Expression("1"), space_S1) f2 = df.Function(space_S1) f3 = df.Function(space_S3) # If we want a scalar function with twice # the values of f1 (THIS WORKS) vec = df.assemble(df.dot(2 * f1, df.TestFunction(space_S1)) * df.dP) f2.vector().axpy(1, vec) # Now we want to modify the vector function space # to get the vector (2, 1, 1) in every vertex vec = df.assemble(df.dot(df.as_vector((2 * f1, f1, f1)), df.TestFunction(space_S3)) * df.dP) f3.vector().axpy(1, vec) # Scalar space assign g2 = df.Function(space_S1) g2.assign(df.FunctionAXPY(f1, 2.)) g2.vector().axpy(-1, f2.vector()) assert df.near(g2.vector().norm('l2'), 0) # Assigner for components of the vector space S3_assigners = [df.FunctionAssigner(space_S3.sub(i), space_S1) for i in range(space_S3.num_sub_spaces())] g3 = df.Function(space_S3) # Assign to components comps = [f2, f1, f1]
import src.model import pylab import dolfin import pickle from pylab import * nx = 20 ny = 20 nz = 6 model = src.model.Model() model.generate_uniform_mesh(nx,ny,nz,0,1,0,1,deform=False,generate_pbcs=True) Q = model.Q U_opt = dolfin.project(dolfin.as_vector([dolfin.Function(Q),dolfin.Function(Q),dolfin.Function(Q)])) b_opt = dolfin.Function(Q) n = len(b_opt.compute_vertex_values()) rcParams['text.usetex']=True rcParams['font.size'] = 12 rcParams['font.family'] = 'serif' Us = zeros((50,n)) betas = zeros((50,n)) fig,axs = subplots(2,1,sharex=True) fig.set_size_inches(8,4) bed_indices = model.mesh.coordinates()[:,2]==0 surface_indices = model.mesh.coordinates()[:,2]==1
def compute_pressure( P, p0, mu, ui, u, my_dx, p_bcs=None, rotational_form=False, tol=1.0e-10, verbose=True, ): """Solve the pressure Poisson equation .. math:: \\begin{align} -\\frac{1}{r} \\div(r \\nabla (p_1-p_0)) = -\\frac{1}{r} \\div(r u),\\\\ \\text{(with boundary conditions)}, \\end{align} for :math:`\\nabla p = u`. The pressure correction is based on the update formula .. math:: \\frac{\\rho}{dt} (u_{n+1}-u^*) + \\begin{pmatrix} \\text{d}\\phi/\\text{d}r\\\\ \\text{d}\\phi/\\text{d}z\\\\ \\frac{1}{r} \\text{d}\\phi/\\text{d}\\theta \\end{pmatrix} = 0 with :math:`\\phi = p_{n+1} - p^*` and .. math:: \\frac{1}{r} \\frac{\\text{d}}{\\text{d}r} (r u_r^{(n+1)}) + \\frac{\\text{d}}{\\text{d}z} (u_z^{(n+1)}) + \\frac{1}{r} \\frac{\\text{d}}{\\text{d}\\theta} (u_{\\theta}^{(n+1)}) = 0 With the assumption that u does not change in the direction :math:`\\theta`, one derives .. math:: - \\frac{1}{r} \\div(r \\nabla \\phi) = \\frac{1}{r} \\frac{\\rho}{dt} \\div(r (u_{n+1} - u^*))\\\\ - \\frac{1}{r} \\langle n, r \\nabla \\phi\\rangle = \\frac{1}{r} \\frac{\\rho}{dt} \\langle n, r (u_{n+1} - u^*)\\rangle In its weak form, this is .. math:: \\int r \\langle\\nabla\\phi, \\nabla q\\rangle \\,2 \\pi = - \\frac{\\rho}{dt} \\int \\div(r u^*) q \\, 2 \\pi - \\frac{\\rho}{dt} \\int_{\\Gamma} \\langle n, r (u_{n+1}-u^*)\\rangle q \\, 2\\pi. (The terms :math:`1/r` cancel with the volume elements :math:`2\\pi r`.) If the Dirichlet boundary conditions are applied to both :math:`u^*` and :math:`u_n` (the latter in the velocity correction step), the boundary integral vanishes. If no Dirichlet conditions are given (which is the default case), the system has no unique solution; one eigenvalue is 0. This however, does not hurt CG convergence if the system is consistent, cf. :cite:`vdV03`. And indeed it is consistent if and only if .. math:: \\int_\\Gamma r \\langle n, u\\rangle = 0. This condition makes clear that for incompressible Navier-Stokes, one either needs to make sure that inflow and outflow always add up to 0, or one has to specify pressure boundary conditions. Note that, when using a multigrid preconditioner as is done here, the coarse solver must be chosen such that it preserves the nullspace of the problem. """ W = ui.function_space() r = SpatialCoordinate(W.mesh())[0] p = TrialFunction(P) q = TestFunction(P) a2 = dot(r * grad(p), grad(q)) * 2 * pi * my_dx # The boundary conditions # n.(p1-p0) = 0 # are implicitly included. # # L2 = -div(r*u) * q * 2*pi*my_dx div_u = 1 / r * (r * u[0]).dx(0) + u[1].dx(1) L2 = -div_u * q * 2 * pi * r * my_dx if p0: L2 += r * dot(grad(p0), grad(q)) * 2 * pi * my_dx # In the Cartesian variant of the rotational form, one makes use of the # fact that # # curl(curl(u)) = grad(div(u)) - div(grad(u)). # # The same equation holds true in cylindrical form. Hence, to get the # rotational form of the splitting scheme, we need to # # rotational form if rotational_form: # If there is no dependence of the angular coordinate, what is # div(grad(div(u))) in Cartesian coordinates becomes # # 1/r div(r * grad(1/r div(r*u))) # # in cylindrical coordinates (div and grad are in cylindrical # coordinates). Unfortunately, we cannot write it down that # compactly since u_phi is in the game. # When using P2 elements, this value will be 0 anyways. div_ui = 1 / r * (r * ui[0]).dx(0) + ui[1].dx(1) grad_div_ui = as_vector((div_ui.dx(0), div_ui.dx(1))) L2 -= r * mu * dot(grad_div_ui, grad(q)) * 2 * pi * my_dx # div_grad_div_ui = 1/r * (r * grad_div_ui[0]).dx(0) \ # + (grad_div_ui[1]).dx(1) # L2 += mu * div_grad_div_ui * q * 2*pi*r*dx # n = FacetNormal(Q.mesh()) # L2 -= mu * (n[0] * grad_div_ui[0] + n[1] * grad_div_ui[1]) \ # * q * 2*pi*r*ds p1 = Function(P) if p_bcs: solve( a2 == L2, p1, bcs=p_bcs, solver_parameters={ "linear_solver": "iterative", "symmetric": True, "preconditioner": "hypre_amg", "krylov_solver": { "relative_tolerance": tol, "absolute_tolerance": 0.0, "maximum_iterations": 100, "monitor_convergence": verbose, }, }, ) else: # If we're dealing with a pure Neumann problem here (which is the # default case), this doesn't hurt CG if the system is consistent, # cf. :cite:`vdV03`. And indeed it is consistent if and only if # # \int_\Gamma r n.u = 0. # # This makes clear that for incompressible Navier-Stokes, one # either needs to make sure that inflow and outflow always add up # to 0, or one has to specify pressure boundary conditions. # # If the right-hand side is very small, round-off errors may impair # the consistency of the system. Make sure the system we are # solving remains consistent. A = assemble(a2) b = assemble(L2) # Assert that the system is indeed consistent. e = Function(P) e.interpolate(Constant(1.0)) evec = e.vector() evec /= norm(evec) alpha = b.inner(evec) normB = norm(b) # Assume that in every component of the vector, a round-off error # of the magnitude DOLFIN_EPS is present. This leads to the # criterion # |<b,e>| / (||b||*||e||) < DOLFIN_EPS # as a check whether to consider the system consistent up to # round-off error. # # TODO think about condition here # if abs(alpha) > normB * DOLFIN_EPS: if abs(alpha) > normB * 1.0e-12: # divu = 1 / r * (r * u[0]).dx(0) + u[1].dx(1) adivu = assemble(((r * u[0]).dx(0) + u[1].dx(1)) * 2 * pi * my_dx) info("\\int 1/r * div(r*u) * 2*pi*r = {:e}".format(adivu)) n = FacetNormal(P.mesh()) boundary_integral = assemble((n[0] * u[0] + n[1] * u[1]) * 2 * pi * r * ds) info("\\int_Gamma n.u * 2*pi*r = {:e}".format(boundary_integral)) message = ( "System not consistent! " "<b,e> = {:g}, ||b|| = {:g}, <b,e>/||b|| = {:e}.".format( alpha, normB, alpha / normB ) ) info(message) # # Plot the stuff, and project it to a finer mesh with linear # # elements for the purpose. # plot(divu, title='div(u_tentative)') # # Vp = FunctionSpace(Q.mesh(), 'CG', 2) # # Wp = MixedFunctionSpace([Vp, Vp]) # # up = project(u, Wp) # fine_mesh = Q.mesh() # for k in range(1): # fine_mesh = refine(fine_mesh) # V = FunctionSpace(fine_mesh, 'CG', 1) # W = V * V # # uplot = Function(W) # # uplot.interpolate(u) # uplot = project(u, W) # plot(uplot[0], title='u_tentative[0]') # plot(uplot[1], title='u_tentative[1]') # # plot(u, title='u_tentative') # interactive() # exit() raise RuntimeError(message) # Project out the roundoff error. b -= alpha * evec # # In principle, the ILU preconditioner isn't advised here since it # might destroy the semidefiniteness needed for CG. # # The system is consistent, but the matrix has an eigenvalue 0. # This does not harm the convergence of CG, but when # preconditioning one has to make sure that the preconditioner # preserves the kernel. ILU might destroy this (and the # semidefiniteness). With AMG, the coarse grid solves cannot be LU # then, so try Jacobi here. # <http://lists.mcs.anl.gov/pipermail/petsc-users/2012-February/012139.html> # prec = PETScPreconditioner("hypre_amg") from dolfin import PETScOptions PETScOptions.set("pc_hypre_boomeramg_relax_type_coarse", "jacobi") solver = PETScKrylovSolver("cg", prec) solver.parameters["absolute_tolerance"] = 0.0 solver.parameters["relative_tolerance"] = tol solver.parameters["maximum_iterations"] = 100 solver.parameters["monitor_convergence"] = verbose # Create solver and solve system A_petsc = as_backend_type(A) b_petsc = as_backend_type(b) p1_petsc = as_backend_type(p1.vector()) solver.set_operator(A_petsc) solver.solve(p1_petsc, b_petsc) return p1
def FacetNormal(mesh): nm = dolfin.FacetNormal(mesh) if len(nm.shape()) == 0: return dolfin.as_vector([nm]) else: return nm
def initialize_eqs(self): """ """ # initial height h = self.initial_h(120+0.0003*self.L, self.c, 0.4*self.L, self.L) self.h_old = d.project(h, self.V) # initial guess of velocity u = d.project(d.Expression('x[0]/L', L=1000*self.L), self.V) self.h_u_dhdx = d.project(d.as_vector((h,u,h.dx(0))), self.V3) self.h,self.u,self.dhdx = d.split(self.h_u_dhdx) # initialize floating conditional class FloatBoolean(Expression): """ creates boolean function over length of ice, true when ice is floating. """ def eval(s,value,x): if self.h_u_dhdx(x[0])[0] <= -h_b(x[0])*(self.rho_w/self.rho-1): value[0] = 1 else: value[0] = 0 # floating conditional fc = self.smooth_step_conditional(FloatBoolean()) # A useful expression for the effective pressure term reduction = fc*(self.rho_w/self.rho)*self.h_b # H (ice thickness) conditional on floating if self.floating: # archimedes principle, H (ice thickness) self.H = fc * (h/(1-self.rho/self.rho_w)) + (1-fc) * (self.h-self.h_b) else: # ice thickness = surface elevation - bed elevation self.H = self.h - self.h_b H = self.H h = self.h W = self.W u = self.u n = self.n # basal drag self.basal_drag = self.mu*self.A_s*(self.H+reduction)**self.p*u**(1/n) if self.floating: self.basal_drag = (1-fc) * self.basal_drag # define variational problem testFunction = TestFunction(self.V3) trialFunction = TrialFunction(self.V3) phi1, phi2, phi3 = split(testFunction) self.driving_stress = self.rho*self.g*H*self.dhdx self.lateral_drag = (self.B_s*H/W)*((n+2)*u/(2*W))**(1/n) force_balance = (self.driving_stress+self.basal_drag+self.lateral_drag)*phi2 ####????#################################################################### mass_conservation = ((h-self.h_old)/self.dt + (H*u*W).dx(0)/W - M)*phi1 ####????#################################################################### F = (mass_conservation + force_balance)*d.dx ###????##################################################################### invariant_squared = ((n+2.)/(n+1.)*u/W)**2+u.dx(0)**2 self.longitudinal_stress = \ 2*self.B_s*H*invariant_squared**((1-n)/(2*n))*u.dx(0) F += self.longitudinal_stress * phi2.dx(0) * d.dx F -= self.longitudinal_stress * phi2 * self.ds(self.TERMINUS) F += (self.h.dx(0)-self.dhdx)*phi3*d.dx ###????##################################################################### J = derivative(F, self.h_u_dhdx, trialFunction) problem =\ NonlinearVariationalProblem(F, self.h_u_dhdx, self.boundary_conditions, J) self.solver = NonlinearVariationalSolver(problem)
nz = 10 m = UnitCubeMesh(nx,ny,nz) Q = FunctionSpace(m,"CG",1) u = Function(Q) v = Function(Q) w = Function(Q) S = Function(Q) for L in [5000,10000,20000,40000,80000,160000]: File('./results_stokes/'+str(L)+'/u.xml') >> u File('./results_stokes/'+str(L)+'/v.xml') >> v File('./results_stokes/'+str(L)+'/w.xml') >> w U = zeros(100) profile = linspace(0,1,100) for ii,x in enumerate(profile): uu = u(x,0.25,0.99999) vv = v(x,0.25,0.99999) ww = w(x,0.25,0.99999) U[ii] = sqrt(uu**2 + vv**2) #plot(profile,U) #data = zip(profile,U) #dump(data,open("djb1a{0:03d}.p".format(L/1000),'w')) U = project(as_vector([u,v,w])) File('./results_stokes/'+str(L)+'/U.pvd') << U
def _compute_boussinesq( problem, u0, p0, theta0, lorentz, joule, target_time=0.1, show=False ): # Define a facet measure on the boundaries. See discussion on # <https://bitbucket.org/fenics-project/dolfin/issue/249/facet-specification-doesnt-work-on-ds>. ds_workpiece = Measure("ds", subdomain_data=problem.wp_boundaries) submesh_workpiece = problem.W.mesh() # Start time, time step. t = 0.0 dt = 1.0e-3 dt_max = 1.0e-1 # Standard gravity, <https://en.wikipedia.org/wiki/Standard_gravity>. grav = 9.80665 assert problem.W.num_sub_spaces() == 3 g = Constant((0.0, -grav, 0.0)) # Compute a few mesh characteristics. wpi_area = assemble(1.0 * dx(submesh_workpiece)) # mesh.hmax() is a local function; get the global hmax. hmax_workpiece = MPI.max(submesh_workpiece.mpi_comm(), submesh_workpiece.hmax()) # Take the maximum length in x-direction as characteristic length of the # domain. coords = submesh_workpiece.coordinates() char_length = max(coords[:, 0]) - min(coords[:, 0]) # Prepare some parameters for the Navier-Stokes simulation in the workpiece m = problem.subdomain_materials[problem.wpi] k_wpi = m.thermal_conductivity cp_wpi = m.specific_heat_capacity rho_wpi = m.density mu_wpi = m.dynamic_viscosity theta_average = average(theta0) # show_total_force = True # if show_total_force: # f = rho_wpi(theta0) * g # if lorentz: # f += as_vector((lorentz[0], lorentz[1], 0.0)) # tri = plot(f, mesh=submesh_workpiece, title='Total external force') # plt.colorbar(tri) # plt.show() with XDMFFile(submesh_workpiece.mpi_comm(), "all.xdmf") as outfile: outfile.parameters["flush_output"] = True outfile.parameters["rewrite_function_mesh"] = False _store(outfile, u0, p0, theta0, t) if show: _plot(p0, theta0) plt.show() successful_steps = 0 failed_steps = 0 while t < target_time + DOLFIN_EPS: info( "Successful steps: {} (failed: {}, total: {})".format( successful_steps, failed_steps, successful_steps + failed_steps ) ) with Message("Time step {:e} -> {:e}...".format(t, t + dt)): # Do one heat time step. with Message("Computing heat..."): # Redefine the heat problem with the new u0. heat_problem = cyl_heat.Heat( problem.Q, kappa=k_wpi, rho=rho_wpi(theta_average), cp=cp_wpi, convection=u0, source=joule, dirichlet_bcs=problem.theta_bcs_d, neumann_bcs=problem.theta_bcs_n, my_dx=dx(submesh_workpiece), my_ds=ds_workpiece, ) # For time-stepping in buoyancy-driven flows, see # # Numerical solution of buoyancy-driven flows; # Einar Rossebø Christensen; # Master's thesis; # <http://www.diva-portal.org/smash/get/diva2:348831/FULLTEXT01.pdf>. # # Similar to the present approach, one first solves for # velocity and pressure, then for temperature. # heat_stepper = parabolic.ImplicitEuler(heat_problem) ns_stepper = cyl_ns.IPCS(time_step_method="backward euler") theta1 = heat_stepper.step(theta0, t, dt) theta0_average = average(theta0) try: # Do one Navier-Stokes time step. with Message("Computing flux and pressure..."): # Include proper temperature-dependence here to account # for the Boussinesq effect. f0 = rho_wpi(theta0) * g f1 = rho_wpi(theta1) * g if lorentz is not None: f = as_vector((lorentz[0], lorentz[1], 0.0)) f0 += f f1 += f u1, p1 = ns_stepper.step( Constant(dt), {0: u0}, p0, problem.W, problem.P, problem.u_bcs, problem.p_bcs, # Make constant TODO Constant(rho_wpi(theta0_average)), Constant(mu_wpi(theta0_average)), f={0: f0, 1: f1}, tol=1.0e-10, my_dx=dx(submesh_workpiece), ) except RuntimeError as e: info(e.args[0]) info( "Navier--Stokes solver failed to converge. " "Decrease time step from {:e} to {:e} and try again.".format( dt, 0.5 * dt ) ) dt *= 0.5 failed_steps += 1 continue successful_steps += 1 # Assignments and plotting. theta0.assign(theta1) u0.assign(u1) p0.assign(p1) _store(outfile, u0, p0, theta0, t + dt) if show: _plot(p0, theta0) plt.show() t += dt with Message("Diagnostics..."): # Print some general info on the flow in the crucible. umax = get_umax(u0) _print_diagnostics( theta0, umax, submesh_workpiece, wpi_area, problem.subdomain_materials, problem.wpi, rho_wpi, mu_wpi, char_length, grav, ) info("") with Message("Step size adaptation..."): # Some smooth step-size adaption. target_dt = 0.2 * hmax_workpiece / umax info("previous dt: {:e}".format(dt)) info("target dt: {:e}".format(target_dt)) # agg is the aggressiveness factor. The distance between # the current step size and the target step size is reduced # by |1-agg|. Hence, if agg==1 then dt_next==target_dt. # Otherwise target_dt is approached more slowly. agg = 0.5 dt = min( dt_max, # At most double the step size from step to step. dt * min(2.0, 1.0 + agg * (target_dt - dt) / dt), ) info("new dt: {:e}".format(dt)) info("") info("") return u0, p0, theta0
def les_setup(u_, mesh, assemble_matrix, CG1Function, nut_krylov_solver, bcs, **NS_namespace): """ Set up for solving the Germano Dynamic LES model applying Lagrangian Averaging. """ # Create function spaces CG1 = FunctionSpace(mesh, "CG", 1) p, q = TrialFunction(CG1), TestFunction(CG1) dim = mesh.geometry().dim() # Define delta and project delta**2 to CG1 delta = pow(CellVolume(mesh), 1. / dim) delta_CG1_sq = project(delta, CG1) delta_CG1_sq.vector().set_local(delta_CG1_sq.vector().array()**2) delta_CG1_sq.vector().apply("insert") # Define nut_ Sij = sym(grad(u_)) magS = sqrt(2 * inner(Sij, Sij)) Cs = Function(CG1) nut_form = Cs**2 * delta**2 * magS # Create nut_ BCs ff = MeshFunction("size_t", mesh, mesh.topology().dim() - 1, 0) bcs_nut = [] for i, bc in enumerate(bcs['u0']): bc.apply(u_[0].vector()) # Need to initialize bc m = bc.markers() # Get facet indices of boundary ff.array()[m] = i + 1 bcs_nut.append(DirichletBC(CG1, Constant(0), ff, i + 1)) nut_ = CG1Function(nut_form, mesh, method=nut_krylov_solver, bcs=bcs_nut, bounded=True, name="nut") # Create functions for holding the different velocities u_CG1 = as_vector([Function(CG1) for i in range(dim)]) u_filtered = as_vector([Function(CG1) for i in range(dim)]) dummy = Function(CG1) ll = LagrangeInterpolator() # Assemble required filter matrices and functions G_under = Function(CG1, assemble(TestFunction(CG1) * dx)) G_under.vector().set_local(1. / G_under.vector().array()) G_under.vector().apply("insert") G_matr = assemble(inner(p, q) * dx) # Set up functions for Lij and Mij Lij = [Function(CG1) for i in range(dim * dim)] Mij = [Function(CG1) for i in range(dim * dim)] # Check if case is 2D or 3D and set up uiuj product pairs and # Sij forms, assemble required matrices Sijcomps = [Function(CG1) for i in range(dim * dim)] Sijfcomps = [Function(CG1) for i in range(dim * dim)] # Assemble some required matrices for solving for rate of strain terms Sijmats = [assemble_matrix(p.dx(i) * q * dx) for i in range(dim)] if dim == 3: tensdim = 6 uiuj_pairs = ((0, 0), (0, 1), (0, 2), (1, 1), (1, 2), (2, 2)) else: tensdim = 3 uiuj_pairs = ((0, 0), (0, 1), (1, 1)) # Set up Lagrange functions JLM = Function(CG1) JLM.vector()[:] += 1E-32 JMM = Function(CG1) JMM.vector()[:] += 1 return dict(Sij=Sij, nut_form=nut_form, nut_=nut_, delta=delta, bcs_nut=bcs_nut, delta_CG1_sq=delta_CG1_sq, CG1=CG1, Cs=Cs, u_CG1=u_CG1, u_filtered=u_filtered, ll=ll, Lij=Lij, Mij=Mij, Sijcomps=Sijcomps, Sijfcomps=Sijfcomps, Sijmats=Sijmats, JLM=JLM, JMM=JMM, dim=dim, tensdim=tensdim, G_matr=G_matr, G_under=G_under, dummy=dummy, uiuj_pairs=uiuj_pairs)
nz = 10 m = dolfin.UnitCubeMesh(nx,ny,nz) Q = dolfin.FunctionSpace(m,"CG",1) u = dolfin.Function(Q) v = dolfin.Function(Q) w = dolfin.Function(Q) S = dolfin.Function(Q) for L in [5000,10000,20000,40000,80000,160000]: dolfin.File('./results_stokes/'+str(L)+'/u.xml') >> u dolfin.File('./results_stokes/'+str(L)+'/v.xml') >> v dolfin.File('./results_stokes/'+str(L)+'/w.xml') >> w U = pylab.zeros(100) profile = pylab.linspace(0,1,100) for ii,x in enumerate(profile): uu = u(x,0.25,0.99999) vv = v(x,0.25,0.99999) ww = w(x,0.25,0.99999) U[ii] = pylab.sqrt(uu**2 + vv**2) #pylab.plot(profile,U) #data = zip(profile,U) #pickle.dump(data,open("djb1a{0:03d}.p".format(L/1000),'w')) U = dolfin.project(dolfin.as_vector([u,v,w])) dolfin.File('./results_stokes/'+str(L)+'/U.pvd') << U
def _pressure_poisson(self, p1, p0, mu, ui, u, p_bcs=None, rotational_form=False, tol=1.0e-10, verbose=True ): '''Solve the pressure Poisson equation -1/r \div(r \nabla (p1-p0)) = -1/r div(r*u), boundary conditions, for \nabla p = u. ''' r = Expression('x[0]', degree=1, domain=self.W.mesh()) Q = p1.function_space() p = TrialFunction(Q) q = TestFunction(Q) a2 = dot(r * grad(p), grad(q)) * 2 * pi * dx # The boundary conditions # n.(p1-p0) = 0 # are implicitly included. # # L2 = -div(r*u) * q * 2*pi*dx div_u = 1/r * (r * u[0]).dx(0) + u[1].dx(1) L2 = -div_u * q * 2*pi*r*dx if p0: L2 += r * dot(grad(p0), grad(q)) * 2*pi*dx # In the Cartesian variant of the rotational form, one makes use of the # fact that # # curl(curl(u)) = grad(div(u)) - div(grad(u)). # # The same equation holds true in cylindrical form. Hence, to get the # rotational form of the splitting scheme, we need to # # rotational form if rotational_form: # If there is no dependence of the angular coordinate, what is # div(grad(div(u))) in Cartesian coordinates becomes # # 1/r div(r * grad(1/r div(r*u))) # # in cylindrical coordinates (div and grad are in cylindrical # coordinates). Unfortunately, we cannot write it down that # compactly since u_phi is in the game. # When using P2 elements, this value will be 0 anyways. div_ui = 1/r * (r * ui[0]).dx(0) + ui[1].dx(1) grad_div_ui = as_vector((div_ui.dx(0), div_ui.dx(1))) L2 -= r * mu * dot(grad_div_ui, grad(q)) * 2*pi*dx #div_grad_div_ui = 1/r * (r * grad_div_ui[0]).dx(0) \ # + (grad_div_ui[1]).dx(1) #L2 += mu * div_grad_div_ui * q * 2*pi*r*dx #n = FacetNormal(Q.mesh()) #L2 -= mu * (n[0] * grad_div_ui[0] + n[1] * grad_div_ui[1]) \ # * q * 2*pi*r*ds if p_bcs: solve( a2 == L2, p1, bcs=p_bcs, solver_parameters={ 'linear_solver': 'iterative', 'symmetric': True, 'preconditioner': 'amg', 'krylov_solver': {'relative_tolerance': tol, 'absolute_tolerance': 0.0, 'maximum_iterations': 100, 'monitor_convergence': verbose} } ) else: # If we're dealing with a pure Neumann problem here (which is the # default case), this doesn't hurt CG if the system is consistent, # cf. :cite:`vdV03`. And indeed it is consistent if and only if # # \int_\Gamma r n.u = 0. # # This makes clear that for incompressible Navier-Stokes, one # either needs to make sure that inflow and outflow always add up # to 0, or one has to specify pressure boundary conditions. # # If the right-hand side is very small, round-off errors may impair # the consistency of the system. Make sure the system we are # solving remains consistent. A = assemble(a2) b = assemble(L2) # Assert that the system is indeed consistent. e = Function(Q) e.interpolate(Constant(1.0)) evec = e.vector() evec /= norm(evec) alpha = b.inner(evec) normB = norm(b) # Assume that in every component of the vector, a round-off error # of the magnitude DOLFIN_EPS is present. This leads to the # criterion # |<b,e>| / (||b||*||e||) < DOLFIN_EPS # as a check whether to consider the system consistent up to # round-off error. # # TODO think about condition here #if abs(alpha) > normB * DOLFIN_EPS: if abs(alpha) > normB * 1.0e-12: divu = 1 / r * (r * u[0]).dx(0) + u[1].dx(1) adivu = assemble(((r * u[0]).dx(0) + u[1].dx(1)) * 2 * pi * dx) info('\int 1/r * div(r*u) * 2*pi*r = %e' % adivu) n = FacetNormal(Q.mesh()) boundary_integral = assemble((n[0] * u[0] + n[1] * u[1]) * 2 * pi * r * ds) info('\int_Gamma n.u * 2*pi*r = %e' % boundary_integral) message = ('System not consistent! ' '<b,e> = %g, ||b|| = %g, <b,e>/||b|| = %e.') \ % (alpha, normB, alpha / normB) info(message) # Plot the stuff, and project it to a finer mesh with linear # elements for the purpose. plot(divu, title='div(u_tentative)') #Vp = FunctionSpace(Q.mesh(), 'CG', 2) #Wp = MixedFunctionSpace([Vp, Vp]) #up = project(u, Wp) fine_mesh = Q.mesh() for k in range(1): fine_mesh = refine(fine_mesh) V = FunctionSpace(fine_mesh, 'CG', 1) W = V * V #uplot = Function(W) #uplot.interpolate(u) uplot = project(u, W) plot(uplot[0], title='u_tentative[0]') plot(uplot[1], title='u_tentative[1]') #plot(u, title='u_tentative') interactive() exit() raise RuntimeError(message) # Project out the roundoff error. b -= alpha * evec # # In principle, the ILU preconditioner isn't advised here since it # might destroy the semidefiniteness needed for CG. # # The system is consistent, but the matrix has an eigenvalue 0. # This does not harm the convergence of CG, but when # preconditioning one has to make sure that the preconditioner # preserves the kernel. ILU might destroy this (and the # semidefiniteness). With AMG, the coarse grid solves cannot be LU # then, so try Jacobi here. # <http://lists.mcs.anl.gov/pipermail/petsc-users/2012-February/012139.html> # prec = PETScPreconditioner('hypre_amg') from dolfin import PETScOptions PETScOptions.set('pc_hypre_boomeramg_relax_type_coarse', 'jacobi') solver = PETScKrylovSolver('cg', prec) solver.parameters['absolute_tolerance'] = 0.0 solver.parameters['relative_tolerance'] = tol solver.parameters['maximum_iterations'] = 100 solver.parameters['monitor_convergence'] = verbose # Create solver and solve system A_petsc = as_backend_type(A) b_petsc = as_backend_type(b) p1_petsc = as_backend_type(p1.vector()) solver.set_operator(A_petsc) solver.solve(p1_petsc, b_petsc) # This would be the stump for Epetra: #solve(A, p.vector(), b, 'cg', 'ml_amg') return
def test(show=False): problem = problems.Crucible() # The voltage is defined as # # v(t) = Im(exp(i omega t) v) # = Im(exp(i (omega t + arg(v)))) |v| # = sin(omega t + arg(v)) |v|. # # Hence, for a lagging voltage, arg(v) needs to be negative. voltages = [ 38.0 * numpy.exp(-1j * 2 * pi * 2 * 70.0 / 360.0), 38.0 * numpy.exp(-1j * 2 * pi * 1 * 70.0 / 360.0), 38.0 * numpy.exp(-1j * 2 * pi * 0 * 70.0 / 360.0), 25.0 * numpy.exp(-1j * 2 * pi * 0 * 70.0 / 360.0), 25.0 * numpy.exp(-1j * 2 * pi * 1 * 70.0 / 360.0), ] lorentz, joule, Phi = get_lorentz_joule(problem, voltages, show=show) # Some assertions ref = 1.4627674791126285e-05 assert abs(norm(Phi[0], "L2") - ref) < 1.0e-3 * ref ref = 3.161363929287592e-05 assert abs(norm(Phi[1], "L2") - ref) < 1.0e-3 * ref # ref = 12.115309575057681 assert abs(norm(lorentz, "L2") - ref) < 1.0e-3 * ref # ref = 1406.336109054347 V = FunctionSpace(problem.submesh_workpiece, "CG", 1) jp = project(joule, V) jp.rename("s", "Joule heat source") assert abs(norm(jp, "L2") - ref) < 1.0e-3 * ref # check_currents = False # if check_currents: # r = SpatialCoordinate(problem.mesh)[0] # begin('Currents computed after the fact:') # k = 0 # with XDMFFile('currents.xdmf') as xdmf_file: # for coil in coils: # for ii in coil['rings']: # J_r = sigma[ii] * ( # voltages[k].real/(2*pi*r) + problem.omega * Phi[1] # ) # J_i = sigma[ii] * ( # voltages[k].imag/(2*pi*r) - problem.omega * Phi[0] # ) # alpha = assemble(J_r * dx(ii)) # beta = assemble(J_i * dx(ii)) # info('J = {:e} + i {:e}'.format(alpha, beta)) # info( # '|J|/sqrt(2) = {:e}'.format( # numpy.sqrt(0.5 * (alpha**2 + beta**2)) # )) # submesh = SubMesh(problem.mesh, problem.subdomains, ii) # V1 = FunctionSpace(submesh, 'CG', 1) # # Those projections may take *very* long. # # TODO find out why # j_v1 = [ # project(J_r, V1), # project(J_i, V1) # ] # # show=Trueplot(j_v1[0], title='j_r') # # plot(j_v1[1], title='j_i') # current = project(as_vector(j_v1), V1*V1) # current.rename('j{}'.format(ii), 'current {}'.format(ii)) # xdmf_file.write(current) # k += 1 # end() filename = "./maxwell.xdmf" with XDMFFile(filename) as xdmf_file: xdmf_file.parameters["flush_output"] = True xdmf_file.parameters["rewrite_function_mesh"] = False # Store phi info("Writing out Phi to {}...".format(filename)) V = FunctionSpace(problem.mesh, "CG", 1) phi = Function(V, name="phi") Phi0 = project(Phi[0], V) Phi1 = project(Phi[1], V) omega = problem.omega for t in numpy.linspace(0.0, 2 * pi / omega, num=100, endpoint=False): # Im(Phi * exp(i*omega*t)) phi.vector().zero() phi.vector().axpy(sin(problem.omega * t), Phi0.vector()) phi.vector().axpy(cos(problem.omega * t), Phi1.vector()) xdmf_file.write(phi, t) # Show the resulting magnetic field # # B_r = -dphi/dz, # B_z = 1/r d(rphi)/dr. # r = SpatialCoordinate(problem.mesh)[0] g = 1.0 / r * grad(r * Phi[0]) V_element = FiniteElement("CG", V.mesh().ufl_cell(), 1) VV = FunctionSpace(V.mesh(), V_element * V_element) B_r = project(as_vector((-g[1], g[0])), VV) g = 1 / r * grad(r * Phi[1]) B_i = project(as_vector((-g[1], g[0])), VV) info("Writing out B to {}...".format(filename)) B = Function(VV) B.rename("B", "magnetic field") if abs(problem.omega) < DOLFIN_EPS: B.assign(B_r) xdmf_file.write(B) # plot(B_r, title='Re(B)') # plot(B_i, title='Im(B)') else: # Write those out to a file. lspace = numpy.linspace( 0.0, 2 * pi / problem.omega, num=100, endpoint=False ) for t in lspace: # Im(B * exp(i*omega*t)) B.vector().zero() B.vector().axpy(sin(problem.omega * t), B_r.vector()) B.vector().axpy(cos(problem.omega * t), B_i.vector()) xdmf_file.write(B, t) filename = "./lorentz-joule.xdmf" info("Writing out Lorentz force and Joule heat source to {}...".format(filename)) with XDMFFile(filename) as xdmf_file: xdmf_file.write(lorentz, 0.0) # xdmf_file.write(jp, 0.0) return
def F( u, v, kappa, rho, cp, convection, source, r, neumann_bcs, robin_bcs, my_dx, my_ds, stabilization, ): """ Compute .. math:: F(u) = \\int_\\Omega \\kappa r \\langle\\nabla u, \\nabla \\frac{v}{\\rho c_p}\\rangle \\, 2\\pi \\, \\text{d}x + \\int_\\Omega \\langle c, \\nabla u\\rangle v \\, 2\\pi r\\,\\text{d}x - \\int_\\Omega \\frac{1}{\\rho c_p} f v \\, 2\\pi r \\,\\text{d}x\\\\ - \\int_\\Gamma r \\kappa \\langle n, \\nabla T\\rangle v \\frac{1}{\\rho c_p} 2\\pi \\,\\text{d}s - \\int_\\Gamma r \\kappa \\alpha (u - u_0) v \\frac{1}{\\rho c_p} \\, 2\\pi \\,\\text{d}s, used for time-stepping .. math:: u' = F(u). """ rho_cp = rho * cp F0 = kappa * r * dot(grad(u), grad(v / rho_cp)) * 2 * pi * my_dx # F -= dot(b, grad(u)) * v * 2*pi*r * dx_workpiece(0) if convection is not None: c = as_vector([convection[0], convection[1]]) F0 += dot(c, grad(u)) * v * 2 * pi * r * my_dx # Joule heat F0 -= source * v / rho_cp * 2 * pi * r * my_dx # Neumann boundary conditions for k, n_grad_T in neumann_bcs.items(): F0 -= r * kappa * n_grad_T * v / rho_cp * 2 * pi * my_ds(k) # Robin boundary conditions for k, value in robin_bcs.items(): alpha, u0 = value F0 -= r * kappa * alpha * (u - u0) * v / rho_cp * 2 * pi * my_ds(k) if stabilization == "supg": # Add SUPG stabilization. assert convection is not None # TODO u_t? R = ( -div(kappa * r * grad(u)) / rho_cp * 2 * pi + dot(c, grad(u)) * 2 * pi * r - source / rho_cp * 2 * pi * r ) mesh = v.function_space().mesh() element_degree = v.ufl_element().degree() tau = stab.supg(mesh, convection, kappa, element_degree) F0 += R * tau * dot(convection, grad(v)) * my_dx else: assert stabilization is None return F0
def eps(u): """ Returns a vector of strains of size (3,1) in the Voigt notation layout {eps_xx, eps_yy, gamma_xy} where gamma_xy = 2*eps_xy""" return df.as_vector([u[i].dx(i) for i in range(2)] + [u[i].dx(j) + u[j].dx(i) for (i,j) in [(0,1)]])