Exemple #1
0
 def setup_problem(self):
     """ Set the `fenics.NonlinearVariationalProblem`. """
     self.problem = fenics.NonlinearVariationalProblem( 
         self.governing_form, 
         self.state.solution, 
         self.fenics_bcs, 
         self.derivative_of_governing_form)
Exemple #2
0
    def setup_solver(self):
        """ Sometimes it is necessary to set up the solver again after breaking
        important references, e.g. after re-meshing.
        """
        self._governing_form = self.governing_form()

        self._boundary_conditions = self.boundary_conditions()

        self._problem = fenics.NonlinearVariationalProblem(
            F=self._governing_form,
            u=self.solution,
            bcs=self._boundary_conditions,
            J=fenics.derivative(form=self._governing_form, u=self.solution))

        save_parameters = False

        if hasattr(self, "solver"):

            save_parameters = True

        if save_parameters:

            solver_parameters = self.solver.parameters.copy()

        self.solver = fenics.NonlinearVariationalSolver(problem=self._problem)

        if save_parameters:

            self.solver.parameters = solver_parameters.copy()

        self._adaptive_goal = self.adaptive_goal()

        if self._adaptive_goal is not None:

            save_parameters = False

            if self.adaptive_solver is not None:

                save_parameters = True

            if save_parameters:

                adaptive_solver_parameters = self.adaptive_solver.parameters.copy(
                )

            self.adaptive_solver = fenics.AdaptiveNonlinearVariationalSolver(
                problem=self._problem, goal=self._adaptive_goal)

            if save_parameters:

                self.adaptive_solver.parameters = adaptive_solver_parameters.copy(
                )

        self.solver_needs_setup = False
Exemple #3
0
    def setup_solver(self):
        F = self.d_LHS - self.d_RHS
        J = fe.derivative(F, self._sp.w)

        # Initialize solver
        problem = fe.NonlinearVariationalProblem(F,
                                                 self._sp.w,
                                                 bcs=self.bcs,
                                                 J=J)
        self.solver = fe.NonlinearVariationalSolver(problem)
        self.solver.parameters['newton_solver']['relative_tolerance'] = 1e-6
Exemple #4
0
    def solve_problem_weak_form(self):
        u = fa.Function(self.V)
        du = fa.TrialFunction(self.V)
        v = fa.TestFunction(self.V)
        F = fa.inner(fa.grad(u), fa.grad(v)) * fa.dx - self.source * v * fa.dx
        J = fa.derivative(F, u, du)

        # The problem in this case is indeed linear, but using a nonlinear
        # solver doesn't hurt
        problem = fa.NonlinearVariationalProblem(F, u, self.bcs, J)
        solver = fa.NonlinearVariationalSolver(problem)
        solver.solve()
        return u
def solve_steady_state_heiser_weissinger(kappa):

    w = fe.Function(V_up)
    (u, p) = fe.split(w)
    p = fe.variable(p)
    (eta, q) = fe.TestFunctions(V_up)
    dw = fe.TrialFunction(V_up)

    kappa = fe.Constant(kappa)

    bcs_u, bcs_p, bcs_v = load_2d_muscle_bc(V_up.sub(0), V_up.sub(1), None,
                                            boundaries)

    F = deformation_grad(u)
    I_1, I_2, J = invariants(F)
    F_iso = isochronic_deformation_grad(F, J)
    I_1_iso, I_2_iso = invariants(F)[0:2]

    W = material_mooney_rivlin(I_1_iso, I_2_iso, c_10,
                               c_01)  #+ incompr_relaxation(p, kappa)
    g = incompr_constr(J)

    # Lagrange function (without constraint)
    L = -W

    # Modified Lagrange function (with constraints)
    L_mod = L - p * g
    P = first_piola_stress(L, F)
    G = incompr_stress(g, F)  # = J*fe.inv(F.T)

    Lp = const_eq(L_mod, p)

    a_static = weak_div_term(P + p * G,
                             eta) + inner(B, eta) * dx + inner(Lp, q) * dx

    J_static = fe.derivative(a_static, w, dw)
    ffc_options = {"optimize": True}
    problem = fe.NonlinearVariationalProblem(
        a_static,
        w,
        bcs_u + bcs_p,
        J=J_static,
        form_compiler_parameters=ffc_options)
    solver = fe.NonlinearVariationalSolver(problem)

    solver.solve()

    return w
Exemple #6
0
    def check_solver_options():
        """
        Check all the options available for the implemented solver.
        Returns
        -------
        None.
        """
        # Create some trivial nonlinear solver instance.
        mesh = fn.UnitIntervalMesh(1)
        V = fn.FunctionSpace(mesh, "CG", 1)
        problem = fn.NonlinearVariationalProblem(
            fn.Function(V) * fn.TestFunction(V) * fn.dx, fn.Function(V))
        solver = mp.BlockPETScSNESSolver(problem)

        # Print out all the options for its parameters:
        fn.info(solver.parameters, True)
Exemple #7
0
    def setup_solver(self):
        F = self.d_LHS - self.d_RHS
        J = fe.derivative(F, self._domain.w)

        # Initialize solver
        problem = fe.NonlinearVariationalProblem(F,
                                                 self._domain.w,
                                                 bcs=self._dbcs,
                                                 J=J)

        self.solver = fe.NonlinearVariationalSolver(problem)
        for key, val in self._solver_parameters.items():

            if isinstance(val, dict):
                for sub_key, sub_val in val.items():
                    self.solver.parameters[key][sub_key] = sub_val

            else:
                self.solver.parameters[key] = val
def Estimate(Ic, J, u, v, du, BoundaryConditions, InitialState, u_1):
    
    # Use Neo-Hookean constitutive model
    Nu_H   = 0.49                         # (-)
    Mu_NH  = 1.15                         # (kPa)
    Lambda = 2*Mu_NH*Nu_H/(1-2*Nu_H)      # (kPa)
    Psi    = CompressibleNeoHookean(Mu_NH, Lambda, Ic, J)
    Pi = Psi * fe.dx
    
    # First directional derivative of the potential energy
    Fpi = fe.derivative(Pi,u,v)

    # Jacobian of Fpi
    Jac = fe.derivative(Fpi,u,du)
    
    # Define option for the compiler (optional)
    ffc_options = {"optimize": True, \
                   "eliminate_zeros": True, \
                   "precompute_basis_const": True, \
                   "precompute_ip_const": True, \
                   "quadrature_degree": 2, \
                   "representation" : "uflacs" }
    
    # Define the problem
    Problem = fe.NonlinearVariationalProblem(Fpi, u, BoundaryConditions, Jac, form_compiler_parameters=ffc_options)

    # Define the solver
    Solver = fe.NonlinearVariationalSolver(Problem)
    
    # Set solver parameters (optional)
    Prm = Solver.parameters
    Prm['nonlinear_solver'] = 'newton'
    Prm['newton_solver']['linear_solver'] = 'cg'             # Conjugate gradient
    Prm['newton_solver']['preconditioner'] = 'icc'           # Incomplete Choleski   
    Prm['newton_solver']['krylov_solver']['nonzero_initial_guess'] = True
    
    # Set initial displacement
    u_1.s = InitialState
    
    # Compute solution and save displacement
    Solver.solve()
    
    return u
Exemple #9
0
def _create_variational_problem(m0, u0, W, dt):
    """We set up the variational problem."""
    
    p, q = fc.TestFunctions(W)
    w = fc.Function(W)  # Function to solve for
    m, u = fc.split(w)
    # Relabel i.e. initialise m_prev, u_prev as m0, u0.
    m_prev, u_prev = m0, u0
    m_mid = 0.5 * (m + m_prev)
    u_mid = 0.5 * (u + u_prev)
    F = (
        (q * u + q.dx(0) * u.dx(0) - q * m) * fc.dx +                                          # q part
        (p * (m - m_prev) + dt * (p * m_mid * u_mid.dx(0) - p.dx(0) * m_mid * u_mid)) * fc.dx  # p part
        )
    J = fc.derivative(F, w)
    problem = fc.NonlinearVariationalProblem(F, w, J=J)
    solver = fc.NonlinearVariationalSolver(problem)
    solver.parameters["newton_solver"]["maximum_iterations"] = 100  # Default is 50
    solver.parameters["newton_solver"]["error_on_nonconvergence"] = False
    
    return solver, w, m_prev, u_prev
Exemple #10
0
    def solve(self, Ain=None, Qin=None, Aout=None, Qout=None):

        # -- Define boundaries
        def bcL(x, on_boundary):
            return on_boundary and x[0] < fe.DOLFIN_EPS

        def bcR(x, on_boundary):
            return on_boundary and self.L - x[0] < fe.DOLFIN_EPS

        # -- Define initial conditions
        bcs = []
        if Ain is not None:
            bc_Ain = fe.DirichletBC(self.V_A,
                                    fe.Expression("Ain", Ain=Ain, degree=1),
                                    bcL)
            bcs.append(bc_Ain)
        if Qin is not None:
            bc_Qin = fe.DirichletBC(self.V_Q,
                                    fe.Expression("Qin", Qin=Qin, degree=1),
                                    bcL)
            bcs.append(bc_Qin)
        if Aout is not None:
            bc_Aout = fe.DirichletBC(
                self.V_A, fe.Expression("Aout", Aout=Aout, degree=1), bcR)
            bcs.append(bc_Aout)
        if Qout is not None:
            bc_Qout = fe.DirichletBC(
                self.V_Q, fe.Expression("Qout", Qout=Qout, degree=1), bcR)
            bcs.append(bc_Qout)

        # -- Setup problem
        problem = fe.NonlinearVariationalProblem(self.wf,
                                                 self.Un,
                                                 bcs,
                                                 J=self.J)
        solver = fe.NonlinearVariationalSolver(problem)

        # -- Solve
        solver.solve()
        self.U0.assign(self.Un)
Exemple #11
0
    def staggered_solve(self):
        self.U = fe.VectorFunctionSpace(self.mesh, 'CG', 1)
        self.W = fe.FunctionSpace(self.mesh, 'CG', 1)

        self.WW = fe.FunctionSpace(self.mesh, 'DG', 0)
        self.EE = fe.TensorFunctionSpace(self.mesh, 'DG', 0)
        self.MM = fe.VectorFunctionSpace(self.mesh, 'CG', 1)

        self.eta = fe.TestFunction(self.U)
        self.zeta = fe.TestFunction(self.W)
        q = fe.TestFunction(self.WW)

        del_x = fe.TrialFunction(self.U)
        del_d = fe.TrialFunction(self.W)
        p = fe.TrialFunction(self.WW)

        self.x_new = fe.Function(self.U, name="u")
        self.d_new = fe.Function(self.W, name="d")
        self.d_pre = fe.Function(self.W)
        self.x_pre = fe.Function(self.U)

        x_old = fe.Function(self.U)
        d_old = fe.Function(self.W)

        self.H_old = fe.Function(self.WW)

        self.map_plot = fe.Function(self.MM, name="m")
        e = fe.Function(self.EE, name="e")

        self.create_custom_xdmf_files()

        self.file_results = fe.XDMFFile('data/xdmf/{}/u.xdmf'.format(
            self.case_name))
        self.file_results.parameters["functions_share_mesh"] = True

        vtkfile_e = fe.File('data/pvd/simulation/{}/e.pvd'.format(
            self.case_name))
        vtkfile_u = fe.File('data/pvd/simulation/{}/u.pvd'.format(
            self.case_name))
        vtkfile_d = fe.File('data/pvd/simulation/{}/d.pvd'.format(
            self.case_name))

        for i, (disp, rp) in enumerate(
                zip(self.displacements, self.relaxation_parameters)):
            print('\n')
            print(
                '================================================================================='
            )
            print('>> Step {}, disp boundary condition = {} [mm]'.format(
                i, disp))
            print(
                '================================================================================='
            )
            self.i = i
            self.update_weak_form_due_to_Model_C_bug()

            if self.update_weak_form:
                self.set_bcs_staggered()
                print("Update weak form...")
                self.build_weak_form_staggered()

                print("Taking derivatives of weak form...")
                J_u = fe.derivative(self.G_u, self.x_new, del_x)
                J_d = fe.derivative(self.G_d, self.d_new, del_d)
                print("Define nonlinear problems...")
                p_u = fe.NonlinearVariationalProblem(self.G_u, self.x_new,
                                                     self.BC_u, J_u)
                p_d = fe.NonlinearVariationalProblem(self.G_d, self.d_new,
                                                     self.BC_d, J_d)
                print("Define solvers...")
                solver_u = fe.NonlinearVariationalSolver(p_u)
                solver_d = fe.NonlinearVariationalSolver(p_d)
                self.update_weak_form = False

                print("Update history weak form")
                a = p * q * fe.dx
                L = history(self.H_old, self.update_history(),
                            self.psi_cr) * q * fe.dx

                if self.map_flag:
                    self.interpolate_map()
                    # delta_x = self.x - self.x_hat
                    # self.map_plot.assign(fe.project(delta_x, self.MM))

            self.presLoad.t = disp

            newton_prm = solver_u.parameters['newton_solver']
            newton_prm['maximum_iterations'] = 100
            # newton_prm['absolute_tolerance'] = 1e-8
            newton_prm['relaxation_parameter'] = rp

            newton_prm = solver_d.parameters['newton_solver']
            newton_prm['maximum_iterations'] = 100
            # newton_prm['absolute_tolerance'] = 1e-8
            newton_prm['relaxation_parameter'] = rp

            vtkfile_e_staggered = fe.File(
                'data/pvd/simulation/{}/step{}/e.pvd'.format(
                    self.case_name, i))
            vtkfile_u_staggered = fe.File(
                'data/pvd/simulation/{}/step{}/u.pvd'.format(
                    self.case_name, i))
            vtkfile_d_staggered = fe.File(
                'data/pvd/simulation/{}/step{}/d.pvd'.format(
                    self.case_name, i))
            iteration = 0
            err = 1.
            while err > self.staggered_tol:
                iteration += 1

                solver_d.solve()

                solver_u.solve()

                if self.solution_scheme == 'explicit':
                    break

                # # Remarks(Tianju): self.x_new.vector() does not behave as expected: producing nan values
                # The following lines of codes cause issues
                # We use an error measure similar in https://doi.org/10.1007/s10704-019-00372-y
                # np_x_new = np.asarray(self.x_new.vector())
                # np_d_new = np.asarray(self.d_new.vector())
                # np_x_old = np.asarray(x_old.vector())
                # np_d_old = np.asarray(d_old.vector())
                # err_x = np.linalg.norm(np_x_new - np_x_old) / np.sqrt(len(np_x_new))
                # err_d = np.linalg.norm(np_d_new - np_d_old) / np.sqrt(len(np_d_new))
                # err = max(err_x, err_d)

                # # Remarks(Tianju): dolfin (2019.1.0) errornorm function has severe bugs not behave as expected
                # The bug seems to be fixed in later versions
                # The following sometimes produces nonzero results in dolfin (2019.1.0)
                # print(fe.errornorm(self.d_new, self.d_new, norm_type='l2'))

                err_x = fe.errornorm(self.x_new, x_old, norm_type='l2')
                err_d = fe.errornorm(self.d_new, d_old, norm_type='l2')
                err = max(err_x, err_d)

                x_old.assign(self.x_new)
                d_old.assign(self.d_new)
                e.assign(
                    fe.project(strain(self.mfem_grad(self.x_new)), self.EE))

                print(
                    '---------------------------------------------------------------------------------'
                )
                print(
                    '>> iteration. {}, err_u = {:.5}, err_d = {:.5}, error = {:.5}'
                    .format(iteration, err_x, err_d, err))
                print(
                    '---------------------------------------------------------------------------------'
                )

                # vtkfile_e_staggered << e
                # vtkfile_u_staggered << self.x_new
                # vtkfile_d_staggered << self.d_new

                if err < self.staggered_tol or iteration >= self.staggered_maxiter:
                    print(
                        '================================================================================='
                    )
                    print('\n')
                    break

            print("L2 projection to update the history function...")
            fe.solve(a == L, self.H_old, [])

            # self.d_pre.assign(self.d_new)
            # self.H_old.assign(fe.project(history(self.H_old, self.update_history(), self.psi_cr), self.WW))

            if self.map_flag and not self.finish_flag:
                self.update_map()

            if self.compute_and_save_intermediate_results:
                print("Save files...")
                self.file_results.write(e, i)
                self.file_results.write(self.x_new, i)
                self.file_results.write(self.d_new, i)
                self.file_results.write(self.map_plot, i)

                vtkfile_e << e
                vtkfile_u << self.x_new
                vtkfile_d << self.d_new

                # Assume boundary is not affected by the map.
                # There's no need to use the mfem_grad wrapper so that fe.grad is used for speed-up
                print("Define forces...")
                sigma = cauchy_stress_plus(strain(fe.grad(self.x_new)),
                                           self.psi)
                sigma_minus = cauchy_stress_minus(strain(fe.grad(self.x_new)),
                                                  self.psi_minus)
                sigma_plus = cauchy_stress_plus(strain(fe.grad(self.x_new)),
                                                self.psi_plus)
                sigma_degraded = g_d(self.d_new) * sigma_plus + sigma_minus

                print("Compute forces...")
                if self.case_name == 'pure_shear':
                    f_full = float(fe.assemble(sigma[0, 1] * self.ds(1)))
                    f_degraded = float(
                        fe.assemble(sigma_degraded[0, 1] * self.ds(1)))
                else:
                    f_full = float(fe.assemble(sigma[1, 1] * self.ds(1)))
                    f_degraded = float(
                        fe.assemble(sigma_degraded[1, 1] * self.ds(1)))

                print("Force full is {}".format(f_full))
                print("Force degraded is {}".format(f_degraded))
                self.delta_u_recorded.append(disp)
                self.force_full.append(f_full)
                self.force_degraded.append(f_degraded)

                # if force_upper < 0.5 and i > 10:
                #     break

                if self.display_intermediate_results and i % 10 == 0:
                    self.show_force_displacement()

                self.save_data_in_loop()

        if self.display_intermediate_results:
            plt.ioff()
            plt.show()
Exemple #12
0
def SolveProblem(LoadCase, ConstitutiveModel, BCsType, FinalRelativeStretch, RelativeStepSize, Dimensions, NumberElements, Mesh, V, u, du, v, Ic, J, F, Psi, Plot = False, Paraview = False):
    
    if LoadCase == 'Compression':
                
        # Load case
        [u_0, u_1, InitialState, Direction, Normal, NumberSteps, DeltaStretch] = LoadCaseDefinition(LoadCase, FinalRelativeStretch, RelativeStepSize, Dimensions, BCsType)
        
        
    elif LoadCase == 'Tension':
                
        # Load case
        [u_0, u_1, InitialState, Direction, Normal, NumberSteps, DeltaStretch] = LoadCaseDefinition(LoadCase, FinalRelativeStretch, RelativeStepSize, Dimensions, BCsType)

        
    elif LoadCase == 'SimpleShear':
                
        # Load case
        [u_0, u_1, InitialState, Direction, Normal, NumberSteps, DeltaStretch] = LoadCaseDefinition(LoadCase, FinalRelativeStretch*2, RelativeStepSize*2, Dimensions, BCsType)

    # Boundary conditions
    [BoundaryConditions, ds] = BCsDefinition(Dimensions, Mesh, V, u_0, u_1, LoadCase, BCsType)
    
    # Estimation of the displacement field using Neo-Hookean model (necessary for Ogden)
    u = Estimate(Ic, J, u, v, du, BoundaryConditions, InitialState, u_1)
    
    # Reformulate the problem with the correct constitutive model
    Pi = Psi * fe.dx

    # First directional derivative of the potential energy
    Fpi = fe.derivative(Pi,u,v)

    # Jacobian of Fpi
    Jac = fe.derivative(Fpi,u,du)
    
    # Define option for the compiler (optional)
    ffc_options = {"optimize": True, \
                   "eliminate_zeros": True, \
                   "precompute_basis_const": True, \
                   "precompute_ip_const": True }

    # Define the problem
    Problem = fe.NonlinearVariationalProblem(Fpi, u, BoundaryConditions, Jac, form_compiler_parameters=ffc_options)

    # Define the solver
    Solver = fe.NonlinearVariationalSolver(Problem)

    # Set solver parameters (optional)
    Prm = Solver.parameters
    Prm['nonlinear_solver'] = 'newton'
    Prm['newton_solver']['linear_solver'] = 'cg'             # Conjugate gradient
    Prm['newton_solver']['preconditioner'] = 'icc'           # Incomplete Choleski
    Prm['newton_solver']['krylov_solver']['nonzero_initial_guess'] = True
    
    # Data frame to store values
    cols = ['Stretches','P']
    df = pd.DataFrame(columns=cols, index=range(int(NumberSteps)+1), dtype='float64')
    
    if Paraview == True:
        # Results File
        Output_Path = os.path.join('OptimizationResults', BCsType, ConstitutiveModel)
        ResultsFile = xdmffile = fe.XDMFFile(os.path.join(Output_Path, str(NumberElements) + 'Elements_' + LoadCase + '.xdmf'))
        ResultsFile.parameters["flush_output"] = True
        ResultsFile.parameters["functions_share_mesh"] = True
    
    if Plot == True:
        plt.rc('figure', figsize=[12,7])
        fig = plt.figure()
        ax = fig.add_subplot(1, 1, 1)
    
    # Set the stretch state to initial state
    StretchState = InitialState
    
    # Loop to solve for each step
    for Step in range(int(NumberSteps+1)):

        # Update current state
        u_1.s = StretchState

        # Compute solution and save displacement
        Solver.solve()

        # First Piola Kirchoff (nominal) stress
        P = fe.diff(Psi, F)

        # Nominal stress vectors normal to upper surface
        p = fe.dot(P,Normal)

        # Reaction force on the upper surface
        f = fe.assemble(fe.inner(p,Direction)*ds(2))

        # Mean nominal stress on the upper surface
        Pm = f/fe.assemble(1*ds(2))

        # Save values to table
        df.loc[Step].Stretches = StretchState
        df.loc[Step].P = Pm

        # Plot
        if Plot == True:
            ax.cla()
            ax.plot(df.Stretches, df.P,  color = 'r', linestyle = '--', label = 'P', marker = 'o', markersize = 8, fillstyle='none')
            ax.set_xlabel('Stretch ratio (-)')
            ax.set_ylabel('Stresses (kPa)')
            ax.xaxis.set_major_locator(plt.MultipleLocator(0.02))
            ax.legend(loc='upper left', frameon=True, framealpha=1)
            display(fig)
            clear_output(wait=True)
            
        if Paraview == True:
            # Project the displacement onto the vector function space
            u_project = fe.project(u, V, solver_type='cg')
            u_project.rename('Displacement (mm)', '')
            ResultsFile.write(u_project,Step)
            
            # Compute nominal stress vector
            p_project = fe.project(p, V)
            p_project.rename("Nominal stress vector (kPa)","")
            ResultsFile.write(p_project,Step)



        # Update the stretch state
        StretchState += DeltaStretch

    return df
Exemple #13
0
if STAB:
    weakForm += res
stab = -tau * fe.inner(fe.grad(q), fe.grad(p)) * fe.dx
weakForm = weakForm + stab

dW = fe.TrialFunction(W)
dFdW = fe.derivative(weakForm, W0, dW)

if MODEL:
    bcSet = [
        bc_1, bc_2, bc_3, bc_inflow, bc_p, bc_v_x0, bc_v_x1, bc_v_y1, bc_v_in,
        bc_v_top
    ]
else:
    bcSet = [bc_1, bc_2, bc_3, bc_inflow, bc_p]
problem = fe.NonlinearVariationalProblem(weakForm, W0, bcSet, J=dFdW)

solver = fe.NonlinearVariationalSolver(problem)

prm = solver.parameters

t = 0.0
t_end = 5.0
pFile = fe.File('Pressure.pvd')
uFile = fe.File('Velocity.pvd')
vFile = fe.File('Vorticity.pvd')
wFile = fe.File('W.pvd')
T = fe.FunctionSpace(mesh, 'CG', 1)
#solver.solve()
while t < t_end:
    print("t =", t)
Exemple #14
0
plt.ylabel('Enthalpy')
plt.show()
# Here is where we solve the newton's linearized problem. The variable JF stores the jacobian of the function F with respect to the enthalpy h.

h_t = (
    h - h_n
) / Delta_t  #{d\T}/{d\h} Simple gateaux derivative of the c*h^3 function
diffth = (3 * (h)**2
          )  #{d\h}/{d\t} but as piecewise as we know the intermediate values
F = (diffth * (fe.dot(fe.grad(v), fe.grad(h))) + (rho / K) *
     (h_t * v)) * fe.dx  #The nonlinear function to be solved is assembled
JF = fe.derivative(
    F, h, fe.TrialFunction(V)
)  #Taking the derivative of the non linear function to solve by newton's method
#Invoking the Newton's method
problem = fe.NonlinearVariationalProblem(F, h, bc, JF)
solver = fe.NonlinearVariationalSolver(problem)
solver.solve()
fe.plot(h)
plt.xlabel('x')
plt.ylabel('Enthalpy')
plt.title('Solution of Enthalpy distribution initially against x ')
plt.show()
fe.plot(phis(h))
plt.xlabel('x')
plt.ylabel('$\phi$')
plt.title('Solid volume fraction before melting')
plt.show()
fe.plot(T, h)
plt.xlabel('Temperature of the initial step solution')
plt.ylabel('Enthalpy of the intital step solution')

def bcL(x, on_boundary):
    return on_boundary and x[0] < fe.DOLFIN_EPS
def bcR(x, on_boundary):
    return on_boundary and L-x[0]   < fe.DOLFIN_EPS
AinBC  = fe.Expression("Ain"  , Ain=A0  , degree=1)
AoutBC = fe.Expression("Aout" , Aout=A0 , degree=1)
QoutBC = fe.Expression("Qout" , Qout=0  , degree=1) 
bc1 = fe.DirichletBC(V_A, AinBC  , bcL)
bc2 = fe.DirichletBC(V_A, AoutBC , bcR)
bc3 = fe.DirichletBC(V_Q, QoutBC , bcR)
bcs = [bc1, bc2, bc3]
W2R = -4*np.sqrt(beta/(2*rho*A0))*A0**(1./4.)

problem = fe.NonlinearVariationalProblem(wf, Un, bcs, J=J)
solver = fe.NonlinearVariationalSolver(problem)


tid = 0
for t in time:
# for t in range(0,1):
    SR0 = U0.compute_vertex_values()[ne]
    QR0 = U0.compute_vertex_values()[2*ne+1]
    c = np.sqrt(beta/(2*rho*A0))*SR0**(1./4.)
    lamR0 = alpha*QR0/SR0 + np.sqrt(c**2+alpha*(alpha-1)*(QR0/SR0)**2)
    xW1R = fe.Point(L-lamR0*dt,0,0)
    (AR,QR) = U0.split()
    AR = AR(xW1R)
    QR = QR(xW1R)
    W1R = QR/AR + 4*np.sqrt(beta/(2*rho*A0))*AR**(1./4.)
Exemple #16
0
    def staggered_solve(self):
        self.U = fe.VectorFunctionSpace(self.mesh, 'CG', 1)
        self.W = fe.FunctionSpace(self.mesh, 'CG', 1)
        self.WW = fe.FunctionSpace(self.mesh, 'DG', 0)

        self.eta = fe.TestFunction(self.U)
        self.zeta = fe.TestFunction(self.W)

        del_x = fe.TrialFunction(self.U)
        del_d = fe.TrialFunction(self.W)

        self.x_new = fe.Function(self.U)
        self.d_new = fe.Function(self.W)

        x_old = fe.Function(self.U)
        d_old = fe.Function(self.W)

        self.H_old = fe.Function(self.WW)

        self.build_weak_form_staggered()
        J_u = fe.derivative(self.G_u, self.x_new, del_x)
        J_d = fe.derivative(self.G_d, self.d_new, del_d)

        self.set_bcs_staggered()
        p_u = fe.NonlinearVariationalProblem(self.G_u, self.x_new, self.BC_u,
                                             J_u)
        p_d = fe.NonlinearVariationalProblem(self.G_d, self.d_new, self.BC_d,
                                             J_d)
        solver_u = fe.NonlinearVariationalSolver(p_u)
        solver_d = fe.NonlinearVariationalSolver(p_d)

        vtkfile_u = fe.File('data/pvd/{}/u.pvd'.format(self.case_name))
        vtkfile_d = fe.File('data/pvd/{}/d.pvd'.format(self.case_name))

        for i, (disp, rp) in enumerate(
                zip(self.displacements, self.relaxation_parameters)):

            print('\n')
            print(
                '================================================================================='
            )
            print('>> Step {}, disp boundary condition = {} [mm]'.format(
                i, disp))
            print(
                '================================================================================='
            )

            self.H_old.assign(
                fe.project(
                    history(self.H_old, self.psi(strain(fe.grad(self.x_new))),
                            self.psi_cr), self.WW))

            self.presLoad.t = disp

            newton_prm = solver_u.parameters['newton_solver']
            newton_prm['maximum_iterations'] = 100
            newton_prm['absolute_tolerance'] = 1e-4
            newton_prm['relaxation_parameter'] = rp

            iteration = 0
            err = 1.

            while err > self.staggered_tol:
                iteration += 1

                solver_d.solve()

                solver_u.solve()

                err_u = fe.errornorm(self.x_new,
                                     x_old,
                                     norm_type='l2',
                                     mesh=None)
                err_d = fe.errornorm(self.d_new,
                                     d_old,
                                     norm_type='l2',
                                     mesh=None)
                err = max(err_u, err_d)

                x_old.assign(self.x_new)
                d_old.assign(self.d_new)

                print(
                    '---------------------------------------------------------------------------------'
                )
                print('>> iteration. {}, error = {:.5}'.format(iteration, err))
                print(
                    '---------------------------------------------------------------------------------'
                )

                if err < self.staggered_tol or iteration >= self.staggered_maxiter:
                    print(
                        '================================================================================='
                    )
                    print('\n')

                    self.x_new.rename("u", "u")
                    self.d_new.rename("d", "d")
                    vtkfile_u << self.x_new
                    vtkfile_d << self.d_new
                    break

            force_upper = float(fe.assemble(self.sigma[1, 1] * self.ds(1)))
            print("Force upper {}".format(force_upper))
            self.delta_u_recorded.append(disp)
            self.sigma_recorded.append(force_upper)
Exemple #17
0
dot, grad = fenics.dot, fenics.grad
    
F = (psi*(T_t - 1./Ste*phi_t) + dot(grad(psi), grad(T)))*fenics.dx


JF = fenics.derivative(F, T, fenics.TrialFunction(V))


hot_wall = "near(x[0],  0.)"

cold_wall = "near(x[0],  1.)"

boundary_conditions = [
    fenics.DirichletBC(V, hot_wall_temperature, hot_wall),
    fenics.DirichletBC(V, cold_wall_temperature, cold_wall)]


problem = fenics.NonlinearVariationalProblem(F, T, boundary_conditions, JF)


solver = fenics.NonlinearVariationalSolver(problem)


solver.solve()

for timestep in range(10):
    
    T_n.vector()[:] = T.vector()
    
    solver.solve()
    
Exemple #18
0
for i in materials:
    psi = strainDensityFunction(E, materials[i][0], materials[i][1])
    integrals_E.append(psi * dxp(i))

# Total potential energy
Pi = sum(integrals_E) - sum(integrals_V) - sum(integrals_S)

# Compute 1st variation of Pi (directional derivative about u in dir. of v)
F = fe.derivative(Pi, u, v)

# Compute Jacobian of F
J = fe.derivative(F, u, du)

############################## SOLVER PARAMS ##################################
# Define the solver params
problem = fe.NonlinearVariationalProblem(F, u, bcs, J)
solver = fe.NonlinearVariationalSolver(problem)
prm = solver.parameters
prm['nonlinear_solver'] = 'newton'
prm['newton_solver']['linear_solver'] = 'petsc'

prm['newton_solver']['error_on_nonconvergence'] = True
prm['newton_solver']['absolute_tolerance'] = 1E-9
prm['newton_solver']['relative_tolerance'] = 1E-8
prm['newton_solver']['maximum_iterations'] = 25
prm['newton_solver']['relaxation_parameter'] = 1.0

prm['newton_solver']['lu_solver']['report'] = True
prm['newton_solver']['lu_solver']['reuse_factorization'] = False
prm['newton_solver']['lu_solver']['same_nonzero_pattern'] = False
prm['newton_solver']['lu_solver']['symmetric'] = False
Exemple #19
0
    def monolithic_solve(self):
        self.U = fe.VectorElement('CG', self.mesh.ufl_cell(), 1)
        self.W = fe.FiniteElement("CG", self.mesh.ufl_cell(), 1)
        self.M = fe.FunctionSpace(self.mesh, self.U * self.W)

        self.WW = fe.FunctionSpace(self.mesh, 'DG', 0)

        m_test = fe.TestFunctions(self.M)
        m_delta = fe.TrialFunctions(self.M)
        m_new = fe.Function(self.M)

        self.eta, self.zeta = m_test
        self.x_new, self.d_new = fe.split(m_new)

        self.H_old = fe.Function(self.WW)

        vtkfile_u = fe.File('data/pvd/{}/u.pvd'.format(self.case_name))
        vtkfile_d = fe.File('data/pvd/{}/d.pvd'.format(self.case_name))

        self.build_weak_form_monolithic()
        dG = fe.derivative(self.G, m_new)

        self.set_bcs_monolithic()
        p = fe.NonlinearVariationalProblem(self.G, m_new, self.BC, dG)
        solver = fe.NonlinearVariationalSolver(p)

        for i, (disp, rp) in enumerate(
                zip(self.displacements, self.relaxation_parameters)):

            print('\n')
            print(
                '================================================================================='
            )
            print('>> Step {}, disp boundary condition = {} [mm]'.format(
                i, disp))
            print(
                '================================================================================='
            )

            self.H_old.assign(
                fe.project(
                    history(self.H_old, self.psi(strain(fe.grad(self.x_new))),
                            self.psi_cr), self.WW))

            self.presLoad.t = disp

            newton_prm = solver.parameters['newton_solver']
            newton_prm['maximum_iterations'] = 100
            newton_prm['absolute_tolerance'] = 1e-4
            newton_prm['relaxation_parameter'] = rp

            solver.solve()

            self.x_plot, self.d_plot = m_new.split()
            self.x_plot.rename("u", "u")
            self.d_plot.rename("d", "d")

            vtkfile_u << self.x_plot
            vtkfile_d << self.d_plot

            force_upper = float(fe.assemble(self.sigma[1, 1] * self.ds(1)))
            print("Force upper {}".format(force_upper))
            self.delta_u_recorded.append(disp)
            self.sigma_recorded.append(force_upper)

            print(
                '================================================================================='
            )
Exemple #20
0
file_u = fe.File("../results/displacement.pvd")
file_p = fe.File("../results/pressure.pvd")

bcul = fe.DirichletBC(V.sub(0), u_left, left)
bcur = fe.DirichletBC(V.sub(0), u_right, right)
#bcpl = fe.DirichletBC(V.sub(1), p_left, left)
bcs = [bcul, bcur]  # bcpl]

J_static = fe.derivative(F_static, w, dw)

#fe.solve(F_static==0, w, bcs)

ffc_options = {"optimize": True}
problem = fe.NonlinearVariationalProblem(F_static,
                                         w,
                                         bcs,
                                         J=J_static,
                                         form_compiler_parameters=ffc_options)
solver = fe.NonlinearVariationalSolver(problem)

# set parameters
prm = solver.parameters
if True:
    iterative_solver = True
    #prm['newton_solver']['absolute_tolerance'] = 1E-3
    #prm['newton_solver']['relative_tolerance'] = 1E-2
    #prm['newton_solver']['maximum_iterations'] = 20
    #prm['newton_solver']['relaxation_parameter'] = 1.0
    prm['newton_solver']['linear_solver'] = 'bicgstab'
    #if iterative_solver:
    #    prm['newton_solver']['krylov_solver']['absolute_tolerance'] = 1E-4
Exemple #21
0
def run(output_dir="output/wang2010_natural_convection_air",
        rayleigh_number=1.e6,
        prandtl_number=0.71,
        stefan_number=0.045,
        heat_capacity=1.,
        thermal_conductivity=1.,
        liquid_viscosity=1.,
        solid_viscosity=1.e8,
        gravity=(0., -1.),
        m_B=None,
        ddT_m_B=None,
        penalty_parameter=1.e-7,
        temperature_of_fusion=-1.e12,
        regularization_smoothing_factor=0.005,
        mesh=fenics.UnitSquareMesh(fenics.dolfin.mpi_comm_world(), 20, 20,
                                   "crossed"),
        initial_values_expression=("0.", "0.", "0.",
                                   "0.5*near(x[0],  0.) -0.5*near(x[0],  1.)"),
        boundary_conditions=[{
            "subspace": 0,
            "value_expression": ("0.", "0."),
            "degree": 3,
            "location_expression":
            "near(x[0],  0.) | near(x[0],  1.) | near(x[1], 0.) | near(x[1],  1.)",
            "method": "topological"
        }, {
            "subspace": 2,
            "value_expression": "0.5",
            "degree": 2,
            "location_expression": "near(x[0],  0.)",
            "method": "topological"
        }, {
            "subspace": 2,
            "value_expression": "-0.5",
            "degree": 2,
            "location_expression": "near(x[0],  1.)",
            "method": "topological"
        }],
        start_time=0.,
        end_time=10.,
        time_step_size=1.e-3,
        stop_when_steady=True,
        steady_relative_tolerance=1.e-4,
        adaptive=False,
        adaptive_metric="all",
        adaptive_solver_tolerance=1.e-4,
        nlp_absolute_tolerance=1.e-8,
        nlp_relative_tolerance=1.e-8,
        nlp_max_iterations=50,
        restart=False,
        restart_filepath=""):
    """Run Phaseflow.
    
    Phaseflow is configured entirely through the arguments in this run() function.
    
    See the tests and examples for demonstrations of how to use this.
    """

    # Handle default function definitions.
    if m_B is None:

        def m_B(T, Ra, Pr, Re):

            return T * Ra / (Pr * Re**2)

    if ddT_m_B is None:

        def ddT_m_B(T, Ra, Pr, Re):

            return Ra / (Pr * Re**2)

    # Report arguments.
    phaseflow.helpers.print_once(
        "Running Phaseflow with the following arguments:")

    phaseflow.helpers.print_once(phaseflow.helpers.arguments())

    phaseflow.helpers.mkdir_p(output_dir)

    if fenics.MPI.rank(fenics.mpi_comm_world()) is 0:

        arguments_file = open(output_dir + "/arguments.txt", "w")

        arguments_file.write(str(phaseflow.helpers.arguments()))

        arguments_file.close()

    # Check if 1D/2D/3D.
    dimensionality = mesh.type().dim()

    phaseflow.helpers.print_once("Running " + str(dimensionality) +
                                 "D problem")

    # Initialize time.
    if restart:

        with h5py.File(restart_filepath, "r") as h5:

            time = h5["t"].value

            assert (abs(time - start_time) < TIME_EPS)

    else:

        time = start_time

    # Define the mixed finite element and the solution function space.
    W_ele = make_mixed_fe(mesh.ufl_cell())

    W = fenics.FunctionSpace(mesh, W_ele)

    # Set the initial values.
    if restart:

        mesh = fenics.Mesh()

        with fenics.HDF5File(mesh.mpi_comm(), restart_filepath, "r") as h5:

            h5.read(mesh, "mesh", True)

        W_ele = make_mixed_fe(mesh.ufl_cell())

        W = fenics.FunctionSpace(mesh, W_ele)

        w_n = fenics.Function(W)

        with fenics.HDF5File(mesh.mpi_comm(), restart_filepath, "r") as h5:

            h5.read(w_n, "w")

    else:

        w_n = fenics.interpolate(
            fenics.Expression(initial_values_expression, element=W_ele), W)

    # Organize the boundary conditions.
    bcs = []

    for item in boundary_conditions:

        bcs.append(
            fenics.DirichletBC(W.sub(item["subspace"]),
                               item["value_expression"],
                               item["location_expression"],
                               method=item["method"]))

    # Set the variational form.
    """Set local names for math operators to improve readability."""
    inner, dot, grad, div, sym = fenics.inner, fenics.dot, fenics.grad, fenics.div, fenics.sym
    """The linear, bilinear, and trilinear forms b, a, and c, follow the common notation 
    for applying the finite element method to the incompressible Navier-Stokes equations,
    e.g. from danaila2014newton and huerta2003fefluids.
    """
    def b(u, q):
        return -div(u) * q  # Divergence

    def D(u):

        return sym(grad(u))  # Symmetric part of velocity gradient

    def a(mu, u, v):

        return 2. * mu * inner(D(u), D(v))  # Stokes stress-strain

    def c(w, z, v):

        return dot(dot(grad(z), w), v)  # Convection of the velocity field

    dt = fenics.Constant(time_step_size)

    Re = fenics.Constant(reynolds_number)

    Ra = fenics.Constant(rayleigh_number)

    Pr = fenics.Constant(prandtl_number)

    Ste = fenics.Constant(stefan_number)

    C = fenics.Constant(heat_capacity)

    K = fenics.Constant(thermal_conductivity)

    g = fenics.Constant(gravity)

    def f_B(T):

        return m_B(T=T, Ra=Ra, Pr=Pr, Re=Re) * g  # Buoyancy force, $f = ma$

    gamma = fenics.Constant(penalty_parameter)

    T_f = fenics.Constant(temperature_of_fusion)

    r = fenics.Constant(regularization_smoothing_factor)

    def P(T):

        return 0.5 * (1. - fenics.tanh(
            (T_f - T) / r))  # Regularized phase field.

    mu_l = fenics.Constant(liquid_viscosity)

    mu_s = fenics.Constant(solid_viscosity)

    def mu(T):

        return mu_s + (mu_l - mu_s) * P(T)  # Variable viscosity.

    L = C / Ste  # Latent heat

    u_n, p_n, T_n = fenics.split(w_n)

    w_w = fenics.TrialFunction(W)

    u_w, p_w, T_w = fenics.split(w_w)

    v, q, phi = fenics.TestFunctions(W)

    w_k = fenics.Function(W)

    u_k, p_k, T_k = fenics.split(w_k)

    F = (b(u_k, q) - gamma * p_k * q + dot(u_k - u_n, v) / dt + c(u_k, u_k, v)
         + b(v, p_k) + a(mu(T_k), u_k, v) + dot(f_B(T_k), v) + C / dt *
         (T_k - T_n) * phi - dot(C * T_k * u_k, grad(phi)) +
         K / Pr * dot(grad(T_k), grad(phi)) + 1. / dt * L *
         (P(T_k) - P(T_n)) * phi) * fenics.dx

    def ddT_f_B(T):

        return ddT_m_B(T=T, Ra=Ra, Pr=Pr, Re=Re) * g

    def sech(theta):

        return 1. / fenics.cosh(theta)

    def dP(T):

        return sech((T_f - T) / r)**2 / (2. * r)

    def dmu(T):

        return (mu_l - mu_s) * dP(T)

    # Set the Jacobian (formally the Gateaux derivative) in variational form.
    JF = (b(u_w, q) - gamma * p_w * q + dot(u_w, v) / dt + c(u_k, u_w, v) +
          c(u_w, u_k, v) + b(v, p_w) + a(T_w * dmu(T_k), u_k, v) +
          a(mu(T_k), u_w, v) + dot(T_w * ddT_f_B(T_k), v) +
          C / dt * T_w * phi - dot(C * T_k * u_w, grad(phi)) -
          dot(C * T_w * u_k, grad(phi)) + K / Pr * dot(grad(T_w), grad(phi)) +
          1. / dt * L * T_w * dP(T_k) * phi) * fenics.dx

    # Set the functional metric for the error estimator for adaptive mesh refinement.
    """I haven't found a good way to make this flexible yet.
    Ideally the user would be able to write the metric, but this would require giving the user
    access to much data that phaseflow is currently hiding.
    """
    M = P(T_k) * fenics.dx

    if adaptive_metric == "phase_only":

        pass

    elif adaptive_metric == "all":

        M += T_k * fenics.dx

        for i in range(dimensionality):

            M += u_k[i] * fenics.dx

    else:

        assert (False)

    # Make the problem.
    problem = fenics.NonlinearVariationalProblem(F, w_k, bcs, JF)

    # Make the solvers.
    """ For the purposes of this project, it would be better to just always use the adaptive solver; but
    unfortunately the adaptive solver encounters nan's whenever evaluating the error for problems not 
    involving phase-change. So far my attempts at writing a MWE to reproduce the  issue have failed.
    """
    adaptive_solver = fenics.AdaptiveNonlinearVariationalSolver(problem, M)

    adaptive_solver.parameters["nonlinear_variational_solver"]["newton_solver"]["maximum_iterations"]\
        = nlp_max_iterations

    adaptive_solver.parameters["nonlinear_variational_solver"]["newton_solver"]["absolute_tolerance"]\
        = nlp_absolute_tolerance

    adaptive_solver.parameters["nonlinear_variational_solver"]["newton_solver"]["relative_tolerance"]\
        = nlp_relative_tolerance

    static_solver = fenics.NonlinearVariationalSolver(problem)

    static_solver.parameters["newton_solver"][
        "maximum_iterations"] = nlp_max_iterations

    static_solver.parameters["newton_solver"][
        "absolute_tolerance"] = nlp_absolute_tolerance

    static_solver.parameters["newton_solver"][
        "relative_tolerance"] = nlp_relative_tolerance

    # Open a context manager for the output file.
    with fenics.XDMFFile(output_dir + "/solution.xdmf") as solution_file:

        # Write the initial values.
        write_solution(solution_file, w_n, time)

        if start_time >= end_time - TIME_EPS:

            phaseflow.helpers.print_once(
                "Start time is already too close to end time. Only writing initial values."
            )

            return w_n, mesh

        # Solve each time step.
        progress = fenics.Progress("Time-stepping")

        fenics.set_log_level(fenics.PROGRESS)

        for it in range(1, MAX_TIME_STEPS):

            if (time > end_time - TIME_EPS):

                break

            if adaptive:

                adaptive_solver.solve(adaptive_solver_tolerance)

            else:

                static_solver.solve()

            time = start_time + it * time_step_size

            phaseflow.helpers.print_once("Reached time t = " + str(time))

            write_solution(solution_file, w_k, time)

            # Write checkpoint/restart files.
            restart_filepath = output_dir + "/restart_t" + str(time) + ".h5"

            with fenics.HDF5File(fenics.mpi_comm_world(), restart_filepath,
                                 "w") as h5:

                h5.write(mesh.leaf_node(), "mesh")

                h5.write(w_k.leaf_node(), "w")

            if fenics.MPI.rank(fenics.mpi_comm_world()) is 0:

                with h5py.File(restart_filepath, "r+") as h5:

                    h5.create_dataset("t", data=time)

            # Check for steady state.
            if stop_when_steady and steady(W, w_k, w_n,
                                           steady_relative_tolerance):

                phaseflow.helpers.print_once(
                    "Reached steady state at time t = " + str(time))

                break

            # Set initial values for next time step.
            w_n.leaf_node().vector()[:] = w_k.leaf_node().vector()

            # Report progress.
            progress.update(time / end_time)

            if time >= (end_time - fenics.dolfin.DOLFIN_EPS):

                phaseflow.helpers.print_once("Reached end time, t = " +
                                             str(end_time))

                break

    # Return the interpolant to sample inside of Python.
    w_k.rename("w", "state")

    return w_k, mesh