Exemplo n.º 1
0
def compute_integrand_scaling_factor(integral):
    """Change integrand geometry to the right representations."""

    domain = integral.ufl_domain()
    integral_type = integral.integral_type()
    # co = CellOrientation(domain)
    weight = QuadratureWeight(domain)
    tdim = domain.topological_dimension()
    # gdim = domain.geometric_dimension()

    # Polynomial degree of integrand scaling
    degree = 0
    if integral_type == "cell":
        detJ = JacobianDeterminant(domain)
        degree = estimate_total_polynomial_degree(
            apply_geometry_lowering(detJ))
        # Despite the abs, |detJ| is polynomial except for
        # self-intersecting cells, where we have other problems.
        scale = abs(detJ) * weight

    elif integral_type.startswith("exterior_facet"):
        if tdim > 1:
            # Scaling integral by facet jacobian determinant and
            # quadrature weight
            detFJ = FacetJacobianDeterminant(domain)
            degree = estimate_total_polynomial_degree(
                apply_geometry_lowering(detFJ))
            scale = detFJ * weight
        else:
            # No need to scale 'integral' over a vertex
            scale = 1

    elif integral_type.startswith("interior_facet"):
        if tdim > 1:
            # Scaling integral by facet jacobian determinant from one
            # side and quadrature weight
            detFJ = FacetJacobianDeterminant(domain)
            degree = estimate_total_polynomial_degree(
                apply_geometry_lowering(detFJ))
            scale = detFJ('+') * weight
        else:
            # No need to scale 'integral' over a vertex
            scale = 1

    elif integral_type in custom_integral_types:
        # Scaling with custom weight, which includes eventual volume
        # scaling
        scale = weight

    elif integral_type in point_integral_types:
        # No need to scale 'integral' over a point
        scale = 1

    else:
        error("Unknown integral type {}, don't know how to scale.".format(
            integral_type))

    return scale, degree
def compute_integrand_scaling_factor(integral):
    """Change integrand geometry to the right representations."""

    domain = integral.ufl_domain()
    integral_type = integral.integral_type()
    # co = CellOrientation(domain)
    weight = QuadratureWeight(domain)
    tdim = domain.topological_dimension()
    # gdim = domain.geometric_dimension()

    # Polynomial degree of integrand scaling
    degree = 0
    if integral_type == "cell":
        detJ = JacobianDeterminant(domain)
        degree = estimate_total_polynomial_degree(apply_geometry_lowering(detJ))
        # Despite the abs, |detJ| is polynomial except for
        # self-intersecting cells, where we have other problems.
        scale = abs(detJ) * weight

    elif integral_type.startswith("exterior_facet"):
        if tdim > 1:
            # Scaling integral by facet jacobian determinant and
            # quadrature weight
            detFJ = FacetJacobianDeterminant(domain)
            degree = estimate_total_polynomial_degree(apply_geometry_lowering(detFJ))
            scale = detFJ * weight
        else:
            # No need to scale 'integral' over a vertex
            scale = 1

    elif integral_type.startswith("interior_facet"):
        if tdim > 1:
            # Scaling integral by facet jacobian determinant from one
            # side and quadrature weight
            detFJ = FacetJacobianDeterminant(domain)
            degree = estimate_total_polynomial_degree(apply_geometry_lowering(detFJ))
            scale = detFJ('+') * weight
        else:
            # No need to scale 'integral' over a vertex
            scale = 1

    elif integral_type in custom_integral_types:
        # Scaling with custom weight, which includes eventual volume
        # scaling
        scale = weight

    elif integral_type in point_integral_types:
        # No need to scale 'integral' over a point
        scale = 1

    else:
        error("Unknown integral type {}, don't know how to scale.".format(integral_type))

    return scale, degree
	def supply_shape_derivative(self, shape_derivative):
		"""Overrides the shape derivative of the reduced cost functional.
		
		This allows users to implement their own shape derivative and use cashocs as a
		solver library only.
		
		Parameters
		----------
		shape_derivative : ufl.form.Form
			The shape_derivative of the reduced (!) cost functional w.r.t. controls.

		Returns
		-------
		None
		"""
		
		try:
			if not shape_derivative.__module__ == 'ufl.form' and type(shape_derivative).__name__ == 'Form':
				raise InputError('cashocs._shape_optimization.shape_optimization_problem.ShapeOptimizationProblem.supply_shape_derivative',
								 'shape_derivative', 'shape_derivative have to be a ufl form')
		except:
			raise InputError('cashocs._shape_optimization.shape_optimization_problem.ShapeOptimizationProblem.supply_shape_derivative',
							 'shape_derivative', 'shape_derivative has to be a ufl form')
		
		if len(shape_derivative.arguments()) == 2:
			raise InputError('cashocs._shape_optimization.shape_optimization_problem.ShapeOptimizationProblem.supply_shape_derivative',
							 'shape_derivative', 'Do not use TrialFunction for the shape_derivative.')
		elif len(shape_derivative.arguments()) == 0:
			raise InputError('cashocs._shape_optimization.shape_optimization_problem.ShapeOptimizationProblem.supply_shape_derivative',
							 'shape_derivative', 'The specified shape_derivative must include a TestFunction object.')
		
		if not shape_derivative.arguments()[0].ufl_function_space().ufl_element() == self.form_handler.deformation_space.ufl_element():
			raise InputError('cashocs._shape_optimization.shape_optimization_problem.ShapeOptimizationProblem.supply_shape_derivative',
							 'shape_derivative', 'The TestFunction has to be chosen from the same space as the corresponding adjoint.')
		
		if not shape_derivative.arguments()[0].ufl_function_space() == self.form_handler.deformation_space:
			shape_derivative = replace(shape_derivative, {shape_derivative.arguments()[0] : self.form_handler.test_vector_field})
		
		if self.form_handler.degree_estimation:
			estimated_degree = np.maximum(estimate_total_polynomial_degree(self.form_handler.riesz_scalar_product),
											   estimate_total_polynomial_degree(shape_derivative))
			self.form_handler.assembler = fenics.SystemAssembler(self.form_handler.riesz_scalar_product, shape_derivative, self.form_handler.bcs_shape,
													form_compiler_parameters={'quadrature_degree' : estimated_degree})
		else:
			try:
				self.form_handler.assembler = fenics.SystemAssembler(self.form_handler.riesz_scalar_product, shape_derivative, self.form_handler.bcs_shape)
			except (AssertionError, ValueError):
				estimated_degree = np.maximum(estimate_total_polynomial_degree(self.form_handler.riesz_scalar_product),
											   estimate_total_polynomial_degree(shape_derivative))
				self.form_handler.assembler = fenics.SystemAssembler(self.form_handler.riesz_scalar_product, shape_derivative, self.form_handler.bcs_shape,
													form_compiler_parameters={'quadrature_degree' : estimated_degree})
		
		self.has_custom_derivative = True
Exemplo n.º 4
0
def attach_estimated_degrees(form):
    """Attach estimated polynomial degree to a form's integrals.

    :arg form: The :class:`~.Form` to inspect.
    :returns: A new Form with estimate degrees attached.
    """
    integrals = form.integrals()

    new_integrals = []
    for integral in integrals:
        md = {}
        md.update(integral.metadata())
        degree = estimate_total_polynomial_degree(integral.integrand())
        md["estimated_polynomial_degree"] = degree
        new_integrals.append(integral.reconstruct(metadata=md))
    return Form(new_integrals)
Exemplo n.º 5
0
def attach_estimated_degrees(form):
    """Attach estimated polynomial degree to a form's integrals.

    :arg form: The :class:`~.Form` to inspect.
    :returns: A new Form with estimate degrees attached.
    """
    integrals = form.integrals()

    new_integrals = []
    for integral in integrals:
        md = {}
        md.update(integral.metadata())
        degree = estimate_total_polynomial_degree(integral.integrand())
        md["estimated_polynomial_degree"] = degree
        new_integrals.append(integral.reconstruct(metadata=md))
    return Form(new_integrals)
Exemplo n.º 6
0
    def __init__(self,
                 lagrangian,
                 bcs_list,
                 states,
                 adjoints,
                 boundaries,
                 config,
                 ksp_options,
                 adjoint_ksp_options,
                 shape_scalar_product=None,
                 deformation_space=None):
        """Initializes the ShapeFormHandler object.

		Parameters
		----------
		lagrangian : cashocs._forms.Lagrangian
			The Lagrangian corresponding to the shape optimization problem
		bcs_list : list[list[dolfin.fem.dirichletbc.DirichletBC]]
			list of boundary conditions for the state variables
		states : list[dolfin.function.function.Function]
			list of state variables
		adjoints : list[dolfin.function.function.Function]
			list of adjoint variables
		boundaries : dolfin.cpp.mesh.MeshFunctionSizet
			a MeshFunction for the boundary markers
		config : configparser.ConfigParser
			the configparser object storing the problems config
		ksp_options : list[list[list[str]]]
			The list of command line options for the KSP for the
			state systems.
		adjoint_ksp_options : list[list[list[str]]]
			The list of command line options for the KSP for the
			adjoint systems.
		shape_scalar_product : ufl.form.Form
			The weak form of the scalar product used to determine the
			shape gradient.
		"""

        FormHandler.__init__(self, lagrangian, bcs_list, states, adjoints,
                             config, ksp_options, adjoint_ksp_options)

        self.boundaries = boundaries
        self.shape_scalar_product = shape_scalar_product

        self.degree_estimation = self.config.getboolean('ShapeGradient',
                                                        'degree_estimation',
                                                        fallback=False)
        self.use_pull_back = self.config.getboolean('ShapeGradient',
                                                    'use_pull_back',
                                                    fallback=True)

        if deformation_space is None:
            self.deformation_space = fenics.VectorFunctionSpace(
                self.mesh, 'CG', 1)
        else:
            self.deformation_space = deformation_space

        self.test_vector_field = fenics.TestFunction(self.deformation_space)

        self.regularization = Regularization(self)

        # Calculate the necessary UFL forms
        self.inhomogeneous_mu = False
        self.__compute_shape_derivative()
        self.__compute_shape_gradient_forms()
        self.__setup_mu_computation()

        if self.degree_estimation:
            self.estimated_degree = np.maximum(
                estimate_total_polynomial_degree(self.riesz_scalar_product),
                estimate_total_polynomial_degree(self.shape_derivative))
            self.assembler = fenics.SystemAssembler(self.riesz_scalar_product,
                                                    self.shape_derivative,
                                                    self.bcs_shape,
                                                    form_compiler_parameters={
                                                        'quadrature_degree':
                                                        self.estimated_degree
                                                    })
        else:
            try:
                self.assembler = fenics.SystemAssembler(
                    self.riesz_scalar_product, self.shape_derivative,
                    self.bcs_shape)
            except (AssertionError, ValueError):
                self.estimated_degree = np.maximum(
                    estimate_total_polynomial_degree(
                        self.riesz_scalar_product),
                    estimate_total_polynomial_degree(self.shape_derivative))
                self.assembler = fenics.SystemAssembler(
                    self.riesz_scalar_product,
                    self.shape_derivative,
                    self.bcs_shape,
                    form_compiler_parameters={
                        'quadrature_degree': self.estimated_degree
                    })

        self.assembler.keep_diagonal = True
        self.fe_scalar_product_matrix = fenics.PETScMatrix()
        self.fe_shape_derivative_vector = fenics.PETScVector()

        self.update_scalar_product()

        # test for symmetry
        if not self.scalar_product_matrix.isSymmetric():
            if not self.scalar_product_matrix.isSymmetric(1e-15):
                if not (self.scalar_product_matrix -
                        self.scalar_product_matrix.copy().transpose()
                        ).norm() / self.scalar_product_matrix.norm() < 1e-15:
                    raise InputError(
                        'cashocs._forms.ShapeFormHandler',
                        'shape_scalar_product',
                        'Supplied scalar product form is not symmetric.')

        if self.opt_algo == 'newton' \
          or (self.opt_algo == 'pdas' and self.inner_pdas == 'newton'):
            raise NotImplementedError(
                'Second order methods are not implemented for shape optimization yet'
            )