boundary_condition.GetDirichletBoundaryConditions(formulation, mesh, material, solver, self)

        # ALLOCATE FOR GEOMETRY - GetDirichletBoundaryConditions CHANGES THE MESH
        # SO EULERX SHOULD BE ALLOCATED AFTERWARDS
        Eulerx = np.copy(mesh.points)
        Eulerp = np.zeros((mesh.points.shape[0]))

        # FIND PURE NEUMANN (EXTERNAL) NODAL FORCE VECTOR
<<<<<<< HEAD
        NeumannForces = boundary_condition.ComputeNeumannForces(mesh, material)
=======
        NeumannForces = boundary_condition.ComputeNeumannForces(mesh, material, function_spaces)
>>>>>>> upstream/master

        # ASSEMBLE STIFFNESS MATRIX AND TRACTION FORCES
        K, TractionForces = Assemble(self, function_spaces[0], formulation, mesh, material,
            Eulerx, Eulerp)[:2]

        print('Finished all pre-processing stage. Time elapsed was', time()-tAssembly, 'seconds')

<<<<<<< HEAD
        self.StaggeredSolver(function_spaces, formulation, solver,
=======
        TotalDisp = self.StaggeredSolver(function_spaces, formulation, solver,
>>>>>>> upstream/master
                K,NeumannForces,NodalForces,Residual,
                mesh,TotalDisp,Eulerx,Eulerp,material, boundary_condition)


        return self.__makeoutput__(mesh, TotalDisp, formulation, function_spaces, material)

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

        Tolerance = fem_solver.newton_raphson_tolerance
        LoadIncrement = fem_solver.number_of_load_increments
        LoadFactor = fem_solver.total_time/fem_solver.number_of_load_increments
        Iter = 0

        # EulerxPrev = np.copy(Eulerx)
        # EulerVPrev = np.copy(velocities[:,:,Increment-1])
        # EulerAPrev = np.copy(accelerations[:,:,Increment-1])

        # PREDICTOR STEP
        tmpV = (1. - self.gamma/self.beta)*velocities + (1. - self.gamma/2./self.beta)*LoadFactor*accelerations
        tmpA = (-1./self.beta/LoadFactor)*velocities - (1./2./self.beta)*(1.- 2.*self.beta)*accelerations
        velocities    = tmpV
        accelerations = tmpA

        if formulation.fields == "electro_mechanics":
            M_mech = M[self.mechanical_dofs,:][:,self.mechanical_dofs]
            InertiaResidual = np.zeros((Residual.shape[0],1))
            InertiaResidual[self.mechanical_dofs,0] = M_mech.dot(accelerations.ravel())
            if fem_solver.include_physical_damping:
                D_mech = D[self.mechanical_dofs,:][:,self.mechanical_dofs]
                InertiaResidual[self.mechanical_dofs,0] += D_mech.dot(velocities.ravel())
        else:
            InertiaResidual = np.zeros((Residual.shape[0],1))
            InertiaResidual[:,0] = M.dot(accelerations.ravel())
            if fem_solver.include_physical_damping:
                InertiaResidual[:,0] += D.dot(velocities.ravel())
        Residual[boundary_condition.columns_in] += InertiaResidual[boundary_condition.columns_in]


        # APPLY INCREMENTAL DIRICHLET PER LOAD STEP (THIS IS INCREMENTAL NOT ACCUMULATIVE)
        IncDirichlet = boundary_condition.UpdateFixDoFs(AppliedDirichletInc,
            K.shape[0],formulation.nvar)
        # UPDATE EULERIAN COORDINATE
        Eulerx += IncDirichlet[:,:formulation.ndim]
        Eulerp[:] = IncDirichlet[:,-1] # ENSURES Eulerp IS CONTIGUOUS - NECESSARY FOR LOW-LEVEL DISPATCHER


        while np.abs(la.norm(Residual[boundary_condition.columns_in])/self.NormForces) > Tolerance or Iter==0:

            # GET EFFECTIVE STIFFNESS
            # K += (1./self.beta/LoadFactor**2)*M
            K += (self.gamma/self.beta/LoadFactor)*D + (1./self.beta/LoadFactor**2)*M
            # GET THE REDUCED SYSTEM OF EQUATIONS
            K_b, F_b, _ = boundary_condition.GetReducedMatrices(K,Residual)

            # SOLVE THE SYSTEM
            sol = solver.Solve(K_b,-F_b)

            # GET ITERATIVE SOLUTION
            dU = boundary_condition.UpdateFreeDoFs(sol,K.shape[0],formulation.nvar)

            # UPDATE THE EULERIAN COMPONENTS
            # UPDATE THE GEOMETRY
            Eulerx += dU[:,:formulation.ndim]
            # GET ITERATIVE ELECTRIC POTENTIAL
            Eulerp += dU[:,-1]

            # UPDATE VELOCITY AND ACCELERATION
            velocities    += self.gamma/self.beta/LoadFactor*dU[:,:formulation.ndim]
            accelerations += 1./self.beta/LoadFactor**2*dU[:,:formulation.ndim]

            # OR ALTERNATIVELY
            # dumA = 1./self.beta/LoadFactor**2*(Eulerx - EulerxPrev) -\
            #     1./self.beta/LoadFactor*(EulerVPrev) -\
            #     1./2./self.beta*(1. - 2.*self.beta)*(EulerAPrev)
            # dumV = (1. - self.gamma/self.beta)*(EulerVPrev) +\
            #     (1. - self.gamma/2./self.beta)*LoadFactor*(EulerAPrev) +\
            #     self.gamma/self.beta/LoadFactor*(Eulerx - EulerxPrev)
            # velocities    = dumV
            # accelerations = dumA

            # RE-ASSEMBLE - COMPUTE STIFFNESS AND INTERNAL TRACTION FORCES
            K, TractionForces, _, _ = Assemble(fem_solver,function_spaces[0], formulation, mesh, material,
                Eulerx, Eulerp)

            # FIND INITIAL RESIDUAL
            if formulation.fields == "electro_mechanics":
                InertiaResidual = np.zeros((TractionForces.shape[0],1))
                InertiaResidual[self.mechanical_dofs,0] = M_mech.dot(accelerations.ravel())
                if fem_solver.include_physical_damping:
                    InertiaResidual[self.mechanical_dofs,0] += D_mech.dot(velocities.ravel())
            else:
                InertiaResidual = np.zeros((TractionForces.shape[0],1))
                InertiaResidual[:,0] = M.dot(accelerations.ravel())
                if fem_solver.include_physical_damping:
                    InertiaResidual[:,0] += D.dot(velocities.ravel())


            # UPDATE RESIDUAL
            Residual[boundary_condition.columns_in] = TractionForces[boundary_condition.columns_in] \
            - NodalForces[boundary_condition.columns_in] + InertiaResidual[boundary_condition.columns_in]


            # SAVE THE NORM
            self.rel_norm_residual = la.norm(Residual[boundary_condition.columns_in])
            if Iter==0:
                self.NormForces = la.norm(Residual[boundary_condition.columns_in])
            self.norm_residual = np.abs(la.norm(Residual[boundary_condition.columns_in])/self.NormForces)

            # SAVE THE NORM
            self.NRConvergence['Increment_'+str(Increment)] = np.append(self.NRConvergence['Increment_'+str(Increment)],\
                self.norm_residual)

            print("Iteration {} for increment {}.".format(Iter, Increment) +\
                " Residual (abs) {0:>16.7g}".format(self.rel_norm_residual),
                "\t Residual (rel) {0:>16.7g}".format(self.norm_residual))

            # BREAK BASED ON RELATIVE NORM
            if np.abs(self.rel_norm_residual) < Tolerance:
                break

            # BREAK BASED ON INCREMENTAL SOLUTION - KEEP IT AFTER UPDATE
            if norm(dU) <=  fem_solver.newton_raphson_solution_tolerance:
                print("Incremental solution within tolerance i.e. norm(dU): {}".format(norm(dU)))
                break

            # UPDATE ITERATION NUMBER
            Iter +=1

            if Iter==fem_solver.maximum_iteration_for_newton_raphson and formulation.fields == "electro_mechanics":
                raise StopIteration("\n\nNewton Raphson did not converge! Maximum number of iterations reached.")

            if Iter==fem_solver.maximum_iteration_for_newton_raphson:
                fem_solver.newton_raphson_failed_to_converge = True
                break

            if np.isnan(self.norm_residual) or self.norm_residual>1e06:
                fem_solver.newton_raphson_failed_to_converge = True
                break

            # USER DEFINED CRITERIA TO BREAK OUT OF NEWTON-RAPHSON
            if fem_solver.user_defined_break_func != None:
                if fem_solver.user_defined_break_func(Increment,Iter,self.norm_residual,self.rel_norm_residual, Tolerance):
                    break

            # USER DEFINED CRITERIA TO STOP NEWTON-RAPHSON AND THE WHOLE ANALYSIS
            if fem_solver.user_defined_stop_func != None:
                if fem_solver.user_defined_stop_func(Increment,Iter,self.norm_residual,self.rel_norm_residual, Tolerance):
                    fem_solver.newton_raphson_failed_to_converge = True
                    break

        return Eulerx, Eulerp, K, Residual, velocities, accelerations
Exemple #3
0
    def Solve(self,
              formulation=None,
              mesh=None,
              material=None,
              boundary_condition=None,
              function_spaces=None,
              solver=None,
              Eulerx=None,
              Eulerp=None):
        """Main solution routine for LaplacianSolver """

        # CHECK FOR ATTRIBUTE FOR LOWLEVEL ASSEMBLY
        if material.nature == "linear" and material.has_low_level_dispatcher and self.has_low_level_dispatcher:
            if hasattr(material, 'e'):
                if material.e is None or isinstance(material.e, float):
                    if material.mtype == "IdealDielectric":
                        material.e = material.eps_1 * np.eye(
                            formulation.ndim, formulation.ndim)
                    else:
                        raise ValueError(
                            "For optimise=True, you need to provide the material permittivity tensor (ndimxndim)"
                        )
            else:
                raise ValueError(
                    "For optimise=True, you need to provide the material permittivity tensor (ndimxndim)"
                )

        # INITIATE DATA FOR THE ANALYSIS
        NodalForces, Residual = np.zeros((mesh.points.shape[0]*formulation.nvar,1),dtype=np.float64), \
            np.zeros((mesh.points.shape[0]*formulation.nvar,1),dtype=np.float64)
        # SET NON-LINEAR PARAMETERS
        self.NRConvergence = {
            'Increment_' + str(Increment): []
            for Increment in range(self.number_of_load_increments)
        }

        # ALLOCATE FOR SOLUTION FIELDS
        if self.save_frequency == 1:
            # TotalDisp = np.zeros((mesh.points.shape[0],self.number_of_load_increments),dtype=np.float32)
            TotalDisp = np.zeros(
                (mesh.points.shape[0], self.number_of_load_increments),
                dtype=np.float64)
        else:
            TotalDisp = np.zeros(
                (mesh.points.shape[0],
                 int(self.number_of_load_increments / self.save_frequency)),
                dtype=np.float64)

        # PRE-ASSEMBLY
        print(
            'Assembling the system and acquiring neccessary information for the analysis...'
        )
        tAssembly = time()

        # APPLY DIRICHELT BOUNDARY CONDITIONS AND GET DIRICHLET RELATED FORCES
        boundary_condition.GetDirichletBoundaryConditions(
            formulation, mesh, material, solver, self)

        # ALLOCATE FOR GEOMETRY - GetDirichletBoundaryConditions CHANGES THE MESH
        # SO EULERX SHOULD BE ALLOCATED AFTERWARDS
        if Eulerx is None:
            Eulerx = np.copy(mesh.points)
        if Eulerp is None:
            Eulerp = np.zeros((mesh.points.shape[0]))

        # FIND PURE NEUMANN (EXTERNAL) NODAL FORCE VECTOR
        NeumannForces = boundary_condition.ComputeNeumannForces(
            mesh,
            material,
            function_spaces,
            compute_traction_forces=True,
            compute_body_forces=self.add_self_weight)

        # ASSEMBLE STIFFNESS MATRIX AND TRACTION FORCES FOR THE FIRST TIME
        if self.analysis_type == "static":
            K, TractionForces, _, _ = Assemble(self, function_spaces[0],
                                               formulation, mesh, material,
                                               Eulerx, Eulerp)
        else:
            pass

        if self.analysis_nature == 'nonlinear':
            print('Finished all pre-processing stage. Time elapsed was',
                  time() - tAssembly, 'seconds')
        else:
            print('Finished the assembly stage. Time elapsed was',
                  time() - tAssembly, 'seconds')

        if self.analysis_type != 'static':
            pass
        else:
            if self.iterative_technique == "newton_raphson" or self.iterative_technique == "modified_newton_raphson":
                TotalDisp = self.StaticSolver(function_spaces, formulation,
                                              solver, K, NeumannForces,
                                              NodalForces, Residual, mesh,
                                              TotalDisp, Eulerx, Eulerp,
                                              material, boundary_condition)

        return self.__makeoutput__(mesh, TotalDisp, formulation,
                                   function_spaces, material)
Exemple #4
0
    def ModifiedNewtonRaphson(self, function_spaces, formulation, solver,
                              Increment, K, NodalForces, Residual, mesh,
                              Eulerx, Eulerp, material, boundary_condition,
                              AppliedDirichletInc):

        from Florence.FiniteElements.Assembly import AssembleInternalTractionForces

        Tolerance = self.newton_raphson_tolerance
        LoadIncrement = self.number_of_load_increments
        Iter = 0

        # APPLY INCREMENTAL DIRICHLET PER LOAD STEP (THIS IS INCREMENTAL NOT ACCUMULATIVE)
        IncDirichlet = boundary_condition.UpdateFixDoFs(
            AppliedDirichletInc, K.shape[0], formulation.nvar)
        # UPDATE EULERIAN COORDINATE
        Eulerx += IncDirichlet[:, :formulation.ndim]
        Eulerp += IncDirichlet[:, -1]

        # ASSEMBLE STIFFNESS PER TIME STEP
        K, TractionForces = Assemble(self, function_spaces[0], formulation,
                                     mesh, material, Eulerx, Eulerp)[:2]

        while self.norm_residual > Tolerance or Iter == 0:
            # GET THE REDUCED SYSTEM OF EQUATIONS
            K_b, F_b = boundary_condition.GetReducedMatrices(K, Residual)[:2]

            # SOLVE THE SYSTEM
            sol = solver.Solve(K_b, -F_b)

            # GET ITERATIVE SOLUTION
            dU = boundary_condition.UpdateFreeDoFs(sol, K.shape[0],
                                                   formulation.nvar)

            # UPDATE THE EULERIAN COMPONENTS
            # UPDATE THE GEOMETRY
            Eulerx += dU[:, :formulation.ndim]
            # GET ITERATIVE ELECTRIC POTENTIAL
            Eulerp += dU[:, -1]

            # RE-ASSEMBLE - COMPUTE INTERNAL TRACTION FORCES
            TractionForces = AssembleInternalTractionForces(
                self, function_spaces[0], formulation, mesh, material, Eulerx,
                Eulerp)

            # FIND THE RESIDUAL
            Residual[boundary_condition.columns_in] = TractionForces[boundary_condition.columns_in] -\
                NodalForces[boundary_condition.columns_in]

            # SAVE THE NORM
            self.rel_norm_residual = la.norm(
                Residual[boundary_condition.columns_in])
            if Iter == 0:
                self.NormForces = la.norm(
                    Residual[boundary_condition.columns_in])
            self.norm_residual = np.abs(
                la.norm(Residual[boundary_condition.columns_in]) /
                self.NormForces)

            # SAVE THE NORM
            self.NRConvergence['Increment_'+str(Increment)] = np.append(self.NRConvergence['Increment_'+str(Increment)],\
                self.norm_residual)

            print("Iteration {} for increment {}.".format(Iter, Increment) +\
                " Residual (abs) {0:>16.7g}".format(self.rel_norm_residual),
                "\t Residual (rel) {0:>16.7g}".format(self.norm_residual))

            # BREAK BASED ON RELATIVE NORM
            if np.abs(self.rel_norm_residual) < Tolerance:
                break

            # BREAK BASED ON INCREMENTAL SOLUTION - KEEP IT AFTER UPDATE
            if norm(dU) <= self.newton_raphson_solution_tolerance:
                print(
                    "Incremental solution within tolerance i.e. norm(dU): {}".
                    format(norm(dU)))
                break

            # UPDATE ITERATION NUMBER
            Iter += 1

            if Iter == self.maximum_iteration_for_newton_raphson and formulation.fields == "electro_mechanics":
                # raise StopIteration("\n\nNewton Raphson did not converge! Maximum number of iterations reached.")
                warn(
                    "\n\nNewton Raphson did not converge! Maximum number of iterations reached."
                )
                self.newton_raphson_failed_to_converge = True
                break

            if Iter == self.maximum_iteration_for_newton_raphson:
                self.newton_raphson_failed_to_converge = True
                break
            if np.isnan(self.norm_residual) or self.norm_residual > 1e06:
                self.newton_raphson_failed_to_converge = True
                break

            # USER DEFINED CRITERIA TO BREAK OUT OF NEWTON-RAPHSON
            if self.user_defined_break_func != None:
                if self.user_defined_break_func(Increment, Iter,
                                                self.norm_residual,
                                                self.rel_norm_residual,
                                                Tolerance):
                    break

            # USER DEFINED CRITERIA TO STOP NEWTON-RAPHSON AND THE WHOLE ANALYSIS
            if self.user_defined_stop_func != None:
                if self.user_defined_stop_func(Increment, Iter,
                                               self.norm_residual,
                                               self.rel_norm_residual,
                                               Tolerance):
                    self.newton_raphson_failed_to_converge = True
                    break

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

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

        # GET BOUNDARY CONDITIONS INFO FOR EACH INDIVIDUAL PROBLEM
        self.GetBoundaryInfo(K, boundary_condition, formulation)

        # SOLVE THE FIRST MECHANICAL PROBLEM
        nodal_forces_mech = np.zeros((self.mechanical_dofs.shape[0], 1))
        residual_mech_neumann = -LoadFactor * NeumannForces[
            self.mechanical_dofs, :]
        residual_mech = residual_mech_neumann - self.ApplyDirichlet(
            K[self.mechanical_dofs, :][:, self.mechanical_dofs],
            nodal_forces_mech,
            self.mech_out,
            self.mech_in,
            self.applied_dirichlet_mech,
            LoadFactor=LoadFactor)

        dUm = self.SolveMechanics(mesh,
                                  formulation,
                                  solver,
                                  K,
                                  residual_mech,
                                  LoadFactor,
                                  initial_solution=True)

        # INITIATE TRANSMITTIVE FORCES
        self.force_up = np.zeros(formulation.ndim * mesh.points.shape[0])
        self.force_pu = np.zeros(mesh.points.shape[0])

        # INITIATE ELECTRIC NODAL FORCES AND RESIDUAL
        nodal_forces_electric = NodalForces[self.electric_dofs]

        for Increment in range(LoadIncrement):

            t_increment = time()

            # UPDATE FIXED DOFs FOR ELECTROSTATICS
            DeltaF_electric = LoadFactor * NeumannForces[self.electric_dofs]
            nodal_forces_electric += DeltaF_electric
            residual_electric = -self.ApplyDirichlet(
                K[self.electric_dofs, :][:, self.electric_dofs],
                nodal_forces_electric, self.electric_out, self.electric_in,
                self.applied_dirichlet_electric, LoadFactor)

            # COMPUTE FORCE TO BE TRANSMITTED TO ELECTROSTATIC
            K_pu = K[self.electric_dofs, :][:, self.mechanical_dofs]
            self.force_pu = K_pu.dot(dUm.flatten())

            # STORE PREVIOUS ELECTRIC POTENTIAL AT THIS INCREMENT
            Eulerp_n = np.copy(Eulerp)
            # APPLY INCREMENTAL POTENTIAL FOR FIXED POTENTIAL DoFs
            applied_dirichlet_electric_inc = LoadFactor * self.applied_dirichlet_electric
            Eulerp[self.electric_out] += applied_dirichlet_electric_inc

            # GET ONLY NORM OF FIXED DOFs (THAT IS WHERE RESIDUAL FORCES GET GENERATED)
            if Increment == 0:
                self.NormForces = la.norm(residual_electric)
            # AVOID DIVISION BY ZERO
            if np.abs(self.NormForces) < 1e-14:
                self.NormForces = 1e-14

            Ke = deepcopy(K)

            residual_mech_from_elec = np.zeros(
                (self.mechanical_dofs.shape[0], 1))
            # DeltaF_mech = LoadFactor*NeumannForces[self.mechanical_dofs]
            # nodal_forces_mech += DeltaF_mech

            Iter = 0
            # ENTER NEWTON-RAPHSON FOR ELECTROSTATICS
            while np.abs(
                    la.norm(residual_electric[self.electric_in]) /
                    self.NormForces) > Tolerance:

                # SOLVE ELECTROSTATIC PROBLEM ITERATIVELY
                dUe = self.SolveElectrostatics(Ke, residual_electric,
                                               formulation, solver, Iter)

                # UPDATE EULERIAN POTENTIAL - GET ITERATIVE ELECTRIC POTENTIAL
                Eulerp += dUe

                # RE-ASSEMBLE - COMPUTE INTERNAL TRACTION FORCES FOR ELECTROSTATICS
                Ke, TractionForces = Assemble(self, function_spaces[0],
                                              formulation, mesh, material,
                                              Eulerx, Eulerp)[:2]

                # FIND THE ITERATIVE RESIDUAL
                residual_electric[self.electric_in] = TractionForces[
                    self.columns_in_electric] - nodal_forces_electric[
                        self.electric_in]

                # traction_forces_mech += TractionForces[self.mechanical_dofs]
                residual_mech_from_elec += TractionForces[
                    self.mechanical_dofs] - nodal_forces_mech

                self.NRConvergence['Increment_'+str(Increment)] = np.append(self.NRConvergence['Increment_'+str(Increment)],\
                    np.abs(la.norm(residual_electric[self.electric_in])/self.NormForces))

                print('Iteration number', Iter, 'for load increment', Increment, 'with a residual of \t\t', \
                    np.abs(la.norm(residual_electric[self.electric_in])/self.NormForces))

                # UPDATE ITERATION NUMBER
                Iter += 1

                if Iter == self.maximum_iteration_for_newton_raphson or self.NRConvergence[
                        'Increment_' + str(Increment)][-1] > 500:
                    self.newton_raphson_failed_to_converge = True
                    break
                if np.isnan(
                        np.abs(
                            la.norm(residual_electric[self.electric_in]) /
                            self.NormForces)):
                    self.newton_raphson_failed_to_converge = True
                    break

            if self.newton_raphson_failed_to_converge:
                print(
                    "Solver blew up! Norm of incremental solution is too large"
                )
                solver.condA = np.NAN
                Increment = Increment if Increment != 0 else 1
                TotalDisp = TotalDisp[:, :, :Increment]
                self.number_of_load_increments = Increment
                return TotalDisp

            # COMPUTE FORCE TO BE TRANSMITTED TO MECHANICS
            K_up = Ke[self.mechanical_dofs, :][:, self.electric_dofs]
            dUe = Eulerp - Eulerp_n
            self.force_up = K_up.dot(dUe)
            # self.force_up = K_up.dot(dUe[:,None])
            # print(self.force_up)

            # if Increment>0:
            # nodal_forces_mech = np.zeros_like(nodal_forces_mech)
            # residual_mech = residual_mech_neumann - self.ApplyDirichlet(K[self.mechanical_dofs,:][:,self.mechanical_dofs],
            # nodal_forces_mech, self.mech_out, self.mech_in, self.applied_dirichlet_mech, LoadFactor=LoadFactor)

            nodal_forces_mech = np.zeros_like(nodal_forces_mech)
            residual_mech = residual_mech_from_elec + residual_mech_neumann - \
                self.ApplyDirichlet(K[self.mechanical_dofs,:][:,self.mechanical_dofs],
                nodal_forces_mech, self.mech_out, self.mech_in, self.applied_dirichlet_mech, LoadFactor=LoadFactor)

            # SOLVE MECHANICS PROBLEM WITH OLD GEOMETRY (K), AND THE FORCE self.force_up AS A RESIDUAL
            dUm = self.SolveMechanics(mesh,
                                      formulation,
                                      solver,
                                      K,
                                      residual_mech,
                                      LoadFactor,
                                      initial_solution=False)
            # dUm = self.SolveMechanics(mesh, formulation, solver, K, traction_forces_mech, LoadFactor, initial_solution=False)
            # UPDATE GEOMETRY INCREMENTALLY
            Eulerx += dUm

            # UPDATE SOLUTION FOR THE CURRENT LOAD INCREMENT
            TotalDisp[:, :formulation.ndim, Increment] = Eulerx - mesh.points
            TotalDisp[:, -1, Increment] = Eulerp

            K = Assemble(self, function_spaces[0], formulation, mesh, material,
                         Eulerx, Eulerp)[0]

            # LOG REULTS
            self.LogSave(formulation, TotalDisp, Increment)

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

            # 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

        return TotalDisp
    def Solve(self,
              formulation=None,
              mesh=None,
              material=None,
              boundary_condition=None,
              function_spaces=None,
              solver=None):
        """Main solution routine for FEMSolver """

        # CHECK DATA CONSISTENCY
        #---------------------------------------------------------------------------#
        function_spaces, solver = self.__checkdata__(material,
                                                     boundary_condition,
                                                     formulation, mesh,
                                                     function_spaces, solver)
        #---------------------------------------------------------------------------#
        caller = inspect.getouterframes(inspect.currentframe(), 2)[1][3]
        if caller != "Solve":
            self.PrintPreAnalysisInfo(mesh, formulation)
        #---------------------------------------------------------------------------#

        # INITIATE DATA FOR NON-LINEAR ANALYSIS
        NodalForces, Residual = np.zeros((mesh.points.shape[0]*formulation.nvar,1),dtype=np.float64), \
            np.zeros((mesh.points.shape[0]*formulation.nvar,1),dtype=np.float64)
        # SET NON-LINEAR PARAMETERS
        self.NRConvergence = {
            'Increment_' + str(Increment): []
            for Increment in range(self.number_of_load_increments)
        }

        # ALLOCATE FOR SOLUTION FIELDS
        TotalDisp = np.zeros((mesh.points.shape[0], formulation.nvar,
                              self.number_of_load_increments),
                             dtype=np.float64)

        # PRE-ASSEMBLY
        print(
            'Assembling the system and acquiring neccessary information for the analysis...'
        )
        tAssembly = time()

        # APPLY DIRICHELT BOUNDARY CONDITIONS AND GET DIRICHLET RELATED FORCES
        boundary_condition.GetDirichletBoundaryConditions(
            formulation, mesh, material, solver, self)

        # ALLOCATE FOR GEOMETRY - GetDirichletBoundaryConditions CHANGES THE MESH
        # SO EULERX SHOULD BE ALLOCATED AFTERWARDS
        Eulerx = np.copy(mesh.points)
        Eulerp = np.zeros((mesh.points.shape[0]))

        # FIND PURE NEUMANN (EXTERNAL) NODAL FORCE VECTOR
        NeumannForces = boundary_condition.ComputeNeumannForces(
            mesh, material, function_spaces)

        # ASSEMBLE STIFFNESS MATRIX AND TRACTION FORCES
        K, TractionForces = Assemble(self, function_spaces[0], formulation,
                                     mesh, material, Eulerx, Eulerp)[:2]

        print('Finished all pre-processing stage. Time elapsed was',
              time() - tAssembly, 'seconds')

        TotalDisp = self.StaggeredSolver(function_spaces, formulation, solver,
                                         K, NeumannForces, NodalForces,
                                         Residual, mesh, TotalDisp, Eulerx,
                                         Eulerp, material, boundary_condition)

        return self.__makeoutput__(mesh, TotalDisp, formulation,
                                   function_spaces, material)
Exemple #7
0
        Eulerp = np.zeros((formulation.meshes[0].points.shape[0]))

        # FIND PURE NEUMANN (EXTERNAL) NODAL FORCE VECTOR
        NeumannForces = boundary_condition.ComputeNeumannForces(mesh, material, function_spaces,
            compute_traction_forces=True, compute_body_forces=self.add_self_weight)
        # NeumannForces = np.zeros((mesh.points.shape[0]*formulation.ndim))

        # ASSEMBLE STIFFNESS MATRIX AND TRACTION FORCES
        if self.analysis_type != 'static':
            if formulation.fields == "couple_stress" or formulation.fields == "flexoelectric":
                K, TractionForces, _, M = formulation.Assemble(self, material, Eulerx, Eulerw, Eulers, Eulerp)
            elif formulation.fields == "mechanics" or formulation.fields == "electro_mechanics":
                # STANDARD MECHANINCS ELECTROMECHANICS DYNAMIC ANALYSIS ARE DISPATCHED HERE
                from Florence.FiniteElements.Assembly import Assemble
                fspace = function_spaces[0] if (mesh.element_type=="hex" or mesh.element_type=="quad") else function_spaces[1]
                K, TractionForces, _, M = Assemble(self, fspace, formulation, mesh, material,
                    Eulerx, Eulerp)
        else:
            K, TractionForces = formulation.Assemble(self, material, Eulerx, Eulerw, Eulers, Eulerp)[:2]

        print('Finished all pre-processing stage. Time elapsed was', time()-tAssembly, 'seconds')

        if self.analysis_type != 'static':
<<<<<<< HEAD

=======
            boundary_condition.ConvertStaticsToDynamics(mesh, self.number_of_load_increments)
>>>>>>> upstream/master
            TotalDisp, TotalW, TotalS = self.DynamicSolver(formulation, solver,
                K, M, NeumannForces, NodalForces, Residual,
                mesh, TotalDisp, TotalW, TotalS, Eulerx, Eulerw, Eulers, Eulerp, material, boundary_condition)
        else:
Exemple #8
0
def NewtonRaphsonArchLength(self, function_spaces, formulation, solver,
                            Increment, K, NodalForces, Residual, mesh, Eulerx,
                            Eulerp, material, boundary_condition,
                            AppliedDirichletInc, NeumannForces, TotalDisp):

    Tolerance = self.newton_raphson_tolerance
    LoadIncrement = self.number_of_load_increments
    Iter = 0

    # APPLY INCREMENTAL DIRICHLET PER LOAD STEP (THIS IS INCREMENTAL NOT ACCUMULATIVE)
    IncDirichlet = boundary_condition.UpdateFixDoFs(AppliedDirichletInc,
                                                    K.shape[0],
                                                    formulation.nvar)

    # UPDATE EULERIAN COORDINATE
    Eulerx += IncDirichlet[:, :formulation.ndim]
    Eulerp += IncDirichlet[:, -1]

    # Predictor
    if Increment == 0:
        # GET THE REDUCED SYSTEM OF EQUATIONS
        # K_b, F_b = boundary_condition.GetReducedMatrices(K,self.accumulated_load_factor*NeumannForces)[:2]
        K_b, F_b = boundary_condition.GetReducedMatrices(K, NeumannForces)[:2]
        # SOLVE THE SYSTEM
        sol = solver.Solve(K_b, F_b)
        # GET ITERATIVE SOLUTION
        dU = boundary_condition.UpdateFreeDoFs(sol, K.shape[0],
                                               formulation.nvar)
        # self.incremental_load_factor = 1./LoadIncrement
    else:
        dU = TotalDisp[:, :, Increment - 1] * self.arc_length_scaling_factor
        self.incremental_load_factor *= self.arc_length_scaling_factor
        self.accumulated_load_factor += self.incremental_load_factor

    # UPDATE THE EULERIAN COMPONENTS
    Eulerx += dU[:, :formulation.ndim]
    Eulerp += dU[:, -1]

    while self.norm_residual > Tolerance or Iter == 0:

        # GET THE REDUCED SYSTEM OF EQUATIONS
        K_b, F_b = boundary_condition.GetReducedMatrices(K, NeumannForces)[:2]
        # SOLVE THE SYSTEM
        sol = solver.Solve(K_b, F_b)
        # GET ITERATIVE SOLUTION
        dU1 = boundary_condition.UpdateFreeDoFs(sol, K.shape[0],
                                                formulation.nvar)

        # GET THE REDUCED SYSTEM OF EQUATIONS
        K_b, F_b = boundary_condition.GetReducedMatrices(K, Residual)[:2]
        # SOLVE THE SYSTEM
        sol = solver.Solve(K_b, -F_b)
        # GET ITERATIVE SOLUTION
        dU2 = boundary_condition.UpdateFreeDoFs(sol, K.shape[0],
                                                formulation.nvar)

        iterative_load_factor = -np.dot(dU.flatten(), dU2.flatten()) / np.dot(
            dU.flatten(), dU1.flatten())
        ddU = iterative_load_factor * dU1 + dU2
        # print(ddlam)
        # dU = dU2

        # UPDATE THE EULERIAN COMPONENTS
        self.incremental_load_factor += iterative_load_factor
        self.accumulated_load_factor += iterative_load_factor
        dU[:, :] += ddU[:, :]
        Eulerx += ddU[:, :formulation.ndim]
        Eulerp += ddU[:, -1]
        # Eulerx += dU[:,:formulation.ndim]
        # Eulerp += dU[:,-1]
        # print(self.accumulated_load_factor)

        # RE-ASSEMBLE - COMPUTE INTERNAL TRACTION FORCES
        K, TractionForces = Assemble(self, function_spaces[0], formulation,
                                     mesh, material, Eulerx, Eulerp)[:2]

        # FIND THE RESIDUAL
        # Residual[boundary_condition.columns_in] = TractionForces[boundary_condition.columns_in] -\
        #     NodalForces[boundary_condition.columns_in] - NeumannForces[boundary_condition.columns_in]*self.accumulated_load_factor
        Residual[boundary_condition.columns_in] = TractionForces[boundary_condition.columns_in] -\
            NeumannForces[boundary_condition.columns_in]*self.accumulated_load_factor

        # SAVE THE NORM
        self.rel_norm_residual = la.norm(
            Residual[boundary_condition.columns_in])
        if Iter == 0:
            self.NormForces = la.norm(Residual[boundary_condition.columns_in])
        self.norm_residual = np.abs(
            la.norm(Residual[boundary_condition.columns_in]) / self.NormForces)

        # SAVE THE NORM
        self.NRConvergence['Increment_'+str(Increment)] = np.append(self.NRConvergence['Increment_'+str(Increment)],\
            self.norm_residual)

        print("Iteration {} for increment {}.".format(Iter, Increment) +\
            " Residual (abs) {0:>16.7g}".format(self.rel_norm_residual),
            "\t Residual (rel) {0:>16.7g}".format(self.norm_residual))

        if np.abs(self.rel_norm_residual) < Tolerance:
            break

        # UPDATE ITERATION NUMBER
        Iter += 1

        self.arc_length_scaling_factor = 0.5**(0.25 * (Iter - 5))

        if Iter == self.maximum_iteration_for_newton_raphson and formulation.fields == "electro_mechanics":
            # raise StopIteration("\n\nNewton Raphson did not converge! Maximum number of iterations reached.")
            warn(
                "\n\nNewton Raphson did not converge! Maximum number of iterations reached."
            )
            self.newton_raphson_failed_to_converge = True
            break

        if Iter == self.maximum_iteration_for_newton_raphson:
            self.newton_raphson_failed_to_converge = True
            break
        if np.isnan(self.norm_residual) or self.norm_residual > 1e06:
            self.newton_raphson_failed_to_converge = True
            break

        # USER DEFINED CRITERIA TO BREAK OUT OF NEWTON-RAPHSON
        if self.user_defined_break_func != None:
            if self.user_defined_break_func(Increment, Iter,
                                            self.norm_residual,
                                            self.rel_norm_residual, Tolerance):
                break

        # USER DEFINED CRITERIA TO STOP NEWTON-RAPHSON AND THE WHOLE ANALYSIS
        if self.user_defined_stop_func != None:
            if self.user_defined_stop_func(Increment, Iter, self.norm_residual,
                                           self.rel_norm_residual, Tolerance):
                self.newton_raphson_failed_to_converge = True
                break

    return Eulerx, Eulerp, K, Residual


# def NewtonRaphsonArchLength(self, function_spaces, formulation, solver,
#     Increment, K, NodalForces, Residual, mesh, Eulerx, Eulerp, material,
#     boundary_condition, AppliedDirichletInc, DeltaF, TotalDisp):

#     Tolerance = self.newton_raphson_tolerance
#     LoadIncrement = self.number_of_load_increments
#     LoadFactor = 1./LoadIncrement
#     accumulated_load_factor = Increment/LoadIncrement
#     Iter = 0
#     dL = 1.
#     psi = 1.
#     # NodalForces = DeltaF

#     Dlam = 0.
#     dU = np.zeros((mesh.points.shape[0],formulation.nvar))
#     dU_b = np.zeros((mesh.points.shape[0],formulation.nvar))

#     # SOLVE WITH INCREMENTAL LOAD
#     K_b, DF_b = boundary_condition.GetReducedMatrices(K,NodalForces)[:2]
#     dU_t = solver.Solve(K_b,DF_b)
#     dU_t = boundary_condition.UpdateFreeDoFs(dU_t,K.shape[0],formulation.nvar)
#     # print(NodalForces)

#     # dU = IncDirichlet
#     # GET TOTAL ITERATIVE SOLUTION
#     # dU = dU_actual + LoadFactor*dU_current

#     # GET ARC LENGTH QUADRATIC EQUATIONS COEFFICIENTS
#     # c1 = np.dot(dU.ravel(),dU.ravel()) + psi**2 * np.dot(DeltaF.ravel(),DeltaF.ravel())
#     # c2 = 2.*np.dot(DU.ravel()+dU_actual.ravel(),dU_current.ravel()) + 2.*psi**2 * LoadFactor * np.dot(DeltaF.ravel(),DeltaF.ravel())
#     # c3 = np.dot((DU+dU_actual).ravel(),(DU+dU_actual).ravel()) + psi**2 * LoadFactor**2 * np.dot(DeltaF.ravel(),DeltaF.ravel()) - dL**2
#     # coeffs = [c1,c2,c3]

#     # c1 = np.dot(dU_t.ravel(),dU_t.ravel()) + psi**2 * np.dot(NodalForces.ravel(),NodalForces.ravel())
#     # c2 = 2.*np.dot(dU.ravel()+dU_b.ravel(),dU_t.ravel()) + 2.*psi**2 * Dlam * np.dot(NodalForces.ravel(),NodalForces.ravel())
#     # c3 = np.dot((dU+dU_b).ravel(),(dU+dU_b).ravel()) + psi**2 * Dlam**2 * np.dot(NodalForces.ravel(),NodalForces.ravel()) - dL**2
#     # coeffs = [c1,c2,c3]

#     # # FIND THE NEW LOAD FACTOR
#     # dlams = np.roots(coeffs)
#     # dlam = np.real(dlams.max())
#     # # print(c1,c2,c3,dlams, dlam)

#     # # CORRECTOR
#     # dU_iter = dU_b + dlam*dU_t
#     # # print (dU_iter)
#     # # exit()

#     # APPLY INCREMENTAL DIRICHLET PER LOAD STEP (THIS IS INCREMENTAL NOT ACCUMULATIVE)
#     IncDirichlet = boundary_condition.UpdateFixDoFs(AppliedDirichletInc,
#         K.shape[0],formulation.nvar)

#     # UPDATE EULERIAN COORDINATE
#     Eulerx += IncDirichlet[:,:formulation.ndim]
#     Eulerp += IncDirichlet[:,-1]
#     # Eulerx += IncDirichlet[:,:formulation.ndim] + dU_iter[:,:formulation.ndim]
#     # Eulerp += IncDirichlet[:,-1] + dU_iter[:,-1]

#     # accumulated_load_factor += dlam
#     # if Increment>0:
#     #     DU = TotalDisp[:,:,Increment] - TotalDisp[:,:,Increment-1]
#     # else:
#     #     DU = np.zeros((mesh.points.shape[0],formulation.nvar))

#     # DU = np.zeros((mesh.points.shape[0],formulation.nvar))

#     while self.norm_residual > Tolerance or Iter==0:
#         # GET THE REDUCED SYSTEM OF EQUATIONS
#         K_b, F_b = boundary_condition.GetReducedMatrices(K,Residual)[:2]
#         # SOLVE THE SYSTEM
#         sol = solver.Solve(K_b,-F_b)
#         # GET ITERATIVE SOLUTION
#         # dU_b = boundary_condition.UpdateFreeDoFs(sol,K.shape[0],formulation.nvar)
#         dU = boundary_condition.UpdateFreeDoFs(sol,K.shape[0],formulation.nvar)

#         # print(dlams)
#         # exit()
#         # LoadFactor += np.real(np.max(dlams))
#         # print(LoadFactor)

#         c1 = np.dot(dU_t.ravel(),dU_t.ravel()) + psi**2 * np.dot(NodalForces.ravel(),NodalForces.ravel())
#         c2 = 2.*np.dot(dU.ravel()+dU_b.ravel(),dU_t.ravel()) + 2.*psi**2 * Dlam * np.dot(NodalForces.ravel(),NodalForces.ravel())
#         c3 = np.dot((dU+dU_b).ravel(),(dU+dU_b).ravel()) + psi**2 * Dlam**2 * np.dot(NodalForces.ravel(),NodalForces.ravel()) - dL**2
#         coeffs = [c1,c2,c3]

#         # FIND THE NEW LOAD FACTOR
#         dlams = np.roots(coeffs)
#         dlam = np.real(dlams.max())
#         print(dlam)

#         # CORRECTOR
#         dU_iter = dU_b + dlam*dU_t
#         accumulated_load_factor += dlam

#         # UPDATE THE EULERIAN COMPONENTS
#         Eulerx += dU[:,:formulation.ndim]
#         Eulerp += dU[:,-1]
#         # Eulerx += dU_iter[:,:formulation.ndim]
#         # Eulerp += dU_iter[:,-1]

#         # RE-ASSEMBLE - COMPUTE INTERNAL TRACTION FORCES
#         K, TractionForces = Assemble(self, function_spaces[0], formulation, mesh, material,
#             Eulerx,Eulerp)[:2]

#         # FIND THE RESIDUAL
#         Residual[boundary_condition.columns_in] = TractionForces[boundary_condition.columns_in] -\
#             NodalForces[boundary_condition.columns_in]

#         # SAVE THE NORM
#         self.rel_norm_residual = la.norm(Residual[boundary_condition.columns_in])
#         if Iter==0:
#             self.NormForces = la.norm(Residual[boundary_condition.columns_in])
#         self.norm_residual = np.abs(la.norm(Residual[boundary_condition.columns_in])/self.NormForces)

#         # SAVE THE NORM
#         self.NRConvergence['Increment_'+str(Increment)] = np.append(self.NRConvergence['Increment_'+str(Increment)],\
#             self.norm_residual)

#         print("Iteration {} for increment {}.".format(Iter, Increment) +\
#             " Residual (abs) {0:>16.7g}".format(self.rel_norm_residual),
#             "\t Residual (rel) {0:>16.7g}".format(self.norm_residual))

#         if np.abs(self.rel_norm_residual) < Tolerance:
#             break

#         # UPDATE ITERATION NUMBER
#         Iter +=1

#         if Iter==self.maximum_iteration_for_newton_raphson and formulation.fields == "electro_mechanics":
#             # raise StopIteration("\n\nNewton Raphson did not converge! Maximum number of iterations reached.")
#             warn("\n\nNewton Raphson did not converge! Maximum number of iterations reached.")
#             self.newton_raphson_failed_to_converge = True
#             break

#         if Iter==self.maximum_iteration_for_newton_raphson:
#             self.newton_raphson_failed_to_converge = True
#             break
#         if np.isnan(self.norm_residual) or self.norm_residual>1e06:
#             self.newton_raphson_failed_to_converge = True
#             break

#         # USER DEFINED CRITERIA TO BREAK OUT OF NEWTON-RAPHSON
#         if self.user_defined_break_func != None:
#             if self.user_defined_break_func(Increment,Iter,self.norm_residual,self.rel_norm_residual, Tolerance):
#                 break

#         # USER DEFINED CRITERIA TO STOP NEWTON-RAPHSON AND THE WHOLE ANALYSIS
#         if self.user_defined_stop_func != None:
#             if self.user_defined_stop_func(Increment,Iter,self.norm_residual,self.rel_norm_residual, Tolerance):
#                 self.newton_raphson_failed_to_converge = True
#                 break

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

    Tolerance = self.newton_raphson_tolerance
    LoadIncrement = self.number_of_load_increments
    Iter = 0
    iterative_load_factor = 0.0

    # APPLY INCREMENTAL DIRICHLET PER LOAD STEP (THIS IS INCREMENTAL NOT ACCUMULATIVE)
    IncDirichlet = boundary_condition.UpdateFixDoFs(AppliedDirichletInc,
                                                    K.shape[0],
                                                    formulation.nvar)

    # UPDATE EULERIAN COORDINATE
    Eulerx += IncDirichlet[:, :formulation.ndim]
    Eulerp += IncDirichlet[:, -1]

    while self.norm_residual > Tolerance or Iter == 0:
        # GET THE REDUCED SYSTEM OF EQUATIONS
        K_b, F_b = boundary_condition.GetReducedMatrices(K, Residual)[:2]
        # SOLVE THE SYSTEM
        sol = solver.Solve(K_b, -F_b)
        # GET ITERATIVE SOLUTION
        dU = boundary_condition.UpdateFreeDoFs(sol, K.shape[0],
                                               formulation.nvar)

        # GET THE REDUCED SYSTEM OF EQUATIONS
        F_bb = boundary_condition.GetReducedMatrices(K, TotalForce)[1]
        # 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)

        # ratio = np.max(np.abs(dU))/np.max(np.abs(dU_b))
        # ratio = np.max(np.abs(dU))/self.max_prescribed_displacement
        max_occured_displacement = np.max(np.abs(dU_b))
        ratio = np.max(np.abs(dU)) / max_occured_displacement
        iterative_load_factor += ratio
        # self.local_load_factor += iterative_load_factor
        print(ratio)
        # print(iterative_load_factor)
        # print(self.local_load_factor)
        # print(self.accumulated_load_factor)

        # # GET THE REDUCED SYSTEM OF EQUATIONS
        # K_b, F_b = boundary_condition.GetReducedMatrices(K, Residual - ratio*TotalForce)[:2]
        # # SOLVE THE SYSTEM
        # sol = solver.Solve(K_b,-F_b)
        # # GET ITERATIVE SOLUTION
        # dU = boundary_condition.UpdateFreeDoFs(sol,K.shape[0],formulation.nvar)

        # # UPDATE THE EULERIAN COMPONENTS
        # Eulerx += dU[:,:formulation.ndim]
        # Eulerp += dU[:,-1]

        # UPDATE THE EULERIAN COMPONENTS
        Eulerx += dU[:, :formulation.ndim] + ratio * dU_b[:, :formulation.ndim]
        Eulerp += dU[:, -1] + ratio * dU_b[:, -1]

        # RE-ASSEMBLE - COMPUTE INTERNAL TRACTION FORCES
        K, TractionForces = Assemble(self, function_spaces[0], formulation,
                                     mesh, material, Eulerx, Eulerp)[:2]

        # FIND THE RESIDUAL
        Residual[boundary_condition.columns_in] = TractionForces[boundary_condition.columns_in] -\
            NodalForces[boundary_condition.columns_in] - ratio*TotalForce[boundary_condition.columns_in]

        # SAVE THE NORM
        self.rel_norm_residual = la.norm(
            Residual[boundary_condition.columns_in])
        if Iter == 0:
            self.NormForces = la.norm(Residual[boundary_condition.columns_in])
        self.norm_residual = np.abs(
            la.norm(Residual[boundary_condition.columns_in]) / self.NormForces)

        # SAVE THE NORM
        self.NRConvergence['Increment_'+str(Increment)] = np.append(self.NRConvergence['Increment_'+str(Increment)],\
            self.norm_residual)

        print("Iteration {} for increment {}.".format(Iter, Increment) +\
            " Residual (abs) {0:>16.7g}".format(self.rel_norm_residual),
            "\t Residual (rel) {0:>16.7g}".format(self.norm_residual))

        if np.abs(self.rel_norm_residual) < Tolerance:
            break

        # UPDATE ITERATION NUMBER
        Iter += 1

        if Iter == self.maximum_iteration_for_newton_raphson and formulation.fields == "electro_mechanics":
            # raise StopIteration("\n\nNewton Raphson did not converge! Maximum number of iterations reached.")
            warn(
                "\n\nNewton Raphson did not converge! Maximum number of iterations reached."
            )
            self.newton_raphson_failed_to_converge = True
            break

        if Iter == self.maximum_iteration_for_newton_raphson:
            self.newton_raphson_failed_to_converge = True
            break
        if np.isnan(self.norm_residual) or self.norm_residual > 1e06:
            self.newton_raphson_failed_to_converge = True
            break

        # USER DEFINED CRITERIA TO BREAK OUT OF NEWTON-RAPHSON
        if self.user_defined_break_func != None:
            if self.user_defined_break_func(Increment, Iter,
                                            self.norm_residual,
                                            self.rel_norm_residual, Tolerance):
                break

        # USER DEFINED CRITERIA TO STOP NEWTON-RAPHSON AND THE WHOLE ANALYSIS
        if self.user_defined_stop_func != None:
            if self.user_defined_stop_func(Increment, Iter, self.norm_residual,
                                           self.rel_norm_residual, Tolerance):
                self.newton_raphson_failed_to_converge = True
                break

        if self.accumulated_load_factor >= 1.0:
            print("Load factor: 1.0, Breaking")
            self.newton_raphson_failed_to_converge = True
            break

    self.local_load_factor += iterative_load_factor

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

        # CHECK FORMULATION
        if formulation.fields != "mechanics" and formulation.fields != "electro_mechanics":
            raise NotImplementedError("Linear implicit solver for {} is not available".format(formulation.fields))
        if formulation.fields == "electro_mechanics":
            warn("Linear implicit solver for electromechanics formulation is not thoroughly checked and may return incorrect results. "
                "Please use nonlinear explicit dynamic solver instead")

        # GET BOUNDARY CONDITIONS INFROMATION
        self.GetBoundaryInfo(mesh, formulation, boundary_condition)

        LoadIncrement = fem_solver.number_of_load_increments
        LoadFactor = fem_solver.total_time/LoadIncrement

        post_process = PostProcess(formulation.ndim,formulation.nvar)
        post_process.SetAnalysis(analysis_type=fem_solver.analysis_type, analysis_nature=fem_solver.analysis_nature)

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

        dU = boundary_condition.UpdateFixDoFs(boundary_condition.applied_dirichlet[:,0],
            mesh.points.shape[0]*formulation.nvar, formulation.nvar)
        TotalDisp[:,:formulation.nvar,0] = dU
        # INITIALISE VELOCITY AND ACCELERATION
        velocities     = np.zeros((mesh.points.shape[0]*formulation.ndim))
        accelerations  = np.zeros((mesh.points.shape[0]*formulation.ndim))
        # COMPUTE DAMPING MATRIX BASED ON MASS
        D = 0.0
        if fem_solver.include_physical_damping:
            D = fem_solver.damping_factor*M

        if formulation.fields == "electro_mechanics":
            M_mech = M[self.mechanical_dofs,:][:,self.mechanical_dofs]
            if fem_solver.include_physical_damping:
                D_mech = D[self.mechanical_dofs,:][:,self.mechanical_dofs]
        else:
            M_mech = M
            D_mech = D

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

        # COMPUTE AUGMENTED K (INCLUDES INERTIA EFFECT)
        K          += (self.gamma/self.beta/LoadFactor)*D + (1./self.beta/LoadFactor**2)*M
        # GET REDUCED VARIABLES
        K_b, F_b, _ = boundary_condition.GetReducedMatrices(K,Residual)

        if self.lump_rhs:
            M_mech = M_mech.sum(axis=1).A.ravel() # FOR CSR
            # M_mech = M_mech.sum(axis=0).ravel() # FOR CSC
            if self.include_physical_damping:
                D_mech = D_mech.sum(axis=1).A.ravel()

        reuse_factorisation = False if formulation.fields == "electro_mechanics" else True

        for Increment in range(1,LoadIncrement):
            t_increment=time()

            # FIXED INCREMENTAL DIRICHLET
            AppliedDirichletInc = boundary_condition.applied_dirichlet[:,Increment-1]

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

            # ACCUMULATED FORCE
            if fem_solver.include_physical_damping:
                if self.lump_rhs:
                    Residual[self.mechanical_dofs,0] = (1./self.beta/LoadFactor**2)*M_mech*TotalDisp[:,:formulation.ndim,Increment-1].ravel() +\
                        (1./self.beta/LoadFactor)*M_mech*velocities + (0.5/self.beta - 1.)*M_mech*accelerations +\
                        (self.gamma/self.beta/LoadFactor)*D_mech*TotalDisp[:,:formulation.ndim,Increment-1].ravel() +\
                        (self.gamma/self.beta - 1.)*D_mech*velocities -\
                        LoadFactor*((1-self.gamma)-self.gamma*(0.5/self.beta - 1.))*D_mech*accelerations
                else:
                    Residual[self.mechanical_dofs,0] = (1./self.beta/LoadFactor**2)*M_mech.dot(TotalDisp[:,:formulation.ndim,Increment-1].ravel()) +\
                        (1./self.beta/LoadFactor)*M_mech.dot(velocities) + (0.5/self.beta - 1.)*M_mech.dot(accelerations) +\
                        (self.gamma/self.beta/LoadFactor)*D_mech.dot(TotalDisp[:,:formulation.ndim,Increment-1].ravel()) +\
                        (self.gamma/self.beta - 1.)*D_mech.dot(velocities) -\
                        LoadFactor*((1-self.gamma)-self.gamma*(0.5/self.beta - 1.))*D_mech.dot(accelerations)
            else:
                if self.lump_rhs:
                    Residual[self.mechanical_dofs,0] = (1./self.beta/LoadFactor**2)*M_mech*TotalDisp[:,:formulation.ndim,Increment-1].ravel() +\
                        (1./self.beta/LoadFactor)*M_mech*velocities + (0.5/self.beta - 1.)*M_mech*accelerations
                else:
                    Residual[self.mechanical_dofs,0] = (1./self.beta/LoadFactor**2)*M_mech.dot(TotalDisp[:,:formulation.ndim,Increment-1].ravel()) +\
                        (1./self.beta/LoadFactor)*M_mech.dot(velocities) + (0.5/self.beta - 1.)*M_mech.dot(accelerations)
            Residual += DeltaF

            if formulation.fields == "electro_mechanics":
                K           = Assemble(fem_solver,function_spaces[0], formulation, mesh, material, Eulerx, Eulerp)[0]
                K          += (self.gamma/self.beta/LoadFactor)*D + (1./self.beta/LoadFactor**2)*M

            # CHECK CONTACT AND ASSEMBLE IF DETECTED
            if fem_solver.has_contact:
                Eulerx = mesh.points + TotalDisp[:,:formulation.ndim,Increment-1]
                TractionForcesContact = np.zeros_like(Residual)
                TractionForcesContact = fem_solver.contact_formulation.AssembleTractions(mesh,material,Eulerx).ravel()*LoadFactor

                if formulation.fields == "electro_mechanics" or formulation.fields == "flexoelectric":
                    Residual[self.mechanical_dofs,0] -= TractionForcesContact
                elif formulation.fields == "mechanics" or formulation.fields == "couple_stress":
                    Residual[:,0] -= TractionForcesContact
                else:
                    raise NotImplementedError("Contact algorithm for {} is not available".format(formulation.fields))

            # REDUCED ACCUMULATED FORCE
            if formulation.fields == "mechanics":
                F_b = boundary_condition.ApplyDirichletGetReducedMatrices(K,Residual,
                    boundary_condition.applied_dirichlet[:,Increment],LoadFactor=1.0,
                    mass=M,only_residual=True)[boundary_condition.columns_in,0]
            else:
                K_b, F_b = boundary_condition.ApplyDirichletGetReducedMatrices(K,Residual,
                    boundary_condition.applied_dirichlet[:,Increment],LoadFactor=1.0,
                    mass=M)[:2]

            # SOLVE THE SYSTEM
            sol = solver.Solve(K_b, F_b, reuse_factorisation=reuse_factorisation)

            dU = post_process.TotalComponentSol(sol, boundary_condition.columns_in,
                boundary_condition.columns_out, AppliedDirichletInc,0,K.shape[0])

            # STORE TOTAL SOLUTION DATA
            TotalDisp[:,:,Increment] += dU

            # UPDATE VELOCITY AND ACCELERATION
            accelerations_old = np.copy(accelerations)
            accelerations = (1./self.beta/LoadFactor**2)*(TotalDisp[:,:formulation.ndim,Increment] -\
                TotalDisp[:,:formulation.ndim,Increment-1]).ravel() -\
                1./self.beta/LoadFactor*velocities + (1.-0.5/self.beta)*accelerations_old
            velocities += LoadFactor*(self.gamma*accelerations + (1-self.gamma)*accelerations_old)

            # UPDATE
            Eulerx += dU[:,:formulation.ndim]
            Eulerp += dU[:,-1]

            # LOG REQUESTS
            fem_solver.LogSave(formulation, TotalDisp, Increment)

            # 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

            # STORE THE INFORMATION IF THE SOLVER BLOWS UP
            if Increment > 0:
                U0 = TotalDisp[:,:,Increment-1].ravel()
                U = TotalDisp[:,:,Increment].ravel()
                tol = 1e200 if Increment < 5 else 10.
                if np.isnan(norm(U)) or np.abs(U.max()/(U0.max()+1e-14)) > tol:
                    print("Solver blew up! Norm of incremental solution is too large")
                    TotalDisp = TotalDisp[:,:,:Increment]
                    fem_solver.number_of_load_increments = Increment
                    break

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

        solver.CleanUp()

        return TotalDisp
Exemple #11
0
    def Solve(self,
              formulation=None,
              mesh=None,
              material=None,
              boundary_condition=None,
              function_spaces=None,
              solver=None,
              contact_formulation=None):
        """Main solution routine for FEMSolver """

        # CHECK DATA CONSISTENCY
        mesh = formulation.meshes[0]
        #---------------------------------------------------------------------------#
        function_spaces, solver = self.__checkdata__(
            material,
            boundary_condition,
            formulation,
            mesh,
            function_spaces,
            solver,
            contact_formulation=contact_formulation)
        #---------------------------------------------------------------------------#
        caller = inspect.getouterframes(inspect.currentframe(), 2)[1][3]
        if caller != "Solve":
            self.PrintPreAnalysisInfo(mesh, formulation)
        #---------------------------------------------------------------------------#

        # INITIATE DATA FOR NON-LINEAR ANALYSIS
        NodalForces, Residual = np.zeros((mesh.points.shape[0]*formulation.nvar,1),dtype=np.float64), \
            np.zeros((mesh.points.shape[0]*formulation.nvar,1),dtype=np.float64)
        # SET NON-LINEAR PARAMETERS
        self.NRConvergence = {
            'Increment_' + str(Increment): []
            for Increment in range(self.number_of_load_increments)
        }

        # ALLOCATE FOR SOLUTION FIELDS
        TotalDisp = np.zeros((mesh.points.shape[0], formulation.nvar,
                              self.number_of_load_increments),
                             dtype=np.float64)
        TotalW = np.zeros((formulation.meshes[1].points.shape[0],
                           formulation.ndim, self.number_of_load_increments),
                          dtype=np.float64)
        TotalS = np.zeros((formulation.meshes[2].points.shape[0],
                           formulation.ndim, self.number_of_load_increments),
                          dtype=np.float64)
        # TotalDisp = np.zeros((mesh.points.shape[0],int(formulation.ndim**2),self.number_of_load_increments),dtype=np.float64)

        # PRE-ASSEMBLY
        if caller != "Solve":
            print(
                'Assembling the system and acquiring neccessary information for the analysis...'
            )
        tAssembly = time()

        # APPLY DIRICHELT BOUNDARY CONDITIONS AND GET DIRICHLET RELATED FORCES
        boundary_condition.GetDirichletBoundaryConditions(
            formulation, mesh, material, solver, self)

        # GET BOUNDARY INFO
        self.GetBoundaryInfo(mesh, formulation, boundary_condition)

        # ALLOCATE FOR GEOMETRY - GetDirichletBoundaryConditions CHANGES THE MESH
        # SO EULERX SHOULD BE ALLOCATED AFTERWARDS
        Eulerx = np.copy(formulation.meshes[0].points)
        Eulerw = np.zeros_like(formulation.meshes[1].points)
        Eulers = np.zeros_like(formulation.meshes[1].points)
        Eulerp = np.zeros((formulation.meshes[0].points.shape[0]))

        # FIND PURE NEUMANN (EXTERNAL) NODAL FORCE VECTOR
        NeumannForces = boundary_condition.ComputeNeumannForces(
            mesh,
            material,
            function_spaces,
            compute_traction_forces=True,
            compute_body_forces=self.add_self_weight)
        # NeumannForces = np.zeros((mesh.points.shape[0]*formulation.ndim))

        # ASSEMBLE STIFFNESS MATRIX AND TRACTION FORCES
        if self.analysis_type != 'static':
            if formulation.fields == "couple_stress" or formulation.fields == "flexoelectric":
                K, TractionForces, _, M = formulation.Assemble(
                    self, material, Eulerx, Eulerw, Eulers, Eulerp)
            elif formulation.fields == "mechanics" or formulation.fields == "electro_mechanics":
                # STANDARD MECHANINCS ELECTROMECHANICS DYNAMIC ANALYSIS ARE DISPATCHED HERE
                from Florence.FiniteElements.Assembly import Assemble
                fspace = function_spaces[0] if (
                    mesh.element_type == "hex"
                    or mesh.element_type == "quad") else function_spaces[1]
                K, TractionForces, _, M = Assemble(self, fspace, formulation,
                                                   mesh, material, Eulerx,
                                                   Eulerp)
        else:
            K, TractionForces = formulation.Assemble(self, material, Eulerx,
                                                     Eulerw, Eulers,
                                                     Eulerp)[:2]

        print('Finished all pre-processing stage. Time elapsed was',
              time() - tAssembly, 'seconds')

        if self.analysis_type != 'static':
            boundary_condition.ConvertStaticsToDynamics(
                mesh, self.number_of_load_increments)
            TotalDisp, TotalW, TotalS = self.DynamicSolver(
                formulation, solver, K, M, NeumannForces, NodalForces,
                Residual, mesh, TotalDisp, TotalW, TotalS, Eulerx, Eulerw,
                Eulers, Eulerp, material, boundary_condition)
        else:
            TotalDisp, TotalW, TotalS = self.StaticSolver(
                formulation, solver, K, NeumannForces, NodalForces, Residual,
                mesh, TotalDisp, TotalW, TotalS, Eulerx, Eulerw, Eulers,
                Eulerp, material, boundary_condition)

        solution = self.__makeoutput__(mesh, TotalDisp, formulation,
                                       function_spaces, material)
        if formulation.fields == "couple_stress" or formulation.fields == "flexoelectric":
            solution.solW = TotalW
            solution.solS = TotalS
        return solution