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, 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.AlternateMinimizationSolver( energy, [u, alpha], [bcs_u, bcs_alpha], parameters = alt_min_parameters) rP = model.rP(u, alpha, v, beta)*dx rN = model.rN(u, alpha, beta)*dx stability = StabilitySolver(mesh, energy, [u, alpha], [bcs_u, bcs_alpha], z, rayleigh=[rP, rN], 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
# set solution times t_init = 0. t_final = 4. t_1 = 1. dt = .1 observation_dt = .2 simulation_times = np.arange(t_init, t_final + .5 * dt, dt) # define PDE eldeg = 1 kappa = 1e-3 ad_diff = TimeDependentAD(mesh=meshsz, simulation_times=simulation_times, eldeg=eldeg, kappa=kappa) # plot mesh # dl.plot(mesh) # set parameters of PDE Vh = ad_diff.Vh[STATE] ic_expr = dl.Expression( 'min(0.5,exp(-100*(pow(x[0]-0.35,2) + pow(x[1]-0.7,2))))', element=Vh.ufl_element()) true_initial_condition = dl.interpolate(ic_expr, Vh).vector() utrue = ad_diff.generate_vector(STATE) x = [utrue, true_initial_condition, None] ad_diff.solveFwd(x[STATE], x) # plot solution plt_times = [0, 0.4, 1., 2., 3., 4.] fig = ad_diff.plot_soln(x[STATE], plt_times, (12, 8)) plt.subplots_adjust(wspace=0.1, hspace=0.2) plt.savefig(os.path.join(os.getcwd(), 'properties/solns.png'), bbox_inches='tight')
class Right(dol.SubDomain): def inside(self, x, on_boundary): return dol.near(x[0], 1.0) # Initialize boundary instances left = Left() right = Right() # Initialize mesh function for boundary domains boundaries = dol.MeshFunction("size_t", mesh, mesh.topology().dim()-1) boundaries.set_all(0) left.mark(boundaries, 1) right.mark(boundaries, 2) # # Boundary conditions bcs = [dol.DirichletBC(FS, dol.Expression(('5', '1'), degree = 2), boundaries, 1), dol.DirichletBC(FS, dol.Expression(('1', '2-exp(1)'), degree = 2), boundaries, 2)] """ bc_l = dol.DirichletBC(FS, dol.Expression(("5","0"), degree = 2), 'x[0] < DOLFIN_EPS') bc_r = dol.DirichletBC(FS, dol.Expression(("0","1"), degree = 2), 'x[0] > 1- DOLFIN_EPS') bc_left = dol.DirichletBC(FS, dol.Expression(("5","0"), degree = 2),left_boundary, method='pointwise') bc_right = dol.DirichletBC(FS, dol.Expression(("0","1"), degree = 2),right_boundary, method='pointwise') def boundary(x, on_boundary): return (abs(x[0]) < 1e-15) or (abs(x[0]-1.0)< 1e-15) bc = dol.DirichletBC(FS, dol.Expression(("5*(1-x[0])","1-x[0]"), degree = 2), boundary) """ # Define test functions f_1, f_2 = dol.TestFunctions(FS) # Split system function to access components
nproc = dl.MPI.size(mesh.mpi_comm()) Vh2 = dl.FunctionSpace(mesh, 'Lagrange', 2) Vh1 = dl.FunctionSpace(mesh, 'Lagrange', 1) Vh = [Vh2, Vh1, Vh2] ndofs = [Vh[STATE].dim(), Vh[PARAMETER].dim(), Vh[ADJOINT].dim()] if rank == 0: print(sep, "Set up the mesh and finite element spaces", sep) print("Number of dofs: STATE={0}, PARAMETER={1}, ADJOINT={2}".format( *ndofs)) # Initialize Expressions f = dl.Constant(0.0) u_bdr = dl.Expression("x[1]", degree=1) u_bdr0 = dl.Constant(0.0) bc = dl.DirichletBC(Vh[STATE], u_bdr, u_boundary) bc0 = dl.DirichletBC(Vh[STATE], u_bdr0, u_boundary) def pde_varf(u, m, p): return dl.exp(m) * dl.inner(dl.nabla_grad(u), dl.nabla_grad(p)) * dl.dx - f * p * dl.dx pde = PDEVariationalProblem(Vh, pde_varf, bc, bc0, is_fwd_linear=True) pde.solver = dl.PETScKrylovSolver(mesh.mpi_comm(), "cg", amg_method()) pde.solver_fwd_inc = dl.PETScKrylovSolver(mesh.mpi_comm(), "cg", amg_method()) pde.solver_adj_inc = dl.PETScKrylovSolver(mesh.mpi_comm(), "cg", amg_method())
def numerical_test(user_parameters): 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 # Define Dirichlet boundaries comm = MPI.comm_world default_parameters = getDefaultParameters() default_parameters.update(user_parameters) # FIXME: Not nice parameters = default_parameters parameters['code']['script'] = __file__ # import pdb; pdb.set_trace() signature = hashlib.md5(str(parameters).encode('utf-8')).hexdigest() outdir = '../output/traction/{}-{}CPU'.format(signature, size) Path(outdir).mkdir(parents=True, exist_ok=True) log(LogLevel.INFO, 'INFO: Outdir is: ' + outdir) BASE_DIR = os.path.dirname(os.path.realpath(__file__)) print(parameters['geometry']) d = { 'Lx': parameters['geometry']['Lx'], 'Ly': parameters['geometry']['Ly'], 'h': parameters['material']['ell'] / parameters['geometry']['n'] } geom_signature = hashlib.md5(str(d).encode('utf-8')).hexdigest() # -------------------------------------------------------- # Mesh creation with gmsh Lx = parameters['geometry']['Lx'] Ly = parameters['geometry']['Ly'] n = parameters['geometry']['n'] ell = parameters['material']['ell'] fname = os.path.join('../meshes', 'strip-{}'.format(geom_signature)) resolution = max(parameters['geometry']['n'] * Lx / ell, 5 / (Ly * 10)) resolution = 3 geom = mshr.Rectangle(dolfin.Point(-Lx / 2., -Ly / 2.), dolfin.Point(Lx / 2., Ly / 2.)) # mesh = mshr.generate_mesh(geom, n * int(float(Lx / ell))) mesh = mshr.generate_mesh(geom, resolution) log( LogLevel.INFO, 'Number of dofs: {}'.format( mesh.num_vertices() * (1 + parameters['general']['dim']))) if size == 1: meshf = dolfin.File(os.path.join(outdir, "mesh.xml")) plot(mesh) plt.savefig(os.path.join(outdir, "mesh.pdf"), bbox_inches='tight') with open(os.path.join(outdir, 'parameters.yaml'), "w") as f: yaml.dump(parameters, f, default_flow_style=False) Lx = parameters['geometry']['Lx'] ell = parameters['material']['ell'] savelag = 1 # mf = dolfin.MeshFunction("size_t", mesh, 1, 0) # Function Spaces V_u = dolfin.VectorFunctionSpace(mesh, "CG", 1) V_alpha = dolfin.FunctionSpace(mesh, "CG", 1) L2 = dolfin.FunctionSpace(mesh, "DG", 0) u = dolfin.Function(V_u, name="Total displacement") u.rename('u', 'u') alpha = Function(V_alpha) alpha_old = dolfin.Function(alpha.function_space()) alpha.rename('alpha', 'alpha') dalpha = TrialFunction(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) v, beta = dolfin.split(z) left = dolfin.CompiledSubDomain("near(x[0], -Lx/2.)", Lx=Lx) right = dolfin.CompiledSubDomain("near(x[0], Lx/2.)", Lx=Lx) bottom = dolfin.CompiledSubDomain("near(x[1],-Ly/2.)", Ly=Ly) top = dolfin.CompiledSubDomain("near(x[1],Ly/2.)", Ly=Ly) left_bottom_pt = dolfin.CompiledSubDomain( "near(x[0],-Lx/2.) && 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) bottom.mark(mf, 3) 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), left_bottom_pt, method="pointwise") ] bcs_alpha = [] bcs = {"damage": bcs_alpha, "elastic": bcs_u} ds = dolfin.Measure("ds", subdomain_data=mf) dx = dolfin.Measure("dx", metadata=parameters['compiler'], domain=mesh) ell = parameters['material']['ell'] # ----------------------- # 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 = sym(grad(u)) eps0t = Expression([['t', 0.], [0., 't']], t=0., degree=0) lmbda0 = parameters['material']['E'] * parameters['material']['nu'] / ( 1. - parameters['material']['nu'])**2. mu0 = parameters['material']['E'] / 2. / (1.0 + parameters['material']['nu']) nu = parameters['material']['nu'] sigma0 = lmbda0 * tr(eps) * dolfin.Identity( parameters['general']['dim']) + 2 * mu0 * eps e1 = Constant((1., 0)) _sigma = ((1 - alpha)**2. + k_res) * sigma0 _snn = dolfin.dot(dolfin.dot(_sigma, e1), e1) # ------------------- ell = parameters['material']['ell'] E = parameters['material']['E'] def elastic_energy(u, alpha, E=E, nu=nu, eps0t=eps0t, k_res=k_res): a = (1 - alpha)**2. + k_res eps = sym(grad(u)) Wt = a*E*nu/(2*(1-nu**2.)) * tr(eps)**2. \ + a*E/(2.*(1+nu))*(inner(eps, eps)) return Wt * dx def dissipated_energy(alpha, w_1=w_1, ell=ell): return w_1 * (alpha + ell**2. * inner(grad(alpha), grad(alpha))) * dx def total_energy(u, alpha, k_res=k_res, w_1=w_1, E=E, nu=nu, ell=ell, eps0t=eps0t): elastic_energy_ = elastic_energy(u, alpha, E=E, nu=nu, eps0t=eps0t, k_res=k_res) dissipated_energy_ = dissipated_energy(alpha, w_1=w_1, ell=ell) return elastic_energy_ + dissipated_energy_ energy = total_energy(u, alpha) # Hessian = derivative(derivative(Wppt*dx, z, TestFunction(Z)), z, TrialFunction(Z)) def create_output(outdir): 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, "postprocess.xdmf")) file_postproc.parameters["functions_share_mesh"] = True file_postproc.parameters["flush_output"] = True file_eig = dolfin.XDMFFile(os.path.join(outdir, "perturbations.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 file_ealpha = dolfin.XDMFFile(os.path.join(outdir, "elapha.xdmf")) file_ealpha.parameters["functions_share_mesh"] = True file_ealpha.parameters["flush_output"] = True files = { 'output': file_out, 'postproc': file_postproc, 'eigen': file_eig, 'bifurcation': file_bif, 'ealpha': file_ealpha } return files files = create_output(outdir) solver = EquilibriumAM(energy, state, bcs, parameters=parameters) stability = StabilitySolver(energy, state, bcs, parameters=parameters) linesearch = LineSearch(energy, state) load_steps = np.linspace(parameters['loading']['load_min'], parameters['loading']['load_max'], parameters['loading']['n_steps']) time_data = [] time_data_pd = [] spacetime = [] lmbda_min_prev = 1e-6 bifurcated = False bifurcation_loads = [] save_current_bifurcation = False bifurc_i = 0 alpha_bif = dolfin.Function(V_alpha) alpha_bif_old = dolfin.Function(V_alpha) bifurcation_loads = [] to_remove = [] perturb = False from matplotlib import cm log(LogLevel.INFO, '{}'.format(parameters)) for step, load in enumerate(load_steps): plt.clf() mineigs = [] exhaust_modes = [] log(LogLevel.CRITICAL, '====================== STEPPING ==========================') log(LogLevel.CRITICAL, 'CRITICAL: Solving load t = {:.2f}'.format(load)) alpha_old.assign(alpha) ut.t = load # (time_data_i, am_iter) = solver.solve(outdir) (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')) mineig = stability.mineig if hasattr(stability, 'mineig') else 0.0 # log(LogLevel.INFO, 'INFO: lmbda min {}'.format(lmbda_min_prev)) log(LogLevel.INFO, 'INFO: mineig {:.5e}'.format(mineig)) 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.INFO, 'INFO: About to bifurcate load {:.3f} step {}'.format( load, step)) bifurcation_loads.append(load) modes = np.where(stability.eigs < 0)[0] bifurc_i += 1 lmbda_min_prev = mineig if hasattr(stability, 'mineig') else 0. # we postpone the update after the stability check if stable: solver.update() log( LogLevel.INFO, ' Current state is{}stable'.format( ' ' if stable else ' un')) else: # Continuation iteration = 1 mineigs.append(stability.mineig) while stable == False: log(LogLevel.INFO, 'Continuation iteration {}'.format(iteration)) plt.close('all') pert = [(_v, _b) for _v, _b in zip( stability.perturbations_v, stability.perturbations_beta)] _nmodes = len(pert) en_vars = [] h_opts = [] hbounds = [] en_perts = [] for i, mode in enumerate(pert): h_opt, bounds, enpert, en_var = linesearch.search( { 'u': u, 'alpha': alpha, 'alpha_old': alpha_old }, mode[0], mode[1]) h_opts.append(h_opt) en_vars.append(en_var) hbounds.append(bounds) en_perts.append(enpert) if rank == 0: # fig = plt.figure(dpi=80, facecolor='w', edgecolor='k') # plt.subplot(1, 4, 1) # plt.set_cmap('binary') # # dolfin.plot(mesh, alpha = 1.) # dolfin.plot( # project(stability.inactivemarker1, L2), alpha = 1., vmin=0., vmax=1.) # plt.title('derivative zero') # plt.subplot(1, 4, 2) # # dolfin.plot(mesh, alpha = .5) # dolfin.plot( # project(stability.inactivemarker2, L2), alpha = 1., vmin=0., vmax=1.) # plt.title('ub tolerance') # plt.subplot(1, 4, 3) # # dolfin.plot(mesh, alpha = .5) # dolfin.plot( # project(stability.inactivemarker3, L2), alpha = 1., vmin=0., vmax=1.) # plt.title('alpha-alpha_old') # plt.subplot(1, 4, 4) # # dolfin.plot(mesh, alpha = .5) # dolfin.plot( # project(stability.inactivemarker4, L2), alpha = 1., vmin=0., vmax=1.) # plt.title('intersec deriv, ub') # plt.savefig(os.path.join(outdir, "inactivesets-{:.3f}-{:d}.pdf".format(load, iteration))) # plt.set_cmap('hot') fig = plt.figure(dpi=80, facecolor='w', edgecolor='k') for i, mode in enumerate(pert): plt.subplot(2, _nmodes + 1, i + 2) plt.axis('off') plot(mode[1], cmap=cm.ocean) plt.title( 'mode {} $h^*$={:.3f}\n $\\lambda_{}$={:.3e} \n $\\Delta E$={:.3e}' .format(i, h_opts[i], i, stability.eigs[i], en_vars[i]), fontsize=15) # plt.title('mode {}' # .format(i), fontsize= 15) plt.subplot(2, _nmodes + 1, _nmodes + 2 + 1 + i) plt.axis('off') _pert_beta = mode[1] _pert_v = mode[0] if hbounds[i][0] == hbounds[i][1] == 0: plt.plot(hbounds[i][0], 0) else: hs = np.linspace(hbounds[i][0], hbounds[i][1], 100) z = np.polyfit( np.linspace(hbounds[i][0], hbounds[i][1], len(en_perts[i])), en_perts[i], parameters['stability']['order']) p = np.poly1d(z) plt.plot(hs, p(hs), c='k') plt.plot(np.linspace(hbounds[i][0], hbounds[i][1], len(en_perts[i])), en_perts[i], marker='o', markersize=10, c='k') # import pdb; pdb.set_trace() plt.plot(hs, stability.eigs[i] * hs**2, c='r', lw=.3) plt.axvline(h_opts[i], lw=.3, c='k') plt.axvline(0, lw=2, c='k') # plt.title('{}'.format(i)) plt.tight_layout(h_pad=1.5, pad=1.5) # plt.legend() plt.savefig( os.path.join( outdir, "modes-{:.3f}-{}.pdf".format(load, iteration))) plt.close(fig) plt.clf() log(LogLevel.INFO, 'plotted modes') cont_data_pre = compile_continuation_data(state, energy) log(LogLevel.INFO, 'Estimated energy variation {:.3e}'.format(en_var)) Ealpha = Function(V_alpha) Ealpha.vector()[:] = assemble(stability.inactiveEalpha)[:] Ealpha.rename('Ealpha-{}'.format(iteration), 'Ealpha-{}'.format(iteration)) with files['ealpha'] as file: file.write(Ealpha, load) save_current_bifurcation = True # pick the first of the non exhausted modes- non_zero_h = np.where(abs(np.array(h_opts)) > DOLFIN_EPS)[0] log(LogLevel.INFO, 'Nonzero h {}'.format(non_zero_h)) avail_modes = set(non_zero_h) - set(exhaust_modes) opt_mode = 0 # opt_mode = np.argmin(en_vars) log(LogLevel.INFO, 'Energy vars {}'.format(en_vars)) log( LogLevel.INFO, 'Pick bifurcation mode {} out of {}'.format( opt_mode, len(en_vars))) # h_opt = min(h_opts[opt_mode],1.e-2) h_opt = h_opts[opt_mode] perturbation_v = stability.perturbations_v[opt_mode] perturbation_beta = stability.perturbations_beta[opt_mode] minmode = stability.minmode (perturbation_v, perturbation_beta) = minmode.split(deepcopy=True) # (perturbation_v, perturbation_beta) = stability.perturbation_v, stability.perturbation_beta def energy_1d(h): #return assemble(energy_functional(u + h * perturbation_v, alpha + h * perturbation_beta)) u_ = Function(u.function_space()) alpha_ = Function(alpha.function_space()) u_.vector( )[:] = u.vector()[:] + h * perturbation_v.vector()[:] alpha_.vector()[:] = alpha.vector( )[:] + h * perturbation_beta.vector()[:] u_.vector().vec().ghostUpdate() alpha_.vector().vec().ghostUpdate() return assemble(total_energy(u_, alpha_)) (hmin, hmax) = linesearch.admissible_interval( alpha, alpha_old, perturbation_beta) hs = np.linspace(hmin, hmax, 20) energy_vals = np.array([energy_1d(h) for h in hs]) stability.solve(solver.damage.problem.lb) Hzz = assemble(stability.H * minmode * minmode) Gz = assemble(stability.J * minmode) mineig_z = Hzz / assemble(dot(minmode, minmode) * dx) energy_vals_quad = energy_1d(0) + hs * Gz + hs**2 * Hzz / 2 # h_opt = hs[np.argmin(energy_vals)] print('computed h_opt {}'.format(hs[np.argmin(energy_vals)])) print("%%%%%%%%% ", mineig_z, "-", mineig) if rank == 0: plt.figure() # plt.plot(hs,energy_vals, marker = 'o') plt.plot(hs, energy_vals, marker='o', label="exact") plt.plot(hs, energy_vals_quad, label="quadratic approximation") plt.legend() plt.title("eig {:.4f} vs {:.4f} expected".format( mineig_z, mineig)) plt.axvline(h_opt) # import pdb; pdb.set_trace() plt.savefig( os.path.join(outdir, "energy1d-{:.3f}.pdf".format(load))) iteration += 1 log(LogLevel.CRITICAL, 'Bifurcating') save_current_bifurcation = True alpha_bif.assign(alpha) alpha_bif_old.assign(alpha_old) # admissible perturbation 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() log(LogLevel.INFO, 'min a+h_opt beta_{} = {}'.format(opt_mode, min(aval))) log(LogLevel.INFO, 'max a+h_opt beta_{} = {}'.format(opt_mode, max(aval))) log(LogLevel.INFO, 'Solving equilibrium from perturbed state') (time_data_i, am_iter) = solver.solve(outdir) # (time_data_i, am_iter) = solver.solve() log(LogLevel.INFO, 'Checking stability of new state') (stable, negev) = stability.solve(solver.damage.problem.lb) mineigs.append(stability.mineig) log( LogLevel.INFO, 'Continuation iteration {}, current state is{}stable'. format(iteration, ' ' if stable else ' un')) cont_data_post = compile_continuation_data(state, energy) DeltaE = (cont_data_post['energy'] - cont_data_pre['energy']) relDeltaE = (cont_data_post['energy'] - cont_data_pre['energy']) / cont_data_pre['energy'] release = DeltaE < 0 and np.abs( DeltaE) > parameters['stability']['cont_rtol'] log( LogLevel.INFO, 'Continuation: post energy {} - pre energy {}'.format( cont_data_post['energy'], cont_data_pre['energy'])) log( LogLevel.INFO, 'Actual absolute energy variation Delta E = {:.7e}'.format( DeltaE)) log( LogLevel.INFO, 'Actual relative energy variation relDelta E = {:.7e}'. format(relDeltaE)) log(LogLevel.INFO, 'Iter {} mineigs = {}'.format(iteration, mineigs)) if rank == 0: plt.figure() plt.plot(mineigs, marker='o') plt.axhline(0.) plt.savefig( os.path.join(outdir, "mineigs-{:.3f}.pdf".format(load))) # continuation criterion if abs(np.diff(mineigs)[-1]) > 1e-10: log(LogLevel.INFO, 'Min eig change = {:.3e}'.format(np.diff(mineigs)[-1])) log(LogLevel.INFO, 'Continuing perturbations') else: log(LogLevel.INFO, 'Min eig change = {:.3e}'.format(np.diff(mineigs)[-1])) log(LogLevel.CRITICAL, 'We are stuck in the matrix') log(LogLevel.WARNING, 'Exploring next mode') exhaust_modes.append(opt_mode) # import pdb; pdb.set_trace() log(LogLevel.WARNING, 'Continuing load program') break # # if not release: # log(LogLevel.CRITICAL, 'Small nergy release , we are stuck in the matrix') # log(LogLevel.CRITICAL, 'No decrease in energy, we are stuck in the matrix') # log(LogLevel.WARNING, 'Continuing load program') # import pdb; pdb.set_trace() # break # else: # # warn # log(LogLevel.CRITICAL, 'Found zero increment, we are stuck in the matrix') # log(LogLevel.WARNING, 'Exploring next mode') # exhaust_modes.append(opt_mode) # import pdb; pdb.set_trace() # # log(LogLevel.WARNING, 'Continuing load program') # # break solver.update() log(LogLevel.INFO, 'bifurcation loads : {}'.format(bifurcation_loads)) np.save(os.path.join(outdir, 'bifurcation_loads'), bifurcation_loads, allow_pickle=True, fix_imports=True) if save_current_bifurcation: time_data_i['h_opt'] = h_opt time_data_i['max_h'] = hbounds[opt_mode][1] time_data_i['min_h'] = hbounds[opt_mode][0] modes = np.where(stability.eigs < 0)[0] leneigs = len(modes) maxmodes = min(3, leneigs) with files['bifurcation'] as file: for n in range(len(pert)): mode = dolfin.project(stability.perturbations_beta[n], V_alpha) modename = 'beta-%d' % n mode.rename(modename, modename) log(LogLevel.INFO, 'Saved mode {}'.format(modename)) file.write(mode, load) # with files['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'), en_perts, allow_pickle=True, fix_imports=True) with files['eigen'] 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') file.write(_v, load) file.write(_beta, load) # save_current_bifurcation = False time_data_i["load"] = load time_data_i["alpha_max"] = max(alpha.vector()[:]) time_data_i["elastic_energy"] = dolfin.assemble( elastic_energy(u, alpha, E=E, nu=nu, eps0t=eps0t, k_res=k_res)) time_data_i["dissipated_energy"] = dolfin.assemble( (w + w_1 * parameters['material']['ell']**2. * inner(grad(alpha), grad(alpha))) * 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 time_data_i["sigma"] = 1 / Ly * dolfin.assemble(_snn * ds(1)) # import pdb; pdb.set_trace() log( LogLevel.INFO, "Load/time step {:.4g}: converged in iterations: {:3d}, err_alpha={:.4e}" .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) with files['output'] as file: file.write(alpha, load) file.write(u, load) with files['postproc'] as file: file.write_checkpoint(alpha, "alpha-{}".format(step), step, append=True) file.write_checkpoint(u, "u-{}".format(step), step, append=True) log(LogLevel.INFO, 'INFO: written postprocessing step {}'.format(step)) time_data_pd.to_json(os.path.join(outdir, "time_data.json")) if rank == 0: # plt.clf() # if load>1.1: # import pdb; pdb.set_trace() # plt.plot(time_data_i["alpha_error"], marker='o') # plt.title('error, criterion: {}'.format(parameters['equilibrium']['criterion'])) # plt.axhline(parameters['equilibrium']['tol']) # plt.savefig(os.path.join(outdir, 'errors-{}.pdf'.format(step))) # plt.clf() # plt.colorbar(plot(alpha)) # fig = plt.figure() # plot(alpha) # plt.savefig(os.path.join(outdir, 'alpha.pdf')) # log(LogLevel.INFO, "Saved figure: {}".format(os.path.join(outdir, 'alpha.pdf'))) plt.close('all') fig = plt.figure() for i, d in enumerate(time_data_pd['eigs']): # if d is not (np.inf or np.nan or float('inf')): if np.isfinite(d).all(): lend = len(d) if isinstance(d, np.ndarray) else 1 plt.scatter([(time_data_pd['load'].values)[i]] * lend, d, c=np.where(np.array(d) < 0., 'red', 'black')) plt.axhline(0, c='k', lw=2.) plt.xlabel('t') # [plt.axvline(b) for b in bifurcation_loads] # import pdb; pdb.set_trace() log(LogLevel.INFO, 'Spectrum bifurcation loads : {}'.format(bifurcation_loads)) plt.xticks(list(plt.xticks()[0]) + bifurcation_loads) [plt.axvline(bif, lw=2, c='k') for bif in bifurcation_loads] plt.savefig(os.path.join(outdir, "spectrum.pdf"), bbox_inches='tight') # plt.plot() return time_data_pd, outdir
def source(t,x1,x2): delta =dl.Expression('M*exp(-(x[0]-x1)*(x[0]-x1)/(a*a)-(x[1]-x2)*(x[1]-x2)/(a*a))/a*(1-2*pi2*f02*t*t)*exp(-pi2*f02*t*t)' ,pi2=np.pi**2,a=6E-2, f02=f02, M=1E5,x1=x1,x2=x2,t=t,degree=1) return delta
def __init__(self, Vh, gamma, delta, locations, m_true, Theta = None, pen = 1e1, order=2, rel_tol=1e-12, max_iter=1000): """ Construct the prior model. Input: - :code:`Vh`: the finite element space for the parameter - :code:`gamma` and :code:`delta`: the coefficients in the PDE - :code:`locations`: the points :math:`x_i` at which we assume to know the true value of the parameter - :code:`m_true`: the true model - :code:`Theta`: the SPD tensor for anisotropic diffusion of the PDE - :code:`pen`: a penalization parameter for the mollifier """ assert delta != 0. or pen != 0, "Intrinsic Gaussian Prior are not supported" self.Vh = Vh trial = dl.TrialFunction(Vh) test = dl.TestFunction(Vh) if Theta == None: varfL = dl.inner(dl.nabla_grad(trial), dl.nabla_grad(test))*dl.dx else: varfL = dl.inner(Theta*dl.grad(trial), dl.grad(test))*dl.dx varfM = dl.inner(trial,test)*dl.dx # self.M_PETScMatrix=dl.PETScMatrix() # dl.assemble(varfM,tensor=self.M_PETScMatrix) self.M = dl.assemble(varfM) # self.M_PETScMatrix.assign(self.M) # self.M_PETScMatrix = dl.assemble(varfM) 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 #mfun = Mollifier(gamma/delta, dl.inv(Theta), order, locations) mfun = dl.Expression(code_Mollifier, degree = Vh.ufl_element().degree()+2) mfun.l = gamma/delta mfun.o = order mfun.theta0 = 1./Theta.theta0 mfun.theta1 = 1./Theta.theta1 mfun.alpha = Theta.alpha for ii in range(locations.shape[0]): mfun.addLocation(locations[ii,0], locations[ii,1]) varfmo = mfun*dl.inner(trial,test)*dl.dx MO = dl.assemble(pen*varfmo) self.A = dl.assemble(gamma*varfL+delta*varfM + pen*varfmo) if dlversion() <= (1,6,0): self.Asolver = dl.PETScKrylovSolver("cg", amg_method()) else: self.Asolver = dl.PETScKrylovSolver(self.Vh.mesh().mpi_comm(), "cg", amg_method()) self.Asolver.set_operator(self.A) self.Asolver.parameters["maximum_iterations"] = max_iter self.Asolver.parameters["relative_tolerance"] = rel_tol self.Asolver.parameters["error_on_nonconvergence"] = True self.Asolver.parameters["nonzero_initial_guess"] = False 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.FunctionSpace(Vh.mesh(), 'Quadrature', qdegree) else: element = dl.FiniteElement("Quadrature", Vh.mesh().ufl_cell(), qdegree, quad_scheme="default") Qh = dl.FunctionSpace(Vh.mesh(), element) ph = dl.TrialFunction(Qh) qh = dl.TestFunction(Qh) Mqh = dl.assemble(ph*qh*dl.dx(metadata=metadata)) ones = dl.interpolate(dl.Constant(1.), Qh).vector() dMqh = Mqh*ones Mqh.zero() dMqh.set_local( ones.get_local() / np.sqrt(dMqh.get_local() ) ) Mqh.set_diagonal(dMqh) MixedM = dl.assemble(ph*test*dl.dx(metadata=metadata)) self.sqrtM = MatMatMult(MixedM, Mqh) dl.parameters["form_compiler"]["quadrature_degree"] = old_qr if dlversion() >= (2017,1,0): dl.parameters["form_compiler"]["representation"] = representation_old self.R = _BilaplacianR(self.A, self.Msolver) self.Rsolver = _BilaplacianRsolver(self.Asolver, self.M) rhs = dl.Vector() self.mean = dl.Vector() self.init_vector(rhs, 0) self.init_vector(self.mean, 0) MO.mult(m_true, rhs) self.Asolver.solve(self.mean, rhs)
L = dl.assemble( (uh.dx(0)*z1h + uh.dx(1)*z2h + uh.dx(2)*z3h + uh*z4h)*dl.dx(metadata=metadata) ) ones = dl.Vector() W.init_vector(ones,0) ones.set_local(np.ones(ones.size())) W1 = W*ones invW1 = dl.Vector() W.init_vector(invW1,0) invW1.set_local(1./W1.array()) Winv = dl.assemble( dl.inner(xh,zh)*dl.dx(metadata=metadata) ) Winv.zero() Winv.set_diagonal(invW1) randx = dl.Vector() A.init_vector(randx,0) randx.set_local(np.random.rand(randx.size() ) ) for x in [dl.interpolate(dl.Constant(1), Vh).vector(), dl.interpolate(dl.Expression("x[0]"), Vh).vector(), dl.interpolate(dl.Expression("x[0]*x[1]"), Vh).vector(), dl.interpolate(dl.Expression("x[0]*x[0]"), Vh).vector(), dl.interpolate(dl.Expression("x[0]*x[0]*x[1]"), Vh).vector(), randx]: y = A*x Lx = L*x help = Winv * Lx y2 = dl.Vector() L.transpmult(help, y2) print (y - y2).norm("linf")/y.norm("linf")
active_model = "active_strain" alpha = df.Constant(0.3) mu = df.Constant(0.385) if active_model == "active_stress": gamma = df.Constant(0.0) Ta = df.Constant(0.9) act = Ta else: gamma = df.Constant(0.3) Ta = df.Constant(0.0) act = gamma # Fiber f0_expr = df.Expression(("0.0", "1.0"), degree=1) # Exact solution u_exact = df.Expression(("0.5*alpha*x[1]*x[1]", "0.0"), alpha=alpha, degree=2) p_exact = df.Expression( "alpha*( 0.5*alpha*x[1]*x[1] + x[0])*(mu / ((1-gamma)*(1-gamma)) + Ta)", alpha=alpha, mu=mu, gamma=gamma, Ta=Ta, degree=2) F_exact = df.Expression((("1.0", "alpha*x[1]"), ("0.0", "1.0")), degree=1, alpha=alpha)
def equilibrium_EC_PNP(w_, test_functions, solutes, permittivity, dx, ds, normal, dirichlet_bcs, neumann_bcs, boundary_to_mark, use_iterative_solvers, V_lagrange, **namespace): """ Electrochemistry equilibrium solver. Nonlinear! """ num_solutes = len(solutes) cV = df.split(w_["EC"]) c, V = cV[:num_solutes], cV[num_solutes] if V_lagrange: V0 = cV[-1] b = test_functions["EC"][:num_solutes] U = test_functions["EC"][num_solutes] if V_lagrange: U0 = test_functions["EC"][-1] z = [] # Charge z[species] K = [] # Diffusivity K[species] for solute in solutes: z.append(solute[1]) K.append(solute[2]) rho_e = sum([c_e*z_e for c_e, z_e in zip(c, z)]) veps_arr = np.array([100.**2, 50.**2, 20.**2, 10.**2, 5.**2, 2.**2, 1.**2])*permittivity[0] veps = df.Expression("val", val=veps_arr[0], degree=1) F_c = [] for ci, bi, Ki, zi in zip(c, b, K, z): ci_grad_g_ci = df.grad(ci) + ci*zi*df.grad(V) F_ci = Ki*df.dot(ci_grad_g_ci, df.grad(bi))*dx F_c.append(F_ci) F_V = veps*df.dot(df.grad(V), df.grad(U))*dx for boundary_name, sigma_e in neumann_bcs["V"].items(): F_V += -sigma_e*U*ds(boundary_to_mark[boundary_name]) if rho_e != 0: F_V += -rho_e*U*dx if V_lagrange: F_V += veps*V0*U*dx + veps*V*U0*dx F = sum(F_c) + F_V J = df.derivative(F, w_["EC"]) problem = df.NonlinearVariationalProblem(F, w_["EC"], dirichlet_bcs["EC"], J) solver = df.NonlinearVariationalSolver(problem) solver.parameters["newton_solver"]["relative_tolerance"] = 1e-7 if use_iterative_solvers: solver.parameters["newton_solver"]["linear_solver"] = "bicgstab" if not V_lagrange: solver.parameters["newton_solver"]["preconditioner"] = "hypre_amg" for val in veps_arr[1:]: veps.val = val solver.solve()
def smoothstart(Vl, ref, pk): return dl.interpolate(dl.Expression('c0 + (c1-c0)*sin(pi*x[0])*sin(pi*x[1])',\ c0=ref, c1=pk, degree=10), Vl)
def velocity_init(L, H, inlet_velocity, degree=2): return df.Expression(("4*U*x[1]*(H-x[1])/pow(H, 2)", "0.0"), L=L, H=H, U=inlet_velocity, degree=degree)
import dolfin as df #Test wether we can combine DG0 and CG1 expressions. Background: # #To allow M to vary as a function of space, we would like to write #M = Ms*m where # # Ms is a DG0 space (with values on the centre of the cells) and # m the normalised magnetisation vector defined on the nodes of the mesh. # # Seems to work. Hans & Weiwei, 19 April 2012. mesh = df.RectangleMesh(0,0,1,1,1,1) VV = df.VectorFunctionSpace(mesh,"CG",1,dim=3) V = df.FunctionSpace(mesh,"DG",0) Ms = df.interpolate(df.Expression("1.0"),V) m = df.interpolate(df.Expression(("2.0","0.0","0.0")),VV) #m = df.interpolate(df.Expression("2.0"),VV) L = df.dot(m,m)*Ms*df.dx u = df.assemble(L) print "expect u to be 4 (2*2*1):" print "u=",u
triangles = mesh.cells() # Create triangulation. triang = mtri.Triangulation(x, y, triangles) # create array of node values from function z = u.vector()[v2d] # Plot the triangulation. plt.figure() plt.tricontourf(triang, z) #plt.triplot(triang, 'k-') #plt.title('Triangular grid') if __name__ == "__main__": import HoworkaTools # get some mesh geo = HoworkaTools.geo mesh = geo.submesh("fluid") # Create some Function V = dolfin.FunctionSpace(mesh, "CG", 1) u = dolfin.Function(V) expr = dolfin.Expression("sin(x[0])") u.interpolate(expr) fem2contour(u) plt.show()
return mesh class Top(SubDomain): def inside(self, x, on_boundary): tol = DOLFIN_EPS return on_boundary and abs(x[1] - 1.0) < tol class NotTop(SubDomain): def inside(self, x, on_boundary): tol = DOLFIN_EPS return on_boundary and abs(x[1] - 1.0) > tol class TestProblem: def __init__(self, bc0, bc1, dim=2): self.bc0 = bc0 self.bc1 = bc1 self.dim = dim # This BC causes the nonlinear solver in RumpfSmoother to throw lots of NaNs. # Just the presence in this file is enough, it does not have to be used. # If an x[1] appears somewhere, everything is fine. Bug in FEniCS 1.4? #bc0 = dolfin.Expression(("x[0]", "1 + t*sin(2*pi*x[0]+ 0.*x[1])"),t=0,pi=math.pi) bc0 = dolfin.Expression(("x[0]", "x[1]")) bc1 = dolfin.Expression(("x[0]", "x[1]")) my_deform = TestProblem(bc0, bc1)
def discretize(DIM, N, ORDER): # ### problem definition import dolfin as df if DIM == 2: mesh = df.UnitSquareMesh(N, N) elif DIM == 3: mesh = df.UnitCubeMesh(N, N, N) else: raise NotImplementedError V = df.FunctionSpace(mesh, "CG", ORDER) g = df.Constant(1.0) c = df.Constant(1.) class DirichletBoundary(df.SubDomain): def inside(self, x, on_boundary): return abs(x[0] - 1.0) < df.DOLFIN_EPS and on_boundary db = DirichletBoundary() bc = df.DirichletBC(V, g, db) u = df.Function(V) v = df.TestFunction(V) f = df.Expression("x[0]*sin(x[1])", degree=2) F = df.inner( (1 + c * u**2) * df.grad(u), df.grad(v)) * df.dx - f * v * df.dx df.solve(F == 0, u, bc, solver_parameters={"newton_solver": { "relative_tolerance": 1e-6 }}) # ### pyMOR wrapping from pymor.bindings.fenics import FenicsVectorSpace, FenicsOperator, FenicsVisualizer from pymor.models.basic import StationaryModel from pymor.operators.constructions import VectorOperator from pymor.parameters.spaces import CubicParameterSpace space = FenicsVectorSpace(V) op = FenicsOperator( F, space, space, u, (bc, ), parameter_setter=lambda mu: c.assign(float(mu['c'])), parameter_type={'c': ()}, solver_options={'inverse': { 'type': 'newton', 'rtol': 1e-6 }}) rhs = VectorOperator(op.range.zeros()) fom = StationaryModel(op, rhs, visualizer=FenicsVisualizer(space), parameter_space=CubicParameterSpace({'c': ()}, 0., 1000.)) return fom
mesh = dl.UnitSquareMesh(nxy, nxy) V = dl.FunctionSpace(mesh, 'Lagrange', 2) # space for state and adjoint variables Vm = dl.FunctionSpace(mesh, 'Lagrange', 1) # space for medium parameter Vme = dl.FunctionSpace(mesh, 'Lagrange', 1) # sp for target med param def u0_boundary(x, on_boundary): return on_boundary u0 = dl.Constant("0.0") bc = dl.DirichletBC(V, u0, u0_boundary) mtrue_exp = \ dl.Expression('2 + 7*(pow(pow(x[0] - 0.5,2) + pow(x[1] - 0.5,2),0.5) > 0.2)') #dl.Expression('1.0 + 3.0*(x[0]<=0.8)*(x[0]>=0.2)*(x[1]<=0.8)*(x[1]>=0.2)') mtrue = dl.interpolate(mtrue_exp, Vme) # target medium mtrueVm = dl.interpolate(mtrue_exp, Vm) # target medium minit_exp = dl.Expression('1.0 + 0.3*sin(pi*x[0])*sin(pi*x[1])') minit = dl.interpolate(minit_exp, Vm) # target medium f = dl.Expression("1.0") # source term if PLOT: filename, ext = splitext(sys.argv[0]) if mpirank == 0 and isdir(filename + '/'): rmtree(filename + '/') MPI.barrier(mpicomm) myplot = PlotFenics(filename) MPI.barrier(mpicomm) myplot.set_varname('m_target')
import dolfin as df mesh = df.UnitIntervalMesh(1) V = df.VectorFunctionSpace(mesh, "CG", 1, dim=3) f = df.Function(V) f.assign(df.Expression(("1", "2", "3"))) print f.vector().array()
def gradhesscheck(): sndorder = True #HH = [1e-4] #HH = [1e-4, 1e-5, 1e-6] HH = [1e-4, 1e-5, 1e-6, 1e-7, 1e-8] mesh = dl.UnitSquareMesh(100, 100) V = dl.FunctionSpace(mesh, 'Lagrange', 1) #k_exp = dl.Expression('1.0 + exp(x[0]*x[1])') #k = dl.interpolate(k_exp, V) #k = dl.Constant(1.0) m_in = dl.Function(V) TV1 = TV({'Vm': V, 'eps': 1e-4, 'k': 1e-2, 'GNhessian': False}) TV2 = TVPD({'Vm': V, 'eps': 1e-4, 'k': 1e-2, 'exact': True}) #M_EXP = [dl.Expression('1.0'),\ #dl.Expression('1.0 + (x[0]>=0.2)*(x[0]<=0.8)*(x[1]>=0.2)*(x[1]<=0.8)'), \ #dl.Expression('1.0 + (x[0]>=0.2)*(x[0]<=0.8)*(x[1]>=0.2)*(x[1]<=0.8) ' + \ #'+ (x[0]>=0.2)*(x[0]<=0.4)*(x[1]>=0.2)*(x[1]<=0.4)')] M_EXP = [ dl.Expression('1.0 + (x[0]>=0.2)*(x[0]<=0.8)*(x[1]>=0.2)*(x[1]<=0.8)') ] for ii, m_exp in enumerate(M_EXP): # Verification point, i.e., point at which gradient and Hessian are checked print 'Verification point', str(ii) #m_exp = dl.Expression('sin(n*pi*x[0])*sin(n*pi*x[1])', n=ii) m = dl.interpolate(m_exp, V) print '\nGradient:' failures = 0 for nn in range(8): print '\ttest ' + str(nn + 1) dm_exp = dl.Expression('sin(n*pi*x[0])*sin(n*pi*x[1])', n=nn + 1) dm = dl.interpolate(dm_exp, V) for h in HH: success = False setfct(m_in, m) m_in.vector().axpy(h, dm.vector()) cost1 = TV1.cost(m_in) cost12 = TV2.cost(m_in) print 'cost1={}, cost12={}, err={}'.format(cost1, cost12, \ np.abs(cost1-cost12)/np.abs(cost1)) if sndorder: setfct(m_in, m) m_in.vector().axpy(-h, dm.vector()) cost2 = TV1.cost(m_in) GradFD = (cost1 - cost2) / (2. * h) else: cost = TV1.cost(m) GradFD = (cost1 - cost) / h Grad1m = TV1.grad(m) Grad1m_h = Grad1m.inner(dm.vector()) Grad2m = TV2.grad(m) Grad2m_h = Grad2m.inner(dm.vector()) if np.abs(Grad1m_h) > 1e-16: err1 = np.abs(GradFD - Grad1m_h) / np.abs(Grad1m_h) err2 = np.abs(Grad1m_h - Grad2m_h) / np.abs(Grad1m_h) else: err1 = np.abs(GradFD - Grad1m_h) err2 = np.abs(Grad1m_h - Grad2m_h) print 'h={}, GradFD={}, Grad1m_h={}, err1={:.2e}'.format(\ h, GradFD, Grad1m_h, err1) print 'Grad2m_h={}, err12={}'.format(Grad2m_h, err2) if err1 < 1e-6: print 'test {}: OK!'.format(nn + 1) success = True break if not success: failures += 1 print '\nTest gradient -- Summary: {} test(s) failed'.format(failures) #if failures < 5: if True: print '\n\nHessian:' failures = 0 for nn in range(8): print '\ttest ' + str(nn + 1) dm_exp = dl.Expression('sin(n*pi*x[0])*sin(n*pi*x[1])', n=nn + 1) dm = dl.interpolate(dm_exp, V) for h in HH: success = False setfct(m_in, m) m_in.vector().axpy(h, dm.vector()) grad1 = TV1.grad(m_in) if sndorder: setfct(m_in, m) m_in.vector().axpy(-h, dm.vector()) grad2 = TV1.grad(m_in) HessFD = (grad1 - grad2) / (2. * h) else: grad = TV1.grad(m) HessFD = (grad1 - grad) / h TV1.assemble_hessian(m) Hess1mdm = TV1.hessian(dm.vector()) TV2.assemble_hessian(m) Hess2mdm = TV2.hessian(dm.vector()) err1 = (HessFD - Hess1mdm).norm('l2') / Hess1mdm.norm('l2') err2 = (Hess1mdm - Hess2mdm).norm('l2') / Hess2mdm.norm('l2') print 'h={}, err1={}, err12={}'.format(h, err1, err2) if err1 < 1e-6: print 'test {}: OK!'.format(nn + 1) success = True break if not success: failures += 1 print '\nTest Hessian -- Summary: {} test(s) failed\n'.format( failures)
plt.plot(xs, m_an, '--', label='Analytical') cg = delta_cg(mesh, expr) plt.plot(xs, cg, '.-', label='cg') xs, dg = delta_dg(mesh, expr) print xs, dg plt.plot(xs, dg, '^--', label='dg') plt.legend(loc=8) fig.savefig(name) if __name__ == "__main__": mesh = df.UnitIntervalMesh(10) xs = mesh.coordinates().flatten() expr = df.Expression('cos(2*pi*x[0])') m_an = -(2 * np.pi)**2 * np.cos(2 * np.pi * xs) plot_m(mesh, expr, m_an, name='cos.pdf') expr = df.Expression('sin(2*pi*x[0])') m_an = -(2 * np.pi)**2 * np.sin(2 * np.pi * xs) plot_m(mesh, expr, m_an, name='sin.pdf') expr = df.Expression('x[0]*x[0]') m_an = 2 + 1e-10 * xs plot_m(mesh, expr, m_an, name='x2.pdf')
nx = 1024 mesh = dl.IntervalMesh(dl.mpi_comm_self(), nx, 0., 1.) # define function space Vh2 = dl.FunctionSpace(mesh, 'Lagrange', 1) Vh1 = dl.FunctionSpace(mesh, 'Lagrange', 1) Vh = [Vh2, Vh1, Vh2] ndofs = [Vh[STATE].dim(), Vh[PARAMETER].dim(), Vh[ADJOINT].dim()] if rank == 0: print(sep, "Set up the mesh and finite element spaces", sep) print( "Number of dofs: STATE={0}, PARAMETER={1}, ADJOINT={2}".format(*ndofs)) # define boundary conditions and PDE u_bdr = dl.Expression("1-x[0]", degree=1) u_bdr0 = dl.Constant(0.0) bc = dl.DirichletBC(Vh[STATE], u_bdr, u_boundary) bc0 = dl.DirichletBC(Vh[STATE], u_bdr0, u_boundary) pde = PDEVariationalProblem(Vh, pde_varf, bc, bc0, is_fwd_linear=True) # if dlversion() <= (1, 6, 0): # pde.solver = dl.PETScKrylovSolver("cg", amg_method()) # pde.solver_fwd_inc = dl.PETScKrylovSolver("cg", amg_method()) # pde.solver_adj_inc = dl.PETScKrylovSolver("cg", amg_method()) # else: # pde.solver = dl.PETScKrylovSolver(mesh.mpi_comm(), "cg", amg_method()) # pde.solver_fwd_inc = dl.PETScKrylovSolver(mesh.mpi_comm(), "cg", amg_method()) # pde.solver_adj_inc = dl.PETScKrylovSolver(mesh.mpi_comm(), "cg", amg_method()) # pde.solver.parameters["relative_tolerance"] = 1e-15 # pde.solver.parameters["absolute_tolerance"] = 1e-20
def navier_stokes_IPCS_cavity(mesh, dt, parameter): """ fenics code: weak form of the problem. """ dx, ds = df.dx, df.ds dot, inner, outer, div = df.dot, df.inner, df.outer, df.div nabla_grad, grad = df.nabla_grad, df.grad test_f, trial_f = df.TestFunction, df.TrialFunction U0, D, mu_solid = parameter g = 9.81/1.0000000000 # function space V = df.VectorFunctionSpace(mesh, 'P', 2) Q = df.FunctionSpace(mesh, 'P', 1) T = df.FunctionSpace(mesh, 'P', 1) ASD1 = df.AutoSubDomain(top) ASD2 = df.AutoSubDomain(left) ASD3 = df.AutoSubDomain(bottom) ASD4 = df.AutoSubDomain(right) mf = df.MeshFunction("size_t", mesh, 1) mf.set_all(9999) ASD1.mark(mf, 1) ASD2.mark(mf, 2) ASD3.mark(mf, 3) ASD4.mark(mf, 4) ds_ = ds(subdomain_data=mf, domain=mesh) print(np.unique(ds_(3).subdomain_data().array())) vu, vp, vt = test_f(V), test_f(Q), test_f(T) u_, p_, t_ = df.Function(V), df.Function(Q), df.Function(T) # solution mu_k, rho_k = df.Function(T), df.Function(T) u_1, p_1, t_1, rho_1 = df.Function(V), df.Function(Q), df.Function(T), df.Function(T) # solution1 u, p, t = trial_f(V), trial_f(Q), trial_f(T) # unknown! u_k = df.Function(V) # boundary conditions no_slip = df.Constant((0., 0)) topflow = df.Expression(("-x[0] * (x[0] - 1.0) * 6.0 * m", "0.0"), m=U0, degree=2) bc0 = df.DirichletBC(V, topflow, top) bc1 = df.DirichletBC(V, no_slip, left) bc2 = df.DirichletBC(V, no_slip, bottom) bc3 = df.DirichletBC(V, no_slip, right) # bc4 = df.DirichletBC(Q, df.Constant(0), top) # bc3 = df.DirichletBC(T, df.Constant(800), top) bcu = [bc0, bc1, bc2, bc3] # no boundary conditions for the pressure bcp = [] # bcp = [df.DirichletBC(Q, df.Constant(0), top)] bct = [] # set initial temp: 500°C y=0, 800°C at y=1 x, y = np.split(T.tabulate_dof_coordinates(), 2, 1) u_1.vector().vec().array[:] = 1e-6 u_k.vector().vec().array[:] = 1e-6 p_.vector().vec().array[:] = -rho(750)*g*y.ravel() p_1.vector().vec().array[:] = -rho(750)*g*y.ravel() t_1.vector().vec().array = (y.ravel())*100 + 700 t_.assign(t_1) mu_k.vector().vec().array = mu(t_1.vector().vec().array, mu_solid) rho_k.vector().vec().array = rho(t_1.vector().vec().array) rho_1.vector().vec().array = rho(t_1.vector().vec().array) n = df.FacetNormal(mesh) # implicit: acceleration = inner((rho_k*u - rho_1*u_1)/dt, vu) * dx convection = dot(div(rho_k*outer(u_k, u)), vu) * dx pressure = inner(p_1, div(vu))*dx - dot(p_1*n, vu)*ds # integrated by parts diffusion = -inner(mu_k * (grad(u) + grad(u).T), grad(vu))*dx \ + dot(mu_k * (grad(u) + grad(u).T)*n, vu)*ds # integrated by parts body_force = dot(df.Constant((0.0, -g))*rho_k, vu)*dx \ + dot(df.Constant((0.0, 0.0)), vu) * ds F1 = -acceleration - convection + diffusion + pressure + body_force a1, L1 = df.lhs(F1), df.rhs(F1) # Define variational problem for step 2 F2 = rho_k / dt * dot(div(u_), vp) * dx + dot(grad(p-p_1), grad(vp)) * dx # grad(p-p_1)/2 * grad(vp) * dx does not work a2, L2 = df.lhs(F2), df.rhs(F2) # Define variational problem for step 3, where u_ = u* from step 1 F3 = -rho_k / dt * dot(u-u_, vu) * dx - dot(grad(p_-p_1), vu) * dx a3, L3 = df.lhs(F3), df.rhs(F3) # Step 4: Transport of rho / Convection-diffusion and SUPG # vr = vr + tau_SUPG * inner(u_, grad(vr)) # SUPG stabilization # F4 = dot((t - t_1) / dt, vt)*dx + dot(div(t*u_), vt) * dx + D*dot(grad(t), grad(vt)) * dx # above does not work, below works fine, but is mathematically not correct, since d/dt (rho) is not 0 F4 = dot((t - t_1) / dt, vt)*dx + dot(dot(grad(t), u_), vt)*dx \ + D*dot(grad(t), grad(vt)) * dx a4, L4 = df.lhs(F4), df.rhs(F4) # Robin BC: HT on the walls. ht coefficient k is arbitray t_amb, t_feeder = 100., 800. k_top, k_lft, k_btm, k_rgt = (1e-3, 3.33e-4, 3.33e-4, 3.33e-4) F4 += k_top*(t - t_feeder)*vt*ds_(1) F4 += k_lft*(t - t_amb)*vt*ds_(2) F4 += k_btm*(t - t_amb)*vt*ds_(3) F4 += k_rgt*(t - t_amb)*vt*ds_(4) # Assemble matrices A1 = df.assemble(a1) A2 = df.assemble(a2) A3 = df.assemble(a3) # A4 = assemble(a4) # Apply boundary conditions to matrices [bc.apply(A1) for bc in bcu] [bc.apply(A2) for bc in bcp] [bc.apply(A3) for bc in bcu] return (u_1, p_1, t_1, mu_k, rho_k, u_, p_, t_, u_k, D, L1, a1, L2, A2, L3, A3, L4, a4, bcu, bcp, bct)
import numpy as np from fenicstools.jointregularization import crossgradient from fenicstools.miscfenics import setfct, createMixedFS print 'Check exact results (cost only):' print 'Test 1' err = 1.0 N = 10 while err > 1e-6: N = 2 * N mesh = dl.UnitSquareMesh(N, N) V = dl.FunctionSpace(mesh, 'Lagrange', 1) VV = createMixedFS(V, V) cg = crossgradient(VV) a = dl.interpolate(dl.Expression('x[0]', degree=10), V) b = dl.interpolate(dl.Expression('x[1]', degree=10), V) cgc = cg.costab(a, b) err = np.abs(cgc - 0.5) / 0.5 print 'N={}, x*y={:.6f}, err={:.3e}'.format(N, cgc, err) print 'Test 2' err = 1.0 N = 20 while err > 1e-6: N = 2 * N mesh = dl.UnitSquareMesh(N, N) V = dl.FunctionSpace(mesh, 'Lagrange', 2) VV = createMixedFS(V, V) cg = crossgradient(VV) a = dl.interpolate(dl.Expression('x[0]*x[0]', degree=10), V) b = dl.interpolate(dl.Expression('x[1]*x[1]', degree=10), V)
left = Left() top = Top() right = Right() bottom = Bottom() # Initialize mesh function for boundary domains boundaries = dol.MeshFunction("size_t", mesh, mesh.topology().dim() - 1) boundaries.set_all(0) left.mark(boundaries, 1) top.mark(boundaries, 2) right.mark(boundaries, 3) bottom.mark(boundaries, 4) # Boundary conditions bcs = [ dol.DirichletBC(FS, dol.Expression(('0', '0', '0'), degree=2), boundaries, 2), dol.DirichletBC(FS, dol.Expression(('-9.1*x[0]+5', '5', '10'), degree=2), boundaries, 4), dol.DirichletBC( FS, dol.Expression(("5*(1-x[1])", "5*(1-x[1])", "10*(1-x[1])"), degree=2), boundaries, 1), dol.DirichletBC( FS, dol.Expression(("-5*(1-x[1])", "5*(1-x[1])", "10*(1-x[1])"), degree=2), boundaries, 3) ] # Define test functions f_1, f_2, f_3 = dol.TestFunctions(FS)
import dolfin import numpy import pylab from dolfin import TrialFunction, TestFunction, inner, dx, Function, solve, assemble from dolfin import PETScMatrix, PETScVector, SLEPcEigenSolver, assemble_system # define an exact stream function psi_exact_str = 'x[1]<=pi ? epsilon*cos(x[0])-(1.0/(cosh((x[1]-0.5*pi)/delta)*cosh((x[1]-0.5*pi)/delta)))/delta : epsilon*cos(x[0]) + (1.0/(cosh((1.5*pi-x[1])/delta)*cosh((1.5*pi-x[1])/delta)))/delta' epsilon = 0.05 delta = numpy.pi/15.0 psi_exact = dolfin.Expression(psi_exact_str,epsilon=epsilon,delta=delta) # define the number of elements and polynomial degree of basis functions n_elements = [5,10,20,40,80] pp = numpy.arange(1,3) # define the mesh xBounds = numpy.array([0.,2.0*numpy.pi]) yBounds = numpy.array([0.,2.0*numpy.pi]) div_max = numpy.zeros([len(pp),len(n_elements)]) def project(expr, space): u, v = TrialFunction(space), TestFunction(space) a = inner(u, v)*dx L = inner(expr, v)*dx A, b = PETScMatrix(), PETScVector() assemble_system(a, L, A_tensor=A, b_tensor=b)
pbc = periodicity.PeriodicDomain.pbc_dual_base( panto_part.global_dimensions[:2, :2], "Y") boundary_conditions = [ { "type": "Periodic", "constraint": pbc }, ("Dirichlet", (0.0, 0.0), left_border), ] # * Step 5.3 : Definition of the load load_width = 4 * a load_x = LX / 2 indicator_fctn = fe.Expression( "x[0] >= (loadx-loadw/2.0) && x[0] <= (loadx+loadw/2.0) ? 1 : 0", degree=1, loadx=load_x, loadw=load_width, ) load_area = fe.assemble(indicator_fctn * fe.dx(panto_part.mesh)) load_magnitude = 1.0 s_load = load_magnitude / load_area s_load = fe.Constant( (s_load, 0.0)) # forme utilisée dans tuto FEniCS linear elasticity load = (2, s_load, indicator_fctn) # * Step 5.3 : Choosing FE characteristics element = ("Lagrange", 2) # * Step 5.4 : Gathering all data in a model model = full_scale_pb.FullScaleModel(panto_part, [load], boundary_conditions, element)
def setup_scalar_equation(self): sim = self.simulation V = sim.data['Vphi'] mesh = V.mesh() P = V.ufl_element().degree() # Source term source_cpp = sim.input.get_value('solver/source', '0', 'string') f = dolfin.Expression(source_cpp, degree=P) # Create the solution function sim.data['phi'] = dolfin.Function(V) # DG elliptic penalty penalty = define_penalty(mesh, P, k_min=1.0, k_max=1.0) penalty_dS = dolfin.Constant(penalty) penalty_ds = dolfin.Constant(penalty * 2) yh = dolfin.Constant(1 / (penalty * 2)) # Define weak form u, v = dolfin.TrialFunction(V), dolfin.TestFunction(V) a = dot(grad(u), grad(v)) * dx L = f * v * dx # Symmetric Interior Penalty method for -∇⋅∇φ n = dolfin.FacetNormal(mesh) a -= dot(n('+'), avg(grad(u))) * jump(v) * dS a -= dot(n('+'), avg(grad(v))) * jump(u) * dS # Symmetric Interior Penalty coercivity term a += penalty_dS * jump(u) * jump(v) * dS # Dirichlet boundary conditions # Nitsche's (1971) method, see e.g. Epshteyn and Rivière (2007) dirichlet_bcs = sim.data['dirichlet_bcs'].get('phi', []) for dbc in dirichlet_bcs: bcval, dds = dbc.func(), dbc.ds() # SIPG for -∇⋅∇φ a -= dot(n, grad(u)) * v * dds a -= dot(n, grad(v)) * u * dds L -= dot(n, grad(v)) * bcval * dds # Weak Dirichlet a += penalty_ds * u * v * dds L += penalty_ds * bcval * v * dds # Neumann boundary conditions neumann_bcs = sim.data['neumann_bcs'].get('phi', []) for nbc in neumann_bcs: L += nbc.func() * v * nbc.ds() # Robin boundary conditions # See Juntunen and Stenberg (2009) # n⋅∇φ = (φ0 - φ)/b + g robin_bcs = sim.data['robin_bcs'].get('phi', []) for rbc in robin_bcs: b, rds = rbc.blend(), rbc.ds() dval, nval = rbc.dfunc(), rbc.nfunc() # From IBP of the main equation a -= dot(n, grad(u)) * v * rds # Test functions for the Robin BC z1 = 1 / (b + yh) * v z2 = -yh / (b + yh) * dot(n, grad(v)) # Robin BC added twice with different test functions for z in [z1, z2]: a += b * dot(n, grad(u)) * z * rds a += u * z * rds L += dval * z * rds L += b * nval * z * rds # Does the system have a null-space? self.has_null_space = len(dirichlet_bcs) + len(robin_bcs) == 0 self.form_lhs = a self.form_rhs = L
return df.between(x[0]**2 + x[1]**2, (0, 1)) and df.between(x[1], (0, 1)) quantumDot = QuantumDot() domains = df.CellFunction("size_t", mesh) domains.set_all(0) quantumDot.mark(domains, 1) V = df.FunctionSpace(mesh, "CG", 1) u = df.TrialFunction(V) v = df.TestFunction(V) drdz = df.Measure("dx")[domains] r = df.Expression("x[0]") # Confining potential potential = df.Constant(100) # Partial derivatives of trial and test functions u_r = u.dx(0) v_r = v.dx(0) u_z = u.dx(1) v_z = v.dx(1) # Initial guess of ground state is 1 inside dot, 0 outside dot psi0 = v * r * drdz(1) Psi0 = df.PETScVector() df.assemble(psi0, tensor=Psi0)
V = dl.FunctionSpace(mesh, 'Lagrange', 2) # space for state and adjoint variables Vm = dl.FunctionSpace(mesh, 'Lagrange', 1) # space for medium parameter Vme = dl.FunctionSpace(mesh, 'Lagrange', 1) # sp for target med param def u0_boundary(x, on_boundary): return on_boundary u0 = dl.Constant("0.0") bc = dl.DirichletBC(V, u0, u0_boundary) #bc = None #mtrue_exp = dl.Expression('2 + 7*(pow(pow(x[0] - 0.5,2) + pow(x[1] - 0.5,2),0.5) > 0.25)') mtrue_exp = dl.Expression('1.0') mtrue = dl.interpolate(mtrue_exp, Vme) # target medium mtrueVm = dl.interpolate(mtrue_exp, Vm) # target medium minit_exp = dl.Expression('1.0') minit = dl.interpolate(minit_exp, Vm) #f = [dl.Expression("1.0")] # source term f = PointSources(V, [[0.5, 0.5]]).PtSrc if PLOT: filename, ext = splitext(sys.argv[0]) if mpirank == 0 and isdir(filename + '/'): rmtree(filename + '/') MPI.barrier(mpicomm) myplot = PlotFenics(filename) MPI.barrier(mpicomm) myplot.set_varname('m_target')
def _discretize_fenics(): # assemble system matrices - FEniCS code ######################################## import dolfin as df mesh = df.UnitSquareMesh(GRID_INTERVALS, GRID_INTERVALS, 'crossed') V = df.FunctionSpace(mesh, 'Lagrange', FENICS_ORDER) u = df.TrialFunction(V) v = df.TestFunction(V) diffusion = df.Expression('(lower0 <= x[0]) * (open0 ? (x[0] < upper0) : (x[0] <= upper0)) *' + '(lower1 <= x[1]) * (open1 ? (x[1] < upper1) : (x[1] <= upper1))', lower0=0., upper0=0., open0=0, lower1=0., upper1=0., open1=0, element=df.FunctionSpace(mesh, 'DG', 0).ufl_element()) def assemble_matrix(x, y, nx, ny): diffusion.user_parameters['lower0'] = x/nx diffusion.user_parameters['lower1'] = y/ny diffusion.user_parameters['upper0'] = (x + 1)/nx diffusion.user_parameters['upper1'] = (y + 1)/ny diffusion.user_parameters['open0'] = (x + 1 == nx) diffusion.user_parameters['open1'] = (y + 1 == ny) return df.assemble(df.inner(diffusion * df.nabla_grad(u), df.nabla_grad(v)) * df.dx) mats = [assemble_matrix(x, y, XBLOCKS, YBLOCKS) for x in range(XBLOCKS) for y in range(YBLOCKS)] mat0 = mats[0].copy() mat0.zero() h1_mat = df.assemble(df.inner(df.nabla_grad(u), df.nabla_grad(v)) * df.dx) f = df.Constant(1.) * v * df.dx F = df.assemble(f) bc = df.DirichletBC(V, 0., df.DomainBoundary()) for m in mats: bc.zero(m) bc.apply(mat0) bc.apply(h1_mat) bc.apply(F) # wrap everything as a pyMOR discretization ########################################### # FEniCS wrappers from pymor.gui.fenics import FenicsVisualizer from pymor.operators.fenics import FenicsMatrixOperator from pymor.vectorarrays.fenics import FenicsVector # define parameter functionals (same as in pymor.analyticalproblems.thermalblock) parameter_functionals = [ProjectionParameterFunctional(component_name='diffusion', component_shape=(YBLOCKS, XBLOCKS), coordinates=(YBLOCKS - y - 1, x)) for x in range(XBLOCKS) for y in range(YBLOCKS)] # wrap operators ops = [FenicsMatrixOperator(mat0, V, V)] + [FenicsMatrixOperator(m, V, V) for m in mats] op = LincombOperator(ops, [1.] + parameter_functionals) rhs = VectorFunctional(ListVectorArray([FenicsVector(F, V)])) h1_product = FenicsMatrixOperator(h1_mat, V, V, name='h1_0_semi') # build discretization visualizer = FenicsVisualizer(V) parameter_space = CubicParameterSpace(op.parameter_type, 0.1, 1.) d = StationaryDiscretization(op, rhs, products={'h1_0_semi': h1_product}, parameter_space=parameter_space, visualizer=visualizer) return d