Example #1
0
def CurvedPlate(ncirc=2, nlong=20, show_plot=False):
    """Creates custom mesh for plate with curved edges
        ncirc           discretisation around circular fillets
        nlong           discretisation along the length - X
    """

    mesh_arc = Mesh()
    mesh_arc.Arc(element_type="quad", nrad=ncirc, ncirc=ncirc, radius=5)

    mesh_arc1 = deepcopy(mesh_arc)
    mesh_arc1.points[:, 1] += 15
    mesh_arc1.points[:, 0] += 95
    mesh_arc2 = deepcopy(mesh_arc)
    mesh_arc2.points[:, 1] += 15
    mesh_arc2.points[:, 0] *= -1.
    mesh_arc2.points[:, 0] += 5.

    mesh_plate1 = Mesh()
    mesh_plate1.Rectangle(element_type="quad",
                          lower_left_point=(5, 15),
                          upper_right_point=(95, 20),
                          ny=ncirc,
                          nx=nlong)

    mesh_plate2 = deepcopy(mesh_plate1)
    mesh_plate2.points[:, 1] -= 5.

    mesh_square1 = Mesh()
    mesh_square1.Square(element_type="quad",
                        lower_left_point=(0, 10),
                        side_length=5,
                        nx=ncirc,
                        ny=ncirc)

    mesh_square2 = deepcopy(mesh_square1)
    mesh_square2.points[:, 0] += 95

    mesh = mesh_plate1 + mesh_plate2 + mesh_arc1 + mesh_arc2 + mesh_square1 + mesh_square2

    mesh.Extrude(length=0.5, nlong=1)

    mesh2 = deepcopy(mesh)
    mesh2.points[:, 2] += 0.5
    mesh += mesh2

    if show_plot:
        mesh.SimplePlot()

    return mesh
    def LogSave(self, fem_solver, formulation, U, Eulerp, Increment):
        if fem_solver.print_incremental_log:
            dmesh = Mesh()
            dmesh.points = U
            dmesh_bounds = dmesh.Bounds
            if formulation.fields == "electro_mechanics":
                _bounds = np.zeros((2,formulation.nvar))
                _bounds[:,:formulation.ndim] = dmesh_bounds
                _bounds[:,-1] = [Eulerp.min(),Eulerp.max()]
                print("\nMinimum and maximum incremental solution values at increment {} are \n".format(Increment),_bounds)
            else:
                print("\nMinimum and maximum incremental solution values at increment {} are \n".format(Increment),dmesh_bounds)

        # SAVE INCREMENTAL SOLUTION IF ASKED FOR
        if fem_solver.save_incremental_solution:
            # FOR BIG MESHES
            if Increment % fem_solver.incremental_solution_save_frequency !=0:
                return
            from scipy.io import savemat
            filename = fem_solver.incremental_solution_filename
            if filename is not None:
                if ".mat" in filename:
                    filename = filename.split(".")[0]
                savemat(filename+"_"+str(Increment),
                    {'solution':np.hstack((U,Eulerp[:,None]))},do_compression=True)
            else:
                raise ValueError("No file name provided to save incremental solution")
Example #3
0
def HighOrderMeshTet_SEMISTABLE(C,
                                mesh,
                                Decimals=10,
                                equally_spaced=False,
                                check_duplicates=True,
                                parallelise=False,
                                nCPU=1,
                                compute_boundary_info=True):

    from Florence.FunctionSpace import Tet
    from Florence.QuadratureRules.FeketePointsTet import FeketePointsTet
    from Florence.MeshGeneration.NodeArrangement import NodeArrangementTet

    # SWITCH OFF MULTI-PROCESSING FOR SMALLER PROBLEMS WITHOUT GIVING A MESSAGE
    Parallel = parallelise
    if (mesh.elements.shape[0] < 500) and (C < 5):
        Parallel = False
        nCPU = 1

    if not equally_spaced:
        eps = FeketePointsTet(C)
        # COMPUTE BASES FUNCTIONS AT ALL NODAL POINTS
        Neval = np.zeros((4, eps.shape[0]), dtype=np.float64)
        hpBases = Tet.hpNodal.hpBases
        for i in range(4, eps.shape[0]):
            Neval[:, i] = hpBases(0,
                                  eps[i, 0],
                                  eps[i, 1],
                                  eps[i, 2],
                                  Transform=1,
                                  EvalOpt=1)[0]
    else:
        from Florence.QuadratureRules.EquallySpacedPoints import EquallySpacedPointsTet
        eps = EquallySpacedPointsTet(C)
        # COMPUTE BASES FUNCTIONS AT ALL NODAL POINTS
        hpBases = Tet.hpNodal.hpBases
        Neval = np.zeros((4, eps.shape[0]), dtype=np.float64)
        for i in range(4, eps.shape[0]):
            Neval[:, i] = hpBases(0,
                                  eps[i, 0],
                                  eps[i, 1],
                                  eps[i, 2],
                                  Transform=1,
                                  EvalOpt=1,
                                  equally_spaced=True)[0]

    # THIS IS NECESSARY FOR REMOVING DUPLICATES
    makezero(Neval, tol=1e-12)

    nodeperelem = mesh.elements.shape[1]
    renodeperelem = int((C + 2.) * (C + 3.) * (C + 4.) / 6.)
    left_over_nodes = renodeperelem - nodeperelem

    reelements = -1 * np.ones(
        (mesh.elements.shape[0], renodeperelem), dtype=np.int64)
    reelements[:, :4] = mesh.elements
    # TOTAL NUMBER OF (INTERIOR+EDGE+FACE) NODES
    iesize = np.int64(C * (C - 1) * (C - 2) / 6. + 6. * C + 2 * C * (C - 1))
    repoints = np.zeros(
        (mesh.points.shape[0] + iesize * mesh.elements.shape[0], 3),
        dtype=np.float64)
    repoints[:mesh.points.shape[0], :] = mesh.points

    telements = time()

    xycoord_higher = []
    ParallelTuple1 = []
    if Parallel:
        # GET HIGHER ORDER COORDINATES - PARALLEL
        ParallelTuple1 = parmap.map(ElementLoopTet,
                                    np.arange(0, mesh.elements.shape[0]),
                                    mesh.elements,
                                    mesh.points,
                                    'tet',
                                    eps,
                                    Neval,
                                    pool=MP.Pool(processes=nCPU))

    maxNode = np.max(reelements)
    for elem in range(0, mesh.elements.shape[0]):
        # maxNode = np.max(reelements) # BIG BOTTLENECK
        if Parallel:
            xycoord_higher = ParallelTuple1[elem]
        else:
            xycoord = mesh.points[mesh.elements[elem, :], :]
            # GET HIGHER ORDER COORDINATES
            xycoord_higher = GetInteriorNodesCoordinates(
                xycoord, 'tet', elem, eps, Neval)

        # EXPAND THE ELEMENT CONNECTIVITY
        newElements = np.arange(maxNode + 1, maxNode + 1 + left_over_nodes)
        reelements[elem, 4:] = newElements
        # INSTEAD COMPUTE maxNode BY INDEXING
        maxNode = newElements[-1]

        repoints[mesh.points.shape[0] + elem * iesize:mesh.points.shape[0] +
                 (elem + 1) * iesize] = xycoord_higher[4:, :]

    if Parallel:
        del ParallelTuple1

    telements = time() - telements
    #--------------------------------------------------------------------------------------
    # NOW REMOVE DUPLICATED POINTS
    tnodes = time()

    nnode_linear = mesh.points.shape[0]
    # KEEP ZEROFY ON, OTHERWISE YOU GET STRANGE BEHVAIOUR
    # rounded_repoints = makezero(repoints[nnode_linear:,:].copy())
    rounded_repoints = repoints[nnode_linear:, :].copy()
    makezero(rounded_repoints)
    rounded_repoints = np.round(rounded_repoints, decimals=Decimals)

    _, idx_repoints, inv_repoints = unique2d(rounded_repoints,
                                             order=False,
                                             consider_sort=False,
                                             return_index=True,
                                             return_inverse=True)
    # idx_repoints.sort()
    del rounded_repoints

    idx_repoints = np.concatenate(
        (np.arange(nnode_linear), idx_repoints + nnode_linear))
    repoints = repoints[idx_repoints, :]

    unique_reelements, inv_reelements = np.unique(reelements[:, 4:],
                                                  return_inverse=True)
    unique_reelements = unique_reelements[inv_repoints]
    reelements = unique_reelements[inv_reelements]
    reelements = reelements.reshape(mesh.elements.shape[0], renodeperelem - 4)
    reelements = np.concatenate((mesh.elements, reelements), axis=1)

    # SANITY CHECK fOR DUPLICATES
    #---------------------------------------------------------------------#
    # NOTE THAT THIS REMAPS THE ELEMENT CONNECTIVITY FOR THE WHOLE MESH
    # AND AS A RESULT THE FIRST FEW COLUMNS WOULD NO LONGER CORRESPOND TO
    # LINEAR CONNECTIVITY
    if check_duplicates:
        last_shape = repoints.shape[0]
        deci = int(Decimals) - 2
        if Decimals < 6:
            deci = Decimals
        repoints, idx_repoints, inv_repoints = remove_duplicates_2D(
            repoints, decimals=deci)
        unique_reelements, inv_reelements = np.unique(reelements,
                                                      return_inverse=True)
        unique_reelements = unique_reelements[inv_repoints]
        reelements = unique_reelements[inv_reelements]
        reelements = reelements.reshape(mesh.elements.shape[0], renodeperelem)
        if last_shape != repoints.shape[0]:
            warn(
                'Duplicated points generated in high order mesh. Lower the "Decimals". I have fixed it for now'
            )
    #---------------------------------------------------------------------#

    tnodes = time() - tnodes
    #------------------------------------------------------------------------------------------

    #------------------------------------------------------------------------------------------
    if compute_boundary_info:
        # BUILD FACES NOW
        tfaces = time()
        # GET MESH EDGES AND FACES
        fsize = int((C + 2.) * (C + 3.) / 2.)
        refaces = np.zeros((mesh.faces.shape[0], fsize),
                           dtype=mesh.faces.dtype)

        refaces = np.zeros((mesh.faces.shape[0], fsize))
        # DO NOT CHANGE THE FACES, BY RECOMPUTING THEM, AS THE LINEAR FACES CAN COME FROM
        # AN EXTERNAL MESH GENERATOR, WHOSE ORDERING MAY NOT BE THE SAME, SO JUST FIND WHICH
        # ELEMENTS CONTAIN THESE FACES
        face_to_elements = mesh.GetElementsWithBoundaryFacesTet()
        node_arranger = NodeArrangementTet(C)[0]

        refaces = reelements[face_to_elements[:, 0][:, None],
                             node_arranger[face_to_elements[:, 1], :]].astype(
                                 mesh.faces.dtype)

        tfaces = time() - tfaces
        #------------------------------------------------------------------------------------------

        #------------------------------------------------------------------------------------------
        # BUILD EDGES NOW
        tedges = time()

        # BUILD A 2D MESH
        from Florence import Mesh
        tmesh = Mesh()
        tmesh.element_type = "tri"
        tmesh.elements = refaces
        tmesh.nelem = tmesh.elements.shape[0]
        # GET BOUNDARY EDGES
        reedges = tmesh.GetEdgesTri()
        del tmesh

        tedges = time() - tedges
    #------------------------------------------------------------------------------------------

    class nmesh(object):
        # """Construct pMesh"""
        points = repoints
        elements = reelements
        edges = np.array([[], []])
        faces = np.array([[], []])
        nnode = repoints.shape[0]
        nelem = reelements.shape[0]
        info = 'tet'

    if compute_boundary_info:
        nmesh.edges = reedges
        nmesh.faces = refaces

    gc.collect()

    # print '\nHigh order meshing timing:\n\t\tElement loop:\t '+str(telements)+' seconds\n\t\tNode loop:\t\t '+str(tnodes)+\
    #  ' seconds'+'\n\t\tEdge loop:\t\t '+str(tedges)+' seconds'+\
    #  '\n\t\tFace loop:\t\t '+str(tfaces)+' seconds\n'

    return nmesh
    def Solver(self, function_spaces, formulation, solver,
        K, M, NeumannForces, NodalForces, Residual,
        mesh, TotalDisp, Eulerx, Eulerp, material, boundary_condition, fem_solver):


        # COMPUTE DAMPING MATRIX BASED ON MASS
        D = 0.0
        if fem_solver.include_physical_damping:
            D = fem_solver.damping_factor*M

        # GET BOUNDARY CONDITIONS INFROMATION
        if formulation.fields == "electro_mechanics":
            self.GetBoundaryInfo(mesh, formulation,boundary_condition)
            M_mech = M[self.mechanical_dofs,:][:,self.mechanical_dofs]
            if fem_solver.include_physical_damping:
                D_mech = D[self.mechanical_dofs,:][:,self.mechanical_dofs]

        # INITIALISE VELOCITY AND ACCELERATION
        velocities     = np.zeros((mesh.points.shape[0],formulation.ndim))
        accelerations  = np.zeros((mesh.points.shape[0],formulation.ndim))

        # COMPUTE INITIAL ACCELERATION FOR TIME STEP 0
        InitResidual = Residual - NeumannForces[:,0][:,None]
        if formulation.fields == "electro_mechanics":
            accelerations[:,:] = solver.Solve(M_mech, -InitResidual[self.mechanical_dofs].ravel()
                ).reshape(mesh.points.shape[0],formulation.ndim)
        else:
            accelerations[:,:] = solver.Solve(M, -InitResidual.ravel() ).reshape(mesh.points.shape[0],formulation.ndim)

        self.NRConvergence = fem_solver.NRConvergence
        LoadIncrement = fem_solver.number_of_load_increments
        LoadFactor = fem_solver.total_time/LoadIncrement
        AppliedDirichletInc = np.zeros(boundary_condition.applied_dirichlet.shape[0],dtype=np.float64)

        if NeumannForces.ndim == 2 and NeumannForces.shape[1]==1:
            tmp = np.zeros((NeumannForces.shape[0],LoadIncrement))
            tmp[:,0] = NeumannForces[:,0]
            NeumannForces = tmp


        # TIME LOOP
        for Increment in range(1,LoadIncrement):

            t_increment = time()

            # APPLY NEUMANN BOUNDARY CONDITIONS
            DeltaF = NeumannForces[:,Increment][:,None]
            NodalForces = DeltaF

            # OBRTAIN INCREMENTAL RESIDUAL - CONTRIBUTION FROM BOTH NEUMANN AND DIRICHLET
            Residual = -boundary_condition.ApplyDirichletGetReducedMatrices(K,Residual,
                boundary_condition.applied_dirichlet[:,Increment],LoadFactor=1.0,mass=M,only_residual=True)
            Residual -= DeltaF
            # Residual = -DeltaF
            # GET THE INCREMENTAL DIRICHLET
            AppliedDirichletInc = boundary_condition.applied_dirichlet[:,Increment]

            # COMPUTE INITIAL ACCELERATION - ONLY NEEDED IN CASES OF PRESTRETCHED CONFIGURATIONS
            # accelerations[:,:] = solver.Solve(M, Residual.ravel() - \
            #     K.dot(TotalDisp[:,:,Increment].ravel())).reshape(mesh.points.shape[0],formulation.nvar)

            # LET NORM OF THE FIRST RESIDUAL BE THE NORM WITH RESPECT TO WHICH WE
            # HAVE TO CHECK THE CONVERGENCE OF NEWTON RAPHSON. TYPICALLY THIS IS
            # NORM OF NODAL FORCES
            if Increment==1:
                self.NormForces = np.linalg.norm(Residual)
                # AVOID DIVISION BY ZERO
                if np.isclose(self.NormForces,0.0):
                    self.NormForces = 1e-14
            self.norm_residual = np.linalg.norm(Residual)/self.NormForces


            Eulerx, Eulerp, K, Residual, velocities, accelerations = self.NewtonRaphson(function_spaces, formulation, solver,
                Increment, K, D, M, NodalForces, Residual, mesh, Eulerx, Eulerp,
                material,boundary_condition,AppliedDirichletInc, fem_solver, velocities, accelerations)

            # UPDATE DISPLACEMENTS FOR THE CURRENT LOAD INCREMENT
            TotalDisp[:,:formulation.ndim,Increment] = Eulerx - mesh.points
            if formulation.fields == "electro_mechanics":
                TotalDisp[:,-1,Increment] = Eulerp

            # COMPUTE DISSIPATION OF ENERGY THROUGH TIME
            if fem_solver.compute_energy_dissipation:
                energy_info = self.ComputeEnergyDissipation(function_spaces[0],mesh,material,formulation,fem_solver,
                    Eulerx, TotalDisp, NeumannForces, M, velocities, Increment)
                formulation.energy_dissipation.append(energy_info[0])
                formulation.internal_energy.append(energy_info[1])
                formulation.kinetic_energy.append(energy_info[2])
                formulation.external_energy.append(energy_info[3])
            # COMPUTE DISSIPATION OF LINEAR MOMENTUM THROUGH TIME
            if fem_solver.compute_linear_momentum_dissipation:
                power_info = self.ComputePowerDissipation(function_spaces[0],mesh,material,formulation,fem_solver,
                    Eulerx, TotalDisp, NeumannForces, M, velocities, accelerations, Increment)
                formulation.power_dissipation.append(power_info[0])
                formulation.internal_power.append(power_info[1])
                formulation.kinetic_power.append(power_info[2])
                formulation.external_power.append(power_info[3])


            # PRINT LOG IF ASKED FOR
            if fem_solver.print_incremental_log:
                dmesh = Mesh()
                dmesh.points = TotalDisp[:,:formulation.ndim,Increment]
                dmesh_bounds = dmesh.Bounds
                if formulation.fields == "electro_mechanics":
                    _bounds = np.zeros((2,formulation.nvar))
                    _bounds[:,:formulation.ndim] = dmesh_bounds
                    _bounds[:,-1] = [TotalDisp[:,-1,Increment].min(),TotalDisp[:,-1,Increment].max()]
                    print("\nMinimum and maximum incremental solution values at increment {} are \n".format(Increment),_bounds)
                else:
                    print("\nMinimum and maximum incremental solution values at increment {} are \n".format(Increment),dmesh_bounds)

            # SAVE INCREMENTAL SOLUTION IF ASKED FOR
            if fem_solver.save_incremental_solution:
                from scipy.io import savemat
                if fem_solver.incremental_solution_filename is not None:
                    savemat(fem_solver.incremental_solution_filename+"_"+str(Increment),{'solution':TotalDisp[:,:,Increment]},do_compression=True)
                else:
                    raise ValueError("No file name provided to save incremental solution")


            print('\nFinished Load increment', Increment, 'in', time()-t_increment, 'seconds')

            try:
                print('Norm of Residual is',
                    np.abs(la.norm(Residual[boundary_condition.columns_in])/self.NormForces), '\n')
            except RuntimeWarning:
                print("Invalid value encountered in norm of Newton-Raphson residual")

            # STORE THE INFORMATION IF NEWTON-RAPHSON FAILS
            if fem_solver.newton_raphson_failed_to_converge:
                solver.condA = np.NAN
                TotalDisp = TotalDisp[:,:,:Increment-1]
                fem_solver.number_of_load_increments = Increment - 1
                break

            # BREAK AT A SPECIFICED LOAD INCREMENT IF ASKED FOR
            if fem_solver.break_at_increment != -1 and fem_solver.break_at_increment is not None:
                if fem_solver.break_at_increment == Increment:
                    if fem_solver.break_at_increment < LoadIncrement - 1:
                        print("\nStopping at increment {} as specified\n\n".format(Increment))
                        TotalDisp = TotalDisp[:,:,:Increment]
                        fem_solver.number_of_load_increments = Increment
                    break

        return TotalDisp
Example #5
0
def QuadBallSphericalArc(center=(0., 0., 0.),
                         inner_radius=9.,
                         outer_radius=10.,
                         n=10,
                         nthick=1,
                         element_type="hex",
                         cut_threshold=None,
                         portion=1. / 8.):
    """Similar to QuadBall but hollow and creates only 1/8th or 1/4th or 1/2th of the sphere.
        Starting and ending angles are not supported. Radial division (nthick: to be consistent
        with SphericalArc method of Mesh class) is supported

        input:
            cut_threshold               [float] cutting threshold for element removal since this function is based
                                        QuadBall. Ideal value is zero, so prescribe a value as close to zero
                                        as possible, however that might not always be possible as the cut
                                        might take remove some wanted elements [default = -0.01]
            portion                     [float] portion of the sphere to take. Can only be 1/8., 1/4., 1/2.
    """

    assert inner_radius < outer_radius

    mm = QuadBallSurface(n=n, element_type=element_type)

    offset = outer_radius * 2.
    if cut_threshold is None:
        cut_threshold = -0.01
    if portion == 1. / 8.:
        mm.RemoveElements(
            np.array([[cut_threshold, cut_threshold, cut_threshold],
                      [offset, offset, offset]]))
    elif portion == 1. / 4.:
        mm.RemoveElements(
            np.array([[cut_threshold, cut_threshold, -offset],
                      [offset, offset, offset]]))
    elif portion == 1. / 2.:
        mm.RemoveElements(
            np.array([[cut_threshold, -offset, -offset],
                      [offset, offset, offset]]))
    else:
        raise ValueError("The value of portion can only be 1/8., 1/4. or 1/2.")

    radii = np.linspace(inner_radius, outer_radius, nthick + 1)

    mesh = Mesh()
    mesh.element_type = "hex"
    mesh.nelem = 0
    mesh.nnode = 0

    for i in range(nthick):
        mm1, mm2 = deepcopy(mm), deepcopy(mm)
        if not np.isclose(radii[i], 1):
            mm1.points *= radii[i]
        if not np.isclose(radii[i + 1], 1):
            mm2.points *= radii[i + 1]

        if i == 0:
            elements = np.hstack(
                (mm1.elements, mm1.nnode + mm2.elements)).astype(np.int64)
            mesh.elements = np.copy(elements)
            mesh.points = np.vstack((mm1.points, mm2.points))
        else:
            elements = np.hstack(
                (mesh.elements[(i - 1) * mm2.nelem:i * mm2.nelem, 4:],
                 mesh.nnode + mm2.elements)).astype(np.int64)
            mesh.elements = np.vstack((mesh.elements, elements))
            mesh.points = np.vstack((mesh.points, mm2.points))
        mesh.nelem = mesh.elements.shape[0]
        mesh.nnode = mesh.points.shape[0]

    mesh.elements = np.ascontiguousarray(mesh.elements, dtype=np.int64)
    mesh.nelem = mesh.elements.shape[0]
    mesh.nnode = mesh.points.shape[0]
    mesh.GetBoundaryFaces()
    mesh.GetBoundaryEdges()

    mesh.points[:, 0] += center[0]
    mesh.points[:, 1] += center[1]
    mesh.points[:, 2] += center[2]

    return mesh
Example #6
0
def Torus(show_plot=False):
    """Custom mesh for torus
    """

    raise NotImplementedError("Not fully implemented yet")

    # MAKE TORUS WORK
    from copy import deepcopy
    from numpy.linalg import norm
    mesh = Mesh()
    mesh.Circle(element_type="quad", ncirc=2, nrad=2)
    tmesh = deepcopy(mesh)
    arc = GeometricArc(start=(10, 10, 8), end=(10, 10, -8))
    # arc.GeometricArc()
    nlong = 10
    points = mesh.Extrude(path=arc, nlong=nlong)
    # mesh.SimplePlot()
    # print points

    # elem_nodes = tmesh.elements[0,:]
    # p1 = tmesh.points[elem_nodes[0],:]
    # p2 = tmesh.points[elem_nodes[1],:]
    # p3 = tmesh.points[elem_nodes[2],:]
    # p4 = tmesh.points[elem_nodes[3],:]

    # E1 = np.append(p2 - p1, 0.0)
    # E2 = np.append(p4 - p1, 0.0)
    # E3 = np.array([0,0,1.])

    # E1 /= norm(E1)
    # E2 /= norm(E2)

    # # print E1,E2,E3

    # elem_nodes = mesh.elements[0,:]
    # p1 = mesh.points[elem_nodes[0],:]
    # p2 = mesh.points[elem_nodes[1],:]
    # p3 = mesh.points[elem_nodes[2],:]
    # p4 = mesh.points[elem_nodes[3],:]
    # p5 = mesh.points[elem_nodes[4],:]
    # e1 = p2 - p1
    # e2 = p4 - p1
    # e3 = p5 - p1

    # e1 /= norm(e1)
    # e2 /= norm(e2)
    # e3 /= norm(e3)
    # # print e1,e2,e3

    # # TRANSFORMATION MATRIX
    # Q = np.array([
    #     [np.einsum('i,i',e1,E1), np.einsum('i,i',e1,E2), np.einsum('i,i',e1,E3)],
    #     [np.einsum('i,i',e2,E1), np.einsum('i,i',e2,E2), np.einsum('i,i',e2,E3)],
    #     [np.einsum('i,i',e3,E1), np.einsum('i,i',e3,E2), np.einsum('i,i',e3,E3)]
    #     ])
    # mesh.points = np.dot(mesh.points,Q.T)
    # points = np.dot(points,Q)
    # E1 = np.array([1,0,0.])
    E3 = np.array([0., 0., 1.])
    nnode_2D = tmesh.points.shape[0]
    for i in range(nlong + 1):
        # e1 = points[i,:][None,:]/norm(points[i,:])
        # Q = np.dot(E1[:,None],e1)
        # vpoints = np.dot(points,Q)

        e3 = points[i + 1, :] - points[i, :]
        e3 /= norm(e3)
        Q = np.dot(e3[:, None], E3[None, :])
        # print Q
        # print np.dot(Q,points[i,:][:,None])
        vpoints = np.dot(points, Q)

        # print current_points
        mesh.points[nnode_2D * i:nnode_2D *
                    (i + 1), :2] = tmesh.points + points[i, :2]
        mesh.points[nnode_2D * i:nnode_2D * (i + 1), 2] = vpoints[i, 2]

    # print Q
    # print tmesh.points

    # mesh = Mesh.HexahedralProjection()
    if show_plot:
        mesh.SimplePlot()

    return mesh
Example #7
0
def QuadBall(center=(0., 0., 0.), radius=1., n=10, element_type="hex"):
    """Creates a fully hexahedral mesh on sphere using midpoint subdivision algorithm
        by creating a cube and spherifying it using PostMesh's projection schemes

        inputs:

            n:                          [int] number of divsion in every direction.
                                        Given that this implementation is based on
                                        high order bases different divisions in
                                        different directions is not possible
    """

    try:
        from Florence import Mesh, BoundaryCondition, DisplacementFormulation, FEMSolver, LinearSolver
        from Florence import LinearElastic, NeoHookean
        from Florence.Tensor import prime_number_factorisation
    except ImportError:
        raise ImportError("This function needs Florence's core support")

    n = int(n)
    if n > 50:
        # Values beyond this result in >1M DoFs due to internal prime factoristaion splitting
        raise ValueError(
            "The value of n={} (division in each direction) is too high".
            format(str(n)))

    if not isinstance(center, tuple):
        raise ValueError(
            "The center of the circle should be given in a tuple with two elements (x,y,z)"
        )
    if len(center) != 3:
        raise ValueError(
            "The center of the circle should be given in a tuple with two elements (x,y,z)"
        )

    if n == 2 or n == 3 or n == 5 or n == 7:
        ps = [n]
    else:

        def factorise_all(n):
            if n < 2:
                n = 2
            factors = prime_number_factorisation(n)
            if len(factors) == 1 and n > 2:
                n += 1
                factors = prime_number_factorisation(n)
            return factors

        factors = factorise_all(n)
        ps = []
        for factor in factors:
            ps += factorise_all(factor)

    # Do high ps first
    ps = np.sort(ps)[::-1].tolist()
    niter = len(ps)

    # IGS file for sphere with radius 1000.
    sphere_igs_file_content = SphereIGS()

    with open("sphere_cad_file.igs", "w") as f:
        f.write(sphere_igs_file_content)

    sys.stdout = open(os.devnull, "w")

    ndim = 3
    scale = 1000.
    condition = 1.e020

    mesh = Mesh()
    material = LinearElastic(ndim, mu=1., lamb=4.)
    # Keep the solver iterative for low memory consumption. All boundary points are Dirichlet BCs
    # so they will be exact anyway
    solver = LinearSolver(linear_solver="iterative",
                          linear_solver_type="cg2",
                          dont_switch_solver=True,
                          iterative_solver_tolerance=1e-9)

    for it in range(niter):

        if it == 0:
            mesh.Parallelepiped(element_type="hex",
                                nx=1,
                                ny=1,
                                nz=1,
                                lower_left_rear_point=(-0.5, -0.5, -0.5),
                                upper_right_front_point=(0.5, 0.5, 0.5))
        mesh.GetHighOrderMesh(p=ps[it], equally_spaced=True)

        boundary_condition = BoundaryCondition()
        boundary_condition.SetCADProjectionParameters(
            "sphere_cad_file.igs",
            scale=scale,
            condition=condition,
            project_on_curves=True,
            solve_for_planar_faces=True,
            modify_linear_mesh_on_projection=True,
            fix_dof_elsewhere=False)
        boundary_condition.GetProjectionCriteria(mesh)

        formulation = DisplacementFormulation(mesh)
        fem_solver = FEMSolver(number_of_load_increments=1,
                               analysis_nature="linear",
                               force_not_computing_mesh_qualities=True,
                               report_log_level=0,
                               optimise=True)

        solution = fem_solver.Solve(formulation=formulation,
                                    mesh=mesh,
                                    material=material,
                                    boundary_condition=boundary_condition,
                                    solver=solver)

        mesh.points += solution.sol[:, :, -1]
        mesh = mesh.ConvertToLinearMesh()

    os.remove("sphere_cad_file.igs")

    if not np.isclose(radius, 1):
        mesh.points *= radius

    mesh.points[:, 0] += center[0]
    mesh.points[:, 1] += center[1]
    mesh.points[:, 2] += center[2]

    if element_type == "tet":
        mesh.ConvertHexesToTets()

    sys.stdout = sys.__stdout__

    return mesh
Example #8
0
def QuadBallSurface(center=(0., 0., 0.), radius=1., n=10, element_type="quad"):
    """Creates a surface quad mesh on sphere using midpoint subdivision algorithm
        by creating a cube and spherifying it using PostMesh's projection schemes.
        Unlike the volume QuadBall method there is no restriction on number of divisions
        here as no system of equations is solved

        inputs:

            n:                          [int] number of divsion in every direction.
                                        Given that this implementation is based on
                                        high order bases different divisions in
                                        different directions is not possible
    """

    try:
        from Florence import Mesh, BoundaryCondition, DisplacementFormulation, FEMSolver, LinearSolver
        from Florence import LinearElastic, NeoHookean
        from Florence.Tensor import prime_number_factorisation
    except ImportError:
        raise ImportError("This function needs Florence's core support")

    n = int(n)
    if not isinstance(center, tuple):
        raise ValueError(
            "The center of the circle should be given in a tuple with two elements (x,y,z)"
        )
    if len(center) != 3:
        raise ValueError(
            "The center of the circle should be given in a tuple with two elements (x,y,z)"
        )

    if n == 2 or n == 3 or n == 5 or n == 7:
        ps = [n]
    else:

        def factorise_all(n):
            if n < 2:
                n = 2
            factors = prime_number_factorisation(n)
            if len(factors) == 1 and n > 2:
                n += 1
                factors = prime_number_factorisation(n)
            return factors

        factors = factorise_all(n)
        ps = []
        for factor in factors:
            ps += factorise_all(factor)

    # Do high ps first
    ps = np.sort(ps)[::-1].tolist()
    niter = len(ps)

    sphere_igs_file_content = SphereIGS()
    with open("sphere_cad_file.igs", "w") as f:
        f.write(sphere_igs_file_content)

    sys.stdout = open(os.devnull, "w")

    ndim = 3
    scale = 1000.
    condition = 1.e020

    mesh = Mesh()
    material = LinearElastic(ndim, mu=1., lamb=4.)

    for it in range(niter):

        if it == 0:
            mesh.Parallelepiped(element_type="hex",
                                nx=1,
                                ny=1,
                                nz=1,
                                lower_left_rear_point=(-0.5, -0.5, -0.5),
                                upper_right_front_point=(0.5, 0.5, 0.5))
            mesh = mesh.CreateSurface2DMeshfrom3DMesh()
            mesh.GetHighOrderMesh(p=ps[it], equally_spaced=True)
            mesh = mesh.CreateDummy3DMeshfrom2DMesh()
            formulation = DisplacementFormulation(mesh)
        else:
            mesh.GetHighOrderMesh(p=ps[it], equally_spaced=True)
            mesh = mesh.CreateDummy3DMeshfrom2DMesh()

        boundary_condition = BoundaryCondition()
        boundary_condition.SetCADProjectionParameters(
            "sphere_cad_file.igs",
            scale=scale,
            condition=condition,
            project_on_curves=True,
            solve_for_planar_faces=True,
            modify_linear_mesh_on_projection=True,
            fix_dof_elsewhere=False)
        boundary_condition.GetProjectionCriteria(mesh)
        nodesDBC, Dirichlet = boundary_condition.PostMeshWrapper(
            formulation, mesh, None, None, FEMSolver())

        mesh.points[nodesDBC.ravel(), :] += Dirichlet
        mesh = mesh.CreateSurface2DMeshfrom3DMesh()
        mesh = mesh.ConvertToLinearMesh()

    os.remove("sphere_cad_file.igs")

    if not np.isclose(radius, 1):
        mesh.points *= radius

    mesh.points[:, 0] += center[0]
    mesh.points[:, 1] += center[1]
    mesh.points[:, 2] += center[2]

    if element_type == "tri":
        mesh.ConvertQuadsToTris()

    sys.stdout = sys.__stdout__

    return mesh
Example #9
0
def HarvesterPatch(ndisc=20, nradial=4, show_plot=False):
    """Creates a custom mesh for an energy harvester patch. [Not to be modified]
        ndisc:              [int] number of discretisation in c
        ndradial:           [int] number of discretisation in radial directions for different
                            components of harevester
    """

    center = np.array([30.6979, 20.5])
    p1 = np.array([30., 20.])
    p2 = np.array([30., 21.])
    p1line = p1 - center
    p2line = p2 - center
    radius = np.linalg.norm(p1line)
    pp = np.array([center[0], center[1] + radius])
    y_line = pp - center
    start_angle = -np.pi / 2. - np.arccos(
        np.linalg.norm(y_line * p1line) / np.linalg.norm(y_line) /
        np.linalg.norm(p1line))
    end_angle = np.pi / 2. + np.arccos(
        np.linalg.norm(y_line * p1line) / np.linalg.norm(y_line) /
        np.linalg.norm(p1line))
    points = np.array([p1, p2, center])

    # nradial = 4
    mesh = Mesh()
    mesh.Arc(element_type="quad",
             radius=radius,
             start_angle=start_angle,
             end_angle=end_angle,
             nrad=nradial,
             ncirc=ndisc,
             center=(center[0], center[1]),
             refinement=True)

    mesh1 = Mesh()
    mesh1.Triangle(element_type="quad",
                   npoints=nradial,
                   c1=totuple(center),
                   c2=totuple(p1),
                   c3=totuple(p2))

    mesh += mesh1

    mesh_patch = Mesh()
    mesh_patch.HollowArc(ncirc=ndisc,
                         nrad=nradial,
                         center=(-7.818181, 44.22727272),
                         start_angle=np.arctan(44.22727272 / -7.818181),
                         end_angle=np.arctan(-24.22727272 / 37.818181),
                         element_type="quad",
                         inner_radius=43.9129782,
                         outer_radius=44.9129782)

    mesh3 = Mesh()
    mesh3.Triangle(element_type="quad",
                   npoints=nradial,
                   c2=totuple(p1),
                   c3=totuple(p2),
                   c1=(mesh_patch.points[0, 0], mesh_patch.points[0, 1]))

    mesh += mesh3
    mesh += mesh_patch

    mesh.Extrude(nlong=ndisc, length=40)

    if show_plot:
        mesh.SimplePlot()

    return mesh
Example #10
0
def SubdivisionCircle(center=(0., 0.),
                      radius=1.,
                      nrad=16,
                      ncirc=40,
                      element_type="tri",
                      refinement=False,
                      refinement_level=2):
    """Creates a mesh on circle using midpoint subdivision.
        This function is internally called from Mesh.Circle if
        'midpoint_subdivision' algorithm is selected
    """

    r = float(radius)
    h_r = float(radius) / 2.
    nx = int(ncirc / 4.)
    ny = int(nrad / 2.)

    if nx < 3:
        warn("Number of division in circumferential direction too low")

    mesh = Mesh()
    mesh.Rectangle(element_type="quad",
                   lower_left_point=(-1., -1.),
                   upper_right_point=(1., 1.),
                   nx=nx,
                   ny=ny)

    uv = np.array([
        [-1., -1],
        [1., -1],
        [1., 1],
        [-1., 1],
    ])

    t = np.pi / 4
    end_points = np.array([
        [-h_r * np.cos(t), h_r * np.sin(t)],
        [h_r * np.cos(t), h_r * np.sin(t)],
        [r * np.cos(t), r * np.sin(t)],
        [-r * np.cos(t), r * np.sin(t)],
    ])

    edge_points = mesh.points[np.unique(mesh.edges), :]

    new_end_points = []
    new_end_points.append(end_points[0, :])
    new_end_points.append(end_points[1, :])
    new_end_points.append(end_points[2, :])

    tt = np.linspace(np.pi / 4, 3 * np.pi / 4, nx)
    x = r * np.cos(tt)
    y = r * np.sin(tt)
    interp_p = np.vstack((x, y)).T

    for i in range(1, len(x) - 1):
        new_end_points.append([x[i], y[i]])
    new_end_points.append(end_points[3, :])
    new_end_points = np.array(new_end_points)

    new_uv = []
    new_uv.append(uv[0, :])
    new_uv.append(uv[1, :])
    new_uv.append(uv[2, :])

    L = 0.
    for i in range(1, interp_p.shape[0]):
        L += np.linalg.norm(interp_p[i, :] - interp_p[i - 1, :])

    interp_uv = []
    last_uv = uv[2, :]
    for i in range(1, interp_p.shape[0] - 1):
        val = (uv[3, :] - uv[2, :]) * np.linalg.norm(
            interp_p[i, :] - interp_p[i - 1, :]) / L + last_uv
        last_uv = np.copy(val)
        interp_uv.append(val)
    interp_uv = np.array(interp_uv)

    new_uv = np.array(new_uv)
    if interp_uv.shape[0] != 0:
        new_uv = np.vstack((new_uv, interp_uv))
    new_uv = np.vstack((new_uv, uv[3, :]))

    from Florence.FunctionSpace import MeanValueCoordinateMapping
    new_points = np.zeros_like(mesh.points)
    for i in range(mesh.nnode):
        point = MeanValueCoordinateMapping(mesh.points[i, :], new_uv,
                                           new_end_points)
        new_points[i, :] = point
    mesh.points = new_points

    rmesh = deepcopy(mesh)
    rmesh.points = mesh.Rotate(angle=np.pi / 2., copy=True)
    mesh += rmesh
    rmesh.points = rmesh.Rotate(angle=np.pi / 2., copy=True)
    mesh += rmesh
    rmesh.points = rmesh.Rotate(angle=np.pi / 2., copy=True)
    mesh += rmesh

    mesh.LaplacianSmoothing(niter=10)
    qmesh = Mesh()
    qmesh.Rectangle(element_type="quad",
                    lower_left_point=(-h_r * np.cos(t), -h_r * np.sin(t)),
                    upper_right_point=(h_r * np.cos(t), h_r * np.sin(t)),
                    nx=nx,
                    ny=nx)
    mesh += qmesh

    mesh.LaplacianSmoothing(niter=20)

    mesh.points[:, 0] += center[0]
    mesh.points[:, 1] += center[1]

    if refinement:
        mesh.Refine(level=refinement_level)

    if element_type == "tri":
        sys.stdout = open(os.devnull, "w")
        mesh.ConvertQuadsToTris()
        sys.stdout = sys.__stdout__

    return mesh
Example #11
0
def SubdivisionArc(center=(0., 0.),
                   radius=1.,
                   nrad=16,
                   ncirc=40,
                   start_angle=0.,
                   end_angle=np.pi / 2.,
                   element_type="tri",
                   refinement=False,
                   refinement_level=2):
    """Creates a mesh on circle using midpoint subdivision.
        This function is internally called from Mesh.Circle if
        'midpoint_subdivision' algorithm is selected
    """

    if start_angle != 0. and end_angle != np.pi / 2.:
        raise ValueError(
            "Subdivision based arc only produces meshes for a quarter-circle arc for now"
        )

    r = float(radius)
    h_r = float(radius) / 2.
    nx = int(ncirc / 4.)
    ny = int(nrad / 2.)

    if nx < 3:
        warn("Number of division in circumferential direction too low")

    mesh = Mesh()
    mesh.Rectangle(element_type="quad",
                   lower_left_point=(-1., -1.),
                   upper_right_point=(1., 1.),
                   nx=nx,
                   ny=ny)

    uv = np.array([
        [-1., -1],
        [1., -1],
        [1., 1],
        [-1., 1],
    ])

    t = np.pi / 4.
    end_points = np.array([
        [0., h_r * np.sin(t)],
        [h_r * np.cos(t), h_r * np.sin(t)],
        [r * np.cos(t), r * np.sin(t)],
        [0., radius],
    ])

    edge_points = mesh.points[np.unique(mesh.edges), :]

    new_end_points = []
    new_end_points.append(end_points[0, :])
    new_end_points.append(end_points[1, :])
    new_end_points.append(end_points[2, :])

    tt = np.linspace(np.pi / 4, np.pi / 2, nx)
    x = r * np.cos(tt)
    y = r * np.sin(tt)
    interp_p = np.vstack((x, y)).T

    for i in range(1, len(x) - 1):
        new_end_points.append([x[i], y[i]])
    new_end_points.append(end_points[3, :])
    new_end_points = np.array(new_end_points)

    new_uv = []
    new_uv.append(uv[0, :])
    new_uv.append(uv[1, :])
    new_uv.append(uv[2, :])

    L = 0.
    for i in range(1, interp_p.shape[0]):
        L += np.linalg.norm(interp_p[i, :] - interp_p[i - 1, :])

    interp_uv = []
    last_uv = uv[2, :]
    for i in range(1, interp_p.shape[0] - 1):
        val = (uv[3, :] - uv[2, :]) * np.linalg.norm(
            interp_p[i, :] - interp_p[i - 1, :]) / L + last_uv
        last_uv = np.copy(val)
        interp_uv.append(val)
    interp_uv = np.array(interp_uv)

    new_uv = np.array(new_uv)
    if interp_uv.shape[0] != 0:
        new_uv = np.vstack((new_uv, interp_uv))
    new_uv = np.vstack((new_uv, uv[3, :]))

    from Florence.FunctionSpace import MeanValueCoordinateMapping
    new_points = np.zeros_like(mesh.points)
    # All nodes barring the ones lying on the arc
    for i in range(mesh.nnode - nx - 1):
        point = MeanValueCoordinateMapping(mesh.points[i, :], new_uv,
                                           new_end_points)
        new_points[i, :] = point
    # The nodes on the arc are not exactly on the arc
    # so they need to be snapped/clipped
    tt = np.linspace(np.pi / 4, np.pi / 2, nx + 1)[::-1]
    x = r * np.cos(tt)
    y = r * np.sin(tt)
    new_points[mesh.nnode - nx - 1:, :] = np.vstack((x, y)).T
    mesh.points = new_points

    rmesh = deepcopy(mesh)
    rmesh.points = mesh.Rotate(angle=-np.pi / 2., copy=True)
    rmesh.points[:, 1] *= -1.
    mesh += rmesh

    mesh.LaplacianSmoothing(niter=10)
    qmesh = Mesh()
    qmesh.Rectangle(element_type="quad",
                    lower_left_point=(0.0, 0.0),
                    upper_right_point=(h_r * np.cos(t), h_r * np.sin(t)),
                    nx=nx,
                    ny=nx)
    mesh += qmesh

    # mesh.LaplacianSmoothing(niter=20)
    NodeSliderSmootherArc(mesh, niter=20)

    mesh.points[:, 0] += center[0]
    mesh.points[:, 1] += center[1]

    if refinement:
        mesh.Refine(level=refinement_level)

    if element_type == "tri":
        sys.stdout = open(os.devnull, "w")
        mesh.ConvertQuadsToTris()
        sys.stdout = sys.__stdout__

    return mesh
Example #12
0
    def StaticSolver(self, function_spaces, formulation, solver, K,
                     NeumannForces, NodalForces, Residual, mesh, TotalDisp,
                     Eulerx, Eulerp, material, boundary_condition):

        LoadIncrement = self.number_of_load_increments
        LoadFactor = 1. / LoadIncrement
        AppliedDirichletInc = np.zeros(
            boundary_condition.applied_dirichlet.shape[0], dtype=np.float64)

        for Increment in range(LoadIncrement):

            # CHECK ADAPTIVE LOAD FACTOR
            if self.load_factor is not None:
                LoadFactor = self.load_factor[Increment]

            # APPLY NEUMANN BOUNDARY CONDITIONS
            DeltaF = LoadFactor * NeumannForces
            NodalForces += DeltaF
            # OBRTAIN INCREMENTAL RESIDUAL - CONTRIBUTION FROM BOTH NEUMANN AND DIRICHLET
            Residual = -boundary_condition.ApplyDirichletGetReducedMatrices(
                K,
                Residual,
                boundary_condition.applied_dirichlet,
                LoadFactor=LoadFactor,
                only_residual=True)
            Residual -= DeltaF
            # GET THE INCREMENTAL DISPLACEMENT
            AppliedDirichletInc = LoadFactor * boundary_condition.applied_dirichlet

            t_increment = time()

            # LET NORM OF THE FIRST RESIDUAL BE THE NORM WITH RESPECT TO WHICH WE
            # HAVE TO CHECK THE CONVERGENCE OF NEWTON RAPHSON. TYPICALLY THIS IS
            # NORM OF NODAL FORCES
            if Increment == 0:
                self.NormForces = np.linalg.norm(Residual)
                # AVOID DIVISION BY ZERO
                if np.isclose(self.NormForces, 0.0):
                    self.NormForces = 1e-14

            self.norm_residual = np.linalg.norm(Residual) / self.NormForces

            if self.iterative_technique == "newton_raphson":
                Eulerx, Eulerp, K, Residual = self.NewtonRaphson(
                    function_spaces, formulation, solver, Increment, K,
                    NodalForces, Residual, mesh, Eulerx, Eulerp, material,
                    boundary_condition, AppliedDirichletInc)
            elif self.iterative_technique == "modified_newton_raphson":
                Eulerx, Eulerp, K, Residual = self.ModifiedNewtonRaphson(
                    function_spaces, formulation, solver, Increment, K,
                    NodalForces, Residual, mesh, Eulerx, Eulerp, material,
                    boundary_condition, AppliedDirichletInc)

            # UPDATE DISPLACEMENTS FOR THE CURRENT LOAD INCREMENT
            TotalDisp[:, Increment] = Eulerp

            # PRINT LOG IF ASKED FOR
            if self.print_incremental_log:
                dmesh = Mesh()
                dmesh.points = TotalDisp[:, :formulation.ndim, Increment]
                dmesh_bounds = dmesh.Bounds
                if formulation.fields == "electro_mechanics":
                    _bounds = np.zeros((2, formulation.nvar))
                    _bounds[:, :formulation.ndim] = dmesh_bounds
                    _bounds[:, -1] = [
                        TotalDisp[:, -1, Increment].min(),
                        TotalDisp[:, -1, Increment].max()
                    ]
                    print(
                        "\nMinimum and maximum incremental solution values at increment {} are \n"
                        .format(Increment), _bounds)
                else:
                    print(
                        "\nMinimum and maximum incremental solution values at increment {} are \n"
                        .format(Increment), dmesh_bounds)

            # SAVE INCREMENTAL SOLUTION IF ASKED FOR
            if self.save_incremental_solution:
                from scipy.io import savemat
                if self.incremental_solution_filename is not None:
                    savemat(self.incremental_solution_filename + "_" +
                            str(Increment),
                            {'solution': TotalDisp[:, :, Increment]},
                            do_compression=True)
                else:
                    raise ValueError(
                        "No file name provided to save incremental solution")

            print('\nFinished Load increment', Increment, 'in',
                  time() - t_increment, 'seconds')
            try:
                print(
                    'Norm of Residual is',
                    np.abs(
                        la.norm(Residual[boundary_condition.columns_in]) /
                        self.NormForces), '\n')
            except RuntimeWarning:
                print(
                    "Invalid value encountered in norm of Newton-Raphson residual"
                )

            # STORE THE INFORMATION IF NEWTON-RAPHSON FAILS
            if self.newton_raphson_failed_to_converge:
                solver.condA = np.NAN
                if Increment == 0:
                    TotalDisp = TotalDisp.ravel()
                else:
                    TotalDisp = TotalDisp[:, :Increment]
                self.number_of_load_increments = Increment
                break

            # BREAK AT A SPECIFICED LOAD INCREMENT IF ASKED FOR
            if self.break_at_increment != -1 and self.break_at_increment is not None:
                if self.break_at_increment == Increment:
                    if self.break_at_increment < LoadIncrement - 1:
                        print("\nStopping at increment {} as specified\n\n".
                              format(Increment))
                        TotalDisp = TotalDisp[:, :, :Increment]
                        self.number_of_load_increments = Increment
                    break

        # print(TotalDisp.shape)
        return TotalDisp
Example #13
0
def test_BEM():
    """Unnecessary test for the ugly and non-working and legacy BEM
        for the sake of coverage
    """


    from Florence.BoundaryElements import GetBasesBEM2D
    from Florence.BoundaryElements import GenerateCoordinates
    from Florence.BoundaryElements import CoordsJacobianRadiusatGaussPoints, CoordsJacobianRadiusatGaussPoints_LM
    from Florence.BoundaryElements import AssemblyBEM2D
    from Florence.BoundaryElements.Assembly import AssemblyBEM2D_Sparse
    from Florence.BoundaryElements import Sort_BEM
    from Florence import QuadratureRule, FunctionSpace, Mesh

    # Unnecessary loop
    for i in range(10):

        mesh = Mesh()
        mesh.element_type = "line"
        mesh.points = np.array([
            [0.,0.],
            [1.,0.],
            [1.,1.],
            [0.,1.],
            ])
        mesh.elements = np.array([
            [0,1],
            [1,2],
            [2,3],
            [3,0],
            ])
        mesh.nelem = 4



        q = QuadratureRule(mesh_type="line")
        for C in range(10):
            N, dN = GetBasesBEM2D(C,q.points)

        N, dN = GetBasesBEM2D(2,q.points)
        global_coord = np.zeros((mesh.points.shape[0],3))
        global_coord[:,:2] = mesh.points
        Jacobian = 2*np.ones((q.weights.shape[0],mesh.nelem))
        nx = 4*np.ones((q.weights.shape[0],mesh.nelem))
        ny = 3*np.ones((q.weights.shape[0],mesh.nelem))
        XCO = 2*np.ones((q.weights.shape[0],mesh.nelem))
        YCO = np.ones((q.weights.shape[0],mesh.nelem))
        N = np.ones((mesh.elements.shape[1],q.weights.shape[0]))
        dN = 0.5*np.ones((mesh.elements.shape[1],q.weights.shape[0]))
        
        GenerateCoordinates(mesh.elements,mesh.points,0,q.points)
        CoordsJacobianRadiusatGaussPoints(mesh.elements,global_coord,0,N,dN,q.weights)
        # Not working
        # CoordsJacobianRadiusatGaussPoints_LM(mesh.elements,global_coord[:,:3],0,N,dN,q.weights,mesh.elements)

        class GeoArgs(object):
            Lagrange_Multipliers = "activated"
            def __init__(self):
                Lagrange_Multipliers = "activated"

        geo_args = GeoArgs()
        K1, K2 = AssemblyBEM2D(0,global_coord,mesh.elements,mesh.elements,dN,N,
            q.weights,q.points,Jacobian, nx, ny, XCO, YCO, geo_args)
        AssemblyBEM2D_Sparse(0,global_coord,mesh.elements,mesh.elements,dN,N,
            q.weights,q.points,Jacobian, nx, ny, XCO, YCO, geo_args)

        bdata = np.zeros((2*mesh.points.shape[0],2))
        bdata[:4,1] = -1
        bdata[4:,0] = -1
        Sort_BEM(bdata,K1, K2)
Example #14
0
        E1 = [1.,0.,0.]
        E2 = [0.,1.,0.]
        E3 = [0.,0.,1.]

        # MAKE A SINGLE INSTANCE OF MATERIAL AND UPDATE IF NECESSARY
        import Florence.MaterialLibrary
        pmaterial_func = getattr(Florence.MaterialLibrary,material.mtype,None)
        pmaterial_dict = deepcopy(material.__dict__)
        del pmaterial_dict['ndim'], pmaterial_dict['mtype']
        pmaterial = pmaterial_func(2,**pmaterial_dict)


        print("The problem requires 2D analyses. Solving", number_of_planar_surfaces, "2D problems")
        for niter in range(number_of_planar_surfaces):

            pmesh = Mesh()
            if mesh.element_type == "tet":
                pmesh.element_type = "tri"
                no_face_vertices = 3
            elif mesh.element_type == "hex":
                pmesh.element_type = "quad"
                no_face_vertices = 4
            else:
                raise ValueError("Curvilinear mesher for element type {} not yet implemented".format(mesh.element_type))

            pmesh.elements = mesh.faces[planar_mesh_faces[planar_mesh_faces[:,1]==surface_flags[niter,0],0],:]
            pmesh.nelem = np.int64(surface_flags[niter,1])
            pmesh.GetBoundaryEdges()
            unique_edges = np.unique(pmesh.edges).astype(nodesDBC.dtype)
            # Dirichlet2D = np.zeros((unique_edges.shape[0],3))
            # nodesDBC2D = np.zeros(unique_edges.shape[0]).astype(np.int64)
def StaticSolverDisplacementControl(self, function_spaces, formulation, solver,
                                    K, NeumannForces, NodalForces, Residual,
                                    mesh, TotalDisp, Eulerx, Eulerp, material,
                                    boundary_condition):

    LoadIncrement = self.number_of_load_increments
    self.accumulated_load_factor = 0.0
    AppliedDirichletInc = np.zeros(
        boundary_condition.applied_dirichlet.shape[0], dtype=np.float64)

    # GET TOTAL FORCE
    TotalForce = np.copy(NeumannForces)
    # TotalForce = boundary_condition.ApplyDirichletGetReducedMatrices(K,TotalForce,
    # boundary_condition.applied_dirichlet,LoadFactor=1.0,only_residual=True)

    # self.max_prescribed_displacement = np.max(np.abs(boundary_condition.applied_dirichlet))
    self.max_prescribed_displacement = 20.
    self.incremental_displacement = self.max_prescribed_displacement / self.number_of_load_increments
    # print(self.incremental_displacement)
    # exit()

    for Increment in range(LoadIncrement):

        # CHECK ADAPTIVE LOAD FACTOR
        # if self.load_factor is not None:
        #     self.local_load_factor = self.load_factor[Increment]
        # else:
        # if Increment <= 1:
        #     self.local_load_factor = 1./LoadIncrement
        # else:

        #         # GET THE REDUCED SYSTEM OF EQUATIONS
        #         K_b, F_bb = boundary_condition.GetReducedMatrices(K,TotalForce)[:2]
        #         # SOLVE THE SYSTEM
        #         sol_b = solver.Solve(K_b,F_bb)
        #         # GET ITERATIVE SOLUTION
        #         dU_b = boundary_condition.UpdateFreeDoFs(sol_b,K.shape[0],formulation.nvar)

        #         # max_occured_displacement = np.max(np.abs((TotalDisp[:,:,Increment-1] - TotalDisp[:,:,Increment-2])))
        #         max_occured_displacement = np.max(np.abs(dU_b))
        #         self.local_load_factor = max_occured_displacement/self.max_prescribed_displacement
        #         # print(self.local_load_factor)
        #         # exit()
        # self.accumulated_load_factor += self.local_load_factor
        # # print(self.accumulated_load_factor)

        # GET THE REDUCED SYSTEM OF EQUATIONS
        K_b, F_bb = boundary_condition.GetReducedMatrices(K, TotalForce)[:2]
        # SOLVE THE SYSTEM
        sol_b = solver.Solve(K_b, F_bb)
        # GET ITERATIVE SOLUTION
        dU_b = boundary_condition.UpdateFreeDoFs(sol_b, K.shape[0],
                                                 formulation.nvar)

        max_occured_displacement = np.max(np.abs(dU_b))
        self.local_load_factor = self.incremental_displacement / max_occured_displacement
        if self.local_load_factor > 1.0:
            raise ValueError("Raise max displacements")
        # print(self.local_load_factor,max_occured_displacement)
        # exit()

        self.accumulated_load_factor += self.local_load_factor
        # print(self.accumulated_load_factor)

        # APPLY NEUMANN BOUNDARY CONDITIONS
        DeltaF = self.local_load_factor * NeumannForces
        NodalForces += DeltaF
        # OBRTAIN INCREMENTAL RESIDUAL - CONTRIBUTION FROM BOTH NEUMANN AND DIRICHLET
        Residual = -boundary_condition.ApplyDirichletGetReducedMatrices(
            K,
            Residual,
            boundary_condition.applied_dirichlet,
            LoadFactor=self.local_load_factor,
            only_residual=True)
        Residual -= DeltaF
        # GET THE INCREMENTAL DISPLACEMENT
        AppliedDirichletInc = self.local_load_factor * boundary_condition.applied_dirichlet

        t_increment = time()

        # LET NORM OF THE FIRST RESIDUAL BE THE NORM WITH RESPECT TO WHICH WE
        # HAVE TO CHECK THE CONVERGENCE OF NEWTON RAPHSON. TYPICALLY THIS IS
        # NORM OF NODAL FORCES
        if Increment == 0:
            self.NormForces = np.linalg.norm(Residual)
            # AVOID DIVISION BY ZERO
            if np.isclose(self.NormForces, 0.0):
                self.NormForces = 1e-14

        self.norm_residual = np.linalg.norm(Residual) / self.NormForces

        Eulerx, Eulerp, K, Residual = NewtonRaphsonDisplacementControl(
            self, function_spaces, formulation, solver, Increment, K,
            NodalForces, Residual, mesh, Eulerx, Eulerp, material,
            boundary_condition, AppliedDirichletInc, NeumannForces, TotalForce,
            TotalDisp)

        # UPDATE DISPLACEMENTS FOR THE CURRENT LOAD INCREMENT
        TotalDisp[:, :formulation.ndim, Increment] = Eulerx - mesh.points
        if formulation.fields == "electro_mechanics":
            TotalDisp[:, -1, Increment] = Eulerp

        # PRINT LOG IF ASKED FOR
        if self.print_incremental_log:
            dmesh = Mesh()
            dmesh.points = TotalDisp[:, :formulation.ndim, Increment]
            dmesh_bounds = dmesh.Bounds
            if formulation.fields == "electro_mechanics":
                _bounds = np.zeros((2, formulation.nvar))
                _bounds[:, :formulation.ndim] = dmesh_bounds
                _bounds[:, -1] = [
                    TotalDisp[:, -1, Increment].min(),
                    TotalDisp[:, -1, Increment].max()
                ]
                print(
                    "\nMinimum and maximum incremental solution values at increment {} are \n"
                    .format(Increment), _bounds)
            else:
                print(
                    "\nMinimum and maximum incremental solution values at increment {} are \n"
                    .format(Increment), dmesh_bounds)

        # SAVE INCREMENTAL SOLUTION IF ASKED FOR
        if self.save_incremental_solution:
            from scipy.io import savemat
            if self.incremental_solution_filename is not None:
                savemat(self.incremental_solution_filename + "_" +
                        str(Increment),
                        {'solution': TotalDisp[:, :, Increment]},
                        do_compression=True)
            else:
                raise ValueError(
                    "No file name provided to save incremental solution")

        print('\nFinished Load increment', Increment, 'in',
              time() - t_increment, 'seconds')
        try:
            print(
                'Norm of Residual is',
                np.abs(
                    la.norm(Residual[boundary_condition.columns_in]) /
                    self.NormForces), '\n')
        except RuntimeWarning:
            print(
                "Invalid value encountered in norm of Newton-Raphson residual")

        # STORE THE INFORMATION IF NEWTON-RAPHSON FAILS
        if self.newton_raphson_failed_to_converge:
            solver.condA = np.NAN
            TotalDisp = TotalDisp[:, :, :Increment]
            self.number_of_load_increments = Increment
            break

        # BREAK AT A SPECIFICED LOAD INCREMENT IF ASKED FOR
        if self.break_at_increment != -1 and self.break_at_increment is not None:
            if self.break_at_increment == Increment:
                if self.break_at_increment < LoadIncrement - 1:
                    print("\nStopping at increment {} as specified\n\n".format(
                        Increment))
                    TotalDisp = TotalDisp[:, :, :Increment]
                break

    return TotalDisp