Example #1
0
def inverse_map_function_ufl(x, control_points, impact_radii, map_type):
    if len(control_points) == 0:
        return x
    x = fe.variable(x)
    df, rho = distance_function_segments_ufl(x, control_points, impact_radii)
    grad_x = fe.diff(df, x)
    delta_x = fe.conditional(
        fe.gt(df, rho), fe.Constant((0., 0.)),
        grad_x * (rho * inverse_ratio_function_ufl(df / rho, map_type) - df))
    return delta_x + x
Example #2
0
    def build_weak_form_staggered(self):
        self.x_hat = fe.variable(fe.SpatialCoordinate(self.mesh))
        self.x = map_function_ufl(self.x_hat, self.control_points,
                                  self.impact_radii, self.map_type,
                                  self.boundary_info)
        self.grad_gamma = fe.diff(self.x, self.x_hat)

        def mfem_grad_wrapper(grad):
            def mfem_grad(u):
                return fe.dot(grad(u), fe.inv(self.grad_gamma))

            return mfem_grad

        self.mfem_grad = mfem_grad_wrapper(fe.grad)

        # A special note (Tianju): We hope to use Model C, but Newton solver fails without the initial guess by Model A
        if self.i < 2:
            self.psi_plus = partial(psi_plus_linear_elasticity_model_A,
                                    lamda=self.lamda,
                                    mu=self.mu)
            self.psi_minus = partial(psi_minus_linear_elasticity_model_A,
                                     lamda=self.lamda,
                                     mu=self.mu)
        else:
            self.psi_plus = partial(psi_plus_linear_elasticity_model_C,
                                    lamda=self.lamda,
                                    mu=self.mu)
            self.psi_minus = partial(psi_minus_linear_elasticity_model_C,
                                     lamda=self.lamda,
                                     mu=self.mu)
            print("use model C")

        self.psi = partial(psi_linear_elasticity, lamda=self.lamda, mu=self.mu)

        self.sigma_plus = cauchy_stress_plus(
            strain(self.mfem_grad(self.x_new)), self.psi_plus)
        self.sigma_minus = cauchy_stress_minus(
            strain(self.mfem_grad(self.x_new)), self.psi_minus)

        # self.sigma = cauchy_stress_plus(strain(self.mfem_grad(self.x_new)), self.psi)
        # self.sigma_degraded = g_d(self.d_new) * self.sigma_plus + self.sigma_minus

        self.G_u = (g_d(self.d_new) * fe.inner(self.sigma_plus, strain(self.mfem_grad(self.eta))) \
            + fe.inner(self.sigma_minus, strain(self.mfem_grad(self.eta)))) * fe.det(self.grad_gamma) * fe.dx

        if self.solution_scheme == 'explicit':
            self.G_d = (self.H_old * self.zeta * g_d_prime(self.d_new, g_d) \
                    + self.G_c / self.l0 * (self.zeta * self.d_new + self.l0**2 * fe.inner(self.mfem_grad(self.zeta), self.mfem_grad(self.d_new)))) * fe.det(self.grad_gamma) * fe.dx
        else:
            self.G_d = (history(self.H_old, self.psi_plus(strain(self.mfem_grad(self.x_new))), self.psi_cr) * self.zeta * g_d_prime(self.d_new, g_d) \
                    + self.G_c / self.l0 * (self.zeta * self.d_new + self.l0**2 * fe.inner(self.mfem_grad(self.zeta), self.mfem_grad(self.d_new)))) * fe.det(self.grad_gamma) * fe.dx
Example #3
0
    def build_weak_form_staggered(self):
        self.x_hat = fe.variable(fe.SpatialCoordinate(self.mesh))
        self.x = fe.variable(
            map_function_ufl(self.x_hat, self.control_points,
                             self.impact_radii, self.map_type,
                             self.boundary_info))
        self.grad_gamma = fe.diff(self.x, self.x_hat)

        def mfem_grad_wrapper(grad):
            def mfem_grad(u):
                return fe.dot(grad(u), fe.inv(self.grad_gamma))

            return mfem_grad

        self.mfem_grad = mfem_grad_wrapper(fe.grad)

        self.psi_plus = partial(self.psi_plus_linear_elasticity,
                                lamda=self.lamda,
                                mu=self.mu)
        self.psi_minus = partial(self.psi_minus_linear_elasticity,
                                 lamda=self.lamda,
                                 mu=self.mu)
        self.psi = partial(psi_linear_elasticity, lamda=self.lamda, mu=self.mu)

        sigma_plus = cauchy_stress_plus(strain(self.mfem_grad(self.x_new)),
                                        self.psi_plus)
        sigma_minus = cauchy_stress_minus(strain(self.mfem_grad(self.x_new)),
                                          self.psi_minus)

        self.u_exact, self.d_exact = self.compute_analytical_solutions_fully_broken(
            self.x)

        self.G_u = (g_d(self.d_exact) * fe.inner(sigma_plus, strain(self.mfem_grad(self.eta))) \
            + fe.inner(sigma_minus, strain(self.mfem_grad(self.eta)))) * fe.det(self.grad_gamma) * fe.dx

        self.G_d = (self.d_new - self.d_exact) * self.zeta * fe.det(
            self.grad_gamma) * fe.dx

        self.u_initial = self.nonzero_initial_guess(self.x)
        self.x_new.assign(fe.project(self.u_initial, self.U))
Example #4
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
rho = fe.Constant(1.1e3)
kappa = fe.Expression("kappa", kappa=1e8, degree=0)

# currently simplifications
p_act = fe.Expression("p_act*scale", p_act=1., scale=1., degree=0)
lmb_f = fe.Expression("lmd_f", lmd_f=2.0, scale=1., degree=0)

I1_ = J**(-2. / 3.) * I_1
I2_ = J**(-4. / 3.) * I_2

W_iso = c_10 * (I1_ - 3) + c_01 * (I2_ - 3) - p * (J - 1) - p**2 / 2 * kappa

dx = fe.dx
ds = fe.ds

P_iso = fe.diff(W_iso, F)
S_iso = F * P_iso

S_passive = lmb_f**(-1) * p_act * A_00

S = S_iso + S_passive

F_static = inner(S, DE(v)) * dx - rho * inner(b, v) * dx - inner(
    t_bar, v) * ds + (p / kappa + (J - 1)) * q * dx

file_u = fe.File("../results/displacement.pvd")
file_p = fe.File("../results/pressure.pvd")

# Define Dirichlet boundary (x = 0 or x = 1)
u_left = fe.Expression(("0.0", "0.0", "0.0"), element=element_3)
u_right = fe.Expression(("1.*scale", "0.0", "0.0"),
Example #6
0
def map_function_ufl(x_hat,
                     control_points,
                     impact_radii,
                     map_type,
                     boundary_info=None):
    if len(control_points) == 0:
        return x_hat
    x_hat = fe.variable(x_hat)
    df, rho = distance_function_segments_ufl(x_hat, control_points,
                                             impact_radii)
    grad_x_hat = fe.diff(df, x_hat)
    delta_x_hat = fe.conditional(
        fe.gt(df, rho), fe.Constant((0., 0.)),
        grad_x_hat * (rho * ratio_function_ufl(df / rho, map_type) - df))
    if boundary_info is None:
        return delta_x_hat + x_hat
    else:
        last_control_point = control_points[-1]
        points, directions, rho_default = boundary_info
        mid_point, mid_point1, mid_point2 = points
        direct_vec, rotated_vec = directions
        aux_control_point1 = last_control_point + rho_default * rotated_vec
        aux_control_point2 = last_control_point - rho_default * rotated_vec

        w1 = np.linalg.norm(mid_point1 - aux_control_point1)
        w2 = np.linalg.norm(mid_point2 - aux_control_point2)
        w0 = np.linalg.norm(mid_point - last_control_point)

        assert np.absolute(2 * w0 - w1 - w2) < 1e-5

        AB = mid_point - last_control_point
        AP = x_hat - last_control_point

        x1 = AB[0]
        y1 = AB[1]
        x2 = AP[0]
        y2 = AP[1]

        mod = fe.sqrt(x1**2 + y1**2)
        df_to_direct = (x1 * y2 - y1 * x2) / mod  # AB x AP
        df_to_rotated = (x1 * x2 + y1 * y2) / mod

        k1 = rho_default * (w1 + w2) / (rho_default *
                                        (w1 + w2) + df_to_direct * (w1 - w2))

        new_df_to_direct = rho_default * ratio_function_ufl(
            df_to_direct / rho_default, map_type)

        k2 = rho_default * (w1 + w2) / (rho_default *
                                        (w1 + w2) + new_df_to_direct *
                                        (w1 - w2))

        new_df_to_rotated = df_to_rotated * k1 / k2

        x = fe.as_vector(last_control_point + direct_vec * new_df_to_rotated +
                         rotated_vec * new_df_to_direct)

        return fe.conditional(
            fe.gt(df_to_rotated, 0),
            fe.conditional(fe.gt(np.absolute(df_to_direct), rho), x_hat, x),
            delta_x_hat + x_hat)
Example #7
0
def g_d_prime(d, degrad_func):
    d = fe.variable(d)
    degrad = degrad_func(d)
    degrad_prime = fe.diff(degrad, d)
    return degrad_prime
Example #8
0
def first_PK_stress_minus(F, psi_minus):
    F = fe.variable(F)
    energy_minus = psi_minus(F)
    P_minus = fe.diff(energy_minus, F)
    return P_minus
Example #9
0
def const_eq(L_mod, p):
    return fe.diff(L_mod, p)
Example #10
0
 def stress(self, u):
     u_var = fe.variable(u)
     C = fe.variable(kin.right_cauchy_green(u_var))
     return 2 * fe.diff(self.strain_energy(u_var), C)
Example #11
0
def incompr_stress(g, F):
    return fe.diff(g, F)
Example #12
0
def first_piola_stress(L, F):
    return -fe.diff(L, F)
Example #13
0
def first_PK_stress(F, psi):
    F = fe.variable(F)
    energy = psi(F)
    P = fe.diff(energy, F)
    return P
Example #14
0
uViewer << u

# Maximum and minimum displacement
u_magnitude = fe.sqrt(fe.dot(u, u))
u_magnitude = fe.project(u_magnitude, W)
print('Min/Max displacement:',
      u_magnitude.vector().array().min(),
      u_magnitude.vector().array().max())

# Computation of the large deformation strains
#cprint("Computing the deformation tensor and saving to file...", 'green')
epsilon_u = largeKinematics(u)
epsilon_u_project = fe.project(epsilon_u, Z)
epsilonViewer = fe.File('paraview/strain.pvd')
epsilonViewer << epsilon_u_project

# Computation of the stresses
#cprint("Stress derivation and saving to file...", 'green')
S = fe.diff(psi, E)
S_project = fe.project(S, Z)
sigmaViewer = fe.File('paraview/stress.pvd')
sigmaViewer << S_project

# Computation of an equivalent stress
s = S - (1. / 3) * fe.tr(S) * fe.Identity(u.geometric_dimension())
von_Mises = fe.sqrt(3. / 2 * fe.inner(s, s))
von_Mises_project = fe.project(von_Mises, W)
misesViewer = fe.File('paraview/mises.pvd')
misesViewer << von_Mises_project
print("Maximum equivalent stress:", von_Mises_project.vector().array().max())
Example #15
0
def cauchy_stress(epsilon, psi):
    epsilon = fe.variable(epsilon)
    energy = psi(epsilon)
    sigma = fe.diff(energy, epsilon)
    return sigma
Example #16
0
# Not found
rho = fe.Constant(1.1e3)
c_10 = 6.352e-10
c_01 = 3.627
kappa = fe.Constant(0.01)

# currently simplifications
p_act = 0.
lmb_f = 2.

W_iso = c_10 * (I_1 - 3) + c_01 * (I_2 - 3) + 0.5 * kappa * (J - 1)**2

dx = fe.dx
ds = fe.ds

P = fe.diff(W_iso, F)
S = 2 * fe.diff(W_iso, C)
F_static = inner(S, DE(v)) * dx - rho * inner(b, v) * dx - inner(
    t_bar, v) * ds + (p / kappa + J - 1) * q * dx
#F_static = inner(P, grad(v))*dx - rho*inner(b, v)*dx - inner(t_bar, v)*ds + (p/kappa + J - 1)*q*dx

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)
Example #17
0
def cauchy_stress_minus(epsilon, psi_minus):
    epsilon = fe.variable(epsilon)
    energy_minus = psi_minus(epsilon)
    sigma_minus = fe.diff(energy_minus, epsilon)
    return sigma_minus