def test_LincombParameterFunctional(): dict_of_d_mus = {'mu': ['200 * mu[0]', '2 * mu[0]'], 'nu': ['cos(nu[0])']} epf = ExpressionParameterFunctional('100 * mu[0]**2 + 2 * mu[1] * mu[0] + sin(nu[0])', {'mu': 2, 'nu': 1}, 'functional_with_derivative_and_second_derivative', dict_of_d_mus) pf = ProjectionParameterFunctional('mu', 2, 0) mu = Mu({'mu': [10,2], 'nu': [3]}) zero = pf - pf two_pf = pf + pf three_pf = pf + 2*pf pf_plus_one = pf + 1 sum_ = epf + pf pf_squared = (pf + 2*epf) * (pf - 2*epf) + 4 * epf * epf assert zero(mu) == 0 assert two_pf(mu) == 2 * pf(mu) assert three_pf(mu) == 3 * pf(mu) assert pf_plus_one(mu) == pf(mu) + 1 assert sum_(mu) == epf(mu) + pf(mu) assert pf_squared(mu) == pf(mu) * pf(mu) assert sum_.d_mu('mu', 0)(mu) == epf.d_mu('mu', 0)(mu) + pf.d_mu('mu', 0)(mu) assert sum_.d_mu('mu', 1)(mu) == epf.d_mu('mu', 1)(mu) + pf.d_mu('mu', 1)(mu) assert sum_.d_mu('nu', 0)(mu) == epf.d_mu('nu', 0)(mu) + pf.d_mu('nu', 0)(mu)
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), ExpressionParameterFunctional('0.1', {})])] dirichlets = [ExpressionFunction('zeros(x.shape[:-1])', 2, ()), LincombFunction( [ExpressionFunction('2 * x[..., 0]', 2, ()), ConstantFunction(1.,2)], [ProjectionParameterFunctional('mu', 0), ExpressionParameterFunctional('0.5', {})])] neumanns = [None, LincombFunction( [ExpressionFunction('1 - x[..., 1]', 2, ()), ConstantFunction(1.,2)], [ProjectionParameterFunctional('mu', 0), ExpressionParameterFunctional('0.5**2', {})])] robins = [None, (LincombFunction( [ExpressionFunction('x[..., 1]', 2, ()), ConstantFunction(1.,2)], [ProjectionParameterFunctional('mu', 0), ExpressionParameterFunctional('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=RectDomain(), rhs=rhs, diffusion=LincombFunction( [ExpressionFunction('1 - x[..., 0]', 2, ()), ExpressionFunction('x[..., 0]', 2, ())], [ProjectionParameterFunctional('mu', 0), ExpressionParameterFunctional('1', {})] ), dirichlet_data=dirichlet, neumann_data=neumann, robin_data=robin, parameter_space=CubicParameterSpace({'mu': 0}, 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 m.parameter_space.sample_uniformly(10): U.append(m.solve(mu)) m.visualize(U, title='Solution for mu in [0.1, 1]')
def _build_dual_models(self): assert self.primal_rom is not None assert self.RBPrimal is not None RBbasis = self.RBPrimal rhs_operators = list( self.fom.output_functional_dict['d_u_linear_part'].operators) rhs_coefficients = list( self.fom.output_functional_dict['d_u_linear_part'].coefficients) bilinear_part = self.fom.output_functional_dict['d_u_bilinear_part'] for i in range(len(RBbasis)): u = RBbasis[i] if isinstance(bilinear_part, LincombOperator): for j, op in enumerate(bilinear_part.operators): rhs_operators.append(VectorOperator(op.apply(u))) rhs_coefficients.append( ExpressionParameterFunctional( 'basis_coefficients[{}]'.format(i), {'basis_coefficients': len(RBbasis)}) * bilinear_part.coefficients[j]) else: rhs_operators.append( VectorOperator(bilinear_part.apply(u, None))) rhs_coefficients.append(1. * ExpressionParameterFunctional( 'basis_coefficients[{}]'.format(i), {'basis_coefficients': len(RBbasis)})) dual_rhs_operator = LincombOperator(rhs_operators, rhs_coefficients) dual_intermediate_fom = self.fom.primal_model.with_( rhs=dual_rhs_operator) if self.reductor_type == 'simple_coercive': print('building simple coercive dual reductor...') dual_reductor = SimpleCoerciveRBReductor( dual_intermediate_fom, RB=self.RBDual, product=self.opt_product, coercivity_estimator=self.coercivity_estimator) elif self.reductor_type == 'non_assembled': print('building non assembled dual reductor...') dual_reductor = NonAssembledCoerciveRBReductor( dual_intermediate_fom, RB=self.RBDual, product=self.opt_product, coercivity_estimator=self.coercivity_estimator) else: print('building coercive dual reductor...') dual_reductor = CoerciveRBReductor( dual_intermediate_fom, RB=self.RBDual, product=self.opt_product, coercivity_estimator=self.coercivity_estimator) dual_rom = dual_reductor.reduce() return dual_intermediate_fom, dual_rom, dual_reductor
def init_grid_and_problem(config): logger = getLogger('senegal_proceedings_problem.senegal_proceedings_problem') logger.info('initializing grid and problem ... ') lower_left = [-1, -1] upper_right = [1, 1] inner_boundary_id = 18446744073709551573 grid = make_grid(lower_left=lower_left, upper_right=upper_right, num_elements=config['num_coarse_grid_elements'], num_refinements=config['num_grid_refinements'], num_partitions=config['num_grid_subdomains'], num_oversampling_layers=config['num_grid_oversampling_layers'], inner_boundary_segment_index=inner_boundary_id) all_dirichlet_boundary_info = make_boundary_info(grid, {'type': 'xt.grid.boundaryinfo.alldirichlet'}) def make_values(background, foreground): checkerboard_values = [[background]]*36 for ii in (7, 25): checkerboard_values[ii] = [foreground] return checkerboard_values diffusion_functions = [make_checkerboard_function_1x1(grid, lower_left, upper_right, [6, 6], make_values(1., 0.), name='lambda_0'), make_checkerboard_function_1x1(grid, lower_left, upper_right, [6, 6], make_values(0., 1.), name='lambda_1')] parameter_type = {'diffusion': (2,)} coefficients = [ExpressionParameterFunctional('1.1 + sin(diffusion[0])*diffusion[1]', parameter_type), ExpressionParameterFunctional('1.1 + sin(diffusion[1])', parameter_type)] kappa = make_constant_function_2x2(grid, [[1., 0.], [0., 1.]], name='kappa') f = make_expression_function_1x1(grid, 'x', '0.5*pi*pi*cos(0.5*pi*x[0])*cos(0.5*pi*x[1])', order=2, name='f') lambda_bar = make_checkerboard_function_1x1(grid, lower_left, upper_right, [6, 6], make_values(1.1, 1.1), name='lambda_bar') lambda_hat = make_checkerboard_function_1x1(grid, lower_left, upper_right, [6, 6], make_values(1.1, 1.1), name='lambda_hat') return {'grid': grid, 'boundary_info': all_dirichlet_boundary_info, 'inner_boundary_id': inner_boundary_id, 'lambda': {'functions': diffusion_functions, 'coefficients': coefficients}, 'lambda_bar': lambda_bar, 'lambda_hat': lambda_hat, 'kappa': kappa, 'f': f, 'parameter_type': parameter_type, 'mu_bar': (0, 0), 'mu_hat': (0, 0), 'mu_min': (0, 0), 'mu_max': (np.pi, np.pi), 'parameter_range': (0, np.pi)}
def test_identity_lincomb(): space = NumpyVectorSpace(10) identity = IdentityOperator(space) ones = space.ones() idid = (identity + identity) idid_ = ExpressionParameterFunctional('2', {}) * identity assert almost_equal(ones * 2, idid.apply(ones)) assert almost_equal(ones * 2, idid.apply_adjoint(ones)) assert almost_equal(ones * 0.5, idid.apply_inverse(ones)) assert almost_equal(ones * 0.5, idid.apply_inverse_adjoint(ones)) assert almost_equal(ones * 0.5, idid_.apply_inverse(ones)) assert almost_equal(ones * 0.5, idid_.apply_inverse_adjoint(ones))
def test_d_mu_of_LincombOperator(): dict_of_d_mus = {'mu': ['100', '2'], 'nu': 'cos(nu)'} pf = ProjectionParameterFunctional('mu', (2, ), (0, )) epf = ExpressionParameterFunctional('100 * mu[0] + 2 * mu[1] + sin(nu)', { 'mu': (2, ), 'nu': () }, 'functional_with_derivative', dict_of_d_mus) mu = {'mu': (10, 2), 'nu': 0} space = NumpyVectorSpace(1) zero_op = ZeroOperator(space, space) operators = [zero_op, zero_op, zero_op] coefficients = [1., pf, epf] operator = LincombOperator(operators, coefficients) op_sensitivity_to_first_mu = operator.d_mu('mu', 0) op_sensitivity_to_second_mu = operator.d_mu('mu', 1) op_sensitivity_to_nu = operator.d_mu('nu', ()) eval_mu_1 = op_sensitivity_to_first_mu.evaluate_coefficients(mu) eval_mu_2 = op_sensitivity_to_second_mu.evaluate_coefficients(mu) eval_nu = op_sensitivity_to_nu.evaluate_coefficients(mu) assert operator.evaluate_coefficients(mu) == [1., 10, 1004.] assert eval_mu_1 == [0., 1., 100.] assert eval_mu_2 == [0., 0., 2.] assert eval_nu == [0., 0., 1.]
def test_min_theta_parameter_functional_fails_for_wrong_input(): thetas = (ExpressionParameterFunctional('2*mu[0]', {'mu': 1}), ConstantParameterFunctional(1), -1) mu_bar = -3 alpha_mu_bar = 10 with pytest.raises(AssertionError): theta = MinThetaParameterFunctional(thetas, mu_bar, alpha_mu_bar)
def test_base_max_theta_parameter_functional(): thetas = (ExpressionParameterFunctional('2*mu[0]', {'mu': 1}, derivative_expressions={ 'mu': ['2'] }), ConstantParameterFunctional(1)) # theta prime can for example be the derivatives of all theta thetas_prime = tuple([theta.d_mu('mu', 0) for theta in thetas]) mu_bar = -3 gamma_mu_bar = 10 theta = BaseMaxThetaParameterFunctional(thetas_prime, thetas, mu_bar, gamma_mu_bar) thetas = [ ConstantParameterFunctional(t) if not isinstance(t, ParameterFunctional) else t for t in thetas ] thetas_prime = [ ConstantParameterFunctional(t) if not isinstance(t, ParameterFunctional) else t for t in thetas_prime ] mu = theta.parameters.parse(1) mu_bar = theta.parameters.parse(mu_bar) expected_value = gamma_mu_bar * np.abs( np.max( np.array([t(mu) for t in thetas_prime]) / np.array([np.abs(t(mu_bar)) for t in thetas]))) actual_value = theta.evaluate(mu) assert expected_value == actual_value
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, ()) parameter_space = CubicParameterSpace({'diffusionl': 0}, 0.1, 1) f0 = ProjectionParameterFunctional('diffusionl', 0) f1 = ExpressionParameterFunctional('1', {}) problem = StationaryProblem( domain=LineDomain(), rhs=rhs, diffusion=LincombFunction([d0, d1], [f0, f1]), dirichlet_data=ConstantFunction(value=0, dim_domain=1), name='1DProblem' ) print('Discretize ...') discretizer = discretize_stationary_fv if args['--fv'] else discretize_stationary_cg d, data = discretizer(problem, diameter=1 / args['N']) print(data['grid']) print() print('Solve ...') U = d.solution_space.empty() for mu in parameter_space.sample_uniformly(10): U.append(d.solve(mu)) d.visualize(U, title='Solution for diffusionl in [0.1, 1]')
def test_LincombParameterFunctional(): dict_of_d_mus = {'mu': ['200 * mu[0]', '2 * mu[0]'], 'nu': ['cos(nu[0])']} epf = ExpressionParameterFunctional('100 * mu[0]**2 + 2 * mu[1] * mu[0] + sin(nu[0])', {'mu': 2, 'nu': 1}, 'functional_with_derivative_and_second_derivative', dict_of_d_mus) pf = ProjectionParameterFunctional('mu', 2, 0) mu = Mu({'mu': [10,2], 'nu': [3]}) zero = pf - pf two_pf = pf + pf two_pf_named = two_pf.with_(name='some_interesting_quantity') three_pf = pf + 2*pf three_pf_ = pf + two_pf three_pf_named = pf + two_pf_named pf_plus_one = pf + 1 pf_plus_one_ = 1 + pf sum_ = epf + pf + 1 - 3 pf_squared_ = pf * pf pf_squared_named = pf_squared_.with_(name='some_interesting_quantity') pf_times_pf_squared = pf * pf_squared_ pf_times_pf_squared_named = pf * pf_squared_named pf_squared = 4 * epf * epf * 1 + (pf + 2*epf) * (pf - 2*epf) assert zero(mu) == 0 assert two_pf(mu) == 2 * pf(mu) assert three_pf(mu) == 3 * pf(mu) assert three_pf_(mu) == 3 * pf(mu) assert pf_plus_one(mu) == pf(mu) + 1 assert pf_plus_one_(mu) == pf(mu) + 1 assert sum_(mu) == epf(mu) + pf(mu) + 1 - 3 assert pf_squared_(mu) == pf(mu) * pf(mu) assert pf_squared(mu) == pf(mu) * pf(mu) assert pf_times_pf_squared(mu) == pf(mu) * pf(mu) * pf(mu) # derivatives are linear assert sum_.d_mu('mu', 0)(mu) == epf.d_mu('mu', 0)(mu) + pf.d_mu('mu', 0)(mu) assert sum_.d_mu('mu', 1)(mu) == epf.d_mu('mu', 1)(mu) + pf.d_mu('mu', 1)(mu) assert sum_.d_mu('nu', 0)(mu) == epf.d_mu('nu', 0)(mu) + pf.d_mu('nu', 0)(mu) # sums and products are not nested assert len(sum_.coefficients) == 4 assert len(pf_squared.functionals[0].factors) == 4 # named functions will not be merged and still be nested assert three_pf_named(mu) == three_pf_(mu) assert len(three_pf_named.coefficients) != len(three_pf_.coefficients) assert pf_times_pf_squared_named(mu) == pf_times_pf_squared(mu) assert len(pf_times_pf_squared_named.factors) != len(pf_times_pf_squared.factors)
def test_ProductParameterFunctional(): # Projection ParameterFunctional pf = ProjectionParameterFunctional('mu', 2, 0) # Expression ParameterFunctional dict_of_d_mus = {'nu': ['2*nu']} dict_of_second_derivative = {'nu': [{'nu': ['2']}]} epf = ExpressionParameterFunctional('nu**2', {'nu': 1}, 'expression_functional', dict_of_d_mus, dict_of_second_derivative) mu = Mu({'mu': (10,2), 'nu': 3}) productf = pf * epf * 2. * pf derivative_to_first_index = productf.d_mu('mu', 0) derivative_to_second_index = productf.d_mu('mu', 1) derivative_to_third_index = productf.d_mu('nu', 0) second_derivative_first_first = productf.d_mu('mu', 0).d_mu('mu', 0) second_derivative_first_second = productf.d_mu('mu', 0).d_mu('mu', 1) second_derivative_first_third = productf.d_mu('mu', 0).d_mu('nu', 0) second_derivative_second_first = productf.d_mu('mu', 1).d_mu('mu', 0) second_derivative_second_second = productf.d_mu('mu', 1).d_mu('mu', 1) second_derivative_second_third = productf.d_mu('mu', 1).d_mu('nu', 0) second_derivative_third_first = productf.d_mu('nu', 0).d_mu('mu', 0) second_derivative_third_second = productf.d_mu('nu', 0).d_mu('mu', 1) second_derivative_third_third = productf.d_mu('nu', 0).d_mu('nu', 0) der_mu_1 = derivative_to_first_index.evaluate(mu) der_mu_2 = derivative_to_second_index.evaluate(mu) der_nu_3 = derivative_to_third_index.evaluate(mu) hes_mu_1_mu_1 = second_derivative_first_first.evaluate(mu) hes_mu_1_mu_2 = second_derivative_first_second.evaluate(mu) hes_mu_1_nu_3 = second_derivative_first_third.evaluate(mu) hes_mu_2_mu_1 = second_derivative_second_first.evaluate(mu) hes_mu_2_mu_2 = second_derivative_second_second.evaluate(mu) hes_mu_2_nu_3 = second_derivative_second_third.evaluate(mu) hes_nu_3_mu_1 = second_derivative_third_first.evaluate(mu) hes_nu_3_mu_2 = second_derivative_third_second.evaluate(mu) hes_nu_3_nu_3 = second_derivative_third_third.evaluate(mu) # note that productf(mu,nu) = 2 * pf(mu)**2 * epf(nu) # and thus: # d_mu productf(mu,nu) = 2 * 2 * pf(mu) * (d_mu pf)(mu) * epf(nu) # d_nu productf(mu,nu) = 2 * pf(mu)**2 * (d_nu epf)(nu) # and so forth assert der_mu_1 == 2 * 2 * 10 * 1 * 9 assert der_mu_2 == 0 assert der_nu_3 == 2 * 10**2 * 6 assert hes_mu_1_mu_1 == 2 * 2 * 9 assert hes_mu_1_mu_2 == 0 assert hes_mu_1_nu_3 == 2 * 2 * 10 * 1 * 6 assert hes_mu_2_mu_1 == 0 assert hes_mu_2_mu_2 == 0 assert hes_mu_2_nu_3 == 0 assert hes_nu_3_mu_1 == 2 * 2 * 10 * 1 * 6 assert hes_nu_3_mu_2 == 0 assert hes_nu_3_nu_3 == 2 * 10**2 * 2
def test_lincomb_adjoint(): op = LincombOperator([NumpyMatrixOperator(np.eye(10)), NumpyMatrixOperator(np.eye(10))], [1+3j, ExpressionParameterFunctional('c[0] + 3', {'c': 1})]) mu = op.parameters.parse(1j) U = op.range.random() V = op.apply_adjoint(U, mu=mu) VV = op.H.apply(U, mu=mu) assert np.all(almost_equal(V, VV)) VVV = op.apply(U, mu=mu).conj() assert np.all(almost_equal(V, VVV))
def test_ExpressionParameterFunctional_for_2d_array(): dict_of_d_mus_2d = {'mu': [['10', '20'], ['1', '2']], 'nu': 'cos(nu)'} epf2d = ExpressionParameterFunctional( '10 * mu[(0,0)] + 20 * mu[(0,1)] \ + 1 * mu[(1,0)] + 2 * mu[(1,1)] \ + sin(nu)', { 'mu': (2, 2), 'nu': () }, 'functional_with_derivative', dict_of_d_mus_2d) derivative_to_11_mu_index = epf2d.d_mu('mu', (0, 0)) derivative_to_12_mu_index = epf2d.d_mu('mu', (0, 1)) derivative_to_21_mu_index = epf2d.d_mu('mu', (1, 0)) derivative_to_22_mu_index = epf2d.d_mu('mu', (1, 1)) derivative_to_nu_index = epf2d.d_mu('nu') mu = {'mu': (1, 2, 3, 4), 'nu': 0} der_mu_11 = derivative_to_11_mu_index.evaluate(mu) der_mu_12 = derivative_to_12_mu_index.evaluate(mu) der_mu_21 = derivative_to_21_mu_index.evaluate(mu) der_mu_22 = derivative_to_22_mu_index.evaluate(mu) der_nu = derivative_to_nu_index.evaluate(mu) assert epf2d.evaluate(mu) == 1 * 10 + 2 * 20 + 3 * 1 + 4 * 2 + 0 assert der_mu_11 == 10 assert der_mu_12 == 20 assert der_mu_21 == 1 assert der_mu_22 == 2 assert der_nu == 1
def test_simple_ProductParameterFunctional(): pf = ProjectionParameterFunctional('mu', 2, 0) mu = Mu({'mu': (10,2)}) productf = pf * 2 * 3 derivative_to_first_index = productf.d_mu('mu', 0) derivative_to_second_index = productf.d_mu('mu', 1) second_derivative_first_first = productf.d_mu('mu', 0).d_mu('mu', 0) second_derivative_first_second = productf.d_mu('mu', 0).d_mu('mu', 1) second_derivative_second_first = productf.d_mu('mu', 1).d_mu('mu', 0) second_derivative_second_second = productf.d_mu('mu', 1).d_mu('mu', 1) der_mu_1 = derivative_to_first_index.evaluate(mu) der_mu_2 = derivative_to_second_index.evaluate(mu) hes_mu_1_mu_1 = second_derivative_first_first.evaluate(mu) hes_mu_1_mu_2 = second_derivative_first_second.evaluate(mu) hes_mu_2_mu_1 = second_derivative_second_first.evaluate(mu) hes_mu_2_mu_2 = second_derivative_second_second.evaluate(mu) assert der_mu_1 == 2 * 3 assert der_mu_2 == 0 assert hes_mu_1_mu_1 == 0 assert hes_mu_1_mu_2 == 0 assert hes_mu_2_mu_1 == 0 assert hes_mu_2_mu_2 == 0 dict_of_d_mus = {'mu': ['2*mu']} dict_of_second_derivative = {'mu': [{'mu': ['2']}]} epf = ExpressionParameterFunctional('mu**2', {'mu': 1}, 'functional_with_derivative_and_second_derivative', dict_of_d_mus, dict_of_second_derivative) productf = epf * 2 mu = Mu({'mu': 3}) derivative_to_first_index = productf.d_mu('mu') second_derivative_first_first = productf.d_mu('mu').d_mu('mu') der_mu = derivative_to_first_index.evaluate(mu) hes_mu_mu = second_derivative_first_first.evaluate(mu) assert productf.evaluate(mu) == 2 * 3 ** 2 assert der_mu == 2 * 2 * 3 assert hes_mu_mu == 2 * 2
def __init__(self, domain=RectDomain(), rhs=None, parameter_range=(0., 100.), dirichlet_data=None, neumann_data=None): self.parameter_range = parameter_range # needed for with_ parameter_space = CubicParameterSpace({'k': ()}, *parameter_range) super().__init__( diffusion_functions=[ConstantFunction(1., dim_domain=domain.dim)], diffusion_functionals=[1.], reaction_functions=[ConstantFunction(1., dim_domain=domain.dim)], reaction_functionals=[ExpressionParameterFunctional('-k**2', {'k': ()})], domain=domain, rhs=rhs or ConstantFunction(1., dim_domain=domain.dim), parameter_space=parameter_space, dirichlet_data=dirichlet_data, neumann_data=neumann_data)
def test_min_theta_parameter_functional(): thetas = (ExpressionParameterFunctional('2*mu', {'mu': ()}), ConstantParameterFunctional(1), 1) mu_bar = 3 alpha_mu_bar = 10 theta = MinThetaParameterFunctional(thetas, mu_bar, alpha_mu_bar) thetas = [ ConstantParameterFunctional(t) if not isinstance(t, ParameterFunctional) else t for t in thetas ] mu = 1 expected_value = alpha_mu_bar * np.min( np.array([t(mu) for t in thetas]) / np.array([t(mu_bar) for t in thetas])) actual_value = theta.evaluate(mu) assert expected_value == actual_value
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**2', {'k': ()})]), parameter_space=CubicParameterSpace({'k': ()}, *parameter_range), name='helmholtz_problem' )
def test_max_theta_parameter_functional(): thetas = (ExpressionParameterFunctional('2*mu[0]', {'mu': 1}), ConstantParameterFunctional(1), -1) mu_bar = -3 gamma_mu_bar = 10 theta = MaxThetaParameterFunctional(thetas, mu_bar, gamma_mu_bar) thetas = [ ConstantParameterFunctional(t) if not isinstance(t, ParameterFunctional) else t for t in thetas ] mu = theta.parameters.parse(1) mu_bar = theta.parameters.parse(mu_bar) expected_value = gamma_mu_bar * np.abs( np.max( np.array([t(mu) for t in thetas]) / np.array([t(mu_bar) for t in thetas]))) actual_value = theta.evaluate(mu) assert expected_value == actual_value
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, ()), ExpressionFunction('(x[..., 0] - 0.5)**2 * 1000', 2, ()) ] rhs = rhss[args['PROBLEM-NUMBER']] problem = StationaryProblem( domain=RectDomain(), rhs=rhs, diffusion=LincombFunction([ ExpressionFunction('1 - x[..., 0]', 2, ()), ExpressionFunction('x[..., 0]', 2, ()) ], [ ProjectionParameterFunctional('diffusionl', 0), ExpressionParameterFunctional('1', {}) ]), parameter_space=CubicParameterSpace({'diffusionl': 0}, 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 m.parameter_space.sample_uniformly(10): U.append(m.solve(mu)) m.visualize(U, title='Solution for diffusionl in [0.1, 1]')
def test_ExpressionParameterFunctional(): dict_of_d_mus = {'mu': ['100', '2'], 'nu': 'cos(nu)'} epf = ExpressionParameterFunctional('100 * mu[0] + 2 * mu[1] + sin(nu)', { 'mu': (2, ), 'nu': () }, 'functional_with_derivative', dict_of_d_mus) mu = {'mu': (10, 2), 'nu': 0} derivative_to_first_mu_index = epf.d_mu('mu', 0) derivative_to_second_mu_index = epf.d_mu('mu', 1) derivative_to_nu_index = epf.d_mu('nu', ()) der_mu_1 = derivative_to_first_mu_index.evaluate(mu) der_mu_2 = derivative_to_second_mu_index.evaluate(mu) der_nu = derivative_to_nu_index.evaluate(mu) assert epf.evaluate(mu) == 100 * 10 + 2 * 2 + 0 assert der_mu_1 == 100 assert der_mu_2 == 2 assert der_nu == 1
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('max(mu["exp"], {})'.format(m), parameter_type={'exp': ()}) for m in range(5)] ))] elliptic_problems = picklable_thermalblock_problems + non_picklable_elliptic_problems @pytest.fixture(params=elliptic_problems + thermalblock_problems + burgers_problems) def analytical_problem(request): return request.param @pytest.fixture(params=picklable_elliptic_problems + picklable_thermalblock_problems + burgers_problems) def picklable_analytical_problem(request):
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
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})', parameter_type={'exp': ()}) for m in range(5)] ))] elliptic_problems = picklable_thermalblock_problems + non_picklable_elliptic_problems @pytest.fixture(params=elliptic_problems + thermalblock_problems + burgers_problems) def analytical_problem(request): return request.param @pytest.fixture(params=picklable_elliptic_problems + picklable_thermalblock_problems + burgers_problems) def picklable_analytical_problem(request):
def EXC_problem(input_dict=None, summed_quantities=None, outside_temperature=10, q_inverse=1., parameters_in_q=False, parameter_scaling=False, relative_path='', data_path='../../EXC_data', coefficient_expressions=None): ''' initialize EXC problem ''' # The pixels of the pictures are 200 x 100 bounding_box = [[0, 0], [2, 1]] # converting Bitmaps # Windows = Fenster f1 = BitmapFunction('{}{}/f1.png'.format(relative_path, data_path), range=[1., 0.], bounding_box=bounding_box) f2 = BitmapFunction('{}{}/f2.png'.format(relative_path, data_path), range=[1., 0.], bounding_box=bounding_box) f3 = BitmapFunction('{}{}/f3.png'.format(relative_path, data_path), range=[1., 0.], bounding_box=bounding_box) f4 = BitmapFunction('{}{}/f4.png'.format(relative_path, data_path), range=[1., 0.], bounding_box=bounding_box) f5 = BitmapFunction('{}{}/f5.png'.format(relative_path, data_path), range=[1., 0.], bounding_box=bounding_box) f6 = BitmapFunction('{}{}/f6.png'.format(relative_path, data_path), range=[1., 0.], bounding_box=bounding_box) f7 = BitmapFunction('{}{}/f7.png'.format(relative_path, data_path), range=[1., 0.], bounding_box=bounding_box) f8 = BitmapFunction('{}{}/f8.png'.format(relative_path, data_path), range=[1., 0.], bounding_box=bounding_box) f9 = BitmapFunction('{}{}/f9.png'.format(relative_path, data_path), range=[1., 0.], bounding_box=bounding_box) f10 = BitmapFunction('{}{}/f10.png'.format(relative_path, data_path), range=[1., 0.], bounding_box=bounding_box) f11 = BitmapFunction('{}{}/f11.png'.format(relative_path, data_path), range=[1., 0.], bounding_box=bounding_box) f12 = BitmapFunction('{}{}/f12.png'.format(relative_path, data_path), range=[1., 0.], bounding_box=bounding_box) # Walls = Waende w1 = BitmapFunction('{}{}/w1.png'.format(relative_path, data_path), range=[1., 0.], bounding_box=bounding_box) w2 = BitmapFunction('{}{}/w2.png'.format(relative_path, data_path), range=[1., 0.], bounding_box=bounding_box) w3 = BitmapFunction('{}{}/w3.png'.format(relative_path, data_path), range=[1., 0.], bounding_box=bounding_box) w4 = BitmapFunction('{}{}/w4.png'.format(relative_path, data_path), range=[1., 0.], bounding_box=bounding_box) w5 = BitmapFunction('{}{}/w5.png'.format(relative_path, data_path), range=[1., 0.], bounding_box=bounding_box) w6 = BitmapFunction('{}{}/w6.png'.format(relative_path, data_path), range=[1., 0.], bounding_box=bounding_box) w7 = BitmapFunction('{}{}/w7.png'.format(relative_path, data_path), range=[1., 0.], bounding_box=bounding_box) w8 = BitmapFunction('{}{}/w8.png'.format(relative_path, data_path), range=[1., 0.], bounding_box=bounding_box) sw = BitmapFunction('{}{}/sw.png'.format(relative_path, data_path), range=[1., 0.], bounding_box=bounding_box) aw = BitmapFunction('{}{}/aw.png'.format(relative_path, data_path), range=[1., 0.], bounding_box=bounding_box) # Doors = Tueren t1 = BitmapFunction('{}{}/t1.png'.format(relative_path, data_path), range=[1., 0.], bounding_box=bounding_box) t2 = BitmapFunction('{}{}/t2.png'.format(relative_path, data_path), range=[1., 0.], bounding_box=bounding_box) t3 = BitmapFunction('{}{}/t3.png'.format(relative_path, data_path), range=[1., 0.], bounding_box=bounding_box) t4 = BitmapFunction('{}{}/t4.png'.format(relative_path, data_path), range=[1., 0.], bounding_box=bounding_box) t5 = BitmapFunction('{}{}/t5.png'.format(relative_path, data_path), range=[1., 0.], bounding_box=bounding_box) t6 = BitmapFunction('{}{}/t6.png'.format(relative_path, data_path), range=[1., 0.], bounding_box=bounding_box) t7 = BitmapFunction('{}{}/t7.png'.format(relative_path, data_path), range=[1., 0.], bounding_box=bounding_box) # outer Doors = Aussentueren at1 = BitmapFunction('{}{}/at1.png'.format(relative_path, data_path), range=[1., 0.], bounding_box=bounding_box) at2 = BitmapFunction('{}{}/at2.png'.format(relative_path, data_path), range=[1., 0.], bounding_box=bounding_box) it = BitmapFunction('{}{}/it.png'.format(relative_path, data_path), range=[1., 0.], bounding_box=bounding_box) #heaters h1 = BitmapFunction('{}{}/h1.png'.format(relative_path, data_path), range=[1., 0.], bounding_box=bounding_box) h2 = BitmapFunction('{}{}/h2.png'.format(relative_path, data_path), range=[1., 0.], bounding_box=bounding_box) h3 = BitmapFunction('{}{}/h3.png'.format(relative_path, data_path), range=[1., 0.], bounding_box=bounding_box) h4 = BitmapFunction('{}{}/h4.png'.format(relative_path, data_path), range=[1., 0.], bounding_box=bounding_box) h5 = BitmapFunction('{}{}/h5.png'.format(relative_path, data_path), range=[1., 0.], bounding_box=bounding_box) h6 = BitmapFunction('{}{}/h6.png'.format(relative_path, data_path), range=[1., 0.], bounding_box=bounding_box) h7 = BitmapFunction('{}{}/h7.png'.format(relative_path, data_path), range=[1., 0.], bounding_box=bounding_box) h8 = BitmapFunction('{}{}/h8.png'.format(relative_path, data_path), range=[1., 0.], bounding_box=bounding_box) h9 = BitmapFunction('{}{}/h9.png'.format(relative_path, data_path), range=[1., 0.], bounding_box=bounding_box) h10 = BitmapFunction('{}{}/h10.png'.format(relative_path, data_path), range=[1., 0.], bounding_box=bounding_box) h11 = BitmapFunction('{}{}/h11.png'.format(relative_path, data_path), range=[1., 0.], bounding_box=bounding_box) h12 = BitmapFunction('{}{}/h12.png'.format(relative_path, data_path), range=[1., 0.], bounding_box=bounding_box) if input_dict is None: parametric_quantities = { 'walls': [4, 6], 'windows': [], 'doors': [6], 'heaters': [1] } active_quantities = { 'removed_walls': [], 'open_windows': [12], 'open_doors': [2, 7], 'active_heaters': [3, 8, 12] } input_dict = set_input_dict(parametric_quantities, active_quantities, parameters_in_q=parameters_in_q) if summed_quantities is None: summed_quantities = { 'walls': [], 'windows': [], 'doors': [], 'heaters': [] } # background if parameters_in_q: background = BitmapFunction('{}{}/background.png'.format( relative_path, data_path), range=[0., 1.], bounding_box=bounding_box) else: background = BitmapFunction('{}{}/full_diffusion.png'.format( relative_path, data_path), range=[0., 1.], bounding_box=bounding_box) if parameters_in_q: diffusion_functions = [ background, w1, w2, w3, w4, w5, w6, w7, w8, sw, t1, t2, t3, t4, t5, t6, t7, it ] for key in summed_quantities.keys(): if len(summed_quantities[key]) > 0: for li in summed_quantities[key]: idx = 0 if isinstance(li, str): if li == 'a': start_idx = 0 idx = 1 if key == 'walls': li_iterate = list(np.arange(2, 11)) if key == 'doors': li_iterate = list(np.arange(2, 11)) else: if key == 'walls': start_idx = 0 idx = li[0] + start_idx if key == 'doors': start_idx = 9 idx = li[0] + start_idx li_iterate = li[1:] if idx != 0: new_lincomb_functions = [diffusion_functions[idx]] new_lincomb_coefficients = [1.] for l in li_iterate: new_lincomb_functions.append( diffusion_functions[l + start_idx]) new_lincomb_coefficients.append(1.) diffusion_functions[l + start_idx] = ConstantFunction( 0, 2) diffusion_functions[idx] = LincombFunction( new_lincomb_functions, new_lincomb_coefficients) else: diffusion_functions = [ background, w1, w2, w3, w4, w5, w6, w7, w8, sw, aw, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, t1, t2, t3, t4, t5, t6, t7, at1, at2, it ] for key in summed_quantities.keys(): if len(summed_quantities[key]) > 0: for li in summed_quantities[key]: idx = 0 if isinstance(li, str): if li == 'a': start_idx = 0 idx = 1 if key == 'walls': li_iterate = list(np.arange(2, 11)) if key == 'windows': li_iterate = list(np.arange(2, 13)) if key == 'doors': li_iterate = list(np.arange(2, 11)) else: if key == 'walls': start_idx = 0 idx = li[0] + start_idx if key == 'windows': start_idx = 10 idx = li[0] + start_idx if key == 'doors': start_idx = 22 idx = li[0] + start_idx li_iterate = li[1:] if idx != 0: new_lincomb_functions = [diffusion_functions[idx]] new_lincomb_coefficients = [1.] for l in li_iterate: new_lincomb_functions.append( diffusion_functions[l + start_idx]) new_lincomb_coefficients.append(1.) diffusion_functions[l + start_idx] = ConstantFunction( 0, 2) diffusion_functions[idx] = LincombFunction( new_lincomb_functions, new_lincomb_coefficients) heat_functions = [h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11, h12] if len(summed_quantities['heaters']) > 0: for li in summed_quantities['heaters']: if isinstance(li, str): if li == 'a': start_idx = -1 idx = 1 li_iterate = list(np.arange(2, 13)) else: start_idx = -1 idx = li[0] + start_idx li_iterate = li[1:] new_lincomb_functions = [heat_functions[idx]] new_lincomb_coefficients = [1.] for l in li_iterate: new_lincomb_functions.append(heat_functions[l + start_idx]) new_lincomb_coefficients.append(1.) heat_functions[l + start_idx] = ConstantFunction(0, 2) heat_functions[idx] = LincombFunction(new_lincomb_functions, new_lincomb_coefficients) scale_quotient = {} coefficients = {} parameter_type = {} parameter_ranges = {} parametric_quantities = {} for (key, tu) in input_dict.items(): key_ranges = [] key_coefficients = [] scale_quotients = [] parametric_quantities[key] = 0 for et in tu: if isinstance(et, list): # Then we have a parametrized value if parameter_scaling: scale_quotients.append(et[1]) key_ranges.append([et[0] / (et[1]), 1]) else: scale_quotients.append(1.) key_ranges.append([et[0], et[1]]) key_coefficients.append(None) parametric_quantities[key] += 1 elif isinstance(et, Number): # Then, we have a deterministic value key_coefficients.append(et) else: print( 'wrong input given for key {}... converting to 1.'.format( key)) key_coefficients.append(1.) coefficients[key] = key_coefficients if len(scale_quotients) > 0: scale_quotient[key] = scale_quotients[ 0] #ranges are the same for the same key if key_ranges != []: parameter_type[key] = (len(key_ranges), ) parameter_ranges[key] = tuple(key_ranges[0]) for (key, list_) in coefficients.items(): it = 0 for (i, l) in enumerate(list_): if l is None: if coefficient_expressions is not None: if key == 'heaters': add_exp = '{}[{}]' add_exp_derivative = '1*' add_exp_second_derivative = '0*' else: add_exp = coefficient_expressions['function'] add_exp_derivative = coefficient_expressions[ 'derivative'] add_exp_second_derivative = coefficient_expressions[ 'second_derivative'] else: add_exp = '{}[{}]' add_exp_derivative = '1*' if parametric_quantities[key] == 1: if coefficient_expressions is None: derivative_expressions = { key: '1*{}'.format(scale_quotient[key]) } second_derivative_expressions = {key: {key: '0'}} else: derivative_expressions = { key: add_exp_derivative.format(key, it) + '1*{}'.format(scale_quotient[key]) } second_derivative_expressions = { key: { key: add_exp_second_derivative.format( key, it, key, it) + '1*{}'.format(scale_quotient[key]) } } else: expressions = np.empty((parametric_quantities[key], ), dtype='<U60') second_expressions = np.empty( (parametric_quantities[key], ), dtype=dict) second_expression = np.empty( (parametric_quantities[key], ), dtype='<U60') for k in range(parametric_quantities[key]): expressions[k] = '0' second_expression[k] = '0' for k in range(parametric_quantities[key]): second_expressions[k] = {key: second_expression.copy()} second_derivative_expressions = {key: second_expressions} if coefficient_expressions is None: expressions[it] = '1*{}'.format(scale_quotient[key]) else: expressions[it] = add_exp_derivative.format( key, it) + '1*{}'.format(scale_quotient[key]) second_derivative_expressions[key][it][key][ it] = add_exp_second_derivative.format( key, it, key, it) + '1*{}'.format( scale_quotient[key]) derivative_expressions = {key: expressions} coefficients[key][i] = ExpressionParameterFunctional( add_exp.format(key, it, key, it) + '*{}'.format(scale_quotient[key]), {key: parameter_type[key]}, derivative_expressions=derivative_expressions, second_derivative_expressions=second_derivative_expressions ) it += 1 if parameters_in_q: q_inverse_coefficients = [ coefficients['walls'].pop(-1), coefficients['doors'].pop(7), coefficients['doors'].pop(7) ] diffusion_coefficients = [] heat_coefficients = [] for (key, val) in coefficients.items(): if (key == 'heaters'): heat_coefficients.extend(val) elif (key == 'windows'): if parameters_in_q: q_inverse_coefficients.extend(val) else: diffusion_coefficients.extend(val) else: diffusion_coefficients.extend(val) lincomb_diffusion = LincombFunction(diffusion_functions, diffusion_coefficients) lincomb_heat = LincombFunction(heat_functions, heat_coefficients) # parameter space parameter_space = CubicParameterSpace(parameter_type, ranges=parameter_ranges) #Define problem domain = RectDomain(bounding_box, left='robin', right='robin', top='robin', bottom='robin') u_out = ConstantFunction(outside_temperature, 2) if parameters_in_q: # extracting parameters for boundary q_inverse_functions = [ aw, at1, at2, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12 ] if len(summed_quantities['windows']) > 0: for li in summed_quantities['heaters']: if isinstance(li, str): if li == 'a': print( 'warning: I have summed all outside quantities together' ) idx = 0 li_iterate = list(np.arange(2, 16)) else: start_idx = 2 idx = li[0] + start_idx li_iterate = li[1:] new_lincomb_functions = [q_inverse_functions[idx]] new_lincomb_coefficients = [1.] for l in li_iterate: new_lincomb_functions += [ q_inverse_functions[l + start_idx] ] new_lincomb_coefficients += [1.] q_inverse_functions[l + start_idx] = ConstantFunction(0, 2) q_inverse_functions[idx] = LincombFunction( new_lincomb_functions, new_lincomb_coefficients) q_inverse_function = LincombFunction(q_inverse_functions, q_inverse_coefficients) robin_data = (q_inverse_function, u_out) # ( 1/q, u_out ) else: robin_data = (ConstantFunction(q_inverse, 2), u_out) # ( 1/q, u_out) problem = StationaryProblem(domain=domain, diffusion=lincomb_diffusion, rhs=lincomb_heat, robin_data=robin_data, parameter_space=parameter_space) return problem, scale_quotient
def thermalblock_demo(args): args['--grid'] = int(args['--grid']) args['RBSIZE'] = int(args['RBSIZE']) args['--test'] = int(args['--test']) args['--ipython-engines'] = int(args['--ipython-engines']) args['--extension-alg'] = args['--extension-alg'].lower() assert args['--extension-alg'] in {'trivial', 'gram_schmidt'} args['--product'] = args['--product'].lower() assert args['--product'] in {'trivial', 'h1'} args['--reductor'] = args['--reductor'].lower() assert args['--reductor'] in {'traditional', 'residual_basis'} args['--cache-region'] = args['--cache-region'].lower() args['--validation-mus'] = int(args['--validation-mus']) args['--rho'] = float(args['--rho']) args['--gamma'] = float(args['--gamma']) args['--theta'] = float(args['--theta']) problem = thermal_block_problem(num_blocks=(2, 2)) functionals = [ ExpressionParameterFunctional('diffusion[0]', {'diffusion': 2}), ExpressionParameterFunctional('diffusion[1]**2', {'diffusion': 2}), ExpressionParameterFunctional('diffusion[0]', {'diffusion': 2}), ExpressionParameterFunctional('diffusion[1]', {'diffusion': 2}) ] problem = problem.with_( diffusion=problem.diffusion.with_(coefficients=functionals), ) print('Discretize ...') fom, _ = discretize_stationary_cg(problem, diameter=1. / args['--grid']) if args['--list-vector-array']: from pymor.discretizers.builtin.list import convert_to_numpy_list_vector_array fom = convert_to_numpy_list_vector_array(fom) if args['--cache-region'] != 'none': # building a cache_id is only needed for persistent CacheRegions cache_id = f"pymordemos.thermalblock_adaptive {args['--grid']}" fom.enable_caching(args['--cache-region'], cache_id) if args['--plot-solutions']: print('Showing some solutions') Us = () legend = () for mu in problem.parameter_space.sample_randomly(2): print(f"Solving for diffusion = \n{mu['diffusion']} ... ") sys.stdout.flush() Us = Us + (fom.solve(mu), ) legend = legend + (str(mu['diffusion']), ) fom.visualize(Us, legend=legend, title='Detailed Solutions for different parameters', block=True) print('RB generation ...') product = fom.h1_0_semi_product if args['--product'] == 'h1' else None coercivity_estimator = ExpressionParameterFunctional( 'min([diffusion[0], diffusion[1]**2])', fom.parameters) reductors = { 'residual_basis': CoerciveRBReductor(fom, product=product, coercivity_estimator=coercivity_estimator), 'traditional': SimpleCoerciveRBReductor(fom, product=product, coercivity_estimator=coercivity_estimator) } reductor = reductors[args['--reductor']] pool = new_parallel_pool(ipython_num_engines=args['--ipython-engines'], ipython_profile=args['--ipython-profile']) greedy_data = rb_adaptive_greedy( fom, reductor, problem.parameter_space, validation_mus=args['--validation-mus'], rho=args['--rho'], gamma=args['--gamma'], theta=args['--theta'], use_estimator=not args['--without-estimator'], error_norm=fom.h1_0_semi_norm, max_extensions=args['RBSIZE'], visualize=not args['--no-visualize-refinement']) rom = greedy_data['rom'] if args['--pickle']: print( f"\nWriting reduced model to file {args['--pickle']}_reduced ...") with open(args['--pickle'] + '_reduced', 'wb') as f: dump(rom, f) print( f"Writing detailed model and reductor to file {args['--pickle']}_detailed ..." ) with open(args['--pickle'] + '_detailed', 'wb') as f: dump((fom, reductor), f) print('\nSearching for maximum error on random snapshots ...') results = reduction_error_analysis( rom, fom=fom, reductor=reductor, estimator=True, error_norms=(fom.h1_0_semi_norm, ), condition=True, test_mus=problem.parameter_space.sample_randomly(args['--test']), basis_sizes=25 if args['--plot-error-sequence'] else 1, plot=True, pool=pool) real_rb_size = rom.solution_space.dim print(''' *** RESULTS *** Problem: number of blocks: 2x2 h: sqrt(2)/{args[--grid]} Greedy basis generation: estimator disabled: {args[--without-estimator]} extension method: {args[--extension-alg]} product: {args[--product]} prescribed basis size: {args[RBSIZE]} actual basis size: {real_rb_size} elapsed time: {greedy_data[time]} '''.format(**locals())) print(results['summary']) sys.stdout.flush() if args['--plot-error-sequence']: from matplotlib import pyplot as plt plt.show(results['figure']) if args['--plot-err']: mumax = results['max_error_mus'][0, -1] U = fom.solve(mumax) URB = reductor.reconstruct(rom.solve(mumax)) fom.visualize( (U, URB, U - URB), legend=('Detailed Solution', 'Reduced Solution', 'Error'), title='Maximum Error Solution', separate_colorbars=True, block=True)
def main(args): args = parse_arguments(args) pool = new_parallel_pool(ipython_num_engines=args['--ipython-engines'], ipython_profile=args['--ipython-profile']) if args['--fenics']: fom, fom_summary = discretize_fenics(args['XBLOCKS'], args['YBLOCKS'], args['--grid'], args['--order']) else: fom, fom_summary = discretize_pymor(args['XBLOCKS'], args['YBLOCKS'], args['--grid'], args['--list-vector-array']) if args['--cache-region'] != 'none': # building a cache_id is only needed for persistent CacheRegions cache_id = (f"pymordemos.thermalblock {args['--fenics']} {args['XBLOCKS']} {args['YBLOCKS']}" f"{args['--grid']} {args['--order']}") fom.enable_caching(args['--cache-region'], cache_id) if args['--plot-solutions']: print('Showing some solutions') Us = () legend = () for mu in fom.parameter_space.sample_randomly(2): print(f"Solving for diffusion = \n{mu['diffusion']} ... ") sys.stdout.flush() Us = Us + (fom.solve(mu),) legend = legend + (str(mu['diffusion']),) fom.visualize(Us, legend=legend, title='Detailed Solutions for different parameters', separate_colorbars=False, block=True) print('RB generation ...') # define estimator for coercivity constant from pymor.parameters.functionals import ExpressionParameterFunctional coercivity_estimator = ExpressionParameterFunctional('min(diffusion)', fom.parameter_type) # inner product for computation of Riesz representatives product = fom.h1_0_semi_product if args['--product'] == 'h1' else None if args['--reductor'] == 'residual_basis': from pymor.reductors.coercive import CoerciveRBReductor reductor = CoerciveRBReductor(fom, product=product, coercivity_estimator=coercivity_estimator, check_orthonormality=False) elif args['--reductor'] == 'traditional': from pymor.reductors.coercive import SimpleCoerciveRBReductor reductor = SimpleCoerciveRBReductor(fom, product=product, coercivity_estimator=coercivity_estimator, check_orthonormality=False) else: assert False # this should never happen if args['--alg'] == 'naive': rom, red_summary = reduce_naive(fom=fom, reductor=reductor, basis_size=args['RBSIZE']) elif args['--alg'] == 'greedy': parallel = not (args['--fenics'] and args['--greedy-without-estimator']) # cannot pickle FEniCS model rom, red_summary = reduce_greedy(fom=fom, reductor=reductor, snapshots_per_block=args['SNAPSHOTS'], extension_alg_name=args['--extension-alg'], max_extensions=args['RBSIZE'], use_estimator=not args['--greedy-without-estimator'], pool=pool if parallel else None) elif args['--alg'] == 'adaptive_greedy': parallel = not (args['--fenics'] and args['--greedy-without-estimator']) # cannot pickle FEniCS model rom, red_summary = reduce_adaptive_greedy(fom=fom, reductor=reductor, validation_mus=args['SNAPSHOTS'], extension_alg_name=args['--extension-alg'], max_extensions=args['RBSIZE'], use_estimator=not args['--greedy-without-estimator'], rho=args['--adaptive-greedy-rho'], gamma=args['--adaptive-greedy-gamma'], theta=args['--adaptive-greedy-theta'], pool=pool if parallel else None) elif args['--alg'] == 'pod': rom, red_summary = reduce_pod(fom=fom, reductor=reductor, snapshots_per_block=args['SNAPSHOTS'], basis_size=args['RBSIZE']) else: assert False # this should never happen if args['--pickle']: print(f"\nWriting reduced model to file {args['--pickle']}_reduced ...") with open(args['--pickle'] + '_reduced', 'wb') as f: dump(rom, f) if not args['--fenics']: # FEniCS data structures do not support serialization print(f"Writing detailed model and reductor to file {args['--pickle']}_detailed ...") with open(args['--pickle'] + '_detailed', 'wb') as f: dump((fom, reductor), f) print('\nSearching for maximum error on random snapshots ...') results = reduction_error_analysis(rom, fom=fom, reductor=reductor, estimator=True, error_norms=(fom.h1_0_semi_norm, fom.l2_norm), condition=True, test_mus=args['--test'], basis_sizes=0 if args['--plot-error-sequence'] else 1, plot=args['--plot-error-sequence'], pool=None if args['--fenics'] else pool, # cannot pickle FEniCS model random_seed=999) print('\n*** RESULTS ***\n') print(fom_summary) print(red_summary) print(results['summary']) sys.stdout.flush() if args['--plot-error-sequence']: import matplotlib.pyplot matplotlib.pyplot.show(results['figure']) if args['--plot-err']: mumax = results['max_error_mus'][0, -1] U = fom.solve(mumax) URB = reductor.reconstruct(rom.solve(mumax)) fom.visualize((U, URB, U - URB), legend=('Detailed Solution', 'Reduced Solution', 'Error'), title='Maximum Error Solution', separate_colorbars=True, block=True) return results
def set_input_dict(parametric_quantities, active_quantities, coefficient_expressions=None, summed_quantities=None, parameters_in_q=False, ac=None, owc=None, iwc=None, idc=None, wc=None, ht=None, owc_c=None, iwc_c=None, idc_c=None, wc_c=None, ht_c=None): # ac means air conductivity # owc means outside wall and outside door conductivity # iwc means inside wall conductivity # idc means inside door conductivity # wc means window conductivity # ht means heat temperature # *_c stands for the constant value for the non parameterized case ! # the need to be evaluated by the coefficient_expressions as well if coefficient_expressions is not None: assert 'function' in coefficient_expressions, 'You might have assigned summed_quantities to coefficient_expressions. Check the input arguments of this function!!!' add_exp = coefficient_expressions['function'] else: print( 'Warning: Check whether you have not used coefficient_expressions for the later experiment' ) add_exp = '{}[{}]' epf = ExpressionParameterFunctional(add_exp.format('anything', ()), {'anything': ()}) # Attention ! Parametric case has priority over active case ! # please provide the owc,iwc,idc,wc and ht in a list or use default def_ac, def_owc, def_iwc, def_idc, def_wc, def_ht = set_default_conductivities( parameters_in_q) if ac is None: ac = def_ac if owc is None: owc = def_owc if iwc is None: iwc = def_iwc if idc is None: idc = def_idc if wc is None: wc = def_wc if ht is None: ht = def_ht if owc_c is None: owc_c = owc[0] if iwc_c is None: iwc_c = iwc[0] if idc_c is None: idc_c = idc[0] if wc_c is None: wc_c = wc[0] if ht_c is None: ht_c = ht[1] # apply epf to _c owc_c = epf(owc_c) iwc_c = epf(iwc_c) idc_c = epf(idc_c) wc_c = epf(wc_c) assert (isinstance(owc, list)) assert (isinstance(iwc, list)) assert (isinstance(idc, list)) assert (isinstance(wc, list)) assert (isinstance(ht, list)) walls_tuple = () windows_tuple = () doors_tuple = () heaters_tuple = () walls_params = parametric_quantities['walls'] windows_params = parametric_quantities['windows'] doors_params = parametric_quantities['doors'] heaters_params = parametric_quantities['heaters'] active_quantities['walls'] = active_quantities['removed_walls'] active_quantities['windows'] = active_quantities['open_windows'] active_quantities['doors'] = active_quantities['open_doors'] active_quantities['heaters'] = active_quantities['active_heaters'] removed_walls = active_quantities['walls'] # removed walls open_windows = active_quantities['windows'] # open windows open_doors = active_quantities['doors'] # open_doors active_heaters = active_quantities['heaters'] # active heater if summed_quantities is not None: for key in ['walls', 'windows', 'doors', 'heaters']: if summed_quantities[key] == 'all': assert len(parametric_quantities[key] ) == 1, 'only parameterize one quantity' assert len(active_quantities[key] ) == 0, 'do not sum active quantities' continue for summand in summed_quantities[key]: assert isinstance(summand, list) assert len(summand) > 1, 'you must at least sum two quantities' for i in range(1, len(summand)): assert summand[i] not in parametric_quantities[ key], 'do not sum parametric quantities' assert summand[i] not in active_quantities[ key], 'do not sum active quantities' for i in range(1, 11): if i in walls_params: if i == 10: # outside wall assert isinstance(owc, list) and len( owc ) == 2, 'WRONG INPUT: owc has to be a list of the parametric range' walls_tuple += (owc, ) else: assert isinstance(iwc, list) and len( iwc ) == 2, 'WRONG INPUT: iwc has to be a list of the parametric range' walls_tuple += (iwc, ) elif i in removed_walls: walls_tuple += (ac, ) else: if i == 10: walls_tuple += (owc_c, ) else: walls_tuple += (iwc_c, ) if i in doors_params: assert isinstance(idc, list) and len( idc ) == 2, 'WRONG INPUT: idc has to be a list of the parametric range' doors_tuple += (idc, ) elif i in open_doors: doors_tuple += (ac, ) else: if i in [8, 9]: doors_tuple += (owc_c, ) else: doors_tuple += (idc_c, ) for i in range(1, 13): if i in windows_params: assert isinstance(wc, list) and len( wc ) == 2, 'WRONG INPUT: wc has to be a list of the parametric range' windows_tuple += (wc, ) elif i in open_windows: assert isinstance(wc, list) and len( wc ) == 2, 'WRONG INPUT: wc has to be a list where the first entry corresponds to open window' windows_tuple += (ac, ) else: windows_tuple += (wc_c, ) if i in heaters_params: assert isinstance(ht, list) and len( ht ) == 2, 'WRONG INPUT: ht has to be a list of the parametric range' heaters_tuple += (ht, ) elif i in active_heaters: heaters_tuple += (ht_c, ) else: heaters_tuple += (0, ) assert (len(walls_tuple) == 10) assert (len(windows_tuple) == 12) assert (len(doors_tuple) == 10) assert (len(heaters_tuple) == 12) input_dict = { 'air': (ac, ), 'walls': walls_tuple, # must be 10 'windows': windows_tuple, # must be 12 'doors': doors_tuple, # must be 10 'heaters': heaters_tuple } # must be 12 return input_dict
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 @pytest.fixture(params=elliptic_problems + thermalblock_problems + burgers_problems) def analytical_problem(request): return request.param @pytest.fixture(params=picklable_elliptic_problems + picklable_thermalblock_problems + burgers_problems) def picklable_analytical_problem(request): return request.param
def discretize_instationary_from_disk(parameter_file, T=None, steps=None, u0=None, time_stepper=None): """Load a linear affinely decomposed |InstationaryModel| from file. Similarly to :func:`discretize_stationary_from_disk`, the model is specified via an `ini.`-file of the following form :: [system-matrices] L_1.mat: l_1(μ_1,...,μ_n) L_2.mat: l_2(μ_1,...,μ_n) ... [rhs-vectors] F_1.mat: f_1(μ_1,...,μ_n) F_2.mat: f_2(μ_1,...,μ_n) ... [mass-matrix] D.mat [initial-solution] u0: u0.mat [parameter] μ_1: a_1,b_1 ... μ_n: a_n,b_n [products] Prod1: P_1.mat Prod2: P_2.mat ... [time] T: final time steps: number of time steps Parameters ---------- parameter_file Path to the '.ini' parameter file. T End-time of desired solution. If `None`, the value specified in the parameter file is used. steps Number of time steps to. If `None`, the value specified in the parameter file is used. u0 Initial solution. If `None` the initial solution is obtained from parameter file. time_stepper The desired :class:`time stepper <pymor.algorithms.timestepping.TimeStepper>` to use. If `None`, implicit Euler time stepping is used. Returns ------- m The |InstationaryModel| that has been generated. """ assert ".ini" == parameter_file[-4:], "Given file is not an .ini file" assert os.path.isfile(parameter_file) base_path = os.path.dirname(parameter_file) # Get input from parameter file config = configparser.ConfigParser() config.optionxform = str config.read(parameter_file) # Assert that all needed entries given assert 'system-matrices' in config.sections() assert 'mass-matrix' in config.sections() assert 'rhs-vectors' in config.sections() assert 'parameter' in config.sections() system_mat = config.items('system-matrices') mass_mat = config.items('mass-matrix') rhs_vec = config.items('rhs-vectors') parameter = config.items('parameter') # Dict of parameters types and ranges parameter_type = {} parameter_range = {} # get parameters for i in range(len(parameter)): parameter_name = parameter[i][0] parameter_list = tuple( float(j) for j in parameter[i][1].replace(" ", "").split(',')) parameter_range[parameter_name] = parameter_list # Assume scalar parameter dependence parameter_type[parameter_name] = 0 # Create parameter space parameter_space = CubicParameterSpace(parameter_type=parameter_type, ranges=parameter_range) # Assemble operators system_operators, system_functionals = [], [] # get parameter functionals and system matrices for i in range(len(system_mat)): path = os.path.join(base_path, system_mat[i][0]) expr = system_mat[i][1] parameter_functional = ExpressionParameterFunctional( expr, parameter_type=parameter_type) system_operators.append( NumpyMatrixOperator.from_file(path, source_id='STATE', range_id='STATE')) system_functionals.append(parameter_functional) system_lincombOperator = LincombOperator(system_operators, coefficients=system_functionals) # get rhs vectors rhs_operators, rhs_functionals = [], [] for i in range(len(rhs_vec)): path = os.path.join(base_path, rhs_vec[i][0]) expr = rhs_vec[i][1] parameter_functional = ExpressionParameterFunctional( expr, parameter_type=parameter_type) op = NumpyMatrixOperator.from_file(path, range_id='STATE') assert isinstance(op.matrix, np.ndarray) op = op.with_(matrix=op.matrix.reshape((-1, 1))) rhs_operators.append(op) rhs_functionals.append(parameter_functional) rhs_lincombOperator = LincombOperator(rhs_operators, coefficients=rhs_functionals) # get mass matrix path = os.path.join(base_path, mass_mat[0][1]) mass_operator = NumpyMatrixOperator.from_file(path, source_id='STATE', range_id='STATE') # Obtain initial solution if not given if u0 is None: u_0 = config.items('initial-solution') path = os.path.join(base_path, u_0[0][1]) op = NumpyMatrixOperator.from_file(path, range_id='STATE') assert isinstance(op.matrix, np.ndarray) u0 = op.with_(matrix=op.matrix.reshape((-1, 1))) # get products if given if 'products' in config.sections(): product = config.items('products') products = {} for i in range(len(product)): product_name = product[i][0] product_path = os.path.join(base_path, product[i][1]) products[product_name] = NumpyMatrixOperator.from_file( product_path, source_id='STATE', range_id='STATE') else: products = None # Further specifications if 'time' in config.sections(): if T is None: assert 'T' in config.options('time') T = float(config.get('time', 'T')) if steps is None: assert 'steps' in config.options('time') steps = int(config.get('time', 'steps')) # Use implicit euler time stepper if no time-stepper given if time_stepper is None: time_stepper = ImplicitEulerTimeStepper(steps) else: time_stepper = time_stepper(steps) # Create and return instationary model return InstationaryModel(operator=system_lincombOperator, rhs=rhs_lincombOperator, parameter_space=parameter_space, initial_data=u0, T=T, time_stepper=time_stepper, mass=mass_operator, products=products)
def discretize_stationary_from_disk(parameter_file): """Load a linear affinely decomposed |StationaryModel| from file. The model is defined via an `.ini`-style file as follows :: [system-matrices] L_1.mat: l_1(μ_1,...,μ_n) L_2.mat: l_2(μ_1,...,μ_n) ... [rhs-vectors] F_1.mat: f_1(μ_1,...,μ_n) F_2.mat: f_2(μ_1,...,μ_n) ... [parameter] μ_1: a_1,b_1 ... μ_n: a_n,b_n [products] Prod1: P_1.mat Prod2: P_2.mat ... Here, `L_1.mat`, `L_2.mat`, ..., `F_1.mat`, `F_2.mat`, ... are files containing matrices `L_1`, `L_2`, ... and vectors `F_1.mat`, `F_2.mat`, ... which correspond to the affine components of the operator and right-hand side. The respective coefficient functionals, are given via the string expressions `l_1(...)`, `l_2(...)`, ..., `f_1(...)` in the (scalar-valued) |Parameter| components `w_1`, ..., `w_n`. The allowed lower and upper bounds `a_i, b_i` for the component `μ_i` are specified in the `[parameters]` section. The resulting operator and right-hand side are then of the form :: L(μ) = l_1(μ)*L_1 + l_2(μ)*L_2+ ... F(μ) = f_1(μ)*F_1 + f_2(μ)*L_2+ ... In the `[products]` section, an optional list of inner products `Prod1`, `Prod2`, .. with corresponding matrices `P_1.mat`, `P_2.mat` can be specified. Example:: [system-matrices] matrix1.mat: 1. matrix2.mat: 1. - theta**2 [rhs-vectors] rhs.mat: 1. [parameter] theta: 0, 0.5 [products] h1: h1.mat l2: mass.mat Parameters ---------- parameter_file Path to the parameter file. Returns ------- m The |StationaryModel| that has been generated. """ assert ".ini" == parameter_file[ -4:], f'Given file is not an .ini file: {parameter_file}' assert os.path.isfile(parameter_file) base_path = os.path.dirname(parameter_file) # Get input from parameter file config = configparser.ConfigParser() config.optionxform = str config.read(parameter_file) # Assert that all needed entries given assert 'system-matrices' in config.sections() assert 'rhs-vectors' in config.sections() assert 'parameter' in config.sections() system_mat = config.items('system-matrices') rhs_vec = config.items('rhs-vectors') parameter = config.items('parameter') # Dict of parameters types and ranges parameter_type = {} parameter_range = {} # get parameters for i in range(len(parameter)): parameter_name = parameter[i][0] parameter_list = tuple( float(j) for j in parameter[i][1].replace(" ", "").split(',')) parameter_range[parameter_name] = parameter_list # Assume scalar parameter dependence parameter_type[parameter_name] = 0 # Create parameter space parameter_space = CubicParameterSpace(parameter_type=parameter_type, ranges=parameter_range) # Assemble operators system_operators, system_functionals = [], [] # get parameter functionals and system matrices for i in range(len(system_mat)): path = os.path.join(base_path, system_mat[i][0]) expr = system_mat[i][1] parameter_functional = ExpressionParameterFunctional( expr, parameter_type=parameter_type) system_operators.append( NumpyMatrixOperator.from_file(path, source_id='STATE', range_id='STATE')) system_functionals.append(parameter_functional) system_lincombOperator = LincombOperator(system_operators, coefficients=system_functionals) # get rhs vectors rhs_operators, rhs_functionals = [], [] for i in range(len(rhs_vec)): path = os.path.join(base_path, rhs_vec[i][0]) expr = rhs_vec[i][1] parameter_functional = ExpressionParameterFunctional( expr, parameter_type=parameter_type) op = NumpyMatrixOperator.from_file(path, range_id='STATE') assert isinstance(op.matrix, np.ndarray) op = op.with_(matrix=op.matrix.reshape((-1, 1))) rhs_operators.append(op) rhs_functionals.append(parameter_functional) rhs_lincombOperator = LincombOperator(rhs_operators, coefficients=rhs_functionals) # get products if given if 'products' in config.sections(): product = config.items('products') products = {} for i in range(len(product)): product_name = product[i][0] product_path = os.path.join(base_path, product[i][1]) products[product_name] = NumpyMatrixOperator.from_file( product_path, source_id='STATE', range_id='STATE') else: products = None # Create and return stationary model return StationaryModel(operator=system_lincombOperator, rhs=rhs_lincombOperator, parameter_space=parameter_space, products=products)