def test_lincomb_function(): for steps in (1, 10): x = np.linspace(0, 1, num=steps) zero = ConstantFunction(0.0, dim_domain=steps) for zero in (ConstantFunction(0.0, dim_domain=steps), GenericFunction(lambda X: np.zeros(X.shape[:-1]), dim_domain=steps)): for one in (ConstantFunction(1.0, dim_domain=steps), GenericFunction(lambda X: np.ones(X.shape[:-1]), dim_domain=steps), 1.0): add = (zero + one) + 1 - 1 add_ = 1 - 1 + (zero + one) sub = (zero - one) + np.zeros(()) neg = -zero assert np.allclose(sub(x), [-1]) assert np.allclose(add(x), [1.0]) assert np.allclose(add_(x), [1.0]) assert np.allclose(neg(x), [0.0]) (repr(add), str(add), repr(one), str(one) ) # just to cover the respective special funcs too mul = neg * 1. * 1. mul_ = 1. * 1. * neg assert np.allclose(mul(x), [0.0]) assert np.allclose(mul_(x), [0.0]) with pytest.raises(AssertionError): zero + ConstantFunction(dim_domain=steps + 1) with pytest.raises(AssertionError): ConstantFunction(dim_domain=0)
def elliptic_gmsh_demo(args): args['ANGLE'] = float(args['ANGLE']) args['NUM_POINTS'] = int(args['NUM_POINTS']) args['CLSCALE'] = float(args['CLSCALE']) problem = StationaryProblem( domain=CircularSectorDomain(args['ANGLE'], radius=1, num_points=args['NUM_POINTS']), diffusion=ConstantFunction(1, dim_domain=2), rhs=ConstantFunction(np.array(0.), dim_domain=2, name='rhs'), dirichlet_data=ExpressionFunction('sin(polar(x)[1] * pi/angle)', 2, (), {}, {'angle': args['ANGLE']}, name='dirichlet') ) print('Discretize ...') m, data = discretize_stationary_cg(analytical_problem=problem, diameter=args['CLSCALE']) grid = data['grid'] print(grid) print() print('Solve ...') U = m.solve() solution = ExpressionFunction('(lambda r, phi: r**(pi/angle) * sin(phi * pi/angle))(*polar(x))', 2, (), {}, {'angle': args['ANGLE']}) U_ref = U.space.make_array(solution(grid.centers(2))) m.visualize((U, U_ref, U-U_ref), legend=('Solution', 'Analytical solution (circular boundary)', 'Error'), separate_colorbars=True)
def burgers_problem_2d(vx=1., vy=1., torus=True, initial_data_type='sin', parameter_range=(1., 2.)): """Two-dimensional Burgers-type problem. The problem is to solve :: ∂_t u(x, t, μ) + ∇ ⋅ (v * u(x, t, μ)^μ) = 0 u(x, 0, μ) = u_0(x) for u with t in [0, 0.3], x in [0, 2] x [0, 1]. Parameters ---------- vx The x component of the velocity vector v. vy The y component of the velocity vector v. torus If `True`, impose periodic boundary conditions. Otherwise, Dirichlet left and bottom, outflow top and right. initial_data_type Type of initial data (`'sin'` or `'bump'`). parameter_range The interval in which μ is allowed to vary. """ assert initial_data_type in ('sin', 'bump') if initial_data_type == 'sin': initial_data = ExpressionFunction( "0.5 * (sin(2 * pi * x[..., 0]) * sin(2 * pi * x[..., 1]) + 1.)", 2, ()) dirichlet_data = ConstantFunction(dim_domain=2, value=0.5) else: initial_data = ExpressionFunction( "(x[..., 0] >= 0.5) * (x[..., 0] <= 1) * 1", 2, ()) dirichlet_data = ConstantFunction(dim_domain=2, value=0.) return InstationaryProblem( StationaryProblem( domain=TorusDomain([[0, 0], [2, 1]]) if torus else RectDomain([[0, 0], [2, 1]], right=None, top=None), dirichlet_data=dirichlet_data, rhs=None, nonlinear_advection=ExpressionFunction("abs(x)**exponent * v", 1, (2, ), {'exponent': 1}, {'v': np.array([vx, vy])}), nonlinear_advection_derivative=ExpressionFunction( "exponent * abs(x)**(exponent-1) * sign(x) * v", 1, (2, ), {'exponent': 1}, {'v': np.array([vx, vy])}), ), initial_data=initial_data, T=0.3, parameter_ranges=parameter_range, name=f"burgers_problem_2d({vx}, {vy}, {torus}, '{initial_data_type}')")
def elliptic_demo(args): args['PROBLEM-NUMBER'] = int(args['PROBLEM-NUMBER']) assert 0 <= args['PROBLEM-NUMBER'] <= 1, ValueError('Invalid problem number') args['DIRICHLET-NUMBER'] = int(args['DIRICHLET-NUMBER']) assert 0 <= args['DIRICHLET-NUMBER'] <= 2, ValueError('Invalid Dirichlet boundary number.') args['NEUMANN-NUMBER'] = int(args['NEUMANN-NUMBER']) assert 0 <= args['NEUMANN-NUMBER'] <= 2, ValueError('Invalid Neumann boundary number.') args['NEUMANN-COUNT'] = int(args['NEUMANN-COUNT']) assert 0 <= args['NEUMANN-COUNT'] <= 3, ValueError('Invalid Neumann boundary count.') rhss = [ExpressionFunction('ones(x.shape[:-1]) * 10', 2, ()), ExpressionFunction('(x[..., 0] - 0.5) ** 2 * 1000', 2, ())] dirichlets = [ExpressionFunction('zeros(x.shape[:-1])', 2, ()), ExpressionFunction('ones(x.shape[:-1])', 2, ()), ExpressionFunction('x[..., 0]', 2, ())] neumanns = [None, ConstantFunction(3., dim_domain=2), ExpressionFunction('50*(0.1 <= x[..., 1]) * (x[..., 1] <= 0.2)' '+50*(0.8 <= x[..., 1]) * (x[..., 1] <= 0.9)', 2, ())] domains = [RectDomain(), RectDomain(right='neumann'), RectDomain(right='neumann', top='neumann'), RectDomain(right='neumann', top='neumann', bottom='neumann')] rhs = rhss[args['PROBLEM-NUMBER']] dirichlet = dirichlets[args['DIRICHLET-NUMBER']] neumann = neumanns[args['NEUMANN-NUMBER']] domain = domains[args['NEUMANN-COUNT']] problem = StationaryProblem( domain=domain, diffusion=ConstantFunction(1, dim_domain=2), rhs=rhs, dirichlet_data=dirichlet, neumann_data=neumann ) for n in [32, 128]: print('Discretize ...') discretizer = discretize_stationary_fv if args['--fv'] else discretize_stationary_cg m, data = discretizer( analytical_problem=problem, grid_type=RectGrid if args['--rect'] else TriaGrid, diameter=np.sqrt(2) / n if args['--rect'] else 1. / n ) grid = data['grid'] print(grid) print() print('Solve ...') U = m.solve() m.visualize(U, title=repr(grid)) print()
def burgers_problem(v=1., circle=True, initial_data_type='sin', parameter_range=(1., 2.)): """One-dimensional Burgers-type problem. The problem is to solve :: ∂_t u(x, t, μ) + ∂_x (v * u(x, t, μ)^μ) = 0 u(x, 0, μ) = u_0(x) for u with t in [0, 0.3] and x in [0, 2]. Parameters ---------- v The velocity v. circle If `True`, impose periodic boundary conditions. Otherwise Dirichlet left, outflow right. initial_data_type Type of initial data (`'sin'` or `'bump'`). parameter_range The interval in which μ is allowed to vary. """ assert initial_data_type in ('sin', 'bump') if initial_data_type == 'sin': initial_data = ExpressionFunction('0.5 * (sin(2 * pi * x) + 1.)', 1, ()) dirichlet_data = ConstantFunction(dim_domain=1, value=0.5) else: initial_data = ExpressionFunction('(x >= 0.5) * (x <= 1) * 1.', 1, ()) dirichlet_data = ConstantFunction(dim_domain=1, value=0.) return InstationaryProblem( StationaryProblem( domain=CircleDomain([0, 2]) if circle else LineDomain([0, 2], right=None), dirichlet_data=dirichlet_data, rhs=None, nonlinear_advection=ExpressionFunction('abs(x)**exponent[0] * v', 1, (1, ), {'exponent': 1}, {'v': v}), nonlinear_advection_derivative=ExpressionFunction( 'exponent * abs(x)**(exponent[0]-1) * sign(x) * v', 1, (1, ), {'exponent': 1}, {'v': v}), ), T=0.3, initial_data=initial_data, parameter_ranges={'exponent': parameter_range}, name=f"burgers_problem({v}, {circle}, '{initial_data_type}')")
def helmholtz_problem(domain=RectDomain(), rhs=None, parameter_range=(0., 100.), dirichlet_data=None, neumann_data=None): """Helmholtz equation problem. This problem is to solve the Helmholtz equation :: - ∆ u(x, k) - k^2 u(x, k) = f(x, k) on a given domain. Parameters ---------- domain A |DomainDescription| of the domain the problem is posed on. rhs The |Function| f(x, μ). parameter_range A tuple `(k_min, k_max)` describing the interval in which k is allowd to vary. dirichlet_data |Function| providing the Dirichlet boundary values. neumann_data |Function| providing the Neumann boundary values. """ return StationaryProblem( domain=domain, rhs=rhs or ConstantFunction(1., dim_domain=domain.dim), dirichlet_data=dirichlet_data, neumann_data=neumann_data, diffusion=ConstantFunction(1., dim_domain=domain.dim), reaction=LincombFunction([ConstantFunction(1., dim_domain=domain.dim)], [ExpressionParameterFunctional('-k[0]**2', {'k': 1})]), parameter_ranges={'k': parameter_range}, name='helmholtz_problem' )
def main( angle: float = Argument(..., help='The angle of the circular sector.'), num_points: int = Argument( ..., help='The number of points that form the arc of the circular sector.'), clscale: float = Argument(..., help='Mesh element size scaling factor.'), ): """Solves the Poisson equation in 2D on a circular sector domain of radius 1 using an unstructured mesh. Note that Gmsh (http://geuz.org/gmsh/) is required for meshing. """ problem = StationaryProblem( domain=CircularSectorDomain(angle, radius=1, num_points=num_points), diffusion=ConstantFunction(1, dim_domain=2), rhs=ConstantFunction(np.array(0.), dim_domain=2, name='rhs'), dirichlet_data=ExpressionFunction('sin(polar(x)[1] * pi/angle)', 2, (), {}, {'angle': angle}, name='dirichlet')) print('Discretize ...') m, data = discretize_stationary_cg(analytical_problem=problem, diameter=clscale) grid = data['grid'] print(grid) print() print('Solve ...') U = m.solve() solution = ExpressionFunction( '(lambda r, phi: r**(pi/angle) * sin(phi * pi/angle))(*polar(x))', 2, (), {}, {'angle': angle}) U_ref = U.space.make_array(solution(grid.centers(2))) m.visualize((U, U_ref, U - U_ref), legend=('Solution', 'Analytical solution (circular boundary)', 'Error'), separate_colorbars=True)
def main( problem_number: int = Argument( ..., min=0, max=1, help='Selects the problem to solve [0 or 1].'), n: int = Argument(..., help='Grid interval count.'), fv: bool = Option( False, help='Use finite volume discretization instead of finite elements.'), ): """Solves the Poisson equation in 1D using pyMOR's builtin discreization toolkit.""" rhss = [ ExpressionFunction('ones(x.shape[:-1]) * 10', 1, ()), ExpressionFunction('(x - 0.5)**2 * 1000', 1, ()) ] rhs = rhss[problem_number] d0 = ExpressionFunction('1 - x', 1, ()) d1 = ExpressionFunction('x', 1, ()) f0 = ProjectionParameterFunctional('diffusionl') f1 = 1. problem = StationaryProblem(domain=LineDomain(), rhs=rhs, diffusion=LincombFunction([d0, d1], [f0, f1]), dirichlet_data=ConstantFunction(value=0, dim_domain=1), name='1DProblem') parameter_space = problem.parameters.space(0.1, 1) print('Discretize ...') discretizer = discretize_stationary_fv if fv else discretize_stationary_cg m, data = discretizer(problem, diameter=1 / n) print(data['grid']) print() print('Solve ...') U = m.solution_space.empty() for mu in parameter_space.sample_uniformly(10): U.append(m.solve(mu)) m.visualize(U, title='Solution for diffusionl in [0.1, 1]')
def elliptic_oned_demo(args): args['PROBLEM-NUMBER'] = int(args['PROBLEM-NUMBER']) assert 0 <= args['PROBLEM-NUMBER'] <= 1, ValueError( 'Invalid problem number.') args['N'] = int(args['N']) rhss = [ ExpressionFunction('ones(x.shape[:-1]) * 10', 1, ()), ExpressionFunction('(x - 0.5)**2 * 1000', 1, ()) ] rhs = rhss[args['PROBLEM-NUMBER']] d0 = ExpressionFunction('1 - x', 1, ()) d1 = ExpressionFunction('x', 1, ()) f0 = ProjectionParameterFunctional('diffusionl') f1 = 1. problem = StationaryProblem(domain=LineDomain(), rhs=rhs, diffusion=LincombFunction([d0, d1], [f0, f1]), dirichlet_data=ConstantFunction(value=0, dim_domain=1), name='1DProblem') parameter_space = problem.parameters.space(0.1, 1) print('Discretize ...') discretizer = discretize_stationary_fv if args[ '--fv'] else discretize_stationary_cg m, data = discretizer(problem, diameter=1 / args['N']) print(data['grid']) print() print('Solve ...') U = m.solution_space.empty() for mu in parameter_space.sample_uniformly(10): U.append(m.solve(mu)) m.visualize(U, title='Solution for diffusionl in [0.1, 1]')
def main( diameter: float = Argument( 0.1, help='Diameter option for the domain discretizer.'), r: int = Argument(5, help='Order of the ROMs.'), ): r"""2D heat equation demo. Discretization of the PDE: .. math:: :nowrap: \begin{align*} \partial_t z(x, y, t) &= \Delta z(x, y, t), & 0 < x, y < 1,\ t > 0 \\ -\nabla z(0, y, t) \cdot n &= z(0, y, t) - u(t), & 0 < y < 1, t > 0 \\ -\nabla z(1, y, t) \cdot n &= z(1, y, t), & 0 < y < 1, t > 0 \\ -\nabla z(0, x, t) \cdot n &= z(0, x, t), & 0 < x < 1, t > 0 \\ -\nabla z(1, x, t) \cdot n &= z(1, x, t), & 0 < x < 1, t > 0 \\ z(x, y, 0) &= 0 & 0 < x, y < 1 \\ y(t) &= \int_0^1 z(1, y, t) dy, & t > 0 \\ \end{align*} where :math:`u(t)` is the input and :math:`y(t)` is the output. """ set_log_levels({'pymor.algorithms.gram_schmidt.gram_schmidt': 'WARNING'}) p = InstationaryProblem(StationaryProblem( domain=RectDomain([[0., 0.], [1., 1.]], left='robin', right='robin', top='robin', bottom='robin'), diffusion=ConstantFunction(1., 2), robin_data=(ConstantFunction(1., 2), ExpressionFunction('(x[...,0] < 1e-10) * 1.', 2)), outputs=[('l2_boundary', ExpressionFunction('(x[...,0] > (1 - 1e-10)) * 1.', 2))]), ConstantFunction(0., 2), T=1.) fom, _ = discretize_instationary_cg(p, diameter=diameter, nt=100) fom.visualize(fom.solve()) lti = fom.to_lti() print(f'order of the model = {lti.order}') print(f'number of inputs = {lti.dim_input}') print(f'number of outputs = {lti.dim_output}') # System poles poles = lti.poles() fig, ax = plt.subplots() ax.plot(poles.real, poles.imag, '.') ax.set_title('System poles') plt.show() # Magnitude plot of the full model w = np.logspace(-1, 3, 100) fig, ax = plt.subplots() lti.mag_plot(w, ax=ax) ax.set_title('Magnitude plot of the full model') plt.show() # Hankel singular values hsv = lti.hsv() fig, ax = plt.subplots() ax.semilogy(range(1, len(hsv) + 1), hsv, '.-') ax.set_title('Hankel singular values') plt.show() # Norms of the system print(f'FOM H_2-norm: {lti.h2_norm():e}') if config.HAVE_SLYCOT: print(f'FOM H_inf-norm: {lti.hinf_norm():e}') else: print('Skipped H_inf-norm calculation due to missing slycot.') print(f'FOM Hankel-norm: {lti.hankel_norm():e}') # Model order reduction run_mor_method(lti, w, BTReductor(lti), 'BT', r, tol=1e-5) run_mor_method(lti, w, LQGBTReductor(lti), 'LQGBT', r, tol=1e-5) run_mor_method(lti, w, BRBTReductor(lti), 'BRBT', r, tol=1e-5) run_mor_method(lti, w, IRKAReductor(lti), 'IRKA', r) run_mor_method(lti, w, TSIAReductor(lti), 'TSIA', r) run_mor_method(lti, w, OneSidedIRKAReductor(lti, 'V'), 'OS-IRKA', r)
def elliptic2_demo(args): args['PROBLEM-NUMBER'] = int(args['PROBLEM-NUMBER']) assert 0 <= args['PROBLEM-NUMBER'] <= 1, ValueError('Invalid problem number.') args['N'] = int(args['N']) norm = args['NORM'] norm = float(norm) if not norm.lower() in ('h1', 'l2') else norm.lower() rhss = [ExpressionFunction('ones(x.shape[:-1]) * 10', 2, ()), LincombFunction( [ExpressionFunction('ones(x.shape[:-1]) * 10', 2, ()), ConstantFunction(1.,2)], [ProjectionParameterFunctional('mu'), 0.1])] dirichlets = [ExpressionFunction('zeros(x.shape[:-1])', 2, ()), LincombFunction( [ExpressionFunction('2 * x[..., 0]', 2, ()), ConstantFunction(1.,2)], [ProjectionParameterFunctional('mu'), 0.5])] neumanns = [None, LincombFunction( [ExpressionFunction('1 - x[..., 1]', 2, ()), ConstantFunction(1.,2)], [ProjectionParameterFunctional('mu'), 0.5**2])] robins = [None, (LincombFunction( [ExpressionFunction('x[..., 1]', 2, ()), ConstantFunction(1.,2)], [ProjectionParameterFunctional('mu'), 1]), ConstantFunction(1.,2))] domains = [RectDomain(), RectDomain(right='neumann', top='dirichlet', bottom='robin')] rhs = rhss[args['PROBLEM-NUMBER']] dirichlet = dirichlets[args['PROBLEM-NUMBER']] neumann = neumanns[args['PROBLEM-NUMBER']] domain = domains[args['PROBLEM-NUMBER']] robin = robins[args['PROBLEM-NUMBER']] problem = StationaryProblem( domain=domain, rhs=rhs, diffusion=LincombFunction( [ExpressionFunction('1 - x[..., 0]', 2, ()), ExpressionFunction('x[..., 0]', 2, ())], [ProjectionParameterFunctional('mu'), 1] ), dirichlet_data=dirichlet, neumann_data=neumann, robin_data=robin, parameter_ranges=(0.1, 1), name='2DProblem' ) if isinstance(norm, float) and not args['--fv']: # use a random parameter to construct an energy product mu_bar = problem.parameters.parse(norm) else: mu_bar = None print('Discretize ...') if args['--fv']: m, data = discretize_stationary_fv(problem, diameter=1. / args['N']) else: m, data = discretize_stationary_cg(problem, diameter=1. / args['N'], mu_energy_product=mu_bar) print(data['grid']) print() print('Solve ...') U = m.solution_space.empty() for mu in problem.parameter_space.sample_uniformly(10): U.append(m.solve(mu)) if mu_bar is not None: # use the given energy product norm_squared = U[-1].norm(m.products['energy'])[0] print('Energy norm of the last snapshot: ', np.sqrt(norm_squared)) if not args['--fv']: if args['NORM'] == 'h1': norm_squared = U[-1].norm(m.products['h1_0_semi'])[0] print('H^1_0 semi norm of the last snapshot: ', np.sqrt(norm_squared)) if args['NORM'] == 'l2': norm_squared = U[-1].norm(m.products['l2_0'])[0] print('L^2_0 norm of the last snapshot: ', np.sqrt(norm_squared)) m.visualize(U, title='Solution for mu in [0.1, 1]')
def discretize_quadratic_pdeopt_stationary_cg(problem, diameter=np.sqrt(2) / 100., weights=None, parameter_scales=None, domain_of_interest=None, desired_temperature=None, mu_for_u_d=None, mu_for_tikhonov=False, parameters_in_q=True, product='h1_l2_boundary', solver_options=None, use_corrected_functional=True, use_corrected_gradient=False, adjoint_approach=False): if use_corrected_functional: print('I am using the corrected functional!!') else: print('I am using the OLD functional!!') if use_corrected_gradient: print('I am using the corrected gradient!!') else: if adjoint_approach: print( 'I am using the adjoint approach for computing the gradient!!') print('I am using the OLD gradient!!') mu_bar = _construct_mu_bar(problem) print(mu_bar) primal_fom, data = discretize_stationary_cg(problem, diameter=diameter, grid_type=RectGrid, energy_product=mu_bar) #Preassemble non parametric parts: simplify, put the constant part in only one function simplified_operators = [ ZeroOperator(primal_fom.solution_space, primal_fom.solution_space) ] simplified_coefficients = [1] to_pre_assemble = ZeroOperator(primal_fom.solution_space, primal_fom.solution_space) if isinstance(primal_fom.operator, LincombOperator): for (i, coef) in enumerate(primal_fom.operator.coefficients): if isinstance(coef, Parametric): simplified_coefficients.append(coef) simplified_operators.append(primal_fom.operator.operators[i]) else: to_pre_assemble += coef * primal_fom.operator.operators[i] else: to_pre_assemble += primal_fom.operator simplified_operators[0] += to_pre_assemble simplified_operators[0] = simplified_operators[0].assemble() lincomb_operator = LincombOperator( simplified_operators, simplified_coefficients, solver_options=primal_fom.operator.solver_options) simplified_rhs = [ ZeroOperator(primal_fom.solution_space, NumpyVectorSpace(1)) ] simplified_rhs_coefficients = [1] to_pre_assemble = ZeroOperator(primal_fom.solution_space, NumpyVectorSpace(1)) if isinstance(primal_fom.rhs, LincombOperator): for (i, coef) in enumerate(primal_fom.rhs.coefficients): if isinstance(coef, Parametric): simplified_rhs_coefficients.append(coef) simplified_rhs.append(primal_fom.rhs.operators[i]) else: to_pre_assemble += coef * primal_fom.rhs.operators[i] else: to_pre_assemble += primal_fom.rhs simplified_rhs[0] += to_pre_assemble simplified_rhs[0] = simplified_rhs[0].assemble() lincomb_rhs = LincombOperator(simplified_rhs, simplified_rhs_coefficients) primal_fom = primal_fom.with_(operator=lincomb_operator, rhs=lincomb_rhs) grid = data['grid'] d = grid.dim # prepare data functions if desired_temperature is not None: u_desired = ConstantFunction(desired_temperature, d) if domain_of_interest is None: domain_of_interest = ConstantFunction(1., d) if mu_for_u_d is not None: domain_of_interest = ConstantFunction(1., d) modifified_mu = mu_for_u_d.copy() for key in mu_for_u_d.keys(): if len(mu_for_u_d[key]) == 0: modifified_mu.pop(key) u_d = primal_fom.solve(modifified_mu) else: assert desired_temperature is not None u_d = InterpolationOperator(grid, u_desired).as_vector() if grid.reference_element is square: L2_OP = L2ProductQ1 else: L2_OP = L2ProductP1 Restricted_L2_OP = L2_OP(grid, data['boundary_info'], dirichlet_clear_rows=False, coefficient_function=domain_of_interest) l2_u_d_squared = Restricted_L2_OP.apply2(u_d, u_d)[0][0] constant_part = 0.5 * l2_u_d_squared # assemble output functional from pdeopt.theta import build_output_coefficient if weights is not None: weight_for_J = weights.pop('state') else: weight_for_J = 1. if isinstance(weight_for_J, dict): assert len( weight_for_J ) == 4, 'you need to give all derivatives including second order' state_functional = ExpressionParameterFunctional( weight_for_J['function'], weight_for_J['parameter_type'], derivative_expressions=weight_for_J['derivative'], second_derivative_expressions=weight_for_J['second_derivatives']) elif isinstance(weight_for_J, float) or isinstance(weight_for_J, int): state_functional = ConstantParameterFunctional(weight_for_J) else: assert 0, 'state weight needs to be an integer or a dict with derivatives' if mu_for_tikhonov: if mu_for_u_d is not None: mu_for_tikhonov = mu_for_u_d else: assert isinstance(mu_for_tikhonov, dict) output_coefficient = build_output_coefficient( primal_fom.parameter_type, weights, mu_for_tikhonov, parameter_scales, state_functional, constant_part) else: output_coefficient = build_output_coefficient( primal_fom.parameter_type, weights, None, parameter_scales, state_functional, constant_part) output_functional = {} output_functional['output_coefficient'] = output_coefficient output_functional['linear_part'] = LincombOperator( [VectorOperator(Restricted_L2_OP.apply(u_d))], [-state_functional]) # j(.) output_functional['bilinear_part'] = LincombOperator( [Restricted_L2_OP], [0.5 * state_functional]) # k(.,.) output_functional['d_u_linear_part'] = LincombOperator( [VectorOperator(Restricted_L2_OP.apply(u_d))], [-state_functional]) # j(.) output_functional['d_u_bilinear_part'] = LincombOperator( [Restricted_L2_OP], [state_functional]) # 2k(.,.) l2_boundary_product = RobinBoundaryOperator( grid, data['boundary_info'], robin_data=(ConstantFunction(1, 2), ConstantFunction(1, 2)), name='l2_boundary_product') # choose product if product == 'h1_l2_boundary': opt_product = primal_fom.h1_semi_product + l2_boundary_product # h1_semi + l2_boundary elif product == 'fixed_energy': opt_product = primal_fom.energy_product # energy w.r.t. mu_bar (see above) else: assert 0, 'product: {} is not nown'.format(product) print('my product is {}'.format(product)) primal_fom = primal_fom.with_( products=dict(opt=opt_product, l2_boundary=l2_boundary_product, **primal_fom.products)) pde_opt_fom = QuadraticPdeoptStationaryModel( primal_fom, output_functional, opt_product=opt_product, use_corrected_functional=use_corrected_functional, use_corrected_gradient=use_corrected_gradient) return pde_opt_fom, data, mu_bar
def discretize_fin_pdeopt_stationary_cg(problem, grid, boundary_info, mu_for_u_d, product='h1_l2_boundary', use_corrected_functional=True, use_corrected_gradient=False, add_constant_term=False): if use_corrected_functional: print('I am using the corrected functional!!') else: print('I am using the OLD functional!!') if use_corrected_gradient: print('I am using the corrected gradient!!') else: print('I am using the OLD gradient!!') mu_bar = _construct_mu_bar(problem) print(mu_bar) primal_fom, data = discretize_stationary_cg(problem, grid=grid, boundary_info=boundary_info, energy_product=mu_bar) u_d = primal_fom.solve(mu_for_u_d) Boundary_Functional = primal_fom.rhs.operators[1] T_root_d = Boundary_Functional.apply_adjoint(u_d) T_root_d_squared = T_root_d.to_numpy()[0][0]**2 # assemble output functional from pdeopt.theta import build_output_coefficient weights = {} mu_for_tikhonov = {} parameter_scales = {} for key, item in mu_for_u_d.items(): if isinstance(item, list): weights[key] = 1. / item[0]**2 else: weights[key] = 1. / item**2 mu_for_tikhonov[key] = mu_for_u_d[key] parameter_scales[key] = 1. if add_constant_term: state_functional = ConstantParameterFunctional(1.) output_coefficient = build_output_coefficient( primal_fom.parameter_type, weights, mu_for_tikhonov, parameter_scales, state_functional=state_functional, constant_part=0.5 * T_root_d_squared) else: output_coefficient = build_output_coefficient( primal_fom.parameter_type, weights, mu_for_tikhonov, parameter_scales) output_functional = {} class Boundary_squared_half(ImmutableObject): def __init__(self, source, range): self.__auto_init(locals()) self.linear = False def apply2(self, u, v, mu=None): return Boundary_Functional.apply_adjoint(u).to_numpy( ) * Boundary_Functional.apply_adjoint(v).to_numpy() * 0.5 class Boundary_squared(ImmutableObject): def __init__(self, source, range): self.__auto_init(locals()) self.linear = False def apply2(self, u, v, mu=None): return Boundary_Functional.apply_adjoint(u).to_numpy( ) * Boundary_Functional.apply_adjoint(v).to_numpy() def apply(self, u, mu=None): b = (Boundary_Functional.apply_adjoint(u).to_numpy()[0][0] * Boundary_Functional).as_vector() return b source_ = Boundary_Functional.source range_ = Boundary_Functional.range output_functional['output_coefficient'] = output_coefficient output_functional[ 'linear_part'] = -1 * Boundary_Functional * T_root_d.to_numpy()[0][ 0] # j(.) output_functional['bilinear_part'] = Boundary_squared_half( range_, range_) # k(.,.) output_functional[ 'd_u_linear_part'] = -1 * Boundary_Functional * T_root_d.to_numpy()[0][ 0] # j(.) output_functional['d_u_bilinear_part'] = Boundary_squared( range_, range_) # 2k(.,.) # choose product l2_boundary_product = RobinBoundaryOperator( grid, data['boundary_info'], robin_data=(ConstantFunction(1, 2), ConstantFunction(1, 2)), name='l2_boundary_product') # choose product if product == 'h1_l2_boundary': opt_product = primal_fom.h1_semi_product + l2_boundary_product # h1_semi + l2_boundary elif product == 'fixed_energy': opt_product = primal_fom.energy_product # energy w.r.t. mu_bar (see above) else: assert 0, 'product: {} is not known'.format(product) print('my product is {}'.format(product)) primal_fom = primal_fom.with_( products=dict(opt=opt_product, l2_boundary=l2_boundary_product, **primal_fom.products)) pde_opt_fom = QuadraticPdeoptStationaryModel( primal_fom, output_functional, opt_product=opt_product, fin_model=True, use_corrected_functional=use_corrected_functional, use_corrected_gradient=use_corrected_gradient) return pde_opt_fom, data, mu_bar
def elliptic2_demo(args): args['PROBLEM-NUMBER'] = int(args['PROBLEM-NUMBER']) assert 0 <= args['PROBLEM-NUMBER'] <= 1, ValueError( 'Invalid problem number.') args['N'] = int(args['N']) rhss = [ ExpressionFunction('ones(x.shape[:-1]) * 10', 2, ()), LincombFunction([ ExpressionFunction('ones(x.shape[:-1]) * 10', 2, ()), ConstantFunction(1., 2) ], [ProjectionParameterFunctional('mu'), 0.1]) ] dirichlets = [ ExpressionFunction('zeros(x.shape[:-1])', 2, ()), LincombFunction([ ExpressionFunction('2 * x[..., 0]', 2, ()), ConstantFunction(1., 2) ], [ProjectionParameterFunctional('mu'), 0.5]) ] neumanns = [ None, LincombFunction([ ExpressionFunction('1 - x[..., 1]', 2, ()), ConstantFunction(1., 2) ], [ProjectionParameterFunctional('mu'), 0.5**2]) ] robins = [ None, (LincombFunction( [ExpressionFunction('x[..., 1]', 2, ()), ConstantFunction(1., 2)], [ProjectionParameterFunctional('mu'), 1]), ConstantFunction(1., 2)) ] domains = [ RectDomain(), RectDomain(right='neumann', top='dirichlet', bottom='robin') ] rhs = rhss[args['PROBLEM-NUMBER']] dirichlet = dirichlets[args['PROBLEM-NUMBER']] neumann = neumanns[args['PROBLEM-NUMBER']] domain = domains[args['PROBLEM-NUMBER']] robin = robins[args['PROBLEM-NUMBER']] problem = StationaryProblem(domain=domain, rhs=rhs, diffusion=LincombFunction([ ExpressionFunction('1 - x[..., 0]', 2, ()), ExpressionFunction('x[..., 0]', 2, ()) ], [ProjectionParameterFunctional('mu'), 1]), dirichlet_data=dirichlet, neumann_data=neumann, robin_data=robin, parameter_ranges=(0.1, 1), name='2DProblem') print('Discretize ...') discretizer = discretize_stationary_fv if args[ '--fv'] else discretize_stationary_cg m, data = discretizer(problem, diameter=1. / args['N']) print(data['grid']) print() print('Solve ...') U = m.solution_space.empty() for mu in problem.parameter_space.sample_uniformly(10): U.append(m.solve(mu)) m.visualize(U, title='Solution for mu in [0.1, 1]')
def main( problem_number: int = Argument(..., min=0, max=1, help='Selects the problem to solve [0 or 1].'), n: int = Argument(..., help='Triangle count per direction'), norm: str = Argument( ..., help="h1: compute the h1-norm of the last snapshot.\n\n" "l2: compute the l2-norm of the last snapshot.\n\n" "k: compute the energy norm of the last snapshot, where the energy-product" "is constructed with a parameter {'mu': k}." ), fv: bool = Option(False, help='Use finite volume discretization instead of finite elements.'), ): """Solves the Poisson equation in 2D using pyMOR's builtin discreization toolkit.""" norm = float(norm) if not norm.lower() in ('h1', 'l2') else norm.lower() rhss = [ExpressionFunction('ones(x.shape[:-1]) * 10', 2, ()), LincombFunction( [ExpressionFunction('ones(x.shape[:-1]) * 10', 2, ()), ConstantFunction(1., 2)], [ProjectionParameterFunctional('mu'), 0.1])] dirichlets = [ExpressionFunction('zeros(x.shape[:-1])', 2, ()), LincombFunction( [ExpressionFunction('2 * x[..., 0]', 2, ()), ConstantFunction(1., 2)], [ProjectionParameterFunctional('mu'), 0.5])] neumanns = [None, LincombFunction( [ExpressionFunction('1 - x[..., 1]', 2, ()), ConstantFunction(1., 2)], [ProjectionParameterFunctional('mu'), 0.5**2])] robins = [None, (LincombFunction( [ExpressionFunction('x[..., 1]', 2, ()), ConstantFunction(1., 2)], [ProjectionParameterFunctional('mu'), 1]), ConstantFunction(1., 2))] domains = [RectDomain(), RectDomain(right='neumann', top='dirichlet', bottom='robin')] rhs = rhss[problem_number] dirichlet = dirichlets[problem_number] neumann = neumanns[problem_number] domain = domains[problem_number] robin = robins[problem_number] problem = StationaryProblem( domain=domain, rhs=rhs, diffusion=LincombFunction( [ExpressionFunction('1 - x[..., 0]', 2, ()), ExpressionFunction('x[..., 0]', 2, ())], [ProjectionParameterFunctional('mu'), 1] ), dirichlet_data=dirichlet, neumann_data=neumann, robin_data=robin, parameter_ranges=(0.1, 1), name='2DProblem' ) if isinstance(norm, float) and not fv: # use a random parameter to construct an energy product mu_bar = problem.parameters.parse(norm) else: mu_bar = None print('Discretize ...') if fv: m, data = discretize_stationary_fv(problem, diameter=1. / n) else: m, data = discretize_stationary_cg(problem, diameter=1. / n, mu_energy_product=mu_bar) print(data['grid']) print() print('Solve ...') U = m.solution_space.empty() for mu in problem.parameter_space.sample_uniformly(10): U.append(m.solve(mu)) if mu_bar is not None: # use the given energy product norm_squared = U[-1].norm(m.products['energy'])[0] print('Energy norm of the last snapshot: ', np.sqrt(norm_squared)) if not fv: if norm == 'h1': norm_squared = U[-1].norm(m.products['h1_0_semi'])[0] print('H^1_0 semi norm of the last snapshot: ', np.sqrt(norm_squared)) if norm == 'l2': norm_squared = U[-1].norm(m.products['l2_0'])[0] print('L^2_0 norm of the last snapshot: ', np.sqrt(norm_squared)) m.visualize(U, title='Solution for mu in [0.1, 1]')
# This file is part of the pyMOR project (http://www.pymor.org). # Copyright 2013-2020 pyMOR developers and contributors. All rights reserved. # License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) import numpy as np import pytest from pymor.analyticalproblems.functions import ConstantFunction, GenericFunction, ExpressionFunction constant_functions = \ [ConstantFunction(), ConstantFunction(np.array([1., 2., 3.]), dim_domain=7), ConstantFunction(np.eye(27), dim_domain=2), ConstantFunction(np.array(3), dim_domain=1)] def importable_function(x): return (x[..., 0] * x[..., 1])[..., np.newaxis] class A: @staticmethod def unimportable_function(x): return np.max(x, axis=-1) def get_function_with_closure(y): def function_with_closure(x): return np.concatenate((x + y, x - y), axis=-1)
def main( problem_number: int = Argument( ..., min=0, max=1, help='Selects the problem to solve [0 or 1].'), dirichlet_number: int = Argument( ..., min=0, max=2, help='Selects the Dirichlet data function [0 to 2].'), neumann_number: int = Argument( ..., min=0, max=2, help='Selects the Neumann data function.'), neumann_count: int = Argument( ..., min=0, max=3, help='0: no neumann boundary\n\n' '1: right edge is neumann boundary\n\n' '2: right+top edges are neumann boundary\n\n' '3: right+top+bottom edges are neumann boundary\n\n'), fv: bool = Option( False, help='Use finite volume discretization instead of finite elements.' ), rect: bool = Option(False, help='Use RectGrid instead of TriaGrid.'), ): """Solves the Poisson equation in 2D using pyMOR's builtin discreization toolkit.""" rhss = [ ExpressionFunction('ones(x.shape[:-1]) * 10', 2, ()), ExpressionFunction('(x[..., 0] - 0.5) ** 2 * 1000', 2, ()) ] dirichlets = [ ExpressionFunction('zeros(x.shape[:-1])', 2, ()), ExpressionFunction('ones(x.shape[:-1])', 2, ()), ExpressionFunction('x[..., 0]', 2, ()) ] neumanns = [ None, ConstantFunction(3., dim_domain=2), ExpressionFunction( '50*(0.1 <= x[..., 1]) * (x[..., 1] <= 0.2)' '+50*(0.8 <= x[..., 1]) * (x[..., 1] <= 0.9)', 2, ()) ] domains = [ RectDomain(), RectDomain(right='neumann'), RectDomain(right='neumann', top='neumann'), RectDomain(right='neumann', top='neumann', bottom='neumann') ] rhs = rhss[problem_number] dirichlet = dirichlets[dirichlet_number] neumann = neumanns[neumann_number] domain = domains[neumann_count] problem = StationaryProblem(domain=domain, diffusion=ConstantFunction(1, dim_domain=2), rhs=rhs, dirichlet_data=dirichlet, neumann_data=neumann) for n in [32, 128]: print('Discretize ...') discretizer = discretize_stationary_fv if fv else discretize_stationary_cg m, data = discretizer(analytical_problem=problem, grid_type=RectGrid if rect else TriaGrid, diameter=np.sqrt(2) / n if rect else 1. / n) grid = data['grid'] print(grid) print() print('Solve ...') U = m.solve() m.visualize(U, title=repr(grid)) print()
thermalblock_problems = picklable_thermalblock_problems + non_picklable_thermalblock_problems burgers_problems = \ [burgers_problem(), burgers_problem(v=0.2, circle=False), burgers_problem(v=0.4, initial_data_type='bump'), burgers_problem(parameter_range=(1., 1.3)), burgers_problem_2d(), burgers_problem_2d(torus=False, initial_data_type='bump', parameter_range=(1.3, 1.5))] picklable_elliptic_problems = \ [StationaryProblem(domain=RectDomain(), rhs=ConstantFunction(dim_domain=2, value=1.)), helmholtz_problem()] non_picklable_elliptic_problems = \ [StationaryProblem(domain=RectDomain(), rhs=ConstantFunction(dim_domain=2, value=21.), diffusion=LincombFunction( [GenericFunction(dim_domain=2, mapping=lambda X, p=p: X[..., 0]**p) for p in range(5)], [ExpressionParameterFunctional(f'max(mu["exp"], {m})', parameters={'exp': 1}) for m in range(5)] ))] elliptic_problems = picklable_thermalblock_problems + non_picklable_elliptic_problems
def text_problem(text='pyMOR', font_name=None): import numpy as np from PIL import Image, ImageDraw, ImageFont from tempfile import NamedTemporaryFile font_list = [font_name] if font_name else [ 'DejaVuSansMono.ttf', 'VeraMono.ttf', 'UbuntuMono-R.ttf', 'Arial.ttf' ] font = None for filename in font_list: try: font = ImageFont.truetype( filename, 64) # load some font from file of given size except (OSError, IOError): pass if font is None: raise ValueError('Could not load TrueType font') size = font.getsize(text) # compute width and height of rendered text size = (size[0] + 20, size[1] + 20 ) # add a border of 10 pixels around the text def make_bitmap_function( char_num ): # we need to genereate a BitmapFunction for each character img = Image.new('L', size) # create new Image object of given dimensions d = ImageDraw.Draw(img) # create ImageDraw object for the given Image # in order to position the character correctly, we first draw all characters from the first # up to the wanted character d.text((10, 10), text[:char_num + 1], font=font, fill=255) # next we erase all previous character by drawing a black rectangle if char_num > 0: d.rectangle( ((0, 0), (font.getsize(text[:char_num])[0] + 10, size[1])), fill=0, outline=0) # open a new temporary file with NamedTemporaryFile( suffix='.png' ) as f: # after leaving this 'with' block, the temporary # file is automatically deleted img.save(f, format='png') return BitmapFunction(f.name, bounding_box=[(0, 0), size], range=[0., 1.]) # create BitmapFunctions for each character dfs = [make_bitmap_function(n) for n in range(len(text))] # create an indicator function for the background background = ConstantFunction(1., 2) - LincombFunction( dfs, np.ones(len(dfs))) # form the linear combination dfs = [background] + dfs coefficients = [1] + [ ProjectionParameterFunctional('diffusion', len(text), i) for i in range(len(text)) ] diffusion = LincombFunction(dfs, coefficients) return StationaryProblem(domain=RectDomain(dfs[1].bounding_box, bottom='neumann'), neumann_data=ConstantFunction(-1., 2), diffusion=diffusion, parameter_ranges=(0.1, 1.))
def thermal_block_problem(num_blocks=(3, 3), parameter_range=(0.1, 1)): """Analytical description of a 2D 'thermal block' diffusion problem. The problem is to solve the elliptic equation :: - ∇ ⋅ [ d(x, μ) ∇ u(x, μ) ] = f(x, μ) on the domain [0,1]^2 with Dirichlet zero boundary values. The domain is partitioned into nx x ny blocks and the diffusion function d(x, μ) is constant on each such block (i,j) with value μ_ij. :: ---------------------------- | | | | | μ_11 | μ_12 | μ_13 | | | | | |--------------------------- | | | | | μ_21 | μ_22 | μ_23 | | | | | ---------------------------- Parameters ---------- num_blocks The tuple `(nx, ny)` parameter_range A tuple `(μ_min, μ_max)`. Each |Parameter| component μ_ij is allowed to lie in the interval [μ_min, μ_max]. """ def parameter_functional_factory(ix, iy): return ProjectionParameterFunctional(component_name='diffusion', component_shape=(num_blocks[1], num_blocks[0]), index=(num_blocks[1] - iy - 1, ix), name=f'diffusion_{ix}_{iy}') def diffusion_function_factory(ix, iy): if ix + 1 < num_blocks[0]: X = '(x[..., 0] >= ix * dx) * (x[..., 0] < (ix + 1) * dx)' else: X = '(x[..., 0] >= ix * dx)' if iy + 1 < num_blocks[1]: Y = '(x[..., 1] >= iy * dy) * (x[..., 1] < (iy + 1) * dy)' else: Y = '(x[..., 1] >= iy * dy)' return ExpressionFunction(f'{X} * {Y} * 1.', 2, (), {}, {'ix': ix, 'iy': iy, 'dx': 1. / num_blocks[0], 'dy': 1. / num_blocks[1]}, name=f'diffusion_{ix}_{iy}') return StationaryProblem( domain=RectDomain(), rhs=ConstantFunction(dim_domain=2, value=1.), diffusion=LincombFunction([diffusion_function_factory(ix, iy) for ix, iy in product(range(num_blocks[0]), range(num_blocks[1]))], [parameter_functional_factory(ix, iy) for ix, iy in product(range(num_blocks[0]), range(num_blocks[1]))], name='diffusion'), parameter_space=CubicParameterSpace({'diffusion': (num_blocks[1], num_blocks[0])}, *parameter_range), name=f'ThermalBlock({num_blocks})' )
def main( diameter: float = Argument( 0.01, help='Diameter option for the domain discretizer.'), r: int = Argument(5, help='Order of the ROMs.'), ): """Parametric 1D heat equation example.""" set_log_levels({'pymor.algorithms.gram_schmidt.gram_schmidt': 'WARNING'}) # Model p = InstationaryProblem(StationaryProblem( domain=LineDomain([0., 1.], left='robin', right='robin'), diffusion=LincombFunction([ ExpressionFunction('(x[...,0] <= 0.5) * 1.', 1), ExpressionFunction('(0.5 < x[...,0]) * 1.', 1) ], [1, ProjectionParameterFunctional('diffusion')]), robin_data=(ConstantFunction(1., 1), ExpressionFunction('(x[...,0] < 1e-10) * 1.', 1)), outputs=(('l2_boundary', ExpressionFunction('(x[...,0] > (1 - 1e-10)) * 1.', 1)), ), ), ConstantFunction(0., 1), T=3.) fom, _ = discretize_instationary_cg(p, diameter=diameter, nt=100) fom.visualize(fom.solve(mu=0.1)) fom.visualize(fom.solve(mu=1)) fom.visualize(fom.solve(mu=10)) lti = fom.to_lti() print(f'order of the model = {lti.order}') print(f'number of inputs = {lti.dim_input}') print(f'number of outputs = {lti.dim_output}') mu_list = [0.1, 1, 10] w_list = np.logspace(-1, 3, 100) # System poles fig, ax = plt.subplots() for mu in mu_list: poles = lti.poles(mu=mu) ax.plot(poles.real, poles.imag, '.', label=fr'$\mu = {mu}$') ax.set_title('System poles') ax.legend() plt.show() # Magnitude plots fig, ax = plt.subplots() for mu in mu_list: lti.mag_plot(w_list, ax=ax, mu=mu, label=fr'$\mu = {mu}$') ax.set_title('Magnitude plot of the full model') ax.legend() plt.show() # Hankel singular values fig, ax = plt.subplots() for mu in mu_list: hsv = lti.hsv(mu=mu) ax.semilogy(range(1, len(hsv) + 1), hsv, label=fr'$\mu = {mu}$') ax.set_title('Hankel singular values') ax.legend() plt.show() # System norms for mu in mu_list: print(f'mu = {mu}:') print(f' H_2-norm of the full model: {lti.h2_norm(mu=mu):e}') if config.HAVE_SLYCOT: print( f' H_inf-norm of the full model: {lti.hinf_norm(mu=mu):e}') print(f' Hankel-norm of the full model: {lti.hankel_norm(mu=mu):e}') # Model order reduction run_mor_method_param(lti, r, w_list, mu_list, BTReductor, 'BT') run_mor_method_param(lti, r, w_list, mu_list, LQGBTReductor, 'LQGBT') run_mor_method_param(lti, r, w_list, mu_list, BRBTReductor, 'BRBT') run_mor_method_param(lti, r, w_list, mu_list, IRKAReductor, 'IRKA') run_mor_method_param(lti, r, w_list, mu_list, TSIAReductor, 'TSIA') run_mor_method_param(lti, r, w_list, mu_list, OneSidedIRKAReductor, 'OS-IRKA', version='V')