def __new__(cls, mesh, tolerance=1e-12): dim = mesh.geometry().dim() X = MeshPool._X[dim - 1] test = assemble(dot(X, X) * CellVolume(mesh)**(0.25) * dx()) * assemble(Constant(1) * dx(domain=mesh)) assert test > 0.0 assert test < np.inf # Do a garbage collect to collect any garbage references # Needed for full parallel compatibility gc.collect() keys = np.array(MeshPool._existing.keys()) self = None if len(keys) > 0: diff = np.abs(keys - test) / np.abs(test) idx = np.argmin(np.abs(keys - test)) if diff[idx] <= tolerance and isinstance( mesh, type(MeshPool._existing[keys[idx]])): self = MeshPool._existing[keys[idx]] if self is None: self = mesh MeshPool._existing[test] = self return self
def expr2function(self, expr, function): """ Convert an expression into a function. How this is done is determined by the parameters (assemble, project or interpolate). """ space = function.function_space() if self.params.expr2function == "assemble": # Compute average values of expr for each cell and place in a DG0 space test = TestFunction(space) scale = 1.0 / CellVolume(space.mesh()) assemble(scale * inner(expr, test) * dx, tensor=function.vector()) return function elif self.params.expr2function == "project": # TODO: Avoid superfluous function creation with fenics-dev/1.5 by using: #project(expr, space, function=function) function.assign(project(expr, space)) return function elif self.params.expr2function == "interpolate": # TODO: Need interpolation with code generated from expr, waiting for uflacs work. function.interpolate( expr) # Currently only works if expr is a single Function return function else: error( "No action selected, need to choose either assemble, project or interpolate." )
def before_first_compute(self, get): u = get("Velocity") mesh = u.function_space().mesh() spaces = SpacePool(mesh) DG0 = spaces.get_space(0, 0) self._v = TestFunction(DG0) self._cfl = Function(DG0) self._hF = Circumradius(mesh) self._hK = CellVolume(mesh)
def extrapolate_setup(F_fluid_linear, extype, mesh_file, d_, phi, gamma, dx_f, **semimp_namespace): def F_(U): return Identity(len(U)) + grad(U) def J_(U): return det(F_(U)) def eps(U): return 0.5 * (grad(U) * inv(F_(U)) + inv(F_(U)).T * grad(U).T) def STVK(U, alfa_mu, alfa_lam): return alfa_lam * tr(eps(U)) * Identity( len(U)) + 2.0 * alfa_mu * eps(U) #return F_(U)*(alfa_lam*tr(eps(U))*Identity(len(U)) + 2.0*alfa_mu*eps(U)) alfa = 1.0 # holder value if linear is chosen if extype == "det": #alfa = inv(J_(d_["n"])) alfa = 1. / (J_(d_["n"])) if extype == "smallconst": alfa = 0.01 * (mesh_file.hmin())**2 if extype == "const": alfa = 1.0 F_extrapolate = alfa * inner(grad(d_["n"]), grad(phi)) * dx_f if extype == "linear": hmin = mesh_file.hmin() #E_y = 1./(J_(d_["n"])) #nu = -0.2 #(-1, 0.5) E_y = 1. / CellVolume(mesh_file) nu = 0.25 alfa_lam = nu * E_y / ((1. + nu) * (1. - 2. * nu)) alfa_mu = E_y / (2. * (1. + nu)) #alfa_lam = hmin*hmin ; alfa_mu = hmin*hmin F_extrapolate = inner( J_(d_["n"]) * STVK(d_["n"], alfa_mu, alfa_lam) * inv(F_(d_["n"])).T, grad(phi)) * dx_f #F_extrapolate = inner(STVK(d_["n"],alfa_mu,alfa_lam) , grad(phi))*dx_f F_fluid_linear += F_extrapolate return dict(F_fluid_linear=F_fluid_linear)
def extrapolate_setup(F_fluid_linear, mesh, d_, phi, gamma, dx_f, **namespace): """ Elastic lifting operator solving the equation of linear elasticity. div(sigma(d)) = 0 in the fluid domain d = 0 on the fluid boundaries other than FSI interface d = solid_d on the FSI interface """ E_y = 1.0 / CellVolume(mesh) nu = 0.25 alpha_lam = nu * E_y / ((1.0 + nu) * (1.0 - 2.0 * nu)) alpha_mu = E_y / (2.0 * (1.0 + nu)) F_extrapolate = inner( J_(d_["n"]) * S_linear(d_["n"], alpha_mu, alpha_lam) * inv(F_(d_["n"])).T, grad(phi)) * dx_f F_fluid_linear += F_extrapolate return dict(F_fluid_linear=F_fluid_linear)
def extrapolate_setup(F_fluid_linear, extrapolation_sub_type, mesh, d_, phi, dx_f, **namespace): """ Laplace lifting operator. Can be used for small to moderate deformations. The diffusion parameter "alfa", which is specified by "extrapolation_sub_type", can be used to control the deformation field from the wall boundaries to the fluid domain. "alfa" is assumed constant within elements. - alfa * laplace(d) = 0 in the fluid domain d = 0 on the fluid boundaries other than FSI interface d = solid_def on the FSI interface References: Slyngstad, Andreas Strøm. Verification and Validation of a Monolithic Fluid-Structure Interaction Solver in FEniCS. A comparison of mesh lifting operators. MS thesis. 2017. Gjertsen, Sebastian. Development of a Verified and Validated Computational Framework for Fluid-Structure Interaction: Investigating Lifting Operators and Numerical Stability. MS thesis. 2017. """ if extrapolation_sub_type == "volume_change": alfa = 1.0 / (J_(d_["n"])) elif extrapolation_sub_type == "volume": alfa = 1.0 / CellVolume(mesh) elif extrapolation_sub_type == "small_constant": alfa = 0.01 * (mesh.hmin())**2 elif extrapolation_sub_type == "constant": alfa = 1.0 else: raise RuntimeError("Could not find extrapolation method {}".format( extrapolation_sub_type)) F_extrapolate = alfa * inner(grad(d_["n"]), grad(phi)) * dx_f F_fluid_linear += F_extrapolate return dict(F_fluid_linear=F_fluid_linear)
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 = FacetFunction("size_t", mesh, 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)
def transport_linear(integrator_type, mesh, subdomains, boundaries, t_start, dt, T, solution0, \ alpha_0, K_0, mu_l_0, lmbda_l_0, Ks_0, \ alpha_1, K_1, mu_l_1, lmbda_l_1, Ks_1, \ alpha, K, mu_l, lmbda_l, Ks, \ cf_0, phi_0, rho_0, mu_0, k_0,\ cf_1, phi_1, rho_1, mu_1, k_1,\ cf, phi, rho, mu, k, \ d_0, d_1, d_t, vel_c, p_con, A_0, Temp, c_extrapolate): # Create mesh and define function space parameters["ghost_mode"] = "shared_facet" # required by dS dx = Measure('dx', domain=mesh, subdomain_data=subdomains) ds = Measure('ds', domain=mesh, subdomain_data=boundaries) dS = Measure('dS', domain=mesh, subdomain_data=boundaries) C_cg = FiniteElement("CG", mesh.ufl_cell(), 1) C_dg = FiniteElement("DG", mesh.ufl_cell(), 0) mini = C_cg + C_dg C = FunctionSpace(mesh, mini) C = BlockFunctionSpace([C]) TM = TensorFunctionSpace(mesh, 'DG', 0) PM = FunctionSpace(mesh, 'DG', 0) n = FacetNormal(mesh) vc = CellVolume(mesh) fc = FacetArea(mesh) h = vc / fc h_avg = (vc('+') + vc('-')) / (2 * avg(fc)) penalty1 = Constant(1.0) tau = Function(PM) tau = tau_cal(tau, phi, -0.5) tuning_para = 0.25 vel_norm = (dot(vel_c, n) + abs(dot(vel_c, n))) / 2.0 cell_size = CellDiameter(mesh) vnorm = sqrt(dot(vel_c, vel_c)) I = Identity(mesh.topology().dim()) d_eff = Function(TM) d_eff = diff_coeff_cal_rev(d_eff, d_0, tau, phi) + tuning_para * cell_size * vnorm * I monitor_dt = dt # Define variational problem dc, = BlockTrialFunction(C) dc_dot, = BlockTrialFunction(C) psic, = BlockTestFunction(C) block_c = BlockFunction(C) c, = block_split(block_c) block_c_dot = BlockFunction(C) c_dot, = block_split(block_c_dot) theta = -1.0 a_time = phi * rho * inner(c_dot, psic) * dx a_dif = dot(rho*d_eff*grad(c),grad(psic))*dx \ - dot(avg_w(rho*d_eff*grad(c),weight_e(rho*d_eff,n)), jump(psic, n))*dS \ + theta*dot(avg_w(rho*d_eff*grad(psic),weight_e(rho*d_eff,n)), jump(c, n))*dS \ + penalty1/h_avg*k_e(rho*d_eff,n)*dot(jump(c, n), jump(psic, n))*dS a_adv = -dot(rho*vel_c*c,grad(psic))*dx \ + dot(jump(psic), rho('+')*vel_norm('+')*c('+') - rho('-')*vel_norm('-')*c('-') )*dS \ + dot(psic, rho*vel_norm*c)*ds(3) R_c = R_c_cal(c_extrapolate, p_con, Temp) c_D1 = Constant(0.5) rhs_c = R_c * A_s_cal(phi, phi_0, A_0) * psic * dx - dot( rho * phi * vel_c, n) * c_D1 * psic * ds(1) r_u = [a_dif + a_adv] j_u = block_derivative(r_u, [c], [dc]) r_u_dot = [a_time] j_u_dot = block_derivative(r_u_dot, [c_dot], [dc_dot]) r = [r_u_dot[0] + r_u[0] - rhs_c] # this part is not applied. exact_solution_expression1 = Expression("1.0", t=0, element=C[0].ufl_element()) def bc(t): p5 = DirichletBC(C.sub(0), exact_solution_expression1, boundaries, 1, method="geometric") return BlockDirichletBC([p5]) # Define problem wrapper class ProblemWrapper(object): def set_time(self, t): pass # Residual and jacobian functions def residual_eval(self, t, solution, solution_dot): return r def jacobian_eval(self, t, solution, solution_dot, solution_dot_coefficient): return [[ Constant(solution_dot_coefficient) * j_u_dot[0, 0] + j_u[0, 0] ]] # Define boundary condition def bc_eval(self, t): pass # Define initial condition def ic_eval(self): return solution0 # Define custom monitor to plot the solution def monitor(self, t, solution, solution_dot): pass problem_wrapper = ProblemWrapper() (solution, solution_dot) = (block_c, block_c_dot) solver = TimeStepping(problem_wrapper, solution, solution_dot) solver.set_parameters({ "initial_time": t_start, "time_step_size": dt, "monitor": { "time_step_size": monitor_dt, }, "final_time": T, "exact_final_time": "stepover", "integrator_type": integrator_type, "problem_type": "linear", "linear_solver": "mumps", "report": True }) export_solution = solver.solve() return export_solution, T
def test(path, type='mf'): '''Evolve the tile in (n, n) pattern checking volume/surface properties''' comm = mpi_comm_world() h5 = HDF5File(comm, path, 'r') tile = Mesh() h5.read(tile, 'mesh', False) init_container = lambda type, dim: ( MeshFunction('size_t', tile, dim, 0) if type == 'mf' else MeshValueCollection('size_t', tile, dim)) for n in (2, 4): data = {} checks = {} for dim, name in zip((2, 3), ('surfaces', 'volumes')): # Get the collection collection = init_container(type, dim) h5.read(collection, name) if type == 'mvc': collection = as_meshf(collection) # Data to evolve tile.init(dim, 0) e2v = tile.topology()(dim, 0) # Only want to evolve tag 1 (interfaces) for the facets. data[(dim, 1)] = np.array( [e2v(e.index()) for e in SubsetIterator(collection, 1)], dtype='uintp') if dim == 2: check = lambda m, f: assemble( FacetArea(m) * ds(domain=m, subdomain_data=f, subdomain_id=1) + avg(FacetArea(m)) * dS(domain=m, subdomain_data=f, subdomain_id=1)) else: check = lambda m, f: assemble( CellVolume(m) * dx( domain=m, subdomain_data=f, subdomain_id=1)) checks[ dim] = lambda m, f, t=tile, c=collection, n=n, check=check: abs( check(m, f) - n**2 * check(t, c)) / (n**2 * check(t, c)) t = Timer('x') mesh, mesh_data = TileMesh(tile, (n, n), mesh_data=data) info('\tTiling took %g s. Ncells %d, nvertices %d, \n' % (t.stop(), mesh.num_vertices(), mesh.num_cells())) foos = mf_from_data(mesh, mesh_data) # Mesh Functions from_mf = np.array([checks[dim](mesh, foos[dim]) for dim in (2, 3)]) mvcs = mvc_from_data(mesh, mesh_data) foos = as_meshf(mvcs) # Mesh ValueCollections from_mvc = np.array([checks[dim](mesh, foos[dim]) for dim in (2, 3)]) assert np.linalg.norm(from_mf - from_mvc) < 1E-13 # I ignore shared facets so there is bound to be some error in facets # Volume should match well print from_mf
def m_linear(integrator_type, mesh, subdomains, boundaries, t_start, dt, T, solution0, \ alpha_0, K_0, mu_l_0, lmbda_l_0, Ks_0, \ alpha_1, K_1, mu_l_1, lmbda_l_1, Ks_1, \ alpha, K, mu_l, lmbda_l, Ks, \ cf_0, phi_0, rho_0, mu_0, k_0,\ cf_1, phi_1, rho_1, mu_1, k_1,\ cf, phi, rho, mu, k, \ pressure_freeze): # Create mesh and define function space parameters["ghost_mode"] = "shared_facet" # required by dS dx = Measure('dx', domain=mesh, subdomain_data=subdomains) ds = Measure('ds', domain=mesh, subdomain_data=boundaries) dS = Measure('dS', domain=mesh, subdomain_data=boundaries) C = VectorFunctionSpace(mesh, "CG", 2) C = BlockFunctionSpace([C]) TM = TensorFunctionSpace(mesh, 'DG', 0) PM = FunctionSpace(mesh, 'DG', 0) n = FacetNormal(mesh) vc = CellVolume(mesh) fc = FacetArea(mesh) h = vc/fc h_avg = (vc('+') + vc('-'))/(2*avg(fc)) monitor_dt = dt f_stress_x = Constant(-1.e3) f_stress_y = Constant(-20.0e6) f = Constant((0.0, 0.0)) #sink/source for displacement I = Identity(mesh.topology().dim()) # Define variational problem psiu, = BlockTestFunction(C) block_u = BlockTrialFunction(C) u, = block_split(block_u) w = BlockFunction(C) theta = -1.0 a_time = inner(-alpha*pressure_freeze*I,sym(grad(psiu)))*dx #quasi static a = inner(2*mu_l*strain(u)+lmbda_l*div(u)*I, sym(grad(psiu)))*dx rhs_a = inner(f,psiu)*dx \ + dot(f_stress_y*n,psiu)*ds(2) r_u = [a] #DirichletBC bcd1 = DirichletBC(C.sub(0).sub(0), 0.0, boundaries, 1) # No normal displacement for solid on left side bcd3 = DirichletBC(C.sub(0).sub(0), 0.0, boundaries, 3) # No normal displacement for solid on right side bcd4 = DirichletBC(C.sub(0).sub(1), 0.0, boundaries, 4) # No normal displacement for solid on bottom side bcs = BlockDirichletBC([bcd1,bcd3,bcd4]) AA = block_assemble([r_u]) FF = block_assemble([rhs_a - a_time]) bcs.apply(AA) bcs.apply(FF) block_solve(AA, w.block_vector(), FF, "mumps") export_solution = w return export_solution, T
dx = Measure("dx", domain=mesh, subdomain_data=subdomains) ds = Measure("ds", domain=mesh, subdomain_data=boundaries) dS = Measure("dS", domain=mesh, subdomain_data=boundaries) # Test and trial functions vq = BlockTestFunction(W) (v, q) = block_split(vq) up = BlockTrialFunction(W) (u, p) = block_split(up) w = BlockFunction(W) w0 = BlockFunction(W) (u0, p0) = block_split(w0) n = FacetNormal(mesh) vc = CellVolume(mesh) fc = FacetArea(mesh) h = vc / fc h_avg = (vc("+") + vc("-")) / (2 * avg(fc)) penalty1 = 1.0 penalty2 = 10.0 theta = 1.0 # Constitutive parameters K = 1000.e3 nu = 0.25 E = K_nu_to_E(K, nu) # Pa 14 (mu_l, lmbda_l) = E_nu_to_mu_lmbda(E, nu)
def h_linear(integrator_type, mesh, subdomains, boundaries, t_start, dt, T, solution0, \ alpha_0, K_0, mu_l_0, lmbda_l_0, Ks_0, \ alpha_1, K_1, mu_l_1, lmbda_l_1, Ks_1, \ alpha, K, mu_l, lmbda_l, Ks, \ cf_0, phi_0, rho_0, mu_0, k_0,\ cf_1, phi_1, rho_1, mu_1, k_1,\ cf, phi, rho, mu, k, \ sigma_v_freeze, dphi_c_dt): # Create mesh and define function space parameters["ghost_mode"] = "shared_facet" # required by dS dx = Measure('dx', domain=mesh, subdomain_data=subdomains) ds = Measure('ds', domain=mesh, subdomain_data=boundaries) dS = Measure('dS', domain=mesh, subdomain_data=boundaries) BDM = FiniteElement("BDM", mesh.ufl_cell(), 1) PDG = FiniteElement("DG", mesh.ufl_cell(), 0) BDM_F = FunctionSpace(mesh, BDM) PDG_F = FunctionSpace(mesh, PDG) W = BlockFunctionSpace([BDM_F, PDG_F], restrict=[None, None]) TM = TensorFunctionSpace(mesh, 'DG', 0) PM = FunctionSpace(mesh, 'DG', 0) n = FacetNormal(mesh) vc = CellVolume(mesh) fc = FacetArea(mesh) h = vc / fc h_avg = (vc('+') + vc('-')) / (2 * avg(fc)) I = Identity(mesh.topology().dim()) monitor_dt = dt p_outlet = 0.1e6 p_inlet = 1000.0 M_inv = phi_0 * cf + (alpha - phi_0) / Ks # Define variational problem trial = BlockTrialFunction(W) dv, dp = block_split(trial) trial_dot = BlockTrialFunction(W) dv_dot, dp_dot = block_split(trial_dot) test = BlockTestFunction(W) psiv, psip = block_split(test) block_w = BlockFunction(W) v, p = block_split(block_w) block_w_dot = BlockFunction(W) v_dot, p_dot = block_split(block_w_dot) a_time = Constant(0.0) * inner(v_dot, psiv) * dx #quasi static # k is a function of phi #k = perm_update_rutqvist_newton(p,p0,phi0,phi,coeff) lhs_a = inner(dot(v, mu * inv(k)), psiv) * dx - p * div( psiv ) * dx #+ 6.0*inner(psiv,n)*ds(2) # - inner(gravity*(rho-rho0), psiv)*dx b_time = (M_inv + pow(alpha, 2.) / K) * p_dot * psip * dx lhs_b = div(v) * psip * dx #div(rho*v)*psip*dx #TODO rho rhs_v = -p_outlet * inner(psiv, n) * ds(3) rhs_p = -alpha / K * sigma_v_freeze * psip * dx - dphi_c_dt * psip * dx r_u = [lhs_a, lhs_b] j_u = block_derivative(r_u, block_w, trial) r_u_dot = [a_time, b_time] j_u_dot = block_derivative(r_u_dot, block_w_dot, trial_dot) r = [r_u_dot[0] + r_u[0] - rhs_v, \ r_u_dot[1] + r_u[1] - rhs_p] def bc(t): #bc_v = [DirichletBC(W.sub(0), (.0, .0), boundaries, 4)] v1 = DirichletBC(W.sub(0), (1.e-4 * 2.0, 0.0), boundaries, 1) v2 = DirichletBC(W.sub(0), (0.0, 0.0), boundaries, 2) v4 = DirichletBC(W.sub(0), (0.0, 0.0), boundaries, 4) bc_v = [v1, v2, v4] return BlockDirichletBC([bc_v, None]) # Define problem wrapper class ProblemWrapper(object): def set_time(self, t): pass #g.t = t # Residual and jacobian functions def residual_eval(self, t, solution, solution_dot): #print(as_backend_type(assemble(p_time - p_time_error)).vec().norm()) #print("gravity effect", as_backend_type(assemble(inner(gravity*(rho-rho0), psiv)*dx)).vec().norm()) return r def jacobian_eval(self, t, solution, solution_dot, solution_dot_coefficient): return [[Constant(solution_dot_coefficient)*j_u_dot[0, 0] + j_u[0, 0], \ Constant(solution_dot_coefficient)*j_u_dot[0, 1] + j_u[0, 1]], \ [Constant(solution_dot_coefficient)*j_u_dot[1, 0] + j_u[1, 0], \ Constant(solution_dot_coefficient)*j_u_dot[1, 1] + j_u[1, 1]]] # Define boundary condition def bc_eval(self, t): return bc(t) # Define initial condition def ic_eval(self): return solution0 # Define custom monitor to plot the solution def monitor(self, t, solution, solution_dot): pass # Solve the time dependent problem problem_wrapper = ProblemWrapper() (solution, solution_dot) = (block_w, block_w_dot) solver = TimeStepping(problem_wrapper, solution, solution_dot) solver.set_parameters({ "initial_time": t_start, "time_step_size": dt, "monitor": { "time_step_size": monitor_dt, }, "final_time": T, "exact_final_time": "stepover", "integrator_type": integrator_type, "problem_type": "linear", "linear_solver": "mumps", "report": True }) export_solution = solver.solve() return export_solution, T
def model(self, parameters=None, logger=None): def format(arr): return np.array(arr) # Setup parameters, logger self.set_parameters(parameters) self.set_logger(logger) # Get parameters parameters = self.get_parameters() #SS#if not parameters.get('simulate'): #SS# return # Setup data self.set_data(reset=True) self.set_observables(reset=True) # Show simulation settings self.get_logger()('\n\t'.join([ 'Simulating:', *[ '%s : %r' % (param, parameters[param] if not isinstance( parameters[param], dict) else list(parameters[param])) for param in ['fields', 'num_elem', 'N', 'dt', 'D', 'alpha', 'tol'] ] ])) # Data mesh mesh = IntervalMesh(MPI.comm_world, parameters['num_elem'], parameters['L_0'], parameters['L_1']) # Fields V = {} W = {} fields_n = {} fields = {} w = {} fields_0 = {} potential = {} potential_derivative = {} bcs = {} R = {} J = {} # v2d_vector = {} observables = {} for field in parameters['fields']: # Define functions V[field] = {} w[field] = {} for space in parameters['spaces']: V[field][space] = getattr( dolfin, parameters['spaces'][space]['type'])( mesh, parameters['spaces'][space]['family'], parameters['spaces'][space]['degree']) w[field][space] = TestFunction(V[field][space]) space = V[field][parameters['fields'][field]['space']] test = w[field][parameters['fields'][field]['space']] fields_n[field] = Function(space, name='%sn' % (field)) fields[field] = Function(space, name=field) # Inital condition fields_0[field] = Expression( parameters['fields'][field]['initial'], element=space.ufl_element()) fields_n[field] = project(fields_0[field], space) fields[field].assign(fields_n[field]) # Define potential if parameters['potential'].get('kwargs') is None: parameters['potential']['kwargs'] = {} for k in parameters['potential']['kwargs']: if parameters['potential']['kwargs'][k] is None: parameters['potential']['kwargs'][k] = fields[k] potential[field] = Expression( parameters['potential']['expression'], degree=parameters['potential']['degree'], **parameters['potential']['kwargs']) potential_derivative[field] = Expression( parameters['potential']['derivative'], degree=parameters['potential']['degree'] - 1, **parameters['potential']['kwargs']) #Subdomain for defining Positive grain sub_domains = MeshFunction('size_t', mesh, mesh.topology().dim(), 0) #BC condition bcs[field] = [] if parameters['fields'][field]['bcs'] == 'dirichlet': BC_l = CompiledSubDomain('near(x[0], side) && on_boundary', side=parameters['L_0']) BC_r = CompiledSubDomain('near(x[0], side) && on_boundary', side=parameters['L_1']) bcl = DirichletBC(V, fields_n[field], BC_l) bcr = DirichletBC(V, fields_n[field], BC_r) bcs[field].extend([bcl, bcr]) elif parameters['fields'][field]['bcs'] == 'neumann': bcs[field].extend([]) # Residual and Jacobian R[field] = ( ((fields[field] - fields_n[field]) / parameters['dt'] * test * dx) + (inner(parameters['D'] * grad(test), grad(fields[field])) * dx) + (parameters['alpha'] * potential_derivative[field] * test * dx)) J[field] = derivative(R[field], fields[field]) # Observables observables[field] = {} files = { 'xdmf': XDMFFile(MPI.comm_world, self.get_paths()['xdmf']), 'hdf5': HDF5File(MPI.comm_world, self.get_paths()['hdf5'], 'w'), } files['hdf5'].write(mesh, '/mesh') eps = lambda n, key, field, observables, tol: ( n == 0) or (abs(observables[key]['total_energy'][n] - observables[ key]['total_energy'][n - 1]) / (observables[key]['total_energy'][0]) > tol) flag = {field: True for field in parameters['fields']} tol = { field: parameters['tol'][field] if isinstance( parameters['tol'], dict) else parameters['tol'] for field in parameters['fields'] } phases = {'p': 1, 'm': 2} n = 0 problem = {} solver = {} while (n < parameters['N'] and any([flag[field] for field in parameters['fields']])): self.get_logger()('Time: %d' % (n)) for field in parameters['fields']: if not flag[field]: continue # Solve problem[field] = NonlinearVariationalProblem( R[field], fields[field], bcs[field], J[field]) solver[field] = NonlinearVariationalSolver(problem[field]) solver[field].solve() # Get field array array = assemble( (1 / CellVolume(mesh)) * inner(fields[field], w[field]['Z']) * dx).get_local() # Observables observables[field]['Time'] = parameters['dt'] * n # observables[field]['energy_density'] = format(0.5*dot(grad(fields[field]),grad(fields[field]))*dx) observables[field]['gradient_energy'] = format( assemble(0.5 * dot(grad(fields[field]), grad(fields[field])) * dx(domain=mesh))) observables[field]['landau_energy'] = format( assemble(potential[field] * dx(domain=mesh))) observables[field]['diffusion_energy'] = format( assemble( project( div(project(grad(fields[field]), V[field]['W'])), V[field]['Z']) * dx(domain=mesh)) ) #Diffusion part of chemical potential observables[field]['spinodal_energy'] = format( assemble( potential_derivative[field] * dx(domain=mesh))) #Spinodal part of chemical potential observables[field]['total_energy'] = parameters[ 'D'] * observables[field]['gradient_energy'] + parameters[ 'alpha'] * observables[field]['landau_energy'] observables[field]['chi'] = parameters['alpha'] * observables[ field]['diffusion_energy'] - parameters['D'] * observables[ field]['spinodal_energy'] # Phase observables sub_domains.set_all(0) sub_domains.array()[:] = np.where(array > 0.0, phases['p'], phases['m']) phases_dxp = Measure('dx', domain=mesh, subdomain_data=sub_domains) for phase in phases: dxp = phases_dxp(phases[phase]) observables[field]['Phi_0%s' % (phase)] = format( assemble(1 * dxp)) observables[field]['Phi_1%s' % (phase)] = format( assemble(fields[field] * dxp)) observables[field]['Phi_2%s' % (phase)] = format( assemble(fields[field] * fields[field] * dxp)) observables[field]['Phi_3%s' % (phase)] = format( assemble(fields[field] * fields[field] * fields[field] * dxp)) observables[field]['Phi_4%s' % (phase)] = format( assemble(fields[field] * fields[field] * fields[field] * fields[field] * dxp)) observables[field]['Phi_5%s' % (phase)] = format( assemble(fields[field] * fields[field] * fields[field] * fields[field] * fields[field] * dxp)) observables[field]['gradient_energy_%s' % (phase)] = format( assemble( 0.5 * dot(grad(fields[field]), grad(fields[field])) * dxp)) observables[field]['landau_energy_%s' % (phase)] = format( assemble(potential[field] * dxp)) observables[field][ 'total_energy_%s' % (phase)] = parameters['D'] * observables[field][ 'gradient_energy_%s' % (phase)] + parameters['alpha'] * observables[ field]['landau_energy_%s' % (phase)] observables[field][ 'diffusion_energy_%s' % (phase)] = format( assemble( project( div( project(grad(fields[field]), V[field]['W'])), V[field]['Z']) * dxp)) #Diffusion part of chemical potential observables[field][ 'spinodal_energy_%s' % (phase)] = format( assemble( potential_derivative[field] * dxp)) #Spinodal part of chemical potential observables[field][ 'chi_%s' % (phase)] = parameters['alpha'] * observables[field][ 'spinodal_energy_%s' % (phase)] - parameters['D'] * observables[field][ 'diffusion_energy_%s' % (phase)] files['hdf5'].write(fields[field], '/%s' % (field), n) files['xdmf'].write(fields[field], n) fields_n[field].assign(fields[field]) self.set_data({field: array}) self.set_observables({field: observables[field]}) flag[field] = eps(n, field, fields[field], self.get_observables(), tol[field]) n += 1 for file in files: files[file].close() return