def computeVelocityField(mesh): Xh = dl.VectorFunctionSpace(mesh,'Lagrange', 2) Wh = dl.FunctionSpace(mesh, 'Lagrange', 1) if dlversion() <= (1,6,0): XW = dl.MixedFunctionSpace([Xh, Wh]) else: mixed_element = dl.MixedElement([Xh.ufl_element(), Wh.ufl_element()]) XW = dl.FunctionSpace(mesh, mixed_element) Re = 1e2 g = dl.Expression(('0.0','(x[0] < 1e-14) - (x[0] > 1 - 1e-14)'), element=Xh.ufl_element()) bc1 = dl.DirichletBC(XW.sub(0), g, v_boundary) bc2 = dl.DirichletBC(XW.sub(1), dl.Constant(0), q_boundary, 'pointwise') bcs = [bc1, bc2] vq = dl.Function(XW) (v,q) = dl.split(vq) (v_test, q_test) = dl.TestFunctions (XW) def strain(v): return dl.sym(dl.nabla_grad(v)) F = ( (2./Re)*dl.inner(strain(v),strain(v_test))+ dl.inner (dl.nabla_grad(v)*v, v_test) - (q * dl.div(v_test)) + ( dl.div(v) * q_test) ) * dl.dx dl.solve(F == 0, vq, bcs, solver_parameters={"newton_solver": {"relative_tolerance":1e-4, "maximum_iterations":100, "linear_solver":"default"}}) return v
def rhs(states, time, parameters, dy=None): """ Compute right hand side """ # Imports import ufl import dolfin # Assign states assert(isinstance(states, dolfin.Function)) assert(states.function_space().depth() == 1) assert(states.function_space().num_sub_spaces() == 2) s, v = dolfin.split(states) # Assign parameters a, b, c_1, c_2, c_3, v_peak, v_rest = parameters v_amp = v_peak - v_rest v_th = v_rest + a*v_amp I = (v - v_rest)*(v - v_th)*(v_peak - v)*c_1/(v_amp*v_amp) - (v -\ v_rest)*c_2*s/v_amp # Init test function _v = dolfin.TestFunction(states.function_space()) # Derivative for state s dy = ((-c_3*s + v - v_rest)*b)*_v[0] # Derivative for state v dy += (I)*_v[1] dya = dolfin.assemble(dy*dolfin.dx) # Return dy return dy
def solve_system(self,rhs,factor,u0,t): """ Dolfin's linear solver for (M-dtA)u = rhs Args: rhs: right-hand side for the nonlinear system factor: abbrev. for the node-to-node stepsize (or any other factor required) u0: initial guess for the iterative solver (not used here so far) Returns: solution as mesh """ sol = fenics_mesh(self.V) # self.g.t = t self.w.assign(sol.values) q1,q2 = df.TestFunctions(self.V) w1,w2 = df.split(self.w) r1,r2 = df.split(rhs.values) F1 = w1*q1*df.dx - factor*self.F1 - r1*q1*df.dx F2 = w2*q2*df.dx - factor*self.F2 - r2*q2*df.dx F = F1+F2 du = df.TrialFunction(self.V) J = df.derivative(F, self.w, du) problem = df.NonlinearVariationalProblem(F, self.w, [], J) solver = df.NonlinearVariationalSolver(problem) prm = solver.parameters prm['newton_solver']['absolute_tolerance'] = 1E-09 prm['newton_solver']['relative_tolerance'] = 1E-08 prm['newton_solver']['maximum_iterations'] = 100 prm['newton_solver']['relaxation_parameter'] = 1.0 # df.set_log_level(df.PROGRESS) solver.solve() sol.values.assign(self.w) return sol
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
def solve(self, it=0): if self.group_GS: self.solve_group_GS(it) else: super(EllipticSNFluxModule, self).solve(it) self.slns_mg = split(self.sln) i,p,q,k1,k2 = ufl.indices(5) sol_timer = Timer("-- Complete solution") aux_timer = Timer("---- SOL: Computing angular flux + adjoint") # TODO: Move to Discretization V11 = FunctionSpace(self.DD.mesh, "CG", self.DD.parameters["p"]) for gto in range(self.DD.G): self.PD.get_xs('D', self.D, gto) form = self.D * ufl.diag_vector(ufl.as_matrix(self.DD.ordinates_matrix[i,p]*self.slns_mg[gto][q].dx(i), (p,q))) for gfrom in range(self.DD.G): pres_Ss = False # TODO: Enlarge self.S and self.C to (L+1)^2 (or 1./2.*(L+1)*(L+2) in 2D) to accomodate for anisotropic # scattering (lines below using CC, SS are correct only for L = 0, when the following inner loop runs only # once. for l in range(self.L+1): for m in range(-l, l+1): if self.DD.angular_quad.get_D() == 2 and divmod(l+m, 2)[1] == 0: continue pres_Ss |= self.PD.get_xs('Ss', self.S[l], gto, gfrom, l) self.PD.get_xs('C', self.C[l], gto, gfrom, l) if pres_Ss: Cd = ufl.diag(self.C) CC = self.tensors.Y[p,k1] * Cd[k1,k2] * self.tensors.Qt[k2,q,i] form += ufl.as_vector(CC[p,q,i] * self.slns_mg[gfrom][q].dx(i), p) # project(form, self.DD.Vpsi1, function=self.aux_slng, preconditioner_type="petsc_amg") # FASTER, but requires form compilation for each dir.: for pp in range(self.DD.M): assign(self.aux_slng.sub(pp), project(form[pp], V11, preconditioner_type="petsc_amg")) self.psi_mg[gto].assign(self.slns_mg[gto] + self.aux_slng) self.adj_psi_mg[gto].assign(self.slns_mg[gto] - self.aux_slng)
def numerical_test( user_parameters, ell=0.05, nu=0., ): time_data = [] time_data_pd = [] spacetime = [] lmbda_min_prev = 1e-6 bifurcated = False bifurcation_loads = [] save_current_bifurcation = False bifurc_i = 0 bifurcation_loads = [] # Create mesh and define function space geometry_parameters = {'Lx': 1., 'n': 5} # Define Dirichlet boundaries outdir = '../test/output/test_1dcheck' Path(outdir).mkdir(parents=True, exist_ok=True) with open('../parameters/form_compiler.yml') as f: form_compiler_parameters = yaml.load(f, Loader=yaml.FullLoader) with open('../parameters/solvers_default.yml') as f: solver_parameters = yaml.load(f, Loader=yaml.FullLoader) with open('../parameters/model1d.yaml') as f: material_parameters = yaml.load(f, Loader=yaml.FullLoader)['material'] with open('../parameters/loading.yaml') as f: loading_parameters = yaml.load(f, Loader=yaml.FullLoader)['loading'] with open('../parameters/stability.yaml') as f: stability_parameters = yaml.load(f, Loader=yaml.FullLoader)['stability'] Path(outdir).mkdir(parents=True, exist_ok=True) print('Outdir is: '+outdir) default_parameters = { 'code': {**code_parameters}, 'compiler': {**form_compiler_parameters}, 'geometry': {**geometry_parameters}, 'loading': {**loading_parameters}, 'material': {**material_parameters}, 'solver':{**solver_parameters}, 'stability': {**stability_parameters}, } default_parameters.update(user_parameters) # FIXME: Not nice parameters = default_parameters with open(os.path.join(outdir, 'parameters.yaml'), "w") as f: yaml.dump(parameters, f, default_flow_style=False) Lx = parameters['geometry']['Lx']; # Ly = parameters['geometry']['Ly'] ell = parameters['material']['ell'] # comm = MPI.comm_world # geom = mshr.Rectangle(dolfin.Point(0, -Ly/2.), dolfin.Point(Lx, Ly/2.)) # import pdb; pdb.set_trace() # resolution = max(geometry_parameters['n'] * Lx / ell, 1/(Ly*10)) # resolution = max(geometry_parameters['n'] * Lx / ell, 5/(Ly*10)) resolution = 50 mesh = dolfin.IntervalMesh(3, 0, Lx) # mesh = dolfin.IntervalMesh(int(float(geometry_parameters['n'] * Lx / ell)), 0, Lx) meshf = dolfin.File(os.path.join(outdir, "mesh.xml")) meshf << mesh plot(mesh) plt.savefig(os.path.join(outdir, "mesh.pdf"), bbox_inches='tight') savelag = 1 left = dolfin.CompiledSubDomain("near(x[0], 0)", Lx=Lx) right = dolfin.CompiledSubDomain("near(x[0], Lx)", Lx=Lx) # left_bottom_pt = dolfin.CompiledSubDomain("near(x[0],0) && near(x[1],-Ly/2.)", Lx=Lx, Ly=Ly) mf = dolfin.MeshFunction("size_t", mesh, 1, 0) right.mark(mf, 1) left.mark(mf, 2) ds = dolfin.Measure("ds", subdomain_data=mf) dx = dolfin.Measure("dx", metadata=form_compiler_parameters, domain=mesh) # Function Spaces V_u = dolfin.FunctionSpace(mesh, "CG", 1) V_alpha = dolfin.FunctionSpace(mesh, "CG", 1) u = dolfin.Function(V_u, name="Total displacement") alpha = Function(V_alpha) dalpha = TrialFunction(V_alpha) alpha_old = dolfin.Function(V_alpha) alpha_bif = dolfin.Function(V_alpha) alpha_bif_old = dolfin.Function(V_alpha) state = {'u': u, 'alpha': alpha} Z = dolfin.FunctionSpace(mesh, dolfin.MixedElement([u.ufl_element(),alpha.ufl_element()])) z = dolfin.Function(Z) z2 = dolfin.Function(Z) dz = dolfin.TestFunction(Z) v, beta = dolfin.split(z) ut = dolfin.Expression("t", t=0.0, degree=0) bcs_u = [dolfin.DirichletBC(V_u, dolfin.Constant(0), left), dolfin.DirichletBC(V_u, ut, right), # dolfin.DirichletBC(V_u, (0, 0), left_bottom_pt, method="pointwise") ] # bcs_alpha_l = DirichletBC(V_alpha, Constant(0.0), left) # bcs_alpha_r = DirichletBC(V_alpha, Constant(0.0), right) # bcs_alpha =[bcs_alpha_l, bcs_alpha_r] bcs_alpha = [] bcs = {"damage": bcs_alpha, "elastic": bcs_u} # import pdb; pdb.set_trace() ell = parameters['material']['ell'] # Problem definition # Problem definition k_res = parameters['material']['k_res'] a = (1 - alpha) ** 2. + k_res w_1 = parameters['material']['sigma_D0'] ** 2 / parameters['material']['E'] w = w_1 * alpha eps = u.dx(0) # lmbda0 = parameters['material']['E'] * parameters['material']['nu'] /(1. - parameters['material']['nu'])**2. mu0 = parameters['material']['E']/ 2. Wu = mu0 * inner(eps, eps) energy = a * Wu * dx + w_1 *( alpha + \ parameters['material']['ell']** 2.* alpha.dx(0)**2.)*dx eps_ = variable(eps) sigma = diff(a * Wu, eps_) file_out = dolfin.XDMFFile(os.path.join(outdir, "output.xdmf")) file_out.parameters["functions_share_mesh"] = True file_out.parameters["flush_output"] = True file_postproc = dolfin.XDMFFile(os.path.join(outdir, "output_postproc.xdmf")) file_postproc.parameters["functions_share_mesh"] = True file_postproc.parameters["flush_output"] = True file_eig = dolfin.XDMFFile(os.path.join(outdir, "modes.xdmf")) file_eig.parameters["functions_share_mesh"] = True file_eig.parameters["flush_output"] = True file_bif = dolfin.XDMFFile(os.path.join(outdir, "bifurcation.xdmf")) file_bif.parameters["functions_share_mesh"] = True file_bif.parameters["flush_output"] = True file_bif_postproc = dolfin.XDMFFile(os.path.join(outdir, "bifurcation_postproc.xdmf")) file_bif_postproc.parameters["functions_share_mesh"] = True file_bif_postproc.parameters["flush_output"] = True solver = EquilibriumAM(energy, state, bcs, parameters=parameters['solver']) stability = StabilitySolver(energy, state, bcs, parameters = parameters['stability']) linesearch = LineSearch(energy, state) # load_steps = np.linspace(parameters['loading']['load_min'], # parameters['loading']['load_max'], # parameters['loading']['n_steps']) load_steps = [0.0, 1.0, 1.1] xs = np.linspace(0, parameters['geometry']['Lx'], 50) log(LogLevel.INFO, '====================== EVO ==========================') log(LogLevel.INFO, '{}'.format(parameters)) for it, load in enumerate(load_steps): alpha_old.assign(alpha) log(LogLevel.CRITICAL, '====================== STEPPING ==========================') log(LogLevel.CRITICAL, 'CRITICAL: Solving load t = {:.2f}'.format(load)) ut.t = load (time_data_i, am_iter) = solver.solve() # Second order stability conditions (stable, negev) = stability.solve(solver.damage.problem.lb) log(LogLevel.CRITICAL, 'Current state is{}stable'.format(' ' if stable else ' un')) # we postpone the update after the stability check solver.update() # if stable: # solver.update() # else: # perturbation_v = stability.perturbation_v # perturbation_beta = stability.perturbation_beta # import pdb; pdb.set_trace() # h_opt, (hmin, hmax), energy_perturbations = linesearch.search( # {'u': u, 'alpha':alpha, 'alpha_old':alpha_old}, # perturbation_v, perturbation_beta) # if h_opt != 0: # save_current_bifurcation = True # alpha_bif.assign(alpha) # alpha_bif_old.assign(alpha_old) # # admissible # uval = u.vector()[:] + h_opt * perturbation_v.vector()[:] # aval = alpha.vector()[:] + h_opt * perturbation_beta.vector()[:] # u.vector()[:] = uval # alpha.vector()[:] = aval # u.vector().vec().ghostUpdate() # alpha.vector().vec().ghostUpdate() # # import pdb; pdb.set_trace() # (time_data_i, am_iter) = solver.solve() # (stable, negev) = stability.solve(alpha_old) # ColorPrint.print_pass(' Continuation iteration {}, current state is{}stable'.format(iteration, ' ' if stable else ' un')) # iteration += 1 # else: # # warn # ColorPrint.print_warn('WARNING: Found zero increment, we are stuck in the matrix') # log(LogLevel.WARNING, 'WARNING: Continuing load program') # break mineig = stability.mineig if hasattr(stability, 'mineig') else 0.0 Deltav = (mineig-lmbda_min_prev) if hasattr(stability, 'eigs') else 0 if (mineig + Deltav)*(lmbda_min_prev+dolfin.DOLFIN_EPS) < 0 and not bifurcated: bifurcated = True # save 3 bif modes log(LogLevel.CRITICAL, 'About to bifurcate load {} step {}'.format(load, it)) bifurcation_loads.append(load) modes = np.where(stability.eigs < 0)[0] with dolfin.XDMFFile(os.path.join(outdir, "postproc.xdmf")) as file: leneigs = len(modes) maxmodes = min(3, leneigs) for n in range(maxmodes): mode = dolfin.project(stability.linsearch[n]['beta_n'], V_alpha) modename = 'beta-%d'%n print(modename) file.write_checkpoint(mode, modename, 0, append=True) bifurc_i += 1 lmbda_min_prev = mineig if hasattr(stability, 'mineig') else 0. time_data_i["load"] = load time_data_i["alpha_max"] = max(alpha.vector()[:]) time_data_i["elastic_energy"] = dolfin.assemble( 1./2.* material_parameters['E']*a*eps**2. *dx) time_data_i["dissipated_energy"] = dolfin.assemble( # e1 = dolfin.Constant([1, 0]) (w + w_1 * material_parameters['ell'] ** 2. * alpha.dx(0)**2.)*dx) time_data_i["stable"] = stability.stable time_data_i["# neg ev"] = stability.negev time_data_i["eigs"] = stability.eigs if hasattr(stability, 'eigs') else np.inf # snn = dolfin.dot(dolfin.dot(sigma, e1), e1) time_data_i["sigma"] = dolfin.assemble(a*mu0*eps*ds(1)) log(LogLevel.INFO, "Load/time step {:.4g}: iteration: {:3d}, err_alpha={:.4g}".format( time_data_i["load"], time_data_i["iterations"][0], time_data_i["alpha_error"][0])) time_data.append(time_data_i) time_data_pd = pd.DataFrame(time_data) if np.mod(it, savelag) == 0: with file_out as f: f.write(alpha, load) f.write(u, load) with file_postproc as f: f.write_checkpoint(alpha, "alpha-{}".format(it), 0, append = True) log(LogLevel.PROGRESS, 'PROGRESS: written step {}'.format(it)) if save_current_bifurcation == True: with file_eig as f: _v = dolfin.project(dolfin.Constant(h_opt)*perturbation_v, V_u) _beta = dolfin.project(dolfin.Constant(h_opt)*perturbation_beta, V_alpha) _v.rename('perturbation displacement', 'perturbation displacement') _beta.rename('perturbation damage', 'perturbation damage') # import pdb; pdb.set_trace() f.write(_v, load) f.write(_beta, load) f.write_checkpoint(_v, 'perturbation_v', 0, append=True) f.write_checkpoint(_beta, 'perturbation_beta', 0, append=True) time_data_pd.to_json(os.path.join(outdir, "time_data.json")) spacetime.append([alpha(x) for x in xs]) if save_current_bifurcation: # modes = np.where(stability.eigs < 0)[0] time_data_i['h_opt'] = h_opt time_data_i['max_h'] = hmax time_data_i['min_h'] = hmin with file_bif_postproc as file: # leneigs = len(modes) # maxmodes = min(3, leneigs) beta0v = dolfin.project(stability.perturbation_beta, V_alpha) log(LogLevel.DEBUG, 'DEBUG: irrev {}'.format(alpha.vector()-alpha_old.vector())) file.write_checkpoint(beta0v, 'beta0', 0, append = True) file.write_checkpoint(alpha_bif_old, 'alpha-old', 0, append=True) file.write_checkpoint(alpha_bif, 'alpha-bif', 0, append=True) file.write_checkpoint(alpha, 'alpha', 0, append=True) np.save(os.path.join(outdir, 'energy_perturbations'), energy_perturbations, allow_pickle=True, fix_imports=True) with file_eig as file: _v = dolfin.project(dolfin.Constant(h_opt)*perturbation_v, V_u) _beta = dolfin.project(dolfin.Constant(h_opt)*perturbation_beta, V_alpha) _v.rename('perturbation displacement', 'perturbation displacement') _beta.rename('perturbation damage', 'perturbation damage') # import pdb; pdb.set_trace() f.write(_v, load) f.write(_beta, load) _spacetime = pd.DataFrame(spacetime) spacetime = _spacetime.fillna(0) mat = np.matrix(spacetime) plt.imshow(mat, cmap = 'Greys', vmin = 0., vmax = 1., aspect=.1) plt.colorbar() def format_space(x, pos, xresol = 100): return '$%1.1f$'%((-x+xresol/2)/xresol) def format_time(t, pos, xresol = 100): return '$%1.1f$'%((t-parameters['loading']['load_min'])/parameters['loading']['n_steps']*parameters['loading']['load_max']) from matplotlib.ticker import FuncFormatter, MaxNLocator ax = plt.gca() ax.yaxis.set_major_formatter(FuncFormatter(format_space)) ax.xaxis.set_major_formatter(FuncFormatter(format_time)) plt.xlabel('$x$') plt.ylabel('$t$') plt.savefig(os.path.join(outdir, "spacetime.pdf".format(load)), bbox_inches="tight") spacetime.to_json(os.path.join(outdir + "/spacetime.json")) from matplotlib.ticker import FuncFormatter, MaxNLocator plot(alpha) plt.savefig(os.path.join(outdir, 'alpha.pdf')) log(LogLevel.INFO, "Saved figure: {}".format(os.path.join(outdir, 'alpha.pdf'))) xs = np.linspace(0, Lx, 100) profile = np.array([alpha(x) for x in xs]) plt.figure() plt.plot(xs, profile, marker='o') plt.plot(xs, np.array([u(x) for x in xs])) # plt.ylim(0., 1.) plt.savefig(os.path.join(outdir, 'profile.pdf')) return time_data_pd, outdir
def RunJob(Tb, mu_value, path): runtimeInit = clock() tfile = File(path + '/t6t.pvd') mufile = File(path + "/mu.pvd") ufile = File(path + '/velocity.pvd') gradpfile = File(path + '/gradp.pvd') pfile = File(path + '/pstar.pvd') parameters = open(path + '/parameters', 'w', 0) vmeltfile = File(path + '/vmelt.pvd') rhofile = File(path + '/rhosolid.pvd') for name in dir(): ev = str(eval(name)) if name[0] != '_' and ev[0] != '<': parameters.write(name + ' = ' + ev + '\n') temp_values = [27. + 273, Tb + 273, 1300. + 273, 1305. + 273] dTemp = temp_values[3] - temp_values[0] temp_values = [x / dTemp for x in temp_values] # non dimensionalising temp mu_a = mu_value # this was taken from the blankenbach paper, can change.. Ep = b / dTemp mu_bot = exp(-Ep * (temp_values[3] * dTemp - 1573) + cc) * mu_a Ra = rho_0 * alpha * g * dTemp * h**3 / (kappa_0 * mu_a) w0 = rho_0 * alpha * g * dTemp * h**2 / mu_a tau = h / w0 p0 = mu_a * w0 / h print(mu_a, mu_bot, Ra, w0, p0) vslipx = 1.6e-09 / w0 vslip = Constant((vslipx, 0.0)) # nondimensional noslip = Constant((0.0, 0.0)) dt = 3.E11 / tau tEnd = 3.E13 / tau # non-dimensionalising times class PeriodicBoundary(SubDomain): def inside(self, x, on_boundary): return left(x, on_boundary) def map(self, x, y): y[0] = x[0] - MeshWidth y[1] = x[1] pbc = PeriodicBoundary() class TempExp(Expression): def eval(self, value, x): if x[1] >= LAB(x): value[0] = temp_values[0] + (temp_values[1] - temp_values[0]) * (MeshHeight - x[1]) / (MeshHeight - LAB(x)) else: value[0] = temp_values[3] - (temp_values[3] - temp_values[2]) * (x[1]) / (LAB(x)) class FluidTemp(Expression): def eval(self, value, x): if value[0] < 1295: value[0] = 1295 mesh = RectangleMesh(Point(0.0, 0.0), Point(MeshWidth, MeshHeight), nx, ny) Svel = VectorFunctionSpace(mesh, 'CG', 2, constrained_domain=pbc) Spre = FunctionSpace(mesh, 'CG', 1, constrained_domain=pbc) Stemp = FunctionSpace(mesh, 'CG', 1, constrained_domain=pbc) Smu = FunctionSpace(mesh, 'CG', 1, constrained_domain=pbc) Sgradp = VectorFunctionSpace(mesh, 'CG', 2, constrained_domain=pbc) Srho = FunctionSpace(mesh, 'CG', 1, constrained_domain=pbc) S0 = MixedFunctionSpace([Svel, Spre, Stemp]) u = Function(S0) v, p, T = split(u) v_t, p_t, T_t = TestFunctions(S0) T0 = interpolate(TempExp(), Stemp) muExp = Expression('exp(-Ep * (T_val * dTemp - 1573) + cc * x[2] / meshHeight)', Smu.ufl_element(), Ep=Ep, dTemp=dTemp, cc=cc, meshHeight=MeshHeight, T_val=T0) mu = interpolate(muExp, Smu) rhosolid = Function(Srho) deltarho = Function(Srho) v0 = Function(Svel) vmelt = Function(Svel) v_theta = (1. - theta)*v0 + theta*v T_theta = (1. - theta)*T + theta*T0 r_v = (inner(sym(grad(v_t)), 2.*mu*sym(grad(v))) \ - div(v_t)*p \ - T*v_t[1] )*dx r_p = p_t*div(v)*dx r_T = (T_t*((T - T0) \ + dt*inner(v_theta, grad(T_theta))) \ + (dt/Ra)*inner(grad(T_t), grad(T_theta)) )*dx # + k_s*(Tf-T_theta)*dt Tf = T0.interpolate(FluidTemp()) # Tf = T0.interpolate(Expression('value[0] >= 1295.0 ? value[0] : 1295.0')) # Tf.interpolate(Expression('value[0] >= 1295 ? value[0] : 1295')) # project(Expression('value[0] >= 1295 ? value[0] : 1295'), Tf) # Alex, a question for you: # can you see if there is a way to set Tf = T in regions where T >=1295 celsius # # 1295 celsius is my arbitrary choice for the LAB isotherm. In regions # where T < 1295 C, set Tf to be some constant for now, such as 1295 C. # Once we do this, then we can add in a term like that last line above where # it will only be non-zero when the solid temperature, T, is cooler than 1295 # can you do this? After this is done, we will then worry about a calculation # where we solve for Tf as a function of time in the regions cooler than 1295 C # Makes sense? If not, we can skype soon -- email me with questions # 3/19/16 r = r_v + r_p + r_T bcv0 = DirichletBC(S0.sub(0), noslip, top) bcv1 = DirichletBC(S0.sub(0), vslip, bottom) bcp0 = DirichletBC(S0.sub(1), Constant(0.0), bottom) bct0 = DirichletBC(S0.sub(2), Constant(temp_values[0]), top) bct1 = DirichletBC(S0.sub(2), Constant(temp_values[3]), bottom) bcs = [bcv0, bcv1, bcp0, bct0, bct1] t = 0 count = 0 while (t < tEnd): solve(r == 0, u, bcs) t += dt nV, nP, nT = u.split() gp = grad(nP) rhosolid = rho_0 * (1 - alpha * (nT * dTemp - 1573)) deltarho = rhosolid - rhomelt yvec = Constant((0.0, 1.0)) vmelt = nV * w0 - darcy * (gp * p0 / h - deltarho * yvec * g) if (count % 100 == 0): pfile << nP ufile << nV tfile << nT mufile << mu gradpfile << project(grad(nP), Sgradp) mufile << project(mu * mu_a, Smu) rhofile << project(rhosolid, Srho) vmeltfile << project(vmelt, Svel) count += 1 assign(T0, nT) assign(v0, nV) mu.interpolate(muExp) print('Case mu=%g, Tb=%g complete.' % (mu_a, Tb), ' Run time =', clock() - runtimeInit, 's')
def main(): pulse.annotation.annotate = True # Set up problem problem, material_control, activation_control = create_problem() disp_file = dolfin.XDMFFile("displacement.xdmf") (U, P) = problem.state.split(deepcopy=True) disp_file.write_checkpoint(U, "displacement", 0, dolfin.XDMFFile.Encoding.HDF5, False) computed_volumes = [problem.geometry.cavity_volume()] # Create volume observersion endo = problem.geometry.markers["ENDO"][0] volume_model = pulse_adjoint.model_observations.VolumeObservation( problem.geometry.mesh, problem.geometry.ds(endo)) passive_volume_data = [2.511304019359619, 2.8] active_volume_data = [2.8, 1.5, 1.2, 1.2, 2.8] volume_data = passive_volume_data + active_volume_data passive_pressure_data = [0, 0.1] active_pressure_data = [1.0, 1.2, 1.0, 0.05, 0.1] pressure_data = passive_pressure_data + active_pressure_data if 0: fig, ax = plt.subplots() ax.plot(volume_data, pressure_data) ax.set_xlabel("Volume [ml]") ax.set_ylabel("Pressure [kPa]") plt.show() # ------------- Passive phase ---------------- volume_target = pulse_adjoint.OptimizationTarget(passive_volume_data[1:], volume_model) material_regularization = pulse_adjoint.Regularization(material_control, weight=1e-4, reg_type="L2") pressure_obs = pulse_adjoint.model_observations.BoundaryObservation( problem.bcs.neumann[0], passive_pressure_data[1:], start_value=passive_pressure_data[0], ) assimilator = pulse_adjoint.Assimilator( problem, targets=[volume_target], bcs=pressure_obs, control=material_control, regularization=material_regularization, ) optimal_control = assimilator.assimilate(min_value=0.1, max_value=10.0, tol=1e-6) material_control.vector()[:] = optimal_control.optimal_control dolfin.File("material.pvd") << material_control optimzed_material_paramter = optimal_control.optimal_control problem.solve() u, p = dolfin.split(problem.state) computed_volume = problem.geometry.cavity_volume(u=u) computed_volumes.append(computed_volume) print(f"Target volume: {passive_volume_data[-1]}") print(f"Model volume: {computed_volume}") print(f"Estimated activation parameters {optimzed_material_paramter}") (U, P) = problem.state.split(deepcopy=True) disp_file.write_checkpoint(U, "displacement", 1, dolfin.XDMFFile.Encoding.HDF5, True) prev_pressure = passive_pressure_data[-1] activation_parameters = [0] * len(passive_pressure_data) # ------------- Active phase ---------------- gamma_regularization = pulse_adjoint.Regularization(activation_control, weight=1e-4, reg_type="L2") gamma_file = dolfin.XDMFFile("activation.xdmf") gamma_file.write_checkpoint(activation_control, "gamma", 0, dolfin.XDMFFile.Encoding.HDF5, False) for i, (volume, pressure) in enumerate( zip(active_volume_data, active_pressure_data), ): print(f"Try to fit volume : {volume} with pressure {pressure}") volume_target = pulse_adjoint.OptimizationTarget([volume], volume_model) pressure_obs = pulse_adjoint.model_observations.BoundaryObservation( problem.bcs.neumann[0], [pressure], start_value=prev_pressure) assimilator = pulse_adjoint.Assimilator( problem, targets=[volume_target], bcs=pressure_obs, control=activation_control, regularization=gamma_regularization, ) optimal_control = assimilator.assimilate(min_value=0.0, max_value=0.3, tol=0.01) activation_control.vector()[:] = optimal_control.optimal_control gamma_file.write_checkpoint(activation_control, "gamma", i + 1, dolfin.XDMFFile.Encoding.HDF5, True) problem.solve() u, p = dolfin.split(problem.state) computed_volume = problem.geometry.cavity_volume(u=u) computed_volumes.append(computed_volume) activation_parameters.append(optimal_control.optimal_control) print(f"Target volume: {volume}") print(f"Model volume: {computed_volume}") print( f"Estimated activation parameters {optimal_control.optimal_control}" ) prev_pressure = pressure (U, P) = problem.state.split(deepcopy=True) disp_file.write_checkpoint(U, "displacement", i + 2, dolfin.XDMFFile.Encoding.HDF5, True) fig, ax = plt.subplots() ax.plot(volume_data, pressure_data, label="Data") ax.plot(computed_volumes, pressure_data, label="Model") ax.set_xlabel("Volume") ax.set_xlabel("Pressure") ax.legend() fig.savefig("results.png")
def rhs(states, time, parameters, dy=None): """ Compute right hand side """ # Imports import ufl import dolfin # Assign states assert(isinstance(states, dolfin.Function)) assert(states.function_space().depth() == 1) assert(states.function_space().num_sub_spaces() == 17) Xr1, Xr2, Xs, m, h, j, d, f, fCa, s, r, Ca_SR, Ca_i, g, Na_i, V, K_i =\ dolfin.split(states) # Assign parameters assert(isinstance(parameters, (dolfin.Function, dolfin.Constant))) if isinstance(parameters, dolfin.Function): assert(parameters.function_space().depth() == 1) assert(parameters.function_space().num_sub_spaces() == 45) else: assert(parameters.value_size() == 45) P_kna, g_K1, g_Kr, g_Ks, g_Na, g_bna, g_CaL, g_bca, g_to, K_mNa, K_mk,\ P_NaK, K_NaCa, K_sat, Km_Ca, Km_Nai, alpha, gamma, K_pCa, g_pCa,\ g_pK, Buf_c, Buf_sr, Ca_o, K_buf_c, K_buf_sr, K_up, V_leak, V_sr,\ Vmax_up, a_rel, b_rel, c_rel, tau_g, Na_o, Cm, F, R, T, V_c,\ stim_amplitude, stim_duration, stim_period, stim_start, K_o =\ dolfin.split(parameters) # Reversal potentials E_Na = R*T*ufl.ln(Na_o/Na_i)/F E_K = R*T*ufl.ln(K_o/K_i)/F E_Ks = R*T*ufl.ln((Na_o*P_kna + K_o)/(Na_i*P_kna + K_i))/F E_Ca = 0.5*R*T*ufl.ln(Ca_o/Ca_i)/F # Inward rectifier potassium current alpha_K1 = 0.1/(1.0 + 6.14421235332821e-6*ufl.exp(0.06*V - 0.06*E_K)) beta_K1 = (3.06060402008027*ufl.exp(0.0002*V - 0.0002*E_K) +\ 0.367879441171442*ufl.exp(0.1*V - 0.1*E_K))/(1.0 + ufl.exp(0.5*E_K -\ 0.5*V)) xK1_inf = alpha_K1/(alpha_K1 + beta_K1) i_K1 = 0.430331482911935*ufl.sqrt(K_o)*(-E_K + V)*g_K1*xK1_inf # Rapid time dependent potassium current i_Kr = 0.430331482911935*ufl.sqrt(K_o)*(-E_K + V)*Xr1*Xr2*g_Kr # Rapid time dependent potassium current xr1 gate xr1_inf = 1.0/(1.0 + 0.0243728440732796*ufl.exp(-0.142857142857143*V)) alpha_xr1 = 450.0/(1.0 + ufl.exp(-9/2 - V/10.0)) beta_xr1 = 6.0/(1.0 + 13.5813245225782*ufl.exp(0.0869565217391304*V)) tau_xr1 = alpha_xr1*beta_xr1 # Rapid time dependent potassium current xr2 gate xr2_inf = 1.0/(1.0 + 39.1212839981532*ufl.exp(0.0416666666666667*V)) alpha_xr2 = 3.0/(1.0 + 0.0497870683678639*ufl.exp(-0.05*V)) beta_xr2 = 1.12/(1.0 + 0.0497870683678639*ufl.exp(0.05*V)) tau_xr2 = alpha_xr2*beta_xr2 # Slow time dependent potassium current i_Ks = (Xs*Xs)*(V - E_Ks)*g_Ks # Slow time dependent potassium current xs gate xs_inf = 1.0/(1.0 + 0.69967253737513*ufl.exp(-0.0714285714285714*V)) alpha_xs = 1100.0/ufl.sqrt(1.0 +\ 0.188875602837562*ufl.exp(-0.166666666666667*V)) beta_xs = 1.0/(1.0 + 0.0497870683678639*ufl.exp(0.05*V)) tau_xs = alpha_xs*beta_xs # Fast sodium current i_Na = (m*m*m)*(-E_Na + V)*g_Na*h*j # Fast sodium current m gate m_inf = 1.0/((1.0 +\ 0.00184221158116513*ufl.exp(-0.110741971207087*V))*(1.0 +\ 0.00184221158116513*ufl.exp(-0.110741971207087*V))) alpha_m = 1.0/(1.0 + ufl.exp(-12.0 - V/5.0)) beta_m = 0.1/(1.0 + 0.778800783071405*ufl.exp(0.005*V)) + 0.1/(1.0 +\ ufl.exp(7.0 + V/5.0)) tau_m = alpha_m*beta_m # Fast sodium current h gate h_inf = 1.0/((1.0 + 15212.5932856544*ufl.exp(0.134589502018843*V))*(1.0 +\ 15212.5932856544*ufl.exp(0.134589502018843*V))) alpha_h = 4.43126792958051e-7*ufl.exp(-0.147058823529412*V)/(1.0 +\ 2.3538526683702e+17*ufl.exp(1.0*V)) beta_h = (310000.0*ufl.exp(0.3485*V) + 2.7*ufl.exp(0.079*V))/(1.0 +\ 2.3538526683702e+17*ufl.exp(1.0*V)) + 0.77*(1.0 - 1.0/(1.0 +\ 2.3538526683702e+17*ufl.exp(1.0*V)))/(0.13 +\ 0.0497581410839387*ufl.exp(-0.0900900900900901*V)) tau_h = 1.0/(alpha_h + beta_h) # Fast sodium current j gate j_inf = 1.0/((1.0 + 15212.5932856544*ufl.exp(0.134589502018843*V))*(1.0 +\ 15212.5932856544*ufl.exp(0.134589502018843*V))) alpha_j = (37.78 + V)*(-6.948e-6*ufl.exp(-0.04391*V) -\ 25428.0*ufl.exp(0.2444*V))/((1.0 +\ 2.3538526683702e+17*ufl.exp(1.0*V))*(1.0 +\ 50262745825.954*ufl.exp(0.311*V))) beta_j = 0.6*(1.0 - 1.0/(1.0 +\ 2.3538526683702e+17*ufl.exp(1.0*V)))*ufl.exp(0.057*V)/(1.0 +\ 0.0407622039783662*ufl.exp(-0.1*V)) +\ 0.02424*ufl.exp(-0.01052*V)/((1.0 +\ 2.3538526683702e+17*ufl.exp(1.0*V))*(1.0 +\ 0.00396086833990426*ufl.exp(-0.1378*V))) tau_j = 1.0/(alpha_j + beta_j) # Sodium background current i_b_Na = (-E_Na + V)*g_bna # L type ca current i_CaL = 4.0*(F*F)*(-0.341*Ca_o +\ Ca_i*ufl.exp(2.0*F*V/(R*T)))*V*d*f*fCa*g_CaL/((-1.0 +\ ufl.exp(2.0*F*V/(R*T)))*R*T) # L type ca current d gate d_inf = 1.0/(1.0 + 0.513417119032592*ufl.exp(-0.133333333333333*V)) alpha_d = 0.25 + 1.4/(1.0 +\ 0.0677244716592409*ufl.exp(-0.0769230769230769*V)) beta_d = 1.4/(1.0 + ufl.exp(1.0 + V/5.0)) gamma_d = 1.0/(1.0 + 12.1824939607035*ufl.exp(-0.05*V)) tau_d = gamma_d + alpha_d*beta_d # L type ca current f gate f_inf = 1.0/(1.0 + 17.4117080633276*ufl.exp(0.142857142857143*V)) tau_f = 80.0 + 165.0/(1.0 + ufl.exp(5/2 - V/10.0)) +\ 1125.0*ufl.exp(-0.00416666666666667*((27.0 + V)*(27.0 + V))) # L type ca current fca gate alpha_fCa = 1.0/(1.0 + 8.03402376701711e+27*ufl.elem_pow(Ca_i, 8.0)) beta_fCa = 0.1/(1.0 + 0.00673794699908547*ufl.exp(10000.0*Ca_i)) gama_fCa = 0.2/(1.0 + 0.391605626676799*ufl.exp(1250.0*Ca_i)) fCa_inf = 0.157534246575342 + 0.684931506849315*gama_fCa +\ 0.684931506849315*beta_fCa + 0.684931506849315*alpha_fCa tau_fCa = 2.0 d_fCa = (-fCa + fCa_inf)/tau_fCa # Calcium background current i_b_Ca = (V - E_Ca)*g_bca # Transient outward current i_to = (-E_K + V)*g_to*r*s # Transient outward current s gate s_inf = 1.0/(1.0 + ufl.exp(4.0 + V/5.0)) tau_s = 3.0 + 85.0*ufl.exp(-0.003125*((45.0 + V)*(45.0 + V))) + 5.0/(1.0 +\ ufl.exp(-4.0 + V/5.0)) # Transient outward current r gate r_inf = 1.0/(1.0 + 28.0316248945261*ufl.exp(-0.166666666666667*V)) tau_r = 0.8 + 9.5*ufl.exp(-0.000555555555555556*((40.0 + V)*(40.0 + V))) # Sodium potassium pump current i_NaK = K_o*Na_i*P_NaK/((K_mk + K_o)*(Na_i + K_mNa)*(1.0 +\ 0.0353*ufl.exp(-F*V/(R*T)) + 0.1245*ufl.exp(-0.1*F*V/(R*T)))) # Sodium calcium exchanger current i_NaCa = (-(Na_o*Na_o*Na_o)*Ca_i*alpha*ufl.exp((-1.0 + gamma)*F*V/(R*T))\ + (Na_i*Na_i*Na_i)*Ca_o*ufl.exp(F*V*gamma/(R*T)))*K_NaCa/((1.0 +\ K_sat*ufl.exp((-1.0 + gamma)*F*V/(R*T)))*((Na_o*Na_o*Na_o) +\ (Km_Nai*Km_Nai*Km_Nai))*(Km_Ca + Ca_o)) # Calcium pump current i_p_Ca = Ca_i*g_pCa/(K_pCa + Ca_i) # Potassium pump current i_p_K = (-E_K + V)*g_pK/(1.0 +\ 65.4052157419383*ufl.exp(-0.167224080267559*V)) # Calcium dynamics i_rel = ((Ca_SR*Ca_SR)*a_rel/((Ca_SR*Ca_SR) + (b_rel*b_rel)) + c_rel)*d*g i_up = Vmax_up/(1.0 + (K_up*K_up)/(Ca_i*Ca_i)) i_leak = (-Ca_i + Ca_SR)*V_leak g_inf = (1.0 - 1.0/(1.0 + 0.0301973834223185*ufl.exp(10000.0*Ca_i)))/(1.0 +\ 1.97201988740492e+55*ufl.elem_pow(Ca_i, 16.0)) + 1.0/((1.0 +\ 0.0301973834223185*ufl.exp(10000.0*Ca_i))*(1.0 +\ 5.43991024148102e+20*ufl.elem_pow(Ca_i, 6.0))) d_g = (-g + g_inf)/tau_g Ca_i_bufc = 1.0/(1.0 + Buf_c*K_buf_c/((K_buf_c + Ca_i)*(K_buf_c + Ca_i))) Ca_sr_bufsr = 1.0/(1.0 + Buf_sr*K_buf_sr/((K_buf_sr + Ca_SR)*(K_buf_sr +\ Ca_SR))) # Sodium dynamics # Membrane i_Stim = -(1.0 - 1.0/(1.0 + ufl.exp(-5.0*stim_start +\ 5.0*time)))*stim_amplitude/(1.0 + ufl.exp(-5.0*stim_start + 5.0*time\ - 5.0*stim_duration)) # Potassium dynamics # The ODE system: 17 states # Init test function _v = dolfin.TestFunction(states.function_space()) # Derivative for state Xr1 dy = ((-Xr1 + xr1_inf)/tau_xr1)*_v[0] # Derivative for state Xr2 dy += ((-Xr2 + xr2_inf)/tau_xr2)*_v[1] # Derivative for state Xs dy += ((-Xs + xs_inf)/tau_xs)*_v[2] # Derivative for state m dy += ((-m + m_inf)/tau_m)*_v[3] # Derivative for state h dy += ((-h + h_inf)/tau_h)*_v[4] # Derivative for state j dy += ((j_inf - j)/tau_j)*_v[5] # Derivative for state d dy += ((d_inf - d)/tau_d)*_v[6] # Derivative for state f dy += ((-f + f_inf)/tau_f)*_v[7] # Derivative for state fCa dy += ((1.0 - 1.0/((1.0 + ufl.exp(60.0 + V))*(1.0 + ufl.exp(-10.0*fCa +\ 10.0*fCa_inf))))*d_fCa)*_v[8] # Derivative for state s dy += ((-s + s_inf)/tau_s)*_v[9] # Derivative for state r dy += ((-r + r_inf)/tau_r)*_v[10] # Derivative for state Ca_SR dy += ((-i_leak + i_up - i_rel)*Ca_sr_bufsr*V_c/V_sr)*_v[11] # Derivative for state Ca_i dy += ((-i_up - (i_CaL + i_p_Ca + i_b_Ca - 2.0*i_NaCa)*Cm/(2.0*F*V_c) +\ i_leak + i_rel)*Ca_i_bufc)*_v[12] # Derivative for state g dy += ((1.0 - 1.0/((1.0 + ufl.exp(60.0 + V))*(1.0 + ufl.exp(-10.0*g +\ 10.0*g_inf))))*d_g)*_v[13] # Derivative for state Na_i dy += ((-3.0*i_NaK - 3.0*i_NaCa - i_Na - i_b_Na)*Cm/(F*V_c))*_v[14] # Derivative for state V dy += (-i_Ks - i_to - i_Kr - i_p_K - i_NaK - i_NaCa - i_Na - i_p_Ca -\ i_b_Na - i_CaL - i_Stim - i_K1 - i_b_Ca)*_v[15] # Derivative for state K_i dy += ((-i_Ks - i_to - i_Kr - i_p_K - i_Stim - i_K1 +\ 2.0*i_NaK)*Cm/(F*V_c))*_v[16] # Return dy return dy
import dolfin as dl mesh = dl.UnitCubeMesh(1,1,1) vectorP2Element = dl.VectorElement("P", mesh.ufl_cell(), 2) scalarP1Element = dl.FiniteElement("P", mesh.ufl_cell(), 1) TaylorHoodV = dl.FunctionSpace(mesh, dl.MixedElement([vectorP2Element,scalarP1Element])) parameterV = dl.VectorFunctionSpace(mesh,"R",0,7) y = dl.Function(TaylorHoodV) ytest = dl.TestFunction(TaylorHoodV) ytrial = dl.TrialFunction(TaylorHoodV) u,p = dl.split(y) a = dl.Function(parameterV) atest = dl.TestFunction(parameterV) atrial = dl.TrialFunction(parameterV) #Model Parameters m0 = 543.09 m1 = 4.73 m2 = 4.57 m3 = 5.27 m4 = 4.49 m5 = 4.49 m6 = 12.02 m = (m0,m1,m2,m3,m4,m5,m6) parameters = dl.interpolate(dl.Constant(m),parameterV) #Model d = len(u) I = dl.Identity(d) # Identity tensor
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)
def linear_solver(self, u_k): r""" Solves the (linear) Newton iteration Eq. :eq:`Eq_linear_solver` for the IR theory. For the IR theory, the form of the Newton iterations is: .. math:: & - \int \hat{\nabla}\hat{\pi} \cdot \hat{\nabla} v_1 \hat{r}^2 d\hat{r} - \int \hat{Y} v_1 \hat{r}^2 d\hat{r} + & + \int \hat{W} v_2 \hat{r}^2 d\hat{r} -n \int {\hat{Y}_k}^{n-1} \hat{Y} v_2 \hat{r}^2 d\hat{r} + & + \int \hat{Y} v_3 \hat{r}^2 d\hat{r} - \int \left( \frac{m}{M_n} \right)^2 \hat{\pi} v_3 \hat{r}^2 d\hat{r} + \epsilon \left( \frac{M_n}{\Lambda} \right)^{3n-1} \left( \frac{M_{f1}}{M_n} \right)^{n-1} \int \nabla\hat{W} \cdot \nabla v_3 \hat{r}^2 d\hat{r} & = (1-n) \int {\hat{Y}_k}^n v_2 \hat{r}^2 d\hat{r} + \int \frac{\hat{\rho}}{M_P} \frac{M_n}{M_{f1}} v_3 \hat{r}^2 d\hat{r} *Arguments* u_k solution at the previous iteration """ # get the boundary conditions Dirichlet_bc = self.get_Dirichlet_bc() # create a vector (pi,w,y) with the three trial functions for the fields u = d.TrialFunction(self.V) # ... and split it into pi, w, y pi, w, y = d.split(u) # define test functions over the function space v1, v2, v3 = d.TestFunctions(self.V) # split solution at current iteration into pi_k, w_k, y_k - this is only really useful for y_k pi_k, w_k, y_k = d.split(u_k) # cast params as constant functions so that, if they are set to 0, FEniCS still understand # what is being integrated m, Lambda, Mp = Constant(self.fields.m), Constant( self.fields.Lambda), Constant(self.fields.Mp) epsilon = Constant(self.fields.epsilon) Mn, Mf1 = Constant(self.Mn), Constant(self.Mf1) n = self.fields.n # r^2 r2 = Expression('pow(x[0],2)', degree=self.fem.func_degree) # define bilinear form a1 = -inner(grad(pi), grad(v1)) * r2 * dx - y * v1 * r2 * dx a2 = w * v2 * r2 * dx - n * y_k**(n - 1) * y * v2 * r2 * dx a3 = y * v3 * r2 * dx - ( m / Mn )**2 * pi * v3 * r2 * dx + \ epsilon * ( Mn / Lambda )**(3*n-1) * ( Mf1 / Mn )**(n-1) * inner( grad(w), grad(v3) ) * r2 * dx a = a1 + a2 + a3 # define linear form # we have L1 = 0. L2 = (1 - n) * y_k**n * v2 * r2 * dx L3 = self.source.rho / Mp * Mn / Mf1 * v3 * r2 * dx L = L2 + L3 # define a vector with the solution sol = d.Function(self.V) # solve linearised system pde = d.LinearVariationalProblem(a, L, sol, Dirichlet_bc) solver = d.LinearVariationalSolver(pde) solver.solve() return sol
def main(): pulse.annotation.annotate = True # Set up problem problem, material_control, activation_control = create_problem() computed_volumes = [problem.geometry.cavity_volume()] # Create volume observersion endo = problem.geometry.markers["ENDO"][0] volume_model = pulse_adjoint.model_observations.VolumeObservation( problem.geometry.mesh, problem.geometry.ds(endo) ) passive_volume_data = [2.511304019359619, 2.8] active_volume_data = [2.8, 1.5, 1.2, 1.2, 2.8] volume_data = passive_volume_data + active_volume_data passive_pressure_data = [0, 0.1] active_pressure_data = [1.0, 1.2, 1.0, 0.05, 0.1] pressure_data = passive_pressure_data + active_pressure_data if 0: fig, ax = plt.subplots() ax.plot(volume_data, pressure_data) ax.set_xlabel("Volume [ml]") ax.set_ylabel("Pressure [kPa]") plt.show() # ------------- Passive phase ---------------- volume_target = pulse_adjoint.OptimizationTarget( passive_volume_data[1:], volume_model ) pressure_obs = pulse_adjoint.model_observations.BoundaryObservation( problem.bcs.neumann[0], passive_pressure_data[1:], start_value=passive_pressure_data[0], ) assimilator = pulse_adjoint.Assimilator( problem, targets=[volume_target], bcs=pressure_obs, control=material_control ) optimal_control = assimilator.assimilate(min_value=0.1, max_value=10.0, tol=0.01) material_control.assign(dolfin.Constant(optimal_control.optimal_control)) optimzed_material_paramter = optimal_control.optimal_control problem.solve() u, p = dolfin.split(problem.state) computed_volume = problem.geometry.cavity_volume(u=u) computed_volumes.append(computed_volume) print(f"Target volume: {passive_volume_data[-1]}") print(f"Model volume: {computed_volume}") print(f"Estimated activation parameters {optimzed_material_paramter}") prev_pressure = passive_pressure_data[-1] activation_parameters = [0] * len(passive_pressure_data) # ------------- Active phase ---------------- for volume, pressure in zip(active_volume_data, active_pressure_data): print(f"Try to fit volume : {volume} with pressure {pressure}") volume_target = pulse_adjoint.OptimizationTarget([volume], volume_model) pressure_obs = pulse_adjoint.model_observations.BoundaryObservation( problem.bcs.neumann[0], [pressure], start_value=prev_pressure ) assimilator = pulse_adjoint.Assimilator( problem, targets=[volume_target], bcs=pressure_obs, control=activation_control, ) optimal_control = assimilator.assimilate(min_value=0.0, max_value=0.3, tol=0.01) activation_control.assign(dolfin.Constant(optimal_control.optimal_control)) problem.solve() u, p = dolfin.split(problem.state) computed_volume = problem.geometry.cavity_volume(u=u) computed_volumes.append(computed_volume) activation_parameters.append(optimal_control.optimal_control) print(f"Target volume: {volume}") print(f"Model volume: {computed_volume}") print(f"Estimated activation parameters {optimal_control.optimal_control}") prev_pressure = pressure fig, ax = plt.subplots(2, 1) ax[0].plot(volume_data, pressure_data, label="Data") ax[0].plot(computed_volumes, pressure_data, label="Model") ax[0].set_title(f"Material parameter {optimzed_material_paramter:.2f}") ax[1].plot(activation_parameters, marker="o") ax[1].set_title("Active strain") fig.savefig("results.png")
def strong_residual_form(self, sol, units): r""" Computes the residual with respect to the strong form of the equations. The total residual is obtained by summing the residuals of all equations: .. math:: F = F_1 + F_2 + F_3 where, in dimensionless in-code units (`units='rescaled'`): .. math:: & F_1(\hat{\pi},\hat{W},\hat{Y}) = \hat{\nabla}^2 \hat{\pi} - \hat{Y} & F_2(\hat{\pi},\hat{W},\hat{Y}) = \hat{W} - \hat{Y}^n & F_3(\hat{\pi},\hat{W},\hat{Y}) = \hat{Y} - \left( \frac{m}{M_n} \right)^2 \hat{\pi} - \epsilon \left( \frac{M_n}{\Lambda} \right)^{3n-1} \left(\frac{M_{f1}}{M_n}\right)^{n-1} \hat{\nabla}^2 \hat{W} - \frac{\hat{\rho}}{M_P} \frac{M_n}{M_{f1}} and in physical units (`units='physical'`): .. math:: & F_1(\pi,W,Y) = \nabla^2\pi - Y & F_2(\pi,W,Y) = W - Y^n & F_3(\pi,W,Y) = Y - m^2 \pi - \frac{\epsilon}{\Lambda^{3n-1}} \nabla^2 W - \frac{\rho}{M_P} .. note:: In this function, the Laplacian :math:`\hat{\nabla}^2` is obtained by projecting :math:`\frac{\partial^2}{\partial\hat{r}^2} + 2\frac{\partial}{\partial\hat{r}}`. As such, it should not be used with interpolating polynomials of degree less than 2. Note that the weak residual in :func:`weak_residual_form` is just the scalar product of the strong residuals by test functions. *Parameters* sol the solution with respect to which the weak residual is computed. units `'rescaled'` (for the rescaled units used inside the code) or `'physical'`, for physical units """ if units == 'rescaled': resc_1, resc_2, resc_3 = 1., 1., 1. elif units == 'physical': resc_1 = self.Mn**2 * self.Mf1 resc_2 = (self.Mn**2 * self.Mf1)**self.fields.n resc_3 = self.Mn**2 * self.Mf1 else: message = "Invalid choice of units: valid choices are 'physical' or 'rescaled'." raise ValueError(message) # cast params as constant functions so that, if they are set to 0, FEniCS still understand # what is being integrated m, Lambda, Mp = Constant(self.fields.m), Constant( self.fields.Lambda), Constant(self.fields.Mp) epsilon = Constant(self.fields.epsilon) Mn, Mf1 = Constant(self.Mn), Constant(self.Mf1) n = self.fields.n # split solution into pi, w, y pi, w, y = d.split(sol) # initialise residual function F = d.Function(self.dV) # define r for use in the computation of the Laplacian r = Expression('x[0]', degree=self.fem.func_degree) # equation 1 f1 = pi.dx(0).dx(0) + Constant(2.) / r * pi.dx(0) - y f1 *= Constant(resc_1) F1 = project(f1, self.fem.dS, self.fem.func_degree) # equation 2 f2 = w - y**n f2 *= Constant(resc_2) F2 = project(f2, self.fem.dS, self.fem.func_degree) # equation 3 f3 = y - ( m/Mn )**2 * pi \ - epsilon * ( Mn / Lambda )**(3*n-1) * ( Mf1 / Mn )**(n-1) * ( w.dx(0).dx(0) + Constant(2.)/r * w.dx(0) ) \ - self.source.rho / Mp * Mn / Mf1 f3 *= Constant(resc_3) F3 = project(f3, self.fem.dS, self.fem.func_degree) # combine equations fa = d.FunctionAssigner(self.dV, [self.fem.dS, self.fem.dS, self.fem.dS]) fa.assign(F, [F1, F2, F3]) return F
def KG_initial_guess(self): r""" Obtains an initial guess for the Galileon equation of motion by assuming the nonlinear term is subdominant, i.e.: .. math:: \Box\pi - m^2\pi \approx \frac{\rho}{Mp} The initial guess is computed by first solving the system of equations: .. math:: & \hat{\nabla}^2\hat{\pi} = \hat{Y} \\ & \hat{Y} - \left( \frac{m}{M_n} \right)^2\pi = \frac{\hat{\rho}}{M_p} and then obtaining :math:`\hat{W}=\hat{Y}^n` by projection. """ # define a function space for (pi, y) only piy_E = d.MixedElement([self.fem.Pn, self.fem.Pn]) piy_V = d.FunctionSpace(self.fem.mesh.mesh, piy_E) # get the boundary conditions for pi and y only piD, yD = Constant(0.), Constant(0.) def boundary(x): return self.fem.mesh.r_max - x[0] < d.DOLFIN_EPS bc_pi = d.DirichletBC(piy_V.sub(0), piD, boundary, method='pointwise') bc_y = d.DirichletBC(piy_V.sub(1), yD, boundary, method='pointwise') Dirichlet_bc = [bc_pi, bc_y] # Trial functions for pi and y u = d.TrialFunction(piy_V) pi, y = d.split(u) # test functions for the two equations v1, v3 = d.TestFunctions(piy_V) # cast params as constant functions so that, if they are set to 0, FEniCS still understand # what is being integrated m, Mp, Mn, Mf1 = Constant(self.fields.m), Constant( self.fields.Mp), Constant(self.Mn), Constant(self.Mf1) n = self.fields.n # r^2 r2 = Expression('pow(x[0],2)', degree=self.fem.func_degree) # bilinear form a1 = -inner(grad(pi), grad(v1)) * r2 * dx - y * v1 * r2 * dx a3 = y * v3 * r2 * dx - (m / Mn)**2 * pi * v3 * r2 * dx a = a1 + a3 # linear form (L1=0) L3 = self.source.rho / Mp * Mn / Mf1 * v3 * r2 * dx L = L3 # solve system sol = d.Function(piy_V) pde = d.LinearVariationalProblem(a, L, sol, Dirichlet_bc) solver = d.LinearVariationalSolver(pde) print('Getting KG initial guess...') solver.solve() # split solution into pi and y - cast as independent functions, not components of a vector function pi, y = sol.split(deepcopy=True) # obtain w by projecting y**n w = y**n w = project(w, self.fem.S, self.fem.func_degree) # and now pack pi, w, y into one function... guess = d.Function(self.V) # this syntax is because, even though pi and y are effectively defined on fem.S, from fenics point # of view, they are obtained as splits of a function fa = d.FunctionAssigner( self.V, [pi.function_space(), self.fem.S, y.function_space()]) fa.assign(guess, [pi, w, y]) return guess
def traction_test( ell=0.1, degree=1, n=3, nu=0.0, load_min=0, load_max=2, loads=None, nsteps=20, Lx=1, Ly=0.1, outdir="outdir", savelag=1, ): # constants ell = ell Lx = Lx Ly = Ly load_min = load_min load_max = load_max nsteps = nsteps loads=loads savelag = 1 nu = dolfin.Constant(nu) ell = dolfin.Constant(ell) E0 = dolfin.Constant(1.0) sigma_D0 = E0 n = n params = { 'material': { "ell": ell.values()[0], "E": E0.values()[0], "nu": nu.values()[0], "sigma_D0": sigma_D0.values()[0]}, 'geometry': { 'Lx': Lx, 'Ly': Ly, 'n': n, }, 'load':{ 'min': load_min, 'max': load_max, 'nsteps': nsteps } } print(params) geom = mshr.Rectangle(dolfin.Point(-Lx/2., -Ly/2.), dolfin.Point(Lx/2., Ly/2.)) nel = max(int(n * float(Lx / ell)), int(Ly/3.)) mesh = mshr.generate_mesh(geom, nel) left = dolfin.CompiledSubDomain("near(x[0], -Lx/2.)", Lx=Lx) right = dolfin.CompiledSubDomain("near(x[0], Lx/2.)", Lx=Lx) right_bottom_pt = dolfin.CompiledSubDomain("near(x[1], Lx/2.) && near(x[0],-Ly/2.)", Lx=Lx, Ly=Ly) mf = dolfin.MeshFunction("size_t", mesh, 1, 0) right.mark(mf, 1) left.mark(mf, 2) ds = dolfin.Measure("ds", subdomain_data=mf) dx = dolfin.Measure("dx", metadata=form_compiler_parameters, domain=mesh) V_u = dolfin.VectorFunctionSpace(mesh, "CG", 1) V_alpha = dolfin.FunctionSpace(mesh, "CG", 1) u = dolfin.Function(V_u, name="Total displacement") alpha = dolfin.Function(V_alpha, name="Damage") state = {'u': u, 'alpha':alpha} Z = dolfin.FunctionSpace(mesh, dolfin.MixedElement([u.ufl_element(),alpha.ufl_element()])) z = dolfin.Function(Z) v, beta = dolfin.split(z) ut = dolfin.Expression("t", t=0.0, degree=0) bcs_u = [dolfin.DirichletBC(V_u.sub(0), dolfin.Constant(0), left), dolfin.DirichletBC(V_u.sub(0), ut, right), dolfin.DirichletBC(V_u, (0, 0), right_bottom_pt, method="pointwise")] bcs_alpha = [] # Problem definition model = DamageElasticityModel(state, E0, nu, ell, sigma_D0) energy = model.total_energy_density(u, alpha)*dx # Alternate minimization solver solver = solvers.EquilibriumAM( energy, {'u':u, 'alpha':alpha}, {'elastic':bcs_u, 'damage':bcs_alpha}, parameters = alt_min_parameters) rP = model.rP(u, alpha, v, beta)*dx rN = model.rN(u, alpha, beta) stability = StabilitySolver(mesh, energy, {'u':u, 'alpha':alpha}, {'elastic':bcs_u, 'damage':bcs_alpha}, z, parameters = stability_parameters) # Time iterations time_data = [] load_steps = np.linspace(load_min, load_max, nsteps) alpha_old = dolfin.Function(V_alpha) for it, load in enumerate(load_steps): stable = None; negev = 0; mineig = np.inf; iteration = 0 ut.t = load ColorPrint.print_pass('load: {:4f} step {:d} ell {:f}'.format(load, it, ell.values()[0])) alpha_old.assign(alpha) time_data_i, am_iter = solver.solve() solver.update() (stable, negev) = stability.solve(alpha_old) time_data_i["load"] = load time_data_i["stable"] = stable time_data_i["# neg ev"] = negev time_data_i["elastic_energy"] = dolfin.assemble( model.elastic_energy_density(model.eps(u), alpha)*dx) time_data_i["dissipated_energy"] = dolfin.assemble( model.damage_dissipation_density(alpha)*dx) time_data_i["eigs"] = stability.eigs if hasattr(stability, 'eigs') else np.inf time_data_i["max alpha"] = np.max(alpha.vector()[:]) time_data.append(time_data_i) time_data_pd = pd.DataFrame(time_data) if stable == False: break return time_data_pd
def __init__(self, fileName, timeEnd, timeStep): self.times = [] self.BB = [] self.HH = [] self.TD = [] self.TB = [] self.TX = [] self.TY = [] self.TZ = [] self.us = [] self.ub = [] ########################################################## ################ MESH ################# ########################################################## # TODO: Probably do not have to save then open mesh self.mesh = df.Mesh() self.inFile = fc.HDF5File(self.mesh.mpi_comm(), fileName, "r") self.inFile.read(self.mesh, "/mesh", False) ######################################################### ################# FUNCTION SPACES ##################### ######################################################### self.E_Q = df.FiniteElement("CG", self.mesh.ufl_cell(), 1) self.Q = df.FunctionSpace(self.mesh, self.E_Q) self.E_V = df.MixedElement(self.E_Q, self.E_Q, self.E_Q) self.V = df.FunctionSpace(self.mesh, self.E_V) self.assigner_inv = fc.FunctionAssigner([self.Q, self.Q, self.Q], self.V) self.assigner = fc.FunctionAssigner(self.V, [self.Q, self.Q, self.Q]) self.U = df.Function(self.V) self.dU = df.TrialFunction(self.V) self.Phi = df.TestFunction(self.V) self.u, self.u2, self.H = df.split(self.U) self.phi, self.phi1, self.xsi = df.split(self.Phi) self.un = df.Function(self.Q) self.u2n = df.Function(self.Q) self.zero_sol = df.Function(self.Q) self.S0 = df.Function(self.Q) self.B = df.Function(self.Q) self.H0 = df.Function(self.Q) self.A = df.Function(self.Q) self.inFile.read(self.S0.vector(), "/surface", True) self.inFile.read(self.B.vector(), "/bed", True) self.inFile.read(self.A.vector(), "/smb", True) self.H0.assign(self.S0 - self.B) self.Hmid = theta * self.H + (1 - theta) * self.H0 self.S = self.B + self.Hmid self.width = df.interpolate(Width(degree=2), self.Q) self.strs = Stresses(self.U, self.Hmid, self.H0, self.H, self.width, self.B, self.S, self.Phi) self.R = -(self.strs.tau_xx + self.strs.tau_xz + self.strs.tau_b + self.strs.tau_d + self.strs.tau_xy) * df.dx ############################################################################# ######################## MASS CONSERVATION ################################ ############################################################################# self.h = df.CellSize(self.mesh) self.D = self.h * abs(self.U[0]) / 2. self.area = self.Hmid * self.width self.mesh_min = self.mesh.coordinates().min() self.mesh_max = self.mesh.coordinates().max() # Define boundaries self.ocean = df.FacetFunctionSizet(self.mesh, 0) self.ds = fc.ds(subdomain_data=self.ocean ) # THIS DS IS FROM FENICS! border integral for f in df.facets(self.mesh): if df.near(f.midpoint().x(), self.mesh_max): self.ocean[f] = 1 if df.near(f.midpoint().x(), self.mesh_min): self.ocean[f] = 2 self.R += ((self.H - self.H0) / dt * self.xsi \ - self.xsi.dx(0) * self.U[0] * self.Hmid \ + self.D * self.xsi.dx(0) * self.Hmid.dx(0) \ - (self.A - self.U[0] * self.H / self.width * self.width.dx(0)) \ * self.xsi) * df.dx + self.U[0] * self.area * self.xsi * self.ds(1) \ - self.U[0] * self.area * self.xsi * self.ds(0) ##################################################################### ######################### SOLVER SETUP ########################### ##################################################################### # Bounds self.l_thick_bound = df.project(Constant(thklim), self.Q) self.u_thick_bound = df.project(Constant(1e4), self.Q) self.l_v_bound = df.project(-10000.0, self.Q) self.u_v_bound = df.project(10000.0, self.Q) self.l_bound = df.Function(self.V) self.u_bound = df.Function(self.V) self.assigner.assign(self.l_bound, [self.l_v_bound] * 2 + [self.l_thick_bound]) self.assigner.assign(self.u_bound, [self.u_v_bound] * 2 + [self.u_thick_bound]) # This should set the velocity at the divide (left) to zero self.dbc0 = df.DirichletBC( self.V.sub(0), 0, lambda x, o: df.near(x[0], self.mesh_min) and o) # Set the velocity on the right terminus to zero self.dbc1 = df.DirichletBC( self.V.sub(0), 0, lambda x, o: df.near(x[0], self.mesh_max) and o) # overkill? self.dbc2 = df.DirichletBC( self.V.sub(1), 0, lambda x, o: df.near(x[0], self.mesh_max) and o) # set the thickness on the right edge to thklim self.dbc3 = df.DirichletBC( self.V.sub(2), thklim, lambda x, o: df.near(x[0], self.mesh_max) and o) # Define variational solver for the mass-momentum coupled problem self.J = df.derivative(self.R, self.U, self.dU) self.coupled_problem = df.NonlinearVariationalProblem(self.R, self.U, bcs=[self.dbc0, self.dbc1, self.dbc3], \ J=self.J) self.coupled_problem.set_bounds(self.l_bound, self.u_bound) self.coupled_solver = df.NonlinearVariationalSolver( self.coupled_problem) # Accquire the optimizations in fenics_optimizations set_solver_options(self.coupled_solver) self.t = 0 self.timeEnd = float(timeEnd) self.dtFloat = float(timeStep) self.inFile.close()
infile.read(mesh) mvc = MeshValueCollection("size_t", mesh, 1) with XDMFFile(pygmsh_facets) as infile: infile.read(mvc, "name_to_read") mf = cpp.mesh.MeshFunctionSizet(mesh, mvc) # Define function spaces for PDEs variational formulation. P1 = FiniteElement('P', mesh.ufl_cell(), 1) # Lagrange 1-order polynomials family element = MixedElement([P1, P1, P1, P1]) V = FunctionSpace(mesh, element) # Splitting test and trial functions v_A, v_B, v_C, v_T = TestFunctions(V) # Test functions u = Function(V) u_A, u_B, u_C, u_T = split(u) # Trial functions, time step = n+1 u_n = Function(V) # Trial functions, time step = n _3u_n = Function(V) # Retrieve boundaries marks for Robin boundary conditions. ds_in = Measure("ds", domain=mesh, subdomain_data=mf, subdomain_id=Inletboundary_id) ds_wall = Measure("ds", domain=mesh, subdomain_data=mf, subdomain_id=Wallboundary_id) """Initial values (t == 0.0)""" CAo = Constant(0.0) # Initial composition for A CBo = Constant(0.0) # Initial composition for A
def ab2tr_step(W, P, dt0, dt_1, mu, rho, u0, u_1, u_bcs, dudt0, dudt_1, dudt_bcs, p_1, p_bcs, f0, f1, tol=1.0e-12, verbose=True ): # General AB2/TR step. # # Steps are labeled in the following way: # # * u_1: previous step. # * u0: current step. # * u1: next step. # # The same scheme applies to all other entities. # WP = W * P # Make sure the boundary conditions fit with the space. u_bcs_new = [] for u_bc in u_bcs: u_bcs_new.append(DirichletBC(WP.sub(0), u_bc.value(), u_bc.user_sub_domain())) p_bcs_new = [] for p_bc in p_bcs: p_bcs_new.append(DirichletBC(WP.sub(1), p_bc.value(), p_bc.user_sub_domain())) # Predict velocity. if dudt_1: u_pred = u0 \ + 0.5*dt0*((2 + dt0/dt_1) * dudt0 - (dt0/dt_1) * dudt_1) else: # Simple linear extrapolation. u_pred = u0 + dt0 * dudt0 uu = TrialFunctions(WP) vv = TestFunctions(WP) # Assign up[1] with u_pred and up[1] with p_1. # As of now (2013/09/05), there is no proper subfunction assignment in # Dolfin, cf. # <https://bitbucket.org/fenics-project/dolfin/issue/84/subfunction-assignment>. # Hence, we need to be creative here. # TODO proper subfunction assignment # # up1.assign(0, u_pred) # up1.assign(1, p_1) # up1 = Function(WP) a = (dot(uu[0], vv[0]) + uu[1] * vv[1]) * dx L = dot(u_pred, vv[0]) * dx if p_1: L += p_1 * vv[1] * dx solve(a == L, up1, bcs=u_bcs_new + p_bcs_new ) # Split up1 for easier access. # This is not as easy as it may seem at first, see # <http://fenicsproject.org/qa/1123/nonlinear-solves-with-mixed-function-spaces>. # Note in particular that # u1, p1 = up1.split() # doesn't work here. # u1, p1 = split(up1) # Form the nonlinear equation system (3.16-235) in Gresho/Sani. # Left-hand side of the nonlinear equation system. F = 2.0/dt0 * rho * dot(u1, vv[0]) * dx \ + mu * inner(grad(u1), grad(vv[0])) * dx \ + rho * 0.5 * (inner(grad(u1)*u1, vv[0]) - inner(grad(vv[0]) * u1, u1)) * dx \ + dot(grad(p1), vv[0]) * dx \ + div(u1) * vv[1] * dx # Subtract the right-hand side. F -= dot(rho*(2.0/dt0*u0 + dudt0) + f1, vv[0]) * dx #J = derivative(F, up1) # Solve nonlinear system for u1, p1. solve( F == 0, up1, bcs=u_bcs_new + p_bcs_new, #J = J, solver_parameters={ #'nonlinear_solver': 'snes', 'nonlinear_solver': 'newton', 'newton_solver': {'maximum_iterations': 5, 'report': True, 'absolute_tolerance': tol, 'relative_tolerance': 0.0 }, 'linear_solver': 'direct', #'linear_solver': 'iterative', ## The nonlinear term makes the problem ## generally nonsymmetric. #'symmetric': False, ## If the nonsymmetry is too strong, e.g., if ## u_1 is large, then AMG preconditioning ## might not work very well. #'preconditioner': 'ilu', ##'preconditioner': 'hypre_amg', #'krylov_solver': {'relative_tolerance': tol, # 'absolute_tolerance': 0.0, # 'maximum_iterations': 100, # 'monitor_convergence': verbose} }) ## Simpler access to the solution. #u1, p1 = up1.split() # Invert trapezoidal rule for next du/dt. dudt1 = 2 * (u1 - u0)/dt0 - dudt0 # Get next dt. if dt_1: # Compute local trunction error (LTE) estimate. d = (u1 - u_pred) / (3*(1.0 + dt_1 / dt)) # There are other ways of estimating the LTE norm. norm_d = numpy.sqrt(inner(d, d) / u_max**2) # Get next step size. dt1 = dt0 * (eps / norm_d)**(1.0/3.0) else: dt1 = dt0 return u1, p1, dudt1, dt1
def initialize(self, pc): if 'vp_spaces' not in self.ctx: raise ValueError("Must provide vp_spaces (velocity and pressure subspaces) to ctx") else: self.vp_spaces = self.ctx['vp_spaces'] if not isinstance(self.vp_spaces,list): raise TypeError('vp_spaces must be of type list()') if 'nu' not in self.ctx: raise ValueError('Must provide nu (viscosity) to ctx') else: self.nu = self.ctx['nu'] self.V = self.vbp.V p = df.TrialFunction(self.V) q = df.TestFunction(self.V) p = df.split(p)[self.vp_spaces[1]] q = df.split(q)[self.vp_spaces[1]] u = df.split(self.vbp.u)[self.vp_spaces[0]] ## Mass term ## self.mP = df.Constant(1.0/self.nu)*p*q*df.dx ## Advection term ## self.aP = df.Constant(1.0/self.nu)*df.dot(df.grad(p), u)*q*df.dx ## Stiffness term ## self.kP = df.inner(df.grad(p), df.grad(q))*df.dx ## Create PETSc Matrices ## self.M_p = df.PETScMatrix() self.A_p = df.PETScMatrix() self.K_p = df.PETScMatrix() df.assemble(self.mP, tensor=self.M_p) df.assemble(self.aP, tensor=self.A_p) df.assemble(self.kP, tensor=self.K_p) ## Optionally apply BCs ## if 'bcs_kP' in self.ctx: self.applyBCs(self.K_p,self.ctx['bcs_kP']) self.bc_dofs, self.bc_value = self.extractBCs(self.ctx['bcs_kP']) ## Extract sub matrices ## self.M_submat = self.M_p.mat().createSubMatrix(self.isset,self.isset) self.A_submat = self.A_p.mat().createSubMatrix(self.isset,self.isset) self.K_submat = self.K_p.mat().createSubMatrix(self.isset,self.isset) ## KSP solver for mass matrix ## self.M_ksp = PETSc.KSP().create(comm=pc.comm) self.M_ksp.setType(PETSc.KSP.Type.GMRES) # Default solver, can change self.M_ksp.pc.setType(PETSc.PC.Type.BJACOBI) # Default solver, can change self.M_ksp.incrementTabLevel(1, parent=pc) self.M_ksp.setOperators(self.M_submat) self.M_ksp.setOptionsPrefix(self.options_prefix+'mP_') self.M_ksp.setFromOptions() self.M_ksp.setUp() ## KSP solver for stiffness matrix ## self.K_ksp = PETSc.KSP().create(comm=pc.comm) self.K_ksp.setType(PETSc.KSP.Type.GMRES) # Default solver, can change self.K_ksp.pc.setType(PETSc.PC.Type.HYPRE) # Default solver, can change self.K_ksp.incrementTabLevel(1, parent=pc) self.K_ksp.setOperators(self.K_submat) self.K_ksp.setOptionsPrefix(self.options_prefix+'aP_') self.K_ksp.setFromOptions() self.K_ksp.setUp()
geo_map.initialize(res, restart_folder=parameters["restart_folder"]) W = geo_map.mixed_space(4) # Define trial and test functions du = df.TrialFunction(W) chi, xi, eta, etahat = df.TestFunctions(W) # Define functions u = df.TrialFunction(W) u_ = df.Function(W, name="u_") # current solution u_1 = df.Function(W, name="u_1") # solution from previous converged step # Split mixed functions psi, mu, nu, nuhat = df.split(u) psi_, mu_, nu_, nuhat_ = df.split(u_) psi_1, mu_1, nu_1, nuhat_1 = df.split(u_1) # Create intial conditions if parameters["restart_folder"] is None: init_mode = parameters["init_mode"] if init_mode == "random": u_init = RandomIC(u_, amplitude=1e-1, degree=1) elif init_mode == "striped": u_init = StripedIC(u_, alpha=parameters["alpha"]*np.pi/180.0, degree=1) else: exit("No init_mode set.") u_1.interpolate(u_init) u_.assign(u_1) else:
#============================================================================== # define auxiliary operators def a_operator(phi, psi): return inner(grad(phi), grad(psi)) / Re * dV def b_operator(phi, psi): return div(phi) * psi * dV def c_operator(phi, psi): return inner(grad(phi) * phi, psi) * dV #============================================================================== sol_v, sol_p = dlfn.split(sol) sol_v0, _ = dlfn.split(sol0) half = dlfn.Constant(0.5) F_CN = (inner(sol_v, del_v) - inner(sol_v0, del_v)) * dV \ + half * dt * ( a_operator(sol_v, del_v) + a_operator(sol_v0, del_v) )\ + half * dt * ( c_operator(sol_v, del_v) + c_operator(sol_v0, del_v) )\ - dt * b_operator(sol_v, del_p) \ - dt * b_operator(del_v, sol_p) J_newton = dlfn.derivative(F_CN, sol) problem = dlfn.NonlinearVariationalProblem(F_CN, sol, bcs=bcs, J=J_newton) solver = dlfn.NonlinearVariationalSolver(problem) #============================================================================== pvd_velocity = dlfn.File("results_{1}/Re_{0:d}/solution_velocity_Re_{0:d}.pvd".\ format(int(reynolds), "FEniCS")) pvd_pressure = dlfn.File("results_{1}/Re_{0:d}/solution_pressure_Re_{0:d}.pvd".\ format(int(reynolds), "FEniCS"))
def left_boundary(x, on_boundary): return on_boundary and abs(x[0]) < tol def right_boundary(x, on_boundary): return on_boundary and abs(x[0] - 1) < tol # Define function space V = df.FunctionSpace(mesh, "Lagrange", p) V2 = df.MixedFunctionSpace([V, V]) u = df.Function(V2) du = df.TrialFunction(V2) v = df.TestFunction(V2) u1, u2 = df.split(u) v1, v2 = df.split(v) # Initial Guesses u1_i = df.Expression("x[0]") u2_i = df.Expression("1-x[0]") # Impose boundary conditions for the solution to the nonlinear system bc = [ df.DirichletBC(V2.sub(0), df.Constant(0.0), left_boundary), df.DirichletBC(V2.sub(0), df.Constant(1.0), right_boundary), df.DirichletBC(V2.sub(1), df.Constant(1.0), left_boundary), df.DirichletBC(V2.sub(1), df.Constant(0.0), right_boundary), ] # Make homogeneous version of BCs for the update
density_function = df.Function(density_function_space) pde_problem.add_input('density', density_function) ''' 4. 2. Add states ''' # Define mixed function space-split into temperature and displacement FS d = mesh.geometry().dim() cell = mesh.ufl_cell() displacement_fe = df.VectorElement("CG", cell, 1) temperature_fe = df.FiniteElement("CG", cell, 1) mixed_fs = df.FunctionSpace(mesh, df.MixedElement([displacement_fe, temperature_fe])) mixed_fs.sub(1).dofmap().dofs() mixed_function = df.Function(mixed_fs) displacements_function, temperature_function = df.split(mixed_function) v, T_hat = df.TestFunctions(mixed_fs) residual_form = get_residual_form(displacements_function, v, density_function, temperature_function, T_hat, KAPPA, K, ALPHA) residual_form -= (df.dot(f_r, v) * dss(10) + df.dot(f_t, v) * dss(14) + \ q*T_hat*dss(5) + q_half*T_hat*dss(6) + q_quart*T_hat*dss(7)) print("get residual_form-------") pde_problem.add_state('mixed_states', mixed_function, residual_form, 'density') ''' 4. 3. Add outputs ''' # Add output-avg_density to the PDE problem:
def __init__(self, cparams, dtype_u, dtype_f): """ Initialization routine Args: cparams: custom parameters for the example dtype_u: particle data type (will be passed parent class) dtype_f: acceleration data type (will be passed parent class) """ # define the Dirichlet boundary def Boundary(x, on_boundary): return on_boundary # these parameters will be used later, so assert their existence assert 'c_nvars' in cparams assert 't0' in cparams assert 'family' in cparams assert 'order' in cparams assert 'refinements' in cparams # add parameters as attributes for further reference for k,v in cparams.items(): setattr(self,k,v) df.set_log_level(df.WARNING) df.parameters["form_compiler"]["optimize"] = True df.parameters["form_compiler"]["cpp_optimize"] = True # set mesh and refinement (for multilevel) # mesh = df.UnitIntervalMesh(self.c_nvars) # mesh = df.UnitSquareMesh(self.c_nvars[0],self.c_nvars[1]) mesh = df.IntervalMesh(self.c_nvars,0,100) # mesh = df.RectangleMesh(0.0,0.0,2.0,2.0,self.c_nvars[0],self.c_nvars[1]) for i in range(self.refinements): mesh = df.refine(mesh) # self.mesh = mesh # define function space for future reference V = df.FunctionSpace(mesh, self.family, self.order) self.V = V*V # invoke super init, passing number of dofs, dtype_u and dtype_f super(fenics_grayscott,self).__init__(self.V,dtype_u,dtype_f) # rhs in weak form self.w = df.Function(self.V) q1,q2 = df.TestFunctions(self.V) self.w1,self.w2 = df.split(self.w) self.F1 = (-self.Du*df.inner(df.nabla_grad(self.w1), df.nabla_grad(q1)) - self.w1*(self.w2**2)*q1 + self.A*(1-self.w1)*q1)*df.dx self.F2 = (-self.Dv*df.inner(df.nabla_grad(self.w2), df.nabla_grad(q2)) + self.w1*(self.w2**2)*q2 - self.B* self.w2*q2)*df.dx self.F = self.F1+self.F2 # mass matrix u1,u2 = df.TrialFunctions(self.V) a_M = u1*q1*df.dx M1 = df.assemble(a_M) a_M = u2*q2*df.dx M2 = df.assemble(a_M) self.M = M1+M2
def __init__(self, Vh, gamma, delta, mean=None, rel_tol=1e-12, max_iter=100): """ Construct the prior model. Input: - :code:`Vh`: the finite element space for the parameter - :code:`gamma` and :code:`delta`: the coefficient in the PDE - :code:`Theta`: the SPD tensor for anisotropic diffusion of the PDE - :code:`mean`: the prior mean """ assert delta != 0., "Intrinsic Gaussian Prior are not supported" self.Vh = Vh trial = dl.TrialFunction(Vh) test = dl.TestFunction(Vh) varfL = dl.inner(dl.nabla_grad(trial), dl.nabla_grad(test))*dl.dx varfM = dl.inner(trial,test)*dl.dx self.M = dl.assemble(varfM) self.R = dl.assemble(gamma*varfL + delta*varfM) if dlversion() <= (1,6,0): self.Rsolver = dl.PETScKrylovSolver("cg", amg_method()) else: self.Rsolver = dl.PETScKrylovSolver(self.Vh.mesh().mpi_comm(), "cg", amg_method()) self.Rsolver.set_operator(self.R) self.Rsolver.parameters["maximum_iterations"] = max_iter self.Rsolver.parameters["relative_tolerance"] = rel_tol self.Rsolver.parameters["error_on_nonconvergence"] = True self.Rsolver.parameters["nonzero_initial_guess"] = False if dlversion() <= (1,6,0): self.Msolver = dl.PETScKrylovSolver("cg", "jacobi") else: self.Msolver = dl.PETScKrylovSolver(self.Vh.mesh().mpi_comm(), "cg", "jacobi") self.Msolver.set_operator(self.M) self.Msolver.parameters["maximum_iterations"] = max_iter self.Msolver.parameters["relative_tolerance"] = rel_tol self.Msolver.parameters["error_on_nonconvergence"] = True self.Msolver.parameters["nonzero_initial_guess"] = False ndim = Vh.mesh().geometry().dim() old_qr = dl.parameters["form_compiler"]["quadrature_degree"] dl.parameters["form_compiler"]["quadrature_degree"] = -1 qdegree = 2*Vh._ufl_element.degree() metadata = {"quadrature_degree" : qdegree} if dlversion() >= (2017,1,0): representation_old = dl.parameters["form_compiler"]["representation"] dl.parameters["form_compiler"]["representation"] = "quadrature" if dlversion() <= (1,6,0): Qh = dl.VectorFunctionSpace(Vh.mesh(), 'Quadrature', qdegree, dim=(ndim+1) ) else: element = dl.VectorElement("Quadrature", Vh.mesh().ufl_cell(), qdegree, dim=(ndim+1), quad_scheme="default") Qh = dl.FunctionSpace(Vh.mesh(), element) ph = dl.TrialFunction(Qh) qh = dl.TestFunction(Qh) pph = dl.split(ph) Mqh = dl.assemble(dl.inner(ph, qh)*dl.dx(metadata = metadata)) ones = dl.Vector(self.R.mpi_comm()) Mqh.init_vector(ones,0) ones.set_local( np.ones(ones.get_local().shape, dtype =ones.get_local().dtype ) ) dMqh = Mqh*ones dMqh.set_local( ones.get_local() / np.sqrt(dMqh.get_local() ) ) Mqh.zero() Mqh.set_diagonal(dMqh) sqrtdelta = math.sqrt(delta) sqrtgamma = math.sqrt(gamma) varfGG = sqrtdelta*pph[0]*test*dl.dx(metadata = metadata) for i in range(ndim): varfGG = varfGG + sqrtgamma*pph[i+1]*test.dx(i)*dl.dx(metadata = metadata) GG = dl.assemble(varfGG) self.sqrtR = MatMatMult(GG, Mqh) dl.parameters["form_compiler"]["quadrature_degree"] = old_qr if dlversion() >= (2017,1,0): dl.parameters["form_compiler"]["representation"] = representation_old self.mean = mean if self.mean is None: self.mean = dl.Vector(self.R.mpi_comm()) self.init_vector(self.mean, 0)
def assembleSystem(self): """Assemble the FEM system. This is only run a single time before time-stepping. The values of the coefficient fields need to be updated between time-steps """ # Loop through the entire model and composite the system of equations self.diffusors = [] # [[compartment, species, diffusivity of species],[ ...],[...]] """ Diffusors have source terms """ self.electrostatic_compartments = [] # (compartment) where electrostatic equations reside """ Has source term """ self.potentials = [] # (membrane) """ No spatial derivatives, just construct ODE """ self.channelvars = [] #(membrane, channel, ...) for compartment in self.compartments: s = 0 for species in compartment.species: if compartment.diffusivities[species] < 1e-10: continue self.diffusors.extend([ [compartment,species,compartment.diffusivities[species]] ]) s+=compartment.diffusivities[species]*abs(species.z) if s>0: self.electrostatic_compartments.extend([compartment]) # Otherwise, there are no mobile charges in the compartment # the number of potentials is the number of spatial potentials + number of membrane potentials self.numdiffusers = len(self.diffusors) self.numpoisson = len(self.electrostatic_compartments) # Functions # Reaction-diffusion type # Diffusers :numdiffusers # # Coefficient # Diffusivities self.V_np = dolfin.MixedFunctionSpace([self.v]*(self.numdiffusers)) self.V_poisson = dolfin.MixedFunctionSpace([self.v]*self.numpoisson) #self.V = self.V_diff*self.V_electro self.V = dolfin.MixedFunctionSpace([self.v]*(self.numdiffusers+self.numpoisson)) self.dofs_is = [self.V.sub(j).dofmap().dofs() for j in range(self.numdiffusers+self.numpoisson)] self.N = len(self.dofs_is[0]) self.diffusivities = [dolfin.Function(self.v) for j in range(self.numdiffusers)] self.trialfunctions = dolfin.TrialFunctions(self.V) # Trial function self.testfunctions = dolfin.TestFunctions(self.V) # test functions, one for each field self.sourcefunctions = [dolfin.Function(self.v) for j in range(self.numpoisson+self.numdiffusers)] self.permitivities = [dolfin.Function(self.v) for j in range(self.numpoisson)] # index the compartments! self.functions__ = dolfin.Function(self.V) self.np_assigner = dolfin.FunctionAssigner(self.V_np,[self.v]*self.numdiffusers) self.poisson_assigner = dolfin.FunctionAssigner(self.V_poisson,[self.v]*self.numpoisson) self.full_assigner = dolfin.FunctionAssigner(self.V,[self.v]*(self.numdiffusers+self.numpoisson)) self.prev_value__ = dolfin.Function(self.V) self.prev_value_ = dolfin.split(self.prev_value__) self.prev_value = [dolfin.Function(self.v) for j in range(self.numdiffusers+self.numpoisson)] self.vfractionfunctions = [dolfin.Function(self.v) for j in range(len(self.compartments))] # Each reaction diffusion eqn should be indexed to a single volume fraction function # Each reaction diffusion eqn should be indexed to a single potential function # Each reaction diffusion eqn should be indexed to a single valence self.dt = dolfin.Constant(0.1) self.eqs = [] self.phi = dolfin.Constant(phi) for membrane in self.membranes: self.potentials.extend([membrane]) membrane.phi_m = np.ones(self.N)*membrane.phi_m self.num_membrane_potentials = len(self.potentials) # improve this """ Assemble the equations for the system Order of equations: for compartment in compartments: for species in compartment.species diffusion (in order) volume potential for electrodiffusion Membrane potentials """ for j,compartment in enumerate(self.compartments): self.vfractionfunctions[j].vector()[:] = self.volfrac[compartment] # Set the reaction-diffusion equations for j,(trial,old,test,source,D,diffusor) in enumerate(zip(self.trialfunctions[:self.numdiffusers],self.prev_value_[:self.numdiffusers] \ ,self.testfunctions[:self.numdiffusers], self.sourcefunctions[:self.numdiffusers]\ ,self.diffusivities,self.diffusors)): """ This instance of the loop corresponds to a diffusion species in self.diffusors """ compartment_index = self.compartments.index(diffusor[0]) # we are in this compartment try: phi_index = self.electrostatic_compartments.index(diffusor[0]) + self.numdiffusers self.eqs.extend([ trial*test*dx-test*old*dx+ \ self.dt*(inner(D*nabla_grad(trial),nabla_grad(test)) + \ dolfin.Constant(diffusor[1].z/phi)*inner(D*trial*nabla_grad(self.prev_value[phi_index]),nabla_grad(test)))*dx ]) """ self.eqs.extend([ trial*test*dx-test*old*dx+ \ self.dt*(inner(D*nabla_grad(trial),nabla_grad(test)) + \ dolfin.Constant(diffusor[1].z/phi)*inner(D*trial*nabla_grad(self.prev_value[phi_index]),nabla_grad(test)) - source*test)*dx ]) """ # electrodiffusion here except ValueError: # No electrodiffusion for this species self.eqs.extend([trial*test*dx-old*test*dx+self.dt*(inner(D*nabla_grad(trial),nabla_grad(test))- source*test)*dx ]) self.prev_value[j].vector()[:] = diffusor[0].value(diffusor[1]) self.diffusivities[j].vector()[:] = diffusor[2] #diffusor[0].setValue(diffusor[1],self.prev_value[j].vector().array()) # do this below instead self.full_assigner.assign(self.prev_value__,self.prev_value) self.full_assigner.assign(self.functions__,self.prev_value) # Initial guess for Newton """ Vectorize the values that aren't already vectorized """ for compartment in self.compartments: for j,(species, val) in enumerate(compartment.values.items()): try: length = len(val) compartment.internalVars.extend([(species,self.N,j*self.N)]) compartment.species_internal_lookup[species] = j*self.N except: compartment.values[species]= np.ones(self.N)*val #compartment.internalVars.extend([(species,self.N,j*self.N)]) compartment.species_internal_lookup[species] = j*self.N # Set the electrostatic eqns # Each equation is associated with a single compartment as defined in for j,(trial, test, source, eps, compartment) in enumerate(zip(self.trialfunctions[self.numdiffusers:],self.testfunctions[self.numdiffusers:], \ self.sourcefunctions[self.numdiffusers:], self.permitivities, self.electrostatic_compartments)): # set the permitivity for this equation eps.vector()[:] = F**2*self.volfrac[compartment]/R/T \ *sum([compartment.diffusivities[species]*species.z**2*compartment.value(species) for species in compartment.species],axis=0) self.eqs.extend( [inner(eps*nabla_grad(trial),nabla_grad(test))*dx - source*test*dx] ) compartmentfluxes = self.updateSources() # """ Set indices for the "internal variables" List of tuples (compartment/membrane, num of variables) Each compartment or membrane has method getInternalVars() get_dot_InternalVars(t,values) get_jacobian_InternalVars(t,values) setInternalVars(values) The internal variables for each object are stored starting in y[obj.system_state_offset] """ self.internalVars = [] index = 0 for membrane in self.membranes: index2 = 0 for channel in membrane.channels: channeltmp = channel.getInternalVars() if channeltmp is not None: self.internalVars.extend([ (channel, len(channeltmp),index2)]) channel.system_state_offset = index+index2 channel.internalLength = len(channeltmp) index2+=len(channeltmp) tmp = membrane.getInternalVars() if tmp is not None: self.internalVars.extend( [(membrane,len(tmp),index)] ) membrane.system_state_offset = index index += len(tmp) membrane.points = self.N """ Compartments at the end, so we may reuse some computations """ for compartment in self.compartments: index2 = 0 compartment.system_state_offset = index # offset for this object in the overall state for species, value in compartment.values.items(): compartment.internalVars.extend([(species,len(compartment.value(species)),index2)]) index2 += len(value) tmp = compartment.getInternalVars() self.internalVars.extend( [(compartment,len(tmp),index)] ) index += len(tmp) compartment.points = self.N for key, val in self.volfrac.items(): self.volfrac[key] = val*np.ones(self.N) """ Solver setup below self.pdewolver is the FEM solver for the concentrations self.ode is the ODE solver for the membrane and volume fraction The ODE solve uses LSODA """ # Define the problem and the solver self.equation = sum(self.eqs) self.equation_ = dolfin.action(self.equation, self.functions__) self.J = dolfin.derivative(self.equation_,self.functions__) ffc_options = {"optimize": True, \ "eliminate_zeros": True, \ "precompute_basis_const": True, \ "precompute_ip_const": True, \ "quadrature_degree": 2} self.problem = dolfin.NonlinearVariationalProblem(self.equation_, self.functions__, None, self.J, form_compiler_parameters=ffc_options) self.pdesolver = dolfin.NonlinearVariationalSolver(self.problem) self.pdesolver.parameters['newton_solver']['absolute_tolerance'] = 1e-9 self.pdesolver.parameters['newton_solver']['relative_tolerance'] = 1e-9 """ ODE integrator here. Add ability to customize the parameters in the future """ self.t = 0.0 self.odesolver = ode(self.ode_rhs) # self.odesolver.set_integrator('lsoda', nsteps=3000, first_step=1e-6, max_step=5e-3 ) self.odesolver.set_initial_value(self.getInternalVars(),self.t) self.isAssembled = True
def run_with_params(Tb, mu_value, k_s, path): run_time_init = clock() mesh = BoxMesh(Point(0.0, 0.0, 0.0), Point(mesh_width, mesh_width, mesh_height), nx, ny, nz) pbc = PeriodicBoundary() WE = VectorElement('CG', mesh.ufl_cell(), 2) SE = FiniteElement('CG', mesh.ufl_cell(), 1) WSSS = FunctionSpace(mesh, MixedElement(WE, SE, SE, SE), constrained_domain=pbc) # W = FunctionSpace(mesh, WE, constrained_domain=pbc) # S = FunctionSpace(mesh, SE, constrained_domain=pbc) W = WSSS.sub(0).collapse() S = WSSS.sub(1).collapse() temperature_vals = [27.0 + 273, Tb + 273, 1300.0 + 273, 1305.0 + 273] temp_prof = TemperatureProfile(temperature_vals, element=S.ufl_element()) mu_a = mu_value # this was taken from the Blankenbach paper, can change Ep = b / temp_prof.delta mu_bot = exp(-Ep * (temp_prof.bottom * temp_prof.delta - 1573.0) + cc) * mu_a # TODO: verify exponentiation Ra = rho_0 * alpha * g * temp_prof.delta * h ** 3 / (kappa_0 * mu_a) w0 = rho_0 * alpha * g * temp_prof.delta * h ** 2 / mu_a tau = h / w0 p0 = mu_a * w0 / h log(mu_a, mu_bot, Ra, w0, p0) slip_vx = 1.6E-09 / w0 # Non-dimensional slip_velocity = Constant((slip_vx, 0.0, 0.0)) zero_slip = Constant((0.0, 0.0, 0.0)) time_step = 3.0E11 / tau * 2 dt = Constant(time_step) t_end = 3.0E15 / tau / 5.0 # Non-dimensional times u = Function(WSSS) # Instead of TrialFunctions, we use split(u) for our non-linear problem v, p, T, Tf = split(u) v_t, p_t, T_t, Tf_t = TestFunctions(WSSS) T0 = interpolate(temp_prof, S) mu_exp = Expression('exp(-Ep * (T_val * dTemp - 1573.0) + cc * x[2] / mesh_height)', Ep=Ep, dTemp=temp_prof.delta, cc=cc, mesh_height=mesh_height, T_val=T0, element=S.ufl_element()) Tf0 = interpolate(temp_prof, S) mu = Function(S) v0 = Function(W) v_theta = (1.0 - theta) * v0 + theta * v T_theta = (1.0 - theta) * T0 + theta * T Tf_theta = (1.0 - theta) * Tf0 + theta * Tf # TODO: Verify forms r_v = (inner(sym(grad(v_t)), 2.0 * mu * sym(grad(v))) - div(v_t) * p - T * v_t[2]) * dx r_p = p_t * div(v) * dx heat_transfer = Constant(k_s) * (Tf_theta - T_theta) * dt r_T = (T_t * ((T - T0) + dt * inner(v_theta, grad(T_theta))) # TODO: Inner vs dot + (dt / Ra) * inner(grad(T_t), grad(T_theta)) - T_t * heat_transfer) * dx v_melt = Function(W) z_hat = Constant((0.0, 0.0, 1.0)) # TODO: inner -> dot, take out Tf_t r_Tf = (Tf_t * ((Tf - Tf0) + dt * inner(v_melt, grad(Tf_theta))) + Tf_t * heat_transfer) * dx r = r_v + r_p + r_T + r_Tf bcv0 = DirichletBC(WSSS.sub(0), zero_slip, top) bcv1 = DirichletBC(WSSS.sub(0), slip_velocity, bottom) bcv2 = DirichletBC(WSSS.sub(0).sub(1), Constant(0.0), back) bcv3 = DirichletBC(WSSS.sub(0).sub(1), Constant(0.0), front) bcp0 = DirichletBC(WSSS.sub(1), Constant(0.0), bottom) bct0 = DirichletBC(WSSS.sub(2), Constant(temp_prof.surface), top) bct1 = DirichletBC(WSSS.sub(2), Constant(temp_prof.bottom), bottom) bctf1 = DirichletBC(WSSS.sub(3), Constant(temp_prof.bottom), bottom) bcs = [bcv0, bcv1, bcv2, bcv3, bcp0, bct0, bct1, bctf1] t = 0 count = 0 files = DefaultDictByKey(partial(create_xdmf, path)) while t < t_end: mu.interpolate(mu_exp) rhosolid = rho_0 * (1.0 - alpha * (T0 * temp_prof.delta - 1573.0)) deltarho = rhosolid - rho_melt # TODO: project (accuracy) vs interpolate assign(v_melt, project(v0 - darcy * (grad(p) * p0 / h - deltarho * z_hat * g) / w0, W)) # TODO: Written out one step later? # v_melt.assign(v0 - darcy * (grad(p) * p0 / h - deltarho * yvec * g) / w0) # TODO: use nP after to avoid projection? solve(r == 0, u, bcs) nV, nP, nT, nTf = u.split() # TODO: write with Tf, ... etc if count % output_every == 0: time_left(count, t_end / time_step, run_time_init) # TODO: timestep vs dt # TODO: Make sure all writes are to the same function for each time step files['T_fluid'].write(nTf, t) files['p'].write(nP, t) files['v_solid'].write(nV, t) files['T_solid'].write(nT, t) files['mu'].write(mu, t) files['v_melt'].write(v_melt, t) files['gradp'].write(project(grad(nP), W), t) files['rho'].write(project(rhosolid, S), t) files['Tf_grad'].write(project(grad(Tf), W), t) files['advect'].write(project(dt * dot(v_melt, grad(nTf))), t) files['ht'].write(project(heat_transfer, S), t) assign(T0, nT) assign(v0, nV) assign(Tf0, nTf) t += time_step count += 1 log('Case mu={}, Tb={}, k={} complete. Run time = {:.2f} minutes'.format(mu_a, Tb, k_s, (clock() - run_time_init) / 60.0))
def __init__(self, PD, DD, verbosity): """ Constructor :param ProblemData PD: Problem information and various mesh-region <-> xs-material mappings :param SNDiscretization DD: Discretization data :param int verbosity: Verbosity level. """ self.max_group_GS_it = parameters["flux_module"]["group_GS"]["max_niter"] self.group_GS = self.max_group_GS_it > 0 try: PD.eigenproblem except AttributeError: PD.distribute_material_data(DD.cell_regions, DD.M) if PD.eigenproblem and self.group_GS: print "Group Gauss-Seidel for eigenproblem not yet supported - switching to all-group coupled solution method." self.group_GS = False if DD.G == 1: self.group_GS = True self.max_group_GS_it = 1 DD.init_solution_spaces(self.group_GS) super(EllipticSNFluxModule, self).__init__(PD, DD, verbosity) if PD.fixed_source_problem: self.vals_Q = numpy.empty(self.DD.ndof,dtype='float64') if self.verb > 1: print0("Defining coefficient functions and tensors") if self.DD.V is self.DD.Vpsi1 or DD.G == 1: # shallow copies of trial/test functions - allows unified treatment of both mixed/single versions self.u = [self.u]*self.DD.G self.v = [self.v]*self.DD.G self.slns_mg = [self.sln] for g in range(1, self.DD.G): self.slns_mg.append(Function(self.DD.Vpsi1)) else: self.u = split(self.u) self.v = split(self.v) # self.group_assigner = [] # for g in range(self.DD.G): # self.group_assigner.append(FunctionAssigner(self.DD.V.sub(g), self.DD.Vpsi1)) # auxiliary single-group angular fluxes (used for monitoring convergence of the group GS iteration and computing # the true forward/adjoint angular fluxes) self.aux_slng = Function(self.DD.Vpsi1) # multigroup angular fluxes self.psi_mg = [] for g in range(self.DD.G): self.psi_mg.append(Function(self.DD.Vpsi1)) # multigroup adjoint angular fluxes self.adj_psi_mg = [] for g in range(self.DD.G): self.adj_psi_mg.append(Function(self.DD.Vpsi1)) self.D = Function(self.DD.V0) self.L = PD.scattering_order-1 self.tensors = self.AngularTensors(self.DD.angular_quad, self.L) self.C = numpy.empty(self.L+1, Function) self.S = numpy.empty(self.L+1, Function) for l in range(self.L+1): self.C[l] = Function(self.DD.V0) self.S[l] = Function(self.DD.V0) for var in {"angular_flux", "adjoint_angular_flux"}: self.vis_files[var] = \ [ [ File(os.path.join(self.vis_folder, "{}_g{}_m{}.pvd".format(var,g,m)), "compressed") for m in range(self.DD.M) ] for g in range(self.DD.G) ] self.__define_boundary_terms()
def define_incompressible_functions(self): """ Define mixed functions necessary to formulate an incompressible fluid mechanics problem. The mixed function is also split using dolfin.split (for use in UFL variational forms) and u.split(), where u is a mixed function (for saving solutions separately). The names of the member data added to the instance of the SolidMechanicsProblem class are: - :code:`sys_v`: mixed function - :code:`ufl_velocity`: sub component corresponding to velocity - :code:`velocity`: copy of sub component for writing and assigning values - :code:`ufl_pressure`: sub component corresponding to pressure - :code:`pressure`: copy of sub component for writing and assigning values - :code:`sys_du`: mixed trial function - :code:`trial_vector`: sub component of mixed trial function - :code:`trial_scalar`: sub component of mixed trial function - :code:`test_vector`: sub component of mixed test function - :code:`test_scalar`: sub component of mixed test function If problem is unsteady, the following are also added: - :code:`sys_v0`: mixed function at previous time step - :code:`ufl_velocity0`: sub component corresponding to velocity - :code:`velocity0`: copy of sub component for writing and assigning values - :code:`ufl_pressure0`: sub component at previous time step - :code:`pressure0`: copy of sub component at previous time step """ self.sys_v = dlf.Function(self.functionSpace) self.ufl_velocity, self.ufl_pressure = dlf.split(self.sys_v) init = self.config['formulation']['initial_condition'] types_for_assign = (dlf.Constant, dlf.Expression) if init['velocity'] is not None \ and init['pressure'] is not None: if isinstance(init['velocity'], types_for_assign): self.velocity = dlf.Function( self.functionSpace.sub(0).collapse()) self.velocity.assign(init['velocity']) else: self.velocity = dlf.project( init['velocity'], self.functionSpace.sub(0).collapse()) if isinstance(init['pressure'], types_for_assign): self.pressure = dlf.Function( self.functionSpace.sub(1).collapse()) self.pressure.assign(init['pressure']) else: self.pressure = dlf.project( init['pressure'], self.functionSpace.sub(1).collapse()) elif init['velocity'] is not None: _, self.pressure = self.sys_v.split(deepcopy=True) if isinstance(init['velocity'], types_for_assign): self.velocity = dlf.Function( self.functionSpace.sub(0).collapse()) self.velocity.assign(init['velocity']) else: self.velocity = dlf.project( init['velocity'], self.functionSpace.sub(0).collapse()) elif init['pressure'] is not None: self.velocity, _ = self.sys_v.split(deepcopy=True) if isinstance(init['pressure'], types_for_assign): self.pressure = dlf.Function( self.functionSpace.sub(1).collapse()) self.pressure.assign(init['pressure']) else: self.pressure = dlf.project( init['pressure'], self.functionSpace.sub(1).collapse()) else: print("No initial conditions were provided") self.velocity, self.pressure = self.sys_v.split(deepcopy=True) self.velocity.rename("v", "velocity") self.pressure.rename("p", "pressure") self.sys_dv = dlf.TrialFunction(self.functionSpace) self.trial_vector, self.trial_scalar = dlf.split(self.sys_dv) self.test_vector, self.test_scalar = dlf.TestFunctions( self.functionSpace) if self.config['formulation']['time']['unsteady']: self.sys_v0 = self.sys_v.copy(deepcopy=True) self.ufl_velocity0, self.ufl_pressure0 = dlf.split(self.sys_v0) self.velocity0, self.pressure0 = self.sys_v0.split(deepcopy=True) self.velocity0.rename("v0", "velocity0") self.pressure0.rename("p0", "pressure0") self.define_ufl_acceleration() self.define_function_assigners() self.assigner_v2sys.assign(self.sys_v, [self.velocity, self.pressure]) return None