def compute_objective(self): """Computes the part of the objective value that comes from the regularization Returns ------- float Part of the objective value coming from the regularization """ if self.has_regularization: value = 0.0 if self.mu_volume > 0.0: if not self.measure_hole: volume = fenics.assemble(Constant(1.0)*self.dx) else: volume = self.delta_x*self.delta_y*self.delta_z - fenics.assemble(Constant(1)*self.dx) value += 0.5*self.mu_volume*pow(volume - self.target_volume, 2) if self.mu_surface > 0.0: surface = fenics.assemble(Constant(1.0)*self.ds) # self.current_surface.val = surface value += 0.5*self.mu_surface*pow(surface - self.target_surface, 2) if self.mu_curvature > 0.0: self.compute_curvature() curvature_val = fenics.assemble(fenics.inner(self.kappa_curvature, self.kappa_curvature)*self.ds) value += 0.5*self.mu_curvature*curvature_val if self.mu_barycenter > 0.0: if not self.measure_hole: volume = fenics.assemble(Constant(1)*self.dx) barycenter_x = fenics.assemble(self.spatial_coordinate[0]*self.dx) / volume barycenter_y = fenics.assemble(self.spatial_coordinate[1]*self.dx) / volume if self.form_handler.mesh.geometric_dimension() == 3: barycenter_z = fenics.assemble(self.spatial_coordinate[2]*self.dx) / volume else: barycenter_z = 0.0 else: volume = self.delta_x*self.delta_y*self.delta_z - fenics.assemble(Constant(1)*self.dx) barycenter_x = (0.5*(pow(self.x_end, 2) - pow(self.x_start, 2))*self.delta_y*self.delta_z - fenics.assemble(self.spatial_coordinate[0]*self.dx)) / volume barycenter_y = (0.5*(pow(self.y_end, 2) - pow(self.y_start, 2))*self.delta_x*self.delta_z - fenics.assemble(self.spatial_coordinate[1]*self.dx)) / volume if self.form_handler.mesh.geometric_dimension() == 3: barycenter_z = (0.5*(pow(self.z_end, 2) - pow(self.z_start, 2))*self.delta_x*self.delta_y - fenics.assemble(self.spatial_coordinate[2]*self.dx)) / volume else: barycenter_z = 0.0 value += 0.5*self.mu_barycenter*(pow(barycenter_x - self.target_barycenter_list[0], 2) + pow(barycenter_y - self.target_barycenter_list[1], 2) + pow(barycenter_z - self.target_barycenter_list[2], 2)) return value else: return 0.0
def solve(self, **arguments): t_start = time.clock() # definig Function space on this mesh using Lagrange #polynoimals of degree 1. H = FunctionSpace(self.mesh, "CG", 1) # Setting up the variational problem v = TrialFunction(H) w = TestFunction(H) epsilon = Constant(arguments[Components().Diffusion]) f = Constant(0) a = (epsilon * inner(grad(v), grad(w)) + inner(v, w)) * dx #Still have to figure it how to use a Neumann Condition here L = f * w * dx # solving the variational problem. v = Function(H) solve(a == L, v) self.solution.extend(v.vector().array()) return [self.solution, time.clock() - t_start]
def run_fokker_planck(nx, num_steps, t_0 = 0, t_final=10): # define mesh mesh = IntervalMesh(nx, -200, 200) # define function space. V = FunctionSpace(mesh, "Lagrange", 1) # Homogenous Neumann BCs don't have to be defined as they are the default in dolfin # define parameters. dt = (t_final-t_0) / num_steps # set mu and sigma mu = Constant(-1) D = Constant(1) # define initial conditions u_0 u_0 = Expression('x[0]', degree=1) # set U_n to be the interpolant of u_0 over the function space V. Note that # u_n is the value of u at the previous timestep, while u is the current value. u_n = interpolate(u_0, V) # Define variational problem u = TrialFunction(V) v = TestFunction(V) F = u*v*dx + dt*inner(D*grad(u), grad(v))*dx + dt*mu*grad(u)[0]*v*dx - inner(u_n, v)*dx # isolate the bilinear and linear forms. a, L = lhs(F), rhs(F) # initialize function to capture solution. t = 0 u_h = Function(V) plt.figure(figsize=(15, 15)) # time-stepping section for n in range(num_steps): t += dt # compute solution solve(a == L, u_h) u_n.assign(u_h) # Plot solutions intermittently if n % (num_steps // 10) == 0 and num_steps > 0: plot(u_h, label='t = %s' % t) plt.legend() plt.grid() plt.title("Finite Element Solutions to Fokker-Planck Equation with $\mu(x, t) = -(x+1)$ , $D(x, t) = e^t x^2$, $t_n$ = %s" % t_final) plt.ylabel("$u(x, t)$") plt.xlabel("x") plt.savefig("fpe/fokker-planck-solutions-mu.png") plt.clf() # return the approximate solution evaluated on the coordinates, and the actual coordinates. return u_n.compute_vertex_values(), mesh.coordinates()
def solve(self, **arguments): t_start = time.clock() # definig Function space on this mesh using Lagrange #polynoimals of degree 1. H = FunctionSpace(self.mesh, "CG", 1) # Setting up the variational problem v = TrialFunction(H) w = TestFunction(H) coeff_dx2 = Constant(1) coeff_v = Constant(1) f = Expression("(4*pow(pi,2))*exp(-(1/coeff_v)*t)*sin(2*pi*x[0])", {'coeff_v': coeff_v}, degree=2) v0 = Expression("sin(2*pi*x[0])", degree=2) f.t = 0 def boundary(x, on_boundary): return on_boundary bc = DirichletBC(H, v0, boundary) v1 = interpolate(v0, H) dt = self.steps.time a = (dt * inner(grad(v), grad(w)) + dt * coeff_v * inner(v, w)) * dx L = (f * dt - coeff_v * v1) * w * dx A = assemble(a) v = Function(H) T = self.domain.time[-1] t = dt # solving the variational problem. while t <= T: b = assemble(L, tensor=b) vo.t = t bc.apply(A, b) solve(A, v.vector(), b) t += dt v1.assign(v) self.solution.extend(v.vector().array()) return [self.solution, time.clock() - t_start]
def init_params(self, parameters, param_funcs): """Initialize parameter attributes from __init__ arguments The attributes initialized are: self.params0: a dict giving initial values of all parameters (not just floats). This is basically a copy of the parameters argument to __init__, with the insertion of 't' as a new parameter (always param_names[-1]). self.param_names: a list of the names of the time-varying parameters. This is the keys of params0 whose corrsponding values are of type float. The order is the order of the parameters in self.PSf. self.nparams: len(self.param_names) self.param_numbers: a dict mapping param names to numbers (ints) in the list param_names and the parameters subspace of the solution FunctionSpace. self.param_funcs: a dict whose keys are the param_names and whose values are functions to determine their values as a function of time, as explained above. These are copied from the param_funcs argument of __init__, except that the default initial value function is filled in for parameters not present in the argument. Also, the function defined for 't' always returns t. self.PSf: a Constant object of dimension self.nparams, holding the initial values of the parameters. """ self.param_names = [ n for n, v in parameters.items() if (type(v) is float and n != 't') ] self.param_names.append('t') self.nparams = len(self.param_names) logVARIABLE('self.param_names', self.param_names) logVARIABLE('self.nparams', self.nparams) self.param_numbers = collections.OrderedDict( zip(self.param_names, itertools.count())) self.params0 = collections.OrderedDict(parameters) self.params0['t'] = 0.0 self.param_funcs = param_funcs.copy() def identity(t, params={}): return t self.param_funcs['t'] = identity for n in self.param_names: if n not in self.param_funcs: def value0(t, params={}, v0=self.params0[n]): return v0 self.param_funcs[n] = value0 self.PSf = Constant([self.params0[n] for n in self.param_names]) return
def _solve(self, z, x=None): # problem variables du = TrialFunction(self.V) # incremental displacement v = TestFunction(self.V) # test function u = Function(self.V) # displacement from previous iteration # kinematics ii = Identity(3) # identity tensor dimension 3 f = ii + grad(u) # deformation gradient c = f.T * f # right Cauchy-Green tensor # invariants of deformation tensors ic = tr(c) j = det(f) # elasticity parameters if type(z) in [list, np.ndarray]: param = self.param_remapper(z[0]) if self.param_remapper is not None else z[0] else: param = self.param_remapper(z) if self.param_remapper is not None else z e_var = variable(Constant(param)) # Young's modulus nu = Constant(.3) # Shear modulus (Lamè's second parameter) mu, lmbda = e_var / (2 * (1 + nu)), e_var * nu / ((1 + nu) * (1 - 2 * nu)) # strain energy density, total potential energy psi = (mu / 2) * (ic - 3) - mu * ln(j) + (lmbda / 2) * (ln(j)) ** 2 pi = psi * dx - self.time * dot(self.f, u) * self.ds(3) ff = derivative(pi, u, v) # compute first variation of pi jj = derivative(ff, u, du) # compute jacobian of f # solving if x is not None: numeric_evals = np.zeros(shape=(x.shape[1], len(self.times))) evals = np.zeros(shape=(x.shape[1], len(self.eval_times))) else: numeric_evals = None evals = None for it, t in enumerate(self.times): self.time.t = t self.solver(ff == 0, u, self.bcs, J=jj, bcs=self.bcs, solver_parameters=self.solver_parameters) if x is not None: numeric_evals[:, it] = np.log(np.array([-u(x_)[2] for x_ in x.T]).T) # time-interpolation if x is not None: for i in range(evals.shape[0]): evals[i, :] = np.interp(self.eval_times, self.times, numeric_evals[i, :]) return (evals, u) if x is not None else u
def update_geometric_quantities(self): """Updates the geometric quantities Updates the volume, surface area, and barycenters (after the mesh is updated) Returns ------- None """ if not self.measure_hole: volume = fenics.assemble(Constant(1) * self.dx) barycenter_x = fenics.assemble( self.spatial_coordinate[0] * self.dx) / volume barycenter_y = fenics.assemble( self.spatial_coordinate[1] * self.dx) / volume if self.form_handler.mesh.geometric_dimension() == 3: barycenter_z = fenics.assemble( self.spatial_coordinate[2] * self.dx) / volume else: barycenter_z = 0.0 else: volume = self.delta_x * self.delta_y * self.delta_z - fenics.assemble( Constant(1) * self.dx) barycenter_x = (0.5 * (pow(self.x_end, 2) - pow(self.x_start, 2)) * self.delta_y * self.delta_z - fenics.assemble( self.spatial_coordinate[0] * self.dx)) / volume barycenter_y = (0.5 * (pow(self.y_end, 2) - pow(self.y_start, 2)) * self.delta_x * self.delta_z - fenics.assemble( self.spatial_coordinate[1] * self.dx)) / volume if self.form_handler.mesh.geometric_dimension() == 3: barycenter_z = (0.5 * (pow(self.z_end, 2) - pow(self.z_start, 2)) * self.delta_x * self.delta_y - fenics.assemble(self.spatial_coordinate[2] * self.dx)) / volume else: barycenter_z = 0.0 surface = fenics.assemble(Constant(1) * self.ds) self.current_volume.val = volume self.current_surface.val = surface self.current_barycenter_x.val = barycenter_x self.current_barycenter_y.val = barycenter_y self.current_barycenter_z.val = barycenter_z
def solve(self, **arguments): t_start = time.clock() # definig Function space on this mesh using Lagrange #polynoimals of degree 1. H = FunctionSpace(self.mesh, "CG", 1) # Setting up the variational problem v = TrialFunction(H) w = TestFunction(H) epsilon = Constant(arguments[Components().Diffusion]) f = Expression("(1 - epsilon*4*pow(pi,2))*cos(2*pi*x[0])",\ epsilon=epsilon, degree=1) a = (epsilon * inner(grad(v), grad(w)) + inner(v, w)) * dx L = f * w * dx # solving the variational problem. v = Function(H) solve(a == L, v) self.solution.extend(v.vector().array()) return [self.solution, time.clock() - t_start]
def initialise(dem, bounds, res): """ Function to initialise the model space :param dem: 0 = no input DEM; 1 = input DEM :param bounds: west, south, east, north - if no DEM [0, 0, lx, ly]; if DEM [west, south, east, north] :param res: model resolution along the y-axis. :return model_space, u_n, mesh, V, bc: """ if dem == 0: lx = bounds[1] ly = bounds[3] # Create mesh and define function space domain = Rectangle(Point(0, 0), Point(lx / ly, ly / ly)) mesh = generate_mesh(domain, res) V = FunctionSpace(mesh, 'P', 1) # Define initial value u_D = Constant(0) eps = 10 / ly u_n = interpolate(u_D, V) u_n.vector().set_local(u_n.vector().get_local() + eps * np.random.random(u_n.vector().size())) if dem == 1: u_n, lx, ly, mesh, V = read_dem(bounds, res) # boundary conditions class East(SubDomain): def inside(self, x, on_boundary): return near(x[0], lx / ly) class West(SubDomain): def inside(self, x, on_boundary): return near(x[0], 0.0) class North(SubDomain): def inside(self, x, on_boundary): return near(x[1], ly / ly) class South(SubDomain): def inside(self, x, on_boundary): return near(x[1], 0.0) # Should make this into an option! bc = [DirichletBC(V, u_n, West()), DirichletBC(V, u_n, East())] # def boundary(x, on_boundary): # return on_boundary # bc = DirichletBC(V, u_n, boundary) model_space = [lx, ly, res] return model_space, u_n, mesh, V, bc
def dual_error_estimates(resolution): mesh = UnitSquareMesh(resolution, resolution) def all_boundary(_, on_boundary): return on_boundary zero = Constant(0.0) def a(u, v): return inner(grad(u), grad(v)) * dx def L(f, v): return f * v * dx # Primal problem f = Expression("32.*x[0]*(1. - x[0])+32.*x[1]*(1. - x[1])", domain=mesh, degree=5) ue = Expression("16.*x[0]*(1. - x[0])*x[1]*(1. - x[1])", domain=mesh, degree=5) Qp = FunctionSpace(mesh, 'CG', 1) bcp = DirichletBC(Qp, zero, all_boundary) u = TrialFunction(Qp) v = TestFunction(Qp) U = Function(Qp) solve(a(u, v) == L(f, v), U, bcp) # Dual problem Qd = FunctionSpace(mesh, 'CG', 2) psi = Constant(1.0) bcd = DirichletBC(Qd, zero, all_boundary) w = TestFunction(Qd) phi = TrialFunction(Qd) Phi = Function(Qd) solve(a(w, phi) == L(psi, w), Phi, bcd) # Compute errors e1 = compute_error(ue, U) e2 = assemble((inner(grad(U), grad(Phi)) - f * Phi) * dx) print("e1 = {}".format(e1)) print("e2 = {}".format(e2))
def __init__(self, *, V: Optional[FunctionSpace], mesh: Mesh, dt: float): V = V or FunctionSpace(mesh, "Lagrange", 1) self.V = V self.u = TrialFunction(V) self.v = TestFunction(V) self.P_prev = Function(V) self.theta_a = Constant(1.0) self.D_e = Constant(1.0) self.P_d = Constant(1.0) self.my_v = Constant(1.0) self.my_d = Constant(1.0) self.alpha_th = Constant(1.0) self.M_mm = Constant(1.0) self.q_h = Constant(1.0) self.T_s = project(Constant(-5.0), V) self.dt = Constant(dt) self.mesh = mesh
def problem_mix(T, dt, E, coupling, VV, boundaries, rho_s, lambda_, mu_s, f, bcs, **Solid_namespace): # Temporal parameters t = 0 k = Constant(dt) # Split problem to two 1.order differential equations psi, phi = TestFunctions(VV) # Functions, wd is for holding the solution d_ = {} w_ = {} wd_ = {} for time in ["n", "n-1", "n-2", "n-3"]: if time == "n" and E not in [None, reference]: tmp_wd = Function(VV) wd_[time] = tmp_wd wd = TrialFunction(VV) w, d = split(wd) else: wd = Function(VV) wd_[time] = wd w, d = split(wd) d_[time] = d w_[time] = w # Time derivative if coupling == "center": G = rho_s / (2 * k) * inner(w_["n"] - w_["n-2"], psi) * dx else: G = rho_s / k * inner(w_["n"] - w_["n-1"], psi) * dx # Stress tensor G += inner(Piola2(d_, w_, k, lambda_, mu_s, E_func=E), grad(psi)) * dx # External forces, like gravity G -= rho_s * inner(f, psi) * dx # d-w coupling if coupling == "CN": G += inner(d_["n"] - d_["n-1"] - k * 0.5 * (w_["n"] + w_["n-1"]), phi) * dx elif coupling == "imp": G += inner(d_["n"] - d_["n-1"] - k * w_["n"], phi) * dx elif coupling == "exp": G += inner(d_["n"] - d_["n-1"] - k * w_["n-1"], phi) * dx elif coupling == "center": G += innter(d_["n"] - d_["n-2"] - 2 * k * w["n-1"], phi) * dx else: print "The coupling %s is not implemented, 'CN', 'imp', and 'exp' are the only valid choices." sys.exit(0) # Solve if E in [None, reference]: solver_nonlinear(G, d_, w_, wd_, bcs, T, dt, **Solid_namespace) else: solver_linear(G, d_, w_, wd_, bcs, T, dt, **Solid_namespace)
def set_time(self, t): self.t = t params = collections.OrderedDict( zip(self.param_names, self.PSf.values())) self.PSf.assign( Constant([ self.param_funcs[n](t, params=params) for n in self.param_names ])) logVARIABLE('self.t', self.t) logVARIABLE( 'collections.OrderedDict(zip(self.param_names, self.PSf.values()))', collections.OrderedDict(zip(self.param_names, self.PSf.values())))
def __init__(self, *, V: Optional[FunctionSpace], mesh: Mesh, dt: float) -> None: V = V or FunctionSpace(mesh, "Lagrange", 1) self.V = V self.T = TrialFunction(V) self.v = TestFunction(V) self.T_prev = Function(V) self.P_s = Constant(1.0) self.c_s = Constant(1.0) self.k_e = Constant(1.0) self.Q_pc = Constant(1.0) self.Q_sw = Constant(1.0) self.Q_mm = Constant(1.0) self.dt = Constant(dt)
def solve_wave_equation(u0, u1, u_boundary, f, domain, mesh, degree): """Solving the wave equation using CG-CG method. Args: u0: Initial data. u1: Initial velocity. u_boundary: Dirichlet boundary condition. f: Right-hand side. domain: Space-time domain. mesh: Computational mesh. degree: CG(degree) will be used as the finite element. Outputs: uh: Numerical solution. """ # Element V = FunctionSpace(mesh, "CG", degree) # Measures on the initial and terminal slice mask = MeshFunction("size_t", mesh, mesh.topology().dim() - 1, 0) domain.get_initial_slice().mark(mask, 1) ends = ds(subdomain_data=mask) # Form g = Constant(((-1.0, 0.0), (0.0, 1.0))) u = TrialFunction(V) v = TestFunction(V) a = dot(grad(v), dot(g, grad(u))) * dx L = f * v * dx + u1 * v * ends(1) # Assembled matrices A = assemble(a, keep_diagonal=True) b = assemble(L, keep_diagonal=True) # Spatial boundary condition bc = DirichletBC(V, u_boundary, domain.get_spatial_boundary()) bc.apply(A, b) # Temporal boundary conditions (by hand) (A, b) = apply_time_boundary_conditions(domain, V, u0, A, b) # Solve solver = LUSolver() solver.set_operator(A) uh = Function(V) solver.solve(uh.vector(), b) return uh
def _incell_geodesic_step_maker(g): """ Symplectic integrator of the Hamiltonian geodesic equation in a cell. """ # initialize mesh = g.function_space().mesh() deg = g.ufl_element().degree() dim = g.ufl_shape[0] # choose solver and compute metric derivatives if deg == 0: # lowest degree Regge solver = _explicit_euler dg = [Constant(((0, ) * dim, ) * dim) for i in range(dim)] else: # for degree >= 1 solver = _gauss6 # compute the first derivatives of the metric globally # note: this is in fact more efficient than computing the derivative # cell by cell on the go. memeory is not a issue here. W = TensorFunctionSpace(mesh, 'DG', deg - 1) dg = [project(g.dx(i), W, solver_type='mumps') for i in range(dim)] def F(y, c): """ Hamiltonian geodesic equation as a system.""" q = y[0:dim] p = y[dim:] ginv = inv(_eval_metric(g, c, q)) nq = ginv.dot(p) np = array([ 0.5 * _eval_metric(dg[i], c, q).dot(ginv.dot(p)).dot(ginv.dot(p)) for i in range(dim) ]) return concatenate([nq, np]) def step(c, t, y0, h): """ Geodesic solver wrapper.""" return solver(lambda y: F(y, c), t, y0, h) return step
def set_local_from_global(m, m_global_array): """ Sets the local values of the distrbuted object m to the values contained in the global array m_global_array. """ # This had to be changed, because the dolfin-adjoint constant.Constant is # different from the constant of dolfin. if type(m) == Constant: if m.rank() == 0: m.assign(m_global_array[0]) else: m.assign(Constant(tuple(m_global_array))) elif type(m) in (function.Function, functions.function.Function): begin, end = m.vector().local_range() m_a_local = m_global_array[begin:end] m.vector().set_local(m_a_local) m.vector().apply('insert') else: raise TypeError, 'Unknown parameter type'
u_n = interpolate(u_D, V) u_n.rename("Temperature", "") precice, precice_dt, initial_data = None, 0.0, None # Initialize the adapter according to the specific participant if problem is ProblemType.DIRICHLET: precice = Adapter(adapter_config_filename="precice-adapter-config-D.json") precice_dt = precice.initialize(coupling_boundary, read_function_space=V, write_object=f_N_function) elif problem is ProblemType.NEUMANN: precice = Adapter(adapter_config_filename="precice-adapter-config-N.json") precice_dt = precice.initialize(coupling_boundary, read_function_space=V_g, write_object=u_D_function) boundary_marker = False dt = Constant(0) dt.assign(np.min([fenics_dt, precice_dt])) # Define variational problem u = TrialFunction(V) v = TestFunction(V) f = Expression('beta + gamma*x[0]*x[0] - 2*gamma*t - 2*(1-gamma) - 2*alpha', degree=2, alpha=alpha, beta=beta, gamma=gamma, t=0) F = u * v / dt * dx + dot(grad(u), grad(v)) * dx - (u_n / dt + f) * v * dx bcs = [DirichletBC(V, u_D, remaining_boundary)] # Set boundary conditions at coupling interface once wrt to the coupling expression coupling_expression = precice.create_coupling_expression() if problem is ProblemType.DIRICHLET: # modify Dirichlet boundary condition on coupling interface
def solve_flem(model_space, physical_space, flow, u_n, mesh, V, bc, dt, num_steps, out_time, plot, statistics, name): """ Solve for landscape evolution This function does hte hard work. First the model domain is created. Then we loop through time and solve the diffusion equation to solve for landscape evolution. Output can be saved as vtk files at every "out_time" specified. Plots using fenics inbuilt library can be visualised at every "plot_time" This function returns a 1d numpy array of time, sediment flux and if statistics is turned on a 2d numpy array of the final wavelength of the landscape. :param model_space: list of domain variables, [lx,ly,res] :param physical_space: list of physical parameters, [kappa, c, nexp, alpha, U] :param flow: 0 = MFD node-to-node; 1 = MFD cell-to-cell; 2 = SD node-to-node; 3 = SD cell-to-cell :param u_n: elevation function :param mesh: dolphyn mesh :param V: fenics functionspace :param bc: boundary conditions :param dt: time step size in years :param num_steps: number of time steps :param out_time: time steps to output vtk files (0=none) :param plot: plot sediment flux (0=off,1=on) :param statistics: output statistics of landscape (0=off,1=on) :param name: directory name for output vtk files :return: sed_flux, time, wavelength """ # Domain dimensions lx = model_space[0] ly = model_space[1] # Physical parameters kappa = physical_space[0] # diffusion coefficient c = physical_space[1] # discharge transport coefficient nexp = physical_space[2] # discharge exponent alpha = physical_space[3] # precipitation rate De = c * pow(alpha * ly, nexp) / kappa uamp = physical_space[4] * ly / kappa # uplift dt = dt * kappa / (ly * ly) # time step size sed_flux = np.zeros(num_steps) # array to store sediment flux time = np.zeros(num_steps) # Define variational problem u = TrialFunction(V) v = TestFunction(V) f = Constant(uamp) # 0 = MFD node-to-node; 1 = MFD cell-to-cell; 2 = SD node-to-node; 3 = SD cell-to-cell if flow == 0: q_n = mfd_nodenode(mesh, V, u_n, De, nexp) if flow == 1: q_n = mfd_cellcell(mesh, V, u_n, De, nexp) if flow == 2: q_n = sd_nodenode(mesh, V, u_n, De, nexp) if flow == 3: q_n = sd_cellcell(mesh, V, u_n, De, nexp) F = u * v * dx + dt * q_n * dot(grad(u), grad(v)) * dx - (u_n + dt * f) * v * dx a, L = lhs(F), rhs(F) # Solution and sediment flux u = Function(V) q_s = Expression('u0 + displ - u1', u0=u_n, displ=Constant(uamp * dt), u1=u, degree=2) # Iterate t = 0 i = 0 for n in range(num_steps): # This needs to become an option! # Double rain fall # if n == 501: # alpha = 2 # De = c*pow(alpha*ly,nexp)/kappa # Update current time t += dt # Compute solution solve(a == L, u, bc) # Calculate sediment flux sed_flux[i] = assemble(q_s * dx(mesh)) time[i] = t i += 1 # Update previous solution u_n.assign(u) # Update flux # 0 = MFD node-to-node; 1 = MFD cell-to-cell; 2 = SD node-to-node; 3 = SD cell-to-cell if flow == 0: q = mfd_nodenode(mesh, V, u_n, De, nexp) if flow == 1: q = mfd_cellcell(mesh, V, u_n, De, nexp) if flow == 2: q = sd_nodenode(mesh, V, u_n, De, nexp) if flow == 3: q = sd_cellcell(mesh, V, u_n, De, nexp) q_n.assign(q) # Output solutions if out_time != 0: if np.mod(n, out_time) == 0: filename = '%s/u_solution_%d.pvd' % (name, n) vtkfile = File(filename) vtkfile << u filename = '%s/q_solution_%d.pvd' % (name, n) vtkfile = File(filename) vtkfile << q # Post processing if plot != 0: plt.plot(time * 1e-6 * ly * ly / kappa, sed_flux / dt * kappa, 'k', linewidth=2) plt.xlabel('Time (Myr)') plt.ylabel('Sediment Flux (m^2/yr)') sedname = '%s/sed_flux_%d.svg' % (name, model_space[2]) plt.savefig(sedname, format='svg') plt.clf() if out_time != 0: # Output last elevation filename = '%s/u_solution_%d_%d.pvd' % (name, model_space[2], n) vtkfile = File(filename) u.rename("elv", "elevation") vtkfile << u # Output last water flux filename = '%s/q_solution_%d_%d.pvd' % (name, model_space[2], n) vtkfile = File(filename) q.rename("flx", "flux") vtkfile << q # Calculate valley spacing from peak to peak in water flux tol = 0.001 # avoid hitting points outside the domain y = np.linspace(0 + tol, 1 - tol, 100) x = np.linspace(0.01, lx / ly - 0.01, 20) wavelength = np.zeros(len(x)) if statistics != 0: i = 0 for ix in x: points = [(ix, y_) for y_ in y] # 2D points q_line = np.array([q(point) for point in points]) indexes = peakutils.indexes(q_line, thres=0.05, min_dist=5) if len(indexes) > 1: wavelength[i] = sum(np.diff(y[indexes])) / (len(indexes) - 1) else: wavelength[i] = 0 i += 1 if plot != 0: plt.plot(y * 1e-3 * ly, q_line * kappa / ly, 'k', linewidth=2) plt.plot(y[indexes] * 1e-3 * ly, q_line[indexes] * kappa / ly, '+r') plt.xlabel('Distance (km)') plt.ylabel('Water Flux (m/yr)') watername = '%s/water_flux_spacing_%d.svg' % (name, model_space[2]) plt.savefig(watername, format='svg') plt.clf() return sed_flux, time, wavelength
u_ini = Expression("1", degree=1) bc = DirichletBC(V, u_ini, AllBoundary()) elif args.drain: u_ini = Expression("0", degree=1) bc = DirichletBC(V, u_ini, RightBoundary()) u_n = interpolate(u_ini, V) dt = precice.initialize(AllDomain(), read_function_space=V, write_object=u_n) volume_term = precice.create_coupling_expression() f = Function(V) dt_inv = Constant(1 / dt) diffusion_source = 1 diffusion_drain = 1 if args.source: F = dt_inv * (u - u_n) * v * dx - (f - u_ini) * v * dx + diffusion_source * inner(grad(u), grad(v)) * dx elif args.drain: F = dt_inv * (u - u_n) * v * dx - (f - u) * v * dx + diffusion_drain * inner(grad(u), grad(v)) * dx # Time-stepping u_np1 = Function(V) if args.source: u_n.rename("Source-Data", "") u_np1.rename("Source-Data", "") elif args.drain: u_n.rename("Drain-Data", "")
def solve_linear_pde( u_D_array, T, D=1, C1=0, num_r=100, min_r=0.001, tol=1e-14, degree=1, ): # disable logging set_log_active(False) num_t = len(u_D_array) dt = T / num_t # time step size mesh = IntervalMesh(num_r, min_r, 1) r = mesh.coordinates().flatten() r_args = np.argsort(r) V = FunctionSpace(mesh, "P", 1) # Define boundary conditions # Dirichlet condition at R def boundary_at_R(x, on_boundary): return on_boundary and near(x[0], 1, tol) D = Constant(D) u_D = Constant(u_D_array[0]) bc_at_R = DirichletBC(V, u_D, boundary_at_R) # Define initial values for free c c_0 = Expression("C1", C1=C1, degree=degree) c_n = interpolate(c_0, V) # Define variational problem c = TrialFunction(V) v = TestFunction(V) # define Constants r_squ = Expression("4*pi*pow(x[0],2)", degree=degree) F_tmp = (D * dt * inner(grad(c), grad(v)) * r_squ * dx + c * v * r_squ * dx - c_n * v * r_squ * dx) a, L = lhs(F_tmp), rhs(F_tmp) u = Function(V) data_c = np.zeros((num_t, len(r)), dtype=np.double) for n in range(num_t): u_D.assign(u_D_array[n]) # Compute solution solve(a == L, u, bc_at_R) data_c[n, :] = u.vector().vec().array c_n.assign(u) data_c = data_c[:, r_args[::-1]] r = r[r_args] return data_c, r
y_top = 0 y_bottom = y_top - .25 x_left = 0 x_right = x_left + 1 p0 = Point(x_left, y_bottom, 0) p1 = Point(x_right, y_top, 1) mesh = RectangleMesh(p0, p1, nx, ny) V = FunctionSpace(mesh, 'P', 1) alpha = 1 # m^2/s, https://en.wikipedia.org/wiki/Thermal_diffusivity k = 100 # kg * m / s^3 / K, https://en.wikipedia.org/wiki/Thermal_conductivity # Define boundary condition u_D = Constant('310') u_D_function = interpolate(u_D, V) # Define flux in x direction on coupling interface (grad(u_D) in normal direction) f_N = Constant('0') f_N_function = interpolate(f_N, V) coupling_boundary = TopBoundary() bottom_boundary = BottomBoundary() # Define initial value u_n = interpolate(u_D, V) u_n.rename("T", "") # Adapter definition and initialization precice = Adapter(adapter_config_filename="precice-adapter-config.json")
determines whether a node is on the coupling boundary """ return on_boundary and ((abs(x[1] - 1) < tol) or abs(abs(x[0]) - W / 2) < tol) # Geometry and material properties dim = 2 # number of dimensions H = 1 W = 0.1 rho = 3000 E = 4000000 nu = 0.3 mu = Constant(E / (2.0 * (1.0 + nu))) lambda_ = Constant(E * nu / ((1.0 + nu) * (1.0 - 2.0 * nu))) # create Mesh n_x_Direction = 4 n_y_Direction = 26 mesh = RectangleMesh(Point(-W / 2, 0), Point(W / 2, H), n_x_Direction, n_y_Direction) h = Constant(H / n_y_Direction) # create Function Space V = VectorFunctionSpace(mesh, 'P', 2) # BCs
def __init__(self, form_handler): """Initializes the regularization Parameters ---------- form_handler : cashocs._forms.ShapeFormHandler the corresponding shape form handler object """ self.form_handler = form_handler self.config = self.form_handler.config self.dx = fenics.Measure('dx', self.form_handler.mesh) self.ds = fenics.Measure('ds', self.form_handler.mesh) self.spatial_coordinate = fenics.SpatialCoordinate( self.form_handler.mesh) self.measure_hole = self.config.getboolean('Regularization', 'measure_hole', fallback=False) if self.measure_hole: self.x_start = self.config.getfloat('Regularization', 'x_start', fallback=0.0) self.x_end = self.config.getfloat('Regularization', 'x_end', fallback=1.0) if not self.x_end >= self.x_start: raise ConfigError('Regularization', 'x_end', 'x_end must not be smaller than x_start.') self.delta_x = self.x_end - self.x_start self.y_start = self.config.getfloat('Regularization', 'y_start', fallback=0.0) self.y_end = self.config.getfloat('Regularization', 'y_end', fallback=1.0) if not self.y_end >= self.y_start: raise ConfigError('Regularization', 'y_end', 'y_end must not be smaller than y_start.') self.delta_y = self.y_end - self.y_start self.z_start = self.config.getfloat('Regularization', 'z_start', fallback=0.0) self.z_end = self.config.getfloat('Regularization', 'z_end', fallback=1.0) if not self.z_end >= self.z_start: raise ConfigError('Regularization', 'z_end', 'z_end must not be smaller than z_start.') self.delta_z = self.z_end - self.z_start if self.form_handler.mesh.geometric_dimension() == 2: self.delta_z = 1.0 self.mu_volume = self.config.getfloat('Regularization', 'factor_volume', fallback=0.0) self.target_volume = self.config.getfloat('Regularization', 'target_volume', fallback=0.0) if self.config.getboolean('Regularization', 'use_initial_volume', fallback=False): if not self.measure_hole: self.target_volume = fenics.assemble(Constant(1) * self.dx) else: self.target_volume = self.delta_x * self.delta_y * self.delta_z - fenics.assemble( Constant(1.0) * self.dx) self.mu_surface = self.config.getfloat('Regularization', 'factor_surface', fallback=0.0) self.target_surface = self.config.getfloat('Regularization', 'target_surface', fallback=0.0) if self.config.getboolean('Regularization', 'use_initial_surface', fallback=False): self.target_surface = fenics.assemble(Constant(1) * self.ds) self.mu_barycenter = self.config.getfloat('Regularization', 'factor_barycenter', fallback=0.0) self.target_barycenter_list = json.loads( self.config.get('Regularization', 'target_barycenter', fallback='[0,0,0]')) if not type(self.target_barycenter_list) == list: raise ConfigError('Regularization', 'target_barycenter', 'This has to be a list.') if self.form_handler.mesh.geometric_dimension() == 2 and len( self.target_barycenter_list) == 2: self.target_barycenter_list.append(0.0) if self.config.getboolean('Regularization', 'use_initial_barycenter', fallback=False): self.target_barycenter_list = [0.0, 0.0, 0.0] if not self.measure_hole: volume = fenics.assemble(Constant(1) * self.dx) self.target_barycenter_list[0] = fenics.assemble( self.spatial_coordinate[0] * self.dx) / volume self.target_barycenter_list[1] = fenics.assemble( self.spatial_coordinate[1] * self.dx) / volume if self.form_handler.mesh.geometric_dimension() == 3: self.target_barycenter_list[2] = fenics.assemble( self.spatial_coordinate[2] * self.dx) / volume else: self.target_barycenter_list[2] = 0.0 else: volume = self.delta_x * self.delta_y * self.delta_z - fenics.assemble( Constant(1) * self.dx) self.target_barycenter_list[0] = ( 0.5 * (pow(self.x_end, 2) - pow(self.x_start, 2)) * self.delta_y * self.delta_z - fenics.assemble( self.spatial_coordinate[0] * self.dx)) / volume self.target_barycenter_list[1] = ( 0.5 * (pow(self.y_end, 2) - pow(self.y_start, 2)) * self.delta_x * self.delta_z - fenics.assemble( self.spatial_coordinate[1] * self.dx)) / volume if self.form_handler.mesh.geometric_dimension() == 3: self.target_barycenter_list[2] = ( 0.5 * (pow(self.z_end, 2) - pow(self.z_start, 2)) * self.delta_x * self.delta_y - fenics.assemble( self.spatial_coordinate[2] * self.dx)) / volume else: self.target_barycenter_list[2] = 0.0 if not (self.mu_volume >= 0.0 and self.mu_surface >= 0.0 and self.mu_barycenter >= 0.0): raise ConfigError( 'Regularization', 'mu_volume, mu_surface, or mu_barycenter', 'All regularization constants have to be nonnegative.') if self.mu_volume > 0.0 or self.mu_surface > 0.0 or self.mu_barycenter > 0.0: self.has_regularization = True else: self.has_regularization = False # self.relative_scaling = self.config.getboolean('Regularization', 'relative_scaling') # if self.relative_scaling and self.has_regularization: # self.scale_weights() self.current_volume = fenics.Expression('val', degree=0, val=1.0) self.current_surface = fenics.Expression('val', degree=0, val=1.0) self.current_barycenter_x = fenics.Expression('val', degree=0, val=0.0) self.current_barycenter_y = fenics.Expression('val', degree=0, val=0.0) self.current_barycenter_z = fenics.Expression('val', degree=0, val=0.0)
def compute_shape_derivative(self): """Computes the part of the shape derivative that comes from the regularization Returns ------- ufl.form.Form The weak form of the shape derivative coming from the regularization """ V = self.form_handler.test_vector_field if self.has_regularization: n = fenics.FacetNormal(self.form_handler.mesh) I = fenics.Identity(self.form_handler.mesh.geometric_dimension()) self.shape_form = Constant(self.mu_surface) * ( self.current_surface - Constant(self.target_surface)) * t_div( V, n) * self.ds if not self.measure_hole: self.shape_form += Constant(self.mu_volume) * ( self.current_volume - Constant(self.target_volume)) * div(V) * self.dx self.shape_form += Constant(self.mu_barycenter)*(self.current_barycenter_x - Constant(self.target_barycenter_list[0]))\ *(self.current_barycenter_x/self.current_volume*div(V) + 1/self.current_volume*(V[0] + self.spatial_coordinate[0]*div(V)))*self.dx \ + Constant(self.mu_barycenter)*(self.current_barycenter_y - Constant(self.target_barycenter_list[1]))\ *(self.current_barycenter_y/self.current_volume*div(V) + 1/self.current_volume*(V[1] + self.spatial_coordinate[1]*div(V)))*self.dx if self.form_handler.mesh.geometric_dimension() == 3: self.shape_form += Constant(self.mu_barycenter)*(self.current_barycenter_z - Constant(self.target_barycenter_list[2]))\ *(self.current_barycenter_z/self.current_volume*div(V) + 1/self.current_volume*(V[2] + self.spatial_coordinate[2]*div(V)))*self.dx else: self.shape_form -= Constant(self.mu_volume) * ( self.current_volume - Constant(self.target_volume)) * div(V) * self.dx self.shape_form += Constant(self.mu_barycenter)*(self.current_barycenter_x - Constant(self.target_barycenter_list[0]))\ *(self.current_barycenter_x/self.current_volume*div(V) - 1/self.current_volume*(V[0] + self.spatial_coordinate[0]*div(V)))*self.dx \ + Constant(self.mu_barycenter)*(self.current_barycenter_y - Constant(self.target_barycenter_list[1]))\ *(self.current_barycenter_y/self.current_volume*div(V) - 1/self.current_volume*(V[1] + self.spatial_coordinate[1]*div(V)))*self.dx if self.form_handler.mesh.geometric_dimension() == 3: self.shape_form += Constant(self.mu_barycenter)*(self.current_barycenter_z - Constant(self.target_barycenter_list[2]))\ *(self.current_barycenter_z/self.current_volume*div(V) - 1/self.current_volume*(V[2] + self.spatial_coordinate[2]*div(V)))*self.dx return self.shape_form else: dim = self.form_handler.mesh.geometric_dimension() return inner(fenics.Constant([0] * dim), V) * self.dx
def __init__( self, nu=Constant(0.001), beta=Constant((5.0, 0.0)), zeta=Constant(1000.0), delta=Constant(0.01), gamma=Constant(1000.0), time_step=0.00125, global_mesh_size=800, local_mesh_size_fluid=1, local_mesh_size_solid=1, number_elements_horizontal=80, number_elements_vertical=20, tau=Constant(0.7), absolute_tolerance_relaxation=1.0e-12, relative_tolerance_relaxation=1.0e-6, max_iterations_relaxation=50, epsilon=1.0e-6, absolute_tolerance_newton=1.0e-12, relative_tolerance_newton=1.0e-6, max_iterations_newton=15, tolerance_gmres=1.0e-12, max_iterations_gmres=10, relaxation=False, shooting=True, goal_functional_fluid=True, goal_functional_solid=False, ): # Define problem parameters self.NU = nu self.BETA = beta self.ZETA = zeta self.DELTA = delta self.GAMMA = gamma # Define time step on the coarsest level self.TIME_STEP = time_step # Define number of macro time steps on the coarsest level self.GLOBAL_MESH_SIZE = global_mesh_size # Define number of micro time-steps for fluid self.LOCAL_MESH_SIZE_FLUID = local_mesh_size_fluid # Define number of micro time-steps for solid self.LOCAL_MESH_SIZE_SOLID = local_mesh_size_solid # Define number of mesh cells self.NUMBER_ELEMENTS_HORIZONTAL = number_elements_horizontal self.NUMBER_ELEMENTS_VERTICAL = number_elements_vertical # Define relaxation parameters self.TAU = tau self.ABSOLUTE_TOLERANCE_RELAXATION = absolute_tolerance_relaxation self.RELATIVE_TOLERANCE_RELAXATION = relative_tolerance_relaxation self.MAX_ITERATIONS_RELAXATION = max_iterations_relaxation # Define parameters for Newton's method self.EPSILON = epsilon self.ABSOLUTE_TOLERANCE_NEWTON = absolute_tolerance_newton self.RELATIVE_TOLERANCE_NEWTON = relative_tolerance_newton self.MAX_ITERATIONS_NEWTON = max_iterations_newton # Define parameters for GMRES method self.TOLERANCE_GMRES = tolerance_gmres self.MAX_ITERATIONS_GMRES = max_iterations_gmres # Choose decoupling method self.RELAXATION = relaxation self.SHOOTING = shooting # Choose goal functional self.GOAL_FUNCTIONAL_FLUID = goal_functional_fluid self.GOAL_FUNCTIONAL_SOLID = goal_functional_solid
boundaries = FacetFunction("size_t", mesh) boundaries.set_all(0) BarLeftSide.mark(boundaries, 1) # BCs bc1 = DirichletBC(VV.sub(0), ((0, 0)), boundaries, 1) bc2 = DirichletBC(VV.sub(1), ((0, 0)), boundaries, 1) bcs = [bc1, bc2] # Parameters: rho_s = 1.0e3 mu_s = 0.5e6 nu_s = 0.4 E_1 = 1.4e6 lambda_ = nu_s * 2. * mu_s / (1. - 2. * nu_s) f = Constant((0, -2.)) beta = Constant(0.25) probe = Probes(coord, V) def action(wd_, t): time.append(t) probe(wd_["n"].sub(1)) # Set up different numerical schemes # TODO: Add options to chose solver and change solver parameters common = { "space": "mixedspace", "E": None, # Full implicte, not energy conservative
y_bottom = y_top - .25 x_left = 0 x_right = x_left + 1 p0 = Point(x_left, y_bottom, 0) p1 = Point(x_right, y_top, 1) mesh = RectangleMesh(p0, p1, nx, ny) V = FunctionSpace(mesh, 'P', 1) V_g = VectorFunctionSpace(mesh, 'P', 1) alpha = 1 # m^2/s, https://en.wikipedia.org/wiki/Thermal_diffusivity k = 100 # kg * m / s^3 / K, https://en.wikipedia.org/wiki/Thermal_conductivity # Define boundary condition u_D = Constant('310') u_D_function = interpolate(u_D, V) # We will only exchange flux in y direction on coupling interface. No initialization necessary. V_flux_y = V_g.sub(1) coupling_boundary = TopBoundary() bottom_boundary = BottomBoundary() # Define initial value u_n = interpolate(u_D, V) u_n.rename("T", "") # Adapter definition and initialization precice = Adapter(adapter_config_filename="precice-adapter-config.json") precice_dt = precice.initialize(coupling_boundary,
interpolation_strategy=interpolation_strategy) if problem is ProblemType.DIRICHLET: precice_dt = precice.initialize(coupling_subdomain=coupling_boundary, mesh=mesh, read_field=u_D_function, write_field=f_N_function, u_n=u_n) elif problem is ProblemType.NEUMANN: precice_dt = precice.initialize(coupling_subdomain=coupling_boundary, mesh=mesh, read_field=f_N_function, write_field=u_D_function, u_n=u_n) dt = Constant(0) dt.assign(np.min([fenics_dt, precice_dt])) # Define variational problem u = TrialFunction(V) v = TestFunction(V) f = Expression( 'beta + gamma * x[0] * x[0] - 2 * gamma * t - 2 * (1-gamma) - 2 * alpha', degree=2, alpha=alpha, beta=beta, gamma=gamma, t=0) F = u * v / dt * dx + dot(grad(u), grad(v)) * dx - (u_n / dt + f) * v * dx if problem is ProblemType.DIRICHLET:
determines whether a node is on the coupling boundary """ return on_boundary and (not (abs(x[1] < tol)) or abs(abs(x[0]) - W / 2) < tol) # Dimensionless Geometry and material properties d = 2 #number of dimensions H = 1 W = 0.1 rho = 1000 E = 100000.0 nu = 0.3 mu = Constant(E / (2.0 * (1.0 + nu))) lambda_ = Constant(E * nu / ((1.0 + nu) * (1.0 - 2.0 * nu))) # create Mesh n_x_Direction = 5 n_y_Direction = 25 mesh = RectangleMesh(Point(-W / 2, 0), Point(W / 2, H), n_x_Direction, n_y_Direction) #create Function Space V = VectorFunctionSpace(mesh, 'P', 2) #BCs tol = 1E-14