Esempio n. 1
0
    def ComputeNeumannForces(self, mesh, materials, function_spaces, compute_traction_forces=True, compute_body_forces=False):
        """Compute/assemble traction and body forces"""

        if self.neumann_flags is None:
            return np.zeros((mesh.points.shape[0]*materials[0].nvar,1),dtype=np.float64)

        nvar = materials[0].nvar
        ndim = mesh.InferSpatialDimension()

        if self.neumann_flags.shape[0] == mesh.points.shape[0]:
            self.neumann_data_applied_at = "node"
        else:
            if ndim==3:
                if self.neumann_flags.shape[0] == mesh.faces.shape[0]:
                    self.neumann_data_applied_at = "face"
            elif ndim==2:
                if self.neumann_flags.shape[0] == mesh.edges.shape[0]:
                    self.neumann_data_applied_at = "face"


        if self.neumann_data_applied_at == 'face':
            from Kuru.FiniteElements.Assembly import AssembleForces
            if not isinstance(function_spaces,tuple):
                raise ValueError("Boundary functional spaces not available for computing Neumman and body forces")
            else:
                # CHECK IF A FUNCTION SPACE FOR BOUNDARY EXISTS - SAFEGAURDS AGAINST FORMULATIONS THAT DO NO PROVIDE ONE
                has_boundary_spaces = False
                for fs in function_spaces:
                    if ndim == 3 and fs.ndim == 2:
                        has_boundary_spaces = True
                        break
                    elif ndim == 2 and fs.ndim == 1:
                        has_boundary_spaces = True
                        break
                if not has_boundary_spaces:
                    from Kuru import QuadratureRule, FunctionSpace
                    # COMPUTE BOUNDARY FUNCTIONAL SPACES
                    p = mesh.InferPolynomialDegree()
                    bquadrature = QuadratureRule(optimal=3, norder=2*p+1,
                        mesh_type=mesh.boundary_element_type, is_flattened=False)
                    bfunction_space = FunctionSpace(mesh.CreateDummyLowerDimensionalMesh(),
                        bquadrature, p=p, equally_spaced=mesh.IsEquallySpaced, use_optimal_quadrature=False)
                    function_spaces = (function_spaces[0],bfunction_space)
                    # raise ValueError("Boundary functional spaces not available for computing Neumman and body forces")

            t_tassembly = time()
            if self.analysis_type == "static":
                F = AssembleForces(self, mesh, materials, function_spaces,
                    compute_traction_forces=compute_traction_forces, compute_body_forces=compute_body_forces)
            elif self.analysis_type == "dynamic":
                if self.neumann_flags.ndim==2:
                    # THE POSITION OF NEUMANN DATA APPLIED AT FACES CAN CHANGE DYNAMICALLY
                    tmp_flags = np.copy(self.neumann_flags)
                    tmp_data = np.copy(self.applied_neumann)
                    F = np.zeros((mesh.points.shape[0]*nvar,self.neumann_flags.shape[1]))
                    for step in range(self.neumann_flags.shape[1]):
                        self.neumann_flags = tmp_flags[:,step]
                        self.applied_neumann = tmp_data[:,:,step]
                        F[:,step] = AssembleForces(self, mesh, materials, function_spaces,
                            compute_traction_forces=compute_traction_forces, compute_body_forces=compute_body_forces).flatten()

                    self.neumann_flags = tmp_flags
                    self.applied_neumann = tmp_data
                else:
                    # THE POSITION OF NEUMANN DATA APPLIED AT FACES CAN CHANGE DYNAMICALLY
                    F = AssembleForces(self, mesh, materials, function_spaces,
                            compute_traction_forces=compute_traction_forces, compute_body_forces=compute_body_forces).flatten()

            print("Assembled external traction forces. Time elapsed is {} seconds".format(time()-t_tassembly))


        elif self.neumann_data_applied_at == 'node':
            # A DIRICHLET TYPE METHODOLGY FOR APPLYING NEUMANN BOUNDARY CONDITONS (i.e. AT NODES)
            if self.analysis_type == "dynamic":
                if self.neumann_flags.ndim ==3:
                    # FOR DYNAMIC ANALYSIS IT IS ASSUMED THAT
                    # to_apply DOOES NOT CHANGE DURING THE ANALYSIS
                    flat_neu = self.neumann_flags[:,:,0].ravel()
                    to_apply = np.arange(self.neumann_flags[:,:,0].size)[~np.isnan(flat_neu)]
                    F = np.zeros((mesh.points.shape[0]*nvar,self.neumann_flags.shape[2]))

                    for step in range(self.neumann_flags.shape[2]):
                        flat_neu = self.neumann_flags[:,:,step].ravel()
                        to_apply = np.arange(self.neumann_flags[:,:,step].size)[~np.isnan(flat_neu)]
                        F[to_apply,step] = flat_neu[~np.isnan(flat_neu)]
                else:
                    F = np.zeros((mesh.points.shape[0]*nvar,1))
                    flat_neu = self.neumann_flags.ravel()
                    to_apply = np.arange(self.neumann_flags.size)[~np.isnan(flat_neu)]
                    applied_neumann = flat_neu[~np.isnan(flat_neu)]
                    F[to_apply,0] = applied_neumann
            else:
                F = np.zeros((mesh.points.shape[0]*nvar,1))
                flat_neu = self.neumann_flags.ravel()
                to_apply = np.arange(self.neumann_flags.size)[~np.isnan(flat_neu)]
                applied_neumann = flat_neu[~np.isnan(flat_neu)]
                F[to_apply,0] = applied_neumann

        return F
Esempio n. 2
0
def AssembleRobinForces(boundary_condition, mesh, material, function_spaces, fem_solver, Eulerx, type_load):
    """Compute/assemble traction (follower)"""

    ndim = mesh.InferSpatialDimension()
    nvar = material.nvar

    if type_load == 'pressure':
        if boundary_condition.pressure_flags.shape[0] == mesh.points.shape[0]:
            #boundary_condition.robin_data_applied_at = "node"
            raise ValueError("Robin boundary forces (pressure) applied at nodes")
    elif type_load == 'spring':
        if boundary_condition.spring_flags.shape[0] == mesh.points.shape[0]:
            #boundary_condition.robin_data_applied_at = "node"
            raise ValueError("Robin boundary forces (spring) applied at nodes")
    elif type_load == 'connector':
        if ndim == 2:
            if boundary_condition.connector_elements.shape[1] != 2*mesh.edges.shape[1]:
                raise ValueError("Robin boundary connector should be compose by two boundary elements")
        else:
            if boundary_condition.connector_elements.shape[1] != 2*mesh.faces.shape[1]:
                raise ValueError("Robin boundary connector should be compose by two boundary elements")
    else:
        raise ValueError("Load {} not unserstood. Just spring or pressure.".format(type_load))

    if not isinstance(function_spaces,tuple):
        raise ValueError("Boundary functional spaces not available for computing pressure stiffness")
    else:
        # CHECK IF A FUNCTION SPACE FOR BOUNDARY EXISTS - SAFEGAURDS AGAINST FORMULATIONS THAT DO NO PROVIDE ONE
        has_boundary_spaces = False
        for fs in function_spaces:
            if ndim == 3 and fs.ndim == 2:
                has_boundary_spaces = True
                break
            elif ndim == 2 and fs.ndim == 1:
                has_boundary_spaces = True
                break
        if not has_boundary_spaces:
            from Kuru import QuadratureRule, FunctionSpace
            # COMPUTE BOUNDARY FUNCTIONAL SPACES
            p = mesh.InferPolynomialDegree()
            bquadrature = QuadratureRule(optimal=3, norder=2*p+1,
                mesh_type=mesh.boundary_element_type, is_flattened=False)
            bfunction_space = FunctionSpace(mesh.CreateDummyLowerDimensionalMesh(),
                bquadrature, p=p, equally_spaced=mesh.IsEquallySpaced, use_optimal_quadrature=False)
            function_spaces = (function_spaces[0],bfunction_space)

    if type_load == 'pressure':
        from .RobinForces import StaticPressureForces
        if boundary_condition.analysis_type == "static":
            if fem_solver.recompute_sparsity_pattern:
                I_robin, J_robin, V_robin, F_robin = StaticPressureForces(boundary_condition,
                    mesh, material, function_spaces[-1], fem_solver, Eulerx)
                K_robin = coo_matrix((V_robin,(I_robin,J_robin)),
                    shape=((nvar*mesh.points.shape[0],nvar*mesh.points.shape[0])),dtype=np.float64).tocsr()
            else:
                V_robin, F_robin = StaticPressureForces(boundary_condition, mesh,
                    material, function_spaces[-1], fem_solver, Eulerx)
                K_robin = csr_matrix((V_robin,fem_solver.indices,fem_solver.indptr),
                    shape=((nvar*mesh.points.shape[0],nvar*mesh.points.shape[0])))

        elif boundary_condition.analysis_type == "dynamic":
            raise ValueError("Not implemented yet")

        return K_robin, F_robin

    if type_load == 'spring':
        from .RobinForces import StaticSpringForces
        if boundary_condition.analysis_type == "static":
            if fem_solver.recompute_sparsity_pattern:
                I_robin, J_robin, V_robin, F_robin = StaticSpringForces(boundary_condition,
                    mesh, material, function_spaces[-1], fem_solver, Eulerx)
                K_robin = coo_matrix((V_robin,(I_robin,J_robin)),
                    shape=((nvar*mesh.points.shape[0],nvar*mesh.points.shape[0])),dtype=np.float64).tocsr()
            else:
                V_robin, F_robin = StaticSpringForces(boundary_condition, mesh,
                    material, function_spaces[-1], fem_solver, Eulerx)
                K_robin = csr_matrix((V_robin,fem_solver.indices,fem_solver.indptr),
                    shape=((nvar*mesh.points.shape[0],nvar*mesh.points.shape[0])))

        elif boundary_condition.analysis_type == "dynamic":
            raise ValueError("Not implemented yet")

        return K_robin, F_robin

    if type_load == 'connector':
        from .RobinForces import StaticConnectorForces
        if boundary_condition.analysis_type == "static":
            if fem_solver.recompute_sparsity_pattern:
                I_robin, J_robin, V_robin, F_robin = StaticConnectorForces(boundary_condition,
                    mesh, material, function_spaces[-1], fem_solver, Eulerx)
                K_robin = coo_matrix((V_robin,(I_robin,J_robin)),
                    shape=((nvar*mesh.points.shape[0],nvar*mesh.points.shape[0])),dtype=np.float64).tocsr()
            else:
                V_robin, F_robin = StaticConnectorForces(boundary_condition, mesh,
                    material, function_spaces[-1], fem_solver, Eulerx)
                K_robin = csr_matrix((V_robin,fem_solver.indices,fem_solver.indptr),
                    shape=((nvar*mesh.points.shape[0],nvar*mesh.points.shape[0])))

        elif boundary_condition.analysis_type == "dynamic":
            raise ValueError("Not implemented yet")

        return K_robin, F_robin
    def GetFibreStressAndSoftness(self,
                                  mesh,
                                  formulation,
                                  material,
                                  fem_solver,
                                  Eulerx,
                                  average_derived_quantities=True):
        """
            steps:          [list,np.1darray] for which time steps/increments the data should
                            be recovered
        """

        det = np.linalg.det
        inv = np.linalg.inv

        # GET THE UNDERLYING LINEAR MESH
        # lmesh = mesh.GetLinearMesh()
        C = mesh.InferPolynomialDegree() - 1
        ndim = mesh.InferSpatialDimension()

        nelem = mesh.elements.shape[0]
        npoint = mesh.points.shape[0]
        nodeperelem = mesh.elements.shape[1]

        # GET QUADRATURE
        norder = 2 * C
        if norder == 0:
            norder = 1
        # quadrature = QuadratureRule(qtype="gauss", norder=norder, mesh_type=mesh.element_type, optimal=3)
        # Domain = FunctionSpace(mesh, quadrature, p=C+1)
        Domain = FunctionSpace(mesh, p=C + 1, evaluate_at_nodes=True)
        Jm = Domain.Jm
        AllGauss = Domain.AllGauss
        Bases = Domain.Bases

        # requires_geometry_update = fem_solver.requires_geometry_update
        requires_geometry_update = True  # ALWAYS TRUE FOR THIS ROUTINE

        F = np.zeros((material.element_set.shape[0], nodeperelem, ndim, ndim))
        # DEFINE CONSTITUENT STRESSES FOR GROWTH-REMODELING PROBLEM
        ElemFibreStress = np.zeros(
            (material.element_set.shape[0], nodeperelem, 5))  # 5-fibres
        ElemSoftness = np.zeros(
            (material.element_set.shape[0], nodeperelem, 5))  # 5-fibres

        FibreStress = np.zeros((material.node_set.shape[0], 5))
        Softness = np.zeros((material.node_set.shape[0], 5))

        # LOOP OVER ELEMENTS
        for ielem in range(material.element_set.shape[0]):
            elem = material.element_set[ielem]
            # GET THE FIELDS AT THE ELEMENT LEVEL
            LagrangeElemCoords = mesh.points[mesh.elements[elem, :], :]
            EulerElemCoords = Eulerx[mesh.elements[elem, :], :]
            # GROWTH-REMODELING VALUES FOR THIS ELEMENT
            material.MappingStateVariables(mesh, Domain, elem)

            if material.has_low_level_dispatcher:
                # GET LOCAL KINEMATICS
                SpatialGradient, F[
                    ielem, :, :, :], detJ, dV = _KinematicMeasures_(
                        Jm, AllGauss[:, 0], LagrangeElemCoords,
                        EulerElemCoords, requires_geometry_update)
                # PARAMETERS FOR INCOMPRESSIBILITY (MEAN DILATATION METHOD HU-WASHIZU)
                if material.is_incompressible:
                    MaterialVolume = np.sum(dV)
                    if fem_solver.has_growth_remodeling:
                        dve = np.true_divide(detJ, material.StateVariables[:,
                                                                           20])
                        CurrentVolume = np.sum(dve)
                    else:
                        CurrentVolume = np.sum(detJ)
                    material.pressure = material.kappa * (
                        CurrentVolume - MaterialVolume) / MaterialVolume

                # COMPUTE FIBRE STRESS AND SOFTNESS
                ElemFibreStress[ielem, :, :], ElemSoftness[
                    ielem, :, :] = material._ConstituentMeasures_(
                        F[ielem, :, :, :], elem)

            else:
                # GAUSS LOOP IN VECTORISED FORM
                ParentGradientX = np.einsum('ijk,jl->kil', Jm,
                                            LagrangeElemCoords)
                # MATERIAL GRADIENT TENSOR IN PHYSICAL ELEMENT [\nabla_0 (N)]
                MaterialGradient = np.einsum('ijk,kli->ijl',
                                             inv(ParentGradientX), Jm)
                # DEFORMATION GRADIENT TENSOR [\vec{x} \otimes \nabla_0 (N)]
                F[ielem, :, :, :] = np.einsum('ij,kli->kjl', EulerElemCoords,
                                              MaterialGradient)
                # COMPUTE REMAINING KINEMATIC MEASURES
                StrainTensors = KinematicMeasures(F[ielem, :, :, :],
                                                  fem_solver.analysis_nature)

                # GEOMETRY UPDATE IS A MUST
                # MAPPING TENSOR [\partial\vec{X}/ \partial\vec{\varepsilon} (ndim x ndim)]
                ParentGradientx = np.einsum('ijk,jl->kil', Jm, EulerElemCoords)
                # SPATIAL GRADIENT TENSOR IN PHYSICAL ELEMENT [\nabla (N)]
                SpatialGradient = np.einsum('ijk,kli->ilj',
                                            inv(ParentGradientx), Jm)
                # COMPUTE ONCE detJ (GOOD SPEEDUP COMPARED TO COMPUTING TWICE)
                detJ = np.einsum('i,i,i->i', AllGauss[:, 0],
                                 np.abs(det(ParentGradientX)),
                                 np.abs(StrainTensors['J']))

                # COMPUTE PARAMETERS FOR MEAN DILATATION METHOD, IT NEEDS TO BE BEFORE COMPUTE HESSIAN AND STRESS
                if material.is_incompressible:
                    dV = np.einsum('i,i->i', AllGauss[:, 0],
                                   np.abs(det(ParentGradientX)))
                    MaterialVolume = np.sum(dV)
                    if fem_solver.has_growth_remodeling:
                        dve = np.true_divide(detJ, material.StateVariables[:,
                                                                           20])
                        CurrentVolume = np.sum(dve)
                    else:
                        CurrentVolume = np.sum(detJ)
                    material.pressure = material.kappa * (
                        CurrentVolume - MaterialVolume) / MaterialVolume

                # LOOP OVER GAUSS POINTS
                for counter in range(AllGauss.shape[0]):
                    # COMPUTE FIBRE STRESS AND SOFTNESS
                    ElemFibreStress[ielem, counter, :], ElemSoftness[
                        ielem, counter, :] = material.ConstituentMeasures(
                            StrainTensors, elem, counter)

        # COMPUTE THE COMMON/NEIGHBOUR NODES ONCE
        Elss, Poss = material.GetNodeCommonality()[:2]
        for inode in range(material.node_set.shape[0]):
            Els, Pos = Elss[inode], Poss[inode]
            ncommon_nodes = Els.shape[0]
            for uelem in range(ncommon_nodes):
                FibreStress[inode, :] += ElemFibreStress[Els[uelem],
                                                         Pos[uelem], :]
                Softness[inode, :] += ElemSoftness[Els[uelem], Pos[uelem], :]

            # AVERAGE OUT
            FibreStress[inode, :] /= ncommon_nodes
            Softness[inode, :] /= ncommon_nodes

        return FibreStress, Softness
Esempio n. 4
0
    def GetQuadraturesAndFunctionSpaces(self,
                                        mesh,
                                        variables_order=(1, ),
                                        quadrature_rules=None,
                                        quadrature_type=None,
                                        function_spaces=None,
                                        compute_post_quadrature=True,
                                        equally_spaced_bases=False,
                                        quadrature_degree=None):
        """"The default function for computing quadrature rules and function spaces for equall order single
            and multi-physics/fields problems"""

        C = mesh.InferPolynomialDegree() - 1
        mesh.InferBoundaryElementType()

        if quadrature_rules == None and self.quadrature_rules == None:

            # OPTION FOR QUADRATURE TECHNIQUE FOR TRIS AND TETS
            optimal_quadrature = 3
            if mesh.element_type == "quad" or mesh.element_type == "hex":
                if quadrature_type == "wv":
                    optimal_quadrature = 4

            norder, norder_post = self.GetQuadratureOrder(
                C, mesh.element_type, quadrature_degree=quadrature_degree)

            # GET QUADRATURE
            quadrature = QuadratureRule(optimal=optimal_quadrature,
                                        norder=norder,
                                        mesh_type=mesh.element_type)
            if self.compute_post_quadrature:
                # COMPUTE INTERPOLATION FUNCTIONS AT ALL INTEGRATION POINTS FOR POST-PROCESSING
                post_quadrature = QuadratureRule(optimal=optimal_quadrature,
                                                 norder=norder_post,
                                                 mesh_type=mesh.element_type)
            else:
                post_quadrature = None

            # BOUNDARY QUADRATURE
            bquadrature = QuadratureRule(optimal=optimal_quadrature,
                                         norder=C + 2,
                                         mesh_type=mesh.boundary_element_type)

            self.quadrature_rules = (quadrature, post_quadrature, bquadrature)
        else:
            self.quadrature_rules = quadrature_rules

        if function_spaces == None and self.function_spaces == None:

            # CREATE FUNCTIONAL SPACES
            function_space = FunctionSpace(mesh,
                                           self.quadrature_rules[0],
                                           p=C + 1,
                                           equally_spaced=equally_spaced_bases)
            if self.compute_post_quadrature:
                post_function_space = FunctionSpace(
                    mesh,
                    self.quadrature_rules[1],
                    p=C + 1,
                    equally_spaced=equally_spaced_bases)
            else:
                post_function_space = None

            # CREATE BOUNDARY FUNCTIONAL SPACES
            bfunction_space = FunctionSpace(
                mesh.CreateDummyLowerDimensionalMesh(),
                self.quadrature_rules[2],
                p=C + 1,
                equally_spaced=equally_spaced_bases)

            self.function_spaces = (function_space, post_function_space,
                                    bfunction_space)
        else:
            self.function_spaces = function_spaces

        local_size = self.function_spaces[0].Bases.shape[0] * self.nvar
        self.local_rows = np.repeat(np.arange(0, local_size),
                                    local_size,
                                    axis=0)
        self.local_columns = np.tile(np.arange(0, local_size), local_size)
        self.local_size = local_size

        # FOR MASS
        local_size_m = self.function_spaces[0].Bases.shape[0] * self.ndim
        self.local_rows_mass = np.repeat(np.arange(0, local_size_m),
                                         local_size_m,
                                         axis=0)
        self.local_columns_mass = np.tile(np.arange(0, local_size_m),
                                          local_size_m)
        self.local_size_m = local_size_m