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")
    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
예제 #3
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
예제 #4
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
예제 #5
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
예제 #6
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
예제 #7
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)
예제 #8
0
            # counter = 0
            # for i in unique_edges:
            #     nodesDBC2D[counter] = np.where(nodesDBC==i)[0][0]
            #     Dirichlet2D[counter,:] = Dirichlet[nodesDBC2D[counter],:]
            #     counter += 1
            # nodesDBC2D = nodesDBC2D.astype(np.int64)

            # temp_dict = []
            # for i in nodesDBC[nodesDBC2D].flatten():
            #     temp_dict.append(np.where(unique_elements==i)[0][0])
            # nodesDBC2D = np.array(temp_dict,copy=False)
            dirichlet_edges = in2d_unsorted(nodesDBC,unique_edges[:,None]).flatten()
            nodesDBC2D = in2d_unsorted(unique_elements.astype(nodesDBC.dtype)[:,None],nodesDBC[dirichlet_edges]).flatten()
            Dirichlet2D = Dirichlet[dirichlet_edges,:]

            pmesh.points = mesh.points[unique_elements,:]

            one_element_coord = pmesh.points[pmesh.elements[0,:no_face_vertices],:]

            # FOR COORDINATE TRANSFORMATION
            AB = one_element_coord[0,:] - one_element_coord[1,:]
            AC = one_element_coord[0,:] - one_element_coord[2,:]

            normal = np.cross(AB,AC)
            unit_normal = normal/np.linalg.norm(normal)

            e1 = AB/np.linalg.norm(AB)
            e2 = np.cross(normal,AB)/np.linalg.norm(np.cross(normal,AB))
            e3 = unit_normal

            # TRANSFORMATION MATRIX
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