def solve(self, dt): self.u = Function(self.V0) self.w = TestFunction(self.V0) self.du = TrialFunction(self.V0) x = SpatialCoordinate(self.mesh0) L = inner( self.S(), self.eps(self.w) )*dx(degree=4)\ - inner( self.b, self.w )*dx(degree=4)\ - inner( self.h, self.w )*ds(degree=4)\ + inner( 1e-6*self.u, self.w )*ds(degree=4)\ - inner( min_value(x[2]+self.ut[2]+self.u[2], 0) * Constant((0,0,-1.0)), self.w )*ds(degree=4) a = derivative(L, self.u, self.du) problem = NonlinearVariationalProblem(L, self.u, bcs=[], J=a) solver = NonlinearVariationalSolver(problem) solver.solve() self.ut.vector()[:] = self.ut.vector()[:] + self.u.vector()[:] ALE.move(self.mesh, Function(self.V, self.u.vector())) self.v.vector()[:] = self.u.vector()[:] / dt self.n = FacetNormal(self.mesh)
def set_solver_alpha_snes2(self): V = self.alpha.function_space() denergy = derivative(self.energy, self.alpha, TestFunction(V)) ddenergy = derivative(denergy, self.alpha, TrialFunction(V)) self.lb = self.alpha_init # interpolate(Constant("0."), V) ub = interpolate(Constant("1."), V) self.problem_alpha = NonlinearVariationalProblem(denergy, self.alpha, self.bcs_alpha, J=ddenergy) self.problem_alpha.set_bounds(self.lb, ub) self.problem_alpha.lb = self.lb # set up the solver solver = NonlinearVariationalSolver(self.problem_alpha) snes_solver_parameters_bounds = { "nonlinear_solver": "snes", "snes_solver": { "linear_solver": "mumps", "maximum_iterations": 300, "report": True, "line_search": "basic", "method": "vinewtonrsls", "absolute_tolerance": 1e-5, "relative_tolerance": 1e-5, "solution_tolerance": 1e-5 } } solver.parameters.update(snes_solver_parameters_bounds) #solver.solve() self.solver = solver
assign(u.sub(2), psi_int) an, ca, psi = split(u) van, vca, vpsi = TestFunctions(ME) Fan = D_an * (-inner(grad(an), grad(van)) * dx - Farad / R / Temp * z_an * an * inner(grad(psi), grad(van)) * dx) Fca = D_ca * (-inner(grad(ca), grad(vca)) * dx - Farad / R / Temp * z_ca * ca * inner(grad(psi), grad(vca)) * dx) Fpsi = inner(grad(psi), grad(vpsi)) * dx - (Farad / (eps0 * epsR)) * ( z_an * an + z_ca * ca + z_fc * fc_function) * vpsi * dx F = Fpsi + Fan + Fca J = derivative(F, u) problem = NonlinearVariationalProblem(F, u, bcs=bcs, J=J) solver = NonlinearVariationalSolver(problem) prm = solver.parameters #print(solver.default_parameters().items()) prm["newton_solver"]["linear_solver"] = 'mumps' solver.solve() ######################### Post - Processing ################################# an, ca, psi = u.split() aftersolveT = timer() first = plot(an, title="Anion concentration, $c^-$") plt.xlim(0.0, 0.015) plt.xticks([0.0, 0.005, 0.01, 0.015]) plt.ylim(0.0, 0.015)
def cmscr1d_weak_solution(V: VectorFunctionSpace, f: Function, ft: Function, fx: Function, alpha0: float, alpha1: float, alpha2: float, alpha3: float, beta: float, bcs=[]) \ -> (Function, Function, float, float, bool): """Solves the weak formulation of the Euler-Lagrange equations of the L2-H1 mass conserving flow functional with source and with spatio-temporal and convective regularisation for a 1D image sequence with natural boundary conditions. Args: V (VectorFunctionSpace): The function space. f (Function): A 1D image sequence. ft (Function): Partial derivative of f wrt. time. fx (Function): Partial derivative of f wrt. space. alpha0 (float): The spatial regularisation parameter for v. alpha1 (float): The temporal regularisation parameter for v. alpha2 (float): The spatial regularisation parameter for k. alpha3 (float): The temporal regularisation parameter for k. beta (float): The convective regularisation parameter for. bcs: boundary conditions (optional). Returns: v (Function): The velocity. k (Function): The source. res (float): The residual. fun (float): The function value. status (bool): True if Newton's method converged. """ # Define trial and test functions. w = Function(V) v, k = split(w) w1, w2 = TestFunctions(V) # Define weak formulation. A = (- (ft + fx * v + f * v.dx(1) - k) * (fx * w1 + f * w1.dx(1)) - alpha0 * v.dx(1) * w1.dx(1) - alpha1 * v.dx(0) * w1.dx(0) - beta * k.dx(1) * (k.dx(0) + k.dx(1) * v) * w1) * dx \ + ((ft + fx * v + f * v.dx(1) - k) * w2 - alpha2 * k.dx(1) * w2.dx(1) - alpha3 * k.dx(0) * w2.dx(0) - beta * (k.dx(0) * w2.dx(0) + k.dx(1) * v * w2.dx(0) + k.dx(0) * v * w2.dx(1) + k.dx(1) * v * v * w2.dx(1))) * dx # Compute Gateaux derivative. DA = derivative(A, w) # Set up solver. problem = NonlinearVariationalProblem(A, w, bcs, DA) solver = NonlinearVariationalSolver(problem) # Set solver parameters. prm = solver.parameters prm['newton_solver']['error_on_nonconvergence'] = False prm['newton_solver']['maximum_iterations'] = 15 prm['newton_solver']['absolute_tolerance'] = 1e-10 prm['newton_solver']['relative_tolerance'] = 1e-10 # Compute solution via Newton method. itern, status = solver.solve() if not bool(status): print("Newton's method did not converge within {0} ".format(itern) + "iterations for parameters alpha0={0}, ".format(alpha0) + "alpha1={0}, alpha3={1}, ".format(alpha1, alpha2) + "alpha4={0}, beta={1}".format(alpha3, beta)) # Recover solution. v, k = w.split(deepcopy=True) # Evaluate and print residual and functional value. res = abs(ft + fx * v + f * v.dx(1) - k) fun = 0.5 * (res**2 + alpha0 * v.dx(1)**2 + alpha1 * v.dx(0)**2 + alpha2 * k.dx(1)**2 + alpha3 * k.dx(0)**2 + beta * (k.dx(0) + k.dx(1) * v)**2) print('Res={0}, Func={1}'.format(assemble(res * dx), assemble(fun * dx))) return v, k, assemble(res * dx), assemble(fun * dx), bool(status)
def solve(self, problem): self.problem = problem doSave = problem.doSave save_this_step = False onlyVel = problem.saveOnlyVel dt = self.metadata['dt'] nu = Constant(self.problem.nu) self.tc.init_watch('init', 'Initialization', True, count_to_percent=False) self.tc.init_watch('solve', 'Running nonlinear solver', True, count_to_percent=True) self.tc.init_watch('next', 'Next step assignments', True, count_to_percent=True) self.tc.init_watch('saveVel', 'Saved velocity', True) self.tc.start('init') mesh = self.problem.mesh # Define function spaces (P2-P1) self.V = VectorFunctionSpace(mesh, "Lagrange", 2) # velocity self.Q = FunctionSpace(mesh, "Lagrange", 1) # pressure self.W = MixedFunctionSpace([self.V, self.Q]) self.PS = FunctionSpace( mesh, "Lagrange", 2) # partial solution (must be same order as V) self.D = FunctionSpace(mesh, "Lagrange", 1) # velocity divergence space # to assign solution in space W.sub(0) to Function(V) we need FunctionAssigner (cannot be assigned directly) fa = FunctionAssigner(self.V, self.W.sub(0)) velSp = Function(self.V) problem.initialize(self.V, self.Q, self.PS, self.D) # Define unknown and test function(s) NS v, q = TestFunctions(self.W) w = Function(self.W) dw = TrialFunction(self.W) u, p = split(w) # Define fields n = FacetNormal(mesh) I = Identity(u.geometric_dimension()) theta = 0.5 # Crank-Nicholson k = Constant(self.metadata['dt']) # Initial conditions: u0 velocity at previous time step u1 velocity two time steps back p0 previous pressure [u0, p0] = self.problem.get_initial_conditions([{ 'type': 'v', 'time': 0.0 }, { 'type': 'p', 'time': 0.0 }]) if doSave: problem.save_vel(False, u0) # boundary conditions bcu, bcp = problem.get_boundary_conditions(False, self.W.sub(0), self.W.sub(1)) # Define steady part of the equation def T(u): return -p * I + 2.0 * nu * sym(grad(u)) def F(u, v, q): return (inner(T(u), grad(v)) - q * div(u)) * dx + inner( grad(u) * u, v) * dx # Define variational forms F_ns = (inner( (u - u0), v) / k) * dx + (1.0 - theta) * F(u0, v, q) + theta * F( u, v, q) J_ns = derivative(F_ns, w, dw) # J_ns = derivative(F_ns, w) # did not work # NS_problem = NonlinearVariationalProblem(F_ns, w, bcu, J_ns, form_compiler_parameters=ffc_options) NS_problem = NonlinearVariationalProblem(F_ns, w, bcu, J_ns) # (var. formulation, unknown, Dir. BC, jacobian, optional) NS_solver = NonlinearVariationalSolver(NS_problem) prm = NS_solver.parameters prm['newton_solver']['absolute_tolerance'] = 1E-08 prm['newton_solver']['relative_tolerance'] = 1E-08 # prm['newton_solver']['maximum_iterations'] = 45 # prm['newton_solver']['relaxation_parameter'] = 1.0 prm['newton_solver']['linear_solver'] = 'mumps' # prm['newton_solver']['lu_solver']['same_nonzero_pattern'] = True info(NS_solver.parameters, True) self.tc.end('init') # Time-stepping info("Running of direct method") ttime = self.metadata['time'] t = dt step = 1 while t < (ttime + dt / 2.0): self.problem.update_time(t, step) if self.MPI_rank == 0: problem.write_status_file(t) if doSave: save_this_step = problem.save_this_step # Compute begin("Solving NS ....") try: self.tc.start('solve') NS_solver.solve() self.tc.end('solve') except RuntimeError as inst: problem.report_fail(t) return 1 end() # Extract solutions: (u, p) = w.split() fa.assign(velSp, u) # we are assigning twice (now and inside save_vel), but it works with one method save_vel for direct and # projection (we could split save_vel to save one assign) if save_this_step: self.tc.start('saveVel') problem.save_vel(False, velSp) self.tc.end('saveVel') if save_this_step and not onlyVel: problem.save_div(False, u) problem.compute_err(False, u, t) problem.compute_div(False, u) # foo = Function(self.Q) # foo.assign(p) # problem.averaging_pressure(foo) # if save_this_step and not onlyVel: # problem.save_pressure(False, foo) if save_this_step and not onlyVel: problem.save_pressure(False, p) # compute functionals (e. g. forces) problem.compute_functionals(u, p, t, step) # Move to next time step self.tc.start('next') u0.assign(velSp) t = round(t + dt, 6) # round time step to 0.000001 step += 1 self.tc.end('next') info("Finished: direct method") problem.report() return 0
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