Example #1
0
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
Example #2
0
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_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
Example #4
0
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 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 build_output_coefficient(parameter_type,
                             parameter_weights=None,
                             mu_d_=None,
                             parameter_scales=None,
                             state_functional=None,
                             constant_part=None):
    def _collect_indices(item):
        item_dict = {}
        if sum(item) < 2:  # case () and (1,)
            item_dict[1] = ()
            new_item = ()
        else:
            assert len(item) == 1  # case (l,) with l > 1
            for l in range(item[0]):
                item_dict[l] = (l, )
            new_item = item
        return item_dict, new_item

    if parameter_weights is None:
        parameter_weights = {
            'walls': 1,
            'heaters': 1,
            'doors': 1,
            'windows': 1
        }
    if parameter_scales is None:
        parameter_scales = {'walls': 1, 'heaters': 1, 'doors': 1, 'windows': 1}
    mu_d = {}
    if mu_d_ is None:
        mu_d_ = {}
    for key, item in parameter_type.items():
        if not isinstance(parameter_weights[key], list):
            if len(item) == 0:  # for the case when item = ()
                parameter_weights[key] = [parameter_weights[key]]
            else:
                parameter_weights[key] = [
                    parameter_weights[key] for i in range(item[0])
                ]
        if key not in mu_d_:
            mu_d_[key] = 0
        if not isinstance(mu_d_[key], list):
            if len(item) == 0:  # for the case when item = ()
                mu_d[key] = [mu_d_[key]]
            else:
                if isinstance(mu_d_[key], type(np.array([]))):
                    mu_d[key] = [mu_d_[key][i] for i in range(item[0])]
                else:
                    mu_d[key] = [mu_d_[key] for i in range(item[0])]
        else:
            mu_d[key] = mu_d_[key]

    parameter_functionals = []

    if constant_part is not None:
        # sigma_d * constant_part
        parameter_functionals.append(state_functional * constant_part)
        # + 1
        parameter_functionals.append(ConstantParameterFunctional(1))

    def make_zero_expressions(parameter_type):
        zero_derivative_expression = {}
        for key, item in parameter_type.items():
            zero_expressions = np.array([], dtype='<U60')
            item_dict, new_item = _collect_indices(item)
            for (l, index) in item_dict.items():
                zero_expressions = np.append(zero_expressions, ['0'])
            if len(zero_expressions) == 1:
                zero_expressions = np.array(zero_expressions[0], dtype='<U60')
            else:
                zero_expressions = np.array(zero_expressions, dtype='<U60')
            zero_derivative_expression[key] = zero_expressions
        return zero_derivative_expression

    #prepare dict
    def make_dict_zero_expressions(parameter_type):
        zero_dict = {}
        for key, item in parameter_type.items():
            index_dict, new_item = _collect_indices(item)
            zero_ = np.empty(new_item, dtype=dict)
            zero_dict[key] = zero_
            for (l, index) in index_dict.items():
                zero_dict[key][index] = make_zero_expressions(parameter_type)
        return zero_dict

    for key, item in parameter_type.items():
        if len(item) == 0:  # for the case when item = ()
            weight = parameter_weights[key][0]
            derivative_expression = make_zero_expressions(parameter_type)
            derivative_expression[key] = '{}*{}**2*'.format(weight,parameter_scales[key]) \
                                          +'({}[{}]'.format(key,()) \
                                          +'-{}'.format(mu_d[key][0]) +')'
            second_derivative_expressions = make_dict_zero_expressions(
                parameter_type)
            second_derivative_expressions[key][()][key] = '{}*{}**2'.format(
                weight, parameter_scales[key])
            parameter_functionals.append(ExpressionParameterFunctional('{}*{}**2*0.5*({}[{}]'.format(
                                                                        weight,parameter_scales[key],key,()) \
                                                                        +'-{}'.format(mu_d[key][0])+')**2',
                                                                        parameter_type,
                                                                        derivative_expressions=derivative_expression,
                                                                        second_derivative_expressions=second_derivative_expressions))
        else:
            for i in range(item[0]):
                weight = parameter_weights[key][i]
                derivative_expression = make_zero_expressions(parameter_type)
                second_derivative_expressions = make_dict_zero_expressions(
                    parameter_type)
                if item[0] == 1:
                    derivative_expression[key] = \
                        '{}*{}**2*({}[{}]-'.format(weight,parameter_scales[key],key,i) + '{}'.format(mu_d[key][i])+')'
                    second_derivative_expressions[key][(
                    )][key] = '{}*{}**2'.format(weight, parameter_scales[key])
                else:
                    derivative_expression[key][i] = \
                            '{}*{}**2*({}[{}]-'.format(weight,parameter_scales[key],key,i) + '{}'.format(mu_d[key][i])+')'
                    second_derivative_expressions[key][i][key][
                        i] = '{}*{}**2'.format(weight, parameter_scales[key])
                parameter_functionals.append(ExpressionParameterFunctional('{}*{}**2*0.5*({}[{}]'.format( \
                                                                            weight,parameter_scales[key],key,i) \
                                                                            +'-{}'.format(mu_d[key][i])+')**2',
                                                                            parameter_type,
                                                                            derivative_expressions=derivative_expression,
                                                                            second_derivative_expressions=second_derivative_expressions))

    def mapping(mu):
        ret = 0
        for f in parameter_functionals:
            ret += f.evaluate(mu)
        return ret

    def make_mapping(key, i):
        def sum_derivatives(mu):
            ret = 0
            if i == -1:
                index = ()
            else:
                index = (i, )
            for f in parameter_functionals:
                ret += f.d_mu(key, index).evaluate(mu)
            return ret

        return sum_derivatives

    def make_second_mapping(key, i):
        def sum_second_derivatives(mu):
            ret = 0
            if i == -1:
                index = ()
            else:
                index = (i, )
            for f in parameter_functionals:
                ret += f.d_mu(key, index).d_mu(key, index).evaluate(mu)
            return ret

        return sum_second_derivatives

    def make_zero_mappings(parameter_type):
        zero_derivative_mappings = {}
        for key, item in parameter_type.items():
            zero_mappings = np.array([], dtype=object)
            zero_mapping = lambda mu: 0.
            if len(item) == 0:  # for the case when item = ()
                zero_mappings = np.append(zero_mappings, [zero_mapping])
                zero_mappings = np.array(zero_mappings[0])
            else:
                for i in range(item[0]):
                    zero_mappings = np.append(zero_mappings, [zero_mapping])
                if item[0] == 1:
                    zero_mappings = np.array(zero_mappings[0])
            zero_derivative_mappings[key] = zero_mappings
        return zero_derivative_mappings

    #prepare dict
    def make_dict_zero_mapping(parameter_type):
        zero_dict = {}
        for key, item in parameter_type.items():
            index_dict, new_item = _collect_indices(item)
            zero_ = np.empty(new_item, dtype=dict)
            zero_dict[key] = zero_
            for (l, index) in index_dict.items():
                zero_dict[key][index] = make_zero_mappings(parameter_type)
        return zero_dict

    derivative_mappings = make_zero_mappings(parameter_type)
    for key, item in parameter_type.items():
        if len(item) == 0:  # for the case when item = ()
            derivative_mappings[key] = np.array(make_mapping(key, -1))
        else:
            for i in range(item[0]):
                if item[0] == 1:
                    derivative_mappings[key] = np.array(make_mapping(key, -1))
                else:
                    derivative_mappings[key][i] = make_mapping(key, i)

    second_derivative_mappings = make_dict_zero_mapping(parameter_type)
    for key, item in parameter_type.items():
        if len(item) == 0:  # for the case when item = ()
            second_derivative_mappings[key][()][key] = np.array(
                make_second_mapping(key, -1))
        else:
            for i in range(item[0]):
                if item[0] == 1:
                    second_derivative_mappings[key][()][key] = np.array(
                        make_second_mapping(key, -1))
                else:
                    second_derivative_mappings[key][i][key][
                        i] = make_second_mapping(key, i)

    output_coefficient = GenericParameterFunctional(
        mapping,
        parameter_type,
        derivative_mappings=derivative_mappings,
        second_derivative_mappings=second_derivative_mappings)
    return output_coefficient
Example #8
0
def build_output_coefficient(parameters, parameter_weights=None, mu_d_=None, parameter_scales=None,
                             state_functional=None, constant_part=None):
    if parameter_weights is None:
        parameter_weights= {'walls': 1, 'heaters': 1, 'doors': 1, 'windows': 1}
    if parameter_scales is None:
        parameter_scales= {'walls': 1, 'heaters': 1, 'doors': 1, 'windows': 1}
    mu_d={}
    if mu_d_ is None:
        mu_d_ = {}
    for key, size in parameters.items():
        if not isinstance(parameter_weights[key], list):
            parameter_weights[key] = [parameter_weights[key] for i in range(size)]
        if key not in mu_d_:
            mu_d_[key] = [0 for i in range(size)]
        if not isinstance(mu_d_[key], list):
            mu_d[key] = [mu_d_[key][i] for i in range(size)]
        else:
            mu_d[key] = mu_d_[key]

    parameter_functionals = []

    if constant_part is not None:
        # sigma_d * constant_part
        parameter_functionals.append(state_functional * constant_part)
        # + 1
        parameter_functionals.append(ConstantParameterFunctional(1))

    def make_zero_expressions(parameters):
        zero_derivative_expression = {}
        for key, size in parameters.items():
            zero_expressions = np.array([], dtype='<U60')
            for l in range(size):
                zero_expressions = np.append(zero_expressions, ['0'])
            zero_expressions = np.array(zero_expressions, dtype='<U60')
            zero_derivative_expression[key] = zero_expressions
        return zero_derivative_expression

    #prepare dict
    def make_dict_zero_expressions(parameters):
        zero_dict = {}
        for key, size in parameters.items():
            zero_ = np.empty(size, dtype=dict)
            zero_dict[key] = zero_
            for l in range(size):
                zero_dict[key][l] = make_zero_expressions(parameters)
        return zero_dict

    for key, size in parameters.items():
        for i in range(size):
            weight = parameter_weights[key][i]
            derivative_expression = make_zero_expressions(parameters)
            second_derivative_expressions = make_dict_zero_expressions(parameters)
            derivative_expression[key][i] = \
                        '{}*{}**2*({}[{}]-'.format(weight,parameter_scales[key],key,i) + '{}'.format(mu_d[key][i])+')'
            second_derivative_expressions[key][i][key][i]= '{}*{}**2'.format(weight,parameter_scales[key])
            parameter_functionals.append(ExpressionParameterFunctional('{}*{}**2*0.5*({}[{}]'.format( \
                                                                        weight,parameter_scales[key],key,i) \
                                                                        +'-{}'.format(mu_d[key][i])+')**2',
                                                                        parameters,
                                                                        derivative_expressions=derivative_expression,
                                                                        second_derivative_expressions=second_derivative_expressions))
    def mapping(mu):
        ret = 0
        for f in parameter_functionals:
            ret += f.evaluate(mu)
        return ret

    def make_mapping(key, i):
        def sum_derivatives(mu):
            ret = 0
            for f in parameter_functionals:
                ret += f.d_mu(key, i).evaluate(mu)
            return ret
        return sum_derivatives

    def make_second_mapping(key, i):
        def sum_second_derivatives(mu):
            ret = 0
            for f in parameter_functionals:
                ret += f.d_mu(key, i).d_mu(key, i).evaluate(mu)
            return ret
        return sum_second_derivatives

    def make_zero_mappings(parameters):
        zero_derivative_mappings = {}
        for key, size in parameters.items():
            zero_mappings = np.array([], dtype=object)
            zero_mapping = lambda mu: 0.
            for i in range(size):
                zero_mappings = np.append(zero_mappings, [zero_mapping])
            zero_derivative_mappings[key] = zero_mappings
        return zero_derivative_mappings

    #prepare dict
    def make_dict_zero_mapping(parameters):
        zero_dict = {}
        for key, size in parameters.items():
            zero_ = np.empty(size, dtype=dict)
            zero_dict[key] = zero_
            for l in range(size):
                zero_dict[key][l] = make_zero_mappings(parameters)
        return zero_dict

    derivative_mappings = make_zero_mappings(parameters)
    for key, size in parameters.items():
        for i in range(size):
            derivative_mappings[key][i] = make_mapping(key,i)

    second_derivative_mappings = make_dict_zero_mapping(parameters)
    for key, size in parameters.items():
        for i in range(size):
            second_derivative_mappings[key][i][key][i] = make_second_mapping(key,i)

    output_coefficient = GenericParameterFunctional(mapping, parameters,
                                                    derivative_mappings=derivative_mappings,
                                                    second_derivative_mappings=second_derivative_mappings)
    return output_coefficient